aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2006-04-28 07:14:48 +0000
committerMartin Willi <martin@strongswan.org>2006-04-28 07:14:48 +0000
commit997358a6c475c8886cce388ab325184a1ff733c9 (patch)
tree27a15790e030fc186d00cd710d2a3540f4defe69
parent52923c9acb349adec3d1cc039e7a74c2e822da6e (diff)
downloadstrongswan-997358a6c475c8886cce388ab325184a1ff733c9.tar.bz2
strongswan-997358a6c475c8886cce388ab325184a1ff733c9.tar.xz
- import of strongswan-2.7.0
- applied patch for charon
-rw-r--r--CHANGES691
-rw-r--r--COPYING340
-rw-r--r--CREDITS110
-rw-r--r--INSTALL249
-rw-r--r--LICENSE33
-rw-r--r--Makefile602
-rw-r--r--Makefile.inc331
-rw-r--r--Makefile.ver1
-rw-r--r--README3091
-rw-r--r--doc/.cvsignore66
-rw-r--r--doc/2.6.known-issues112
-rw-r--r--doc/HowTo.html18733
-rw-r--r--doc/Makefile167
-rw-r--r--doc/README39
-rw-r--r--doc/adv_config.html1232
-rw-r--r--doc/background.html323
-rw-r--r--doc/biblio.html274
-rw-r--r--doc/compat.html707
-rw-r--r--doc/config.html308
-rw-r--r--doc/draft-richardson-ipsec-opportunistic.txt2688
-rw-r--r--doc/draft-richardson-ipsec-rr.txt840
-rw-r--r--doc/draft-spencer-ipsec-ike-implementation.nr1203
-rw-r--r--doc/draft-spencer-ipsec-ike-implementation.txt1232
-rw-r--r--doc/examples182
-rw-r--r--doc/faq.html2339
-rw-r--r--doc/firewall.html767
-rw-r--r--doc/glossary.html2132
-rw-r--r--doc/impl.notes127
-rw-r--r--doc/index.html55
-rw-r--r--doc/install.html286
-rw-r--r--doc/interop.html983
-rw-r--r--doc/intro.html733
-rw-r--r--doc/ipsec.conf.2_to_122
-rw-r--r--doc/ipsec.html1040
-rw-r--r--doc/kernel.html353
-rw-r--r--doc/kernel.notes173
-rw-r--r--doc/mail.html216
-rw-r--r--doc/makecheck.html523
-rw-r--r--doc/manpage.d/ipsec.8.html215
-rw-r--r--doc/manpage.d/ipsec.conf.5.html1830
-rw-r--r--doc/manpage.d/ipsec.secrets.5.html227
-rw-r--r--doc/manpage.d/ipsec__confread.8.html58
-rw-r--r--doc/manpage.d/ipsec__copyright.8.html62
-rw-r--r--doc/manpage.d/ipsec__include.8.html67
-rw-r--r--doc/manpage.d/ipsec__keycensor.8.html64
-rw-r--r--doc/manpage.d/ipsec__plutoload.8.html64
-rw-r--r--doc/manpage.d/ipsec__plutorun.8.html70
-rw-r--r--doc/manpage.d/ipsec__realsetup.8.html68
-rw-r--r--doc/manpage.d/ipsec__secretcensor.8.html65
-rw-r--r--doc/manpage.d/ipsec__startklips.8.html63
-rw-r--r--doc/manpage.d/ipsec__updown.8.html63
-rw-r--r--doc/manpage.d/ipsec_addrbytesof.3.html232
-rw-r--r--doc/manpage.d/ipsec_addrbytesptr.3.html232
-rw-r--r--doc/manpage.d/ipsec_addrcmp.3.html274
-rw-r--r--doc/manpage.d/ipsec_addrinsubnet.3.html274
-rw-r--r--doc/manpage.d/ipsec_addrlenof.3.html232
-rw-r--r--doc/manpage.d/ipsec_addrtoa.3.html448
-rw-r--r--doc/manpage.d/ipsec_addrtosubnet.3.html238
-rw-r--r--doc/manpage.d/ipsec_addrtot.3.html569
-rw-r--r--doc/manpage.d/ipsec_addrtypeof.3.html232
-rw-r--r--doc/manpage.d/ipsec_anyaddr.3.html166
-rw-r--r--doc/manpage.d/ipsec_atoaddr.3.html448
-rw-r--r--doc/manpage.d/ipsec_atoasr.3.html294
-rw-r--r--doc/manpage.d/ipsec_atosa.3.html347
-rw-r--r--doc/manpage.d/ipsec_atosubnet.3.html448
-rw-r--r--doc/manpage.d/ipsec_atoul.3.html266
-rw-r--r--doc/manpage.d/ipsec_auto.8.html416
-rw-r--r--doc/manpage.d/ipsec_barf.8.html150
-rw-r--r--doc/manpage.d/ipsec_bitstomask.3.html122
-rw-r--r--doc/manpage.d/ipsec_broadcastof.3.html107
-rw-r--r--doc/manpage.d/ipsec_calcgoo.8.html78
-rw-r--r--doc/manpage.d/ipsec_copyright_notice.3.html94
-rw-r--r--doc/manpage.d/ipsec_datatot.3.html439
-rw-r--r--doc/manpage.d/ipsec_eroute.5.html370
-rw-r--r--doc/manpage.d/ipsec_eroute.8.html421
-rw-r--r--doc/manpage.d/ipsec_goodmask.3.html122
-rw-r--r--doc/manpage.d/ipsec_hostof.3.html107
-rw-r--r--doc/manpage.d/ipsec_ikeping.8.html137
-rw-r--r--doc/manpage.d/ipsec_initaddr.3.html232
-rw-r--r--doc/manpage.d/ipsec_initsaid.3.html453
-rw-r--r--doc/manpage.d/ipsec_initsubnet.3.html238
-rw-r--r--doc/manpage.d/ipsec_isanyaddr.3.html166
-rw-r--r--doc/manpage.d/ipsec_isloopbackaddr.3.html166
-rw-r--r--doc/manpage.d/ipsec_isunspecaddr.3.html166
-rw-r--r--doc/manpage.d/ipsec_keyblobtoid.3.html174
-rw-r--r--doc/manpage.d/ipsec_klipsdebug.5.html229
-rw-r--r--doc/manpage.d/ipsec_klipsdebug.8.html264
-rw-r--r--doc/manpage.d/ipsec_look.8.html76
-rw-r--r--doc/manpage.d/ipsec_loopbackaddr.3.html166
-rw-r--r--doc/manpage.d/ipsec_lwdnsq.8.html400
-rw-r--r--doc/manpage.d/ipsec_mailkey.8.html97
-rw-r--r--doc/manpage.d/ipsec_manual.8.html414
-rw-r--r--doc/manpage.d/ipsec_maskof.3.html238
-rw-r--r--doc/manpage.d/ipsec_masktobits.3.html122
-rw-r--r--doc/manpage.d/ipsec_masktocount.3.html238
-rw-r--r--doc/manpage.d/ipsec_networkof.3.html238
-rw-r--r--doc/manpage.d/ipsec_newhostkey.8.html196
-rw-r--r--doc/manpage.d/ipsec_optionsfrom.3.html275
-rw-r--r--doc/manpage.d/ipsec_pf_key.5.html176
-rw-r--r--doc/manpage.d/ipsec_pf_key.8.html122
-rw-r--r--doc/manpage.d/ipsec_pluto.8.html1824
-rw-r--r--doc/manpage.d/ipsec_portof.3.html143
-rw-r--r--doc/manpage.d/ipsec_prng.3.html204
-rw-r--r--doc/manpage.d/ipsec_prng_bytes.3.html204
-rw-r--r--doc/manpage.d/ipsec_prng_final.3.html204
-rw-r--r--doc/manpage.d/ipsec_prng_init.3.html204
-rw-r--r--doc/manpage.d/ipsec_ranbits.8.html147
-rw-r--r--doc/manpage.d/ipsec_rangetoa.3.html294
-rw-r--r--doc/manpage.d/ipsec_rangetosubnet.3.html116
-rw-r--r--doc/manpage.d/ipsec_rsasigkey.8.html401
-rw-r--r--doc/manpage.d/ipsec_sameaddr.3.html274
-rw-r--r--doc/manpage.d/ipsec_sameaddrtype.3.html274
-rw-r--r--doc/manpage.d/ipsec_samesaid.3.html274
-rw-r--r--doc/manpage.d/ipsec_samesubnet.3.html274
-rw-r--r--doc/manpage.d/ipsec_samesubnettype.3.html274
-rw-r--r--doc/manpage.d/ipsec_satoa.3.html347
-rw-r--r--doc/manpage.d/ipsec_satot.3.html453
-rw-r--r--doc/manpage.d/ipsec_send-pr.8.html427
-rw-r--r--doc/manpage.d/ipsec_setportof.3.html143
-rw-r--r--doc/manpage.d/ipsec_setup.8.html237
-rw-r--r--doc/manpage.d/ipsec_showdefaults.8.html82
-rw-r--r--doc/manpage.d/ipsec_showhostkey.8.html269
-rw-r--r--doc/manpage.d/ipsec_showpolicy.8.html88
-rw-r--r--doc/manpage.d/ipsec_sockaddrlenof.3.html143
-rw-r--r--doc/manpage.d/ipsec_sockaddrof.3.html143
-rw-r--r--doc/manpage.d/ipsec_spi.5.html305
-rw-r--r--doc/manpage.d/ipsec_spi.8.html790
-rw-r--r--doc/manpage.d/ipsec_spigrp.5.html193
-rw-r--r--doc/manpage.d/ipsec_spigrp.8.html280
-rw-r--r--doc/manpage.d/ipsec_splitkeytoid.3.html174
-rw-r--r--doc/manpage.d/ipsec_subnetinsubnet.3.html274
-rw-r--r--doc/manpage.d/ipsec_subnetishost.3.html274
-rw-r--r--doc/manpage.d/ipsec_subnetof.3.html107
-rw-r--r--doc/manpage.d/ipsec_subnettoa.3.html448
-rw-r--r--doc/manpage.d/ipsec_subnettot.3.html569
-rw-r--r--doc/manpage.d/ipsec_subnettypeof.3.html238
-rw-r--r--doc/manpage.d/ipsec_tnatoaddr.3.html569
-rw-r--r--doc/manpage.d/ipsec_tncfg.5.html175
-rw-r--r--doc/manpage.d/ipsec_tncfg.8.html195
-rw-r--r--doc/manpage.d/ipsec_trap_count.5.html74
-rw-r--r--doc/manpage.d/ipsec_trap_sendcount.5.html72
-rw-r--r--doc/manpage.d/ipsec_ttoaddr.3.html569
-rw-r--r--doc/manpage.d/ipsec_ttodata.3.html439
-rw-r--r--doc/manpage.d/ipsec_ttosa.3.html453
-rw-r--r--doc/manpage.d/ipsec_ttosubnet.3.html569
-rw-r--r--doc/manpage.d/ipsec_ttoul.3.html310
-rw-r--r--doc/manpage.d/ipsec_ultoa.3.html266
-rw-r--r--doc/manpage.d/ipsec_ultot.3.html310
-rw-r--r--doc/manpage.d/ipsec_unspecaddr.3.html166
-rw-r--r--doc/manpage.d/ipsec_verify.8.html107
-rw-r--r--doc/manpage.d/ipsec_version.3.html94
-rw-r--r--doc/manpage.d/ipsec_version.5.html103
-rw-r--r--doc/manpage.d/ipsec_version_code.3.html94
-rw-r--r--doc/manpage.d/ipsec_version_string.3.html94
-rw-r--r--doc/manpage.d/ipsec_whack.8.html1824
-rw-r--r--doc/manpages.html145
-rw-r--r--doc/nightly.html125
-rw-r--r--doc/oppimpl.txt514
-rw-r--r--doc/opportunism-spec.txt1254
-rw-r--r--doc/opportunism.howto415
-rw-r--r--doc/opportunism.known-issues287
-rw-r--r--doc/opportunism.nr1115
-rw-r--r--doc/performance.html458
-rw-r--r--doc/policygroups.html341
-rw-r--r--doc/politics.html1231
-rw-r--r--doc/quickstart.html323
-rw-r--r--doc/rfc.html135
-rw-r--r--doc/roadmap.html167
-rw-r--r--doc/src/.cvsignore3
-rw-r--r--doc/src/adv_config.html1412
-rw-r--r--doc/src/background.html376
-rw-r--r--doc/src/biblio.html354
-rw-r--r--doc/src/buildtools.html27
-rw-r--r--doc/src/compat.html795
-rw-r--r--doc/src/config.html394
-rw-r--r--doc/src/crosscompile.html105
-rw-r--r--doc/src/draft-richardson-ipsec-opportunistic.html2456
-rw-r--r--doc/src/draft-richardson-ipsec-opportunistic.xml2519
-rw-r--r--doc/src/draft-richardson-ipsec-rr.html659
-rw-r--r--doc/src/draft-richardson-ipsec-rr.xml560
-rw-r--r--doc/src/faq.html2770
-rw-r--r--doc/src/firewall.html895
-rw-r--r--doc/src/forwardingstate.txt35
-rw-r--r--doc/src/glossary.html2257
-rw-r--r--doc/src/index.html55
-rw-r--r--doc/src/initiatorstate.txt66
-rw-r--r--doc/src/install.html378
-rw-r--r--doc/src/interop.html1802
-rw-r--r--doc/src/intro.html887
-rw-r--r--doc/src/ipsec.html1206
-rw-r--r--doc/src/kernel.html392
-rw-r--r--doc/src/mail.html250
-rw-r--r--doc/src/makecheck.html684
-rw-r--r--doc/src/manpages.html155
-rw-r--r--doc/src/nightly.html164
-rwxr-xr-xdoc/src/performance.html576
-rw-r--r--doc/src/policy-groups-table.html297
-rw-r--r--doc/src/policygroups.html489
-rw-r--r--doc/src/politics.html1466
-rw-r--r--doc/src/quickstart-configs.html144
-rw-r--r--doc/src/quickstart-firewall.html187
-rw-r--r--doc/src/quickstart.html458
-rw-r--r--doc/src/reference.ESPUDP.xml34
-rw-r--r--doc/src/reference.KEYRESTRICT.xml31
-rw-r--r--doc/src/reference.MODPGROUPS.xml32
-rw-r--r--doc/src/reference.OEspec.xml45
-rw-r--r--doc/src/reference.RFC.3526.xml32
-rw-r--r--doc/src/responderstate.txt43
-rw-r--r--doc/src/rfc.html158
-rw-r--r--doc/src/roadmap.html203
-rw-r--r--doc/src/testing.html395
-rw-r--r--doc/src/testingtools.html188
-rw-r--r--doc/src/trouble.html840
-rw-r--r--doc/src/uml-rhroot-list.txt91
-rw-r--r--doc/src/uml-rhroot.html116
-rw-r--r--doc/src/uml-stack-trace.html129
-rw-r--r--doc/src/umltesting.html478
-rw-r--r--doc/src/upgrading.html260
-rwxr-xr-xdoc/src/user_examples.html322
-rw-r--r--doc/src/web.html905
-rw-r--r--doc/testing.html332
-rw-r--r--doc/toc.html1019
-rw-r--r--doc/trouble.html706
-rw-r--r--doc/umltesting.html313
-rw-r--r--doc/upgrading.html184
-rw-r--r--doc/user_examples.html320
-rw-r--r--doc/utils/cleanhtml.sed1
-rwxr-xr-xdoc/utils/cleanhtml.sh12
-rw-r--r--doc/utils/contents.awk109
-rw-r--r--doc/utils/four2perm.120
-rw-r--r--doc/utils/four2perm.c140
-rw-r--r--doc/utils/html2four.126
-rw-r--r--doc/utils/html2four.c298
-rw-r--r--doc/utils/html2txt.sed86
-rw-r--r--doc/utils/killtoodeepcontents.pl59
-rwxr-xr-xdoc/utils/man2html.script48
-rw-r--r--doc/utils/man_xref.c125
-rwxr-xr-xdoc/utils/mkhtmlman44
-rw-r--r--doc/utils/perm1.awk1
-rw-r--r--doc/utils/perm2.awk46
-rw-r--r--doc/utils/rfc_pg.c76
-rw-r--r--doc/utils/xref.sed56
-rw-r--r--doc/web.html749
-rw-r--r--lib/.cvsignore2
-rw-r--r--lib/COPYING.LIB481
-rw-r--r--lib/Makefile41
-rw-r--r--lib/Makefile.kernel65
-rw-r--r--lib/README3
-rw-r--r--lib/libcrypto/include/cbc_generic.h110
-rw-r--r--lib/libcrypto/include/hmac_generic.h60
-rw-r--r--lib/libcrypto/include/md32_common.h607
-rw-r--r--lib/libcrypto/libaes/Makefile40
-rw-r--r--lib/libcrypto/libaes/aes.c1415
-rw-r--r--lib/libcrypto/libaes/aes.h97
-rw-r--r--lib/libcrypto/libaes/aes_cbc.c13
-rw-r--r--lib/libcrypto/libaes/aes_cbc.h4
-rw-r--r--lib/libcrypto/libaes/aes_xcbc_mac.c67
-rw-r--r--lib/libcrypto/libaes/aes_xcbc_mac.h12
-rw-r--r--lib/libcrypto/libaes/asm/aes-i586.S892
-rw-r--r--lib/libcrypto/libaes/test_main.c41
-rw-r--r--lib/libcrypto/libaes/test_main_mac.c30
-rw-r--r--lib/libcrypto/libblowfish/COPYRIGHT46
-rw-r--r--lib/libcrypto/libblowfish/INSTALL14
-rw-r--r--lib/libcrypto/libblowfish/Makefile121
-rw-r--r--lib/libcrypto/libblowfish/Makefile.ssl118
-rw-r--r--lib/libcrypto/libblowfish/README8
-rw-r--r--lib/libcrypto/libblowfish/VERSION6
-rw-r--r--lib/libcrypto/libblowfish/asm/bf-586.pl136
-rw-r--r--lib/libcrypto/libblowfish/asm/bf-686.pl127
-rw-r--r--lib/libcrypto/libblowfish/asm/readme10
-rw-r--r--lib/libcrypto/libblowfish/bf_enc.c306
-rw-r--r--lib/libcrypto/libblowfish/bf_locl.h218
-rw-r--r--lib/libcrypto/libblowfish/bf_pi.h325
-rw-r--r--lib/libcrypto/libblowfish/bf_skey.c122
-rw-r--r--lib/libcrypto/libblowfish/blowfish.h133
-rw-r--r--lib/libcrypto/libserpent/Makefile20
-rw-r--r--lib/libcrypto/libserpent/serpent.c995
-rw-r--r--lib/libcrypto/libserpent/serpent.h17
-rw-r--r--lib/libcrypto/libserpent/serpent_cbc.c8
-rw-r--r--lib/libcrypto/libserpent/serpent_cbc.h3
-rw-r--r--lib/libcrypto/libserpent/test_main.c34
-rw-r--r--lib/libcrypto/libsha2/Makefile21
-rw-r--r--lib/libcrypto/libsha2/hmac_sha2.c32
-rw-r--r--lib/libcrypto/libsha2/hmac_sha2.h17
-rw-r--r--lib/libcrypto/libsha2/sha2.c437
-rw-r--r--lib/libcrypto/libsha2/sha2.h52
-rw-r--r--lib/libcrypto/libtwofish/Makefile21
-rw-r--r--lib/libcrypto/libtwofish/test_main.c34
-rw-r--r--lib/libcrypto/libtwofish/twofish.c861
-rw-r--r--lib/libcrypto/libtwofish/twofish.h20
-rw-r--r--lib/libcrypto/libtwofish/twofish_cbc.c8
-rw-r--r--lib/libcrypto/libtwofish/twofish_cbc.h3
-rw-r--r--lib/libcrypto/perlasm/LICENSE127
-rw-r--r--lib/libcrypto/perlasm/alpha.pl434
-rw-r--r--lib/libcrypto/perlasm/cbc.pl342
-rw-r--r--lib/libcrypto/perlasm/readme124
-rw-r--r--lib/libcrypto/perlasm/version5
-rw-r--r--lib/libcrypto/perlasm/x86asm.pl118
-rw-r--r--lib/libcrypto/perlasm/x86ms.pl365
-rw-r--r--lib/libcrypto/perlasm/x86nasm.pl366
-rw-r--r--lib/libcrypto/perlasm/x86unix.pl472
-rw-r--r--lib/libdes/.cvsignore3
-rw-r--r--lib/libdes/Makefile245
-rw-r--r--lib/libfreeswan/.cvsignore9
-rw-r--r--lib/libfreeswan/Makefile174
-rw-r--r--lib/libipsecpolicy/.cvsignore1
-rw-r--r--lib/libipsecpolicy/Makefile96
-rw-r--r--lib/libipsecpolicy/cgipolicy.c77
-rw-r--r--lib/libipsecpolicy/libipsecpolicy.h4
-rw-r--r--lib/libipsecpolicy/policyquery.c167
-rw-r--r--lib/libipsecpolicy/version.in.c38
-rw-r--r--lib/liblwres/Makefile73
-rw-r--r--lib/liblwres/api3
-rw-r--r--lib/liblwres/assert_p.h33
-rw-r--r--lib/liblwres/async.c361
-rw-r--r--lib/liblwres/config.h0
-rw-r--r--lib/liblwres/context.c380
-rw-r--r--lib/liblwres/context_p.h68
-rw-r--r--lib/liblwres/gai_strerror.c52
-rw-r--r--lib/liblwres/getaddrinfo.c692
-rw-r--r--lib/liblwres/gethost.c219
-rw-r--r--lib/liblwres/getipnode.c839
-rw-r--r--lib/liblwres/getnameinfo.c289
-rw-r--r--lib/liblwres/getrrset.c211
-rw-r--r--lib/liblwres/getrrset2.c97
-rw-r--r--lib/liblwres/herror.c101
-rw-r--r--lib/liblwres/include/lwres/async.h78
-rw-r--r--lib/liblwres/include/lwres/context.h133
-rw-r--r--lib/liblwres/include/lwres/int.h32
-rw-r--r--lib/liblwres/include/lwres/ipv6.h118
-rw-r--r--lib/liblwres/include/lwres/lang.h31
-rw-r--r--lib/liblwres/include/lwres/list.h119
-rw-r--r--lib/liblwres/include/lwres/lwbuffer.h402
-rw-r--r--lib/liblwres/include/lwres/lwpacket.h124
-rw-r--r--lib/liblwres/include/lwres/lwres.h584
-rw-r--r--lib/liblwres/include/lwres/netdb.h522
-rw-r--r--lib/liblwres/include/lwres/netdb.h.in518
-rw-r--r--lib/liblwres/include/lwres/platform.h91
-rw-r--r--lib/liblwres/include/lwres/platform.h.in91
-rw-r--r--lib/liblwres/include/lwres/result.h40
-rw-r--r--lib/liblwres/lwbuffer.c287
-rw-r--r--lib/liblwres/lwconfig.c703
-rw-r--r--lib/liblwres/lwinetaton.c203
-rw-r--r--lib/liblwres/lwinetntop.c191
-rw-r--r--lib/liblwres/lwinetpton.c206
-rw-r--r--lib/liblwres/lwpacket.c85
-rw-r--r--lib/liblwres/lwres_gabn.c415
-rw-r--r--lib/liblwres/lwres_gnba.c328
-rw-r--r--lib/liblwres/lwres_grbn.c416
-rw-r--r--lib/liblwres/lwres_noop.c255
-rw-r--r--lib/liblwres/lwresutil.c491
-rw-r--r--lib/liblwres/man/Makefile.in232
-rw-r--r--lib/liblwres/man/lwres.3158
-rw-r--r--lib/liblwres/man/lwres.docbook244
-rw-r--r--lib/liblwres/man/lwres.html444
-rw-r--r--lib/liblwres/man/lwres_buffer.3277
-rw-r--r--lib/liblwres/man/lwres_buffer.docbook378
-rw-r--r--lib/liblwres/man/lwres_buffer.html608
-rw-r--r--lib/liblwres/man/lwres_config.3105
-rw-r--r--lib/liblwres/man/lwres_config.docbook159
-rw-r--r--lib/liblwres/man/lwres_config.html295
-rw-r--r--lib/liblwres/man/lwres_context.3194
-rw-r--r--lib/liblwres/man/lwres_context.docbook283
-rw-r--r--lib/liblwres/man/lwres_context.html519
-rw-r--r--lib/liblwres/man/lwres_gabn.3193
-rw-r--r--lib/liblwres/man/lwres_gabn.docbook255
-rw-r--r--lib/liblwres/man/lwres_gabn.html442
-rw-r--r--lib/liblwres/man/lwres_gai_strerror.386
-rw-r--r--lib/liblwres/man/lwres_gai_strerror.docbook161
-rw-r--r--lib/liblwres/man/lwres_gai_strerror.html294
-rw-r--r--lib/liblwres/man/lwres_getaddrinfo.3247
-rw-r--r--lib/liblwres/man/lwres_getaddrinfo.docbook372
-rw-r--r--lib/liblwres/man/lwres_getaddrinfo.html722
-rw-r--r--lib/liblwres/man/lwres_gethostent.3270
-rw-r--r--lib/liblwres/man/lwres_gethostent.docbook407
-rw-r--r--lib/liblwres/man/lwres_gethostent.html827
-rw-r--r--lib/liblwres/man/lwres_getipnode.3187
-rw-r--r--lib/liblwres/man/lwres_getipnode.docbook307
-rw-r--r--lib/liblwres/man/lwres_getipnode.html529
-rw-r--r--lib/liblwres/man/lwres_getnameinfo.384
-rw-r--r--lib/liblwres/man/lwres_getnameinfo.docbook154
-rw-r--r--lib/liblwres/man/lwres_getnameinfo.html303
-rw-r--r--lib/liblwres/man/lwres_getrrsetbyname.3142
-rw-r--r--lib/liblwres/man/lwres_getrrsetbyname.docbook208
-rw-r--r--lib/liblwres/man/lwres_getrrsetbyname.html371
-rw-r--r--lib/liblwres/man/lwres_gnba.3186
-rw-r--r--lib/liblwres/man/lwres_gnba.docbook259
-rw-r--r--lib/liblwres/man/lwres_gnba.html408
-rw-r--r--lib/liblwres/man/lwres_hstrerror.367
-rw-r--r--lib/liblwres/man/lwres_hstrerror.docbook124
-rw-r--r--lib/liblwres/man/lwres_hstrerror.html242
-rw-r--r--lib/liblwres/man/lwres_inetntop.352
-rw-r--r--lib/liblwres/man/lwres_inetntop.docbook99
-rw-r--r--lib/liblwres/man/lwres_inetntop.html186
-rw-r--r--lib/liblwres/man/lwres_noop.3160
-rw-r--r--lib/liblwres/man/lwres_noop.docbook229
-rw-r--r--lib/liblwres/man/lwres_noop.html409
-rw-r--r--lib/liblwres/man/lwres_packet.3149
-rw-r--r--lib/liblwres/man/lwres_packet.docbook218
-rw-r--r--lib/liblwres/man/lwres_packet.html373
-rw-r--r--lib/liblwres/man/lwres_resutil.3151
-rw-r--r--lib/liblwres/man/lwres_resutil.docbook221
-rw-r--r--lib/liblwres/man/lwres_resutil.html412
-rw-r--r--lib/liblwres/unix/include/lwres/net.h127
-rw-r--r--lib/liblwres/version.c24
-rw-r--r--linux/Documentation/Configure.help.fs2_0.patch65
-rw-r--r--linux/Documentation/Configure.help.fs2_2.patch70
-rw-r--r--linux/Documentation/Configure.help.fs2_4.patch69
-rw-r--r--linux/Makefile32
-rw-r--r--linux/README.freeswan177
-rw-r--r--linux/crypto/ciphers/des/COPYRIGHT50
-rw-r--r--linux/crypto/ciphers/des/INSTALL69
-rw-r--r--linux/crypto/ciphers/des/Makefile.objs20
-rw-r--r--linux/crypto/ciphers/des/README54
-rw-r--r--linux/crypto/ciphers/des/README.freeswan33
-rw-r--r--linux/crypto/ciphers/des/VERSION406
-rw-r--r--linux/crypto/ciphers/des/asm/crypt586.pl204
-rw-r--r--linux/crypto/ciphers/des/asm/des-586.pl251
-rw-r--r--linux/crypto/ciphers/des/asm/des686.pl230
-rw-r--r--linux/crypto/ciphers/des/asm/desboth.pl79
-rw-r--r--linux/crypto/ciphers/des/asm/perlasm/cbc.pl342
-rw-r--r--linux/crypto/ciphers/des/asm/perlasm/readme124
-rw-r--r--linux/crypto/ciphers/des/asm/perlasm/x86asm.pl111
-rw-r--r--linux/crypto/ciphers/des/asm/perlasm/x86ms.pl345
-rw-r--r--linux/crypto/ciphers/des/asm/perlasm/x86unix.pl403
-rw-r--r--linux/crypto/ciphers/des/asm/readme131
-rw-r--r--linux/crypto/ciphers/des/cbc_enc.c135
-rw-r--r--linux/crypto/ciphers/des/des.doc505
-rw-r--r--linux/crypto/ciphers/des/des_crypt.man508
-rw-r--r--linux/crypto/ciphers/des/des_enc.c502
-rw-r--r--linux/crypto/ciphers/des/des_locl.h515
-rw-r--r--linux/crypto/ciphers/des/des_opts.c620
-rw-r--r--linux/crypto/ciphers/des/des_ver.h60
-rw-r--r--linux/crypto/ciphers/des/destest.c871
-rw-r--r--linux/crypto/ciphers/des/dx86unix.S3160
-rw-r--r--linux/crypto/ciphers/des/ecb_enc.c128
-rw-r--r--linux/crypto/ciphers/des/fcrypt.c152
-rw-r--r--linux/crypto/ciphers/des/fcrypt_b.c148
-rw-r--r--linux/crypto/ciphers/des/options.txt39
-rw-r--r--linux/crypto/ciphers/des/podd.h75
-rw-r--r--linux/crypto/ciphers/des/set_key.c246
-rw-r--r--linux/crypto/ciphers/des/sk.h204
-rw-r--r--linux/crypto/ciphers/des/speed.c329
-rw-r--r--linux/crypto/ciphers/des/spr.h204
-rw-r--r--linux/include/crypto/des.h308
-rw-r--r--linux/include/freeswan.h477
-rw-r--r--linux/include/freeswan/ipcomp.h61
-rw-r--r--linux/include/freeswan/ipsec_ah.h235
-rw-r--r--linux/include/freeswan/ipsec_alg.h254
-rw-r--r--linux/include/freeswan/ipsec_encap.h143
-rw-r--r--linux/include/freeswan/ipsec_eroute.h103
-rw-r--r--linux/include/freeswan/ipsec_errs.h53
-rw-r--r--linux/include/freeswan/ipsec_esp.h220
-rw-r--r--linux/include/freeswan/ipsec_ipe4.h68
-rw-r--r--linux/include/freeswan/ipsec_kversion.h227
-rw-r--r--linux/include/freeswan/ipsec_life.h112
-rw-r--r--linux/include/freeswan/ipsec_md5h.h140
-rw-r--r--linux/include/freeswan/ipsec_param.h226
-rw-r--r--linux/include/freeswan/ipsec_policy.h225
-rw-r--r--linux/include/freeswan/ipsec_proto.h111
-rw-r--r--linux/include/freeswan/ipsec_radij.h63
-rw-r--r--linux/include/freeswan/ipsec_rcv.h196
-rw-r--r--linux/include/freeswan/ipsec_sa.h338
-rw-r--r--linux/include/freeswan/ipsec_sha1.h79
-rw-r--r--linux/include/freeswan/ipsec_stats.h38
-rw-r--r--linux/include/freeswan/ipsec_tunnel.h265
-rw-r--r--linux/include/freeswan/ipsec_xform.h274
-rw-r--r--linux/include/freeswan/ipsec_xmit.h140
-rw-r--r--linux/include/freeswan/radij.h280
-rw-r--r--linux/include/mast.h33
-rw-r--r--linux/include/pfkey.h498
-rw-r--r--linux/include/pfkeyv2.h385
-rw-r--r--linux/include/zlib/zlib.h893
-rw-r--r--linux/include/zlib/zutil.h225
-rw-r--r--linux/lib/libfreeswan/Makefile.objs18
-rw-r--r--linux/lib/libfreeswan/addrtoa.c68
-rw-r--r--linux/lib/libfreeswan/addrtot.c302
-rw-r--r--linux/lib/libfreeswan/addrtypeof.c94
-rw-r--r--linux/lib/libfreeswan/anyaddr.387
-rw-r--r--linux/lib/libfreeswan/anyaddr.c146
-rw-r--r--linux/lib/libfreeswan/atoaddr.3294
-rw-r--r--linux/lib/libfreeswan/atoaddr.c238
-rw-r--r--linux/lib/libfreeswan/atoasr.3186
-rw-r--r--linux/lib/libfreeswan/atoasr.c212
-rw-r--r--linux/lib/libfreeswan/atosa.3218
-rw-r--r--linux/lib/libfreeswan/atosa.c200
-rw-r--r--linux/lib/libfreeswan/atosubnet.c216
-rw-r--r--linux/lib/libfreeswan/atoul.3161
-rw-r--r--linux/lib/libfreeswan/atoul.c90
-rw-r--r--linux/lib/libfreeswan/copyright.c56
-rw-r--r--linux/lib/libfreeswan/datatot.c233
-rw-r--r--linux/lib/libfreeswan/goodmask.357
-rw-r--r--linux/lib/libfreeswan/goodmask.c97
-rw-r--r--linux/lib/libfreeswan/initaddr.3129
-rw-r--r--linux/lib/libfreeswan/initaddr.c51
-rw-r--r--linux/lib/libfreeswan/initsaid.c33
-rw-r--r--linux/lib/libfreeswan/initsubnet.3137
-rw-r--r--linux/lib/libfreeswan/initsubnet.c95
-rw-r--r--linux/lib/libfreeswan/internal.h81
-rw-r--r--linux/lib/libfreeswan/keyblobtoid.3103
-rw-r--r--linux/lib/libfreeswan/keyblobtoid.c148
-rw-r--r--linux/lib/libfreeswan/optionsfrom.3182
-rw-r--r--linux/lib/libfreeswan/optionsfrom.c301
-rw-r--r--linux/lib/libfreeswan/pfkey_v2_build.c1438
-rw-r--r--linux/lib/libfreeswan/pfkey_v2_debug.c179
-rw-r--r--linux/lib/libfreeswan/pfkey_v2_ext_bits.c803
-rw-r--r--linux/lib/libfreeswan/pfkey_v2_parse.c1832
-rw-r--r--linux/lib/libfreeswan/portof.370
-rw-r--r--linux/lib/libfreeswan/portof.c96
-rw-r--r--linux/lib/libfreeswan/prng.3121
-rw-r--r--linux/lib/libfreeswan/prng.c202
-rw-r--r--linux/lib/libfreeswan/rangetoa.c61
-rw-r--r--linux/lib/libfreeswan/rangetosubnet.359
-rw-r--r--linux/lib/libfreeswan/rangetosubnet.c226
-rw-r--r--linux/lib/libfreeswan/sameaddr.3165
-rw-r--r--linux/lib/libfreeswan/sameaddr.c190
-rw-r--r--linux/lib/libfreeswan/satoa.c102
-rw-r--r--linux/lib/libfreeswan/satot.c132
-rw-r--r--linux/lib/libfreeswan/subnetof.347
-rw-r--r--linux/lib/libfreeswan/subnetof.c60
-rw-r--r--linux/lib/libfreeswan/subnettoa.c62
-rw-r--r--linux/lib/libfreeswan/subnettot.c56
-rw-r--r--linux/lib/libfreeswan/subnettypeof.c109
-rw-r--r--linux/lib/libfreeswan/ttoaddr.3377
-rw-r--r--linux/lib/libfreeswan/ttoaddr.c426
-rw-r--r--linux/lib/libfreeswan/ttodata.3281
-rw-r--r--linux/lib/libfreeswan/ttodata.c722
-rw-r--r--linux/lib/libfreeswan/ttoprotoport.c103
-rw-r--r--linux/lib/libfreeswan/ttosa.3288
-rw-r--r--linux/lib/libfreeswan/ttosa.c280
-rw-r--r--linux/lib/libfreeswan/ttosubnet.c296
-rw-r--r--linux/lib/libfreeswan/ttoul.3192
-rw-r--r--linux/lib/libfreeswan/ttoul.c91
-rw-r--r--linux/lib/libfreeswan/ultoa.c67
-rw-r--r--linux/lib/libfreeswan/ultot.c83
-rw-r--r--linux/lib/libfreeswan/version.344
-rw-r--r--linux/lib/libfreeswan/version.in.c44
-rw-r--r--linux/lib/zlib/Makefile121
-rw-r--r--linux/lib/zlib/Makefile.objs27
-rw-r--r--linux/lib/zlib/README147
-rw-r--r--linux/lib/zlib/README.freeswan13
-rw-r--r--linux/lib/zlib/adler32.c49
-rw-r--r--linux/lib/zlib/deflate.c1351
-rw-r--r--linux/lib/zlib/deflate.h318
-rw-r--r--linux/lib/zlib/infblock.c403
-rw-r--r--linux/lib/zlib/infblock.h39
-rw-r--r--linux/lib/zlib/infcodes.c251
-rw-r--r--linux/lib/zlib/infcodes.h31
-rw-r--r--linux/lib/zlib/inffast.c183
-rw-r--r--linux/lib/zlib/inffast.h22
-rw-r--r--linux/lib/zlib/inffixed.h151
-rw-r--r--linux/lib/zlib/inflate.c368
-rw-r--r--linux/lib/zlib/inftrees.c454
-rw-r--r--linux/lib/zlib/inftrees.h63
-rw-r--r--linux/lib/zlib/infutil.c87
-rw-r--r--linux/lib/zlib/infutil.h98
-rw-r--r--linux/lib/zlib/match586.S357
-rw-r--r--linux/lib/zlib/match686.S330
-rw-r--r--linux/lib/zlib/trees.c1214
-rw-r--r--linux/lib/zlib/trees.h128
-rw-r--r--linux/lib/zlib/zconf.h309
-rw-r--r--linux/lib/zlib/zutil.c227
-rw-r--r--linux/net/Config.in.fs2_0.patch12
-rw-r--r--linux/net/Config.in.fs2_2.patch12
-rw-r--r--linux/net/Config.in.fs2_4.patch13
-rw-r--r--linux/net/Makefile.fs2_0.patch20
-rw-r--r--linux/net/Makefile.fs2_2.patch20
-rw-r--r--linux/net/Makefile.fs2_4.ipsec_alg.patch10
-rw-r--r--linux/net/Makefile.fs2_4.patch11
-rw-r--r--linux/net/include.net.sock.h.fs2_2.patch25
-rw-r--r--linux/net/include.net.sock.h.fs2_4.patch27
-rw-r--r--linux/net/ipsec/.cvsignore47
-rw-r--r--linux/net/ipsec/Config.in41
-rw-r--r--linux/net/ipsec/Makefile529
-rw-r--r--linux/net/ipsec/Makefile.algtest125
-rw-r--r--linux/net/ipsec/alg/Config.alg_aes.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_blowfish.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_cryptoapi.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_serpent.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_sha2.in3
-rw-r--r--linux/net/ipsec/alg/Config.alg_twofish.in3
-rw-r--r--linux/net/ipsec/alg/Config.in7
-rw-r--r--linux/net/ipsec/alg/Makefile112
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_aes23
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_blowfish23
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_cryptoapi14
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_serpent21
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_sha222
-rw-r--r--linux/net/ipsec/alg/Makefile.alg_twofish21
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_aes.c253
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_blowfish.c142
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_cryptoapi.c421
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_serpent.c139
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_sha2.c185
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_twofish.c138
-rw-r--r--linux/net/ipsec/alg/scripts/mk-static_init.c.sh18
-rw-r--r--linux/net/ipsec/defconfig140
-rw-r--r--linux/net/ipsec/ipcomp.c725
-rw-r--r--linux/net/ipsec/ipsec_alg.c927
-rw-r--r--linux/net/ipsec/ipsec_init.c755
-rw-r--r--linux/net/ipsec/ipsec_life.c210
-rw-r--r--linux/net/ipsec/ipsec_mast.c1064
-rw-r--r--linux/net/ipsec/ipsec_md5c.c448
-rw-r--r--linux/net/ipsec/ipsec_proc.c1003
-rw-r--r--linux/net/ipsec/ipsec_radij.c550
-rw-r--r--linux/net/ipsec/ipsec_rcv.c2204
-rw-r--r--linux/net/ipsec/ipsec_sa.c1031
-rw-r--r--linux/net/ipsec/ipsec_sha1.c219
-rw-r--r--linux/net/ipsec/ipsec_tunnel.c1671
-rw-r--r--linux/net/ipsec/ipsec_xform.c73
-rw-r--r--linux/net/ipsec/ipsec_xmit.c1782
-rw-r--r--linux/net/ipsec/pfkey_v2.c2125
-rw-r--r--linux/net/ipsec/pfkey_v2_ext_process.c851
-rw-r--r--linux/net/ipsec/pfkey_v2_parser.c3420
-rw-r--r--linux/net/ipsec/radij.c992
-rw-r--r--linux/net/ipsec/sysctl_net_ipsec.c196
-rw-r--r--linux/net/ipsec/tagsfile.mak6
-rw-r--r--linux/net/ipv4/af_inet.c.fs2_0.patch21
-rw-r--r--linux/net/ipv4/af_inet.c.fs2_2.patch21
-rw-r--r--linux/net/ipv4/af_inet.c.fs2_4.patch21
-rw-r--r--linux/net/ipv4/udp.c.fs2_2.patch108
-rw-r--r--linux/net/ipv4/udp.c.fs2_4.patch107
-rw-r--r--packaging/ipkg/conffiles1
-rw-r--r--packaging/ipkg/control-freeswan-module.dist8
-rw-r--r--packaging/ipkg/control-freeswan.dist8
-rw-r--r--packaging/ipkg/debian-binary1
-rwxr-xr-xpackaging/ipkg/generate-ipkg43
-rw-r--r--packaging/linus/config-all.h62
-rw-r--r--packaging/makefiles/module.make5
-rw-r--r--packaging/redhat/.cvsignore12
-rw-r--r--packaging/redhat/Makefile100
-rw-r--r--packaging/redhat/config-athlon-smp.h79
-rw-r--r--packaging/redhat/config-athlon.h79
-rw-r--r--packaging/redhat/config-i386-smp.h79
-rw-r--r--packaging/redhat/config-i386.h79
-rw-r--r--packaging/redhat/config-i586-smp.h79
-rw-r--r--packaging/redhat/config-i586-up.h79
-rw-r--r--packaging/redhat/config-i586.h79
-rw-r--r--packaging/redhat/config-i686-bigmem.h78
-rw-r--r--packaging/redhat/config-i686-smp.h79
-rw-r--r--packaging/redhat/config-i686.h79
-rw-r--r--packaging/redhat/freeswan.spec176
-rw-r--r--packaging/redhat/kernel-list.txt9
-rw-r--r--packaging/redhat/rpm.in149
-rwxr-xr-xpackaging/utils/backup80
-rwxr-xr-xpackaging/utils/branch70
-rwxr-xr-xpackaging/utils/canrel55
-rw-r--r--packaging/utils/disttools.pl357
-rwxr-xr-xpackaging/utils/errcheck40
-rw-r--r--packaging/utils/kernel.patch.gen.sh52
-rwxr-xr-xpackaging/utils/kerneldiff35
-rwxr-xr-xpackaging/utils/kernelpatch55
-rwxr-xr-xpackaging/utils/kernelversion10
-rwxr-xr-xpackaging/utils/kernelversion-short8
-rwxr-xr-xpackaging/utils/manlink74
-rwxr-xr-xpackaging/utils/maysnap41
-rwxr-xr-xpackaging/utils/maytest42
-rwxr-xr-xpackaging/utils/mkcand126
-rwxr-xr-xpackaging/utils/mkrel95
-rwxr-xr-xpackaging/utils/mksnap114
-rwxr-xr-xpackaging/utils/mvcand62
-rwxr-xr-xpackaging/utils/mvrel65
-rwxr-xr-xpackaging/utils/patcher188
-rwxr-xr-xpackaging/utils/prepcand33
-rwxr-xr-xpackaging/utils/recan17
-rwxr-xr-xpackaging/utils/setup9
-rwxr-xr-xpackaging/utils/sshenv4
-rwxr-xr-xpackaging/utils/tattle33
-rwxr-xr-xpackaging/utils/wantsnap3
-rwxr-xr-xpackaging/utils/wanttest10
-rw-r--r--programs/Makefile46
-rw-r--r--programs/Makefile.program150
-rw-r--r--programs/_confread/.cvsignore7
-rw-r--r--programs/_confread/Makefile27
-rw-r--r--programs/_confread/README.conf.V2103
-rw-r--r--programs/_confread/_confread.828
-rwxr-xr-xprograms/_confread/_confread.in520
-rw-r--r--programs/_confread/block.in8
-rw-r--r--programs/_confread/clear-or-private.in8
-rw-r--r--programs/_confread/clear.in7
-rw-r--r--programs/_confread/ipsec.conf.51286
-rw-r--r--programs/_confread/ipsec.conf.in44
-rw-r--r--programs/_confread/private-or-clear.in14
-rw-r--r--programs/_confread/private.in6
-rwxr-xr-xprograms/_confread/randomize28
-rw-r--r--programs/_copyright/.cvsignore1
-rw-r--r--programs/_copyright/Makefile44
-rw-r--r--programs/_copyright/_copyright.832
-rw-r--r--programs/_copyright/_copyright.c69
-rw-r--r--programs/_include/.cvsignore1
-rw-r--r--programs/_include/Makefile43
-rw-r--r--programs/_include/_include.835
-rwxr-xr-xprograms/_include/_include.in102
-rw-r--r--programs/_keycensor/.cvsignore1
-rw-r--r--programs/_keycensor/Makefile43
-rw-r--r--programs/_keycensor/_keycensor.833
-rwxr-xr-xprograms/_keycensor/_keycensor.in52
-rw-r--r--programs/_plutoload/.cvsignore1
-rw-r--r--programs/_plutoload/Makefile43
-rw-r--r--programs/_plutoload/_plutoload.833
-rwxr-xr-xprograms/_plutoload/_plutoload.in164
-rw-r--r--programs/_plutorun/.cvsignore1
-rw-r--r--programs/_plutorun/Makefile43
-rw-r--r--programs/_plutorun/_plutorun.837
-rwxr-xr-xprograms/_plutorun/_plutorun.in281
-rw-r--r--programs/_realsetup/.cvsignore1
-rw-r--r--programs/_realsetup/Makefile43
-rw-r--r--programs/_realsetup/_realsetup.836
-rwxr-xr-xprograms/_realsetup/_realsetup.in456
-rw-r--r--programs/_secretcensor/.cvsignore1
-rw-r--r--programs/_secretcensor/Makefile43
-rw-r--r--programs/_secretcensor/_secretcensor.834
-rwxr-xr-xprograms/_secretcensor/_secretcensor.in75
-rw-r--r--programs/_startklips/.cvsignore1
-rw-r--r--programs/_startklips/Makefile43
-rw-r--r--programs/_startklips/_startklips.833
-rwxr-xr-xprograms/_startklips/_startklips.in367
-rw-r--r--programs/_updown/.cvsignore2
-rw-r--r--programs/_updown/Makefile22
-rw-r--r--programs/_updown/_updown.819
-rwxr-xr-xprograms/_updown/_updown.in503
-rw-r--r--programs/_updown_espmark/Makefile22
-rw-r--r--programs/_updown_espmark/_updown_espmark.818
-rw-r--r--programs/_updown_espmark/_updown_espmark.in452
-rw-r--r--programs/auto/.cvsignore1
-rw-r--r--programs/auto/Makefile21
-rw-r--r--programs/auto/auto.8481
-rwxr-xr-xprograms/auto/auto.in660
-rw-r--r--programs/barf/.cvsignore1
-rw-r--r--programs/barf/Makefile38
-rw-r--r--programs/barf/barf.884
-rwxr-xr-xprograms/barf/barf.in296
-rw-r--r--programs/calcgoo/.cvsignore1
-rw-r--r--programs/calcgoo/Makefile41
-rw-r--r--programs/calcgoo/calcgoo.831
-rw-r--r--programs/calcgoo/calcgoo.in43
-rw-r--r--programs/charon/Doxyfile (renamed from Source/Doxyfile)0
-rw-r--r--programs/charon/Makefile (renamed from Source/Makefile)0
-rw-r--r--programs/charon/charon.kdevelop (renamed from Source/charon.kdevelop)0
-rw-r--r--programs/charon/charon/Makefile.charon (renamed from Source/charon/Makefile.charon)0
-rw-r--r--programs/charon/charon/config/Makefile.config (renamed from Source/charon/config/Makefile.config)0
-rwxr-xr-xprograms/charon/charon/config/configuration.c (renamed from Source/charon/config/configuration.c)0
-rwxr-xr-xprograms/charon/charon/config/configuration.h (renamed from Source/charon/config/configuration.h)0
-rw-r--r--programs/charon/charon/config/connections/Makefile.connections (renamed from Source/charon/config/connections/Makefile.connections)0
-rw-r--r--programs/charon/charon/config/connections/connection.c (renamed from Source/charon/config/connections/connection.c)0
-rw-r--r--programs/charon/charon/config/connections/connection.h (renamed from Source/charon/config/connections/connection.h)0
-rwxr-xr-xprograms/charon/charon/config/connections/connection_store.h (renamed from Source/charon/config/connections/connection_store.h)0
-rw-r--r--programs/charon/charon/config/connections/local_connection_store.c (renamed from Source/charon/config/connections/local_connection_store.c)0
-rw-r--r--programs/charon/charon/config/connections/local_connection_store.h (renamed from Source/charon/config/connections/local_connection_store.h)0
-rw-r--r--programs/charon/charon/config/credentials/Makefile.credentials (renamed from Source/charon/config/credentials/Makefile.credentials)0
-rwxr-xr-xprograms/charon/charon/config/credentials/credential_store.h (renamed from Source/charon/config/credentials/credential_store.h)0
-rw-r--r--programs/charon/charon/config/credentials/local_credential_store.c (renamed from Source/charon/config/credentials/local_credential_store.c)0
-rw-r--r--programs/charon/charon/config/credentials/local_credential_store.h (renamed from Source/charon/config/credentials/local_credential_store.h)0
-rw-r--r--programs/charon/charon/config/policies/Makefile.policies (renamed from Source/charon/config/policies/Makefile.policies)0
-rw-r--r--programs/charon/charon/config/policies/local_policy_store.c (renamed from Source/charon/config/policies/local_policy_store.c)0
-rw-r--r--programs/charon/charon/config/policies/local_policy_store.h (renamed from Source/charon/config/policies/local_policy_store.h)0
-rw-r--r--programs/charon/charon/config/policies/policy.c (renamed from Source/charon/config/policies/policy.c)0
-rw-r--r--programs/charon/charon/config/policies/policy.h (renamed from Source/charon/config/policies/policy.h)0
-rwxr-xr-xprograms/charon/charon/config/policies/policy_store.h (renamed from Source/charon/config/policies/policy_store.h)0
-rw-r--r--programs/charon/charon/config/proposal.c (renamed from Source/charon/config/proposal.c)0
-rw-r--r--programs/charon/charon/config/proposal.h (renamed from Source/charon/config/proposal.h)0
-rw-r--r--programs/charon/charon/config/traffic_selector.c (renamed from Source/charon/config/traffic_selector.c)0
-rw-r--r--programs/charon/charon/config/traffic_selector.h (renamed from Source/charon/config/traffic_selector.h)0
-rw-r--r--programs/charon/charon/daemon.c (renamed from Source/charon/daemon.c)0
-rw-r--r--programs/charon/charon/daemon.h (renamed from Source/charon/daemon.h)0
-rw-r--r--programs/charon/charon/encoding/Makefile.encoding (renamed from Source/charon/encoding/Makefile.encoding)0
-rw-r--r--programs/charon/charon/encoding/generator.c (renamed from Source/charon/encoding/generator.c)0
-rw-r--r--programs/charon/charon/encoding/generator.h (renamed from Source/charon/encoding/generator.h)0
-rw-r--r--programs/charon/charon/encoding/message.c (renamed from Source/charon/encoding/message.c)0
-rw-r--r--programs/charon/charon/encoding/message.h (renamed from Source/charon/encoding/message.h)0
-rw-r--r--programs/charon/charon/encoding/parser.c (renamed from Source/charon/encoding/parser.c)0
-rw-r--r--programs/charon/charon/encoding/parser.h (renamed from Source/charon/encoding/parser.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/Makefile.payloads (renamed from Source/charon/encoding/payloads/Makefile.payloads)0
-rw-r--r--programs/charon/charon/encoding/payloads/auth_payload.c (renamed from Source/charon/encoding/payloads/auth_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/auth_payload.h (renamed from Source/charon/encoding/payloads/auth_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/cert_payload.c (renamed from Source/charon/encoding/payloads/cert_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/cert_payload.h (renamed from Source/charon/encoding/payloads/cert_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/certreq_payload.c (renamed from Source/charon/encoding/payloads/certreq_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/certreq_payload.h (renamed from Source/charon/encoding/payloads/certreq_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/configuration_attribute.c (renamed from Source/charon/encoding/payloads/configuration_attribute.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/configuration_attribute.h (renamed from Source/charon/encoding/payloads/configuration_attribute.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/cp_payload.c (renamed from Source/charon/encoding/payloads/cp_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/cp_payload.h (renamed from Source/charon/encoding/payloads/cp_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/delete_payload.c (renamed from Source/charon/encoding/payloads/delete_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/delete_payload.h (renamed from Source/charon/encoding/payloads/delete_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/eap_payload.c (renamed from Source/charon/encoding/payloads/eap_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/eap_payload.h (renamed from Source/charon/encoding/payloads/eap_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/encodings.c (renamed from Source/charon/encoding/payloads/encodings.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/encodings.h (renamed from Source/charon/encoding/payloads/encodings.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/encryption_payload.c (renamed from Source/charon/encoding/payloads/encryption_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/encryption_payload.h (renamed from Source/charon/encoding/payloads/encryption_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/id_payload.c (renamed from Source/charon/encoding/payloads/id_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/id_payload.h (renamed from Source/charon/encoding/payloads/id_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/ike_header.c (renamed from Source/charon/encoding/payloads/ike_header.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/ike_header.h (renamed from Source/charon/encoding/payloads/ike_header.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/ke_payload.c (renamed from Source/charon/encoding/payloads/ke_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/ke_payload.h (renamed from Source/charon/encoding/payloads/ke_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/nonce_payload.c (renamed from Source/charon/encoding/payloads/nonce_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/nonce_payload.h (renamed from Source/charon/encoding/payloads/nonce_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/notify_payload.c (renamed from Source/charon/encoding/payloads/notify_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/notify_payload.h (renamed from Source/charon/encoding/payloads/notify_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/payload.c (renamed from Source/charon/encoding/payloads/payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/payload.h (renamed from Source/charon/encoding/payloads/payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/proposal_substructure.c (renamed from Source/charon/encoding/payloads/proposal_substructure.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/proposal_substructure.h (renamed from Source/charon/encoding/payloads/proposal_substructure.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/sa_payload.c (renamed from Source/charon/encoding/payloads/sa_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/sa_payload.h (renamed from Source/charon/encoding/payloads/sa_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/traffic_selector_substructure.c (renamed from Source/charon/encoding/payloads/traffic_selector_substructure.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/traffic_selector_substructure.h (renamed from Source/charon/encoding/payloads/traffic_selector_substructure.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/transform_attribute.c (renamed from Source/charon/encoding/payloads/transform_attribute.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/transform_attribute.h (renamed from Source/charon/encoding/payloads/transform_attribute.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/transform_substructure.c (renamed from Source/charon/encoding/payloads/transform_substructure.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/transform_substructure.h (renamed from Source/charon/encoding/payloads/transform_substructure.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/ts_payload.c (renamed from Source/charon/encoding/payloads/ts_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/ts_payload.h (renamed from Source/charon/encoding/payloads/ts_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/unknown_payload.c (renamed from Source/charon/encoding/payloads/unknown_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/unknown_payload.h (renamed from Source/charon/encoding/payloads/unknown_payload.h)0
-rw-r--r--programs/charon/charon/encoding/payloads/vendor_id_payload.c (renamed from Source/charon/encoding/payloads/vendor_id_payload.c)0
-rw-r--r--programs/charon/charon/encoding/payloads/vendor_id_payload.h (renamed from Source/charon/encoding/payloads/vendor_id_payload.h)0
-rw-r--r--programs/charon/charon/network/Makefile.network (renamed from Source/charon/network/Makefile.network)0
-rw-r--r--programs/charon/charon/network/packet.c (renamed from Source/charon/network/packet.c)0
-rw-r--r--programs/charon/charon/network/packet.h (renamed from Source/charon/network/packet.h)0
-rw-r--r--programs/charon/charon/network/socket.c (renamed from Source/charon/network/socket.c)0
-rw-r--r--programs/charon/charon/network/socket.h (renamed from Source/charon/network/socket.h)0
-rw-r--r--programs/charon/charon/queues/Makefile.queues (renamed from Source/charon/queues/Makefile.queues)0
-rw-r--r--programs/charon/charon/queues/event_queue.c (renamed from Source/charon/queues/event_queue.c)0
-rw-r--r--programs/charon/charon/queues/event_queue.h (renamed from Source/charon/queues/event_queue.h)0
-rw-r--r--programs/charon/charon/queues/job_queue.c (renamed from Source/charon/queues/job_queue.c)0
-rw-r--r--programs/charon/charon/queues/job_queue.h (renamed from Source/charon/queues/job_queue.h)0
-rw-r--r--programs/charon/charon/queues/jobs/Makefile.jobs (renamed from Source/charon/queues/jobs/Makefile.jobs)0
-rw-r--r--programs/charon/charon/queues/jobs/delete_established_ike_sa_job.c (renamed from Source/charon/queues/jobs/delete_established_ike_sa_job.c)0
-rw-r--r--programs/charon/charon/queues/jobs/delete_established_ike_sa_job.h (renamed from Source/charon/queues/jobs/delete_established_ike_sa_job.h)0
-rw-r--r--programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.c (renamed from Source/charon/queues/jobs/delete_half_open_ike_sa_job.c)0
-rw-r--r--programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.h (renamed from Source/charon/queues/jobs/delete_half_open_ike_sa_job.h)0
-rw-r--r--programs/charon/charon/queues/jobs/incoming_packet_job.c (renamed from Source/charon/queues/jobs/incoming_packet_job.c)0
-rw-r--r--programs/charon/charon/queues/jobs/incoming_packet_job.h (renamed from Source/charon/queues/jobs/incoming_packet_job.h)0
-rw-r--r--programs/charon/charon/queues/jobs/initiate_ike_sa_job.c (renamed from Source/charon/queues/jobs/initiate_ike_sa_job.c)0
-rw-r--r--programs/charon/charon/queues/jobs/initiate_ike_sa_job.h (renamed from Source/charon/queues/jobs/initiate_ike_sa_job.h)0
-rw-r--r--programs/charon/charon/queues/jobs/job.c (renamed from Source/charon/queues/jobs/job.c)0
-rw-r--r--programs/charon/charon/queues/jobs/job.h (renamed from Source/charon/queues/jobs/job.h)0
-rw-r--r--programs/charon/charon/queues/jobs/retransmit_request_job.c (renamed from Source/charon/queues/jobs/retransmit_request_job.c)0
-rw-r--r--programs/charon/charon/queues/jobs/retransmit_request_job.h (renamed from Source/charon/queues/jobs/retransmit_request_job.h)0
-rw-r--r--programs/charon/charon/queues/send_queue.c (renamed from Source/charon/queues/send_queue.c)0
-rw-r--r--programs/charon/charon/queues/send_queue.h (renamed from Source/charon/queues/send_queue.h)0
-rw-r--r--programs/charon/charon/sa/Makefile.sa (renamed from Source/charon/sa/Makefile.sa)0
-rw-r--r--programs/charon/charon/sa/authenticator.c (renamed from Source/charon/sa/authenticator.c)0
-rw-r--r--programs/charon/charon/sa/authenticator.h (renamed from Source/charon/sa/authenticator.h)0
-rw-r--r--programs/charon/charon/sa/child_sa.c (renamed from Source/charon/sa/child_sa.c)0
-rw-r--r--programs/charon/charon/sa/child_sa.h (renamed from Source/charon/sa/child_sa.h)0
-rw-r--r--programs/charon/charon/sa/ike_sa.c (renamed from Source/charon/sa/ike_sa.c)0
-rw-r--r--programs/charon/charon/sa/ike_sa.h (renamed from Source/charon/sa/ike_sa.h)0
-rw-r--r--programs/charon/charon/sa/ike_sa_id.c (renamed from Source/charon/sa/ike_sa_id.c)0
-rw-r--r--programs/charon/charon/sa/ike_sa_id.h (renamed from Source/charon/sa/ike_sa_id.h)0
-rw-r--r--programs/charon/charon/sa/ike_sa_manager.c (renamed from Source/charon/sa/ike_sa_manager.c)0
-rw-r--r--programs/charon/charon/sa/ike_sa_manager.h (renamed from Source/charon/sa/ike_sa_manager.h)0
-rw-r--r--programs/charon/charon/sa/states/Makefile.states (renamed from Source/charon/sa/states/Makefile.states)0
-rw-r--r--programs/charon/charon/sa/states/ike_auth_requested.c (renamed from Source/charon/sa/states/ike_auth_requested.c)0
-rw-r--r--programs/charon/charon/sa/states/ike_auth_requested.h (renamed from Source/charon/sa/states/ike_auth_requested.h)0
-rw-r--r--programs/charon/charon/sa/states/ike_sa_established.c (renamed from Source/charon/sa/states/ike_sa_established.c)0
-rw-r--r--programs/charon/charon/sa/states/ike_sa_established.h (renamed from Source/charon/sa/states/ike_sa_established.h)0
-rw-r--r--programs/charon/charon/sa/states/ike_sa_init_requested.c (renamed from Source/charon/sa/states/ike_sa_init_requested.c)0
-rw-r--r--programs/charon/charon/sa/states/ike_sa_init_requested.h (renamed from Source/charon/sa/states/ike_sa_init_requested.h)0
-rw-r--r--programs/charon/charon/sa/states/ike_sa_init_responded.c (renamed from Source/charon/sa/states/ike_sa_init_responded.c)0
-rw-r--r--programs/charon/charon/sa/states/ike_sa_init_responded.h (renamed from Source/charon/sa/states/ike_sa_init_responded.h)0
-rw-r--r--programs/charon/charon/sa/states/initiator_init.c (renamed from Source/charon/sa/states/initiator_init.c)0
-rw-r--r--programs/charon/charon/sa/states/initiator_init.h (renamed from Source/charon/sa/states/initiator_init.h)0
-rw-r--r--programs/charon/charon/sa/states/responder_init.c (renamed from Source/charon/sa/states/responder_init.c)0
-rw-r--r--programs/charon/charon/sa/states/responder_init.h (renamed from Source/charon/sa/states/responder_init.h)0
-rw-r--r--programs/charon/charon/sa/states/state.c (renamed from Source/charon/sa/states/state.c)0
-rw-r--r--programs/charon/charon/sa/states/state.h (renamed from Source/charon/sa/states/state.h)0
-rw-r--r--programs/charon/charon/threads/Makefile.threads (renamed from Source/charon/threads/Makefile.threads)0
-rw-r--r--programs/charon/charon/threads/kernel_interface.c (renamed from Source/charon/threads/kernel_interface.c)0
-rw-r--r--programs/charon/charon/threads/kernel_interface.h (renamed from Source/charon/threads/kernel_interface.h)0
-rw-r--r--programs/charon/charon/threads/receiver.c (renamed from Source/charon/threads/receiver.c)0
-rw-r--r--programs/charon/charon/threads/receiver.h (renamed from Source/charon/threads/receiver.h)0
-rw-r--r--programs/charon/charon/threads/scheduler.c (renamed from Source/charon/threads/scheduler.c)0
-rw-r--r--programs/charon/charon/threads/scheduler.h (renamed from Source/charon/threads/scheduler.h)0
-rw-r--r--programs/charon/charon/threads/sender.c (renamed from Source/charon/threads/sender.c)0
-rw-r--r--programs/charon/charon/threads/sender.h (renamed from Source/charon/threads/sender.h)0
-rwxr-xr-xprograms/charon/charon/threads/stroke_interface.c (renamed from Source/charon/threads/stroke_interface.c)0
-rw-r--r--programs/charon/charon/threads/stroke_interface.h (renamed from Source/charon/threads/stroke_interface.h)0
-rw-r--r--programs/charon/charon/threads/thread_pool.c (renamed from Source/charon/threads/thread_pool.c)0
-rw-r--r--programs/charon/charon/threads/thread_pool.h (renamed from Source/charon/threads/thread_pool.h)0
-rw-r--r--programs/charon/doc/Architecture.txt (renamed from Source/doc/Architecture.txt)0
-rw-r--r--programs/charon/doc/Known-bugs.txt (renamed from Source/doc/Known-bugs.txt)0
-rw-r--r--programs/charon/doc/Todo-list.txt (renamed from Source/doc/Todo-list.txt)0
-rw-r--r--programs/charon/lib/Makefile.lib (renamed from Source/lib/Makefile.lib)0
-rw-r--r--programs/charon/lib/asn1/Makefile.asn1 (renamed from Source/lib/asn1/Makefile.asn1)0
-rw-r--r--programs/charon/lib/asn1/asn1.c (renamed from Source/lib/asn1/asn1.c)0
-rw-r--r--programs/charon/lib/asn1/asn1.h (renamed from Source/lib/asn1/asn1.h)0
-rw-r--r--programs/charon/lib/asn1/oid.c (renamed from Source/lib/asn1/oid.c)0
-rw-r--r--programs/charon/lib/asn1/oid.h (renamed from Source/lib/asn1/oid.h)0
-rw-r--r--programs/charon/lib/asn1/oid.pl (renamed from Source/lib/asn1/oid.pl)0
-rw-r--r--programs/charon/lib/asn1/oid.txt (renamed from Source/lib/asn1/oid.txt)0
-rwxr-xr-xprograms/charon/lib/asn1/pem.c (renamed from Source/lib/asn1/pem.c)0
-rwxr-xr-xprograms/charon/lib/asn1/pem.h (renamed from Source/lib/asn1/pem.h)0
-rw-r--r--programs/charon/lib/asn1/ttodata.c (renamed from Source/lib/asn1/ttodata.c)0
-rw-r--r--programs/charon/lib/asn1/ttodata.h (renamed from Source/lib/asn1/ttodata.h)0
-rw-r--r--programs/charon/lib/crypto/Makefile.transforms (renamed from Source/lib/crypto/Makefile.transforms)0
-rw-r--r--programs/charon/lib/crypto/crypters/Makefile.crypters (renamed from Source/lib/crypto/crypters/Makefile.crypters)0
-rw-r--r--programs/charon/lib/crypto/crypters/aes_cbc_crypter.c (renamed from Source/lib/crypto/crypters/aes_cbc_crypter.c)0
-rw-r--r--programs/charon/lib/crypto/crypters/aes_cbc_crypter.h (renamed from Source/lib/crypto/crypters/aes_cbc_crypter.h)0
-rw-r--r--programs/charon/lib/crypto/crypters/crypter.c (renamed from Source/lib/crypto/crypters/crypter.c)0
-rw-r--r--programs/charon/lib/crypto/crypters/crypter.h (renamed from Source/lib/crypto/crypters/crypter.h)0
-rw-r--r--programs/charon/lib/crypto/diffie_hellman.c (renamed from Source/lib/crypto/diffie_hellman.c)0
-rw-r--r--programs/charon/lib/crypto/diffie_hellman.h (renamed from Source/lib/crypto/diffie_hellman.h)0
-rw-r--r--programs/charon/lib/crypto/hashers/Makefile.hashers (renamed from Source/lib/crypto/hashers/Makefile.hashers)0
-rw-r--r--programs/charon/lib/crypto/hashers/hasher.c (renamed from Source/lib/crypto/hashers/hasher.c)0
-rw-r--r--programs/charon/lib/crypto/hashers/hasher.h (renamed from Source/lib/crypto/hashers/hasher.h)0
-rw-r--r--programs/charon/lib/crypto/hashers/md5_hasher.c (renamed from Source/lib/crypto/hashers/md5_hasher.c)0
-rw-r--r--programs/charon/lib/crypto/hashers/md5_hasher.h (renamed from Source/lib/crypto/hashers/md5_hasher.h)0
-rw-r--r--programs/charon/lib/crypto/hashers/sha1_hasher.c (renamed from Source/lib/crypto/hashers/sha1_hasher.c)0
-rw-r--r--programs/charon/lib/crypto/hashers/sha1_hasher.h (renamed from Source/lib/crypto/hashers/sha1_hasher.h)0
-rw-r--r--programs/charon/lib/crypto/hmac.c (renamed from Source/lib/crypto/hmac.c)0
-rw-r--r--programs/charon/lib/crypto/hmac.h (renamed from Source/lib/crypto/hmac.h)0
-rw-r--r--programs/charon/lib/crypto/prf_plus.c (renamed from Source/lib/crypto/prf_plus.c)0
-rw-r--r--programs/charon/lib/crypto/prf_plus.h (renamed from Source/lib/crypto/prf_plus.h)0
-rw-r--r--programs/charon/lib/crypto/prfs/Makefile.prfs (renamed from Source/lib/crypto/prfs/Makefile.prfs)0
-rw-r--r--programs/charon/lib/crypto/prfs/hmac_prf.c (renamed from Source/lib/crypto/prfs/hmac_prf.c)0
-rw-r--r--programs/charon/lib/crypto/prfs/hmac_prf.h (renamed from Source/lib/crypto/prfs/hmac_prf.h)0
-rw-r--r--programs/charon/lib/crypto/prfs/prf.c (renamed from Source/lib/crypto/prfs/prf.c)0
-rw-r--r--programs/charon/lib/crypto/prfs/prf.h (renamed from Source/lib/crypto/prfs/prf.h)0
-rw-r--r--programs/charon/lib/crypto/rsa/Makefile.rsa (renamed from Source/lib/crypto/rsa/Makefile.rsa)0
-rw-r--r--programs/charon/lib/crypto/rsa/rsa_private_key.c (renamed from Source/lib/crypto/rsa/rsa_private_key.c)0
-rw-r--r--programs/charon/lib/crypto/rsa/rsa_private_key.h (renamed from Source/lib/crypto/rsa/rsa_private_key.h)0
-rw-r--r--programs/charon/lib/crypto/rsa/rsa_public_key.c (renamed from Source/lib/crypto/rsa/rsa_public_key.c)0
-rw-r--r--programs/charon/lib/crypto/rsa/rsa_public_key.h (renamed from Source/lib/crypto/rsa/rsa_public_key.h)0
-rw-r--r--programs/charon/lib/crypto/signers/Makefile.signers (renamed from Source/lib/crypto/signers/Makefile.signers)0
-rw-r--r--programs/charon/lib/crypto/signers/hmac_signer.c (renamed from Source/lib/crypto/signers/hmac_signer.c)0
-rw-r--r--programs/charon/lib/crypto/signers/hmac_signer.h (renamed from Source/lib/crypto/signers/hmac_signer.h)0
-rw-r--r--programs/charon/lib/crypto/signers/signer.c (renamed from Source/lib/crypto/signers/signer.c)0
-rw-r--r--programs/charon/lib/crypto/signers/signer.h (renamed from Source/lib/crypto/signers/signer.h)0
-rwxr-xr-xprograms/charon/lib/crypto/x509.c (renamed from Source/lib/crypto/x509.c)0
-rwxr-xr-xprograms/charon/lib/crypto/x509.h (renamed from Source/lib/crypto/x509.h)0
-rw-r--r--programs/charon/lib/definitions.c (renamed from Source/lib/definitions.c)0
-rw-r--r--programs/charon/lib/definitions.h (renamed from Source/lib/definitions.h)0
-rw-r--r--programs/charon/lib/library.c (renamed from Source/lib/library.c)0
-rw-r--r--programs/charon/lib/library.h (renamed from Source/lib/library.h)0
-rw-r--r--programs/charon/lib/types.c (renamed from Source/lib/types.c)0
-rw-r--r--programs/charon/lib/types.h (renamed from Source/lib/types.h)0
-rw-r--r--programs/charon/lib/utils/Makefile.utils (renamed from Source/lib/utils/Makefile.utils)0
-rw-r--r--programs/charon/lib/utils/host.c (renamed from Source/lib/utils/host.c)0
-rw-r--r--programs/charon/lib/utils/host.h (renamed from Source/lib/utils/host.h)0
-rw-r--r--programs/charon/lib/utils/identification.c (renamed from Source/lib/utils/identification.c)0
-rw-r--r--programs/charon/lib/utils/identification.h (renamed from Source/lib/utils/identification.h)0
-rw-r--r--programs/charon/lib/utils/iterator.h (renamed from Source/lib/utils/iterator.h)0
-rw-r--r--programs/charon/lib/utils/leak_detective.c (renamed from Source/lib/utils/leak_detective.c)0
-rw-r--r--programs/charon/lib/utils/leak_detective.h (renamed from Source/lib/utils/leak_detective.h)0
-rw-r--r--programs/charon/lib/utils/linked_list.c (renamed from Source/lib/utils/linked_list.c)0
-rw-r--r--programs/charon/lib/utils/linked_list.h (renamed from Source/lib/utils/linked_list.h)0
-rw-r--r--programs/charon/lib/utils/logger.c (renamed from Source/lib/utils/logger.c)0
-rw-r--r--programs/charon/lib/utils/logger.h (renamed from Source/lib/utils/logger.h)0
-rw-r--r--programs/charon/lib/utils/logger_manager.c (renamed from Source/lib/utils/logger_manager.c)0
-rw-r--r--programs/charon/lib/utils/logger_manager.h (renamed from Source/lib/utils/logger_manager.h)0
-rw-r--r--programs/charon/lib/utils/randomizer.c (renamed from Source/lib/utils/randomizer.c)0
-rw-r--r--programs/charon/lib/utils/randomizer.h (renamed from Source/lib/utils/randomizer.h)0
-rw-r--r--programs/charon/lib/utils/tester.c (renamed from Source/lib/utils/tester.c)0
-rw-r--r--programs/charon/lib/utils/tester.h (renamed from Source/lib/utils/tester.h)0
-rw-r--r--programs/charon/patches/strongswan-2.7.0.patch (renamed from Source/patches/strongswan-2.7.0.patch)0
-rw-r--r--programs/charon/scripts/alice-key.der (renamed from Source/scripts/alice-key.der)bin1190 -> 1190 bytes
-rw-r--r--programs/charon/scripts/alice.der (renamed from Source/scripts/alice.der)bin764 -> 764 bytes
-rw-r--r--programs/charon/scripts/bob-key.der (renamed from Source/scripts/bob-key.der)bin1187 -> 1187 bytes
-rw-r--r--programs/charon/scripts/bob.der (renamed from Source/scripts/bob.der)bin759 -> 759 bytes
-rw-r--r--programs/charon/scripts/complex1.der (renamed from Source/scripts/complex1.der)bin934 -> 934 bytes
-rw-r--r--programs/charon/scripts/complex2.der (renamed from Source/scripts/complex2.der)bin956 -> 956 bytes
-rwxr-xr-xprograms/charon/scripts/daemon-loop.sh (renamed from Source/scripts/daemon-loop.sh)0
-rwxr-xr-xprograms/charon/scripts/deleteline (renamed from Source/scripts/deleteline)0
-rwxr-xr-xprograms/charon/scripts/replace (renamed from Source/scripts/replace)0
-rwxr-xr-xprograms/charon/scripts/to-alice.sh (renamed from Source/scripts/to-alice.sh)0
-rwxr-xr-xprograms/charon/scripts/to-bob.sh (renamed from Source/scripts/to-bob.sh)0
-rw-r--r--programs/charon/stroke/Makefile.stroke (renamed from Source/stroke/Makefile.stroke)0
-rw-r--r--programs/charon/stroke/stroke.c (renamed from Source/stroke/stroke.c)0
-rw-r--r--programs/charon/stroke/stroke.h (renamed from Source/stroke/stroke.h)0
-rw-r--r--programs/charon/testing/Makefile.testcases (renamed from Source/testing/Makefile.testcases)0
-rw-r--r--programs/charon/testing/aes_cbc_crypter_test.c (renamed from Source/testing/aes_cbc_crypter_test.c)0
-rw-r--r--programs/charon/testing/aes_cbc_crypter_test.h (renamed from Source/testing/aes_cbc_crypter_test.h)0
-rw-r--r--programs/charon/testing/certificate_test.c (renamed from Source/testing/certificate_test.c)0
-rw-r--r--programs/charon/testing/certificate_test.h (renamed from Source/testing/certificate_test.h)0
-rw-r--r--programs/charon/testing/child_sa_test.c (renamed from Source/testing/child_sa_test.c)0
-rw-r--r--programs/charon/testing/child_sa_test.h (renamed from Source/testing/child_sa_test.h)0
-rw-r--r--programs/charon/testing/connection_test.c (renamed from Source/testing/connection_test.c)0
-rw-r--r--programs/charon/testing/connection_test.h (renamed from Source/testing/connection_test.h)0
-rw-r--r--programs/charon/testing/diffie_hellman_test.c (renamed from Source/testing/diffie_hellman_test.c)0
-rw-r--r--programs/charon/testing/diffie_hellman_test.h (renamed from Source/testing/diffie_hellman_test.h)0
-rw-r--r--programs/charon/testing/encryption_payload_test.c (renamed from Source/testing/encryption_payload_test.c)0
-rw-r--r--programs/charon/testing/encryption_payload_test.h (renamed from Source/testing/encryption_payload_test.h)0
-rw-r--r--programs/charon/testing/event_queue_test.c (renamed from Source/testing/event_queue_test.c)0
-rw-r--r--programs/charon/testing/event_queue_test.h (renamed from Source/testing/event_queue_test.h)0
-rw-r--r--programs/charon/testing/generator_test.c (renamed from Source/testing/generator_test.c)0
-rw-r--r--programs/charon/testing/generator_test.h (renamed from Source/testing/generator_test.h)0
-rw-r--r--programs/charon/testing/hasher_test.c (renamed from Source/testing/hasher_test.c)0
-rw-r--r--programs/charon/testing/hasher_test.h (renamed from Source/testing/hasher_test.h)0
-rw-r--r--programs/charon/testing/hmac_signer_test.c (renamed from Source/testing/hmac_signer_test.c)0
-rw-r--r--programs/charon/testing/hmac_signer_test.h (renamed from Source/testing/hmac_signer_test.h)0
-rw-r--r--programs/charon/testing/hmac_test.c (renamed from Source/testing/hmac_test.c)0
-rw-r--r--programs/charon/testing/hmac_test.h (renamed from Source/testing/hmac_test.h)0
-rw-r--r--programs/charon/testing/identification_test.c (renamed from Source/testing/identification_test.c)0
-rw-r--r--programs/charon/testing/identification_test.h (renamed from Source/testing/identification_test.h)0
-rw-r--r--programs/charon/testing/ike_sa_id_test.c (renamed from Source/testing/ike_sa_id_test.c)0
-rw-r--r--programs/charon/testing/ike_sa_id_test.h (renamed from Source/testing/ike_sa_id_test.h)0
-rw-r--r--programs/charon/testing/ike_sa_manager_test.c (renamed from Source/testing/ike_sa_manager_test.c)0
-rw-r--r--programs/charon/testing/ike_sa_manager_test.h (renamed from Source/testing/ike_sa_manager_test.h)0
-rw-r--r--programs/charon/testing/ike_sa_test.c (renamed from Source/testing/ike_sa_test.c)0
-rw-r--r--programs/charon/testing/ike_sa_test.h (renamed from Source/testing/ike_sa_test.h)0
-rw-r--r--programs/charon/testing/job_queue_test.c (renamed from Source/testing/job_queue_test.c)0
-rw-r--r--programs/charon/testing/job_queue_test.h (renamed from Source/testing/job_queue_test.h)0
-rw-r--r--programs/charon/testing/kernel_interface_test.c (renamed from Source/testing/kernel_interface_test.c)0
-rw-r--r--programs/charon/testing/kernel_interface_test.h (renamed from Source/testing/kernel_interface_test.h)0
-rw-r--r--programs/charon/testing/leak_detective_test.c (renamed from Source/testing/leak_detective_test.c)0
-rw-r--r--programs/charon/testing/leak_detective_test.h (renamed from Source/testing/leak_detective_test.h)0
-rw-r--r--programs/charon/testing/linked_list_test.c (renamed from Source/testing/linked_list_test.c)0
-rw-r--r--programs/charon/testing/linked_list_test.h (renamed from Source/testing/linked_list_test.h)0
-rw-r--r--programs/charon/testing/packet_test.c (renamed from Source/testing/packet_test.c)0
-rw-r--r--programs/charon/testing/packet_test.h (renamed from Source/testing/packet_test.h)0
-rw-r--r--programs/charon/testing/parser_test.c (renamed from Source/testing/parser_test.c)0
-rw-r--r--programs/charon/testing/parser_test.h (renamed from Source/testing/parser_test.h)0
-rw-r--r--programs/charon/testing/policy_test.c (renamed from Source/testing/policy_test.c)0
-rw-r--r--programs/charon/testing/policy_test.h (renamed from Source/testing/policy_test.h)0
-rw-r--r--programs/charon/testing/prf_plus_test.c (renamed from Source/testing/prf_plus_test.c)0
-rw-r--r--programs/charon/testing/prf_plus_test.h (renamed from Source/testing/prf_plus_test.h)0
-rw-r--r--programs/charon/testing/proposal_test.c (renamed from Source/testing/proposal_test.c)0
-rw-r--r--programs/charon/testing/proposal_test.h (renamed from Source/testing/proposal_test.h)0
-rw-r--r--programs/charon/testing/rsa_test.c (renamed from Source/testing/rsa_test.c)0
-rw-r--r--programs/charon/testing/rsa_test.h (renamed from Source/testing/rsa_test.h)0
-rw-r--r--programs/charon/testing/scheduler_test.c (renamed from Source/testing/scheduler_test.c)0
-rw-r--r--programs/charon/testing/scheduler_test.h (renamed from Source/testing/scheduler_test.h)0
-rw-r--r--programs/charon/testing/send_queue_test.c (renamed from Source/testing/send_queue_test.c)0
-rw-r--r--programs/charon/testing/send_queue_test.h (renamed from Source/testing/send_queue_test.h)0
-rw-r--r--programs/charon/testing/sender_test.c (renamed from Source/testing/sender_test.c)0
-rw-r--r--programs/charon/testing/sender_test.h (renamed from Source/testing/sender_test.h)0
-rw-r--r--programs/charon/testing/socket_test.c (renamed from Source/testing/socket_test.c)0
-rw-r--r--programs/charon/testing/socket_test.h (renamed from Source/testing/socket_test.h)0
-rw-r--r--programs/charon/testing/testcases.c (renamed from Source/testing/testcases.c)0
-rw-r--r--programs/charon/testing/thread_pool_test.c (renamed from Source/testing/thread_pool_test.c)0
-rw-r--r--programs/charon/testing/thread_pool_test.h (renamed from Source/testing/thread_pool_test.h)0
-rw-r--r--programs/eroute/.cvsignore1
-rw-r--r--programs/eroute/Makefile52
-rw-r--r--programs/eroute/eroute.5272
-rw-r--r--programs/eroute/eroute.8354
-rw-r--r--programs/eroute/eroute.c1044
-rw-r--r--programs/examples/Makefile22
-rw-r--r--programs/examples/oe.conf.in68
-rw-r--r--programs/ikeping/.cvsignore1
-rw-r--r--programs/ikeping/Makefile57
-rw-r--r--programs/ikeping/ikeping.871
-rw-r--r--programs/ikeping/ikeping.c483
-rw-r--r--programs/ipsec/.cvsignore1
-rw-r--r--programs/ipsec/Makefile28
-rw-r--r--programs/ipsec/distro.txt1
-rw-r--r--programs/ipsec/ipsec.8336
-rwxr-xr-xprograms/ipsec/ipsec.in244
-rw-r--r--programs/klipsdebug/.cvsignore1
-rw-r--r--programs/klipsdebug/Makefile80
-rw-r--r--programs/klipsdebug/klipsdebug.5138
-rw-r--r--programs/klipsdebug/klipsdebug.8164
-rw-r--r--programs/klipsdebug/klipsdebug.c436
-rw-r--r--programs/look/.cvsignore1
-rw-r--r--programs/look/Makefile38
-rw-r--r--programs/look/look.845
-rwxr-xr-xprograms/look/look.in87
-rw-r--r--programs/lwdnsq/.cvsignore4
-rw-r--r--programs/lwdnsq/CONTRACT.txt106
-rw-r--r--programs/lwdnsq/Makefile96
-rw-r--r--programs/lwdnsq/cmds.c351
-rw-r--r--programs/lwdnsq/lookup.c632
-rw-r--r--programs/lwdnsq/lwdnsq.8250
-rw-r--r--programs/lwdnsq/lwdnsq.c506
-rw-r--r--programs/lwdnsq/lwdnsq.h121
-rw-r--r--programs/lwdnsq/lwdnsq.xml.in446
-rw-r--r--programs/lwdnsq/states.fig66
-rw-r--r--programs/lwdnsq/states.pngbin0 -> 6756 bytes
-rw-r--r--programs/mailkey/.cvsignore1
-rw-r--r--programs/mailkey/Makefile41
-rw-r--r--programs/mailkey/mailkey.847
-rwxr-xr-xprograms/mailkey/mailkey.in241
-rw-r--r--programs/manual/.cvsignore1
-rw-r--r--programs/manual/Makefile38
-rw-r--r--programs/manual/manual.8267
-rwxr-xr-xprograms/manual/manual.in637
-rw-r--r--programs/openac/Makefile154
-rw-r--r--programs/openac/build.c242
-rw-r--r--programs/openac/build.h47
-rw-r--r--programs/openac/loglite.c295
-rw-r--r--programs/openac/openac.8180
-rwxr-xr-xprograms/openac/openac.c438
-rw-r--r--programs/pf_key/.cvsignore1
-rw-r--r--programs/pf_key/Makefile49
-rw-r--r--programs/pf_key/pf_key.5122
-rw-r--r--programs/pf_key/pf_key.873
-rw-r--r--programs/pf_key/pf_key.c353
-rw-r--r--programs/pluto/.cvsignore3
-rw-r--r--programs/pluto/Makefile1090
-rw-r--r--programs/pluto/PLUTO-CONVENTIONS127
-rw-r--r--programs/pluto/TODO129
-rw-r--r--programs/pluto/ac.c1018
-rw-r--r--programs/pluto/ac.h103
-rw-r--r--programs/pluto/adns.c615
-rw-r--r--programs/pluto/adns.h75
-rw-r--r--programs/pluto/alg/Config.ike_alg9
-rw-r--r--programs/pluto/alg/Makefile93
-rw-r--r--programs/pluto/alg/Makefile.ike_alg_aes14
-rw-r--r--programs/pluto/alg/Makefile.ike_alg_blowfish13
-rw-r--r--programs/pluto/alg/Makefile.ike_alg_serpent13
-rw-r--r--programs/pluto/alg/Makefile.ike_alg_sha213
-rw-r--r--programs/pluto/alg/Makefile.ike_alg_twofish13
-rw-r--r--programs/pluto/alg/ike_alg_aes.c68
-rw-r--r--programs/pluto/alg/ike_alg_blowfish.c52
-rw-r--r--programs/pluto/alg/ike_alg_serpent.c70
-rw-r--r--programs/pluto/alg/ike_alg_sha2.c61
-rw-r--r--programs/pluto/alg/ike_alg_twofish.c85
-rw-r--r--programs/pluto/alg_info.c1197
-rw-r--r--programs/pluto/alg_info.h85
-rw-r--r--programs/pluto/asn1.c770
-rw-r--r--programs/pluto/asn1.h141
-rw-r--r--programs/pluto/ca.c694
-rw-r--r--programs/pluto/ca.h70
-rw-r--r--programs/pluto/certs.c287
-rw-r--r--programs/pluto/certs.h80
-rw-r--r--programs/pluto/connections.c4431
-rw-r--r--programs/pluto/connections.h375
-rw-r--r--programs/pluto/constants.c1271
-rw-r--r--programs/pluto/constants.h1184
-rw-r--r--programs/pluto/cookie.c67
-rw-r--r--programs/pluto/cookie.h24
-rw-r--r--programs/pluto/crl.c763
-rw-r--r--programs/pluto/crl.h87
-rw-r--r--programs/pluto/crypto.c261
-rw-r--r--programs/pluto/crypto.h107
-rw-r--r--programs/pluto/db_ops.c439
-rw-r--r--programs/pluto/db_ops.h56
-rw-r--r--programs/pluto/defs.c374
-rw-r--r--programs/pluto/defs.h145
-rw-r--r--programs/pluto/demux.c2411
-rw-r--r--programs/pluto/demux.h100
-rw-r--r--programs/pluto/dnskey.c1962
-rw-r--r--programs/pluto/dnskey.h84
-rw-r--r--programs/pluto/dsa.c476
-rw-r--r--programs/pluto/dsa.h32
-rw-r--r--programs/pluto/elgamal.c613
-rw-r--r--programs/pluto/elgamal.h35
-rw-r--r--programs/pluto/fetch.c1081
-rw-r--r--programs/pluto/fetch.h79
-rw-r--r--programs/pluto/foodgroups.c462
-rw-r--r--programs/pluto/foodgroups.h24
-rw-r--r--programs/pluto/gcryptfix.c283
-rw-r--r--programs/pluto/gcryptfix.h111
-rw-r--r--programs/pluto/id.c509
-rw-r--r--programs/pluto/id.h67
-rw-r--r--programs/pluto/ike_alg.c459
-rw-r--r--programs/pluto/ike_alg.h73
-rw-r--r--programs/pluto/ipsec.secrets.5175
-rw-r--r--programs/pluto/ipsec_doi.c5649
-rw-r--r--programs/pluto/ipsec_doi.h104
-rw-r--r--programs/pluto/kameipsec.h47
-rw-r--r--programs/pluto/kernel.c2997
-rw-r--r--programs/pluto/kernel.h200
-rw-r--r--programs/pluto/kernel_alg.c775
-rw-r--r--programs/pluto/kernel_alg.h46
-rw-r--r--programs/pluto/kernel_netlink.c1221
-rw-r--r--programs/pluto/kernel_netlink.h20
-rw-r--r--programs/pluto/kernel_noklips.c126
-rw-r--r--programs/pluto/kernel_noklips.h19
-rw-r--r--programs/pluto/kernel_pfkey.c938
-rw-r--r--programs/pluto/kernel_pfkey.h23
-rw-r--r--programs/pluto/keys.c1404
-rw-r--r--programs/pluto/keys.h110
-rw-r--r--programs/pluto/lex.c213
-rw-r--r--programs/pluto/lex.h52
-rw-r--r--programs/pluto/linux26/netlink.h90
-rw-r--r--programs/pluto/linux26/rtnetlink.h562
-rw-r--r--programs/pluto/linux26/xfrm.h233
-rw-r--r--programs/pluto/log.c843
-rw-r--r--programs/pluto/log.h236
-rw-r--r--programs/pluto/md2.c237
-rw-r--r--programs/pluto/md2.h72
-rw-r--r--programs/pluto/md5.c385
-rw-r--r--programs/pluto/md5.h75
-rw-r--r--programs/pluto/modecfg.c798
-rw-r--r--programs/pluto/modecfg.h33
-rw-r--r--programs/pluto/mp_defs.c70
-rw-r--r--programs/pluto/mp_defs.h36
-rw-r--r--programs/pluto/nat_traversal.c869
-rw-r--r--programs/pluto/nat_traversal.h154
-rw-r--r--programs/pluto/ocsp.c1568
-rw-r--r--programs/pluto/ocsp.h85
-rw-r--r--programs/pluto/oid.c197
-rw-r--r--programs/pluto/oid.h75
-rw-r--r--programs/pluto/oid.pl123
-rw-r--r--programs/pluto/oid.txt184
-rw-r--r--programs/pluto/packet.c1244
-rw-r--r--programs/pluto/packet.h655
-rw-r--r--programs/pluto/pem.c463
-rw-r--r--programs/pluto/pem.h18
-rw-r--r--programs/pluto/pgp.c647
-rw-r--r--programs/pluto/pgp.h54
-rw-r--r--programs/pluto/pkcs1.c635
-rw-r--r--programs/pluto/pkcs1.h88
-rw-r--r--programs/pluto/pkcs7.c862
-rw-r--r--programs/pluto/pkcs7.h51
-rw-r--r--programs/pluto/pluto-style.el4
-rw-r--r--programs/pluto/pluto.81649
-rw-r--r--programs/pluto/plutomain.c696
-rw-r--r--programs/pluto/primegen.c593
-rw-r--r--programs/pluto/rcv_info.c308
-rw-r--r--programs/pluto/rcv_info.h18
-rw-r--r--programs/pluto/rcv_whack.c655
-rw-r--r--programs/pluto/rcv_whack.h17
-rw-r--r--programs/pluto/rnd.c250
-rw-r--r--programs/pluto/rnd.h21
-rw-r--r--programs/pluto/routing.txt331
-rw-r--r--programs/pluto/rsaref/pkcs11.h299
-rw-r--r--programs/pluto/rsaref/pkcs11f.h912
-rw-r--r--programs/pluto/rsaref/pkcs11t.h1685
-rw-r--r--programs/pluto/rsaref/unix.h24
-rw-r--r--programs/pluto/server.c1064
-rw-r--r--programs/pluto/server.h60
-rw-r--r--programs/pluto/sha1.c193
-rw-r--r--programs/pluto/sha1.h16
-rw-r--r--programs/pluto/smallprime.c122
-rw-r--r--programs/pluto/smartcard.c1956
-rw-r--r--programs/pluto/smartcard.h100
-rw-r--r--programs/pluto/spdb.c2402
-rw-r--r--programs/pluto/spdb.h113
-rw-r--r--programs/pluto/state.c1007
-rw-r--r--programs/pluto/state.h269
-rw-r--r--programs/pluto/timer.c537
-rw-r--r--programs/pluto/timer.h34
-rw-r--r--programs/pluto/vendor.c493
-rw-r--r--programs/pluto/vendor.h107
-rw-r--r--programs/pluto/virtual.c338
-rw-r--r--programs/pluto/virtual.h31
-rw-r--r--programs/pluto/whack.c1911
-rw-r--r--programs/pluto/whack.h318
-rw-r--r--programs/pluto/x509.c2241
-rw-r--r--programs/pluto/x509.h138
-rw-r--r--programs/proc/Makefile51
-rw-r--r--programs/proc/trap_count.535
-rw-r--r--programs/proc/trap_sendcount.533
-rw-r--r--programs/proc/version.554
-rw-r--r--programs/ranbits/.cvsignore1
-rw-r--r--programs/ranbits/Makefile39
-rw-r--r--programs/ranbits/ranbits.877
-rw-r--r--programs/ranbits/ranbits.c146
-rw-r--r--programs/rsasigkey/.cvsignore1
-rw-r--r--programs/rsasigkey/Makefile39
-rw-r--r--programs/rsasigkey/rsasigkey.8259
-rw-r--r--programs/rsasigkey/rsasigkey.c573
-rw-r--r--programs/scepclient/Makefile184
-rw-r--r--programs/scepclient/pkcs10.c220
-rw-r--r--programs/scepclient/pkcs10.h57
-rw-r--r--programs/scepclient/rsakey.c349
-rw-r--r--programs/scepclient/rsakey.h31
-rw-r--r--programs/scepclient/scep.c598
-rw-r--r--programs/scepclient/scep.h93
-rw-r--r--programs/scepclient/scepclient.8288
-rw-r--r--programs/scepclient/scepclient.c1036
-rw-r--r--programs/secrets/Makefile38
-rw-r--r--programs/secrets/secrets.820
-rw-r--r--programs/secrets/secrets.in18
-rw-r--r--programs/send-pr/.cvsignore1
-rw-r--r--programs/send-pr/Makefile39
-rw-r--r--programs/send-pr/ipsec_pr.template54
-rw-r--r--programs/send-pr/send-pr.8291
-rwxr-xr-xprograms/send-pr/send-pr.in643
-rw-r--r--programs/setup/.cvsignore1
-rw-r--r--programs/setup/Makefile22
-rw-r--r--programs/setup/setup.8142
-rwxr-xr-xprograms/setup/setup.in162
-rw-r--r--programs/showdefaults/.cvsignore1
-rw-r--r--programs/showdefaults/Makefile38
-rw-r--r--programs/showdefaults/showdefaults.834
-rwxr-xr-xprograms/showdefaults/showdefaults.in33
-rw-r--r--programs/showhostkey/.cvsignore1
-rw-r--r--programs/showhostkey/Makefile38
-rw-r--r--programs/showhostkey/showhostkey.8168
-rwxr-xr-xprograms/showhostkey/showhostkey.in180
-rw-r--r--programs/showpolicy/.cvsignore1
-rw-r--r--programs/showpolicy/Makefile38
-rw-r--r--programs/showpolicy/showpolicy.841
-rw-r--r--programs/showpolicy/showpolicy.c251
-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
-rw-r--r--programs/spigrp/.cvsignore1
-rw-r--r--programs/spigrp/Makefile52
-rw-r--r--programs/spigrp/spigrp.5116
-rw-r--r--programs/spigrp/spigrp.8174
-rw-r--r--programs/spigrp/spigrp.c491
-rw-r--r--programs/starter/Makefile182
-rw-r--r--programs/starter/README104
-rw-r--r--programs/starter/args.c620
-rw-r--r--programs/starter/args.h34
-rw-r--r--programs/starter/cmp.c105
-rw-r--r--programs/starter/cmp.h29
-rw-r--r--programs/starter/confread.c861
-rw-r--r--programs/starter/confread.h199
-rw-r--r--programs/starter/exec.c54
-rw-r--r--programs/starter/exec.h23
-rw-r--r--programs/starter/files.h47
-rw-r--r--programs/starter/interfaces.c595
-rw-r--r--programs/starter/interfaces.h41
-rw-r--r--programs/starter/invokepluto.c286
-rw-r--r--programs/starter/invokepluto.h28
-rw-r--r--programs/starter/keywords.c235
-rw-r--r--programs/starter/keywords.h164
-rw-r--r--programs/starter/keywords.txt105
-rw-r--r--programs/starter/klips.c134
-rw-r--r--programs/starter/klips.h26
-rw-r--r--programs/starter/lex.yy.c1966
-rw-r--r--programs/starter/netkey.c85
-rw-r--r--programs/starter/netkey.h24
-rw-r--r--programs/starter/parser.h57
-rw-r--r--programs/starter/parser.l190
-rw-r--r--programs/starter/parser.output351
-rw-r--r--programs/starter/parser.tab.c1666
-rw-r--r--programs/starter/parser.tab.h72
-rw-r--r--programs/starter/parser.y283
-rw-r--r--programs/starter/starter.80
-rw-r--r--programs/starter/starter.c571
-rw-r--r--programs/starter/starterwhack.c371
-rw-r--r--programs/starter/starterwhack.h32
-rw-r--r--programs/tncfg/.cvsignore1
-rw-r--r--programs/tncfg/Makefile52
-rw-r--r--programs/tncfg/tncfg.5109
-rw-r--r--programs/tncfg/tncfg.8113
-rw-r--r--programs/tncfg/tncfg.c393
-rw-r--r--testing/INSTALL150
-rw-r--r--testing/README160
-rwxr-xr-xtesting/do-tests458
-rw-r--r--testing/hosts/alice/etc/conf.d/hostname1
-rw-r--r--testing/hosts/alice/etc/conf.d/net11
-rwxr-xr-xtesting/hosts/alice/etc/init.d/iptables74
-rwxr-xr-xtesting/hosts/alice/etc/init.d/net.eth0314
-rwxr-xr-xtesting/hosts/alice/etc/ipsec.conf25
-rw-r--r--testing/hosts/alice/etc/ipsec.d/cacerts/strongswanCert.pem22
-rw-r--r--testing/hosts/alice/etc/ipsec.d/certs/aliceCert.pem25
-rw-r--r--testing/hosts/alice/etc/ipsec.d/private/aliceKey.pem27
-rw-r--r--testing/hosts/alice/etc/ipsec.secrets9
-rwxr-xr-xtesting/hosts/alice/etc/runlevels/default/net.eth0314
-rw-r--r--testing/hosts/bob/etc/conf.d/hostname1
-rw-r--r--testing/hosts/bob/etc/conf.d/net10
-rwxr-xr-xtesting/hosts/bob/etc/init.d/iptables74
-rwxr-xr-xtesting/hosts/bob/etc/init.d/net.eth0314
-rwxr-xr-xtesting/hosts/bob/etc/ipsec.conf24
-rw-r--r--testing/hosts/bob/etc/ipsec.d/cacerts/strongswanCert.pem22
-rw-r--r--testing/hosts/bob/etc/ipsec.d/certs/bobCert.pem25
-rw-r--r--testing/hosts/bob/etc/ipsec.d/private/bobKey.pem27
-rw-r--r--testing/hosts/bob/etc/ipsec.secrets8
-rwxr-xr-xtesting/hosts/bob/etc/runlevels/default/net.eth0314
-rw-r--r--testing/hosts/carol/etc/conf.d/hostname1
-rw-r--r--testing/hosts/carol/etc/conf.d/net10
-rwxr-xr-xtesting/hosts/carol/etc/init.d/iptables73
-rwxr-xr-xtesting/hosts/carol/etc/init.d/net.eth0314
-rwxr-xr-xtesting/hosts/carol/etc/ipsec.conf29
-rw-r--r--testing/hosts/carol/etc/ipsec.d/cacerts/strongswanCert.pem22
-rw-r--r--testing/hosts/carol/etc/ipsec.d/certs/carolCert.pem25
-rw-r--r--testing/hosts/carol/etc/ipsec.d/private/carolKey.pem27
-rw-r--r--testing/hosts/carol/etc/ipsec.secrets7
-rwxr-xr-xtesting/hosts/carol/etc/runlevels/default/net.eth0314
-rw-r--r--testing/hosts/dave/etc/conf.d/hostname1
-rw-r--r--testing/hosts/dave/etc/conf.d/net10
-rwxr-xr-xtesting/hosts/dave/etc/init.d/iptables73
-rwxr-xr-xtesting/hosts/dave/etc/init.d/net.eth0314
-rwxr-xr-xtesting/hosts/dave/etc/ipsec.conf24
-rw-r--r--testing/hosts/dave/etc/ipsec.d/cacerts/strongswanCert.pem22
-rw-r--r--testing/hosts/dave/etc/ipsec.d/certs/daveCert.pem25
-rw-r--r--testing/hosts/dave/etc/ipsec.d/private/daveKey.pem27
-rw-r--r--testing/hosts/dave/etc/ipsec.secrets7
-rwxr-xr-xtesting/hosts/dave/etc/runlevels/default/net.eth0314
-rw-r--r--testing/hosts/default/etc/hosts34
-rw-r--r--testing/hosts/moon/etc/conf.d/hostname1
-rw-r--r--testing/hosts/moon/etc/conf.d/net11
-rwxr-xr-xtesting/hosts/moon/etc/init.d/iptables76
-rwxr-xr-xtesting/hosts/moon/etc/init.d/net.eth0314
-rwxr-xr-xtesting/hosts/moon/etc/init.d/net.eth1314
-rwxr-xr-xtesting/hosts/moon/etc/ipsec.conf36
-rw-r--r--testing/hosts/moon/etc/ipsec.d/cacerts/strongswanCert.pem22
-rw-r--r--testing/hosts/moon/etc/ipsec.d/certs/moonCert.pem24
-rw-r--r--testing/hosts/moon/etc/ipsec.d/private/moonKey.pem27
-rw-r--r--testing/hosts/moon/etc/ipsec.secrets7
-rwxr-xr-xtesting/hosts/moon/etc/runlevels/default/net.eth0314
-rwxr-xr-xtesting/hosts/moon/etc/runlevels/default/net.eth1314
-rw-r--r--testing/hosts/ssh_host_rsa_key.pub1
-rw-r--r--testing/hosts/sun/etc/conf.d/hostname1
-rw-r--r--testing/hosts/sun/etc/conf.d/net13
-rwxr-xr-xtesting/hosts/sun/etc/init.d/iptables80
-rwxr-xr-xtesting/hosts/sun/etc/init.d/net.eth0314
-rwxr-xr-xtesting/hosts/sun/etc/init.d/net.eth1314
-rwxr-xr-xtesting/hosts/sun/etc/ipsec.conf37
-rw-r--r--testing/hosts/sun/etc/ipsec.d/cacerts/strongswanCert.pem22
-rw-r--r--testing/hosts/sun/etc/ipsec.d/certs/sunCert.pem24
-rw-r--r--testing/hosts/sun/etc/ipsec.d/private/sunKey.pem27
-rw-r--r--testing/hosts/sun/etc/ipsec.secrets8
-rwxr-xr-xtesting/hosts/sun/etc/runlevels/default/net.eth0314
-rwxr-xr-xtesting/hosts/sun/etc/runlevels/default/net.eth1314
-rw-r--r--testing/hosts/venus/etc/conf.d/hostname1
-rw-r--r--testing/hosts/venus/etc/conf.d/net11
-rwxr-xr-xtesting/hosts/venus/etc/init.d/iptables74
-rwxr-xr-xtesting/hosts/venus/etc/init.d/net.eth0314
-rwxr-xr-xtesting/hosts/venus/etc/ipsec.conf25
-rw-r--r--testing/hosts/venus/etc/ipsec.d/cacerts/strongswanCert.pem22
-rw-r--r--testing/hosts/venus/etc/ipsec.d/certs/venusCert.pem24
-rw-r--r--testing/hosts/venus/etc/ipsec.d/private/venusKey.pem27
-rw-r--r--testing/hosts/venus/etc/ipsec.secrets8
-rwxr-xr-xtesting/hosts/venus/etc/runlevels/default/net.eth0314
-rw-r--r--testing/hosts/winnetou/etc/apache2/conf/ssl/ca.crt22
-rw-r--r--testing/hosts/winnetou/etc/apache2/conf/ssl/server.crt24
-rw-r--r--testing/hosts/winnetou/etc/apache2/conf/ssl/server.key27
-rw-r--r--testing/hosts/winnetou/etc/conf.d/apache252
-rw-r--r--testing/hosts/winnetou/etc/conf.d/hostname1
-rw-r--r--testing/hosts/winnetou/etc/conf.d/net10
-rw-r--r--testing/hosts/winnetou/etc/conf.d/slapd8
-rw-r--r--testing/hosts/winnetou/etc/hostname1
-rwxr-xr-xtesting/hosts/winnetou/etc/init.d/apache278
-rwxr-xr-xtesting/hosts/winnetou/etc/init.d/net.eth0314
-rwxr-xr-xtesting/hosts/winnetou/etc/init.d/slapd25
-rw-r--r--testing/hosts/winnetou/etc/openldap/ldif.txt40
-rw-r--r--testing/hosts/winnetou/etc/openldap/slapd.conf68
-rwxr-xr-xtesting/hosts/winnetou/etc/openssl/generate-crl35
-rw-r--r--testing/hosts/winnetou/etc/openssl/index.html36
-rw-r--r--testing/hosts/winnetou/etc/openssl/index.txt15
-rw-r--r--testing/hosts/winnetou/etc/openssl/index.txt.attr1
-rw-r--r--testing/hosts/winnetou/etc/openssl/index.txt.attr.old1
-rw-r--r--testing/hosts/winnetou/etc/openssl/index.txt.old14
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/01.pem24
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/02.pem24
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/03.pem24
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/04.pem24
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/05.pem25
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/06.pem25
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/07.pem25
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/08.pem25
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/09.pem25
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/0A.pem25
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/0B.pem25
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/0C.pem23
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/0D.pem22
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/0E.pem24
-rw-r--r--testing/hosts/winnetou/etc/openssl/newcerts/0F.pem23
-rw-r--r--testing/hosts/winnetou/etc/openssl/ocspCert.pem25
-rw-r--r--testing/hosts/winnetou/etc/openssl/ocspKey.pem27
-rw-r--r--testing/hosts/winnetou/etc/openssl/openssl.cnf182
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/.randbin0 -> 1024 bytes
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/carolReq.pem17
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/index.txt2
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/index.txt.attr1
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/index.txt.attr.old1
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/index.txt.old1
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/newcerts/01.pem25
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/newcerts/02.pem24
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/openssl.cnf181
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/researchCert.derbin0 -> 965 bytes
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/researchCert.pem23
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/researchKey.pem27
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/serial1
-rw-r--r--testing/hosts/winnetou/etc/openssl/research/serial.old1
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/.randbin0 -> 1024 bytes
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/index.txt2
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/index.txt.attr1
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/index.txt.old1
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/newcerts/01.pem24
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/newcerts/02.pem24
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/openssl.cnf181
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/salesCert.derbin0 -> 959 bytes
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/salesCert.pem22
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/salesKey.pem27
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/serial1
-rw-r--r--testing/hosts/winnetou/etc/openssl/sales/serial.old1
-rw-r--r--testing/hosts/winnetou/etc/openssl/serial1
-rw-r--r--testing/hosts/winnetou/etc/openssl/serial.old1
-rwxr-xr-xtesting/hosts/winnetou/etc/openssl/start-ocsp20
-rw-r--r--testing/hosts/winnetou/etc/openssl/strongswanCert.derbin0 -> 953 bytes
-rw-r--r--testing/hosts/winnetou/etc/openssl/strongswanCert.pem22
-rw-r--r--testing/hosts/winnetou/etc/openssl/strongswanKey.pem27
-rwxr-xr-xtesting/hosts/winnetou/etc/runlevels/default/apache278
-rwxr-xr-xtesting/hosts/winnetou/etc/runlevels/default/net.eth0314
-rwxr-xr-xtesting/images/a-m-c-w-d.pngbin0 -> 23987 bytes
-rwxr-xr-xtesting/images/a-m-c-w.pngbin0 -> 19339 bytes
-rw-r--r--testing/images/a-m-c.pngbin0 -> 15755 bytes
-rwxr-xr-xtesting/images/a-m-w-s-b.pngbin0 -> 23365 bytes
-rwxr-xr-xtesting/images/a-v-m-c-w-d.pngbin0 -> 27900 bytes
-rwxr-xr-xtesting/images/a-v-m-w-s-b.pngbin0 -> 27769 bytes
-rwxr-xr-xtesting/images/m-c-w.pngbin0 -> 13018 bytes
-rwxr-xr-xtesting/images/m-w-s.pngbin0 -> 12340 bytes
-rw-r--r--testing/images/umlArchitecture_large.pngbin0 -> 108323 bytes
-rw-r--r--testing/images/umlArchitecture_small.pngbin0 -> 40071 bytes
-rwxr-xr-xtesting/make-testing89
-rwxr-xr-xtesting/scripts/build-hostconfig103
-rwxr-xr-xtesting/scripts/build-sshkeys88
-rwxr-xr-xtesting/scripts/build-umlhostfs78
-rwxr-xr-xtesting/scripts/build-umlkernel134
-rwxr-xr-xtesting/scripts/build-umlrootfs174
-rwxr-xr-xtesting/scripts/function.sh82
-rwxr-xr-xtesting/scripts/kstart-umls113
-rwxr-xr-xtesting/scripts/load-testconfig64
-rwxr-xr-xtesting/scripts/restore-defaults53
-rwxr-xr-xtesting/scripts/start-switches39
-rwxr-xr-xtesting/scripts/start-umls113
-rwxr-xr-xtesting/scripts/xstart-umls113
-rwxr-xr-xtesting/start-testing83
-rwxr-xr-xtesting/stop-testing51
-rwxr-xr-xtesting/testing.conf154
-rw-r--r--testing/tests/alg-blowfish/description.txt4
-rw-r--r--testing/tests/alg-blowfish/evaltest.dat9
-rwxr-xr-xtesting/tests/alg-blowfish/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/alg-blowfish/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/alg-blowfish/posttest.dat2
-rw-r--r--testing/tests/alg-blowfish/pretest.dat5
-rw-r--r--testing/tests/alg-blowfish/test.conf22
-rw-r--r--testing/tests/alg-serpent/description.txt4
-rw-r--r--testing/tests/alg-serpent/evaltest.dat9
-rwxr-xr-xtesting/tests/alg-serpent/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/alg-serpent/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/alg-serpent/posttest.dat2
-rw-r--r--testing/tests/alg-serpent/pretest.dat5
-rw-r--r--testing/tests/alg-serpent/test.conf22
-rw-r--r--testing/tests/alg-sha2_256/description.txt4
-rw-r--r--testing/tests/alg-sha2_256/evaltest.dat9
-rwxr-xr-xtesting/tests/alg-sha2_256/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/alg-sha2_256/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/alg-sha2_256/posttest.dat2
-rw-r--r--testing/tests/alg-sha2_256/pretest.dat5
-rw-r--r--testing/tests/alg-sha2_256/test.conf22
-rw-r--r--testing/tests/alg-twofish/description.txt4
-rw-r--r--testing/tests/alg-twofish/evaltest.dat8
-rwxr-xr-xtesting/tests/alg-twofish/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/alg-twofish/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/alg-twofish/posttest.dat2
-rw-r--r--testing/tests/alg-twofish/pretest.dat5
-rw-r--r--testing/tests/alg-twofish/test.conf22
-rw-r--r--testing/tests/attr-cert/description.txt7
-rw-r--r--testing/tests/attr-cert/evaltest.dat12
-rwxr-xr-xtesting/tests/attr-cert/hosts/carol/etc/ipsec.conf33
-rwxr-xr-xtesting/tests/attr-cert/hosts/dave/etc/ipsec.conf33
-rwxr-xr-xtesting/tests/attr-cert/hosts/moon/etc/ipsec.conf31
-rw-r--r--testing/tests/attr-cert/hosts/moon/etc/ipsec.d/aacerts/aaCert.pem25
-rw-r--r--testing/tests/attr-cert/hosts/moon/etc/openac/aaKey.pem27
-rw-r--r--testing/tests/attr-cert/hosts/moon/etc/openac/carolCert.pem25
-rw-r--r--testing/tests/attr-cert/hosts/moon/etc/openac/daveCert.pem25
-rw-r--r--testing/tests/attr-cert/hosts/moon/etc/openac/default.conf4
-rw-r--r--testing/tests/attr-cert/posttest.dat6
-rw-r--r--testing/tests/attr-cert/pretest.dat12
-rw-r--r--testing/tests/attr-cert/test.conf21
-rw-r--r--testing/tests/compress/description.txt3
-rw-r--r--testing/tests/compress/evaltest.dat10
-rwxr-xr-xtesting/tests/compress/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/compress/hosts/moon/etc/ipsec.conf25
-rw-r--r--testing/tests/compress/posttest.dat2
-rw-r--r--testing/tests/compress/pretest.dat5
-rw-r--r--testing/tests/compress/test.conf22
-rw-r--r--testing/tests/crl-from-cache/description.txt5
-rw-r--r--testing/tests/crl-from-cache/evaltest.dat10
-rwxr-xr-xtesting/tests/crl-from-cache/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/crl-from-cache/hosts/moon/etc/ipsec.conf36
-rw-r--r--testing/tests/crl-from-cache/posttest.dat4
-rw-r--r--testing/tests/crl-from-cache/pretest.dat8
-rw-r--r--testing/tests/crl-from-cache/test.conf21
-rw-r--r--testing/tests/crl-ldap/description.txt9
-rw-r--r--testing/tests/crl-ldap/evaltest.dat16
-rwxr-xr-xtesting/tests/crl-ldap/hosts/carol/etc/init.d/iptables73
-rwxr-xr-xtesting/tests/crl-ldap/hosts/carol/etc/ipsec.conf31
-rw-r--r--testing/tests/crl-ldap/hosts/carol/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crlbin0 -> 560 bytes
-rwxr-xr-xtesting/tests/crl-ldap/hosts/moon/etc/init.d/iptables76
-rwxr-xr-xtesting/tests/crl-ldap/hosts/moon/etc/ipsec.conf42
-rw-r--r--testing/tests/crl-ldap/hosts/moon/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crlbin0 -> 560 bytes
-rw-r--r--testing/tests/crl-ldap/posttest.dat9
-rw-r--r--testing/tests/crl-ldap/pretest.dat7
-rw-r--r--testing/tests/crl-ldap/test.conf21
-rw-r--r--testing/tests/crl-revoked/description.txt7
-rw-r--r--testing/tests/crl-revoked/evaltest.dat6
-rwxr-xr-xtesting/tests/crl-revoked/hosts/carol/etc/ipsec.conf24
-rw-r--r--testing/tests/crl-revoked/hosts/carol/etc/ipsec.d/certs/carolRevokedCert.pem25
-rw-r--r--testing/tests/crl-revoked/hosts/carol/etc/ipsec.d/private/carolRevokedKey.pem27
-rw-r--r--testing/tests/crl-revoked/hosts/carol/etc/ipsec.secrets3
-rwxr-xr-xtesting/tests/crl-revoked/hosts/moon/etc/ipsec.conf35
-rw-r--r--testing/tests/crl-revoked/posttest.dat4
-rw-r--r--testing/tests/crl-revoked/pretest.dat4
-rw-r--r--testing/tests/crl-revoked/test.conf21
-rw-r--r--testing/tests/crl-strict/description.txt6
-rw-r--r--testing/tests/crl-strict/evaltest.dat8
-rwxr-xr-xtesting/tests/crl-strict/hosts/carol/etc/ipsec.conf24
-rwxr-xr-xtesting/tests/crl-strict/hosts/moon/etc/ipsec.conf35
-rw-r--r--testing/tests/crl-strict/posttest.dat2
-rw-r--r--testing/tests/crl-strict/pretest.dat4
-rw-r--r--testing/tests/crl-strict/test.conf21
-rw-r--r--testing/tests/crl-to-cache/description.txt6
-rw-r--r--testing/tests/crl-to-cache/evaltest.dat4
-rwxr-xr-xtesting/tests/crl-to-cache/hosts/carol/etc/ipsec.conf24
-rwxr-xr-xtesting/tests/crl-to-cache/hosts/moon/etc/ipsec.conf23
-rw-r--r--testing/tests/crl-to-cache/posttest.dat4
-rw-r--r--testing/tests/crl-to-cache/pretest.dat4
-rw-r--r--testing/tests/crl-to-cache/test.conf21
-rw-r--r--testing/tests/default-keys/description.txt8
-rw-r--r--testing/tests/default-keys/evaltest.dat7
-rwxr-xr-xtesting/tests/default-keys/hosts/carol/etc/ipsec.conf26
-rwxr-xr-xtesting/tests/default-keys/hosts/moon/etc/init.d/iptables78
-rwxr-xr-xtesting/tests/default-keys/hosts/moon/etc/ipsec.conf27
-rw-r--r--testing/tests/default-keys/posttest.dat10
-rw-r--r--testing/tests/default-keys/pretest.dat18
-rw-r--r--testing/tests/default-keys/test.conf21
-rw-r--r--testing/tests/double-nat-net/description.txt7
-rw-r--r--testing/tests/double-nat-net/evaltest.dat5
-rwxr-xr-xtesting/tests/double-nat-net/hosts/alice/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/double-nat-net/hosts/bob/etc/ipsec.conf25
-rw-r--r--testing/tests/double-nat-net/posttest.dat9
-rw-r--r--testing/tests/double-nat-net/pretest.dat15
-rw-r--r--testing/tests/double-nat-net/test.conf21
-rw-r--r--testing/tests/double-nat/description.txt5
-rw-r--r--testing/tests/double-nat/evaltest.dat5
-rwxr-xr-xtesting/tests/double-nat/hosts/alice/etc/ipsec.conf25
-rw-r--r--testing/tests/double-nat/posttest.dat8
-rw-r--r--testing/tests/double-nat/pretest.dat13
-rw-r--r--testing/tests/double-nat/test.conf21
-rw-r--r--testing/tests/dpd-clear/description.txt5
-rw-r--r--testing/tests/dpd-clear/evaltest.dat7
-rwxr-xr-xtesting/tests/dpd-clear/hosts/moon/etc/ipsec.conf30
-rw-r--r--testing/tests/dpd-clear/posttest.dat3
-rw-r--r--testing/tests/dpd-clear/pretest.dat4
-rw-r--r--testing/tests/dpd-clear/test.conf21
-rw-r--r--testing/tests/esp-ah-transport/description.txt5
-rw-r--r--testing/tests/esp-ah-transport/evaltest.dat8
-rwxr-xr-xtesting/tests/esp-ah-transport/hosts/carol/etc/init.d/iptables73
-rwxr-xr-xtesting/tests/esp-ah-transport/hosts/carol/etc/ipsec.conf28
-rwxr-xr-xtesting/tests/esp-ah-transport/hosts/moon/etc/init.d/iptables76
-rwxr-xr-xtesting/tests/esp-ah-transport/hosts/moon/etc/ipsec.conf28
-rw-r--r--testing/tests/esp-ah-transport/posttest.dat6
-rw-r--r--testing/tests/esp-ah-transport/pretest.dat6
-rw-r--r--testing/tests/esp-ah-transport/test.conf22
-rw-r--r--testing/tests/esp-ah-tunnel/description.txt6
-rw-r--r--testing/tests/esp-ah-tunnel/evaltest.dat8
-rwxr-xr-xtesting/tests/esp-ah-tunnel/hosts/carol/etc/init.d/iptables73
-rwxr-xr-xtesting/tests/esp-ah-tunnel/hosts/carol/etc/ipsec.conf28
-rwxr-xr-xtesting/tests/esp-ah-tunnel/hosts/moon/etc/init.d/iptables76
-rwxr-xr-xtesting/tests/esp-ah-tunnel/hosts/moon/etc/ipsec.conf28
-rw-r--r--testing/tests/esp-ah-tunnel/posttest.dat6
-rw-r--r--testing/tests/esp-ah-tunnel/pretest.dat6
-rw-r--r--testing/tests/esp-ah-tunnel/test.conf22
-rw-r--r--testing/tests/esp-alg-des/description.txt5
-rw-r--r--testing/tests/esp-alg-des/evaltest.dat6
-rwxr-xr-xtesting/tests/esp-alg-des/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/esp-alg-des/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/esp-alg-des/posttest.dat2
-rw-r--r--testing/tests/esp-alg-des/pretest.dat5
-rw-r--r--testing/tests/esp-alg-des/test.conf22
-rw-r--r--testing/tests/esp-alg-null/description.txt5
-rw-r--r--testing/tests/esp-alg-null/evaltest.dat5
-rwxr-xr-xtesting/tests/esp-alg-null/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/esp-alg-null/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/esp-alg-null/posttest.dat2
-rw-r--r--testing/tests/esp-alg-null/pretest.dat4
-rw-r--r--testing/tests/esp-alg-null/test.conf22
-rw-r--r--testing/tests/esp-alg-strict-fail/description.txt5
-rw-r--r--testing/tests/esp-alg-strict-fail/evaltest.dat9
-rwxr-xr-xtesting/tests/esp-alg-strict-fail/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/esp-alg-strict-fail/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/esp-alg-strict-fail/posttest.dat2
-rw-r--r--testing/tests/esp-alg-strict-fail/pretest.dat4
-rw-r--r--testing/tests/esp-alg-strict-fail/test.conf21
-rw-r--r--testing/tests/esp-alg-strict/description.txt7
-rw-r--r--testing/tests/esp-alg-strict/evaltest.dat7
-rwxr-xr-xtesting/tests/esp-alg-strict/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/esp-alg-strict/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/esp-alg-strict/posttest.dat2
-rw-r--r--testing/tests/esp-alg-strict/pretest.dat4
-rw-r--r--testing/tests/esp-alg-strict/test.conf22
-rw-r--r--testing/tests/esp-alg-weak/description.txt5
-rw-r--r--testing/tests/esp-alg-weak/evaltest.dat5
-rwxr-xr-xtesting/tests/esp-alg-weak/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/esp-alg-weak/hosts/moon/etc/ipsec.conf24
-rw-r--r--testing/tests/esp-alg-weak/posttest.dat2
-rw-r--r--testing/tests/esp-alg-weak/pretest.dat5
-rw-r--r--testing/tests/esp-alg-weak/test.conf22
-rw-r--r--testing/tests/host2host-cert/description.txt4
-rw-r--r--testing/tests/host2host-cert/evaltest.dat5
-rw-r--r--testing/tests/host2host-cert/posttest.dat6
-rw-r--r--testing/tests/host2host-cert/pretest.dat6
-rw-r--r--testing/tests/host2host-cert/test.conf21
-rw-r--r--testing/tests/host2host-swapped/description.txt3
-rw-r--r--testing/tests/host2host-swapped/evaltest.dat5
-rwxr-xr-xtesting/tests/host2host-swapped/hosts/moon/etc/ipsec.conf24
-rwxr-xr-xtesting/tests/host2host-swapped/hosts/sun/etc/ipsec.conf25
-rw-r--r--testing/tests/host2host-swapped/posttest.dat6
-rw-r--r--testing/tests/host2host-swapped/pretest.dat6
-rw-r--r--testing/tests/host2host-swapped/test.conf21
-rw-r--r--testing/tests/host2host-transport/description.txt4
-rw-r--r--testing/tests/host2host-transport/evaltest.dat5
-rwxr-xr-xtesting/tests/host2host-transport/hosts/moon/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/host2host-transport/hosts/sun/etc/ipsec.conf26
-rw-r--r--testing/tests/host2host-transport/posttest.dat6
-rw-r--r--testing/tests/host2host-transport/pretest.dat6
-rw-r--r--testing/tests/host2host-transport/test.conf21
-rw-r--r--testing/tests/ike-alg-sha2_512/description.txt4
-rw-r--r--testing/tests/ike-alg-sha2_512/evaltest.dat8
-rwxr-xr-xtesting/tests/ike-alg-sha2_512/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/ike-alg-sha2_512/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/ike-alg-sha2_512/posttest.dat2
-rw-r--r--testing/tests/ike-alg-sha2_512/pretest.dat5
-rw-r--r--testing/tests/ike-alg-sha2_512/test.conf22
-rw-r--r--testing/tests/ike-alg-strict-fail/description.txt5
-rw-r--r--testing/tests/ike-alg-strict-fail/evaltest.dat5
-rwxr-xr-xtesting/tests/ike-alg-strict-fail/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/ike-alg-strict-fail/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/ike-alg-strict-fail/posttest.dat2
-rw-r--r--testing/tests/ike-alg-strict-fail/pretest.dat4
-rw-r--r--testing/tests/ike-alg-strict-fail/test.conf21
-rw-r--r--testing/tests/ike-alg-strict/description.txt5
-rw-r--r--testing/tests/ike-alg-strict/evaltest.dat7
-rwxr-xr-xtesting/tests/ike-alg-strict/hosts/carol/etc/ipsec.conf25
-rwxr-xr-xtesting/tests/ike-alg-strict/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/ike-alg-strict/posttest.dat2
-rw-r--r--testing/tests/ike-alg-strict/pretest.dat4
-rw-r--r--testing/tests/ike-alg-strict/test.conf21
-rw-r--r--testing/tests/mode-config-swapped/description.txt3
-rw-r--r--testing/tests/mode-config-swapped/evaltest.dat16
-rwxr-xr-xtesting/tests/mode-config-swapped/hosts/carol/etc/ipsec.conf30
-rwxr-xr-xtesting/tests/mode-config-swapped/hosts/dave/etc/ipsec.conf30
-rwxr-xr-xtesting/tests/mode-config-swapped/hosts/moon/etc/ipsec.conf33
-rw-r--r--testing/tests/mode-config-swapped/posttest.dat11
-rw-r--r--testing/tests/mode-config-swapped/pretest.dat9
-rw-r--r--testing/tests/mode-config-swapped/test.conf21
-rw-r--r--testing/tests/mode-config/description.txt7
-rw-r--r--testing/tests/mode-config/evaltest.dat16
-rwxr-xr-xtesting/tests/mode-config/hosts/carol/etc/ipsec.conf30
-rwxr-xr-xtesting/tests/mode-config/hosts/dave/etc/ipsec.conf30
-rwxr-xr-xtesting/tests/mode-config/hosts/moon/etc/ipsec.conf33
-rw-r--r--testing/tests/mode-config/posttest.dat11
-rw-r--r--testing/tests/mode-config/pretest.dat9
-rw-r--r--testing/tests/mode-config/test.conf21
-rw-r--r--testing/tests/multi-level-ca-ldap/description.txt11
-rw-r--r--testing/tests/multi-level-ca-ldap/evaltest.dat13
-rwxr-xr-xtesting/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.conf32
-rw-r--r--testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.d/certs/carolCert.pem25
-rw-r--r--testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.d/private/carolKey.pem27
-rwxr-xr-xtesting/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.conf32
-rw-r--r--testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.d/certs/daveCert.pem24
-rw-r--r--testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.d/private/daveKey.pem27
-rwxr-xr-xtesting/tests/multi-level-ca-ldap/hosts/moon/etc/init.d/iptables76
-rwxr-xr-xtesting/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.conf47
-rw-r--r--testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem23
-rw-r--r--testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem22
-rw-r--r--testing/tests/multi-level-ca-ldap/posttest.dat8
-rw-r--r--testing/tests/multi-level-ca-ldap/pretest.dat10
-rw-r--r--testing/tests/multi-level-ca-ldap/test.conf21
-rw-r--r--testing/tests/multi-level-ca-loop/description.txt6
-rw-r--r--testing/tests/multi-level-ca-loop/evaltest.dat3
-rwxr-xr-xtesting/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.conf28
-rw-r--r--testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.d/certs/carolCert.pem25
-rw-r--r--testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.d/private/carolKey.pem27
-rwxr-xr-xtesting/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.conf24
-rw-r--r--testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.d/cacerts/research_by_salesCert.pem24
-rw-r--r--testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.d/cacerts/sales_by_researchCert.pem24
-rw-r--r--testing/tests/multi-level-ca-loop/posttest.dat4
-rw-r--r--testing/tests/multi-level-ca-loop/pretest.dat6
-rw-r--r--testing/tests/multi-level-ca-loop/test.conf21
-rw-r--r--testing/tests/multi-level-ca-revoked/description.txt4
-rw-r--r--testing/tests/multi-level-ca-revoked/evaltest.dat6
-rwxr-xr-xtesting/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.conf24
-rw-r--r--testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.d/certs/carolCert.pem25
-rw-r--r--testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.d/private/carolKey.pem27
-rw-r--r--testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.secrets3
-rwxr-xr-xtesting/tests/multi-level-ca-revoked/hosts/moon/etc/ipsec.conf29
-rw-r--r--testing/tests/multi-level-ca-revoked/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem23
-rw-r--r--testing/tests/multi-level-ca-revoked/posttest.dat3
-rw-r--r--testing/tests/multi-level-ca-revoked/pretest.dat4
-rw-r--r--testing/tests/multi-level-ca-revoked/test.conf21
-rw-r--r--testing/tests/multi-level-ca-strict/description.txt10
-rw-r--r--testing/tests/multi-level-ca-strict/evaltest.dat12
-rwxr-xr-xtesting/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.conf32
-rw-r--r--testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.d/certs/carolCert.pem25
-rw-r--r--testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.d/private/carolKey.pem27
-rwxr-xr-xtesting/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.conf32
-rw-r--r--testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.d/certs/daveCert.pem24
-rw-r--r--testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.d/private/daveKey.pem27
-rwxr-xr-xtesting/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.conf36
-rw-r--r--testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem23
-rw-r--r--testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem22
-rw-r--r--testing/tests/multi-level-ca-strict/posttest.dat5
-rw-r--r--testing/tests/multi-level-ca-strict/pretest.dat9
-rw-r--r--testing/tests/multi-level-ca-strict/test.conf21
-rw-r--r--testing/tests/multi-level-ca/description.txt7
-rw-r--r--testing/tests/multi-level-ca/evaltest.dat12
-rwxr-xr-xtesting/tests/multi-level-ca/hosts/carol/etc/ipsec.conf33
-rw-r--r--testing/tests/multi-level-ca/hosts/carol/etc/ipsec.d/certs/carolCert.pem25
-rw-r--r--testing/tests/multi-level-ca/hosts/carol/etc/ipsec.d/private/carolKey.pem27
-rwxr-xr-xtesting/tests/multi-level-ca/hosts/dave/etc/ipsec.conf33
-rw-r--r--testing/tests/multi-level-ca/hosts/dave/etc/ipsec.d/certs/daveCert.pem24
-rw-r--r--testing/tests/multi-level-ca/hosts/dave/etc/ipsec.d/private/daveKey.pem27
-rwxr-xr-xtesting/tests/multi-level-ca/hosts/moon/etc/ipsec.conf37
-rw-r--r--testing/tests/multi-level-ca/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem23
-rw-r--r--testing/tests/multi-level-ca/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem22
-rw-r--r--testing/tests/multi-level-ca/posttest.dat5
-rw-r--r--testing/tests/multi-level-ca/pretest.dat9
-rw-r--r--testing/tests/multi-level-ca/test.conf21
-rw-r--r--testing/tests/nat-one-rw/description.txt5
-rw-r--r--testing/tests/nat-one-rw/evaltest.dat5
-rw-r--r--testing/tests/nat-one-rw/posttest.dat8
-rw-r--r--testing/tests/nat-one-rw/pretest.dat10
-rw-r--r--testing/tests/nat-one-rw/test.conf21
-rw-r--r--testing/tests/nat-two-rw/description.txt5
-rw-r--r--testing/tests/nat-two-rw/evaltest.dat9
-rw-r--r--testing/tests/nat-two-rw/posttest.dat11
-rw-r--r--testing/tests/nat-two-rw/pretest.dat13
-rw-r--r--testing/tests/nat-two-rw/test.conf21
-rw-r--r--testing/tests/net2net-cert/description.txt6
-rw-r--r--testing/tests/net2net-cert/evaltest.dat5
-rw-r--r--testing/tests/net2net-cert/posttest.dat6
-rw-r--r--testing/tests/net2net-cert/pretest.dat6
-rw-r--r--testing/tests/net2net-cert/test.conf21
-rw-r--r--testing/tests/net2net-pgp/description.txt6
-rw-r--r--testing/tests/net2net-pgp/evaltest.dat5
-rwxr-xr-xtesting/tests/net2net-pgp/hosts/moon/etc/ipsec.conf24
-rw-r--r--testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/certs/moonCert.asc15
-rw-r--r--testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/certs/sunCert.asc15
-rw-r--r--testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/private/moonKey.asc19
-rw-r--r--testing/tests/net2net-pgp/hosts/moon/etc/ipsec.secrets3
-rwxr-xr-xtesting/tests/net2net-pgp/hosts/sun/etc/ipsec.conf24
-rw-r--r--testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/certs/moonCert.asc15
-rw-r--r--testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/certs/sunCert.asc15
-rw-r--r--testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/private/sunKey.asc19
-rw-r--r--testing/tests/net2net-pgp/hosts/sun/etc/ipsec.secrets3
-rw-r--r--testing/tests/net2net-pgp/posttest.dat10
-rw-r--r--testing/tests/net2net-pgp/pretest.dat8
-rw-r--r--testing/tests/net2net-pgp/test.conf21
-rw-r--r--testing/tests/net2net-psk-fail/description.txt7
-rw-r--r--testing/tests/net2net-psk-fail/evaltest.dat6
-rwxr-xr-xtesting/tests/net2net-psk-fail/hosts/moon/etc/ipsec.conf23
-rw-r--r--testing/tests/net2net-psk-fail/hosts/moon/etc/ipsec.secrets7
-rwxr-xr-xtesting/tests/net2net-psk-fail/hosts/sun/etc/ipsec.conf23
-rw-r--r--testing/tests/net2net-psk-fail/hosts/sun/etc/ipsec.secrets7
-rw-r--r--testing/tests/net2net-psk-fail/posttest.dat2
-rw-r--r--testing/tests/net2net-psk-fail/pretest.dat6
-rw-r--r--testing/tests/net2net-psk-fail/test.conf21
-rw-r--r--testing/tests/net2net-psk/description.txt6
-rw-r--r--testing/tests/net2net-psk/evaltest.dat5
-rwxr-xr-xtesting/tests/net2net-psk/hosts/moon/etc/ipsec.conf24
-rw-r--r--testing/tests/net2net-psk/hosts/moon/etc/ipsec.secrets7
-rwxr-xr-xtesting/tests/net2net-psk/hosts/sun/etc/ipsec.conf24
-rw-r--r--testing/tests/net2net-psk/hosts/sun/etc/ipsec.secrets7
-rw-r--r--testing/tests/net2net-psk/posttest.dat6
-rw-r--r--testing/tests/net2net-psk/pretest.dat8
-rw-r--r--testing/tests/net2net-psk/test.conf21
-rw-r--r--testing/tests/net2net-route/description.txt9
-rw-r--r--testing/tests/net2net-route/evaltest.dat6
-rwxr-xr-xtesting/tests/net2net-route/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/net2net-route/posttest.dat6
-rw-r--r--testing/tests/net2net-route/pretest.dat6
-rw-r--r--testing/tests/net2net-route/test.conf21
-rw-r--r--testing/tests/net2net-rsa/description.txt6
-rw-r--r--testing/tests/net2net-rsa/evaltest.dat5
-rwxr-xr-xtesting/tests/net2net-rsa/hosts/moon/etc/ipsec.conf25
-rw-r--r--testing/tests/net2net-rsa/hosts/moon/etc/ipsec.secrets17
-rwxr-xr-xtesting/tests/net2net-rsa/hosts/sun/etc/ipsec.conf25
-rw-r--r--testing/tests/net2net-rsa/hosts/sun/etc/ipsec.secrets17
-rw-r--r--testing/tests/net2net-rsa/posttest.dat6
-rw-r--r--testing/tests/net2net-rsa/pretest.dat8
-rw-r--r--testing/tests/net2net-rsa/test.conf21
-rw-r--r--testing/tests/net2net-start/description.txt8
-rw-r--r--testing/tests/net2net-start/evaltest.dat5
-rwxr-xr-xtesting/tests/net2net-start/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/net2net-start/posttest.dat6
-rw-r--r--testing/tests/net2net-start/pretest.dat5
-rw-r--r--testing/tests/net2net-start/test.conf21
-rw-r--r--testing/tests/no-priv-key/description.txt4
-rw-r--r--testing/tests/no-priv-key/evaltest.dat4
-rw-r--r--testing/tests/no-priv-key/hosts/carol/etc/ipsec.secrets3
-rw-r--r--testing/tests/no-priv-key/posttest.dat2
-rw-r--r--testing/tests/no-priv-key/pretest.dat4
-rw-r--r--testing/tests/no-priv-key/test.conf21
-rw-r--r--testing/tests/ocsp-revoked/description.txt7
-rw-r--r--testing/tests/ocsp-revoked/evaltest.dat6
-rwxr-xr-xtesting/tests/ocsp-revoked/hosts/carol/etc/ipsec.conf29
-rw-r--r--testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.d/certs/carolRevokedCert.pem25
-rw-r--r--testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.d/private/carolRevokedKey.pem27
-rw-r--r--testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.secrets3
-rwxr-xr-xtesting/tests/ocsp-revoked/hosts/moon/etc/ipsec.conf40
-rw-r--r--testing/tests/ocsp-revoked/posttest.dat5
-rw-r--r--testing/tests/ocsp-revoked/pretest.dat5
-rw-r--r--testing/tests/ocsp-revoked/test.conf21
-rw-r--r--testing/tests/ocsp-strict/description.txt6
-rw-r--r--testing/tests/ocsp-strict/evaltest.dat8
-rwxr-xr-xtesting/tests/ocsp-strict/hosts/carol/etc/ipsec.conf29
-rwxr-xr-xtesting/tests/ocsp-strict/hosts/moon/etc/ipsec.conf40
-rw-r--r--testing/tests/ocsp-strict/posttest.dat3
-rw-r--r--testing/tests/ocsp-strict/pretest.dat5
-rw-r--r--testing/tests/ocsp-strict/test.conf21
-rw-r--r--testing/tests/protoport-dual/description.txt6
-rw-r--r--testing/tests/protoport-dual/evaltest.dat7
-rwxr-xr-xtesting/tests/protoport-dual/hosts/carol/etc/ipsec.conf31
-rwxr-xr-xtesting/tests/protoport-dual/hosts/moon/etc/ipsec.conf31
-rw-r--r--testing/tests/protoport-dual/posttest.dat6
-rw-r--r--testing/tests/protoport-dual/pretest.dat7
-rw-r--r--testing/tests/protoport-dual/test.conf21
-rw-r--r--testing/tests/protoport-pass/description.txt13
-rw-r--r--testing/tests/protoport-pass/evaltest.dat7
-rwxr-xr-xtesting/tests/protoport-pass/hosts/carol/etc/ipsec.conf27
-rwxr-xr-xtesting/tests/protoport-pass/hosts/moon/etc/ipsec.conf27
-rw-r--r--testing/tests/protoport-pass/posttest.dat6
-rw-r--r--testing/tests/protoport-pass/pretest.dat10
-rw-r--r--testing/tests/protoport-pass/test.conf21
-rw-r--r--testing/tests/protoport-route/description.txt8
-rw-r--r--testing/tests/protoport-route/evaltest.dat8
-rwxr-xr-xtesting/tests/protoport-route/hosts/carol/etc/ipsec.conf31
-rwxr-xr-xtesting/tests/protoport-route/hosts/moon/etc/ipsec.conf31
-rw-r--r--testing/tests/protoport-route/posttest.dat6
-rw-r--r--testing/tests/protoport-route/pretest.dat6
-rw-r--r--testing/tests/protoport-route/test.conf21
-rw-r--r--testing/tests/req-pkcs10/description.txt11
-rw-r--r--testing/tests/req-pkcs10/evaltest.dat5
-rwxr-xr-xtesting/tests/req-pkcs10/hosts/carol/etc/ipsec.conf29
-rw-r--r--testing/tests/req-pkcs10/hosts/carol/etc/ipsec.secrets3
-rw-r--r--testing/tests/req-pkcs10/hosts/carol/etc/scepclient.conf3
-rw-r--r--testing/tests/req-pkcs10/hosts/moon/etc/ipsec.secrets3
-rw-r--r--testing/tests/req-pkcs10/hosts/moon/etc/scepclient.conf4
-rw-r--r--testing/tests/req-pkcs10/hosts/winnetou/etc/openssl/yy.txt2
-rw-r--r--testing/tests/req-pkcs10/posttest.dat13
-rw-r--r--testing/tests/req-pkcs10/pretest.dat22
-rw-r--r--testing/tests/req-pkcs10/test.conf21
-rw-r--r--testing/tests/rw-cert/description.txt6
-rw-r--r--testing/tests/rw-cert/evaltest.dat5
-rw-r--r--testing/tests/rw-cert/posttest.dat6
-rw-r--r--testing/tests/rw-cert/pretest.dat6
-rw-r--r--testing/tests/rw-cert/test.conf21
-rw-r--r--testing/tests/rw-psk-fqdn-named/description.txt11
-rw-r--r--testing/tests/rw-psk-fqdn-named/evaltest.dat5
-rwxr-xr-xtesting/tests/rw-psk-fqdn-named/hosts/carol/etc/ipsec.conf23
-rw-r--r--testing/tests/rw-psk-fqdn-named/hosts/carol/etc/ipsec.secrets7
-rwxr-xr-xtesting/tests/rw-psk-fqdn-named/hosts/moon/etc/ipsec.conf23
-rw-r--r--testing/tests/rw-psk-fqdn-named/hosts/moon/etc/ipsec.secrets7
-rw-r--r--testing/tests/rw-psk-fqdn-named/posttest.dat6
-rw-r--r--testing/tests/rw-psk-fqdn-named/pretest.dat8
-rw-r--r--testing/tests/rw-psk-fqdn-named/test.conf21
-rw-r--r--testing/tests/rw-psk-fqdn/description.txt5
-rw-r--r--testing/tests/rw-psk-fqdn/evaltest.dat5
-rwxr-xr-xtesting/tests/rw-psk-fqdn/hosts/carol/etc/ipsec.conf23
-rw-r--r--testing/tests/rw-psk-fqdn/hosts/carol/etc/ipsec.secrets7
-rwxr-xr-xtesting/tests/rw-psk-fqdn/hosts/moon/etc/ipsec.conf22
-rw-r--r--testing/tests/rw-psk-fqdn/hosts/moon/etc/ipsec.secrets7
-rw-r--r--testing/tests/rw-psk-fqdn/posttest.dat6
-rw-r--r--testing/tests/rw-psk-fqdn/pretest.dat8
-rw-r--r--testing/tests/rw-psk-fqdn/test.conf21
-rw-r--r--testing/tests/rw-psk-ipv4/description.txt5
-rw-r--r--testing/tests/rw-psk-ipv4/evaltest.dat5
-rwxr-xr-xtesting/tests/rw-psk-ipv4/hosts/carol/etc/ipsec.conf21
-rw-r--r--testing/tests/rw-psk-ipv4/hosts/carol/etc/ipsec.secrets7
-rwxr-xr-xtesting/tests/rw-psk-ipv4/hosts/moon/etc/ipsec.conf21
-rw-r--r--testing/tests/rw-psk-ipv4/hosts/moon/etc/ipsec.secrets7
-rw-r--r--testing/tests/rw-psk-ipv4/posttest.dat6
-rw-r--r--testing/tests/rw-psk-ipv4/pretest.dat8
-rw-r--r--testing/tests/rw-psk-ipv4/test.conf21
-rw-r--r--testing/tests/rw-psk-no-policy/description.txt3
-rw-r--r--testing/tests/rw-psk-no-policy/evaltest.dat5
-rwxr-xr-xtesting/tests/rw-psk-no-policy/hosts/carol/etc/ipsec.conf23
-rw-r--r--testing/tests/rw-psk-no-policy/hosts/carol/etc/ipsec.secrets7
-rwxr-xr-xtesting/tests/rw-psk-no-policy/hosts/moon/etc/ipsec.conf22
-rw-r--r--testing/tests/rw-psk-no-policy/posttest.dat2
-rw-r--r--testing/tests/rw-psk-no-policy/pretest.dat5
-rw-r--r--testing/tests/rw-psk-no-policy/test.conf21
-rw-r--r--testing/tests/rw-psk-rsa-mixed/description.txt5
-rw-r--r--testing/tests/rw-psk-rsa-mixed/evaltest.dat7
-rwxr-xr-xtesting/tests/rw-psk-rsa-mixed/hosts/carol/etc/ipsec.conf24
-rw-r--r--testing/tests/rw-psk-rsa-mixed/hosts/carol/etc/ipsec.secrets7
-rwxr-xr-xtesting/tests/rw-psk-rsa-mixed/hosts/moon/etc/ipsec.conf27
-rw-r--r--testing/tests/rw-psk-rsa-mixed/hosts/moon/etc/ipsec.secrets5
-rw-r--r--testing/tests/rw-psk-rsa-mixed/posttest.dat3
-rw-r--r--testing/tests/rw-psk-rsa-mixed/pretest.dat7
-rw-r--r--testing/tests/rw-psk-rsa-mixed/test.conf21
-rw-r--r--testing/tests/rw-rsa-no-policy/description.txt3
-rw-r--r--testing/tests/rw-rsa-no-policy/evaltest.dat5
-rwxr-xr-xtesting/tests/rw-rsa-no-policy/hosts/moon/etc/ipsec.conf22
-rw-r--r--testing/tests/rw-rsa-no-policy/hosts/moon/etc/ipsec.secrets3
-rw-r--r--testing/tests/rw-rsa-no-policy/posttest.dat2
-rw-r--r--testing/tests/rw-rsa-no-policy/pretest.dat5
-rw-r--r--testing/tests/rw-rsa-no-policy/test.conf21
-rw-r--r--testing/tests/self-signed/description.txt8
-rw-r--r--testing/tests/self-signed/evaltest.dat7
-rwxr-xr-xtesting/tests/self-signed/hosts/carol/etc/ipsec.conf27
-rw-r--r--testing/tests/self-signed/hosts/carol/etc/ipsec.secrets3
-rwxr-xr-xtesting/tests/self-signed/hosts/moon/etc/init.d/iptables78
-rwxr-xr-xtesting/tests/self-signed/hosts/moon/etc/ipsec.conf28
-rw-r--r--testing/tests/self-signed/hosts/moon/etc/ipsec.secrets3
-rw-r--r--testing/tests/self-signed/hosts/moon/etc/scepclient.conf6
-rw-r--r--testing/tests/self-signed/posttest.dat10
-rw-r--r--testing/tests/self-signed/pretest.dat17
-rw-r--r--testing/tests/self-signed/test.conf21
-rw-r--r--testing/tests/starter-also-loop/description.txt4
-rw-r--r--testing/tests/starter-also-loop/evaltest.dat3
-rwxr-xr-xtesting/tests/starter-also-loop/hosts/moon/etc/ipsec.conf48
-rw-r--r--testing/tests/starter-also-loop/posttest.dat0
-rw-r--r--testing/tests/starter-also-loop/pretest.dat1
-rw-r--r--testing/tests/starter-also-loop/test.conf21
-rw-r--r--testing/tests/starter-also/description.txt3
-rw-r--r--testing/tests/starter-also/evaltest.dat5
-rwxr-xr-xtesting/tests/starter-also/hosts/moon/etc/ipsec.conf47
-rw-r--r--testing/tests/starter-also/posttest.dat6
-rw-r--r--testing/tests/starter-also/pretest.dat6
-rw-r--r--testing/tests/starter-also/test.conf21
-rw-r--r--testing/tests/starter-includes/description.txt6
-rw-r--r--testing/tests/starter-includes/evaltest.dat16
-rwxr-xr-xtesting/tests/starter-includes/hosts/carol/etc/ipsec.conf30
-rwxr-xr-xtesting/tests/starter-includes/hosts/dave/etc/ipsec.conf30
-rwxr-xr-xtesting/tests/starter-includes/hosts/moon/etc/ipsec.conf10
-rw-r--r--testing/tests/starter-includes/hosts/moon/etc/ipsec.connections12
-rwxr-xr-xtesting/tests/starter-includes/hosts/moon/etc/ipsec.host11
-rw-r--r--testing/tests/starter-includes/hosts/moon/etc/ipsec.peers/ipsec.carol8
-rw-r--r--testing/tests/starter-includes/hosts/moon/etc/ipsec.peers/ipsec.dave8
-rw-r--r--testing/tests/starter-includes/posttest.dat13
-rw-r--r--testing/tests/starter-includes/pretest.dat10
-rw-r--r--testing/tests/starter-includes/test.conf21
-rw-r--r--testing/tests/virtual-ip-swapped/description.txt3
-rw-r--r--testing/tests/virtual-ip-swapped/evaltest.dat9
-rwxr-xr-xtesting/tests/virtual-ip-swapped/hosts/carol/etc/ipsec.conf30
-rwxr-xr-xtesting/tests/virtual-ip-swapped/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/virtual-ip-swapped/posttest.dat7
-rw-r--r--testing/tests/virtual-ip-swapped/pretest.dat6
-rw-r--r--testing/tests/virtual-ip-swapped/test.conf21
-rw-r--r--testing/tests/virtual-ip/description.txt8
-rw-r--r--testing/tests/virtual-ip/evaltest.dat9
-rwxr-xr-xtesting/tests/virtual-ip/hosts/carol/etc/ipsec.conf30
-rwxr-xr-xtesting/tests/virtual-ip/hosts/moon/etc/ipsec.conf26
-rw-r--r--testing/tests/virtual-ip/posttest.dat7
-rw-r--r--testing/tests/virtual-ip/pretest.dat6
-rw-r--r--testing/tests/virtual-ip/test.conf21
-rw-r--r--testing/tests/wildcards/description.txt8
-rw-r--r--testing/tests/wildcards/evaltest.dat8
-rwxr-xr-xtesting/tests/wildcards/hosts/carol/etc/ipsec.conf32
-rwxr-xr-xtesting/tests/wildcards/hosts/dave/etc/ipsec.conf32
-rwxr-xr-xtesting/tests/wildcards/hosts/moon/etc/ipsec.conf31
-rw-r--r--testing/tests/wildcards/posttest.dat3
-rw-r--r--testing/tests/wildcards/pretest.dat9
-rw-r--r--testing/tests/wildcards/test.conf21
-rw-r--r--testing/tests/wlan/description.txt15
-rw-r--r--testing/tests/wlan/evaltest.dat11
-rwxr-xr-xtesting/tests/wlan/hosts/alice/etc/init.d/iptables73
-rwxr-xr-xtesting/tests/wlan/hosts/alice/etc/ipsec.conf37
-rwxr-xr-xtesting/tests/wlan/hosts/moon/etc/init.d/iptables82
-rwxr-xr-xtesting/tests/wlan/hosts/moon/etc/ipsec.conf37
-rwxr-xr-xtesting/tests/wlan/hosts/venus/etc/init.d/iptables73
-rwxr-xr-xtesting/tests/wlan/hosts/venus/etc/ipsec.conf37
-rw-r--r--testing/tests/wlan/posttest.dat10
-rw-r--r--testing/tests/wlan/pretest.dat11
-rw-r--r--testing/tests/wlan/test.conf21
2043 files changed, 346842 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 000000000..e87a5da33
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,691 @@
+strongswan-2.7.0
+----------------
+
+- the dynamic iptables rules from the _updown_x509 template
+ for KLIPS and the _updown_policy template for NETKEY have
+ been merged into the default _updown script. The existing
+ left|rightfirewall keyword causes the automatic insertion
+ and deletion of ACCEPT rules for tunneled traffic upon
+ the successful setup and teardown of an IPsec SA, respectively.
+ left|rightfirwall can be used with KLIPS under any Linux 2.4
+ kernel or with NETKEY under a Linux kernel version >= 2.6.16
+ in conjuction with iptables >= 1.3.5. For NETKEY under a Linux
+ kernel version < 2.6.16 which does not support IPsec policy
+ matching yet, please continue to use a copy of the _updown_espmark
+ template loaded via the left|rightupdown keyword.
+
+- a new left|righthostaccess keyword has been introduced which
+ can be used in conjunction with left|rightfirewall and the
+ default _updown script. By default leftfirewall=yes inserts
+ a bi-directional iptables FORWARD rule for a local client network
+ with a netmask different from 255.255.255.255 (single host).
+ This does not allow to access the VPN gateway host via its
+ internal network interface which is part of the client subnet
+ because an iptables INPUT and OUTPUT rule would be required.
+ lefthostaccess=yes will cause this additional ACCEPT rules to
+ be inserted.
+
+- mixed PSK|RSA roadwarriors are now supported. The ISAKMP proposal
+ payload is preparsed in order to find out whether the roadwarrior
+ requests PSK or RSA so that a matching connection candidate can
+ be found.
+
+
+strongswan-2.6.4
+----------------
+
+- the new _updown_policy template allows ipsec policy based
+ iptables firewall rules. Required are iptables version
+ >= 1.3.5 and linux kernel >= 2.6.16. This script obsoletes
+ the _updown_espmark template, so that no INPUT mangle rules
+ are required any more.
+
+- added support of DPD restart mode
+
+- ipsec starter now allows the use of wildcards in include
+ statements as e.g. in "include /etc/my_ipsec/*.conf".
+ Patch courtesy of Matthias Haas.
+
+- the Netscape OID 'employeeNumber' is now recognized and can be
+ used as a Relative Distinguished Name in certificates.
+
+
+strongswan-2.6.3
+----------------
+
+- /etc/init.d/ipsec or /etc/rc.d/ipsec is now a copy of the ipsec
+ command and not of ipsec setup any more.
+
+- ipsec starter now supports AH authentication in conjunction with
+ ESP encryption. AH authentication is configured in ipsec.conf
+ via the auth=ah parameter.
+
+- The command ipsec scencrypt|scdecrypt <args> is now an alias for
+ ipsec whack --scencrypt|scdecrypt <args>.
+
+- get_sa_info() now determines for the native netkey IPsec stack
+ the exact time of the last use of an active eroute. This information
+ is used by the Dead Peer Detection algorithm and is also displayed by
+ the ipsec status command.
+
+
+strongswan-2.6.2
+----------------
+
+- running under the native Linux 2.6 IPsec stack, the function
+ get_sa_info() is called by ipsec auto --status to display the current
+ number of transmitted bytes per IPsec SA.
+
+- get_sa_info() is also used by the Dead Peer Detection process to detect
+ recent ESP activity. If ESP traffic was received from the peer within
+ the last dpd_delay interval then no R_Y_THERE notification must be sent.
+
+- strongSwan now supports the Relative Distinguished Name "unstructuredName"
+ in ID_DER_ASN1_DN identities. The following notations are possible:
+
+ rightid="unstructuredName=John Doe"
+ rightid="UN=John Doe"
+
+- fixed a long-standing bug which caused PSK-based roadwarrior connections
+ to segfault in the function id.c:same_id() called by keys.c:get_secret()
+ if an FQDN, USER_FQDN, or Key ID was defined, as in the following example.
+
+ conn rw
+ right=%any
+ rightid=@foo.bar
+ authby=secret
+
+- the ipsec command now supports most ipsec auto commands (e.g. ipsec listall).
+
+- ipsec starter didn't set host_addr and client.addr ports in whack msg.
+
+- in order to guarantee backwards-compatibility with the script-based
+ auto function (e.g. auto --replace), the ipsec starter scripts stores
+ the defaultroute information in the temporary file /var/run/ipsec.info.
+
+- The compile-time option USE_XAUTH_VID enables the sending of the XAUTH
+ Vendor ID which is expected by Cisco PIX 7 boxes that act as IKE Mode Config
+ servers.
+
+- the ipsec starter now also recognizes the parameters authby=never and
+ type=passthrough|pass|drop|reject.
+
+
+strongswan-2.6.1
+----------------
+
+- ipsec starter now supports the also parameter which allows
+ a modular structure of the connection definitions. Thus
+ "ipsec start" is now ready to replace "ipsec setup".
+
+
+strongswan-2.6.0
+----------------
+
+- Mathieu Lafon's popular ipsec starter tool has been added to the
+ strongSwan distribution. Many thanks go to Stephan Scholz from astaro
+ for his integration work. ipsec starter is a C program which is going
+ to replace the various shell and awk starter scripts (setup, _plutoload,
+ _plutostart, _realsetup, _startklips, _confread, and auto). Since
+ ipsec.conf is now parsed only once, the starting of multiple tunnels is
+ accelerated tremedously.
+
+- Added support of %defaultroute to the ipsec starter. If the IP address
+ changes, a HUP signal to the ipsec starter will automatically
+ reload pluto's connections.
+
+- moved most compile time configurations from pluto/Makefile to
+ Makefile.inc by defining the options USE_LIBCURL, USE_LDAP,
+ USE_SMARTCARD, and USE_NAT_TRAVERSAL_TRANSPORT_MODE.
+
+- removed the ipsec verify and ipsec newhostkey commands
+
+- fixed some 64-bit issues in formatted print statements
+
+- The scepclient functionality implementing the Simple Certificate
+ Enrollment Protocol (SCEP) is nearly complete but hasn't been
+ documented yet.
+
+
+strongswan-2.5.7
+----------------
+
+- CA certicates are now automatically loaded from a smartcard
+ or USB crypto token and appear in the ipsec auto --listcacerts
+ listing.
+
+
+strongswan-2.5.6
+----------------
+
+- when using "ipsec whack --scencrypt <data>" with a PKCS#11
+ library that does not support the C_Encrypt() Cryptoki
+ function (e.g. OpenSC), the RSA encryption is done in
+ software using the public key fetched from the smartcard.
+
+- The scepclient function now allows to define the
+ validity of a self-signed certificate using the --days,
+ --startdate, and --enddate options. The default validity
+ has been changed from one year to five years.
+
+
+strongswan-2.5.5
+----------------
+
+- the config setup parameter pkcs11proxy=yes opens pluto's PKCS#11
+ interface to other applications for RSA encryption and decryption
+ via the whack interface. Notation:
+
+ ipsec whack --scencrypt <data>
+ [--inbase 16|hex|64|base64|256|text|ascii]
+ [--outbase 16|hex|64|base64|256|text|ascii]
+ [--keyid <keyid>]
+
+ ipsec whack --scdecrypt <data>
+ [--inbase 16|hex|64|base64|256|text|ascii]
+ [--outbase 16|hex|64|base64|256|text|ascii]
+ [--keyid <keyid>]
+
+ The default setting for inbase and outbase is hex.
+
+ The new proxy interface can be used for securing symmetric
+ encryption keys required by the cryptoloop or dm-crypt
+ disk encryption schemes, especially in the case when
+ pkcs11keepstate=yes causes pluto to lock the pkcs11 slot
+ permanently.
+
+- if the file /etc/ipsec.secrets is lacking during the startup of
+ pluto then the root-readable file /etc/ipsec.d/private/myKey.der
+ containing a 2048 bit RSA private key and a matching self-signed
+ certificate stored in the file /etc/ipsec.d/certs/selfCert.der
+ is automatically generated by calling the function
+
+ ipsec scepclient --out pkcs1 --out cert-self
+
+ scepclient was written by Jan Hutter and Martin Willi, students
+ at the University of Applied Sciences in Rapperswil, Switzerland.
+
+
+strongswan-2.5.4
+----------------
+
+- the current extension of the PKCS#7 framework introduced
+ a parsing error in PKCS#7 wrapped X.509 certificates that are
+ e.g. transmitted by Windows XP when multi-level CAs are used.
+ the parsing syntax has been fixed.
+
+- added a patch by Gerald Richter which tolerates multiple occurrences
+ of the ipsec0 interface when using KLIPS.
+
+
+strongswan-2.5.3
+----------------
+
+- with gawk-3.1.4 the word "default2 has become a protected
+ keyword for use in switch statements and cannot be used any
+ more in the strongSwan scripts. This problem has been
+ solved by renaming "default" to "defaults" and "setdefault"
+ in the scripts _confread and auto, respectively.
+
+- introduced the parameter leftsendcert with the values
+
+ always|yes (the default, always send a cert)
+ ifasked (send the cert only upon a cert request)
+ never|no (never send a cert, used for raw RSA keys and
+ self-signed certs)
+
+- fixed the initialization of the ESP key length to a default of
+ 128 bits in the case that the peer does not send a key length
+ attribute for AES encryption.
+
+- applied Herbert Xu's uniqueIDs patch
+
+- applied Herbert Xu's CLOEXEC patches
+
+
+strongswan-2.5.2
+----------------
+
+- CRLs can now be cached also in the case when the issuer's
+ certificate does not contain a subjectKeyIdentifier field.
+ In that case the subjectKeyIdentifier is computed by pluto as the
+ 160 bit SHA-1 hash of the issuer's public key in compliance
+ with section 4.2.1.2 of RFC 3280.
+
+- Fixed a bug introduced by strongswan-2.5.1 which eliminated
+ not only multiple Quick Modes of a given connection but also
+ multiple connections between two security gateways.
+
+
+strongswan-2.5.1
+----------------
+
+- Under the native IPsec of the Linux 2.6 kernel, a %trap eroute
+ installed either by setting auto=route in ipsec.conf or by
+ a connection put into hold, generates an XFRM_AQUIRE event
+ for each packet that wants to use the not-yet exisiting
+ tunnel. Up to now each XFRM_AQUIRE event led to an entry in
+ the Quick Mode queue, causing multiple IPsec SA to be
+ established in rapid succession. Starting with strongswan-2.5.1
+ only a single IPsec SA is established per host-pair connection.
+
+- Right after loading the PKCS#11 module, all smartcard slots are
+ searched for certificates. The result can be viewed using
+ the command
+
+ ipsec auto --listcards
+
+ The certificate objects found in the slots are numbered
+ starting with #1, #2, etc. This position number can be used to address
+ certificates (leftcert=%smartcard) and keys (: PIN %smartcard)
+ in ipsec.conf and ipsec.secrets, respectively:
+
+ %smartcard (selects object #1)
+ %smartcard#1 (selects object #1)
+ %smartcard#3 (selects object #3)
+
+ As an alternative the existing retrieval scheme can be used:
+
+ %smartcard:45 (selects object with id=45)
+ %smartcard0 (selects first object in slot 0)
+ %smartcard4:45 (selects object in slot 4 with id=45)
+
+- Depending on the settings of CKA_SIGN and CKA_DECRYPT
+ private key flags either C_Sign() or C_Decrypt() is used
+ to generate a signature.
+
+- The output buffer length parameter siglen in C_Sign()
+ is now initialized to the actual size of the output
+ buffer prior to the function call. This fixes the
+ CKR_BUFFER_TOO_SMALL error that could occur when using
+ the OpenSC PKCS#11 module.
+
+- Changed the initialization of the PKCS#11 CK_MECHANISM in
+ C_SignInit() to mech = { CKM_RSA_PKCS, NULL_PTR, 0 }.
+
+- Refactored the RSA public/private key code and transferred it
+ from keys.c to the new pkcs1.c file as a preparatory step
+ towards the release of the SCEP client.
+
+
+strongswan-2.5.0
+----------------
+
+- The loading of a PKCS#11 smartcard library module during
+ runtime does not require OpenSC library functions any more
+ because the corresponding code has been integrated into
+ smartcard.c. Also the RSAREF pkcs11 header files have been
+ included in a newly created pluto/rsaref directory so that
+ no external include path has to be defined any longer.
+
+- A long-awaited feature has been implemented at last:
+ The local caching of CRLs fetched via HTTP or LDAP, activated
+ by the parameter cachecrls=yes in the config setup section
+ of ipsec.conf. The dynamically fetched CRLs are stored under
+ a unique file name containing the issuer's subjectKeyID
+ in /etc/ipsec.d/crls.
+
+- Applied a one-line patch courtesy of Michael Richardson
+ from the Openswan project which fixes the kernel-oops
+ in KLIPS when an snmp daemon is running on the same box.
+
+
+strongswan-2.4.4
+----------------
+
+- Eliminated null length CRL distribution point strings.
+
+- Fixed a trust path evaluation bug introduced with 2.4.3
+
+
+strongswan-2.4.3
+----------------
+
+- Improved the joint OCSP / CRL revocation policy.
+ OCSP responses have precedence over CRL entries.
+
+- Introduced support of CRLv2 reason codes.
+
+- Fixed a bug with key-pad equipped readers which caused
+ pluto to prompt for the pin via the console when the first
+ occasion to enter the pin via the key-pad was missed.
+
+- When pluto is built with LDAP_V3 enabled, the library
+ liblber required by newer versions of openldap is now
+ included.
+
+
+strongswan-2.4.2
+----------------
+
+- Added the _updown_espmark template which requires all
+ incoming ESP traffic to be marked with a default mark
+ value of 50.
+
+- Introduced the pkcs11keepstate parameter in the config setup
+ section of ipsec.conf. With pkcs11keepstate=yes the PKCS#11
+ session and login states are kept as long as possible during
+ the lifetime of pluto. This means that a PIN entry via a key
+ pad has to be done only once.
+
+- Introduced the pkcs11module parameter in the config setup
+ section of ipsec.conf which specifies the PKCS#11 module
+ to be used with smart cards. Example:
+
+ pkcs11module=/usr/lib/pkcs11/opensc-pkcs11.lo
+
+- Added support of smartcard readers equipped with a PIN pad.
+
+- Added patch by Jay Pfeifer which detects when netkey
+ modules have been statically built into the Linux 2.6 kernel.
+
+- Added two patches by Herbert Xu. The first uses ip xfrm
+ instead of setkey to flush the IPsec policy database. The
+ second sets the optional flag in inbound IPComp SAs only.
+
+- Applied Ulrich Weber's patch which fixes an interoperability
+ problem between native IPsec and KLIPS systems caused by
+ setting the replay window to 32 instead of 0 for ipcomp.
+
+
+strongswan-2.4.1
+----------------
+
+- Fixed a bug which caused an unwanted Mode Config request
+ to be initiated in the case where "right" was used to denote
+ the local side in ipsec.conf and "left" the remote side,
+ contrary to the recommendation that "right" be remote and
+ "left" be"local".
+
+
+strongswan-2.4.0a
+-----------------
+
+- updated Vendor ID to strongSwan-2.4.0
+
+- updated copyright statement to include David Buechi and
+ Michael Meier
+
+
+strongswan-2.4.0
+----------------
+
+- strongSwan now communicates with attached smartcards and
+ USB crypto tokens via the standardized PKCS #11 interface.
+ By default the OpenSC library from www.opensc.org is used
+ but any other PKCS#11 library could be dynamically linked.
+ strongSwan's PKCS#11 API was implemented by David Buechi
+ and Michael Meier, both graduates of the Zurich University
+ of Applied Sciences in Winterthur, Switzerland.
+
+- When a %trap eroute is triggered by an outgoing IP packet
+ then the native IPsec stack of the Linux 2.6 kernel [often/
+ always?] returns an XFRM_ACQUIRE message with an undefined
+ protocol family field and the connection setup fails.
+ As a workaround IPv4 (AF_INET) is now assumed.
+
+- the results of the UML test scenarios are now enhanced
+ with block diagrams of the virtual network topology used
+ in a particular test.
+
+
+strongswan-2.3.2
+----------------
+
+- fixed IV used to decrypt informational messages.
+ This bug was introduced with Mode Config functionality.
+
+- fixed NCP Vendor ID.
+
+- undid one of Ulrich Weber's maximum udp size patches
+ because it caused a segmentation fault with NAT-ed
+ Delete SA messages.
+
+- added UML scenarios wildcards and attr-cert which
+ demonstrate the implementation of IPsec policies based
+ on wildcard parameters contained in Distinguished Names and
+ on X.509 attribute certificates, respectively.
+
+
+strongswan-2.3.1
+----------------
+
+- Added basic Mode Config functionality
+
+- Added Mathieu Lafon's patch which upgrades the status of
+ the NAT-Traversal implementation to RFC 3947.
+
+- The _startklips script now also loads the xfrm4_tunnel
+ module.
+
+- Added Ulrich Weber's netlink replay window size and
+ maximum udp size patches.
+
+- UML testing now uses the Linux 2.6.10 UML kernel by default.
+
+
+strongswan-2.3.0
+----------------
+
+- Eric Marchionni and Patrik Rayo, both recent graduates from
+ the Zuercher Hochschule Winterthur in Switzerland, created a
+ User-Mode-Linux test setup for strongSwan. For more details
+ please read the INSTALL and README documents in the testing
+ subdirectory.
+
+- Full support of group attributes based on X.509 attribute
+ certificates. Attribute certificates can be generated
+ using the openac facility. For more details see
+
+ man ipsec_openac.
+
+ The group attributes can be used in connection definitions
+ in order to give IPsec access to specific user groups.
+ This is done with the new parameter left|rightgroups as in
+
+ rightgroups="Research, Sales"
+
+ giving access to users possessing the group attributes
+ Research or Sales, only.
+
+- In Quick Mode clients with subnet mask /32 are now
+ coded as IP_V4_ADDRESS or IP_V6_ADDRESS. This should
+ fix rekeying problems with the SafeNet/SoftRemote and NCP
+ Secure Entry Clients.
+
+- Changed the defaults of the ikelifetime and keylife parameters
+ to 3h and 1h, respectively. The maximum allowable values are
+ now both set to 24 h.
+
+- Suppressed notification wars between two IPsec peers that
+ could e.g. be triggered by incorrect ISAKMP encryption.
+
+- Public RSA keys can now have identical IDs if either the
+ issuing CA or the serial number is different. The serial
+ number of a certificate is now shown by the command
+
+ ipsec auto --listpubkeys
+
+
+strongswan-2.2.2
+----------------
+
+- Added Tuomo Soini's sourceip feature which allows a strongSwan
+ roadwarrior to use a fixed Virtual IP (see README section 2.6)
+ and reduces the well-known four tunnel case on VPN gateways to
+ a single tunnel definition (see README section 2.4).
+
+- Fixed a bug occuring with NAT-Traversal enabled when the responder
+ suddenly turns initiator and the initiator cannot find a matching
+ connection because of the floated IKE port 4500.
+
+- Removed misleading ipsec verify command from barf.
+
+- Running under the native IP stack, ipsec --version now shows
+ the Linux kernel version (courtesy to the Openswan project).
+
+
+strongswan-2.2.1
+----------------
+
+- Introduced the ipsec auto --listalgs monitoring command which lists
+ all currently registered IKE and ESP algorithms.
+
+- Fixed a bug in the ESP algorithm selection occuring when the strict flag
+ is set and the first proposed transform does not match.
+
+- Fixed another deadlock in the use of the lock_certs_and_keys() mutex,
+ occuring when a smartcard is present.
+
+- Prevented that a superseded Phase1 state can trigger a DPD_TIMEOUT event.
+
+- Fixed the printing of the notification names (null)
+
+- Applied another of Herbert Xu's Netlink patches.
+
+
+strongswan-2.2.0
+----------------
+
+- Support of Dead Peer Detection. The connection parameter
+
+ dpdaction=clear|hold
+
+ activates DPD for the given connection.
+
+- The default Opportunistic Encryption (OE) policy groups are not
+ automatically included anymore. Those wishing to activate OE can include
+ the policy group with the following statement in ipsec.conf:
+
+ include /etc/ipsec.d/examples/oe.conf
+
+ The default for [right|left]rsasigkey is now set to %cert.
+
+- strongSwan now has a Vendor ID of its own which can be activated
+ using the compile option VENDORID
+
+- Applied Herbert Xu's patch which sets the compression algorithm correctly.
+
+- Applied Herbert Xu's patch fixing an ESPINUDP problem
+
+- Applied Herbert Xu's patch setting source/destination port numbers.
+
+- Reapplied one of Herbert Xu's NAT-Traversal patches which got
+ lost during the migration from SuperFreeS/WAN.
+
+- Fixed a deadlock in the use of the lock_certs_and_keys() mutex.
+
+- Fixed the unsharing of alg parameters when instantiating group
+ connection.
+
+
+strongswan-2.1.5
+----------------
+
+- Thomas Walpuski made me aware of a potential DoS attack via
+ a PKCS#7-wrapped certificate bundle which could overwrite valid CA
+ certificates in Pluto's authority certificate store. This vulnerability
+ was fixed by establishing trust in CA candidate certificates up to a
+ trusted root CA prior to insertion into Pluto's chained list.
+
+- replaced the --assign option by the -v option in the auto awk script
+ in order to make it run with mawk under debian/woody.
+
+
+strongswan-2.1.4
+----------------
+
+- Split of the status information between ipsec auto --status (concise)
+ and ipsec auto --statusall (verbose). Both commands can be used with
+ an optional connection selector:
+
+ ipsec auto --status[all] <connection_name>
+
+- Added the description of X.509 related features to the ipsec_auto(8)
+ man page.
+
+- Hardened the ASN.1 parser in debug mode, especially the printing
+ of malformed distinguished names.
+
+- The size of an RSA public key received in a certificate is now restricted to
+
+ 512 bits <= modulus length <= 8192 bits.
+
+- Fixed the debug mode enumeration.
+
+
+strongswan-2.1.3
+----------------
+
+- Fixed another PKCS#7 vulnerability which could lead to an
+ endless loop while following the X.509 trust chain.
+
+
+strongswan-2.1.2
+----------------
+
+- Fixed the PKCS#7 vulnerability discovered by Thomas Walpuski
+ that accepted end certificates having identical issuer and subject
+ distinguished names in a multi-tier X.509 trust chain.
+
+
+strongswan-2.1.1
+----------------
+
+- Removed all remaining references to ipsec_netlink.h in KLIPS.
+
+
+strongswan-2.1.0
+----------------
+
+- The new "ca" section allows to define the following parameters:
+
+ ca kool
+ cacert=koolCA.pem # cacert of kool CA
+ ocspuri=http://ocsp.kool.net:8001 # ocsp server
+ ldapserver=ldap.kool.net # default ldap server
+ crluri=http://www.kool.net/kool.crl # crl distribution point
+ crluri2="ldap:///O=Kool, C= .." # crl distribution point #2
+ auto=add # add, ignore
+
+ The ca definitions can be monitored via the command
+
+ ipsec auto --listcainfos
+
+- Fixed cosmetic corruption of /proc filesystem by integrating
+ D. Hugh Redelmeier's freeswan-2.06 kernel fixes.
+
+
+strongswan-2.0.2
+----------------
+
+- Added support for the 818043 NAT-Traversal update of Microsoft's
+ Windows 2000/XP IPsec client which sends an ID_FQDN during Quick Mode.
+
+- A symbolic link to libcrypto is now added in the kernel sources
+ during kernel compilation
+
+- Fixed a couple of 64 bit issues (mostly casts to int).
+ Thanks to Ken Bantoft who checked my sources on a 64 bit platform.
+
+- Replaced s[n]printf() statements in the kernel by ipsec_snprintf().
+ Credits go to D. Hugh Redelmeier, Michael Richardson, and Sam Sgro
+ of the FreeS/WAN team who solved this problem with the 2.4.25 kernel.
+
+
+strongswan-2.0.1
+----------------
+
+- an empty ASN.1 SEQUENCE OF or SET OF object (e.g. a subjectAltName
+ certificate extension which contains no generalName item) can cause
+ a pluto crash. This bug has been fixed. Additionally the ASN.1 parser has
+ been hardened to make it more robust against malformed ASN.1 objects.
+
+- applied Herbert Xu's NAT-T patches which fixes NAT-T under the native
+ Linux 2.6 IPsec stack.
+
+
+strongswan-2.0.0
+----------------
+
+- based on freeswan-2.04, x509-1.5.3, nat-0.6c, alg-0.8.1rc12
diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000..60549be51
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 000000000..a0c8eb2fa
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,110 @@
+We haven't kept proper track of everybody who has helped us, alas, but
+here's a first attempt at acknowledgements...
+
+Most of the FreeS/WAN software has been done by Richard Guy Briggs
+(KLIPS), D. Hugh Redelmeier (Pluto), Michael Richardson (technical lead,
+KLIPS, testing, etc.), Henry Spencer (past technical lead, scripts,
+libraries, packaging, etc.), Sandy Harris (documentation), Claudia
+Schmeing (support, documentation), and Sam Sgro (support, releases).
+Peter Onion has collaborated extensively with RGB on PFKEY2 stuff. The
+original version of our IPComp code came from Svenning Soerensen, who has
+also contributed various bug fixes and improvements.
+
+The first versions of KLIPS were done by John Ioannidis <ji@hol.gr>. The
+first versions of Pluto (and further work on KLIPS) were done by Angelos
+D. Keromytis <angelos@dsl.cis.upenn.edu>.
+
+The MD2 implementation is from RSA Data Security Inc., so this package must
+include the following phrase: "RSA Data Security, Inc. MD2 Message Digest
+Algorithm" It is not under the GPL; see details in programs/pluto/md2.c.
+
+The MD5 implementation is from RSA Data Security Inc., so this package must
+include the following phrase: "derived from the RSA Data Security, Inc.
+MD5 Message-Digest Algorithm". It is not under the GPL; see details in
+linux/net/ipsec/ipsec_md5c.c.
+
+The PKCS#11 header files in programs/pluto/rsaref/ are from RSA Security Inc.,
+so they must include the following phrase: "RSA Security Inc. PKCS#11
+Cryptographic Token Interface (Cryptoki)". The headers are not under the GPL;
+see details in programs/pluto/rsaref/pkcs11.h.
+
+The LIBDES library by Eric Young is used. It is not under the GPL -- see
+details in libdes/COPYRIGHT -- although he has graciously waived the
+advertising clause for FreeS/WAN use of LIBDES.
+
+The SHA-1 code is derived from Steve Reid's; it is public domain.
+
+Some bits of Linux code, notably drivers/net/new_tunnel.c and net/ipv4/ipip.c,
+are used in heavily modified forms.
+
+The radix-tree code from 4.4BSD is used in a modified form. It is not
+under the GPL; see details in klips/net/ipsec/radij.c.
+
+The lib/pfkeyv2.h header file contains public-domain material published in
+RFC 2367.
+
+Delete SA code and Notification messages were contributed by Mathieu Lafon.
+He also implemented the vital NAT traversal support.
+
+Peter Onion has been immensely helpful in finding portability bugs in
+general, and in making FreeS/WAN work on the Alpha in particular. Rob
+Hatfield likewise found and fixed some problems making it work on the
+Netwinder.
+
+John S. Denker of AT&T Shannon Labs has found a number of bugs the hard
+way, has pointed out various problems (some of which we have fixed!) in
+using the software in production applications, and has suggested some
+substantial improvements to the documentation.
+
+Marc Boucher <marc@mbsi.ca> did a quick-and-dirty port of KLIPS to the
+Linux 2.2.x kernels, at a time when we needed it badly, and has helped
+chase down 2.2.xx bugs and keep us current with 2.4.x development.
+
+John Gilmore organized the FreeS/WAN project and continues to direct it.
+Hugh Daniel handles day-to-day management, customer interface, and both
+constructive and destructive testing. See the project's web page
+<http://www.freeswan.org> for other contributors to this project and
+related ones.
+
+Herbert Xu ported the FreeS/WAN code to the native IPsec stack
+of the Linux 2.6 kernel.
+
+Kai Martius added initial support of OpenPGP certificates.
+
+Andreas Steffen introduced the support of X.509 certificates in 2000
+and has been both maintaining the X.509 code and adding extensions
+to it ever since.
+
+Andreas Hess, Patric Lichtsteiner, and Roger Wegmann implemented the
+the initial X.509 certificate support, relying on Kai Martius's work.
+
+Marco Bertossa and Andreas Schleiss implemented the verification of
+the X.509 chain from the peer certificate up to the root CA.
+
+Ueli Galizzi and Ariane Seiler did the original work on the support
+of attribute certificates.
+
+Martin Berner and Lukas Suter implemented the definition of group
+attributes and dynamic fetching of attribute certificates.
+
+Christoph Gysin and Simon Zwahlen implemented PKCS#15-based
+smartcard suppport and contributed a fully operational OCSP client.
+
+David Buechi and Michael Meier implemented the PKCS#11 smartcard
+interface.
+
+The support of port and protocol selectors was based on Stephen J.
+Bevan's original work.
+
+Stephane Laroche donated the original LDAP and HTTP fetching code
+based on pthreads.
+
+JuanJo Ciarlante introduced the modular support of alternative
+encryption and authentication algorithms (AES, Serpent, twofish, etc).
+
+The ipsec starter is based on Mathieu Lafon's original work.
+
+Jan Hutter and Martin Willi developed the scepclient which fully
+supports Cisco's Simple Certificate Enrollment Protocol (SCEP).
+
+This file is RCSID $Id: CREDITS,v 1.6 2006/01/22 21:28:27 as Exp $
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 000000000..0ed541936
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,249 @@
+ ---------------------------
+ strongSwan - Installation
+ ---------------------------
+
+
+Contents
+--------
+
+ 1. Required packages
+ 2. Optional packages
+ 2.1 libcurl
+ 2.2 OpenLDAP
+ 2.3 PKCS#11 smartcard library modules
+ 3. Building strongSwan with a Linux 2.4 kernel
+ 4. Updating strongSwan with a Linux 2.4 kernel
+ 5. Building strongSwan with a Linux 2.6 kernel
+
+
+1. Required packages
+ -----------------
+
+ In order to be able to build strongSwan you'll need the GNU Multiprecision
+ Arithmetic Library (GMP) available from http://www.swox.com/gmp/.
+
+ The libgmp library and the corresponding header file gmp.h are usually
+ included in the form of one or two packages in the major Linux
+ distributions (SuSE: gmp; Debian unstable: libgmp3, libgmp3-dev).
+
+
+2. Optional packages
+ -----------------
+
+2.1 libcurl
+ -------
+
+ If you intend to dynamically fetch Certificate Revocation Lists (CRLs)
+ from an HTTP server or as an alternative want to use the Online
+ Certificate Status Protocol (OCSP) then you will need the libcurl library
+ available from http://curl.haxx.se/.
+
+ In order to keep the library as compact as possible for use with strongSwan
+ you can build libcurl from the sources with the optimized options
+
+ ./configure --prefix=<dir> --without-ssl \
+ --disable-ldap --disable-telnet \
+ --disable-dict --disable-gopher \
+ --disable-debug \
+ --enable-nonblocking --enable-thread
+
+ As an alternative you can use the ready-made packages included with your
+ favorite Linux distribution (SuSE: curl, curl-devel).
+
+ In order to activate the use of the libcurl library in strongSwan you must
+ set the USE_LIBCURL option in "Makefile.inc":
+
+ # include libcurl support (CRL fetching, OCSP and SCEP)
+ USE_LIBCURL?=true
+
+ Under Gentoo emerge strongSwan with
+
+ USE="curl -ssl" emerge strongswan
+
+
+2.2 OpenLDAP
+ --------
+
+ If you intend to dynamically fetch Certificate Revocation Lists (CRLs)
+ from an LDAP server then you will need the libldap library available
+ from http://www.openldap.org/.
+
+ OpenLDAP is usually included with your Linux distribution. You will need
+ both the run-time and development environments (SuSE: openldap2,
+ openldap2-devel).
+
+ In order to activate the use of the libldap library in strongSwan you must
+ set the USE_LDAP option in "Makefile.inc":
+
+ # include LDAP support (CRL fetching)
+ USE_LDAP?=true
+
+ Depending upon whether your LDAP server understands the V3 (preferred) or
+ V2 LDAP protocol, uncomment one ot the two following lines:
+
+ # Uncomment to enable dynamic CRL fetching using LDAP V3
+ LDAP_VERSION=3
+ # Uncomment to enable dynamic CRL fetching using LDAP V2
+ #LDAP_VERSION=2
+
+ The latest OpenLDAP releases use the LDAP V3 protocol, whereas older
+ versions require LDAP V2.
+
+ Under Gentoo emerge strongSwan with
+
+ USE="ldap -ssl" emerge strongswan
+
+
+2.3 PKCS#11 smartcard library modules
+ ---------------------------------
+
+ If you want to securely store your X.509 certificates and private RSA keys
+ on a smart card or a USB crypto token then you will need a PKCS #11 library
+ for the smart card of your choice. The OpenSC PKCS#11 library (use
+ versions >= 0.9.4) available from http://www.opensc.org/ supports quite a
+ selection of cards and tokens (e.g. Aladdin eToken Pro32k, Schlumberger
+ Cryptoflex e-gate, Oberthur AuthentIC, etc.) but requires that a PKCS#15
+ directory structure be present on the smart card. But in principle
+ any other PKCS#11 library could be used since the PKCS#11 API hides the
+ internal data representation on the card.
+
+ For USB crypto token support you must add the OpenCT driver library
+ (version >= 0.6.2) from the OpenSC site, whereas for serial smartcard
+ readers you'll need the pcsc-lite library and the matching driver from the
+ M.U.S.C.L.E project http://www.linuxnet.com/ .
+
+ In order to activate the PKCS#11-based smartcard support in strongSwan
+ you must set the USE_SMARTCARD option in "Makefile.inc":
+
+ #include PKCS11-based smartcard support
+ USE_SMARTCARD?=true
+
+ During compilation no externel smart card libraries must be present.
+ strongSwan directly references a copy of the standard RSAREF pkcs11.h
+ header files stored in the pluto/rsaref sub directory. During compile
+ time a pathname to a default PKCS#11 dynamical library can be specified
+ in "Makefile.inc"
+
+ # Uncomment this line if using OpenSC <= 0.9.6
+ PKCS11_DEFAULT_LIB=\"/usr/lib/pkcs11/opensc-pkcs11.so\"
+ # Uncomment tis line if using OpenSC >= 0.10.0
+ #PKCS11_DEFAULT_LIB=\"usr/lib/opensc-pkcs11.so\"
+
+ This default path to the easily-obtainable OpenSC library module can be
+ simply overridden during run-time by specifying an alternative path in
+ ipsec.conf pointing to any dynamic PKCS#11 library of your choice.
+
+ config setup
+ pkcs11module="/usr/lib/xyz-pkcs11.so"
+
+ Under Gentoo emerge strongSwan with
+
+ USE="smartcard usb -pam -X" emerge strongswan
+
+
+3. Building strongSwan with a Linux 2.4 kernel
+ -------------------------------------------
+
+ * Building strongSwan with a Linux 2.4 kernel requires the presence of the
+ matching kernel sources referenced via the symbolic link /usr/src/linux.
+ The use of the vanilla kernel sources from ftp.kernel.org is strongly
+ recommended.
+
+ Before building strongSwan you must have compiled the kernel sources at
+ least once:
+
+ make menuconfig; make dep; make bzImage; make modules
+
+ * Now change into the strongswan-2.x.x source directory.
+
+ First uncomment any desired compile options in "programs/pluto/Makefile"
+ (see section 2. Optional packages).
+
+ Then in the top source directory type
+
+ make menumod
+
+ This command applies an ESP_IN_UDP encapsulation patch which is required
+ for NAT-Traversal to the kernel sources.
+
+ In the "Networking options" menu set
+
+ <M> IP Security Protocol (strongSwan IPsec)
+
+ in order to build KLIPS as a loadable kernel module "ipsec.o". Do not
+ forget to save the modified configuration file when leaving "menumod".
+
+ The strongSwan userland programs are now automatically built and
+ installed, whereas the ipsec.o kernel module and the crypto modules
+ are only built and must be installed with the command
+
+ make minstall
+
+ * If you intend to use the NAT-Traversal feature then you must compile the
+ patched kernel sources again by executing
+
+ make bzImage
+
+ and then install and boot the modified kernel.
+
+ * Next add your connections to "/etc/ipsec.conf" and start strongSwan with
+
+ ipsec setup start
+
+
+4. Updating strongSwan with a Linux 2.4 kernel
+ -------------------------------------------
+
+ * If you have already successfully installed strongSwan and want to update
+ to a newer version then the following shortcut can be taken:
+
+ First uncomment any desired compile options in "programs/pluto/Makefile"
+ (see section 2. Optional packages).
+
+ Then in the strongwan-2.x.x top directory type
+
+ make programs; make install
+
+ followed by
+
+ make module; make minstall
+
+ * You can then start the updated strongSwan version with
+
+ ipsec setup restart
+
+
+5. Building strongSwan with a Linux 2.6 kernel
+ -------------------------------------------
+
+ * Because the Linux 2.6 kernel comes with a built-in native IPsec stack,
+ you won't need to build the strongSwan kernel modules. Please make sure
+ that the the following Linux 2.6 IPsec kernel modules are available:
+
+ o af_key
+ o ah4
+ o esp4
+ o ipcomp
+ o xfrm_user
+
+ Also the built-in kernel Cryptoapi modules with selected encryption and
+ hash algorithms should be available.
+
+ * First uncomment any desired compile options in "programs/pluto/Makefile"
+ (see section 2. Optional packages).
+
+ Then in the strongwan-2.x.x top directory type
+
+ make programs
+
+ followed by
+
+ make install
+
+ * Next add your connections to "etc/ipsec.conf" and start strongSwan with
+
+ ipsec setup start
+
+-----------------------------------------------------------------------------
+
+This file is RCSID $Id: INSTALL,v 1.8 2006/01/22 16:22:23 as Exp $
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..1dc0f01f0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,33 @@
+Except for the DES library, MD2 and MD5 code, the PKCS#11 headers, and
+linux/net/ipsec/radij.c this software is under the GNU Public License,
+see the file COPYING.
+
+See the file CREDITS for details on origins of more of the code.
+
+The DES library is under a BSD style license, see
+ linux/crypto/ciphers/des/COPYRIGHT.
+Note that this software has a advertising clause in it.
+
+The MD2 implementation is from RSA Data Security Inc., so this package must
+include the following phrase: "RSA Data Security, Inc. MD2 Message Digest
+Algorithm" It is not under the GPL; see details in programs/pluto/md2.c.
+
+The MD5 implementation is from RSA Data Security Inc., so this package must
+include the following phrase: "derived from the RSA Data Security, Inc.
+MD5 Message-Digest Algorithm". It is not under the GPL; see details in
+linux/net/ipsec/ipsec_md5c.c.
+
+The PKCS#11 header files in programs/pluto/rsaref/ are from RSA Security Inc.,
+so they must include the following phrase: "RSA Security Inc. PKCS#11
+Cryptographic Token Interface (Cryptoki)". The headers are not under the GPL;
+see details in programs/pluto/rsaref/pkcs11.h.
+
+The linux/net/ipsec/radij.c code is derived from BSD 4.4lite code
+from sys/net/radix.c.
+
+In addition to the terms set out under the GPL, permission is granted to
+link the software against the libdes, md5c.c, and radij.c libraries just
+mentioned.
+
+
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..e24377652
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,602 @@
+# FreeS/WAN master makefile
+# Copyright (C) 1998-2002 Henry Spencer.
+#
+# 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.4 2004/11/14 21:50:59 as Exp $
+
+
+FREESWANSRCDIR=$(shell pwd)
+export FREESWANSRCDIR
+
+include Makefile.inc
+
+
+
+PATCHES=linux
+# where KLIPS goes in the kernel
+# note, some of the patches know the last part of this path
+KERNELKLIPS=$(KERNELSRC)/net/ipsec
+KERNELCRYPTODES=$(KERNELSRC)/crypto/ciphers/des
+KERNELLIBFREESWAN=$(KERNELSRC)/lib/libfreeswan
+KERNELLIBZLIB=$(KERNELSRC)/lib/zlib
+KERNELLIBCRYPTO=$(KERNELSRC)/lib/libcrypto
+KERNELINCLUDE=$(KERNELSRC)/include
+KERNELALG=$(KERNELKLIPS)/alg
+
+MAKEUTILS=packaging/utils
+ERRCHECK=${MAKEUTILS}/errcheck
+KVUTIL=${MAKEUTILS}/kernelversion
+KVSHORTUTIL=${MAKEUTILS}/kernelversion-short
+
+# kernel details
+# what variant of our patches should we use, and where is it
+KERNELREL=$(shell ${KVSHORTUTIL} ${KERNELSRC}/Makefile)
+
+# directories visited by all recursion
+SUBDIRS=doc lib programs linux
+
+# declaration for make's benefit
+.PHONY: def insert kpatch klink klibcryptolink patches _patches _patches2.2 _patches2.4 \
+ klipsdefaults programs install clean distclean \
+ ogo oldgo menugo xgo \
+ omod oldmod menumod xmod \
+ pcf ocf mcf xcf rcf nopromptgo \
+ precheck verset confcheck kernel module kinstall minstall \
+ backup unpatch uinstall install_file_list \
+ snapready relready ready buildready devready uml check taroldinstall \
+ umluserland
+
+
+# dummy default rule
+def:
+ @echo "Please read doc/intro.html or INSTALL before running make"
+ @false
+
+# everything that's necessary to put Klips into the kernel
+insert: patches klink klipsdefaults
+
+kpatch: unapplypatch applypatch klipsdefaults
+
+unapplypatch:
+ -if [ -f ${KERNELSRC}/freeswan.patch ]; then \
+ echo Undoing previous patches; \
+ cat ${KERNELSRC}/freeswan.patch | (cd ${KERNELSRC} && patch -p1 -R --force -E -z .preipsec --reverse --ignore-whitespace ); \
+ fi
+
+applypatch:
+ echo Now performing forward patches;
+ make kernelpatch${KERNELREL} | tee ${KERNELSRC}/freeswan.patch | (cd ${KERNELSRC} && patch -p1 -b -z .preipsec --forward --ignore-whitespace )
+
+kdiff:
+ echo Comparing ${KERNELSRC} to ${FREESWANSRCDIR}/linux.
+ packaging/utils/kerneldiff ${KERNELSRC}
+
+# create KERNELKLIPS and populate it with symlinks to the sources
+klink:
+ -[ -L $(KERNELKLIPS)/ipsec_init.c ] && rm -rf ${KERNELKLIPS}
+ -[ -L $(KERNELCRYPTODES)/cbc_enc.c ] && rm -rf ${KERNELCRYPTODES}
+ -[ -L $(KERNELLIBFREESWAN)/subnettoa.c ] && rm -rf ${KERNELLIBFREESWAN}
+ -[ -L ${KERNELLIBZLIB}/deflate.c ] && rm -rf ${KERNELLIBZLIB}
+ -[ -L ${KERNELINCLUDE}/freeswan.h ] && for i in linux/include/*; do rm -f ${KERNELINCLUDE}/$$i; done
+ -[ -L $(KERNELALG)/Makefile ] && rm -rf $(KERNELALG)
+ -[ -L $(KERNELLIBCRYPTO) ] && rm -f $(KERNELLIBCRYPTO)
+ mkdir -p $(KERNELKLIPS)
+ mkdir -p $(KERNELCRYPTODES)
+ mkdir -p $(KERNELLIBFREESWAN)
+ mkdir -p $(KERNELLIBZLIB)
+ mkdir -p $(KERNELALG)
+ $(KLIPSLINK) `pwd`/Makefile.ver $(KERNELKLIPS)
+ $(KLIPSLINK) `pwd`/linux/include/* $(KERNELINCLUDE)
+ $(KLIPSLINK) `pwd`/linux/net/ipsec/Makefile* $(KERNELKLIPS)
+ $(KLIPSLINK) `pwd`/linux/net/ipsec/Config.in $(KERNELKLIPS)
+ $(KLIPSLINK) `pwd`/linux/net/ipsec/defconfig $(KERNELKLIPS)
+ $(KLIPSLINK) `pwd`/linux/net/ipsec/*.[ch] $(KERNELKLIPS)
+ $(KLIPSLINK) `pwd`/linux/net/ipsec/alg/Makefile* $(KERNELALG)
+ $(KLIPSLINK) `pwd`/linux/net/ipsec/alg/Config.* $(KERNELALG)
+ $(KLIPSLINK) `pwd`/linux/net/ipsec/alg/ipsec_alg*.[ch] $(KERNELALG)
+ $(KLIPSLINK) `pwd`/linux/net/ipsec/alg/scripts $(KERNELALG)
+ # Each ALGo does it own symlinks
+ $(KLIPSLINK) `pwd`/lib/libcrypto $(KERNELLIBCRYPTO)
+ $(KLIPSLINK) `pwd`/linux/lib/zlib/*.[ch] $(KERNELLIBZLIB)
+ $(KLIPSLINK) `pwd`/linux/lib/zlib/Makefile* $(KERNELLIBZLIB)
+ $(KLIPSLINK) `pwd`/linux/lib/libfreeswan/*.[ch] $(KERNELLIBFREESWAN)
+ $(KLIPSLINK) `pwd`/linux/lib/libfreeswan/Makefile* $(KERNELLIBFREESWAN)
+ $(KLIPSLINK) `pwd`/linux/crypto/ciphers/des/*.[chsS] $(KERNELCRYPTODES)
+ $(KLIPSLINK) `pwd`/linux/crypto/ciphers/des/Makefile* $(KERNELCRYPTODES)
+ sed '/"/s/xxx/$(IPSECVERSION)/' linux/lib/libfreeswan/version.in.c >$(KERNELKLIPS)/version.c
+
+# create libcrypto symlink
+klibcryptolink:
+ -[ -L $(KERNELLIBCRYPTO) ] && rm -f $(KERNELLIBCRYPTO)
+ $(KLIPSLINK) `pwd`/lib/libcrypto $(KERNELLIBCRYPTO)
+
+# patch kernel
+PATCHER=packaging/utils/patcher
+
+patches:
+ @echo \"make patches\" is obsolete. See \"make kpatch\".
+ exit 1
+
+_patches:
+ echo "===============" >>out.kpatch
+ echo "`date` `cd $(KERNELSRC) ; pwd`" >>out.kpatch
+ $(MAKE) __patches$(KERNELREL) >>out.kpatch
+
+# Linux-2.0.x version
+__patches __patches2.0:
+ @$(PATCHER) -v $(KERNELSRC) Documentation/Configure.help \
+ 'CONFIG_IPSEC' $(PATCHES)/Documentation/Configure.help.fs2_0.patch
+ @$(PATCHER) -v $(KERNELSRC) net/Config.in \
+ 'CONFIG_IPSEC' $(PATCHES)/net/Config.in.fs2_0.patch
+ @$(PATCHER) -v $(KERNELSRC) net/Makefile \
+ 'CONFIG_IPSEC' $(PATCHES)/net/Makefile.fs2_0.patch
+ @$(PATCHER) -v $(KERNELSRC) net/ipv4/af_inet.c \
+ 'CONFIG_IPSEC' $(PATCHES)/net/ipv4/af_inet.c.fs2_0.patch
+# Removed patches, will unpatch automatically.
+ @$(PATCHER) -v $(KERNELSRC) include/linux/proc_fs.h
+ @$(PATCHER) -v $(KERNELSRC) net/core/dev.c
+ @$(PATCHER) -v $(KERNELSRC) net/ipv4/protocol.c
+ @$(PATCHER) -v $(KERNELSRC) drivers/net/Space.c
+ @$(PATCHER) -v $(KERNELSRC) net/netlink.c
+ @$(PATCHER) -v $(KERNELSRC) drivers/isdn/isdn_net.c
+
+# Linux-2.2.x version
+PATCHES24=klips/patches2.3
+__patches2.2:
+ @$(PATCHER) -v -c $(KERNELSRC) Documentation/Configure.help \
+ 'CONFIG_IPSEC' $(PATCHES)/Documentation/Configure.help.fs2_2.patch
+ @$(PATCHER) -v $(KERNELSRC) net/Config.in \
+ 'CONFIG_IPSEC' $(PATCHES)/net/Config.in.fs2_2.patch
+ @$(PATCHER) -v $(KERNELSRC) net/Makefile \
+ 'CONFIG_IPSEC' $(PATCHES)/net/Makefile.fs2_2.patch
+ @$(PATCHER) -v $(KERNELSRC) net/ipv4/af_inet.c \
+ 'CONFIG_IPSEC' $(PATCHES)/net/ipv4/af_inet.c.fs2_2.patch
+ @$(PATCHER) -v $(KERNELSRC) net/ipv4/udp.c \
+ 'CONFIG_IPSEC' $(PATCHES)/net/ipv4/udp.c.fs2_2.patch
+ @$(PATCHER) -v $(KERNELSRC) include/net/sock.h \
+ 'CONFIG_IPSEC' $(PATCHES)/net/include.net.sock.h.fs2_2.patch
+# Removed patches, will unpatch automatically.
+ @$(PATCHER) -v $(KERNELSRC) include/linux/proc_fs.h
+ @$(PATCHER) -v $(KERNELSRC) net/core/dev.c
+ @$(PATCHER) -v $(KERNELSRC) net/ipv4/protocol.c
+ @$(PATCHER) -v $(KERNELSRC) drivers/net/Space.c
+ @$(PATCHER) -v $(KERNELSRC) include/linux/netlink.h
+ @$(PATCHER) -v $(KERNELSRC) net/netlink/af_netlink.c
+ @$(PATCHER) -v $(KERNELSRC) net/netlink/netlink_dev.c
+ @$(PATCHER) -v $(KERNELSRC) include/linux/socket.h
+ @$(PATCHER) -v $(KERNELSRC) drivers/isdn/isdn_net.c
+
+# Linux-2.4.0 version
+PATCHES22=klips/patches2.2
+__patches2.3 __patches2.4:
+ @$(PATCHER) -v -c $(KERNELSRC) Documentation/Configure.help \
+ 'CONFIG_IPSEC' $(PATCHES)/Documentation/Configure.help.fs2_2.patch
+ @$(PATCHER) -v $(KERNELSRC) net/Config.in \
+ 'CONFIG_IPSEC' $(PATCHES)/net/Config.in.fs2_4.patch
+ @$(PATCHER) -v $(KERNELSRC) net/Makefile \
+ 'CONFIG_IPSEC' $(PATCHES)/net/Makefile.fs2_4.patch
+ @$(PATCHER) -v $(KERNELSRC) net/ipv4/af_inet.c \
+ 'CONFIG_IPSEC' $(PATCHES)/net/ipv4/af_inet.c.fs2_4.patch
+ @$(PATCHER) -v $(KERNELSRC) net/ipv4/udp.c \
+ 'CONFIG_IPSEC' $(PATCHES)/net/ipv4/udp.c.fs2_4.patch
+ @$(PATCHER) -v $(KERNELSRC) include/net/sock.h \
+ 'CONFIG_IPSEC' $(PATCHES)/net/include.net.sock.h.fs2_4.patch
+# Removed patches, will unpatch automatically.
+ @$(PATCHER) -v $(KERNELSRC) include/linux/proc_fs.h
+ @$(PATCHER) -v $(KERNELSRC) net/core/dev.c
+ @$(PATCHER) -v $(KERNELSRC) net/ipv4/protocol.c
+ @$(PATCHER) -v $(KERNELSRC) drivers/net/Space.c
+ @$(PATCHER) -v $(KERNELSRC) include/linux/netlink.h
+ @$(PATCHER) -v $(KERNELSRC) net/netlink/af_netlink.c
+ @$(PATCHER) -v $(KERNELSRC) net/netlink/netlink_dev.c
+ @$(PATCHER) -v $(KERNELSRC) drivers/isdn/isdn_net.c
+
+klipsdefaults:
+ @KERNELDEFCONFIG=$(KERNELSRC)/arch/$(ARCH)/defconfig ; \
+ KERNELCONFIG=$(KCFILE) ; \
+ if ! egrep -q 'CONFIG_IPSEC' $$KERNELDEFCONFIG ; \
+ then \
+ set -x ; \
+ cp -a $$KERNELDEFCONFIG $$KERNELDEFCONFIG.orig ; \
+ chmod u+w $$KERNELDEFCONFIG ; \
+ cat $$KERNELDEFCONFIG $(KERNELKLIPS)/defconfig \
+ >$$KERNELDEFCONFIG.tmp ; \
+ rm -f $$KERNELDEFCONFIG ; \
+ cp -a $$KERNELDEFCONFIG.tmp $$KERNELDEFCONFIG ; \
+ rm -f $$KERNELDEFCONFIG.tmp ; \
+ fi ; \
+ if ! egrep -q 'CONFIG_IPSEC' $$KERNELCONFIG ; \
+ then \
+ set -x ; \
+ cp -a $$KERNELCONFIG $$KERNELCONFIG.orig ; \
+ chmod u+w $$KERNELCONFIG ; \
+ cat $$KERNELCONFIG $(KERNELKLIPS)/defconfig \
+ >$$KERNELCONFIG.tmp ; \
+ rm -f $$KERNELCONFIG ; \
+ cp -a $$KERNELCONFIG.tmp $$KERNELCONFIG ; \
+ rm -f $$KERNELCONFIG.tmp ; \
+ fi
+
+
+
+# programs
+
+checkv199install:
+ if [ -f ${LIBDIR}/pluto ]; \
+ then \
+ echo WARNING: FreeS/WAN 1.99 still installed. ;\
+ echo WARNING: moving ${LIBDIR} to ${LIBDIR}.v1 ;\
+ mv ${LIBDIR} ${LIBDIR}.v1 ;\
+ fi
+
+install:: checkv199install
+
+programs install clean checkprograms::
+ @for d in $(SUBDIRS) ; \
+ do \
+ (cd $$d && $(MAKE) FREESWANSRCDIR=.. $@ ) || exit 1; \
+ done; \
+
+clean::
+ rm -rf $(RPMTMPDIR) $(RPMDEST)
+ rm -f out.*build out.*install # but leave out.kpatch
+ rm -f rpm.spec
+
+distclean: clean
+ rm -f out.kpatch
+ if [ -f umlsetup.sh ]; then source umlsetup.sh; if [ -d "$$POOLSPACE" ]; then rm -rf $$POOLSPACE; fi; fi
+
+
+
+# proxies for major kernel make operations
+
+# do-everything entries
+KINSERT_PRE=precheck verset insert
+PRE=precheck verset kpatch klibcryptolink
+POST=confcheck programs kernel install
+MPOST=confcheck programs module install
+ogo: $(PRE) pcf $(POST)
+oldgo: $(PRE) ocf $(POST)
+nopromptgo: $(PRE) rcf $(POST)
+menugo: $(PRE) mcf $(POST)
+xgo: $(PRE) xcf $(POST)
+omod: $(PRE) pcf $(MPOST)
+oldmod: $(PRE) ocf $(MPOST)
+menumod: $(PRE) mcf $(MPOST)
+xmod: $(PRE) xcf $(MPOST)
+
+# preliminaries
+precheck:
+ @if test ! -d $(KERNELSRC) -a ! -L $(KERNELSRC) ; \
+ then \
+ echo '*** cannot find directory "$(KERNELSRC)"!!' ; \
+ echo '*** may be necessary to add symlink to kernel source' ; \
+ exit 1 ; \
+ fi
+ @if ! cd $(KERNELSRC) ; \
+ then \
+ echo '*** cannot "cd $(KERNELSRC)"!!' ; \
+ echo '*** may be necessary to add symlink to kernel source' ; \
+ exit 1 ; \
+ fi
+ @if test ! -f $(KCFILE) ; \
+ then \
+ echo '*** cannot find "$(KCFILE)"!!' ; \
+ echo '*** perhaps kernel has never been configured?' ; \
+ echo '*** please do that first; the results are necessary.' ; \
+ exit 1 ; \
+ fi
+ @if test ! -f $(VERFILE) ; \
+ then \
+ echo '*** cannot find "$(VERFILE)"!!' ; \
+ echo '*** perhaps kernel has never been compiled?' ; \
+ echo '*** please do that first; the results are necessary.' ; \
+ exit 1 ; \
+ fi
+
+# set version code if this is a fresh CVS checkout
+ifeq ($(wildcard cvs.datemark),cvs.datemark)
+verset Makefile.ver: cvs.datemark
+ echo IPSECVERSION=`date -r cvs.datemark +cvs%Y%b%d_%H:%M:%S` >Makefile.ver
+ rm -f cvs.datemark;
+else
+verset Makefile.ver:
+ @grep IPSECVERSION Makefile.ver
+endif
+
+Makefile: Makefile.ver
+
+# configuring (exit statuses disregarded, something fishy here sometimes)
+xcf:
+ -cd $(KERNELSRC) ; $(MAKE) $(KERNMAKEOPTS) xconfig
+mcf:
+ -cd $(KERNELSRC) ; $(MAKE) $(KERNMAKEOPTS) menuconfig
+pcf:
+ -cd $(KERNELSRC) ; $(MAKE) $(KERNMAKEOPTS) config
+
+ocf:
+ -cd $(KERNELSRC) ; $(MAKE) $(KERNMAKEOPTS) oldconfig
+
+rcf:
+ cd $(KERNELSRC) ; $(MAKE) $(KERNMAKEOPTS) oldconfig_nonint </dev/null
+ cd $(KERNELSRC) ; $(MAKE) $(KERNMAKEOPTS) dep >/dev/null
+
+confcheck:
+ @if test ! -f $(KCFILE) ; \
+ then echo '*** no kernel configuration file written!!' ; exit 1 ; \
+ fi
+ @if ! egrep -q '^CONFIG_IPSEC=[my]' $(KCFILE) ; \
+ then echo '*** IPsec not in kernel config ($(KCFILE))!!' ; exit 1 ; \
+ fi
+ @if ! egrep -q 'CONFIG_IPSEC[ ]+1' $(ACFILE) && \
+ ! egrep -q 'CONFIG_IPSEC_MODULE[ ]+1' $(ACFILE) ; \
+ then echo '*** IPsec in kernel config ($(KCFILE)),' ; \
+ echo '*** but not in config header file ($(ACFILE))!!' ; \
+ exit 1 ; \
+ fi
+ @if egrep -q '^CONFIG_IPSEC=m' $(KCFILE) && \
+ ! egrep -q '^CONFIG_MODULES=y' $(KCFILE) ; \
+ then echo '*** IPsec configured as module in kernel with no module support!!' ; exit 1 ; \
+ fi
+ @if ! egrep -q 'CONFIG_IPSEC_AH[ ]+1' $(ACFILE) && \
+ ! egrep -q 'CONFIG_IPSEC_ESP[ ]+1' $(ACFILE) ; \
+ then echo '*** IPsec configuration must include AH or ESP!!' ; exit 1 ; \
+ fi
+
+# kernel building, with error checks
+kernel:
+ rm -f out.kbuild out.kinstall
+ # undocumented kernel folklore: clean BEFORE dep.
+ # we run make dep seperately, because there is no point in running ERRCHECK
+ # on the make dep output.
+ # see LKML thread "clean before or after dep?"
+ ( cd $(KERNELSRC) ; $(MAKE) $(KERNMAKEOPTS) $(KERNCLEAN) $(KERNDEP) )
+ ( cd $(KERNELSRC) ; $(MAKE) $(KERNMAKEOPTS) $(KERNEL) ) 2>&1 | tee out.kbuild
+ @if egrep -q '^CONFIG_MODULES=y' $(KCFILE) ; \
+ then set -x ; \
+ ( cd $(KERNELSRC) ; \
+ $(MAKE) $(KERNMAKEOPTS) modules 2>&1 ) | tee -a out.kbuild ; \
+ fi
+ ${ERRCHECK} out.kbuild
+
+# this target takes a kernel source tree and it builds a link tree,
+# and then does make oldconfig for each .config file that was found in configs.
+# The location for the disk space required for the link tree is found via
+# $RH_KERNELSRC_POOL
+preprhkern4module:
+ if [ -z "${RH_KERNELSRC_POOL}" ]; then echo Please set RH_KERNELSRC_POOL.; exit 1; fi
+ mkdir -p ${RH_KERNELSRC_POOL}
+ KV=`${KVUTIL} $(RH_KERNELSRC)/Makefile` ; \
+ cd ${RH_KERNELSRC_POOL} && \
+ mkdir -p $$KV && cd $$KV && \
+ for config in ${RH_KERNELSRC}/configs/*; do \
+ basecfg=`basename $$config` ;\
+ mkdir -p ${RH_KERNELSRC_POOL}/$$KV/$$basecfg && \
+ cd ${RH_KERNELSRC_POOL}/$$KV/$$basecfg && \
+ lndir ${RH_KERNELSRC} . && \
+ rm -rf include/asm && \
+ (cd include/linux && sed -e '/#include "\/boot\/kernel.h"/d' <rhconfig.h >rhconfig.h-new && mv rhconfig.h-new rhconfig.h ) && \
+ rm -f include/linux/modules/*.stamp && \
+ make dep && \
+ make oldconfig; \
+ done;
+
+# module-only building, with error checks
+ifneq ($(strip $(MODBUILDDIR)),)
+${MODBUILDDIR}/Makefile : ${FREESWANSRCDIR}/packaging/makefiles/module.make
+ mkdir -p ${MODBUILDDIR}
+ cp ${FREESWANSRCDIR}/packaging/makefiles/module.make ${MODBUILDDIR}/Makefile
+ echo "# " >>${MODBUILDDIR}/Makefile
+ echo "# Local Variables: " >>${MODBUILDDIR}/Makefile
+ echo "# compile-command: \"${MAKE} FREESWANSRCDIR=${FREESWANSRCDIR} ARCH=${ARCH} ${MODULE_FLAGS} MODULE_DEF_INCLUDE=${MODULE_DEF_INCLUDE} ipsec.o\"" >>${MODBUILDDIR}/Makefile
+ echo "# End: " >>${MODBUILDDIR}/Makefile
+
+# clean out the linux/net/ipsec directory so that VPATH will work properly
+module: ${MODBUILDDIR}/Makefile
+ ${MAKE} -C linux/net/ipsec ${MODULE_FLAGS} MODULE_DEF_INCLUDE=${MODULE_DEF_INCLUDE} clean
+ ${MAKE} -C ${MODBUILDDIR} ARCH=${ARCH} ${MODULE_FLAGS} MODULE_DEF_INCLUDE=${MODULE_DEF_INCLUDE} ipsec.o
+ ${MAKE} -C ${MODBUILDDIR} ARCH=${ARCH} ${MODULE_FLAGS} MODULE_DEF_INCLUDE=${MODULE_DEF_INCLUDE} LIBCRYPTO=${FREESWANSRCDIR}/lib/libcrypto MODULE_FLAGS="$(MODULE_FLAGS)" alg_modules
+
+modclean: ${MODBUILDDIR}/Makefile
+ ${MAKE} -C ${MODBUILDDIR} clean
+
+# module-only install, with error checks
+minstall:
+ ( FSMODLIB=`make -C $(KERNELSRC) -p dummy | ( sed -n -e '/^MODLIB/p' -e '/^MODLIB/q' ; cat > /dev/null ) | sed -e 's/^MODLIB[ :=]*\([^;]*\).*/\1/'` ; \
+ if [ -z "$$FSMODLIB" ] ; then \
+ FSMODLIB=`make -C $(KERNELSRC) -n -p modules_install | ( sed -n -e '/^MODLIB/p' -e '/^MODLIB/q' ; cat > /dev/null ) | sed -e 's/^MODLIB[ :=]*\([^;]*\).*/\1/'` ; \
+ fi ; \
+ if [ -z "$$FSMODLIB" ] ; then \
+ echo "No known place to install module. Aborting." ; \
+ exit 93 ; \
+ fi ; \
+ set -x ; \
+ mkdir -p $$FSMODLIB/kernel/net/ipsec ; \
+ cp $(MODBUILDDIR)/ipsec.o $$FSMODLIB/kernel/net/ipsec ; \
+ mkdir -p $$FSMODLIB/kernel/net/ipsec/alg ; \
+ for i in `sed -n '/IPSEC_ALG/s/CONFIG_IPSEC_ALG_\(.*\)=[Mm]/ipsec_\1.o/p' $(KCFILE) | tr '[A-Z]' '[a-z]'`;do \
+ echo "installing $$i"; \
+ cp $(MODBUILDDIR)/alg/$$i $$FSMODLIB/kernel/net/ipsec/alg ;\
+ done )
+
+else
+module:
+ ${MAKE} -C linux/net/ipsec ARCH=${ARCH} ${MODULE_FLAGS} MODULE_DEF_INCLUDE=${MODULE_DEF_INCLUDE} ipsec.o
+ ${MAKE} -C linux/net/ipsec ARCH=${ARCH} ${MODULE_FLAGS} MODULE_DEF_INCLUDE=${MODULE_DEF_INCLUDE} LIBCRYPTO=${FREESWANSRCDIR}/lib/libcrypto MODULE_FLAGS="$(MODULE_FLAGS)" alg_modules
+
+modclean:
+ ${MAKE} -C linux/net/ipsec ARCH=${ARCH} ${MODULE_FLAGS} MODULE_DEF_INCLUDE=${MODULE_DEF_INCLUDE} clean
+
+# module-only install, with error checks
+minstall:
+ ( FSMODLIB=`make -C $(KERNELSRC) -p dummy | ( sed -n -e '/^MODLIB/p' -e '/^MODLIB/q' ; cat > /dev/null ) | sed -e 's/^MODLIB[ :=]*\([^;]*\).*/\1/'` ; \
+ if [ -z "$$FSMODLIB" ] ; then \
+ FSMODLIB=`make -C $(KERNELSRC) -n -p modules_install | ( sed -n -e '/^MODLIB/p' -e '/^MODLIB/q' ; cat > /dev/null ) | sed -e 's/^MODLIB[ :=]*\([^;]*\).*/\1/'` ; \
+ fi ; \
+ if [ -z "$$FSMODLIB" ] ; then \
+ echo "No known place to install module. Aborting." ; \
+ exit 93 ; \
+ fi ; \
+ set -x ; \
+ mkdir -p $$FSMODLIB/kernel/net/ipsec ; \
+ cp linux/net/ipsec/ipsec.o $$FSMODLIB/kernel/net/ipsec ; \
+ mkdir -p $$FSMODLIB/kernel/net/ipsec/alg ; \
+ for i in `sed -n '/IPSEC_ALG/s/CONFIG_IPSEC_ALG_\(.*\)=[Mm]/ipsec_\1.o/p' $(KCFILE) | tr '[A-Z]' '[a-z]'`;do \
+ echo "installing $$i"; \
+ cp linux/net/ipsec/alg/$$i $$FSMODLIB/kernel/net/ipsec/alg ;\
+ done )
+
+endif
+
+# kernel install, with error checks
+kinstall:
+ rm -f out.kinstall
+ >out.kinstall
+ # undocumented kernel folklore: modules_install must precede install (observed on RHL8.0)
+ @if egrep -q '^CONFIG_MODULES=y' $(KCFILE) ; \
+ then set -x ; \
+ ( cd $(KERNELSRC) ; \
+ $(MAKE) $(KERNMAKEOPTS) modules_install 2>&1 ) | tee -a out.kinstall ; \
+ fi
+ ( cd $(KERNELSRC) ; $(MAKE) $(KERNMAKEOPTS) install ) 2>&1 | tee -a out.kinstall
+ ${ERRCHECK} out.kinstall
+
+kernelpatch2.5:
+ packaging/utils/kernelpatch 2.5
+
+kernelpatch2.4 kernelpatch:
+ packaging/utils/kernelpatch 2.4
+
+kernelpatch2.2:
+ packaging/utils/kernelpatch 2.2
+
+kernelpatch2.0:
+ packaging/utils/kernelpatch 2.0
+
+install_file_list:
+ @for d in $(SUBDIRS) ; \
+ do \
+ (cd $$d && $(MAKE) --no-print-directory FREESWANSRCDIR=.. install_file_list ) || exit 1; \
+ done;
+
+# take all the patches out of the kernel
+# (Note, a couple of files are modified by non-patch means; they are
+# included in "make backup".)
+unpatch:
+ @echo \"make unpatch\" is obsolete. See make unapplypatch.
+ exit 1
+
+_unpatch:
+ for f in `find $(KERNELSRC)/. -name '*.preipsec' -print` ; \
+ do \
+ echo "restoring $$f:" ; \
+ dir=`dirname $$f` ; \
+ core=`basename $$f .preipsec` ; \
+ cd $$dir ; \
+ mv -f $$core.preipsec $$core ; \
+ rm -f $$core.wipsec $$core.ipsecmd5 ; \
+ done
+
+# uninstall, as much as possible
+uninstall:
+ $(MAKE) --no-print-directory install_file_list | egrep -v '(/ipsec.conf$$|/ipsec.d/)' | xargs rm -f
+
+taroldinstall:
+ tar --ignore-failed-read -c -z -f oldFreeSWAN.tar.gz `$(MAKE) --no-print-directory install_file_list`
+
+# some oddities meant for the developers, probably of no use to users
+
+# make tags and TAGS files from ctags and etags for vi and emacs, respectively.
+tags TAGS: dummy
+ etags `find lib programs linux -name '*.[ch]'`
+ ctags `find lib programs linux -name '*.[ch]'`
+
+dummy:
+
+# at the moment there is no difference between snapshot and release build
+snapready: buildready
+relready: buildready
+ready: devready
+
+# set up for build
+buildready:
+ rm -f dtrmakefile cvs.datemark
+ cd doc ; $(MAKE) -s
+
+uml: programs checkprograms
+ @echo XXX do some checks to see if all the manual pieces are done.
+ -chmod +x testing/utils/make-uml.sh
+ testing/utils/make-uml.sh `pwd`
+
+umluserland:
+ (touch Makefile.inc && source umlsetup.sh && cd $$POOLSPACE && make $$FREESWANHOSTS $$REGULARHOSTS )
+
+
+# DESTDIR is normally set in Makefile.inc
+# These recipes explicitly pass it to the second-level makes so that
+# DESTDIR can be adjusted for building for UML without changing Makefile.inc
+# See testing/utils/functions.sh
+# testing/utils/make-uml.sh
+# testing/utils/uml-functions.sh
+check: uml Makefile.ver
+ifneq ($(strip(${REGRESSRESULTS})),)
+ mkdir -p ${REGRESSRESULTS}
+endif
+ @for d in $(SUBDIRS); do (cd $$d && $(MAKE) DESTDIR=${DESTDIR} checkprograms || exit 1); done
+ @for d in $(SUBDIRS); \
+ do \
+ echo ===================================; \
+ echo Now making check in $$d; \
+ echo ===================================; \
+ (cd $$d && $(MAKE) DESTDIR=${DESTDIR} check || exit 1);\
+ done
+ifneq ($(strip(${REGRESSRESULTS})),)
+ -perl testing/utils/regress-summarize-results.pl ${REGRESSRESULTS}
+endif
+
+
+rpm:
+ @echo please cd packaging/redhat and
+ @echo run "make RH_KERNELSRC=/some/path/to/kernel/src rpm"
+
+ipkg_strip:
+ @echo "Minimizing size for ipkg binaries..."
+ @cd $(DESTDIR)$(INC_USRLOCAL)/lib/ipsec && \
+ for f in *; do (if file $$f | grep ARM > /dev/null; then ( $(STRIP) --strip-unneeded $$f); fi); done
+ @rm -r $(DESTDIR)$(INC_USRLOCAL)/man
+ @rm -f $(DESTDIR)$(INC_RCDEFAULT)/*.old
+ @rm -f $(DESTDIR)$(INC_USRLOCAL)/lib/ipsec/*.old
+ @rm -f $(DESTDIR)$(INC_USRLOCAL)/libexec/ipsec/*.old
+ @rm -f $(DESTDIR)$(INC_USRLOCAL)/sbin/*.old
+
+ipkg_module:
+ @echo "Moving ipsec.o into temporary location..."
+ KV=$(shell ${KVUTIL} ${KERNELSRC}/Makefile) && \
+ mkdir -p $(FREESWANSRCDIR)/packaging/ipkg/kernel-module/lib/modules/$$KV/net/ipsec
+ KV=$(shell ${KVUTIL} ${KERNELSRC}/Makefile) && \
+ cp linux/net/ipsec/ipsec.o $(FREESWANSRCDIR)/packaging/ipkg/kernel-module/lib/modules/$$KV/net/ipsec/
+ KV=$(shell ${KVUTIL} ${KERNELSRC}/Makefile)
+
+ipkg_clean:
+ rm -rf $(FREESWANSRCDIR)/packaging/ipkg/kernel-module/
+ rm -rf $(FREESWANSRCDIR)/packaging/ipkg/ipkg/
+ rm -f $(FREESWANSRCDIR)/packaging/ipkg/control-freeswan
+ rm -f $(FREESWANSRCDIR)/packaging/ipkg/control-freeswan-module
+
+
+ipkg: programs install ipkg_strip ipkg_module
+ @echo "Generating ipkg...";
+ DESTDIR=${DESTDIR} FREESWANSRCDIR=${FREESWANSRCDIR} ARCH=${ARCH} IPSECVERSION=${IPSECVERSION} ./packaging/ipkg/generate-ipkg
+
+
+
+
diff --git a/Makefile.inc b/Makefile.inc
new file mode 100644
index 000000000..f5ec6741d
--- /dev/null
+++ b/Makefile.inc
@@ -0,0 +1,331 @@
+# FreeS/WAN pathnames and other master configuration
+# Copyright (C) 2001, 2002 Henry Spencer.
+#
+# 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.inc,v 1.12 2006/01/25 17:23:15 as Exp $
+
+
+# Variables in this file with names starting with INC_ are not for use
+# by Makefiles which include it; they are subject to change without warning.
+#
+# "Final" and "finally" refer to where the files will end up on the
+# running IPsec system, as opposed to where they get installed by our
+# Makefiles. (The two are different for cross-compiles and the like,
+# where our Makefiles are not the end of the installation process.)
+# Paths with FINAL in their names are the only ones that the installed
+# software itself depends on. (Very few things should know about the
+# FINAL paths; think twice and consult Henry before making something new
+# depend on them.) All other paths are install targets.
+# See also DESTDIR, below.
+
+
+### boilerplate, do not change
+SHELL=/bin/sh
+
+### paths within the source tree
+
+KLIPSINC=${FREESWANSRCDIR}/linux/include
+KLIPSSRC=${FREESWANSRCDIR}/linux/net/ipsec
+
+LIBFREESWANDIR=${FREESWANSRCDIR}/linux/lib/libfreeswan
+FREESWANLIB=${FREESWANSRCDIR}/lib/libfreeswan/libfreeswan.a
+
+LWRESDIR=${FREESWANSRCDIR}/lib/liblwres
+LWRESLIB=${LWRESDIR}/liblwres.a
+
+LIBDESSRCDIR=${FREESWANSRCDIR}/linux/crypto/ciphers/des
+LIBDESLITE=${FREESWANSRCDIR}/lib/libdes/libdes.a
+
+LIBPOLICYDIR=${FREESWANSRCDIR}/linux/lib/libipsecpolicy
+POLICYLIB=${FREESWANSRCDIR}/lib/libipsecpolicy/libipsecpolicy.a
+
+.PHONY: programs checkprograms clean
+
+### install pathnames
+
+# DESTDIR can be used to supply a prefix to all install targets.
+# (Note that "final" pathnames, signifying where files will eventually
+# reside rather than where install puts them, are exempt from this.)
+# The prefixing is done in this file, so as to have central control over
+# it; DESTDIR itself should never appear in any other Makefile.
+DESTDIR?=
+
+# "local" part of tree, used in building other pathnames
+INC_USRLOCAL=/usr/local
+
+# PUBDIR is where the "ipsec" command goes; beware, many things define PATH
+# settings which are assumed to include it (or at least, to include *some*
+# copy of the "ipsec" command).
+PUBDIR=$(DESTDIR)$(INC_USRLOCAL)/sbin
+
+# BINDIR is where sub-commands get put, FINALBINDIR is where the "ipsec"
+# command will look for them when it is run. Also called LIBEXECDIR.
+FINALLIBEXECDIR=$(INC_USRLOCAL)/libexec/ipsec
+LIBEXECDIR=$(DESTDIR)$(FINALBINDIR)
+
+FINALBINDIR=${FINALLIBEXECDIR}
+BINDIR=${LIBEXECDIR}
+
+
+# SBINDIR is where the user interface command goes.
+FINALSBINDIR=$(INC_USRLOCAL)/sbin
+SBINDIR=$(DESTDIR)$(FINALSBINDIR)
+
+# libdir is where utility files go
+FINALLIBDIR=$(INC_USRLOCAL)/lib/ipsec
+LIBDIR=$(DESTDIR)$(FINALLIBDIR)
+
+
+# where the appropriate manpage tree is located
+# location within INC_USRLOCAL
+INC_MANDIR=man
+# the full pathname
+MANTREE=$(DESTDIR)$(INC_USRLOCAL)/$(INC_MANDIR)
+# all relevant subdirectories of MANTREE
+MANPLACES=man3 man5 man8
+
+# where configuration files go
+FINALCONFFILE?=/etc/ipsec.conf
+CONFFILE=$(DESTDIR)$(FINALCONFFILE)
+
+FINALCONFDIR?=/etc
+CONFDIR=$(DESTDIR)$(FINALCONFDIR)
+
+FINALCONFDDIR?=${FINALCONFDIR}/ipsec.d
+CONFDDIR=$(DESTDIR)$(FINALCONFDDIR)
+
+# sample configuration files go into
+INC_DOCDIR?=share/doc
+FINALEXAMPLECONFDIR=${INC_USRLOCAL}/${INC_DOCDIR}/strongswan
+EXAMPLECONFDIR=${DESTDIR}${FINALEXAMPLECONFDIR}
+
+FINALDOCDIR?=${INC_USRLOCAL}/${INC_DOCDIR}/strongswan
+DOCDIR=${DESTDIR}${FINALDOCDIR}
+
+# where per-conn pluto logs go
+VARDIR?=/var
+LOGDIR?=${VARDIR}/log
+FINALLOGDIR?=${DESTDIR}${LOGDIR}
+
+
+# An attempt is made to automatically figure out where boot/shutdown scripts
+# will finally go: the first directory in INC_RCDIRS which exists gets them.
+# If none of those exists (or INC_RCDIRS is empty), INC_RCDEFAULT gets them.
+# With a non-null DESTDIR, INC_RCDEFAULT will be used unless one of the
+# INC_RCDIRS directories has been pre-created under DESTDIR.
+INC_RCDIRS=/etc/rc.d/init.d /etc/rc.d /etc/init.d /sbin/init.d
+INC_RCDEFAULT=/etc/rc.d/init.d
+
+# RCDIR is where boot/shutdown scripts go; FINALRCDIR is where they think
+# will finally be (so utils/Makefile can create a symlink in BINDIR to the
+# place where the boot/shutdown script will finally be, rather than the
+# place where it is installed).
+FINALRCDIR=$(shell for d in $(INC_RCDIRS) ; \
+ do if test -d $(DESTDIR)/$$d ; \
+ then echo $$d ; exit 0 ; \
+ fi ; done ; echo $(INC_RCDEFAULT) )
+RCDIR=$(DESTDIR)$(FINALRCDIR)
+
+
+
+### kernel pathnames
+
+# Kernel location: where patches are inserted, where kernel builds are done.
+
+# this is a hack using the wildcard to look for existence of a file/dir
+ifneq ($(wildcard /usr/src/linux-2.4),)
+KERNELSRC?=/usr/src/linux-2.4
+else
+KERNELSRC?=/usr/src/linux
+endif
+
+
+# where kernel configuration outputs are located
+KCFILE=$(KERNELSRC)/.config
+ACFILE=$(KERNELSRC)/include/linux/autoconf.h
+VERFILE=$(KERNELSRC)/include/linux/version.h
+
+
+
+### misc installation stuff
+
+# what program to use when installing things
+INSTALL=install
+
+# flags to the install program, for programs, manpages, and config files
+# -b has install make backups (n.b., unlinks original), --suffix controls
+# how backup names are composed.
+# Note that the install procedures will never overwrite an existing config
+# file, which is why -b is not specified for them.
+INSTBINFLAGS=-b --suffix=.old
+INSTMANFLAGS=
+INSTCONFFLAGS=
+
+
+### misc configuration, included here in hopes that other files will not
+### have to be changed for common customizations.
+
+# extra compile flags, for userland and kernel stuff, e.g. -g for debug info
+# (caution, this stuff is still being sorted out, will change in future)
+USERCOMPILE?=-g -O3
+KLIPSCOMPILE=-O3
+
+# command used to link/copy KLIPS into kernel source tree
+# There are good reasons why this is "ln -s"; only people like distribution
+# builders should ever change it.
+KLIPSLINK=ln -s -f
+
+# extra options for use in kernel build
+KERNMAKEOPTS=
+
+# kernel Makefile targets to be done before build
+# Can be overridden if you are *sure* your kernel doesn't need them. (2.2.xx
+# and later reportedly do not.)
+KERNDEP=dep
+KERNCLEAN=clean
+
+# kernel make name: zImage for 2.0.xx, bzImage for 2.2.xx and later, and
+# boot on non-x86s (what ever happened to standards?)
+INC_B=$(shell test -d $(DIRIN22) && echo b)
+KERNEL=$(shell if expr " `uname -m`" : ' i.86' >/dev/null ; \
+ then echo $(INC_B)zImage ; \
+ else echo boot ; \
+ fi)
+
+# temporary directory to be used when building RPMs, and where to put the
+# resulting RPM tree
+RPMKERNDIR := $(shell echo `pwd`/tmp.rpmkernel)
+RPMTMPDIR := $(shell echo `pwd`/tmp.rpmbuild)
+RPMDEST := $(shell echo `pwd`/rpms)
+
+# Newer versions of RPM do not permit building of packages with the "rpm"
+# command. For RedHat systems with older version of RPM, use:
+# RPMBUILD=rpm
+# instead.
+RPMBUILD=rpmbuild
+
+### paths to resources on the host system
+#
+# Set this to a RedHat kernel-sources RPM. This normally extracts into
+# /usr/src/linux-2.4, but you might have extracted it elsewhere with
+# rpm2cpio.
+#
+RH_KERNELSRC?=/usr/src/linux-2.4
+
+## build environment variations
+##
+
+# set this to a place where you have installed a bind9.3
+# snapshot (20021115 or better). A bind 9.2, particularly a RedHat
+# installed one in RH 7.2, won't work - you wind up depending upon
+# openssl.
+
+BIND9STATICLIBDIR?=/usr/local/lib
+
+# FreeSWAN 3.x will require bind9.
+USE_LWRES?=false
+
+# whether or not to use iproute2 based commands.
+#
+USE_IPROUTE2?=true
+
+# what kind of firewalling to use:
+# 2.0 - ipfwadm
+# 2.2 - ipchains
+# 2.4 - iptables
+IPSEC_FIREWALLTYPE=iptables
+
+# whether or not to include ipsec policy code into pluto.
+# false for now, since it is still experimental.
+USE_IPSECPOLICY?=false
+
+# include IKEPING in the distribution
+USE_IKEPING?=false
+
+# include support for KEY RR
+# this will become false in late 2003.
+USE_KEYRR?=true
+
+# include support for KERNEL 2.5/2.6 IPsec in pluto
+USE_KERNEL26?=true
+
+# whether or not pluto sends its strongSwan Vendor ID
+USE_VENDORID?=true
+
+# whether or not pluto sends an XAUTH VID (Cisco Mode Config Interoperability)
+USE_XAUTH_VID?=false
+
+# whether to support NAT Traversal (aka NAT-T)
+USE_NAT_TRAVERSAL?=true
+
+# whether to support NAT-T in transport mode (needed for Win2K NAT-T Interop)
+USE_NAT_TRAVERSAL_TRANSPORT_MODE?=false
+
+# include libcurl support (currently used for fetching CRLs, OCSP and SCEP)
+USE_LIBCURL?=false
+
+# include LDAP support (currently used for fetching CRLs)
+USE_LDAP?=false
+
+# uncomment this line if using the LDAPv3 protocol
+LDAP_VERSION=3
+# uncomment this line if using the LDAPv2 protocol
+#LDAP_VERSION=2
+
+# include PKCS11-based smartcard support
+USE_SMARTCARD?=false
+
+# Default PKCS11 library
+# Uncomment this line if using OpenSC <= 0.9.6
+PKCS11_DEFAULT_LIB=\"/usr/lib/pkcs11/opensc-pkcs11.so\"
+# Uncomment this line if using OpenSC >= 0.10.0
+#PKCS11_DEFAULT_LIB=\"/usr/lib/opensc-pkcs11.so\"
+# Uncomment and complete this line if using another default library
+#PKCS11_DEFAULT_LIB=\"/usr/lib/...\"
+
+# Enable the leak detective to find memory leaks
+USE_LEAK_DETECTIVE?=false
+
+# set this to space where a linked/configured tree can be created by
+# preprhkern4module. Only needed if you are going to be created RPMs
+# outside of a distribution (as the FS team does for RedHat).
+#RH_KERNELSRC_POOL=/c2/freeswan/rh_kern
+
+# the following is a list of symbols which will be used to construct
+# the module goo to identify which module goes with each kernel.
+MODULE_GOO_LIST=irq_stat netif_rx register_sysctl_table send_sig
+MODULE_GOO_LIST+=kmalloc __kfree_skb __ip_select_ident alloc_skb
+MODULE_GOO_LIST+=icmp_send ip_fragment sock_register
+
+MODULE_DEF_INCLUDE=${FREESWANSRCDIR}/packaging/linus/config-all.h
+MODULE_DEFCONFIG?=${KLIPSSRC}/defconfig
+
+MODULE_FLAGS:=KLIPSMODULE=true TOPDIR=${KERNELSRC} -f ${MODULE_DEFCONFIG} -f Makefile
+
+# supply kernel-configuration ARCH defaults
+ifeq ($(ARCH),)
+ARCH := $(shell uname -m)
+endif
+# always sanitize $(ARCH)
+ARCH := $(shell echo $(ARCH) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+
+# export everything so that scripts can use them.
+export LIBFREESWANDIR FREESWANSRCDIR FREESWANLIB
+
+-include ${FREESWANSRCDIR}/Makefile.ver
+
+# for emacs
+#
+# Local Variables: ;;;
+# mode: makefile ;;;
+# End Variables: ;;;
+#
diff --git a/Makefile.ver b/Makefile.ver
new file mode 100644
index 000000000..435dd7311
--- /dev/null
+++ b/Makefile.ver
@@ -0,0 +1 @@
+IPSECVERSION=2.7.0
diff --git a/README b/README
new file mode 100644
index 000000000..d40d887a3
--- /dev/null
+++ b/README
@@ -0,0 +1,3091 @@
+ ----------------------------
+ strongSwan - Configuration
+ ----------------------------
+
+
+Contents
+--------
+
+ 1. Overview
+ 2. Quickstart
+ 2.1 Site-to-Site case
+ 2.2 Host-to-Host case
+ 2.3 Four Tunnel case
+ 2.4 Four Tunnel case the elegant way with source routing
+ 2.5 Roadwarrior case
+ 2.6 Roadwarrior case with virtual IP
+ 3. Generating X.509 certificates and CRLs with OpenSSL
+ 3.1 Generating a CA certificate
+ 3.2 Generating a host or user certificate
+ 3.3 Generating a CRL
+ 3.4 Revoking a certificate
+ 4. Configuring the connections - ipsec.conf
+ 4.1 Configuring my side
+ 4.2 Multiple certificates
+ 4.3 Configuring the peer side using CA certificates
+ 4.4 Handling Virtual IPs and wildcard subnets
+ 4.5 Protocol and port selectors
+ 4.6 IPsec policies based on wildcards
+ 4.7 IPsec policies based on CA certificates
+ 4.8 Sending certificate requests
+ 4.9 IPsec policies based on group attributes
+ 5. Configuring certificates and CRLs
+ 5.1 Installing CA certificates
+ 5.2 Installing optional Certificate Revocation Lists (CRLs)
+ 5.3 Dynamic update of certificates and CRLs
+ 5.4 Local caching of CRLs
+ 5.5 Online Certificate Status Protocol (OCSP)
+ 5.6 CRL policy
+ 5.7 Configuring the peer side using locally stored certificates
+ 6. Configuring the private keys - ipsec.secrets
+ 6.1 Loading private key files in PKCS#1 format
+ 6.2 Entering passphrases interactively
+ 6.3 Multiple private keys
+ 7. Configuring CA properties - ipsec.conf
+ 8. Smartcard support
+ 8.1 Configuring a smartcard-based connection
+ 8.2 Entering the PIN code
+ 8.3 PIN-pad equipped smartcard readers
+ 8.4 Configuring a smartcard using pkcs15-init
+ 8.5 PKCS#1 proxy functions
+ 9. Configuring the clients
+ 9.1 strongSwan
+ 9.2 PGPnet
+ 9.3 Safenet/Soft-Remote
+ 9.4 SSH Sentinel
+ 9.5 Windows 2000/XP
+ 10. Monitoring functions
+ 11. Firewall support functions
+ 11.1 Environment variables in the updown script
+ 11.2 Automatic insertion and deletion of iptables firewall rules (NEW)
+ 11.3 Sample Linux 2.6 _updown_espmark script for iptables < 1.3.5
+ 12. Authentication with raw RSA public keys
+ 13. Authentication with OpenPGP certificates
+ 13.1 OpenPGP certificates
+ 13.2 OpenPGP private keys
+ 13.3 Monitoring functions
+ 13.4 Suppression of certificate request messages
+ 14. Additional features
+ 14.1 Authentication and encryption algorithms
+ 14.2 NAT traversal
+ 14.3 Dead peer detection
+ 14.4 IKE Mode Config
+ 15. Copyright statement and acknowledgements
+
+
+1. Overview
+ --------
+
+strongSwan is an OpenSource IPsec solution for the Linux operating system
+and currently supports the following features:
+
+ * runs both on Linux 2.4 (KLIPS) and Linux 2.6 (native IPsec) kernels.
+
+ * strong 3DES, AES, Serpent, Twofish, or Blowfish encryption.
+
+ * Authentication based on X.509 certificates or preshared secrets.
+
+ * IPsec policies based on wildcards or intermediate CAs.
+
+ * Powerful and flexible IPsec policies based on group attributes.
+
+ * Retrieval of Certificate Revocation Lists (CRLs) via HTTP or LDAP.
+
+ * Local caching of fetched CRLs
+
+ * Full support of the Online Certificate Status Protocol (OCSP, RFC 2560).
+
+ * CA management functions including OCSP and CRL URIs and default LDAP server.
+
+ * Optional storage of RSA private keys on smartcards or USB crypto tokens
+
+ * Standardized PKCS#11 interface with optional proxy functions serving
+ external applications (disc encryption, etc.).
+
+ * NAT-Traversal (RFC 3947)
+
+ * Support of Virtual IPs via static configuratin and IKE Mode Config
+
+ * Support of Delete SA and informational Notification messages.
+
+ * Dead Peer Detection (DPD, RFC 3706)
+
+Compatibility has successfully been tested with peers running the following
+IPsec clients:
+
+ FreeS/WAN, Openswan, SafeNet/SoftRemote, NCP Secure Entry Client,
+ SonicWALL Global VPN Client, The GreenBow, Microsoft Windows 2000/XP, etc.
+
+Furthermore, interoperability with the following VPN gateways
+has been demonstrated during the IPsec 2001 Conference in Paris:
+
+ Cisco IOS Routers, Cisco PIX firewall, Cisco VPN3000,
+ Nortel Contivity VPN Switch, NetScreen (FreeS/WAN as responder only),
+ OpenBSD with isakmpd, Netasq, Netcelo, and 6WIND.
+
+Potentially any IPsec implementation with X.509 certificate support can
+be made to cooperate with strongSwan. The latest addition has been the successful
+interoperability with the Check Point VPN-1 NG gateway.
+
+
+2. Quickstart
+ ----------
+
+In the following examples we assume for reasons of clarity that left designates
+the local host and that right is the remote host. Certificates for users, hosts
+and gateways are issued by a ficticious strongSwan CA. How to generate private keys
+and certificates using OpenSSL will be explained in section 3. The CA certificate
+"strongswanCert.pem" must be present on all VPN end points in order to be able to
+authenticate the peers.
+
+
+2.1 Site-to-site case
+ -----------------
+
+In this scenario two security gateways moon and sun will connect the
+two subnets moon-net and sun-net with each other through a VPN tunnel
+set up between the two gateways:
+
+ 10.1.0.0/16 -- | 192.168.0.1 | === | 192.168.0.2 | -- 10.2.0.0/16
+ moon-net moon sun sun-net
+
+Configuration on gateway moon:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/moonCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA moonKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn net-net
+ left=%defaultroute
+ leftsubnet=10.1.0.0/16
+ leftcert=moonCert.pem
+ right=192.168.0.2
+ rightsubnet=10.2.0.0/16
+ rightid="C=CH, O=Linux strongSwan, CN=sun.strongswan.org"
+ auto=start
+
+Configuration on gateway sun:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/sunCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA sunKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn net-net
+ left=%defaultroute
+ leftsubnet=10.2.0.0/16
+ leftcert=sunCert.pem
+ right=192.168.0.1
+ rightsubnet=10.1.0.0/16
+ rightid="C=CH, O=Linux strongSwan, CN=moon.strongswan.org"
+ auto=start
+
+
+2.2 Host-to-host case
+ -----------------
+
+This is a setup between two single hosts which don't have a subnet behind
+them. Although IPsec transport mode would be sufficient for host-to-host
+connections we will use the default IPsec tunnel mode.
+
+ | 192.168.0.1 | === | 192.168.0.2 |
+ moon sun
+
+Configuration on host moon:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/moonCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA moonKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn host-host
+ left=%defaultroute
+ leftcert=moonCert.pem
+ right=192.168.0.2
+ rightid="C=CH, O=Linux strongSwan, CN=sun.strongswan.org"
+ auto=start
+
+Configuration on host sun:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/sunCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA sunKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn host-host
+ left=%defaultroute
+ leftcert=sunCert.pem
+ right=192.168.0.1
+ rightid="C=CH, O=Linux strongSwan, CN=moon.strongswan.org"
+ auto=start
+
+
+2.3 Four Tunnel case
+ ----------------
+
+In a site-to-site setup a system administrator logged into the local gateway
+often would like to access the peer gateway or a server in the subnet behind
+the peer gateway over a secure IPsec tunnel.Since IP packets leaving a gateway
+via the outer network interface carry the IP address of this NIC, four IPsec
+Security Associations (SAs) must be set up to achieve full connectivity. The
+example below shows how this can be done without much additional typing work ,
+using the "also" macro which includes connection definitions defined farther
+down in the ipsec.conf file.
+
+ 10.1.0.0/16 -- | 192.168.0.1 | === | 192.168.0.2 | -- 10.2.0.0/16
+ moon-net moon sun sun-net
+
+Configuration on gateway moon:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/moonCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA moonKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn net-net
+ leftsubnet=10.1.0.0/16
+ rightsubnet=10.2.0.0/16
+ also host-host
+
+ conn net-host
+ leftsubnet=10.1.0.0/16
+ also host-host
+
+ conn host-net
+ rightsubnet=10.2.0.0/16
+ also host-host
+
+ conn host-host
+ left=%defaultroute
+ leftcert=moonCert.pem
+ right=192.168.0.2
+ rightid="C=CH, O=Linux strongSwan, CN=sun.strongswan.org"
+ auto=start
+
+Configuration on gateway sun:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/sunCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA sunKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn net-net
+ leftsubnet=10.2.0.0/16
+ rightsubnet=10.1.0.0/16
+ also=host-host
+
+ conn net-host
+ leftsubnet=10.2.0.0/16
+ also=host-host
+
+ conn host-net
+ rightsubnet=10.1.0.0/16
+ also=host-host
+
+ conn host-host
+ left=%defaultroute
+ leftcert=sunCert.pem
+ right=192.168.0.1
+ rightid="C=CH, O=Linux strongSwan, CN=moon.strongswan.org"
+ auto=start
+
+
+2.4 The four tunnel case the elegant way with source routing
+ --------------------------------------------------------
+
+As you certainly agree, the full four tunnel case described in the previous
+section becomes quite complex. If we could force the source address of the
+IP packets leaving the gateway through the outer interface to take on the
+IP address of the inner interface then we could use the single subnet-to-subnet
+tunnel from section 2.1. Such a setup becomes possible if we use the
+source routing capabilites of the ip route command that is already used
+by strongSwan's updown scripts.
+
+ 10.1.0.0/16 -- | 192.168.0.1 | === | 192.168.0.2 | -- 10.2.0.0/16
+ moon-net moon sun sun-net
+
+If we assume that the inner IP address of gateway moon is 10.1.0.1
+and the inner IP address of gateway sun is 10.2.0.1 then the
+insertion of the parameter
+
+ leftsourceip=10.1.0.1
+
+in the connection definition of moon and
+
+ leftsourceip=10.2.0.1
+
+on sun, respectively, will install source routing on both gateways.
+As a result the command
+
+ ping 10.2.0.1
+
+executed on moon will leave the gateway with a source address of
+10.1.0.1 and will therefore take the net-net IPsec tunnel.
+
+Configuration on gateway moon:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/moonCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA moonKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn net-net
+ left=%defaultroute
+ leftsourceip=10.1.0.1
+ leftsubnet=10.1.0.0/16
+ leftcert=moonCert.pem
+ right=192.168.0.2
+ rightsubnet=10.2.0.0/16
+ rightid="C=CH, O=Linux strongSwan, CN=sun.strongswan.org"
+ auto=start
+
+Configuration on gateway sun:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/sunCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA sunKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn net-net
+ left=%defaultroute
+ leftsubnet=10.2.0.0/16
+ leftsourceip=10.2.0.1
+ leftcert=sunCert.pem
+ right=192.168.0.1
+ rightsubnet=10.1.0.0/16
+ rightid="C=CH, O=Linux strongSwan, CN=moon.strongswan.org"
+ auto=start
+
+
+2.5 Roadwarrior case
+ ----------------
+
+This is a very common case where a strongSwan gateway serves an arbitrary number
+of remote VPN clients usually having dynamic IP addresses.
+
+ 10.1.0.0/16 -- | 192.168.0.1 | === | x.x.x.x |
+ moon-net moon carol
+
+Configuration on gateway moon:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/moonCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA moonKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn rw
+ left=%defaultroute
+ leftsubnet=10.1.0.0/16
+ leftcert=moonCert.pem
+ right=%any
+ auto=add
+
+Configuration on roadwarrior carol:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/carolCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA carolKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn home
+ left=%defaultroute
+ leftcert=carolCert.pem
+ right=192.168.0.1
+ rightsubnet=10.1.0.0/16
+ rightid="C=CH, O=Linux strongSwan, CN=moon.strongswan.org"
+ auto=start
+
+
+2.6 Roadwarrior case with virtual IP
+ --------------------------------
+
+Roadwarriors usually have dynamic IP addresses assigned by the ISP they are
+currently attached to. In order to simplify the routing from moon-net back
+to the remote access client carol it would be desirable if the roadwarrior had
+an inner IP address chosen from a pre-assigned pool.
+
+ 10.1.0.0/16 -- | 192.168.0.1 | === | x.x.x.x | -- 10.3.0.1
+ moon-net moon carol virtual IP
+
+This virtual IP address can be assigned to a strongSwan roadwarrior by adding
+the parameter
+
+ leftsourceip=10.3.0.1
+
+to the roadwarrior's ipsec.conf. Of course the virtual IP of each roadwarrior
+must be distinct. In our example it is chosen from the address pool
+
+ rightsubnetwithin=10.3.0.0/16
+
+which can be added to the gateway's ipsec.conf so that a single connection
+definition can handle multiple roadwarriors.
+
+Configuration on gateway moon:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/moonCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA moonKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn rw
+ left=%defaultroute
+ leftsubnet=10.1.0.0/16
+ leftcert=moonCert.pem
+ right=%any
+ rightsubnetwithin=10.3.0.0/16
+ auto=add
+
+Configuration on roadwarrior carol:
+
+ /etc/ipsec.d/cacerts/strongswanCert.pem
+
+ /etc/ipsec.d/certs/carolCert.pem
+
+ /etc/ipsec.secrets:
+
+ : RSA carolKey.pem "<optional passphrase>"
+
+ /etc/ipsec.conf:
+
+ conn home
+ left=%defaultroute
+ leftsourceip=10.3.0.1
+ leftcert=carolCert.pem
+ right=192.168.0.1
+ rightsubnet=10.1.0.0/16
+ rightid="C=CH, O=Linux strongSwan, CN=moon.strongswan.org"
+ auto=start
+
+
+3. Generating certificates and CRLs with OpenSSL
+ ---------------------------------------------
+
+This section is not a full-blown tutorial on how to use OpenSSL. It just lists
+a few points that are relevant if you want to generate your own certificates
+and CRLs for use with strongSwan.
+
+
+3.1 Generating a CA certificate
+ ---------------------------
+
+The OpenSSL statement
+
+ openssl req -x509 -days 1460 -newkey rsa:2048 \
+ -keyout strongswanKey.pem -out strongswanCert.pem
+
+creates a 2048 bit RSA private key strongswanKey.pem and a self-signed CA
+certificate strongswanCert.pem with a validity of 4 years (1460 days).
+
+ openssl x509 -in cert.pem -noout -text
+
+lists the properties of a X.509 certificate cert.pem. It allows you to verify
+whether the configuration defaults in openssl.cnf have been inserted correctly.
+
+If you prefer the CA certificate to be in binary DER format then the following
+command achieves this transformation:
+
+ openssl x509 -in strongswanCert.pem -outform DER -out strongswanCert.der
+
+The directory /etc/ipsec.d/cacerts contains all required CA certificates either
+in binary DER or in base64 PEM format. Irrespective of the file suffix, Pluto
+"automagically" determines the correct format.
+
+
+3.2 Generating a host or user certificate
+ -------------------------------------
+
+The OpenSSL statement
+
+ openssl req -newkey rsa:1024 -keyout hostKey.pem \
+ -out hostReq.pem
+
+generates a 1024 bit RSA private key hostKey.pem and a certificate request
+hostReq.pem which has to be signed by the CA.
+
+If you want to add a subjectAltName field to the host certificate you must edit
+the OpenSSL configuration file openssl.cnf and add the following line in the
+[ usr_cert ] section:
+
+ subjectAltName=DNS:moon.strongswan.org
+
+if you want to identify the host by its Fully Qualified Domain Name (FQDN ), or
+
+ subjectAltName=IP:192.168.0.1
+
+if you want the ID to be of type IPV4_ADDR. Of course you could include both
+ID types with
+
+ subjectAltName=DNS:moon.strongswan.org,IP:192.168.0.1
+
+but the use of an IP address for the identification of a host should be
+discouraged anyway.
+
+For user certificates the appropriate ID type is USER_FQDN which can be
+specified as
+
+ subjectAltName=email:carol@strongswan.org
+
+or if the user's e-mail address is part of the subject's distinguished name
+
+ subjectAltName=email:copy
+
+Now the certificate request can be signed by the CA with the command
+
+ openssl ca -in hostReq.pem -days 730 -out hostCert.pem -notext
+
+If you omit the -days option then the default_days value (365 days) specified
+in openssl.cnf is used. The -notext option avoids that a human readable
+listing of the certificate is prepended to the base64 encoded certificate
+body.
+
+If you want to use the dynamic CRL fetching feature described in section 4.7
+then you may include one or several crlDistributionPoints in your end
+certificates. This can be done in the [ usr_cert ] section of the openssl.cnf
+configuration file:
+
+ crlDistributionPoints= @crl_dp
+
+ [ crl_dp ]
+
+ URI.1="http://crl.strongswan.org/strongswan.crl"
+ URI.2="ldap://ldap.strongswan.org/cn=strongSwan Root CA, o=Linux strongSwan
+ , c=CH?certificateRevocationList"
+
+If you have only a single http distribution point then the short form
+
+ crlDistributionPoints="URI:http://crl.strongswan.org/strongswan.crl"
+
+also works. Due to a known bug in OpenSSL this notation fails with ldap URIs.
+
+Usually a Windows-based VPN client needs its private key, its host or
+user certificate, and the CA certificate. The most convenient way to load
+this information is to put everything into a PKCS#12 file:
+
+ openssl pkcs12 -export -inkey carolKey.pem \
+ -in carolCert.pem -name "carol" \
+ -certfile strongswanCert.pem -caname "strongSwan Root CA" \
+ -out carolCert.p12
+
+
+3.3 Generating a CRL
+ ----------------
+
+An empty CRL that is signed by the CA can be generated with the command
+
+ openssl ca -gencrl -crldays 15 -out crl.pem
+
+If you omit the -crldays option then the default_crl_days value (30 days)
+specified in openssl.cnf is used.
+
+If you prefer the CRL to be in binary DER format then this conversion
+can be achieved with
+
+ openssl crl -in crl.pem -outform DER -out cert.crl
+
+The directory /etc/ipsec.d/crls contains all CRLs either in binary DER
+or in base64 PEM format. Irrespective of the file suffix, Pluto
+"automagically" determines the correct format.
+
+
+3.4 Revoking a certificate
+ ----------------------
+
+A specific host certificate stored in the file host.pem is revoked with the
+command
+
+ openssl ca -revoke host.pem
+
+Next the CRL file must be updated
+
+ openssl ca -gencrl -crldays 60 -out crl.pem
+
+The content of the CRL file can be listed with the command
+
+ openssl crl -in crl.pem -noout -text
+
+in the case of a base64 CRL, or alternatively for a CRL in DER format
+
+ openssl crl -inform DER -in cert.crl -noout -text
+
+
+
+4. Configuring the connections - ipsec.conf
+ ----------------------------------------
+
+4.1 Configuring my side
+ -------------------
+
+Usually the local side is the same for all connections. Therefore it makes
+sense to put the definitions characterizing the strongSwan security gateway into
+the conn %default section of the configuration file /etc/ipsec.conf. If we
+assume throughout this document that the strongSwan security gateway is left and
+the peer is right then we can write
+
+conn %default
+ # my side is left - the freeswan security gateway
+ left=%defaultroute
+ leftcert=moonCert.pem
+ # load connection definitions automatically
+ auto=add
+
+The X.509 certificate by which the strongSwan security gateway will authenticate
+itself by sending it in binary form to its peers as part of the Internet Key
+Exchange (IKE) is specified in the line
+
+ leftcert=moonCert.pem
+
+The certificate can either be stored in base64 PEM-format or in the binary
+DER-format. Irrespective of the file suffix, Pluto "automagically" determines
+the correct format. Therefore
+
+ leftcert=moonCert.der
+
+or
+
+ leftcert=moonCert.cer
+
+would also be valid alternatives.
+
+When using relative pathnames as in the examples above, the certificate files
+must be stored in in the directory /etc/ipsec.d/certs. In order to distinguish
+strongSwan's own certificates from locally stored trusted peer certificates
+(see section 5.5 for details), they could also be stored in a subdirectory
+below /etc/ipsec.d/certs as e.g. in
+
+ leftcert=mycerts/moonCert.pem
+
+Absolute pathnames are also possible as in
+
+ leftcert=/usr/ssl/certs/moonCert.pem
+
+As an ID for the VPN gateway we recommend the use of a Fully Qualified Domain
+Name (FQDN) of the form
+
+conn rw
+ right=%any
+ leftid=@moon.strongswan.org
+
+Important: When an FQDN identifier is used it must be explicitly included as a
+so called subjectAltName of type dnsName (DNS:) in the certificate indicated
+by leftcert. For details on how to generate certificates with subjectAltNames,
+please refer to section 7.2.
+
+If you don't want to mess with subjectAltNames, you can use the certificate's
+Distinguished Name (DN) instead, which is an identifier of type DER_ASN1_DN
+and which can be written e.g. in the LDAP-type format
+
+conn rw
+ right=%any
+ leftid="C=CH, O=Linux strongSwan, CN=moon.strongswan.org"
+
+Since the subject's DN is part of the certificate, the leftid does not have to
+be declared explicitly. Thus the entry
+
+conn rw
+ right=%any
+
+automatically assumes the subject DN of leftcert to be the host ID.
+
+
+4.2 Multiple certificates
+ ---------------------
+
+strongSwan supports multiple local host certificates and corresponding
+RSA private keys:
+
+conn rw1
+ right=%any
+ rightid=@peer1.domain1
+ leftcert=myCert1.pem
+ # leftid is DN of myCert1
+
+conn rw2
+ right=%any
+ rightid=@peer2.domain2
+ leftcert=myCert2.pem
+ # leftid is DN of myCert2
+
+When peer1 initiates a connection then strongSwan will send myCert1 and will
+sign with myKey1 defined in /etc/ipsec.secrets (see section 6.2) whereas
+myCert2 and myKey2 will be used in a connection setup started from peer2.
+
+
+4.3 Configuring the peer side using CA certificates
+ -----------------------------------------------
+
+Now we can proceed to define our connections. In many applications we might
+have dozens of mostly Windows-based road warriors connecting to a central
+strongSwan security gateway. The following most simple statement:
+
+conn rw
+ right=%any
+
+defines the general roadwarrior case. The line right=%any literally means that
+any IPSec peer is accepted, regardless of its current IP source address and its
+ID, as long as the peer presents a valid X.509 certificate signed by a CA the
+strongSwan security gateway puts explicit trust in. Additionally the signature
+during IKE main mode gives proof that the peer is in possession of the private
+RSA key matching the public key contained in the transmitted certificate.
+
+The ID by which a peer is identifying itself during IKE main mode can by any of
+the ID types IPV4_ADDR, FQDN, USER_FQDN or DER_ASN1_DN. If one of the first
+three ID types is used, then the accompanying X.509 certificate of the peer
+must contain a matching subjectAltName field of the type ipAddress (IP:),
+dnsName (DNS:) or rfc822Name (email:), respectively. With the fourth type
+DER_ASN1_DN the identifier must completely match the subject field of the
+peer's certificate. One of the two possible representations of a
+Distinguished Name (DN) is the LDAP-type format
+
+ rightid="C=CH, O=Linux strongSwan, CN=sun.strongswan.org"
+
+Additional whitespace can be added everywhere as desired since it will be
+automatically eliminated by the X.509 parser. An exception is the single
+whitespace between individual words , like e.g. in Linux strongSwan, which is
+preserved by the parser.
+
+The Relative Distinguished Names (RDNs) can alternatively be separated by a
+slash '/' instead of a comma ','
+
+ rightid="/C=CH/O=Linux strongSwan/CN=sun.strongswan.org"
+
+This is the representation extracted from the certificate by the OpenSSL
+command line option
+
+ openssl x509 -in sunCert.pem -noout -subject
+
+The following RDNs are supported by strongSwan
+
++---------------------------------------------------+
+| DC Domain Component |
+|---------------------------------------------------|
+| C Country |
+|---------------------------------------------------|
+| ST State or province |
+|---------------------------------------------------|
+| L Locality or town |
+|---------------------------------------------------|
+| O Organisation |
+|---------------------------------------------------|
+| OU Organisational Unit |
+|---------------------------------------------------|
+| CN Common Name |
+|---------------------------------------------------|
+| ND NameDistinguisher, used with CN |
+|---------------------------------------------------|
+| N Name |
+|---------------------------------------------------|
+| G Given name |
+|---------------------------------------------------|
+| S Surname |
+|---------------------------------------------------|
+| I Initials |
+|---------------------------------------------------|
+| T Personal title |
+|---------------------------------------------------|
+| E E-mail |
+|---------------------------------------------------|
+| Email E-mail |
+|---------------------------------------------------|
+| emailAddress E-mail |
+|---------------------------------------------------|
+| SN Serial number |
+|---------------------------------------------------|
+| serialNumber Serial number |
+|---------------------------------------------------|
+| D Description |
+|---------------------------------------------------|
+| ID X.500 Unique Identifier |
+|---------------------------------------------------|
+| UID User ID |
+|---------------------------------------------------|
+| TCGID [Siemens] Trust Center Global ID |
+|---------------------------------------------------|
+| unstructuredName Unstructured Name |
+|---------------------------------------------------|
+| UN Unstructured Name |
+|---------------------------------------------------|
+| employeeNumber Employee Number |
+|---------------------------------------------------|
+| EN Employee Number |
++---------------------------------------------------+
+
+With the roadwarrior connection definition listed above, an IPsec SA for
+the strongSwan security gateway moon.strongswan.org itself can be established.
+If any roadwarrior should be able to reach e.g. the two subnets 10.1.0.0/24
+and 10.1.3.0/24 behind the security gateway then the following connection
+definitions will make this possible
+
+conn rw1
+ right=%any
+ leftsubnet=10.1.0.0/24
+
+conn rw3
+ right=%any
+ leftsubnet=10.1.3.0/24
+
+If not all peers in possession of a X.509 certificate signed by a specific
+certificate authority shall be given access to the Linux security gateway,
+then either a subset of them can be barred by listing the serial numbers of
+their certificates in a certificate revocation list (CRL) as specified in
+section 5.2 or as an alternative, access can be controlled by explicitly
+putting a roadwarrior entry for each eligible peer into ipsec.conf:
+
+conn sun
+ right=%any
+ rightid=@sun.strongswan.org
+
+conn carol
+ right=%any
+ rightid=carol@strongswan.org
+
+conn dave
+ right=%any
+ rightid="C=CH, O=Linux strongSwan, CN=dave@strongswan.org"
+
+When the IP address of a peer is known to be stable, it can be specified as
+well. This entry is mandatory when the strongSwan host wants to act as the
+initiator of an IPSec connection.
+
+conn sun
+ right=192.168.0.2
+ rightid=@sun.strongswan.org
+
+conn carol
+ right=192.168.0.100
+ rightid=carol@strongswan.org
+
+conn dave
+ right=192.168.0.200
+ rightid="C=CH, O=Linux strongSwan, CN=dave@strongswan.org"
+
+conn venus
+ right=192.168.0.50
+
+In the last example the ID types FQDN, USER_FQDN, DER_ASN1_DN and IPV4_ADDR,
+respectively, were used. Of course all connection definitions presented so far
+have included the lines in the conn %defaults section, comprising among other
+a left and leftcert entry.
+
+
+4.4 Handling Virtual IPs and wildcard subnets
+ -----------------------------------------
+
+Often roadwarriors are behind NAT-boxes with IPsec passthrough, which causes
+the inner IP source address of an IPsec tunnel to be different from the
+outer IP source address usually assigned dynamically by the ISP.
+Whereas the varying outer IP address can be handled by the right=%any
+construct, the inner IP address or subnet must always be declared in a
+connection definition. Therefore for the three roadwarriors rw1 to rw3
+connecting to a strongSwan security gateway the following entries are
+required in /etc/ipsec.conf:
+
+conn rw1
+ right=%any
+ righsubnet=10.4.0.5/32
+
+conn rw2
+ right=%any
+ rightsubnet=10.4.0.47/32
+
+conn rw3
+ right=%any
+ rightsubnet=10.4.0.128/28
+
+With the wildcard parameter rightsubnetwithin these three entries can be
+reduced to the single connection definition
+
+conn rw
+ right=%any
+ rightsubnetwithin=10.4.0.0/24
+
+Any host will be accepted (of course after successful authentication based on
+the peer's X.509 certificate only) if it declares a client subnet lying totally
+within the brackets defined by the wildcard subnet definition (in our example
+10.4.0.0/24). For each roadwarrior a connection instance tailored to the
+subnet of the particular client will be created,based on the generic
+rightsubnetwithin template.
+
+This strongSwan feature can also be helpful with VPN clients getting a
+dynamically assigned inner IP from a DHCP server located on the NAT router box.
+
+
+4.5 Protocol and Port Selectors
+ ---------------------------
+
+strongSwan offer the possibility to restrict the protocol and optionally the
+ports in an IPsec SA using the rightprotoport and leftprotoport parameters.
+
+Some examples:
+
+conn icmp
+ right=%any
+ rightprotoport=icmp
+ left=%defaultroute
+ leftid=@moon.strongswan.org
+ leftprotoport=icmp
+
+conn http
+ right=%any
+ rightprotoport=6
+ left=%defaultroute
+ leftid=@moon.strongswan.org
+ leftprotoport=6/80
+
+conn l2tp # with port wildcard for Mac OS X Panther interoperability
+ right=%any
+ rightprotoport=17/%any
+ left=%defaultroute
+ leftid=@moon.strongswan.org
+ leftprotoport=17/1701
+
+conn dhcp
+ right=%any
+ rightprotoport=udp/bootpc
+ left=%defaultroute
+ leftid=@moon.strongswan.org
+ leftsubnet=0.0.0.0/0 #allows DHCP discovery broadcast
+ leftprotoport=udp/bootps
+ rekey=no
+ keylife=20s
+ rekeymargin=10s
+ auto=add
+
+Protocols and ports can be designated either by their numerical values
+or by their acronyms defined in /etc/services.
+
+ ipsec status
+
+shows the following connection definitions:
+
+"icmp": 192.168.0.1[@moon.strongswan.org]:1/0...%any:1/0
+"http": 192.168.0.1[@moon.strongswan.org]:6/80...%any:6/0
+"l2tp": 192.168.0.1[@moon.strongswan.org]:17/1701...%any:17/%any
+"dhcp": 0.0.0.0/0===192.168.0.1[@moon.strongswan.org]:17/67...%any:17/68
+
+Based on the protocol and port selectors appropriate eroutes will be set
+up, so that only the specified payload types will pass through the IPsec
+tunnel.
+
+
+4.6 IPsec policies based on wildcards
+ ---------------------------------
+
+In large VPN-based remote access networks there is often a requirement that
+access to the various parts of an internal network must be granted selectively,
+e.g. depending on the group membership of the remote access user. strongSwan
+makes this possible by applying wildcard filtering on the VPN user's
+distinguished name (ID_DER_ASN1_DN).
+
+Let's make a practical example:
+
+An organization has a sales department (OU=Sales) and a research group
+(OU=Research). In the company intranet there are separate subnets for Sales
+(10.0.0.0/24) and Research (10.0.1.0/24) but both groups share a common web
+server (10.0.2.100). The VPN clients use Virtual IP addresses that are either
+assigned statically or via DHCP-over-IPsec. The sales and research departments
+use IP addresses from separate DHCP address pools (10.1.0.0/24) and (10.1.1.0/24),
+respectively. An X.509 certificate is issued to each employee, containing in its
+subject distinguished name the country (C=CH), the company (O=ACME),
+the group membership(OU=Sales or OU=Research) and the common name (e.g.
+CN=Bart Simpson).
+
+The IPsec policy defined above can now be enforced with the following three
+IPsec security associations:
+
+conn sales
+ right=%any
+ rightid="C=CH, O=ACME, OU=Sales, CN=*"
+ rightsubnetwithin=10.1.0.0/24 # Sales DHCP range
+ leftsubnet=10.0.0.0/24 # Sales subnet
+
+conn research
+ right=%any
+ rightid="C=CH, O=ACME, OU=Research, CN=*"
+ rightsubnetwithin=10.1.1.0/24 # Research DHCP range
+ leftsubnet=10.0.1.0/24 # Research subnet
+
+conn web
+ right=%any
+ rightid="C=CH, O=ACME, OU=*, CN=*"
+ rightsubnetwithin=10.1.0.0/23 # Remote access DHCP range
+ leftsubnet=10.0.2.100/32 # Web server
+ rightprotoport=tcp # TCP protocol only
+ leftprotoport=tcp/http # TCP port 80 only
+
+Of course group specific tunneling could be implemented on the
+basis of the Virtual IP range specified by the rightsubnetwithin
+parameter alone, but the wildcard matching mechanism guarantees that
+only authorized user can access the corresponding subnets.
+
+The '*' character is used as a wildcard in relative distinguished names (RDNs).
+In order to match a wildcard template, the ID_DER_ASN1_DN of a peer must contain
+the same number of RDNs (selected from the list in section 4.3) appearing in the
+exact order defined by the template.
+
+ "C=CH, O=ACME, OU=Research, OU=Special Effects, CN=Bart Simpson"
+
+matches the templates
+
+ "C=CH, O=ACME, OU=Research, OU=*, CN=*"
+
+ "C=CH, O=ACME, OU=*, OU=Special Effects, CN=*"
+
+ "C=CH, O=ACME, OU=*, OU=*, CN=*"
+
+but not the template
+
+ "C=CH, O=ACME, OU=*, CN=*"
+
+which doesn't have the same number of RDNs.
+
+
+4.7 IPsec policies based on CA certificates
+ ---------------------------------------
+
+As an alternative to the wildcard based IPsec policies described in section 4.6,
+access to specific client host and subnets can abe controlled on the basis of
+the CA that issued the peer certificate
+
+
+conn sales
+ right=%any
+ rightca="C=CH, O=ACME, OU=Sales, CN=Sales CA"
+ rightsubnetwithin=10.1.0.0/24 # Sales DHCP range
+ leftsubnet=10.0.0.0/24 # Sales subnet
+
+conn research
+ right=%any
+ rightca="C=CH, O=ACME, OU=Research, CN=Research CA"
+ rightsubnetwithin=10.1.1.0/24 # Research DHCP range
+ leftsubnet=10.0.1.0/24 # Research subnet
+
+conn web
+ right=%any
+ rightca="C=CH, O=ACME, CN=ACME Root CA"
+ rightsubnetwithin=10.1.0.0/23 # Remote access DHCP range
+ leftsubnet=10.0.2.100/32 # Web server
+ rightprotoport=tcp # TCP protocol only
+ leftprotoport=tcp/http # TCP port 80 only
+
+In the example above, the connection "sales" can be used by peers
+presenting certificates issued by the Sales CA, only. In the same way,
+the use of the connection "research" is restricted to owners of certificates
+issued by the Research CA. The connection "web" is open to both "Sales" and
+"Research" peers because the required "ACME Root CA" is the issuer of the
+Research and Sales intermediate CAs. If no rightca parameter is present
+then any valid certificate issued by one of the trusted CAs in
+/etc/ipsec.d/cacerts can be used by the peer.
+
+The leftca parameter usually doesn't have to be set explicitly because
+by default it is set to the issuer field of the certificate loaded via
+leftcert. The statement
+
+ rightca=%same
+
+sets the CA requested from the peer to the CA used by the left side itself
+as e.g. in
+
+conn sales
+ right=%any
+ rightca=%same
+ leftcert=mySalesCert.pem
+
+
+4.8 Sending certificate requests
+ ----------------------------
+
+The presence of a rightca parameter also causes the CA to be sent as
+part of the certificate request message when strongSwan is the initiator.
+A special case occurs when strongSwan responds to a roadwarrior. If several
+roadwarrior connections based on different CAs are defined then all eligible
+CAs will be listed in Pluto’s certificate request message.
+
+
+4.9 IPsec policies based on group attributes
+ ----------------------------------------
+
+X.509 attribute certificates are the most powerful mechanism for implementing
+IPsec security policies. The rightgroups parameter in a connection definition
+restricts the access to members of the listed groups only. An IPsec peer must
+have a valid attribute certificate issued by a trusted Authorization Authority
+and listing one of the requirede group attributes in order to get admitted.
+
+conn sales
+ right=%any
+ rightgroups="Sales"
+ rightsubnetwithin=10.1.0.0/24 # Sales DHCP range
+ leftsubnet=10.0.0.0/24 # Sales subnet
+
+conn research
+ right=%any
+ rightgroups="Research"
+ rightsubnetwithin=10.1.1.0/24 # Research DHCP range
+ leftsubnet=10.0.1.0/24 # Research subnet
+
+conn web
+ right=%any
+ rightgroups="Sales, Research"
+ rightsubnetwithin=10.1.0.0/23 # Remote access DHCP range
+ leftsubnet=10.0.2.100/32 # Web server
+ rightprotoport=tcp # TCP protocol only
+ leftprotoport=tcp/http # TCP port 80 only
+
+In the examples above membership of the group "Sales" is required for
+connection sales and membership of "Research" for connection research
+whereas connection web is accessible for both groups.
+
+Currently the attribute certificates of the peers must be loaded statically
+via the /etc/ipsec.d/acerts/ directory. In future releases of strongSwan it
+will be possible to fetch them from an LDAP directory server.
+
+
+5. Configuring certificates and CRLs
+ ---------------------------------
+
+
+5.1 Installing the CA certificates
+ ------------------------------
+
+X.509 certificates received by strongSwan during the IKE protocol are
+automatically authenticated by going up the trust chain until a self-signed
+root CA certificate is reached. Usually host certificates are directly signed
+by a root CA, but strongSwan also supports multi-level hierarchies with
+intermediate CAs in between. All CA certificates belonging to a trust chain
+must be copied in either binary DER or base64 PEM format into the directory
+
+ /etc/ipsec.d/cacerts/
+
+
+5.2 Installing optional certificate revocation lists (CRLs)
+ -------------------------------------------------------
+
+By copying a CA certificate into /etc/ipsec.d/cacerts/, automatically all user
+or host certificates issued by this CA are declared valid. Unfortunately
+private keys might get compromised inadvertently or intentionally, personal
+certificates of users leaving a company have to be blocked immediately, etc.
+To this purpose certificate revocation lists (CRLs) have been created. CRLs
+contain the serial numbers of all user or host certificates that have been
+revoked due to various reasons.
+
+After successful verification of the X.509 trust chain, Pluto searches its
+list of CRLs either obtained by loading them from the /etc/ipsec.d/crls/
+directory or fetching them dynamically from a HTTP or LDAP server for the
+presence of a CRL issued by the CA that has signed the certificate.
+
+If the serial number of the certificate is found in the CRL then the public key
+contained in the certificate is declared invalid and the IPSec SA will not be
+established. If no CRL is found or if the deadline defined in the nextUpdate
+field of the CRL has been reached, a warning is issued but the public key will
+nevertheless be accepted. CRLs must be stored either in binary DER or base64 PEM
+format in the crls directory. Section 7.3 will explain in detail how CRLs can
+be created using OpenSSL.
+
+
+5.3 Dynamic update of certificates and CRLs
+ ---------------------------------------
+
+Pluto reads certificates and CRLs from their respective files during system
+startup and keeps them in memory in the form of chained lists. X.509
+certificates have a finite life span defined by their validity field. Therefore
+it must be possible to replace CA or OCSP certificates kept in system memory
+without disturbing established ISAKMP SAs. Certificate revocation lists should
+also be updated in the regular intervals indicated by the nextUpdate field in
+the CRL body. The following interactive commands allow the manual replacement
+of the various files:
+
++---------------------------------------------------------------------------+
+| ipsec rereadsecrets reload file /etc/ipsec.secrets |
+|---------------------------------------------------------------------------|
+| ipsec rereadcacerts reload all files in /etc/ipsec.d/cacerts/ |
+|---------------------------------------------------------------------------|
+| ipsec rereadaacerts reload all files in /etc/ipsec.d/aacerts/ |
+|---------------------------------------------------------------------------|
+| ipsec rereadocspcerts reload all files in /etc/ipsec.d/ocspcerts/ |
+|---------------------------------------------------------------------------|
+| ipsec rereadacerts reload all files in /etc/ipsec.d/acerts/ |
+|---------------------------------------------------------------------------|
+| ipsec rereadcrls reload all files in /etc/ipsec.d/crls/ |
+|---------------------------------------------------------------------------|
+| ipsec rereadall ipsec rereadsecrets |
+| rereadcacerts |
+| rereadaacerts |
+| rereadocspcerts |
+| rereadacerts |
+| rereadcrls |
+|---------------------------------------------------------------------------|
+| ipsec purgeocsp purge the OCSP cache and fetching requests |
++---------------------------------------------------------------------------+
+
+CRLs can also be automatically fetched from an HTTP or LDAP server by using
+the CRL distribution points contained in X.509 certificates. The command
+
+ ipsec listcrls
+
+shows any pending fetch requests:
+
+ Oct 31 00:29:53 2002, trials: 2
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ distPts: 'http://crl.strongswan.org/strongswan.crl'
+ 'ldap://ldap.strongswan.org/o=Linux strongSwan, c=CH
+ ?certificateRevocationList?base
+ ?(objectClass=certificationAuthority)'
+
+In the example above, an http and an ldap URL were extracted from a received
+end certificate. An independent thread then tries to fetch a CRL from the
+designated distribution points. The same thread also periodically checks
+if any loaded CRLs are about to expire. The check interval can be defined in
+the "config setup" section of the ipsec.conf file:
+
+ config setup
+ crlcheckinterval=600
+
+In our example the thread wakes up every 600 seconds or 10 minutes in order
+to check the validity of the CRLs or to retry any pending fetch requests:
+
+ List of X.509 CRLs:
+
+ Dec 19 09:35:31 2002, revoked certs: 40
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ distPts: 'http://crl.strongswan.org/strongswan.crl'
+ updates: this Dec 19 09:35:00 2002
+ next Dec 19 10:35:00 2002 warning (expires in 19 minutes)
+
+ List of fetch requests:
+
+ Dec 19 10:15:31 2002, trials: 1
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ distPts: 'http://crl.strongwan.org/strongswan.crl'
+
+The first trial to update a CRL is started 2*crlcheckinterval before the
+nextUpdate time, i.e. when less than 20 minutes are left in our practical
+example. When crlcheckinterval is set to 0 (this is also the default value
+when the parameter is not set in ipsec.conf) then the CRL checking and updating
+thread is not started and dynamic CRL fetching is disabled.
+
+
+5.4 Local caching of CRLs
+ ---------------------
+
+The the ipsec.conf option
+
+ config setup
+ cachecrls=yes
+
+activates the local caching of CRLs that were dynamically fetched from an
+HTTP or LDAP server. Cached copies are stored in /etc/ipsec.d/crls under a
+unique filename formed from the issuer's SubjectKeyIdentifier and the suffix .crl.
+
+With the cached copy the CRL is immediately available after pluto's startup.
+When the local copy is about to expire it is automatically replaced with an
+updated CRL fetched from one of the defined CRL distribution points.
+
+
+5.5 Online Certificate Status Protocol (OCSP)
+ -----------------------------------------
+
+The Online Certificate Status Protocol is defined by RFC 2560. It can be
+used to query an OCSP server about the current status of an X.509 certificate
+and is often used as a more dynamic alternative to a static Certificate
+Revocation List (CRL). Both the OCSP request sent by the client and the OCSP
+response messages returned by the server are transported via a standard
+TCP/HTTP connection. Therefore cURL support must be enabled in pluto/Makefile:
+
+ # Uncomment this line to enable OCSP fetching using HTTP
+ LIBCURL=1
+
+In the simplest OCSP setup, a default URI under which the OCSP server for a
+given CA can be accessed is defined in ipsec.conf:
+
+ config setup
+ crlcheckinterval=600
+
+ ca strongswan
+ cacert=strongswanCert.pem
+ ocspuri=http://ocsp.strongswan.org:8880
+ auto=add
+
+The HTTP port can be freely chosen. In our example we have assumed TCP port 8880.
+The crlcheckinterval must be set to a value different from zero. Otherwise the
+OCSP fetching thread will not be started.
+
+The well-known openssl-0.9.7 package from http://www.openssl.org implements
+an OCSP server that can be used in conjunction with an openssl-based Public
+Key Infrastructure. The OCSP client integrated into Pluto does not contain
+any OpenSSL code though, but is based on the existing ASN.1 functionality of
+strongSwan.
+
+The OpenSSL-based OCSP server is started with the following command:
+
+ openssl ocsp -index index.txt -CA strongswanCert.pem -port 8880 \
+ -rkey ocspKey.pem -rsigner ocspCert.pem \
+ -resp_no_certs -nmin 60 -text
+
+The command consists of the parameters
+
+ -index index.txt is a copy of the OpenSSL index file containing the list of
+ all issued certificates. The certificate status in indext.txt
+ is designated either by V for valid or R for revoked. If
+ a new certificate is added or if a certificate is revoked
+ using the openssl ca command, the OCSP server must be restarted
+ in order for the changes in index.txt to take effect.
+
+ -CA the CA certificate
+
+ -port the HTTP port the OCSP server is listening on.
+
+-rkey the private key used to sign the OCSP response. The use of the
+ sensitive CA private key is not recommended since this could
+ jeopardize the security of your production PKI if the OCSP
+ server is hacked. It is much better to generate a special
+ RSA private key just for OCSP signing use instead.
+
+-rsigner the certificate of the OCSP server containing a public key which
+ matches the private key defined by -rkey and which can be used by
+ the client to check the trustworthiness of the signed OCSP response.
+
+-resp_no_certs With this option the OCSP signer certificate defined by
+ -rsigner is not included in the OCSP response.
+
+-nmin the validity interval of an OCSP response given in minutes.
+ 2*crlcheckinterval before the expiration of the OCSP responses,
+ a new query will by pro-actively started by the Pluto fetching thread.
+
+ If nmin is missing or set to zero then the default validity interval
+ compiled into Pluto will be 2 minutes, leading to a quasi one-time
+ use of the OCSP status response which will not be periodically
+ refreshed by the fetching thread. In conjunction with the parameter
+ setting "strictcrlpolicy=yes" a real-time certificate status query
+ can be implemented in this way.
+
+-text This option activates a verbose logging output, showing the contents
+ of both the received OCSP request and sent OCSP response.
+
+How does Pluto get hold of the OCSP signer certificate? There are two
+possibilities:
+
+Either you put the OCSP certificate into the default directory
+
+ /etc/ipsec.d/ocspcerts
+
+or alternatively Pluto can receive it as part of the OCSP response from the
+remote OCSP server. In the latter case, how can Pluto make sure that
+the server has indeed been authorized by the CA to deal out certificate status
+information? In order to ascertain the OCSP signer capability, an extended
+key usage attribute can be included in the OCSP server certificate. Just
+insert the parameter
+
+ extendedKeyUsage=OCSPSigner
+
+in the [ usr_cert ] section of your openssl.cnf configuration file before
+the CA signs the OCSP server certificate.
+
+For a given CA the corresponding ca section in ipsec.conf (see section 7) allows
+to define the URI of a single OCSP server. As an alternative an OCSP URI can be
+embedded into each host and user certificate by putting the line
+
+ authorityInfoAccess = OCSP;URI:http://ocsp.strongswan.org:8880
+
+into the [ usr_cert ] section of your openssl.cnf configuration file.
+If an OCSP authorityInfoAccess extension is present in a certificate then this
+record overrides the default URI defined by the ca section.
+
+
+5.6 CRL Policy
+ ----------
+
+By default Pluto is quite tolerant concerning the handling of CRLs. It is not
+mandatory for a CRL to be present in /etc/ipsec.d/crls and if the expiration
+date defined by the nextUpdate field of a CRL has been reached just a warning
+is issued but a peer certificate will always be accepted if it has not been
+revoked.
+
+If you want to enforce a stricter CRL policy then you can do this by setting
+the "strictcrlpolicy" option. This is done in the "config setup" section
+of the ipsec.conf file:
+
+ config setup
+ strictcrlpolicy=yes
+ ...
+
+A certificate received from a peer will not be accepted if no corresponding
+CRL or OCSP response is available. And if an ISAKMP SA re-negotiation takes
+place after the nextUpdate deadline has been reached, the peer certificate
+will be declared invalid and the cached RSA public key will be deleted, causing
+the connection in question to fail. Therefore if you are going to use the
+"strictcrlpolicy=yes" option, make sure that the CRLs will always be updated
+in time. Otherwise a total standstill would ensue.
+
+As mentioned earlier the default setting is "strictcrlpolicy=no"
+
+
+5.7 Configuring the peer side using locally stored certificates
+ -----------------------------------------------------------
+
+If you don't want to use trust chains based on CA certificates as proposed in
+section 4.3 you can alternatively import trusted peer certificates directly
+into Pluto. Thus you do not have to rely on the certificate to be transmitted
+by the peer as part of the IKE protocol.
+
+With the conn %default section defined in section 4.1 and the use of the
+rightcert keyword for the peer side, the connection definitions in section 4.3
+can alternatively be written as
+
+ conn sun
+ right=%any
+ rightid=@sun.strongswan.org
+ rightcert=sunCert.cer
+
+ conn carol
+ right=192.168.0.100
+ rightcert=carolCert.der
+
+If the peer certificates are loaded locally then there is no sense in sending
+any certificates to the other end via the IKE Main Mode protocol. Especially
+if self-signed certificates are used which wouldn't be accepted any way by
+the other side. In these cases it is recommended to add
+
+ leftsendcert=never
+
+to the connection definition[s] in order to avoid the sending of the host's
+own certificate. The default value is
+
+ leftsendcert=always.
+
+If a peer certificate contains a subjectAltName extension, then an alternative
+rightid type can be used, as the example "conn sun" shows. If no rightid
+entry is present then the subject distinguished name contained in the
+certificate is taken as the ID.
+
+Using the same rules concerning pathnames that apply to strongSwan's own
+certificates, the following two definitions are also valid for trusted peer
+certificates:
+
+ rightcert=peercerts/carolCert.der
+
+or
+
+ rightcert=/usr/ssl/certs/carolCert.der
+
+
+6. Installing the private key - ipsec.secrets
+ ------------------------------------------
+
+6.1 Loading private key files in PKCS#1 format
+ ------------------------------------------
+
+Besides strongSwan's raw private key format strongSwan has been enabled to
+load RSA private keys in the PKCS#1 file format. The key files can be
+optionally secured with a passphrase.
+
+RSA private key files are declared in /etc/ipsec.secrets using the syntax
+
+ : RSA <my keyfile> "<optional passphrase>"
+
+The key file can be either in base64 PEM-format or binary DER-format. The
+actual coding is detected "automagically" by Pluto. The example
+
+ : RSA moonKey.pem
+
+uses a relative pathname. In this case Pluto will look for the key file
+in the directory
+
+ /etc/ipsec.d/private
+
+As an alternative an absolute pathname can be given as in
+
+ : RSA /usr/ssl/private/moonKey.pem
+
+In both cases make sure that the key files are root readable only.
+
+Often a private key must be transported from the Certification Authority
+where it was generated to the target security gateway where it is going
+to be used. In order to protect the key it can be encrypted with 3DES
+using a symmetric transport key derived from a cryptographically strong
+passphrase.
+
+ openssl genrsa -des3 -out moonKey.pem 1024
+
+Because of the weak security, key files protected by single DES will not
+be accepted by Pluto!!!
+
+Once on the security gateway the private key can either be permanently
+unlocked so that it can be used by Pluto without having to know a
+passphrase
+
+ openssl rsa -in moonKey.pem -out moonKey.pem
+
+or as an option the key file can remain secured. In this case the passphrase
+unlocking the private key must be added after the pathname in
+/etc/ipsec.secrets
+
+ : RSA moonKey.pem "This is my passphrase"
+
+Some CAs distribute private keys embedded in a PKCS#12 file. Since Pluto
+is not able yet to read this format directly, the private key part must
+first be extracted using the command
+
+ openssl pkcs12 -nocerts -in moonCert.p12 -out moonKey.pem
+
+if the key file moonKey.pem is to be secured again by a passphrase, or
+
+ openssl pkcs12 -nocerts -nodes -in moonCert.p12 -out moonKey.pem
+
+if the private key is to be stored unlocked.
+
+
+6.2 Entering passphrases interactively
+ ----------------------------------
+
+On a VPN gateway you would want to put the passphrase protecting the private
+key file right into /etc/ipsec.secrets as described in the previous paragraph,
+so that the gateway can be booted in unattended mode. The risk of keeping
+unencrypted secrets on a server can be minimized by putting the box into a
+locked room. As long as no one can get root access on the machine the private
+keys are safe.
+
+On a mobile laptop computer the situation is quite different. The computer can
+be stolen or the user is leaving it unattended so that unauthorized persons
+can get access to it. In theses cases it would be preferable not to keep any
+passphrases openly in /etc/ipsec.secrets but to prompt for them interactively
+instead. This is easily done by defining
+
+ : RSA moonKey.pem %prompt
+
+Since strongSwan is usually started during the boot process, usually no
+interactive console windows is available which can be used by Pluto to
+prompt for the passphrase. This must be initiated by the user by typing
+
+ ipsec secrets
+
+which actually is an alias for the existing command
+
+ ipsec rereadsecrets
+
+and which causes the prompt
+
+ need passphrase for '/etc/ipsec.d/private/moonKey.pem'
+ Enter:
+
+to appear. If the passphrase was correct and the private key file could be
+successfully decrypted then
+
+ valid passphrase
+
+results. Otherwise the prompt
+
+ invalid passphrase, please try again
+ Enter:
+
+will give you another try. Entering a carriage return will abort the
+the passphrase prompting.
+
+
+6.3 Multiple private keys
+ ---------------------
+
+strongSwan supports multiple private keys. Since the connections defined
+in ipsec.conf can find the correct private key based on the public key
+contained in the certificate assigned by leftcert, default private key
+definitions without specific IDs can be used
+
+ : RSA myKey1.pem "<optional passphrase1>"
+
+ : RSA myKey2.pem "<optional passphrase2>"
+
+
+7. Configuring CA properties - ipsec.conf
+ --------------------------------------
+
+Besides the definition of IPsec connections the ipsec.conf file can also
+be used to configure a few properties of the certification authorities
+needed to establish the X.509 trust chains. The following example shows
+the parameters that are currently available:
+
+ ca strongswan
+ cacert=strongswanCert.pem
+ ocspuri=http://ocsp.strongswan.org:8880
+ crluri=http://crl.strongswan.org/strongswan.crl'
+ crluri2="ldap:///O=Linux strongSwan, C=CH?certificateRevocationList"
+ ldaphost=ldap.strongswan.org
+ auto=add
+
+In a similar way as conn sections are used for connection definitions, an
+arbitrary number of optional ca sections define the basic properties of CAs.
+
+Each ca section is named with a unique label
+
+ ca strongswan
+
+The only mandatory parameter is
+
+ cacert=strongswanCert.pem
+
+which points to the CA certificate which usually resides in the default
+directory /etc/ipsec.d/cacerts/ but could also be retrieved via an absolute
+path name. If the CA certificate is stored on a smartcard then the
+notation
+
+ cacert=%smartcard#<n>
+
+or alternatively
+
+ cacert=%smartcard<optional slot nr>:<key id>
+
+can be used. The selection of smartcard slots is described in more detail
+in section 8.1.
+
+From the certificate the CA's distinguished name and the serial number
+is extracted. If an optional subjectKeyAuthentifier is present then it can
+be used to uniquely identify consecutive generations of CA certificates
+carrying the same distinguished name.
+
+The OCSP URI
+
+ ocspuri=http://ocsp.strongswan.org:8880
+
+allows to define an individual OCSP server per CA. Also up to two additional
+CRL distribution points (CDPs) can be defined
+
+ crluri=http://crl.strongswan.org/strongswan.crl'
+ crluri2="ldap:///O=Linux strongSwan, C=CH?certificateRevocationList"
+
+which are added to any CDPs already present in the received certificates
+themselves. The last parameter
+
+ ldaphost=ldap.strongswan.org
+
+can be used to fill in the actual server name in LDAP CDPs where the host is missing
+as e.g. in the crluri2 above. In future releases this ldaphost parameter might be used
+to retrieve user, host and attribute certificates.
+
+
+With the auto=add statement the ca definition is automatically loaded into Pluto during
+system startup. Setting auto=ignore will ignore the ca section. Additional ca definitions
+can be loaded from ipsec.conf during runtime with the command
+
+ ipsec auto --type ca --add strongswan-sales
+
+and
+
+ ipsec auto --type ca --delete strongswan-sales
+
+deletes the labeled ca entry. And finally the command
+
+ ipsec auto --type ca --replace strongswan
+
+first deletes the old definition in Pluto's memory and then loads the updated version
+from ipsec.conf. Any parameters which appear in several ca definitions can be put in
+a common ca %default section
+
+ ca %default
+ ldaphost=ldap.strongswan.org
+
+
+8. Smartcard support
+ -----------------
+
+8.1 Configuring a smartcard-based connection
+ ----------------------------------------
+
+Defining a smartcard-based connection in ipsec.conf is easy:
+
+ conn sun
+ right=192.168.0.2
+ rightid=@sun.strongswan.org
+ left=%defaultroute
+ leftcert=%smartcard
+ auto=add
+
+In most cases there is a single smartcard reader or cryptotoken and only one
+RSA private key safely stored on the crypto device. Thus usually the entry
+
+ leftcert=%smartcard
+
+which stands for the full notation
+
+ leftcert=%smartcard#1
+
+is sufficient where the first certificate/private key object enumerated by
+the PKCS#11 module is used. If several certificate/private key objects are
+present then the nth object can be selected using
+
+ leftcert=%smartcard#<n>
+
+The command
+
+ ipsec listcards
+
+gives an overview over all certificate objects made available by the PKCS#11
+module.CA certificates are automatically available as trust anchors.
+
+As an alternative the certificate ID and/or the slot number defined by
+the PKCS#11 standard can be specified using the notation
+
+ leftcert=%smartcard<optional slot nr>:<key id in hex format>
+
+Thus
+
+ leftcert=%smartcard:50
+
+will look in all available slots for ID 0x50 starting with the first slot
+(usually slot 0) whereas
+
+ leftcert=%smartcard4:50
+
+will directly check slot 4 (which is usually the first slot on the second
+reader/token when using the OpenSC library) for a key with ID 0x50.
+
+
+8.2 Entering the PIN code
+ ---------------------
+
+Since the smartcard signing operation needed to sign the hash with the
+RSA private key during IKE Main Mode is protected by a PIN code,
+the secret PIN must be made available to Pluto.
+
+For gateways that must be able to start IPsec tunnels automatically in
+unattended mode after a reboot, the secret PIN can be stored statically
+in ipsec.secrets
+
+ : PIN %smartcard "12345678"
+
+or with the general notation
+
+ : PIN %smartcard#<n> "<PIN code>"
+
+or alternatively
+
+ : PIN %smartcard<optional slot nr>:<key id> "<PIN code>"
+
+On personal notebooks that could get stolen, you wouldn't want to store
+your PIN in ipsec.secrets. Thus the alternative form
+
+ : PIN %smartcard %prompt
+
+will prompt you for the PIN when you start up the first IPsec connection
+using the command
+
+ ipsec up sun
+
+The auto command calls the whack function which in turn communicates with
+Pluto over a socket. Since the whack function call is executed from a command
+window, Pluto can prompt you for the PIN over this socket connection.
+Unfortunately roadwarrior connections which just wait passively for peers
+cannot be initiated via the command window:
+
+ conn rw
+ right=%any
+ left=%defaultroute
+ leftcert=%smartcard4:50
+ auto=add
+
+But if there is a corresponding entry
+
+ : PIN %smartcard4:50 %prompt
+
+in ipsec.secrets, then the standard command
+
+ ipsec rereadsecrets
+
+or the alias
+
+ ipsec secrets
+
+can be used to enter the PIN code for this connection interactively.
+
+The command
+
+ ipsec listcards
+
+can be executed at any time to check the current status of the PIN code[s].
+
+
+8.3 PIN-pad equipped smartcard readers
+ ----------------------------------
+
+Smartcard readers with an integrated PIN-pad offer an increased security
+level because the PIN entry cannot be sniffed on the host computer e.g.
+by a surrepticiously installed key logger. In order to tell pluto not to
+prompt for the PIN on the host itself, the entry
+
+ : PIN %smartcard:50 %pinpad
+
+can be used in ipsec.secrets. Because the key pad does not cache the PIN in
+the smartcard reader, it must be entered for every PKCS #11 session login.
+By default pluto does a session logout after every RSA signature. In order
+to avoid the repeated entry of the PIN code during the periodic IKE main
+mode rekeyings, the following parameter can be set in the config setup
+section of ipsec.conf:
+
+ config setup
+ pkcs11keepstate=yes
+
+The default setting is pkcs11keepstate=no.
+
+
+8.4 Configuring a smartcard with pkcsc15-init
+ -----------------------------------------
+
+strongSwan's smartcard solution is based on the PKCS#15 "Cryptographic Token
+Information Format Standard" fully supported by OpenSC library functions.
+Using the command
+
+ pkcs15-init --erase-card --create-pkcs15
+
+a fresh PKCS#15 file structure is created on a smartcard or cryptotoken.
+With the next command
+
+ pkcs15-init --auth-id 1 --store-pin --pin "12345678" --puk "87654321"
+ --label "my PIN"
+
+a secret PIN code with auth-id 1 is stored in an unretrievable location on
+the smart card. The PIN will protect the RSA signing operation. If the PIN
+is entered incorrectly more than three times the smartcard will be locked
+and the PUK code can be used to unlock the card again.
+
+Next the RSA private key is transferred to the smartcard
+
+ pkcs15-init --auth-id 1 --store-private-key myKey.pem [--id 45]
+
+By default the PKCS#15 smartcard record will be assigned the id 45.
+Using the --id option multiple key records can be stored on a smartcard.
+
+At last we load the matching X.509 certificate onto the smartcard
+
+ pkcs15-init --auth-id 1 --store-certificate myCert.pem [--id 45]
+
+The pkcs15-tool can now be used to verify the contents of the smartcard.
+
+ pkcs15-tool --list-pins --list-keys --list-certificates
+
+If everything is ok then you are ready to use the generated PKCS#15
+structure with strongSwan.
+
+8.5 PKCS#11 proxy functions
+ -----------------------
+
+ With the setting pkcs11keepstate=yes some PKCS#11 implementations
+ (e.g. OpenSC) will lock the access to the smartcard as soon as pluto has
+ opened a session and will thus prevent other application from sharing the
+ smartcard resource. In order to solve this locking problem, strongSwan
+ offers a PKCS#11 proxy service making use of the whack socket communication
+ channel. The setting
+
+ config setup
+ pkcs11proxy=yes
+
+will enable the proxy mode that is disabled by default.
+
+Currently two smartcard operations are supported: RSA encryption and
+RSA decryption. The notation is as follows:
+
+ ipsec scdecrypt <encrypted data>
+ [--inbase 16|hex|64|base64|256|text|ascii]
+ [--outbase 16|hex|64|base64|256|text|ascii]
+ [--keyid <id>]
+
+The default settings for inbase and outbase is hexadecimal.
+Thus the simplest call has the form
+
+ ipsec scdecrypt bb952b71920094ce0696ef9b8b26...12e6
+
+and the returned result might be a decrypted 128 bit AES key
+
+ 000 8836362e030e6707c32ffaa0bdad5540
+
+The leading three characters represent the return code of the whack channel
+with 000 signifying that no error has occured. Here is another example showing
+the use of the inbase and outbase attributes
+
+ ipsec scdecrypt m/ewDnTs0k...woE= --inbase base64 --outbase text
+
+where the result has the form
+
+ 000 This is a secret
+
+By default the first RSA private key found by the PKCS#11 enumeration is
+used. If a different key should be selected then the notation introduced
+in sections 8.1 and 8.2 can be used:
+
+ --keyid %smartcard:50
+ --keyid %smartcard4:50
+ --keyid %smartcard#3
+
+with --keyid %smartcard#1 being the default. If supported by the smartcard
+and PKCS#11 library RSA encryption can be used with the notation
+
+ ipsec scencrypt <plaintext data>
+ [--inbase 16|hex|64|base64|256|text|ascii]
+ [--outbase 16|hex|64|base64|256|text|ascii]
+ [--keyid <id>]
+
+with the example
+
+ ipsec scencrypt "This is a secret" --inbase ascii --outbase 64
+
+returning the expected output
+
+ 000 m/ewDnTs0k...woE=
+
+
+9. Configuring the clients
+ -----------------------
+
+9.1 strongSwan
+ ----------
+
+A strongSwan to strongSwan connection is symmetrical. Any of the four defined
+ID types can be used, even different types on either end of the connection,
+although this wouldn't make much sense.
+
++--------------------------------------------------------------+
+| Connection Definition ID type subjectAltName |
+|--------------------------------------------------------------|
+| rightid (strongSwan) DER_ASN1_DN - |
+| FQDN DNS: |
+| USER_FQDN email: |
+| IPV4_ADDR IP: |
+|--------------------------------------------------------------|
+| leftid (strongSwan) DER_ASN1_DN - |
+| FQDN DNS: |
+| USER_FQDN email: |
+| IPV4_ADDR IP: |
++--------------------------------------------------------------+
+
+
+9.2 PGPnet
+ ------
+
+Use the file peerCert.p12 to import PGPnet's X.509 certificate, the CA
+certificate, plus the encrypted private key in binary PKCS#12 format into the
+PGPkey tool. You will be prompted for the passphrase securing the private key.
+
+Use the file myCert.pem to import the X.509 certificate of the strongSwan
+security gateway into the PGPkey tool. The PGPkeyTool does not accept X.509
+certificates in binary DER format, so it must be imported in base64 format:
+
+ -----BEGIN CERTIFICATE-----
+ M...
+
+ ...
+ -----END CERTIFICATE-----
+
+Make sure that there is no human-readable listing of the X.509 certificate in
+front of the line
+
+ -----BEGIN CERTIFICATE-----
+
+otherwise PGPnet will refuse to load the *.PEM file. Any surplus lines can
+either be deleted by loading the certificate into a text editor or you can
+apply the command
+
+ openssl x509 -in myCert.pem -out myCert.pem
+
+to achieve the same effect.
+
+With authentication based on X.509 certificates, PGPnet always sends the ID
+type DER_ASN1_DN, therefore rightid in the connection definition of the
+strongSwan security gateway must be an ASN.1 distinguished name.
+
+In the receiving direction PGPnet accepts all four ID types from strongSwan.
+
++--------------------------------------------------------------+
+| Connection Definition ID type subjectAltName |
+|--------------------------------------------------------------|
+| rightid (PGPnet) DER_ASN1_DN - |
+|--------------------------------------------------------------|
+| leftid (strongSwan) DER_ASN1_DN - |
+| FQDN DNS: |
+| USER_FQDN email: |
+| IPV4_ADDR IP: |
++--------------------------------------------------------------+
+
+
+9.3 SafeNet/Soft-PK/Soft-Remote
+ ---------------------------
+
+SafeNet/Soft-PK and SafeNet/Soft-Remote can be configured to send their
+identity either as DER_ASN1_DN, IPV4_ADDR, FQDN, or USER_FQDN.
+In the receiving direction SafeNet/Soft-PK and SafeNet/Soft-Remote
+accept all four ID types coming from strongSwan.
+
++--------------------------------------------------------------+
+| Connection Definition ID type subjectAltName |
+|--------------------------------------------------------------|
+| rightid (SafeNet/Soft-PK) DER_ASN1_DN - |
+| FQDN DNS: |
+| USER_FQDN email: |
+| IPV4_ADDR IP: |
+|--------------------------------------------------------------|
+| leftid (strongSwan) DER_ASN1_DN - |
+| FQDN DNS: |
+| USER_FQDN email: |
+| IPV4_ADDR IP: |
++--------------------------------------------------------------+
+
+
+9.4 SSH Sentinel
+ ------------
+
+SSH Sentinel sends its identity as DER_ASN1_DN if the subjectAltName field of
+its certificate is empty. If a subjectAltName field is present, then the
+corresponding type IPV4_ADDR, FQDN, or USER_FQDN is automatically chosen.
+With several subjectAltName entries, the precedence of the different ID types
+is not quite clear. In the receiving direction SSH Sentinel accepts all four
+ID types from strongSwan.
+
++--------------------------------------------------------------+
+| Connection Definition ID type subjectAltName |
+|--------------------------------------------------------------|
+| rightid (SSH Sentinel) DER_ASN1_DN - |
+| FQDN DNS: |
+| USER_FQDN email: |
+| IPV4_ADDR IP: |
+|--------------------------------------------------------------|
+| leftid (strongSwan) DER_ASN1_DN - |
+| FQDN DNS: |
+| USER_FQDN email: |
+| IPV4_ADDR IP: |
++--------------------------------------------------------------+
+
+
+9.5 Windows 2000/XP
+ ---------------
+
+Windows 2000 and Windows XP always send the ID type DER_ASN1_DN,
+therefore rightid in the connection definition of the strongSwan
+security gateway must be an ASN.1 distinguished name.In the
+receiving direction Windows 2000/XP accepts all four ID types
+from strongSwan.
+
++--------------------------------------------------------------+
+| Connection Definition ID type subjectAltName |
+|--------------------------------------------------------------|
+| rightid (Windows 2000/XP) DER_ASN1_DN - |
+|--------------------------------------------------------------|
+| leftid (strongSwan) DER_ASN1_D - |
+| FQDN DNS: |
+| USER_FQDN email: |
+| IPV4_ADDR IP: |
++--------------------------------------------------------------+
+
+
+10. Monitoring functions
+ --------------------
+
+strongSwan offers the following monitoring functions:
+
+
+ ipsec listalgs
+
+lists all IKE and ESP cryptographic algorithms that are currently
+registered with strongSwan.
+
+The a listing has the following form:
+
+ List of registered IKE Encryption Algorithms:
+
+ #3 OAKLEY_BLOWFISH_CBC, blocksize: 64, keylen: 128-128-256
+ #5 OAKLEY_3DES_CBC, blocksize: 64, keylen: 192-192-192
+ #7 OAKLEY_AES_CBC, blocksize: 128, keylen: 128-128-256
+ #65004 OAKLEY_SERPENT_CBC, blocksize: 128, keylen: 128-128-256
+ #65005 OAKLEY_TWOFISH_CBC, blocksize: 128, keylen: 128-128-256
+ #65289 OAKLEY_TWOFISH_CBC_SSH, blocksize: 128, keylen: 128-128-256
+
+ List of registered IKE Hash Algorithms:
+
+ #1 OAKLEY_MD5, hashsize: 128
+ #2 OAKLEY_SHA, hashsize: 160
+ #4 OAKLEY_SHA2_256, hashsize: 256
+ #6 OAKLEY_SHA2_512, hashsize: 512
+
+ List of registered IKE DH Groups:
+
+ #2 OAKLEY_GROUP_MODP1024, groupsize: 1024
+ #5 OAKLEY_GROUP_MODP1536, groupsize: 1536
+ #14 OAKLEY_GROUP_MODP2048, groupsize: 2048
+ #15 OAKLEY_GROUP_MODP3072, groupsize: 3072
+ #16 OAKLEY_GROUP_MODP4096, groupsize: 4096
+ #17 OAKLEY_GROUP_MODP6144, groupsize: 6144
+ #18 OAKLEY_GROUP_MODP8192, groupsize: 8192
+
+ List of registered ESP Encryption Algorithms:
+
+ #3 ESP_3DES, blocksize: 64, keylen: 168-168
+ #7 ESP_BLOWFISH, blocksize: 64, keylen: 96-128
+ #12 ESP_AES, blocksize: 128, keylen: 128-256
+ #252 ESP_SERPENT, blocksize: 128, keylen: 128-256
+ #253 ESP_TWOFISH, blocksize: 128, keylen: 128-256
+
+ List of registered ESP Authentication Algorithms:
+
+ #1 AUTH_ALGORITHM_HMAC_MD5, keylen: 128-128
+ #2 AUTH_ALGORITHM_HMAC_SHA1, keylen: 160-160
+ #5 AUTH_ALGORITHM_HMAC_SHA2_256, keylen: 256-256
+ #7 AUTH_ALGORITHM_HMAC_SHA2_512, keylen: 512-512
+
+
+The command
+
+ ipsec listpubkeys [--utc]
+
+lists all public keys currently installed in the chained list of public
+keys. These keys were statically loaded from ipsec.conf or aquired either
+from received certificates or retrieved from secure DNS servers using
+opportunistic mode.
+
+The public key listing has the following form:
+
+ Feb 11 14:40:18 2005, 2048 RSA Key AwEAAa+uL,
+ until Sep 09 13:17:25 2009 ok
+ ID_FQDN '@moon.strongswan.org'
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ serial: '03'
+ Feb 11 14:40:18 2005, 2048 RSA Key AwEAAa+uL,
+ until Sep 09 13:17:25 2009 ok
+ ID_DER_ASN1_DN 'C=CH, O=Linux strongSwan, CN=moon.strongswan.org'
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ serial: '03'
+ Feb 11 13:36:53 2005, 2048 RSA Key AwEAAbgbh,
+ until Dec 31 22:43:18 2009 ok
+ ID_USER_FQDN 'carol@strongswan.org'
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ serial: '0a'
+
+It consists of
+
+ - the date the public key was installed either in local time or UTC (--utc)
+ - the modulus size of the RSA key in bits
+ - a keyID consisting of 9 base64 symbols representing the public exponent
+ and the most significant bits of the modulus
+ - the expiration date of the public key (extracted from the certificate)
+ - the type and value of the ID associated with the public key.
+ - the issuer of the certificate the public key was extracted from.
+ - the serial number of the certificate the public key was extracted from.
+
+A public key can be associated with several IDs, e.g. using subjectAltNames
+in certificates and an ID can possess several public keys, e.g. retrieved
+from a secure DNS server.
+
+
+The command
+
+ ipsec listcerts [--utc]
+
+lists all local certificates, both strongSwan's own and those of
+trusted peer loaded via leftcert and rightcert, respectively.
+
+The output has the form
+
+ Feb 11 13:36:47 2005, count: 4
+ subject: 'C=CH, O=Linux strongSwan, CN=moon.strongswan.org'
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ serial: 03
+ pubkey: 2048 RSA Key AwEAAa+uL, has private key
+ validity: not before Sep 10 13:17:25 2004 ok
+ not after Sep 09 13:17:25 2009 ok
+ subjkey: e5:e4:10:87:6c:2a:c4:be:ad:85:49:42:a6:de:76:58:30:3a:9f:c1
+ authkey: 5d:a7:dd:70:06:51:32:7e:e7:b6:6d:b3:b5:e5:e0:60:ea:2e:4d:ef
+ aserial: 00
+
+and shows
+
+ - the date the certificate was installed either in local time or UTC (--utc)
+ - the count shows how many connections refer to this certificate
+ - the subject of the certificate
+ - the issuer of the certificate
+ - the serial number of the certificate
+ - the size and keyid of the RSA public key contained in the certificate.
+ the label "has private key" indicates that a matching RSA private key
+ has been found, defined or loaded in ipsec.secrets.
+ - the label "on smartcard" indicates that the certificate was loaded from
+ a smartcard or cryptotoken and that most probably a matching RSA private
+ key also resides on-card.
+ - the validity of the CA certificate expressed either in local time or
+ UTC (--utc). The validity is checked automatically resulting either
+ in an "ok" message or a "fatal" error message.
+ - the optional subjectKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the certificate's public key.
+ - the optional authorityKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the public key of the issuer who signed the certificate.
+ - the serial number of the issuer's certificate.
+
+
+The command
+
+ ipsec listcacerts [--utc]
+
+lists all CA certificates that have been either been loaded from the directory
+/etc/ipsec.d/cacerts/ or received via the IKE protocol. The output has the form
+
+ Feb 11 13:36:52 2005, count: 1
+ subject: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ serial: 00
+ pubkey: 2048 RSA Key AwEAAb/yX
+ validity: not before Sep 10 13:01:45 2004 ok
+ not after Sep 08 13:01:45 2014 ok
+ subjkey: 5d:a7:dd:70:06:51:32:7e:e7:b6:6d:b3:b5:e5:e0:60:ea:2e:4d:ef
+ authkey: 5d:a7:dd:70:06:51:32:7e:e7:b6:6d:b3:b5:e5:e0:60:ea:2e:4d:ef
+ aserial: 00
+
+and shows
+
+ - the date the CA certificate was installed either in local time or UTC (--utc)
+ - the count is always set to 1
+ - the subject of the CA certificate
+ - the issuer of the CA certificate
+ - the serial number of the CA certificate
+ - the size and keyid of the RSA public key contained in the certificate.
+ - the validity of the CA certificate expressed either in local time or
+ UTC (--utc). The validity is checked automatically resulting either
+ in an "ok" message or a "fatal" error message.
+ - the optional subjectKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the CA certificate's public key.
+ - the optional authorityKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the public key of the issuer who signed the CA certificate.
+ For Root CA certificates the authorityKeyIdentifier and subjectKeyIdentifier
+ fields must be equal.
+ - the serial number of the issuer's certificate.
+
+
+The command
+
+ ipsec listaacerts [--utc]
+
+lists all Authorization Authority certificates that have been loaded from
+the directory /etc/ipsec.d/aacerts/.
+The output has the form
+
+ Dec 20 13:29:55 2004, count: 1
+ subject: 'C=CH, O=strongSec GmbH, CN=strongSec Authorization Authority'
+ issuer: 'C=CH, O=strongSec GmbH, CN=strongSec Root CA'
+ serial: 0f
+ pubkey: 2048 RSA Key AwEAAfazH
+ validity: not before Aug 24 13:41:56 2003 ok
+ not after Aug 23 13:41:56 2005 ok
+ subjkey: 56:89:b9:28:c9:1b:a0:00:7f:50:9d:ec:28:75:23:c1:1e:d1:dd:90
+ authkey: af:80:d5:c6:02:1c:96:78:b3:85:a5:65:a2:23:fd:ad:cf:e2:55:b2
+ aserial: 00
+
+and shows
+
+ - the date the AA certificate was installed either in local time or UTC (--utc)
+ - the count is always set to 1
+ - the subject of the AA certificate
+ - the issuer of the AA certificate
+ - the serial number of the AA certificate
+ - the size and keyid of the RSA public key contained in the certificate.
+ - the validity of the AA certificate expressed either in local time or
+ UTC (--utc). The validity is checked automatically resulting either
+ in an "ok" message or a "fatal" error message.
+ - the optional subjectKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the AA certificate's public key.
+ - the optional authorityKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the public key of the issuer who signed the AA certificate.
+ - the serial number of the issuer's certificate.
+
+
+The command
+
+ ipsec listocspcerts [--utc]
+
+lists all OCSO signer certificates that have been either loaded from
+/etc/ipsec.d/ocspcerts/ or have been received included in the OCSP server
+response. The output has the form
+
+ Feb 09 22:56:17 2005, count: 1
+ subject: 'C=CH, O=Linux strongSwan, OU=OCSP, CN=ocsp.strongswan.org'
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ serial: 09
+ pubkey: 2048 RSA Key AwEAAaonT
+ validity: not before Nov 19 17:29:28 2004 ok
+ not after Nov 18 17:29:28 2009 ok
+ subjkey: 88:07:0a:b8:ae:c7:c1:07:5c:be:68:6a:c4:a5:7f:81:1f:37:b5:56
+ authkey: 5d:a7:dd:70:06:51:32:7e:e7:b6:6d:b3:b5:e5:e0:60:ea:2e:4d:ef
+ aserial: 00
+
+and shows
+
+ - the date the OCSP signer certificate was installed either in local time
+ or UTC (--utc)
+ - the count is always set to 1
+ - the subject of the OCSP signer certificate
+ - the issuer of the OCSP signer certificate
+ - the serial number of the OCSP signer certificate
+ - the size and keyid of the RSA public key contained in the certificate.
+ - the validity of the OCSP signer certificate expressed either in local time
+ or UTC (--utc). The validity is checked automatically resulting either
+ in an "ok" message or a "fatal" error message.
+ - the optional subjectKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the OCSP signer certificate's public key.
+ - the optional authorityKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the public key of the issuer who signed the OCSP certificate.
+ - the serial number of the issuer's certificate.
+
+
+The command
+
+ ipsec listacerts [--utc]
+
+lists all X.509 attribute certificates that have been loaded from the directory
+/etc/ipsec.d/acerts/.
+The output has the form
+
+ Dec 20 13:29:56 2004
+ holder: 'C=CH, O=strongSec GmbH, CN=Andreas Steffen'
+ hissuer: 'C=CH, O=strongSec GmbH, CN=strongSec Root CA'
+ hserial: 1e
+ groups: Research, Sales
+ issuer: 'C=CH, O=strongSec GmbH, CN=strongSec Authorization Authority'
+ serial: 2c
+ validity: not before Dec 19 14:51:38 2004 ok
+ not after Dec 20 14:51:38 2004 fatal (expired)
+ authkey: 56:89:b9:28:c9:1b:a0:00:7f:50:9d:ec:28:75:23:c1:1e:d1:dd:90
+ aserial: 0f
+
+and shows
+
+ - the date the attribute certificate was installed either in local time
+ or UTC (--utc)
+ - the holder of the attribute certificate
+ - the issuer of holder's certificate
+ - the serial number of the holder's certificate
+ - the group attributes
+ - the issuing Authorization Authority of the attribute certificate
+ - the serial number of the attribute certificate
+ - the validity of the attribute certificate expressed either in local time or
+ UTC (--utc). The validity is checked automatically resulting either
+ in an "ok" message or a "fatal" error message.
+ - an authorityKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the public key of the issuing Authorization Authority
+ - the serial number of the AA certificate.
+
+
+The command
+
+ ipsec listgroups [--utc]
+
+lists all group attributes either defined in right|leftgroups statements
+in ipsec.conf or contained in loaded X.509 attribute certificates.
+The output has the form
+
+ Dec 20 13:29:55 2004, count: 4
+ Research
+ Dec 20 13:30:04 2004, count: 1
+ Research New York
+ Dec 20 13:29:55 2004, count: 3
+ Sales
+
+and shows
+
+ - the date the group attribute was first installed either in local time
+ or UTC (--utc)
+ - the count shows how many times the attribute is used
+ - the group name
+
+
+The command
+
+ ipsec listcainfos [--utc]
+
+lists the properties defined by the ca definition sections in ipsec.conf.
+The output has the form
+
+ Jun 08 22:31:37 2004, "strongswan"
+ authname: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ ldaphost: 'ldap.strongswan.org'
+ ocspuri: 'http://ocsp.strongswan.org:8880'
+ distPts: 'http://crl.strongswan.org/strongswan.crl'
+ 'ldap:///O=Linux strongSwan, C=CH?certificateRevocationList'
+ authkey: 5d:a7:dd:70:06:51:32:7e:e7:b6:6d:b3:b5:e5:e0:60:ea:2e:4d:ef
+ aserial: 00
+
+and shows
+
+ - the date the CA definition was loaded either in local time or UTC (--utc)
+ - the name of the ca section
+ - the distinguished name of the CA
+ - an optional default ldap host for the CA
+ - an optional OCSP URI
+ - a maximum of two optional CRL distribution points
+ - the optional authorityKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the public key of the CA.
+ - the serial number of the CA.
+
+
+The command
+
+ ipsec listcrls [--utc]
+
+lists all CRLs that have been loaded from /etc/ipsec.d/crls/.
+The output has the form
+
+ Feb 11 13:37:00 2005, revoked certs: 1
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ distPts: 'http://crl.strongswan.org/strongswan.crl'
+ updates: this Feb 08 07:46:29 2005
+ next Mar 10 07:46:29 2005 ok
+ authkey: 5d:a7:dd:70:06:51:32:7e:e7:b6:6d:b3:b5:e5:e0:60:ea:2e:4d:ef
+ aserial: 00
+
+and shows
+
+ - the date the CRL was installed either in local time or UTC (--utc)
+ - the number revoked certificates
+ - the issuer of the CRL
+ - the URLs of the distribution points where the CRL can be fetched from.
+ - the dates when the CRL was issued and when the next update
+ is expected, respectively, expressed either in local time or
+ UTC (--utc). It is automatically checked if the next update
+ deadline has passed, resulting either in an "ok" message, a
+ a "warning" message when strictcrlpolicy=no or a "fatal" message when
+ strictcrlpolicy=yes.
+ - the optional authorityKeyIdentifier extension which is a 20 byte SHA-1 hash
+ over the public key of the issuer who signed the CRL. This extension is
+ present in version 2 CRLs, only.
+ - the serial number of the issuer's certificate.
+
+
+The command
+
+
+ ipsec listocsp [--utc]
+
+lists the contents of the OCSP response cache. The output has the form
+
+ issuer: 'C=CH, O=Linux strongSwan, CN=strongSwan Root CA'
+ uri: 'http://ocsp.strongswan.org:8880'
+ authname: 13:9d:a0:9e:f4:32:ab:8f:e2:89:56:67:fa:d0:d4:e3:35:86:71:b9
+ authkey: 5d:a7:dd:70:06:51:32:7e:e7:b6:6d:b3:b5:e5:e0:60:ea:2e:4d:ef
+ aserial: 00
+ Feb 09 22:56:17 2005, until Feb 09 23:01:17 2005 warning (expires in 4 minutes)
+ serial: 0a, good
+
+and shows
+
+ - the distinguished name of the CA handled by the OCSP server
+ - the http URI of the OCSP server.
+ - the 20 byte SHA-1 hash of the CA's distinguished name
+ - the 20 byte SHA-1 hash of the CA's public key
+ - the serial number of the CA's certificate
+ - a certificate status list showing
+ - the time the OCSP status was received
+ - an optional nextUpdate deadline (if missing the OCSP status will be
+ onetime with a lifetime of 2 minutes only).
+ - the serial number of the certificate
+ - the status of the certificate (good, revoked, unknown)
+
+
+The command
+
+ ipsec listcards [--utc]
+
+lists all smartcard records that are currently in use by Pluto.
+The output has the form
+
+ Aug 17 16:47:59 2005, #1, count: 6
+ slot: 0, session closed, logged out, has valid pin
+ id: 45
+ label: 'strongSwan'
+ subject: 'C=CH, O=Linux strongSwan, CN=carol@strongswan.org'
+
+with pkcs11keepstate=no and
+
+ Aug 17 16:47:59 2005, #1, count: 6
+ slot: 0, session opened, logged in, has pin pad
+ id: 45
+ label: 'strongSwan'
+ subject: 'C=CH, O=Linux strongSwan, CN=carol@strongswan.org'
+
+with pkcs11keepstate=yes and shows
+
+- the date the certificate was read from the smartcard record
+- the certificate objects are numbered starting from #1
+- the count shows how many connections and secret pin entries point
+ to the smartcard record
+- the PKCS #11 slot number
+- the PKCS #11 session state: closed | opened
+- the PKCS #11 session login state: logged out | logged in
+- the status of the PIN: no pin | valid pin | invalid pin | pin pad
+- the ID of the certificate object
+- the label of the certificate object
+- the subject distinguished name of the certificate
+
+
+The command
+
+ ipsec auto --listall [--utc]
+
+is equivalent to
+
+ ipsec listalgs
+ ipsec listpubkeys [--utc]
+ ipsec listcerts [--utc]
+ ipsec listcacerts [--utc]
+ ipsec listaacerts [--utc]
+ ipsec listocspcerts [--utc]
+ ipsec listacerts [--utc]
+ ipsec listgroups [--utc]
+ ipsec listcainfos [--utc]
+ ipsec listcrls [--utc]
+ ipsec listocsp [--utc]
+ ipsec listcards [--utc]
+
+
+11. Firewall support functions
+ --------------------------
+
+
+11.1 Environment variables in the updown script
+ ------------------------------------------
+
+strongSwan makes the following environment variables available
+in the updown script indicated by the leftupdown option:
+
++------------------------------------------------------------------+
+| Variable Example Comment |
+|------------------------------------------------------------------|
+| $PLUTO_PEER_ID carol@strongswan.org USER_FQDN (1) |
+|------------------------------------------------------------------|
+| $PLUTO_PEER_PROTOCOL 17 udp (2) |
+|------------------------------------------------------------------|
+| $PLUTO_PEER_PORT 68 bootpc (3) |
+|------------------------------------------------------------------|
+| $PLUTO_PEER_CA C=CH, O=ACME, CN=Sales CA (4) |
+|------------------------------------------------------------------|
+| $PLUTO_MY_ID @moon.strongswan.org FQDN (1) |
+|------------------------------------------------------------------|
+| $PLUTO_MY_PROTOCOL 17 udp (2) |
+|------------------------------------------------------------------|
+| $PLUTO_MY_PORT 67 bootps (3) |
++------------------------------------------------------------------+
+
+(1) $PLUTO_PEER_ID/$PLUTO_MY_ID contain the IDs of the two ends
+ of an established connection. In our examples these
+ correspond to the strings defined by rightid and leftid,
+ respectively.
+
+(2) $PLUTO_PEER_PROTOCOL/$PLUTO_MY_PROTOCOL contain the protocol
+ defined by the rightprotoport and leftprotoport options,
+ respectively. Both variables contain the same protocol value.
+ The variables take on the value '0' if no protocol has been defined.
+
+(3) $PLUTO_PEER_PORT/$PLUTO_MY_PORT contain the ports defined by
+ the rightprotoport and leftprotoport options, respectively.
+ The variables take on the value '0' if no port has been defined.
+
+(4) $PLUTO_PEER_CA contains the distinguished name of the CA that
+ issued the peer's certificate.
+
+
+11.2 Automatic insertion and deletion of iptables firewall rules
+ -----------------------------------------------------------
+
+Starting with strongswan-2.7.0, the default _updown script automatically inserts
+and deletes dynamic iptables firewall rules upon the establishment or teardown,
+respectively, of an IPsec security association. This new feature is activated
+with the line
+
+ leftfirewall=yes
+
+and can be used when the following prerequisites are fulfilled:
+
+ - Linux 2.4.x kernel, KLIPS IPsec stack, and arbitrary iptables version.
+ Filtering of tunneled traffic is based on ipsecN interfaces.
+
+ - Linux 2.4.16 kernel or newer, native NETKEY IPsec stack, and
+ iptables-1.3.5 or newer. Filtering of tunneled traffic is based on
+ IPsec policy matching rules.
+
+If you define a local client subnet with a netmask larger than /32 behind
+the gateway then the automatically inserted FORWARD iptables rules will
+not allow to access the internal IP address of the host although it is
+part of the client subnet definition. If you want additional INPUT and
+OUTPUT iptables rules to be inserted, so that the host itself can be accessed
+then add the following line:
+
+ lefthostaccess=yes
+
+The _updown script also features a logging facility which will register the
+creation (+) and the expiration (-) of each successfully established VPN
+connection in a special syslog file in the following concise and easily
+readable format:
+
+Jul 19 18:58:38 moon vpn:
+ + @carol.strongswan.org 192.168.0.100 -- 192.168.0.1 == 10.1.0.0/16
+Jul 19 22:15:17 moon vpn:
+ - @carol.strongswan.org 192.168.0.100 -- 192.168.0.1 == 10.1.0.0/16
+
+
+11.3 Sample Linux 2.6 updown script for iptables < 1.3.5
+ ---------------------------------------------------
+
+If you are using a Linux 2.6 kernel older than 2.6.16 or an iptables version
+older than 1.3.5 then the IPsec policy matching rules will not be available.
+In order to make sure that only tunneled packets are accepted, a mark can be
+set on incoming ESP packets. This "ESP" mark will be retained on the
+decapsulated packet so that iptables rules inserted by the updown script can
+check on the presence of this mark. For this purpose the template located in
+
+ programs/_updown_espmark
+
+can be used. Store a copy of _updown_espmark e.g. in /etc/ipsec.updown and load
+the script with the line
+
+ leftupdown=/etc/updown.ipsec.
+
+In addition for the dynamic updown script to work the following static iptables rules
+must be applied:
+
+ iptables -t mangle -A INPUT -p 50 -j MARK --set-mark 50
+
+
+12. Authentication with raw RSA public keys
+ ---------------------------------------
+
+FreeS/WAN, as it is available from www.freeswan.org does public key
+authentication with raw RSA public keys that are directly defined in
+/etc/ipsec.conf
+
+ rightrsasigkey=0sAq4c....
+
+When version 1.x of standard FreeS/WAN receives a certificate request (CR),
+it immediately drops the negotiation because it does not know how to answer
+the request. As a workaround strongSwan does not send a CR if the RSA
+key has been statically loaded using [right/left]rsasigkey. A problem
+remains with roadwarriors initiating a connection. Since strongSwan
+does not know the identity of the initiating peer in advance, it will always
+send a CR, causing the rupture of the IKE negotiation if the peer is a
+version 1.x FreeS/WAN host. To circumvent this problem the configuration
+parameter 'nocrsend' can be set in the config setup section of /etc/ipsec.conf:
+
+ config setup:
+ nocrsend=yes
+
+With this entry no certificate request is sent in any connection.
+The default setting is nocrsend=no.
+
+
+13. Authentication with OpenPGP certificates
+ ----------------------------------------
+
+strongSwan also supports RSA based authentication using OpenPGP
+certificates and OpenPGP V3 fingerprints used as an KEY_ID identifier.
+
+
+13.1 OpenPGP certificates
+ --------------------
+
+OpenPGP certificates containing RSA public keys can now directly be loaded
+in ASCII armored PGP format using the leftcert and rightcert parameters
+in /etc/ipsec.conf:
+
+ conn pgp
+ right=%any
+ righcert=peerCert.asc
+ left=%defaultroute
+ leftcert=gatewayCert.asc
+
+The peer certificate must be stored locally (the default directory is
+/etc/ipsec.d/certs) since currently no trust can be established for
+PGP certificates received from a peer via the IKE protocol.
+
+
+13.2 OpenPGP private keys
+ --------------------
+
+PGP private keys in unencrypted form can now directly be loaded in ASCII
+armored PGP format via an entry in /etc/ipsec.secrets:
+
+ : RSA gatewayKey.asc
+
+Existing IDEA-encrypted RSA private keys can be unlocked with GnuPG and
+the IDEA extension (see http://www.gnupg.org/gph/en/pgp2x.html) using
+the commands
+
+ gpg --import gatewayCert.asc
+
+ gpg --allow-secret-key-import --import gatewayKey.asc
+
+ gpg --edit-key <gateway ID>
+ > passwd #change to empty password
+ > save
+
+ gpg -a --export-secret-key <gateway ID> gatewayKey.asc
+
+
+13.3 Monitoring functions
+ --------------------
+
+The command ipsec listcerts shows all loaded PGP certificates
+in the following format:
+
+ Aug 28 09:51:55 2002, count: 1
+ fingerprint: 0x1ccfca12d93467ffa9d5093d87a465dc
+ pubkey: 1024 RSA Key ARHso6uKQ
+ created: Aug 27 08:51:39 2002
+ until: --- -- --:--:-- ---- ok (expires never)
+
+The entries are
+
+ - the date the certificate was loaded either in local time or UTC (--utc)
+ - the V3 fingerprint consisting of the 16 byte MD5 hash of the public key
+ which is used as an ID of type KEY_ID
+ - the modulus size of the RSA key in bits
+ - a keyID consisting of 9 base64 symbols representing the public exponent
+ and the most significant bits of the modulus
+ - the creation date of the public key (extracted from the certificate)
+ - the optional expiration date of the public key (extracted from the
+ certificate)
+
+
+13.4 Suppression of certificate request messages
+ -------------------------------------------
+
+PGPnet configured to work with OpenPGP certificates aborts the IKE
+negotiation when it receives a X.509 certificate. Therefore it is recommended
+(mandatory for roadwarrior connections) to set
+
+ config setup:
+ nocrsend=yes
+
+in /etc/ipsec.conf.
+
+
+14. Additional Features
+ -------------------
+
+
+14.1 Authentication and encryption algorithms
+ ----------------------------------------
+
+strongSwan supports the following suite of encryption and authentication
+algorithms for both IKE and ESP payloads.
+
++------------------------------------------------------------------+
+| IKE algorithms (negotiated in Phase 1 Main Mode) |
++------------------------------------------------------------------+
+| Encryption algorithms: 3des, aes, serpent, twofish, blowfish |
+|------------------------------------------------------------------|
+| Hash algorithms: md5, sha, sha2 |
+|------------------------------------------------------------------|
+| DH groups: 1024, 1536, 2048, 3072, 4096, 6144, 8192 |
++------------------------------------------------------------------+
+
+NOTE: For IKE the SHA-1 algorithm is denoted by "sha"
+
+The cryptographic IKE algorithms listed above are a fixed part of the
+strongSwan distribution. Particular algorithms can be added or removed
+in the "programs/pluto/alg" directory.
+
++------------------------------------------------------------------+
+| ESP algorithms (negotiated in Phase 2 Quick Mode) |
++------------------------------------------------------------------+
+| Encryption algorithms: 3des, aes, serpent, twofish, blowfish |
+|------------------------------------------------------------------|
+| Hash algorithms: md5, sha1, sha2 |
+|------------------------------------------------------------------|
+| PFS groups: 1024, 1536, 2048, 3072, 4096, 6144, 8192 |
++------------------------------------------------------------------+
+
+The cryptographic ESP algorithms listed above are a fixed part of the
+strongSwan distribution. If your Linux 2.4 or 2.6 kernel includes the
+CryptoAPI then additional ESP algorithms can be added or deleted as
+kernel modules.
+
+The IKE and ESP cryptographic algorithms to be proposed to the peer
+as an initiator can be specified on a per connection basis in the form
+
+conn normal
+ ...
+ ike=aes128-sha-modp1536,3des-sha-modp1536
+ esp=aes128-sha1,3des-sha1
+ ...
+
+or if you are more paranoid
+
+conn paranoid
+ ...
+ ike=aes256-sha2_512-modp2048
+ esp=aes256-sha2_512
+ ...
+
+If the the "ike" and "esp" configuration parameters are missing in
+ipsec.conf, then the default settings
+
+ ike=3des-md5-modp1536,3des-sha-modp1536,\
+ 3des-md5-modp1024,3des-sha-modp1024
+ esp=3des-md5,3des-sha1
+
+arre implicitly assumed. The 3DES encryption algorithm and the MD5 and
+SHA-1 hash algorithms are hardcoded into strongSwan and cannot be removed.
+
+If Perfect Forward Secrecy (PFS is desired), then a PFS group can be
+optionally specified:
+
+conn make_sure
+ ...
+ pfs=yes
+ pfsgroup=modp2048,modp1536
+ ...
+
+If the "pfs" parameter is missing then "pfs=yes" is assumed by default.
+This means that PFS must be disabled explicitly by setting "pfs=no".
+
+If the "pfsgroup" parameter is missing then the default is
+
+ pfsgroup=<Phase1 DH group>
+
+The "ike" and "esp" parameters are used to formulate one or several
+transform proposals to the peer if the strongSwan VPN host is the initiator.
+Attention! As a responder the first proposal from the peer is accepted that
+is supported the by one of the registered algorithms listed by the command
+
+ ipsec listalgs
+
+If the responder wants to restrict the allowed cipher suites the '!' flag
+can be used to do so. The configuration
+
+conn normal_but_strict
+ ...
+ ike=aes128-sha-modp1536,3des-sha-modp1536!
+ esp=aes128-sha1,3des-sha1!
+ ...
+
+will only permit the listed algorithms defined above but no other methods
+even if they might be supported by the responder.
+
+
+14.2 NAT traversal
+ -------------
+
+Currently please refer to README.NAT-Traversal document in the strongSwan
+distribution.
+
+
+14.3 Dead peer detection
+ --------------------
+
+strongSwan implements the RFC 3706 Dead Peer Detection (DPD) keep-alive
+scheme. If an established IPsec SA has been idle (i.e. without any traffic)
+for N seconds (dpddelay=N) then strongSwan side sends a "hello" message
+(R_U_THERE) and the peer replies with an acknowledge message (R_U_THERE_ACK).
+If no response is received, the R_U_THERE messages are repeated until a DPD
+timeout of M seconds (dpdtimeout=M) has elapsed. If still no traffic or
+R_U_THERE_ACK packets were received, the peer is declared to be dead and all
+SAs belonging to a common Phase 1 SA are deleted.
+
+DPD support is tuneable on a per connection basis by using the dpdaction,
+dpddelay and dpdtimeout directives:
+
+ conn roadwarrior
+ right=%any
+ left=%defaultroute
+ leftsubnet=10.1.0.0/16
+ dpdaction=clear
+
+ conn net-to-net
+ right=192.168.0.2
+ rightsubnet=10.2.0.0/16
+ left=%defaultroute
+ leftsubnet=10.1.0.0/16
+ dpdaction=hold
+ dpddelay=60
+ dpdtimeout=500
+
+In the first example dpdaction=clear activates the DPD mechanism under the
+condition that the peer supports RFC 3706. The values dpddelay=30s and
+dpdtimeout=120s are assumed by default in the absence of these parameters, so
+that during idle periods an R_U_THERE packet is sent every 30 seconds. If no
+traffic or a no R_U_THERE_ACK packet is received from the peer within a
+120 second time span, the peer will be declared dead and all SAs and associated
+eroutes will be cleared.
+
+In the second example R_U_THERE packets are sent every 60 seconds and the
+parameter setting dpdaction=hold will put the eroute of the ruptured connection
+into a %trap state, so that when new outgoing traffic will occur, the
+correspondig connection will be automatically renegotiated as soon as the
+peer is up again.
+
+It is recommended to use dpdaction=hold for statically defined connections and
+dpdaction=clear for dynamic roadwarrior connections. The default value is
+dpdaction=none, which disables DPD.
+
+
+14.4 IKE Mode Config
+ ---------------
+
+The IKE Mode Config protocol <draft-ietf-ipsec-isakmp-mode-cfg-04.txt> allows
+the dynamic assignment of virtual IP addresses and optional DNS and WINS server
+information to IPsec clients. Currently only "Mode Config Pull Mode" is
+implemented where the client actively sends a Mode Config request to the server
+in order to obtain a virtual IP.
+
+Client side configuration (carol):
+
+ conn home
+ right=192.168.0.1
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ left=%defaultroute
+ leftsourceip=%modeconfig
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ auto=start
+
+Server side configuration (moon):
+
+ conn roadwarrior
+ right=%any
+ rightid=carol@strongswan.org
+ rightsourceip=10.3.0.1
+ left=%defaultroute
+ leftsubnet=10.1.0.0/16
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ auto=add
+
+The wildcard %modeconfig or %modecfg used in the leftsourceip parameter of the
+client will trigger a Mode Config request. Currently the server will return
+the virtual IP address defined by the rightsourceip parameter. In the future
+an LDAP-based lookup mechanism will be supported.
+
+
+15. Copyright statement and acknowledgements
+ ----------------------------------------
+
+
+ FreeS/WAN version base system:
+
+ Copyright (c) 1999-2004
+ Henry Spencer, Richard Guy Briggs,
+ D. Hugh Redelmeier, Sandy Harris, Claudia Schmeing,
+ Michael Richardson, Angelos D. Keromytis, John Ioannidis,
+
+ NAT-Traversal, ipsec starter, Delete SA and Notification messages:
+
+ Copyright (c) 2002-2003, Mathieu Lafon
+
+ Additional cryptoalgorithms (AES, etc):
+
+ Copyright (c) 2002-2003, JuanJo Ciarlante
+
+ Dead Peer Detection:
+
+ Copyright (c) 2002-2004
+ Ken Bantoft, JuanJo Ciarlante, Philip Craig,
+ Pawel Krawczyk, Srinvasan Venkataraman
+
+ Porting to Linux 2.6 kernel:
+
+ Copyright (c) 2003, Herbert Xu
+
+ Dynamic CRL fetching:
+
+ Copyright (c) 2002, Stephane Laroche
+
+ IKE Mode Config protocol:
+
+ Copyright (c) 2001-2002, Colubris Networks
+
+ Virtual IP and source routing:
+
+ Copyright (c) 2003, Tuomo Soini
+
+ Port and protocol selectors for outbound traffic:
+
+ Copyright (c) 2002, Stephen J. Bevan
+
+ PGPnet-RSA parts of patch:
+
+ Copyright (c) 2000, Kai Martius
+
+ X.509, OCSP and smartcard functionality:
+
+ Copyright (c) 2000, Andreas Hess, Patric Lichtsteiner, Roger Wegmann
+ Copyright (c) 2001, Marco Bertossa, Andreas Schleiss
+ Copyright (c) 2002, Uli Galizzi, Ariane Seiler, Mario Strasser
+ Copyright (c) 2002, Martin Berner, Lukas Suter
+ Copyright (c) 2003, Christoph Gysin, Simon Zwahlen
+ Copyright (c) 2004, David Buechi, Michael Meier
+ Copyright (c) 2000-2005, Andreas Steffen
+
+ Zurich University of Applied Sciences in Winterthur, Switzerland
+
+ scepclient:
+
+ Copyright (c) 2005, Jan Hutter, Martin Willi
+ Copyright (c) 2005-2006, Andreas Steffen
+
+ University of Applied Sciences in Rapperswil, Switzerland
+
+ 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.
+-----------------------------------------------------------------------------
+
+This file is RCSID $Id: README,v 1.33 2006/04/24 21:27:49 as Exp $
+
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644
index 000000000..a523b809d
--- /dev/null
+++ b/doc/.cvsignore
@@ -0,0 +1,66 @@
+HowTo.html
+HowTo.html
+adv_config.html
+adv_config.html
+background.html
+background.html
+biblio.html
+biblio.html
+compat.html
+compat.html
+config.html
+config.html
+draft-richardson-ipsec-opportunistic.nr
+draft-richardson-ipsec-rr.nr
+draft-richardson-ipsec-rr.txt
+faq.html
+faq.html
+firewall.html
+firewall.html
+glossary.html
+glossary.html
+index.html
+index.html
+install.html
+install.html
+interop.html
+interop.html
+intro.html
+intro.html
+ipsec.html
+ipsec.html
+kernel.html
+kernel.html
+mail.html
+mail.html
+makecheck.html
+manpage.d
+manpage.d
+manpages.html
+manpages.html
+multi_netjig.png
+nightly.html
+performance.html
+performance.html
+policygroups.html
+politics.html
+politics.html
+quickstart.html
+rfc.html
+rfc.html
+rfc_pg
+roadmap.html
+roadmap.html
+single_netjig.png
+testing.html
+testing.html
+toc.html
+toc.html
+trouble.html
+trouble.html
+umltesting.html
+upgrading.html
+user_examples.html
+user_examples.html
+web.html
+web.html
diff --git a/doc/2.6.known-issues b/doc/2.6.known-issues
new file mode 100644
index 000000000..397c4f957
--- /dev/null
+++ b/doc/2.6.known-issues
@@ -0,0 +1,112 @@
+Known issues with FreeS/WAN on a 2.6 kernel Claudia Schmeing
+-------------------------------------------
+
+
+This is an overview of known issues with FreeS/WAN on the 2.6 kernel codebase
+(also 2.5.x), which includes native Linux IPsec code.
+
+More information on the native IPsec code is available here:
+
+ http://lartc.org/howto/lartc.ipsec.html
+
+Tools for use with that code are here:
+
+ http://ipsec-tools.sourceforge.net/
+
+
+* As of FreeS/WAN 2.03, FreeS/WAN ships with some support for the 2.6 kernel
+ IPsec code. In 2.03, this support is preliminary, but we expect to develop
+ it fully. Many thanks to Herbert Xu for the initial code patches.
+
+* Use the most recent Linux FreeS/WAN 2.x release from ftp.xs4all.nl
+ to try our 2.6 kernel support.
+
+* The installation procedure for use with 2.6 kernel IPsec is a little
+ different from a traditional FreeS/WAN installation. Please see
+ the latest doc/install.html.
+
+* Please see the design and users' mailing lists
+ (http://www.freeswan.org/mail.html) for more detail and the latest reports.
+
+
+
+DESIGN-RELATED ISSUES
+
+
+* In 2.6, IPsec policies are detached from routing decisions. Because of this
+ design, Opportunistic Encryption on the local LAN will be possible with 2.6.
+
+ One side effect: When contacting a node on the local LAN which is protected
+ by gateway OE, you will get asymmetrical routing (one way through the gateway,
+ one way direct), and IPsec will drop the return packets.
+
+
+
+CURRENT ISSUES
+
+
+* For the moment, users wishing to test FreeS/WAN with 2.6 will require
+ ipsec-tools' "setkey" program. Though FreeS/WAN's keying daemon, Pluto,
+ directly sets IPsec policy, setkey is currently required to reset kernel SPD
+ (Security Policy Database) states when Pluto restarts. We will likely add
+ this basic functionality to an upcoming FreeS/WAN release.
+
+* State information is not available to the user, eg. ipsec
+ eroute/ipsec spi/ipsec look do not work. The exception: ipsec auto --status
+ This will be fixed in a future release.
+
+* If you're running Opportunistic Encryption, connectivity to new hosts will
+ immediately fail. You may receive a message similar to this:
+
+ connect: Resource temporarily unavailable
+
+ The reason for this lies in the kernel code. Fairly complex discussion:
+
+ http://lists.freeswan.org/archives/design/2003-September/msg00073.html
+
+ As of 2.6.0-test6, this has not been fixed.
+
+* This initial connectivity failure has an unintended side effect on DNS queries.
+ This will result in a rekey failure for OE connections; a %pass will be
+ installed for your destination IP before a %pass is re-instituted to your
+ DNS server. As a workaround, please add your DNS servers to
+ /etc/ipsec.d/policies/clear.
+
+* Packets on all interfaces are considered for OE, including loopback. If you're
+ running a local nameserver, you'll still need to exempt localhost DNS traffic
+ as per the previous point. Since this traffic has a source of 127.0.0.1/32,
+ the "clear" policy group will not suffice; you'll need to add the following
+ %passthrough conn to ipsec.conf:
+
+ conn exclude-lo
+ authby=never
+ left=127.0.0.1
+ leftsubnet=127.0.0.0/8
+ right=127.0.0.2
+ rightsubnet=127.0.0.0/8
+ type=passthrough
+ auto=route
+
+
+
+OLD ISSUES
+
+
+None, yet.
+
+
+
+RELATED DOCUMENTS
+
+
+FreeS/WAN Install web page doc/install.html
+
+FreeS/WAN Install guide INSTALL
+
+FreeS/WAN mailing list posts, including:
+
+ http://lists.freeswan.org/archives/design/2003-September/msg00057.html
+
+To sign up for our mailing lists, see http://www.freeswan.org/mail.html
+
+
diff --git a/doc/HowTo.html b/doc/HowTo.html
new file mode 100644
index 000000000..a6f92dda9
--- /dev/null
+++ b/doc/HowTo.html
@@ -0,0 +1,18733 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<CENTER><A HREF="#CONTENTS"><H1>Introduction to FreeS/WAN</H1></A><BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#intro">Introduction</A></B>
+<UL>
+<LI><A HREF="#ipsec.intro">IPsec, Security for the Internet Protocol</A></LI>
+<UL>
+<LI><A HREF="#intro.interop">Interoperating with other IPsec
+ implementations</A></LI>
+<LI><A HREF="#advantages">Advantages of IPsec</A></LI>
+<LI><A HREF="#applications">Applications of IPsec</A></LI>
+<UL>
+<LI><A HREF="#makeVPN">Using secure tunnels to create a VPN</A></LI>
+<LI><A HREF="#road.intro">Road Warriors</A></LI>
+<LI><A HREF="#opp.intro">Opportunistic encryption</A></LI>
+</UL>
+<LI><A HREF="#types">The need to authenticate gateways</A></LI>
+</UL>
+<LI><A HREF="#project">The FreeS/WAN project</A></LI>
+<UL>
+<LI><A HREF="#goals">Project goals</A></LI>
+<LI><A HREF="#staff">Project team</A></LI>
+</UL>
+<LI><A HREF="#products">Products containing FreeS/WAN</A></LI>
+<UL>
+<LI><A HREF="#distwith">Full Linux distributions</A></LI>
+<LI><A HREF="#kernel_dist">Linux kernel distributions</A></LI>
+<LI><A HREF="#office_dist">Office server distributions</A></LI>
+<LI><A HREF="#fw_dist">Firewall distributions</A></LI>
+<LI><A HREF="#turnkey">Firewall and VPN products</A></LI>
+</UL>
+<LI><A HREF="#docs">Information sources</A></LI>
+<UL>
+<LI><A HREF="#docformats">This HowTo, in multiple formats</A></LI>
+<LI><A HREF="#rtfm">RTFM (please Read The Fine Manuals)</A></LI>
+<LI><A HREF="#text">Other documents in the distribution</A></LI>
+<LI><A HREF="#assumptions">Background material</A></LI>
+<LI><A HREF="#archives">Archives of the project mailing list</A></LI>
+<LI><A HREF="#howto">User-written HowTo information</A></LI>
+<LI><A HREF="#applied">Papers on FreeS/WAN</A></LI>
+<LI><A HREF="#licensing">License and copyright information</A></LI>
+</UL>
+<LI><A HREF="#sites">Distribution sites</A></LI>
+<UL>
+<LI><A HREF="#1_5_1">Primary site</A></LI>
+<LI><A HREF="#mirrors">Mirrors</A></LI>
+<LI><A HREF="#munitions">The &quot;munitions&quot; archive of Linux crypto
+ software</A></LI>
+</UL>
+<LI><A HREF="#1_6">Links to other sections</A></LI>
+</UL>
+<B><A HREF="#2">Upgrading to FreeS/WAN 2.x</A></B>
+<UL>
+<LI><A HREF="#2_1">New! Built in Opportunistic connections</A></LI>
+<UL>
+<LI><A HREF="#2_1_1">Upgrading Opportunistic Encryption to 2.01 (or
+ later)</A></LI>
+</UL>
+<LI><A HREF="#2_2">New! Policy Groups</A></LI>
+<LI><A HREF="#2_3">New! Packetdefault Connection</A></LI>
+<LI><A HREF="#2_4">FreeS/WAN now disables Reverse Path Filtering</A></LI>
+<LI><A HREF="#2_5">Revised ipsec.conf</A></LI>
+<UL>
+<LI><A HREF="#2_5_1">No promise of compatibility</A></LI>
+<LI><A HREF="#2_5_2">Most ipsec.conf files will work fine</A></LI>
+<LI><A HREF="#2_5_3">Backward compatibility patch</A></LI>
+<LI><A HREF="#2_5_4">Details</A></LI>
+<LI><A HREF="#2_5_5">Upgrading from 1.x RPMs to 2.x RPMs</A></LI>
+</UL>
+</UL>
+<B><A HREF="#quickstart">Quickstart Guide to Opportunistic Encryption</A>
+</B>
+<UL>
+<LI><A HREF="#opp.setup">Purpose</A></LI>
+<UL>
+<LI><A HREF="#3_1_1">OE &quot;flag day&quot;</A></LI>
+</UL>
+<LI><A HREF="#opp.dns">Requirements</A></LI>
+<LI><A HREF="#easy.install">RPM install</A></LI>
+<UL>
+<LI><A HREF="#3_3_1">Download RPMs</A></LI>
+<LI><A HREF="#3_3_2">Check signatures</A></LI>
+<LI><A HREF="#3_3_3">Install the RPMs</A></LI>
+<LI><A HREF="#testinstall">Test</A></LI>
+</UL>
+<LI><A HREF="#opp.setups.list">Our Opportunistic Setups</A></LI>
+<UL>
+<LI><A HREF="#3_4_1">Full or partial opportunism?</A></LI>
+</UL>
+<LI><A HREF="#opp.client">Initiate-only setup</A></LI>
+<UL>
+<LI><A HREF="#3_5_1">Restrictions</A></LI>
+<LI><A HREF="#forward.dns">Create and publish a forward DNS record</A></LI>
+<UL>
+<LI><A HREF="#3_5_2_1">Find a domain you can use</A></LI>
+<LI><A HREF="#3_5_2_2">Choose your ID</A></LI>
+<LI><A HREF="#3_5_2_3">Create a forward TXT record</A></LI>
+<LI><A HREF="#3_5_2_4">Publish the forward TXT record</A></LI>
+</UL>
+<LI><A HREF="#3_5_3">Test that your key has been published</A></LI>
+<LI><A HREF="#3_5_4">Configure, if necessary</A></LI>
+<LI><A HREF="#3_5_5">Test</A></LI>
+</UL>
+<LI><A HREF="#3_6">Full Opportunism</A></LI>
+<UL>
+<LI><A HREF="#3_6_1">Put a TXT record in a Forward Domain</A></LI>
+<LI><A HREF="#3_6_2">Put a TXT record in Reverse DNS</A></LI>
+<UL>
+<LI><A HREF="#3_6_2_1">Create a Reverse DNS TXT record</A></LI>
+<LI><A HREF="#3_6_2_2">Publish your TXT record</A></LI>
+</UL>
+<LI><A HREF="#3_6_3">Test your DNS record</A></LI>
+<LI><A HREF="#3_6_4">No Configuration Needed</A></LI>
+<LI><A HREF="#3_6_5">Consider Firewalling</A></LI>
+<LI><A HREF="#3_6_6">Test</A></LI>
+<LI><A HREF="#3_6_7">Test</A></LI>
+</UL>
+<LI><A HREF="#opp.test">Testing opportunistic connections</A></LI>
+<LI><A HREF="#3_8">Now what?</A></LI>
+<LI><A HREF="#3_9">Notes</A></LI>
+<LI><A HREF="#3_10">Troubleshooting OE</A></LI>
+<LI><A HREF="#3_11">Known Issues</A></LI>
+</UL>
+<B><A HREF="#4">How to Configure Linux FreeS/WAN with Policy Groups</A></B>
+<UL>
+<LI><A HREF="#4_1">What are Policy Groups?</A></LI>
+<UL>
+<LI><A HREF="#4_1_1">Built-In Security Options</A></LI>
+</UL>
+<LI><A HREF="#4_2">Using Policy Groups</A></LI>
+<UL>
+<LI><A HREF="#4_2_1">Example 1: Using a Base Policy Group</A></LI>
+<LI><A HREF="#4_2_2">Example 2: Defining IPsec Security Policy with
+ Groups</A></LI>
+<LI><A HREF="#4_2_3">Example 3: Creating a Simple IPsec VPN with the
+ private Group</A></LI>
+<LI><A HREF="#4_2_4">Example 4: New Policy Groups to Protect a Subnet</A>
+</LI>
+<LI><A HREF="#4_2_5">Example 5: Adding a Subnet to the VPN</A></LI>
+</UL>
+<LI><A HREF="#4_3">Appendix</A></LI>
+<UL>
+<LI><A HREF="#4_3_1">Our Hidden Connections</A></LI>
+<LI><A HREF="#4_3_2">Custom Policy Groups</A></LI>
+<LI><A HREF="#4_3_3">Disabling Opportunistic Encryption</A></LI>
+</UL>
+</UL>
+<B><A HREF="#5">FreeS/WAN FAQ</A></B>
+<UL>
+<LI><A HREF="#questions">Index of FAQ questions</A></LI>
+<LI><A HREF="#whatzit">What is FreeS/WAN?</A></LI>
+<LI><A HREF="#problems">How do I report a problem or seek help?</A></LI>
+<LI><A HREF="#generic">Can I get ...</A></LI>
+<UL>
+<LI><A HREF="#lemme_out">Can I get an off-the-shelf system that includes
+ FreeS/WAN?</A></LI>
+<LI><A HREF="#consultant">Can I hire consultants or staff who know
+ FreeS/WAN?</A></LI>
+<LI><A HREF="#commercial">Can I get commercial support?</A></LI>
+</UL>
+<LI><A HREF="#release">Release questions</A></LI>
+<UL>
+<LI><A HREF="#rel.current">What is the current release?</A></LI>
+<LI><A HREF="#relwhen">When is the next release?</A></LI>
+<LI><A HREF="#rel.bugs">Are there known bugs in the current release?</A></LI>
+</UL>
+<LI><A HREF="#mod_cons">Modifications and contributions</A></LI>
+<UL>
+<LI><A HREF="#modify.faq">Can I modify FreeS/WAN to ...?</A></LI>
+<LI><A HREF="#contrib.faq">Can I contribute to the project?</A></LI>
+<LI><A HREF="#ddoc.faq">Is there detailed design documentation?</A></LI>
+</UL>
+<LI><A HREF="#interact">Will FreeS/WAN work in my environment?</A></LI>
+<UL>
+<LI><A HREF="#interop.faq">Can FreeS/WAN talk to ...?</A></LI>
+<LI><A HREF="#old_to_new">Can different FreeS/WAN versions talk to each
+ other?</A></LI>
+<LI><A HREF="#faq.bandwidth">Is there a limit on throughput?</A></LI>
+<LI><A HREF="#faq.number">Is there a limit on number of tunnels?</A></LI>
+<LI><A HREF="#faq.speed">Is a ... fast enough to handle FreeS/WAN with
+ my loads?</A></LI>
+</UL>
+<LI><A HREF="#work_on">Will FreeS/WAN work on ... ?</A></LI>
+<UL>
+<LI><A HREF="#versions">Will FreeS/WAN run on my version of Linux?</A></LI>
+<LI><A HREF="#nonIntel.faq">Will FreeS/WAN run on non-Intel CPUs?</A></LI>
+<LI><A HREF="#multi.faq">Will FreeS/WAN run on multiprocessors?</A></LI>
+<LI><A HREF="#k.old">Will FreeS/WAN work on an older kernel?</A></LI>
+<LI><A HREF="#k.versions">Will FreeS/WAN run on the latest kernel
+ version?</A></LI>
+<LI><A HREF="#interface.faq">Will FreeS/WAN work on unusual network
+ hardware?</A></LI>
+<LI><A HREF="#vlan">Will FreeS/WAN work on a VLAN (802.1q) network?</A></LI>
+</UL>
+<LI><A HREF="#features.faq">Does FreeS/WAN support ...</A></LI>
+<UL>
+<LI><A HREF="#VPN.faq">Does FreeS/WAN support site-to-site VPN (Virtual
+ Private Network) applications?</A></LI>
+<LI><A HREF="#warrior.faq">Does FreeS/WAN support remote users
+ connecting to a LAN?</A></LI>
+<LI><A HREF="#road.shared.possible">Does FreeS/WAN support remote users
+ using shared secret authentication?</A></LI>
+<LI><A HREF="#wireless.faq">Does FreeS/WAN support wireless networks?</A>
+</LI>
+<LI><A HREF="#PKIcert">Does FreeS/WAN support X.509 or other PKI
+ certificates?</A></LI>
+<LI><A HREF="#Radius">Does FreeS/WAN support user authentication
+ (Radius, SecureID, Smart Card...)?</A></LI>
+<LI><A HREF="#NATtraversal">Does FreeS/WAN support NAT traversal?</A></LI>
+<LI><A HREF="#virtID">Does FreeS/WAN support assigning a &quot;virtual
+ identity&quot; to a remote system?</A></LI>
+<LI><A HREF="#noDES.faq">Does FreeS/WAN support single DES encryption?</A>
+</LI>
+<LI><A HREF="#AES.faq">Does FreeS/WAN support AES encryption?</A></LI>
+<LI><A HREF="#other.cipher">Does FreeS/WAN support other encryption
+ algorithms?</A></LI>
+</UL>
+<LI><A HREF="#canI">Can I ...</A></LI>
+<UL>
+<LI><A HREF="#policy.preconfig">Can I use policy groups along with
+ explicitly configured connections?</A></LI>
+<LI><A HREF="#policy.off">Can I turn off policy groups?</A></LI>
+<LI><A HREF="#reload">Can I reload connection info without restarting?</A>
+</LI>
+<LI><A HREF="#masq.faq">Can I use several masqueraded subnets?</A></LI>
+<LI><A HREF="#dup_route">Can I use subnets masqueraded to the same
+ addresses?</A></LI>
+<LI><A HREF="#road.masq">Can I assign a road warrior an address on my
+ net (a virtual identity)?</A></LI>
+<LI><A HREF="#road.many">Can I support many road warriors with one
+ gateway?</A></LI>
+<LI><A HREF="#road.PSK">Can I have many road warriors using shared
+ secret authentication?</A></LI>
+<LI><A HREF="#QoS">Can I use Quality of Service routing with FreeS/WAN?</A>
+</LI>
+<LI><A HREF="#deadtunnel">Can I recognise dead tunnels and shut them
+ down?</A></LI>
+<LI><A HREF="#demanddial">Can I build IPsec tunnels over a demand-dialed
+ link?</A></LI>
+<LI><A HREF="#GRE">Can I build GRE, L2TP or PPTP tunnels over IPsec?</A></LI>
+<LI><A HREF="#NetBIOS">... use Network Neighborhood (Samba, NetBIOS)
+ over IPsec?</A></LI>
+</UL>
+<LI><A HREF="#setup.faq">Life's little mysteries</A></LI>
+<UL>
+<LI><A HREF="#cantping">I cannot ping ....</A></LI>
+<LI><A HREF="#forever">It takes forever to ...</A></LI>
+<LI><A HREF="#route">I send packets to the tunnel with route(8) but they
+ vanish</A></LI>
+<LI><A HREF="#down_route">When a tunnel goes down, packets vanish</A></LI>
+<LI><A HREF="#firewall_ate">The firewall ate my packets!</A></LI>
+<LI><A HREF="#dropconn">Dropped connections</A></LI>
+<LI><A HREF="#defaultroutegone">Disappearing %defaultroute</A></LI>
+<LI><A HREF="#tcpdump.faq">TCPdump on the gateway shows strange things</A>
+</LI>
+<LI><A HREF="#no_trace">Traceroute does not show anything between the
+ gateways</A></LI>
+</UL>
+<LI><A HREF="#man4debug">Testing in stages</A></LI>
+<UL>
+<LI><A HREF="#nomanual">Manually keyed connections don't work</A></LI>
+<LI><A HREF="#spi_error">One manual connection works, but second one
+ fails</A></LI>
+<LI><A HREF="#man_no_auto">Manual connections work, but automatic keying
+ doesn't</A></LI>
+<LI><A HREF="#nocomp">IPsec works, but connections using compression
+ fail</A></LI>
+<LI><A HREF="#pmtu.broken">Small packets work, but large transfers fail</A>
+</LI>
+<LI><A HREF="#subsub">Subnet-to-subnet works, but tests from the
+ gateways don't</A></LI>
+</UL>
+<LI><A HREF="#compile.faq">Compilation problems</A></LI>
+<UL>
+<LI><A HREF="#gmp.h_missing">gmp.h: No such file or directory</A></LI>
+<LI><A HREF="#noVM">... virtual memory exhausted</A></LI>
+</UL>
+<LI><A HREF="#error">Interpreting error messages</A></LI>
+<UL>
+<LI><A HREF="#route-client">route-client (or host) exited with status 7</A>
+</LI>
+<LI><A HREF="#unreachable">SIOCADDRT:Network is unreachable</A></LI>
+<LI><A HREF="#modprobe">ipsec_setup: modprobe: Can't locate module ipsec</A>
+</LI>
+<LI><A HREF="#noKLIPS">ipsec_setup: Fatal error, kernel appears to lack
+ KLIPS</A></LI>
+<LI><A HREF="#noDNS">ipsec_setup: ... failure to fetch key for ... from
+ DNS</A></LI>
+<LI><A HREF="#dup_address">ipsec_setup: ... interfaces ... and ... share
+ address ...</A></LI>
+<LI><A HREF="#kflags">ipsec_setup: Cannot adjust kernel flags</A></LI>
+<LI><A HREF="#message_num">Message numbers (MI3, QR1, et cetera) in
+ Pluto messages</A></LI>
+<LI><A HREF="#conn_name">Connection names in Pluto error messages</A></LI>
+<LI><A HREF="#cantorient">Pluto: ... can't orient connection</A></LI>
+<LI><A HREF="#no.interface">... we have no ipsecN interface for either
+ end of this connection</A></LI>
+<LI><A HREF="#noconn">Pluto: ... no connection is known</A></LI>
+<LI><A HREF="#nosuit">Pluto: ... no suitable connection ...</A></LI>
+<LI><A HREF="#noconn.auth">Pluto: ... no connection has been authorized</A>
+</LI>
+<LI><A HREF="#noDESsupport">Pluto: ... OAKLEY_DES_CBC is not supported.</A>
+</LI>
+<LI><A HREF="#notransform">Pluto: ... no acceptable transform</A></LI>
+<LI><A HREF="#rsasigkey">rsasigkey dumps core</A></LI>
+<LI><A HREF="#sig4">!Pluto failure!: ... exited with ... signal 4</A></LI>
+<LI><A HREF="#econnrefused">ECONNREFUSED error message</A></LI>
+<LI><A HREF="#no_eroute">klips_debug: ... no eroute!</A></LI>
+<LI><A HREF="#SAused">... trouble writing to /dev/ipsec ... SA already
+ in use</A></LI>
+<LI><A HREF="#ignore">... ignoring ... payload</A></LI>
+<LI><A HREF="#unknown_rightcert">unknown parameter name &quot;rightcert&quot;</A></LI>
+</UL>
+<LI><A HREF="#spam">Why don't you restrict the mailing lists to reduce
+ spam?</A></LI>
+</UL>
+<B><A HREF="#manpages">FreeS/WAN manual pages</A></B>
+<UL>
+<LI><A HREF="#man.file">Files</A></LI>
+<LI><A HREF="#man.command">Commands</A></LI>
+<LI><A HREF="#man.lib">Library routines</A></LI>
+</UL>
+<B><A HREF="#firewall">FreeS/WAN and firewalls</A></B>
+<UL>
+<LI><A HREF="#filters">Filtering rules for IPsec packets</A></LI>
+<LI><A HREF="#examplefw">Firewall configuration at boot</A></LI>
+<UL>
+<LI><A HREF="#simple.rules">A simple set of rules</A></LI>
+<LI><A HREF="#complex.rules">Other rules</A></LI>
+<UL>
+<LI><A HREF="#7_2_2_1">Adding additional rules</A></LI>
+<LI><A HREF="#7_2_2_2">Modifying existing rules</A></LI>
+</UL>
+<LI><A HREF="#rules.pub">Published rule sets</A></LI>
+<UL>
+<LI><A HREF="#Ranch.trinity">Scripts based on Ranch's work</A></LI>
+<LI><A HREF="#seawall">The Seattle firewall</A></LI>
+<LI><A HREF="#rcf">The RCF scripts</A></LI>
+<LI><A HREF="#asgard">Asgard scripts</A></LI>
+<LI><A HREF="#user.scripts">User scripts from the mailing list</A></LI>
+</UL>
+</UL>
+<LI><A HREF="#updown">Calling firewall scripts, named in ipsec.conf(5)</A>
+</LI>
+<UL>
+<LI><A HREF="#pre_post">Scripts called at IPsec start and stop</A></LI>
+<LI><A HREF="#up_down">Scripts called at connection up and down</A></LI>
+<UL>
+<LI><A HREF="#fw.default">The default script</A></LI>
+<LI><A HREF="#userscript">User-written scripts</A></LI>
+</UL>
+<LI><A HREF="#ipchains.script">Scripts for ipchains or iptables</A></LI>
+</UL>
+<LI><A HREF="#NAT">A complication: IPsec vs. NAT</A></LI>
+<UL>
+<LI><A HREF="#nat_ok">NAT on or behind the IPsec gateway works</A></LI>
+<LI><A HREF="#nat_bad">NAT between gateways is problematic</A></LI>
+<LI><A HREF="#NAT.ref">Other references on NAT and IPsec</A></LI>
+</UL>
+<LI><A HREF="#complications">Other complications</A></LI>
+<UL>
+<LI><A HREF="#through">IPsec through the gateway</A></LI>
+<LI><A HREF="#ipsec_only">Preventing non-IPsec traffic</A></LI>
+<LI><A HREF="#unknowngate">Filtering packets from unknown gateways</A></LI>
+</UL>
+<LI><A HREF="#otherfilter">Other packet filters</A></LI>
+<UL>
+<LI><A HREF="#ICMP">ICMP filtering</A></LI>
+<LI><A HREF="#traceroute">UDP packets for traceroute</A></LI>
+<LI><A HREF="#l2tp">UDP for L2TP</A></LI>
+</UL>
+<LI><A HREF="#packets">How it all works: IPsec packet details</A></LI>
+<UL>
+<LI><A HREF="#noport">ESP and AH do not have ports</A></LI>
+<LI><A HREF="#header">Header layout</A></LI>
+<LI><A HREF="#dhr">DHR on the updown script</A></LI>
+</UL>
+</UL>
+<B><A HREF="#trouble">Linux FreeS/WAN Troubleshooting Guide</A></B>
+<UL>
+<LI><A HREF="#overview">Overview</A></LI>
+<LI><A HREF="#install">1. During Install</A></LI>
+<UL>
+<LI><A HREF="#8_2_1">1.1 RPM install gotchas</A></LI>
+<LI><A HREF="#8_2_2">1.2 Problems installing from source</A></LI>
+<LI><A HREF="#install.check">1.3 Install checks</A></LI>
+<LI><A HREF="#oe.trouble">1.3 Troubleshooting OE</A></LI>
+</UL>
+<LI><A HREF="#negotiation">2. During Negotiation</A></LI>
+<UL>
+<LI><A HREF="#state">2.1 Determine Connection State</A></LI>
+<UL>
+<LI><A HREF="#8_3_1_1">Finding current state</A></LI>
+<LI><A HREF="#8_3_1_2">What's this supposed to look like?</A></LI>
+</UL>
+<LI><A HREF="#find.pluto.error">2.2 Finding error text</A></LI>
+<UL>
+<LI><A HREF="#8_3_2_1">Verbose start for more information</A></LI>
+<LI><A HREF="#8_3_2_2">Debug levels count</A></LI>
+<LI><A HREF="#8_3_2_3">ipsec barf for lots of debugging information</A></LI>
+<LI><A HREF="#8_3_2_4">Find the error</A></LI>
+<LI><A HREF="#8_3_2_5">Play both sides</A></LI>
+</UL>
+<LI><A HREF="#interpret.pluto.error">2.3 Interpreting a Negotiation
+ Error</A></LI>
+<UL>
+<LI><A HREF="#ikepath">Connection stuck at STATE_MAIN_I1</A></LI>
+<LI><A HREF="#8_3_3_2">Other errors</A></LI>
+</UL>
+</UL>
+<LI><A HREF="#use">3. Using a Connection</A></LI>
+<UL>
+<LI><A HREF="#8_4_1">3.1 Orienting yourself</A></LI>
+<UL>
+<LI><A HREF="#8_4_1_1">How do I know if it works?</A></LI>
+<LI><A HREF="#8_4_1_2">ipsec barf is useful again</A></LI>
+</UL>
+<LI><A HREF="#8_4_2">3.2 Those pesky configuration errors</A></LI>
+<LI><A HREF="#route.firewall">3.3 Check Routing and Firewalling</A></LI>
+<UL>
+<LI><A HREF="#8_4_3_1">Background:</A></LI>
+<LI><A HREF="#ifconfig">View Interface and Firewall Statistics</A></LI>
+</UL>
+<LI><A HREF="#sniff">3.4 When in doubt, sniff it out</A></LI>
+<UL>
+<LI><A HREF="#8_4_4_1">Anticipate your packets' path</A></LI>
+</UL>
+<LI><A HREF="#find.use.error">3.5 Check your logs</A></LI>
+<UL>
+<LI><A HREF="#interpret.use.error">Interpreting log text</A></LI>
+</UL>
+<LI><A HREF="#bigpacket">3.6 More testing for the truly thorough</A></LI>
+<UL>
+<LI><A HREF="#8_4_6_1">Large Packets</A></LI>
+<LI><A HREF="#8_4_6_2">Stress Tests</A></LI>
+</UL>
+</UL>
+<LI><A HREF="#prob.report">4. Problem Reporting</A></LI>
+<UL>
+<LI><A HREF="#8_5_1">4.1 How to ask for help</A></LI>
+<LI><A HREF="#8_5_2">4.2 Where to ask</A></LI>
+</UL>
+<LI><A HREF="#notes">5. Additional Notes on Troubleshooting</A></LI>
+<UL>
+<LI><A HREF="#system.info">5.1 Information available on your system</A></LI>
+<UL>
+<LI><A HREF="#logusage">Logs used</A></LI>
+<LI><A HREF="#pages">man pages provided</A></LI>
+<LI><A HREF="#statusinfo">Status information</A></LI>
+</UL>
+<LI><A HREF="#testgates"> 5.2 Testing between security gateways</A></LI>
+<LI><A HREF="#ifconfig1">5.3 ifconfig reports for KLIPS debugging</A></LI>
+<LI><A HREF="#gdb"> 5.4 Using GDB on Pluto</A></LI>
+</UL>
+</UL>
+<B><A HREF="#compat">Linux FreeS/WAN Compatibility Guide</A></B>
+<UL>
+<LI><A HREF="#spec">Implemented parts of the IPsec Specification</A></LI>
+<UL>
+<LI><A HREF="#in">In Linux FreeS/WAN</A></LI>
+<LI><A HREF="#dropped">Deliberately omitted</A></LI>
+<LI><A HREF="#not">Not (yet) in Linux FreeS/WAN</A></LI>
+</UL>
+<LI><A HREF="#pfkey">Our PF-Key implementation</A></LI>
+<UL>
+<LI><A HREF="#pfk.port">PF-Key portability</A></LI>
+</UL>
+<LI><A HREF="#otherk">Kernels other than the latest 2.2.x and 2.4.y</A></LI>
+<UL>
+<LI><A HREF="#kernel.2.0">2.0.x kernels</A></LI>
+<LI><A HREF="#kernel.production">2.2 and 2.4 kernels</A></LI>
+</UL>
+<LI><A HREF="#otherdist">Intel Linux distributions other than Redhat</A></LI>
+<UL>
+<LI><A HREF="#rh7">Redhat 7.0</A></LI>
+<LI><A HREF="#suse">SuSE Linux</A></LI>
+<UL>
+<LI><A HREF="#9_4_2_1">SuSE Linux 5.3</A></LI>
+</UL>
+<LI><A HREF="#slack">Slackware</A></LI>
+<LI><A HREF="#deb">Debian</A></LI>
+<LI><A HREF="#caldera">Caldera</A></LI>
+</UL>
+<LI><A HREF="#CPUs">CPUs other than Intel</A></LI>
+<UL>
+<LI><A HREF="# strongarm">Corel Netwinder (StrongARM CPU)</A></LI>
+<LI><A HREF="#yellowdog">Yellow Dog Linux on Power PC</A></LI>
+<LI><A HREF="#mklinux">Mklinux</A></LI>
+<LI><A HREF="#alpha">Alpha 64-bit processors</A></LI>
+<LI><A HREF="#SPARC">Sun SPARC processors</A></LI>
+<LI><A HREF="#mips">MIPS processors</A></LI>
+<LI><A HREF="#crusoe">Transmeta Crusoe</A></LI>
+<LI><A HREF="#coldfire">Motorola Coldfire</A></LI>
+</UL>
+<LI><A HREF="#multiprocessor">Multiprocessor machines</A></LI>
+<LI><A HREF="#hardware">Support for crypto hardware</A></LI>
+<LI><A HREF="#ipv6">IP version 6 (IPng)</A></LI>
+<UL>
+<LI><A HREF="#v6.back">IPv6 background</A></LI>
+</UL>
+</UL>
+<B><A HREF="#10">Interoperating with FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="#10_1">Interop at a Glance</A></LI>
+<UL>
+<LI><A HREF="#10_1_1">Key</A></LI>
+</UL>
+<LI><A HREF="#10_2">Basic Interop Rules</A></LI>
+<LI><A HREF="#10_3">Longer Stories</A></LI>
+<UL>
+<LI><A HREF="#10_3_1">For More Compatible Implementations</A></LI>
+<UL>
+<LI><A HREF="#freeswan">FreeS/WAN</A></LI>
+<LI><A HREF="#isakmpd">isakmpd (OpenBSD)</A></LI>
+<LI><A HREF="#kame">Kame</A></LI>
+<LI><A HREF="#mcafee">PGPNet/McAfee</A></LI>
+<LI><A HREF="#microsoft">Microsoft Windows 2000/XP</A></LI>
+<LI><A HREF="#ssh">SSH Sentinel</A></LI>
+<LI><A HREF="#safenet">Safenet SoftPK/SoftRemote</A></LI>
+</UL>
+<LI><A HREF="#10_3_2">For Other Implementations</A></LI>
+<UL>
+<LI><A HREF="#6wind">6Wind</A></LI>
+<LI><A HREF="#alcatel">Alcatel Timestep</A></LI>
+<LI><A HREF="#apple">Apple Macintosh System 10+</A></LI>
+<LI><A HREF="#ashleylaurent">AshleyLaurent VPCom</A></LI>
+<LI><A HREF="#borderware">Borderware</A></LI>
+<LI><A HREF="#checkpoint">Check Point VPN-1 or FW-1</A></LI>
+<LI><A HREF="#cisco">Cisco</A></LI>
+<LI><A HREF="#equinux">Equinux VPN tracker (for Mac OS X)</A></LI>
+<LI><A HREF="#fsecure">F-Secure</A></LI>
+<LI><A HREF="#gauntlet">Gauntlet GVPN</A></LI>
+<LI><A HREF="#aix">IBM AIX</A></LI>
+<LI><A HREF="#as400">IBM AS/400</A></LI>
+<LI><A HREF="#intel">Intel Shiva LANRover / Net Structure</A></LI>
+<LI><A HREF="#lancom">LanCom (formerly ELSA)</A></LI>
+<LI><A HREF="#linksys">Linksys</A></LI>
+<LI><A HREF="#lucent">Lucent</A></LI>
+<LI><A HREF="#netasq">Netasq</A></LI>
+<LI><A HREF="#netcelo">Netcelo</A></LI>
+<LI><A HREF="#netgear">Netgear fvs318</A></LI>
+<LI><A HREF="#netscreen">Netscreen 100 or 5xp</A></LI>
+<LI><A HREF="#nortel">Nortel Contivity</A></LI>
+<LI><A HREF="#radguard">Radguard</A></LI>
+<LI><A HREF="#raptor">Raptor (NT or Solaris)</A></LI>
+<LI><A HREF="#redcreek">Redcreek Ravlin</A></LI>
+<LI><A HREF="#sonicwall">SonicWall</A></LI>
+<LI><A HREF="#sun">Sun Solaris</A></LI>
+<LI><A HREF="#symantec">Symantec</A></LI>
+<LI><A HREF="#watchguard">Watchguard Firebox</A></LI>
+<LI><A HREF="#xedia">Xedia Access Point/QVPN</A></LI>
+<LI><A HREF="#zyxel">Zyxel</A></LI>
+</UL>
+</UL>
+</UL>
+<B><A HREF="#performance">Performance of FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="#pub.bench">Published material</A></LI>
+<LI><A HREF="#perf.estimate">Estimating CPU overheads</A></LI>
+<UL>
+<LI><A HREF="#perf.more">Higher performance alternatives</A></LI>
+<LI><A HREF="#11_2_2">Other considerations</A></LI>
+</UL>
+<LI><A HREF="#biggate">Many tunnels from a single gateway</A></LI>
+<LI><A HREF="#low-end">Low-end systems</A></LI>
+<LI><A HREF="#klips.bench">Measuring KLIPS</A></LI>
+<LI><A HREF="#speed.compress">Speed with compression</A></LI>
+<LI><A HREF="#methods">Methods of measuring</A></LI>
+</UL>
+<B><A HREF="#test.freeswan">Testing FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="#test.oe">Testing opportunistic connections</A></LI>
+<UL>
+<LI><A HREF="#12_1_1">Basic OE Test</A></LI>
+<LI><A HREF="#12_1_2">OE Gateway Test</A></LI>
+<LI><A HREF="#12_1_3">Additional OE tests</A></LI>
+</UL>
+<LI><A HREF="#test.uml">Testing with User Mode Linux</A></LI>
+<LI><A HREF="#testnet">Configuration for a testbed network</A></LI>
+<UL>
+<LI><A HREF="#testbed">Testbed network</A></LI>
+<LI><A HREF="#tcpdump.test">Using packet sniffers in testing</A></LI>
+</UL>
+<LI><A HREF="#verify.crypt">Verifying encryption</A></LI>
+<LI><A HREF="#mail.test">Mailing list pointers</A></LI>
+</UL>
+<B><A HREF="#kernelconfig">Kernel configuration for FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="#notall">Not everyone needs to worry about kernel
+ configuration</A></LI>
+<LI><A HREF="#assume">Assumptions and notation</A></LI>
+<UL>
+<LI><A HREF="#labels">Labels used</A></LI>
+</UL>
+<LI><A HREF="#kernelopt">Kernel options for FreeS/WAN</A></LI>
+</UL>
+<B><A HREF="#adv_config">Other configuration possibilities</A></B>
+<UL>
+<LI><A HREF="#thumb">Some rules of thumb about configuration</A></LI>
+<UL>
+<LI><A HREF="#cheap.tunnel">Tunnels are cheap</A></LI>
+<LI><A HREF="#subnet.size">Subnet sizes</A></LI>
+<LI><A HREF="#example.more">Other network layouts</A></LI>
+<UL>
+<LI><A HREF="#internet.subnet">The Internet as a big subnet</A></LI>
+<LI><A HREF="#wireless.config">Wireless</A></LI>
+</UL>
+</UL>
+<LI><A HREF="#choose">Choosing connection types</A></LI>
+<UL>
+<LI><A HREF="#man-auto">Manual vs. automatic keying</A></LI>
+<LI><A HREF="#auto-auth">Authentication methods for auto-keying</A></LI>
+<LI><A HREF="#adv-pk">Advantages of public key methods</A></LI>
+</UL>
+<LI><A HREF="#prodsecrets">Using shared secrets in production</A></LI>
+<UL>
+<LI><A HREF="#secrets">Putting secrets in ipsec.secrets(5)</A></LI>
+<LI><A HREF="#securing.secrets">File security</A></LI>
+<LI><A HREF="#notroadshared">Shared secrets for road warriors</A></LI>
+</UL>
+<LI><A HREF="#prodman">Using manual keying in production</A></LI>
+<UL>
+<LI><A HREF="#ranbits">Creating keys with ranbits</A></LI>
+</UL>
+<LI><A HREF="#boot">Setting up connections at boot time</A></LI>
+<LI><A HREF="#multitunnel">Multiple tunnels between the same two
+ gateways</A></LI>
+<UL>
+<LI><A HREF="#advroute">One tunnel plus advanced routing</A></LI>
+</UL>
+<LI><A HREF="#opp.gate">An Opportunistic Gateway</A></LI>
+<UL>
+<LI><A HREF="#14_7_1">Start from full opportunism</A></LI>
+<LI><A HREF="#14_7_2">Reverse DNS TXT records for each protected machine</A>
+</LI>
+<LI><A HREF="#14_7_3">Publish your records</A></LI>
+<LI><A HREF="#14_7_4">...and test them</A></LI>
+<LI><A HREF="#14_7_5">No Configuration Needed</A></LI>
+</UL>
+<LI><A HREF="#extruded.config">Extruded Subnets</A></LI>
+<LI><A HREF="#roadvirt">Road Warrior with virtual IP address</A></LI>
+<LI><A HREF="#dynamic">Dynamic Network Interfaces</A></LI>
+<UL>
+<LI><A HREF="#basicdyn">Basics</A></LI>
+<LI><A HREF="#bootdyn">Boot Time</A></LI>
+<LI><A HREF="#changedyn">Change Time</A></LI>
+</UL>
+<LI><A HREF="#unencrypted">Unencrypted tunnels</A></LI>
+</UL>
+<B><A HREF="#install">Installing FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="#15_1">Requirements</A></LI>
+<LI><A HREF="#15_2">Choose your install method</A></LI>
+<LI><A HREF="#15_3">FreeS/WAN ships with some Linuxes</A></LI>
+<UL>
+<LI><A HREF="#15_3_1">FreeS/WAN may be altered...</A></LI>
+<LI><A HREF="#15_3_2">You might need to create an authentication keypair</A>
+</LI>
+<LI><A HREF="#15_3_3">Start and test FreeS/WAN</A></LI>
+</UL>
+<LI><A HREF="#15_4">RPM install</A></LI>
+<UL>
+<LI><A HREF="#15_4_1">Download RPMs</A></LI>
+<LI><A HREF="#15_4_2">For freeswan.org RPMs: check signatures</A></LI>
+<LI><A HREF="#15_4_3">Install the RPMs</A></LI>
+<LI><A HREF="#15_4_4">Start and Test FreeS/WAN</A></LI>
+</UL>
+<LI><A HREF="#15_5">Install from Source</A></LI>
+<UL>
+<LI><A HREF="#15_5_1">Decide what functionality you need</A></LI>
+<LI><A HREF="#15_5_2">Download FreeS/WAN</A></LI>
+<LI><A HREF="#15_5_3">For freeswan.org source: check its signature</A></LI>
+<LI><A HREF="#15_5_4">Untar, unzip</A></LI>
+<LI><A HREF="#15_5_5">Patch if desired</A></LI>
+<LI><A HREF="#15_5_6">... and Make</A></LI>
+<UL>
+<LI><A HREF="#15_5_6_1">Userland-only Install for 2.6 kernels</A></LI>
+<LI><A HREF="#15_5_6_2">KLIPS install for 2.2, 2.4, or 2.6 kernels</A></LI>
+</UL>
+</UL>
+<LI><A HREF="#15_6">Start FreeS/WAN and test your install</A></LI>
+<LI><A HREF="#15_7">Test your install</A></LI>
+<LI><A HREF="#15_8">Making FreeS/WAN play well with others</A></LI>
+<LI><A HREF="#15_9">Configure for your needs</A></LI>
+</UL>
+<B><A HREF="#config">How to configure FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="#16_1">Requirements</A></LI>
+<LI><A HREF="#config.netnet">Net-to-Net connection</A></LI>
+<UL>
+<LI><A HREF="#netnet.info.ex">Gather information</A></LI>
+<UL>
+<LI><A HREF="#16_2_1_1">Get your leftrsasigkey</A></LI>
+<LI><A HREF="#16_2_1_2">...and your rightrsasigkey</A></LI>
+</UL>
+<LI><A HREF="#16_2_2">Edit /etc/ipsec.conf</A></LI>
+<LI><A HREF="#16_2_3">Start your connection</A></LI>
+<LI><A HREF="#16_2_4">Do not MASQ or NAT packets to be tunneled</A></LI>
+<LI><A HREF="#16_2_5">Test your connection</A></LI>
+<LI><A HREF="#16_2_6">Finishing touches</A></LI>
+</UL>
+<LI><A HREF="#config.rw">Road Warrior Configuration</A></LI>
+<UL>
+<LI><A HREF="#rw.info.ex">Gather information</A></LI>
+<UL>
+<LI><A HREF="#16_3_1_1">Get your leftrsasigkey...</A></LI>
+<LI><A HREF="#16_3_1_2">...and your rightrsasigkey</A></LI>
+</UL>
+<LI><A HREF="#16_3_2">Customize /etc/ipsec.conf</A></LI>
+<LI><A HREF="#16_3_3">Start your connection</A></LI>
+<LI><A HREF="#16_3_4">Do not MASQ or NAT packets to be tunneled</A></LI>
+<LI><A HREF="#16_3_5">Test your connection</A></LI>
+<LI><A HREF="#16_3_6">Finishing touches</A></LI>
+<LI><A HREF="#16_3_7">Multiple Road Warriors</A></LI>
+</UL>
+<LI><A HREF="#16_4">What next?</A></LI>
+</UL>
+<B><A HREF="#background">Linux FreeS/WAN background</A></B>
+<UL>
+<LI><A HREF="#dns.background">Some DNS background</A></LI>
+<UL>
+<LI><A HREF="#forward.reverse">Forward and reverse maps</A></LI>
+<LI><A HREF="#17_1_2">Hierarchy and delegation</A></LI>
+<LI><A HREF="#17_1_3">Syntax of DNS records</A></LI>
+<LI><A HREF="#17_1_4">Cacheing, TTL and propagation delay</A></LI>
+</UL>
+<LI><A HREF="#MTU.trouble">Problems with packet fragmentation</A></LI>
+<LI><A HREF="#nat.background">Network address translation (NAT)</A></LI>
+<UL>
+<LI><A HREF="#17_3_1">NAT to non-routable addresses</A></LI>
+<LI><A HREF="#17_3_2">NAT to routable addresses</A></LI>
+</UL>
+</UL>
+<B><A HREF="#user.examples">FreeS/WAN script examples</A></B>
+<UL>
+<LI><A HREF="#poltorak">Poltorak's Firewall script</A></LI>
+</UL>
+<B><A HREF="#makecheck">How to configure to use &quot;make check&quot;</A></B>
+<UL>
+<LI><A HREF="#19_1">What is &quot;make check&quot;</A></LI>
+<LI><A HREF="#19_2">Running &quot;make check&quot;</A></LI>
+</UL>
+<B><A HREF="#20">How to write a &quot;make check&quot; test</A></B>
+<UL>
+<LI><A HREF="#20_1">Structure of a test</A></LI>
+<LI><A HREF="#20_2">The TESTLIST</A></LI>
+<LI><A HREF="#20_3">Test kinds</A></LI>
+<LI><A HREF="#20_4">Common parameters</A></LI>
+<LI><A HREF="#20_5">KLIPStest paramaters</A></LI>
+<LI><A HREF="#20_6">mkinsttest paramaters</A></LI>
+<LI><A HREF="#20_7">rpm_build_install_test paramaters</A></LI>
+<LI><A HREF="#20_8">libtest paramaters</A></LI>
+<LI><A HREF="#20_9">umlplutotest paramaters</A></LI>
+<LI><A HREF="#20_10">umlXhost parameters</A></LI>
+<LI><A HREF="#20_11">kernel_patch_test paramaters</A></LI>
+<LI><A HREF="#20_12">module_compile paramaters</A></LI>
+</UL>
+<B><A HREF="#21">Current pitfalls</A></B>
+<BR>
+<BR><B><A HREF="#umltesting">User-Mode-Linux Testing guide</A></B>
+<UL>
+<LI><A HREF="#22_1">Preliminary Notes on BIND</A></LI>
+<LI><A HREF="#22_2">Steps to Install UML for FreeS/WAN</A></LI>
+</UL>
+<B><A HREF="#23">Debugging the kernel with GDB</A></B>
+<UL>
+<LI><A HREF="#23_1">Other notes about debugging</A></LI>
+</UL>
+<B><A HREF="#24">User-Mode-Linux mysteries</A></B>
+<BR>
+<BR><B><A HREF="#25">Getting more info from uml_netjig</A></B>
+<BR>
+<BR><B><A HREF="#politics">History and politics of cryptography</A></B>
+<UL>
+<LI><A HREF="#intro.politics">Introduction</A></LI>
+<UL>
+<LI><A HREF="#26_1_1">History</A></LI>
+<UL>
+<LI><A HREF="#26_1_1_1">World War II</A></LI>
+<LI><A HREF="#postwar">Postwar and Cold War</A></LI>
+<LI><A HREF="#recent">Recent history -- the crypto wars</A></LI>
+</UL>
+<LI><A HREF="#intro.poli">Politics</A></LI>
+<LI><A HREF="#26_1_3">Links</A></LI>
+<LI><A HREF="#26_1_4">Outline of this section</A></LI>
+</UL>
+<LI><A HREF="#leader">From our project leader</A></LI>
+<UL>
+<LI><A HREF="#gilmore">Swan: Securing the Internet against Wiretapping</A>
+</LI>
+<UL>
+<LI><A HREF="#26_2_1_1">Deployment of IPSEC</A></LI>
+<LI><A HREF="#26_2_1_2">Current status</A></LI>
+<LI><A HREF="#26_2_1_3">Why?</A></LI>
+<LI><A HREF="#26_2_1_4">What You Can Do</A></LI>
+<LI><A HREF="#26_2_1_5">Related projects</A></LI>
+</UL>
+<LI><A HREF="#policestate">Stopping wholesale monitoring</A></LI>
+</UL>
+<LI><A HREF="#weak">Government promotion of weak crypto</A></LI>
+<UL>
+<LI><A HREF="#escrow">Escrowed encryption</A></LI>
+<LI><A HREF="#shortkeys">Limited key lengths</A></LI>
+<UL>
+<LI><A HREF="#26_3_2_1">Some real trade-offs</A></LI>
+</UL>
+</UL>
+<LI><A HREF="#exlaw">Cryptography Export Laws</A></LI>
+<UL>
+<LI><A HREF="#USlaw">US Law</A></LI>
+<UL>
+<LI><A HREF="#UScontrib">US contributions to FreeS/WAN</A></LI>
+</UL>
+<LI><A HREF="#wrong">What's wrong with restrictions on cryptography</A></LI>
+<LI><A HREF="#Wassenaar">The Wassenaar Arrangement</A></LI>
+<LI><A HREF="#status">Export status of Linux FreeS/WAN</A></LI>
+<LI><A HREF="#help">Help spread IPsec around</A></LI>
+</UL>
+<LI><A HREF="#desnotsecure">DES is Not Secure</A></LI>
+<UL>
+<LI><A HREF="#deshware">Dedicated hardware breaks DES in a few days</A></LI>
+<LI><A HREF="#spooks">Spooks may break DES faster yet</A></LI>
+<LI><A HREF="#desnet">Networks break DES in a few weeks</A></LI>
+<LI><A HREF="#no_des">We disable DES</A></LI>
+<LI><A HREF="#40joke">40-bits is laughably weak</A></LI>
+<LI><A HREF="#altdes">Triple DES is almost certainly secure</A></LI>
+<LI><A HREF="#aes.ipsec">AES in IPsec</A></LI>
+</UL>
+<LI><A HREF="#press">Press coverage of Linux FreeS/WAN:</A></LI>
+<UL>
+<LI><A HREF="#26_6_1">FreeS/WAN 1.0 press</A></LI>
+<LI><A HREF="#release">Press release for version 1.0</A></LI>
+</UL>
+</UL>
+<B><A HREF="#ipsec.detail">The IPsec protocols</A></B>
+<UL>
+<LI><A HREF="#27_1">Protocols and phases</A></LI>
+<LI><A HREF="#others">Applying IPsec</A></LI>
+<UL>
+<LI><A HREF="#advantages">Advantages of IPsec</A></LI>
+<LI><A HREF="#limitations">Limitations of IPsec</A></LI>
+<LI><A HREF="#uses">IPsec is a general mechanism for securing IP</A></LI>
+<LI><A HREF="#authonly">Using authentication without encryption</A></LI>
+<LI><A HREF="#encnoauth">Encryption without authentication is dangerous</A>
+</LI>
+<LI><A HREF="#multilayer">Multiple layers of IPsec processing are
+ possible</A></LI>
+<LI><A HREF="#traffic.resist">Resisting traffic analysis</A></LI>
+<UL>
+<LI><A HREF="#extra">Using &quot;unnecessary&quot; encryption</A></LI>
+<LI><A HREF="#multi-encrypt">Using multiple encryption</A></LI>
+<LI><A HREF="#fewer">Using fewer tunnels</A></LI>
+</UL>
+</UL>
+<LI><A HREF="#primitives">Cryptographic components</A></LI>
+<UL>
+<LI><A HREF="#block.cipher">Block ciphers</A></LI>
+<LI><A HREF="#hash.ipsec">Hash functions</A></LI>
+<UL>
+<LI><A HREF="#hmac.ipsec">The HMAC construct</A></LI>
+<LI><A HREF="#27_3_2_2">Choice of hash algorithm</A></LI>
+</UL>
+<LI><A HREF="#DH.keying">Diffie-Hellman key agreement</A></LI>
+<LI><A HREF="#RSA.auth">RSA authentication</A></LI>
+</UL>
+<LI><A HREF="#structure">Structure of IPsec</A></LI>
+<UL>
+<LI><A HREF="#IKE.ipsec">IKE (Internet Key Exchange)</A></LI>
+<UL>
+<LI><A HREF="#phases">Phases of IKE</A></LI>
+<LI><A HREF="#sequence">Sequence of messages in IKE</A></LI>
+<LI><A HREF="#struct.exchange">Structure of IKE messages</A></LI>
+</UL>
+<LI><A HREF="#services">IPsec Services, AH and ESP</A></LI>
+<LI><A HREF="#AH.ipsec">The Authentication Header (AH)</A></LI>
+<UL>
+<LI><A HREF="#keyed">Keyed MD5 and Keyed SHA</A></LI>
+<LI><A HREF="#sequence">Sequence numbers</A></LI>
+</UL>
+<LI><A HREF="#ESP.ipsec">Encapsulated Security Payload (ESP)</A></LI>
+</UL>
+<LI><A HREF="#modes">IPsec modes</A></LI>
+<UL>
+<LI><A HREF="#tunnel.ipsec">Tunnel mode</A></LI>
+<LI><A HREF="#transport.ipsec">Transport mode</A></LI>
+</UL>
+<LI><A HREF="#parts">FreeS/WAN parts</A></LI>
+<UL>
+<LI><A HREF="#KLIPS.ipsec">KLIPS: Kernel IPsec Support</A></LI>
+<LI><A HREF="#Pluto.ipsec">The Pluto daemon</A></LI>
+<LI><A HREF="#command">The ipsec(8) command</A></LI>
+<LI><A HREF="#ipsec.conf">Linux FreeS/WAN configuration file</A></LI>
+</UL>
+<LI><A HREF="#key">Key management</A></LI>
+<UL>
+<LI><A HREF="#current">Currently Implemented Methods</A></LI>
+<UL>
+<LI><A HREF="#manual">Manual keying</A></LI>
+<LI><A HREF="#auto">Automatic keying</A></LI>
+</UL>
+<LI><A HREF="#notyet">Methods not yet implemented</A></LI>
+<UL>
+<LI><A HREF="#noauth">Unauthenticated key exchange</A></LI>
+<LI><A HREF="#DNS">Key exchange using DNS</A></LI>
+<LI><A HREF="#PKI">Key exchange using a PKI</A></LI>
+<LI><A HREF="#photuris">Photuris</A></LI>
+<LI><A HREF="#skip">SKIP</A></LI>
+</UL>
+</UL>
+</UL>
+<B><A HREF="#lists">Mailing lists and newsgroups</A></B>
+<UL>
+<LI><A HREF="#list.fs">Mailing lists about FreeS/WAN</A></LI>
+<UL>
+<LI><A HREF="#projlist">The project mailing lists</A></LI>
+<UL>
+<LI><A HREF="#which.list">Which list should I use?</A></LI>
+<LI><A HREF="#policy.list">List policies</A></LI>
+</UL>
+<LI><A HREF="#archive">Archives of the lists</A></LI>
+</UL>
+<LI><A HREF="#indexes">Indexes of mailing lists</A></LI>
+<LI><A HREF="#otherlists">Lists for related software and topics</A></LI>
+<UL>
+<LI><A HREF="#28_3_1">Products that include FreeS/WAN</A></LI>
+<LI><A HREF="#linux.lists">Linux mailing lists</A></LI>
+<LI><A HREF="#ietf">Lists for IETF working groups</A></LI>
+<LI><A HREF="#other">Other mailing lists</A></LI>
+</UL>
+<LI><A HREF="#newsgroups">Usenet newsgroups</A></LI>
+</UL>
+<B><A HREF="#weblink">Web links</A></B>
+<UL>
+<LI><A HREF="#freeswan">The Linux FreeS/WAN Project</A></LI>
+<UL>
+<LI><A HREF="#patch">Add-ons and patches for FreeS/WAN</A></LI>
+<UL>
+<LI><A HREF="#29_1_1_1">Current patches</A></LI>
+<LI><A HREF="#29_1_1_2">Older patches</A></LI>
+<LI><A HREF="#VPN.masq">VPN masquerade patches</A></LI>
+</UL>
+<LI><A HREF="#dist">Distributions including FreeS/WAN</A></LI>
+<LI><A HREF="#used">Things FreeS/WAN uses or could use</A></LI>
+<LI><A HREF="#alternatives">Other approaches to VPNs for Linux</A></LI>
+</UL>
+<LI><A HREF="#ipsec.link">The IPsec Protocols</A></LI>
+<UL>
+<LI><A HREF="#general">General IPsec or VPN information</A></LI>
+<LI><A HREF="#overview">IPsec overview documents or slide sets</A></LI>
+<LI><A HREF="#otherlang">IPsec information in languages other than
+ English</A></LI>
+<LI><A HREF="#RFCs1">RFCs and other reference documents</A></LI>
+<LI><A HREF="#analysis">Analysis and critiques of IPsec protocols</A></LI>
+<LI><A HREF="#IP.background">Background information on IP</A></LI>
+</UL>
+<LI><A HREF="#implement">IPsec Implementations</A></LI>
+<UL>
+<LI><A HREF="#linuxprod">Linux products</A></LI>
+<LI><A HREF="#router">IPsec in router products</A></LI>
+<LI><A HREF="#fw.web">IPsec in firewall products</A></LI>
+<LI><A HREF="#ipsecos">Operating systems with IPsec support</A></LI>
+<LI><A HREF="#29_3_5">IPsec on network cards</A></LI>
+<LI><A HREF="#opensource">Open source IPsec implementations</A></LI>
+<UL>
+<LI><A HREF="#linuxipsec">Other Linux IPsec implementations</A></LI>
+<LI><A HREF="#BSD">IPsec for BSD Unix</A></LI>
+<LI><A HREF="#misc">IPsec for other systems</A></LI>
+</UL>
+<LI><A HREF="#interop.web">Interoperability</A></LI>
+<UL>
+<LI><A HREF="#result">Interoperability results</A></LI>
+<LI><A HREF="#test1">Interoperability test sites</A></LI>
+</UL>
+</UL>
+<LI><A HREF="#linux.link">Linux links</A></LI>
+<UL>
+<LI><A HREF="#linux.basic">Basic and tutorial Linux information</A></LI>
+<LI><A HREF="#general">General Linux sites</A></LI>
+<LI><A HREF="#docs.ldp">Documentation</A></LI>
+<LI><A HREF="#advroute.web">Advanced routing</A></LI>
+<LI><A HREF="#linsec">Security for Linux</A></LI>
+<LI><A HREF="#firewall.linux">Linux firewalls</A></LI>
+<LI><A HREF="#linux.misc">Miscellaneous Linux information</A></LI>
+</UL>
+<LI><A HREF="#crypto.link">Crypto and security links</A></LI>
+<UL>
+<LI><A HREF="#security">Crypto and security resources</A></LI>
+<UL>
+<LI><A HREF="#std.links">The standard link collections</A></LI>
+<LI><A HREF="#FAQ">Frequently Asked Question (FAQ) documents</A></LI>
+<LI><A HREF="#cryptover">Tutorials</A></LI>
+<LI><A HREF="#standards">Crypto and security standards</A></LI>
+<LI><A HREF="#quotes">Crypto quotes</A></LI>
+</UL>
+<LI><A HREF="#policy">Cryptography law and policy</A></LI>
+<UL>
+<LI><A HREF="#legal">Surveys of crypto law</A></LI>
+<LI><A HREF="#oppose">Organisations opposing crypto restrictions</A></LI>
+<LI><A HREF="#other.policy">Other information on crypto policy</A></LI>
+</UL>
+<LI><A HREF="#crypto.tech">Cryptography technical information</A></LI>
+<UL>
+<LI><A HREF="#cryptolinks">Collections of crypto links</A></LI>
+<LI><A HREF="#papers">Lists of online cryptography papers</A></LI>
+<LI><A HREF="#interesting">Particularly interesting papers</A></LI>
+</UL>
+<LI><A HREF="#compsec">Computer and network security</A></LI>
+<UL>
+<LI><A HREF="#seclink">Security links</A></LI>
+<LI><A HREF="#firewall.web">Firewall links</A></LI>
+<LI><A HREF="#vpn">VPN links</A></LI>
+<LI><A HREF="#tools">Security tools</A></LI>
+</UL>
+<LI><A HREF="#people">Links to home pages</A></LI>
+</UL>
+</UL>
+<B><A HREF="#ourgloss">Glossary for the Linux FreeS/WAN project</A></B>
+<UL>
+<LI><A HREF="#jump">Jump to a letter in the glossary</A></LI>
+<LI><A HREF="#gloss">Other glossaries</A></LI>
+<LI><A HREF="#definitions">Definitions</A></LI>
+</UL>
+<B><A HREF="#biblio">Bibliography for the Linux FreeS/WAN project</A></B>
+<BR>
+<BR><B><A HREF="#RFC">IPsec RFCs and related documents</A></B>
+<UL>
+<LI><A HREF="#RFCfile">The RFCs.tar.gz Distribution File</A></LI>
+<LI><A HREF="#sources">Other sources for RFCs &amp; Internet drafts</A></LI>
+<UL>
+<LI><A HREF="#RFCdown">RFCs</A></LI>
+<LI><A HREF="#drafts">Internet Drafts</A></LI>
+<LI><A HREF="#FIPS1">FIPS standards</A></LI>
+</UL>
+<LI><A HREF="#RFCs.tar.gz">What's in the RFCs.tar.gz bundle?</A></LI>
+<UL>
+<LI><A HREF="#rfc.ov">Overview RFCs</A></LI>
+<LI><A HREF="#basic.prot">Basic protocols</A></LI>
+<LI><A HREF="#key.ike">Key management</A></LI>
+<LI><A HREF="#rfc.detail">Details of various things used</A></LI>
+<LI><A HREF="#rfc.ref">Older RFCs which may be referenced</A></LI>
+<LI><A HREF="#rfc.dns">RFCs for secure DNS service, which IPsec may use</A>
+</LI>
+<LI><A HREF="#rfc.exp">RFCs labelled &quot;experimental&quot;</A></LI>
+<LI><A HREF="#rfc.rel">Related RFCs</A></LI>
+</UL>
+</UL>
+<B><A HREF="#roadmap">Distribution Roadmap: What's Where in Linux
+ FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="#top">Top directory</A></LI>
+<LI><A HREF="#doc">Documentation</A></LI>
+<LI><A HREF="#klips.roadmap">KLIPS: kernel IP security</A></LI>
+<LI><A HREF="#pluto.roadmap">Pluto key and connection management daemon</A>
+</LI>
+<LI><A HREF="#utils">Utils</A></LI>
+<LI><A HREF="#lib">Libraries</A></LI>
+<UL>
+<LI><A HREF="#fswanlib">FreeS/WAN Library</A></LI>
+<LI><A HREF="#otherlib">Imported Libraries</A></LI>
+<UL>
+<LI><A HREF="#33_6_2_1">LibDES</A></LI>
+<LI><A HREF="#33_6_2_2">GMP</A></LI>
+</UL>
+</UL>
+</UL>
+<B><A HREF="#umltesting">User-Mode-Linux Testing guide</A></B>
+<UL>
+<LI><A HREF="#34_1">Preliminary Notes on BIND</A></LI>
+<LI><A HREF="#34_2">Steps to Install UML for FreeS/WAN</A></LI>
+</UL>
+<B><A HREF="#35">Debugging the kernel with GDB</A></B>
+<UL>
+<LI><A HREF="#35_1">Other notes about debugging</A></LI>
+</UL>
+<B><A HREF="#36">User-Mode-Linux mysteries</A></B>
+<BR>
+<BR><B><A HREF="#37">Getting more info from uml_netjig</A></B>
+<BR>
+<BR><B><A HREF="#makecheck">How to configure to use &quot;make check&quot;</A></B>
+<UL>
+<LI><A HREF="#38_1">What is &quot;make check&quot;</A></LI>
+<LI><A HREF="#38_2">Running &quot;make check&quot;</A></LI>
+</UL>
+<B><A HREF="#39">How to write a &quot;make check&quot; test</A></B>
+<UL>
+<LI><A HREF="#39_1">Structure of a test</A></LI>
+<LI><A HREF="#39_2">The TESTLIST</A></LI>
+<LI><A HREF="#39_3">Test kinds</A></LI>
+<LI><A HREF="#39_4">Common parameters</A></LI>
+<LI><A HREF="#39_5">KLIPStest paramaters</A></LI>
+<LI><A HREF="#39_6">mkinsttest paramaters</A></LI>
+<LI><A HREF="#39_7">rpm_build_install_test paramaters</A></LI>
+<LI><A HREF="#39_8">libtest paramaters</A></LI>
+<LI><A HREF="#39_9">umlplutotest paramaters</A></LI>
+<LI><A HREF="#39_10">umlXhost parameters</A></LI>
+<LI><A HREF="#39_11">kernel_patch_test paramaters</A></LI>
+<LI><A HREF="#39_12">module_compile paramaters</A></LI>
+</UL>
+<B><A HREF="#40">Current pitfalls</A></B>
+<BR>
+<BR><B><A HREF="#nightly">Nightly regression testing</A></B>
+<BR>
+<BR><B><A HREF="#nightlyhowto">How to setup the nightly build</A></B>
+<UL>
+<LI><A HREF="#42_1"> Files you need to know about</A></LI>
+<LI><A HREF="#42_2">Configuring freeswan-regress-env.sh</A></LI>
+</UL>
+<HR>
+<H1><A name="intro">Introduction</A></H1>
+<P>This section gives an overview of:</P>
+<UL>
+<LI>what IP Security (IPsec) does</LI>
+<LI>how IPsec works</LI>
+<LI>why we are implementing it for Linux</LI>
+<LI>how this implementation works</LI>
+</UL>
+<P>This section is intended to cover only the essentials,<EM> things you
+ should know before trying to use FreeS/WAN.</EM></P>
+<P>For more detailed background information, see the<A href="#politics">
+ history and politics</A> and<A href="#ipsec.detail"> IPsec protocols</A>
+ sections.</P>
+<H2><A name="ipsec.intro">IPsec, Security for the Internet Protocol</A></H2>
+<P>FreeS/WAN is a Linux implementation of the IPsec (IP security)
+ protocols. IPsec provides<A href="#encryption"> encryption</A> and<A href="#authentication">
+ authentication</A> services at the IP (Internet Protocol) level of the
+ network protocol stack.</P>
+<P>Working at this level, IPsec can protect any traffic carried over IP,
+ unlike other encryption which generally protects only a particular
+ higher-level protocol --<A href="#PGP"> PGP</A> for mail,<A href="#ssh">
+ SSH</A> for remote login,<A href="#SSL"> SSL</A> for web work, and so
+ on. This approach has both considerable advantages and some
+ limitations. For discussion, see our<A href="#others"> IPsec section</A>
+</P>
+<P>IPsec can be used on any machine which does IP networking. Dedicated
+ IPsec gateway machines can be installed wherever required to protect
+ traffic. IPsec can also run on routers, on firewall machines, on
+ various application servers, and on end-user desktop or laptop
+ machines.</P>
+<P>Three protocols are used</P>
+<UL>
+<LI><A href="#AH">AH</A> (Authentication Header) provides a packet-level
+ authentication service</LI>
+<LI><A href="#ESP">ESP</A> (Encapsulating Security Payload) provides
+ encryption plus authentication</LI>
+<LI><A href="#IKE">IKE</A> (Internet Key Exchange) negotiates connection
+ parameters, including keys, for the other two</LI>
+</UL>
+<P>Our implementation has three main parts:</P>
+<UL>
+<LI><A href="#KLIPS">KLIPS</A> (kernel IPsec) implements AH, ESP, and
+ packet handling within the kernel</LI>
+<LI><A href="#Pluto">Pluto</A> (an IKE daemon) implements IKE,
+ negotiating connections with other systems</LI>
+<LI>various scripts provide an adminstrator's interface to the machinery</LI>
+</UL>
+<P>IPsec is optional for the current (version 4) Internet Protocol.
+ FreeS/WAN adds IPsec to the Linux IPv4 network stack. Implementations
+ of<A href="#ipv6.gloss"> IP version 6</A> are required to include
+ IPsec. Work toward integrating FreeS/WAN into the Linux IPv6 stack has<A
+href="#ipv6"> started</A>.</P>
+<P>For more information on IPsec, see our<A href="#ipsec.detail"> IPsec
+ protocols</A> section, our collection of<A href="#ipsec.link"> IPsec
+ links</A> or the<A href="#RFC"> RFCs</A> which are the official
+ definitions of these protocols.</P>
+<H3><A name="intro.interop">Interoperating with other IPsec
+ implementations</A></H3>
+<P>IPsec is designed to let different implementations work together. We
+ provide:</P>
+<UL>
+<LI>a<A href="#implement"> list</A> of some other implementations</LI>
+<LI>information on<A href="#interop"> using FreeS/WAN with other
+ implementations</A></LI>
+</UL>
+<P>The VPN Consortium fosters cooperation among implementers and
+ interoperability among implementations. Their<A href="http://www.vpnc.org/">
+ web site</A> has much more information.</P>
+<H3><A name="advantages">Advantages of IPsec</A></H3>
+<P>IPsec has a number of security advantages. Here are some
+ independently written articles which discuss these:</P>
+<P><A HREF="http://www.sans.org/rr/"> SANS institute papers</A>. See the
+ section on Encryption &amp;VPNs.
+<BR><A HREF="http://www.cisco.com/en/US/netsol/ns110/ns170/ns171/ns128/networking_solutions_white_papers_list.html">
+ Cisco's white papers on &quot;Networking Solutions&quot;</A>.
+<BR><A HREF="http://iscs.sourceforge.net/HowWhyBrief/HowWhyBrief.html">
+ Advantages of ISCS (Linux Integrated Secure Communications System;
+ includes FreeS/WAN and other software)</A>.</P>
+<H3><A name="applications">Applications of IPsec</A></H3>
+<P>Because IPsec operates at the network layer, it is remarkably
+ flexible and can be used to secure nearly any type of Internet traffic.
+ Two applications, however, are extremely widespread:</P>
+<UL>
+<LI>a<A href="#VPN"> Virtual Private Network</A>, or VPN, allows
+ multiple sites to communicate securely over an insecure Internet by
+ encrypting all communication between the sites.</LI>
+<LI>&quot;Road Warriors&quot; connect to the office from home, or perhaps from a
+ hotel somewhere</LI>
+</UL>
+<P>There is enough opportunity in these applications that vendors are
+ flocking to them. IPsec is being built into routers, into firewall
+ products, and into major operating systems, primarily to support these
+ applications. See our<A href="#implement"> list</A> of implementations
+ for details.</P>
+<P>We support both of those applications, and various less common IPsec
+ applications as well, but we also add one of our own:</P>
+<UL>
+<LI>opportunistic encryption, the ability to set up FreeS/WAN gateways
+ so that any two of them can encrypt to each other, and will do so
+ whenever packets pass between them.</LI>
+</UL>
+<P>This is an extension we are adding to the protocols. FreeS/WAN is the
+ first prototype implementation, though we hope other IPsec
+ implementations will adopt the technique once we demonstrate it. See<A href="#goals">
+ project goals</A> below for why we think this is important.</P>
+<P>A somewhat more detailed description of each of these applications is
+ below. Our<A href="#quick_guide"> quickstart</A> section will show you
+ how to build each of them.</P>
+<H4><A name="makeVPN">Using secure tunnels to create a VPN</A></H4>
+<P>A VPN, or<STRONG> V</STRONG>irtual<STRONG> P</STRONG>rivate<STRONG> N</STRONG>
+etwork lets two networks communicate securely when the only connection
+ between them is over a third network which they do not trust.</P>
+<P>The method is to put a security gateway machine between each of the
+ communicating networks and the untrusted network. The gateway machines
+ encrypt packets entering the untrusted net and decrypt packets leaving
+ it, creating a secure tunnel through it.</P>
+<P>If the cryptography is strong, the implementation is careful, and the
+ administration of the gateways is competent, then one can reasonably
+ trust the security of the tunnel. The two networks then behave like a
+ single large private network, some of whose links are encrypted tunnels
+ through untrusted nets.</P>
+<P>Actual VPNs are often more complex. One organisation may have fifty
+ branch offices, plus some suppliers and clients, with whom it needs to
+ communicate securely. Another might have 5,000 stores, or 50,000
+ point-of-sale devices. The untrusted network need not be the Internet.
+ All the same issues arise on a corporate or institutional network
+ whenever two departments want to communicate privately with each other.</P>
+<P>Administratively, the nice thing about many VPN setups is that large
+ parts of them are static. You know the IP addresses of most of the
+ machines involved. More important, you know they will not change on
+ you. This simplifies some of the admin work. For cases where the
+ addresses do change, see the next section.</P>
+<H4><A name="road.intro">Road Warriors</A></H4>
+<P>The prototypical &quot;Road Warrior&quot; is a traveller connecting to home
+ base from a laptop machine. Administratively, most of the same problems
+ arise for a telecommuter connecting from home to the office, especially
+ if the telecommuter does not have a static IP address.</P>
+<P>For purposes of this document:</P>
+<UL>
+<LI>anyone with a dynamic IP address is a &quot;Road Warrior&quot;.</LI>
+<LI>any machine doing IPsec processing is a &quot;gateway&quot;. Think of the
+ single-user road warrior machine as a gateway with a degenerate subnet
+ (one machine, itself) behind it.</LI>
+</UL>
+<P>These require somewhat different setup than VPN gateways with static
+ addresses and with client systems behind them, but are basically not
+ problematic.</P>
+<P>There are some difficulties which appear for some road warrior
+ connections:</P>
+<UL>
+<LI>Road Wariors who get their addresses via DHCP may have a problem.
+ FreeS/WAN can quite happily build and use a tunnel to such an address,
+ but when the DHCP lease expires, FreeS/WAN does not know that. The
+ tunnel fails, and the only recovery method is to tear it down and
+ re-build it.</LI>
+<LI>If<A href="#NAT.gloss"> Network Address Translation</A> (NAT) is
+ applied between the two IPsec Gateways, this breaks IPsec. IPsec
+ authenticates packets on an end-to-end basis, to ensure they are not
+ altered en route. NAT rewrites packets as they go by. See our<A href="#NAT">
+ firewalls</A> document for details.</LI>
+</UL>
+<P>In most situations, however, FreeS/WAN supports road warrior
+ connections just fine.</P>
+<H4><A name="opp.intro">Opportunistic encryption</A></H4>
+<P>One of the reasons we are working on FreeS/WAN is that it gives us
+ the opportunity to add what we call opportuntistic encryption. This
+ means that any two FreeS/WAN gateways will be able to encrypt their
+ traffic, even if the two gateway administrators have had no prior
+ contact and neither system has any preset information about the other.</P>
+<P>Both systems pick up the authentication information they need from
+ the<A href="#DNS"> DNS</A> (domain name service), the service they
+ already use to look up IP addresses. Of course the administrators must
+ put that information in the DNS, and must set up their gateways with
+ opportunistic encryption enabled. Once that is done, everything is
+ automatic. The gateways look for opportunities to encrypt, and encrypt
+ whatever they can. Whether they also accept unencrypted communication
+ is a policy decision the administrator can make.</P>
+<P>This technique can give two large payoffs:</P>
+<UL>
+<LI>It reduces the administrative overhead for IPsec enormously. You
+ configure your gateway and thereafter everything is automatic. The need
+ to configure the system on a per-tunnel basis disappears. Of course,
+ FreeS/WAN allows specifically configured tunnels to co-exist with
+ opportunistic encryption, but we hope to make them unnecessary in most
+ cases.</LI>
+<LI>It moves us toward a more secure Internet, allowing users to create
+ an environment where message privacy is the default. All messages can
+ be encrypted, provided the other end is willing to co-operate. See our<A
+href="#politics"> history and politics of cryptography</A> section for
+ discussion of why we think this is needed.</LI>
+</UL>
+<P>Opportunistic encryption is not (yet?) a standard part of the IPsec
+ protocols, but an extension we are proposing and demonstrating. For
+ details of our design, see<A href="#applied"> links</A> below.</P>
+<P>Only one current product we know of implements a form of
+ opportunistic encryption.<A href="#ssmail"> Secure sendmail</A> will
+ automatically encrypt server-to-server mail transfers whenever
+ possible.</P>
+<H3><A name="types">The need to authenticate gateways</A></H3>
+<P>A complication, which applies to any type of connection -- VPN, Road
+ Warrior or opportunistic -- is that a secure connection cannot be
+ created magically.<EM> There must be some mechanism which enables the
+ gateways to reliably identify each other.</EM> Without this, they
+ cannot sensibly trust each other and cannot create a genuinely secure
+ link.</P>
+<P>Any link they do create without some form of<A href="#authentication">
+ authentication</A> will be vulnerable to a<A href="#middle">
+ man-in-the-middle attack</A>. If<A href="#alicebob"> Alice and Bob</A>
+ are the people creating the connection, a villian who can re-route or
+ intercept the packets can pose as Alice while talking to Bob and pose
+ as Bob while talking to Alice. Alice and Bob then both talk to the man
+ in the middle, thinking they are talking to each other, and the villain
+ gets everything sent on the bogus &quot;secure&quot; connection.</P>
+<P>There are two ways to build links securely, both of which exclude the
+ man-in-the middle:</P>
+<UL>
+<LI>with<STRONG> manual keying</STRONG>, Alice and Bob share a secret
+ key (which must be transmitted securely, perhaps in a note or via PGP
+ or SSH) to encrypt their messages. For FreeS/WAN, such keys are stored
+ in the<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> file. Of
+ course, if an enemy gets the key, all is lost.</LI>
+<LI>with<STRONG> automatic keying</STRONG>, the two systems authenticate
+ each other and negotiate their own secret keys. The keys are
+ automatically changed periodically.</LI>
+</UL>
+<P>Automatic keying is much more secure, since if an enemy gets one key
+ only messages between the previous re-keying and the next are exposed.
+ It is therefore the usual mode of operation for most IPsec deployment,
+ and the mode we use in our setup examples. FreeS/WAN does support
+ manual keying for special circumstanes. See this<A href="#prodman">
+ section</A>.</P>
+<P>For automatic keying, the two systems must authenticate each other
+ during the negotiations. There is a choice of methods for this:</P>
+<UL>
+<LI>a<STRONG> shared secret</STRONG> provides authentication. If Alice
+ and Bob are the only ones who know a secret and Alice recives a message
+ which could not have been created without that secret, then Alice can
+ safely believe the message came from Bob.</LI>
+<LI>a<A href="#public"> public key</A> can also provide authentication.
+ If Alice receives a message signed with Bob's private key (which of
+ course only he should know) and she has a trustworthy copy of his
+ public key (so that she can verify the signature), then she can safely
+ believe the message came from Bob.</LI>
+</UL>
+<P>Public key techniques are much preferable, for reasons discussed<A href="#choose">
+ later</A>, and will be used in all our setup examples. FreeS/WAN does
+ also support auto-keying with shared secret authentication. See this<A href="#prodsecrets">
+ section</A>.</P>
+<H2><A name="project">The FreeS/WAN project</A></H2>
+<P>For complete information on the project, see our web site,<A href="http://liberty.freeswan.org">
+ freeswan.org</A>.</P>
+<P>In summary, we are implementing the<A href="#IPSEC"> IPsec</A>
+ protocols for Linux and extending them to do<A href="#carpediem">
+ opportunistic encryption</A>.</P>
+<H3><A name="goals">Project goals</A></H3>
+<P>Our overall goal in FreeS/WAN is to make the Internet more secure and
+ more private.</P>
+<P>Our IPsec implementation supports VPNs and Road Warriors of course.
+ Those are important applications. Many users will want FreeS/WAN to
+ build corporate VPNs or to provide secure remote access.</P>
+<P>However, our goals in building it go beyond that. We are trying to
+ help<STRONG> build security into the fabric of the Internet</STRONG> so
+ that anyone who choses to communicate securely can do so, as easily as
+ they can do anything else on the net.</P>
+<P>More detailed objectives are:</P>
+<UL>
+<LI>extend IPsec to do<A href="#carpediem"> opportunistic encryption</A>
+ so that
+<UL>
+<LI>any two systems can secure their communications without a
+ pre-arranged connection</LI>
+<LI><STRONG>secure connections can be the default</STRONG>, falling back
+ to unencrypted connections only if:
+<UL>
+<LI><EM>both</EM> the partner is not set up to co-operate on securing
+ the connection</LI>
+<LI><EM>and</EM> your policy allows insecure connections</LI>
+</UL>
+</LI>
+<LI>a significant fraction of all Internet traffic is encrypted</LI>
+<LI>wholesale monitoring of the net (<A href="#intro.poli">examples</A>)
+ becomes difficult or impossible</LI>
+</UL>
+</LI>
+<LI>help make IPsec widespread by providing an implementation with no
+ restrictions:
+<UL>
+<LI>freely available in source code under the<A href="#GPL"> GNU General
+ Public License</A></LI>
+<LI>running on a range of readily available hardware</LI>
+<LI>not subject to US or other nations'<A href="#exlaw"> export
+ restrictions</A>.
+<BR> Note that in order to avoid<EM> even the appearance</EM> of being
+ subject to those laws, the project cannot accept software contributions
+ --<EM> not even one-line bug fixes</EM> -- from US residents or
+ citizens.</LI>
+</UL>
+</LI>
+<LI>provide a high-quality IPsec implementation for Linux
+<UL>
+<LI>portable to all CPUs Linux supports:<A href="#CPUs"> (current list)</A>
+</LI>
+<LI>interoperable with other IPsec implementations:<A href="#interop">
+ (current list)</A></LI>
+</UL>
+</LI>
+</UL>
+<P>If we can get opportunistic encryption implemented and widely
+ deployed, then it becomes impossible for even huge well-funded agencies
+ to monitor the net.</P>
+<P>See also our section on<A href="#politics"> history and politics</A>
+ of cryptography, which includes our project leader's<A href="#gilmore">
+ rationale</A> for starting the project.</P>
+<H3><A name="staff">Project team</A></H3>
+<P>Two of the team are from the US and can therefore contribute no code:</P>
+<UL>
+<LI>John Gilmore: founder and policy-maker (<A href="http://www.toad.com/gnu/">
+home page</A>)</LI>
+<LI>Hugh Daniel: project manager, Most Demented Tester, and occasionally
+ Pointy-Haired Boss</LI>
+</UL>
+<P>The rest of the team are Canadians, working in Canada. (<A href="#status">
+Why Canada?</A>)</P>
+<UL>
+<LI>Hugh Redelmeier:<A href="#Pluto"> Pluto daemon</A> programmer</LI>
+<LI>Richard Guy Briggs:<A href="#KLIPS"> KLIPS</A> programmer</LI>
+<LI>Michael Richardson: hacker without portfolio</LI>
+<LI>Claudia Schmeing: documentation</LI>
+<LI>Sam Sgro: technical support via the<A href="#lists"> mailing lists</A>
+</LI>
+</UL>
+<P>The project is funded by civil libertarians who consider our goals
+ worthwhile. Most of the team are paid for this work.</P>
+<P>People outside this core team have made substantial contributions.
+ See</P>
+<UL>
+<LI>our<A href="../CREDITS"> CREDITS</A> file</LI>
+<LI>the<A href="#patch"> patches and add-ons</A> section of our web
+ references file</LI>
+<LI>lists below of user-written<A href="#howto"> HowTos</A> and<A href="#applied">
+ other papers</A></LI>
+</UL>
+<P>Additional contributions are welcome. See the<A href="#contrib.faq">
+ FAQ</A> for details.</P>
+<H2><A name="products">Products containing FreeS/WAN</A></H2>
+<P>Unfortunately the<A href="#exlaw"> export laws</A> of some countries
+ restrict the distribution of strong cryptography. FreeS/WAN is
+ therefore not in the standard Linux kernel and not in all CD or web
+ distributions.</P>
+<P>FreeS/WAN is, however, quite widely used. Products we know of that
+ use it are listed below. We would appreciate hearing, via the<A href="#lists">
+ mailing lists</A>, of any we don't know of.</P>
+<H3><A name="distwith">Full Linux distributions</A></H3>
+<P>FreeS/WAN is included in various general-purpose Linux distributions,
+ mostly from countries (shown in brackets) with more sensible laws:</P>
+<UL>
+<LI><A href="http://www.suse.com/">SuSE Linux</A> (Germany)</LI>
+<LI><A href="http://www.conectiva.com">Conectiva</A> (Brazil)</LI>
+<LI><A href="http://www.linux-mandrake.com/en/">Mandrake</A> (France)</LI>
+<LI><A href="http://www.debian.org">Debian</A></LI>
+<LI>the<A href="http://www.pld.org.pl/"> Polish(ed) Linux Distribution</A>
+ (Poland)</LI>
+<LI><A>Best Linux</A> (Finland)</LI>
+</UL>
+<P>For distributions which do not include FreeS/WAN and are not Redhat
+ (which we develop and test on), there is additional information in our<A
+href="#otherdist"> compatibility</A> section.</P>
+<P>The server edition of<A href="http://www.corel.com"> Corel</A> Linux
+ (Canada) also had FreeS/WAN, but Corel have dropped that product line.</P>
+<H3><A name="kernel_dist">Linux kernel distributions</A></H3>
+<UL>
+<LI><A href="http://sourceforge.net/projects/wolk/">Working Overloaded
+ Linux Kernel (WOLK)</A></LI>
+</UL>
+<H3><A name="office_dist">Office server distributions</A></H3>
+<P>FreeS/WAN is also included in several distributions aimed at the
+ market for turnkey business servers:</P>
+<UL>
+<LI><A href="http://www.e-smith.com/">e-Smith</A> (Canada), which has
+ recently been acquired and become the Network Server Solutions group of<A
+href="http://www.mitel.com/"> Mitel Networks</A> (Canada)</LI>
+<LI><A href="http://www.clarkconnect.org/">ClarkConnect</A> from Point
+ Clark Networks (Canada)</LI>
+<LI><A href="http://www.trustix.net/">Trustix Secure Linux</A> (Norway)</LI>
+</UL>
+<H3><A name="fw_dist">Firewall distributions</A></H3>
+<P>Several distributions intended for firewall and router applications
+ include FreeS/WAN:</P>
+<UL>
+<LI>The<A href="http://www.linuxrouter.org/"> Linux Router Project</A>
+ produces a Linux distribution that will boot from a single floppy. The<A
+href="http://leaf.sourceforge.net"> LEAF</A> firewall project provides
+ several different LRP-based firewall packages. At least one of them,
+ Charles Steinkuehler's Dachstein, includes FreeS/WAN with X.509
+ patches.</LI>
+<LI>there are several distributions bootable directly from CD-ROM,
+ usable on a machine without hard disk.
+<UL>
+<LI>Dachstein (see above) can be used this way</LI>
+<LI><A href="http://www.gibraltar.at/">Gibraltar</A> is based on Debian
+ GNU/Linux.</LI>
+<LI>at time of writing,<A href="www.xiloo.com"> Xiloo</A> is available
+ only in Chinese. An English version is expected.</LI>
+</UL>
+</LI>
+<LI><A href="http://www.astaro.com/products/index.html">Astaro Security
+ Linux</A> includes FreeS/WAN. It has some web-based tools for managing
+ the firewall that include FreeS/WAN configuration management.</LI>
+<LI><A href="http://www.linuxwall.de">Linuxwall</A></LI>
+<LI><A href="http://www.smoothwall.org/">Smoothwall</A></LI>
+<LI><A href="http://www.devil-linux.org/">Devil Linux</A></LI>
+<LI>Coyote Linux has a<A href="http://embedded.coyotelinux.com/wolverine/index.php">
+ Wolverine</A> firewall/VPN server</LI>
+</UL>
+<P>There are also several sets of scripts available for managing a
+ firewall which is also acting as a FreeS/WAN IPsec gateway. See this<A href="#rules.pub">
+ list</A>.</P>
+<H3><A name="turnkey">Firewall and VPN products</A></H3>
+<P>Several vendors use FreeS/WAN as the IPsec component of a turnkey
+ firewall or VPN product.</P>
+<P>Software-only products:</P>
+<UL>
+<LI><A href="http://www.linuxmagic.com/vpn/index.html">Linux Magic</A>
+ offer a VPN/Firewall product using FreeS/WAN</LI>
+<LI>The Software Group's<A href="http://www.wanware.com/sentinet/">
+ Sentinet</A> product uses FreeS/WAN</LI>
+<LI><A href="http://www.merilus.com">Merilus</A> use FreeS/WAN in their
+ Gateway Guardian firewall product</LI>
+</UL>
+<P>Products that include the hardware:</P>
+<UL>
+<LI>The<A href="http://www.lasat.com"> LASAT SafePipe[tm]</A> series. is
+ an IPsec box based on an embedded MIPS running Linux with FreeS/WAN and
+ a web-config front end. This company also host our freeswan.org web
+ site.</LI>
+<LI>Merilus<A href="http://www.merilus.com/products/fc/index.shtml">
+ Firecard</A> is a Linux firewall on a PCI card.</LI>
+<LI><A href="http://www.kyzo.com/">Kyzo</A> have a &quot;pizza box&quot; product
+ line with various types of server, all running from flash. One of them
+ is an IPsec/PPTP VPN server</LI>
+<LI><A href="http://www.pfn.com">PFN</A> use FreeS/WAN in some of their
+ products</LI>
+</UL>
+<P><A href="www.rebel.com">Rebel.com</A>, makers of the Netwinder Linux
+ machines (ARM or Crusoe based), had a product that used FreeS/WAN. The
+ company is in receivership so the future of the Netwinder is at best
+ unclear.<A href="#patch"> PKIX patches</A> for FreeS/WAN developed at
+ Rebel are listed in our web links document.</P>
+<H2><A name="docs">Information sources</A></H2>
+<H3><A name="docformats">This HowTo, in multiple formats</A></H3>
+<P>FreeS/WAN documentation up to version 1.5 was available only in HTML.
+ Now we ship two formats:</P>
+<UL>
+<LI>as HTML, one file for each doc section plus a global<A href="toc.html">
+ Table of Contents</A></LI>
+<LI><A href="HowTo.html">one big HTML file</A> for easy searching</LI>
+</UL>
+<P>and provide a Makefile to generate other formats if required:</P>
+<UL>
+<LI><A href="HowTo.pdf">PDF</A></LI>
+<LI><A href="HowTo.ps">Postscript</A></LI>
+<LI><A href="HowTo.txt">ASCII text</A></LI>
+</UL>
+<P>The Makefile assumes the htmldoc tool is available. You can download
+ it from<A href="http://www.easysw.com"> Easy Software</A>.</P>
+<P>All formats should be available at the following websites:</P>
+<UL>
+<LI><A href="http://www.freeswan.org/doc.html">FreeS/WAN project</A></LI>
+<LI><A href="http://www.linuxdoc.org">Linux Documentation Project</A></LI>
+</UL>
+<P>The distribution tarball has only the two HTML formats.</P>
+<P><STRONG>Note:</STRONG> If you need the latest doc version, for
+ example to see if anyone has managed to set up interoperation between
+ FreeS/WAN and whatever, then you should download the current snapshot.
+ What is on the web is documentation as of the last release. Snapshots
+ have all changes I've checked in to date.</P>
+<H3><A name="rtfm">RTFM (please Read The Fine Manuals)</A></H3>
+<P>As with most things on any Unix-like system, most parts of Linux
+ FreeS/WAN are documented in online manual pages. We provide a list of<A href="/mnt/floppy/manpages.html">
+ FreeS/WAN man pages</A>, with links to HTML versions of them.</P>
+<P>The man pages describing configuration files are:</P>
+<UL>
+<LI><A href="/mnt/floppy/manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A></LI>
+<LI><A href="/mnt/floppy/manpage.d/ipsec.secrets.5.html">
+ipsec.secrets(5)</A></LI>
+</UL>
+<P>Man pages for common commands include:</P>
+<UL>
+<LI><A href="/mnt/floppy/manpage.d/ipsec.8.html">ipsec(8)</A></LI>
+<LI><A href="/mnt/floppy/manpage.d/ipsec_pluto.8.html">ipsec_pluto(8)</A>
+</LI>
+<LI><A href="/mnt/floppy/manpage.d/ipsec_newhostkey.8.html">
+ipsec_newhostkey(8)</A></LI>
+<LI><A href="/mnt/floppy/manpage.d/ipsec_auto.8.html">ipsec_auto(8)</A></LI>
+</UL>
+<P>You can read these either in HTML using the links above or with the<VAR>
+ man(1)</VAR> command.</P>
+<P>In the event of disagreement between this HTML documentation and the
+ man pages, the man pages are more likely correct since they are written
+ by the implementers. Please report any such inconsistency on the<A href="#lists">
+ mailing list</A>.</P>
+<H3><A name="text">Other documents in the distribution</A></H3>
+<P>Text files in the main distribution directory are README, INSTALL,
+ CREDITS, CHANGES, BUGS and COPYING.</P>
+<P>The Libdes encryption library we use has its own documentation. You
+ can find it in the library directory..</P>
+<H3><A name="assumptions">Background material</A></H3>
+<P>Throughout this documentation, I write as if the reader had at least
+ a general familiarity with Linux, with Internet Protocol networking,
+ and with the basic ideas of system and network security. Of course that
+ will certainly not be true for all readers, and quite likely not even
+ for a majority.</P>
+<P>However, I must limit amount of detail on these topics in the main
+ text. For one thing, I don't understand all the details of those topics
+ myself. Even if I did, trying to explain everything here would produce
+ extremely long and almost completely unreadable documentation.</P>
+<P>If one or more of those areas is unknown territory for you, there are
+ plenty of other resources you could look at:</P>
+<DL>
+<DT>Linux</DT>
+<DD>the<A href="http://www.linuxdoc.org"> Linux Documentation Project</A>
+ or a local<A href="http://www.linux.org/groups/"> Linux User Group</A>
+ and these<A href="#linux.link"> links</A></DD>
+<DT>IP networks</DT>
+<DD>Rusty Russell's<A href="http://netfilter.samba.org/unreliable-guides/networking-concepts-HOWTO/index.html">
+ Networking Concepts HowTo</A> and these<A href="#IP.background"> links</A>
+</DD>
+<DT>Security</DT>
+<DD>Schneier's book<A href="#secrets"> Secrets and Lies</A> and these<A href="#crypto.link">
+ links</A></DD>
+</DL>
+<P>Also, I do make an effort to provide some background material in
+ these documents. All the basic ideas behind IPsec and FreeS/WAN are
+ explained here. Explanations that do not fit in the main text, or that
+ not everyone will need, are often in the<A href="#ourgloss"> glossary</A>
+, which is the largest single file in this document set. There is also a<A
+href="#background"> background</A> file containing various explanations
+ too long to fit in glossary definitions. All files are heavily
+ sprinkled with links to each other and to the glossary.<STRONG> If some
+ passage makes no sense to you, try the links</STRONG>.</P>
+<P>For other reference material, see the<A href="#biblio"> bibliography</A>
+ and our collection of<A href="web.html#weblinks"> web links</A>.</P>
+<P>Of course, no doubt I get this (and other things) wrong sometimes.
+ Feedback via the<A href="#lists"> mailing lists</A> is welcome.</P>
+<H3><A name="archives">Archives of the project mailing list</A></H3>
+<P>Until quite recently, there was only one FreeS/WAN mailing list, and
+ archives of it were:</P>
+<UL>
+<LI><A href="http://www.sandelman.ottawa.on.ca/linux-ipsec">Canada</A></LI>
+<LI><A href="http://www.nexial.com">Holland</A></LI>
+</UL>
+ The two archives use completely different search engines. You might
+ want to try both.
+<P>More recently we have expanded to five lists, each with its own
+ archive.</P>
+<P><A href="#lists">More information</A> on mailing lists.</P>
+<H3><A name="howto">User-written HowTo information</A></H3>
+<P>Various user-written HowTo documents are available. The ones covering
+ FreeS/WAN-to-FreeS/WAN connections are:</P>
+<UL>
+<LI>Jean-Francois Nadeau's<A href="http://jixen.tripod.com/"> practical
+ configurations</A> document</LI>
+<LI>Jens Zerbst's HowTo on<A href="http://dynipsec.tripod.com/"> Using
+ FreeS/WAN with dynamic IP addresses</A>.</LI>
+<LI>an entry in Kurt Seifried's<A href="http://www.securityportal.com/lskb/kben00000013.html">
+ Linux Security Knowledge Base</A>.</LI>
+<LI>a section of David Ranch's<A href="http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos">
+ Trinity OS Guide</A></LI>
+<LI>a section in David Bander's book<A href="#bander"> Linux Security
+ Toolkit</A></LI>
+</UL>
+<P>User-wriiten HowTo material may be<STRONG> especially helpful if you
+ need to interoperate with another IPsec implementation</STRONG>. We
+ have neither the equipment nor the manpower to test such
+ configurations. Users seem to be doing an admirable job of filling the
+ gaps.</P>
+<UL>
+<LI>list of user-written<A href="interop.html#otherpub"> interoperation
+ HowTos</A> in our interop document</LI>
+</UL>
+<P>Check what version of FreeS/WAN user-written documents cover. The
+ software is under active development and the current version may be
+ significantly different from what an older document describes.</P>
+<H3><A name="applied">Papers on FreeS/WAN</A></H3>
+<P>Two design documents show team thinking on new developments:</P>
+<UL>
+<LI><A href="opportunism.spec">Opportunistic Encryption</A> by technical
+ lead Henry Spencer and Pluto programmer Hugh Redelemeier</LI>
+<LI>discussion of<A href="http://www.sandelman.ottawa.on.ca/SSW/freeswan/klips2req/">
+ KLIPS redesign</A></LI>
+</UL>
+<P>Both documents are works in progress and are frequently revised. For
+ the latest version, see the<A href="#lists"> design mailing list</A>.
+ Comments should go to that list.</P>
+<P>There is now an<A href="http://www.ietf.org/internet-drafts/draft-richardson-ipsec-opportunistic-06.txt">
+ Internet Draft on Opportunistic Encryption</A> by Michael Richardson,
+ Hugh Redelmeier and Henry Spencer. This is a first step toward getting
+ the protocol standardised so there can be multiple implementations of
+ it. Discussion of it takes place on the<A href="http://www.ietf.org/html.charters/ipsec-charter.html">
+ IETF IPsec Working Group</A> mailing list.</P>
+<P>A number of papers giving further background on FreeS/WAN, or
+ exploring its future or its applications, are also available:</P>
+<UL>
+<LI>Both Henry and Richard gave talks on FreeS/WAN at the 2000<A href="http://www.linuxsymposium.org">
+ Ottawa Linux Symposium</A>.
+<UL>
+<LI>Richard's<A href="http://www.conscoop.ottawa.on.ca/rgb/freeswan/ols2k/">
+ slides</A></LI>
+<LI>Henry's paper</LI>
+<LI>MP3 audio of their talks is available from the<A href="http://www.linuxsymposium.org/">
+ conference page</A></LI>
+</UL>
+</LI>
+<LI><CITE>Moat: A Virtual Private Network Appliances and Services
+ Platform</CITE> is a paper about large-scale (a few 100 links) use of
+ FreeS/WAN in a production application at AT&amp;T Research. It is available
+ in Postscript or PDF from co-author Steve Bellovin's<A href="http://www.research.att.com/~smb/papers/index.html">
+ papers list page</A>.</LI>
+<LI>One of the Moat co-authors, John Denker, has also written
+<UL>
+<LI>a<A href="http://www.av8n.com/vpn/ipsec+routing.htm"> proposal</A>
+ for how future versions of FreeS/WAN might interact with routing
+ protocols</LI>
+<LI>a<A href="http://www.av8n.com/vpn/wishlist.htm"> wishlist</A> of
+ possible new features</LI>
+</UL>
+</LI>
+<LI>Bart Trojanowski's web page has a draft design for<A href="http://www.jukie.net/~bart/linux-ipsec/">
+ hardware acceleration</A> of FreeS/WAN</LI>
+</UL>
+<P>Several of these provoked interesting discussions on the mailing
+ lists, worth searching for in the<A href="#archive"> archives</A>.</P>
+<P>There are also several papers in languages other than English, see
+ our<A href="#otherlang"> web links</A>.</P>
+<H3><A name="licensing">License and copyright information</A></H3>
+<P>All code and documentation written for this project is distributed
+ under either the GNU General Public License (<A href="#GPL">GPL</A>) or
+ the GNU Library General Public License. For details see the COPYING
+ file in the distribution.</P>
+<P>Not all code in the distribution is ours, however. See the CREDITS
+ file for details. In particular, note that the<A href="#LIBDES"> Libdes</A>
+ library and the version of<A href="#MD5"> MD5</A> that we use each have
+ their own license.</P>
+<H2><A name="sites">Distribution sites</A></H2>
+<P>FreeS/WAN is available from a number of sites.</P>
+<H3><A NAME="1_5_1">Primary site</A></H3>
+<P>Our primary site, is at xs4all (Thanks, folks!) in Holland:</P>
+<UL>
+<LI><A href="http://www.xs4all.nl/~freeswan">HTTP</A></LI>
+<LI><A href="ftp://ftp.xs4all.nl/pub/crypto/freeswan">FTP</A></LI>
+</UL>
+<H3><A name="mirrors">Mirrors</A></H3>
+<P>There are also mirror sites all over the world:</P>
+<UL>
+<LI><A href="http://www.flora.org/freeswan">Eastern Canada</A> (limited
+ resouces)</LI>
+<LI><A href="ftp://ludwig.doculink.com/pub/freeswan/">Eastern Canada</A>
+ (has older versions too)</LI>
+<LI><A href="ftp://ntsc.notBSD.org/pub/crypto/freeswan/">Eastern Canada</A>
+ (has older versions too)</LI>
+<LI><A href="ftp://ftp.kame.net/pub/freeswan/">Japan</A></LI>
+<LI><A href="ftp://ftp.futuredynamics.com/freecrypto/FreeSWAN/">Hong
+ Kong</A></LI>
+<LI><A href="ftp://ipsec.dk/pub/freeswan/">Denmark</A></LI>
+<LI><A href="ftp://ftp.net.lut.ac.uk/freeswan">the UK</A></LI>
+<LI><A href="http://storm.alert.sk/comp/mirrors/freeswan/">Slovak
+ Republic</A></LI>
+<LI><A href="http://the.wiretapped.net/security/vpn-tunnelling/freeswan/">
+Australia</A></LI>
+<LI><A href="http://freeswan.technolust.cx/">technolust</A></LI>
+<LI><A href="http://freeswan.devguide.de/">Germany</A></LI>
+<LI>Ivan Moore's<A href="http://snowcrash.tdyc.com/freeswan/"> site</A></LI>
+<LI>the<A href="http://www.cryptoarchive.net/"> Crypto Archive</A> on
+ the<A href="http://www.securityportal.com/"> Security Portal</A> site</LI>
+<LI><A href="http://www.wiretapped.net/">Wiretapped.net</A> in Australia</LI>
+</UL>
+<P>Thanks to those folks as well.</P>
+<H3><A name="munitions">The &quot;munitions&quot; archive of Linux crypto software</A>
+</H3>
+<P>There is also an archive of Linux crypto software called &quot;munitions&quot;,
+ with its own mirrors in a number of countries. It includes FreeS/WAN,
+ though not always the latest version. Some of its sites are:</P>
+<UL>
+<LI><A href="http://munitions.vipul.net/">Germany</A></LI>
+<LI><A href="http://munitions.iglu.cjb.net/">Italy</A></LI>
+<LI><A href="http://munitions2.xs4all.nl/">Netherlands</A></LI>
+</UL>
+<P>Any of those will have a list of other &quot;munitions&quot; mirrors. There is
+ also a CD available.</P>
+<H2><A NAME="1_6">Links to other sections</A></H2>
+<P>For more detailed background information, see:</P>
+<UL>
+<LI><A href="#politics">history and politics</A> of cryptography</LI>
+<LI><A href="#ipsec.detail">IPsec protocols</A></LI>
+</UL>
+<P>To begin working with FreeS/WAN, go to our<A href="quickstart.html#quick.guide">
+ quickstart</A> guide.</P>
+<HR>
+<A NAME="upgrading"></A>
+<H1><A NAME="2">Upgrading to FreeS/WAN 2.x</A></H1>
+<H2><A NAME="2_1">New! Built in Opportunistic connections</A></H2>
+<P>Out of the box, FreeS/WAN 2.x will attempt to encrypt all your IP
+ traffic. It will try to establish IPsec connections for:</P>
+<UL>
+<LI> IP traffic from the Linux box on which you have installed
+ FreeS/WAN, and</LI>
+<LI> outbound IP traffic routed through that Linux box (eg. from a
+ protected subnet).</LI>
+</UL>
+<P>FreeS/WAN 2.x uses<STRONG> hidden, automatically enabled<VAR>
+ ipsec.conf</VAR> connections</STRONG> to do this.</P>
+<P>This behaviour is part of our campaign to get Opportunistic
+ Encryption (OE) widespread in the Linux world, so that any two Linux
+ boxes can encrypt to one another without prearrangement. There's one
+ catch, however: you must<A HREF="#quickstart"> set up a few DNS records</A>
+ to distribute RSA public keys and (if applicable) IPsec gateway
+ information.</P>
+<P>If you start FreeS/WAN before you have set up these DNS records, your
+ connectivity will be slow, and messages relating to the built in
+ connections will clutter your logs. If you are unable to set up DNS for
+ OE, you will wish to<A HREF="#disable_policygroups"> disable the hidden
+ connections</A>.</P>
+<A NAME="upgrading.flagday"></A>
+<H3><A NAME="2_1_1">Upgrading Opportunistic Encryption to 2.01 (or
+ later)</A></H3>
+<P>As of FreeS/WAN 2.01, Opportunistic Encryption (OE) uses DNS TXT
+ resource records (RRs) only (rather than TXT with KEY). This change
+ causes a &quot;flag day&quot;. Users of FreeS/WAN 2.00 (or earlier) OE who are
+ upgrading may need to post additional resource records.</P>
+<P>If you are running<A HREF="#initiate-only"> initiate-only OE</A>, you<EM>
+ must</EM> put up a TXT record in any forward domain as per our<A HREF="#opp.client">
+ quickstart instructions</A>. This replaces your old forward KEY.</P>
+<P> If you are running full OE, you require no updates. You already have
+ the needed TXT record in the reverse domain. However, to facilitate
+ future features, you may also wish to publish that TXT record in a
+ forward domain as instructed<A HREF="#opp.incoming"> here</A>.</P>
+<P>If you are running OE on a gateway (and encrypting on behalf of
+ subnetted boxes) you require no updates. You already have the required
+ TXT record in your gateway's reverse map, and the TXT records for any
+ subnetted boxes require no updating. However, to facilitate future
+ features, you may wish to publish your gateway's TXT record in a
+ forward domain as shown<A HREF="#opp.incoming"> here</A>.</P>
+<P> During the transition, you may wish to leave any old KEY records up
+ for some time. They will provide limited backward compatibility.
+<!--
+For more
+detail on that compatibility, see <A HREF="oe.known-issues">Known Issues with
+OE</A>.
+-->
+</P>
+<H2><A NAME="2_2">New! Policy Groups</A></H2>
+<P>We want to make it easy for you to declare security policy as it
+ applies to IPsec connections.</P>
+<P>Policy Groups make it simple to say:</P>
+<UL>
+<LI>These are the folks I want to talk to in the clear.</LI>
+<LI>These spammers' domains -- I don't want to talk to them at all.</LI>
+<LI>To talk to the finance department, I must use IPsec.</LI>
+<LI>For any other communication, try to encrypt, but it's okay if we
+ can't.</LI>
+</UL>
+<P>FreeS/WAN then implements these policies, creating OE connections if
+ and when needed. You can use Policy Groups along with connections you
+ explicitly define in ipsec.conf.</P>
+<P>For more information, see our<A HREF="policygroups.html"> Policy
+ Group HOWTO</A>.</P>
+<H2><A NAME="2_3">New! Packetdefault Connection</A></H2>
+<P>Free/SWAN 2.x ships with the<STRONG> automatically enabled, hidden
+ connection</STRONG><VAR> packetdefault</VAR>. This configures a
+ FreeS/WAN box as an OE gateway for any hosts located behind it. As
+ mentioned above, you must configure some<A HREF="quickstart.html"> DNS
+ records</A> for OE to work.</P>
+<P>As the name implies, this connection functions as a default. If you
+ have more specific connections, such as policy groups which configure
+ your FreeS/WAN box as an OE gateway for a local subnet, these will
+ apply before<VAR> packetdefault</VAR>. You can view<VAR> packetdefault</VAR>
+'s specifics in<A HREF="manpage.d/ipsec.conf.5.html"> man ipsec.conf</A>
+.</P>
+<H2><A NAME="2_4">FreeS/WAN now disables Reverse Path Filtering</A></H2>
+<P>FreeS/WAN often doesn't work with reverse path filtering. At start
+ time, FreeS/WAN now turns rp_filter off, and logs a warning.</P>
+<P>FreeS/WAN does not turn it back on again. You can do this yourself
+ with a command like:</P>
+<PRE> echo 1 &gt; /proc/sys/net/ipv4/conf/eth0/rp_filter</PRE>
+<P>For eth0, substitute the interface which FreeS/WAN was affecting.</P>
+<A NAME="ipsec.conf_v2"></A>
+<H2><A NAME="2_5">Revised<VAR> ipsec.conf</VAR></A></H2>
+<H3><A NAME="2_5_1">No promise of compatibility</A></H3>
+<P>The FreeS/WAN team promised config-file compatibility throughout the
+ 1.x series. That means a 1.5 config file can be directly imported into
+ a fresh 1.99 install with no problems.</P>
+<P>With FreeS/WAN 2.x, we've given ourselves permission to make the
+ config file easier to use. The cost: some FreeS/WAN 1.x configurations
+ will not work properly. Many of the new features are, however, backward
+ compatible.</P>
+<H3><A NAME="2_5_2">Most<VAR> ipsec.conf</VAR> files will work fine</A></H3>
+<P>... so long as you paste this line,<STRONG> with no preceding
+ whitespace</STRONG>, at the top of your config file:</P>
+<PRE> version 2</PRE>
+<H3><A NAME="2_5_3">Backward compatibility patch</A></H3>
+<P>If the new defaults bite you, use<A HREF="ipsec.conf.2_to_1"> this<VAR>
+ ipsec.conf</VAR> fragment</A> to simulate the old default values.</P>
+<H3><A NAME="2_5_4">Details</A></H3>
+<P> We've obsoleted various directives which almost no one was using:</P>
+<PRE> dump
+ plutobackgroundload
+ no_eroute_pass
+ lifetime
+ rekeystart
+ rekeytries</PRE>
+<P>For most of these, there is some other way to elicit the desired
+ behaviour. See<A HREF="http://lists.freeswan.org/pipermail/design/2002-August/003243.html">
+ this post</A>.</P>
+<P> We've made some settings, which almost everyone was using, defaults.
+ For example:</P>
+<PRE> interfaces=%defaultroute
+ plutoload=%search
+ plutostart=%search
+ uniqueids=yes</PRE>
+<P>We've also changed some default values to help with OE and Policy
+ Groups:</P>
+<PRE> authby=rsasig ## not secret!!!
+ leftrsasigkey=%dnsondemand ## looks up missing keys in DNS when needed.
+ rightrsasigkey=%dnsondemand</PRE>
+<P> Of course, you can still override any defaults by explictly
+ declaring something else in your connection.</P>
+<P><A HREF="http://lists.freeswan.org/pipermail/design/2002-August/003243.html">
+ A post with a list of many ipsec.conf changes.</A>
+<BR><A HREF="manpage.d/ipsec.conf.5.html"> Current ipsec.conf manual.</A>
+</P>
+<A NAME="upgrading.rpms"></A>
+<H3><A NAME="2_5_5">Upgrading from 1.x RPMs to 2.x RPMs</A></H3>
+<P>Note: When upgrading from 1-series to 2-series RPMs,<VAR> rpm -U</VAR>
+ will not work.</P>
+<P>You must instead erase the 1.x RPMs, then install the 2.x set:</P>
+<PRE> rpm -e freeswan</PRE>
+<PRE> rpm -e freeswan-module</PRE>
+<P>On erasing, your old<VAR> ipsec.conf</VAR> should be moved to<VAR>
+ ipsec.conf.rpmsave</VAR>. Keep this. You will probably want to copy
+ your existing connections to the end of your new 2.x file.</P>
+<P>Install the RPMs suitable for your kernel version, such as:</P>
+<PRE> rpm -ivh freeswan-module-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<PRE> rpm -ivh freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<P>Or, to splice the files:</P>
+<PRE> cat /etc/ipsec.conf /etc/ipsec.conf.rpmsave &gt; /etc/ipsec.conf.tmp
+ mv /etc/ipsec.conf.tmp /etc/ipsec.conf</PRE>
+<P>Then, remove the redundant<VAR> conn %default</VAR> and<VAR> config
+ setup</VAR> sections. Unless you have done any special configuring
+ here, you'll likely want to remove the 1.x versions. Remove<VAR> conn
+ OEself</VAR>, if present.</P>
+<HR>
+<H1><A name="quickstart">Quickstart Guide to Opportunistic Encryption</A>
+</H1>
+<A name="quick_guide"></A>
+<H2><A name="opp.setup">Purpose</A></H2>
+<P>This page will get you started using Linux FreeS/WAN with
+ opportunistic encryption (OE). OE enables you to set up IPsec tunnels
+ without co-ordinating with another site administrator, and without hand
+ configuring each tunnel. If enough sites support OE, a &quot;FAX effect&quot;
+ occurs, and many of us can communicate without eavesdroppers.</P>
+<H3><A NAME="3_1_1">OE &quot;flag day&quot;</A></H3>
+<P>As of FreeS/WAN 2.01, OE uses DNS TXT resource records (RRs) only
+ (rather than TXT with KEY). This change causes a<A href="http://jargon.watson-net.com/jargon.asp?w=flag+day">
+ &quot;flag day&quot;</A>. Users of FreeS/WAN 2.00 (or earlier) OE who are
+ upgrading may require additional resource records, as detailed in our<A href="#upgrading.flagday">
+ upgrading document</A>. OE setup instructions here are for 2.02 or
+ later.</P>
+<H2><A name="opp.dns">Requirements</A></H2>
+<P>To set up opportunistic encryption, you will need:</P>
+<UL>
+<LI>a Linux box. For OE to the public Internet, this box must NOT be
+ behind<A HREF="#NAT.gloss"> Network Address Translation</A> (NAT).</LI>
+<LI>to install Linux FreeS/WAN 2.02 or later</LI>
+<LI>either control over your reverse DNS (for full opportunism) or the
+ ability to write to some forward domain (for initiator-only).<A HREF="http://www.fdns.net">
+ This free DNS service</A> explicitly supports forward TXT records for
+ FreeS/WAN use.</LI>
+<LI>(for full opportunism) a static IP</LI>
+</UL>
+<P>Note: Currently, only Linux FreeS/WAN supports opportunistic
+ encryption.</P>
+<H2><A name="easy.install">RPM install</A></H2>
+<P>Our instructions are for a recent Red Hat with a 2.4-series stock or
+ Red Hat updated kernel. For other ways to install, see our<A href="#install">
+ install document</A>.</P>
+<H3><A NAME="3_3_1">Download RPMs</A></H3>
+<P>If we have prebuilt RPMs for your Red Hat system, this command will
+ get them:</P>
+<PRE> ncftpget ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs/`uname -r | tr -d 'a-wy-z'`/\*</PRE>
+<P>If that fails, you will need to try<A HREF="install.html"> another
+ install method</A>. Our kernel modules<B> will only work on the Red Hat
+ kernel they were built for</B>, since they are very sensitive to small
+ changes in the kernel.</P>
+<P>If it succeeds, you will have userland tools, a kernel module, and an
+ RPM signing key:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm
+ freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm
+ freeswan-rpmsign.asc</PRE>
+<H3><A NAME="3_3_2">Check signatures</A></H3>
+<P>If you're running RedHat 8.x or later, import the RPM signing key
+ into the RPM database:</P>
+<PRE> rpm --import freeswan-rpmsign.asc</PRE>
+<P>For RedHat 7.x systems, you'll need to add it to your<A HREF="#PGP">
+ PGP</A> keyring:</P>
+<PRE> pgp -ka freeswan-rpmsign.asc</PRE>
+<P>Check the digital signatures on both RPMs using:</P>
+<PRE> rpm --checksig freeswan*.rpm </PRE>
+<P>You should see that these signatures are good:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK
+ freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK</PRE>
+<H3><A NAME="3_3_3">Install the RPMs</A></H3>
+<P>Become root:</P>
+<PRE> su</PRE>
+<P>Install your RPMs with:</P>
+<P></P>
+<PRE> rpm -ivh freeswan*.rpm</PRE>
+<P>If you're upgrading from FreeS/WAN 1.x RPMs, and have problems with
+ that command, see<A HREF="#upgrading.rpms"> this note</A>.</P>
+<P>Then, start FreeS/WAN:</P>
+<PRE> service ipsec start</PRE>
+<H3><A name="testinstall">Test</A></H3>
+<P>To check that you have a successful install, run:</P>
+<PRE> ipsec verify</PRE>
+<P>You should see as part of the<VAR> verify</VAR> output:</P>
+<PRE>
+ Checking your system to see if IPsec got installed and started correctly
+ Version check and ipsec on-path [OK]
+ Checking for KLIPS support in kernel [OK]
+ Checking for RSA private key (/etc/ipsec.secrets) [OK]
+ Checking that pluto is running [OK]
+ ...</PRE>
+<P>If any of these first four checks fails, see our<A href="#install.check">
+ troubleshooting guide</A>.</P>
+<H2><A name="opp.setups.list">Our Opportunistic Setups</A></H2>
+<H3><A NAME="3_4_1">Full or partial opportunism?</A></H3>
+<P>Determine the best form of opportunism your system can support.</P>
+<UL>
+<LI>For<A HREF="#opp.incoming"> full opportunism</A>, you'll need a
+ static IP and and either control over your reverse DNS or an ISP that
+ can add the required TXT record for you.</LI>
+<LI>If you have a dynamic IP, and/or write access to forward DNS only,
+ you can do<A HREF="#opp.client"> initiate-only opportunism</A></LI>
+<LI>To protect traffic bound for real IPs behind your gateway, use<A HREF="#opp.gate">
+ this form of full opportunism</A>.</LI>
+</UL>
+<H2><A name="opp.client">Initiate-only setup</A></H2>
+<H3><A NAME="3_5_1">Restrictions</A></H3>
+<P>When you set up initiate-only Opportunistic Encryption (iOE):</P>
+<UL>
+<LI>there will be<STRONG> no incoming connection requests</STRONG>; you
+ can initiate all the IPsec connections you need.</LI>
+<LI><STRONG>only one machine is visible</STRONG> on your end of the
+ connection.</LI>
+<LI>iOE also protects traffic on behalf of<A HREF="#NAT.gloss"> NATted</A>
+ hosts behind the iOE box.</LI>
+</UL>
+<P>You cannot network a group of initiator-only machines if none of
+ these is capable of responding to OE. If one is capable of responding,
+ you may be able to create a hub topology using routing.</P>
+<H3><A name="forward.dns">Create and publish a forward DNS record</A></H3>
+<H4><A NAME="3_5_2_1">Find a domain you can use</A></H4>
+<P>Find a DNS forward domain (e.g. example.com) where you can publish
+ your key. You'll need access to the DNS zone files for that domain.
+ This is common for a domain you own. Some free DNS providers, such as<A HREF="http://www.fdns.net">
+ this one</A>, also provide this service.</P>
+<P>Dynamic IP users take note: the domain where you place your key need
+ not be associated with the IP address for your system, or even with
+ your system's usual hostname.</P>
+<H4><A NAME="3_5_2_2">Choose your ID</A></H4>
+<P>Choose a name within that domain which you will use to identify your
+ machine. It's convenient if this can be the same as your hostname:</P>
+<PRE> [root@xy root]# hostname --fqdn
+ xy.example.com</PRE>
+<P>This name in FQDN (fully-qualified domain name) format will be your
+ ID, for DNS key lookup and IPsec negotiation.</P>
+<H4><A NAME="3_5_2_3">Create a forward TXT record</A></H4>
+<P>Generate a forward TXT record containing your system's public key
+ with a command like:</P>
+<PRE> ipsec showhostkey --txt @xy.example.com</PRE>
+<P>using your chosen ID in place of xy.example.com. This command takes
+ the contents of /etc/ipsec.secrets and reformats it into something
+ usable by ISC's BIND. The result should look like this (with the key
+ data trimmed down for clarity):</P>
+<PRE>
+ ; RSA 2192 bits xy.example.com Thu Jan 2 12:41:44 2003
+ IN TXT &quot;X-IPsec-Server(10)=@xy.example.com&quot;
+ &quot;AQOF8tZ2... ...+buFuFn/&quot;
+</PRE>
+<H4><A NAME="3_5_2_4">Publish the forward TXT record</A></H4>
+<P>Insert the record into DNS, or have a system adminstrator do it for
+ you. It may take up to 48 hours for the record to propagate, but it's
+ usually much quicker.</P>
+<H3><A NAME="3_5_3">Test that your key has been published</A></H3>
+<P>Check your DNS work</P>
+<PRE> ipsec verify --host xy.example.com</PRE>
+<P>As part of the<VAR> verify</VAR> output, you ought to see something
+ like:</P>
+<PRE> ...
+ Looking for TXT in forward map: xy.example.com [OK]
+ ...</PRE>
+<P>For this type of opportunism, only the forward test is relevant; you
+ can ignore the tests designed to find reverse records.</P>
+<H3><A NAME="3_5_4">Configure, if necessary</A></H3>
+<P> If your ID is the same as your hostname, you're ready to go.
+ FreeS/WAN will use its<A HREF="policygroups.html"> built-in connections</A>
+ to create your iOE functionality.</P>
+<P>If you have chosen a different ID, you must tell FreeS/WAN about it
+ via<A HREF="manpage.d/ipsec.conf.5.html"><VAR> ipsec.conf</VAR></A>:</P>
+<PRE> config setup
+ myid=@myname.freedns.example.com</PRE>
+<P>and restart FreeS/WAN:</P>
+<PRE> service ipsec restart</PRE>
+<P>The new ID will be applied to the built-in connections.</P>
+<P>Note: you can create more complex iOE configurations as explained in
+ our<A HREF="#policygroups"> policy groups document</A>, or disable OE
+ using<A HREF="#disable_policygroups"> these instructions</A>.</P>
+<H3><A NAME="3_5_5">Test</A></H3>
+<P>That's it!<A HREF="#opp.test"> Test your connections</A>.</P>
+<A name="opp.incoming"></A>
+<H2><A NAME="3_6">Full Opportunism</A></H2>
+<P>Full opportunism allows you to initiate and receive opportunistic
+ connections on your machine.</P>
+<A name="incoming.opp.dns"></A>
+<H3><A NAME="3_6_1">Put a TXT record in a Forward Domain</A></H3>
+<P>To set up full opportunism, first<A HREF="#forward.dns"> set up a
+ forward TXT record</A> as for<A HREF="#opp.client"> initiator-only OE</A>
+, using an ID (for example, your hostname) that resolves to your IP. Do
+ not configure<VAR> /etc/ipsec.conf</VAR>, but continue with the
+ instructions for full opportunism, below.</P>
+<P>Note that this forward record is not currently necessary for full OE,
+ but will facilitate future features.</P>
+<A name="incoming.opp.dns"></A>
+<H3><A NAME="3_6_2">Put a TXT record in Reverse DNS</A></H3>
+<P>You must be able to publish your DNS RR directly in the reverse
+ domain. FreeS/WAN will not follow a PTR which appears in the reverse,
+ since a second lookup at connection start time is too costly.</P>
+<H4><A NAME="3_6_2_1">Create a Reverse DNS TXT record</A></H4>
+<P>This record serves to publicize your FreeS/WAN public key. In
+ addition, it lets others know that this machine can receive
+ opportunistic connections, and asserts that the machine is authorized
+ to encrypt on its own behalf.</P>
+<P>Use the command:</P>
+<PRE> ipsec showhostkey --txt 192.0.2.11</PRE>
+<P>where you replace 192.0.2.11 with your public IP.</P>
+<P>The record (with key shortened) looks like:</P>
+<PRE> ; RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+<H4><A NAME="3_6_2_2">Publish your TXT record</A></H4>
+<P>Send these records to your ISP, to be published in your IP's reverse
+ map. It may take up to 48 hours for these to propagate, but usually
+ takes much less time.</P>
+<H3><A NAME="3_6_3">Test your DNS record</A></H3>
+<P>Check your DNS work with</P>
+<PRE> ipsec verify --host xy.example.com</PRE>
+<P>As part of the<VAR> verify</VAR> output, you ought to see something
+ like:</P>
+<PRE> ...
+ Looking for TXT in reverse map: 11.2.0.192.in-addr.arpa [OK]
+ ...</PRE>
+<P>which indicates that you've passed the reverse-map test.</P>
+<H3><A NAME="3_6_4">No Configuration Needed</A></H3>
+<P>FreeS/WAN 2.x ships with full OE enabled, so you don't need to
+ configure anything. To enable OE out of the box, FreeS/WAN 2.x uses the
+ policy group<VAR> private-or-clear</VAR>, which creates IPsec
+ connections if possible (using OE if needed), and allows traffic in the
+ clear otherwise. You can create more complex OE configurations as
+ described in our<A HREF="#policygroups"> policy groups document</A>, or
+ disable OE using<A HREF="#disable_policygroups"> these instructions</A>
+.</P>
+<P>If you've previously configured for initiator-only opportunism,
+ remove<VAR> myid=</VAR> from<VAR> config setup</VAR>, so that peer
+ FreeS/WANs will look up your key by IP. Restart FreeS/WAN so that your
+ change will take effect, with</P>
+<PRE> service ipsec restart</PRE>
+<H3><A NAME="3_6_5">Consider Firewalling</A></H3>
+<P>If you are running a default install of RedHat 8.x, take note: you
+ will need to alter your iptables rule setup to allow IPSec traffic
+ through your firewall. See<A HREF="#simple.rules"> our firewall
+ document</A> for sample<VAR> iptables</VAR> rules.</P>
+<H3><A NAME="3_6_6">Test</A></H3>
+<P>That's it. Now,<A HREF="#opp.test"> test your connection</A>.</P>
+<H3><A NAME="3_6_7">Test</A></H3>
+<P>Instructions are in the next section.</P>
+<H2><A NAME="opp.test">Testing opportunistic connections</A></H2>
+<P>Be sure IPsec is running. You can see whether it is with:</P>
+<PRE> ipsec setup status</PRE>
+<P>If need be, you can restart it with:</P>
+<PRE> service ipsec restart</PRE>
+<P>Load a FreeS/WAN test website from the host on which you're running
+ FreeS/WAN. Note: the feds may be watching these sites. Type one of:</P>
+<P></P>
+<PRE> links oetest.freeswan.org</PRE>
+<PRE> links oetest.freeswan.nl</PRE>
+
+<!--<PRE> links oetest.freeswan.ca</PRE>-->
+<P>A positive result looks like this:</P>
+<PRE>
+ You seem to be connecting from: 192.0.2.11 which DNS says is:
+ gateway.example.com
+ _________________________________________________________________
+
+ Status E-route
+ OE enabled 16 192.139.46.73/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x2097@192.0.2.11
+ OE enabled 176 192.139.46.77/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x208a@192.0.2.11
+</PRE>
+<P>If you see this, congratulations! Your OE host or gateway will now
+ encrypt its own traffic whenever it can. For more OE tests, please see
+ our<A HREF="#test.oe"> testing document</A>. If you have difficulty,
+ see our<A HREF="#oe.trouble"> OE troubleshooting tips</A>.</P>
+<H2><A NAME="3_8">Now what?</A></H2>
+<P>Please see our<A HREF="policygroups.html"> policy groups document</A>
+ for more ways to set up Opportunistic Encryption.</P>
+<P>You may also wish to make some<A HREF="config.html"> pre-configured
+ connections</A>.</P>
+<H2><A NAME="3_9">Notes</A></H2>
+<UL>
+<LI>We assume some facts about your system in order to make
+ Opportunistic Encryption easier to configure. For example, we assume
+ that you wish to have FreeS/WAN secure your default interface.</LI>
+<LI>You may change this, and other settings, by altering the<VAR> config
+ setup</VAR> section in<VAR> /etc/ipsec.conf</VAR>.</LI>
+<LI>Note that the built-in connections used to build policy groups do
+ not inherit from<VAR> conn default</VAR>.</LI>
+
+<!--
+<LI>If you do not define your local identity
+(eg. <VAR>leftid</VAR>), this will be the IP address of your default
+FreeS/WAN interface.
+-->
+<LI> If you fail to define your local identity and do not fill in your
+ reverse DNS entry, you will not be able to use OE.</LI>
+</UL>
+<A NAME="oe.trouble"></A>
+<H2><A NAME="3_10">Troubleshooting OE</A></H2>
+<P>See the OE troubleshooting hints in our<A HREF="#oe.trouble">
+ troubleshooting guide</A>.</P>
+<A NAME="oe.known-issues"></A>
+<H2><A NAME="3_11">Known Issues</A></H2>
+<P>Please see<A HREF="opportunism.known-issues"> this list</A> of known
+ issues with Opportunistic Encryption.</P>
+<HR>
+<H1><A NAME="4">How to Configure Linux FreeS/WAN with Policy Groups</A></H1>
+<A NAME="policygroups"></A>
+<H2><A NAME="4_1">What are Policy Groups?</A></H2>
+<P><STRONG>Policy Groups</STRONG> are an elegant general mechanism to
+ configure FreeS/WAN. They are useful for many FreeS/WAN users.</P>
+<P>In previous FreeS/WAN versions, you needed to configure each IPsec
+ connection explicitly, on both local and remote hosts. This could
+ become complex.</P>
+<P>By contrast, Policy Groups allow you to set local IPsec policy for
+ lists of remote hosts and networks, simply by listing the hosts and
+ networks which you wish to have special treatment in one of several
+ Policy Group files. FreeS/WAN then internally creates the connections
+ needed to implement each policy.</P>
+<P>In the next section we describe our five Base Policy Groups, which
+ you can use to configure IPsec in many useful ways. Later, we will show
+ you how to create an IPsec VPN using one line of configuration for each
+ remote host or network.</P>
+<A NAME="builtin_policygroups"></A>
+<H3><A NAME="4_1_1">Built-In Security Options</A></H3>
+<P>FreeS/WAN offers these Base Policy Groups:</P>
+<DL>
+<DT>private</DT>
+<DD> FreeS/WAN only communicates privately with the listed<A HREF="#CIDR">
+ CIDR</A> blocks. If needed, FreeS/WAN attempts to create a connection
+ opportunistically. If this fails, FreeS/WAN blocks communication.
+ Inbound blocking is assumed to be done by the firewall. FreeS/WAN
+ offers firewall hooks but no modern firewall rules to help with inbound
+ blocking.</DD>
+<DT>private-or-clear</DT>
+<DD> FreeS/WAN prefers private communication with the listed CIDR
+ blocks. If needed, FreeS/WAN attempts to create a connection
+ opportunistically. If this fails, FreeS/WAN allows traffic in the
+ clear.</DD>
+<DT>clear-or-private</DT>
+<DD> FreeS/WAN communicates cleartext with the listed CIDR blocks, but
+ also accepts inbound OE connection requests from them. Also known as<A HREF="#passive.OE">
+ passive OE (pOE)</A>, this policy may be used to create an<A HREF="#responder">
+ opportunistic responder</A>.</DD>
+<DT>clear</DT>
+<DD> FreeS/WAN only communicates cleartext with the listed CIDR blocks.</DD>
+<DT>block</DT>
+<DD>FreeS/WAN blocks traffic to and from and the listed CIDR blocks.
+ Inbound blocking is assumed to be done by the firewall. FreeS/WAN
+ offers firewall hooks but no modern firewall rules to help with inbound
+ blocking.
+<!-- also called "blockdrop".-->
+</DD>
+</DL>
+<A NAME="policy.group.notes"></A>
+<P>Notes:</P>
+<UL>
+<LI>Base Policy Groups apply to communication with this host only.</LI>
+<LI>The most specific rule (whether policy or pre-configured connection)
+ applies. This has several practical applications:
+<UL>
+<LI>If CIDR blocks overlap, FreeS/WAN chooses the most specific
+ applicable block.</LI>
+<LI>This decision also takes into account any pre-configured connections
+ you may have.</LI>
+<LI>If the most specific connection is a pre-configured connection, the
+ following procedure applies. If that connection is up, it will be used.
+ If it is routed, it will be brought up. If it is added, no action will
+ be taken.</LI>
+</UL>
+</LI>
+<LI>Base Policy Groups are created using built-in connections. Details
+ in<A HREF="manpage.d/ipsec.conf.5.html"> man ipsec.conf</A>.</LI>
+<LI>All Policy Groups are bidirectional.<A HREF="src/policy-groups-table.html">
+ This chart</A> shows some technical details. FreeS/WAN does not support
+ one-way encryption, since it can give users a false sense of security.</LI>
+</UL>
+<H2><A NAME="4_2">Using Policy Groups</A></H2>
+<P>The Base Policy Groups which build IPsec connections rely on
+ Opportunistic Encryption. To use the following examples, you must first
+ become OE-capable, as described in our<A HREF="#quickstart"> quickstart
+ guide</A>.<A NAME="example1"></A></P>
+<H3><A NAME="4_2_1">Example 1: Using a Base Policy Group</A></H3>
+<P>Simply place CIDR blocks (<A HREF="#dnswarning">names</A>, IPs or IP
+ ranges) in /etc/ipsec.d/policies/<VAR>[groupname]</VAR>, and reread the
+ policy group files.</P>
+<P>For example, the<VAR> private-or-clear</VAR> policy tells FreeS/WAN
+ to prefer encrypted communication to the listed CIDR blocks. Failing
+ that, it allows talk in the clear.</P>
+<P>To make this your default policy, place<A HREF="#fullnet"> fullnet</A>
+ in the<VAR> private-or-clear</VAR> policy group file:</P>
+<PRE> [root@xy root]# cat /etc/ipsec.d/policies/private-or-clear
+ # This file defines the set of CIDRs (network/mask-length) to which
+ # communication should be private, if possible, but in the clear otherwise.
+ ....
+ 0.0.0.0/0</PRE>
+<P>and reload your policies with</P>
+<PRE> ipsec auto --rereadgroups</PRE>
+<P>Use<A HREF="#opp.test"> this test</A> to verify opportunistic
+ connections.</P>
+<A NAME="example2"></A>
+<H3><A NAME="4_2_2">Example 2: Defining IPsec Security Policy with
+ Groups</A></H3>
+<P>Defining IPsec security policy with Base Policy Groups is like
+ creating a shopping list: just put CIDR blocks in the appropriate group
+ files. For example:</P>
+<PRE> [root@xy root]# cd /etc/ipsec.d/policies
+ [root@xy policies]# cat private
+ 192.0.2.96/27 # The finance department
+ 192.0.2.192/29 # HR
+ 192.0.2.12 # HR gateway
+ irc.private.example.com # Private IRC server
+
+ [root@xy policies]# cat private-or-clear
+ 0.0.0.0/0 # My default policy: try to encrypt.
+
+ [root@xy policies]# cat clear
+ 192.0.2.18/32 # My POP3 server
+ 192.0.2.19/32 # My Web proxy
+
+ [root@xy policies]# cat block
+ spamsource.example.com</PRE>
+<P>To make these settings take effect, type:</P>
+<PRE> ipsec auto --rereadgroups</PRE>
+<P>Notes:</P>
+<UL>
+<LI>For opportunistic connection attempts to succeed, all participating
+ FreeS/WAN hosts and gateways must be configured for OE.</LI>
+<LI>Examples 3 through 5 show how to implement a detailed<VAR> private</VAR>
+ policy.</LI>
+<LI><A NAME="dnswarning"></A><FONT COLOR="RED"> Warning:</FONT> Using
+ DNS names in policy files and ipsec.conf can be tricky. If the name
+ does not resolve, the policy will not be implemented for that name. It
+ is therefore safer either to use IPs, or to put any critical names in
+ /etc/hosts. We plan to implement periodic DNS retry to help with this.
+<BR> Names are resolved at FreeS/WAN startup, or when the policies are
+ reloaded. Unfortunately, name lookup can hold up the startup process.
+ If you have fast DNS servers, the problem may be less severe.</LI>
+</UL>
+<A HREF="example3"></A>
+<H3><A NAME="4_2_3">Example 3: Creating a Simple IPsec VPN with the<VAR>
+ private</VAR> Group</A></H3>
+<P>You can create an IPsec VPN between several hosts, with only one line
+ of configuration per host, using the<VAR> private</VAR> policy group.</P>
+<P>First, use our<A HREF="quickstart.html"> quickstart guide</A> to set
+ up each participating host with a FreeS/WAN install and OE.</P>
+<P>In one host's<VAR> /etc/ipsec.d/policies/private</VAR>, list the
+ peers to which you wish to protect traffic. For example:</P>
+<PRE> [root@xy root]# cd /etc/ipsec.d/policies
+ [root@xy policies]# cat private
+ 192.0.2.9 # several hosts at example.com
+ 192.0.2.11
+ 192.0.2.12
+ irc.private.example.com
+</PRE>
+<P>Copy the<VAR> private</VAR> file to each host. Remove the local host,
+ and add the initial host.</P>
+<PRE> scp2 /etc/ipsec.d/policies/private root@192.0.2.12:/etc/ipsec.d/policies/private</PRE>
+<P>On each host, reread the policy groups with</P>
+<PRE> ipsec auto --rereadgroups</PRE>
+<P>That's it! You're configured.</P>
+<P>Test by pinging between two hosts. After a second or two, traffic
+ should flow, and</P>
+<PRE> ipsec eroute</PRE>
+<P>should yield something like</P>
+<PRE> 192.0.2.11/32 -&gt; 192.0.2.8/32 =&gt; tun0x149f@192.0.2.8</PRE>
+<P>where your host IPs are substituted for 192.0.2.11 and 192.0.2.8.</P>
+<P>If traffic does not flow, there may be an error in your OE setup.
+ Revisit our<A HREF="quickstart.html"> quickstart guide</A>.</P>
+<P>Our next two examples show you how to add subnets to this IPsec VPN.</P>
+<A NAME="example4"></A>
+<H3><A NAME="4_2_4">Example 4: New Policy Groups to Protect a Subnet</A></H3>
+<P>To protect traffic to a subnet behind your FreeS/WAN gateway, you'll
+ need additional DNS records, and new policy groups. To set up the DNS,
+ see our<A HREF="#opp.gate"> quickstart guide</A>. To create five new
+ policy groups for your subnet, copy these connections to<VAR>
+ /etc/ipsec.conf</VAR>. Substitute your subnet's IPs for 192.0.2.128/29.</P>
+<PRE>
+conn private-net
+ also=private # inherits settings (eg. auto=start) from built in conn
+ leftsubnet=192.0.2.128/29 # your subnet's IPs here
+
+conn private-or-clear-net
+ also=private-or-clear
+ leftsubnet=192.0.2.128/29
+
+conn clear-or-private-net
+ also=clear-or-private
+ leftsubnet=192.0.2.128/29
+
+conn clear-net
+ also=clear
+ leftsubnet=192.0.2.128/29
+
+conn block-net
+ also=block
+ leftsubnet=192.0.2.128/29
+</PRE>
+<P>Copy the gateway's files to serve as the initial policy group files
+ for the new groups:</P>
+<PRE>
+ cp -p /etc/ipsec.d/policies/private /etc/ipsec.d/policies/private-net
+ cp -p /etc/ipsec.d/policies/private-or-clear /etc/ipsec.d/policies/private-or-clear-net
+ cp -p /etc/ipsec.d/policies/clear-or-private /etc/ipsec.d/policies/clear-or-private-net
+ cp -p /etc/ipsec.d/policies/clear /etc/ipsec.d/policies/clear-net
+ cp -p /etc/ipsec.d/policies/block /etc/ipsec.d/policies/block
+</PRE>
+<P><STRONG>Tip: Since a missing policy group file is equivalent to a
+ file with no entries, you need only create files for the connections
+ you'll use.</STRONG></P>
+<P>To test one of your new groups, place the fullnet 0.0.0.0/0 in<VAR>
+ private-or-clear-net</VAR>. Perform the subnet test in<A HREF="#opp.test">
+ our quickstart guide</A>. You should see a connection, and</P>
+<PRE> ipsec eroute</PRE>
+<P>should include an entry which mentions the subnet node's IP and the
+ OE test site IP, like this:</P>
+<PRE> 192.0.2.131/32 -&gt; 192.139.46.77/32 =&gt; tun0x149f@192.0.2.11</PRE>
+<A HREF="example5"></A>
+<H3><A NAME="4_2_5">Example 5: Adding a Subnet to the VPN</A></H3>
+<P>Suppose you wish to secure traffic to a subnet 192.0.2.192/29 behind
+ a FreeS/WAN box 192.0.2.12.</P>
+<P>First, add DNS entries to configure 192.0.2.12 as an opportunistic
+ gateway for that subnet. Instructions are in our<A HREF="#opp.gate">
+ quickstart guide</A>. Next, create a<VAR> private-net</VAR> group on
+ 192.0.2.12 as described in<A HREF="#example4"> Example 4</A>.</P>
+<P>On each other host, add the subnet 192.0.2.192/29 to<VAR> private</VAR>
+, yielding for example</P>
+<PRE> [root@xy root]# cd /etc/ipsec.d/policies
+ [root@xy policies]# cat private
+ 192.0.2.9 # several hosts at example.com
+ 192.0.2.11
+ 192.0.2.12 # HR department gateway
+ 192.0.2.192/29 # HR subnet
+ irc.private.example.com
+</PRE>
+<P>and reread policy groups with</P>
+<PRE> ipsec auto --rereadgroups</PRE>
+<P>That's all the configuration you need.</P>
+<P>Test your VPN by pinging from a machine on 192.0.2.192/29 to any
+ other host:</P>
+<PRE> [root@192.0.2.194]# ping 192.0.2.11</PRE>
+<P>After a second or two, traffic should flow, and</P>
+<PRE> ipsec eroute</PRE>
+<P>should yield something like</P>
+<PRE> 192.0.2.11/32 -&gt; 192.0.2.194/32 =&gt; tun0x149f@192.0.2.12
+</PRE>
+<P>Key:</P>
+<TABLE>
+<TR><TD>1.</TD><TD>192.0.2.11/32</TD><TD>Local start point of the
+ protected traffic.</TD></TR>
+<TR><TD>2.</TD><TD>192.0.2.194/32</TD><TD>Remote end point of the
+ protected traffic.</TD></TR>
+<TR><TD>3.</TD><TD>192.0.2.12</TD><TD>Remote FreeS/WAN node (gateway or
+ host). May be the same as (2).</TD></TR>
+<TR><TD>4.</TD><TD>[not shown]</TD><TD>Local FreeS/WAN node (gateway or
+ host), where you've produced the output. May be the same as (1).</TD></TR>
+</TABLE>
+<P>For additional assurance, you can verify with a packet sniffer that
+ the traffic is being encrypted.</P>
+<P>Note</P>
+<UL>
+<LI>Because strangers may also connect via OE, this type of VPN may
+ require a stricter firewalling policy than a conventional VPN.</LI>
+</UL>
+<H2><A NAME="4_3">Appendix</A></H2>
+<A NAME="hiddenconn"></A>
+<H3><A NAME="4_3_1">Our Hidden Connections</A></H3>
+<P>Our Base Policy Groups are created using hidden connections. These
+ are spelled out in<A HREF="manpage.d/ipsec.conf.5.html"> man ipsec.conf</A>
+ and defined in<VAR> /usr/local/lib/ipsec/_confread</VAR>.</P>
+<A NAME="custom_policygroups"></A>
+<H3><A NAME="4_3_2">Custom Policy Groups</A></H3>
+<P>A policy group is built using a special connection description in<VAR>
+ ipsec.conf</VAR>, which:</P>
+<UL>
+<LI>is<STRONG> generic</STRONG>. It uses<VAR>
+ right=[%group|%opportunisticgroup]</VAR> rather than specific IPs. The
+ connection is cloned for every name or IP range listed in its Policy
+ Group file.</LI>
+<LI>often has a<STRONG> failure rule</STRONG>. This rule, written<VAR>
+ failureshunt=[passthrough|drop|reject|none]</VAR>, tells FreeS/WAN what
+ to do with packets for these CIDRs if it fails to establish the
+ connection. Default is<VAR> none</VAR>.</LI>
+</UL>
+<P>To create a new group:</P>
+<OL>
+<LI>Create its connection definition in<VAR> ipsec.conf</VAR>.</LI>
+<LI>Create a Policy Group file in<VAR> /etc/ipsec.d/policies</VAR> with
+ the same name as your connection.</LI>
+<LI>Put a CIDR block in that file.</LI>
+<LI>Reread groups with<VAR> ipsec auto --rereadgroups</VAR>.</LI>
+<LI>Test:<VAR> ping</VAR> to activate any OE connection, and view
+ results with<VAR> ipsec eroute</VAR>.</LI>
+</OL>
+<A NAME="disable_oe"></A><A NAME="disable_policygroups"></A>
+<H3><A NAME="4_3_3">Disabling Opportunistic Encryption</A></H3>
+<P>To disable OE (eg. policy groups and packetdefault), cut and paste
+ the following lines to<VAR> /etc/ipsec.conf</VAR>:</P>
+<PRE>conn block
+ auto=ignore
+
+conn private
+ auto=ignore
+
+conn private-or-clear
+ auto=ignore
+
+conn clear-or-private
+ auto=ignore
+
+conn clear
+ auto=ignore
+
+conn packetdefault
+ auto=ignore</PRE>
+<P>Restart FreeS/WAN so that the changes take effect:</P>
+<PRE> ipsec setup restart</PRE>
+<HR>
+<H1><A NAME="5">FreeS/WAN FAQ</A></H1>
+<P>This is a collection of questions and answers, mostly taken from the
+ FreeS/WAN<A href="mail.html"> mailing list</A>. See the project<A href="http://www.freeswan.org/">
+ web site</A> for more information. All the FreeS/WAN documentation is
+ online there.</P>
+<P>Contributions to the FAQ are welcome. Please send them to the project<A
+href="mail.html"> mailing list</A>.</P>
+<HR>
+<H2><A name="questions">Index of FAQ questions</A></H2>
+<UL>
+<LI><A href="#whatzit">What is FreeS/WAN?</A></LI>
+<LI><A href="#problems">How do I report a problem or seek help?</A></LI>
+<LI><A href="#generic">Can I get ...</A>
+<UL>
+<LI><A href="#lemme_out">... an off-the-shelf system that includes
+ FreeS/WAN?</A></LI>
+<LI><A href="#contractor">... contractors or staff who know FreeS/WAN?</A>
+</LI>
+<LI><A href="#commercial">... commercial support?</A></LI>
+</UL>
+</LI>
+<LI><A href="#release">Release questions</A>
+<UL>
+<LI><A href="#rel.current">What is the current release?</A></LI>
+<LI><A href="#relwhen">When is the next release?</A></LI>
+<LI><A href="#rel.bugs">Are there known bugs in the current release?</A></LI>
+</UL>
+</LI>
+<LI><A href="mod_cons">Modifications and contributions</A>
+<UL>
+<LI><A href="#modify.faq">Can I modify FreeS/WAN to ...?</A></LI>
+<LI><A href="#contrib.faq">Can I contribute to the project?</A></LI>
+<LI><A href="#ddoc.faq">Is there detailed design documentation?</A></LI>
+</UL>
+</LI>
+<LI><A href="#interact">Will FreeS/WAN work in my environment?</A>
+<UL>
+<LI><A href="#interop.faq">Can FreeS/WAN talk to ... ?</A></LI>
+<LI><A href="#old_to_new">Can different FreeS/WAN versions talk to each
+ other?</A></LI>
+<LI><A href="#faq.bandwidth">Is there a limit on throughput?</A></LI>
+<LI><A href="#faq.number">Is there a limit on number of connections?</A></LI>
+<LI><A href="#faq.speed">Is a ... fast enough to handle FreeS/WAN with
+ my loads?</A></LI>
+</UL>
+</LI>
+<LI><A href="#work_on">Will FreeS/WAN work on ...</A>
+<UL>
+<LI><A href="#versions">... my version of Linux?</A></LI>
+<LI><A href="#nonIntel.faq">... non-Intel CPUs?</A></LI>
+<LI><A href="#multi.faq">... multiprocessors?</A></LI>
+<LI><A href="#k.old">... an older kernel?</A></LI>
+<LI><A href="#k.versions">... the latest kernel version?</A></LI>
+<LI><A href="#interface.faq">... unusual network hardware?</A></LI>
+<LI><A href="#vlan">... a VLAN (802.1q) network?</A></LI>
+</UL>
+</LI>
+<LI><A href="#features.faq">Does FreeS/WAN support ...</A>
+<UL>
+<LI><A href="#VPN.faq">... site-to-site VPN applications</A></LI>
+<LI><A href="#warrior.faq">... remote users connecting to a LAN</A></LI>
+<LI><A href="#road.shared.possible">... remote users using shared secret
+ authentication?</A></LI>
+<LI><A href="#wireless.faq">... wireless networks</A></LI>
+<LI><A href="#PKIcert">... X.509 or other PKI certificates?</A></LI>
+<LI><A href="#Radius">... user authentication (Radius, SecureID, Smart
+ Card ...)?</A></LI>
+<LI><A href="#NATtraversal">... NAT traversal</A></LI>
+<LI><A href="#virtID">... assigning a &quot;virtual identity&quot; to a remote
+ system?</A></LI>
+<LI><A href="#noDES.faq">... single DES encryption?</A></LI>
+<LI><A href="#AES.faq">... AES encryption?</A></LI>
+<LI><A href="#other.cipher">... other encryption algorithms?</A></LI>
+</UL>
+</LI>
+<LI><A href="#canI">Can I ...</A>
+<UL>
+<LI><A href="#policy.preconfig">...use policy groups along with
+ explicitly configured connections?</A></LI>
+<LI><A href="#policy.off">...turn off policy groups?</A></LI>
+
+<!--
+ <li><a href="#policy.otherinterface">...use policy groups
+ on an interface other than <VAR>%defaultroute</VAR>?</a></li>
+-->
+<LI><A href="#reload">... reload connection info without restarting?</A></LI>
+<LI><A href="#masq.faq">... use several masqueraded subnets?</A></LI>
+<LI><A href="#dup_route">... use subnets masqueraded to the same
+ addresses?</A></LI>
+<LI><A href="#road.masq">... assign a road warrior an address on my net
+ (a virtual identity)?</A></LI>
+<LI><A href="#road.many">... support many road warriors with one
+ gateway?</A></LI>
+<LI><A href="#road.PSK">... have many road warriors using shared secret
+ authentication?</A></LI>
+<LI><A href="#QoS">... use Quality of Service routing with FreeS/WAN?</A>
+</LI>
+<LI><A href="#deadtunnel">... recognise dead tunnels and shut them down?</A>
+</LI>
+<LI><A href="#demanddial">... build IPsec tunnels over a demand-dialed
+ link?</A></LI>
+<LI><A href="#GRE">... build GRE, L2TP or PPTP tunnels over IPsec?</A></LI>
+<LI><A href="#NetBIOS">... use Network Neighborhood (Samba, NetBIOS)
+ over IPsec?</A></LI>
+</UL>
+</LI>
+<LI><A href="#setup.faq">Life's little mysteries</A>
+<UL>
+<LI><A href="#cantping">I cannot ping ....</A></LI>
+<LI><A href="#forever">It takes forever to ...</A></LI>
+<LI><A href="#route">I send packets to the tunnel with route(8) but they
+ vanish</A></LI>
+<LI><A href="#down_route">When a tunnel goes down, packets vanish</A></LI>
+<LI><A href="#firewall_ate">The firewall ate my packets!</A></LI>
+<LI><A href="#dropconn">Dropped connections</A></LI>
+<LI><A href="#defaultroutegone">Disappearing %defaultroute</A></LI>
+<LI><A href="#tcpdump.faq">TCPdump on the gateway shows strange things</A>
+</LI>
+<LI><A href="#no_trace">Traceroute does not show anything between the
+ gateways</A></LI>
+</UL>
+</LI>
+<LI><A href="#man4debug">Testing in stages (or .... works but ...
+ doesn't)</A>
+<UL>
+<LI><A href="#nomanual">Manually keyed connections don't work</A></LI>
+<LI><A href="#spi_error">One manual connection works, but second one
+ fails</A></LI>
+<LI><A href="#man_no_auto">Manual connections work, but automatic keying
+ doesn't</A></LI>
+<LI><A href="#nocomp">IPsec works, but connections using compression
+ fail</A></LI>
+<LI><A href="#pmtu.broken">Small packets work, but large transfers fail</A>
+</LI>
+<LI><A href="#subsub">Subnet-to-subnet works, but tests from the
+ gateways don't</A></LI>
+</UL>
+</LI>
+<LI><A href="#compile.faq">Compilation problems</A>
+<UL>
+<LI><A href="#gmp.h_missing">gmp.h: No such file or directory</A></LI>
+<LI><A href="#noVM">... virtual memory exhausted</A></LI>
+</UL>
+</LI>
+<LI><A href="#error">Interpreting error messages</A>
+<UL>
+<LI><A href="#route-client">route-client (or host) exited with status 7</A>
+</LI>
+<LI><A href="#unreachable">SIOCADDRT:Network is unreachable</A></LI>
+<LI><A href="#modprobe">ipsec_setup: modprobe: Can't locate moduleipsec</A>
+</LI>
+<LI><A href="#noKLIPS">ipsec_setup: Fatal error, kernel appears to lack
+ KLIPS</A></LI>
+<LI><A href="#noDNS">ipsec_setup: ... failure to fetch key for ... from
+ DNS</A></LI>
+<LI><A href="#dup_address">ipsec_setup: ... interfaces ... and ... share
+ address ...</A></LI>
+<LI><A href="#kflags">ipsec_setup: Cannot adjust kernel flags</A></LI>
+<LI><A href="#message_num">Message numbers (MI3, QR1, et cetera) in
+ Pluto messages</A></LI>
+<LI><A href="#conn_name">Connection names in Pluto error messages</A></LI>
+<LI><A href="#cantorient">Pluto: ... can't orient connection</A></LI>
+<LI><A href="#no.interface">... we have no ipsecN interface for either
+ end of this connection</A></LI>
+<LI><A href="#noconn">Pluto: ... no connection is known</A></LI>
+<LI><A href="#nosuit">Pluto: ... no suitable connection ...</A></LI>
+<LI><A href="#noconn.auth">Pluto: ... no connection has been authorized</A>
+</LI>
+<LI><A href="#noDESsupport">Pluto: ... OAKLEY_DES_CBC is not supported.</A>
+</LI>
+<LI><A href="#notransform">Pluto: ... no acceptable transform</A></LI>
+<LI><A href="#rsasigkey">rsasigkey dumps core</A></LI>
+<LI><A href="#sig4">!Pluto failure!: ... exited with ... signal 4</A></LI>
+<LI><A href="#econnrefused">ECONNREFUSED error message</A></LI>
+<LI><A href="#no_eroute">klips_debug: ... no eroute!</A></LI>
+<LI><A href="#SAused">... trouble writing to /dev/ipsec ... SA already
+ in use</A></LI>
+<LI><A href="#ignore">... ignoring ... payload</A></LI>
+<LI><A href="#unknown_rightcert">unknown parameter name &quot;rightcert&quot;</A></LI>
+</UL>
+</LI>
+<LI><A href="#spam">Why don't you restrict the mailing lists to reduce
+ spam?</A></LI>
+</UL>
+<HR>
+<H2><A name="whatzit">What is FreeS/WAN?</A></H2>
+<P>FreeS/WAN is a Linux implementation of the<A href="#IPSEC"> IPsec</A>
+ protocols, providing security services at the IP (Internet Protocol)
+ level of the network.</P>
+<P>For more detail, see our<A href="intro.html"> introduction</A>
+ document or the FreeS/WAN project<A href="http://www.freeswan.org/">
+ web site</A>.</P>
+<P>To start setting it up, go to our<A href="quickstart.html">
+ quickstart guide</A>.</P>
+<P>Our<A href="web.html"> web links</A> document has information on<A href="#implement">
+ IPsec for other systems</A>.</P>
+<H2><A name="problems">How do I report a problem or seek help?</A></H2>
+<DL>
+<DT>Read our<A href="trouble.html"> troubleshooting</A> document.</DT>
+<DD>
+<P>It may guide you to a solution. If not, see its<A href="#prob.report">
+ problem reporting</A> section.</P>
+<P>Basically, what it says is<STRONG> give us the output from<VAR> ipsec
+ barf</VAR> from both gateways</STRONG>. Without full information, we
+ cannot diagnose a problem. However,<VAR> ipsec barf</VAR> produces a
+ lot of output. If at all possible,<STRONG> please make barfs accessible
+ via the web or FTP</STRONG> rather than sending enormous mail messages.</P>
+</DD>
+<DT><STRONG>Use the<A href="mail.html"> users mailing list</A> for
+ problem reports</STRONG>, rather than mailing developers directly.</DT>
+<DD>
+<UL>
+<LI>This gives you access to more expertise, including users who may
+ have encountered and solved the same problems.</LI>
+<LI>It is more likely to get a quick response. Developers may get behind
+ on email, or even ignore it entirely for a while, but a list message
+ (given a reasonable Subject: line) is certain to be read by a fair
+ number of people within hours.</LI>
+<LI>It may also be important because of<A href="#exlaw"> cryptography
+ export laws</A>. A US citizen who provides technical assistance to
+ foreign cryptographic work might be charged under the arms export
+ regulations. Such a charge would be easier to defend if the discussion
+ took place on a public mailing list than if it were done in private
+ mail.</LI>
+</UL>
+</DD>
+<DT>Try irc.freenode.net#freeswan.</DT>
+<DD>
+<P>FreeS/WAN developers, volunteers and users can often be found there.
+ Be patient and be prepared to provide lots of information to support
+ your question.</P>
+<P>If your question was really interesting, and you found an answer,
+ please share that with the class by posting to the<A href="mail.html">
+ users mailing list</A>. That way others with the same problem can find
+ your answer in the archives.</P>
+</DD>
+<DT>Premium support is also available.</DT>
+<DD>
+<P>See the next several questions.</P>
+</DD>
+</DL>
+<H2><A name="generic">Can I get ...</A></H2>
+<H3><A name="lemme_out">Can I get an off-the-shelf system that includes
+ FreeS/WAN?</A></H3>
+<P>There are a number of Linux distributions or firewall products which
+ include FreeS/WAN. See this<A href="#products"> list</A>. Using one of
+ these, chosen to match your requirements and budget, may save you
+ considerable time and effort.</P>
+<P>If you don't know your requirements, start by reading Schneier's<A href="#secrets">
+ Secrets and Lies</A>. That gives the best overview of security issues I
+ have seen. Then consider hiring a consultant (see next question) to
+ help define your requirements.</P>
+<H3><A name="consultant">Can I hire consultants or staff who know
+ FreeS/WAN?</A></H3>
+<P>If you want the help of a contractor, or to hire staff with FreeS/WAN
+ expertise, you could:</P>
+<UL>
+<LI>check availability in your area through your local Linux User Group
+ (<A href="http://lugww.counter.li.org/">LUG Index</A>)</LI>
+<LI>try asking on our<A href="mail.html"> mailing list</A></LI>
+</UL>
+<P>For companies offerring support, see the next question.</P>
+<H3><A name="commercial">Can I get commercial support?</A></H3>
+<P>Many of the distributions or firewall products which include
+ FreeS/WAN (see this<A href="#products"> list</A>) come with commercial
+ support or have it available as an option.</P>
+<P>Various companies specialize in commercial support of open source
+ software. Our project leader was a founder of the first such company,
+ Cygnus Support. It has since been bought by<A href="http://www.redhat.com">
+ Redhat</A>. Another such firm is<A href="http://www.linuxcare.com">
+ Linuxcare</A>.</P>
+<H2><A name="release">Release questions</A></H2>
+<H3><A name="rel.current">What is the current release?</A></H3>
+<P>The current release is the highest-numbered tarball on our<A href="ftp://ftp.xs4all.nl/pub/crypto/freeswan">
+ distribution site</A>. Almost always, any of<A href="#mirrors"> the
+ mirrors</A> will have the same file, though perhaps not for a day or so
+ after a release.</P>
+<P>Unfortunately, the web site is not always updated as quickly as it
+ should be.</P>
+<H3><A name="relwhen">When is the next release?</A></H3>
+<P>We try to do a release approximately every six to eight weeks.</P>
+<P>If pre-release tests fail and the fix appears complex, or more
+ generally if the code does not appear stable when a release is
+ scheduled, we will just skip that release.</P>
+<P>For serious bugs, we may bring out an extra bug-fix release. These
+ get numbers in the normal release series. For example, there was a bug
+ found in FreeS/WAN 1.6, so we did another release less than two weeks
+ later. The bug-fix release was called 1.7.</P>
+<H3><A name="rel.bugs">Are there known bugs in the current release?</A></H3>
+<P>Any problems we are aware of at the time of a release are documented
+ in the<A href="../BUGS"> BUGS</A> file for that release. You should
+ also look at the<A href="../CHANGES"> CHANGES</A> file.</P>
+<P>Bugs discovered after a release are discussed on the<A href="mail.html">
+ mailing lists</A>. The easiest way to check for any problems in the
+ current code would be to peruse the<A href="http://lists.freeswan.org/pipermail/briefs">
+ List In Brief</A>.</P>
+<H2><A name="mod_cons">Modifications and contributions</A></H2>
+<H3><A name="modify.faq">Can I modify FreeS/WAN to ...?</A></H3>
+<P>You are free to modify FreeS/WAN in any way. See the discussion of<A href="#licensing">
+ licensing</A> in our introduction document.</P>
+<P>Before investing much energy in any such project, we suggest that you</P>
+<UL>
+<LI>check the list of<A href="#patch"> existing patches</A></LI>
+<LI>post something about your project to the<A href="mail.html"> design
+ mailing list</A></LI>
+</UL>
+<P>This may prevent duplicated effort, or lead to interesting
+ collaborations.</P>
+<H3><A name="contrib.faq">Can I contribute to the project?</A></H3>
+ In general, we welcome contributions from the community. Various
+ contributed patches, either to fix bugs or to add features, have been
+ incorporated into our distribution. Other patches, not yet included in
+ the distribution, are listed in our<A href="#patch"> web links</A>
+ section.
+<P>Users have also contributed heavily to documentation, both by
+ creating their own<A href="#howto"> HowTos</A> and by posting things on
+ the<A href="mail.html"> mailing lists</A> which I have quoted in these
+ HTML docs.</P>
+<P>There are, however, some caveats.</P>
+<P>FreeS/WAN is being implemented in Canada, by Canadians, largely to
+ ensure that is it is entirely free of export restrictions. See this<A href="#status">
+ discussion</A>. We<STRONG> cannot accept code contributions from US
+ residents or citizens</STRONG>, not even one-line bugs fixes. The
+ reasons for this were recently discussed extensively on the mailing
+ list, in a thread starting<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/01/msg00111.html">
+ here</A>.</P>
+<P>Not all contributions are of interest to us. The project has a set of
+ fairly ambitious and quite specific goals, described in our<A href="#goals">
+ introduction</A>. Contributions that lead toward these goals are likely
+ to be welcomed enthusiastically. Other contributions may be seen as
+ lower priority, or even as a distraction.</P>
+<P>Discussion of possible contributions takes place on the<A href="mail.html">
+ design mailing list</A>.</P>
+<H3><A name="ddoc.faq">Is there detailed design documentation?</A></H3>
+ There are:
+<UL>
+<LI><A href="rfc.html">RFCs</A> specifying the protocols we implement</LI>
+<LI><A href="manpages.html">man pages</A> for our utilities, library
+ functions and file formats</LI>
+<LI>comments in the source code</LI>
+<LI><A href="index.html">HTML documentation</A> written primarily for
+ users</LI>
+<LI>archived discussions from the<A href="mail.html"> mailing lists</A></LI>
+<LI>other papers mentioned in our<A href="#applied"> introduction</A></LI>
+</UL>
+<P>The only formal design documents are a few papers in the last
+ category above. All the other categories, however, have things to say
+ about design as well.</P>
+<H2><A name="interact">Will FreeS/WAN work in my environment?</A></H2>
+<H3><A name="interop.faq">Can FreeS/WAN talk to ...?</A></H3>
+<P>The IPsec protocols are designed to support interoperation. In
+ theory, any two IPsec implementations should be able to talk to each
+ other. In practice, it is considerably more complex. We have a whole<A href="interop.html">
+ interoperation document</A> devoted to this problem.</P>
+<P>An important part of that document is links to the many<A href="interop.html#otherpub">
+ user-written HowTos</A> on interoperation between FreeS/WAN and various
+ other implementations. Often the users know more than the developers
+ about these issues (and almost always more than me :-), so these
+ documents may be your best resource.</P>
+<H3><A name="old_to_new">Can different FreeS/WAN versions talk to each
+ other?</A></H3>
+<P>Linux FreeS/WAN can interoperate with many IPsec implementations,
+ including earlier versions of Linux FreeS/WAN itself.</P>
+<P>In a few cases, there are some complications. See our<A href="interop.html#oldswan">
+ interoperation</A> document for details.</P>
+<H3><A name="faq.bandwidth">Is there a limit on throughput?</A></H3>
+<P>There is no hard limit, but see below.</P>
+<H3><A name="faq.number">Is there a limit on number of tunnels?</A></H3>
+<P>There is no hard limit, but see next question.</P>
+<H3><A name="faq.speed">Is a ... fast enough to handle FreeS/WAN with my
+ loads?</A></H3>
+<P>A quick summary:</P>
+<DL>
+<DT>Even a limited machine can be useful</DT>
+<DD>A 486 can handle a T1, ADSL or cable link, though the machine may be
+ breathing hard.</DD>
+<DT>A mid-range PC (say 800 MHz with good network cards) can do a lot of
+ IPsec</DT>
+<DD>With up to roughly 50 tunnels and aggregate bandwidth of 20 Megabits
+ per second, it willl have cycles left over for other tasks.</DD>
+<DT>There are limits</DT>
+<DD>Even a high end CPU will not come close to handling a fully loaded
+ 100 Mbit/second Ethernet link.
+<P>Beyond about 50 tunnels it needs careful management.</P>
+</DD>
+</DL>
+<P>See our<A href="performance.html"> FreeS/WAN performance</A> document
+ for details.</P>
+<H2><A name="work_on">Will FreeS/WAN work on ... ?</A></H2>
+<H3><A name="versions">Will FreeS/WAN run on my version of Linux?</A></H3>
+<P>We build and test on Redhat distributions, but FreeS/WAN runs just
+ fine on several other distributions, sometimes with minor fiddles to
+ adapt to the local environment. Details are in our<A href="#otherdist">
+ compatibility</A> document. Also, some distributions or products come
+ with<A href="#products"> FreeS/WAN included</A>.</P>
+<H3><A name="nonIntel.faq">Will FreeS/WAN run on non-Intel CPUs?</A></H3>
+<P>FreeS/WAN is<STRONG> intended to run on all CPUs Linux supports</STRONG>
+. We know of it being used in production on x86, ARM, Alpha and MIPS. It
+ has also had successful tests on PPC and SPARC, though we don't know of
+ actual use there. Details are in our<A href="#CPUs"> compatibility</A>
+ document.</P>
+<H3><A name="multi.faq">Will FreeS/WAN run on multiprocessors?</A></H3>
+<P>FreeS/WAN is designed to work on any SMP architecture Linux supports,
+ and has been tested successfully on at least dual processor Intel
+ architecture machines. Details are in our<A href="#multiprocessor">
+ compatibility</A> document.</P>
+<H3><A name="k.old">Will FreeS/WAN work on an older kernel?</A></H3>
+<P>It might, but we strongly recommend using a recent 2.2 or 2.4 series
+ kernel. Sometimes the newer versions include security fixes which can
+ be quite important on a gateway.</P>
+<P>Also, we use recent kernels for development and testing, so those are
+ better tested and, if you do encounter a problem, more easily
+ supported. If something breaks applying recent FreeS/WAN patches to an
+ older kernel, then &quot;update your kernel&quot; is almost certain to be the
+ first thing we suggest. It may be the only suggestion we have.</P>
+<P>The precise kernel versions supported by a particular FreeS/WAN
+ release are given in the<A href="XX"> README</A> file of that release.</P>
+<P>See the following question for more on kernels.</P>
+<H3><A name="k.versions">Will FreeS/WAN run on the latest kernel
+ version?</A></H3>
+<P>Sometimes yes, but quite often, no.</P>
+<P>Kernel versions supported are given in the<A href="../README"> README</A>
+ file of each FreeS/WAN release. Typically, they are whatever production
+ kernels were current at the time of our release (or shortly before; we
+ might release for kernel<VAR> n</VAR> just as Linus releases<VAR> n+1</VAR>
+). Often FreeS/WAN will work on slightly later kernels as well, but of
+ course this cannot be guaranteed.</P>
+<P>For example, FreeS/WAN 1.91 was released for kernels 2.2.19 or 2.4.5,
+ the current kernels at the time. It also worked on 2.4.6, 2.4.7 and
+ 2.4.8, but 2.4.9 had changes that caused compilation errors if it was
+ patched with FreeS/WAN 1.91.</P>
+<P>When such changes appear, we put a fix in the FreeS/WAN snapshots,
+ and distribute it with our next release. However, this is not a high
+ priority for us, and it may take anything from a few days to several
+ weeks for such a problem to find its way to the top of our kernel
+ programmer's To-Do list. In the meanwhile, you have two choices:</P>
+<UL>
+<LI>either stick with a slightly older kernel, even if it is not the
+ latest and greatest. This is recommended for production systems; new
+ versions may have new bugs.</LI>
+<LI>or fix the problem yourself and send us a patch, via the<A href="mail.html">
+ Users mailing list</A>.</LI>
+</UL>
+<P>We don't even try to keep up with kernel changes outside the main 2.2
+ and 2.4 branches, such as the 2.4.x-ac patched versions from Alan Cox
+ or the 2.5 series of development kernels. We'd rather work on
+ developing the FreeS/WAN code than on chasing these moving targets. We
+ are, however, happy to get patches for problems discovered there.</P>
+<P>See also the<A href="install.html#choosek"> Choosing a kernel</A>
+ section of our installation document.</P>
+<H3><A name="interface.faq">Will FreeS/WAN work on unusual network
+ hardware?</A></H3>
+<P>IPsec is designed to work over any network that IP works over, and
+ FreeS/WAN is intended to work over any network interface hardware that
+ Linux supports.</P>
+<P>If you have working IP on some unusual interface -- perhaps Arcnet,
+ Token Ring, ATM or Gigabit Ethernet -- then IPsec should &quot;just work&quot;.</P>
+<P>That said, practice is sometimes less tractable than theory. Our
+ testing is done almost entirely on:</P>
+<UL>
+<LI>10 or 100 Mbit Ethernet</LI>
+<LI>ADSL or cable connections, with and without PPPoE</LI>
+<LI>IEEE 802.11 wireless LANs (see<A href="#wireless.faq"> below</A>)</LI>
+</UL>
+<P>If you have some other interface, especially an uncommon one, it is
+ entirely possible you will get bitten either by a FreeS/WAN bug which
+ our testing did not turn up, or by a bug in the driver that shows up
+ only with our loads.</P>
+<P>If IP works on your interface and FreeS/WAN doesn't, seek help on the<A
+href="mail.html"> mailing lists</A>.</P>
+<P>Another FAQ section describes<A href="#pmtu.broken"> MTU problems</A>
+. These are a possibility for some interfaces.</P>
+<H3><A name="vlan">Will FreeS/WAN work on a VLAN (802.1q) network?</A></H3>
+<P> Yes, FreeSwan works fine, though some network drivers have problems
+ with jumbo sized ethernet frames. If you used interfaces=%defaultroute
+ you do not need to change anything, but if you specified an interface
+ (eg eth0) then remember you must change that to reflect the VLAN
+ interface (eg eth0.2 for VLAN ID 2).</P>
+<P> The &quot;eepro100&quot; module is known to be broken, use the e100 driver for
+ those cards instead (included in 2.4 as 'alternative driver' for the
+ Intel EtherExpressPro/100.</P>
+<P> You do not need to change any MTU setting (those are workarounds
+ that are only needed for buggy drivers)</P>
+<P><EM>This FAQ contributed by Paul Wouters.</EM></P>
+<H2><A name="features.faq">Does FreeS/WAN support ...</A></H2>
+<P>For a discussion of which parts of the IPsec specifications FreeS/WAN
+ does and does not implement, see our<A href="#spec"> compatibility</A>
+ document.</P>
+<P>For information on some often-requested features, see below.</P>
+<H3><A name="VPN.faq"></A>Does FreeS/WAN support site-to-site VPN (<A HREF="#VPN">
+Virtual Private Network</A>) applications?</H3>
+<P>Absolutely. See this FreeS/WAN-FreeS/WAN<A HREF="config.html">
+ configuration example</A>. If only one site is using FreeS/WAN, there
+ may be a relevant HOWTO on our<A HREF="interop.html"> interop page</A>.</P>
+<H3><A name="warrior.faq">Does FreeS/WAN support remote users connecting
+ to a LAN?</A></H3>
+<P>Yes. We call the remote users &quot;Road Warriors&quot;. Check out our
+ FreeS/WAN-FreeS/WAN<A HREF="#config.rw"> Road Warrior Configuration
+ Example</A>.</P>
+<P>If your Road Warrior is a Windows or Mac PC, you may need to install
+ an IPsec implementation on that machine. Our<A HREF="interop.html">
+ interop</A> page lists many available brands, and features links to
+ several HOWTOs.</P>
+<H3><A name="road.shared.possible">Does FreeS/WAN support remote users
+ using shared secret authentication?</A></H3>
+<P><STRONG>Yes, but</STRONG> there are severe restrictions, so<STRONG>
+ we strongly recommend using</STRONG><A href="#RSA"><STRONG> RSA</STRONG>
+</A><STRONG> keys for</STRONG><A href="#authentication"><STRONG>
+ authentication</STRONG></A><STRONG> instead</STRONG>.</P>
+<P>See this<A href="#road.PSK"> FAQ question</A>.</P>
+<H3><A name="wireless.faq">Does FreeS/WAN support wireless networks?</A></H3>
+<P>Yes, it is a common practice to use IPsec over wireless networks
+ because their built-in encryption,<A href="#WEP"> WEP</A>, is insecure.</P>
+<P>There is some<A href="#wireless.config"> discussion</A> in our
+ advanced configuration document. See also the<A HREF="http://www.wavesec.org">
+ WaveSEC site</A>.</P>
+<H3><A name="PKIcert">Does FreeS/WAN support X.509 or other PKI
+ certificates?</A></H3>
+<P>Vanilla FreeS/WAN does not support X.509, but Andreas Steffen and
+ others have provided a popular, well-supported X.509 patch.</P>
+<UL>
+<LI><A HREF="http://www.strongsec.com/freeswan">patch</A></LI>
+<LI><A HREF="http://www.freeswan.ca">Super FreeS/WAN</A> incorporates
+ this and other user-contributed patches.</LI>
+<LI> Kai Martius'<A HREF="http://www.strongsec.com/freeswan/install.htm">
+ X.509 Installation and Configuration Guide</A></LI>
+</UL>
+<P> Linux FreeS/WAN features<A HREF="quickstart.html"> Opportunistic
+ Encryption</A>, an alternative Public Key Infrastructure based on
+ Secure DNS.</P>
+<H3><A name="Radius">Does FreeS/WAN support user authentication (Radius,
+ SecureID, Smart Card...)?</A></H3>
+<P>Andreas Steffen's<A HREF="http://www.strongsec.com/freeswan"> X.509
+ patch</A> (v. 1.42+) supports Smart Cards. The patch does not ship with
+ vanilla FreeS/WAN, but will be incorporated into<A HREF="http://www.freeswan.ca/">
+ Super FreeS/WAN 2.01+</A>. The patch implements the PCKS#15
+ Cryptographic Token Information Format Standard, using the OpenSC
+ smartcard library functions.</P>
+<P>Older news:</P>
+<P>A user-supported patch to FreeS/WAN 1.3, for smart card style
+ authentication, is available on<A HREF="http://alcatraz.webcriminals.com/~bastiaan/ipsec">
+ Bastiaan's site</A>. It supports skeyid and ibutton. This patch is not
+ part of Super FreeS/WAN.</P>
+<P>For a while progress on this front was impeded by a lack of standard.
+ The IETF<A href="http://www.ietf.org/html.charters/ipsra-charter.html">
+ working group</A> has now nearly completed its recommended solution to
+ the problem; meanwhile several vendors have implemented various things.</P>
+
+<!--
+<p>The <a href="web.html#patch">patches</a> section of our web links document
+has links to some user work on this.</p>
+-->
+<P>Of course, there are various ways to avoid any requirement for user
+ authentication in IPsec. Consider the situation where road warriors
+ build IPsec tunnels to your office net and you are considering
+ requiring user authentication during tunnel negotiation. Alternatives
+ include:</P>
+<UL>
+<LI>If you can trust the road warrior machines, then set them up so that
+ only authorised users can create tunnels. If your road warriors use
+ laptops, consider the possibility of theft.</LI>
+<LI>If the tunnel only provides access to particular servers and you can
+ trust those servers, then set the servers up to require user
+ authentication.</LI>
+</UL>
+<P>If either of those is trustworthy, it is not clear that you need user
+ authentication in IPsec.</P>
+<H3><A name="NATtraversal">Does FreeS/WAN support NAT traversal?</A></H3>
+<P>Vanilla FreeS/WAN does not, but thanks to Mathieu Lafon and Arkoon
+ Network Security, there's a patch to support this.</P>
+<UL>
+<LI><A HREF="http://open-source.arkoon.net">patch and documentation</A></LI>
+<LI><A HREF="http://www.freeswan.ca">Super FreeS/WAN</A> incorporates
+ this and other user-contributed patches.</LI>
+</UL>
+<P>The NAT traversal patch has some issues with PSKs, so you may wish to
+ authenticate with RSA keys, or X.509 (requires a patch which is also
+ included in Super FreeS/WAN). Doing the latter also has advantages when
+ dealing with large numbers of clients who may be behind NAT; instead of
+ having to make an individual Roadwarrior connection for each virtual
+ IP, you can use the &quot;rightsubnetwithin&quot; parameter to specify a range.
+ See<A HREF="http://www.strongsec.com/freeswan/install.htm#section_4.4">
+ these<VAR> rightsubnetwithin</VAR> instructions</A>.</P>
+<H3><A name="virtID">Does FreeS/WAN support assigning a &quot;virtual
+ identity&quot; to a remote system?</A></H3>
+<P>Some IPsec implementations allow you to make the source address on
+ packets sent by a Road Warrior machine be something other than the
+ address of its interface to the Internet. This is sometimes described
+ as assigning a virtual identity to that machine.</P>
+<P>FreeS/WAN does not directly support this, but it can be done. See
+ this<A href="#road.masq"> FAQ question</A>.</P>
+<H3><A name="noDES.faq">Does FreeS/WAN support single DES encryption?</A>
+</H3>
+<P><STRONG>No</STRONG>, single DES is not used either at the<A href="#IKE">
+ IKE</A> level for negotiating connections or at the<A href="#IPSEC">
+ IPsec</A> level for actually building them.</P>
+<P>Single DES is<A href="#desnotsecure"> insecure</A>. As we see it, it
+ is more important to deliver real security than to comply with a
+ standard which has been subverted into allowing use of inadequate
+ methods. See this<A href="#weak"> discussion</A>.</P>
+<P>If you want to interoperate with an IPsec implementation which offers
+ only DES, see our<A href="interop.html#noDES"> interoperation</A>
+ document.</P>
+<H3><A name="AES.faq">Does FreeS/WAN support AES encryption?</A></H3>
+<P><A href="#AES">AES</A> is a new US government<A href="#block"> block
+ cipher</A> standard to replace the obsolete<A href="#DES"> DES</A>.</P>
+<P>At time of writing (March 2002), the FreeS/WAN distribution does not
+ yet support AES but user-written<A href="#patch"> patches</A> are
+ available to add it. Our kernel programmer is working on integrating
+ those patches into the distribution, and there is active discussion of
+ this on the design mailimg list.</P>
+<H3><A name="other.cipher">Does FreeS/WAN support other encryption
+ algorithms?</A></H3>
+<P>Currently<A href="#3DES"> triple DES</A> is the only cipher
+ supported. AES will almost certainly be added (see previous question),
+ and it is likely that in the process we will also add the other two AES
+ finalists with open licensing, Twofish and Serpent.</P>
+<P>We are extremely reluctant to add other ciphers. This would make both
+ use and maintenance of FreeS/WAN more complex without providing any
+ clear benefit. Complexity is emphatically not desirable in a security
+ product.</P>
+<P>Various users have written patches to add other ciphers. We provide<A href="#patch">
+ links</A> to these.</P>
+<H2><A name="canI">Can I ...</A></H2>
+<H3><A name="policy.preconfig">Can I use policy groups along with
+ explicitly configured connections?</A></H3>
+<P>Yes, you can, so long as you pay attention to the selection rule,
+ which can be summarized &quot;the most specific connection wins&quot;. We
+ describe the rule in our<A HREF="#policy.group.notes"> policy groups</A>
+ document, and provide a more technical explanation in<A HREF="manpage.d/ipsec.conf.5.html">
+ man ipsec.conf</A>.</P>
+<P>A good guideline: If you have a regular connection defined in<VAR>
+ ipsec.conf</VAR>, ensure that a subset of that connection is not listed
+ in a less restrictive policy group. Otherwise, FreeS/WAN will use the
+ subset, with its more specific source/destination pair.</P>
+<P>Here's an example. Suppose you are the system administrator at
+ 192.0.2.2. You have this connection in ipsec.conf:<VAR> ipsec.conf</VAR>
+:</P>
+<PRE>conn net-to-net
+ left=192.0.2.2 # you are here
+ right=192.0.2.8
+ rightsubnet=192.0.2.96/27
+ ....
+</PRE>
+<P>If you then place a host or net within<VAR> rightsubnet</VAR>, (let's
+ say 192.0.2.98) in<VAR> private-or-clear</VAR>, you may find that
+ 192.0.2.2 at times communicates in the clear with 192.0.2.98. That's
+ consistent with the rule, but may be contrary to your expectations.</P>
+<P>On the other hand, it's safe to put a larger subnet in a less
+ restrictive policy group file. If<VAR> private-or-clear</VAR> contains
+ 192.0.2.0/24, then the more specific<VAR> net-to-net</VAR> connection
+ is used for any communication to 192.0.2.96/27. The more general policy
+ applies only to communication with hosts or subnets in 192.0.2.0/24
+ without a more specific policy or connection.</P>
+<H3><A name="policy.off">Can I turn off policy groups?</A></H3>
+<P>Yes. Use<A HREF="#disable_policygroups"> these instructions</A>.</P>
+
+<!--
+<h3><a name="policy.otherinterface">Can I use policy groups
+ on an interface other than <VAR>%defaultroute</VAR>?</a></h3>
+
+<p>??<p>
+-->
+<H3><A name="reload">Can I reload connection info without restarting?</A>
+</H3>
+<P>Yes, you can do this. Here are the details, in a mailing list message
+ from Pluto programmer Hugh Redelmeier:</P>
+<PRE>| How can I reload config's without restarting all of pluto and klips? I am using
+| FreeSWAN -&gt; PGPNet in a medium sized production environment, and would like to be
+| able to add new connections ( i am using include config/* ) without dropping current
+| SA's.
+|
+| Can this be done?
+|
+| If not, are there plans to add this kind of feature?
+
+ ipsec auto --add whatever
+This will look in the usual place (/etc/ipsec.conf) for a conn named
+whatever and add it.
+
+If you added new secrets, you need to do
+ ipsec auto --rereadsecrets
+before Pluto needs to know those secrets.
+
+| I have looked (perhaps not thoroughly enough tho) to see how to do this:
+
+There may be more bits to look for, depending on what you are trying
+to do.</PRE>
+<P>Another useful command here is<VAR> ipsec auto --replace &lt;conn_name&gt;</VAR>
+ which re-reads data for a named connection.</P>
+<H3><A name="masq.faq">Can I use several masqueraded subnets?</A></H3>
+<P>Yes. This is done all the time. See the discussion in our<A href="config.html#route_or_not">
+ setup</A> document. The only restriction is that the subnets on the two
+ ends must not overlap. See the next question.</P>
+<P>Here is a mailing list message on the topic. The user incorrectly
+ thinks you need a 2.4 kernel for this -- actually various people have
+ been doing it on 2.0 and 2.2 for quite some time -- but he has it right
+ for 2.4.</P>
+<PRE>Subject: Double NAT and freeswan working :)
+ Date: Sun, 11 Mar 2001
+ From: Paul Wouters &lt;paul@xtdnet.nl&gt;
+
+Just to share my pleasure, and make an entry for people who are searching
+the net on how to do this. Here's the very simple solution to have a double
+NAT'ed network working with freeswan. (Not sure if this is old news, but I'm
+not on the list (too much spam) and I didn't read this in any HOWTO/FAQ/doc
+on the freeswan site yet (Sandy, put it in! :)
+
+10.0.0.0/24 --- 10.0.0.1 a.b.c.d ---- a.b.c.e {internet} ----+
+ |
+10.0.1.0/24 --- 10.0.1.1 f.g.h.i ---- f.g.h.j {internet} ----+
+
+the goal is to have the first network do a VPN to the second one, yet also
+have NAT in place for connections not destinated for the other side of the
+NAT. Here the two Linux security gateways have one real IP number (cable
+modem, dialup, whatever.
+
+The problem with NAT is you don't want packets from 10.*.*.* to 10.*.*.*
+to be NAT'ed. While with Linux 2.2, you can't, with Linux 2.4 you can.
+
+(This has been tested and works for 2.4.2 with Freeswan snapshot2001mar8b)
+
+relevant parts of /etc/ipsec.conf:
+
+ left=f.g.h.i
+ leftsubnet=10.0.1.0/24
+ leftnexthop=f.g.h.j
+ leftfirewall=yes
+ leftid=@firewall.netone.nl
+ leftrsasigkey=0x0........
+ right=a.b.c.d
+ rightsubnet=10.0.0.0/24
+ rightnexthop=a.b.c.e
+ rightfirewall=yes
+ rightid=@firewall.nettwo.nl
+ rightrsasigkey=0x0......
+ # To authorize this connection, but not actually start it, at startup,
+ # uncomment this.
+ auto=add
+
+and now the real trick. Setup the NAT correctly on both sites:
+
+iptables -t nat -F
+iptables -t nat -A POSTROUTING -o eth0 -d \! 10.0.0.0/8 -j MASQUERADE
+
+This tells the NAT code to only do NAT for packets with destination other then
+10.* networks. note the backslash to mask the exclamation mark to protect it
+against the shell.
+
+Happy painting :)
+
+Paul</PRE>
+<H3><A name="dup_route">Can I use subnets masqueraded to the same
+ addresses?</A></H3>
+<P><STRONG>No.</STRONG> The notion that IP addresses are unique is one
+ of the fundamental principles of the IP protocol. Messing with it is
+ exceedingly perilous.</P>
+<P>Fairly often a situation comes up where a company has several
+ branches, all using the same<A href="#non-routable"> non-routable
+ addresses</A>, perhaps 192.168.0.0/24. This works fine as long as those
+ nets are kept distinct. The<A href="#masq"> IP masquerading</A> on
+ their firewalls ensures that packets reaching the Internet carry the
+ firewall address, not the private address.</P>
+<P>This can break down when IPsec enters the picture. FreeS/WAN builds a
+ tunnel that pokes through both masquerades and delivers packets from<VAR>
+ leftsubnet</VAR> to<VAR> rightsubnet</VAR> and vice versa. For this to
+ work, the two subnets<EM> must</EM> be distinct.</P>
+<P>There are several solutions to this problem.</P>
+<P>Usually, you<STRONG> re-number the subnets</STRONG>. Perhaps the
+ Vancouver office becomes 192.168.101.0/24, Calgary 192.168.102.0/24 and
+ so on. FreeS/WAN can happily handle this. With, for example<VAR>
+ leftsubnet=192.168.101.0/24</VAR> and<VAR> rightsubnet=192.168.102.0/24</VAR>
+ in a connection description, any machine in Calgary can talk to any
+ machine in Vancouver. If you want to be more restrictive and use
+ something like<VAR> leftsubnet=192.168.101.128/25</VAR> and<VAR>
+ rightsubnet=192.168.102.240/28</VAR> so only certain machines on each
+ end have access to the tunnel, that's fine too.</P>
+<P>You could also<STRONG> split the subnet</STRONG> into smaller ones,
+ for example using<VAR> 192.168.1.0/25</VAR> in Vancouver and<VAR>
+ rightsubnet=192.168.0.128/25</VAR> in Calgary.</P>
+<P>Alternately, you can just<STRONG> give up routing</STRONG> directly
+ to machines on the subnets. Omit the<VAR> leftsubnet</VAR> and<VAR>
+ rightsubnet</VAR> parameters from your connection descriptions. Your
+ IPsec tunnels will then run between the public interfaces of the two
+ firewalls. Packets will be masqueraded both before they are put into
+ tunnels and after they emerge. Your Vancouver client machines will see
+ only one Calgary machine, the firewall.</P>
+<H3><A name="road.masq">Can I assign a road warrior an address on my net
+ (a virtual identity)?</A></H3>
+<P>Often it would be convenient to be able to give a Road Warrior an IP
+ address which appears to be on the local network. Some IPsec
+ implementations have support for this, sometimes calling the feature
+ &quot;virtual identity&quot;.</P>
+<P>Currently (Sept 2002) FreeS/WAN does not support this, and we have no
+ definite plans to add it. The difficulty is that is not yet a standard
+ mechanism for it. There is an Internet Draft for a method of doing it
+ using<A href="#DHCP"> DHCP</A> which looks promising. FreeS/WAN may
+ support that in a future release.</P>
+<P>In the meanwhile, you can do it yourself using the Linux iproute2(8)
+ facilities. Details are in<A href="http://www.av8n.com/vpn/iproute2.htm">
+ this paper</A>.</P>
+<P>Another method has also been discussed on the mailing list.:</P>
+<UL>
+<LI>You can use a variant of the<A href="#extruded.config"> extruded
+ subnet</A> procedure.</LI>
+<LI>You have to avoid having the road warrior's assigned address within
+ the range you actually use at home base. See previous question.</LI>
+<LI>On the other hand, you want the roadwarrior's address to be within
+ the range that<EM> seems</EM> to be on your network.</LI>
+</UL>
+<P>For example, you might have:</P>
+<DL>
+<DT>leftsubnet=a.b.c.0/25</DT>
+<DD>head office network</DD>
+<DT>rightsubnet=a.b.c.129/32</DT>
+<DD>extruded to a road warrior. Note that this is not in a.b.c.0/25</DD>
+<DT>a.b.c.0/24</DT>
+<DD>whole network, including both the above</DD>
+</DL>
+<P>You then set up routing so that the office machines use the IPsec
+ gateway as their route to a.b.c.128/25. The leftsubnet parameter tells
+ the road warriors to use tunnels to reach a.b.c.0/25, so you should
+ have two-way communication. Depending or your network and applications,
+ there may be some additional work to do on DNS or Windows configuration</P>
+<H3><A name="road.many">Can I support many road warriors with one
+ gateway?</A></H3>
+<P>Yes. This is easily done, using</P>
+<DL>
+<DT>either RSA authentication</DT>
+<DD>standard in the FreeS/WAN distribution</DD>
+<DT>or X.509 certificates</DT>
+<DD>requires<A href="#PKIcert"> Super FreeS/WAN or a patch</A>.</DD>
+</DL>
+<P>In either case, each Road Warrior must have a different key or
+ certificate.</P>
+<P>It is also possible using pre-shared key authentication, though we
+ don't recommend this; see the<A href="#road.PSK"> next question</A> for
+ details.</P>
+<P>If you expect to have more than a few dozen Road Warriors connecting
+ simultaneously, you may need a fairly powerful gateway machine. See our
+ document on<A href="performance.html"> FreeS/WAN performance</A>.</P>
+<H3><A name="road.PSK">Can I have many road warriors using shared secret
+ authentication?</A></H3>
+<P><STRONG>Yes, but avoid it if possible</STRONG>.</P>
+<P>You can have multiple Road Warriors using shared secret
+ authentication<STRONG> only if they all use the same secret</STRONG>.
+ You must also set:</P>
+<P></P>
+<PRE> uniqueids=no </PRE>
+<P>in the connection definition.</P>
+<P>Why it's less secure:</P>
+<UL>
+<LI>If you have many users, it becomes almost certain the secret will
+ leak</LI>
+<LI>The secret becomes quite valuable to an attacker</LI>
+<LI>All users authenticate the same way, so the gateway cannot tell them
+ apart for logging or access control purposes</LI>
+<LI>Changing the secret is difficult. You have to securely notify all
+ users.</LI>
+<LI>If you find out the secret has been compromised, you can change it,
+ but then what? None of your users can connect without the new secret.
+ How will you notify them all, quickly and securely, without using the
+ VPN?</LI>
+</UL>
+<P>This is a designed-in limitation of the<A href="#IKE"> IKE</A> key
+ negotiation protocol, not a problem with our implementation.</P>
+<P><STRONG>We very strongly recommend that you avoid using shared secret
+ authentication for multiple Road Warriors.</STRONG> Use RSA
+ authentication instead.</P>
+<P>The longer story: When using shared secrets, the protocol requires
+ that the responding gateway be able to determine which secret to use at
+ a time when all it knows about the initiator is an IP address. This
+ works fine if you know the initiator's address in advance and can use
+ it to look up the appropiriate secret. However, it fails for Road
+ Warriors since the gateway cannot know their IP addresses in advance.</P>
+<P>With RSA signatures (or certificates) the protocol is slightly
+ different. The initiator provides an identifier early in the exchange
+ and the responder can use that identifier to look up the correct key or
+ certificate. See<A href="#road.many"> above</A>.</P>
+<H3><A name="QoS">Can I use Quality of Service routing with FreeS/WAN?</A>
+</H3>
+<P>From project technical lead Henry Spencer:</P>
+<PRE>&gt; Do QoS add to FreeS/WAN?
+&gt; For example integrating DiffServ and FreeS/WAN?
+
+With a current version of FreeS/WAN, you will have to add hidetos=no to
+the config-setup section of your configuration file. By default, the TOS
+field of tunnel packets is zeroed; with hidetos=no, it is copied from the
+packet inside. (This is a modest security hole, which is why it is no
+longer the default.)
+
+DiffServ does not interact well with tunneling in general. Ways of
+improving this are being studied.</PRE>
+<P>Copying the<A href="#TOS"> TOS</A> (type of service) information from
+ the encapsulated packet to the outer header reveals the TOS information
+ to an eavesdropper. This does not tell him much, but it might be of use
+ in<A href="#traffic"> traffic analysis</A>. Since we do not have to
+ give it to him, our default is not to.</P>
+<P>Even with the TOS hidden, you can still:</P>
+<UL>
+<LI>apply QOS rules to the tunneled (ESP) packets; for example, by
+ giving ESP packets a certain priority.</LI>
+<LI>apply QOS rules to the packets as they enter or exit the tunnel via
+ an IPsec virtual interface (eg.<VAR> ipsec0</VAR>).</LI>
+</UL>
+<P>See<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> for more
+ on the<VAR> hidetos=</VAR> parameter.</P>
+<H3><A name="deadtunnel">Can I recognise dead tunnels and shut them
+ down?</A></H3>
+<P>There is no general mechanism to do this is in the IPsec protocols.</P>
+<P>From time to time, there is discussion on the IETF Working Group<A href="#ietf">
+ mailing list</A> of adding a &quot;keep-alive&quot; mechanism (which some say
+ should be called &quot;make-dead&quot;), but it is a fairly complex problem and
+ no consensus has been reached on whether or how it should be done.</P>
+<P>The protocol does have optional<A href="#ignore"> delete-SA</A>
+ messages which one side can send when it closes a connection in hopes
+ this will cause the other side to do the same. FreeS/WAN does not
+ currently support these. In any case, they would not solve the problem
+ since:</P>
+<UL>
+<LI>a gateway that crashes or hangs would not send the messages</LI>
+<LI>the sender is not required to send them</LI>
+<LI>they are not authenticated, so any receiver that trusts them leaves
+ itself open to a<A href="#DOS"> denial of service</A> attack</LI>
+<LI>the receiver is not required to do anything about them</LI>
+<LI>the receiver cannot acknowledge them; the protocol provides no
+ mechanism for that</LI>
+<LI>since they are not acknowledged, the sender cannot rely on them</LI>
+</UL>
+<P>However, connections do have limited lifetimes and you can control
+ how many attempts your gateway makes to rekey before giving up. For
+ example, you can set:</P>
+<PRE>conn default
+ keyingtries=3
+ keylife=30m</PRE>
+<P>With these settings old connections will be cleaned up. Within 30
+ minutes of the other end dying, rekeying will be attempted. If it
+ succeeds, the new connection replaces the old one. If it fails, no new
+ connection is created. Either way, the old connection is taken down
+ when its lifetime expires.</P>
+<P>Here is a mailing list message on the topic from FreeS/WAN tech
+ support person Claudia Schmeing:</P>
+<PRE>You ask how to determine whether a tunnel is redundant:
+
+&gt; Can anybody explain the best way to determine this. Esp when a RW has
+&gt; disconnected? I thought 'ipsec auto --status' might be one way.
+
+If a tunnel goes down from one end, Linux FreeS/WAN on the
+other end has no way of knowing this until it attempts to rekey.
+Once it tries to rekey and fails, it will 'know' that the tunnel is
+down.
+
+Because it doesn't have a way of knowing the state until this point,
+it will also not be able to tell you the state via ipsec auto --status.
+
+&gt; However, comparing output from a working tunnel with that of one that
+&gt; was closed
+&gt; did not show clearly show tunnel status.
+
+If your tunnel is down but not 'unrouted' (see man ipsec_auto), you
+should not be able to ping the opposite side of the tunnel. You can
+use this as an indicator of tunnel status.
+
+On a related note, you may be interested to know that as of 1.7,
+redundant tunnels caused by RW disconnections are likely to be
+less of a pain. From doc/CHANGES:
+
+ There is a new configuration parameter, uniqueids, to control a new Pluto
+ option: when a new connection is negotiated with the same ID as an old
+ one, the old one is deleted immediately. This should help eliminate
+ dangling Road Warrior connections when the same Road Warrior reconnects.
+ It thus requires that IDs not be shared by hosts (a previously legal but
+ probably useless capability). NOTE WELL: the sample ipsec.conf now has
+ uniqueids=yes in its config-setup section.
+
+
+Cheers,
+
+Claudia</PRE>
+<H3><A name="demanddial">Can I build IPsec tunnels over a demand-dialed
+ link?</A></H3>
+<P>This is possible, but not easy. FreeS/WAN technical lead Henry
+ Spencer wrote:</P>
+<PRE>&gt; 5. If the ISDN link goes down in between and is reestablished, the SAs
+&gt; are still up but the eroute are deleted and the IPsec interface shows
+&gt; garbage (with ifconfig)
+&gt; 6. Only restarting IPsec will bring the VPN back online.
+
+This one is awkward to solve. If the real interface that the IPsec
+interface is mounted on goes down, it takes most of the IPsec machinery
+down with it, and a restart is the only good way to recover.
+
+The only really clean fix, right now, is to split the machines in two:
+
+1. A minimal machine serves as the network router, and only it is aware
+that the link goes up and down.
+
+2. The IPsec is done on a separate gateway machine, which thinks it has
+a permanent network connection, via the router.
+
+This is clumsy but it does work. Trying to do both functions within a
+single machine is tricky. There is a software package (diald) which will
+give the illusion of a permanent connection for demand-dialed modem
+connections; I don't know whether it's usable for ISDN, or whether it can
+be made to cooperate properly with FreeS/WAN.
+
+Doing a restart each time the interface comes up *does* work, although it
+is a bit painful. I did that with PPP when I was running on a modem link;
+it wasn't hard to arrange the PPP scripts to bring IPsec up and down at
+the right times. (I'd meant to investigate diald but never found time.)
+
+In principle you don't need to do a complete restart on reconnect, but you
+do have to rebuild some things, and we have no nice clean way of doing
+only the necessary parts.</PRE>
+<P>In the same thread, one user commented:</P>
+<PRE>Subject: Re: linux-ipsec: IPsec and Dial Up Connections
+ Date: Wed, 22 Nov 2000
+ From: Andy Bradford &lt;andyb@calderasystems.com&gt;
+
+On Wed, 22 Nov 2000 19:47:11 +0100, Philip Reetz wrote:
+
+&gt; Are there any ideas what might be the cause of the problem and any way
+&gt; to work around it.
+&gt; Any help is highly appreciated.
+
+On my laptop, when using ppp there is a ip-up script in /etc/ppp that
+will be executed each time that the ppp interface is brought up.
+Likewise there is an ip-down script that is called when it is taken
+down. You might consider custimzing those to stop and start FreeS/WAN
+with each connection. I believe that ISDN uses the same files, though
+I could be wrong---there should be something similar though.</PRE>
+<H3><A name="GRE">Can I build GRE, L2TP or PPTP tunnels over IPsec?</A></H3>
+<P>Yes. Normally this is not necessary, but it is useful in a few
+ special cases. For example, if you must route non-IP packets such as
+ IPX, you will need to use a tunneling protocol that can route these
+ packets. IPsec can be layered around it for extra security. Another
+ example: you can provide failover protection for high availability (HA)
+ environments by combining IPsec with other tools. Ken Bantoft describes
+ one such setup in<A HREF="http://www.freeswan.ca/docs/HA"> Using
+ FreeS/WAN with Linux-HA, GRE, OSPF and BGP for enterprise grade VPN
+ solutions</A>.</P>
+<P>GRE over IPsec is covered as part of<A HREF="http://www.freeswan.ca/docs/HA">
+ that document</A>.<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/07/msg00209.html">
+ Here are links</A> to other GRE resources. Jacco de Leuw has created<A HREF="http://www.jacco2.dds.nl/networking/">
+ this page on L2TP over IPsec</A> with instructions for FreeS/WAN and
+ several other brands of IPsec software.</P>
+<P>Please let us know of other useful links via the<A HREF="mail.html">
+ mailing lists</A>.</P>
+<H3><A name="NetBIOS">... use Network Neighborhood (Samba, NetBIOS) over
+ IPsec?</A></H3>
+<P>Your local PC needs to know how to translate NetBIOS names to IP
+ addresses. It may do this either via a local LMHOSTS file, or using a
+ local or remote WINS server. The WINS server is preferable since it
+ provides a centralized source of the information to the entire network.
+ To use a WINS server over the<A HREF="#VPN"> VPN</A> (or any IP-based
+ network), you must enable &quot;NetBIOS over TCP&quot;.</P>
+<P><A HREF="http://www.samba.org">Samba</A> can emulate a WINS server on
+ Linux.</P>
+<P> See also several discussions in our<A HREF="http://lists.freeswan.org/pipermail/users/2002-September/thread.html">
+ September 2002 Users archives</A></P>
+<H2><A name="setup.faq">Life's little mysteries</A></H2>
+<P>FreeS/WAN is a fairly complex product. (Neither the networks it runs
+ on nor the protocols it uses are simple, so it could hardly be
+ otherwise.) It therefore sometimes exhibits behaviour which can be
+ somewhat confusing, or has problems which are not easy to diagnose.
+ This section tries to explain those problems.</P>
+<P>Setup and configuration of FreeS/WAN are covered in other
+ documentation sections:</P>
+<UL>
+<LI><A href="quickstart.html">basic setup and configuration</A></LI>
+<LI><A href="adv_config.html">advanced configuration</A></LI>
+<LI><A href="trouble.html">Troubleshooting</A></LI>
+</UL>
+<P>However, we also list some of the commonest problems here.</P>
+<H3><A name="cantping">I cannot ping ....</A></H3>
+<P>This question is dealt with in the advanced configuration section
+ under the heading<A href="#multitunnel"> multiple tunnels</A>.</P>
+<P>The standard subnet-to-subnet tunnel protects traffic<STRONG> only
+ between the subnets</STRONG>. To test it, you must use pings that go
+ from one subnet to the other.</P>
+<P>For example, suppose you have:</P>
+<PRE> subnet a.b.c.0/24
+ |
+ eth1 = a.b.c.1
+ gate1
+ eth0 = 192.0.2.8
+ |
+
+ ~ internet ~
+
+ |
+ eth0 = 192.0.2.11
+ gate2
+ eth1 = x.y.z.1
+ |
+ subnet x.y.z.0/24</PRE>
+<P>and the connection description:</P>
+<PRE>conn abc-xyz
+ left=192.0.2.8
+ leftsubnet=a.b.c.0/24
+ right=192.0.2.11
+ rightsubnet=x.y.z.0/24</PRE>
+<P>You can test this connection description only by sending a ping that
+ will actually go through the tunnel. Assuming you have machines at
+ addresses a.b.c.2 and x.y.z.2, pings you might consider trying are:</P>
+<DL>
+<DT>ping from x.y.z.2 to a.b.c.2 or vice versa</DT>
+<DD>Succeeds if tunnel is working. This is the<STRONG> only valid test
+ of the tunnel</STRONG>.</DD>
+<DT>ping from gate2 to a.b.c.2 or vice versa</DT>
+<DD><STRONG>Does not use tunnel</STRONG>. gate2 is not on protected
+ subnet.</DD>
+<DT>ping from gate1 to x.y.z.2 or vice versa</DT>
+<DD><STRONG>Does not use tunnel</STRONG>. gate1 is not on protected
+ subnet.</DD>
+<DT>ping from gate1 to gate2 or vice versa</DT>
+<DD><STRONG>Does not use tunnel</STRONG>. Neither gate is on a protected
+ subnet.</DD>
+</DL>
+<P>Only the first of these is a useful test of this tunnel. The others
+ do not use the tunnel. Depending on other details of your setup and
+ routing, they:</P>
+<UL>
+<LI>either fail, telling you nothing about the tunnel</LI>
+<LI>or succeed, telling you nothing about the tunnel since these packets
+ use some other route</LI>
+</UL>
+<P>In some cases, you may be able to get around this. For the example
+ network above, you could use:</P>
+<PRE> ping -I a.b.c.1 x.y.z.1</PRE>
+<P>Both the adresses given are within protected subnets, so this should
+ go through the tunnel.</P>
+<P>If required, you can build additional tunnels so that all the
+ machines involved can talk to all the others. See<A href="#multitunnel">
+ multiple tunnels</A> in the advanced configuration document for
+ details.</P>
+<H3><A name="forever">It takes forever to ...</A></H3>
+<P>Users fairly often report various problems involving long delays,
+ sometimes on tunnel setup and sometimes on operations done through the
+ tunnel, occasionally on simple things like ping or more often on more
+ complex operations like doing NFS or Samba through the tunnel.</P>
+<P>Almost always, these turn out to involve failure of a DNS lookup. The
+ timeouts waiting for DNS are typically set long so that you won't time
+ out when a query involves multiple lookups or long paths. Genuine
+ failures therefore produce long delays before they are detected.</P>
+<P>A mailing list message from project technical lead Henry Spencer:</P>
+<PRE>&gt; ... when i run /etc/rc.d/init.d/ipsec start, i get:
+&gt; ipsec_setup: Starting FreeS/WAN IPsec 1.5...
+&gt; and it just sits there, doesn't give back my bash prompt.
+
+Almost certainly, the problem is that you're using DNS names in your
+ipsec.conf, but DNS lookups are not working for some reason. You will
+get your prompt back... eventually. But the DNS timeouts are long.
+Doing something about this is on our list, but it is not easy.</PRE>
+<P>In the meanwhile, we recommend that connection descriptions in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> use numeric IP addresses rather than names which will
+ require a DNS lookup.</P>
+<P>Names that do not require a lookup are fine. For example:</P>
+<UL>
+<LI>a road warrior might use the identity<VAR>
+ rightid=@lancelot.example.org</VAR></LI>
+<LI>the gateway might use<VAR> leftid=@camelot.example.org</VAR></LI>
+</UL>
+<P>These are fine. The @ sign prevents any DNS lookup. However, do not
+ attempt to give the gateway address as<VAR> left=camelot.example.org</VAR>
+. That requires a lookup.</P>
+<P>A post from one user after solving a problem with long delays:</P>
+<PRE>Subject: Final Answer to Delay!!!
+ Date: Mon, 19 Feb 2001
+ From: &quot;Felippe Solutions&quot; &lt;felippe@solutionstecnologia.com.br&gt;
+
+Sorry people, but seems like the Delay problem had nothing to do with
+freeswan.
+
+The problem was DNS as some people sad from the beginning, but not the way
+they thought it was happening. Samba, ssh, telnet and other apps try to
+reverse lookup addresses when you use IP numbers (Stupid that ahh).
+
+I could ping very fast because I always ping with &quot;-n&quot; option, but I don't
+know the option on the other apps to stop reverse addressing so I don't use
+it.</PRE>
+<P>This post is fairly typical. These problems are often tricky and
+ frustrating to diagnose, and most turn out to be DNS-related.</P>
+<P>One suggestion for diagnosis: test with both names and addresses if
+ possible. For example, try all of:</P>
+<UL>
+<LI>ping<VAR> address</VAR></LI>
+<LI>ping -n<VAR> address</VAR></LI>
+<LI>ping<VAR> name</VAR></LI>
+</UL>
+<P>If these behave differently, the problem must be DNS-related since
+ the three commands do exactly the same thing except for DNS lookups.</P>
+<H3><A name="route">I send packets to the tunnel with route(8) but they
+ vanish</A></H3>
+<P>IPsec connections are designed to carry only packets travelling
+ between pre-defined connection endpoints. As project technical lead
+ Henry Spencer put it:</P>
+<BLOCKQUOTE> IPsec tunnels are not just virtual wires; they are virtual
+ wires with built-in access controls. Negotiation of an IPsec tunnel
+ includes negotiation of access rights for it, which don't include
+ packets to/from other IP addresses. (The protocols themselves are quite
+ inflexible about this, so there are limits to what we can do about it.)</BLOCKQUOTE>
+<P>For fairly obvious security reasons, and to comply with the IPsec
+ RFCs,<A href="#KLIPS"> KLIPS</A> drops any packets it receives that are
+ not allowed on the tunnels currently defined. So if you send it packets
+ with<VAR> route(8)</VAR>, and suitable tunnels are not defined, the
+ packets vanish. Whether this is reported in the logs depends on the
+ setting of<VAR> klipsdebug</VAR> in your<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> file.</P>
+<P>To rescue vanishing packets, you must ensure that suitable tunnels
+ for them exist, by editing the connection descriptions in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>. For example, supposing you have a simple setup:</P>
+<PRE> leftsubnet -- leftgateway === internet === roadwarrior</PRE>
+<P>If you want to give the roadwarrior access to some resource that is
+ located behind the left gateway but is not in the currently defined
+ left subnet, then the usual procedure is to define an additional tunnel
+ for those packets by creating a new connection description.</P>
+<P>In some cases, it may be easier to alter an existing connection
+ description, enlarging the definition of<VAR> leftsubnet</VAR>. For
+ example, instead of two connection descriptions with 192.168.8.0/24 and
+ 192.168.9.0/24 as their<VAR> leftsubnet</VAR> parameters, you can use a
+ single description with 192.168.8.0/23.</P>
+<P>If you have multiple endpoints on each side, you need to ensure that
+ there is a route for each pair of endpoints. See this<A href="#multitunnel">
+ example</A>.</P>
+<H3><A name="down_route">When a tunnel goes down, packets vanish</A></H3>
+<P>This is a special case of the vanishing packet problem described in
+ the previous question. Whenever KLIPS sees packets for which it does
+ not have a tunnel, it drops them.</P>
+<P>When a tunnel goes away, either because negotiations with the other
+ gateway failed or because you gave an<VAR> ipsec auto --down</VAR>
+ command, the route to its other end is left pointing into KLIPS, and
+ KLIPS will drop packets it has no tunnel for.</P>
+<P>This is a documented design decision, not a bug. FreeS/WAN must not
+ automatically adjust things to send packets via another route. The
+ other route might be insecure.</P>
+<P>Of course, re-routing may be necessary in many cases. In those cases,
+ you have to do it manually or via scripts. We provide the<VAR> ipsec
+ auto --unroute</VAR> command for these cases.</P>
+<P>From<A href="manpage.d/ipsec_auto.8.html"> ipsec_auto(8)</A>:</P>
+<BLOCKQUOTE> Normally, pluto establishes a route to the destination
+ specified for a connection as part of the --up operation. However, the
+ route and only the route can be established with the --route operation.
+ Until and unless an actual connection is established, this discards any
+ packets sent there, which may be preferable to having them sent
+ elsewhere based on a more general route (e.g., a default route).</BLOCKQUOTE><BLOCKQUOTE>
+ Normally, pluto's route to a destination remains in place when a --down
+ operation is used to take the connection down (or if connection setup,
+ or later automatic rekeying, fails). This permits establishing a new
+ connection (perhaps using a different specification; the route is
+ altered as necessary) without having a ``window'' in which packets
+ might go elsewhere based on a more general route. Such a route can be
+ removed using the --unroute operation (and is implicitly removed by
+ --delete).</BLOCKQUOTE>
+<P>See also this mailing list<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00523.html">
+ message</A>.</P>
+<H3><A name="firewall_ate">The firewall ate my packets!</A></H3>
+<P>If firewalls filter out:</P>
+<UL>
+<LI>either the UDP port 500 packets used in IKE negotiations</LI>
+<LI>or the ESP and AH (protocols 50 and 51) packets used to implement
+ the IPsec tunnel</LI>
+</UL>
+<P>then IPsec cannot work. The first thing to check if packets seem to
+ be vanishing is the firewall rules on the two gateway machines and any
+ other machines along the path that you have access to.</P>
+<P>For details, see our document on<A href="firewall.html"> firewalls</A>
+.</P>
+<P>Some advice from technical lead Henry Spencer on diagnosing such
+ problems:</P>
+<PRE>&gt; &gt; Packets vanishing between the hardware interface and the ipsecN interface
+&gt; &gt; is usually the result of firewalls not being configured to let them in...
+&gt;
+&gt; Thanks for the suggestion. If only it were that simple! My ipchains startup
+&gt; script does take care of that, but just in case I manually inserted rules
+&gt; accepting everything from london on dublin. No difference.
+
+The other thing to check is whether the &quot;RX packets dropped&quot; count on the
+ipsecN interface (run &quot;ifconfig ipsecN&quot;, for N=1 or whatever, to see the
+counts) is rising. If so, then there's some sort of configuration mismatch
+between the two ends, and IPsec itself is rejecting them. If none of the
+ipsecN counts is rising, then the packets are never reaching the IPsec
+machinery, and the problem is almost certainly in firewalls etc.</PRE>
+<H3><A name="dropconn">Dropped connections</A></H3>
+<P>Networks being what they are, IPsec connections can be broken for any
+ number of reasons, ranging from hardware failures to various software
+ problems such as the path MTU problems discussed<A href="#pmtu.broken">
+ elsewhere in the FAQ</A>. Fortunately, various diagnostic tools exist
+ that help you sort out many of the possible problems.</P>
+<P>There is one situation, however, where FreeS/WAN (using default
+ settings) may destroy a connection for no readily apparent reason. This
+ occurs when things are<STRONG> misconfigured</STRONG> so that<STRONG>
+ two tunnels</STRONG> from the same gateway expect<STRONG> the same
+ subnet on the far end</STRONG>.</P>
+<P>In this situation, the first tunnel comes up fine and works until the
+ second is established. At that point, because of the way we track
+ connections internally, the first tunnel ceases to exist as far as this
+ gateway is concerned. Of course the far end does not know that, and a
+ storm of error messages appears on both systems as it tries to use the
+ tunnel.</P>
+<P>If the far end gives up, goes back to square one and negotiates a new
+ tunnel, then that wipes out the second tunnel and ...</P>
+<P>The solution is simple.<STRONG> Do not build multiple conn
+ descriptions with the same remote subnet</STRONG>.</P>
+<P>This is actually intended to be a feature, rather than a bug.
+ Consider the situation where a single remote system goes down, then
+ comes back up and reconnects to the gateway. It is useful to have the
+ gateway tear down the old tunnel and recover resources when the
+ reconnection is made. It recognises that situation by checking the
+ remote subnet for each tunnel it builds and discarding duplicates. This
+ works fine as long as you don't configure multiple tunnels with the
+ same remote subnet.</P>
+<P>If this behaviour is inconvenient for you, you can disable it by
+ setting<VAR> uniqueids=no</VAR> in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>.</P>
+<H3><A name="defaultroutegone">Disappearing %defaultroute</A></H3>
+<P>When an underlying connection (eg. ppp) goes down, FreeS/WAN will not
+ recover properly without a little help. Here are the symptoms that
+ FreeS/WAN user Michael Carmody noticed:</P>
+<PRE>
+&gt; After about 24 hours the freeswan connection takes over the default route.
+&gt;
+&gt; i.e instead of deafult gateway pointing to the router via eth0, it becomes a
+&gt; pointer to the router via ipsec0.
+
+&gt; All internet access is then lost as all replies (and not just the link I
+&gt; wanted) are routed out ipsec0 and the router doesn't respond to the ipsec
+&gt; traffic.
+</PRE>
+<P>If you're using a FreeS/WAN 2.x/KLIPS system, simply re-attach the
+ IPsec virtual interface with<EM> ipsec tnconfig</EM> command such as:</P>
+<PRE> ipsec tnconfig --attach --virtual ipsec0 --physical ppp0</PRE>
+<P>In your command, name the physical and virtual interfaces as they
+ appear paired on your system during regular uptime. For a system with
+ several physical/virtual interface pairs on flaky links, you'll need
+ more than one such command. If you're using FreeS/WAN 1.x, you must
+ restart FreeS/WAN, which is more time consuming.</P>
+<P><A href="http://lists.freeswan.org/pipermail/design/2002-July/003070.html">
+ Here</A> is a script which can help to automate the process of
+ FreeS/WAN restart at need. It could easily be adapted to use tnconfig
+ instead.</P>
+<H3><A name="tcpdump.faq">TCPdump on the gateway shows strange things</A>
+</H3>
+ As another user pointed out, keeping the connect
+<P>Attempting to look at IPsec packets by running monitoring tools on
+ the IPsec gateway machine can produce silly results. That machine is
+ mangling the packets for IPsec, and possibly for firewall or NAT
+ purposes as well. If the internals of the machine's IP stack are not
+ what the monitoring tool expects, then the tool can misinterpret them
+ and produce nonsense output.</P>
+<P>See our<A href="#tcpdump.test"> testing</A> document for more detail.</P>
+<H3><A name="no_trace">Traceroute does not show anything between the
+ gateways</A></H3>
+<P>As far as traceroute can see, the two gateways are one hop apart; the
+ data packet goes directly from one to the other through the tunnel. Of
+ course the outer packets that implement the tunnel pass through
+ whatever lies between the gateways, but those packets are built and
+ dismantled by the gateways. Traceroute does not see them and cannot
+ report anything about their path.</P>
+<P>Here is a mailing list message with more detail.</P>
+<PRE>Date: Mon, 14 May 2001
+To: linux-ipsec@freeswan.org
+From: &quot;John S. Denker&quot; &lt;jsd@research.att.com&lt;
+Subject: Re: traceroute: one virtual hop
+
+At 02:20 PM 5/14/01 -0400, Claudia Schmeing wrote:
+&gt;
+&gt;&gt; &gt; A bonus question: traceroute in subnet to subnet enviroment looks like:
+&gt;&gt; &gt;
+&gt;&gt; &gt; traceroute to andris.dmz (172.20.24.10), 30 hops max, 38 byte packets
+&gt;&gt; &gt; 1 drama (172.20.1.1) 0.716 ms 0.942 ms 0.434 ms
+&gt;&gt; &gt; 2 * * *
+&gt;&gt; &gt; 3 andris.dmz (172.20.24.10) 73.576 ms 78.858 ms 79.434 ms
+&gt;&gt; &gt;
+&gt;&gt; &gt; Why aren't there the other hosts which take part in the delivery during
+&gt; * * * ?
+&gt;
+&gt;If there is an ipsec tunnel between GateA and Gate B, this tunnel forms a
+&gt;'virtual wire'. When it is tunneled, the original packet becomes an inner
+&gt;packet, and new ESP and/or AH headers are added to create an outer packet
+&gt;around it. You can see an example of how this is done for AH at
+&gt;doc/ipsec.html#AH . For ESP it is similar.
+&gt;
+&gt;Think about the packet's path from the inner packet's perspective.
+&gt;It leaves the subnet, goes into the tunnel, and re-emerges in the second
+&gt;subnet. This perspective is also the only one available to the
+&gt;'traceroute' command when the IPSec tunnel is up.
+
+Claudia got this exactly right. Let me just expand on a couple of points:
+
+*) GateB is exactly one (virtual) hop away from GateA. This is how it
+would be if there were a physically private wire from A to B. The
+virtually private connection should work the same, and it does.
+
+*) While the information is in transit from GateA to GateB, the hop count
+of the outer header (the &quot;envelope&quot;) is being decremented. The hop count
+of the inner header (the &quot;contents&quot; of the envelope) is not decremented and
+should not be decremented. The hop count of the outer header is not
+derived from and should not be derived from the hop count of the inner header.
+
+Indeed, even if the packets did time out in transit along the tunnel, there
+would be no way for traceroute to find out what happened. Just as
+information cannot leak _out_ of the tunnel to the outside, information
+cannot leak _into_ the tunnel from outside, and this includes ICMP messages
+from routers along the path.
+
+There are some cases where one might wish for information about what is
+happening at the IP layer (below the tunnel layer) -- but the protocol
+makes no provision for this. This raises all sorts of conceptual issues.
+AFAIK nobody has ever cared enough to really figure out what _should_
+happen, let alone implement it and standardize it.
+
+*) I consider the &quot;* * *&quot; to be a slight bug. One might wish for it to be
+replaced by &quot;GateB GateB GateB&quot;. It has to do with treating host-to-subnet
+traffic different from subnet-to-subnet traffic (and other gory details).
+I fervently hope KLIPS2 will make this problem go away.
+
+*) If you want to ask questions about the link from GateA to GateB at the
+IP level (below the tunnel level), you have to ssh to GateA and launch a
+traceroute from there.</PRE>
+<H2><A name="man4debug">Testing in stages</A></H2>
+<P>It is often useful in debugging to test things one at a time:</P>
+<UL>
+<LI>disable IPsec entirely, for example by turning it off with
+ chkconfig(8), and make sure routing works</LI>
+<LI>Once that works, try a manually keyed connection. This does not
+ require key negotiation between Pluto and the key daemon on the other
+ end.</LI>
+<LI>Once that works, try automatically keyed connections</LI>
+<LI>Once IPsec works, add packet compression</LI>
+<LI>Once everything seems to work, try stress tests with large
+ transfers, many connections, frequent re-keying, ...</LI>
+</UL>
+<P>FreeS/WAN releases are tested for all of these, so you can be
+ reasonably certain they<EM> can</EM> do them all. Of course, that does
+ not mean they<EM> will</EM> on the first try, especially if you have
+ some unusual configuration.</P>
+<P>The rest of this section gives information on diagnosing the problem
+ when each of the above steps fails.</P>
+<H3><A name="nomanual">Manually keyed connections don't work</A></H3>
+<P>Suspect one of:</P>
+<UL>
+<LI>mis-configuration of IPsec system in the /etc/ipsec.conf file
+<BR> common errors are incorrect interface or next hop information</LI>
+<LI>mis-configuration of manual connection in the /etc/ipsec.conf file</LI>
+<LI>routing problems causing IPsec packets to be lost</LI>
+<LI>bugs in KLIPS</LI>
+<LI>mismatch between the transforms we support and those another IPsec
+ implementation offers.</LI>
+</UL>
+<H3><A name="spi_error">One manual connection works, but second one
+ fails</A></H3>
+<P>This is a fairly common problem when attempting to configure multiple
+ manually keyed connections from a single gateway.</P>
+<P>Each connection must be identified by a unique<A href="#SPI"> SPI</A>
+ value. For automatic connections, these values are assigned
+ automatically. For manual connections, you must set them with<VAR> spi=</VAR>
+ statements in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A>.</P>
+<P>Each manual connection must have a unique SPI value in the range
+ 0x100 to 0x999. Two or more with the same value will fail. For details,
+ see our doc section<A href="#prodman"> Using manual keying in
+ production</A> and the man page<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>.</P>
+<H3><A name="man_no_auto">Manual connections work, but automatic keying
+ doesn't</A></H3>
+<P>The most common reason for this behaviour is a firewall dropping the
+ UDP port 500 packets used in key negotiation.</P>
+<P>Other possibilities:</P>
+<UL>
+<LI>mis-configuration of auto connection in the /etc/ipsec.conf file.
+<P>One common configuration error is forgetting that you need<VAR>
+ auto=add</VAR> to load the connection description on the receiving end
+ so it recognises the connection when the other end asks for it.</P>
+</LI>
+<LI>error in shared secret in /etc/ipsec.secrets</LI>
+<LI>one gateway lacks a route to the other so Pluto's UDP packets are
+ lost</LI>
+<LI>bugs in Pluto</LI>
+<LI>incompatibilities between Pluto's<A href="#IKE"> IKE</A>
+ implementation and the IKE at the other end of the tunnel.
+<P>Some possibile problems are discussed in out<A href="interop.html#interop.problem">
+ interoperation</A> document.</P>
+</LI>
+</UL>
+<H3><A name="nocomp">IPsec works, but connections using compression fail</A>
+</H3>
+<P>When we first added compression, we saw some problems:</P>
+<UL>
+<LI>compatibility issues with other implementations. We followed the
+ RFCs and omitted some extra material that many compression libraries
+ add by default. Some other implementations left the extras in</LI>
+<LI>bugs in assembler compression routines on non-Intel CPUs. The
+ workaround is to use C code instead of possibly problematic assembler.</LI>
+</UL>
+<P>We have not seen either problem in some time (at least six months as
+ I write in March 2002), but if you have some unusual configuration then
+ you may see them.</P>
+<H3><A name="pmtu.broken">Small packets work, but large transfers fail</A>
+</H3>
+<P>If tests with ping(1) and a small packet size succeed, but tests or
+ transfers with larger packet sizes fail, suspect problems with packet
+ fragmentation and perhaps<A href="#pathMTU"> path MTU discovery</A>.</P>
+<P>Our<A href="#bigpacket"> troubleshooting document</A> covers these
+ problems. Information on the underlying mechanism is in our<A href="#MTU.trouble">
+ background</A> document.</P>
+<H3><A name="subsub">Subnet-to-subnet works, but tests from the gateways
+ don't</A></H3>
+<P>This is described under<A href="#cantping"> I cannot ping...</A>
+ above.</P>
+<H2><A name="compile.faq">Compilation problems</A></H2>
+<H3><A name="gmp.h_missing">gmp.h: No such file or directory</A></H3>
+<P>Pluto needs the GMP (<STRONG>G</STRONG>NU</P>
+<P><STRONG>M</STRONG>ulti-<STRONG>P</STRONG>recision) library for the
+ large integer calculations it uses in<A href="#public"> public key</A>
+ cryptography. This error message indicates a failure to find the
+ library. You must install it before Pluto will compile.</P>
+<P>The GMP library is included in most Linux distributions. Typically,
+ there are two RPMs, libgmp and libgmp-devel, You need to<EM> install
+ both</EM>, either from your distribution CDs or from your vendor's web
+ site.</P>
+<P>On Debian, a mailing list message reports that the command to give is<VAR>
+ apt-get install gmp2</VAR>.</P>
+<P>For more information and the latest version, see the<A href="http://www.swox.com/gmp/">
+ GMP home page</A>.</P>
+<H3><A name="noVM">... virtual memory exhausted</A></H3>
+<P>We have had several reports of this message appearing, all on SPARC
+ Linux. Here is a mailing message on a solution:</P>
+<PRE>&gt; ipsec_sha1.c: In function `SHA1Transform':
+&gt; ipsec_sha1.c:95: virtual memory exhausted
+
+I'm seeing exactly the same problem on an Ultra with 256MB ram and 500
+MB swap. Except I am compiling version 1.5 and its Red Hat 6.2.
+
+I can get around this by using -O instead of -O2 for the optimization
+level. So it is probably a bug in the optimizer on the sparc complier.
+I'll try and chase this down on the sparc lists.</PRE>
+<H2><A name="error">Interpreting error messages</A></H2>
+<H3><A name="route-client">route-client (or host) exited with status 7</A>
+</H3>
+<P>Here is a discussion of this error from FreeS/WAN &quot;listress&quot; (mailing
+ list tech support person) Claudia Schmeing. The &quot;FAQ on the network
+ unreachable error&quot; which she refers to is the next question below.</P>
+<PRE>&gt; I reached the point where the two boxes (both on dial-up connections, but
+&gt; treated as static IPs by getting the IP and editing ipsec.conf after the
+&gt; connection is established) to the point where they exchange some info, but I
+&gt; get an error like &quot;route-client command exited with status 7 \n internal
+&gt; error&quot;.
+&gt; Where can I find a description of this error?
+
+In general, if the FAQ doesn't cover it, you can search the mailing list
+archives - I like to use
+http://www.sandelman.ottawa.on.ca/linux-ipsec/
+but you can see doc/mail.html for different archive formats.
+
+
+Your error comes from the _updown script, which performs some
+routing and firewall functions to help Linux FreeS/WAN. More info
+is available at doc/firewall.html and man ipsec.conf. Its routing
+is integral to the health of Linux FreeS/WAN; it also provides facility
+to insert custom firewall rules to be executed when you create or destroy
+a connection.
+
+Yours is, of course, a routing error. You can be fairly sure the routing
+machinery is saying &quot;network is unreachable&quot;. There's a FAQ on the
+&quot;network is unreachable&quot; error, but more information is available now; read on.
+
+If your _updown script is recent (for example if it shipped with
+Linux FreeS/WAN 1.91), you will see another debugging line in your logs
+that looks something like this:
+
+&gt; output: /usr/local/lib/ipsec/_updown: `route add -net 128.174.253.83
+&gt; netmask 255.255.255.255 dev ipsec0 gw 66.92.93.161' failed
+
+This is, of course, the system route command that exited with status 7,
+(ie. failed). Man route for details. Seeing the command typed out yields
+more information. If your _updown script is older, you may wish to update
+it to show the command explicitly.
+
+Three parameters fed to the route command: net, netmask and gw [gateway]
+are derived from things you've put in ipsec.conf.
+
+Net and netmask are derived from the peer's IP and mask. In more detail:
+
+You may see a routing error when routing to a client (ie. subnet), or
+to a host (IPSec gateway or freestanding host; a box that does IPSec for
+itself). In _updown, the &quot;route-client&quot; section is responsible to set up
+the route for IPSec'd (usually, read 'tunneled') packets headed to a
+peer subnet. Similarly, route-host routes IPSec'd packets to a peer host
+or IPSec gateway.
+
+When routing to a 'client', net and netmask are ipsec.conf's left- or
+rightsubnet (whichever is not local). Similarly, when routing to a
+'host' the net is left or right. Host netmask is always /32, indicating a
+single machine.
+
+Gw is nexthop's value. Again, the value in question is left- or rightnexthop,
+whichever is local. Where left/right or left-/rightnexthop has the special
+value %defaultroute (described in man ipsec.conf), gw will automagically get
+the value of the next hop on the default route.
+
+Q: &quot;What's a nexthop and why do I need one?&quot;
+
+A: 'nexthop' is a routing kluge; its value is the next hop away
+ from the machine that's doing IPSec, and toward your IPSec peer.
+ You need it to get the processed packets out of the local system and
+ onto the wire. While we often route other packets through the machine
+ that's now doing IPSec, and are done with it, this does not suffice here.
+ After packets are processed with IPSec, this machine needs to know where
+ they go next. Of course using the 'IPSec gateway' as their routing gateway
+ would cause an infinite loop! [To visualize this, see the packet flow
+ diagram at doc/firewall.html.] To avoid this, we route packets through
+ the next hop down their projected path.
+
+Now that you know the background, consider:
+1. Did you test routing between the gateways in the absence of Linux
+ FreeS/WAN, as recommended? You need to ensure the two machines that
+ will be running Linux FreeS/WAN can route to one another before trying to
+ make a secure connection.
+2. Is there anything obviously wrong with the sense of your route command?
+
+Normally, this problem is caused by an incorrect local nexthop parameter.
+Check out the use of %defaultroute, described in man ipsec.conf. This is
+a simple way to set nexthop for most people. To figure nexthop out by hand,
+traceroute in-the-clear to your IPSec peer. Nexthop is the traceroute's
+first hop after your IPSec gateway.</PRE>
+<H3><A name="unreachable">SIOCADDRT:Network is unreachable</A></H3>
+<P>This message is not from FreeS/WAN, but from the Linux IP stack
+ itself. That stack is seeing packets it has no route for, either
+ because your routing was broken before FreeS/WAN started or because
+ FreeS/WAN's changes broke it.</P>
+<P>Here is a message from Claudia suggesting ways to diagnose and fix
+ such problems:</P>
+<PRE>You write,
+&gt; I have correctly installed freeswan-1.8 on RH7.0 kernel 2.2.17, but when
+&gt; I setup a VPN connection with the other machine(RH5.2 Kernel 2.0.36
+&gt; freeswan-1.0, it works well.) it told me that
+&gt; &quot;SIOCADDRT:Network is unreachable&quot;! But the network connection is no
+&gt; problem.
+
+Often this error is the result of a misconfiguration.
+
+Be sure that you can route successfully in the absence of Linux
+FreeS/WAN. (You say this is no problem, so proceed to the next step.)
+
+Use a custom copy of the default updownscript. Do not change the route
+commands, but add a diagnostic message revealing the exact text of the
+route command. Is there a problem with the sense of the route command
+that you can see? If so, then re-examine those ipsec.conf settings
+that are being sent to the route command.
+
+You may wish to use the ipsec auto --route and --unroute commands to
+troubleshoot the problem. See man ipsec_auto for details.</PRE>
+<P>Since the above message was written, we have modified the updown
+ script to provide a better diagnostic for this problem. Check<VAR>
+ /var/log/messages</VAR>.</P>
+<P>See also the FAQ question<A href="#route-client"> route-client (or
+ host) exited with status 7</A>.</P>
+<H3><A name="modprobe">ipsec_setup: modprobe: Can't locate module ipsec</A>
+</H3>
+<H3><A name="noKLIPS">ipsec_setup: Fatal error, kernel appears to lack
+ KLIPS</A></H3>
+<P>These messages indicate an installation failure. The kernel you are
+ running does not contain the<A href="#KLIPS"> KLIPS (kernel IPsec)</A>
+ code.</P>
+<P>Note that the &quot;modprobe: Can't locate module ipsec&quot; message appears
+ even if you are not using modules. If there is no KLIPS in your kernel,
+ FreeS/WAN tries to load it as a module. If that fails, you get this
+ message.</P>
+<P>Commands you can quickly try are:</P>
+<DL>
+<DT><VAR>uname -a</VAR></DT>
+<DD>to get details, including compilation date and time, of the
+ currently running kernel</DD>
+<DT><VAR>ls /</VAR></DT>
+<DT><VAR>ls /boot</VAR></DT>
+<DD>to ensure a new kernel is where it should be. If kernel compilation
+ puts it in<VAR> /</VAR> but<VAR> lilo</VAR> wants it in<VAR> /boot</VAR>
+, then you should uncomment the<VAR> INSTALL_PATH=/boot</VAR> line in
+ the kernel<VAR> Makefile</VAR>.</DD>
+<DT><VAR>more /etc/lilo.conf</VAR></DT>
+<DD>to see that<VAR> lilo</VAR> has correct information</DD>
+<DT><VAR>lilo</VAR></DT>
+<DD>to ensure that information in<VAR> /etc/lilo.conf</VAR> has been
+ transferred to the boot sector</DD>
+</DL>
+<P>If those don't find the problem, you have to go back and check
+ through the<A href="install.html"> install</A> procedure to see what
+ was missed.</P>
+<P>Here is one of Claudia's messages on the topic:</P>
+<PRE>&gt; I tried to install freeswan 1.8 on my mandrake 7.2 test box. ...
+
+&gt; It does show version and some output for whack.
+
+Yes, because the Pluto (daemon) part of ipsec is installed correctly, but
+as we see below the kernel portion is not.
+
+&gt; However, I get the following from /var/log/messages:
+&gt;
+&gt; Mar 11 22:11:55 pavillion ipsec_setup: Starting FreeS/WAN IPsec 1.8...
+&gt; Mar 11 22:12:02 pavillion ipsec_setup: modprobe: Can't locate module ipsec
+&gt; Mar 11 22:12:02 pavillion ipsec_setup: Fatal error, kernel appears to lack
+&gt; KLIPS.
+
+This is your problem. You have not successfully installed a kernel with
+IPSec machinery in it.
+
+Did you build Linux FreeS/WAN as a module? If so, you need to ensure that
+your new module has been installed in the directory where your kernel
+loader normally finds your modules. If not, you need to ensure
+that the new IPSec-enabled kernel is being loaded correctly.
+
+See also doc/install.html, and INSTALL in the distro.</PRE>
+<H3><A name="noDNS">ipsec_setup: ... failure to fetch key for ... from
+ DNS</A></H3>
+<P>Quoting Henry:</P>
+<PRE>Note that by default, FreeS/WAN is now set up to
+ (a) authenticate with RSA keys, and
+ (b) fetch the public key of the far end from DNS.
+Explicit attention to ipsec.conf will be needed if you want
+to do something different.</PRE>
+<P>and Claudia, responding to the same user:</P>
+<PRE>You write,
+
+&gt; My current setup in ipsec.conf is leftrsasigkey=%dns I have
+&gt; commented this and authby=rsasig out. I am able to get ipsec running,
+&gt; but what I find is that the documentation only specifies for %dns are
+&gt; there any other values that can be placed in this variable other than
+&gt; %dns and the key? I am also assuming that this is where I would place
+&gt; my public key for the left and right side as well is this correct?
+
+Valid values for authby= are rsasig and secret, which entail authentication
+by RSA signature or by shared secret, respectively. Because you have
+commented authby=rsasig out, you are using the default value of authby=secret.
+
+When using RSA signatures, there are two ways to get the public key for the
+IPSec peer: either copy it directly into *rsasigkey= in ipsec.conf, or
+fetch it from dns. The magic value %dns for *rsasigkey parameters says to
+try to fetch the peer's key from dns.
+
+For any parameters, you may find their significance and special values in
+man ipsec.conf. If you are setting up keys or secrets, be sure also to
+reference man ipsec.secrets.</PRE>
+<H3><A name="dup_address">ipsec_setup: ... interfaces ... and ... share
+ address ...</A></H3>
+<P>This is a fatal error. FreeS/WAN cannot cope with two or more
+ interfaces using the same IP address. You must re-configure to avoid
+ this.</P>
+<P>A mailing list message on the topic from Pluto developer Hugh
+ Redelmeier:</P>
+<PRE>| I'm trying to get freeswan working between two machine where one has a ppp
+| interface.
+| I've already suceeded with two machines with ethernet ports but the ppp
+| interface is causing me problems.
+| basically when I run ipsec start i get
+| ipsec_setup: Starting FreeS/WAN IPsec 1.7...
+| ipsec_setup: 003 IP interfaces ppp1 and ppp0 share address 192.168.0.10!
+| ipsec_setup: 003 IP interfaces ppp1 and ppp2 share address 192.168.0.10!
+| ipsec_setup: 003 IP interfaces ppp0 and ppp2 share address 192.168.0.10!
+| ipsec_setup: 003 no public interfaces found
+|
+| followed by lots of cannot work out interface for connection messages
+|
+| now I can specify the interface in ipsec.conf to be ppp0 , but this does
+| not affect the above behaviour. A quick look in server.c indicates that the
+| interfaces value is not used but some sort of raw detect happens.
+|
+| I guess I could prevent the formation of the extra ppp interfaces or
+| allocate them different ip but I'd rather not. if at all possible. Any
+| suggestions please.
+
+Pluto won't touch an interface that shares an IP address with another.
+This will eventually change, but it probably won't happen soon.
+
+For now, you will have to give the ppp1 and ppp2 different addresses.</PRE>
+<H3><A name="kflags">ipsec_setup: Cannot adjust kernel flags</A></H3>
+<P>A mailing list message form technical lead Henry Spencer:</P>
+<PRE>&gt; When FreeS/WAN IPsec 1.7 is starting on my 2.0.38 Linux kernel the following
+&gt; error message is generated:
+&gt; ipsec_setup: Cannot adjust kernel flags, no /proc/sys/net/ipsec directory!
+&gt; What is supposed to create this directory and how can I fix this problem?
+
+I think that directory is a 2.2ism, although I'm not certain (I don't have
+a 2.0.xx system handy any more for testing). Without it, some of the
+ipsec.conf config-setup flags won't work, but otherwise things should
+function. </PRE>
+<P>You also need to enable the<VAR> /proc</VAR> filesystem in your
+ kernel configuration for these operations to work.</P>
+<H3><A name="message_num">Message numbers (MI3, QR1, et cetera) in Pluto
+ messages</A></H3>
+<P>Pluto messages often indicate where Pluto is in the IKE protocols.
+ The letters indicate<STRONG> M</STRONG>ain mode or<STRONG> Q</STRONG>
+uick mode and<STRONG> I</STRONG>nitiator or<STRONG> R</STRONG>esponder.
+ The numerals are message sequence numbers. For more detail, see our<A href="#sequence">
+ IPsec section</A>.</P>
+<H3><A name="conn_name">Connection names in Pluto error messages</A></H3>
+<P>From Pluto programmer Hugh Redelmeier:</P>
+<PRE>| Jan 17 16:21:10 remus Pluto[13631]: &quot;jumble&quot; #1: responding to Main Mode from Road Warrior 130.205.82.46
+| Jan 17 16:21:11 remus Pluto[13631]: &quot;jumble&quot; #1: no suitable connection for peer @banshee.wittsend.com
+|
+| The connection &quot;jumble&quot; has nothing to do with the incoming
+| connection requests, which were meant for the connection &quot;banshee&quot;.
+
+You are right. The message tells you which Connection Pluto is
+currently using, which need not be the right one. It need not be the
+right one now for the negotiation to eventually succeed! This is
+described in ipsec_pluto(8) in the section &quot;Road Warrior Support&quot;.
+
+There are two times when Pluto will consider switching Connections for
+a state object. Both are in response to receiving ID payloads (one in
+Phase 1 / Main Mode and one in Phase 2 / Quick Mode). The second is
+not unique to Road Warriors. In fact, neither is the first any more
+(two connections for the same pair of hosts could differ in Phase 1 ID
+payload; probably nobody else has tried this).</PRE>
+<H3><A name="cantorient">Pluto: ... can't orient connection</A></H3>
+<P>Older versions of FreeS/WAN used this message. The same error now
+ gives the &quot;we have no ipsecN ...&quot; error described just below.</P>
+<H3><A name="no.interface">... we have no ipsecN interface for either
+ end of this connection</A></H3>
+<P>Your tunnel has no IP address which matches the IP address of any of
+ the available IPsec interfaces. Either you've misconfigured the
+ connection, or you need to define an appropriate IPsec interface
+ connection.<VAR> interfaces=%defaultroute</VAR> works in many cases.</P>
+<P>A longer story: Pluto needs to know whether it is running on the
+ machine which the connection description calls<VAR> left</VAR> or on<VAR>
+ right</VAR>. It figures that out by:</P>
+<UL>
+<LI>looking at the interfaces given in<VAR> interfaces=</VAR> lines in
+ the<VAR> config setup</VAR> section</LI>
+<LI>discovering the IP addresses for those interfaces</LI>
+<LI>searching for a match between those addresses and the ones given in<VAR>
+ left=</VAR> or<VAR> right=</VAR> lines.</LI>
+</UL>
+<P>Normally a match is found. Then Pluto knows where it is and can set
+ up other things (for example, if it is<VAR> left</VAR>) using
+ parameters such as<VAR> leftsubnet</VAR> and<VAR> leftnexthop</VAR>,
+ and sending its outgoing packets to<VAR> right</VAR>.</P>
+<P>If no match is found, it emits the above error message.</P>
+<H3><A name="noconn">Pluto: ... no connection is known</A></H3>
+<P>This error message occurs when a remote system attempts to negotiate
+ a connection and Pluto does not have a connection description that
+ matches what the remote system has requested. The most common cause is
+ a configuration error on one end or the other.</P>
+<P>Parameters involved in this match are<VAR> left</VAR>,<VAR> right</VAR>
+,<VAR> leftsubnet</VAR> and<VAR> rightsubnet</VAR>.</P>
+<P><STRONG>The match must be exact</STRONG>. For example, if your left
+ subnet is a.b.c.0/24 then neither a single machine in that net nor a
+ smaller subnet such as a.b.c.64/26 will be considered a match.</P>
+<P>The message can also occur when an appropriate description exists but
+ Pluto has not loaded it. Use an<VAR> auto=add</VAR> statement in the
+ connection description, or an<VAR> ipsec auto --add &lt;conn_name&gt;</VAR>
+ command, to correct this.</P>
+<P>An explanation from the Pluto developer:</P>
+<PRE>| Jul 12 15:00:22 sohar58 Pluto[574]: &quot;corp_road&quot; #2: cannot respond to IPsec
+| SA request because no connection is known for
+| 216.112.83.112/32===216.112.83.112...216.67.25.118
+
+This is the first message from the Pluto log showing a problem. It
+means that PGPnet is trying to negotiate a set of SAs with this
+topology:
+
+216.112.83.112/32===216.112.83.112...216.67.25.118
+^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
+client on our side our host PGPnet host, no client
+
+None of the conns you showed look like this.
+
+Use
+ ipsec auto --status
+to see a snapshot of what connections are in pluto, what
+negotiations are going on, and what SAs are established.
+
+The leftsubnet= (client) in your conn is 216.112.83.64/26. It must
+exactly match what pluto is looking for, and it does not.</PRE>
+<H3><A name="nosuit">Pluto: ... no suitable connection ...</A></H3>
+<P>This is similar to the<A href="#noconn"> no connection known</A>
+ error, but occurs at a different point in Pluto processing.</P>
+<P>Here is one of Claudia's messages explaining the problem:</P>
+<PRE>You write,
+
+&gt; What could be the reason of the following error?
+&gt; &quot;no suitable connection for peer '@xforce'&quot;
+
+When a connection is initiated by the peer, Pluto must choose which entry in
+the conf file best matches the incoming connection. A preliminary choice is
+made on the basis of source and destination IPs, since that information is
+available at that time.
+
+A payload containing an ID arrives later in the negotiation. Based on this
+id and the *id= parameters, Pluto refines its conn selection. ...
+
+The message &quot;no suitable connection&quot; indicates that in this refining step,
+Pluto does not find a connection that matches that ID.
+
+Please see &quot;Selecting a connection when responding&quot; in man ipsec_pluto for
+more details.</PRE>
+<P>See also<A href="#conn_name"> Connection names in Pluto error
+ messages</A>.</P>
+<H3><A name="noconn.auth">Pluto: ... no connection has been authorized</A>
+</H3>
+<P>Here is one of Claudia's messages discussing this problem:</P>
+<PRE>You write,
+
+&gt; May 22 10:46:31 debian Pluto[25834]: packet from x.y.z.p:10014:
+&gt; initial Main Mode message from x.y.z.p:10014
+ but no connection has been authorized
+
+This error occurs early in the connection negotiation process,
+at the first step of IKE negotiation (Main Mode), which is itself the
+first of two negotiation phases involved in creating an IPSec connection.
+
+Here, Linux FreeS/WAN receives a packet from a potential peer, which
+requests that they begin discussing a connection.
+
+The &quot;no connection has been authorized&quot; means that there is no connection
+description in Linux FreeS/WAN's internal database that can be used to
+link your ipsec interface with that peer.
+
+&quot;But of course I configured that connection!&quot;
+
+It may be that the appropriate connection description exists in ipsec.conf
+but has not been added to the database with ipsec auto --add myconn or the
+auto=add method. Or, the connection description may be misconfigured.
+
+The only parameters that are relevant in this decision are left= and right= .
+Local and remote ports are also taken into account -- we see that the port
+is printed in the message above -- but there is no way to control these
+in ipsec.conf.
+
+
+Failure at &quot;no connection has been authorized&quot; is similar to the
+&quot;no connection is known for...&quot; error in the FAQ, and the &quot;no suitable
+connection&quot; error described in the snapshot's FAQ. In all three cases,
+Linux FreeS/WAN is trying to match parameters received in the
+negotiation with the connection description in the local config file.
+
+As it receives more information, its matches take more parameters into
+account, and become more precise: first the pair of potential peers,
+then the peer IDs, then the endpoints (including any subnets).
+
+The &quot;no suitable connection for peer *&quot; occurs toward the end of IKE
+(Main Mode) negotiation, when the IDs are matched.
+
+&quot;no connection is known for a/b===c...d&quot; is seen at the beginning of IPSec
+(Quick Mode, phase 2) negotiation, when the connections are matched using
+left, right, and any information about the subnets.</PRE>
+<H3><A name="noDESsupport">Pluto: ... OAKLEY_DES_CBC is not supported.</A>
+</H3>
+<P>This message occurs when the other system attempts to negotiate a
+ connection using<A href="#DES"> single DES</A>, which we do not support
+ because it is<A href="#desnotsecure"> insecure</A>.</P>
+<P>Our interoperation document has suggestions for<A href="interop.html#noDES">
+ how to deal with</A> systems that attempt to use single DES.</P>
+<H3><A name="notransform">Pluto: ... no acceptable transform</A></H3>
+<P>This message means that the other gateway has made a proposal for
+ connection parameters, but nothing they proposed is acceptable to
+ Pluto. Possible causes include:</P>
+<UL>
+<LI>misconfiguration on either end</LI>
+<LI>policy incompatibilities, for example we require encrypted
+ connections but they are trying to create one with just authentication</LI>
+<LI>interoperation problems, for example they offer only single DES and
+ FreeS/WAN does not support that. See<A href="interop.html#interop.problem">
+ discussion</A> in our interoperation document.</LI>
+</UL>
+<P>A more detailed explanation, from Pluto programmer Hugh Redelmeier:</P>
+<PRE>Background:
+
+When one IKE system (for example, Pluto) is negotiating with another
+to create an SA, the Initiator proposes a bunch of choices and the
+Responder replies with one that it has selected.
+
+The structure of the choices is fairly complicated. An SA payload
+contains a list of lists of &quot;Proposals&quot;. The outer list is a set of
+choices: the selection must be from one element of this list.
+
+Each of these elements is a list of Proposals. A selection must be
+made from each of the elements of the inner list. In other words,
+*all* of them apply (that is how, for example, both AH and ESP can
+apply at once).
+
+Within each of these Proposals is a list of Transforms. For each
+Proposal selected, one Transform must be selected (in other words,
+each Proposal provides a choice of Transforms).
+
+Each Transform is made up of a list of Attributes describing, well,
+attributes. Such as lifetime of the SA. Such as algorithm to be
+used. All the Attributes apply to a Transform.
+
+You will have noticed a pattern here: layers alternate between being
+disjunctions (&quot;or&quot;) and conjunctions (&quot;and&quot;).
+
+For Phase 1 / Main Mode (negotiating an ISAKMP SA), this structure is
+cut back. There must be exactly one Proposal. So this degenerates to
+a list of Transforms, one of which must be chosen.
+
+In your case, no proposal was considered acceptable to Pluto (the
+Responder). So negotiation ceased. Pluto logs the reason it rejects
+each Transform. So look back in the log to see what is going wrong.</PRE>
+<H3><A name="rsasigkey">rsasigkey dumps core</A></H3>
+ A comment on this error from Henry:
+<PRE>On Fri, 29 Jun 2001, Rodrigo Gruppelli wrote:
+&gt; ...Well, it seem that there's
+&gt; another problem with it. When I try to generate a pair of RSA keys,
+&gt; rsasigkey cores dump...
+
+*That* is a neon sign flashing &quot;GMP LIBRARY IS BROKEN&quot;. Rsasigkey calls
+GMP a lot, and our own library a little bit, and that's very nearly all it
+does. Barring bugs in its code or our library -- which have happened, but
+not very often -- a problem in rsasigkey is a problem in GMP.</PRE>
+<P>See the next question for how to deal with GMP errors.</P>
+<H3><A name="sig4">!Pluto failure!: ... exited with ... signal 4</A></H3>
+<P>Pluto has died. Signal 4 is SIGILL, illegal instruction.</P>
+<P>The most likely cause is that your<A href="#GMP"> GMP</A> (GNU
+ multi-precision) library is compiled for a different processor than
+ what you are running on. Pluto uses that library for its public key
+ calculations.</P>
+<P>Try getting the GMP sources and recompile for your processor type.
+ Most Linux distributions will include this source, or you can download
+ it from the<A href="http://www.swox.com/gmp/"> GMP home page</A>.</P>
+<H3><A name="econnrefused">ECONNREFUSED error message</A></H3>
+<P>From John Denker, on the mailing list:</P>
+<PRE>1) The log message
+ some IKE message we sent has been rejected with
+ ECONNREFUSED (kernel supplied no details)
+is much more suitable than the previous version. Thanks.
+
+2) Minor suggestion for further improvement: it might be worth mentioning
+that the command
+ tcpdump -i eth1 icmp[0] != 8 and icmp[0] != 0
+is useful for tracking down the details in question. We shouldn't expect
+all IPsec users to figure that out on their own. The log message might
+even provide a hint as to where to look in the docs.</PRE>
+<P>Reply From Pluto developer Hugh Redelmeier</P>
+<PRE>Good idea.
+
+I've added a bit pluto(8)'s BUGS section along these lines.
+I didn't have the heart to lengthen this message.</PRE>
+<H3><A name="no_eroute">klips_debug: ... no eroute!</A></H3>
+<P>This message means<A href="#KLIPS"> KLIPS</A> has received a packet
+ for which no IPsec tunnel has been defined.</P>
+<P>Here is a more detailed duscussion from the team's tech support
+ person Claudia Schmeing, responding to a query on the mailing list:</P>
+<PRE>&gt; Why ipsec reports no eroute! ???? IP Masq... is disabled.
+
+In general, more information is required so that people on the list may
+give you informed input. See doc/prob.report.</PRE>
+<P>The document she refers to has since been replaced by a<A href="#prob.report">
+ section</A> of the troubleshooting document.</P>
+<PRE>However, I can make some general comments on this type of error.
+
+This error usually looks something like this (clipped from an archived
+message):
+
+&gt; ttl:64 proto:1 chk:45459 saddr:192.168.1.2 daddr:192.168.100.1
+&gt; ... klips_debug:ipsec_findroute: 192.168.1.2-&gt;192.168.100.1
+&gt; ... klips_debug:rj_match: * See if we match exactly as a host destination
+&gt; ... klips_debug:rj_match: ** try to match a leaf, t=0xc1a260b0
+&gt; ... klips_debug:rj_match: *** start searching up the tree, t=0xc1a260b0
+&gt; ... klips_debug:rj_match: **** t=0xc1a260c8
+&gt; ... klips_debug:rj_match: **** t=0xc1fe5960
+&gt; ... klips_debug:rj_match: ***** not found.
+&gt; ... klips_debug:ipsec_tunnel_start_xmit: Original head/tailroom: 2, 28
+&gt; ... klips_debug:ipsec_tunnel_start_xmit: no eroute!: ts=47.3030, dropping.
+
+
+What does this mean?
+- --------------------
+
+&quot;eroute&quot; stands for &quot;extended route&quot;, and is a special type of route
+internal to Linux FreeS/WAN. For more information about this type of route,
+see the section of man ipsec_auto on ipsec auto --route.
+
+&quot;no eroute!&quot; here means, roughly, that Linux FreeS/WAN cannot find an
+appropriate tunnel that should have delivered this packet. Linux
+FreeS/WAN therefore drops the packet, with the message &quot;no eroute! ...
+dropping&quot;, on the assumption that this packet is not a legitimate
+transmission through a properly constructed tunnel.
+
+
+How does this situation come about?
+- -----------------------------------
+
+Linux FreeS/WAN has a number of connection descriptions defined in
+ipsec.conf. These must be successfully brought &quot;up&quot; to form actual tunnels.
+(see doc/setup.html's step 15, man ipsec.conf and man ipsec_auto
+for details).
+
+Such connections are often specific to the endpoints' IPs. However, in
+some cases they may be more general, for example in the case of
+Road Warriors where left or right is the special value %any.
+
+When Linux FreeS/WAN receives a packet, it verifies that the packet has
+come through a legitimate channel, by checking that there is an
+appropriate tunnel through which this packet might legitimately have
+arrived. This is the process we see above.
+
+First, it checks for an eroute that exactly matches the packet. In the
+example above, we see it checking for a route that begins at 192.168.1.2
+and ends at 192.168.100.1. This search favours the most specific match that
+would apply to the route between these IPs. So, if there is a connection
+description exactly matching these IPs, the search will end there. If not,
+the code will search for a more general description matching the IPs.
+If there is no match, either specific or general, the packet will be
+dropped, as we see, above.
+
+Unless you are working with Road Warriors, only the first, specific part
+of the matching process is likely to be relevant to you.
+
+
+&quot;But I defined the tunnel, and it came up, why do I have this error?&quot;
+- ---------------------------------------------------------------------
+
+One of the most common causes of this error is failure to specify enough
+connection descriptions to cover all needed tunnels between any two
+gateways and their respective subnets. As you have noticed, troubleshooting
+this error may be complicated by the use of IP Masq. However, this error is
+not limited to cases where IP Masq is used.
+
+See doc/configuration.html#multitunnel for a detailed example of the
+solution to this type of problem.</PRE>
+<P>The documentation section she refers to is now<A href="#multitunnel">
+ here</A>.</P>
+<H3><A name="SAused">... trouble writing to /dev/ipsec ... SA already in
+ use</A></H3>
+<P>This error message occurs when two manual connections are set up with
+ the same SPI value.</P>
+<P>See the FAQ for<A href="#spi_error"> One manual connection works, but
+ second one fails</A>.</P>
+<H3><A name="ignore">... ignoring ... payload</A></H3>
+<P>This message is harmless. The IKE protocol provides for a number of
+ optional messages types:</P>
+<UL>
+<LI>delete SA</LI>
+<LI>initial contact</LI>
+<LI>vendor ID</LI>
+<LI>...</LI>
+</UL>
+<P>An implementation is never required to send these, but they are
+ allowed to. The receiver is not required to do anything with them.
+ FreeS/WAN ignores them, but notifies you via the logs.</P>
+<P>For the &quot;ignoring delete SA Payload&quot; message, see also our discussion
+ of cleaning up<A href="#deadtunnel"> dead tunnels</A>.</P>
+<H3><A name="unknown_rightcert">unknown parameter name &quot;rightcert&quot;</A></H3>
+<P>This message can appear when you've upgraded an X.509-enabled Linux
+ FreeS/WAN with a vanilla Linux FreeS/WAN. To use your X.509 configs you
+ will need to overwrite the new install with<A HREF="http://www.freeswan.ca">
+ Super FreeS/WAN</A>, or add the<A HREF="http://www.strongsec.ca/freeswan">
+ X.509 patch</A> by hand.</P>
+<H2><A name="spam">Why don't you restrict the mailing lists to reduce
+ spam?</A></H2>
+<P>As a matter of policy, some of our<A href="mail.html"> mailing lists</A>
+ need to be open to non-subscribers. Project management feel strongly
+ that maintaining this openness is more important than blocking spam.</P>
+<UL>
+<LI>Users should be able to get help or report bugs without subscribing.</LI>
+<LI>Even a user who is subscribed may not have access to his or her
+ subscribed account when he or she needs help, miles from home base in
+ the middle of setting up a client's gateway.</LI>
+<LI>There is arguably a legal requirement for this policy. A US resident
+ or citizen could be charged under munitions export laws for providing
+ technical assistance to a foreign cryptographic project. Such a charge
+ would be more easily defended if the discussion takes place in public,
+ on an open list.</LI>
+</UL>
+<P>This has been discussed several times at some length on the list. See
+ the<A href="#archive"> list archives</A>. Bringing the topic up again
+ is unlikely to be useful. Please don't. Or at the very least, please
+ don't without reading the archives and being certain that whatever you
+ are about to suggest has not yet been discussed.</P>
+<P>Project technical lead Henry Spencer summarised one discussion:</P>
+<BLOCKQUOTE> For the third and last time: this list *will* *not* do
+ address-based filtering. This is a policy decision, not an
+ implementation problem. The decision is final, and is not open to
+ discussion. This needs to be communicated better to people, and steps
+ are being taken to do that.</BLOCKQUOTE>
+<P>Adding this FAQ section is one of the steps he refers to.</P>
+<P>You have various options other than just putting up with the spam,
+ filtering it yourself, or unsubscribing:</P>
+<UL>
+<LI>subscribe only to one or both of our lists with restricted posting
+ rules:
+<UL>
+<LI><A href="mailto:briefs@lists.freeswan.org?body=subscribe">briefs</A>
+, weekly list summaries</LI>
+<LI><A href="mailto:announce@lists.freeswan.org?body=subscribe">announce</A>
+, project-related announcements</LI>
+</UL>
+</LI>
+<LI>read the other lists via the<A href="#archive"> archives</A></LI>
+</UL>
+<P>A number of tools are available to filter mail.</P>
+<UL>
+<LI>Many mail readers include some filtering capability.</LI>
+<LI>Many Linux distributions include<A href="http://www.procmail.org/">
+ procmail(8)</A> for server-side filtering.</LI>
+<LI>The<A href="http://www.spambouncer.org/"> Spam Bouncer</A> is a set
+ of procmail(8) filters designed to combat spam.</LI>
+<LI>Roaring Penguin have a<A href="http://www.roaringpenguin.com/mimedefang/">
+ MIME defanger</A> that removes potentially dangerous attachments.</LI>
+</UL>
+<P>If you use your ISP's mail server rather than running your own,
+ consider suggesting to the ISP that they tag suspected spam as<A href="http://www.msen.com/1997/spam.html#SUSPECTED">
+ this ISP</A> does. They could just refuse mail from dubious sources,
+ but that is tricky and runs some risk of losing valuable mail or
+ senselessly annoying senders and their admins. However, they can safely
+ tag and deliver dubious mail. The tags can greatly assist your
+ filtering.</P>
+<P>For information on tracking down spammers, see these<A href="http://www.rahul.net/falk/#howtos">
+ HowTos</A>, or the<A href="http://www.sputum.com/index2.html"> Sputum</A>
+ site. Sputum have a Linux anti-spam screensaver available for download.</P>
+<P>Here is a more detailed message from Henry:</P>
+<PRE>On Mon, 15 Jan 2001, Jay Vaughan wrote:
+&gt; I know I'm flogging a dead horse here, but I'm curious as to the reasons for
+&gt; an aversion for a subscriber-only mailing list?
+
+Once again: for legal reasons, it is important that discussions of these
+things be held in a public place -- the list -- and we do not want to
+force people to subscribe to the list just to ask one question, because
+that may be more than merely inconvenient for them. There are also real
+difficulties with people who are temporarily forced to use alternate
+addresses; that is precisely the time when they may be most in need of
+help, yet a subscribers-only policy shuts them out.
+
+These issues do not apply to most mailing lists, but for a list that is
+(necessarily) the primary user support route for a crypto package, they
+are very important. This is *not* an ordinary mailing list; it has to
+function under awkward constraints that make various simplistic solutions
+inapplicable or undesirable.
+
+&gt; We're *ALL* sick of hearing about list management problems, not just you
+&gt; old-timers, so why don't you DO SOMETHING EFFECTIVE ABOUT IT...
+
+Because it's a lot harder than it looks, and many existing &quot;solutions&quot;
+have problems when examined closely.
+
+&gt; A suggestion for you, based on 10 years of experience with management of my
+&gt; own mailing lists would be to use mailman, which includes pretty much every
+&gt; feature under the sun that you guys need and want, plus some. The URL for
+&gt; mailman...
+
+I assure you, we're aware of mailman. Along with a whole bunch of others,
+including some you almost certainly have never heard of (I hadn't!).
+
+&gt; As for the argument that the list shouldn't be configured to enforce
+&gt; subscription - I contend that it *SHOULD* AT LEAST require manual address
+&gt; verification in order for posts to be redirected.
+
+You do realize, I hope, that interposing such a manual step might cause
+your government to decide that this is not truly a public forum, and thus
+you could go to jail if you don't get approval from them before mailing to
+it? If you think this sounds irrational, your government is noted for
+making irrational decisions in this area; we can't assume that they will
+suddenly start being sensible. See above about awkward constraints. You
+may be willing to take the risk, but we can't, in good conscience, insist
+that all users with problems do so.
+
+ Henry Spencer
+ henry@spsystems.net</PRE>
+<P>and a message on the topic from project leader John Gilmore:</P>
+<PRE>Subject: Re: The linux-ipsec list's topic
+ Date: Sat, 30 Dec 2000
+ From: John Gilmore &lt;gnu@toad.com&gt;
+
+I'll post this single message, once only, in this discussion, and then
+not burden the list with any further off-topic messages. I encourage
+everyone on the list to restrain themself from posting ANY off-topic
+messages to the linux-ipsec list.
+
+The topic of the linux-ipsec mailing list is the FreeS/WAN software.
+
+I frequently see &quot;discussions about spam on a list&quot; overwhelm the
+volume of &quot;actual spam&quot; on a list. BOTH kinds of messages are
+off-topic messages. Twenty anti-spam messages take just as long to
+detect and discard as twenty spam messages.
+
+The Linux-ipsec list encourages on-topic messages from people who have
+not joined the list itself. We will not censor messages to the list
+based on where they originate, or what return address they contain.
+In other words, non-subscribers ARE allowed to post, and this will not
+change. My own valid contributions have been rejected out-of-hand by
+too many other mailing lists for me to want to impose that censorship
+on anybody else's contributions. And every day I see the damage that
+anti-spam zeal is causing in many other ways; that zeal is far more
+damaging to the culture of the Internet than the nuisance of spam.
+
+In general, it is the responsibility of recipients to filter,
+prioritize, or otherwise manage the handling of email that comes to
+them. It is not the responsibility of the rest of the Internet
+community to refrain from sending messages to recipients that they
+might not want to see. If your software infrastructure for managing
+your incoming email is insufficient, then improve it. If you think
+the signal-to-noise ratio on linux-ipsec is too poor, then please
+unsubscribe. But don't further increase the noise by posting to the
+linux-ipsec list about those topics.
+
+ John Gilmore
+ founder &amp; sponsor, FreeS/WAN project</PRE>
+<HR>
+<H1><A name="manpages">FreeS/WAN manual pages</A></H1>
+<P>The various components of Linux FreeS/WAN are of course documented in
+ standard Unix manual pages, accessible via the man(1) command.</P>
+<P>Links here take you to an HTML version of the man pages.</P>
+<H2><A name="man.file">Files</A></H2>
+<DL>
+<DT><A href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A></DT>
+<DD>IPsec configuration and connections</DD>
+<DT><A href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</A></DT>
+<DD>secrets for IKE authentication, either pre-shared keys or RSA
+ private keys</DD>
+</DL>
+<P>These files are also discussed in the<A href="config.html">
+ configuration</A> section.</P>
+<H2><A name="man.command">Commands</A></H2>
+<P>Many users will never give most of the FreeS/WAN commands directly.
+ Configure the files listed above correctly and everything should be
+ automatic.</P>
+<P>The exceptions are commands for mainpulating the<A href="#RSA"> RSA</A>
+ keys used in Pluto authentication:</P>
+<DL>
+<DT><A href="manpage.d/ipsec_rsasigkey.8.html">ipsec_rsasigkey(8)</A></DT>
+<DD>generate keys</DD>
+<DT><A href="manpage.d/ipsec_newhostkey.8.html">ipsec_newhostkey(8)</A></DT>
+<DD>generate keys in a convenient format</DD>
+<DT><A href="manpage.d/ipsec_showhostkey.8.html">ipsec_showhostkey(8)</A>
+</DT>
+<DD>extract<A href="#RSA"> RSA</A> keys from<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A> (or optionally, another file) and format them for
+ insertion in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> or
+ in DNS records</DD>
+</DL>
+<P>Note that:</P>
+<UL>
+<LI>These keys are for<STRONG> authentication only</STRONG>. They are<STRONG>
+ not secure for encryption</STRONG>.</LI>
+<LI>The utility uses random(4) as a source of<A href="#random"> random
+ numbers</A>. This may block for some time if there is not enough
+ activity on the machine to provide the required entropy. You may want
+ to give it some bogus activity such as random mouse movements or some
+ command such as<NOBR> <TT>du /usr &gt; /dev/null &amp;</TT>.</LI>
+</UL>
+<P>The following commands are fairly likely to be used, if only for
+ testing and status checks:</P>
+<DL>
+<DT><A href="manpage.d/ipsec.8.html">ipsec(8)</A></DT>
+<DD>invoke IPsec utilities</DD>
+<DT><A href="manpage.d/ipsec_setup.8.html">ipsec_setup(8)</A></DT>
+<DD>control IPsec subsystem</DD>
+<DT><A href="manpage.d/ipsec_auto.8.html">ipsec_auto(8)</A></DT>
+<DD>control automatically-keyed IPsec connections</DD>
+<DT><A href="manpage.d/ipsec_manual.8.html">ipsec_manual(8)</A></DT>
+<DD>take manually-keyed IPsec connections up and down</DD>
+<DT><A href="manpage.d/ipsec_ranbits.8.html">ipsec_ranbits(8)</A></DT>
+<DD>generate random bits in ASCII form</DD>
+<DT><A href="manpage.d/ipsec_look.8.html">ipsec_look(8)</A></DT>
+<DD>show minimal debugging information</DD>
+<DT><A href="manpage.d/ipsec_barf.8.html">ipsec_barf(8)</A></DT>
+<DD>spew out collected IPsec debugging information</DD>
+</DL>
+<P>The lower-level utilities listed below are normally invoked via
+ scripts listed above, but they can also be used directly when required.</P>
+<DL>
+<DT><A href="manpage.d/ipsec_eroute.8.html">ipsec_eroute(8)</A></DT>
+<DD>manipulate IPsec extended routing tables</DD>
+<DT><A href="manpage.d/ipsec_klipsdebug.8.html">ipsec_klipsdebug(8)</A></DT>
+<DD>set Klips (kernel IPsec support) debug features and level</DD>
+<DT><A href="manpage.d/ipsec_pluto.8.html">ipsec_pluto(8)</A></DT>
+<DD>IPsec IKE keying daemon</DD>
+<DT><A href="manpage.d/ipsec_spi.8.html">ipsec_spi(8)</A></DT>
+<DD>manage IPsec Security Associations</DD>
+<DT><A href="manpage.d/ipsec_spigrp.8.html">ipsec_spigrp(8)</A></DT>
+<DD>group/ungroup IPsec Security Associations</DD>
+<DT><A href="manpage.d/ipsec_tncfg.8.html">ipsec_tncfg(8)</A></DT>
+<DD>associate IPsec virtual interface with real interface</DD>
+<DT><A href="manpage.d/ipsec_whack.8.html">ipsec_whack(8)</A></DT>
+<DD>control interface for IPsec keying daemon</DD>
+</DL>
+<H2><A name="man.lib">Library routines</A></H2>
+<DL>
+<DT><A href="manpage.d/ipsec_atoaddr.3.html">ipsec_atoaddr(3)</A></DT>
+<DT><A href="manpage.d/ipsec_addrtoa.3.html">ipsec_addrtoa(3)</A></DT>
+<DD>convert Internet addresses to and from ASCII</DD>
+<DT><A href="manpage.d/ipsec_atosubnet.3.html">ipsec_atosubnet(3)</A></DT>
+<DT><A href="manpage.d/ipsec_subnettoa.3.html">ipsec_subnettoa(3)</A></DT>
+<DD>convert subnet/mask ASCII form to and from addresses</DD>
+<DT><A href="manpage.d/ipsec_atoasr.3.html">ipsec_atoasr(3)</A></DT>
+<DD>convert ASCII to Internet address, subnet, or range</DD>
+<DT><A href="manpage.d/ipsec_rangetoa.3.html">ipsec_rangetoa(3)</A></DT>
+<DD>convert Internet address range to ASCII</DD>
+<DT>ipsec_atodata(3)</DT>
+<DT><A href="manpage.d/ipsec_datatoa.3.html">ipsec_datatoa(3)</A></DT>
+<DD>convert binary data from and to ASCII formats</DD>
+<DT><A href="manpage.d/ipsec_atosa.3.html">ipsec_atosa(3)</A></DT>
+<DT><A href="manpage.d/ipsec_satoa.3.html">ipsec_satoa(3)</A></DT>
+<DD>convert IPsec Security Association IDs to and from ASCII</DD>
+<DT><A href="manpage.d/ipsec_atoul.3.html">ipsec_atoul(3)</A></DT>
+<DT><A href="manpage.d/ipsec_ultoa.3.html">ipsec_ultoa(3)</A></DT>
+<DD>convert unsigned-long numbers to and from ASCII</DD>
+<DT><A href="manpage.d/ipsec_goodmask.3.html">ipsec_goodmask(3)</A></DT>
+<DD>is this Internet subnet mask a valid one?</DD>
+<DT><A href="manpage.d/ipsec_masktobits.3.html">ipsec_masktobits(3)</A></DT>
+<DD>convert Internet subnet mask to bit count</DD>
+<DT><A href="manpage.d/ipsec_bitstomask.3.html">ipsec_bitstomask(3)</A></DT>
+<DD>convert bit count to Internet subnet mask</DD>
+<DT><A href="manpage.d/ipsec_optionsfrom.3.html">ipsec_optionsfrom(3)</A>
+</DT>
+<DD>read additional ``command-line'' options from file</DD>
+<DT><A href="manpage.d/ipsec_subnetof.3.html">ipsec_subnetof(3)</A></DT>
+<DD>given Internet address and subnet mask, return subnet number</DD>
+<DT><A href="manpage.d/ipsec_hostof.3.html">ipsec_hostof(3)</A></DT>
+<DD>given Internet address and subnet mask, return host part</DD>
+<DT><A href="manpage.d/ipsec_broadcastof.3.html">ipsec_broadcastof(3)</A>
+</DT>
+<DD>given Internet address and subnet mask, return broadcast address</DD>
+</DL>
+<HR>
+<H1><A name="firewall">FreeS/WAN and firewalls</A></H1>
+<P>FreeS/WAN, or other IPsec implementations, frequently run on gateway
+ machines, the same machines running firewall or packet filtering code.
+ This document discusses the relation between the two.</P>
+<P>The firewall code in 2.4 and later kernels is called Netfilter. The
+ user-space utility to manage a firewall is iptables(8). See the<A href="http://netfilter.samba.org">
+ netfilter/iptables web site</A> for details.</P>
+<H2><A name="filters">Filtering rules for IPsec packets</A></H2>
+<P>The basic constraint is that<STRONG> an IPsec gateway must have
+ packet filters that allow IPsec packets</STRONG>, at least when talking
+ to other IPsec gateways:</P>
+<UL>
+<LI>UDP port 500 for<A href="#IKE"> IKE</A> negotiations</LI>
+<LI>protocol 50 if you use<A href="#ESP"> ESP</A> encryption and/or
+ authentication (the typical case)</LI>
+<LI>protocol 51 if you use<A href="#AH"> AH</A> packet-level
+ authentication</LI>
+</UL>
+<P>Your gateway and the other IPsec gateways it communicates with must
+ be able to exchange these packets for IPsec to work. Firewall rules
+ must allow UDP 500 and at least one of<A href="#AH"> AH</A> or<A href="#ESP">
+ ESP</A> on the interface that communicates with the other gateway.</P>
+<P>For nearly all FreeS/WAN applications, you must allow UDP port 500
+ and the ESP protocol.</P>
+<P>There are two ways to set this up:</P>
+<DL>
+<DT>easier but less flexible</DT>
+<DD>Just set up your firewall scripts at boot time to allow IPsec
+ packets to and from your gateway. Let FreeS/WAN reject any bogus
+ packets.</DD>
+<DT>more work, giving you more precise control</DT>
+<DD>Have the<A href="manpage.d/ipsec_pluto.8.html"> ipsec_pluto(8)</A>
+ daemon call scripts to adjust firewall rules dynamically as required.
+ This is done by naming the scripts in the<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> variables<VAR> prepluto=</VAR>,<VAR> postpluto=</VAR>
+,<VAR> leftupdown=</VAR> and<VAR> rightupdown=</VAR>.</DD>
+</DL>
+<P>Both methods are described in more detail below.</P>
+<H2><A name="examplefw">Firewall configuration at boot</A></H2>
+<P>It is possible to set up both firewalling and IPsec with appropriate
+ scripts at boot and then not use<VAR> leftupdown=</VAR> and<VAR>
+ rightupdown=</VAR>, or use them only for simple up and down operations.</P>
+<P>Basically, the technique is</P>
+<UL>
+<LI>allow IPsec packets (typically, IKE on UDP port 500 plus ESP,
+ protocol 50)
+<UL>
+<LI>incoming, if the destination address is your gateway (and
+ optionally, only from known senders)</LI>
+<LI>outgoing, with the from address of your gateway (and optionally,
+ only to known receivers)</LI>
+</UL>
+</LI>
+<LI>let<A href="#Pluto"> Pluto</A> deal with IKE</LI>
+<LI>let<A href="#KLIPS"> KLIPS</A> deal with ESP</LI>
+</UL>
+<P>Since Pluto authenticates its partners during the negotiation, and
+ KLIPS drops packets for which no tunnel has been negotiated, this may
+ be all you need.</P>
+<H3><A name="simple.rules">A simple set of rules</A></H3>
+<P>In simple cases, you need only a few rules, as in this example:</P>
+<PRE># allow IPsec
+#
+# IKE negotiations
+iptables -I INPUT -p udp --sport 500 --dport 500 -j ACCEPT
+iptables -I OUTPUT -p udp --sport 500 --dport 500 -j ACCEPT
+# ESP encryption and authentication
+iptables -I INPUT -p 50 -j ACCEPT
+iptables -I OUTPUT -p 50 -j ACCEPT
+</PRE>
+<P>This should be all you need to allow IPsec through<VAR> lokkit</VAR>,
+ which ships with Red Hat 9, on its medium security setting. Once you've
+ tweaked to your satisfaction, save your active rule set with:</P>
+<PRE>service iptables save</PRE>
+<H3><A name="complex.rules">Other rules</A></H3>
+ You can add additional rules, or modify existing ones, to work with
+ IPsec and with your network and policies. We give a some examples in
+ this section.
+<P>However, while it is certainly possible to create an elaborate set of
+ rules yourself (please let us know via the<A href="mail.html"> mailing
+ list</A> if you do), it may be both easier and more secure to use a set
+ which has already been published and tested.</P>
+<P>The published rule sets we know of are described in the<A href="#rules.pub">
+ next section</A>.</P>
+<H4><A NAME="7_2_2_1">Adding additional rules</A></H4>
+ If necessary, you can add additional rules to:
+<DL>
+<DT>reject IPsec packets that are not to or from known gateways</DT>
+<DD>This possibility is discussed in more detail<A href="#unknowngate">
+ later</A></DD>
+<DT>allow systems behind your gateway to build IPsec tunnels that pass
+ through the gateway</DT>
+<DD>This possibility is discussed in more detail<A href="#through">
+ later</A></DD>
+<DT>filter incoming packets emerging from KLIPS.</DT>
+<DD>Firewall rules can recognise packets emerging from IPsec. They are
+ marked as arriving on an interface such as<VAR> ipsec0</VAR>, rather
+ than<VAR> eth0</VAR>,<VAR> ppp0</VAR> or whatever.</DD>
+</DL>
+<P>It is therefore reasonably straightforward to filter these packets in
+ whatever way suits your situation.</P>
+<H4><A NAME="7_2_2_2">Modifying existing rules</A></H4>
+<P>In some cases rules that work fine before you add IPsec may require
+ modification to work with IPsec.</P>
+<P>This is especially likely for rules that deal with interfaces on the
+ Internet side of your system. IPsec adds a new interface; often the
+ rules must change to take account of that.</P>
+<P>For example, consider the rules given in<A href="http://www.netfilter.org/documentation/HOWTO//packet-filtering-HOWTO-5.html">
+ this section</A> of the Netfilter documentation:</P>
+<PRE>Most people just have a single PPP connection to the Internet, and don't
+want anyone coming back into their network, or the firewall:
+
+ ## Insert connection-tracking modules (not needed if built into kernel).
+ # insmod ip_conntrack
+ # insmod ip_conntrack_ftp
+
+ ## Create chain which blocks new connections, except if coming from inside.
+ # iptables -N block
+ # iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
+ # iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
+ # iptables -A block -j DROP
+
+ ## Jump to that chain from INPUT and FORWARD chains.
+ # iptables -A INPUT -j block
+ # iptables -A FORWARD -j block</PRE>
+<P>On an IPsec gateway, those rules may need to be modified. The above
+ allows new connections from<EM> anywhere except ppp0</EM>. That means
+ new connections from ipsec0 are allowed.</P>
+<P>Do you want to allow anyone who can establish an IPsec connection to
+ your gateway to initiate TCP connections to any service on your
+ network? Almost certainly not if you are using opportunistic
+ encryption. Quite possibly not even if you have only explicitly
+ configured connections.</P>
+<P>To disallow incoming connections from ipsec0, change the middle
+ section above to:</P>
+<PRE> ## Create chain which blocks new connections, except if coming from inside.
+ # iptables -N block
+ # iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
+ # iptables -A block -m state --state NEW -i ppp+ -j DROP
+ # iptables -A block -m state --state NEW -i ipsec+ -j DROP
+ # iptables -A block -m state --state NEW -i -j ACCEPT
+ # iptables -A block -j DROP</PRE>
+<P>The original rules accepted NEW connections from anywhere except
+ ppp0. This version drops NEW connections from any PPP interface (ppp+)
+ and from any ipsec interface (ipsec+), then accepts the survivors.</P>
+<P>Of course, these are only examples. You will need to adapt them to
+ your own situation.</P>
+<H3><A name="rules.pub">Published rule sets</A></H3>
+<P>Several sets of firewall rules that work with FreeS/WAN are
+ available.</P>
+<H4><A name="Ranch.trinity">Scripts based on Ranch's work</A></H4>
+<P>One user, Rob Hutton, posted his boot time scripts to the mailing
+ list, and we included them in previous versions of this documentation.
+ They are still available from our<A href="http://www.freeswan.org/freeswan_trees/freeswan-1.5/doc/firewall.html#examplefw">
+ web site</A>. However, they were for an earlier FreeS/WAN version so we
+ no longer recommend them. Also, they had some bugs. See this<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/04/msg00316.html">
+ message</A>.</P>
+<P>Those scripts were based on David Ranch's scripts for his &quot;Trinity
+ OS&quot; for setting up a secure Linux. Check his<A href="http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html">
+ home page</A> for the latest version and for information on his<A href="#ranch">
+ book</A> on securing Linux. If you are going to base your firewalling
+ on Ranch's scripts, we recommend using his latest version, and sending
+ him any IPsec modifications you make for incorporation into later
+ versions.</P>
+<H4><A name="seawall">The Seattle firewall</A></H4>
+<P>We have had several mailing lists reports of good results using
+ FreeS/WAN with Seawall (the Seattle Firewall). See that project's<A href="http://seawall.sourceforge.net/">
+ home page</A> on Sourceforge.</P>
+<H4><A name="rcf">The RCF scripts</A></H4>
+<P>Another set of firewall scripts with IPsec support are the RCF or
+ rc.firewall scripts. See their<A href="http://jsmoriss.mvlan.net/linux/rcf.html">
+ home page</A>.</P>
+<H4><A name="asgard">Asgard scripts</A></H4>
+<P><A href="http://heimdall.asgardsrealm.net/linux/firewall/">Asgard's
+ Realm</A> has set of firewall scripts with FreeS/WAN support, for 2.4
+ kernels and iptables.</P>
+<H4><A name="user.scripts">User scripts from the mailing list</A></H4>
+<P>One user gave considerable detail on his scripts, including
+ supporting<A href="#IPX"> IPX</A> through the tunnel. His message was
+ too long to conveniently be quoted here, so I've put it in a<A href="user_examples.html">
+ separate file</A>.</P>
+<H2><A name="updown">Calling firewall scripts, named in ipsec.conf(5)</A>
+</H2>
+<P>The<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A>
+ configuration file has three pairs of parameters used to specify an
+ interface between FreeS/WAN and firewalling code.</P>
+<P>Note that using these is not required if you have a static firewall
+ setup. In that case, you just set your firewall up at boot time (in a
+ way that permits the IPsec connections you want) and do not change it
+ thereafter. Omit all the FreeS/WAN firewall parameters and FreeS/WAN
+ will not attempt to adjust firewall rules at all. See<A href="#examplefw">
+ above</A> for some information on appropriate scripts.</P>
+<P>However, if you want your firewall rules to change when IPsec
+ connections change, then you need to use these parameters.</P>
+<H3><A name="pre_post">Scripts called at IPsec start and stop</A></H3>
+<P>One pair of parmeters are set in the<VAR> config setup</VAR> section
+ of the<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> file and
+ affect all connections:</P>
+<DL>
+<DT>prepluto=</DT>
+<DD>script to be called before<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> IKE daemon is started.</DD>
+<DT>postpluto=</DT>
+<DD>script to be called after<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> IKE daemon is stopped.</DD>
+</DL>
+ These parameters allow you to change firewall parameters whenever IPsec
+ is started or stopped.
+<P>They can also be used in other ways. For example, you might have<VAR>
+ prepluto</VAR> add a module to your kernel for the secure network
+ interface or make a dialup connection, and then have<VAR> postpluto</VAR>
+ remove the module or take the connection down.</P>
+<H3><A name="up_down">Scripts called at connection up and down</A></H3>
+<P>The other parameters are set in connection descriptions. They can be
+ set in individual connection descriptions, and could even call
+ different scripts for each connection for maximum flexibility. In most
+ applications, however, it makes sense to use only one script and to
+ call it from<VAR> conn %default</VAR> section so that it applies to all
+ connections.</P>
+<P>You can:</P>
+<DL>
+<DT><STRONG>either</STRONG></DT>
+<DD>set<VAR> leftfirewall=yes</VAR> or<VAR> rightfirewall=yes</VAR> to
+ use our supplied default script</DD>
+<DT><STRONG>or</STRONG></DT>
+<DD>assign a name in a<VAR> leftupdown=</VAR> or<VAR> rightupdown=</VAR>
+ line to use your own script</DD>
+</DL>
+<P>Note that<STRONG> only one of these should be used</STRONG>. You
+ cannot sensibly use both. Since<STRONG> our default script is obsolete</STRONG>
+ (designed for firewalls using<VAR> ipfwadm(8)</VAR> on 2.0 kernels),
+ most users who need this service will<STRONG> need to write a custom
+ script</STRONG>.</P>
+<H4><A name="fw.default">The default script</A></H4>
+<P>We supply a default script named<VAR> _updown</VAR>.</P>
+<DL>
+<DT>leftfirewall=</DT>
+<DD></DD>
+<DT>rightfirewall=</DT>
+<DD>indicates that the gateway is doing firewalling and that<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> should poke holes in the firewall as required.</DD>
+</DL>
+<P>Set these to<VAR> yes</VAR> and Pluto will call our default script<VAR>
+ _updown</VAR> with appropriate arguments whenever it:</P>
+<UL>
+<LI>starts or stops IPsec services</LI>
+<LI>brings a connection up or down</LI>
+</UL>
+<P>The supplied default<VAR> _updown</VAR> script is appropriate for
+ simple cases using the<VAR> ipfwadm(8)</VAR> firewalling package.</P>
+<H4><A name="userscript">User-written scripts</A></H4>
+<P>You can also write your own script and have Pluto call it. Just put
+ the script's name in one of these<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> lines:</P>
+<DL>
+<DT>leftupdown=</DT>
+<DD></DD>
+<DT>rightupdown=</DT>
+<DD>specifies a script to call instead of our default script<VAR>
+ _updown</VAR>.</DD>
+</DL>
+<P>Your script should take the same arguments and use the same
+ environment variables as<VAR> _updown</VAR>. See the &quot;updown command&quot;
+ section of the<A href="manpage.d/ipsec_pluto.8.html"> ipsec_pluto(8)</A>
+ man page for details.</P>
+<P>Note that<STRONG> you should not modify our _updown script in place</STRONG>
+. If you did that, then upgraded FreeS/WAN, the upgrade would install a
+ new default script, overwriting your changes.</P>
+<H3><A name="ipchains.script">Scripts for ipchains or iptables</A></H3>
+<P>Our<VAR> _updown</VAR> is for firewalls using<VAR> ipfwadm(8)</VAR>,
+ the firewall code for the 2.0 series of Linux kernels. If you are using
+ the more recent packages<VAR> ipchains(8)</VAR> (for 2.2 kernels) or<VAR>
+ iptables(8)</VAR> (2.4 kernels), then you must do one of:</P>
+<UL>
+<LI>use static firewall rules which are set up at boot time as described<A
+href="#examplefw"> above</A> and do not need to be changed by Pluto</LI>
+<LI>limit yourself to ipchains(8)'s ipfwadm(8) emulation mode in order
+ to use our script</LI>
+<LI>write your own script and call it with<VAR> leftupdown</VAR> and<VAR>
+ rightupdown</VAR>.</LI>
+</UL>
+<P>You can write a script to do whatever you need with firewalling.
+ Specify its name in a<VAR> [left|right]updown=</VAR> parameter in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> and Pluto will automatically call it for you.</P>
+<P>The arguments Pluto passes such a script are the same ones it passes
+ to our default _updown script, so the best way to build yours is to
+ copy ours and modify the copy.</P>
+<P>Note, however, that<STRONG> you should not modify our _updown script
+ in place</STRONG>. If you did that, then upgraded FreeS/WAN, the
+ upgrade would install a new default script, overwriting your changes.</P>
+<H2><A name="NAT">A complication: IPsec vs. NAT</A></H2>
+<P><A href="#NAT.gloss">Network Address Translation</A>, also known as
+ IP masquerading, is a method of allocating IP addresses dynamically,
+ typically in circumstances where the total number of machines which
+ need to access the Internet exceeds the supply of IP addresses.</P>
+<P>Any attempt to perform NAT operations on IPsec packets<EM> between
+ the IPsec gateways</EM> creates a basic conflict:</P>
+<UL>
+<LI>IPsec wants to authenticate packets and ensure they are unaltered on
+ a gateway-to-gateway basis</LI>
+<LI>NAT rewrites packet headers as they go by</LI>
+<LI>IPsec authentication fails if packets are rewritten anywhere between
+ the IPsec gateways</LI>
+</UL>
+<P>For<A href="#AH"> AH</A>, which authenticates parts of the packet
+ header including source and destination IP addresses, this is fatal. If
+ NAT changes those fields, AH authentication fails.</P>
+<P>For<A href="#IKE"> IKE</A> and<A href="#ESP"> ESP</A> it is not
+ necessarily fatal, but is certainly an unwelcome complication.</P>
+<H3><A name="nat_ok">NAT on or behind the IPsec gateway works</A></H3>
+<P>This problem can be avoided by having the masquerading take place<EM>
+ on or behind</EM> the IPsec gateway.</P>
+<P>This can be done physically with two machines, one physically behind
+ the other. A picture, using SG to indicate IPsec<STRONG> S</STRONG>
+ecurity<STRONG> G</STRONG>ateways, is:</P>
+<PRE> clients --- NAT ----- SG ---------- SG
+ two machines</PRE>
+<P>In this configuration, the actual client addresses need not be given
+ in the<VAR> leftsubnet=</VAR> parameter of the FreeS/WAN connection
+ description. The security gateway just delivers packets to the NAT box;
+ it needs only that machine's address. What that machine does with them
+ does not affect FreeS/WAN.</P>
+<P>A more common setup has one machine performing both functions:</P>
+<PRE> clients ----- NAT/SG ---------------SG
+ one machine</PRE>
+<P>Here you have a choice of techniques depending on whether you want to
+ make your client subnet visible to clients on the other end:</P>
+<UL>
+<LI>If you want the single gateway to behave like the two shown above,
+ with your clients hidden behind the NAT, then omit the<VAR> leftsubnet=</VAR>
+ parameter. It then defaults to the gateway address. Clients on the
+ other end then talk via the tunnel only to your gateway. The gateway
+ takes packets emerging from the tunnel, applies normal masquerading,
+ and forwards them to clients.</LI>
+<LI>If you want to make your client machines visible, then give the
+ client subnet addresses as the<VAR> leftsubnet=</VAR> parameter in the
+ connection description and
+<DL>
+<DT>either</DT>
+<DD>set<VAR> leftfirewall=yes</VAR> to use the default<VAR> updown</VAR>
+ script</DD>
+<DT>or</DT>
+<DD>use your own script by giving its name in a<VAR> leftupdown=</VAR>
+ parameter</DD>
+</DL>
+ These scripts are described in their own<A href="#updown"> section</A>.
+<P>In this case, no masquerading is done. Packets to or from the client
+ subnet are encrypted or decrypted without any change to their client
+ subnet addresses, although of course the encapsulating packets use
+ gateway addresses in their headers. Clients behind the right security
+ gateway see a route via that gateway to the left subnet.</P>
+</LI>
+</UL>
+<H3><A name="nat_bad">NAT between gateways is problematic</A></H3>
+<P>We recommend not trying to build IPsec connections which pass through
+ a NAT machine. This setup poses problems:</P>
+<PRE> clients --- SG --- NAT ---------- SG</PRE>
+<P>If you must try it, some references are:</P>
+<UL>
+<LI>Jean_Francois Nadeau's document on doing<A href="http://jixen.tripod.com/#NATed gateways">
+ IPsec behind NAT</A></LI>
+<LI><A href="#VPN.masq">VPN masquerade patches</A> to make a Linux NAT
+ box handle IPsec packets correctly</LI>
+</UL>
+<H3><A name="NAT.ref">Other references on NAT and IPsec</A></H3>
+<P>Other documents which may be relevant include:</P>
+<UL>
+<LI>an Internet Draft on<A href="http://search.ietf.org/internet-drafts/draft-aboba-nat-ipsec-04.txt">
+ IPsec and NAT</A> which may eventually evolve into a standard solution
+ for this problem.</LI>
+<LI>an informational<A href="http://www.cis.ohio-state.edu/rfc/rfc2709.txt">
+ RFC</A>,<CITE> Security Model with Tunnel-mode IPsec for NAT Domains</CITE>
+.</LI>
+<LI>an<A href="http://www.cisco.com/warp/public/759/ipj_3-4/ipj_3-4_nat.html">
+ article</A> in Cisco's<CITE> Internet Protocol Journal</CITE></LI>
+</UL>
+<H2><A name="complications">Other complications</A></H2>
+<P>Of course simply allowing UDP 500 and ESP packets is not the whole
+ story. Various other issues arise in making IPsec and packet filters
+ co-exist and even co-operate. Some of them are summarised below.</P>
+<H3><A name="through">IPsec<EM> through</EM></A> the gateway</H3>
+<P>Basic IPsec packet filtering rules deal only with packets addressed
+ to or sent from your IPsec gateway.</P>
+<P>It is a separate policy decision whether to permit such packets to
+ pass through the gateway so that client machines can build end-to-end
+ IPsec tunnels of their own. This may not be practical if you are using<A
+href="#NAT"> NAT (IP masquerade)</A> on your gateway, and may conflict
+ with some corporate security policies.</P>
+<P>Where possible, allowing this is almost certainly a good idea. Using
+ IPsec on an end-to-end basis is more secure than gateway-to-gateway.</P>
+<P>Doing it is quite simple. You just need firewall rules that allow UDP
+ port 500 and protocols 50 and 51 to pass through your gateway. If you
+ wish, you can of course restrict this to certain hosts.</P>
+<H3><A name="ipsec_only">Preventing non-IPsec traffic</A></H3>
+ You can also filter<EM> everything but</EM> UDP port 500 and ESP or AH
+ to restrict traffic to IPsec only, either for anyone communicating with
+ your host or just for specific partners.
+<P>One application of this is for the telecommuter who might have:</P>
+<PRE> Sunset==========West------------------East ================= firewall --- the Internet
+ home network untrusted net corporate network</PRE>
+<P>The subnet on the right is 0.0.0.0/0, the whole Internet. The West
+ gateway is set up so that it allows only IPsec packets to East in or
+ out.</P>
+<P>This configuration is used in AT&amp;T Research's network. For details,
+ see the<A href="#applied"> papers</A> links in our introduction.</P>
+<P>Another application would be to set up firewall rules so that an
+ internal machine, such as an employees-only web server, could not talk
+ to the outside world except via specific IPsec tunnels.</P>
+<H3><A name="unknowngate">Filtering packets from unknown gateways</A></H3>
+<P>It is possible to use firewall rules to restrict UDP 500, ESP and AH
+ packets so that these packets are accepted only from known gateways.
+ This is not strictly necessary since FreeS/WAN will discard packets
+ from unknown gateways. You might, however, want to do it for any of a
+ number of reasons. For example:</P>
+<UL>
+<LI>Arguably, &quot;belt and suspenders&quot; is the sensible approach to
+ security. If you can block a potential attack in two ways, use both.
+ The only question is whether to look for a third way after implementing
+ the first two.</LI>
+<LI>Some admins may prefer to use the firewall code this way because
+ they prefer firewall logging to FreeS/WAN's logging.</LI>
+<LI>You may need it to implement your security policy. Consider an
+ employee working at home, and a policy that says traffic from the home
+ system to the Internet at large must go first via IPsec to the
+ corporate LAN and then out to the Internet via the corporate firewall.
+ One way to do that is to make<VAR> ipsec0</VAR> the default route on
+ the home gateway and provide exceptions only for UDP 500 and ESP to the
+ corporate gateway. Everything else is then routed via the tunnel to the
+ corporate gateway.</LI>
+</UL>
+<P>It is not possible to use only static firewall rules for this
+ filtering if you do not know the other gateways' IP addresses in
+ advance, for example if you have &quot;road warriors&quot; who may connect from a
+ different address each time or if want to do<A href="#carpediem">
+ opportunistic encryption</A> to arbitrary gateways. In these cases, you
+ can accept UDP 500 IKE packets from anywhere, then use the<A href="#updown">
+ updown</A> script feature of<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> to dynamically adjust firewalling for each negotiated
+ tunnel.</P>
+<P>Firewall packet filtering does not much reduce the risk of a<A href="#DOS">
+ denial of service attack</A> on FreeS/WAN. The firewall can drop
+ packets from unknown gateways, but KLIPS does that quite efficiently
+ anyway, so you gain little. The firewall cannot drop otherwise
+ legitmate packets that fail KLIPS authentication, so it cannot protect
+ against an attack designed to exhaust resources by making FreeS/WAN
+ perform many expensive authentication operations.</P>
+<P>In summary, firewall filtering of IPsec packets from unknown gateways
+ is possible but not strictly necessary.</P>
+<H2><A name="otherfilter">Other packet filters</A></H2>
+<P>When the IPsec gateway is also acting as your firewall, other packet
+ filtering rules will be in play. In general, those are outside the
+ scope of this document. See our<A href="#firewall.linux"> Linux
+ firewall links</A> for information. There are a few types of packet,
+ however, which can affect the operation of FreeS/WAN or of diagnostic
+ tools commonly used with it. These are discussed below.</P>
+<H3><A name="ICMP">ICMP filtering</A></H3>
+<P><A href="#ICMP.gloss">ICMP</A> is the<STRONG> I</STRONG>nternet<STRONG>
+ C</STRONG>ontrol<STRONG> M</STRONG>essage<STRONG> P</STRONG>rotocol. It
+ is used for messages between IP implementations themselves, whereas IP
+ used is used between the clients of those implementations. ICMP is,
+ unsurprisingly, used for control messages. For example, it is used to
+ notify a sender that a desination is not reachable, or to tell a router
+ to reroute certain packets elsewhere.</P>
+<P>ICMP handling is tricky for firewalls.</P>
+<UL>
+<LI>You definitely want some ICMP messages to get through; things won't
+ work without them. For example, your clients need to know if some
+ destination they ask for is unreachable.</LI>
+<LI>On the other hand, you do equally definitely do not want untrusted
+ folk sending arbitrary control messages to your machines. Imagine what
+ someone moderately clever and moderately malicious could do to you,
+ given control of your network's routing.</LI>
+</UL>
+<P>ICMP does not use ports. Messages are distinguished by a &quot;message
+ type&quot; field and, for some types, by an additional &quot;code&quot; field. The
+ definitive list of types and codes is on the<A href="http://www.iana.org">
+ IANA</A> site.</P>
+<P>One expert uses this definition for ICMP message types to be dropped
+ at the firewall.</P>
+<PRE># ICMP types which lack socially redeeming value.
+# 5 Redirect
+# 9 Router Advertisement
+# 10 Router Selection
+# 15 Information Request
+# 16 Information Reply
+# 17 Address Mask Request
+# 18 Address Mask Reply
+
+badicmp='5 9 10 15 16 17 18'</PRE>
+<P>A more conservative approach would be to make a list of allowed types
+ and drop everything else.</P>
+<P>Whichever way you do it, your ICMP filtering rules on a FreeS/WAN
+ gateway should allow at least the following ICMP packet types:</P>
+<DL>
+<DT>echo (type 8)</DT>
+<DD></DD>
+<DT>echo reply (type 0)</DT>
+<DD>These are used by ping(1). We recommend allowing both types through
+ the tunnel and to or from your gateway's external interface, since
+ ping(1) is an essential testing tool.
+<P>It is fairly common for firewalls to drop ICMP echo packets addressed
+ to machines behind the firewall. If that is your policy, please create
+ an exception for such packets arriving via an IPsec tunnel, at least
+ during intial testing of those tunnels.</P>
+</DD>
+<DT>destination unreachable (type 3)</DT>
+<DD>This is used, with code 4 (Fragmentation Needed and Don't Fragment
+ was Set) in the code field, to control<A href="#pathMTU"> path MTU
+ discovery</A>. Since IPsec processing adds headers, enlarges packets
+ and may cause fragmentation, an IPsec gateway should be able to send
+ and receive these ICMP messages<STRONG> on both inside and outside
+ interfaces</STRONG>.</DD>
+</DL>
+<H3><A name="traceroute">UDP packets for traceroute</A></H3>
+<P>The traceroute(1) utility uses UDP port numbers from 33434 to
+ approximately 33633. Generally, these should be allowed through for
+ troubleshooting.</P>
+<P>Some firewalls drop these packets to prevent outsiders exploring the
+ protected network with traceroute(1). If that is your policy, consider
+ creating an exception for such packets arriving via an IPsec tunnel, at
+ least during intial testing of those tunnels.</P>
+<H3><A name="l2tp">UDP for L2TP</A></H3>
+<P> Windows 2000 does, and products designed for compatibility with it
+ may, build<A href="#l2tp"> L2TP</A> tunnels over IPsec connections.</P>
+<P>For this to work, you must allow UDP protocol 1701 packets coming out
+ of your tunnels to continue to their destination. You can, and probably
+ should, block such packets to or from your external interfaces, but
+ allow them from<VAR> ipsec0</VAR>.</P>
+<P>See also our Windows 2000<A href="interop.html#win2k"> interoperation
+ discussion</A>.</P>
+<H2><A name="packets">How it all works: IPsec packet details</A></H2>
+<P>IPsec uses three main types of packet:</P>
+<DL>
+<DT><A href="#IKE">IKE</A> uses<STRONG> the UDP protocol and port 500</STRONG>
+.</DT>
+<DD>Unless you are using only (less secure, not recommended) manual
+ keying, you need IKE to negotiate connection parameters, acceptable
+ algorithms, key sizes and key setup. IKE handles everything required to
+ set up, rekey, repair or tear down IPsec connections.</DD>
+<DT><A href="#ESP">ESP</A> is<STRONG> protocol number 50</STRONG></DT>
+<DD>This is required for encrypted connections.</DD>
+<DT><A href="#AH">AH</A> is<STRONG> protocol number 51</STRONG></DT>
+<DD>This can be used where only authentication, not encryption, is
+ required.</DD>
+</DL>
+<P>All of those packets should have appropriate IPsec gateway addresses
+ in both the to and from IP header fields. Firewall rules can check this
+ if you wish, though it is not strictly necessary. This is discussed in
+ more detail<A href="#unknowngate"> later</A>.</P>
+<P>IPsec processing of incoming packets authenticates them then removes
+ the ESP or AH header and decrypts if necessary. Successful processing
+ exposes an inner packet which is then delivered back to the firewall
+ machinery, marked as having arrived on an<VAR> ipsec[0-3]</VAR>
+ interface. Firewall rules can use that interface label to distinguish
+ these packets from unencrypted packets which are labelled with the
+ physical interface they arrived on (or perhaps with a non-IPsec virtual
+ interface such as<VAR> ppp0</VAR>).</P>
+<P>One of our users sent a mailing list message with a<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00006.html">
+ diagram</A> of the packet flow.</P>
+<H3><A name="noport">ESP and AH do not have ports</A></H3>
+<P>Some protocols, such as TCP and UDP, have the notion of ports. Others
+ protocols, including ESP and AH, do not. Quite a few IPsec newcomers
+ have become confused on this point. There are no ports<EM> in</EM> the
+ ESP or AH protocols, and no ports used<EM> for</EM> them. For these
+ protocols,<EM> the idea of ports is completely irrelevant</EM>.</P>
+<H3><A name="header">Header layout</A></H3>
+<P>The protocol numbers for ESP or AH are used in the 'next header'
+ field of the IP header. On most non-IPsec packets, that field would
+ have one of:</P>
+<UL>
+<LI>1 for ICMP</LI>
+<LI>4 for IP-in-IP encapsulation</LI>
+<LI>6 for TCP</LI>
+<LI>17 for UDP</LI>
+<LI>... or one of about 100 other possibilities listed by<A href="http://www.iana.org">
+ IANA</A></LI>
+</UL>
+<P>Each header in the sequence tells what the next header will be. IPsec
+ adds headers for ESP or AH near the beginning of the sequence. The
+ original headers are kept and the 'next header' fields adjusted so that
+ all headers can be correctly interpreted.</P>
+<P>For example, using<STRONG> [</STRONG><STRONG> ]</STRONG> to indicate
+ data protected by ESP and unintelligible to an eavesdropper between the
+ gateways:</P>
+<UL>
+<LI>a simple packet might have only IP and TCP headers with:
+<UL>
+<LI>IP header says next header --&gt; TCP</LI>
+<LI>TCP header port number --&gt; which process to send data to</LI>
+<LI>data</LI>
+</UL>
+</LI>
+<LI>with ESP<A href="#transport"> transport mode</A> encapsulation, that
+ packet would have:
+<UL>
+<LI>IP header says next header --&gt; ESP</LI>
+<LI>ESP header<STRONG> [</STRONG> says next --&gt; TCP</LI>
+<LI>TCP header port number --&gt; which process to send data to</LI>
+<LI>data<STRONG> ]</STRONG></LI>
+</UL>
+ Note that the IP header is outside ESP protection, visible to an
+ attacker, and that the final destination must be the gateway.</LI>
+<LI>with ESP in<A href="#tunnel"> tunnel mode</A>, we might have:
+<UL>
+<LI>IP header says next header --&gt; ESP</LI>
+<LI>ESP header<STRONG> [</STRONG> says next --&gt; IP</LI>
+<LI>IP header says next header --&gt; TCP</LI>
+<LI>TCP header port number --&gt; which process to send data to</LI>
+<LI>data<STRONG> ]</STRONG></LI>
+</UL>
+ Here the inner IP header is protected by ESP, unreadable by an
+ attacker. Also, the inner header can have a different IP address than
+ the outer IP header, so the decrypted packet can be routed from the
+ IPsec gateway to a final destination which may be another machine.</LI>
+</UL>
+<P>Part of the ESP header itself is encrypted, which is why the<STRONG>
+ [</STRONG> indicating protected data appears in the middle of some
+ lines above. The next header field of the ESP header is protected. This
+ makes<A href="#traffic"> traffic analysis</A> more difficult. The next
+ header field would tell an eavesdropper whether your packet was UDP to
+ the gateway, TCP to the gateway, or encapsulated IP. It is better not
+ to give this information away. A clever attacker may deduce some of it
+ from the pattern of packet sizes and timings, but we need not make it
+ easy.</P>
+<P>IPsec allows various combinations of these to match local policies,
+ including combinations that use both AH and ESP headers or that nest
+ multiple copies of these headers.</P>
+<P>For example, suppose my employer has an IPsec VPN running between two
+ offices so all packets travelling between the gateways for those
+ offices are encrypted. If gateway policies allow it (The admins could
+ block UDP 500 and protocols 50 and 51 to disallow it), I can build an
+ IPsec tunnel from my desktop to a machine in some remote office. Those
+ packets will have one ESP header throughout their life, for my
+ end-to-end tunnel. For part of the route, however, they will also have
+ another ESP layer for the corporate VPN's encapsulation. The whole
+ header scheme for a packet on the Internet might be:</P>
+<UL>
+<LI>IP header (with gateway address) says next header --&gt; ESP</LI>
+<LI>ESP header<STRONG> [</STRONG> says next --&gt; IP</LI>
+<LI>IP header (with receiving machine address) says next header --&gt; ESP</LI>
+<LI>ESP header<STRONG> [</STRONG> says next --&gt; TCP</LI>
+<LI>TCP header port number --&gt; which process to send data to</LI>
+<LI>data<STRONG> ]]</STRONG></LI>
+</UL>
+<P>The first ESP (outermost) header is for the corporate VPN. The inner
+ ESP header is for the secure machine-to-machine link.</P>
+<H3><A name="dhr">DHR on the updown script</A></H3>
+<P>Here are some mailing list comments from<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> developer Hugh Redelmeier on an earlier draft of this
+ document:</P>
+<PRE>There are many important things left out
+
+- firewalling is important but must reflect (implement) policy. Since
+ policy isn't the same for all our customers, and we're not experts,
+ we should concentrate on FW and MASQ interactions with FreeS/WAN.
+
+- we need a diagram to show packet flow WITHIN ONE MACHINE, assuming
+ IKE, IPsec, FW, and MASQ are all done on that machine. The flow is
+ obvious if the components are run on different machines (trace the
+ cables).
+
+ IKE input:
+ + packet appears on public IF, as UDP port 500
+ + input firewalling rules are applied (may discard)
+ + Pluto sees the packet.
+
+ IKE output:
+ + Pluto generates the packet &amp; writes to public IF, UDP port 500
+ + output firewalling rules are applied (may discard)
+ + packet sent out public IF
+
+ IPsec input, with encapsulated packet, outer destination of this host:
+ + packet appears on public IF, protocol 50 or 51. If this
+ packet is the result of decapsulation, it will appear
+ instead on the paired ipsec IF.
+ + input firewalling rules are applied (but packet is opaque)
+ + KLIPS decapsulates it, writes result to paired ipsec IF
+ + input firewalling rules are applied to resulting packet
+ as input on ipsec IF
+ + if the destination of the packet is this machine, the
+ packet is passed on to the appropriate protocol handler.
+ If the original packet was encapsulated more than once
+ and the new outer destination is this machine, that
+ handler will be KLIPS.
+ + otherwise:
+ * routing is done for the resulting packet. This may well
+ direct it into KLIPS for encoding or encrypting. What
+ happens then is described elsewhere.
+ * forwarding firewalling rules are applied
+ * output firewalling rules are applied
+ * the packet is sent where routing specified
+
+ IPsec input, with encapsulated packet, outer destination of another host:
+ + packet appears on some IF, protocol 50 or 51
+ + input firewalling rules are applied (but packet is opaque)
+ + routing selects where to send the packet
+ + forwarding firewalling rules are applied (but packet is opaque)
+ + packet forwarded, still encapsulated
+
+ IPsec output, from this host or from a client:
+ + if from a client, input firewalling rules are applied as the
+ packet arrives on the private IF
+ + routing directs the packet to an ipsec IF (this is how the
+ system decides KLIPS processing is required)
+ + if from a client, forwarding firewalling rules are applied
+ + KLIPS eroute mechanism matches the source and destination
+ to registered eroutes, yielding a SPI group. This dictates
+ processing, and where the resulting packet is to be sent
+ (the destinations SG and the nexthop).
+ + output firewalling is not applied to the resulting
+ encapsulated packet
+
+- Until quite recently, KLIPS would double encapsulate packets that
+ didn't strictly need to be. Firewalling should be prepared for
+ those packets showing up as ESP and AH protocol input packets on
+ an ipsec IF.
+
+- MASQ processing seems to be done as if it were part of the
+ forwarding firewall processing (this should be verified).
+
+- If a firewall is being used, it is likely the case that it needs to
+ be adjusted whenever IPsec SAs are added or removed. Pluto invokes
+ a script to do this (and to adjust routing) at suitable times. The
+ default script is only suitable for ipfwadm-managed firewalls. Under
+ LINUX 2.2.x kernels, ipchains can be managed by ipfwadm (emulation),
+ but ipchains more powerful if manipulated using the ipchains command.
+ In this case, a custom updown script must be used.
+
+ We think that the flexibility of ipchains precludes us supplying an
+ updown script that would be widely appropriate.</PRE>
+<HR>
+<H1><A NAME="trouble"></A>Linux FreeS/WAN Troubleshooting Guide</H1>
+<H2><A NAME="overview"></A>Overview</H2>
+<P> This document covers several general places where you might have a
+ problem:</P>
+<OL>
+<LI><A HREF="#install">During install</A>.</LI>
+<LI><A HREF="#negotiation">During the negotiation process</A>.</LI>
+<LI><A HREF="#use">Using an established connection</A>.</LI>
+</OL>
+<P>This document also contains<A HREF="#notes"> notes</A> which expand
+ on points made in these sections, and tips for<A HREF="#prob.report">
+ problem reporting</A>. If the other end of your connection is not
+ FreeS/WAN, you'll also want to read our<A HREF="interop.html#interop.problem">
+ interoperation</A> document.</P>
+<H2><A NAME="install"></A>1. During Install</H2>
+<H3><A NAME="8_2_1">1.1 RPM install gotchas</A></H3>
+<P>With the RPM method:</P>
+<UL>
+<LI>Be sure you have installed both the userland tools and the kernel
+ components. One will not work without the other. For example, when
+ using FreeS/WAN-produced RPMs for our 2.04 release, you need both:
+<PRE> freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm
+ freeswan-module-2.04_2.4.20_20.9-0.i386.rpm
+</PRE>
+</LI>
+</UL>
+<H3><A NAME="8_2_2">1.2 Problems installing from source</A></H3>
+<P>When installing from source, you may find these problems:</P>
+<UL>
+<LI>Missing library. See<A HREF="#gmp.h_missing"> this</A> FAQ.</LI>
+<LI>Missing utilities required for compile. See this<A HREF="install.html#tool.lib">
+ checklist</A>.</LI>
+<LI>Kernel version incompatibility. See<A HREF="#k.versions"> this</A>
+ FAQ.</LI>
+<LI>Another compile problem. Find information in the out.* files, ie.
+ out.kpatch, out.kbuild, created at compile time in the top-level Linux
+ FreeS/WAN directory. Error messages generated by KLIPS during the boot
+ sequence are accessible with the<VAR> dmesg</VAR> command.
+<BR> Check the list archives and the List in Brief to see if this is a
+ known issue. If it is not, report it to the bugs list as described in
+ our<A HREF="#prob.report"> problem reporting</A> section. In some
+ cases, you may be asked to provide debugging information using gdb;
+ details<A HREF="#gdb"> below</A>.</LI>
+<LI>If your kernel compiles but you fail to install your new
+ FreeS/WAN-enabled kernel, review the sections on<A HREF="install.html#newk">
+ installing the patched kernel</A>, and<A HREF="#testinstall"> testing</A>
+ to see if install succeeded.</LI>
+</UL>
+<H3><A NAME="install.check"></A>1.3 Install checks</H3>
+<P><VAR>ipsec verify</VAR> checks a number of FreeS/WAN essentials. Here
+ are some hints on what do to when your system doesn't check out:</P>
+<P></P>
+<TABLE border="1">
+<TR><TD><STRONG>Problem</STRONG></TD><TD><STRONG>Status</STRONG></TD><TD>
+<STRONG>Action</STRONG></TD></TR>
+<TR><TD><VAR>ipsec</VAR> not on-path</TD><TD>&nbsp;</TD><TD>
+<P>Add<VAR> /usr/local/sbin</VAR> to your PATH.</P>
+</TD></TR>
+<TR><TD>Missing KLIPS support</TD><TD><FONT COLOR="#FF0000">critical</FONT>
+</TD><TD>See<A HREF="#noKLIPS"> this FAQ.</A></TD></TR>
+<TR><TD>No RSA private key</TD><TD>&nbsp;</TD><TD>
+<P>Follow<A HREF="install.html#genrsakey"> these instructions</A> to
+ create an RSA key pair for your host. RSA keys are:</P>
+<UL>
+<LI>required for opportunistic encryption, and</LI>
+<LI>our preferred method to authenticate pre-configured connections.</LI>
+</UL>
+</TD></TR>
+<TR><TD><VAR>pluto</VAR> not running</TD><TD><FONT COLOR="#FF0000">
+critical</FONT></TD><TD>
+<PRE>service ipsec start</PRE>
+</TD></TR>
+<TR><TD>No port 500 hole</TD><TD><FONT COLOR="#FF0000">critical</FONT></TD><TD>
+Open port 500 for IKE negotiation.</TD></TR>
+<TR><TD>Port 500 check N/A</TD><TD>&nbsp;</TD><TD>Check that port 500 is open
+ for IKE negotiation.</TD></TR>
+<TR><TD>Failed DNS checks</TD><TD>&nbsp;</TD><TD>Opportunistic encryption
+ requires information from DNS. To set this up, see<A HREF="#opp.setup">
+ our instructions</A>.</TD></TR>
+<TR><TD>No public IP address</TD><TD>&nbsp;</TD><TD>Check that the interface
+ which you want to protect with IPSec is up and running.</TD></TR>
+</TABLE>
+<H3><A NAME="oe.trouble"></A>1.3 Troubleshooting OE</H3>
+<P>OE should work with no local configuration, if you have posted DNS
+ TXT records according to the instructions in our<A HREF="quickstart.html">
+ quickstart guide</A>. If you encounter trouble, try these hints. We
+ welcome additional hints via the<A HREF="mail.html"> users' mailing
+ list</A>.</P>
+<TABLE border="1">
+<TR><TD><STRONG>Symptom</STRONG></TD><TD><STRONG>Problem</STRONG></TD><TD>
+<STRONG>Action</STRONG></TD></TR>
+<TR><TD> You're running FreeS/WAN 2.01 (or later), and initiating a
+ connection to FreeS/WAN 2.00 (or earlier). In your logs, you see a
+ message like:
+<PRE>no RSA public key known for '192.0.2.13';
+DNS search for KEY failed (no KEY record
+for 13.2.0.192.in-addr.arpa.)</PRE>
+ The older FreeS/WAN logs no error.</TD><TD><A NAME="oe.trouble.flagday">
+</A> A protocol level incompatibility between 2.01 (or later) and 2.00
+ (or earlier) causes this error. It occurs when a FreeS/WAN 2.01 (or
+ later) box for which no KEY record is posted attempts to initiate an OE
+ connection to older FreeS/WAN versions (2.00 and earlier). Note that
+ older versions can initiate to newer versions without this error.</TD><TD>
+If you control the peer host, upgrade its FreeS/WAN to 2.01 (or later),
+ and post new style TXT records for it. If not, but if you know its
+ sysadmin, perhaps a quick note is in order. If neither option is
+ possible, you can ease the transition by posting an old style KEY
+ record (created with a command like &quot;ipsec&nbsp;showhostkey&nbsp;--key&quot;) to the
+ reverse map for the FreeS/WAN 2.01 (or later) box.</TD></TR>
+<TR><TD>OE host is very slow to contact other hosts.</TD><TD>Slow DNS
+ service while running OE.</TD><TD>It's a good idea to run a caching DNS
+ server on your OE host, as outlined in<A HREF="http://lists.freeswan.org/pipermail/design/2003-January/004205.html">
+ this mailing list message</A>. If your DNS servers are elsewhere, put
+ their IPs in the<VAR> clear</VAR> policy group, and re-read groups with
+<PRE>ipsec auto --rereadgroups</PRE>
+</TD></TR>
+<TR><TD>
+<PRE>Can't Opportunistically initiate for
+192.0.2.2 to 192.0.2.3: no TXT record
+for 13.2.0.192.in-addr.arpa.</PRE>
+</TD><TD>Peer is not set up for OE.</TD><TD>
+<P>None. Plenty of hosts on the Internet do not run OE. If, however, you
+ have set OE up on that peer, this may indicate that you need to wait up
+ to 48 hours for its DNS records to propagate.</P>
+</TD></TR>
+<TR><TD><VAR>ipsec verify</VAR> does not find DNS records:
+<PRE>...
+Looking for TXT in forward map:
+ xy.example.com...[FAILED]
+Looking for TXT in reverse map...[FAILED]
+...</PRE>
+ You also experience authentication failure:
+<BR>
+<PRE>Possible authentication failure:
+no acceptable response to our
+first encrypted message</PRE>
+</TD><TD>DNS records are not posted or have not propagated.</TD><TD>Did
+ you post the DNS records necessary for OE? If not, do so using the
+ instructions in our<A HREF="#quickstart"> quickstart guide</A>. If so,
+ wait up to 48 hours for the DNS records to propagate.</TD></TR>
+<TR><TD><VAR>ipsec verify</VAR> does not find DNS records, and you
+ experience authentication failure.</TD><TD>For iOE, your ID does not
+ match location of forward DNS record.</TD><TD>In<VAR> config setup</VAR>
+, change<VAR> myid=</VAR> to match the forward DNS where you posted the
+ record. Restart FreeS/WAN. For reference, see our<A HREF="#opp.client">
+ iOE instructions</A>.</TD></TR>
+<TR><TD><VAR>ipsec verify</VAR> finds DNS records, yet there is still
+ authentication failure. ( ? )</TD><TD>DNS records are malformed.</TD><TD>
+Re-create the records and send new copies to your DNS administrator.</TD>
+</TR>
+<TR><TD><VAR>ipsec verify</VAR> finds DNS records, yet there is still
+ authentication failure. ( ? )</TD><TD>DNS records show different keys
+ for a gateway vs. its subnet hosts.</TD><TD>All TXT records for boxes
+ protected by an OE gateway must contain the gateway's public key.
+ Re-create and re-post any incorrect records using<A HREF="#opp.incoming">
+ these instructions</A>.</TD></TR>
+<TR><TD>OE gateway loses connectivity to its subnet. The gateway's
+ routing table shows routes to the subnet through IPsec interfaces.</TD><TD>
+The subnet is part of the<VAR> private</VAR> or<VAR> block</VAR> policy
+ group on the gateway.</TD><TD>Remove the subnet from the group, and
+ reread groups with
+<PRE>ipsec auto --rereadgroups</PRE>
+</TD></TR>
+<TR><TD>OE does not work to hosts on the local LAN.</TD><TD>This is a
+ known issue.</TD><TD>See<A HREF="opportunism.known-issues"> this list</A>
+ of known issues with OE.</TD></TR>
+<TR><TD>FreeS/WAN does not seem to be executing your default policy. In
+ your logs, you see a message like:
+<PRE>/etc/ipsec.d/policies/iprivate-or-clear&quot;
+line 14: subnet &quot;0.0.0.0/0&quot;,
+source 192.0.2.13/32,
+already &quot;private-or-clear&quot;</PRE>
+</TD><TD><A HREF="#fullnet">Fullnet</A> in a policy group file defines
+ your default policy. Fullnet should normally be present in only one
+ policy group file. The fine print: you can have two default policies
+ defined so long as they protect different local endpoints (e.g. the
+ FreeS/WAN gateway and a subnet).</TD><TD> Find all policies which
+ contain fullnet with:
+<BR>
+<PRE>grep -F 0.0.0.0/0 /etc/ipsec.d/policies/*</PRE>
+ then remove the unwanted occurrence(s).</TD></TR>
+</TABLE>
+<H2><A NAME="negotiation"></A>2. During Negotiation</H2>
+<P>When you fail to bring up a tunnel, you'll need to find out:</P>
+<UL>
+<LI><A HREF="#state">what your connection state is,</A> and often</LI>
+<LI><A HREF="#find.pluto.error">an error message</A>.</LI>
+</UL>
+<P>before you can<A HREF="#interpret.pluto.error"> diagnose your problem</A>
+.</P>
+<H3><A NAME="state"></A>2.1 Determine Connection State</H3>
+<H4><A NAME="8_3_1_1">Finding current state</A></H4>
+<P>You can see connection states (STATE_MAIN_I1 and so on) when you
+ bring up a connection on the command line. If you have missed this, or
+ brought up your connection automatically, use:</P>
+<PRE>ipsec auto --status</PRE>
+<P>The most relevant state is the last one reached.</P>
+<H4><A NAME="8_3_1_2"><VAR>What's this supposed to look like?</VAR></A></H4>
+<P>Negotiations should proceed though various states, in the processes
+ of:</P>
+<OL>
+<LI>IKE negotiations (aka Phase 1, Main Mode, STATE_MAIN_*)</LI>
+<LI>IPSEC negotiations (aka Phase 2, Quick Mode, STATE_QUICK_*)</LI>
+</OL>
+<P>These are done and a connection is established when you see messages
+ like:</P>
+<PRE> 000 #21: &quot;myconn&quot; STATE_MAIN_I4 (ISAKMP SA established)...
+ 000 #2: &quot;myconn&quot; STATE_QUICK_I2 (sent QI2, IPsec SA established)...</PRE>
+<P> Look for the key phrases are &quot;ISAKMP SA established&quot; and &quot;IPSec SA
+ established&quot;, with the relevant connection name. Often, this happens at
+ STATE_MAIN_I4 and STATE_QUICK_I2, respectively.</P>
+<P><VAR>ipsec auto --status</VAR> will tell you what states<STRONG> have
+ been achieved</STRONG>, rather than the current state. Since
+ determining the current state is rather more difficult to do, current
+ state information is not available from Linux FreeS/WAN. If you are
+ actively bringing a connection up, the status report's last states for
+ that connection likely reflect its current state. Beware, though, of
+ the case where a connection was correctly brought up but is now downed:
+ Linux FreeS/WAN will not notice this until it attempts to rekey.
+ Meanwhile, the last known state indicates that the connection has been
+ established.</P>
+<P>If your connection is stuck at STATE_MAIN_I1, skip straight to<A HREF="#ikepath">
+ here</A>.</P>
+<H3><A NAME="find.pluto.error"></A>2.2 Finding error text</H3>
+<P>Solving most errors will require you to find verbose error text,
+ either on the command line or in the logs.</P>
+<H4><A NAME="8_3_2_1">Verbose start for more information</A></H4>
+<P> Note that you can get more detail from<VAR> ipsec auto</VAR> using
+ the --verbose flag:</P>
+<PRE STYLE="margin-bottom: 0.2in"> ipsec auto --verbose --up west-east</PRE>
+<P> More complete information can be gleaned from the<A HREF="#logusage">
+ log files</A>.</P>
+<H4><A NAME="8_3_2_2">Debug levels count</A></H4>
+<P>The amount of description you'll get here depends on ipsec.conf debug
+ settings,<VAR> klipsdebug</VAR>= and<VAR> plutodebug</VAR>=. When
+ troubleshooting, set at least one of these to<VAR> all</VAR>, and when
+ done, reset it to<VAR> none</VAR> so your logs don't fill up. Note that
+ you must have enabled the<VAR> klipsdebug</VAR><A HREF="install.html#allbut">
+ compile-time option</A> for the<VAR> klipsdebug</VAR> configuration
+ switch to work.</P>
+<P>For negotiation problems<VAR> plutodebug</VAR> is most relevant.<VAR>
+ klipsdebug</VAR> applies mainly to attempts to use an
+ already-established connection. See also<A HREF="#parts"> this</A>
+ description of the division of duties within Linux FreeS/WAN.</P>
+<P>After raising your debug levels, restart Linux FreeS/WAN to ensure
+ that ipsec.conf is reread, then recreate the error to generate verbose
+ logs.</P>
+<H4><A NAME="8_3_2_3"><VAR>ipsec barf</VAR> for lots of debugging
+ information</A></H4>
+<P><A HREF="manpage.d/ipsec_barf.8.html"><VAR> ipsec barf (8)</VAR></A>
+ collects a bunch of useful debugging information, including these logs
+ Use the command</P>
+<PRE>
+ ipsec barf &gt; barf.west
+</PRE>
+<P>to generate one.</P>
+<H4><A NAME="8_3_2_4">Find the error</A></H4>
+<P>Search out the failure point in your logs. Are there a handful of
+ lines which succinctly describe how things are going wrong or contrary
+ to your expectation? Sometimes the failure point is not immediately
+ obvious: Linux FreeS/WAN's errors are usually not marked &quot;Error&quot;. Have
+ a look in the<A HREF="faq.html"> FAQ</A> for what some common failures
+ look like.</P>
+<P>Tip: problems snowball. Focus your efforts on the first problem,
+ which is likely to be the cause of later errors.</P>
+<H4><A NAME="8_3_2_5">Play both sides</A></H4>
+<P>Also find error text on the peer IPSec box. This gives you two
+ perspectives on the same failure.</P>
+<P>At times you will require information which only one side has. The
+ peer can merely indicate the presence of an error, and its approximate
+ point in the negotiations. If one side keeps retrying, it may be
+ because there is a show stopper on the other side. Have a look at the
+ other side and figure out what it doesn't like.</P>
+<P>If the other end is not Linux FreeS/WAN, the principle is the same:
+ replicate the error with its most verbose logging on, and capture the
+ output to a file.</P>
+<H3><A NAME="interpret.pluto.error"></A>2.3 Interpreting a Negotiation
+ Error</H3>
+<H4><A NAME="ikepath"></A>Connection stuck at STATE_MAIN_I1</H4>
+<P>This error commonly happens because IKE (port 500) packets, needed to
+ negotiate an IPSec connection, cannot travel freely between your IPSec
+ gateways. See<A HREF="#packets"> our firewall document</A> for details.</P>
+<H4><A NAME="8_3_3_2">Other errors</A></H4>
+<P>Other errors require a bit more digging. Use the following resources:</P>
+<UL>
+<LI><A HREF="faq.html">the FAQ</A> . Since this document is constantly
+ updated, the snapshot's FAQ may have a new entry relevant to your
+ problem.</LI>
+<LI>our<A HREF="background.html"> background document</A> . Special
+ considerations which, while not central to Linux FreeS/WAN, are often
+ tripped over. Includes problems with<A href="#MTU.trouble"> packet
+ fragmentation</A>, and considerations for testing opportunism.</LI>
+<LI>the<A HREF="#lists"> list archives</A>. Each of the searchable
+ archives works differently, so it's worth checking each. Use a search
+ term which is generic, but identifies your error, for example &quot;No
+ connection is known for&quot;.
+<BR> Often, you will find that your question has been answered in the
+ past. Finding an archived answer is quicker than asking the list. You
+ may, however, find similar questions without answers. If you do, send
+ their URLs to the list with your trouble report. The additional
+ examples may help the list tech support person find your answer.</LI>
+<LI>Look into the code where the error is being generated. The pluto
+ code is nicely documented with comments and meaningful variable names.</LI>
+</UL>
+<P>If you have failed to solve your problem with the help of these
+ resources, send a detailed problem report to the users list, following
+ these<A HREF="#prob.report"> guidelines</A>.</P>
+<H2><A NAME="use"></A>3. Using a Connection</H2>
+<H3><A NAME="8_4_1">3.1 Orienting yourself</A></H3>
+<H4><A NAME="8_4_1_1"><VAR>How do I know if it works?</VAR></A></H4>
+<P>Test your connection by sending packets through it. The simplest way
+ to do this is with ping, but the ping needs to<STRONG> test the correct
+ tunnel.</STRONG> See<A HREF="#testgates"> this example scenario</A> if
+ you don't understand this.</P>
+<P></P>
+<P>If your ping returns, test any other connections you've brought u all
+ check out, great. You may wish to<A HREF="#bigpacket"> test with large
+ packets</A> for MTU problems.</P>
+<H4><A NAME="8_4_1_2"><VAR>ipsec barf</VAR> is useful again</A></H4>
+<P>If your ping fails to return, generate an ipsec barf debugging report
+ on each IPSec gateway. On a non-Linux FreeS/WAN implementation, gather
+ equivalent information. Use this, and the tips in the next sections, to
+ troubleshoot. Are you sure that both endpoints are capable of hearing
+ and responding to ping?</P>
+<H3><A NAME="8_4_2">3.2 Those pesky configuration errors</A></H3>
+<P>IPSec may be dropping your ping packets since they do not belong in
+ the tunnels you have constructed:</P>
+<UL>
+<LI>Your ping may not test the tunnel you intend to test. For details,
+ see our<A HREF="#cantping"> &quot;I can't ping&quot;</A> FAQ.</LI>
+<LI> Alternately, you may have a configuration error. For example, you
+ may have configured one of the four possible tunnels between two
+ gateways, but not the one required to secure the important traffic
+ you're now testing. In this case, add and start the tunnel, and try
+ again.</LI>
+</UL>
+<P>In either case, you will often see a message like:</P>
+<PRE>klipsdebug... no eroute</PRE>
+<P>which we discuss in<A HREF="#no_eroute"> this FAQ</A>.</P>
+<P>Note:</P>
+<UL>
+<LI><A HREF="#NAT.gloss">Network Address Translation (NAT)</A> and<A HREF="#masq">
+ IP masquerade</A> may have an effect on which tunnels you need to
+ configure.</LI>
+<LI>When testing a tunnel that protects a multi-node subnet, try several
+ subnet nodes as ping targets, in case one node is routing incorrectly.</LI>
+</UL>
+<H3><A NAME="route.firewall"></A>3.3 Check Routing and Firewalling</H3>
+<P>If you've confirmed your configuration assumptions, the problem is
+ almost certainly with routing or firewalling. Isolate the problem using
+ interface statistics, firewall statistics, or a packet sniffer.</P>
+<H4><A NAME="8_4_3_1">Background:</A></H4>
+<UL>
+<LI>Linux FreeS/WAN supplies all the special routing it needs; you need
+ only route packets out through your IPSec gateway. Verify that on the<VAR>
+ subnetted</VAR> machines you are using for your ping-test, your routing
+ is as expected. I have seen a tunnel &quot;fail&quot; because the subnet machine
+ sending packets out an alternate gateway (not our IPSec gateway) on
+ their return path.</LI>
+<LI>Linux FreeS/WAN requires particular<A HREF="firewall.html">
+ firewalling considerations</A>. Check the firewall rules on your IPSec
+ gateways and ensure that they allow IPSec traffic through. Be sure that
+ no other machine - for example a router between the gateways - is
+ blocking your IPSec packets.</LI>
+</UL>
+<H4><A NAME="ifconfig"></A>View Interface and Firewall Statistics</H4>
+<P>Interface reports and firewall statistics can help you track down
+ lost packets at a glance. Check any firewall statistics you may be
+ keeping on your IPSec gateways, for dropped packets.</P>
+<P><STRONG>Tip</STRONG>: You can take a snapshot of the packets
+ processed by your firewall with:</P>
+<PRE> iptables -L -n -v</PRE>
+<P>You can get creative with &quot;diff&quot; to find out what happens to a
+ particular packet during transmission.</P>
+<P>Both<VAR> cat /proc/net/dev</VAR> and<VAR> ifconfig</VAR> display
+ interface statistics, and both are included in<VAR> ipsec barf</VAR>.
+ Use either to check if any interface has dropped packets. If you find
+ that one has, test whether this is related to your ping. While you ping
+ continuously, print that interface's statistics several times. Does its
+ drop count increase in proportion to the ping? If so, check why the
+ packets are dropped there.</P>
+<P>To do this, look at the firewall rules that apply to that interface.
+ If the interface is an IPSec interface, more information may be
+ available in the log. Grep for the word &quot;drop&quot; in a log which was
+ created with<VAR> klipsdebug=all</VAR> as the error happened.</P>
+<P>See also this<A HREF="#ifconfig1"> discussion</A> on interpreting<VAR>
+ ifconfig</VAR> statistics.</P>
+<H3><A NAME="sniff"></A>3.4 When in doubt, sniff it out</H3>
+<P>If you have checked configuration assumptions, routing, and firewall
+ rules, and your interface statistics yield no clue, it remains for you
+ to investigate the mystery of the lost packet by the most thorough
+ method: with a packet sniffer (providing, of course, that this is legal
+ where you are working).</P>
+<P>In order to detect packets on the ipsec virtual interfaces, you will
+ need an up-to-date sniffer (tcpdump, ethereal, ksnuffle) on your IPSec
+ gateway machines. You may also find it useful to sniff the ping
+ endpoints.</P>
+<H4><A NAME="8_4_4_1">Anticipate your packets' path</A></H4>
+<P>Ping, and examine each interface along the projected path, checking
+ for your ping's arrival. If it doesn't get to the the next stop, you
+ have narrowed down where to look for it. In this way, you can isolate a
+ problem area, and narrow your troubleshooting focus.</P>
+<P>Within a machine running Linux FreeS/WAN, this<A HREF="#packets">
+ packet flow diagram</A> will help you anticipate a packet's path.</P>
+<P>Note that:</P>
+<UL>
+<LI> from the perspective of the tunneled packet, the entire tunnel is
+ one hop. That's explained in<A HREF="#no_trace"> this</A> FAQ.</LI>
+<LI> an encapsulated IPSec packet will look different, when sniffed,
+ from the plaintext packet which generated it. You can see plaintext
+ packets entering an IPSec interface and the resulting cyphertext
+ packets as they emerge from the corresponding physical interface.</LI>
+</UL>
+<P>Once you isolate where the packet is lost, take a closer look at
+ firewall rules, routing and configuration assumptions as they affect
+ that specific area. If the packet is lost on an IPSec gateway, comb
+ through<VAR> klipsdebug</VAR> output for anomalies.</P>
+<P>If the packet goes through both gateways successfully and reaches the
+ ping target, but does not return, suspect routing. Check that the ping
+ target routes packets back to the IPSec gateway.</P>
+<H3><A NAME="find.use.error"></A>3.5 Check your logs</H3>
+<P>Here, too, log information can be useful. Start with the<A HREF="#find.pluto.error">
+ guidelines above</A>.</P>
+<P>For connection use problems, set<VAR> klipsdebug=all</VAR>. Note that
+ you must have enabled the<VAR> klipsdebug</VAR><A HREF="install.html#allbut">
+ compile-time option</A> to do this. Restart Linux FreeS/WAN so that it
+ rereads<VAR> ipsec.conf</VAR>, then recreate the error condition. When
+ searching through<VAR> klipsdebug</VAR> data, look especially for the
+ keywords &quot;drop&quot; (as in dropped packets) and &quot;error&quot;.</P>
+<P>Often the problem with connection use is not software error, but
+ rather that the software is behaving contrary to expectation.</P>
+<H4><A NAME="interpret.use.error"></A>Interpreting log text</H4>
+<P>To interpret the Linux FreeS/WAN log text you've found, use the same
+ resources as indicated for troubleshooting connection negotiation:<A HREF="faq.html">
+ the FAQ</A> , our<A HREF="background.html"> background document</A>,
+ and the<A HREF="#lists"> list archives</A>. Looking in the KLIPS code
+ is only for the very brave.</P>
+<P>If you are still stuck, send a<A HREF="#prob.report"> detailed
+ problem report</A> to the users' list.</P>
+<H3><A NAME="bigpacket"></A>3.6 More testing for the truly thorough</H3>
+<H4><A NAME="8_4_6_1">Large Packets</A></H4>
+<P>If each of your connections passed the ping test, you may wish to
+ test by pinging with large packets (2000 bytes or larger). If it does
+ not return, suspect MTU issues, and see this<A HREF="#MTU.trouble">
+ discussion</A>.</P>
+<H4><A NAME="8_4_6_2">Stress Tests</A></H4>
+<P>In most users' view, a simple ping test, and perhaps a large-packet
+ ping test suffice to indicate a working IPSec connection.</P>
+<P>Some people might like to do additional stress tests prior to
+ production use. They may be interested in this<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00224.html">
+ testing protocol</A> we use at interoperation conferences, aka
+ &quot;bakeoffs&quot;. We also have a<VAR> testing</VAR> directory that ships with
+ the release.</P>
+<H2><A NAME="prob.report"></A>4. Problem Reporting</H2>
+<H3><A NAME="8_5_1">4.1 How to ask for help</A></H3>
+<P>Ask for troubleshooting help on the users' mailing list,<A HREF="mailto:users@lists.freeswan.org">
+ users@lists.freeswan.org</A>. While sometimes an initial query with a
+ quick description of your intent and error will twig someone's memory
+ of a similar problem, it's often necessary to send a second mail with a
+ complete problem report.</P>
+<P>When reporting problems to the mailing list(s), please include:</P>
+<UL>
+<LI>a brief description of the problem</LI>
+<LI>if it's a compile problem, the actual output from make, showing the
+ problem. Try to edit it down to only the relevant part, but when in
+ doubt, be as complete as you can. If it's a kernel compile problem, any
+ relevant out.* files</LI>
+<LI>if it's a run-time problem, pointers to where we can find the
+ complete output from &quot;ipsec barf&quot; from BOTH ENDS (not just one of
+ them). Remember that it's common outside the US and Canada to pay for
+ download volume, so if you can't post barfs on the web and send the URL
+ to the mailing list, at least compress them with tar or gzip.
+<BR> If you can, try to simplify the case that is causing the problem.
+ In particular, if you clear your logs, start FreeS/WAN with no other
+ connections running, cause the problem to happen, and then do<VAR>
+ ipsec barf</VAR> on both ends immediately, that gives the smallest and
+ least cluttered output.</LI>
+<LI>any other error messages, complaints, etc. that you saw. Please send
+ the complete text of the messages, not just a summary.</LI>
+<LI>what your network setup is. Include subnets, gateway addresses, etc.
+ A schematic diagram is a good format for this information.</LI>
+<LI>exactly what you were trying to do with Linux FreeS/WAN, and exactly
+ what went wrong</LI>
+<LI>a fix, if you have one. But remember, you are sending mail to people
+ all over the world; US residents and US citizens in particular, please
+ read doc/exportlaws.html before sending code -- even small bug fixes --
+ to the list or to us.</LI>
+<LI>When in doubt about whether to include some seemingly-trivial item
+ of information, include it. It is rare for problem reports to have too
+ much information, and common for them to have too little.</LI>
+</UL>
+<P>Here are some good general guidelines on bug reporting:<A href="http://tuxedo.org/~esr/faqs/smart-questions.html">
+ How To Ask Questions The Smart Way</A> and<A href="http://www.chiark.greenend.org.uk/~sgtatham/bugs.html">
+ How to Report Bugs Effectively</A>.</P>
+<H3><A NAME="8_5_2">4.2 Where to ask</A></H3>
+<P>To report a problem, send mail about it to the users' list. If you
+ are certain that you have found a bug, report it to the bugs list. If
+ you encounter a problem while doing your own coding on the Linux
+ FreeS/WAN codebase and think it is of interest to the design team,
+ notify the design list. When in doubt, default to the users' list. More
+ information about the mailing lists is found<A HREF="#lists"> here</A>.</P>
+<P>For a number of reasons -- including export-control regulations
+ affecting almost any<STRONG> private</STRONG> discussion of encryption
+ software -- we prefer that problem reports and discussions go to the
+ lists, not directly to the team. Beware that the list goes worldwide;
+ US citizens, read this important information about your<A HREF="#exlaw">
+ export laws</A>. If you're using this software, you really should be on
+ the lists. To get onto them, visit<A HREF="http://lists.freeswan.org/">
+ lists.freeswan.org</A>.</P>
+<P>If you do send private mail to our coders or want a private reply
+ from them, please make sure that the return address on your mail (From
+ or Reply-To header) is a valid one. They have more important things to
+ do than to unravel addresses that have been mangled in an attempt to
+ confuse spammers.</P>
+<H2><A NAME="notes"></A>5. Additional Notes on Troubleshooting</H2>
+<P>The following sections supplement the Guide:<A HREF="#system.info">
+ information available on your system</A>;<A HREF="#testgates"> testing
+ between security gateways</A>;<A HREF="#ifconfig1"> ifconfig reports
+ for KLIPS debugging</A>;<A HREF="#gdb"> using GDB on Pluto</A>.</P>
+<H3><A NAME="system.info"></A>5.1 Information available on your system</H3>
+<H4><A NAME="logusage"></A>Logs used</H4>
+<P>Linux FreeS/WAN logs to:</P>
+<UL>
+<LI>/var/log/secure (or, on Debian, /var/log/auth.log)</LI>
+<LI>/var/log/messages</LI>
+</UL>
+<P>Check both places to get full information. If you find nothing, check
+ your<VAR> syslogd.conf(5)</VAR> to see where your /etc/syslog.conf or
+ equivalent is directing<VAR> authpriv</VAR> messages.</P>
+<H4><A NAME="pages"></A>man pages provided</H4>
+<DL>
+<DT><A HREF="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A></DT>
+<DD> Manual page for IPSEC configuration file.</DD>
+<DT><A HREF="manpage.d/ipsec.8.html"> ipsec(8)</A></DT>
+<DD STYLE="margin-bottom: 0.2in"> Primary man page for ipsec utilities.</DD>
+</DL>
+<P> Other man pages are on<A HREF="manpages.html"> this list</A> and in</P>
+<UL>
+<LI>/usr/local/man/man3</LI>
+<LI>/usr/local/man/man5</LI>
+<LI>/usr/local/man/man8/ipsec_*</LI>
+</UL>
+<H4><A NAME="statusinfo"></A>Status information</H4>
+<DL>
+<DT>ipsec auto --status</DT>
+<DD> Command to get status report from running system. Displays Pluto's
+ state. Includes the list of connections which are currently &quot;added&quot; to
+ Pluto's internal database; lists state objects reflecting ISAKMP and
+ IPsec SAs being negotiated or installed.</DD>
+<DT> ipsec look</DT>
+<DD> Brief status info.</DD>
+<DT> ipsec barf</DT>
+<DD STYLE="margin-bottom: 0.2in"> Copious debugging info.</DD>
+</DL>
+<H3><A NAME="testgates"></A> 5.2 Testing between security gateways</H3>
+<P>Sometimes you need to test a subnet-subnet tunnel. This is a tunnel
+ between two security gateways, which protects traffic on behalf of the
+ subnets behind these gateways. On this network:</P>
+<PRE> Sunset==========West------------------East=========Sunrise
+ IPSec gateway IPSec gateway
+ local net untrusted net local net</PRE>
+<P> you might name this tunnel sunset-sunrise. You can test this tunnel
+ by having a machine behind one gateway ping a machine behind the other
+ gateway, but this is not always convenient or even possible.</P>
+<P>Simply pinging one gateway from the other is not useful. Such a ping
+ does not normally go through the tunnel.<STRONG> The tunnel handles
+ traffic between the two protected subnets, not between the gateways</STRONG>
+ . Depending on the routing in place, a ping might</P>
+<UL>
+<LI>either succeed by finding an unencrypted route</LI>
+<LI>or fail by finding no route. Packets without an IPSEC eroute are
+ discarded.</LI>
+</UL>
+<P><STRONG>Neither event tells you anything about the tunnel</STRONG>.
+ You can explicitly create an eroute to force such packets through the
+ tunnel, or you can create additional tunnels as described in our<A HREF="#multitunnel">
+ configuration document</A>, but those may be unnecessary complications
+ in your situation.</P>
+<P>The trick is to explicitly test between<STRONG> both gateways'
+ private-side IP addresses</STRONG>. Since the private-side interfaces
+ are on the protected subnets, the resulting packets do go via the
+ tunnel. Use either ping -I or traceroute -i, both of which allow you to
+ specify a source interface. (Note: unsupported on older Linuxes). The
+ same principles apply for a road warrior (or other) case where only one
+ end of your tunnel is a subnet.</P>
+<H3><A NAME="ifconfig1"></A>5.3 ifconfig reports for KLIPS debugging</H3>
+<P>When diagnosing problems using ifconfig statistics, you may wonder
+ what type of activity increments a particular counter for an ipsecN
+ device. Here's an index, posted by KLIPS developer Richard Guy Briggs:</P>
+<PRE>Here is a catalogue of the types of errors that can occur for which
+statistics are kept when transmitting and receiving packets via klips.
+I notice that they are not necessarily logged in the right counter.
+. . .
+
+Sources of ifconfig statistics for ipsec devices
+
+rx-errors:
+- packet handed to ipsec_rcv that is not an ipsec packet.
+- ipsec packet with payload length not modulo 4.
+- ipsec packet with bad authenticator length.
+- incoming packet with no SA.
+- replayed packet.
+- incoming authentication failed.
+- got esp packet with length not modulo 8.
+
+tx_dropped:
+- cannot process ip_options.
+- packet ttl expired.
+- packet with no eroute.
+- eroute with no SA.
+- cannot allocate sk_buff.
+- cannot allocate kernel memory.
+- sk_buff internal error.
+
+
+The standard counters are:
+
+struct enet_statistics
+{
+ int rx_packets; /* total packets received */
+ int tx_packets; /* total packets transmitted */
+ int rx_errors; /* bad packets received */
+ int tx_errors; /* packet transmit problems */
+ int rx_dropped; /* no space in linux buffers */
+ int tx_dropped; /* no space available in linux */
+ int multicast; /* multicast packets received */
+ int collisions;
+
+ /* detailed rx_errors: */
+ int rx_length_errors;
+ int rx_over_errors; /* receiver ring buff overflow */
+ int rx_crc_errors; /* recved pkt with crc error */
+ int rx_frame_errors; /* recv'd frame alignment error */
+ int rx_fifo_errors; /* recv'r fifo overrun */
+ int rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ int tx_aborted_errors;
+ int tx_carrier_errors;
+ int tx_fifo_errors;
+ int tx_heartbeat_errors;
+ int tx_window_errors;
+};
+
+of which I think only the first 6 are useful.</PRE>
+<H3><A NAME="gdb"></A> 5.4 Using GDB on Pluto</H3>
+<P>You may need to use the GNU debugger, gdb(1), on Pluto. This should
+ be necessary only in unusual cases, for example if you encounter a
+ problem which the Pluto developer cannot readily reproduce or if you
+ are modifying Pluto.</P>
+<P>Here are the Pluto developer's suggestions for doing this:</P>
+<PRE>Can you get a core dump and use gdb to find out what Pluto was doing
+when it died?
+
+To get a core dump, you will have to set dumpdir to point to a
+suitable directory (see <A HREF="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A>).
+
+To get gdb to tell you interesting stuff:
+ $ script
+ $ cd dump-directory-you-chose
+ $ gdb /usr/local/lib/ipsec/pluto core
+ (gdb) where
+ (gdb) quit
+ $ exit
+
+The resulting output will have been captured by the script command in
+a file called &quot;typescript&quot;. Send it to the list.
+
+Do not delete the core file. I may need to ask you to print out some
+more relevant stuff.</PRE>
+<P> Note that the<VAR> dumpdir</VAR> parameter takes effect only when
+ the IPsec subsystem is restarted -- reboot or ipsec setup restart.</P>
+<P>
+<BR>
+<BR></P>
+<HR>
+<H1><A name="compat">Linux FreeS/WAN Compatibility Guide</A></H1>
+<P>Much of this document is quoted directly from the Linux FreeS/WAN<A href="mail.html">
+ mailing list</A>. Thanks very much to the community of testers,
+ patchers and commenters there, especially the ones quoted below but
+ also various contributors we haven't quoted.</P>
+<H2><A name="spec">Implemented parts of the IPsec Specification</A></H2>
+<P>In general, do not expect Linux FreeS/WAN to do everything yet. This
+ is a work-in-progress and some parts of the IPsec specification are not
+ yet implemented.</P>
+<H3><A name="in">In Linux FreeS/WAN</A></H3>
+<P>Things we do, as of version 1.96:</P>
+<UL>
+<LI>key management methods
+<DL>
+<DT>manually keyed</DT>
+<DD>using keys stored in /etc/ipsec.conf</DD>
+<DT>automatically keyed</DT>
+<DD>Automatically negotiating session keys as required. All connections
+ are automatically re-keyed periodically. The<A href="#Pluto"> Pluto</A>
+ daemon implements this using the<A href="#IKE"> IKE</A> protocol.</DD>
+</DL>
+</LI>
+<LI>Methods of authenticating gateways for IKE
+<DL>
+<DT>shared secrets</DT>
+<DD>stored in<A href="manpage.d/ipsec.secrets.5.html"> ipsec.secrets(5)</A>
+</DD>
+<DT><A href="#RSA">RSA</A> signatures</DT>
+<DD>For details, see<A href="manpage.d/ipsec_pluto.8.html"> pluto(8)</A>
+.</DD>
+<DT>looking up RSA authentication keys from<A href="#DNS"> DNS</A>.</DT>
+<DD>Note that this technique cannot be fully secure until<A href="#SDNS">
+ secure DNS</A> is widely deployed.</DD>
+</DL>
+</LI>
+<LI>groups for<A href="#DH"> Diffie-Hellman</A> key negotiation
+<DL>
+<DT>group 2, modp 1024-bit</DT>
+<DT>group 5, modp 1536-bit</DT>
+<DD>We implement these two groups.
+<P>In negotiating a keying connection (ISAKMP SA, Phase 1) we propose
+ both groups when we are the initiator, and accept either when a peer
+ proposes them. Once the keying connection is made, we propose only the
+ alternative agreed there for data connections (IPsec SA's, Phase 2)
+ negotiated over that keying connection.</P>
+</DD>
+</DL>
+</LI>
+<LI>encryption transforms
+<DL>
+<DT><A href="#DES">DES</A></DT>
+<DD>DES is in the source code since it is needed to implement 3DES, but
+ single DES is not made available to users because<A href="#desnotsecure">
+ DES is insecure</A>.</DD>
+<DT><A href="#3DES">Triple DES</A></DT>
+<DD>implemented, and used as the default encryption in Linux FreeS/WAN.</DD>
+</DL>
+</LI>
+<LI>authentication transforms
+<DL>
+<DT><A href="#HMAC">HMAC</A> using<A href="#MD5"> MD5</A></DT>
+<DD>implemented, may be used in IKE or by by AH or ESP transforms.</DD>
+<DT><A href="#HMAC">HMAC</A> using<A href="#SHA"> SHA</A></DT>
+<DD>implemented, may be used in IKE or by AH or ESP transforms.</DD>
+</DL>
+<P>In negotiations, we propose both of these and accept either.</P>
+</LI>
+<LI>compression transforms
+<DL>
+<DT>IPComp</DT>
+<DD>IPComp as described in RFC 2393 was added for FreeS/WAN 1.6. Note
+ that Pluto becomes confused if you ask it to do IPComp when the kernel
+ cannot.</DD>
+</DL>
+</LI>
+</UL>
+<P>All combinations of implemented transforms are supported. Note that
+ some form of packet-level<STRONG> authentication is required whenever
+ encryption is used</STRONG>. Without it, the encryption will not be
+ secure.</P>
+<H3><A name="dropped">Deliberately omitted</A></H3>
+ We do not implement everything in the RFCs because some of those things
+ are insecure. See our discussions of avoiding<A href="#weak"> bogus
+ security</A>.
+<P>Things we deliberately omit which are required in the RFCs are:</P>
+<UL>
+<LI>null encryption (to use ESP as an authentication-only service)</LI>
+<LI>single DES</LI>
+<LI>DH group 1, a 768-bit modp group</LI>
+</UL>
+<P>Since these are the only encryption algorithms and DH group the RFCs
+ require, it is possible in theory to have a standards-conforming
+ implementation which will not interpoperate with FreeS/WAN. Such an
+ implementation would be inherently insecure, so we do not consider this
+ a problem.</P>
+<P>Anyway, most implementations sensibly include more secure options as
+ well, so dropping null encryption, single DES and Group 1 does not
+ greatly hinder interoperation in practice.</P>
+<P>We also do not implement some optional features allowed by the RFCs:</P>
+<UL>
+<LI>aggressive mode for negotiation of the keying channel or ISAKMP SA.
+ This mode is a little faster than main mode, but exposes more
+ information to an eavesdropper.</LI>
+</UL>
+<P>In theory, this should cause no interoperation problems since all
+ implementations are required to support the more secure main mode,
+ whether or not they also allow aggressive mode.</P>
+<P>In practice, it does sometimes produce problems with implementations
+ such as Windows 2000 where aggressive mode is the default. Typically,
+ these are easily solved with a configuration change that overrides that
+ default.</P>
+<H3><A name="not">Not (yet) in Linux FreeS/WAN</A></H3>
+<P>Things we don't yet do, as of version 1.96:</P>
+<UL>
+<LI>key management methods
+<UL>
+<LI>authenticate key negotiations via local<A href="#PKI"> PKI</A>
+ server, but see links to user<A href="#patch"> patches</A></LI>
+<LI>authenticate key negotiations via<A href="#SDNS"> secure DNS</A></LI>
+<LI>unauthenticated key management, using<A href="#DH"> Diffie-Hellman</A>
+ key agreement protocol without authentication. Arguably, this would be
+ worth doing since it is secure against all passive attacks. On the
+ other hand, it is vulnerable to an active<A href="#middle">
+ man-in-the-middle attack</A>.</LI>
+</UL>
+</LI>
+<LI>encryption transforms
+<P>Currently<A href="#3DES"> Triple DES</A> is the only encryption
+ method Pluto will negotiate.</P>
+<P>No additional encryption transforms are implemented, though the RFCs
+ allow them and some other IPsec implementations support various of
+ them. We are not eager to add more. See this<A href="#other.cipher">
+ FAQ question</A>.</P>
+<P><A href="#AES">AES</A>, the successor to the DES standard, is an
+ excellent candidate for inclusion in FreeS/WAN, see links to user<A href="#patch">
+ patches</A>.</P>
+</LI>
+<LI>authentication transforms
+<P>No optional additional authentication transforms are currently
+ implemented. Likely<A href="#SHA-256"> SHA-256, SHA-384 and SHA-512</A>
+ will be added when AES is.</P>
+</LI>
+<LI>Policy checking on decrypted packets
+<P>To fully comply with the RFCs, it is not enough just to accept only
+ packets which survive any firewall rules in place to limit what IPsec
+ packets get in, and then pass KLIPS authentication. That is what
+ FreeS/WAN currently does.</P>
+<P>We should also apply additional tests, for example ensuring that all
+ packets emerging from a particular tunnel have source and destination
+ addresses that fall within the subnets defined for that tunnel, and
+ that packets with those addresses that did not emerge from the
+ appropriate tunnel are disallowed.</P>
+<P>This will be done as part of a KLIPS rewrite. See these<A href="#applied">
+ links</A> and the<A href="mail.html"> design mailing list</A> for
+ discussion.</P>
+</LI>
+</UL>
+<H2><A name="pfkey">Our PF-Key implementation</A></H2>
+<P>We use PF-key Version Two for communication between the KLIPS kernel
+ code and the Pluto Daemon. PF-Key v2 is defined by<A href="http://www.normos.org/ietf/rfc/rfc2367.txt">
+ RFC 2367</A>.</P>
+<P>The &quot;PF&quot; stands for Protocol Family. PF-Inet defines a
+ kernel/userspace interface for the TCP/IP Internet protocols (TCP/IP),
+ and other members of the PF series handle Netware, Appletalk, etc.
+ PF-Key is just a PF for key-related matters.</P>
+<H3><A name="pfk.port">PF-Key portability</A></H3>
+<P>PF-Key came out of Berkeley Unix work and is used in the various BSD
+ IPsec implementations, and in Solaris. This means there is some hope of
+ porting our Pluto(8) to one of the BSD distributions, or of running
+ their photurisd(8) on Linux if you prefer<A href="#photuris"> Photuris</A>
+ key management over IKE.</P>
+<P>It is, however, more complex than that. The PK-Key RFC deliberately
+ deals only with keying, not policy management. The three PF-Key
+ implementations we have looked at -- ours, OpenBSD and KAME -- all have
+ extensions to deal with security policy, and the extensions are
+ different. There have been discussions aimed at sorting out the
+ differences, perhaps for a version three PF-Key spec. All players are
+ in favour of this, but everyone involved is busy and it is not clear
+ whether or when these discussions might bear fruit.</P>
+<H2><A name="otherk">Kernels other than the latest 2.2.x and 2.4.y</A></H2>
+<P>We develop and test on Redhat Linux using the most recent kernel in
+ the 2.2 and 2.4 series. In general, we recommend you use the latest
+ kernel in one of those series. Complications and caveats are discussed
+ below.</P>
+<H3><A name="kernel.2.0">2.0.x kernels</A></H3>
+<P>Consider upgrading to the 2.2 kernel series. If you want to stay with
+ the 2.0 series, then we strongly recommend 2.0.39. Some useful security
+ patches were added in 2.0.38.</P>
+<P>Various versions of the code have run at various times on most 2.0.xx
+ kernels, but the current version is only lightly tested on 2.0.39, and
+ not at all on older kernels.</P>
+<P>Some of our patches for older kernels are shipped in 2.0.37 and
+ later, so they are no longer provided in FreeS/WAN. This means recent
+ versions of FreeS/WAN will probably not compile on anything earlier
+ than 2.0.37.</P>
+<H3><A name="kernel.production">2.2 and 2.4 kernels</A></H3>
+<DL>
+<DT>FreeS/WAN 1.0</DT>
+<DD>ran only on 2.0 kernels</DD>
+<DT>FreeS/WAN 1.1 to 1.8</DT>
+<DD>ran on 2.0 or 2.2 kernels
+<BR> ran on some development kernels, 2.3 or 2.4-test</DD>
+<DT>FreeS/WAN 1.9 to 1.96</DT>
+<DD>runs on 2.0, 2.2 or 2.4 kernels</DD>
+</DL>
+<P>In general,<STRONG> we suggest the latest 2.2 kernel or 2.4 for
+ production use</STRONG>.</P>
+<P>Of course no release can be guaranteed to run on kernels more recent
+ than it is, so quite often there will be no stable FreeS/WAN for the
+ absolute latest kernel. See the<A href="#k.versions"> FAQ</A> for
+ discussion.</P>
+<H2><A name="otherdist">Intel Linux distributions other than Redhat</A></H2>
+<P>We develop and test on Redhat 6.1 for 2.2 kernels, and on Redhat 7.1
+ or 7.2 for 2.4, so minor changes may be required for other
+ distributions.</P>
+<H3><A name="rh7">Redhat 7.0</A></H3>
+<P>There are some problems with FreeS/WAN on Redhat 7.0. They are
+ soluble, but we recommend you upgrade to a later Redhat instead..</P>
+<P>Redhat 7 ships with two compilers.</P>
+<UL>
+<LI>Their<VAR> gcc</VAR> is version 2.96. Various people, including the
+ GNU compiler developers and Linus, have said fairly emphatically that
+ using this was a mistake. 2.96 is a development version, not intended
+ for production use. In particular, it will not compile a Linux kernel.</LI>
+<LI>Redhat therefore also ship a separate compiler, which they call<VAR>
+ kgcc</VAR>, for compiling kernels.</LI>
+</UL>
+<P>Kernel Makefiles have<VAR> gcc</VAR> as a default, and must be
+ adjusted to use<VAR> kgcc</VAR> before a kernel will compile on 7.0.
+ This mailing list message gives details:</P>
+<PRE>Subject: Re: AW: Installing IPsec on Redhat 7.0
+ Date: Thu, 1 Feb 2001 14:32:52 -0200 (BRST)
+ From: Mads Rasmussen &lt;mads@cit.com.br&gt;
+
+&gt; From www.redhat.com/support/docs/gotchas/7.0/gotchas-7-6.html#ss6.1
+
+cd to /usr/src/linux and open the Makefile in your favorite editor. You
+will need to look for a line similar to this:
+
+CC = $(CROSS_COMPILE)gcc -D__KERNEL__ -I$(HPATH)
+
+This line specifies which C compiler to use to build the kernel. It should
+be changed to:
+
+CC = $(CROSS_COMPILE)kgcc -D__KERNEL__ -I$(HPATH)
+
+for Red Hat Linux 7. The kgcc compiler is egcs 2.91.66. From here you can
+proceed with the typical compiling steps.</PRE>
+<P>Check the<A href="mail.html"> mailing list</A> archive for more
+ recent news.</P>
+<H3><A name="suse">SuSE Linux</A></H3>
+<P>SuSE 6.3 and later versions, at least in Europe, ship with FreeS/WAN
+ included.</P>
+<P>FreeS/WAN packages distributed for SuSE 7.0-7.2 were somehow
+ miscompiled. You can find fixed packages on<A HREF="http://www.suse.de/~garloff/linux/FreeSWAN">
+ Kurt Garloff's page</A>.</P>
+<P>Here are some notes for an earlier SuSE version.</P>
+<H4><A NAME="9_4_2_1">SuSE Linux 5.3</A></H4>
+<PRE>Date: Mon, 30 Nov 1998
+From: Peter Onion &lt;ponion@srd.bt.co.uk&gt;
+
+... I got Saturdays snapshot working between my two SUSE5.3 machines at home.
+
+The mods to the install process are quite simple. From memory and looking at
+the files on the SUSE53 machine here at work....
+
+And extra link in each of the /etc/init.d/rc?.d directories called K35ipsec
+which SUSE use to shut a service down.
+
+A few mods in /etc/init.d/ipsec to cope with the different places that SUSE
+put config info, and remove the inculsion of /etc/rc.d/init.d/functions and .
+/etc/sysconfig/network as they don't exists and 1st one isn't needed anyway.
+
+insert &quot;. /etc/rc.config&quot; to pick up the SUSE config info and use
+
+ if test -n &quot;$NETCONFIG&quot; -a &quot;$NETCONFIG&quot; != &quot;YAST_ASK&quot; ; then
+
+to replace
+
+ [ ${NETWORKING} = &quot;no&quot; ] &amp;&amp; exit 0
+
+Create /etc/sysconfig as SUSE doesn't have one.
+
+I think that was all (but I prob forgot something)....</PRE>
+<P>You may also need to fiddle initialisation scripts to ensure that<VAR>
+ /var/run/pluto.pid</VAR> is removed when rebooting. If this file is
+ present, Pluto does not come up correctly.</P>
+<H3><A name="slack">Slackware</A></H3>
+<PRE>Subject: Re: linux-IPsec: Slackware distribution
+ Date: Thu, 15 Apr 1999 12:07:01 -0700
+ From: Evan Brewer &lt;dmessiah@silcon.com&gt;
+
+&gt; Very shortly, I will be needing to install IPsec on at least gateways that
+&gt; are running Slackware. . . .
+
+The only trick to getting it up is that on the slackware dist there is no
+init.d directory in /etc/rc.d .. so create one. Then, what I do is take the
+IPsec startup script which normally gets put into the init.d directory, and
+put it in /etc/rc.d and name ir rc.ipsec .. then I symlink it to the file
+in init.d. The only file in the dist you need to really edit is the
+utils/Makefile, setup4:
+
+Everything else should be just fine.</PRE>
+<P>A year or so later:</P>
+<PRE>Subject: Re: HTML Docs- Need some cleanup?
+ Date: Mon, 8 Jan 2001
+ From: Jody McIntyre &lt;jodym@oeone.com&gt;
+
+I have successfully installed FreeS/WAN on several Slackware 7.1 machines.
+FreeS/WAN installed its rc.ipsec file in /etc/rc.d. I had to manually call
+this script from rc.inet2. This seems to be an easier method than Evan
+Brewer's.</PRE>
+<H3><A name="deb">Debian</A></H3>
+<P>A recent (Nov 2001) mailing list points to a<A href="http://www.thing.dyndns.org/debian/vpn.htm">
+ web page</A> on setting up several types of tunnel, including IPsec, on
+ Debian.</P>
+<P>Some older information:</P>
+<PRE>Subject: FreeS/WAN 1.0 on Debian 2.1
+ Date: Tue, 20 Apr 1999
+ From: Tim Miller &lt;cerebus+counterpane@haybaler.sackheads.org&gt;
+
+ Compiled and installed without error on a Debian 2.1 system
+with kernel-source-2.0.36 after pointing RCDIR in utils/Makefile to
+/etc/init.d.
+
+ /var/lock/subsys/ doesn't exist on Debian boxen, needs to be
+created; not a fatal error.
+
+ Finally, IPsec scripts appear to be dependant on GNU awk
+(gawk); the default Debian awk (mawk-1.3.3-2) had fatal difficulties.
+With gawk installed and /etc/alternatives/awk linked to /usr/bin/gawk
+operation appears flawless.</PRE>
+<P>The scripts in question have been modified since this was posted. Awk
+ versions should no longer be a problem.</P>
+<H3><A name="caldera">Caldera</A></H3>
+<PRE>Subject: Re: HTML Docs- Need some cleanup?
+ Date: Mon, 08 Jan 2001
+ From: Andy Bradford &lt;andyb@calderasystems.com&gt;
+
+On Sun, 07 Jan 2001 22:59:05 EST, Sandy Harris wrote:
+
+&gt; Intel Linux distributions other than Redhat 5.x and 6.x
+&gt; Redhat 7.0
+&gt; SuSE Linux
+&gt; SuSE Linux 5.3
+&gt; Slackware
+&gt; Debian
+
+Can you please include Caldera in this list? I have tested it since
+FreeS/Wan 1.1 and it works great with our systems---provided one
+follows the FreeS/Wan documentation. :-)
+
+Thank you,
+Andy</PRE>
+<H2><A name="CPUs">CPUs other than Intel</A></H2>
+<P>FreeS/WAN has been run sucessfully on a number of different CPU
+ architectures. If you have tried it on one not listed here, please post
+ to the<A href="mail.html"> mailing list</A>.</P>
+<H3><A name=" strongarm">Corel Netwinder (StrongARM CPU)</A></H3>
+<PRE>Subject: linux-ipsec: Netwinder diffs
+Date: Wed, 06 Jan 1999
+From: rhatfield@plaintree.com
+
+I had a mistake in my IPsec-auto, so I got things working this morning.
+
+Following are the diffs for my changes. Probably not the best and cleanest way
+of doing it, but it works. . . . </PRE>
+<P>These diffs are in the 0.92 and later distributions, so these should
+ work out-of-the-box on Netwinder.</P>
+<H3><A name="yellowdog">Yellow Dog Linux on Power PC</A></H3>
+<PRE>Subject: Compiling FreeS/WAN 1.1 on YellowDog Linux (PPC)
+ Date: 11 Dec 1999
+ From: Darron Froese &lt;darron@fudgehead.com&gt;
+
+I'm summarizing here for the record - because it's taken me many hours to do
+this (multiple times) and because I want to see IPsec on more linuxes than
+just x86.
+
+Also, I can't remember if I actually did summarize it before... ;-) I'm
+working too many late hours.
+
+That said - here goes.
+
+1. Get your linux kernel and unpack into /usr/src/linux/ - I used 2.2.13.
+&lt;http://www.kernel.org/pub/linux/kernel/v2.2/linux-2.2.13.tar.bz2&gt;
+
+2. Get FreeS/WAN and unpack into /usr/src/freeswan-1.1
+&lt;ftp://ftp.xs4all.nl/pub/crypto/freeswan/freeswan-1.1.tar.gz&gt;
+
+3. Get the gmp src rpm from here:
+&lt;ftp://ftp.yellowdoglinux.com//pub/yellowdog/champion-1.1/SRPMS/SRPMS/gmp-2.0.2-9a.src.rpm&gt;
+
+4. Su to root and do this: rpm --rebuild gmp-2.0.2-9a.src.rpm
+
+You will see a lot of text fly by and when you start to see the rpm
+recompiling like this:
+
+Executing: %build
++ umask 022
++ cd /usr/src/redhat/BUILD
++ cd gmp-2.0.2
++ libtoolize --copy --force
+Remember to add `AM_PROG_LIBTOOL' to `configure.in'.
+You should add the contents of `/usr/share/aclocal/libtool.m4' to
+`aclocal.m4'.
++ CFLAGS=-O2 -fsigned-char
++ ./configure --prefix=/usr
+
+Hit Control-C to stop the rebuild. NOTE: We're doing this because for some
+reason the gmp source provided with FreeS/WAN 1.1 won't build properly on
+ydl.
+
+cd /usr/src/redhat/BUILD/
+cp -ar gmp-2.0.2 /usr/src/freeswan-1.1/
+cd /usr/src/freeswan-1.1/
+rm -rf gmp
+mv gmp-2.0.2 gmp
+
+5. Open the freeswan Makefile and change the line that says:
+KERNEL=$(b)zimage (or something like that) to
+KERNEL=vmlinux
+
+6. cd ../linux/
+
+7. make menuconfig
+Select an option or two and then exit - saving your changes.
+
+8. cd ../freeswan-1.1/ ; make menugo
+
+That will start the whole process going - once that's finished compiling,
+you have to install your new kernel and reboot.
+
+That should build FreeS/WAN on ydl (I tried it on 1.1).</PRE>
+ And a later message on the same topic:
+<PRE>Subject: Re: FreeS/WAN, PGPnet and E-mail
+ Date: Sat, 22 Jan 2000
+ From: Darron Froese &lt;darron@fudgehead.com&gt;
+
+on 1/22/00 6:47 PM, Philip Trauring at philip@trauring.com wrote:
+
+&gt; I have a PowerMac G3 ...
+
+The PowerMac G3 can run YDL 1.1 just fine. It should also be able to run
+FreeS/WAN 1.2patch1 with a couple minor modifications:
+
+1. In the Makefile it specifies a bzimage for the kernel compile - you have
+to change that to vmlinux for the PPC.
+
+2. The gmp source that comes with FreeS/WAN (for whatever reason) fails to
+compile. I have gotten around this by getting the gmp src rpm from here:
+
+ftp://ftp.yellowdoglinux.com//pub/yellowdog/champion-1.1/SRPMS/SRPMS/gmp-2.0.2-9a.src.rpm
+
+If you rip the source out of there - and place it where the gmp source
+resides it will compile just fine.</PRE>
+<P>FreeS/WAN no longer includes GMP source.</P>
+<H3><A name="mklinux">Mklinux</A></H3>
+<P>One user reports success on the Mach-based<STRONG> m</STRONG>icro<STRONG>
+k</STRONG>ernel Linux.</P>
+<PRE>Subject: Smiles on sparc and ppc
+ Date: Fri, 10 Mar 2000
+ From: Jake Hill &lt;jah@alien.bt.co.uk&gt;
+
+You may or may not be interested to know that I have successfully built
+FreeS/WAN on a number of non intel alpha architectures; namely on ppc
+and sparc and also on osfmach3/ppc (MkLinux). I can report that it just
+works, mostly, with few changes.</PRE>
+<H3><A name="alpha">Alpha 64-bit processors</A></H3>
+<PRE>Subject: IT WORKS (again) between intel &amp; alpha :-)))))
+ Date: Fri, 29 Jan 1999
+ From: Peter Onion &lt;ponion@srd.bt.co.uk&gt;
+
+Well I'm happy to report that I've got an IPsec connection between by intel &amp; alpha machines again :-))
+
+If you look back on this list to 7th of December I wrote...
+
+-On 07-Dec-98 Peter Onion wrote:
+-&gt;
+-&gt; I've about had enuf of wandering around inside the kernel trying to find out
+-&gt; just what is corrupting outgoing packets...
+-
+-Its 7:30 in the evening .....
+-
+-I FIXED IT :-))))))))))))))))))))))))))))))))
+-
+-It was my own fault :-((((((((((((((((((
+-
+-If you ask me very nicly I'll tell you where I was a little too over keen to
+-change unsigned long int __u32 :-) OPSE ...
+-
+-So tomorrow it will full steam ahead to produce a set of diffs/patches against
+-0.91
+-
+-Peter Onion.</PRE>
+<P>In general (there have been some glitches), FreeS/WAN has been
+ running on Alphas since then.</P>
+<H3><A name="SPARC">Sun SPARC processors</A></H3>
+<P>Several users have reported success with FreeS/WAN on SPARC Linux.
+ Here is one mailing list message:</P>
+<PRE>Subject: Smiles on sparc and ppc
+ Date: Fri, 10 Mar 2000
+ From: Jake Hill &lt;jah@alien.bt.co.uk&gt;
+
+You may or may not be interested to know that I have successfully built
+FreeS/WAN on a number of non intel alpha architectures; namely on ppc
+and sparc and also on osfmach3/ppc (MkLinux). I can report that it just
+works, mostly, with few changes.
+
+I have a question, before I make up some patches. I need to hack
+gmp/mpn/powerpc32/*.s to build them. Is this ok? The changes are
+trivial, but could I also use a different version of gmp? Is it vanilla
+here?
+
+I guess my only real headache is from ipchains, which appears to stop
+running when IPsec has been started for a while. This is with 2.2.14 on
+sparc.</PRE>
+<P>This message, from a different mailing list, may be relevant for
+ anyone working with FreeS/WAN on Suns:</P>
+<PRE>Subject: UltraSPARC DES assembler
+ Date: Thu, 13 Apr 2000
+ From: svolaf@inet.uni2.dk (Svend Olaf Mikkelsen)
+ To: coderpunks@toad.com
+
+An UltraSPARC assembler version of the LibDES/SSLeay/OpenSSL des_enc.c
+file is available at http://inet.uni2.dk/~svolaf/des.htm.
+
+This brings DES on UltraSPARC from slower than Pentium at the same
+clock speed to significantly faster.</PRE>
+<H3><A name="mips">MIPS processors</A></H3>
+<P>We know FreeS/WAN runs on at least some MIPS processors because<A href="http://www.lasat.com">
+ Lasat</A> manufacture an IPsec box based on an embedded MIPS running
+ Linux with FreeS/WAN. We have no details.</P>
+<H3><A name="crusoe">Transmeta Crusoe</A></H3>
+<P>The Merilus<A href="http://www.merilus.com/products/fc/index.shtml">
+ Firecard</A>, a Linux firewall on a PCI card, is based on a Crusoe
+ processor and supports FreeS/WAN.</P>
+<H3><A name="coldfire">Motorola Coldfire</A></H3>
+<PRE>Subject: Re: Crypto hardware support
+ Date: Mon, 03 Jul 2000
+ From: Dan DeVault &lt;devault@tampabay.rr.com&gt;
+
+.... I have been running
+uClinux with FreeS/WAN 1.4 on a system built by Moreton Bay (
+http://www.moretonbay.com ) and it was using a Coldfire processor
+and was able to do the Triple DES encryption at just about
+1 mbit / sec rate....... they put a Hi/Fn 7901 hardware encryption
+chip on their board and now their system does over 25 mbit of 3DES
+encryption........ pretty significant increase if you ask me.</PRE>
+<H2><A name="multiprocessor">Multiprocessor machines</A></H2>
+<P>FreeS/WAN is designed to work on SMP (symmetric multi-processing)
+ Linux machines and is regularly tested on dual processor x86 machines.</P>
+<P>We do not know of any testing on multi-processor machines with other
+ CPU architectures or with more than two CPUs. Anyone who does test
+ this, please report results to the<A href="mail.html"> mailing list</A>
+.</P>
+<P>The current design does not make particularly efficient use of
+ multiprocessor machines; some of the kernel work is single-threaded.</P>
+<H2><A name="hardware">Support for crypto hardware</A></H2>
+<P>Supporting hardware cryptography accelerators has not been a high
+ priority for the development team because it raises a number of fairly
+ complex issues:</P>
+<UL>
+<LI>Can you trust the hardware? If it is not Open Source, how do you
+ audit its security? Even if it is, how do you check that the design has
+ no concealed traps?</LI>
+<LI>If an interface is added for such hardware, can that interface be
+ subverted or misused?</LI>
+<LI>Is hardware acceleration actually a performance win? It clearly is
+ in many cases, but on a fast machine it might be better to use the CPU
+ for the encryption than to pay the overheads of moving data to and from
+ a crypto board.</LI>
+<LI>the current KLIPS code does not provide a clean interface for
+ hardware accelerators</LI>
+</UL>
+<P>That said, we have a<A href="#coldfire"> report</A> of FreeS/WAN
+ working with one crypto accelerator and some work is going on to modify
+ KLIPS to create a clean generic interface to such products. See this<A href="http://www.jukie.net/~bart/linux-ipsec/">
+ web page</A> for some of the design discussion.</P>
+<P>More recently, a patch to support some hardware accelerators has been
+ posted:</P>
+<PRE>Subject: [Design] [PATCH] H/W acceleration patch
+ Date: Tue, 18 Sep 2001
+ From: &quot;Martin Gadbois&quot; &lt;martin.gadbois@colubris.com&gt;
+
+Finally!!
+Here's a web site with H/W acceleration patch for FreeS/WAN 1.91, including
+S/W and Hifn 7901 crypto support.
+
+http://sources.colubris.com/
+
+Martin Gadbois</PRE>
+<P>Hardware accelerators could take performance well beyond what
+ FreeS/WAN can do in software (discussed<A href="performance.html"> here</A>
+). Here is some discussion off the IETF IPsec list, October 2001:</P>
+<PRE> ... Currently shipping chips deliver, 600 mbps throughput on a single
+ stream of 3DES IPsec traffic. There are also chips that use multiple
+ cores to do 2.4 gbps. We (Cavium) and others have announced even faster
+ chips. ... Mid 2002 versions will handle at line rate (OC48 and OC192)
+ IPsec and SSL/TLS traffic not only 3DES CBC but also AES and arc4.</PRE>
+<P>The patches to date support chips that have been in production for
+ some time, not the state-of-the-art latest-and-greatest devices
+ described in that post. However, they may still outperform software and
+ they almost certainly reduce CPU overhead.</P>
+<H2><A name="ipv6">IP version 6 (IPng)</A></H2>
+<P>The Internet currently runs on version four of the IP protocols. IPv4
+ is what is in the standard Linux IP stack, and what FreeS/WAN was built
+ for. In IPv4, IPsec is an optional feature.</P>
+<P>The next version of the IP protocol suite is version six, usually
+ abbreviated either as &quot;IPv6&quot; or as &quot;IPng&quot; for &quot;IP: the next
+ generation&quot;. For IPv6, IPsec is a required feature. Any machine doing
+ IPv6 is required to support IPsec, much as any machine doing (any
+ version of) IP is required to support ICMP.</P>
+<P>There is a Linux implementation of IPv6 in Linux kernels 2.2 and
+ above. For details, see the<A href="http://www.cs-ipv6.lancs.ac.uk/ipv6/systems/linux/faq/">
+ FAQ</A>. It does not yet support IPsec. The<A href="http://www.linux-ipv6.org/">
+ USAGI</A> project are also working on IPv6 for Linux.</P>
+<P>FreeS/WAN was originally built for the current standard, IPv4, but we
+ are interested in seeing it work with IPv6. Some progress has been
+ made, and a patched version with IPv6 support is<A href="http://www.ipv6.iabg.de/downloadframe/index.html">
+ available</A>. For more recent information, check the<A href="mail.html">
+ mailing list</A>.</P>
+<H3><A name="v6.back">IPv6 background</A></H3>
+<P>IPv6 has been specified by an IETF<A href="http://www.ietf.org/html.charters/ipngwg-charter.html">
+ working group</A>. The group's page lists over 30 RFCs to date, and
+ many Internet Drafts as well. The overview is<A href="http://www.ietf.org/rfc/rfc2460.txt">
+ RFC 2460</A>. Major features include:</P>
+<UL>
+<LI>expansion of the address space from 32 to 128 bits,</LI>
+<LI>changes to improve support for
+<UL>
+<LI>mobile IP</LI>
+<LI>automatic network configuration</LI>
+<LI>quality of service routing</LI>
+<LI>...</LI>
+</UL>
+</LI>
+<LI>improved security via IPsec</LI>
+</UL>
+<P>A number of projects are working on IPv6 implementation. A prominent
+ Open Source effort is<A href="http://www.kame.net/"> KAME</A>, a
+ collaboration among several large Japanese companies to implement IPv6
+ for Berkeley Unix. Other major players are also working on IPv6. For
+ example, see pages at:</P>
+<UL>
+<LI><A href="http://playground.sun.com/pub/ipng/html/ipng-main.html">Sun</A>
+</LI>
+<LI><A href="http://www.cisco.com/warp/public/732/ipv6/index.html">Cisco</A>
+</LI>
+<LI><A href="http://www.microsoft.com/windows2000/techinfo/howitworks/communications/networkbasics/IPv6.asp">
+Microsoft</A></LI>
+</UL>
+<P>The<A href="http://www.6bone.net/"> 6bone</A> (IPv6 backbone) testbed
+ network has been up for some time. There is an active<A href="http://www.ipv6.org/">
+ IPv6 user group</A>.</P>
+<P>One of the design goals for IPv6 was that it must be possible to
+ convert from v4 to v6 via a gradual transition process. Imagine the
+ mess if there were a &quot;flag day&quot; after which the entire Internet used
+ v6, and all software designed for v4 stopped working. Almost every
+ computer on the planet would need major software changes! There would
+ be huge costs to replace older equipment. Implementers would be worked
+ to death before &quot;the day&quot;, systems administrators and technical support
+ would be completely swamped after it. The bugs in every implementation
+ would all bite simultaneously. Large chunks of the net would almost
+ certainly be down for substantial time periods. ...</P>
+<P>Fortunately, the design avoids any &quot;flag day&quot;. It is therefore a
+ little tricky to tell how quickly IPv6 will take over. The transition
+ has certainly begun. For examples, see announcements from<A href="http://www.mailbase.ac.uk/lists/internet2/2000-03/0016.html">
+ NTT</A> and<A href="http://www.vnunet.com/News/1102383"> Nokia</A>.
+ However, it is not yet clear how quickly the process will gain
+ momentum, or when it will be completed. Likely large parts of the
+ Internet will remain with IPv4 for years to come.</P>
+<HR>
+<A NAME="interop"></A>
+<H1><A NAME="10">Interoperating with FreeS/WAN</A></H1>
+<P>The FreeS/WAN project needs you! We rely on the user community to
+ keep up to date. Mail users@lists.freeswan.org with your interop
+ success stories.</P>
+<P><STRONG>Please note</STRONG>: Most of our interop examples feature
+ Linux FreeS/WAN 1.x config files. You can convert them to 2.x files
+ fairly easily with the patch in our<A HREF="#ipsec.conf_v2"> Upgrading
+ Guide</A>.</P>
+<H2><A NAME="10_1">Interop at a Glance</A></H2>
+<TABLE BORDER="1">
+<TR><TD>&nbsp;</TD><TD colspan="5">FreeS/WAN VPN</TD><TD>Road Warrior</TD><TD>
+OE</TD></TR>
+<TR><TD>&nbsp;</TD><TD>PSK</TD><TD>RSA Secret</TD><TD>X.509
+<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD><TD>
+NAT-Traversal
+<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD><TD>
+Manual
+<BR>Keying</TD><TD>&nbsp;</TD><TD>&nbsp;</TD></TR>
+<TR><TD colspan="8">More Compatible</TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#freeswan">FreeS/WAN</A><A NAME="freeswan.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#isakmpd">isakmpd (OpenBSD)</A><A NAME="isakmpd.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>
+<FONT color="#cc0000">No&nbsp;&nbsp;&nbsp;&nbsp;</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#kame">Kame (FreeBSD,
+<BR> NetBSD, MacOSX)
+<BR> <SMALL>aka racoon</SMALL></A><A NAME="kame.top"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#mcafee">McAfee VPN
+<BR><SMALL>was PGPNet</SMALL></A><A NAME="mcafee.top"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#microsoft">Microsoft
+<BR> Windows 2000/XP</A><A NAME="microsoft.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#ssh">SSH Sentinel</A><A NAME="ssh.top"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT>
+</TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#safenet">Safenet SoftPK
+<BR>/SoftRemote</A><A NAME="safenet.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+<TR><TD colspan="8">Other</TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#6wind">6Wind</A><A NAME="6wind.top"> &nbsp;</A></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+<FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#alcatel">Alcatel Timestep</A><A NAME="alcatel.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#apple">Apple Macintosh
+<BR>System 10+</A><A NAME="apple.top"> &nbsp;</A></TD><TD><FONT color="#cccc00">
+Maybe</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#cccc00">
+Maybe</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#ashleylaurent">AshleyLaurent
+<BR> VPCom</A><A NAME="ashleylaurent.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#borderware">Borderware</A><A NAME="borderware.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+
+<!--
+http://www.cequrux.com/vpn-guides.php3
+"coming soon" guide to connect with FreeS/WAN.
+-->
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#checkpoint">Check Point FW-1/VPN-1</A><A NAME="checkpoint.top">
+ &nbsp;</A></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>
+<FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#cisco">Cisco with 3DES</A><A NAME="cisco.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#cccc00">Maybe</FONT>
+</TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#equinux">Equinux VPN Tracker
+<BR> (for Mac OS X)</A><A NAME="equinux.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#fsecure">F-Secure</A><A NAME="fsecure.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">
+Maybe</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#gauntlet">Gauntlet GVPN</A><A NAME="gauntlet.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#aix">IBM AIX</A><A NAME="aix.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#as400">IBM AS/400</A><A NAME="as400"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#intel">Intel Shiva
+<BR>LANRover/Net Structure</A><A NAME="intel.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#lancom">LanCom (formerly ELSA)</A><A NAME="lancom.top">
+ &nbsp;</A></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#linksys">Linksys</A><A NAME="linksys.top"> &nbsp;</A></TD><TD>
+<FONT color="#cccc00">Maybe</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">
+No</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>
+<FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#lucent">Lucent</A><A NAME="lucent.top"> &nbsp;</A></TD><TD><FONT
+color="#cccc00">Partial</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#netasq">Netasq</A><A NAME="netasq.top"> &nbsp;</A></TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#netcelo">netcelo</A><A NAME="netcelo.top"> &nbsp;</A></TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#netgear">Netgear fvs318</A><A NAME="netgear.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#netscreen">Netscreen 100
+<BR>or 5xp</A><A NAME="netscreen.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">
+Maybe</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#nortel">Nortel Contivity</A><A NAME="nortel.top"> &nbsp;</A>
+</TD><TD><FONT color="#cccc00">Partial</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#radguard">RadGuard</A><A NAME="radguard.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#raptor">Raptor</A><A NAME="raptor"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#redcreek">Redcreek Ravlin</A><A NAME="redcreek.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT><FONT color="#cccc00">/Partial</FONT>
+</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#sonicwall">SonicWall</A><A NAME="sonicwall.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cccc00">Maybe</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD><TD>
+<FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#sun">Sun Solaris</A><A NAME="sun.top"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT>
+</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#symantec">Symantec</A><A NAME="symantec.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#watchguard">Watchguard
+<BR> Firebox</A><A NAME="watchguard.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#xedia">Xedia Access Point
+<BR>/QVPN</A><A NAME="xedia.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#zyxel">Zyxel Zywall
+<BR>/Prestige</A><A NAME="zyxel.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE
+
+
+<TR>
+<TD><A HREF="#sample">sample</A></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+-->
+<TR><TD>&nbsp;</TD><TD>PSK</TD><TD>RSA Secret</TD><TD>X.509
+<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD><TD>
+NAT-Traversal
+<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD><TD>
+Manual
+<BR>Keying</TD><TD>&nbsp;</TD><TD>&nbsp;</TD></TR>
+<TR><TD>&nbsp;</TD><TD colspan="5">FreeS/WAN VPN</TD><TD>Road Warrior</TD><TD>
+OE</TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+</TABLE>
+<H3><A NAME="10_1_1">Key</A></H3>
+<TABLE BORDER="1">
+<TR><TD><FONT color="#00cc00">Yes</FONT></TD><TD>People report that this
+ works for them.</TD></TR>
+<TR><TD>[Blank]</TD><TD>We don't know.</TD></TR>
+<TR><TD><FONT color="#cc0000">No</FONT></TD><TD>We have reason to
+ believe it was, at some point, not possible to get this to work.</TD></TR>
+<TR><TD><FONT color="#cccc00">Partial</FONT></TD><TD>Partial success.
+ For example, a connection can be created from one end only.</TD></TR>
+<TR><TD><FONT color="#00cc00">Yes</FONT><FONT color="#cccc00">/Partial</FONT>
+</TD><TD>Mixed reports.</TD></TR>
+<TR><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>We think the answer
+ is &quot;yes&quot;, but need confirmation.</TD></TR>
+</TABLE>
+<A NAME="interoprules"></A>
+<H2><A NAME="10_2">Basic Interop Rules</A></H2>
+<P>Vanilla FreeS/WAN implements<A HREF="#compat"> these parts</A> of the
+ IPSec specifications. You can add more with<A HREF="http://www.freeswan.ca">
+ Super FreeS/WAN</A>, but what we offer may be enough for many users.</P>
+<UL>
+<LI> To use X.509 certificates with FreeS/WAN, you will need the<A HREF="http://www.strongsec.org/freeswan">
+ X.509 patch</A> or<A HREF="http://www.freeswan.ca"> Super FreeS/WAN</A>
+, which includes that patch.</LI>
+<LI> To use<A HREF="#NAT.gloss"> Network Address Translation</A> (NAT)
+ traversal with FreeS/WAN, you will need Arkoon Network Security's<A HREF="http://open-source.arkoon.net">
+ NAT traversal patch</A> or<A HREF="http://www.freeswan.ca"> Super
+ FreeS/WAN</A>, which includes it.</LI>
+</UL>
+<P>We offer a set of proposals which is not user-adjustable, but covers
+ all combinations that we can offer. FreeS/WAN always proposes triple
+ DES encryption and Perfect Forward Secrecy (PFS). In addition, we
+ propose Diffie Hellman groups 5 and 2 (in that order), and MD5 and
+ SHA-1 hashes. We accept the same proposals, in the same order of
+ preference.</P>
+<P>Other interop notes:</P>
+<UL>
+<LI> A<A HREF="http://lists.freeswan.org/archives/users/2003-September/msg00462.html">
+ SHA-1 bug in FreeS/WAN 2.00, 2.01 and 2.02</A> may affect some interop
+ scenarios. It does not affect 1.x versions, and is fixed in 2.03 and
+ later.</LI>
+<LI> Some other implementations will close a connection with FreeS/WAN
+ after some time. This may be a problem with rekey lifetimes. Please see<A
+HREF="http://lists.freeswan.org/archives/users/2003-October/msg00293.html">
+ this tip</A> and<A HREF="http://lists.freeswan.org/pipermail/users/2001-December/005758.html">
+ this workaround</A>.</LI>
+</UL>
+<H2><A NAME="10_3">Longer Stories</A></H2>
+<H3><A NAME="10_3_1">For<EM> More Compatible</EM> Implementations</A></H3>
+<H4><A NAME="freeswan">FreeS/WAN</A></H4>
+<P> See our documentation at<A HREF="http://www.freeswan.org">
+ freeswan.org</A> and the Super FreeS/WAN docs at<A HREF="http://www.freeswan.ca">
+ freeswan.ca</A>. Some user-written HOWTOs for FreeS/WAN-FreeS/WAN
+ connections are listed in<A HREF="#howto"> our Introduction</A>.</P>
+<P>See also:</P>
+<UL>
+<LI><A HREF="http://lugbe.ch/action/reports/ipsec_htbe.phtml"> A German
+ FreeS/WAN-FreeS/WAN page by Markus Wernig (X.509)</A></LI>
+</UL>
+<P><A HREF="#freeswan.top">Back to chart</A></P>
+<H4><A NAME="isakmpd">isakmpd (OpenBSD)</A></H4>
+<P><A HREF="http://www.openbsd.org/faq/faq13.html">OpenBSD FAQ: Using
+ IPsec</A>
+<BR><A HREF="http://www.rommel.stw.uni-erlangen.de/~hshoexer/ipsec-howto/HOWTO.html">
+ Hans-Joerg Hoexer's interop Linux-OpenBSD (PSK)</A>
+<BR><A HREF="http://www.segfault.net/ipsec/"> Skyper's configuration
+ (PSK)</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A></P>
+<P><A HREF="#isakmpd.top">Back to chart</A></P>
+<H4><A NAME="kame">Kame</A></H4>
+<UL>
+<LI>For FreeBSD and NetBSD. Ships with Mac OS X; see also our<A HREF="#apple">
+ Mac</A> section.</LI>
+<LI>Also known as<EM> racoon</EM>, its keying daemon.</LI>
+</UL>
+<P><A HREF="http://www.kame.net">Kame homepage, with FAQ</A>
+<BR><A HREF="http://www.netbsd.org/Documentation/network/ipsec">
+ NetBSD's IPSec FAQ</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00560.html">
+ Ghislaine's post explaining some interop peculiarities</A></P>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/09/msg00511.html">
+ Itojun's Kame-FreeS/WAN interop tips (PSK)</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2000"> Ghislaine
+ Labouret's French page with links to matching FreeS/WAN and Kame
+ configs (RSA)</A>
+<BR><A HREF="http://lugbe.ch/lostfound/contrib/freebsd_router/"> Markus
+ Wernig's HOWTO (X.509, BSD gateway)</A>
+<BR><A HREF="http://web.morgul.net/~frodo/docs/kame+freeswan_interop.html">
+ Frodo's Kame-FreeS/WAN interop (X.509)</A>
+<BR><A HREF="http://www.wavesec.org/kame.phtml"> Kame as a WAVEsec
+ client.</A></P>
+<P><A HREF="#kame.top">Back to chart</A></P>
+<H4><A NAME="mcafee">PGPNet/McAfee</A></H4>
+<P></P>
+<UL>
+<LI>Now called McAfee VPN Client.</LI>
+<LI>PGPNet also came in a freeware version which did not support subnets</LI>
+<LI>To support dhcp-over-ipsec, you need the X.509 patch, which is
+ included in<A HREF="http://www.freeswan.ca"> Super FreeS/WAN</A>.</LI>
+</UL>
+<P><A HREF="http://www.freeswan.ca/docs/WindowsInterop"> Tim Carr's
+ Windows Interop Guide (X.509)</A>
+<BR><A HREF="http://www.rommel.stw.uni-erlangen.de/~hshoexer/ipsec-howto/HOWTO.html#Interop2">
+ Hans-Joerg Hoexer's Guide for Linux-PGPNet (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/04/msg00339.html">
+ Kai Martius' instructions using RSA Key-Extractor Tool (RSA)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.zengl.net/freeswan/english.html">Christian
+ Zeng's page (RSA)</A> based on Kai's work. English or German.
+<BR><A HREF="http://tirnanog.ls.fi.upm.es/CriptoLab/Biblioteca/InfTech/InfTech_CriptoLab.htm">
+ Oscar Delgado's PDF (X.509, no configs)</A>
+<BR><A HREF="http://www-ec.njit.edu/~rxt1077/Howto.txt"> Ryan's HOWTO
+ for FreeS/WAN-PGPNet (X.509)</A>. Through a Linksys Router with IPsec
+ Passthru enabled.
+<BR><A HREF="http://jixen.tripod.com/#RW-PGP-to-Fwan"> Jean-Francois
+ Nadeau's Practical Configuration (Road Warrior with PSK)</A>
+<BR><A HREF="http://www.evolvedatacom.nl/freeswan.html#toc"> Wouter
+ Prins' HOWTO (Road Warrior with X.509)</A>
+<BR></P>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/01/msg00271.html">
+ Rekeying problem with FreeS/WAN and older PGPNets</A>
+<BR></P>
+<P><A HREF="http://www.strongsec.com/freeswan/dhcprelay/index.htm"> DHCP
+ over IPSEC HOWTO for FreeS/WAN (requires X.509 and dhcprelay patches)</A>
+</P>
+<P><A HREF="#mcafee.top">Back to chart</A></P>
+<H4><A NAME="microsoft">Microsoft Windows 2000/XP</A></H4>
+<UL>
+<LI>IPsec comes with Win2k, and with XP Support Tools. May require<A HREF="http://www.microsoft.com/windows2000/downloads/recommended/encryption/default.asp">
+ High Encryption Pack</A>. WinXP users have also reported better results
+ with Service Pack 1.</LI>
+<LI>The Road Warrior setup works either way round. Windows (XP or 2K)
+ IPsec can connect as a Road Warrior to FreeS/WAN. However, FreeS/WAN
+ can also successfully connect as a Road Warrior to Windows IPsec (see
+ Nate Carlson's configs below).</LI>
+<LI>FreeS/WAN version 1.92 or later is required to avoid an
+ interoperation problem with Windows native IPsec. Earlier FreeS/WAN
+ versions did not process the Commit Bit as Windows native IPsec
+ expected.</LI>
+</UL>
+<P><A HREF="http://www.freeswan.ca/docs/WindowsInterop"> Tim Carr's
+ Windows Interop Guide (X.509)</A>
+<BR><A HREF="http://ipsec.math.ucla.edu/services/ipsec.html"> James
+ Carter's instructions (X.509, NAT-T)</A>
+<BR><A HREF="http://jixen.tripod.com/#Win2000-Fwan"> Jean-Francois
+ Nadeau's Net-net Configuration (PSK)</A>
+<BR><A HREF="http://security.nta.no/freeswan-w2k.html"> Telenor's
+ Node-node Config (Transport-mode PSK)</A>
+<BR><A HREF="http://vpn.ebootis.de"> Marcus Mueller's HOWTO using his
+ VPN config tool (X.509).</A> Tool also works with PSK.
+<BR><A HREF="http://www.natecarlson.com/include/showpage.php?cat=linux&page=ipsec-x509">
+ Nate Carlson's HOWTO using same tool (Road Warrior with X.509)</A>.
+ Unusually, FreeS/WAN is the Road Warrior here.
+<BR><A HREF="http://tirnanog.ls.fi.upm.es/CriptoLab/Biblioteca/InfTech/InfTech_CriptoLab.htm">
+ Oscar Delgado's PDF (X.509, no configs)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2003-July/022425.html">
+ Tim Scannell's Windows XP Additional Checklist (X.509)</A>
+<BR></P>
+
+<!-- Note to self: Include L2TP references? -->
+<P><A HREF="http://www.microsoft.com/windows2000/en/server/help/default.asp?url=/windows2000/en/server/help/sag_TCPIP_ovr_secfeatures.htm">
+ Microsoft's page on Win2k TCP/IP security features</A>
+<BR><A HREF="http://support.microsoft.com/support/kb/articles/Q257/2/25.ASP">
+ Microsoft's Win2k IPsec debugging tips</A>
+<BR>
+<!-- Alt-URL http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257225
+Perhaps newer? -->
+<A HREF="http://www.wired.com/news/technology/0,1282,36336,00.html">
+ MS VPN may fall back to 1DES</A></P>
+<P><A HREF="#microsoft.top">Back to chart</A></P>
+<H4><A NAME="ssh">SSH Sentinel</A></H4>
+<UL>
+<LI>Popular and well tested.</LI>
+<LI>Also rebranded in<A HREF="http://www.zyxel.com"> Zyxel Zywall</A>.
+ Our Zyxel interop notes are<A HREF="#zyxel"> here</A>.</LI>
+<LI> SSH supports IPsec-over-UDP NAT traversal.</LI>
+<LI>There is this<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/12/msg00370.html">
+ potential problem</A> if you're not using the Legacy Proposal option.</LI>
+</UL>
+<P><A HREF="http://www.ssh.com/support/sentinel/documents.cfm"> SSH's
+ Sentinel-FreeSWAN interop PDF (X.509)</A>
+<BR><A HREF="http://www.nadmm.com/show.php?story=articles/vpn.inc">
+ Nadeem Hassan's SUSE-to-Sentinel article (Road warrior with X.509)</A>
+<BR><A HREF="http://www.zerozone.it/documents/Linux/HowTo/VPN-IPsec-Freeswan-HOWTO.html">
+ O-Zone's Italian HOWTO (Road Warrior, X.509, DHCP)</A>
+<BR></P>
+<P><A HREF="#ssh.top">Back to chart</A></P>
+<H4><A NAME="safenet">Safenet SoftPK/SoftRemote</A></H4>
+<UL>
+<LI>People recommend SafeNet as a low cost Windows client.</LI>
+<LI>SoftRemote seems to be the newer name for SoftPK.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005061.html">
+ Whit Blauvelt's SoftRemote tips</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015591.html">
+ Tim Wilson's tips (X.509)</A><A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00607.html">
+ Workaround for a &quot;gotcha&quot;</A></P>
+<P><A HREF="http://jixen.tripod.com/#Rw-IRE-to-Fwan"> Jean-Francois
+ Nadeau's Practical Configuration (Road Warrior with PSK)</A>
+<BR><A HREF="http://www.terradoncommunications.com/security/whitepapers/safe_net-to-free_swan.pdf">
+ Terradon Communications' PDF (Road Warrior with PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/?????.html">
+ Seaan.net's PDF (Road Warrior to Subnet, with PSK)</A>
+<BR><A HREF="http://www.redbaronconsulting.com/freeswan/fswansafenet.pdf">
+ Red Baron Consulting's PDF (Road Warrior with X.509)</A></P>
+<P><A HREF="#safenet.top">Back to chart</A></P>
+<H3><A NAME="10_3_2">For<EM> Other Implementations</EM></A></H3>
+<H4><A NAME="6wind">6Wind</A></H4>
+<P><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A></P>
+<P><A HREF="#6wind.top">Back to chart</A></P>
+<H4><A NAME="alcatel">Alcatel Timestep</A></H4>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-June/011878.html">
+ Alain Sabban's settings (PSK or PSK road warrior; through static NAT)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/1999/06/msg00100.html">
+ Derick Cassidy's configs (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/1999/08/msg00194.html">
+ David Kerry's Timestep settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013711.html">
+ Kevin Gerbracht's ipsec.conf (X.509)</A></P>
+<P><A HREF="#alcatel.top">Back to chart</A></P>
+<H4><A NAME="apple">Apple Macintosh System 10+</A></H4>
+<UL>
+<LI>Since the system is based on FreeBSD, this should interoperate<A HREF="#kame">
+ just like FreeBSD</A>.</LI>
+<LI> To use Appletalk over IPsec tunnels,<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005116.html">
+ run it over TCP/IP</A>, or use Open Door Networks' Shareway IP tool,<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005426.html">
+ described here.</A></LI>
+<LI>See also the<A HREF="#equinux"> Equinux VPN Tracker</A> for Mac OS
+ X.</LI>
+</UL>
+<P><A HREF="http://ipsec.math.ucla.edu/services/ipsec.html"> James
+ Carter's instructions (X.509, NAT-T)</A></P>
+<P><A HREF="#apple.top">Back to chart</A></P>
+<H4><A NAME="ashleylaurent">AshleyLaurent VPCom</A></H4>
+<P><A HREF="http://www.ashleylaurent.com/newsletter/01-28-00.htm">
+ Successful interop report, no details</A></P>
+<P><A HREF="#ashleylaurent.top">Back to chart</A></P>
+<H4><A NAME="borderware">Borderware</A></H4>
+<UL>
+<LI>I suspect the Borderware client is a rebranded Safenet. If that's
+ true, our<A HREF="#safenet"> Safenet section</A> will help.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-March/008288.html">
+ Philip Reetz' configs (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/09/msg00217.html">
+ Borderware server does not support FreeS/WAN road warriors</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007733.html">
+ Older Borderware may not support Diffie Hellman groups 2, 5</A>
+<BR></P>
+<P><A HREF="#borderware.top">Back to chart</A></P>
+<H4><A NAME="checkpoint">Check Point VPN-1 or FW-1</A></H4>
+<UL>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00099.html">
+ Caveat about IP-range inclusion on Check Point.</A></LI>
+<LI> Some versions of Check Point may require an aggressive mode patch
+ to interoperate with FreeS/WAN.
+<BR><A HREF="http://www.freeswan.ca/code/super-freeswan"> Super
+ FreeS/WAN</A> now features this patch.
+<!--
+<A HREF="http://www.freeswan.ca/patches/aggressivemode">Steve Harvey's
+aggressive mode patch for FreeS/WAN 1.5</A>
+-->
+</LI>
+<LI></LI>
+<LI>A Linux FreeS/WAN-Checkpoint connection may close after some time.
+ Try<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00293.html">
+ this tip</A> toward a workaround.</LI>
+</UL>
+<P><A HREF="http://www.fw-1.de/aerasec/ng/vpn-freeswan/CPNG+Linux-FreeSWAN.html">
+ AERAsec's Firewall-1 NG site (PSK, X.509, Road Warrior with X.509,
+ other algorithms)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.fw-1.de/aerasec/ng/vpn-freeswan/CPNG+Linux-FreeSWAN.html#support-matrix">
+ AERAsec's detailed Check Point-FreeS/WAN support matrix</A>
+<BR><A HREF="http://support.checkpoint.com/kb/docs/public/firewall1/4_1/pdf/fw-linuxvpn.pdf">
+ Checkpoint.com PDF: Linux as a VPN Client to FW-1 (PSK)</A>
+<BR><A HREF="http://www.phoneboy.com"> PhoneBoy's Check Point FAQ (on
+ Check Point only, not FreeS/WAN)</A>
+<BR></P>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2001-August/002351.html">
+ Chris Harwell's tips FreeS/WAN configs (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009362.html">
+ Daniel Tombeil's configs (PSK)</A></P>
+<P><A HREF="#checkpoint.top">Back to chart</A></P>
+<H4><A NAME="cisco">Cisco</A></H4>
+<UL>
+<LI> Cisco supports IPsec-over-UDP NAT traversal.</LI>
+<LI>Cisco VPN Client appears to use nonstandard IPsec and does not work
+ with FreeS/WAN.<A HREF="https://mj2.freeswan.org/archives/2003-August/maillist.html">
+ This message</A> concerns Cisco VPN Client 4.01.
+<!-- fix link -->
+</LI>
+<LI>A Linux FreeS/WAN-Cisco connection may close after some time.<A HREF="http://lists.freeswan.org/pipermail/users/2001-December/005758.html">
+ Here</A> is a workaround, and<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00293.html">
+ here</A> is another comment on the same subject.</LI>
+<LI><A HREF="http://www.cisco.com/univercd/cc/td/doc/product/software/ios120/120newft/120t/120t2/3desips.htm">
+Older Ciscos</A> purchased outside the United States may not have 3DES,
+ which FreeS/WAN requires.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2001-June/000406.html">
+RSA keying may not be possible between Cisco and FreeS/WAN.</A></LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2001-October/004357.html">
+In ipsec.conf, VPN3000 DN (distinguished name) must be in binary (X.509
+ only)</A></LI>
+</UL>
+<P><A HREF="http://rr.sans.org/encryption/cisco_router.php"> SANS
+ Institute HOWTO (PSK).</A> Detailed, with extensive references.
+<BR><A HREF="http://www.worldbank.ro/IPSEC/cisco-linux.txt"> Short HOWTO
+ (PSK)</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs for Cisco IOS, PIX and VPN 3000 (X.509)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-August/002966.html">
+ Dave McFerren's sample configs (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-September/003422.html">
+ Wolfgang Tremmel's sample configs (PSK road warrior)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00578.html">
+ Old doc from Pete Davis, with William Watson's updated Tips (PSK)</A>
+<BR></P>
+<P><STRONG>Some PIX specific information:</STRONG>
+<BR><A HREF="http://www.wlug.org.nz/FreeSwanToCiscoPix"> Waikato Linux
+ Users' Group HOWTO. Nice detail (PSK)</A>
+<BR><A HREF="http://www.johnleach.co.uk/documents/freeswan-pix/freeswan-pix.html">
+ John Leach's configs (PSK)</A>
+<BR><A HREF="http://www.diverdown.cc/vpn/freeswanpix.html"> Greg
+ Robinson's settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007901.html">
+ Scott's ipsec.conf for PIX (PSK, FreeS/WAN side only)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-October/003949.html">
+ Rick Trimble's PIX and FreeS/WAN settings (PSK)</A>
+<BR></P>
+<P><A href="http://www.cisco.com/public/support/tac"> Cisco VPN support
+ page</A>
+<BR><A href="http://www.ieng.com/warp/public/707/index.shtml#ipsec">
+ Cisco IPsec information page</A></P>
+<P><A HREF="#cisco.top">Back to chart</A></P>
+<H4><A NAME="equinux">Equinux VPN tracker (for Mac OS X)</A></H4>
+<UL>
+<LI>Graphical configurator for Mac OS X IPsec. May be an interface to
+ the<A HREF="#apple"> native Mac OS X IPsec</A>, which is essentially<A HREF="#kame">
+ KAME</A>.</LI>
+<LI>To use Appletalk over IPsec tunnels,<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005116.html">
+ run it over TCP/IP</A>, or use Open Door Networks' Shareway IP tool,<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005426.html">
+ described here.</A></LI>
+</UL>
+<P> Equinux provides<A HREF="http://www.equinux.com/download/HowTo_FreeSWAN.pdf">
+ this excellent interop PDF</A> (PSK, RSA, X.509).</P>
+<P><A HREF="#equinux.top">Back to chart</A></P>
+<H4><A NAME="fsecure">F-Secure</A></H4>
+<UL>
+<LI>
+<!-- <A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007596.html"> -->
+ F-Secure supports IPsec-over-UDP NAT traversal.</LI>
+</UL>
+<P><A HREF="http://www.pingworks.de/tech/vpn/vpn.txt">pingworks.de's
+ &quot;Connecting F-Secure's VPN+ to Linux FreeS/WAN&quot; (PSK road warrior)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.pingworks.de/tech/vpn/vpn.pdf">Same thing
+ as PDF</A>
+<BR><A HREF="http://www.exim.org/pipermail/linux-ipsec/Week-of-Mon-20010122/000061.html">
+ Success report, no detail (PSK)</A>
+<BR><A HREF="http://www.exim.org/pipermail/linux-ipsec/Week-of-Mon-20010122/000041.html">
+ Success report, no detail (Manual)</A></P>
+
+<!-- Other NAT traversers:
+http://lists.freeswan.org/pipermail/users/2002-April/009136.html
+and ssh sentinel:
+http://lists.freeswan.org/pipermail/users/2001-September/003108.html
+-->
+<P><A HREF="#fsecure.top">Back to chart</A></P>
+<H4><A NAME="gauntlet">Gauntlet GVPN</A></H4>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00535.html">
+ Richard Reiner's ipsec.conf (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-June/011434.html">
+ Might work without that pesky firewall... (PSK)</A>
+<BR>
+<!-- insert archive link -->
+ In late July, 2003 Alexandar Antik reported success interoperating
+ with Gauntlet 6.0 for Solaris (X.509). Unfortunately the message is not
+ properly archived at this time.</P>
+<P><A HREF="#gauntlet.top">Back to chart</A></P>
+<H4><A NAME="aix">IBM AIX</A></H4>
+<P><A HREF="http://www-1.ibm.com/servers/esdd/articles/security.html">
+ IBM's &quot;Built-In Network Security with AIX&quot; (PSK, X.509)</A>
+<BR><A HREF="http://www-1.ibm.com/servers/aix/products/ibmsw/security/vpn/faqandtips/#ques20">
+ IBM's tip: importing Linux FreeS/WAN settings into AIX's<VAR> ikedb</VAR>
+ (PSK)</A></P>
+<P><A HREF="#aix.top">Back to chart</A></P>
+<H4><A NAME="as400">IBM AS/400</A></H4>
+<UL>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009106.html">
+ Road Warriors may act flaky</A>.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-September/014264.html">
+ Richard Welty's tips and tricks</A>
+<BR></P>
+<P><A HREF="#as400.top">Back to chart</A></P>
+<H4><A NAME="intel">Intel Shiva LANRover / Net Structure</A></H4>
+<UL>
+<LI>Intel Shiva LANRover is now known as Intel Net Structure.</LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/01/msg00298.html">
+ Shiva seems to have two modes: IPsec or the proprietary &quot;Shiva Tunnel&quot;.</A>
+ Of course, FreeS/WAN will only create IPsec tunnels.</LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00293.html">
+ AH may not work for Shiva-FreeS/WAN.</A> That's OK, since FreeS/WAN has
+ phased out the use of AH.</LI>
+</UL>
+<P><A HREF="http://snowcrash.tdyc.com/freeswan/"> Snowcrash's configs
+ (PSK)</A>
+<BR><A HREF="http://www.opus1.com/vpn/index.html"> Old configs from an
+ interop (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-October/003831.html">
+ The day Shiva tickled a Pluto bug (PSK)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://lists.freeswan.org/pipermail/users/2001-October/004270.html">
+ Follow up: success!</A></P>
+<P><A HREF="#intel.top">Back to chart</A></P>
+<H4><A NAME="lancom">LanCom (formerly ELSA)</A></H4>
+<UL>
+<LI>This router is popular in Germany.</LI>
+</UL>
+<P> Jakob Curdes successfully created a PSK connection with the LanCom
+ 1612 in August 2003.
+<!-- add ML link when it appears -->
+</P>
+<P><A HREF="#lancom.top">Back to chart</A></P>
+<H4><A NAME="linksys">Linksys</A></H4>
+<UL>
+<LI>Linksys may be used as an IPsec tunnel endpoint,<STRONG> OR</STRONG>
+ as a router in &quot;IPsec passthrough&quot; mode, so that the IPsec tunnel
+ passes through the Linksys.</LI>
+</UL>
+<H5>As tunnel endpoint</H5>
+<P><A HREF="http://www.freeswan.ca/docs/BEFVP41/"> Ken Bantoft's
+ instructions (Road Warrior with PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007814.html">
+ Nate Carlson's caveats</A></P>
+<H5>In IPsec passthrough mode</H5>
+<P><A HREF="http://www-ec.njit.edu/~rxt1077/Howto.txt"> Sample HOWTO
+ through a Linksys Router</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2002/02/msg00114.html">
+ Nadeem Hasan's configs</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2002/02/msg00180.html">
+ Brock Nanson's tips</A>
+<BR></P>
+<P><A HREF="#linksys.top">Back to chart</A></P>
+<H4><A NAME="lucent">Lucent</A></H4>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010976.html">
+ Partial success report; see also the next message in thread</A></P>
+
+<!-- section done -->
+<P><A HREF="#lucent.top">Back to chart</A></P>
+<H4><A NAME="netasq">Netasq</A></H4>
+<P><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A></P>
+
+<!-- section done -->
+<P><A HREF="#netasq.top">Back to chart</A></P>
+<H4><A NAME="netcelo">Netcelo</A></H4>
+<P><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A>
+<!-- section done -->
+</P>
+<P><A HREF="#netcelo.top">Back to chart</A></P>
+<H4><A NAME="netgear">Netgear fvs318</A></H4>
+<UL>
+<LI>With a recent Linux FreeS/WAN, you will require the latest (12/2002)
+ Netgear firmware, which supports Diffie-Hellman (DH) group 2. For
+ security reasons, we phased out DH 1 after Linux FreeS/WAN 1.5.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-June/011833.html">
+ This message</A> reports the incompatibility between Linux FreeS/WAN
+ 1.6+ and Netgear fvs318 without the firmware upgrade.</LI>
+<LI>We believe Linux FreeS/WAN 1.5 and earlier will interoperate with
+ any NetGear firmware.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2003-February/017891.html">
+ John Morris' setup (PSK)</A></P>
+<P><A HREF="#netgear.top">Back to chart</A></P>
+<H4><A NAME="netscreen">Netscreen 100 or 5xp</A></H4>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013409.html">
+ Errol Neal's settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015265.html">
+ Corey Rogers' configs (PSK, no PFS)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013051.html">
+ Jordan Share's configs (PSK, 2 subnets, through static NAT)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/08/msg00404.html">
+ Set src proxy_id to your protected subnet/mask</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with ipsec.conf, Netscreen screen shots (X.509, may need to
+ revert to PSK...)</A></P>
+<P><A HREF="http://archives.neohapsis.com/archives/sf/linux/2001-q2/0123.html">
+ A report of a company using Netscreen with FreeS/WAN on a large scale
+ (FreeS/WAN road warriors?)</A></P>
+<P><A HREF="#netscreen.top">Back to chart</A></P>
+<H4><A NAME="nortel">Nortel Contivity</A></H4>
+<UL>
+<LI> Nortel supports IPsec-over-UDP NAT traversal.</LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00417.html">
+ Some older versions of Contivity and FreeS/WAN will not communicate.</A>
+</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010924.html">
+ FreeS/WAN cannot be used as a &quot;client&quot; to a Nortel Contivity server,
+ but can be used as a branch-office tunnel.</A></LI>
+
+<!-- Probably obsoleted by Ken's post
+<LI>
+(Matthias siebler from old interop)
+At one point you could not configure Nortel-FreeS/WAN tunnels as
+"Client Tunnels" since FreeS/WAN does not support Aggressive Mode.
+Current status of this problem: unknown.
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/004612.html">
+How do we map group and user passwords onto the data that FreeS/WAN wants?
+</A>
+</LI>
+-->
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015455.html">
+ Contivity does not send Distinguished Names in the order FS wants them
+ (X.509).</A></LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/03/msg00137.html">
+ Connections may time out after 30-40 minutes idle.</A></LI>
+</UL>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/03/msg00137.html">
+ JJ Streicher-Bremer's mini HOWTO for old new software. (PSK with two
+ subnets)</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A>. This succeeds using the above
+ X.509 tip.</P>
+
+<!-- I could do more searching but this is a solid start. -->
+<P><A HREF="#nortel.top">Back to chart</A></P>
+<H4><A NAME="radguard">Radguard</A></H4>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/05/msg00009.html">
+ Marko Hausalo's configs (PSK).</A> Note: These do create a connection,
+ as you can see by &quot;IPsec SA established&quot;.
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/???.html">
+ Claudia Schmeing's comments</A></P>
+<P><A HREF="#radguard.top">Back to chart</A></P>
+<H4><A NAME="raptor">Raptor (NT or Solaris)</A></H4>
+<P></P>
+<UL>
+<LI>Now known as Symantec Enterprise Firewall.</LI>
+<LI>The Raptor does not normally come with X.509, but this may be
+ available as an add-on.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010256.html">
+ Raptor requires alphanumberic PSK values, whereas FreeS/WAN uses hex.</A>
+</LI>
+<LI>Raptor's tunnel endpoint may be a host, subnet or group of subnets
+ (see<A HREF="http://lists.freeswan.org/pipermail/design/2001-November/001295.html">
+ this message</A> ). FreeS/WAN cannot handle the group of subnets; you
+ must create separate connections for each in order to interoperate.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010113.html">
+ Some versions of Raptor accept only single DES.</A> According to this
+ German message,<A HREF="http://radawana.cg.tuwien.ac.at/mail-archives/lll/200012/msg00065.html">
+ the Raptor Mobile Client demo offers single DES only.</A></LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-January/006935.html">
+ Peter Mazinger's settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005522.html">
+ Peter Gerland's configs (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/07/msg00597.html">
+ Charles Griebel's configs (PSK).</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-July/012275.html">
+ Lumir Srch's tips (PSK)</A></P>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/05/msg00214.html">
+ John Hardy's configs (Manual)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/01/msg00236.html">
+ Older Raptors want 3DES keys in 3 parts (Manual).</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/06/msg00480.html">
+ Different keys for each direction? (Manual)</A>
+<BR></P>
+<P><A HREF="#raptor.top">Back to chart</A></P>
+<H4><A NAME="redcreek">Redcreek Ravlin</A></H4>
+<UL>
+<LI>Known issue #1: The Ravlin expects a quick mode renegotiation right
+ after every Main Mode negotiation.</LI>
+<LI> Known issue #2: The Ravlin tries to negotiate a zero connection
+ lifetime, which it takes to mean &quot;infinite&quot;.<A HREF="http://www.bear-cave.org.uk/linux/ravlin/">
+ Jim Hague's patch</A> addresses both issues.</LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/03/msg00191.html">
+ Interop works with Ravlin Firmware &gt; 3.33. Includes tips (PSK).</A></LI>
+</UL>
+<P><A HREF="#redcreek.top">Back to chart</A></P>
+<H4><A NAME="sonicwall">SonicWall</A></H4>
+<UL>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2001-June/000998.html">
+ Sonicwall cannot be used for Road Warrior setups</A></LI>
+<LI> At one point,<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/05/msg00217.html">
+ only Sonicwall PRO supported triple DES</A>.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-March/008600.html">
+ Older Sonicwalls (before Nov 2001) feature Diffie Hellman group 1 only</A>
+.</LI>
+</UL>
+<P><A HREF="http://www.xinit.cx/docs/freeswan.html"> Paul Wouters'
+ config (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00073.html">
+ Dilan Arumainathan's configuration (PSK)</A>
+<BR><A HREF="http://www.gravitas.co.uk/vpndebug"> Dariush's setup...
+ only opens one way (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2003-July/022302.html">
+ Andreas Steffen's tips (X.509)</A>
+<BR></P>
+<P><A HREF="#sonicwall.top">Back to chart</A></P>
+<H4><A NAME="sun">Sun Solaris</A></H4>
+<UL>
+<LI> Solaris 8+ has a native (in kernel) IPsec implementation.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010503.html">
+ Solaris does not seem to support tunnel mode, but you can make IP-in-IP
+ tunnels instead, like this.</A></LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2003-June/022216.html">
+ Reports of some successful interops</A> from a fellow @sun.com. See
+ also<A HREF="http://lists.freeswan.org/pipermail/users/2003-July/022247.html">
+ these follow up posts</A>.
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/03/msg00332.html">
+ Aleks Shenkman's configs (Manual in transport mode)</A>
+<BR>
+<!--sparc 64 stuff goes where?-->
+</P>
+<P><A HREF="#solaris.top">Back to chart</A></P>
+<H4><A NAME="symantec">Symantec</A></H4>
+<UL>
+<LI>The Raptor, covered<A HREF="#raptor"> above</A>, is now known as
+ Symantec Enterprise Firewall.</LI>
+<LI>Symantec's &quot;distinguished name&quot; is a KEY_ID. See Andreas Steffen's
+ post, below.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009037.html">
+ Andreas Steffen's configs for Symantec 200R (PSK)</A></P>
+<P><A HREF="#symantec.top">Back to chart</A></P>
+<H4><A NAME="watchguard">Watchguard Firebox</A></H4>
+<UL>
+<LI>Automatic keying works with WatchGuard 5.0+ only.</LI>
+<LI>Seen to interoperate with WatchGuard 1000, II, III; firmware v. 5,
+ 6..</LI>
+<LI>For manual keying, Watchguard's Policy Manager expects SPI numbers
+ and encryption and authentication keys in decimal (not hex).</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-July/012595.html">
+ WatchGuard's HOWTO (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013342.html">
+ Ronald C. Riviera's Settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00179.html">
+ Walter Wickersham's Notes (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015587.html">
+ Max Enders' Configs (Manual)</A></P>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009404.html">
+ Old known issue with auto keying</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00124.html">
+ Tips on key generation and format (Manual)</A>
+<BR></P>
+<P><A HREF="#watchguard.top">Back to chart</A></P>
+<H4><A NAME="xedia">Xedia Access Point/QVPN</A></H4>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/12/msg00520.html">
+ Hybrid IPsec/L2TP connection settings (X.509)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/ipsec/1999/08/msg00140.html">
+ Xedia's LAN-LAN links don't use multiple tunnels</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.sandelman.ottawa.on.ca/ipsec/1999/08/msg00140.html">
+ That explanation, continued</A></P>
+<P><A HREF="#xedia.top">Back to chart</A></P>
+<H4><A NAME="zyxel">Zyxel</A></H4>
+<UL>
+<LI>The Zyxel Zywall is a rebranded SSH Sentinel box. See also our
+ section on<A HREF="#ssh"> SSH</A>.</LI>
+<LI>There seems to be a problem with keeping this connection alive. This
+ is caused at the Zyxel end. See this brief<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00141.html">
+ discussion and solution.</A></LI>
+</UL>
+<P><A HREF="http://www.zyxel.com/support/supportnote/zywall/app/zw_freeswan.htm">
+ Zyxel's Zywall to FreeS/WAN instructions (PSK)</A>
+<BR><A HREF="http://www.zyxel.com/support/supportnote/p652/app/zw_freeswan.htm">
+ Zyxel's Prestige to FreeS/WAN instructions (PSK)</A>. Note: not all
+ Prestige versions include VPN software.
+<BR><A HREF="http://www.lancry.net/techdocs/freeswan-zyxel.txt"> Fabrice
+ Cahen's HOWTO (PSK)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;</P>
+<P><A HREF="#zyxel.top">Back to chart</A></P>
+
+<!-- SAMPLE ENTRY
+
+<H4><A NAME="timestep">Timestep</A></H4>
+
+<P>Text goes here.
+</P>
+
+-->
+<HR>
+<H1><A name="performance">Performance of FreeS/WAN</A></H1>
+ The performance of FreeS/WAN is adequate for most applications.
+<P>In normal operation, the main concern is the overhead for encryption,
+ decryption and authentication of the actual IPsec (<A href="#ESP">ESP</A>
+ and/or<A href="#AH"> AH</A>) data packets. Tunnel setup and rekeying
+ occur so much less frequently than packet processing that, in general,
+ their overheads are not worth worrying about.</P>
+<P>At startup, however, tunnel setup overheads may be significant. If
+ you reboot a gateway and it needs to establish many tunnels, expect
+ some delay. This and other issues for large gateways are discussed<A href="#biggate">
+ below</A>.</P>
+<H2><A name="pub.bench">Published material</A></H2>
+<P>The University of Wales at Aberystwyth has done quite detailed speed
+ tests and put<A href="http://tsc.llwybr.org.uk/public/reports/SWANTIME/">
+ their results</A> on the web.</P>
+<P>Davide Cerri's<A href="http://www.linux.it/~davide/doc/"> thesis (in
+ Italian)</A> includes performance results for FreeS/WAN and for<A href="#TLS">
+ TLS</A>. He posted an<A href="http://lists.freeswan.org/pipermail/users/2001-December/006303.html">
+ English summary</A> on the mailing list.</P>
+<P>Steve Bellovin used one of AT&amp;T Research's FreeS/WAN gateways as his
+ data source for an analysis of the cache sizes required for key
+ swapping in IPsec. Available as<A href="http://www.research.att.com/~smb/talks/key-agility.email.txt">
+ text</A> or<A href="http://www.research.att.com/~smb/talks/key-agility.pdf">
+ PDF slides</A> for a talk on the topic.</P>
+<P>See also the NAI work mentioned in the next section.</P>
+<H2><A name="perf.estimate">Estimating CPU overheads</A></H2>
+<P>We can come up with a formula that roughly relates CPU speed to the
+ rate of IPsec processing possible. It is far from exact, but should be
+ usable as a first approximation.</P>
+<P>An analysis of authentication overheads for high-speed networks,
+ including some tests using FreeS/WAN, is on the<A href="http://www.pgp.com/research/nailabs/cryptographic/adaptive-cryptographic.asp">
+ NAI Labs site</A>. In particular, see figure 3 in this<A href="http://download.nai.com/products/media/pgp/pdf/acsa_final_report.pdf">
+ PDF document</A>. Their estimates of overheads, measured in Pentium II
+ cycles per byte processed are:</P>
+<TABLE align="center" border="1"><TBODY></TBODY>
+<TR><TH></TH><TH>IPsec</TH><TH>authentication</TH><TH>encryption</TH><TH>
+cycles/byte</TH></TR>
+<TR><TD>Linux IP stack alone</TD><TD>no</TD><TD>no</TD><TD>no</TD><TD align="right">
+5</TD></TR>
+<TR><TD>IPsec without crypto</TD><TD>yes</TD><TD>no</TD><TD>no</TD><TD align="right">
+11</TD></TR>
+<TR><TD>IPsec, authentication only</TD><TD>yes</TD><TD>SHA-1</TD><TD>no</TD><TD
+align="right">24</TD></TR>
+<TR><TD>IPsec with encryption</TD><TD>yes</TD><TD>yes</TD><TD>yes</TD><TD
+align="right">not tested</TD></TR>
+</TABLE>
+<P>Overheads for IPsec with encryption were not tested in the NAI work,
+ but Antoon Bosselaers'<A href="http://www.esat.kuleuven.ac.be/~bosselae/fast.html">
+ web page</A> gives cost for his optimised Triple DES implementation as
+ 928 Pentium cycles per block, or 116 per byte. Adding that to the 24
+ above, we get 140 cycles per byte for IPsec with encryption.</P>
+<P>At 140 cycles per byte, a 140 MHz machine can handle a megabyte -- 8
+ megabits -- per second. Speeds for other machines will be proportional
+ to this. To saturate a link with capacity C megabits per second, you
+ need a machine running at<VAR> C * 140/8 = C * 17.5</VAR> MHz.</P>
+<P>However, that estimate is not precise. It ignores the differences
+ between:</P>
+<UL>
+<LI>NAI's test packets and real traffic</LI>
+<LI>NAI's Pentium II cycles, Bosselaers' Pentium cycles, and your
+ machine's cycles</LI>
+<LI>different 3DES implementations</LI>
+<LI>SHA-1 and MD5</LI>
+</UL>
+<P>and does not account for some overheads you will almost certainly
+ have:</P>
+<UL>
+<LI>communication on the client-side interface</LI>
+<LI>switching between multiple tunnels -- re-keying, cache reloading and
+ so on</LI>
+</UL>
+<P>so we suggest using<VAR> C * 25</VAR> to get an estimate with a bit
+ of a built-in safety factor.</P>
+<P>This covers only IP and IPsec processing. If you have other loads on
+ your gateway -- for example if it is also working as a firewall -- then
+ you will need to add your own safety factor atop that.</P>
+<P>This estimate matches empirical data reasonably well. For example,
+ Metheringham's tests, described<A href="#klips.bench"> below</A>, show
+ a 733 topping out between 32 and 36 Mbit/second, pushing data as fast
+ as it can down a 100 Mbit link. Our formula suggests you need at least
+ an 800 to handle a fully loaded 32 Mbit link. The two results are
+ consistent.</P>
+<P>Some examples using this estimation method:</P>
+<TABLE align="center" border="1"><TBODY></TBODY>
+<TR><TH colspan="2">Interface</TH><TH colspan="3">Machine speed in MHz</TH>
+</TR>
+<TR><TH>Type</TH><TH>Mbit per
+<BR> second</TH><TH>Estimate
+<BR> Mbit*25</TH><TH>Minimum IPSEC gateway</TH><TH>Minimum with other
+ load
+<P>(e.g. firewall)</P>
+</TH></TR>
+<TR><TD>DSL</TD><TD align="right">1</TD><TD align="right">25 MHz</TD><TD rowspan="2">
+whatever you have</TD><TD rowspan="2">133, or better if you have it</TD></TR>
+<TR><TD>cable modem</TD><TD align="right">3</TD><TD align="right">75 MHz</TD>
+</TR>
+<TR><TD><STRONG>any link, light load</STRONG></TD><TD align="right"><STRONG>
+5</STRONG></TD><TD align="right">125 MHz</TD><TD>133</TD><TD>200+,<STRONG>
+ almost any surplus machine</STRONG></TD></TR>
+<TR><TD>Ethernet</TD><TD align="right">10</TD><TD align="right">250 MHz</TD><TD>
+surplus 266 or 300</TD><TD>500+</TD></TR>
+<TR><TD><STRONG>fast link, moderate load</STRONG></TD><TD align="right"><STRONG>
+20</STRONG></TD><TD align="right">500 MHz</TD><TD>500</TD><TD>800+,<STRONG>
+ any current off-the-shelf PC</STRONG></TD></TR>
+<TR><TD>T3 or E3</TD><TD align="right">45</TD><TD align="right">1125 MHz</TD><TD>
+1200</TD><TD>1500+</TD></TR>
+<TR><TD>fast Ethernet</TD><TD align="right">100</TD><TD align="right">
+2500 MHz</TD><TD align="center" colspan="2" rowspan="2">// not feasible
+ with 3DES in software on current machines //</TD></TR>
+<TR><TD>OC3</TD><TD align="right">155</TD><TD align="right">3875 MHz</TD>
+</TR>
+</TABLE>
+<P>Such an estimate is far from exact, but should be usable as minimum
+ requirement for planning. The key observations are:</P>
+<UL>
+<LI>older<STRONG> surplus machines</STRONG> are fine for IPsec gateways
+ at loads up to<STRONG> 5 megabits per second</STRONG> or so</LI>
+<LI>a<STRONG> mid-range new machine</STRONG> can handle IPsec at rates
+ up to<STRONG> 20 megabits per second</STRONG> or more</LI>
+</UL>
+<H3><A name="perf.more">Higher performance alternatives</A></H3>
+<P><A href="#AES">AES</A> is a new US government block cipher standard,
+ designed to replace the obsolete<A href="#DES"> DES</A>. If FreeS/WAN
+ using<A href="#3DES"> 3DES</A> is not fast enough for your application,
+ the AES<A href="#patch"> patch</A> may help.</P>
+<P>To date (March 2002) we have had only one<A href="http://lists.freeswan.org/pipermail/users/2002-February/007771.html">
+ mailing list report</A> of measurements with the patch applied. It
+ indicates that, at least for the tested load on that user's network,<STRONG>
+ AES roughly doubles IPsec throughput</STRONG>. If further testing
+ confirms this, it may prove possible to saturate an OC3 link in
+ software on a high-end box.</P>
+<P>Also, some work is being done toward support of<A href="#hardware">
+ hardware IPsec acceleration</A> which might extend the range of
+ requirements FreeS/WAN could meet.</P>
+<H3><A NAME="11_2_2">Other considerations</A></H3>
+<P>CPU speed may be the main issue for IPsec performance, but of course
+ it isn't the only one.</P>
+<P>You need good ethernet cards or other network interface hardware to
+ get the best performance. See this<A href="http://www.ethermanage.com/ethernet/ethernet.html">
+ ethernet information</A> page and this<A href="http://www.scyld.com/diag">
+ Linux network driver</A> page.</P>
+<P>The current FreeS/WAN kernel code is largely single-threaded. It is
+ SMP safe, and will run just fine on a multiprocessor machine (<A href="#multiprocessor">
+discussion</A>), but the load within the kernel is not shared
+ effectively. This means that, for example to saturate a T3 -- which
+ needs about a 1200 MHz machine -- you cannot expect something like a
+ dual 800 to do the job.</P>
+<P>On the other hand, SMP machines do tend to share loads well so --
+ provided one CPU is fast enough for the IPsec work -- a multiprocessor
+ machine may be ideal for a gateway with a mixed load.</P>
+<H2><A name="biggate">Many tunnels from a single gateway</A></H2>
+<P>FreeS/WAN allows a single gateway machine to build tunnels to many
+ others. There may, however, be some problems for large numbers as
+ indicated in this message from the mailing list:</P>
+<PRE>Subject: Re: Maximum number of ipsec tunnels?
+ Date: Tue, 18 Apr 2000
+ From: &quot;John S. Denker&quot; &lt;jsd@research.att.com&gt;
+
+Christopher Ferris wrote:
+
+&gt;&gt; What are the maximum number ipsec tunnels FreeS/WAN can handle??
+
+Henry Spencer wrote:
+
+&gt;There is no particular limit. Some of the setup procedures currently
+&gt;scale poorly to large numbers of connections, but there are (clumsy)
+&gt;workarounds for that now, and proper fixes are coming.
+
+1) &quot;Large&quot; numbers means anything over 50 or so. I routinely run boxes
+with about 200 tunnels. Once you get more than 50 or so, you need to worry
+about several scalability issues:
+
+a) You need to put a &quot;-&quot; sign in syslogd.conf, and rotate the logs daily
+not weekly.
+
+b) Processor load per tunnel is small unless the tunnel is not up, in which
+case a new half-key gets generated every 90 seconds, which can add up if
+you've got a lot of down tunnels.
+
+c) There's other bits of lore you need when running a large number of
+tunnels. For instance, systematically keeping the .conf file free of
+conflicts requires tools that aren't shipped with the standard freeswan
+package.
+
+d) The pluto startup behavior is quadratic. With 200 tunnels, this eats up
+several minutes at every restart. I'm told fixes are coming soon.
+
+2) Other than item (1b), the CPU load depends mainly on the size of the
+pipe attached, not on the number of tunnels.
+</PRE>
+<P>It is worth noting that item (1b) applies only to repeated attempts
+ to re-key a data connection (IPsec SA, Phase 2) over an established
+ keying connection (ISAKMP SA, Phase 1). There are two ways to reduce
+ this overhead using settings in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>:</P>
+<UL>
+<LI>set<VAR> keyingtries</VAR> to some small value to limit repetitions</LI>
+<LI>set<VAR> keylife</VAR> to a short time so that a failing data
+ connection will be cleaned up when the keying connection is reset.</LI>
+</UL>
+<P>The overheads for establishing keying connections (ISAKMP SAs, Phase
+ 1) are lower because for these Pluto does not perform expensive
+ operations before receiving a reply from the peer.</P>
+<P>A gateway that does a lot of rekeying -- many tunnels and/or low
+ settings for tunnel lifetimes -- will also need a lot of<A href="#random">
+ random numbers</A> from the random(4) driver.</P>
+<H2><A name="low-end">Low-end systems</A></H2>
+<P><EM>Even a 486 can handle a T1 line</EM>, according to this mailing
+ list message:</P>
+<PRE>Subject: Re: linux-ipsec: IPSec Masquerade
+ Date: Fri, 15 Jan 1999 11:13:22 -0500
+ From: Michael Richardson
+
+. . . A 486/66 has been clocked by Phil Karn to do
+10Mb/s encryption.. that uses all the CPU, so half that to get some CPU,
+and you have 5Mb/s. 1/3 that for 3DES and you get 1.6Mb/s....</PRE>
+<P>and a piece of mail from project technical lead Henry Spencer:</P>
+<PRE>Oh yes, and a new timing point for Sandy's docs... A P60 -- yes, a 60MHz
+Pentium, talk about antiques -- running a host-to-host tunnel to another
+machine shows an FTP throughput (that is, end-to-end results with a real
+protocol) of slightly over 5Mbit/s either way. (The other machine is much
+faster, the network is 100Mbps, and the ether cards are good ones... so
+the P60 is pretty definitely the bottleneck.)</PRE>
+<P>From the above, and from general user experience as reported on the
+ list, it seems clear that a cheap surplus machine -- a reasonable 486,
+ a minimal Pentium box, a Sparc 5, ... -- can easily handle a home
+ office or a small company connection using any of:</P>
+<UL>
+<LI>ADSL service</LI>
+<LI>cable modem</LI>
+<LI>T1</LI>
+<LI>E1</LI>
+</UL>
+<P>If available, we suggest using a Pentium 133 or better. This should
+ ensure that, even under maximum load, IPsec will use less than half the
+ CPU cycles. You then have enough left for other things you may want on
+ your gateway -- firewalling, web caching, DNS and such.</P>
+<H2><A name="klips.bench">Measuring KLIPS</A></H2>
+<P>Here is some additional data from the mailing list.</P>
+<PRE>Subject: FreeSWAN (specically KLIPS) performance measurements
+ Date: Thu, 01 Feb 2001
+ From: Nigel Metheringham &lt;Nigel.Metheringham@intechnology.co.uk&gt;
+
+I've spent a happy morning attempting performance tests against KLIPS
+(this is due to me not being able to work out the CPU usage of KLIPS so
+resorting to the crude measurements of maximum throughput to give a
+baseline to work out loading of a box).
+
+Measurements were done using a set of 4 boxes arranged in a line, each
+connected to the next by 100Mbit duplex ethernet. The inner 2 had an
+ipsec tunnel between them (shared secret, but I was doing measurements
+when the tunnel was up and running - keying should not be an issue
+here). The outer pair of boxes were traffic generators or traffic sink.
+
+The crypt boxes are Compaq DL380s - Uniprocessor PIII/733 with 256K
+cache. They have 128M main memory. Nothing significant was running on
+the boxes other than freeswan. The kernel was a 2.2.19pre7 patched
+with freeswan and ext3.
+
+Without an ipsec tunnel in the chain (ie the 2 inner boxes just being
+100BaseT routers), throughput (measured with ttcp) was between 10644
+and 11320 KB/sec
+
+With an ipsec tunnel in place, throughput was between 3268 and 3402
+KB/sec
+
+These measurements are for data pushed across a TCP link, so the
+traffic on the wire between the 2 ipsec boxes would have been higher
+than this....
+
+vmstat (run during some other tests, so not affecting those figures) on
+the encrypting box shows approx 50% system &amp; 50% idle CPU - which I
+don't believe at all. Interactive feel of the box was significantly
+sluggish.
+
+I also tried running the kernel profiler (see man readprofile) during
+test runs.
+
+A box doing primarily decrypt work showed basically nothing happening -
+I assume interrupts were off.
+A box doing encrypt work showed the following:-
+ Ticks Function Load
+ ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~
+ 956 total 0.0010
+ 532 des_encrypt2 0.1330
+ 110 MD5Transform 0.0443
+ 97 kmalloc 0.1880
+ 39 des_encrypt3 0.1336
+ 23 speedo_interrupt 0.0298
+ 14 skb_copy_expand 0.0250
+ 13 ipsec_tunnel_start_xmit 0.0009
+ 13 Decode 0.1625
+ 11 handle_IRQ_event 0.1019
+ 11 .des_ncbc_encrypt_end 0.0229
+ 10 speedo_start_xmit 0.0188
+ 9 satoa 0.0225
+ 8 kfree 0.0118
+ 8 ip_fragment 0.0121
+ 7 ultoa 0.0365
+ 5 speedo_rx 0.0071
+ 5 .des_encrypt2_end 5.0000
+ 4 _stext 0.0140
+ 4 ip_fw_check 0.0035
+ 2 rj_match 0.0034
+ 2 ipfw_output_check 0.0200
+ 2 inet_addr_type 0.0156
+ 2 eth_copy_and_sum 0.0139
+ 2 dev_get 0.0294
+ 2 addrtoa 0.0143
+ 1 speedo_tx_buffer_gc 0.0024
+ 1 speedo_refill_rx_buf 0.0022
+ 1 restore_all 0.0667
+ 1 number 0.0020
+ 1 net_bh 0.0021
+ 1 neigh_connected_output 0.0076
+ 1 MD5Final 0.0083
+ 1 kmem_cache_free 0.0016
+ 1 kmem_cache_alloc 0.0022
+ 1 __kfree_skb 0.0060
+ 1 ipsec_rcv 0.0001
+ 1 ip_rcv 0.0014
+ 1 ip_options_fragment 0.0071
+ 1 ip_local_deliver 0.0023
+ 1 ipfw_forward_check 0.0139
+ 1 ip_forward 0.0011
+ 1 eth_header 0.0040
+ 1 .des_encrypt3_end 0.0833
+ 1 des_decrypt3 0.0034
+ 1 csum_partial_copy_generic 0.0045
+ 1 call_out_firewall 0.0125
+
+Hope this data is helpful to someone... however the lack of visibility
+into the decrypt side makes things less clear</PRE>
+<H2><A name="speed.compress">Speed with compression</A></H2>
+<P>Another user reported some results for connections with and without
+ IP compression:</P>
+<PRE>Subject: [Users] Speed with compression
+ Date: Fri, 29 Jun 2001
+ From: John McMonagle &lt;johnm@advocap.org&gt;
+
+Did a couple tests with compression using the new 1.91 freeswan.
+
+Running between 2 sites with cable modems. Both using approximately
+130 mhz pentium.
+
+Transferred files with ncftp.
+
+Compressed file was a 6mb compressed installation file.
+Non compressed was 18mb /var/lib/rpm/packages.rpm
+
+ Compressed vpn regular vpn
+Compress file 42.59 kBs 42.08 kBs
+regular file 110.84 kBs 41.66 kBs
+
+Load was about 0 either way.
+Ping times were very similar a bit above 9 ms.
+
+Compression looks attractive to me.</PRE>
+ Later in the same thread, project technical lead Henry Spencer added:
+<PRE>&gt; is there a reason not to switch compression on? I have large gateway boxes
+&gt; connecting 3 connections, one of them with a measly DS1 link...
+
+Run some timing tests with and without, with data and loads representative
+of what you expect in production. That's the definitive way to decide.
+If compression is a net loss, then obviously, leave it turned off. If it
+doesn't make much difference, leave it off for simplicity and hence
+robustness. If there's a substantial gain, by all means turn it on.
+
+If both ends support compression and can successfully negotiate a
+compressed connection (trivially true if both are FreeS/WAN 1.91), then
+the crucial question is CPU cycles.
+
+Compression has some overhead, so one question is whether *your* data
+compresses well enough to save you more CPU cycles (by reducing the volume
+of data going through CPU-intensive encryption/decryption) than it costs
+you. Last time I ran such tests on data that was reasonably compressible
+but not deliberately contrived to be so, this generally was not true --
+compression cost extra CPU cycles -- so compression was worthwhile only if
+the link, not the CPU, was the bottleneck. However, that was before the
+slow-compression bug was fixed. I haven't had a chance to re-run those
+tests yet, but it sounds like I'd probably see a different result. </PRE>
+ The bug he refers to was a problem with the compression libraries that
+ had us using C code, rather than assembler, for compression. It was
+ fixed before 1.91.
+<H2><A name="methods">Methods of measuring</A></H2>
+<P>If you want to measure the loads FreeS/WAN puts on a system, note
+ that tools such as top or measurements such as load average are
+ more-or-less useless for this. They are not designed to measure
+ something that does most of its work inside the kernel.</P>
+<P>Here is a message from FreeS/WAN kernel programmer Richard Guy Briggs
+ on this:</P>
+<PRE>&gt; I have a batch of boxes doing Freeswan stuff.
+&gt; I want to measure the CPU loading of the Freeswan tunnels, but am
+&gt; having trouble seeing how I get some figures out...
+&gt;
+&gt; - Keying etc is in userspace so will show up on the per-process
+&gt; and load average etc (ie pluto's load)
+
+Correct.
+
+&gt; - KLIPS is in the kernel space, and does not show up in load average
+&gt; I think also that the KLIPS per-packet processing stuff is running
+&gt; as part of an interrupt handler so it does not show up in the
+&gt; /proc/stat system_cpu or even idle_cpu figures
+
+It is not running in interrupt handler. It is in the bottom half.
+This is somewhere between user context (careful, this is not
+userspace!) and hardware interrupt context.
+
+&gt; Is this correct, and is there any means of instrumenting how much the
+&gt; cpu is being loaded - I don't like the idea of a system running out of
+&gt; steam whilst still showing 100% idle CPU :-)
+
+vmstat seems to do a fairly good job, but use a running tally to get a
+good idea. A one-off call to vmstat gives different numbers than a
+running stat. To do this, put an interval on your vmstat command
+line.</PRE>
+ and another suggestion from the same thread:
+<PRE>Subject: Re: Measuring the CPU usage of Freeswan
+ Date: Mon, 29 Jan 2001
+ From: Patrick Michael Kane &lt;modus@pr.es.to&gt;
+
+The only truly accurate way to accurately track FreeSWAN CPU usage is to use
+a CPU soaker. You run it on an unloaded system as a benchmark, then start up
+FreeSWAN and take the difference to determine how much FreeSWAN is eating.
+I believe someone has done this in the past, so you may find something in
+the FreeSWAN archives. If not, someone recently posted a URL to a CPU
+soaker benchmark tool on linux-kernel.</PRE>
+<HR>
+<H1><A name="test.freeswan">Testing FreeS/WAN</A></H1>
+ This document discusses testing FreeS/WAN.
+<P>Not all types of testing are described here. Other parts of the
+ documentation describe some tests:</P>
+<DL>
+<DT><A href="#testinstall">installation</A> document</DT>
+<DD>testing for a successful install</DD>
+<DT><A href="config.html#testsetup">configuration</A> document</DT>
+<DD>basic tests for a working configuration</DD>
+<DT><A href="#interop.web">web links</A> document</DT>
+<DD>General information on tests for interoperability between various
+ IPsec implementations. This includes links to several test sites.</DD>
+<DT><A href="interop.html">interoperation</A> document.</DT>
+<DD>More specific information on FreeS/WAN interoperation with other
+ implementations.</DD>
+<DT><A href="performance.html">performance</A> document</DT>
+<DD>performance measurements</DD>
+</DL>
+<P>The test setups and procedures described here can also be used in
+ other testing, but this document focuses on testing the IPsec
+ functionality of FreeS/WAN.</P>
+<H2><A NAME="test.oe">Testing opportunistic connections</A></H2>
+<P>This section teaches you how to test your opportunistically encrypted
+ (OE) connections. To set up OE, please see the easy instructions in our<A
+HREF="quickstart.html"> quickstart guide</A>.</P>
+<H3><A NAME="12_1_1">Basic OE Test</A></H3>
+<P>This test is for basic OE functionality.
+<!-- You may use it on an
+<A HREF="quickstart.html#oppo.client">initiate-only OE</A> box or a
+<A HREF="quickstart.html#opp.incoming">full OE</A> box. -->
+ For additional tests, keep
+ reading.</P>
+<P>Be sure IPsec is running. You can see whether it is with:</P>
+<PRE> ipsec setup status</PRE>
+<P>If need be, you can restart it with:</P>
+<PRE> service ipsec restart</PRE>
+<P>Load a FreeS/WAN test website from the host on which you're running
+ FreeS/WAN. Note: the feds may be watching these sites. Type one of:</P>
+<P></P>
+<PRE> links oetest.freeswan.org</PRE>
+<PRE> links oetest.freeswan.nl</PRE>
+
+<!--<PRE> links oetest.freeswan.ca</PRE>-->
+<P>A positive result looks like this:</P>
+<PRE>
+ You seem to be connecting from: 192.0.2.11 which DNS says is:
+ gateway.example.com
+ _________________________________________________________________
+
+ Status E-route
+ OE enabled 16 192.139.46.73/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x2097@192.0.2.11
+ OE enabled 176 192.139.46.77/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x208a@192.0.2.11
+</PRE>
+<P>If you see this, congratulations! Your OE box will now encrypt its
+ own traffic whenever it can. If you have difficulty, see our<A HREF="#oe.trouble">
+ OE troubleshooting tips</A>.</P>
+<H3><A NAME="12_1_2">OE Gateway Test</A></H3>
+<P>If you've set up FreeS/WAN to protect a subnet behind your gateway,
+ you'll need to run another simple test, which can be done from a
+ machine running any OS. That's right, your Windows box can be protected
+ by opportunistic encryption without any FreeS/WAN install or
+ configuration on that box. From<STRONG> each protected subnet node</STRONG>
+, load the FreeS/WAN website with:</P>
+<PRE> links oetest.freeswan.org</PRE>
+<PRE> links oetest.freeswan.nl</PRE>
+<P>A positive result looks like this:</P>
+<PRE>
+ You seem to be connecting from: 192.0.2.98 which DNS says is:
+ box98.example.com
+ _________________________________________________________________
+
+ Status E-route
+ OE enabled 16 192.139.46.73/32 -&gt; 192.0.2.98/32 =&gt;
+ tun0x134ed@192.0.2.11
+ OE enabled 176 192.139.46.77/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x134d2@192.0.2.11
+</PRE>
+<P>If you see this, congratulations! Your OE gateway will now encrypt
+ traffic for this subnet node whenever it can. If you have difficulty,
+ see our<A HREF="#oe.trouble"> OE troubleshooting tips</A>.</P>
+<H3><A NAME="12_1_3">Additional OE tests</A></H3>
+<P>When testing OE, you will often find it useful to execute this
+ command on the FreeS/WAN host:</P>
+<PRE> ipsec eroute</PRE>
+<P>If you have established a connection (either for or for a subnet
+ node) you will see a result like:</P>
+<PRE> 192.0.2.11/32 -&gt; 192.139.46.73/32 =&gt; tun0x149f@192.139.46.38
+</PRE>
+<P>Key:</P>
+<TABLE>
+<TR><TD>1.</TD><TD>192.0.2.11/32</TD><TD>Local start point of the
+ protected traffic.</TD></TR>
+<TR><TD>2.</TD><TD>192.0.2.194/32</TD><TD>Remote end point of the
+ protected traffic.</TD></TR>
+<TR><TD>3.</TD><TD>192.0.48.38</TD><TD>Remote FreeS/WAN node (gateway or
+ host). May be the same as (2).</TD></TR>
+<TR><TD>4.</TD><TD>[not shown]</TD><TD>Local FreeS/WAN node (gateway or
+ host), where you've produced the output. May be the same as (1).</TD></TR>
+</TABLE>
+<P>For extra assurance, you may wish to use a packet sniffer such as<A HREF="http://www.tcpdump.org">
+ tcpdump</A> to verify that packets are being encrypted. You should see
+ output that indicates<STRONG> ESP</STRONG> encrypted data, for example:</P>
+<PRE> 02:17:47.353750 PPPoE [ses 0x1e12] IP 154: xy.example.com &gt; oetest.freeswan.org: ESP(spi=0x87150d16,seq=0x55)</PRE>
+<H2><A name="test.uml">Testing with User Mode Linux</A></H2>
+<P><A href="http://user-mode-linux.sourceforge.net/">User Mode Linux</A>
+ allows you to run Linux as a user process on another Linux machine.</P>
+<P>As of 1.92, the distribution has a new directory named testing. It
+ contains a collection of test scripts and sample configurations. Using
+ these, you can bring up several copies of Linux in user mode and have
+ them build tunnels to each other. This lets you do some testing of a
+ FreeS/WAN configuration on a single machine.</P>
+<P>You need a moderately well-endowed machine for this to work well.
+ Each UML wants about 16 megs of memory by default, which is plenty for
+ FreeS/WAN usage. Typical regression testing only occasionally uses as
+ many as 4 UMLs. If one is doing nothing else with the machine (in
+ particular, not running X on it), then 128 megs and a 500MHz CPU are
+ fine.</P>
+ Documentation on these scripts is<A href="umltesting.html"> here</A>.
+ There is also documentation on automated testing<A href="makecheck.html">
+ here</A>.
+<H2><A name="testnet">Configuration for a testbed network</A></H2>
+<P>A common test setup is to put a machine with dual Ethernet cards in
+ between two gateways under test. You need at least five machines; two
+ gateways, two clients and a testing machine in the middle.</P>
+<P>The central machine both routes packets and provides a place to run
+ diagnostic software for checking IPsec packets. See next section for
+ discussion of<A href="#tcpdump.faq"> using tcpdump(8)</A> for this.</P>
+<P>This makes things more complicated than if you just connected the two
+ gateway machines directly to each other, but it also makes your test
+ setup much more like the environment you actually use IPsec in. Those
+ environments nearly always involve routing, and quite a few apparent
+ IPsec failures turn out to be problems with routing or with firewalls
+ dropping packets. This approach lets you deal with those problems on
+ your test setup.</P>
+<P>What you end up with looks like:</P>
+<H3><A name="testbed">Testbed network</A></H3>
+<PRE> subnet a.b.c.0/24
+ |
+ eth1 = a.b.c.1
+ gate1
+ eth0 = 192.168.p.1
+ |
+ |
+ eth0 = 192.168.p.2
+ route/monitor box
+ eth1 = 192.168.q.2
+ |
+ |
+ eth0 = 192.168.q.1
+ gate2
+ eth1 = x.y.z.1
+ |
+ subnet x.y.z.0/24</PRE>
+<PRE>Where p and q are any convenient values that do not interfere with other
+routes you may have. The ipsec.conf(5) file then has, among other things:</PRE>
+<PRE>conn abc-xyz
+ left=192.168.p.1
+ leftnexthop=192.168.p.2
+ right=192.168.q.1
+ rightnexthop=192.168.q.2</PRE>
+<P>Once that works, you can remove the &quot;route/monitor box&quot;, and connect
+ the two gateways to the Internet. The only parameters in ipsec.conf(5)
+ that need to change are the four shown above. You replace them with
+ values appropriate for your Internet connection, and change the eth0 IP
+ addresses and the default routes on both gateways.</P>
+<P>Note that nothing on either subnet needs to change. This lets you
+ test most of your IPsec setup before connecting to the insecure
+ Internet.</P>
+<H3><A name="tcpdump.test">Using packet sniffers in testing</A></H3>
+<P>A number of tools are available for looking at packets. We will
+ discuss using<A href="http://www.tcpdump.org/"> tcpdump(8)</A>, a
+ common Linux tool included in most distributions. Alternatives
+ offerring more-or-less the same functionality include:</P>
+<DL>
+<DT><A href="http://www.ethereal.com">Ethereal</A></DT>
+<DD>Several people on our mailing list report a preference for this over
+ tcpdump.</DD>
+<DT><A href="http://netgroup-serv.polito.it/windump/">windump</A></DT>
+<DD>a Windows version of tcpdump(8), possibly handy if you have Windows
+ boxes in your network</DD>
+<DT><A href="http://reptile.rug.ac.be/~coder/sniffit/sniffit.html">
+Sniffit</A></DT>
+<DD>A linux sniffer that we don't know much about. If you use it, please
+ comment on our mailing list.</DD>
+</DL>
+<P>See also this<A href="http://www.tlsecurity.net/unix/ids/sniffer/">
+ index</A> of packet sniffers.</P>
+<P>tcpdump(8) may misbehave if run on the gateways themselves. It is
+ designed to look into a normal IP stack and may become confused if you
+ ask it to display data from a stack which has IPsec in play.</P>
+<P>At one point, the problem was quite severe. Recent versions of
+ tcpdump, however, understand IPsec well enough to be usable on a
+ gateway. You can get the latest version from<A href="http://www.tcpdump.org/">
+ tcpdump.org</A>.</P>
+<P>Even with a recent tcpdump, some care is required. Here is part of a
+ post from Henry on the topic:</P>
+<PRE>&gt; a) data from sunset to sunrise or the other way is not being
+&gt; encrypted (I am using tcpdump (ver. 3.4) -x/ping -p to check
+&gt; packages)
+
+What *interface* is tcpdump being applied to? Use the -i option to
+control this. It matters! If tcpdump is looking at the ipsecN
+interfaces, e.g. ipsec0, then it is seeing the packets before they are
+encrypted or after they are decrypted, so of course they don't look
+encrypted. You want to have tcpdump looking at the actual hardware
+interfaces, e.g. eth0.
+
+Actually, the only way to be *sure* what you are sending on the wire is to
+have a separate machine eavesdropping on the traffic. Nothing you can do
+on the machines actually running IPsec is 100% guaranteed reliable in this
+area (although tcpdump is a lot better now than it used to be).</PRE>
+<P>The most certain way to examine IPsec packets is to look at them on
+ the wire. For security, you need to be certain, so we recommend doing
+ that. To do so, you need a<STRONG> separate sniffer machine located
+ between the two gateways</STRONG>. This machine can be routing IPsec
+ packets, but it must not be an IPsec gateway. Network configuration for
+ such testing is discussed<A href="#testnet"> above</A>.</P>
+<P>Here's another mailing list message with advice on using tcpdump(8):</P>
+<PRE>Subject: RE: [Users] Encrypted???
+ Date: Thu, 29 Nov 2001
+ From: &quot;Joe Patterson&quot; &lt;jpatterson@asgardgroup.com&gt;
+
+tcpdump -nl -i $EXT-IF proto 50
+
+-nl tells it not to buffer output or resolve names (if you don't do that it
+may confuse you by not outputing anything for a while), -i $EXT-IF (replace
+with your external interface) tells it what interface to listen on, and
+proto 50 is ESP. Use &quot;proto 51&quot; if for some odd reason you're using AH, and
+&quot;udp port 500&quot; if you want to see the isakmp key exchange/tunnel setup
+packets.
+
+You can also run `tcpdump -nl -i ipsec0` to see what traffic is on that
+virtual interface. Anything you see there *should* be either encrypted or
+dropped (unless you've turned on some strange options in your ipsec.conf
+file)
+
+Another very handy thing is ethereal (http://www.ethereal.com/) which runs
+on just about anything, has a nice gui interface (or a nice text-based
+interface), and does a great job of protocol breakdown. For ESP and AH
+it'll basically just tell you that there's a packet of that protocol, and
+what the spi is, but for isakmp it'll actually show you a lot of the tunnel
+setup information (until it gets to the point in the protocol where isakmp
+is encrypted....)</PRE>
+<H2><A name="verify.crypt">Verifying encryption</A></H2>
+<P>The question of how to verify that messages are actually encrypted
+ has been extensively discussed on the mailing list. See this<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/07/msg00262.html">
+ thread</A>.</P>
+<P>If you just want to verify that packets are encrypted, look at them
+ with a packet sniffer (see<A href="#tcpdump.test"> previous section</A>
+) located between the gateways. The packets should, except for some of
+ the header information, be utterly unintelligible.<STRONG> The output
+ of good encryption looks<EM> exactly</EM> like random noise</STRONG>.</P>
+<P>A packet sniffer can only tell you that the data you looked at was
+ encrypted. If you have stronger requirements -- for example if your
+ security policy requires verification that plaintext is not leaked
+ during startup or under various anomolous conditions -- then you will
+ need to devise much more thorough tests. If you do that, please post
+ any results or methodological details which your security policy allows
+ you to make public.</P>
+<P>You can put recognizable data into ping packets with something like:</P>
+<PRE> ping -p feedfacedeadbeef 11.0.1.1</PRE>
+<P>&quot;feedfacedeadbeef&quot; is a legal hexadecimal pattern that is easy to
+ pick out of hex dumps.</P>
+<P>For other protocols, you may need to check if you have encrypted data
+ or ASCII text. Encrypted data has approximately equal frequencies for
+ all 256 possible characters. ASCII text has most characters in the
+ printable range 0x20-0x7f, a few control characters less than 0x20, and
+ none at all in the range 0x80-0xff. 0x20, space, is a good character to
+ look for. In normal English text space occurs about once in seven
+ characters, versus about once in 256 for random or encrypted data.</P>
+<P>One thing to watch for: the output of good compression, like that of
+ good encryption, looks just like random noise. You cannot tell just by
+ looking at a data stream whether it has been compressed, encrypted, or
+ both. You need a little care not to mistake compressed data for
+ encrypted data in your testing.</P>
+<P>Note also that weak encryption also produces random-looking output.
+ You cannot tell whether the encryption is strong by looking at the
+ output. To be sure of that, you would need to have both the algorithms
+ and the implementation examined by experts.</P>
+<P>For IPsec, you can get partial assurance from interoperability tests.
+ See our<A href="interop.html"> interop</A> document. When twenty
+ products all claim to implement<A href="#3DES"> 3DES</A>, and they all
+ talk to each other, you can be fairly sure they have it right. Of
+ course, you might wonder whether all the implementers are consipring to
+ trick you or, more plausibly, whether some implementations might have
+ &quot;back doors&quot; so they can get also it wrong when required.. If you're
+ seriously worried about things like that, you need to get the code you
+ use audited (good luck if it is not Open Source), or perhaps to talk to
+ a psychiatrist about treatments for paranoia.</P>
+<H2><A name="mail.test">Mailing list pointers</A></H2>
+<P>Additional information on testing can be found in these<A href="mail.html">
+ mailing list</A> messages:</P>
+<UL>
+<LI>a user's detailed<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00571.html">
+ setup diary</A> for his testbed network</LI>
+<LI>a FreeS/WAN team member's<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00425.html">
+ notes</A> from testing at an IPsec interop &quot;bakeoff&quot;</LI>
+</UL>
+<HR>
+<H1><A name="kernelconfig">Kernel configuration for FreeS/WAN</A></H1>
+<P> This section lists many of the options available when configuring a
+ Linux kernel, and explains how they should be set on a FreeS/WAN IPsec
+ gateway.</P>
+<H2><A name="notall">Not everyone needs to worry about kernel
+ configuration</A></H2>
+<P>Note that in many cases you do not need to mess with these.</P>
+<P> You may have a Linux distribution which comes with FreeS/WAN
+ installed (see this<A href="#products"> list</A>). In that case, you
+ need not do a FreeS/WAN installation or a kernel configuration. Of
+ course, you might still want to configure and rebuild your kernel to
+ improve performance or security. This can be done with standard tools
+ described in the<A href="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">
+ Kernel HowTo</A>.</P>
+<P>If you need to install FreeS/WAN, then you do need to configure a
+ kernel. However, you may choose to do that using the simplest
+ procedure:</P>
+<UL>
+<LI>Configure, build and test a kernel for your system before adding
+ FreeS/WAN. See the<A href="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">
+ Kernel HowTo</A> for details.<STRONG> This step cannot be skipped</STRONG>
+. FreeS/WAN needs the results of your configuration.</LI>
+<LI>Then use FreeS/WAN's<VAR> make oldgo</VAR> command. This sets
+ everything FreeS/WAN needs and retains your values everywhere else.</LI>
+</UL>
+<P> This document is for those who choose to configure their FreeS/WAN
+ kernel themselves.</P>
+<H2><A name="assume">Assumptions and notation</A></H2>
+<P> Help text for most kernel options is included with the kernel files,
+ and is accessible from within the configuration utilities. We assume
+ you will refer to that, and to the<A href="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">
+ Kernel HowTo</A>, as necessary. This document covers only the
+ FreeS/WAN-specific aspects of the problem.</P>
+<P> To avoid duplication, this document section does not cover settings
+ for the additional IPsec-related kernel options which become available
+ after you have patched your kernel with FreeS/WAN patches. There is
+ help text for those available from within the configuration utility.</P>
+<P> We assume a common configuration in which the FreeS/WAN IPsec
+ gateway is also doing ipchains(8) firewalling for a local network, and
+ possibly masquerading as well.</P>
+<P> Some suggestions below are labelled as appropriate for &quot;a true
+ paranoid&quot;. By this we mean they may cause inconvenience and it is not
+ entirely clear they are necessary, but they appear to be the safest
+ choice. Not using them might entail some risk. Of course one suggested
+ mantra for security administrators is: &quot;I know I'm paranoid. I wonder
+ if I'm paranoid enough.&quot;</P>
+<H3><A name="labels">Labels used</A></H3>
+<P> Six labels are used to indicate how options should be set. We mark
+ the labels with [square brackets]. For two of these labels, you have no
+ choice:</P>
+<DL>
+<DT>[required]</DT>
+<DD>essential for FreeS/WAN operation.</DD>
+<DT>[incompatible]</DT>
+<DD>incompatible with FreeS/WAN.</DD>
+</DL>
+<P>those must be set correctly or FreeS/WAN will not work</P>
+<P>FreeS/WAN should work with any settings of the others, though of
+ course not all combinations have been tested. We do label these in
+ various ways, but<EM> these labels are only suggestions</EM>.</P>
+<DL>
+<DT>[recommended]</DT>
+<DD>useful on most FreeS/WAN gateways</DD>
+<DT>[disable]</DT>
+<DD>an unwelcome complication on a FreeS/WAN gateway.</DD>
+<DT>[optional]</DT>
+<DD>Your choice. We outline issues you might consider.</DD>
+<DT>[anything]</DT>
+<DD>This option has no direct effect on FreeS/WAN and related tools, so
+ you should be able to set it as you please.</DD>
+</DL>
+<P> Of course complexity is an enemy in any effort to build secure
+ systems.<STRONG> For maximum security, any feature that can reasonably
+ be turned off should be</STRONG>. &quot;If in doubt, leave it out.&quot;</P>
+<H2><A name="kernelopt">Kernel options for FreeS/WAN</A></H2>
+<P> Indentation is based on the nesting shown by 'make menuconfig' with
+ a 2.2.16 kernel for the i386 architecture.</P>
+<DL>
+<DT><A name="maturity">Code maturity and level options</A></DT>
+<DD>
+<DL>
+<DT><A name="devel">Prompt for development ... code/drivers</A></DT>
+<DD>[optional] If this is<VAR> no</VAR>, experimental drivers are not
+ shown in later menus.
+<P>For most FreeS/WAN work,<VAR> no</VAR> is the preferred setting.
+ Using new or untested components is too risky for a security gateway.</P>
+<P>However, for some hardware (such as the author's network cards) the
+ only drivers available are marked<VAR> new/experimental</VAR>. In such
+ cases, you must enable this option or your cards will not appear under
+ &quot;network device support&quot;. A true paranoid would leave this option off
+ and replace the cards.</P>
+</DD>
+<DT>Processor type and features</DT>
+<DD>[anything]</DD>
+<DT>Loadable module support</DT>
+<DD>
+<DL>
+<DT>Enable loadable module support</DT>
+<DD>[optional] A true paranoid would disable this. An attacker who has
+ root access to your machine can fairly easily install a bogus module
+ that does awful things, provided modules are enabled. A common tool for
+ attackers is a &quot;rootkit&quot;, a set of tools the attacker uses once he or
+ she has become root on your system. The kit introduces assorted
+ additional compromises so that the attacker will continue to &quot;own&quot; your
+ system despite most things you might do to recovery the situation. For
+ Linux, there is a tool called<A href="http://www.sans.org/newlook/resources/IDFAQ/knark.htm">
+ knark</A> which is basically a rootkit packaged as a kernel module.
+<P>With modules disabled, an attacker cannot install a bogus module. The
+ only way he can achieve the same effects is to install a new kernel and
+ reboot. This is considerably more likely to be noticed.</P>
+<P>Many FreeS/WAN gateways run with modules enabled. This simplifies
+ some administrative tasks and some ipchains features are available only
+ as modules. Once an enemy has root on your machine your security is
+ nil, so arguably defenses which come into play only in that situation
+ are pointless.</P>
+<P></P>
+</DD>
+<DT>Set version information ....</DT>
+<DD>[optional] This provides a check to prevent loading modules compiled
+ for a different kernel.</DD>
+<DT>Kernel module loader</DT>
+<DD>[disable] It gives little benefit on a typical FreeS/WAN gate and
+ entails some risk.</DD>
+</DL>
+</DD>
+<DT>General setup</DT>
+<DD>We list here only the options that matter for FreeS/WAN.
+<DL>
+<DT>Networking support</DT>
+<DD>[required]</DD>
+<DT>Sysctl interface</DT>
+<DD>[optional] If this option is turned on and the<VAR> /proc</VAR>
+ filesystem installed, then you can control various system behaviours by
+ writing to files under<VAR> /proc/sys</VAR>. For example:
+<PRE> echo 1 &gt; /proc/sys/net/ipv4/ipforward</PRE>
+ turns IP forwarding on.
+<P>Disabling this option breaks many firewall scripts. A true paranoid
+ would disable it anyway since it might conceivably be of use to an
+ attacker.</P>
+</DD>
+</DL>
+</DD>
+<DT>Plug and Play support</DT>
+<DD>[anything]</DD>
+<DT>Block devices</DT>
+<DD>[anything]</DD>
+<DT>Networking options</DT>
+<DD>
+<DL>
+<DT>Packet socket</DT>
+<DD>[optional] This kernel feature supports tools such as tcpdump(8)
+ which communicate directly with network hardware, bypassing kernel
+ protocols. This is very much a two-edged sword:
+<UL>
+<LI>such tools can be very useful to the firewall admin, especially
+ during initial testing</LI>
+<LI>should an evildoer breach your firewall, such tools could give him
+ or her a great deal of information about the rest of your network</LI>
+</UL>
+ We recommend disabling this option on production gateways.</DD>
+<DT><A name="netlink">Kernel/User netlink socket</A></DT>
+<DD>[optional] Required if you want to use<A href="#adv"> advanced
+ router</A> features.</DD>
+<DT>Routing messages</DT>
+<DD>[optional]</DD>
+<DT>Netlink device emulation</DT>
+<DD>[optional]</DD>
+<DT>Network firewalls</DT>
+<DD>[recommended] You need this if the IPsec gateway also functions as a
+ firewall.
+<P>Even if the IPsec gateway is not your primary firewall, we suggest
+ setting this so that you can protect the gateway with at least basic
+ local packet filters.</P>
+</DD>
+<DT>Socket filtering</DT>
+<DD>[disable] This enables an older filtering interface. We suggest
+ using ipchains(8) instead. To do that, set the &quot;Network firewalls&quot;
+ option just above, and not this one.</DD>
+<DT>Unix domain sockets</DT>
+<DD>[required] These sockets are used for communication between the<A href="manpage.d/ipsec.8.html">
+ ipsec(8)</A> commands and the<A href="manpage.d/ipsec_pluto.8.html">
+ ipsec_pluto(8)</A> daemon.</DD>
+<DT>TCP/IP networking</DT>
+<DD>[required]
+<DL>
+<DT>IP: multicasting</DT>
+<DD>[anything]</DD>
+<DT><A name="adv">IP: advanced router</A></DT>
+<DD>[optional] This gives you policy routing, which some people have
+ used to good advantage in their scripts for FreeS/WAN gateway
+ management. It is not used in our distributed scripts, so not required
+ unless you want it for custom scripts. It requires the<A href="#netlink">
+ netlink</A> interface between kernel code and the iproute2(8) command.</DD>
+<DT>IP: kernel level autoconfiguration</DT>
+<DD>[disable] It gives little benefit on a typical FreeS/WAN gate and
+ entails some risk.</DD>
+<DT>IP: firewall packet netlink device</DT>
+<DD>[disable]</DD>
+<DT>IP: transparent proxy support</DT>
+<DD>[optional] This is required in some firewall configurations, but
+ should be disabled unless you have a definite need for it.</DD>
+<DT>IP: masquerading</DT>
+<DD>[optional] Required if you want to use<A href="#non-routable">
+ non-routable</A> private IP addresses for your local network.</DD>
+<DT>IP: Optimize as router not host</DT>
+<DD>[recommended]</DD>
+<DT>IP: tunneling</DT>
+<DD>[required]</DD>
+<DT>IP: GRE tunnels over IP</DT>
+<DD>[anything]</DD>
+<DT>IP: aliasing support</DT>
+<DD>[anything]</DD>
+<DT>IP: ARP daemon support (EXPERIMENTAL)</DT>
+<DD>Not required on most systems, but might prove useful on
+ heavily-loaded gateways.</DD>
+<DT>IP: TCP syncookie support</DT>
+<DD>[recommended] It provides a defense against a<A href="#DOS"> denial
+ of service attack</A> which uses bogus TCP connection requests to waste
+ resources on the victim machine.</DD>
+<DT>IP: Reverse ARP</DT>
+<DD></DD>
+<DT>IP: large window support</DT>
+<DD>[recommended] unless you have less than 16 meg RAM</DD>
+</DL>
+</DD>
+<DT>IPv6</DT>
+<DD>[optional] FreeS/WAN does not currently support IPv6, though work on
+ integrating FreeS/WAN with the Linux IPv6 stack has begun.<A href="#ipv6">
+ Details</A>.
+<P> It should be possible to use IPv4 FreeS/WAN on a machine which also
+ does IPv6. This combination is not yet well tested. We would be quite
+ interested in hearing results from anyone expermenting with it, via the<A
+href="mail.html"> mailing list</A>.</P>
+<P> We do not recommend using IPv6 on production FreeS/WAN gateways
+ until more testing has been done.</P>
+</DD>
+<DT>Novell IPX</DT>
+<DD>[disable]</DD>
+<DT>Appletalk</DT>
+<DD>[disable] Quite a few Linux installations use IP but also have some
+ other protocol, such as Appletalk or IPX, for communication with local
+ desktop machines. In theory it should be possible to configure IPsec
+ for the IP side of things without interfering with the second protocol.
+<P>We do not recommend this. Keep the software on your gateway as simple
+ as possible. If you need a Linux-based Appletalk or IPX server, use a
+ separate machine.</P>
+</DD>
+</DL>
+</DD>
+<DT>Telephony support</DT>
+<DD>[anything]</DD>
+<DT>SCSI support</DT>
+<DD>[anything]</DD>
+<DT>I2O device support</DT>
+<DD>[anything]</DD>
+<DT>Network device support</DT>
+<DD>[anything] should work, but there are some points to note.
+<P>The development team test almost entirely on 10 or 100 megabit
+ Ethernet and modems. In principle, any device that can do IP should be
+ just fine for IPsec, but in the real world any device that has not been
+ well-tested is somewhat risky. By all means try it, but don't bet your
+ project on it until you have solid test results.</P>
+<P>If you disabled experimental drivers in the<A href="#maturity"> Code
+ maturity</A> section above, then those drivers will not be shown here.
+ Check that option before going off to hunt for missing drivers.</P>
+<P>If you want Linux to automatically find more than one ethernet
+ interface at boot time, you need to:</P>
+<UL>
+<LI>compile the appropriate driver(s) into your kernel. Modules will not
+ work for this</LI>
+<LI>add a line such as
+<PRE>
+ append=&quot;ether=0,0,eth0 ether=0,0,eth1&quot;
+</PRE>
+ to your /etc/lilo.conf file. In some cases you may need to specify
+ parameters such as IRQ or base address. The example uses &quot;0,0&quot; for
+ these, which tells the system to search. If the search does not succeed
+ on your hardware, then you should retry with explicit parameters. See
+ the lilo.conf(5) man page for details.</LI>
+<LI>run lilo(8)</LI>
+</UL>
+ Having Linux find the cards this way is not necessary, but is usually
+ more convenient than loading modules in your boot scripts.</DD>
+<DT>Amateur radio support</DT>
+<DD>[anything]</DD>
+<DT>IrDA (infrared) support</DT>
+<DD>[anything]</DD>
+<DT>ISDN subsystem</DT>
+<DD>[anything]</DD>
+<DT>Old CDROM drivers</DT>
+<DD>[anything]</DD>
+<DT>Character devices</DT>
+<DD>The only required character device is:
+<DL>
+<DT>random(4)</DT>
+<DD>[required] This is a source of<A href="#random"> random</A> numbers
+ which are required for many cryptographic protocols, including several
+ used in IPsec.
+<P>If you are comfortable with C source code, it is likely a good idea
+ to go in and adjust the<VAR> #define</VAR> lines in<VAR>
+ /usr/src/linux/drivers/char/random.c</VAR> to ensure that all sources
+ of randomness are enabled. Relying solely on keyboard and mouse
+ randomness is dubious procedure for a gateway machine. You could also
+ increase the randomness pool size from the default 512 bytes (128
+ 32-bit words).</P>
+</DD>
+</DL>
+</DD>
+<DT>Filesystems</DT>
+<DD>[anything] should work, but we suggest limiting a gateway machine to
+ the standard Linux ext2 filesystem in most cases.</DD>
+<DT>Network filesystems</DT>
+<DD>[disable] These systems are an unnecessary risk on an IPsec gateway.</DD>
+<DT>Console drivers</DT>
+<DD>[anything]</DD>
+<DT>Sound</DT>
+<DD>[anything] should work, but we suggest enabling sound only if you
+ plan to use audible alarms for firewall problems.</DD>
+<DT>Kernel hacking</DT>
+<DD>[disable] This might be enabled on test machines, but should not be
+ on production gateways.</DD>
+</DL>
+</DD>
+</DL>
+<HR>
+<H1><A name="adv_config">Other configuration possibilities</A></H1>
+<P>This document describes various options for FreeS/WAN configuration
+ which are less used or more complex (often both) than the standard
+ cases described in our<A href="#config"> config</A> and<A href="#quick_guide">
+ quickstart</A> documents.</P>
+<H2><A name="thumb">Some rules of thumb about configuration</A></H2>
+<H3><A name="cheap.tunnel">Tunnels are cheap</A></H3>
+<P>Nearly all of the overhead in IPsec processing is in the encryption
+ and authentication of packets. Our<A href="performance.html">
+ performance</A> document discusses these overheads.</P>
+<P>Beside those overheads, the cost of managing additional tunnels is
+ trivial. Whether your gateway supports one tunnel or ten just does not
+ matter. A hundred might be a problem; there is a<A href="#biggate">
+ section</A> on this in the performance document.</P>
+<P>So, in nearly all cases, if using multiple tunnels gives you a
+ reasonable way to describe what you need to do, you should describe it
+ that way in your configuration files.</P>
+<P>For example, one user recently asked on a mailing list about this
+ network configuration:</P>
+<PRE> netA---gwA---gwB---netB
+ |----netC
+
+ netA and B are secured netC not.
+ netA and gwA can not access netC</PRE>
+<P>The user had constructed only one tunnel, netA to netB, and wanted to
+ know how to use ip-route to get netC packets into it. This is entirely
+ unnecessary. One of the replies was:</P>
+<PRE> The simplest way and indeed the right way to
+ solve this problem is to set up two connections:
+
+ leftsubnet=NetA
+ left=gwA
+ right=gwB
+ rightsubnet=NetB
+ and
+ leftsubnet=NetA
+ left=gwA
+ right=gwB
+ rightsubnet=NetC</PRE>
+<P>This would still be correct even if we added nets D, E, F, ... to the
+ above diagram and needed twenty tunnels.</P>
+<P>Of course another possibility would be to just use one tunnel, with a
+ subnet mask that includes both netB and netC (or B, C, D, ...). See
+ next section.</P>
+<P>In general, you can construct as many tunnels as you need. Networks
+ like netC in this example that do not connect directly to the gateway
+ are fine, as long as the gateway can route to them.</P>
+<P>The number of tunnels can become an issue if it reaches 50 or so.
+ This is discussed in the<A href="#biggate"> performance</A> document.
+ Look there for information on supporting hundreds of Road Warriors from
+ one gateway.</P>
+<P>If you find yourself with too many tunnels for some reason like
+ having eight subnets at one location and nine at another so you end up
+ with 9*8=72 tunnels, read the next section here.</P>
+<H3><A name="subnet.size">Subnet sizes</A></H3>
+<P>The subnets used in<VAR> leftsubnet</VAR> and<VAR> rightsubnet</VAR>
+ can be of any size that fits your needs, and they need not correspond
+ to physical networks.</P>
+<P>You adjust the size by changing the<A href="#subnet"> subnet mask</A>
+, the number after the slash in the subnet description. For example</P>
+<UL>
+<LI>in 192.168.100.0/24 the /24 mask says 24 bits are used to designate
+ the network. This leave 8 bits to label machines. This subnet has 256
+ addresses. .0 and .255 are reserved, so it can have 254 machines.</LI>
+<LI>A subnet with a /23 mask would be twice as large, 512 addresses.</LI>
+<LI>A subnet with a /25 mask would be half the size, 128 addresses.</LI>
+<LI>/0 is the whole Internet</LI>
+<LI>/32 is a single machine</LI>
+</UL>
+<P>As an example of using these in connection descriptions, suppose your
+ company's head office has four physical networks using the address
+ ranges:</P>
+<DL>
+<DT>192.168.100.0/24</DT>
+<DD>development</DD>
+<DT>192.168.101.0/24</DT>
+<DD>production</DD>
+<DT>192.168.102.0/24</DT>
+<DD>marketing</DD>
+<DT>192.168.103.0/24</DT>
+<DD>administration</DD>
+</DL>
+<P>You can use exactly those subnets in your connection descriptions, or
+ use larger subnets to grant broad access if required:</P>
+<DL>
+<DT>leftsubnet=192.168.100.0/24</DT>
+<DD>remote hosts can access only development</DD>
+<DT>leftsubnet=192.168.100.0/23</DT>
+<DD>remote hosts can access development or production</DD>
+<DT>leftsubnet=192.168.102.0/23</DT>
+<DD>remote hosts can access marketing or administration</DD>
+<DT>leftsubnet=192.168.100.0/22</DT>
+<DD>remote hosts can access any of the four departments</DD>
+</DL>
+<P>or use smaller subnets to restrict access:</P>
+<DL>
+<DT>leftsubnet=192.168.103.0/24</DT>
+<DD>remote hosts can access any machine in administration</DD>
+<DT>leftsubnet=192.168.103.64/28</DT>
+<DD>remote hosts can access only certain machines in administration.</DD>
+<DT>leftsubnet=192.168.103.42/32</DT>
+<DD>remote hosts can access only one particular machine in
+ administration</DD>
+</DL>
+<P>To be exact, 192.68.103.64/28 means all addresses whose top 28 bits
+ match 192.168.103.64. There are 16 of these because there are 16
+ possibilities for the remainingg 4 bits. Their addresses are
+ 192.168.103.64 to 192.168.103.79.</P>
+<P>Each connection description can use a different subnet if required.</P>
+<P>It is possible to use all the examples above on the same FreeS/WAN
+ gateway, each in a different connection description, perhaps for
+ different classes of user or for different remote offices.</P>
+<P>It is also possible to have multiple tunnels using different<VAR>
+ leftsubnet</VAR> descriptions with the same<VAR> right</VAR>. For
+ example, when the marketing manager is on the road he or she might have
+ access to:</P>
+<DL>
+<DT>leftsubnet=192.168.102.0/24</DT>
+<DD>all machines in marketing</DD>
+<DT>192.168.101.32/29</DT>
+<DD>some machines in production</DD>
+<DT>leftsubnet=192.168.103.42/32</DT>
+<DD>one particular machine in administration</DD>
+</DL>
+<P>This takes three tunnels, but tunnels are cheap. If the laptop is set
+ up to build all three tunnels automatically, then he or she can access
+ all these machines concurrently, perhaps from different windows.</P>
+<H3><A name="example.more">Other network layouts</A></H3>
+<P>Here is the usual network picture for a site-to-site VPN::</P>
+<PRE> Sunset==========West------------------East=========Sunrise
+ local net untrusted net local net</PRE>
+<P>and for the Road Warrior::</P>
+<PRE> telecommuter's PC or
+ traveller's laptop
+ Sunset==========West------------------East
+ corporate LAN untrusted net</PRE>
+<P>Other configurations are also possible.</P>
+<H4><A name="internet.subnet">The Internet as a big subnet</A></H4>
+<P>A telecommuter might have:</P>
+<PRE> Sunset==========West------------------East ================= firewall --- the Internet
+ home network untrusted net corporate network</PRE>
+<P>This can be described as a special case of the general
+ subnet-to-subnet connection. The subnet on the right is 0.0.0.0/0, the
+ whole Internet.</P>
+<P>West (the home gateway) can have its firewall rules set up so that
+ only IPsec packets to East are allowed out. It will then behave as if
+ its only connection to the world was a wire to East.</P>
+<P>When machines on the home network need to reach the Internet, they do
+ so via the tunnel, East and the corporate firewall. From the viewpoint
+ of the Internet (perhaps of some EvilDoer trying to break in!), those
+ home office machines are behind the firewall and protected by it.</P>
+<H4><A name="wireless.config">Wireless</A></H4>
+<P>Another possible configuration comes up when you do not trust the
+ local network, either because you have very high security standards or
+ because your are using easily-intercepted wireless signals.</P>
+<P>Some wireless networks have built-in encryption called<A href="#WEP">
+ WEP</A>, but its security is dubious. It is a fairly common practice to
+ use IPsec instead.</P>
+<P>In this case, part of your network may look like this:</P>
+<PRE> West-----------------------------East == the rest of your network
+ workstation untrusted wireless net</PRE>
+<P>Of course, there would likely be several wireless workstations, each
+ with its own IPsec tunnel to the East gateway.</P>
+<P>The connection descriptions look much like Road Warrior descriptions:</P>
+<UL>
+<LI>each workstation should have its own unique
+<UL>
+<LI>identifier for IPsec</LI>
+<LI>RSA key</LI>
+<LI>connection description.</LI>
+</UL>
+</LI>
+<LI>on the gateway, use<VAR> left=%any</VAR>, or the workstation IP
+ address</LI>
+<LI>on workstations,<VAR> left=%defaultroute</VAR>, or the workstation
+ IP address</LI>
+<LI><VAR>leftsubnet=</VAR> is not used.</LI>
+</UL>
+<P>The<VAR> rightsubnet=</VAR> parameter might be set in any of several
+ ways:</P>
+<DL>
+<DT>rightsubnet=0.0.0.0/0</DT>
+<DD>allowing workstations to access the entire Internet (see<A href="#internet.subnet">
+ above</A>)</DD>
+<DT>rightsubnet=a.b.c.0/24</DT>
+<DD>allowing access to your entire local network</DD>
+<DT>rightsubnet=a.b.c.d/32</DT>
+<DD>restricting the workstation to connecting to a particular server</DD>
+</DL>
+<P>Of course you can mix and match these as required. For example, a
+ university might allow faculty full Internet access while letting
+ student laptops connect only to a group of lab machines.</P>
+<H2><A name="choose">Choosing connection types</A></H2>
+<P>One choice you need to make before configuring additional connections
+ is what type or types of connections you will use. There are several
+ options, and you can use more than one concurrently.</P>
+<H3><A name="man-auto">Manual vs. automatic keying</A></H3>
+<P>IPsec allows two types of connections, with manual or automatic
+ keying. FreeS/WAN starts them with commands such as:</P>
+<PRE> ipsec manual --up <VAR>name</VAR>
+ ipsec auto --up <VAR>name</VAR></PRE>
+<P>The difference is in how they are keyed.</P>
+<DL>
+<DT><A href="#manual">Manually keyed</A> connections</DT>
+<DD>use keys stored in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf</A>
+.</DD>
+<DT><A href="#auto">Automatically keyed</A> connections</DT>
+<DD>use keys automatically generated by the Pluto key negotiation
+ daemon. The key negotiation protocol,<A href="#IKE"> IKE</A>, must
+ authenticate the other system. (It is vulnerable to a<A href="#middle">
+ man-in-the-middle attack</A> if used without authentication.) We
+ currently support two authentication methods:
+<UL>
+<LI>using shared secrets stored in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets</A>.</LI>
+<LI>RSA<A href="#public"> public key</A> authentication, with our
+ machine's private key in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets</A>. Public keys for other machines may either be placed
+ in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf</A> or provided via
+ DNS.</LI>
+</UL>
+<P>A third method, using RSA keys embedded in<A href="#X509"> X.509</A>
+ certtificates, is provided by user<A href="#patch"> patches</A>.</P>
+</DD>
+</DL>
+<P><A href="#manual">Manually keyed</A> connections provide weaker
+ security than<A href="#auto"> automatically keyed</A> connections. An
+ opponent who reads ipsec.secrets(5) gets your encryption key and can
+ read all data encrypted by it. If he or she has an archive of old
+ messages, all of them back to your last key change are also readable.</P>
+<P>With automatically-(re)-keyed connections, an opponent who reads
+ ipsec.secrets(5) gets the key used to authenticate your system in IKE
+ -- the shared secret or your private key, depending what authentication
+ mechanism is in use. However, he or she does not automatically gain
+ access to any encryption keys or any data.</P>
+<P>An attacker who has your authentication key can mount a<A href="#middle">
+ man-in-the-middle attack</A> and, if that succeeds, he or she will get
+ encryption keys and data. This is a serious danger, but it is better
+ than having the attacker read everyting as soon as he or she breaks
+ into ipsec.secrets(5).. Moreover, the keys change often so an opponent
+ who gets one key does not get a large amount of data. To read all your
+ data, he or she would have to do a man-in-the-middle attack at every
+ key change.</P>
+<P>We discuss using<A href="#prodman"> manual keying in production</A>
+ below, but this is<STRONG> not recommended</STRONG> except in special
+ circumstances, such as needing to communicate with some implementation
+ that offers no auto-keyed mode compatible with FreeS/WAN.</P>
+<P>Manual keying may also be useful for testing. There is some
+ discussion of this in our<A href="#man4debug"> FAQ</A>.</P>
+<H3><A name="auto-auth">Authentication methods for auto-keying</A></H3>
+<P>The IKE protocol which Pluto uses to negotiate connections between
+ gateways must use some form of authentication of peers. A gateway must
+ know who it is talking to before it can create a secure connection. We
+ support two basic methods for this authentication:</P>
+<UL>
+<LI>shared secrets, stored in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A></LI>
+<LI>RSA authentication</LI>
+</UL>
+<P>There are, howver, several variations on the RSA theme, using
+ different methods of managing the RSA keys:</P>
+<UL>
+<LI>our RSA private key in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A> with other gateways' public keys
+<DL>
+<DT>either</DT>
+<DD>stored in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A></DD>
+<DT>or</DT>
+<DD>looked up via<A href="#DNS"> DNS</A></DD>
+</DL>
+</LI>
+<LI>authentication with<A href="#X509"> x.509</A> certificates.; See our<A
+href="#patch"> links section</A> for information on user-contributed
+ patches for this.:</LI>
+</UL>
+<P>Public keys in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5</A>
+) give a reasonably straightforward method of specifying keys for
+ explicitly configured connections.</P>
+<P>Putting public keys in DNS allows us to support<A href="#carpediem">
+ opportunistic encryption</A>. Any two FreeS/WAN gateways can provide
+ secure communication, without either of them having any preset
+ information about the other.</P>
+<P>X.509 certificates may be required to interface to various<A href="#PKI">
+ PKI</A>s.</P>
+<H3><A name="adv-pk">Advantages of public key methods</A></H3>
+<P>Authentication with a<A href="#public"> public key</A> method such as<A
+href="#RSA"> RSA</A> has some important advantages over using shared
+ secrets.</P>
+<UL>
+<LI>no problem of secure transmission of secrets
+<UL>
+<LI>A shared secret must be shared, so you have the problem of
+ transmitting it securely to the other party. If you get this wrong, you
+ have no security.</LI>
+<LI>With a public key technique, you transmit only your public key. The
+ system is designed to ensure that it does not matter if an enemy
+ obtains public keys. The private key never leaves your machine.</LI>
+</UL>
+</LI>
+<LI>easier management
+<UL>
+<LI>Suppose you have 20 branch offices all connecting to one gateway at
+ head office, and all using shared secrets. Then the head office admin
+ has 20 secrets to manage. Each of them must be kept secret not only
+ from outsiders, but also from 19 of the branch office admins. The
+ branch office admins have only one secret each to manage.
+<P>If the branch offices need to talk to each other, this becomes
+ problematic. You need another 20*19/2 = 190 secrets for
+ branch-to-branch communication, each known to exactly two branches. Now
+ all the branch admins have the headache of handling 20 keys, each
+ shared with exactly one other branch or with head office.</P>
+<P>For larger numbers of branches, the number of connections and secrets
+ increases quadratically and managing them becomes a nightmare. A
+ 1000-gateway fully connected network needs 499,500 secrets, each known
+ to exactly two players. There are ways to reduce this problem, for
+ example by introducing a central key server, but these involve
+ additional communication overheads, more administrative work, and new
+ threats that must be carefully guarded against.</P>
+</LI>
+<LI>With public key techniques, the<EM> only</EM> thing you have to keep
+ secret is your private key, and<EM> you keep that secret from everyone</EM>
+.
+<P>As network size increaes, the number of public keys used increases
+ linearly with the number of nodes. This still requires careful
+ administration in large applications, but is nothing like the disaster
+ of a quadratic increase. On a 1000-gateway network, you have 1000
+ private keys, each of which must be kept secure on one machine, and
+ 1000 public keys which must be distributed. This is not a trivial
+ problem, but it is manageable.</P>
+</LI>
+</UL>
+</LI>
+<LI>does not require fixed IP addresses
+<UL>
+<LI>When shared secrets are used in IPsec, the responder must be able to
+ tell which secret to use by looking at the IP address on the incoming
+ packets. When the other parties do not have a fixed IP address to be
+ identified by (for example, on nearly all dialup ISP connections and
+ many cable or ADSL links), this does not work well -- all must share
+ the same secret!</LI>
+<LI>When RSA authentication is in use, the initiator can identify itself
+ by name before the key must be determined. The responder then checks
+ that the message is signed with the public key corresponding to that
+ name.</LI>
+</UL>
+</LI>
+</UL>
+<P>There is also a disadvantage:</P>
+<UL>
+<LI>your private key is a single point of attack, extremely valuable to
+ an enemy
+<UL>
+<LI>with shared secrets, an attacker who steals your ipsec.secrets file
+ can impersonate you or try<A href="#middle"> man-in-the-middle</A>
+ attacks, but can only attack connections described in that file</LI>
+<LI>an attacker who steals your private key gains the chance to attack
+ not only existing connections<EM> but also any future connections</EM>
+ created using that key</LI>
+</UL>
+</LI>
+</UL>
+<P>This is partly counterbalanced by the fact that the key is never
+ transmitted and remains under your control at all times. It is likely
+ necessary, however, to take account of this in setting security policy.
+ For example, you should change gateway keys when an administrator
+ leaves the company, and should change them periodically in any case.</P>
+<P>Overall, public key methods are<STRONG> more secure, more easily
+ managed and more flexible</STRONG>. We recommend that they be used for
+ all connections, unless there is a compelling reason to do otherwise.</P>
+<H2><A name="prodsecrets">Using shared secrets in production</A></H2>
+<P>Generally, public key methods are preferred for reasons given above,
+ but shared secrets can be used with no loss of security, just more work
+ and perhaps more need to take precautions.</P>
+<P>What I call &quot;shared secrets&quot; are sometimes also called &quot;pre-shared
+ keys&quot;. They are used only for for authentication, never for encryption.
+ Calling them &quot;pre-shared keys&quot; has confused some users into thinking
+ they were encryption keys, so I prefer to avoid the term..</P>
+<P>If you are interoperating with another IPsec implementation, you may
+ find its documentation calling them &quot;passphrases&quot;.</P>
+<H3><A name="secrets">Putting secrets in ipsec.secrets(5)</A></H3>
+<P>If shared secrets are to be used to<A href="#authentication">
+ authenticate</A> communication for the<A href="#DH"> Diffie-Hellman</A>
+ key exchange in the<A href="#IKE"> IKE</A> protocol, then those secrets
+ must be stored in<VAR> /etc/ipsec.secrets</VAR>. For details, see the<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A> man page.</P>
+<P>A few considerations are vital:</P>
+<UL>
+<LI>make the secrets long and unguessable. Since they need not be
+ remembered by humans, very long ugly strings may be used. We suggest
+ using our<A href="manpage.d/ipsec_ranbits.8.html"> ipsec_ranbits(8)</A>
+ utility to generate long (128 bits or more) random strings.</LI>
+<LI>transmit secrets securely. You have to share them with other
+ systems, but you lose if they are intercepted and used against you. Use<A
+href="#PGP"> PGP</A>,<A href="#ssh"> SSH</A>, hand delivery of a floppy
+ disk which is then destroyed, or some other trustworthy method to
+ deliver them.</LI>
+<LI>store secrets securely, in root-owned files with permissions
+ rw------.</LI>
+<LI>limit sharing of secrets. Alice, Bob, Carol and Dave may all talk to
+ each other, but only Alice and Bob should know the secret for an
+ Alice-Bob link.</LI>
+<LI><STRONG>do not share private keys</STRONG>. The private key for RSA
+ authentication of your system is stored in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A>, but it is a different class of secret from the
+ pre-shared keys used for the &quot;shared secret&quot; authentication. No-one but
+ you should have the RSA private key.</LI>
+</UL>
+<P>Each line has the IP addresses of the two gateways plus the secret.
+ It should look something like this:</P>
+<PRE> 10.0.0.1 11.0.0.1 : PSK &quot;jxTR1lnmSjuj33n4W51uW3kTR55luUmSmnlRUuWnkjRj3UuTV4T3USSu23Uk55nWu5TkTUnjT&quot;</PRE>
+<P><VAR>PSK</VAR> indicates the use of a<STRONG> p</STRONG>re-<STRONG>s</STRONG>
+hared<STRONG> k</STRONG>ey. The quotes and the whitespace shown are
+ required.</P>
+<P>You can use any character string as your secret. For security, it
+ should be both long and extremely hard to guess. We provide a utility
+ to generate such strings,<A href="manpage.d/ipsec_ranbits.8.html">
+ ipsec_ranbits(8)</A>.</P>
+<P>You want the same secret on the two gateways used, so you create a
+ line with that secret and the two gateway IP addresses. The
+ installation process supplies an example secret, useful<EM> only</EM>
+ for testing. You must change it for production use.</P>
+<H3><A name="securing.secrets">File security</A></H3>
+<P>You must deliver this file, or the relevant part of it, to the other
+ gateway machine by some<STRONG> secure</STRONG> means.<EM> Don't just
+ FTP or mail the file!</EM> It is vital that the secrets in it remain
+ secret. An attacker who knew those could easily have<EM> all the data
+ on your &quot;secure&quot; connection</EM>.</P>
+<P>This file must be owned by root and should have permissions<VAR>
+ rw-------</VAR>.</P>
+<H3><A name="notroadshared">Shared secrets for road warriors</A></H3>
+<P>You can use a shared secret to support a single road warrior
+ connecting to your gateway, and this is a reasonable thing to do in
+ some circumstances. Public key methods have advantages, discussed<A href="#choose">
+ above</A>, but they are not critical in this case.</P>
+<P>To do this, the line in ipsec.secrets(5) is something like:</P>
+<PRE> 10.0.0.1 0.0.0.0 : PSK &quot;jxTR1lnmSjuj33n4W51uW3kTR55luUmSmnlRUuWnkjRj3UuTV4T3USSu23Uk55nWu5TkTUnjT&quot;</PRE>
+ where the<VAR> 0.0.0.0</VAR> means that any IP address is acceptable.
+<P><STRONG>For more than one road warrior, shared secrets are<EM> not</EM>
+ recommended.</STRONG> If shared secrets are used, then when the
+ responder needs to look up the secret, all it knows about the sender is
+ an IP address. This is fine if the sender is at a fixed IP address
+ specified in the config file. It is also fine if only one road warrior
+ uses the wildcard<VAR> 0.0.0.0</VAR> address. However, if you have more
+ than one road warrior using shared secret authentication, then they
+ must all use that wildcard and therefore<STRONG> all road warriors
+ using PSK autentication must use the same secret</STRONG>. Obviously,
+ this is insecure.</P>
+<P><STRONG>For multiple road warriors, use public key authentication.</STRONG>
+ Each roadwarrior can then have its own identity (our<VAR> leftid=</VAR>
+ or<VAR> rightid=</VAR> parameters), its own public/private key pair,
+ and its own secure connection.</P>
+<H2><A name="prodman">Using manual keying in production</A></H2>
+<P>Generally,<A href="#auto"> automatic keying</A> is preferred over<A href="#manual">
+ manual keying</A> for production use because it is both easier to
+ manage and more secure. Automatic keying frees the admin from much of
+ the burden of managing keys securely, and can provide<A href="#PFS">
+ perfect forward secrecy</A>. This is discussed in more detail<A href="#man-auto">
+ above</A>.</P>
+<P>However, it is possible to use manual keying in production if that is
+ what you want to do. This might be necessary, for example, in order to
+ interoperate with some device that either does not provide automatic
+ keying or provides it in some version we cannot talk to.</P>
+<P>Note that with manual keying<STRONG> all security rests with the keys</STRONG>
+. If an adversary acquires your keys, you've had it. He or she can read
+ everything ever sent with those keys, including old messages he or she
+ may have archived.</P>
+<P>You need to<STRONG> be really paranoid about keys</STRONG> if you're
+ going to rely on manual keying for anything important.</P>
+<UL>
+<LI>keep keys in files with 600 permissions, owned by root</LI>
+<LI>be extremely careful about security of your gateway systems. Anyone
+ who breaks into a gateway and gains root privileges can get all your
+ keys and read everything ever encrypted with those keys, both old
+ messages he has archived and any new ones you may send.</LI>
+<LI>change keys regularly. This can be a considerable bother, (and
+ provides an excellent reason to consider automatic keying instead), but
+ it is<EM> absolutely essential</EM> for security. Consider a manually
+ keyed system in which you leave the same key in place for months:
+<UL>
+<LI>an attacker can have a very large sample of text sent with that key
+ to work with. This makes various cryptographic attacks much more likely
+ to succeed.</LI>
+<LI>The chances of the key being compromised in some non-cryptographic
+ manner -- a spy finds it on a discarded notepad, someone breaks into
+ your server or your building and steals it, a staff member is bribed,
+ tricked, seduced or coerced into revealing it, etc. -- also increase
+ over time.</LI>
+<LI>a successful attacker can read everything ever sent with that key.
+ This makes any successful attack extremely damaging.</LI>
+</UL>
+ It is clear that you must change keys often to have any useful
+ security. The only question is how often.</LI>
+<LI>use<A href="#PGP"> PGP</A> or<A href="#ssh"> SSH</A> for all key
+ transfers</LI>
+<LI>don't edit files with keys in them when someone can look over your
+ shoulder</LI>
+<LI>worry about network security; could someone get keys by snooping
+ packets on the LAN between your X desktop and the gateway?</LI>
+<LI>lock up your backup tapes for the gateway system</LI>
+<LI>... and so on</LI>
+</UL>
+<P>Linux FreeS/WAN provides some facilities to help with this. In
+ particular, it is good policy to<STRONG> keep keys in separate files</STRONG>
+ so you can edit configuration information in /etc/ipsec.conf without
+ exposing keys to &quot;shoulder surfers&quot; or network snoops. We support this
+ with the<VAR> also=</VAR> and<VAR> include</VAR> syntax in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>.</P>
+<P>See the last example in our<A href="examples"> examples</A> file. In
+ the /etc/ipsec.conf<VAR> conn samplesep</VAR> section, it has the line:</P>
+<PRE> also=samplesep-keys</PRE>
+<P>which tells the &quot;ipsec manual&quot; script to insert the configuration
+ description labelled &quot;samplesep-keys&quot; if it can find it. The
+ /etc/ipsec.conf file must also have a line such as:</P>
+<PRE>include ipsec.*.conf</PRE>
+<P>which tells it to read other files. One of those other files then
+ might contain the additional data:</P>
+<PRE>conn samplesep-keys
+ spi=0x200
+ esp=3des-md5-96
+ espenckey=0x01234567_89abcdef_02468ace_13579bdf_12345678_9abcdef0
+ espauthkey=0x12345678_9abcdef0_2468ace0_13579bdf</PRE>
+<P>The first line matches the label in the &quot;also=&quot; line, so the indented
+ lines are inserted. The net effect is exactly as if the inserted lines
+ had occurred in the original file in place of the &quot;also=&quot; line.</P>
+<P>Variables set here are:</P>
+<DL>
+<DT>spi</DT>
+<DD>A number needed by the manual keying code. Any 3-digit hex number
+ will do, but if you have more than one manual connection then<STRONG>
+ spi must be different</STRONG> for each connection.</DD>
+<DT>esp</DT>
+<DD>Options for<A href="#ESP"> ESP</A> (Encapsulated Security Payload),
+ the usual IPsec encryption mode. Settings here are for<A href="#encryption">
+ encryption</A> using<A href="#3DES"> triple DES</A> and<A href="#authentication">
+ authentication</A> using<A href="#MD5"> MD5</A>. Note that encryption
+ without authentication should not be used; it is insecure.</DD>
+<DT>espenkey</DT>
+<DD>Key for ESP encryption. Here, a 192-bit hex number for triple DES.</DD>
+<DT>espauthkey</DT>
+<DD>Key for ESP authentication. Here, a 128-bit hex number for MD5.</DD>
+</DL>
+<P><STRONG>Note</STRONG> that the<STRONG> example keys we supply</STRONG>
+ are intended<STRONG> only for testing</STRONG>. For real use, you
+ should go to automatic keying. If that is not possible, create your own
+ keys for manual mode and keep them secret</P>
+<P>Of course, any files containing keys<STRONG> must</STRONG> have 600
+ permissions and be owned by root.</P>
+<P>If you connect in this way to multiple sites, we recommend that you
+ keep keys for each site in a separate file and adopt some naming
+ convention that lets you pick them all up with a single &quot;include&quot; line.
+ This minimizes the risk of losing several keys to one error or attack
+ and of accidentally giving another site admin keys which he or she has
+ no business knowing.</P>
+<P>Also note that if you have multiple manually keyed connections on a
+ single machine, then the<VAR> spi</VAR> parameter must be different for
+ each one. Any 3-digit hex number is OK, provided they are different for
+ each connection. We reserve the range 0x100 to 0xfff for manual
+ connections. Pluto assigns SPIs from 0x1000 up for automatically keyed
+ connections.</P>
+<P>If<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> contains
+ keys for manual mode connections, then it too must have permissions<VAR>
+ rw-------</VAR>. We recommend instead that, if you must manual keying
+ in production, you keep the keys in separate files.</P>
+<P>Note also that<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf</A>
+ is installed with permissions<VAR> rw-r--r--</VAR>. If you plan to use
+ manually keyed connections for anything more than initial testing, you<B>
+ must</B>:</P>
+<UL>
+<LI>either change permissions to<VAR> rw-------</VAR></LI>
+<LI>or store keys separately in secure files and access them via include
+ statements in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf</A>.</LI>
+</UL>
+<P>We recommend the latter method for all but the simplest
+ configurations.</P>
+<H3><A name="ranbits">Creating keys with ranbits</A></H3>
+<P>You can create new<A href="#random"> random</A> keys with the<A href="manpage.d/ipsec_ranbits.8.html">
+ ranbits(8)</A> utility. For example, the commands:</P>
+<PRE> umask 177
+ ipsec ranbits 192 &gt; temp
+ ipsec ranbits 128 &gt;&gt; temp</PRE>
+<P>create keys in the sizes needed for our default algorithms:</P>
+<UL>
+<LI>192-bit key for<A href="#3DES"> 3DES</A> encryption
+<BR> (only 168 bits are used; parity bits are ignored)</LI>
+<LI>128-bit key for keyed<A href="#MD5"> MD5</A> authentication</LI>
+</UL>
+<P>If you want to use<A href="#SHA"> SHA</A> instead of<A href="#MD5">
+ MD5</A>, that requires a 160-bit key</P>
+<P>Note that any<STRONG> temporary files</STRONG> used must be kept<STRONG>
+ secure</STRONG> since they contain keys. That is the reason for the
+ umask command above. The temporary file should be deleted as soon as
+ you are done with it. You may also want to change the umask back to its
+ default value after you are finished working on keys.</P>
+<P>The ranbits utility may pause for a few seconds if not enough entropy
+ is available immediately. See ipsec_ranbits(8) and random(4) for
+ details. You may wish to provide some activity to feed entropy into the
+ system. For example, you might move the mouse around, type random
+ characters, or do<VAR> du /usr &gt; /dev/null</VAR> in the background.</P>
+<H2><A name="boot">Setting up connections at boot time</A></H2>
+<P>You can tell the system to set up connections automatically at boot
+ time by putting suitable stuff in /etc/ipsec.conf on both systems. The
+ relevant section of the file is labelled by a line reading<VAR> config
+ setup</VAR>.</P>
+<P>Details can be found in the<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> man page. We also provide a file of<A href="examples">
+ example configurations</A>.</P>
+<P>The most likely options are something like:</P>
+<DL>
+<DT>interfaces=&quot;ipsec0=eth0 ipsec1=ppp0&quot;</DT>
+<DD>Tells KLIPS which interfaces to use. Up to four interfaces numbered
+ ipsec[0-3] are supported. Each interface can support an arbitrary
+ number of tunnels.
+<P>Note that for PPP, you give the ppp[0-9] device name here, not the
+ underlying device such as modem (or eth1 if you are using PPPoE).</P>
+</DD>
+<DT>interfaces=%defaultroute</DT>
+<DD>Alternative setting, useful in simple cases. KLIPS will pick up both
+ its interface and the next hop information from the settings of the
+ Linux default route.</DD>
+<DT>forwardcontrol=no</DT>
+<DD>Normally &quot;no&quot;. Set to &quot;yes&quot; if the IP forwarding option is disabled
+ in your network configuration. (This can be set as a kernel
+ configuration option or later. e.g. on Redhat, it's in
+ /etc/sysconfig/network and on SuSE you can adjust it with Yast.) Linux
+ FreeS/WAN will then enable forwarding when starting up and turn it off
+ when going down. This is used to ensure that no packets will be
+ forwarded before IPsec comes up and takes control.</DD>
+<DT>syslog=daemon.error</DT>
+<DD>Used in messages to the system logging daemon (syslogd) to specify
+ what type of software is sending the messages. If the settings are
+ &quot;daemon.error&quot; as in our example, then syslogd treats the messages as
+ error messages from a daemon.
+<P>Note that<A href="#Pluto"> Pluto</A> does not currently pay attention
+ to this variable. The variable controls setup messages only.</P>
+</DD>
+<DT>klipsdebug=</DT>
+<DD>Debug settings for<A href="#KLIPS"> KLIPS</A>.</DD>
+<DT>plutodebug=</DT>
+<DD>Debug settings for<A href="#Pluto"> Pluto</A>.</DD>
+<DT>... for both the above DEBUG settings</DT>
+<DD>Normally, leave empty as shown above for no debugging output.
+<BR> Use &quot;all&quot; for maximum information.
+<BR> See ipsec_klipsdebug(8) and ipsec_pluto(8) man page for other
+ options. Beware that if you set /etc/ipsec.conf to enable debug output,
+ your system's log files may get large quickly.</DD>
+<DT>dumpdir=/safe/directory</DT>
+<DD>Normally, programs started by ipsec setup don't crash. If they do,
+ by default, no core dump will be produced because such dumps would
+ contain secrets. If you find you need to debug such crashes, you can
+ set dumpdir to the name of a directory in which to collect the core
+ file.</DD>
+<DT>manualstart=</DT>
+<DD>List of manually keyed connections to be automatically started at
+ boot time. Useful for testing, but not for long term use. Connections
+ which are automatically started should also be automatically re-keyed.</DD>
+<DT>pluto=yes</DT>
+<DD>Whether to start<A href="#Pluto"> Pluto</A> when ipsec startup is
+ done.
+<BR> This parameter is optional and defaults to &quot;yes&quot; if not present.
+<P>&quot;yes&quot; is strongly recommended for production use so that the keying
+ daemon (Pluto) will automatically re-key the connections regularly. The
+ ipsec-auto parameters ikelifetime, ipseclifetime and reykeywindow give
+ you control over frequency of rekeying.</P>
+</DD>
+<DT>plutoload=&quot;reno-van reno-adam reno-nyc&quot;</DT>
+<DD>List of tunnels (by name, e.g. fred-susan or reno-van in our
+ examples) to be loaded into Pluto's internal database at startup. In
+ this example, Pluto loads three tunnels into its database when it is
+ started.
+<P>If plutoload is &quot;%search&quot;, Pluto will load any connections whose
+ description includes &quot;auto=add&quot; or &quot;auto=start&quot;.</P>
+</DD>
+<DT>plutostart=&quot;reno-van reno-adam reno-nyc&quot;</DT>
+<DD>List of tunnels to attempt to negotiate when Pluto is started.
+<P>If plutostart is &quot;%search&quot;, Pluto will start any connections whose
+ description includes &quot;auto=start&quot;.</P>
+<P>Note that, for a connection intended to be permanent,<STRONG> both
+ gateways should be set try to start</STRONG> the tunnel. This allows
+ quick recovery if either gateway is rebooted or has its IPsec
+ restarted. If only one gateway is set to start the tunnel and the other
+ gateway restarts, the tunnel may not be rebuilt.</P>
+</DD>
+<DT>plutowait=no</DT>
+<DD>Controls whether Pluto waits for one tunnel to be established before
+ starting to negotiate the next. You might set this to &quot;yes&quot;
+<UL>
+<LI>if your gateway is a very limited machine and you need to conserve
+ resources.</LI>
+<LI>for debugging; the logs are clearer if only one connection is
+ brought up at a time</LI>
+</UL>
+ For a busy and resource-laden production gateway, you likely want &quot;no&quot;
+ so that connections are brought up in parallel and the whole process
+ takes less time.</DD>
+</DL>
+<P>The example assumes you are at the Reno office and will use IPsec to
+ Vancouver, New York City and Amsterdam.</P>
+<H2><A name="multitunnel">Multiple tunnels between the same two gateways</A>
+</H2>
+<P>Consider a pair of subnets, each with a security gateway, connected
+ via the Internet:</P>
+<PRE> 192.168.100.0/24 left subnet
+ |
+ 192.168.100.1
+ North Gateway
+ 101.101.101.101 left
+ |
+ 101.101.101.1 left next hop
+ [Internet]
+ 202.202.202.1 right next hop
+ |
+ 202.202.202.202 right
+ South gateway
+ 192.168.200.1
+ |
+ 192.168.200.0/24 right subnet</PRE>
+<P>A tunnel specification such as:</P>
+<PRE>conn northnet-southnet
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ leftsubnet=192.168.100.0/24
+ leftfirewall=yes
+ right=202.202.202.202
+ rightnexthop=202.202.202.1
+ rightsubnet=192.168.200.0/24
+ rightfirewall=yes</PRE>
+ will allow machines on the two subnets to talk to each other. You might
+ test this by pinging from polarbear (192.168.100.7) to penguin
+ (192.168.200.5).
+<P>However,<STRONG> this does not cover other traffic you might want to
+ secure</STRONG>. To handle all the possibilities, you might also want
+ these connection descriptions:</P>
+<PRE>conn northgate-southnet
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ right=202.202.202.202
+ rightnexthop=202.202.202.1
+ rightsubnet=192.168.200.0/24
+ rightfirewall=yes
+
+conn northnet-southgate
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ leftsubnet=192.168.100.0/24
+ leftfirewall=yes
+ right=202.202.202.202
+ rightnexthop=202.202.202.1</PRE>
+<P>Without these, neither gateway can do IPsec to the remote subnet.
+ There is no IPsec tunnel or eroute set up for the traffic.</P>
+<P>In our example, with the non-routable 192.168.* addresses used,
+ packets would simply be discarded. In a different configuration, with
+ routable addresses for the remote subnet,<STRONG> they would be sent
+ unencrypted</STRONG> since there would be no IPsec eroute and there
+ would be a normal IP route.</P>
+<P>You might also want:</P>
+<PRE>conn northgate-southgate
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ right=202.202.202.202
+ rightnexthop=202.202.202.1</PRE>
+<P>This is required if you want the two gateways to speak IPsec to each
+ other.</P>
+<P>This requires a lot of duplication of details. Judicious use of<VAR>
+ also=</VAR> and<VAR> include</VAR> can reduce this problem.</P>
+<P>Note that, while FreeS/WAN supports all four tunnel types, not all
+ implementations do. In particular, some versions of Windows 2000 and
+ the freely downloadable version of PGP provide only &quot;client&quot;
+ functionality. You cannot use them as gateways with a subnet behind
+ them. To get that functionality, you must upgrade to Windows 2000
+ server or the commercially available PGP products.</P>
+<H3><A name="advroute">One tunnel plus advanced routing</A></H3>
+ It is also possible to use the new routing features in 2.2 and later
+ kernels to avoid most needs for multple tunnels. Here is one mailing
+ list message on the topic:
+<PRE>Subject: Re: linux-ipsec: IPSec packets not entering tunnel?
+ Date: Mon, 20 Nov 2000
+ From: Justin Guyett &lt;jfg@sonicity.com&gt;
+
+On Mon, 20 Nov 2000, Claudia Schmeing wrote:
+
+&gt; Right Left
+&gt; &quot;home&quot; &quot;office&quot;
+&gt; 10.92.10.0/24 ---- 24.93.85.110 ========= 216.175.164.91 ---- 10.91.10.24/24
+&gt;
+&gt; I've created all four tunnels, and can ping to test each of them,
+&gt; *except* homegate-officenet.
+
+I keep wondering why people create all four tunnels. Why not route
+traffic generated from home to 10.91.10.24/24 out ipsec0 with iproute2?
+And 99% of the time you don't need to access &quot;office&quot; directly, which
+means you can eliminate all but the subnet&lt;-&gt;subnet connection.</PRE>
+ and FreeS/WAN technical lead Henry Spencer's comment:
+<PRE>&gt; I keep wondering why people create all four tunnels. Why not route
+&gt; traffic generated from home to 10.91.10.24/24 out ipsec0 with iproute2?
+
+This is feasible, given some iproute2 attention to source addresses, but
+it isn't something we've documented yet... (partly because we're still
+making some attempt to support 2.0.xx kernels, which can't do this, but
+mostly because we haven't caught up with it yet).
+
+&gt; And 99% of the time you don't need to access &quot;office&quot; directly, which
+&gt; means you can eliminate all but the subnet&lt;-&gt;subnet connection.
+
+Correct in principle, but people will keep trying to ping to or from the
+gateways during testing, and sometimes they want to run services on the
+gateway machines too.</PRE>
+
+<!-- Is this in the right spot in this document? -->
+<H2><A name="opp.gate">An Opportunistic Gateway</A></H2>
+<H3><A NAME="14_7_1">Start from full opportunism</A></H3>
+<P>Full opportunism allows you to initiate and receive opportunistic
+ connections on your machine. The remaining instructions in this section
+ assume you have first set up full opportunism on your gateway using<A HREF="#opp.incoming">
+ these instructions</A>. Both sets of instructions require mailing DNS
+ records to your ISP. Collect DNS records for both the gateway (above)
+ and the subnet nodes (below) before contacting your ISP.</P>
+<H3><A NAME="14_7_2">Reverse DNS TXT records for each protected machine</A>
+</H3>
+<P>You need these so that your Opportunistic peers can:</P>
+<UL>
+<LI>discover the gateway's address, knowing only the IP address that
+ packets are bound for</LI>
+<LI>verify that the gateway is authorised to encrypt for that endpoint</LI>
+</UL>
+<P>On the gateway, generate a TXT record with:</P>
+<PRE> ipsec showhostkey --txt 192.0.2.11</PRE>
+<P>Use your gateway address in place of 192.0.2.11.</P>
+<P>You should see (keys are trimmed for clarity throughout our example):</P>
+<PRE> ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+<P><B>This MUST BE the same key as in your gateway's TXT record, or
+ nothing will work.</B></P>
+<P>In a text file, make one copy of this TXT record for each subnet
+ node:</P>
+<PRE> ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+<P>Above each entry, insert a line like this:</P>
+<PRE> 98.2.0.192.in-addr.arpa. IN PTR arthur.example.com.</PRE>
+<P>It must include:</P>
+<UL>
+<LI>The subnet node's address in reverse map format. For example,
+ 192.0.2.120 becomes<VAR> 120.2.0.192.in-addr.arpa.</VAR>. Note the
+ final period.</LI>
+<LI><VAR>IN PTR</VAR></LI>
+<LI>The node's name, ie.<VAR> arthur.example.com.</VAR>. Note the final
+ period.</LI>
+</UL>
+<P>The result will be a file of TXT records, like this:</P>
+<PRE> 98.2.0.192.in-addr.arpa. IN PTR arthur.example.com.
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ 99.2.0.192.in-addr.arpa. IN PTR ford.example.com.
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ 100.2.0.192.in-addr.arpa. IN PTR trillian.example.com.
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+<H3><A NAME="14_7_3">Publish your records</A></H3>
+<P>Ask your ISP to publish all the reverse DNS records you have
+ collected. There may be a delay of up to 48 hours as the records
+ propagate.</P>
+<H3><A NAME="14_7_4">...and test them</A></H3>
+<P>Check a couple of records with commands like this one:</P>
+<PRE> ipsec verify --host ford.example.com
+ ipsec verify --host trillian.example.com</PRE>
+<P>The<VAR> verify</VAR> command checks for TXT records for both the
+ subnet host and its gateway. You should see output like:</P>
+<PRE> ...
+ Looking for TXT in reverse map: 99.2.0.192.in-addr.arpa [OK]
+ ...
+ Looking for TXT in reverse map: 11.2.0.192.in-addr.arpa [OK]
+ ...
+ Looking for TXT in reverse map: 100.2.0.192.in-addr.arpa [OK]
+ ...
+ Looking for TXT in reverse map: 11.2.0.192.in-addr.arpa [OK]
+ ...</PRE>
+<H3><A NAME="14_7_5">No Configuration Needed</A></H3>
+<P>FreeS/WAN 2.x ships with a built-in, automatically enabled OE
+ connection<VAR> conn packetdefault</VAR> which applies OE, if possible,
+ to all outbound traffic routed through the FreeS/WAN box. The<A HREF="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5) manual</A> describes this connection in detail. While the
+ effect is much the same as<VAR> private-or-clear</VAR>, the
+ implementation is different: notably, it does not use policy groups.</P>
+<P>You can create more complex OE configurations for traffic forwarded
+ through a FreeS/WAN box, as explained in our<A HREF="#policygroups">
+ policy groups document</A>, or disable OE using<A HREF="#disable_policygroups">
+ these instructions</A>.</P>
+<H2><A name="extruded.config">Extruded Subnets</A></H2>
+<P>What we call<A href="glossary.html#extruded"> extruded subnets</A>
+ are a special case of<A href="glossary.html#VPN.gloss"> VPNs</A>.</P>
+<P>If your buddy has some unused IP addresses, in his subnet far off at
+ the other side of the Internet, he can loan them to you... provided
+ that the connection between you and him is fast enough to carry all the
+ traffic between your machines and the rest of the Internet. In effect,
+ he &quot;extrudes&quot; a part of his address space over the network to you, with
+ your Internet traffic appearing to originate from behind his Internet
+ gateway.</P>
+<P>As far as the Internet is concerned, your new extruded net is behind
+ your buddy's gateway. You route all your packets for the Internet at
+ large out his gateway, and receive return packets the same way. You
+ route your local packets locally.</P>
+<P>Suppose your friend has a.b.c.0/24 and wants to give you
+ a.b.c.240/28. The initial situation is:</P>
+<PRE> subnet gateway Internet
+ a.b.c.0/24 a.b.c.1 p.q.r.s</PRE>
+ where anything from the Internet destined for any machine in a.b.c.0/24
+ is routed via p.q.r.s and that gateway knows what to do from there.
+<P>Of course it is quite normal for various smaller subnets to exist
+ behind your friend's gateway. For example, your friend's company might
+ have a.b.c.16/28=development, a.b.c.32/28=marketing and so on. The
+ Internet neither knows not cares about this; it just delivers packets
+ to the p.q.r.s and lets the gateway do whatever needs to be done from
+ there.</P>
+<P>What we want to do is take a subnet, perhaps a.b.c.240/28, out of
+ your friend's physical location<EM> while still having your friend's
+ gateway route to it</EM>. As far as the Internet is concerned, you
+ remain behind that gateway.</P>
+<PRE> subnet gateway Internet your gate extruded
+
+ a.b.c.0/24 a.b.c.1 p.q.r.s d.e.f.g a.b.c.240/28
+
+ ========== tunnel ==========</PRE>
+<P>The extruded addresses have to be a complete subnet.</P>
+<P>In our example, the friend's security gateway is also his Internet
+ gateway, but this is not necessary. As long as all traffic from the
+ Internet to his addresses passes through the Internet gate, the
+ security gate could be a machine behind that. The IG would need to
+ route all traffic for the extruded subnet to the SG, and the SG could
+ handle the rest.</P>
+<P>First, configure your subnet using the extruded addresses. Your
+ security gateway's interface to your subnet needs to have an extruded
+ address (possibly using a Linux<A href="#virtual"> virtual interface</A>
+, if it also has to have a different address). Your gateway needs to
+ have a route to the extruded subnet, pointing to that interface. The
+ other machines at your site need to have addresses in that subnet, and
+ default routes pointing to your gateway.</P>
+<P>If any of your friend's machines need to talk to the extruded subnet,<EM>
+ they</EM> need to have a route for the extruded subnet, pointing at his
+ gateway.</P>
+<P>Then set up an IPsec subnet-to-subnet tunnel between your gateway and
+ his, with your subnet specified as the extruded subnet, and his subnet
+ specified as &quot;0.0.0.0/0&quot;.</P>
+<P>The tunnel description should be:</P>
+<PRE>conn extruded
+ left=p.q.r.s
+ leftsubnet=0.0.0.0/0
+ right=d.e.f.g
+ rightsubnet=a.b.c.0/28</PRE>
+<P>If either side was doing firewalling for the extruded subnet before
+ the IPsec connection is set up, you'll need to poke holes in your<A HREF="#firewall">
+ firewall</A> to allow packets through.</P>
+<P>And it all just works. Your SG routes traffic for 0.0.0.0/0 -- that
+ is, the whole Internet -- through the tunnel to his SG, which then
+ sends it onward as if it came from his subnet. When traffic for the
+ extruded subnet arrives at his SG, it gets sent through the tunnel to
+ your SG, which passes it to the right machine.</P>
+<P>Remember that when ipsec_manual or ipsec_auto takes a connection
+ down, it<EM> does not undo the route</EM> it made for that connection.
+ This lets you take a connection down and bring up a new one, or a
+ modified version of the old one, without having to rebuild the route it
+ uses and without any risk of packets which should use IPsec
+ accidentally going out in the clear. Because the route always points
+ into KLIPS, the packets will always go there. Because KLIPS temporarily
+ has no idea what to do with them (no eroute for them), they will be
+ discarded.</P>
+<P>If you<EM> do</EM> want to take the route down, this is what the
+ &quot;unroute&quot; operation in manual and auto is for. Just do an unroute after
+ doing the down.</P>
+<P>Note that the route for a connection may have replaced an existing
+ non-IPsec route. Nothing in Linux FreeS/WAN will put that pre-IPsec
+ route back. If you need it back, you have to create it with the route
+ command.</P>
+<H2><A name="roadvirt">Road Warrior with virtual IP address</A></H2>
+<P>Please note that<A HREF="http://www.freeswan.ca/download.php"> Super
+ FreeS/WAN</A> now features DHCP-over-IPsec, which is an alternate
+ procedure for Virtual IP address assignment.</P>
+<P></P>
+<P>Here is a mailing list message about another way to configure for
+ road warrior support:</P>
+<PRE>Subject: Re: linux-ipsec: understanding the vpn
+ Date: Thu, 28 Oct 1999 10:43:22 -0400
+ From: Irving Reid &lt;irving@nevex.com&gt;
+
+&gt; local-------linux------internet------mobile
+&gt; LAN box user
+&gt; ...
+
+&gt; now when the mobile user connects to the linux box
+&gt; it is given a virtual IP address, i have configured it to
+&gt; be in the 10.x.x.x range. mobile user and linux box
+&gt; have a tunnel between them with these IP addresses.
+
+&gt; Uptil this all is fine.
+
+If it is possible to configure your mobile client software *not* to
+use a virtual IP address, that will make your life easier. It is easier
+to configure FreeS/WAN to use the actual address the mobile user gets
+from its ISP.
+
+Unfortunately, some Windows clients don't let you choose.
+
+&gt; what i would like to know is that how does the mobile
+&gt; user communicate with other computers on the local
+&gt; LAN , of course with the vpn ?
+
+&gt; what IP address should the local LAN
+&gt; computers have ? I guess their default gateway
+&gt; should be the linux box ? and does the linux box need
+&gt; to be a 2 NIC card box or one is fine.
+
+As someone else stated, yes, the Linux box would usually be the default
+IP gateway for the local lan.
+
+However...
+
+If you mobile user has software that *must* use a virtual IP address,
+the whole picture changes. Nobody has put much effort into getting
+FreeS/WAN to play well in this environment, but here's a sketch of one
+approach:
+
+Local Lan 1.0.0.0/24
+ |
+ +- Linux FreeS/WAN 1.0.0.2
+ |
+ | 1.0.0.1
+ Router
+ | 2.0.0.1
+ |
+Internet
+ |
+ | 3.0.0.1
+Mobile User
+ Virtual Address: 1.0.0.3
+
+Note that the Local Lan network (1.0.0.x) can be registered, routable
+addresses.
+
+Now, the Mobile User sets up an IPSec security association with the
+Linux box (1.0.0.2); it should ESP encapsulate all traffic to the
+network 1.0.0.x **EXCEPT** UDP port 500. 500/udp is required for the key
+negotiation, which needs to work outside of the IPSec tunnel.
+
+On the Linux side, there's a bunch of stuff you need to do by hand (for
+now). FreeS/WAN should correctly handle setting up the IPSec SA and
+routes, but I haven't tested it so this may not work...
+
+The FreeS/WAN conn should look like:
+
+conn mobile
+ right=1.0.0.2
+ rightsubnet=1.0.0.0/24
+ rightnexthop=1.0.0.1
+ left=0.0.0.0 # The infamous &quot;road warrior&quot;
+ leftsubnet=1.0.0.3/32
+
+Note that the left subnet contains *only* the remote host's virtual
+address.
+
+Hopefully the routing table on the FreeS/WAN box ends up looking like
+this:
+
+% netstat -rn
+Kernel IP routing table
+Destination Gateway Genmask Flags MSS Window irtt Iface
+1.0.0.0 0.0.0.0 255.255.255.0 U 1500 0 0 eth0
+127.0.0.0 0.0.0.0 255.0.0.0 U 3584 0 0 lo
+0.0.0.0 1.0.0.1 0.0.0.0 UG 1500 0 0 eth0
+1.0.0.3 1.0.0.1 255.255.255.255 UG 1433 0 0 ipsec0
+
+So, if anybody sends a packet for 1.0.0.3 to the Linux box, it should
+get bundled up and sent through the tunnel. To get the packets for
+1.0.0.3 to the Linux box in the first place, you need to use &quot;proxy
+ARP&quot;.
+
+How this works is: when a host or router on the local Ethernet segment
+wants to send a packet to 1.0.0.3, it sends out an Ethernet level
+broadcast &quot;ARP request&quot;. If 1.0.0.3 was on the local LAN, it would
+reply, saying &quot;send IP packets for 1.0.0.3 to my Ethernet address&quot;.
+
+Instead, you need to set up the Linux box so that _it_ answers ARP
+requests for 1.0.0.3, even though that isn't its IP address. That
+convinces everyone else on the lan to send 1.0.0.3 packets to the Linux
+box, where the usual FreeS/WAN processing and routing take over.
+
+% arp -i eth0 -s 1.0.0.3 -D eth0 pub
+
+This says, if you see an ARP request on interface eth0 asking for
+1.0.0.3, respond with the Ethernet address of interface eth0.
+
+Now, as I said at the very beginning, if it is *at all* possible to
+configure your client *not* to use the virtual IP address, you can avoid
+this whole mess.</PRE>
+<H2><A name="dynamic">Dynamic Network Interfaces</A></H2>
+<P>Sometimes you have to cope with a situation where the network
+ interface(s) aren't all there at boot. The common example is notebooks
+ with PCMCIA.</P>
+<H3><A name="basicdyn">Basics</A></H3>
+<P>The key issue here is that the<VAR> config setup</VAR> section of the<VAR>
+ /etc/ipsec.conf</VAR> configuration file lists the connection between
+ ipsecN and hardware interfaces, in the<VAR> interfaces=</VAR> variable.
+ At any time when<VAR> ipsec setup start</VAR> or<VAR> ipsec setup
+ restart</VAR> is run this variable<STRONG> must</STRONG> correspond to
+ the current real situation. More precisely, it<STRONG> must not</STRONG>
+ mention any hardware interfaces which don't currently exist. The
+ difficulty is that an<VAR> ipsec setup start</VAR> command is normally
+ run at boot time so interfaces that are not up then are mis-handled.</P>
+<H3><A name="bootdyn">Boot Time</A></H3>
+<P>Normally, an<VAR> ipsec setup start</VAR> is run at boot time.
+ However, if the hardware situation at boot time is uncertain, one of
+ two things must be done.</P>
+<UL>
+<LI>One possibility is simply not to have IPsec brought up at boot time.
+ To do this:
+<PRE> chkconfig --level 2345 ipsec off</PRE>
+ That's for modern Red Hats or other Linuxes with chkconfig. Systems
+ which lack this will require fiddling with symlinks in /etc/rc.d/rc?.d
+ or the equivalent.</LI>
+<LI>Another possibility is to bring IPsec up with no interfaces, which
+ is less aesthetically satisfying but simpler. Just put
+<PRE> interfaces=</PRE>
+ in the configuration file. KLIPS and Pluto will be started, but won't
+ do anything.</LI>
+</UL>
+<H3><A name="changedyn">Change Time</A></H3>
+<P>When the hardware *is* in place, IPsec has to be made aware of it.
+ Someday there may be a nice way to do this.</P>
+<P>Right now, the way to do it is to fix the<VAR> /etc/ipsec.conf</VAR>
+ file appropriately, so<VAR> interfaces</VAR> reflects the new
+ situation, and then restart the IPsec subsystem. This does break any
+ existing IPsec connections.</P>
+<P>If IPsec wasn't brought up at boot time, do</P>
+<PRE> ipsec setup start</PRE>
+ while if it was, do
+<PRE> ipsec setup restart</PRE>
+ which won't be as quick.
+<P>If some of the hardware is to be taken out, before doing that, amend
+ the configuration file so interfaces no longer includes it, and do</P>
+<PRE> ipsec setup restart</PRE>
+<P>Again, this breaks any existing connections.</P>
+<H2><A name="unencrypted">Unencrypted tunnels</A></H2>
+<P>Sometimes you might want to create a tunnel without encryption. Often
+ this is a bad idea, even if you have some data which need not be
+ private. See this<A href="#traffic.resist"> discussion</A>.</P>
+<P>The IPsec protocols provide two ways to do build such tunnels:</P>
+<DL>
+<DT>using ESP with null encryption</DT>
+<DD>not supported by FreeS/WAN</DD>
+<DT>using<A href="#AH"> AH</A> without<A href="#ESP"> ESP</A></DT>
+<DD>supported for manually keyed connections</DD>
+<DD>possible with explicit commands via<A href="manpage.d/ipsec_whack.8.html">
+ ipsec_whack(8)</A> (see this<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00190.html">
+ list message</A>)</DD>
+<DD>not supported in the<A href="manpage.d/ipsec_auto.8.html">
+ ipsec_auto(8)</A> scripts.</DD>
+</DL>
+ One situation in which this comes up is when otherwise some data would
+ be encrypted twice. Alice wants a secure tunnel from her machine to
+ Bob's. Since she's behind one security gateway and he's behind another,
+ part of the tunnel that they build passes through the tunnel that their
+ site admins have built between the gateways. All of Alice and Bob's
+ messages are encrypted twice.
+<P>There are several ways to handle this.</P>
+<UL>
+<LI>Just accept the overhead of double encryption. The site admins might
+ choose this if any of the following apply:
+<UL>
+<LI>policy says encrypt everything (usually, it should)</LI>
+<LI>they don't entirely trust Alice and Bob (usually, if they don't have
+ to, they shouldn't)</LI>
+<LI>if they don't feel the saved cycles are worth the time they'd need
+ to build a non-encrypted tunnel for Alice and Bob's packets (often,
+ they aren't)</LI>
+</UL>
+</LI>
+<LI>Use a plain IP-in-IP tunnel. These are not well documented. A good
+ starting point is in the Linux kernel source tree, in
+ /usr/src/linux/drivers/net/README.tunnel.</LI>
+<LI>Use a manually-keyed AH-only tunnel.</LI>
+</UL>
+<P>Note that if Alice and Bob want end-to-end security, they must build
+ a tunnel end-to-end between their machines or use some other end-to-end
+ tool such as PGP or SSL that suits their data. The only question is
+ whether the admins build some special unencrypted tunnel for those
+ already-encrypted packets.</P>
+<HR>
+<H1><A name="install">Installing FreeS/WAN</A></H1>
+<P>This document will teach you how to install Linux FreeS/WAN. If your
+ distribution comes with Linux FreeS/WAN, we offer tips to get you
+ started.</P>
+<H2><A NAME="15_1">Requirements</A></H2>
+<P>To install FreeS/WAN you must:</P>
+<UL>
+<LI>be running Linux with the 2.4 or 2.2 kernel series. See this<A HREF="http://www.freeswan.ca/download.php#contact">
+ kernel compatibility table</A>.
+<BR>We also have experimental support for 2.6 kernels. Here are two
+ basic approaches:
+<UL>
+<LI> install FreeS/WAN, including its<A HREF="#parts"> KLIPS</A> kernel
+ code. This will remove the native IPsec stack and replace it with
+ KLIPS.</LI>
+<LI> install the FreeS/WAN<A HREF="#parts"> userland tools</A> (keying
+ daemon and supporting scripts) for use with<A HREF="http://lartc.org/howto/lartc.ipsec.html">
+ 2.6 kernel native IPsec</A>,</LI>
+</UL>
+ See also these<A HREF="2.6.known-issues"> known issues with 2.6</A>.</LI>
+<LI>have root access to your Linux box</LI>
+<LI>choose the version of FreeS/WAN you wish to install based on<A HREF="http://www.freeswan.org/mail.html">
+ mailing list reports</A>
+<!-- or
+our updates page (coming soon)-->
+</LI>
+</UL>
+<H2><A NAME="15_2">Choose your install method</A></H2>
+<P>There are three basic ways to get FreeS/WAN onto your system:</P>
+<UL>
+<LI>activating and testing a FreeS/WAN that<A HREF="#distroinstall">
+ shipped with your Linux distribution</A></LI>
+<LI><A HREF="#rpminstall">RPM install</A></LI>
+<LI><A HREF="#srcinstall">Install from source</A></LI>
+</UL>
+<A NAME="distroinstall"></A>
+<H2><A NAME="15_3">FreeS/WAN ships with some Linuxes</A></H2>
+<P>FreeS/WAN comes with<A HREF="#distwith"> these distributions</A>.</P>
+<P>If you're running one of these, include FreeS/WAN in the choices you
+ make during installation, or add it later using the distribution's
+ tools.</P>
+<H3><A NAME="15_3_1">FreeS/WAN may be altered...</A></H3>
+<P>Your distribution may have integrated extra features, such as Andreas
+ Steffen's X.509 patch, into FreeS/WAN. It may also use custom startup
+ script locations or directory names.</P>
+<H3><A NAME="15_3_2">You might need to create an authentication keypair</A>
+</H3>
+<P>If your FreeS/WAN came with your distribution, you may wish to
+ generate a fresh RSA key pair. FreeS/WAN will use these keys for
+ authentication.</P>
+<P> To do this, become root, and type:</P>
+<PRE> ipsec newhostkey --output /etc/ipsec.secrets --hostname xy.example.com
+ chmod 600 /etc/ipsec.secrets</PRE>
+<P>where you replace xy.example.com with your machine's fully-qualified
+ domain name. Generate some randomness, for example by wiggling your
+ mouse, to speed the process.</P>
+<P>The resulting ipsec.secrets looks like:</P>
+<PRE>: RSA {
+ # RSA 2192 bits xy.example.com Sun Jun 8 13:42:19 2003
+ # for signatures only, UNSAFE FOR ENCRYPTION
+ #pubkey=0sAQOFppfeE3cC7wqJi...
+ Modulus: 0x85a697de137702ef0...
+ # everything after this point is secret
+ PrivateExponent: 0x16466ea5033e807...
+ Prime1: 0xdfb5003c8947b7cc88759065...
+ Prime2: 0x98f199b9149fde11ec956c814...
+ Exponent1: 0x9523557db0da7a885af90aee...
+ Exponent2: 0x65f6667b63153eb69db8f300dbb...
+ Coefficient: 0x90ad00415d3ca17bebff123413fc518...
+ }
+# do not change the indenting of that &quot;}&quot;</PRE>
+<P>In the actual file, the strings are much longer.</P>
+<H3><A NAME="15_3_3">Start and test FreeS/WAN</A></H3>
+<P>You can now<A HREF="#starttest"> start FreeS/WAN and test whether
+ it's been successfully installed.</A>.</P>
+<A NAME="rpminstall"></A>
+<H2><A NAME="15_4">RPM install</A></H2>
+<P>These instructions are for a recent Red Hat with a stock Red Hat
+ kernel. We know that Mandrake and SUSE also produce FreeS/WAN RPMs. If
+ you're running either, install using your distribution's tools.</P>
+<H3><A NAME="15_4_1">Download RPMs</A></H3>
+<P>Decide which functionality you need:</P>
+<UL>
+<LI>standard FreeS/WAN RPMs. Use these shortcuts:
+<BR>
+<UL>
+<LI>(for 2.6 kernels: userland only)
+<BR> ncftpget
+ ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs/\*userland*
+</LI>
+<LI>(for 2.4 kernels)
+<BR> ncftpget
+ ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs/`uname -r
+ | tr -d 'a-wy-z'`/\*</LI>
+<LI> or view all the offerings at our<A href="ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs">
+ FTP site</A>.</LI>
+</UL>
+</LI>
+<LI>unofficial<A href="http://www.freeswan.ca/download.php"> Super
+ FreeS/WAN</A> RPMs, which include Andreas Steffen's X.509 patch and
+ more. Super FreeS/WAN RPMs do not currently include<A HREF="#NAT.gloss">
+ Network Address Translation</A> (NAT) traversal, but Super FreeS/WAN
+ source does.</LI>
+</UL>
+<A NAME="2.6.rpm"></A>
+<P>For 2.6 kernels, get the latest FreeS/WAN userland RPM, for example:</P>
+<PRE> freeswan-userland-2.04.9-0.i386.rpm</PRE>
+<P>Note: FreeS/WAN's support for 2.6 kernel IPsec is preliminary. Please
+ see<A HREf="2.6.known-issues"> 2.6.known-issues</A>, and the latest<A HREF="http://www.freeswan.org/mail.html">
+ mailing list reports</A>.</P>
+<P>Change to your new FreeS/WAN directory, and make and install the</P>
+<P>For 2.4 kernels, get both kernel and userland RPMs. Check your kernel
+ version with</P>
+<PRE> uname -r</PRE>
+<P>Get a kernel module which matches that version. For example:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<P>Note: These modules<B> will only work on the Red Hat kernel they were
+ built for</B>, since they are very sensitive to small changes in the
+ kernel.</P>
+<P>Get FreeS/WAN utilities to match. For example:</P>
+<PRE> freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<H3><A NAME="15_4_2">For freeswan.org RPMs: check signatures</A></H3>
+<P>While you're at our ftp site, grab the RPM signing key</P>
+<PRE> freeswan-rpmsign.asc</PRE>
+<P>If you're running RedHat 8.x or later, import this key into the RPM
+ database:</P>
+<PRE> rpm --import freeswan-rpmsign.asc</PRE>
+<P>For RedHat 7.x systems, you'll need to add it to your<A HREF="#PGP">
+ PGP</A> keyring:</P>
+<PRE> pgp -ka freeswan-rpmsign.asc</PRE>
+<P>Check the digital signatures on both RPMs using:</P>
+<PRE> rpm --checksig freeswan*.rpm </PRE>
+<P>You should see that these signatures are good:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK
+ freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK</PRE>
+<H3><A NAME="15_4_3">Install the RPMs</A></H3>
+<P>Become root:</P>
+<PRE> su</PRE>
+<P>For a first time install, use:</P>
+<PRE> rpm -ivh freeswan*.rpm</PRE>
+<P>To upgrade existing RPMs (and keep all .conf files in place), use:</P>
+<PRE> rpm -Uvh freeswan*.rpm</PRE>
+<P>If you're upgrading from FreeS/WAN 1.x to 2.x RPMs, and encounter
+ problems, see<A HREF="#upgrading.rpms"> this note</A>.</P>
+<H3><A NAME="15_4_4">Start and Test FreeS/WAN</A></H3>
+<P>Now,<A HREF="#starttest"> start FreeS/WAN and test your install</A>.</P>
+<A NAME="srcinstall"></A>
+<H2><A NAME="15_5">Install from Source</A></H2>
+
+<!-- Most of this section, along with "Start and Test", can replace
+INSTALL. -->
+<H3><A NAME="15_5_1">Decide what functionality you need</A></H3>
+<P>Your choices are:</P>
+<UL>
+<LI><A HREF="ftp://ftp.xs4all.nl/pub/crypto/freeswan">standard FreeS/WAN</A>
+,</LI>
+<LI>standard FreeS/WAN plus any of these<A HREF="#patch"> user-supported
+ patches</A>, or</LI>
+<LI><A HREF="http://www.freeswan.ca/download">Super FreeS/WAN</A>, an
+ unofficial FreeS/WAN pre-patched with many of the above. Provides
+ additional algorithms, X.509, SA deletion, dead peer detection, and<A HREF="#NAT.gloss">
+ Network Address Translation</A> (NAT) traversal.</LI>
+</UL>
+<H3><A NAME="15_5_2">Download FreeS/WAN</A></H3>
+<P>Download the source tarball you've chosen, along with any patches.</P>
+<H3><A NAME="15_5_3">For freeswan.org source: check its signature</A></H3>
+<P>While you're at our ftp site, get our source signing key</P>
+<PRE> freeswan-sigkey.asc</PRE>
+<P>Add it to your PGP keyring:</P>
+<PRE> pgp -ka freeswan-sigkey.asc</PRE>
+<P>Check the signature using:</P>
+<PRE> pgp freeswan-2.04.tar.gz.sig freeswan-2.04.tar.gz</PRE>
+<P>You should see something like:</P>
+<PRE> Good signature from user &quot;Linux FreeS/WAN Software Team (build@freeswan.org)&quot;.
+ Signature made 2002/06/26 21:04 GMT using 2047-bit key, key ID 46EAFCE1</PRE>
+
+<!-- Note to self: build@freeswan.org has angled brackets in the original.
+ Changed because it conflicts with HTML tags. -->
+<H3><A NAME="15_5_4">Untar, unzip</A></H3>
+<P>As root, unpack your FreeS/WAN source into<VAR> /usr/src</VAR>.</P>
+<PRE> su
+ mv freeswan-2.04.tar.gz /usr/src
+ cd /usr/src
+ tar -xzf freeswan-2.04.tar.gz
+</PRE>
+<H3><A NAME="15_5_5">Patch if desired</A></H3>
+<P>Now's the time to add any patches. The contributor may have special
+ instructions, or you may simply use the patch command.</P>
+<H3><A NAME="15_5_6">... and Make</A></H3>
+<P>Choose one of the methods below.</P>
+<H4><A NAME="15_5_6_1">Userland-only Install for 2.6 kernels</A></H4>
+<A NAME="2.6.src"></A>
+<P>Note: FreeS/WAN's support for 2.6 kernel IPsec is preliminary. Please
+ see<A HREf="2.6.known-issues"> 2.6.known-issues</A>, and the latest<A HREF="http://www.freeswan.org/mail.html">
+ mailing list reports</A>.</P>
+<P>Change to your new FreeS/WAN directory, and make and install the
+ FreeS/WAN userland tools.</P>
+<PRE> cd /usr/src/freeswan-2.04
+ make programs
+ make install</PRE>
+<P>Now,<A HREF="#starttest"> start FreeS/WAN and test your install</A>.</P>
+<H4><A NAME="15_5_6_2">KLIPS install for 2.2, 2.4, or 2.6 kernels</A></H4>
+<A NAME="modinstall"></A>
+<P>To make a modular version of KLIPS, along with other FreeS/WAN
+ programs you'll need, use the command sequence below. This will change
+ to your new FreeS/WAN directory, make the FreeS/WAN module (and other
+ stuff), and install it all.</P>
+<PRE> cd /usr/src/freeswan-2.04
+ make oldmod
+ make minstall</PRE>
+<P><A HREF="#starttest">Start FreeS/WAN and test your install</A>.</P>
+<P>To link KLIPS statically into your kernel (using your old kernel
+ settings), and install other FreeS/WAN components, do:</P>
+<PRE> cd /usr/src/freeswan-2.04
+ make oldmod
+ make minstall</PRE>
+<P>Reboot your system and<A HREF="#testonly"> test your install</A>.</P>
+<P>For other ways to compile KLIPS, see our Makefile.</P>
+<A name="starttest"></A>
+<H2><A NAME="15_6">Start FreeS/WAN and test your install</A></H2>
+<P>Bring FreeS/WAN up with:</P>
+<PRE> service ipsec start</PRE>
+<P>This is not necessary if you've rebooted.</P>
+<A name="testonly"></A>
+<H2><A NAME="15_7">Test your install</A></H2>
+<P>To check that you have a successful install, run:</P>
+<PRE> ipsec verify</PRE>
+<P>You should see at least:</P>
+<PRE>
+ Checking your system to see if IPsec got installed and started correctly
+ Version check and ipsec on-path [OK]
+ Checking for KLIPS support in kernel [OK]
+ Checking for RSA private key (/etc/ipsec.secrets) [OK]
+ Checking that pluto is running [OK]
+</PRE>
+<P>If any of these first four checks fails, see our<A href="#install.check">
+ troubleshooting guide</A>.</P>
+<H2><A NAME="15_8">Making FreeS/WAN play well with others</A></H2>
+<P>There are at least a couple of things on your system that might
+ interfere with FreeS/WAN, and now's a good time to check these:</P>
+<UL>
+<LI>Firewalling. You need to allow UDP 500 through your firewall, plus
+ ESP (protocol 50) and AH (protocol 51). For more information, see our
+ updated firewalls document (coming soon).</LI>
+<LI>Network address translation. Do not NAT the packets you will be
+ tunneling.</LI>
+</UL>
+<H2><A NAME="15_9">Configure for your needs</A></H2>
+<P>You'll need to configure FreeS/WAN for your local site. Have a look
+ at our<A HREF="quickstart.html"> opportunism quickstart guide</A> to
+ see if that easy method is right for your needs. Or, see how to<A HREF="config.html">
+ configure a network-to-network or Road Warrior style VPN</A>.</P>
+<HR>
+<H1><A NAME="config">How to configure FreeS/WAN</A></H1>
+<P>This page will teach you how to configure a simple network-to-network
+ link or a Road Warrior connection between two Linux FreeS/WAN boxes.</P>
+<P>See also these related documents:</P>
+<UL>
+<LI>our<A HREF="#quickstart"> quickstart</A> guide to<A HREF="#carpediem">
+ opportunistic encryption</A></LI>
+<LI>our guide to configuration with<A HREF="#policygroups"> policy
+ groups</A></LI>
+<LI>our<A HREF="#adv_config"> advanced configuration</A> document</LI>
+</UL>
+<P> The network-to-network setup allows you to connect two office
+ networks into one Virtual Private Network, while the Road Warrior
+ connection secures a laptop's telecommute to work. Our examples also
+ show the basic procedure on the Linux FreeS/WAN side where another
+ IPsec peer is in play.</P>
+<P> Shortcut to<A HREF="#config.netnet"> net-to-net</A>.
+<BR> Shortcut to<A HREF="#config.rw"> Road Warrior</A>.</P>
+<H2><A NAME="16_1">Requirements</A></H2>
+<P>To configure the network-to-network connection you must have:</P>
+<UL>
+<LI>two Linux gateways with static IPs</LI>
+<LI>a network behind each gate. Networks must have non-overlapping IP
+ ranges.</LI>
+<LI>Linux FreeS/WAN<A HREF="#install"> installed</A> on both gateways</LI>
+<LI><A HREF="http://www.tcpdump.org"><VAR>tcpdump</VAR></A> on the local
+ gate, to test the connection</LI>
+</UL>
+<P>For the Road Warrior you need:</P>
+<UL>
+<LI>one Linux box with a static IP</LI>
+<LI>a Linux laptop with a dynamic IP</LI>
+<LI>Linux FreeS/WAN installed on both</LI>
+<LI>for testing,<VAR> tcpdump</VAR> on your gateway or laptop</LI>
+</UL>
+<P>If both IPs are dynamic, your situation is a bit trickier. Your best
+ bet is a variation on the<A HREF="#config.rw"> Road Warrior</A>, as
+ described in<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00282.html">
+ this mailing list message</A>.</P>
+<H2><A name="config.netnet"></A>Net-to-Net connection</H2>
+<H3><A name="netnet.info.ex">Gather information</A></H3>
+<P>For each gateway, compile the following information:</P>
+<UL>
+<LI>gateway IP</LI>
+<LI>IP range of the subnet you will be protecting. This doesn't have to
+ be your whole physical subnet.</LI>
+<LI>a name by which that gateway can identify itself for IPsec
+ negotiations. Its form is a Fully Qualified Domain Name preceded by an
+ @ sign, ie. @xy.example.com.
+<BR> It does not need to be within a domain that you own. It can be a
+ made-up name.</LI>
+</UL>
+<H4><A NAME="16_2_1_1">Get your leftrsasigkey</A></H4>
+<P>On your local Linux FreeS/WAN gateway, print your IPsec public key:</P>
+<PRE> ipsec showhostkey --left</PRE>
+<P>The output should look like this (with the key shortened for easy
+ reading):</P>
+<PRE> # RSA 2048 bits xy.example.com Fri Apr 26 15:01:41 2002
+ leftrsasigkey=0sAQOnwiBPt...</PRE>
+<P>Don't have a key? Use<A HREF="manpage.d/ipsec_newhostkey.8.html"><VAR>
+ ipsec newhostkey</VAR></A> to create one.</P>
+<H4><A NAME="16_2_1_2">...and your rightrsasigkey</A></H4>
+<P>Get a console on the remote side:</P>
+<PRE> ssh2 ab.example.com</PRE>
+<P>In that window, type:</P>
+<PRE> ipsec showhostkey --right</PRE>
+<P>You'll see something like:</P>
+<PRE> # RSA 2192 bits ab.example.com Thu May 16 15:26:20 2002
+ rightrsasigkey=0sAQOqH55O...</PRE>
+<H3><A NAME="16_2_2">Edit<VAR> /etc/ipsec.conf</VAR></A></H3>
+<P>Back on the local gate, copy our template to<VAR> /etc/ipsec.conf</VAR>
+. (on Mandrake,<VAR> /etc/freeswan/ipsec.conf</VAR>). Substitute the
+ information you've gathered for our example data.</P>
+<PRE>conn net-to-net
+ left=192.0.2.2 # Local vitals
+ leftsubnet=192.0.2.128/29 #
+ leftid=@xy.example.com #
+ leftrsasigkey=0s1LgR7/oUM... #
+ leftnexthop=%defaultroute # correct in many situations
+ right=192.0.2.9 # Remote vitals
+ rightsubnet=10.0.0.0/24 #
+ rightid=@ab.example.com #
+ rightrsasigkey=0sAQOqH55O... #
+ rightnexthop=%defaultroute # correct in many situations
+ auto=add # authorizes but doesn't start this
+ # connection at startup</PRE>
+<P> &quot;Left&quot; and &quot;right&quot; should represent the machines that have FreeS/WAN
+ installed on them, and &quot;leftsubnet&quot; and &quot;rightsubnet&quot; machines that are
+ being protected. /32 is assumed for left/right and left/rightsubnet
+ parameters.</P>
+<P>Copy<VAR> conn net-to-net</VAR> to the remote-side /etc/ipsec.conf.
+ If you've made no other modifications to either<VAR> ipsec.conf</VAR>,
+ simply:</P>
+<PRE> scp2 ipsec.conf root@ab.example.com:/etc/ipsec.conf</PRE>
+<H3><A NAME="16_2_3">Start your connection</A></H3>
+<P>Locally, type:</P>
+<PRE> ipsec auto --up net-to-net</PRE>
+<P>You should see:</P>
+<PRE> 104 &quot;net-net&quot; #223: STATE_MAIN_I1: initiate
+ 106 &quot;net-net&quot; #223: STATE_MAIN_I2: sent MI2, expecting MR2
+ 108 &quot;net-net&quot; #223: STATE_MAIN_I3: sent MI3, expecting MR3
+ 004 &quot;net-net&quot; #223: STATE_MAIN_I4: ISAKMP SA established
+ 112 &quot;net-net&quot; #224: STATE_QUICK_I1: initiate
+ 004 &quot;net-net&quot; #224: STATE_QUICK_I2: sent QI2, IPsec SA established</PRE>
+<P>The important thing is<VAR> IPsec SA established</VAR>. If you're
+ unsuccessful, see our<A HREF="#trouble"> troubleshooting tips</A>.</P>
+<H3><A NAME="16_2_4">Do not MASQ or NAT packets to be tunneled</A></H3>
+<P>If you are using<A HREF="#masq"> IP masquerade</A> or<A HREF="#NAT.gloss">
+ Network Address Translation (NAT)</A> on either gateway, you must now
+ exempt the packets you wish to tunnel from this treatment. For example,
+ if you have a rule like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -j MASQUERADE
+</PRE>
+<P>change it to something like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -d \! 192.0.2.128/29 -j MASQUERADE</PRE>
+<P>This may be necessary on both gateways.</P>
+<H3><A NAME="16_2_5">Test your connection</A></H3>
+<P>Sit at one of your local subnet nodes (not the gateway), and ping a
+ subnet node on the other (again, not the gateway).</P>
+<PRE> ping fileserver.toledo.example.com</PRE>
+<P>While still pinging, go to the local gateway and snoop your outgoing
+ interface, for example:</P>
+<PRE> tcpdump -i ppp0</PRE>
+<P>You want to see ESP (Encapsulating Security Payload) packets moving<B>
+ back and forth</B> between the two gateways at the same frequency as
+ your pings:</P>
+<PRE> 19:16:32.046220 192.0.2.2 &gt; 192.0.2.9: ESP(spi=0x3be6c4dc,seq=0x3)
+ 19:16:32.085630 192.0.2.9 &gt; 192.0.2.2: ESP(spi=0x5fdd1cf8,seq=0x6)</PRE>
+<P>If you see this, congratulations are in order! You have a tunnel
+ which will protect any IP data from one subnet to the other, as it
+ passes between the two gates. If not, go and<A HREF="#trouble">
+ troubleshoot</A>.</P>
+<P>Note: your new tunnel protects only net-net traffic, not
+ gateway-gateway, or gateway-subnet. If you need this (for example, if
+ machines on one net need to securely contact a fileserver on the IPsec
+ gateway), you'll need to create<A HREF="#adv_config"> extra connections</A>
+.</P>
+<H3><A NAME="16_2_6">Finishing touches</A></H3>
+<P>Now that your connection works, name it something sensible, like:</P>
+<PRE>conn winstonnet-toledonet</PRE>
+<P>To have the tunnel come up on-boot, replace</P>
+<PRE> auto=add</PRE>
+<P>with:</P>
+<PRE> auto=start</PRE>
+<P>Copy these changes to the other side, for example:</P>
+<PRE> scp2 ipsec.conf root@ab.example.com:/etc/ipsec.conf</PRE>
+<P>Enjoy!</P>
+<H2><A name="config.rw"></A>Road Warrior Configuration</H2>
+<H3><A name="rw.info.ex">Gather information</A></H3>
+<P>You'll need to know:</P>
+<UL>
+<LI>the gateway's static IP</LI>
+<LI>the IP range of the subnet behind that gateway</LI>
+<LI>a name by which each side can identify itself for IPsec
+ negotiations. Its form is a Fully Qualified Domain Name preceded by an
+ @ sign, ie. @road.example.com.
+<BR> It does not need to be within a domain that you own. It can be a
+ made-up name.</LI>
+</UL>
+<H4><A NAME="16_3_1_1">Get your leftrsasigkey...</A></H4>
+<P>On your laptop, print your IPsec public key:</P>
+<PRE> ipsec showhostkey --left</PRE>
+<P>The output should look like this (with the key shortened for easy
+ reading):</P>
+<PRE> # RSA 2192 bits road.example.com Sun Jun 9 02:45:02 2002
+ leftrsasigkey=0sAQPIPN9uI...</PRE>
+<P>Don't have a key? See<A HREF="old_config.html#genrsakey"> these
+ instructions</A>.</P>
+<H4><A NAME="16_3_1_2">...and your rightrsasigkey</A></H4>
+<P>Get a console on the gateway:</P>
+<PRE> ssh2 xy.example.com</PRE>
+<P>View the gateway's public key with:</P>
+<PRE> ipsec showhostkey --right</PRE>
+<P>This will yield something like</P>
+<PRE> # RSA 2048 bits xy.example.com Fri Apr 26 15:01:41 2002
+ rightrsasigkey=0sAQOnwiBPt...</PRE>
+<H3><A NAME="16_3_2">Customize<VAR> /etc/ipsec.conf</VAR></A></H3>
+<P>On your laptop, copy this template to<VAR> /etc/ipsec.conf</VAR>. (on
+ Mandrake,<VAR> /etc/freeswan/ipsec.conf</VAR>). Substitute the
+ information you've gathered for our example data.</P>
+<PRE>conn road
+ left=%defaultroute # Picks up our dynamic IP
+ leftnexthop=%defaultroute #
+ leftid=@road.example.com # Local information
+ leftrsasigkey=0sAQPIPN9uI... #
+ right=192.0.2.10 # Remote information
+ rightsubnet=10.0.0.0/24 #
+ rightid=@xy.example.com #
+ rightrsasigkey=0sAQOnwiBPt... #
+ auto=add # authorizes but doesn't start this
+ # connection at startup</PRE>
+<P>The template for the gateway is different. Notice how it reverses<VAR>
+ left</VAR> and<VAR> right</VAR>, in keeping with our convention that<STRONG>
+ L</STRONG>eft is<STRONG> L</STRONG>ocal,<STRONG> R</STRONG>ight<STRONG>
+ R</STRONG>emote. Be sure to switch your rsasigkeys in keeping with
+ this.</P>
+<PRE> ssh2 xy.example.com
+ vi /etc/ipsec.conf</PRE>
+<P>and add:</P>
+<PRE>conn road
+ left=192.0.2.2 # Gateway's information
+ leftid=@xy.example.com #
+ leftsubnet=192.0.2.128/29 #
+ leftrsasigkey=0sAQOnwiBPt... #
+ rightnexthop=%defaultroute # correct in many situations
+ right=%any # Wildcard: we don't know the laptop's IP
+ rightid=@road.example.com #
+ rightrsasigkey=0sAQPIPN9uI... #
+ auto=add # authorizes but doesn't start this
+ # connection at startup</PRE>
+<H3><A NAME="16_3_3">Start your connection</A></H3>
+<P>You must start the connection from the Road Warrior side. On your
+ laptop, type:</P>
+<PRE> ipsec auto --start net-to-net</PRE>
+<P>You should see:</P>
+<PRE>104 &quot;net-net&quot; #223: STATE_MAIN_I1: initiate
+106 &quot;road&quot; #301: STATE_MAIN_I2: sent MI2, expecting MR2
+108 &quot;road&quot; #301: STATE_MAIN_I3: sent MI3, expecting MR3
+004 &quot;road&quot; #301: STATE_MAIN_I4: ISAKMP SA established
+112 &quot;road&quot; #302: STATE_QUICK_I1: initiate
+004 &quot;road&quot; #302: STATE_QUICK_I2: sent QI2, IPsec SA established</PRE>
+<P>Look for<VAR> IPsec SA established</VAR>. If you're unsuccessful, see
+ our<A HREF="#trouble"> troubleshooting tips</A>.</P>
+<H3><A NAME="16_3_4">Do not MASQ or NAT packets to be tunneled</A></H3>
+<P>If you are using<A HREF="#masq"> IP masquerade</A> or<A HREF="#NAT.gloss">
+ Network Address Translation (NAT)</A> on either gateway, you must now
+ exempt the packets you wish to tunnel from this treatment. For example,
+ if you have a rule like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -j MASQUERADE
+</PRE>
+<P>change it to something like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -d \! 192.0.2.128/29 -j MASQUERADE</PRE>
+<H3><A NAME="16_3_5">Test your connection</A></H3>
+<P>From your laptop, ping a subnet node behind the remote gateway. Do
+ not choose the gateway itself for this test.</P>
+<PRE> ping ns.winston.example.com</PRE>
+<P>Snoop the packets exiting the laptop, with a command like:</P>
+<PRE> tcpdump -i wlan0</PRE>
+<P>You have success if you see (Encapsulating Security Payload) packets
+ travelling<B> in both directions</B>:</P>
+<PRE> 19:16:32.046220 192.0.2.2 &gt; 192.0.2.9: ESP(spi=0x3be6c4dc,seq=0x3)
+ 19:16:32.085630 192.0.2.9 &gt; 192.0.2.2: ESP(spi=0x5fdd1cf8,seq=0x6)</PRE>
+<P>If you do, great! Traffic between your Road Warrior and the net
+ behind your gateway is protected. If not, see our<A HREF="#trouble">
+ troubleshooting hints</A>.</P>
+<P>Your new tunnel protects only traffic addressed to the net, not to
+ the IPsec gateway itself. If you need the latter, you'll want to make
+ an<A HREF="#adv_config"> extra tunnel.</A>.</P>
+<H3><A NAME="16_3_6">Finishing touches</A></H3>
+<P>On both ends, name your connection wisely, like:</P>
+<PRE>conn mike-to-office</PRE>
+<P><B>On the laptop only,</B> replace</P>
+<PRE> auto=add</PRE>
+<P>with:</P>
+<PRE> auto=start</PRE>
+<P>so that you'll be connected on-boot.</P>
+<P>Happy telecommuting!</P>
+<H3><A NAME="16_3_7">Multiple Road Warriors</A></H3>
+<P>If you're using RSA keys, as we did in this example, you can add as
+ many Road Warriors as you like. The left/rightid parameter lets Linux
+ FreeS/WAN distinguish between multiple Road Warrior peers, each with
+ its own public key.</P>
+<P>The situation is different for shared secrets (PSK). During a PSK
+ negotiation, ID information is not available at the time Pluto is
+ trying to determine which secret to use, so, effectively, you can only
+ define one Roadwarrior connection. All your PSK road warriors must
+ therefore share one secret.</P>
+<H2><A NAME="16_4">What next?</A></H2>
+<P>Using the principles illustrated here, you can try variations such
+ as:</P>
+<UL>
+<LI>a telecommuter with a static IP</LI>
+<LI>a road warrior with a subnet behind it</LI>
+</UL>
+<P>Or, look at some of our<A HREF="#adv_config"> more complex
+ configuration examples.</A>.</P>
+<HR>
+<H1><A name="background">Linux FreeS/WAN background</A></H1>
+<P>This section discusses a number of issues which have three things in
+ common:</P>
+<UL>
+<LI>They are not specifically FreeS/WAN problems</LI>
+<LI>You may have to understand them to get FreeS/WAN working right</LI>
+<LI>They are not simple questions</LI>
+</UL>
+<P>Grouping them here lets us provide the explanations some users will
+ need without unduly complicating the main text.</P>
+<P>The explanations here are intended to be adequate for FreeS/WAN
+ purposes (please comment to the<A href="mail.html"> users mailing list</A>
+ if you don't find them so), but they are not trying to be complete or
+ definitive. If you need more information, see the references provided
+ in each section.</P>
+<H2><A name="dns.background">Some DNS background</A></H2>
+<P><A href="#carpediem">Opportunistic encryption</A> requires that the
+ gateway systems be able to fetch public keys, and other IPsec-related
+ information, from each other's DNS (Domain Name Service) records.</P>
+<P><A href="#DNS">DNS</A> is a distributed database that maps names to
+ IP addresses and vice versa.</P>
+<P>Much good reference material is available for DNS, including:</P>
+<UL>
+<LI>the<A href="http://www.linuxdoc.org/HOWTO/DNS-HOWTO.html"> DNS HowTo</A>
+</LI>
+<LI>the standard<A href="#DNS.book"> DNS reference</A> book</LI>
+<LI><A href="http://www.linuxdoc.org/LDP/nag2/index.html">Linux Network
+ Administrator's Guide</A></LI>
+<LI><A href="http://www.nominum.com/resources/whitepapers/bind-white-paper.html">
+BIND overview</A></LI>
+<LI><A href="http://www.nominum.com/resources/documentation/Bv9ARM.pdf">
+BIND 9 Administrator's Reference</A></LI>
+</UL>
+<P>We give only a brief overview here, intended to help you use DNS for
+ FreeS/WAN purposes.</P>
+<H3><A name="forward.reverse">Forward and reverse maps</A></H3>
+<P>Although the implementation is distributed, it is often useful to
+ speak of DNS as if it were just two enormous tables:</P>
+<UL>
+<LI>the forward map: look up a name, get an IP address</LI>
+<LI>the reverse map: look up an IP address, get a name</LI>
+</UL>
+<P>Both maps can optionally contain additional data. For opportunistic
+ encryption, we insert the data need for IPsec authentication.</P>
+<P>A system named gateway.example.com with IP address 10.20.30.40 should
+ have at least two DNS records, one in each map:</P>
+<DL>
+<DT>gateway.example.com. IN A 10.20.30.40</DT>
+<DD>used to look up the name and get an IP address</DD>
+<DT>40.30.20.10.in-addr.arpa. IN PTR gateway.example.com.</DT>
+<DD>used for reverse lookups, looking up an address to get the
+ associated name. Notice that the digits here are in reverse order; the
+ actual address is 10.20.30.40 but we use 40.30.20.10 here.</DD>
+</DL>
+<H3><A NAME="17_1_2">Hierarchy and delegation</A></H3>
+<P>For both maps there is a hierarchy of DNS servers and a system of
+ delegating authority so that, for example:</P>
+<UL>
+<LI>the DNS administrator for example.com can create entries of the form<VAR>
+ name</VAR>.example.com</LI>
+<LI>the example.com admin cannot create an entry for counterexample.com;
+ only someone with authority for .com can do that</LI>
+<LI>an admin might have authority for 20.10.in-addr.arpa.</LI>
+<LI>in either map, authority can be delegated
+<UL>
+<LI>the example.com admin could give you authority for
+ westcoast.example.com</LI>
+<LI>the 20.10.in-addr.arpa admin could give you authority for
+ 30.20.10.in-addr.arpa</LI>
+</UL>
+</LI>
+</UL>
+<P>DNS zones are the units of delegation. There is a hierarchy of zones.</P>
+<H3><A NAME="17_1_3">Syntax of DNS records</A></H3>
+<P>Returning to the example records:</P>
+<PRE> gateway.example.com. IN A 10.20.30.40
+ 40.30.20.10.in-addr.arpa. IN PTR gateway.example.com.</PRE>
+<P>some syntactic details are:</P>
+<UL>
+<LI>the IN indicates that these records are for<STRONG> In</STRONG>
+ternet addresses</LI>
+<LI>The final periods in '.com.' and '.arpa.' are required. They
+ indicate the root of the domain name system.</LI>
+</UL>
+<P>The capitalised strings after IN indicate the type of record.
+ Possible types include:</P>
+<UL>
+<LI><STRONG>A</STRONG>ddress, for forward lookups</LI>
+<LI><STRONG>P</STRONG>oin<STRONG>T</STRONG>e<STRONG>R</STRONG>, for
+ reverse lookups</LI>
+<LI><STRONG>C</STRONG>anonical<STRONG> NAME</STRONG>, records to support
+ aliasing, multiple names for one address</LI>
+<LI><STRONG>M</STRONG>ail e<STRONG>X</STRONG>change, used in mail
+ routing</LI>
+<LI><STRONG>SIG</STRONG>nature, used in<A href="#SDNS"> secure DNS</A></LI>
+<LI><STRONG>KEY</STRONG>, used in<A href="#SDNS"> secure DNS</A></LI>
+<LI><STRONG>T</STRONG>e<STRONG>XT</STRONG>, a multi-purpose record type</LI>
+</UL>
+<P>To set up for opportunistic encryption, you add some TXT records to
+ your DNS data. Details are in our<A href="quickstart.html"> quickstart</A>
+ document.</P>
+<H3><A NAME="17_1_4">Cacheing, TTL and propagation delay</A></H3>
+<P>DNS information is extensively cached. With no caching, a lookup by
+ your system of &quot;www.freeswan.org&quot; might involve:</P>
+<UL>
+<LI>your system asks your nameserver for &quot;www.freeswan.org&quot;</LI>
+<LI>local nameserver asks root server about &quot;.org&quot;, gets reply</LI>
+<LI>local nameserver asks .org nameserver about &quot;freeswan.org&quot;, gets
+ reply</LI>
+<LI>local nameserver asks freeswan.org nameserver about
+ &quot;www.freeswan.org&quot;, gets reply</LI>
+</UL>
+<P>However, this can be a bit inefficient. For example, if you are in
+ the Phillipines, the closest a root server is in Japan. That might send
+ you to a .org server in the US, and then to freeswan.org in Holland. If
+ everyone did all those lookups every time they clicked on a web link,
+ the net would grind to a halt.</P>
+<P>Nameservers therefore cache information they look up. When you click
+ on another link at www.freeswan.org, your local nameserver has the IP
+ address for that server in its cache, and no further lookups are
+ required.</P>
+<P>Intermediate results are also cached. If you next go to
+ lists.freeswan.org, your nameserver can just ask the freeswan.org
+ nameserver for that address; it does not need to query the root or .org
+ nameservers because it has a cached address for the freeswan.org zone
+ server.</P>
+<P>Of course, like any cacheing mechanism, this can create problems of
+ consistency. What if the administrator for freeswan.org changes the IP
+ address, or the authentication key, for www.freeswan.org? If you use
+ old information from the cache, you may get it wrong. On the other
+ hand, you cannot afford to look up fresh information every time. Nor
+ can you expect the freeswan.org server to notify you; that isn't in the
+ protocols.</P>
+<P>The solution that is in the protocols is fairly simple. Cacheable
+ records are marked with Time To Live (TTL) information. When the time
+ expires, the caching server discards the record. The next time someone
+ asks for it, the server fetches a fresh copy. Of course, a server may
+ also discard records before their TTL expires if it is running out of
+ cache space.</P>
+<P>This implies that there will be some delay before the new version of
+ a changed record propagates around the net. Until the TTLs on all
+ copies of the old record expire, some users will see it because that is
+ what is in their cache. Other users may see the new record immediately
+ because they don't have an old one cached.</P>
+<H2><A name="MTU.trouble">Problems with packet fragmentation</A></H2>
+<P>It seems, from mailing list reports, to be moderately common for
+ problems to crop up in which small packets pass through the IPsec
+ tunnels just fine but larger packets fail.</P>
+<P>These problems are caused by various devices along the way
+ mis-handling either packet fragments or<A href="#pathMTU"> path MTU
+ discovery</A>.</P>
+<P>IPsec makes packets larger by adding an ESP or AH header. This can
+ tickle assorted bugs in fragment handling in routers and firewalls, or
+ in path MTU discovery mechanisms, and cause a variety of symptoms which
+ are both annoying and, often, quite hard to diagnose.</P>
+<P>An explanation from project technical lead Henry Spencer:</P>
+<PRE>The problem is IP fragmentation; more precisely, the problem is that the
+second, third, etc. fragments of an IP packet are often difficult for
+filtering mechanisms to classify.
+
+Routers cannot rely on reassembling the packet, or remembering what was in
+earlier fragments, because the fragments may be out of order or may even
+follow different routes. So any general, worst-case filtering decision
+pretty much has to be made on each fragment independently. (If the router
+knows that it is the only route to the destination, so all fragments
+*must* pass through it, reassembly would be possible... but most routers
+don't want to bother with the complications of that.)
+
+All fragments carry roughly the original IP header, but any higher-level
+header is (for IP purposes) just the first part of the packet data... so
+only the first fragment carries that. So, for example, on examining the
+second fragment of a TCP packet, you could tell that it's TCP, but not
+what port number it is destined for -- that information is in the TCP
+header, which appears in the first fragment only.
+
+The result of this classification difficulty is that stupid routers and
+over-paranoid firewalls may just throw fragments away. To get through
+them, you must reduce your MTU enough that fragmentation will not occur.
+(In some cases, they might be willing to attempt reassembly, but have very
+limited resources to devote to it, meaning that packets must be small and
+fragments few in number, leading to the same conclusion: smaller MTU.)</PRE>
+<P>In addition to the problem Henry describes, you may also have trouble
+ with<A href="#pathMTU"> path MTU discovery</A>.</P>
+<P>By default, FreeS/WAN uses a large<A href="#MTU"> MTU</A> for the
+ ipsec device. This avoids some problems, but may complicate others.
+ Here's an explanation from Claudia:</P>
+<PRE>Here are a couple of pieces of background information. Apologies if you
+have seen these already. An excerpt from one of my old posts:
+
+ An MTU of 16260 on ipsec0 is usual. The IPSec device defaults to this
+ high MTU so that it does not fragment incoming packets before encryption
+ and encapsulation. If after IPSec processing packets are larger than 1500,
+ [ie. the mtu of eth0] then eth0 will fragment them.
+
+ Adding IPSec headers adds a certain number of bytes to each packet.
+ The MTU of the IPSec interface refers to the maximum size of the packet
+ before the IPSec headers are added. In some cases, people find it helpful
+ to set ipsec0's MTU to 1500-(IPSec header size), which IIRC is about 1430.
+
+ That way, the resulting encapsulated packets don't exceed 1500. On most
+ networks, packets less than 1500 will not need to be fragmented.
+
+and... (from Henry Spencer)
+
+ The way it *ought* to work is that the MTU advertised by the ipsecN
+ interface should be that of the underlying hardware interface, less a
+ pinch for the extra headers needed.
+
+ Unfortunately, in certain situations this breaks many applications.
+ There is a widespread implicit assumption that the smallest MTUs are
+ at the ends of paths, not in the middle, and another that MTUs are
+ never less than 1500. A lot of code is unprepared to handle paths
+ where there is an &quot;interior minimum&quot; in the MTU, especially when it's
+ less than 1500. So we advertise a big MTU and just let the resulting
+ big packets fragment.
+
+This usually works, but we do get bitten in cases where some intermediate
+point can't handle all that fragmentation. We can't win on this one.</PRE>
+<P>The MTU can be changed with an<VAR> overridemtu=</VAR> statement in
+ the<VAR> config setup</VAR> section of<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf.5</A>.</P>
+<P>For a discussion of MTU issues and some possible solutions using
+ Linux advanced routing facilities, see the<A href="http://www.linuxguruz.org/iptables/howto/2.4routing-15.html#ss15.6">
+ Linux 2.4 Advanced Routing HOWTO</A>. For a discussion of MTU and NAT
+ (Network Address Translation), see<A HREF="http://harlech.math.ucla.edu/services/ipsec.html">
+ James Carter's MTU notes</A>.</P>
+<H2><A name="nat.background">Network address translation (NAT)</A></H2>
+<P><STRONG>N</STRONG>etwork<STRONG> A</STRONG>ddress<STRONG> T</STRONG>
+ranslation is a service provided by some gateway machines. Calling it
+ NAPT (adding the word<STRONG> P</STRONG>ort) would be more precise, but
+ we will follow the widespread usage.</P>
+<P>A gateway doing NAT rewrites the headers of packets it is forwarding,
+ changing one or more of:</P>
+<UL>
+<LI>source address</LI>
+<LI>source port</LI>
+<LI>destination address</LI>
+<LI>destination port</LI>
+</UL>
+<P>On Linux 2.4, NAT services are provided by the<A href="http://netfilter.samba.org">
+ netfilter(8)</A> firewall code. There are several<A href="http://netfilter.samba.org/documentation/index.html#HOWTO">
+ Netfilter HowTos</A> including one on NAT.</P>
+<P>For older versions of Linux, this was referred to as &quot;IP masquerade&quot;
+ and different tools were used. See this<A href="http://www.e-infomax.com/ipmasq/">
+ resource page</A>.</P>
+<P>Putting an IPsec gateway behind a NAT gateway is not recommended. See
+ our<A href="#NAT"> firewalls document</A>.</P>
+<H3><A NAME="17_3_1">NAT to non-routable addresses</A></H3>
+<P>The most common application of NAT uses private<A href="#non-routable">
+ non-routable</A> addresses.</P>
+<P>Often a home or small office network will have:</P>
+<UL>
+<LI>one connection to the Internet</LI>
+<LI>one assigned publicly visible IP address</LI>
+<LI>several machines that all need access to the net</LI>
+</UL>
+<P>Of course this poses a problem since several machines cannot use one
+ address. The best solution might be to obtain more addresses, but often
+ this is impractical or uneconomical.</P>
+<P>A common solution is to have:</P>
+<UL>
+<LI><A href="#non-routable">non-routable</A> addresses on the local
+ network</LI>
+<LI>the gateway machine doing NAT</LI>
+<LI>all packets going outside the LAN rewritten to have the gateway as
+ their source address</LI>
+</UL>
+<P>The client machines are set up with reserved<A href="#non-routable">
+ non-routable</A> IP addresses defined in RFC 1918. The masquerading
+ gateway, the machine with the actual link to the Internet, rewrites
+ packet headers so that all packets going onto the Internet appear to
+ come from one IP address, that of its Internet interface. It then gets
+ all the replies, does some table lookups and more header rewriting, and
+ delivers the replies to the appropriate client machines.</P>
+<P>As far as anyone else on the Internet is concerned, the systems
+ behind the gateway are completely hidden. Only one machine with one IP
+ address is visible.</P>
+<P>For IPsec on such a gateway, you can entirely ignore the NAT in:</P>
+<UL>
+<LI><A href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A></LI>
+<LI>firewall rules affecting your Internet-side interface</LI>
+</UL>
+<P>Those can be set up exactly as they would be if your gateway had no
+ other systems behind it.</P>
+<P>You do, however, have to take account of the NAT in firewall rules
+ which affect packet forwarding.</P>
+<H3><A NAME="17_3_2">NAT to routable addresses</A></H3>
+<P>NAT to routable addresses is also possible, but is less common and
+ may make for rather tricky routing problems. We will not discuss it
+ here. See the<A href="http://netfilter.samba.org/documentation/index.html#HOWTO">
+ Netfilter HowTos</A>.</P>
+<HR>
+<H1><A name="user.examples">FreeS/WAN script examples</A></H1>
+ This file is intended to hold a collection of user-written example
+ scripts or configuration files for use with FreeS/WAN.
+<P> So far it has only one entry.</P>
+<H2><A name="poltorak">Poltorak's Firewall script</A></H2>
+<PRE>
+From: Poltorak Serguei &lt;poltorak@dataforce.net&gt;
+Subject: [Users] Using FreeS/WAN
+Date: Tue, 16 Oct 2001
+
+Hello.
+
+I'm using FreeS/WAN IPsec for half a year. I learned a lot of things about
+it and I think it would be interesting for someone to see the result of my
+experiments and usage of FreeS/WAN. If you find a mistake in this
+file, please e-mail me. And excuse me for my english... I'm learning.. :)
+
+I'll talk about vary simple configuration:
+
+addresses prefix = 192.168
+
+ lan1 sgw1 .0.0/24 (Internet) sgw2 lan2
+ .1.0/24---[ .1.1 ; .0.1 ]===================[ .0.10 ; . 2.10 ]---.2.0/24
+
+
+We need to let lan1 see lan2 across Internet like it is behind sgw1. The
+same for lan2. And we need to do IPX bridge for Novel Clients and NDS
+synchronization.
+
+my config:
+------------------- ipsec.conf -------------------
+conn lan1-lan2
+ type=tunnel
+ compress=yes
+ #-------------------
+ left=192.168.0.1
+ leftsubnet=192.168.1.0/24
+ #-------------------
+ right=192.168.0.10
+ rightsubnet=192.168.2.0/24
+ #-------------------
+ auth=esp
+ authby=secret
+--------------- end of ipsec.conf ----------------
+
+ping .2.x from .1.y (y != 1)
+It works?? Fine. Let's continue...
+
+Why y != 1 ?? Because kernel of sgw1 have 2 IP addresses and it will choose
+the first IP (which is used to go to Internet) .0.1 and the packet won't go
+through IPsec tunnel :( But if do ping on .1.1 kernel will respond from
+that address (.1.1) and the packet will be tunneled. The same problem occurred then
+.2.x sends a packet to .1.2 which is down at the moment. What happens? .1.1
+sends ARP requesting .1.2... after 3 tries it send to .2.x an destunreach,
+but from his &quot;natural&quot; IP or .0.1 . So the error message won't be delivered!
+It's a big problem...
+
+Resolution... One can manipulate with ipsec0 or ipsec0:0 to solve the
+problem (if ipsec0 has .1.1 kernel will send packets correctly), but there
+are powerful and elegant iproute2 :) We simply need to change source address
+of packet that goes to other secure lan. This is done with
+
+ip route replace 192.168.2.0/24 via 192.168.0.10 dev ipsec0 src 192.168.1.1
+
+Cool!! Now it works!!
+
+The second step. We want install firewall on sgw1 and sgw2. Encryption of
+traffic without security isn't a good idea. I don't use {left|right}firewall,
+because I'm running firewall from init scripts.
+
+We want IPsec data between lan1-lan2, some ICMP errors (destination
+unreachable, TTL exceeded, parameter problem and source quench), replying on
+pings from both lans and Internet, ipxtunnel data for IPX and of course SSH
+between sgw1 and sgw2 and from/to one specified host.
+
+I'm using ipchains. With iptables there are some changes.
+
+---------------- rc.firewall ---------------------
+#!/bin/sh
+#
+# Firewall for IPsec lan1-lan2
+#
+
+IPC=/sbin/ipchains
+ANY=0.0.0.0/0
+
+# left
+SGW1_EXT=192.168.0.1
+SGW1_INT=192.168.1.1
+LAN1=192.168.1.0/24
+
+# right
+SGW2_EXT=192.168.0.10
+SGW2_INT=192.168.2.10
+LAN2=192.168.2.0/24
+
+# SSH from and to this host
+SSH_PEER_HOST=_SOME_HOST_
+
+# this is for left. exchange these values for right.
+MY_EXT=$SGW1_EXT
+MY_INT=$SGW1_INT
+PEER_EXT=$SGW2_EXT
+PEER_INT=$SGW2_INT
+INT_IF=eth1
+EXT_IF=eth0
+IPSEC_IF=ipsec0
+MY_LAN=$LAN1
+PEER_LAN=$LAN2
+
+$IPC -F
+$IPC -P input DENY
+$IPC -P forward DENY
+$IPC -P output DENY
+
+# Loopback traffic
+$IPC -A input -i lo -j ACCEPT
+$IPC -A output -i lo -j ACCEPT
+
+# for IPsec SGW1-SGW2
+## IKE
+$IPC -A input -p udp -s $PEER_EXT 500 -d $MY_EXT 500 -i $EXT_IF -j ACCEPT
+$IPC -A output -p udp -s $MY_EXT 500 -d $PEER_EXT 500 -i $EXT_IF -j ACCEPT
+## ESP
+$IPC -A input -p 50 -s $PEER_EXT -d $MY_EXT -i $EXT_IF -j ACCEPT
+### we don't need this line ### $IPC -A output -p 50 -s $MY_EXT -d $PEER_EXT -i $EXT_IF -j ACCEPT
+## forward LAN1-LAN2
+$IPC -A forward -s $MY_LAN -d $PEER_LAN -i $IPSEC_IF -j ACCEPT
+$IPC -A forward -s $PEER_LAN -d $MY_LAN -i $INT_IF -j ACCEPT
+$IPC -A output -s $PEER_LAN -d $MY_LAN -i $INT_IF -j ACCEPT
+$IPC -A input -s $PEER_LAN -d $MY_LAN -i $IPSEC_IF -j ACCEPT
+$IPC -A input -s $MY_LAN -d $PEER_LAN -i $INT_IF -j ACCEPT
+$IPC -A output -s $MY_LAN -d $PEER_LAN -i $IPSEC_IF -j ACCEPT
+
+# ICMP
+#
+## Dest unreachable
+### from/to Internet
+$IPC -A input -p icmp --icmp-type destination-unreachable -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type destination-unreachable -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### from/to Lan
+$IPC -A input -p icmp --icmp-type destination-unreachable -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type destination-unreachable -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### from/to Peer Lan
+$IPC -A input -p icmp --icmp-type destination-unreachable -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type destination-unreachable -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+#
+## Source quench
+### from/to Internet
+$IPC -A input -p icmp --icmp-type source-quench -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type source-quench -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### from/to Lan
+$IPC -A input -p icmp --icmp-type source-quench -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type source-quench -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### from/to Peer Lan
+$IPC -A input -p icmp --icmp-type source-quench -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type source-quench -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+#
+## Parameter problem
+### from/to Internet
+$IPC -A input -p icmp --icmp-type parameter-problem -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type parameter-problem -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### from/to Lan
+$IPC -A input -p icmp --icmp-type parameter-problem -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type parameter-problem -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### from/to Peer Lan
+$IPC -A input -p icmp --icmp-type parameter-problem -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type parameter-problem -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+#
+## Time To Live exceeded
+### from/to Internet
+$IPC -A input -p icmp --icmp-type time-exceeded -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type time-exceeded -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### to Lan
+$IPC -A input -p icmp --icmp-type time-exceeded -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type time-exceeded -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### to Peer Lan
+$IPC -A input -p icmp --icmp-type time-exceeded -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type time-exceeded -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+
+# ICMP PINGs
+## from Internet
+$IPC -A input -p icmp -s $ANY -d $MY_EXT --icmp-type echo-request -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp -s $MY_EXT -d $ANY --icmp-type echo-reply -i $EXT_IF -j ACCEPT
+## from LAN
+$IPC -A input -p icmp -s $ANY -d $MY_INT --icmp-type echo-request -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp -s $MY_INT -d $ANY --icmp-type echo-reply -i $INT_IF -j ACCEPT
+## from Peer LAN
+$IPC -A input -p icmp -s $ANY -d $MY_INT --icmp-type echo-request -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp -s $MY_INT -d $ANY --icmp-type echo-reply -i $IPSEC_IF -j ACCEPT
+
+# SSH
+## from SSH_PEER_HOST
+$IPC -A input -p tcp -s $SSH_PEER_HOST -d $MY_EXT 22 -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp \! -y -s $MY_EXT 22 -d $SSH_PEER_HOST -i $EXT_IF -j ACCEPT
+## to SSH_PEER_HOST
+$IPC -A input -p tcp \! -y -s $SSH_PEER_HOST 22 -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp -s $MY_EXT -d $SSH_PEER_HOST 22 -i $EXT_IF -j ACCEPT
+## from PEER
+$IPC -A input -p tcp -s $PEER_EXT -d $MY_EXT 22 -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp \! -y -s $MY_EXT 22 -d $PEER_EXT -i $EXT_IF -j ACCEPT
+## to PEER
+$IPC -A input -p tcp \! -y -s $PEER_EXT 22 -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp -s $MY_EXT -d $PEER_EXT 22 -i $EXT_IF -j ACCEPT
+
+# ipxtunnel
+$IPC -A input -p udp -s $PEER_INT 2005 -d $MY_INT 2005 -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p udp -s $MY_INT 2005 -d $PEER_INT 2005 -i $IPSEC_IF -j ACCEPT
+
+---------------- end of rc.firewall ----------------------
+
+To understand this we need to look on this scheme:
+
+ ++-----------------------&lt;----------------------------+
+ || ipsec0 |
+ \/ |
+ eth0 +--------+ /---------/ yes /---------/ yes +-----------------------+
+------&gt;| INPUT |--&gt;/ ?local? /-----&gt;/ ?IPsec? /-----&gt;| decrypt decapsulate |
+ eth1 +--------+ /---------/ /---------/ +-----------------------+
+ || no || no
+ \/ \/
+ +----------+ +---------+ +-------+
+ | routing | | local | | local |
+ | decision | | deliver | | send |
+ +----------+ +---------+ +-------+
+ || ||
+ \/ \/
+ +---------+ +----------+
+ | forward | | routing |
+ +---------+ | decision |
+ || +----------+
+ || ||
+ ++----------------&lt;-----------------++
+ ||
+ \/
+ +--------+ eth0
+ | OUTPUT | eth1
+ +--------+ ipsec0
+ ||
+ \/
+ /---------/ yes +-----------------------+
+ / ?IPsec? /-----&gt;| encrypt encapsulate |
+ /---------/ +-----------------------+
+ || no ||
+ || ||
+ || \/ eth0, eth1
+ ++-----------------------++--------------&gt;
+
+This explain how a packet traverse TCP/IP stack in IPsec capable kernel.
+
+FIX ME, please, if there are any errors
+
+Test the new firewall now.
+
+
+Now about IPX. I tried 3 programs for tunneling IPX: tipxd, SIB and ipxtunnel
+
+tipxd didn't send packets.. :(
+SIB and ipxtunnel worked fine :)
+With ipxtunnel there was a little problem. In sources there are an error.
+
+--------------------- in main.c ------------------------
+&lt; bytes += p.len;
+---
+&gt; bytes += len;
+--------------------------------------------------------
+
+After this FIX everything goes right...
+
+------------------- /etc/ipxtunnel.conf ----------------
+port 2005
+remote 192.168.101.97 2005
+interface eth1
+--------------- end of /etc/ipxtunnel.conf -------------
+
+I use IPX tunnel between .1.1 and .2.10 so we don't need to encrypt nor
+authenticate encapsulated IPX packets, it is done with IPsec.
+
+If you don't wont to use iproute2 to change source IP you need to use SIB
+(it is able to bind local address) or establish tunnel between .0.1 and
+.0.10 (external IPs, you need to do encryption in the program, but it isn't
+strong).
+
+For now I'm using ipxtunnel.
+
+I think that's all for the moment. If there are any error, please e-mail me:
+poltorak@df.ru . It would be cool if someone puts the scheme of TCP/IP in
+kernel and firewall example on FreeS/WAN's manual pages.
+
+PoltoS
+</PRE>
+<HR>
+<H1><A name="makecheck">How to configure to use &quot;make check&quot;</A></H1>
+<H2><A NAME="19_1">What is &quot;make check&quot;</A></H2>
+<P> &quot;make check&quot; is a target in the top level makefile. It takes care of
+ running a number of unit and system tests to confirm that FreeSWAN has
+ been compiled correctly, and that no new bugs have been introduced.</P>
+<P> As FreeSWAN contains both kernel and userspace components, doing
+ testing of FreeSWAN requires that the kernel be simulated. This is
+ typically difficult to do as a kernel requires that it be run on bare
+ hardware. A technology has emerged that makes this simpler. This is<A HREF="http://user-mode-linux.sourceforge.net">
+ User Mode Linux</A>.</P>
+<P> User-Mode Linux is a way to build a Linux kernel such that it can
+ run as a process under another Linux (or in the future other) kernel.
+ Presently, this can only be done for 2.4 guest kernels. The host kernel
+ can be 2.2 or 2.4.</P>
+<P> &quot;make check&quot; expects to be able to build User-Mode Linux kernels
+ with FreeSWAN included. To do this it needs to have some files
+ downloaded and extracted prior to running &quot;make check&quot;. This is
+ described in the<A HREF="umltesting.html"> UML testing</A> document.</P>
+<P> After having run the example in the UML testing document and
+ successfully brought up the four machine combination, you are ready to
+ use &quot;make check&quot;</P>
+<H2><A NAME="19_2">Running &quot;make check&quot;</A></H2>
+<P> &quot;make check&quot; works by walking the FreeSWAN source tree invoking the
+ &quot;check&quot; target at each node. At present there are tests defined only
+ for the <CODE>klips</CODE> directory. These tests will use the UML
+ infrastructure to test out pieces of the <CODE>klips</CODE> code.</P>
+<P> The results of the tests can be recorded. If the environment
+ variable <CODE>$REGRESSRESULTS</CODE> is non-null, then the results of
+ each test will be recorded. This can be used as part of a nightly
+ regression testing system, see<A HREF="nightly.html"> Nightly testing</A>
+ for more details.</P>
+<P> &quot;make check&quot; otherwise prints a minimal amount of output for each
+ test, and indicates pass/fail status of each test as they are run.
+ Failed tests do not cause failure of the target in the form of exit
+ codes.</P>
+<H1><A NAME="20">How to write a &quot;make check&quot; test</A></H1>
+<H2><A NAME="20_1">Structure of a test</A></H2>
+<P> Each test consists of a set of directories under <CODE>testing/</CODE>
+. There are directories for <CODE>klips</CODE>, <CODE>pluto</CODE>, <CODE>
+packaging</CODE> and <CODE>libraries</CODE>. Each directory has a list
+ of tests to run is stored in a file called <CODE>TESTLIST</CODE> in
+ that directory. e.g. <CODE>testing/klips/TESTLIST</CODE>.</P>
+<H2 NAME="TESTLIST"><A NAME="20_2">The TESTLIST</A></H2>
+<P> This isn't actually a shell script. It just looks like one. Some
+ tools other than /bin/sh process it. Lines that start with # are
+ comments.</P>
+<PRE>
+# test-kind directory-containing-test expectation [PR#]
+</PRE>
+<P>The first word provides the test type, detailed below.</P>
+<P> The second word is the name of the test to run. This the directory
+ in which the test case is to be found..</P>
+<P>The third word may be one of:</P>
+<DL>
+<DT> blank/good</DT>
+<DD>the test is believed to function, report failure</DD>
+<DT> bad</DT>
+<DD> the test is known to fail, report unexpected success</DD>
+<DT> suspended</DT>
+<DD> the test should not be run</DD>
+</DL>
+<P> The fourth word may be a number, which is a PR# if the test is
+ failing.</P>
+<H2><A NAME="20_3">Test kinds</A></H2>
+ The test types are:
+<DL>
+<DT>skiptest</DT>
+<DD>means run no test.</DD>
+<DT>ctltest</DT>
+<DD>means run a single system without input/output.</DD>
+<DT>klipstest</DT>
+<DD>means run a single system with input/output networks</DD>
+<DT><A HREF="#umlplutotest">umlplutotest</A></DT>
+<DD>means run a pair of systems</DD>
+<DT><A HREF="#umlXhost">umlXhost</A></DT>
+<DD>run an arbitrary number of systems</DD>
+<DT>suntest (TBD)</DT>
+<DD>means run a quad of east/west/sunrise/sunset</DD>
+<DT>roadtest (TBD)</DT>
+<DD>means run a trio of east-sunrise + warrior</DD>
+<DT>extrudedtest (TBD)</DT>
+<DD>means run a quad of east-sunrise + warriorsouth + park</DD>
+<DT>mkinsttest</DT>
+<DD>a test of the &quot;make install&quot; machinery.</DD>
+<DT>kernel_test_patch</DT>
+<DD>a test of the &quot;make kernelpatch&quot; machinery.</DD>
+</DL>
+ Tests marked (TBD) have yet to be fully defined.
+<P> Each test directory has a file in it called <CODE>testparams.sh</CODE>
+. This file sets a number of environment variables to define the
+ parameters of the test.</P>
+<H2><A NAME="20_4">Common parameters</A></H2>
+<DL>
+<DT>TESTNAME</DT>
+<DD>the name of the test (repeated for checking purposes)</DD>
+<DT>TEST_TYPE</DT>
+<DD>the type of the test (repeat of type type above)</DD>
+<DT>TESTHOST</DT>
+<DD>the name of the UML machine to run for the test, typically &quot;east&quot; or
+ &quot;west&quot;</DD>
+<DT>TEST_PURPOSE</DT>
+<DD>The purpose of the test is one of:
+<DL>
+<DT>goal</DT>
+<DD>The goal purpose is where a test is defined for code that is not yet
+ finished. The test indicates when the goals have in fact been reached.</DD>
+<DT>regress</DT>
+<DD>This is a test to determine that a previously existing bug has been
+ repaired. This test will initially be created to reproduce the bug in
+ isolation, and then the bug will be fixed.</DD>
+<DT>exploit</DT>
+<DD>This is a set of packets/programs that causes a vulnerability to be
+ exposed. It is a specific variation of the regress option.</DD>
+</DL>
+</DD>
+<DT>TEST_GOAL_ITEM</DT>
+<DT></DT>
+<DD>in the case of a goal test, this is a reference to the requirements
+ document</DD>
+<DT>TEST_PROB_REPORT</DT>
+<DD>in the case of regression test, this the problem report number from
+ GNATS</DD>
+<DT>TEST_EXPLOIT_URL</DT>
+<DD>in the case of an exploit, this is a URL referencing the paper
+ explaining the origin of the test and the origin of exploit software</DD>
+<DT>REF_CONSOLE_OUTPUT</DT>
+<DD>a file in the test directory that contains the sanitized console
+ output against which to compare the output of the actual test.</DD>
+<DT>REF_CONSOLE_FIXUPS</DT>
+<DD>a list of scripts (found in <CODE>klips/test/fixups</CODE>) to apply
+ to sanitize the console output of the machine under test. These are
+ typically perl, awk or sed scripts that remove things in the kernel
+ output that change each time the test is run and/or compiled.</DD>
+<DT>INIT_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode prior to starting the tests. This file will usually
+ set up any eroute's and SADB entries that are required for the test.</P>
+<P>Lines beginning with # are skipped. Blank lines are skipped.
+ Otherwise, a shell prompted is waited for each time (consisting of <CODE>
+\n#</CODE>) and then the command is sent. Note that the prompt is waited
+ for before the command and not after, so completion of the last command
+ in the script is not required. This is often used to invoke a program
+ to monitor the system, e.g. <CODE>ipsec pf_key</CODE>.</P>
+</DD>
+<DT>RUN_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode, before the packets are sent. On single machine tests,
+ this script doesn't provide any more power than INIT_SCRIPT, but is
+ implemented for consistency's sake.</P>
+</DD>
+<DT>FINAL_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode after the final packet is sent. Similar to
+ INIT_SCRIPT, above. If not specified, then the single command &quot;halt&quot; is
+ sent. If specified, then the script should end with a halt command to
+ nicely shutdown the UML.</P>
+</DD>
+<DT>CONSOLEDIFFDEBUG</DT>
+<DD>If set to &quot;true&quot; then the series of console fixups (see
+ REF_CONSOLE_FIXUPS) will be output after it is constructed. (It should
+ be set to &quot;false&quot;, or unset otherwise)</DD>
+<DT>NETJIGDEBUG</DT>
+<DD>If set to &quot;true&quot; then the series of console fixups (see
+ REF_CONSOLE_FIXUPS) will be output after it is constructed. (It should
+ be set to &quot;false&quot;, or unset otherwise)</DD>
+<DT>NETJIGTESTDEBUG</DT>
+<DD> If set to &quot;netjig&quot;, then the results of talking to the <CODE>
+uml_netjig</CODE> will be printed to stderr during the test. In
+ addition, the jig will be invoked with --debug, which causes it to log
+ its process ID, and wait 60 seconds before continuing. This can be used
+ if you are trying to debug the <CODE>uml_netjig</CODE> program itself.</DD>
+<DT>HOSTTESTDEBUG</DT>
+<DD> If set to &quot;hosttest&quot;, then the results of taling to the consoles of
+ the UMLs will be printed to stderr during the test.</DD>
+<DT>NETJIGWAITUSER</DT>
+<DD> If set to &quot;waituser&quot;, then the scripts will wait forever for user
+ input before they shut the tests down. Use this is if you are debugging
+ through the kernel.</DD>
+<DT>PACKETRATE</DT>
+<DD> A number, in miliseconds (default is 500ms) at which packets will
+ be replayed by the netjig.</DD>
+</DL>
+<H2><A NAME="20_5">KLIPStest paramaters</A></H2>
+<P> The klipstest function starts a program (<CODE>
+testing/utils/uml_netjig/uml_netjig</CODE>) to setup a bunch of I/O
+ sockets (that simulate network interfaces). It then exports the
+ references to these sockets to the environment and invokes (using
+ system()) a given script. It waits for the script to finish.</P>
+
+<!-- <IMG SRC="single_netjig.png" ALT="block diagram of uml_netjig"> -->
+<P> The script invoked (<CODE>testing/utils/host-test.tcl</CODE>) is a
+ TCL<A HREF="http://expect.nist.gov/"> expect</A> script that arranges
+ to start the UML and configure it appropriately for the test. The
+ configuration is done with the script given above for<VAR> INIT_SCRIPT</VAR>
+. The TCL script then forks, leaves the UML in the background and exits.
+ uml_netjig continues. It then starts listening to the simulated network
+ answering ARPs and inserting packets as appropriate.</P>
+<P> The klipstest function invokes <CODE>uml_netjig</CODE> with
+ arguments to capture output from network interface(s) and insert
+ packets as appropriate:</P>
+<DL>
+<DT>PUB_INPUT</DT>
+<DD>a<A HREF="http://www.tcpdump.org/"> pcap</A> file to feed in on the
+ public (encrypted) interface. (typically, eth1)</DD>
+<DT>PRIV_INPUT</DT>
+<DD>a pcap file to feed in on the private (plain-text) interface
+ (typically, eth0).</DD>
+<DT>REF_PUB_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the public (eth1)
+ interface are captured to a<A HREF="http://www.tcpdump.org/"> pcap</A>
+ file by <CODE>uml_netjig</CODE>. The klipstest function then uses
+ tcpdump on the file to produce text output, which is compared to the
+ file given.</DD>
+<DT>REF_PUB_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+<DT>REF_PRIV_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the private (eth0)
+ interface are captured and compared after conversion by tcpdump, as
+ with<VAR> REFPUBOUTPUT</VAR>.</DD>
+<DT>REF_PRIV_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+<DT>EXITONEMPTY</DT>
+<DD>a flag for <CODE>uml_netjig</CODE>. It should contain
+ &quot;--exitonempty&quot; of uml_netjig should exit when all of the input (<VAR>
+PUBINPUT</VAR>,<VAR>PRIVINPUT</VAR>) packets have been injected.</DD>
+<DT>ARPREPLY</DT>
+<DD>a flag for <CODE>uml_netjig</CODE>. It should contain &quot;--arpreply&quot;
+ if <CODE>uml_netjig</CODE> should reply to ARP requests. One will
+ typically set this to avoid having to fudge the ARP cache manually.</DD>
+<DT>TCPDUMPFLAGS</DT>
+<DD>a set of flags for the tcpdump used when converting captured output.
+ Typical values will include &quot;-n&quot; to turn off DNS, and often &quot;-E&quot; to set
+ the decryption key (tcpdump 3.7.1 and higher only) for ESP packets. The
+ &quot;-t&quot; flag (turn off timestamps) is provided automatically</DD>
+<DT>NETJIG_EXTRA</DT>
+<DD>additional comments to be sent to the netjig. This may arrange to
+ record or create additional networks, or may toggle options.</DD>
+</DL>
+<H2><A NAME="20_6">mkinsttest paramaters</A></H2>
+<P> The basic concept of the <CODE>mkinsttest</CODE> test type is that
+ it performs a &quot;make install&quot; to a temporary $DESTDIR. The resulting
+ tree can then be examined to determine if it was done properly. The
+ files can be uninstalled to determine if the file list was correct, or
+ the contents of files can be examined more precisely.</P>
+<DL>
+<DT>INSTALL_FLAGS</DT>
+<DD>If set, then an install will be done. This provides the set of flags
+ to provide for the install. The target to be used (usually &quot;install&quot;)
+ must be among the flags.</DD>
+<DT>POSTINSTALL_SCRIPT</DT>
+<DD>If set, a script to run after initial &quot;make install&quot;. Two arguments
+ are provided: an absolute path to the root of the FreeSWAN src tree,
+ and an absolute path to the temporary installation area.</DD>
+<DT>INSTALL2_FLAGS</DT>
+<DD>If set, a second install will be done using these flags. Similarly
+ to INSTALL_FLAGS, the target must be among the flags.</DD>
+<DT>UNINSTALL_FLAGS</DT>
+<DD>If set, an uninstall will be done using these flags. Similarly to
+ INSTALL_FLAGS, the target (usually &quot;uninstall&quot;) must be among the
+ flags.</DD>
+<DT>REF_FIND_f_l_OUTPUT</DT>
+<DD>If set, a <CODE>find $ROOT ( -type f -or -type -l )</CODE> will be
+ done to get a list of a real files and symlinks. The resulting file
+ will be compared to the file listed by this option.</DD>
+<DT>REF_FILE_CONTENTS</DT>
+<DD>If set, it should point to a file containing records for the form:
+<PRE>
+
+<!--VARIABLE-->
+reffile</(null)>
+<!--VARIABLE-->
+samplefile</(null)>
+</PRE>
+ one record per line. A diff between the provided reference file, and
+ the sample file (located in the temporary installation root) will be
+ done for each record.</DD>
+</DL>
+<H2><A NAME="20_7">rpm_build_install_test paramaters</A></H2>
+<P> The <CODE>rpm_build_install_test</CODE> type is to verify that the
+ proper packing list is produced by &quot;make rpm&quot;, and that the mechanisms
+ for building the kernel modules produce consistent results.</P>
+<DL>
+<DT>RPM_KERNEL_SOURCE</DT>
+<DD>Point to an extracted copy of the RedHat kernel source code.
+ Variables from the environment may be used.</DD>
+<DT>REF_RPM_CONTENTS</DT>
+<DD>This is a file containing one record per line. Each record consists
+ of a RPM name (may contain wildcards) and a filename to compare the
+ contents to. The RPM will be located and a file list will be produced
+ with rpm2cpio.</DD>
+</DL>
+<H2><A NAME="20_8">libtest paramaters</A></H2>
+<P> The libtest test is for testing library routines. The library file
+ is expected to provided an <CODE>#ifdef</CODE> by the name of<VAR>
+ library</VAR>
+<!--CODE_MAIN</CODE-->
+. The libtest type invokes the C compiler to compile this
+ file, links it against <CODE>libfreeswan.a</CODE> (to resolve any other
+ dependancies) and runs the test with the <CODE>-r</CODE> argument to
+ invoke a regression test.</(null)></P>
+<P>The library test case is expected to do a self-test, exiting with
+ status code 0 if everything is okay, and with non-zero otherwise. A
+ core dump (exit code greater than 128) is noted specifically.</P>
+<P> Unlike other tests, there are no subdirectories required, or other
+ parameters to set.</P>
+<H2 NAME="umlplutotest"><A NAME="20_9">umlplutotest paramaters</A></H2>
+<P> The umlplutotest function starts a pair of user mode line processes.
+ This is a 2-host version of umlXhost. The &quot;EAST&quot; and &quot;WEST&quot; slots are
+ defined.</P>
+<H2 NAME="umlXhost"><A NAME="20_10">umlXhost parameters</A></H2>
+<P> The umlXtest function starts an arbitrary number of user mode line
+ processes.</P>
+
+<!-- <IMG SRC="single_netjig.png" ALT="block diagram of uml_netjig"> -->
+<P> The script invoked (<CODE>testing/utils/Xhost-test.tcl</CODE>) is a
+ TCL<A HREF="http://expect.nist.gov/"> expect</A> script that arranges
+ to start each UML and configure it appropriately for the test. It then
+ starts listening (using uml_netjig) to the simulated network answering
+ ARPs and inserting packets as appropriate.</P>
+<P> umlXtest has a series of slots, each of which should be filled by a
+ host. The list of slots is controlled by the variable, XHOST_LIST. This
+ variable should be set to a space seperated list of slots. The former
+ umlplutotest is now implemented as a variation of the umlXhost test,
+ with XHOST_LIST=&quot;EAST WEST&quot;.</P>
+<P> For each host slot that is defined, a series of variables should be
+ filled in, defining what configuration scripts to use for that host.</P>
+<P> The following are used to control the console input and output to
+ the system. Where the string ${host} is present, the host slot should
+ be filled in. I.e. for the two host system with XHOST_LIST=&quot;EAST WEST&quot;,
+ then the variables: EAST_INIT_SCRIPT and WEST_INIT_SCRIPT will exist.</P>
+<DL>
+<DT>${host}HOST</DT>
+<DD>The name of the UML host which will fill this slot</DD>
+<DT>${host}_INIT_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode prior to starting the tests. This file will usually
+ set up any eroute's and SADB entries that are required for the test.
+ Similar to INIT_SCRIPT, above.</P>
+</DD>
+<DT>${host}_RUN_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode, before the packets are sent. This set of commands is
+ run after all of the virtual machines are initialized. I.e. after
+ EAST_INIT_SCRIPT<B> AND</B> WEST_INIT_SCRIPT. This script can therefore
+ do things that require that all machines are properly configured.</P>
+</DD>
+<DT>${host}_RUN2_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode, after the packets are sent. This set of commands is
+ run before any of the virtual machines have been shut down. (I.e.
+ before EAST_FINAL_SCRIPT<B> AND</B> WEST_FINAL_SCRIPT.) This script can
+ therefore catch post-activity status reports.</P>
+</DD>
+<DT>${host}_FINAL_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode after the final packet is sent. Similar to
+ INIT_SCRIPT, above. If not specified, then the single command &quot;halt&quot; is
+ sent. Note that when this script is run, the other virtual machines may
+ already have been killed. If specified, then the script should end with
+ a halt command to nicely shutdown the UML.</P>
+</DD>
+<DT>REF_${host}_CONSOLE_OUTPUT</DT>
+<DD>Similar to REF_CONSOLE_OUTPUT, above.</DD>
+</DL>
+<P>Some additional flags apply to all hosts:</P>
+<DL>
+<DT>REF_CONSOLE_FIXUPS</DT>
+<DD>a list of scripts (found in <CODE>klips/test/fixups</CODE>) to apply
+ to sanitize the console output of the machine under test. These are
+ typically perl, awk or sed scripts that remove things in the kernel
+ output that change each time the test is run and/or compiled.</DD>
+</DL>
+<P> In addition to input to the console, the networks may have input fed
+ to them:</P>
+<DL>
+<DT>EAST_INPUT/WEST_INPUT</DT>
+<DD>a<A HREF="http://www.tcpdump.org/"> pcap</A> file to feed in on the
+ private network side of each network. The &quot;EAST&quot; and &quot;WEST&quot; here refer
+ to the networks, not the hosts.</DD>
+<DT>REF_PUB_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+<DT>REF_EAST_FILTER/REF_WEST_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+&lt;
+<DT>TCPDUMPFLAGS</DT>
+<DD>a set of flags for the tcpdump used when converting captured output.
+ Typical values will include &quot;-n&quot; to turn off DNS, and often &quot;-E&quot; to set
+ the decryption key (tcpdump 3.7.1 and higher only) for ESP packets. The
+ &quot;-t&quot; flag (turn off timestamps) is provided automatically</DD>
+<DT>REF_EAST_OUTPUT/REF_WEST_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the private (eth0)
+ interface are captured and compared after conversion by tcpdump, as
+ with<VAR> REF_PUB_OUTPUT</VAR>.</DD>
+<P> There are two additional environment variables that may be set on
+ the command line:</P>
+<DL>
+<DT> NETJIGVERBOSE=verbose export NETJIGVERBOSE</DT>
+<DD> If set, then the test output will be &quot;chatty&quot;, and let you know
+ what commands it is running, and as packets are sent. Without it set,
+ the output is limited to success/failure messages.</DD>
+<DT> NETJIGTESTDEBUG=netjig export NETJIGTESTDEBUG</DT>
+<DD> This will enable debugging of the communication with uml_netjig,
+ and turn on debugging in this utility. This does not imply
+ NETJIGVERBOSE.</DD>
+</DL>
+<DT> HOSTTESTDEBUG=hosttest export HOSTTESTDEBUG</DT>
+<DD> This will show all interactions with the user-mode-linux consoles</DD>
+</DL>
+<H2 NAME="kernelpatch"><A NAME="20_11">kernel_patch_test paramaters</A></H2>
+<P> The kernel_patch_test function takes some kernel source, copies it
+ with lndir, and then applies the patch as produced by &quot;make
+ kernelpatch&quot;.</P>
+<P> The following are used to control the input and output to the
+ system:</P>
+<DL>
+<DT>KERNEL_NAME</DT>
+<DD>the kernel name, typically something like &quot;linus&quot; or &quot;rh&quot;</DD>
+<DT>KERNEL_VERSION</DT>
+<DD>the kernel version number, as in &quot;2.2&quot; or &quot;2.4&quot;.</DD>
+<DT>KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC</DT>
+<DD>This variable should set in the environment, probably in
+ ~/freeswan-regress-env.sh. Examples of this variables would be
+ KERNEL_LINUS2_0_SRC or KERNEL_RH7_3_SRC. This variable should point to
+ an extracted copy of the kernel source in question.</DD>
+<DT>REF_PATCH_OUTPUT</DT>
+<DD>a copy of the patch output to compare against</DD>
+<DT>KERNEL_PATCH_LEAVE_SOURCE</DT>
+<DD>If set to a non-empty string, then the patched kernel source is not
+ removed at the end of the test. This will typically be set in the
+ environment while debugging.</DD>
+</DL>
+<H2 NAME="modtest"><A NAME="20_12">module_compile paramaters</A></H2>
+<P> The module_compile test attempts to build the KLIPS module against a
+ given set of kernel source. This is also done by the RPM tests, but in
+ a very specific manner.</P>
+<P> There are two variations of this test - one where the kernel either
+ doesn't need to be configured, or is already done, and tests were there
+ is a local configuration file.</P>
+<P> Where the kernel doesn't need to be configured, the kernel source
+ that is found is simply used. It may be a RedHat-style kernel, where
+ one can cause it to configure itself via rhconfig.h-style definitions.
+ Or, it may just be a kernel tree that has been configured.</P>
+<P> If the variable KERNEL_CONFIG_FILE is set, then a new directory is
+ created for the kernel source. It is populated with lndir(1). The
+ referenced file is then copied in as .config, and &quot;make oldconfig&quot; is
+ used to configure the kernel. This resulting kernel is then used as the
+ reference source.</P>
+<P> In all cases, the kernel source is found the same was for the
+ kernelpatch test, i.e. via KERNEL_VERSION/KERNEL_NAME and
+ KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC.</P>
+<P> Once there is kernel source, the module is compiled using the
+ top-level &quot;make module&quot; target.</P>
+<P> The test is considered successful if an executable is found in
+ OUTPUT/module/ipsec.o at the end of the test.</P>
+<DL>
+<DT>KERNEL_NAME</DT>
+<DD>the kernel name, typically something like &quot;linus&quot; or &quot;rh&quot;</DD>
+<DT>KERNEL_VERSION</DT>
+<DD>the kernel version number, as in &quot;2.2&quot; or &quot;2.4&quot;.</DD>
+<DT>KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC</DT>
+<DD>This variable should set in the environment, probably in
+ ~/freeswan-regress-env.sh. Examples of this variables would be
+ KERNEL_LINUS2_0_SRC or KERNEL_RH7_3_SRC. This variable should point to
+ an extracted copy of the kernel source in question.</DD>
+<DT>KERNEL_CONFIG_FILE</DT>
+<DD>The configuration file for the kernel.</DD>
+<DT>KERNEL_PATCH_LEAVE_SOURCE</DT>
+<DD>If set to a non-empty string, then the configured kernel source is
+ not removed at the end of the test. This will typically be set in the
+ environment while debugging.</DD>
+<DT>MODULE_DEF_INCLUDE</DT>
+<DD>The include file that will be used to configure the KLIPS module,
+ and possibly the kernel source.</DD>
+</DL>
+<H1><A NAME="21">Current pitfalls</A></H1>
+<DL>
+<DT> &quot;tcpdump dissector&quot; not available.</DT>
+<DD> This is a non-fatal warning. If uml_netjig is invoked with the -t
+ option, then it will attempt to use tcpdump's dissector to decode each
+ packet that it processes. The dissector is presently not available, so
+ this option it normally turned off at compile time. The dissector
+ library will be released with tcpdump version 4.0.</DD>
+</DL>
+<HR>
+<H1><A name="umltesting">User-Mode-Linux Testing guide</A></H1>
+<P> User mode linux is a way to compile a linux kernel such that it can
+ run as a process in another linux system (potentially as a *BSD or
+ Windows process later). See<A HREF="http://user-mode-linux.sourceforge.net/">
+ http://user-mode-linux.sourceforge.net/</A></P>
+<P> UML is a good platform for testing and experimenting with FreeS/WAN.
+ It allows several network nodes to be simulated on a single machine.
+ Creating, configuring, installing, monitoring, and controling these
+ nodes is generally easier and easier to script with UML than real
+ hardware.</P>
+<P> You'll need about 500Mb of disk space for a full
+ sunrise-east-west-sunset setup. You can possibly get this down by 130Mb
+ if you remove the sunrise/sunset kernel build. If you just want to run,
+ then you can even remove the east/west kernel build.</P>
+<P> Nothing need be done as super user. In a couple of steps, we note
+ where super user is required to install commands in system-wide
+ directories, but ~/bin could be used instead. UML seems to use a
+ system-wide /tmp/uml directory so different users may interfere with
+ one another. Later UMLs use ~/.uml instead, so multiple users running
+ UML tests should not be a problem, but note that a single user running
+ the UML tests will only be able run one set. Further, UMLs sometimes
+ get stuck and hang around. These &quot;zombies&quot; (most will actually be in
+ the &quot;T&quot; state in the process table) will interfere with subsequent
+ tests.</P>
+<H2><A NAME="22_1">Preliminary Notes on BIND</A></H2>
+<P> As of 2003/3/1, the Light-Weight Resolver is used by pluto. This
+ requires that BIND9 be running. It also requires that BIND9 development
+ libraries be present in the build environment. The DNSSEC code is only
+ truly functional in BIND9 snapshots. The library code could be 9.2.2,
+ we believe. We are using BIND9 20021115 snapshot code from<A HREF="ftp://ftp.isc.org/isc/bind9/snapshots">
+ ftp://ftp.isc.org/isc/bind9/snapshots</A>.</P>
+<P> FreeS/WAN may well require a newer BIND than is on your system. Many
+ distributions have moved to BIND9.2.2 recently due to a security
+ advisory. BIND is five components.</P>
+<OL>
+<LI> named</LI>
+<LI> dnssec-*</LI>
+<LI> client side resolver libraries</LI>
+<LI> client side utility libraries I thought there were lib and named
+ parts to dnsssec...</LI>
+<LI> dynamic DNS update utilities</LI>
+</OL>
+<P> The only piece that we need for *building* is #4. That's the only
+ part that has to be on the build host. What is the difference between
+ resolver and util libs? If you want to edit
+ testing/baseconfigs/all/etc/bind, you'll need a snapshot version. The
+ resolver library contains the resolver. FreeS/WAN has its own copy of
+ that in lib/liblwres.</P>
+<H2><A NAME="22_2">Steps to Install UML for FreeS/WAN</A></H2>
+<OL>
+<LI> Get the following files:
+<OL type="a">
+<LI> from<A HREF="http://www.sandelman.ottawa.on.ca/freeswan/uml/">
+ http://www.sandelman.ottawa.on.ca/freeswan/uml/</A>
+ umlfreeroot-15.1.tar.gz (or highest numbered one). This is a debian
+ potato root file system. You can use this even on a Redhat host, as it
+ has the newer GLIBC2.2 libraries as well.
+<!-- If you are using
+ Redhat 7.2 or newer as your development machine, you can create the
+ image from your installation media. See <A HREF="uml-rhroot.html">Building a RedHat root"></A>.
+ A future document will explain how to build this from .DEB files as well.
+-->
+
+<!--
+<LI> umlfreesharemini.tar.gz (or umlfreeshareall.tar.gz).
+ If you are a Debian potato user, you don't need it you can use your
+ native /usr/share.
+</UL>
+-->
+</LI>
+<LI> From<A HREF="ftp://ftp.xs4all.nl/pub/crypto/freeswan/">
+ ftp://ftp.xs4all.nl/pub/crypto/freeswan/</A> a snapshot or release
+ (1.92 or better)</LI>
+<LI> From a<A HREF="http://www.kernel.org/mirrors/">
+ http://www.kernel.org mirror</A>, the virgin 2.4.19 kernel. Please
+ realize that we have defaults in our tree for kernel configuration. We
+ try to track the latest UML kernels. If you use a newer kernel, you may
+ have faults in the kernel build process. You can see what the latest
+ that is being regularly tested by visiting<A HREF="http://bugs.freeswan.org:81/regress/HEAD/lastgood/freeswan-regress-env.sh">
+ freeswan-regress-env.sh</A>.</LI>
+<LI>
+<!-- Note: this step is refered to as "step 1d" below. -->
+ Get<A HREF="http://ftp.nl.linux.org/uml/">
+ http://ftp.nl.linux.org/uml/</A> uml-patch-2.4.19-47.bz2 or the one
+ associated with your kernel. As of 2003/03/05, uml-patch-2.4.19-47.bz2
+ works for us.<STRONG> More recent versions of the patch have not been
+ tested by us.</STRONG></LI>
+<LI> You'll probably want to visit<A HREF="http://user-mode-linux.sourceforge.net">
+ http://user-mode-linux.sourceforge.net</A> and get the UML utilities.
+ These are not needed for the build or interactive use (but
+ recommended). They are necessary for the regression testing procedures
+ used by &quot;make check&quot;. We currently use uml_utilities_20020212.tar.bz2.</LI>
+<LI> You need tcpdump version 3.7.1 or better. This is newer than the
+ version included in most LINUX distributions. You can check the version
+ of an installed tcpdump with the --version flag. If you need a newer
+ tcpdump fetch both tcpdump and libpcap source tar files from<A HREF="http://www.tcpdump.org/">
+ http://www.tcpdump.org/</A> or a mirror.</LI>
+</OL>
+</LI>
+<LI> Pick a suitable place, and extract the following files:
+<OL type="a">
+<LI>
+<!-- Note: this step is refered to as "step 2a" later. -->
+ 2.4.19 kernel. For instance:
+<PRE>
+ <CODE> cd /c2/kernel
+ tar xzvf ../download/pub/linux/kernel/v2.4/linux-2.4.19.tar.gz
+</CODE>
+</PRE>
+</LI>
+<LI> extract the umlfreeroot file
+<!-- (unless you <A HREF="uml-rhroot.html">built your own from RPMs</A>) -->
+
+<PRE>
+ <CODE> mkdir -p /c2/user-mode-linux/basic-root
+ cd /c2/user-mode-linux/basic-root
+ tar xzvf ../download/umlfreeroot-15.1.tar.gz
+</CODE>
+</PRE>
+</LI>
+<LI> FreeSWAN itself (or checkout &quot;all&quot; from CVS)
+<PRE>
+ <CODE> mkdir -p /c2/freeswan/sandbox
+ cd /c2/freeswan/sandbox
+ tar xzvf ../download/snapshot.tar.gz
+</CODE>
+</PRE>
+</LI>
+</OL>
+</LI>
+<LI> If you need to build a newer tcpdump:
+<UL>
+<LI> Make sure you have OpenSSL installed -- it is needed for
+ cryptographic routines.</LI>
+<LI> Unpack libpcap and tcpdump source in parallel directories (the
+ tcpdump build procedures look for libpcap next door).</LI>
+<LI> Change directory into the libpcap source directory and then build
+ the library:
+<PRE>
+ <CODE> ./configure
+ make
+</CODE>
+</PRE>
+</LI>
+<LI> Change into the tcpdump source directory, build tcpdump, and
+ install it.
+<PRE>
+ <CODE> ./configure
+ make
+ # Need to be superuser to install in system directories.
+ # Installing in ~/bin would be an alternative.
+ su -c &quot;make install&quot;
+</CODE>
+</PRE>
+</LI>
+</UL>
+</LI>
+<LI> If you need the uml utilities, unpack them somewhere then build and
+ install them:
+<PRE>
+ <CODE> cd tools
+ make all
+ # Need to be superuser to install in system directories.
+ # Installing in ~/bin would be an alternative.
+ su -c &quot;make install BIN_DIR=/usr/local/bin&quot;
+</CODE>
+</PRE>
+</LI>
+<LI> set up the configuration file
+<UL>
+<LI> <CODE>cd /c2/freeswan/sandbox/freeswan-1.97/testing/utils</CODE></LI>
+<LI> copy umlsetup-sample.sh to ../../umlsetup.sh: <CODE> cp
+ umlsetup-sample.sh ../../umlsetup.sh</CODE></LI>
+<LI> open up ../../umlsetup.sh in your favorite editor.</LI>
+<LI> change POOLSPACE= to point to the place with at least 500Mb of
+ disk. Best if it is on the same partition as the &quot;umlfreeroot&quot;
+ extraction, as it will attempt to use hard links if possible to save
+ disk space.</LI>
+<LI> Set TESTINGROOT if you intend to run the script outside of the
+ sandbox/snapshot/release directory. Otherwise, it will configure
+ itself.</LI>
+<LI> KERNPOOL should point to the directory with your 2.4.19 kernel
+ tree. This tree should be unconfigured! This is the directory you used
+ in step 2a.</LI>
+<LI> UMLPATCH should point at the bz2 file you downloaded at 1d. If
+ using a kernel that already includes the patch, set this to /dev/null.</LI>
+<LI> FREESWANDIR should point at the directory where you unpacked the
+ snapshot/release. Include the &quot;freeswan-snap2001sep16b&quot; or whatever in
+ it. If you are running from CVS, then you point at the directory where
+ top, klips, etc. are. The script will fix up the directory so that it
+ can be used.</LI>
+<LI> BASICROOT should be set to the directory used in 2b, or to the
+ directory that you created with RPMs.</LI>
+<LI> SHAREDIR should be set to the directory used in 2c, to /usr/share
+ for Debian potato users, or to $BASICROOT/usr/share.</LI>
+</UL>
+</LI>
+<LI>
+<PRE> <CODE>cd $TESTINGROOT/utils
+sh make-uml.sh
+</CODE></PRE>
+ It will grind for awhile. If there are errors it will bail. If so, run
+ it under &quot;script&quot; and send the output to bugs@lists.freeswan.org.</LI>
+<LI> You will have a bunch of stuff under $POOLSPACE. Open four xterms:
+<PRE> <CODE> for i in sunrise sunset east west
+ do
+ xterm -name $i -title $i -e $POOLSPACE/$i/start.sh done
+</CODE></PRE>
+</LI>
+<LI> Login as root. Password is &quot;root&quot; (Note, these virtual machines are
+ networked together, but are not configured to talk to the rest of the
+ world.)</LI>
+<LI> verify that pluto started on east/west, run &quot;ipsec look&quot;</LI>
+<LI> login to sunrise. run &quot;ping sunset&quot;</LI>
+<LI> login to west. run &quot;tcpdump -p -i eth1 -n&quot; (tcpdump must be version
+ 3.7.1 or newer)</LI>
+<LI> Closing a console xterm will shut down that UML.</LI>
+<LI> You can &quot;make check&quot;, if you want to. It is run from
+ /c2/freeswan/sandbox/freeswan-1.97.</LI>
+</OL>
+<H1><A NAME="23">Debugging the kernel with GDB</A></H1>
+<P> With User-Mode-Linux, you can debug the kernel using GDB. See
+<!--HREF="http://user-mode-linux.sourceforge.net/debugging.html"-->
+
+ http://user-mode-linux.sourceforge.net/debugging.html.</(null)></P>
+<P> Typically, one will want to address a test case for a failing
+ situation. Running GDB from Emacs, or from other front ends is
+ possible. First start GDB.</P>
+<P> Tell it to open the UMLPOOL/swan/linux program.</P>
+<P> Note the PID of GDB:</P>
+<PRE>
+marajade-[projects/freeswan/mgmt/planning] mcr 1029 %ps ax | grep gdb
+ 1659 pts/9 SN 0:00 /usr/bin/gdb -fullname -cd /mara4/freeswan/kernpatch/UMLPOOL/swan/ linux
+</PRE>
+<P> Set the following in the environment:</P>
+<PRE>
+UML_east_OPT=&quot;debug gdb-pid=1659&quot;
+</PRE>
+<P> Then start the user-mode-linux in the test scheme you wish:</P>
+<PRE>
+marajade-[kernpatch/testing/klips/east-icmp-02] mcr 1220 %../../utils/runme.sh
+</PRE>
+ The user-mode-linux will stop on boot, giving you a chance to attach to
+ the process:
+<PRE>
+(gdb) file linux
+Reading symbols from linux...done.
+(gdb) attach 1
+Attaching to program: /mara4/freeswan/kernpatch/UMLPOOL/swan/linux, process 1
+0xa0118bc1 in kill () at hostfs_kern.c:770
+</PRE>
+<P> At this point, break points should be created as appropriate.</P>
+<H2><A NAME="23_1">Other notes about debugging</A></H2>
+<P> If you are running a standard test, after all the packets are sent,
+ the UML will be shutdown. This can cause problems, because the UML may
+ get terminated while you are debugging.</P>
+<P> The environment variable <CODE>NETJIGWAITUSER</CODE> can be set to
+ &quot;waituser&quot;. If so, then the testing system will prompt before exiting
+ the test.</P>
+<H1><A NAME="24">User-Mode-Linux mysteries</A></H1>
+<UL>
+<LI> running more than one UML of the same name (e.g. &quot;west&quot;) can cause
+ problems.</LI>
+<LI> running more than one UML from the same root file system is not a
+ good idea.</LI>
+<LI> all this means that running &quot;make check&quot; twice on the same machine
+ is probably not a good idea.</LI>
+<LI> occationally, UMLs will get stuck. This can happen like:
+<!--BLOCK-->
+ 15134 ? T
+ 0:00 /spare/hugh/uml/uml2.4.18-sept5/umlbuild/east/linux (east)
+ [/bin/sh] 15138 ? T 0:00
+ /spare/hugh/uml/uml2.4.18-sept5/umlbuild/east/linux (east) [halt]</(null)>
+ these will need to be killed. Note that they are in &quot;T&quot;racing mode.</LI>
+<LI> UMLs can also hang, and will report &quot;Tracing myself and I can't get
+ out&quot;. This is a bug in UML. There are ways to find out what is going on
+ and report this to the UML people, but we don't know the magic right
+ now.</LI>
+</UL>
+<H1><A NAME="25">Getting more info from uml_netjig</A></H1>
+<P> uml_netjig can be compiled with a built-in tcpdump. This uses
+ not-yet-released code from<A HREF="http://www.tcpdump.org/">
+ www.tcpdump.org</A>. Please see the instructions in <CODE>
+testing/utils/uml_netjig/Makefile</CODE>.</P>
+<HR>
+<H1><A name="politics">History and politics of cryptography</A></H1>
+<P>Cryptography has a long and interesting history, and has been the
+ subject of considerable political controversy.</P>
+<H2><A name="intro.politics">Introduction</A></H2>
+<H3><A NAME="26_1_1">History</A></H3>
+<P>The classic book on the history of cryptography is David Kahn's<A href="#Kahn">
+ The Codebreakers</A>. It traces codes and codebreaking from ancient
+ Egypt to the 20th century.</P>
+<P>Diffie and Landau<A href="#diffie"> Privacy on the Line: The Politics
+ of Wiretapping and Encryption</A> covers the history from the First
+ World War to the 1990s, with an emphasis on the US.</P>
+<H4><A NAME="26_1_1_1">World War II</A></H4>
+<P>During the Second World War, the British &quot;Ultra&quot; project achieved one
+ of the greatest intelligence triumphs in the history of warfare,
+ breaking many Axis codes. One major target was the Enigma cipher
+ machine, a German device whose users were convinced it was unbreakable.
+ The American &quot;Magic&quot; project had some similar triumphs against Japanese
+ codes.</P>
+<P>There are many books on this period. See our bibliography for
+ several. Two I particularly like are:</P>
+<UL>
+<LI>Andrew Hodges has done a superb<A href="http://www.turing.org.uk/book/">
+ biography</A> of Alan Turing, a key player among the Ultra
+ codebreakers. Turing was also an important computer pioneer. The terms<A
+href="http://www.abelard.org/turpap/turpap.htm"> Turing test</A> and<A href="http://plato.stanford.edu/entries/turing-machine/">
+ Turing machine</A> are named for him, as is the<A href="http://www.acm.org">
+ ACM</A>'s highest technical<A href="http://www.acm.org/awards/taward.html">
+ award</A>.</LI>
+<LI>Neal Stephenson's<A href="#neal"> Cryptonomicon</A> is a novel with
+ cryptography central to the plot. Parts of it take place during WW II,
+ other parts today.</LI>
+</UL>
+<P>Bletchley Park, where much of the Ultra work was done, now has a
+ museum and a<A href="http://www.bletchleypark.org.uk/"> web site</A>.</P>
+<P>The Ultra work introduced three major innovations.</P>
+<UL>
+<LI>The first break of Enigma was achieved by Polish Intelligence in
+ 1931. Until then most code-breakers had been linguists, but a different
+ approach was needed to break machine ciphers. Polish Intelligence
+ recruited bright young mathematicians to crack the &quot;unbreakable&quot;
+ Enigma. When war came in 1939, the Poles told their allies about this,
+ putting Britain on the road to Ultra. The British also adopted a
+ mathematical approach.</LI>
+<LI>Machines were extensively used in the attacks. First the Polish
+ &quot;Bombe&quot; for attacking Enigma, then British versions of it, then
+ machines such as Collosus for attacking other codes. By the end of the
+ war, some of these machines were beginning to closely resemble digital
+ computers. After the war, a team at Manchester University, several old
+ Ultra hands included, built one of the world's first actual
+ general-purpose digital computers.</LI>
+<LI>Ultra made codebreaking a large-scale enterprise, producing
+ intelligence on an industrial scale. This was not a &quot;black chamber&quot;,
+ not a hidden room in some obscure government building with a small crew
+ of code-breakers. The whole operation -- from wholesale interception of
+ enemy communications by stations around the world, through large-scale
+ code-breaking and analysis of the decrypted material (with an enormous
+ set of files for cross-referencing), to delivery of intelligence to
+ field commanders -- was huge, and very carefully managed.</LI>
+</UL>
+<P>So by the end of the war, Allied code-breakers were expert at
+ large-scale mechanised code-breaking. The payoffs were enormous.</P>
+<H4><A name="postwar">Postwar and Cold War</A></H4>
+<P>The wartime innovations were enthusiastically adopted by post-war and
+ Cold War signals intelligence agencies. Presumably many nations now
+ have some agency capable of sophisticated attacks on communications
+ security, and quite a few engage in such activity on a large scale.</P>
+<P>America's<A href="#NSA"> NSA</A>, for example, is said to be both the
+ world's largest employer of mathematicians and the world's largest
+ purchaser of computer equipment. Such claims may be somewhat
+ exaggerated, but beyond doubt the NSA -- and similar agencies in other
+ countries -- have some excellent mathematicians, lots of powerful
+ computers, sophisticated software, and the organisation and funding to
+ apply them on a large scale. Details of the NSA budget are secret, but
+ there are some published<A href="http://www.fas.org/irp/nsa/nsabudget.html">
+ estimates</A>.</P>
+<P>Changes in the world's communications systems since WW II have
+ provided these agencies with new targets. Cracking the codes used on an
+ enemy's military or diplomatic communications has been common practice
+ for centuries. Extensive use of radio in war made large-scale attacks
+ such as Ultra possible. Modern communications make it possible to go
+ far beyond that. Consider listening in on cell phones, or intercepting
+ electronic mail, or tapping into the huge volumes of data on new media
+ such as fiber optics or satellite links. None of these targets existed
+ in 1950. All of them can be attacked today, and almost certainly are
+ being attacked.</P>
+<P>The Ultra story was not made public until the 1970s. Much of the
+ recent history of codes and code-breaking has not been made public, and
+ some of it may never be. Two important books are:</P>
+<UL>
+<LI>Bamford's<A href="#puzzle"> The Puzzle Palace</A>, a history of the
+ NSA</LI>
+<LI>Hager's<A href="http://www.fas.org/irp/eprint/sp/index.html"> Secret
+ Power</A>, about the<A href="http://sg.yahoo.com/government/intelligence/echelon_network/">
+ Echelon</A> system -- the US, UK, Canada, Australia and New Zealand
+ co-operating to monitor much of the world's communications.</LI>
+</UL>
+<P>Note that these books cover only part of what is actually going on,
+ and then only the activities of nations open and democratic enough that
+ (some of) what they are doing can be discovered. A full picture,
+ including:</P>
+<UL>
+<LI>actions of the English-speaking democracies not covered in those
+ books</LI>
+<LI>actions of other more-or-less sane governments</LI>
+<LI>the activities of various more-or-less insane governments</LI>
+<LI>possibilities for unauthorized action by government employees</LI>
+<LI>possible actions by large non-government organisations:
+ corporations, criminals, or conspiracies</LI>
+</UL>
+<P>might be really frightening.</P>
+<H4><A name="recent">Recent history -- the crypto wars</A></H4>
+<P>Until quite recently, cryptography was primarily a concern of
+ governments, especially of the military, of spies, and of diplomats.
+ Much of it was extremely secret.</P>
+<P>In recent years, that has changed a great deal. With computers and
+ networking becoming ubiquitous, cryptography is now important to almost
+ everyone. Among the developments since the 1970s:</P>
+<UL>
+<LI>The US gov't established the Data Encryption Standard,<A href="#DES">
+ DES</A>, a<A href="#block"> block cipher</A> for cryptographic
+ protection of unclassfied documents.</LI>
+<LI>DES also became widely used in industry, especially regulated
+ industries such as banking.</LI>
+<LI>Other nations produced their own standards, such as<A href="glossary.html#GOST">
+ GOST</A> in the Soviet Union.</LI>
+<LI><A href="#public">Public key</A> cryptography was invented by Diffie
+ and Hellman.</LI>
+<LI>Academic conferences such as<A href="http://www-cse.ucsd.edu/users/mihir/crypto2k.html">
+ Crypto</A> and<A href="http://www.esat.kuleuven.ac.be/cosic/eurocrypt2000/">
+ Eurocrypt</A> began.</LI>
+<LI>Several companies began offerring cryptographic products:<A href="#RSAco">
+ RSA</A>,<A href="#PGPI"> PGP</A>, the many vendors with<A href="#PKI">
+ PKI</A> products, ...</LI>
+<LI>Cryptography appeared in other products: operating systems, word
+ processors, ...</LI>
+<LI>Network protocols based on crypto were developed:<A href="#ssh"> SSH</A>
+,<A href="#SSL"> SSL</A>,<A href="#IPSEC"> IPsec</A>, ...</LI>
+<LI>Crytography came into widespread use to secure bank cards,
+ terminals, ...</LI>
+<LI>The US government replaced<A href="#DES"> DES</A> with the much
+ stronger Advanced Encryption Standard,<A href="#AES"> AES</A></LI>
+</UL>
+<P>This has led to a complex ongoing battle between various mainly
+ government groups wanting to control the spread of crypto and various
+ others, notably the computer industry and the<A href="http://online.offshore.com.ai/security/">
+ cypherpunk</A> crypto advocates, wanting to encourage widespread use.</P>
+<P>Steven Levy has written a fine history of much of this, called<A href="#crypto">
+ Crypto: How the Code rebels Beat the Government -- Saving Privacy in
+ the Digital Age</A>.</P>
+<P>The FreeS/WAN project is to a large extent an outgrowth of cypherpunk
+ ideas. Our reasons for doing the project can be seen in these quotes
+ from the<A href="http://www.eff.org/pub/Privacy/Crypto_misc/cypherpunk.manifesto">
+ Cypherpunk Manifesto</A>:</P>
+<BLOCKQUOTE> Privacy is necessary for an open society in the electronic
+ age. ...
+<P>We cannot expect governments, corporations, or other large, faceless
+ organizations to grant us privacy out of their beneficence. It is to
+ their advantage to speak of us, and we should expect that they will
+ speak. ...</P>
+<P>We must defend our own privacy if we expect to have any. ...</P>
+<P>Cypherpunks write code. We know that someone has to write software to
+ defend privacy, and since we can't get privacy unless we all do, we're
+ going to write it. We publish our code so that our fellow Cypherpunks
+ may practice and play with it. Our code is free for all to use,
+ worldwide. We don't much care if you don't approve of the software we
+ write. We know that software can't be destroyed and that a widely
+ dispersed system can't be shut down.</P>
+<P>Cypherpunks deplore regulations on cryptography, for encryption is
+ fundamentally a private act. ...</P>
+<P>For privacy to be widespread it must be part of a social contract.
+ People must come and together deploy these systems for the common good.
+ ...</P>
+</BLOCKQUOTE>
+<P>To quote project leader John Gilmore:</P>
+<BLOCKQUOTE> We are literally in a race between our ability to build and
+ deploy technology, and their ability to build and deploy laws and
+ treaties. Neither side is likely to back down or wise up until it has
+ definitively lost the race.</BLOCKQUOTE>
+<P>If FreeS/WAN reaches its goal of making<A href="#opp.intro">
+ opportunistic encryption</A> widespread so that secure communication
+ can become the default for a large part of the net, we will have struck
+ a major blow.</P>
+<H3><A name="intro.poli">Politics</A></H3>
+<P>The political problem is that nearly all governments want to monitor
+ their enemies' communications, and some want to monitor their citizens.
+ They may be very interested in protecting some of their own
+ communications, and often some types of business communication, but not
+ in having everyone able to communicate securely. They therefore attempt
+ to restrict availability of strong cryptography as much as possible.</P>
+<P>Things various governments have tried or are trying include:</P>
+<UL>
+<LI>Echelon, a monitor-the-world project of the US, UK, NZ, Australian
+ and Canadian<A href="#SIGINT"> signals intelligence</A> agencies. See
+ this<A href="http://sg.yahoo.com/government/intelligence/echelon_network/">
+ collection</A> of links and this<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2640682,00.html">
+ story</A> on the French Parliament's reaction.</LI>
+<LI>Others governments may well have their own Echelon-like projects. To
+ quote the Dutch Minister of Defense, as reported in a German<A href="http://www.heise.de/tp/english/inhalt/te/4729/1.html">
+ magazine</A>:<BLOCKQUOTE> The government believes not only the
+ governments associated with Echelon are able to intercept communication
+ systems, but that it is an activity of the investigative authorities
+ and intelligence services of many countries with governments of
+ different political signature.</BLOCKQUOTE> Even if they have nothing
+ on the scale of Echelon, most intelligence agencies and police forces
+ certainly have some interception capability.</LI>
+<LI><A href="#NSA">NSA</A> tapping of submarine communication cables,
+ described in<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2764372,00.html">
+ this article</A></LI>
+<LI>A proposal for international co-operation on<A href="http://www.heise.de/tp/english/special/enfo/4306/1.html">
+ Internet surveillance</A>.</LI>
+<LI>Alleged<A href="http://cryptome.org/nsa-sabotage.htm"> sabotage</A>
+ of security products by the<A href="#NSA"> NSA</A> (the US signals
+ intelligence agency).</LI>
+<LI>The German armed forces and some government departments will stop
+ using American software for fear of NSA &quot;back doors&quot;, according to this<A
+href="http://www.theregister.co.uk/content/4/17679.html"> news story</A>
+.</LI>
+<LI>The British Regulation of Investigatory Powers bill. See this<A href="http://www.fipr.org/rip/index.html">
+ web page.</A> and perhaps this<A href="http://ars.userfriendly.org/cartoons/?id=20000806&amp;mode=classic">
+ cartoon</A>.</LI>
+<LI>A Russian<A href="http://www.eff.org/pub/Privacy/Foreign_and_local/Russia/russian_crypto_ban_english.edict">
+ ban</A> on cryptography</LI>
+<LI>Chinese<A href="http://www.eff.org/pub/Misc/Publications/Declan_McCullagh/www/global/china">
+ controls</A> on net use.</LI>
+<LI>The FBI's carnivore system for covert searches of email. See this<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2601502,00.html">
+ news coverage</A> and this<A href="http://www.crypto.com/papers/carnivore-risks.html">
+ risk assessment</A>. The government had an external review of some
+ aspects of this system done. See this<A href="http://www.crypto.com/papers/carnivore_report_comments.html">
+ analysis</A> of that review. Possible defenses against Carnivore
+ include:
+<UL>
+<LI><A href="#PGP">PGP</A> for end-to-end mail encryption</LI>
+<LI><A href="http://www.home.aone.net.au/qualcomm/">secure sendmail</A>
+ for server-to-server encryption</LI>
+<LI>IPsec encryption on the underlying IP network</LI>
+</UL>
+</LI>
+<LI>export laws restricting strong cryptography as a munition. See<A href="#exlaw">
+ discussion</A> below.</LI>
+<LI>various attempts to convince people that fundamentally flawed
+ cryptography, such as encryption with a<A href="#escrow"> back door</A>
+ for government access to data or with<A href="#shortkeys"> inadequate
+ key lengths</A>, was adequate for their needs.</LI>
+</UL>
+<P>Of course governments are by no means the only threat to privacy and
+ security on the net. Other threats include:</P>
+<UL>
+<LI>industrial espionage, as for example in this<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2626931,00.html">
+ news story</A></LI>
+<LI>attacks by organised criminals, as in this<A href="http://www.sans.org/newlook/alerts/NTE-bank.htm">
+ large-scale attack</A></LI>
+<LI>collection of personal data by various companies.
+<UL>
+<LI>for example, consider the various corporate winners of Privacy
+ International's<A href="http://www.privacyinternational.org/bigbrother/">
+ Big Brother Awards</A>.</LI>
+<LI><A href="http://www.zeroknowledge.com">Zero Knowledge</A> sell tools
+ to defend against this</LI>
+</UL>
+</LI>
+<LI>individuals may also be a threat in a variety of ways and for a
+ variety of reasons</LI>
+<LI>in particular, an individual with access to government or industry
+ data collections could do considerable damage using that data in
+ unauthorized ways.</LI>
+</UL>
+<P>One<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2640674,00.html">
+ study</A> enumerates threats and possible responses for small and
+ medium businesses. VPNs are a key part of the suggested strategy.</P>
+<P>We consider privacy a human right. See the UN's<A href="http://www.un.org/Overview/rights.html">
+ Universal Declaration of Human Rights</A>, article twelve:</P>
+<BLOCKQUOTE> No one shall be subjected to arbitrary interference with
+ his privacy, family, home or correspondence, nor to attacks upon his
+ honor and reputation. Everyone has the right to the protection of the
+ law against such interference or attacks.</BLOCKQUOTE>
+<P>Our objective is to help make privacy possible on the Internet using
+ cryptography strong enough not even those well-funded government
+ agencies are likely to break it. If we can do that, the chances of
+ anyone else breaking it are negliible.</P>
+<H3><A NAME="26_1_3">Links</A></H3>
+<P>Many groups are working in different ways to defend privacy on the
+ net and elsewhere. Please consider contributing to one or more of these
+ groups:</P>
+<UL>
+<LI>the EFF's<A href="http://www.eff.org/crypto/"> Privacy Now!</A>
+ campaign</LI>
+<LI>the<A href="http://www.gilc.org"> Global Internet Liberty Campaign</A>
+</LI>
+<LI><A href="http://www.cpsr.org/program/privacy/privacy.html">Computer
+ Professionals for Social Responsibility</A></LI>
+</UL>
+<P>For more on these issues see:</P>
+<UL>
+<LI>Steven Levy (Newsweek's chief technology writer and author of the
+ classic &quot;Hackers&quot;) new book<A href="#crypto"> Crypto: How the Code
+ Rebels Beat the Government--Saving Privacy in the Digital Age</A></LI>
+<LI>Simson Garfinkel (Boston Globe columnist and author of books on<A href="#PGP">
+ PGP</A> and<A href="#practical"> Unix Security</A>) book<A href="#Garfinkel">
+ Database Nation: the death of privacy in the 21st century</A></LI>
+</UL>
+<P>There are several collections of<A href="#quotes"> crypto quotes</A>
+ on the net.</P>
+<P>See also the<A href="biblio.html"> bibliography</A> and our list of<A href="#policy">
+ web references</A> on cryptography law and policy.</P>
+<H3><A NAME="26_1_4">Outline of this section</A></H3>
+<P>The remainder of this section includes two pieces of writing by our
+ project leader</P>
+<UL>
+<LI>his<A href="#gilmore"> rationale</A> for starting this</LI>
+<LI>another<A href="#policestate"> discussion</A> of project goals</LI>
+</UL>
+<P>and discussions of:</P>
+<UL>
+<LI><A href="#desnotsecure">why we do not use DES</A></LI>
+<LI><A href="#exlaw">cryptography export laws</A></LI>
+<LI>why<A href="#escrow"> government access to keys</A> is not a good
+ idea</LI>
+<LI>the myth that<A href="#shortkeys"> short keys</A> are adequate for
+ some security requirements</LI>
+</UL>
+<P>and a section on<A href="#press"> press coverage of FreeS/WAN</A>.</P>
+<H2><A name="leader">From our project leader</A></H2>
+<P>FreeS/WAN project founder John Gilmore wrote a web page about why we
+ are doing this. The version below is slightly edited, to fit this
+ format and to update some links. For a version without these edits, see
+ his<A href="http://www.toad.com/gnu/"> home page</A>.</P>
+<CENTER>
+<H3><A name="gilmore">Swan: Securing the Internet against Wiretapping</A>
+</H3>
+</CENTER>
+<P>My project for 1996 was to<B> secure 5% of the Internet traffic
+ against passive wiretapping</B>. It didn't happen in 1996, so I'm still
+ working on it in 1997, 1998, and 1999! If we get 5% in 1999 or 2000, we
+ can secure 20% the next year, against both active and passive attacks;
+ and 80% the following year. Soon the whole Internet will be private and
+ secure. The project is called S/WAN or S/Wan or Swan for Secure Wide
+ Area Network; since it's free software, we call it FreeSwan to
+ distinguish it from various commercial implementations.<A href="http://www.rsa.com/rsa/SWAN/">
+ RSA</A> came up with the term &quot;S/WAN&quot;. Our main web site is at<A href="http://www.freeswan.org/">
+ http://www.freeswan.org/</A>. Want to help?</P>
+<P>The idea is to deploy PC-based boxes that will sit between your local
+ area network and the Internet (near your firewall or router) which
+ opportunistically encrypt your Internet packets. Whenever you talk to a
+ machine (like a Web site) that doesn't support encryption, your traffic
+ goes out &quot;in the clear&quot; as usual. Whenever you connect to a machine
+ that does support this kind of encryption, this box automatically
+ encrypts all your packets, and decrypts the ones that come in. In
+ effect, each packet gets put into an &quot;envelope&quot; on one side of the net,
+ and removed from the envelope when it reaches its destination. This
+ works for all kinds of Internet traffic, including Web access, Telnet,
+ FTP, email, IRC, Usenet, etc.</P>
+<P>The encryption boxes are standard PC's that use freely available
+ Linux software that you can download over the Internet or install from
+ a cheap CDROM.</P>
+<P>This wasn't just my idea; lots of people have been working on it for
+ years. The encryption protocols for these boxes are called<A href="#IPSEC">
+ IPSEC (IP Security)</A>. They have been developed by the<A href="http://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html">
+ IP Security Working Group</A> of the<A href="http://www.ietf.org/">
+ Internet Engineering Task Force</A>, and will be a standard part of the
+ next major version of the Internet protocols (<A href="http://playground.sun.com/pub/ipng/html/ipng-main.html">
+IPv6</A>). For today's (IP version 4) Internet, they are an option.</P>
+<P>The<A href="http://www.iab.org/iab"> Internet Architecture Board</A>
+ and<A href="http://www.ietf.org/"> Internet Engineering Steering Group</A>
+ have taken a<A href="iab-iesg.stmt"> strong stand</A> that the Internet
+ should use powerful encryption to provide security and privacy. I think
+ these protocols are the best chance to do that, because they can be
+ deployed very easily, without changing your hardware or software or
+ retraining your users. They offer the best security we know how to
+ build, using the Triple-DES, RSA, and Diffie-Hellman algorithms.</P>
+<P>This &quot;opportunistic encryption box&quot; offers the &quot;fax effect&quot;. As each
+ person installs one for their own use, it becomes more valuable for
+ their neighbors to install one too, because there's one more person to
+ use it with. The software automatically notices each newly installed
+ box, and doesn't require a network administrator to reconfigure it.
+ Instead of &quot;virtual private networks&quot; we have a &quot;REAL private network&quot;;
+ we add privacy to the real network instead of layering a
+ manually-maintained virtual network on top of an insecure Internet.</P>
+<H4><A NAME="26_2_1_1">Deployment of IPSEC</A></H4>
+<P>The US government would like to control the deployment of IP Security
+ with its<A href="#exlaw"> crypto export laws</A>. This isn't a problem
+ for my effort, because the cryptographic work is happening outside the
+ United States. A foreign philanthropist, and others, have donated the
+ resources required to add these protocols to the Linux operating
+ system.<A href="http://www.linux.org/"> Linux</A> is a complete, freely
+ available operating system for IBM PC's and several kinds of
+ workstation, which is compatible with Unix. It was written by Linus
+ Torvalds, and is still maintained by a talented team of expert
+ programmers working all over the world and coordinating over the
+ Internet. Linux is distributed under the<A href="#GPL"> GNU Public
+ License</A>, which gives everyone the right to copy it, improve it,
+ give it to their friends, sell it commercially, or do just about
+ anything else with it, without paying anyone for the privilege.</P>
+<P>Organizations that want to secure their network will be able to put
+ two Ethernet cards into an IBM PC, install Linux on it from a $30 CDROM
+ or by downloading it over the net, and plug it in between their
+ Ethernet and their Internet link or firewall. That's all they'll have
+ to do to encrypt their Internet traffic everywhere outside their own
+ local area network.</P>
+<P>Travelers will be able to run Linux on their laptops, to secure their
+ connection back to their home network (and to everywhere else that they
+ connect to, such as customer sites). Anyone who runs Linux on a
+ standalone PC will also be able to secure their network connections,
+ without changing their application software or how they operate their
+ computer from day to day.</P>
+<P>There will also be numerous commercially available firewalls that use
+ this technology.<A href="http://www.rsa.com/"> RSA Data Security</A> is
+ coordinating the<A href="http://www.rsa.com/rsa/SWAN"> S/Wan (Secure
+ Wide Area Network)</A> project among more than a dozen vendors who use
+ these protocols. There's a<A href="http://www.rsa.com/rsa/SWAN/swan_test.htm">
+ compatability chart</A> that shows which vendors have tested their
+ boxes against which other vendors to guarantee interoperatility.</P>
+<P>Eventually it will also move into the operating systems and
+ networking protocol stacks of major vendors. This will probably take
+ longer, because those vendors will have to figure out what they want to
+ do about the export controls.</P>
+<H4><A NAME="26_2_1_2">Current status</A></H4>
+<P>My initial goal of securing 5% of the net by Christmas '96 was not
+ met. It was an ambitious goal, and inspired me and others to work hard,
+ but was ultimately too ambitious. The protocols were in an early stage
+ of development, and needed a lot more protocol design before they could
+ be implemented. As of April 1999, we have released version 1.0 of the
+ software (<A href="ftp://ftp.xs4all.nl/freeswan/freeswan-1.0.tar.gz">
+freeswan-1.0.tar.gz</A>), which is suitable for setting up Virtual
+ Private Networks using shared secrets for authentication. It does not
+ yet do opportunistic encryption, or use DNSSEC for authentication;
+ those features are coming in a future release.</P>
+<DL>
+<DT>Protocols</DT>
+<DD>The low-level encrypted packet formats are defined. The system for
+ publishing keys and providing secure domain name service is defined.
+ The IP Security working group has settled on an NSA-sponsored protocol
+ for key agreement (called ISAKMP/Oakley), but it is still being worked
+ on, as the protocol and its documentation is too complex and
+ incomplete. There are prototype implementations of ISAKMP. The protocol
+ is not yet defined to enable opportunistic encryption or the use of
+ DNSSEC keys.</DD>
+<DT>Linux Implementation</DT>
+<DD>The Linux implementation has reached its first major release and is
+ ready for production use in manually-configured networks, using Linux
+ kernel version 2.0.36.</DD>
+<DT>Domain Name System Security</DT>
+<DD>There is now a release of BIND 8.2 that includes most DNS Security
+ features.
+<P>The first prototype implementation of Domain Name System Security was
+ funded by<A href="#DARPA"> DARPA</A> as part of their<A href="http://www.darpa.mil/ito/research/is/index.html">
+ Information Survivability program</A>.<A href="http://www.tis.com">
+ Trusted Information Systems</A> wrote a modified version of<A href="http://www.isc.org/bind.html">
+ BIND</A>, the widely-used Berkeley implementation of the Domain Name
+ System.</P>
+<P>TIS, ISC, and I merged the prototype into the standard version of
+ BIND. The first production version that supports KEY and SIG records is<B>
+ bind-4.9.5</B>. This or any later version of BIND will do for
+ publishing keys. It is available from the<A href="http://www.isc.org/bind.html">
+ Internet Software Consortium</A>. This version of BIND is not
+ export-controlled since it does not contain any cryptography. Later
+ releases starting with BIND 8.2 include cryptography for authenticating
+ DNS records, which is also exportable. Better documentation is needed.</P>
+</DD>
+</DL>
+<H4><A NAME="26_2_1_3">Why?</A></H4>
+<P>Because I can. I have made enough money from several successful
+ startup companies, that for a while I don't have to work to support
+ myself. I spend my energies and money creating the kind of world that
+ I'd like to live in and that I'd like my (future) kids to live in.
+ Keeping and improving on the civil rights we have in the United States,
+ as we move more of our lives into cyberspace, is a particular goal of
+ mine.</P>
+<H4><A NAME="26_2_1_4">What You Can Do</A></H4>
+<DL>
+<DT>Install the latest BIND at your site.</DT>
+<DD>You won't be able to publish any keys for your domain, until you
+ have upgraded your copy of BIND. The thing you really need from it is
+ the new version of<I> named</I>, the Name Daemon, which knows about the
+ new KEY and SIG record types. So, download it from the<A href="http://www.isc.org/bind.html">
+ Internet Software Consortium</A> and install it on your name server
+ machine (or get your system administrator, or Internet Service
+ Provider, to install it). Both your primary DNS site and all of your
+ secondary DNS sites will need the new release before you will be able
+ to publish your keys. You can tell which sites this is by running the
+ Unix command &quot;dig MYDOMAIN ns&quot; and seeing which sites are mentioned in
+ your NS (name server) records.</DD>
+<DT>Set up a Linux system and run a 2.0.x kernel on it</DT>
+<DD>Get a machine running Linux (say the 5.2 release from<A href="http://www.redhat.com">
+ Red Hat</A>). Give the machine two Ethernet cards.</DD>
+<DT>Install the Linux IPSEC (Freeswan) software</DT>
+<DD>If you're an experienced sysadmin or Linux hacker, install the
+ freeswan-1.0 release, or any later release or snapshot. These releases
+ do NOT provide automated &quot;opportunistic&quot; operation; they must be
+ manually configured for each site you wish to encrypt with.</DD>
+<DT>Get on the linux-ipsec mailing list</DT>
+<DD>The discussion forum for people working on the project, and testing
+ the code and documentation, is: linux-ipsec@clinet.fi. To join this
+ mailing list, send email to<A href="mailto:linux-ipsec-REQUEST@clinet.fi">
+ linux-ipsec-REQUEST@clinet.fi</A> containing a line of text that says
+ &quot;subscribe linux-ipsec&quot;. (You can later get off the mailing list the
+ same way -- just send &quot;unsubscribe linux-ipsec&quot;).</DD>
+<P></P>
+<DT>Check back at this web page every once in a while</DT>
+<DD>I update this page periodically, and there may be new information in
+ it that you haven't seen. My intent is to send email to the mailing
+ list when I update the page in any significant way, so subscribing to
+ the list is an alternative.</DD>
+</DL>
+<P>Would you like to help? I can use people who are willing to write
+ documentation, install early releases for testing, write cryptographic
+ code outside the United States, sell pre-packaged software or systems
+ including this technology, and teach classes for network administrators
+ who want to install this technology. To offer to help, send me email at
+ gnu@toad.com. Tell me what country you live in and what your
+ citizenship is (it matters due to the export control laws; personally I
+ don't care). Include a copy of your resume and the URL of your home
+ page. Describe what you'd like to do for the project, and what you're
+ uniquely qualified for. Mention what other volunteer projects you've
+ been involved in (and how they worked out). Helping out will require
+ that you be able to commit to doing particular things, meet your
+ commitments, and be responsive by email. Volunteer projects just don't
+ work without those things.</P>
+<H4><A NAME="26_2_1_5">Related projects</A></H4>
+<DL>
+<DT>IPSEC for NetBSD</DT>
+<DD>This prototype implementation of the IP Security protocols is for
+ another free operating system.<A href="ftp://ftp.funet.fi/pub/unix/security/net/ip/BSDipsec.tar.gz">
+ Download BSDipsec.tar.gz</A>.</DD>
+<DT>IPSEC for<A href="http://www.openbsd.org"> OpenBSD</A></DT>
+<DD>This prototype implementation of the IP Security protocols is for
+ yet another free operating system. It is directly integrated into the
+ OS release, since the OS is maintained in Canada, which has freedom of
+ speech in software.</DD>
+</DL>
+<H3><A name="policestate">Stopping wholesale monitoring</A></H3>
+<P>From a message project leader John Gilmore posted to the mailing
+ list:</P>
+<PRE>John Denker wrote:
+
+&gt; Indeed there are several ways in which the documentation overstates the
+&gt; scope of what this project does -- starting with the name
+&gt; FreeS/WAN. There's a big difference between having an encrypted IP tunnel
+&gt; versus having a Secure Wide-Area Network. This software does a fine job of
+&gt; the former, which is necessary but not sufficient for the latter.
+
+The goal of the project is to make it very hard to tap your wide area
+communications. The current system provides very good protection
+against passive attacks (wiretapping and those big antenna farms).
+Active attacks, which involve the intruder sending packets to your
+system (like packets that break into sendmail and give them a root
+shell :-) are much harder to guard against. Active attacks that
+involve sending people (breaking into your house and replacing parts
+of your computer with ones that transmit what you're doing) are also
+much harder to guard against. Though we are putting effort into
+protecting against active attacks, it's a much bigger job than merely
+providing strong encryption. It involves general computer security,
+and general physical security, which are two very expensive problems
+for even a site to solve, let alone to build into a whole society.
+
+The societal benefit of building an infrastructure that protects
+well against passive attacks is that it makes it much harder to do
+undetected bulk monitoring of the population. It's a defense against
+police-states, not against policemen.
+
+Policemen can put in the effort required to actively attack sites that
+they have strong suspicions about. But police states won't be able to
+build systems that automatically monitor everyone's communications.
+Either they will be able to monitor only a small subset of the
+populace (by targeting those who screwed up their passive security),
+or their monitoring activities will be detectable by those monitored
+(active attacks leave packet traces or footprints), which can then be
+addressed through the press and through political means if they become
+too widespread.
+
+FreeS/WAN does not protect very well against traffic analysis, which
+is a kind of widespread police-state style monitoring that still
+reveals significant information (who's talking to who) without
+revealing the contents of what was said. Defenses against traffic
+analysis are an open research problem. Zero Knowledge Systems is
+actively deploying a system designed to thwart it, designed by Ian
+Goldberg. The jury is out on whether it actually works; a lot more
+experience with it will be needed.</PRE>
+<P>Notes on things mentioned in that message:</P>
+<UL>
+<LI>Denker is a co-author of a<A href="#applied"> paper</A> on a large
+ FreeS/WAN application.</LI>
+<LI>Information on Zero Knowledge is on their<A href="http://www.zks.net/">
+ web site</A>. Their Freedom product, designed to provide untracable
+ pseudonyms for use on the net, is no longer marketed.</LI>
+<LI>Another section of our documentation discusses ways to<A href="#traffic.resist">
+ resist traffic analysis</A>.</LI>
+</UL>
+<H2><A name="weak">Government promotion of weak crypto</A></H2>
+<P>Various groups, especially governments and especially the US
+ government, have a long history of advocating various forms of bogus
+ security.</P>
+<P>We regard bogus security as extremely dangerous. If users are
+ deceived into relying on bogus security, then they may be exposed to
+ large risks. They would be better off having no security and knowing
+ it. At least then they would be careful about what they said.</P>
+<P><STRONG>Avoiding bogus security is a key design criterion for
+ everything we do in FreeS/WAN</STRONG>. The most conspicuous example is
+ our refusal to support<A href="#desnotsecure"> single DES</A>. Other
+ IPsec &quot;features&quot; which we do not implement are discussed in our<A href="#dropped">
+ compatibility</A> document.</P>
+<H3><A name="escrow">Escrowed encryption</A></H3>
+<P>Various governments have made persistent attempts to encourage or
+ mandate &quot;escrowed encrytion&quot;, also called &quot;key recovery&quot;, or GAK for
+ &quot;government access to keys&quot;. The idea is that cryptographic keys be
+ held by some third party and turned over to law enforcement or security
+ agencies under some conditions.</P>
+<PRE> Mary had a little key - she kept it in escrow,
+ and every thing that Mary said,
+ the feds were sure to know.</PRE>
+<P>A<A href="#quotes"> crypto quotes</A> page attributes this to<A href="http://www.scramdisk.clara.net/">
+ Sam Simpson</A>.</P>
+<P>There is an excellent paper available on<A href="http://www.cdt.org/crypto/risks98/">
+ Risks of Escrowed Encryption</A>, from a group of cryptographic
+ luminaries which included our project leader.</P>
+<P>Like any unnecessary complication, GAK tends to weaken security of
+ any design it infects. For example:</P>
+<UL>
+<LI>Matt Blaze found a fatal flaw in the US government's Clipper chip
+ shortly after design information became public. See his paper &quot;Protocol
+ Failure in the Escrowed Encryption Standard&quot; on his<A href="http://www.crypto.com/papers/">
+ papers</A> page.</LI>
+<LI>a rather<A href="http://www.pgp.com/other/advisories/adk.asp"> nasty
+ bug</A> was found in the &quot;additional decryption keys&quot; &quot;feature&quot; of some
+ releases of<A href="#PGP"> PGP</A></LI>
+</UL>
+<P>FreeS/WAN does not support escrowed encryption, and never will.</P>
+<H3><A name="shortkeys">Limited key lengths</A></H3>
+<P>Various governments, and some vendors, have also made persistent
+ attempts to convince people that:</P>
+<UL>
+<LI>weak systems are sufficient for some data</LI>
+<LI>strong cryptography should be reserved for cases where the extra
+ overheads are justified</LI>
+</UL>
+<P><STRONG>This is utter nonsense</STRONG>.</P>
+<P>Weak systems touted include:</P>
+<UL>
+<LI>the ludicrously weak (deliberately crippled) 40-bit ciphers that
+ until recently were all various<A href="#exlaw"> export laws</A>
+ allowed</LI>
+<LI>56-bit single DES, discussed<A href="#desnotsecure"> below</A></LI>
+<LI>64-bit symmetric ciphers and 512-bit RSA, the maximums for
+ unrestricted export under various current laws</LI>
+</UL>
+<P>The notion that choice of ciphers or keysize should be determined by
+ a trade-off between security requirements and overheads is pure
+ bafflegab.</P>
+<UL>
+<LI>For most<A href="#symmetric"> symmetric ciphers</A>, it is simply a
+ lie. Any block cipher has some natural maximum keysize inherent in the
+ design -- 128 bits for<A href="#IDEA"> IDEA</A> or<A href="#CAST128">
+ CAST-128</A>, 256 for Serpent or Twofish, 448 for<A href="#Blowfish">
+ Blowfish</A> and 2048 for<A href="#RC4"> RC4</A>. Using a key size
+ smaller than that limit gives<EM> exactly zero</EM> savings in
+ overhead. The crippled 40-bit or 64-bit version of the cipher provides<EM>
+ no advantage whatsoever</EM>.</LI>
+<LI><A href="#AES">AES</A> uses 10 rounds with 128-bit keys, 12 rounds
+ for 192-bit and 14 rounds for 256-bit, so there actually is a small
+ difference in overhead, but not enough to matter in most applications.</LI>
+<LI>For<A href="#3DES"> triple DES</A> there is a grain of truth in the
+ argument. 3DES is indeed three times slower than single DES. However,
+ the solution is not to use the insecure single DES, but to pick a
+ faster secure cipher.<A href="#CAST128"> CAST-128</A>,<A href="#Blowfish">
+ Blowfish</A> and the<A href="#AES"> AES candidate</A> ciphers are are
+ all considerably faster in software than DES (let alone 3DES!), and
+ apparently secure.</LI>
+<LI>For<A href="#public"> public key</A> techniques, there are extra
+ overheads for larger keys, but they generally do not affect overall
+ performance significantly. Practical public key applications are
+ usually<A href="#hybrid"> hybrid</A> systems in which the bulk of the
+ work is done by a symmetric cipher. The effect of increasing the cost
+ of the public key operations is typically negligible because the public
+ key operations use only a tiny fraction of total resources.
+<P>For example, suppose public key operations use use 1% of the time in
+ a hybrid system and you triple the cost of public key operations. The
+ cost of symmetric cipher operations is unchanged at 99% of the original
+ total cost, so the overall effect is a jump from 99 + 1 = 100 to 99 + 3
+ = 102, a 2% rise in system cost.</P>
+</LI>
+</UL>
+<P>In short,<STRONG> there has never been any technical reason to use
+ inadequate ciphers</STRONG>. The only reason there has ever been for
+ anyone to use such ciphers is that government agencies want weak
+ ciphers used so that they can crack them. The alleged savings are
+ simply propaganda.</P>
+<PRE> Mary had a little key (It's all she could export),
+ and all the email that she sent was opened at the Fort.</PRE>
+<P>A<A href="#quotes"> crypto quotes</A> page attributes this to<A href="http://theory.lcs.mit.edu:80/~rivest/">
+ Ron Rivest</A>. NSA headquarters is at Fort Meade, Maryland.</P>
+<P>Our policy in FreeS/WAN is to use only cryptographic components with
+ adequate keylength and no known weaknesses.</P>
+<UL>
+<LI>We do not implement single DES because it is clearly<A href="#desnotsecure">
+ insecure</A>, so implemeting it would violate our policy of avoiding
+ bogus security. Our default cipher is<A href="#3DES"> 3DES</A></LI>
+<LI>Similarly, we do not implement the 768-bit Group 1 for<A href="#DH">
+ Diffie-Hellman</A> key negotiation. We provide only the 1024-bit Group
+ 2 and 1536-bit Group 5.</LI>
+</UL>
+<P>Detailed discussion of which IPsec features we implement or omit is
+ in out<A href="compat.html"> compatibility document</A>.</P>
+<P>These decisions imply that we cannot fully conform to the IPsec RFCs,
+ since those have DES as the only required cipher and Group 1 as the
+ only required DH group. (In our view, the standards were subverted into
+ offerring bogus security.) Fortunately, we can still interoperate with
+ most other IPsec implementations since nearly all implementers provide
+ at least 3DES and Group 2 as well.</P>
+<P>We hope that eventually the RFCs will catch up with our (and others')
+ current practice and reject dubious components. Some of our team and a
+ number of others are working on this in<A href="#ietf"> IETF</A>
+ working groups.</P>
+<H4><A NAME="26_3_2_1">Some real trade-offs</A></H4>
+<P>Of course, making systems secure does involve costs, and trade-offs
+ can be made between cost and security. However, the real trade-offs
+ have nothing to do with using weaker ciphers.</P>
+<P>There can be substantial hardware and software costs. There are often
+ substantial training costs, both to train administrators and to
+ increase user awareness of security issues and procedures. There are
+ almost always substantial staff or contracting costs.</P>
+<P>Security takes staff time for planning, implementation, testing and
+ auditing. Some of the issues are subtle; you need good (hence often
+ expensive) people for this. You also need people to monitor your
+ systems and respond to problems. The best safe ever built is insecure
+ if an attacker can work on it for days without anyone noticing. Any
+ computer is insecure if the administrator is &quot;too busy&quot; to check the
+ logs.</P>
+<P>Moreover, someone in your organisation (or on contract to it) needs
+ to spend considerable time keeping up with new developments. EvilDoers<EM>
+ will</EM> know about new attacks shortly after they are found. You need
+ to know about them before your systems are attacked. If your vendor
+ provides a patch, you need to apply it. If the vendor does nothing, you
+ need to complain or start looking for another vendor.</P>
+<P>For a fairly awful example, see this<A href="http://www.sans.org/newlook/alerts/NTE-bank.htm">
+ report</A>. In that case over a million credit card numbers were taken
+ from e-commerce sites, using security flaws in Windows NT servers.
+ Microsoft had long since released patches for most or all of the flaws,
+ but the site administrators had not applied them.</P>
+<P>At an absolute minimum, you must do something about such issues<EM>
+ before</EM> an exploitation tool is posted to the net for downloading
+ by dozens of &quot;script kiddies&quot;. Such a tool might appear at any time
+ from the announcement of the security hole to several months later.
+ Once it appears, anyone with a browser and an attitude can break any
+ system whose administrators have done nothing about the flaw.</P>
+<P>Compared to those costs, cipher overheads are an insignificant factor
+ in the cost of security.</P>
+<P>The only thing using a weak cipher can do for you is to cause all
+ your other investment to be wasted.</P>
+<H2><A name="exlaw">Cryptography Export Laws</A></H2>
+<P>Many nations restrict the export of cryptography and some restrict
+ its use by their citizens or others within their borders.</P>
+<H3><A name="USlaw">US Law</A></H3>
+<P>US laws, as currently interpreted by the US government, forbid export
+ of most cryptographic software from the US in machine-readable form
+ without government permission. In general, the restrictions apply even
+ if the software is widely-disseminated or public-domain and even if it
+ came from outside the US originally. Cryptography is legally a munition
+ and export is tightly controlled under the<A href="#EAR"> EAR</A>
+ Export Administration Regulations.</P>
+<P>If you are a US citizen, your brain is considered US territory no
+ matter where it is physically located at the moment. The US believes
+ that its laws apply to its citizens everywhere, not just within the US.
+ Providing technical assistance or advice to foreign &quot;munitions&quot;
+ projects is illegal. The US government has very little sense of humor
+ about this issue and does not consider good intentions to be sufficient
+ excuse. Beware.</P>
+<P>The<A href="http://www.bxa.doc.gov/Encryption/"> official website</A>
+ for these regulations is run by the Commerce Department's Bureau of
+ Export Administration (BXA).</P>
+<P>The<A href="http://www.eff.org/bernstein/"> Bernstein case</A>
+ challenges the export restrictions on Constitutional grounds. Code is
+ speech so restrictions on export of code violate the First Amendment's
+ free speech provisions. This argument has succeeded in two levels of
+ court so far. It is quite likely to go on to the Supreme Court.</P>
+<P>The regulations were changed substantially in January 2000,
+ apparently as a government attempt to get off the hook in the Bernstein
+ case. It is now legal to export public domain source code for
+ encryption, provided you notify the<A href="#BXA"> BXA</A>.</P>
+<P>There are, however, still restrictions in force. Moreover, the
+ regulations can still be changed again whenever the government chooses
+ to do so. Short of a Supreme Court ruling (in the Berstein case or
+ another) that overturns the regulations completely, the problem of
+ export regulation is not likely to go away in the forseeable future.</P>
+<H4><A name="UScontrib">US contributions to FreeS/WAN</A></H4>
+<P>The FreeS/WAN project<STRONG> cannot accept software contributions,<EM>
+ not even small bug fixes</EM>, from US citizens or residents</STRONG>.
+ We want it to be absolutely clear that our distribution is not subject
+ to US export law. Any contribution from an American might open that
+ question to a debate we'd prefer to avoid. It might also put the
+ contributor at serious legal risk.</P>
+<P>Of course Americans can still make valuable contributions (many
+ already have) by reporting bugs, or otherwise contributing to
+ discussions, on the project<A href="mail.html"> mailing list</A>. Since
+ the list is public, this is clearly constitutionally protected free
+ speech.</P>
+<P>Note, however, that the export laws restrict Americans from providing
+ technical assistance to foreign &quot;munitions&quot; projects. The government
+ might claim that private discussions or correspondence with FreeS/WAN
+ developers were covered by this. It is not clear what the courts would
+ do with such a claim, so we strongly encourage Americans to use the
+ list rather than risk the complications.</P>
+<H3><A name="wrong">What's wrong with restrictions on cryptography</A></H3>
+<P>Some quotes from prominent cryptography experts:</P>
+<BLOCKQUOTE> The real aim of current policy is to ensure the continued
+ effectiveness of US information warfare assets against individuals,
+ businesses and governments in Europe and elsewhere.
+<BR><A href="http://www.cl.cam.ac.uk/users/rja14"> Ross Anderson,
+ Cambridge University</A></BLOCKQUOTE><BLOCKQUOTE> If the government
+ were honest about its motives, then the debate about crypto export
+ policy would have ended years ago.
+<BR><A href="http://www.counterpane.com"> Bruce Schneier, Counterpane
+ Systems</A></BLOCKQUOTE><BLOCKQUOTE> The NSA regularly lies to people
+ who ask it for advice on export control. They have no reason not to;
+ accomplishing their goal by any legal means is fine by them. Lying by
+ government employees is legal.
+<BR> John Gilmore.</BLOCKQUOTE>
+<P>The Internet Architecture Board (IAB) and the Internet Engineering
+ Steering Group (IESG) made a<A href="iab-iesg.stmt"> strong statement</A>
+ in favour of worldwide access to strong cryptography. Essentially the
+ same statement is in the appropriately numbered<A href="ftp://ftp.isi.edu/in-notes/rfc1984.txt">
+ RFC 1984</A>. Two critical paragraphs are:</P>
+<BLOCKQUOTE> ... various governments have actual or proposed policies on
+ access to cryptographic technology ...
+<P>(a) ... export controls ...
+<BR> (b) ... short cryptographic keys ...
+<BR> (c) ... keys should be in the hands of the government or ...
+<BR> (d) prohibit the use of cryptology ...</P>
+<P>We believe that such policies are against the interests of consumers
+ and the business community, are largely irrelevant to issues of
+ military security, and provide only a marginal or illusory benefit to
+ law enforcement agencies, ...</P>
+<P>The IAB and IESG would like to encourage policies that allow ready
+ access to uniform strong cryptographic technology for all Internet
+ users in all countries.</P>
+</BLOCKQUOTE>
+<P>Our goal in the FreeS/WAN project is to build just such &quot;strong
+ cryptographic technology&quot; and to distribute it &quot;for all Internet users
+ in all countries&quot;.</P>
+<P>More recently, the same two bodies (IESG and IAB) have issued<A href="ftp://ftp.isi.edu/in-notes/rfc2804.txt">
+ RFC 2804</A> on why the IETF should not build wiretapping capabilities
+ into protocols for the convenience of security or law enforcement
+ agenicies. The abstract from that document is:</P>
+<BLOCKQUOTE> The Internet Engineering Task Force (IETF) has been asked
+ to take a position on the inclusion into IETF standards-track documents
+ of functionality designed to facilitate wiretapping.
+<P>This memo explains what the IETF thinks the question means, why its
+ answer is &quot;no&quot;, and what that answer means.</P>
+</BLOCKQUOTE> A quote from the debate leading up to that RFC:<BLOCKQUOTE>
+ We should not be building surveillance technology into standards. Law
+ enforcement was not supposed to be easy. Where it is easy, it's called
+ a police state.
+<BR> Jeff Schiller of MIT, in a discussion of FBI demands for wiretap
+ capability on the net, as quoted by<A href="http://www.wired.com/news/politics/0,1283,31895,00.html">
+ Wired</A>.</BLOCKQUOTE>
+<P>The<A href="http://www.ietf.org/mailman/listinfo/raven"> Raven</A>
+ mailing list was set up for this IETF discussion.</P>
+<P>Our goal is to go beyond that RFC and prevent Internet wiretapping
+ entirely.</P>
+<H3><A name="Wassenaar">The Wassenaar Arrangement</A></H3>
+<P>Restrictions on the export of cryptography are not just US policy,
+ though some consider the US at least partly to blame for the policies
+ of other nations in this area.</P>
+<P>A number of countries:</P>
+<P>Argentina, Australia, Austria, Belgium, Bulgaria, Canada, Czech
+ Republic, Denmark, Finland, France, Germany, Greece, Hungary, Ireland,
+ Italy, Japan, Luxembourg, Netherlands, New Zealand, Norway, Poland,
+ Portugal, Republic of Korea, Romania, Russian Federation, Slovak
+ Republic, Spain, Sweden, Switzerland, Turkey, Ukraine, United Kingdom
+ and United States</P>
+<P>have signed the Wassenaar Arrangement which restricts export of
+ munitions and other tools of war. Cryptographic sofware is covered
+ there.</P>
+<P>Wassenaar details are available from the<A href="http://www.wassenaar.org/">
+ Wassenaar Secretariat</A>, and elsewhere in a more readable<A href="http://www.fitug.de/news/wa/index.html">
+ HTML version</A>.</P>
+<P>For a critique see the<A href="http://www.gilc.org/crypto/wassenaar">
+ GILC site</A>:</P>
+<BLOCKQUOTE> The Global Internet Liberty Campaign (GILC) has begun a
+ campaign calling for the removal of cryptography controls from the
+ Wassenaar Arrangement.
+<P>The aim of the Wassenaar Arrangement is to prevent the build up of
+ military capabilities that threaten regional and international security
+ and stability . . .</P>
+<P>There is no sound basis within the Wassenaar Arrangement for the
+ continuation of any export controls on cryptographic products.</P>
+</BLOCKQUOTE>
+<P>We agree entirely.</P>
+<P>An interesting analysis of Wassenaar can be found on the<A href="http://www.cyber-rights.org/crypto/wassenaar.htm">
+ cyber-rights.org</A> site.</P>
+<H3><A name="status">Export status of Linux FreeS/WAN</A></H3>
+<P>We believe our software is entirely exempt from these controls since
+ the Wassenaar<A href="http://www.wassenaar.org/list/GTN%20and%20GSN%20-%2099.pdf">
+ General Software Note</A> says:</P>
+<BLOCKQUOTE> The Lists do not control &quot;software&quot; which is either:
+<OL>
+<LI>Generally available to the public by . . . retail . . . or</LI>
+<LI>&quot;In the public domain&quot;.</LI>
+</OL>
+</BLOCKQUOTE>
+<P>There is a note restricting some of this, but it is a sub-heading
+ under point 1, so it appears not to apply to public domain software.</P>
+<P>Their glossary defines &quot;In the public domain&quot; as:</P>
+<BLOCKQUOTE> . . . &quot;technology&quot; or &quot;software&quot; which has been made
+ available without restrictions upon its further dissemination.
+<P>N.B. Copyright restrictions do not remove &quot;technology&quot; or &quot;software&quot;
+ from being &quot;in the public domain&quot;.</P>
+</BLOCKQUOTE>
+<P>We therefore believe that software freely distributed under the<A href="#GPL">
+ GNU Public License</A>, such as Linux FreeS/WAN, is exempt from
+ Wassenaar restrictions.</P>
+<P>Most of the development work is being done in Canada. Our
+ understanding is that the Canadian government accepts this
+ interpretation.</P>
+<UL>
+<LI>A web statement of<A href="http://www.dfait-maeci.gc.ca/~eicb/notices/ser113-e.htm">
+ Canadian policy</A> is available from the Department of Foreign Affairs
+ and International Trade.</LI>
+<LI>Another document from that department states that<A href="http://www.dfait-maeci.gc.ca/~eicb/export/gr1_e.htm">
+ public domain software</A> is exempt from the export controls.</LI>
+<LI>A researcher's<A href="http://insight.mcmaster.ca/org/efc/pages/doc/crypto-export.html">
+ analysis</A> of Canadian policy is also available.</LI>
+</UL>
+<P>Recent copies of the freely modifiable and distributable source code
+ exist in many countries. Citizens all over the world participate in its
+ use and evolution, and guard its ongoing distribution. Even if Canadian
+ policy were to change, the software would continue to evolve in
+ countries which do not restrict exports, and would continue to be
+ imported from there into unfree countries. &quot;The Net culture treats
+ censorship as damage, and routes around it.&quot;</P>
+<H3><A name="help">Help spread IPsec around</A></H3>
+<P>You can help. If you don't know of a Linux FreeS/WAN archive in your
+ own country, please download it now to your personal machine, and
+ consider making it publicly accessible if that doesn't violate your own
+ laws. If you have the resources, consider going one step further and
+ setting up a mirror site for the whole<A href="#munitions"> munitions</A>
+ Linux crypto software archive.</P>
+<P>If you make Linux CD-ROMs, please consider including this code, in a
+ way that violates no laws (in a free country, or in a domestic-only CD
+ product).</P>
+<P>Please send a note about any new archive mirror sites or CD
+ distributions to linux-ipsec@clinet.fi so we can update the
+ documentation.</P>
+<P>Lists of current<A href="#sites"> mirror sites</A> and of<A href="#distwith">
+ distributions</A> which include FreeS/WAN are in our introduction
+ section.</P>
+<H2><A name="desnotsecure">DES is Not Secure</A></H2>
+<P>DES, the<STRONG> D</STRONG>ata<STRONG> E</STRONG>ncryption<STRONG> S</STRONG>
+tandard, can no longer be considered secure. While no major flaws in its
+ innards are known, it is fundamentally inadequate because its<STRONG>
+ 56-bit key is too short</STRONG>. It is vulnerable to<A href="#brute">
+ brute-force search</A> of the whole key space, either by large
+ collections of general-purpose machines or even more quickly by
+ specialized hardware. Of course this also applies to<STRONG> any other
+ cipher with only a 56-bit key</STRONG>. The only reason anyone could
+ have for using a 56 or 64-bit key is to comply with various<A href="exportlaw.html">
+ export laws</A> intended to ensure the use of breakable ciphers.</P>
+<P>Non-government cryptologists have been saying DES's 56-bit key was
+ too short for some time -- some of them were saying it in the 70's when
+ DES became a standard -- but the US government has consistently
+ ridiculed such suggestions.</P>
+<P>A group of well-known cryptographers looked at key lengths in a<A href="http://www.counterpane.com/keylength.html">
+ 1996 paper</A>. They suggested a<EM> minimum</EM> of 75 bits to
+ consider an existing cipher secure and a<EM> minimum of 90 bits for new
+ ciphers</EM>. More recent papers, covering both<A href="#symmetric">
+ symmetric</A> and<A href="#public"> public key</A> systems are at<A href="http://www.cryptosavvy.com/">
+ cryptosavvy.com</A> and<A href="http://www.rsasecurity.com/rsalabs/bulletins/bulletin13.html">
+ rsa.com</A>. For all algorithms, the minimum keylengths recommended in
+ such papers are significantly longer than the maximums allowed by
+ various export laws.</P>
+<P>In a<A href="http://www.privacy.nb.ca/cryptography/archives/cryptography/html/1998-09/0095.html">
+ 1998 ruling</A>, a German court described DES as &quot;out-of-date and not
+ safe enough&quot; and held a bank liable for using it.</P>
+<H3><A name="deshware">Dedicated hardware breaks DES in a few days</A></H3>
+<P>The question of DES security has now been settled once and for all.
+ In early 1998, the<A href="http://www.eff.org/"> Electronic Frontier
+ Foundation</A> built a<A href="http://www.eff.org/descracker.html">
+ DES-cracking machine</A>. It can find a DES key in an average of a few
+ days' search. The details of all this, including complete code listings
+ and complete plans for the machine, have been published in<A href="#EFF">
+<CITE> Cracking DES</CITE></A>, by the Electronic Frontier Foundation.</P>
+<P>That machine cost just over $200,000 to design and build. &quot;Moore's
+ Law&quot; is that machines get faster (or cheaper, for the same speed) by
+ roughly a factor of two every 18 months. At that rate, their $200,000
+ in 1998 becomes $50,000 in 2001.</P>
+<P>However, Moore's Law is not exact and the $50,000 estimate does not
+ allow for the fact that a copy based on the published EFF design would
+ cost far less than the original. We cannot say exactly what such a
+ cracker would cost today, but it would likely be somewhere between
+ $10,000 and $100,000.</P>
+<P>A large corporation could build one of these out of petty cash. The
+ cost is low enough for a senior manager to hide it in a departmental
+ budget and avoid having to announce or justify the project. Any
+ government agency, from a major municipal police force up, could afford
+ one. Or any other group with a respectable budget -- criminal
+ organisations, political groups, labour unions, religious groups, ...
+ Or any millionaire with an obsession or a grudge, or just strange taste
+ in toys.</P>
+<P>One might wonder if a private security or detective agency would have
+ one for rent. They wouldn't need many clients to pay off that
+ investment.</P>
+<H3><A name="spooks">Spooks may break DES faster yet</A></H3>
+<P>As for the security and intelligence agencies of various nations,
+ they may have had DES crackers for years, and theirs may be much
+ faster. It is difficult to make most computer applications work well on
+ parallel machines, or to design specialised hardware to accelerate
+ them. Cipher-cracking is one of the very few exceptions. It is entirely
+ straightforward to speed up cracking by just adding hardware. Within
+ very broad limits, you can make it as fast as you like if you have the
+ budget. The EFF's $200,000 machine breaks DES in a few days. An<A href="http://www.planepage.com/">
+ aviation website</A> gives the cost of a B1 bomber as $200,000,000.
+ Spending that much, an intelligence agency could break DES in an
+ average time of<EM> six and a half minutes</EM>.</P>
+<P>That estimate assumes they use the EFF's 1998 technology and just
+ spend more money. They may have an attack that is superior to brute
+ force, they quite likely have better chip technology (Moore's law, a
+ bigger budget, and whatever secret advances they may have made) and of
+ course they may have spent the price of an aircraft carrier, not just
+ one aircraft.</P>
+<P>In short, we have<EM> no idea</EM> how quickly these organisations
+ can break DES. Unless they're spectacularly incompetent or horribly
+ underfunded, they can certainly break it, but we cannot guess how
+ quickly. Pick any time unit between days and milliseconds; none is
+ entirely unbelievable. More to the point, none of them is of any
+ comfort if you don't want such organisations reading your
+ communications.</P>
+<P>Note that this may be a concern even if nothing you do is a threat to
+ anyone's national security. An intelligence agency might well consider
+ it to be in their national interest for certain companies to do well.
+ If you're competing against such companies in a world market and that
+ agency can read your secrets, you have a serious problem.</P>
+<P>One might wonder about technology the former Soviet Union and its
+ allies developed for cracking DES during the Cold War. They must have
+ tried; the cipher was an American standard and widely used. Certainly
+ those countries have some fine mathematicians, and those agencies had
+ budget. How well did they succeed? Is their technology now for sale or
+ rent?</P>
+<H3><A name="desnet">Networks break DES in a few weeks</A></H3>
+<P>Before the definitive EFF effort, DES had been cracked several times
+ by people using many machines. See this<A href="http://www.distributed.net/pressroom/DESII-1-PR.html">
+ press release</A> for example.</P>
+<P>A major corporation, university, or government department could break
+ DES by using spare cycles on their existing collection of computers, by
+ dedicating a group of otherwise surplus machines to the problem, or by
+ combining the two approaches. It might take them weeks or months,
+ rather than the days required for the EFF machine, but they could do
+ it.</P>
+<P>What about someone working alone, without the resources of a large
+ organisation? For them, cracking DES will not be easy, but it may be
+ possible. A few thousand dollars buys a lot of surplus workstations. A
+ pile of such machines will certainly heat your garage nicely and might
+ break DES in a few months or years. Or enroll at a university and use
+ their machines. Or use an employer's machines. Or crack security
+ somewhere and steal the resources to crack a DES key. Or write a virus
+ that steals small amounts of resources on many machines. Or . . .</P>
+<P>None of these approaches are easy or break DES really quickly, but an
+ attacker only needs to find one that is feasible and breaks DES quickly
+ enough to be dangerous. How much would you care to bet that this will
+ be impossible if the attacker is clever and determined? How valuable is
+ your data? Are you authorised to risk it on a dubious bet?</P>
+<H3><A name="no_des">We disable DES</A></H3>
+<P>In short, it is now absolutely clear that<STRONG> DES is not secure</STRONG>
+ against</P>
+<UL>
+<LI>any<STRONG> well-funded opponent</STRONG></LI>
+<LI>any opponent (even a penniless one) with access (even stolen access)
+ to<STRONG> enough general purpose computers</STRONG></LI>
+</UL>
+<P>That is why<STRONG> Linux FreeS/WAN disables all transforms which use
+ plain DES</STRONG> for encryption.</P>
+<P>DES is in the source code, because we need DES to implement our
+ default encryption transform,<A href="#3DES"> Triple DES</A>.<STRONG>
+ We urge you not to use single DES</STRONG>. We do not provide any easy
+ way to enable it in FreeS/WAN, and our policy is to provide no
+ assistance to anyone wanting to do so.</P>
+<H3><A name="40joke">40-bits is laughably weak</A></H3>
+<P>The same is true, in spades, of ciphers -- DES or others -- crippled
+ by 40-bit keys, as many ciphers were required to be until recently
+ under various<A href="#exlaw"> export laws</A>. A brute force search of
+ such a cipher's keyspace is 2<SUP>16</SUP> times faster than a similar
+ search against DES. The EFF's machine can do a brute-force search of a
+ 40-bit key space in<EM> seconds</EM>. One contest to crack a 40-bit
+ cipher was won by a student<A href="http://catless.ncl.ac.uk/Risks/18.80.html#subj1">
+ using a few hundred idle machines at his university</A>. It took only
+ three and half hours.</P>
+<P>We do not, and will not, implement any 40-bit cipher.</P>
+<H3><A name="altdes">Triple DES is almost certainly secure</A></H3>
+<P><A href="#3DES">Triple DES</A>, usually abbreviated 3DES, applies DES
+ three times, with three different keys. DES seems to be basically an
+ excellent cipher design; it has withstood several decades of intensive
+ analysis without any disastrous flaws being found. It's only major flaw
+ is that the small keyspace allows brute force attacks to succeeed.
+ Triple DES enlarges the key space to 168 bits, making brute-force
+ search a ridiculous impossibility.</P>
+<P>3DES is currently the only block cipher implemented in FreeS/WAN.
+ 3DES is, unfortunately, about 1/3 the speed of DES, but modern CPUs
+ still do it at quite respectable speeds. Some<A href="#benchmarks">
+ speed measurements</A> for our code are available.</P>
+<H3><A name="aes.ipsec">AES in IPsec</A></H3>
+<P>The<A href="#AES"> AES</A> project has chosen a replacement for DES,
+ a new standard cipher for use in non-classified US government work and
+ in regulated industries such as banking. This cipher will almost
+ certainly become widely used for many applications, including IPsec.</P>
+<P>The winner, announced in October 2000 after several years of analysis
+ and discussion, was the<A href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">
+ Rijndael</A> cipher from two Belgian designers.</P>
+<P>It is almost certain that FreeS/WAN will add AES support.<A href="#patch">
+ AES patches</A> are already available.</P>
+<H2><A name="press">Press coverage of Linux FreeS/WAN:</A></H2>
+<H3><A NAME="26_6_1">FreeS/WAN 1.0 press</A></H3>
+<UL>
+<LI><A href="http://www.wired.com/news/news/technology/story/19136.html">
+Wired</A> &quot;Linux-Based Crypto Stops Snoops&quot;, James Glave April 15 1999</LI>
+<LI><A href="http://slashdot.org/articles/99/04/15/1851212.shtml">
+Slashdot</A></LI>
+<LI><A href="http://dgl.com/itinfo/1999/it990415.html">DGL</A>, Damar
+ Group Limited; looking at FreeS/WAN from a perspective of business
+ computing</LI>
+<LI><A href="http://linuxtoday.com/stories/5010.html">Linux Today</A></LI>
+<LI><A href="http://www.tbtf.com/archive/1999-04-21.html#Tcep">TBTF</A>,
+ Tasty Bits from the Technology Front</LI>
+<LI><A href="http://www.salonmagazine.com/tech/log/1999/04/16/encryption/index.html">
+Salon Magazine</A> &quot;Free Encryption Takes a Big Step&quot;</LI>
+</UL>
+<H3><A name="release">Press release for version 1.0</A></H3>
+<PRE> Strong Internet Privacy Software Free for Linux Users Worldwide
+
+Toronto, ON, April 14, 1999 -
+
+The Linux FreeS/WAN project today released free software to protect
+the privacy of Internet communications using strong encryption codes.
+FreeS/WAN automatically encrypts data as it crosses the Internet, to
+prevent unauthorized people from receiving or modifying it. One
+ordinary PC per site runs this free software under Linux to become a
+secure gateway in a Virtual Private Network, without having to modify
+users' operating systems or application software. The project built
+and released the software outside the United States, avoiding US
+government regulations which prohibit good privacy protection.
+FreeS/WAN version 1.0 is available immediately for downloading at
+http://www.xs4all.nl/~freeswan/.
+
+&quot;Today's FreeS/WAN release allows network administrators to build
+excellent secure gateways out of old PCs at no cost, or using a cheap
+new PC,&quot; said John Gilmore, the entrepreneur who instigated the
+project in 1996. &quot;They can build operational experience with strong
+network encryption and protect their users' most important
+communications worldwide.&quot;
+
+&quot;The software was written outside the United States, and we do not
+accept contributions from US citizens or residents, so that it can be
+freely published for use in every country,&quot; said Henry Spencer, who
+built the release in Toronto, Canada. &quot;Similar products based in the
+US require hard-to-get government export licenses before they can be
+provided to non-US users, and can never be simply published on a Web
+site. Our product is freely available worldwide for immediate
+downloading, at no cost.&quot;
+
+FreeS/WAN provides privacy against both quiet eavesdropping (such as
+&quot;packet sniffing&quot;) and active attempts to compromise communications
+(such as impersonating participating computers). Secure &quot;tunnels&quot; carry
+information safely across the Internet between locations such as a
+company's main office, distant sales offices, and roaming laptops. This
+protects the privacy and integrity of all information sent among those
+locations, including sensitive intra-company email, financial transactions
+such as mergers and acquisitions, business negotiations, personal medical
+records, privileged correspondence with lawyers, and information about
+crimes or civil rights violations. The software will be particularly
+useful to frequent wiretapping targets such as private companies competing
+with government-owned companies, civil rights groups and lawyers,
+opposition political parties, and dissidents.
+
+FreeS/WAN provides privacy for Internet packets using the proposed
+standard Internet Protocol Security (IPSEC) protocols. FreeS/WAN
+negotiates strong keys using Diffie-Hellman key agreement with 1024-bit
+keys, and encrypts each packet with 168-bit Triple-DES (3DES). A modern
+$500 PC can set up a tunnel in less than a second, and can encrypt
+6 megabits of packets per second, easily handling the whole available
+bandwidth at the vast majority of Internet sites. In preliminary testing,
+FreeS/WAN interoperated with 3DES IPSEC products from OpenBSD, PGP, SSH,
+Cisco, Raptor, and Xedia. Since FreeS/WAN is distributed as source code,
+its innards are open to review by outside experts and sophisticated users,
+reducing the chance of undetected bugs or hidden security compromises.
+
+The software has been in development for several years. It has been
+funded by several philanthropists interested in increased privacy on
+the Internet, including John Gilmore, co-founder of the Electronic
+Frontier Foundation, a leading online civil rights group.
+
+Press contacts:
+Hugh Daniel, +1 408 353 8124, hugh@toad.com
+Henry Spencer, +1 416 690 6561, henry@spsystems.net
+
+* FreeS/WAN derives its name from S/WAN, which is a trademark of RSA Data
+ Security, Inc; used by permission.</PRE>
+<HR>
+<H1><A name="ipsec.detail">The IPsec protocols</A></H1>
+<P>This section provides information on the IPsec protocols which
+ FreeS/WAN implements. For more detail, see the<A href="rfc.html"> RFCs</A>
+.</P>
+<P>The basic idea of IPsec is to provide security functions,<A href="#authentication">
+ authentication</A> and<A href="#encryption"> encryption</A>, at the IP
+ (Internet Protocol) level. This requires a higher-level protocol (IKE)
+ to set things up for the IP-level services (ESP and AH).</P>
+<H2><A NAME="27_1">Protocols and phases</A></H2>
+<P>Three protocols are used in an IPsec implementation:</P>
+<DL>
+<DT>ESP, Encapsulating Security Payload</DT>
+<DD>Encrypts and/or authenticates data</DD>
+<DT>AH, Authentication Header</DT>
+<DD>Provides a packet authentication service</DD>
+<DT>IKE, Internet Key Exchange</DT>
+<DD>Negotiates connection parameters, including keys, for the other two</DD>
+</DL>
+<P>The term &quot;IPsec&quot; (also written as IPSEC) is slightly ambiguous. In
+ some contexts, it includes all three of the above but in other contexts
+ it refers only to AH and ESP.</P>
+<P>There is more detail below, but a quick summary of how the whole
+ thing works is:</P>
+<DL>
+<DT>Phase one IKE (main mode exchange)</DT>
+<DD>sets up a keying channel (ISAKMP SA) between the two gateways</DD>
+<DT>Phase two IKE (quick mode exchange)</DT>
+<DD>sets up data channels (IPsec SAs)</DD>
+<DT>IPsec proper</DT>
+<DD>exchanges data using AH or ESP</DD>
+</DL>
+<P>Both phases of IKE are repeated periodically to automate re-keying.</P>
+<H2><A name="others">Applying IPsec</A></H2>
+<P>Authentication and encryption functions for network data can, of
+ course, be provided at other levels. Many security protocols work at
+ levels above IP.</P>
+<UL>
+<LI><A href="#PGP">PGP</A> encrypts and authenticates mail messages</LI>
+<LI><A href="#ssh">SSH</A> authenticates remote logins and then encrypts
+ the session</LI>
+<LI><A href="#SSL">SSL</A> or<A href="#TLS"> TLS</A> provides security
+ at the sockets layer, e.g. for secure web browsing</LI>
+</UL>
+<P>and so on. Other techniques work at levels below IP. For example,
+ data on a communications circuit or an entire network can be encrypted
+ by specialised hardware. This is common practice in high-security
+ applications.</P>
+<H3><A name="advantages">Advantages of IPsec</A></H3>
+<P>There are, however, advantages to doing it at the IP level instead
+ of, or as well as, at other levels.</P>
+<P>IPsec is the<STRONG> most general way to provide these services for
+ the Internet</STRONG>.</P>
+<UL>
+<LI>Higher-level services protect a<EM> single protocol</EM>; for
+ example PGP protects mail.</LI>
+<LI>Lower level services protect a<EM> single medium</EM>; for example a
+ pair of encryption boxes on the ends of a line make wiretaps on that
+ line useless unless the attacker is capable of breaking the encryption.</LI>
+</UL>
+<P>IPsec, however, can protect<EM> any protocol</EM> running above IP
+ and<EM> any medium</EM> which IP runs over. More to the point, it can
+ protect a mixture of application protocols running over a complex
+ combination of media. This is the normal situation for Internet
+ communication; IPsec is the only general solution.</P>
+<P>IPsec can also provide some security services &quot;in the background&quot;,
+ with<STRONG> no visible impact on users</STRONG>. To use<A href="#PGP">
+ PGP</A> encryption and signatures on mail, for example, the user must
+ at least:</P>
+<UL>
+<LI>remember his or her passphrase,</LI>
+<LI>keep it secure</LI>
+<LI>follow procedures to validate correspondents' keys</LI>
+</UL>
+<P>These systems can be designed so that the burden on users is not
+ onerous, but any system will place some requirements on users. No such
+ system can hope to be secure if users are sloppy about meeting those
+ requirements. The author has seen username and password stuck on
+ terminals with post-it notes in an allegedly secure environment, for
+ example.</P>
+<H3><A name="limitations">Limitations of IPsec</A></H3>
+<P>IPsec is designed to secure IP links between machines. It does that
+ well, but it is important to remember that there are many things it
+ does not do. Some of the important limitations are:</P>
+<DL>
+<DT><A name="depends">IPsec cannot be secure if your system isn't</A></DT>
+<DD>System security on IPsec gateway machines is an essential
+ requirement if IPsec is to function as designed. No system can be
+ trusted if the underlying machine has been subverted. See books on Unix
+ security such as<A href="#practical"> Garfinkel and Spafford</A> or our
+ web references for<A href="#linsec"> Linux security</A> or more general<A
+href="#compsec"> computer security</A>.
+<P>Of course, there is another side to this. IPsec can be a powerful
+ tool for improving system and network security. For example, requiring
+ packet authentication makes various spoofing attacks harder and IPsec
+ tunnels can be extremely useful for secure remote administration of
+ various things.</P>
+</DD>
+<DT><A name="not-end-to-end">IPsec is not end-to-end</A></DT>
+<DD>IPsec cannot provide the same end-to-end security as systems working
+ at higher levels. IPsec encrypts an IP connection between two machines,
+ which is quite a different thing than encrypting messages between users
+ or between applications.
+<P>For example, if you need mail encrypted from the sender's desktop to
+ the recipient's desktop and decryptable only by the recipient, use<A href="#PGP">
+ PGP</A> or another such system. IPsec can encrypt any or all of the
+ links involved -- between the two mail servers, or between either
+ server and its clients. It could even be used to secure a direct IP
+ link from the sender's desktop machine to the recipient's, cutting out
+ any sort of network snoop. What it cannot ensure is end-to-end
+ user-to-user security. If only IPsec is used to secure mail, then
+ anyone with appropriate privileges on any machine where that mail is
+ stored (at either end or on any store-and-forward servers in the path)
+ can read it.</P>
+<P>In another common setup, IPsec encrypts packets at a security gateway
+ machine as they leave the sender's site and decrypts them on arrival at
+ the gateway to the recipient's site. This does provide a useful
+ security service -- only encrypted data is passed over the Internet --
+ but it does not even come close to providing an end-to-end service. In
+ particular, anyone with appropriate privileges on either site's LAN can
+ intercept the message in unencrypted form.</P>
+</DD>
+<DT><A name="notpanacea">IPsec cannot do everything</A></DT>
+<DD>IPsec also cannot provide all the functions of systems working at
+ higher levels of the protocol stack. If you need a document
+ electronically signed by a particular person, then you need his or her<A
+href="#signature"> digital signature</A> and a<A href="#public"> public
+ key cryptosystem</A> to verify it with.
+<P>Note, however, that IPsec authentication of the underlying
+ communication can make various attacks on higher-level protocols more
+ difficult. In particular, authentication prevents<A href="#middle">
+ man-in-the-middle attacks</A>.</P>
+</DD>
+<DT><A name="no_user">IPsec authenticates machines, not users</A></DT>
+<DD>IPsec uses strong authentication mechanisms to control which
+ messages go to which machines, but it does not have the concept of user
+ ID, which is vital to many other security mechansims and policies. This
+ means some care must be taken in fitting the various security
+ mechansims on a network together. For example, if you need to control
+ which users access your database server, you need some non-IPsec
+ mechansim for that. IPsec can control which machines connect to the
+ server, and can ensure that data transfer to those machines is done
+ securely, but that is all. Either the machines themselves must control
+ user access or there must be some form of user authentication to the
+ database, independent of IPsec.</DD>
+<DT><A name="DoS">IPsec does not stop denial of service attacks</A></DT>
+<DD><A href="#DOS">Denial of service</A> attacks aim at causing a system
+ to crash, overload, or become confused so that legitimate users cannot
+ get whatever services the system is supposed to provide. These are
+ quite different from attacks in which the attacker seeks either to use
+ the service himself or to subvert the service into delivering incorrect
+ results.
+<P>IPsec shifts the ground for DoS attacks; the attacks possible against
+ systems using IPsec are different than those that might be used against
+ other systems. It does not, however, eliminate the possibility of such
+ attacks.</P>
+</DD>
+<DT><A name="traffic">IPsec does not stop traffic analysis</A></DT>
+<DD><A href="#traffic">Traffic analysis</A> is the attempt to derive
+ intelligence from messages without regard for their contents. In the
+ case of IPsec, it would mean analysis based on things visible in the
+ unencrypted headers of encrypted packets -- source and destination
+ gateway addresses, packet size, et cetera. Given the resources to
+ acquire such data and some skill in analysing it (both of which any
+ national intelligence agency should have), this can be a very powerful
+ technique.
+<P>IPsec is not designed to defend against this. Partial defenses are
+ certainly possible, and some are<A href="#traffic.resist"> described
+ below</A>, but it is not clear that any complete defense can be
+ provided.</P>
+</DD>
+</DL>
+<H3><A name="uses">IPsec is a general mechanism for securing IP</A></H3>
+<P>While IPsec does not provide all functions of a mail encryption
+ package, it can encrypt your mail. In particular, it can ensure that
+ all mail passing between a pair or a group of sites is encrypted. An
+ attacker looking only at external traffic, without access to anything
+ on or behind the IPsec gateway, cannot read your mail. He or she is
+ stymied by IPsec just as he or she would be by<A href="#PGP"> PGP</A>.</P>
+<P>The advantage is that IPsec can provide the same protection for<STRONG>
+ anything transmitted over IP</STRONG>. In a corporate network example,
+ PGP lets the branch offices exchange secure mail with head office. SSL
+ and SSH allow them to securely view web pages, connect as terminals to
+ machines, and so on. IPsec can support all those applications, plus
+ database queries, file sharing (NFS or Windows), other protocols
+ encapsulated in IP (Netware, Appletalk, ...), phone-over-IP,
+ video-over-IP, ... anything-over-IP. The only limitation is that IP
+ Multicast is not yet supported, though there are Internet Draft
+ documents for that.</P>
+<P>IPsec creates<STRONG> secure tunnels through untrusted networks</STRONG>
+. Sites connected by these tunnels form VPNs,<A href="#VPN"> Virtual
+ Private Networks</A>.</P>
+<P>IPsec gateways can be installed wherever they are required.</P>
+<UL>
+<LI>One organisation might choose to install IPsec only on firewalls
+ between their LANs and the Internet. This would allow them to create a
+ VPN linking several offices. It would provide protection against anyone
+ outside their sites.</LI>
+<LI>Another might install IPsec on departmental servers so everything on
+ the corporate backbone net was encrypted. This would protect messages
+ on that net from everyone except the sending and receiving department.</LI>
+<LI>Another might be less concerned with information secrecy and more
+ with controlling access to certain resources. They might use IPsec
+ packet authentication as part of an access control mechanism, with or
+ without also using the IPsec encryption service.</LI>
+<LI>It is even possible (assuming adequate processing power and an IPsec
+ implementation in each node) to make every machine its own IPsec
+ gateway so that everything on a LAN is encrypted. This protects
+ information from everyone outside the sending and receiving machine.</LI>
+<LI>These techniques can be combined in various ways. One might, for
+ example, require authentication everywhere on a network while using
+ encryption only for a few links.</LI>
+</UL>
+<P>Which of these, or of the many other possible variants, to use is up
+ to you.<STRONG> IPsec provides mechanisms; you provide the policy</STRONG>
+.</P>
+<P><STRONG>No end user action is required</STRONG> for IPsec security to
+ be used; they don't even have to know about it. The site
+ administrators, of course, do have to know about it and to put some
+ effort into making it work. Poor administration can compromise IPsec as
+ badly as the post-it notes mentioned above. It seems reasonable,
+ though, for organisations to hope their system administrators are
+ generally both more security-conscious than end users and more able to
+ follow computer security procedures. If not, at least there are fewer
+ of them to educate or replace.</P>
+<P>IPsec can be, and often should be, used with along with security
+ protocols at other levels. If two sites communicate with each other via
+ the Internet, then IPsec is the obvious way to protect that
+ communication. If two others have a direct link between them, either
+ link encryption or IPsec would make sense. Choose one or use both.
+ Whatever you use at and below the IP level, use other things as
+ required above that level. Whatever you use above the IP level,
+ consider what can be done with IPsec to make attacks on the higher
+ levels harder. For example,<A href="#middle"> man-in-the-middle attacks</A>
+ on various protocols become difficult if authentication at packet level
+ is in use on the potential victims' communication channel.</P>
+<H3><A name="authonly">Using authentication without encryption</A></H3>
+<P>Where appropriate, IPsec can provide authentication without
+ encryption. One might do this, for example:</P>
+<UL>
+<LI>where the data is public but one wants to be sure of getting the
+ right data, for example on some web sites</LI>
+<LI>where encryption is judged unnecessary, for example on some company
+ or department LANs</LI>
+<LI>where strong encryption is provided at link level, below IP</LI>
+<LI>where strong encryption is provided in other protocols, above IP
+<BR> Note that IPsec authentication may make some attacks on those
+ protocols harder.</LI>
+</UL>
+<P>Authentication has lower overheads than encryption.</P>
+<P>The protocols provide four ways to build such connections, using
+ either an AH-only connection or ESP using null encryption, and in
+ either manually or automatically keyed mode. FreeS/WAN supports only
+ one of these, manually keyed AH-only connections, and<STRONG> we do not
+ recommend using that</STRONG>. Our reasons are discussed under<A href="#traffic.resist">
+ Resisting traffic analysis</A> a few sections further along.</P>
+<H3><A name="encnoauth">Encryption without authentication is dangerous</A>
+</H3>
+<P>Originally, the IPsec encryption protocol<A href="#ESP"> ESP</A>
+ didn't do integrity checking. It only did encryption. Steve Bellovin
+ found many ways to attack ESP used without authentication. See his
+ paper<A href="http://www.research.att.com/~smb/papers/badesp.ps">
+ Problem areas for the IP Security Protocols</A>. To make a secure
+ connection, you had to add an<A href="#AH"> AH</A> Authentication
+ Header as well as ESP. Rather than incur the overhead of several layers
+ (and rather than provide an ESP layer that didn't actually protect the
+ traffic), the IPsec working group built integrity and replay checking
+ directly into ESP.</P>
+<P>Today, typical usage is one of:</P>
+<UL>
+<LI>ESP for encryption and authentication</LI>
+<LI>AH for authentication alone</LI>
+</UL>
+<P>Other variants are allowed by the standard, but not much used:</P>
+<DL>
+<DT>ESP encryption without authentication</DT>
+<DD><STRONG>Bellovin has demonstrated fatal flaws in this. Do not use.</STRONG>
+</DD>
+<DT>ESP encryption with AH authentication</DT>
+<DD>This has higher overheads than using the authentication in ESP, and
+ no obvious benefit in most cases. The exception might be a network
+ where AH authentication was widely or universally used. If you're going
+ to do AH to conform with network policy, why authenticate again in the
+ ESP layer?</DD>
+<DT>Authenticate twice, with AH and with ESP</DT>
+<DD>Why? Of course, some folk consider &quot;belt and suspenders&quot; the
+ sensible approach to security. If you're among them, you might use both
+ protocols here. You might also use both to satisfy different parts of a
+ security policy. For example, an organisation might require AH
+ authentication everywhere but two users within the organisation might
+ use ESP as well.</DD>
+<DT>ESP authentication without encryption</DT>
+<DD>The standard allows this, calling it &quot;null encryption&quot;. FreeS/WAN
+ does not support it. We recommend that you use AH instead if
+ authentication is all you require. AH authenticates parts of the IP
+ header, which ESP-null does not do.</DD>
+</DL>
+<P>Some of these variants cannot be used with FreeS/WAN because we do
+ not support ESP-null and do not support automatic keying of AH-only
+ connections.</P>
+<P>There are fairly frequent suggestions that AH be dropped entirely
+ from the IPsec specifications since ESP and null encryption can handle
+ that situation. It is not clear whether this will occur. My guess is
+ that it is unlikely.</P>
+<H3><A name="multilayer">Multiple layers of IPsec processing are
+ possible</A></H3>
+<P>The above describes combinations possible on a single IPsec
+ connection. In a complex network you may have several layers of IPsec
+ in play, with any of the above combinations at each layer.</P>
+<P>For example, a connection from a desktop machine to a database server
+ might require AH authentication. Working with other host, network and
+ database security measures, AH might be just the thing for access
+ control. You might decide not to use ESP encryption on such packets,
+ since it uses resources and might complicate network debugging. Within
+ the site where the server is, then, only AH would be used on those
+ packets.</P>
+<P>Users at another office, however, might have their whole connection
+ (AH headers and all) passing over an IPsec tunnel connecting their
+ office to the one with the database server. Such a tunnel should use
+ ESP encryption and authentication. You need authentication in this
+ layer because without authentication the encryption is vulnerable and
+ the gateway cannot verify the AH authentication. The AH is between
+ client and database server; the gateways aren't party to it.</P>
+<P>In this situation, some packets would get multiple layers of IPsec
+ applied to them, AH on an end-to-end client-to-server basis and ESP
+ from one office's security gateway to the other.</P>
+<H3><A name="traffic.resist">Resisting traffic analysis</A></H3>
+<P><A href="#traffic">Traffic analysis</A> is the attempt to derive
+ useful intelligence from encrypted traffic without breaking the
+ encryption.</P>
+<P>Is your CEO exchanging email with a venture capital firm? With
+ bankruptcy trustees? With an executive recruiting agency? With the
+ holder of some important patents? If an eavesdropper learns about any
+ of those, then he has interesting intelligence on your company, whether
+ or not he can read the messages themselves.</P>
+<P>Even just knowing that there is network traffic between two sites may
+ tell an analyst something useful, especially when combined with
+ whatever other information he or she may have. For example, if you know
+ Company A is having cashflow problems and Company B is looking for
+ aquisitions, then knowing that packets are passing between the two is
+ interesting. It is more interesting if you can tell it is email, and
+ perhaps yet more if you know the sender and recipient.</P>
+<P>Except in the simplest cases, traffic analysis is hard to do well. It
+ requires both considerable resources and considerable analytic skill.
+ However, intelligence agencies of various nations have been doing it
+ for centuries and many of them are likely quite good at it by now.
+ Various commercial organisations, especially those working on &quot;targeted
+ marketing&quot; may also be quite good at analysing certain types of
+ traffic.</P>
+<P>In general, defending against traffic analysis is also difficult.
+ Inventing a really good defense could get you a PhD and some
+ interesting job offers.</P>
+<P>IPsec is not designed to stop traffic analysis and we know of no
+ plausible method of extending it to do so. That said, there are ways to
+ make traffic analysis harder. This section describes them.</P>
+<H4><A name="extra">Using &quot;unnecessary&quot; encryption</A></H4>
+<P>One might choose to use encryption even where it appears unnecessary
+ in order to make analysis more difficult. Consider two offices which
+ pass a small volume of business data between them using IPsec and also
+ transfer large volumes of Usenet news. At first glance, it would seem
+ silly to encrypt the newsfeed, except possibly for any newsgroups that
+ are internal to the company. Why encrypt data that is all publicly
+ available from many sites?</P>
+<P>However, if we encrypt a lot of news and send it down the same
+ connection as our business data, we make<A href="#traffic"> traffic
+ analysis</A> much harder. A snoop cannot now make inferences based on
+ patterns in the volume, direction, sizes, sender, destination, or
+ timing of our business messages. Those messages are hidden in a mass of
+ news messages encapsulated in the same way.</P>
+<P>If we're going to do this we need to ensure that keys change often
+ enough to remain secure even with high volumes and with the adversary
+ able to get plaintext of much of the data. We also need to look at
+ other attacks this might open up. For example, can the adversary use a
+ chosen plaintext attack, deliberately posting news articles which, when
+ we receive and encrypt them, will help break our encryption? Or can he
+ block our business data transmission by flooding us with silly news
+ articles? Or ...</P>
+<P>Also, note that this does not provide complete protection against
+ traffic analysis. A clever adversary might still deduce useful
+ intelligence from statistical analysis (perhaps comparing the input
+ newsfeed to encrypted output, or comparing the streams we send to
+ different branch offices), or by looking for small packets which might
+ indicate establishment of TCP connections, or ...</P>
+<P>As a general rule, though, to improve resistance to traffic analysis,
+ you should<STRONG> encrypt as much traffic as possible, not just as
+ much as seems necessary.</STRONG></P>
+<H4><A name="multi-encrypt">Using multiple encryption</A></H4>
+<P>This also applies to using multiple layers of encryption. If you have
+ an IPsec tunnel between two branch offices, it might appear silly to
+ send<A href="#PGP"> PGP</A>-encrypted email through that tunnel.
+ However, if you suspect someone is snooping your traffic, then it does
+ make sense:</P>
+<UL>
+<LI>it protects the mail headers; they cannot even see who is mailing
+ who</LI>
+<LI>it protects against user bungles or software malfunctions that
+ accidentally send messages in the clear</LI>
+<LI>it makes any attack on the mail encryption much harder; they have to
+ break IPsec or break into your network before they can start on the
+ mail encryption</LI>
+</UL>
+<P>Similar arguments apply for<A href="#SSL"> SSL</A>-encrypted web
+ traffic or<A href="#ssh"> SSH</A>-encrypted remote login sessions, even
+ for end-to-end IPsec tunnels between systems in the two offices.</P>
+<H4><A name="fewer">Using fewer tunnels</A></H4>
+<P>It may also help to use fewer tunnels. For example, if all you
+ actually need encrypted is connections between:</P>
+<UL>
+<LI>mail servers at branch and head offices</LI>
+<LI>a few branch office users and the head office database server</LI>
+</UL>
+<P>You might build one tunnel per mail server and one per remote
+ database user, restricting traffic to those applications. This gives
+ the traffic analyst some information, however. He or she can
+ distinguish the tunnels by looking at information in the ESP header
+ and, given that distinction and the patterns of tunnel usage, might be
+ able to figure out something useful. Perhaps not, but why take the
+ risk?</P>
+<P>We suggest instead that you build one tunnel per branch office,
+ encrypting everything passing from head office to branches. This has a
+ number of advantages:</P>
+<UL>
+<LI>it is easier to build and administer</LI>
+<LI>it resists traffic analysis somewhat better</LI>
+<LI>it provides security for whatever you forgot. For example, if some
+ user at a remote office browses proprietary company data on some head
+ office web page (that the security people may not even know about!),
+ then that data is encrypted before it reaches the Internet.</LI>
+</UL>
+<P>Of course you might also want to add additional tunnels. For example,
+ if some of the database data is confidential and should not be exposed
+ even within the company, then you need protection from the user's
+ desktop to the database server. We suggest you do that in whatever way
+ seems appropriate -- IPsec, SSH or SSL might fit -- but, whatever you
+ choose, pass it between locations via a gateway-to-gateway IPsec tunnel
+ to provide some resistance to traffic analysis.</P>
+<H2><A name="primitives">Cryptographic components</A></H2>
+<P>IPsec combines a number of cryptographic techniques, all of them
+ well-known and well-analyzed. The overall design approach was
+ conservative; no new or poorly-understood components were included.</P>
+<P>This section gives a brief overview of each technique. It is intended
+ only as an introduction. There is more information, and links to
+ related topics, in our<A href="glossary.html"> glossary</A>. See also
+ our<A href="biblio.html"> bibliography</A> and cryptography<A href="#crypto.link">
+ web links</A>.</P>
+<H3><A name="block.cipher">Block ciphers</A></H3>
+<P>The<A href="#encryption"> encryption</A> in the<A href="#ESP"> ESP</A>
+ encapsulation protocol is done with a<A href="#block"> block cipher</A>
+.</P>
+<P>We do not implement<A href="#DES"> single DES</A>. It is<A href="#desnotsecure">
+ insecure</A>. Our default, and currently only, block cipher is<A href="#3DES">
+ triple DES</A>.</P>
+<P>The<A href="#rijndael"> Rijndael</A> block cipher has won the<A href="#AES">
+ AES</A> competition to choose a relacement for DES. It will almost
+ certainly be added to FreeS/WAN and to other IPsec implementations.<A href="#patch">
+ Patches</A> are already available.</P>
+<H3><A name="hash.ipsec">Hash functions</A></H3>
+<H4><A name="hmac.ipsec">The HMAC construct</A></H4>
+<P>IPsec packet authentication is done with the<A href="#HMAC"> HMAC</A>
+ construct. This is not just a hash of the packet data, but a more
+ complex operation which uses both a hashing algorithm and a key. It
+ therefore does more than a simple hash would. A simple hash would only
+ tell you that the packet data was not changed in transit, or that
+ whoever changed it also regenerated the hash. An HMAC also tells you
+ that the sender knew the HMAC key.</P>
+<P>For IPsec HMAC, the output of the hash algorithm is truncated to 96
+ bits. This saves some space in the packets. More important, it prevents
+ an attacker from seeing all the hash output bits and perhaps creating
+ some sort of attack based on that knowledge.</P>
+<H4><A NAME="27_3_2_2">Choice of hash algorithm</A></H4>
+<P>The IPsec RFCs require two hash algorithms --<A href="#MD5"> MD5</A>
+ and<A href="#SHA"> SHA-1</A> -- both of which FreeS/WAN implements.</P>
+<P>Various other algorithms -- such as RIPEMD and Tiger -- are listed in
+ the RFCs as optional. None of these are in the FreeS/WAN distribution,
+ or are likely to be added, although user<A href="#patch"> patches</A>
+ exist for several of them.</P>
+<P>Additional hash algorithms --<A href="#SHA-256"> SHA-256, SHA-384 and
+ SHA-512</A> -- may be required to give hash strength matching the
+ strength of<A href="#AES"> AES</A>. These are likely to be added to
+ FreeS/WAN along with AES.</P>
+<H3><A name="DH.keying">Diffie-Hellman key agreement</A></H3>
+<P>The<A href="#DH"> Diffie-Hellman</A> key agreement protocol allows
+ two parties (A and B or<A href="#alicebob"> Alice and Bob</A>) to agree
+ on a key in such a way that an eavesdropper who intercepts the entire
+ conversation cannot learn the key.</P>
+<P>The protocol is based on the<A href="#dlog"> discrete logarithm</A>
+ problem and is therefore thought to be secure. Mathematicians have been
+ working on that problem for years and seem no closer to a solution,
+ though there is no proof that an efficient solution is impossible.</P>
+<H3><A name="RSA.auth">RSA authentication</A></H3>
+<P>The<A href="#RSA"> RSA</A> algorithm (named for its inventors --
+ Rivest, Shamir and Adleman) is a very widely used<A href="glossary.html#">
+ public key</A> cryptographic technique. It is used in IPsec as one
+ method of authenticating gateways for Diffie-Hellman key negotiation.</P>
+<H2><A name="structure">Structure of IPsec</A></H2>
+<P>There are three protocols used in an IPsec implementation:</P>
+<DL>
+<DT>ESP, Encapsulating Security Payload</DT>
+<DD>Encrypts and/or authenticates data</DD>
+<DT>AH, Authentication Header</DT>
+<DD>Provides a packet authentication service</DD>
+<DT>IKE, Internet Key Exchange</DT>
+<DD>Negotiates connection parameters, including keys, for the other two</DD>
+</DL>
+<P>The term &quot;IPsec&quot; is slightly ambiguous. In some contexts, it includes
+ all three of the above but in other contexts it refers only to AH and
+ ESP.</P>
+<H3><A name="IKE.ipsec">IKE (Internet Key Exchange)</A></H3>
+<P>The IKE protocol sets up IPsec (ESP or AH) connections after
+ negotiating appropriate parameters (algorithms to be used, keys,
+ connection lifetimes) for them. This is done by exchanging packets on
+ UDP port 500 between the two gateways.</P>
+<P>IKE (RFC 2409) was the outcome of a long, complex process in which
+ quite a number of protocols were proposed and debated. Oversimplifying
+ mildly, IKE combines:</P>
+<DL>
+<DT>ISAKMP (RFC 2408)</DT>
+<DD>The<STRONG> I</STRONG>nternet<STRONG> S</STRONG>ecurity<STRONG> A</STRONG>
+ssociation and<STRONG> K</STRONG>ey<STRONG> M</STRONG>anagement<STRONG>
+ P</STRONG>rotocol manages negotiation of connections and defines<A href="#SA">
+ SA</A>s (Security Associations) as a means of describing connection
+ properties.</DD>
+<DT>IPsec DOI for ISAKMP (RFC 2407)</DT>
+<DD>A<STRONG> D</STRONG>omain<STRONG> O</STRONG>f<STRONG> I</STRONG>
+nterpretation fills in the details necessary to turn the rather abstract
+ ISAKMP protocol into a more tightly specified protocol, so it becomes
+ applicable in a particular domain.</DD>
+<DT>Oakley key determination protocol (RFC 2412)</DT>
+<DD>Oakley creates keys using the<A href="#DH"> Diffie-Hellman</A> key
+ agreement protocol.</DD>
+</DL>
+<P>For all the details, you would need to read the four<A href="rfc.html">
+ RFCs</A> just mentioned (over 200 pages) and a number of others. We
+ give a summary below, but it is far from complete.</P>
+<H4><A name="phases">Phases of IKE</A></H4>
+<P>IKE negotiations have two phases.</P>
+<DL>
+<DT>Phase one</DT>
+<DD>The two gateways negotiate and set up a two-way ISAKMP SA which they
+ can then use to handle phase two negotiations. One such SA between a
+ pair of gateways can handle negotiations for multiple tunnels.</DD>
+<DT>Phase two</DT>
+<DD>Using the ISAKMP SA, the gateways negotiate IPsec (ESP and/or AH)
+ SAs as required. IPsec SAs are unidirectional (a different key is used
+ in each direction) and are always negotiated in pairs to handle two-way
+ traffic. There may be more than one pair defined between two gateways.</DD>
+</DL>
+<P>Both of these phases use the UDP protocol and port 500 for their
+ negotiations.</P>
+<P>After both IKE phases are complete, you have IPsec SAs to carry your
+ encrypted data. These use the ESP or AH protocols. These protocols do
+ not have ports. Ports apply only to UDP or TCP.</P>
+<P>The IKE protocol is designed to be extremely flexible. Among the
+ things that can be negotiated (separately for each SA) are:</P>
+<UL>
+<LI>SA lifetime before rekeying</LI>
+<LI>encryption algorithm used. We currently support only<A href="#3DES">
+ triple DES</A>. Single DES is<A href="#desnotsecure"> insecure</A>. The
+ RFCs say you MUST do DES, SHOULD do 3DES and MAY do various others. We
+ do not do any of the others.</LI>
+<LI>authentication algorithms. We support<A href="#MD5"> MD5</A> and<A href="#SHA">
+ SHA</A>. These are the two the RFCs require.</LI>
+<LI>choice of group for<A href="#DH"> Diffie-Hellman</A> key agreement.
+ We currently support Groups 2 and 5 (which are defined modulo primes of
+ various lengths) and do not support Group 1 (defined modulo a shorter
+ prime, and therefore cryptographically weak) or groups 3 and 4 (defined
+ using elliptic curves). The RFCs require only Group 1.</LI>
+</UL>
+<P>The protocol also allows implementations to add their own encryption
+ algorithms, authentication algorithms or Diffie-Hellman groups. We do
+ not support any such extensions, but there are some<A href="#patch">
+ patches</A> that do.</P>
+<P>There are a number of complications:</P>
+<UL>
+<LI>The gateways must be able to authenticate each other's identities
+ before they can create a secure connection. This host authentication is
+ part of phase one negotiations, and is a required prerequisite for
+ packet authentication used later. Host authentication can be done in a
+ variety of ways. Those supported by FreeS/WAN are discussed in our<A href="#auto-auth">
+ advanced configuration</A> document.</LI>
+<LI>Phase one can be done in two ways.
+<UL>
+<LI>Main Mode is required by the RFCs and supported in FreeS/WAN. It
+ uses a 6-packet exzchange.</LI>
+<LI>Aggressive Mode is somewhat faster (only 3 packets) but reveals more
+ to an eavesdropper. This is optional in the RFCs, not currently
+ supported by FreeS/WAN, and not likely to be.</LI>
+</UL>
+</LI>
+<LI>A new group exchange may take place after phase one but before phase
+ two, defining an additional group for use in the<A href="#DH">
+ Diffie-Hellman</A> key agreement part of phase two. FreeS/WAN does not
+ currently support this.</LI>
+<LI>Phase two always uses Quick Mode, but there are two variants of
+ that:
+<UL>
+<LI>One variant provides<A href="#PFS"> Perfect Forward Secrecy (PFS)</A>
+. An attacker that obtains your long-term host authentication key does
+ not immediately get any of your short-term packet encryption of packet
+ authentication keys. He must conduct another successful attack each
+ time you rekey to get the short-term keys. Having some short-term keys
+ does not help him learn others. In particular, breaking your system
+ today does not let him read messages he archived yestarday, assuming
+ you've changed short-term keys in the meanwhile. We enable PFS as the
+ default.</LI>
+<LI>The other variant disables PFS and is therefore slightly faster. We
+ do not recommend this since it is less secure, but FreeS/WAN does
+ support it. You can enable it with a<VAR> pfs=no</VAR> statement in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>.</LI>
+<LI>The protocol provides no way to negotiate which variant will be
+ used. If one gateway is set for PFS and the other is not, the
+ negotiation fails. This has proved a fairly common source of
+ interoperation problems.</LI>
+</UL>
+</LI>
+<LI>Several types of notification message may be sent by either side
+ during either phase, or later. FreeS/WAN does not currently support
+ these, but they are a likely addition in future releases.</LI>
+<LI>There is a commit flag which may optionally be set on some messages.
+ The<A href="http://www.lounge.org/ike_doi_errata.html"> errata</A> page
+ for the RFCs includes two changes related to this, one to clarify the
+ description of its use and one to block a<A href="#DOS"> denial of
+ service</A> attack which uses it. We currently do not implement this
+ feature.</LI>
+</UL>
+<P>These complications can of course lead to problems, particularly when
+ two different implementations attempt to interoperate. For example, we
+ have seen problems such as:</P>
+<UL>
+<LI>Some implementations (often products crippled by<A href="#exlaw">
+ export laws</A>) have the insecure DES algorithm as their only
+ supported encryption method. Other parts of our documentation discuss
+ the<A href="#desnotsecure"> reasons we do not implement single DES</A>,
+ and<A href="interop.html#noDES"> how to cope with crippled products</A>
+.</LI>
+<LI>Windows 2000 IPsec tries to negotiate using Aggressive Mode, which
+ we don't support. Later on, it uses the commit bit, which we also don't
+ support.</LI>
+<LI>Various implementations disable PFS by default, and therefore will
+ not talk to FreeS/WAN until you either turn on PFS on their end or turn
+ it off in FreeS/WAN with a<VAR> pfs=no</VAR> entry in the connection
+ description.</LI>
+<LI>FreeS/WAN's interaction with PGPnet is complicated by their use of
+ notification messages we do not yet support.</LI>
+</UL>
+<P>Despite this, we do interoperate successfully with many
+ implementations, including both Windows 2000 and PGPnet. Details are in
+ our<A href="interop.html"> interoperability</A> document.</P>
+<H4><A name="sequence">Sequence of messages in IKE</A></H4>
+<P>Each phase (see<A href="#phases"> previous section</A>)of IKE
+ involves a series of messages. In Pluto error messages, these are
+ abbreviated using:</P>
+<DL>
+<DT>M</DT>
+<DD><STRONG>M</STRONG>ain mode, settting up the keying channel (ISAKMP
+ SA)</DD>
+<DT>Q</DT>
+<DD><STRONG>Q</STRONG>uick mode, setting up the data channel (IPsec SA)</DD>
+<DT>I</DT>
+<DD><STRONG>I</STRONG>nitiator, the machine that starts the negotiation</DD>
+<DT>R</DT>
+<DD><STRONG>R</STRONG>esponder</DD>
+</DL>
+<P>For example, the six messages of a main mode negotiation, in
+ sequence, are labelled:</P>
+<PRE> MI1 ----------&gt;
+ &lt;---------- MR1
+ MI2 ----------&gt;
+ &lt;---------- MR2
+ MI3 ----------&gt;
+ &lt;---------- MR3</PRE>
+<H4><A name="struct.exchange">Structure of IKE messages</A></H4>
+<P>Here is our Pluto developer explaining some of this on the mailing
+ list:</P>
+<PRE>When one IKE system (for example, Pluto) is negotiating with another
+to create an SA, the Initiator proposes a bunch of choices and the
+Responder replies with one that it has selected.
+
+The structure of the choices is fairly complicated. An SA payload
+contains a list of lists of &quot;Proposals&quot;. The outer list is a set of
+choices: the selection must be from one element of this list.
+
+Each of these elements is a list of Proposals. A selection must be
+made from each of the elements of the inner list. In other words,
+*all* of them apply (that is how, for example, both AH and ESP can
+apply at once).
+
+Within each of these Proposals is a list of Transforms. For each
+Proposal selected, one Transform must be selected (in other words,
+each Proposal provides a choice of Transforms).
+
+Each Transform is made up of a list of Attributes describing, well,
+attributes. Such as lifetime of the SA. Such as algorithm to be
+used. All the Attributes apply to a Transform.
+
+You will have noticed a pattern here: layers alternate between being
+disjunctions (&quot;or&quot;) and conjunctions (&quot;and&quot;).
+
+For Phase 1 / Main Mode (negotiating an ISAKMP SA), this structure is
+cut back. There must be exactly one Proposal. So this degenerates to
+a list of Transforms, one of which must be chosen.</PRE>
+<H3><A name="services">IPsec Services, AH and ESP</A></H3>
+<P>IPsec offers two services,<A href="#authentication"> authentication</A>
+ and<A href="#encryption"> encryption</A>. These can be used separately
+ but are often used together.</P>
+<DL>
+<DT>Authentication</DT>
+<DD>Packet-level authentication allows you to be confident that a packet
+ came from a particular machine and that its contents were not altered
+ en route to you. No attempt is made to conceal or protect the contents,
+ only to assure their integrity. Packet authentication can be provided
+ separately using an<A href="#AH"> Authentication Header</A>, described
+ just below, or it can be included as part of the<A href="#ESP"> ESP</A>
+ (Encapsulated Security Payload) service, described in the following
+ section. That service offers encryption as well as authentication. In
+ either case, the<A href="#HMAC"> HMAC</A> construct is used as the
+ authentication mechanism.
+<P>There is a separate authentication operation at the IKE level, in
+ which each gateway authenticates the other. This can be done in a
+ variety of ways.</P>
+</DD>
+<DT>Encryption</DT>
+<DD>Encryption allows you to conceal the contents of a message from
+ eavesdroppers.
+<P>In IPsec this is done using a<A href="#block"> block cipher</A>
+ (normally<A href="#3DES"> Triple DES</A> for Linux). In the most used
+ setup, keys are automatically negotiated, and periodically
+ re-negotiated, using the<A href="#IKE"> IKE</A> (Internet Key Exchange)
+ protocol. In Linux FreeS/WAN this is handled by the Pluto Daemon.</P>
+<P>The IPsec protocol offering encryption is<A href="#ESP"> ESP</A>,
+ Encapsulated Security Payload. It can also include a packet
+ authentication service.</P>
+</DD>
+</DL>
+<P>Note that<STRONG> encryption should always be used with some packet
+ authentication service</STRONG>. Unauthenticated encryption is
+ vulnerable to<A href="#middle"> man-in-the-middle attacks</A>. Also
+ note that encryption does not prevent<A href="#traffic"> traffic
+ analysis</A>.</P>
+<H3><A name="AH.ipsec">The Authentication Header (AH)</A></H3>
+<P>Packet authentication can be provided separately from encryption by
+ adding an authentication header (AH) after the IP header but before the
+ other headers on the packet. This is the subject of this section.
+ Details are in RFC 2402.</P>
+<P>Each of the several headers on a packet header contains a &quot;next
+ protocol&quot; field telling the system what header to look for next. IP
+ headers generally have either TCP or UDP in this field. When IPsec
+ authentication is used, the packet IP header has AH in this field,
+ saying that an Authentication Header comes next. The AH header then has
+ the next header type -- usually TCP, UDP or encapsulated IP.</P>
+<P>IPsec packet authentication can be added in transport mode, as a
+ modification of standard IP transport. This is shown in this diagram
+ from the RFC:</P>
+<PRE> BEFORE APPLYING AH
+ ----------------------------
+ IPv4 |orig IP hdr | | |
+ |(any options)| TCP | Data |
+ ----------------------------
+
+ AFTER APPLYING AH
+ ---------------------------------
+ IPv4 |orig IP hdr | | | |
+ |(any options)| AH | TCP | Data |
+ ---------------------------------
+ ||
+ except for mutable fields</PRE>
+<P>Athentication can also be used in tunnel mode, encapsulating the
+ underlying IP packet beneath AH and an additional IP header.</P>
+<PRE> ||
+IPv4 | new IP hdr* | | orig IP hdr* | | |
+ |(any options)| AH | (any options) |TCP | Data |
+ ------------------------------------------------
+ ||
+ | in the new IP hdr |</PRE>
+<P>This would normally be used in a gateway-to-gateway tunnel. The
+ receiving gateway then strips the outer IP header and the AH header and
+ forwards the inner IP packet.</P>
+<P>The mutable fields referred to are things like the time-to-live field
+ in the IP header. These cannot be included in authentication
+ calculations because they change as the packet travels.</P>
+<H4><A name="keyed">Keyed MD5 and Keyed SHA</A></H4>
+<P>The actual authentication data in the header is typically 96 bits and
+ depends both on a secret shared between sender and receiver and on
+ every byte of the data being authenticated. The technique used is<A href="#HMAC">
+ HMAC</A>, defined in RFC 2104.</P>
+<P>The algorithms involved are the<A href="#MD5"> MD5</A> Message Digest
+ Algorithm or<A href="#SHA"> SHA</A>, the Secure Hash Algorithm. For
+ details on their use in this application, see RFCs 2403 and 2404
+ respectively.</P>
+<P>For descriptions of the algorithms themselves, see RFC 1321 for MD5
+ and<A href="#FIPS"> FIPS</A> (Federal Information Processing Standard)
+ number 186 from<A href="#NIST"> NIST</A>, the US National Institute of
+ Standards and Technology for SHA.<A href="#schneier"><CITE> Applied
+ Cryptography</CITE></A> covers both in some detail, MD5 starting on
+ page 436 and SHA on 442.</P>
+<P>These algorithms are intended to make it nearly impossible for anyone
+ to alter the authenticated data in transit. The sender calculates a
+ digest or hash value from that data and includes the result in the
+ authentication header. The recipient does the same calculation and
+ compares results. For unchanged data, the results will be identical.
+ The hash algorithms are designed to make it extremely difficult to
+ change the data in any way and still get the correct hash.</P>
+<P>Since the shared secret key is also used in both calculations, an
+ interceptor cannot simply alter the authenticated data and change the
+ hash value to match. Without the key, he or she (or even the dreaded
+ They) cannot produce a usable hash.</P>
+<H4><A name="sequence">Sequence numbers</A></H4>
+<P>The authentication header includes a sequence number field which the
+ sender is required to increment for each packet. The receiver can
+ ignore it or use it to check that packets are indeed arriving in the
+ expected sequence.</P>
+<P>This provides partial protection against<A href="#replay"> replay
+ attacks</A> in which an attacker resends intercepted packets in an
+ effort to confuse or subvert the receiver. Complete protection is not
+ possible since it is necessary to handle legitmate packets which are
+ lost, duplicated, or delivered out of order, but use of sequence
+ numbers makes the attack much more difficult.</P>
+<P>The RFCs require that sequence numbers never cycle, that a new key
+ always be negotiated before the sequence number reaches 2^32-1. This
+ protects both against replays attacks using packets from a previous
+ cyclce and against<A href="#birthday"> birthday attacks</A> on the the
+ packet authentication algorithm.</P>
+<P>In Linux FreeS/WAN, the sequence number is ignored for manually keyed
+ connections and checked for automatically keyed ones. In manual mode,
+ there is no way to negotiate a new key, or to recover from a sequence
+ number problem, so we don't use sequence numbers.</P>
+<H3><A name="ESP.ipsec">Encapsulated Security Payload (ESP)</A></H3>
+<P>The ESP protocol is defined in RFC 2406. It provides one or both of
+ encryption and packet authentication. It may be used with or without AH
+ packet authentication.</P>
+<P>Note that<STRONG> some form of packet authentication should<EM>
+ always</EM> be used whenever data is encrypted</STRONG>. Without
+ authentication, the encryption is vulnerable to active attacks which
+ may allow an enemy to break the encryption. ESP should<STRONG> always</STRONG>
+ either include its own authentication or be used with AH
+ authentication.</P>
+<P>The RFCs require support for only two mandatory encryption algorithms
+ --<A href="#DES"> DES</A>, and null encryption -- and for two
+ authentication methods -- keyed MD5 and keyed SHA. Implementers may
+ choose to support additional algorithms in either category.</P>
+<P>The authentication algorithms are the same ones used in the IPsec<A href="#AH">
+ authentication header</A>.</P>
+<P>We do not implement single DES since<A href="#desnotsecure"> DES is
+ insecure</A>. Instead we provide<A href="#3DES"> triple DES or 3DES</A>
+. This is currently the only encryption algorithm supported.</P>
+<P>We do not implement null encryption since it is obviously insecure.</P>
+<H2><A name="modes">IPsec modes</A></H2>
+<P>IPsec can connect in two modes. Transport mode is a host-to-host
+ connection involving only two machines. In tunnel mode, the IPsec
+ machines act as gateways and trafiic for any number of client machines
+ may be carried.</P>
+<H3><A name="tunnel.ipsec">Tunnel mode</A></H3>
+<P>Security gateways are required to support tunnel mode connections. In
+ this mode the gateways provide tunnels for use by client machines
+ behind the gateways. The client machines need not do any IPsec
+ processing; all they have to do is route things to gateways.</P>
+<H3><A name="transport.ipsec">Transport mode</A></H3>
+<P>Host machines (as opposed to security gateways) with IPsec
+ implementations must also support transport mode. In this mode, the
+ host does its own IPsec processing and routes some packets via IPsec.</P>
+<H2><A name="parts">FreeS/WAN parts</A></H2>
+<H3><A name="KLIPS.ipsec">KLIPS: Kernel IPsec Support</A></H3>
+<P>KLIPS is<STRONG> K</STRONG>erne<STRONG>L</STRONG><STRONG> IP</STRONG>
+SEC<STRONG> S</STRONG>upport, the modifications necessary to support
+ IPsec within the Linux kernel. KILPS does all the actual IPsec
+ packet-handling, including</P>
+<UL>
+<LI>encryption</LI>
+<LI>packet authentication calculations</LI>
+<LI>creation of ESP and AH headers for outgoing packets</LI>
+<LI>interpretation of those headers on incoming packets</LI>
+</UL>
+<P>KLIPS also checks all non-IPsec packets to ensure they are not
+ bypassing IPsec security policies.</P>
+<H3><A name="Pluto.ipsec">The Pluto daemon</A></H3>
+<P><A href="manpage.d/ipsec_pluto.8.html">Pluto(8)</A> is a daemon which
+ implements the IKE protocol. It</P>
+<UL>
+<LI>handles all the Phase one ISAKMP SAs</LI>
+<LI>performs host authentication and negotiates with other gateways</LI>
+<LI>creates IPsec SAs and passes the data required to run them to KLIPS</LI>
+<LI>adjust routing and firewall setup to meet IPsec requirements. See
+ our<A href="firewall.html"> IPsec and firewalling</A> document for
+ details.</LI>
+</UL>
+<P>Pluto is controlled mainly by the<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> configuration file.</P>
+<H3><A name="command">The ipsec(8) command</A></H3>
+<P>The<A href="manpage.d/ipsec.8.html"> ipsec(8)</A> command is a front
+ end shellscript that allows control over IPsec activity.</P>
+<H3><A name="ipsec.conf">Linux FreeS/WAN configuration file</A></H3>
+<P>The configuration file for Linux FreeS/WAN is</P>
+<PRE> /etc/ipsec.conf</PRE>
+<P>For details see the<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> manual page .</P>
+<H2><A name="key">Key management</A></H2>
+<P>There are several ways IPsec can manage keys. Not all are implemented
+ in Linux FreeS/WAN.</P>
+<H3><A name="current">Currently Implemented Methods</A></H3>
+<H4><A name="manual">Manual keying</A></H4>
+<P>IPsec allows keys to be manually set. In Linux FreeS/WAN, such keys
+ are stored with the connection definitions in /etc/ipsec.conf.</P>
+<P><A href="#manual">Manual keying</A> is useful for debugging since it
+ allows you to test the<A href="#KLIPS"> KLIPS</A> kernel IPsec code
+ without the<A href="#Pluto"> Pluto</A> daemon doing key negotiation.</P>
+<P>In general, however, automatic keying is preferred because it is more
+ secure.</P>
+<H4><A name="auto">Automatic keying</A></H4>
+<P>In automatic keying, the<A href="#Pluto"> Pluto</A> daemon negotiates
+ keys using the<A href="#IKE"> IKE</A> Internet Key Exchange protocol.
+ Connections are automatically re-keyed periodically.</P>
+<P>This is considerably more secure than manual keying. In either case
+ an attacker who acquires a key can read every message encrypted with
+ that key, but automatic keys can be changed every few hours or even
+ every few minutes without breaking the connection or requiring
+ intervention by the system administrators. Manual keys can only be
+ changed manually; you need to shut down the connection and have the two
+ admins make changes. Moreover, they have to communicate the new keys
+ securely, perhaps with<A href="#PGP"> PGP</A> or<A href="#ssh"> SSH</A>
+. This may be possible in some cases, but as a general solution it is
+ expensive, bothersome and unreliable. Far better to let<A href="#Pluto">
+ Pluto</A> handle these chores; no doubt the administrators have enough
+ to do.</P>
+<P>Also, automatic keying is inherently more secure against an attacker
+ who manages to subvert your gateway system. If manual keying is in use
+ and an adversary acquires root privilege on your gateway, he reads your
+ keys from /etc/ipsec.conf and then reads all messages encrypted with
+ those keys.</P>
+<P>If automatic keying is used, an adversary with the same privileges
+ can read /etc/ipsec.secrets, but this does not contain any keys, only
+ the secrets used to authenticate key exchanges. Having an adversary
+ able to authenticate your key exchanges need not worry you overmuch.
+ Just having the secrets does not give him any keys. You are still
+ secure against<A href="#passive"> passive</A> attacks. This property of
+ automatic keying is called<A href="#PFS"> perfect forward secrecy</A>,
+ abbreviated PFS.</P>
+<P>Unfortunately, having the secrets does allow an<A href="#active">
+ active attack</A>, specifically a<A href="#middle"> man-in-the-middle</A>
+ attack. Losing these secrets to an attacker may not be quite as
+ disastrous as losing the actual keys, but it is<EM> still a serious
+ security breach</EM>. These secrets should be guarded as carefully as
+ keys.</P>
+<H3><A name="notyet">Methods not yet implemented</A></H3>
+<H4><A name="noauth">Unauthenticated key exchange</A></H4>
+<P>It would be possible to exchange keys without authenticating the
+ players. This would support<A href="#carpediem"> opportunistic
+ encryption</A> -- allowing any two systems to encrypt their
+ communications without requiring a shared PKI or a previously
+ negotiated secret -- and would be secure against<A href="#passive">
+ passive attacks</A>. It would, however, be highly vulnerable to active<A
+href="#middle"> man-in-the-middle</A> attacks. RFC 2408 therefore
+ specifies that all<A href="#ISAKMP"> ISAKMP</A> key management
+ interactions<EM> must</EM> be authenticated.</P>
+<P>There is room for debate here. Should we provide immediate security
+ against<A href="#passive"> passive attacks</A> and encourage widespread
+ use of encryption, at the expense of risking the more difficult<A href="#active">
+ active attacks</A>? Or should we wait until we can implement a solution
+ that can both be widespread and offer security against active attacks?</P>
+<P>So far, we have chosen the second course, complying with the RFCs and
+ waiting for secure DNS (see<A href="#DNS"> below</A>) so that we can do<A
+href="#carpediem"> opportunistic encryption</A> right.</P>
+<H4><A name="DNS">Key exchange using DNS</A></H4>
+<P>The IPsec RFCs allow key exchange based on authentication services
+ provided by<A href="#SDNS"> Secure DNS</A>. Once Secure DNS service
+ becomes widely available, we expect to make this the<EM> primary key
+ management method for Linux FreeS/WAN</EM>. It is the best way we know
+ of to support<A href="#carpediem"> opportunistic encryption</A>,
+ allowing two systems without a common PKI or previous negotiation to
+ secure their communication.</P>
+<P>We currently have code to acquire RSA keys from DNS but do not yet
+ have code to validate Secure DNS signatures.</P>
+<H4><A name="PKI">Key exchange using a PKI</A></H4>
+<P>The IPsec RFCs allow key exchange based on authentication services
+ provided by a<A href="#PKI"> PKI</A> or Public Key Infrastructure. With
+ many vendors selling such products and many large organisations
+ building these infrastructures, this will clearly be an important
+ application of IPsec and one Linux FreeS/WAN will eventually support.</P>
+<P>On the other hand, this is not as high a priority for Linux FreeS/WAN
+ as solutions based on<A href="#SDNS"> secure DNS</A>. We do not expect
+ any PKI to become as universal as DNS.</P>
+<P>Some<A href="#patch"> patches</A> to handle authentication with X.509
+ certificates, which most PKIs use, are available.</P>
+<H4><A name="photuris">Photuris</A></H4>
+<P><A href="#photuris">Photuris</A> is another key management protocol,
+ an alternative to IKE and ISAKMP, described in RFCs 2522 and 2523 which
+ are labelled &quot;experimental&quot;. Adding Photuris support to Linux FreeS/WAN
+ might be a good project for a volunteer. The likely starting point
+ would be the OpenBSD photurisd code.</P>
+<H4><A name="skip">SKIP</A></H4>
+<P><A href="#SKIP">SKIP</A> is yet another key management protocol,
+ developed by Sun. At one point it was fairly widely used, but it now
+ seems moribund, displaced by IKE. Sun now (as of Solaris 8.0) ship an
+ IPsec implementation using IKE. We have no plans to implement SKIP. If
+ a user were to implement it, we would almost certainly not want to add
+ the code to our distribution.</P>
+<HR>
+<H1><A name="lists">Mailing lists and newsgroups</A></H1>
+<H2><A name="list.fs">Mailing lists about FreeS/WAN</A></H2>
+<H3><A name="projlist">The project mailing lists</A></H3>
+<P>The Linux FreeS/WAN project has several email lists for user support,
+ bug reports and software development discussions.</P>
+<P>We had a single list on clinet.fi for several years (Thanks, folks!),
+ then one list on freeswan.org, but now we've split into several lists:</P>
+<DL>
+<DT><A href="mailto:users-request@lists.freeswan.org?body=subscribe">
+users</A></DT>
+<DD>
+<UL>
+<LI>The general list for discussing use of the software</LI>
+<LI>The place for seeking<STRONG> help with problems</STRONG> (but
+ please check the<A href="faq.html"> FAQ</A> first).</LI>
+<LI>Anyone can post.</LI>
+</UL>
+</DD>
+<DT><A href="mailto:bugs-request@lists.freeswan.org?body=subscribe">bugs</A>
+</DT>
+<DD>
+<UL>
+<LI>For<STRONG> bug reports</STRONG>.</LI>
+<LI>If you are not certain what is going on -- could be a bug, a
+ configuration error, a network problem, ... -- please post to the users
+ list instead.</LI>
+<LI>Anyone can post.</LI>
+</UL>
+</DD>
+<DT><A href="mailto:design-request@lists.freeswan.org?body=subscribe">
+design</A></DT>
+<DD>
+<UL>
+<LI><STRONG>Design discussions</STRONG>, for people working on FreeS/WAN
+ development or others with an interest in design and security issues.</LI>
+<LI>It would be a good idea to read the existing design papers (see this<A
+href="#applied"> list</A>) before posting.</LI>
+<LI>Anyone can post.</LI>
+</UL>
+</DD>
+<DT><A href="mailto:announce-request@lists.freeswan.org?body=subscribe">
+announce</A></DT>
+<DD>
+<UL>
+<LI>A<STRONG> low-traffic</STRONG> list.</LI>
+<LI><STRONG>Announcements</STRONG> about FreeS/WAN and related software.</LI>
+<LI>All posts here are also sent to the users list. You need not
+ subscribe to both.</LI>
+<LI>Only the FreeS/WAN team can post.</LI>
+<LI>If you have something you feel should go on this list, send it to<VAR>
+ announce-admin@lists.freeswan.org</VAR>. Unless it is obvious, please
+ include a short note explaining why we should post it.</LI>
+</UL>
+</DD>
+<DT><A href="mailto:briefs-request@lists.freeswan.org?body=subscribe">
+briefs</A></DT>
+<DD>
+<UL>
+<LI>A<STRONG> low-traffic</STRONG> list.</LI>
+<LI><STRONG>Weekly summaries</STRONG> of activity on the users list.</LI>
+<LI>All posts here are also sent to the users list. You need not
+ subscribe to both.</LI>
+<LI>Only the FreeS/WAN team can post.</LI>
+</UL>
+</DD>
+</DL>
+<P>To subscribe to any of these, you can:</P>
+<UL>
+<LI>just follow the links above</LI>
+<LI>use our<A href="http://www.freeswan.org/mail.html"> web interface</A>
+</LI>
+<LI>send mail to<VAR> listname</VAR>-request@lists.freeswan.org with a
+ one-line message body &quot;subscribe&quot;</LI>
+</UL>
+<P>Archives of these lists are available via the<A href="http://www.freeswan.org/mail.html">
+ web interface</A>.</P>
+<H4><A name="which.list">Which list should I use?</A></H4>
+<P>For most questions, please check the<A href="faq.html"> FAQ</A>
+ first, and if that does not have an answer, ask on the users list. &quot;My
+ configuration doesn't work.&quot; does not belong on the bugs list, and &quot;Can
+ FreeS/WAN do such-and-such&quot; or &quot;How do I configure it to...&quot; do not
+ belong in design discussions.</P>
+<P>Cross-posting the same message to two or more of these lists is
+ discouraged. Quite a few people read more than one list and getting
+ multiple copies is annoying.</P>
+<H4><A name="policy.list">List policies</A></H4>
+<P><STRONG>US citizens or residents are asked not to post code to the
+ lists, not even one-line bug fixes</STRONG>. The project cannot accept
+ code which might entangle it in US<A href="#exlaw"> export restrictions</A>
+.</P>
+<P>Non-subscribers can post to some of these lists. This is necessary;
+ someone working on a gateway install who encounters a problem may not
+ have access to a subscribed account.</P>
+<P>Some spam turns up on these lists from time to time. For discussion
+ of why we do not attempt to filter it, see the<A href="#spam"> FAQ</A>.
+ Please do not clutter the lists with complaints about this.</P>
+<H3><A name="archive">Archives of the lists</A></H3>
+<P>Searchable archives of the old single list have existed for some
+ time. At time of writing, it is not yet clear how they will change for
+ the new multi-list structure.</P>
+<UL>
+<LI><A href="http://www.sandelman.ottawa.on.ca/linux-ipsec">Canada</A></LI>
+<LI><A href="http://www.nexial.com">Holland</A></LI>
+</UL>
+<P>Note that these use different search engines. Try both.</P>
+<P>Archives of the new lists are available via the<A href="http://www.freeswan.org/mail.html">
+ web interface</A>.</P>
+<H2><A name="indexes">Indexes of mailing lists</A></H2>
+<P><A href="http://paml.net/">PAML</A> is the standard reference for<STRONG>
+ P</STRONG>ublicly<STRONG> A</STRONG>ccessible<STRONG> M</STRONG>ailing<STRONG>
+ L</STRONG>ists. When we last checked, it had over 7500 lists on an
+ amazing variety of topics. It also has FAQ information and a search
+ engine.</P>
+<P>There is an index of<A href="http://oslab.snu.ac.kr/~djshin/linux/mail-list/index.shtml">
+ Linux mailing lists</A> available.</P>
+<P>A list of<A href="http://xforce.iss.net/maillists/otherlists.php">
+ computer security mailing lists</A>, with descriptions.</P>
+<H2><A name="otherlists">Lists for related software and topics</A></H2>
+<P>Most links in this section point to subscription addresses for the
+ various lists. Send the one-line message &quot;subscribe<VAR> list_name</VAR>
+&quot; to subscribe to any of them.</P>
+<H3><A NAME="28_3_1">Products that include FreeS/WAN</A></H3>
+<P>Our introduction document gives a<A href="#products"> list of
+ products that include FreeS/WAN</A>. If you have, or are considering,
+ one of those, check the supplier's web site for information on mailing
+ lists for their users.</P>
+<H3><A name="linux.lists">Linux mailing lists</A></H3>
+<UL>
+<LI><A href="mailto:majordomo@vger.kernel.org">
+linux-admin@vger.kernel.org</A>, for Linux system administrators</LI>
+<LI><A href="mailto:netfilter-request@lists.samba.org">
+netfilter@lists.samba.org</A>, about Netfilter, which replaces IPchains
+ in kernels 2.3.15 and later</LI>
+<LI><A href="mailto:security-audit-request@ferret.lmh.ox.ac.uk">
+security-audit@ferret.lmh.ox.ac.uk</A>, for people working on security
+ audits of various Linux programs</LI>
+<LI><A href="mailto:securedistros-request@humbolt.geo.uu.nl">
+securedistros@humbolt.geo.uu.nl</A>, for discussion of issues common to
+ all the half dozen projects working on secure Linux distributions.</LI>
+</UL>
+<P>Each of the scure distribution projects also has its own web site and
+ mailing list. Some of the sites are:</P>
+<UL>
+<LI><A href="http://bastille-linux.org/">Bastille Linux</A> scripts to
+ harden Redhat, e.g. by changing permissions and modifying inialisation
+ scripts</LI>
+<LI><A href="http://immunix.org/">Immunix</A> take a different approach,
+ using a modified compiler to build kernel and utilities with better
+ resistance to various types of overflow and exploit</LI>
+<LI>the<A href="#NSA"> NSA</A> have contractors working on a<A href="#SElinux">
+ Security Enhanced Linux</A>, primarily adding stronger access control
+ mechanisms. You can download the current version (which interestingly
+ is under GPL and not export resrtricted) or subscribe to the mailing
+ list from the<A href="http://www.nsa.gov/selinux"> project web page</A>
+.</LI>
+</UL>
+<H3><A name="ietf">Lists for IETF working groups</A></H3>
+<P>Each<A href="#ietf"> IETF</A> working group has an associated mailing
+ list where much of the work takes place.</P>
+<UL>
+<LI><A href="mailto:majordomo@lists.tislabs.com">ipsec@lists.tislabs.com</A>
+, the IPsec<A href="http://www.ietf.org/html.charters/ipsec-charter.html">
+ working group</A>. This is where the protocols are discussed, new
+ drafts announced, and so on. By now, the IPsec working group is winding
+ down since the work is essentially complete. A<A href="http://www.sandelman.ottawa.on.ca/ipsec/">
+ list archive</A> is available.</LI>
+<LI><A href="mailto:ipsec-policy-request@vpnc.org">IPsec policy</A>
+ list, and its<A href="http://www.vpnc.org/ipsec-policy/"> archive</A></LI>
+<LI><A href="mailto:ietf-ipsra-request@vpnc.org">IP secure remote access</A>
+ list, and its<A href="http://www.vpnc.org/ietf-ipsra/mail-archive/">
+ archive</A></LI>
+</UL>
+<H3><A name="other">Other mailing lists</A></H3>
+<UL>
+<LI><A href="mailto:ipc-announce-request@privacy.org">
+ipc-announce@privacy.org</A> a low-traffic list with announcements of
+ developments in privacy, encryption and online civil rights</LI>
+<LI>a VPN mailing list's<A href="http://kubarb.phsx.ukans.edu/~tbird/vpn.html">
+ home page</A></LI>
+</UL>
+<H2><A name="newsgroups">Usenet newsgroups</A></H2>
+<UL>
+<LI>sci.crypt</LI>
+<LI>sci.crypt.research</LI>
+<LI>comp.dcom.vpn</LI>
+<LI>talk.politics.crypto</LI>
+</UL>
+<HR>
+<H1><A name="weblink">Web links</A></H1>
+<H2><A name="freeswan">The Linux FreeS/WAN Project</A></H2>
+<P>The main project web site is<A href="http://www.freeswan.org/">
+ www.freeswan.org</A>.</P>
+<P>Links to other project-related<A href="#sites"> sites</A> are
+ provided in our introduction section.</P>
+<H3><A name="patch">Add-ons and patches for FreeS/WAN</A></H3>
+<P>Some user-contributed patches have been integrated into the FreeS/WAN
+ distribution. For a variety of reasons, those listed below have not.</P>
+<P>Note that not all patches are a good idea.</P>
+<UL>
+<LI>There are a number of &quot;features&quot; of IPsec which we do not implement
+ because they reduce security. See this<A href="#dropped"> discussion</A>
+. We do not recommend using patches that implement these. One example is
+ aggressive mode.</LI>
+<LI>We do not recommend adding &quot;features&quot; of any sort unless they are
+ clearly necessary, or at least have clear benefits. For example,
+ FreeS/WAN would not become more secure if it offerred a choice of 14
+ ciphers. If even one was flawed, it would certainly become less secure
+ for anyone using that cipher. Even with 14 wonderful ciphers, it would
+ be harder to maintain and administer, hence more vulnerable to various
+ human errors.</LI>
+</UL>
+<P>This is not to say that patches are necessarily bad, only that using
+ them requires some deliberation. For example, there might be perfectly
+ good reasons to add a specific cipher in your application: perhaps GOST
+ to comply with government standards in Eastern Europe, or AES for
+ performance benefits.</P>
+<H4><A NAME="29_1_1_1">Current patches</A></H4>
+<P>Patches believed current::</P>
+<UL>
+<LI>patches for<A href="http://www.strongsec.com/freeswan/"> X.509
+ certificate support</A>, also available from a<A href="http://www.twi.ch/~sna/strongsec/freeswan/">
+ mirror site</A></LI>
+<LI>patches to add<A href="http://www.irrigacion.gov.ar/juanjo/ipsec">
+ AES and other ciphers</A>. There is preliminary data indicating AES
+ gives a substantial<A href="#perf.more"> performance gain</A>.</LI>
+</UL>
+<P>There is also one add-on that takes the form of a modified FreeS/WAN
+ distribution, rather than just patches to the standard distribution:</P>
+<UL>
+<LI><A href="http://www.ipv6.iabg.de/downloadframe/index.html">IPv6
+ support</A></LI>
+</UL>
+<P>Before using any of the above,, check the<A href="mail.html"> mailing
+ lists</A> for news of newer versions and to see whether they have been
+ incorporated into more recent versions of FreeS/WAN.</P>
+<H4><A NAME="29_1_1_2">Older patches</A></H4>
+<UL>
+<LI><A href="http://sources.colubris.com/en/projects/FreeSWAN/">hardware
+ acceleration</A></LI>
+<LI>a<A href="http://tzukanov.narod.ru/"> series</A> of patches that
+<UL>
+<LI>provide GOST, a Russian gov't. standard cipher, in MMX assembler</LI>
+<LI>add GOST to OpenSSL</LI>
+<LI>add GOST to the International kernel patch</LI>
+<LI>let FreeS/WAN use International kernel patch ciphers</LI>
+</UL>
+</LI>
+<LI>Neil Dunbar's patches for<A href="ftp://hplose.hpl.hp.com/pub/nd/pluto-openssl.tar.gz">
+ certificate support</A>, using code from<A href="http://www.openssl.org">
+ Open SSL</A>.</LI>
+<LI>Luc Lanthier's<A href="ftp://ftp.netwinder.org/users/f/firesoul/">
+ patches</A> for<A href="#PKIX"> PKIX</A> support.</LI>
+<LI><A href="ftp://ftp.heise.de/pub/ct/listings/9916-180.tgz">patches</A>
+ to add<A href="#Blowfish"> Blowfish</A>,<A href="#IDEA"> IDEA</A> and<A href="#CAST128">
+ CAST-128</A> to FreeS/WAN</LI>
+<LI>patches for FreeS/WAN 1.3, Pluto support for<A href="http://alcatraz.webcriminals.com/~bastiaan/ipsec/">
+ external authentication</A>, for example with a smartcard or SKEYID.</LI>
+<LI><A href="http://www.zengl.net/freeswan/download/">patches and
+ utilities</A> for using FreeS/WAN with PGPnet</LI>
+<LI><A href="http://www.freelith.com/lithworks/crypto/freeswan_patch.htm">
+Blowfish encryption and Tiger hash</A></LI>
+<LI><A href="http://www.cendio.se/~bellman/aggressive-pluto.snap.tar.gz">
+patches</A> for aggressive mode support</LI>
+</UL>
+<P>These patches are for older versions of FreeS/WAN and will likely not
+ work with the current version. Older versions of FreeS/WAN may be
+ available on some of the<A href="#sites"> distribution sites</A>, but
+ we recommend using the current release.</P>
+<H4><A name="VPN.masq">VPN masquerade patches</A></H4>
+<P>Finally, there are some patches to other code that may be useful with
+ FreeS/WAN:</P>
+<UL>
+<LI>a<A href="ftp://ftp.rubyriver.com/pub/jhardin/masquerade/ip_masq_vpn.html">
+ patch</A> to make IPsec, PPTP and SSH VPNs work through a Linux
+ firewall with<A href="#masq"> IP masquerade</A>.</LI>
+<LI><A href="http://www.linuxdoc.org/HOWTO/VPN-Masquerade-HOWTO.html">
+Linux VPN Masquerade HOWTO</A></LI>
+</UL>
+<P>Note that this is not required if the same machine does IPsec and
+ masquerading, only if you want a to locate your IPsec gateway on a
+ masqueraded network. See our<A href="#NAT"> firewalls</A> document for
+ discussion of why this is problematic.</P>
+<P>At last report, this patch could not co-exist with FreeS/WAN on the
+ same machine.</P>
+<H3><A name="dist">Distributions including FreeS/WAN</A></H3>
+<P>The introductory section of our document set lists several<A href="#distwith">
+ Linux distributions</A> which include FreeS/WAN.</P>
+<H3><A name="used">Things FreeS/WAN uses or could use</A></H3>
+<UL>
+<LI><A href="http://openpgp.net/random">/dev/random</A> support page,
+ discussion of and code for the Linux<A href="#random"> random number
+ driver</A>. Out-of-date when we last checked (January 2000), but still
+ useful.</LI>
+<LI>other programs related to random numbers:
+<UL>
+<LI><A href="http://www.mindrot.org/audio-entropyd.html">audio entropy
+ daemon</A> to gather noise from a sound card and feed it into
+ /dev/random</LI>
+<LI>an<A href="http://www.lothar.com/tech/crypto/"> entropy-gathering
+ daemon</A></LI>
+<LI>a driver for the random number generator in recent<A href="http://sourceforge.net/projects/gkernel/">
+ Intel chipsets</A>. This driver is included as standard in 2.4 kernels.</LI>
+</UL>
+</LI>
+<LI>a Linux<A href="http://www.marko.net/l2tp/"> L2TP Daemon</A> which
+ might be useful for communicating with Windows 2000 which builds L2TP
+ tunnels over its IPsec connections</LI>
+<LI>to use opportunistic encryption, you need a recent version of<A href="#BIND">
+ BIND</A>. You can get one from the<A href="http://www.isc.org">
+ Internet Software Consortium</A> who maintain BIND.</LI>
+</UL>
+<H3><A name="alternatives">Other approaches to VPNs for Linux</A></H3>
+<UL>
+<LI>other Linux<A href="#linuxipsec"> IPsec implementations</A></LI>
+<LI><A href="http://www.tik.ee.ethz.ch/~skip/">ENskip</A>, a free
+ implementation of Sun's<A href="#SKIP"> SKIP</A> protocol</LI>
+<LI><A href="http://sunsite.auc.dk/vpnd/">vpnd</A>, a non-IPsec VPN
+ daemon for Linux which creates tunnels using<A href="#Blowfish">
+ Blowfish</A> encryption</LI>
+<LI><A href="http://www.winton.org.uk/zebedee/">Zebedee</A>, a simple
+ GPLd tunnel-building program with Linux and Win32 versions. The name is
+ from<STRONG> Z</STRONG>lib compression,<STRONG> B</STRONG>lowfish
+ encryption and<STRONG> D</STRONG>iffie-Hellman key exchange.</LI>
+<LI>There are at least two PPTP implementations for Linux
+<UL>
+<LI>Moreton Bay's<A href="http://www.moretonbay.com/vpn/pptp.html">
+ PoPToP</A></LI>
+<LI><A href="http://cag.lcs.mit.edu/~cananian/Projects/PPTP/">PPTP-Linux</A>
+</LI>
+</UL>
+</LI>
+<LI><A href="http://sites.inka.de/sites/bigred/devel/cipe.html">CIPE</A>
+ (crypto IP encapsulation) project, using their own lightweight protocol
+ to encrypt between routers</LI>
+<LI><A href="http://tinc.nl.linux.org/">tinc</A>, a VPN Daemon</LI>
+</UL>
+<P>There is a list of<A href="http://www.securityportal.com/lskb/10000000/kben10000005.html">
+ Linux VPN</A> software in the<A href="http://www.securityportal.com/lskb/kben00000001.html">
+ Linux Security Knowledge Base</A>.</P>
+<H2><A name="ipsec.link">The IPsec Protocols</A></H2>
+<H3><A name="general">General IPsec or VPN information</A></H3>
+<UL>
+<LI>The<A href="http://www.vpnc.org"> VPN Consortium</A> is a group for
+ vendors of IPsec products. Among other things, they have a good
+ collection of<A href="http://www.vpnc.org/white-papers.html"> IPsec
+ white papers</A>.</LI>
+<LI>A VPN mailing list with a<A href="http://kubarb.phsx.ukans.edu/~tbird/vpn.html">
+ home page</A>, a FAQ, some product comparisons, and many links.</LI>
+<LI><A href="http://www.opus1.com/vpn/index.html">VPN pointer page</A></LI>
+<LI>a<A href="http://www.epm.ornl.gov/~dunigan/vpn.html"> collection</A>
+ of VPN links, and some explanation</LI>
+</UL>
+<H3><A name="overview">IPsec overview documents or slide sets</A></H3>
+<UL>
+<LI>the FreeS/WAN<A href="ipsec.html"> document section</A> on these
+ protocols</LI>
+</UL>
+<H3><A name="otherlang">IPsec information in languages other than
+ English</A></H3>
+<UL>
+<LI><A href="http://www.imib.med.tu-dresden.de/imib/Internet/Literatur/ipsec-docu.html">
+German</A></LI>
+<LI><A href="http://www.kame.net/index-j.html">Japanese</A></LI>
+<LI>Feczak Szabolcs' thesis in<A href="http://feczo.koli.kando.hu/vpn/">
+ Hungarian</A></LI>
+<LI>Davide Cerri's thesis and some presentation slides<A href="http://www.linux.it/~davide/doc/">
+ Italian</A></LI>
+</UL>
+<H3><A name="RFCs1">RFCs and other reference documents</A></H3>
+<UL>
+<LI><A href="rfc.html">Our document</A> listing the RFCs relevant to
+ Linux FreeS/WAN and giving various ways of obtaining both RFCs and
+ Internet Drafts.</LI>
+<LI><A href="http://www.vpnc.org/vpn-standards.html">VPN Standards</A>
+ page maintained by<A href="#VPNC"> VPNC</A>. This covers both RFCs and
+ Drafts, and classifies them in a fairly helpful way.</LI>
+<LI><A href="http://www.rfc-editor.org">RFC archive</A></LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/ipsec.html">Internet Drafts</A>
+ related to IPsec</LI>
+<LI>US government<A href="http://www.itl.nist.gov/div897/pubs"> site</A>
+ with their<A href="#FIPS"> FIPS</A> standards</LI>
+<LI>Archives of the ipsec@tis.com mailing list where discussion of
+ drafts takes place.
+<UL>
+<LI><A href="http://www.sandelman.ottawa.on.ca/ipsec">Eastern Canada</A></LI>
+<LI><A href="http://www.vpnc.org/ietf-ipsec">California</A>.</LI>
+</UL>
+</LI>
+</UL>
+<H3><A name="analysis">Analysis and critiques of IPsec protocols</A></H3>
+<UL>
+<LI>Counterpane's<A href="http://www.counterpane.com/ipsec.pdf">
+ evaluation</A> of the protocols</LI>
+<LI>Simpson's<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/1999/06/msg00319.html">
+ IKE Considered Dangerous</A> paper. Note that this is a link to an
+ archive of our mailing list. There are several replies in addition to
+ the paper itself.</LI>
+<LI>Fate Labs<A href="http://www.fatelabs.com/loki-vpn.pdf"> Virual
+ Private Problems: the Broken Dream</A></LI>
+<LI>Catherine Meadows' paper<CITE> Analysis of the Internet Key Exchange
+ Protocol Using the NRL Protocol Analyzer</CITE>, in<A href="http://chacs.nrl.navy.mil/publications/CHACS/1999/1999meadows-IEEE99.pdf">
+ PDF</A> or<A href="http://chacs.nrl.navy.mil/publications/CHACS/1999/1999meadows-IEEE99.ps">
+ Postscript</A>.</LI>
+<LI>Perlman and Kaufmnan
+<UL>
+<LI><A href="http://snoopy.seas.smu.edu/ee8392_summer01/week7/perlman2.pdf">
+Key Exchange in IPsec</A></LI>
+<LI>a newer<A href="http://sec.femto.org/wetice-2001/papers/radia-paper.pdf">
+ PDF paper</A>,<CITE> Analysis of the IPsec Key Exchange Standard</CITE>
+.</LI>
+</UL>
+</LI>
+<LI>Bellovin's<A href="http://www.research.att.com/~smb/papers/index.html">
+ papers</A> page including his:
+<UL>
+<LI><CITE>Security Problems in the TCP/IP Protocol Suite</CITE> (1989)</LI>
+<LI><CITE>Problem Areas for the IP Security Protocols</CITE> (1996)</LI>
+<LI><CITE>Probable Plaintext Cryptanalysis of the IP Security Protocols</CITE>
+ (1997)</LI>
+</UL>
+</LI>
+<LI>An<A href="http://www.lounge.org/ike_doi_errata.html"> errata list</A>
+ for the IPsec RFCs.</LI>
+</UL>
+<H3><A name="IP.background">Background information on IP</A></H3>
+<UL>
+<LI>An<A href="http://ipprimer.windsorcs.com/"> IP tutorial</A> that
+ seems to be written mainly for Netware or Microsoft LAN admins entering
+ a new world</LI>
+<LI><A href="http://www.iana.org">IANA</A>, Internet Assigned Numbers
+ Authority</LI>
+<LI><A href="http://public.pacbell.net/dedicated/cidr.html">CIDR</A>,
+ Classless Inter-Domain Routing</LI>
+<LI>Also see our<A href="biblio.html"> bibliography</A></LI>
+</UL>
+<H2><A name="implement">IPsec Implementations</A></H2>
+<H3><A name="linuxprod">Linux products</A></H3>
+<P>Vendors using FreeS/WAN in turnkey firewall or VPN products are
+ listed in our<A href="#turnkey"> introduction</A>.</P>
+<P>Other vendors have Linux IPsec products which, as far as we know, do
+ not use FreeS/WAN</P>
+<UL>
+<LI><A href="http://www.redcreek.com/products/shareware.html">Redcreek</A>
+ provide an open source Linux driver for their PCI hardware VPN card.
+ This card has a 100 Mbit Ethernet port, an Intel 960 CPU plus more
+ specialised crypto chips, and claimed encryption performance of 45
+ Mbit/sec. The PC sees it as an Ethernet board.</LI>
+<LI><A href="http://linuxtoday.com/stories/8428.html?nn">Paktronix</A>
+ offer a Linux-based VPN with hardware encryption</LI>
+<LI><A href="http://www.watchguard.com/">Watchguard</A> use Linux in
+ their Firebox product.</LI>
+<LI><A href="http://www.entrust.com">Entrust</A> offer a developers'
+ toolkit for using their<A href="#PKI"> PKI</A> for IPsec authentication</LI>
+<LI>According to a report on our mailing list,<A href="http://www.axent.com">
+ Axent</A> have a Linux version of their product.</LI>
+</UL>
+<H3><A name="router">IPsec in router products</A></H3>
+<P>All the major router vendors support IPsec, at least in some models.</P>
+<UL>
+<LI><A href="http://www.cisco.com/warp/public/707/16.html">Cisco</A>
+ IPsec information</LI>
+<LI>Ascend, now part of<A href="http://www.lucent.com/"> Lucent</A>,
+ have some IPsec-based products</LI>
+<LI><A href="http://www.nortelnetworks.com/">Bay Networks</A>, now part
+ of Nortel, use IPsec in their Contivity switch product line</LI>
+<LI><A href="http://www.3com.com/products/enterprise.html">3Com</A> have
+ a number of VPN products, some using IPsec</LI>
+</UL>
+<H3><A name="fw.web">IPsec in firewall products</A></H3>
+<P>Many firewall vendors offer IPsec, either as a standard part of their
+ product, or an optional extra. A few we know about are:</P>
+<UL>
+<LI><A href="http://www.borderware.com/">Borderware</A></LI>
+<LI><A href="http://www.ashleylaurent.com/vpn/ipsec_vpn.htm">Ashley
+ Laurent</A></LI>
+<LI><A href="http://www.watchguard.com">Watchguard</A></LI>
+<LI><A href="http://www.fx.dk/firewall/ipsec.html">Injoy</A> for OS/2</LI>
+</UL>
+<P>Vendors using FreeS/WAN in turnkey firewall products are listed in
+ our<A href="#turnkey"> introduction</A>.</P>
+<H3><A name="ipsecos">Operating systems with IPsec support</A></H3>
+<P>All the major open source operating systems support IPsec. See below
+ for details on<A href="#BSD"> BSD-derived</A> Unix variants.</P>
+<P>Among commercial OS vendors, IPsec players include:</P>
+<UL>
+<LI><A href="http://msdn.microsoft.com/isapi/msdnlib.idc?theURL=/library/backgrnd/html/msdn_ip_security.htm">
+Microsoft</A> have put IPsec in their Windows 2000 and XP products</LI>
+<LI><A href="http://www.s390.ibm.com/stories/1999/os390v2r8_pr.html">IBM</A>
+ announce a release of OS390 with IPsec support via a crypto
+ co-processor</LI>
+<LI><A href="http://www.sun.com/solaris/ds/ds-security/ds-security.pdf">
+Sun</A> include IPsec in Solaris 8</LI>
+<LI><A href="http://www.hp.com/security/products/extranet-security.html">
+Hewlett Packard</A> offer IPsec for their Unix machines</LI>
+<LI>Certicom have IPsec available for the<A href="http://www.certicom.com/products/movian/movianvpn_tech.html">
+ Palm</A>.</LI>
+<LI>There were reports before the release that Apple's Mac OS X would
+ have IPsec support built in, but it did not seem to be there when we
+ last checked. If you find, it please let us know via the<A href="mail.html">
+ mailing list</A>.</LI>
+</UL>
+<H3><A NAME="29_3_5">IPsec on network cards</A></H3>
+<P>Network cards with built-in IPsec acceleration are available from at
+ least Intel, 3Com and Redcreek.</P>
+<H3><A name="opensource">Open source IPsec implementations</A></H3>
+<H4><A name="linuxipsec">Other Linux IPsec implementations</A></H4>
+<P>We like to think of FreeS/WAN as<EM> the</EM> Linux IPsec
+ implementation, but it is not the only one. Others we know of are:</P>
+<UL>
+<LI><A href="http://www.enst.fr/~beyssac/pipsec/">pipsecd</A>, a
+ lightweight implementation of IPsec for Linux. Does not require kernel
+ recompilation.</LI>
+<LI>Petr Novak's<A href="ftp://ftp.eunet.cz/icz/ipnsec/"> ipnsec</A>,
+ based on the OpenBSD IPsec code and using<A href="#photuris"> Photuris</A>
+ for key management</LI>
+<LI>A now defunct project at<A href="http://www.cs.arizona.edu/security/hpcc-blue/linux.html">
+ U of Arizona</A> (export controlled)</LI>
+<LI><A href="http://snad.ncsl.nist.gov/cerberus">NIST Cerebus</A>
+ (export controlled)</LI>
+</UL>
+<H4><A name="BSD">IPsec for BSD Unix</A></H4>
+<UL>
+<LI><A href="http://www.kame.net/project-overview.html">KAME</A>,
+ several large Japanese companies co-operating on IPv6 and IPsec</LI>
+<LI><A href="http://web.mit.edu/network/isakmp">US Naval Research Lab</A>
+ implementation of IPv6 and of IPsec for IPv4 (export controlled)</LI>
+<LI><A href="http://www.openbsd.org">OpenBSD</A> includes IPsec as a
+ standard part of the distribution</LI>
+<LI><A href="http://www.r4k.net/ipsec">IPsec for FreeBSD</A></LI>
+<LI>a<A href="http://www.netbsd.org/Documentation/network/ipsec/"> FAQ</A>
+ on NetBSD's IPsec implementation</LI>
+</UL>
+<H4><A name="misc">IPsec for other systems</A></H4>
+<UL>
+<LI><A href="http://www.tcm.hut.fi/Tutkimus/IPSEC/">Helsinki U of
+ Technolgy</A> have implemented IPsec for Solaris, Java and Macintosh</LI>
+</UL>
+<H3><A name="interop.web">Interoperability</A></H3>
+<P>The IPsec protocols are designed so that different implementations
+ should be able to work together. As they say &quot;the devil is in the
+ details&quot;. IPsec has a lot of details, but considerable success has been
+ achieved.</P>
+<H4><A name="result">Interoperability results</A></H4>
+<P>Linux FreeS/WAN has been tested for interoperability with many other
+ IPsec implementations. Results to date are in our<A href="interop.html">
+ interoperability</A> section.</P>
+<P>Various other sites have information on interoperability between
+ various IPsec implementations:</P>
+<UL>
+<LI><A href="http://www.opus1.com/vpn/atl99display.html">interop results</A>
+ from a bakeoff in Atlanta, September 1999.</LI>
+<LI>a French company, HSC's,<A href="http://www.hsc.fr/ressources/presentations/ipsec99/index.html.en">
+ interoperability</A> test data covers FreeS/WAN, Open BSD, KAME, Linux
+ pipsecd, Checkpoint, Red Creek Ravlin, and Cisco IOS</LI>
+<LI><A href="http://www.icsa.net/">ICSA</A> offer certification programs
+ for various security-related products. See their list of<A href="http://www.icsa.net/html/communities/ipsec/certification/certified_products/index.shtml">
+ certified IPsec</A> products. Linux FreeS/WAN is not currently on that
+ list, but several products with which we interoperate are.</LI>
+<LI>VPNC have a page on why they are not yet doing<A href="http://www.vpnc.org/interop.html">
+ interoperability</A> testing and a page on the<A href="http://www.vpnc.org/conformance.html">
+ spec conformance</A> testing that they are doing</LI>
+<LI>a<A href="http://www.commweb.com/article/COM20000912S0009"> review</A>
+ comparing a dozen commercial IPsec implemetations. Unfortunately, the
+ reviewers did not look at Open Source implementations such as FreeS/WAN
+ or OpenBSD.</LI>
+<LI><A href="http://www.tanu.org/~sakane/doc/public/report-ike-interop0007.html">
+results</A> from interoperability tests at a conference. FreeS/WAN was
+ not tested there.</LI>
+<LI>test results from the<A href="http://www.hsc.fr/ressources/veille/ipsec/ipsec2000/">
+ IPSEC 2000</A> conference</LI>
+</UL>
+<H4><A name="test1">Interoperability test sites</A></H4>
+<UL>
+<LI><A href="http://www.tahi.org/">TAHI</A>, a Japanese IPv6 testing
+ project with free IPsec validation software</LI>
+<LI><A href="http://ipsec-wit.antd.nist.gov">National Institute of
+ Standards and Technology</A></LI>
+<LI><A href="http://isakmp-test.ssh.fi/">SSH Communications Security</A></LI>
+</UL>
+<H2><A name="linux.link">Linux links</A></H2>
+<H3><A name="linux.basic">Basic and tutorial Linux information</A></H3>
+<UL>
+<LI>Linux<A href="http://linuxcentral.com/linux/LDP/LDP/gs/gs.html">
+ Getting Started</A> HOWTO document</LI>
+<LI>A getting started guide from the<A href="http://darkwing.uoregon.edu/~cchome/linuxgettingstarted.html">
+ U of Oregon</A></LI>
+<LI>A large<A href="http://www.herring.org/techie.html"> link collection</A>
+ which includes a lot of introductory and tutorial material on Unix,
+ Linux, the net, . . .</LI>
+</UL>
+<H3><A name="general">General Linux sites</A></H3>
+<UL>
+<LI><A href="http://www.freshmeat.net">Freshmeat</A> Linux news</LI>
+<LI><A href="http://slashdot.org">Slashdot</A> &quot;News for Nerds&quot;</LI>
+<LI><A href="http://www.linux.org">Linux Online</A></LI>
+<LI><A href="http://www.linuxhq.com">Linux HQ</A></LI>
+<LI><A href="http://www.tux.org">tux.org</A></LI>
+</UL>
+<H3><A name="docs.ldp">Documentation</A></H3>
+<P>Nearly any Linux documentation you are likely to want can be found at
+ the<A href="http://metalab.unc.edu/LDP"> Linux Documentation Project</A>
+ or LDP.</P>
+<UL>
+<LI><A href="http://metalab.unc.edu/LDP/HOWTO/META-FAQ.html">Meta-FAQ</A>
+ guide to Linux information sources</LI>
+<LI>The LDP's HowTo documents are a standard Linux reference. See this<A href="http://www.linuxdoc.org/docs.html#howto">
+ list</A>. Documents there most relevant to a FreeS/WAN gateway are:
+<UL>
+<LI><A href="http://metalab.unc.edu/LDP/HOWTO/Kernel-HOWTO.html">Kernel
+ HOWTO</A></LI>
+<LI><A href="http://metalab.unc.edu/LDP/HOWTO/Networking-Overview-HOWTO.html">
+Networking Overview HOWTO</A></LI>
+<LI><A href="http://metalab.unc.edu/LDP/HOWTO/Security-HOWTO.html">
+Security HOWTO</A></LI>
+</UL>
+</LI>
+<LI>The LDP do a series of Guides, book-sized publications with more
+ detail (and often more &quot;why do it this way?&quot;) than the HowTos. See this<A
+href="http://www.linuxdoc.org/guides.html"> list</A>. Documents there
+ most relevant to a FreeS/WAN gateway are:
+<UL>
+<LI><A href="http://www.tml.hut.fi/~viu/linux/sag/">System
+ Administrator's Guide</A></LI>
+<LI><A href="http://www.linuxdoc.org/LDP/nag2/index.html">Network
+ Adminstrator's Guide</A></LI>
+<LI><A href="http://www.seifried.org/lasg/">Linux Administrator's
+ Security Guide</A></LI>
+</UL>
+</LI>
+</UL>
+<P>You may not need to go to the LDP to get this material. Most Linux
+ distributions include the HowTos on their CDs and several include the
+ Guides as well. Also, most of the Guides and some collections of HowTos
+ are available in book form from various publishers.</P>
+<P>Much of the LDP material is also available in languages other than
+ English. See this<A href="http://www.linuxdoc.org/links/nenglish.html">
+ LDP page</A>.</P>
+<H3><A name="advroute.web">Advanced routing</A></H3>
+<P>The Linux IP stack has some new features in 2.4 kernels. Some HowTos
+ have been written:</P>
+<UL>
+<LI>several HowTos for the<A href="http://netfilter.samba.org/unreliable-guides/">
+ netfilter</A> firewall code in newer kernels</LI>
+<LI><A href="http://www.ds9a.nl/2.4Networking/HOWTO//cvs/2.4routing/output/2.4networking.html">
+2.4 networking</A> HowTo</LI>
+<LI><A href="http://www.ds9a.nl/2.4Networking/HOWTO//cvs/2.4routing/output/2.4routing.html">
+2.4 routing</A> HowTo</LI>
+</UL>
+<H3><A name="linsec">Security for Linux</A></H3>
+<P>See also the<A href="#docs.ldp"> LDP material</A> above.</P>
+<UL>
+<LI><A href="http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos">
+Trinity OS guide to setting up Linux</A></LI>
+<LI><A href="http://www.deter.com/unix">Unix security</A> page</LI>
+<LI><A href="http://linux01.gwdg.de/~alatham/">PPDD</A> encrypting
+ filesystem</LI>
+<LI><A href="http://EncryptionHOWTO.sourceforge.net/">Linux Encryption
+ HowTo</A> (outdated when last checked, had an Oct 2000 revision date in
+ March 2002)</LI>
+</UL>
+<H3><A name="firewall.linux">Linux firewalls</A></H3>
+<P>Our<A href="firewall.html"> FreeS/WAN and firewalls</A> document
+ includes links to several sets of<A href="#examplefw"> scripts</A>
+ known to work with FreeS/WAN.</P>
+<P>Other information sources:</P>
+<UL>
+<LI><A href="http://ipmasq.cjb.net/">IP Masquerade resource page</A></LI>
+<LI><A href="http://netfilter.samba.org/unreliable-guides/">netfilter</A>
+ firewall code in 2.4 kernels</LI>
+<LI>Our list of general<A href="#firewall.web"> firewall references</A>
+ on the web</LI>
+<LI><A href="http://users.dhp.com/~whisper/mason/">Mason</A>, a tool for
+ automatically configuring Linux firewalls</LI>
+<LI>the web cache software<A href="http://www.squid-cache.org/"> squid</A>
+ and<A href="http://www.squidguard.org/"> squidguard</A> which turns
+ Squid into a filtering web proxy</LI>
+</UL>
+<H3><A name="linux.misc">Miscellaneous Linux information</A></H3>
+<UL>
+<LI><A href="http://lwn.net/current/dists.php3">Linux distribution
+ vendors</A></LI>
+<LI><A href="http://www.linux.org/groups/">Linux User Groups</A></LI>
+</UL>
+<H2><A name="crypto.link">Crypto and security links</A></H2>
+<H3><A name="security">Crypto and security resources</A></H3>
+<H4><A name="std.links">The standard link collections</A></H4>
+<P>Two enormous collections of links, each the standard reference in its
+ area:</P>
+<DL>
+<DT>Gene Spafford's<A href="http://www.cerias.purdue.edu/coast/hotlist/">
+ COAST hotlist</A></DT>
+<DD>Computer and network security.</DD>
+<DT>Peter Gutmann's<A href="http://www.cs.auckland.ac.nz/~pgut001/links.html">
+ Encryption and Security-related Resources</A></DT>
+<DD>Cryptography.</DD>
+</DL>
+<H4><A name="FAQ">Frequently Asked Question (FAQ) documents</A></H4>
+<UL>
+<LI><A href="http://www.faqs.org/faqs/cryptography-faq/">Cryptography
+ FAQ</A></LI>
+<LI><A href="http://www.interhack.net/pubs/fwfaq">Firewall FAQ</A></LI>
+<LI><A href="http://www.whitefang.com/sup/secure-faq.html">Secure Unix
+ Programming FAQ</A></LI>
+<LI>FAQs for specific programs are listed in the<A href="#tools"> tools</A>
+ section below.</LI>
+</UL>
+<H4><A name="cryptover">Tutorials</A></H4>
+<UL>
+<LI>Gary Kessler's<A href="http://www.garykessler.net/library/crypto.html">
+ Overview of Cryptography</A></LI>
+<LI>Terry Ritter's<A href="http://www.ciphersbyritter.com/LEARNING.HTM">
+ introduction</A></LI>
+<LI>Peter Gutman's<A href="http://www.cs.auckland.ac.nz/~pgut001/tutorial/index.html">
+ cryptography</A> tutorial (500 slides in PDF format)</LI>
+<LI>Amir Herzberg of IBM's sildes for his course<A href="http://www.hrl.il.ibm.com/mpay/course.html">
+ Introduction to Cryptography and Electronic Commerce</A></LI>
+<LI>the<A href="http://www.gnupg.org/gph/en/manual/c173.html"> concepts
+ section</A> of the<A href="#GPG"> GNU Privacy Guard</A> documentation</LI>
+<LI>Bruce Schneier's self-study<A href="http://www.counterpane.com/self-study.html">
+ cryptanalysis</A> course</LI>
+</UL>
+<P>See also the<A href="#interesting"> interesting papers</A> section
+ below.</P>
+<H4><A name="standards">Crypto and security standards</A></H4>
+<UL>
+<LI><A href="http://csrc.nist.gov/cc">Common Criteria</A>, new
+ international computer and network security standards to replace the
+ &quot;Rainbow&quot; series</LI>
+<LI>AES<A href="http://csrc.nist.gov/encryption/aes/aes_home.htm">
+ Advanced Encryption Standard</A> which will replace DES</LI>
+<LI><A href="http://grouper.ieee.org/groups/1363">IEEE P-1363 public key
+ standard</A></LI>
+<LI>our collection of links for the<A href="#ipsec.link"> IPsec</A>
+ standards</LI>
+<LI>history of<A href="http://www.visi.com/crypto/evalhist/index.html">
+ formal evaluation</A> of security policies and implementation</LI>
+</UL>
+<H4><A name="quotes">Crypto quotes</A></H4>
+<P>There are several collections of cryptographic quotes on the net:</P>
+<UL>
+<LI><A href="http://www.eff.org/pub/EFF/quotes.eff">the EFF</A></LI>
+<LI><A href="http://www.samsimpson.com/cquotes.php">Sam Simpson</A></LI>
+<LI><A href="http://www.amk.ca/quotations/cryptography/page-1.html">AM
+ Kutchling</A></LI>
+</UL>
+<H3><A name="policy">Cryptography law and policy</A></H3>
+<H4><A name="legal">Surveys of crypto law</A></H4>
+<UL>
+<LI>International survey of<A href="http://cwis.kub.nl/~FRW/PEOPLE/koops/lawsurvy.htm">
+ crypto law</A>.</LI>
+<LI>International survey of<A href="http://rechten.kub.nl/simone/ds-lawsu.htm">
+ digital signature law</A></LI>
+</UL>
+<H4><A name="oppose">Organisations opposing crypto restrictions</A></H4>
+<UL>
+<LI>The<A href="#EFF"> EFF</A>'s archives on<A href="http://www.eff.org/pub/Privacy/">
+ privacy</A> and<A href="http://www.eff.org/pub/Privacy/ITAR_export/">
+ export control</A>.</LI>
+<LI><A href="http://www.gilc.org">Global Internet Liberty Campaign</A></LI>
+<LI><A href="http://www.cdt.org/crypto">Center for Democracy and
+ Technology</A></LI>
+<LI><A href="http://www.privacyinternational.org/">Privacy International</A>
+, who give out<A href="http://www.bigbrotherawards.org/"> Big Brother
+ Awards</A> to snoopy organisations</LI>
+</UL>
+<H4><A name="other.policy">Other information on crypto policy</A></H4>
+<UL>
+<LI><A href="ftp://ftp.isi.edu/in-notes/rfc1984.txt">RFC 1984</A>, the<A href="#IAB">
+ IAB</A> and<A href="#IESG"> IESG</A> Statement on Cryptographic
+ Technology and the Internet.</LI>
+<LI>John Young's collection of<A href="http://cryptome.org/"> documents</A>
+ of interest to the cryptography, open government and privacy movements,
+ organized chronologically</LI>
+<LI>AT&amp;T researcher Matt Blaze's Encryption, Privacy and Security<A href="http://www.crypto.com">
+ Resource Page</A></LI>
+<LI>A good<A href="http://cryptome.org/crypto97-ne.htm"> overview</A> of
+ the issues from Australia.</LI>
+</UL>
+<P>See also our documentation section on the<A href="politics.html">
+ history and politics</A> of cryptography.</P>
+<H3><A name="crypto.tech">Cryptography technical information</A></H3>
+<H4><A name="cryptolinks">Collections of crypto links</A></H4>
+<UL>
+<LI><A href="http://www.counterpane.com/hotlist.html">Counterpane</A></LI>
+<LI><A href="http://www.cs.auckland.ac.nz/~pgut001/links.html">Peter
+ Gutman's links</A></LI>
+<LI><A href="http://www.pca.dfn.de/eng/team/ske/pem-dok.html">PKI links</A>
+</LI>
+<LI><A href="http://crypto.yashy.com/www/">Robert Guerra's links</A></LI>
+</UL>
+<H4><A name="papers">Lists of online cryptography papers</A></H4>
+<UL>
+<LI><A href="http://www.counterpane.com/biblio">Counterpane</A></LI>
+<LI><A href="http://www.cryptography.com/resources/papers">
+cryptography.com</A></LI>
+<LI><A href="http://www.cryptosoft.com/html/secpub.htm">Cryptosoft</A></LI>
+</UL>
+<H4><A name="interesting">Particularly interesting papers</A></H4>
+<P>These papers emphasize important issues around the use of
+ cryptography, and the design and management of secure systems.</P>
+<UL>
+<LI><A href="http://www.counterpane.com/keylength.html">Key length
+ requirements for security</A></LI>
+<LI><A href="http://www.cl.cam.ac.uk/users/rja14/wcf.html">Why
+ Cryptosystems Fail</A></LI>
+<LI><A href="http://www.cdt.org/crypto/risks98/">Risks of escrowed
+ encryption</A></LI>
+<LI><A href="http://www.counterpane.com/pitfalls.html">Security pitfalls
+ in cryptography</A></LI>
+<LI><A href="http://www.acm.org/classics/sep95">Reflections on Trusting
+ Trust</A>, Ken Thompson on Trojan horse design</LI>
+<LI><A href="http://www.apache-ssl.org/disclosure.pdf">Security against
+ Compelled Disclosure</A>, how to maintain privacy in the face of legal
+ or other coersion</LI>
+</UL>
+<H3><A name="compsec">Computer and network security</A></H3>
+<H4><A name="seclink">Security links</A></H4>
+<UL>
+<LI><A href="http://www.cs.purdue.edu/coast/hotlist">COAST Hotlist</A></LI>
+<LI>DMOZ open directory project<A href="http://dmoz.org/Computers/Security/">
+ computer security</A> links</LI>
+<LI><A href="http://www-cse.ucsd.edu/users/bsy/sec.html">Bennet Yee</A></LI>
+<LI>Mike Fuhr's<A href="http://www.fuhr.org/~mfuhr/computers/security.html">
+ link collection</A></LI>
+<LI><A href="http://www.networkintrusion.co.uk/">links</A> with an
+ emphasis on intrusion detection</LI>
+</UL>
+<H4><A name="firewall.web">Firewall links</A></H4>
+<UL>
+<LI><A href="http://www.cs.purdue.edu/coast/firewalls">COAST firewalls</A>
+</LI>
+<LI><A href="http://www.zeuros.co.uk">Firewalls Resource page</A></LI>
+</UL>
+<H4><A name="vpn">VPN links</A></H4>
+<UL>
+<LI><A href="http://www.vpnc.org">VPN Consortium</A></LI>
+<LI>First VPN's<A href="http://www.firstvpn.com/research/rhome.html">
+ white paper</A> collection</LI>
+</UL>
+<H4><A name="tools">Security tools</A></H4>
+<UL>
+<LI>PGP -- mail encryption
+<UL>
+<LI><A href="http://www.pgp.com/">PGP Inc.</A> (part of NAI) for
+ commercial versions</LI>
+<LI><A href="http://web.mit.edu/network/pgp.html">MIT</A> distributes
+ the NAI product for non-commercial use</LI>
+<LI><A href="http://www.pgpi.org/">international</A> distribution site</LI>
+<LI><A href="http://gnupg.org">GNU Privacy Guard (GPG)</A></LI>
+<LI><A href="http://www.dk.pgp.net/pgpnet/pgp-faq/">PGP FAQ</A></LI>
+</UL>
+ A message in our mailing list archive has considerable detail on<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00029.html">
+ available versions</A> of PGP and on IPsec support in them.
+<P><STRONG>Note:</STRONG> A fairly nasty bug exists in all commercial
+ PGP versions from 5.5 through 6.5.3. If you have one of those,<STRONG>
+ upgrade now</STRONG>.</P>
+</LI>
+<LI>SSH -- secure remote login
+<UL>
+<LI><A href="http://www.ssh.fi">SSH Communications Security</A>, for the
+ original software. It is free for trial, academic and non-commercial
+ use.</LI>
+<LI><A href="http://www.openssh.com/">Open SSH</A>, the Open BSD team's
+ free replacement</LI>
+<LI><A href="http://www.freessh.org/">freessh.org</A>, links to free
+ implementations for many systems</LI>
+<LI><A href="http://www.uni-karlsruhe.de/~ig25/ssh-faq">SSH FAQ</A></LI>
+<LI><A href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">Putty</A>
+, an SSH client for Windows</LI>
+</UL>
+</LI>
+<LI>Tripwire saves message digests of your system files. Re-calculate
+ the digests and compare to saved values to detect any file changes.
+ There are several versions available:
+<UL>
+<LI><A href="http://www.tripwiresecurity.com/">commercial version</A></LI>
+<LI><A href="http://www.tripwire.org/">Open Source</A></LI>
+</UL>
+</LI>
+<LI><A href="http://www.snort.org">Snort</A> and<A href="http://www.lids.org">
+ LIDS</A> are intrusion detection system for Linux</LI>
+<LI><A href="http://www.fish.com/~zen/satan/satan.html">SATAN</A> System
+ Administrators Tool for Analysing Networks</LI>
+<LI><A href="http://www.insecure.org/nmap/">NMAP</A> Network Mapper</LI>
+<LI><A href="ftp://ftp.porcupine.org/pub/security/index.html">Wietse
+ Venema's page</A> with various tools</LI>
+<LI><A href="http://ita.ee.lbl.gov/index.html">Internet Traffic Archive</A>
+, various tools to analyze network traffic, mostly scripts to organise
+ and format tcpdump(8) output for specific purposes</LI>
+<LI><A name="ssmail">ssmail -- sendmail patched to do</A><A href="#carpediem">
+ opportunistic encryption</A>
+<UL>
+<LI><A href="http://www.home.aone.net.au/qualcomm/">web page</A> with
+ links to code and to a Usenix paper describing it, in PDF</LI>
+</UL>
+</LI>
+<LI><A href="http://www.openca.org/">Open CA</A> project to develop a
+ freely distributed<A href="#CA"> Certification Authority</A> for
+ building a open<A href="#PKI"> Public Key Infrastructure</A>.</LI>
+</UL>
+<H3><A name="people">Links to home pages</A></H3>
+<P>David Wagner at Berkeley provides a set of links to<A href="http://www.cs.berkeley.edu/~daw/people/crypto.html">
+ home pages</A> of cryptographers, cypherpunks and computer security
+ people.</P>
+<HR>
+<H1><A name="ourgloss">Glossary for the Linux FreeS/WAN project</A></H1>
+<P>Entries are in alphabetical order. Some entries are only one line or
+ one paragraph long. Others run to several paragraphs. I have tried to
+ put the essential information in the first paragraph so you can skip
+ the other paragraphs if that seems appropriate.</P>
+<HR>
+<H2><A name="jump">Jump to a letter in the glossary</A></H2>
+<CENTER> <BIG><B><A href="#0">numeric</A><A href="#A"> A</A><A href="#B">
+ B</A><A href="#C"> C</A><A href="#D"> D</A><A href="#E"> E</A><A href="#F">
+ F</A><A href="#G"> G</A><A href="#H"> H</A><A href="#I"> I</A><A href="#J">
+ J</A><A href="#K"> K</A><A href="#L"> L</A><A href="#M"> M</A><A href="#N">
+ N</A><A href="#O"> O</A><A href="#P"> P</A><A href="#Q"> Q</A><A href="#R">
+ R</A><A href="#S"> S</A><A href="#T"> T</A><A href="#U"> U</A><A href="#V">
+ V</A><A href="#W"> W</A><A href="#X"> X</A><A href="#Y"> Y</A><A href="#Z">
+ Z</A></B></BIG></CENTER>
+<HR>
+<H2><A name="gloss">Other glossaries</A></H2>
+<P>Other glossaries which overlap this one include:</P>
+<UL>
+<LI>The VPN Consortium's glossary of<A href="http://www.vpnc.org/terms.html">
+ VPN terms</A>.</LI>
+<LI>glossary portion of the<A href="http://www.rsa.com/rsalabs/faq/B.html">
+ Cryptography FAQ</A></LI>
+<LI>an extensive crytographic glossary on<A href="http://www.ciphersbyritter.com/GLOSSARY.HTM">
+ Terry Ritter's</A> page.</LI>
+<LI>The<A href="#NSA"> NSA</A>'s<A href="http://www.sans.org/newlook/resources/glossary.htm">
+ glossary of computer security</A> on the<A href="http://www.sans.org">
+ SANS Institute</A> site.</LI>
+<LI>a small glossary for Internet Security at<A href="http://www5.zdnet.com/pcmag/pctech/content/special/glossaries/internetsecurity.html">
+ PC magazine</A></LI>
+<LI>The<A href="http://www.visi.com/crypto/inet-crypto/glossary.html">
+ glossary</A> from Richard Smith's book<A href="#Smith"> Internet
+ Cryptography</A></LI>
+</UL>
+<P>Several Internet glossaries are available as RFCs:</P>
+<UL>
+<LI><A href="http://www.rfc-editor.org/rfc/rfc1208.txt">Glossary of
+ Networking Terms</A></LI>
+<LI><A href="http://www.rfc-editor.org/rfc/rfc1983.txt">Internet User's
+ Glossary</A></LI>
+<LI><A href="http://www.rfc-editor.org/rfc/rfc2828.txt">Internet
+ Security Glossary</A></LI>
+</UL>
+<P>More general glossary or dictionary information:</P>
+<UL>
+<LI>Free Online Dictionary of Computing (FOLDOC)
+<UL>
+<LI><A href="http://www.nightflight.com/foldoc">North America</A></LI>
+<LI><A href="http://wombat.doc.ic.ac.uk/foldoc/index.html">Europe</A></LI>
+<LI><A href="http://www.nue.org/foldoc/index.html">Japan</A></LI>
+</UL>
+<P>There are many more mirrors of this dictionary.</P>
+</LI>
+<LI>The Jargon File, the definitive resource for hacker slang and
+ folklore
+<UL>
+<LI><A href="http://www.netmeg.net/jargon">North America</A></LI>
+<LI><A href="http://info.wins.uva.nl/~mes/jargon/">Holland</A></LI>
+<LI><A href="http://www.tuxedo.org/~esr/jargon">home page</A></LI>
+</UL>
+<P>There are also many mirrors of this. See the home page for a list.</P>
+</LI>
+<LI>A general<A href="http://www.trinity.edu/~rjensen/245glosf.htm#Navigate">
+ technology glossary</A></LI>
+<LI>An<A href="http://www.yourdictionary.com/"> online dictionary
+ resource page</A> with pointers to many dictionaries for many languages</LI>
+<LI>A<A href="http://www.onelook.com/"> search engine</A> that accesses
+ several hundred online dictionaries</LI>
+<LI>O'Reilly<A href="http://www.ora.com/reference/dictionary/">
+ Dictionary of PC Hardware and Data Communications Terms</A></LI>
+<LI><A href="http://www.FreeSoft.org/CIE/index.htm">Connected</A>
+ Internet encyclopedia</LI>
+<LI><A href="http://www.whatis.com/">whatis.com</A></LI>
+</UL>
+<HR>
+<H2><A name="definitions">Definitions</A></H2>
+<DL>
+<DT><A name="0">0</A></DT>
+<DT><A name="3DES">3DES (Triple DES)</A></DT>
+<DD>Using three<A href="#DES"> DES</A> encryptions on a single data
+ block, with at least two different keys, to get higher security than is
+ available from a single DES pass. The three-key version of 3DES is the
+ default encryption algorithm for<A href="#FreeSWAN"> Linux FreeS/WAN</A>
+.
+<P><A href="#IPSEC">IPsec</A> always does 3DES with three different
+ keys, as required by RFC 2451. For an explanation of the two-key
+ variant, see<A href="#2key"> two key triple DES</A>. Both use an<A href="#EDE">
+ EDE</A> encrypt-decrypt-encrpyt sequence of operations.</P>
+<P>Single<A href="#DES"> DES</A> is<A href="#desnotsecure"> insecure</A>
+.</P>
+<P>Double DES is ineffective. Using two 56-bit keys, one might expect an
+ attacker to have to do 2<SUP>112</SUP> work to break it. In fact, only
+ 2<SUP>57</SUP> work is required with a<A href="#meet">
+ meet-in-the-middle attack</A>, though a large amount of memory is also
+ required. Triple DES is vulnerable to a similar attack, but that just
+ reduces the work factor from the 2<SUP>168</SUP> one might expect to 2<SUP>
+112</SUP>. That provides adequate protection against<A href="#brute">
+ brute force</A> attacks, and no better attack is known.</P>
+<P>3DES can be somewhat slow compared to other ciphers. It requires
+ three DES encryptions per block. DES was designed for hardware
+ implementation and includes some operations which are difficult in
+ software. However, the speed we get is quite acceptable for many uses.
+ See our<A href="performance.html"> performance</A> document for
+ details.</P>
+</DD>
+<DT><A name="A">A</A></DT>
+<DT><A name="active">Active attack</A></DT>
+<DD>An attack in which the attacker does not merely eavesdrop (see<A href="#passive">
+ passive attack</A>) but takes action to change, delete, reroute, add,
+ forge or divert data. Perhaps the best-known active attack is<A href="#middle">
+ man-in-the-middle</A>. In general,<A href="#authentication">
+ authentication</A> is a useful defense against active attacks.</DD>
+<DT><A name="AES">AES</A></DT>
+<DD>The<B> A</B>dvanced<B> E</B>ncryption<B> S</B>tandard -- a new<A href="#block">
+ block cipher</A> standard to replace<A href="#desnotsecure"> DES</A> --
+ developed by<A href="#NIST"> NIST</A>, the US National Institute of
+ Standards and Technology. DES used 64-bit blocks and a 56-bit key. AES
+ ciphers use a 128-bit block and 128, 192 or 256-bit keys. The larger
+ block size helps resist<A href="#birthday"> birthday attacks</A> while
+ the large key size prevents<A href="#brute"> brute force attacks</A>.
+<P>Fifteen proposals meeting NIST's basic criteria were submitted in
+ 1998 and subjected to intense discussion and analysis, &quot;round one&quot;
+ evaluation. In August 1999, NIST narrowed the field to five &quot;round two&quot;
+ candidates:</P>
+<UL>
+<LI><A href="http://www.research.ibm.com/security/mars.html">Mars</A>
+ from IBM</LI>
+<LI><A href="http://www.rsa.com/rsalabs/aes/">RC6</A> from RSA</LI>
+<LI><A href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">Rijndael</A>
+ from two Belgian researchers</LI>
+<LI><A href="http://www.cl.cam.ac.uk/~rja14/serpent.html">Serpent</A>, a
+ British-Norwegian-Israeli collaboration</LI>
+<LI><A href="http://www.counterpane.com/twofish.html">Twofish</A> from
+ the consulting firm<A href="http://www.counterpane.com"> Counterpane</A>
+</LI>
+</UL>
+<P>Three of the five finalists -- Rijndael, Serpent and Twofish -- have
+ completely open licenses.</P>
+<P>In October 2000, NIST announced the winner -- Rijndael.</P>
+<P>For more information, see:</P>
+<UL>
+<LI>NIST's<A href="http://csrc.nist.gov/encryption/aes/aes_home.htm">
+ AES home page</A></LI>
+<LI>the Block Cipher Lounge<A href="http://www.ii.uib.no/~larsr/aes.html">
+ AES page</A></LI>
+<LI>Brian Gladman's<A href="http://fp.gladman.plus.com/cryptography_technology/index.htm">
+ code and benchmarks</A></LI>
+<LI>Helger Lipmaa's<A href="http://www.tcs.hut.fi/~helger/aes/"> survey
+ of implementations</A></LI>
+</UL>
+<P>AES will be added to a future release of<A href="#FreeSWAN"> Linux
+ FreeS/WAN</A>. Likely we will add all three of the finalists with good
+ licenses. User-written<A href="#patch"> AES patches</A> are already
+ available.</P>
+<P>Adding AES may also require adding stronger hashes,<A href="#SHA-256">
+ SHA-256, SHA-384 and SHA-512</A>.</P>
+</DD>
+<DT><A name="AH">AH</A></DT>
+<DD>The<A href="#IPSEC"> IPsec</A><B> A</B>uthentication<B> H</B>eader,
+ added after the IP header. For details, see our<A href="#AH.ipsec">
+ IPsec</A> document and/or RFC 2402.</DD>
+<DT><A name="alicebob">Alice and Bob</A></DT>
+<DD>A and B, the standard example users in writing on cryptography and
+ coding theory. Carol and Dave join them for protocols which require
+ more players.
+<P>Bruce Schneier extends these with many others such as Eve the
+ Eavesdropper and Victor the Verifier. His extensions seem to be in the
+ process of becoming standard as well. See page 23 of<A href="#schneier">
+ Applied Cryptography</A></P>
+<P>Alice and Bob have an amusing<A href="http://www.conceptlabs.co.uk/alicebob.html">
+ biography</A> on the web.</P>
+</DD>
+<DT>ARPA</DT>
+<DD>see<A href="#DARPA"> DARPA</A></DD>
+<DT><A name="ASIO">ASIO</A></DT>
+<DD>Australian Security Intelligence Organisation.</DD>
+<DT>Asymmetric cryptography</DT>
+<DD>See<A href="#public"> public key cryptography</A>.</DD>
+<DT><A name="authentication">Authentication</A></DT>
+<DD>Ensuring that a message originated from the expected sender and has
+ not been altered on route.<A href="#IPSEC"> IPsec</A> uses
+ authentication in two places:
+<UL>
+<LI>peer authentication, authenticating the players in<A href="#IKE">
+ IKE</A>'s<A href="#DH"> Diffie-Hellman</A> key exchanges to prevent<A href="#middle">
+ man-in-the-middle attacks</A>. This can be done in a number of ways.
+ The methods supported by FreeS/WAN are discussed in our<A href="#choose">
+ advanced configuration</A> document.</LI>
+<LI>packet authentication, authenticating packets on an established<A href="#SA">
+ SA</A>, either with a separate<A href="#AH"> authentication header</A>
+ or with the optional authentication in the<A href="#ESP"> ESP</A>
+ protocol. In either case, packet authentication uses a<A href="#HMAC">
+ hashed message athentication code</A> technique.</LI>
+</UL>
+<P>Outside IPsec, passwords are perhaps the most common authentication
+ mechanism. Their function is essentially to authenticate the person's
+ identity to the system. Passwords are generally only as secure as the
+ network they travel over. If you send a cleartext password over a
+ tapped phone line or over a network with a packet sniffer on it, the
+ security provided by that password becomes zero. Sending an encrypted
+ password is no better; the attacker merely records it and reuses it at
+ his convenience. This is called a<A href="#replay"> replay</A> attack.</P>
+<P>A common solution to this problem is a<A href="#challenge">
+ challenge-response</A> system. This defeats simple eavesdropping and
+ replay attacks. Of course an attacker might still try to break the
+ cryptographic algorithm used, or the<A href="#random"> random number</A>
+ generator.</P>
+</DD>
+<DT><A name="auto">Automatic keying</A></DT>
+<DD>A mode in which keys are automatically generated at connection
+ establisment and new keys automaically created periodically thereafter.
+ Contrast with<A href="#manual"> manual keying</A> in which a single
+ stored key is used.
+<P>IPsec uses the<A href="#DH"> Diffie-Hellman key exchange protocol</A>
+ to create keys. An<A href="#authentication"> authentication</A>
+ mechansim is required for this. FreeS/WAN normally uses<A href="#RSA">
+ RSA</A> for this. Other methods supported are discussed in our<A href="#choose">
+ advanced configuration</A> document.</P>
+<P>Having an attacker break the authentication is emphatically not a
+ good idea. An attacker that breaks authentication, and manages to
+ subvert some other network entities (DNS, routers or gateways), can use
+ a<A href="#middle"> man-in-the middle attack</A> to break the security
+ of your IPsec connections.</P>
+<P>However, having an attacker break the authentication in automatic
+ keying is not quite as bad as losing the key in manual keying.</P>
+<UL>
+<LI>An attacker who reads /etc/ipsec.conf and gets the keys for a
+ manually keyed connection can, without further effort, read all
+ messages encrypted with those keys, including any old messages he may
+ have archived.</LI>
+<LI>Automatic keying has a property called<A href="#PFS"> perfect
+ forward secrecy</A>. An attacker who breaks the authentication gets
+ none of the automatically generated keys and cannot immediately read
+ any messages. He has to mount a successful<A href="#middle">
+ man-in-the-middle attack</A> in real time before he can read anything.
+ He cannot read old archived messages at all and will not be able to
+ read any future messages not caught by man-in-the-middle tricks.</LI>
+</UL>
+<P>That said, the secrets used for authentication, stored in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A>, should still be protected as tightly as
+ cryptographic keys.</P>
+</DD>
+<DT><A name="B">B</A></DT>
+<DT><A href="http://www.nortelnetworks.com">Bay Networks</A></DT>
+<DD>A vendor of routers, hubs and related products, now a subsidiary of
+ Nortel. Interoperation between their IPsec products and Linux FreeS/WAN
+ was problematic at last report; see our<A href="interop.html#bay">
+ interoperation</A> section.</DD>
+<DT><A name="benchmarks">benchmarks</A></DT>
+<DD>Our default block cipher,<A href="#3DES"> triple DES</A>, is slower
+ than many alternate ciphers that might be used. Speeds achieved,
+ however, seem adequate for many purposes. For example, the assembler
+ code from the<A href="#LIBDES"> LIBDES</A> library we use encrypts 1.6
+ megabytes per second on a Pentium 200, according to the test program
+ supplied with the library.
+<P>For more detail, see our document on<A href="performance.html">
+ FreeS/WAN performance</A>.</P>
+</DD>
+<DT><A name="BIND">BIND</A></DT>
+<DD><B>B</B>erkeley<B> I</B>nternet<B> N</B>ame<B> D</B>aemon, a widely
+ used implementation of<A href="#DNS"> DNS</A> (Domain Name Service).
+ See our bibliography for a<A href="#DNS"> useful reference</A>. See the<A
+href="http://www.isc.org/bind.html"> BIND home page</A> for more
+ information and the latest version.</DD>
+<DT><A name="birthday">Birthday attack</A></DT>
+<DD>A cryptographic attack based on the mathematics exemplified by the<A href="#paradox">
+ birthday paradox</A>. This math turns up whenever the question of two
+ cryptographic operations producing the same result becomes an issue:
+<UL>
+<LI><A href="#collision">collisions</A> in<A href="#digest"> message
+ digest</A> functions.</LI>
+<LI>identical output blocks from a<A href="#block"> block cipher</A></LI>
+<LI>repetition of a challenge in a<A href="#challenge">
+ challenge-response</A> system</LI>
+</UL>
+<P>Resisting such attacks is part of the motivation for:</P>
+<UL>
+<LI>hash algorithms such as<A href="#SHA"> SHA</A> and<A href="#RIPEMD">
+ RIPEMD-160</A> giving a 160-bit result rather than the 128 bits of<A href="#MD4">
+ MD4</A>,<A href="#MD5"> MD5</A> and<A href="#RIPEMD"> RIPEMD-128</A>.</LI>
+<LI><A href="#AES">AES</A> block ciphers using a 128-bit block instead
+ of the 64-bit block of most current ciphers</LI>
+<LI><A href="#IPSEC">IPsec</A> using a 32-bit counter for packets sent
+ on an<A href="#auto"> automatically keyed</A><A href="#SA"> SA</A> and
+ requiring that the connection always be rekeyed before the counter
+ overflows.</LI>
+</UL>
+</DD>
+<DT><A name="paradox">Birthday paradox</A></DT>
+<DD>Not really a paradox, just a rather counter-intuitive mathematical
+ fact. In a group of 23 people, the chance of a least one pair having
+ the same birthday is over 50%.
+<P>The second person has 1 chance in 365 (ignoring leap years) of
+ matching the first. If they don't match, the third person's chances of
+ matching one of them are 2/365. The 4th, 3/365, and so on. The total of
+ these chances grows more quickly than one might guess.</P>
+</DD>
+<DT><A name="block">Block cipher</A></DT>
+<DD>A<A href="#symmetric"> symmetric cipher</A> which operates on
+ fixed-size blocks of plaintext, giving a block of ciphertext for each.
+ Contrast with<A href="#stream"> stream cipher</A>. Block ciphers can be
+ used in various<A href="#mode"> modes</A> when multiple block are to be
+ encrypted.
+<P><A href="#DES">DES</A> is among the the best known and widely used
+ block ciphers, but is now obsolete. Its 56-bit key size makes it<A href="#desnotsecure">
+ highly insecure</A> today.<A href="#3DES"> Triple DES</A> is the
+ default block cipher for<A href="#FreeSWAN"> Linux FreeS/WAN</A>.</P>
+<P>The current generation of block ciphers -- such as<A href="#Blowfish">
+ Blowfish</A>,<A href="#CAST128"> CAST-128</A> and<A href="#IDEA"> IDEA</A>
+ -- all use 64-bit blocks and 128-bit keys. The next generation,<A href="#AES">
+ AES</A>, uses 128-bit blocks and supports key sizes up to 256 bits.</P>
+<P>The<A href="http://www.ii.uib.no/~larsr/bc.html"> Block Cipher Lounge</A>
+ web site has more information.</P>
+</DD>
+<DT><A name="Blowfish">Blowfish</A></DT>
+<DD>A<A href="#block"> block cipher</A> using 64-bit blocks and keys of
+ up to 448 bits, designed by<A href="#schneier"> Bruce Schneier</A> and
+ used in several products.
+<P>This is not required by the<A href="#IPSEC"> IPsec</A> RFCs and not
+ currently used in<A href="#FreeSWAN"> Linux FreeS/WAN</A>.</P>
+</DD>
+<DT><A name="brute">Brute force attack (exhaustive search)</A></DT>
+<DD>Breaking a cipher by trying all possible keys. This is always
+ possible in theory (except against a<A href="#OTP"> one-time pad</A>),
+ but it becomes practical only if the key size is inadequate. For an
+ important example, see our document on the<A href="#desnotsecure">
+ insecurity of DES</A> with its 56-bit key. For an analysis of key sizes
+ required to resist plausible brute force attacks, see<A href="http://www.counterpane.com/keylength.html">
+ this paper</A>.
+<P>Longer keys protect against brute force attacks. Each extra bit in
+ the key doubles the number of possible keys and therefore doubles the
+ work a brute force attack must do. A large enough key defeats<STRONG>
+ any</STRONG> brute force attack.</P>
+<P>For example, the EFF's<A href="#EFF"> DES Cracker</A> searches a
+ 56-bit key space in an average of a few days. Let us assume an attacker
+ that can find a 64-bit key (256 times harder) by brute force search in
+ a second (a few hundred thousand times faster). For a 96-bit key, that
+ attacker needs 2<SUP>32</SUP> seconds, about 135 years. Against a
+ 128-bit key, he needs 2<SUP>32</SUP> times that, over 500,000,000,000
+ years. Your data is then obviously secure against brute force attacks.
+ Even if our estimate of the attacker's speed is off by a factor of a
+ million, it still takes him over 500,000 years to crack a message.</P>
+<P>This is why</P>
+<UL>
+<LI>single<A href="#DES"> DES</A> is now considered<A href="#desnotsecure">
+ dangerously insecure</A></LI>
+<LI>all of the current generation of<A href="#block"> block ciphers</A>
+ use a 128-bit or longer key</LI>
+<LI><A href="#AES">AES</A> ciphers support keysizes 128, 192 and 256
+ bits</LI>
+<LI>any cipher we add to Linux FreeS/WAN will have<EM> at least</EM> a
+ 128-bit key</LI>
+</UL>
+<P><STRONG>Cautions:</STRONG>
+<BR><EM> Inadequate keylength always indicates a weak cipher</EM> but it
+ is important to note that<EM> adequate keylength does not necessarily
+ indicate a strong cipher</EM>. There are many attacks other than brute
+ force, and adequate keylength<EM> only</EM> guarantees resistance to
+ brute force. Any cipher, whatever its key size, will be weak if design
+ or implementation flaws allow other attacks.</P>
+<P>Also,<EM> once you have adequate keylength</EM> (somewhere around 90
+ or 100 bits),<EM> adding more key bits make no practical difference</EM>
+, even against brute force. Consider our 128-bit example above that
+ takes 500,000,000,000 years to break by brute force. We really don't
+ care how many zeroes there are on the end of that, as long as the
+ number remains ridiculously large. That is, we don't care exactly how
+ large the key is as long as it is large enough.</P>
+<P>There may be reasons of convenience in the design of the cipher to
+ support larger keys. For example<A href="#Blowfish"> Blowfish</A>
+ allows up to 448 bits and<A href="#RC4"> RC4</A> up to 2048, but beyond
+ 100-odd bits it makes no difference to practical security.</P>
+</DD>
+<DT>Bureau of Export Administration</DT>
+<DD>see<A href="#BXA"> BXA</A></DD>
+<DT><A name="BXA">BXA</A></DT>
+<DD>The US Commerce Department's<B> B</B>ureau of E<B>x</B>port<B> A</B>
+dministration which administers the<A href="#EAR"> EAR</A> Export
+ Administration Regulations controling the export of, among other
+ things, cryptography.</DD>
+<DT><A name="C">C</A></DT>
+<DT><A name="CA">CA</A></DT>
+<DD><B>C</B>ertification<B> A</B>uthority, an entity in a<A href="#PKI">
+ public key infrastructure</A> that can certify keys by signing them.
+ Usually CAs form a hierarchy. The top of this hierarchy is called the<A href="#rootCA">
+ root CA</A>.
+<P>See<A href="#web"> Web of Trust</A> for an alternate model.</P>
+</DD>
+<DT><A name="CAST128">CAST-128</A></DT>
+<DD>A<A href="#block"> block cipher</A> using 64-bit blocks and 128-bit
+ keys, described in RFC 2144 and used in products such as<A href="#Entrust">
+ Entrust</A> and recent versions of<A href="#PGP"> PGP</A>.
+<P>This is not required by the<A href="#IPSEC"> IPsec</A> RFCs and not
+ currently used in<A href="#FreeSWAN"> Linux FreeS/WAN</A>.</P>
+</DD>
+<DT>CAST-256</DT>
+<DD><A href="#Entrust">Entrust</A>'s candidate cipher for the<A href="#AES">
+ AES standard</A>, largely based on the<A href="#CAST128"> CAST-128</A>
+ design.</DD>
+<DT><A name="CBC">CBC mode</A></DT>
+<DD><B>C</B>ipher<B> B</B>lock<B> C</B>haining<A href="#mode"> mode</A>,
+ a method of using a<A href="#block"> block cipher</A> in which for each
+ block except the first, the result of the previous encryption is XORed
+ into the new block before it is encrypted. CBC is the mode used in<A href="#IPSEC">
+ IPsec</A>.
+<P>An<A href="#IV"> initialisation vector</A> (IV) must be provided. It
+ is XORed into the first block before encryption. The IV need not be
+ secret but should be different for each message and unpredictable.</P>
+</DD>
+<DT><A name="CIDR">CIDR</A></DT>
+<DD><B>C</B>lassless<B> I</B>nter-<B>D</B>omain<B> R</B>outing, an
+ addressing scheme used to describe networks not restricted to the old
+ Class A, B, and C sizes. A CIDR block is written<VAR> address</VAR>/<VAR>
+mask</VAR>, where<VAR> address</VAR> is a 32-bit Internet address. The
+ first<VAR> mask</VAR> bits of<VAR> address</VAR> are part of the
+ gateway address, while the remaining bits designate other host
+ addresses. For example, the CIDR block 192.0.2.96/27 describes a
+ network with gateway 192.0.2.96, hosts 192.0.2.96 through 192.0.2.126
+ and broadcast 192.0.2.127.
+<P>FreeS/WAN policy group files accept CIDR blocks of the format<VAR>
+ address</VAR>/[<VAR>mask</VAR>], where<VAR> address</VAR> may take the
+ form<VAR> name.domain.tld</VAR>. An absent<VAR> mask</VAR> is assumed
+ to be /32.</P>
+</DD>
+<DT>Certification Authority</DT>
+<DD>see<A href="#CA"> CA</A></DD>
+<DT><A name="challenge">Challenge-response authentication</A></DT>
+<DD>An<A href="#authentication"> authentication</A> system in which one
+ player generates a<A href="#random"> random number</A>, encrypts it and
+ sends the result as a challenge. The other player decrypts and sends
+ back the result. If the result is correct, that proves to the first
+ player that the second player knew the appropriate secret, required for
+ the decryption. Variations on this technique exist using<A href="#public">
+ public key</A> or<A href="#symmetric"> symmetric</A> cryptography. Some
+ provide two-way authentication, assuring each player of the other's
+ identity.
+<P>This is more secure than passwords against two simple attacks:</P>
+<UL>
+<LI>If cleartext passwords are sent across the wire (e.g. for telnet),
+ an eavesdropper can grab them. The attacker may even be able to break
+ into other systems if the user has chosen the same password for them.</LI>
+<LI>If an encrypted password is sent, an attacker can record the
+ encrypted form and use it later. This is called a replay attack.</LI>
+</UL>
+<P>A challenge-response system never sends a password, either cleartext
+ or encrypted. An attacker cannot record the response to one challenge
+ and use it as a response to a later challenge. The random number is
+ different each time.</P>
+<P>Of course an attacker might still try to break the cryptographic
+ algorithm used, or the<A href="#random"> random number</A> generator.</P>
+</DD>
+<DT><A name="mode">Cipher Modes</A></DT>
+<DD>Different ways of using a block cipher when encrypting multiple
+ blocks.
+<P>Four standard modes were defined for<A href="#DES"> DES</A> in<A href="#FIPS">
+ FIPS</A> 81. They can actually be applied with any block cipher.</P>
+<TABLE><TBODY></TBODY>
+<TR><TD></TD><TD><A href="#ECB">ECB</A></TD><TD>Electronic CodeBook</TD><TD>
+encrypt each block independently</TD></TR>
+<TR><TD></TD><TD><A href="#CBC">CBC</A></TD><TD>Cipher Block Chaining
+<BR></TD><TD>XOR previous block ciphertext into new block plaintext
+ before encrypting new block</TD></TR>
+<TR><TD></TD><TD>CFB</TD><TD>Cipher FeedBack</TD><TD></TD></TR>
+<TR><TD></TD><TD>OFB</TD><TD>Output FeedBack</TD><TD></TD></TR>
+</TABLE>
+<P><A href="#IPSEC">IPsec</A> uses<A href="#CBC"> CBC</A> mode since
+ this is only marginally slower than<A href="#ECB"> ECB</A> and is more
+ secure. In ECB mode the same plaintext always encrypts to the same
+ ciphertext, unless the key is changed. In CBC mode, this does not
+ occur.</P>
+<P>Various other modes are also possible, but none of them are used in
+ IPsec.</P>
+</DD>
+<DT><A name="ciphertext">Ciphertext</A></DT>
+<DD>The encrypted output of a cipher, as opposed to the unencrypted<A href="#plaintext">
+ plaintext</A> input.</DD>
+<DT><A href="http://www.cisco.com">Cisco</A></DT>
+<DD>A vendor of routers, hubs and related products. Their IPsec products
+ interoperate with Linux FreeS/WAN; see our<A href="#cisco"> interop</A>
+ section.</DD>
+<DT><A name="client">Client</A></DT>
+<DD>This term has at least two distinct uses in discussing IPsec:
+<UL>
+<LI>The<STRONG> clients of an IPsec gateway</STRONG> are the machines it
+ protects, typically on one or more subnets behind the gateway. In this
+ usage, all the machines on an office network are clients of that
+ office's IPsec gateway. Laptop or home machines connecting to the
+ office, however, are<EM> not</EM> clients of that gateway. They are
+ remote gateways, running the other end of an IPsec connection. Each of
+ them is also its own client.</LI>
+<LI><STRONG>IPsec client software</STRONG> is used to describe software
+ which runs on various standalone machines to let them connect to IPsec
+ networks. In this usage, a laptop or home machine connecting to the
+ office is a client, and the office gateway is the server.</LI>
+</UL>
+<P>We generally use the term in the first sense. Vendors of Windows
+ IPsec solutions often use it in the second. See this<A href="interop.html#client.server">
+ discussion</A>.</P>
+</DD>
+<DT><A name="cc">Common Criteria</A></DT>
+<DD>A set of international security classifications which are replacing
+ the old US<A href="#rainbow"> Rainbow Book</A> standards and similar
+ standards in other countries.
+<P>Web references include this<A href="http://csrc.nist.gov/cc"> US
+ government site</A> and this<A href="http://www.commoncriteria.org">
+ global home page</A>.</P>
+</DD>
+<DT>Conventional cryptography</DT>
+<DD>See<A href="#symmetric"> symmetric cryptography</A></DD>
+<DT><A name="collision">Collision resistance</A></DT>
+<DD>The property of a<A href="#digest"> message digest</A> algorithm
+ which makes it hard for an attacker to find or construct two inputs
+ which hash to the same output.</DD>
+<DT>Copyleft</DT>
+<DD>see GNU<A href="#GPL"> General Public License</A></DD>
+<DT><A name="CSE">CSE</A></DT>
+<DD><A href="http://www.cse-cst.gc.ca/">Communications Security
+ Establishment</A>, the Canadian organisation for<A href="#SIGINT">
+ signals intelligence</A>.</DD>
+<DT><A name="D">D</A></DT>
+<DT><A name="DARPA">DARPA (sometimes just ARPA)</A></DT>
+<DD>The US government's<B> D</B>efense<B> A</B>dvanced<B> R</B>esearch<B>
+ P</B>rojects<B> A</B>gency. Projects they have funded over the years
+ have included the Arpanet which evolved into the Internet, the TCP/IP
+ protocol suite (as a replacement for the original Arpanet suite), the
+ Berkeley 4.x BSD Unix projects, and<A href="#SDNS"> Secure DNS</A>.
+<P>For current information, see their<A href="http://www.darpa.mil/ito">
+ web site</A>.</P>
+</DD>
+<DT><A name="DOS">Denial of service (DoS) attack</A></DT>
+<DD>An attack that aims at denying some service to legitimate users of a
+ system, rather than providing a service to the attacker.
+<UL>
+<LI>One variant is a flooding attack, overwhelming the system with too
+ many packets, to much email, or whatever.</LI>
+<LI>A closely related variant is a resource exhaustion attack. For
+ example, consider a &quot;TCP SYN flood&quot; attack. Setting up a TCP connection
+ involves a three-packet exchange:
+<UL>
+<LI>Initiator: Connection please (SYN)</LI>
+<LI>Responder: OK (ACK)</LI>
+<LI>Initiator: OK here too</LI>
+</UL>
+<P>If the attacker puts bogus source information in the first packet,
+ such that the second is never delivered, the responder may wait a long
+ time for the third to come back. If responder has already allocated
+ memory for the connection data structures, and if many of these bogus
+ packets arrive, the responder may run out of memory.</P>
+</LI>
+<LI>Another variant is to feed the system undigestible data, hoping to
+ make it sick. For example, IP packets are limited in size to 64K bytes
+ and a fragment carries information on where it starts within that 64K
+ and how long it is. The &quot;ping of death&quot; delivers fragments that say,
+ for example, that they start at 60K and are 20K long. Attempting to
+ re-assemble these without checking for overflow can be fatal.</LI>
+</UL>
+<P>The two example attacks discussed were both quite effective when
+ first discovered, capable of crashing or disabling many operating
+ systems. They were also well-publicised, and today far fewer systems
+ are vulnerable to them.</P>
+</DD>
+<DT><A name="DES">DES</A></DT>
+<DD>The<B> D</B>ata<B> E</B>ncryption<B> S</B>tandard, a<A href="#block">
+ block cipher</A> with 64-bit blocks and a 56-bit key. Probably the most
+ widely used<A href="#symmetric"> symmetric cipher</A> ever devised. DES
+ has been a US government standard for their own use (only for
+ unclassified data), and for some regulated industries such as banking,
+ since the late 70's. It is now being replaced by<A href="#AES"> AES</A>
+.
+<P><A href="#desnotsecure">DES is seriously insecure against current
+ attacks.</A></P>
+<P><A href="#FreeSWAN">Linux FreeS/WAN</A> does not include DES, even
+ though the RFCs specify it.<B> We strongly recommend that single DES
+ not be used.</B></P>
+<P>See also<A href="#3DES"> 3DES</A> and<A href="#DESX"> DESX</A>,
+ stronger ciphers based on DES.</P>
+</DD>
+<DT><A name="DESX">DESX</A></DT>
+<DD>An improved<A href="#DES"> DES</A> suggested by Ron Rivest of RSA
+ Data Security. It XORs extra key material into the text before and
+ after applying the DES cipher.
+<P>This is not required by the<A href="#IPSEC"> IPsec</A> RFCs and not
+ currently used in<A href="#FreeSWAN"> Linux FreeS/WAN</A>. DESX would
+ be the easiest additional transform to add; there would be very little
+ code to write. It would be much faster than 3DES and almost certainly
+ more secure than DES. However, since it is not in the RFCs other IPsec
+ implementations cannot be expected to have it.</P>
+</DD>
+<DT>DH</DT>
+<DD>see<A href="#DH"> Diffie-Hellman</A></DD>
+<DT><A name="DHCP">DHCP</A></DT>
+<DD><STRONG>D</STRONG>ynamic<STRONG> H</STRONG>ost<STRONG> C</STRONG>
+onfiguration<STRONG> P</STRONG>rotocol, a method of assigning<A href="#dynamic">
+ dynamic IP addresses</A>, and providing additional information such as
+ addresses of DNS servers and of gateways. See this<A href="http://www.dhcp.org">
+ DHCP resource page.</A></DD>
+<DT><A name="DH">Diffie-Hellman (DH) key exchange protocol</A></DT>
+<DD>A protocol that allows two parties without any initial shared secret
+ to create one in a manner immune to eavesdropping. Once they have done
+ this, they can communicate privately by using that shared secret as a
+ key for a block cipher or as the basis for key exchange.
+<P>The protocol is secure against all<A href="#passive"> passive attacks</A>
+, but it is not at all resistant to active<A href="#middle">
+ man-in-the-middle attacks</A>. If a third party can impersonate Bob to
+ Alice and vice versa, then no useful secret can be created.
+ Authentication of the participants is a prerequisite for safe
+ Diffie-Hellman key exchange. IPsec can use any of several<A href="#authentication">
+ authentication</A> mechanisims. Those supported by FreeS/WAN are
+ discussed in our<A href="#choose"> configuration</A> section.</P>
+<P>The Diffie-Hellman key exchange is based on the<A href="#dlog">
+ discrete logarithm</A> problem and is secure unless someone finds an
+ efficient solution to that problem.</P>
+<P>Given a prime<VAR> p</VAR> and generator<VAR> g</VAR> (explained
+ under<A href="#dlog"> discrete log</A> below), Alice:</P>
+<UL>
+<LI>generates a random number<VAR> a</VAR></LI>
+<LI>calculates<VAR> A = g^a modulo p</VAR></LI>
+<LI>sends<VAR> A</VAR> to Bob</LI>
+</UL>
+<P>Meanwhile Bob:</P>
+<UL>
+<LI>generates a random number<VAR> b</VAR></LI>
+<LI>calculates<VAR> B = g^b modulo p</VAR></LI>
+<LI>sends<VAR> B</VAR> to Alice</LI>
+</UL>
+<P>Now Alice and Bob can both calculate the shared secret<VAR> s =
+ g^(ab)</VAR>. Alice knows<VAR> a</VAR> and<VAR> B</VAR>, so she
+ calculates<VAR> s = B^a</VAR>. Bob knows<VAR> A</VAR> and<VAR> b</VAR>
+ so he calculates<VAR> s = A^b</VAR>.</P>
+<P>An eavesdropper will know<VAR> p</VAR> and<VAR> g</VAR> since these
+ are made public, and can intercept<VAR> A</VAR> and<VAR> B</VAR> but,
+ short of solving the<A href="#dlog"> discrete log</A> problem, these do
+ not let him or her discover the secret<VAR> s</VAR>.</P>
+</DD>
+<DT><A name="signature">Digital signature</A></DT>
+<DD>Sender:
+<UL>
+<LI>calculates a<A href="#digest"> message digest</A> of a document</LI>
+<LI>encrypts the digest with his or her private key, using some<A href="#public">
+ public key cryptosystem</A>.</LI>
+<LI>attaches the encrypted digest to the document as a signature</LI>
+</UL>
+<P>Receiver:</P>
+<UL>
+<LI>calculates a digest of the document (not including the signature)</LI>
+<LI>decrypts the signature with the signer's public key</LI>
+<LI>verifies that the two results are identical</LI>
+</UL>
+<P>If the public-key system is secure and the verification succeeds,
+ then the receiver knows</P>
+<UL>
+<LI>that the document was not altered between signing and verification</LI>
+<LI>that the signer had access to the private key</LI>
+</UL>
+<P>Such an encrypted message digest can be treated as a signature since
+ it cannot be created without<EM> both</EM> the document<EM> and</EM>
+ the private key which only the sender should possess. The<A href="#legal">
+ legal issues</A> are complex, but several countries are moving in the
+ direction of legal recognition for digital signatures.</P>
+</DD>
+<DT><A name="dlog">discrete logarithm problem</A></DT>
+<DD>The problem of finding logarithms in a finite field. Given a field
+ defintion (such definitions always include some operation analogous to
+ multiplication) and two numbers, a base and a target, find the power
+ which the base must be raised to in order to yield the target.
+<P>The discrete log problem is the basis of several cryptographic
+ systems, including the<A href="#DH"> Diffie-Hellman</A> key exchange
+ used in the<A href="#IKE"> IKE</A> protocol. The useful property is
+ that exponentiation is relatively easy but the inverse operation,
+ finding the logarithm, is hard. The cryptosystems are designed so that
+ the user does only easy operations (exponentiation in the field) but an
+ attacker must solve the hard problem (discrete log) to crack the
+ system.</P>
+<P>There are several variants of the problem for different types of
+ field. The IKE/Oakley key determination protocol uses two variants,
+ either over a field modulo a prime or over a field defined by an
+ elliptic curve. We give an example modulo a prime below. For the
+ elliptic curve version, consult an advanced text such as<A href="#handbook">
+ Handbook of Applied Cryptography</A>.</P>
+<P>Given a prime<VAR> p</VAR>, a generator<VAR> g</VAR> for the field
+ modulo that prime, and a number<VAR> x</VAR> in the field, the problem
+ is to find<VAR> y</VAR> such that<VAR> g^y = x</VAR>.</P>
+<P>For example, let p = 13. The field is then the integers from 0 to 12.
+ Any integer equals one of these modulo 13. That is, the remainder when
+ any integer is divided by 13 must be one of these.</P>
+<P>2 is a generator for this field. That is, the powers of two modulo 13
+ run through all the non-zero numbers in the field. Modulo 13 we have:</P>
+<PRE> y x
+ 2^0 == 1
+ 2^1 == 2
+ 2^2 == 4
+ 2^3 == 8
+ 2^4 == 3 that is, the remainder from 16/13 is 3
+ 2^5 == 6 the remainder from 32/13 is 6
+ 2^6 == 12 and so on
+ 2^7 == 11
+ 2^8 == 9
+ 2^9 == 5
+ 2^10 == 10
+ 2^11 == 7
+ 2^12 == 1</PRE>
+<P>Exponentiation in such a field is not difficult. Given, say,<NOBR><VAR>
+ y = 11</VAR>,calculating<NOBR><VAR> x = 7</VAR>is straightforward. One
+ method is just to calculate<NOBR><VAR> 2^11 = 2048</VAR>,then<NOBR><VAR>
+ 2048 mod 13 == 7</VAR>.When the field is modulo a large prime (say a
+ few 100 digits) you need a silghtly cleverer method and even that is
+ moderately expensive in computer time, but the calculation is still not
+ problematic in any basic way.</P>
+<P>The discrete log problem is the reverse. In our example, given<NOBR><VAR>
+ x = 7</VAR>,find the logarithm<NOBR><VAR> y = 11</VAR>.When the field
+ is modulo a large prime (or is based on a suitable elliptic curve),
+ this is indeed problematic. No solution method that is not
+ catastrophically expensive is known. Quite a few mathematicians have
+ tackled this problem. No efficient method has been found and
+ mathematicians do not expect that one will be. It seems likely no
+ efficient solution to either of the main variants the discrete log
+ problem exists.</P>
+<P>Note, however, that no-one has proven such methods do not exist. If a
+ solution to either variant were found, the security of any crypto
+ system using that variant would be destroyed. This is one reason<A href="#IKE">
+ IKE</A> supports two variants. If one is broken, we can switch to the
+ other.</P>
+</DD>
+<DT><A name="discretionary">discretionary access control</A></DT>
+<DD>access control mechanisms controlled by the user, for example Unix
+ rwx file permissions. These contrast with<A href="#mandatory">
+ mandatory access controls</A>.</DD>
+<DT><A name="DNS">DNS</A></DT>
+<DD><B>D</B>omain<B> N</B>ame<B> S</B>ervice, a distributed database
+ through which names are associated with numeric addresses and other
+ information in the Internet Protocol Suite. See also the<A href="#dns.background">
+ DNS background</A> section of our documentation.</DD>
+<DT>DOS attack</DT>
+<DD>see<A href="#DOS"> Denial Of Service</A> attack</DD>
+<DT><A name="dynamic">dynamic IP address</A></DT>
+<DD>an IP address which is automatically assigned, either by<A href="#DHCP">
+ DHCP</A> or by some protocol such as<A href="#PPP"> PPP</A> or<A href="#PPPoE">
+ PPPoE</A> which the machine uses to connect to the Internet. This is
+ the opposite of a<A href="#static"> static IP address</A>, pre-set on
+ the machine itself.</DD>
+<DT><A name="E">E</A></DT>
+<DT><A name="EAR">EAR</A></DT>
+<DD>The US government's<B> E</B>xport<B> A</B>dministration<B> R</B>
+egulations, administered by the<A href="#BXA"> Bureau of Export
+ Administration</A>. These have replaced the earlier<A href="#ITAR">
+ ITAR</A> regulations as the controls on export of cryptography.</DD>
+<DT><A name="ECB">ECB mode</A></DT>
+<DD><B>E</B>lectronic<B> C</B>ode<B>B</B>ook mode, the simplest way to
+ use a block cipher. See<A href="#mode"> Cipher Modes</A>.</DD>
+<DT><A name="EDE">EDE</A></DT>
+<DD>The sequence of operations normally used in either the three-key
+ variant of<A href="#3DES"> triple DES</A> used in<A href="#IPSEC">
+ IPsec</A> or the<A href="#2key"> two-key</A> variant used in some other
+ systems.
+<P>The sequence is:</P>
+<UL>
+<LI><B>E</B>ncrypt with key1</LI>
+<LI><B>D</B>ecrypt with key2</LI>
+<LI><B>E</B>ncrypt with key3</LI>
+</UL>
+<P>For the two-key version, key1=key3.</P>
+<P>The &quot;advantage&quot; of this EDE order of operations is that it makes it
+ simple to interoperate with older devices offering only single DES. Set
+ key1=key2=key3 and you have the worst of both worlds, the overhead of
+ triple DES with the &quot;security&quot; of single DES. Since both the<A href="#desnotsecure">
+ security of single DES</A> and the overheads of triple DES are
+ seriously inferior to many other ciphers, this is a spectacularly
+ dubious &quot;advantage&quot;.</P>
+</DD>
+<DT><A name="Entrust">Entrust</A></DT>
+<DD>A Canadian company offerring enterprise<A href="#PKI"> PKI</A>
+ products using<A href="#CAST128"> CAST-128</A> symmetric crypto,<A href="#RSA">
+ RSA</A> public key and<A href="#X509"> X.509</A> directories.<A href="http://www.entrust.com">
+ Web site</A></DD>
+<DT><A name="EFF">EFF</A></DT>
+<DD><A href="http://www.eff.org">Electronic Frontier Foundation</A>, an
+ advocacy group for civil rights in cyberspace.</DD>
+<DT><A name="encryption">Encryption</A></DT>
+<DD>Techniques for converting a readable message (<A href="#plaintext">
+plaintext</A>) into apparently random material (<A href="#ciphertext">
+ciphertext</A>) which cannot be read if intercepted. A key is required
+ to read the message.
+<P>Major variants include<A href="#symmetric"> symmetric</A> encryption
+ in which sender and receiver use the same secret key and<A href="#public">
+ public key</A> methods in which the sender uses one of a matched pair
+ of keys and the receiver uses the other. Many current systems,
+ including<A href="#IPSEC"> IPsec</A>, are<A href="#hybrid"> hybrids</A>
+ combining the two techniques.</P>
+</DD>
+<DT><A name="ESP">ESP</A></DT>
+<DD><B>E</B>ncapsulated<B> S</B>ecurity<B> P</B>ayload, the<A href="#IPSEC">
+ IPsec</A> protocol which provides<A href="#encryption"> encryption</A>.
+ It can also provide<A href="#authentication"> authentication</A>
+ service and may be used with null encryption (which we do not
+ recommend). For details see our<A href="#ESP.ipsec"> IPsec</A> document
+ and/or RFC 2406.</DD>
+<DT><A name="#extruded">Extruded subnet</A></DT>
+<DD>A situation in which something IP sees as one network is actually in
+ two or more places.
+<P>For example, the Internet may route all traffic for a particular
+ company to that firm's corporate gateway. It then becomes the company's
+ problem to get packets to various machines on their<A href="#subnet">
+ subnets</A> in various departments. They may decide to treat a branch
+ office like a subnet, giving it IP addresses &quot;on&quot; their corporate net.
+ This becomes an extruded subnet.</P>
+<P>Packets bound for it are delivered to the corporate gateway, since as
+ far as the outside world is concerned, that subnet is part of the
+ corporate network. However, instead of going onto the corporate LAN (as
+ they would for, say, the accounting department) they are then
+ encapsulated and sent back onto the Internet for delivery to the branch
+ office.</P>
+<P>For information on doing this with Linux FreeS/WAN, look in our<A href="#extruded.config">
+ advanced configuration</A> section.</P>
+</DD>
+<DT>Exhaustive search</DT>
+<DD>See<A href="#brute"> brute force attack</A>.</DD>
+<DT><A name="F">F</A></DT>
+<DT><A name="FIPS">FIPS</A></DT>
+<DD><B>F</B>ederal<B> I</B>nformation<B> P</B>rocessing<B> S</B>tandard,
+ the US government's standards for products it buys. These are issued by<A
+href="#NIST"> NIST</A>. Among other things,<A href="#DES"> DES</A> and<A href="#SHA">
+ SHA</A> are defined in FIPS documents. NIST have a<A href="http://www.itl.nist.gov/div897/pubs">
+ FIPS home page</A>.</DD>
+<DT><A name="FSF">Free Software Foundation (FSF)</A></DT>
+<DD>An organisation to promote free software, free in the sense of these
+ quotes from their web pages</DD>
+<DD><BLOCKQUOTE> &quot;Free software&quot; is a matter of liberty, not price. To
+ understand the concept, you should think of &quot;free speech&quot;, not &quot;free
+ beer.&quot;
+<P>&quot;Free software&quot; refers to the users' freedom to run, copy,
+ distribute, study, change and improve the software.</P>
+</BLOCKQUOTE>
+<P>See also<A href="#GNU"> GNU</A>,<A href="#GPL"> GNU General Public
+ License</A>, and<A href="http://www.fsf.org"> the FSF site</A>.</P>
+</DD>
+<DT>FreeS/WAN</DT>
+<DD>see<A href="#FreeSWAN"> Linux FreeS/WAN</A></DD>
+<DT><A name="fullnet">Fullnet</A></DT>
+<DD>The CIDR block containing all IPs of its IP version. The<A HREF="#IPv4">
+ IPv4</A> fullnet is written 0.0.0.0/0. Also known as &quot;all&quot; and
+ &quot;default&quot;, fullnet may be used in a routing table to specify a default
+ route, and in a FreeS/WAN<A HREF="#policygroups"> policy group</A> file
+ to specify a default IPsec policy.</DD>
+<DT>FSF</DT>
+<DD>see<A href="#FSF"> Free software Foundation</A></DD>
+<DT><A name="G">G</A></DT>
+<DT><A name="GCHQ">GCHQ</A></DT>
+<DD><A href="http://www.gchq.gov.uk">Government Communications
+ Headquarters</A>, the British organisation for<A href="#SIGINT">
+ signals intelligence</A>.</DD>
+<DT>generator of a prime field</DT>
+<DD>see<A href="#dlog"> discrete logarithm problem</A></DD>
+<DT><A name="GILC">GILC</A></DT>
+<DD><A href="http://www.gilc.org">Global Internet Liberty Campaign</A>,
+ an international organisation advocating, among other things, free
+ availability of cryptography. They have a<A href="http://www.gilc.org/crypto/wassenaar">
+ campaign</A> to remove cryptographic software from the<A href="#Wassenaar.gloss">
+ Wassenaar Arrangement</A>.</DD>
+<DT>Global Internet Liberty Campaign</DT>
+<DD>see<A href="#GILC"> GILC</A>.</DD>
+<DT><A name="GTR">Global Trust Register</A></DT>
+<DD>An attempt to create something like a<A href="#rootCA"> root CA</A>
+ for<A href="#PGP"> PGP</A> by publishing both<A href="#GTR"> as a book</A>
+ and<A href="http://www.cl.cam.ac.uk/Research/Security/Trust-Register">
+ on the web</A> the fingerprints of a set of verified keys for
+ well-known users and organisations.</DD>
+<DT><A name="GMP">GMP</A></DT>
+<DD>The<B> G</B>NU<B> M</B>ulti-<B>P</B>recision library code, used in<A href="#FreeSWAN">
+ Linux FreeS/WAN</A> by<A href="#Pluto"> Pluto</A> for<A href="#public">
+ public key</A> calculations. See the<A href="http://www.swox.com/gmp">
+ GMP home page</A>.</DD>
+<DT><A name="GNU">GNU</A></DT>
+<DD><B>G</B>NU's<B> N</B>ot<B> U</B>nix, the<A href="#FSF"> Free
+ Software Foundation's</A> project aimed at creating a free system with
+ at least the capabilities of Unix.<A href="#Linux"> Linux</A> uses GNU
+ utilities extensively.</DD>
+<DT><A name="#GOST">GOST</A></DT>
+<DD>a Soviet government standard<A href="#block"> block cipher</A>.<A href="#schneier">
+ Applied Cryptography</A> has details.</DD>
+<DT>GPG</DT>
+<DD>see<A href="#GPG"> GNU Privacy Guard</A></DD>
+<DT><A name="GPL">GNU General Public License</A>(GPL, copyleft)</DT>
+<DD>The license developed by the<A href="#FSF"> Free Software Foundation</A>
+ under which<A href="#Linux"> Linux</A>,<A href="#FreeSWAN"> Linux
+ FreeS/WAN</A> and many other pieces of software are distributed. The
+ license allows anyone to redistribute and modify the code, but forbids
+ anyone from distributing executables without providing access to source
+ code. For more details see the file<A href="../COPYING"> COPYING</A>
+ included with GPLed source distributions, including ours, or<A href="http://www.fsf.org/copyleft/gpl.html">
+ the GNU site's GPL page</A>.</DD>
+<DT><A name="GPG">GNU Privacy Guard</A></DT>
+<DD>An open source implementation of Open<A href="#PGP"> PGP</A> as
+ defined in RFC 2440. See their<A href="http://www.gnupg.org"> web site</A>
+</DD>
+<DT>GPL</DT>
+<DD>see<A href="#GPL"> GNU General Public License</A>.</DD>
+<DT><A name="H">H</A></DT>
+<DT><A name="hash">Hash</A></DT>
+<DD>see<A href="#digest"> message digest</A></DD>
+<DT><A name="HMAC">Hashed Message Authentication Code (HMAC)</A></DT>
+<DD>using keyed<A href="#digest"> message digest</A> functions to
+ authenticate a message. This differs from other uses of these
+ functions:
+<UL>
+<LI>In normal usage, the hash function's internal variable are
+ initialised in some standard way. Anyone can reproduce the hash to
+ check that the message has not been altered.</LI>
+<LI>For HMAC usage, you initialise the internal variables from the key.
+ Only someone with the key can reproduce the hash. A successful check of
+ the hash indicates not only that the message is unchanged but also that
+ the creator knew the key.</LI>
+</UL>
+<P>The exact techniques used in<A href="#IPSEC"> IPsec</A> are defined
+ in RFC 2104. They are referred to as HMAC-MD5-96 and HMAC-SHA-96
+ because they output only 96 bits of the hash. This makes some attacks
+ on the hash functions harder.</P>
+</DD>
+<DT>HMAC</DT>
+<DD>see<A href="#HMAC"> Hashed Message Authentication Code</A></DD>
+<DT>HMAC-MD5-96</DT>
+<DD>see<A href="#HMAC"> Hashed Message Authentication Code</A></DD>
+<DT>HMAC-SHA-96</DT>
+<DD>see<A href="#HMAC"> Hashed Message Authentication Code</A></DD>
+<DT><A name="hybrid">Hybrid cryptosystem</A></DT>
+<DD>A system using both<A href="#public"> public key</A> and<A href="#symmetric">
+ symmetric cipher</A> techniques. This works well. Public key methods
+ provide key management and<A href="#signature"> digital signature</A>
+ facilities which are not readily available using symmetric ciphers. The
+ symmetric cipher, however, can do the bulk of the encryption work much
+ more efficiently than public key methods.</DD>
+<DT><A name="I">I</A></DT>
+<DT><A name="IAB">IAB</A></DT>
+<DD><A href="http://www.iab.org/iab">Internet Architecture Board</A>.</DD>
+<DT><A name="ICMP.gloss">ICMP</A></DT>
+<DD><STRONG>I</STRONG>nternet<STRONG> C</STRONG>ontrol<STRONG> M</STRONG>
+essage<STRONG> P</STRONG>rotocol. This is used for various IP-connected
+ devices to manage the network.</DD>
+<DT><A name="IDEA">IDEA</A></DT>
+<DD><B>I</B>nternational<B> D</B>ata<B> E</B>ncrypion<B> A</B>lgorithm,
+ developed in Europe as an alternative to exportable American ciphers
+ such as<A href="#DES"> DES</A> which were<A href="#desnotsecure"> too
+ weak for serious use</A>. IDEA is a<A href="#block"> block cipher</A>
+ using 64-bit blocks and 128-bit keys, and is used in products such as<A href="#PGP">
+ PGP</A>.
+<P>IDEA is not required by the<A href="#IPSEC"> IPsec</A> RFCs and not
+ currently used in<A href="#FreeSWAN"> Linux FreeS/WAN</A>.</P>
+<P>IDEA is patented and, with strictly limited exceptions for personal
+ use, using it requires a license from<A href="http://www.ascom.com">
+ Ascom</A>.</P>
+</DD>
+<DT><A name="IEEE">IEEE</A></DT>
+<DD><A href="http://www.ieee.org">Institute of Electrical and Electronic
+ Engineers</A>, a professional association which, among other things,
+ sets some technical standards</DD>
+<DT><A name="IESG">IESG</A></DT>
+<DD><A href="http://www.iesg.org">Internet Engineering Steering Group</A>
+.</DD>
+<DT><A name="IETF">IETF</A></DT>
+<DD><A href="http://www.ietf.org">Internet Engineering Task Force</A>,
+ the umbrella organisation whose various working groups make most of the
+ technical decisions for the Internet. The IETF<A href="http://www.ietf.org/html.charters/ipsec-charter.html">
+ IPsec working group</A> wrote the<A href="#RFC"> RFCs</A> we are
+ implementing.</DD>
+<DT><A name="IKE">IKE</A></DT>
+<DD><B>I</B>nternet<B> K</B>ey<B> E</B>xchange, based on the<A href="#DH">
+ Diffie-Hellman</A> key exchange protocol. For details, see RFC 2409 and
+ our<A href="ipsec.html"> IPsec</A> document. IKE is implemented in<A href="#FreeSWAN">
+ Linux FreeS/WAN</A> by the<A href="#Pluto"> Pluto daemon</A>.</DD>
+<DT>IKE v2</DT>
+<DD>A proposed replacement for<A href="#IKE"> IKE</A>. There are other
+ candidates, such as<A href="#JFK"> JFK</A>, and at time of writing
+ (March 2002) the choice between them has not yet been made and does not
+ appear imminent.</DD>
+<DT><A name="iOE">iOE</A></DT>
+<DD>See<A HREF="#initiate-only"> Initiate-only opportunistic encryption</A>
+.</DD>
+<DT><A name="IP">IP</A></DT>
+<DD><B>I</B>nternet<B> P</B>rotocol.</DD>
+<DT><A name="masq">IP masquerade</A></DT>
+<DD>A mostly obsolete term for a method of allowing multiple machines to
+ communicate over the Internet when only one IP address is available for
+ their use. The more current term is Network Address Translation or<A href="#NAT.gloss">
+ NAT</A>.</DD>
+<DT><A name="IPng">IPng</A></DT>
+<DD>&quot;IP the Next Generation&quot;, see<A href="#ipv6.gloss"> IPv6</A>.</DD>
+<DT><A name="IPv4">IPv4</A></DT>
+<DD>The current version of the<A href="#IP"> Internet protocol suite</A>
+.</DD>
+<DT><A name="ipv6.gloss">IPv6 (IPng)</A></DT>
+<DD>Version six of the<A href="#IP"> Internet protocol suite</A>,
+ currently being developed. It will replace the current<A href="#IPv4">
+ version four</A>. IPv6 has<A href="#IPSEC"> IPsec</A> as a mandatory
+ component.
+<P>See this<A href="http://playground.sun.com/pub/ipng/html/ipng-main.html">
+ web site</A> for more details, and our<A href="#ipv6"> compatibility</A>
+ document for information on FreeS/WAN and the Linux implementation of
+ IPv6.</P>
+</DD>
+<DT><A name="IPSEC">IPsec</A> or IPSEC</DT>
+<DD><B>I</B>nternet<B> P</B>rotocol<B> SEC</B>urity, security functions
+ (<A href="#authentication">authentication</A> and<A href="#encryption">
+ encryption</A>) implemented at the IP level of the protocol stack. It
+ is optional for<A href="#IPv4"> IPv4</A> and mandatory for<A href="#ipv6.gloss">
+ IPv6</A>.
+<P>This is the standard<A href="#FreeSWAN"> Linux FreeS/WAN</A> is
+ implementing. For more details, see our<A href="ipsec.html"> IPsec
+ Overview</A>. For the standards, see RFCs listed in our<A href="#RFC">
+ RFCs document</A>.</P>
+</DD>
+<DT><A name="IPX">IPX</A></DT>
+<DD>Novell's Netware protocol tunnelled over an IP link. Our<A href="#user.scripts">
+ firewalls</A> document includes an example of using this through an
+ IPsec tunnel.</DD>
+<DT><A name="ISAKMP">ISAKMP</A></DT>
+<DD><B>I</B>nternet<B> S</B>ecurity<B> A</B>ssociation and<B> K</B>ey<B>
+ M</B>anagement<B> P</B>rotocol, defined in RFC 2408.</DD>
+<DT><A name="ITAR">ITAR</A></DT>
+<DD><B>I</B>nternational<B> T</B>raffic in<B> A</B>rms<B> R</B>
+egulations, US regulations administered by the State Department which
+ until recently limited export of, among other things, cryptographic
+ technology and software. ITAR still exists, but the limits on
+ cryptography have now been transferred to the<A href="#EAR"> Export
+ Administration Regulations</A> under the Commerce Department's<A href="#BXA">
+ Bureau of Export Administration</A>.</DD>
+<DT>IV</DT>
+<DD>see<A href="#IV"> Initialisation vector</A></DD>
+<DT><A name="IV">Initialisation Vector (IV)</A></DT>
+<DD>Some cipher<A href="#mode"> modes</A>, including the<A href="#CBC">
+ CBC</A> mode which IPsec uses, require some extra data at the
+ beginning. This data is called the initialisation vector. It need not
+ be secret, but should be different for each message. Its function is to
+ prevent messages which begin with the same text from encrypting to the
+ same ciphertext. That might give an analyst an opening, so it is best
+ prevented.</DD>
+<DT><A name="initiate-only">Initiate-only opportunistic encryption (iOE)</A>
+</DT>
+<DD>A form of<A HREF="#carpediem"> opportunistic encryption</A> (OE) in
+ which a host proposes opportunistic connections, but lacks the reverse
+ DNS records necessary to support incoming opportunistic connection
+ requests. Common among hosts on cable or pppoe connections where the
+ system administrator does not have write access to the DNS reverse map
+ for the host's external IP.
+<P>Configuring for initiate-only opportunistic encryption is described
+ in our<A href="#opp.client"> quickstart</A> document.</P>
+</DD>
+<DT><A name="J">J</A></DT>
+<DT><A name="JFK">JFK</A></DT>
+<DD><STRONG>J</STRONG>ust<STRONG> F</STRONG>ast<STRONG> K</STRONG>eying,
+ a proposed simpler replacement for<A href="#IKE"> IKE.</A></DD>
+<DT><A name="K">K</A></DT>
+<DT><A name="kernel">Kernel</A></DT>
+<DD>The basic part of an operating system (e.g. Linux) which controls
+ the hardware and provides services to all other programs.
+<P>In the Linux release numbering system, an even second digit as in 2.<STRONG>
+2</STRONG>.x indicates a stable or production kernel while an odd number
+ as in 2.<STRONG>3</STRONG>.x indicates an experimental or development
+ kernel. Most users should run a recent kernel version from the
+ production series. The development kernels are primarily for people
+ doing kernel development. Others should consider using development
+ kernels only if they have an urgent need for some feature not yet
+ available in production kernels.</P>
+</DD>
+<DT>Keyed message digest</DT>
+<DD>See<A href="#HMAC"> HMAC</A>.</DD>
+<DT>Key length</DT>
+<DD>see<A href="#brute"> brute force attack</A></DD>
+<DT><A name="KLIPS">KLIPS</A></DT>
+<DD><B>K</B>erne<B>l</B><B> IP</B><B> S</B>ecurity, the<A href="#FreeSWAN">
+ Linux FreeS/WAN</A> project's changes to the<A href="#Linux"> Linux</A>
+ kernel to support the<A href="#IPSEC"> IPsec</A> protocols.</DD>
+<DT><A name="L">L</A></DT>
+<DT><A name="LDAP">LDAP</A></DT>
+<DD><B>L</B>ightweight<B> D</B>irectory<B> A</B>ccess<B> P</B>rotocol,
+ defined in RFCs 1777 and 1778, a method of accessing information stored
+ in directories. LDAP is used by several<A href="#PKI"> PKI</A>
+ implementations, often with X.501 directories and<A href="#X509"> X.509</A>
+ certificates. It may also be used by<A href="#IPSEC"> IPsec</A> to
+ obtain key certifications from those PKIs. This is not yet implemented
+ in<A href="#FreeSWAN"> Linux FreeS/WAN</A>.</DD>
+<DT><A name="LIBDES">LIBDES</A></DT>
+<DD>A publicly available library of<A href="#DES"> DES</A> code, written
+ by Eric Young, which<A href="#FreeSWAN"> Linux FreeS/WAN</A> uses in
+ both<A href="#KLIPS"> KLIPS</A> and<A href="#Pluto"> Pluto</A>.</DD>
+<DT><A name="Linux">Linux</A></DT>
+<DD>A freely available Unix-like operating system based on a kernel
+ originally written for the Intel 386 architecture by (then) student
+ Linus Torvalds. Once his 32-bit kernel was available, the<A href="#GNU">
+ GNU</A> utilities made it a usable system and contributions from many
+ others led to explosive growth.
+<P>Today Linux is a complete Unix replacement available for several CPU
+ architectures -- Intel, DEC/Compaq Alpha, Power PC, both 32-bit SPARC
+ and the 64-bit UltraSPARC, SrongARM, . . . -- with support for multiple
+ CPUs on some architectures.</P>
+<P><A href="#FreeSWAN">Linux FreeS/WAN</A> is intended to run on all
+ CPUs supported by Linux and is known to work on several. See our<A href="#CPUs">
+ compatibility</A> section for a list.</P>
+</DD>
+<DT><A name="FreeSWAN">Linux FreeS/WAN</A></DT>
+<DD>Our implementation of the<A href="#IPSEC"> IPsec</A> protocols,
+ intended to be freely redistributable source code with<A href="#GPL"> a
+ GNU GPL license</A> and no constraints under US or other<A href="#exlaw">
+ export laws</A>. Linux FreeS/WAN is intended to interoperate with other<A
+href="#IPSEC"> IPsec</A> implementations. The name is partly taken, with
+ permission, from the<A href="#SWAN"> S/WAN</A> multi-vendor IPsec
+ compatability effort. Linux FreeS/WAN has two major components,<A href="#KLIPS">
+ KLIPS</A> (KerneL IPsec Support) and the<A href="#Pluto"> Pluto</A>
+ daemon which manages the whole thing.
+<P>See our<A href="ipsec.html"> IPsec section</A> for more detail. For
+ the code see our<A href="http://freeswan.org"> primary site</A> or one
+ of the mirror sites on<A href="#mirrors"> this list</A>.</P>
+</DD>
+<DT><A name="LSM">Linux Security Modules (LSM)</A></DT>
+<DD>a project to create an interface in the Linux kernel that supports
+ plug-in modules for various security policies.
+<P>This allows multiple security projects to take different approaches
+ to security enhancement without tying the kernel down to one particular
+ approach. As I understand the history, several projects were pressing
+ Linus to incorporate their changes, the various sets of changes were
+ incompatible, and his answer was more-or-less &quot;a plague on all your
+ houses; I'll give you an interface, but I won't incorporate anything&quot;.</P>
+<P>It seems to be working. There is a fairly active<A href="http://mail.wirex.com/mailman/listinfo/linux-security-module">
+ LSM mailing list</A>, and several projects are already using the
+ interface.</P>
+</DD>
+<DT>LSM</DT>
+<DD>see<A href="#LSM"> Linux Security Modules</A></DD>
+<DT><A name="M">M</A></DT>
+<DT><A name="list">Mailing list</A></DT>
+<DD>The<A href="#FreeSWAN"> Linux FreeS/WAN</A> project has several
+ public email lists for bug reports and software development
+ discussions. See our document on<A href="mail.html"> mailing lists</A>.</DD>
+<DT><A name="middle">Man-in-the-middle attack</A></DT>
+<DD>An<A href="#active"> active attack</A> in which the attacker
+ impersonates each of the legitimate players in a protocol to the other.
+<P>For example, if<A href="#alicebob"> Alice and Bob</A> are negotiating
+ a key via the<A href="#DH"> Diffie-Hellman</A> key agreement, and are
+ not using<A href="#authentication"> authentication</A> to be certain
+ they are talking to each other, then an attacker able to insert himself
+ in the communication path can deceive both players.</P>
+<P>Call the attacker Mallory. For Bob, he pretends to be Alice. For
+ Alice, he pretends to be Bob. Two keys are then negotiated,
+ Alice-to-Mallory and Bob-to-Mallory. Alice and Bob each think the key
+ they have is Alice-to-Bob.</P>
+<P>A message from Alice to Bob then goes to Mallory who decrypts it,
+ reads it and/or saves a copy, re-encrypts using the Bob-to-Mallory key
+ and sends it along to Bob. Bob decrypts successfully and sends a reply
+ which Mallory decrypts, reads, re-encrypts and forwards to Alice.</P>
+<P>To make this attack effective, Mallory must</P>
+<UL>
+<LI>subvert some part of the network in some way that lets him carry out
+ the deception
+<BR> possible targets: DNS, router, Alice or Bob's machine, mail server,
+ ...</LI>
+<LI>beat any authentication mechanism Alice and Bob use
+<BR> strong authentication defeats the attack entirely; this is why<A href="#IKE">
+ IKE</A> requires authentication</LI>
+<LI>work in real time, delivering messages without introducing a delay
+ large enough to alert the victims
+<BR> not hard if Alice and Bob are using email; quite difficult in some
+ situations.</LI>
+</UL>
+<P>If he manages it, however, it is devastating. He not only gets to
+ read all the messages; he can alter messages, inject his own, forge
+ anything he likes, . . . In fact, he controls the communication
+ completely.</P>
+</DD>
+<DT><A name="mandatory">mandatory access control</A></DT>
+<DD>access control mechanisims which are not settable by the user (see<A href="#discretionary">
+ discretionary access control</A>), but are enforced by the system.
+<P>For example, a document labelled &quot;secret, zebra&quot; might be readable
+ only by someone with secret clearance working on Project Zebra.
+ Ideally, the system will prevent any transfer outside those boundaries.
+ For example, even if you can read it, you should not be able to e-mail
+ it (unless the recipient is appropriately cleared) or print it (unless
+ certain printers are authorised for that classification).</P>
+<P>Mandatory access control is a required feature for some levels of<A href="#rainbow">
+ Rainbow Book</A> or<A href="#cc"> Common Criteria</A> classification,
+ but has not been widely used outside the military and government. There
+ is a good discussion of the issues in Anderson's<A href="#anderson">
+ Security Engineering</A>.</P>
+<P>The<A href="#SElinux"> Security Enhanced Linux</A> project is adding
+ mandatory access control to Linux.</P>
+</DD>
+<DT><A name="manual">Manual keying</A></DT>
+<DD>An IPsec mode in which the keys are provided by the administrator.
+ In FreeS/WAN, they are stored in /etc/ipsec.conf. The alternative,<A href="#auto">
+ automatic keying</A>, is preferred in most cases. See this<A href="#man-auto">
+ discussion</A>.</DD>
+<DT><A name="MD4">MD4</A></DT>
+<DD><A href="#digest">Message Digest Algorithm</A> Four from Ron Rivest
+ of<A href="#RSAco"> RSA</A>. MD4 was widely used a few years ago, but
+ is now considered obsolete. It has been replaced by its descendants<A href="#MD5">
+ MD5</A> and<A href="#SHA"> SHA</A>.</DD>
+<DT><A name="MD5">MD5</A></DT>
+<DD><A href="#digest">Message Digest Algorithm</A> Five from Ron Rivest
+ of<A href="#RSAco"> RSA</A>, an improved variant of his<A href="#MD4">
+ MD4</A>. Like MD4, it produces a 128-bit hash. For details see RFC
+ 1321.
+<P>MD5 is one of two message digest algorithms available in IPsec. The
+ other is<A href="#SHA"> SHA</A>. SHA produces a longer hash and is
+ therefore more resistant to<A href="#birthday"> birthday attacks</A>,
+ but this is not a concern for IPsec. The<A href="#HMAC"> HMAC</A>
+ method used in IPsec is secure even if the underlying hash is not
+ particularly strong against this attack.</P>
+<P>Hans Dobbertin found a weakness in MD5, and people often ask whether
+ this means MD5 is unsafe for IPsec. It doesn't. The IPsec RFCs discuss
+ Dobbertin's attack and conclude that it does not affect MD5 as used for
+ HMAC in IPsec.</P>
+</DD>
+<DT><A name="meet">Meet-in-the-middle attack</A></DT>
+<DD>A divide-and-conquer attack which breaks a cipher into two parts,
+ works against each separately, and compares results. Probably the best
+ known example is an attack on double DES. This applies in principle to
+ any pair of block ciphers, e.g. to an encryption system using, say,
+ CAST-128 and Blowfish, but we will describe it for double DES.
+<P>Double DES encryption and decryption can be written:</P>
+<PRE> C = E(k2,E(k1,P))
+ P = D(k1,D(k2,C))</PRE>
+<P>Where C is ciphertext, P is plaintext, E is encryption, D is
+ decryption, k1 is one key, and k2 is the other key. If we know a P, C
+ pair, we can try and find the keys with a brute force attack, trying
+ all possible k1, k2 pairs. Since each key is 56 bits, there are 2<SUP>
+112</SUP> such pairs and this attack is painfully inefficient.</P>
+<P>The meet-in-the middle attack re-writes the equations to calculate a
+ middle value M:</P>
+<PRE> M = E(k1,P)
+ M = D(k2,C)</PRE>
+<P>Now we can try some large number of D(k2,C) decryptions with various
+ values of k2 and store the results in a table. Then start doing E(k1,P)
+ encryptions, checking each result to see if it is in the table.</P>
+<P>With enough table space, this breaks double DES with<NOBR> 2<SUP>56</SUP>
+ + 2<SUP>56</SUP> = 2<SUP>57</SUP>work. Against triple DES, you need<NOBR>
+ 2<SUP>56</SUP> + 2<SUP>112</SUP> ~= 2<SUP>112</SUP>.</P>
+<P>The memory requirements for such attacks can be prohibitive, but
+ there is a whole body of research literature on methods of reducing
+ them.</P>
+</DD>
+<DT><A name="digest">Message Digest Algorithm</A></DT>
+<DD>An algorithm which takes a message as input and produces a hash or
+ digest of it, a fixed-length set of bits which depend on the message
+ contents in some highly complex manner. Design criteria include making
+ it extremely difficult for anyone to counterfeit a digest or to change
+ a message without altering its digest. One essential property is<A href="#collision">
+ collision resistance</A>. The main applications are in message<A href="#authentication">
+ authentication</A> and<A href="#signature"> digital signature</A>
+ schemes. Widely used algorithms include<A href="#MD5"> MD5</A> and<A href="#SHA">
+ SHA</A>. In IPsec, message digests are used for<A href="#HMAC"> HMAC</A>
+ authentication of packets.</DD>
+<DT><A name="MTU">MTU</A></DT>
+<DD><STRONG>M</STRONG>aximum<STRONG> T</STRONG>ransmission<STRONG> U</STRONG>
+nit, the largest size of packet that can be sent over a link. This is
+ determined by the underlying network, but must be taken account of at
+ the IP level.
+<P>IP packets, which can be up to 64K bytes each, must be packaged into
+ lower-level packets of the appropriate size for the underlying
+ network(s) and re-assembled on the other end. When a packet must pass
+ over multiple networks, each with its own MTU, and many of the MTUs are
+ unknown to the sender, this becomes a fairly complex problem. See<A href="#pathMTU">
+ path MTU discovery</A> for details.</P>
+<P>Often the MTU is a few hundred bytes on serial links and 1500 on
+ Ethernet. There are, however, serial link protocols which use a larger
+ MTU to avoid fragmentation at the ethernet/serial boundary, and newer
+ (especially gigabit) Ethernet networks sometimes support much larger
+ packets because these are more efficient in some applications.</P>
+</DD>
+<DT><A name="N">N</A></DT>
+<DT><A name="NAI">NAI</A></DT>
+<DD><A href="http://www.nai.com">Network Associates</A>, a conglomerate
+ formed from<A href="#PGPI"> PGP Inc.</A>, TIS (Trusted Information
+ Systems, a firewall vendor) and McAfee anti-virus products. Among other
+ things, they offer an IPsec-based VPN product.</DD>
+<DT><A name="NAT.gloss">NAT</A></DT>
+<DD><B>N</B>etwork<B> A</B>ddress<B> T</B>ranslation, a process by which
+ firewall machines may change the addresses on packets as they go
+ through. For discussion, see our<A href="#nat.background"> background</A>
+ section.</DD>
+<DT><A name="NIST">NIST</A></DT>
+<DD>The US<A href="http://www.nist.gov"> National Institute of Standards
+ and Technology</A>, responsible for<A href="#FIPS"> FIPS standards</A>
+ including<A href="#DES"> DES</A> and its replacement,<A href="#AES">
+ AES</A>.</DD>
+<DT><A name="nonce">Nonce</A></DT>
+<DD>A<A href="#random"> random</A> value used in an<A href="#authentication">
+ authentication</A> protocol.</DD>
+<DT></DT>
+<DT><A name="non-routable">Non-routable IP address</A></DT>
+<DD>An IP address not normally allowed in the &quot;to&quot; or &quot;from&quot; IP address
+ field header of IP packets.
+<P>Almost invariably, the phrase &quot;non-routable address&quot; means one of the
+ addresses reserved by RFC 1918 for private networks:</P>
+<UL>
+<LI>10.anything</LI>
+<LI>172.x.anything with 16 &lt;= x &lt;= 31</LI>
+<LI>192.168.anything</LI>
+</UL>
+<P>These addresses are commonly used on private networks, e.g. behind a
+ Linux machines doing<A href="#masq"> IP masquerade</A>. Machines within
+ the private network can address each other with these addresses. All
+ packets going outside that network, however, have these addresses
+ replaced before they reach the Internet.</P>
+<P>If any packets using these addresses do leak out, they do not go far.
+ Most routers automatically discard all such packets.</P>
+<P>Various other addresses -- the 127.0.0.0/8 block reserved for local
+ use, 0.0.0.0, various broadcast and network addresses -- cannot be
+ routed over the Internet, but are not normally included in the meaning
+ when the phrase &quot;non-routable address&quot; is used.</P>
+</DD>
+<DT><A name="NSA">NSA</A></DT>
+<DD>The US<A href="http://www.nsa.gov"> National Security Agency</A>,
+ the American organisation for<A href="#SIGINT"> signals intelligence</A>
+, the protection of US government messages and the interception and
+ analysis of other messages. For details, see Bamford's<A href="#puzzle">
+ &quot;The Puzzle Palace&quot;</A>.
+<P>Some<A href="http://www.gwu.edu/~nsarchiv/NSAEBB/NSAEBB23/index.html">
+ history of NSA</A> documents were declassified in response to a FOIA
+ (Freedom of Information Act) request.</P>
+</DD>
+<DT><A name="O">O</A></DT>
+<DT><A name="oakley">Oakley</A></DT>
+<DD>A key determination protocol, defined in RFC 2412.</DD>
+<DT>Oakley groups</DT>
+<DD>The groups used as the basis of<A href="#DH"> Diffie-Hellman</A> key
+ exchange in the Oakley protocol, and in<A href="#IKE"> IKE</A>. Four
+ were defined in the original RFC, and a fifth has been<A href="http://www.lounge.org/ike_doi_errata.html">
+ added since</A>.
+<P>Linux FreeS/WAN currently supports the three groups based on finite
+ fields modulo a prime (Groups 1, 2 and 5) and does not support the
+ elliptic curve groups (3 and 4). For a description of the difference of
+ the types, see<A href="#dlog"> discrete logarithms</A>.</P>
+</DD>
+<DT><A name="OTP">One time pad</A></DT>
+<DD>A cipher in which the key is:
+<UL>
+<LI>as long as the total set of messages to be enciphered</LI>
+<LI>absolutely<A href="#random"> random</A></LI>
+<LI>never re-used</LI>
+</UL>
+<P>Given those three conditions, it can easily be proved that the cipher
+ is perfectly secure, in the sense that an attacker with intercepted
+ message in hand has no better chance of guessing the message than an
+ attacker who has not intercepted the message and only knows the message
+ length. No such proof exists for any other cipher.</P>
+<P>There are, however, several problems with this &quot;perfect&quot; cipher.</P>
+<P>First, it is<STRONG> wildly impractical</STRONG> for most
+ applications. Key management is at best difficult, often completely
+ impossible.</P>
+<P>Second, it is<STRONG> extremely fragile</STRONG>. Small changes which
+ violate the conditions listed above do not just weaken the cipher
+ liitle. Quite often they destroy its security completely.</P>
+<UL>
+<LI>Re-using the pad weakens the cipher to the point where it can be
+ broken with pencil and paper. With a computer, the attack is trivially
+ easy.</LI>
+<LI>Using<EM> anything</EM> less than truly<A href="#random"> random</A>
+ numbers<EM> completely</EM> invalidates the security proof.</LI>
+<LI>In particular, using computer-generated pseudo-random numbers may
+ give an extremely weak cipher. It might also produce a good stream
+ cipher, if the pseudo-random generator is both well-designed and
+ properely seeded.</LI>
+</UL>
+<P>Marketing claims about the &quot;unbreakable&quot; security of various products
+ which somewhat resemble one-time pads are common. Such claims are one
+ of the surest signs of cryptographic<A href="#snake"> snake oil</A>;
+ most systems marketed with such claims are worthless.</P>
+<P>Finally, even if the system is implemented and used correctly, it is<STRONG>
+ highly vulnerable to a substitution attack</STRONG>. If an attacker
+ knows some plaintext and has an intercepted message, he can discover
+ the pad.</P>
+<UL>
+<LI>This does not matter if the attacker is just a<A href="#passive">
+ passive</A> eavesdropper. It gives him no plaintext he didn't already
+ know and we don't care that he learns a pad which we will never re-use.</LI>
+<LI>However, an<A href="#active"> active</A> attacker who knows the
+ plaintext can recover the pad, then use it to encode with whatever he
+ chooses. If he can get his version delivered instead of yours, this may
+ be a disaster. If you send &quot;attack at dawn&quot;, the delivered message can
+ be anything the same length -- perhaps &quot;retreat to east&quot; or &quot;shoot
+ generals&quot;.</LI>
+<LI>An active attacker with only a reasonable guess at the plaintext can
+ try the same attack. If the guess is correct, this works and the
+ attacker's bogus message is delivered. If the guess is wrong, a garbled
+ message is delivered.</LI>
+</UL>
+<P>In general then, despite its theoretical perfection, the one-time-pad
+ has very limited practical application.</P>
+<P>See also the<A href="http://pubweb.nfr.net/~mjr/pubs/otpfaq/"> one
+ time pad FAQ</A>.</P>
+</DD>
+<DT><A name="carpediem">Opportunistic encryption (OE)</A></DT>
+<DD>A situation in which any two IPsec-aware machines can secure their
+ communications, without a pre-shared secret and without a common<A href="#PKI">
+ PKI</A> or previous exchange of public keys. This is one of the goals
+ of the Linux FreeS/WAN project, discussed in our<A href="#goals">
+ introduction</A> section.
+<P>Setting up for opportunistic encryption is described in our<A href="#quickstart">
+ quickstart</A> document.</P>
+</DD>
+<DT><A name="responder">Opportunistic responder</A></DT>
+<DD>A host which accepts, but does not initiate, requests for<A HREF="#carpediem">
+ opportunistic encryption</A> (OE). An opportunistic responder has
+ enabled OE in its<A HREF="#passive.OE"> passive</A> form (pOE) only. A
+ web server or file server may be usefully set up as an opportunistic
+ responder.
+<P>Configuring passive OE is described in our<A href="#policygroups">
+ policy groups</A> document.</P>
+</DD>
+<DT><A name="orange">Orange book</A></DT>
+<DD>the most basic and best known of the US government's<A href="#rainbow">
+ Rainbow Book</A> series of computer security standards.</DD>
+<DT><A name="P">P</A></DT>
+<DT><A name="P1363">P1363 standard</A></DT>
+<DD>An<A href="#IEEE"> IEEE</A> standard for public key cryptography.<A href="http://grouper.ieee.org/groups/1363">
+ Web page</A>.</DD>
+<DT><A name="pOE">pOE</A></DT>
+<DD>See<A href="#passive.OE"> Passive opportunistic encryption</A>.</DD>
+<DT><A name="passive">Passive attack</A></DT>
+<DD>An attack in which the attacker only eavesdrops and attempts to
+ analyse intercepted messages, as opposed to an<A href="#active"> active
+ attack</A> in which he diverts messages or generates his own.</DD>
+<DT><A name="passive.OE">Passive opportunistic encryption (pOE)</A></DT>
+<DD>A form of<A HREF="#carpediem"> opportunistic encryption</A> (OE) in
+ which the host will accept opportunistic connection requests, but will
+ not initiate such requests. A host which runs OE in its passive form
+ only is known as an<A HREF="#responder"> opportunistic responder</A>.
+<P>Configuring passive OE is described in our<A href="#policygroups">
+ policy groups</A> document.</P>
+</DD>
+<DT><A name="pathMTU">Path MTU discovery</A></DT>
+<DD>The process of discovering the largest packet size which all links
+ on a path can handle without fragmentation -- that is, without any
+ router having to break the packet up into smaller pieces to match the<A href="#MTU">
+ MTU</A> of its outgoing link.
+<P>This is done as follows:</P>
+<UL>
+<LI>originator sends the largest packets allowed by<A href="#MTU"> MTU</A>
+ of the first link, setting the DF (<STRONG>d</STRONG>on't<STRONG> f</STRONG>
+ragment) bit in the packet header</LI>
+<LI>any router which cannot send the packet on (outgoing MTU is too
+ small for it, and DF prevents fragmenting it to match) sends back an<A href="#ICMP.gloss">
+ ICMP</A> packet reporting the problem</LI>
+<LI>originator looks at ICMP message and tries a smaller size</LI>
+<LI>eventually, you settle on a size that can pass all routers</LI>
+<LI>thereafter, originator just sends that size and no-one has to
+ fragment</LI>
+</UL>
+<P>Since this requires co-operation of many systems, and since the next
+ packet may travel a different path, this is one of the trickier areas
+ of IP programming. Bugs that have shown up over the years have
+ included:</P>
+<UL>
+<LI>malformed ICMP messages</LI>
+<LI>hosts that ignore or mishandle these ICMP messages</LI>
+<LI>firewalls blocking the ICMP messages so host does not see them</LI>
+</UL>
+<P>Since IPsec adds a header, it increases packet size and may require
+ fragmentation even where incoming and outgoing MTU are equal.</P>
+</DD>
+<DT><A name="PFS">Perfect forward secrecy (PFS)</A></DT>
+<DD>A property of systems such as<A href="#DH"> Diffie-Hellman</A> key
+ exchange which use a long-term key (such as the shared secret in IKE)
+ and generate short-term keys as required. If an attacker who acquires
+ the long-term key<EM> provably</EM> can
+<UL>
+<LI><EM>neither</EM> read previous messages which he may have archived</LI>
+<LI><EM>nor</EM> read future messages without performing additional
+ successful attacks</LI>
+</UL>
+<P>then the system has PFS. The attacker needs the short-term keys in
+ order to read the trafiic and merely having the long-term key does not
+ allow him to infer those. Of course, it may allow him to conduct
+ another attack (such as<A href="#middle"> man-in-the-middle</A>) which
+ gives him some short-term keys, but he does not automatically get them
+ just by acquiring the long-term key.</P>
+<P>See also<A href="http://sandelman.ottawa.on.ca/ipsec/1996/08/msg00123.html">
+ Phil Karn's definition</A>.</P>
+</DD>
+<DT>PFS</DT>
+<DD>see Perfect Forward Secrecy</DD>
+<DT><A name="PGP">PGP</A></DT>
+<DD><B>P</B>retty<B> G</B>ood<B> P</B>rivacy, a personal encryption
+ system for email based on public key technology, written by Phil
+ Zimmerman.
+<P>The 2.xx versions of PGP used the<A href="#RSA"> RSA</A> public key
+ algorithm and used<A href="#IDEA"> IDEA</A> as the symmetric cipher.
+ These versions are described in RFC 1991 and in<A href="#PGP">
+ Garfinkel's book</A>. Since version 5, the products from<A href="#PGPI">
+ PGP Inc</A>. have used<A href="#DH"> Diffie-Hellman</A> public key
+ methods and<A href="#CAST128"> CAST-128</A> symmetric encryption. These
+ can verify signatures from the 2.xx versions, but cannot exchange
+ encryted messages with them.</P>
+<P>An<A href="#IETF"> IETF</A> working group has issued RFC 2440 for an
+ &quot;Open PGP&quot; standard, similar to the 5.x versions. PGP Inc. staff were
+ among the authors. A free<A href="#GPG"> Gnu Privacy Guard</A> based on
+ that standard is now available.</P>
+<P>For more information on PGP, including how to obtain it, see our
+ cryptography<A href="#tools"> links</A>.</P>
+</DD>
+<DT><A name="PGPI">PGP Inc.</A></DT>
+<DD>A company founded by Zimmerman, the author of<A href="#PGP"> PGP</A>
+, now a division of<A href="#NAI"> NAI</A>. See the<A href="http://www.pgp.com">
+ corporate website</A>. Zimmerman left in 2001, and early in 2002 NAI
+ announced that they would no longer sell PGP..
+<P>Versions 6.5 and later of the PGP product include PGPnet, an IPsec
+ client for Macintosh or for Windows 95/98/NT. See our<A href="interop.html#pgpnet">
+ interoperation documen</A>t.</P>
+</DD>
+<DT><A name="photuris">Photuris</A></DT>
+<DD>Another key negotiation protocol, an alternative to<A href="#IKE">
+ IKE</A>, described in RFCs 2522 and 2523.</DD>
+<DT><A name="PPP">PPP</A></DT>
+<DD><B>P</B>oint-to-<B>P</B>oint<B> P</B>rotocol, originally a method of
+ connecting over modems or serial lines, but see also PPPoE.</DD>
+<DT><A name="PPPoE">PPPoE</A></DT>
+<DD><B>PPP</B><B> o</B>ver<B> E</B>thernet, a somewhat odd protocol that
+ makes Ethernet look like a point-to-point serial link. It is widely
+ used for cable or ADSL Internet services, apparently mainly because it
+ lets the providers use access control and address assignmment
+ mechanisms developed for dialup networks.<A href="http://www.roaringpenguin.com">
+ Roaring Penguin</A> provide a widely used Linux implementation.</DD>
+<DT><A name="PPTP">PPTP</A></DT>
+<DD><B>P</B>oint-to-<B>P</B>oint<B> T</B>unneling<B> P</B>rotocol, used
+ in some Microsoft VPN implementations. Papers discussing weaknesses in
+ it are on<A href="http://www.counterpane.com/publish.html">
+ counterpane.com</A>. It is now largely obsolete, replaced by L2TP.</DD>
+<DT><A name="PKI">PKI</A></DT>
+<DD><B>P</B>ublic<B> K</B>ey<B> I</B>nfrastructure, the things an
+ organisation or community needs to set up in order to make<A href="#public">
+ public key</A> cryptographic technology a standard part of their
+ operating procedures.
+<P>There are several PKI products on the market. Typically they use a
+ hierarchy of<A href="#CA"> Certification Authorities (CAs)</A>. Often
+ they use<A href="#LDAP"> LDAP</A> access to<A href="#X509"> X.509</A>
+ directories to implement this.</P>
+<P>See<A href="#web"> Web of Trust</A> for a different sort of
+ infrastructure.</P>
+</DD>
+<DT><A name="PKIX">PKIX</A></DT>
+<DD><B>PKI</B> e<B>X</B>change, an<A href="#IETF"> IETF</A> standard
+ that allows<A href="#PKI"> PKI</A>s to talk to each other.
+<P>This is required, for example, when users of a corporate PKI need to
+ communicate with people at client, supplier or government
+ organisations, any of which may have a different PKI in place. I should
+ be able to talk to you securely whenever:</P>
+<UL>
+<LI>your organisation and mine each have a PKI in place</LI>
+<LI>you and I are each set up to use those PKIs</LI>
+<LI>the two PKIs speak PKIX</LI>
+<LI>the configuration allows the conversation</LI>
+</UL>
+<P>At time of writing (March 1999), this is not yet widely implemented
+ but is under quite active development by several groups.</P>
+</DD>
+<DT><A name="plaintext">Plaintext</A></DT>
+<DD>The unencrypted input to a cipher, as opposed to the encrypted<A href="#ciphertext">
+ ciphertext</A> output.</DD>
+<DT><A name="Pluto">Pluto</A></DT>
+<DD>The<A href="#FreeSWAN"> Linux FreeS/WAN</A> daemon which handles key
+ exchange via the<A href="#IKE"> IKE</A> protocol, connection
+ negotiation, and other higher-level tasks. Pluto calls the<A href="#KLIPS">
+ KLIPS</A> kernel code as required. For details, see the manual page
+ ipsec_pluto(8).</DD>
+<DT><A name="public">Public Key Cryptography</A></DT>
+<DD>In public key cryptography, keys are created in matched pairs.
+ Encrypt with one half of a pair and only the matching other half can
+ decrypt it. This contrasts with<A href="#symmetric"> symmetric or
+ secret key cryptography</A> in which a single key known to both parties
+ is used for both encryption and decryption.
+<P>One half of each pair, called the public key, is made public. The
+ other half, called the private key, is kept secret. Messages can then
+ be sent by anyone who knows the public key to the holder of the private
+ key. Encrypt with the public key and you know that only someone with
+ the matching private key can decrypt.</P>
+<P>Public key techniques can be used to create<A href="#signature">
+ digital signatures</A> and to deal with key management issues, perhaps
+ the hardest part of effective deployment of<A href="#symmetric">
+ symmetric ciphers</A>. The resulting<A href="#hybrid"> hybrid
+ cryptosystems</A> use public key methods to manage keys for symmetric
+ ciphers.</P>
+<P>Many organisations are currently creating<A href="#PKI"> PKIs, public
+ key infrastructures</A> to make these benefits widely available.</P>
+</DD>
+<DT>Public Key Infrastructure</DT>
+<DD>see<A href="#PKI"> PKI</A></DD>
+<DT><A name="Q">Q</A></DT>
+<DT><A name="R">R</A></DT>
+<DT><A name="rainbow">Rainbow books</A></DT>
+<DD>A set of US government standards for evaluation of &quot;trusted computer
+ systems&quot;, of which the best known was the<A href="#orange"> Orange Book</A>
+. One fairly often hears references to &quot;C2 security&quot; or a product
+ &quot;evaluated at B1&quot;. The Rainbow books define the standards referred to
+ in those comments.
+<P>See this<A href="http://www.fas.org/irp/nsa/rainbow.htm"> reference
+ page</A>.</P>
+<P>The Rainbow books are now mainly obsolete, replaced by the
+ international<A href="#cc"> Common Criteria</A> standards.</P>
+</DD>
+<DT><A name="random">Random</A></DT>
+<DD>A remarkably tricky term, far too much so for me to attempt a
+ definition here. Quite a few cryptosystems have been broken via attacks
+ on weak random number generators, even when the rest of the system was
+ sound.
+<P>See<A href="http://nis.nsf.net/internet/documents/rfc/rfc1750.txt">
+ RFC 1750</A> for the theory.</P>
+<P>See the manual pages for<A href="manpage.d/ipsec_ranbits.8.html">
+ ipsec_ranbits(8)</A> and ipsec_prng(3) for more on FreeS/WAN's use of
+ randomness. Both depend on the random(4) device driver..</P>
+<P>A couple of years ago, there was extensive mailing list discussion
+ (archived<A href="http://www.openpgp.net/random/index.html"> here</A>
+)of Linux /dev/random and FreeS/WAN. Since then, the design of the
+ random(4) driver has changed considerably. Linux 2.4 kernels have the
+ new driver..</P>
+</DD>
+<DT>Raptor</DT>
+<DD>A firewall product for Windows NT offerring IPsec-based VPN
+ services. Linux FreeS/WAN interoperates with Raptor; see our<A href="#raptor">
+ interop</A> document for details. Raptor have recently merged with
+ Axent.</DD>
+<DT><A name="RC4">RC4</A></DT>
+<DD><B>R</B>ivest<B> C</B>ipher four, designed by Ron Rivest of<A href="#RSAco">
+ RSA</A> and widely used. Believed highly secure with adequate key
+ length, but often implemented with inadequate key length to comply with
+ export restrictions.</DD>
+<DT><A name="RC6">RC6</A></DT>
+<DD><B>R</B>ivest<B> C</B>ipher six,<A href="#RSAco"> RSA</A>'s<A href="#AES">
+ AES</A> candidate cipher.</DD>
+<DT><A name="replay">Replay attack</A></DT>
+<DD>An attack in which the attacker records data and later replays it in
+ an attempt to deceive the recipient.</DD>
+<DT><A name="reverse">Reverse map</A></DT>
+<DD>In<A href="#DNS"> DNS</A>, a table where IP addresses can be used as
+ the key for lookups which return a system name and/or other
+ information.</DD>
+<DT>RFC</DT>
+<DD><B>R</B>equest<B> F</B>or<B> C</B>omments, an Internet document.
+ Some RFCs are just informative. Others are standards.
+<P>Our list of<A href="#IPSEC"> IPsec</A> and other security-related
+ RFCs is<A href="#RFC"> here</A>, along with information on methods of
+ obtaining them.</P>
+</DD>
+<DT><A name="rijndael">Rijndael</A></DT>
+<DD>a<A href="#block"> block cipher</A> designed by two Belgian
+ cryptographers, winner of the US government's<A href="#AES"> AES</A>
+ contest to pick a replacement for<A href="#DES"> DES</A>. See the<A href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael">
+ Rijndael home page</A>.</DD>
+<DT><A name="RIPEMD">RIPEMD</A></DT>
+<DD>A<A href="#digest"> message digest</A> algorithm. The current
+ version is RIPEMD-160 which gives a 160-bit hash.</DD>
+<DT><A name="rootCA">Root CA</A></DT>
+<DD>The top level<A href="#CA"> Certification Authority</A> in a
+ hierachy of such authorities.</DD>
+<DT><A name="routable">Routable IP address</A></DT>
+<DD>Most IP addresses can be used as &quot;to&quot; and &quot;from&quot; addresses in packet
+ headers. These are the routable addresses; we expect routing to be
+ possible for them. If we send a packet to one of them, we expect (in
+ most cases; there are various complications) that it will be delivered
+ if the address is in use and will cause an<A href="#ICMP.gloss"> ICMP</A>
+ error packet to come back to us if not.
+<P>There are also several classes of<A href="#non-routable">
+ non-routable</A> IP addresses.</P>
+</DD>
+<DT><A name="RSA">RSA algorithm</A></DT>
+<DD><B>R</B>ivest<B> S</B>hamir<B> A</B>dleman<A href="#public"> public
+ key</A> algorithm, named for its three inventors. It is widely used and
+ likely to become moreso since it became free of patent encumbrances in
+ September 2000.
+<P>RSA can be used to provide either<A href="#encryption"> encryption</A>
+ or<A href="#signature"> digital signatures</A>. In IPsec, it is used
+ only for signatures. These provide gateway-to-gateway<A href="#authentication">
+ authentication</A> for<A href="#IKE"> IKE</A> negotiations.</P>
+<P>For a full explanation of the algorithm, consult one of the standard
+ references such as<A href="#schneier"> Applied Cryptography</A>. A
+ simple explanation is:</P>
+<P>The great 17th century French mathematician<A href="http://www-groups.dcs.st-andrews.ac.uk/~history/Mathematicians/Fermat.html">
+ Fermat</A> proved that,</P>
+<P>for any prime p and number x, 0 &lt;= x &lt; p:</P>
+<PRE> x^p == x modulo p
+ x^(p-1) == 1 modulo p, non-zero x
+ </PRE>
+<P>From this it follows that if we have a pair of primes p, q and two
+ numbers e, d such that:</P>
+<PRE> ed == 1 modulo lcm( p-1, q-1)
+ </PRE>
+ where lcm() is least common multiple, then
+<BR> for all x, 0 &lt;= x &lt; pq:
+<PRE> x^ed == x modulo pq
+ </PRE>
+<P>So we construct such as set of numbers p, q, e, d and publish the
+ product N=pq and e as the public key. Using c for<A href="#ciphertext">
+ ciphertext</A> and i for the input<A href="#plaintext"> plaintext</A>,
+ encryption is then:</P>
+<PRE> c = i^e modulo N
+ </PRE>
+<P>An attacker cannot deduce i from the cyphertext c, short of either
+ factoring N or solving the<A href="#dlog"> discrete logarithm</A>
+ problem for this field. If p, q are large primes (hundreds or thousands
+ of bits) no efficient solution to either problem is known.</P>
+<P>The receiver, knowing the private key (N and d), can readily recover
+ the plaintext p since:</P>
+<PRE> c^d == (i^e)^d modulo N
+ == i^ed modulo N
+ == i modulo N
+ </PRE>
+<P>This gives an effective public key technique, with only a couple of
+ problems. It uses a good deal of computer time, since calculations with
+ large integers are not cheap, and there is no proof it is necessarily
+ secure since no-one has proven either factoring or discrete log cannot
+ be done efficiently. Quite a few good mathematicians have tried both
+ problems, and no-one has announced success, but there is no proof they
+ are insoluble.</P>
+</DD>
+<DT><A name="RSAco">RSA Data Security</A></DT>
+<DD>A company founded by the inventors of the<A href="#RSA"> RSA</A>
+ public key algorithm.</DD>
+<DT><A name="S">S</A></DT>
+<DT><A name="SA">SA</A></DT>
+<DD><B>S</B>ecurity<B> A</B>ssociation, the channel negotiated by the
+ higher levels of an<A href="#IPSEC"> IPsec</A> implementation (<A href="#IKE">
+IKE</A>) and used by the lower (<A href="#ESP">ESP</A> and<A href="#AH">
+ AH</A>). SAs are unidirectional; you need a pair of them for two-way
+ communication.
+<P>An SA is defined by three things -- the destination, the protocol (<A href="#AH">
+AH</A> or<A href="#ESP">ESP</A>) and the<A href="SPI"> SPI</A>, security
+ parameters index. It is used as an index to look up other things such
+ as session keys and intialisation vectors.</P>
+<P>For more detail, see our section on<A href="ipsec.html"> IPsec</A>
+ and/or RFC 2401.</P>
+</DD>
+<DT><A name="SElinux">SE Linux</A></DT>
+<DD><STRONG>S</STRONG>ecurity<STRONG> E</STRONG>nhanced Linux, an<A href="#NSA">
+ NSA</A>-funded project to add<A href="#mandatory"> mandatory access
+ control</A> to Linux. See the<A href="http://www.nsa.gov/selinux">
+ project home page</A>.
+<P>According to their web pages, this work will include extending
+ mandatory access controls to IPsec tunnels.</P>
+<P>Recent versions of SE Linux code use the<A href="#LSM"> Linux
+ Security Module</A> interface.</P>
+</DD>
+<DT><A name="SDNS">Secure DNS</A></DT>
+<DD>A version of the<A href="#DNS"> DNS or Domain Name Service</A>
+ enhanced with authentication services. This is being designed by the<A href="#IETF">
+ IETF</A> DNS security<A href="http://www.ietf.org/ids.by.wg/dnssec.html">
+ working group</A>. Check the<A href="http://www.isc.org/bind.html">
+ Internet Software Consortium</A> for information on implementation
+ progress and for the latest version of<A href="#BIND"> BIND</A>.
+ Another site has<A href="http://www.toad.com/~dnssec"> more information</A>
+.
+<P><A href="#IPSEC">IPsec</A> can use this plus<A href="#DH">
+ Diffie-Hellman key exchange</A> to bootstrap itself. This allows<A href="#carpediem">
+ opportunistic encryption</A>. Any pair of machines which can
+ authenticate each other via DNS can communicate securely, without
+ either a pre-existing shared secret or a shared<A href="#PKI"> PKI</A>.</P>
+</DD>
+<DT>Secret key cryptography</DT>
+<DD>See<A href="#symmetric"> symmetric cryptography</A></DD>
+<DT>Security Association</DT>
+<DD>see<A href="#SA"> SA</A></DD>
+<DT>Security Enhanced Linux</DT>
+<DD>see<A href="#SElinux"> SE Linux</A></DD>
+<DT><A name="sequence">Sequence number</A></DT>
+<DD>A number added to a packet or message which indicates its position
+ in a sequence of packets or messages. This provides some security
+ against<A href="#replay"> replay attacks</A>.
+<P>For<A href="#auto"> automatic keying</A> mode, the<A href="#IPSEC">
+ IPsec</A> RFCs require that the sender generate sequence numbers for
+ each packet, but leave it optional whether the receiver does anything
+ with them.</P>
+</DD>
+<DT><A name="SHA">SHA</A></DT>
+<DT>SHA-1</DT>
+<DD><B>S</B>ecure<B> H</B>ash<B> A</B>lgorithm, a<A href="#digest">
+ message digest algorithm</A> developed by the<A href="#NSA"> NSA</A>
+ for use in the Digital Signature standard,<A href="#FIPS"> FIPS</A>
+ number 186 from<A href="#NIST"> NIST</A>. SHA is an improved variant of<A
+href="#MD4"> MD4</A> producing a 160-bit hash.
+<P>SHA is one of two message digest algorithms available in IPsec. The
+ other is<A href="#MD5"> MD5</A>. Some people do not trust SHA because
+ it was developed by the<A href="#NSA"> NSA</A>. There is, as far as we
+ know, no cryptographic evidence that SHA is untrustworthy, but this
+ does not prevent that view from being strongly held.</P>
+<P>The NSA made one small change after the release of the original SHA.
+ They did not give reasons. Iit may be a defense against some attack
+ they found and do not wish to disclose. Technically the modified
+ algorithm should be called SHA-1, but since it has replaced the
+ original algorithm in nearly all applications, it is generally just
+ referred to as SHA..</P>
+</DD>
+<DT><A name="SHA-256">SHA-256</A></DT>
+<DT>SHA-384</DT>
+<DT>SHA-512</DT>
+<DD>Newer variants of SHA designed to match the strength of the 128, 192
+ and 256-bit keys of<A href="#AES"> AES</A>. The work to break an
+ encryption algorithm's strength by<A href="#brute"> brute force</A> is
+ 2
+<!--math xmlns="http://www.w3.org/1998/Math/MathML"-->
+
+<!--msup-->
+
+<!--mi-->
+ keylength</(null)></(null)></(null)> operations but a<A href="birthday">
+ birthday attack</A> on a hash needs only 2
+<!--math xmlns="http://www.w3.org/1998/Math/MathML"-->
+
+<!--msup-->
+
+<!--mrow-->
+
+<!--mi-->
+ hashlength</(null)>
+<!--mo-->
+ /</(null)>
+<!--mn-->
+
+ 2</(null)></(null)></(null)></(null)> , so as a general rule you need a
+ hash twice the size of the key to get similar strength. SHA-256,
+ SHA-384 and SHA-512 are designed to match the 128, 192 and 256-bit key
+ sizes of AES, respectively.</DD>
+<DT><A name="SIGINT">Signals intelligence (SIGINT)</A></DT>
+<DD>Activities of government agencies from various nations aimed at
+ protecting their own communications and reading those of others.
+ Cryptography, cryptanalysis, wiretapping, interception and monitoring
+ of various sorts of signals. The players include the American<A href="#NSA">
+ NSA</A>, British<A href="#GCHQ"> GCHQ</A> and Canadian<A href="#CSE">
+ CSE</A>.</DD>
+<DT><A name="SKIP">SKIP</A></DT>
+<DD><B>S</B>imple<B> K</B>ey management for<B> I</B>nternet<B> P</B>
+rotocols, an alternative to<A href="#IKE"> IKE</A> developed by Sun and
+ being marketed by their<A href="http://skip.incog.com"> Internet
+ Commerce Group</A>.</DD>
+<DT><A name="snake">Snake oil</A></DT>
+<DD>Bogus cryptography. See the<A href="http://www.interhack.net/people/cmcurtin/snake-oil-faq.html">
+ Snake Oil FAQ</A> or<A href="http://www.counterpane.com/crypto-gram-9902.html#snakeoil">
+ this paper</A> by Schneier.</DD>
+<DT><A name="SPI">SPI</A></DT>
+<DD><B>S</B>ecurity<B> P</B>arameter<B> I</B>ndex, an index used within<A
+href="#IPSEC"> IPsec</A> to keep connections distinct. A<A href="#SA">
+ Security Association (SA)</A> is defined by destination, protocol and
+ SPI. Without the SPI, two connections to the same gateway using the
+ same protocol could not be distinguished.
+<P>For more detail, see our<A href="ipsec.html"> IPsec</A> section
+ and/or RFC 2401.</P>
+</DD>
+<DT><A name="SSH">SSH</A></DT>
+<DD><B>S</B>ecure<B> SH</B>ell, an encrypting replacement for the
+ insecure Berkeley commands whose names begin with &quot;r&quot; for &quot;remote&quot;:
+ rsh, rlogin, etc.
+<P>For more information on SSH, including how to obtain it, see our
+ cryptography<A href="#tools"> links</A>.</P>
+</DD>
+<DT><A name="SSHco">SSH Communications Security</A></DT>
+<DD>A company founded by the authors of<A href="#SSH"> SSH</A>. Offices
+ are in<A href="http://www.ssh.fi"> Finland</A> and<A href="http://www.ipsec.com">
+ California</A>. They have a toolkit for developers of IPsec
+ applications.</DD>
+<DT><A name="SSL">SSL</A></DT>
+<DD><A href="http://home.netscape.com/eng/ssl3">Secure Sockets Layer</A>
+, a set of encryption and authentication services for web browsers,
+ developed by Netscape. Widely used in Internet commerce. Also known as<A
+href="#TLS"> TLS</A>.</DD>
+<DT>SSLeay</DT>
+<DD>A free implementation of<A href="#SSL"> SSL</A> by Eric Young (eay)
+ and others. Developed in Australia; not subject to US export controls.</DD>
+<DT><A name="static">static IP address</A></DT>
+<DD>an IP adddress which is pre-set on the machine itself, as opposed to
+ a<A href="#dynamic"> dynamic address</A> which is assigned by a<A href="#DHCP">
+ DHCP</A> server or obtained as part of the process of establishing a<A href="#PPP">
+ PPP</A> or<A href="#PPPoE"> PPPoE</A> connection</DD>
+<DT><A name="stream">Stream cipher</A></DT>
+<DD>A<A href="#symmetric"> symmetric cipher</A> which produces a stream
+ of output which can be combined (often using XOR or bytewise addition)
+ with the plaintext to produce ciphertext. Contrasts with<A href="#block">
+ block cipher</A>.
+<P><A href="#IPSEC">IPsec</A> does not use stream ciphers. Their main
+ application is link-level encryption, for example of voice, video or
+ data streams on a wire or a radio signal.</P>
+</DD>
+<DT><A name="subnet">subnet</A></DT>
+<DD>A group of IP addresses which are logically one network, typically
+ (but not always) assigned to a group of physically connected machines.
+ The range of addresses in a subnet is described using a subnet mask.
+ See next entry.</DD>
+<DT>subnet mask</DT>
+<DD>A method of indicating the addresses included in a subnet. Here are
+ two equivalent examples:
+<UL>
+<LI>101.101.101.0/24</LI>
+<LI>101.101.101.0 with mask 255.255.255.0</LI>
+</UL>
+<P>The '24' is shorthand for a mask with the top 24 bits one and the
+ rest zero. This is exactly the same as 255.255.255.0 which has three
+ all-ones bytes and one all-zeros byte.</P>
+<P>These indicate that, for this range of addresses, the top 24 bits are
+ to be treated as naming a network (often referred to as &quot;the
+ 101.101.101.0/24 subnet&quot;) while most combinations of the low 8 bits can
+ be used to designate machines on that network. Two addresses are
+ reserved; 101.101.101.0 refers to the subnet rather than a specific
+ machine while 101.101.101.255 is a broadcast address. 1 to 254 are
+ available for machines.</P>
+<P>It is common to find subnets arranged in a hierarchy. For example, a
+ large company might have a /16 subnet and allocate /24 subnets within
+ that to departments. An ISP might have a large subnet and allocate /26
+ subnets (64 addresses, 62 usable) to business customers and /29 subnets
+ (8 addresses, 6 usable) to residential clients.</P>
+</DD>
+<DT><A name="SWAN">S/WAN</A></DT>
+<DD>Secure Wide Area Network, a project involving<A href="#RSAco"> RSA
+ Data Security</A> and a number of other companies. The goal was to
+ ensure that all their<A href="#IPSEC"> IPsec</A> implementations would
+ interoperate so that their customers can communicate with each other
+ securely.</DD>
+<DT><A name="symmetric">Symmetric cryptography</A></DT>
+<DD>Symmetric cryptography, also referred to as conventional or secret
+ key cryptography, relies on a<EM> shared secret key</EM>, identical for
+ sender and receiver. Sender encrypts with that key, receiver decrypts
+ with it. The idea is that an eavesdropper without the key be unable to
+ read the messages. There are two main types of symmetric cipher,<A href="#block">
+ block ciphers</A> and<A href="#stream"> stream ciphers</A>.
+<P>Symmetric cryptography contrasts with<A href="#public"> public key</A>
+ or asymmetric systems where the two players use different keys.</P>
+<P>The great difficulty in symmetric cryptography is, of course, key
+ management. Sender and receiver<EM> must</EM> have identical keys and
+ those keys<EM> must</EM> be kept secret from everyone else. Not too
+ much of a problem if only two people are involved and they can
+ conveniently meet privately or employ a trusted courier. Quite a
+ problem, though, in other circumstances.</P>
+<P>It gets much worse if there are many people. An application might be
+ written to use only one key for communication among 100 people, for
+ example, but there would be serious problems. Do you actually trust all
+ of them that much? Do they trust each other that much? Should they?
+ What is at risk if that key is compromised? How are you going to
+ distribute that key to everyone without risking its secrecy? What do
+ you do when one of them leaves the company? Will you even know?</P>
+<P>On the other hand, if you need unique keys for every possible
+ connection between a group of 100, then each user must have 99 keys.
+ You need either 99*100/2 = 4950<EM> secure</EM> key exchanges between
+ users or a central authority that<EM> securely</EM> distributes 100 key
+ packets, each with a different set of 99 keys.</P>
+<P>Either of these is possible, though tricky, for 100 users. Either
+ becomes an administrative nightmare for larger numbers. Moreover, keys<EM>
+ must</EM> be changed regularly, so the problem of key distribution
+ comes up again and again. If you use the same key for many messages
+ then an attacker has more text to work with in an attempt to crack that
+ key. Moreover, one successful crack will give him or her the text of
+ all those messages.</P>
+<P>In short, the<EM> hardest part of conventional cryptography is key
+ management</EM>. Today the standard solution is to build a<A href="#hybrid">
+ hybrid system</A> using<A href="#public"> public key</A> techniques to
+ manage keys.</P>
+</DD>
+<DT><A name="T">T</A></DT>
+<DT><A name="TIS">TIS</A></DT>
+<DD>Trusted Information Systems, a firewall vendor now part of<A href="#NAI">
+ NAI</A>. Their Gauntlet product offers IPsec VPN services. TIS
+ implemented the first version of<A href="#SDNS"> Secure DNS</A> on a<A href="#DARPA">
+ DARPA</A> contract.</DD>
+<DT><A name="TLS">TLS</A></DT>
+<DD><B>T</B>ransport<B> L</B>ayer<B> S</B>ecurity, a newer name for<A href="#SSL">
+ SSL</A>.</DD>
+<DT><A name="TOS">TOS field</A></DT>
+<DD>The<STRONG> T</STRONG>ype<STRONG> O</STRONG>f<STRONG> S</STRONG>
+ervice field in an IP header, used to control qualkity of service
+ routing.</DD>
+<DT><A name="traffic">Traffic analysis</A></DT>
+<DD>Deducing useful intelligence from patterns of message traffic,
+ without breaking codes or reading the messages. In one case during
+ World War II, the British guessed an attack was coming because all
+ German radio traffic stopped. The &quot;radio silence&quot; order, intended to
+ preserve security, actually gave the game away.
+<P>In an industrial espionage situation, one might deduce something
+ interesting just by knowing that company A and company B were talking,
+ especially if one were able to tell which departments were involved, or
+ if one already knew that A was looking for acquisitions and B was
+ seeking funds for expansion.</P>
+<P>In general, traffic analysis by itself is not very useful. However,
+ in the context of a larger intelligence effort where quite a bit is
+ already known, it can be very useful. When you are solving a complex
+ puzzle, every little bit helps.</P>
+<P><A href="#IPSEC">IPsec</A> itself does not defend against traffic
+ analysis, but carefully thought out systems using IPsec can provide at
+ least partial protection. In particular, one might want to encrypt more
+ traffic than was strictly necessary, route things in odd ways, or even
+ encrypt dummy packets, to confuse the analyst. We discuss this<A href="#traffic.resist">
+ here</A>.</P>
+</DD>
+<DT><A name="transport">Transport mode</A></DT>
+<DD>An IPsec application in which the IPsec gateway is the destination
+ of the protected packets, a machine acts as its own gateway. Contrast
+ with<A href="#tunnel"> tunnel mode</A>.</DD>
+<DT>Triple DES</DT>
+<DD>see<A href="#3DES"> 3DES</A></DD>
+<DT><A name="TTL">TTL</A></DT>
+<DD><STRONG>T</STRONG>ime<STRONG> T</STRONG>o<STRONG> L</STRONG>ive,
+ used to control<A href="#DNS"> DNS</A> caching. Servers discard cached
+ records whose TTL expires</DD>
+<DT><A name="tunnel">Tunnel mode</A></DT>
+<DD>An IPsec application in which an IPsec gateway provides protection
+ for packets to and from other systems. Contrast with<A href="#transport">
+ transport mode</A>.</DD>
+<DT><A name="2key">Two-key Triple DES</A></DT>
+<DD>A variant of<A href="#3DES"> triple DES or 3DES</A> in which only
+ two keys are used. As in the three-key version, the order of operations
+ is<A href="#EDE"> EDE</A> or encrypt-decrypt-encrypt, but in the
+ two-key variant the first and third keys are the same.
+<P>3DES with three keys has 3*56 = 168 bits of key but has only 112-bit
+ strength against a<A href="#meet"> meet-in-the-middle</A> attack, so it
+ is possible that the two key version is just as strong. Last I looked,
+ this was an open question in the research literature.</P>
+<P>RFC 2451 defines triple DES for<A href="#IPSEC"> IPsec</A> as the
+ three-key variant. The two-key variant should not be used and is not
+ implemented directly in<A href="#FreeSWAN"> Linux FreeS/WAN</A>. It
+ cannot be used in automatically keyed mode without major fiddles in the
+ source code. For manually keyed connections, you could make Linux
+ FreeS/WAN talk to a two-key implementation by setting two keys the same
+ in /etc/ipsec.conf.</P>
+</DD>
+<DT><A name="U">U</A></DT>
+<DT><A name="V">V</A></DT>
+<DT><A name="virtual">Virtual Interface</A></DT>
+<DD>A<A href="#Linux"> Linux</A> feature which allows one physical
+ network interface to have two or more IP addresses. See the<CITE> Linux
+ Network Administrator's Guide</CITE> in<A href="#kirch"> book form</A>
+ or<A href="http://metalab.unc.edu/LDP/LDP/nag/node1.html"> on the web</A>
+ for details.</DD>
+<DT>Virtual Private Network</DT>
+<DD>see<A href="#VPN"> VPN</A></DD>
+<DT><A name="VPN">VPN</A></DT>
+<DD><B>V</B>irtual<B> P</B>rivate<B> N</B>etwork, a network which can
+ safely be used as if it were private, even though some of its
+ communication uses insecure connections. All traffic on those
+ connections is encrypted.
+<P><A href="#IPSEC">IPsec</A> is not the only technique available for
+ building VPNs, but it is the only method defined by<A href="#RFC"> RFCs</A>
+ and supported by many vendors. VPNs are by no means the only thing you
+ can do with IPsec, but they may be the most important application for
+ many users.</P>
+</DD>
+<DT><A name="VPNC">VPNC</A></DT>
+<DD><A href="http://www.vpnc.org">Virtual Private Network Consortium</A>
+, an association of vendors of VPN products.</DD>
+<DT><A name="W">W</A></DT>
+<DT><A name="Wassenaar.gloss">Wassenaar Arrangement</A></DT>
+<DD>An international agreement restricting export of munitions and other
+ tools of war. Unfortunately, cryptographic software is also restricted
+ under the current version of the agreement.<A href="#Wassenaar">
+ Discussion</A>.</DD>
+<DT><A name="web">Web of Trust</A></DT>
+<DD><A href="#PGP">PGP</A>'s method of certifying keys. Any user can
+ sign a key; you decide which signatures or combinations of signatures
+ to accept as certification. This contrasts with the hierarchy of<A href="#CA">
+ CAs (Certification Authorities)</A> used in many<A href="#PKI"> PKIs
+ (Public Key Infrastructures)</A>.
+<P>See<A href="#GTR"> Global Trust Register</A> for an interesting
+ addition to the web of trust.</P>
+</DD>
+<DT><A name="WEP">WEP (Wired Equivalent Privacy)</A></DT>
+<DD>The cryptographic part of the<A href="#IEEE"> IEEE</A> standard for
+ wireless LANs. As the name suggests, this is designed to be only as
+ secure as a normal wired ethernet. Anyone with a network conection can
+ tap it. Its advocates would claim this is good design, refusing to
+ build in complex features beyond the actual requirements.
+<P>Critics refer to WEP as &quot;Wire<EM>tap</EM> Equivalent Privacy&quot;, and
+ consider it a horribly flawed design based on bogus &quot;requirements&quot;. You
+ do not control radio waves as you might control your wires, so the
+ metaphor in the rationale is utterly inapplicable. A security policy
+ that chooses not to invest resources in protecting against certain
+ attacks which can only be conducted by people physically plugged into
+ your LAN may or may not be reasonable. The same policy is completely
+ unreasonable when someone can &quot;plug in&quot; from a laptop half a block
+ away..</P>
+<P>There has been considerable analysis indicating that WEP is seriously
+ flawed. A FAQ on attacks against WEP is available. Part of it reads:</P>
+<BLOCKQUOTE> ... attacks are practical to mount using only inexpensive
+ off-the-shelf equipment. We recommend that anyone using an 802.11
+ wireless network not rely on WEP for security, and employ other
+ security measures to protect their wireless network. Note that our
+ attacks apply to both 40-bit and the so-called 128-bit versions of WEP
+ equally well.</BLOCKQUOTE>
+<P>WEP appears to be yet another instance of governments, and
+ unfortunately some vendors and standards bodies, deliberately promoting
+ hopelessly flawed &quot;security&quot; products, apparently mainly for the
+ benefit of eavesdropping agencies. See this<A href="#weak"> discussion</A>
+.</P>
+</DD>
+<DT><A name="X">X</A></DT>
+<DT><A name="X509">X.509</A></DT>
+<DD>A standard from the<A href="http://www.itu.int"> ITU (International
+ Telecommunication Union)</A>, for hierarchical directories with
+ authentication services, used in many<A href="#PKI"> PKI</A>
+ implementations.
+<P>Use of X.509 services, via the<A href="#LDAP"> LDAP protocol</A>, for
+ certification of keys is allowed but not required by the<A href="#IPSEC">
+ IPsec</A> RFCs. It is not yet implemented in<A href="#FreeSWAN"> Linux
+ FreeS/WAN</A>.</P>
+</DD>
+<DT>Xedia</DT>
+<DD>A vendor of router and Internet access products, now part of Lucent.
+ Their QVPN products interoperate with Linux FreeS/WAN; see our<A href="#xedia">
+ interop document</A>.</DD>
+<DT><A name="Y">Y</A></DT>
+<DT><A name="Z">Z</A></DT>
+</DL>
+<HR>
+<H1><A name="biblio">Bibliography for the Linux FreeS/WAN project</A></H1>
+<P>For extensive bibliographic links, see the<A href="http://liinwww.ira.uka.de/bibliography/index.html">
+ Collection of Computer Science Bibliographies</A></P>
+<P>See our<A href="web.html"> web links</A> for material available
+ online.</P>
+<HR><A name="adams"> Carlisle Adams and Steve Lloyd<CITE> Understanding
+ Public Key Infrastructure</CITE>
+<BR></A> Macmillan 1999 ISBN 1-57870-166-x
+<P>An overview, mainly concentrating on policy and strategic issues
+ rather than the technical details. Both authors work for<A href="#PKI">
+ PKI</A> vendor<A href="http://www.entrust.com/"> Entrust</A>.</P>
+<HR><A name="DNS.book"> Albitz, Liu &amp; Loukides<CITE> DNS &amp; BIND</CITE>
+ 3rd edition
+<BR></A> O'Reilly 1998 ISBN 1-56592-512-2
+<P>The standard reference on the<A href="#DNS"> Domain Name Service</A>
+ and<A href="#BIND"> Berkeley Internet Name Daemon</A>.</P>
+<HR><A name="anderson"> Ross Anderson</A>,<CITE> Security Engineering -
+ a Guide to Building Dependable Distributed Systems</CITE>
+<BR> Wiley, 2001, ISBN 0471389226
+<P>Easily the best book for the security professional I have seen.<STRONG>
+ Highly recommended</STRONG>. See the<A href="http://www.cl.cam.ac.uk/~rja14/book.html">
+ book web page</A>.</P>
+<P>This is quite readable, but Schneier's<A href="#secrets"> Secrets and
+ Lies</A> might be an easier introduction.</P>
+<HR><A name="puzzle"> Bamford<CITE> The Puzzle Palace, A report on NSA,
+ Americas's most Secret Agency</CITE>
+<BR> Houghton Mifflin 1982 ISBN 0-395-31286-8</A>
+<HR> Bamford<CITE> Body of Secrets</CITE>
+<P>The sequel.</P>
+<HR><A name="bander"> David Bander</A>,<CITE> Linux Security Toolkit</CITE>
+<BR> IDG Books, 2000, ISBN: 0764546902
+<P>This book has a short section on FreeS/WAN and includes Caldera Linux
+ on CD.</P>
+<HR><A name="CZR"> Chapman, Zwicky &amp; Russell</A>,<CITE> Building
+ Internet Firewalls</CITE>
+<BR> O'Reilly 1995 ISBN 1-56592-124-0
+<HR><A name="firewall.book"> Cheswick and Bellovin</A><CITE> Firewalls
+ and Internet Security: Repelling the Wily Hacker</CITE>
+<BR> Addison-Wesley 1994 ISBN 0201633574
+<P>A fine book on firewalls in particular and security in general from
+ two of AT&amp;T's system adminstrators.</P>
+<P>Bellovin has also done a number of<A href="#papers"> papers</A> on
+ IPsec and co-authored a<A href="#applied"> paper</A> on a large
+ FreeS/WAN application.</P>
+<HR><A name="comer"> Comer<CITE> Internetworking with TCP/IP</CITE>
+<BR> Prentice Hall</A>
+<UL>
+<LI>Vol. I: Principles, Protocols, &amp; Architecture, 3rd Ed. 1995
+ ISBN:0-13-216987-8</LI>
+<LI>Vol. II: Design, Implementation, &amp; Internals, 2nd Ed. 1994
+ ISBN:0-13-125527-4</LI>
+<LI>Vol. III: Client/Server Programming &amp; Applications
+<UL>
+<LI>AT&amp;T TLI Version 1994 ISBN:0-13-474230-3</LI>
+<LI>BSD Socket Version 1996 ISBN:0-13-260969-X</LI>
+<LI>Windows Sockets Version 1997 ISBN:0-13-848714-6</LI>
+</UL>
+</LI>
+</UL>
+<P>If you need to deal with the details of the network protocols, read
+ either this series or the<A href="#stevens"> Stevens and Wright</A>
+ series before you start reading the RFCs.</P>
+<HR><A name="diffie"> Diffie and Landau</A><CITE> Privacy on the Line:
+ The Politics of Wiretapping and Encryption</CITE>
+<BR> MIT press 1998 ISBN 0-262-04167-7 (hardcover) or 0-262-54100-9
+<BR>
+<HR><A name="d_and_hark"> Doraswamy and Harkins<CITE> IP Sec: The New
+ Security Standard for the Internet, Intranets and Virtual Private
+ Networks</CITE>
+<BR> Prentice Hall 1999 ISBN: 0130118982</A>
+<HR><A name="EFF"> Electronic Frontier Foundation<CITE> Cracking DES:
+ Secrets of Encryption Research, Wiretap Politics and Chip Design</CITE>
+<BR></A> O'Reilly 1998 ISBN 1-56592-520-3
+<P>To conclusively demonstrate that DES is inadequate for continued use,
+ the<A href="#EFF"> EFF</A> built a machine for just over $200,000 that
+ breaks DES encryption in under five days on average, under nine in the
+ worst case.</P>
+<P>The book provides details of their design and, perhaps even more
+ important, discusses why they felt the project was necessary.
+ Recommended for anyone interested in any of the three topics mentioned
+ in the subtitle.</P>
+<P>See also the<A href="http://www.eff.org/descracker.html"> EFF page on
+ this project</A> and our discussion of<A href="#desnotsecure"> DES
+ insecurity</A>.</P>
+<HR> Martin Freiss<CITE> Protecting Networks with SATAN</CITE>
+<BR> O'Reilly 1998 ISBN 1-56592-425-8
+<BR> translated from a 1996 work in German
+<P>SATAN is a Security Administrator's Tool for Analysing Networks. This
+ book is a tutorial in its use.</P>
+<HR> Gaidosch and Kunzinger<CITE> A Guide to Virtual Private Networks</CITE>
+<BR> Prentice Hall 1999 ISBN: 0130839647
+<HR><A name="Garfinkel"> Simson Garfinkel</A><CITE> Database Nation: the
+ death of privacy in the 21st century</CITE>
+<BR> O'Reilly 2000 ISBN 1-56592-653-6
+<P>A thoughtful and rather scary book.</P>
+<HR><A name="PGP"> Simson Garfinkel</A><CITE> PGP: Pretty Good Privacy</CITE>
+<BR> O'Reilly 1995 ISBN 1-56592-098-8
+<P>An excellent introduction and user manual for the<A href="#PGP"> PGP</A>
+ email-encryption package. PGP is a good package with a complex and
+ poorly-designed user interface. This book or one like it is a must for
+ anyone who has to use it at length.</P>
+<P>The book covers using PGP in Unix, PC and Macintosh environments,
+ plus considerable background material on both the technical and
+ political issues around cryptography.</P>
+<P>The book is now seriously out of date. It does not cover recent
+ developments such as commercial versions since PGP 5, the Open PGP
+ standard or GNU PG..</P>
+<HR><A name="practical"> Garfinkel and Spafford</A><CITE> Practical Unix
+ Security</CITE>
+<BR> O'Reilly 1996 ISBN 1-56592-148-8
+<P>A standard reference.</P>
+<P>Spafford's web page has an excellent collection of<A href="http://www.cs.purdue.edu/coast/hotlist">
+ crypto and security links</A>.</P>
+<HR><A name="Kahn"> David Kahn</A><CITE> The Codebreakers: the
+ Comprehensive History of Secret Communications from Ancient Times to
+ the Internet</CITE>
+<BR> second edition Scribner 1996 ISBN 0684831309
+<P>A history of codes and code-breaking from ancient Egypt to the 20th
+ century. Well-written and exhaustively researched.<STRONG> Highly
+ recommended</STRONG>, even though it does not have much on computer
+ cryptography.</P>
+<HR> David Kahn<CITE> Seizing the Enigma, The Race to Break the German
+ U-Boat codes, 1939-1943</CITE>
+<BR> Houghton Mifflin 1991 ISBN 0-395-42739-8
+<HR><A name="kirch"> Olaf Kirch</A><CITE> Linux Network Administrator's
+ Guide</CITE>
+<BR> O'Reilly 1995 ISBN 1-56592-087-2
+<P>Now becoming somewhat dated in places, but still a good introductory
+ book and general reference.</P>
+<HR><A name="LinVPN"> Kolesnikov and Hatch</A>,<CITE> Building Linux
+ Virtual Private Networks (VPNs)</CITE>
+<BR> New Riders 2002
+<P>This has had a number of favorable reviews, including<A href="http://www.slashdot.org/article.pl?sid=02/02/27/0115214&amp;mode=thread&amp;tid=172">
+ this one</A> on Slashdot. The book has a<A href="http://www.buildinglinuxvpns.net/">
+ web site</A>.</P>
+<HR><A name="RFCs"> Pete Loshin<CITE> Big Book of IPsec RFCs</CITE>
+<BR> Morgan Kaufmann 2000 ISBN: 0-12-455839-9</A>
+<HR><A name="crypto"> Steven Levy<CITE> Crypto: How the Code Rebels Beat
+ the Government -- Saving Privacy in the Digital Age</CITE></A>
+<BR> Penguin 2001, ISBN 0-670--85950-8
+<P><STRONG>Highly recommended</STRONG>. A fine history of recent (about
+ 1970-2000) developments in the field, and the related political
+ controversies. FreeS/WAN project founder and leader John Gilmore
+ appears several times.</P>
+<P>The book does not cover IPsec or FreeS/WAN, but this project is very
+ much another battle in the same war. See our discussion of the<A href="politics.html">
+ politics</A>.</P>
+<HR><A name="GTR"> Matyas, Anderson et al.</A><CITE> The Global Trust
+ Register</CITE>
+<BR> Northgate Consultants Ltd 1998 ISBN: 0953239705
+<BR> hard cover edition MIT Press 1999 ISBN 0262511053
+<P>From<A href="http://www.cl.cam.ac.uk/Research/Security/Trust-Register">
+ their web page:</A></P>
+<BLOCKQUOTE> This book is a register of the fingerprints of the world's
+ most important public keys; it implements a top-level certification
+ authority (CA) using paper and ink rather than in an electronic system.</BLOCKQUOTE>
+<HR><A name="handbook"> Menezies, van Oorschot and Vanstone<CITE>
+ Handbook of Applied Cryptography</CITE></A>
+<BR> CRC Press 1997
+<BR> ISBN 0-8493-8523-7
+<P>An excellent reference. Read<A href="#schneier"> Schneier</A> before
+ tackling this.</P>
+<HR> Michael Padlipsky<CITE> Elements of Networking Style</CITE>
+<BR> Prentice-Hall 1985 ISBN 0-13-268111-0 or 0-13-268129-3
+<P>Probably<STRONG> the funniest technical book ever written</STRONG>,
+ this is a vicious but well-reasoned attack on the OSI &quot;seven layer
+ model&quot; and all that went with it. Several chapters of it are also
+ available as RFCs 871 to 875.</P>
+<HR><A name="matrix"> John S. Quarterman</A><CITE> The Matrix: Computer
+ Networks and Conferencing Systems Worldwide</CITE>
+<BR> Digital Press 1990 ISBN 155558-033-5
+<BR> Prentice-Hall ISBN 0-13-565607-9
+<P>The best general treatment of computer-mediated communication we have
+ seen. It naturally has much to say about the Internet, but also covers
+ UUCP, Fidonet and so on.</P>
+<HR><A name="ranch"> David Ranch</A><CITE> Securing Linux Step by Step</CITE>
+<BR> SANS Institute, 1999
+<P><A href="http://www.sans.org/">SANS</A> is a respected organisation,
+ this guide is part of a well-known series, and Ranch has previously
+ written the useful<A href=" http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos">
+ Trinity OS</A> guide to securing Linux, so my guess would be this is a
+ pretty good book. I haven't read it yet, so I'm not certain. It can be
+ ordered online from<A href="http://www.sans.org/"> SANS</A>.</P>
+<P>Note (Mar 1, 2002): a new edition with different editors in the
+ works. Expect it this year.</P>
+<HR><A name="schneier"> Bruce Schneier</A><CITE> Applied Cryptography,
+ Second Edition</CITE>
+<BR> John Wiley &amp; Sons, 1996
+<BR> ISBN 0-471-12845-7 hardcover
+<BR> ISBN 0-471-11709-9 paperback
+<P>A standard reference on computer cryptography. For more recent
+ essays, see the<A href="http://www.counterpane.com/"> author's
+ company's web site</A>.</P>
+<HR><A name="secrets"> Bruce Schneier</A><CITE> Secrets and Lies</CITE>
+<BR> Wiley 2000, ISBN 0-471-25311-1
+<P>An interesting discussion of security and privacy issues, written
+ with more of an &quot;executive overview&quot; approach rather than a narrow
+ focus on the technical issues.<STRONG> Highly recommended</STRONG>.</P>
+<P>This is worth reading even if you already understand security issues,
+ or think you do. To go deeper, follow it with Anderson's<A href="#anderson">
+ Security Engineering</A>.</P>
+<HR><A name="VPNbook"> Scott, Wolfe and Irwin<CITE> Virtual Private
+ Networks</CITE></A>
+<BR> 2nd edition, O'Reilly 1999 ISBN: 1-56592-529-7
+<P>This is the only O'Reilly book, out of a dozen I own, that I'm
+ disappointed with. It deals mainly with building VPNs with various
+ proprietary tools --<A href="#PPTP"> PPTP</A>,<A href="#ssh"> SSH</A>,
+ Cisco PIX, ... -- and touches only lightly on IPsec-based approaches.</P>
+<P>That said, it appears to deal competently with what it does cover and
+ it has readable explanations of many basic VPN and security concepts.
+ It may be exactly what some readers require, even if I find the
+ emphasis unfortunate.</P>
+<HR><A name="LASG"> Kurt Seifried<CITE> Linux Administrator's Security
+ Guide</CITE></A>
+<P>Available online from<A href="http://www.securityportal.com/lasg/">
+ Security Portal</A>. It has fairly extensive coverage of IPsec.</P>
+<HR><A name="Smith"> Richard E Smith<CITE> Internet Cryptography</CITE>
+<BR></A> ISBN 0-201-92480-3, Addison Wesley, 1997
+<P>See the book's<A href="http://www.visi.com/crypto/inet-crypto/index.html">
+ home page</A></P>
+<HR><A name="neal"> Neal Stephenson<CITE> Cryptonomicon</CITE></A>
+<BR> Hardcover ISBN -380-97346-4, Avon, 1999.
+<P>A novel in which cryptography and the net figure prominently.<STRONG>
+ Highly recommended</STRONG>: I liked it enough I immediately went out
+ and bought all the author's other books.</P>
+<P>There is also a paperback edition. Sequels are expected.</P>
+<HR><A name="stevens"> Stevens and Wright</A><CITE> TCP/IP Illustrated</CITE>
+<BR> Addison-Wesley
+<UL>
+<LI>Vol. I: The Protocols 1994 ISBN:0-201-63346-9</LI>
+<LI>Vol. II: The Implementation 1995 ISBN:0-201-63354-X</LI>
+<LI>Vol. III: TCP for Transactions, HTTP, NNTP, and the UNIX Domain
+ Protocols 1996 ISBN: 0-201-63495-3</LI>
+</UL>
+<P>If you need to deal with the details of the network protocols, read
+ either this series or the<A href="#comer"> Comer</A> series before you
+ start reading the RFCs.</P>
+<HR><A name="Rubini"> Rubini</A><CITE> Linux Device Drivers</CITE>
+<BR> O'Reilly &amp; Associates, Inc. 1998 ISBN 1-56592-292-1
+<HR><A name="Zeigler"> Robert Zeigler</A><CITE> Linux Firewalls</CITE>
+<BR> Newriders Publishing, 2000 ISBN 0-7537-0900-9
+<P>A good book, with detailed coverage of ipchains(8) firewalls and of
+ many related issues.</P>
+<HR>
+<H1><A name="RFC">IPsec RFCs and related documents</A></H1>
+<H2><A name="RFCfile">The RFCs.tar.gz Distribution File</A></H2>
+<P>The Linux FreeS/WAN distribution is available from<A href="http://www.xs4all.nl/~freeswan">
+ our primary distribution site</A> and various mirror sites. To give
+ people more control over their downloads, the RFCs that define IP
+ security are bundled separately in the file RFCs.tar.gz.</P>
+<P>The file you are reading is included in the main distribution and is
+ available on the web site. It describes the RFCs included in the<A href="#RFCs.tar.gz">
+ RFCs.tar.gz</A> bundle and gives some pointers to<A href="#sources">
+ other ways to get them</A>.</P>
+<H2><A name="sources">Other sources for RFCs &amp; Internet drafts</A></H2>
+<H3><A name="RFCdown">RFCs</A></H3>
+<P>RFCs are downloadble at many places around the net such as:</P>
+<UL>
+<LI><A href="http://www.rfc-editor.org">http://www.rfc-editor.org</A></LI>
+<LI><A href="http://nis.nsf.net/internet/documents/rfc">NSF.net</A></LI>
+<LI><A href="http://sunsite.doc.ic.ac.uk/computing/internet/rfc">Sunsite
+ in the UK</A></LI>
+</UL>
+<P>browsable in HTML form at others such as:</P>
+<UL>
+<LI><A href="http://www.landfield.com/rfcs/index.html">landfield.com</A></LI>
+<LI><A href="http://www.library.ucg.ie/Connected/RFC">Connected Internet
+ Encyclopedia</A></LI>
+</UL>
+<P>and some of them are available in translation:</P>
+<UL>
+<LI><A href="http://www.eisti.fr/eistiweb/docs/normes/">French</A></LI>
+</UL>
+<P>There is also a published<A href="#RFCs"> Big Book of IPSEC RFCs</A>.</P>
+<H3><A name="drafts">Internet Drafts</A></H3>
+<P>Internet Drafts, working documents which sometimes evolve into RFCs,
+ are also available.</P>
+<UL>
+<LI><A href="http://www.ietf.org/ID.html">Overall reference page</A></LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/ipsec.html">IPsec</A> working
+ group</LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/ipsra.html">IPSRA (IPsec
+ Remote Access)</A> working group</LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/ipsp.html">IPsec Policy</A>
+ working group</LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/kink.html">KINK (Kerberized
+ Internet Negotiation of Keys)</A> working group</LI>
+</UL>
+<P>Note: some of these may be obsolete, replaced by later drafts or by
+ RFCs.</P>
+<H3><A name="FIPS1">FIPS standards</A></H3>
+<P>Some things used by<A href="#IPSEC"> IPsec</A>, such as<A href="#DES">
+ DES</A> and<A href="#SHA"> SHA</A>, are defined by US government
+ standards called<A href="#FIPS"> FIPS</A>. The issuing organisation,<A href="#NIST">
+ NIST</A>, have a<A href="http://www.itl.nist.gov/div897/pubs"> FIPS
+ home page</A>.</P>
+<H2><A name="RFCs.tar.gz">What's in the RFCs.tar.gz bundle?</A></H2>
+<P>All filenames are of the form rfc*.txt, with the * replaced with the
+ RFC number.</P>
+<PRE>RFC# Title</PRE>
+<H3><A name="rfc.ov">Overview RFCs</A></H3>
+<PRE>2401 Security Architecture for the Internet Protocol
+2411 IP Security Document Roadmap</PRE>
+<H3><A name="basic.prot">Basic protocols</A></H3>
+<PRE>2402 IP Authentication Header
+2406 IP Encapsulating Security Payload (ESP)</PRE>
+<H3><A name="key.ike">Key management</A></H3>
+<PRE>2367 PF_KEY Key Management API, Version 2
+2407 The Internet IP Security Domain of Interpretation for ISAKMP
+2408 Internet Security Association and Key Management Protocol (ISAKMP)
+2409 The Internet Key Exchange (IKE)
+2412 The OAKLEY Key Determination Protocol
+2528 Internet X.509 Public Key Infrastructure</PRE>
+<H3><A name="rfc.detail">Details of various things used</A></H3>
+<PRE>2085 HMAC-MD5 IP Authentication with Replay Prevention
+2104 HMAC: Keyed-Hashing for Message Authentication
+2202 Test Cases for HMAC-MD5 and HMAC-SHA-1
+2207 RSVP Extensions for IPSEC Data Flows
+2403 The Use of HMAC-MD5-96 within ESP and AH
+2404 The Use of HMAC-SHA-1-96 within ESP and AH
+2405 The ESP DES-CBC Cipher Algorithm With Explicit IV
+2410 The NULL Encryption Algorithm and Its Use With IPsec
+2451 The ESP CBC-Mode Cipher Algorithms
+2521 ICMP Security Failures Messages</PRE>
+<H3><A name="rfc.ref">Older RFCs which may be referenced</A></H3>
+<PRE>1321 The MD5 Message-Digest Algorithm
+1828 IP Authentication using Keyed MD5
+1829 The ESP DES-CBC Transform
+1851 The ESP Triple DES Transform
+1852 IP Authentication using Keyed SHA</PRE>
+<H3><A name="rfc.dns">RFCs for secure DNS service, which IPsec may use</A>
+</H3>
+<PRE>2137 Secure Domain Name System Dynamic Update
+2230 Key Exchange Delegation Record for the DNS
+2535 Domain Name System Security Extensions
+2536 DSA KEYs and SIGs in the Domain Name System (DNS)
+2537 RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)
+2538 Storing Certificates in the Domain Name System (DNS)
+2539 Storage of Diffie-Hellman Keys in the Domain Name System (DNS)</PRE>
+<H3><A name="rfc.exp">RFCs labelled &quot;experimental&quot;</A></H3>
+<PRE>2521 ICMP Security Failures Messages
+2522 Photuris: Session-Key Management Protocol
+2523 Photuris: Extended Schemes and Attributes</PRE>
+<H3><A name="rfc.rel">Related RFCs</A></H3>
+<PRE>1750 Randomness Recommendations for Security
+1918 Address Allocation for Private Internets
+1984 IAB and IESG Statement on Cryptographic Technology and the Internet
+2144 The CAST-128 Encryption Algorithm</PRE>
+<HR>
+<H1><A name="roadmap">Distribution Roadmap: What's Where in Linux
+ FreeS/WAN</A></H1>
+<P> This file is a guide to the locations of files within the FreeS/WAN
+ distribution. Everything described here should be on your system once
+ you download, gunzip, and untar the distribution.</P>
+<P>This distribution contains two major subsystems</P>
+<DL>
+<DT><A href="#klips.roadmap">KLIPS</A></DT>
+<DD>the kernel code</DD>
+<DT><A href="#pluto.roadmap">Pluto</A></DT>
+<DD>the user-level key-management daemon</DD>
+</DL>
+<P>plus assorted odds and ends.</P>
+<H2><A name="top">Top directory</A></H2>
+<P>The top directory has essential information in text files:</P>
+<DL>
+<DT>README</DT>
+<DD>introduction to the software</DD>
+<DT>INSTALL</DT>
+<DD>short experts-only installation procedures. More detalied procedures
+ are in<A href="install.html"> installation</A> and<A href="config.html">
+ configuration</A> HTML documents.</DD>
+<DT>BUGS</DT>
+<DD>major known bugs in the current release.</DD>
+<DT>CHANGES</DT>
+<DD>changes from previous releases</DD>
+<DT>CREDITS</DT>
+<DD>acknowledgement of contributors</DD>
+<DT>COPYING</DT>
+<DD>licensing and distribution information</DD>
+</DL>
+<H2><A name="doc">Documentation</A></H2>
+<P> The doc directory contains the bulk of the documentation, most of it
+ in HTML format. See the<A href="index.html"> index file</A> for
+ details.</P>
+<H2><A name="klips.roadmap">KLIPS: kernel IP security</A></H2>
+<P><A href="#KLIPS"> KLIPS</A> is<STRONG> K</STRONG>erne<STRONG>L</STRONG><STRONG>
+ IP</STRONG><STRONG> S</STRONG>ecurity. It lives in the klips directory,
+ of course.</P>
+<DL>
+<DT>klips/doc</DT>
+<DD>documentation</DD>
+<DT>klips/patches</DT>
+<DD>patches for existing kernel files</DD>
+<DT>klips/test</DT>
+<DD>test stuff</DD>
+<DT>klips/utils</DT>
+<DD>low-level user utilities</DD>
+<DT>klips/net/ipsec</DT>
+<DD>actual klips kernel files</DD>
+<DT>klips/src</DT>
+<DD>symbolic link to klips/net/ipsec
+<P>The &quot;make insert&quot; step of installation installs the patches and makes
+ a symbolic link from the kernel tree to klips/net/ipsec. The odd name
+ of klips/net/ipsec is dictated by some annoying limitations of the
+ scripts which build the Linux kernel. The symbolic-link business is a
+ bit messy, but all the alternatives are worse.</P>
+<P></P>
+</DD>
+<DT>klips/utils</DT>
+<DD>Utility programs:
+<P></P>
+<DL>
+<DT>eroute</DT>
+<DD>manipulate IPsec extended routing tables</DD>
+<DT>klipsdebug</DT>
+<DD>set Klips (kernel IPsec support) debug features and level</DD>
+<DT>spi</DT>
+<DD>manage IPsec Security Associations</DD>
+<DT>spigrp</DT>
+<DD>group/ungroup IPsec Security Associations</DD>
+<DT>tncfg</DT>
+<DD>associate IPsec virtual interface with real interface</DD>
+</DL>
+<P>These are all normally invoked by ipsec(8) with commands such as</P>
+<PRE> ipsec tncfg <VAR>arguments</VAR></PRE>
+ There are section 8 man pages for all of these; the names have &quot;ipsec_&quot;
+ as a prefix, so your man command should be something like:
+<PRE> man 8 ipsec_tncfg</PRE>
+</DD>
+</DL>
+<H2><A name="pluto.roadmap">Pluto key and connection management daemon</A>
+</H2>
+<P><A href="#Pluto"> Pluto</A> is our key management and negotiation
+ daemon. It lives in the pluto directory, along with its low-level user
+ utility, whack.</P>
+<P> There are no subdirectories. Documentation is a man page,<A href="manpage.d/ipsec_pluto.8.html">
+ pluto.8</A>. This covers whack as well.</P>
+<H2><A name="utils">Utils</A></H2>
+<P> The utils directory contains a growing collection of higher-level
+ user utilities, the commands that administer and control the software.
+ Most of the things that you will actually have to run yourself are in
+ there.</P>
+<DL>
+<DT>ipsec</DT>
+<DD>invoke IPsec utilities
+<P>ipsec(8) is normally the only program installed in a standard
+ directory, /usr/local/sbin. It is used to invoke the others, both those
+ listed below and the ones in klips/utils mentioned above.</P>
+<P></P>
+</DD>
+<DT>auto</DT>
+<DD>control automatically-keyed IPsec connections</DD>
+<DT>manual</DT>
+<DD>take manually-keyed IPsec connections up and down</DD>
+<DT>barf</DT>
+<DD>generate copious debugging output</DD>
+<DT>look</DT>
+<DD>generate moderate amounts of debugging output</DD>
+</DL>
+<P> There are .8 manual pages for these. look is covered in barf.8. The
+ man pages have an &quot;ipsec_&quot; prefix so your man command should be
+ something like:</P>
+<PRE>
+ man 8 ipsec_auto
+</PRE>
+<P> Examples are in various files with names utils/*.eg</P>
+<H2><A name="lib">Libraries</A></H2>
+<H3><A name="fswanlib">FreeS/WAN Library</A></H3>
+<P> The lib directory is the FreeS/WAN library, also steadily growing,
+ used by both user-level and kernel code.
+<BR /> It includes section 3<A href="manpages.html"> man pages</A> for
+ the library routines.</P>
+<H3><A name="otherlib">Imported Libraries</A></H3>
+<H4><A NAME="33_6_2_1">LibDES</A></H4>
+ The libdes library, originally from SSLeay, is used by both Klips and
+ Pluto for<A href="#3DES"> Triple DES</A> encryption. Single DES is not
+ used because<A href="#desnotsecure"> it is insecure</A>.
+<P> Note that this library has its own license, different from the<A href="#GPL">
+ GPL</A> used for other code in FreeS/WAN.</P>
+<P> The library includes its own documentation.</P>
+<H4><A NAME="33_6_2_2">GMP</A></H4>
+ The GMP (GNU multi-precision) library is used for multi-precision
+ arithmetic in Pluto's key-exchange code and public key code.
+<P> Older versions (up to 1.7) of FreeS/WAN included a copy of this
+ library in the FreeS/WAN distribution.</P>
+<P> Since 1.8, we have begun to rely on the system copy of GMP.</P>
+<HR>
+<H1><A name="umltesting">User-Mode-Linux Testing guide</A></H1>
+<P> User mode linux is a way to compile a linux kernel such that it can
+ run as a process in another linux system (potentially as a *BSD or
+ Windows process later). See<A HREF="http://user-mode-linux.sourceforge.net/">
+ http://user-mode-linux.sourceforge.net/</A></P>
+<P> UML is a good platform for testing and experimenting with FreeS/WAN.
+ It allows several network nodes to be simulated on a single machine.
+ Creating, configuring, installing, monitoring, and controling these
+ nodes is generally easier and easier to script with UML than real
+ hardware.</P>
+<P> You'll need about 500Mb of disk space for a full
+ sunrise-east-west-sunset setup. You can possibly get this down by 130Mb
+ if you remove the sunrise/sunset kernel build. If you just want to run,
+ then you can even remove the east/west kernel build.</P>
+<P> Nothing need be done as super user. In a couple of steps, we note
+ where super user is required to install commands in system-wide
+ directories, but ~/bin could be used instead. UML seems to use a
+ system-wide /tmp/uml directory so different users may interfere with
+ one another. Later UMLs use ~/.uml instead, so multiple users running
+ UML tests should not be a problem, but note that a single user running
+ the UML tests will only be able run one set. Further, UMLs sometimes
+ get stuck and hang around. These &quot;zombies&quot; (most will actually be in
+ the &quot;T&quot; state in the process table) will interfere with subsequent
+ tests.</P>
+<H2><A NAME="34_1">Preliminary Notes on BIND</A></H2>
+<P> As of 2003/3/1, the Light-Weight Resolver is used by pluto. This
+ requires that BIND9 be running. It also requires that BIND9 development
+ libraries be present in the build environment. The DNSSEC code is only
+ truly functional in BIND9 snapshots. The library code could be 9.2.2,
+ we believe. We are using BIND9 20021115 snapshot code from<A HREF="ftp://ftp.isc.org/isc/bind9/snapshots">
+ ftp://ftp.isc.org/isc/bind9/snapshots</A>.</P>
+<P> FreeS/WAN may well require a newer BIND than is on your system. Many
+ distributions have moved to BIND9.2.2 recently due to a security
+ advisory. BIND is five components.</P>
+<OL>
+<LI> named</LI>
+<LI> dnssec-*</LI>
+<LI> client side resolver libraries</LI>
+<LI> client side utility libraries I thought there were lib and named
+ parts to dnsssec...</LI>
+<LI> dynamic DNS update utilities</LI>
+</OL>
+<P> The only piece that we need for *building* is #4. That's the only
+ part that has to be on the build host. What is the difference between
+ resolver and util libs? If you want to edit
+ testing/baseconfigs/all/etc/bind, you'll need a snapshot version. The
+ resolver library contains the resolver. FreeS/WAN has its own copy of
+ that in lib/liblwres.</P>
+<H2><A NAME="34_2">Steps to Install UML for FreeS/WAN</A></H2>
+<OL>
+<LI> Get the following files:
+<OL type="a">
+<LI> from<A HREF="http://www.sandelman.ottawa.on.ca/freeswan/uml/">
+ http://www.sandelman.ottawa.on.ca/freeswan/uml/</A>
+ umlfreeroot-15.1.tar.gz (or highest numbered one). This is a debian
+ potato root file system. You can use this even on a Redhat host, as it
+ has the newer GLIBC2.2 libraries as well.
+<!-- If you are using
+ Redhat 7.2 or newer as your development machine, you can create the
+ image from your installation media. See <A HREF="uml-rhroot.html">Building a RedHat root"></A>.
+ A future document will explain how to build this from .DEB files as well.
+-->
+
+<!--
+<LI> umlfreesharemini.tar.gz (or umlfreeshareall.tar.gz).
+ If you are a Debian potato user, you don't need it you can use your
+ native /usr/share.
+</UL>
+-->
+</LI>
+<LI> From<A HREF="ftp://ftp.xs4all.nl/pub/crypto/freeswan/">
+ ftp://ftp.xs4all.nl/pub/crypto/freeswan/</A> a snapshot or release
+ (1.92 or better)</LI>
+<LI> From a<A HREF="http://www.kernel.org/mirrors/">
+ http://www.kernel.org mirror</A>, the virgin 2.4.19 kernel. Please
+ realize that we have defaults in our tree for kernel configuration. We
+ try to track the latest UML kernels. If you use a newer kernel, you may
+ have faults in the kernel build process. You can see what the latest
+ that is being regularly tested by visiting<A HREF="http://bugs.freeswan.org:81/regress/HEAD/lastgood/freeswan-regress-env.sh">
+ freeswan-regress-env.sh</A>.</LI>
+<LI>
+<!-- Note: this step is refered to as "step 1d" below. -->
+ Get<A HREF="http://ftp.nl.linux.org/uml/">
+ http://ftp.nl.linux.org/uml/</A> uml-patch-2.4.19-47.bz2 or the one
+ associated with your kernel. As of 2003/03/05, uml-patch-2.4.19-47.bz2
+ works for us.<STRONG> More recent versions of the patch have not been
+ tested by us.</STRONG></LI>
+<LI> You'll probably want to visit<A HREF="http://user-mode-linux.sourceforge.net">
+ http://user-mode-linux.sourceforge.net</A> and get the UML utilities.
+ These are not needed for the build or interactive use (but
+ recommended). They are necessary for the regression testing procedures
+ used by &quot;make check&quot;. We currently use uml_utilities_20020212.tar.bz2.</LI>
+<LI> You need tcpdump version 3.7.1 or better. This is newer than the
+ version included in most LINUX distributions. You can check the version
+ of an installed tcpdump with the --version flag. If you need a newer
+ tcpdump fetch both tcpdump and libpcap source tar files from<A HREF="http://www.tcpdump.org/">
+ http://www.tcpdump.org/</A> or a mirror.</LI>
+</OL>
+</LI>
+<LI> Pick a suitable place, and extract the following files:
+<OL type="a">
+<LI>
+<!-- Note: this step is refered to as "step 2a" later. -->
+ 2.4.19 kernel. For instance:
+<PRE>
+ <CODE> cd /c2/kernel
+ tar xzvf ../download/pub/linux/kernel/v2.4/linux-2.4.19.tar.gz
+</CODE>
+</PRE>
+</LI>
+<LI> extract the umlfreeroot file
+<!-- (unless you <A HREF="uml-rhroot.html">built your own from RPMs</A>) -->
+
+<PRE>
+ <CODE> mkdir -p /c2/user-mode-linux/basic-root
+ cd /c2/user-mode-linux/basic-root
+ tar xzvf ../download/umlfreeroot-15.1.tar.gz
+</CODE>
+</PRE>
+</LI>
+<LI> FreeSWAN itself (or checkout &quot;all&quot; from CVS)
+<PRE>
+ <CODE> mkdir -p /c2/freeswan/sandbox
+ cd /c2/freeswan/sandbox
+ tar xzvf ../download/snapshot.tar.gz
+</CODE>
+</PRE>
+</LI>
+</OL>
+</LI>
+<LI> If you need to build a newer tcpdump:
+<UL>
+<LI> Make sure you have OpenSSL installed -- it is needed for
+ cryptographic routines.</LI>
+<LI> Unpack libpcap and tcpdump source in parallel directories (the
+ tcpdump build procedures look for libpcap next door).</LI>
+<LI> Change directory into the libpcap source directory and then build
+ the library:
+<PRE>
+ <CODE> ./configure
+ make
+</CODE>
+</PRE>
+</LI>
+<LI> Change into the tcpdump source directory, build tcpdump, and
+ install it.
+<PRE>
+ <CODE> ./configure
+ make
+ # Need to be superuser to install in system directories.
+ # Installing in ~/bin would be an alternative.
+ su -c &quot;make install&quot;
+</CODE>
+</PRE>
+</LI>
+</UL>
+</LI>
+<LI> If you need the uml utilities, unpack them somewhere then build and
+ install them:
+<PRE>
+ <CODE> cd tools
+ make all
+ # Need to be superuser to install in system directories.
+ # Installing in ~/bin would be an alternative.
+ su -c &quot;make install BIN_DIR=/usr/local/bin&quot;
+</CODE>
+</PRE>
+</LI>
+<LI> set up the configuration file
+<UL>
+<LI> <CODE>cd /c2/freeswan/sandbox/freeswan-1.97/testing/utils</CODE></LI>
+<LI> copy umlsetup-sample.sh to ../../umlsetup.sh: <CODE> cp
+ umlsetup-sample.sh ../../umlsetup.sh</CODE></LI>
+<LI> open up ../../umlsetup.sh in your favorite editor.</LI>
+<LI> change POOLSPACE= to point to the place with at least 500Mb of
+ disk. Best if it is on the same partition as the &quot;umlfreeroot&quot;
+ extraction, as it will attempt to use hard links if possible to save
+ disk space.</LI>
+<LI> Set TESTINGROOT if you intend to run the script outside of the
+ sandbox/snapshot/release directory. Otherwise, it will configure
+ itself.</LI>
+<LI> KERNPOOL should point to the directory with your 2.4.19 kernel
+ tree. This tree should be unconfigured! This is the directory you used
+ in step 2a.</LI>
+<LI> UMLPATCH should point at the bz2 file you downloaded at 1d. If
+ using a kernel that already includes the patch, set this to /dev/null.</LI>
+<LI> FREESWANDIR should point at the directory where you unpacked the
+ snapshot/release. Include the &quot;freeswan-snap2001sep16b&quot; or whatever in
+ it. If you are running from CVS, then you point at the directory where
+ top, klips, etc. are. The script will fix up the directory so that it
+ can be used.</LI>
+<LI> BASICROOT should be set to the directory used in 2b, or to the
+ directory that you created with RPMs.</LI>
+<LI> SHAREDIR should be set to the directory used in 2c, to /usr/share
+ for Debian potato users, or to $BASICROOT/usr/share.</LI>
+</UL>
+</LI>
+<LI>
+<PRE> <CODE>cd $TESTINGROOT/utils
+sh make-uml.sh
+</CODE></PRE>
+ It will grind for awhile. If there are errors it will bail. If so, run
+ it under &quot;script&quot; and send the output to bugs@lists.freeswan.org.</LI>
+<LI> You will have a bunch of stuff under $POOLSPACE. Open four xterms:
+<PRE> <CODE> for i in sunrise sunset east west
+ do
+ xterm -name $i -title $i -e $POOLSPACE/$i/start.sh done
+</CODE></PRE>
+</LI>
+<LI> Login as root. Password is &quot;root&quot; (Note, these virtual machines are
+ networked together, but are not configured to talk to the rest of the
+ world.)</LI>
+<LI> verify that pluto started on east/west, run &quot;ipsec look&quot;</LI>
+<LI> login to sunrise. run &quot;ping sunset&quot;</LI>
+<LI> login to west. run &quot;tcpdump -p -i eth1 -n&quot; (tcpdump must be version
+ 3.7.1 or newer)</LI>
+<LI> Closing a console xterm will shut down that UML.</LI>
+<LI> You can &quot;make check&quot;, if you want to. It is run from
+ /c2/freeswan/sandbox/freeswan-1.97.</LI>
+</OL>
+<H1><A NAME="35">Debugging the kernel with GDB</A></H1>
+<P> With User-Mode-Linux, you can debug the kernel using GDB. See
+<!--HREF="http://user-mode-linux.sourceforge.net/debugging.html"-->
+
+ http://user-mode-linux.sourceforge.net/debugging.html.</(null)></P>
+<P> Typically, one will want to address a test case for a failing
+ situation. Running GDB from Emacs, or from other front ends is
+ possible. First start GDB.</P>
+<P> Tell it to open the UMLPOOL/swan/linux program.</P>
+<P> Note the PID of GDB:</P>
+<PRE>
+marajade-[projects/freeswan/mgmt/planning] mcr 1029 %ps ax | grep gdb
+ 1659 pts/9 SN 0:00 /usr/bin/gdb -fullname -cd /mara4/freeswan/kernpatch/UMLPOOL/swan/ linux
+</PRE>
+<P> Set the following in the environment:</P>
+<PRE>
+UML_east_OPT=&quot;debug gdb-pid=1659&quot;
+</PRE>
+<P> Then start the user-mode-linux in the test scheme you wish:</P>
+<PRE>
+marajade-[kernpatch/testing/klips/east-icmp-02] mcr 1220 %../../utils/runme.sh
+</PRE>
+ The user-mode-linux will stop on boot, giving you a chance to attach to
+ the process:
+<PRE>
+(gdb) file linux
+Reading symbols from linux...done.
+(gdb) attach 1
+Attaching to program: /mara4/freeswan/kernpatch/UMLPOOL/swan/linux, process 1
+0xa0118bc1 in kill () at hostfs_kern.c:770
+</PRE>
+<P> At this point, break points should be created as appropriate.</P>
+<H2><A NAME="35_1">Other notes about debugging</A></H2>
+<P> If you are running a standard test, after all the packets are sent,
+ the UML will be shutdown. This can cause problems, because the UML may
+ get terminated while you are debugging.</P>
+<P> The environment variable <CODE>NETJIGWAITUSER</CODE> can be set to
+ &quot;waituser&quot;. If so, then the testing system will prompt before exiting
+ the test.</P>
+<H1><A NAME="36">User-Mode-Linux mysteries</A></H1>
+<UL>
+<LI> running more than one UML of the same name (e.g. &quot;west&quot;) can cause
+ problems.</LI>
+<LI> running more than one UML from the same root file system is not a
+ good idea.</LI>
+<LI> all this means that running &quot;make check&quot; twice on the same machine
+ is probably not a good idea.</LI>
+<LI> occationally, UMLs will get stuck. This can happen like:
+<!--BLOCK-->
+ 15134 ? T
+ 0:00 /spare/hugh/uml/uml2.4.18-sept5/umlbuild/east/linux (east)
+ [/bin/sh] 15138 ? T 0:00
+ /spare/hugh/uml/uml2.4.18-sept5/umlbuild/east/linux (east) [halt]</(null)>
+ these will need to be killed. Note that they are in &quot;T&quot;racing mode.</LI>
+<LI> UMLs can also hang, and will report &quot;Tracing myself and I can't get
+ out&quot;. This is a bug in UML. There are ways to find out what is going on
+ and report this to the UML people, but we don't know the magic right
+ now.</LI>
+</UL>
+<H1><A NAME="37">Getting more info from uml_netjig</A></H1>
+<P> uml_netjig can be compiled with a built-in tcpdump. This uses
+ not-yet-released code from<A HREF="http://www.tcpdump.org/">
+ www.tcpdump.org</A>. Please see the instructions in <CODE>
+testing/utils/uml_netjig/Makefile</CODE>.</P>
+<HR>
+<H1><A name="makecheck">How to configure to use &quot;make check&quot;</A></H1>
+<H2><A NAME="38_1">What is &quot;make check&quot;</A></H2>
+<P> &quot;make check&quot; is a target in the top level makefile. It takes care of
+ running a number of unit and system tests to confirm that FreeSWAN has
+ been compiled correctly, and that no new bugs have been introduced.</P>
+<P> As FreeSWAN contains both kernel and userspace components, doing
+ testing of FreeSWAN requires that the kernel be simulated. This is
+ typically difficult to do as a kernel requires that it be run on bare
+ hardware. A technology has emerged that makes this simpler. This is<A HREF="http://user-mode-linux.sourceforge.net">
+ User Mode Linux</A>.</P>
+<P> User-Mode Linux is a way to build a Linux kernel such that it can
+ run as a process under another Linux (or in the future other) kernel.
+ Presently, this can only be done for 2.4 guest kernels. The host kernel
+ can be 2.2 or 2.4.</P>
+<P> &quot;make check&quot; expects to be able to build User-Mode Linux kernels
+ with FreeSWAN included. To do this it needs to have some files
+ downloaded and extracted prior to running &quot;make check&quot;. This is
+ described in the<A HREF="umltesting.html"> UML testing</A> document.</P>
+<P> After having run the example in the UML testing document and
+ successfully brought up the four machine combination, you are ready to
+ use &quot;make check&quot;</P>
+<H2><A NAME="38_2">Running &quot;make check&quot;</A></H2>
+<P> &quot;make check&quot; works by walking the FreeSWAN source tree invoking the
+ &quot;check&quot; target at each node. At present there are tests defined only
+ for the <CODE>klips</CODE> directory. These tests will use the UML
+ infrastructure to test out pieces of the <CODE>klips</CODE> code.</P>
+<P> The results of the tests can be recorded. If the environment
+ variable <CODE>$REGRESSRESULTS</CODE> is non-null, then the results of
+ each test will be recorded. This can be used as part of a nightly
+ regression testing system, see<A HREF="nightly.html"> Nightly testing</A>
+ for more details.</P>
+<P> &quot;make check&quot; otherwise prints a minimal amount of output for each
+ test, and indicates pass/fail status of each test as they are run.
+ Failed tests do not cause failure of the target in the form of exit
+ codes.</P>
+<H1><A NAME="39">How to write a &quot;make check&quot; test</A></H1>
+<H2><A NAME="39_1">Structure of a test</A></H2>
+<P> Each test consists of a set of directories under <CODE>testing/</CODE>
+. There are directories for <CODE>klips</CODE>, <CODE>pluto</CODE>, <CODE>
+packaging</CODE> and <CODE>libraries</CODE>. Each directory has a list
+ of tests to run is stored in a file called <CODE>TESTLIST</CODE> in
+ that directory. e.g. <CODE>testing/klips/TESTLIST</CODE>.</P>
+<H2 NAME="TESTLIST"><A NAME="39_2">The TESTLIST</A></H2>
+<P> This isn't actually a shell script. It just looks like one. Some
+ tools other than /bin/sh process it. Lines that start with # are
+ comments.</P>
+<PRE>
+# test-kind directory-containing-test expectation [PR#]
+</PRE>
+<P>The first word provides the test type, detailed below.</P>
+<P> The second word is the name of the test to run. This the directory
+ in which the test case is to be found..</P>
+<P>The third word may be one of:</P>
+<DL>
+<DT> blank/good</DT>
+<DD>the test is believed to function, report failure</DD>
+<DT> bad</DT>
+<DD> the test is known to fail, report unexpected success</DD>
+<DT> suspended</DT>
+<DD> the test should not be run</DD>
+</DL>
+<P> The fourth word may be a number, which is a PR# if the test is
+ failing.</P>
+<H2><A NAME="39_3">Test kinds</A></H2>
+ The test types are:
+<DL>
+<DT>skiptest</DT>
+<DD>means run no test.</DD>
+<DT>ctltest</DT>
+<DD>means run a single system without input/output.</DD>
+<DT>klipstest</DT>
+<DD>means run a single system with input/output networks</DD>
+<DT><A HREF="#umlplutotest">umlplutotest</A></DT>
+<DD>means run a pair of systems</DD>
+<DT><A HREF="#umlXhost">umlXhost</A></DT>
+<DD>run an arbitrary number of systems</DD>
+<DT>suntest (TBD)</DT>
+<DD>means run a quad of east/west/sunrise/sunset</DD>
+<DT>roadtest (TBD)</DT>
+<DD>means run a trio of east-sunrise + warrior</DD>
+<DT>extrudedtest (TBD)</DT>
+<DD>means run a quad of east-sunrise + warriorsouth + park</DD>
+<DT>mkinsttest</DT>
+<DD>a test of the &quot;make install&quot; machinery.</DD>
+<DT>kernel_test_patch</DT>
+<DD>a test of the &quot;make kernelpatch&quot; machinery.</DD>
+</DL>
+ Tests marked (TBD) have yet to be fully defined.
+<P> Each test directory has a file in it called <CODE>testparams.sh</CODE>
+. This file sets a number of environment variables to define the
+ parameters of the test.</P>
+<H2><A NAME="39_4">Common parameters</A></H2>
+<DL>
+<DT>TESTNAME</DT>
+<DD>the name of the test (repeated for checking purposes)</DD>
+<DT>TEST_TYPE</DT>
+<DD>the type of the test (repeat of type type above)</DD>
+<DT>TESTHOST</DT>
+<DD>the name of the UML machine to run for the test, typically &quot;east&quot; or
+ &quot;west&quot;</DD>
+<DT>TEST_PURPOSE</DT>
+<DD>The purpose of the test is one of:
+<DL>
+<DT>goal</DT>
+<DD>The goal purpose is where a test is defined for code that is not yet
+ finished. The test indicates when the goals have in fact been reached.</DD>
+<DT>regress</DT>
+<DD>This is a test to determine that a previously existing bug has been
+ repaired. This test will initially be created to reproduce the bug in
+ isolation, and then the bug will be fixed.</DD>
+<DT>exploit</DT>
+<DD>This is a set of packets/programs that causes a vulnerability to be
+ exposed. It is a specific variation of the regress option.</DD>
+</DL>
+</DD>
+<DT>TEST_GOAL_ITEM</DT>
+<DT></DT>
+<DD>in the case of a goal test, this is a reference to the requirements
+ document</DD>
+<DT>TEST_PROB_REPORT</DT>
+<DD>in the case of regression test, this the problem report number from
+ GNATS</DD>
+<DT>TEST_EXPLOIT_URL</DT>
+<DD>in the case of an exploit, this is a URL referencing the paper
+ explaining the origin of the test and the origin of exploit software</DD>
+<DT>REF_CONSOLE_OUTPUT</DT>
+<DD>a file in the test directory that contains the sanitized console
+ output against which to compare the output of the actual test.</DD>
+<DT>REF_CONSOLE_FIXUPS</DT>
+<DD>a list of scripts (found in <CODE>klips/test/fixups</CODE>) to apply
+ to sanitize the console output of the machine under test. These are
+ typically perl, awk or sed scripts that remove things in the kernel
+ output that change each time the test is run and/or compiled.</DD>
+<DT>INIT_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode prior to starting the tests. This file will usually
+ set up any eroute's and SADB entries that are required for the test.</P>
+<P>Lines beginning with # are skipped. Blank lines are skipped.
+ Otherwise, a shell prompted is waited for each time (consisting of <CODE>
+\n#</CODE>) and then the command is sent. Note that the prompt is waited
+ for before the command and not after, so completion of the last command
+ in the script is not required. This is often used to invoke a program
+ to monitor the system, e.g. <CODE>ipsec pf_key</CODE>.</P>
+</DD>
+<DT>RUN_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode, before the packets are sent. On single machine tests,
+ this script doesn't provide any more power than INIT_SCRIPT, but is
+ implemented for consistency's sake.</P>
+</DD>
+<DT>FINAL_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode after the final packet is sent. Similar to
+ INIT_SCRIPT, above. If not specified, then the single command &quot;halt&quot; is
+ sent. If specified, then the script should end with a halt command to
+ nicely shutdown the UML.</P>
+</DD>
+<DT>CONSOLEDIFFDEBUG</DT>
+<DD>If set to &quot;true&quot; then the series of console fixups (see
+ REF_CONSOLE_FIXUPS) will be output after it is constructed. (It should
+ be set to &quot;false&quot;, or unset otherwise)</DD>
+<DT>NETJIGDEBUG</DT>
+<DD>If set to &quot;true&quot; then the series of console fixups (see
+ REF_CONSOLE_FIXUPS) will be output after it is constructed. (It should
+ be set to &quot;false&quot;, or unset otherwise)</DD>
+<DT>NETJIGTESTDEBUG</DT>
+<DD> If set to &quot;netjig&quot;, then the results of talking to the <CODE>
+uml_netjig</CODE> will be printed to stderr during the test. In
+ addition, the jig will be invoked with --debug, which causes it to log
+ its process ID, and wait 60 seconds before continuing. This can be used
+ if you are trying to debug the <CODE>uml_netjig</CODE> program itself.</DD>
+<DT>HOSTTESTDEBUG</DT>
+<DD> If set to &quot;hosttest&quot;, then the results of taling to the consoles of
+ the UMLs will be printed to stderr during the test.</DD>
+<DT>NETJIGWAITUSER</DT>
+<DD> If set to &quot;waituser&quot;, then the scripts will wait forever for user
+ input before they shut the tests down. Use this is if you are debugging
+ through the kernel.</DD>
+<DT>PACKETRATE</DT>
+<DD> A number, in miliseconds (default is 500ms) at which packets will
+ be replayed by the netjig.</DD>
+</DL>
+<H2><A NAME="39_5">KLIPStest paramaters</A></H2>
+<P> The klipstest function starts a program (<CODE>
+testing/utils/uml_netjig/uml_netjig</CODE>) to setup a bunch of I/O
+ sockets (that simulate network interfaces). It then exports the
+ references to these sockets to the environment and invokes (using
+ system()) a given script. It waits for the script to finish.</P>
+
+<!-- <IMG SRC="single_netjig.png" ALT="block diagram of uml_netjig"> -->
+<P> The script invoked (<CODE>testing/utils/host-test.tcl</CODE>) is a
+ TCL<A HREF="http://expect.nist.gov/"> expect</A> script that arranges
+ to start the UML and configure it appropriately for the test. The
+ configuration is done with the script given above for<VAR> INIT_SCRIPT</VAR>
+. The TCL script then forks, leaves the UML in the background and exits.
+ uml_netjig continues. It then starts listening to the simulated network
+ answering ARPs and inserting packets as appropriate.</P>
+<P> The klipstest function invokes <CODE>uml_netjig</CODE> with
+ arguments to capture output from network interface(s) and insert
+ packets as appropriate:</P>
+<DL>
+<DT>PUB_INPUT</DT>
+<DD>a<A HREF="http://www.tcpdump.org/"> pcap</A> file to feed in on the
+ public (encrypted) interface. (typically, eth1)</DD>
+<DT>PRIV_INPUT</DT>
+<DD>a pcap file to feed in on the private (plain-text) interface
+ (typically, eth0).</DD>
+<DT>REF_PUB_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the public (eth1)
+ interface are captured to a<A HREF="http://www.tcpdump.org/"> pcap</A>
+ file by <CODE>uml_netjig</CODE>. The klipstest function then uses
+ tcpdump on the file to produce text output, which is compared to the
+ file given.</DD>
+<DT>REF_PUB_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+<DT>REF_PRIV_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the private (eth0)
+ interface are captured and compared after conversion by tcpdump, as
+ with<VAR> REFPUBOUTPUT</VAR>.</DD>
+<DT>REF_PRIV_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+<DT>EXITONEMPTY</DT>
+<DD>a flag for <CODE>uml_netjig</CODE>. It should contain
+ &quot;--exitonempty&quot; of uml_netjig should exit when all of the input (<VAR>
+PUBINPUT</VAR>,<VAR>PRIVINPUT</VAR>) packets have been injected.</DD>
+<DT>ARPREPLY</DT>
+<DD>a flag for <CODE>uml_netjig</CODE>. It should contain &quot;--arpreply&quot;
+ if <CODE>uml_netjig</CODE> should reply to ARP requests. One will
+ typically set this to avoid having to fudge the ARP cache manually.</DD>
+<DT>TCPDUMPFLAGS</DT>
+<DD>a set of flags for the tcpdump used when converting captured output.
+ Typical values will include &quot;-n&quot; to turn off DNS, and often &quot;-E&quot; to set
+ the decryption key (tcpdump 3.7.1 and higher only) for ESP packets. The
+ &quot;-t&quot; flag (turn off timestamps) is provided automatically</DD>
+<DT>NETJIG_EXTRA</DT>
+<DD>additional comments to be sent to the netjig. This may arrange to
+ record or create additional networks, or may toggle options.</DD>
+</DL>
+<H2><A NAME="39_6">mkinsttest paramaters</A></H2>
+<P> The basic concept of the <CODE>mkinsttest</CODE> test type is that
+ it performs a &quot;make install&quot; to a temporary $DESTDIR. The resulting
+ tree can then be examined to determine if it was done properly. The
+ files can be uninstalled to determine if the file list was correct, or
+ the contents of files can be examined more precisely.</P>
+<DL>
+<DT>INSTALL_FLAGS</DT>
+<DD>If set, then an install will be done. This provides the set of flags
+ to provide for the install. The target to be used (usually &quot;install&quot;)
+ must be among the flags.</DD>
+<DT>POSTINSTALL_SCRIPT</DT>
+<DD>If set, a script to run after initial &quot;make install&quot;. Two arguments
+ are provided: an absolute path to the root of the FreeSWAN src tree,
+ and an absolute path to the temporary installation area.</DD>
+<DT>INSTALL2_FLAGS</DT>
+<DD>If set, a second install will be done using these flags. Similarly
+ to INSTALL_FLAGS, the target must be among the flags.</DD>
+<DT>UNINSTALL_FLAGS</DT>
+<DD>If set, an uninstall will be done using these flags. Similarly to
+ INSTALL_FLAGS, the target (usually &quot;uninstall&quot;) must be among the
+ flags.</DD>
+<DT>REF_FIND_f_l_OUTPUT</DT>
+<DD>If set, a <CODE>find $ROOT ( -type f -or -type -l )</CODE> will be
+ done to get a list of a real files and symlinks. The resulting file
+ will be compared to the file listed by this option.</DD>
+<DT>REF_FILE_CONTENTS</DT>
+<DD>If set, it should point to a file containing records for the form:
+<PRE>
+
+<!--VARIABLE-->
+reffile</(null)>
+<!--VARIABLE-->
+samplefile</(null)>
+</PRE>
+ one record per line. A diff between the provided reference file, and
+ the sample file (located in the temporary installation root) will be
+ done for each record.</DD>
+</DL>
+<H2><A NAME="39_7">rpm_build_install_test paramaters</A></H2>
+<P> The <CODE>rpm_build_install_test</CODE> type is to verify that the
+ proper packing list is produced by &quot;make rpm&quot;, and that the mechanisms
+ for building the kernel modules produce consistent results.</P>
+<DL>
+<DT>RPM_KERNEL_SOURCE</DT>
+<DD>Point to an extracted copy of the RedHat kernel source code.
+ Variables from the environment may be used.</DD>
+<DT>REF_RPM_CONTENTS</DT>
+<DD>This is a file containing one record per line. Each record consists
+ of a RPM name (may contain wildcards) and a filename to compare the
+ contents to. The RPM will be located and a file list will be produced
+ with rpm2cpio.</DD>
+</DL>
+<H2><A NAME="39_8">libtest paramaters</A></H2>
+<P> The libtest test is for testing library routines. The library file
+ is expected to provided an <CODE>#ifdef</CODE> by the name of<VAR>
+ library</VAR>
+<!--CODE_MAIN</CODE-->
+. The libtest type invokes the C compiler to compile this
+ file, links it against <CODE>libfreeswan.a</CODE> (to resolve any other
+ dependancies) and runs the test with the <CODE>-r</CODE> argument to
+ invoke a regression test.</(null)></P>
+<P>The library test case is expected to do a self-test, exiting with
+ status code 0 if everything is okay, and with non-zero otherwise. A
+ core dump (exit code greater than 128) is noted specifically.</P>
+<P> Unlike other tests, there are no subdirectories required, or other
+ parameters to set.</P>
+<H2 NAME="umlplutotest"><A NAME="39_9">umlplutotest paramaters</A></H2>
+<P> The umlplutotest function starts a pair of user mode line processes.
+ This is a 2-host version of umlXhost. The &quot;EAST&quot; and &quot;WEST&quot; slots are
+ defined.</P>
+<H2 NAME="umlXhost"><A NAME="39_10">umlXhost parameters</A></H2>
+<P> The umlXtest function starts an arbitrary number of user mode line
+ processes.</P>
+
+<!-- <IMG SRC="single_netjig.png" ALT="block diagram of uml_netjig"> -->
+<P> The script invoked (<CODE>testing/utils/Xhost-test.tcl</CODE>) is a
+ TCL<A HREF="http://expect.nist.gov/"> expect</A> script that arranges
+ to start each UML and configure it appropriately for the test. It then
+ starts listening (using uml_netjig) to the simulated network answering
+ ARPs and inserting packets as appropriate.</P>
+<P> umlXtest has a series of slots, each of which should be filled by a
+ host. The list of slots is controlled by the variable, XHOST_LIST. This
+ variable should be set to a space seperated list of slots. The former
+ umlplutotest is now implemented as a variation of the umlXhost test,
+ with XHOST_LIST=&quot;EAST WEST&quot;.</P>
+<P> For each host slot that is defined, a series of variables should be
+ filled in, defining what configuration scripts to use for that host.</P>
+<P> The following are used to control the console input and output to
+ the system. Where the string ${host} is present, the host slot should
+ be filled in. I.e. for the two host system with XHOST_LIST=&quot;EAST WEST&quot;,
+ then the variables: EAST_INIT_SCRIPT and WEST_INIT_SCRIPT will exist.</P>
+<DL>
+<DT>${host}HOST</DT>
+<DD>The name of the UML host which will fill this slot</DD>
+<DT>${host}_INIT_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode prior to starting the tests. This file will usually
+ set up any eroute's and SADB entries that are required for the test.
+ Similar to INIT_SCRIPT, above.</P>
+</DD>
+<DT>${host}_RUN_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode, before the packets are sent. This set of commands is
+ run after all of the virtual machines are initialized. I.e. after
+ EAST_INIT_SCRIPT<B> AND</B> WEST_INIT_SCRIPT. This script can therefore
+ do things that require that all machines are properly configured.</P>
+</DD>
+<DT>${host}_RUN2_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode, after the packets are sent. This set of commands is
+ run before any of the virtual machines have been shut down. (I.e.
+ before EAST_FINAL_SCRIPT<B> AND</B> WEST_FINAL_SCRIPT.) This script can
+ therefore catch post-activity status reports.</P>
+</DD>
+<DT>${host}_FINAL_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode after the final packet is sent. Similar to
+ INIT_SCRIPT, above. If not specified, then the single command &quot;halt&quot; is
+ sent. Note that when this script is run, the other virtual machines may
+ already have been killed. If specified, then the script should end with
+ a halt command to nicely shutdown the UML.</P>
+</DD>
+<DT>REF_${host}_CONSOLE_OUTPUT</DT>
+<DD>Similar to REF_CONSOLE_OUTPUT, above.</DD>
+</DL>
+<P>Some additional flags apply to all hosts:</P>
+<DL>
+<DT>REF_CONSOLE_FIXUPS</DT>
+<DD>a list of scripts (found in <CODE>klips/test/fixups</CODE>) to apply
+ to sanitize the console output of the machine under test. These are
+ typically perl, awk or sed scripts that remove things in the kernel
+ output that change each time the test is run and/or compiled.</DD>
+</DL>
+<P> In addition to input to the console, the networks may have input fed
+ to them:</P>
+<DL>
+<DT>EAST_INPUT/WEST_INPUT</DT>
+<DD>a<A HREF="http://www.tcpdump.org/"> pcap</A> file to feed in on the
+ private network side of each network. The &quot;EAST&quot; and &quot;WEST&quot; here refer
+ to the networks, not the hosts.</DD>
+<DT>REF_PUB_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+<DT>REF_EAST_FILTER/REF_WEST_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+&lt;
+<DT>TCPDUMPFLAGS</DT>
+<DD>a set of flags for the tcpdump used when converting captured output.
+ Typical values will include &quot;-n&quot; to turn off DNS, and often &quot;-E&quot; to set
+ the decryption key (tcpdump 3.7.1 and higher only) for ESP packets. The
+ &quot;-t&quot; flag (turn off timestamps) is provided automatically</DD>
+<DT>REF_EAST_OUTPUT/REF_WEST_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the private (eth0)
+ interface are captured and compared after conversion by tcpdump, as
+ with<VAR> REF_PUB_OUTPUT</VAR>.</DD>
+<P> There are two additional environment variables that may be set on
+ the command line:</P>
+<DL>
+<DT> NETJIGVERBOSE=verbose export NETJIGVERBOSE</DT>
+<DD> If set, then the test output will be &quot;chatty&quot;, and let you know
+ what commands it is running, and as packets are sent. Without it set,
+ the output is limited to success/failure messages.</DD>
+<DT> NETJIGTESTDEBUG=netjig export NETJIGTESTDEBUG</DT>
+<DD> This will enable debugging of the communication with uml_netjig,
+ and turn on debugging in this utility. This does not imply
+ NETJIGVERBOSE.</DD>
+</DL>
+<DT> HOSTTESTDEBUG=hosttest export HOSTTESTDEBUG</DT>
+<DD> This will show all interactions with the user-mode-linux consoles</DD>
+</DL>
+<H2 NAME="kernelpatch"><A NAME="39_11">kernel_patch_test paramaters</A></H2>
+<P> The kernel_patch_test function takes some kernel source, copies it
+ with lndir, and then applies the patch as produced by &quot;make
+ kernelpatch&quot;.</P>
+<P> The following are used to control the input and output to the
+ system:</P>
+<DL>
+<DT>KERNEL_NAME</DT>
+<DD>the kernel name, typically something like &quot;linus&quot; or &quot;rh&quot;</DD>
+<DT>KERNEL_VERSION</DT>
+<DD>the kernel version number, as in &quot;2.2&quot; or &quot;2.4&quot;.</DD>
+<DT>KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC</DT>
+<DD>This variable should set in the environment, probably in
+ ~/freeswan-regress-env.sh. Examples of this variables would be
+ KERNEL_LINUS2_0_SRC or KERNEL_RH7_3_SRC. This variable should point to
+ an extracted copy of the kernel source in question.</DD>
+<DT>REF_PATCH_OUTPUT</DT>
+<DD>a copy of the patch output to compare against</DD>
+<DT>KERNEL_PATCH_LEAVE_SOURCE</DT>
+<DD>If set to a non-empty string, then the patched kernel source is not
+ removed at the end of the test. This will typically be set in the
+ environment while debugging.</DD>
+</DL>
+<H2 NAME="modtest"><A NAME="39_12">module_compile paramaters</A></H2>
+<P> The module_compile test attempts to build the KLIPS module against a
+ given set of kernel source. This is also done by the RPM tests, but in
+ a very specific manner.</P>
+<P> There are two variations of this test - one where the kernel either
+ doesn't need to be configured, or is already done, and tests were there
+ is a local configuration file.</P>
+<P> Where the kernel doesn't need to be configured, the kernel source
+ that is found is simply used. It may be a RedHat-style kernel, where
+ one can cause it to configure itself via rhconfig.h-style definitions.
+ Or, it may just be a kernel tree that has been configured.</P>
+<P> If the variable KERNEL_CONFIG_FILE is set, then a new directory is
+ created for the kernel source. It is populated with lndir(1). The
+ referenced file is then copied in as .config, and &quot;make oldconfig&quot; is
+ used to configure the kernel. This resulting kernel is then used as the
+ reference source.</P>
+<P> In all cases, the kernel source is found the same was for the
+ kernelpatch test, i.e. via KERNEL_VERSION/KERNEL_NAME and
+ KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC.</P>
+<P> Once there is kernel source, the module is compiled using the
+ top-level &quot;make module&quot; target.</P>
+<P> The test is considered successful if an executable is found in
+ OUTPUT/module/ipsec.o at the end of the test.</P>
+<DL>
+<DT>KERNEL_NAME</DT>
+<DD>the kernel name, typically something like &quot;linus&quot; or &quot;rh&quot;</DD>
+<DT>KERNEL_VERSION</DT>
+<DD>the kernel version number, as in &quot;2.2&quot; or &quot;2.4&quot;.</DD>
+<DT>KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC</DT>
+<DD>This variable should set in the environment, probably in
+ ~/freeswan-regress-env.sh. Examples of this variables would be
+ KERNEL_LINUS2_0_SRC or KERNEL_RH7_3_SRC. This variable should point to
+ an extracted copy of the kernel source in question.</DD>
+<DT>KERNEL_CONFIG_FILE</DT>
+<DD>The configuration file for the kernel.</DD>
+<DT>KERNEL_PATCH_LEAVE_SOURCE</DT>
+<DD>If set to a non-empty string, then the configured kernel source is
+ not removed at the end of the test. This will typically be set in the
+ environment while debugging.</DD>
+<DT>MODULE_DEF_INCLUDE</DT>
+<DD>The include file that will be used to configure the KLIPS module,
+ and possibly the kernel source.</DD>
+</DL>
+<H1><A NAME="40">Current pitfalls</A></H1>
+<DL>
+<DT> &quot;tcpdump dissector&quot; not available.</DT>
+<DD> This is a non-fatal warning. If uml_netjig is invoked with the -t
+ option, then it will attempt to use tcpdump's dissector to decode each
+ packet that it processes. The dissector is presently not available, so
+ this option it normally turned off at compile time. The dissector
+ library will be released with tcpdump version 4.0.</DD>
+</DL>
+<HR>
+<H1><A name="nightly">Nightly regression testing</A></H1>
+<P> The nightly regression testing system consists of several shell
+ scripts and some perl scripts. The goal is to check out a fresh tree,
+ run &quot;make check&quot; on it, record the results and summarize the results to
+ the team and to the web site.</P>
+<P> Output can be found on<A HREF="http://bugs.freeswan.org:81/"> adams</A>
+, although the tests are actually run on another project machine.</P>
+<H1><A name="nightlyhowto">How to setup the nightly build</A></H1>
+<P> The best way to do nightly testing is to setup a new account. We
+ call the account &quot;build&quot; - you could call it something else, but there
+ may still be some references to ~build in the scripts.</P>
+<H2><A NAME="42_1"> Files you need to know about</A></H2>
+<P> As few files as possible need to be extracted from the source tree -
+ files are run from the source tree whenever possible. However, there
+ are some bootstrap and configuration files that are necessary.</P>
+<P> There are 7 files in testing/utils that are involved:</P>
+<DL>
+<DT> nightly-sample.sh</DT>
+<DD> This is the root of the build process. This file should be copied
+ out of the CVS tree, to $HOME/bin/nightly.sh of the build account. This
+ file should be invoked from cron.</DD>
+<DT> freeswan-regress-env-sample.sh</DT>
+<DD> This file should be copied to $HOME/freeswan-regress-env.sh. It
+ should be edited to localize the values. See below.</DD>
+<DT> regress-cleanup.pl</DT>
+<DD> This file needs to be copied to $HOME/bin/regress-cleanup.pl. It is
+ invoked by the nightly file before doing anything else. It removes
+ previous nights builds in order to free up disk space for the build
+ about to be done.</DD>
+<DT> teammail-sample.sh</DT>
+<DD> A script used to send results email to the &quot;team&quot;. This sample
+ script could be copied to $HOME/bin/teammail.sh. This version will PGP
+ encrypt all the output to the team members. If this script is used,
+ then PGP will have to be properly setup to have the right keys.</DD>
+<DT> regress-nightly.sh</DT>
+<DD> This is the first stage of the nightly build. This stage will call
+ other scripts as appropriate, and will extract the source code from
+ CVS. This script should be copied to $HOME/bin/regress-nightly.sh</DD>
+<DT> regress-stage2.sh</DT>
+<DD> This is the second stage of the nightly build. It is called in
+ place. It essentially sets up the UML setup in umlsetup.sh, and calls
+ &quot;make check&quot;.</DD>
+<DT> regress-summarize-results.pl</DT>
+<DD> This script will summarize the results from the tests to a
+ permanent directory set by $REGRESSRESULTS. It is invoked from the
+ stage2 nightly script.</DD>
+<DT> regress-chart.sh</DT>
+<DD> This script is called at the end of the build process, and will
+ summarize each night's results (as saved into $REGRESSRESULTS by
+ regress-summarize-results.pl) as a chart using gnuplot. Note that this
+ requires at least gnuplot 3.7.2.</DD>
+</DL>
+<H2><A NAME="42_2">Configuring freeswan-regress-env.sh</A></H2>
+<P>For more info on KERNPOOL, UMLPATCH, BASICROOT and SHAREDIR, see<A HREF="umltesting.html">
+ User-Mode-Linux testing guide</A>.</P>
+<DL>
+<DT> KERNPOOL</DT>
+<DD> Extract copy of some kernel source to be used for UML builds</DD>
+<DT> UMLPATCH</DT>
+<DD> matching User-Mode-Linux patch.</DD>
+<DT> BASICROOT</DT>
+<DD> the root file system image (see<A HREF="umltesting.html">
+ User-Mode-Linux testing guide</A>).</DD>
+<DT> SHAREDIR=${BASICROOT}/usr/share</DT>
+<DD> The /usr/share to use.</DD>
+<DT> REGRESSTREE</DT>
+<DD> A directory in which to store the nightly regression results.
+ Directories will be created by date in this tree.</DD>
+<DT> TCPDUMP=tcpdump-3.7.1</DT>
+<DD> The path to the<A HREF="http://www.tcpdump.org/"> tcpdump</A> to
+ use. This must have crypto compiled in, and must be at least 3.7.1</DD>
+<DT> KERNEL_RH7_2_SRC=/a3/kernel_sources/linux-2.4.9-13/</DT>
+<DD> An extracted copy of the RedHat 7.2. kernel source. If set, then
+ the packaging/rpm-rh72-install-01 test will be run, and an RPM will be
+ built as a test.</DD>
+<DT> KERNEL_RH7_3_SRC=/a3/kernel_sources/rh/linux-2.4.18-5</DT>
+<DD> An extracted copy of the RedHat 7.3. kernel source. If set, then
+ the packaging/rpm-rh73-install-01 test will be run, and an RPM will be
+ built as a test.</DD>
+<DT> NIGHTLY_WATCHERS=&quot;userid,userid,userid&quot;</DT>
+<DD> The list of people who should receive nightly output. This is used
+ by teammail.sh</DD>
+<DT> FAILLINES=128</DT>
+<DD> How many lines of failed test output to include in the nightly
+ output</DD>
+<DT> PATH=$PATH:/sandel/bin export PATH</DT>
+<DD> You can also override the path if necessary here.</DD>
+<DT> CVSROOT=:pserver:anoncvs@ip212.xs4net.freeswan.org:/freeswan/MASTER</DT>
+<DD> The CVSROOT to use. This example may work for anonymous CVS, but
+ will be 12 hours behind the primary, and is still experimental</DD>
+<DT> SNAPSHOTSIGDIR=$HOME/snapshot-sig</DT>
+<DD> For the release tools, where to put the generated per-snapshot
+ signature keys</DD>
+<DT> LASTREL=1.97</DT>
+<DD> the name of the last release branch (to find the right per-snapshot
+ signature</DD>
+<DD></DD>
+</DL>
+</BODY>
+</HTML>
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 000000000..f8209b3a8
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,167 @@
+# Makefile to generate various formats from HTML source
+#
+# Assumes the htmldoc utility is available.
+# This can be downloaded from www.easysw.com
+#
+# Also needs lynx(1) for HTML-to-text conversion
+
+.SUFFIXES: .png .fig
+
+FREESWANSRCDIR=..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+# Format arguments for htmldoc
+F="--toclevels 4 --header 1cd"
+
+# source files in subdirectory
+# basic stuff
+a=src/intro.html src/upgrading.html src/quickstart.html \
+ src/policygroups.html src/faq.html
+
+# related
+b=src/manpages.html src/firewall.html src/trouble.html
+
+# more advanced
+c=src/compat.html src/interop.html src/performance.html \
+ src/testing.html src/kernel.html src/adv_config.html \
+ src/install.html src/config.html \
+ src/background.html src/user_examples.html \
+ src/makecheck.html src/umltesting.html \
+
+# background and reference material
+d=src/politics.html src/ipsec.html \
+ src/mail.html src/web.html src/glossary.html src/biblio.html \
+ src/rfc.html src/roadmap.html
+
+# build and release related
+e=src/umltesting.html src/makecheck.html src/nightly.html
+
+sections=$a $b $c $d $e
+
+# separate HTML files built in current directory
+separate=intro.html install.html config.html manpages.html \
+ firewall.html trouble.html kernel.html roadmap.html \
+ compat.html interop.html politics.html ipsec.html \
+ mail.html performance.html testing.html web.html \
+ glossary.html biblio.html rfc.html faq.html \
+ adv_config.html user_examples.html background.html \
+ quickstart.html umltesting.html makecheck.html nightly.html \
+ upgrading.html policygroups.html
+
+# various one-big-file formats
+howto=HowTo.html HowTo.ps HowTo.pdf HowTo.txt
+
+alldocs=${seperate} ${howto} index.html toc.html
+
+srcdir=..
+# where are scripts
+SCRIPTDIR=utils
+
+# where
+TESTINGDIR=${srcdir}/testing
+
+# where do we put HTML manpages?
+HMANDIR=manpage.d
+
+# default, build HTML only
+# dependencies build most of it
+# then we add index
+index.html: toc.html HowTo.html manpages src/index.html
+ cp src/index.html index.html
+
+# separate files plus table of contents
+# and then remove HTML formatting added by htmldoc
+toc.html : $(sections)
+ @htmldoc -t html --path ".;${TESTINGDIR}/doc" -d . $(sections)
+ @$(SCRIPTDIR)/cleanhtml.sh $(SCRIPTDIR)/cleanhtml.sed $(separate)
+
+# one big HTML file
+HowTo.html : $(sections)
+ @htmldoc -t html --toclevels 4 --header ' cf' -f $@ $(sections)
+
+# other HowTo formats
+HowTo.txt: HowTo.html
+ lynx -dump $< > $@
+
+HowTo.ps : $(sections)
+ htmldoc -f $@ $(sections)
+
+HowTo.pdf : $(sections)
+ @htmldoc -f $@ $(sections)
+
+manpages: manp
+
+manp: $(SCRIPTDIR)/mkhtmlman
+ @$(SCRIPTDIR)/mkhtmlman $(HMANDIR) `find ../programs ../lib ../linux -type f -name '*.[1-8]' -print | grep -v lwres | grep -v CVS`
+
+programs:
+
+all: #$(howto) $(manpages) index.html
+
+clean:
+ @rm -f $(howto) $(separate) toc.html index.html
+ @rm -rf $(HMANDIR)
+
+install:
+#install: ${alldocs} manpages
+# @mkdir -p ${DOCDIR}
+# @$(foreach f, $(alldocs), \
+# $(INSTALL) $f ${DOCDIR} || exit 1;\
+# )
+# @find ${HMANDIR} -type f -name "*.html" -print | while read file; \
+# do \
+# $(INSTALL) $$file ${DOCDIR} || exit 1;\
+# done;
+
+install_file_list:
+ @$(foreach f, $(alldocs), \
+ echo ${DOCDIR}/$f; \
+ )
+ @if [ -d ${HMANDIR} ]; then find ${HMANDIR} -type f -name "*.html" -print | while read file; \
+ do \
+ echo ${DOCDIR}/$$file; \
+ done; fi;
+
+checkprograms: ;
+
+check: ;
+
+# not enabled by default, because xml2rfc must be installed first.
+drafts: draft-richardson-ipsec-opportunistic.txt src/draft-richardson-ipsec-opportunistic.html \
+ draft-richardson-ipsec-rr.txt src/draft-richardson-ipsec-rr.html
+
+draft-richardson-ipsec-opportunistic.txt: src/draft-richardson-ipsec-opportunistic.xml
+ XML_LIBRARY=$(XML_LIBRARY):./src xml2rfc xml2rfc $? $@
+
+draft-richardson-ipsec-rr.txt: src/draft-richardson-ipsec-rr.xml
+ XML_LIBRARY=$(XML_LIBRARY):./src xml2rfc xml2rfc $? $@
+
+draft-%.nr: src/draft-%.xml
+ XML_LIBRARY=$(XML_LIBRARY):./src xml2rfc xml2nroff $? $@
+
+draft-%.html: draft-%.xml
+ XML_LIBRARY=$(XML_LIBRARY):./src xml2rfc xml2html $? $@
+
+
+.fig.eps:
+ fig2dev -L ps $< $@
+
+.fig.png:
+ fig2dev -L png $< $@
+
+single_netjig.png: testing/single_netjig.fig
+multi_netjig.png: testing/multi_netjig.fig
+
+makecheck.html: single_netjig.png multi_netjig.png
+
+#
+# DocBook based documentation
+#
+xmldocs: mast.html klips/mast.4
+
+mast.html: klips/mast.xml
+ xmlto html klips/mast.xml
+
+klips/mast.4: klips/mast.xml
+ xmlto -o klips man klips/mast.xml
+
diff --git a/doc/README b/doc/README
new file mode 100644
index 000000000..ff5564e4e
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,39 @@
+This directory has the HTML FreeS/WAN documentation.
+
+Start from either of:
+
+ toc.html table of contents for HTML docs
+ index.html pointers to everything, including
+ text files not in HTML docs
+
+The Makefile in this directory can generate various
+things from the HTML source:
+
+ ./*.html individual HTML files
+ with previous/contents/next links
+ toc.html table of contents
+ HowTo.html one big HTML file
+ HowTo.ps Postscript
+ HowTo.pdf PDF
+ HowTo.txt ASCII text
+
+Not all of the above are in the shipped version. All but
+text are on our website, www.freeswan.org. To get PDF or
+Postscript, either grab them from the web or install
+htmldoc from www.easysw.com, then use the Makefile.
+
+Subdirectories are:
+ src/*.html HTML source files
+ manpage.d/*.html HTML versions of man pages
+
+You should not need to look at these, except for following
+links to HTML man pages.
+
+The Internet Drafts are natively in XML format. They have been
+converted with Marshall Rose's xml2rfc.
+
+xml2rfc is available at xml.resource.org.
+You may have to install the TclXML package by symlinking it into
+/usr/lib/tcl8.3 or some such.
+
+
diff --git a/doc/adv_config.html b/doc/adv_config.html
new file mode 100644
index 000000000..4b779c753
--- /dev/null
+++ b/doc/adv_config.html
@@ -0,0 +1,1232 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="kernel.html">Previous</A>
+<A HREF="install.html">Next</A>
+<HR>
+<H1><A name="adv_config">Other configuration possibilities</A></H1>
+<P>This document describes various options for FreeS/WAN configuration
+ which are less used or more complex (often both) than the standard
+ cases described in our<A href="config.html#config"> config</A> and<A href="quickstart.html#quick_guide">
+ quickstart</A> documents.</P>
+<H2><A name="thumb">Some rules of thumb about configuration</A></H2>
+<H3><A name="cheap.tunnel">Tunnels are cheap</A></H3>
+<P>Nearly all of the overhead in IPsec processing is in the encryption
+ and authentication of packets. Our<A href="performance.html">
+ performance</A> document discusses these overheads.</P>
+<P>Beside those overheads, the cost of managing additional tunnels is
+ trivial. Whether your gateway supports one tunnel or ten just does not
+ matter. A hundred might be a problem; there is a<A href="performance.html#biggate">
+ section</A> on this in the performance document.</P>
+<P>So, in nearly all cases, if using multiple tunnels gives you a
+ reasonable way to describe what you need to do, you should describe it
+ that way in your configuration files.</P>
+<P>For example, one user recently asked on a mailing list about this
+ network configuration:</P>
+<PRE> netA---gwA---gwB---netB
+ |----netC
+
+ netA and B are secured netC not.
+ netA and gwA can not access netC</PRE>
+<P>The user had constructed only one tunnel, netA to netB, and wanted to
+ know how to use ip-route to get netC packets into it. This is entirely
+ unnecessary. One of the replies was:</P>
+<PRE> The simplest way and indeed the right way to
+ solve this problem is to set up two connections:
+
+ leftsubnet=NetA
+ left=gwA
+ right=gwB
+ rightsubnet=NetB
+ and
+ leftsubnet=NetA
+ left=gwA
+ right=gwB
+ rightsubnet=NetC</PRE>
+<P>This would still be correct even if we added nets D, E, F, ... to the
+ above diagram and needed twenty tunnels.</P>
+<P>Of course another possibility would be to just use one tunnel, with a
+ subnet mask that includes both netB and netC (or B, C, D, ...). See
+ next section.</P>
+<P>In general, you can construct as many tunnels as you need. Networks
+ like netC in this example that do not connect directly to the gateway
+ are fine, as long as the gateway can route to them.</P>
+<P>The number of tunnels can become an issue if it reaches 50 or so.
+ This is discussed in the<A href="performance.html#biggate"> performance</A>
+ document. Look there for information on supporting hundreds of Road
+ Warriors from one gateway.</P>
+<P>If you find yourself with too many tunnels for some reason like
+ having eight subnets at one location and nine at another so you end up
+ with 9*8=72 tunnels, read the next section here.</P>
+<H3><A name="subnet.size">Subnet sizes</A></H3>
+<P>The subnets used in<VAR> leftsubnet</VAR> and<VAR> rightsubnet</VAR>
+ can be of any size that fits your needs, and they need not correspond
+ to physical networks.</P>
+<P>You adjust the size by changing the<A href="glossary.html#subnet">
+ subnet mask</A>, the number after the slash in the subnet description.
+ For example</P>
+<UL>
+<LI>in 192.168.100.0/24 the /24 mask says 24 bits are used to designate
+ the network. This leave 8 bits to label machines. This subnet has 256
+ addresses. .0 and .255 are reserved, so it can have 254 machines.</LI>
+<LI>A subnet with a /23 mask would be twice as large, 512 addresses.</LI>
+<LI>A subnet with a /25 mask would be half the size, 128 addresses.</LI>
+<LI>/0 is the whole Internet</LI>
+<LI>/32 is a single machine</LI>
+</UL>
+<P>As an example of using these in connection descriptions, suppose your
+ company's head office has four physical networks using the address
+ ranges:</P>
+<DL>
+<DT>192.168.100.0/24</DT>
+<DD>development</DD>
+<DT>192.168.101.0/24</DT>
+<DD>production</DD>
+<DT>192.168.102.0/24</DT>
+<DD>marketing</DD>
+<DT>192.168.103.0/24</DT>
+<DD>administration</DD>
+</DL>
+<P>You can use exactly those subnets in your connection descriptions, or
+ use larger subnets to grant broad access if required:</P>
+<DL>
+<DT>leftsubnet=192.168.100.0/24</DT>
+<DD>remote hosts can access only development</DD>
+<DT>leftsubnet=192.168.100.0/23</DT>
+<DD>remote hosts can access development or production</DD>
+<DT>leftsubnet=192.168.102.0/23</DT>
+<DD>remote hosts can access marketing or administration</DD>
+<DT>leftsubnet=192.168.100.0/22</DT>
+<DD>remote hosts can access any of the four departments</DD>
+</DL>
+<P>or use smaller subnets to restrict access:</P>
+<DL>
+<DT>leftsubnet=192.168.103.0/24</DT>
+<DD>remote hosts can access any machine in administration</DD>
+<DT>leftsubnet=192.168.103.64/28</DT>
+<DD>remote hosts can access only certain machines in administration.</DD>
+<DT>leftsubnet=192.168.103.42/32</DT>
+<DD>remote hosts can access only one particular machine in
+ administration</DD>
+</DL>
+<P>To be exact, 192.68.103.64/28 means all addresses whose top 28 bits
+ match 192.168.103.64. There are 16 of these because there are 16
+ possibilities for the remainingg 4 bits. Their addresses are
+ 192.168.103.64 to 192.168.103.79.</P>
+<P>Each connection description can use a different subnet if required.</P>
+<P>It is possible to use all the examples above on the same FreeS/WAN
+ gateway, each in a different connection description, perhaps for
+ different classes of user or for different remote offices.</P>
+<P>It is also possible to have multiple tunnels using different<VAR>
+ leftsubnet</VAR> descriptions with the same<VAR> right</VAR>. For
+ example, when the marketing manager is on the road he or she might have
+ access to:</P>
+<DL>
+<DT>leftsubnet=192.168.102.0/24</DT>
+<DD>all machines in marketing</DD>
+<DT>192.168.101.32/29</DT>
+<DD>some machines in production</DD>
+<DT>leftsubnet=192.168.103.42/32</DT>
+<DD>one particular machine in administration</DD>
+</DL>
+<P>This takes three tunnels, but tunnels are cheap. If the laptop is set
+ up to build all three tunnels automatically, then he or she can access
+ all these machines concurrently, perhaps from different windows.</P>
+<H3><A name="example.more">Other network layouts</A></H3>
+<P>Here is the usual network picture for a site-to-site VPN::</P>
+<PRE> Sunset==========West------------------East=========Sunrise
+ local net untrusted net local net</PRE>
+<P>and for the Road Warrior::</P>
+<PRE> telecommuter's PC or
+ traveller's laptop
+ Sunset==========West------------------East
+ corporate LAN untrusted net</PRE>
+<P>Other configurations are also possible.</P>
+<H4><A name="internet.subnet">The Internet as a big subnet</A></H4>
+<P>A telecommuter might have:</P>
+<PRE> Sunset==========West------------------East ================= firewall --- the Internet
+ home network untrusted net corporate network</PRE>
+<P>This can be described as a special case of the general
+ subnet-to-subnet connection. The subnet on the right is 0.0.0.0/0, the
+ whole Internet.</P>
+<P>West (the home gateway) can have its firewall rules set up so that
+ only IPsec packets to East are allowed out. It will then behave as if
+ its only connection to the world was a wire to East.</P>
+<P>When machines on the home network need to reach the Internet, they do
+ so via the tunnel, East and the corporate firewall. From the viewpoint
+ of the Internet (perhaps of some EvilDoer trying to break in!), those
+ home office machines are behind the firewall and protected by it.</P>
+<H4><A name="wireless.config">Wireless</A></H4>
+<P>Another possible configuration comes up when you do not trust the
+ local network, either because you have very high security standards or
+ because your are using easily-intercepted wireless signals.</P>
+<P>Some wireless networks have built-in encryption called<A href="glossary.html#WEP">
+ WEP</A>, but its security is dubious. It is a fairly common practice to
+ use IPsec instead.</P>
+<P>In this case, part of your network may look like this:</P>
+<PRE> West-----------------------------East == the rest of your network
+ workstation untrusted wireless net</PRE>
+<P>Of course, there would likely be several wireless workstations, each
+ with its own IPsec tunnel to the East gateway.</P>
+<P>The connection descriptions look much like Road Warrior descriptions:</P>
+<UL>
+<LI>each workstation should have its own unique
+<UL>
+<LI>identifier for IPsec</LI>
+<LI>RSA key</LI>
+<LI>connection description.</LI>
+</UL>
+</LI>
+<LI>on the gateway, use<VAR> left=%any</VAR>, or the workstation IP
+ address</LI>
+<LI>on workstations,<VAR> left=%defaultroute</VAR>, or the workstation
+ IP address</LI>
+<LI><VAR>leftsubnet=</VAR> is not used.</LI>
+</UL>
+<P>The<VAR> rightsubnet=</VAR> parameter might be set in any of several
+ ways:</P>
+<DL>
+<DT>rightsubnet=0.0.0.0/0</DT>
+<DD>allowing workstations to access the entire Internet (see<A href="#internet.subnet">
+ above</A>)</DD>
+<DT>rightsubnet=a.b.c.0/24</DT>
+<DD>allowing access to your entire local network</DD>
+<DT>rightsubnet=a.b.c.d/32</DT>
+<DD>restricting the workstation to connecting to a particular server</DD>
+</DL>
+<P>Of course you can mix and match these as required. For example, a
+ university might allow faculty full Internet access while letting
+ student laptops connect only to a group of lab machines.</P>
+<H2><A name="choose">Choosing connection types</A></H2>
+<P>One choice you need to make before configuring additional connections
+ is what type or types of connections you will use. There are several
+ options, and you can use more than one concurrently.</P>
+<H3><A name="man-auto">Manual vs. automatic keying</A></H3>
+<P>IPsec allows two types of connections, with manual or automatic
+ keying. FreeS/WAN starts them with commands such as:</P>
+<PRE> ipsec manual --up <VAR>name</VAR>
+ ipsec auto --up <VAR>name</VAR></PRE>
+<P>The difference is in how they are keyed.</P>
+<DL>
+<DT><A href="glossary.html#manual">Manually keyed</A> connections</DT>
+<DD>use keys stored in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf</A>
+.</DD>
+<DT><A href="glossary.html#auto">Automatically keyed</A> connections</DT>
+<DD>use keys automatically generated by the Pluto key negotiation
+ daemon. The key negotiation protocol,<A href="glossary.html#IKE"> IKE</A>
+, must authenticate the other system. (It is vulnerable to a<A href="glossary.html#middle">
+ man-in-the-middle attack</A> if used without authentication.) We
+ currently support two authentication methods:
+<UL>
+<LI>using shared secrets stored in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets</A>.</LI>
+<LI>RSA<A href="glossary.html#public"> public key</A> authentication,
+ with our machine's private key in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets</A>. Public keys for other machines may either be placed
+ in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf</A> or provided via
+ DNS.</LI>
+</UL>
+<P>A third method, using RSA keys embedded in<A href="glossary.html#X509">
+ X.509</A> certtificates, is provided by user<A href="web.html#patch">
+ patches</A>.</P>
+</DD>
+</DL>
+<P><A href="glossary.html#manual">Manually keyed</A> connections provide
+ weaker security than<A href="glossary.html#auto"> automatically keyed</A>
+ connections. An opponent who reads ipsec.secrets(5) gets your
+ encryption key and can read all data encrypted by it. If he or she has
+ an archive of old messages, all of them back to your last key change
+ are also readable.</P>
+<P>With automatically-(re)-keyed connections, an opponent who reads
+ ipsec.secrets(5) gets the key used to authenticate your system in IKE
+ -- the shared secret or your private key, depending what authentication
+ mechanism is in use. However, he or she does not automatically gain
+ access to any encryption keys or any data.</P>
+<P>An attacker who has your authentication key can mount a<A href="glossary.html#middle">
+ man-in-the-middle attack</A> and, if that succeeds, he or she will get
+ encryption keys and data. This is a serious danger, but it is better
+ than having the attacker read everyting as soon as he or she breaks
+ into ipsec.secrets(5).. Moreover, the keys change often so an opponent
+ who gets one key does not get a large amount of data. To read all your
+ data, he or she would have to do a man-in-the-middle attack at every
+ key change.</P>
+<P>We discuss using<A href="#prodman"> manual keying in production</A>
+ below, but this is<STRONG> not recommended</STRONG> except in special
+ circumstances, such as needing to communicate with some implementation
+ that offers no auto-keyed mode compatible with FreeS/WAN.</P>
+<P>Manual keying may also be useful for testing. There is some
+ discussion of this in our<A href="faq.html#man4debug"> FAQ</A>.</P>
+<H3><A name="auto-auth">Authentication methods for auto-keying</A></H3>
+<P>The IKE protocol which Pluto uses to negotiate connections between
+ gateways must use some form of authentication of peers. A gateway must
+ know who it is talking to before it can create a secure connection. We
+ support two basic methods for this authentication:</P>
+<UL>
+<LI>shared secrets, stored in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A></LI>
+<LI>RSA authentication</LI>
+</UL>
+<P>There are, howver, several variations on the RSA theme, using
+ different methods of managing the RSA keys:</P>
+<UL>
+<LI>our RSA private key in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A> with other gateways' public keys
+<DL>
+<DT>either</DT>
+<DD>stored in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A></DD>
+<DT>or</DT>
+<DD>looked up via<A href="glossary.html#DNS"> DNS</A></DD>
+</DL>
+</LI>
+<LI>authentication with<A href="glossary.html#x509"> x.509</A>
+ certificates.; See our<A href="web.html#patch"> links section</A> for
+ information on user-contributed patches for this.:</LI>
+</UL>
+<P>Public keys in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5</A>
+) give a reasonably straightforward method of specifying keys for
+ explicitly configured connections.</P>
+<P>Putting public keys in DNS allows us to support<A href="glossary.html#carpediem">
+ opportunistic encryption</A>. Any two FreeS/WAN gateways can provide
+ secure communication, without either of them having any preset
+ information about the other.</P>
+<P>X.509 certificates may be required to interface to various<A href="glossary.html#PKI">
+ PKI</A>s.</P>
+<H3><A name="adv-pk">Advantages of public key methods</A></H3>
+<P>Authentication with a<A href="glossary.html#public"> public key</A>
+ method such as<A href="glossary.html#RSA"> RSA</A> has some important
+ advantages over using shared secrets.</P>
+<UL>
+<LI>no problem of secure transmission of secrets
+<UL>
+<LI>A shared secret must be shared, so you have the problem of
+ transmitting it securely to the other party. If you get this wrong, you
+ have no security.</LI>
+<LI>With a public key technique, you transmit only your public key. The
+ system is designed to ensure that it does not matter if an enemy
+ obtains public keys. The private key never leaves your machine.</LI>
+</UL>
+</LI>
+<LI>easier management
+<UL>
+<LI>Suppose you have 20 branch offices all connecting to one gateway at
+ head office, and all using shared secrets. Then the head office admin
+ has 20 secrets to manage. Each of them must be kept secret not only
+ from outsiders, but also from 19 of the branch office admins. The
+ branch office admins have only one secret each to manage.
+<P>If the branch offices need to talk to each other, this becomes
+ problematic. You need another 20*19/2 = 190 secrets for
+ branch-to-branch communication, each known to exactly two branches. Now
+ all the branch admins have the headache of handling 20 keys, each
+ shared with exactly one other branch or with head office.</P>
+<P>For larger numbers of branches, the number of connections and secrets
+ increases quadratically and managing them becomes a nightmare. A
+ 1000-gateway fully connected network needs 499,500 secrets, each known
+ to exactly two players. There are ways to reduce this problem, for
+ example by introducing a central key server, but these involve
+ additional communication overheads, more administrative work, and new
+ threats that must be carefully guarded against.</P>
+</LI>
+<LI>With public key techniques, the<EM> only</EM> thing you have to keep
+ secret is your private key, and<EM> you keep that secret from everyone</EM>
+.
+<P>As network size increaes, the number of public keys used increases
+ linearly with the number of nodes. This still requires careful
+ administration in large applications, but is nothing like the disaster
+ of a quadratic increase. On a 1000-gateway network, you have 1000
+ private keys, each of which must be kept secure on one machine, and
+ 1000 public keys which must be distributed. This is not a trivial
+ problem, but it is manageable.</P>
+</LI>
+</UL>
+</LI>
+<LI>does not require fixed IP addresses
+<UL>
+<LI>When shared secrets are used in IPsec, the responder must be able to
+ tell which secret to use by looking at the IP address on the incoming
+ packets. When the other parties do not have a fixed IP address to be
+ identified by (for example, on nearly all dialup ISP connections and
+ many cable or ADSL links), this does not work well -- all must share
+ the same secret!</LI>
+<LI>When RSA authentication is in use, the initiator can identify itself
+ by name before the key must be determined. The responder then checks
+ that the message is signed with the public key corresponding to that
+ name.</LI>
+</UL>
+</LI>
+</UL>
+<P>There is also a disadvantage:</P>
+<UL>
+<LI>your private key is a single point of attack, extremely valuable to
+ an enemy
+<UL>
+<LI>with shared secrets, an attacker who steals your ipsec.secrets file
+ can impersonate you or try<A href="glossary.html#middle">
+ man-in-the-middle</A> attacks, but can only attack connections
+ described in that file</LI>
+<LI>an attacker who steals your private key gains the chance to attack
+ not only existing connections<EM> but also any future connections</EM>
+ created using that key</LI>
+</UL>
+</LI>
+</UL>
+<P>This is partly counterbalanced by the fact that the key is never
+ transmitted and remains under your control at all times. It is likely
+ necessary, however, to take account of this in setting security policy.
+ For example, you should change gateway keys when an administrator
+ leaves the company, and should change them periodically in any case.</P>
+<P>Overall, public key methods are<STRONG> more secure, more easily
+ managed and more flexible</STRONG>. We recommend that they be used for
+ all connections, unless there is a compelling reason to do otherwise.</P>
+<H2><A name="prodsecrets">Using shared secrets in production</A></H2>
+<P>Generally, public key methods are preferred for reasons given above,
+ but shared secrets can be used with no loss of security, just more work
+ and perhaps more need to take precautions.</P>
+<P>What I call &quot;shared secrets&quot; are sometimes also called &quot;pre-shared
+ keys&quot;. They are used only for for authentication, never for encryption.
+ Calling them &quot;pre-shared keys&quot; has confused some users into thinking
+ they were encryption keys, so I prefer to avoid the term..</P>
+<P>If you are interoperating with another IPsec implementation, you may
+ find its documentation calling them &quot;passphrases&quot;.</P>
+<H3><A name="secrets">Putting secrets in ipsec.secrets(5)</A></H3>
+<P>If shared secrets are to be used to<A href="glossary.html#authentication">
+ authenticate</A> communication for the<A href="glossary.html#DH">
+ Diffie-Hellman</A> key exchange in the<A href="glossary.html#IKE"> IKE</A>
+ protocol, then those secrets must be stored in<VAR> /etc/ipsec.secrets</VAR>
+. For details, see the<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A> man page.</P>
+<P>A few considerations are vital:</P>
+<UL>
+<LI>make the secrets long and unguessable. Since they need not be
+ remembered by humans, very long ugly strings may be used. We suggest
+ using our<A href="manpage.d/ipsec_ranbits.8.html"> ipsec_ranbits(8)</A>
+ utility to generate long (128 bits or more) random strings.</LI>
+<LI>transmit secrets securely. You have to share them with other
+ systems, but you lose if they are intercepted and used against you. Use<A
+href="glossary.html#PGP"> PGP</A>,<A href="glossary.html#SSH"> SSH</A>,
+ hand delivery of a floppy disk which is then destroyed, or some other
+ trustworthy method to deliver them.</LI>
+<LI>store secrets securely, in root-owned files with permissions
+ rw------.</LI>
+<LI>limit sharing of secrets. Alice, Bob, Carol and Dave may all talk to
+ each other, but only Alice and Bob should know the secret for an
+ Alice-Bob link.</LI>
+<LI><STRONG>do not share private keys</STRONG>. The private key for RSA
+ authentication of your system is stored in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A>, but it is a different class of secret from the
+ pre-shared keys used for the &quot;shared secret&quot; authentication. No-one but
+ you should have the RSA private key.</LI>
+</UL>
+<P>Each line has the IP addresses of the two gateways plus the secret.
+ It should look something like this:</P>
+<PRE> 10.0.0.1 11.0.0.1 : PSK &quot;jxTR1lnmSjuj33n4W51uW3kTR55luUmSmnlRUuWnkjRj3UuTV4T3USSu23Uk55nWu5TkTUnjT&quot;</PRE>
+<P><VAR>PSK</VAR> indicates the use of a<STRONG> p</STRONG>re-<STRONG>s</STRONG>
+hared<STRONG> k</STRONG>ey. The quotes and the whitespace shown are
+ required.</P>
+<P>You can use any character string as your secret. For security, it
+ should be both long and extremely hard to guess. We provide a utility
+ to generate such strings,<A href="manpage.d/ipsec_ranbits.8.html">
+ ipsec_ranbits(8)</A>.</P>
+<P>You want the same secret on the two gateways used, so you create a
+ line with that secret and the two gateway IP addresses. The
+ installation process supplies an example secret, useful<EM> only</EM>
+ for testing. You must change it for production use.</P>
+<H3><A name="securing.secrets">File security</A></H3>
+<P>You must deliver this file, or the relevant part of it, to the other
+ gateway machine by some<STRONG> secure</STRONG> means.<EM> Don't just
+ FTP or mail the file!</EM> It is vital that the secrets in it remain
+ secret. An attacker who knew those could easily have<EM> all the data
+ on your &quot;secure&quot; connection</EM>.</P>
+<P>This file must be owned by root and should have permissions<VAR>
+ rw-------</VAR>.</P>
+<H3><A name="notroadshared">Shared secrets for road warriors</A></H3>
+<P>You can use a shared secret to support a single road warrior
+ connecting to your gateway, and this is a reasonable thing to do in
+ some circumstances. Public key methods have advantages, discussed<A href="#choose">
+ above</A>, but they are not critical in this case.</P>
+<P>To do this, the line in ipsec.secrets(5) is something like:</P>
+<PRE> 10.0.0.1 0.0.0.0 : PSK &quot;jxTR1lnmSjuj33n4W51uW3kTR55luUmSmnlRUuWnkjRj3UuTV4T3USSu23Uk55nWu5TkTUnjT&quot;</PRE>
+ where the<VAR> 0.0.0.0</VAR> means that any IP address is acceptable.
+<P><STRONG>For more than one road warrior, shared secrets are<EM> not</EM>
+ recommended.</STRONG> If shared secrets are used, then when the
+ responder needs to look up the secret, all it knows about the sender is
+ an IP address. This is fine if the sender is at a fixed IP address
+ specified in the config file. It is also fine if only one road warrior
+ uses the wildcard<VAR> 0.0.0.0</VAR> address. However, if you have more
+ than one road warrior using shared secret authentication, then they
+ must all use that wildcard and therefore<STRONG> all road warriors
+ using PSK autentication must use the same secret</STRONG>. Obviously,
+ this is insecure.</P>
+<P><STRONG>For multiple road warriors, use public key authentication.</STRONG>
+ Each roadwarrior can then have its own identity (our<VAR> leftid=</VAR>
+ or<VAR> rightid=</VAR> parameters), its own public/private key pair,
+ and its own secure connection.</P>
+<H2><A name="prodman">Using manual keying in production</A></H2>
+<P>Generally,<A href="glossary.html#auto"> automatic keying</A> is
+ preferred over<A href="glossary.html#manual"> manual keying</A> for
+ production use because it is both easier to manage and more secure.
+ Automatic keying frees the admin from much of the burden of managing
+ keys securely, and can provide<A href="glossary.html#PFS"> perfect
+ forward secrecy</A>. This is discussed in more detail<A href="#man-auto">
+ above</A>.</P>
+<P>However, it is possible to use manual keying in production if that is
+ what you want to do. This might be necessary, for example, in order to
+ interoperate with some device that either does not provide automatic
+ keying or provides it in some version we cannot talk to.</P>
+<P>Note that with manual keying<STRONG> all security rests with the keys</STRONG>
+. If an adversary acquires your keys, you've had it. He or she can read
+ everything ever sent with those keys, including old messages he or she
+ may have archived.</P>
+<P>You need to<STRONG> be really paranoid about keys</STRONG> if you're
+ going to rely on manual keying for anything important.</P>
+<UL>
+<LI>keep keys in files with 600 permissions, owned by root</LI>
+<LI>be extremely careful about security of your gateway systems. Anyone
+ who breaks into a gateway and gains root privileges can get all your
+ keys and read everything ever encrypted with those keys, both old
+ messages he has archived and any new ones you may send.</LI>
+<LI>change keys regularly. This can be a considerable bother, (and
+ provides an excellent reason to consider automatic keying instead), but
+ it is<EM> absolutely essential</EM> for security. Consider a manually
+ keyed system in which you leave the same key in place for months:
+<UL>
+<LI>an attacker can have a very large sample of text sent with that key
+ to work with. This makes various cryptographic attacks much more likely
+ to succeed.</LI>
+<LI>The chances of the key being compromised in some non-cryptographic
+ manner -- a spy finds it on a discarded notepad, someone breaks into
+ your server or your building and steals it, a staff member is bribed,
+ tricked, seduced or coerced into revealing it, etc. -- also increase
+ over time.</LI>
+<LI>a successful attacker can read everything ever sent with that key.
+ This makes any successful attack extremely damaging.</LI>
+</UL>
+ It is clear that you must change keys often to have any useful
+ security. The only question is how often.</LI>
+<LI>use<A href="glossary.html#PGP"> PGP</A> or<A href="glossary.html#SSH">
+ SSH</A> for all key transfers</LI>
+<LI>don't edit files with keys in them when someone can look over your
+ shoulder</LI>
+<LI>worry about network security; could someone get keys by snooping
+ packets on the LAN between your X desktop and the gateway?</LI>
+<LI>lock up your backup tapes for the gateway system</LI>
+<LI>... and so on</LI>
+</UL>
+<P>Linux FreeS/WAN provides some facilities to help with this. In
+ particular, it is good policy to<STRONG> keep keys in separate files</STRONG>
+ so you can edit configuration information in /etc/ipsec.conf without
+ exposing keys to &quot;shoulder surfers&quot; or network snoops. We support this
+ with the<VAR> also=</VAR> and<VAR> include</VAR> syntax in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>.</P>
+<P>See the last example in our<A href="examples"> examples</A> file. In
+ the /etc/ipsec.conf<VAR> conn samplesep</VAR> section, it has the line:</P>
+<PRE> also=samplesep-keys</PRE>
+<P>which tells the &quot;ipsec manual&quot; script to insert the configuration
+ description labelled &quot;samplesep-keys&quot; if it can find it. The
+ /etc/ipsec.conf file must also have a line such as:</P>
+<PRE>include ipsec.*.conf</PRE>
+<P>which tells it to read other files. One of those other files then
+ might contain the additional data:</P>
+<PRE>conn samplesep-keys
+ spi=0x200
+ esp=3des-md5-96
+ espenckey=0x01234567_89abcdef_02468ace_13579bdf_12345678_9abcdef0
+ espauthkey=0x12345678_9abcdef0_2468ace0_13579bdf</PRE>
+<P>The first line matches the label in the &quot;also=&quot; line, so the indented
+ lines are inserted. The net effect is exactly as if the inserted lines
+ had occurred in the original file in place of the &quot;also=&quot; line.</P>
+<P>Variables set here are:</P>
+<DL>
+<DT>spi</DT>
+<DD>A number needed by the manual keying code. Any 3-digit hex number
+ will do, but if you have more than one manual connection then<STRONG>
+ spi must be different</STRONG> for each connection.</DD>
+<DT>esp</DT>
+<DD>Options for<A href="glossary.html#ESP"> ESP</A> (Encapsulated
+ Security Payload), the usual IPsec encryption mode. Settings here are
+ for<A href="glossary.html#encryption"> encryption</A> using<A href="glossary.html#3DES">
+ triple DES</A> and<A href="glossary.html#authentication">
+ authentication</A> using<A href="glossary.html#MD5"> MD5</A>. Note that
+ encryption without authentication should not be used; it is insecure.</DD>
+<DT>espenkey</DT>
+<DD>Key for ESP encryption. Here, a 192-bit hex number for triple DES.</DD>
+<DT>espauthkey</DT>
+<DD>Key for ESP authentication. Here, a 128-bit hex number for MD5.</DD>
+</DL>
+<P><STRONG>Note</STRONG> that the<STRONG> example keys we supply</STRONG>
+ are intended<STRONG> only for testing</STRONG>. For real use, you
+ should go to automatic keying. If that is not possible, create your own
+ keys for manual mode and keep them secret</P>
+<P>Of course, any files containing keys<STRONG> must</STRONG> have 600
+ permissions and be owned by root.</P>
+<P>If you connect in this way to multiple sites, we recommend that you
+ keep keys for each site in a separate file and adopt some naming
+ convention that lets you pick them all up with a single &quot;include&quot; line.
+ This minimizes the risk of losing several keys to one error or attack
+ and of accidentally giving another site admin keys which he or she has
+ no business knowing.</P>
+<P>Also note that if you have multiple manually keyed connections on a
+ single machine, then the<VAR> spi</VAR> parameter must be different for
+ each one. Any 3-digit hex number is OK, provided they are different for
+ each connection. We reserve the range 0x100 to 0xfff for manual
+ connections. Pluto assigns SPIs from 0x1000 up for automatically keyed
+ connections.</P>
+<P>If<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> contains
+ keys for manual mode connections, then it too must have permissions<VAR>
+ rw-------</VAR>. We recommend instead that, if you must manual keying
+ in production, you keep the keys in separate files.</P>
+<P>Note also that<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf</A>
+ is installed with permissions<VAR> rw-r--r--</VAR>. If you plan to use
+ manually keyed connections for anything more than initial testing, you<B>
+ must</B>:</P>
+<UL>
+<LI>either change permissions to<VAR> rw-------</VAR></LI>
+<LI>or store keys separately in secure files and access them via include
+ statements in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf</A>.</LI>
+</UL>
+<P>We recommend the latter method for all but the simplest
+ configurations.</P>
+<H3><A name="ranbits">Creating keys with ranbits</A></H3>
+<P>You can create new<A href="glossary.html#random"> random</A> keys
+ with the<A href="manpage.d/ipsec_ranbits.8.html"> ranbits(8)</A>
+ utility. For example, the commands:</P>
+<PRE> umask 177
+ ipsec ranbits 192 &gt; temp
+ ipsec ranbits 128 &gt;&gt; temp</PRE>
+<P>create keys in the sizes needed for our default algorithms:</P>
+<UL>
+<LI>192-bit key for<A href="glossary.html#3DES"> 3DES</A> encryption
+<BR> (only 168 bits are used; parity bits are ignored)</LI>
+<LI>128-bit key for keyed<A href="glossary.html#MD5"> MD5</A>
+ authentication</LI>
+</UL>
+<P>If you want to use<A href="glossary.html#SHA"> SHA</A> instead of<A href="glossary.html#MD5">
+ MD5</A>, that requires a 160-bit key</P>
+<P>Note that any<STRONG> temporary files</STRONG> used must be kept<STRONG>
+ secure</STRONG> since they contain keys. That is the reason for the
+ umask command above. The temporary file should be deleted as soon as
+ you are done with it. You may also want to change the umask back to its
+ default value after you are finished working on keys.</P>
+<P>The ranbits utility may pause for a few seconds if not enough entropy
+ is available immediately. See ipsec_ranbits(8) and random(4) for
+ details. You may wish to provide some activity to feed entropy into the
+ system. For example, you might move the mouse around, type random
+ characters, or do<VAR> du /usr &gt; /dev/null</VAR> in the background.</P>
+<H2><A name="boot">Setting up connections at boot time</A></H2>
+<P>You can tell the system to set up connections automatically at boot
+ time by putting suitable stuff in /etc/ipsec.conf on both systems. The
+ relevant section of the file is labelled by a line reading<VAR> config
+ setup</VAR>.</P>
+<P>Details can be found in the<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> man page. We also provide a file of<A href="examples">
+ example configurations</A>.</P>
+<P>The most likely options are something like:</P>
+<DL>
+<DT>interfaces=&quot;ipsec0=eth0 ipsec1=ppp0&quot;</DT>
+<DD>Tells KLIPS which interfaces to use. Up to four interfaces numbered
+ ipsec[0-3] are supported. Each interface can support an arbitrary
+ number of tunnels.
+<P>Note that for PPP, you give the ppp[0-9] device name here, not the
+ underlying device such as modem (or eth1 if you are using PPPoE).</P>
+</DD>
+<DT>interfaces=%defaultroute</DT>
+<DD>Alternative setting, useful in simple cases. KLIPS will pick up both
+ its interface and the next hop information from the settings of the
+ Linux default route.</DD>
+<DT>forwardcontrol=no</DT>
+<DD>Normally &quot;no&quot;. Set to &quot;yes&quot; if the IP forwarding option is disabled
+ in your network configuration. (This can be set as a kernel
+ configuration option or later. e.g. on Redhat, it's in
+ /etc/sysconfig/network and on SuSE you can adjust it with Yast.) Linux
+ FreeS/WAN will then enable forwarding when starting up and turn it off
+ when going down. This is used to ensure that no packets will be
+ forwarded before IPsec comes up and takes control.</DD>
+<DT>syslog=daemon.error</DT>
+<DD>Used in messages to the system logging daemon (syslogd) to specify
+ what type of software is sending the messages. If the settings are
+ &quot;daemon.error&quot; as in our example, then syslogd treats the messages as
+ error messages from a daemon.
+<P>Note that<A href="glossary.html#Pluto"> Pluto</A> does not currently
+ pay attention to this variable. The variable controls setup messages
+ only.</P>
+</DD>
+<DT>klipsdebug=</DT>
+<DD>Debug settings for<A href="glossary.html#KLIPS"> KLIPS</A>.</DD>
+<DT>plutodebug=</DT>
+<DD>Debug settings for<A href="glossary.html#Pluto"> Pluto</A>.</DD>
+<DT>... for both the above DEBUG settings</DT>
+<DD>Normally, leave empty as shown above for no debugging output.
+<BR> Use &quot;all&quot; for maximum information.
+<BR> See ipsec_klipsdebug(8) and ipsec_pluto(8) man page for other
+ options. Beware that if you set /etc/ipsec.conf to enable debug output,
+ your system's log files may get large quickly.</DD>
+<DT>dumpdir=/safe/directory</DT>
+<DD>Normally, programs started by ipsec setup don't crash. If they do,
+ by default, no core dump will be produced because such dumps would
+ contain secrets. If you find you need to debug such crashes, you can
+ set dumpdir to the name of a directory in which to collect the core
+ file.</DD>
+<DT>manualstart=</DT>
+<DD>List of manually keyed connections to be automatically started at
+ boot time. Useful for testing, but not for long term use. Connections
+ which are automatically started should also be automatically re-keyed.</DD>
+<DT>pluto=yes</DT>
+<DD>Whether to start<A href="glossary.html#Pluto"> Pluto</A> when ipsec
+ startup is done.
+<BR> This parameter is optional and defaults to &quot;yes&quot; if not present.
+<P>&quot;yes&quot; is strongly recommended for production use so that the keying
+ daemon (Pluto) will automatically re-key the connections regularly. The
+ ipsec-auto parameters ikelifetime, ipseclifetime and reykeywindow give
+ you control over frequency of rekeying.</P>
+</DD>
+<DT>plutoload=&quot;reno-van reno-adam reno-nyc&quot;</DT>
+<DD>List of tunnels (by name, e.g. fred-susan or reno-van in our
+ examples) to be loaded into Pluto's internal database at startup. In
+ this example, Pluto loads three tunnels into its database when it is
+ started.
+<P>If plutoload is &quot;%search&quot;, Pluto will load any connections whose
+ description includes &quot;auto=add&quot; or &quot;auto=start&quot;.</P>
+</DD>
+<DT>plutostart=&quot;reno-van reno-adam reno-nyc&quot;</DT>
+<DD>List of tunnels to attempt to negotiate when Pluto is started.
+<P>If plutostart is &quot;%search&quot;, Pluto will start any connections whose
+ description includes &quot;auto=start&quot;.</P>
+<P>Note that, for a connection intended to be permanent,<STRONG> both
+ gateways should be set try to start</STRONG> the tunnel. This allows
+ quick recovery if either gateway is rebooted or has its IPsec
+ restarted. If only one gateway is set to start the tunnel and the other
+ gateway restarts, the tunnel may not be rebuilt.</P>
+</DD>
+<DT>plutowait=no</DT>
+<DD>Controls whether Pluto waits for one tunnel to be established before
+ starting to negotiate the next. You might set this to &quot;yes&quot;
+<UL>
+<LI>if your gateway is a very limited machine and you need to conserve
+ resources.</LI>
+<LI>for debugging; the logs are clearer if only one connection is
+ brought up at a time</LI>
+</UL>
+ For a busy and resource-laden production gateway, you likely want &quot;no&quot;
+ so that connections are brought up in parallel and the whole process
+ takes less time.</DD>
+</DL>
+<P>The example assumes you are at the Reno office and will use IPsec to
+ Vancouver, New York City and Amsterdam.</P>
+<H2><A name="multitunnel">Multiple tunnels between the same two gateways</A>
+</H2>
+<P>Consider a pair of subnets, each with a security gateway, connected
+ via the Internet:</P>
+<PRE> 192.168.100.0/24 left subnet
+ |
+ 192.168.100.1
+ North Gateway
+ 101.101.101.101 left
+ |
+ 101.101.101.1 left next hop
+ [Internet]
+ 202.202.202.1 right next hop
+ |
+ 202.202.202.202 right
+ South gateway
+ 192.168.200.1
+ |
+ 192.168.200.0/24 right subnet</PRE>
+<P>A tunnel specification such as:</P>
+<PRE>conn northnet-southnet
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ leftsubnet=192.168.100.0/24
+ leftfirewall=yes
+ right=202.202.202.202
+ rightnexthop=202.202.202.1
+ rightsubnet=192.168.200.0/24
+ rightfirewall=yes</PRE>
+ will allow machines on the two subnets to talk to each other. You might
+ test this by pinging from polarbear (192.168.100.7) to penguin
+ (192.168.200.5).
+<P>However,<STRONG> this does not cover other traffic you might want to
+ secure</STRONG>. To handle all the possibilities, you might also want
+ these connection descriptions:</P>
+<PRE>conn northgate-southnet
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ right=202.202.202.202
+ rightnexthop=202.202.202.1
+ rightsubnet=192.168.200.0/24
+ rightfirewall=yes
+
+conn northnet-southgate
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ leftsubnet=192.168.100.0/24
+ leftfirewall=yes
+ right=202.202.202.202
+ rightnexthop=202.202.202.1</PRE>
+<P>Without these, neither gateway can do IPsec to the remote subnet.
+ There is no IPsec tunnel or eroute set up for the traffic.</P>
+<P>In our example, with the non-routable 192.168.* addresses used,
+ packets would simply be discarded. In a different configuration, with
+ routable addresses for the remote subnet,<STRONG> they would be sent
+ unencrypted</STRONG> since there would be no IPsec eroute and there
+ would be a normal IP route.</P>
+<P>You might also want:</P>
+<PRE>conn northgate-southgate
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ right=202.202.202.202
+ rightnexthop=202.202.202.1</PRE>
+<P>This is required if you want the two gateways to speak IPsec to each
+ other.</P>
+<P>This requires a lot of duplication of details. Judicious use of<VAR>
+ also=</VAR> and<VAR> include</VAR> can reduce this problem.</P>
+<P>Note that, while FreeS/WAN supports all four tunnel types, not all
+ implementations do. In particular, some versions of Windows 2000 and
+ the freely downloadable version of PGP provide only &quot;client&quot;
+ functionality. You cannot use them as gateways with a subnet behind
+ them. To get that functionality, you must upgrade to Windows 2000
+ server or the commercially available PGP products.</P>
+<H3><A name="advroute">One tunnel plus advanced routing</A></H3>
+ It is also possible to use the new routing features in 2.2 and later
+ kernels to avoid most needs for multple tunnels. Here is one mailing
+ list message on the topic:
+<PRE>Subject: Re: linux-ipsec: IPSec packets not entering tunnel?
+ Date: Mon, 20 Nov 2000
+ From: Justin Guyett &lt;jfg@sonicity.com&gt;
+
+On Mon, 20 Nov 2000, Claudia Schmeing wrote:
+
+&gt; Right Left
+&gt; &quot;home&quot; &quot;office&quot;
+&gt; 10.92.10.0/24 ---- 24.93.85.110 ========= 216.175.164.91 ---- 10.91.10.24/24
+&gt;
+&gt; I've created all four tunnels, and can ping to test each of them,
+&gt; *except* homegate-officenet.
+
+I keep wondering why people create all four tunnels. Why not route
+traffic generated from home to 10.91.10.24/24 out ipsec0 with iproute2?
+And 99% of the time you don't need to access &quot;office&quot; directly, which
+means you can eliminate all but the subnet&lt;-&gt;subnet connection.</PRE>
+ and FreeS/WAN technical lead Henry Spencer's comment:
+<PRE>&gt; I keep wondering why people create all four tunnels. Why not route
+&gt; traffic generated from home to 10.91.10.24/24 out ipsec0 with iproute2?
+
+This is feasible, given some iproute2 attention to source addresses, but
+it isn't something we've documented yet... (partly because we're still
+making some attempt to support 2.0.xx kernels, which can't do this, but
+mostly because we haven't caught up with it yet).
+
+&gt; And 99% of the time you don't need to access &quot;office&quot; directly, which
+&gt; means you can eliminate all but the subnet&lt;-&gt;subnet connection.
+
+Correct in principle, but people will keep trying to ping to or from the
+gateways during testing, and sometimes they want to run services on the
+gateway machines too.</PRE>
+
+<!-- Is this in the right spot in this document? -->
+<H2><A name="opp.gate">An Opportunistic Gateway</A></H2>
+<H3><A NAME="14_7_1">Start from full opportunism</A></H3>
+<P>Full opportunism allows you to initiate and receive opportunistic
+ connections on your machine. The remaining instructions in this section
+ assume you have first set up full opportunism on your gateway using<A HREF="quickstart.html#opp.incoming">
+ these instructions</A>. Both sets of instructions require mailing DNS
+ records to your ISP. Collect DNS records for both the gateway (above)
+ and the subnet nodes (below) before contacting your ISP.</P>
+<H3><A NAME="14_7_2">Reverse DNS TXT records for each protected machine</A>
+</H3>
+<P>You need these so that your Opportunistic peers can:</P>
+<UL>
+<LI>discover the gateway's address, knowing only the IP address that
+ packets are bound for</LI>
+<LI>verify that the gateway is authorised to encrypt for that endpoint</LI>
+</UL>
+<P>On the gateway, generate a TXT record with:</P>
+<PRE> ipsec showhostkey --txt 192.0.2.11</PRE>
+<P>Use your gateway address in place of 192.0.2.11.</P>
+<P>You should see (keys are trimmed for clarity throughout our example):</P>
+<PRE> ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+<P><B>This MUST BE the same key as in your gateway's TXT record, or
+ nothing will work.</B></P>
+<P>In a text file, make one copy of this TXT record for each subnet
+ node:</P>
+<PRE> ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+<P>Above each entry, insert a line like this:</P>
+<PRE> 98.2.0.192.in-addr.arpa. IN PTR arthur.example.com.</PRE>
+<P>It must include:</P>
+<UL>
+<LI>The subnet node's address in reverse map format. For example,
+ 192.0.2.120 becomes<VAR> 120.2.0.192.in-addr.arpa.</VAR>. Note the
+ final period.</LI>
+<LI><VAR>IN PTR</VAR></LI>
+<LI>The node's name, ie.<VAR> arthur.example.com.</VAR>. Note the final
+ period.</LI>
+</UL>
+<P>The result will be a file of TXT records, like this:</P>
+<PRE> 98.2.0.192.in-addr.arpa. IN PTR arthur.example.com.
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ 99.2.0.192.in-addr.arpa. IN PTR ford.example.com.
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ 100.2.0.192.in-addr.arpa. IN PTR trillian.example.com.
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+<H3><A NAME="14_7_3">Publish your records</A></H3>
+<P>Ask your ISP to publish all the reverse DNS records you have
+ collected. There may be a delay of up to 48 hours as the records
+ propagate.</P>
+<H3><A NAME="14_7_4">...and test them</A></H3>
+<P>Check a couple of records with commands like this one:</P>
+<PRE> ipsec verify --host ford.example.com
+ ipsec verify --host trillian.example.com</PRE>
+<P>The<VAR> verify</VAR> command checks for TXT records for both the
+ subnet host and its gateway. You should see output like:</P>
+<PRE> ...
+ Looking for TXT in reverse map: 99.2.0.192.in-addr.arpa [OK]
+ ...
+ Looking for TXT in reverse map: 11.2.0.192.in-addr.arpa [OK]
+ ...
+ Looking for TXT in reverse map: 100.2.0.192.in-addr.arpa [OK]
+ ...
+ Looking for TXT in reverse map: 11.2.0.192.in-addr.arpa [OK]
+ ...</PRE>
+<H3><A NAME="14_7_5">No Configuration Needed</A></H3>
+<P>FreeS/WAN 2.x ships with a built-in, automatically enabled OE
+ connection<VAR> conn packetdefault</VAR> which applies OE, if possible,
+ to all outbound traffic routed through the FreeS/WAN box. The<A HREF="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5) manual</A> describes this connection in detail. While the
+ effect is much the same as<VAR> private-or-clear</VAR>, the
+ implementation is different: notably, it does not use policy groups.</P>
+<P>You can create more complex OE configurations for traffic forwarded
+ through a FreeS/WAN box, as explained in our<A HREF="policygroups.html#policygroups">
+ policy groups document</A>, or disable OE using<A HREF="policygroups.html#disable_policygroups">
+ these instructions</A>.</P>
+<H2><A name="extruded.config">Extruded Subnets</A></H2>
+<P>What we call<A href="glossary.html#extruded"> extruded subnets</A>
+ are a special case of<A href="glossary.html#VPN.gloss"> VPNs</A>.</P>
+<P>If your buddy has some unused IP addresses, in his subnet far off at
+ the other side of the Internet, he can loan them to you... provided
+ that the connection between you and him is fast enough to carry all the
+ traffic between your machines and the rest of the Internet. In effect,
+ he &quot;extrudes&quot; a part of his address space over the network to you, with
+ your Internet traffic appearing to originate from behind his Internet
+ gateway.</P>
+<P>As far as the Internet is concerned, your new extruded net is behind
+ your buddy's gateway. You route all your packets for the Internet at
+ large out his gateway, and receive return packets the same way. You
+ route your local packets locally.</P>
+<P>Suppose your friend has a.b.c.0/24 and wants to give you
+ a.b.c.240/28. The initial situation is:</P>
+<PRE> subnet gateway Internet
+ a.b.c.0/24 a.b.c.1 p.q.r.s</PRE>
+ where anything from the Internet destined for any machine in a.b.c.0/24
+ is routed via p.q.r.s and that gateway knows what to do from there.
+<P>Of course it is quite normal for various smaller subnets to exist
+ behind your friend's gateway. For example, your friend's company might
+ have a.b.c.16/28=development, a.b.c.32/28=marketing and so on. The
+ Internet neither knows not cares about this; it just delivers packets
+ to the p.q.r.s and lets the gateway do whatever needs to be done from
+ there.</P>
+<P>What we want to do is take a subnet, perhaps a.b.c.240/28, out of
+ your friend's physical location<EM> while still having your friend's
+ gateway route to it</EM>. As far as the Internet is concerned, you
+ remain behind that gateway.</P>
+<PRE> subnet gateway Internet your gate extruded
+
+ a.b.c.0/24 a.b.c.1 p.q.r.s d.e.f.g a.b.c.240/28
+
+ ========== tunnel ==========</PRE>
+<P>The extruded addresses have to be a complete subnet.</P>
+<P>In our example, the friend's security gateway is also his Internet
+ gateway, but this is not necessary. As long as all traffic from the
+ Internet to his addresses passes through the Internet gate, the
+ security gate could be a machine behind that. The IG would need to
+ route all traffic for the extruded subnet to the SG, and the SG could
+ handle the rest.</P>
+<P>First, configure your subnet using the extruded addresses. Your
+ security gateway's interface to your subnet needs to have an extruded
+ address (possibly using a Linux<A href="glossary.html#virtual"> virtual
+ interface</A>, if it also has to have a different address). Your
+ gateway needs to have a route to the extruded subnet, pointing to that
+ interface. The other machines at your site need to have addresses in
+ that subnet, and default routes pointing to your gateway.</P>
+<P>If any of your friend's machines need to talk to the extruded subnet,<EM>
+ they</EM> need to have a route for the extruded subnet, pointing at his
+ gateway.</P>
+<P>Then set up an IPsec subnet-to-subnet tunnel between your gateway and
+ his, with your subnet specified as the extruded subnet, and his subnet
+ specified as &quot;0.0.0.0/0&quot;.</P>
+<P>The tunnel description should be:</P>
+<PRE>conn extruded
+ left=p.q.r.s
+ leftsubnet=0.0.0.0/0
+ right=d.e.f.g
+ rightsubnet=a.b.c.0/28</PRE>
+<P>If either side was doing firewalling for the extruded subnet before
+ the IPsec connection is set up, you'll need to poke holes in your<A HREF="firewall.html#firewall">
+ firewall</A> to allow packets through.</P>
+<P>And it all just works. Your SG routes traffic for 0.0.0.0/0 -- that
+ is, the whole Internet -- through the tunnel to his SG, which then
+ sends it onward as if it came from his subnet. When traffic for the
+ extruded subnet arrives at his SG, it gets sent through the tunnel to
+ your SG, which passes it to the right machine.</P>
+<P>Remember that when ipsec_manual or ipsec_auto takes a connection
+ down, it<EM> does not undo the route</EM> it made for that connection.
+ This lets you take a connection down and bring up a new one, or a
+ modified version of the old one, without having to rebuild the route it
+ uses and without any risk of packets which should use IPsec
+ accidentally going out in the clear. Because the route always points
+ into KLIPS, the packets will always go there. Because KLIPS temporarily
+ has no idea what to do with them (no eroute for them), they will be
+ discarded.</P>
+<P>If you<EM> do</EM> want to take the route down, this is what the
+ &quot;unroute&quot; operation in manual and auto is for. Just do an unroute after
+ doing the down.</P>
+<P>Note that the route for a connection may have replaced an existing
+ non-IPsec route. Nothing in Linux FreeS/WAN will put that pre-IPsec
+ route back. If you need it back, you have to create it with the route
+ command.</P>
+<H2><A name="roadvirt">Road Warrior with virtual IP address</A></H2>
+<P>Please note that<A HREF="http://www.freeswan.ca/download.php"> Super
+ FreeS/WAN</A> now features DHCP-over-IPsec, which is an alternate
+ procedure for Virtual IP address assignment.</P>
+<P></P>
+<P>Here is a mailing list message about another way to configure for
+ road warrior support:</P>
+<PRE>Subject: Re: linux-ipsec: understanding the vpn
+ Date: Thu, 28 Oct 1999 10:43:22 -0400
+ From: Irving Reid &lt;irving@nevex.com&gt;
+
+&gt; local-------linux------internet------mobile
+&gt; LAN box user
+&gt; ...
+
+&gt; now when the mobile user connects to the linux box
+&gt; it is given a virtual IP address, i have configured it to
+&gt; be in the 10.x.x.x range. mobile user and linux box
+&gt; have a tunnel between them with these IP addresses.
+
+&gt; Uptil this all is fine.
+
+If it is possible to configure your mobile client software *not* to
+use a virtual IP address, that will make your life easier. It is easier
+to configure FreeS/WAN to use the actual address the mobile user gets
+from its ISP.
+
+Unfortunately, some Windows clients don't let you choose.
+
+&gt; what i would like to know is that how does the mobile
+&gt; user communicate with other computers on the local
+&gt; LAN , of course with the vpn ?
+
+&gt; what IP address should the local LAN
+&gt; computers have ? I guess their default gateway
+&gt; should be the linux box ? and does the linux box need
+&gt; to be a 2 NIC card box or one is fine.
+
+As someone else stated, yes, the Linux box would usually be the default
+IP gateway for the local lan.
+
+However...
+
+If you mobile user has software that *must* use a virtual IP address,
+the whole picture changes. Nobody has put much effort into getting
+FreeS/WAN to play well in this environment, but here's a sketch of one
+approach:
+
+Local Lan 1.0.0.0/24
+ |
+ +- Linux FreeS/WAN 1.0.0.2
+ |
+ | 1.0.0.1
+ Router
+ | 2.0.0.1
+ |
+Internet
+ |
+ | 3.0.0.1
+Mobile User
+ Virtual Address: 1.0.0.3
+
+Note that the Local Lan network (1.0.0.x) can be registered, routable
+addresses.
+
+Now, the Mobile User sets up an IPSec security association with the
+Linux box (1.0.0.2); it should ESP encapsulate all traffic to the
+network 1.0.0.x **EXCEPT** UDP port 500. 500/udp is required for the key
+negotiation, which needs to work outside of the IPSec tunnel.
+
+On the Linux side, there's a bunch of stuff you need to do by hand (for
+now). FreeS/WAN should correctly handle setting up the IPSec SA and
+routes, but I haven't tested it so this may not work...
+
+The FreeS/WAN conn should look like:
+
+conn mobile
+ right=1.0.0.2
+ rightsubnet=1.0.0.0/24
+ rightnexthop=1.0.0.1
+ left=0.0.0.0 # The infamous &quot;road warrior&quot;
+ leftsubnet=1.0.0.3/32
+
+Note that the left subnet contains *only* the remote host's virtual
+address.
+
+Hopefully the routing table on the FreeS/WAN box ends up looking like
+this:
+
+% netstat -rn
+Kernel IP routing table
+Destination Gateway Genmask Flags MSS Window irtt Iface
+1.0.0.0 0.0.0.0 255.255.255.0 U 1500 0 0 eth0
+127.0.0.0 0.0.0.0 255.0.0.0 U 3584 0 0 lo
+0.0.0.0 1.0.0.1 0.0.0.0 UG 1500 0 0 eth0
+1.0.0.3 1.0.0.1 255.255.255.255 UG 1433 0 0 ipsec0
+
+So, if anybody sends a packet for 1.0.0.3 to the Linux box, it should
+get bundled up and sent through the tunnel. To get the packets for
+1.0.0.3 to the Linux box in the first place, you need to use &quot;proxy
+ARP&quot;.
+
+How this works is: when a host or router on the local Ethernet segment
+wants to send a packet to 1.0.0.3, it sends out an Ethernet level
+broadcast &quot;ARP request&quot;. If 1.0.0.3 was on the local LAN, it would
+reply, saying &quot;send IP packets for 1.0.0.3 to my Ethernet address&quot;.
+
+Instead, you need to set up the Linux box so that _it_ answers ARP
+requests for 1.0.0.3, even though that isn't its IP address. That
+convinces everyone else on the lan to send 1.0.0.3 packets to the Linux
+box, where the usual FreeS/WAN processing and routing take over.
+
+% arp -i eth0 -s 1.0.0.3 -D eth0 pub
+
+This says, if you see an ARP request on interface eth0 asking for
+1.0.0.3, respond with the Ethernet address of interface eth0.
+
+Now, as I said at the very beginning, if it is *at all* possible to
+configure your client *not* to use the virtual IP address, you can avoid
+this whole mess.</PRE>
+<H2><A name="dynamic">Dynamic Network Interfaces</A></H2>
+<P>Sometimes you have to cope with a situation where the network
+ interface(s) aren't all there at boot. The common example is notebooks
+ with PCMCIA.</P>
+<H3><A name="basicdyn">Basics</A></H3>
+<P>The key issue here is that the<VAR> config setup</VAR> section of the<VAR>
+ /etc/ipsec.conf</VAR> configuration file lists the connection between
+ ipsecN and hardware interfaces, in the<VAR> interfaces=</VAR> variable.
+ At any time when<VAR> ipsec setup start</VAR> or<VAR> ipsec setup
+ restart</VAR> is run this variable<STRONG> must</STRONG> correspond to
+ the current real situation. More precisely, it<STRONG> must not</STRONG>
+ mention any hardware interfaces which don't currently exist. The
+ difficulty is that an<VAR> ipsec setup start</VAR> command is normally
+ run at boot time so interfaces that are not up then are mis-handled.</P>
+<H3><A name="bootdyn">Boot Time</A></H3>
+<P>Normally, an<VAR> ipsec setup start</VAR> is run at boot time.
+ However, if the hardware situation at boot time is uncertain, one of
+ two things must be done.</P>
+<UL>
+<LI>One possibility is simply not to have IPsec brought up at boot time.
+ To do this:
+<PRE> chkconfig --level 2345 ipsec off</PRE>
+ That's for modern Red Hats or other Linuxes with chkconfig. Systems
+ which lack this will require fiddling with symlinks in /etc/rc.d/rc?.d
+ or the equivalent.</LI>
+<LI>Another possibility is to bring IPsec up with no interfaces, which
+ is less aesthetically satisfying but simpler. Just put
+<PRE> interfaces=</PRE>
+ in the configuration file. KLIPS and Pluto will be started, but won't
+ do anything.</LI>
+</UL>
+<H3><A name="changedyn">Change Time</A></H3>
+<P>When the hardware *is* in place, IPsec has to be made aware of it.
+ Someday there may be a nice way to do this.</P>
+<P>Right now, the way to do it is to fix the<VAR> /etc/ipsec.conf</VAR>
+ file appropriately, so<VAR> interfaces</VAR> reflects the new
+ situation, and then restart the IPsec subsystem. This does break any
+ existing IPsec connections.</P>
+<P>If IPsec wasn't brought up at boot time, do</P>
+<PRE> ipsec setup start</PRE>
+ while if it was, do
+<PRE> ipsec setup restart</PRE>
+ which won't be as quick.
+<P>If some of the hardware is to be taken out, before doing that, amend
+ the configuration file so interfaces no longer includes it, and do</P>
+<PRE> ipsec setup restart</PRE>
+<P>Again, this breaks any existing connections.</P>
+<H2><A name="unencrypted">Unencrypted tunnels</A></H2>
+<P>Sometimes you might want to create a tunnel without encryption. Often
+ this is a bad idea, even if you have some data which need not be
+ private. See this<A href="ipsec.html#traffic.resist"> discussion</A>.</P>
+<P>The IPsec protocols provide two ways to do build such tunnels:</P>
+<DL>
+<DT>using ESP with null encryption</DT>
+<DD>not supported by FreeS/WAN</DD>
+<DT>using<A href="glossary.html#AH"> AH</A> without<A href="glossary.html#ESP">
+ ESP</A></DT>
+<DD>supported for manually keyed connections</DD>
+<DD>possible with explicit commands via<A href="manpage.d/ipsec_whack.8.html">
+ ipsec_whack(8)</A> (see this<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00190.html">
+ list message</A>)</DD>
+<DD>not supported in the<A href="manpage.d/ipsec_auto.8.html">
+ ipsec_auto(8)</A> scripts.</DD>
+</DL>
+ One situation in which this comes up is when otherwise some data would
+ be encrypted twice. Alice wants a secure tunnel from her machine to
+ Bob's. Since she's behind one security gateway and he's behind another,
+ part of the tunnel that they build passes through the tunnel that their
+ site admins have built between the gateways. All of Alice and Bob's
+ messages are encrypted twice.
+<P>There are several ways to handle this.</P>
+<UL>
+<LI>Just accept the overhead of double encryption. The site admins might
+ choose this if any of the following apply:
+<UL>
+<LI>policy says encrypt everything (usually, it should)</LI>
+<LI>they don't entirely trust Alice and Bob (usually, if they don't have
+ to, they shouldn't)</LI>
+<LI>if they don't feel the saved cycles are worth the time they'd need
+ to build a non-encrypted tunnel for Alice and Bob's packets (often,
+ they aren't)</LI>
+</UL>
+</LI>
+<LI>Use a plain IP-in-IP tunnel. These are not well documented. A good
+ starting point is in the Linux kernel source tree, in
+ /usr/src/linux/drivers/net/README.tunnel.</LI>
+<LI>Use a manually-keyed AH-only tunnel.</LI>
+</UL>
+<P>Note that if Alice and Bob want end-to-end security, they must build
+ a tunnel end-to-end between their machines or use some other end-to-end
+ tool such as PGP or SSL that suits their data. The only question is
+ whether the admins build some special unencrypted tunnel for those
+ already-encrypted packets.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="kernel.html">Previous</A>
+<A HREF="install.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/background.html b/doc/background.html
new file mode 100644
index 000000000..8f24cad4a
--- /dev/null
+++ b/doc/background.html
@@ -0,0 +1,323 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="config.html">Previous</A>
+<A HREF="user_examples.html">Next</A>
+<HR>
+<H1><A name="background">Linux FreeS/WAN background</A></H1>
+<P>This section discusses a number of issues which have three things in
+ common:</P>
+<UL>
+<LI>They are not specifically FreeS/WAN problems</LI>
+<LI>You may have to understand them to get FreeS/WAN working right</LI>
+<LI>They are not simple questions</LI>
+</UL>
+<P>Grouping them here lets us provide the explanations some users will
+ need without unduly complicating the main text.</P>
+<P>The explanations here are intended to be adequate for FreeS/WAN
+ purposes (please comment to the<A href="mail.html"> users mailing list</A>
+ if you don't find them so), but they are not trying to be complete or
+ definitive. If you need more information, see the references provided
+ in each section.</P>
+<H2><A name="dns.background">Some DNS background</A></H2>
+<P><A href="glossary.html#carpediem">Opportunistic encryption</A>
+ requires that the gateway systems be able to fetch public keys, and
+ other IPsec-related information, from each other's DNS (Domain Name
+ Service) records.</P>
+<P><A href="glossary.html#DNS">DNS</A> is a distributed database that
+ maps names to IP addresses and vice versa.</P>
+<P>Much good reference material is available for DNS, including:</P>
+<UL>
+<LI>the<A href="http://www.linuxdoc.org/HOWTO/DNS-HOWTO.html"> DNS HowTo</A>
+</LI>
+<LI>the standard<A href="biblio.html#DNS.book"> DNS reference</A> book</LI>
+<LI><A href="http://www.linuxdoc.org/LDP/nag2/index.html">Linux Network
+ Administrator's Guide</A></LI>
+<LI><A href="http://www.nominum.com/resources/whitepapers/bind-white-paper.html">
+BIND overview</A></LI>
+<LI><A href="http://www.nominum.com/resources/documentation/Bv9ARM.pdf">
+BIND 9 Administrator's Reference</A></LI>
+</UL>
+<P>We give only a brief overview here, intended to help you use DNS for
+ FreeS/WAN purposes.</P>
+<H3><A name="forward.reverse">Forward and reverse maps</A></H3>
+<P>Although the implementation is distributed, it is often useful to
+ speak of DNS as if it were just two enormous tables:</P>
+<UL>
+<LI>the forward map: look up a name, get an IP address</LI>
+<LI>the reverse map: look up an IP address, get a name</LI>
+</UL>
+<P>Both maps can optionally contain additional data. For opportunistic
+ encryption, we insert the data need for IPsec authentication.</P>
+<P>A system named gateway.example.com with IP address 10.20.30.40 should
+ have at least two DNS records, one in each map:</P>
+<DL>
+<DT>gateway.example.com. IN A 10.20.30.40</DT>
+<DD>used to look up the name and get an IP address</DD>
+<DT>40.30.20.10.in-addr.arpa. IN PTR gateway.example.com.</DT>
+<DD>used for reverse lookups, looking up an address to get the
+ associated name. Notice that the digits here are in reverse order; the
+ actual address is 10.20.30.40 but we use 40.30.20.10 here.</DD>
+</DL>
+<H3><A NAME="17_1_2">Hierarchy and delegation</A></H3>
+<P>For both maps there is a hierarchy of DNS servers and a system of
+ delegating authority so that, for example:</P>
+<UL>
+<LI>the DNS administrator for example.com can create entries of the form<VAR>
+ name</VAR>.example.com</LI>
+<LI>the example.com admin cannot create an entry for counterexample.com;
+ only someone with authority for .com can do that</LI>
+<LI>an admin might have authority for 20.10.in-addr.arpa.</LI>
+<LI>in either map, authority can be delegated
+<UL>
+<LI>the example.com admin could give you authority for
+ westcoast.example.com</LI>
+<LI>the 20.10.in-addr.arpa admin could give you authority for
+ 30.20.10.in-addr.arpa</LI>
+</UL>
+</LI>
+</UL>
+<P>DNS zones are the units of delegation. There is a hierarchy of zones.</P>
+<H3><A NAME="17_1_3">Syntax of DNS records</A></H3>
+<P>Returning to the example records:</P>
+<PRE> gateway.example.com. IN A 10.20.30.40
+ 40.30.20.10.in-addr.arpa. IN PTR gateway.example.com.</PRE>
+<P>some syntactic details are:</P>
+<UL>
+<LI>the IN indicates that these records are for<STRONG> In</STRONG>
+ternet addresses</LI>
+<LI>The final periods in '.com.' and '.arpa.' are required. They
+ indicate the root of the domain name system.</LI>
+</UL>
+<P>The capitalised strings after IN indicate the type of record.
+ Possible types include:</P>
+<UL>
+<LI><STRONG>A</STRONG>ddress, for forward lookups</LI>
+<LI><STRONG>P</STRONG>oin<STRONG>T</STRONG>e<STRONG>R</STRONG>, for
+ reverse lookups</LI>
+<LI><STRONG>C</STRONG>anonical<STRONG> NAME</STRONG>, records to support
+ aliasing, multiple names for one address</LI>
+<LI><STRONG>M</STRONG>ail e<STRONG>X</STRONG>change, used in mail
+ routing</LI>
+<LI><STRONG>SIG</STRONG>nature, used in<A href="glossary.html#SDNS">
+ secure DNS</A></LI>
+<LI><STRONG>KEY</STRONG>, used in<A href="glossary.html#SDNS"> secure
+ DNS</A></LI>
+<LI><STRONG>T</STRONG>e<STRONG>XT</STRONG>, a multi-purpose record type</LI>
+</UL>
+<P>To set up for opportunistic encryption, you add some TXT records to
+ your DNS data. Details are in our<A href="quickstart.html"> quickstart</A>
+ document.</P>
+<H3><A NAME="17_1_4">Cacheing, TTL and propagation delay</A></H3>
+<P>DNS information is extensively cached. With no caching, a lookup by
+ your system of &quot;www.freeswan.org&quot; might involve:</P>
+<UL>
+<LI>your system asks your nameserver for &quot;www.freeswan.org&quot;</LI>
+<LI>local nameserver asks root server about &quot;.org&quot;, gets reply</LI>
+<LI>local nameserver asks .org nameserver about &quot;freeswan.org&quot;, gets
+ reply</LI>
+<LI>local nameserver asks freeswan.org nameserver about
+ &quot;www.freeswan.org&quot;, gets reply</LI>
+</UL>
+<P>However, this can be a bit inefficient. For example, if you are in
+ the Phillipines, the closest a root server is in Japan. That might send
+ you to a .org server in the US, and then to freeswan.org in Holland. If
+ everyone did all those lookups every time they clicked on a web link,
+ the net would grind to a halt.</P>
+<P>Nameservers therefore cache information they look up. When you click
+ on another link at www.freeswan.org, your local nameserver has the IP
+ address for that server in its cache, and no further lookups are
+ required.</P>
+<P>Intermediate results are also cached. If you next go to
+ lists.freeswan.org, your nameserver can just ask the freeswan.org
+ nameserver for that address; it does not need to query the root or .org
+ nameservers because it has a cached address for the freeswan.org zone
+ server.</P>
+<P>Of course, like any cacheing mechanism, this can create problems of
+ consistency. What if the administrator for freeswan.org changes the IP
+ address, or the authentication key, for www.freeswan.org? If you use
+ old information from the cache, you may get it wrong. On the other
+ hand, you cannot afford to look up fresh information every time. Nor
+ can you expect the freeswan.org server to notify you; that isn't in the
+ protocols.</P>
+<P>The solution that is in the protocols is fairly simple. Cacheable
+ records are marked with Time To Live (TTL) information. When the time
+ expires, the caching server discards the record. The next time someone
+ asks for it, the server fetches a fresh copy. Of course, a server may
+ also discard records before their TTL expires if it is running out of
+ cache space.</P>
+<P>This implies that there will be some delay before the new version of
+ a changed record propagates around the net. Until the TTLs on all
+ copies of the old record expire, some users will see it because that is
+ what is in their cache. Other users may see the new record immediately
+ because they don't have an old one cached.</P>
+<H2><A name="MTU.trouble">Problems with packet fragmentation</A></H2>
+<P>It seems, from mailing list reports, to be moderately common for
+ problems to crop up in which small packets pass through the IPsec
+ tunnels just fine but larger packets fail.</P>
+<P>These problems are caused by various devices along the way
+ mis-handling either packet fragments or<A href="glossary.html#pathMTU">
+ path MTU discovery</A>.</P>
+<P>IPsec makes packets larger by adding an ESP or AH header. This can
+ tickle assorted bugs in fragment handling in routers and firewalls, or
+ in path MTU discovery mechanisms, and cause a variety of symptoms which
+ are both annoying and, often, quite hard to diagnose.</P>
+<P>An explanation from project technical lead Henry Spencer:</P>
+<PRE>The problem is IP fragmentation; more precisely, the problem is that the
+second, third, etc. fragments of an IP packet are often difficult for
+filtering mechanisms to classify.
+
+Routers cannot rely on reassembling the packet, or remembering what was in
+earlier fragments, because the fragments may be out of order or may even
+follow different routes. So any general, worst-case filtering decision
+pretty much has to be made on each fragment independently. (If the router
+knows that it is the only route to the destination, so all fragments
+*must* pass through it, reassembly would be possible... but most routers
+don't want to bother with the complications of that.)
+
+All fragments carry roughly the original IP header, but any higher-level
+header is (for IP purposes) just the first part of the packet data... so
+only the first fragment carries that. So, for example, on examining the
+second fragment of a TCP packet, you could tell that it's TCP, but not
+what port number it is destined for -- that information is in the TCP
+header, which appears in the first fragment only.
+
+The result of this classification difficulty is that stupid routers and
+over-paranoid firewalls may just throw fragments away. To get through
+them, you must reduce your MTU enough that fragmentation will not occur.
+(In some cases, they might be willing to attempt reassembly, but have very
+limited resources to devote to it, meaning that packets must be small and
+fragments few in number, leading to the same conclusion: smaller MTU.)</PRE>
+<P>In addition to the problem Henry describes, you may also have trouble
+ with<A href="glossary.html#pathMTU"> path MTU discovery</A>.</P>
+<P>By default, FreeS/WAN uses a large<A href="glossary.html#MTU"> MTU</A>
+ for the ipsec device. This avoids some problems, but may complicate
+ others. Here's an explanation from Claudia:</P>
+<PRE>Here are a couple of pieces of background information. Apologies if you
+have seen these already. An excerpt from one of my old posts:
+
+ An MTU of 16260 on ipsec0 is usual. The IPSec device defaults to this
+ high MTU so that it does not fragment incoming packets before encryption
+ and encapsulation. If after IPSec processing packets are larger than 1500,
+ [ie. the mtu of eth0] then eth0 will fragment them.
+
+ Adding IPSec headers adds a certain number of bytes to each packet.
+ The MTU of the IPSec interface refers to the maximum size of the packet
+ before the IPSec headers are added. In some cases, people find it helpful
+ to set ipsec0's MTU to 1500-(IPSec header size), which IIRC is about 1430.
+
+ That way, the resulting encapsulated packets don't exceed 1500. On most
+ networks, packets less than 1500 will not need to be fragmented.
+
+and... (from Henry Spencer)
+
+ The way it *ought* to work is that the MTU advertised by the ipsecN
+ interface should be that of the underlying hardware interface, less a
+ pinch for the extra headers needed.
+
+ Unfortunately, in certain situations this breaks many applications.
+ There is a widespread implicit assumption that the smallest MTUs are
+ at the ends of paths, not in the middle, and another that MTUs are
+ never less than 1500. A lot of code is unprepared to handle paths
+ where there is an &quot;interior minimum&quot; in the MTU, especially when it's
+ less than 1500. So we advertise a big MTU and just let the resulting
+ big packets fragment.
+
+This usually works, but we do get bitten in cases where some intermediate
+point can't handle all that fragmentation. We can't win on this one.</PRE>
+<P>The MTU can be changed with an<VAR> overridemtu=</VAR> statement in
+ the<VAR> config setup</VAR> section of<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf.5</A>.</P>
+<P>For a discussion of MTU issues and some possible solutions using
+ Linux advanced routing facilities, see the<A href="http://www.linuxguruz.org/iptables/howto/2.4routing-15.html#ss15.6">
+ Linux 2.4 Advanced Routing HOWTO</A>. For a discussion of MTU and NAT
+ (Network Address Translation), see<A HREF="http://harlech.math.ucla.edu/services/ipsec.html">
+ James Carter's MTU notes</A>.</P>
+<H2><A name="nat.background">Network address translation (NAT)</A></H2>
+<P><STRONG>N</STRONG>etwork<STRONG> A</STRONG>ddress<STRONG> T</STRONG>
+ranslation is a service provided by some gateway machines. Calling it
+ NAPT (adding the word<STRONG> P</STRONG>ort) would be more precise, but
+ we will follow the widespread usage.</P>
+<P>A gateway doing NAT rewrites the headers of packets it is forwarding,
+ changing one or more of:</P>
+<UL>
+<LI>source address</LI>
+<LI>source port</LI>
+<LI>destination address</LI>
+<LI>destination port</LI>
+</UL>
+<P>On Linux 2.4, NAT services are provided by the<A href="http://netfilter.samba.org">
+ netfilter(8)</A> firewall code. There are several<A href="http://netfilter.samba.org/documentation/index.html#HOWTO">
+ Netfilter HowTos</A> including one on NAT.</P>
+<P>For older versions of Linux, this was referred to as &quot;IP masquerade&quot;
+ and different tools were used. See this<A href="http://www.e-infomax.com/ipmasq/">
+ resource page</A>.</P>
+<P>Putting an IPsec gateway behind a NAT gateway is not recommended. See
+ our<A href="firewall.html#NAT"> firewalls document</A>.</P>
+<H3><A NAME="17_3_1">NAT to non-routable addresses</A></H3>
+<P>The most common application of NAT uses private<A href="glossary.html#non-routable">
+ non-routable</A> addresses.</P>
+<P>Often a home or small office network will have:</P>
+<UL>
+<LI>one connection to the Internet</LI>
+<LI>one assigned publicly visible IP address</LI>
+<LI>several machines that all need access to the net</LI>
+</UL>
+<P>Of course this poses a problem since several machines cannot use one
+ address. The best solution might be to obtain more addresses, but often
+ this is impractical or uneconomical.</P>
+<P>A common solution is to have:</P>
+<UL>
+<LI><A href="glossary.html#non-routable">non-routable</A> addresses on
+ the local network</LI>
+<LI>the gateway machine doing NAT</LI>
+<LI>all packets going outside the LAN rewritten to have the gateway as
+ their source address</LI>
+</UL>
+<P>The client machines are set up with reserved<A href="glossary.html#non-routable">
+ non-routable</A> IP addresses defined in RFC 1918. The masquerading
+ gateway, the machine with the actual link to the Internet, rewrites
+ packet headers so that all packets going onto the Internet appear to
+ come from one IP address, that of its Internet interface. It then gets
+ all the replies, does some table lookups and more header rewriting, and
+ delivers the replies to the appropriate client machines.</P>
+<P>As far as anyone else on the Internet is concerned, the systems
+ behind the gateway are completely hidden. Only one machine with one IP
+ address is visible.</P>
+<P>For IPsec on such a gateway, you can entirely ignore the NAT in:</P>
+<UL>
+<LI><A href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A></LI>
+<LI>firewall rules affecting your Internet-side interface</LI>
+</UL>
+<P>Those can be set up exactly as they would be if your gateway had no
+ other systems behind it.</P>
+<P>You do, however, have to take account of the NAT in firewall rules
+ which affect packet forwarding.</P>
+<H3><A NAME="17_3_2">NAT to routable addresses</A></H3>
+<P>NAT to routable addresses is also possible, but is less common and
+ may make for rather tricky routing problems. We will not discuss it
+ here. See the<A href="http://netfilter.samba.org/documentation/index.html#HOWTO">
+ Netfilter HowTos</A>.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="config.html">Previous</A>
+<A HREF="user_examples.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/biblio.html b/doc/biblio.html
new file mode 100644
index 000000000..d54af5cbf
--- /dev/null
+++ b/doc/biblio.html
@@ -0,0 +1,274 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="glossary.html">Previous</A>
+<A HREF="rfc.html">Next</A>
+<HR>
+<H1><A name="biblio">Bibliography for the Linux FreeS/WAN project</A></H1>
+<P>For extensive bibliographic links, see the<A href="http://liinwww.ira.uka.de/bibliography/index.html">
+ Collection of Computer Science Bibliographies</A></P>
+<P>See our<A href="web.html"> web links</A> for material available
+ online.</P>
+<HR><A name="adams"> Carlisle Adams and Steve Lloyd<CITE> Understanding
+ Public Key Infrastructure</CITE>
+<BR></A> Macmillan 1999 ISBN 1-57870-166-x
+<P>An overview, mainly concentrating on policy and strategic issues
+ rather than the technical details. Both authors work for<A href="glossary.html#PKI">
+ PKI</A> vendor<A href="http://www.entrust.com/"> Entrust</A>.</P>
+<HR><A name="DNS.book"> Albitz, Liu &amp; Loukides<CITE> DNS &amp; BIND</CITE>
+ 3rd edition
+<BR></A> O'Reilly 1998 ISBN 1-56592-512-2
+<P>The standard reference on the<A href="glossary.html#DNS"> Domain Name
+ Service</A> and<A href="glossary.html#BIND"> Berkeley Internet Name
+ Daemon</A>.</P>
+<HR><A name="anderson"> Ross Anderson</A>,<CITE> Security Engineering -
+ a Guide to Building Dependable Distributed Systems</CITE>
+<BR> Wiley, 2001, ISBN 0471389226
+<P>Easily the best book for the security professional I have seen.<STRONG>
+ Highly recommended</STRONG>. See the<A href="http://www.cl.cam.ac.uk/~rja14/book.html">
+ book web page</A>.</P>
+<P>This is quite readable, but Schneier's<A href="#secrets"> Secrets and
+ Lies</A> might be an easier introduction.</P>
+<HR><A name="puzzle"> Bamford<CITE> The Puzzle Palace, A report on NSA,
+ Americas's most Secret Agency</CITE>
+<BR> Houghton Mifflin 1982 ISBN 0-395-31286-8</A>
+<HR> Bamford<CITE> Body of Secrets</CITE>
+<P>The sequel.</P>
+<HR><A name="bander"> David Bander</A>,<CITE> Linux Security Toolkit</CITE>
+<BR> IDG Books, 2000, ISBN: 0764546902
+<P>This book has a short section on FreeS/WAN and includes Caldera Linux
+ on CD.</P>
+<HR><A name="CZR"> Chapman, Zwicky &amp; Russell</A>,<CITE> Building
+ Internet Firewalls</CITE>
+<BR> O'Reilly 1995 ISBN 1-56592-124-0
+<HR><A name="firewall.book"> Cheswick and Bellovin</A><CITE> Firewalls
+ and Internet Security: Repelling the Wily Hacker</CITE>
+<BR> Addison-Wesley 1994 ISBN 0201633574
+<P>A fine book on firewalls in particular and security in general from
+ two of AT&amp;T's system adminstrators.</P>
+<P>Bellovin has also done a number of<A href="web.html#papers"> papers</A>
+ on IPsec and co-authored a<A href="intro.html#applied"> paper</A> on a
+ large FreeS/WAN application.</P>
+<HR><A name="comer"> Comer<CITE> Internetworking with TCP/IP</CITE>
+<BR> Prentice Hall</A>
+<UL>
+<LI>Vol. I: Principles, Protocols, &amp; Architecture, 3rd Ed. 1995
+ ISBN:0-13-216987-8</LI>
+<LI>Vol. II: Design, Implementation, &amp; Internals, 2nd Ed. 1994
+ ISBN:0-13-125527-4</LI>
+<LI>Vol. III: Client/Server Programming &amp; Applications
+<UL>
+<LI>AT&amp;T TLI Version 1994 ISBN:0-13-474230-3</LI>
+<LI>BSD Socket Version 1996 ISBN:0-13-260969-X</LI>
+<LI>Windows Sockets Version 1997 ISBN:0-13-848714-6</LI>
+</UL>
+</LI>
+</UL>
+<P>If you need to deal with the details of the network protocols, read
+ either this series or the<A href="#stevens"> Stevens and Wright</A>
+ series before you start reading the RFCs.</P>
+<HR><A name="diffie"> Diffie and Landau</A><CITE> Privacy on the Line:
+ The Politics of Wiretapping and Encryption</CITE>
+<BR> MIT press 1998 ISBN 0-262-04167-7 (hardcover) or 0-262-54100-9
+<BR>
+<HR><A name="d_and_hark"> Doraswamy and Harkins<CITE> IP Sec: The New
+ Security Standard for the Internet, Intranets and Virtual Private
+ Networks</CITE>
+<BR> Prentice Hall 1999 ISBN: 0130118982</A>
+<HR><A name="EFF"> Electronic Frontier Foundation<CITE> Cracking DES:
+ Secrets of Encryption Research, Wiretap Politics and Chip Design</CITE>
+<BR></A> O'Reilly 1998 ISBN 1-56592-520-3
+<P>To conclusively demonstrate that DES is inadequate for continued use,
+ the<A href="glossary.html#EFF"> EFF</A> built a machine for just over
+ $200,000 that breaks DES encryption in under five days on average,
+ under nine in the worst case.</P>
+<P>The book provides details of their design and, perhaps even more
+ important, discusses why they felt the project was necessary.
+ Recommended for anyone interested in any of the three topics mentioned
+ in the subtitle.</P>
+<P>See also the<A href="http://www.eff.org/descracker.html"> EFF page on
+ this project</A> and our discussion of<A href="politics.html#desnotsecure">
+ DES insecurity</A>.</P>
+<HR> Martin Freiss<CITE> Protecting Networks with SATAN</CITE>
+<BR> O'Reilly 1998 ISBN 1-56592-425-8
+<BR> translated from a 1996 work in German
+<P>SATAN is a Security Administrator's Tool for Analysing Networks. This
+ book is a tutorial in its use.</P>
+<HR> Gaidosch and Kunzinger<CITE> A Guide to Virtual Private Networks</CITE>
+<BR> Prentice Hall 1999 ISBN: 0130839647
+<HR><A name="Garfinkel"> Simson Garfinkel</A><CITE> Database Nation: the
+ death of privacy in the 21st century</CITE>
+<BR> O'Reilly 2000 ISBN 1-56592-653-6
+<P>A thoughtful and rather scary book.</P>
+<HR><A name="PGP"> Simson Garfinkel</A><CITE> PGP: Pretty Good Privacy</CITE>
+<BR> O'Reilly 1995 ISBN 1-56592-098-8
+<P>An excellent introduction and user manual for the<A href="glossary.html#PGP">
+ PGP</A> email-encryption package. PGP is a good package with a complex
+ and poorly-designed user interface. This book or one like it is a must
+ for anyone who has to use it at length.</P>
+<P>The book covers using PGP in Unix, PC and Macintosh environments,
+ plus considerable background material on both the technical and
+ political issues around cryptography.</P>
+<P>The book is now seriously out of date. It does not cover recent
+ developments such as commercial versions since PGP 5, the Open PGP
+ standard or GNU PG..</P>
+<HR><A name="practical"> Garfinkel and Spafford</A><CITE> Practical Unix
+ Security</CITE>
+<BR> O'Reilly 1996 ISBN 1-56592-148-8
+<P>A standard reference.</P>
+<P>Spafford's web page has an excellent collection of<A href="http://www.cs.purdue.edu/coast/hotlist">
+ crypto and security links</A>.</P>
+<HR><A name="Kahn"> David Kahn</A><CITE> The Codebreakers: the
+ Comprehensive History of Secret Communications from Ancient Times to
+ the Internet</CITE>
+<BR> second edition Scribner 1996 ISBN 0684831309
+<P>A history of codes and code-breaking from ancient Egypt to the 20th
+ century. Well-written and exhaustively researched.<STRONG> Highly
+ recommended</STRONG>, even though it does not have much on computer
+ cryptography.</P>
+<HR> David Kahn<CITE> Seizing the Enigma, The Race to Break the German
+ U-Boat codes, 1939-1943</CITE>
+<BR> Houghton Mifflin 1991 ISBN 0-395-42739-8
+<HR><A name="kirch"> Olaf Kirch</A><CITE> Linux Network Administrator's
+ Guide</CITE>
+<BR> O'Reilly 1995 ISBN 1-56592-087-2
+<P>Now becoming somewhat dated in places, but still a good introductory
+ book and general reference.</P>
+<HR><A name="LinVPN"> Kolesnikov and Hatch</A>,<CITE> Building Linux
+ Virtual Private Networks (VPNs)</CITE>
+<BR> New Riders 2002
+<P>This has had a number of favorable reviews, including<A href="http://www.slashdot.org/article.pl?sid=02/02/27/0115214&amp;mode=thread&amp;tid=172">
+ this one</A> on Slashdot. The book has a<A href="http://www.buildinglinuxvpns.net/">
+ web site</A>.</P>
+<HR><A name="RFCs"> Pete Loshin<CITE> Big Book of IPsec RFCs</CITE>
+<BR> Morgan Kaufmann 2000 ISBN: 0-12-455839-9</A>
+<HR><A name="crypto"> Steven Levy<CITE> Crypto: How the Code Rebels Beat
+ the Government -- Saving Privacy in the Digital Age</CITE></A>
+<BR> Penguin 2001, ISBN 0-670--85950-8
+<P><STRONG>Highly recommended</STRONG>. A fine history of recent (about
+ 1970-2000) developments in the field, and the related political
+ controversies. FreeS/WAN project founder and leader John Gilmore
+ appears several times.</P>
+<P>The book does not cover IPsec or FreeS/WAN, but this project is very
+ much another battle in the same war. See our discussion of the<A href="politics.html">
+ politics</A>.</P>
+<HR><A name="GTR"> Matyas, Anderson et al.</A><CITE> The Global Trust
+ Register</CITE>
+<BR> Northgate Consultants Ltd 1998 ISBN: 0953239705
+<BR> hard cover edition MIT Press 1999 ISBN 0262511053
+<P>From<A href="http://www.cl.cam.ac.uk/Research/Security/Trust-Register">
+ their web page:</A></P>
+<BLOCKQUOTE> This book is a register of the fingerprints of the world's
+ most important public keys; it implements a top-level certification
+ authority (CA) using paper and ink rather than in an electronic system.</BLOCKQUOTE>
+<HR><A name="handbook"> Menezies, van Oorschot and Vanstone<CITE>
+ Handbook of Applied Cryptography</CITE></A>
+<BR> CRC Press 1997
+<BR> ISBN 0-8493-8523-7
+<P>An excellent reference. Read<A href="#schneier"> Schneier</A> before
+ tackling this.</P>
+<HR> Michael Padlipsky<CITE> Elements of Networking Style</CITE>
+<BR> Prentice-Hall 1985 ISBN 0-13-268111-0 or 0-13-268129-3
+<P>Probably<STRONG> the funniest technical book ever written</STRONG>,
+ this is a vicious but well-reasoned attack on the OSI &quot;seven layer
+ model&quot; and all that went with it. Several chapters of it are also
+ available as RFCs 871 to 875.</P>
+<HR><A name="matrix"> John S. Quarterman</A><CITE> The Matrix: Computer
+ Networks and Conferencing Systems Worldwide</CITE>
+<BR> Digital Press 1990 ISBN 155558-033-5
+<BR> Prentice-Hall ISBN 0-13-565607-9
+<P>The best general treatment of computer-mediated communication we have
+ seen. It naturally has much to say about the Internet, but also covers
+ UUCP, Fidonet and so on.</P>
+<HR><A name="ranch"> David Ranch</A><CITE> Securing Linux Step by Step</CITE>
+<BR> SANS Institute, 1999
+<P><A href="http://www.sans.org/">SANS</A> is a respected organisation,
+ this guide is part of a well-known series, and Ranch has previously
+ written the useful<A href=" http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos">
+ Trinity OS</A> guide to securing Linux, so my guess would be this is a
+ pretty good book. I haven't read it yet, so I'm not certain. It can be
+ ordered online from<A href="http://www.sans.org/"> SANS</A>.</P>
+<P>Note (Mar 1, 2002): a new edition with different editors in the
+ works. Expect it this year.</P>
+<HR><A name="schneier"> Bruce Schneier</A><CITE> Applied Cryptography,
+ Second Edition</CITE>
+<BR> John Wiley &amp; Sons, 1996
+<BR> ISBN 0-471-12845-7 hardcover
+<BR> ISBN 0-471-11709-9 paperback
+<P>A standard reference on computer cryptography. For more recent
+ essays, see the<A href="http://www.counterpane.com/"> author's
+ company's web site</A>.</P>
+<HR><A name="secrets"> Bruce Schneier</A><CITE> Secrets and Lies</CITE>
+<BR> Wiley 2000, ISBN 0-471-25311-1
+<P>An interesting discussion of security and privacy issues, written
+ with more of an &quot;executive overview&quot; approach rather than a narrow
+ focus on the technical issues.<STRONG> Highly recommended</STRONG>.</P>
+<P>This is worth reading even if you already understand security issues,
+ or think you do. To go deeper, follow it with Anderson's<A href="#anderson">
+ Security Engineering</A>.</P>
+<HR><A name="VPNbook"> Scott, Wolfe and Irwin<CITE> Virtual Private
+ Networks</CITE></A>
+<BR> 2nd edition, O'Reilly 1999 ISBN: 1-56592-529-7
+<P>This is the only O'Reilly book, out of a dozen I own, that I'm
+ disappointed with. It deals mainly with building VPNs with various
+ proprietary tools --<A href="glossary.html#PPTP"> PPTP</A>,<A href="glossary.html#SSH">
+ SSH</A>, Cisco PIX, ... -- and touches only lightly on IPsec-based
+ approaches.</P>
+<P>That said, it appears to deal competently with what it does cover and
+ it has readable explanations of many basic VPN and security concepts.
+ It may be exactly what some readers require, even if I find the
+ emphasis unfortunate.</P>
+<HR><A name="LASG"> Kurt Seifried<CITE> Linux Administrator's Security
+ Guide</CITE></A>
+<P>Available online from<A href="http://www.securityportal.com/lasg/">
+ Security Portal</A>. It has fairly extensive coverage of IPsec.</P>
+<HR><A name="Smith"> Richard E Smith<CITE> Internet Cryptography</CITE>
+<BR></A> ISBN 0-201-92480-3, Addison Wesley, 1997
+<P>See the book's<A href="http://www.visi.com/crypto/inet-crypto/index.html">
+ home page</A></P>
+<HR><A name="neal"> Neal Stephenson<CITE> Cryptonomicon</CITE></A>
+<BR> Hardcover ISBN -380-97346-4, Avon, 1999.
+<P>A novel in which cryptography and the net figure prominently.<STRONG>
+ Highly recommended</STRONG>: I liked it enough I immediately went out
+ and bought all the author's other books.</P>
+<P>There is also a paperback edition. Sequels are expected.</P>
+<HR><A name="stevens"> Stevens and Wright</A><CITE> TCP/IP Illustrated</CITE>
+<BR> Addison-Wesley
+<UL>
+<LI>Vol. I: The Protocols 1994 ISBN:0-201-63346-9</LI>
+<LI>Vol. II: The Implementation 1995 ISBN:0-201-63354-X</LI>
+<LI>Vol. III: TCP for Transactions, HTTP, NNTP, and the UNIX Domain
+ Protocols 1996 ISBN: 0-201-63495-3</LI>
+</UL>
+<P>If you need to deal with the details of the network protocols, read
+ either this series or the<A href="#comer"> Comer</A> series before you
+ start reading the RFCs.</P>
+<HR><A name="Rubini"> Rubini</A><CITE> Linux Device Drivers</CITE>
+<BR> O'Reilly &amp; Associates, Inc. 1998 ISBN 1-56592-292-1
+<HR><A name="Zeigler"> Robert Zeigler</A><CITE> Linux Firewalls</CITE>
+<BR> Newriders Publishing, 2000 ISBN 0-7537-0900-9
+<P>A good book, with detailed coverage of ipchains(8) firewalls and of
+ many related issues.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="glossary.html">Previous</A>
+<A HREF="rfc.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/compat.html b/doc/compat.html
new file mode 100644
index 000000000..f01efa64c
--- /dev/null
+++ b/doc/compat.html
@@ -0,0 +1,707 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="trouble.html">Previous</A>
+<A HREF="interop.html">Next</A>
+<HR>
+<H1><A name="compat">Linux FreeS/WAN Compatibility Guide</A></H1>
+<P>Much of this document is quoted directly from the Linux FreeS/WAN<A href="mail.html">
+ mailing list</A>. Thanks very much to the community of testers,
+ patchers and commenters there, especially the ones quoted below but
+ also various contributors we haven't quoted.</P>
+<H2><A name="spec">Implemented parts of the IPsec Specification</A></H2>
+<P>In general, do not expect Linux FreeS/WAN to do everything yet. This
+ is a work-in-progress and some parts of the IPsec specification are not
+ yet implemented.</P>
+<H3><A name="in">In Linux FreeS/WAN</A></H3>
+<P>Things we do, as of version 1.96:</P>
+<UL>
+<LI>key management methods
+<DL>
+<DT>manually keyed</DT>
+<DD>using keys stored in /etc/ipsec.conf</DD>
+<DT>automatically keyed</DT>
+<DD>Automatically negotiating session keys as required. All connections
+ are automatically re-keyed periodically. The<A href="glossary.html#Pluto">
+ Pluto</A> daemon implements this using the<A href="glossary.html#IKE">
+ IKE</A> protocol.</DD>
+</DL>
+</LI>
+<LI>Methods of authenticating gateways for IKE
+<DL>
+<DT>shared secrets</DT>
+<DD>stored in<A href="manpage.d/ipsec.secrets.5.html"> ipsec.secrets(5)</A>
+</DD>
+<DT><A href="glossary.html#RSA">RSA</A> signatures</DT>
+<DD>For details, see<A href="manpage.d/ipsec_pluto.8.html"> pluto(8)</A>
+.</DD>
+<DT>looking up RSA authentication keys from<A href="glossary.html#DNS">
+ DNS</A>.</DT>
+<DD>Note that this technique cannot be fully secure until<A href="glossary.html#SDNS">
+ secure DNS</A> is widely deployed.</DD>
+</DL>
+</LI>
+<LI>groups for<A href="glossary.html#DH"> Diffie-Hellman</A> key
+ negotiation
+<DL>
+<DT>group 2, modp 1024-bit</DT>
+<DT>group 5, modp 1536-bit</DT>
+<DD>We implement these two groups.
+<P>In negotiating a keying connection (ISAKMP SA, Phase 1) we propose
+ both groups when we are the initiator, and accept either when a peer
+ proposes them. Once the keying connection is made, we propose only the
+ alternative agreed there for data connections (IPsec SA's, Phase 2)
+ negotiated over that keying connection.</P>
+</DD>
+</DL>
+</LI>
+<LI>encryption transforms
+<DL>
+<DT><A href="glossary.html#DES">DES</A></DT>
+<DD>DES is in the source code since it is needed to implement 3DES, but
+ single DES is not made available to users because<A href="politics.html#desnotsecure">
+ DES is insecure</A>.</DD>
+<DT><A href="glossary.html#3DES">Triple DES</A></DT>
+<DD>implemented, and used as the default encryption in Linux FreeS/WAN.</DD>
+</DL>
+</LI>
+<LI>authentication transforms
+<DL>
+<DT><A href="glossary.html#HMAC">HMAC</A> using<A href="glossary.html#MD5">
+ MD5</A></DT>
+<DD>implemented, may be used in IKE or by by AH or ESP transforms.</DD>
+<DT><A href="glossary.html#HMAC">HMAC</A> using<A href="glossary.html#SHA">
+ SHA</A></DT>
+<DD>implemented, may be used in IKE or by AH or ESP transforms.</DD>
+</DL>
+<P>In negotiations, we propose both of these and accept either.</P>
+</LI>
+<LI>compression transforms
+<DL>
+<DT>IPComp</DT>
+<DD>IPComp as described in RFC 2393 was added for FreeS/WAN 1.6. Note
+ that Pluto becomes confused if you ask it to do IPComp when the kernel
+ cannot.</DD>
+</DL>
+</LI>
+</UL>
+<P>All combinations of implemented transforms are supported. Note that
+ some form of packet-level<STRONG> authentication is required whenever
+ encryption is used</STRONG>. Without it, the encryption will not be
+ secure.</P>
+<H3><A name="dropped">Deliberately omitted</A></H3>
+ We do not implement everything in the RFCs because some of those things
+ are insecure. See our discussions of avoiding<A href="politics.html#weak">
+ bogus security</A>.
+<P>Things we deliberately omit which are required in the RFCs are:</P>
+<UL>
+<LI>null encryption (to use ESP as an authentication-only service)</LI>
+<LI>single DES</LI>
+<LI>DH group 1, a 768-bit modp group</LI>
+</UL>
+<P>Since these are the only encryption algorithms and DH group the RFCs
+ require, it is possible in theory to have a standards-conforming
+ implementation which will not interpoperate with FreeS/WAN. Such an
+ implementation would be inherently insecure, so we do not consider this
+ a problem.</P>
+<P>Anyway, most implementations sensibly include more secure options as
+ well, so dropping null encryption, single DES and Group 1 does not
+ greatly hinder interoperation in practice.</P>
+<P>We also do not implement some optional features allowed by the RFCs:</P>
+<UL>
+<LI>aggressive mode for negotiation of the keying channel or ISAKMP SA.
+ This mode is a little faster than main mode, but exposes more
+ information to an eavesdropper.</LI>
+</UL>
+<P>In theory, this should cause no interoperation problems since all
+ implementations are required to support the more secure main mode,
+ whether or not they also allow aggressive mode.</P>
+<P>In practice, it does sometimes produce problems with implementations
+ such as Windows 2000 where aggressive mode is the default. Typically,
+ these are easily solved with a configuration change that overrides that
+ default.</P>
+<H3><A name="not">Not (yet) in Linux FreeS/WAN</A></H3>
+<P>Things we don't yet do, as of version 1.96:</P>
+<UL>
+<LI>key management methods
+<UL>
+<LI>authenticate key negotiations via local<A href="glossary.html#PKI">
+ PKI</A> server, but see links to user<A href="web.html#patch"> patches</A>
+</LI>
+<LI>authenticate key negotiations via<A href="glossary.html#SDNS">
+ secure DNS</A></LI>
+<LI>unauthenticated key management, using<A href="glossary.html#DH">
+ Diffie-Hellman</A> key agreement protocol without authentication.
+ Arguably, this would be worth doing since it is secure against all
+ passive attacks. On the other hand, it is vulnerable to an active<A href="glossary.html#middle">
+ man-in-the-middle attack</A>.</LI>
+</UL>
+</LI>
+<LI>encryption transforms
+<P>Currently<A href="glossary.html#3DES"> Triple DES</A> is the only
+ encryption method Pluto will negotiate.</P>
+<P>No additional encryption transforms are implemented, though the RFCs
+ allow them and some other IPsec implementations support various of
+ them. We are not eager to add more. See this<A href="faq.html#other.cipher">
+ FAQ question</A>.</P>
+<P><A href="glossary.html#AES">AES</A>, the successor to the DES
+ standard, is an excellent candidate for inclusion in FreeS/WAN, see
+ links to user<A href="web.html#patch"> patches</A>.</P>
+</LI>
+<LI>authentication transforms
+<P>No optional additional authentication transforms are currently
+ implemented. Likely<A href="glossary.html#SHA-256"> SHA-256, SHA-384
+ and SHA-512</A> will be added when AES is.</P>
+</LI>
+<LI>Policy checking on decrypted packets
+<P>To fully comply with the RFCs, it is not enough just to accept only
+ packets which survive any firewall rules in place to limit what IPsec
+ packets get in, and then pass KLIPS authentication. That is what
+ FreeS/WAN currently does.</P>
+<P>We should also apply additional tests, for example ensuring that all
+ packets emerging from a particular tunnel have source and destination
+ addresses that fall within the subnets defined for that tunnel, and
+ that packets with those addresses that did not emerge from the
+ appropriate tunnel are disallowed.</P>
+<P>This will be done as part of a KLIPS rewrite. See these<A href="intro.html#applied">
+ links</A> and the<A href="mail.html"> design mailing list</A> for
+ discussion.</P>
+</LI>
+</UL>
+<H2><A name="pfkey">Our PF-Key implementation</A></H2>
+<P>We use PF-key Version Two for communication between the KLIPS kernel
+ code and the Pluto Daemon. PF-Key v2 is defined by<A href="http://www.normos.org/ietf/rfc/rfc2367.txt">
+ RFC 2367</A>.</P>
+<P>The &quot;PF&quot; stands for Protocol Family. PF-Inet defines a
+ kernel/userspace interface for the TCP/IP Internet protocols (TCP/IP),
+ and other members of the PF series handle Netware, Appletalk, etc.
+ PF-Key is just a PF for key-related matters.</P>
+<H3><A name="pfk.port">PF-Key portability</A></H3>
+<P>PF-Key came out of Berkeley Unix work and is used in the various BSD
+ IPsec implementations, and in Solaris. This means there is some hope of
+ porting our Pluto(8) to one of the BSD distributions, or of running
+ their photurisd(8) on Linux if you prefer<A href="glossary.html#photuris">
+ Photuris</A> key management over IKE.</P>
+<P>It is, however, more complex than that. The PK-Key RFC deliberately
+ deals only with keying, not policy management. The three PF-Key
+ implementations we have looked at -- ours, OpenBSD and KAME -- all have
+ extensions to deal with security policy, and the extensions are
+ different. There have been discussions aimed at sorting out the
+ differences, perhaps for a version three PF-Key spec. All players are
+ in favour of this, but everyone involved is busy and it is not clear
+ whether or when these discussions might bear fruit.</P>
+<H2><A name="otherk">Kernels other than the latest 2.2.x and 2.4.y</A></H2>
+<P>We develop and test on Redhat Linux using the most recent kernel in
+ the 2.2 and 2.4 series. In general, we recommend you use the latest
+ kernel in one of those series. Complications and caveats are discussed
+ below.</P>
+<H3><A name="kernel.2.0">2.0.x kernels</A></H3>
+<P>Consider upgrading to the 2.2 kernel series. If you want to stay with
+ the 2.0 series, then we strongly recommend 2.0.39. Some useful security
+ patches were added in 2.0.38.</P>
+<P>Various versions of the code have run at various times on most 2.0.xx
+ kernels, but the current version is only lightly tested on 2.0.39, and
+ not at all on older kernels.</P>
+<P>Some of our patches for older kernels are shipped in 2.0.37 and
+ later, so they are no longer provided in FreeS/WAN. This means recent
+ versions of FreeS/WAN will probably not compile on anything earlier
+ than 2.0.37.</P>
+<H3><A name="kernel.production">2.2 and 2.4 kernels</A></H3>
+<DL>
+<DT>FreeS/WAN 1.0</DT>
+<DD>ran only on 2.0 kernels</DD>
+<DT>FreeS/WAN 1.1 to 1.8</DT>
+<DD>ran on 2.0 or 2.2 kernels
+<BR> ran on some development kernels, 2.3 or 2.4-test</DD>
+<DT>FreeS/WAN 1.9 to 1.96</DT>
+<DD>runs on 2.0, 2.2 or 2.4 kernels</DD>
+</DL>
+<P>In general,<STRONG> we suggest the latest 2.2 kernel or 2.4 for
+ production use</STRONG>.</P>
+<P>Of course no release can be guaranteed to run on kernels more recent
+ than it is, so quite often there will be no stable FreeS/WAN for the
+ absolute latest kernel. See the<A href="faq.html#k.versions"> FAQ</A>
+ for discussion.</P>
+<H2><A name="otherdist">Intel Linux distributions other than Redhat</A></H2>
+<P>We develop and test on Redhat 6.1 for 2.2 kernels, and on Redhat 7.1
+ or 7.2 for 2.4, so minor changes may be required for other
+ distributions.</P>
+<H3><A name="rh7">Redhat 7.0</A></H3>
+<P>There are some problems with FreeS/WAN on Redhat 7.0. They are
+ soluble, but we recommend you upgrade to a later Redhat instead..</P>
+<P>Redhat 7 ships with two compilers.</P>
+<UL>
+<LI>Their<VAR> gcc</VAR> is version 2.96. Various people, including the
+ GNU compiler developers and Linus, have said fairly emphatically that
+ using this was a mistake. 2.96 is a development version, not intended
+ for production use. In particular, it will not compile a Linux kernel.</LI>
+<LI>Redhat therefore also ship a separate compiler, which they call<VAR>
+ kgcc</VAR>, for compiling kernels.</LI>
+</UL>
+<P>Kernel Makefiles have<VAR> gcc</VAR> as a default, and must be
+ adjusted to use<VAR> kgcc</VAR> before a kernel will compile on 7.0.
+ This mailing list message gives details:</P>
+<PRE>Subject: Re: AW: Installing IPsec on Redhat 7.0
+ Date: Thu, 1 Feb 2001 14:32:52 -0200 (BRST)
+ From: Mads Rasmussen &lt;mads@cit.com.br&gt;
+
+&gt; From www.redhat.com/support/docs/gotchas/7.0/gotchas-7-6.html#ss6.1
+
+cd to /usr/src/linux and open the Makefile in your favorite editor. You
+will need to look for a line similar to this:
+
+CC = $(CROSS_COMPILE)gcc -D__KERNEL__ -I$(HPATH)
+
+This line specifies which C compiler to use to build the kernel. It should
+be changed to:
+
+CC = $(CROSS_COMPILE)kgcc -D__KERNEL__ -I$(HPATH)
+
+for Red Hat Linux 7. The kgcc compiler is egcs 2.91.66. From here you can
+proceed with the typical compiling steps.</PRE>
+<P>Check the<A href="mail.html"> mailing list</A> archive for more
+ recent news.</P>
+<H3><A name="suse">SuSE Linux</A></H3>
+<P>SuSE 6.3 and later versions, at least in Europe, ship with FreeS/WAN
+ included.</P>
+<P>FreeS/WAN packages distributed for SuSE 7.0-7.2 were somehow
+ miscompiled. You can find fixed packages on<A HREF="http://www.suse.de/~garloff/linux/FreeSWAN">
+ Kurt Garloff's page</A>.</P>
+<P>Here are some notes for an earlier SuSE version.</P>
+<H4>SuSE Linux 5.3</H4>
+<PRE>Date: Mon, 30 Nov 1998
+From: Peter Onion &lt;ponion@srd.bt.co.uk&gt;
+
+... I got Saturdays snapshot working between my two SUSE5.3 machines at home.
+
+The mods to the install process are quite simple. From memory and looking at
+the files on the SUSE53 machine here at work....
+
+And extra link in each of the /etc/init.d/rc?.d directories called K35ipsec
+which SUSE use to shut a service down.
+
+A few mods in /etc/init.d/ipsec to cope with the different places that SUSE
+put config info, and remove the inculsion of /etc/rc.d/init.d/functions and .
+/etc/sysconfig/network as they don't exists and 1st one isn't needed anyway.
+
+insert &quot;. /etc/rc.config&quot; to pick up the SUSE config info and use
+
+ if test -n &quot;$NETCONFIG&quot; -a &quot;$NETCONFIG&quot; != &quot;YAST_ASK&quot; ; then
+
+to replace
+
+ [ ${NETWORKING} = &quot;no&quot; ] &amp;&amp; exit 0
+
+Create /etc/sysconfig as SUSE doesn't have one.
+
+I think that was all (but I prob forgot something)....</PRE>
+<P>You may also need to fiddle initialisation scripts to ensure that<VAR>
+ /var/run/pluto.pid</VAR> is removed when rebooting. If this file is
+ present, Pluto does not come up correctly.</P>
+<H3><A name="slack">Slackware</A></H3>
+<PRE>Subject: Re: linux-IPsec: Slackware distribution
+ Date: Thu, 15 Apr 1999 12:07:01 -0700
+ From: Evan Brewer &lt;dmessiah@silcon.com&gt;
+
+&gt; Very shortly, I will be needing to install IPsec on at least gateways that
+&gt; are running Slackware. . . .
+
+The only trick to getting it up is that on the slackware dist there is no
+init.d directory in /etc/rc.d .. so create one. Then, what I do is take the
+IPsec startup script which normally gets put into the init.d directory, and
+put it in /etc/rc.d and name ir rc.ipsec .. then I symlink it to the file
+in init.d. The only file in the dist you need to really edit is the
+utils/Makefile, setup4:
+
+Everything else should be just fine.</PRE>
+<P>A year or so later:</P>
+<PRE>Subject: Re: HTML Docs- Need some cleanup?
+ Date: Mon, 8 Jan 2001
+ From: Jody McIntyre &lt;jodym@oeone.com&gt;
+
+I have successfully installed FreeS/WAN on several Slackware 7.1 machines.
+FreeS/WAN installed its rc.ipsec file in /etc/rc.d. I had to manually call
+this script from rc.inet2. This seems to be an easier method than Evan
+Brewer's.</PRE>
+<H3><A name="deb">Debian</A></H3>
+<P>A recent (Nov 2001) mailing list points to a<A href="http://www.thing.dyndns.org/debian/vpn.htm">
+ web page</A> on setting up several types of tunnel, including IPsec, on
+ Debian.</P>
+<P>Some older information:</P>
+<PRE>Subject: FreeS/WAN 1.0 on Debian 2.1
+ Date: Tue, 20 Apr 1999
+ From: Tim Miller &lt;cerebus+counterpane@haybaler.sackheads.org&gt;
+
+ Compiled and installed without error on a Debian 2.1 system
+with kernel-source-2.0.36 after pointing RCDIR in utils/Makefile to
+/etc/init.d.
+
+ /var/lock/subsys/ doesn't exist on Debian boxen, needs to be
+created; not a fatal error.
+
+ Finally, IPsec scripts appear to be dependant on GNU awk
+(gawk); the default Debian awk (mawk-1.3.3-2) had fatal difficulties.
+With gawk installed and /etc/alternatives/awk linked to /usr/bin/gawk
+operation appears flawless.</PRE>
+<P>The scripts in question have been modified since this was posted. Awk
+ versions should no longer be a problem.</P>
+<H3><A name="caldera">Caldera</A></H3>
+<PRE>Subject: Re: HTML Docs- Need some cleanup?
+ Date: Mon, 08 Jan 2001
+ From: Andy Bradford &lt;andyb@calderasystems.com&gt;
+
+On Sun, 07 Jan 2001 22:59:05 EST, Sandy Harris wrote:
+
+&gt; Intel Linux distributions other than Redhat 5.x and 6.x
+&gt; Redhat 7.0
+&gt; SuSE Linux
+&gt; SuSE Linux 5.3
+&gt; Slackware
+&gt; Debian
+
+Can you please include Caldera in this list? I have tested it since
+FreeS/Wan 1.1 and it works great with our systems---provided one
+follows the FreeS/Wan documentation. :-)
+
+Thank you,
+Andy</PRE>
+<H2><A name="CPUs">CPUs other than Intel</A></H2>
+<P>FreeS/WAN has been run sucessfully on a number of different CPU
+ architectures. If you have tried it on one not listed here, please post
+ to the<A href="mail.html"> mailing list</A>.</P>
+<H3><A name=" strongarm">Corel Netwinder (StrongARM CPU)</A></H3>
+<PRE>Subject: linux-ipsec: Netwinder diffs
+Date: Wed, 06 Jan 1999
+From: rhatfield@plaintree.com
+
+I had a mistake in my IPsec-auto, so I got things working this morning.
+
+Following are the diffs for my changes. Probably not the best and cleanest way
+of doing it, but it works. . . . </PRE>
+<P>These diffs are in the 0.92 and later distributions, so these should
+ work out-of-the-box on Netwinder.</P>
+<H3><A name="yellowdog">Yellow Dog Linux on Power PC</A></H3>
+<PRE>Subject: Compiling FreeS/WAN 1.1 on YellowDog Linux (PPC)
+ Date: 11 Dec 1999
+ From: Darron Froese &lt;darron@fudgehead.com&gt;
+
+I'm summarizing here for the record - because it's taken me many hours to do
+this (multiple times) and because I want to see IPsec on more linuxes than
+just x86.
+
+Also, I can't remember if I actually did summarize it before... ;-) I'm
+working too many late hours.
+
+That said - here goes.
+
+1. Get your linux kernel and unpack into /usr/src/linux/ - I used 2.2.13.
+&lt;http://www.kernel.org/pub/linux/kernel/v2.2/linux-2.2.13.tar.bz2&gt;
+
+2. Get FreeS/WAN and unpack into /usr/src/freeswan-1.1
+&lt;ftp://ftp.xs4all.nl/pub/crypto/freeswan/freeswan-1.1.tar.gz&gt;
+
+3. Get the gmp src rpm from here:
+&lt;ftp://ftp.yellowdoglinux.com//pub/yellowdog/champion-1.1/SRPMS/SRPMS/gmp-2.0.2-9a.src.rpm&gt;
+
+4. Su to root and do this: rpm --rebuild gmp-2.0.2-9a.src.rpm
+
+You will see a lot of text fly by and when you start to see the rpm
+recompiling like this:
+
+Executing: %build
++ umask 022
++ cd /usr/src/redhat/BUILD
++ cd gmp-2.0.2
++ libtoolize --copy --force
+Remember to add `AM_PROG_LIBTOOL' to `configure.in'.
+You should add the contents of `/usr/share/aclocal/libtool.m4' to
+`aclocal.m4'.
++ CFLAGS=-O2 -fsigned-char
++ ./configure --prefix=/usr
+
+Hit Control-C to stop the rebuild. NOTE: We're doing this because for some
+reason the gmp source provided with FreeS/WAN 1.1 won't build properly on
+ydl.
+
+cd /usr/src/redhat/BUILD/
+cp -ar gmp-2.0.2 /usr/src/freeswan-1.1/
+cd /usr/src/freeswan-1.1/
+rm -rf gmp
+mv gmp-2.0.2 gmp
+
+5. Open the freeswan Makefile and change the line that says:
+KERNEL=$(b)zimage (or something like that) to
+KERNEL=vmlinux
+
+6. cd ../linux/
+
+7. make menuconfig
+Select an option or two and then exit - saving your changes.
+
+8. cd ../freeswan-1.1/ ; make menugo
+
+That will start the whole process going - once that's finished compiling,
+you have to install your new kernel and reboot.
+
+That should build FreeS/WAN on ydl (I tried it on 1.1).</PRE>
+ And a later message on the same topic:
+<PRE>Subject: Re: FreeS/WAN, PGPnet and E-mail
+ Date: Sat, 22 Jan 2000
+ From: Darron Froese &lt;darron@fudgehead.com&gt;
+
+on 1/22/00 6:47 PM, Philip Trauring at philip@trauring.com wrote:
+
+&gt; I have a PowerMac G3 ...
+
+The PowerMac G3 can run YDL 1.1 just fine. It should also be able to run
+FreeS/WAN 1.2patch1 with a couple minor modifications:
+
+1. In the Makefile it specifies a bzimage for the kernel compile - you have
+to change that to vmlinux for the PPC.
+
+2. The gmp source that comes with FreeS/WAN (for whatever reason) fails to
+compile. I have gotten around this by getting the gmp src rpm from here:
+
+ftp://ftp.yellowdoglinux.com//pub/yellowdog/champion-1.1/SRPMS/SRPMS/gmp-2.0.2-9a.src.rpm
+
+If you rip the source out of there - and place it where the gmp source
+resides it will compile just fine.</PRE>
+<P>FreeS/WAN no longer includes GMP source.</P>
+<H3><A name="mklinux">Mklinux</A></H3>
+<P>One user reports success on the Mach-based<STRONG> m</STRONG>icro<STRONG>
+k</STRONG>ernel Linux.</P>
+<PRE>Subject: Smiles on sparc and ppc
+ Date: Fri, 10 Mar 2000
+ From: Jake Hill &lt;jah@alien.bt.co.uk&gt;
+
+You may or may not be interested to know that I have successfully built
+FreeS/WAN on a number of non intel alpha architectures; namely on ppc
+and sparc and also on osfmach3/ppc (MkLinux). I can report that it just
+works, mostly, with few changes.</PRE>
+<H3><A name="alpha">Alpha 64-bit processors</A></H3>
+<PRE>Subject: IT WORKS (again) between intel &amp; alpha :-)))))
+ Date: Fri, 29 Jan 1999
+ From: Peter Onion &lt;ponion@srd.bt.co.uk&gt;
+
+Well I'm happy to report that I've got an IPsec connection between by intel &amp; alpha machines again :-))
+
+If you look back on this list to 7th of December I wrote...
+
+-On 07-Dec-98 Peter Onion wrote:
+-&gt;
+-&gt; I've about had enuf of wandering around inside the kernel trying to find out
+-&gt; just what is corrupting outgoing packets...
+-
+-Its 7:30 in the evening .....
+-
+-I FIXED IT :-))))))))))))))))))))))))))))))))
+-
+-It was my own fault :-((((((((((((((((((
+-
+-If you ask me very nicly I'll tell you where I was a little too over keen to
+-change unsigned long int __u32 :-) OPSE ...
+-
+-So tomorrow it will full steam ahead to produce a set of diffs/patches against
+-0.91
+-
+-Peter Onion.</PRE>
+<P>In general (there have been some glitches), FreeS/WAN has been
+ running on Alphas since then.</P>
+<H3><A name="SPARC">Sun SPARC processors</A></H3>
+<P>Several users have reported success with FreeS/WAN on SPARC Linux.
+ Here is one mailing list message:</P>
+<PRE>Subject: Smiles on sparc and ppc
+ Date: Fri, 10 Mar 2000
+ From: Jake Hill &lt;jah@alien.bt.co.uk&gt;
+
+You may or may not be interested to know that I have successfully built
+FreeS/WAN on a number of non intel alpha architectures; namely on ppc
+and sparc and also on osfmach3/ppc (MkLinux). I can report that it just
+works, mostly, with few changes.
+
+I have a question, before I make up some patches. I need to hack
+gmp/mpn/powerpc32/*.s to build them. Is this ok? The changes are
+trivial, but could I also use a different version of gmp? Is it vanilla
+here?
+
+I guess my only real headache is from ipchains, which appears to stop
+running when IPsec has been started for a while. This is with 2.2.14 on
+sparc.</PRE>
+<P>This message, from a different mailing list, may be relevant for
+ anyone working with FreeS/WAN on Suns:</P>
+<PRE>Subject: UltraSPARC DES assembler
+ Date: Thu, 13 Apr 2000
+ From: svolaf@inet.uni2.dk (Svend Olaf Mikkelsen)
+ To: coderpunks@toad.com
+
+An UltraSPARC assembler version of the LibDES/SSLeay/OpenSSL des_enc.c
+file is available at http://inet.uni2.dk/~svolaf/des.htm.
+
+This brings DES on UltraSPARC from slower than Pentium at the same
+clock speed to significantly faster.</PRE>
+<H3><A name="mips">MIPS processors</A></H3>
+<P>We know FreeS/WAN runs on at least some MIPS processors because<A href="http://www.lasat.com">
+ Lasat</A> manufacture an IPsec box based on an embedded MIPS running
+ Linux with FreeS/WAN. We have no details.</P>
+<H3><A name="crusoe">Transmeta Crusoe</A></H3>
+<P>The Merilus<A href="http://www.merilus.com/products/fc/index.shtml">
+ Firecard</A>, a Linux firewall on a PCI card, is based on a Crusoe
+ processor and supports FreeS/WAN.</P>
+<H3><A name="coldfire">Motorola Coldfire</A></H3>
+<PRE>Subject: Re: Crypto hardware support
+ Date: Mon, 03 Jul 2000
+ From: Dan DeVault &lt;devault@tampabay.rr.com&gt;
+
+.... I have been running
+uClinux with FreeS/WAN 1.4 on a system built by Moreton Bay (
+http://www.moretonbay.com ) and it was using a Coldfire processor
+and was able to do the Triple DES encryption at just about
+1 mbit / sec rate....... they put a Hi/Fn 7901 hardware encryption
+chip on their board and now their system does over 25 mbit of 3DES
+encryption........ pretty significant increase if you ask me.</PRE>
+<H2><A name="multiprocessor">Multiprocessor machines</A></H2>
+<P>FreeS/WAN is designed to work on SMP (symmetric multi-processing)
+ Linux machines and is regularly tested on dual processor x86 machines.</P>
+<P>We do not know of any testing on multi-processor machines with other
+ CPU architectures or with more than two CPUs. Anyone who does test
+ this, please report results to the<A href="mail.html"> mailing list</A>
+.</P>
+<P>The current design does not make particularly efficient use of
+ multiprocessor machines; some of the kernel work is single-threaded.</P>
+<H2><A name="hardware">Support for crypto hardware</A></H2>
+<P>Supporting hardware cryptography accelerators has not been a high
+ priority for the development team because it raises a number of fairly
+ complex issues:</P>
+<UL>
+<LI>Can you trust the hardware? If it is not Open Source, how do you
+ audit its security? Even if it is, how do you check that the design has
+ no concealed traps?</LI>
+<LI>If an interface is added for such hardware, can that interface be
+ subverted or misused?</LI>
+<LI>Is hardware acceleration actually a performance win? It clearly is
+ in many cases, but on a fast machine it might be better to use the CPU
+ for the encryption than to pay the overheads of moving data to and from
+ a crypto board.</LI>
+<LI>the current KLIPS code does not provide a clean interface for
+ hardware accelerators</LI>
+</UL>
+<P>That said, we have a<A href="#coldfire"> report</A> of FreeS/WAN
+ working with one crypto accelerator and some work is going on to modify
+ KLIPS to create a clean generic interface to such products. See this<A href="http://www.jukie.net/~bart/linux-ipsec/">
+ web page</A> for some of the design discussion.</P>
+<P>More recently, a patch to support some hardware accelerators has been
+ posted:</P>
+<PRE>Subject: [Design] [PATCH] H/W acceleration patch
+ Date: Tue, 18 Sep 2001
+ From: &quot;Martin Gadbois&quot; &lt;martin.gadbois@colubris.com&gt;
+
+Finally!!
+Here's a web site with H/W acceleration patch for FreeS/WAN 1.91, including
+S/W and Hifn 7901 crypto support.
+
+http://sources.colubris.com/
+
+Martin Gadbois</PRE>
+<P>Hardware accelerators could take performance well beyond what
+ FreeS/WAN can do in software (discussed<A href="performance.html"> here</A>
+). Here is some discussion off the IETF IPsec list, October 2001:</P>
+<PRE> ... Currently shipping chips deliver, 600 mbps throughput on a single
+ stream of 3DES IPsec traffic. There are also chips that use multiple
+ cores to do 2.4 gbps. We (Cavium) and others have announced even faster
+ chips. ... Mid 2002 versions will handle at line rate (OC48 and OC192)
+ IPsec and SSL/TLS traffic not only 3DES CBC but also AES and arc4.</PRE>
+<P>The patches to date support chips that have been in production for
+ some time, not the state-of-the-art latest-and-greatest devices
+ described in that post. However, they may still outperform software and
+ they almost certainly reduce CPU overhead.</P>
+<H2><A name="ipv6">IP version 6 (IPng)</A></H2>
+<P>The Internet currently runs on version four of the IP protocols. IPv4
+ is what is in the standard Linux IP stack, and what FreeS/WAN was built
+ for. In IPv4, IPsec is an optional feature.</P>
+<P>The next version of the IP protocol suite is version six, usually
+ abbreviated either as &quot;IPv6&quot; or as &quot;IPng&quot; for &quot;IP: the next
+ generation&quot;. For IPv6, IPsec is a required feature. Any machine doing
+ IPv6 is required to support IPsec, much as any machine doing (any
+ version of) IP is required to support ICMP.</P>
+<P>There is a Linux implementation of IPv6 in Linux kernels 2.2 and
+ above. For details, see the<A href="http://www.cs-ipv6.lancs.ac.uk/ipv6/systems/linux/faq/">
+ FAQ</A>. It does not yet support IPsec. The<A href="http://www.linux-ipv6.org/">
+ USAGI</A> project are also working on IPv6 for Linux.</P>
+<P>FreeS/WAN was originally built for the current standard, IPv4, but we
+ are interested in seeing it work with IPv6. Some progress has been
+ made, and a patched version with IPv6 support is<A href="http://www.ipv6.iabg.de/downloadframe/index.html">
+ available</A>. For more recent information, check the<A href="mail.html">
+ mailing list</A>.</P>
+<H3><A name="v6.back">IPv6 background</A></H3>
+<P>IPv6 has been specified by an IETF<A href="http://www.ietf.org/html.charters/ipngwg-charter.html">
+ working group</A>. The group's page lists over 30 RFCs to date, and
+ many Internet Drafts as well. The overview is<A href="http://www.ietf.org/rfc/rfc2460.txt">
+ RFC 2460</A>. Major features include:</P>
+<UL>
+<LI>expansion of the address space from 32 to 128 bits,</LI>
+<LI>changes to improve support for
+<UL>
+<LI>mobile IP</LI>
+<LI>automatic network configuration</LI>
+<LI>quality of service routing</LI>
+<LI>...</LI>
+</UL>
+</LI>
+<LI>improved security via IPsec</LI>
+</UL>
+<P>A number of projects are working on IPv6 implementation. A prominent
+ Open Source effort is<A href="http://www.kame.net/"> KAME</A>, a
+ collaboration among several large Japanese companies to implement IPv6
+ for Berkeley Unix. Other major players are also working on IPv6. For
+ example, see pages at:</P>
+<UL>
+<LI><A href="http://playground.sun.com/pub/ipng/html/ipng-main.html">Sun</A>
+</LI>
+<LI><A href="http://www.cisco.com/warp/public/732/ipv6/index.html">Cisco</A>
+</LI>
+<LI><A href="http://www.microsoft.com/windows2000/techinfo/howitworks/communications/networkbasics/IPv6.asp">
+Microsoft</A></LI>
+</UL>
+<P>The<A href="http://www.6bone.net/"> 6bone</A> (IPv6 backbone) testbed
+ network has been up for some time. There is an active<A href="http://www.ipv6.org/">
+ IPv6 user group</A>.</P>
+<P>One of the design goals for IPv6 was that it must be possible to
+ convert from v4 to v6 via a gradual transition process. Imagine the
+ mess if there were a &quot;flag day&quot; after which the entire Internet used
+ v6, and all software designed for v4 stopped working. Almost every
+ computer on the planet would need major software changes! There would
+ be huge costs to replace older equipment. Implementers would be worked
+ to death before &quot;the day&quot;, systems administrators and technical support
+ would be completely swamped after it. The bugs in every implementation
+ would all bite simultaneously. Large chunks of the net would almost
+ certainly be down for substantial time periods. ...</P>
+<P>Fortunately, the design avoids any &quot;flag day&quot;. It is therefore a
+ little tricky to tell how quickly IPv6 will take over. The transition
+ has certainly begun. For examples, see announcements from<A href="http://www.mailbase.ac.uk/lists/internet2/2000-03/0016.html">
+ NTT</A> and<A href="http://www.vnunet.com/News/1102383"> Nokia</A>.
+ However, it is not yet clear how quickly the process will gain
+ momentum, or when it will be completed. Likely large parts of the
+ Internet will remain with IPv4 for years to come.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="trouble.html">Previous</A>
+<A HREF="interop.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/config.html b/doc/config.html
new file mode 100644
index 000000000..4e9f0a513
--- /dev/null
+++ b/doc/config.html
@@ -0,0 +1,308 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="install.html">Previous</A>
+<A HREF="background.html">Next</A>
+<HR>
+<H1><A NAME="config">How to configure FreeS/WAN</A></H1>
+<P>This page will teach you how to configure a simple network-to-network
+ link or a Road Warrior connection between two Linux FreeS/WAN boxes.</P>
+<P>See also these related documents:</P>
+<UL>
+<LI>our<A HREF="quickstart.html#quickstart"> quickstart</A> guide to<A HREF="glossary.html#carpediem">
+ opportunistic encryption</A></LI>
+<LI>our guide to configuration with<A HREF="policygroups.html#policygroups">
+ policy groups</A></LI>
+<LI>our<A HREF="adv_config.html#adv_config"> advanced configuration</A>
+ document</LI>
+</UL>
+<P> The network-to-network setup allows you to connect two office
+ networks into one Virtual Private Network, while the Road Warrior
+ connection secures a laptop's telecommute to work. Our examples also
+ show the basic procedure on the Linux FreeS/WAN side where another
+ IPsec peer is in play.</P>
+<P> Shortcut to<A HREF="#config.netnet"> net-to-net</A>.
+<BR> Shortcut to<A HREF="#config.rw"> Road Warrior</A>.</P>
+<H2><A NAME="16_1">Requirements</A></H2>
+<P>To configure the network-to-network connection you must have:</P>
+<UL>
+<LI>two Linux gateways with static IPs</LI>
+<LI>a network behind each gate. Networks must have non-overlapping IP
+ ranges.</LI>
+<LI>Linux FreeS/WAN<A HREF="install.html#install"> installed</A> on both
+ gateways</LI>
+<LI><A HREF="http://www.tcpdump.org"><VAR>tcpdump</VAR></A> on the local
+ gate, to test the connection</LI>
+</UL>
+<P>For the Road Warrior you need:</P>
+<UL>
+<LI>one Linux box with a static IP</LI>
+<LI>a Linux laptop with a dynamic IP</LI>
+<LI>Linux FreeS/WAN installed on both</LI>
+<LI>for testing,<VAR> tcpdump</VAR> on your gateway or laptop</LI>
+</UL>
+<P>If both IPs are dynamic, your situation is a bit trickier. Your best
+ bet is a variation on the<A HREF="#config.rw"> Road Warrior</A>, as
+ described in<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00282.html">
+ this mailing list message</A>.</P>
+<H2><A name="config.netnet"></A>Net-to-Net connection</H2>
+<H3><A name="netnet.info.ex">Gather information</A></H3>
+<P>For each gateway, compile the following information:</P>
+<UL>
+<LI>gateway IP</LI>
+<LI>IP range of the subnet you will be protecting. This doesn't have to
+ be your whole physical subnet.</LI>
+<LI>a name by which that gateway can identify itself for IPsec
+ negotiations. Its form is a Fully Qualified Domain Name preceded by an
+ @ sign, ie. @xy.example.com.
+<BR> It does not need to be within a domain that you own. It can be a
+ made-up name.</LI>
+</UL>
+<H4>Get your leftrsasigkey</H4>
+<P>On your local Linux FreeS/WAN gateway, print your IPsec public key:</P>
+<PRE> ipsec showhostkey --left</PRE>
+<P>The output should look like this (with the key shortened for easy
+ reading):</P>
+<PRE> # RSA 2048 bits xy.example.com Fri Apr 26 15:01:41 2002
+ leftrsasigkey=0sAQOnwiBPt...</PRE>
+<P>Don't have a key? Use<A HREF="manpage.d/ipsec_newhostkey.8.html"><VAR>
+ ipsec newhostkey</VAR></A> to create one.</P>
+<H4>...and your rightrsasigkey</H4>
+<P>Get a console on the remote side:</P>
+<PRE> ssh2 ab.example.com</PRE>
+<P>In that window, type:</P>
+<PRE> ipsec showhostkey --right</PRE>
+<P>You'll see something like:</P>
+<PRE> # RSA 2192 bits ab.example.com Thu May 16 15:26:20 2002
+ rightrsasigkey=0sAQOqH55O...</PRE>
+<H3><A NAME="16_2_2">Edit<VAR> /etc/ipsec.conf</VAR></A></H3>
+<P>Back on the local gate, copy our template to<VAR> /etc/ipsec.conf</VAR>
+. (on Mandrake,<VAR> /etc/freeswan/ipsec.conf</VAR>). Substitute the
+ information you've gathered for our example data.</P>
+<PRE>conn net-to-net
+ left=192.0.2.2 # Local vitals
+ leftsubnet=192.0.2.128/29 #
+ leftid=@xy.example.com #
+ leftrsasigkey=0s1LgR7/oUM... #
+ leftnexthop=%defaultroute # correct in many situations
+ right=192.0.2.9 # Remote vitals
+ rightsubnet=10.0.0.0/24 #
+ rightid=@ab.example.com #
+ rightrsasigkey=0sAQOqH55O... #
+ rightnexthop=%defaultroute # correct in many situations
+ auto=add # authorizes but doesn't start this
+ # connection at startup</PRE>
+<P> &quot;Left&quot; and &quot;right&quot; should represent the machines that have FreeS/WAN
+ installed on them, and &quot;leftsubnet&quot; and &quot;rightsubnet&quot; machines that are
+ being protected. /32 is assumed for left/right and left/rightsubnet
+ parameters.</P>
+<P>Copy<VAR> conn net-to-net</VAR> to the remote-side /etc/ipsec.conf.
+ If you've made no other modifications to either<VAR> ipsec.conf</VAR>,
+ simply:</P>
+<PRE> scp2 ipsec.conf root@ab.example.com:/etc/ipsec.conf</PRE>
+<H3><A NAME="16_2_3">Start your connection</A></H3>
+<P>Locally, type:</P>
+<PRE> ipsec auto --up net-to-net</PRE>
+<P>You should see:</P>
+<PRE> 104 &quot;net-net&quot; #223: STATE_MAIN_I1: initiate
+ 106 &quot;net-net&quot; #223: STATE_MAIN_I2: sent MI2, expecting MR2
+ 108 &quot;net-net&quot; #223: STATE_MAIN_I3: sent MI3, expecting MR3
+ 004 &quot;net-net&quot; #223: STATE_MAIN_I4: ISAKMP SA established
+ 112 &quot;net-net&quot; #224: STATE_QUICK_I1: initiate
+ 004 &quot;net-net&quot; #224: STATE_QUICK_I2: sent QI2, IPsec SA established</PRE>
+<P>The important thing is<VAR> IPsec SA established</VAR>. If you're
+ unsuccessful, see our<A HREF="trouble.html#trouble"> troubleshooting
+ tips</A>.</P>
+<H3><A NAME="16_2_4">Do not MASQ or NAT packets to be tunneled</A></H3>
+<P>If you are using<A HREF="glossary.html#masq"> IP masquerade</A> or<A HREF="glossary.html#NAT.gloss">
+ Network Address Translation (NAT)</A> on either gateway, you must now
+ exempt the packets you wish to tunnel from this treatment. For example,
+ if you have a rule like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -j MASQUERADE
+</PRE>
+<P>change it to something like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -d \! 192.0.2.128/29 -j MASQUERADE</PRE>
+<P>This may be necessary on both gateways.</P>
+<H3><A NAME="16_2_5">Test your connection</A></H3>
+<P>Sit at one of your local subnet nodes (not the gateway), and ping a
+ subnet node on the other (again, not the gateway).</P>
+<PRE> ping fileserver.toledo.example.com</PRE>
+<P>While still pinging, go to the local gateway and snoop your outgoing
+ interface, for example:</P>
+<PRE> tcpdump -i ppp0</PRE>
+<P>You want to see ESP (Encapsulating Security Payload) packets moving<B>
+ back and forth</B> between the two gateways at the same frequency as
+ your pings:</P>
+<PRE> 19:16:32.046220 192.0.2.2 &gt; 192.0.2.9: ESP(spi=0x3be6c4dc,seq=0x3)
+ 19:16:32.085630 192.0.2.9 &gt; 192.0.2.2: ESP(spi=0x5fdd1cf8,seq=0x6)</PRE>
+<P>If you see this, congratulations are in order! You have a tunnel
+ which will protect any IP data from one subnet to the other, as it
+ passes between the two gates. If not, go and<A HREF="trouble.html#trouble">
+ troubleshoot</A>.</P>
+<P>Note: your new tunnel protects only net-net traffic, not
+ gateway-gateway, or gateway-subnet. If you need this (for example, if
+ machines on one net need to securely contact a fileserver on the IPsec
+ gateway), you'll need to create<A HREF="adv_config.html#adv_config">
+ extra connections</A>.</P>
+<H3><A NAME="16_2_6">Finishing touches</A></H3>
+<P>Now that your connection works, name it something sensible, like:</P>
+<PRE>conn winstonnet-toledonet</PRE>
+<P>To have the tunnel come up on-boot, replace</P>
+<PRE> auto=add</PRE>
+<P>with:</P>
+<PRE> auto=start</PRE>
+<P>Copy these changes to the other side, for example:</P>
+<PRE> scp2 ipsec.conf root@ab.example.com:/etc/ipsec.conf</PRE>
+<P>Enjoy!</P>
+<H2><A name="config.rw"></A>Road Warrior Configuration</H2>
+<H3><A name="rw.info.ex">Gather information</A></H3>
+<P>You'll need to know:</P>
+<UL>
+<LI>the gateway's static IP</LI>
+<LI>the IP range of the subnet behind that gateway</LI>
+<LI>a name by which each side can identify itself for IPsec
+ negotiations. Its form is a Fully Qualified Domain Name preceded by an
+ @ sign, ie. @road.example.com.
+<BR> It does not need to be within a domain that you own. It can be a
+ made-up name.</LI>
+</UL>
+<H4>Get your leftrsasigkey...</H4>
+<P>On your laptop, print your IPsec public key:</P>
+<PRE> ipsec showhostkey --left</PRE>
+<P>The output should look like this (with the key shortened for easy
+ reading):</P>
+<PRE> # RSA 2192 bits road.example.com Sun Jun 9 02:45:02 2002
+ leftrsasigkey=0sAQPIPN9uI...</PRE>
+<P>Don't have a key? See<A HREF="old_config.html#genrsakey"> these
+ instructions</A>.</P>
+<H4>...and your rightrsasigkey</H4>
+<P>Get a console on the gateway:</P>
+<PRE> ssh2 xy.example.com</PRE>
+<P>View the gateway's public key with:</P>
+<PRE> ipsec showhostkey --right</PRE>
+<P>This will yield something like</P>
+<PRE> # RSA 2048 bits xy.example.com Fri Apr 26 15:01:41 2002
+ rightrsasigkey=0sAQOnwiBPt...</PRE>
+<H3><A NAME="16_3_2">Customize<VAR> /etc/ipsec.conf</VAR></A></H3>
+<P>On your laptop, copy this template to<VAR> /etc/ipsec.conf</VAR>. (on
+ Mandrake,<VAR> /etc/freeswan/ipsec.conf</VAR>). Substitute the
+ information you've gathered for our example data.</P>
+<PRE>conn road
+ left=%defaultroute # Picks up our dynamic IP
+ leftnexthop=%defaultroute #
+ leftid=@road.example.com # Local information
+ leftrsasigkey=0sAQPIPN9uI... #
+ right=192.0.2.10 # Remote information
+ rightsubnet=10.0.0.0/24 #
+ rightid=@xy.example.com #
+ rightrsasigkey=0sAQOnwiBPt... #
+ auto=add # authorizes but doesn't start this
+ # connection at startup</PRE>
+<P>The template for the gateway is different. Notice how it reverses<VAR>
+ left</VAR> and<VAR> right</VAR>, in keeping with our convention that<STRONG>
+ L</STRONG>eft is<STRONG> L</STRONG>ocal,<STRONG> R</STRONG>ight<STRONG>
+ R</STRONG>emote. Be sure to switch your rsasigkeys in keeping with
+ this.</P>
+<PRE> ssh2 xy.example.com
+ vi /etc/ipsec.conf</PRE>
+<P>and add:</P>
+<PRE>conn road
+ left=192.0.2.2 # Gateway's information
+ leftid=@xy.example.com #
+ leftsubnet=192.0.2.128/29 #
+ leftrsasigkey=0sAQOnwiBPt... #
+ rightnexthop=%defaultroute # correct in many situations
+ right=%any # Wildcard: we don't know the laptop's IP
+ rightid=@road.example.com #
+ rightrsasigkey=0sAQPIPN9uI... #
+ auto=add # authorizes but doesn't start this
+ # connection at startup</PRE>
+<H3><A NAME="16_3_3">Start your connection</A></H3>
+<P>You must start the connection from the Road Warrior side. On your
+ laptop, type:</P>
+<PRE> ipsec auto --start net-to-net</PRE>
+<P>You should see:</P>
+<PRE>104 &quot;net-net&quot; #223: STATE_MAIN_I1: initiate
+106 &quot;road&quot; #301: STATE_MAIN_I2: sent MI2, expecting MR2
+108 &quot;road&quot; #301: STATE_MAIN_I3: sent MI3, expecting MR3
+004 &quot;road&quot; #301: STATE_MAIN_I4: ISAKMP SA established
+112 &quot;road&quot; #302: STATE_QUICK_I1: initiate
+004 &quot;road&quot; #302: STATE_QUICK_I2: sent QI2, IPsec SA established</PRE>
+<P>Look for<VAR> IPsec SA established</VAR>. If you're unsuccessful, see
+ our<A HREF="trouble.html#trouble"> troubleshooting tips</A>.</P>
+<H3><A NAME="16_3_4">Do not MASQ or NAT packets to be tunneled</A></H3>
+<P>If you are using<A HREF="glossary.html#masq"> IP masquerade</A> or<A HREF="glossary.html#NAT.gloss">
+ Network Address Translation (NAT)</A> on either gateway, you must now
+ exempt the packets you wish to tunnel from this treatment. For example,
+ if you have a rule like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -j MASQUERADE
+</PRE>
+<P>change it to something like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -d \! 192.0.2.128/29 -j MASQUERADE</PRE>
+<H3><A NAME="16_3_5">Test your connection</A></H3>
+<P>From your laptop, ping a subnet node behind the remote gateway. Do
+ not choose the gateway itself for this test.</P>
+<PRE> ping ns.winston.example.com</PRE>
+<P>Snoop the packets exiting the laptop, with a command like:</P>
+<PRE> tcpdump -i wlan0</PRE>
+<P>You have success if you see (Encapsulating Security Payload) packets
+ travelling<B> in both directions</B>:</P>
+<PRE> 19:16:32.046220 192.0.2.2 &gt; 192.0.2.9: ESP(spi=0x3be6c4dc,seq=0x3)
+ 19:16:32.085630 192.0.2.9 &gt; 192.0.2.2: ESP(spi=0x5fdd1cf8,seq=0x6)</PRE>
+<P>If you do, great! Traffic between your Road Warrior and the net
+ behind your gateway is protected. If not, see our<A HREF="trouble.html#trouble">
+ troubleshooting hints</A>.</P>
+<P>Your new tunnel protects only traffic addressed to the net, not to
+ the IPsec gateway itself. If you need the latter, you'll want to make
+ an<A HREF="adv_config.html#adv_config"> extra tunnel.</A>.</P>
+<H3><A NAME="16_3_6">Finishing touches</A></H3>
+<P>On both ends, name your connection wisely, like:</P>
+<PRE>conn mike-to-office</PRE>
+<P><B>On the laptop only,</B> replace</P>
+<PRE> auto=add</PRE>
+<P>with:</P>
+<PRE> auto=start</PRE>
+<P>so that you'll be connected on-boot.</P>
+<P>Happy telecommuting!</P>
+<H3><A NAME="16_3_7">Multiple Road Warriors</A></H3>
+<P>If you're using RSA keys, as we did in this example, you can add as
+ many Road Warriors as you like. The left/rightid parameter lets Linux
+ FreeS/WAN distinguish between multiple Road Warrior peers, each with
+ its own public key.</P>
+<P>The situation is different for shared secrets (PSK). During a PSK
+ negotiation, ID information is not available at the time Pluto is
+ trying to determine which secret to use, so, effectively, you can only
+ define one Roadwarrior connection. All your PSK road warriors must
+ therefore share one secret.</P>
+<H2><A NAME="16_4">What next?</A></H2>
+<P>Using the principles illustrated here, you can try variations such
+ as:</P>
+<UL>
+<LI>a telecommuter with a static IP</LI>
+<LI>a road warrior with a subnet behind it</LI>
+</UL>
+<P>Or, look at some of our<A HREF="adv_config.html#adv_config"> more
+ complex configuration examples.</A>.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="install.html">Previous</A>
+<A HREF="background.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/draft-richardson-ipsec-opportunistic.txt b/doc/draft-richardson-ipsec-opportunistic.txt
new file mode 100644
index 000000000..4c87d857a
--- /dev/null
+++ b/doc/draft-richardson-ipsec-opportunistic.txt
@@ -0,0 +1,2688 @@
+
+
+Independent submission M. Richardson
+Internet-Draft SSW
+Expires: November 19, 2003 D. Redelmeier
+ Mimosa
+ May 21, 2003
+
+
+ Opportunistic Encryption using The Internet Key Exchange (IKE)
+ draft-richardson-ipsec-opportunistic-11.txt
+
+Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of RFC2026.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working groups. Note that
+ other groups may also distribute working documents as Internet-
+ Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at http://
+ www.ietf.org/ietf/1id-abstracts.txt.
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ This Internet-Draft will expire on November 19, 2003.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+Abstract
+
+ This document describes opportunistic encryption (OE) using the
+ Internet Key Exchange (IKE) and IPsec. Each system administrator
+ adds new resource records to his or her Domain Name System (DNS) to
+ support opportunistic encryption. The objective is to allow
+ encryption for secure communication without any pre-arrangement
+ specific to the pair of systems involved.
+
+ DNS is used to distribute the public keys of each system involved.
+ This is resistant to passive attacks. The use of DNS Security
+ (DNSSEC) secures this system against active attackers as well.
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 1]
+
+Internet-Draft opportunistic May 2003
+
+
+ As a result, the administrative overhead is reduced from the square
+ of the number of systems to a linear dependence, and it becomes
+ possible to make secure communication the default even when the
+ partner is not known in advance.
+
+ This document is offered up as an Informational RFC.
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 3. Specification . . . . . . . . . . . . . . . . . . . . . . . . 10
+ 4. Impacts on IKE . . . . . . . . . . . . . . . . . . . . . . . . 21
+ 5. DNS issues . . . . . . . . . . . . . . . . . . . . . . . . . . 24
+ 6. Network address translation interaction . . . . . . . . . . . 28
+ 7. Host implementations . . . . . . . . . . . . . . . . . . . . . 29
+ 8. Multi-homing . . . . . . . . . . . . . . . . . . . . . . . . . 30
+ 9. Failure modes . . . . . . . . . . . . . . . . . . . . . . . . 32
+ 10. Unresolved issues . . . . . . . . . . . . . . . . . . . . . . 34
+ 11. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
+ 12. Security considerations . . . . . . . . . . . . . . . . . . . 42
+ 13. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 44
+ 14. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 45
+ Normative references . . . . . . . . . . . . . . . . . . . . . 46
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 47
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . . 48
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 2]
+
+Internet-Draft opportunistic May 2003
+
+
+1. Introduction
+
+1.1 Motivation
+
+ The objective of opportunistic encryption is to allow encryption
+ without any pre-arrangement specific to the pair of systems involved.
+ Each system administrator adds public key information to DNS records
+ to support opportunistic encryption and then enables this feature in
+ the nodes' IPsec stack. Once this is done, any two such nodes can
+ communicate securely.
+
+ This document describes opportunistic encryption as designed and
+ mostly implemented by the Linux FreeS/WAN project. For project
+ information, see http://www.freeswan.org.
+
+ The Internet Architecture Board (IAB) and Internet Engineering
+ Steering Group (IESG) have taken a strong stand that the Internet
+ should use powerful encryption to provide security and privacy [4].
+ The Linux FreeS/WAN project attempts to provide a practical means to
+ implement this policy.
+
+ The project uses the IPsec, ISAKMP/IKE, DNS and DNSSEC protocols
+ because they are standardized, widely available and can often be
+ deployed very easily without changing hardware or software or
+ retraining users.
+
+ The extensions to support opportunistic encryption are simple. No
+ changes to any on-the-wire formats are needed. The only changes are
+ to the policy decision making system. This means that opportunistic
+ encryption can be implemented with very minimal changes to an
+ existing IPsec implementation.
+
+ Opportunistic encryption creates a "fax effect". The proliferation
+ of the fax machine was possible because it did not require that
+ everyone buy one overnight. Instead, as each person installed one,
+ the value of having one increased - as there were more people that
+ could receive faxes. Once opportunistic encryption is installed it
+ automatically recognizes other boxes using opportunistic encryption,
+ without any further configuration by the network administrator. So,
+ as opportunistic encryption software is installed on more boxes, its
+ value as a tool increases.
+
+ This document describes the infrastructure to permit deployment of
+ Opportunistic Encryption.
+
+ The term S/WAN is a trademark of RSA Data Systems, and is used with
+ permission by this project.
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 3]
+
+Internet-Draft opportunistic May 2003
+
+
+1.2 Types of network traffic
+
+ To aid in understanding the relationship between security processing
+ and IPsec we divide network traffic into four categories:
+
+ * Deny: networks to which traffic is always forbidden.
+
+ * Permit: networks to which traffic in the clear is permitted.
+
+ * Opportunistic tunnel: networks to which traffic is encrypted if
+ possible, but otherwise is in the clear or fails depending on the
+ default policy in place.
+
+ * Configured tunnel: networks to which traffic must be encrypted, and
+ traffic in the clear is never permitted.
+
+ Traditional firewall devices handle the first two categories. No
+ authentication is required. The permit policy is currently the
+ default on the Internet.
+
+ This document describes the third category - opportunistic tunnel,
+ which is proposed as the new default for the Internet.
+
+ Category four, encrypt traffic or drop it, requires authentication of
+ the end points. As the number of end points is typically bounded and
+ is typically under a single authority, arranging for distribution of
+ authentication material, while difficult, does not require any new
+ technology. The mechanism described here provides an additional way
+ to distribute the authentication materials, that of a public key
+ method that does not require deployment of an X.509 based
+ infrastructure.
+
+ Current Virtual Private Networks can often be replaced by an "OE
+ paranoid" policy as described herein.
+
+1.3 Peer authentication in opportunistic encryption
+
+ Opportunistic encryption creates tunnels between nodes that are
+ essentially strangers. This is done without any prior bilateral
+ arrangement. There is, therefore, the difficult question of how one
+ knows to whom one is talking.
+
+ One possible answer is that since no useful authentication can be
+ done, none should be tried. This mode of operation is named
+ "anonymous encryption". An active man-in-the-middle attack can be
+ used to thwart the privacy of this type of communication. Without
+ peer authentication, there is no way to prevent this kind of attack.
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 4]
+
+Internet-Draft opportunistic May 2003
+
+
+ Although a useful mode, anonymous encryption is not the goal of this
+ project. Simpler methods are available that can achieve anonymous
+ encryption only, but authentication of the peer is a desireable goal.
+ The latter is achieved through key distribution in DNS, leveraging
+ upon the authentication of the DNS in DNSSEC.
+
+ Peers are, therefore, authenticated with DNSSEC when available.
+ Local policy determines how much trust to extend when DNSSEC is not
+ available.
+
+ However, an essential premise of building private connections with
+ strangers is that datagrams received through opportunistic tunnels
+ are no more special than datagrams that arrive in the clear. Unlike
+ in a VPN, these datagrams should not be given any special exceptions
+ when it comes to auditing, further authentication or firewalling.
+
+ When initiating outbound opportunistic encryption, local
+ configuration determines what happens if tunnel setup fails. It may
+ be that the packet goes out in the clear, or it may be dropped.
+
+1.4 Use of RFC2119 terms
+
+ The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD,
+ SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this
+ document, are to be interpreted as described in [5]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 5]
+
+Internet-Draft opportunistic May 2003
+
+
+2. Overview
+
+2.1 Reference diagram
+
+ ---------------------------------------------------------------------
+
+ The following network diagram is used in the rest of this document as
+ the canonical diagram:
+
+ [Q] [R]
+ . . AS2
+ [A]----+----[SG-A].......+....+.......[SG-B]-------[B]
+ | ......
+ AS1 | ..PI..
+ | ......
+ [D]----+----[SG-D].......+....+.......[C] AS3
+
+
+
+ Figure 1: Reference Network Diagram
+
+ ---------------------------------------------------------------------
+
+ In this diagram, there are four end-nodes: A, B, C and D. There are
+ three gateways, SG-A, SG-B, SG-D. A, D, SG-A and SG-D are part of
+ the same administrative authority, AS1. SG-A and SG-D are on two
+ different exit paths from organization 1. SG-B/B is an independent
+ organization, AS2. Nodes Q and R are nodes on the Internet. PI is
+ the Public Internet ("The Wild").
+
+2.2 Terminology
+
+ The following terminology is used in this document:
+
+ Security gateway: a system that performs IPsec tunnel mode
+ encapsulation/decapsulation. [SG-x] in the diagram.
+
+ Alice: node [A] in the diagram. When an IP address is needed, this
+ is 192.1.0.65.
+
+ Bob: node [B] in the diagram. When an IP address is needed, this is
+ 192.2.0.66.
+
+ Carol: node [C] in the diagram. When an IP address is needed, this
+ is 192.1.1.67.
+
+ Dave: node [D] in the diagram. When an IP address is needed, this is
+ 192.3.0.68.
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 6]
+
+Internet-Draft opportunistic May 2003
+
+
+ SG-A: Alice's security gateway. Internally it is 192.1.0.1,
+ externally it is 192.1.1.4.
+
+ SG-B: Bob's security gateway. Internally it is 192.2.0.1, externally
+ it is 192.1.1.5.
+
+ SG-D: Dave's security gateway. Also Alice's backup security gateway.
+ Internally it is 192.3.0.1, externally it is 192.1.1.6.
+
+ - A single dash represents clear-text datagrams.
+
+ = An equals sign represents phase 2 (IPsec) cipher-text datagrams.
+
+ ~ A single tilde represents clear-text phase 1 datagrams.
+
+ # A hash sign represents phase 1 (IKE) cipher-text datagrams.
+
+ . A period represents an untrusted network of unknown type.
+
+ Configured tunnel: a tunnel that is directly and deliberately hand
+ configured on participating gateways. Configured tunnels are
+ typically given a higher level of trust than opportunistic
+ tunnels.
+
+ Road warrior tunnel: a configured tunnel connecting one node with a
+ fixed IP address and one node with a variable IP address. A road
+ warrior (RW) connection must be initiated by the variable node,
+ since the fixed node cannot know the current address for the road
+ warrior.
+
+ Anonymous encryption: the process of encrypting a session without any
+ knowledge of who the other parties are. No authentication of
+ identities is done.
+
+ Opportunistic encryption: the process of encrypting a session with
+ authenticated knowledge of who the other parties are.
+
+ Lifetime: the period in seconds (bytes or datagrams) for which a
+ security association will remain alive before needing to be re-
+ keyed.
+
+ Lifespan: the effective time for which a security association remains
+ useful. A security association with a lifespan shorter than its
+ lifetime would be removed when no longer needed. A security
+ association with a lifespan longer than its lifetime would need to
+ be re-keyed one or more times.
+
+ Phase 1 SA: an ISAKMP/IKE security association sometimes referred to
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 7]
+
+Internet-Draft opportunistic May 2003
+
+
+ as a keying channel.
+
+ Phase 2 SA: an IPsec security association.
+
+ Tunnel: another term for a set of phase 2 SA (one in each direction).
+
+ NAT: Network Address Translation (see [20]).
+
+ NAPT: Network Address and Port Translation (see [20]).
+
+ AS: an autonomous system (AS) is a group of systems (a network) that
+ are under the administrative control of a single organization.
+
+ Default-free zone: a set of routers that maintain a complete set of
+ routes to all currently reachable destinations. Having such a
+ list, these routers never make use of a default route. A datagram
+ with a destination address not matching any route will be dropped
+ by such a router.
+
+
+2.3 Model of operation
+
+ The opportunistic encryption security gateway (OE gateway) is a
+ regular gateway node as described in [2] section 2.4 and [3] with the
+ additional capabilities described here and in [7]. The algorithm
+ described here provides a way to determine, for each datagram,
+ whether or not to encrypt and tunnel the datagram. Two important
+ things that must be determined are whether or not to encrypt and
+ tunnel and, if so, the destination address or name of the tunnel end
+ point which should be used.
+
+2.3.1 Tunnel authorization
+
+ The OE gateway determines whether or not to create a tunnel based on
+ the destination address of each packet. Upon receiving a packet with
+ a destination address not recently seen, the OE gateway performs a
+ lookup in DNS for an authorization resource record (see Section 5.2).
+ The record is located using the IP address to perform a search in the
+ in-addr.arpa (IPv4) or ip6.arpa (IPv6) maps. If an authorization
+ record is found, the OE gateway interprets this as a request for a
+ tunnel to be formed.
+
+2.3.2 Tunnel end-point discovery
+
+ The authorization resource record also provides the address or name
+ of the tunnel end point which should be used.
+
+ The record may also provide the public RSA key of the tunnel end
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 8]
+
+Internet-Draft opportunistic May 2003
+
+
+ point itself. This is provided for efficiency only. If the public
+ RSA key is not present, the OE gateway performs a second lookup to
+ find a KEY resource record for the end point address or name.
+
+ Origin and integrity protection of the resource records is provided
+ by DNSSEC ([16]). Section 3.2.4.1 documents an optional restriction
+ on the tunnel end point if DNSSEC signatures are not available for
+ the relevant records.
+
+2.3.3 Caching of authorization results
+
+ The OE gateway maintains a cache, in the forwarding plane, of source/
+ destination pairs for which opportunistic encryption has been
+ attempted. This cache maintains a record of whether or not OE was
+ successful so that subsequent datagrams can be forwarded properly
+ without additional delay.
+
+ Successful negotiation of OE instantiates a new security association.
+ Failure to negotiate OE results in creation of a forwarding policy
+ entry either to drop or transmit in the clear future datagrams. This
+ negative cache is necessary to avoid the possibly lengthy process of
+ repeatedly looking up the same information.
+
+ The cache is timed out periodically, as described in Section 3.4.
+ This removes entries that are no longer being used and permits the
+ discovery of changes in authorization policy.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 9]
+
+Internet-Draft opportunistic May 2003
+
+
+3. Specification
+
+ The OE gateway is modeled to have a forwarding plane and a control
+ plane. A control channel, such as PF_KEY, connects the two planes.
+ (See [6].) The forwarding plane performs per datagram operations.
+ The control plane contains a keying daemon, such as ISAKMP/IKE, and
+ performs all authorization, peer authentication and key derivation
+ functions.
+
+3.1 Datagram state machine
+
+ Let the OE gateway maintain a collection of objects -- a superset of
+ the security policy database (SPD) specified in [7]. For each
+ combination of source and destination address, an SPD object exists
+ in one of five following states. Prior to forwarding each datagram,
+ the responder uses the source and destination addresses to pick an
+ entry from the SPD. The SPD then determines if and how the packet is
+ forwarded.
+
+3.1.1 Non-existent policy
+
+ If the responder does not find an entry, then this policy applies.
+ The responder creates an entry with an initial state of "hold policy"
+ and requests keying material from the keying daemon. The responder
+ does not forward the datagram, rather it attaches the datagram to the
+ SPD entry as the "first" datagram and retains it for eventual
+ transmission in a new state.
+
+3.1.2 Hold policy
+
+ The responder requests keying material. If the interface to the
+ keying system is lossy (PF_KEY, for instance, can be), the
+ implementation SHOULD include a mechanism to retransmit the keying
+ request at a rate limited to less than 1 request per second. The
+ responder does not forward the datagram. It attaches the datagram to
+ the SPD entry as the "last" datagram where it is retained for
+ eventual transmission. If there is a datagram already so stored,
+ then that already stored datagram is discarded.
+
+ Because the "first" datagram is probably a TCP SYN packet, the
+ responder retains the "first" datagram in an attempt to avoid waiting
+ for a TCP retransmit. The responder retains the "last" datagram in
+ deference to streaming protocols that find it useful to know how much
+ data has been lost. These are recommendations to decrease latency.
+ There are no operational requirements for this.
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 10]
+
+Internet-Draft opportunistic May 2003
+
+
+3.1.3 Pass-through policy
+
+ The responder forwards the datagram using the normal forwarding
+ table. The responder enters this state only by command from the
+ keying daemon, and upon entering this state, also forwards the
+ "first" and "last" datagrams.
+
+3.1.4 Deny policy
+
+ The responder discards the datagram. The responder enters this state
+ only by command from the keying daemon, and upon entering this state,
+ discards the "first" and "last" datagrams. Local administration
+ decides if further datagrams cause ICMP messages to be generated
+ (i.e. ICMP Destination Unreachable, Communication Administratively
+ Prohibited. type=3, code=13).
+
+3.1.5 Encrypt policy
+
+ The responder encrypts the datagram using the indicated security
+ association database (SAD) entry. The responder enters this state
+ only by command from the keying daemon, and upon entering this state,
+ releases and forwards the "first" and "last" datagrams using the new
+ encrypt policy.
+
+ If the associated SAD entry expires because of byte, packet or time
+ limits, then the entry returns to the Hold policy, and an expire
+ message is sent to the keying daemon.
+
+ All states may be created directly by the keying daemon while acting
+ as a responder.
+
+3.2 Keying state machine - initiator
+
+ Let the keying daemon maintain a collection of objects. Let them be
+ called "connections" or "conn"s. There are two categories of
+ connection objects: classes and instances. A class represents an
+ abstract policy - what could be. An instance represents an actual
+ connection - what is implemented at the time.
+
+ Let there be two further subtypes of connections: keying channels
+ (Phase 1 SAs) and data channels (Phase 2 SAs). Each data channel
+ object may have a corresponding SPD and SAD entry maintained by the
+ datagram state machine.
+
+ For the purposes of opportunistic encryption, there MUST, at least,
+ be connection classes known as "deny", "always-clear-text", "OE-
+ permissive", and "OE-paranoid". The latter two connection classes
+ define a set of source and/or destination addresses for which
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 11]
+
+Internet-Draft opportunistic May 2003
+
+
+ opportunistic encryption will be attempted. The administrator MAY
+ set policy options in a number of additional places. An
+ implementation MAY create additional connection classes to further
+ refine these policies.
+
+ The simplest system may need only the "OE-permissive" connection, and
+ would list its own (single) IP address as the source address of this
+ policy and the wild-card address 0.0.0.0/0 as the destination IPv4
+ address. That is, the simplest policy is to try opportunistic
+ encryption with all destinations.
+
+ The distinction between permissive and paranoid OE use will become
+ clear in the state transition differences. In general a permissive
+ OE will, on failure, install a pass-through policy, while a paranoid
+ OE will, on failure, install a drop policy.
+
+ In this description of the keying machine's state transitions, the
+ states associated with the keying system itself are omitted because
+ they are best documented in the keying system ([8], [9] and [10] for
+ ISAKMP/IKE), and the details are keying system specific.
+ Opportunistic encryption is not dependent upon any specific keying
+ protocol, but this document does provide requirements for those using
+ ISAKMP/IKE to assure that implementations inter-operate.
+
+ The state transitions that may be involved in communicating with the
+ forwarding plane are omitted. PF_KEY and similar protocols have
+ their own set of states required for message sends and completion
+ notifications.
+
+ Finally, the retransmits and recursive lookups that are normal for
+ DNS are not included in this description of the state machine.
+
+3.2.1 Nonexistent connection
+
+ There is no connection instance for a given source/destination
+ address pair. Upon receipt of a request for keying material for this
+ source/destination pair, the initiator searches through the
+ connection classes to determine the most appropriate policy. Upon
+ determining an appropriate connection class, an instance object is
+ created of that type. Both of the OE types result in a potential OE
+ connection.
+
+ Failure to find an appropriate connection class results in an
+ administrator defined default.
+
+ In each case, when the initiator finds an appropriate class for the
+ new flow, an instance connection is made of the class which matched.
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 12]
+
+Internet-Draft opportunistic May 2003
+
+
+3.2.2 Clear-text connection
+
+ The non-existent connection makes a transition to this state when an
+ always-clear-text class is instantiated, or when an OE-permissive
+ connection fails. During the transition, the initiator creates a
+ pass-through policy object in the forwarding plane for the
+ appropriate flow.
+
+ Timing out is the only way to leave this state (see Section 3.2.7).
+
+3.2.3 Deny connection
+
+ The empty connection makes a transition to this state when a deny
+ class is instantiated, or when an OE-paranoid connection fails.
+ During the transition, the initiator creates a deny policy object in
+ the forwarding plane for the appropriate flow.
+
+ Timing out is the only way to leave this state (see Section 3.2.7).
+
+3.2.4 Potential OE connection
+
+ The empty connection makes a transition to this state when one of
+ either OE class is instantiated. During the transition to this
+ state, the initiator creates a hold policy object in the forwarding
+ plane for the appropriate flow.
+
+ In addition, when making a transition into this state, DNS lookup is
+ done in the reverse-map for a TXT delegation resource record (see
+ Section 5.2). The lookup key is the destination address of the flow.
+
+ There are three ways to exit this state:
+
+ 1. DNS lookup finds a TXT delegation resource record.
+
+ 2. DNS lookup does not find a TXT delegation resource record.
+
+ 3. DNS lookup times out.
+
+ Based upon the results of the DNS lookup, the potential OE connection
+ makes a transition to the pending OE connection state. The
+ conditions for a successful DNS look are:
+
+ 1. DNS finds an appropriate resource record
+
+ 2. It is properly formatted according to Section 5.2
+
+ 3. if DNSSEC is enabled, then the signature has been vouched for.
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 13]
+
+Internet-Draft opportunistic May 2003
+
+
+ Note that if the initiator does not find the public key present in
+ the TXT delegation record, then the public key must be looked up as a
+ sub-state. Only successful completion of all the DNS lookups is
+ considered a success.
+
+ If DNS lookup does not find a resource record or DNS times out, then
+ the initiator considers the receiver not OE capable. If this is an
+ OE-paranoid instance, then the potential OE connection makes a
+ transition to the deny connection state. If this is an OE-permissive
+ instance, then the potential OE connection makes a transition to the
+ clear-text connection state.
+
+ If the initiator finds a resource record but it is not properly
+ formatted, or if DNSSEC is enabled and reports a failure to
+ authenticate, then the potential OE connection should make a
+ transition to the deny connection state. This action SHOULD be
+ logged. If the administrator wishes to override this transition
+ between states, then an always-clear class can be installed for this
+ flow. An implementation MAY make this situation a new class.
+
+3.2.4.1 Restriction on unauthenticated TXT delegation records
+
+ An implementation SHOULD also provide an additional administrative
+ control on delegation records and DNSSEC. This control would apply
+ to delegation records (the TXT records in the reverse-map) that are
+ not protected by DNSSEC. Records of this type are only permitted to
+ delegate to their own address as a gateway. When this option is
+ enabled, an active attack on DNS will be unable to redirect packets
+ to other than the original destination.
+
+3.2.5 Pending OE connection
+
+ The potential OE connection makes a transition to this state when the
+ initiator determines that all the information required from the DNS
+ lookup is present. Upon entering this state, the initiator attempts
+ to initiate keying to the gateway provided.
+
+ Exit from this state occurs either with a successfully created IPsec
+ SA, or with a failure of some kind. Successful SA creation results
+ in a transition to the key connection state.
+
+ Three failures have caused significant problems. They are clearly
+ not the only possible failures from keying.
+
+ Note that if there are multiple gateways available in the TXT
+ delegation records, then a failure can only be declared after all
+ have been tried. Further, creation of a phase 1 SA does not
+ constitute success. A set of phase 2 SAs (a tunnel) is considered
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 14]
+
+Internet-Draft opportunistic May 2003
+
+
+ success.
+
+ The first failure occurs when an ICMP port unreachable is
+ consistently received without any other communication, or when there
+ is silence from the remote end. This usually means that either the
+ gateway is not alive, or the keying daemon is not functional. For an
+ OE-permissive connection, the initiator makes a transition to the
+ clear-text connection but with a low lifespan. For an OE-pessimistic
+ connection, the initiator makes a transition to the deny connection
+ again with a low lifespan. The lifespan in both cases is kept low
+ because the remote gateway may be in the process of rebooting or be
+ otherwise temporarily unavailable.
+
+ The length of time to wait for the remote keying daemon to wake up is
+ a matter of some debate. If there is a routing failure, 5 minutes is
+ usually long enough for the network to re-converge. Many systems can
+ reboot in that amount of time as well. However, 5 minutes is far too
+ long for most users to wait to hear that they can not connect using
+ OE. Implementations SHOULD make this a tunable parameter.
+
+ The second failure occurs after a phase 1 SA has been created, but
+ there is either no response to the phase 2 proposal, or the initiator
+ receives a negative notify (the notify must be authenticated). The
+ remote gateway is not prepared to do OE at this time. As before, the
+ initiator makes a transition to the clear-text or the deny connection
+ based upon connection class, but this time with a normal lifespan.
+
+ The third failure occurs when there is signature failure while
+ authenticating the remote gateway. This can occur when there has
+ been a key roll-over, but DNS has not caught up. In this case again,
+ the initiator makes a transition to the clear-text or the deny
+ connection based upon the connection class. However, the lifespan
+ depends upon the remaining time to live in the DNS. (Note that
+ DNSSEC signed resource records have a different expiry time than non-
+ signed records.)
+
+3.2.6 Keyed connection
+
+ The pending OE connection makes a transition to this state when
+ session keying material (the phase 2 SAs) is derived. The initiator
+ creates an encrypt policy in the forwarding plane for this flow.
+
+ There are three ways to exit this state. The first is by receipt of
+ an authenticated delete message (via the keying channel) from the
+ peer. This is normal teardown and results in a transition to the
+ expired connection state.
+
+ The second exit is by expiry of the forwarding plane keying material.
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 15]
+
+Internet-Draft opportunistic May 2003
+
+
+ This starts a re-key operation with a transition back to pending OE
+ connection. In general, the soft expiry occurs with sufficient time
+ left to continue to use the keys. A re-key can fail, which may
+ result in the connection failing to clear-text or deny as
+ appropriate. In the event of a failure, the forwarding plane policy
+ does not change until the phase 2 SA (IPsec SA) reaches its hard
+ expiry.
+
+ The third exit is in response to a negotiation from a remote gateway.
+ If the forwarding plane signals the control plane that it has
+ received an unknown SPI from the remote gateway, or an ICMP is
+ received from the remote gateway indicating an unknown SPI, the
+ initiator should consider that the remote gateway has rebooted or
+ restarted. Since these indications are easily forged, the
+ implementation must exercise care. The initiator should make a
+ cautious (rate-limited) attempt to re-key the connection.
+
+3.2.7 Expiring connection
+
+ The initiator will periodically place each of the deny, clear-text,
+ and keyed connections into this sub-state. See Section 3.4 for more
+ details of how often this occurs. The initiator queries the
+ forwarding plane for last use time of the appropriate policy. If the
+ last use time is relatively recent, then the connection returns to
+ the previous deny, clear-text or keyed connection state. If not,
+ then the connection enters the expired connection state.
+
+ The DNS query and answer that lead to the expiring connection state
+ are also examined. The DNS query may become stale. (A negative,
+ i.e. no such record, answer is valid for the period of time given by
+ the MINIMUM field in an attached SOA record. See [12] section
+ 4.3.4.) If the DNS query is stale, then a new query is made. If the
+ results change, then the connection makes a transition to a new state
+ as described in potential OE connection state.
+
+ Note that when considering how stale a connection is, both outgoing
+ SPD and incoming SAD must be queried as some flows may be
+ unidirectional for some time.
+
+ Also note that the policy at the forwarding plane is not updated
+ unless there is a conclusion that there should be a change.
+
+3.2.8 Expired connection
+
+ Entry to this state occurs when no datagrams have been forwarded
+ recently via the appropriate SPD and SAD objects. The objects in the
+ forwarding plane are removed (logging any final byte and packet
+ counts if appropriate) and the connection instance in the keying
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 16]
+
+Internet-Draft opportunistic May 2003
+
+
+ plane is deleted.
+
+ The initiator sends an ISAKMP/IKE delete to clean up the phase 2 SAs
+ as described in Section 3.4.
+
+ Whether or not to delete the phase 1 SAs at this time is left as a
+ local implementation issue. Implementations that do delete the phase
+ 1 SAs MUST send authenticated delete messages to indicate that they
+ are doing so. There is an advantage to keeping the phase 1 SAs until
+ they expire - they may prove useful again in the near future.
+
+3.3 Keying state machine - responder
+
+ The responder has a set of objects identical to those of the
+ initiator.
+
+ The responder receives an invitation to create a keying channel from
+ an initiator.
+
+3.3.1 Unauthenticated OE peer
+
+ Upon entering this state, the responder starts a DNS lookup for a KEY
+ record for the initiator. The responder looks in the reverse-map for
+ a KEY record for the initiator if the initiator has offered an
+ ID_IPV4_ADDR, and in the forward map if the initiator has offered an
+ ID_FQDN type. (See [8] section 4.6.2.1.)
+
+ The responder exits this state upon successful receipt of a KEY from
+ DNS, and use of the key to verify the signature of the initiator.
+
+ Successful authentication of the peer results in a transition to the
+ authenticated OE Peer state.
+
+ Note that the unauthenticated OE peer state generally occurs in the
+ middle of the key negotiation protocol. It is really a form of
+ pseudo-state.
+
+3.3.2 Authenticated OE Peer
+
+ The peer will eventually propose one or more phase 2 SAs. The
+ responder uses the source and destination address in the proposal to
+ finish instantiating the connection state using the connection class
+ table. The responder MUST search for an identical connection object
+ at this point.
+
+ If an identical connection is found, then the responder deletes the
+ old instance, and the new object makes a transition to the pending OE
+ connection state. This means that new ISAKMP connections with a
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 17]
+
+Internet-Draft opportunistic May 2003
+
+
+ given peer will always use the latest instance, which is the correct
+ one if the peer has rebooted in the interim.
+
+ If an identical connection is not found, then the responder makes the
+ transition according to the rules given for the initiator.
+
+ Note that if the initiator is in OE-paranoid mode and the responder
+ is in either always-clear-text or deny, then no communication is
+ possible according to policy. An implementation is permitted to
+ create new types of policies such as "accept OE but do not initiate
+ it". This is a local matter.
+
+3.4 Renewal and teardown
+
+3.4.1 Aging
+
+ A potentially unlimited number of tunnels may exist. In practice,
+ only a few tunnels are used during a period of time. Unused tunnels
+ MUST, therefore, be torn down. Detecting when tunnels are no longer
+ in use is the subject of this section.
+
+ There are two methods for removing tunnels: explicit deletion or
+ expiry.
+
+ Explicit deletion requires an IKE delete message. As the deletes
+ MUST be authenticated, both ends of the tunnel must maintain the key
+ channel (phase 1 ISAKMP SA). An implementation which refuses to
+ either maintain or recreate the keying channel SA will be unable to
+ use this method.
+
+ The tunnel expiry method, simply allows the IKE daemon to expire
+ normally without attempting to re-key it.
+
+ Regardless of which method is used to remove tunnels, the
+ implementation requires a method to determine if the tunnel is still
+ in use. The specifics are a local matter, but the FreeS/WAN project
+ uses the following criteria. These criteria are currently
+ implemented in the key management daemon, but could also be
+ implemented at the SPD layer using an idle timer.
+
+ Set a short initial (soft) lifespan of 1 minute since many net flows
+ last only a few seconds.
+
+ At the end of the lifespan, check to see if the tunnel was used by
+ traffic in either direction during the last 30 seconds. If so,
+ assign a longer tentative lifespan of 20 minutes after which, look
+ again. If the tunnel is not in use, then close the tunnel.
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 18]
+
+Internet-Draft opportunistic May 2003
+
+
+ The expiring state in the key management system (see Section 3.2.7)
+ implements these timeouts. The timer above may be in the forwarding
+ plane, but then it must be re-settable.
+
+ The tentative lifespan is independent of re-keying; it is just the
+ time when the tunnel's future is next considered. (The term lifespan
+ is used here rather than lifetime for this reason.) Unlike re-keying,
+ this tunnel use check is not costly and should happen reasonably
+ frequently.
+
+ A multi-step back-off algorithm is not considered worth the effort
+ here.
+
+ If the security gateway and the client host are the same and not a
+ Bump-in-the-Stack or Bump-in-the-Wire implementation, tunnel teardown
+ decisions MAY pay attention to TCP connection status as reported by
+ the local TCP layer. A still-open TCP connection is almost a
+ guarantee that more traffic is expected. Closing of the only TCP
+ connection through a tunnel is a strong hint that no more traffic is
+ expected.
+
+3.4.2 Teardown and cleanup
+
+ Teardown should always be coordinated between the two ends of the
+ tunnel by interpreting and sending delete notifications. There is a
+ detailed sub-state in the expired connection state of the key manager
+ that relates to retransmits of the delete notifications, but this is
+ considered to be a keying system detail.
+
+ On receiving a delete for the outbound SAs of a tunnel (or some
+ subset of them), tear down the inbound ones also and notify the
+ remote end with a delete. If the local system receives a delete for
+ a tunnel which is no longer in existence, then two delete messages
+ have crossed paths. Ignore the delete. The operation has already
+ been completed. Do not generate any messages in this situation.
+
+ Tunnels are to be considered as bidirectional entities, even though
+ the low-level protocols don't treat them this way.
+
+ When the deletion is initiated locally, rather than as a response to
+ a received delete, send a delete for (all) the inbound SAs of a
+ tunnel. If the local system does not receive a responding delete for
+ the outbound SAs, try re-sending the original delete. Three tries
+ spaced 10 seconds apart seems a reasonable level of effort. A
+ failure of the other end to respond after 3 attempts, indicates that
+ the possibility of further communication is unlikely. Remove the
+ outgoing SAs. (The remote system may be a mobile node that is no
+ longer present or powered on.)
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 19]
+
+Internet-Draft opportunistic May 2003
+
+
+ After re-keying, transmission should switch to using the new outgoing
+ SAs (ISAKMP or IPsec) immediately, and the old leftover outgoing SAs
+ should be cleared out promptly (delete should be sent for the
+ outgoing SAs) rather than waiting for them to expire. This reduces
+ clutter and minimizes confusion for the operator doing diagnostics.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 20]
+
+Internet-Draft opportunistic May 2003
+
+
+4. Impacts on IKE
+
+4.1 ISAKMP/IKE protocol
+
+ The IKE wire protocol needs no modifications. The major changes are
+ implementation issues relating to how the proposals are interpreted,
+ and from whom they may come.
+
+ As opportunistic encryption is designed to be useful between peers
+ without prior operator configuration, an IKE daemon must be prepared
+ to negotiate phase 1 SAs with any node. This may require a large
+ amount of resources to maintain cookie state, as well as large
+ amounts of entropy for nonces, cookies and so on.
+
+ The major changes to support opportunistic encryption are at the IKE
+ daemon level. These changes relate to handling of key acquisition
+ requests, lookup of public keys and TXT records, and interactions
+ with firewalls and other security facilities that may be co-resident
+ on the same gateway.
+
+4.2 Gateway discovery process
+
+ In a typical configured tunnel, the address of SG-B is provided via
+ configuration. Furthermore, the mapping of an SPD entry to a gateway
+ is typically a 1:1 mapping. When the 0.0.0.0/0 SPD entry technique
+ is used, then the mapping to a gateway is determined by the reverse
+ DNS records.
+
+ The need to do a DNS lookup and wait for a reply will typically
+ introduce a new state and a new event source (DNS replies) to IKE.
+ Although a synchronous DNS request can be implemented for proof of
+ concept, experience is that it can cause very high latencies when a
+ queue of queries must all timeout in series.
+
+ Use of an asynchronous DNS lookup will also permit overlap of DNS
+ lookups with some of the protocol steps.
+
+4.3 Self identification
+
+ SG-A will have to establish its identity. Use an IPv4 ID in phase 1.
+
+ There are many situations where the administrator of SG-A may not be
+ able to control the reverse DNS records for SG-A's public IP address.
+ Typical situations include dialup connections and most residential-
+ type broadband Internet access (ADSL, cable-modem) connections. In
+ these situations, a fully qualified domain name that is under the
+ control of SG-A's administrator may be used when acting as an
+ initiator only. The FQDN ID should be used in phase 1. See Section
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 21]
+
+Internet-Draft opportunistic May 2003
+
+
+ 5.3 for more details and restrictions.
+
+4.4 Public key retrieval process
+
+ Upon receipt of a phase 1 SA proposal with either an IPv4 (IPv6) ID
+ or an FQDN ID, an IKE daemon needs to examine local caches and
+ configuration files to determine if this is part of a configured
+ tunnel. If no configured tunnels are found, then the implementation
+ should attempt to retrieve a KEY record from the reverse DNS in the
+ case of an IPv4/IPv6 ID, or from the forward DNS in the case of FQDN
+ ID.
+
+ It is reasonable that if other non-local sources of policy are used
+ (COPS, LDAP), they be consulted concurrently but some clear ordering
+ of policy be provided. Note that due to variances in latency,
+ implementations must wait for positive or negative replies from all
+ sources of policy before making any decisions.
+
+4.5 Interactions with DNSSEC
+
+ The implementation described (1.98) neither uses DNSSEC directly to
+ explicitly verify the authenticity of zone information, nor uses the
+ NXT records to provide authentication of the absence of a TXT or KEY
+ record. Rather, this implementation uses a trusted path to a DNSSEC
+ capable caching resolver.
+
+ To distinguish between an authenticated and an unauthenticated DNS
+ resource record, a stub resolver capable of returning DNSSEC
+ information MUST be used.
+
+4.6 Required proposal types
+
+4.6.1 Phase 1 parameters
+
+ Main mode MUST be used.
+
+ The initiator MUST offer at least one proposal using some combination
+ of: 3DES, HMAC-MD5 or HMAC-SHA1, DH group 2 or 5. Group 5 SHOULD be
+ proposed first. [11]
+
+ The initiator MAY offer additional proposals, but the cipher MUST not
+ be weaker than 3DES. The initiator SHOULD limit the number of
+ proposals such that the IKE datagrams do not need to be fragmented.
+
+ The responder MUST accept one of the proposals. If any configuration
+ of the responder is required then the responder is not acting in an
+ opportunistic way.
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 22]
+
+Internet-Draft opportunistic May 2003
+
+
+ SG-A SHOULD use an ID_IPV4_ADDR (ID_IPV6_ADDR for IPv6) of the
+ external interface of SG-A for phase 1. (There is an exception, see
+ Section 5.3.) The authentication method MUST be RSA public key
+ signatures. The RSA key for SG-A SHOULD be placed into a DNS KEY
+ record in the reverse space of SG-A (i.e. using in-addr.arpa).
+
+4.6.2 Phase 2 parameters
+
+ SG-A MUST propose a tunnel between Alice and Bob, using 3DES-CBC
+ mode, MD5 or SHA1 authentication. Perfect Forward Secrecy MUST be
+ specified.
+
+ Tunnel mode MUST be used.
+
+ Identities MUST be ID_IPV4_ADDR_SUBNET with the mask being /32.
+
+ Authorization for SG-A to act on Alice's behalf is determined by
+ looking for a TXT record in the reverse-map at Alice's address.
+
+ Compression SHOULD NOT be mandatory. It may be offered as an option.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 23]
+
+Internet-Draft opportunistic May 2003
+
+
+5. DNS issues
+
+5.1 Use of KEY record
+
+ In order to establish their own identities, SG-A and SG-B SHOULD
+ publish their public keys in their reverse DNS via DNSSEC's KEY
+ record. See section 3 of RFC 2535 [16].
+
+ For example:
+
+ KEY 0x4200 4 1 AQNJjkKlIk9...nYyUkKK8
+
+ 0x4200: The flag bits, indicating that this key is prohibited for
+ confidentiality use (it authenticates the peer only, a separate
+ Diffie-Hellman exchange is used for confidentiality), and that
+ this key is associated with the non-zone entity whose name is the
+ RR owner name. No other flags are set.
+
+ 4: This indicates that this key is for use by IPsec.
+
+ 1: An RSA key is present.
+
+ AQNJjkKlIk9...nYyUkKK8: The public key of the host as described in
+ [17].
+
+ Use of several KEY records allows for key rollover. The SIG Payload
+ in IKE phase 1 SHOULD be accepted if the public key given by any KEY
+ RR validates it.
+
+5.2 Use of TXT delegation record
+
+ Alice publishes a TXT record to provide authorization for SG-A to act
+ on Alice's behalf. Bob publishes a TXT record to provide
+ authorization for SG-B to act on Bob's behalf. These records are
+ located in the reverse DNS (in-addr.arpa) for their respective IP
+ addresses. The reverse DNS SHOULD be secured by DNSSEC, when it is
+ deployed. DNSSEC is required to defend against active attacks.
+
+ If Alice's address is P.Q.R.S, then she can authorize another node to
+ act on her behalf by publishing records at:
+
+ S.R.Q.P.in-addr.arpa
+
+ The contents of the resource record are expected to be a string that
+ uses the following syntax, as suggested in [15]. (Note that the
+ reply to query may include other TXT resource records used by other
+ applications.)
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 24]
+
+Internet-Draft opportunistic May 2003
+
+
+ ---------------------------------------------------------------------
+
+
+ X-IPsec-Server(P)=A.B.C.D KEY
+
+ Figure 2: Format of reverse delegation record
+
+ ---------------------------------------------------------------------
+
+ P: Specifies a precedence for this record. This is similar to MX
+ record preferences. Lower numbers have stronger preference.
+
+ A.B.C.D: Specifies the IP address of the Security Gateway for this
+ client machine.
+
+ KEY: Is the encoded RSA Public key of the Security Gateway. The key
+ is provided here to avoid a second DNS lookup. If this field is
+ absent, then a KEY resource record should be looked up in the
+ reverse-map of A.B.C.D. The key is transmitted in base64 format.
+
+ The pieces of the record are separated by any whitespace (space, tab,
+ newline, carriage return). An ASCII space SHOULD be used.
+
+ In the case where Alice is located at a public address behind a
+ security gateway that has no fixed address (or no control over its
+ reverse-map), then Alice may delegate to a public key by domain name.
+
+ ---------------------------------------------------------------------
+
+
+ X-IPsec-Server(P)=@FQDN KEY
+
+ Figure 3: Format of reverse delegation record (FQDN version)
+
+ ---------------------------------------------------------------------
+
+ P: Is as above.
+
+ FQDN: Specifies the FQDN that the Security Gateway will identify
+ itself with.
+
+ KEY: Is the encoded RSA Public key of the Security Gateway.
+
+ If there is more than one such TXT record with strongest (lowest
+ numbered) precedence, one Security Gateway is picked arbitrarily from
+ those specified in the strongest-preference records.
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 25]
+
+Internet-Draft opportunistic May 2003
+
+
+5.2.1 Long TXT records
+
+ When packed into transport format, TXT records which are longer than
+ 255 characters are divided into smaller <character-strings>. (See
+ [13] section 3.3 and 3.3.14.) These MUST be reassembled into a single
+ string for processing. Whitespace characters in the base64 encoding
+ are to be ignored.
+
+5.2.2 Choice of TXT record
+
+ It has been suggested to use the KEY, OPT, CERT, or KX records
+ instead of a TXT record. None is satisfactory.
+
+ The KEY RR has a protocol field which could be used to indicate a new
+ protocol, and an algorithm field which could be used to indicate
+ different contents in the key data. However, the KEY record is
+ clearly not intended for storing what are really authorizations, it
+ is just for identities. Other uses have been discouraged.
+
+ OPT resource records, as defined in [14] are not intended to be used
+ for storage of information. They are not to be loaded, cached or
+ forwarded. They are, therefore, inappropriate for use here.
+
+ CERT records [18] can encode almost any set of information. A custom
+ type code could be used permitting any suitable encoding to be
+ stored, not just X.509. According to the RFC, the certificate RRs
+ are to be signed internally which may add undesirable and unnecessary
+ bulk. Larger DNS records may require TCP instead of UDP transfers.
+
+ At the time of protocol design, the CERT RR was not widely deployed
+ and could not be counted upon. Use of CERT records will be
+ investigated, and may be proposed in a future revision of this
+ document.
+
+ KX records are ideally suited for use instead of TXT records, but had
+ not been deployed at the time of implementation.
+
+5.3 Use of FQDN IDs
+
+ Unfortunately, not every administrator has control over the contents
+ of the reverse-map. Where the initiator (SG-A) has no suitable
+ reverse-map, the authorization record present in the reverse-map of
+ Alice may refer to a FQDN instead of an IP address.
+
+ In this case, the client's TXT record gives the fully qualified
+ domain name (FQDN) in place of its security gateway's IP address.
+ The initiator should use the ID_FQDN ID-payload in phase 1. A
+ forward lookup for a KEY record on the FQDN must yield the
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 26]
+
+Internet-Draft opportunistic May 2003
+
+
+ initiator's public key.
+
+ This method can also be used when the external address of SG-A is
+ dynamic.
+
+ If SG-A is acting on behalf of Alice, then Alice must still delegate
+ authority for SG-A to do so in her reverse-map. When Alice and SG-A
+ are one and the same (i.e. Alice is acting as an end-node) then
+ there is no need for this when initiating only.
+
+ However, Alice must still delegate to herself if she wishes others
+ to initiate OE to her. See Figure 3.
+
+5.4 Key roll-over
+
+ Good cryptographic hygiene says that one should replace public/
+ private key pairs periodically. Some administrators may wish to do
+ this as often as daily. Typical DNS propagation delays are
+ determined by the SOA Resource Record MINIMUM parameter, which
+ controls how long DNS replies may be cached. For reasonable
+ operation of DNS servers, administrators usually want this value to
+ be at least several hours, sometimes as a long as a day. This
+ presents a problem - a new key MUST not be used prior to it
+ propagating through DNS.
+
+ This problem is dealt with by having the Security Gateway generate a
+ new public/private key pair at least MINIMUM seconds in advance of
+ using it. It then adds this key to the DNS (both as a second KEY
+ record and in additional TXT delegation records) at key generation
+ time. Note: only one key is allowed in each TXT record.
+
+ When authenticating, all gateways MUST have available all public keys
+ that are found in DNS for this entity. This permits the
+ authenticating end to check both the key for "today" and the key for
+ "tomorrow". Note that it is the end which is creating the signature
+ (possesses the private key) that determines which key is to be used.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 27]
+
+Internet-Draft opportunistic May 2003
+
+
+6. Network address translation interaction
+
+ There are no fundamentally new issues for implementing opportunistic
+ encryption in the presence of network address translation. Rather
+ there are only the regular IPsec issues with NAT traversal.
+
+ There are several situations to consider for NAT.
+
+6.1 Co-located NAT/NAPT
+
+ If SG-A is also performing network address translation on behalf of
+ Alice, then the packet should be translated prior to being subjected
+ to opportunistic encryption. This is in contrast to typically
+ configured tunnels which often exist to bridge islands of private
+ network address space. SG-A will use the translated source address
+ for phase 2, and so SG-B will look up that address to confirm SG-A's
+ authorization.
+
+ In the case of NAT (1:1), the address space into which the
+ translation is done MUST be globally unique, and control over the
+ reverse-map is assumed. Placing of TXT records is possible.
+
+ In the case of NAPT (m:1), the address will be SG-A. The ability to
+ get KEY and TXT records in place will again depend upon whether or
+ not there is administrative control over the reverse-map. This is
+ identical to situations involving a single host acting on behalf of
+ itself. FQDN style can be used to get around a lack of a reverse-map
+ for initiators only.
+
+6.2 SG-A behind NAT/NAPT
+
+ If there is a NAT or NAPT between SG-A and SG-B, then normal IPsec
+ NAT traversal rules apply. In addition to the transport problem
+ which may be solved by other mechanisms, there is the issue of what
+ phase 1 and phase 2 IDs to use. While FQDN could be used during
+ phase 1 for SG-A, there is no appropriate ID for phase 2 that permits
+ SG-B to determine that SG-A is in fact authorized to speak for Alice.
+
+6.3 Bob is behind a NAT/NAPT
+
+ If Bob is behind a NAT (perhaps SG-B), then there is, in fact, no way
+ for Alice to address a packet to Bob. Not only is opportunistic
+ encryption impossible, but it is also impossible for Alice to
+ initiate any communication to Bob. It may be possible for Bob to
+ initiate in such a situation. This creates an asymmetry, but this is
+ common for NAPT.
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 28]
+
+Internet-Draft opportunistic May 2003
+
+
+7. Host implementations
+
+ When Alice and SG-A are components of the same system, they are
+ considered to be a host implementation. The packet sequence scenario
+ remains unchanged.
+
+ Components marked Alice are the upper layers (TCP, UDP, the
+ application), and SG-A is the IP layer.
+
+ Note that tunnel mode is still required.
+
+ As Alice and SG-A are acting on behalf of themselves, no TXT based
+ delegation record is necessary for Alice to initiate. She can rely
+ on FQDN in a forward map. This is particularly attractive to mobile
+ nodes such as notebook computers at conferences. To respond, Alice/
+ SG-A will still need an entry in Alice's reverse-map.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 29]
+
+Internet-Draft opportunistic May 2003
+
+
+8. Multi-homing
+
+ If there are multiple paths between Alice and Bob (as illustrated in
+ the diagram with SG-D), then additional DNS records are required to
+ establish authorization.
+
+ In Figure 1, Alice has two ways to exit her network: SG-A and SG-D.
+ Previously SG-D has been ignored. Postulate that there are routers
+ between Alice and her set of security gateways (denoted by the +
+ signs and the marking of an autonomous system number for Alice's
+ network). Datagrams may, therefore, travel to either SG-A or SG-D en
+ route to Bob.
+
+ As long as all network connections are in good order, it does not
+ matter how datagrams exit Alice's network. When they reach either
+ security gateway, the security gateway will find the TXT delegation
+ record in Bob's reverse-map, and establish an SA with SG-B.
+
+ SG-B has no problem establishing that either of SG-A or SG-D may
+ speak for Alice, because Alice has published two equally weighted TXT
+ delegation records:
+
+ ---------------------------------------------------------------------
+
+
+ X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
+ X-IPsec-Server(10)=192.1.1.6 AAJN...j8r9==
+
+ Figure 4: Multiple gateway delegation example for Alice
+
+ ---------------------------------------------------------------------
+
+ Alice's routers can now do any kind of load sharing needed. Both SG-
+ A and SG-D send datagrams addressed to Bob through their tunnel to
+ SG-B.
+
+ Alice's use of non-equal weight delegation records to show preference
+ of one gateway over another, has relevance only when SG-B is
+ initiating to Alice.
+
+ If the precedences are the same, then SG-B has a more difficult time.
+ It must decide which of the two tunnels to use. SG-B has no
+ information about which link is less loaded, nor which security
+ gateway has more cryptographic resources available. SG-B, in fact,
+ has no knowledge of whether both gateways are even reachable.
+
+ The Public Internet's default-free zone may well know a good route to
+ Alice, but the datagrams that SG-B creates must be addressed to
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 30]
+
+Internet-Draft opportunistic May 2003
+
+
+ either SG-A or SG-D; they can not be addressed to Alice directly.
+
+ SG-B may make a number of choices:
+
+ 1. It can ignore the problem and round robin among the tunnels.
+ This causes losses during times when one or the other security
+ gateway is unreachable. If this worries Alice, she can change
+ the weights in her TXT delegation records.
+
+ 2. It can send to the gateway from which it most recently received
+ datagrams. This assumes that routing and reachability are
+ symmetrical.
+
+ 3. It can listen to BGP information from the Internet to decide
+ which system is currently up. This is clearly much more
+ complicated, but if SG-B is already participating in the BGP
+ peering system to announce Bob, the results data may already be
+ available to it.
+
+ 4. It can refuse to negotiate the second tunnel. (It is unclear
+ whether or not this is even an option.)
+
+ 5. It can silently replace the outgoing portion of the first tunnel
+ with the second one while still retaining the incoming portions
+ of both. SG-B can, thus, accept datagrams from either SG-A or
+ SG-D, but send only to the gateway that most recently re-keyed
+ with it.
+
+ Local policy determines which choice SG-B makes. Note that even if
+ SG-B has perfect knowledge about the reachability of SG-A and SG-D,
+ Alice may not be reachable from either of these security gateways
+ because of internal reachability issues.
+
+ FreeS/WAN implements option 5. Implementing a different option is
+ being considered. The multi-homing aspects of OE are not well
+ developed and may be the subject of a future document.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 31]
+
+Internet-Draft opportunistic May 2003
+
+
+9. Failure modes
+
+9.1 DNS failures
+
+ If a DNS server fails to respond, local policy decides whether or not
+ to permit communication in the clear as embodied in the connection
+ classes in Section 3.2. It is easy to mount a denial of service
+ attack on the DNS server responsible for a particular network's
+ reverse-map. Such an attack may cause all communication with that
+ network to go in the clear if the policy is permissive, or fail
+ completely if the policy is paranoid. Please note that this is an
+ active attack.
+
+ There are still many networks that do not have properly configured
+ reverse-maps. Further, if the policy is not to communicate, the
+ above denial of service attack isolates the target network.
+ Therefore, the decision of whether or not to permit communication in
+ the clear MUST be a matter of local policy.
+
+9.2 DNS configured, IKE failures
+
+ DNS records claim that opportunistic encryption should occur, but the
+ target gateway either does not respond on port 500, or refuses the
+ proposal. This may be because of a crash or reboot, a faulty
+ configuration, or a firewall filtering port 500.
+
+ The receipt of ICMP port, host or network unreachable messages
+ indicates a potential problem, but MUST NOT cause communication to
+ fail immediately. ICMP messages are easily forged by attackers. If
+ such a forgery caused immediate failure, then an active attacker
+ could easily prevent any encryption from ever occurring, possibly
+ preventing all communication.
+
+ In these situations a clear log should be produced and local policy
+ should dictate if communication is then permitted in the clear.
+
+9.3 System reboots
+
+ Tunnels sometimes go down because the remote end crashes,
+ disconnects, or has a network link break. In general there is no
+ notification of this. Even in the event of a crash and successful
+ reboot, other SGs don't hear about it unless the rebooted SG has
+ specific reason to talk to them immediately. Over-quick response to
+ temporary network outages is undesirable. Note that a tunnel can be
+ torn down and then re-established without any effect visible to the
+ user except a pause in traffic. On the other hand, if one end
+ reboots, the other end can't get datagrams to it at all (except via
+ IKE) until the situation is noticed. So a bias toward quick response
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 32]
+
+Internet-Draft opportunistic May 2003
+
+
+ is appropriate even at the cost of occasional false alarms.
+
+ A mechanism for recovery after reboot is a topic of current research
+ and is not specified in this document.
+
+ A deliberate shutdown should include an attempt, using deletes, to
+ notify all other SGs currently connected by phase 1 SAs that
+ communication is about to fail. Again, a remote SG will assume this
+ is a teardown. Attempts by the remote SGs to negotiate new tunnels
+ as replacements should be ignored. When possible, SGs should attempt
+ to preserve information about currently-connected SGs in non-volatile
+ storage, so that after a crash, an Initial-Contact can be sent to
+ previous partners to indicate loss of all previously established
+ connections.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 33]
+
+Internet-Draft opportunistic May 2003
+
+
+10. Unresolved issues
+
+10.1 Control of reverse DNS
+
+ The method of obtaining information by reverse DNS lookup causes
+ problems for people who cannot control their reverse DNS bindings.
+ This is an unresolved problem in this version, and is out of scope.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 34]
+
+Internet-Draft opportunistic May 2003
+
+
+11. Examples
+
+11.1 Clear-text usage (permit policy)
+
+ Two example scenarios follow. In the first example GW-A (Gateway A)
+ and GW-B (Gateway B) have always-clear-text policies, and in the
+ second example they have an OE policy.
+
+ ---------------------------------------------------------------------
+
+
+ Alice SG-A DNS SG-B Bob
+ (1)
+ ------(2)-------------->
+ <-----(3)---------------
+ (4)----(5)----->
+ ----------(6)------>
+ ------(7)----->
+ <------(8)------
+ <----------(9)------
+ <----(10)-----
+ (11)----------->
+ ----------(12)----->
+ -------------->
+ <---------------
+ <-------------------
+ <-------------
+
+ Figure 5: Timing of regular transaction
+
+ ---------------------------------------------------------------------
+
+ Alice wants to communicate with Bob. Perhaps she wants to retrieve a
+ web page from Bob's web server. In the absence of opportunistic
+ encryptors, the following events occur:
+
+ (1) Human or application 'clicks' with a name.
+
+ (2) Application looks up name in DNS to get IP address.
+
+ (3) Resolver returns A record to application.
+
+ (4) Application starts a TCP session or UDP session and OS sends
+ datagram.
+
+ (5) Datagram is seen at first gateway from Alice (SG-A). (SG-A makes
+ a transition through Empty connection to always-clear connection
+ and instantiates a pass-through policy at the forwarding plane.)
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 35]
+
+Internet-Draft opportunistic May 2003
+
+
+ (6) Datagram is seen at last gateway before Bob (SG-B).
+
+ (7) First datagram from Alice is seen by Bob.
+
+ (8) First return datagram is sent by Bob.
+
+ (9) Datagram is seen at Bob's gateway. (SG-B makes a transition
+ through Empty connection to always-clear connection and
+ instantiates a pass-through policy at the forwarding plane.)
+
+ (10) Datagram is seen at Alice's gateway.
+
+ (11) OS hands datagram to application. Alice sends another datagram.
+
+ (12) A second datagram traverses the Internet.
+
+
+11.2 Opportunistic encryption
+
+ In the presence of properly configured opportunistic encryptors, the
+ event list is extended.
+
+ ---------------------------------------------------------------------
+
+
+ Alice SG-A DNS SG-B Bob
+ (1)
+ ------(2)-------------->
+ <-----(3)---------------
+ (4)----(5)----->+
+ ----(5B)->
+ <---(5C)--
+ ~~~~~~~~~~~~~(5D)~~~>
+ <~~~~~~~~~~~~(5E1)~~~
+ ~~~~~~~~~~~~~(5E2)~~>
+ <~~~~~~~~~~~~(5E3)~~~
+ #############(5E4)##>
+ <############(5E5)###
+ <----(5F1)--
+ -----(5F2)->
+ #############(5G1)##>
+ <----(5H1)--
+ -----(5H2)->
+ <############(5G2)###
+ #############(5G3)##>
+ ============(6)====>
+ ------(7)----->
+ <------(8)------
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 36]
+
+Internet-Draft opportunistic May 2003
+
+
+ <==========(9)======
+ <-----(10)----
+ (11)----------->
+ ==========(12)=====>
+ -------------->
+ <---------------
+ <===================
+ <-------------
+
+ Figure 6: Timing of opportunistic encryption transaction
+
+ ---------------------------------------------------------------------
+
+ (1) Human or application clicks with a name.
+
+ (2) Application initiates DNS mapping.
+
+ (3) Resolver returns A record to application.
+
+ (4) Application starts a TCP session or UDP.
+
+ (5) SG-A (host or SG) sees datagram to target, and buffers it.
+
+ (5B) SG-A asks DNS for TXT record.
+
+ (5C) DNS returns TXT record(s).
+
+ (5D) Initial IKE Main Mode Packet goes out.
+
+ (5E) IKE ISAKMP phase 1 succeeds.
+
+ (5F) SG-B asks DNS for TXT record to prove SG-A is an agent for
+ Alice.
+
+ (5G) IKE phase 2 negotiation.
+
+ (5H) DNS lookup by responder (SG-B).
+
+ (6) Buffered datagram is sent by SG-A.
+
+ (7) Datagram is received by SG-B, decrypted, and sent to Bob.
+
+ (8) Bob replies, and datagram is seen by SG-B.
+
+ (9) SG-B already has tunnel up with SG-A, and uses it.
+
+ (10) SG-A decrypts datagram and gives it to Alice.
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 37]
+
+Internet-Draft opportunistic May 2003
+
+
+ (11) Alice receives datagram. Sends new packet to Bob.
+
+ (12) SG-A gets second datagram, sees that tunnel is up, and uses it.
+
+ For the purposes of this section, we will describe only the changes
+ that occur between Figure 5 and Figure 6. This corresponds to time
+ points 5, 6, 7, 9 and 10 on the list above.
+
+11.2.1 (5) IPsec datagram interception
+
+ At point (5), SG-A intercepts the datagram because this source/
+ destination pair lacks a policy (the non-existent policy state). SG-
+ A creates a hold policy, and buffers the datagram. SG-A requests
+ keys from the keying daemon.
+
+11.2.2 (5B) DNS lookup for TXT record
+
+ SG-A's IKE daemon, having looked up the source/destination pair in
+ the connection class list, creates a new Potential OE connection
+ instance. SG-A starts DNS queries.
+
+11.2.3 (5C) DNS returns TXT record(s)
+
+ DNS returns properly formed TXT delegation records, and SG-A's IKE
+ daemon causes this instance to make a transition from Potential OE
+ connection to Pending OE connection.
+
+ Using the example above, the returned record might contain:
+
+ ---------------------------------------------------------------------
+
+
+ X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
+
+ Figure 7: Example of reverse delegation record for Bob
+
+ ---------------------------------------------------------------------
+
+ with SG-B's IP address and public key listed.
+
+11.2.4 (5D) Initial IKE main mode packet goes out
+
+ Upon entering Pending OE connection, SG-A sends the initial ISAKMP
+ message with proposals. See Section 4.6.1.
+
+11.2.5 (5E1) Message 2 of phase 1 exchange
+
+ SG-B receives the message. A new connection instance is created in
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 38]
+
+Internet-Draft opportunistic May 2003
+
+
+ the unauthenticated OE peer state.
+
+11.2.6 (5E2) Message 3 of phase 1 exchange
+
+ SG-A sends a Diffie-Hellman exponent. This is an internal state of
+ the keying daemon.
+
+11.2.7 (5E3) Message 4 of phase 1 exchange
+
+ SG-B responds with a Diffie-Hellman exponent. This is an internal
+ state of the keying protocol.
+
+11.2.8 (5E4) Message 5 of phase 1 exchange
+
+ SG-A uses the phase 1 SA to send its identity under encryption. The
+ choice of identity is discussed in Section 4.6.1. This is an
+ internal state of the keying protocol.
+
+11.2.9 (5F1) Responder lookup of initiator key
+
+ SG-B asks DNS for the public key of the initiator. DNS looks for a
+ KEY record by IP address in the reverse-map. That is, a KEY resource
+ record is queried for 4.1.1.192.in-addr.arpa (recall that SG-A's
+ external address is 192.1.1.4). SG-B uses the resulting public key
+ to authenticate the initiator. See Section 5.1 for further details.
+
+11.2.10 (5F2) DNS replies with public key of initiator
+
+ Upon successfully authenticating the peer, the connection instance
+ makes a transition to authenticated OE peer on SG-B.
+
+ The format of the TXT record returned is described in Section 5.2.
+
+11.2.11 (5E5) Responder replies with ID and authentication
+
+ SG-B sends its ID along with authentication material. This is an
+ internal state for the keying protocol.
+
+11.2.12 (5G) IKE phase 2
+
+11.2.12.1 (5G1) Initiator proposes tunnel
+
+ Having established mutually agreeable authentications (via KEY) and
+ authorizations (via TXT), SG-A proposes to create an IPsec tunnel for
+ datagrams transiting from Alice to Bob. This tunnel is established
+ only for the Alice/Bob combination, not for any subnets that may be
+ behind SG-A and SG-B.
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 39]
+
+Internet-Draft opportunistic May 2003
+
+
+11.2.12.2 (5H1) Responder determines initiator's authority
+
+ While the identity of SG-A has been established, its authority to
+ speak for Alice has not yet been confirmed. SG-B does a reverse
+ lookup on Alice's address for a TXT record.
+
+ Upon receiving this specific proposal, SG-B's connection instance
+ makes a transition into the potential OE connection state. SG-B may
+ already have an instance, and the check is made as described above.
+
+11.2.12.3 (5H2) DNS replies with TXT record(s)
+
+ The returned key and IP address should match that of SG-A.
+
+11.2.12.4 (5G2) Responder agrees to proposal
+
+ Should additional communication occur between, for instance, Dave and
+ Bob using SG-A and SG-B, a new tunnel (phase 2 SA) would be
+ established. The phase 1 SA may be reusable.
+
+ SG-A, having successfully keyed the tunnel, now makes a transition
+ from Pending OE connection to Keyed OE connection.
+
+ The responder MUST setup the inbound IPsec SAs before sending its
+ reply.
+
+11.2.12.5 (5G3) Final acknowledgment from initiator
+
+ The initiator agrees with the responder's choice and sets up the
+ tunnel. The initiator sets up the inbound and outbound IPsec SAs.
+
+ The proper authorization returned with keys prompts SG-B to make a
+ transition to the keyed OE connection state.
+
+ Upon receipt of this message, the responder may now setup the
+ outbound IPsec SAs.
+
+11.2.13 (6) IPsec succeeds, and sets up tunnel for communication between
+ Alice and Bob
+
+ SG-A sends the datagram saved at step (5) through the newly created
+ tunnel to SG-B, where it gets decrypted and forwarded. Bob receives
+ it at (7) and replies at (8).
+
+11.2.14 (9) SG-B already has tunnel up with G1 and uses it
+
+ At (9), SG-B has already established an SPD entry mapping Bob->Alice
+ via a tunnel, so this tunnel is simply applied. The datagram is
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 40]
+
+Internet-Draft opportunistic May 2003
+
+
+ encrypted to SG-A, decrypted by SG-A and passed to Alice at (10).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 41]
+
+Internet-Draft opportunistic May 2003
+
+
+12. Security considerations
+
+12.1 Configured vs opportunistic tunnels
+
+ Configured tunnels are those which are setup using bilateral
+ mechanisms: exchanging public keys (raw RSA, DSA, PKIX), pre-shared
+ secrets, or by referencing keys that are in known places
+ (distinguished name from LDAP, DNS). These keys are then used to
+ configure a specific tunnel.
+
+ A pre-configured tunnel may be on all the time, or may be keyed only
+ when needed. The end points of the tunnel are not necessarily
+ static: many mobile applications (road warrior) are considered to be
+ configured tunnels.
+
+ The primary characteristic is that configured tunnels are assigned
+ specific security properties. They may be trusted in different ways
+ relating to exceptions to firewall rules, exceptions to NAT
+ processing, and to bandwidth or other quality of service
+ restrictions.
+
+ Opportunistic tunnels are not inherently trusted in any strong way.
+ They are created without prior arrangement. As the two parties are
+ strangers, there MUST be no confusion of datagrams that arrive from
+ opportunistic peers and those that arrive from configured tunnels. A
+ security gateway MUST take care that an opportunistic peer can not
+ impersonate a configured peer.
+
+ Ingress filtering MUST be used to make sure that only datagrams
+ authorized by negotiation (and the concomitant authentication and
+ authorization) are accepted from a tunnel. This is to prevent one
+ peer from impersonating another.
+
+ An implementation suggestion is to treat opportunistic tunnel
+ datagrams as if they arrive on a logical interface distinct from
+ other configured tunnels. As the number of opportunistic tunnels
+ that may be created automatically on a system is potentially very
+ high, careful attention to scaling should be taken into account.
+
+ As with any IKE negotiation, opportunistic encryption cannot be
+ secure without authentication. Opportunistic encryption relies on
+ DNS for its authentication information and, therefore, cannot be
+ fully secure without a secure DNS. Without secure DNS, opportunistic
+ encryption can protect against passive eavesdropping but not against
+ active man-in-the-middle attacks.
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 42]
+
+Internet-Draft opportunistic May 2003
+
+
+12.2 Firewalls versus Opportunistic Tunnels
+
+ Typical usage of per datagram access control lists is to implement
+ various kinds of security gateways. These are typically called
+ "firewalls".
+
+ Typical usage of a virtual private network (VPN) within a firewall is
+ to bypass all or part of the access controls between two networks.
+ Additional trust (as outlined in the previous section) is given to
+ datagrams that arrive in the VPN.
+
+ Datagrams that arrive via opportunistically configured tunnels MUST
+ not be trusted. Any security policy that would apply to a datagram
+ arriving in the clear SHOULD also be applied to datagrams arriving
+ opportunistically.
+
+12.3 Denial of service
+
+ There are several different forms of denial of service that an
+ implementor should concern themselves with. Most of these problems
+ are shared with security gateways that have large numbers of mobile
+ peers (road warriors).
+
+ The design of ISAKMP/IKE, and its use of cookies, defend against many
+ kinds of denial of service. Opportunism changes the assumption that
+ if the phase 1 (ISAKMP) SA is authenticated, that it was worthwhile
+ creating. Because the gateway will communicate with any machine, it
+ is possible to form phase 1 SAs with any machine on the Internet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 43]
+
+Internet-Draft opportunistic May 2003
+
+
+13. IANA Considerations
+
+ There are no known numbers which IANA will need to manage.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 44]
+
+Internet-Draft opportunistic May 2003
+
+
+14. Acknowledgments
+
+ Substantive portions of this document are based upon previous work by
+ Henry Spencer.
+
+ Thanks to Tero Kivinen, Sandy Harris, Wes Hardarker, Robert
+ Moskowitz, Jakob Schlyter, Bill Sommerfeld, John Gilmore and John
+ Denker for their comments and constructive criticism.
+
+ Sandra Hoffman and Bill Dickie did the detailed proof reading and
+ editing.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 45]
+
+Internet-Draft opportunistic May 2003
+
+
+Normative references
+
+ [1] Redelmeier, D. and H. Spencer, "Opportunistic Encryption",
+ paper http://www.freeswan.org/freeswan_trees/freeswan-1.91/doc/
+ opportunism.spec, May 2001.
+
+ [2] Defense Advanced Research Projects Agency (DARPA), Information
+ Processing Techniques Office and University of Southern
+ California (USC)/Information Sciences Institute, "Internet
+ Protocol", STD 5, RFC 791, September 1981.
+
+ [3] Braden, R. and J. Postel, "Requirements for Internet gateways",
+ RFC 1009, June 1987.
+
+ [4] IAB, IESG, Carpenter, B. and F. Baker, "IAB and IESG Statement
+ on Cryptographic Technology and the Internet", RFC 1984, August
+ 1996.
+
+ [5] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+ [6] McDonald, D., Metz, C. and B. Phan, "PF_KEY Key Management API,
+ Version 2", RFC 2367, July 1998.
+
+ [7] Kent, S. and R. Atkinson, "Security Architecture for the
+ Internet Protocol", RFC 2401, November 1998.
+
+ [8] Piper, D., "The Internet IP Security Domain of Interpretation
+ for ISAKMP", RFC 2407, November 1998.
+
+ [9] Maughan, D., Schneider, M. and M. Schertler, "Internet Security
+ Association and Key Management Protocol (ISAKMP)", RFC 2408,
+ November 1998.
+
+ [10] Harkins, D. and D. Carrel, "The Internet Key Exchange (IKE)",
+ RFC 2409, November 1998.
+
+ [11] Kivinen, T. and M. Kojo, "More MODP Diffie-Hellman groups for
+ IKE", RFC 3526, March 2003.
+
+ [12] Mockapetris, P., "Domain names - concepts and facilities", STD
+ 13, RFC 1034, November 1987.
+
+ [13] Mockapetris, P., "Domain names - implementation and
+ specification", STD 13, RFC 1035, November 1987.
+
+ [14] Vixie, P., "Extension Mechanisms for DNS (EDNS0)", RFC 2671,
+ August 1999.
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 46]
+
+Internet-Draft opportunistic May 2003
+
+
+ [15] Rosenbaum, R., "Using the Domain Name System To Store Arbitrary
+ String Attributes", RFC 1464, May 1993.
+
+ [16] Eastlake, D., "Domain Name System Security Extensions", RFC
+ 2535, March 1999.
+
+ [17] Eastlake, D., "RSA/SHA-1 SIGs and RSA KEYs in the Domain Name
+ System (DNS)", RFC 3110, May 2001.
+
+ [18] Eastlake, D. and O. Gudmundsson, "Storing Certificates in the
+ Domain Name System (DNS)", RFC 2538, March 1999.
+
+ [19] Durham, D., Boyle, J., Cohen, R., Herzog, S., Rajan, R. and A.
+ Sastry, "The COPS (Common Open Policy Service) Protocol", RFC
+ 2748, January 2000.
+
+ [20] Srisuresh, P. and M. Holdrege, "IP Network Address Translator
+ (NAT) Terminology and Considerations", RFC 2663, August 1999.
+
+
+Authors' Addresses
+
+ Michael C. Richardson
+ Sandelman Software Works
+ 470 Dawson Avenue
+ Ottawa, ON K1Z 5V7
+ CA
+
+ EMail: mcr@sandelman.ottawa.on.ca
+ URI: http://www.sandelman.ottawa.on.ca/
+
+
+ D. Hugh Redelmeier
+ Mimosa
+ Toronto, ON
+ CA
+
+ EMail: hugh@mimosa.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 47]
+
+Internet-Draft opportunistic May 2003
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson & Redelmeier Expires November 19, 2003 [Page 48]
+
diff --git a/doc/draft-richardson-ipsec-rr.txt b/doc/draft-richardson-ipsec-rr.txt
new file mode 100644
index 000000000..7c229b8e1
--- /dev/null
+++ b/doc/draft-richardson-ipsec-rr.txt
@@ -0,0 +1,840 @@
+
+
+IPSECKEY WG M. Richardson
+Internet-Draft SSW
+Expires: March 4, 2004 September 4, 2003
+
+
+ A method for storing IPsec keying material in DNS.
+ draft-ietf-ipseckey-rr-07.txt
+
+Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of RFC2026.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working groups. Note that
+ other groups may also distribute working documents as Internet-
+ Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at http://
+ www.ietf.org/ietf/1id-abstracts.txt.
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ This Internet-Draft will expire on March 4, 2004.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+Abstract
+
+ This document describes a new resource record for DNS. This record
+ may be used to store public keys for use in IPsec systems.
+
+ This record replaces the functionality of the sub-type #1 of the KEY
+ Resource Record, which has been obsoleted by RFC3445.
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 1]
+
+Internet-Draft ipsecrr September 2003
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 1.2 Usage Criteria . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2. Storage formats . . . . . . . . . . . . . . . . . . . . . . . 4
+ 2.1 IPSECKEY RDATA format . . . . . . . . . . . . . . . . . . . . 4
+ 2.2 RDATA format - precedence . . . . . . . . . . . . . . . . . . 4
+ 2.3 RDATA format - algorithm type . . . . . . . . . . . . . . . . 4
+ 2.4 RDATA format - gateway type . . . . . . . . . . . . . . . . . 4
+ 2.5 RDATA format - gateway . . . . . . . . . . . . . . . . . . . . 5
+ 2.6 RDATA format - public keys . . . . . . . . . . . . . . . . . . 5
+ 3. Presentation formats . . . . . . . . . . . . . . . . . . . . . 7
+ 3.1 Representation of IPSECKEY RRs . . . . . . . . . . . . . . . . 7
+ 3.2 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
+ 4. Security Considerations . . . . . . . . . . . . . . . . . . . 9
+ 4.1 Active attacks against unsecured IPSECKEY resource records . . 9
+ 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 11
+ 6. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 12
+ Normative references . . . . . . . . . . . . . . . . . . . . . 13
+ Non-normative references . . . . . . . . . . . . . . . . . . . 14
+ Author's Address . . . . . . . . . . . . . . . . . . . . . . . 14
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . . 15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 2]
+
+Internet-Draft ipsecrr September 2003
+
+
+1. Introduction
+
+ The type number for the IPSECKEY RR is TBD.
+
+1.1 Overview
+
+ The IPSECKEY resource record (RR) is used to publish a public key
+ that is to be associated with a Domain Name System (DNS) name for use
+ with the IPsec protocol suite. This can be the public key of a
+ host, network, or application (in the case of per-port keying).
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC2119 [8].
+
+1.2 Usage Criteria
+
+ An IPSECKEY resource record SHOULD be used in combination with DNSSEC
+ unless some other means of authenticating the IPSECKEY resource
+ record is available.
+
+ It is expected that there will often be multiple IPSECKEY resource
+ records at the same name. This will be due to the presence of
+ multiple gateways and the need to rollover keys.
+
+ This resource record is class independent.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 3]
+
+Internet-Draft ipsecrr September 2003
+
+
+2. Storage formats
+
+2.1 IPSECKEY RDATA format
+
+ The RDATA for an IPSECKEY RR consists of a precedence value, a public
+ key, algorithm type, and an optional gateway address.
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | precedence | gateway type | algorithm | gateway |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------+ +
+ ~ gateway ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | /
+ / public key /
+ / /
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
+
+
+2.2 RDATA format - precedence
+
+ This is an 8-bit precedence for this record. This is interpreted in
+ the same way as the PREFERENCE field described in section 3.3.9 of
+ RFC1035 [2].
+
+ Gateways listed in IPSECKEY records with lower precedence are to be
+ attempted first. Where there is a tie in precedence, the order
+ should be non-deterministic.
+
+2.3 RDATA format - algorithm type
+
+ The algorithm type field identifies the public key's cryptographic
+ algorithm and determines the format of the public key field.
+
+ A value of 0 indicates that no key is present.
+
+ The following values are defined:
+
+ 1 A DSA key is present, in the format defined in RFC2536 [11]
+
+ 2 A RSA key is present, in the format defined in RFC3110 [12]
+
+
+2.4 RDATA format - gateway type
+
+ The gateway type field indicates the format of the information that
+ is stored in the gateway field.
+
+
+
+Richardson Expires March 4, 2004 [Page 4]
+
+Internet-Draft ipsecrr September 2003
+
+
+ The following values are defined:
+
+ 0 No gateway is present
+
+ 1 A 4-byte IPv4 address is present
+
+ 2 A 16-byte IPv6 address is present
+
+ 3 A wire-encoded domain name is present. The wire-encoded format is
+ self-describing, so the length is implicit. The domain name MUST
+ NOT be compressed.
+
+
+2.5 RDATA format - gateway
+
+ The gateway field indicates a gateway to which an IPsec tunnel may be
+ created in order to reach the entity named by this resource record.
+
+ There are three formats:
+
+ A 32-bit IPv4 address is present in the gateway field. The data
+ portion is an IPv4 address as described in section 3.4.1 of RFC1035
+ [2]. This is a 32-bit number in network byte order.
+
+ A 128-bit IPv6 address is present in the gateway field. The data
+ portion is an IPv6 address as described in section 2.2 of RFC1886
+ [7]. This is a 128-bit number in network byte order.
+
+ The gateway field is a normal wire-encoded domain name, as described
+ in section 3.3 of RFC1035 [2]. Compression MUST NOT be used.
+
+2.6 RDATA format - public keys
+
+ Both of the public key types defined in this document (RSA and DSA)
+ inherit their public key formats from the corresponding KEY RR
+ formats. Specifically, the public key field contains the algorithm-
+ specific portion of the KEY RR RDATA, which is all of the KEY RR DATA
+ after the first four octets. This is the same portion of the KEY RR
+ that must be specified by documents that define a DNSSEC algorithm.
+ Those documents also specify a message digest to be used for
+ generation of SIG RRs; that specification is not relevant for
+ IPSECKEY RR.
+
+ Future algorithms, if they are to be used by both DNSSEC (in the KEY
+ RR) and IPSECKEY, are likely to use the same public key encodings in
+ both records. Unless otherwise specified, the IPSECKEY public key
+ field will contain the algorithm-specific portion of the KEY RR RDATA
+ for the corresponding algorithm. The algorithm must still be
+
+
+
+Richardson Expires March 4, 2004 [Page 5]
+
+Internet-Draft ipsecrr September 2003
+
+
+ designated for use by IPSECKEY, and an IPSECKEY algorithm type number
+ (which might be different than the DNSSEC algorithm number) must be
+ assigned to it.
+
+ The DSA key format is defined in RFC2536 [11]
+
+ The RSA key format is defined in RFC3110 [12], with the following
+ changes:
+
+ The earlier definition of RSA/MD5 in RFC2065 limited the exponent and
+ modulus to 2552 bits in length. RFC3110 extended that limit to 4096
+ bits for RSA/SHA1 keys. The IPSECKEY RR imposes no length limit on
+ RSA public keys, other than the 65535 octet limit imposed by the two-
+ octet length encoding. This length extension is applicable only to
+ IPSECKEY and not to KEY RRs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 6]
+
+Internet-Draft ipsecrr September 2003
+
+
+3. Presentation formats
+
+3.1 Representation of IPSECKEY RRs
+
+ IPSECKEY RRs may appear in a zone data master file. The precedence,
+ gateway type and algorithm and gateway fields are REQUIRED. The
+ base64 encoded public key block is OPTIONAL; if not present, then the
+ public key field of the resource record MUST be construed as being
+ zero octets in length.
+
+ The algorithm field is an unsigned integer. No mnemonics are
+ defined.
+
+ If no gateway is to be indicated, then the gateway type field MUST be
+ zero, and the gateway field MUST be "."
+
+ The Public Key field is represented as a Base64 encoding of the
+ Public Key. Whitespace is allowed within the Base64 text. For a
+ definition of Base64 encoding, see RFC1521 [3] Section 5.2.
+
+ The general presentation for the record as as follows:
+
+ IN IPSECKEY ( precedence gateway-type algorithm
+ gateway base64-encoded-public-key )
+
+
+3.2 Examples
+
+ An example of a node 192.0.2.38 that will accept IPsec tunnels on its
+ own behalf.
+
+ 38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2
+ 192.0.2.38
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+
+ An example of a node, 192.0.2.38 that has published its key only.
+
+ 38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2
+ .
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+
+ An example of a node, 192.0.2.38 that has delegated authority to the
+ node 192.0.2.3.
+
+ 38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2
+ 192.0.2.3
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+
+
+
+
+Richardson Expires March 4, 2004 [Page 7]
+
+Internet-Draft ipsecrr September 2003
+
+
+ An example of a node, 192.0.1.38 that has delegated authority to the
+ node with the identity "mygateway.example.com".
+
+ 38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2
+ mygateway.example.com.
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+
+ An example of a node, 2001:0DB8:0200:1:210:f3ff:fe03:4d0 that has
+ delegated authority to the node 2001:0DB8:c000:0200:2::1
+
+ $ORIGIN 1.0.0.0.0.0.2.8.B.D.0.1.0.0.2.ip6.int.
+ 0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2
+ 2001:0DB8:0:8002::2000:1
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 8]
+
+Internet-Draft ipsecrr September 2003
+
+
+4. Security Considerations
+
+ This entire memo pertains to the provision of public keying material
+ for use by key management protocols such as ISAKMP/IKE (RFC2407) [9].
+
+ The IPSECKEY resource record contains information that SHOULD be
+ communicated to the end client in an integral fashion - i.e. free
+ from modification. The form of this channel is up to the consumer of
+ the data - there must be a trust relationship between the end
+ consumer of this resource record and the server. This relationship
+ may be end-to-end DNSSEC validation, a TSIG or SIG(0) channel to
+ another secure source, a secure local channel on the host, or some
+ combination of the above.
+
+ The keying material provided by the IPSECKEY resource record is not
+ sensitive to passive attacks. The keying material may be freely
+ disclosed to any party without any impact on the security properties
+ of the resulting IPsec session: IPsec and IKE provide for defense
+ against both active and passive attacks.
+
+ Any user of this resource record MUST carefully document their trust
+ model, and why the trust model of DNSSEC is appropriate, if that is
+ the secure channel used.
+
+4.1 Active attacks against unsecured IPSECKEY resource records
+
+ This section deals with active attacks against the DNS. These
+ attacks require that DNS requests and responses be intercepted and
+ changed. DNSSEC is designed to defend against attacks of this kind.
+
+ The first kind of active attack is when the attacker replaces the
+ keying material with either a key under its control or with garbage.
+
+ If the attacker is not able to mount a subsequent man-in-the-middle
+ attack on the IKE negotiation after replacing the public key, then
+ this will result in a denial of service, as the authenticator used by
+ IKE would fail.
+
+ If the attacker is able to both to mount active attacks against DNS
+ and is also in a position to perform a man-in-the-middle attack on
+ IKE and IPsec negotiations, then the attacker will be in a position
+ to compromise the resulting IPsec channel. Note that an attacker
+ must be able to perform active DNS attacks on both sides of the IKE
+ negotiation in order for this to succeed.
+
+ The second kind of active attack is one in which the attacker
+ replaces the the gateway address to point to a node under the
+ attacker's control. The attacker can then either replace the public
+
+
+
+Richardson Expires March 4, 2004 [Page 9]
+
+Internet-Draft ipsecrr September 2003
+
+
+ key or remove it, thus providing an IPSECKEY record of its own to
+ match the gateway address.
+
+ This later form creates a simple man-in-the-middle since the attacker
+ can then create a second tunnel to the real destination. Note that,
+ as before, this requires that the attacker also mount an active
+ attack against the responder.
+
+ Note that the man-in-the-middle can not just forward cleartext
+ packets to the original destination. While the destination may be
+ willing to speak in the clear, replying to the original sender, the
+ sender will have already created a policy expecting ciphertext.
+ Thus, the attacker will need to intercept traffic from both sides.
+ In some cases, the attacker may be able to accomplish the full
+ intercept by use of Network Addresss/Port Translation (NAT/NAPT)
+ technology.
+
+ Note that the danger here only applies to cases where the gateway
+ field of the IPSECKEY RR indicates a different entity than the owner
+ name of the IPSECKEY RR. In cases where the end-to-end integrity of
+ the IPSECKEY RR is suspect, the end client MUST restrict its use of
+ the IPSECKEY RR to cases where the RR owner name matches the content
+ of the gateway field.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 10]
+
+Internet-Draft ipsecrr September 2003
+
+
+5. IANA Considerations
+
+ This document updates the IANA Registry for DNS Resource Record Types
+ by assigning type X to the IPSECKEY record.
+
+ This document creates an IANA registry for the algorithm type field.
+
+ Values 0, 1 and 2 are defined in Section 2.3. Algorithm numbers 3
+ through 255 can be assigned by IETF Consensus (see RFC2434 [6]).
+
+ This document creates an IANA registry for the gateway type field.
+
+ Values 0, 1, 2 and 3 are defined in Section 2.4. Algorithm numbers 4
+ through 255 can be assigned by Standards Action (see RFC2434 [6]).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 11]
+
+Internet-Draft ipsecrr September 2003
+
+
+6. Acknowledgments
+
+ My thanks to Paul Hoffman, Sam Weiler, Jean-Jacques Puig, Rob
+ Austein, and Olafur Gurmundsson who reviewed this document carefully.
+ Additional thanks to Olafur Gurmundsson for a reference
+ implementation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 12]
+
+Internet-Draft ipsecrr September 2003
+
+
+Normative references
+
+ [1] Mockapetris, P., "Domain names - concepts and facilities", STD
+ 13, RFC 1034, November 1987.
+
+ [2] Mockapetris, P., "Domain names - implementation and
+ specification", STD 13, RFC 1035, November 1987.
+
+ [3] Borenstein, N. and N. Freed, "MIME (Multipurpose Internet Mail
+ Extensions) Part One: Mechanisms for Specifying and Describing
+ the Format of Internet Message Bodies", RFC 1521, September
+ 1993.
+
+ [4] Bradner, S., "The Internet Standards Process -- Revision 3", BCP
+ 9, RFC 2026, October 1996.
+
+ [5] Eastlake, D. and C. Kaufman, "Domain Name System Security
+ Extensions", RFC 2065, January 1997.
+
+ [6] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA
+ Considerations Section in RFCs", BCP 26, RFC 2434, October 1998.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 13]
+
+Internet-Draft ipsecrr September 2003
+
+
+Non-normative references
+
+ [7] Thomson, S. and C. Huitema, "DNS Extensions to support IP
+ version 6", RFC 1886, December 1995.
+
+ [8] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+ [9] Piper, D., "The Internet IP Security Domain of Interpretation
+ for ISAKMP", RFC 2407, November 1998.
+
+ [10] Eastlake, D., "Domain Name System Security Extensions", RFC
+ 2535, March 1999.
+
+ [11] Eastlake, D., "DSA KEYs and SIGs in the Domain Name System
+ (DNS)", RFC 2536, March 1999.
+
+ [12] Eastlake, D., "RSA/SHA-1 SIGs and RSA KEYs in the Domain Name
+ System (DNS)", RFC 3110, May 2001.
+
+ [13] Massey, D. and S. Rose, "Limiting the Scope of the KEY Resource
+ Record (RR)", RFC 3445, December 2002.
+
+
+Author's Address
+
+ Michael C. Richardson
+ Sandelman Software Works
+ 470 Dawson Avenue
+ Ottawa, ON K1Z 5V7
+ CA
+
+ EMail: mcr@sandelman.ottawa.on.ca
+ URI: http://www.sandelman.ottawa.on.ca/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 14]
+
+Internet-Draft ipsecrr September 2003
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richardson Expires March 4, 2004 [Page 15]
+
diff --git a/doc/draft-spencer-ipsec-ike-implementation.nr b/doc/draft-spencer-ipsec-ike-implementation.nr
new file mode 100644
index 000000000..5b5776e22
--- /dev/null
+++ b/doc/draft-spencer-ipsec-ike-implementation.nr
@@ -0,0 +1,1203 @@
+.\" date, expiry date, copyright year, and revision
+.DA "26 Feb 2002"
+.ds e "26 Aug 2002
+.ds c 2002
+.ds r 02
+.\" boilerplate
+.pl 10i
+.nr PL 10i
+.po 0
+.nr PO 0
+.ll 7.2i
+.nr LL 7.2i
+.lt 7.2i
+.nr LT 7.2i
+.hy 0
+.nr HY 0
+.ad l
+.nr PD 1v
+.\" macros for paragraph, section header, reference, TOC
+.de P
+.br
+.LP
+.in 3
+..
+.de H
+.br
+.ne 5
+.LP
+.in 0
+..
+.de R
+.IP " [\\$1]" 14
+..
+.de T
+.ie \\$1=1 \{\
+.nf
+.ta \n(LLu-3nR
+.\}
+.el \{\
+.fi
+.\}
+..
+.de S
+.ie '\\$1'' \\$2 \a \\$3
+.el \\$1. \\$2 \a \\$3
+..
+.\" headers/footers
+.ds LH "Internet Draft
+.ds CH "IKE Implementation Issues
+.ds RH "\*(DY
+.ds LF "Spencer & Redelmeier
+.ds CF "
+.ds RF "[Page %]
+.\" and let's get started
+.RT
+.nf
+.tl 'Network Working Group''Henry Spencer'
+.tl 'Internet Draft''SP Systems'
+.tl 'Expires: \*e''D. Hugh Redelmeier'
+.tl '''Mimosa Systems'
+.tl '''\*(DY'
+.sp
+.ce 99
+IKE Implementation Issues
+<draft-spencer-ipsec-ike-implementation-\*r.txt>
+.ce 0
+.H
+Status of this Memo
+.P
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC2026.
+.P
+(If approved as an Informational RFC...)
+This memo provides information for the Internet community.
+This memo does not specify an Internet standard of any kind.
+.P
+Distribution of this memo is unlimited.
+.P
+Internet-Drafts are working documents of the Internet Engineering
+Task Force (IETF), its areas, and its working groups.
+Note that
+other groups may also distribute working documents as Internet-Drafts.
+.P
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time.
+It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
+.P
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt.
+.P
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html.
+.P
+This Internet-Draft will expire on \*e.
+.H
+Copyright Notice
+.P
+Copyright (C) The Internet Society \*c. All Rights Reserved.
+.bp
+.H
+Table of Contents
+.P
+.T 1
+.S "1" "Introduction" "3"
+.S "2" "Lower-level Background and Notes" "4"
+.S "2.1" "Packet Handling" "4"
+.S "2.2" "Ciphers" "5"
+.S "2.3" "Interfaces" "5"
+.S "3" "IKE Infrastructural Issues" "5"
+.S "3.1" "Continuous Channel" "5"
+.S "3.2" "Retransmission" "5"
+.S "3.3" "Replay Prevention" "6"
+.S "4" "Basic Keying and Rekeying" "7"
+.S "4.1" "When to Create SAs" "7"
+.S "4.2" "When to Rekey" "8"
+.S "4.3" "Choosing an SA" "9"
+.S "4.4" "Why to Rekey" "9"
+.S "4.5" "Rekeying ISAKMP SAs" "10"
+.S "4.6" "Bulk Negotiation" "10"
+.S "5" "Deletions, Teardowns, Crashes" "11"
+.S "5.1" "Deletions" "11"
+.S "5.2" "Teardowns and Shutdowns" "12"
+.S "5.3" "Crashes" "13"
+.S "5.4" "Network Partitions" "13"
+.S "5.5" "Unknown SAs" "14"
+.S "6" "Misc. IKE Issues" "16"
+.S "6.1" "Groups 1 and 5" "16"
+.S "6.2" "To PFS Or Not To PFS" "16"
+.S "6.3" "Debugging Tools, Lack Thereof" "16"
+.S "6.4" "Terminology, Vagueness Thereof" "17"
+.S "6.5" "A Question of Identity" "17"
+.S "6.6" "Opportunistic Encryption" "17"
+.S "6.7" "Authentication and RSA Keys" "17"
+.S "6.8" "Misc. Snags" "18"
+.S "7" "Security Considerations" "19"
+.S "8" "References" "19"
+.S "" "Authors' Addresses" "20"
+.S "" "Full Copyright Statement" "21"
+.T 0
+.bp
+.H
+Abstract
+.P
+The current IPsec specifications for key exchange and connection management,
+RFCs 2408 [ISAKMP] and 2409 [IKE],
+leave many aspects of connection management unspecified,
+most prominently rekeying practices.
+Pending clarifications in future revisions of the specifications,
+this document sets down some successful experiences,
+to minimize the extent to which new implementors have to rely
+on unwritten folklore.
+.P
+The Linux FreeS/WAN implementation of IPsec interoperates
+with almost every other IPsec implementation.
+This document describes how the FreeS/WAN project has resolved
+some of the gaps in the IPsec specifications
+(and plans to resolve some others),
+and what difficulties have been encountered,
+in hopes that this generally-successful experience
+might be informative to new implementors.
+.P
+This is offered as an Informational RFC.
+.P
+This -\*r revision mainly:
+discusses ISAKMP SA expiry during IPsec-SA rekeying (4.5),
+revises the discussion of bidirectional Deletes (5.1),
+suggests remembering the parameters of successful negotiations
+for later use (4.2, 5.3),
+notes an unsuccessful negotiation from the other end as a hint of a possibly
+broken connection (5.5),
+and adds sections on network partitions (5.4),
+authentication methods and the subtleties of RSA public keys (6.7),
+and miscellaneous interoperability concerns (6.8).
+.H
+1. Introduction
+.P
+The current IPsec specifications for key exchange and connection management,
+RFCs 2408 [ISAKMP] and 2409 [IKE],
+leave many aspects of connection management unspecified,
+most prominently rekeying practices.
+This is a cryptic puzzle which
+each group of implementors has to struggle with,
+and differences in how the ambiguities and gaps are resolved are
+potentially a fruitful source of interoperability problems.
+We can hope that future revisions of the specifications will clear this up.
+Meanwhile, it seems useful to set down some successful experiences,
+to minimize the extent to which new implementors have to rely
+on unwritten folklore.
+.P
+The Linux FreeS/WAN implementation of IPsec interoperates
+with almost every other IPsec implementation,
+and because of its free nature,
+it also sees some use as a reference implementation by other implementors.
+The high degree of interoperability is noteworthy
+given its organizers' strong minimalist bias,
+which has caused them to implement only
+a small subset of the full glory of IPsec.
+This document describes how the FreeS/WAN project has resolved
+some of the gaps in the IPsec specifications
+(and plans to resolve some others),
+and what difficulties have been encountered,
+in hopes that this generally-successful experience
+might be informative to new implementors.
+.P
+One small caution about applicability:
+this experience may not be relevant
+to severely resource-constrained implementations.
+FreeS/WAN's target environment is previous-generation PCs,
+now available at trivial cost (often,
+within an organization, at no cost),
+which have quite impressive CPU power and memory by the standards
+of only a few years ago.
+Some of the approaches discussed here may be inapplicable to
+implementations with severe external constraints which prevent them
+from taking advantage of modern hardware technology.
+.H
+2. Lower-level Background and Notes
+.H
+2.1. Packet Handling
+.P
+FreeS/WAN implements ESP [ESP] and AH [AH] straightforwardly,
+although AH sees little use among our users.
+Our ESP/AH implementation cannot currently handle packets
+with IP options;
+somewhat surprisingly, this has caused little difficulty.
+We insist on encryption and do not support authentication-only
+connections, and this has not caused significant difficulty either.
+.P
+MTU and fragmentation issues, by contrast, have been a constant headache.
+We will not describe the details of our current approach to them,
+because it still needs work.
+One difficulty we have encountered is that many combinations of
+packet source and packet destination
+apparently cannot cope with an "interior minimum" in the path MTU,
+e.g. where an IPsec tunnel intervenes and its headers reduce the MTU
+for an intermediate link.
+This is particularly prevalent when using common PC software to
+connect to large well-known web sites;
+we think it is largely due to
+misconfigured firewalls which do not pass ICMP
+Fragmentation Required messages.
+The only solution we have yet found is to lie about the MTU of the tunnel,
+accepting the (undesirable) fragmentation of the ESP packets
+for the sake of preserving connectivity.
+.P
+We currently zero out the TOS field of ESP packets,
+rather than copying it from the inner header,
+on the grounds that it lends itself too well to traffic analysis
+and covert channels.
+We provide an option to restore RFC 2401 [IPSEC] copying behavior,
+but this appears to see little use.
+.H
+2.2. Ciphers
+.P
+We initially implemented both DES [DES] and 3DES [CIPHERS] for both
+IKE and ESP,
+but after the Deep Crack effort [CRACK] demonstrated its inherent insecurity,
+we dropped support for DES.
+Somewhat surprisingly,
+our insistence on 3DES has caused almost no interoperability problems,
+despite DES being officially mandatory.
+A very few other systems either do not support 3DES or support it only
+as an optional upgrade,
+which inconveniences a few would-be users.
+There have also been one or two cases of systems
+which don't quite seem to know the difference!
+.P
+See also section 6.1 for a consequence of our insistence on 3DES.
+.H
+2.3. Interfaces
+.P
+We currently employ PF_KEY version 2 [PFKEY],
+plus various non-standard extensions,
+as our interface between keying and ESP.
+This has not proven entirely satisfactory.
+Our feeling now is that keying issues and policy issues
+do not really lend
+themselves to the clean separation that PF_KEY envisions.
+.H
+3. IKE Infrastructural Issues
+.P
+A number of problems in IPsec connection management become easier if
+some attention is first paid to providing an infrastructure
+to support solving them.
+.H
+3.1. Continuous Channel
+.P
+FreeS/WAN uses an approximation to the "continuous channel" model,
+in which ISAKMP SAs are maintained between IKEs
+so long as any IPsec SAs are open between the two systems.
+The resource consumption of this is minor:
+the only substantial overhead is occasional rekeying.
+IPsec SA management becomes significantly simpler if there is always
+a channel for transmission of control messages.
+We suggest (although we do not yet fully implement this) that
+inability to maintain (e.g., to rekey) this control path
+should be grounds for tearing down the IPsec SAs as well.
+.P
+As a corollary of this,
+there is one and only one ISAKMP SA maintained between a pair of IKEs
+(although see sections 5.3 and 6.5 for minor complications).
+.H
+3.2. Retransmission
+.P
+The unreliable nature of UDP transmission is a nuisance.
+IKE implementations should always be prepared to retransmit the most recent
+message they sent on an ISAKMP SA,
+since there is some possibility that the other end did not get it.
+This means, in particular,
+that the system sending the supposedly-last message of an exchange
+cannot relax and assume that the exchange is complete,
+at least not until a significant timeout has elapsed.
+.P
+Systems must also retain information about the message most recently received
+in an exchange,
+so that a duplicate of it can be detected
+(and possibly interpreted as a NACK for the response).
+.P
+The retransmission rules FreeS/WAN follows are:
+(1) if a reply is expected, retransmit only if it does not appear
+before a timeout;
+and (2) if a reply is not expected (last message of the exchange),
+retransmit only on receiving a retransmission of the previous message.
+Notably, in case (1) we do NOT retransmit on receiving a retransmission,
+which avoids possible congestion problems arising from packet duplication,
+at the price of slowing response to packet loss.
+The timeout for case (1) is 10 seconds for the first retry,
+20 seconds for the second, and 40 seconds for all subsequent
+retries (normally only one,
+except when
+configuration settings call for persistence and the message is
+the first message of Main Mode with a new peer).
+These retransmission rules have been entirely successful.
+.P
+(Michael Thomas of Cisco has pointed out that the retry timeouts should
+include some random jitter, to de-synchronize hosts which are
+initially synchronized by, e.g., a power outage.
+We already jitter our rekeying times,
+as noted in section 4.2,
+but that does not help with initial startup.
+We're implementing jittered retries,
+but cannot yet report on experience with this.)
+.P
+There is a deeper problem, of course, when an entire "exchange" consists
+of a single message,
+e.g. the ISAKMP Informational Exchange.
+Then there is no way to decide whether or when a retransmission is
+warranted at all.
+This seems like poor design, to put it mildly
+(and there is now talk of fixing it).
+We have no experience in dealing with this problem at this time,
+although it is part of the reason why we have delayed implementing
+Notification messages.
+.H
+3.3. Replay Prevention
+.P
+The unsequenced nature of UDP transmission is also troublesome,
+because it means that higher levels must consider the possibility
+of replay attacks.
+FreeS/WAN takes the position that systematically eliminating this
+possibility at a low level is strongly preferable to forcing careful
+consideration of possible impacts at every step of an exchange.
+RFC 2408 [ISAKMP] section 3.1 states that the Message ID of an
+ISAKMP message must be "unique".
+FreeS/WAN interprets this literally,
+as forbidding duplication of Message IDs
+within the set of all messages sent via a single ISAKMP SA.
+.P
+This requires remembering all Message IDs until the ISAKMP SA is
+superseded by rekeying,
+but that is not costly (four bytes per sent or received message),
+and it ELIMINATES replay attacks from consideration;
+we believe this investment of resources is well worthwhile.
+If the resource consumption becomes excessive\(emin our experience
+it has not\(emthe ISAKMP SA can be rekeyed early to collect the garbage.
+.P
+There is theoretically an interoperability problem when talking to
+implementations which interpret "unique" more loosely
+and may re-use Message IDs,
+but it has not been encountered in practice.
+This approach appears to be completely interoperable.
+.P
+The proposal by
+Andrew Krywaniuk [REPLAY],
+which advocates turning the Message ID into an anti-replay counter,
+would achieve the same goal without the minor per-message memory overhead.
+This may be preferable,
+although it means an actual protocol change and more study is needed.
+.H
+4. Basic Keying and Rekeying
+.H
+4.1. When to Create SAs
+.P
+As Tim Jenkins [REKEY] pointed out,
+there is a potential race condition in Quick Mode:
+a fast lightly-loaded Initiator might start using IPsec SAs very
+shortly after sending QM3 (the third and last message of Quick Mode),
+while a slow heavily-loaded Responder might
+not be ready to receive them until after spending
+a significant amount of time creating its inbound SAs.
+The problem is even worse if QM3 gets delayed or lost.
+.P
+FreeS/WAN's approach to this is what Jenkins called "Responder Pre-Setup":
+the Responder creates its inbound IPsec SAs before it sends QM2,
+so they are always ready and waiting
+when the Initiator sends QM3 and begins sending traffic.
+This approach is simple and reliable,
+and in our experience it interoperates with everybody.
+(There is potentially still a problem if FreeS/WAN is the Initiator
+and the Responder does not use Responder Pre-Setup,
+but no such problems have been seen.)
+The only real weakness of Responder Pre-Setup
+is the possibility of replay attacks,
+which we have eliminated by other means (see section 3.3).
+.P
+With this approach, the Commit Bit is useless,
+and we ignore it.
+In fact, until quite recently we discarded any IKE message containing it,
+and this caused surprisingly few interoperability problems;
+apparently it is not widely used.
+We have recently been persuaded that simply ignoring it is preferable;
+preliminary experience with this indicates that the result is successful
+interoperation with implementations which set it.
+.H
+4.2. When to Rekey
+.P
+To preserve connectivity for user traffic,
+rekeying of a connection
+(that is, creation of new IPsec SAs to supersede the current ones)
+must begin before its current IPsec SAs expire.
+Preferably one end should predictably start rekeying negotiations first,
+to avoid the extra overhead of two simultaneous negotiations,
+although either end should be prepared to rekey if the other does not.
+There is also a problem with "convoys" of keying negotiations:
+for example, a "hub" gateway with many IPsec connections
+can be inundated with rekeying negotiations
+exactly one connection-expiry time after it reboots,
+and the massive overload this induces tends to make this
+situation self-perpetuating,
+so it recurs regularly.
+(Convoys can also evolve gradually from initially-unsynchronized negotiations.)
+.P
+FreeS/WAN has the concept of a "rekeying margin", measured in seconds.
+If FreeS/WAN was the Initiator for the previous rekeying
+(or the startup, if none) of the connection,
+it nominally starts rekeying negotiations at expiry time
+minus one rekeying margin.
+Some random jitter is added to break up convoys:
+rather than starting rekeying exactly at minus one margin,
+it starts at a random time between minus one margin
+and minus two margins.
+(The randomness here need not be cryptographic in quality,
+so long as it varies over time and between hosts.
+We use an ordinary PRNG seeded with a few bytes from a cryptographic
+randomness source.
+The seeding mostly just ensures that the PRNG sequence is different
+for different hosts, even if they start up simultaneously.)
+.P
+If FreeS/WAN was the Responder for the previous rekeying/startup,
+and nothing has been heard from the previous Initiator
+at expiry time minus one-half the rekeying margin,
+FreeS/WAN will initiate rekeying negotiations.
+No jitter is applied;
+we now believe that it should be jittered,
+say between minus one-half margin and minus one-quarter margin.
+.P
+Having the Initiator lead the way is an obvious way of deciding
+who should speak first,
+since there is already an Initiator/Responder asymmetry in the connection.
+Moreover, our experience has been that Initiator lead gives a significantly
+higher probability of successful negotiation!
+The negotiation process itself is asymmetric,
+because the Initiator must make a few specific proposals which the Responder
+can only accept or reject,
+so the Initiator must try to guess where its "acceptable" region
+(in parameter space)
+might overlap with the Responder's.
+We have seen situations where negotiations would succeed or fail
+depending on which end initiated them,
+because one end was making better guesses.
+Given an existing connection,
+we KNOW that the previous Initiator WAS able to initiate a successful
+negotiation,
+so it should (if at all possible) take the lead again.
+Also, the Responder should remember the Initiator's successful proposal,
+and start from that
+rather than from his own default proposals if he must take the lead;
+we don't currently implement this completely but plan to.
+.P
+FreeS/WAN defaults the rekeying margin to 9 minutes,
+although this can be changed by configuration.
+There is also
+a configuration option to alter the permissible range of jitter.
+The defaults were chosen somewhat arbitrarily,
+but they work extremely well
+and the configuration options are rarely used.
+.H
+4.3. Choosing an SA
+.P
+Once rekeying has occurred,
+both old and new IPsec SAs for the connection exist,
+at least momentarily.
+FreeS/WAN accepts incoming traffic
+on either old or new inbound SAs,
+but sends outgoing traffic only on the new outbound ones.
+This approach appears to be significantly more robust than
+using the old ones until they expire,
+notably in cases where renegotiation has occurred because something has
+gone wrong on the other end.
+It avoids having to pay meticulous attention to the state of the other end,
+state which is difficult to learn reliably given the limitations of IKE.
+.P
+This approach has interoperated successfully with ALMOST all other
+implementations.
+The only (well-characterized) problem cases have been implementations
+which rely on receiving a Delete message for the old SAs to tell them
+to switch over to the new ones.
+Since delivery of Delete is unreliable,
+and support for Delete is optional,
+this reliance seems like a serious mistake.
+This is all the more true because Delete
+announces that the deletion has
+already occurred [ISAKMP, section 3.15], not that it is about to occur,
+so packets already in transit in the other direction could be lost.
+Delete should be used for resource cleanup, not for switchover control.
+(These matters are discussed further in section 5.)
+.H
+4.4. Why to Rekey
+.P
+FreeS/WAN currently implements only time-based expiry (life in seconds),
+although we are working toward
+supporting volume-based expiry (life in kilobytes) as well.
+The lack of volume-based expiry has not been an interoperability
+problem so far.
+.P
+Volume-based expiry does add some minor complications.
+In particular, it makes explicit Delete of now-disused SAs more important,
+because once an SA stops being used,
+it might not expire on its own.
+We believe this lacks robustness and is generally unwise,
+especially given the lack of a reliable Delete,
+and expect to use volume-based expiry only as a supplement
+to time-based expiry.
+However, Delete support (see section 5) does seem advisable
+for use with volume-based expiry.
+.P
+We do not believe that volume-based expiry alters the desirability
+of switching immediately to the new SAs after rekeying.
+Rekeying margins are normally a small fraction of the total life of an SA,
+so we feel there is no great need to "use it all up".
+.H
+4.5. Rekeying ISAKMP SAs
+.P
+The above discussion has focused on rekeying for IPsec SAs,
+but FreeS/WAN applies the same approaches to rekeying for ISAKMP SAs,
+with similar success.
+.P
+One issue which we have noticed, but not explicitly dealt with,
+is that difficulties may ensue if an IPsec-SA rekeying negotiation
+is in progress at the time when the relevant ISAKMP SA gets rekeyed.
+The IKE specification [IKE] hints, but does not actually say,
+that a Quick Mode negotiation should remain on a single ISAKMP SA throughout.
+.P
+A reasonable rekeying margin will generally
+prevent the old ISAKMP SA from actually expiring during a negotiation.
+Some attention may be needed to prevent in-progress negotiations from
+being switched to the new ISAKMP SA.
+Any attempt at pre-expiry deletion of the ISAKMP SA must be postponed
+until after such dangling negotiations are completed,
+and there should be enough delay between ISAKMP-SA rekeying and a
+deletion attempt to (more or less)
+ensure that there are no negotiation-starting packets still in transit
+from before the rekeying.
+.P
+At present, FreeS/WAN does none of this,
+and we don't KNOW of any resulting trouble.
+With normal lifetimes, the problem should be uncommon,
+and we speculate that an occasional disrupted negotiation simply gets retried.
+.H
+4.6. Bulk Negotiation
+.P
+Quick Mode nominally provides for negotiating possibly-large numbers of
+similar but unrelated IPsec SAs simultaneously
+[IKE, section 9].
+Nobody appears to do this.
+FreeS/WAN does not support it, and its absence has caused no problems.
+.H
+5. Deletions, Teardowns, Crashes
+.P
+FreeS/WAN currently ignores all Notifications and Deletes,
+and never generates them.
+This has caused little difficulty in interoperability,
+which shouldn't be surprising (since Notification and Delete support is
+officially entirely optional) but does seem to surprise some people.
+Nevertheless, we do plan some changes to this approach
+based on past experience.
+.H
+5.1. Deletions
+.P
+As hinted at above,
+we plan to implement Delete support, done as follows.
+Shortly after rekeying of IPsec SAs,
+the Responder issues a Delete for its old inbound SAs
+(but does not actually delete them yet).
+The Responder initiates this because the Initiator started using the
+new SAs on sending QM3, while the Responder started using them only
+on (or somewhat after) receiving QM3,
+so there is less chance of old-SA packets still being in transit from
+the Initiator.
+The Initiator issues an unsolicited Delete only if it does not hear one
+from the Responder after a longer delay.
+.P
+Either party, on receiving a Delete
+for one or more of the old outbound SAs of a connection,
+deletes ALL the connection's SAs,
+and acknowledges with a Delete for the old inbound SAs.
+A Delete for nonexistent SAs
+(e.g., SAs which have already been expired or deleted) is ignored.
+There is no retransmission of unacknowledged Deletes.
+.P
+In the normal case,
+with prompt reliable transmission (except possibly for loss of the
+Responder's initial Delete)
+and conforming implementations
+on both ends, this results in three Deletes being transmitted,
+resembling the classic three-way handshake.
+Loss of a Delete after the first, or multiple losses,
+will cause the SAs not to be deleted on at least one end.
+It appears difficult to do much better without at least
+a distinction between request and acknowledgement.
+.P
+RFC 2409 section 9 "strongly suggests" that there be no response to
+informational messages such as Deletes,
+but the only rationale offered is prevention of infinite loops
+endlessly exchanging "I don't understand you" informationals.
+Since Deletes cannot lead to such a loop
+(and in any case, the nonexistent-SA rule prevents more than one
+acknowledgement for the same connection),
+we believe this recommendation is inapplicable here.
+.P
+As noted in section 4.3, these Deletes are intended for
+resource cleanup, not to control switching between SAs.
+But we expect that they will improve interoperability
+with some broken implementations.
+.P
+We believe strongly that connections need to be considered as a whole,
+rather than treating each SA as an independent entity.
+We will issue Deletes only for the full set of inbound SAs of
+a connection,
+and will treat a Delete for any outbound SA as equivalent to deletion
+of all the outbound SAs for the associated connection.
+.P
+The above is phrased in terms of IPsec SAs,
+but essentially the same approach can be applied to ISAKMP SAs
+(the Deletes for the old ISAKMP SA should be sent via the new one).
+.H
+5.2. Teardowns and Shutdowns
+.P
+When a connection is not intended to be up permanently,
+there is a need to coordinate teardown,
+so that both ends are aware that the connection is down.
+This is both for recovery of resources,
+and to avoid routing packets through
+dangling SAs which can no longer deliver them.
+.P
+Connection teardown will use the same bidirectional exchange of Deletes
+as discussed in section 5.1:
+a Delete received for current IPsec SAs (not yet obsoleted by rekeying)
+indicates that the other host wishes to tear down the associated connection.
+.P
+A Delete received for a current ISAKMP SA indicates that the other host
+wishes to tear down not only the ISAKMP SA but also all IPsec SAs
+currently under the supervision of that ISAKMP SA.
+The 5.1 bidirectional exchange might seem impossible in this case,
+since reception of an ISAKMP-SA Delete indicates that the other end
+will ignore further traffic on that ISAKMP SA.
+We suggest using the same tactic discussed in 5.1 for IPsec SAs:
+the first Delete is sent without actually doing the deletion,
+and the response to receiving a Delete is to do the deletion and reply
+with another Delete.
+If there is no response to the first Delete,
+retry a small number of times and then give up and do the deletion;
+apart from being robust against packet loss,
+this also maximizes the probability that an implementation which does
+not do the bidirectional Delete will receive at least one of the Deletes.
+.P
+When a host with current connections knows that it is about to shut down,
+it will issue Deletes for all SAs involved (both IPsec and ISAKMP),
+advising its peers (as per the meaning of Delete [ISAKMP, section 3.15])
+that the SAs have become useless.
+It will ignore attempts at rekeying or connection startup thereafter,
+until it shuts down.
+.P
+It would be better to have a Final-Contact notification,
+analogous to Initial-Contact but indicating that no new negotiations
+should be attempted until further notice.
+Initial-Contact actually could be used for shutdown notification (!),
+but in networks where connections are intended to exist permanently,
+it seems likely to provoke unwanted attempts
+to renegotiate the lost connections.
+.H
+5.3. Crashes
+.P
+Systems sometimes crash.
+Coping with the resulting loss of information is easily the most
+difficult problem we have found in implementing robust IPsec systems.
+.P
+When connections are intended to be permanent,
+it is simple to specify renegotiation on reboot.
+With our approach to SA selection (see section 4.3),
+this handles such cases robustly and well.
+We do have to tell users that BOTH hosts should be set this way.
+In cases where crashes are synchronized (e.g. by power interruptions),
+this may result in simultaneous negotiations at reboot.
+We currently allow both negotiations to proceed to completion,
+but our use-newest selection method
+effectively ignores one connection or the other,
+and when one of them rekeys,
+we notice that the new SAs replace those of both old connections,
+and we then refrain from rekeying the other.
+(This duplicate detection is desirable in any event, for robustness,
+to ensure that the system converges on a reasonable state eventually
+after it is perturbed by difficulties or bugs.)
+.P
+When connections are not permanent, the situation is less happy.
+One particular situation in which we see problems is when a number of
+"Road Warrior" hosts occasionally call in to a central server.
+The server is normally configured not to initiate such connections,
+since it does not know when the Road Warrior is available (or what IP
+address it is using).
+Unfortunately, if the server crashes and reboots,
+any Road Warriors then connected have a problem:
+they don't know that the server has crashed,
+so they can't renegotiate,
+and the server has forgotten both the connections and
+their (transient) IP addresses,
+so it cannot renegotiate.
+.P
+We believe that the simplest answer to this problem is what John Denker
+has dubbed "address inertia":
+the server makes a best-effort attempt to remember (in nonvolatile storage)
+which connections were active and what the far-end addresses were
+(and what the successful proposal's parameters were),
+so that it can attempt renegotiation on reboot.
+We have not implemented this yet, but intend to;
+Denker has implemented it himself,
+although in a somewhat messy way,
+and reports excellent results.
+.H
+5.4. Network Partitions
+.P
+A network partition, making the two ends unable to reach each other,
+has many of the same characteristics as having the other end crash... until
+the network reconnects.
+It is desirable that recovery from this be automatic.
+.P
+If the network reconnects before any rekeying attempts
+or other IKE activities occurred,
+recovery is fully transparent,
+because the IKEs have no idea that there was any problem.
+(Complaints such as ICMP Host Unreachable messages are unauthenticated
+and hence cannot be given much weight.)
+This fits the general mold of TCP/IP:
+if nobody wanted to send any traffic, a network outage doesn't matter.
+.P
+If IKE activity did occur,
+the IKE implementation will discover that the other end doesn't seem
+to be responding.
+The preferred response to this depends on the nature of the connection.
+If it was intended to be ephemeral (e.g. opportunistic encryption [OE]),
+closing it down after a few retries is reasonable.
+If the other end is expected to sometimes drop the connection without
+warning, it may not be desirable to retry at all.
+(We support both these forms of configurability,
+and indeed we also have a configuration option to suppress
+rekeying entirely on one end.)
+.P
+If the connection was intended to be permanent, however,
+then persistent attempts to re-establish it are appropriate.
+Some degree of backoff is appropriate here,
+so that retries get less frequent as the outage gets prolonged.
+Backoff should be limited,
+so that re-established connectivity is not followed by a long delay
+before a retry.
+Finally, after many retries (say 24 hours' worth),
+it may be preferable to just declare the connection down and rely
+on manual intervention to re-establish it,
+should this be desirable.
+We do not yet fully support all this.
+.H
+5.5. Unknown SAs
+.P
+A more complete solution to crashes
+would be for an IPsec host to note the arrival
+of ESP packets on an unknown IPsec SA,
+and report it somehow to the other host, which can then decide to renegotiate.
+This arguably might be preferable in any case\(emif
+the non-rebooted host has no traffic to send,
+it does not care whether the connection is intact\(embut
+delays and packet loss will be reduced
+if the connection is renegotiated BEFORE there is traffic for it.
+So unknown-SA detection is best reserved as a fallback method,
+with address inertia used to deal with most such cases.
+.P
+A difficulty with unknown-SA detection is,
+just HOW should the other host be notified?
+IKE provides no good way to do the notification:
+Notification payloads (e.g., Initial-Contact) are unauthenticated
+unless they are sent under protection of an ISAKMP SA.
+A "Security Failures - Bad SPI" ICMP message [SECFAIL]
+is an interesting alternative,
+but has the disadvantage of likewise being unauthenticated.
+It's fundamentally unlikely that there is a simple solution to this,
+given that almost any way of arranging or checking authentication for such a
+notification is costly.
+.P
+We think the best answer to this is a two-step approach.
+An unauthenticated Initial-Contact or
+Security Failures - Bad SPI cannot be taken as a reliable
+report of a problem,
+but can be taken as a hint that a problem MIGHT exist.
+Then there needs to be some reliable way of checking such hints,
+subject to rate limiting since the checks are likely to be costly
+(and checking the same connection repeatedly at short intervals is unlikely
+to be worthwhile anyway).
+So the rebooted host sends the notification,
+and the non-rebooted host\(emwhich still thinks it has a connection\(emchecks
+whether the connection still works,
+and renegotiates if not.
+.P
+Also, if an IPsec host which believes it has a connection to another host
+sees an unsuccessful attempt by that host to negotiate a new one,
+that is also a hint of possible problems,
+justifying a check and possible renegotiation.
+("Unsuccessful" here means a negotiation failure due to lack of a
+satisfactory proposal.
+A failure due to authentication failure
+suggests a denial-of-service attack by a third party,
+rather than a genuine problem on the legitimate other end.)
+As noted in section 4.2,
+it is possible for negotiations to succeed or fail based on which
+end initiates them, and some robustness against that is desirable.
+.P
+We have not yet decided what form the notification should take.
+IKE Initial-Contact is an obvious possibility,
+but has some disadvantages.
+It does not specify which connection has had difficulties.
+Also, the specification [IKE section 4.6.3.3]
+refers to "remote system" and "sending system"
+without clearly specifying just what "system" means;
+in the case of a multi-homed host using multiple forms of identification,
+the question is not trivial.
+Initial-Contact does have the fairly-decisive advantage
+that it is likely to convey the right general
+meaning even to an implementation which does not do things
+exactly the way ours does.
+.P
+A more fundamental difficulty is what form the reliable check takes.
+What is wanted is an "IKE ping",
+verifying that the ISAKMP SA is still intact
+(it being unlikely that IPsec SAs have been lost while the ISAKMP SA has not).
+The lack of such a facility is a serious failing of IKE.
+An acknowledged Notification of some sort would be ideal,
+but there is none at present.
+Some existing implementations are known
+to use the private Notification values 30000 as ping
+and 30002 as ping reply,
+and that seems the most attractive choice at present.
+If it is not recognized, there will probably be no reply,
+and the result will be an unnecessary renegotiation,
+so this needs strict rate limiting.
+(Also, when a new connection is set up,
+it's probably worth determining by experiment whether the other end
+supports IKE ping, and remembering that.)
+.P
+While we think this facility is desirable,
+and is about the best that can be done with the poor tools available,
+we have not gotten very far in implementation and cannot comment
+intelligently about how well it works or interoperates.
+.H
+6. Misc. IKE Issues
+.H
+6.1. Groups 1 and 5
+.P
+We have dropped support for the first Oakley Group (group 1),
+despite it being officially mandatory,
+on the grounds that it is
+grossly too weak to provide enough randomness for 3DES.
+There have been some interoperability problems,
+mostly quite minor:
+ALMOST everyone supports group 2 as well,
+although sometimes it has to be explicitly configured.
+.P
+We also support the quasi-standard group 5 [GROUPS].
+This has not been seriously exercised yet,
+because historically
+we offered group 2 first and almost everyone accepted it.
+We have recently changed to offering group 5 first,
+and no difficulties have been reported.
+.H
+6.2. To PFS Or Not To PFS
+.P
+A persistent small interoperability problem is that
+the presence or absence of PFS (for keys [IKE, section 5.5])
+is neither negotiated nor announced.
+We have it enabled by default,
+and successful interoperation often requires having
+the other end turn it on in their implementation,
+or having the FreeS/WAN end disable it.
+Almost everyone supports it, but it's usually not the default,
+and interoperability is often impossible unless the two ends
+somehow reach prior agreement on it.
+.P
+We do not explicitly support the other flavor of PFS,
+for identities [IKE, section 8],
+and this has caused no interoperability problems.
+.H
+6.3. Debugging Tools, Lack Thereof
+.P
+We find IKE lacking in basic debugging tools.
+Section 5.4, above,
+notes that an IKE ping would be useful for connectivity verification.
+It would also be extremely helpful for determining that UDP/500
+packets get back and forth successfully between the two ends,
+which is often an important first step in debugging.
+.P
+It's also quite common to have IKE negotiate a connection successfully,
+but to have some firewall along the way blocking ESP.
+Users find this mysterious and difficult to diagnose.
+We have no immediate suggestions on what could be done about it.
+.H
+6.4. Terminology, Vagueness Thereof
+.P
+The terminology of IPsec needs work.
+We feel that both the specifications and user-oriented
+documentation would be greatly clarified by concise, intelligible names for
+certain concepts.
+.P
+We semi-consistently use "group" for the set of IPsec SAs which are
+established in one direction
+by a single Quick Mode negotiation and are used together
+to process a packet (e.g., an ESP SA plus an AH SA),
+"connection" for the logical packet path provided
+by a succession of pairs of groups
+(each rekeying providing a new pair, one group in each direction),
+and "keying channel" for the corresponding supervisory path provided
+by a sequence of ISAKMP SAs.
+.P
+We think it's a botch that "PFS" is used to refer to two very different things,
+but we have no specific new terms to suggest, since we only implement
+one kind of PFS and thus can just ignore the other.
+.H
+6.5. A Question of Identity
+.P
+One specification problem deserves note:
+exactly when can an existing phase 1 negotiation
+be re-used for a new phase 2 negotiation,
+as IKE [IKE, section 4] specifies?
+Presumably,
+when it connects the same two "parties"... but exactly what is a "party"?
+.P
+As noted in section 5.4,
+in cases involving multi-homing and multiple identities,
+it's not clear exactly what criteria are used for deciding
+whether the intended far end for a new negotiation is the same one
+as for a previous negotiation.
+Is it by Identification Payload?
+By IP address?
+Or what?
+.P
+We currently use a somewhat-vague notion of "identity",
+basically what gets sent in Identification Payloads,
+for this, and this seems to be successful,
+but we think this needs better specification.
+.H
+6.6. Opportunistic Encryption
+.P
+Further IKE challenges appear in the context of Opportunistic Encryption
+[OE],
+but operational experience with it is too limited as yet for us
+to comment usefully right now.
+.H
+6.7. Authentication and RSA Keys
+.P
+We provide two IKE authentication methods:
+shared secrets ("pre-shared keys")
+and RSA digital signatures.
+(A user-provided add-on package generalizes the latter to limited
+support for certificates;
+we have not worked extensively with it ourselves yet and cannot comment
+on it yet.)
+.P
+Shared secrets, despite their administrative difficulties,
+see considerable use,
+and are also the method of last resort for interoperability problems.
+.P
+For digital signatures,
+we have taken the somewhat unorthodox approach of using "bare" RSA public keys,
+either supplied in configuration files or fetched from DNS,
+rather than getting involved in the complexity of certificates.
+We encode our RSA public keys using the DNS KEY encoding [DNSRSA]
+(aka "RFC 2537", although that RFC is now outdated),
+which has given us no difficulties and which we highly recommend.
+We have seen two difficulties in connection with RSA keys, however.
+.P
+First,
+while a number of IPsec implementations are able to take "bare" RSA public keys,
+each one seems to have its own idea of what format should be used
+for transporting them.
+We've had little success with interoperability here,
+mostly because of key-format issues;
+the implementations generally WILL interoperate successfully if you can
+somehow get an RSA key into them at all, but that's hard.
+X.509 certificates seem to be the lowest (!)
+common denominator for key transfer.
+.P
+Second,
+although the content of RSA public keys has been stable,
+there has been a small but subtle change over time in the content
+of RSA private keys.
+The "internal modulus",
+used to compute the private exponent "d" from the public exponent "e"
+(or vice-versa)
+was originally [RSA] [PKCS1v1] [SCHNEIER] specified to be (p-1)*(q-1),
+where p and q are the two primes.
+However, more recent definitions [PKCS1v2] call it
+"lambda(n)" and define it to be lcm(p-1,\ q-1);
+this appears to be a minor optimization.
+The result is that private keys generated with the new definition
+often fail consistency checks in implementations using the old definition.
+Fortunately, it is seldom necessary to move private keys around.
+Our software now consistently uses the new definition
+(and thus will accept keys generated with either definition),
+but our key generator also has an option to generate old-definition keys,
+for the benefit of users who upgrade their networks incrementally.
+.H
+6.8. Misc. Snags
+.P
+Nonce size is another characteristic that is neither negotiated nor announced
+but that the two ends must somehow be able to agree on.
+Our software accepts anything between 8 and 256, and defaults to 16.
+These numbers were chosen rather arbitrarily,
+but we have seen no interoperability failures here.
+.P
+Nothing in the ISAKMP [ISAKMP] or IKE [IKE] specifications says
+explicitly that a normal Message ID must be non-zero,
+but a zero Message ID in fact causes failures.
+.P
+Similarly, there is nothing in the specs which says that ISAKMP cookies
+must be non-zero, but zero cookies will in fact cause trouble.
+.H
+7. Security Considerations
+.P
+Since this document discusses aspects of building robust and
+interoperable IPsec implementations,
+security considerations permeate it.
+.H
+8. References
+.R AH
+Kent, S., and Atkinson, R.,
+"IP Authentication Header",
+RFC 2402,
+Nov 1998.
+.R CIPHERS
+Pereira, R., and Adams, R.,
+"The ESP CBC-Mode Cipher Algorithms",
+RFC 2451,
+Nov 1998.
+.R CRACK
+Electronic Frontier Foundation,
+"Cracking DES:
+Secrets of Encryption Research, Wiretap Politics and Chip Design",
+O'Reilly 1998,
+ISBN 1-56592-520-3.
+.R DES
+Madson, C., and Doraswamy, N.,
+"The ESP DES-CBC Cipher Algorithm",
+RFC 2405,
+Nov 1998.
+.R DNSRSA
+D. Eastlake 3rd,
+"RSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)",
+RFC 3110,
+May 2001.
+.R ESP
+Kent, S., and Atkinson, R.,
+"IP Encapsulating Security Payload (ESP)",
+RFC 2406,
+Nov 1998.
+.R GROUPS
+Kivinen, T., and Kojo, M.,
+"More MODP Diffie-Hellman groups for IKE",
+<draft-ietf-ipsec-ike-modp-groups-04.txt>,
+13 Dec 2001 (work in progress).
+.R IKE
+Harkins, D., and Carrel, D.,
+"The Internet Key Exchange (IKE)",
+RFC 2409, Nov 1998.
+.R IPSEC
+Kent, S., and Atkinson, R.,
+"Security Architecture for the Internet Protocol",
+RFC 2401, Nov 1998.
+.R ISAKMP
+Maughan, D., Schertler, M., Schneider, M., and Turner, J.,
+"Internet Security Association and Key Management Protocol (ISAKMP)",
+RFC 2408, Nov 1998.
+.R OE
+Richardson, M., Redelmeier, D. H., and Spencer, H.,
+"A method for doing opportunistic encryption with IKE",
+<draft-richardson-ipsec-opportunistic-06.txt>,
+21 Feb 2002 (work in progress).
+.R PKCS1v1
+Kaliski, B.,
+"PKCS #1: RSA Encryption, Version 1.5",
+RFC 2313, March 1998.
+.R PKCS1v2
+Kaliski, B., and Staddon, J.,
+"PKCS #1: RSA Cryptography Specifications, Version 2.0",
+RFC 2437, Oct 1998.
+.R PFKEY
+McDonald, D., Metz, C., and Phan, B.,
+"PF_KEY Key Management API, Version 2",
+RFC 2367, July 1998.
+.R REKEY
+Tim Jenkins, "IPsec Re-keying Issues",
+<draft-jenkins-ipsec-rekeying-06.txt>,
+2 May 2000 (draft expired, work no longer in progress).
+.R REPLAY
+Krywaniuk, A.,
+"Using Isakmp Message Ids for Replay Protection",
+<draft-krywaniuk-ipsec-antireplay-00.txt>,
+9 July 2001
+(work in progress).
+.R RSA
+Rivest, R.L., Shamir, A., and Adleman, L.,
+"A Method for Obtaining Digital Signatures and Public-Key
+Cryptosystems",
+Communications of the ACM v21n2, Feb 1978, p. 120.
+.R SCHNEIER
+Bruce Schneier, "Applied Cryptography", 2nd ed.,
+Wiley 1996, ISBN 0-471-11709-9.
+.R SECFAIL
+Karn, P., and Simpson, W.,
+"ICMP Security Failures Messages",
+RFC 2521,
+March 1999.
+.H
+Authors' Addresses
+.P
+.nf
+.ne 8
+Henry Spencer
+SP Systems
+Box 280 Stn. A
+Toronto, Ont. M5W1B2
+Canada
+
+henry@spsystems.net
+416-690-6561
+.ne 8
+.sp 2
+D. Hugh Redelmeier
+Mimosa Systems Inc.
+29 Donino Ave.
+Toronto, Ont. M4N2W6
+Canada
+
+hugh@mimosa.com
+416-482-8253
+.bp
+.H
+Full Copyright Statement
+.P
+Copyright (C) The Internet Society \*c. All Rights
+Reserved.
+
+This document and translations of it may be copied and
+furnished to others, and derivative works that comment on or
+otherwise explain it or assist in its implmentation may be
+prepared, copied, published and distributed, in whole or in
+part, without restriction of any kind, provided that the above
+copyright notice and this paragraph are included on all such
+copies and derivative works. However, this document itself may
+not be modified in any way, such as by removing the copyright
+notice or references to the Internet Society or other Internet
+organizations, except as needed for the purpose of developing
+Internet standards in which case the procedures for copyrights
+defined in the Internet Standards process must be followed, or
+as required to translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will
+not be revoked by the Internet Society or its successors or
+assigns.
+
+This document and the information contained herein is provided
+on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET
+ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE
+OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY
+IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
+PARTICULAR PURPOSE.
diff --git a/doc/draft-spencer-ipsec-ike-implementation.txt b/doc/draft-spencer-ipsec-ike-implementation.txt
new file mode 100644
index 000000000..145c00ba8
--- /dev/null
+++ b/doc/draft-spencer-ipsec-ike-implementation.txt
@@ -0,0 +1,1232 @@
+
+
+
+Network Working Group Henry Spencer
+Internet Draft SP Systems
+Expires: 26 Aug 2002 D. Hugh Redelmeier
+ Mimosa Systems
+ 26 Feb 2002
+
+ IKE Implementation Issues
+ <draft-spencer-ipsec-ike-implementation-02.txt>
+
+Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of RFC2026.
+
+ (If approved as an Informational RFC...) This memo provides
+ information for the Internet community. This memo does not specify
+ an Internet standard of any kind.
+
+ Distribution of this memo is unlimited.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working groups. Note that
+ other groups may also distribute working documents as Internet-
+ Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt.
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ This Internet-Draft will expire on 26 Aug 2002.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society 2002. All Rights Reserved.
+
+
+
+
+
+
+
+
+
+
+Spencer & Redelmeier [Page 1]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+Table of Contents
+
+ 1. Introduction ................................................... 3
+ 2. Lower-level Background and Notes ............................... 4
+ 2.1. Packet Handling .............................................. 4
+ 2.2. Ciphers ...................................................... 5
+ 2.3. Interfaces ................................................... 5
+ 3. IKE Infrastructural Issues ..................................... 5
+ 3.1. Continuous Channel ........................................... 5
+ 3.2. Retransmission ............................................... 5
+ 3.3. Replay Prevention ............................................ 6
+ 4. Basic Keying and Rekeying ...................................... 7
+ 4.1. When to Create SAs ........................................... 7
+ 4.2. When to Rekey ................................................ 8
+ 4.3. Choosing an SA ............................................... 9
+ 4.4. Why to Rekey ................................................. 9
+ 4.5. Rekeying ISAKMP SAs ......................................... 10
+ 4.6. Bulk Negotiation ............................................ 10
+ 5. Deletions, Teardowns, Crashes ................................. 11
+ 5.1. Deletions ................................................... 11
+ 5.2. Teardowns and Shutdowns ..................................... 12
+ 5.3. Crashes ..................................................... 13
+ 5.4. Network Partitions .......................................... 13
+ 5.5. Unknown SAs ................................................. 14
+ 6. Misc. IKE Issues .............................................. 16
+ 6.1. Groups 1 and 5 .............................................. 16
+ 6.2. To PFS Or Not To PFS ........................................ 16
+ 6.3. Debugging Tools, Lack Thereof ............................... 16
+ 6.4. Terminology, Vagueness Thereof .............................. 17
+ 6.5. A Question of Identity ...................................... 17
+ 6.6. Opportunistic Encryption .................................... 17
+ 6.7. Authentication and RSA Keys ................................. 17
+ 6.8. Misc. Snags ................................................. 18
+ 7. Security Considerations ....................................... 19
+ 8. References .................................................... 19
+ Authors' Addresses ............................................... 20
+ Full Copyright Statement ......................................... 21
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Spencer & Redelmeier [Page 2]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+Abstract
+
+ The current IPsec specifications for key exchange and connection
+ management, RFCs 2408 [ISAKMP] and 2409 [IKE], leave many aspects of
+ connection management unspecified, most prominently rekeying
+ practices. Pending clarifications in future revisions of the
+ specifications, this document sets down some successful experiences,
+ to minimize the extent to which new implementors have to rely on
+ unwritten folklore.
+
+ The Linux FreeS/WAN implementation of IPsec interoperates with almost
+ every other IPsec implementation. This document describes how the
+ FreeS/WAN project has resolved some of the gaps in the IPsec
+ specifications (and plans to resolve some others), and what
+ difficulties have been encountered, in hopes that this generally-
+ successful experience might be informative to new implementors.
+
+ This is offered as an Informational RFC.
+
+ This -02 revision mainly: discusses ISAKMP SA expiry during IPsec-SA
+ rekeying (4.5), revises the discussion of bidirectional Deletes
+ (5.1), suggests remembering the parameters of successful negotiations
+ for later use (4.2, 5.3), notes an unsuccessful negotiation from the
+ other end as a hint of a possibly broken connection (5.5), and adds
+ sections on network partitions (5.4), authentication methods and the
+ subtleties of RSA public keys (6.7), and miscellaneous
+ interoperability concerns (6.8).
+
+1. Introduction
+
+ The current IPsec specifications for key exchange and connection
+ management, RFCs 2408 [ISAKMP] and 2409 [IKE], leave many aspects of
+ connection management unspecified, most prominently rekeying
+ practices. This is a cryptic puzzle which each group of implementors
+ has to struggle with, and differences in how the ambiguities and gaps
+ are resolved are potentially a fruitful source of interoperability
+ problems. We can hope that future revisions of the specifications
+ will clear this up. Meanwhile, it seems useful to set down some
+ successful experiences, to minimize the extent to which new
+ implementors have to rely on unwritten folklore.
+
+ The Linux FreeS/WAN implementation of IPsec interoperates with almost
+ every other IPsec implementation, and because of its free nature, it
+ also sees some use as a reference implementation by other
+ implementors. The high degree of interoperability is noteworthy
+ given its organizers' strong minimalist bias, which has caused them
+ to implement only a small subset of the full glory of IPsec. This
+ document describes how the FreeS/WAN project has resolved some of the
+
+
+
+Spencer & Redelmeier [Page 3]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ gaps in the IPsec specifications (and plans to resolve some others),
+ and what difficulties have been encountered, in hopes that this
+ generally-successful experience might be informative to new
+ implementors.
+
+ One small caution about applicability: this experience may not be
+ relevant to severely resource-constrained implementations.
+ FreeS/WAN's target environment is previous-generation PCs, now
+ available at trivial cost (often, within an organization, at no
+ cost), which have quite impressive CPU power and memory by the
+ standards of only a few years ago. Some of the approaches discussed
+ here may be inapplicable to implementations with severe external
+ constraints which prevent them from taking advantage of modern
+ hardware technology.
+
+2. Lower-level Background and Notes
+
+2.1. Packet Handling
+
+ FreeS/WAN implements ESP [ESP] and AH [AH] straightforwardly,
+ although AH sees little use among our users. Our ESP/AH
+ implementation cannot currently handle packets with IP options;
+ somewhat surprisingly, this has caused little difficulty. We insist
+ on encryption and do not support authentication-only connections, and
+ this has not caused significant difficulty either.
+
+ MTU and fragmentation issues, by contrast, have been a constant
+ headache. We will not describe the details of our current approach
+ to them, because it still needs work. One difficulty we have
+ encountered is that many combinations of packet source and packet
+ destination apparently cannot cope with an "interior minimum" in the
+ path MTU, e.g. where an IPsec tunnel intervenes and its headers
+ reduce the MTU for an intermediate link. This is particularly
+ prevalent when using common PC software to connect to large well-
+ known web sites; we think it is largely due to misconfigured
+ firewalls which do not pass ICMP Fragmentation Required messages.
+ The only solution we have yet found is to lie about the MTU of the
+ tunnel, accepting the (undesirable) fragmentation of the ESP packets
+ for the sake of preserving connectivity.
+
+ We currently zero out the TOS field of ESP packets, rather than
+ copying it from the inner header, on the grounds that it lends itself
+ too well to traffic analysis and covert channels. We provide an
+ option to restore RFC 2401 [IPSEC] copying behavior, but this appears
+ to see little use.
+
+
+
+
+
+
+Spencer & Redelmeier [Page 4]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+2.2. Ciphers
+
+ We initially implemented both DES [DES] and 3DES [CIPHERS] for both
+ IKE and ESP, but after the Deep Crack effort [CRACK] demonstrated its
+ inherent insecurity, we dropped support for DES. Somewhat
+ surprisingly, our insistence on 3DES has caused almost no
+ interoperability problems, despite DES being officially mandatory. A
+ very few other systems either do not support 3DES or support it only
+ as an optional upgrade, which inconveniences a few would-be users.
+ There have also been one or two cases of systems which don't quite
+ seem to know the difference!
+
+ See also section 6.1 for a consequence of our insistence on 3DES.
+
+2.3. Interfaces
+
+ We currently employ PF_KEY version 2 [PFKEY], plus various non-
+ standard extensions, as our interface between keying and ESP. This
+ has not proven entirely satisfactory. Our feeling now is that keying
+ issues and policy issues do not really lend themselves to the clean
+ separation that PF_KEY envisions.
+
+3. IKE Infrastructural Issues
+
+ A number of problems in IPsec connection management become easier if
+ some attention is first paid to providing an infrastructure to
+ support solving them.
+
+3.1. Continuous Channel
+
+ FreeS/WAN uses an approximation to the "continuous channel" model, in
+ which ISAKMP SAs are maintained between IKEs so long as any IPsec SAs
+ are open between the two systems. The resource consumption of this
+ is minor: the only substantial overhead is occasional rekeying.
+ IPsec SA management becomes significantly simpler if there is always
+ a channel for transmission of control messages. We suggest (although
+ we do not yet fully implement this) that inability to maintain (e.g.,
+ to rekey) this control path should be grounds for tearing down the
+ IPsec SAs as well.
+
+ As a corollary of this, there is one and only one ISAKMP SA
+ maintained between a pair of IKEs (although see sections 5.3 and 6.5
+ for minor complications).
+
+3.2. Retransmission
+
+ The unreliable nature of UDP transmission is a nuisance. IKE
+ implementations should always be prepared to retransmit the most
+
+
+
+Spencer & Redelmeier [Page 5]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ recent message they sent on an ISAKMP SA, since there is some
+ possibility that the other end did not get it. This means, in
+ particular, that the system sending the supposedly-last message of an
+ exchange cannot relax and assume that the exchange is complete, at
+ least not until a significant timeout has elapsed.
+
+ Systems must also retain information about the message most recently
+ received in an exchange, so that a duplicate of it can be detected
+ (and possibly interpreted as a NACK for the response).
+
+ The retransmission rules FreeS/WAN follows are: (1) if a reply is
+ expected, retransmit only if it does not appear before a timeout; and
+ (2) if a reply is not expected (last message of the exchange),
+ retransmit only on receiving a retransmission of the previous
+ message. Notably, in case (1) we do NOT retransmit on receiving a
+ retransmission, which avoids possible congestion problems arising
+ from packet duplication, at the price of slowing response to packet
+ loss. The timeout for case (1) is 10 seconds for the first retry, 20
+ seconds for the second, and 40 seconds for all subsequent retries
+ (normally only one, except when configuration settings call for
+ persistence and the message is the first message of Main Mode with a
+ new peer). These retransmission rules have been entirely successful.
+
+ (Michael Thomas of Cisco has pointed out that the retry timeouts
+ should include some random jitter, to de-synchronize hosts which are
+ initially synchronized by, e.g., a power outage. We already jitter
+ our rekeying times, as noted in section 4.2, but that does not help
+ with initial startup. We're implementing jittered retries, but
+ cannot yet report on experience with this.)
+
+ There is a deeper problem, of course, when an entire "exchange"
+ consists of a single message, e.g. the ISAKMP Informational Exchange.
+ Then there is no way to decide whether or when a retransmission is
+ warranted at all. This seems like poor design, to put it mildly (and
+ there is now talk of fixing it). We have no experience in dealing
+ with this problem at this time, although it is part of the reason why
+ we have delayed implementing Notification messages.
+
+3.3. Replay Prevention
+
+ The unsequenced nature of UDP transmission is also troublesome,
+ because it means that higher levels must consider the possibility of
+ replay attacks. FreeS/WAN takes the position that systematically
+ eliminating this possibility at a low level is strongly preferable to
+ forcing careful consideration of possible impacts at every step of an
+ exchange. RFC 2408 [ISAKMP] section 3.1 states that the Message ID
+ of an ISAKMP message must be "unique". FreeS/WAN interprets this
+ literally, as forbidding duplication of Message IDs within the set of
+
+
+
+Spencer & Redelmeier [Page 6]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ all messages sent via a single ISAKMP SA.
+
+ This requires remembering all Message IDs until the ISAKMP SA is
+ superseded by rekeying, but that is not costly (four bytes per sent
+ or received message), and it ELIMINATES replay attacks from
+ consideration; we believe this investment of resources is well
+ worthwhile. If the resource consumption becomes excessive--in our
+ experience it has not--the ISAKMP SA can be rekeyed early to collect
+ the garbage.
+
+ There is theoretically an interoperability problem when talking to
+ implementations which interpret "unique" more loosely and may re-use
+ Message IDs, but it has not been encountered in practice. This
+ approach appears to be completely interoperable.
+
+ The proposal by Andrew Krywaniuk [REPLAY], which advocates turning
+ the Message ID into an anti-replay counter, would achieve the same
+ goal without the minor per-message memory overhead. This may be
+ preferable, although it means an actual protocol change and more
+ study is needed.
+
+4. Basic Keying and Rekeying
+
+4.1. When to Create SAs
+
+ As Tim Jenkins [REKEY] pointed out, there is a potential race
+ condition in Quick Mode: a fast lightly-loaded Initiator might start
+ using IPsec SAs very shortly after sending QM3 (the third and last
+ message of Quick Mode), while a slow heavily-loaded Responder might
+ not be ready to receive them until after spending a significant
+ amount of time creating its inbound SAs. The problem is even worse
+ if QM3 gets delayed or lost.
+
+ FreeS/WAN's approach to this is what Jenkins called "Responder Pre-
+ Setup": the Responder creates its inbound IPsec SAs before it sends
+ QM2, so they are always ready and waiting when the Initiator sends
+ QM3 and begins sending traffic. This approach is simple and
+ reliable, and in our experience it interoperates with everybody.
+ (There is potentially still a problem if FreeS/WAN is the Initiator
+ and the Responder does not use Responder Pre-Setup, but no such
+ problems have been seen.) The only real weakness of Responder Pre-
+ Setup is the possibility of replay attacks, which we have eliminated
+ by other means (see section 3.3).
+
+ With this approach, the Commit Bit is useless, and we ignore it. In
+ fact, until quite recently we discarded any IKE message containing
+ it, and this caused surprisingly few interoperability problems;
+ apparently it is not widely used. We have recently been persuaded
+
+
+
+Spencer & Redelmeier [Page 7]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ that simply ignoring it is preferable; preliminary experience with
+ this indicates that the result is successful interoperation with
+ implementations which set it.
+
+4.2. When to Rekey
+
+ To preserve connectivity for user traffic, rekeying of a connection
+ (that is, creation of new IPsec SAs to supersede the current ones)
+ must begin before its current IPsec SAs expire. Preferably one end
+ should predictably start rekeying negotiations first, to avoid the
+ extra overhead of two simultaneous negotiations, although either end
+ should be prepared to rekey if the other does not. There is also a
+ problem with "convoys" of keying negotiations: for example, a "hub"
+ gateway with many IPsec connections can be inundated with rekeying
+ negotiations exactly one connection-expiry time after it reboots, and
+ the massive overload this induces tends to make this situation self-
+ perpetuating, so it recurs regularly. (Convoys can also evolve
+ gradually from initially-unsynchronized negotiations.)
+
+ FreeS/WAN has the concept of a "rekeying margin", measured in
+ seconds. If FreeS/WAN was the Initiator for the previous rekeying
+ (or the startup, if none) of the connection, it nominally starts
+ rekeying negotiations at expiry time minus one rekeying margin. Some
+ random jitter is added to break up convoys: rather than starting
+ rekeying exactly at minus one margin, it starts at a random time
+ between minus one margin and minus two margins. (The randomness here
+ need not be cryptographic in quality, so long as it varies over time
+ and between hosts. We use an ordinary PRNG seeded with a few bytes
+ from a cryptographic randomness source. The seeding mostly just
+ ensures that the PRNG sequence is different for different hosts, even
+ if they start up simultaneously.)
+
+ If FreeS/WAN was the Responder for the previous rekeying/startup, and
+ nothing has been heard from the previous Initiator at expiry time
+ minus one-half the rekeying margin, FreeS/WAN will initiate rekeying
+ negotiations. No jitter is applied; we now believe that it should be
+ jittered, say between minus one-half margin and minus one-quarter
+ margin.
+
+ Having the Initiator lead the way is an obvious way of deciding who
+ should speak first, since there is already an Initiator/Responder
+ asymmetry in the connection. Moreover, our experience has been that
+ Initiator lead gives a significantly higher probability of successful
+ negotiation! The negotiation process itself is asymmetric, because
+ the Initiator must make a few specific proposals which the Responder
+ can only accept or reject, so the Initiator must try to guess where
+ its "acceptable" region (in parameter space) might overlap with the
+ Responder's. We have seen situations where negotiations would
+
+
+
+Spencer & Redelmeier [Page 8]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ succeed or fail depending on which end initiated them, because one
+ end was making better guesses. Given an existing connection, we KNOW
+ that the previous Initiator WAS able to initiate a successful
+ negotiation, so it should (if at all possible) take the lead again.
+ Also, the Responder should remember the Initiator's successful
+ proposal, and start from that rather than from his own default
+ proposals if he must take the lead; we don't currently implement this
+ completely but plan to.
+
+ FreeS/WAN defaults the rekeying margin to 9 minutes, although this
+ can be changed by configuration. There is also a configuration
+ option to alter the permissible range of jitter. The defaults were
+ chosen somewhat arbitrarily, but they work extremely well and the
+ configuration options are rarely used.
+
+4.3. Choosing an SA
+
+ Once rekeying has occurred, both old and new IPsec SAs for the
+ connection exist, at least momentarily. FreeS/WAN accepts incoming
+ traffic on either old or new inbound SAs, but sends outgoing traffic
+ only on the new outbound ones. This approach appears to be
+ significantly more robust than using the old ones until they expire,
+ notably in cases where renegotiation has occurred because something
+ has gone wrong on the other end. It avoids having to pay meticulous
+ attention to the state of the other end, state which is difficult to
+ learn reliably given the limitations of IKE.
+
+ This approach has interoperated successfully with ALMOST all other
+ implementations. The only (well-characterized) problem cases have
+ been implementations which rely on receiving a Delete message for the
+ old SAs to tell them to switch over to the new ones. Since delivery
+ of Delete is unreliable, and support for Delete is optional, this
+ reliance seems like a serious mistake. This is all the more true
+ because Delete announces that the deletion has already occurred
+ [ISAKMP, section 3.15], not that it is about to occur, so packets
+ already in transit in the other direction could be lost. Delete
+ should be used for resource cleanup, not for switchover control.
+ (These matters are discussed further in section 5.)
+
+4.4. Why to Rekey
+
+ FreeS/WAN currently implements only time-based expiry (life in
+ seconds), although we are working toward supporting volume-based
+ expiry (life in kilobytes) as well. The lack of volume-based expiry
+ has not been an interoperability problem so far.
+
+ Volume-based expiry does add some minor complications. In
+ particular, it makes explicit Delete of now-disused SAs more
+
+
+
+Spencer & Redelmeier [Page 9]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ important, because once an SA stops being used, it might not expire
+ on its own. We believe this lacks robustness and is generally
+ unwise, especially given the lack of a reliable Delete, and expect to
+ use volume-based expiry only as a supplement to time-based expiry.
+ However, Delete support (see section 5) does seem advisable for use
+ with volume-based expiry.
+
+ We do not believe that volume-based expiry alters the desirability of
+ switching immediately to the new SAs after rekeying. Rekeying
+ margins are normally a small fraction of the total life of an SA, so
+ we feel there is no great need to "use it all up".
+
+4.5. Rekeying ISAKMP SAs
+
+ The above discussion has focused on rekeying for IPsec SAs, but
+ FreeS/WAN applies the same approaches to rekeying for ISAKMP SAs,
+ with similar success.
+
+ One issue which we have noticed, but not explicitly dealt with, is
+ that difficulties may ensue if an IPsec-SA rekeying negotiation is in
+ progress at the time when the relevant ISAKMP SA gets rekeyed. The
+ IKE specification [IKE] hints, but does not actually say, that a
+ Quick Mode negotiation should remain on a single ISAKMP SA
+ throughout.
+
+ A reasonable rekeying margin will generally prevent the old ISAKMP SA
+ from actually expiring during a negotiation. Some attention may be
+ needed to prevent in-progress negotiations from being switched to the
+ new ISAKMP SA. Any attempt at pre-expiry deletion of the ISAKMP SA
+ must be postponed until after such dangling negotiations are
+ completed, and there should be enough delay between ISAKMP-SA
+ rekeying and a deletion attempt to (more or less) ensure that there
+ are no negotiation-starting packets still in transit from before the
+ rekeying.
+
+ At present, FreeS/WAN does none of this, and we don't KNOW of any
+ resulting trouble. With normal lifetimes, the problem should be
+ uncommon, and we speculate that an occasional disrupted negotiation
+ simply gets retried.
+
+4.6. Bulk Negotiation
+
+ Quick Mode nominally provides for negotiating possibly-large numbers
+ of similar but unrelated IPsec SAs simultaneously [IKE, section 9].
+ Nobody appears to do this. FreeS/WAN does not support it, and its
+ absence has caused no problems.
+
+
+
+
+
+Spencer & Redelmeier [Page 10]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+5. Deletions, Teardowns, Crashes
+
+ FreeS/WAN currently ignores all Notifications and Deletes, and never
+ generates them. This has caused little difficulty in
+ interoperability, which shouldn't be surprising (since Notification
+ and Delete support is officially entirely optional) but does seem to
+ surprise some people. Nevertheless, we do plan some changes to this
+ approach based on past experience.
+
+5.1. Deletions
+
+ As hinted at above, we plan to implement Delete support, done as
+ follows. Shortly after rekeying of IPsec SAs, the Responder issues a
+ Delete for its old inbound SAs (but does not actually delete them
+ yet). The Responder initiates this because the Initiator started
+ using the new SAs on sending QM3, while the Responder started using
+ them only on (or somewhat after) receiving QM3, so there is less
+ chance of old-SA packets still being in transit from the Initiator.
+ The Initiator issues an unsolicited Delete only if it does not hear
+ one from the Responder after a longer delay.
+
+ Either party, on receiving a Delete for one or more of the old
+ outbound SAs of a connection, deletes ALL the connection's SAs, and
+ acknowledges with a Delete for the old inbound SAs. A Delete for
+ nonexistent SAs (e.g., SAs which have already been expired or
+ deleted) is ignored. There is no retransmission of unacknowledged
+ Deletes.
+
+ In the normal case, with prompt reliable transmission (except
+ possibly for loss of the Responder's initial Delete) and conforming
+ implementations on both ends, this results in three Deletes being
+ transmitted, resembling the classic three-way handshake. Loss of a
+ Delete after the first, or multiple losses, will cause the SAs not to
+ be deleted on at least one end. It appears difficult to do much
+ better without at least a distinction between request and
+ acknowledgement.
+
+ RFC 2409 section 9 "strongly suggests" that there be no response to
+ informational messages such as Deletes, but the only rationale
+ offered is prevention of infinite loops endlessly exchanging "I don't
+ understand you" informationals. Since Deletes cannot lead to such a
+ loop (and in any case, the nonexistent-SA rule prevents more than one
+ acknowledgement for the same connection), we believe this
+ recommendation is inapplicable here.
+
+ As noted in section 4.3, these Deletes are intended for resource
+ cleanup, not to control switching between SAs. But we expect that
+ they will improve interoperability with some broken implementations.
+
+
+
+Spencer & Redelmeier [Page 11]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ We believe strongly that connections need to be considered as a
+ whole, rather than treating each SA as an independent entity. We
+ will issue Deletes only for the full set of inbound SAs of a
+ connection, and will treat a Delete for any outbound SA as equivalent
+ to deletion of all the outbound SAs for the associated connection.
+
+ The above is phrased in terms of IPsec SAs, but essentially the same
+ approach can be applied to ISAKMP SAs (the Deletes for the old ISAKMP
+ SA should be sent via the new one).
+
+5.2. Teardowns and Shutdowns
+
+ When a connection is not intended to be up permanently, there is a
+ need to coordinate teardown, so that both ends are aware that the
+ connection is down. This is both for recovery of resources, and to
+ avoid routing packets through dangling SAs which can no longer
+ deliver them.
+
+ Connection teardown will use the same bidirectional exchange of
+ Deletes as discussed in section 5.1: a Delete received for current
+ IPsec SAs (not yet obsoleted by rekeying) indicates that the other
+ host wishes to tear down the associated connection.
+
+ A Delete received for a current ISAKMP SA indicates that the other
+ host wishes to tear down not only the ISAKMP SA but also all IPsec
+ SAs currently under the supervision of that ISAKMP SA. The 5.1
+ bidirectional exchange might seem impossible in this case, since
+ reception of an ISAKMP-SA Delete indicates that the other end will
+ ignore further traffic on that ISAKMP SA. We suggest using the same
+ tactic discussed in 5.1 for IPsec SAs: the first Delete is sent
+ without actually doing the deletion, and the response to receiving a
+ Delete is to do the deletion and reply with another Delete. If there
+ is no response to the first Delete, retry a small number of times and
+ then give up and do the deletion; apart from being robust against
+ packet loss, this also maximizes the probability that an
+ implementation which does not do the bidirectional Delete will
+ receive at least one of the Deletes.
+
+ When a host with current connections knows that it is about to shut
+ down, it will issue Deletes for all SAs involved (both IPsec and
+ ISAKMP), advising its peers (as per the meaning of Delete [ISAKMP,
+ section 3.15]) that the SAs have become useless. It will ignore
+ attempts at rekeying or connection startup thereafter, until it shuts
+ down.
+
+ It would be better to have a Final-Contact notification, analogous to
+ Initial-Contact but indicating that no new negotiations should be
+ attempted until further notice. Initial-Contact actually could be
+
+
+
+Spencer & Redelmeier [Page 12]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ used for shutdown notification (!), but in networks where connections
+ are intended to exist permanently, it seems likely to provoke
+ unwanted attempts to renegotiate the lost connections.
+
+5.3. Crashes
+
+ Systems sometimes crash. Coping with the resulting loss of
+ information is easily the most difficult problem we have found in
+ implementing robust IPsec systems.
+
+ When connections are intended to be permanent, it is simple to
+ specify renegotiation on reboot. With our approach to SA selection
+ (see section 4.3), this handles such cases robustly and well. We do
+ have to tell users that BOTH hosts should be set this way. In cases
+ where crashes are synchronized (e.g. by power interruptions), this
+ may result in simultaneous negotiations at reboot. We currently
+ allow both negotiations to proceed to completion, but our use-newest
+ selection method effectively ignores one connection or the other, and
+ when one of them rekeys, we notice that the new SAs replace those of
+ both old connections, and we then refrain from rekeying the other.
+ (This duplicate detection is desirable in any event, for robustness,
+ to ensure that the system converges on a reasonable state eventually
+ after it is perturbed by difficulties or bugs.)
+
+ When connections are not permanent, the situation is less happy. One
+ particular situation in which we see problems is when a number of
+ "Road Warrior" hosts occasionally call in to a central server. The
+ server is normally configured not to initiate such connections, since
+ it does not know when the Road Warrior is available (or what IP
+ address it is using). Unfortunately, if the server crashes and
+ reboots, any Road Warriors then connected have a problem: they don't
+ know that the server has crashed, so they can't renegotiate, and the
+ server has forgotten both the connections and their (transient) IP
+ addresses, so it cannot renegotiate.
+
+ We believe that the simplest answer to this problem is what John
+ Denker has dubbed "address inertia": the server makes a best-effort
+ attempt to remember (in nonvolatile storage) which connections were
+ active and what the far-end addresses were (and what the successful
+ proposal's parameters were), so that it can attempt renegotiation on
+ reboot. We have not implemented this yet, but intend to; Denker has
+ implemented it himself, although in a somewhat messy way, and reports
+ excellent results.
+
+5.4. Network Partitions
+
+ A network partition, making the two ends unable to reach each other,
+ has many of the same characteristics as having the other end crash...
+
+
+
+Spencer & Redelmeier [Page 13]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ until the network reconnects. It is desirable that recovery from
+ this be automatic.
+
+ If the network reconnects before any rekeying attempts or other IKE
+ activities occurred, recovery is fully transparent, because the IKEs
+ have no idea that there was any problem. (Complaints such as ICMP
+ Host Unreachable messages are unauthenticated and hence cannot be
+ given much weight.) This fits the general mold of TCP/IP: if nobody
+ wanted to send any traffic, a network outage doesn't matter.
+
+ If IKE activity did occur, the IKE implementation will discover that
+ the other end doesn't seem to be responding. The preferred response
+ to this depends on the nature of the connection. If it was intended
+ to be ephemeral (e.g. opportunistic encryption [OE]), closing it down
+ after a few retries is reasonable. If the other end is expected to
+ sometimes drop the connection without warning, it may not be
+ desirable to retry at all. (We support both these forms of
+ configurability, and indeed we also have a configuration option to
+ suppress rekeying entirely on one end.)
+
+ If the connection was intended to be permanent, however, then
+ persistent attempts to re-establish it are appropriate. Some degree
+ of backoff is appropriate here, so that retries get less frequent as
+ the outage gets prolonged. Backoff should be limited, so that re-
+ established connectivity is not followed by a long delay before a
+ retry. Finally, after many retries (say 24 hours' worth), it may be
+ preferable to just declare the connection down and rely on manual
+ intervention to re-establish it, should this be desirable. We do not
+ yet fully support all this.
+
+5.5. Unknown SAs
+
+ A more complete solution to crashes would be for an IPsec host to
+ note the arrival of ESP packets on an unknown IPsec SA, and report it
+ somehow to the other host, which can then decide to renegotiate.
+ This arguably might be preferable in any case--if the non-rebooted
+ host has no traffic to send, it does not care whether the connection
+ is intact--but delays and packet loss will be reduced if the
+ connection is renegotiated BEFORE there is traffic for it. So
+ unknown-SA detection is best reserved as a fallback method, with
+ address inertia used to deal with most such cases.
+
+ A difficulty with unknown-SA detection is, just HOW should the other
+ host be notified? IKE provides no good way to do the notification:
+ Notification payloads (e.g., Initial-Contact) are unauthenticated
+ unless they are sent under protection of an ISAKMP SA. A "Security
+ Failures - Bad SPI" ICMP message [SECFAIL] is an interesting
+ alternative, but has the disadvantage of likewise being
+
+
+
+Spencer & Redelmeier [Page 14]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ unauthenticated. It's fundamentally unlikely that there is a simple
+ solution to this, given that almost any way of arranging or checking
+ authentication for such a notification is costly.
+
+ We think the best answer to this is a two-step approach. An
+ unauthenticated Initial-Contact or Security Failures - Bad SPI cannot
+ be taken as a reliable report of a problem, but can be taken as a
+ hint that a problem MIGHT exist. Then there needs to be some
+ reliable way of checking such hints, subject to rate limiting since
+ the checks are likely to be costly (and checking the same connection
+ repeatedly at short intervals is unlikely to be worthwhile anyway).
+ So the rebooted host sends the notification, and the non-rebooted
+ host--which still thinks it has a connection--checks whether the
+ connection still works, and renegotiates if not.
+
+ Also, if an IPsec host which believes it has a connection to another
+ host sees an unsuccessful attempt by that host to negotiate a new
+ one, that is also a hint of possible problems, justifying a check and
+ possible renegotiation. ("Unsuccessful" here means a negotiation
+ failure due to lack of a satisfactory proposal. A failure due to
+ authentication failure suggests a denial-of-service attack by a third
+ party, rather than a genuine problem on the legitimate other end.)
+ As noted in section 4.2, it is possible for negotiations to succeed
+ or fail based on which end initiates them, and some robustness
+ against that is desirable.
+
+ We have not yet decided what form the notification should take. IKE
+ Initial-Contact is an obvious possibility, but has some
+ disadvantages. It does not specify which connection has had
+ difficulties. Also, the specification [IKE section 4.6.3.3] refers
+ to "remote system" and "sending system" without clearly specifying
+ just what "system" means; in the case of a multi-homed host using
+ multiple forms of identification, the question is not trivial.
+ Initial-Contact does have the fairly-decisive advantage that it is
+ likely to convey the right general meaning even to an implementation
+ which does not do things exactly the way ours does.
+
+ A more fundamental difficulty is what form the reliable check takes.
+ What is wanted is an "IKE ping", verifying that the ISAKMP SA is
+ still intact (it being unlikely that IPsec SAs have been lost while
+ the ISAKMP SA has not). The lack of such a facility is a serious
+ failing of IKE. An acknowledged Notification of some sort would be
+ ideal, but there is none at present. Some existing implementations
+ are known to use the private Notification values 30000 as ping and
+ 30002 as ping reply, and that seems the most attractive choice at
+ present. If it is not recognized, there will probably be no reply,
+ and the result will be an unnecessary renegotiation, so this needs
+ strict rate limiting. (Also, when a new connection is set up, it's
+
+
+
+Spencer & Redelmeier [Page 15]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ probably worth determining by experiment whether the other end
+ supports IKE ping, and remembering that.)
+
+ While we think this facility is desirable, and is about the best that
+ can be done with the poor tools available, we have not gotten very
+ far in implementation and cannot comment intelligently about how well
+ it works or interoperates.
+
+6. Misc. IKE Issues
+
+6.1. Groups 1 and 5
+
+ We have dropped support for the first Oakley Group (group 1), despite
+ it being officially mandatory, on the grounds that it is grossly too
+ weak to provide enough randomness for 3DES. There have been some
+ interoperability problems, mostly quite minor: ALMOST everyone
+ supports group 2 as well, although sometimes it has to be explicitly
+ configured.
+
+ We also support the quasi-standard group 5 [GROUPS]. This has not
+ been seriously exercised yet, because historically we offered group 2
+ first and almost everyone accepted it. We have recently changed to
+ offering group 5 first, and no difficulties have been reported.
+
+6.2. To PFS Or Not To PFS
+
+ A persistent small interoperability problem is that the presence or
+ absence of PFS (for keys [IKE, section 5.5]) is neither negotiated
+ nor announced. We have it enabled by default, and successful
+ interoperation often requires having the other end turn it on in
+ their implementation, or having the FreeS/WAN end disable it. Almost
+ everyone supports it, but it's usually not the default, and
+ interoperability is often impossible unless the two ends somehow
+ reach prior agreement on it.
+
+ We do not explicitly support the other flavor of PFS, for identities
+ [IKE, section 8], and this has caused no interoperability problems.
+
+6.3. Debugging Tools, Lack Thereof
+
+ We find IKE lacking in basic debugging tools. Section 5.4, above,
+ notes that an IKE ping would be useful for connectivity verification.
+ It would also be extremely helpful for determining that UDP/500
+ packets get back and forth successfully between the two ends, which
+ is often an important first step in debugging.
+
+ It's also quite common to have IKE negotiate a connection
+ successfully, but to have some firewall along the way blocking ESP.
+
+
+
+Spencer & Redelmeier [Page 16]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ Users find this mysterious and difficult to diagnose. We have no
+ immediate suggestions on what could be done about it.
+
+6.4. Terminology, Vagueness Thereof
+
+ The terminology of IPsec needs work. We feel that both the
+ specifications and user-oriented documentation would be greatly
+ clarified by concise, intelligible names for certain concepts.
+
+ We semi-consistently use "group" for the set of IPsec SAs which are
+ established in one direction by a single Quick Mode negotiation and
+ are used together to process a packet (e.g., an ESP SA plus an AH
+ SA), "connection" for the logical packet path provided by a
+ succession of pairs of groups (each rekeying providing a new pair,
+ one group in each direction), and "keying channel" for the
+ corresponding supervisory path provided by a sequence of ISAKMP SAs.
+
+ We think it's a botch that "PFS" is used to refer to two very
+ different things, but we have no specific new terms to suggest, since
+ we only implement one kind of PFS and thus can just ignore the other.
+
+6.5. A Question of Identity
+
+ One specification problem deserves note: exactly when can an existing
+ phase 1 negotiation be re-used for a new phase 2 negotiation, as IKE
+ [IKE, section 4] specifies? Presumably, when it connects the same
+ two "parties"... but exactly what is a "party"?
+
+ As noted in section 5.4, in cases involving multi-homing and multiple
+ identities, it's not clear exactly what criteria are used for
+ deciding whether the intended far end for a new negotiation is the
+ same one as for a previous negotiation. Is it by Identification
+ Payload? By IP address? Or what?
+
+ We currently use a somewhat-vague notion of "identity", basically
+ what gets sent in Identification Payloads, for this, and this seems
+ to be successful, but we think this needs better specification.
+
+6.6. Opportunistic Encryption
+
+ Further IKE challenges appear in the context of Opportunistic
+ Encryption [OE], but operational experience with it is too limited as
+ yet for us to comment usefully right now.
+
+6.7. Authentication and RSA Keys
+
+ We provide two IKE authentication methods: shared secrets ("pre-
+ shared keys") and RSA digital signatures. (A user-provided add-on
+
+
+
+Spencer & Redelmeier [Page 17]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ package generalizes the latter to limited support for certificates;
+ we have not worked extensively with it ourselves yet and cannot
+ comment on it yet.)
+
+ Shared secrets, despite their administrative difficulties, see
+ considerable use, and are also the method of last resort for
+ interoperability problems.
+
+ For digital signatures, we have taken the somewhat unorthodox
+ approach of using "bare" RSA public keys, either supplied in
+ configuration files or fetched from DNS, rather than getting involved
+ in the complexity of certificates. We encode our RSA public keys
+ using the DNS KEY encoding [DNSRSA] (aka "RFC 2537", although that
+ RFC is now outdated), which has given us no difficulties and which we
+ highly recommend. We have seen two difficulties in connection with
+ RSA keys, however.
+
+ First, while a number of IPsec implementations are able to take
+ "bare" RSA public keys, each one seems to have its own idea of what
+ format should be used for transporting them. We've had little
+ success with interoperability here, mostly because of key-format
+ issues; the implementations generally WILL interoperate successfully
+ if you can somehow get an RSA key into them at all, but that's hard.
+ X.509 certificates seem to be the lowest (!) common denominator for
+ key transfer.
+
+ Second, although the content of RSA public keys has been stable,
+ there has been a small but subtle change over time in the content of
+ RSA private keys. The "internal modulus", used to compute the
+ private exponent "d" from the public exponent "e" (or vice-versa) was
+ originally [RSA] [PKCS1v1] [SCHNEIER] specified to be (p-1)*(q-1),
+ where p and q are the two primes. However, more recent definitions
+ [PKCS1v2] call it "lambda(n)" and define it to be lcm(p-1, q-1); this
+ appears to be a minor optimization. The result is that private keys
+ generated with the new definition often fail consistency checks in
+ implementations using the old definition. Fortunately, it is seldom
+ necessary to move private keys around. Our software now consistently
+ uses the new definition (and thus will accept keys generated with
+ either definition), but our key generator also has an option to
+ generate old-definition keys, for the benefit of users who upgrade
+ their networks incrementally.
+
+6.8. Misc. Snags
+
+ Nonce size is another characteristic that is neither negotiated nor
+ announced but that the two ends must somehow be able to agree on.
+ Our software accepts anything between 8 and 256, and defaults to 16.
+ These numbers were chosen rather arbitrarily, but we have seen no
+
+
+
+Spencer & Redelmeier [Page 18]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ interoperability failures here.
+
+ Nothing in the ISAKMP [ISAKMP] or IKE [IKE] specifications says
+ explicitly that a normal Message ID must be non-zero, but a zero
+ Message ID in fact causes failures.
+
+ Similarly, there is nothing in the specs which says that ISAKMP
+ cookies must be non-zero, but zero cookies will in fact cause
+ trouble.
+
+7. Security Considerations
+
+ Since this document discusses aspects of building robust and
+ interoperable IPsec implementations, security considerations permeate
+ it.
+
+8. References
+
+ [AH] Kent, S., and Atkinson, R., "IP Authentication Header",
+ RFC 2402, Nov 1998.
+
+ [CIPHERS] Pereira, R., and Adams, R., "The ESP CBC-Mode Cipher
+ Algorithms", RFC 2451, Nov 1998.
+
+ [CRACK] Electronic Frontier Foundation, "Cracking DES: Secrets of
+ Encryption Research, Wiretap Politics and Chip Design",
+ O'Reilly 1998, ISBN 1-56592-520-3.
+
+ [DES] Madson, C., and Doraswamy, N., "The ESP DES-CBC Cipher
+ Algorithm", RFC 2405, Nov 1998.
+
+ [DNSRSA] D. Eastlake 3rd, "RSA/SHA-1 SIGs and RSA KEYs in the
+ Domain Name System (DNS)", RFC 3110, May 2001.
+
+ [ESP] Kent, S., and Atkinson, R., "IP Encapsulating Security
+ Payload (ESP)", RFC 2406, Nov 1998.
+
+ [GROUPS] Kivinen, T., and Kojo, M., "More MODP Diffie-Hellman
+ groups for IKE", <draft-ietf-ipsec-ike-modp-
+ groups-04.txt>, 13 Dec 2001 (work in progress).
+
+ [IKE] Harkins, D., and Carrel, D., "The Internet Key Exchange
+ (IKE)", RFC 2409, Nov 1998.
+
+ [IPSEC] Kent, S., and Atkinson, R., "Security Architecture for the
+ Internet Protocol", RFC 2401, Nov 1998.
+
+
+
+
+
+Spencer & Redelmeier [Page 19]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ [ISAKMP] Maughan, D., Schertler, M., Schneider, M., and Turner, J.,
+ "Internet Security Association and Key Management Protocol
+ (ISAKMP)", RFC 2408, Nov 1998.
+
+ [OE] Richardson, M., Redelmeier, D. H., and Spencer, H., "A
+ method for doing opportunistic encryption with IKE",
+ <draft-richardson-ipsec-opportunistic-06.txt>, 21 Feb 2002
+ (work in progress).
+
+ [PKCS1v1] Kaliski, B., "PKCS #1: RSA Encryption, Version 1.5", RFC
+ 2313, March 1998.
+
+ [PKCS1v2] Kaliski, B., and Staddon, J., "PKCS #1: RSA Cryptography
+ Specifications, Version 2.0", RFC 2437, Oct 1998.
+
+ [PFKEY] McDonald, D., Metz, C., and Phan, B., "PF_KEY Key
+ Management API, Version 2", RFC 2367, July 1998.
+
+ [REKEY] Tim Jenkins, "IPsec Re-keying Issues", <draft-jenkins-
+ ipsec-rekeying-06.txt>, 2 May 2000 (draft expired, work no
+ longer in progress).
+
+ [REPLAY] Krywaniuk, A., "Using Isakmp Message Ids for Replay
+ Protection", <draft-krywaniuk-ipsec-antireplay-00.txt>, 9
+ July 2001 (work in progress).
+
+ [RSA] Rivest, R.L., Shamir, A., and Adleman, L., "A Method for
+ Obtaining Digital Signatures and Public-Key
+ Cryptosystems", Communications of the ACM v21n2, Feb 1978,
+ p. 120.
+
+ [SCHNEIER] Bruce Schneier, "Applied Cryptography", 2nd ed., Wiley
+ 1996, ISBN 0-471-11709-9.
+
+ [SECFAIL] Karn, P., and Simpson, W., "ICMP Security Failures
+ Messages", RFC 2521, March 1999.
+
+Authors' Addresses
+
+ Henry Spencer
+ SP Systems
+ Box 280 Stn. A
+ Toronto, Ont. M5W1B2
+ Canada
+
+ henry@spsystems.net
+ 416-690-6561
+
+
+
+
+Spencer & Redelmeier [Page 20]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+ D. Hugh Redelmeier
+ Mimosa Systems Inc.
+ 29 Donino Ave.
+ Toronto, Ont. M4N2W6
+ Canada
+
+ hugh@mimosa.com
+ 416-482-8253
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Spencer & Redelmeier [Page 21]
+
+Internet Draft IKE Implementation Issues 26 Feb 2002
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society 2002. All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implmentation may be prepared, copied, published and
+ distributed, in whole or in part, without restriction of any kind,
+ provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Spencer & Redelmeier [Page 22]
+
diff --git a/doc/examples b/doc/examples
new file mode 100644
index 000000000..315049b04
--- /dev/null
+++ b/doc/examples
@@ -0,0 +1,182 @@
+# sample connections
+# This file is RCSID $Id: examples,v 1.1 2004/03/15 20:35:21 as Exp $
+
+
+
+# basic configuration
+config setup
+ # THIS SETTING MUST BE CORRECT or almost nothing will work.
+ interfaces="ipsec0=eth1 ipsec1=ppp0"
+ # Debug-logging controls: "none" for (almost) none, "all" for lots.
+ klipsdebug=none
+ plutodebug=none
+ # Manual connections to be started at startup.
+ manualstart="test1 test2"
+ # Auto connections to be loaded into Pluto at startup.
+ plutoload="samplehth samplefire"
+ # Auto connections to be started at startup.
+ plutostart=samplefire
+
+
+
+# defaults for subsequent connection descriptions
+conn %default
+ # How persistent to be in (re)keying negotiations (0 means very).
+ keyingtries=0
+ # Parameters for manual-keying testing (DON'T USE OPERATIONALLY).
+ spi=0x200
+ esp=3des-md5-96
+ espenckey=0x01234567_89abcdef_02468ace_13579bdf_12345678_9abcdef0
+ espauthkey=0x12345678_9abcdef0_2468ace0_13579bdf
+ # key lifetime (before automatic rekeying)
+ keylife=8h
+
+
+
+# sample connection
+conn sample
+ # Left security gateway and subnet behind it.
+ left=10.0.0.1
+ leftsubnet=172.16.0.0/24
+ # Right security gateway and subnet behind it.
+ right=10.12.12.1
+ rightsubnet=192.168.0.0/24
+ # Authorize this connection, but don't actually start it, at startup.
+ auto=add
+
+# sample tunnel (manually or automatically keyed)
+# Here we just use ESP for both encryption and authentication, which is
+# the simplest and often the best method.
+conn sample
+ # left security gateway (public-network address)
+ left=10.0.0.1
+ # next hop to reach right
+ leftnexthop=10.44.55.66
+ # subnet behind left (omit if left end of the tunnel is just the s.g.)
+ leftsubnet=172.16.0.0/24
+ # right s.g., subnet behind it, and next hop to reach left
+ right=10.12.12.1
+ rightnexthop=10.88.77.66
+ rightsubnet=192.168.0.0/24
+ # (manual) SPI number
+ spi=0x200
+ # (manual) encryption/authentication algorithm and parameters to it
+ esp=3des-md5-96
+ espenckey=[192 bits]
+ espauthkey=[128 bits]
+
+# In the remaining examples, deviations from the sample-tunnel configuration
+# are marked with ###.
+
+# sample host-to-host tunnel (no subnets)
+# Here we assume (for purposes of illustration) that the hosts talk directly
+# to each other, so we don't need next-hop settings.
+conn samplehth
+ ### left host (public-network address)
+ left=10.0.0.1
+ ### next hop to reach right
+ leftnexthop=
+ ### right host
+ right=10.12.12.1
+ ### next hop to reach left
+ rightnexthop=
+ ### (manual) SPI number
+ spi=0x300
+ # (manual) encryption/authentication algorithm and parameters to it
+ esp=3des-md5-96
+ espenckey=[192 bits]
+ espauthkey=[128 bits]
+
+# sample hybrid tunnel, with a host on one end and a subnet (behind a
+# security gateway) on the other
+# This case is also sometimes called "road warrior".
+conn samplehyb
+ ### left host (public-network address)
+ left=10.0.0.1
+ # next hop to reach right
+ leftnexthop=10.44.55.66
+ # subnet behind left
+ leftsubnet=172.16.0.0/24
+ ### right host, and next hop to reach left
+ right=10.12.12.1
+ rightnexthop=10.88.77.66
+ ### (manual) SPI number
+ spi=0x400
+ # (manual) encryption/authentication algorithm and parameters to it
+ esp=3des-md5-96
+ espenckey=[192 bits]
+ espauthkey=[128 bits]
+
+# sample firewall-penetrating tunnel
+# Here we assume that firewalling is being done on the left side.
+conn samplefire
+ # left security gateway (public-network address)
+ left=10.0.0.1
+ # next hop to reach right
+ leftnexthop=10.44.55.66
+ # subnet behind left (omit if left end of the tunnel is just the s.g.)
+ leftsubnet=172.16.0.0/24
+ ### left is firewalling for its subnet
+ leftfirewall=yes
+ # right s.g., subnet behind it, and next hop to reach left
+ right=10.12.12.1
+ rightnexthop=10.88.77.66
+ rightsubnet=192.168.0.0/24
+ ### (manual) SPI number
+ spi=0x500
+ # (manual) encryption/authentication algorithm and parameters to it
+ esp=3des-md5-96
+ espenckey=[192 bits]
+ espauthkey=[128 bits]
+
+# sample transport-mode connection (which can only be host-to-host)
+# Here we use the whole nine yards, with encryption done by ESP and
+# authentication by AH; this perhaps is slightly preferable for transport
+# mode, where the IP headers are exposed.
+conn sampletm
+ ### transport mode rather than tunnel
+ type=transport
+ ### left host (public-network address)
+ left=10.0.0.1
+ # next hop to reach right
+ leftnexthop=10.44.55.66
+ ### right host, and next hop to reach left
+ right=10.12.12.1
+ rightnexthop=10.88.77.66
+ ### (manual) SPI number
+ spi=0x600
+ ### (manual) encryption algorithm and parameters to it
+ esp=3des
+ espenckey=[192 bits]
+ ### (manual) authentication algorithm and parameters to it
+ ah=hmac-md5
+ ahkey=[128 bits]
+ ### (auto) authentication control
+ auth=ah
+
+# sample description with keys split out into a separate section
+# Normally the key section would go in a separate file, with tighter
+# permissions set on it.
+conn samplesep
+ # left security gateway (public-network address)
+ left=10.0.0.1
+ # next hop to reach right
+ leftnexthop=10.44.55.66
+ # subnet behind left (omit if left end of the tunnel is just the s.g.)
+ leftsubnet=172.16.0.0/24
+ # right s.g., subnet behind it, and next hop to reach left
+ right=10.12.12.1
+ rightnexthop=10.88.77.66
+ rightsubnet=192.168.0.0/24
+ ### (manual) SPI number
+ spi=0x700
+ # (manual) encryption/authentication algorithm and parameters to it
+ esp=3des-md5-96
+ also=samplesep-keys
+
+# keys for the previous section
+# Normally this would go in a separate file, picked up using an include line,
+# to allow keeping the keys confidential.
+conn samplesep-keys
+ espenckey=[192 bits]
+ espauthkey=[128 bits]
diff --git a/doc/faq.html b/doc/faq.html
new file mode 100644
index 000000000..b0fed502e
--- /dev/null
+++ b/doc/faq.html
@@ -0,0 +1,2339 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="policygroups.html">Previous</A>
+<A HREF="manpages.html">Next</A>
+<HR>
+<H1><A NAME="5">FreeS/WAN FAQ</A></H1>
+<P>This is a collection of questions and answers, mostly taken from the
+ FreeS/WAN<A href="mail.html"> mailing list</A>. See the project<A href="http://www.freeswan.org/">
+ web site</A> for more information. All the FreeS/WAN documentation is
+ online there.</P>
+<P>Contributions to the FAQ are welcome. Please send them to the project<A
+href="mail.html"> mailing list</A>.</P>
+<HR>
+<H2><A name="questions">Index of FAQ questions</A></H2>
+<UL>
+<LI><A href="#whatzit">What is FreeS/WAN?</A></LI>
+<LI><A href="#problems">How do I report a problem or seek help?</A></LI>
+<LI><A href="#generic">Can I get ...</A>
+<UL>
+<LI><A href="#lemme_out">... an off-the-shelf system that includes
+ FreeS/WAN?</A></LI>
+<LI><A href="#contractor">... contractors or staff who know FreeS/WAN?</A>
+</LI>
+<LI><A href="#commercial">... commercial support?</A></LI>
+</UL>
+</LI>
+<LI><A href="#release">Release questions</A>
+<UL>
+<LI><A href="#rel.current">What is the current release?</A></LI>
+<LI><A href="#relwhen">When is the next release?</A></LI>
+<LI><A href="#rel.bugs">Are there known bugs in the current release?</A></LI>
+</UL>
+</LI>
+<LI><A href="mod_cons">Modifications and contributions</A>
+<UL>
+<LI><A href="#modify.faq">Can I modify FreeS/WAN to ...?</A></LI>
+<LI><A href="#contrib.faq">Can I contribute to the project?</A></LI>
+<LI><A href="#ddoc.faq">Is there detailed design documentation?</A></LI>
+</UL>
+</LI>
+<LI><A href="#interact">Will FreeS/WAN work in my environment?</A>
+<UL>
+<LI><A href="#interop.faq">Can FreeS/WAN talk to ... ?</A></LI>
+<LI><A href="#old_to_new">Can different FreeS/WAN versions talk to each
+ other?</A></LI>
+<LI><A href="#faq.bandwidth">Is there a limit on throughput?</A></LI>
+<LI><A href="#faq.number">Is there a limit on number of connections?</A></LI>
+<LI><A href="#faq.speed">Is a ... fast enough to handle FreeS/WAN with
+ my loads?</A></LI>
+</UL>
+</LI>
+<LI><A href="#work_on">Will FreeS/WAN work on ...</A>
+<UL>
+<LI><A href="#versions">... my version of Linux?</A></LI>
+<LI><A href="#nonIntel.faq">... non-Intel CPUs?</A></LI>
+<LI><A href="#multi.faq">... multiprocessors?</A></LI>
+<LI><A href="#k.old">... an older kernel?</A></LI>
+<LI><A href="#k.versions">... the latest kernel version?</A></LI>
+<LI><A href="#interface.faq">... unusual network hardware?</A></LI>
+<LI><A href="#vlan">... a VLAN (802.1q) network?</A></LI>
+</UL>
+</LI>
+<LI><A href="#features.faq">Does FreeS/WAN support ...</A>
+<UL>
+<LI><A href="#VPN.faq">... site-to-site VPN applications</A></LI>
+<LI><A href="#warrior.faq">... remote users connecting to a LAN</A></LI>
+<LI><A href="#road.shared.possible">... remote users using shared secret
+ authentication?</A></LI>
+<LI><A href="#wireless.faq">... wireless networks</A></LI>
+<LI><A href="#PKIcert">... X.509 or other PKI certificates?</A></LI>
+<LI><A href="#Radius">... user authentication (Radius, SecureID, Smart
+ Card ...)?</A></LI>
+<LI><A href="#NATtraversal">... NAT traversal</A></LI>
+<LI><A href="#virtID">... assigning a &quot;virtual identity&quot; to a remote
+ system?</A></LI>
+<LI><A href="#noDES.faq">... single DES encryption?</A></LI>
+<LI><A href="#AES.faq">... AES encryption?</A></LI>
+<LI><A href="#other.cipher">... other encryption algorithms?</A></LI>
+</UL>
+</LI>
+<LI><A href="#canI">Can I ...</A>
+<UL>
+<LI><A href="#policy.preconfig">...use policy groups along with
+ explicitly configured connections?</A></LI>
+<LI><A href="#policy.off">...turn off policy groups?</A></LI>
+
+<!--
+ <li><a href="#policy.otherinterface">...use policy groups
+ on an interface other than <VAR>%defaultroute</VAR>?</a></li>
+-->
+<LI><A href="#reload">... reload connection info without restarting?</A></LI>
+<LI><A href="#masq.faq">... use several masqueraded subnets?</A></LI>
+<LI><A href="#dup_route">... use subnets masqueraded to the same
+ addresses?</A></LI>
+<LI><A href="#road.masq">... assign a road warrior an address on my net
+ (a virtual identity)?</A></LI>
+<LI><A href="#road.many">... support many road warriors with one
+ gateway?</A></LI>
+<LI><A href="#road.PSK">... have many road warriors using shared secret
+ authentication?</A></LI>
+<LI><A href="#QoS">... use Quality of Service routing with FreeS/WAN?</A>
+</LI>
+<LI><A href="#deadtunnel">... recognise dead tunnels and shut them down?</A>
+</LI>
+<LI><A href="#demanddial">... build IPsec tunnels over a demand-dialed
+ link?</A></LI>
+<LI><A href="#GRE">... build GRE, L2TP or PPTP tunnels over IPsec?</A></LI>
+<LI><A href="#NetBIOS">... use Network Neighborhood (Samba, NetBIOS)
+ over IPsec?</A></LI>
+</UL>
+</LI>
+<LI><A href="#setup.faq">Life's little mysteries</A>
+<UL>
+<LI><A href="#cantping">I cannot ping ....</A></LI>
+<LI><A href="#forever">It takes forever to ...</A></LI>
+<LI><A href="#route">I send packets to the tunnel with route(8) but they
+ vanish</A></LI>
+<LI><A href="#down_route">When a tunnel goes down, packets vanish</A></LI>
+<LI><A href="#firewall_ate">The firewall ate my packets!</A></LI>
+<LI><A href="#dropconn">Dropped connections</A></LI>
+<LI><A href="#defaultroutegone">Disappearing %defaultroute</A></LI>
+<LI><A href="#tcpdump.faq">TCPdump on the gateway shows strange things</A>
+</LI>
+<LI><A href="#no_trace">Traceroute does not show anything between the
+ gateways</A></LI>
+</UL>
+</LI>
+<LI><A href="#man4debug">Testing in stages (or .... works but ...
+ doesn't)</A>
+<UL>
+<LI><A href="#nomanual">Manually keyed connections don't work</A></LI>
+<LI><A href="#spi_error">One manual connection works, but second one
+ fails</A></LI>
+<LI><A href="#man_no_auto">Manual connections work, but automatic keying
+ doesn't</A></LI>
+<LI><A href="#nocomp">IPsec works, but connections using compression
+ fail</A></LI>
+<LI><A href="#pmtu.broken">Small packets work, but large transfers fail</A>
+</LI>
+<LI><A href="#subsub">Subnet-to-subnet works, but tests from the
+ gateways don't</A></LI>
+</UL>
+</LI>
+<LI><A href="#compile.faq">Compilation problems</A>
+<UL>
+<LI><A href="#gmp.h_missing">gmp.h: No such file or directory</A></LI>
+<LI><A href="#noVM">... virtual memory exhausted</A></LI>
+</UL>
+</LI>
+<LI><A href="#error">Interpreting error messages</A>
+<UL>
+<LI><A href="#route-client">route-client (or host) exited with status 7</A>
+</LI>
+<LI><A href="#unreachable">SIOCADDRT:Network is unreachable</A></LI>
+<LI><A href="#modprobe">ipsec_setup: modprobe: Can't locate moduleipsec</A>
+</LI>
+<LI><A href="#noKLIPS">ipsec_setup: Fatal error, kernel appears to lack
+ KLIPS</A></LI>
+<LI><A href="#noDNS">ipsec_setup: ... failure to fetch key for ... from
+ DNS</A></LI>
+<LI><A href="#dup_address">ipsec_setup: ... interfaces ... and ... share
+ address ...</A></LI>
+<LI><A href="#kflags">ipsec_setup: Cannot adjust kernel flags</A></LI>
+<LI><A href="#message_num">Message numbers (MI3, QR1, et cetera) in
+ Pluto messages</A></LI>
+<LI><A href="#conn_name">Connection names in Pluto error messages</A></LI>
+<LI><A href="#cantorient">Pluto: ... can't orient connection</A></LI>
+<LI><A href="#no.interface">... we have no ipsecN interface for either
+ end of this connection</A></LI>
+<LI><A href="#noconn">Pluto: ... no connection is known</A></LI>
+<LI><A href="#nosuit">Pluto: ... no suitable connection ...</A></LI>
+<LI><A href="#noconn.auth">Pluto: ... no connection has been authorized</A>
+</LI>
+<LI><A href="#noDESsupport">Pluto: ... OAKLEY_DES_CBC is not supported.</A>
+</LI>
+<LI><A href="#notransform">Pluto: ... no acceptable transform</A></LI>
+<LI><A href="#rsasigkey">rsasigkey dumps core</A></LI>
+<LI><A href="#sig4">!Pluto failure!: ... exited with ... signal 4</A></LI>
+<LI><A href="#econnrefused">ECONNREFUSED error message</A></LI>
+<LI><A href="#no_eroute">klips_debug: ... no eroute!</A></LI>
+<LI><A href="#SAused">... trouble writing to /dev/ipsec ... SA already
+ in use</A></LI>
+<LI><A href="#ignore">... ignoring ... payload</A></LI>
+<LI><A href="#unknown_rightcert">unknown parameter name &quot;rightcert&quot;</A></LI>
+</UL>
+</LI>
+<LI><A href="#spam">Why don't you restrict the mailing lists to reduce
+ spam?</A></LI>
+</UL>
+<HR>
+<H2><A name="whatzit">What is FreeS/WAN?</A></H2>
+<P>FreeS/WAN is a Linux implementation of the<A href="glossary.html#IPSEC">
+ IPsec</A> protocols, providing security services at the IP (Internet
+ Protocol) level of the network.</P>
+<P>For more detail, see our<A href="intro.html"> introduction</A>
+ document or the FreeS/WAN project<A href="http://www.freeswan.org/">
+ web site</A>.</P>
+<P>To start setting it up, go to our<A href="quickstart.html">
+ quickstart guide</A>.</P>
+<P>Our<A href="web.html"> web links</A> document has information on<A href="web.html#implement">
+ IPsec for other systems</A>.</P>
+<H2><A name="problems">How do I report a problem or seek help?</A></H2>
+<DL>
+<DT>Read our<A href="trouble.html"> troubleshooting</A> document.</DT>
+<DD>
+<P>It may guide you to a solution. If not, see its<A href="trouble.html#prob.report">
+ problem reporting</A> section.</P>
+<P>Basically, what it says is<STRONG> give us the output from<VAR> ipsec
+ barf</VAR> from both gateways</STRONG>. Without full information, we
+ cannot diagnose a problem. However,<VAR> ipsec barf</VAR> produces a
+ lot of output. If at all possible,<STRONG> please make barfs accessible
+ via the web or FTP</STRONG> rather than sending enormous mail messages.</P>
+</DD>
+<DT><STRONG>Use the<A href="mail.html"> users mailing list</A> for
+ problem reports</STRONG>, rather than mailing developers directly.</DT>
+<DD>
+<UL>
+<LI>This gives you access to more expertise, including users who may
+ have encountered and solved the same problems.</LI>
+<LI>It is more likely to get a quick response. Developers may get behind
+ on email, or even ignore it entirely for a while, but a list message
+ (given a reasonable Subject: line) is certain to be read by a fair
+ number of people within hours.</LI>
+<LI>It may also be important because of<A href="politics.html#exlaw">
+ cryptography export laws</A>. A US citizen who provides technical
+ assistance to foreign cryptographic work might be charged under the
+ arms export regulations. Such a charge would be easier to defend if the
+ discussion took place on a public mailing list than if it were done in
+ private mail.</LI>
+</UL>
+</DD>
+<DT>Try irc.freenode.net#freeswan.</DT>
+<DD>
+<P>FreeS/WAN developers, volunteers and users can often be found there.
+ Be patient and be prepared to provide lots of information to support
+ your question.</P>
+<P>If your question was really interesting, and you found an answer,
+ please share that with the class by posting to the<A href="mail.html">
+ users mailing list</A>. That way others with the same problem can find
+ your answer in the archives.</P>
+</DD>
+<DT>Premium support is also available.</DT>
+<DD>
+<P>See the next several questions.</P>
+</DD>
+</DL>
+<H2><A name="generic">Can I get ...</A></H2>
+<H3><A name="lemme_out">Can I get an off-the-shelf system that includes
+ FreeS/WAN?</A></H3>
+<P>There are a number of Linux distributions or firewall products which
+ include FreeS/WAN. See this<A href="intro.html#products"> list</A>.
+ Using one of these, chosen to match your requirements and budget, may
+ save you considerable time and effort.</P>
+<P>If you don't know your requirements, start by reading Schneier's<A href="biblio.html#secrets">
+ Secrets and Lies</A>. That gives the best overview of security issues I
+ have seen. Then consider hiring a consultant (see next question) to
+ help define your requirements.</P>
+<H3><A name="consultant">Can I hire consultants or staff who know
+ FreeS/WAN?</A></H3>
+<P>If you want the help of a contractor, or to hire staff with FreeS/WAN
+ expertise, you could:</P>
+<UL>
+<LI>check availability in your area through your local Linux User Group
+ (<A href="http://lugww.counter.li.org/">LUG Index</A>)</LI>
+<LI>try asking on our<A href="mail.html"> mailing list</A></LI>
+</UL>
+<P>For companies offerring support, see the next question.</P>
+<H3><A name="commercial">Can I get commercial support?</A></H3>
+<P>Many of the distributions or firewall products which include
+ FreeS/WAN (see this<A href="intro.html#products"> list</A>) come with
+ commercial support or have it available as an option.</P>
+<P>Various companies specialize in commercial support of open source
+ software. Our project leader was a founder of the first such company,
+ Cygnus Support. It has since been bought by<A href="http://www.redhat.com">
+ Redhat</A>. Another such firm is<A href="http://www.linuxcare.com">
+ Linuxcare</A>.</P>
+<H2><A name="release">Release questions</A></H2>
+<H3><A name="rel.current">What is the current release?</A></H3>
+<P>The current release is the highest-numbered tarball on our<A href="ftp://ftp.xs4all.nl/pub/crypto/freeswan">
+ distribution site</A>. Almost always, any of<A href="intro.html#mirrors">
+ the mirrors</A> will have the same file, though perhaps not for a day
+ or so after a release.</P>
+<P>Unfortunately, the web site is not always updated as quickly as it
+ should be.</P>
+<H3><A name="relwhen">When is the next release?</A></H3>
+<P>We try to do a release approximately every six to eight weeks.</P>
+<P>If pre-release tests fail and the fix appears complex, or more
+ generally if the code does not appear stable when a release is
+ scheduled, we will just skip that release.</P>
+<P>For serious bugs, we may bring out an extra bug-fix release. These
+ get numbers in the normal release series. For example, there was a bug
+ found in FreeS/WAN 1.6, so we did another release less than two weeks
+ later. The bug-fix release was called 1.7.</P>
+<H3><A name="rel.bugs">Are there known bugs in the current release?</A></H3>
+<P>Any problems we are aware of at the time of a release are documented
+ in the<A href="../BUGS"> BUGS</A> file for that release. You should
+ also look at the<A href="../CHANGES"> CHANGES</A> file.</P>
+<P>Bugs discovered after a release are discussed on the<A href="mail.html">
+ mailing lists</A>. The easiest way to check for any problems in the
+ current code would be to peruse the<A href="http://lists.freeswan.org/pipermail/briefs">
+ List In Brief</A>.</P>
+<H2><A name="mod_cons">Modifications and contributions</A></H2>
+<H3><A name="modify.faq">Can I modify FreeS/WAN to ...?</A></H3>
+<P>You are free to modify FreeS/WAN in any way. See the discussion of<A href="intro.html#licensing">
+ licensing</A> in our introduction document.</P>
+<P>Before investing much energy in any such project, we suggest that you</P>
+<UL>
+<LI>check the list of<A href="web.html#patch"> existing patches</A></LI>
+<LI>post something about your project to the<A href="mail.html"> design
+ mailing list</A></LI>
+</UL>
+<P>This may prevent duplicated effort, or lead to interesting
+ collaborations.</P>
+<H3><A name="contrib.faq">Can I contribute to the project?</A></H3>
+ In general, we welcome contributions from the community. Various
+ contributed patches, either to fix bugs or to add features, have been
+ incorporated into our distribution. Other patches, not yet included in
+ the distribution, are listed in our<A href="web.html#patch"> web links</A>
+ section.
+<P>Users have also contributed heavily to documentation, both by
+ creating their own<A href="intro.html#howto"> HowTos</A> and by posting
+ things on the<A href="mail.html"> mailing lists</A> which I have quoted
+ in these HTML docs.</P>
+<P>There are, however, some caveats.</P>
+<P>FreeS/WAN is being implemented in Canada, by Canadians, largely to
+ ensure that is it is entirely free of export restrictions. See this<A href="politics.html#status">
+ discussion</A>. We<STRONG> cannot accept code contributions from US
+ residents or citizens</STRONG>, not even one-line bugs fixes. The
+ reasons for this were recently discussed extensively on the mailing
+ list, in a thread starting<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/01/msg00111.html">
+ here</A>.</P>
+<P>Not all contributions are of interest to us. The project has a set of
+ fairly ambitious and quite specific goals, described in our<A href="intro.html#goals">
+ introduction</A>. Contributions that lead toward these goals are likely
+ to be welcomed enthusiastically. Other contributions may be seen as
+ lower priority, or even as a distraction.</P>
+<P>Discussion of possible contributions takes place on the<A href="mail.html">
+ design mailing list</A>.</P>
+<H3><A name="ddoc.faq">Is there detailed design documentation?</A></H3>
+ There are:
+<UL>
+<LI><A href="rfc.html">RFCs</A> specifying the protocols we implement</LI>
+<LI><A href="manpages.html">man pages</A> for our utilities, library
+ functions and file formats</LI>
+<LI>comments in the source code</LI>
+<LI><A href="index.html">HTML documentation</A> written primarily for
+ users</LI>
+<LI>archived discussions from the<A href="mail.html"> mailing lists</A></LI>
+<LI>other papers mentioned in our<A href="intro.html#applied">
+ introduction</A></LI>
+</UL>
+<P>The only formal design documents are a few papers in the last
+ category above. All the other categories, however, have things to say
+ about design as well.</P>
+<H2><A name="interact">Will FreeS/WAN work in my environment?</A></H2>
+<H3><A name="interop.faq">Can FreeS/WAN talk to ...?</A></H3>
+<P>The IPsec protocols are designed to support interoperation. In
+ theory, any two IPsec implementations should be able to talk to each
+ other. In practice, it is considerably more complex. We have a whole<A href="interop.html">
+ interoperation document</A> devoted to this problem.</P>
+<P>An important part of that document is links to the many<A href="interop.html#otherpub">
+ user-written HowTos</A> on interoperation between FreeS/WAN and various
+ other implementations. Often the users know more than the developers
+ about these issues (and almost always more than me :-), so these
+ documents may be your best resource.</P>
+<H3><A name="old_to_new">Can different FreeS/WAN versions talk to each
+ other?</A></H3>
+<P>Linux FreeS/WAN can interoperate with many IPsec implementations,
+ including earlier versions of Linux FreeS/WAN itself.</P>
+<P>In a few cases, there are some complications. See our<A href="interop.html#oldswan">
+ interoperation</A> document for details.</P>
+<H3><A name="faq.bandwidth">Is there a limit on throughput?</A></H3>
+<P>There is no hard limit, but see below.</P>
+<H3><A name="faq.number">Is there a limit on number of tunnels?</A></H3>
+<P>There is no hard limit, but see next question.</P>
+<H3><A name="faq.speed">Is a ... fast enough to handle FreeS/WAN with my
+ loads?</A></H3>
+<P>A quick summary:</P>
+<DL>
+<DT>Even a limited machine can be useful</DT>
+<DD>A 486 can handle a T1, ADSL or cable link, though the machine may be
+ breathing hard.</DD>
+<DT>A mid-range PC (say 800 MHz with good network cards) can do a lot of
+ IPsec</DT>
+<DD>With up to roughly 50 tunnels and aggregate bandwidth of 20 Megabits
+ per second, it willl have cycles left over for other tasks.</DD>
+<DT>There are limits</DT>
+<DD>Even a high end CPU will not come close to handling a fully loaded
+ 100 Mbit/second Ethernet link.
+<P>Beyond about 50 tunnels it needs careful management.</P>
+</DD>
+</DL>
+<P>See our<A href="performance.html"> FreeS/WAN performance</A> document
+ for details.</P>
+<H2><A name="work_on">Will FreeS/WAN work on ... ?</A></H2>
+<H3><A name="versions">Will FreeS/WAN run on my version of Linux?</A></H3>
+<P>We build and test on Redhat distributions, but FreeS/WAN runs just
+ fine on several other distributions, sometimes with minor fiddles to
+ adapt to the local environment. Details are in our<A href="compat.html#otherdist">
+ compatibility</A> document. Also, some distributions or products come
+ with<A href="intro.html#products"> FreeS/WAN included</A>.</P>
+<H3><A name="nonIntel.faq">Will FreeS/WAN run on non-Intel CPUs?</A></H3>
+<P>FreeS/WAN is<STRONG> intended to run on all CPUs Linux supports</STRONG>
+. We know of it being used in production on x86, ARM, Alpha and MIPS. It
+ has also had successful tests on PPC and SPARC, though we don't know of
+ actual use there. Details are in our<A href="compat.html#CPUs">
+ compatibility</A> document.</P>
+<H3><A name="multi.faq">Will FreeS/WAN run on multiprocessors?</A></H3>
+<P>FreeS/WAN is designed to work on any SMP architecture Linux supports,
+ and has been tested successfully on at least dual processor Intel
+ architecture machines. Details are in our<A href="compat.html#multiprocessor">
+ compatibility</A> document.</P>
+<H3><A name="k.old">Will FreeS/WAN work on an older kernel?</A></H3>
+<P>It might, but we strongly recommend using a recent 2.2 or 2.4 series
+ kernel. Sometimes the newer versions include security fixes which can
+ be quite important on a gateway.</P>
+<P>Also, we use recent kernels for development and testing, so those are
+ better tested and, if you do encounter a problem, more easily
+ supported. If something breaks applying recent FreeS/WAN patches to an
+ older kernel, then &quot;update your kernel&quot; is almost certain to be the
+ first thing we suggest. It may be the only suggestion we have.</P>
+<P>The precise kernel versions supported by a particular FreeS/WAN
+ release are given in the<A href="XX"> README</A> file of that release.</P>
+<P>See the following question for more on kernels.</P>
+<H3><A name="k.versions">Will FreeS/WAN run on the latest kernel
+ version?</A></H3>
+<P>Sometimes yes, but quite often, no.</P>
+<P>Kernel versions supported are given in the<A href="../README"> README</A>
+ file of each FreeS/WAN release. Typically, they are whatever production
+ kernels were current at the time of our release (or shortly before; we
+ might release for kernel<VAR> n</VAR> just as Linus releases<VAR> n+1</VAR>
+). Often FreeS/WAN will work on slightly later kernels as well, but of
+ course this cannot be guaranteed.</P>
+<P>For example, FreeS/WAN 1.91 was released for kernels 2.2.19 or 2.4.5,
+ the current kernels at the time. It also worked on 2.4.6, 2.4.7 and
+ 2.4.8, but 2.4.9 had changes that caused compilation errors if it was
+ patched with FreeS/WAN 1.91.</P>
+<P>When such changes appear, we put a fix in the FreeS/WAN snapshots,
+ and distribute it with our next release. However, this is not a high
+ priority for us, and it may take anything from a few days to several
+ weeks for such a problem to find its way to the top of our kernel
+ programmer's To-Do list. In the meanwhile, you have two choices:</P>
+<UL>
+<LI>either stick with a slightly older kernel, even if it is not the
+ latest and greatest. This is recommended for production systems; new
+ versions may have new bugs.</LI>
+<LI>or fix the problem yourself and send us a patch, via the<A href="mail.html">
+ Users mailing list</A>.</LI>
+</UL>
+<P>We don't even try to keep up with kernel changes outside the main 2.2
+ and 2.4 branches, such as the 2.4.x-ac patched versions from Alan Cox
+ or the 2.5 series of development kernels. We'd rather work on
+ developing the FreeS/WAN code than on chasing these moving targets. We
+ are, however, happy to get patches for problems discovered there.</P>
+<P>See also the<A href="install.html#choosek"> Choosing a kernel</A>
+ section of our installation document.</P>
+<H3><A name="interface.faq">Will FreeS/WAN work on unusual network
+ hardware?</A></H3>
+<P>IPsec is designed to work over any network that IP works over, and
+ FreeS/WAN is intended to work over any network interface hardware that
+ Linux supports.</P>
+<P>If you have working IP on some unusual interface -- perhaps Arcnet,
+ Token Ring, ATM or Gigabit Ethernet -- then IPsec should &quot;just work&quot;.</P>
+<P>That said, practice is sometimes less tractable than theory. Our
+ testing is done almost entirely on:</P>
+<UL>
+<LI>10 or 100 Mbit Ethernet</LI>
+<LI>ADSL or cable connections, with and without PPPoE</LI>
+<LI>IEEE 802.11 wireless LANs (see<A href="#wireless.faq"> below</A>)</LI>
+</UL>
+<P>If you have some other interface, especially an uncommon one, it is
+ entirely possible you will get bitten either by a FreeS/WAN bug which
+ our testing did not turn up, or by a bug in the driver that shows up
+ only with our loads.</P>
+<P>If IP works on your interface and FreeS/WAN doesn't, seek help on the<A
+href="mail.html"> mailing lists</A>.</P>
+<P>Another FAQ section describes<A href="#pmtu.broken"> MTU problems</A>
+. These are a possibility for some interfaces.</P>
+<H3><A name="vlan">Will FreeS/WAN work on a VLAN (802.1q) network?</A></H3>
+<P> Yes, FreeSwan works fine, though some network drivers have problems
+ with jumbo sized ethernet frames. If you used interfaces=%defaultroute
+ you do not need to change anything, but if you specified an interface
+ (eg eth0) then remember you must change that to reflect the VLAN
+ interface (eg eth0.2 for VLAN ID 2).</P>
+<P> The &quot;eepro100&quot; module is known to be broken, use the e100 driver for
+ those cards instead (included in 2.4 as 'alternative driver' for the
+ Intel EtherExpressPro/100.</P>
+<P> You do not need to change any MTU setting (those are workarounds
+ that are only needed for buggy drivers)</P>
+<P><EM>This FAQ contributed by Paul Wouters.</EM></P>
+<H2><A name="features.faq">Does FreeS/WAN support ...</A></H2>
+<P>For a discussion of which parts of the IPsec specifications FreeS/WAN
+ does and does not implement, see our<A href="compat.html#spec">
+ compatibility</A> document.</P>
+<P>For information on some often-requested features, see below.</P>
+<H3><A name="VPN.faq"></A>Does FreeS/WAN support site-to-site VPN (<A HREF="glossary.html#VPN">
+Virtual Private Network</A>) applications?</H3>
+<P>Absolutely. See this FreeS/WAN-FreeS/WAN<A HREF="config.html">
+ configuration example</A>. If only one site is using FreeS/WAN, there
+ may be a relevant HOWTO on our<A HREF="interop.html"> interop page</A>.</P>
+<H3><A name="warrior.faq">Does FreeS/WAN support remote users connecting
+ to a LAN?</A></H3>
+<P>Yes. We call the remote users &quot;Road Warriors&quot;. Check out our
+ FreeS/WAN-FreeS/WAN<A HREF="config.html#config.rw"> Road Warrior
+ Configuration Example</A>.</P>
+<P>If your Road Warrior is a Windows or Mac PC, you may need to install
+ an IPsec implementation on that machine. Our<A HREF="interop.html">
+ interop</A> page lists many available brands, and features links to
+ several HOWTOs.</P>
+<H3><A name="road.shared.possible">Does FreeS/WAN support remote users
+ using shared secret authentication?</A></H3>
+<P><STRONG>Yes, but</STRONG> there are severe restrictions, so<STRONG>
+ we strongly recommend using</STRONG><A href="glossary.html#RSA"><STRONG>
+ RSA</STRONG></A><STRONG> keys for</STRONG><A href="glossary.html#authentication">
+<STRONG> authentication</STRONG></A><STRONG> instead</STRONG>.</P>
+<P>See this<A href="#road.PSK"> FAQ question</A>.</P>
+<H3><A name="wireless.faq">Does FreeS/WAN support wireless networks?</A></H3>
+<P>Yes, it is a common practice to use IPsec over wireless networks
+ because their built-in encryption,<A href="glossary.html#WEP"> WEP</A>,
+ is insecure.</P>
+<P>There is some<A href="adv_config.html#wireless.config"> discussion</A>
+ in our advanced configuration document. See also the<A HREF="http://www.wavesec.org">
+ WaveSEC site</A>.</P>
+<H3><A name="PKIcert">Does FreeS/WAN support X.509 or other PKI
+ certificates?</A></H3>
+<P>Vanilla FreeS/WAN does not support X.509, but Andreas Steffen and
+ others have provided a popular, well-supported X.509 patch.</P>
+<UL>
+<LI><A HREF="http://www.strongsec.com/freeswan">patch</A></LI>
+<LI><A HREF="http://www.freeswan.ca">Super FreeS/WAN</A> incorporates
+ this and other user-contributed patches.</LI>
+<LI> Kai Martius'<A HREF="http://www.strongsec.com/freeswan/install.htm">
+ X.509 Installation and Configuration Guide</A></LI>
+</UL>
+<P> Linux FreeS/WAN features<A HREF="quickstart.html"> Opportunistic
+ Encryption</A>, an alternative Public Key Infrastructure based on
+ Secure DNS.</P>
+<H3><A name="Radius">Does FreeS/WAN support user authentication (Radius,
+ SecureID, Smart Card...)?</A></H3>
+<P>Andreas Steffen's<A HREF="http://www.strongsec.com/freeswan"> X.509
+ patch</A> (v. 1.42+) supports Smart Cards. The patch does not ship with
+ vanilla FreeS/WAN, but will be incorporated into<A HREF="http://www.freeswan.ca/">
+ Super FreeS/WAN 2.01+</A>. The patch implements the PCKS#15
+ Cryptographic Token Information Format Standard, using the OpenSC
+ smartcard library functions.</P>
+<P>Older news:</P>
+<P>A user-supported patch to FreeS/WAN 1.3, for smart card style
+ authentication, is available on<A HREF="http://alcatraz.webcriminals.com/~bastiaan/ipsec">
+ Bastiaan's site</A>. It supports skeyid and ibutton. This patch is not
+ part of Super FreeS/WAN.</P>
+<P>For a while progress on this front was impeded by a lack of standard.
+ The IETF<A href="http://www.ietf.org/html.charters/ipsra-charter.html">
+ working group</A> has now nearly completed its recommended solution to
+ the problem; meanwhile several vendors have implemented various things.</P>
+
+<!--
+<p>The <a href="web.html#patch">patches</a> section of our web links document
+has links to some user work on this.</p>
+-->
+<P>Of course, there are various ways to avoid any requirement for user
+ authentication in IPsec. Consider the situation where road warriors
+ build IPsec tunnels to your office net and you are considering
+ requiring user authentication during tunnel negotiation. Alternatives
+ include:</P>
+<UL>
+<LI>If you can trust the road warrior machines, then set them up so that
+ only authorised users can create tunnels. If your road warriors use
+ laptops, consider the possibility of theft.</LI>
+<LI>If the tunnel only provides access to particular servers and you can
+ trust those servers, then set the servers up to require user
+ authentication.</LI>
+</UL>
+<P>If either of those is trustworthy, it is not clear that you need user
+ authentication in IPsec.</P>
+<H3><A name="NATtraversal">Does FreeS/WAN support NAT traversal?</A></H3>
+<P>Vanilla FreeS/WAN does not, but thanks to Mathieu Lafon and Arkoon
+ Network Security, there's a patch to support this.</P>
+<UL>
+<LI><A HREF="http://open-source.arkoon.net">patch and documentation</A></LI>
+<LI><A HREF="http://www.freeswan.ca">Super FreeS/WAN</A> incorporates
+ this and other user-contributed patches.</LI>
+</UL>
+<P>The NAT traversal patch has some issues with PSKs, so you may wish to
+ authenticate with RSA keys, or X.509 (requires a patch which is also
+ included in Super FreeS/WAN). Doing the latter also has advantages when
+ dealing with large numbers of clients who may be behind NAT; instead of
+ having to make an individual Roadwarrior connection for each virtual
+ IP, you can use the &quot;rightsubnetwithin&quot; parameter to specify a range.
+ See<A HREF="http://www.strongsec.com/freeswan/install.htm#section_4.4">
+ these<VAR> rightsubnetwithin</VAR> instructions</A>.</P>
+<H3><A name="virtID">Does FreeS/WAN support assigning a &quot;virtual
+ identity&quot; to a remote system?</A></H3>
+<P>Some IPsec implementations allow you to make the source address on
+ packets sent by a Road Warrior machine be something other than the
+ address of its interface to the Internet. This is sometimes described
+ as assigning a virtual identity to that machine.</P>
+<P>FreeS/WAN does not directly support this, but it can be done. See
+ this<A href="#road.masq"> FAQ question</A>.</P>
+<H3><A name="noDES.faq">Does FreeS/WAN support single DES encryption?</A>
+</H3>
+<P><STRONG>No</STRONG>, single DES is not used either at the<A href="glossary.html#IKE">
+ IKE</A> level for negotiating connections or at the<A href="glossary.html#IPsec">
+ IPsec</A> level for actually building them.</P>
+<P>Single DES is<A href="politics.html#desnotsecure"> insecure</A>. As
+ we see it, it is more important to deliver real security than to comply
+ with a standard which has been subverted into allowing use of
+ inadequate methods. See this<A href="politics.html#weak"> discussion</A>
+.</P>
+<P>If you want to interoperate with an IPsec implementation which offers
+ only DES, see our<A href="interop.html#noDES"> interoperation</A>
+ document.</P>
+<H3><A name="AES.faq">Does FreeS/WAN support AES encryption?</A></H3>
+<P><A href="glossary.html#AES">AES</A> is a new US government<A href="glossary.html#block">
+ block cipher</A> standard to replace the obsolete<A href="glossary.html#DES">
+ DES</A>.</P>
+<P>At time of writing (March 2002), the FreeS/WAN distribution does not
+ yet support AES but user-written<A href="web.html#patch"> patches</A>
+ are available to add it. Our kernel programmer is working on
+ integrating those patches into the distribution, and there is active
+ discussion of this on the design mailimg list.</P>
+<H3><A name="other.cipher">Does FreeS/WAN support other encryption
+ algorithms?</A></H3>
+<P>Currently<A href="glossary.html#3DES"> triple DES</A> is the only
+ cipher supported. AES will almost certainly be added (see previous
+ question), and it is likely that in the process we will also add the
+ other two AES finalists with open licensing, Twofish and Serpent.</P>
+<P>We are extremely reluctant to add other ciphers. This would make both
+ use and maintenance of FreeS/WAN more complex without providing any
+ clear benefit. Complexity is emphatically not desirable in a security
+ product.</P>
+<P>Various users have written patches to add other ciphers. We provide<A href="web.html#patch">
+ links</A> to these.</P>
+<H2><A name="canI">Can I ...</A></H2>
+<H3><A name="policy.preconfig">Can I use policy groups along with
+ explicitly configured connections?</A></H3>
+<P>Yes, you can, so long as you pay attention to the selection rule,
+ which can be summarized &quot;the most specific connection wins&quot;. We
+ describe the rule in our<A HREF="policygroups.html#policy.group.notes">
+ policy groups</A> document, and provide a more technical explanation in<A
+HREF="manpage.d/ipsec.conf.5.html"> man ipsec.conf</A>.</P>
+<P>A good guideline: If you have a regular connection defined in<VAR>
+ ipsec.conf</VAR>, ensure that a subset of that connection is not listed
+ in a less restrictive policy group. Otherwise, FreeS/WAN will use the
+ subset, with its more specific source/destination pair.</P>
+<P>Here's an example. Suppose you are the system administrator at
+ 192.0.2.2. You have this connection in ipsec.conf:<VAR> ipsec.conf</VAR>
+:</P>
+<PRE>conn net-to-net
+ left=192.0.2.2 # you are here
+ right=192.0.2.8
+ rightsubnet=192.0.2.96/27
+ ....
+</PRE>
+<P>If you then place a host or net within<VAR> rightsubnet</VAR>, (let's
+ say 192.0.2.98) in<VAR> private-or-clear</VAR>, you may find that
+ 192.0.2.2 at times communicates in the clear with 192.0.2.98. That's
+ consistent with the rule, but may be contrary to your expectations.</P>
+<P>On the other hand, it's safe to put a larger subnet in a less
+ restrictive policy group file. If<VAR> private-or-clear</VAR> contains
+ 192.0.2.0/24, then the more specific<VAR> net-to-net</VAR> connection
+ is used for any communication to 192.0.2.96/27. The more general policy
+ applies only to communication with hosts or subnets in 192.0.2.0/24
+ without a more specific policy or connection.</P>
+<H3><A name="policy.off">Can I turn off policy groups?</A></H3>
+<P>Yes. Use<A HREF="policygroups.html#disable_policygroups"> these
+ instructions</A>.</P>
+
+<!--
+<h3><a name="policy.otherinterface">Can I use policy groups
+ on an interface other than <VAR>%defaultroute</VAR>?</a></h3>
+
+<p>??<p>
+-->
+<H3><A name="reload">Can I reload connection info without restarting?</A>
+</H3>
+<P>Yes, you can do this. Here are the details, in a mailing list message
+ from Pluto programmer Hugh Redelmeier:</P>
+<PRE>| How can I reload config's without restarting all of pluto and klips? I am using
+| FreeSWAN -&gt; PGPNet in a medium sized production environment, and would like to be
+| able to add new connections ( i am using include config/* ) without dropping current
+| SA's.
+|
+| Can this be done?
+|
+| If not, are there plans to add this kind of feature?
+
+ ipsec auto --add whatever
+This will look in the usual place (/etc/ipsec.conf) for a conn named
+whatever and add it.
+
+If you added new secrets, you need to do
+ ipsec auto --rereadsecrets
+before Pluto needs to know those secrets.
+
+| I have looked (perhaps not thoroughly enough tho) to see how to do this:
+
+There may be more bits to look for, depending on what you are trying
+to do.</PRE>
+<P>Another useful command here is<VAR> ipsec auto --replace &lt;conn_name&gt;</VAR>
+ which re-reads data for a named connection.</P>
+<H3><A name="masq.faq">Can I use several masqueraded subnets?</A></H3>
+<P>Yes. This is done all the time. See the discussion in our<A href="config.html#route_or_not">
+ setup</A> document. The only restriction is that the subnets on the two
+ ends must not overlap. See the next question.</P>
+<P>Here is a mailing list message on the topic. The user incorrectly
+ thinks you need a 2.4 kernel for this -- actually various people have
+ been doing it on 2.0 and 2.2 for quite some time -- but he has it right
+ for 2.4.</P>
+<PRE>Subject: Double NAT and freeswan working :)
+ Date: Sun, 11 Mar 2001
+ From: Paul Wouters &lt;paul@xtdnet.nl&gt;
+
+Just to share my pleasure, and make an entry for people who are searching
+the net on how to do this. Here's the very simple solution to have a double
+NAT'ed network working with freeswan. (Not sure if this is old news, but I'm
+not on the list (too much spam) and I didn't read this in any HOWTO/FAQ/doc
+on the freeswan site yet (Sandy, put it in! :)
+
+10.0.0.0/24 --- 10.0.0.1 a.b.c.d ---- a.b.c.e {internet} ----+
+ |
+10.0.1.0/24 --- 10.0.1.1 f.g.h.i ---- f.g.h.j {internet} ----+
+
+the goal is to have the first network do a VPN to the second one, yet also
+have NAT in place for connections not destinated for the other side of the
+NAT. Here the two Linux security gateways have one real IP number (cable
+modem, dialup, whatever.
+
+The problem with NAT is you don't want packets from 10.*.*.* to 10.*.*.*
+to be NAT'ed. While with Linux 2.2, you can't, with Linux 2.4 you can.
+
+(This has been tested and works for 2.4.2 with Freeswan snapshot2001mar8b)
+
+relevant parts of /etc/ipsec.conf:
+
+ left=f.g.h.i
+ leftsubnet=10.0.1.0/24
+ leftnexthop=f.g.h.j
+ leftfirewall=yes
+ leftid=@firewall.netone.nl
+ leftrsasigkey=0x0........
+ right=a.b.c.d
+ rightsubnet=10.0.0.0/24
+ rightnexthop=a.b.c.e
+ rightfirewall=yes
+ rightid=@firewall.nettwo.nl
+ rightrsasigkey=0x0......
+ # To authorize this connection, but not actually start it, at startup,
+ # uncomment this.
+ auto=add
+
+and now the real trick. Setup the NAT correctly on both sites:
+
+iptables -t nat -F
+iptables -t nat -A POSTROUTING -o eth0 -d \! 10.0.0.0/8 -j MASQUERADE
+
+This tells the NAT code to only do NAT for packets with destination other then
+10.* networks. note the backslash to mask the exclamation mark to protect it
+against the shell.
+
+Happy painting :)
+
+Paul</PRE>
+<H3><A name="dup_route">Can I use subnets masqueraded to the same
+ addresses?</A></H3>
+<P><STRONG>No.</STRONG> The notion that IP addresses are unique is one
+ of the fundamental principles of the IP protocol. Messing with it is
+ exceedingly perilous.</P>
+<P>Fairly often a situation comes up where a company has several
+ branches, all using the same<A href="glossary.html#non-routable">
+ non-routable addresses</A>, perhaps 192.168.0.0/24. This works fine as
+ long as those nets are kept distinct. The<A href="glossary.html#masq">
+ IP masquerading</A> on their firewalls ensures that packets reaching
+ the Internet carry the firewall address, not the private address.</P>
+<P>This can break down when IPsec enters the picture. FreeS/WAN builds a
+ tunnel that pokes through both masquerades and delivers packets from<VAR>
+ leftsubnet</VAR> to<VAR> rightsubnet</VAR> and vice versa. For this to
+ work, the two subnets<EM> must</EM> be distinct.</P>
+<P>There are several solutions to this problem.</P>
+<P>Usually, you<STRONG> re-number the subnets</STRONG>. Perhaps the
+ Vancouver office becomes 192.168.101.0/24, Calgary 192.168.102.0/24 and
+ so on. FreeS/WAN can happily handle this. With, for example<VAR>
+ leftsubnet=192.168.101.0/24</VAR> and<VAR> rightsubnet=192.168.102.0/24</VAR>
+ in a connection description, any machine in Calgary can talk to any
+ machine in Vancouver. If you want to be more restrictive and use
+ something like<VAR> leftsubnet=192.168.101.128/25</VAR> and<VAR>
+ rightsubnet=192.168.102.240/28</VAR> so only certain machines on each
+ end have access to the tunnel, that's fine too.</P>
+<P>You could also<STRONG> split the subnet</STRONG> into smaller ones,
+ for example using<VAR> 192.168.1.0/25</VAR> in Vancouver and<VAR>
+ rightsubnet=192.168.0.128/25</VAR> in Calgary.</P>
+<P>Alternately, you can just<STRONG> give up routing</STRONG> directly
+ to machines on the subnets. Omit the<VAR> leftsubnet</VAR> and<VAR>
+ rightsubnet</VAR> parameters from your connection descriptions. Your
+ IPsec tunnels will then run between the public interfaces of the two
+ firewalls. Packets will be masqueraded both before they are put into
+ tunnels and after they emerge. Your Vancouver client machines will see
+ only one Calgary machine, the firewall.</P>
+<H3><A name="road.masq">Can I assign a road warrior an address on my net
+ (a virtual identity)?</A></H3>
+<P>Often it would be convenient to be able to give a Road Warrior an IP
+ address which appears to be on the local network. Some IPsec
+ implementations have support for this, sometimes calling the feature
+ &quot;virtual identity&quot;.</P>
+<P>Currently (Sept 2002) FreeS/WAN does not support this, and we have no
+ definite plans to add it. The difficulty is that is not yet a standard
+ mechanism for it. There is an Internet Draft for a method of doing it
+ using<A href="glossary.html#DHCP"> DHCP</A> which looks promising.
+ FreeS/WAN may support that in a future release.</P>
+<P>In the meanwhile, you can do it yourself using the Linux iproute2(8)
+ facilities. Details are in<A href="http://www.av8n.com/vpn/iproute2.htm">
+ this paper</A>.</P>
+<P>Another method has also been discussed on the mailing list.:</P>
+<UL>
+<LI>You can use a variant of the<A href="adv_config.html#extruded.config">
+ extruded subnet</A> procedure.</LI>
+<LI>You have to avoid having the road warrior's assigned address within
+ the range you actually use at home base. See previous question.</LI>
+<LI>On the other hand, you want the roadwarrior's address to be within
+ the range that<EM> seems</EM> to be on your network.</LI>
+</UL>
+<P>For example, you might have:</P>
+<DL>
+<DT>leftsubnet=a.b.c.0/25</DT>
+<DD>head office network</DD>
+<DT>rightsubnet=a.b.c.129/32</DT>
+<DD>extruded to a road warrior. Note that this is not in a.b.c.0/25</DD>
+<DT>a.b.c.0/24</DT>
+<DD>whole network, including both the above</DD>
+</DL>
+<P>You then set up routing so that the office machines use the IPsec
+ gateway as their route to a.b.c.128/25. The leftsubnet parameter tells
+ the road warriors to use tunnels to reach a.b.c.0/25, so you should
+ have two-way communication. Depending or your network and applications,
+ there may be some additional work to do on DNS or Windows configuration</P>
+<H3><A name="road.many">Can I support many road warriors with one
+ gateway?</A></H3>
+<P>Yes. This is easily done, using</P>
+<DL>
+<DT>either RSA authentication</DT>
+<DD>standard in the FreeS/WAN distribution</DD>
+<DT>or X.509 certificates</DT>
+<DD>requires<A href="#PKIcert"> Super FreeS/WAN or a patch</A>.</DD>
+</DL>
+<P>In either case, each Road Warrior must have a different key or
+ certificate.</P>
+<P>It is also possible using pre-shared key authentication, though we
+ don't recommend this; see the<A href="#road.PSK"> next question</A> for
+ details.</P>
+<P>If you expect to have more than a few dozen Road Warriors connecting
+ simultaneously, you may need a fairly powerful gateway machine. See our
+ document on<A href="performance.html"> FreeS/WAN performance</A>.</P>
+<H3><A name="road.PSK">Can I have many road warriors using shared secret
+ authentication?</A></H3>
+<P><STRONG>Yes, but avoid it if possible</STRONG>.</P>
+<P>You can have multiple Road Warriors using shared secret
+ authentication<STRONG> only if they all use the same secret</STRONG>.
+ You must also set:</P>
+<P></P>
+<PRE> uniqueids=no </PRE>
+<P>in the connection definition.</P>
+<P>Why it's less secure:</P>
+<UL>
+<LI>If you have many users, it becomes almost certain the secret will
+ leak</LI>
+<LI>The secret becomes quite valuable to an attacker</LI>
+<LI>All users authenticate the same way, so the gateway cannot tell them
+ apart for logging or access control purposes</LI>
+<LI>Changing the secret is difficult. You have to securely notify all
+ users.</LI>
+<LI>If you find out the secret has been compromised, you can change it,
+ but then what? None of your users can connect without the new secret.
+ How will you notify them all, quickly and securely, without using the
+ VPN?</LI>
+</UL>
+<P>This is a designed-in limitation of the<A href="glossary.html#IKE">
+ IKE</A> key negotiation protocol, not a problem with our
+ implementation.</P>
+<P><STRONG>We very strongly recommend that you avoid using shared secret
+ authentication for multiple Road Warriors.</STRONG> Use RSA
+ authentication instead.</P>
+<P>The longer story: When using shared secrets, the protocol requires
+ that the responding gateway be able to determine which secret to use at
+ a time when all it knows about the initiator is an IP address. This
+ works fine if you know the initiator's address in advance and can use
+ it to look up the appropiriate secret. However, it fails for Road
+ Warriors since the gateway cannot know their IP addresses in advance.</P>
+<P>With RSA signatures (or certificates) the protocol is slightly
+ different. The initiator provides an identifier early in the exchange
+ and the responder can use that identifier to look up the correct key or
+ certificate. See<A href="#road.many"> above</A>.</P>
+<H3><A name="QoS">Can I use Quality of Service routing with FreeS/WAN?</A>
+</H3>
+<P>From project technical lead Henry Spencer:</P>
+<PRE>&gt; Do QoS add to FreeS/WAN?
+&gt; For example integrating DiffServ and FreeS/WAN?
+
+With a current version of FreeS/WAN, you will have to add hidetos=no to
+the config-setup section of your configuration file. By default, the TOS
+field of tunnel packets is zeroed; with hidetos=no, it is copied from the
+packet inside. (This is a modest security hole, which is why it is no
+longer the default.)
+
+DiffServ does not interact well with tunneling in general. Ways of
+improving this are being studied.</PRE>
+<P>Copying the<A href="glossary.html#TOS"> TOS</A> (type of service)
+ information from the encapsulated packet to the outer header reveals
+ the TOS information to an eavesdropper. This does not tell him much,
+ but it might be of use in<A href="glossary.html#traffic"> traffic
+ analysis</A>. Since we do not have to give it to him, our default is
+ not to.</P>
+<P>Even with the TOS hidden, you can still:</P>
+<UL>
+<LI>apply QOS rules to the tunneled (ESP) packets; for example, by
+ giving ESP packets a certain priority.</LI>
+<LI>apply QOS rules to the packets as they enter or exit the tunnel via
+ an IPsec virtual interface (eg.<VAR> ipsec0</VAR>).</LI>
+</UL>
+<P>See<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> for more
+ on the<VAR> hidetos=</VAR> parameter.</P>
+<H3><A name="deadtunnel">Can I recognise dead tunnels and shut them
+ down?</A></H3>
+<P>There is no general mechanism to do this is in the IPsec protocols.</P>
+<P>From time to time, there is discussion on the IETF Working Group<A href="mail.html#ietf">
+ mailing list</A> of adding a &quot;keep-alive&quot; mechanism (which some say
+ should be called &quot;make-dead&quot;), but it is a fairly complex problem and
+ no consensus has been reached on whether or how it should be done.</P>
+<P>The protocol does have optional<A href="#ignore"> delete-SA</A>
+ messages which one side can send when it closes a connection in hopes
+ this will cause the other side to do the same. FreeS/WAN does not
+ currently support these. In any case, they would not solve the problem
+ since:</P>
+<UL>
+<LI>a gateway that crashes or hangs would not send the messages</LI>
+<LI>the sender is not required to send them</LI>
+<LI>they are not authenticated, so any receiver that trusts them leaves
+ itself open to a<A href="glossary.html#DOS"> denial of service</A>
+ attack</LI>
+<LI>the receiver is not required to do anything about them</LI>
+<LI>the receiver cannot acknowledge them; the protocol provides no
+ mechanism for that</LI>
+<LI>since they are not acknowledged, the sender cannot rely on them</LI>
+</UL>
+<P>However, connections do have limited lifetimes and you can control
+ how many attempts your gateway makes to rekey before giving up. For
+ example, you can set:</P>
+<PRE>conn default
+ keyingtries=3
+ keylife=30m</PRE>
+<P>With these settings old connections will be cleaned up. Within 30
+ minutes of the other end dying, rekeying will be attempted. If it
+ succeeds, the new connection replaces the old one. If it fails, no new
+ connection is created. Either way, the old connection is taken down
+ when its lifetime expires.</P>
+<P>Here is a mailing list message on the topic from FreeS/WAN tech
+ support person Claudia Schmeing:</P>
+<PRE>You ask how to determine whether a tunnel is redundant:
+
+&gt; Can anybody explain the best way to determine this. Esp when a RW has
+&gt; disconnected? I thought 'ipsec auto --status' might be one way.
+
+If a tunnel goes down from one end, Linux FreeS/WAN on the
+other end has no way of knowing this until it attempts to rekey.
+Once it tries to rekey and fails, it will 'know' that the tunnel is
+down.
+
+Because it doesn't have a way of knowing the state until this point,
+it will also not be able to tell you the state via ipsec auto --status.
+
+&gt; However, comparing output from a working tunnel with that of one that
+&gt; was closed
+&gt; did not show clearly show tunnel status.
+
+If your tunnel is down but not 'unrouted' (see man ipsec_auto), you
+should not be able to ping the opposite side of the tunnel. You can
+use this as an indicator of tunnel status.
+
+On a related note, you may be interested to know that as of 1.7,
+redundant tunnels caused by RW disconnections are likely to be
+less of a pain. From doc/CHANGES:
+
+ There is a new configuration parameter, uniqueids, to control a new Pluto
+ option: when a new connection is negotiated with the same ID as an old
+ one, the old one is deleted immediately. This should help eliminate
+ dangling Road Warrior connections when the same Road Warrior reconnects.
+ It thus requires that IDs not be shared by hosts (a previously legal but
+ probably useless capability). NOTE WELL: the sample ipsec.conf now has
+ uniqueids=yes in its config-setup section.
+
+
+Cheers,
+
+Claudia</PRE>
+<H3><A name="demanddial">Can I build IPsec tunnels over a demand-dialed
+ link?</A></H3>
+<P>This is possible, but not easy. FreeS/WAN technical lead Henry
+ Spencer wrote:</P>
+<PRE>&gt; 5. If the ISDN link goes down in between and is reestablished, the SAs
+&gt; are still up but the eroute are deleted and the IPsec interface shows
+&gt; garbage (with ifconfig)
+&gt; 6. Only restarting IPsec will bring the VPN back online.
+
+This one is awkward to solve. If the real interface that the IPsec
+interface is mounted on goes down, it takes most of the IPsec machinery
+down with it, and a restart is the only good way to recover.
+
+The only really clean fix, right now, is to split the machines in two:
+
+1. A minimal machine serves as the network router, and only it is aware
+that the link goes up and down.
+
+2. The IPsec is done on a separate gateway machine, which thinks it has
+a permanent network connection, via the router.
+
+This is clumsy but it does work. Trying to do both functions within a
+single machine is tricky. There is a software package (diald) which will
+give the illusion of a permanent connection for demand-dialed modem
+connections; I don't know whether it's usable for ISDN, or whether it can
+be made to cooperate properly with FreeS/WAN.
+
+Doing a restart each time the interface comes up *does* work, although it
+is a bit painful. I did that with PPP when I was running on a modem link;
+it wasn't hard to arrange the PPP scripts to bring IPsec up and down at
+the right times. (I'd meant to investigate diald but never found time.)
+
+In principle you don't need to do a complete restart on reconnect, but you
+do have to rebuild some things, and we have no nice clean way of doing
+only the necessary parts.</PRE>
+<P>In the same thread, one user commented:</P>
+<PRE>Subject: Re: linux-ipsec: IPsec and Dial Up Connections
+ Date: Wed, 22 Nov 2000
+ From: Andy Bradford &lt;andyb@calderasystems.com&gt;
+
+On Wed, 22 Nov 2000 19:47:11 +0100, Philip Reetz wrote:
+
+&gt; Are there any ideas what might be the cause of the problem and any way
+&gt; to work around it.
+&gt; Any help is highly appreciated.
+
+On my laptop, when using ppp there is a ip-up script in /etc/ppp that
+will be executed each time that the ppp interface is brought up.
+Likewise there is an ip-down script that is called when it is taken
+down. You might consider custimzing those to stop and start FreeS/WAN
+with each connection. I believe that ISDN uses the same files, though
+I could be wrong---there should be something similar though.</PRE>
+<H3><A name="GRE">Can I build GRE, L2TP or PPTP tunnels over IPsec?</A></H3>
+<P>Yes. Normally this is not necessary, but it is useful in a few
+ special cases. For example, if you must route non-IP packets such as
+ IPX, you will need to use a tunneling protocol that can route these
+ packets. IPsec can be layered around it for extra security. Another
+ example: you can provide failover protection for high availability (HA)
+ environments by combining IPsec with other tools. Ken Bantoft describes
+ one such setup in<A HREF="http://www.freeswan.ca/docs/HA"> Using
+ FreeS/WAN with Linux-HA, GRE, OSPF and BGP for enterprise grade VPN
+ solutions</A>.</P>
+<P>GRE over IPsec is covered as part of<A HREF="http://www.freeswan.ca/docs/HA">
+ that document</A>.<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/07/msg00209.html">
+ Here are links</A> to other GRE resources. Jacco de Leuw has created<A HREF="http://www.jacco2.dds.nl/networking/">
+ this page on L2TP over IPsec</A> with instructions for FreeS/WAN and
+ several other brands of IPsec software.</P>
+<P>Please let us know of other useful links via the<A HREF="mail.html">
+ mailing lists</A>.</P>
+<H3><A name="NetBIOS">... use Network Neighborhood (Samba, NetBIOS) over
+ IPsec?</A></H3>
+<P>Your local PC needs to know how to translate NetBIOS names to IP
+ addresses. It may do this either via a local LMHOSTS file, or using a
+ local or remote WINS server. The WINS server is preferable since it
+ provides a centralized source of the information to the entire network.
+ To use a WINS server over the<A HREF="glossary.html#VPN"> VPN</A> (or
+ any IP-based network), you must enable &quot;NetBIOS over TCP&quot;.</P>
+<P><A HREF="http://www.samba.org">Samba</A> can emulate a WINS server on
+ Linux.</P>
+<P> See also several discussions in our<A HREF="http://lists.freeswan.org/pipermail/users/2002-September/thread.html">
+ September 2002 Users archives</A></P>
+<H2><A name="setup.faq">Life's little mysteries</A></H2>
+<P>FreeS/WAN is a fairly complex product. (Neither the networks it runs
+ on nor the protocols it uses are simple, so it could hardly be
+ otherwise.) It therefore sometimes exhibits behaviour which can be
+ somewhat confusing, or has problems which are not easy to diagnose.
+ This section tries to explain those problems.</P>
+<P>Setup and configuration of FreeS/WAN are covered in other
+ documentation sections:</P>
+<UL>
+<LI><A href="quickstart.html">basic setup and configuration</A></LI>
+<LI><A href="adv_config.html">advanced configuration</A></LI>
+<LI><A href="trouble.html">Troubleshooting</A></LI>
+</UL>
+<P>However, we also list some of the commonest problems here.</P>
+<H3><A name="cantping">I cannot ping ....</A></H3>
+<P>This question is dealt with in the advanced configuration section
+ under the heading<A href="adv_config.html#multitunnel"> multiple
+ tunnels</A>.</P>
+<P>The standard subnet-to-subnet tunnel protects traffic<STRONG> only
+ between the subnets</STRONG>. To test it, you must use pings that go
+ from one subnet to the other.</P>
+<P>For example, suppose you have:</P>
+<PRE> subnet a.b.c.0/24
+ |
+ eth1 = a.b.c.1
+ gate1
+ eth0 = 192.0.2.8
+ |
+
+ ~ internet ~
+
+ |
+ eth0 = 192.0.2.11
+ gate2
+ eth1 = x.y.z.1
+ |
+ subnet x.y.z.0/24</PRE>
+<P>and the connection description:</P>
+<PRE>conn abc-xyz
+ left=192.0.2.8
+ leftsubnet=a.b.c.0/24
+ right=192.0.2.11
+ rightsubnet=x.y.z.0/24</PRE>
+<P>You can test this connection description only by sending a ping that
+ will actually go through the tunnel. Assuming you have machines at
+ addresses a.b.c.2 and x.y.z.2, pings you might consider trying are:</P>
+<DL>
+<DT>ping from x.y.z.2 to a.b.c.2 or vice versa</DT>
+<DD>Succeeds if tunnel is working. This is the<STRONG> only valid test
+ of the tunnel</STRONG>.</DD>
+<DT>ping from gate2 to a.b.c.2 or vice versa</DT>
+<DD><STRONG>Does not use tunnel</STRONG>. gate2 is not on protected
+ subnet.</DD>
+<DT>ping from gate1 to x.y.z.2 or vice versa</DT>
+<DD><STRONG>Does not use tunnel</STRONG>. gate1 is not on protected
+ subnet.</DD>
+<DT>ping from gate1 to gate2 or vice versa</DT>
+<DD><STRONG>Does not use tunnel</STRONG>. Neither gate is on a protected
+ subnet.</DD>
+</DL>
+<P>Only the first of these is a useful test of this tunnel. The others
+ do not use the tunnel. Depending on other details of your setup and
+ routing, they:</P>
+<UL>
+<LI>either fail, telling you nothing about the tunnel</LI>
+<LI>or succeed, telling you nothing about the tunnel since these packets
+ use some other route</LI>
+</UL>
+<P>In some cases, you may be able to get around this. For the example
+ network above, you could use:</P>
+<PRE> ping -I a.b.c.1 x.y.z.1</PRE>
+<P>Both the adresses given are within protected subnets, so this should
+ go through the tunnel.</P>
+<P>If required, you can build additional tunnels so that all the
+ machines involved can talk to all the others. See<A href="adv_config.html#multitunnel">
+ multiple tunnels</A> in the advanced configuration document for
+ details.</P>
+<H3><A name="forever">It takes forever to ...</A></H3>
+<P>Users fairly often report various problems involving long delays,
+ sometimes on tunnel setup and sometimes on operations done through the
+ tunnel, occasionally on simple things like ping or more often on more
+ complex operations like doing NFS or Samba through the tunnel.</P>
+<P>Almost always, these turn out to involve failure of a DNS lookup. The
+ timeouts waiting for DNS are typically set long so that you won't time
+ out when a query involves multiple lookups or long paths. Genuine
+ failures therefore produce long delays before they are detected.</P>
+<P>A mailing list message from project technical lead Henry Spencer:</P>
+<PRE>&gt; ... when i run /etc/rc.d/init.d/ipsec start, i get:
+&gt; ipsec_setup: Starting FreeS/WAN IPsec 1.5...
+&gt; and it just sits there, doesn't give back my bash prompt.
+
+Almost certainly, the problem is that you're using DNS names in your
+ipsec.conf, but DNS lookups are not working for some reason. You will
+get your prompt back... eventually. But the DNS timeouts are long.
+Doing something about this is on our list, but it is not easy.</PRE>
+<P>In the meanwhile, we recommend that connection descriptions in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> use numeric IP addresses rather than names which will
+ require a DNS lookup.</P>
+<P>Names that do not require a lookup are fine. For example:</P>
+<UL>
+<LI>a road warrior might use the identity<VAR>
+ rightid=@lancelot.example.org</VAR></LI>
+<LI>the gateway might use<VAR> leftid=@camelot.example.org</VAR></LI>
+</UL>
+<P>These are fine. The @ sign prevents any DNS lookup. However, do not
+ attempt to give the gateway address as<VAR> left=camelot.example.org</VAR>
+. That requires a lookup.</P>
+<P>A post from one user after solving a problem with long delays:</P>
+<PRE>Subject: Final Answer to Delay!!!
+ Date: Mon, 19 Feb 2001
+ From: &quot;Felippe Solutions&quot; &lt;felippe@solutionstecnologia.com.br&gt;
+
+Sorry people, but seems like the Delay problem had nothing to do with
+freeswan.
+
+The problem was DNS as some people sad from the beginning, but not the way
+they thought it was happening. Samba, ssh, telnet and other apps try to
+reverse lookup addresses when you use IP numbers (Stupid that ahh).
+
+I could ping very fast because I always ping with &quot;-n&quot; option, but I don't
+know the option on the other apps to stop reverse addressing so I don't use
+it.</PRE>
+<P>This post is fairly typical. These problems are often tricky and
+ frustrating to diagnose, and most turn out to be DNS-related.</P>
+<P>One suggestion for diagnosis: test with both names and addresses if
+ possible. For example, try all of:</P>
+<UL>
+<LI>ping<VAR> address</VAR></LI>
+<LI>ping -n<VAR> address</VAR></LI>
+<LI>ping<VAR> name</VAR></LI>
+</UL>
+<P>If these behave differently, the problem must be DNS-related since
+ the three commands do exactly the same thing except for DNS lookups.</P>
+<H3><A name="route">I send packets to the tunnel with route(8) but they
+ vanish</A></H3>
+<P>IPsec connections are designed to carry only packets travelling
+ between pre-defined connection endpoints. As project technical lead
+ Henry Spencer put it:</P>
+<BLOCKQUOTE> IPsec tunnels are not just virtual wires; they are virtual
+ wires with built-in access controls. Negotiation of an IPsec tunnel
+ includes negotiation of access rights for it, which don't include
+ packets to/from other IP addresses. (The protocols themselves are quite
+ inflexible about this, so there are limits to what we can do about it.)</BLOCKQUOTE>
+<P>For fairly obvious security reasons, and to comply with the IPsec
+ RFCs,<A href="glossary.html#KLIPS"> KLIPS</A> drops any packets it
+ receives that are not allowed on the tunnels currently defined. So if
+ you send it packets with<VAR> route(8)</VAR>, and suitable tunnels are
+ not defined, the packets vanish. Whether this is reported in the logs
+ depends on the setting of<VAR> klipsdebug</VAR> in your<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> file.</P>
+<P>To rescue vanishing packets, you must ensure that suitable tunnels
+ for them exist, by editing the connection descriptions in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>. For example, supposing you have a simple setup:</P>
+<PRE> leftsubnet -- leftgateway === internet === roadwarrior</PRE>
+<P>If you want to give the roadwarrior access to some resource that is
+ located behind the left gateway but is not in the currently defined
+ left subnet, then the usual procedure is to define an additional tunnel
+ for those packets by creating a new connection description.</P>
+<P>In some cases, it may be easier to alter an existing connection
+ description, enlarging the definition of<VAR> leftsubnet</VAR>. For
+ example, instead of two connection descriptions with 192.168.8.0/24 and
+ 192.168.9.0/24 as their<VAR> leftsubnet</VAR> parameters, you can use a
+ single description with 192.168.8.0/23.</P>
+<P>If you have multiple endpoints on each side, you need to ensure that
+ there is a route for each pair of endpoints. See this<A href="adv_config.html#multitunnel">
+ example</A>.</P>
+<H3><A name="down_route">When a tunnel goes down, packets vanish</A></H3>
+<P>This is a special case of the vanishing packet problem described in
+ the previous question. Whenever KLIPS sees packets for which it does
+ not have a tunnel, it drops them.</P>
+<P>When a tunnel goes away, either because negotiations with the other
+ gateway failed or because you gave an<VAR> ipsec auto --down</VAR>
+ command, the route to its other end is left pointing into KLIPS, and
+ KLIPS will drop packets it has no tunnel for.</P>
+<P>This is a documented design decision, not a bug. FreeS/WAN must not
+ automatically adjust things to send packets via another route. The
+ other route might be insecure.</P>
+<P>Of course, re-routing may be necessary in many cases. In those cases,
+ you have to do it manually or via scripts. We provide the<VAR> ipsec
+ auto --unroute</VAR> command for these cases.</P>
+<P>From<A href="manpage.d/ipsec_auto.8.html"> ipsec_auto(8)</A>:</P>
+<BLOCKQUOTE> Normally, pluto establishes a route to the destination
+ specified for a connection as part of the --up operation. However, the
+ route and only the route can be established with the --route operation.
+ Until and unless an actual connection is established, this discards any
+ packets sent there, which may be preferable to having them sent
+ elsewhere based on a more general route (e.g., a default route).</BLOCKQUOTE><BLOCKQUOTE>
+ Normally, pluto's route to a destination remains in place when a --down
+ operation is used to take the connection down (or if connection setup,
+ or later automatic rekeying, fails). This permits establishing a new
+ connection (perhaps using a different specification; the route is
+ altered as necessary) without having a ``window'' in which packets
+ might go elsewhere based on a more general route. Such a route can be
+ removed using the --unroute operation (and is implicitly removed by
+ --delete).</BLOCKQUOTE>
+<P>See also this mailing list<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00523.html">
+ message</A>.</P>
+<H3><A name="firewall_ate">The firewall ate my packets!</A></H3>
+<P>If firewalls filter out:</P>
+<UL>
+<LI>either the UDP port 500 packets used in IKE negotiations</LI>
+<LI>or the ESP and AH (protocols 50 and 51) packets used to implement
+ the IPsec tunnel</LI>
+</UL>
+<P>then IPsec cannot work. The first thing to check if packets seem to
+ be vanishing is the firewall rules on the two gateway machines and any
+ other machines along the path that you have access to.</P>
+<P>For details, see our document on<A href="firewall.html"> firewalls</A>
+.</P>
+<P>Some advice from technical lead Henry Spencer on diagnosing such
+ problems:</P>
+<PRE>&gt; &gt; Packets vanishing between the hardware interface and the ipsecN interface
+&gt; &gt; is usually the result of firewalls not being configured to let them in...
+&gt;
+&gt; Thanks for the suggestion. If only it were that simple! My ipchains startup
+&gt; script does take care of that, but just in case I manually inserted rules
+&gt; accepting everything from london on dublin. No difference.
+
+The other thing to check is whether the &quot;RX packets dropped&quot; count on the
+ipsecN interface (run &quot;ifconfig ipsecN&quot;, for N=1 or whatever, to see the
+counts) is rising. If so, then there's some sort of configuration mismatch
+between the two ends, and IPsec itself is rejecting them. If none of the
+ipsecN counts is rising, then the packets are never reaching the IPsec
+machinery, and the problem is almost certainly in firewalls etc.</PRE>
+<H3><A name="dropconn">Dropped connections</A></H3>
+<P>Networks being what they are, IPsec connections can be broken for any
+ number of reasons, ranging from hardware failures to various software
+ problems such as the path MTU problems discussed<A href="#pmtu.broken">
+ elsewhere in the FAQ</A>. Fortunately, various diagnostic tools exist
+ that help you sort out many of the possible problems.</P>
+<P>There is one situation, however, where FreeS/WAN (using default
+ settings) may destroy a connection for no readily apparent reason. This
+ occurs when things are<STRONG> misconfigured</STRONG> so that<STRONG>
+ two tunnels</STRONG> from the same gateway expect<STRONG> the same
+ subnet on the far end</STRONG>.</P>
+<P>In this situation, the first tunnel comes up fine and works until the
+ second is established. At that point, because of the way we track
+ connections internally, the first tunnel ceases to exist as far as this
+ gateway is concerned. Of course the far end does not know that, and a
+ storm of error messages appears on both systems as it tries to use the
+ tunnel.</P>
+<P>If the far end gives up, goes back to square one and negotiates a new
+ tunnel, then that wipes out the second tunnel and ...</P>
+<P>The solution is simple.<STRONG> Do not build multiple conn
+ descriptions with the same remote subnet</STRONG>.</P>
+<P>This is actually intended to be a feature, rather than a bug.
+ Consider the situation where a single remote system goes down, then
+ comes back up and reconnects to the gateway. It is useful to have the
+ gateway tear down the old tunnel and recover resources when the
+ reconnection is made. It recognises that situation by checking the
+ remote subnet for each tunnel it builds and discarding duplicates. This
+ works fine as long as you don't configure multiple tunnels with the
+ same remote subnet.</P>
+<P>If this behaviour is inconvenient for you, you can disable it by
+ setting<VAR> uniqueids=no</VAR> in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>.</P>
+<H3><A name="defaultroutegone">Disappearing %defaultroute</A></H3>
+<P>When an underlying connection (eg. ppp) goes down, FreeS/WAN will not
+ recover properly without a little help. Here are the symptoms that
+ FreeS/WAN user Michael Carmody noticed:</P>
+<PRE>
+&gt; After about 24 hours the freeswan connection takes over the default route.
+&gt;
+&gt; i.e instead of deafult gateway pointing to the router via eth0, it becomes a
+&gt; pointer to the router via ipsec0.
+
+&gt; All internet access is then lost as all replies (and not just the link I
+&gt; wanted) are routed out ipsec0 and the router doesn't respond to the ipsec
+&gt; traffic.
+</PRE>
+<P>If you're using a FreeS/WAN 2.x/KLIPS system, simply re-attach the
+ IPsec virtual interface with<EM> ipsec tnconfig</EM> command such as:</P>
+<PRE> ipsec tnconfig --attach --virtual ipsec0 --physical ppp0</PRE>
+<P>In your command, name the physical and virtual interfaces as they
+ appear paired on your system during regular uptime. For a system with
+ several physical/virtual interface pairs on flaky links, you'll need
+ more than one such command. If you're using FreeS/WAN 1.x, you must
+ restart FreeS/WAN, which is more time consuming.</P>
+<P><A href="http://lists.freeswan.org/pipermail/design/2002-July/003070.html">
+ Here</A> is a script which can help to automate the process of
+ FreeS/WAN restart at need. It could easily be adapted to use tnconfig
+ instead.</P>
+<H3><A name="tcpdump.faq">TCPdump on the gateway shows strange things</A>
+</H3>
+ As another user pointed out, keeping the connect
+<P>Attempting to look at IPsec packets by running monitoring tools on
+ the IPsec gateway machine can produce silly results. That machine is
+ mangling the packets for IPsec, and possibly for firewall or NAT
+ purposes as well. If the internals of the machine's IP stack are not
+ what the monitoring tool expects, then the tool can misinterpret them
+ and produce nonsense output.</P>
+<P>See our<A href="testing.html#tcpdump.test"> testing</A> document for
+ more detail.</P>
+<H3><A name="no_trace">Traceroute does not show anything between the
+ gateways</A></H3>
+<P>As far as traceroute can see, the two gateways are one hop apart; the
+ data packet goes directly from one to the other through the tunnel. Of
+ course the outer packets that implement the tunnel pass through
+ whatever lies between the gateways, but those packets are built and
+ dismantled by the gateways. Traceroute does not see them and cannot
+ report anything about their path.</P>
+<P>Here is a mailing list message with more detail.</P>
+<PRE>Date: Mon, 14 May 2001
+To: linux-ipsec@freeswan.org
+From: &quot;John S. Denker&quot; &lt;jsd@research.att.com&lt;
+Subject: Re: traceroute: one virtual hop
+
+At 02:20 PM 5/14/01 -0400, Claudia Schmeing wrote:
+&gt;
+&gt;&gt; &gt; A bonus question: traceroute in subnet to subnet enviroment looks like:
+&gt;&gt; &gt;
+&gt;&gt; &gt; traceroute to andris.dmz (172.20.24.10), 30 hops max, 38 byte packets
+&gt;&gt; &gt; 1 drama (172.20.1.1) 0.716 ms 0.942 ms 0.434 ms
+&gt;&gt; &gt; 2 * * *
+&gt;&gt; &gt; 3 andris.dmz (172.20.24.10) 73.576 ms 78.858 ms 79.434 ms
+&gt;&gt; &gt;
+&gt;&gt; &gt; Why aren't there the other hosts which take part in the delivery during
+&gt; * * * ?
+&gt;
+&gt;If there is an ipsec tunnel between GateA and Gate B, this tunnel forms a
+&gt;'virtual wire'. When it is tunneled, the original packet becomes an inner
+&gt;packet, and new ESP and/or AH headers are added to create an outer packet
+&gt;around it. You can see an example of how this is done for AH at
+&gt;doc/ipsec.html#AH . For ESP it is similar.
+&gt;
+&gt;Think about the packet's path from the inner packet's perspective.
+&gt;It leaves the subnet, goes into the tunnel, and re-emerges in the second
+&gt;subnet. This perspective is also the only one available to the
+&gt;'traceroute' command when the IPSec tunnel is up.
+
+Claudia got this exactly right. Let me just expand on a couple of points:
+
+*) GateB is exactly one (virtual) hop away from GateA. This is how it
+would be if there were a physically private wire from A to B. The
+virtually private connection should work the same, and it does.
+
+*) While the information is in transit from GateA to GateB, the hop count
+of the outer header (the &quot;envelope&quot;) is being decremented. The hop count
+of the inner header (the &quot;contents&quot; of the envelope) is not decremented and
+should not be decremented. The hop count of the outer header is not
+derived from and should not be derived from the hop count of the inner header.
+
+Indeed, even if the packets did time out in transit along the tunnel, there
+would be no way for traceroute to find out what happened. Just as
+information cannot leak _out_ of the tunnel to the outside, information
+cannot leak _into_ the tunnel from outside, and this includes ICMP messages
+from routers along the path.
+
+There are some cases where one might wish for information about what is
+happening at the IP layer (below the tunnel layer) -- but the protocol
+makes no provision for this. This raises all sorts of conceptual issues.
+AFAIK nobody has ever cared enough to really figure out what _should_
+happen, let alone implement it and standardize it.
+
+*) I consider the &quot;* * *&quot; to be a slight bug. One might wish for it to be
+replaced by &quot;GateB GateB GateB&quot;. It has to do with treating host-to-subnet
+traffic different from subnet-to-subnet traffic (and other gory details).
+I fervently hope KLIPS2 will make this problem go away.
+
+*) If you want to ask questions about the link from GateA to GateB at the
+IP level (below the tunnel level), you have to ssh to GateA and launch a
+traceroute from there.</PRE>
+<H2><A name="man4debug">Testing in stages</A></H2>
+<P>It is often useful in debugging to test things one at a time:</P>
+<UL>
+<LI>disable IPsec entirely, for example by turning it off with
+ chkconfig(8), and make sure routing works</LI>
+<LI>Once that works, try a manually keyed connection. This does not
+ require key negotiation between Pluto and the key daemon on the other
+ end.</LI>
+<LI>Once that works, try automatically keyed connections</LI>
+<LI>Once IPsec works, add packet compression</LI>
+<LI>Once everything seems to work, try stress tests with large
+ transfers, many connections, frequent re-keying, ...</LI>
+</UL>
+<P>FreeS/WAN releases are tested for all of these, so you can be
+ reasonably certain they<EM> can</EM> do them all. Of course, that does
+ not mean they<EM> will</EM> on the first try, especially if you have
+ some unusual configuration.</P>
+<P>The rest of this section gives information on diagnosing the problem
+ when each of the above steps fails.</P>
+<H3><A name="nomanual">Manually keyed connections don't work</A></H3>
+<P>Suspect one of:</P>
+<UL>
+<LI>mis-configuration of IPsec system in the /etc/ipsec.conf file
+<BR> common errors are incorrect interface or next hop information</LI>
+<LI>mis-configuration of manual connection in the /etc/ipsec.conf file</LI>
+<LI>routing problems causing IPsec packets to be lost</LI>
+<LI>bugs in KLIPS</LI>
+<LI>mismatch between the transforms we support and those another IPsec
+ implementation offers.</LI>
+</UL>
+<H3><A name="spi_error">One manual connection works, but second one
+ fails</A></H3>
+<P>This is a fairly common problem when attempting to configure multiple
+ manually keyed connections from a single gateway.</P>
+<P>Each connection must be identified by a unique<A href="glossary.html#SPI">
+ SPI</A> value. For automatic connections, these values are assigned
+ automatically. For manual connections, you must set them with<VAR> spi=</VAR>
+ statements in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A>.</P>
+<P>Each manual connection must have a unique SPI value in the range
+ 0x100 to 0x999. Two or more with the same value will fail. For details,
+ see our doc section<A href="adv_config.html#prodman"> Using manual
+ keying in production</A> and the man page<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>.</P>
+<H3><A name="man_no_auto">Manual connections work, but automatic keying
+ doesn't</A></H3>
+<P>The most common reason for this behaviour is a firewall dropping the
+ UDP port 500 packets used in key negotiation.</P>
+<P>Other possibilities:</P>
+<UL>
+<LI>mis-configuration of auto connection in the /etc/ipsec.conf file.
+<P>One common configuration error is forgetting that you need<VAR>
+ auto=add</VAR> to load the connection description on the receiving end
+ so it recognises the connection when the other end asks for it.</P>
+</LI>
+<LI>error in shared secret in /etc/ipsec.secrets</LI>
+<LI>one gateway lacks a route to the other so Pluto's UDP packets are
+ lost</LI>
+<LI>bugs in Pluto</LI>
+<LI>incompatibilities between Pluto's<A href="glossary.html#IKE"> IKE</A>
+ implementation and the IKE at the other end of the tunnel.
+<P>Some possibile problems are discussed in out<A href="interop.html#interop.problem">
+ interoperation</A> document.</P>
+</LI>
+</UL>
+<H3><A name="nocomp">IPsec works, but connections using compression fail</A>
+</H3>
+<P>When we first added compression, we saw some problems:</P>
+<UL>
+<LI>compatibility issues with other implementations. We followed the
+ RFCs and omitted some extra material that many compression libraries
+ add by default. Some other implementations left the extras in</LI>
+<LI>bugs in assembler compression routines on non-Intel CPUs. The
+ workaround is to use C code instead of possibly problematic assembler.</LI>
+</UL>
+<P>We have not seen either problem in some time (at least six months as
+ I write in March 2002), but if you have some unusual configuration then
+ you may see them.</P>
+<H3><A name="pmtu.broken">Small packets work, but large transfers fail</A>
+</H3>
+<P>If tests with ping(1) and a small packet size succeed, but tests or
+ transfers with larger packet sizes fail, suspect problems with packet
+ fragmentation and perhaps<A href="glossary.html#pathMTU"> path MTU
+ discovery</A>.</P>
+<P>Our<A href="trouble.html#bigpacket"> troubleshooting document</A>
+ covers these problems. Information on the underlying mechanism is in
+ our<A href="background.html#MTU.trouble"> background</A> document.</P>
+<H3><A name="subsub">Subnet-to-subnet works, but tests from the gateways
+ don't</A></H3>
+<P>This is described under<A href="#cantping"> I cannot ping...</A>
+ above.</P>
+<H2><A name="compile.faq">Compilation problems</A></H2>
+<H3><A name="gmp.h_missing">gmp.h: No such file or directory</A></H3>
+<P>Pluto needs the GMP (<STRONG>G</STRONG>NU</P>
+<P><STRONG>M</STRONG>ulti-<STRONG>P</STRONG>recision) library for the
+ large integer calculations it uses in<A href="glossary.html#public">
+ public key</A> cryptography. This error message indicates a failure to
+ find the library. You must install it before Pluto will compile.</P>
+<P>The GMP library is included in most Linux distributions. Typically,
+ there are two RPMs, libgmp and libgmp-devel, You need to<EM> install
+ both</EM>, either from your distribution CDs or from your vendor's web
+ site.</P>
+<P>On Debian, a mailing list message reports that the command to give is<VAR>
+ apt-get install gmp2</VAR>.</P>
+<P>For more information and the latest version, see the<A href="http://www.swox.com/gmp/">
+ GMP home page</A>.</P>
+<H3><A name="noVM">... virtual memory exhausted</A></H3>
+<P>We have had several reports of this message appearing, all on SPARC
+ Linux. Here is a mailing message on a solution:</P>
+<PRE>&gt; ipsec_sha1.c: In function `SHA1Transform':
+&gt; ipsec_sha1.c:95: virtual memory exhausted
+
+I'm seeing exactly the same problem on an Ultra with 256MB ram and 500
+MB swap. Except I am compiling version 1.5 and its Red Hat 6.2.
+
+I can get around this by using -O instead of -O2 for the optimization
+level. So it is probably a bug in the optimizer on the sparc complier.
+I'll try and chase this down on the sparc lists.</PRE>
+<H2><A name="error">Interpreting error messages</A></H2>
+<H3><A name="route-client">route-client (or host) exited with status 7</A>
+</H3>
+<P>Here is a discussion of this error from FreeS/WAN &quot;listress&quot; (mailing
+ list tech support person) Claudia Schmeing. The &quot;FAQ on the network
+ unreachable error&quot; which she refers to is the next question below.</P>
+<PRE>&gt; I reached the point where the two boxes (both on dial-up connections, but
+&gt; treated as static IPs by getting the IP and editing ipsec.conf after the
+&gt; connection is established) to the point where they exchange some info, but I
+&gt; get an error like &quot;route-client command exited with status 7 \n internal
+&gt; error&quot;.
+&gt; Where can I find a description of this error?
+
+In general, if the FAQ doesn't cover it, you can search the mailing list
+archives - I like to use
+http://www.sandelman.ottawa.on.ca/linux-ipsec/
+but you can see doc/mail.html for different archive formats.
+
+
+Your error comes from the _updown script, which performs some
+routing and firewall functions to help Linux FreeS/WAN. More info
+is available at doc/firewall.html and man ipsec.conf. Its routing
+is integral to the health of Linux FreeS/WAN; it also provides facility
+to insert custom firewall rules to be executed when you create or destroy
+a connection.
+
+Yours is, of course, a routing error. You can be fairly sure the routing
+machinery is saying &quot;network is unreachable&quot;. There's a FAQ on the
+&quot;network is unreachable&quot; error, but more information is available now; read on.
+
+If your _updown script is recent (for example if it shipped with
+Linux FreeS/WAN 1.91), you will see another debugging line in your logs
+that looks something like this:
+
+&gt; output: /usr/local/lib/ipsec/_updown: `route add -net 128.174.253.83
+&gt; netmask 255.255.255.255 dev ipsec0 gw 66.92.93.161' failed
+
+This is, of course, the system route command that exited with status 7,
+(ie. failed). Man route for details. Seeing the command typed out yields
+more information. If your _updown script is older, you may wish to update
+it to show the command explicitly.
+
+Three parameters fed to the route command: net, netmask and gw [gateway]
+are derived from things you've put in ipsec.conf.
+
+Net and netmask are derived from the peer's IP and mask. In more detail:
+
+You may see a routing error when routing to a client (ie. subnet), or
+to a host (IPSec gateway or freestanding host; a box that does IPSec for
+itself). In _updown, the &quot;route-client&quot; section is responsible to set up
+the route for IPSec'd (usually, read 'tunneled') packets headed to a
+peer subnet. Similarly, route-host routes IPSec'd packets to a peer host
+or IPSec gateway.
+
+When routing to a 'client', net and netmask are ipsec.conf's left- or
+rightsubnet (whichever is not local). Similarly, when routing to a
+'host' the net is left or right. Host netmask is always /32, indicating a
+single machine.
+
+Gw is nexthop's value. Again, the value in question is left- or rightnexthop,
+whichever is local. Where left/right or left-/rightnexthop has the special
+value %defaultroute (described in man ipsec.conf), gw will automagically get
+the value of the next hop on the default route.
+
+Q: &quot;What's a nexthop and why do I need one?&quot;
+
+A: 'nexthop' is a routing kluge; its value is the next hop away
+ from the machine that's doing IPSec, and toward your IPSec peer.
+ You need it to get the processed packets out of the local system and
+ onto the wire. While we often route other packets through the machine
+ that's now doing IPSec, and are done with it, this does not suffice here.
+ After packets are processed with IPSec, this machine needs to know where
+ they go next. Of course using the 'IPSec gateway' as their routing gateway
+ would cause an infinite loop! [To visualize this, see the packet flow
+ diagram at doc/firewall.html.] To avoid this, we route packets through
+ the next hop down their projected path.
+
+Now that you know the background, consider:
+1. Did you test routing between the gateways in the absence of Linux
+ FreeS/WAN, as recommended? You need to ensure the two machines that
+ will be running Linux FreeS/WAN can route to one another before trying to
+ make a secure connection.
+2. Is there anything obviously wrong with the sense of your route command?
+
+Normally, this problem is caused by an incorrect local nexthop parameter.
+Check out the use of %defaultroute, described in man ipsec.conf. This is
+a simple way to set nexthop for most people. To figure nexthop out by hand,
+traceroute in-the-clear to your IPSec peer. Nexthop is the traceroute's
+first hop after your IPSec gateway.</PRE>
+<H3><A name="unreachable">SIOCADDRT:Network is unreachable</A></H3>
+<P>This message is not from FreeS/WAN, but from the Linux IP stack
+ itself. That stack is seeing packets it has no route for, either
+ because your routing was broken before FreeS/WAN started or because
+ FreeS/WAN's changes broke it.</P>
+<P>Here is a message from Claudia suggesting ways to diagnose and fix
+ such problems:</P>
+<PRE>You write,
+&gt; I have correctly installed freeswan-1.8 on RH7.0 kernel 2.2.17, but when
+&gt; I setup a VPN connection with the other machine(RH5.2 Kernel 2.0.36
+&gt; freeswan-1.0, it works well.) it told me that
+&gt; &quot;SIOCADDRT:Network is unreachable&quot;! But the network connection is no
+&gt; problem.
+
+Often this error is the result of a misconfiguration.
+
+Be sure that you can route successfully in the absence of Linux
+FreeS/WAN. (You say this is no problem, so proceed to the next step.)
+
+Use a custom copy of the default updownscript. Do not change the route
+commands, but add a diagnostic message revealing the exact text of the
+route command. Is there a problem with the sense of the route command
+that you can see? If so, then re-examine those ipsec.conf settings
+that are being sent to the route command.
+
+You may wish to use the ipsec auto --route and --unroute commands to
+troubleshoot the problem. See man ipsec_auto for details.</PRE>
+<P>Since the above message was written, we have modified the updown
+ script to provide a better diagnostic for this problem. Check<VAR>
+ /var/log/messages</VAR>.</P>
+<P>See also the FAQ question<A href="#route-client"> route-client (or
+ host) exited with status 7</A>.</P>
+<H3><A name="modprobe">ipsec_setup: modprobe: Can't locate module ipsec</A>
+</H3>
+<H3><A name="noKLIPS">ipsec_setup: Fatal error, kernel appears to lack
+ KLIPS</A></H3>
+<P>These messages indicate an installation failure. The kernel you are
+ running does not contain the<A href="glossary.html#KLIPS"> KLIPS
+ (kernel IPsec)</A> code.</P>
+<P>Note that the &quot;modprobe: Can't locate module ipsec&quot; message appears
+ even if you are not using modules. If there is no KLIPS in your kernel,
+ FreeS/WAN tries to load it as a module. If that fails, you get this
+ message.</P>
+<P>Commands you can quickly try are:</P>
+<DL>
+<DT><VAR>uname -a</VAR></DT>
+<DD>to get details, including compilation date and time, of the
+ currently running kernel</DD>
+<DT><VAR>ls /</VAR></DT>
+<DT><VAR>ls /boot</VAR></DT>
+<DD>to ensure a new kernel is where it should be. If kernel compilation
+ puts it in<VAR> /</VAR> but<VAR> lilo</VAR> wants it in<VAR> /boot</VAR>
+, then you should uncomment the<VAR> INSTALL_PATH=/boot</VAR> line in
+ the kernel<VAR> Makefile</VAR>.</DD>
+<DT><VAR>more /etc/lilo.conf</VAR></DT>
+<DD>to see that<VAR> lilo</VAR> has correct information</DD>
+<DT><VAR>lilo</VAR></DT>
+<DD>to ensure that information in<VAR> /etc/lilo.conf</VAR> has been
+ transferred to the boot sector</DD>
+</DL>
+<P>If those don't find the problem, you have to go back and check
+ through the<A href="install.html"> install</A> procedure to see what
+ was missed.</P>
+<P>Here is one of Claudia's messages on the topic:</P>
+<PRE>&gt; I tried to install freeswan 1.8 on my mandrake 7.2 test box. ...
+
+&gt; It does show version and some output for whack.
+
+Yes, because the Pluto (daemon) part of ipsec is installed correctly, but
+as we see below the kernel portion is not.
+
+&gt; However, I get the following from /var/log/messages:
+&gt;
+&gt; Mar 11 22:11:55 pavillion ipsec_setup: Starting FreeS/WAN IPsec 1.8...
+&gt; Mar 11 22:12:02 pavillion ipsec_setup: modprobe: Can't locate module ipsec
+&gt; Mar 11 22:12:02 pavillion ipsec_setup: Fatal error, kernel appears to lack
+&gt; KLIPS.
+
+This is your problem. You have not successfully installed a kernel with
+IPSec machinery in it.
+
+Did you build Linux FreeS/WAN as a module? If so, you need to ensure that
+your new module has been installed in the directory where your kernel
+loader normally finds your modules. If not, you need to ensure
+that the new IPSec-enabled kernel is being loaded correctly.
+
+See also doc/install.html, and INSTALL in the distro.</PRE>
+<H3><A name="noDNS">ipsec_setup: ... failure to fetch key for ... from
+ DNS</A></H3>
+<P>Quoting Henry:</P>
+<PRE>Note that by default, FreeS/WAN is now set up to
+ (a) authenticate with RSA keys, and
+ (b) fetch the public key of the far end from DNS.
+Explicit attention to ipsec.conf will be needed if you want
+to do something different.</PRE>
+<P>and Claudia, responding to the same user:</P>
+<PRE>You write,
+
+&gt; My current setup in ipsec.conf is leftrsasigkey=%dns I have
+&gt; commented this and authby=rsasig out. I am able to get ipsec running,
+&gt; but what I find is that the documentation only specifies for %dns are
+&gt; there any other values that can be placed in this variable other than
+&gt; %dns and the key? I am also assuming that this is where I would place
+&gt; my public key for the left and right side as well is this correct?
+
+Valid values for authby= are rsasig and secret, which entail authentication
+by RSA signature or by shared secret, respectively. Because you have
+commented authby=rsasig out, you are using the default value of authby=secret.
+
+When using RSA signatures, there are two ways to get the public key for the
+IPSec peer: either copy it directly into *rsasigkey= in ipsec.conf, or
+fetch it from dns. The magic value %dns for *rsasigkey parameters says to
+try to fetch the peer's key from dns.
+
+For any parameters, you may find their significance and special values in
+man ipsec.conf. If you are setting up keys or secrets, be sure also to
+reference man ipsec.secrets.</PRE>
+<H3><A name="dup_address">ipsec_setup: ... interfaces ... and ... share
+ address ...</A></H3>
+<P>This is a fatal error. FreeS/WAN cannot cope with two or more
+ interfaces using the same IP address. You must re-configure to avoid
+ this.</P>
+<P>A mailing list message on the topic from Pluto developer Hugh
+ Redelmeier:</P>
+<PRE>| I'm trying to get freeswan working between two machine where one has a ppp
+| interface.
+| I've already suceeded with two machines with ethernet ports but the ppp
+| interface is causing me problems.
+| basically when I run ipsec start i get
+| ipsec_setup: Starting FreeS/WAN IPsec 1.7...
+| ipsec_setup: 003 IP interfaces ppp1 and ppp0 share address 192.168.0.10!
+| ipsec_setup: 003 IP interfaces ppp1 and ppp2 share address 192.168.0.10!
+| ipsec_setup: 003 IP interfaces ppp0 and ppp2 share address 192.168.0.10!
+| ipsec_setup: 003 no public interfaces found
+|
+| followed by lots of cannot work out interface for connection messages
+|
+| now I can specify the interface in ipsec.conf to be ppp0 , but this does
+| not affect the above behaviour. A quick look in server.c indicates that the
+| interfaces value is not used but some sort of raw detect happens.
+|
+| I guess I could prevent the formation of the extra ppp interfaces or
+| allocate them different ip but I'd rather not. if at all possible. Any
+| suggestions please.
+
+Pluto won't touch an interface that shares an IP address with another.
+This will eventually change, but it probably won't happen soon.
+
+For now, you will have to give the ppp1 and ppp2 different addresses.</PRE>
+<H3><A name="kflags">ipsec_setup: Cannot adjust kernel flags</A></H3>
+<P>A mailing list message form technical lead Henry Spencer:</P>
+<PRE>&gt; When FreeS/WAN IPsec 1.7 is starting on my 2.0.38 Linux kernel the following
+&gt; error message is generated:
+&gt; ipsec_setup: Cannot adjust kernel flags, no /proc/sys/net/ipsec directory!
+&gt; What is supposed to create this directory and how can I fix this problem?
+
+I think that directory is a 2.2ism, although I'm not certain (I don't have
+a 2.0.xx system handy any more for testing). Without it, some of the
+ipsec.conf config-setup flags won't work, but otherwise things should
+function. </PRE>
+<P>You also need to enable the<VAR> /proc</VAR> filesystem in your
+ kernel configuration for these operations to work.</P>
+<H3><A name="message_num">Message numbers (MI3, QR1, et cetera) in Pluto
+ messages</A></H3>
+<P>Pluto messages often indicate where Pluto is in the IKE protocols.
+ The letters indicate<STRONG> M</STRONG>ain mode or<STRONG> Q</STRONG>
+uick mode and<STRONG> I</STRONG>nitiator or<STRONG> R</STRONG>esponder.
+ The numerals are message sequence numbers. For more detail, see our<A href="ipsec.html#sequence">
+ IPsec section</A>.</P>
+<H3><A name="conn_name">Connection names in Pluto error messages</A></H3>
+<P>From Pluto programmer Hugh Redelmeier:</P>
+<PRE>| Jan 17 16:21:10 remus Pluto[13631]: &quot;jumble&quot; #1: responding to Main Mode from Road Warrior 130.205.82.46
+| Jan 17 16:21:11 remus Pluto[13631]: &quot;jumble&quot; #1: no suitable connection for peer @banshee.wittsend.com
+|
+| The connection &quot;jumble&quot; has nothing to do with the incoming
+| connection requests, which were meant for the connection &quot;banshee&quot;.
+
+You are right. The message tells you which Connection Pluto is
+currently using, which need not be the right one. It need not be the
+right one now for the negotiation to eventually succeed! This is
+described in ipsec_pluto(8) in the section &quot;Road Warrior Support&quot;.
+
+There are two times when Pluto will consider switching Connections for
+a state object. Both are in response to receiving ID payloads (one in
+Phase 1 / Main Mode and one in Phase 2 / Quick Mode). The second is
+not unique to Road Warriors. In fact, neither is the first any more
+(two connections for the same pair of hosts could differ in Phase 1 ID
+payload; probably nobody else has tried this).</PRE>
+<H3><A name="cantorient">Pluto: ... can't orient connection</A></H3>
+<P>Older versions of FreeS/WAN used this message. The same error now
+ gives the &quot;we have no ipsecN ...&quot; error described just below.</P>
+<H3><A name="no.interface">... we have no ipsecN interface for either
+ end of this connection</A></H3>
+<P>Your tunnel has no IP address which matches the IP address of any of
+ the available IPsec interfaces. Either you've misconfigured the
+ connection, or you need to define an appropriate IPsec interface
+ connection.<VAR> interfaces=%defaultroute</VAR> works in many cases.</P>
+<P>A longer story: Pluto needs to know whether it is running on the
+ machine which the connection description calls<VAR> left</VAR> or on<VAR>
+ right</VAR>. It figures that out by:</P>
+<UL>
+<LI>looking at the interfaces given in<VAR> interfaces=</VAR> lines in
+ the<VAR> config setup</VAR> section</LI>
+<LI>discovering the IP addresses for those interfaces</LI>
+<LI>searching for a match between those addresses and the ones given in<VAR>
+ left=</VAR> or<VAR> right=</VAR> lines.</LI>
+</UL>
+<P>Normally a match is found. Then Pluto knows where it is and can set
+ up other things (for example, if it is<VAR> left</VAR>) using
+ parameters such as<VAR> leftsubnet</VAR> and<VAR> leftnexthop</VAR>,
+ and sending its outgoing packets to<VAR> right</VAR>.</P>
+<P>If no match is found, it emits the above error message.</P>
+<H3><A name="noconn">Pluto: ... no connection is known</A></H3>
+<P>This error message occurs when a remote system attempts to negotiate
+ a connection and Pluto does not have a connection description that
+ matches what the remote system has requested. The most common cause is
+ a configuration error on one end or the other.</P>
+<P>Parameters involved in this match are<VAR> left</VAR>,<VAR> right</VAR>
+,<VAR> leftsubnet</VAR> and<VAR> rightsubnet</VAR>.</P>
+<P><STRONG>The match must be exact</STRONG>. For example, if your left
+ subnet is a.b.c.0/24 then neither a single machine in that net nor a
+ smaller subnet such as a.b.c.64/26 will be considered a match.</P>
+<P>The message can also occur when an appropriate description exists but
+ Pluto has not loaded it. Use an<VAR> auto=add</VAR> statement in the
+ connection description, or an<VAR> ipsec auto --add &lt;conn_name&gt;</VAR>
+ command, to correct this.</P>
+<P>An explanation from the Pluto developer:</P>
+<PRE>| Jul 12 15:00:22 sohar58 Pluto[574]: &quot;corp_road&quot; #2: cannot respond to IPsec
+| SA request because no connection is known for
+| 216.112.83.112/32===216.112.83.112...216.67.25.118
+
+This is the first message from the Pluto log showing a problem. It
+means that PGPnet is trying to negotiate a set of SAs with this
+topology:
+
+216.112.83.112/32===216.112.83.112...216.67.25.118
+^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
+client on our side our host PGPnet host, no client
+
+None of the conns you showed look like this.
+
+Use
+ ipsec auto --status
+to see a snapshot of what connections are in pluto, what
+negotiations are going on, and what SAs are established.
+
+The leftsubnet= (client) in your conn is 216.112.83.64/26. It must
+exactly match what pluto is looking for, and it does not.</PRE>
+<H3><A name="nosuit">Pluto: ... no suitable connection ...</A></H3>
+<P>This is similar to the<A href="#noconn"> no connection known</A>
+ error, but occurs at a different point in Pluto processing.</P>
+<P>Here is one of Claudia's messages explaining the problem:</P>
+<PRE>You write,
+
+&gt; What could be the reason of the following error?
+&gt; &quot;no suitable connection for peer '@xforce'&quot;
+
+When a connection is initiated by the peer, Pluto must choose which entry in
+the conf file best matches the incoming connection. A preliminary choice is
+made on the basis of source and destination IPs, since that information is
+available at that time.
+
+A payload containing an ID arrives later in the negotiation. Based on this
+id and the *id= parameters, Pluto refines its conn selection. ...
+
+The message &quot;no suitable connection&quot; indicates that in this refining step,
+Pluto does not find a connection that matches that ID.
+
+Please see &quot;Selecting a connection when responding&quot; in man ipsec_pluto for
+more details.</PRE>
+<P>See also<A href="#conn_name"> Connection names in Pluto error
+ messages</A>.</P>
+<H3><A name="noconn.auth">Pluto: ... no connection has been authorized</A>
+</H3>
+<P>Here is one of Claudia's messages discussing this problem:</P>
+<PRE>You write,
+
+&gt; May 22 10:46:31 debian Pluto[25834]: packet from x.y.z.p:10014:
+&gt; initial Main Mode message from x.y.z.p:10014
+ but no connection has been authorized
+
+This error occurs early in the connection negotiation process,
+at the first step of IKE negotiation (Main Mode), which is itself the
+first of two negotiation phases involved in creating an IPSec connection.
+
+Here, Linux FreeS/WAN receives a packet from a potential peer, which
+requests that they begin discussing a connection.
+
+The &quot;no connection has been authorized&quot; means that there is no connection
+description in Linux FreeS/WAN's internal database that can be used to
+link your ipsec interface with that peer.
+
+&quot;But of course I configured that connection!&quot;
+
+It may be that the appropriate connection description exists in ipsec.conf
+but has not been added to the database with ipsec auto --add myconn or the
+auto=add method. Or, the connection description may be misconfigured.
+
+The only parameters that are relevant in this decision are left= and right= .
+Local and remote ports are also taken into account -- we see that the port
+is printed in the message above -- but there is no way to control these
+in ipsec.conf.
+
+
+Failure at &quot;no connection has been authorized&quot; is similar to the
+&quot;no connection is known for...&quot; error in the FAQ, and the &quot;no suitable
+connection&quot; error described in the snapshot's FAQ. In all three cases,
+Linux FreeS/WAN is trying to match parameters received in the
+negotiation with the connection description in the local config file.
+
+As it receives more information, its matches take more parameters into
+account, and become more precise: first the pair of potential peers,
+then the peer IDs, then the endpoints (including any subnets).
+
+The &quot;no suitable connection for peer *&quot; occurs toward the end of IKE
+(Main Mode) negotiation, when the IDs are matched.
+
+&quot;no connection is known for a/b===c...d&quot; is seen at the beginning of IPSec
+(Quick Mode, phase 2) negotiation, when the connections are matched using
+left, right, and any information about the subnets.</PRE>
+<H3><A name="noDESsupport">Pluto: ... OAKLEY_DES_CBC is not supported.</A>
+</H3>
+<P>This message occurs when the other system attempts to negotiate a
+ connection using<A href="glossary.html#DES"> single DES</A>, which we
+ do not support because it is<A href="politics.html#desnotsecure">
+ insecure</A>.</P>
+<P>Our interoperation document has suggestions for<A href="interop.html#noDES">
+ how to deal with</A> systems that attempt to use single DES.</P>
+<H3><A name="notransform">Pluto: ... no acceptable transform</A></H3>
+<P>This message means that the other gateway has made a proposal for
+ connection parameters, but nothing they proposed is acceptable to
+ Pluto. Possible causes include:</P>
+<UL>
+<LI>misconfiguration on either end</LI>
+<LI>policy incompatibilities, for example we require encrypted
+ connections but they are trying to create one with just authentication</LI>
+<LI>interoperation problems, for example they offer only single DES and
+ FreeS/WAN does not support that. See<A href="interop.html#interop.problem">
+ discussion</A> in our interoperation document.</LI>
+</UL>
+<P>A more detailed explanation, from Pluto programmer Hugh Redelmeier:</P>
+<PRE>Background:
+
+When one IKE system (for example, Pluto) is negotiating with another
+to create an SA, the Initiator proposes a bunch of choices and the
+Responder replies with one that it has selected.
+
+The structure of the choices is fairly complicated. An SA payload
+contains a list of lists of &quot;Proposals&quot;. The outer list is a set of
+choices: the selection must be from one element of this list.
+
+Each of these elements is a list of Proposals. A selection must be
+made from each of the elements of the inner list. In other words,
+*all* of them apply (that is how, for example, both AH and ESP can
+apply at once).
+
+Within each of these Proposals is a list of Transforms. For each
+Proposal selected, one Transform must be selected (in other words,
+each Proposal provides a choice of Transforms).
+
+Each Transform is made up of a list of Attributes describing, well,
+attributes. Such as lifetime of the SA. Such as algorithm to be
+used. All the Attributes apply to a Transform.
+
+You will have noticed a pattern here: layers alternate between being
+disjunctions (&quot;or&quot;) and conjunctions (&quot;and&quot;).
+
+For Phase 1 / Main Mode (negotiating an ISAKMP SA), this structure is
+cut back. There must be exactly one Proposal. So this degenerates to
+a list of Transforms, one of which must be chosen.
+
+In your case, no proposal was considered acceptable to Pluto (the
+Responder). So negotiation ceased. Pluto logs the reason it rejects
+each Transform. So look back in the log to see what is going wrong.</PRE>
+<H3><A name="rsasigkey">rsasigkey dumps core</A></H3>
+ A comment on this error from Henry:
+<PRE>On Fri, 29 Jun 2001, Rodrigo Gruppelli wrote:
+&gt; ...Well, it seem that there's
+&gt; another problem with it. When I try to generate a pair of RSA keys,
+&gt; rsasigkey cores dump...
+
+*That* is a neon sign flashing &quot;GMP LIBRARY IS BROKEN&quot;. Rsasigkey calls
+GMP a lot, and our own library a little bit, and that's very nearly all it
+does. Barring bugs in its code or our library -- which have happened, but
+not very often -- a problem in rsasigkey is a problem in GMP.</PRE>
+<P>See the next question for how to deal with GMP errors.</P>
+<H3><A name="sig4">!Pluto failure!: ... exited with ... signal 4</A></H3>
+<P>Pluto has died. Signal 4 is SIGILL, illegal instruction.</P>
+<P>The most likely cause is that your<A href="glossary.html#GMP"> GMP</A>
+ (GNU multi-precision) library is compiled for a different processor
+ than what you are running on. Pluto uses that library for its public
+ key calculations.</P>
+<P>Try getting the GMP sources and recompile for your processor type.
+ Most Linux distributions will include this source, or you can download
+ it from the<A href="http://www.swox.com/gmp/"> GMP home page</A>.</P>
+<H3><A name="econnrefused">ECONNREFUSED error message</A></H3>
+<P>From John Denker, on the mailing list:</P>
+<PRE>1) The log message
+ some IKE message we sent has been rejected with
+ ECONNREFUSED (kernel supplied no details)
+is much more suitable than the previous version. Thanks.
+
+2) Minor suggestion for further improvement: it might be worth mentioning
+that the command
+ tcpdump -i eth1 icmp[0] != 8 and icmp[0] != 0
+is useful for tracking down the details in question. We shouldn't expect
+all IPsec users to figure that out on their own. The log message might
+even provide a hint as to where to look in the docs.</PRE>
+<P>Reply From Pluto developer Hugh Redelmeier</P>
+<PRE>Good idea.
+
+I've added a bit pluto(8)'s BUGS section along these lines.
+I didn't have the heart to lengthen this message.</PRE>
+<H3><A name="no_eroute">klips_debug: ... no eroute!</A></H3>
+<P>This message means<A href="glossary.html#KLIPS"> KLIPS</A> has
+ received a packet for which no IPsec tunnel has been defined.</P>
+<P>Here is a more detailed duscussion from the team's tech support
+ person Claudia Schmeing, responding to a query on the mailing list:</P>
+<PRE>&gt; Why ipsec reports no eroute! ???? IP Masq... is disabled.
+
+In general, more information is required so that people on the list may
+give you informed input. See doc/prob.report.</PRE>
+<P>The document she refers to has since been replaced by a<A href="trouble.html#prob.report">
+ section</A> of the troubleshooting document.</P>
+<PRE>However, I can make some general comments on this type of error.
+
+This error usually looks something like this (clipped from an archived
+message):
+
+&gt; ttl:64 proto:1 chk:45459 saddr:192.168.1.2 daddr:192.168.100.1
+&gt; ... klips_debug:ipsec_findroute: 192.168.1.2-&gt;192.168.100.1
+&gt; ... klips_debug:rj_match: * See if we match exactly as a host destination
+&gt; ... klips_debug:rj_match: ** try to match a leaf, t=0xc1a260b0
+&gt; ... klips_debug:rj_match: *** start searching up the tree, t=0xc1a260b0
+&gt; ... klips_debug:rj_match: **** t=0xc1a260c8
+&gt; ... klips_debug:rj_match: **** t=0xc1fe5960
+&gt; ... klips_debug:rj_match: ***** not found.
+&gt; ... klips_debug:ipsec_tunnel_start_xmit: Original head/tailroom: 2, 28
+&gt; ... klips_debug:ipsec_tunnel_start_xmit: no eroute!: ts=47.3030, dropping.
+
+
+What does this mean?
+- --------------------
+
+&quot;eroute&quot; stands for &quot;extended route&quot;, and is a special type of route
+internal to Linux FreeS/WAN. For more information about this type of route,
+see the section of man ipsec_auto on ipsec auto --route.
+
+&quot;no eroute!&quot; here means, roughly, that Linux FreeS/WAN cannot find an
+appropriate tunnel that should have delivered this packet. Linux
+FreeS/WAN therefore drops the packet, with the message &quot;no eroute! ...
+dropping&quot;, on the assumption that this packet is not a legitimate
+transmission through a properly constructed tunnel.
+
+
+How does this situation come about?
+- -----------------------------------
+
+Linux FreeS/WAN has a number of connection descriptions defined in
+ipsec.conf. These must be successfully brought &quot;up&quot; to form actual tunnels.
+(see doc/setup.html's step 15, man ipsec.conf and man ipsec_auto
+for details).
+
+Such connections are often specific to the endpoints' IPs. However, in
+some cases they may be more general, for example in the case of
+Road Warriors where left or right is the special value %any.
+
+When Linux FreeS/WAN receives a packet, it verifies that the packet has
+come through a legitimate channel, by checking that there is an
+appropriate tunnel through which this packet might legitimately have
+arrived. This is the process we see above.
+
+First, it checks for an eroute that exactly matches the packet. In the
+example above, we see it checking for a route that begins at 192.168.1.2
+and ends at 192.168.100.1. This search favours the most specific match that
+would apply to the route between these IPs. So, if there is a connection
+description exactly matching these IPs, the search will end there. If not,
+the code will search for a more general description matching the IPs.
+If there is no match, either specific or general, the packet will be
+dropped, as we see, above.
+
+Unless you are working with Road Warriors, only the first, specific part
+of the matching process is likely to be relevant to you.
+
+
+&quot;But I defined the tunnel, and it came up, why do I have this error?&quot;
+- ---------------------------------------------------------------------
+
+One of the most common causes of this error is failure to specify enough
+connection descriptions to cover all needed tunnels between any two
+gateways and their respective subnets. As you have noticed, troubleshooting
+this error may be complicated by the use of IP Masq. However, this error is
+not limited to cases where IP Masq is used.
+
+See doc/configuration.html#multitunnel for a detailed example of the
+solution to this type of problem.</PRE>
+<P>The documentation section she refers to is now<A href="adv_config.html#multitunnel">
+ here</A>.</P>
+<H3><A name="SAused">... trouble writing to /dev/ipsec ... SA already in
+ use</A></H3>
+<P>This error message occurs when two manual connections are set up with
+ the same SPI value.</P>
+<P>See the FAQ for<A href="#spi_error"> One manual connection works, but
+ second one fails</A>.</P>
+<H3><A name="ignore">... ignoring ... payload</A></H3>
+<P>This message is harmless. The IKE protocol provides for a number of
+ optional messages types:</P>
+<UL>
+<LI>delete SA</LI>
+<LI>initial contact</LI>
+<LI>vendor ID</LI>
+<LI>...</LI>
+</UL>
+<P>An implementation is never required to send these, but they are
+ allowed to. The receiver is not required to do anything with them.
+ FreeS/WAN ignores them, but notifies you via the logs.</P>
+<P>For the &quot;ignoring delete SA Payload&quot; message, see also our discussion
+ of cleaning up<A href="#deadtunnel"> dead tunnels</A>.</P>
+<H3><A name="unknown_rightcert">unknown parameter name &quot;rightcert&quot;</A></H3>
+<P>This message can appear when you've upgraded an X.509-enabled Linux
+ FreeS/WAN with a vanilla Linux FreeS/WAN. To use your X.509 configs you
+ will need to overwrite the new install with<A HREF="http://www.freeswan.ca">
+ Super FreeS/WAN</A>, or add the<A HREF="http://www.strongsec.ca/freeswan">
+ X.509 patch</A> by hand.</P>
+<H2><A name="spam">Why don't you restrict the mailing lists to reduce
+ spam?</A></H2>
+<P>As a matter of policy, some of our<A href="mail.html"> mailing lists</A>
+ need to be open to non-subscribers. Project management feel strongly
+ that maintaining this openness is more important than blocking spam.</P>
+<UL>
+<LI>Users should be able to get help or report bugs without subscribing.</LI>
+<LI>Even a user who is subscribed may not have access to his or her
+ subscribed account when he or she needs help, miles from home base in
+ the middle of setting up a client's gateway.</LI>
+<LI>There is arguably a legal requirement for this policy. A US resident
+ or citizen could be charged under munitions export laws for providing
+ technical assistance to a foreign cryptographic project. Such a charge
+ would be more easily defended if the discussion takes place in public,
+ on an open list.</LI>
+</UL>
+<P>This has been discussed several times at some length on the list. See
+ the<A href="mail.html#archive"> list archives</A>. Bringing the topic
+ up again is unlikely to be useful. Please don't. Or at the very least,
+ please don't without reading the archives and being certain that
+ whatever you are about to suggest has not yet been discussed.</P>
+<P>Project technical lead Henry Spencer summarised one discussion:</P>
+<BLOCKQUOTE> For the third and last time: this list *will* *not* do
+ address-based filtering. This is a policy decision, not an
+ implementation problem. The decision is final, and is not open to
+ discussion. This needs to be communicated better to people, and steps
+ are being taken to do that.</BLOCKQUOTE>
+<P>Adding this FAQ section is one of the steps he refers to.</P>
+<P>You have various options other than just putting up with the spam,
+ filtering it yourself, or unsubscribing:</P>
+<UL>
+<LI>subscribe only to one or both of our lists with restricted posting
+ rules:
+<UL>
+<LI><A href="mailto:briefs@lists.freeswan.org?body=subscribe">briefs</A>
+, weekly list summaries</LI>
+<LI><A href="mailto:announce@lists.freeswan.org?body=subscribe">announce</A>
+, project-related announcements</LI>
+</UL>
+</LI>
+<LI>read the other lists via the<A href="mail.html#archive"> archives</A>
+</LI>
+</UL>
+<P>A number of tools are available to filter mail.</P>
+<UL>
+<LI>Many mail readers include some filtering capability.</LI>
+<LI>Many Linux distributions include<A href="http://www.procmail.org/">
+ procmail(8)</A> for server-side filtering.</LI>
+<LI>The<A href="http://www.spambouncer.org/"> Spam Bouncer</A> is a set
+ of procmail(8) filters designed to combat spam.</LI>
+<LI>Roaring Penguin have a<A href="http://www.roaringpenguin.com/mimedefang/">
+ MIME defanger</A> that removes potentially dangerous attachments.</LI>
+</UL>
+<P>If you use your ISP's mail server rather than running your own,
+ consider suggesting to the ISP that they tag suspected spam as<A href="http://www.msen.com/1997/spam.html#SUSPECTED">
+ this ISP</A> does. They could just refuse mail from dubious sources,
+ but that is tricky and runs some risk of losing valuable mail or
+ senselessly annoying senders and their admins. However, they can safely
+ tag and deliver dubious mail. The tags can greatly assist your
+ filtering.</P>
+<P>For information on tracking down spammers, see these<A href="http://www.rahul.net/falk/#howtos">
+ HowTos</A>, or the<A href="http://www.sputum.com/index2.html"> Sputum</A>
+ site. Sputum have a Linux anti-spam screensaver available for download.</P>
+<P>Here is a more detailed message from Henry:</P>
+<PRE>On Mon, 15 Jan 2001, Jay Vaughan wrote:
+&gt; I know I'm flogging a dead horse here, but I'm curious as to the reasons for
+&gt; an aversion for a subscriber-only mailing list?
+
+Once again: for legal reasons, it is important that discussions of these
+things be held in a public place -- the list -- and we do not want to
+force people to subscribe to the list just to ask one question, because
+that may be more than merely inconvenient for them. There are also real
+difficulties with people who are temporarily forced to use alternate
+addresses; that is precisely the time when they may be most in need of
+help, yet a subscribers-only policy shuts them out.
+
+These issues do not apply to most mailing lists, but for a list that is
+(necessarily) the primary user support route for a crypto package, they
+are very important. This is *not* an ordinary mailing list; it has to
+function under awkward constraints that make various simplistic solutions
+inapplicable or undesirable.
+
+&gt; We're *ALL* sick of hearing about list management problems, not just you
+&gt; old-timers, so why don't you DO SOMETHING EFFECTIVE ABOUT IT...
+
+Because it's a lot harder than it looks, and many existing &quot;solutions&quot;
+have problems when examined closely.
+
+&gt; A suggestion for you, based on 10 years of experience with management of my
+&gt; own mailing lists would be to use mailman, which includes pretty much every
+&gt; feature under the sun that you guys need and want, plus some. The URL for
+&gt; mailman...
+
+I assure you, we're aware of mailman. Along with a whole bunch of others,
+including some you almost certainly have never heard of (I hadn't!).
+
+&gt; As for the argument that the list shouldn't be configured to enforce
+&gt; subscription - I contend that it *SHOULD* AT LEAST require manual address
+&gt; verification in order for posts to be redirected.
+
+You do realize, I hope, that interposing such a manual step might cause
+your government to decide that this is not truly a public forum, and thus
+you could go to jail if you don't get approval from them before mailing to
+it? If you think this sounds irrational, your government is noted for
+making irrational decisions in this area; we can't assume that they will
+suddenly start being sensible. See above about awkward constraints. You
+may be willing to take the risk, but we can't, in good conscience, insist
+that all users with problems do so.
+
+ Henry Spencer
+ henry@spsystems.net</PRE>
+<P>and a message on the topic from project leader John Gilmore:</P>
+<PRE>Subject: Re: The linux-ipsec list's topic
+ Date: Sat, 30 Dec 2000
+ From: John Gilmore &lt;gnu@toad.com&gt;
+
+I'll post this single message, once only, in this discussion, and then
+not burden the list with any further off-topic messages. I encourage
+everyone on the list to restrain themself from posting ANY off-topic
+messages to the linux-ipsec list.
+
+The topic of the linux-ipsec mailing list is the FreeS/WAN software.
+
+I frequently see &quot;discussions about spam on a list&quot; overwhelm the
+volume of &quot;actual spam&quot; on a list. BOTH kinds of messages are
+off-topic messages. Twenty anti-spam messages take just as long to
+detect and discard as twenty spam messages.
+
+The Linux-ipsec list encourages on-topic messages from people who have
+not joined the list itself. We will not censor messages to the list
+based on where they originate, or what return address they contain.
+In other words, non-subscribers ARE allowed to post, and this will not
+change. My own valid contributions have been rejected out-of-hand by
+too many other mailing lists for me to want to impose that censorship
+on anybody else's contributions. And every day I see the damage that
+anti-spam zeal is causing in many other ways; that zeal is far more
+damaging to the culture of the Internet than the nuisance of spam.
+
+In general, it is the responsibility of recipients to filter,
+prioritize, or otherwise manage the handling of email that comes to
+them. It is not the responsibility of the rest of the Internet
+community to refrain from sending messages to recipients that they
+might not want to see. If your software infrastructure for managing
+your incoming email is insufficient, then improve it. If you think
+the signal-to-noise ratio on linux-ipsec is too poor, then please
+unsubscribe. But don't further increase the noise by posting to the
+linux-ipsec list about those topics.
+
+ John Gilmore
+ founder &amp; sponsor, FreeS/WAN project</PRE>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="policygroups.html">Previous</A>
+<A HREF="manpages.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/firewall.html b/doc/firewall.html
new file mode 100644
index 000000000..0747ab83d
--- /dev/null
+++ b/doc/firewall.html
@@ -0,0 +1,767 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="manpages.html">Previous</A>
+<A HREF="trouble.html">Next</A>
+<HR>
+<H1><A name="firewall">FreeS/WAN and firewalls</A></H1>
+<P>FreeS/WAN, or other IPsec implementations, frequently run on gateway
+ machines, the same machines running firewall or packet filtering code.
+ This document discusses the relation between the two.</P>
+<P>The firewall code in 2.4 and later kernels is called Netfilter. The
+ user-space utility to manage a firewall is iptables(8). See the<A href="http://netfilter.samba.org">
+ netfilter/iptables web site</A> for details.</P>
+<H2><A name="filters">Filtering rules for IPsec packets</A></H2>
+<P>The basic constraint is that<STRONG> an IPsec gateway must have
+ packet filters that allow IPsec packets</STRONG>, at least when talking
+ to other IPsec gateways:</P>
+<UL>
+<LI>UDP port 500 for<A href="glossary.html#IKE"> IKE</A> negotiations</LI>
+<LI>protocol 50 if you use<A href="glossary.html#ESP"> ESP</A>
+ encryption and/or authentication (the typical case)</LI>
+<LI>protocol 51 if you use<A href="glossary.html#AH"> AH</A>
+ packet-level authentication</LI>
+</UL>
+<P>Your gateway and the other IPsec gateways it communicates with must
+ be able to exchange these packets for IPsec to work. Firewall rules
+ must allow UDP 500 and at least one of<A href="glossary.html#AH"> AH</A>
+ or<A href="glossary.html#ESP"> ESP</A> on the interface that
+ communicates with the other gateway.</P>
+<P>For nearly all FreeS/WAN applications, you must allow UDP port 500
+ and the ESP protocol.</P>
+<P>There are two ways to set this up:</P>
+<DL>
+<DT>easier but less flexible</DT>
+<DD>Just set up your firewall scripts at boot time to allow IPsec
+ packets to and from your gateway. Let FreeS/WAN reject any bogus
+ packets.</DD>
+<DT>more work, giving you more precise control</DT>
+<DD>Have the<A href="manpage.d/ipsec_pluto.8.html"> ipsec_pluto(8)</A>
+ daemon call scripts to adjust firewall rules dynamically as required.
+ This is done by naming the scripts in the<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> variables<VAR> prepluto=</VAR>,<VAR> postpluto=</VAR>
+,<VAR> leftupdown=</VAR> and<VAR> rightupdown=</VAR>.</DD>
+</DL>
+<P>Both methods are described in more detail below.</P>
+<H2><A name="examplefw">Firewall configuration at boot</A></H2>
+<P>It is possible to set up both firewalling and IPsec with appropriate
+ scripts at boot and then not use<VAR> leftupdown=</VAR> and<VAR>
+ rightupdown=</VAR>, or use them only for simple up and down operations.</P>
+<P>Basically, the technique is</P>
+<UL>
+<LI>allow IPsec packets (typically, IKE on UDP port 500 plus ESP,
+ protocol 50)
+<UL>
+<LI>incoming, if the destination address is your gateway (and
+ optionally, only from known senders)</LI>
+<LI>outgoing, with the from address of your gateway (and optionally,
+ only to known receivers)</LI>
+</UL>
+</LI>
+<LI>let<A href="glossary.html#Pluto"> Pluto</A> deal with IKE</LI>
+<LI>let<A href="glossary.html#KLIPS"> KLIPS</A> deal with ESP</LI>
+</UL>
+<P>Since Pluto authenticates its partners during the negotiation, and
+ KLIPS drops packets for which no tunnel has been negotiated, this may
+ be all you need.</P>
+<H3><A name="simple.rules">A simple set of rules</A></H3>
+<P>In simple cases, you need only a few rules, as in this example:</P>
+<PRE># allow IPsec
+#
+# IKE negotiations
+iptables -I INPUT -p udp --sport 500 --dport 500 -j ACCEPT
+iptables -I OUTPUT -p udp --sport 500 --dport 500 -j ACCEPT
+# ESP encryption and authentication
+iptables -I INPUT -p 50 -j ACCEPT
+iptables -I OUTPUT -p 50 -j ACCEPT
+</PRE>
+<P>This should be all you need to allow IPsec through<VAR> lokkit</VAR>,
+ which ships with Red Hat 9, on its medium security setting. Once you've
+ tweaked to your satisfaction, save your active rule set with:</P>
+<PRE>service iptables save</PRE>
+<H3><A name="complex.rules">Other rules</A></H3>
+ You can add additional rules, or modify existing ones, to work with
+ IPsec and with your network and policies. We give a some examples in
+ this section.
+<P>However, while it is certainly possible to create an elaborate set of
+ rules yourself (please let us know via the<A href="mail.html"> mailing
+ list</A> if you do), it may be both easier and more secure to use a set
+ which has already been published and tested.</P>
+<P>The published rule sets we know of are described in the<A href="#rules.pub">
+ next section</A>.</P>
+<H4>Adding additional rules</H4>
+ If necessary, you can add additional rules to:
+<DL>
+<DT>reject IPsec packets that are not to or from known gateways</DT>
+<DD>This possibility is discussed in more detail<A href="#unknowngate">
+ later</A></DD>
+<DT>allow systems behind your gateway to build IPsec tunnels that pass
+ through the gateway</DT>
+<DD>This possibility is discussed in more detail<A href="#through">
+ later</A></DD>
+<DT>filter incoming packets emerging from KLIPS.</DT>
+<DD>Firewall rules can recognise packets emerging from IPsec. They are
+ marked as arriving on an interface such as<VAR> ipsec0</VAR>, rather
+ than<VAR> eth0</VAR>,<VAR> ppp0</VAR> or whatever.</DD>
+</DL>
+<P>It is therefore reasonably straightforward to filter these packets in
+ whatever way suits your situation.</P>
+<H4>Modifying existing rules</H4>
+<P>In some cases rules that work fine before you add IPsec may require
+ modification to work with IPsec.</P>
+<P>This is especially likely for rules that deal with interfaces on the
+ Internet side of your system. IPsec adds a new interface; often the
+ rules must change to take account of that.</P>
+<P>For example, consider the rules given in<A href="http://www.netfilter.org/documentation/HOWTO//packet-filtering-HOWTO-5.html">
+ this section</A> of the Netfilter documentation:</P>
+<PRE>Most people just have a single PPP connection to the Internet, and don't
+want anyone coming back into their network, or the firewall:
+
+ ## Insert connection-tracking modules (not needed if built into kernel).
+ # insmod ip_conntrack
+ # insmod ip_conntrack_ftp
+
+ ## Create chain which blocks new connections, except if coming from inside.
+ # iptables -N block
+ # iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
+ # iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
+ # iptables -A block -j DROP
+
+ ## Jump to that chain from INPUT and FORWARD chains.
+ # iptables -A INPUT -j block
+ # iptables -A FORWARD -j block</PRE>
+<P>On an IPsec gateway, those rules may need to be modified. The above
+ allows new connections from<EM> anywhere except ppp0</EM>. That means
+ new connections from ipsec0 are allowed.</P>
+<P>Do you want to allow anyone who can establish an IPsec connection to
+ your gateway to initiate TCP connections to any service on your
+ network? Almost certainly not if you are using opportunistic
+ encryption. Quite possibly not even if you have only explicitly
+ configured connections.</P>
+<P>To disallow incoming connections from ipsec0, change the middle
+ section above to:</P>
+<PRE> ## Create chain which blocks new connections, except if coming from inside.
+ # iptables -N block
+ # iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
+ # iptables -A block -m state --state NEW -i ppp+ -j DROP
+ # iptables -A block -m state --state NEW -i ipsec+ -j DROP
+ # iptables -A block -m state --state NEW -i -j ACCEPT
+ # iptables -A block -j DROP</PRE>
+<P>The original rules accepted NEW connections from anywhere except
+ ppp0. This version drops NEW connections from any PPP interface (ppp+)
+ and from any ipsec interface (ipsec+), then accepts the survivors.</P>
+<P>Of course, these are only examples. You will need to adapt them to
+ your own situation.</P>
+<H3><A name="rules.pub">Published rule sets</A></H3>
+<P>Several sets of firewall rules that work with FreeS/WAN are
+ available.</P>
+<H4><A name="Ranch.trinity">Scripts based on Ranch's work</A></H4>
+<P>One user, Rob Hutton, posted his boot time scripts to the mailing
+ list, and we included them in previous versions of this documentation.
+ They are still available from our<A href="http://www.freeswan.org/freeswan_trees/freeswan-1.5/doc/firewall.html#examplefw">
+ web site</A>. However, they were for an earlier FreeS/WAN version so we
+ no longer recommend them. Also, they had some bugs. See this<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/04/msg00316.html">
+ message</A>.</P>
+<P>Those scripts were based on David Ranch's scripts for his &quot;Trinity
+ OS&quot; for setting up a secure Linux. Check his<A href="http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html">
+ home page</A> for the latest version and for information on his<A href="biblio.html#ranch">
+ book</A> on securing Linux. If you are going to base your firewalling
+ on Ranch's scripts, we recommend using his latest version, and sending
+ him any IPsec modifications you make for incorporation into later
+ versions.</P>
+<H4><A name="seawall">The Seattle firewall</A></H4>
+<P>We have had several mailing lists reports of good results using
+ FreeS/WAN with Seawall (the Seattle Firewall). See that project's<A href="http://seawall.sourceforge.net/">
+ home page</A> on Sourceforge.</P>
+<H4><A name="rcf">The RCF scripts</A></H4>
+<P>Another set of firewall scripts with IPsec support are the RCF or
+ rc.firewall scripts. See their<A href="http://jsmoriss.mvlan.net/linux/rcf.html">
+ home page</A>.</P>
+<H4><A name="asgard">Asgard scripts</A></H4>
+<P><A href="http://heimdall.asgardsrealm.net/linux/firewall/">Asgard's
+ Realm</A> has set of firewall scripts with FreeS/WAN support, for 2.4
+ kernels and iptables.</P>
+<H4><A name="user.scripts">User scripts from the mailing list</A></H4>
+<P>One user gave considerable detail on his scripts, including
+ supporting<A href="glossary.html#IPX"> IPX</A> through the tunnel. His
+ message was too long to conveniently be quoted here, so I've put it in
+ a<A href="user_examples.html"> separate file</A>.</P>
+<H2><A name="updown">Calling firewall scripts, named in ipsec.conf(5)</A>
+</H2>
+<P>The<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A>
+ configuration file has three pairs of parameters used to specify an
+ interface between FreeS/WAN and firewalling code.</P>
+<P>Note that using these is not required if you have a static firewall
+ setup. In that case, you just set your firewall up at boot time (in a
+ way that permits the IPsec connections you want) and do not change it
+ thereafter. Omit all the FreeS/WAN firewall parameters and FreeS/WAN
+ will not attempt to adjust firewall rules at all. See<A href="#examplefw">
+ above</A> for some information on appropriate scripts.</P>
+<P>However, if you want your firewall rules to change when IPsec
+ connections change, then you need to use these parameters.</P>
+<H3><A name="pre_post">Scripts called at IPsec start and stop</A></H3>
+<P>One pair of parmeters are set in the<VAR> config setup</VAR> section
+ of the<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> file and
+ affect all connections:</P>
+<DL>
+<DT>prepluto=</DT>
+<DD>script to be called before<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> IKE daemon is started.</DD>
+<DT>postpluto=</DT>
+<DD>script to be called after<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> IKE daemon is stopped.</DD>
+</DL>
+ These parameters allow you to change firewall parameters whenever IPsec
+ is started or stopped.
+<P>They can also be used in other ways. For example, you might have<VAR>
+ prepluto</VAR> add a module to your kernel for the secure network
+ interface or make a dialup connection, and then have<VAR> postpluto</VAR>
+ remove the module or take the connection down.</P>
+<H3><A name="up_down">Scripts called at connection up and down</A></H3>
+<P>The other parameters are set in connection descriptions. They can be
+ set in individual connection descriptions, and could even call
+ different scripts for each connection for maximum flexibility. In most
+ applications, however, it makes sense to use only one script and to
+ call it from<VAR> conn %default</VAR> section so that it applies to all
+ connections.</P>
+<P>You can:</P>
+<DL>
+<DT><STRONG>either</STRONG></DT>
+<DD>set<VAR> leftfirewall=yes</VAR> or<VAR> rightfirewall=yes</VAR> to
+ use our supplied default script</DD>
+<DT><STRONG>or</STRONG></DT>
+<DD>assign a name in a<VAR> leftupdown=</VAR> or<VAR> rightupdown=</VAR>
+ line to use your own script</DD>
+</DL>
+<P>Note that<STRONG> only one of these should be used</STRONG>. You
+ cannot sensibly use both. Since<STRONG> our default script is obsolete</STRONG>
+ (designed for firewalls using<VAR> ipfwadm(8)</VAR> on 2.0 kernels),
+ most users who need this service will<STRONG> need to write a custom
+ script</STRONG>.</P>
+<H4><A name="fw.default">The default script</A></H4>
+<P>We supply a default script named<VAR> _updown</VAR>.</P>
+<DL>
+<DT>leftfirewall=</DT>
+<DD></DD>
+<DT>rightfirewall=</DT>
+<DD>indicates that the gateway is doing firewalling and that<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> should poke holes in the firewall as required.</DD>
+</DL>
+<P>Set these to<VAR> yes</VAR> and Pluto will call our default script<VAR>
+ _updown</VAR> with appropriate arguments whenever it:</P>
+<UL>
+<LI>starts or stops IPsec services</LI>
+<LI>brings a connection up or down</LI>
+</UL>
+<P>The supplied default<VAR> _updown</VAR> script is appropriate for
+ simple cases using the<VAR> ipfwadm(8)</VAR> firewalling package.</P>
+<H4><A name="userscript">User-written scripts</A></H4>
+<P>You can also write your own script and have Pluto call it. Just put
+ the script's name in one of these<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> lines:</P>
+<DL>
+<DT>leftupdown=</DT>
+<DD></DD>
+<DT>rightupdown=</DT>
+<DD>specifies a script to call instead of our default script<VAR>
+ _updown</VAR>.</DD>
+</DL>
+<P>Your script should take the same arguments and use the same
+ environment variables as<VAR> _updown</VAR>. See the &quot;updown command&quot;
+ section of the<A href="manpage.d/ipsec_pluto.8.html"> ipsec_pluto(8)</A>
+ man page for details.</P>
+<P>Note that<STRONG> you should not modify our _updown script in place</STRONG>
+. If you did that, then upgraded FreeS/WAN, the upgrade would install a
+ new default script, overwriting your changes.</P>
+<H3><A name="ipchains.script">Scripts for ipchains or iptables</A></H3>
+<P>Our<VAR> _updown</VAR> is for firewalls using<VAR> ipfwadm(8)</VAR>,
+ the firewall code for the 2.0 series of Linux kernels. If you are using
+ the more recent packages<VAR> ipchains(8)</VAR> (for 2.2 kernels) or<VAR>
+ iptables(8)</VAR> (2.4 kernels), then you must do one of:</P>
+<UL>
+<LI>use static firewall rules which are set up at boot time as described<A
+href="#examplefw"> above</A> and do not need to be changed by Pluto</LI>
+<LI>limit yourself to ipchains(8)'s ipfwadm(8) emulation mode in order
+ to use our script</LI>
+<LI>write your own script and call it with<VAR> leftupdown</VAR> and<VAR>
+ rightupdown</VAR>.</LI>
+</UL>
+<P>You can write a script to do whatever you need with firewalling.
+ Specify its name in a<VAR> [left|right]updown=</VAR> parameter in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> and Pluto will automatically call it for you.</P>
+<P>The arguments Pluto passes such a script are the same ones it passes
+ to our default _updown script, so the best way to build yours is to
+ copy ours and modify the copy.</P>
+<P>Note, however, that<STRONG> you should not modify our _updown script
+ in place</STRONG>. If you did that, then upgraded FreeS/WAN, the
+ upgrade would install a new default script, overwriting your changes.</P>
+<H2><A name="NAT">A complication: IPsec vs. NAT</A></H2>
+<P><A href="glossary.html#NAT.gloss">Network Address Translation</A>,
+ also known as IP masquerading, is a method of allocating IP addresses
+ dynamically, typically in circumstances where the total number of
+ machines which need to access the Internet exceeds the supply of IP
+ addresses.</P>
+<P>Any attempt to perform NAT operations on IPsec packets<EM> between
+ the IPsec gateways</EM> creates a basic conflict:</P>
+<UL>
+<LI>IPsec wants to authenticate packets and ensure they are unaltered on
+ a gateway-to-gateway basis</LI>
+<LI>NAT rewrites packet headers as they go by</LI>
+<LI>IPsec authentication fails if packets are rewritten anywhere between
+ the IPsec gateways</LI>
+</UL>
+<P>For<A href="glossary.html#AH"> AH</A>, which authenticates parts of
+ the packet header including source and destination IP addresses, this
+ is fatal. If NAT changes those fields, AH authentication fails.</P>
+<P>For<A href="glossary.html#IKE"> IKE</A> and<A href="glossary.html#ESP">
+ ESP</A> it is not necessarily fatal, but is certainly an unwelcome
+ complication.</P>
+<H3><A name="nat_ok">NAT on or behind the IPsec gateway works</A></H3>
+<P>This problem can be avoided by having the masquerading take place<EM>
+ on or behind</EM> the IPsec gateway.</P>
+<P>This can be done physically with two machines, one physically behind
+ the other. A picture, using SG to indicate IPsec<STRONG> S</STRONG>
+ecurity<STRONG> G</STRONG>ateways, is:</P>
+<PRE> clients --- NAT ----- SG ---------- SG
+ two machines</PRE>
+<P>In this configuration, the actual client addresses need not be given
+ in the<VAR> leftsubnet=</VAR> parameter of the FreeS/WAN connection
+ description. The security gateway just delivers packets to the NAT box;
+ it needs only that machine's address. What that machine does with them
+ does not affect FreeS/WAN.</P>
+<P>A more common setup has one machine performing both functions:</P>
+<PRE> clients ----- NAT/SG ---------------SG
+ one machine</PRE>
+<P>Here you have a choice of techniques depending on whether you want to
+ make your client subnet visible to clients on the other end:</P>
+<UL>
+<LI>If you want the single gateway to behave like the two shown above,
+ with your clients hidden behind the NAT, then omit the<VAR> leftsubnet=</VAR>
+ parameter. It then defaults to the gateway address. Clients on the
+ other end then talk via the tunnel only to your gateway. The gateway
+ takes packets emerging from the tunnel, applies normal masquerading,
+ and forwards them to clients.</LI>
+<LI>If you want to make your client machines visible, then give the
+ client subnet addresses as the<VAR> leftsubnet=</VAR> parameter in the
+ connection description and
+<DL>
+<DT>either</DT>
+<DD>set<VAR> leftfirewall=yes</VAR> to use the default<VAR> updown</VAR>
+ script</DD>
+<DT>or</DT>
+<DD>use your own script by giving its name in a<VAR> leftupdown=</VAR>
+ parameter</DD>
+</DL>
+ These scripts are described in their own<A href="#updown"> section</A>.
+<P>In this case, no masquerading is done. Packets to or from the client
+ subnet are encrypted or decrypted without any change to their client
+ subnet addresses, although of course the encapsulating packets use
+ gateway addresses in their headers. Clients behind the right security
+ gateway see a route via that gateway to the left subnet.</P>
+</LI>
+</UL>
+<H3><A name="nat_bad">NAT between gateways is problematic</A></H3>
+<P>We recommend not trying to build IPsec connections which pass through
+ a NAT machine. This setup poses problems:</P>
+<PRE> clients --- SG --- NAT ---------- SG</PRE>
+<P>If you must try it, some references are:</P>
+<UL>
+<LI>Jean_Francois Nadeau's document on doing<A href="http://jixen.tripod.com/#NATed gateways">
+ IPsec behind NAT</A></LI>
+<LI><A href="web.html#VPN.masq">VPN masquerade patches</A> to make a
+ Linux NAT box handle IPsec packets correctly</LI>
+</UL>
+<H3><A name="NAT.ref">Other references on NAT and IPsec</A></H3>
+<P>Other documents which may be relevant include:</P>
+<UL>
+<LI>an Internet Draft on<A href="http://search.ietf.org/internet-drafts/draft-aboba-nat-ipsec-04.txt">
+ IPsec and NAT</A> which may eventually evolve into a standard solution
+ for this problem.</LI>
+<LI>an informational<A href="http://www.cis.ohio-state.edu/rfc/rfc2709.txt">
+ RFC</A>,<CITE> Security Model with Tunnel-mode IPsec for NAT Domains</CITE>
+.</LI>
+<LI>an<A href="http://www.cisco.com/warp/public/759/ipj_3-4/ipj_3-4_nat.html">
+ article</A> in Cisco's<CITE> Internet Protocol Journal</CITE></LI>
+</UL>
+<H2><A name="complications">Other complications</A></H2>
+<P>Of course simply allowing UDP 500 and ESP packets is not the whole
+ story. Various other issues arise in making IPsec and packet filters
+ co-exist and even co-operate. Some of them are summarised below.</P>
+<H3><A name="through">IPsec<EM> through</EM></A> the gateway</H3>
+<P>Basic IPsec packet filtering rules deal only with packets addressed
+ to or sent from your IPsec gateway.</P>
+<P>It is a separate policy decision whether to permit such packets to
+ pass through the gateway so that client machines can build end-to-end
+ IPsec tunnels of their own. This may not be practical if you are using<A
+href="#NAT"> NAT (IP masquerade)</A> on your gateway, and may conflict
+ with some corporate security policies.</P>
+<P>Where possible, allowing this is almost certainly a good idea. Using
+ IPsec on an end-to-end basis is more secure than gateway-to-gateway.</P>
+<P>Doing it is quite simple. You just need firewall rules that allow UDP
+ port 500 and protocols 50 and 51 to pass through your gateway. If you
+ wish, you can of course restrict this to certain hosts.</P>
+<H3><A name="ipsec_only">Preventing non-IPsec traffic</A></H3>
+ You can also filter<EM> everything but</EM> UDP port 500 and ESP or AH
+ to restrict traffic to IPsec only, either for anyone communicating with
+ your host or just for specific partners.
+<P>One application of this is for the telecommuter who might have:</P>
+<PRE> Sunset==========West------------------East ================= firewall --- the Internet
+ home network untrusted net corporate network</PRE>
+<P>The subnet on the right is 0.0.0.0/0, the whole Internet. The West
+ gateway is set up so that it allows only IPsec packets to East in or
+ out.</P>
+<P>This configuration is used in AT&amp;T Research's network. For details,
+ see the<A href="intro.html#applied"> papers</A> links in our
+ introduction.</P>
+<P>Another application would be to set up firewall rules so that an
+ internal machine, such as an employees-only web server, could not talk
+ to the outside world except via specific IPsec tunnels.</P>
+<H3><A name="unknowngate">Filtering packets from unknown gateways</A></H3>
+<P>It is possible to use firewall rules to restrict UDP 500, ESP and AH
+ packets so that these packets are accepted only from known gateways.
+ This is not strictly necessary since FreeS/WAN will discard packets
+ from unknown gateways. You might, however, want to do it for any of a
+ number of reasons. For example:</P>
+<UL>
+<LI>Arguably, &quot;belt and suspenders&quot; is the sensible approach to
+ security. If you can block a potential attack in two ways, use both.
+ The only question is whether to look for a third way after implementing
+ the first two.</LI>
+<LI>Some admins may prefer to use the firewall code this way because
+ they prefer firewall logging to FreeS/WAN's logging.</LI>
+<LI>You may need it to implement your security policy. Consider an
+ employee working at home, and a policy that says traffic from the home
+ system to the Internet at large must go first via IPsec to the
+ corporate LAN and then out to the Internet via the corporate firewall.
+ One way to do that is to make<VAR> ipsec0</VAR> the default route on
+ the home gateway and provide exceptions only for UDP 500 and ESP to the
+ corporate gateway. Everything else is then routed via the tunnel to the
+ corporate gateway.</LI>
+</UL>
+<P>It is not possible to use only static firewall rules for this
+ filtering if you do not know the other gateways' IP addresses in
+ advance, for example if you have &quot;road warriors&quot; who may connect from a
+ different address each time or if want to do<A href="glossary.html#carpediem">
+ opportunistic encryption</A> to arbitrary gateways. In these cases, you
+ can accept UDP 500 IKE packets from anywhere, then use the<A href="#updown">
+ updown</A> script feature of<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> to dynamically adjust firewalling for each negotiated
+ tunnel.</P>
+<P>Firewall packet filtering does not much reduce the risk of a<A href="glossary.html#DOS">
+ denial of service attack</A> on FreeS/WAN. The firewall can drop
+ packets from unknown gateways, but KLIPS does that quite efficiently
+ anyway, so you gain little. The firewall cannot drop otherwise
+ legitmate packets that fail KLIPS authentication, so it cannot protect
+ against an attack designed to exhaust resources by making FreeS/WAN
+ perform many expensive authentication operations.</P>
+<P>In summary, firewall filtering of IPsec packets from unknown gateways
+ is possible but not strictly necessary.</P>
+<H2><A name="otherfilter">Other packet filters</A></H2>
+<P>When the IPsec gateway is also acting as your firewall, other packet
+ filtering rules will be in play. In general, those are outside the
+ scope of this document. See our<A href="web.html#firewall.linux"> Linux
+ firewall links</A> for information. There are a few types of packet,
+ however, which can affect the operation of FreeS/WAN or of diagnostic
+ tools commonly used with it. These are discussed below.</P>
+<H3><A name="ICMP">ICMP filtering</A></H3>
+<P><A href="glossary.html#ICMP.gloss">ICMP</A> is the<STRONG> I</STRONG>
+nternet<STRONG> C</STRONG>ontrol<STRONG> M</STRONG>essage<STRONG> P</STRONG>
+rotocol. It is used for messages between IP implementations themselves,
+ whereas IP used is used between the clients of those implementations.
+ ICMP is, unsurprisingly, used for control messages. For example, it is
+ used to notify a sender that a desination is not reachable, or to tell
+ a router to reroute certain packets elsewhere.</P>
+<P>ICMP handling is tricky for firewalls.</P>
+<UL>
+<LI>You definitely want some ICMP messages to get through; things won't
+ work without them. For example, your clients need to know if some
+ destination they ask for is unreachable.</LI>
+<LI>On the other hand, you do equally definitely do not want untrusted
+ folk sending arbitrary control messages to your machines. Imagine what
+ someone moderately clever and moderately malicious could do to you,
+ given control of your network's routing.</LI>
+</UL>
+<P>ICMP does not use ports. Messages are distinguished by a &quot;message
+ type&quot; field and, for some types, by an additional &quot;code&quot; field. The
+ definitive list of types and codes is on the<A href="http://www.iana.org">
+ IANA</A> site.</P>
+<P>One expert uses this definition for ICMP message types to be dropped
+ at the firewall.</P>
+<PRE># ICMP types which lack socially redeeming value.
+# 5 Redirect
+# 9 Router Advertisement
+# 10 Router Selection
+# 15 Information Request
+# 16 Information Reply
+# 17 Address Mask Request
+# 18 Address Mask Reply
+
+badicmp='5 9 10 15 16 17 18'</PRE>
+<P>A more conservative approach would be to make a list of allowed types
+ and drop everything else.</P>
+<P>Whichever way you do it, your ICMP filtering rules on a FreeS/WAN
+ gateway should allow at least the following ICMP packet types:</P>
+<DL>
+<DT>echo (type 8)</DT>
+<DD></DD>
+<DT>echo reply (type 0)</DT>
+<DD>These are used by ping(1). We recommend allowing both types through
+ the tunnel and to or from your gateway's external interface, since
+ ping(1) is an essential testing tool.
+<P>It is fairly common for firewalls to drop ICMP echo packets addressed
+ to machines behind the firewall. If that is your policy, please create
+ an exception for such packets arriving via an IPsec tunnel, at least
+ during intial testing of those tunnels.</P>
+</DD>
+<DT>destination unreachable (type 3)</DT>
+<DD>This is used, with code 4 (Fragmentation Needed and Don't Fragment
+ was Set) in the code field, to control<A href="glossary.html#pathMTU">
+ path MTU discovery</A>. Since IPsec processing adds headers, enlarges
+ packets and may cause fragmentation, an IPsec gateway should be able to
+ send and receive these ICMP messages<STRONG> on both inside and outside
+ interfaces</STRONG>.</DD>
+</DL>
+<H3><A name="traceroute">UDP packets for traceroute</A></H3>
+<P>The traceroute(1) utility uses UDP port numbers from 33434 to
+ approximately 33633. Generally, these should be allowed through for
+ troubleshooting.</P>
+<P>Some firewalls drop these packets to prevent outsiders exploring the
+ protected network with traceroute(1). If that is your policy, consider
+ creating an exception for such packets arriving via an IPsec tunnel, at
+ least during intial testing of those tunnels.</P>
+<H3><A name="l2tp">UDP for L2TP</A></H3>
+<P> Windows 2000 does, and products designed for compatibility with it
+ may, build<A href="glossary.html#L2TP"> L2TP</A> tunnels over IPsec
+ connections.</P>
+<P>For this to work, you must allow UDP protocol 1701 packets coming out
+ of your tunnels to continue to their destination. You can, and probably
+ should, block such packets to or from your external interfaces, but
+ allow them from<VAR> ipsec0</VAR>.</P>
+<P>See also our Windows 2000<A href="interop.html#win2k"> interoperation
+ discussion</A>.</P>
+<H2><A name="packets">How it all works: IPsec packet details</A></H2>
+<P>IPsec uses three main types of packet:</P>
+<DL>
+<DT><A href="glossary.html#IKE">IKE</A> uses<STRONG> the UDP protocol
+ and port 500</STRONG>.</DT>
+<DD>Unless you are using only (less secure, not recommended) manual
+ keying, you need IKE to negotiate connection parameters, acceptable
+ algorithms, key sizes and key setup. IKE handles everything required to
+ set up, rekey, repair or tear down IPsec connections.</DD>
+<DT><A href="glossary.html#ESP">ESP</A> is<STRONG> protocol number 50</STRONG>
+</DT>
+<DD>This is required for encrypted connections.</DD>
+<DT><A href="glossary.html#AH">AH</A> is<STRONG> protocol number 51</STRONG>
+</DT>
+<DD>This can be used where only authentication, not encryption, is
+ required.</DD>
+</DL>
+<P>All of those packets should have appropriate IPsec gateway addresses
+ in both the to and from IP header fields. Firewall rules can check this
+ if you wish, though it is not strictly necessary. This is discussed in
+ more detail<A href="#unknowngate"> later</A>.</P>
+<P>IPsec processing of incoming packets authenticates them then removes
+ the ESP or AH header and decrypts if necessary. Successful processing
+ exposes an inner packet which is then delivered back to the firewall
+ machinery, marked as having arrived on an<VAR> ipsec[0-3]</VAR>
+ interface. Firewall rules can use that interface label to distinguish
+ these packets from unencrypted packets which are labelled with the
+ physical interface they arrived on (or perhaps with a non-IPsec virtual
+ interface such as<VAR> ppp0</VAR>).</P>
+<P>One of our users sent a mailing list message with a<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00006.html">
+ diagram</A> of the packet flow.</P>
+<H3><A name="noport">ESP and AH do not have ports</A></H3>
+<P>Some protocols, such as TCP and UDP, have the notion of ports. Others
+ protocols, including ESP and AH, do not. Quite a few IPsec newcomers
+ have become confused on this point. There are no ports<EM> in</EM> the
+ ESP or AH protocols, and no ports used<EM> for</EM> them. For these
+ protocols,<EM> the idea of ports is completely irrelevant</EM>.</P>
+<H3><A name="header">Header layout</A></H3>
+<P>The protocol numbers for ESP or AH are used in the 'next header'
+ field of the IP header. On most non-IPsec packets, that field would
+ have one of:</P>
+<UL>
+<LI>1 for ICMP</LI>
+<LI>4 for IP-in-IP encapsulation</LI>
+<LI>6 for TCP</LI>
+<LI>17 for UDP</LI>
+<LI>... or one of about 100 other possibilities listed by<A href="http://www.iana.org">
+ IANA</A></LI>
+</UL>
+<P>Each header in the sequence tells what the next header will be. IPsec
+ adds headers for ESP or AH near the beginning of the sequence. The
+ original headers are kept and the 'next header' fields adjusted so that
+ all headers can be correctly interpreted.</P>
+<P>For example, using<STRONG> [</STRONG><STRONG> ]</STRONG> to indicate
+ data protected by ESP and unintelligible to an eavesdropper between the
+ gateways:</P>
+<UL>
+<LI>a simple packet might have only IP and TCP headers with:
+<UL>
+<LI>IP header says next header --&gt; TCP</LI>
+<LI>TCP header port number --&gt; which process to send data to</LI>
+<LI>data</LI>
+</UL>
+</LI>
+<LI>with ESP<A href="glossary.html#transport"> transport mode</A>
+ encapsulation, that packet would have:
+<UL>
+<LI>IP header says next header --&gt; ESP</LI>
+<LI>ESP header<STRONG> [</STRONG> says next --&gt; TCP</LI>
+<LI>TCP header port number --&gt; which process to send data to</LI>
+<LI>data<STRONG> ]</STRONG></LI>
+</UL>
+ Note that the IP header is outside ESP protection, visible to an
+ attacker, and that the final destination must be the gateway.</LI>
+<LI>with ESP in<A href="glossary.html#tunnel"> tunnel mode</A>, we might
+ have:
+<UL>
+<LI>IP header says next header --&gt; ESP</LI>
+<LI>ESP header<STRONG> [</STRONG> says next --&gt; IP</LI>
+<LI>IP header says next header --&gt; TCP</LI>
+<LI>TCP header port number --&gt; which process to send data to</LI>
+<LI>data<STRONG> ]</STRONG></LI>
+</UL>
+ Here the inner IP header is protected by ESP, unreadable by an
+ attacker. Also, the inner header can have a different IP address than
+ the outer IP header, so the decrypted packet can be routed from the
+ IPsec gateway to a final destination which may be another machine.</LI>
+</UL>
+<P>Part of the ESP header itself is encrypted, which is why the<STRONG>
+ [</STRONG> indicating protected data appears in the middle of some
+ lines above. The next header field of the ESP header is protected. This
+ makes<A href="glossary.html#traffic"> traffic analysis</A> more
+ difficult. The next header field would tell an eavesdropper whether
+ your packet was UDP to the gateway, TCP to the gateway, or encapsulated
+ IP. It is better not to give this information away. A clever attacker
+ may deduce some of it from the pattern of packet sizes and timings, but
+ we need not make it easy.</P>
+<P>IPsec allows various combinations of these to match local policies,
+ including combinations that use both AH and ESP headers or that nest
+ multiple copies of these headers.</P>
+<P>For example, suppose my employer has an IPsec VPN running between two
+ offices so all packets travelling between the gateways for those
+ offices are encrypted. If gateway policies allow it (The admins could
+ block UDP 500 and protocols 50 and 51 to disallow it), I can build an
+ IPsec tunnel from my desktop to a machine in some remote office. Those
+ packets will have one ESP header throughout their life, for my
+ end-to-end tunnel. For part of the route, however, they will also have
+ another ESP layer for the corporate VPN's encapsulation. The whole
+ header scheme for a packet on the Internet might be:</P>
+<UL>
+<LI>IP header (with gateway address) says next header --&gt; ESP</LI>
+<LI>ESP header<STRONG> [</STRONG> says next --&gt; IP</LI>
+<LI>IP header (with receiving machine address) says next header --&gt; ESP</LI>
+<LI>ESP header<STRONG> [</STRONG> says next --&gt; TCP</LI>
+<LI>TCP header port number --&gt; which process to send data to</LI>
+<LI>data<STRONG> ]]</STRONG></LI>
+</UL>
+<P>The first ESP (outermost) header is for the corporate VPN. The inner
+ ESP header is for the secure machine-to-machine link.</P>
+<H3><A name="dhr">DHR on the updown script</A></H3>
+<P>Here are some mailing list comments from<A href="manpage.d/ipsec_pluto.8.html">
+ pluto(8)</A> developer Hugh Redelmeier on an earlier draft of this
+ document:</P>
+<PRE>There are many important things left out
+
+- firewalling is important but must reflect (implement) policy. Since
+ policy isn't the same for all our customers, and we're not experts,
+ we should concentrate on FW and MASQ interactions with FreeS/WAN.
+
+- we need a diagram to show packet flow WITHIN ONE MACHINE, assuming
+ IKE, IPsec, FW, and MASQ are all done on that machine. The flow is
+ obvious if the components are run on different machines (trace the
+ cables).
+
+ IKE input:
+ + packet appears on public IF, as UDP port 500
+ + input firewalling rules are applied (may discard)
+ + Pluto sees the packet.
+
+ IKE output:
+ + Pluto generates the packet &amp; writes to public IF, UDP port 500
+ + output firewalling rules are applied (may discard)
+ + packet sent out public IF
+
+ IPsec input, with encapsulated packet, outer destination of this host:
+ + packet appears on public IF, protocol 50 or 51. If this
+ packet is the result of decapsulation, it will appear
+ instead on the paired ipsec IF.
+ + input firewalling rules are applied (but packet is opaque)
+ + KLIPS decapsulates it, writes result to paired ipsec IF
+ + input firewalling rules are applied to resulting packet
+ as input on ipsec IF
+ + if the destination of the packet is this machine, the
+ packet is passed on to the appropriate protocol handler.
+ If the original packet was encapsulated more than once
+ and the new outer destination is this machine, that
+ handler will be KLIPS.
+ + otherwise:
+ * routing is done for the resulting packet. This may well
+ direct it into KLIPS for encoding or encrypting. What
+ happens then is described elsewhere.
+ * forwarding firewalling rules are applied
+ * output firewalling rules are applied
+ * the packet is sent where routing specified
+
+ IPsec input, with encapsulated packet, outer destination of another host:
+ + packet appears on some IF, protocol 50 or 51
+ + input firewalling rules are applied (but packet is opaque)
+ + routing selects where to send the packet
+ + forwarding firewalling rules are applied (but packet is opaque)
+ + packet forwarded, still encapsulated
+
+ IPsec output, from this host or from a client:
+ + if from a client, input firewalling rules are applied as the
+ packet arrives on the private IF
+ + routing directs the packet to an ipsec IF (this is how the
+ system decides KLIPS processing is required)
+ + if from a client, forwarding firewalling rules are applied
+ + KLIPS eroute mechanism matches the source and destination
+ to registered eroutes, yielding a SPI group. This dictates
+ processing, and where the resulting packet is to be sent
+ (the destinations SG and the nexthop).
+ + output firewalling is not applied to the resulting
+ encapsulated packet
+
+- Until quite recently, KLIPS would double encapsulate packets that
+ didn't strictly need to be. Firewalling should be prepared for
+ those packets showing up as ESP and AH protocol input packets on
+ an ipsec IF.
+
+- MASQ processing seems to be done as if it were part of the
+ forwarding firewall processing (this should be verified).
+
+- If a firewall is being used, it is likely the case that it needs to
+ be adjusted whenever IPsec SAs are added or removed. Pluto invokes
+ a script to do this (and to adjust routing) at suitable times. The
+ default script is only suitable for ipfwadm-managed firewalls. Under
+ LINUX 2.2.x kernels, ipchains can be managed by ipfwadm (emulation),
+ but ipchains more powerful if manipulated using the ipchains command.
+ In this case, a custom updown script must be used.
+
+ We think that the flexibility of ipchains precludes us supplying an
+ updown script that would be widely appropriate.</PRE>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="manpages.html">Previous</A>
+<A HREF="trouble.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/glossary.html b/doc/glossary.html
new file mode 100644
index 000000000..3ca33810f
--- /dev/null
+++ b/doc/glossary.html
@@ -0,0 +1,2132 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="web.html">Previous</A>
+<A HREF="biblio.html">Next</A>
+<HR>
+<H1><A name="ourgloss">Glossary for the Linux FreeS/WAN project</A></H1>
+<P>Entries are in alphabetical order. Some entries are only one line or
+ one paragraph long. Others run to several paragraphs. I have tried to
+ put the essential information in the first paragraph so you can skip
+ the other paragraphs if that seems appropriate.</P>
+<HR>
+<H2><A name="jump">Jump to a letter in the glossary</A></H2>
+<CENTER> <BIG><B><A href="#0">numeric</A><A href="#A"> A</A><A href="#B">
+ B</A><A href="#C"> C</A><A href="#D"> D</A><A href="#E"> E</A><A href="#F">
+ F</A><A href="#G"> G</A><A href="#H"> H</A><A href="#I"> I</A><A href="#J">
+ J</A><A href="#K"> K</A><A href="#L"> L</A><A href="#M"> M</A><A href="#N">
+ N</A><A href="#O"> O</A><A href="#P"> P</A><A href="#Q"> Q</A><A href="#R">
+ R</A><A href="#S"> S</A><A href="#T"> T</A><A href="#U"> U</A><A href="#V">
+ V</A><A href="#W"> W</A><A href="#X"> X</A><A href="#Y"> Y</A><A href="#Z">
+ Z</A></B></BIG></CENTER>
+<HR>
+<H2><A name="gloss">Other glossaries</A></H2>
+<P>Other glossaries which overlap this one include:</P>
+<UL>
+<LI>The VPN Consortium's glossary of<A href="http://www.vpnc.org/terms.html">
+ VPN terms</A>.</LI>
+<LI>glossary portion of the<A href="http://www.rsa.com/rsalabs/faq/B.html">
+ Cryptography FAQ</A></LI>
+<LI>an extensive crytographic glossary on<A href="http://www.ciphersbyritter.com/GLOSSARY.HTM">
+ Terry Ritter's</A> page.</LI>
+<LI>The<A href="#NSA"> NSA</A>'s<A href="http://www.sans.org/newlook/resources/glossary.htm">
+ glossary of computer security</A> on the<A href="http://www.sans.org">
+ SANS Institute</A> site.</LI>
+<LI>a small glossary for Internet Security at<A href="http://www5.zdnet.com/pcmag/pctech/content/special/glossaries/internetsecurity.html">
+ PC magazine</A></LI>
+<LI>The<A href="http://www.visi.com/crypto/inet-crypto/glossary.html">
+ glossary</A> from Richard Smith's book<A href="biblio.html#Smith">
+ Internet Cryptography</A></LI>
+</UL>
+<P>Several Internet glossaries are available as RFCs:</P>
+<UL>
+<LI><A href="http://www.rfc-editor.org/rfc/rfc1208.txt">Glossary of
+ Networking Terms</A></LI>
+<LI><A href="http://www.rfc-editor.org/rfc/rfc1983.txt">Internet User's
+ Glossary</A></LI>
+<LI><A href="http://www.rfc-editor.org/rfc/rfc2828.txt">Internet
+ Security Glossary</A></LI>
+</UL>
+<P>More general glossary or dictionary information:</P>
+<UL>
+<LI>Free Online Dictionary of Computing (FOLDOC)
+<UL>
+<LI><A href="http://www.nightflight.com/foldoc">North America</A></LI>
+<LI><A href="http://wombat.doc.ic.ac.uk/foldoc/index.html">Europe</A></LI>
+<LI><A href="http://www.nue.org/foldoc/index.html">Japan</A></LI>
+</UL>
+<P>There are many more mirrors of this dictionary.</P>
+</LI>
+<LI>The Jargon File, the definitive resource for hacker slang and
+ folklore
+<UL>
+<LI><A href="http://www.netmeg.net/jargon">North America</A></LI>
+<LI><A href="http://info.wins.uva.nl/~mes/jargon/">Holland</A></LI>
+<LI><A href="http://www.tuxedo.org/~esr/jargon">home page</A></LI>
+</UL>
+<P>There are also many mirrors of this. See the home page for a list.</P>
+</LI>
+<LI>A general<A href="http://www.trinity.edu/~rjensen/245glosf.htm#Navigate">
+ technology glossary</A></LI>
+<LI>An<A href="http://www.yourdictionary.com/"> online dictionary
+ resource page</A> with pointers to many dictionaries for many languages</LI>
+<LI>A<A href="http://www.onelook.com/"> search engine</A> that accesses
+ several hundred online dictionaries</LI>
+<LI>O'Reilly<A href="http://www.ora.com/reference/dictionary/">
+ Dictionary of PC Hardware and Data Communications Terms</A></LI>
+<LI><A href="http://www.FreeSoft.org/CIE/index.htm">Connected</A>
+ Internet encyclopedia</LI>
+<LI><A href="http://www.whatis.com/">whatis.com</A></LI>
+</UL>
+<HR>
+<H2><A name="definitions">Definitions</A></H2>
+<DL>
+<DT><A name="0">0</A></DT>
+<DT><A name="3DES">3DES (Triple DES)</A></DT>
+<DD>Using three<A href="#DES"> DES</A> encryptions on a single data
+ block, with at least two different keys, to get higher security than is
+ available from a single DES pass. The three-key version of 3DES is the
+ default encryption algorithm for<A href="web.html#FreeSWAN"> Linux
+ FreeS/WAN</A>.
+<P><A href="#IPSEC">IPsec</A> always does 3DES with three different
+ keys, as required by RFC 2451. For an explanation of the two-key
+ variant, see<A href="#2key"> two key triple DES</A>. Both use an<A href="#EDE">
+ EDE</A> encrypt-decrypt-encrpyt sequence of operations.</P>
+<P>Single<A href="#DES"> DES</A> is<A href="politics.html#desnotsecure">
+ insecure</A>.</P>
+<P>Double DES is ineffective. Using two 56-bit keys, one might expect an
+ attacker to have to do 2<SUP>112</SUP> work to break it. In fact, only
+ 2<SUP>57</SUP> work is required with a<A href="#meet">
+ meet-in-the-middle attack</A>, though a large amount of memory is also
+ required. Triple DES is vulnerable to a similar attack, but that just
+ reduces the work factor from the 2<SUP>168</SUP> one might expect to 2<SUP>
+112</SUP>. That provides adequate protection against<A href="#brute">
+ brute force</A> attacks, and no better attack is known.</P>
+<P>3DES can be somewhat slow compared to other ciphers. It requires
+ three DES encryptions per block. DES was designed for hardware
+ implementation and includes some operations which are difficult in
+ software. However, the speed we get is quite acceptable for many uses.
+ See our<A href="performance.html"> performance</A> document for
+ details.</P>
+</DD>
+<DT><A name="A">A</A></DT>
+<DT><A name="active">Active attack</A></DT>
+<DD>An attack in which the attacker does not merely eavesdrop (see<A href="#passive">
+ passive attack</A>) but takes action to change, delete, reroute, add,
+ forge or divert data. Perhaps the best-known active attack is<A href="#middle">
+ man-in-the-middle</A>. In general,<A href="#authentication">
+ authentication</A> is a useful defense against active attacks.</DD>
+<DT><A name="AES">AES</A></DT>
+<DD>The<B> A</B>dvanced<B> E</B>ncryption<B> S</B>tandard -- a new<A href="#block">
+ block cipher</A> standard to replace<A href="politics.html#desnotsecure">
+ DES</A> -- developed by<A href="#NIST"> NIST</A>, the US National
+ Institute of Standards and Technology. DES used 64-bit blocks and a
+ 56-bit key. AES ciphers use a 128-bit block and 128, 192 or 256-bit
+ keys. The larger block size helps resist<A href="#birthday"> birthday
+ attacks</A> while the large key size prevents<A href="#brute"> brute
+ force attacks</A>.
+<P>Fifteen proposals meeting NIST's basic criteria were submitted in
+ 1998 and subjected to intense discussion and analysis, &quot;round one&quot;
+ evaluation. In August 1999, NIST narrowed the field to five &quot;round two&quot;
+ candidates:</P>
+<UL>
+<LI><A href="http://www.research.ibm.com/security/mars.html">Mars</A>
+ from IBM</LI>
+<LI><A href="http://www.rsa.com/rsalabs/aes/">RC6</A> from RSA</LI>
+<LI><A href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">Rijndael</A>
+ from two Belgian researchers</LI>
+<LI><A href="http://www.cl.cam.ac.uk/~rja14/serpent.html">Serpent</A>, a
+ British-Norwegian-Israeli collaboration</LI>
+<LI><A href="http://www.counterpane.com/twofish.html">Twofish</A> from
+ the consulting firm<A href="http://www.counterpane.com"> Counterpane</A>
+</LI>
+</UL>
+<P>Three of the five finalists -- Rijndael, Serpent and Twofish -- have
+ completely open licenses.</P>
+<P>In October 2000, NIST announced the winner -- Rijndael.</P>
+<P>For more information, see:</P>
+<UL>
+<LI>NIST's<A href="http://csrc.nist.gov/encryption/aes/aes_home.htm">
+ AES home page</A></LI>
+<LI>the Block Cipher Lounge<A href="http://www.ii.uib.no/~larsr/aes.html">
+ AES page</A></LI>
+<LI>Brian Gladman's<A href="http://fp.gladman.plus.com/cryptography_technology/index.htm">
+ code and benchmarks</A></LI>
+<LI>Helger Lipmaa's<A href="http://www.tcs.hut.fi/~helger/aes/"> survey
+ of implementations</A></LI>
+</UL>
+<P>AES will be added to a future release of<A href="web.html#FreeSWAN">
+ Linux FreeS/WAN</A>. Likely we will add all three of the finalists with
+ good licenses. User-written<A href="web.html#patch"> AES patches</A>
+ are already available.</P>
+<P>Adding AES may also require adding stronger hashes,<A href="#SHA-256">
+ SHA-256, SHA-384 and SHA-512</A>.</P>
+</DD>
+<DT><A name="AH">AH</A></DT>
+<DD>The<A href="#IPSEC"> IPsec</A><B> A</B>uthentication<B> H</B>eader,
+ added after the IP header. For details, see our<A href="ipsec.html#AH.ipsec">
+ IPsec</A> document and/or RFC 2402.</DD>
+<DT><A name="alicebob">Alice and Bob</A></DT>
+<DD>A and B, the standard example users in writing on cryptography and
+ coding theory. Carol and Dave join them for protocols which require
+ more players.
+<P>Bruce Schneier extends these with many others such as Eve the
+ Eavesdropper and Victor the Verifier. His extensions seem to be in the
+ process of becoming standard as well. See page 23 of<A href="biblio.html#schneier">
+ Applied Cryptography</A></P>
+<P>Alice and Bob have an amusing<A href="http://www.conceptlabs.co.uk/alicebob.html">
+ biography</A> on the web.</P>
+</DD>
+<DT>ARPA</DT>
+<DD>see<A href="#DARPA"> DARPA</A></DD>
+<DT><A name="ASIO">ASIO</A></DT>
+<DD>Australian Security Intelligence Organisation.</DD>
+<DT>Asymmetric cryptography</DT>
+<DD>See<A href="#public"> public key cryptography</A>.</DD>
+<DT><A name="authentication">Authentication</A></DT>
+<DD>Ensuring that a message originated from the expected sender and has
+ not been altered on route.<A href="#IPSEC"> IPsec</A> uses
+ authentication in two places:
+<UL>
+<LI>peer authentication, authenticating the players in<A href="#IKE">
+ IKE</A>'s<A href="#DH"> Diffie-Hellman</A> key exchanges to prevent<A href="#middle">
+ man-in-the-middle attacks</A>. This can be done in a number of ways.
+ The methods supported by FreeS/WAN are discussed in our<A href="adv_config.html#choose">
+ advanced configuration</A> document.</LI>
+<LI>packet authentication, authenticating packets on an established<A href="#SA">
+ SA</A>, either with a separate<A href="#AH"> authentication header</A>
+ or with the optional authentication in the<A href="#ESP"> ESP</A>
+ protocol. In either case, packet authentication uses a<A href="#HMAC">
+ hashed message athentication code</A> technique.</LI>
+</UL>
+<P>Outside IPsec, passwords are perhaps the most common authentication
+ mechanism. Their function is essentially to authenticate the person's
+ identity to the system. Passwords are generally only as secure as the
+ network they travel over. If you send a cleartext password over a
+ tapped phone line or over a network with a packet sniffer on it, the
+ security provided by that password becomes zero. Sending an encrypted
+ password is no better; the attacker merely records it and reuses it at
+ his convenience. This is called a<A href="#replay"> replay</A> attack.</P>
+<P>A common solution to this problem is a<A href="#challenge">
+ challenge-response</A> system. This defeats simple eavesdropping and
+ replay attacks. Of course an attacker might still try to break the
+ cryptographic algorithm used, or the<A href="#random"> random number</A>
+ generator.</P>
+</DD>
+<DT><A name="auto">Automatic keying</A></DT>
+<DD>A mode in which keys are automatically generated at connection
+ establisment and new keys automaically created periodically thereafter.
+ Contrast with<A href="ipsec.html#manual"> manual keying</A> in which a
+ single stored key is used.
+<P>IPsec uses the<A href="#DH"> Diffie-Hellman key exchange protocol</A>
+ to create keys. An<A href="#authentication"> authentication</A>
+ mechansim is required for this. FreeS/WAN normally uses<A href="#RSA">
+ RSA</A> for this. Other methods supported are discussed in our<A href="adv_config.html#choose">
+ advanced configuration</A> document.</P>
+<P>Having an attacker break the authentication is emphatically not a
+ good idea. An attacker that breaks authentication, and manages to
+ subvert some other network entities (DNS, routers or gateways), can use
+ a<A href="#middle"> man-in-the middle attack</A> to break the security
+ of your IPsec connections.</P>
+<P>However, having an attacker break the authentication in automatic
+ keying is not quite as bad as losing the key in manual keying.</P>
+<UL>
+<LI>An attacker who reads /etc/ipsec.conf and gets the keys for a
+ manually keyed connection can, without further effort, read all
+ messages encrypted with those keys, including any old messages he may
+ have archived.</LI>
+<LI>Automatic keying has a property called<A href="#PFS"> perfect
+ forward secrecy</A>. An attacker who breaks the authentication gets
+ none of the automatically generated keys and cannot immediately read
+ any messages. He has to mount a successful<A href="#middle">
+ man-in-the-middle attack</A> in real time before he can read anything.
+ He cannot read old archived messages at all and will not be able to
+ read any future messages not caught by man-in-the-middle tricks.</LI>
+</UL>
+<P>That said, the secrets used for authentication, stored in<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A>, should still be protected as tightly as
+ cryptographic keys.</P>
+</DD>
+<DT><A name="B">B</A></DT>
+<DT><A href="http://www.nortelnetworks.com">Bay Networks</A></DT>
+<DD>A vendor of routers, hubs and related products, now a subsidiary of
+ Nortel. Interoperation between their IPsec products and Linux FreeS/WAN
+ was problematic at last report; see our<A href="interop.html#bay">
+ interoperation</A> section.</DD>
+<DT><A name="benchmarks">benchmarks</A></DT>
+<DD>Our default block cipher,<A href="#3DES"> triple DES</A>, is slower
+ than many alternate ciphers that might be used. Speeds achieved,
+ however, seem adequate for many purposes. For example, the assembler
+ code from the<A href="#LIBDES"> LIBDES</A> library we use encrypts 1.6
+ megabytes per second on a Pentium 200, according to the test program
+ supplied with the library.
+<P>For more detail, see our document on<A href="performance.html">
+ FreeS/WAN performance</A>.</P>
+</DD>
+<DT><A name="BIND">BIND</A></DT>
+<DD><B>B</B>erkeley<B> I</B>nternet<B> N</B>ame<B> D</B>aemon, a widely
+ used implementation of<A href="ipsec.html#DNS"> DNS</A> (Domain Name
+ Service). See our bibliography for a<A href="ipsec.html#DNS"> useful
+ reference</A>. See the<A href="http://www.isc.org/bind.html"> BIND home
+ page</A> for more information and the latest version.</DD>
+<DT><A name="birthday">Birthday attack</A></DT>
+<DD>A cryptographic attack based on the mathematics exemplified by the<A href="#paradox">
+ birthday paradox</A>. This math turns up whenever the question of two
+ cryptographic operations producing the same result becomes an issue:
+<UL>
+<LI><A href="#collision">collisions</A> in<A href="#digest"> message
+ digest</A> functions.</LI>
+<LI>identical output blocks from a<A href="#block"> block cipher</A></LI>
+<LI>repetition of a challenge in a<A href="#challenge">
+ challenge-response</A> system</LI>
+</UL>
+<P>Resisting such attacks is part of the motivation for:</P>
+<UL>
+<LI>hash algorithms such as<A href="#SHA"> SHA</A> and<A href="#RIPEMD">
+ RIPEMD-160</A> giving a 160-bit result rather than the 128 bits of<A href="#MD4">
+ MD4</A>,<A href="#MD5"> MD5</A> and<A href="#RIPEMD"> RIPEMD-128</A>.</LI>
+<LI><A href="#AES">AES</A> block ciphers using a 128-bit block instead
+ of the 64-bit block of most current ciphers</LI>
+<LI><A href="#IPSEC">IPsec</A> using a 32-bit counter for packets sent
+ on an<A href="ipsec.html#auto"> automatically keyed</A><A href="#SA">
+ SA</A> and requiring that the connection always be rekeyed before the
+ counter overflows.</LI>
+</UL>
+</DD>
+<DT><A name="paradox">Birthday paradox</A></DT>
+<DD>Not really a paradox, just a rather counter-intuitive mathematical
+ fact. In a group of 23 people, the chance of a least one pair having
+ the same birthday is over 50%.
+<P>The second person has 1 chance in 365 (ignoring leap years) of
+ matching the first. If they don't match, the third person's chances of
+ matching one of them are 2/365. The 4th, 3/365, and so on. The total of
+ these chances grows more quickly than one might guess.</P>
+</DD>
+<DT><A name="block">Block cipher</A></DT>
+<DD>A<A href="#symmetric"> symmetric cipher</A> which operates on
+ fixed-size blocks of plaintext, giving a block of ciphertext for each.
+ Contrast with<A href="#stream"> stream cipher</A>. Block ciphers can be
+ used in various<A href="#mode"> modes</A> when multiple block are to be
+ encrypted.
+<P><A href="#DES">DES</A> is among the the best known and widely used
+ block ciphers, but is now obsolete. Its 56-bit key size makes it<A href="politics.html#desnotsecure">
+ highly insecure</A> today.<A href="#3DES"> Triple DES</A> is the
+ default block cipher for<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A>
+.</P>
+<P>The current generation of block ciphers -- such as<A href="#Blowfish">
+ Blowfish</A>,<A href="#CAST128"> CAST-128</A> and<A href="#IDEA"> IDEA</A>
+ -- all use 64-bit blocks and 128-bit keys. The next generation,<A href="#AES">
+ AES</A>, uses 128-bit blocks and supports key sizes up to 256 bits.</P>
+<P>The<A href="http://www.ii.uib.no/~larsr/bc.html"> Block Cipher Lounge</A>
+ web site has more information.</P>
+</DD>
+<DT><A name="Blowfish">Blowfish</A></DT>
+<DD>A<A href="#block"> block cipher</A> using 64-bit blocks and keys of
+ up to 448 bits, designed by<A href="biblio.html#schneier"> Bruce
+ Schneier</A> and used in several products.
+<P>This is not required by the<A href="#IPSEC"> IPsec</A> RFCs and not
+ currently used in<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A>.</P>
+</DD>
+<DT><A name="brute">Brute force attack (exhaustive search)</A></DT>
+<DD>Breaking a cipher by trying all possible keys. This is always
+ possible in theory (except against a<A href="#OTP"> one-time pad</A>),
+ but it becomes practical only if the key size is inadequate. For an
+ important example, see our document on the<A href="politics.html#desnotsecure">
+ insecurity of DES</A> with its 56-bit key. For an analysis of key sizes
+ required to resist plausible brute force attacks, see<A href="http://www.counterpane.com/keylength.html">
+ this paper</A>.
+<P>Longer keys protect against brute force attacks. Each extra bit in
+ the key doubles the number of possible keys and therefore doubles the
+ work a brute force attack must do. A large enough key defeats<STRONG>
+ any</STRONG> brute force attack.</P>
+<P>For example, the EFF's<A href="#EFF"> DES Cracker</A> searches a
+ 56-bit key space in an average of a few days. Let us assume an attacker
+ that can find a 64-bit key (256 times harder) by brute force search in
+ a second (a few hundred thousand times faster). For a 96-bit key, that
+ attacker needs 2<SUP>32</SUP> seconds, about 135 years. Against a
+ 128-bit key, he needs 2<SUP>32</SUP> times that, over 500,000,000,000
+ years. Your data is then obviously secure against brute force attacks.
+ Even if our estimate of the attacker's speed is off by a factor of a
+ million, it still takes him over 500,000 years to crack a message.</P>
+<P>This is why</P>
+<UL>
+<LI>single<A href="#DES"> DES</A> is now considered<A href="politics.html#desnotsecure">
+ dangerously insecure</A></LI>
+<LI>all of the current generation of<A href="#block"> block ciphers</A>
+ use a 128-bit or longer key</LI>
+<LI><A href="#AES">AES</A> ciphers support keysizes 128, 192 and 256
+ bits</LI>
+<LI>any cipher we add to Linux FreeS/WAN will have<EM> at least</EM> a
+ 128-bit key</LI>
+</UL>
+<P><STRONG>Cautions:</STRONG>
+<BR><EM> Inadequate keylength always indicates a weak cipher</EM> but it
+ is important to note that<EM> adequate keylength does not necessarily
+ indicate a strong cipher</EM>. There are many attacks other than brute
+ force, and adequate keylength<EM> only</EM> guarantees resistance to
+ brute force. Any cipher, whatever its key size, will be weak if design
+ or implementation flaws allow other attacks.</P>
+<P>Also,<EM> once you have adequate keylength</EM> (somewhere around 90
+ or 100 bits),<EM> adding more key bits make no practical difference</EM>
+, even against brute force. Consider our 128-bit example above that
+ takes 500,000,000,000 years to break by brute force. We really don't
+ care how many zeroes there are on the end of that, as long as the
+ number remains ridiculously large. That is, we don't care exactly how
+ large the key is as long as it is large enough.</P>
+<P>There may be reasons of convenience in the design of the cipher to
+ support larger keys. For example<A href="#Blowfish"> Blowfish</A>
+ allows up to 448 bits and<A href="#RC4"> RC4</A> up to 2048, but beyond
+ 100-odd bits it makes no difference to practical security.</P>
+</DD>
+<DT>Bureau of Export Administration</DT>
+<DD>see<A href="#BXA"> BXA</A></DD>
+<DT><A name="BXA">BXA</A></DT>
+<DD>The US Commerce Department's<B> B</B>ureau of E<B>x</B>port<B> A</B>
+dministration which administers the<A href="#EAR"> EAR</A> Export
+ Administration Regulations controling the export of, among other
+ things, cryptography.</DD>
+<DT><A name="C">C</A></DT>
+<DT><A name="CA">CA</A></DT>
+<DD><B>C</B>ertification<B> A</B>uthority, an entity in a<A href="#PKI">
+ public key infrastructure</A> that can certify keys by signing them.
+ Usually CAs form a hierarchy. The top of this hierarchy is called the<A href="#rootCA">
+ root CA</A>.
+<P>See<A href="#web"> Web of Trust</A> for an alternate model.</P>
+</DD>
+<DT><A name="CAST128">CAST-128</A></DT>
+<DD>A<A href="#block"> block cipher</A> using 64-bit blocks and 128-bit
+ keys, described in RFC 2144 and used in products such as<A href="#Entrust">
+ Entrust</A> and recent versions of<A href="#PGP"> PGP</A>.
+<P>This is not required by the<A href="#IPSEC"> IPsec</A> RFCs and not
+ currently used in<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A>.</P>
+</DD>
+<DT>CAST-256</DT>
+<DD><A href="#Entrust">Entrust</A>'s candidate cipher for the<A href="#AES">
+ AES standard</A>, largely based on the<A href="#CAST128"> CAST-128</A>
+ design.</DD>
+<DT><A name="CBC">CBC mode</A></DT>
+<DD><B>C</B>ipher<B> B</B>lock<B> C</B>haining<A href="#mode"> mode</A>,
+ a method of using a<A href="#block"> block cipher</A> in which for each
+ block except the first, the result of the previous encryption is XORed
+ into the new block before it is encrypted. CBC is the mode used in<A href="#IPSEC">
+ IPsec</A>.
+<P>An<A href="#IV"> initialisation vector</A> (IV) must be provided. It
+ is XORed into the first block before encryption. The IV need not be
+ secret but should be different for each message and unpredictable.</P>
+</DD>
+<DT><A name="CIDR">CIDR</A></DT>
+<DD><B>C</B>lassless<B> I</B>nter-<B>D</B>omain<B> R</B>outing, an
+ addressing scheme used to describe networks not restricted to the old
+ Class A, B, and C sizes. A CIDR block is written<VAR> address</VAR>/<VAR>
+mask</VAR>, where<VAR> address</VAR> is a 32-bit Internet address. The
+ first<VAR> mask</VAR> bits of<VAR> address</VAR> are part of the
+ gateway address, while the remaining bits designate other host
+ addresses. For example, the CIDR block 192.0.2.96/27 describes a
+ network with gateway 192.0.2.96, hosts 192.0.2.96 through 192.0.2.126
+ and broadcast 192.0.2.127.
+<P>FreeS/WAN policy group files accept CIDR blocks of the format<VAR>
+ address</VAR>/[<VAR>mask</VAR>], where<VAR> address</VAR> may take the
+ form<VAR> name.domain.tld</VAR>. An absent<VAR> mask</VAR> is assumed
+ to be /32.</P>
+</DD>
+<DT>Certification Authority</DT>
+<DD>see<A href="#CA"> CA</A></DD>
+<DT><A name="challenge">Challenge-response authentication</A></DT>
+<DD>An<A href="#authentication"> authentication</A> system in which one
+ player generates a<A href="#random"> random number</A>, encrypts it and
+ sends the result as a challenge. The other player decrypts and sends
+ back the result. If the result is correct, that proves to the first
+ player that the second player knew the appropriate secret, required for
+ the decryption. Variations on this technique exist using<A href="#public">
+ public key</A> or<A href="#symmetric"> symmetric</A> cryptography. Some
+ provide two-way authentication, assuring each player of the other's
+ identity.
+<P>This is more secure than passwords against two simple attacks:</P>
+<UL>
+<LI>If cleartext passwords are sent across the wire (e.g. for telnet),
+ an eavesdropper can grab them. The attacker may even be able to break
+ into other systems if the user has chosen the same password for them.</LI>
+<LI>If an encrypted password is sent, an attacker can record the
+ encrypted form and use it later. This is called a replay attack.</LI>
+</UL>
+<P>A challenge-response system never sends a password, either cleartext
+ or encrypted. An attacker cannot record the response to one challenge
+ and use it as a response to a later challenge. The random number is
+ different each time.</P>
+<P>Of course an attacker might still try to break the cryptographic
+ algorithm used, or the<A href="#random"> random number</A> generator.</P>
+</DD>
+<DT><A name="mode">Cipher Modes</A></DT>
+<DD>Different ways of using a block cipher when encrypting multiple
+ blocks.
+<P>Four standard modes were defined for<A href="#DES"> DES</A> in<A href="#FIPS">
+ FIPS</A> 81. They can actually be applied with any block cipher.</P>
+<TABLE><TBODY></TBODY>
+<TR><TD></TD><TD><A href="#ECB">ECB</A></TD><TD>Electronic CodeBook</TD><TD>
+encrypt each block independently</TD></TR>
+<TR><TD></TD><TD><A href="#CBC">CBC</A></TD><TD>Cipher Block Chaining
+<BR></TD><TD>XOR previous block ciphertext into new block plaintext
+ before encrypting new block</TD></TR>
+<TR><TD></TD><TD>CFB</TD><TD>Cipher FeedBack</TD><TD></TD></TR>
+<TR><TD></TD><TD>OFB</TD><TD>Output FeedBack</TD><TD></TD></TR>
+</TABLE>
+<P><A href="#IPSEC">IPsec</A> uses<A href="#CBC"> CBC</A> mode since
+ this is only marginally slower than<A href="#ECB"> ECB</A> and is more
+ secure. In ECB mode the same plaintext always encrypts to the same
+ ciphertext, unless the key is changed. In CBC mode, this does not
+ occur.</P>
+<P>Various other modes are also possible, but none of them are used in
+ IPsec.</P>
+</DD>
+<DT><A name="ciphertext">Ciphertext</A></DT>
+<DD>The encrypted output of a cipher, as opposed to the unencrypted<A href="#plaintext">
+ plaintext</A> input.</DD>
+<DT><A href="http://www.cisco.com">Cisco</A></DT>
+<DD>A vendor of routers, hubs and related products. Their IPsec products
+ interoperate with Linux FreeS/WAN; see our<A href="interop.html#Cisco">
+ interop</A> section.</DD>
+<DT><A name="client">Client</A></DT>
+<DD>This term has at least two distinct uses in discussing IPsec:
+<UL>
+<LI>The<STRONG> clients of an IPsec gateway</STRONG> are the machines it
+ protects, typically on one or more subnets behind the gateway. In this
+ usage, all the machines on an office network are clients of that
+ office's IPsec gateway. Laptop or home machines connecting to the
+ office, however, are<EM> not</EM> clients of that gateway. They are
+ remote gateways, running the other end of an IPsec connection. Each of
+ them is also its own client.</LI>
+<LI><STRONG>IPsec client software</STRONG> is used to describe software
+ which runs on various standalone machines to let them connect to IPsec
+ networks. In this usage, a laptop or home machine connecting to the
+ office is a client, and the office gateway is the server.</LI>
+</UL>
+<P>We generally use the term in the first sense. Vendors of Windows
+ IPsec solutions often use it in the second. See this<A href="interop.html#client.server">
+ discussion</A>.</P>
+</DD>
+<DT><A name="cc">Common Criteria</A></DT>
+<DD>A set of international security classifications which are replacing
+ the old US<A href="#rainbow"> Rainbow Book</A> standards and similar
+ standards in other countries.
+<P>Web references include this<A href="http://csrc.nist.gov/cc"> US
+ government site</A> and this<A href="http://www.commoncriteria.org">
+ global home page</A>.</P>
+</DD>
+<DT>Conventional cryptography</DT>
+<DD>See<A href="#symmetric"> symmetric cryptography</A></DD>
+<DT><A name="collision">Collision resistance</A></DT>
+<DD>The property of a<A href="#digest"> message digest</A> algorithm
+ which makes it hard for an attacker to find or construct two inputs
+ which hash to the same output.</DD>
+<DT>Copyleft</DT>
+<DD>see GNU<A href="#GPL"> General Public License</A></DD>
+<DT><A name="CSE">CSE</A></DT>
+<DD><A href="http://www.cse-cst.gc.ca/">Communications Security
+ Establishment</A>, the Canadian organisation for<A href="#SIGINT">
+ signals intelligence</A>.</DD>
+<DT><A name="D">D</A></DT>
+<DT><A name="DARPA">DARPA (sometimes just ARPA)</A></DT>
+<DD>The US government's<B> D</B>efense<B> A</B>dvanced<B> R</B>esearch<B>
+ P</B>rojects<B> A</B>gency. Projects they have funded over the years
+ have included the Arpanet which evolved into the Internet, the TCP/IP
+ protocol suite (as a replacement for the original Arpanet suite), the
+ Berkeley 4.x BSD Unix projects, and<A href="#SDNS"> Secure DNS</A>.
+<P>For current information, see their<A href="http://www.darpa.mil/ito">
+ web site</A>.</P>
+</DD>
+<DT><A name="DOS">Denial of service (DoS) attack</A></DT>
+<DD>An attack that aims at denying some service to legitimate users of a
+ system, rather than providing a service to the attacker.
+<UL>
+<LI>One variant is a flooding attack, overwhelming the system with too
+ many packets, to much email, or whatever.</LI>
+<LI>A closely related variant is a resource exhaustion attack. For
+ example, consider a &quot;TCP SYN flood&quot; attack. Setting up a TCP connection
+ involves a three-packet exchange:
+<UL>
+<LI>Initiator: Connection please (SYN)</LI>
+<LI>Responder: OK (ACK)</LI>
+<LI>Initiator: OK here too</LI>
+</UL>
+<P>If the attacker puts bogus source information in the first packet,
+ such that the second is never delivered, the responder may wait a long
+ time for the third to come back. If responder has already allocated
+ memory for the connection data structures, and if many of these bogus
+ packets arrive, the responder may run out of memory.</P>
+</LI>
+<LI>Another variant is to feed the system undigestible data, hoping to
+ make it sick. For example, IP packets are limited in size to 64K bytes
+ and a fragment carries information on where it starts within that 64K
+ and how long it is. The &quot;ping of death&quot; delivers fragments that say,
+ for example, that they start at 60K and are 20K long. Attempting to
+ re-assemble these without checking for overflow can be fatal.</LI>
+</UL>
+<P>The two example attacks discussed were both quite effective when
+ first discovered, capable of crashing or disabling many operating
+ systems. They were also well-publicised, and today far fewer systems
+ are vulnerable to them.</P>
+</DD>
+<DT><A name="DES">DES</A></DT>
+<DD>The<B> D</B>ata<B> E</B>ncryption<B> S</B>tandard, a<A href="#block">
+ block cipher</A> with 64-bit blocks and a 56-bit key. Probably the most
+ widely used<A href="#symmetric"> symmetric cipher</A> ever devised. DES
+ has been a US government standard for their own use (only for
+ unclassified data), and for some regulated industries such as banking,
+ since the late 70's. It is now being replaced by<A href="#AES"> AES</A>
+.
+<P><A href="politics.html#desnotsecure">DES is seriously insecure
+ against current attacks.</A></P>
+<P><A href="web.html#FreeSWAN">Linux FreeS/WAN</A> does not include DES,
+ even though the RFCs specify it.<B> We strongly recommend that single
+ DES not be used.</B></P>
+<P>See also<A href="#3DES"> 3DES</A> and<A href="#DESX"> DESX</A>,
+ stronger ciphers based on DES.</P>
+</DD>
+<DT><A name="DESX">DESX</A></DT>
+<DD>An improved<A href="#DES"> DES</A> suggested by Ron Rivest of RSA
+ Data Security. It XORs extra key material into the text before and
+ after applying the DES cipher.
+<P>This is not required by the<A href="#IPSEC"> IPsec</A> RFCs and not
+ currently used in<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A>. DESX
+ would be the easiest additional transform to add; there would be very
+ little code to write. It would be much faster than 3DES and almost
+ certainly more secure than DES. However, since it is not in the RFCs
+ other IPsec implementations cannot be expected to have it.</P>
+</DD>
+<DT>DH</DT>
+<DD>see<A href="#DH"> Diffie-Hellman</A></DD>
+<DT><A name="DHCP">DHCP</A></DT>
+<DD><STRONG>D</STRONG>ynamic<STRONG> H</STRONG>ost<STRONG> C</STRONG>
+onfiguration<STRONG> P</STRONG>rotocol, a method of assigning<A href="#dynamic">
+ dynamic IP addresses</A>, and providing additional information such as
+ addresses of DNS servers and of gateways. See this<A href="http://www.dhcp.org">
+ DHCP resource page.</A></DD>
+<DT><A name="DH">Diffie-Hellman (DH) key exchange protocol</A></DT>
+<DD>A protocol that allows two parties without any initial shared secret
+ to create one in a manner immune to eavesdropping. Once they have done
+ this, they can communicate privately by using that shared secret as a
+ key for a block cipher or as the basis for key exchange.
+<P>The protocol is secure against all<A href="#passive"> passive attacks</A>
+, but it is not at all resistant to active<A href="#middle">
+ man-in-the-middle attacks</A>. If a third party can impersonate Bob to
+ Alice and vice versa, then no useful secret can be created.
+ Authentication of the participants is a prerequisite for safe
+ Diffie-Hellman key exchange. IPsec can use any of several<A href="#authentication">
+ authentication</A> mechanisims. Those supported by FreeS/WAN are
+ discussed in our<A href="config.html#choose"> configuration</A>
+ section.</P>
+<P>The Diffie-Hellman key exchange is based on the<A href="#dlog">
+ discrete logarithm</A> problem and is secure unless someone finds an
+ efficient solution to that problem.</P>
+<P>Given a prime<VAR> p</VAR> and generator<VAR> g</VAR> (explained
+ under<A href="#dlog"> discrete log</A> below), Alice:</P>
+<UL>
+<LI>generates a random number<VAR> a</VAR></LI>
+<LI>calculates<VAR> A = g^a modulo p</VAR></LI>
+<LI>sends<VAR> A</VAR> to Bob</LI>
+</UL>
+<P>Meanwhile Bob:</P>
+<UL>
+<LI>generates a random number<VAR> b</VAR></LI>
+<LI>calculates<VAR> B = g^b modulo p</VAR></LI>
+<LI>sends<VAR> B</VAR> to Alice</LI>
+</UL>
+<P>Now Alice and Bob can both calculate the shared secret<VAR> s =
+ g^(ab)</VAR>. Alice knows<VAR> a</VAR> and<VAR> B</VAR>, so she
+ calculates<VAR> s = B^a</VAR>. Bob knows<VAR> A</VAR> and<VAR> b</VAR>
+ so he calculates<VAR> s = A^b</VAR>.</P>
+<P>An eavesdropper will know<VAR> p</VAR> and<VAR> g</VAR> since these
+ are made public, and can intercept<VAR> A</VAR> and<VAR> B</VAR> but,
+ short of solving the<A href="#dlog"> discrete log</A> problem, these do
+ not let him or her discover the secret<VAR> s</VAR>.</P>
+</DD>
+<DT><A name="signature">Digital signature</A></DT>
+<DD>Sender:
+<UL>
+<LI>calculates a<A href="#digest"> message digest</A> of a document</LI>
+<LI>encrypts the digest with his or her private key, using some<A href="#public">
+ public key cryptosystem</A>.</LI>
+<LI>attaches the encrypted digest to the document as a signature</LI>
+</UL>
+<P>Receiver:</P>
+<UL>
+<LI>calculates a digest of the document (not including the signature)</LI>
+<LI>decrypts the signature with the signer's public key</LI>
+<LI>verifies that the two results are identical</LI>
+</UL>
+<P>If the public-key system is secure and the verification succeeds,
+ then the receiver knows</P>
+<UL>
+<LI>that the document was not altered between signing and verification</LI>
+<LI>that the signer had access to the private key</LI>
+</UL>
+<P>Such an encrypted message digest can be treated as a signature since
+ it cannot be created without<EM> both</EM> the document<EM> and</EM>
+ the private key which only the sender should possess. The<A href="web.html#legal">
+ legal issues</A> are complex, but several countries are moving in the
+ direction of legal recognition for digital signatures.</P>
+</DD>
+<DT><A name="dlog">discrete logarithm problem</A></DT>
+<DD>The problem of finding logarithms in a finite field. Given a field
+ defintion (such definitions always include some operation analogous to
+ multiplication) and two numbers, a base and a target, find the power
+ which the base must be raised to in order to yield the target.
+<P>The discrete log problem is the basis of several cryptographic
+ systems, including the<A href="#DH"> Diffie-Hellman</A> key exchange
+ used in the<A href="#IKE"> IKE</A> protocol. The useful property is
+ that exponentiation is relatively easy but the inverse operation,
+ finding the logarithm, is hard. The cryptosystems are designed so that
+ the user does only easy operations (exponentiation in the field) but an
+ attacker must solve the hard problem (discrete log) to crack the
+ system.</P>
+<P>There are several variants of the problem for different types of
+ field. The IKE/Oakley key determination protocol uses two variants,
+ either over a field modulo a prime or over a field defined by an
+ elliptic curve. We give an example modulo a prime below. For the
+ elliptic curve version, consult an advanced text such as<A href="biblio.html#handbook">
+ Handbook of Applied Cryptography</A>.</P>
+<P>Given a prime<VAR> p</VAR>, a generator<VAR> g</VAR> for the field
+ modulo that prime, and a number<VAR> x</VAR> in the field, the problem
+ is to find<VAR> y</VAR> such that<VAR> g^y = x</VAR>.</P>
+<P>For example, let p = 13. The field is then the integers from 0 to 12.
+ Any integer equals one of these modulo 13. That is, the remainder when
+ any integer is divided by 13 must be one of these.</P>
+<P>2 is a generator for this field. That is, the powers of two modulo 13
+ run through all the non-zero numbers in the field. Modulo 13 we have:</P>
+<PRE> y x
+ 2^0 == 1
+ 2^1 == 2
+ 2^2 == 4
+ 2^3 == 8
+ 2^4 == 3 that is, the remainder from 16/13 is 3
+ 2^5 == 6 the remainder from 32/13 is 6
+ 2^6 == 12 and so on
+ 2^7 == 11
+ 2^8 == 9
+ 2^9 == 5
+ 2^10 == 10
+ 2^11 == 7
+ 2^12 == 1</PRE>
+<P>Exponentiation in such a field is not difficult. Given, say,<NOBR><VAR>
+ y = 11</VAR>,calculating<NOBR><VAR> x = 7</VAR>is straightforward. One
+ method is just to calculate<NOBR><VAR> 2^11 = 2048</VAR>,then<NOBR><VAR>
+ 2048 mod 13 == 7</VAR>.When the field is modulo a large prime (say a
+ few 100 digits) you need a silghtly cleverer method and even that is
+ moderately expensive in computer time, but the calculation is still not
+ problematic in any basic way.</P>
+<P>The discrete log problem is the reverse. In our example, given<NOBR><VAR>
+ x = 7</VAR>,find the logarithm<NOBR><VAR> y = 11</VAR>.When the field
+ is modulo a large prime (or is based on a suitable elliptic curve),
+ this is indeed problematic. No solution method that is not
+ catastrophically expensive is known. Quite a few mathematicians have
+ tackled this problem. No efficient method has been found and
+ mathematicians do not expect that one will be. It seems likely no
+ efficient solution to either of the main variants the discrete log
+ problem exists.</P>
+<P>Note, however, that no-one has proven such methods do not exist. If a
+ solution to either variant were found, the security of any crypto
+ system using that variant would be destroyed. This is one reason<A href="#IKE">
+ IKE</A> supports two variants. If one is broken, we can switch to the
+ other.</P>
+</DD>
+<DT><A name="discretionary">discretionary access control</A></DT>
+<DD>access control mechanisms controlled by the user, for example Unix
+ rwx file permissions. These contrast with<A href="#mandatory">
+ mandatory access controls</A>.</DD>
+<DT><A name="DNS">DNS</A></DT>
+<DD><B>D</B>omain<B> N</B>ame<B> S</B>ervice, a distributed database
+ through which names are associated with numeric addresses and other
+ information in the Internet Protocol Suite. See also the<A href="background.html#dns.background">
+ DNS background</A> section of our documentation.</DD>
+<DT>DOS attack</DT>
+<DD>see<A href="#DOS"> Denial Of Service</A> attack</DD>
+<DT><A name="dynamic">dynamic IP address</A></DT>
+<DD>an IP address which is automatically assigned, either by<A href="#DHCP">
+ DHCP</A> or by some protocol such as<A href="#PPP"> PPP</A> or<A href="#PPPoE">
+ PPPoE</A> which the machine uses to connect to the Internet. This is
+ the opposite of a<A href="#static"> static IP address</A>, pre-set on
+ the machine itself.</DD>
+<DT><A name="E">E</A></DT>
+<DT><A name="EAR">EAR</A></DT>
+<DD>The US government's<B> E</B>xport<B> A</B>dministration<B> R</B>
+egulations, administered by the<A href="#BXA"> Bureau of Export
+ Administration</A>. These have replaced the earlier<A href="#ITAR">
+ ITAR</A> regulations as the controls on export of cryptography.</DD>
+<DT><A name="ECB">ECB mode</A></DT>
+<DD><B>E</B>lectronic<B> C</B>ode<B>B</B>ook mode, the simplest way to
+ use a block cipher. See<A href="#mode"> Cipher Modes</A>.</DD>
+<DT><A name="EDE">EDE</A></DT>
+<DD>The sequence of operations normally used in either the three-key
+ variant of<A href="#3DES"> triple DES</A> used in<A href="#IPSEC">
+ IPsec</A> or the<A href="#2key"> two-key</A> variant used in some other
+ systems.
+<P>The sequence is:</P>
+<UL>
+<LI><B>E</B>ncrypt with key1</LI>
+<LI><B>D</B>ecrypt with key2</LI>
+<LI><B>E</B>ncrypt with key3</LI>
+</UL>
+<P>For the two-key version, key1=key3.</P>
+<P>The &quot;advantage&quot; of this EDE order of operations is that it makes it
+ simple to interoperate with older devices offering only single DES. Set
+ key1=key2=key3 and you have the worst of both worlds, the overhead of
+ triple DES with the &quot;security&quot; of single DES. Since both the<A href="politics.html#desnotsecure">
+ security of single DES</A> and the overheads of triple DES are
+ seriously inferior to many other ciphers, this is a spectacularly
+ dubious &quot;advantage&quot;.</P>
+</DD>
+<DT><A name="Entrust">Entrust</A></DT>
+<DD>A Canadian company offerring enterprise<A href="#PKI"> PKI</A>
+ products using<A href="#CAST128"> CAST-128</A> symmetric crypto,<A href="#RSA">
+ RSA</A> public key and<A href="#X509"> X.509</A> directories.<A href="http://www.entrust.com">
+ Web site</A></DD>
+<DT><A name="EFF">EFF</A></DT>
+<DD><A href="http://www.eff.org">Electronic Frontier Foundation</A>, an
+ advocacy group for civil rights in cyberspace.</DD>
+<DT><A name="encryption">Encryption</A></DT>
+<DD>Techniques for converting a readable message (<A href="#plaintext">
+plaintext</A>) into apparently random material (<A href="#ciphertext">
+ciphertext</A>) which cannot be read if intercepted. A key is required
+ to read the message.
+<P>Major variants include<A href="#symmetric"> symmetric</A> encryption
+ in which sender and receiver use the same secret key and<A href="#public">
+ public key</A> methods in which the sender uses one of a matched pair
+ of keys and the receiver uses the other. Many current systems,
+ including<A href="#IPSEC"> IPsec</A>, are<A href="#hybrid"> hybrids</A>
+ combining the two techniques.</P>
+</DD>
+<DT><A name="ESP">ESP</A></DT>
+<DD><B>E</B>ncapsulated<B> S</B>ecurity<B> P</B>ayload, the<A href="#IPSEC">
+ IPsec</A> protocol which provides<A href="#encryption"> encryption</A>.
+ It can also provide<A href="#authentication"> authentication</A>
+ service and may be used with null encryption (which we do not
+ recommend). For details see our<A href="ipsec.html#ESP.ipsec"> IPsec</A>
+ document and/or RFC 2406.</DD>
+<DT><A name="#extruded">Extruded subnet</A></DT>
+<DD>A situation in which something IP sees as one network is actually in
+ two or more places.
+<P>For example, the Internet may route all traffic for a particular
+ company to that firm's corporate gateway. It then becomes the company's
+ problem to get packets to various machines on their<A href="#subnet">
+ subnets</A> in various departments. They may decide to treat a branch
+ office like a subnet, giving it IP addresses &quot;on&quot; their corporate net.
+ This becomes an extruded subnet.</P>
+<P>Packets bound for it are delivered to the corporate gateway, since as
+ far as the outside world is concerned, that subnet is part of the
+ corporate network. However, instead of going onto the corporate LAN (as
+ they would for, say, the accounting department) they are then
+ encapsulated and sent back onto the Internet for delivery to the branch
+ office.</P>
+<P>For information on doing this with Linux FreeS/WAN, look in our<A href="adv_config.html#extruded.config">
+ advanced configuration</A> section.</P>
+</DD>
+<DT>Exhaustive search</DT>
+<DD>See<A href="#brute"> brute force attack</A>.</DD>
+<DT><A name="F">F</A></DT>
+<DT><A name="FIPS">FIPS</A></DT>
+<DD><B>F</B>ederal<B> I</B>nformation<B> P</B>rocessing<B> S</B>tandard,
+ the US government's standards for products it buys. These are issued by<A
+href="#NIST"> NIST</A>. Among other things,<A href="#DES"> DES</A> and<A href="#SHA">
+ SHA</A> are defined in FIPS documents. NIST have a<A href="http://www.itl.nist.gov/div897/pubs">
+ FIPS home page</A>.</DD>
+<DT><A name="FSF">Free Software Foundation (FSF)</A></DT>
+<DD>An organisation to promote free software, free in the sense of these
+ quotes from their web pages</DD>
+<DD><BLOCKQUOTE> &quot;Free software&quot; is a matter of liberty, not price. To
+ understand the concept, you should think of &quot;free speech&quot;, not &quot;free
+ beer.&quot;
+<P>&quot;Free software&quot; refers to the users' freedom to run, copy,
+ distribute, study, change and improve the software.</P>
+</BLOCKQUOTE>
+<P>See also<A href="#GNU"> GNU</A>,<A href="#GPL"> GNU General Public
+ License</A>, and<A href="http://www.fsf.org"> the FSF site</A>.</P>
+</DD>
+<DT>FreeS/WAN</DT>
+<DD>see<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A></DD>
+<DT><A name="fullnet">Fullnet</A></DT>
+<DD>The CIDR block containing all IPs of its IP version. The<A HREF="#IPv4">
+ IPv4</A> fullnet is written 0.0.0.0/0. Also known as &quot;all&quot; and
+ &quot;default&quot;, fullnet may be used in a routing table to specify a default
+ route, and in a FreeS/WAN<A HREF="policygroups.html#policygroups">
+ policy group</A> file to specify a default IPsec policy.</DD>
+<DT>FSF</DT>
+<DD>see<A href="#FSF"> Free software Foundation</A></DD>
+<DT><A name="G">G</A></DT>
+<DT><A name="GCHQ">GCHQ</A></DT>
+<DD><A href="http://www.gchq.gov.uk">Government Communications
+ Headquarters</A>, the British organisation for<A href="#SIGINT">
+ signals intelligence</A>.</DD>
+<DT>generator of a prime field</DT>
+<DD>see<A href="#dlog"> discrete logarithm problem</A></DD>
+<DT><A name="GILC">GILC</A></DT>
+<DD><A href="http://www.gilc.org">Global Internet Liberty Campaign</A>,
+ an international organisation advocating, among other things, free
+ availability of cryptography. They have a<A href="http://www.gilc.org/crypto/wassenaar">
+ campaign</A> to remove cryptographic software from the<A href="#Wassenaar.gloss">
+ Wassenaar Arrangement</A>.</DD>
+<DT>Global Internet Liberty Campaign</DT>
+<DD>see<A href="#GILC"> GILC</A>.</DD>
+<DT><A name="GTR">Global Trust Register</A></DT>
+<DD>An attempt to create something like a<A href="#rootCA"> root CA</A>
+ for<A href="#PGP"> PGP</A> by publishing both<A href="biblio.html#GTR">
+ as a book</A> and<A href="http://www.cl.cam.ac.uk/Research/Security/Trust-Register">
+ on the web</A> the fingerprints of a set of verified keys for
+ well-known users and organisations.</DD>
+<DT><A name="GMP">GMP</A></DT>
+<DD>The<B> G</B>NU<B> M</B>ulti-<B>P</B>recision library code, used in<A href="web.html#FreeSWAN">
+ Linux FreeS/WAN</A> by<A href="#Pluto"> Pluto</A> for<A href="#public">
+ public key</A> calculations. See the<A href="http://www.swox.com/gmp">
+ GMP home page</A>.</DD>
+<DT><A name="GNU">GNU</A></DT>
+<DD><B>G</B>NU's<B> N</B>ot<B> U</B>nix, the<A href="#FSF"> Free
+ Software Foundation's</A> project aimed at creating a free system with
+ at least the capabilities of Unix.<A href="#Linux"> Linux</A> uses GNU
+ utilities extensively.</DD>
+<DT><A name="#GOST">GOST</A></DT>
+<DD>a Soviet government standard<A href="#block"> block cipher</A>.<A href="biblio.html#schneier">
+ Applied Cryptography</A> has details.</DD>
+<DT>GPG</DT>
+<DD>see<A href="#GPG"> GNU Privacy Guard</A></DD>
+<DT><A name="GPL">GNU General Public License</A>(GPL, copyleft)</DT>
+<DD>The license developed by the<A href="#FSF"> Free Software Foundation</A>
+ under which<A href="#Linux"> Linux</A>,<A href="web.html#FreeSWAN">
+ Linux FreeS/WAN</A> and many other pieces of software are distributed.
+ The license allows anyone to redistribute and modify the code, but
+ forbids anyone from distributing executables without providing access
+ to source code. For more details see the file<A href="../COPYING">
+ COPYING</A> included with GPLed source distributions, including ours,
+ or<A href="http://www.fsf.org/copyleft/gpl.html"> the GNU site's GPL
+ page</A>.</DD>
+<DT><A name="GPG">GNU Privacy Guard</A></DT>
+<DD>An open source implementation of Open<A href="#PGP"> PGP</A> as
+ defined in RFC 2440. See their<A href="http://www.gnupg.org"> web site</A>
+</DD>
+<DT>GPL</DT>
+<DD>see<A href="#GPL"> GNU General Public License</A>.</DD>
+<DT><A name="H">H</A></DT>
+<DT><A name="hash">Hash</A></DT>
+<DD>see<A href="#digest"> message digest</A></DD>
+<DT><A name="HMAC">Hashed Message Authentication Code (HMAC)</A></DT>
+<DD>using keyed<A href="#digest"> message digest</A> functions to
+ authenticate a message. This differs from other uses of these
+ functions:
+<UL>
+<LI>In normal usage, the hash function's internal variable are
+ initialised in some standard way. Anyone can reproduce the hash to
+ check that the message has not been altered.</LI>
+<LI>For HMAC usage, you initialise the internal variables from the key.
+ Only someone with the key can reproduce the hash. A successful check of
+ the hash indicates not only that the message is unchanged but also that
+ the creator knew the key.</LI>
+</UL>
+<P>The exact techniques used in<A href="#IPSEC"> IPsec</A> are defined
+ in RFC 2104. They are referred to as HMAC-MD5-96 and HMAC-SHA-96
+ because they output only 96 bits of the hash. This makes some attacks
+ on the hash functions harder.</P>
+</DD>
+<DT>HMAC</DT>
+<DD>see<A href="#HMAC"> Hashed Message Authentication Code</A></DD>
+<DT>HMAC-MD5-96</DT>
+<DD>see<A href="#HMAC"> Hashed Message Authentication Code</A></DD>
+<DT>HMAC-SHA-96</DT>
+<DD>see<A href="#HMAC"> Hashed Message Authentication Code</A></DD>
+<DT><A name="hybrid">Hybrid cryptosystem</A></DT>
+<DD>A system using both<A href="#public"> public key</A> and<A href="#symmetric">
+ symmetric cipher</A> techniques. This works well. Public key methods
+ provide key management and<A href="#signature"> digital signature</A>
+ facilities which are not readily available using symmetric ciphers. The
+ symmetric cipher, however, can do the bulk of the encryption work much
+ more efficiently than public key methods.</DD>
+<DT><A name="I">I</A></DT>
+<DT><A name="IAB">IAB</A></DT>
+<DD><A href="http://www.iab.org/iab">Internet Architecture Board</A>.</DD>
+<DT><A name="ICMP.gloss">ICMP</A></DT>
+<DD><STRONG>I</STRONG>nternet<STRONG> C</STRONG>ontrol<STRONG> M</STRONG>
+essage<STRONG> P</STRONG>rotocol. This is used for various IP-connected
+ devices to manage the network.</DD>
+<DT><A name="IDEA">IDEA</A></DT>
+<DD><B>I</B>nternational<B> D</B>ata<B> E</B>ncrypion<B> A</B>lgorithm,
+ developed in Europe as an alternative to exportable American ciphers
+ such as<A href="#DES"> DES</A> which were<A href="politics.html#desnotsecure">
+ too weak for serious use</A>. IDEA is a<A href="#block"> block cipher</A>
+ using 64-bit blocks and 128-bit keys, and is used in products such as<A href="#PGP">
+ PGP</A>.
+<P>IDEA is not required by the<A href="#IPSEC"> IPsec</A> RFCs and not
+ currently used in<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A>.</P>
+<P>IDEA is patented and, with strictly limited exceptions for personal
+ use, using it requires a license from<A href="http://www.ascom.com">
+ Ascom</A>.</P>
+</DD>
+<DT><A name="IEEE">IEEE</A></DT>
+<DD><A href="http://www.ieee.org">Institute of Electrical and Electronic
+ Engineers</A>, a professional association which, among other things,
+ sets some technical standards</DD>
+<DT><A name="IESG">IESG</A></DT>
+<DD><A href="http://www.iesg.org">Internet Engineering Steering Group</A>
+.</DD>
+<DT><A name="IETF">IETF</A></DT>
+<DD><A href="http://www.ietf.org">Internet Engineering Task Force</A>,
+ the umbrella organisation whose various working groups make most of the
+ technical decisions for the Internet. The IETF<A href="http://www.ietf.org/html.charters/ipsec-charter.html">
+ IPsec working group</A> wrote the<A href="rfc.html#RFC"> RFCs</A> we
+ are implementing.</DD>
+<DT><A name="IKE">IKE</A></DT>
+<DD><B>I</B>nternet<B> K</B>ey<B> E</B>xchange, based on the<A href="#DH">
+ Diffie-Hellman</A> key exchange protocol. For details, see RFC 2409 and
+ our<A href="ipsec.html"> IPsec</A> document. IKE is implemented in<A href="web.html#FreeSWAN">
+ Linux FreeS/WAN</A> by the<A href="#Pluto"> Pluto daemon</A>.</DD>
+<DT>IKE v2</DT>
+<DD>A proposed replacement for<A href="#IKE"> IKE</A>. There are other
+ candidates, such as<A href="#JFK"> JFK</A>, and at time of writing
+ (March 2002) the choice between them has not yet been made and does not
+ appear imminent.</DD>
+<DT><A name="iOE">iOE</A></DT>
+<DD>See<A HREF="#initiate-only"> Initiate-only opportunistic encryption</A>
+.</DD>
+<DT><A name="IP">IP</A></DT>
+<DD><B>I</B>nternet<B> P</B>rotocol.</DD>
+<DT><A name="masq">IP masquerade</A></DT>
+<DD>A mostly obsolete term for a method of allowing multiple machines to
+ communicate over the Internet when only one IP address is available for
+ their use. The more current term is Network Address Translation or<A href="#NAT.gloss">
+ NAT</A>.</DD>
+<DT><A name="IPng">IPng</A></DT>
+<DD>&quot;IP the Next Generation&quot;, see<A href="#ipv6.gloss"> IPv6</A>.</DD>
+<DT><A name="IPv4">IPv4</A></DT>
+<DD>The current version of the<A href="#IP"> Internet protocol suite</A>
+.</DD>
+<DT><A name="ipv6.gloss">IPv6 (IPng)</A></DT>
+<DD>Version six of the<A href="#IP"> Internet protocol suite</A>,
+ currently being developed. It will replace the current<A href="#IPv4">
+ version four</A>. IPv6 has<A href="#IPSEC"> IPsec</A> as a mandatory
+ component.
+<P>See this<A href="http://playground.sun.com/pub/ipng/html/ipng-main.html">
+ web site</A> for more details, and our<A href="compat.html#ipv6">
+ compatibility</A> document for information on FreeS/WAN and the Linux
+ implementation of IPv6.</P>
+</DD>
+<DT><A name="IPSEC">IPsec</A> or IPSEC</DT>
+<DD><B>I</B>nternet<B> P</B>rotocol<B> SEC</B>urity, security functions
+ (<A href="#authentication">authentication</A> and<A href="#encryption">
+ encryption</A>) implemented at the IP level of the protocol stack. It
+ is optional for<A href="#IPv4"> IPv4</A> and mandatory for<A href="#ipv6.gloss">
+ IPv6</A>.
+<P>This is the standard<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A>
+ is implementing. For more details, see our<A href="ipsec.html"> IPsec
+ Overview</A>. For the standards, see RFCs listed in our<A href="rfc.html#RFC">
+ RFCs document</A>.</P>
+</DD>
+<DT><A name="IPX">IPX</A></DT>
+<DD>Novell's Netware protocol tunnelled over an IP link. Our<A href="firewall.html#user.scripts">
+ firewalls</A> document includes an example of using this through an
+ IPsec tunnel.</DD>
+<DT><A name="ISAKMP">ISAKMP</A></DT>
+<DD><B>I</B>nternet<B> S</B>ecurity<B> A</B>ssociation and<B> K</B>ey<B>
+ M</B>anagement<B> P</B>rotocol, defined in RFC 2408.</DD>
+<DT><A name="ITAR">ITAR</A></DT>
+<DD><B>I</B>nternational<B> T</B>raffic in<B> A</B>rms<B> R</B>
+egulations, US regulations administered by the State Department which
+ until recently limited export of, among other things, cryptographic
+ technology and software. ITAR still exists, but the limits on
+ cryptography have now been transferred to the<A href="#EAR"> Export
+ Administration Regulations</A> under the Commerce Department's<A href="#BXA">
+ Bureau of Export Administration</A>.</DD>
+<DT>IV</DT>
+<DD>see<A href="#IV"> Initialisation vector</A></DD>
+<DT><A name="IV">Initialisation Vector (IV)</A></DT>
+<DD>Some cipher<A href="#mode"> modes</A>, including the<A href="#CBC">
+ CBC</A> mode which IPsec uses, require some extra data at the
+ beginning. This data is called the initialisation vector. It need not
+ be secret, but should be different for each message. Its function is to
+ prevent messages which begin with the same text from encrypting to the
+ same ciphertext. That might give an analyst an opening, so it is best
+ prevented.</DD>
+<DT><A name="initiate-only">Initiate-only opportunistic encryption (iOE)</A>
+</DT>
+<DD>A form of<A HREF="#carpediem"> opportunistic encryption</A> (OE) in
+ which a host proposes opportunistic connections, but lacks the reverse
+ DNS records necessary to support incoming opportunistic connection
+ requests. Common among hosts on cable or pppoe connections where the
+ system administrator does not have write access to the DNS reverse map
+ for the host's external IP.
+<P>Configuring for initiate-only opportunistic encryption is described
+ in our<A href="quickstart.html#opp.client"> quickstart</A> document.</P>
+</DD>
+<DT><A name="J">J</A></DT>
+<DT><A name="JFK">JFK</A></DT>
+<DD><STRONG>J</STRONG>ust<STRONG> F</STRONG>ast<STRONG> K</STRONG>eying,
+ a proposed simpler replacement for<A href="#IKE"> IKE.</A></DD>
+<DT><A name="K">K</A></DT>
+<DT><A name="kernel">Kernel</A></DT>
+<DD>The basic part of an operating system (e.g. Linux) which controls
+ the hardware and provides services to all other programs.
+<P>In the Linux release numbering system, an even second digit as in 2.<STRONG>
+2</STRONG>.x indicates a stable or production kernel while an odd number
+ as in 2.<STRONG>3</STRONG>.x indicates an experimental or development
+ kernel. Most users should run a recent kernel version from the
+ production series. The development kernels are primarily for people
+ doing kernel development. Others should consider using development
+ kernels only if they have an urgent need for some feature not yet
+ available in production kernels.</P>
+</DD>
+<DT>Keyed message digest</DT>
+<DD>See<A href="#HMAC"> HMAC</A>.</DD>
+<DT>Key length</DT>
+<DD>see<A href="#brute"> brute force attack</A></DD>
+<DT><A name="KLIPS">KLIPS</A></DT>
+<DD><B>K</B>erne<B>l</B><B> IP</B><B> S</B>ecurity, the<A href="web.html#FreeSWAN">
+ Linux FreeS/WAN</A> project's changes to the<A href="#Linux"> Linux</A>
+ kernel to support the<A href="#IPSEC"> IPsec</A> protocols.</DD>
+<DT><A name="L">L</A></DT>
+<DT><A name="LDAP">LDAP</A></DT>
+<DD><B>L</B>ightweight<B> D</B>irectory<B> A</B>ccess<B> P</B>rotocol,
+ defined in RFCs 1777 and 1778, a method of accessing information stored
+ in directories. LDAP is used by several<A href="#PKI"> PKI</A>
+ implementations, often with X.501 directories and<A href="#X509"> X.509</A>
+ certificates. It may also be used by<A href="#IPSEC"> IPsec</A> to
+ obtain key certifications from those PKIs. This is not yet implemented
+ in<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A>.</DD>
+<DT><A name="LIBDES">LIBDES</A></DT>
+<DD>A publicly available library of<A href="#DES"> DES</A> code, written
+ by Eric Young, which<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A>
+ uses in both<A href="#KLIPS"> KLIPS</A> and<A href="#Pluto"> Pluto</A>.</DD>
+<DT><A name="Linux">Linux</A></DT>
+<DD>A freely available Unix-like operating system based on a kernel
+ originally written for the Intel 386 architecture by (then) student
+ Linus Torvalds. Once his 32-bit kernel was available, the<A href="#GNU">
+ GNU</A> utilities made it a usable system and contributions from many
+ others led to explosive growth.
+<P>Today Linux is a complete Unix replacement available for several CPU
+ architectures -- Intel, DEC/Compaq Alpha, Power PC, both 32-bit SPARC
+ and the 64-bit UltraSPARC, SrongARM, . . . -- with support for multiple
+ CPUs on some architectures.</P>
+<P><A href="web.html#FreeSWAN">Linux FreeS/WAN</A> is intended to run on
+ all CPUs supported by Linux and is known to work on several. See our<A href="compat.html#CPUs">
+ compatibility</A> section for a list.</P>
+</DD>
+<DT><A name="FreeSWAN">Linux FreeS/WAN</A></DT>
+<DD>Our implementation of the<A href="#IPSEC"> IPsec</A> protocols,
+ intended to be freely redistributable source code with<A href="#GPL"> a
+ GNU GPL license</A> and no constraints under US or other<A href="politics.html#exlaw">
+ export laws</A>. Linux FreeS/WAN is intended to interoperate with other<A
+href="#IPSEC"> IPsec</A> implementations. The name is partly taken, with
+ permission, from the<A href="#SWAN"> S/WAN</A> multi-vendor IPsec
+ compatability effort. Linux FreeS/WAN has two major components,<A href="#KLIPS">
+ KLIPS</A> (KerneL IPsec Support) and the<A href="#Pluto"> Pluto</A>
+ daemon which manages the whole thing.
+<P>See our<A href="ipsec.html"> IPsec section</A> for more detail. For
+ the code see our<A href="http://freeswan.org"> primary site</A> or one
+ of the mirror sites on<A href="intro.html#mirrors"> this list</A>.</P>
+</DD>
+<DT><A name="LSM">Linux Security Modules (LSM)</A></DT>
+<DD>a project to create an interface in the Linux kernel that supports
+ plug-in modules for various security policies.
+<P>This allows multiple security projects to take different approaches
+ to security enhancement without tying the kernel down to one particular
+ approach. As I understand the history, several projects were pressing
+ Linus to incorporate their changes, the various sets of changes were
+ incompatible, and his answer was more-or-less &quot;a plague on all your
+ houses; I'll give you an interface, but I won't incorporate anything&quot;.</P>
+<P>It seems to be working. There is a fairly active<A href="http://mail.wirex.com/mailman/listinfo/linux-security-module">
+ LSM mailing list</A>, and several projects are already using the
+ interface.</P>
+</DD>
+<DT>LSM</DT>
+<DD>see<A href="#LSM"> Linux Security Modules</A></DD>
+<DT><A name="M">M</A></DT>
+<DT><A name="list">Mailing list</A></DT>
+<DD>The<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A> project has
+ several public email lists for bug reports and software development
+ discussions. See our document on<A href="mail.html"> mailing lists</A>.</DD>
+<DT><A name="middle">Man-in-the-middle attack</A></DT>
+<DD>An<A href="#active"> active attack</A> in which the attacker
+ impersonates each of the legitimate players in a protocol to the other.
+<P>For example, if<A href="#alicebob"> Alice and Bob</A> are negotiating
+ a key via the<A href="#DH"> Diffie-Hellman</A> key agreement, and are
+ not using<A href="#authentication"> authentication</A> to be certain
+ they are talking to each other, then an attacker able to insert himself
+ in the communication path can deceive both players.</P>
+<P>Call the attacker Mallory. For Bob, he pretends to be Alice. For
+ Alice, he pretends to be Bob. Two keys are then negotiated,
+ Alice-to-Mallory and Bob-to-Mallory. Alice and Bob each think the key
+ they have is Alice-to-Bob.</P>
+<P>A message from Alice to Bob then goes to Mallory who decrypts it,
+ reads it and/or saves a copy, re-encrypts using the Bob-to-Mallory key
+ and sends it along to Bob. Bob decrypts successfully and sends a reply
+ which Mallory decrypts, reads, re-encrypts and forwards to Alice.</P>
+<P>To make this attack effective, Mallory must</P>
+<UL>
+<LI>subvert some part of the network in some way that lets him carry out
+ the deception
+<BR> possible targets: DNS, router, Alice or Bob's machine, mail server,
+ ...</LI>
+<LI>beat any authentication mechanism Alice and Bob use
+<BR> strong authentication defeats the attack entirely; this is why<A href="#IKE">
+ IKE</A> requires authentication</LI>
+<LI>work in real time, delivering messages without introducing a delay
+ large enough to alert the victims
+<BR> not hard if Alice and Bob are using email; quite difficult in some
+ situations.</LI>
+</UL>
+<P>If he manages it, however, it is devastating. He not only gets to
+ read all the messages; he can alter messages, inject his own, forge
+ anything he likes, . . . In fact, he controls the communication
+ completely.</P>
+</DD>
+<DT><A name="mandatory">mandatory access control</A></DT>
+<DD>access control mechanisims which are not settable by the user (see<A href="#discretionary">
+ discretionary access control</A>), but are enforced by the system.
+<P>For example, a document labelled &quot;secret, zebra&quot; might be readable
+ only by someone with secret clearance working on Project Zebra.
+ Ideally, the system will prevent any transfer outside those boundaries.
+ For example, even if you can read it, you should not be able to e-mail
+ it (unless the recipient is appropriately cleared) or print it (unless
+ certain printers are authorised for that classification).</P>
+<P>Mandatory access control is a required feature for some levels of<A href="#rainbow">
+ Rainbow Book</A> or<A href="#cc"> Common Criteria</A> classification,
+ but has not been widely used outside the military and government. There
+ is a good discussion of the issues in Anderson's<A href="biblio.html#anderson">
+ Security Engineering</A>.</P>
+<P>The<A href="#SElinux"> Security Enhanced Linux</A> project is adding
+ mandatory access control to Linux.</P>
+</DD>
+<DT><A name="manual">Manual keying</A></DT>
+<DD>An IPsec mode in which the keys are provided by the administrator.
+ In FreeS/WAN, they are stored in /etc/ipsec.conf. The alternative,<A href="ipsec.html#auto">
+ automatic keying</A>, is preferred in most cases. See this<A href="adv_config.html#man-auto">
+ discussion</A>.</DD>
+<DT><A name="MD4">MD4</A></DT>
+<DD><A href="#digest">Message Digest Algorithm</A> Four from Ron Rivest
+ of<A href="#RSAco"> RSA</A>. MD4 was widely used a few years ago, but
+ is now considered obsolete. It has been replaced by its descendants<A href="#MD5">
+ MD5</A> and<A href="#SHA"> SHA</A>.</DD>
+<DT><A name="MD5">MD5</A></DT>
+<DD><A href="#digest">Message Digest Algorithm</A> Five from Ron Rivest
+ of<A href="#RSAco"> RSA</A>, an improved variant of his<A href="#MD4">
+ MD4</A>. Like MD4, it produces a 128-bit hash. For details see RFC
+ 1321.
+<P>MD5 is one of two message digest algorithms available in IPsec. The
+ other is<A href="#SHA"> SHA</A>. SHA produces a longer hash and is
+ therefore more resistant to<A href="#birthday"> birthday attacks</A>,
+ but this is not a concern for IPsec. The<A href="#HMAC"> HMAC</A>
+ method used in IPsec is secure even if the underlying hash is not
+ particularly strong against this attack.</P>
+<P>Hans Dobbertin found a weakness in MD5, and people often ask whether
+ this means MD5 is unsafe for IPsec. It doesn't. The IPsec RFCs discuss
+ Dobbertin's attack and conclude that it does not affect MD5 as used for
+ HMAC in IPsec.</P>
+</DD>
+<DT><A name="meet">Meet-in-the-middle attack</A></DT>
+<DD>A divide-and-conquer attack which breaks a cipher into two parts,
+ works against each separately, and compares results. Probably the best
+ known example is an attack on double DES. This applies in principle to
+ any pair of block ciphers, e.g. to an encryption system using, say,
+ CAST-128 and Blowfish, but we will describe it for double DES.
+<P>Double DES encryption and decryption can be written:</P>
+<PRE> C = E(k2,E(k1,P))
+ P = D(k1,D(k2,C))</PRE>
+<P>Where C is ciphertext, P is plaintext, E is encryption, D is
+ decryption, k1 is one key, and k2 is the other key. If we know a P, C
+ pair, we can try and find the keys with a brute force attack, trying
+ all possible k1, k2 pairs. Since each key is 56 bits, there are 2<SUP>
+112</SUP> such pairs and this attack is painfully inefficient.</P>
+<P>The meet-in-the middle attack re-writes the equations to calculate a
+ middle value M:</P>
+<PRE> M = E(k1,P)
+ M = D(k2,C)</PRE>
+<P>Now we can try some large number of D(k2,C) decryptions with various
+ values of k2 and store the results in a table. Then start doing E(k1,P)
+ encryptions, checking each result to see if it is in the table.</P>
+<P>With enough table space, this breaks double DES with<NOBR> 2<SUP>56</SUP>
+ + 2<SUP>56</SUP> = 2<SUP>57</SUP>work. Against triple DES, you need<NOBR>
+ 2<SUP>56</SUP> + 2<SUP>112</SUP> ~= 2<SUP>112</SUP>.</P>
+<P>The memory requirements for such attacks can be prohibitive, but
+ there is a whole body of research literature on methods of reducing
+ them.</P>
+</DD>
+<DT><A name="digest">Message Digest Algorithm</A></DT>
+<DD>An algorithm which takes a message as input and produces a hash or
+ digest of it, a fixed-length set of bits which depend on the message
+ contents in some highly complex manner. Design criteria include making
+ it extremely difficult for anyone to counterfeit a digest or to change
+ a message without altering its digest. One essential property is<A href="#collision">
+ collision resistance</A>. The main applications are in message<A href="#authentication">
+ authentication</A> and<A href="#signature"> digital signature</A>
+ schemes. Widely used algorithms include<A href="#MD5"> MD5</A> and<A href="#SHA">
+ SHA</A>. In IPsec, message digests are used for<A href="#HMAC"> HMAC</A>
+ authentication of packets.</DD>
+<DT><A name="MTU">MTU</A></DT>
+<DD><STRONG>M</STRONG>aximum<STRONG> T</STRONG>ransmission<STRONG> U</STRONG>
+nit, the largest size of packet that can be sent over a link. This is
+ determined by the underlying network, but must be taken account of at
+ the IP level.
+<P>IP packets, which can be up to 64K bytes each, must be packaged into
+ lower-level packets of the appropriate size for the underlying
+ network(s) and re-assembled on the other end. When a packet must pass
+ over multiple networks, each with its own MTU, and many of the MTUs are
+ unknown to the sender, this becomes a fairly complex problem. See<A href="#pathMTU">
+ path MTU discovery</A> for details.</P>
+<P>Often the MTU is a few hundred bytes on serial links and 1500 on
+ Ethernet. There are, however, serial link protocols which use a larger
+ MTU to avoid fragmentation at the ethernet/serial boundary, and newer
+ (especially gigabit) Ethernet networks sometimes support much larger
+ packets because these are more efficient in some applications.</P>
+</DD>
+<DT><A name="N">N</A></DT>
+<DT><A name="NAI">NAI</A></DT>
+<DD><A href="http://www.nai.com">Network Associates</A>, a conglomerate
+ formed from<A href="#PGPI"> PGP Inc.</A>, TIS (Trusted Information
+ Systems, a firewall vendor) and McAfee anti-virus products. Among other
+ things, they offer an IPsec-based VPN product.</DD>
+<DT><A name="NAT.gloss">NAT</A></DT>
+<DD><B>N</B>etwork<B> A</B>ddress<B> T</B>ranslation, a process by which
+ firewall machines may change the addresses on packets as they go
+ through. For discussion, see our<A href="background.html#nat.background">
+ background</A> section.</DD>
+<DT><A name="NIST">NIST</A></DT>
+<DD>The US<A href="http://www.nist.gov"> National Institute of Standards
+ and Technology</A>, responsible for<A href="#FIPS"> FIPS standards</A>
+ including<A href="#DES"> DES</A> and its replacement,<A href="#AES">
+ AES</A>.</DD>
+<DT><A name="nonce">Nonce</A></DT>
+<DD>A<A href="#random"> random</A> value used in an<A href="#authentication">
+ authentication</A> protocol.</DD>
+<DT></DT>
+<DT><A name="non-routable">Non-routable IP address</A></DT>
+<DD>An IP address not normally allowed in the &quot;to&quot; or &quot;from&quot; IP address
+ field header of IP packets.
+<P>Almost invariably, the phrase &quot;non-routable address&quot; means one of the
+ addresses reserved by RFC 1918 for private networks:</P>
+<UL>
+<LI>10.anything</LI>
+<LI>172.x.anything with 16 &lt;= x &lt;= 31</LI>
+<LI>192.168.anything</LI>
+</UL>
+<P>These addresses are commonly used on private networks, e.g. behind a
+ Linux machines doing<A href="#masq"> IP masquerade</A>. Machines within
+ the private network can address each other with these addresses. All
+ packets going outside that network, however, have these addresses
+ replaced before they reach the Internet.</P>
+<P>If any packets using these addresses do leak out, they do not go far.
+ Most routers automatically discard all such packets.</P>
+<P>Various other addresses -- the 127.0.0.0/8 block reserved for local
+ use, 0.0.0.0, various broadcast and network addresses -- cannot be
+ routed over the Internet, but are not normally included in the meaning
+ when the phrase &quot;non-routable address&quot; is used.</P>
+</DD>
+<DT><A name="NSA">NSA</A></DT>
+<DD>The US<A href="http://www.nsa.gov"> National Security Agency</A>,
+ the American organisation for<A href="#SIGINT"> signals intelligence</A>
+, the protection of US government messages and the interception and
+ analysis of other messages. For details, see Bamford's<A href="biblio.html#puzzle">
+ &quot;The Puzzle Palace&quot;</A>.
+<P>Some<A href="http://www.gwu.edu/~nsarchiv/NSAEBB/NSAEBB23/index.html">
+ history of NSA</A> documents were declassified in response to a FOIA
+ (Freedom of Information Act) request.</P>
+</DD>
+<DT><A name="O">O</A></DT>
+<DT><A name="oakley">Oakley</A></DT>
+<DD>A key determination protocol, defined in RFC 2412.</DD>
+<DT>Oakley groups</DT>
+<DD>The groups used as the basis of<A href="#DH"> Diffie-Hellman</A> key
+ exchange in the Oakley protocol, and in<A href="#IKE"> IKE</A>. Four
+ were defined in the original RFC, and a fifth has been<A href="http://www.lounge.org/ike_doi_errata.html">
+ added since</A>.
+<P>Linux FreeS/WAN currently supports the three groups based on finite
+ fields modulo a prime (Groups 1, 2 and 5) and does not support the
+ elliptic curve groups (3 and 4). For a description of the difference of
+ the types, see<A href="#dlog"> discrete logarithms</A>.</P>
+</DD>
+<DT><A name="OTP">One time pad</A></DT>
+<DD>A cipher in which the key is:
+<UL>
+<LI>as long as the total set of messages to be enciphered</LI>
+<LI>absolutely<A href="#random"> random</A></LI>
+<LI>never re-used</LI>
+</UL>
+<P>Given those three conditions, it can easily be proved that the cipher
+ is perfectly secure, in the sense that an attacker with intercepted
+ message in hand has no better chance of guessing the message than an
+ attacker who has not intercepted the message and only knows the message
+ length. No such proof exists for any other cipher.</P>
+<P>There are, however, several problems with this &quot;perfect&quot; cipher.</P>
+<P>First, it is<STRONG> wildly impractical</STRONG> for most
+ applications. Key management is at best difficult, often completely
+ impossible.</P>
+<P>Second, it is<STRONG> extremely fragile</STRONG>. Small changes which
+ violate the conditions listed above do not just weaken the cipher
+ liitle. Quite often they destroy its security completely.</P>
+<UL>
+<LI>Re-using the pad weakens the cipher to the point where it can be
+ broken with pencil and paper. With a computer, the attack is trivially
+ easy.</LI>
+<LI>Using<EM> anything</EM> less than truly<A href="#random"> random</A>
+ numbers<EM> completely</EM> invalidates the security proof.</LI>
+<LI>In particular, using computer-generated pseudo-random numbers may
+ give an extremely weak cipher. It might also produce a good stream
+ cipher, if the pseudo-random generator is both well-designed and
+ properely seeded.</LI>
+</UL>
+<P>Marketing claims about the &quot;unbreakable&quot; security of various products
+ which somewhat resemble one-time pads are common. Such claims are one
+ of the surest signs of cryptographic<A href="#snake"> snake oil</A>;
+ most systems marketed with such claims are worthless.</P>
+<P>Finally, even if the system is implemented and used correctly, it is<STRONG>
+ highly vulnerable to a substitution attack</STRONG>. If an attacker
+ knows some plaintext and has an intercepted message, he can discover
+ the pad.</P>
+<UL>
+<LI>This does not matter if the attacker is just a<A href="#passive">
+ passive</A> eavesdropper. It gives him no plaintext he didn't already
+ know and we don't care that he learns a pad which we will never re-use.</LI>
+<LI>However, an<A href="#active"> active</A> attacker who knows the
+ plaintext can recover the pad, then use it to encode with whatever he
+ chooses. If he can get his version delivered instead of yours, this may
+ be a disaster. If you send &quot;attack at dawn&quot;, the delivered message can
+ be anything the same length -- perhaps &quot;retreat to east&quot; or &quot;shoot
+ generals&quot;.</LI>
+<LI>An active attacker with only a reasonable guess at the plaintext can
+ try the same attack. If the guess is correct, this works and the
+ attacker's bogus message is delivered. If the guess is wrong, a garbled
+ message is delivered.</LI>
+</UL>
+<P>In general then, despite its theoretical perfection, the one-time-pad
+ has very limited practical application.</P>
+<P>See also the<A href="http://pubweb.nfr.net/~mjr/pubs/otpfaq/"> one
+ time pad FAQ</A>.</P>
+</DD>
+<DT><A name="carpediem">Opportunistic encryption (OE)</A></DT>
+<DD>A situation in which any two IPsec-aware machines can secure their
+ communications, without a pre-shared secret and without a common<A href="#PKI">
+ PKI</A> or previous exchange of public keys. This is one of the goals
+ of the Linux FreeS/WAN project, discussed in our<A href="intro.html#goals">
+ introduction</A> section.
+<P>Setting up for opportunistic encryption is described in our<A href="quickstart.html#quickstart">
+ quickstart</A> document.</P>
+</DD>
+<DT><A name="responder">Opportunistic responder</A></DT>
+<DD>A host which accepts, but does not initiate, requests for<A HREF="#carpediem">
+ opportunistic encryption</A> (OE). An opportunistic responder has
+ enabled OE in its<A HREF="#passive.OE"> passive</A> form (pOE) only. A
+ web server or file server may be usefully set up as an opportunistic
+ responder.
+<P>Configuring passive OE is described in our<A href="policygroups.html#policygroups">
+ policy groups</A> document.</P>
+</DD>
+<DT><A name="orange">Orange book</A></DT>
+<DD>the most basic and best known of the US government's<A href="#rainbow">
+ Rainbow Book</A> series of computer security standards.</DD>
+<DT><A name="P">P</A></DT>
+<DT><A name="P1363">P1363 standard</A></DT>
+<DD>An<A href="#IEEE"> IEEE</A> standard for public key cryptography.<A href="http://grouper.ieee.org/groups/1363">
+ Web page</A>.</DD>
+<DT><A name="pOE">pOE</A></DT>
+<DD>See<A href="#passive.OE"> Passive opportunistic encryption</A>.</DD>
+<DT><A name="passive">Passive attack</A></DT>
+<DD>An attack in which the attacker only eavesdrops and attempts to
+ analyse intercepted messages, as opposed to an<A href="#active"> active
+ attack</A> in which he diverts messages or generates his own.</DD>
+<DT><A name="passive.OE">Passive opportunistic encryption (pOE)</A></DT>
+<DD>A form of<A HREF="#carpediem"> opportunistic encryption</A> (OE) in
+ which the host will accept opportunistic connection requests, but will
+ not initiate such requests. A host which runs OE in its passive form
+ only is known as an<A HREF="#responder"> opportunistic responder</A>.
+<P>Configuring passive OE is described in our<A href="policygroups.html#policygroups">
+ policy groups</A> document.</P>
+</DD>
+<DT><A name="pathMTU">Path MTU discovery</A></DT>
+<DD>The process of discovering the largest packet size which all links
+ on a path can handle without fragmentation -- that is, without any
+ router having to break the packet up into smaller pieces to match the<A href="#MTU">
+ MTU</A> of its outgoing link.
+<P>This is done as follows:</P>
+<UL>
+<LI>originator sends the largest packets allowed by<A href="#MTU"> MTU</A>
+ of the first link, setting the DF (<STRONG>d</STRONG>on't<STRONG> f</STRONG>
+ragment) bit in the packet header</LI>
+<LI>any router which cannot send the packet on (outgoing MTU is too
+ small for it, and DF prevents fragmenting it to match) sends back an<A href="#ICMP.gloss">
+ ICMP</A> packet reporting the problem</LI>
+<LI>originator looks at ICMP message and tries a smaller size</LI>
+<LI>eventually, you settle on a size that can pass all routers</LI>
+<LI>thereafter, originator just sends that size and no-one has to
+ fragment</LI>
+</UL>
+<P>Since this requires co-operation of many systems, and since the next
+ packet may travel a different path, this is one of the trickier areas
+ of IP programming. Bugs that have shown up over the years have
+ included:</P>
+<UL>
+<LI>malformed ICMP messages</LI>
+<LI>hosts that ignore or mishandle these ICMP messages</LI>
+<LI>firewalls blocking the ICMP messages so host does not see them</LI>
+</UL>
+<P>Since IPsec adds a header, it increases packet size and may require
+ fragmentation even where incoming and outgoing MTU are equal.</P>
+</DD>
+<DT><A name="PFS">Perfect forward secrecy (PFS)</A></DT>
+<DD>A property of systems such as<A href="#DH"> Diffie-Hellman</A> key
+ exchange which use a long-term key (such as the shared secret in IKE)
+ and generate short-term keys as required. If an attacker who acquires
+ the long-term key<EM> provably</EM> can
+<UL>
+<LI><EM>neither</EM> read previous messages which he may have archived</LI>
+<LI><EM>nor</EM> read future messages without performing additional
+ successful attacks</LI>
+</UL>
+<P>then the system has PFS. The attacker needs the short-term keys in
+ order to read the trafiic and merely having the long-term key does not
+ allow him to infer those. Of course, it may allow him to conduct
+ another attack (such as<A href="#middle"> man-in-the-middle</A>) which
+ gives him some short-term keys, but he does not automatically get them
+ just by acquiring the long-term key.</P>
+<P>See also<A href="http://sandelman.ottawa.on.ca/ipsec/1996/08/msg00123.html">
+ Phil Karn's definition</A>.</P>
+</DD>
+<DT>PFS</DT>
+<DD>see Perfect Forward Secrecy</DD>
+<DT><A name="PGP">PGP</A></DT>
+<DD><B>P</B>retty<B> G</B>ood<B> P</B>rivacy, a personal encryption
+ system for email based on public key technology, written by Phil
+ Zimmerman.
+<P>The 2.xx versions of PGP used the<A href="#RSA"> RSA</A> public key
+ algorithm and used<A href="#IDEA"> IDEA</A> as the symmetric cipher.
+ These versions are described in RFC 1991 and in<A href="#PGP">
+ Garfinkel's book</A>. Since version 5, the products from<A href="#PGPI">
+ PGP Inc</A>. have used<A href="#DH"> Diffie-Hellman</A> public key
+ methods and<A href="#CAST128"> CAST-128</A> symmetric encryption. These
+ can verify signatures from the 2.xx versions, but cannot exchange
+ encryted messages with them.</P>
+<P>An<A href="mail.html#IETF"> IETF</A> working group has issued RFC
+ 2440 for an &quot;Open PGP&quot; standard, similar to the 5.x versions. PGP Inc.
+ staff were among the authors. A free<A href="#GPG"> Gnu Privacy Guard</A>
+ based on that standard is now available.</P>
+<P>For more information on PGP, including how to obtain it, see our
+ cryptography<A href="web.html#tools"> links</A>.</P>
+</DD>
+<DT><A name="PGPI">PGP Inc.</A></DT>
+<DD>A company founded by Zimmerman, the author of<A href="#PGP"> PGP</A>
+, now a division of<A href="#NAI"> NAI</A>. See the<A href="http://www.pgp.com">
+ corporate website</A>. Zimmerman left in 2001, and early in 2002 NAI
+ announced that they would no longer sell PGP..
+<P>Versions 6.5 and later of the PGP product include PGPnet, an IPsec
+ client for Macintosh or for Windows 95/98/NT. See our<A href="interop.html#pgpnet">
+ interoperation documen</A>t.</P>
+</DD>
+<DT><A name="photuris">Photuris</A></DT>
+<DD>Another key negotiation protocol, an alternative to<A href="#IKE">
+ IKE</A>, described in RFCs 2522 and 2523.</DD>
+<DT><A name="PPP">PPP</A></DT>
+<DD><B>P</B>oint-to-<B>P</B>oint<B> P</B>rotocol, originally a method of
+ connecting over modems or serial lines, but see also PPPoE.</DD>
+<DT><A name="PPPoE">PPPoE</A></DT>
+<DD><B>PPP</B><B> o</B>ver<B> E</B>thernet, a somewhat odd protocol that
+ makes Ethernet look like a point-to-point serial link. It is widely
+ used for cable or ADSL Internet services, apparently mainly because it
+ lets the providers use access control and address assignmment
+ mechanisms developed for dialup networks.<A href="http://www.roaringpenguin.com">
+ Roaring Penguin</A> provide a widely used Linux implementation.</DD>
+<DT><A name="PPTP">PPTP</A></DT>
+<DD><B>P</B>oint-to-<B>P</B>oint<B> T</B>unneling<B> P</B>rotocol, used
+ in some Microsoft VPN implementations. Papers discussing weaknesses in
+ it are on<A href="http://www.counterpane.com/publish.html">
+ counterpane.com</A>. It is now largely obsolete, replaced by L2TP.</DD>
+<DT><A name="PKI">PKI</A></DT>
+<DD><B>P</B>ublic<B> K</B>ey<B> I</B>nfrastructure, the things an
+ organisation or community needs to set up in order to make<A href="#public">
+ public key</A> cryptographic technology a standard part of their
+ operating procedures.
+<P>There are several PKI products on the market. Typically they use a
+ hierarchy of<A href="#CA"> Certification Authorities (CAs)</A>. Often
+ they use<A href="#LDAP"> LDAP</A> access to<A href="#X509"> X.509</A>
+ directories to implement this.</P>
+<P>See<A href="#web"> Web of Trust</A> for a different sort of
+ infrastructure.</P>
+</DD>
+<DT><A name="PKIX">PKIX</A></DT>
+<DD><B>PKI</B> e<B>X</B>change, an<A href="mail.html#IETF"> IETF</A>
+ standard that allows<A href="#PKI"> PKI</A>s to talk to each other.
+<P>This is required, for example, when users of a corporate PKI need to
+ communicate with people at client, supplier or government
+ organisations, any of which may have a different PKI in place. I should
+ be able to talk to you securely whenever:</P>
+<UL>
+<LI>your organisation and mine each have a PKI in place</LI>
+<LI>you and I are each set up to use those PKIs</LI>
+<LI>the two PKIs speak PKIX</LI>
+<LI>the configuration allows the conversation</LI>
+</UL>
+<P>At time of writing (March 1999), this is not yet widely implemented
+ but is under quite active development by several groups.</P>
+</DD>
+<DT><A name="plaintext">Plaintext</A></DT>
+<DD>The unencrypted input to a cipher, as opposed to the encrypted<A href="#ciphertext">
+ ciphertext</A> output.</DD>
+<DT><A name="Pluto">Pluto</A></DT>
+<DD>The<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A> daemon which
+ handles key exchange via the<A href="#IKE"> IKE</A> protocol,
+ connection negotiation, and other higher-level tasks. Pluto calls the<A href="#KLIPS">
+ KLIPS</A> kernel code as required. For details, see the manual page
+ ipsec_pluto(8).</DD>
+<DT><A name="public">Public Key Cryptography</A></DT>
+<DD>In public key cryptography, keys are created in matched pairs.
+ Encrypt with one half of a pair and only the matching other half can
+ decrypt it. This contrasts with<A href="#symmetric"> symmetric or
+ secret key cryptography</A> in which a single key known to both parties
+ is used for both encryption and decryption.
+<P>One half of each pair, called the public key, is made public. The
+ other half, called the private key, is kept secret. Messages can then
+ be sent by anyone who knows the public key to the holder of the private
+ key. Encrypt with the public key and you know that only someone with
+ the matching private key can decrypt.</P>
+<P>Public key techniques can be used to create<A href="#signature">
+ digital signatures</A> and to deal with key management issues, perhaps
+ the hardest part of effective deployment of<A href="#symmetric">
+ symmetric ciphers</A>. The resulting<A href="#hybrid"> hybrid
+ cryptosystems</A> use public key methods to manage keys for symmetric
+ ciphers.</P>
+<P>Many organisations are currently creating<A href="#PKI"> PKIs, public
+ key infrastructures</A> to make these benefits widely available.</P>
+</DD>
+<DT>Public Key Infrastructure</DT>
+<DD>see<A href="#PKI"> PKI</A></DD>
+<DT><A name="Q">Q</A></DT>
+<DT><A name="R">R</A></DT>
+<DT><A name="rainbow">Rainbow books</A></DT>
+<DD>A set of US government standards for evaluation of &quot;trusted computer
+ systems&quot;, of which the best known was the<A href="#orange"> Orange Book</A>
+. One fairly often hears references to &quot;C2 security&quot; or a product
+ &quot;evaluated at B1&quot;. The Rainbow books define the standards referred to
+ in those comments.
+<P>See this<A href="http://www.fas.org/irp/nsa/rainbow.htm"> reference
+ page</A>.</P>
+<P>The Rainbow books are now mainly obsolete, replaced by the
+ international<A href="#cc"> Common Criteria</A> standards.</P>
+</DD>
+<DT><A name="random">Random</A></DT>
+<DD>A remarkably tricky term, far too much so for me to attempt a
+ definition here. Quite a few cryptosystems have been broken via attacks
+ on weak random number generators, even when the rest of the system was
+ sound.
+<P>See<A href="http://nis.nsf.net/internet/documents/rfc/rfc1750.txt">
+ RFC 1750</A> for the theory.</P>
+<P>See the manual pages for<A href="manpage.d/ipsec_ranbits.8.html">
+ ipsec_ranbits(8)</A> and ipsec_prng(3) for more on FreeS/WAN's use of
+ randomness. Both depend on the random(4) device driver..</P>
+<P>A couple of years ago, there was extensive mailing list discussion
+ (archived<A href="http://www.openpgp.net/random/index.html"> here</A>
+)of Linux /dev/random and FreeS/WAN. Since then, the design of the
+ random(4) driver has changed considerably. Linux 2.4 kernels have the
+ new driver..</P>
+</DD>
+<DT>Raptor</DT>
+<DD>A firewall product for Windows NT offerring IPsec-based VPN
+ services. Linux FreeS/WAN interoperates with Raptor; see our<A href="interop.html#Raptor">
+ interop</A> document for details. Raptor have recently merged with
+ Axent.</DD>
+<DT><A name="RC4">RC4</A></DT>
+<DD><B>R</B>ivest<B> C</B>ipher four, designed by Ron Rivest of<A href="#RSAco">
+ RSA</A> and widely used. Believed highly secure with adequate key
+ length, but often implemented with inadequate key length to comply with
+ export restrictions.</DD>
+<DT><A name="RC6">RC6</A></DT>
+<DD><B>R</B>ivest<B> C</B>ipher six,<A href="#RSAco"> RSA</A>'s<A href="#AES">
+ AES</A> candidate cipher.</DD>
+<DT><A name="replay">Replay attack</A></DT>
+<DD>An attack in which the attacker records data and later replays it in
+ an attempt to deceive the recipient.</DD>
+<DT><A name="reverse">Reverse map</A></DT>
+<DD>In<A href="ipsec.html#DNS"> DNS</A>, a table where IP addresses can
+ be used as the key for lookups which return a system name and/or other
+ information.</DD>
+<DT>RFC</DT>
+<DD><B>R</B>equest<B> F</B>or<B> C</B>omments, an Internet document.
+ Some RFCs are just informative. Others are standards.
+<P>Our list of<A href="#IPSEC"> IPsec</A> and other security-related
+ RFCs is<A href="rfc.html#RFC"> here</A>, along with information on
+ methods of obtaining them.</P>
+</DD>
+<DT><A name="rijndael">Rijndael</A></DT>
+<DD>a<A href="#block"> block cipher</A> designed by two Belgian
+ cryptographers, winner of the US government's<A href="#AES"> AES</A>
+ contest to pick a replacement for<A href="#DES"> DES</A>. See the<A href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael">
+ Rijndael home page</A>.</DD>
+<DT><A name="RIPEMD">RIPEMD</A></DT>
+<DD>A<A href="#digest"> message digest</A> algorithm. The current
+ version is RIPEMD-160 which gives a 160-bit hash.</DD>
+<DT><A name="rootCA">Root CA</A></DT>
+<DD>The top level<A href="#CA"> Certification Authority</A> in a
+ hierachy of such authorities.</DD>
+<DT><A name="routable">Routable IP address</A></DT>
+<DD>Most IP addresses can be used as &quot;to&quot; and &quot;from&quot; addresses in packet
+ headers. These are the routable addresses; we expect routing to be
+ possible for them. If we send a packet to one of them, we expect (in
+ most cases; there are various complications) that it will be delivered
+ if the address is in use and will cause an<A href="#ICMP.gloss"> ICMP</A>
+ error packet to come back to us if not.
+<P>There are also several classes of<A href="#non-routable">
+ non-routable</A> IP addresses.</P>
+</DD>
+<DT><A name="RSA">RSA algorithm</A></DT>
+<DD><B>R</B>ivest<B> S</B>hamir<B> A</B>dleman<A href="#public"> public
+ key</A> algorithm, named for its three inventors. It is widely used and
+ likely to become moreso since it became free of patent encumbrances in
+ September 2000.
+<P>RSA can be used to provide either<A href="#encryption"> encryption</A>
+ or<A href="#signature"> digital signatures</A>. In IPsec, it is used
+ only for signatures. These provide gateway-to-gateway<A href="#authentication">
+ authentication</A> for<A href="#IKE"> IKE</A> negotiations.</P>
+<P>For a full explanation of the algorithm, consult one of the standard
+ references such as<A href="biblio.html#schneier"> Applied Cryptography</A>
+. A simple explanation is:</P>
+<P>The great 17th century French mathematician<A href="http://www-groups.dcs.st-andrews.ac.uk/~history/Mathematicians/Fermat.html">
+ Fermat</A> proved that,</P>
+<P>for any prime p and number x, 0 &lt;= x &lt; p:</P>
+<PRE> x^p == x modulo p
+ x^(p-1) == 1 modulo p, non-zero x
+ </PRE>
+<P>From this it follows that if we have a pair of primes p, q and two
+ numbers e, d such that:</P>
+<PRE> ed == 1 modulo lcm( p-1, q-1)
+ </PRE>
+ where lcm() is least common multiple, then
+<BR> for all x, 0 &lt;= x &lt; pq:
+<PRE> x^ed == x modulo pq
+ </PRE>
+<P>So we construct such as set of numbers p, q, e, d and publish the
+ product N=pq and e as the public key. Using c for<A href="#ciphertext">
+ ciphertext</A> and i for the input<A href="#plaintext"> plaintext</A>,
+ encryption is then:</P>
+<PRE> c = i^e modulo N
+ </PRE>
+<P>An attacker cannot deduce i from the cyphertext c, short of either
+ factoring N or solving the<A href="#dlog"> discrete logarithm</A>
+ problem for this field. If p, q are large primes (hundreds or thousands
+ of bits) no efficient solution to either problem is known.</P>
+<P>The receiver, knowing the private key (N and d), can readily recover
+ the plaintext p since:</P>
+<PRE> c^d == (i^e)^d modulo N
+ == i^ed modulo N
+ == i modulo N
+ </PRE>
+<P>This gives an effective public key technique, with only a couple of
+ problems. It uses a good deal of computer time, since calculations with
+ large integers are not cheap, and there is no proof it is necessarily
+ secure since no-one has proven either factoring or discrete log cannot
+ be done efficiently. Quite a few good mathematicians have tried both
+ problems, and no-one has announced success, but there is no proof they
+ are insoluble.</P>
+</DD>
+<DT><A name="RSAco">RSA Data Security</A></DT>
+<DD>A company founded by the inventors of the<A href="#RSA"> RSA</A>
+ public key algorithm.</DD>
+<DT><A name="S">S</A></DT>
+<DT><A name="SA">SA</A></DT>
+<DD><B>S</B>ecurity<B> A</B>ssociation, the channel negotiated by the
+ higher levels of an<A href="#IPSEC"> IPsec</A> implementation (<A href="#IKE">
+IKE</A>) and used by the lower (<A href="#ESP">ESP</A> and<A href="#AH">
+ AH</A>). SAs are unidirectional; you need a pair of them for two-way
+ communication.
+<P>An SA is defined by three things -- the destination, the protocol (<A href="#AH">
+AH</A> or<A href="#ESP">ESP</A>) and the<A href="SPI"> SPI</A>, security
+ parameters index. It is used as an index to look up other things such
+ as session keys and intialisation vectors.</P>
+<P>For more detail, see our section on<A href="ipsec.html"> IPsec</A>
+ and/or RFC 2401.</P>
+</DD>
+<DT><A name="SElinux">SE Linux</A></DT>
+<DD><STRONG>S</STRONG>ecurity<STRONG> E</STRONG>nhanced Linux, an<A href="#NSA">
+ NSA</A>-funded project to add<A href="#mandatory"> mandatory access
+ control</A> to Linux. See the<A href="http://www.nsa.gov/selinux">
+ project home page</A>.
+<P>According to their web pages, this work will include extending
+ mandatory access controls to IPsec tunnels.</P>
+<P>Recent versions of SE Linux code use the<A href="#LSM"> Linux
+ Security Module</A> interface.</P>
+</DD>
+<DT><A name="SDNS">Secure DNS</A></DT>
+<DD>A version of the<A href="ipsec.html#DNS"> DNS or Domain Name Service</A>
+ enhanced with authentication services. This is being designed by the<A href="mail.html#IETF">
+ IETF</A> DNS security<A href="http://www.ietf.org/ids.by.wg/dnssec.html">
+ working group</A>. Check the<A href="http://www.isc.org/bind.html">
+ Internet Software Consortium</A> for information on implementation
+ progress and for the latest version of<A href="#BIND"> BIND</A>.
+ Another site has<A href="http://www.toad.com/~dnssec"> more information</A>
+.
+<P><A href="#IPSEC">IPsec</A> can use this plus<A href="#DH">
+ Diffie-Hellman key exchange</A> to bootstrap itself. This allows<A href="#carpediem">
+ opportunistic encryption</A>. Any pair of machines which can
+ authenticate each other via DNS can communicate securely, without
+ either a pre-existing shared secret or a shared<A href="#PKI"> PKI</A>.</P>
+</DD>
+<DT>Secret key cryptography</DT>
+<DD>See<A href="#symmetric"> symmetric cryptography</A></DD>
+<DT>Security Association</DT>
+<DD>see<A href="#SA"> SA</A></DD>
+<DT>Security Enhanced Linux</DT>
+<DD>see<A href="#SElinux"> SE Linux</A></DD>
+<DT><A name="sequence">Sequence number</A></DT>
+<DD>A number added to a packet or message which indicates its position
+ in a sequence of packets or messages. This provides some security
+ against<A href="#replay"> replay attacks</A>.
+<P>For<A href="ipsec.html#auto"> automatic keying</A> mode, the<A href="#IPSEC">
+ IPsec</A> RFCs require that the sender generate sequence numbers for
+ each packet, but leave it optional whether the receiver does anything
+ with them.</P>
+</DD>
+<DT><A name="SHA">SHA</A></DT>
+<DT>SHA-1</DT>
+<DD><B>S</B>ecure<B> H</B>ash<B> A</B>lgorithm, a<A href="#digest">
+ message digest algorithm</A> developed by the<A href="#NSA"> NSA</A>
+ for use in the Digital Signature standard,<A href="#FIPS"> FIPS</A>
+ number 186 from<A href="#NIST"> NIST</A>. SHA is an improved variant of<A
+href="#MD4"> MD4</A> producing a 160-bit hash.
+<P>SHA is one of two message digest algorithms available in IPsec. The
+ other is<A href="#MD5"> MD5</A>. Some people do not trust SHA because
+ it was developed by the<A href="#NSA"> NSA</A>. There is, as far as we
+ know, no cryptographic evidence that SHA is untrustworthy, but this
+ does not prevent that view from being strongly held.</P>
+<P>The NSA made one small change after the release of the original SHA.
+ They did not give reasons. Iit may be a defense against some attack
+ they found and do not wish to disclose. Technically the modified
+ algorithm should be called SHA-1, but since it has replaced the
+ original algorithm in nearly all applications, it is generally just
+ referred to as SHA..</P>
+</DD>
+<DT><A name="SHA-256">SHA-256</A></DT>
+<DT>SHA-384</DT>
+<DT>SHA-512</DT>
+<DD>Newer variants of SHA designed to match the strength of the 128, 192
+ and 256-bit keys of<A href="#AES"> AES</A>. The work to break an
+ encryption algorithm's strength by<A href="#brute"> brute force</A> is
+ 2
+<!--math xmlns="http://www.w3.org/1998/Math/MathML"-->
+
+<!--msup-->
+
+<!--mi-->
+ keylength</(null)></(null)></(null)> operations but a<A href="birthday">
+ birthday attack</A> on a hash needs only 2
+<!--math xmlns="http://www.w3.org/1998/Math/MathML"-->
+
+<!--msup-->
+
+<!--mrow-->
+
+<!--mi-->
+ hashlength</(null)>
+<!--mo-->
+ /</(null)>
+<!--mn-->
+
+ 2</(null)></(null)></(null)></(null)> , so as a general rule you need a
+ hash twice the size of the key to get similar strength. SHA-256,
+ SHA-384 and SHA-512 are designed to match the 128, 192 and 256-bit key
+ sizes of AES, respectively.</DD>
+<DT><A name="SIGINT">Signals intelligence (SIGINT)</A></DT>
+<DD>Activities of government agencies from various nations aimed at
+ protecting their own communications and reading those of others.
+ Cryptography, cryptanalysis, wiretapping, interception and monitoring
+ of various sorts of signals. The players include the American<A href="#NSA">
+ NSA</A>, British<A href="#GCHQ"> GCHQ</A> and Canadian<A href="#CSE">
+ CSE</A>.</DD>
+<DT><A name="SKIP">SKIP</A></DT>
+<DD><B>S</B>imple<B> K</B>ey management for<B> I</B>nternet<B> P</B>
+rotocols, an alternative to<A href="#IKE"> IKE</A> developed by Sun and
+ being marketed by their<A href="http://skip.incog.com"> Internet
+ Commerce Group</A>.</DD>
+<DT><A name="snake">Snake oil</A></DT>
+<DD>Bogus cryptography. See the<A href="http://www.interhack.net/people/cmcurtin/snake-oil-faq.html">
+ Snake Oil FAQ</A> or<A href="http://www.counterpane.com/crypto-gram-9902.html#snakeoil">
+ this paper</A> by Schneier.</DD>
+<DT><A name="SPI">SPI</A></DT>
+<DD><B>S</B>ecurity<B> P</B>arameter<B> I</B>ndex, an index used within<A
+href="#IPSEC"> IPsec</A> to keep connections distinct. A<A href="#SA">
+ Security Association (SA)</A> is defined by destination, protocol and
+ SPI. Without the SPI, two connections to the same gateway using the
+ same protocol could not be distinguished.
+<P>For more detail, see our<A href="ipsec.html"> IPsec</A> section
+ and/or RFC 2401.</P>
+</DD>
+<DT><A name="SSH">SSH</A></DT>
+<DD><B>S</B>ecure<B> SH</B>ell, an encrypting replacement for the
+ insecure Berkeley commands whose names begin with &quot;r&quot; for &quot;remote&quot;:
+ rsh, rlogin, etc.
+<P>For more information on SSH, including how to obtain it, see our
+ cryptography<A href="web.html#tools"> links</A>.</P>
+</DD>
+<DT><A name="SSHco">SSH Communications Security</A></DT>
+<DD>A company founded by the authors of<A href="#SSH"> SSH</A>. Offices
+ are in<A href="http://www.ssh.fi"> Finland</A> and<A href="http://www.ipsec.com">
+ California</A>. They have a toolkit for developers of IPsec
+ applications.</DD>
+<DT><A name="SSL">SSL</A></DT>
+<DD><A href="http://home.netscape.com/eng/ssl3">Secure Sockets Layer</A>
+, a set of encryption and authentication services for web browsers,
+ developed by Netscape. Widely used in Internet commerce. Also known as<A
+href="#TLS"> TLS</A>.</DD>
+<DT>SSLeay</DT>
+<DD>A free implementation of<A href="#SSL"> SSL</A> by Eric Young (eay)
+ and others. Developed in Australia; not subject to US export controls.</DD>
+<DT><A name="static">static IP address</A></DT>
+<DD>an IP adddress which is pre-set on the machine itself, as opposed to
+ a<A href="#dynamic"> dynamic address</A> which is assigned by a<A href="#DHCP">
+ DHCP</A> server or obtained as part of the process of establishing a<A href="#PPP">
+ PPP</A> or<A href="#PPPoE"> PPPoE</A> connection</DD>
+<DT><A name="stream">Stream cipher</A></DT>
+<DD>A<A href="#symmetric"> symmetric cipher</A> which produces a stream
+ of output which can be combined (often using XOR or bytewise addition)
+ with the plaintext to produce ciphertext. Contrasts with<A href="#block">
+ block cipher</A>.
+<P><A href="#IPSEC">IPsec</A> does not use stream ciphers. Their main
+ application is link-level encryption, for example of voice, video or
+ data streams on a wire or a radio signal.</P>
+</DD>
+<DT><A name="subnet">subnet</A></DT>
+<DD>A group of IP addresses which are logically one network, typically
+ (but not always) assigned to a group of physically connected machines.
+ The range of addresses in a subnet is described using a subnet mask.
+ See next entry.</DD>
+<DT>subnet mask</DT>
+<DD>A method of indicating the addresses included in a subnet. Here are
+ two equivalent examples:
+<UL>
+<LI>101.101.101.0/24</LI>
+<LI>101.101.101.0 with mask 255.255.255.0</LI>
+</UL>
+<P>The '24' is shorthand for a mask with the top 24 bits one and the
+ rest zero. This is exactly the same as 255.255.255.0 which has three
+ all-ones bytes and one all-zeros byte.</P>
+<P>These indicate that, for this range of addresses, the top 24 bits are
+ to be treated as naming a network (often referred to as &quot;the
+ 101.101.101.0/24 subnet&quot;) while most combinations of the low 8 bits can
+ be used to designate machines on that network. Two addresses are
+ reserved; 101.101.101.0 refers to the subnet rather than a specific
+ machine while 101.101.101.255 is a broadcast address. 1 to 254 are
+ available for machines.</P>
+<P>It is common to find subnets arranged in a hierarchy. For example, a
+ large company might have a /16 subnet and allocate /24 subnets within
+ that to departments. An ISP might have a large subnet and allocate /26
+ subnets (64 addresses, 62 usable) to business customers and /29 subnets
+ (8 addresses, 6 usable) to residential clients.</P>
+</DD>
+<DT><A name="SWAN">S/WAN</A></DT>
+<DD>Secure Wide Area Network, a project involving<A href="#RSAco"> RSA
+ Data Security</A> and a number of other companies. The goal was to
+ ensure that all their<A href="#IPSEC"> IPsec</A> implementations would
+ interoperate so that their customers can communicate with each other
+ securely.</DD>
+<DT><A name="symmetric">Symmetric cryptography</A></DT>
+<DD>Symmetric cryptography, also referred to as conventional or secret
+ key cryptography, relies on a<EM> shared secret key</EM>, identical for
+ sender and receiver. Sender encrypts with that key, receiver decrypts
+ with it. The idea is that an eavesdropper without the key be unable to
+ read the messages. There are two main types of symmetric cipher,<A href="#block">
+ block ciphers</A> and<A href="#stream"> stream ciphers</A>.
+<P>Symmetric cryptography contrasts with<A href="#public"> public key</A>
+ or asymmetric systems where the two players use different keys.</P>
+<P>The great difficulty in symmetric cryptography is, of course, key
+ management. Sender and receiver<EM> must</EM> have identical keys and
+ those keys<EM> must</EM> be kept secret from everyone else. Not too
+ much of a problem if only two people are involved and they can
+ conveniently meet privately or employ a trusted courier. Quite a
+ problem, though, in other circumstances.</P>
+<P>It gets much worse if there are many people. An application might be
+ written to use only one key for communication among 100 people, for
+ example, but there would be serious problems. Do you actually trust all
+ of them that much? Do they trust each other that much? Should they?
+ What is at risk if that key is compromised? How are you going to
+ distribute that key to everyone without risking its secrecy? What do
+ you do when one of them leaves the company? Will you even know?</P>
+<P>On the other hand, if you need unique keys for every possible
+ connection between a group of 100, then each user must have 99 keys.
+ You need either 99*100/2 = 4950<EM> secure</EM> key exchanges between
+ users or a central authority that<EM> securely</EM> distributes 100 key
+ packets, each with a different set of 99 keys.</P>
+<P>Either of these is possible, though tricky, for 100 users. Either
+ becomes an administrative nightmare for larger numbers. Moreover, keys<EM>
+ must</EM> be changed regularly, so the problem of key distribution
+ comes up again and again. If you use the same key for many messages
+ then an attacker has more text to work with in an attempt to crack that
+ key. Moreover, one successful crack will give him or her the text of
+ all those messages.</P>
+<P>In short, the<EM> hardest part of conventional cryptography is key
+ management</EM>. Today the standard solution is to build a<A href="#hybrid">
+ hybrid system</A> using<A href="#public"> public key</A> techniques to
+ manage keys.</P>
+</DD>
+<DT><A name="T">T</A></DT>
+<DT><A name="TIS">TIS</A></DT>
+<DD>Trusted Information Systems, a firewall vendor now part of<A href="#NAI">
+ NAI</A>. Their Gauntlet product offers IPsec VPN services. TIS
+ implemented the first version of<A href="#SDNS"> Secure DNS</A> on a<A href="#DARPA">
+ DARPA</A> contract.</DD>
+<DT><A name="TLS">TLS</A></DT>
+<DD><B>T</B>ransport<B> L</B>ayer<B> S</B>ecurity, a newer name for<A href="#SSL">
+ SSL</A>.</DD>
+<DT><A name="TOS">TOS field</A></DT>
+<DD>The<STRONG> T</STRONG>ype<STRONG> O</STRONG>f<STRONG> S</STRONG>
+ervice field in an IP header, used to control qualkity of service
+ routing.</DD>
+<DT><A name="traffic">Traffic analysis</A></DT>
+<DD>Deducing useful intelligence from patterns of message traffic,
+ without breaking codes or reading the messages. In one case during
+ World War II, the British guessed an attack was coming because all
+ German radio traffic stopped. The &quot;radio silence&quot; order, intended to
+ preserve security, actually gave the game away.
+<P>In an industrial espionage situation, one might deduce something
+ interesting just by knowing that company A and company B were talking,
+ especially if one were able to tell which departments were involved, or
+ if one already knew that A was looking for acquisitions and B was
+ seeking funds for expansion.</P>
+<P>In general, traffic analysis by itself is not very useful. However,
+ in the context of a larger intelligence effort where quite a bit is
+ already known, it can be very useful. When you are solving a complex
+ puzzle, every little bit helps.</P>
+<P><A href="#IPSEC">IPsec</A> itself does not defend against traffic
+ analysis, but carefully thought out systems using IPsec can provide at
+ least partial protection. In particular, one might want to encrypt more
+ traffic than was strictly necessary, route things in odd ways, or even
+ encrypt dummy packets, to confuse the analyst. We discuss this<A href="ipsec.html#traffic.resist">
+ here</A>.</P>
+</DD>
+<DT><A name="transport">Transport mode</A></DT>
+<DD>An IPsec application in which the IPsec gateway is the destination
+ of the protected packets, a machine acts as its own gateway. Contrast
+ with<A href="#tunnel"> tunnel mode</A>.</DD>
+<DT>Triple DES</DT>
+<DD>see<A href="#3DES"> 3DES</A></DD>
+<DT><A name="TTL">TTL</A></DT>
+<DD><STRONG>T</STRONG>ime<STRONG> T</STRONG>o<STRONG> L</STRONG>ive,
+ used to control<A href="ipsec.html#DNS"> DNS</A> caching. Servers
+ discard cached records whose TTL expires</DD>
+<DT><A name="tunnel">Tunnel mode</A></DT>
+<DD>An IPsec application in which an IPsec gateway provides protection
+ for packets to and from other systems. Contrast with<A href="#transport">
+ transport mode</A>.</DD>
+<DT><A name="2key">Two-key Triple DES</A></DT>
+<DD>A variant of<A href="#3DES"> triple DES or 3DES</A> in which only
+ two keys are used. As in the three-key version, the order of operations
+ is<A href="#EDE"> EDE</A> or encrypt-decrypt-encrypt, but in the
+ two-key variant the first and third keys are the same.
+<P>3DES with three keys has 3*56 = 168 bits of key but has only 112-bit
+ strength against a<A href="#meet"> meet-in-the-middle</A> attack, so it
+ is possible that the two key version is just as strong. Last I looked,
+ this was an open question in the research literature.</P>
+<P>RFC 2451 defines triple DES for<A href="#IPSEC"> IPsec</A> as the
+ three-key variant. The two-key variant should not be used and is not
+ implemented directly in<A href="web.html#FreeSWAN"> Linux FreeS/WAN</A>
+. It cannot be used in automatically keyed mode without major fiddles in
+ the source code. For manually keyed connections, you could make Linux
+ FreeS/WAN talk to a two-key implementation by setting two keys the same
+ in /etc/ipsec.conf.</P>
+</DD>
+<DT><A name="U">U</A></DT>
+<DT><A name="V">V</A></DT>
+<DT><A name="virtual">Virtual Interface</A></DT>
+<DD>A<A href="#Linux"> Linux</A> feature which allows one physical
+ network interface to have two or more IP addresses. See the<CITE> Linux
+ Network Administrator's Guide</CITE> in<A href="biblio.html#kirch">
+ book form</A> or<A href="http://metalab.unc.edu/LDP/LDP/nag/node1.html">
+ on the web</A> for details.</DD>
+<DT>Virtual Private Network</DT>
+<DD>see<A href="#VPN"> VPN</A></DD>
+<DT><A name="VPN">VPN</A></DT>
+<DD><B>V</B>irtual<B> P</B>rivate<B> N</B>etwork, a network which can
+ safely be used as if it were private, even though some of its
+ communication uses insecure connections. All traffic on those
+ connections is encrypted.
+<P><A href="#IPSEC">IPsec</A> is not the only technique available for
+ building VPNs, but it is the only method defined by<A href="rfc.html#RFC">
+ RFCs</A> and supported by many vendors. VPNs are by no means the only
+ thing you can do with IPsec, but they may be the most important
+ application for many users.</P>
+</DD>
+<DT><A name="VPNC">VPNC</A></DT>
+<DD><A href="http://www.vpnc.org">Virtual Private Network Consortium</A>
+, an association of vendors of VPN products.</DD>
+<DT><A name="W">W</A></DT>
+<DT><A name="Wassenaar.gloss">Wassenaar Arrangement</A></DT>
+<DD>An international agreement restricting export of munitions and other
+ tools of war. Unfortunately, cryptographic software is also restricted
+ under the current version of the agreement.<A href="politics.html#Wassenaar">
+ Discussion</A>.</DD>
+<DT><A name="web">Web of Trust</A></DT>
+<DD><A href="#PGP">PGP</A>'s method of certifying keys. Any user can
+ sign a key; you decide which signatures or combinations of signatures
+ to accept as certification. This contrasts with the hierarchy of<A href="#CA">
+ CAs (Certification Authorities)</A> used in many<A href="#PKI"> PKIs
+ (Public Key Infrastructures)</A>.
+<P>See<A href="#GTR"> Global Trust Register</A> for an interesting
+ addition to the web of trust.</P>
+</DD>
+<DT><A name="WEP">WEP (Wired Equivalent Privacy)</A></DT>
+<DD>The cryptographic part of the<A href="#IEEE"> IEEE</A> standard for
+ wireless LANs. As the name suggests, this is designed to be only as
+ secure as a normal wired ethernet. Anyone with a network conection can
+ tap it. Its advocates would claim this is good design, refusing to
+ build in complex features beyond the actual requirements.
+<P>Critics refer to WEP as &quot;Wire<EM>tap</EM> Equivalent Privacy&quot;, and
+ consider it a horribly flawed design based on bogus &quot;requirements&quot;. You
+ do not control radio waves as you might control your wires, so the
+ metaphor in the rationale is utterly inapplicable. A security policy
+ that chooses not to invest resources in protecting against certain
+ attacks which can only be conducted by people physically plugged into
+ your LAN may or may not be reasonable. The same policy is completely
+ unreasonable when someone can &quot;plug in&quot; from a laptop half a block
+ away..</P>
+<P>There has been considerable analysis indicating that WEP is seriously
+ flawed. A FAQ on attacks against WEP is available. Part of it reads:</P>
+<BLOCKQUOTE> ... attacks are practical to mount using only inexpensive
+ off-the-shelf equipment. We recommend that anyone using an 802.11
+ wireless network not rely on WEP for security, and employ other
+ security measures to protect their wireless network. Note that our
+ attacks apply to both 40-bit and the so-called 128-bit versions of WEP
+ equally well.</BLOCKQUOTE>
+<P>WEP appears to be yet another instance of governments, and
+ unfortunately some vendors and standards bodies, deliberately promoting
+ hopelessly flawed &quot;security&quot; products, apparently mainly for the
+ benefit of eavesdropping agencies. See this<A href="politics.html#weak">
+ discussion</A>.</P>
+</DD>
+<DT><A name="X">X</A></DT>
+<DT><A name="X509">X.509</A></DT>
+<DD>A standard from the<A href="http://www.itu.int"> ITU (International
+ Telecommunication Union)</A>, for hierarchical directories with
+ authentication services, used in many<A href="#PKI"> PKI</A>
+ implementations.
+<P>Use of X.509 services, via the<A href="#LDAP"> LDAP protocol</A>, for
+ certification of keys is allowed but not required by the<A href="#IPSEC">
+ IPsec</A> RFCs. It is not yet implemented in<A href="web.html#FreeSWAN">
+ Linux FreeS/WAN</A>.</P>
+</DD>
+<DT>Xedia</DT>
+<DD>A vendor of router and Internet access products, now part of Lucent.
+ Their QVPN products interoperate with Linux FreeS/WAN; see our<A href="interop.html#Xedia">
+ interop document</A>.</DD>
+<DT><A name="Y">Y</A></DT>
+<DT><A name="Z">Z</A></DT>
+</DL>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="web.html">Previous</A>
+<A HREF="biblio.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/impl.notes b/doc/impl.notes
new file mode 100644
index 000000000..6ea3678b6
--- /dev/null
+++ b/doc/impl.notes
@@ -0,0 +1,127 @@
+Introduction
+
+This document is some quick notes to sophisticated implementors, on topics
+which are a bit too arcane to be mentioned in the install instructions.
+Beware that it is not updated very often, and may be behind the times.
+This file is RCSID $Id: impl.notes,v 1.1 2004/03/15 20:35:21 as Exp $
+
+
+
+Where are things?
+
+If your kernel sources are not located in /usr/src/linux, or local manual
+pages are not in /usr/local/man/man[1-8], you've got a problem. You may
+be able to get around it to some extent just by modifying the top-level
+Makefile, but we don't promise. For a different manpage location, that
+will probably suffice; for a different kernel location, probably not.
+We'd welcome reports of what needs to be fixed for this.
+
+
+
+Cross-compiling
+
+At the moment, this distribution makes no attempt to support building
+the software on one machine for use on another. That's hard, especially
+since the Linux kernel sources are not set up for it at all.
+
+
+
+One thing at a time
+
+(CAUTION: This is somewhat outdated. It's retained because it may be a
+useful guide for experts. Consult the Makefile for current details.)
+
+If you want to do the build and install one step at a time, instead of
+using the prepackaged make commands like "make menugo", do the following
+instead. (We do things in a slightly different order here, to avoid
+unnecessary directory changing.)
+
+To fit the kernel part of KLIPS into the kernel sources, do:
+
+ make insert
+
+(This makes a symbolic link /usr/src/linux/net/ipsec, pointing to the
+KLIPS source directory. It patches some kernel files, where necessary, to
+know about KLIPS and/or to fix bugs. It adds a default configuration to
+the kernel configuration file. Finally, it makes the KLIPS communication
+file, /dev/ipsec, if it's not already there.)
+
+Build the libraries, Pluto, and various user-level utilities:
+
+ make programs
+
+Install the Pluto daemon and user-level utilities, and set things up for
+boot-time startup:
+
+ make install
+
+Configure the kernel:
+
+ cd /usr/src/linux
+ make menuconfig # (or xconfig, or whatever)
+
+See the configuration step of INSTALL for details of what to do within
+the configuration program. Don't forget to save the results.
+
+Go through the usual kernel make process (still in /usr/src/linux):
+
+ make dep clean zImage
+
+Caution: the Linux kernel Makefiles are not always careful about checking
+for errors. We recommend capturing the output of this step and searching
+it for any occurrence of "error", "Error", etc. The details of how to do
+so are unfortunately somewhat shell-dependent, although if you are using
+the standard shell (rather than csh, tcsh, etc.), this would do:
+
+ make dep clean zImage 2>&1 | tee junk
+ egrep -i error junk # no output is good output
+
+(One glitch here is that the word "error" can sometimes occur legitimately
+in the make output. For example, the kernel math emulation package has a
+source file "errors.c". Some judgement is required to ignore such false
+alarms.) The prepackaged make commands do all this for you.
+
+If your kernel is using loadable modules, you'll also need to do:
+
+ make modules
+
+Now you need to install the resulting kernel. If you're not using the
+kernel's "make install" -- many people aren't -- then you need to do your
+usual install procedure. You might want to read doc/kernel.notes, which
+recounts some of our experiences with RedHat 5.2 kernel installation in
+particular.
+
+If "make install" is good enough for you, then:
+
+ make install
+
+(Same comments on error checking as in previous step.) If your kernel is
+using loadable modules, you'll also need to do:
+
+ make modules_install
+
+Finally, go back to INSTALL for the remaining steps.
+
+
+
+Klips as a module
+
+It is possible to run Klips as a kernel module, meaning that it does not
+have to be loaded until needed. Formerly this was necessary, in fact,
+because Klips wouldn't run any other way. Now it will, and we recommend
+static linking ("y", not "m", to the configuration question) for security.
+Klips is not terribly large (tens of KB, not hundreds) and should not
+cause size problems unless your kernel is already pushing the limits.
+
+However, Klips does still run as a module, if you want (although beware
+that we don't test this option very often). "ipsec setup start" and
+"ipsec setup stop" load and unload it as appropriate, and you should not
+need to do anything about that yourself.
+
+
+
+Old Red Hats
+
+Our development is currently on a mix of Red Hat 6.2 and 7.1, with 6.2
+fading fast. Our older Red Hats have been retired, and although FreeS/WAN
+should still work on them, we no longer make any attempt to ensure that.
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 000000000..427ed7ea7
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,55 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN index</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, encryption, cryptography, FreeS/WAN, FreeSWAN">
+ <!--
+
+ Written by Claudia Schmeing for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: index.html,v 1.1 2004/03/15 20:35:21 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:21 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1>FreeS/WAN documentation</h1>
+
+<ul>
+ <li><a href="intro.html">Introduction</a></li>
+ <li><a href="upgrading.html">Upgrading to 2.x</a></li>
+</ul>
+
+<ul>
+ <li><a href="quickstart.html">Quickstart guide to Opportunistic Encryption</a></li>
+ <li><a href="install.html">Installing</a></li>
+ <li><a href="config.html">Configuring</a></li>
+ <li><a href="policygroups.html">Policy Groups</a>
+ </li>
+ <li><a href="interop.html">Interoperating</a>
+<FONT COLOR="#FF0000">New and improved!</FONT></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="trouble.html">Troubleshooting and problem reporting</a></li>
+</ul>
+
+<ul>
+ <li><a href="toc.html">Full table of contents, with much more</a></li>
+ <li><a href="HowTo.html">All our docs as one big file</a></li>
+</ul>
+
+<p>For technical support and other questions, use our <a
+href="mail.html">mailing lists</a>.</p>
+
+<pre> This index last changed: $Date: 2004/03/15 20:35:21 $</pre>
+
+</body>
+</html>
diff --git a/doc/install.html b/doc/install.html
new file mode 100644
index 000000000..6cd55535e
--- /dev/null
+++ b/doc/install.html
@@ -0,0 +1,286 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="adv_config.html">Previous</A>
+<A HREF="config.html">Next</A>
+<HR>
+<H1><A name="install">Installing FreeS/WAN</A></H1>
+<P>This document will teach you how to install Linux FreeS/WAN. If your
+ distribution comes with Linux FreeS/WAN, we offer tips to get you
+ started.</P>
+<H2><A NAME="15_1">Requirements</A></H2>
+<P>To install FreeS/WAN you must:</P>
+<UL>
+<LI>be running Linux with the 2.4 or 2.2 kernel series. See this<A HREF="http://www.freeswan.ca/download.php#contact">
+ kernel compatibility table</A>.
+<BR>We also have experimental support for 2.6 kernels. Here are two
+ basic approaches:
+<UL>
+<LI> install FreeS/WAN, including its<A HREF="ipsec.html#parts"> KLIPS</A>
+ kernel code. This will remove the native IPsec stack and replace it
+ with KLIPS.</LI>
+<LI> install the FreeS/WAN<A HREF="ipsec.html#parts"> userland tools</A>
+ (keying daemon and supporting scripts) for use with<A HREF="http://lartc.org/howto/lartc.ipsec.html">
+ 2.6 kernel native IPsec</A>,</LI>
+</UL>
+ See also these<A HREF="2.6.known-issues"> known issues with 2.6</A>.</LI>
+<LI>have root access to your Linux box</LI>
+<LI>choose the version of FreeS/WAN you wish to install based on<A HREF="http://www.freeswan.org/mail.html">
+ mailing list reports</A>
+<!-- or
+our updates page (coming soon)-->
+</LI>
+</UL>
+<H2><A NAME="15_2">Choose your install method</A></H2>
+<P>There are three basic ways to get FreeS/WAN onto your system:</P>
+<UL>
+<LI>activating and testing a FreeS/WAN that<A HREF="#distroinstall">
+ shipped with your Linux distribution</A></LI>
+<LI><A HREF="#rpminstall">RPM install</A></LI>
+<LI><A HREF="#srcinstall">Install from source</A></LI>
+</UL>
+<A NAME="distroinstall"></A>
+<H2><A NAME="15_3">FreeS/WAN ships with some Linuxes</A></H2>
+<P>FreeS/WAN comes with<A HREF="intro.html#distwith"> these
+ distributions</A>.</P>
+<P>If you're running one of these, include FreeS/WAN in the choices you
+ make during installation, or add it later using the distribution's
+ tools.</P>
+<H3><A NAME="15_3_1">FreeS/WAN may be altered...</A></H3>
+<P>Your distribution may have integrated extra features, such as Andreas
+ Steffen's X.509 patch, into FreeS/WAN. It may also use custom startup
+ script locations or directory names.</P>
+<H3><A NAME="15_3_2">You might need to create an authentication keypair</A>
+</H3>
+<P>If your FreeS/WAN came with your distribution, you may wish to
+ generate a fresh RSA key pair. FreeS/WAN will use these keys for
+ authentication.</P>
+<P> To do this, become root, and type:</P>
+<PRE> ipsec newhostkey --output /etc/ipsec.secrets --hostname xy.example.com
+ chmod 600 /etc/ipsec.secrets</PRE>
+<P>where you replace xy.example.com with your machine's fully-qualified
+ domain name. Generate some randomness, for example by wiggling your
+ mouse, to speed the process.</P>
+<P>The resulting ipsec.secrets looks like:</P>
+<PRE>: RSA {
+ # RSA 2192 bits xy.example.com Sun Jun 8 13:42:19 2003
+ # for signatures only, UNSAFE FOR ENCRYPTION
+ #pubkey=0sAQOFppfeE3cC7wqJi...
+ Modulus: 0x85a697de137702ef0...
+ # everything after this point is secret
+ PrivateExponent: 0x16466ea5033e807...
+ Prime1: 0xdfb5003c8947b7cc88759065...
+ Prime2: 0x98f199b9149fde11ec956c814...
+ Exponent1: 0x9523557db0da7a885af90aee...
+ Exponent2: 0x65f6667b63153eb69db8f300dbb...
+ Coefficient: 0x90ad00415d3ca17bebff123413fc518...
+ }
+# do not change the indenting of that &quot;}&quot;</PRE>
+<P>In the actual file, the strings are much longer.</P>
+<H3><A NAME="15_3_3">Start and test FreeS/WAN</A></H3>
+<P>You can now<A HREF="install.html#starttest"> start FreeS/WAN and test
+ whether it's been successfully installed.</A>.</P>
+<A NAME="rpminstall"></A>
+<H2><A NAME="15_4">RPM install</A></H2>
+<P>These instructions are for a recent Red Hat with a stock Red Hat
+ kernel. We know that Mandrake and SUSE also produce FreeS/WAN RPMs. If
+ you're running either, install using your distribution's tools.</P>
+<H3><A NAME="15_4_1">Download RPMs</A></H3>
+<P>Decide which functionality you need:</P>
+<UL>
+<LI>standard FreeS/WAN RPMs. Use these shortcuts:
+<BR>
+<UL>
+<LI>(for 2.6 kernels: userland only)
+<BR> ncftpget
+ ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs/\*userland*
+</LI>
+<LI>(for 2.4 kernels)
+<BR> ncftpget
+ ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs/`uname -r
+ | tr -d 'a-wy-z'`/\*</LI>
+<LI> or view all the offerings at our<A href="ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs">
+ FTP site</A>.</LI>
+</UL>
+</LI>
+<LI>unofficial<A href="http://www.freeswan.ca/download.php"> Super
+ FreeS/WAN</A> RPMs, which include Andreas Steffen's X.509 patch and
+ more. Super FreeS/WAN RPMs do not currently include<A HREF="glossary.html#NAT.gloss">
+ Network Address Translation</A> (NAT) traversal, but Super FreeS/WAN
+ source does.</LI>
+</UL>
+<A NAME="2.6.rpm"></A>
+<P>For 2.6 kernels, get the latest FreeS/WAN userland RPM, for example:</P>
+<PRE> freeswan-userland-2.04.9-0.i386.rpm</PRE>
+<P>Note: FreeS/WAN's support for 2.6 kernel IPsec is preliminary. Please
+ see<A HREf="2.6.known-issues"> 2.6.known-issues</A>, and the latest<A HREF="http://www.freeswan.org/mail.html">
+ mailing list reports</A>.</P>
+<P>Change to your new FreeS/WAN directory, and make and install the</P>
+<P>For 2.4 kernels, get both kernel and userland RPMs. Check your kernel
+ version with</P>
+<PRE> uname -r</PRE>
+<P>Get a kernel module which matches that version. For example:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<P>Note: These modules<B> will only work on the Red Hat kernel they were
+ built for</B>, since they are very sensitive to small changes in the
+ kernel.</P>
+<P>Get FreeS/WAN utilities to match. For example:</P>
+<PRE> freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<H3><A NAME="15_4_2">For freeswan.org RPMs: check signatures</A></H3>
+<P>While you're at our ftp site, grab the RPM signing key</P>
+<PRE> freeswan-rpmsign.asc</PRE>
+<P>If you're running RedHat 8.x or later, import this key into the RPM
+ database:</P>
+<PRE> rpm --import freeswan-rpmsign.asc</PRE>
+<P>For RedHat 7.x systems, you'll need to add it to your<A HREF="glossary.html#PGP">
+ PGP</A> keyring:</P>
+<PRE> pgp -ka freeswan-rpmsign.asc</PRE>
+<P>Check the digital signatures on both RPMs using:</P>
+<PRE> rpm --checksig freeswan*.rpm </PRE>
+<P>You should see that these signatures are good:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK
+ freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK</PRE>
+<H3><A NAME="15_4_3">Install the RPMs</A></H3>
+<P>Become root:</P>
+<PRE> su</PRE>
+<P>For a first time install, use:</P>
+<PRE> rpm -ivh freeswan*.rpm</PRE>
+<P>To upgrade existing RPMs (and keep all .conf files in place), use:</P>
+<PRE> rpm -Uvh freeswan*.rpm</PRE>
+<P>If you're upgrading from FreeS/WAN 1.x to 2.x RPMs, and encounter
+ problems, see<A HREF="upgrading.html#upgrading.rpms"> this note</A>.</P>
+<H3><A NAME="15_4_4">Start and Test FreeS/WAN</A></H3>
+<P>Now,<A HREF="install.html#starttest"> start FreeS/WAN and test your
+ install</A>.</P>
+<A NAME="srcinstall"></A>
+<H2><A NAME="15_5">Install from Source</A></H2>
+
+<!-- Most of this section, along with "Start and Test", can replace
+INSTALL. -->
+<H3><A NAME="15_5_1">Decide what functionality you need</A></H3>
+<P>Your choices are:</P>
+<UL>
+<LI><A HREF="ftp://ftp.xs4all.nl/pub/crypto/freeswan">standard FreeS/WAN</A>
+,</LI>
+<LI>standard FreeS/WAN plus any of these<A HREF="web.html#patch">
+ user-supported patches</A>, or</LI>
+<LI><A HREF="http://www.freeswan.ca/download">Super FreeS/WAN</A>, an
+ unofficial FreeS/WAN pre-patched with many of the above. Provides
+ additional algorithms, X.509, SA deletion, dead peer detection, and<A HREF="glossary.html#NAT.gloss">
+ Network Address Translation</A> (NAT) traversal.</LI>
+</UL>
+<H3><A NAME="15_5_2">Download FreeS/WAN</A></H3>
+<P>Download the source tarball you've chosen, along with any patches.</P>
+<H3><A NAME="15_5_3">For freeswan.org source: check its signature</A></H3>
+<P>While you're at our ftp site, get our source signing key</P>
+<PRE> freeswan-sigkey.asc</PRE>
+<P>Add it to your PGP keyring:</P>
+<PRE> pgp -ka freeswan-sigkey.asc</PRE>
+<P>Check the signature using:</P>
+<PRE> pgp freeswan-2.04.tar.gz.sig freeswan-2.04.tar.gz</PRE>
+<P>You should see something like:</P>
+<PRE> Good signature from user &quot;Linux FreeS/WAN Software Team (build@freeswan.org)&quot;.
+ Signature made 2002/06/26 21:04 GMT using 2047-bit key, key ID 46EAFCE1</PRE>
+
+<!-- Note to self: build@freeswan.org has angled brackets in the original.
+ Changed because it conflicts with HTML tags. -->
+<H3><A NAME="15_5_4">Untar, unzip</A></H3>
+<P>As root, unpack your FreeS/WAN source into<VAR> /usr/src</VAR>.</P>
+<PRE> su
+ mv freeswan-2.04.tar.gz /usr/src
+ cd /usr/src
+ tar -xzf freeswan-2.04.tar.gz
+</PRE>
+<H3><A NAME="15_5_5">Patch if desired</A></H3>
+<P>Now's the time to add any patches. The contributor may have special
+ instructions, or you may simply use the patch command.</P>
+<H3><A NAME="15_5_6">... and Make</A></H3>
+<P>Choose one of the methods below.</P>
+<H4>Userland-only Install for 2.6 kernels</H4>
+<A NAME="2.6.src"></A>
+<P>Note: FreeS/WAN's support for 2.6 kernel IPsec is preliminary. Please
+ see<A HREf="2.6.known-issues"> 2.6.known-issues</A>, and the latest<A HREF="http://www.freeswan.org/mail.html">
+ mailing list reports</A>.</P>
+<P>Change to your new FreeS/WAN directory, and make and install the
+ FreeS/WAN userland tools.</P>
+<PRE> cd /usr/src/freeswan-2.04
+ make programs
+ make install</PRE>
+<P>Now,<A HREF="install.html#starttest"> start FreeS/WAN and test your
+ install</A>.</P>
+<H4>KLIPS install for 2.2, 2.4, or 2.6 kernels</H4>
+<A NAME="modinstall"></A>
+<P>To make a modular version of KLIPS, along with other FreeS/WAN
+ programs you'll need, use the command sequence below. This will change
+ to your new FreeS/WAN directory, make the FreeS/WAN module (and other
+ stuff), and install it all.</P>
+<PRE> cd /usr/src/freeswan-2.04
+ make oldmod
+ make minstall</PRE>
+<P><A HREF="install.html#starttest">Start FreeS/WAN and test your
+ install</A>.</P>
+<P>To link KLIPS statically into your kernel (using your old kernel
+ settings), and install other FreeS/WAN components, do:</P>
+<PRE> cd /usr/src/freeswan-2.04
+ make oldmod
+ make minstall</PRE>
+<P>Reboot your system and<A HREF="install.html#testonly"> test your
+ install</A>.</P>
+<P>For other ways to compile KLIPS, see our Makefile.</P>
+<A name="starttest"></A>
+<H2><A NAME="15_6">Start FreeS/WAN and test your install</A></H2>
+<P>Bring FreeS/WAN up with:</P>
+<PRE> service ipsec start</PRE>
+<P>This is not necessary if you've rebooted.</P>
+<A name="testonly"></A>
+<H2><A NAME="15_7">Test your install</A></H2>
+<P>To check that you have a successful install, run:</P>
+<PRE> ipsec verify</PRE>
+<P>You should see at least:</P>
+<PRE>
+ Checking your system to see if IPsec got installed and started correctly
+ Version check and ipsec on-path [OK]
+ Checking for KLIPS support in kernel [OK]
+ Checking for RSA private key (/etc/ipsec.secrets) [OK]
+ Checking that pluto is running [OK]
+</PRE>
+<P>If any of these first four checks fails, see our<A href="trouble.html#install.check">
+ troubleshooting guide</A>.</P>
+<H2><A NAME="15_8">Making FreeS/WAN play well with others</A></H2>
+<P>There are at least a couple of things on your system that might
+ interfere with FreeS/WAN, and now's a good time to check these:</P>
+<UL>
+<LI>Firewalling. You need to allow UDP 500 through your firewall, plus
+ ESP (protocol 50) and AH (protocol 51). For more information, see our
+ updated firewalls document (coming soon).</LI>
+<LI>Network address translation. Do not NAT the packets you will be
+ tunneling.</LI>
+</UL>
+<H2><A NAME="15_9">Configure for your needs</A></H2>
+<P>You'll need to configure FreeS/WAN for your local site. Have a look
+ at our<A HREF="quickstart.html"> opportunism quickstart guide</A> to
+ see if that easy method is right for your needs. Or, see how to<A HREF="config.html">
+ configure a network-to-network or Road Warrior style VPN</A>.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="adv_config.html">Previous</A>
+<A HREF="config.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/interop.html b/doc/interop.html
new file mode 100644
index 000000000..1cd7b9e78
--- /dev/null
+++ b/doc/interop.html
@@ -0,0 +1,983 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="compat.html">Previous</A>
+<A HREF="performance.html">Next</A>
+<HR>
+<A NAME="interop"></A>
+<H1><A NAME="10">Interoperating with FreeS/WAN</A></H1>
+<P>The FreeS/WAN project needs you! We rely on the user community to
+ keep up to date. Mail users@lists.freeswan.org with your interop
+ success stories.</P>
+<P><STRONG>Please note</STRONG>: Most of our interop examples feature
+ Linux FreeS/WAN 1.x config files. You can convert them to 2.x files
+ fairly easily with the patch in our<A HREF="upgrading.html#ipsec.conf_v2">
+ Upgrading Guide</A>.</P>
+<H2><A NAME="10_1">Interop at a Glance</A></H2>
+<TABLE BORDER="1">
+<TR><TD>&nbsp;</TD><TD colspan="5">FreeS/WAN VPN</TD><TD>Road Warrior</TD><TD>
+OE</TD></TR>
+<TR><TD>&nbsp;</TD><TD>PSK</TD><TD>RSA Secret</TD><TD>X.509
+<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD><TD>
+NAT-Traversal
+<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD><TD>
+Manual
+<BR>Keying</TD><TD>&nbsp;</TD><TD>&nbsp;</TD></TR>
+<TR><TD colspan="8">More Compatible</TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="web.html#freeswan">FreeS/WAN</A><A NAME="freeswan.top">
+ &nbsp;</A></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#isakmpd">isakmpd (OpenBSD)</A><A NAME="isakmpd.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>
+<FONT color="#cc0000">No&nbsp;&nbsp;&nbsp;&nbsp;</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#kame">Kame (FreeBSD,
+<BR> NetBSD, MacOSX)
+<BR> <SMALL>aka racoon</SMALL></A><A NAME="kame.top"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#mcafee">McAfee VPN
+<BR><SMALL>was PGPNet</SMALL></A><A NAME="mcafee.top"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#microsoft">Microsoft
+<BR> Windows 2000/XP</A><A NAME="microsoft.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="glossary.html#ssh">SSH Sentinel</A><A NAME="ssh.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>&nbsp;</TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#safenet">Safenet SoftPK
+<BR>/SoftRemote</A><A NAME="safenet.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+<TR><TD colspan="8">Other</TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#6wind">6Wind</A><A NAME="6wind.top"> &nbsp;</A></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+<FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#alcatel">Alcatel Timestep</A><A NAME="alcatel.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#apple">Apple Macintosh
+<BR>System 10+</A><A NAME="apple.top"> &nbsp;</A></TD><TD><FONT color="#cccc00">
+Maybe</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#cccc00">
+Maybe</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#ashleylaurent">AshleyLaurent
+<BR> VPCom</A><A NAME="ashleylaurent.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#borderware">Borderware</A><A NAME="borderware.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+
+<!--
+http://www.cequrux.com/vpn-guides.php3
+"coming soon" guide to connect with FreeS/WAN.
+-->
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#checkpoint">Check Point FW-1/VPN-1</A><A NAME="checkpoint.top">
+ &nbsp;</A></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>
+<FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#cisco">Cisco with 3DES</A><A NAME="cisco.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#cccc00">Maybe</FONT>
+</TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#equinux">Equinux VPN Tracker
+<BR> (for Mac OS X)</A><A NAME="equinux.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#fsecure">F-Secure</A><A NAME="fsecure.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">
+Maybe</FONT></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#gauntlet">Gauntlet GVPN</A><A NAME="gauntlet.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#aix">IBM AIX</A><A NAME="aix.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#as400">IBM AS/400</A><A NAME="as400"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#intel">Intel Shiva
+<BR>LANRover/Net Structure</A><A NAME="intel.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#lancom">LanCom (formerly ELSA)</A><A NAME="lancom.top">
+ &nbsp;</A></TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#linksys">Linksys</A><A NAME="linksys.top"> &nbsp;</A></TD><TD>
+<FONT color="#cccc00">Maybe</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">
+No</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>
+<FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#lucent">Lucent</A><A NAME="lucent.top"> &nbsp;</A></TD><TD><FONT
+color="#cccc00">Partial</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#netasq">Netasq</A><A NAME="netasq.top"> &nbsp;</A></TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#netcelo">netcelo</A><A NAME="netcelo.top"> &nbsp;</A></TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#netgear">Netgear fvs318</A><A NAME="netgear.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#netscreen">Netscreen 100
+<BR>or 5xp</A><A NAME="netscreen.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cccc00">
+Maybe</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#nortel">Nortel Contivity</A><A NAME="nortel.top"> &nbsp;</A>
+</TD><TD><FONT color="#cccc00">Partial</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#radguard">RadGuard</A><A NAME="radguard.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#raptor">Raptor</A><A NAME="raptor"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#redcreek">Redcreek Ravlin</A><A NAME="redcreek.top"> &nbsp;</A>
+</TD><TD><FONT color="#00cc00">Yes</FONT><FONT color="#cccc00">/Partial</FONT>
+</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">
+No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#sonicwall">SonicWall</A><A NAME="sonicwall.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cccc00">Maybe</FONT></TD><TD><FONT color="#cc0000">No</FONT></TD><TD>
+<FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#sun">Sun Solaris</A><A NAME="sun.top"> &nbsp;</A></TD><TD><FONT
+color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT>
+</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#symantec">Symantec</A><A NAME="symantec.top"> &nbsp;</A></TD><TD>
+<FONT color="#00cc00">Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>
+&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#watchguard">Watchguard
+<BR> Firebox</A><A NAME="watchguard.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD><FONT color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#xedia">Xedia Access Point
+<BR>/QVPN</A><A NAME="xedia.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR><TD><A HREF="#zyxel">Zyxel Zywall
+<BR>/Prestige</A><A NAME="zyxel.top"> &nbsp;</A></TD><TD><FONT color="#00cc00">
+Yes</FONT></TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD><FONT
+color="#cc0000">No</FONT></TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE
+
+
+<TR>
+<TD><A HREF="#sample">sample</A></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+-->
+<TR><TD>&nbsp;</TD><TD>PSK</TD><TD>RSA Secret</TD><TD>X.509
+<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD><TD>
+NAT-Traversal
+<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD><TD>
+Manual
+<BR>Keying</TD><TD>&nbsp;</TD><TD>&nbsp;</TD></TR>
+<TR><TD>&nbsp;</TD><TD colspan="5">FreeS/WAN VPN</TD><TD>Road Warrior</TD><TD>
+OE</TD></TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+</TABLE>
+<H3><A NAME="10_1_1">Key</A></H3>
+<TABLE BORDER="1">
+<TR><TD><FONT color="#00cc00">Yes</FONT></TD><TD>People report that this
+ works for them.</TD></TR>
+<TR><TD>[Blank]</TD><TD>We don't know.</TD></TR>
+<TR><TD><FONT color="#cc0000">No</FONT></TD><TD>We have reason to
+ believe it was, at some point, not possible to get this to work.</TD></TR>
+<TR><TD><FONT color="#cccc00">Partial</FONT></TD><TD>Partial success.
+ For example, a connection can be created from one end only.</TD></TR>
+<TR><TD><FONT color="#00cc00">Yes</FONT><FONT color="#cccc00">/Partial</FONT>
+</TD><TD>Mixed reports.</TD></TR>
+<TR><TD><FONT color="#cccc00">Maybe</FONT></TD><TD>We think the answer
+ is &quot;yes&quot;, but need confirmation.</TD></TR>
+</TABLE>
+<A NAME="interoprules"></A>
+<H2><A NAME="10_2">Basic Interop Rules</A></H2>
+<P>Vanilla FreeS/WAN implements<A HREF="compat.html#compat"> these parts</A>
+ of the IPSec specifications. You can add more with<A HREF="http://www.freeswan.ca">
+ Super FreeS/WAN</A>, but what we offer may be enough for many users.</P>
+<UL>
+<LI> To use X.509 certificates with FreeS/WAN, you will need the<A HREF="http://www.strongsec.org/freeswan">
+ X.509 patch</A> or<A HREF="http://www.freeswan.ca"> Super FreeS/WAN</A>
+, which includes that patch.</LI>
+<LI> To use<A HREF="glossary.html#NAT.gloss"> Network Address
+ Translation</A> (NAT) traversal with FreeS/WAN, you will need Arkoon
+ Network Security's<A HREF="http://open-source.arkoon.net"> NAT
+ traversal patch</A> or<A HREF="http://www.freeswan.ca"> Super FreeS/WAN</A>
+, which includes it.</LI>
+</UL>
+<P>We offer a set of proposals which is not user-adjustable, but covers
+ all combinations that we can offer. FreeS/WAN always proposes triple
+ DES encryption and Perfect Forward Secrecy (PFS). In addition, we
+ propose Diffie Hellman groups 5 and 2 (in that order), and MD5 and
+ SHA-1 hashes. We accept the same proposals, in the same order of
+ preference.</P>
+<P>Other interop notes:</P>
+<UL>
+<LI> A<A HREF="http://lists.freeswan.org/archives/users/2003-September/msg00462.html">
+ SHA-1 bug in FreeS/WAN 2.00, 2.01 and 2.02</A> may affect some interop
+ scenarios. It does not affect 1.x versions, and is fixed in 2.03 and
+ later.</LI>
+<LI> Some other implementations will close a connection with FreeS/WAN
+ after some time. This may be a problem with rekey lifetimes. Please see<A
+HREF="http://lists.freeswan.org/archives/users/2003-October/msg00293.html">
+ this tip</A> and<A HREF="http://lists.freeswan.org/pipermail/users/2001-December/005758.html">
+ this workaround</A>.</LI>
+</UL>
+<H2><A NAME="10_3">Longer Stories</A></H2>
+<H3><A NAME="10_3_1">For<EM> More Compatible</EM> Implementations</A></H3>
+<H4><A NAME="freeswan">FreeS/WAN</A></H4>
+<P> See our documentation at<A HREF="http://www.freeswan.org">
+ freeswan.org</A> and the Super FreeS/WAN docs at<A HREF="http://www.freeswan.ca">
+ freeswan.ca</A>. Some user-written HOWTOs for FreeS/WAN-FreeS/WAN
+ connections are listed in<A HREF="intro.html#howto"> our Introduction</A>
+.</P>
+<P>See also:</P>
+<UL>
+<LI><A HREF="http://lugbe.ch/action/reports/ipsec_htbe.phtml"> A German
+ FreeS/WAN-FreeS/WAN page by Markus Wernig (X.509)</A></LI>
+</UL>
+<P><A HREF="#freeswan.top">Back to chart</A></P>
+<H4><A NAME="isakmpd">isakmpd (OpenBSD)</A></H4>
+<P><A HREF="http://www.openbsd.org/faq/faq13.html">OpenBSD FAQ: Using
+ IPsec</A>
+<BR><A HREF="http://www.rommel.stw.uni-erlangen.de/~hshoexer/ipsec-howto/HOWTO.html">
+ Hans-Joerg Hoexer's interop Linux-OpenBSD (PSK)</A>
+<BR><A HREF="http://www.segfault.net/ipsec/"> Skyper's configuration
+ (PSK)</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A></P>
+<P><A HREF="#isakmpd.top">Back to chart</A></P>
+<H4><A NAME="kame">Kame</A></H4>
+<UL>
+<LI>For FreeBSD and NetBSD. Ships with Mac OS X; see also our<A HREF="#apple">
+ Mac</A> section.</LI>
+<LI>Also known as<EM> racoon</EM>, its keying daemon.</LI>
+</UL>
+<P><A HREF="http://www.kame.net">Kame homepage, with FAQ</A>
+<BR><A HREF="http://www.netbsd.org/Documentation/network/ipsec">
+ NetBSD's IPSec FAQ</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00560.html">
+ Ghislaine's post explaining some interop peculiarities</A></P>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/09/msg00511.html">
+ Itojun's Kame-FreeS/WAN interop tips (PSK)</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2000"> Ghislaine
+ Labouret's French page with links to matching FreeS/WAN and Kame
+ configs (RSA)</A>
+<BR><A HREF="http://lugbe.ch/lostfound/contrib/freebsd_router/"> Markus
+ Wernig's HOWTO (X.509, BSD gateway)</A>
+<BR><A HREF="http://web.morgul.net/~frodo/docs/kame+freeswan_interop.html">
+ Frodo's Kame-FreeS/WAN interop (X.509)</A>
+<BR><A HREF="http://www.wavesec.org/kame.phtml"> Kame as a WAVEsec
+ client.</A></P>
+<P><A HREF="#kame.top">Back to chart</A></P>
+<H4><A NAME="mcafee">PGPNet/McAfee</A></H4>
+<P></P>
+<UL>
+<LI>Now called McAfee VPN Client.</LI>
+<LI>PGPNet also came in a freeware version which did not support subnets</LI>
+<LI>To support dhcp-over-ipsec, you need the X.509 patch, which is
+ included in<A HREF="http://www.freeswan.ca"> Super FreeS/WAN</A>.</LI>
+</UL>
+<P><A HREF="http://www.freeswan.ca/docs/WindowsInterop"> Tim Carr's
+ Windows Interop Guide (X.509)</A>
+<BR><A HREF="http://www.rommel.stw.uni-erlangen.de/~hshoexer/ipsec-howto/HOWTO.html#Interop2">
+ Hans-Joerg Hoexer's Guide for Linux-PGPNet (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/04/msg00339.html">
+ Kai Martius' instructions using RSA Key-Extractor Tool (RSA)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.zengl.net/freeswan/english.html">Christian
+ Zeng's page (RSA)</A> based on Kai's work. English or German.
+<BR><A HREF="http://tirnanog.ls.fi.upm.es/CriptoLab/Biblioteca/InfTech/InfTech_CriptoLab.htm">
+ Oscar Delgado's PDF (X.509, no configs)</A>
+<BR><A HREF="http://www-ec.njit.edu/~rxt1077/Howto.txt"> Ryan's HOWTO
+ for FreeS/WAN-PGPNet (X.509)</A>. Through a Linksys Router with IPsec
+ Passthru enabled.
+<BR><A HREF="http://jixen.tripod.com/#RW-PGP-to-Fwan"> Jean-Francois
+ Nadeau's Practical Configuration (Road Warrior with PSK)</A>
+<BR><A HREF="http://www.evolvedatacom.nl/freeswan.html#toc"> Wouter
+ Prins' HOWTO (Road Warrior with X.509)</A>
+<BR></P>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/01/msg00271.html">
+ Rekeying problem with FreeS/WAN and older PGPNets</A>
+<BR></P>
+<P><A HREF="http://www.strongsec.com/freeswan/dhcprelay/index.htm"> DHCP
+ over IPSEC HOWTO for FreeS/WAN (requires X.509 and dhcprelay patches)</A>
+</P>
+<P><A HREF="#mcafee.top">Back to chart</A></P>
+<H4><A NAME="microsoft">Microsoft Windows 2000/XP</A></H4>
+<UL>
+<LI>IPsec comes with Win2k, and with XP Support Tools. May require<A HREF="http://www.microsoft.com/windows2000/downloads/recommended/encryption/default.asp">
+ High Encryption Pack</A>. WinXP users have also reported better results
+ with Service Pack 1.</LI>
+<LI>The Road Warrior setup works either way round. Windows (XP or 2K)
+ IPsec can connect as a Road Warrior to FreeS/WAN. However, FreeS/WAN
+ can also successfully connect as a Road Warrior to Windows IPsec (see
+ Nate Carlson's configs below).</LI>
+<LI>FreeS/WAN version 1.92 or later is required to avoid an
+ interoperation problem with Windows native IPsec. Earlier FreeS/WAN
+ versions did not process the Commit Bit as Windows native IPsec
+ expected.</LI>
+</UL>
+<P><A HREF="http://www.freeswan.ca/docs/WindowsInterop"> Tim Carr's
+ Windows Interop Guide (X.509)</A>
+<BR><A HREF="http://ipsec.math.ucla.edu/services/ipsec.html"> James
+ Carter's instructions (X.509, NAT-T)</A>
+<BR><A HREF="http://jixen.tripod.com/#Win2000-Fwan"> Jean-Francois
+ Nadeau's Net-net Configuration (PSK)</A>
+<BR><A HREF="http://security.nta.no/freeswan-w2k.html"> Telenor's
+ Node-node Config (Transport-mode PSK)</A>
+<BR><A HREF="http://vpn.ebootis.de"> Marcus Mueller's HOWTO using his
+ VPN config tool (X.509).</A> Tool also works with PSK.
+<BR><A HREF="http://www.natecarlson.com/include/showpage.php?cat=linux&page=ipsec-x509">
+ Nate Carlson's HOWTO using same tool (Road Warrior with X.509)</A>.
+ Unusually, FreeS/WAN is the Road Warrior here.
+<BR><A HREF="http://tirnanog.ls.fi.upm.es/CriptoLab/Biblioteca/InfTech/InfTech_CriptoLab.htm">
+ Oscar Delgado's PDF (X.509, no configs)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2003-July/022425.html">
+ Tim Scannell's Windows XP Additional Checklist (X.509)</A>
+<BR></P>
+
+<!-- Note to self: Include L2TP references? -->
+<P><A HREF="http://www.microsoft.com/windows2000/en/server/help/default.asp?url=/windows2000/en/server/help/sag_TCPIP_ovr_secfeatures.htm">
+ Microsoft's page on Win2k TCP/IP security features</A>
+<BR><A HREF="http://support.microsoft.com/support/kb/articles/Q257/2/25.ASP">
+ Microsoft's Win2k IPsec debugging tips</A>
+<BR>
+<!-- Alt-URL http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257225
+Perhaps newer? -->
+<A HREF="http://www.wired.com/news/technology/0,1282,36336,00.html">
+ MS VPN may fall back to 1DES</A></P>
+<P><A HREF="#microsoft.top">Back to chart</A></P>
+<H4><A NAME="ssh">SSH Sentinel</A></H4>
+<UL>
+<LI>Popular and well tested.</LI>
+<LI>Also rebranded in<A HREF="http://www.zyxel.com"> Zyxel Zywall</A>.
+ Our Zyxel interop notes are<A HREF="#zyxel"> here</A>.</LI>
+<LI> SSH supports IPsec-over-UDP NAT traversal.</LI>
+<LI>There is this<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/12/msg00370.html">
+ potential problem</A> if you're not using the Legacy Proposal option.</LI>
+</UL>
+<P><A HREF="http://www.ssh.com/support/sentinel/documents.cfm"> SSH's
+ Sentinel-FreeSWAN interop PDF (X.509)</A>
+<BR><A HREF="http://www.nadmm.com/show.php?story=articles/vpn.inc">
+ Nadeem Hassan's SUSE-to-Sentinel article (Road warrior with X.509)</A>
+<BR><A HREF="http://www.zerozone.it/documents/Linux/HowTo/VPN-IPsec-Freeswan-HOWTO.html">
+ O-Zone's Italian HOWTO (Road Warrior, X.509, DHCP)</A>
+<BR></P>
+<P><A HREF="#ssh.top">Back to chart</A></P>
+<H4><A NAME="safenet">Safenet SoftPK/SoftRemote</A></H4>
+<UL>
+<LI>People recommend SafeNet as a low cost Windows client.</LI>
+<LI>SoftRemote seems to be the newer name for SoftPK.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005061.html">
+ Whit Blauvelt's SoftRemote tips</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015591.html">
+ Tim Wilson's tips (X.509)</A><A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00607.html">
+ Workaround for a &quot;gotcha&quot;</A></P>
+<P><A HREF="http://jixen.tripod.com/#Rw-IRE-to-Fwan"> Jean-Francois
+ Nadeau's Practical Configuration (Road Warrior with PSK)</A>
+<BR><A HREF="http://www.terradoncommunications.com/security/whitepapers/safe_net-to-free_swan.pdf">
+ Terradon Communications' PDF (Road Warrior with PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/?????.html">
+ Seaan.net's PDF (Road Warrior to Subnet, with PSK)</A>
+<BR><A HREF="http://www.redbaronconsulting.com/freeswan/fswansafenet.pdf">
+ Red Baron Consulting's PDF (Road Warrior with X.509)</A></P>
+<P><A HREF="#safenet.top">Back to chart</A></P>
+<H3><A NAME="10_3_2">For<EM> Other Implementations</EM></A></H3>
+<H4><A NAME="6wind">6Wind</A></H4>
+<P><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A></P>
+<P><A HREF="#6wind.top">Back to chart</A></P>
+<H4><A NAME="alcatel">Alcatel Timestep</A></H4>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-June/011878.html">
+ Alain Sabban's settings (PSK or PSK road warrior; through static NAT)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/1999/06/msg00100.html">
+ Derick Cassidy's configs (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/1999/08/msg00194.html">
+ David Kerry's Timestep settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013711.html">
+ Kevin Gerbracht's ipsec.conf (X.509)</A></P>
+<P><A HREF="#alcatel.top">Back to chart</A></P>
+<H4><A NAME="apple">Apple Macintosh System 10+</A></H4>
+<UL>
+<LI>Since the system is based on FreeBSD, this should interoperate<A HREF="#kame">
+ just like FreeBSD</A>.</LI>
+<LI> To use Appletalk over IPsec tunnels,<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005116.html">
+ run it over TCP/IP</A>, or use Open Door Networks' Shareway IP tool,<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005426.html">
+ described here.</A></LI>
+<LI>See also the<A HREF="#equinux"> Equinux VPN Tracker</A> for Mac OS
+ X.</LI>
+</UL>
+<P><A HREF="http://ipsec.math.ucla.edu/services/ipsec.html"> James
+ Carter's instructions (X.509, NAT-T)</A></P>
+<P><A HREF="#apple.top">Back to chart</A></P>
+<H4><A NAME="ashleylaurent">AshleyLaurent VPCom</A></H4>
+<P><A HREF="http://www.ashleylaurent.com/newsletter/01-28-00.htm">
+ Successful interop report, no details</A></P>
+<P><A HREF="#ashleylaurent.top">Back to chart</A></P>
+<H4><A NAME="borderware">Borderware</A></H4>
+<UL>
+<LI>I suspect the Borderware client is a rebranded Safenet. If that's
+ true, our<A HREF="#safenet"> Safenet section</A> will help.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-March/008288.html">
+ Philip Reetz' configs (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/09/msg00217.html">
+ Borderware server does not support FreeS/WAN road warriors</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007733.html">
+ Older Borderware may not support Diffie Hellman groups 2, 5</A>
+<BR></P>
+<P><A HREF="#borderware.top">Back to chart</A></P>
+<H4><A NAME="checkpoint">Check Point VPN-1 or FW-1</A></H4>
+<UL>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00099.html">
+ Caveat about IP-range inclusion on Check Point.</A></LI>
+<LI> Some versions of Check Point may require an aggressive mode patch
+ to interoperate with FreeS/WAN.
+<BR><A HREF="http://www.freeswan.ca/code/super-freeswan"> Super
+ FreeS/WAN</A> now features this patch.
+<!--
+<A HREF="http://www.freeswan.ca/patches/aggressivemode">Steve Harvey's
+aggressive mode patch for FreeS/WAN 1.5</A>
+-->
+</LI>
+<LI></LI>
+<LI>A Linux FreeS/WAN-Checkpoint connection may close after some time.
+ Try<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00293.html">
+ this tip</A> toward a workaround.</LI>
+</UL>
+<P><A HREF="http://www.fw-1.de/aerasec/ng/vpn-freeswan/CPNG+Linux-FreeSWAN.html">
+ AERAsec's Firewall-1 NG site (PSK, X.509, Road Warrior with X.509,
+ other algorithms)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.fw-1.de/aerasec/ng/vpn-freeswan/CPNG+Linux-FreeSWAN.html#support-matrix">
+ AERAsec's detailed Check Point-FreeS/WAN support matrix</A>
+<BR><A HREF="http://support.checkpoint.com/kb/docs/public/firewall1/4_1/pdf/fw-linuxvpn.pdf">
+ Checkpoint.com PDF: Linux as a VPN Client to FW-1 (PSK)</A>
+<BR><A HREF="http://www.phoneboy.com"> PhoneBoy's Check Point FAQ (on
+ Check Point only, not FreeS/WAN)</A>
+<BR></P>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2001-August/002351.html">
+ Chris Harwell's tips FreeS/WAN configs (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009362.html">
+ Daniel Tombeil's configs (PSK)</A></P>
+<P><A HREF="#checkpoint.top">Back to chart</A></P>
+<H4><A NAME="cisco">Cisco</A></H4>
+<UL>
+<LI> Cisco supports IPsec-over-UDP NAT traversal.</LI>
+<LI>Cisco VPN Client appears to use nonstandard IPsec and does not work
+ with FreeS/WAN.<A HREF="https://mj2.freeswan.org/archives/2003-August/maillist.html">
+ This message</A> concerns Cisco VPN Client 4.01.
+<!-- fix link -->
+</LI>
+<LI>A Linux FreeS/WAN-Cisco connection may close after some time.<A HREF="http://lists.freeswan.org/pipermail/users/2001-December/005758.html">
+ Here</A> is a workaround, and<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00293.html">
+ here</A> is another comment on the same subject.</LI>
+<LI><A HREF="http://www.cisco.com/univercd/cc/td/doc/product/software/ios120/120newft/120t/120t2/3desips.htm">
+Older Ciscos</A> purchased outside the United States may not have 3DES,
+ which FreeS/WAN requires.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2001-June/000406.html">
+RSA keying may not be possible between Cisco and FreeS/WAN.</A></LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2001-October/004357.html">
+In ipsec.conf, VPN3000 DN (distinguished name) must be in binary (X.509
+ only)</A></LI>
+</UL>
+<P><A HREF="http://rr.sans.org/encryption/cisco_router.php"> SANS
+ Institute HOWTO (PSK).</A> Detailed, with extensive references.
+<BR><A HREF="http://www.worldbank.ro/IPSEC/cisco-linux.txt"> Short HOWTO
+ (PSK)</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs for Cisco IOS, PIX and VPN 3000 (X.509)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-August/002966.html">
+ Dave McFerren's sample configs (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-September/003422.html">
+ Wolfgang Tremmel's sample configs (PSK road warrior)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00578.html">
+ Old doc from Pete Davis, with William Watson's updated Tips (PSK)</A>
+<BR></P>
+<P><STRONG>Some PIX specific information:</STRONG>
+<BR><A HREF="http://www.wlug.org.nz/FreeSwanToCiscoPix"> Waikato Linux
+ Users' Group HOWTO. Nice detail (PSK)</A>
+<BR><A HREF="http://www.johnleach.co.uk/documents/freeswan-pix/freeswan-pix.html">
+ John Leach's configs (PSK)</A>
+<BR><A HREF="http://www.diverdown.cc/vpn/freeswanpix.html"> Greg
+ Robinson's settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007901.html">
+ Scott's ipsec.conf for PIX (PSK, FreeS/WAN side only)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-October/003949.html">
+ Rick Trimble's PIX and FreeS/WAN settings (PSK)</A>
+<BR></P>
+<P><A href="http://www.cisco.com/public/support/tac"> Cisco VPN support
+ page</A>
+<BR><A href="http://www.ieng.com/warp/public/707/index.shtml#ipsec">
+ Cisco IPsec information page</A></P>
+<P><A HREF="#cisco.top">Back to chart</A></P>
+<H4><A NAME="equinux">Equinux VPN tracker (for Mac OS X)</A></H4>
+<UL>
+<LI>Graphical configurator for Mac OS X IPsec. May be an interface to
+ the<A HREF="#apple"> native Mac OS X IPsec</A>, which is essentially<A HREF="#kame">
+ KAME</A>.</LI>
+<LI>To use Appletalk over IPsec tunnels,<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005116.html">
+ run it over TCP/IP</A>, or use Open Door Networks' Shareway IP tool,<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005426.html">
+ described here.</A></LI>
+</UL>
+<P> Equinux provides<A HREF="http://www.equinux.com/download/HowTo_FreeSWAN.pdf">
+ this excellent interop PDF</A> (PSK, RSA, X.509).</P>
+<P><A HREF="#equinux.top">Back to chart</A></P>
+<H4><A NAME="fsecure">F-Secure</A></H4>
+<UL>
+<LI>
+<!-- <A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007596.html"> -->
+ F-Secure supports IPsec-over-UDP NAT traversal.</LI>
+</UL>
+<P><A HREF="http://www.pingworks.de/tech/vpn/vpn.txt">pingworks.de's
+ &quot;Connecting F-Secure's VPN+ to Linux FreeS/WAN&quot; (PSK road warrior)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.pingworks.de/tech/vpn/vpn.pdf">Same thing
+ as PDF</A>
+<BR><A HREF="http://www.exim.org/pipermail/linux-ipsec/Week-of-Mon-20010122/000061.html">
+ Success report, no detail (PSK)</A>
+<BR><A HREF="http://www.exim.org/pipermail/linux-ipsec/Week-of-Mon-20010122/000041.html">
+ Success report, no detail (Manual)</A></P>
+
+<!-- Other NAT traversers:
+http://lists.freeswan.org/pipermail/users/2002-April/009136.html
+and ssh sentinel:
+http://lists.freeswan.org/pipermail/users/2001-September/003108.html
+-->
+<P><A HREF="#fsecure.top">Back to chart</A></P>
+<H4><A NAME="gauntlet">Gauntlet GVPN</A></H4>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00535.html">
+ Richard Reiner's ipsec.conf (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-June/011434.html">
+ Might work without that pesky firewall... (PSK)</A>
+<BR>
+<!-- insert archive link -->
+ In late July, 2003 Alexandar Antik reported success interoperating
+ with Gauntlet 6.0 for Solaris (X.509). Unfortunately the message is not
+ properly archived at this time.</P>
+<P><A HREF="#gauntlet.top">Back to chart</A></P>
+<H4><A NAME="aix">IBM AIX</A></H4>
+<P><A HREF="http://www-1.ibm.com/servers/esdd/articles/security.html">
+ IBM's &quot;Built-In Network Security with AIX&quot; (PSK, X.509)</A>
+<BR><A HREF="http://www-1.ibm.com/servers/aix/products/ibmsw/security/vpn/faqandtips/#ques20">
+ IBM's tip: importing Linux FreeS/WAN settings into AIX's<VAR> ikedb</VAR>
+ (PSK)</A></P>
+<P><A HREF="#aix.top">Back to chart</A></P>
+<H4><A NAME="as400">IBM AS/400</A></H4>
+<UL>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009106.html">
+ Road Warriors may act flaky</A>.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-September/014264.html">
+ Richard Welty's tips and tricks</A>
+<BR></P>
+<P><A HREF="#as400.top">Back to chart</A></P>
+<H4><A NAME="intel">Intel Shiva LANRover / Net Structure</A></H4>
+<UL>
+<LI>Intel Shiva LANRover is now known as Intel Net Structure.</LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/01/msg00298.html">
+ Shiva seems to have two modes: IPsec or the proprietary &quot;Shiva Tunnel&quot;.</A>
+ Of course, FreeS/WAN will only create IPsec tunnels.</LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00293.html">
+ AH may not work for Shiva-FreeS/WAN.</A> That's OK, since FreeS/WAN has
+ phased out the use of AH.</LI>
+</UL>
+<P><A HREF="http://snowcrash.tdyc.com/freeswan/"> Snowcrash's configs
+ (PSK)</A>
+<BR><A HREF="http://www.opus1.com/vpn/index.html"> Old configs from an
+ interop (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-October/003831.html">
+ The day Shiva tickled a Pluto bug (PSK)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://lists.freeswan.org/pipermail/users/2001-October/004270.html">
+ Follow up: success!</A></P>
+<P><A HREF="#intel.top">Back to chart</A></P>
+<H4><A NAME="lancom">LanCom (formerly ELSA)</A></H4>
+<UL>
+<LI>This router is popular in Germany.</LI>
+</UL>
+<P> Jakob Curdes successfully created a PSK connection with the LanCom
+ 1612 in August 2003.
+<!-- add ML link when it appears -->
+</P>
+<P><A HREF="#lancom.top">Back to chart</A></P>
+<H4><A NAME="linksys">Linksys</A></H4>
+<UL>
+<LI>Linksys may be used as an IPsec tunnel endpoint,<STRONG> OR</STRONG>
+ as a router in &quot;IPsec passthrough&quot; mode, so that the IPsec tunnel
+ passes through the Linksys.</LI>
+</UL>
+<H5>As tunnel endpoint</H5>
+<P><A HREF="http://www.freeswan.ca/docs/BEFVP41/"> Ken Bantoft's
+ instructions (Road Warrior with PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007814.html">
+ Nate Carlson's caveats</A></P>
+<H5>In IPsec passthrough mode</H5>
+<P><A HREF="http://www-ec.njit.edu/~rxt1077/Howto.txt"> Sample HOWTO
+ through a Linksys Router</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2002/02/msg00114.html">
+ Nadeem Hasan's configs</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2002/02/msg00180.html">
+ Brock Nanson's tips</A>
+<BR></P>
+<P><A HREF="#linksys.top">Back to chart</A></P>
+<H4><A NAME="lucent">Lucent</A></H4>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010976.html">
+ Partial success report; see also the next message in thread</A></P>
+
+<!-- section done -->
+<P><A HREF="#lucent.top">Back to chart</A></P>
+<H4><A NAME="netasq">Netasq</A></H4>
+<P><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A></P>
+
+<!-- section done -->
+<P><A HREF="#netasq.top">Back to chart</A></P>
+<H4><A NAME="netcelo">Netcelo</A></H4>
+<P><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A>
+<!-- section done -->
+</P>
+<P><A HREF="#netcelo.top">Back to chart</A></P>
+<H4><A NAME="netgear">Netgear fvs318</A></H4>
+<UL>
+<LI>With a recent Linux FreeS/WAN, you will require the latest (12/2002)
+ Netgear firmware, which supports Diffie-Hellman (DH) group 2. For
+ security reasons, we phased out DH 1 after Linux FreeS/WAN 1.5.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-June/011833.html">
+ This message</A> reports the incompatibility between Linux FreeS/WAN
+ 1.6+ and Netgear fvs318 without the firmware upgrade.</LI>
+<LI>We believe Linux FreeS/WAN 1.5 and earlier will interoperate with
+ any NetGear firmware.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2003-February/017891.html">
+ John Morris' setup (PSK)</A></P>
+<P><A HREF="#netgear.top">Back to chart</A></P>
+<H4><A NAME="netscreen">Netscreen 100 or 5xp</A></H4>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013409.html">
+ Errol Neal's settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015265.html">
+ Corey Rogers' configs (PSK, no PFS)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013051.html">
+ Jordan Share's configs (PSK, 2 subnets, through static NAT)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/08/msg00404.html">
+ Set src proxy_id to your protected subnet/mask</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with ipsec.conf, Netscreen screen shots (X.509, may need to
+ revert to PSK...)</A></P>
+<P><A HREF="http://archives.neohapsis.com/archives/sf/linux/2001-q2/0123.html">
+ A report of a company using Netscreen with FreeS/WAN on a large scale
+ (FreeS/WAN road warriors?)</A></P>
+<P><A HREF="#netscreen.top">Back to chart</A></P>
+<H4><A NAME="nortel">Nortel Contivity</A></H4>
+<UL>
+<LI> Nortel supports IPsec-over-UDP NAT traversal.</LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00417.html">
+ Some older versions of Contivity and FreeS/WAN will not communicate.</A>
+</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010924.html">
+ FreeS/WAN cannot be used as a &quot;client&quot; to a Nortel Contivity server,
+ but can be used as a branch-office tunnel.</A></LI>
+
+<!-- Probably obsoleted by Ken's post
+<LI>
+(Matthias siebler from old interop)
+At one point you could not configure Nortel-FreeS/WAN tunnels as
+"Client Tunnels" since FreeS/WAN does not support Aggressive Mode.
+Current status of this problem: unknown.
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/004612.html">
+How do we map group and user passwords onto the data that FreeS/WAN wants?
+</A>
+</LI>
+-->
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015455.html">
+ Contivity does not send Distinguished Names in the order FS wants them
+ (X.509).</A></LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/03/msg00137.html">
+ Connections may time out after 30-40 minutes idle.</A></LI>
+</UL>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/03/msg00137.html">
+ JJ Streicher-Bremer's mini HOWTO for old new software. (PSK with two
+ subnets)</A>
+<BR><A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+ French page with configs (X.509)</A>. This succeeds using the above
+ X.509 tip.</P>
+
+<!-- I could do more searching but this is a solid start. -->
+<P><A HREF="#nortel.top">Back to chart</A></P>
+<H4><A NAME="radguard">Radguard</A></H4>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/05/msg00009.html">
+ Marko Hausalo's configs (PSK).</A> Note: These do create a connection,
+ as you can see by &quot;IPsec SA established&quot;.
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/???.html">
+ Claudia Schmeing's comments</A></P>
+<P><A HREF="#radguard.top">Back to chart</A></P>
+<H4><A NAME="raptor">Raptor (NT or Solaris)</A></H4>
+<P></P>
+<UL>
+<LI>Now known as Symantec Enterprise Firewall.</LI>
+<LI>The Raptor does not normally come with X.509, but this may be
+ available as an add-on.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010256.html">
+ Raptor requires alphanumberic PSK values, whereas FreeS/WAN uses hex.</A>
+</LI>
+<LI>Raptor's tunnel endpoint may be a host, subnet or group of subnets
+ (see<A HREF="http://lists.freeswan.org/pipermail/design/2001-November/001295.html">
+ this message</A> ). FreeS/WAN cannot handle the group of subnets; you
+ must create separate connections for each in order to interoperate.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010113.html">
+ Some versions of Raptor accept only single DES.</A> According to this
+ German message,<A HREF="http://radawana.cg.tuwien.ac.at/mail-archives/lll/200012/msg00065.html">
+ the Raptor Mobile Client demo offers single DES only.</A></LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-January/006935.html">
+ Peter Mazinger's settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005522.html">
+ Peter Gerland's configs (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/07/msg00597.html">
+ Charles Griebel's configs (PSK).</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-July/012275.html">
+ Lumir Srch's tips (PSK)</A></P>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/05/msg00214.html">
+ John Hardy's configs (Manual)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/01/msg00236.html">
+ Older Raptors want 3DES keys in 3 parts (Manual).</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/06/msg00480.html">
+ Different keys for each direction? (Manual)</A>
+<BR></P>
+<P><A HREF="#raptor.top">Back to chart</A></P>
+<H4><A NAME="redcreek">Redcreek Ravlin</A></H4>
+<UL>
+<LI>Known issue #1: The Ravlin expects a quick mode renegotiation right
+ after every Main Mode negotiation.</LI>
+<LI> Known issue #2: The Ravlin tries to negotiate a zero connection
+ lifetime, which it takes to mean &quot;infinite&quot;.<A HREF="http://www.bear-cave.org.uk/linux/ravlin/">
+ Jim Hague's patch</A> addresses both issues.</LI>
+<LI><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/03/msg00191.html">
+ Interop works with Ravlin Firmware &gt; 3.33. Includes tips (PSK).</A></LI>
+</UL>
+<P><A HREF="#redcreek.top">Back to chart</A></P>
+<H4><A NAME="sonicwall">SonicWall</A></H4>
+<UL>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2001-June/000998.html">
+ Sonicwall cannot be used for Road Warrior setups</A></LI>
+<LI> At one point,<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/05/msg00217.html">
+ only Sonicwall PRO supported triple DES</A>.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-March/008600.html">
+ Older Sonicwalls (before Nov 2001) feature Diffie Hellman group 1 only</A>
+.</LI>
+</UL>
+<P><A HREF="http://www.xinit.cx/docs/freeswan.html"> Paul Wouters'
+ config (PSK)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00073.html">
+ Dilan Arumainathan's configuration (PSK)</A>
+<BR><A HREF="http://www.gravitas.co.uk/vpndebug"> Dariush's setup...
+ only opens one way (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2003-July/022302.html">
+ Andreas Steffen's tips (X.509)</A>
+<BR></P>
+<P><A HREF="#sonicwall.top">Back to chart</A></P>
+<H4><A NAME="sun">Sun Solaris</A></H4>
+<UL>
+<LI> Solaris 8+ has a native (in kernel) IPsec implementation.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010503.html">
+ Solaris does not seem to support tunnel mode, but you can make IP-in-IP
+ tunnels instead, like this.</A></LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2003-June/022216.html">
+ Reports of some successful interops</A> from a fellow @sun.com. See
+ also<A HREF="http://lists.freeswan.org/pipermail/users/2003-July/022247.html">
+ these follow up posts</A>.
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/03/msg00332.html">
+ Aleks Shenkman's configs (Manual in transport mode)</A>
+<BR>
+<!--sparc 64 stuff goes where?-->
+</P>
+<P><A HREF="#solaris.top">Back to chart</A></P>
+<H4><A NAME="symantec">Symantec</A></H4>
+<UL>
+<LI>The Raptor, covered<A HREF="#raptor"> above</A>, is now known as
+ Symantec Enterprise Firewall.</LI>
+<LI>Symantec's &quot;distinguished name&quot; is a KEY_ID. See Andreas Steffen's
+ post, below.</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009037.html">
+ Andreas Steffen's configs for Symantec 200R (PSK)</A></P>
+<P><A HREF="#symantec.top">Back to chart</A></P>
+<H4><A NAME="watchguard">Watchguard Firebox</A></H4>
+<UL>
+<LI>Automatic keying works with WatchGuard 5.0+ only.</LI>
+<LI>Seen to interoperate with WatchGuard 1000, II, III; firmware v. 5,
+ 6..</LI>
+<LI>For manual keying, Watchguard's Policy Manager expects SPI numbers
+ and encryption and authentication keys in decimal (not hex).</LI>
+</UL>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-July/012595.html">
+ WatchGuard's HOWTO (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013342.html">
+ Ronald C. Riviera's Settings (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00179.html">
+ Walter Wickersham's Notes (PSK)</A>
+<BR><A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015587.html">
+ Max Enders' Configs (Manual)</A></P>
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009404.html">
+ Old known issue with auto keying</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00124.html">
+ Tips on key generation and format (Manual)</A>
+<BR></P>
+<P><A HREF="#watchguard.top">Back to chart</A></P>
+<H4><A NAME="xedia">Xedia Access Point/QVPN</A></H4>
+<P><A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/12/msg00520.html">
+ Hybrid IPsec/L2TP connection settings (X.509)</A>
+<BR><A HREF="http://www.sandelman.ottawa.on.ca/ipsec/1999/08/msg00140.html">
+ Xedia's LAN-LAN links don't use multiple tunnels</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.sandelman.ottawa.on.ca/ipsec/1999/08/msg00140.html">
+ That explanation, continued</A></P>
+<P><A HREF="#xedia.top">Back to chart</A></P>
+<H4><A NAME="zyxel">Zyxel</A></H4>
+<UL>
+<LI>The Zyxel Zywall is a rebranded SSH Sentinel box. See also our
+ section on<A HREF="glossary.html#ssh"> SSH</A>.</LI>
+<LI>There seems to be a problem with keeping this connection alive. This
+ is caused at the Zyxel end. See this brief<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00141.html">
+ discussion and solution.</A></LI>
+</UL>
+<P><A HREF="http://www.zyxel.com/support/supportnote/zywall/app/zw_freeswan.htm">
+ Zyxel's Zywall to FreeS/WAN instructions (PSK)</A>
+<BR><A HREF="http://www.zyxel.com/support/supportnote/p652/app/zw_freeswan.htm">
+ Zyxel's Prestige to FreeS/WAN instructions (PSK)</A>. Note: not all
+ Prestige versions include VPN software.
+<BR><A HREF="http://www.lancry.net/techdocs/freeswan-zyxel.txt"> Fabrice
+ Cahen's HOWTO (PSK)</A>
+<BR> &nbsp;&nbsp;&nbsp;&nbsp;</P>
+<P><A HREF="#zyxel.top">Back to chart</A></P>
+
+<!-- SAMPLE ENTRY
+
+<H4><A NAME="timestep">Timestep</A></H4>
+
+<P>Text goes here.
+</P>
+
+-->
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="compat.html">Previous</A>
+<A HREF="performance.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/intro.html b/doc/intro.html
new file mode 100644
index 000000000..3afc3e324
--- /dev/null
+++ b/doc/intro.html
@@ -0,0 +1,733 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="upgrading.html">Next</A>
+<HR>
+<H1><A name="intro">Introduction</A></H1>
+<P>This section gives an overview of:</P>
+<UL>
+<LI>what IP Security (IPsec) does</LI>
+<LI>how IPsec works</LI>
+<LI>why we are implementing it for Linux</LI>
+<LI>how this implementation works</LI>
+</UL>
+<P>This section is intended to cover only the essentials,<EM> things you
+ should know before trying to use FreeS/WAN.</EM></P>
+<P>For more detailed background information, see the<A href="politics.html#politics">
+ history and politics</A> and<A href="ipsec.html#ipsec.detail"> IPsec
+ protocols</A> sections.</P>
+<H2><A name="ipsec.intro">IPsec, Security for the Internet Protocol</A></H2>
+<P>FreeS/WAN is a Linux implementation of the IPsec (IP security)
+ protocols. IPsec provides<A href="glossary.html#encryption"> encryption</A>
+ and<A href="glossary.html#authentication"> authentication</A> services
+ at the IP (Internet Protocol) level of the network protocol stack.</P>
+<P>Working at this level, IPsec can protect any traffic carried over IP,
+ unlike other encryption which generally protects only a particular
+ higher-level protocol --<A href="glossary.html#PGP"> PGP</A> for mail,<A
+href="glossary.html#SSH"> SSH</A> for remote login,<A href="glossary.html#SSL">
+ SSL</A> for web work, and so on. This approach has both considerable
+ advantages and some limitations. For discussion, see our<A href="ipsec.html#others">
+ IPsec section</A></P>
+<P>IPsec can be used on any machine which does IP networking. Dedicated
+ IPsec gateway machines can be installed wherever required to protect
+ traffic. IPsec can also run on routers, on firewall machines, on
+ various application servers, and on end-user desktop or laptop
+ machines.</P>
+<P>Three protocols are used</P>
+<UL>
+<LI><A href="glossary.html#AH">AH</A> (Authentication Header) provides a
+ packet-level authentication service</LI>
+<LI><A href="glossary.html#ESP">ESP</A> (Encapsulating Security Payload)
+ provides encryption plus authentication</LI>
+<LI><A href="glossary.html#IKE">IKE</A> (Internet Key Exchange)
+ negotiates connection parameters, including keys, for the other two</LI>
+</UL>
+<P>Our implementation has three main parts:</P>
+<UL>
+<LI><A href="glossary.html#KLIPS">KLIPS</A> (kernel IPsec) implements
+ AH, ESP, and packet handling within the kernel</LI>
+<LI><A href="glossary.html#Pluto">Pluto</A> (an IKE daemon) implements
+ IKE, negotiating connections with other systems</LI>
+<LI>various scripts provide an adminstrator's interface to the machinery</LI>
+</UL>
+<P>IPsec is optional for the current (version 4) Internet Protocol.
+ FreeS/WAN adds IPsec to the Linux IPv4 network stack. Implementations
+ of<A href="glossary.html#ipv6.gloss"> IP version 6</A> are required to
+ include IPsec. Work toward integrating FreeS/WAN into the Linux IPv6
+ stack has<A href="compat.html#ipv6"> started</A>.</P>
+<P>For more information on IPsec, see our<A href="ipsec.html#ipsec.detail">
+ IPsec protocols</A> section, our collection of<A href="web.html#ipsec.link">
+ IPsec links</A> or the<A href="rfc.html#RFC"> RFCs</A> which are the
+ official definitions of these protocols.</P>
+<H3><A name="intro.interop">Interoperating with other IPsec
+ implementations</A></H3>
+<P>IPsec is designed to let different implementations work together. We
+ provide:</P>
+<UL>
+<LI>a<A href="web.html#implement"> list</A> of some other
+ implementations</LI>
+<LI>information on<A href="interop.html#interop"> using FreeS/WAN with
+ other implementations</A></LI>
+</UL>
+<P>The VPN Consortium fosters cooperation among implementers and
+ interoperability among implementations. Their<A href="http://www.vpnc.org/">
+ web site</A> has much more information.</P>
+<H3><A name="advantages">Advantages of IPsec</A></H3>
+<P>IPsec has a number of security advantages. Here are some
+ independently written articles which discuss these:</P>
+<P><A HREF="http://www.sans.org/rr/"> SANS institute papers</A>. See the
+ section on Encryption &amp;VPNs.
+<BR><A HREF="http://www.cisco.com/en/US/netsol/ns110/ns170/ns171/ns128/networking_solutions_white_papers_list.html">
+ Cisco's white papers on &quot;Networking Solutions&quot;</A>.
+<BR><A HREF="http://iscs.sourceforge.net/HowWhyBrief/HowWhyBrief.html">
+ Advantages of ISCS (Linux Integrated Secure Communications System;
+ includes FreeS/WAN and other software)</A>.</P>
+<H3><A name="applications">Applications of IPsec</A></H3>
+<P>Because IPsec operates at the network layer, it is remarkably
+ flexible and can be used to secure nearly any type of Internet traffic.
+ Two applications, however, are extremely widespread:</P>
+<UL>
+<LI>a<A href="glossary.html#VPN"> Virtual Private Network</A>, or VPN,
+ allows multiple sites to communicate securely over an insecure Internet
+ by encrypting all communication between the sites.</LI>
+<LI>&quot;Road Warriors&quot; connect to the office from home, or perhaps from a
+ hotel somewhere</LI>
+</UL>
+<P>There is enough opportunity in these applications that vendors are
+ flocking to them. IPsec is being built into routers, into firewall
+ products, and into major operating systems, primarily to support these
+ applications. See our<A href="web.html#implement"> list</A> of
+ implementations for details.</P>
+<P>We support both of those applications, and various less common IPsec
+ applications as well, but we also add one of our own:</P>
+<UL>
+<LI>opportunistic encryption, the ability to set up FreeS/WAN gateways
+ so that any two of them can encrypt to each other, and will do so
+ whenever packets pass between them.</LI>
+</UL>
+<P>This is an extension we are adding to the protocols. FreeS/WAN is the
+ first prototype implementation, though we hope other IPsec
+ implementations will adopt the technique once we demonstrate it. See<A href="#goals">
+ project goals</A> below for why we think this is important.</P>
+<P>A somewhat more detailed description of each of these applications is
+ below. Our<A href="quickstart.html#quick_guide"> quickstart</A> section
+ will show you how to build each of them.</P>
+<H4><A name="makeVPN">Using secure tunnels to create a VPN</A></H4>
+<P>A VPN, or<STRONG> V</STRONG>irtual<STRONG> P</STRONG>rivate<STRONG> N</STRONG>
+etwork lets two networks communicate securely when the only connection
+ between them is over a third network which they do not trust.</P>
+<P>The method is to put a security gateway machine between each of the
+ communicating networks and the untrusted network. The gateway machines
+ encrypt packets entering the untrusted net and decrypt packets leaving
+ it, creating a secure tunnel through it.</P>
+<P>If the cryptography is strong, the implementation is careful, and the
+ administration of the gateways is competent, then one can reasonably
+ trust the security of the tunnel. The two networks then behave like a
+ single large private network, some of whose links are encrypted tunnels
+ through untrusted nets.</P>
+<P>Actual VPNs are often more complex. One organisation may have fifty
+ branch offices, plus some suppliers and clients, with whom it needs to
+ communicate securely. Another might have 5,000 stores, or 50,000
+ point-of-sale devices. The untrusted network need not be the Internet.
+ All the same issues arise on a corporate or institutional network
+ whenever two departments want to communicate privately with each other.</P>
+<P>Administratively, the nice thing about many VPN setups is that large
+ parts of them are static. You know the IP addresses of most of the
+ machines involved. More important, you know they will not change on
+ you. This simplifies some of the admin work. For cases where the
+ addresses do change, see the next section.</P>
+<H4><A name="road.intro">Road Warriors</A></H4>
+<P>The prototypical &quot;Road Warrior&quot; is a traveller connecting to home
+ base from a laptop machine. Administratively, most of the same problems
+ arise for a telecommuter connecting from home to the office, especially
+ if the telecommuter does not have a static IP address.</P>
+<P>For purposes of this document:</P>
+<UL>
+<LI>anyone with a dynamic IP address is a &quot;Road Warrior&quot;.</LI>
+<LI>any machine doing IPsec processing is a &quot;gateway&quot;. Think of the
+ single-user road warrior machine as a gateway with a degenerate subnet
+ (one machine, itself) behind it.</LI>
+</UL>
+<P>These require somewhat different setup than VPN gateways with static
+ addresses and with client systems behind them, but are basically not
+ problematic.</P>
+<P>There are some difficulties which appear for some road warrior
+ connections:</P>
+<UL>
+<LI>Road Wariors who get their addresses via DHCP may have a problem.
+ FreeS/WAN can quite happily build and use a tunnel to such an address,
+ but when the DHCP lease expires, FreeS/WAN does not know that. The
+ tunnel fails, and the only recovery method is to tear it down and
+ re-build it.</LI>
+<LI>If<A href="glossary.html#NAT.gloss"> Network Address Translation</A>
+ (NAT) is applied between the two IPsec Gateways, this breaks IPsec.
+ IPsec authenticates packets on an end-to-end basis, to ensure they are
+ not altered en route. NAT rewrites packets as they go by. See our<A href="firewall.html#NAT">
+ firewalls</A> document for details.</LI>
+</UL>
+<P>In most situations, however, FreeS/WAN supports road warrior
+ connections just fine.</P>
+<H4><A name="opp.intro">Opportunistic encryption</A></H4>
+<P>One of the reasons we are working on FreeS/WAN is that it gives us
+ the opportunity to add what we call opportuntistic encryption. This
+ means that any two FreeS/WAN gateways will be able to encrypt their
+ traffic, even if the two gateway administrators have had no prior
+ contact and neither system has any preset information about the other.</P>
+<P>Both systems pick up the authentication information they need from
+ the<A href="glossary.html#DNS"> DNS</A> (domain name service), the
+ service they already use to look up IP addresses. Of course the
+ administrators must put that information in the DNS, and must set up
+ their gateways with opportunistic encryption enabled. Once that is
+ done, everything is automatic. The gateways look for opportunities to
+ encrypt, and encrypt whatever they can. Whether they also accept
+ unencrypted communication is a policy decision the administrator can
+ make.</P>
+<P>This technique can give two large payoffs:</P>
+<UL>
+<LI>It reduces the administrative overhead for IPsec enormously. You
+ configure your gateway and thereafter everything is automatic. The need
+ to configure the system on a per-tunnel basis disappears. Of course,
+ FreeS/WAN allows specifically configured tunnels to co-exist with
+ opportunistic encryption, but we hope to make them unnecessary in most
+ cases.</LI>
+<LI>It moves us toward a more secure Internet, allowing users to create
+ an environment where message privacy is the default. All messages can
+ be encrypted, provided the other end is willing to co-operate. See our<A
+href="politics.html#politics"> history and politics of cryptography</A>
+ section for discussion of why we think this is needed.</LI>
+</UL>
+<P>Opportunistic encryption is not (yet?) a standard part of the IPsec
+ protocols, but an extension we are proposing and demonstrating. For
+ details of our design, see<A href="#applied"> links</A> below.</P>
+<P>Only one current product we know of implements a form of
+ opportunistic encryption.<A href="web.html#ssmail"> Secure sendmail</A>
+ will automatically encrypt server-to-server mail transfers whenever
+ possible.</P>
+<H3><A name="types">The need to authenticate gateways</A></H3>
+<P>A complication, which applies to any type of connection -- VPN, Road
+ Warrior or opportunistic -- is that a secure connection cannot be
+ created magically.<EM> There must be some mechanism which enables the
+ gateways to reliably identify each other.</EM> Without this, they
+ cannot sensibly trust each other and cannot create a genuinely secure
+ link.</P>
+<P>Any link they do create without some form of<A href="glossary.html#authentication">
+ authentication</A> will be vulnerable to a<A href="glossary.html#middle">
+ man-in-the-middle attack</A>. If<A href="glossary.html#alicebob"> Alice
+ and Bob</A> are the people creating the connection, a villian who can
+ re-route or intercept the packets can pose as Alice while talking to
+ Bob and pose as Bob while talking to Alice. Alice and Bob then both
+ talk to the man in the middle, thinking they are talking to each other,
+ and the villain gets everything sent on the bogus &quot;secure&quot; connection.</P>
+<P>There are two ways to build links securely, both of which exclude the
+ man-in-the middle:</P>
+<UL>
+<LI>with<STRONG> manual keying</STRONG>, Alice and Bob share a secret
+ key (which must be transmitted securely, perhaps in a note or via PGP
+ or SSH) to encrypt their messages. For FreeS/WAN, such keys are stored
+ in the<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> file. Of
+ course, if an enemy gets the key, all is lost.</LI>
+<LI>with<STRONG> automatic keying</STRONG>, the two systems authenticate
+ each other and negotiate their own secret keys. The keys are
+ automatically changed periodically.</LI>
+</UL>
+<P>Automatic keying is much more secure, since if an enemy gets one key
+ only messages between the previous re-keying and the next are exposed.
+ It is therefore the usual mode of operation for most IPsec deployment,
+ and the mode we use in our setup examples. FreeS/WAN does support
+ manual keying for special circumstanes. See this<A href="adv_config.html#prodman">
+ section</A>.</P>
+<P>For automatic keying, the two systems must authenticate each other
+ during the negotiations. There is a choice of methods for this:</P>
+<UL>
+<LI>a<STRONG> shared secret</STRONG> provides authentication. If Alice
+ and Bob are the only ones who know a secret and Alice recives a message
+ which could not have been created without that secret, then Alice can
+ safely believe the message came from Bob.</LI>
+<LI>a<A href="glossary.html#public"> public key</A> can also provide
+ authentication. If Alice receives a message signed with Bob's private
+ key (which of course only he should know) and she has a trustworthy
+ copy of his public key (so that she can verify the signature), then she
+ can safely believe the message came from Bob.</LI>
+</UL>
+<P>Public key techniques are much preferable, for reasons discussed<A href="config.html#choose">
+ later</A>, and will be used in all our setup examples. FreeS/WAN does
+ also support auto-keying with shared secret authentication. See this<A href="adv_config.html#prodsecrets">
+ section</A>.</P>
+<H2><A name="project">The FreeS/WAN project</A></H2>
+<P>For complete information on the project, see our web site,<A href="http://liberty.freeswan.org">
+ freeswan.org</A>.</P>
+<P>In summary, we are implementing the<A href="glossary.html#IPsec">
+ IPsec</A> protocols for Linux and extending them to do<A href="glossary.html#carpediem">
+ opportunistic encryption</A>.</P>
+<H3><A name="goals">Project goals</A></H3>
+<P>Our overall goal in FreeS/WAN is to make the Internet more secure and
+ more private.</P>
+<P>Our IPsec implementation supports VPNs and Road Warriors of course.
+ Those are important applications. Many users will want FreeS/WAN to
+ build corporate VPNs or to provide secure remote access.</P>
+<P>However, our goals in building it go beyond that. We are trying to
+ help<STRONG> build security into the fabric of the Internet</STRONG> so
+ that anyone who choses to communicate securely can do so, as easily as
+ they can do anything else on the net.</P>
+<P>More detailed objectives are:</P>
+<UL>
+<LI>extend IPsec to do<A href="glossary.html#carpediem"> opportunistic
+ encryption</A> so that
+<UL>
+<LI>any two systems can secure their communications without a
+ pre-arranged connection</LI>
+<LI><STRONG>secure connections can be the default</STRONG>, falling back
+ to unencrypted connections only if:
+<UL>
+<LI><EM>both</EM> the partner is not set up to co-operate on securing
+ the connection</LI>
+<LI><EM>and</EM> your policy allows insecure connections</LI>
+</UL>
+</LI>
+<LI>a significant fraction of all Internet traffic is encrypted</LI>
+<LI>wholesale monitoring of the net (<A href="politics.html#intro.poli">
+examples</A>) becomes difficult or impossible</LI>
+</UL>
+</LI>
+<LI>help make IPsec widespread by providing an implementation with no
+ restrictions:
+<UL>
+<LI>freely available in source code under the<A href="glossary.html#GPL">
+ GNU General Public License</A></LI>
+<LI>running on a range of readily available hardware</LI>
+<LI>not subject to US or other nations'<A href="politics.html#exlaw">
+ export restrictions</A>.
+<BR> Note that in order to avoid<EM> even the appearance</EM> of being
+ subject to those laws, the project cannot accept software contributions
+ --<EM> not even one-line bug fixes</EM> -- from US residents or
+ citizens.</LI>
+</UL>
+</LI>
+<LI>provide a high-quality IPsec implementation for Linux
+<UL>
+<LI>portable to all CPUs Linux supports:<A href="compat.html#CPUs">
+ (current list)</A></LI>
+<LI>interoperable with other IPsec implementations:<A href="interop.html#interop">
+ (current list)</A></LI>
+</UL>
+</LI>
+</UL>
+<P>If we can get opportunistic encryption implemented and widely
+ deployed, then it becomes impossible for even huge well-funded agencies
+ to monitor the net.</P>
+<P>See also our section on<A href="politics.html#politics"> history and
+ politics</A> of cryptography, which includes our project leader's<A href="politics.html#gilmore">
+ rationale</A> for starting the project.</P>
+<H3><A name="staff">Project team</A></H3>
+<P>Two of the team are from the US and can therefore contribute no code:</P>
+<UL>
+<LI>John Gilmore: founder and policy-maker (<A href="http://www.toad.com/gnu/">
+home page</A>)</LI>
+<LI>Hugh Daniel: project manager, Most Demented Tester, and occasionally
+ Pointy-Haired Boss</LI>
+</UL>
+<P>The rest of the team are Canadians, working in Canada. (<A href="politics.html#status">
+Why Canada?</A>)</P>
+<UL>
+<LI>Hugh Redelmeier:<A href="glossary.html#Pluto"> Pluto daemon</A>
+ programmer</LI>
+<LI>Richard Guy Briggs:<A href="glossary.html#KLIPS"> KLIPS</A>
+ programmer</LI>
+<LI>Michael Richardson: hacker without portfolio</LI>
+<LI>Claudia Schmeing: documentation</LI>
+<LI>Sam Sgro: technical support via the<A href="mail.html#lists">
+ mailing lists</A></LI>
+</UL>
+<P>The project is funded by civil libertarians who consider our goals
+ worthwhile. Most of the team are paid for this work.</P>
+<P>People outside this core team have made substantial contributions.
+ See</P>
+<UL>
+<LI>our<A href="../CREDITS"> CREDITS</A> file</LI>
+<LI>the<A href="web.html#patch"> patches and add-ons</A> section of our
+ web references file</LI>
+<LI>lists below of user-written<A href="#howto"> HowTos</A> and<A href="#applied">
+ other papers</A></LI>
+</UL>
+<P>Additional contributions are welcome. See the<A href="faq.html#contrib.faq">
+ FAQ</A> for details.</P>
+<H2><A name="products">Products containing FreeS/WAN</A></H2>
+<P>Unfortunately the<A href="politics.html#exlaw"> export laws</A> of
+ some countries restrict the distribution of strong cryptography.
+ FreeS/WAN is therefore not in the standard Linux kernel and not in all
+ CD or web distributions.</P>
+<P>FreeS/WAN is, however, quite widely used. Products we know of that
+ use it are listed below. We would appreciate hearing, via the<A href="mail.html#lists">
+ mailing lists</A>, of any we don't know of.</P>
+<H3><A name="distwith">Full Linux distributions</A></H3>
+<P>FreeS/WAN is included in various general-purpose Linux distributions,
+ mostly from countries (shown in brackets) with more sensible laws:</P>
+<UL>
+<LI><A href="http://www.suse.com/">SuSE Linux</A> (Germany)</LI>
+<LI><A href="http://www.conectiva.com">Conectiva</A> (Brazil)</LI>
+<LI><A href="http://www.linux-mandrake.com/en/">Mandrake</A> (France)</LI>
+<LI><A href="http://www.debian.org">Debian</A></LI>
+<LI>the<A href="http://www.pld.org.pl/"> Polish(ed) Linux Distribution</A>
+ (Poland)</LI>
+<LI><A>Best Linux</A> (Finland)</LI>
+</UL>
+<P>For distributions which do not include FreeS/WAN and are not Redhat
+ (which we develop and test on), there is additional information in our<A
+href="compat.html#otherdist"> compatibility</A> section.</P>
+<P>The server edition of<A href="http://www.corel.com"> Corel</A> Linux
+ (Canada) also had FreeS/WAN, but Corel have dropped that product line.</P>
+<H3><A name="kernel_dist">Linux kernel distributions</A></H3>
+<UL>
+<LI><A href="http://sourceforge.net/projects/wolk/">Working Overloaded
+ Linux Kernel (WOLK)</A></LI>
+</UL>
+<H3><A name="office_dist">Office server distributions</A></H3>
+<P>FreeS/WAN is also included in several distributions aimed at the
+ market for turnkey business servers:</P>
+<UL>
+<LI><A href="http://www.e-smith.com/">e-Smith</A> (Canada), which has
+ recently been acquired and become the Network Server Solutions group of<A
+href="http://www.mitel.com/"> Mitel Networks</A> (Canada)</LI>
+<LI><A href="http://www.clarkconnect.org/">ClarkConnect</A> from Point
+ Clark Networks (Canada)</LI>
+<LI><A href="http://www.trustix.net/">Trustix Secure Linux</A> (Norway)</LI>
+</UL>
+<H3><A name="fw_dist">Firewall distributions</A></H3>
+<P>Several distributions intended for firewall and router applications
+ include FreeS/WAN:</P>
+<UL>
+<LI>The<A href="http://www.linuxrouter.org/"> Linux Router Project</A>
+ produces a Linux distribution that will boot from a single floppy. The<A
+href="http://leaf.sourceforge.net"> LEAF</A> firewall project provides
+ several different LRP-based firewall packages. At least one of them,
+ Charles Steinkuehler's Dachstein, includes FreeS/WAN with X.509
+ patches.</LI>
+<LI>there are several distributions bootable directly from CD-ROM,
+ usable on a machine without hard disk.
+<UL>
+<LI>Dachstein (see above) can be used this way</LI>
+<LI><A href="http://www.gibraltar.at/">Gibraltar</A> is based on Debian
+ GNU/Linux.</LI>
+<LI>at time of writing,<A href="www.xiloo.com"> Xiloo</A> is available
+ only in Chinese. An English version is expected.</LI>
+</UL>
+</LI>
+<LI><A href="http://www.astaro.com/products/index.html">Astaro Security
+ Linux</A> includes FreeS/WAN. It has some web-based tools for managing
+ the firewall that include FreeS/WAN configuration management.</LI>
+<LI><A href="http://www.linuxwall.de">Linuxwall</A></LI>
+<LI><A href="http://www.smoothwall.org/">Smoothwall</A></LI>
+<LI><A href="http://www.devil-linux.org/">Devil Linux</A></LI>
+<LI>Coyote Linux has a<A href="http://embedded.coyotelinux.com/wolverine/index.php">
+ Wolverine</A> firewall/VPN server</LI>
+</UL>
+<P>There are also several sets of scripts available for managing a
+ firewall which is also acting as a FreeS/WAN IPsec gateway. See this<A href="firewall.html#rules.pub">
+ list</A>.</P>
+<H3><A name="turnkey">Firewall and VPN products</A></H3>
+<P>Several vendors use FreeS/WAN as the IPsec component of a turnkey
+ firewall or VPN product.</P>
+<P>Software-only products:</P>
+<UL>
+<LI><A href="http://www.linuxmagic.com/vpn/index.html">Linux Magic</A>
+ offer a VPN/Firewall product using FreeS/WAN</LI>
+<LI>The Software Group's<A href="http://www.wanware.com/sentinet/">
+ Sentinet</A> product uses FreeS/WAN</LI>
+<LI><A href="http://www.merilus.com">Merilus</A> use FreeS/WAN in their
+ Gateway Guardian firewall product</LI>
+</UL>
+<P>Products that include the hardware:</P>
+<UL>
+<LI>The<A href="http://www.lasat.com"> LASAT SafePipe[tm]</A> series. is
+ an IPsec box based on an embedded MIPS running Linux with FreeS/WAN and
+ a web-config front end. This company also host our freeswan.org web
+ site.</LI>
+<LI>Merilus<A href="http://www.merilus.com/products/fc/index.shtml">
+ Firecard</A> is a Linux firewall on a PCI card.</LI>
+<LI><A href="http://www.kyzo.com/">Kyzo</A> have a &quot;pizza box&quot; product
+ line with various types of server, all running from flash. One of them
+ is an IPsec/PPTP VPN server</LI>
+<LI><A href="http://www.pfn.com">PFN</A> use FreeS/WAN in some of their
+ products</LI>
+</UL>
+<P><A href="www.rebel.com">Rebel.com</A>, makers of the Netwinder Linux
+ machines (ARM or Crusoe based), had a product that used FreeS/WAN. The
+ company is in receivership so the future of the Netwinder is at best
+ unclear.<A href="web.html#patch"> PKIX patches</A> for FreeS/WAN
+ developed at Rebel are listed in our web links document.</P>
+<H2><A name="docs">Information sources</A></H2>
+<H3><A name="docformats">This HowTo, in multiple formats</A></H3>
+<P>FreeS/WAN documentation up to version 1.5 was available only in HTML.
+ Now we ship two formats:</P>
+<UL>
+<LI>as HTML, one file for each doc section plus a global<A href="toc.html">
+ Table of Contents</A></LI>
+<LI><A href="HowTo.html">one big HTML file</A> for easy searching</LI>
+</UL>
+<P>and provide a Makefile to generate other formats if required:</P>
+<UL>
+<LI><A href="HowTo.pdf">PDF</A></LI>
+<LI><A href="HowTo.ps">Postscript</A></LI>
+<LI><A href="HowTo.txt">ASCII text</A></LI>
+</UL>
+<P>The Makefile assumes the htmldoc tool is available. You can download
+ it from<A href="http://www.easysw.com"> Easy Software</A>.</P>
+<P>All formats should be available at the following websites:</P>
+<UL>
+<LI><A href="http://www.freeswan.org/doc.html">FreeS/WAN project</A></LI>
+<LI><A href="http://www.linuxdoc.org">Linux Documentation Project</A></LI>
+</UL>
+<P>The distribution tarball has only the two HTML formats.</P>
+<P><STRONG>Note:</STRONG> If you need the latest doc version, for
+ example to see if anyone has managed to set up interoperation between
+ FreeS/WAN and whatever, then you should download the current snapshot.
+ What is on the web is documentation as of the last release. Snapshots
+ have all changes I've checked in to date.</P>
+<H3><A name="rtfm">RTFM (please Read The Fine Manuals)</A></H3>
+<P>As with most things on any Unix-like system, most parts of Linux
+ FreeS/WAN are documented in online manual pages. We provide a list of<A href="/mnt/floppy/manpages.html">
+ FreeS/WAN man pages</A>, with links to HTML versions of them.</P>
+<P>The man pages describing configuration files are:</P>
+<UL>
+<LI><A href="/mnt/floppy/manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A></LI>
+<LI><A href="/mnt/floppy/manpage.d/ipsec.secrets.5.html">
+ipsec.secrets(5)</A></LI>
+</UL>
+<P>Man pages for common commands include:</P>
+<UL>
+<LI><A href="/mnt/floppy/manpage.d/ipsec.8.html">ipsec(8)</A></LI>
+<LI><A href="/mnt/floppy/manpage.d/ipsec_pluto.8.html">ipsec_pluto(8)</A>
+</LI>
+<LI><A href="/mnt/floppy/manpage.d/ipsec_newhostkey.8.html">
+ipsec_newhostkey(8)</A></LI>
+<LI><A href="/mnt/floppy/manpage.d/ipsec_auto.8.html">ipsec_auto(8)</A></LI>
+</UL>
+<P>You can read these either in HTML using the links above or with the<VAR>
+ man(1)</VAR> command.</P>
+<P>In the event of disagreement between this HTML documentation and the
+ man pages, the man pages are more likely correct since they are written
+ by the implementers. Please report any such inconsistency on the<A href="mail.html#lists">
+ mailing list</A>.</P>
+<H3><A name="text">Other documents in the distribution</A></H3>
+<P>Text files in the main distribution directory are README, INSTALL,
+ CREDITS, CHANGES, BUGS and COPYING.</P>
+<P>The Libdes encryption library we use has its own documentation. You
+ can find it in the library directory..</P>
+<H3><A name="assumptions">Background material</A></H3>
+<P>Throughout this documentation, I write as if the reader had at least
+ a general familiarity with Linux, with Internet Protocol networking,
+ and with the basic ideas of system and network security. Of course that
+ will certainly not be true for all readers, and quite likely not even
+ for a majority.</P>
+<P>However, I must limit amount of detail on these topics in the main
+ text. For one thing, I don't understand all the details of those topics
+ myself. Even if I did, trying to explain everything here would produce
+ extremely long and almost completely unreadable documentation.</P>
+<P>If one or more of those areas is unknown territory for you, there are
+ plenty of other resources you could look at:</P>
+<DL>
+<DT>Linux</DT>
+<DD>the<A href="http://www.linuxdoc.org"> Linux Documentation Project</A>
+ or a local<A href="http://www.linux.org/groups/"> Linux User Group</A>
+ and these<A href="web.html#linux.link"> links</A></DD>
+<DT>IP networks</DT>
+<DD>Rusty Russell's<A href="http://netfilter.samba.org/unreliable-guides/networking-concepts-HOWTO/index.html">
+ Networking Concepts HowTo</A> and these<A href="web.html#IP.background">
+ links</A></DD>
+<DT>Security</DT>
+<DD>Schneier's book<A href="biblio.html#secrets"> Secrets and Lies</A>
+ and these<A href="web.html#crypto.link"> links</A></DD>
+</DL>
+<P>Also, I do make an effort to provide some background material in
+ these documents. All the basic ideas behind IPsec and FreeS/WAN are
+ explained here. Explanations that do not fit in the main text, or that
+ not everyone will need, are often in the<A href="glossary.html#ourgloss">
+ glossary</A>, which is the largest single file in this document set.
+ There is also a<A href="background.html#background"> background</A>
+ file containing various explanations too long to fit in glossary
+ definitions. All files are heavily sprinkled with links to each other
+ and to the glossary.<STRONG> If some passage makes no sense to you, try
+ the links</STRONG>.</P>
+<P>For other reference material, see the<A href="biblio.html#biblio">
+ bibliography</A> and our collection of<A href="web.html#weblinks"> web
+ links</A>.</P>
+<P>Of course, no doubt I get this (and other things) wrong sometimes.
+ Feedback via the<A href="mail.html#lists"> mailing lists</A> is
+ welcome.</P>
+<H3><A name="archives">Archives of the project mailing list</A></H3>
+<P>Until quite recently, there was only one FreeS/WAN mailing list, and
+ archives of it were:</P>
+<UL>
+<LI><A href="http://www.sandelman.ottawa.on.ca/linux-ipsec">Canada</A></LI>
+<LI><A href="http://www.nexial.com">Holland</A></LI>
+</UL>
+ The two archives use completely different search engines. You might
+ want to try both.
+<P>More recently we have expanded to five lists, each with its own
+ archive.</P>
+<P><A href="mail.html#lists">More information</A> on mailing lists.</P>
+<H3><A name="howto">User-written HowTo information</A></H3>
+<P>Various user-written HowTo documents are available. The ones covering
+ FreeS/WAN-to-FreeS/WAN connections are:</P>
+<UL>
+<LI>Jean-Francois Nadeau's<A href="http://jixen.tripod.com/"> practical
+ configurations</A> document</LI>
+<LI>Jens Zerbst's HowTo on<A href="http://dynipsec.tripod.com/"> Using
+ FreeS/WAN with dynamic IP addresses</A>.</LI>
+<LI>an entry in Kurt Seifried's<A href="http://www.securityportal.com/lskb/kben00000013.html">
+ Linux Security Knowledge Base</A>.</LI>
+<LI>a section of David Ranch's<A href="http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos">
+ Trinity OS Guide</A></LI>
+<LI>a section in David Bander's book<A href="biblio.html#bander"> Linux
+ Security Toolkit</A></LI>
+</UL>
+<P>User-wriiten HowTo material may be<STRONG> especially helpful if you
+ need to interoperate with another IPsec implementation</STRONG>. We
+ have neither the equipment nor the manpower to test such
+ configurations. Users seem to be doing an admirable job of filling the
+ gaps.</P>
+<UL>
+<LI>list of user-written<A href="interop.html#otherpub"> interoperation
+ HowTos</A> in our interop document</LI>
+</UL>
+<P>Check what version of FreeS/WAN user-written documents cover. The
+ software is under active development and the current version may be
+ significantly different from what an older document describes.</P>
+<H3><A name="applied">Papers on FreeS/WAN</A></H3>
+<P>Two design documents show team thinking on new developments:</P>
+<UL>
+<LI><A href="opportunism.spec">Opportunistic Encryption</A> by technical
+ lead Henry Spencer and Pluto programmer Hugh Redelemeier</LI>
+<LI>discussion of<A href="http://www.sandelman.ottawa.on.ca/SSW/freeswan/klips2req/">
+ KLIPS redesign</A></LI>
+</UL>
+<P>Both documents are works in progress and are frequently revised. For
+ the latest version, see the<A href="mail.html#lists"> design mailing
+ list</A>. Comments should go to that list.</P>
+<P>There is now an<A href="http://www.ietf.org/internet-drafts/draft-richardson-ipsec-opportunistic-06.txt">
+ Internet Draft on Opportunistic Encryption</A> by Michael Richardson,
+ Hugh Redelmeier and Henry Spencer. This is a first step toward getting
+ the protocol standardised so there can be multiple implementations of
+ it. Discussion of it takes place on the<A href="http://www.ietf.org/html.charters/ipsec-charter.html">
+ IETF IPsec Working Group</A> mailing list.</P>
+<P>A number of papers giving further background on FreeS/WAN, or
+ exploring its future or its applications, are also available:</P>
+<UL>
+<LI>Both Henry and Richard gave talks on FreeS/WAN at the 2000<A href="http://www.linuxsymposium.org">
+ Ottawa Linux Symposium</A>.
+<UL>
+<LI>Richard's<A href="http://www.conscoop.ottawa.on.ca/rgb/freeswan/ols2k/">
+ slides</A></LI>
+<LI>Henry's paper</LI>
+<LI>MP3 audio of their talks is available from the<A href="http://www.linuxsymposium.org/">
+ conference page</A></LI>
+</UL>
+</LI>
+<LI><CITE>Moat: A Virtual Private Network Appliances and Services
+ Platform</CITE> is a paper about large-scale (a few 100 links) use of
+ FreeS/WAN in a production application at AT&amp;T Research. It is available
+ in Postscript or PDF from co-author Steve Bellovin's<A href="http://www.research.att.com/~smb/papers/index.html">
+ papers list page</A>.</LI>
+<LI>One of the Moat co-authors, John Denker, has also written
+<UL>
+<LI>a<A href="http://www.av8n.com/vpn/ipsec+routing.htm"> proposal</A>
+ for how future versions of FreeS/WAN might interact with routing
+ protocols</LI>
+<LI>a<A href="http://www.av8n.com/vpn/wishlist.htm"> wishlist</A> of
+ possible new features</LI>
+</UL>
+</LI>
+<LI>Bart Trojanowski's web page has a draft design for<A href="http://www.jukie.net/~bart/linux-ipsec/">
+ hardware acceleration</A> of FreeS/WAN</LI>
+</UL>
+<P>Several of these provoked interesting discussions on the mailing
+ lists, worth searching for in the<A href="mail.html#archive"> archives</A>
+.</P>
+<P>There are also several papers in languages other than English, see
+ our<A href="web.html#otherlang"> web links</A>.</P>
+<H3><A name="licensing">License and copyright information</A></H3>
+<P>All code and documentation written for this project is distributed
+ under either the GNU General Public License (<A href="glossary.html#GPL">
+GPL</A>) or the GNU Library General Public License. For details see the
+ COPYING file in the distribution.</P>
+<P>Not all code in the distribution is ours, however. See the CREDITS
+ file for details. In particular, note that the<A href="glossary.html#LIBDES">
+ Libdes</A> library and the version of<A href="glossary.html#MD5"> MD5</A>
+ that we use each have their own license.</P>
+<H2><A name="sites">Distribution sites</A></H2>
+<P>FreeS/WAN is available from a number of sites.</P>
+<H3><A NAME="1_5_1">Primary site</A></H3>
+<P>Our primary site, is at xs4all (Thanks, folks!) in Holland:</P>
+<UL>
+<LI><A href="http://www.xs4all.nl/~freeswan">HTTP</A></LI>
+<LI><A href="ftp://ftp.xs4all.nl/pub/crypto/freeswan">FTP</A></LI>
+</UL>
+<H3><A name="mirrors">Mirrors</A></H3>
+<P>There are also mirror sites all over the world:</P>
+<UL>
+<LI><A href="http://www.flora.org/freeswan">Eastern Canada</A> (limited
+ resouces)</LI>
+<LI><A href="ftp://ludwig.doculink.com/pub/freeswan/">Eastern Canada</A>
+ (has older versions too)</LI>
+<LI><A href="ftp://ntsc.notBSD.org/pub/crypto/freeswan/">Eastern Canada</A>
+ (has older versions too)</LI>
+<LI><A href="ftp://ftp.kame.net/pub/freeswan/">Japan</A></LI>
+<LI><A href="ftp://ftp.futuredynamics.com/freecrypto/FreeSWAN/">Hong
+ Kong</A></LI>
+<LI><A href="ftp://ipsec.dk/pub/freeswan/">Denmark</A></LI>
+<LI><A href="ftp://ftp.net.lut.ac.uk/freeswan">the UK</A></LI>
+<LI><A href="http://storm.alert.sk/comp/mirrors/freeswan/">Slovak
+ Republic</A></LI>
+<LI><A href="http://the.wiretapped.net/security/vpn-tunnelling/freeswan/">
+Australia</A></LI>
+<LI><A href="http://freeswan.technolust.cx/">technolust</A></LI>
+<LI><A href="http://freeswan.devguide.de/">Germany</A></LI>
+<LI>Ivan Moore's<A href="http://snowcrash.tdyc.com/freeswan/"> site</A></LI>
+<LI>the<A href="http://www.cryptoarchive.net/"> Crypto Archive</A> on
+ the<A href="http://www.securityportal.com/"> Security Portal</A> site</LI>
+<LI><A href="http://www.wiretapped.net/">Wiretapped.net</A> in Australia</LI>
+</UL>
+<P>Thanks to those folks as well.</P>
+<H3><A name="munitions">The &quot;munitions&quot; archive of Linux crypto software</A>
+</H3>
+<P>There is also an archive of Linux crypto software called &quot;munitions&quot;,
+ with its own mirrors in a number of countries. It includes FreeS/WAN,
+ though not always the latest version. Some of its sites are:</P>
+<UL>
+<LI><A href="http://munitions.vipul.net/">Germany</A></LI>
+<LI><A href="http://munitions.iglu.cjb.net/">Italy</A></LI>
+<LI><A href="http://munitions2.xs4all.nl/">Netherlands</A></LI>
+</UL>
+<P>Any of those will have a list of other &quot;munitions&quot; mirrors. There is
+ also a CD available.</P>
+<H2><A NAME="1_6">Links to other sections</A></H2>
+<P>For more detailed background information, see:</P>
+<UL>
+<LI><A href="politics.html#politics">history and politics</A> of
+ cryptography</LI>
+<LI><A href="ipsec.html#ipsec.detail">IPsec protocols</A></LI>
+</UL>
+<P>To begin working with FreeS/WAN, go to our<A href="quickstart.html#quick.guide">
+ quickstart</A> guide.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="upgrading.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/ipsec.conf.2_to_1 b/doc/ipsec.conf.2_to_1
new file mode 100644
index 000000000..3100ed78d
--- /dev/null
+++ b/doc/ipsec.conf.2_to_1
@@ -0,0 +1,22 @@
+version 2
+# If you put the preceding line in front of a 1.x ipsec.conf,
+# it should work within 2.x.
+
+
+# Merge the following sections with your existing config setup
+# and conn %default.
+# Allot these values to any you have not explictly defined.
+
+config setup
+ interfaces=%none # new default is %defaultroute
+ plutoload=%none # new default is %search
+ plutostart=%none # new default is %search
+
+conn %default
+ uniqueids=no # new default is yes
+ keyingtries=3 # new default is %forever
+ disablearrivalcheck=yes # new default is no
+ authby=secret # new default is rsasig
+ leftrsasigkey=%none # new default %dnsondemand
+ rightrsasigkey=%none # new default %dnsondemand
+
diff --git a/doc/ipsec.html b/doc/ipsec.html
new file mode 100644
index 000000000..4fb27b92b
--- /dev/null
+++ b/doc/ipsec.html
@@ -0,0 +1,1040 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="politics.html">Previous</A>
+<A HREF="mail.html">Next</A>
+<HR>
+<H1><A name="ipsec.detail">The IPsec protocols</A></H1>
+<P>This section provides information on the IPsec protocols which
+ FreeS/WAN implements. For more detail, see the<A href="rfc.html"> RFCs</A>
+.</P>
+<P>The basic idea of IPsec is to provide security functions,<A href="glossary.html#authentication">
+ authentication</A> and<A href="glossary.html#encryption"> encryption</A>
+, at the IP (Internet Protocol) level. This requires a higher-level
+ protocol (IKE) to set things up for the IP-level services (ESP and AH).</P>
+<H2><A NAME="27_1">Protocols and phases</A></H2>
+<P>Three protocols are used in an IPsec implementation:</P>
+<DL>
+<DT>ESP, Encapsulating Security Payload</DT>
+<DD>Encrypts and/or authenticates data</DD>
+<DT>AH, Authentication Header</DT>
+<DD>Provides a packet authentication service</DD>
+<DT>IKE, Internet Key Exchange</DT>
+<DD>Negotiates connection parameters, including keys, for the other two</DD>
+</DL>
+<P>The term &quot;IPsec&quot; (also written as IPSEC) is slightly ambiguous. In
+ some contexts, it includes all three of the above but in other contexts
+ it refers only to AH and ESP.</P>
+<P>There is more detail below, but a quick summary of how the whole
+ thing works is:</P>
+<DL>
+<DT>Phase one IKE (main mode exchange)</DT>
+<DD>sets up a keying channel (ISAKMP SA) between the two gateways</DD>
+<DT>Phase two IKE (quick mode exchange)</DT>
+<DD>sets up data channels (IPsec SAs)</DD>
+<DT>IPsec proper</DT>
+<DD>exchanges data using AH or ESP</DD>
+</DL>
+<P>Both phases of IKE are repeated periodically to automate re-keying.</P>
+<H2><A name="others">Applying IPsec</A></H2>
+<P>Authentication and encryption functions for network data can, of
+ course, be provided at other levels. Many security protocols work at
+ levels above IP.</P>
+<UL>
+<LI><A href="glossary.html#PGP">PGP</A> encrypts and authenticates mail
+ messages</LI>
+<LI><A href="glossary.html#SSH">SSH</A> authenticates remote logins and
+ then encrypts the session</LI>
+<LI><A href="glossary.html#SSL">SSL</A> or<A href="glossary.html#TLS">
+ TLS</A> provides security at the sockets layer, e.g. for secure web
+ browsing</LI>
+</UL>
+<P>and so on. Other techniques work at levels below IP. For example,
+ data on a communications circuit or an entire network can be encrypted
+ by specialised hardware. This is common practice in high-security
+ applications.</P>
+<H3><A name="advantages">Advantages of IPsec</A></H3>
+<P>There are, however, advantages to doing it at the IP level instead
+ of, or as well as, at other levels.</P>
+<P>IPsec is the<STRONG> most general way to provide these services for
+ the Internet</STRONG>.</P>
+<UL>
+<LI>Higher-level services protect a<EM> single protocol</EM>; for
+ example PGP protects mail.</LI>
+<LI>Lower level services protect a<EM> single medium</EM>; for example a
+ pair of encryption boxes on the ends of a line make wiretaps on that
+ line useless unless the attacker is capable of breaking the encryption.</LI>
+</UL>
+<P>IPsec, however, can protect<EM> any protocol</EM> running above IP
+ and<EM> any medium</EM> which IP runs over. More to the point, it can
+ protect a mixture of application protocols running over a complex
+ combination of media. This is the normal situation for Internet
+ communication; IPsec is the only general solution.</P>
+<P>IPsec can also provide some security services &quot;in the background&quot;,
+ with<STRONG> no visible impact on users</STRONG>. To use<A href="glossary.html#PGP">
+ PGP</A> encryption and signatures on mail, for example, the user must
+ at least:</P>
+<UL>
+<LI>remember his or her passphrase,</LI>
+<LI>keep it secure</LI>
+<LI>follow procedures to validate correspondents' keys</LI>
+</UL>
+<P>These systems can be designed so that the burden on users is not
+ onerous, but any system will place some requirements on users. No such
+ system can hope to be secure if users are sloppy about meeting those
+ requirements. The author has seen username and password stuck on
+ terminals with post-it notes in an allegedly secure environment, for
+ example.</P>
+<H3><A name="limitations">Limitations of IPsec</A></H3>
+<P>IPsec is designed to secure IP links between machines. It does that
+ well, but it is important to remember that there are many things it
+ does not do. Some of the important limitations are:</P>
+<DL>
+<DT><A name="depends">IPsec cannot be secure if your system isn't</A></DT>
+<DD>System security on IPsec gateway machines is an essential
+ requirement if IPsec is to function as designed. No system can be
+ trusted if the underlying machine has been subverted. See books on Unix
+ security such as<A href="biblio.html#practical"> Garfinkel and Spafford</A>
+ or our web references for<A href="web.html#linsec"> Linux security</A>
+ or more general<A href="web.html#compsec"> computer security</A>.
+<P>Of course, there is another side to this. IPsec can be a powerful
+ tool for improving system and network security. For example, requiring
+ packet authentication makes various spoofing attacks harder and IPsec
+ tunnels can be extremely useful for secure remote administration of
+ various things.</P>
+</DD>
+<DT><A name="not-end-to-end">IPsec is not end-to-end</A></DT>
+<DD>IPsec cannot provide the same end-to-end security as systems working
+ at higher levels. IPsec encrypts an IP connection between two machines,
+ which is quite a different thing than encrypting messages between users
+ or between applications.
+<P>For example, if you need mail encrypted from the sender's desktop to
+ the recipient's desktop and decryptable only by the recipient, use<A href="glossary.html#PGP">
+ PGP</A> or another such system. IPsec can encrypt any or all of the
+ links involved -- between the two mail servers, or between either
+ server and its clients. It could even be used to secure a direct IP
+ link from the sender's desktop machine to the recipient's, cutting out
+ any sort of network snoop. What it cannot ensure is end-to-end
+ user-to-user security. If only IPsec is used to secure mail, then
+ anyone with appropriate privileges on any machine where that mail is
+ stored (at either end or on any store-and-forward servers in the path)
+ can read it.</P>
+<P>In another common setup, IPsec encrypts packets at a security gateway
+ machine as they leave the sender's site and decrypts them on arrival at
+ the gateway to the recipient's site. This does provide a useful
+ security service -- only encrypted data is passed over the Internet --
+ but it does not even come close to providing an end-to-end service. In
+ particular, anyone with appropriate privileges on either site's LAN can
+ intercept the message in unencrypted form.</P>
+</DD>
+<DT><A name="notpanacea">IPsec cannot do everything</A></DT>
+<DD>IPsec also cannot provide all the functions of systems working at
+ higher levels of the protocol stack. If you need a document
+ electronically signed by a particular person, then you need his or her<A
+href="glossary.html#signature"> digital signature</A> and a<A href="glossary.html#public">
+ public key cryptosystem</A> to verify it with.
+<P>Note, however, that IPsec authentication of the underlying
+ communication can make various attacks on higher-level protocols more
+ difficult. In particular, authentication prevents<A href="glossary.html#middle">
+ man-in-the-middle attacks</A>.</P>
+</DD>
+<DT><A name="no_user">IPsec authenticates machines, not users</A></DT>
+<DD>IPsec uses strong authentication mechanisms to control which
+ messages go to which machines, but it does not have the concept of user
+ ID, which is vital to many other security mechansims and policies. This
+ means some care must be taken in fitting the various security
+ mechansims on a network together. For example, if you need to control
+ which users access your database server, you need some non-IPsec
+ mechansim for that. IPsec can control which machines connect to the
+ server, and can ensure that data transfer to those machines is done
+ securely, but that is all. Either the machines themselves must control
+ user access or there must be some form of user authentication to the
+ database, independent of IPsec.</DD>
+<DT><A name="DoS">IPsec does not stop denial of service attacks</A></DT>
+<DD><A href="glossary.html#DOS">Denial of service</A> attacks aim at
+ causing a system to crash, overload, or become confused so that
+ legitimate users cannot get whatever services the system is supposed to
+ provide. These are quite different from attacks in which the attacker
+ seeks either to use the service himself or to subvert the service into
+ delivering incorrect results.
+<P>IPsec shifts the ground for DoS attacks; the attacks possible against
+ systems using IPsec are different than those that might be used against
+ other systems. It does not, however, eliminate the possibility of such
+ attacks.</P>
+</DD>
+<DT><A name="traffic">IPsec does not stop traffic analysis</A></DT>
+<DD><A href="glossary.html#traffic">Traffic analysis</A> is the attempt
+ to derive intelligence from messages without regard for their contents.
+ In the case of IPsec, it would mean analysis based on things visible in
+ the unencrypted headers of encrypted packets -- source and destination
+ gateway addresses, packet size, et cetera. Given the resources to
+ acquire such data and some skill in analysing it (both of which any
+ national intelligence agency should have), this can be a very powerful
+ technique.
+<P>IPsec is not designed to defend against this. Partial defenses are
+ certainly possible, and some are<A href="#traffic.resist"> described
+ below</A>, but it is not clear that any complete defense can be
+ provided.</P>
+</DD>
+</DL>
+<H3><A name="uses">IPsec is a general mechanism for securing IP</A></H3>
+<P>While IPsec does not provide all functions of a mail encryption
+ package, it can encrypt your mail. In particular, it can ensure that
+ all mail passing between a pair or a group of sites is encrypted. An
+ attacker looking only at external traffic, without access to anything
+ on or behind the IPsec gateway, cannot read your mail. He or she is
+ stymied by IPsec just as he or she would be by<A href="glossary.html#PGP">
+ PGP</A>.</P>
+<P>The advantage is that IPsec can provide the same protection for<STRONG>
+ anything transmitted over IP</STRONG>. In a corporate network example,
+ PGP lets the branch offices exchange secure mail with head office. SSL
+ and SSH allow them to securely view web pages, connect as terminals to
+ machines, and so on. IPsec can support all those applications, plus
+ database queries, file sharing (NFS or Windows), other protocols
+ encapsulated in IP (Netware, Appletalk, ...), phone-over-IP,
+ video-over-IP, ... anything-over-IP. The only limitation is that IP
+ Multicast is not yet supported, though there are Internet Draft
+ documents for that.</P>
+<P>IPsec creates<STRONG> secure tunnels through untrusted networks</STRONG>
+. Sites connected by these tunnels form VPNs,<A href="glossary.html#VPN">
+ Virtual Private Networks</A>.</P>
+<P>IPsec gateways can be installed wherever they are required.</P>
+<UL>
+<LI>One organisation might choose to install IPsec only on firewalls
+ between their LANs and the Internet. This would allow them to create a
+ VPN linking several offices. It would provide protection against anyone
+ outside their sites.</LI>
+<LI>Another might install IPsec on departmental servers so everything on
+ the corporate backbone net was encrypted. This would protect messages
+ on that net from everyone except the sending and receiving department.</LI>
+<LI>Another might be less concerned with information secrecy and more
+ with controlling access to certain resources. They might use IPsec
+ packet authentication as part of an access control mechanism, with or
+ without also using the IPsec encryption service.</LI>
+<LI>It is even possible (assuming adequate processing power and an IPsec
+ implementation in each node) to make every machine its own IPsec
+ gateway so that everything on a LAN is encrypted. This protects
+ information from everyone outside the sending and receiving machine.</LI>
+<LI>These techniques can be combined in various ways. One might, for
+ example, require authentication everywhere on a network while using
+ encryption only for a few links.</LI>
+</UL>
+<P>Which of these, or of the many other possible variants, to use is up
+ to you.<STRONG> IPsec provides mechanisms; you provide the policy</STRONG>
+.</P>
+<P><STRONG>No end user action is required</STRONG> for IPsec security to
+ be used; they don't even have to know about it. The site
+ administrators, of course, do have to know about it and to put some
+ effort into making it work. Poor administration can compromise IPsec as
+ badly as the post-it notes mentioned above. It seems reasonable,
+ though, for organisations to hope their system administrators are
+ generally both more security-conscious than end users and more able to
+ follow computer security procedures. If not, at least there are fewer
+ of them to educate or replace.</P>
+<P>IPsec can be, and often should be, used with along with security
+ protocols at other levels. If two sites communicate with each other via
+ the Internet, then IPsec is the obvious way to protect that
+ communication. If two others have a direct link between them, either
+ link encryption or IPsec would make sense. Choose one or use both.
+ Whatever you use at and below the IP level, use other things as
+ required above that level. Whatever you use above the IP level,
+ consider what can be done with IPsec to make attacks on the higher
+ levels harder. For example,<A href="glossary.html#middle">
+ man-in-the-middle attacks</A> on various protocols become difficult if
+ authentication at packet level is in use on the potential victims'
+ communication channel.</P>
+<H3><A name="authonly">Using authentication without encryption</A></H3>
+<P>Where appropriate, IPsec can provide authentication without
+ encryption. One might do this, for example:</P>
+<UL>
+<LI>where the data is public but one wants to be sure of getting the
+ right data, for example on some web sites</LI>
+<LI>where encryption is judged unnecessary, for example on some company
+ or department LANs</LI>
+<LI>where strong encryption is provided at link level, below IP</LI>
+<LI>where strong encryption is provided in other protocols, above IP
+<BR> Note that IPsec authentication may make some attacks on those
+ protocols harder.</LI>
+</UL>
+<P>Authentication has lower overheads than encryption.</P>
+<P>The protocols provide four ways to build such connections, using
+ either an AH-only connection or ESP using null encryption, and in
+ either manually or automatically keyed mode. FreeS/WAN supports only
+ one of these, manually keyed AH-only connections, and<STRONG> we do not
+ recommend using that</STRONG>. Our reasons are discussed under<A href="#traffic.resist">
+ Resisting traffic analysis</A> a few sections further along.</P>
+<H3><A name="encnoauth">Encryption without authentication is dangerous</A>
+</H3>
+<P>Originally, the IPsec encryption protocol<A href="glossary.html#ESP">
+ ESP</A> didn't do integrity checking. It only did encryption. Steve
+ Bellovin found many ways to attack ESP used without authentication. See
+ his paper<A href="http://www.research.att.com/~smb/papers/badesp.ps">
+ Problem areas for the IP Security Protocols</A>. To make a secure
+ connection, you had to add an<A href="glossary.html#AH"> AH</A>
+ Authentication Header as well as ESP. Rather than incur the overhead of
+ several layers (and rather than provide an ESP layer that didn't
+ actually protect the traffic), the IPsec working group built integrity
+ and replay checking directly into ESP.</P>
+<P>Today, typical usage is one of:</P>
+<UL>
+<LI>ESP for encryption and authentication</LI>
+<LI>AH for authentication alone</LI>
+</UL>
+<P>Other variants are allowed by the standard, but not much used:</P>
+<DL>
+<DT>ESP encryption without authentication</DT>
+<DD><STRONG>Bellovin has demonstrated fatal flaws in this. Do not use.</STRONG>
+</DD>
+<DT>ESP encryption with AH authentication</DT>
+<DD>This has higher overheads than using the authentication in ESP, and
+ no obvious benefit in most cases. The exception might be a network
+ where AH authentication was widely or universally used. If you're going
+ to do AH to conform with network policy, why authenticate again in the
+ ESP layer?</DD>
+<DT>Authenticate twice, with AH and with ESP</DT>
+<DD>Why? Of course, some folk consider &quot;belt and suspenders&quot; the
+ sensible approach to security. If you're among them, you might use both
+ protocols here. You might also use both to satisfy different parts of a
+ security policy. For example, an organisation might require AH
+ authentication everywhere but two users within the organisation might
+ use ESP as well.</DD>
+<DT>ESP authentication without encryption</DT>
+<DD>The standard allows this, calling it &quot;null encryption&quot;. FreeS/WAN
+ does not support it. We recommend that you use AH instead if
+ authentication is all you require. AH authenticates parts of the IP
+ header, which ESP-null does not do.</DD>
+</DL>
+<P>Some of these variants cannot be used with FreeS/WAN because we do
+ not support ESP-null and do not support automatic keying of AH-only
+ connections.</P>
+<P>There are fairly frequent suggestions that AH be dropped entirely
+ from the IPsec specifications since ESP and null encryption can handle
+ that situation. It is not clear whether this will occur. My guess is
+ that it is unlikely.</P>
+<H3><A name="multilayer">Multiple layers of IPsec processing are
+ possible</A></H3>
+<P>The above describes combinations possible on a single IPsec
+ connection. In a complex network you may have several layers of IPsec
+ in play, with any of the above combinations at each layer.</P>
+<P>For example, a connection from a desktop machine to a database server
+ might require AH authentication. Working with other host, network and
+ database security measures, AH might be just the thing for access
+ control. You might decide not to use ESP encryption on such packets,
+ since it uses resources and might complicate network debugging. Within
+ the site where the server is, then, only AH would be used on those
+ packets.</P>
+<P>Users at another office, however, might have their whole connection
+ (AH headers and all) passing over an IPsec tunnel connecting their
+ office to the one with the database server. Such a tunnel should use
+ ESP encryption and authentication. You need authentication in this
+ layer because without authentication the encryption is vulnerable and
+ the gateway cannot verify the AH authentication. The AH is between
+ client and database server; the gateways aren't party to it.</P>
+<P>In this situation, some packets would get multiple layers of IPsec
+ applied to them, AH on an end-to-end client-to-server basis and ESP
+ from one office's security gateway to the other.</P>
+<H3><A name="traffic.resist">Resisting traffic analysis</A></H3>
+<P><A href="glossary.html#traffic">Traffic analysis</A> is the attempt
+ to derive useful intelligence from encrypted traffic without breaking
+ the encryption.</P>
+<P>Is your CEO exchanging email with a venture capital firm? With
+ bankruptcy trustees? With an executive recruiting agency? With the
+ holder of some important patents? If an eavesdropper learns about any
+ of those, then he has interesting intelligence on your company, whether
+ or not he can read the messages themselves.</P>
+<P>Even just knowing that there is network traffic between two sites may
+ tell an analyst something useful, especially when combined with
+ whatever other information he or she may have. For example, if you know
+ Company A is having cashflow problems and Company B is looking for
+ aquisitions, then knowing that packets are passing between the two is
+ interesting. It is more interesting if you can tell it is email, and
+ perhaps yet more if you know the sender and recipient.</P>
+<P>Except in the simplest cases, traffic analysis is hard to do well. It
+ requires both considerable resources and considerable analytic skill.
+ However, intelligence agencies of various nations have been doing it
+ for centuries and many of them are likely quite good at it by now.
+ Various commercial organisations, especially those working on &quot;targeted
+ marketing&quot; may also be quite good at analysing certain types of
+ traffic.</P>
+<P>In general, defending against traffic analysis is also difficult.
+ Inventing a really good defense could get you a PhD and some
+ interesting job offers.</P>
+<P>IPsec is not designed to stop traffic analysis and we know of no
+ plausible method of extending it to do so. That said, there are ways to
+ make traffic analysis harder. This section describes them.</P>
+<H4><A name="extra">Using &quot;unnecessary&quot; encryption</A></H4>
+<P>One might choose to use encryption even where it appears unnecessary
+ in order to make analysis more difficult. Consider two offices which
+ pass a small volume of business data between them using IPsec and also
+ transfer large volumes of Usenet news. At first glance, it would seem
+ silly to encrypt the newsfeed, except possibly for any newsgroups that
+ are internal to the company. Why encrypt data that is all publicly
+ available from many sites?</P>
+<P>However, if we encrypt a lot of news and send it down the same
+ connection as our business data, we make<A href="glossary.html#traffic">
+ traffic analysis</A> much harder. A snoop cannot now make inferences
+ based on patterns in the volume, direction, sizes, sender, destination,
+ or timing of our business messages. Those messages are hidden in a mass
+ of news messages encapsulated in the same way.</P>
+<P>If we're going to do this we need to ensure that keys change often
+ enough to remain secure even with high volumes and with the adversary
+ able to get plaintext of much of the data. We also need to look at
+ other attacks this might open up. For example, can the adversary use a
+ chosen plaintext attack, deliberately posting news articles which, when
+ we receive and encrypt them, will help break our encryption? Or can he
+ block our business data transmission by flooding us with silly news
+ articles? Or ...</P>
+<P>Also, note that this does not provide complete protection against
+ traffic analysis. A clever adversary might still deduce useful
+ intelligence from statistical analysis (perhaps comparing the input
+ newsfeed to encrypted output, or comparing the streams we send to
+ different branch offices), or by looking for small packets which might
+ indicate establishment of TCP connections, or ...</P>
+<P>As a general rule, though, to improve resistance to traffic analysis,
+ you should<STRONG> encrypt as much traffic as possible, not just as
+ much as seems necessary.</STRONG></P>
+<H4><A name="multi-encrypt">Using multiple encryption</A></H4>
+<P>This also applies to using multiple layers of encryption. If you have
+ an IPsec tunnel between two branch offices, it might appear silly to
+ send<A href="glossary.html#PGP"> PGP</A>-encrypted email through that
+ tunnel. However, if you suspect someone is snooping your traffic, then
+ it does make sense:</P>
+<UL>
+<LI>it protects the mail headers; they cannot even see who is mailing
+ who</LI>
+<LI>it protects against user bungles or software malfunctions that
+ accidentally send messages in the clear</LI>
+<LI>it makes any attack on the mail encryption much harder; they have to
+ break IPsec or break into your network before they can start on the
+ mail encryption</LI>
+</UL>
+<P>Similar arguments apply for<A href="glossary.html#SSL"> SSL</A>
+-encrypted web traffic or<A href="glossary.html#SSH"> SSH</A>-encrypted
+ remote login sessions, even for end-to-end IPsec tunnels between
+ systems in the two offices.</P>
+<H4><A name="fewer">Using fewer tunnels</A></H4>
+<P>It may also help to use fewer tunnels. For example, if all you
+ actually need encrypted is connections between:</P>
+<UL>
+<LI>mail servers at branch and head offices</LI>
+<LI>a few branch office users and the head office database server</LI>
+</UL>
+<P>You might build one tunnel per mail server and one per remote
+ database user, restricting traffic to those applications. This gives
+ the traffic analyst some information, however. He or she can
+ distinguish the tunnels by looking at information in the ESP header
+ and, given that distinction and the patterns of tunnel usage, might be
+ able to figure out something useful. Perhaps not, but why take the
+ risk?</P>
+<P>We suggest instead that you build one tunnel per branch office,
+ encrypting everything passing from head office to branches. This has a
+ number of advantages:</P>
+<UL>
+<LI>it is easier to build and administer</LI>
+<LI>it resists traffic analysis somewhat better</LI>
+<LI>it provides security for whatever you forgot. For example, if some
+ user at a remote office browses proprietary company data on some head
+ office web page (that the security people may not even know about!),
+ then that data is encrypted before it reaches the Internet.</LI>
+</UL>
+<P>Of course you might also want to add additional tunnels. For example,
+ if some of the database data is confidential and should not be exposed
+ even within the company, then you need protection from the user's
+ desktop to the database server. We suggest you do that in whatever way
+ seems appropriate -- IPsec, SSH or SSL might fit -- but, whatever you
+ choose, pass it between locations via a gateway-to-gateway IPsec tunnel
+ to provide some resistance to traffic analysis.</P>
+<H2><A name="primitives">Cryptographic components</A></H2>
+<P>IPsec combines a number of cryptographic techniques, all of them
+ well-known and well-analyzed. The overall design approach was
+ conservative; no new or poorly-understood components were included.</P>
+<P>This section gives a brief overview of each technique. It is intended
+ only as an introduction. There is more information, and links to
+ related topics, in our<A href="glossary.html"> glossary</A>. See also
+ our<A href="biblio.html"> bibliography</A> and cryptography<A href="web.html#crypto.link">
+ web links</A>.</P>
+<H3><A name="block.cipher">Block ciphers</A></H3>
+<P>The<A href="glossary.html#encryption"> encryption</A> in the<A href="glossary.html#ESP">
+ ESP</A> encapsulation protocol is done with a<A href="glossary.html#block">
+ block cipher</A>.</P>
+<P>We do not implement<A href="glossary.html#DES"> single DES</A>. It is<A
+href="politics.html#desnotsecure"> insecure</A>. Our default, and
+ currently only, block cipher is<A href="glossary.html#3DES"> triple DES</A>
+.</P>
+<P>The<A href="glossary.html#rijndael"> Rijndael</A> block cipher has
+ won the<A href="glossary.html#AES"> AES</A> competition to choose a
+ relacement for DES. It will almost certainly be added to FreeS/WAN and
+ to other IPsec implementations.<A href="web.html#patch"> Patches</A>
+ are already available.</P>
+<H3><A name="hash.ipsec">Hash functions</A></H3>
+<H4><A name="hmac.ipsec">The HMAC construct</A></H4>
+<P>IPsec packet authentication is done with the<A href="glossary.html#HMAC">
+ HMAC</A> construct. This is not just a hash of the packet data, but a
+ more complex operation which uses both a hashing algorithm and a key.
+ It therefore does more than a simple hash would. A simple hash would
+ only tell you that the packet data was not changed in transit, or that
+ whoever changed it also regenerated the hash. An HMAC also tells you
+ that the sender knew the HMAC key.</P>
+<P>For IPsec HMAC, the output of the hash algorithm is truncated to 96
+ bits. This saves some space in the packets. More important, it prevents
+ an attacker from seeing all the hash output bits and perhaps creating
+ some sort of attack based on that knowledge.</P>
+<H4>Choice of hash algorithm</H4>
+<P>The IPsec RFCs require two hash algorithms --<A href="glossary.html#MD5">
+ MD5</A> and<A href="glossary.html#SHA"> SHA-1</A> -- both of which
+ FreeS/WAN implements.</P>
+<P>Various other algorithms -- such as RIPEMD and Tiger -- are listed in
+ the RFCs as optional. None of these are in the FreeS/WAN distribution,
+ or are likely to be added, although user<A href="web.html#patch">
+ patches</A> exist for several of them.</P>
+<P>Additional hash algorithms --<A href="glossary.html#SHA-256">
+ SHA-256, SHA-384 and SHA-512</A> -- may be required to give hash
+ strength matching the strength of<A href="glossary.html#AES"> AES</A>.
+ These are likely to be added to FreeS/WAN along with AES.</P>
+<H3><A name="DH.keying">Diffie-Hellman key agreement</A></H3>
+<P>The<A href="glossary.html#DH"> Diffie-Hellman</A> key agreement
+ protocol allows two parties (A and B or<A href="glossary.html#alicebob">
+ Alice and Bob</A>) to agree on a key in such a way that an eavesdropper
+ who intercepts the entire conversation cannot learn the key.</P>
+<P>The protocol is based on the<A href="glossary.html#dlog"> discrete
+ logarithm</A> problem and is therefore thought to be secure.
+ Mathematicians have been working on that problem for years and seem no
+ closer to a solution, though there is no proof that an efficient
+ solution is impossible.</P>
+<H3><A name="RSA.auth">RSA authentication</A></H3>
+<P>The<A href="glossary.html#RSA"> RSA</A> algorithm (named for its
+ inventors -- Rivest, Shamir and Adleman) is a very widely used<A href="glossary.html#">
+ public key</A> cryptographic technique. It is used in IPsec as one
+ method of authenticating gateways for Diffie-Hellman key negotiation.</P>
+<H2><A name="structure">Structure of IPsec</A></H2>
+<P>There are three protocols used in an IPsec implementation:</P>
+<DL>
+<DT>ESP, Encapsulating Security Payload</DT>
+<DD>Encrypts and/or authenticates data</DD>
+<DT>AH, Authentication Header</DT>
+<DD>Provides a packet authentication service</DD>
+<DT>IKE, Internet Key Exchange</DT>
+<DD>Negotiates connection parameters, including keys, for the other two</DD>
+</DL>
+<P>The term &quot;IPsec&quot; is slightly ambiguous. In some contexts, it includes
+ all three of the above but in other contexts it refers only to AH and
+ ESP.</P>
+<H3><A name="IKE.ipsec">IKE (Internet Key Exchange)</A></H3>
+<P>The IKE protocol sets up IPsec (ESP or AH) connections after
+ negotiating appropriate parameters (algorithms to be used, keys,
+ connection lifetimes) for them. This is done by exchanging packets on
+ UDP port 500 between the two gateways.</P>
+<P>IKE (RFC 2409) was the outcome of a long, complex process in which
+ quite a number of protocols were proposed and debated. Oversimplifying
+ mildly, IKE combines:</P>
+<DL>
+<DT>ISAKMP (RFC 2408)</DT>
+<DD>The<STRONG> I</STRONG>nternet<STRONG> S</STRONG>ecurity<STRONG> A</STRONG>
+ssociation and<STRONG> K</STRONG>ey<STRONG> M</STRONG>anagement<STRONG>
+ P</STRONG>rotocol manages negotiation of connections and defines<A href="glossary.html#SA">
+ SA</A>s (Security Associations) as a means of describing connection
+ properties.</DD>
+<DT>IPsec DOI for ISAKMP (RFC 2407)</DT>
+<DD>A<STRONG> D</STRONG>omain<STRONG> O</STRONG>f<STRONG> I</STRONG>
+nterpretation fills in the details necessary to turn the rather abstract
+ ISAKMP protocol into a more tightly specified protocol, so it becomes
+ applicable in a particular domain.</DD>
+<DT>Oakley key determination protocol (RFC 2412)</DT>
+<DD>Oakley creates keys using the<A href="glossary.html#DH">
+ Diffie-Hellman</A> key agreement protocol.</DD>
+</DL>
+<P>For all the details, you would need to read the four<A href="rfc.html">
+ RFCs</A> just mentioned (over 200 pages) and a number of others. We
+ give a summary below, but it is far from complete.</P>
+<H4><A name="phases">Phases of IKE</A></H4>
+<P>IKE negotiations have two phases.</P>
+<DL>
+<DT>Phase one</DT>
+<DD>The two gateways negotiate and set up a two-way ISAKMP SA which they
+ can then use to handle phase two negotiations. One such SA between a
+ pair of gateways can handle negotiations for multiple tunnels.</DD>
+<DT>Phase two</DT>
+<DD>Using the ISAKMP SA, the gateways negotiate IPsec (ESP and/or AH)
+ SAs as required. IPsec SAs are unidirectional (a different key is used
+ in each direction) and are always negotiated in pairs to handle two-way
+ traffic. There may be more than one pair defined between two gateways.</DD>
+</DL>
+<P>Both of these phases use the UDP protocol and port 500 for their
+ negotiations.</P>
+<P>After both IKE phases are complete, you have IPsec SAs to carry your
+ encrypted data. These use the ESP or AH protocols. These protocols do
+ not have ports. Ports apply only to UDP or TCP.</P>
+<P>The IKE protocol is designed to be extremely flexible. Among the
+ things that can be negotiated (separately for each SA) are:</P>
+<UL>
+<LI>SA lifetime before rekeying</LI>
+<LI>encryption algorithm used. We currently support only<A href="glossary.html#3DES">
+ triple DES</A>. Single DES is<A href="politics.html#desnotsecure">
+ insecure</A>. The RFCs say you MUST do DES, SHOULD do 3DES and MAY do
+ various others. We do not do any of the others.</LI>
+<LI>authentication algorithms. We support<A href="glossary.html#MD5">
+ MD5</A> and<A href="glossary.html#SHA"> SHA</A>. These are the two the
+ RFCs require.</LI>
+<LI>choice of group for<A href="glossary.html#DH"> Diffie-Hellman</A>
+ key agreement. We currently support Groups 2 and 5 (which are defined
+ modulo primes of various lengths) and do not support Group 1 (defined
+ modulo a shorter prime, and therefore cryptographically weak) or groups
+ 3 and 4 (defined using elliptic curves). The RFCs require only Group 1.</LI>
+</UL>
+<P>The protocol also allows implementations to add their own encryption
+ algorithms, authentication algorithms or Diffie-Hellman groups. We do
+ not support any such extensions, but there are some<A href="web.html#patch">
+ patches</A> that do.</P>
+<P>There are a number of complications:</P>
+<UL>
+<LI>The gateways must be able to authenticate each other's identities
+ before they can create a secure connection. This host authentication is
+ part of phase one negotiations, and is a required prerequisite for
+ packet authentication used later. Host authentication can be done in a
+ variety of ways. Those supported by FreeS/WAN are discussed in our<A href="adv_config.html#auto-auth">
+ advanced configuration</A> document.</LI>
+<LI>Phase one can be done in two ways.
+<UL>
+<LI>Main Mode is required by the RFCs and supported in FreeS/WAN. It
+ uses a 6-packet exzchange.</LI>
+<LI>Aggressive Mode is somewhat faster (only 3 packets) but reveals more
+ to an eavesdropper. This is optional in the RFCs, not currently
+ supported by FreeS/WAN, and not likely to be.</LI>
+</UL>
+</LI>
+<LI>A new group exchange may take place after phase one but before phase
+ two, defining an additional group for use in the<A href="glossary.html#DH">
+ Diffie-Hellman</A> key agreement part of phase two. FreeS/WAN does not
+ currently support this.</LI>
+<LI>Phase two always uses Quick Mode, but there are two variants of
+ that:
+<UL>
+<LI>One variant provides<A href="glossary.html#PFS"> Perfect Forward
+ Secrecy (PFS)</A>. An attacker that obtains your long-term host
+ authentication key does not immediately get any of your short-term
+ packet encryption of packet authentication keys. He must conduct
+ another successful attack each time you rekey to get the short-term
+ keys. Having some short-term keys does not help him learn others. In
+ particular, breaking your system today does not let him read messages
+ he archived yestarday, assuming you've changed short-term keys in the
+ meanwhile. We enable PFS as the default.</LI>
+<LI>The other variant disables PFS and is therefore slightly faster. We
+ do not recommend this since it is less secure, but FreeS/WAN does
+ support it. You can enable it with a<VAR> pfs=no</VAR> statement in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>.</LI>
+<LI>The protocol provides no way to negotiate which variant will be
+ used. If one gateway is set for PFS and the other is not, the
+ negotiation fails. This has proved a fairly common source of
+ interoperation problems.</LI>
+</UL>
+</LI>
+<LI>Several types of notification message may be sent by either side
+ during either phase, or later. FreeS/WAN does not currently support
+ these, but they are a likely addition in future releases.</LI>
+<LI>There is a commit flag which may optionally be set on some messages.
+ The<A href="http://www.lounge.org/ike_doi_errata.html"> errata</A> page
+ for the RFCs includes two changes related to this, one to clarify the
+ description of its use and one to block a<A href="glossary.html#DOS">
+ denial of service</A> attack which uses it. We currently do not
+ implement this feature.</LI>
+</UL>
+<P>These complications can of course lead to problems, particularly when
+ two different implementations attempt to interoperate. For example, we
+ have seen problems such as:</P>
+<UL>
+<LI>Some implementations (often products crippled by<A href="politics.html#exlaw">
+ export laws</A>) have the insecure DES algorithm as their only
+ supported encryption method. Other parts of our documentation discuss
+ the<A href="politics.html#desnotsecure"> reasons we do not implement
+ single DES</A>, and<A href="interop.html#noDES"> how to cope with
+ crippled products</A>.</LI>
+<LI>Windows 2000 IPsec tries to negotiate using Aggressive Mode, which
+ we don't support. Later on, it uses the commit bit, which we also don't
+ support.</LI>
+<LI>Various implementations disable PFS by default, and therefore will
+ not talk to FreeS/WAN until you either turn on PFS on their end or turn
+ it off in FreeS/WAN with a<VAR> pfs=no</VAR> entry in the connection
+ description.</LI>
+<LI>FreeS/WAN's interaction with PGPnet is complicated by their use of
+ notification messages we do not yet support.</LI>
+</UL>
+<P>Despite this, we do interoperate successfully with many
+ implementations, including both Windows 2000 and PGPnet. Details are in
+ our<A href="interop.html"> interoperability</A> document.</P>
+<H4><A name="sequence">Sequence of messages in IKE</A></H4>
+<P>Each phase (see<A href="#phases"> previous section</A>)of IKE
+ involves a series of messages. In Pluto error messages, these are
+ abbreviated using:</P>
+<DL>
+<DT>M</DT>
+<DD><STRONG>M</STRONG>ain mode, settting up the keying channel (ISAKMP
+ SA)</DD>
+<DT>Q</DT>
+<DD><STRONG>Q</STRONG>uick mode, setting up the data channel (IPsec SA)</DD>
+<DT>I</DT>
+<DD><STRONG>I</STRONG>nitiator, the machine that starts the negotiation</DD>
+<DT>R</DT>
+<DD><STRONG>R</STRONG>esponder</DD>
+</DL>
+<P>For example, the six messages of a main mode negotiation, in
+ sequence, are labelled:</P>
+<PRE> MI1 ----------&gt;
+ &lt;---------- MR1
+ MI2 ----------&gt;
+ &lt;---------- MR2
+ MI3 ----------&gt;
+ &lt;---------- MR3</PRE>
+<H4><A name="struct.exchange">Structure of IKE messages</A></H4>
+<P>Here is our Pluto developer explaining some of this on the mailing
+ list:</P>
+<PRE>When one IKE system (for example, Pluto) is negotiating with another
+to create an SA, the Initiator proposes a bunch of choices and the
+Responder replies with one that it has selected.
+
+The structure of the choices is fairly complicated. An SA payload
+contains a list of lists of &quot;Proposals&quot;. The outer list is a set of
+choices: the selection must be from one element of this list.
+
+Each of these elements is a list of Proposals. A selection must be
+made from each of the elements of the inner list. In other words,
+*all* of them apply (that is how, for example, both AH and ESP can
+apply at once).
+
+Within each of these Proposals is a list of Transforms. For each
+Proposal selected, one Transform must be selected (in other words,
+each Proposal provides a choice of Transforms).
+
+Each Transform is made up of a list of Attributes describing, well,
+attributes. Such as lifetime of the SA. Such as algorithm to be
+used. All the Attributes apply to a Transform.
+
+You will have noticed a pattern here: layers alternate between being
+disjunctions (&quot;or&quot;) and conjunctions (&quot;and&quot;).
+
+For Phase 1 / Main Mode (negotiating an ISAKMP SA), this structure is
+cut back. There must be exactly one Proposal. So this degenerates to
+a list of Transforms, one of which must be chosen.</PRE>
+<H3><A name="services">IPsec Services, AH and ESP</A></H3>
+<P>IPsec offers two services,<A href="glossary.html#authentication">
+ authentication</A> and<A href="glossary.html#encryption"> encryption</A>
+. These can be used separately but are often used together.</P>
+<DL>
+<DT>Authentication</DT>
+<DD>Packet-level authentication allows you to be confident that a packet
+ came from a particular machine and that its contents were not altered
+ en route to you. No attempt is made to conceal or protect the contents,
+ only to assure their integrity. Packet authentication can be provided
+ separately using an<A href="glossary.html#AH"> Authentication Header</A>
+, described just below, or it can be included as part of the<A href="glossary.html#ESP">
+ ESP</A> (Encapsulated Security Payload) service, described in the
+ following section. That service offers encryption as well as
+ authentication. In either case, the<A href="glossary.html#HMAC"> HMAC</A>
+ construct is used as the authentication mechanism.
+<P>There is a separate authentication operation at the IKE level, in
+ which each gateway authenticates the other. This can be done in a
+ variety of ways.</P>
+</DD>
+<DT>Encryption</DT>
+<DD>Encryption allows you to conceal the contents of a message from
+ eavesdroppers.
+<P>In IPsec this is done using a<A href="glossary.html#block"> block
+ cipher</A> (normally<A href="glossary.html#3DES"> Triple DES</A> for
+ Linux). In the most used setup, keys are automatically negotiated, and
+ periodically re-negotiated, using the<A href="glossary.html#IKE"> IKE</A>
+ (Internet Key Exchange) protocol. In Linux FreeS/WAN this is handled by
+ the Pluto Daemon.</P>
+<P>The IPsec protocol offering encryption is<A href="glossary.html#ESP">
+ ESP</A>, Encapsulated Security Payload. It can also include a packet
+ authentication service.</P>
+</DD>
+</DL>
+<P>Note that<STRONG> encryption should always be used with some packet
+ authentication service</STRONG>. Unauthenticated encryption is
+ vulnerable to<A href="glossary.html#middle"> man-in-the-middle attacks</A>
+. Also note that encryption does not prevent<A href="glossary.html#traffic">
+ traffic analysis</A>.</P>
+<H3><A name="AH.ipsec">The Authentication Header (AH)</A></H3>
+<P>Packet authentication can be provided separately from encryption by
+ adding an authentication header (AH) after the IP header but before the
+ other headers on the packet. This is the subject of this section.
+ Details are in RFC 2402.</P>
+<P>Each of the several headers on a packet header contains a &quot;next
+ protocol&quot; field telling the system what header to look for next. IP
+ headers generally have either TCP or UDP in this field. When IPsec
+ authentication is used, the packet IP header has AH in this field,
+ saying that an Authentication Header comes next. The AH header then has
+ the next header type -- usually TCP, UDP or encapsulated IP.</P>
+<P>IPsec packet authentication can be added in transport mode, as a
+ modification of standard IP transport. This is shown in this diagram
+ from the RFC:</P>
+<PRE> BEFORE APPLYING AH
+ ----------------------------
+ IPv4 |orig IP hdr | | |
+ |(any options)| TCP | Data |
+ ----------------------------
+
+ AFTER APPLYING AH
+ ---------------------------------
+ IPv4 |orig IP hdr | | | |
+ |(any options)| AH | TCP | Data |
+ ---------------------------------
+ ||
+ except for mutable fields</PRE>
+<P>Athentication can also be used in tunnel mode, encapsulating the
+ underlying IP packet beneath AH and an additional IP header.</P>
+<PRE> ||
+IPv4 | new IP hdr* | | orig IP hdr* | | |
+ |(any options)| AH | (any options) |TCP | Data |
+ ------------------------------------------------
+ ||
+ | in the new IP hdr |</PRE>
+<P>This would normally be used in a gateway-to-gateway tunnel. The
+ receiving gateway then strips the outer IP header and the AH header and
+ forwards the inner IP packet.</P>
+<P>The mutable fields referred to are things like the time-to-live field
+ in the IP header. These cannot be included in authentication
+ calculations because they change as the packet travels.</P>
+<H4><A name="keyed">Keyed MD5 and Keyed SHA</A></H4>
+<P>The actual authentication data in the header is typically 96 bits and
+ depends both on a secret shared between sender and receiver and on
+ every byte of the data being authenticated. The technique used is<A href="glossary.html#HMAC">
+ HMAC</A>, defined in RFC 2104.</P>
+<P>The algorithms involved are the<A href="glossary.html#MD5"> MD5</A>
+ Message Digest Algorithm or<A href="glossary.html#SHA"> SHA</A>, the
+ Secure Hash Algorithm. For details on their use in this application,
+ see RFCs 2403 and 2404 respectively.</P>
+<P>For descriptions of the algorithms themselves, see RFC 1321 for MD5
+ and<A href="glossary.html#FIPS"> FIPS</A> (Federal Information
+ Processing Standard) number 186 from<A href="glossary.html#NIST"> NIST</A>
+, the US National Institute of Standards and Technology for SHA.<A href="biblio.html#schneier">
+<CITE> Applied Cryptography</CITE></A> covers both in some detail, MD5
+ starting on page 436 and SHA on 442.</P>
+<P>These algorithms are intended to make it nearly impossible for anyone
+ to alter the authenticated data in transit. The sender calculates a
+ digest or hash value from that data and includes the result in the
+ authentication header. The recipient does the same calculation and
+ compares results. For unchanged data, the results will be identical.
+ The hash algorithms are designed to make it extremely difficult to
+ change the data in any way and still get the correct hash.</P>
+<P>Since the shared secret key is also used in both calculations, an
+ interceptor cannot simply alter the authenticated data and change the
+ hash value to match. Without the key, he or she (or even the dreaded
+ They) cannot produce a usable hash.</P>
+<H4><A name="sequence">Sequence numbers</A></H4>
+<P>The authentication header includes a sequence number field which the
+ sender is required to increment for each packet. The receiver can
+ ignore it or use it to check that packets are indeed arriving in the
+ expected sequence.</P>
+<P>This provides partial protection against<A href="glossary.html#replay">
+ replay attacks</A> in which an attacker resends intercepted packets in
+ an effort to confuse or subvert the receiver. Complete protection is
+ not possible since it is necessary to handle legitmate packets which
+ are lost, duplicated, or delivered out of order, but use of sequence
+ numbers makes the attack much more difficult.</P>
+<P>The RFCs require that sequence numbers never cycle, that a new key
+ always be negotiated before the sequence number reaches 2^32-1. This
+ protects both against replays attacks using packets from a previous
+ cyclce and against<A href="glossary.html#birthday"> birthday attacks</A>
+ on the the packet authentication algorithm.</P>
+<P>In Linux FreeS/WAN, the sequence number is ignored for manually keyed
+ connections and checked for automatically keyed ones. In manual mode,
+ there is no way to negotiate a new key, or to recover from a sequence
+ number problem, so we don't use sequence numbers.</P>
+<H3><A name="ESP.ipsec">Encapsulated Security Payload (ESP)</A></H3>
+<P>The ESP protocol is defined in RFC 2406. It provides one or both of
+ encryption and packet authentication. It may be used with or without AH
+ packet authentication.</P>
+<P>Note that<STRONG> some form of packet authentication should<EM>
+ always</EM> be used whenever data is encrypted</STRONG>. Without
+ authentication, the encryption is vulnerable to active attacks which
+ may allow an enemy to break the encryption. ESP should<STRONG> always</STRONG>
+ either include its own authentication or be used with AH
+ authentication.</P>
+<P>The RFCs require support for only two mandatory encryption algorithms
+ --<A href="glossary.html#DES"> DES</A>, and null encryption -- and for
+ two authentication methods -- keyed MD5 and keyed SHA. Implementers may
+ choose to support additional algorithms in either category.</P>
+<P>The authentication algorithms are the same ones used in the IPsec<A href="glossary.html#AH">
+ authentication header</A>.</P>
+<P>We do not implement single DES since<A href="politics.html#desnotsecure">
+ DES is insecure</A>. Instead we provide<A href="glossary.html#3DES">
+ triple DES or 3DES</A>. This is currently the only encryption algorithm
+ supported.</P>
+<P>We do not implement null encryption since it is obviously insecure.</P>
+<H2><A name="modes">IPsec modes</A></H2>
+<P>IPsec can connect in two modes. Transport mode is a host-to-host
+ connection involving only two machines. In tunnel mode, the IPsec
+ machines act as gateways and trafiic for any number of client machines
+ may be carried.</P>
+<H3><A name="tunnel.ipsec">Tunnel mode</A></H3>
+<P>Security gateways are required to support tunnel mode connections. In
+ this mode the gateways provide tunnels for use by client machines
+ behind the gateways. The client machines need not do any IPsec
+ processing; all they have to do is route things to gateways.</P>
+<H3><A name="transport.ipsec">Transport mode</A></H3>
+<P>Host machines (as opposed to security gateways) with IPsec
+ implementations must also support transport mode. In this mode, the
+ host does its own IPsec processing and routes some packets via IPsec.</P>
+<H2><A name="parts">FreeS/WAN parts</A></H2>
+<H3><A name="KLIPS.ipsec">KLIPS: Kernel IPsec Support</A></H3>
+<P>KLIPS is<STRONG> K</STRONG>erne<STRONG>L</STRONG><STRONG> IP</STRONG>
+SEC<STRONG> S</STRONG>upport, the modifications necessary to support
+ IPsec within the Linux kernel. KILPS does all the actual IPsec
+ packet-handling, including</P>
+<UL>
+<LI>encryption</LI>
+<LI>packet authentication calculations</LI>
+<LI>creation of ESP and AH headers for outgoing packets</LI>
+<LI>interpretation of those headers on incoming packets</LI>
+</UL>
+<P>KLIPS also checks all non-IPsec packets to ensure they are not
+ bypassing IPsec security policies.</P>
+<H3><A name="Pluto.ipsec">The Pluto daemon</A></H3>
+<P><A href="manpage.d/ipsec_pluto.8.html">Pluto(8)</A> is a daemon which
+ implements the IKE protocol. It</P>
+<UL>
+<LI>handles all the Phase one ISAKMP SAs</LI>
+<LI>performs host authentication and negotiates with other gateways</LI>
+<LI>creates IPsec SAs and passes the data required to run them to KLIPS</LI>
+<LI>adjust routing and firewall setup to meet IPsec requirements. See
+ our<A href="firewall.html"> IPsec and firewalling</A> document for
+ details.</LI>
+</UL>
+<P>Pluto is controlled mainly by the<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> configuration file.</P>
+<H3><A name="command">The ipsec(8) command</A></H3>
+<P>The<A href="manpage.d/ipsec.8.html"> ipsec(8)</A> command is a front
+ end shellscript that allows control over IPsec activity.</P>
+<H3><A name="ipsec.conf">Linux FreeS/WAN configuration file</A></H3>
+<P>The configuration file for Linux FreeS/WAN is</P>
+<PRE> /etc/ipsec.conf</PRE>
+<P>For details see the<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A> manual page .</P>
+<H2><A name="key">Key management</A></H2>
+<P>There are several ways IPsec can manage keys. Not all are implemented
+ in Linux FreeS/WAN.</P>
+<H3><A name="current">Currently Implemented Methods</A></H3>
+<H4><A name="manual">Manual keying</A></H4>
+<P>IPsec allows keys to be manually set. In Linux FreeS/WAN, such keys
+ are stored with the connection definitions in /etc/ipsec.conf.</P>
+<P><A href="glossary.html#manual">Manual keying</A> is useful for
+ debugging since it allows you to test the<A href="glossary.html#KLIPS">
+ KLIPS</A> kernel IPsec code without the<A href="glossary.html#Pluto">
+ Pluto</A> daemon doing key negotiation.</P>
+<P>In general, however, automatic keying is preferred because it is more
+ secure.</P>
+<H4><A name="auto">Automatic keying</A></H4>
+<P>In automatic keying, the<A href="glossary.html#Pluto"> Pluto</A>
+ daemon negotiates keys using the<A href="glossary.html#IKE"> IKE</A>
+ Internet Key Exchange protocol. Connections are automatically re-keyed
+ periodically.</P>
+<P>This is considerably more secure than manual keying. In either case
+ an attacker who acquires a key can read every message encrypted with
+ that key, but automatic keys can be changed every few hours or even
+ every few minutes without breaking the connection or requiring
+ intervention by the system administrators. Manual keys can only be
+ changed manually; you need to shut down the connection and have the two
+ admins make changes. Moreover, they have to communicate the new keys
+ securely, perhaps with<A href="glossary.html#PGP"> PGP</A> or<A href="glossary.html#SSH">
+ SSH</A>. This may be possible in some cases, but as a general solution
+ it is expensive, bothersome and unreliable. Far better to let<A href="glossary.html#Pluto">
+ Pluto</A> handle these chores; no doubt the administrators have enough
+ to do.</P>
+<P>Also, automatic keying is inherently more secure against an attacker
+ who manages to subvert your gateway system. If manual keying is in use
+ and an adversary acquires root privilege on your gateway, he reads your
+ keys from /etc/ipsec.conf and then reads all messages encrypted with
+ those keys.</P>
+<P>If automatic keying is used, an adversary with the same privileges
+ can read /etc/ipsec.secrets, but this does not contain any keys, only
+ the secrets used to authenticate key exchanges. Having an adversary
+ able to authenticate your key exchanges need not worry you overmuch.
+ Just having the secrets does not give him any keys. You are still
+ secure against<A href="glossary.html#passive"> passive</A> attacks.
+ This property of automatic keying is called<A href="glossary.html#PFS">
+ perfect forward secrecy</A>, abbreviated PFS.</P>
+<P>Unfortunately, having the secrets does allow an<A href="glossary.html#active">
+ active attack</A>, specifically a<A href="glossary.html#middle">
+ man-in-the-middle</A> attack. Losing these secrets to an attacker may
+ not be quite as disastrous as losing the actual keys, but it is<EM>
+ still a serious security breach</EM>. These secrets should be guarded
+ as carefully as keys.</P>
+<H3><A name="notyet">Methods not yet implemented</A></H3>
+<H4><A name="noauth">Unauthenticated key exchange</A></H4>
+<P>It would be possible to exchange keys without authenticating the
+ players. This would support<A href="glossary.html#carpediem">
+ opportunistic encryption</A> -- allowing any two systems to encrypt
+ their communications without requiring a shared PKI or a previously
+ negotiated secret -- and would be secure against<A href="glossary.html#passive">
+ passive attacks</A>. It would, however, be highly vulnerable to active<A
+href="glossary.html#middle"> man-in-the-middle</A> attacks. RFC 2408
+ therefore specifies that all<A href="glossary.html#ISAKMP"> ISAKMP</A>
+ key management interactions<EM> must</EM> be authenticated.</P>
+<P>There is room for debate here. Should we provide immediate security
+ against<A href="glossary.html#passive"> passive attacks</A> and
+ encourage widespread use of encryption, at the expense of risking the
+ more difficult<A href="glossary.html#active"> active attacks</A>? Or
+ should we wait until we can implement a solution that can both be
+ widespread and offer security against active attacks?</P>
+<P>So far, we have chosen the second course, complying with the RFCs and
+ waiting for secure DNS (see<A href="glossary.html#DNS"> below</A>) so
+ that we can do<A href="glossary.html#carpediem"> opportunistic
+ encryption</A> right.</P>
+<H4><A name="DNS">Key exchange using DNS</A></H4>
+<P>The IPsec RFCs allow key exchange based on authentication services
+ provided by<A href="glossary.html#SDNS"> Secure DNS</A>. Once Secure
+ DNS service becomes widely available, we expect to make this the<EM>
+ primary key management method for Linux FreeS/WAN</EM>. It is the best
+ way we know of to support<A href="glossary.html#carpediem">
+ opportunistic encryption</A>, allowing two systems without a common PKI
+ or previous negotiation to secure their communication.</P>
+<P>We currently have code to acquire RSA keys from DNS but do not yet
+ have code to validate Secure DNS signatures.</P>
+<H4><A name="PKI">Key exchange using a PKI</A></H4>
+<P>The IPsec RFCs allow key exchange based on authentication services
+ provided by a<A href="glossary.html#PKI"> PKI</A> or Public Key
+ Infrastructure. With many vendors selling such products and many large
+ organisations building these infrastructures, this will clearly be an
+ important application of IPsec and one Linux FreeS/WAN will eventually
+ support.</P>
+<P>On the other hand, this is not as high a priority for Linux FreeS/WAN
+ as solutions based on<A href="glossary.html#SDNS"> secure DNS</A>. We
+ do not expect any PKI to become as universal as DNS.</P>
+<P>Some<A href="web.html#patch"> patches</A> to handle authentication
+ with X.509 certificates, which most PKIs use, are available.</P>
+<H4><A name="photuris">Photuris</A></H4>
+<P><A href="glossary.html#photuris">Photuris</A> is another key
+ management protocol, an alternative to IKE and ISAKMP, described in
+ RFCs 2522 and 2523 which are labelled &quot;experimental&quot;. Adding Photuris
+ support to Linux FreeS/WAN might be a good project for a volunteer. The
+ likely starting point would be the OpenBSD photurisd code.</P>
+<H4><A name="skip">SKIP</A></H4>
+<P><A href="glossary.html#SKIP">SKIP</A> is yet another key management
+ protocol, developed by Sun. At one point it was fairly widely used, but
+ it now seems moribund, displaced by IKE. Sun now (as of Solaris 8.0)
+ ship an IPsec implementation using IKE. We have no plans to implement
+ SKIP. If a user were to implement it, we would almost certainly not
+ want to add the code to our distribution.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="politics.html">Previous</A>
+<A HREF="mail.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/kernel.html b/doc/kernel.html
new file mode 100644
index 000000000..de305683a
--- /dev/null
+++ b/doc/kernel.html
@@ -0,0 +1,353 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="testing.html">Previous</A>
+<A HREF="adv_config.html">Next</A>
+<HR>
+<H1><A name="kernelconfig">Kernel configuration for FreeS/WAN</A></H1>
+<P> This section lists many of the options available when configuring a
+ Linux kernel, and explains how they should be set on a FreeS/WAN IPsec
+ gateway.</P>
+<H2><A name="notall">Not everyone needs to worry about kernel
+ configuration</A></H2>
+<P>Note that in many cases you do not need to mess with these.</P>
+<P> You may have a Linux distribution which comes with FreeS/WAN
+ installed (see this<A href="intro.html#products"> list</A>). In that
+ case, you need not do a FreeS/WAN installation or a kernel
+ configuration. Of course, you might still want to configure and rebuild
+ your kernel to improve performance or security. This can be done with
+ standard tools described in the<A href="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">
+ Kernel HowTo</A>.</P>
+<P>If you need to install FreeS/WAN, then you do need to configure a
+ kernel. However, you may choose to do that using the simplest
+ procedure:</P>
+<UL>
+<LI>Configure, build and test a kernel for your system before adding
+ FreeS/WAN. See the<A href="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">
+ Kernel HowTo</A> for details.<STRONG> This step cannot be skipped</STRONG>
+. FreeS/WAN needs the results of your configuration.</LI>
+<LI>Then use FreeS/WAN's<VAR> make oldgo</VAR> command. This sets
+ everything FreeS/WAN needs and retains your values everywhere else.</LI>
+</UL>
+<P> This document is for those who choose to configure their FreeS/WAN
+ kernel themselves.</P>
+<H2><A name="assume">Assumptions and notation</A></H2>
+<P> Help text for most kernel options is included with the kernel files,
+ and is accessible from within the configuration utilities. We assume
+ you will refer to that, and to the<A href="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">
+ Kernel HowTo</A>, as necessary. This document covers only the
+ FreeS/WAN-specific aspects of the problem.</P>
+<P> To avoid duplication, this document section does not cover settings
+ for the additional IPsec-related kernel options which become available
+ after you have patched your kernel with FreeS/WAN patches. There is
+ help text for those available from within the configuration utility.</P>
+<P> We assume a common configuration in which the FreeS/WAN IPsec
+ gateway is also doing ipchains(8) firewalling for a local network, and
+ possibly masquerading as well.</P>
+<P> Some suggestions below are labelled as appropriate for &quot;a true
+ paranoid&quot;. By this we mean they may cause inconvenience and it is not
+ entirely clear they are necessary, but they appear to be the safest
+ choice. Not using them might entail some risk. Of course one suggested
+ mantra for security administrators is: &quot;I know I'm paranoid. I wonder
+ if I'm paranoid enough.&quot;</P>
+<H3><A name="labels">Labels used</A></H3>
+<P> Six labels are used to indicate how options should be set. We mark
+ the labels with [square brackets]. For two of these labels, you have no
+ choice:</P>
+<DL>
+<DT>[required]</DT>
+<DD>essential for FreeS/WAN operation.</DD>
+<DT>[incompatible]</DT>
+<DD>incompatible with FreeS/WAN.</DD>
+</DL>
+<P>those must be set correctly or FreeS/WAN will not work</P>
+<P>FreeS/WAN should work with any settings of the others, though of
+ course not all combinations have been tested. We do label these in
+ various ways, but<EM> these labels are only suggestions</EM>.</P>
+<DL>
+<DT>[recommended]</DT>
+<DD>useful on most FreeS/WAN gateways</DD>
+<DT>[disable]</DT>
+<DD>an unwelcome complication on a FreeS/WAN gateway.</DD>
+<DT>[optional]</DT>
+<DD>Your choice. We outline issues you might consider.</DD>
+<DT>[anything]</DT>
+<DD>This option has no direct effect on FreeS/WAN and related tools, so
+ you should be able to set it as you please.</DD>
+</DL>
+<P> Of course complexity is an enemy in any effort to build secure
+ systems.<STRONG> For maximum security, any feature that can reasonably
+ be turned off should be</STRONG>. &quot;If in doubt, leave it out.&quot;</P>
+<H2><A name="kernelopt">Kernel options for FreeS/WAN</A></H2>
+<P> Indentation is based on the nesting shown by 'make menuconfig' with
+ a 2.2.16 kernel for the i386 architecture.</P>
+<DL>
+<DT><A name="maturity">Code maturity and level options</A></DT>
+<DD>
+<DL>
+<DT><A name="devel">Prompt for development ... code/drivers</A></DT>
+<DD>[optional] If this is<VAR> no</VAR>, experimental drivers are not
+ shown in later menus.
+<P>For most FreeS/WAN work,<VAR> no</VAR> is the preferred setting.
+ Using new or untested components is too risky for a security gateway.</P>
+<P>However, for some hardware (such as the author's network cards) the
+ only drivers available are marked<VAR> new/experimental</VAR>. In such
+ cases, you must enable this option or your cards will not appear under
+ &quot;network device support&quot;. A true paranoid would leave this option off
+ and replace the cards.</P>
+</DD>
+<DT>Processor type and features</DT>
+<DD>[anything]</DD>
+<DT>Loadable module support</DT>
+<DD>
+<DL>
+<DT>Enable loadable module support</DT>
+<DD>[optional] A true paranoid would disable this. An attacker who has
+ root access to your machine can fairly easily install a bogus module
+ that does awful things, provided modules are enabled. A common tool for
+ attackers is a &quot;rootkit&quot;, a set of tools the attacker uses once he or
+ she has become root on your system. The kit introduces assorted
+ additional compromises so that the attacker will continue to &quot;own&quot; your
+ system despite most things you might do to recovery the situation. For
+ Linux, there is a tool called<A href="http://www.sans.org/newlook/resources/IDFAQ/knark.htm">
+ knark</A> which is basically a rootkit packaged as a kernel module.
+<P>With modules disabled, an attacker cannot install a bogus module. The
+ only way he can achieve the same effects is to install a new kernel and
+ reboot. This is considerably more likely to be noticed.</P>
+<P>Many FreeS/WAN gateways run with modules enabled. This simplifies
+ some administrative tasks and some ipchains features are available only
+ as modules. Once an enemy has root on your machine your security is
+ nil, so arguably defenses which come into play only in that situation
+ are pointless.</P>
+<P></P>
+</DD>
+<DT>Set version information ....</DT>
+<DD>[optional] This provides a check to prevent loading modules compiled
+ for a different kernel.</DD>
+<DT>Kernel module loader</DT>
+<DD>[disable] It gives little benefit on a typical FreeS/WAN gate and
+ entails some risk.</DD>
+</DL>
+</DD>
+<DT>General setup</DT>
+<DD>We list here only the options that matter for FreeS/WAN.
+<DL>
+<DT>Networking support</DT>
+<DD>[required]</DD>
+<DT>Sysctl interface</DT>
+<DD>[optional] If this option is turned on and the<VAR> /proc</VAR>
+ filesystem installed, then you can control various system behaviours by
+ writing to files under<VAR> /proc/sys</VAR>. For example:
+<PRE> echo 1 &gt; /proc/sys/net/ipv4/ipforward</PRE>
+ turns IP forwarding on.
+<P>Disabling this option breaks many firewall scripts. A true paranoid
+ would disable it anyway since it might conceivably be of use to an
+ attacker.</P>
+</DD>
+</DL>
+</DD>
+<DT>Plug and Play support</DT>
+<DD>[anything]</DD>
+<DT>Block devices</DT>
+<DD>[anything]</DD>
+<DT>Networking options</DT>
+<DD>
+<DL>
+<DT>Packet socket</DT>
+<DD>[optional] This kernel feature supports tools such as tcpdump(8)
+ which communicate directly with network hardware, bypassing kernel
+ protocols. This is very much a two-edged sword:
+<UL>
+<LI>such tools can be very useful to the firewall admin, especially
+ during initial testing</LI>
+<LI>should an evildoer breach your firewall, such tools could give him
+ or her a great deal of information about the rest of your network</LI>
+</UL>
+ We recommend disabling this option on production gateways.</DD>
+<DT><A name="netlink">Kernel/User netlink socket</A></DT>
+<DD>[optional] Required if you want to use<A href="#adv"> advanced
+ router</A> features.</DD>
+<DT>Routing messages</DT>
+<DD>[optional]</DD>
+<DT>Netlink device emulation</DT>
+<DD>[optional]</DD>
+<DT>Network firewalls</DT>
+<DD>[recommended] You need this if the IPsec gateway also functions as a
+ firewall.
+<P>Even if the IPsec gateway is not your primary firewall, we suggest
+ setting this so that you can protect the gateway with at least basic
+ local packet filters.</P>
+</DD>
+<DT>Socket filtering</DT>
+<DD>[disable] This enables an older filtering interface. We suggest
+ using ipchains(8) instead. To do that, set the &quot;Network firewalls&quot;
+ option just above, and not this one.</DD>
+<DT>Unix domain sockets</DT>
+<DD>[required] These sockets are used for communication between the<A href="manpage.d/ipsec.8.html">
+ ipsec(8)</A> commands and the<A href="manpage.d/ipsec_pluto.8.html">
+ ipsec_pluto(8)</A> daemon.</DD>
+<DT>TCP/IP networking</DT>
+<DD>[required]
+<DL>
+<DT>IP: multicasting</DT>
+<DD>[anything]</DD>
+<DT><A name="adv">IP: advanced router</A></DT>
+<DD>[optional] This gives you policy routing, which some people have
+ used to good advantage in their scripts for FreeS/WAN gateway
+ management. It is not used in our distributed scripts, so not required
+ unless you want it for custom scripts. It requires the<A href="#netlink">
+ netlink</A> interface between kernel code and the iproute2(8) command.</DD>
+<DT>IP: kernel level autoconfiguration</DT>
+<DD>[disable] It gives little benefit on a typical FreeS/WAN gate and
+ entails some risk.</DD>
+<DT>IP: firewall packet netlink device</DT>
+<DD>[disable]</DD>
+<DT>IP: transparent proxy support</DT>
+<DD>[optional] This is required in some firewall configurations, but
+ should be disabled unless you have a definite need for it.</DD>
+<DT>IP: masquerading</DT>
+<DD>[optional] Required if you want to use<A href="glossary.html#non-routable">
+ non-routable</A> private IP addresses for your local network.</DD>
+<DT>IP: Optimize as router not host</DT>
+<DD>[recommended]</DD>
+<DT>IP: tunneling</DT>
+<DD>[required]</DD>
+<DT>IP: GRE tunnels over IP</DT>
+<DD>[anything]</DD>
+<DT>IP: aliasing support</DT>
+<DD>[anything]</DD>
+<DT>IP: ARP daemon support (EXPERIMENTAL)</DT>
+<DD>Not required on most systems, but might prove useful on
+ heavily-loaded gateways.</DD>
+<DT>IP: TCP syncookie support</DT>
+<DD>[recommended] It provides a defense against a<A href="glossary.html#DOS">
+ denial of service attack</A> which uses bogus TCP connection requests
+ to waste resources on the victim machine.</DD>
+<DT>IP: Reverse ARP</DT>
+<DD></DD>
+<DT>IP: large window support</DT>
+<DD>[recommended] unless you have less than 16 meg RAM</DD>
+</DL>
+</DD>
+<DT>IPv6</DT>
+<DD>[optional] FreeS/WAN does not currently support IPv6, though work on
+ integrating FreeS/WAN with the Linux IPv6 stack has begun.<A href="compat.html#ipv6">
+ Details</A>.
+<P> It should be possible to use IPv4 FreeS/WAN on a machine which also
+ does IPv6. This combination is not yet well tested. We would be quite
+ interested in hearing results from anyone expermenting with it, via the<A
+href="mail.html"> mailing list</A>.</P>
+<P> We do not recommend using IPv6 on production FreeS/WAN gateways
+ until more testing has been done.</P>
+</DD>
+<DT>Novell IPX</DT>
+<DD>[disable]</DD>
+<DT>Appletalk</DT>
+<DD>[disable] Quite a few Linux installations use IP but also have some
+ other protocol, such as Appletalk or IPX, for communication with local
+ desktop machines. In theory it should be possible to configure IPsec
+ for the IP side of things without interfering with the second protocol.
+<P>We do not recommend this. Keep the software on your gateway as simple
+ as possible. If you need a Linux-based Appletalk or IPX server, use a
+ separate machine.</P>
+</DD>
+</DL>
+</DD>
+<DT>Telephony support</DT>
+<DD>[anything]</DD>
+<DT>SCSI support</DT>
+<DD>[anything]</DD>
+<DT>I2O device support</DT>
+<DD>[anything]</DD>
+<DT>Network device support</DT>
+<DD>[anything] should work, but there are some points to note.
+<P>The development team test almost entirely on 10 or 100 megabit
+ Ethernet and modems. In principle, any device that can do IP should be
+ just fine for IPsec, but in the real world any device that has not been
+ well-tested is somewhat risky. By all means try it, but don't bet your
+ project on it until you have solid test results.</P>
+<P>If you disabled experimental drivers in the<A href="#maturity"> Code
+ maturity</A> section above, then those drivers will not be shown here.
+ Check that option before going off to hunt for missing drivers.</P>
+<P>If you want Linux to automatically find more than one ethernet
+ interface at boot time, you need to:</P>
+<UL>
+<LI>compile the appropriate driver(s) into your kernel. Modules will not
+ work for this</LI>
+<LI>add a line such as
+<PRE>
+ append=&quot;ether=0,0,eth0 ether=0,0,eth1&quot;
+</PRE>
+ to your /etc/lilo.conf file. In some cases you may need to specify
+ parameters such as IRQ or base address. The example uses &quot;0,0&quot; for
+ these, which tells the system to search. If the search does not succeed
+ on your hardware, then you should retry with explicit parameters. See
+ the lilo.conf(5) man page for details.</LI>
+<LI>run lilo(8)</LI>
+</UL>
+ Having Linux find the cards this way is not necessary, but is usually
+ more convenient than loading modules in your boot scripts.</DD>
+<DT>Amateur radio support</DT>
+<DD>[anything]</DD>
+<DT>IrDA (infrared) support</DT>
+<DD>[anything]</DD>
+<DT>ISDN subsystem</DT>
+<DD>[anything]</DD>
+<DT>Old CDROM drivers</DT>
+<DD>[anything]</DD>
+<DT>Character devices</DT>
+<DD>The only required character device is:
+<DL>
+<DT>random(4)</DT>
+<DD>[required] This is a source of<A href="glossary.html#random"> random</A>
+ numbers which are required for many cryptographic protocols, including
+ several used in IPsec.
+<P>If you are comfortable with C source code, it is likely a good idea
+ to go in and adjust the<VAR> #define</VAR> lines in<VAR>
+ /usr/src/linux/drivers/char/random.c</VAR> to ensure that all sources
+ of randomness are enabled. Relying solely on keyboard and mouse
+ randomness is dubious procedure for a gateway machine. You could also
+ increase the randomness pool size from the default 512 bytes (128
+ 32-bit words).</P>
+</DD>
+</DL>
+</DD>
+<DT>Filesystems</DT>
+<DD>[anything] should work, but we suggest limiting a gateway machine to
+ the standard Linux ext2 filesystem in most cases.</DD>
+<DT>Network filesystems</DT>
+<DD>[disable] These systems are an unnecessary risk on an IPsec gateway.</DD>
+<DT>Console drivers</DT>
+<DD>[anything]</DD>
+<DT>Sound</DT>
+<DD>[anything] should work, but we suggest enabling sound only if you
+ plan to use audible alarms for firewall problems.</DD>
+<DT>Kernel hacking</DT>
+<DD>[disable] This might be enabled on test machines, but should not be
+ on production gateways.</DD>
+</DL>
+</DD>
+</DL>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="testing.html">Previous</A>
+<A HREF="adv_config.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/kernel.notes b/doc/kernel.notes
new file mode 100644
index 000000000..675e80be3
--- /dev/null
+++ b/doc/kernel.notes
@@ -0,0 +1,173 @@
+Notes on Red Hat 5.2 kernel installation (See Addendum for RH6.1)
+=================================================================
+
+Warning: We (the FreeS/WAN Project http://www.xs4all.nl/~freeswan/)
+had nothing to do with designing the kernel installation process. This
+document explains some tricky points that we wish we had been told.
+We don't know if these notes apply to systems other than Red Hat 5.2.
+This is meant as a supplement to other kernel install guides (such as
+the Red Hat 5.2 Installation Guide section 11.6).
+
+Goal: install a new kernel on RH5.2 in such a way that it doesn't
+interfere with any other kernels. This should be repeatable: each new
+kernel should have this property. Each should remain bootable.
+
+Problem: there are several components to a kernel, and each must be
+segregated. How are the parts kept apart? How are they found?
+
+All the parts live in the file system, so it all comes down to
+pathnames. Well, except for the fiddly bits in /etc/lilo.conf. What
+are the parts?
+
+ /lib/modules/VER/ directory for kernel modules
+ /boot/vmlinux-VER the kernel
+ /boot/System.map-VER the kernel symbol table
+ /boot/initrd-VER.img the initial ramdisk (for modules needed
+ at boot time -- usually not necessary)
+ /boot/boot.b the second-stage loader
+ /boot/map the map file, an index into system index for
+ all files used by boot loader (all kernels,
+ all initrds, perhaps /boot/boot.b, and itself)
+
+This list does not include /boot/module-info-VER. That is supplied
+by RedHat, and it isn't clear to me how to build it or why.
+
+In each entry, I've used "VER" to signify a version number. For
+RH-supplied kernels, these look like 2.0.36-0.7 (the original 5.2) or
+2.0.36-3 (the kernel updates).
+
+There are also symbolic links:
+ /lib/modules/preferred created by /etc/rc.d/rc.sysinit
+ /boot/System.map created by /etc/rc.d/rc.sysinit
+ /boot/module-info created by /etc/rc.d/rc.sysinit
+ /vmlinuz created by ???
+I don't know when the /vmlinuz symlink is set up and I don't know
+for what it is used.
+
+If you follow the RH procedures, documented in 11.6 of their Installation
+Guide, all your VERs will be 2.0.36. This is very bad: all your builds
+will step on each other. Worse, your new module directory will be half
+picked up when you boot a stock RH kernel binary!
+
+It is important to know how the various parts of the built kernel are
+found at booting.
+
+- the kernel path is specified in the image= option in lilo.conf.
+ (Lilo.conf may specify several and one is selected at boot time
+ by default or user selection.) The kernel is loaded by the
+ boot loader.
+
+- The initial ramdisk is a per-image option (initrd=) specified in
+ lilo.conf. (It isn't described in the RH5.2 lilo.conf(5) manpage!).
+ The initial ramdisk is loaded into RAM by the boot loader.
+
+- Since the boot loader doesn't know about the file system, it needs a
+ map to figure out which absolute disk blocks to load, and where.
+ This is /boot/map. It is built by the lilo command (also known as
+ the map installer). It will have indices for the all the kernels
+ that can be booted, all their initial ram disks, perhaps
+ /boot/boot.b, and itself. This is why moving the blocks of these
+ files throws off the boot loader -- lilo must be rerun after even a
+ cp command to one of them.
+
+- the modules directory is found two different ways. Unfortunately,
+ they don't mesh properly:
+
+ + at boot time, /etc/rc.d/rc.sysinit tries to figure out the correct
+ subdirectory of /lib/modules, using the .rhkmvtag trick (see
+ later). It then builds a symlink /lib/modules/preferred to
+ record this. It also invokes depmod to build the module
+ dependency info. At the same time, it creates the symlinks
+ /boot/System.map and /boot/module-info, using the inferred
+ value for VER!
+
+ + modprobe and friends stupidly look first in /lib/modules/2.0.36
+ (more precisely, /lib/modules/`uname -r`) and then in
+ /lib/modules/preferred. So if there is a /lib/modules/2.0.36 and
+ it is the wrong one, you are in trouble.
+
+ If there is no /lib/modules/2.0.36, then both searches above will
+ agree (a very Good Thing). So I recommend strongly that you not
+ have a /lib/boot/2.0.36 at boot time. Unfortunately, you will get
+ one during the kernel install process. Be sure to rename it. I
+ suggest using 2.0.36-x (for some unique x) as VER.
+
+- Red Hat supplied /lib/modules/VER directories contain a hidden file
+ .rhkmvtag. This file contains exactly one line. This line is
+ exactly the same as the contents of /proc/version while the
+ corresponding kernel is running. For the stock kernel, the line is:
+Linux version 2.0.36 (root@porky.redhat.com) (gcc version 2.7.2.3) #1 Tue Dec 29 13:11:13 EST 1998
+
+- At boot time, /etc/rc.d/rc.sysinit uses the .rhkmvtag files to
+ figure out which of the /lib/modules/* directories matches the
+ kernel. If it could figure out the directory, it uses this
+ information to set the symlinks mentioned above. It then runs
+ depmod to build the module dependency information (in
+ /lib/modules/preferred/modules.dep, if it created the
+ /lib/modules/preferred symlink). I recommend looking at the code.
+
+- The documented kernel install procedures DO NOT fill in the
+ .rhkmvtag file for the new modules directory! So you should do so
+ by hand. You have to figure out what the contents should be. Here
+ is is a command that will do the job, assuming that
+ /usr/src/linux/vmlinux is the kernel associated with
+ /lib/modules/2.0.36/:
+
+ strings /usr/src/linux/vmlinux \
+ | grep 'x version' >/lib/modules/2.0.36/.rhkmvtag
+
+I've recommended (above) that you use 2.0.36-x for VER when you install
+a kernel. What should x be? I have found that there is a hidden file
+/usr/src/linux/.version which contains a counter that gets incremented
+whenever you do a "make install" in the kernel (see target
+newversion). There are some other times that it gets incremented, but
+I think that it all works out. It also gets incorporated into the
+resulting kernel's /proc/version, prefixed with ``#''. This makes it
+a natural.
+
+Here is a script to do the recommended renaming:
+
+ # VER will eventually need to be updated
+ VER=2.0.36
+ VERX=${VER}-`cat /usr/src/linux/.version`
+
+ strings /usr/src/linux/vmlinux | grep 'x version' >/lib/modules/$VER/.rhkmvtag
+ mv /lib/modules/$VER /lib/modules/$VERX
+ mv /boot/System.map-$VER /boot/System.map-$VERX
+ mv /boot/vmlinuz-$VER /boot/vmlinuz-$VERX
+
+And, if an initrd has been built (usually it is best to arrange not to
+use one -- see the Red Hat Installation Guide):
+
+ /sbin/mkinitrd /boot/initrd-$VERX.img $VERX
+
+Remember: a new lilo.conf entry is needed for the new kernel, and then
+the lilo command will need to be rerun.
+
+Now that kernel installs don't overwrite the results of previous ones,
+you will need to manually delete the components and their lilo entry
+to get rid of them.
+
+Please send comments, additions, and corrections to:
+
+Hugh Redelmeier
+hugh@mimosa.com voice: +1 416 482-8253
+
+
+Addendum: Red Hat 6.1
+=====================
+
+The kernel supplied with RH6.1 kernel is out of date, so you might
+wish to use a newer one.
+
+Much of the description for 5.2 still applies, but the procedure is
+quite different because the .version file is no longer used. Instead,
+the top-level Makefile contains a definition EXTRAVERSION which adds a
+qualifier to the version for most purposes. No manual renaming is
+required.
+
+Before building the kernel, change EXTRAVERSION by editing
+/usr/src/linux/Makefile, and make an appropriate entry in /etc/lilo.conf.
+
+EXTRAVERSION is a feature of the standard kernel sources, not just the
+ones supplied by Red Hat.
diff --git a/doc/mail.html b/doc/mail.html
new file mode 100644
index 000000000..68b5d8cd8
--- /dev/null
+++ b/doc/mail.html
@@ -0,0 +1,216 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="ipsec.html">Previous</A>
+<A HREF="web.html">Next</A>
+<HR>
+<H1><A name="lists">Mailing lists and newsgroups</A></H1>
+<H2><A name="list.fs">Mailing lists about FreeS/WAN</A></H2>
+<H3><A name="projlist">The project mailing lists</A></H3>
+<P>The Linux FreeS/WAN project has several email lists for user support,
+ bug reports and software development discussions.</P>
+<P>We had a single list on clinet.fi for several years (Thanks, folks!),
+ then one list on freeswan.org, but now we've split into several lists:</P>
+<DL>
+<DT><A href="mailto:users-request@lists.freeswan.org?body=subscribe">
+users</A></DT>
+<DD>
+<UL>
+<LI>The general list for discussing use of the software</LI>
+<LI>The place for seeking<STRONG> help with problems</STRONG> (but
+ please check the<A href="faq.html"> FAQ</A> first).</LI>
+<LI>Anyone can post.</LI>
+</UL>
+</DD>
+<DT><A href="mailto:bugs-request@lists.freeswan.org?body=subscribe">bugs</A>
+</DT>
+<DD>
+<UL>
+<LI>For<STRONG> bug reports</STRONG>.</LI>
+<LI>If you are not certain what is going on -- could be a bug, a
+ configuration error, a network problem, ... -- please post to the users
+ list instead.</LI>
+<LI>Anyone can post.</LI>
+</UL>
+</DD>
+<DT><A href="mailto:design-request@lists.freeswan.org?body=subscribe">
+design</A></DT>
+<DD>
+<UL>
+<LI><STRONG>Design discussions</STRONG>, for people working on FreeS/WAN
+ development or others with an interest in design and security issues.</LI>
+<LI>It would be a good idea to read the existing design papers (see this<A
+href="intro.html#applied"> list</A>) before posting.</LI>
+<LI>Anyone can post.</LI>
+</UL>
+</DD>
+<DT><A href="mailto:announce-request@lists.freeswan.org?body=subscribe">
+announce</A></DT>
+<DD>
+<UL>
+<LI>A<STRONG> low-traffic</STRONG> list.</LI>
+<LI><STRONG>Announcements</STRONG> about FreeS/WAN and related software.</LI>
+<LI>All posts here are also sent to the users list. You need not
+ subscribe to both.</LI>
+<LI>Only the FreeS/WAN team can post.</LI>
+<LI>If you have something you feel should go on this list, send it to<VAR>
+ announce-admin@lists.freeswan.org</VAR>. Unless it is obvious, please
+ include a short note explaining why we should post it.</LI>
+</UL>
+</DD>
+<DT><A href="mailto:briefs-request@lists.freeswan.org?body=subscribe">
+briefs</A></DT>
+<DD>
+<UL>
+<LI>A<STRONG> low-traffic</STRONG> list.</LI>
+<LI><STRONG>Weekly summaries</STRONG> of activity on the users list.</LI>
+<LI>All posts here are also sent to the users list. You need not
+ subscribe to both.</LI>
+<LI>Only the FreeS/WAN team can post.</LI>
+</UL>
+</DD>
+</DL>
+<P>To subscribe to any of these, you can:</P>
+<UL>
+<LI>just follow the links above</LI>
+<LI>use our<A href="http://www.freeswan.org/mail.html"> web interface</A>
+</LI>
+<LI>send mail to<VAR> listname</VAR>-request@lists.freeswan.org with a
+ one-line message body &quot;subscribe&quot;</LI>
+</UL>
+<P>Archives of these lists are available via the<A href="http://www.freeswan.org/mail.html">
+ web interface</A>.</P>
+<H4><A name="which.list">Which list should I use?</A></H4>
+<P>For most questions, please check the<A href="faq.html"> FAQ</A>
+ first, and if that does not have an answer, ask on the users list. &quot;My
+ configuration doesn't work.&quot; does not belong on the bugs list, and &quot;Can
+ FreeS/WAN do such-and-such&quot; or &quot;How do I configure it to...&quot; do not
+ belong in design discussions.</P>
+<P>Cross-posting the same message to two or more of these lists is
+ discouraged. Quite a few people read more than one list and getting
+ multiple copies is annoying.</P>
+<H4><A name="policy.list">List policies</A></H4>
+<P><STRONG>US citizens or residents are asked not to post code to the
+ lists, not even one-line bug fixes</STRONG>. The project cannot accept
+ code which might entangle it in US<A href="politics.html#exlaw"> export
+ restrictions</A>.</P>
+<P>Non-subscribers can post to some of these lists. This is necessary;
+ someone working on a gateway install who encounters a problem may not
+ have access to a subscribed account.</P>
+<P>Some spam turns up on these lists from time to time. For discussion
+ of why we do not attempt to filter it, see the<A href="faq.html#spam">
+ FAQ</A>. Please do not clutter the lists with complaints about this.</P>
+<H3><A name="archive">Archives of the lists</A></H3>
+<P>Searchable archives of the old single list have existed for some
+ time. At time of writing, it is not yet clear how they will change for
+ the new multi-list structure.</P>
+<UL>
+<LI><A href="http://www.sandelman.ottawa.on.ca/linux-ipsec">Canada</A></LI>
+<LI><A href="http://www.nexial.com">Holland</A></LI>
+</UL>
+<P>Note that these use different search engines. Try both.</P>
+<P>Archives of the new lists are available via the<A href="http://www.freeswan.org/mail.html">
+ web interface</A>.</P>
+<H2><A name="indexes">Indexes of mailing lists</A></H2>
+<P><A href="http://paml.net/">PAML</A> is the standard reference for<STRONG>
+ P</STRONG>ublicly<STRONG> A</STRONG>ccessible<STRONG> M</STRONG>ailing<STRONG>
+ L</STRONG>ists. When we last checked, it had over 7500 lists on an
+ amazing variety of topics. It also has FAQ information and a search
+ engine.</P>
+<P>There is an index of<A href="http://oslab.snu.ac.kr/~djshin/linux/mail-list/index.shtml">
+ Linux mailing lists</A> available.</P>
+<P>A list of<A href="http://xforce.iss.net/maillists/otherlists.php">
+ computer security mailing lists</A>, with descriptions.</P>
+<H2><A name="otherlists">Lists for related software and topics</A></H2>
+<P>Most links in this section point to subscription addresses for the
+ various lists. Send the one-line message &quot;subscribe<VAR> list_name</VAR>
+&quot; to subscribe to any of them.</P>
+<H3><A NAME="28_3_1">Products that include FreeS/WAN</A></H3>
+<P>Our introduction document gives a<A href="intro.html#products"> list
+ of products that include FreeS/WAN</A>. If you have, or are
+ considering, one of those, check the supplier's web site for
+ information on mailing lists for their users.</P>
+<H3><A name="linux.lists">Linux mailing lists</A></H3>
+<UL>
+<LI><A href="mailto:majordomo@vger.kernel.org">
+linux-admin@vger.kernel.org</A>, for Linux system administrators</LI>
+<LI><A href="mailto:netfilter-request@lists.samba.org">
+netfilter@lists.samba.org</A>, about Netfilter, which replaces IPchains
+ in kernels 2.3.15 and later</LI>
+<LI><A href="mailto:security-audit-request@ferret.lmh.ox.ac.uk">
+security-audit@ferret.lmh.ox.ac.uk</A>, for people working on security
+ audits of various Linux programs</LI>
+<LI><A href="mailto:securedistros-request@humbolt.geo.uu.nl">
+securedistros@humbolt.geo.uu.nl</A>, for discussion of issues common to
+ all the half dozen projects working on secure Linux distributions.</LI>
+</UL>
+<P>Each of the scure distribution projects also has its own web site and
+ mailing list. Some of the sites are:</P>
+<UL>
+<LI><A href="http://bastille-linux.org/">Bastille Linux</A> scripts to
+ harden Redhat, e.g. by changing permissions and modifying inialisation
+ scripts</LI>
+<LI><A href="http://immunix.org/">Immunix</A> take a different approach,
+ using a modified compiler to build kernel and utilities with better
+ resistance to various types of overflow and exploit</LI>
+<LI>the<A href="glossary.html#NSA"> NSA</A> have contractors working on
+ a<A href="glossary.html#SElinux"> Security Enhanced Linux</A>,
+ primarily adding stronger access control mechanisms. You can download
+ the current version (which interestingly is under GPL and not export
+ resrtricted) or subscribe to the mailing list from the<A href="http://www.nsa.gov/selinux">
+ project web page</A>.</LI>
+</UL>
+<H3><A name="ietf">Lists for IETF working groups</A></H3>
+<P>Each<A href="glossary.html#IETF"> IETF</A> working group has an
+ associated mailing list where much of the work takes place.</P>
+<UL>
+<LI><A href="mailto:majordomo@lists.tislabs.com">ipsec@lists.tislabs.com</A>
+, the IPsec<A href="http://www.ietf.org/html.charters/ipsec-charter.html">
+ working group</A>. This is where the protocols are discussed, new
+ drafts announced, and so on. By now, the IPsec working group is winding
+ down since the work is essentially complete. A<A href="http://www.sandelman.ottawa.on.ca/ipsec/">
+ list archive</A> is available.</LI>
+<LI><A href="mailto:ipsec-policy-request@vpnc.org">IPsec policy</A>
+ list, and its<A href="http://www.vpnc.org/ipsec-policy/"> archive</A></LI>
+<LI><A href="mailto:ietf-ipsra-request@vpnc.org">IP secure remote access</A>
+ list, and its<A href="http://www.vpnc.org/ietf-ipsra/mail-archive/">
+ archive</A></LI>
+</UL>
+<H3><A name="other">Other mailing lists</A></H3>
+<UL>
+<LI><A href="mailto:ipc-announce-request@privacy.org">
+ipc-announce@privacy.org</A> a low-traffic list with announcements of
+ developments in privacy, encryption and online civil rights</LI>
+<LI>a VPN mailing list's<A href="http://kubarb.phsx.ukans.edu/~tbird/vpn.html">
+ home page</A></LI>
+</UL>
+<H2><A name="newsgroups">Usenet newsgroups</A></H2>
+<UL>
+<LI>sci.crypt</LI>
+<LI>sci.crypt.research</LI>
+<LI>comp.dcom.vpn</LI>
+<LI>talk.politics.crypto</LI>
+</UL>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="ipsec.html">Previous</A>
+<A HREF="web.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/makecheck.html b/doc/makecheck.html
new file mode 100644
index 000000000..e77631782
--- /dev/null
+++ b/doc/makecheck.html
@@ -0,0 +1,523 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="umltesting.html">Previous</A>
+<A HREF="nightly.html">Next</A>
+<HR>
+<H1><A name="makecheck">How to configure to use &quot;make check&quot;</A></H1>
+<H2><A NAME="38_1">What is &quot;make check&quot;</A></H2>
+<P> &quot;make check&quot; is a target in the top level makefile. It takes care of
+ running a number of unit and system tests to confirm that FreeSWAN has
+ been compiled correctly, and that no new bugs have been introduced.</P>
+<P> As FreeSWAN contains both kernel and userspace components, doing
+ testing of FreeSWAN requires that the kernel be simulated. This is
+ typically difficult to do as a kernel requires that it be run on bare
+ hardware. A technology has emerged that makes this simpler. This is<A HREF="http://user-mode-linux.sourceforge.net">
+ User Mode Linux</A>.</P>
+<P> User-Mode Linux is a way to build a Linux kernel such that it can
+ run as a process under another Linux (or in the future other) kernel.
+ Presently, this can only be done for 2.4 guest kernels. The host kernel
+ can be 2.2 or 2.4.</P>
+<P> &quot;make check&quot; expects to be able to build User-Mode Linux kernels
+ with FreeSWAN included. To do this it needs to have some files
+ downloaded and extracted prior to running &quot;make check&quot;. This is
+ described in the<A HREF="umltesting.html"> UML testing</A> document.</P>
+<P> After having run the example in the UML testing document and
+ successfully brought up the four machine combination, you are ready to
+ use &quot;make check&quot;</P>
+<H2><A NAME="38_2">Running &quot;make check&quot;</A></H2>
+<P> &quot;make check&quot; works by walking the FreeSWAN source tree invoking the
+ &quot;check&quot; target at each node. At present there are tests defined only
+ for the <CODE>klips</CODE> directory. These tests will use the UML
+ infrastructure to test out pieces of the <CODE>klips</CODE> code.</P>
+<P> The results of the tests can be recorded. If the environment
+ variable <CODE>$REGRESSRESULTS</CODE> is non-null, then the results of
+ each test will be recorded. This can be used as part of a nightly
+ regression testing system, see<A HREF="nightly.html"> Nightly testing</A>
+ for more details.</P>
+<P> &quot;make check&quot; otherwise prints a minimal amount of output for each
+ test, and indicates pass/fail status of each test as they are run.
+ Failed tests do not cause failure of the target in the form of exit
+ codes.</P>
+<H1><A NAME="39">How to write a &quot;make check&quot; test</A></H1>
+<H2><A NAME="39_1">Structure of a test</A></H2>
+<P> Each test consists of a set of directories under <CODE>testing/</CODE>
+. There are directories for <CODE>klips</CODE>, <CODE>pluto</CODE>, <CODE>
+packaging</CODE> and <CODE>libraries</CODE>. Each directory has a list
+ of tests to run is stored in a file called <CODE>TESTLIST</CODE> in
+ that directory. e.g. <CODE>testing/klips/TESTLIST</CODE>.</P>
+<H2 NAME="TESTLIST"><A NAME="39_2">The TESTLIST</A></H2>
+<P> This isn't actually a shell script. It just looks like one. Some
+ tools other than /bin/sh process it. Lines that start with # are
+ comments.</P>
+<PRE>
+# test-kind directory-containing-test expectation [PR#]
+</PRE>
+<P>The first word provides the test type, detailed below.</P>
+<P> The second word is the name of the test to run. This the directory
+ in which the test case is to be found..</P>
+<P>The third word may be one of:</P>
+<DL>
+<DT> blank/good</DT>
+<DD>the test is believed to function, report failure</DD>
+<DT> bad</DT>
+<DD> the test is known to fail, report unexpected success</DD>
+<DT> suspended</DT>
+<DD> the test should not be run</DD>
+</DL>
+<P> The fourth word may be a number, which is a PR# if the test is
+ failing.</P>
+<H2><A NAME="39_3">Test kinds</A></H2>
+ The test types are:
+<DL>
+<DT>skiptest</DT>
+<DD>means run no test.</DD>
+<DT>ctltest</DT>
+<DD>means run a single system without input/output.</DD>
+<DT>klipstest</DT>
+<DD>means run a single system with input/output networks</DD>
+<DT><A HREF="#umlplutotest">umlplutotest</A></DT>
+<DD>means run a pair of systems</DD>
+<DT><A HREF="#umlXhost">umlXhost</A></DT>
+<DD>run an arbitrary number of systems</DD>
+<DT>suntest (TBD)</DT>
+<DD>means run a quad of east/west/sunrise/sunset</DD>
+<DT>roadtest (TBD)</DT>
+<DD>means run a trio of east-sunrise + warrior</DD>
+<DT>extrudedtest (TBD)</DT>
+<DD>means run a quad of east-sunrise + warriorsouth + park</DD>
+<DT>mkinsttest</DT>
+<DD>a test of the &quot;make install&quot; machinery.</DD>
+<DT>kernel_test_patch</DT>
+<DD>a test of the &quot;make kernelpatch&quot; machinery.</DD>
+</DL>
+ Tests marked (TBD) have yet to be fully defined.
+<P> Each test directory has a file in it called <CODE>testparams.sh</CODE>
+. This file sets a number of environment variables to define the
+ parameters of the test.</P>
+<H2><A NAME="39_4">Common parameters</A></H2>
+<DL>
+<DT>TESTNAME</DT>
+<DD>the name of the test (repeated for checking purposes)</DD>
+<DT>TEST_TYPE</DT>
+<DD>the type of the test (repeat of type type above)</DD>
+<DT>TESTHOST</DT>
+<DD>the name of the UML machine to run for the test, typically &quot;east&quot; or
+ &quot;west&quot;</DD>
+<DT>TEST_PURPOSE</DT>
+<DD>The purpose of the test is one of:
+<DL>
+<DT>goal</DT>
+<DD>The goal purpose is where a test is defined for code that is not yet
+ finished. The test indicates when the goals have in fact been reached.</DD>
+<DT>regress</DT>
+<DD>This is a test to determine that a previously existing bug has been
+ repaired. This test will initially be created to reproduce the bug in
+ isolation, and then the bug will be fixed.</DD>
+<DT>exploit</DT>
+<DD>This is a set of packets/programs that causes a vulnerability to be
+ exposed. It is a specific variation of the regress option.</DD>
+</DL>
+</DD>
+<DT>TEST_GOAL_ITEM</DT>
+<DT></DT>
+<DD>in the case of a goal test, this is a reference to the requirements
+ document</DD>
+<DT>TEST_PROB_REPORT</DT>
+<DD>in the case of regression test, this the problem report number from
+ GNATS</DD>
+<DT>TEST_EXPLOIT_URL</DT>
+<DD>in the case of an exploit, this is a URL referencing the paper
+ explaining the origin of the test and the origin of exploit software</DD>
+<DT>REF_CONSOLE_OUTPUT</DT>
+<DD>a file in the test directory that contains the sanitized console
+ output against which to compare the output of the actual test.</DD>
+<DT>REF_CONSOLE_FIXUPS</DT>
+<DD>a list of scripts (found in <CODE>klips/test/fixups</CODE>) to apply
+ to sanitize the console output of the machine under test. These are
+ typically perl, awk or sed scripts that remove things in the kernel
+ output that change each time the test is run and/or compiled.</DD>
+<DT>INIT_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode prior to starting the tests. This file will usually
+ set up any eroute's and SADB entries that are required for the test.</P>
+<P>Lines beginning with # are skipped. Blank lines are skipped.
+ Otherwise, a shell prompted is waited for each time (consisting of <CODE>
+\n#</CODE>) and then the command is sent. Note that the prompt is waited
+ for before the command and not after, so completion of the last command
+ in the script is not required. This is often used to invoke a program
+ to monitor the system, e.g. <CODE>ipsec pf_key</CODE>.</P>
+</DD>
+<DT>RUN_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode, before the packets are sent. On single machine tests,
+ this script doesn't provide any more power than INIT_SCRIPT, but is
+ implemented for consistency's sake.</P>
+</DD>
+<DT>FINAL_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode after the final packet is sent. Similar to
+ INIT_SCRIPT, above. If not specified, then the single command &quot;halt&quot; is
+ sent. If specified, then the script should end with a halt command to
+ nicely shutdown the UML.</P>
+</DD>
+<DT>CONSOLEDIFFDEBUG</DT>
+<DD>If set to &quot;true&quot; then the series of console fixups (see
+ REF_CONSOLE_FIXUPS) will be output after it is constructed. (It should
+ be set to &quot;false&quot;, or unset otherwise)</DD>
+<DT>NETJIGDEBUG</DT>
+<DD>If set to &quot;true&quot; then the series of console fixups (see
+ REF_CONSOLE_FIXUPS) will be output after it is constructed. (It should
+ be set to &quot;false&quot;, or unset otherwise)</DD>
+<DT>NETJIGTESTDEBUG</DT>
+<DD> If set to &quot;netjig&quot;, then the results of talking to the <CODE>
+uml_netjig</CODE> will be printed to stderr during the test. In
+ addition, the jig will be invoked with --debug, which causes it to log
+ its process ID, and wait 60 seconds before continuing. This can be used
+ if you are trying to debug the <CODE>uml_netjig</CODE> program itself.</DD>
+<DT>HOSTTESTDEBUG</DT>
+<DD> If set to &quot;hosttest&quot;, then the results of taling to the consoles of
+ the UMLs will be printed to stderr during the test.</DD>
+<DT>NETJIGWAITUSER</DT>
+<DD> If set to &quot;waituser&quot;, then the scripts will wait forever for user
+ input before they shut the tests down. Use this is if you are debugging
+ through the kernel.</DD>
+<DT>PACKETRATE</DT>
+<DD> A number, in miliseconds (default is 500ms) at which packets will
+ be replayed by the netjig.</DD>
+</DL>
+<H2><A NAME="39_5">KLIPStest paramaters</A></H2>
+<P> The klipstest function starts a program (<CODE>
+testing/utils/uml_netjig/uml_netjig</CODE>) to setup a bunch of I/O
+ sockets (that simulate network interfaces). It then exports the
+ references to these sockets to the environment and invokes (using
+ system()) a given script. It waits for the script to finish.</P>
+
+<!-- <IMG SRC="single_netjig.png" ALT="block diagram of uml_netjig"> -->
+<P> The script invoked (<CODE>testing/utils/host-test.tcl</CODE>) is a
+ TCL<A HREF="http://expect.nist.gov/"> expect</A> script that arranges
+ to start the UML and configure it appropriately for the test. The
+ configuration is done with the script given above for<VAR> INIT_SCRIPT</VAR>
+. The TCL script then forks, leaves the UML in the background and exits.
+ uml_netjig continues. It then starts listening to the simulated network
+ answering ARPs and inserting packets as appropriate.</P>
+<P> The klipstest function invokes <CODE>uml_netjig</CODE> with
+ arguments to capture output from network interface(s) and insert
+ packets as appropriate:</P>
+<DL>
+<DT>PUB_INPUT</DT>
+<DD>a<A HREF="http://www.tcpdump.org/"> pcap</A> file to feed in on the
+ public (encrypted) interface. (typically, eth1)</DD>
+<DT>PRIV_INPUT</DT>
+<DD>a pcap file to feed in on the private (plain-text) interface
+ (typically, eth0).</DD>
+<DT>REF_PUB_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the public (eth1)
+ interface are captured to a<A HREF="http://www.tcpdump.org/"> pcap</A>
+ file by <CODE>uml_netjig</CODE>. The klipstest function then uses
+ tcpdump on the file to produce text output, which is compared to the
+ file given.</DD>
+<DT>REF_PUB_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+<DT>REF_PRIV_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the private (eth0)
+ interface are captured and compared after conversion by tcpdump, as
+ with<VAR> REFPUBOUTPUT</VAR>.</DD>
+<DT>REF_PRIV_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+<DT>EXITONEMPTY</DT>
+<DD>a flag for <CODE>uml_netjig</CODE>. It should contain
+ &quot;--exitonempty&quot; of uml_netjig should exit when all of the input (<VAR>
+PUBINPUT</VAR>,<VAR>PRIVINPUT</VAR>) packets have been injected.</DD>
+<DT>ARPREPLY</DT>
+<DD>a flag for <CODE>uml_netjig</CODE>. It should contain &quot;--arpreply&quot;
+ if <CODE>uml_netjig</CODE> should reply to ARP requests. One will
+ typically set this to avoid having to fudge the ARP cache manually.</DD>
+<DT>TCPDUMPFLAGS</DT>
+<DD>a set of flags for the tcpdump used when converting captured output.
+ Typical values will include &quot;-n&quot; to turn off DNS, and often &quot;-E&quot; to set
+ the decryption key (tcpdump 3.7.1 and higher only) for ESP packets. The
+ &quot;-t&quot; flag (turn off timestamps) is provided automatically</DD>
+<DT>NETJIG_EXTRA</DT>
+<DD>additional comments to be sent to the netjig. This may arrange to
+ record or create additional networks, or may toggle options.</DD>
+</DL>
+<H2><A NAME="39_6">mkinsttest paramaters</A></H2>
+<P> The basic concept of the <CODE>mkinsttest</CODE> test type is that
+ it performs a &quot;make install&quot; to a temporary $DESTDIR. The resulting
+ tree can then be examined to determine if it was done properly. The
+ files can be uninstalled to determine if the file list was correct, or
+ the contents of files can be examined more precisely.</P>
+<DL>
+<DT>INSTALL_FLAGS</DT>
+<DD>If set, then an install will be done. This provides the set of flags
+ to provide for the install. The target to be used (usually &quot;install&quot;)
+ must be among the flags.</DD>
+<DT>POSTINSTALL_SCRIPT</DT>
+<DD>If set, a script to run after initial &quot;make install&quot;. Two arguments
+ are provided: an absolute path to the root of the FreeSWAN src tree,
+ and an absolute path to the temporary installation area.</DD>
+<DT>INSTALL2_FLAGS</DT>
+<DD>If set, a second install will be done using these flags. Similarly
+ to INSTALL_FLAGS, the target must be among the flags.</DD>
+<DT>UNINSTALL_FLAGS</DT>
+<DD>If set, an uninstall will be done using these flags. Similarly to
+ INSTALL_FLAGS, the target (usually &quot;uninstall&quot;) must be among the
+ flags.</DD>
+<DT>REF_FIND_f_l_OUTPUT</DT>
+<DD>If set, a <CODE>find $ROOT ( -type f -or -type -l )</CODE> will be
+ done to get a list of a real files and symlinks. The resulting file
+ will be compared to the file listed by this option.</DD>
+<DT>REF_FILE_CONTENTS</DT>
+<DD>If set, it should point to a file containing records for the form:
+<PRE>
+
+<!--VARIABLE-->
+reffile</(null)>
+<!--VARIABLE-->
+samplefile</(null)>
+</PRE>
+ one record per line. A diff between the provided reference file, and
+ the sample file (located in the temporary installation root) will be
+ done for each record.</DD>
+</DL>
+<H2><A NAME="39_7">rpm_build_install_test paramaters</A></H2>
+<P> The <CODE>rpm_build_install_test</CODE> type is to verify that the
+ proper packing list is produced by &quot;make rpm&quot;, and that the mechanisms
+ for building the kernel modules produce consistent results.</P>
+<DL>
+<DT>RPM_KERNEL_SOURCE</DT>
+<DD>Point to an extracted copy of the RedHat kernel source code.
+ Variables from the environment may be used.</DD>
+<DT>REF_RPM_CONTENTS</DT>
+<DD>This is a file containing one record per line. Each record consists
+ of a RPM name (may contain wildcards) and a filename to compare the
+ contents to. The RPM will be located and a file list will be produced
+ with rpm2cpio.</DD>
+</DL>
+<H2><A NAME="39_8">libtest paramaters</A></H2>
+<P> The libtest test is for testing library routines. The library file
+ is expected to provided an <CODE>#ifdef</CODE> by the name of<VAR>
+ library</VAR>
+<!--CODE_MAIN</CODE-->
+. The libtest type invokes the C compiler to compile this
+ file, links it against <CODE>libfreeswan.a</CODE> (to resolve any other
+ dependancies) and runs the test with the <CODE>-r</CODE> argument to
+ invoke a regression test.</(null)></P>
+<P>The library test case is expected to do a self-test, exiting with
+ status code 0 if everything is okay, and with non-zero otherwise. A
+ core dump (exit code greater than 128) is noted specifically.</P>
+<P> Unlike other tests, there are no subdirectories required, or other
+ parameters to set.</P>
+<H2 NAME="umlplutotest"><A NAME="39_9">umlplutotest paramaters</A></H2>
+<P> The umlplutotest function starts a pair of user mode line processes.
+ This is a 2-host version of umlXhost. The &quot;EAST&quot; and &quot;WEST&quot; slots are
+ defined.</P>
+<H2 NAME="umlXhost"><A NAME="39_10">umlXhost parameters</A></H2>
+<P> The umlXtest function starts an arbitrary number of user mode line
+ processes.</P>
+
+<!-- <IMG SRC="single_netjig.png" ALT="block diagram of uml_netjig"> -->
+<P> The script invoked (<CODE>testing/utils/Xhost-test.tcl</CODE>) is a
+ TCL<A HREF="http://expect.nist.gov/"> expect</A> script that arranges
+ to start each UML and configure it appropriately for the test. It then
+ starts listening (using uml_netjig) to the simulated network answering
+ ARPs and inserting packets as appropriate.</P>
+<P> umlXtest has a series of slots, each of which should be filled by a
+ host. The list of slots is controlled by the variable, XHOST_LIST. This
+ variable should be set to a space seperated list of slots. The former
+ umlplutotest is now implemented as a variation of the umlXhost test,
+ with XHOST_LIST=&quot;EAST WEST&quot;.</P>
+<P> For each host slot that is defined, a series of variables should be
+ filled in, defining what configuration scripts to use for that host.</P>
+<P> The following are used to control the console input and output to
+ the system. Where the string ${host} is present, the host slot should
+ be filled in. I.e. for the two host system with XHOST_LIST=&quot;EAST WEST&quot;,
+ then the variables: EAST_INIT_SCRIPT and WEST_INIT_SCRIPT will exist.</P>
+<DL>
+<DT>${host}HOST</DT>
+<DD>The name of the UML host which will fill this slot</DD>
+<DT>${host}_INIT_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode prior to starting the tests. This file will usually
+ set up any eroute's and SADB entries that are required for the test.
+ Similar to INIT_SCRIPT, above.</P>
+</DD>
+<DT>${host}_RUN_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode, before the packets are sent. This set of commands is
+ run after all of the virtual machines are initialized. I.e. after
+ EAST_INIT_SCRIPT<B> AND</B> WEST_INIT_SCRIPT. This script can therefore
+ do things that require that all machines are properly configured.</P>
+</DD>
+<DT>${host}_RUN2_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode, after the packets are sent. This set of commands is
+ run before any of the virtual machines have been shut down. (I.e.
+ before EAST_FINAL_SCRIPT<B> AND</B> WEST_FINAL_SCRIPT.) This script can
+ therefore catch post-activity status reports.</P>
+</DD>
+<DT>${host}_FINAL_SCRIPT</DT>
+<DD>
+<P>a file of commands that is fed into the virtual machine's console in
+ single user mode after the final packet is sent. Similar to
+ INIT_SCRIPT, above. If not specified, then the single command &quot;halt&quot; is
+ sent. Note that when this script is run, the other virtual machines may
+ already have been killed. If specified, then the script should end with
+ a halt command to nicely shutdown the UML.</P>
+</DD>
+<DT>REF_${host}_CONSOLE_OUTPUT</DT>
+<DD>Similar to REF_CONSOLE_OUTPUT, above.</DD>
+</DL>
+<P>Some additional flags apply to all hosts:</P>
+<DL>
+<DT>REF_CONSOLE_FIXUPS</DT>
+<DD>a list of scripts (found in <CODE>klips/test/fixups</CODE>) to apply
+ to sanitize the console output of the machine under test. These are
+ typically perl, awk or sed scripts that remove things in the kernel
+ output that change each time the test is run and/or compiled.</DD>
+</DL>
+<P> In addition to input to the console, the networks may have input fed
+ to them:</P>
+<DL>
+<DT>EAST_INPUT/WEST_INPUT</DT>
+<DD>a<A HREF="http://www.tcpdump.org/"> pcap</A> file to feed in on the
+ private network side of each network. The &quot;EAST&quot; and &quot;WEST&quot; here refer
+ to the networks, not the hosts.</DD>
+<DT>REF_PUB_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+<DT>REF_EAST_FILTER/REF_WEST_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further
+ processing. Defaults to &quot;cat&quot;.</DD>
+&lt;
+<DT>TCPDUMPFLAGS</DT>
+<DD>a set of flags for the tcpdump used when converting captured output.
+ Typical values will include &quot;-n&quot; to turn off DNS, and often &quot;-E&quot; to set
+ the decryption key (tcpdump 3.7.1 and higher only) for ESP packets. The
+ &quot;-t&quot; flag (turn off timestamps) is provided automatically</DD>
+<DT>REF_EAST_OUTPUT/REF_WEST_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the private (eth0)
+ interface are captured and compared after conversion by tcpdump, as
+ with<VAR> REF_PUB_OUTPUT</VAR>.</DD>
+<P> There are two additional environment variables that may be set on
+ the command line:</P>
+<DL>
+<DT> NETJIGVERBOSE=verbose export NETJIGVERBOSE</DT>
+<DD> If set, then the test output will be &quot;chatty&quot;, and let you know
+ what commands it is running, and as packets are sent. Without it set,
+ the output is limited to success/failure messages.</DD>
+<DT> NETJIGTESTDEBUG=netjig export NETJIGTESTDEBUG</DT>
+<DD> This will enable debugging of the communication with uml_netjig,
+ and turn on debugging in this utility. This does not imply
+ NETJIGVERBOSE.</DD>
+</DL>
+<DT> HOSTTESTDEBUG=hosttest export HOSTTESTDEBUG</DT>
+<DD> This will show all interactions with the user-mode-linux consoles</DD>
+</DL>
+<H2 NAME="kernelpatch"><A NAME="39_11">kernel_patch_test paramaters</A></H2>
+<P> The kernel_patch_test function takes some kernel source, copies it
+ with lndir, and then applies the patch as produced by &quot;make
+ kernelpatch&quot;.</P>
+<P> The following are used to control the input and output to the
+ system:</P>
+<DL>
+<DT>KERNEL_NAME</DT>
+<DD>the kernel name, typically something like &quot;linus&quot; or &quot;rh&quot;</DD>
+<DT>KERNEL_VERSION</DT>
+<DD>the kernel version number, as in &quot;2.2&quot; or &quot;2.4&quot;.</DD>
+<DT>KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC</DT>
+<DD>This variable should set in the environment, probably in
+ ~/freeswan-regress-env.sh. Examples of this variables would be
+ KERNEL_LINUS2_0_SRC or KERNEL_RH7_3_SRC. This variable should point to
+ an extracted copy of the kernel source in question.</DD>
+<DT>REF_PATCH_OUTPUT</DT>
+<DD>a copy of the patch output to compare against</DD>
+<DT>KERNEL_PATCH_LEAVE_SOURCE</DT>
+<DD>If set to a non-empty string, then the patched kernel source is not
+ removed at the end of the test. This will typically be set in the
+ environment while debugging.</DD>
+</DL>
+<H2 NAME="modtest"><A NAME="39_12">module_compile paramaters</A></H2>
+<P> The module_compile test attempts to build the KLIPS module against a
+ given set of kernel source. This is also done by the RPM tests, but in
+ a very specific manner.</P>
+<P> There are two variations of this test - one where the kernel either
+ doesn't need to be configured, or is already done, and tests were there
+ is a local configuration file.</P>
+<P> Where the kernel doesn't need to be configured, the kernel source
+ that is found is simply used. It may be a RedHat-style kernel, where
+ one can cause it to configure itself via rhconfig.h-style definitions.
+ Or, it may just be a kernel tree that has been configured.</P>
+<P> If the variable KERNEL_CONFIG_FILE is set, then a new directory is
+ created for the kernel source. It is populated with lndir(1). The
+ referenced file is then copied in as .config, and &quot;make oldconfig&quot; is
+ used to configure the kernel. This resulting kernel is then used as the
+ reference source.</P>
+<P> In all cases, the kernel source is found the same was for the
+ kernelpatch test, i.e. via KERNEL_VERSION/KERNEL_NAME and
+ KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC.</P>
+<P> Once there is kernel source, the module is compiled using the
+ top-level &quot;make module&quot; target.</P>
+<P> The test is considered successful if an executable is found in
+ OUTPUT/module/ipsec.o at the end of the test.</P>
+<DL>
+<DT>KERNEL_NAME</DT>
+<DD>the kernel name, typically something like &quot;linus&quot; or &quot;rh&quot;</DD>
+<DT>KERNEL_VERSION</DT>
+<DD>the kernel version number, as in &quot;2.2&quot; or &quot;2.4&quot;.</DD>
+<DT>KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC</DT>
+<DD>This variable should set in the environment, probably in
+ ~/freeswan-regress-env.sh. Examples of this variables would be
+ KERNEL_LINUS2_0_SRC or KERNEL_RH7_3_SRC. This variable should point to
+ an extracted copy of the kernel source in question.</DD>
+<DT>KERNEL_CONFIG_FILE</DT>
+<DD>The configuration file for the kernel.</DD>
+<DT>KERNEL_PATCH_LEAVE_SOURCE</DT>
+<DD>If set to a non-empty string, then the configured kernel source is
+ not removed at the end of the test. This will typically be set in the
+ environment while debugging.</DD>
+<DT>MODULE_DEF_INCLUDE</DT>
+<DD>The include file that will be used to configure the KLIPS module,
+ and possibly the kernel source.</DD>
+</DL>
+<H1><A NAME="40">Current pitfalls</A></H1>
+<DL>
+<DT> &quot;tcpdump dissector&quot; not available.</DT>
+<DD> This is a non-fatal warning. If uml_netjig is invoked with the -t
+ option, then it will attempt to use tcpdump's dissector to decode each
+ packet that it processes. The dissector is presently not available, so
+ this option it normally turned off at compile time. The dissector
+ library will be released with tcpdump version 4.0.</DD>
+</DL>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="umltesting.html">Previous</A>
+<A HREF="nightly.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec.8.html b/doc/manpage.d/ipsec.8.html
new file mode 100644
index 000000000..ff9b7ca39
--- /dev/null
+++ b/doc/manpage.d/ipsec.8.html
@@ -0,0 +1,215 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC</TITLE>
+</HEAD><BODY>
+<H1>IPSEC</H1>
+Section: Maintenance Commands (8)<BR>Updated: 26 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec - invoke IPsec utilities
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+command [ argument ...]
+<P>
+<B>ipsec</B>
+
+<B>--help</B>
+
+<BR>
+
+<B>ipsec</B>
+
+<B>--version</B>
+
+<BR>
+
+<B>ipsec</B>
+
+<B>--versioncode</B>
+
+<BR>
+
+<B>ipsec</B>
+
+<B>--copyright</B>
+
+<BR>
+
+<B>ipsec</B>
+
+<B>--directory</B>
+
+<BR>
+
+<B>ipsec</B>
+
+<B>--confdir</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ipsec</I>
+
+invokes any of several utilities involved in controlling the IPsec
+encryption/authentication system,
+running the specified
+<I>command</I>
+
+with the specified
+<I>argument</I>s
+
+as if it had been invoked directly.
+This largely eliminates possible name collisions with other software,
+and also permits some centralized services.
+<P>
+
+In particular,
+<I>ipsec</I>
+
+supplies the invoked
+<I>command</I>
+
+with a suitable PATH environment variable,
+and also provides IPSEC_DIR,
+IPSEC_CONFS, and IPSEC_VERSION environment variables,
+containing respectively
+the full pathname of the directory where the IPsec utilities are stored,
+the full pathname of the directory where the configuration files live,
+and the IPsec version number.
+<P>
+
+<B>ipsec --help</B>
+
+lists the available commands.
+Most have their own manual pages, e.g.
+<I><A HREF="ipsec_auto.8.html">ipsec_auto</A></I>(8)
+
+for
+<I>auto</I>.
+
+<P>
+
+<B>ipsec --version</B>
+
+outputs version information about Linux FreeS/WAN.
+A version code of the form ``U<I>xxx</I>/K<I>yyy</I>''
+indicates that the user-level utilities are version <I>xxx</I>
+but the kernel portion appears to be version <I>yyy</I>
+(this form is used only if the two disagree).
+<P>
+
+<B>ipsec --versioncode</B>
+
+outputs <I>just</I> the version code,
+with none of
+<B>--version</B>'s
+
+supporting information,
+for use by scripts.
+<P>
+
+<B>ipsec --copyright</B>
+
+supplies boring copyright details.
+<P>
+
+<B>ipsec --directory</B>
+
+reports where
+<I>ipsec</I>
+
+thinks the IPsec utilities are stored.
+<P>
+
+<B>ipsec --confdir</B>
+
+reports where
+<I>ipsec</I>
+
+thinks the IPsec configuration files are stored.
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+/usr/local/lib/ipsec<TT>&nbsp;&nbsp;&nbsp;</TT>usual utilities directory<BR>
+<A NAME="lbAF">&nbsp;</A>
+<H2>ENVIRONMENT</H2>
+
+<P>
+
+The following environment variables control where FreeS/WAN finds its
+components.
+The
+<B>ipsec</B>
+
+command sets them if they are not already set.
+<PRE>
+IPSEC_EXECDIR directory containing published commands
+IPSEC_LIBDIR directory containing internal executables
+IPSEC_SBINDIR directory containing <B>ipsec</B> command
+IPSEC_CONFS directory containing configuration files
+</PRE>
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+
+
+<A HREF="ipsec.conf.5.html">ipsec.conf</A>(5), <A HREF="ipsec.secrets.5.html">ipsec.secrets</A>(5),
+<A HREF="ipsec_auto.8.html">ipsec_auto</A>(8),
+<A HREF="ipsec_barf.8.html">ipsec_barf</A>(8),
+<A HREF="ipsec_setup.8.html">ipsec_setup</A>(8),
+<A HREF="ipsec_showdefaults.8.html">ipsec_showdefaults</A>(8),
+<A HREF="ipsec_showhostkey.8.html">ipsec_showhostkey</A>(8)
+
+
+<P>
+
+HTML documentation shipped with the release, starting with
+<I>doc/index.html</I>.
+
+<I>&lt;<A HREF="http://www.freeswan.org/doc.html">http://www.freeswan.org/doc.html</A>&gt;</I>
+
+may also be of use.
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for Linux FreeS/WAN
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<A NAME="lbAI">&nbsp;</A>
+<H2>BUGS</H2>
+
+The provision of centralized services,
+while convenient,
+does compromise the original concept of making the utilities
+invocable directly as well as via
+<I>ipsec</I>.
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">ENVIRONMENT</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+<DT><A HREF="#lbAI">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec.conf.5.html b/doc/manpage.d/ipsec.conf.5.html
new file mode 100644
index 000000000..36e0452ef
--- /dev/null
+++ b/doc/manpage.d/ipsec.conf.5.html
@@ -0,0 +1,1830 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC.CONF</TITLE>
+</HEAD><BODY>
+<H1>IPSEC.CONF</H1>
+Section: File Formats (5)<BR>Updated: 26 Nov 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec.conf - IPsec configuration and connections
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The optional
+<I>ipsec.conf</I>
+
+file
+specifies most configuration and control information for the
+FreeS/WAN IPsec subsystem.
+(The major exception is secrets for authentication;
+see
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5).)
+
+Its contents are not security-sensitive
+<I>unless</I>
+
+manual keying is being done for more than just testing,
+in which case the encryption/authentication keys in the
+descriptions for the manually-keyed connections are very sensitive
+(and those connection descriptions
+are probably best kept in a separate file,
+via the include facility described below).
+<P>
+
+The file is a text file, consisting of one or more
+<I>sections</I>.
+
+White space followed by
+<B>#</B>
+
+followed by anything to the end of the line
+is a comment and is ignored,
+as are empty lines which are not within a section.
+<P>
+
+A line which contains
+<B>include</B>
+
+and a file name, separated by white space,
+is replaced by the contents of that file,
+preceded and followed by empty lines.
+If the file name is not a full pathname,
+it is considered to be relative to the directory containing the
+including file.
+Such inclusions can be nested.
+Only a single filename may be supplied, and it may not contain white space,
+but it may include shell wildcards (see
+<I><A HREF="sh.1.html">sh</A></I>(1));
+
+for example:
+<P>
+
+<B>include</B>
+
+<B>ipsec.*.conf</B>
+
+<P>
+
+The intention of the include facility is mostly to permit keeping
+information on connections, or sets of connections,
+separate from the main configuration file.
+This permits such connection descriptions to be changed,
+copied to the other security gateways involved, etc.,
+without having to constantly extract them from the configuration
+file and then insert them back into it.
+Note also the
+<B>also</B>
+
+and
+<B>alsoflip</B>
+
+parameters (described below) which permit splitting a single logical section
+(e.g. a connection description) into several actual sections.
+<P>
+
+The first significant line of the file must specify the version
+of this specification that it conforms to:
+<P>
+
+<B>version 2</B>
+<P>
+
+A section
+begins with a line of the form:
+<P>
+
+<I>type</I>
+
+<I>name</I>
+
+<P>
+
+where
+<I>type</I>
+
+indicates what type of section follows, and
+<I>name</I>
+
+is an arbitrary name which distinguishes the section from others
+of the same type.
+(Names must start with a letter and may contain only
+letters, digits, periods, underscores, and hyphens.)
+All subsequent non-empty lines
+which begin with white space are part of the section;
+comments within a section must begin with white space too.
+There may be only one section of a given type with a given name.
+<P>
+
+Lines within the section are generally of the form
+<P>
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I>parameter</I><B>=</B><I>value</I>
+<P>
+
+(note the mandatory preceding white space).
+There can be white space on either side of the
+<B>=</B>.
+
+Parameter names follow the same syntax as section names,
+and are specific to a section type.
+Unless otherwise explicitly specified,
+no parameter name may appear more than once in a section.
+<P>
+
+An empty
+<I>value</I>
+
+stands for the system default value (if any) of the parameter,
+i.e. it is roughly equivalent to omitting the parameter line entirely.
+A
+<I>value</I>
+
+may contain white space only if the entire
+<I>value</I>
+
+is enclosed in double quotes (<B>&quot;</B>);
+a
+<I>value</I>
+
+cannot itself contain a double quote,
+nor may it be continued across more than one line.
+<P>
+
+Numeric values are specified to be either an ``integer''
+(a sequence of digits) or a ``decimal number''
+(sequence of digits optionally followed by `.' and another sequence of digits).
+<P>
+
+There is currently one parameter which is available in any type of
+section:
+<DL COMPACT>
+<DT><B>also</B>
+
+<DD>
+the value is a section name;
+the parameters of that section are appended to this section,
+as if they had been written as part of it.
+The specified section must exist, must follow the current one,
+and must have the same section type.
+(Nesting is permitted,
+and there may be more than one
+<B>also</B>
+
+in a single section,
+although it is forbidden to append the same section more than once.)
+This allows, for example, keeping the encryption keys
+for a connection in a separate file
+from the rest of the description, by using both an
+<B>also</B>
+
+parameter and an
+<B>include</B>
+
+line.
+(Caution, see BUGS below for some restrictions.)
+<DT><B>alsoflip</B>
+
+<DD>
+can be used in a
+<B>conn</B>
+
+section.
+It acts like an
+<B>also</B>
+
+that flips the referenced section's entries left-for-right.
+</DL>
+<P>
+
+Parameter names beginning with
+<B>x-</B>
+
+(or
+<B>X-</B>,
+
+or
+<B>x_</B>,
+
+or
+<B>X_</B>)
+
+are reserved for user extensions and will never be assigned meanings
+by IPsec.
+Parameters with such names must still observe the syntax rules
+(limits on characters used in the name;
+no white space in a non-quoted value;
+no newlines or double quotes within the value).
+All other as-yet-unused parameter names are reserved for future IPsec
+improvements.
+<P>
+
+A section with name
+<B>%default</B>
+
+specifies defaults for sections of the same type.
+For each parameter in it,
+any section of that type which does not have a parameter of the same name
+gets a copy of the one from the
+<B>%default</B>
+
+section.
+There may be multiple
+<B>%default</B>
+
+sections of a given type,
+but only one default may be supplied for any specific parameter name,
+and all
+<B>%default</B>
+
+sections of a given type must precede all non-<B>%default</B>
+
+sections of that type.
+<B>%default</B>
+
+sections may not contain
+<B>also</B>
+
+or
+<B>alsoflip</B>
+
+parameters.
+<P>
+
+Currently there are two types of section:
+a
+<B>config</B>
+
+section specifies general configuration information for IPsec,
+while a
+<B>conn</B>
+
+section specifies an IPsec connection.
+<A NAME="lbAD">&nbsp;</A>
+<H2>CONN SECTIONS</H2>
+
+A
+<B>conn</B>
+
+section contains a
+<I>connection specification</I>,
+
+defining a network connection to be made using IPsec.
+The name given is arbitrary, and is used to identify the connection to
+<I><A HREF="ipsec_auto.8.html">ipsec_auto</A></I>(8)
+
+and
+<I><A HREF="ipsec_manual.8.html">ipsec_manual</A></I>(8).
+
+Here's a simple example:
+<P>
+
+
+<PRE>
+<B>
+conn snt
+ left=10.11.11.1
+ leftsubnet=10.0.1.0/24
+ leftnexthop=172.16.55.66
+ right=192.168.22.1
+ rightsubnet=10.0.2.0/24
+ rightnexthop=172.16.88.99
+ keyingtries=%forever
+</B></PRE>
+
+<P>
+
+A note on terminology...
+In automatic keying, there are two kinds of communications going on:
+transmission of user IP packets, and gateway-to-gateway negotiations for
+keying, rekeying, and general control.
+The data path (a set of ``IPsec SAs'') used for user packets is herein
+referred to as the ``connection'';
+the path used for negotiations (built with ``ISAKMP SAs'') is referred to as
+the ``keying channel''.
+<P>
+
+To avoid trivial editing of the configuration file to suit it to each system
+involved in a connection,
+connection specifications are written in terms of
+<I>left</I>
+
+and
+<I>right</I>
+
+participants,
+rather than in terms of local and remote.
+Which participant is considered
+<I>left</I>
+
+or
+<I>right</I>
+
+is arbitrary;
+IPsec figures out which one it is being run on based on internal information.
+This permits using identical connection specifications on both ends.
+There are cases where there is no symmetry; a good convention is to
+use
+<I>left</I>
+
+for the local side and
+<I>right</I>
+
+for the remote side (the first letters are a good mnemonic).
+<P>
+
+Many of the parameters relate to one participant or the other;
+only the ones for
+<I>left</I>
+
+are listed here, but every parameter whose name begins with
+<B>left</B>
+
+has a
+<B>right</B>
+
+counterpart,
+whose description is the same but with
+<B>left</B>
+
+and
+<B>right</B>
+
+reversed.
+<P>
+
+Parameters are optional unless marked ``(required)'';
+a parameter required for manual keying need not be included for
+a connection which will use only automatic keying, and vice versa.
+<A NAME="lbAE">&nbsp;</A>
+<H3>CONN PARAMETERS: GENERAL</H3>
+
+The following parameters are relevant to both automatic and manual keying.
+Unless otherwise noted,
+for a connection to work,
+in general it is necessary for the two ends to agree exactly
+on the values of these parameters.
+<DL COMPACT>
+<DT><B>type</B>
+
+<DD>
+the type of the connection; currently the accepted values
+are
+<B>tunnel</B>
+
+(the default)
+signifying a host-to-host, host-to-subnet, or subnet-to-subnet tunnel;
+<B>transport</B>,
+
+signifying host-to-host transport mode;
+<B>passthrough</B>,
+
+signifying that no IPsec processing should be done at all;
+<B>drop</B>,
+
+signifying that packets should be discarded; and
+<B>reject</B>,
+
+signifying that packets should be discarded and a diagnostic ICMP returned.
+<DT><B>left</B>
+
+<DD>
+(required)
+the IP address of the left participant's public-network interface,
+in any form accepted by
+<I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3)
+
+or one of several magic values.
+If it is
+<B>%defaultroute</B>,
+
+and
+the
+<B>config</B>
+
+<B>setup</B>
+
+section's,
+<B>interfaces</B>
+
+specification contains
+<B>%defaultroute,</B>
+
+<B>left</B>
+
+will be filled in automatically with the local address
+of the default-route interface (as determined at IPsec startup time);
+this also overrides any value supplied for
+<B>leftnexthop</B>.
+
+(Either
+<B>left</B>
+
+or
+<B>right</B>
+
+may be
+<B>%defaultroute</B>,
+
+but not both.)
+The value
+<B>%any</B>
+
+signifies an address to be filled in (by automatic keying) during
+negotiation.
+The value
+<B>%opportunistic</B>
+
+signifies that both
+<B>left</B>
+
+and
+<B>leftnexthop</B>
+
+are to be filled in (by automatic keying) from DNS data for
+<B>left</B>'s
+
+client.
+The values
+<B>%group</B>
+
+and
+<B>%opportunisticgroup</B>
+
+makes this a policy group conn: one that will be instantiated
+into a regular or opportunistic conn for each CIDR block listed in the
+policy group file with the same name as the conn.
+<DT><B>leftsubnet</B>
+
+<DD>
+private subnet behind the left participant, expressed as
+<I>network</I><B>/</B><I>netmask</I>
+(actually, any form acceptable to
+<I><A HREF="ipsec_ttosubnet.3.html">ipsec_ttosubnet</A></I>(3));
+
+if omitted, essentially assumed to be <I>left</I><B>/32</B>,
+signifying that the left end of the connection goes to the left participant only
+<DT><B>leftnexthop</B>
+
+<DD>
+next-hop gateway IP address for the left participant's connection
+to the public network;
+defaults to
+<B>%direct</B>
+
+(meaning
+<I>right</I>).
+
+If the value is to be overridden by the
+<B>left=%defaultroute</B>
+
+method (see above),
+an explicit value must
+<I>not</I>
+
+be given.
+If that method is not being used,
+but
+<B>leftnexthop</B>
+
+is
+<B>%defaultroute</B>,
+
+and
+<B>interfaces=%defaultroute</B>
+
+is used in the
+<B>config</B>
+
+<B>setup</B>
+
+section,
+the next-hop gateway address of the default-route interface
+will be used.
+The magic value
+<B>%direct</B>
+
+signifies a value to be filled in (by automatic keying)
+with the peer's address.
+Relevant only locally, other end need not agree on it.
+<DT><B>leftupdown</B>
+
+<DD>
+what ``updown'' script to run to adjust routing and/or firewalling
+when the status of the connection
+changes (default
+<B>ipsec _updown</B>).
+
+May include positional parameters separated by white space
+(although this requires enclosing the whole string in quotes);
+including shell metacharacters is unwise.
+See
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8)
+
+for details.
+Relevant only locally, other end need not agree on it.
+<DT><B>leftfirewall</B>
+
+<DD>
+whether the left participant is doing forwarding-firewalling
+(including masquerading) for traffic from <I>leftsubnet</I>,
+which should be turned off (for traffic to the other subnet)
+once the connection is established;
+acceptable values are
+<B>yes</B>
+
+and (the default)
+<B>no</B>.
+
+May not be used in the same connection description with
+<B>leftupdown</B>.
+
+Implemented as a parameter to the default
+<I>updown</I>
+
+script.
+See notes below.
+Relevant only locally, other end need not agree on it.
+</DL>
+<P>
+
+If one or both security gateways are doing forwarding firewalling
+(possibly including masquerading),
+and this is specified using the firewall parameters,
+tunnels established with IPsec are exempted from it
+so that packets can flow unchanged through the tunnels.
+(This means that all subnets connected in this manner must have
+distinct, non-overlapping subnet address blocks.)
+This is done by the default
+<I>updown</I>
+
+script (see
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8)).
+
+<P>
+
+The implementation of this makes certain assumptions about firewall setup,
+notably the use of the old
+<I>ipfwadm</I>
+
+interface to the firewall.
+In situations calling for more control,
+it may be preferable for the user to supply his own
+<I>updown</I>
+
+script,
+which makes the appropriate adjustments for his system.
+<A NAME="lbAF">&nbsp;</A>
+<H3>CONN PARAMETERS: AUTOMATIC KEYING</H3>
+
+The following parameters are relevant only to automatic keying,
+and are ignored in manual keying.
+Unless otherwise noted,
+for a connection to work,
+in general it is necessary for the two ends to agree exactly
+on the values of these parameters.
+<DL COMPACT>
+<DT><B>keyexchange</B>
+
+<DD>
+method of key exchange;
+the default and currently the only accepted value is
+<B>ike</B>
+
+<DT><B>auto</B>
+
+<DD>
+what operation, if any, should be done automatically at IPsec startup;
+currently-accepted values are
+<B>add</B>
+
+(signifying an
+<B>ipsec auto</B>
+
+<B>--add</B>),
+
+<B>route</B>
+
+(signifying that plus an
+<B>ipsec auto</B>
+
+<B>--route</B>),
+
+<B>start</B>
+
+(signifying that plus an
+<B>ipsec auto</B>
+
+<B>--up</B>),
+
+<B>manual</B>
+
+(signifying an
+<B>ipsec</B>
+
+<B>manual</B>
+
+<B>--up</B>),
+
+and
+<B>ignore</B>
+
+(also the default) (signifying no automatic startup operation).
+See the
+<B>config</B>
+
+<B>setup</B>
+
+discussion below.
+Relevant only locally, other end need not agree on it
+(but in general, for an intended-to-be-permanent connection,
+both ends should use
+<B>auto=start</B>
+
+to ensure that any reboot causes immediate renegotiation).
+<DT><B>auth</B>
+
+<DD>
+whether authentication should be done as part of
+ESP encryption, or separately using the AH protocol;
+acceptable values are
+<B>esp</B>
+
+(the default) and
+<B>ah</B>.
+
+<DT><B>authby</B>
+
+<DD>
+how the two security gateways should authenticate each other;
+acceptable values are
+<B>secret</B>
+
+for shared secrets,
+<B>rsasig</B>
+
+for RSA digital signatures (the default),
+<B>secret|rsasig</B>
+
+for either, and
+<B>never</B>
+
+if negotiation is never to be attempted or accepted (useful for shunt-only conns).
+Digital signatures are superior in every way to shared secrets.
+<DT><B>leftid</B>
+
+<DD>
+how
+the left participant
+should be identified for authentication;
+defaults to
+<B>left</B>.
+
+Can be an IP address (in any
+<I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3)
+
+syntax)
+or a fully-qualified domain name preceded by
+<B>@</B>
+
+(which is used as a literal string and not resolved).
+The magic value
+<B>%myid</B>
+
+stands for the current setting of <I>myid</I>.
+This is set in <B>config setup</B> or by <I><A HREF="ipsec_whack.8.html">ipsec_whack</A></I>(8)), or, if not set,
+it is the IP address in <B>%defaultroute</B> (if that is supported by a TXT record in its reverse domain), or otherwise
+it is the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined.
+<DT><B>leftrsasigkey</B>
+
+<DD>
+the left participant's
+public key for RSA signature authentication,
+in RFC 2537 format using
+<I><A HREF="ipsec_ttodata.3.html">ipsec_ttodata</A></I>(3)
+
+encoding.
+The magic value
+<B>%none</B>
+
+means the same as not specifying a value (useful to override a default).
+The value
+<B>%dnsondemand</B>
+
+(the default)
+means the key is to be fetched from DNS at the time it is needed.
+The value
+<B>%dnsonload</B>
+
+means the key is to be fetched from DNS at the time
+the connection description is read from
+<I>ipsec.conf</I>;
+
+currently this will be treated as
+<B>%none</B>
+
+if
+<B>right=%any</B>
+
+or
+<B>right=%opportunistic</B>.
+
+The value
+<B>%dns</B>
+
+is currently treated as
+<B>%dnsonload</B>
+
+but will change to
+<B>%dnsondemand</B>
+
+in the future.
+The identity used for the left participant
+must be a specific host, not
+<B>%any</B>
+
+or another magic value.
+<B>Caution:</B>
+
+if two connection descriptions
+specify different public keys for the same
+<B>leftid</B>,
+
+confusion and madness will ensue.
+<DT><B>leftrsasigkey2</B>
+
+<DD>
+if present, a second public key.
+Either key can authenticate the signature, allowing for key rollover.
+<DT><B>pfs</B>
+
+<DD>
+whether Perfect Forward Secrecy of keys is desired on the connection's
+keying channel
+(with PFS, penetration of the key-exchange protocol
+does not compromise keys negotiated earlier);
+acceptable values are
+<B>yes</B>
+
+(the default)
+and
+<B>no</B>.
+
+<DT><B>keylife</B>
+
+<DD>
+how long a particular instance of a connection
+(a set of encryption/authentication keys for user packets) should last,
+from successful negotiation to expiry;
+acceptable values are an integer optionally followed by
+<B>s</B>
+
+(a time in seconds)
+or a decimal number followed by
+<B>m</B>,
+
+<B>h</B>,
+
+or
+<B>d</B>
+
+(a time
+in minutes, hours, or days respectively)
+(default
+<B>8.0h</B>,
+
+maximum
+<B>24h</B>).
+
+Normally, the connection is renegotiated (via the keying channel)
+before it expires.
+The two ends need not exactly agree on
+<B>keylife</B>,
+
+although if they do not,
+there will be some clutter of superseded connections on the end
+which thinks the lifetime is longer.
+<DT><B>rekey</B>
+
+<DD>
+whether a connection should be renegotiated when it is about to expire;
+acceptable values are
+<B>yes</B>
+
+(the default)
+and
+<B>no</B>.
+
+The two ends need not agree,
+but while a value of
+<B>no</B>
+
+prevents Pluto from requesting renegotiation,
+it does not prevent responding to renegotiation requested from the other end,
+so
+<B>no</B>
+
+will be largely ineffective unless both ends agree on it.
+<DT><B>rekeymargin</B>
+
+<DD>
+how long before connection expiry or keying-channel expiry
+should attempts to
+negotiate a replacement
+begin; acceptable values as for
+<B>keylife</B>
+
+(default
+<B>9m</B>).
+
+Relevant only locally, other end need not agree on it.
+<DT><B>rekeyfuzz</B>
+
+<DD>
+maximum percentage by which
+<B>rekeymargin</B>
+
+should be randomly increased to randomize rekeying intervals
+(important for hosts with many connections);
+acceptable values are an integer,
+which may exceed 100,
+followed by a `%'
+(default set by
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8),
+
+currently
+<B>100%</B>).
+
+The value of
+<B>rekeymargin</B>,
+
+after this random increase,
+must not exceed
+<B>keylife</B>.
+
+The value
+<B>0%</B>
+
+will suppress time randomization.
+Relevant only locally, other end need not agree on it.
+<DT><B>keyingtries</B>
+
+<DD>
+how many attempts (a whole number or <B>%forever</B>) should be made to
+negotiate a connection, or a replacement for one, before giving up
+(default
+<B>%forever</B>).
+
+The value <B>%forever</B>
+means ``never give up'' (obsolete: this can be written <B>0</B>).
+Relevant only locally, other end need not agree on it.
+<DT><B>ikelifetime</B>
+
+<DD>
+how long the keying channel of a connection (buzzphrase: ``ISAKMP SA'')
+should last before being renegotiated;
+acceptable values as for
+<B>keylife</B>
+
+(default set by
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8),
+
+currently
+<B>1h</B>,
+
+maximum
+<B>8h</B>).
+
+The two-ends-disagree case is similar to that of
+<B>keylife</B>.
+
+<DT><B>compress</B>
+
+<DD>
+whether IPComp compression of content is proposed on the connection
+(link-level compression does not work on encrypted data,
+so to be effective, compression must be done <I>before</I> encryption);
+acceptable values are
+<B>yes</B>
+
+and
+<B>no</B>
+
+(the default).
+The two ends need not agree.
+A value of
+<B>yes</B>
+
+causes IPsec to propose both compressed and uncompressed,
+and prefer compressed.
+A value of
+<B>no</B>
+
+prevents IPsec from proposing compression;
+a proposal to compress will still be accepted.
+<DT><B>disablearrivalcheck</B>
+
+<DD>
+whether KLIPS's normal tunnel-exit check
+(that a packet emerging from a tunnel has plausible addresses in its header)
+should be disabled;
+acceptable values are
+<B>yes</B>
+
+and
+<B>no</B>
+
+(the default).
+Tunnel-exit checks improve security and do not break any normal configuration.
+Relevant only locally, other end need not agree on it.
+<DT><B>failureshunt</B>
+
+<DD>
+what to do with packets when negotiation fails.
+The default is
+<B>none</B>:
+
+no shunt;
+<B>passthrough</B>,
+
+<B>drop</B>,
+
+and
+<B>reject</B>
+
+have the obvious meanings.
+</DL>
+<A NAME="lbAG">&nbsp;</A>
+<H3>CONN PARAMETERS: MANUAL KEYING</H3>
+
+The following parameters are relevant only to manual keying,
+and are ignored in automatic keying.
+Unless otherwise noted,
+for a connection to work,
+in general it is necessary for the two ends to agree exactly
+on the values of these parameters.
+A manually-keyed
+connection must specify at least one of AH or ESP.
+<DL COMPACT>
+<DT><B>spi</B>
+
+<DD>
+(this or
+<B>spibase</B>
+
+required for manual keying)
+the SPI number to be used for the connection (see
+<I><A HREF="ipsec_manual.8.html">ipsec_manual</A></I>(8));
+
+must be of the form <B>0x</B><I>hex</I><B></B>,
+where
+<I>hex</I>
+
+is one or more hexadecimal digits
+(note, it will generally be necessary to make
+<I>spi</I>
+
+at least
+<B>0x100</B>
+
+to be acceptable to KLIPS,
+and use of SPIs in the range
+<B>0x100</B>-<B>0xfff</B>
+
+is recommended)
+<DT><B>spibase</B>
+
+<DD>
+(this or
+<B>spi</B>
+
+required for manual keying)
+the base number for the SPIs to be used for the connection (see
+<I><A HREF="ipsec_manual.8.html">ipsec_manual</A></I>(8));
+
+must be of the form <B>0x</B><I>hex</I><B>0</B>,
+where
+<I>hex</I>
+
+is one or more hexadecimal digits
+(note, it will generally be necessary to make
+<I>spibase</I>
+
+at least
+<B>0x100</B>
+
+for the resulting SPIs
+to be acceptable to KLIPS,
+and use of numbers in the range
+<B>0x100</B>-<B>0xff0</B>
+
+is recommended)
+<DT><B>esp</B>
+
+<DD>
+ESP encryption/authentication algorithm to be used
+for the connection, e.g.
+<B>3des-md5-96</B>
+
+(must be suitable as a value of
+<I><A HREF="ipsec_spi.8.html">ipsec_spi</A></I>(8)'s
+
+<B>--esp</B>
+
+option);
+default is not to use ESP
+<DT><B>espenckey</B>
+
+<DD>
+ESP encryption key
+(must be suitable as a value of
+<I><A HREF="ipsec_spi.8.html">ipsec_spi</A></I>(8)'s
+
+<B>--enckey</B>
+
+option)
+(may be specified separately for each direction using
+<B>leftespenckey</B>
+
+(leftward SA)
+and
+<B>rightespenckey</B>
+
+parameters)
+<DT><B>espauthkey</B>
+
+<DD>
+ESP authentication key
+(must be suitable as a value of
+<I><A HREF="ipsec_spi.8.html">ipsec_spi</A></I>(8)'s
+
+<B>--authkey</B>
+
+option)
+(may be specified separately for each direction using
+<B>leftespauthkey</B>
+
+(leftward SA)
+and
+<B>rightespauthkey</B>
+
+parameters)
+<DT><B>espreplay_window</B>
+
+<DD>
+ESP replay-window setting,
+an integer from
+<B>0</B>
+
+(the
+<I>ipsec_manual</I>
+
+default, which turns off replay protection) to
+<B>64</B>;
+
+relevant only if ESP authentication is being used
+<DT><B>leftespspi</B>
+
+<DD>
+SPI to be used for the leftward ESP SA, overriding
+automatic assignment using
+<B>spi</B>
+
+or
+<B>spibase</B>;
+
+typically a hexadecimal number beginning with
+<B>0x</B>
+
+<DT><B>ah</B>
+
+<DD>
+AH authentication algorithm to be used
+for the connection, e.g.
+<B>hmac-md5-96</B>
+
+(must be suitable as a value of
+<I><A HREF="ipsec_spi.8.html">ipsec_spi</A></I>(8)'s
+
+<B>--ah</B>
+
+option);
+default is not to use AH
+<DT><B>ahkey</B>
+
+<DD>
+(required if
+<B>ah</B>
+
+is present) AH authentication key
+(must be suitable as a value of
+<I><A HREF="ipsec_spi.8.html">ipsec_spi</A></I>(8)'s
+
+<B>--authkey</B>
+
+option)
+(may be specified separately for each direction using
+<B>leftahkey</B>
+
+(leftward SA)
+and
+<B>rightahkey</B>
+
+parameters)
+<DT><B>ahreplay_window</B>
+
+<DD>
+AH replay-window setting,
+an integer from
+<B>0</B>
+
+(the
+<I>ipsec_manual</I>
+
+default, which turns off replay protection) to
+<B>64</B>
+
+<DT><B>leftahspi</B>
+
+<DD>
+SPI to be used for the leftward AH SA, overriding
+automatic assignment using
+<B>spi</B>
+
+or
+<B>spibase</B>;
+
+typically a hexadecimal number beginning with
+<B>0x</B>
+
+</DL>
+<A NAME="lbAH">&nbsp;</A>
+<H2>CONFIG SECTIONS</H2>
+
+At present, the only
+<B>config</B>
+
+section known to the IPsec software is the one named
+<B>setup</B>,
+
+which contains information used when the software is being started
+(see
+<I><A HREF="ipsec_setup.8.html">ipsec_setup</A></I>(8)).
+
+Here's an example:
+<P>
+
+
+<PRE>
+<B>
+config setup
+ interfaces=&quot;ipsec0=eth1 ipsec1=ppp0&quot;
+ klipsdebug=none
+ plutodebug=all
+ manualstart=
+</B></PRE>
+
+<P>
+
+Parameters are optional unless marked ``(required)''.
+The currently-accepted
+<I>parameter</I>
+
+names in a
+<B>config</B>
+
+<B>setup</B>
+
+section are:
+<DL COMPACT>
+<DT><B>myid</B>
+
+<DD>
+the identity to be used for
+<B>%myid</B>.
+
+<B>%myid</B>
+
+is used in the implicit policy group conns and can be used as
+an identity in explicit conns.
+If unspecified,
+<B>%myid</B>
+
+is set to the IP address in <B>%defaultroute</B> (if that is supported by a TXT record in its reverse domain), or otherwise
+the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined.
+An explicit value generally starts with ``<B>@</B>''.
+<DT><B>interfaces</B>
+
+<DD>
+virtual and physical interfaces for IPsec to use:
+a single
+<I>virtual</I><B>=</B><I>physical</I> pair, a (quoted!) list of pairs separated
+by white space, or
+<B>%none</B>.
+
+One of the pairs may be written as
+<B>%defaultroute</B>,
+
+which means: find the interface <I>d</I> that the default route points to,
+and then act as if the value was ``<B>ipsec0=</B><I>d</I>''.
+<B>%defaultroute</B>
+
+is the default;
+<B>%none</B>
+
+must be used to denote no interfaces.
+If
+<B>%defaultroute</B>
+
+is used (implicitly or explicitly)
+information about the default route and its interface is noted for
+use by
+<I><A HREF="ipsec_manual.8.html">ipsec_manual</A></I>(8)
+
+and
+<I><A HREF="ipsec_auto.8.html">ipsec_auto</A></I>(8).)
+
+<DT><B>forwardcontrol</B>
+
+<DD>
+whether
+<I>setup</I>
+
+should turn IP forwarding on
+(if it's not already on) as IPsec is started,
+and turn it off again (if it was off) as IPsec is stopped;
+acceptable values are
+<B>yes</B>
+
+and (the default)
+<B>no</B>.
+
+For this to have full effect, forwarding must be
+disabled before the hardware interfaces are brought
+up (e.g.,
+<B>net.ipv4.ip_forward&nbsp;=&nbsp;0</B>
+
+in Red Hat 6.x
+<I>/etc/sysctl.conf</I>),
+
+because IPsec doesn't get control early enough to do that.
+<DT><B>rp_filter</B>
+
+<DD>
+whether and how
+<I>setup</I>
+
+should adjust the reverse path filtering mechanism for the
+physical devices to be used.
+Values are <B>%unchanged</B> (to leave it alone)
+or <B>0</B>, <B>1</B>, <B>2</B> (values to set it to).
+<I>/proc/sys/net/ipv4/conf/PHYS/rp_filter</I>
+is badly documented; it must be <B>0</B> in many cases
+for ipsec to function.
+The default value for the parameter is <B>0</B>.
+<DT><B>syslog</B>
+
+<DD>
+the
+<I><A HREF="syslog.2.html">syslog</A></I>(2)
+
+``facility'' name and priority to use for
+startup/shutdown log messages,
+default
+<B>daemon.error</B>.
+
+<DT><B>klipsdebug</B>
+
+<DD>
+how much KLIPS debugging output should be logged.
+An empty value,
+or the magic value
+<B>none</B>,
+
+means no debugging output (the default).
+The magic value
+<B>all</B>
+
+means full output.
+Otherwise only the specified types of output
+(a quoted list, names separated by white space) are enabled;
+for details on available debugging types, see
+<I><A HREF="ipsec_klipsdebug.8.html">ipsec_klipsdebug</A></I>(8).
+
+<DT><B>plutodebug</B>
+
+<DD>
+how much Pluto debugging output should be logged.
+An empty value,
+or the magic value
+<B>none</B>,
+
+means no debugging output (the default).
+The magic value
+<B>all</B>
+
+means full output.
+Otherwise only the specified types of output
+(a quoted list, names without the
+<B>--debug-</B>
+
+prefix,
+separated by white space) are enabled;
+for details on available debugging types, see
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8).
+
+<DT><B>plutoopts</B>
+
+<DD>
+additional options to pass to pluto upon startup. See
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8).
+
+<DT><B>plutostderrlog</B>
+
+<DD>
+do not use syslog, but rather log to stderr, and direct stderr to the
+argument file.
+<DT><B>dumpdir</B>
+
+<DD>
+in what directory should things started by
+<I>setup</I>
+
+(notably the Pluto daemon) be allowed to
+dump core?
+The empty value (the default) means they are not
+allowed to.
+<DT><B>manualstart</B>
+
+<DD>
+which manually-keyed connections to set up at startup
+(empty, a name, or a quoted list of names separated by white space);
+see
+<I><A HREF="ipsec_manual.8.html">ipsec_manual</A></I>(8).
+
+Default is none.
+<DT><B>pluto</B>
+
+<DD>
+whether to start Pluto or not;
+Values are
+<B>yes</B>
+
+(the default)
+or
+<B>no</B>
+
+(useful only in special circumstances).
+<DT><B>plutowait</B>
+
+<DD>
+should Pluto wait for each
+negotiation attempt that is part of startup to
+finish before proceeding with the next?
+Values are
+<B>yes</B>
+
+or
+<B>no</B>
+
+(the default).
+<DT><B>prepluto</B>
+
+<DD>
+shell command to run before starting Pluto
+(e.g., to decrypt an encrypted copy of the
+<I>ipsec.secrets</I>
+
+file).
+It's run in a very simple way;
+complexities like I/O redirection are best hidden within a script.
+Any output is redirected for logging,
+so running interactive commands is difficult unless they use
+<I>/dev/tty</I>
+
+or equivalent for their interaction.
+Default is none.
+<DT><B>postpluto</B>
+
+<DD>
+shell command to run after starting Pluto
+(e.g., to remove a decrypted copy of the
+<I>ipsec.secrets</I>
+
+file).
+It's run in a very simple way;
+complexities like I/O redirection are best hidden within a script.
+Any output is redirected for logging,
+so running interactive commands is difficult unless they use
+<I>/dev/tty</I>
+
+or equivalent for their interaction.
+Default is none.
+<DT><B>fragicmp</B>
+
+<DD>
+whether a tunnel's need to fragment a packet should be reported
+back with an ICMP message,
+in an attempt to make the sender lower his PMTU estimate;
+acceptable values are
+<B>yes</B>
+
+(the default)
+and
+<B>no</B>.
+
+<DT><B>hidetos</B>
+
+<DD>
+whether a tunnel packet's TOS field should be set to
+<B>0</B>
+
+rather than copied from the user packet inside;
+acceptable values are
+<B>yes</B>
+
+(the default)
+and
+<B>no</B>.
+
+<DT><B>uniqueids</B>
+
+<DD>
+whether a particular participant ID should be kept unique,
+with any new (automatically keyed)
+connection using an ID from a different IP address
+deemed to replace all old ones using that ID;
+acceptable values are
+<B>yes</B>
+
+(the default)
+and
+<B>no</B>.
+
+Participant IDs normally <I>are</I> unique,
+so a new (automatically-keyed) connection using the same ID is
+almost invariably intended to replace an old one.
+<DT><B>overridemtu</B>
+
+<DD>
+value that the MTU of the ipsec<I>n</I> interface(s) should be set to,
+overriding IPsec's (large) default.
+This parameter is needed only in special situations.
+</DL>
+<A NAME="lbAI">&nbsp;</A>
+<H2>IMPLICIT CONNS</H2>
+
+<P>
+
+The system automatically defines several conns to implement
+default policy groups. Each can be overridden by explicitly
+defining a new conn with the same name. If the new conn has <B>auto=ignore</B>,
+the definition is suppressed.
+<P>
+
+Here are the automatically supplied definitions.
+<P>
+
+
+<PRE>
+<B>
+conn clear
+ type=passthrough
+ authby=never
+ left=%defaultroute
+ right=%group
+ auto=route
+
+conn clear-or-private
+ type=passthrough
+ left=%defaultroute
+ leftid=%myid
+ right=%opportunisticgroup
+ failureshunt=passthrough
+ keyingtries=3
+ ikelifetime=1h
+ keylife=1h
+ rekey=no
+ auto=route
+
+conn private-or-clear
+ type=tunnel
+ left=%defaultroute
+ leftid=%myid
+ right=%opportunisticgroup
+ failureshunt=passthrough
+ keyingtries=3
+ ikelifetime=1h
+ keylife=1h
+ rekey=no
+ auto=route
+
+conn private
+ type=tunnel
+ left=%defaultroute
+ leftid=%myid
+ right=%opportunisticgroup
+ failureshunt=drop
+ keyingtries=3
+ ikelifetime=1h
+ keylife=1h
+ rekey=no
+ auto=route
+
+conn block
+ type=reject
+ authby=never
+ left=%defaultroute
+ right=%group
+ auto=route
+
+# default policy
+conn packetdefault
+ type=tunnel
+ left=%defaultroute
+ leftid=%myid
+ left=0.0.0.0/0
+ right=%opportunistic
+ failureshunt=passthrough
+ keyingtries=3
+ ikelifetime=1h
+ keylife=1h
+ rekey=no
+ auto=route
+</B></PRE>
+
+<P>
+
+These conns are <I>not</I> affected by anything in <B>conn %default</B>.
+They will only work if <B>%defaultroute</B> works.
+The <B>leftid</B> will be the interfaces IP address; this
+requires that reverse DNS records be set up properly.
+<P>
+
+The implicit conns are defined after all others. It is
+appropriate and reasonable to use <B>also=private-or-clear</B>
+(for example) in any other opportunistic conn.
+<A NAME="lbAJ">&nbsp;</A>
+<H2>POLICY GROUP FILES</H2>
+
+<P>
+
+The optional files under
+<I>/etc/ipsec.d/policy</I>,
+
+including
+<PRE>
+
+/etc/ipsec.d/policies/clear
+/etc/ipsec.d/policies/clear-or-private
+/etc/ipsec.d/policies/private-or-clear
+/etc/ipsec.d/policies/private
+/etc/ipsec.d/policies/block
+
+</PRE>
+
+may contain policy group configuration information to
+supplement
+<I>ipsec.conf</I>.
+
+Their contents are not security-sensitive.
+<P>
+
+These files are text files.
+Each consists of a list of CIDR blocks, one per line.
+White space followed by # followed by anything to the end of the line
+is a comment and is ignored, as are empty lines.
+<P>
+
+A connection in
+<I>/etc/ipsec.conf</I>
+
+which has
+<B>right=%group</B>
+
+or
+<B>right=%opportunisticgroup</B>
+
+is a policy group connection.
+When a policy group file of the same name is loaded, with
+<P>
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B>ipsec auto --rereadgroups</B>
+<P>
+
+or at system start, the connection is instantiated such that each
+CIDR block serves as an instance's
+<B>right</B>
+
+value. The system treats the
+resulting instances as normal connections.
+<P>
+
+For example, given a suitable connection definition
+<B>private</B>,
+
+and the file
+<I>/etc/ipsec.d/policy/private </I>
+
+with an entry 192.0.2.3,
+the system creates a connection instance
+<B>private#192.0.2.3.</B>
+
+This connection inherits all details from
+<B>private</B>,
+
+except that its right client is 192.0.2.3.
+<A NAME="lbAK">&nbsp;</A>
+<H2>DEFAULT POLICY GROUPS</H2>
+
+<P>
+
+The standard FreeS/WAN install includes several policy groups
+which provide a way of classifying possible peers into IPsec security classes:
+<B>private</B>
+
+(talk encrypted only),
+<B>private-or-clear</B>
+
+(prefer encryption),
+<B>clear-or-private</B>
+
+(respond to requests for encryption),
+<B>clear</B>
+
+and
+<B>block</B>.
+
+Implicit policy groups apply to the local host only,
+and are implemented by the
+<B>IMPLICIT CONNECTIONS </B>
+
+described above.
+<A NAME="lbAL">&nbsp;</A>
+<H2>CHOOSING A CONNECTION</H2>
+
+<P>
+
+When choosing a connection to apply to an outbound packet caught with a
+<B>%trap,</B>
+
+the system prefers the one with the most specific eroute that
+includes the packet's source and destination IP addresses.
+Source subnets are examined before destination subnets.
+For initiating, only routed connections are considered. For responding,
+unrouted but added connections are considered.
+<P>
+
+When choosing a connection to use to respond to a negotiation which
+doesn't match an ordinary conn, an opportunistic connection
+may be instantiated. Eventually, its instance will be /32 -&gt; /32, but
+for earlier stages of the negotiation, there will not be enough
+information about the client subnets to complete the instantiation.
+<A NAME="lbAM">&nbsp;</A>
+<H2>FILES</H2>
+
+<PRE>
+/etc/ipsec.conf
+/etc/ipsec.d/policies/clear
+/etc/ipsec.d/policies/clear-or-private
+/etc/ipsec.d/policies/private-or-clear
+/etc/ipsec.d/policies/private
+/etc/ipsec.d/policies/block
+</PRE>
+
+<A NAME="lbAN">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_ttoaddr.8.html">ipsec_ttoaddr</A>(8), <A HREF="ipsec_auto.8.html">ipsec_auto</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_rsasigkey.8.html">ipsec_rsasigkey</A>(8)
+<A NAME="lbAO">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Designed for the FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<A NAME="lbAP">&nbsp;</A>
+<H2>BUGS</H2>
+
+<P>
+
+When
+<B>type</B>
+
+or
+<B>failureshunt</B>
+
+is set to
+<B>drop</B>
+
+or
+<B>reject,</B>
+
+FreeS/WAN blocks outbound packets using eroutes, but assumes inbound
+blocking is handled by the firewall. FreeS/WAN offers firewall hooks
+via an ``updown'' script. However, the default
+<B>ipsec _updown</B>
+
+provides no help in controlling a modern firewall.
+<P>
+
+Including attributes of the keying channel
+(authentication methods,
+<B>ikelifetime</B>,
+
+etc.)
+as an attribute of a connection,
+rather than of a participant pair, is dubious and incurs limitations.
+<P>
+
+<I>Ipsec_manual</I>
+
+is not nearly as generous about the syntax of subnets,
+addresses, etc. as the usual FreeS/WAN user interfaces.
+Four-component dotted-decimal must be used for all addresses.
+It
+<I>is</I>
+
+smart enough to translate bit-count netmasks to dotted-decimal form.
+<P>
+
+It would be good to have a line-continuation syntax,
+especially for the very long lines involved in
+RSA signature keys.
+<P>
+
+The ability to specify different identities,
+<B>authby</B>,
+
+and public keys for different automatic-keyed connections
+between the same participants is misleading;
+this doesn't work dependably because the identity of the participants
+is not known early enough.
+This is especially awkward for the ``Road Warrior'' case,
+where the remote IP address is specified as
+<B>0.0.0.0</B>,
+
+and that is considered to be the ``participant'' for such connections.
+<P>
+
+In principle it might be necessary to control MTU on an
+interface-by-interface basis,
+rather than with the single global override that
+<B>overridemtu</B>
+
+provides.
+<P>
+
+A number of features which <I>could</I> be implemented in
+both manual and automatic keying
+actually are not yet implemented for manual keying.
+This is unlikely to be fixed any time soon.
+<P>
+
+If conns are to be added before DNS is available,
+<B>left=</B><I>FQDN</I>,
+<B>leftnextop=</B><I>FQDN</I>,
+and
+<B>leftrsasigkey=%dnsonload</B>
+
+will fail.
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8)
+
+does not actually use the public key for our side of a conn but it
+isn't generally known at a add-time which side is ours (Road Warrior
+and Opportunistic conns are currently exceptions).
+<P>
+
+The <B>myid</B> option does not affect explicit <B> ipsec auto --add</B> or <B>ipsec auto --replace</B> commands for implicit conns.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">CONN SECTIONS</A><DD>
+<DL>
+<DT><A HREF="#lbAE">CONN PARAMETERS: GENERAL</A><DD>
+<DT><A HREF="#lbAF">CONN PARAMETERS: AUTOMATIC KEYING</A><DD>
+<DT><A HREF="#lbAG">CONN PARAMETERS: MANUAL KEYING</A><DD>
+</DL>
+<DT><A HREF="#lbAH">CONFIG SECTIONS</A><DD>
+<DT><A HREF="#lbAI">IMPLICIT CONNS</A><DD>
+<DT><A HREF="#lbAJ">POLICY GROUP FILES</A><DD>
+<DT><A HREF="#lbAK">DEFAULT POLICY GROUPS</A><DD>
+<DT><A HREF="#lbAL">CHOOSING A CONNECTION</A><DD>
+<DT><A HREF="#lbAM">FILES</A><DD>
+<DT><A HREF="#lbAN">SEE ALSO</A><DD>
+<DT><A HREF="#lbAO">HISTORY</A><DD>
+<DT><A HREF="#lbAP">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec.secrets.5.html b/doc/manpage.d/ipsec.secrets.5.html
new file mode 100644
index 000000000..8abc1f492
--- /dev/null
+++ b/doc/manpage.d/ipsec.secrets.5.html
@@ -0,0 +1,227 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC.SECRETS</TITLE>
+</HEAD><BODY>
+<H1>IPSEC.SECRETS</H1>
+Section: File Formats (5)<BR>Updated: 28 March 1999<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec.secrets - secrets for IKE/IPsec authentication
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The file <I>ipsec.secrets</I> holds a table of secrets.
+These secrets are used by <I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8), the FreeS/WAN Internet Key
+Exchange daemon, to authenticate other hosts.
+Currently there are two kinds of secrets: preshared secrets and
+
+RSA private keys.
+<P>
+
+It is vital that these secrets be protected. The file should be owned
+by the super-user,
+and its permissions should be set to block all access by others.
+<P>
+
+The file is a sequence of entries and include directives.
+Here is an example. Each entry or directive must start at the
+left margin, but if it continues beyond a single line, each continuation
+line must be indented.
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+# sample /etc/ipsec.secrets file for 10.1.0.1
+10.1.0.1 10.2.0.1: PSK &quot;secret shared by two hosts&quot;
+
+# an entry may be split across lines,
+# but indentation matters
+<A HREF="http://www.xs4all.nl">www.xs4all.nl</A> @<A HREF="http://www.kremvax.ru">www.kremvax.ru</A>
+&nbsp;&nbsp;&nbsp;&nbsp;10.6.0.1 10.7.0.1 1.8.0.1: PSK &quot;secret shared by 5&quot;
+
+# an RSA private key.
+# note that the lines are too wide for a
+# man page, so ... has been substituted for
+# the truncated part
+@my.com: rsa {
+&nbsp;&nbsp;&nbsp;&nbsp;Modulus:&nbsp;0syXpo/6waam+ZhSs8Lt6jnBzu3C4grtt...
+&nbsp;&nbsp;&nbsp;&nbsp;PublicExponent:&nbsp;0sAw==
+&nbsp;&nbsp;&nbsp;&nbsp;PrivateExponent:&nbsp;0shlGbVR1m8Z+7rhzSyenCaBN...
+&nbsp;&nbsp;&nbsp;&nbsp;Prime1:&nbsp;0s8njV7WTxzVzRz7AP+0OraDxmEAt1BL5l...
+&nbsp;&nbsp;&nbsp;&nbsp;Prime2:&nbsp;0s1LgR7/oUMo9BvfU8yRFNos1s211KX5K0...
+&nbsp;&nbsp;&nbsp;&nbsp;Exponent1:&nbsp;0soaXj85ihM5M2inVf/NfHmtLutVz4r...
+&nbsp;&nbsp;&nbsp;&nbsp;Exponent2:&nbsp;0sjdAL9VFizF+BKU4ohguJFzOd55OG6...
+&nbsp;&nbsp;&nbsp;&nbsp;Coefficient:&nbsp;0sK1LWwgnNrNFGZsS/2GuMBg9nYVZ...
+&nbsp;&nbsp;&nbsp;&nbsp;}
+
+include ipsec.*.secrets # get secrets from other files
+</PRE>
+
+</DL>
+
+<P>
+
+Each entry in the file is a list of indices, followed by a secret.
+The two parts are separated by a colon (<B>:</B>) that is
+followed by whitespace or a newline. For compatability
+with the previous form of this file, if the key part is just a
+double-quoted string the colon may be left out.
+<P>
+
+An index is an IP address, or a Fully Qualified Domain Name, <A HREF="mailto:user@FQDN">user@FQDN</A>,
+<B>%any</B> or <B>%any6</B> (other kinds may come). An IP address may be written
+in the familiar dotted quad form or as a domain name to be looked up
+when the file is loaded
+(or in any of the forms supported by the FreeS/WAN <I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3)
+routine). In many cases it is a bad idea to use domain names because
+the name server may not be running or may be insecure. To denote a
+Fully Qualified Domain Name (as opposed to an IP address denoted by
+its domain name), precede the name with an at sign (<B>@</B>).
+<P>
+
+Matching IDs with indices is fairly straightforward: they have to be
+equal. In the case of a ``Road Warrior'' connection, if an equal
+match is not found for the Peer's ID, and it is in the form of an IP
+address, an index of <B>%any</B> will match the peer's IP address if IPV4
+and <B>%any6</B> will match a the peer's IP address if IPV6.
+Currently, the obsolete notation <B>0.0.0.0</B> may be used in place of
+<B>%any</B>.
+<P>
+
+An additional complexity
+arises in the case of authentication by preshared secret: the
+responder will need to look up the secret before the Peer's ID payload has
+been decoded, so the ID used will be the IP address.
+<P>
+
+To authenticate a connection between two hosts, the entry that most
+specifically matches the host and peer IDs is used. An entry with no
+index will match any host and peer. More specifically, an entry with one index will
+match a host and peer if the index matches the host's ID (the peer isn't
+considered). Still more specifically, an entry with multiple indices will match a host and
+peer if the host ID and peer ID each match one of the indices. If the key
+is for an asymmetric authentication technique (i.e. a public key
+system such as RSA), an entry with multiple indices will match a host
+and peer even if only the host ID matches an index (it is presumed that the
+multiple indices are all identities of the host).
+It is acceptable for two entries to be the best match as
+long as they agree about the secret or private key.
+<P>
+
+Authentication by preshared secret requires that both systems find the
+identical secret (the secret is not actually transmitted by the IKE
+protocol). If both the host and peer appear in the index list, the
+same entry will be suitable for both systems so verbatim copying
+between systems can be used. This naturally extends to larger groups
+sharing the same secret. Thus multiple-index entries are best for PSK
+authentication.
+<P>
+
+Authentication by RSA Signatures requires that each host have its own private
+key. A host could reasonably use a different private keys
+for different interfaces and for different peers. But it would not
+be normal to share entries between systems. Thus thus no-index and
+one-index forms of entry often make sense for RSA Signature authentication.
+<P>
+
+The key part of an entry may start with a token indicating the kind of
+key. ``RSA'' signifies RSA private key and ``PSK'' signifies
+PreShared Key (case is ignored). For compatability with previous
+forms of this file, PSK is the default.
+<P>
+
+A preshared secret is most conveniently represented as a sequence of
+characters, delimited by the double-quote
+character (<B>&quot;</B>). The sequence cannot contain a newline or
+double-quote. Strictly speaking, the secret is actually the sequence
+of bytes that is used in the file to represent the sequence of
+characters (excluding the delimiters).
+A preshared secret may also be represented, without quotes, in any form supported by
+<I><A HREF="ipsec_ttodata.3.html">ipsec_ttodata</A></I>(3).
+<P>
+
+An RSA private key is a composite of eight generally large numbers. The notation
+used is a brace-enclosed list of field name and value pairs (see the example above).
+A suitable key, in a suitable format, may be generated by <I><A HREF="ipsec_rsasigkey.8.html">ipsec_rsasigkey</A></I>(8).
+The structure is very similar to that used by BIND 8.2.2 or later, but note that
+the numbers must have a ``0s'' prefix if they are in base 64. The order of
+the fields is fixed.
+<P>
+
+The first token an entry must start in
+the first column of its line. Subsequent tokens must be
+separated by whitespace,
+except for a colon token, which only needs to be followed by whitespace.
+A newline is taken as whitespace, but every
+line of an entry after the first must be indented.
+<P>
+
+Whitespace at the end of a line is ignored (except in the 0t
+notation for a key). At the start of line or
+after whitespace, <B>#</B> and the following text up to the end of the
+line is treated as a comment. Within entries, all lines must be
+indented (except for lines with no tokens).
+Outside entries, no line may be indented (this is to make sure that
+the file layout reflects its structure).
+<P>
+
+An include directive causes the contents of the named file to be processed
+before continuing with the current file. The filename is subject to
+``globbing'' as in <I><A HREF="sh.1.html">sh</A></I>(1), so every file with a matching name
+is processed. Includes may be nested to a modest
+depth (10, currently). If the filename doesn't start with a <B>/</B>, the
+directory containing the current file is prepended to the name. The
+include directive is a line that starts with the word <B>include</B>,
+followed by whitespace, followed by the filename (which must not contain
+whitespace).
+<A NAME="lbAD">&nbsp;</A>
+<H2>FILES</H2>
+
+/etc/ipsec.secrets
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+The rest of the FreeS/WAN distribution, in particular
+<I><A HREF="ipsec.conf.5.html">ipsec.conf</A></I>(5),
+<I><A HREF="ipsec.8.html">ipsec</A></I>(8),
+<I><A HREF="ipsec_newhostkey.8.html">ipsec_newhostkey</A></I>(8),
+<I><A HREF="ipsec_rsasigkey.8.html">ipsec_rsasigkey</A></I>(8),
+<I><A HREF="ipsec_showhostkey.8.html">ipsec_showhostkey</A></I>(8),
+<I><A HREF="ipsec_auto.8.html">ipsec_auto</A></I>(8) <B>--rereadsecrets</B>,
+and <I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8) <B>--listen</B>,.
+<BR>
+
+BIND 8.2.2 or later, <A HREF="ftp://ftp.isc.org/isc/bind/src/">ftp://ftp.isc.org/isc/bind/src/</A>
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Designed for the FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by D. Hugh Redelmeier.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+If an ID is <B>0.0.0.0</B>, it will match <B>%any</B>;
+if it is <B>0::0</B>, it will match <B>%any6</B>.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">FILES</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__confread.8.html b/doc/manpage.d/ipsec__confread.8.html
new file mode 100644
index 000000000..ecc120c7e
--- /dev/null
+++ b/doc/manpage.d/ipsec__confread.8.html
@@ -0,0 +1,58 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _CONFREAD</TITLE>
+</HEAD><BODY>
+<H1>_CONFREAD</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _confread - internal routing to parse config file
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>_confread </I>
+
+is an internal script used for parsing /etc/ipsec.conf into a canonical format.
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_conf.8.html">ipsec_conf</A>(8)
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Program written by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__copyright.8.html b/doc/manpage.d/ipsec__copyright.8.html
new file mode 100644
index 000000000..7f78b3feb
--- /dev/null
+++ b/doc/manpage.d/ipsec__copyright.8.html
@@ -0,0 +1,62 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _COPYRIGHT</TITLE>
+</HEAD><BODY>
+<H1>_COPYRIGHT</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _copyright - prints FreeSWAN copyright
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>_copyright</I>
+
+outputs the FreeSWAN copyright, and version numbers for &quot;ipsec --copyright&quot;
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8)
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Program written by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__include.8.html b/doc/manpage.d/ipsec__include.8.html
new file mode 100644
index 000000000..d85ee7852
--- /dev/null
+++ b/doc/manpage.d/ipsec__include.8.html
@@ -0,0 +1,67 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _INCLUDE</TITLE>
+</HEAD><BODY>
+<H1>_INCLUDE</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _include - internal script to process config files
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>_include</I>
+
+is used by
+<I>_confread </I>
+
+to process
+<B>include </B>
+
+directives in /etc/ipsec.conf.
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec__confread.8.html">ipsec__confread</A>(8)
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Program written by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__keycensor.8.html b/doc/manpage.d/ipsec__keycensor.8.html
new file mode 100644
index 000000000..22e574932
--- /dev/null
+++ b/doc/manpage.d/ipsec__keycensor.8.html
@@ -0,0 +1,64 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _KEYCENSOR</TITLE>
+</HEAD><BODY>
+<H1>_KEYCENSOR</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _keycensor - internal routine to remove sensitive information
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>_keycensor</I>
+
+is used by
+<B>ipsec barf</B>
+
+to process the /etc/ipsec.secrets file, removing private key info.
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_barf.8.html">ipsec_barf</A>(8)
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Original program by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__plutoload.8.html b/doc/manpage.d/ipsec__plutoload.8.html
new file mode 100644
index 000000000..2c4968300
--- /dev/null
+++ b/doc/manpage.d/ipsec__plutoload.8.html
@@ -0,0 +1,64 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _PLUTOLOAD</TITLE>
+</HEAD><BODY>
+<H1>_PLUTOLOAD</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _plutoload - internal script to start pluto
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>_plutoload</I>
+
+is called by
+<B>_plutorun</B>
+
+to actually start the pluto executable.
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_setup.8.html">ipsec_setup</A>(8), <A HREF="ipsec__realsetup.8.html">ipsec__realsetup</A>(8), <A HREF="ipsec__plutorun.8.html">ipsec__plutorun</A>(8)
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Original program by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__plutorun.8.html b/doc/manpage.d/ipsec__plutorun.8.html
new file mode 100644
index 000000000..1b5a1da11
--- /dev/null
+++ b/doc/manpage.d/ipsec__plutorun.8.html
@@ -0,0 +1,70 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _PLUTORUN</TITLE>
+</HEAD><BODY>
+<H1>_PLUTORUN</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _plutorun - internal script to start pluto
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>_plutorun</I>
+
+is called by
+<B>_realsetup</B>
+
+to configure and bring up
+<B><A HREF="ipsec_pluto.8.html">ipsec_pluto</A>(8).</B>
+
+It calls
+<B>_plutoload</B>
+
+to invoke pluto, and watches to makes sure that pluto is restarted if it fails.
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_setup.8.html">ipsec_setup</A>(8), <A HREF="ipsec__realsetup.8.html">ipsec__realsetup</A>(8), <A HREF="ipsec__plutoload.8.html">ipsec__plutoload</A>(8), <A HREF="ipsec_pluto.8.html">ipsec_pluto</A>(8).
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Original program written by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__realsetup.8.html b/doc/manpage.d/ipsec__realsetup.8.html
new file mode 100644
index 000000000..f45bec647
--- /dev/null
+++ b/doc/manpage.d/ipsec__realsetup.8.html
@@ -0,0 +1,68 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _REALSETUP</TITLE>
+</HEAD><BODY>
+<H1>_REALSETUP</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _realsetup - internal routine to start FreeS/WAN.
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>_realsetup</I>
+
+is called by the system init scripts to start the FreeS/WAN
+system. It starts
+<B>KLIPS </B>
+
+(the kernel component) and
+<B>pluto </B>
+
+(the userspace keying component).
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec__klipsstart.8.html">ipsec__klipsstart</A>(8), <A HREF="ipsec__plutorun.8.html">ipsec__plutorun</A>(8).
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Original program by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__secretcensor.8.html b/doc/manpage.d/ipsec__secretcensor.8.html
new file mode 100644
index 000000000..6c6ea312d
--- /dev/null
+++ b/doc/manpage.d/ipsec__secretcensor.8.html
@@ -0,0 +1,65 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _SECRETCENSOR</TITLE>
+</HEAD><BODY>
+<H1>_SECRETCENSOR</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _secretcensor - internal routing to sanitize files
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>_secretcensor</I>
+
+is called by
+<B>ipsec barf</B>
+
+to process the /etc/ipsec.secrets file to remove the private key components
+from the file prior to revealing the contents.
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_barf.8.html">ipsec_barf</A>(8).
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Original program by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__startklips.8.html b/doc/manpage.d/ipsec__startklips.8.html
new file mode 100644
index 000000000..3ad565e57
--- /dev/null
+++ b/doc/manpage.d/ipsec__startklips.8.html
@@ -0,0 +1,63 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _STARTKLIPS</TITLE>
+</HEAD><BODY>
+<H1>_STARTKLIPS</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _startklips - internal script to bring up kernel components
+<A NAME="lbAC">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>_startklips</I>
+
+brings up the FreeS/WAN kernel component. This involves loading any
+required modules, attaching and configuring the ipsecX pseudo-devices and
+attaching the pseudo-devices to the physical devices.
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8).
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Original program by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec__updown.8.html b/doc/manpage.d/ipsec__updown.8.html
new file mode 100644
index 000000000..73bf8a343
--- /dev/null
+++ b/doc/manpage.d/ipsec__updown.8.html
@@ -0,0 +1,63 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of _UPDOWN</TITLE>
+</HEAD><BODY>
+<H1>_UPDOWN</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec _updown - klips manipulation script
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<I>_updown</I>
+
+is invoked by pluto when it has brought up a new connection. This script
+is used to insert the appropriate routing entries for IPsec operation.
+The interface to the script is documented in the pluto man page.
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_pluto.8.html">ipsec_pluto</A>(8).
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Original program written by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_addrbytesof.3.html b/doc/manpage.d/ipsec_addrbytesof.3.html
new file mode 100644
index 000000000..ca1f857e7
--- /dev/null
+++ b/doc/manpage.d/ipsec_addrbytesof.3.html
@@ -0,0 +1,232 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initaddr - initialize an ip_address
+<BR>
+
+ipsec addrtypeof - get address type of an ip_address
+<BR>
+
+ipsec addrlenof - get length of address within an ip_address
+<BR>
+
+ipsec addrbytesof - get copy of address within an ip_address
+<BR>
+
+ipsec addrbytesptr - get pointer to address within an ip_address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int addrtypeof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrlenof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrbytesof(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>unsigned char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>size_t addrbytesptr(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char **dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_address</I>
+
+to contain one of the (currently two) types of IP address.
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initaddr</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_address</I>
+
+from an address
+(in network byte order,
+indicated by a pointer
+<I>src</I>
+
+and a length
+<I>srclen</I>)
+
+and an address family
+<I>af</I>
+
+(typically
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The length must be consistent with the address family.
+<P>
+
+<I>Addrtypeof</I>
+
+returns the address type of an address,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Addrlenof</I>
+
+returns the size (in bytes) of the address within an
+<I>ip_address</I>,
+
+to permit storage allocation etc.
+<P>
+
+<I>Addrbytesof</I>
+
+copies the address within the
+<I>ip_address</I>
+
+<I>src</I>
+
+to the buffer indicated by the pointer
+<I>dst</I>
+
+and the length
+<I>dstlen</I>,
+
+and returns the address length (in bytes).
+If the address will not fit,
+as many bytes as will fit are copied;
+the returned length is still the full length.
+It is the caller's responsibility to check the
+returned value to ensure that there was enough room.
+<P>
+
+<I>Addrbytesptr</I>
+
+sets
+<I>*dst</I>
+
+to a pointer to the internal address within the
+<I>ip_address</I>,
+
+and returns the address length (in bytes).
+If
+<I>dst</I>
+
+is
+<B>NULL</B>,
+
+it just returns the address length.
+The pointer points to
+<B>const</B>
+
+to discourage misuse.
+<P>
+
+<I>Initaddr</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+The functions which return
+<I>size_t</I>
+
+return
+<B>0</B>
+
+for a failure.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+An unknown address family is a fatal error for any of these functions
+except
+<I>addrtypeof</I>.
+
+An address-size mismatch is a fatal error for
+<I>initaddr</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+<I>Addrtypeof</I>
+
+should probably have been named
+<I>addrfamilyof</I>.
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_addrbytesptr.3.html b/doc/manpage.d/ipsec_addrbytesptr.3.html
new file mode 100644
index 000000000..ca1f857e7
--- /dev/null
+++ b/doc/manpage.d/ipsec_addrbytesptr.3.html
@@ -0,0 +1,232 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initaddr - initialize an ip_address
+<BR>
+
+ipsec addrtypeof - get address type of an ip_address
+<BR>
+
+ipsec addrlenof - get length of address within an ip_address
+<BR>
+
+ipsec addrbytesof - get copy of address within an ip_address
+<BR>
+
+ipsec addrbytesptr - get pointer to address within an ip_address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int addrtypeof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrlenof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrbytesof(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>unsigned char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>size_t addrbytesptr(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char **dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_address</I>
+
+to contain one of the (currently two) types of IP address.
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initaddr</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_address</I>
+
+from an address
+(in network byte order,
+indicated by a pointer
+<I>src</I>
+
+and a length
+<I>srclen</I>)
+
+and an address family
+<I>af</I>
+
+(typically
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The length must be consistent with the address family.
+<P>
+
+<I>Addrtypeof</I>
+
+returns the address type of an address,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Addrlenof</I>
+
+returns the size (in bytes) of the address within an
+<I>ip_address</I>,
+
+to permit storage allocation etc.
+<P>
+
+<I>Addrbytesof</I>
+
+copies the address within the
+<I>ip_address</I>
+
+<I>src</I>
+
+to the buffer indicated by the pointer
+<I>dst</I>
+
+and the length
+<I>dstlen</I>,
+
+and returns the address length (in bytes).
+If the address will not fit,
+as many bytes as will fit are copied;
+the returned length is still the full length.
+It is the caller's responsibility to check the
+returned value to ensure that there was enough room.
+<P>
+
+<I>Addrbytesptr</I>
+
+sets
+<I>*dst</I>
+
+to a pointer to the internal address within the
+<I>ip_address</I>,
+
+and returns the address length (in bytes).
+If
+<I>dst</I>
+
+is
+<B>NULL</B>,
+
+it just returns the address length.
+The pointer points to
+<B>const</B>
+
+to discourage misuse.
+<P>
+
+<I>Initaddr</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+The functions which return
+<I>size_t</I>
+
+return
+<B>0</B>
+
+for a failure.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+An unknown address family is a fatal error for any of these functions
+except
+<I>addrtypeof</I>.
+
+An address-size mismatch is a fatal error for
+<I>initaddr</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+<I>Addrtypeof</I>
+
+should probably have been named
+<I>addrfamilyof</I>.
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_addrcmp.3.html b/doc/manpage.d/ipsec_addrcmp.3.html
new file mode 100644
index 000000000..93ac522cd
--- /dev/null
+++ b/doc/manpage.d/ipsec_addrcmp.3.html
@@ -0,0 +1,274 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Nov 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec sameaddr - are two addresses the same?
+<BR>
+
+ipsec addrcmp - ordered comparison of addresses
+<BR>
+
+ipsec samesubnet - are two subnets the same?
+<BR>
+
+ipsec addrinsubnet - is an address within a subnet?
+<BR>
+
+ipsec subnetinsubnet - is a subnet within another subnet?
+<BR>
+
+ipsec subnetishost - is a subnet a single host?
+<BR>
+
+ipsec samesaid - are two SA IDs the same?
+<BR>
+
+ipsec sameaddrtype - are two addresses of the same address family?
+<BR>
+
+ipsec samesubnettype - are two subnets of the same address family?
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int sameaddr(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int addrcmp(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int addrinsubnet(const ip_address *a, const ip_subnet *s);</B>
+
+<BR>
+
+<B>int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int subnetishost(const ip_subnet *s);</B>
+
+<BR>
+
+<B>int samesaid(const ip_said *a, const ip_said *b);</B>
+
+<BR>
+
+<B>int sameaddrtype(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnettype(const ip_subnet *a, const ip_subnet *b);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions do various comparisons and tests on the
+<I>ip_address</I>
+
+type and
+<I>ip_subnet</I>
+
+types.
+<P>
+
+<I>Sameaddr</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Addresses of different families are never identical.
+<P>
+
+<I>Addrcmp</I>
+
+returns
+<B>-1</B>,
+
+<B>0</B>,
+
+or
+<B>1</B>
+
+respectively
+if address
+<I>a</I>
+
+is less than, equal to, or greater than
+<I>b</I>.
+
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+<P>
+
+<I>Samesubnet</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Subnets of different address families are never identical.
+<P>
+
+<I>Addrinsubnet</I>
+
+returns
+non-zero
+if address
+<I>a</I>
+
+is within subnet
+<I>s</I>
+
+and
+<B>0</B>
+
+otherwise.
+An address is never within a
+subnet of a different address family.
+<P>
+
+<I>Subnetinsubnet</I>
+
+returns
+non-zero
+if subnet
+<I>a</I>
+
+is a subset of subnet
+<I>b</I>
+
+and
+<B>0</B>
+
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+<P>
+
+<I>Subnetishost</I>
+
+returns
+non-zero
+if subnet
+<I>s</I>
+
+is in fact only a single host,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesaid</I>
+
+returns
+non-zero
+if SA IDs
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Sameaddrtype</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesubnettype</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_addrinsubnet.3.html b/doc/manpage.d/ipsec_addrinsubnet.3.html
new file mode 100644
index 000000000..93ac522cd
--- /dev/null
+++ b/doc/manpage.d/ipsec_addrinsubnet.3.html
@@ -0,0 +1,274 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Nov 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec sameaddr - are two addresses the same?
+<BR>
+
+ipsec addrcmp - ordered comparison of addresses
+<BR>
+
+ipsec samesubnet - are two subnets the same?
+<BR>
+
+ipsec addrinsubnet - is an address within a subnet?
+<BR>
+
+ipsec subnetinsubnet - is a subnet within another subnet?
+<BR>
+
+ipsec subnetishost - is a subnet a single host?
+<BR>
+
+ipsec samesaid - are two SA IDs the same?
+<BR>
+
+ipsec sameaddrtype - are two addresses of the same address family?
+<BR>
+
+ipsec samesubnettype - are two subnets of the same address family?
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int sameaddr(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int addrcmp(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int addrinsubnet(const ip_address *a, const ip_subnet *s);</B>
+
+<BR>
+
+<B>int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int subnetishost(const ip_subnet *s);</B>
+
+<BR>
+
+<B>int samesaid(const ip_said *a, const ip_said *b);</B>
+
+<BR>
+
+<B>int sameaddrtype(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnettype(const ip_subnet *a, const ip_subnet *b);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions do various comparisons and tests on the
+<I>ip_address</I>
+
+type and
+<I>ip_subnet</I>
+
+types.
+<P>
+
+<I>Sameaddr</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Addresses of different families are never identical.
+<P>
+
+<I>Addrcmp</I>
+
+returns
+<B>-1</B>,
+
+<B>0</B>,
+
+or
+<B>1</B>
+
+respectively
+if address
+<I>a</I>
+
+is less than, equal to, or greater than
+<I>b</I>.
+
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+<P>
+
+<I>Samesubnet</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Subnets of different address families are never identical.
+<P>
+
+<I>Addrinsubnet</I>
+
+returns
+non-zero
+if address
+<I>a</I>
+
+is within subnet
+<I>s</I>
+
+and
+<B>0</B>
+
+otherwise.
+An address is never within a
+subnet of a different address family.
+<P>
+
+<I>Subnetinsubnet</I>
+
+returns
+non-zero
+if subnet
+<I>a</I>
+
+is a subset of subnet
+<I>b</I>
+
+and
+<B>0</B>
+
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+<P>
+
+<I>Subnetishost</I>
+
+returns
+non-zero
+if subnet
+<I>s</I>
+
+is in fact only a single host,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesaid</I>
+
+returns
+non-zero
+if SA IDs
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Sameaddrtype</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesubnettype</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_addrlenof.3.html b/doc/manpage.d/ipsec_addrlenof.3.html
new file mode 100644
index 000000000..ca1f857e7
--- /dev/null
+++ b/doc/manpage.d/ipsec_addrlenof.3.html
@@ -0,0 +1,232 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initaddr - initialize an ip_address
+<BR>
+
+ipsec addrtypeof - get address type of an ip_address
+<BR>
+
+ipsec addrlenof - get length of address within an ip_address
+<BR>
+
+ipsec addrbytesof - get copy of address within an ip_address
+<BR>
+
+ipsec addrbytesptr - get pointer to address within an ip_address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int addrtypeof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrlenof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrbytesof(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>unsigned char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>size_t addrbytesptr(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char **dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_address</I>
+
+to contain one of the (currently two) types of IP address.
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initaddr</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_address</I>
+
+from an address
+(in network byte order,
+indicated by a pointer
+<I>src</I>
+
+and a length
+<I>srclen</I>)
+
+and an address family
+<I>af</I>
+
+(typically
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The length must be consistent with the address family.
+<P>
+
+<I>Addrtypeof</I>
+
+returns the address type of an address,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Addrlenof</I>
+
+returns the size (in bytes) of the address within an
+<I>ip_address</I>,
+
+to permit storage allocation etc.
+<P>
+
+<I>Addrbytesof</I>
+
+copies the address within the
+<I>ip_address</I>
+
+<I>src</I>
+
+to the buffer indicated by the pointer
+<I>dst</I>
+
+and the length
+<I>dstlen</I>,
+
+and returns the address length (in bytes).
+If the address will not fit,
+as many bytes as will fit are copied;
+the returned length is still the full length.
+It is the caller's responsibility to check the
+returned value to ensure that there was enough room.
+<P>
+
+<I>Addrbytesptr</I>
+
+sets
+<I>*dst</I>
+
+to a pointer to the internal address within the
+<I>ip_address</I>,
+
+and returns the address length (in bytes).
+If
+<I>dst</I>
+
+is
+<B>NULL</B>,
+
+it just returns the address length.
+The pointer points to
+<B>const</B>
+
+to discourage misuse.
+<P>
+
+<I>Initaddr</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+The functions which return
+<I>size_t</I>
+
+return
+<B>0</B>
+
+for a failure.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+An unknown address family is a fatal error for any of these functions
+except
+<I>addrtypeof</I>.
+
+An address-size mismatch is a fatal error for
+<I>initaddr</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+<I>Addrtypeof</I>
+
+should probably have been named
+<I>addrfamilyof</I>.
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_addrtoa.3.html b/doc/manpage.d/ipsec_addrtoa.3.html
new file mode 100644
index 000000000..8f0d765e5
--- /dev/null
+++ b/doc/manpage.d/ipsec_addrtoa.3.html
@@ -0,0 +1,448 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atoaddr, addrtoa - convert Internet addresses to and from ASCII
+<BR>
+
+ipsec atosubnet, subnettoa - convert subnet/mask ASCII form to and from addresses
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr *addr);</B>
+
+<BR>
+
+<B>size_t addrtoa(struct in_addr addr, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>const char *atosubnet(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr *addr, struct in_addr *mask);</B>
+
+<BR>
+
+<B>size_t subnettoa(struct in_addr addr, struct in_addr mask,</B>
+
+<BR>
+&nbsp;
+<B>int format, char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Atoaddr</I>
+
+converts an ASCII name or dotted-decimal address into a binary address
+(in network byte order).
+<I>Addrtoa</I>
+
+does the reverse conversion, back to an ASCII dotted-decimal address.
+<I>Atosubnet</I>
+
+and
+<I>subnettoa</I>
+
+do likewise for the ``address/mask'' ASCII form used to write a
+specification of a subnet.
+<P>
+
+An address is specified in ASCII as a
+dotted-decimal address (e.g.
+<B>1.2.3.4</B>),
+
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+<B>0x01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>),
+
+an eight-digit host-order hexadecimal number with a
+<B>0h</B>
+
+prefix (e.g.
+<B>0h01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>
+
+on a big-endian host and
+<B>4.3.2.1</B>
+
+on a little-endian host),
+a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3),
+
+or an old-style network name to be looked up via
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3).
+
+<P>
+
+A dotted-decimal address may be incomplete, in which case
+ASCII-to-binary conversion implicitly appends
+as many instances of
+<B>.0</B>
+
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+<B>10</B>
+
+is synonymous with
+<B>10.0.0.0</B>,
+
+and
+<B>128.009.000.032</B>
+
+is synonymous with
+<B>128.9.0.32</B>
+
+(the latter example is verbatim from RFC 1166).
+The result of
+<I>addrtoa</I>
+
+is always complete and does not contain leading zeros.
+<P>
+
+The letters in
+a hexadecimal address may be uppercase or lowercase or any mixture thereof.
+Use of hexadecimal addresses is
+<B>strongly</B>
+
+<B>discouraged</B>;
+
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+<P>
+
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+<I><A HREF="resolver.5.html">resolver</A></I>(5)).
+
+The
+<I>h_addr</I>
+
+value returned by
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3)
+
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+Name lookup resorts to
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3)
+
+only if
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3)
+
+fails.
+<P>
+
+A subnet specification is of the form <I>network</I><B>/</B><I>mask</I>.
+The
+<I>network</I>
+
+and
+<I>mask</I>
+
+can be any form acceptable to
+<I>atoaddr</I>.
+
+In addition, the
+<I>mask</I>
+
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+<B>24</B>
+
+means
+<B>255.255.255.0</B>).
+
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+<B>%default</B>
+
+is a synonym for
+<B>0.0.0.0/0</B>.
+
+<P>
+
+<I>Atosubnet</I>
+
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+<B>10.1.2.3/24</B>
+
+is synonymous with
+<B>10.1.2.0/24</B>).
+
+<I>Subnettoa</I>
+
+generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros,
+unless the mask is non-contiguous.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atoaddr</I>
+
+and
+<I>atosubnet</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines constants,
+<B>ADDRTOA_BUF</B>
+
+and
+<B>SUBNETTOA_BUF</B>,
+
+which are the sizes of buffers just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+<P>
+
+The ASCII-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-ASCII functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atoaddr</I>
+
+are:
+empty input;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal form;
+dotted-decimal component too large to fit in 8 bits.
+<P>
+
+Fatal errors in
+<I>atosubnet</I>
+
+are:
+no
+<B>/</B>
+
+in
+<I>src</I>;
+
+<I>atoaddr</I>
+
+error in conversion of
+<I>network</I>
+
+or
+<I>mask</I>;
+
+bit-count mask too big;
+mask non-contiguous.
+<P>
+
+Fatal errors in
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+<B>10/24</B>
+
+means
+<B>10.0.0.0/24</B>)
+
+differs from that of some older conversion
+functions, e.g. those of
+<I><A HREF="inet.3.html">inet</A></I>(3).
+
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+<P>
+
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+<P>
+
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+<P>
+
+<I><A HREF="Getnetbyname.3.html">Getnetbyname</A></I>(3)
+
+is a historical dreg.
+<P>
+
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_addrtosubnet.3.html b/doc/manpage.d/ipsec_addrtosubnet.3.html
new file mode 100644
index 000000000..e442a9100
--- /dev/null
+++ b/doc/manpage.d/ipsec_addrtosubnet.3.html
@@ -0,0 +1,238 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITSUBNET</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITSUBNET</H1>
+Section: C Library Functions (3)<BR>Updated: 12 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initsubnet - initialize an ip_subnet
+<BR>
+
+ipsec addrtosubnet - initialize a singleton ip_subnet
+<BR>
+
+ipsec subnettypeof - get address type of an ip_subnet
+<BR>
+
+ipsec masktocount - convert subnet mask to bit count
+<BR>
+
+ipsec networkof - get base address of an ip_subnet
+<BR>
+
+ipsec maskof - get subnet mask of an ip_subnet
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initsubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>int maskbits, int clash, ip_subnet *dst);</B>
+
+<BR>
+
+<B>const char *addrtosubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>ip_subnet *dst);</B>
+
+<P>
+<B>int subnettypeof(const ip_subnet *src);</B>
+
+<BR>
+
+<B>int masktocount(const ip_address *src);</B>
+
+<BR>
+
+<B>void networkof(const ip_subnet *src, ip_address *dst);</B>
+
+<BR>
+
+<B>void maskof(const ip_subnet *src, ip_address *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_subnet</I>
+
+to contain a description of an IP subnet
+(base address plus mask).
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initsubnet</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_subnet</I>
+
+from a base address and
+a count of mask bits.
+The
+<I>clash</I>
+
+parameter specifies what to do if the base address includes
+<B>1</B>
+
+bits outside the prefix specified by the mask
+(that is, in the ``host number'' part of the address):
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT>'0'<DD>
+zero out host-number bits
+<DT>'x'<DD>
+non-zero host-number bits are an error
+</DL>
+</DL>
+
+<P>
+
+<I>Initsubnet</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+<I>Addrtosubnet</I>
+
+initializes an
+<I>ip_subnet</I>
+
+variable
+<I>*dst</I>
+
+to a ``singleton subnet'' containing the single address
+<I>*addr</I>.
+
+It returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure.
+<P>
+
+<I>Subnettypeof</I>
+
+returns the address type of a subnet,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Masktocount</I>
+
+converts a subnet mask, expressed as an address, to a bit count
+suitable for use with
+<I>initsubnet</I>.
+
+It returns
+<B>-1</B>
+
+for error; see DIAGNOSTICS.
+<P>
+
+<I>Networkof</I>
+
+fills in
+<I>*dst</I>
+
+with the base address of subnet
+<I>src</I>.
+
+<P>
+
+<I>Maskof</I>
+
+fills in
+<I>*dst</I>
+
+with the subnet mask of subnet
+<I>src</I>,
+
+expressed as an address.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttosubnet.3.html">ipsec_ttosubnet</A>(3), <A HREF="ipsec_rangetosubnet.3.html">ipsec_rangetosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>initsubnet</I>
+
+are:
+unknown address family;
+unknown
+<I>clash</I>
+
+value;
+impossible mask bit count;
+non-zero host-number bits and
+<I>clash</I>
+
+is
+<B>'x'</B>.
+
+Fatal errors in
+<I>addrtosubnet</I>
+
+are:
+unknown address family.
+Fatal errors in
+<I>masktocount</I>
+
+are:
+unknown address family;
+mask bits not contiguous.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_addrtot.3.html b/doc/manpage.d/ipsec_addrtot.3.html
new file mode 100644
index 000000000..eccb946e6
--- /dev/null
+++ b/doc/manpage.d/ipsec_addrtot.3.html
@@ -0,0 +1,569 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Sept 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttoaddr, tnatoaddr, addrtot - convert Internet addresses to and from text
+<BR>
+
+ipsec ttosubnet, subnettot - convert subnet/mask text form to and from addresses
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ttoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>const char *tnatoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>size_t addrtot(const ip_address *addr, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>const char *ttosubnet(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_subnet *dst);</B>
+
+<BR>
+
+<B>size_t subnettot(const ip_subnet *sub, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttoaddr</I>
+
+converts a text-string name or numeric address into a binary address
+(in network byte order).
+<I>Tnatoaddr</I>
+
+does the same conversion,
+but the only text forms it accepts are
+the ``official'' forms of
+numeric address (dotted-decimal for IPv4, colon-hex for IPv6).
+<I>Addrtot</I>
+
+does the reverse conversion, from binary address back to a text form.
+<I>Ttosubnet</I>
+
+and
+<I>subnettot</I>
+
+do likewise for the ``address/mask'' form used to write a
+specification of a subnet.
+<P>
+
+An IPv4 address is specified in text as a
+dotted-decimal address (e.g.
+<B>1.2.3.4</B>),
+
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+<B>0x01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>),
+
+an eight-digit host-order hexadecimal number with a
+<B>0h</B>
+
+prefix (e.g.
+<B>0h01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>
+
+on a big-endian host and
+<B>4.3.2.1</B>
+
+on a little-endian host),
+a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3),
+
+or an old-style network name to be looked up via
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3).
+
+<P>
+
+A dotted-decimal address may be incomplete, in which case
+text-to-binary conversion implicitly appends
+as many instances of
+<B>.0</B>
+
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+<B>10</B>
+
+is synonymous with
+<B>10.0.0.0</B>,
+
+and
+<B>128.009.000.032</B>
+
+is synonymous with
+<B>128.9.0.32</B>
+
+(the latter example is verbatim from RFC 1166).
+The result of applying
+<I>addrtot</I>
+
+to an IPv4 address is always complete and does not contain leading zeros.
+<P>
+
+Use of hexadecimal addresses is
+<B>strongly</B>
+
+<B>discouraged</B>;
+
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+<P>
+
+An IPv6 address is specified in text with
+colon-hex notation (e.g.
+<B>0:56:78ab:22:33:44:55:66</B>),
+
+colon-hex with
+<B>::</B>
+
+abbreviating at most one subsequence of multiple zeros (e.g.
+<B>99:ab::54:068</B>,
+
+which is synonymous with
+<B>99:ab:0:0:0:0:54:68</B>),
+
+or a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3).
+
+The result of applying
+<I>addrtot</I>
+
+to an IPv6 address will use
+<B>::</B>
+
+abbreviation if possible,
+and will not contain leading zeros.
+<P>
+
+The letters in hexadecimal
+may be uppercase or lowercase or any mixture thereof.
+<P>
+
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+<I><A HREF="resolver.5.html">resolver</A></I>(5)).
+
+The
+<I>h_addr</I>
+
+value returned by
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+IPv4 name lookup resorts to
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3)
+
+only if
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+fails.
+<P>
+
+A subnet specification is of the form <I>network</I><B>/</B><I>mask</I>.
+The
+<I>network</I>
+
+and
+<I>mask</I>
+
+can be any form acceptable to
+<I>ttoaddr</I>.
+
+In addition, and preferably, the
+<I>mask</I>
+
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+<B>24</B>
+
+in IPv4 means
+<B>255.255.255.0</B>).
+
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+<B>%default</B>
+
+is a synonym for
+<B>0.0.0.0/0</B>
+
+or
+<B>::/0</B>
+
+in IPv4 or IPv6 respectively.
+<P>
+
+<I>Ttosubnet</I>
+
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+<B>10.1.2.3/24</B>
+
+is synonymous with
+<B>10.1.2.0/24</B>).
+
+<I>Subnettot</I>
+
+always generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the length of the text string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>af</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the address family of interest.
+It should be either
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines constants,
+<B>ADDRTOT_BUF</B>
+
+and
+<B>SUBNETTOT_BUF</B>,
+
+which are the sizes of buffers just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available in
+<I>subnettot</I>.
+
+<I>Addrtot</I>
+
+also accepts format values
+<B>'r'</B>
+
+(signifying a text form suitable for DNS reverse lookups,
+e.g.
+<B>4.3.2.1.IN-ADDR.ARPA.</B>
+
+for IPv4 and
+RFC 2874 format for IPv6),
+and
+<B>'R'</B>
+
+(signifying an alternate reverse-lookup form,
+an error for IPv4 and RFC 1886 format for IPv6).
+Reverse-lookup names always end with a ``.''.
+<P>
+
+The text-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-text functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttoaddr</I>
+
+are:
+empty input;
+unknown address family;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal or colon-hex form;
+dotted-decimal or colon-hex component too large.
+<P>
+
+Fatal errors in
+<I>ttosubnet</I>
+
+are:
+no
+<B>/</B>
+
+in
+<I>src</I>;
+
+<I>ttoaddr</I>
+
+error in conversion of
+<I>network</I>
+
+or
+<I>mask</I>;
+
+bit-count mask too big;
+mask non-contiguous.
+<P>
+
+Fatal errors in
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+<B>10/24</B>
+
+means
+<B>10.0.0.0/24</B>)
+
+differs from that of some older conversion
+functions, e.g. those of
+<I><A HREF="inet.3.html">inet</A></I>(3).
+
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+<P>
+
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+<P>
+
+<I>Ttoaddr</I>
+
+does not support the mixed colon-hex-dotted-decimal
+convention used to embed an IPv4 address in an IPv6 address.
+<P>
+
+<I>Addrtot</I>
+
+always uses the
+<B>::</B>
+
+abbreviation (which can appear only once in an address) for the
+<I>first</I>
+
+sequence of multiple zeros in an IPv6 address.
+One can construct addresses (unlikely ones) in which this is suboptimal.
+<P>
+
+<I>Addrtot</I>
+
+<B>'r'</B>
+
+conversion of an IPv6 address uses lowercase hexadecimal,
+not the uppercase used in RFC 2874's examples.
+It takes careful reading of RFCs 2874, 2673, and 2234 to realize
+that lowercase is technically legitimate here,
+and there may be software which botches this
+and hence would have trouble with lowercase hex.
+<P>
+
+Possibly
+<I>subnettot</I>
+
+ought to recognize the
+<B>%default</B>
+
+case and generate that string as its output.
+Currently it doesn't.
+<P>
+
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+<P>
+
+<I><A HREF="Getnetbyname.3.html">Getnetbyname</A></I>(3)
+
+is a historical dreg.
+<P>
+
+<I>Tnatoaddr</I>
+
+probably should enforce completeness of dotted-decimal addresses.
+<P>
+
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_addrtypeof.3.html b/doc/manpage.d/ipsec_addrtypeof.3.html
new file mode 100644
index 000000000..ca1f857e7
--- /dev/null
+++ b/doc/manpage.d/ipsec_addrtypeof.3.html
@@ -0,0 +1,232 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initaddr - initialize an ip_address
+<BR>
+
+ipsec addrtypeof - get address type of an ip_address
+<BR>
+
+ipsec addrlenof - get length of address within an ip_address
+<BR>
+
+ipsec addrbytesof - get copy of address within an ip_address
+<BR>
+
+ipsec addrbytesptr - get pointer to address within an ip_address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int addrtypeof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrlenof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrbytesof(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>unsigned char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>size_t addrbytesptr(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char **dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_address</I>
+
+to contain one of the (currently two) types of IP address.
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initaddr</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_address</I>
+
+from an address
+(in network byte order,
+indicated by a pointer
+<I>src</I>
+
+and a length
+<I>srclen</I>)
+
+and an address family
+<I>af</I>
+
+(typically
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The length must be consistent with the address family.
+<P>
+
+<I>Addrtypeof</I>
+
+returns the address type of an address,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Addrlenof</I>
+
+returns the size (in bytes) of the address within an
+<I>ip_address</I>,
+
+to permit storage allocation etc.
+<P>
+
+<I>Addrbytesof</I>
+
+copies the address within the
+<I>ip_address</I>
+
+<I>src</I>
+
+to the buffer indicated by the pointer
+<I>dst</I>
+
+and the length
+<I>dstlen</I>,
+
+and returns the address length (in bytes).
+If the address will not fit,
+as many bytes as will fit are copied;
+the returned length is still the full length.
+It is the caller's responsibility to check the
+returned value to ensure that there was enough room.
+<P>
+
+<I>Addrbytesptr</I>
+
+sets
+<I>*dst</I>
+
+to a pointer to the internal address within the
+<I>ip_address</I>,
+
+and returns the address length (in bytes).
+If
+<I>dst</I>
+
+is
+<B>NULL</B>,
+
+it just returns the address length.
+The pointer points to
+<B>const</B>
+
+to discourage misuse.
+<P>
+
+<I>Initaddr</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+The functions which return
+<I>size_t</I>
+
+return
+<B>0</B>
+
+for a failure.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+An unknown address family is a fatal error for any of these functions
+except
+<I>addrtypeof</I>.
+
+An address-size mismatch is a fatal error for
+<I>initaddr</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+<I>Addrtypeof</I>
+
+should probably have been named
+<I>addrfamilyof</I>.
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_anyaddr.3.html b/doc/manpage.d/ipsec_anyaddr.3.html
new file mode 100644
index 000000000..974236005
--- /dev/null
+++ b/doc/manpage.d/ipsec_anyaddr.3.html
@@ -0,0 +1,166 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec anyaddr - get &quot;any&quot; address
+<BR>
+
+ipsec isanyaddr - test address for equality to &quot;any&quot; address
+<BR>
+
+ipsec unspecaddr - get &quot;unspecified&quot; address
+<BR>
+
+ipsec isunspecaddr - test address for equality to &quot;unspecified&quot; address
+<BR>
+
+ipsec loopbackaddr - get loopback address
+<BR>
+
+ipsec isloopbackaddr - test address for equality to loopback address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *anyaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isanyaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *unspecaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isunspecaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *loopbackaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isloopbackaddr(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions fill in, and test for, special values of the
+<I>ip_address</I>
+
+type.
+<P>
+
+<I>Anyaddr</I>
+
+fills in the destination
+<I>*dst</I>
+
+with the ``any'' address of address family
+<I>af</I>
+
+(normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The IPv4 ``any'' address is the one embodied in the old
+<B>INADDR_ANY</B>
+
+macro.
+<P>
+
+<I>Isanyaddr</I>
+
+returns
+<B>1</B>
+
+if the
+<I>src</I>
+
+address equals the ``any'' address,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+Similarly,
+<I>unspecaddr</I>
+
+supplies, and
+<I>isunspecaddr</I>
+
+tests for,
+the ``unspecified'' address,
+which may be the same as the ``any'' address.
+<P>
+
+Similarly,
+<I>loopbackaddr</I>
+
+supplies, and
+<I>islookbackaddr</I>
+
+tests for,
+the loopback address.
+<P>
+
+<I>Anyaddr</I>,
+
+<I>unspecaddr</I>,
+
+and
+<I>loopbackaddr</I>
+
+return
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_addrtot.3.html">ipsec_addrtot</A>(3), <A HREF="ipsec_sameaddr.3.html">ipsec_sameaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in the address-supplying functions are:
+unknown address family.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_atoaddr.3.html b/doc/manpage.d/ipsec_atoaddr.3.html
new file mode 100644
index 000000000..8f0d765e5
--- /dev/null
+++ b/doc/manpage.d/ipsec_atoaddr.3.html
@@ -0,0 +1,448 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atoaddr, addrtoa - convert Internet addresses to and from ASCII
+<BR>
+
+ipsec atosubnet, subnettoa - convert subnet/mask ASCII form to and from addresses
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr *addr);</B>
+
+<BR>
+
+<B>size_t addrtoa(struct in_addr addr, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>const char *atosubnet(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr *addr, struct in_addr *mask);</B>
+
+<BR>
+
+<B>size_t subnettoa(struct in_addr addr, struct in_addr mask,</B>
+
+<BR>
+&nbsp;
+<B>int format, char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Atoaddr</I>
+
+converts an ASCII name or dotted-decimal address into a binary address
+(in network byte order).
+<I>Addrtoa</I>
+
+does the reverse conversion, back to an ASCII dotted-decimal address.
+<I>Atosubnet</I>
+
+and
+<I>subnettoa</I>
+
+do likewise for the ``address/mask'' ASCII form used to write a
+specification of a subnet.
+<P>
+
+An address is specified in ASCII as a
+dotted-decimal address (e.g.
+<B>1.2.3.4</B>),
+
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+<B>0x01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>),
+
+an eight-digit host-order hexadecimal number with a
+<B>0h</B>
+
+prefix (e.g.
+<B>0h01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>
+
+on a big-endian host and
+<B>4.3.2.1</B>
+
+on a little-endian host),
+a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3),
+
+or an old-style network name to be looked up via
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3).
+
+<P>
+
+A dotted-decimal address may be incomplete, in which case
+ASCII-to-binary conversion implicitly appends
+as many instances of
+<B>.0</B>
+
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+<B>10</B>
+
+is synonymous with
+<B>10.0.0.0</B>,
+
+and
+<B>128.009.000.032</B>
+
+is synonymous with
+<B>128.9.0.32</B>
+
+(the latter example is verbatim from RFC 1166).
+The result of
+<I>addrtoa</I>
+
+is always complete and does not contain leading zeros.
+<P>
+
+The letters in
+a hexadecimal address may be uppercase or lowercase or any mixture thereof.
+Use of hexadecimal addresses is
+<B>strongly</B>
+
+<B>discouraged</B>;
+
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+<P>
+
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+<I><A HREF="resolver.5.html">resolver</A></I>(5)).
+
+The
+<I>h_addr</I>
+
+value returned by
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3)
+
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+Name lookup resorts to
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3)
+
+only if
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3)
+
+fails.
+<P>
+
+A subnet specification is of the form <I>network</I><B>/</B><I>mask</I>.
+The
+<I>network</I>
+
+and
+<I>mask</I>
+
+can be any form acceptable to
+<I>atoaddr</I>.
+
+In addition, the
+<I>mask</I>
+
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+<B>24</B>
+
+means
+<B>255.255.255.0</B>).
+
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+<B>%default</B>
+
+is a synonym for
+<B>0.0.0.0/0</B>.
+
+<P>
+
+<I>Atosubnet</I>
+
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+<B>10.1.2.3/24</B>
+
+is synonymous with
+<B>10.1.2.0/24</B>).
+
+<I>Subnettoa</I>
+
+generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros,
+unless the mask is non-contiguous.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atoaddr</I>
+
+and
+<I>atosubnet</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines constants,
+<B>ADDRTOA_BUF</B>
+
+and
+<B>SUBNETTOA_BUF</B>,
+
+which are the sizes of buffers just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+<P>
+
+The ASCII-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-ASCII functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atoaddr</I>
+
+are:
+empty input;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal form;
+dotted-decimal component too large to fit in 8 bits.
+<P>
+
+Fatal errors in
+<I>atosubnet</I>
+
+are:
+no
+<B>/</B>
+
+in
+<I>src</I>;
+
+<I>atoaddr</I>
+
+error in conversion of
+<I>network</I>
+
+or
+<I>mask</I>;
+
+bit-count mask too big;
+mask non-contiguous.
+<P>
+
+Fatal errors in
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+<B>10/24</B>
+
+means
+<B>10.0.0.0/24</B>)
+
+differs from that of some older conversion
+functions, e.g. those of
+<I><A HREF="inet.3.html">inet</A></I>(3).
+
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+<P>
+
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+<P>
+
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+<P>
+
+<I><A HREF="Getnetbyname.3.html">Getnetbyname</A></I>(3)
+
+is a historical dreg.
+<P>
+
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_atoasr.3.html b/doc/manpage.d/ipsec_atoasr.3.html
new file mode 100644
index 000000000..7c9e2c4aa
--- /dev/null
+++ b/doc/manpage.d/ipsec_atoasr.3.html
@@ -0,0 +1,294 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOASR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOASR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atoasr - convert ASCII to Internet address, subnet, or range
+<BR>
+
+ipsec rangetoa - convert Internet address range to ASCII
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atoasr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>char *type, struct in_addr *addrs);</B>
+
+<BR>
+
+<B>size_t rangetoa(struct in_addr *addrs, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete;
+there is no current equivalent,
+because so far they have not proved useful.
+<P>
+
+<I>Atoasr</I>
+
+converts an ASCII address, subnet, or address range
+into a suitable combination of binary addresses
+(in network byte order).
+<I>Rangetoa</I>
+
+converts an address range back into ASCII,
+using dotted-decimal form for the addresses
+(the other reverse conversions are handled by
+<I><A HREF="ipsec_addrtoa.3.html">ipsec_addrtoa</A></I>(3)
+
+and
+<I><A HREF="ipsec_subnettoa.3.html">ipsec_subnettoa</A></I>(3)).
+
+<P>
+
+A single address can be any form acceptable to
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3):
+
+dotted decimal, DNS name, or hexadecimal number.
+A subnet
+specification uses the form <I>network</I><B>/</B><I>mask</I>
+interpreted by
+<I><A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A></I>(3).
+
+<P>
+
+An address range is two
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3)
+
+addresses separated by a
+<B>...</B>
+
+delimiter.
+If there are four dots rather than three, the first is taken as
+part of the begin address,
+e.g. for a complete DNS name which ends with
+<B>.</B>
+
+to suppress completion attempts.
+The begin address of a range must be
+less than or equal to the end address.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atoasr</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>type</I>
+
+parameter of
+<I>atoasr</I>
+
+must point to a
+<B>char</B>
+
+variable used to record which form was found.
+The
+<I>addrs</I>
+
+parameter must point to a two-element array of
+<B>struct in_addr</B>
+
+which receives the results.
+The values stored into
+<B>*type</B>,
+
+and the corresponding values in the array, are:
+<P>
+
+
+
+<TT>&nbsp;&nbsp;&nbsp;</TT>*typeaddrs[0]addrs[1]<BR>
+<P>
+address<B>'a'</B>address-<BR>
+<BR>
+
+subnet<TT>&nbsp;</TT><B>'s'</B>networkmask<BR>
+<BR>
+
+range<TT>&nbsp;&nbsp;</TT><B>'r'</B>beginend<BR>
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>rangetoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines a constant,
+<B>RANGETOA_BUF</B>,
+
+which is the size of a buffer just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>rangetoa</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+<P>
+
+<I>Atoasr</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Rangetoa</I>
+
+returns
+<B>0</B>
+
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A>(3), <A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atoasr</I>
+
+are:
+empty input;
+error in
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3)
+
+or
+<I><A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A></I>(3)
+
+during conversion;
+begin address of range exceeds end address.
+<P>
+
+Fatal errors in
+<I>rangetoa</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoasr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_atosa.3.html b/doc/manpage.d/ipsec_atosa.3.html
new file mode 100644
index 000000000..9e2dc2f61
--- /dev/null
+++ b/doc/manpage.d/ipsec_atosa.3.html
@@ -0,0 +1,347 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOSA</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOSA</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atosa, satoa - convert IPsec Security Association IDs to and from ASCII
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atosa(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct sa_id *sa);</B>
+
+<BR>
+
+<B>size_t satoa(struct sa_id sa, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>struct sa_id {</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr dst;</B>
+
+<BR>
+&nbsp;
+<B>ipsec_spi_t spi;</B>
+
+<BR>
+&nbsp;
+<B>int proto;</B>
+
+<BR>
+
+<B>};</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_ttosa.3.html">ipsec_ttosa</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Atosa</I>
+
+converts an ASCII Security Association (SA) specifier into an
+<B>sa_id</B>
+
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+<I>Satoa</I>
+
+does the reverse conversion, back to an ASCII SA specifier.
+<P>
+
+An SA is specified in ASCII with a mail-like syntax, e.g.
+<B><A HREF="mailto:esp507@1.2.3.4">esp507@1.2.3.4</A></B>.
+
+An SA specifier contains
+a protocol prefix (currently
+<B>ah</B>,
+
+<B>esp</B>,
+
+or
+<B>tun</B>),
+
+an unsigned integer SPI number,
+and an IP address.
+The SPI number can be decimal or hexadecimal
+(with
+<B>0x</B>
+
+prefix), as accepted by
+<I><A HREF="ipsec_atoul.3.html">ipsec_atoul</A></I>(3).
+
+The IP address can be any form accepted by
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3),
+
+e.g. dotted-decimal address or DNS name.
+<P>
+
+As a special case, the SA specifier
+<B>%passthrough</B>
+
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, this is a synonym for
+<B><A HREF="mailto:tun0x0@0.0.0.0">tun0x0@0.0.0.0</A></B>,
+
+but that is subject to change without notice.)
+This form is known to both
+<I>atosa</I>
+
+and
+<I>satoa</I>,
+
+so the internal form of
+<B>%passthrough</B>
+
+is never visible.
+<P>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file supplies the
+<B>sa_id</B>
+
+structure, as well as a data type
+<B>ipsec_spi_t</B>
+
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+<P>
+
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+defines the names
+<B>SA_ESP</B>,
+
+<B>SA_AH</B>,
+
+and
+<B>SA_IPIP</B>
+
+to have the same values as the kernel names
+<B>IPPROTO_ESP</B>,
+
+<B>IPPROTO_AH</B>,
+
+and
+<B>IPPROTO_IPIP</B>.
+
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atosa</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>satoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines a constant,
+<B>SATOA_BUF</B>,
+
+which is the size of a buffer just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>satoa</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI, dotted-decimal address).
+The value
+<B>d</B>
+
+causes the SPI to be generated in decimal instead.
+<P>
+
+<I>Atosa</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Satoa</I>
+
+returns
+<B>0</B>
+
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_atoul.3.html">ipsec_atoul</A>(3), <A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A>(3), <A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atosa</I>
+
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+<B>@</B>
+
+in input;
+unknown protocol prefix;
+conversion error in
+<I>atoul</I>
+
+or
+<I>atoaddr</I>.
+
+<P>
+
+Fatal errors in
+<I>satoa</I>
+
+are:
+unknown format; unknown protocol code.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The
+<B>tun</B>
+
+protocol code is a FreeS/WANism which may eventually disappear.
+<P>
+
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_atosubnet.3.html b/doc/manpage.d/ipsec_atosubnet.3.html
new file mode 100644
index 000000000..8f0d765e5
--- /dev/null
+++ b/doc/manpage.d/ipsec_atosubnet.3.html
@@ -0,0 +1,448 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atoaddr, addrtoa - convert Internet addresses to and from ASCII
+<BR>
+
+ipsec atosubnet, subnettoa - convert subnet/mask ASCII form to and from addresses
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr *addr);</B>
+
+<BR>
+
+<B>size_t addrtoa(struct in_addr addr, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>const char *atosubnet(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr *addr, struct in_addr *mask);</B>
+
+<BR>
+
+<B>size_t subnettoa(struct in_addr addr, struct in_addr mask,</B>
+
+<BR>
+&nbsp;
+<B>int format, char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Atoaddr</I>
+
+converts an ASCII name or dotted-decimal address into a binary address
+(in network byte order).
+<I>Addrtoa</I>
+
+does the reverse conversion, back to an ASCII dotted-decimal address.
+<I>Atosubnet</I>
+
+and
+<I>subnettoa</I>
+
+do likewise for the ``address/mask'' ASCII form used to write a
+specification of a subnet.
+<P>
+
+An address is specified in ASCII as a
+dotted-decimal address (e.g.
+<B>1.2.3.4</B>),
+
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+<B>0x01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>),
+
+an eight-digit host-order hexadecimal number with a
+<B>0h</B>
+
+prefix (e.g.
+<B>0h01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>
+
+on a big-endian host and
+<B>4.3.2.1</B>
+
+on a little-endian host),
+a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3),
+
+or an old-style network name to be looked up via
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3).
+
+<P>
+
+A dotted-decimal address may be incomplete, in which case
+ASCII-to-binary conversion implicitly appends
+as many instances of
+<B>.0</B>
+
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+<B>10</B>
+
+is synonymous with
+<B>10.0.0.0</B>,
+
+and
+<B>128.009.000.032</B>
+
+is synonymous with
+<B>128.9.0.32</B>
+
+(the latter example is verbatim from RFC 1166).
+The result of
+<I>addrtoa</I>
+
+is always complete and does not contain leading zeros.
+<P>
+
+The letters in
+a hexadecimal address may be uppercase or lowercase or any mixture thereof.
+Use of hexadecimal addresses is
+<B>strongly</B>
+
+<B>discouraged</B>;
+
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+<P>
+
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+<I><A HREF="resolver.5.html">resolver</A></I>(5)).
+
+The
+<I>h_addr</I>
+
+value returned by
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3)
+
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+Name lookup resorts to
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3)
+
+only if
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3)
+
+fails.
+<P>
+
+A subnet specification is of the form <I>network</I><B>/</B><I>mask</I>.
+The
+<I>network</I>
+
+and
+<I>mask</I>
+
+can be any form acceptable to
+<I>atoaddr</I>.
+
+In addition, the
+<I>mask</I>
+
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+<B>24</B>
+
+means
+<B>255.255.255.0</B>).
+
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+<B>%default</B>
+
+is a synonym for
+<B>0.0.0.0/0</B>.
+
+<P>
+
+<I>Atosubnet</I>
+
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+<B>10.1.2.3/24</B>
+
+is synonymous with
+<B>10.1.2.0/24</B>).
+
+<I>Subnettoa</I>
+
+generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros,
+unless the mask is non-contiguous.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atoaddr</I>
+
+and
+<I>atosubnet</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines constants,
+<B>ADDRTOA_BUF</B>
+
+and
+<B>SUBNETTOA_BUF</B>,
+
+which are the sizes of buffers just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+<P>
+
+The ASCII-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-ASCII functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atoaddr</I>
+
+are:
+empty input;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal form;
+dotted-decimal component too large to fit in 8 bits.
+<P>
+
+Fatal errors in
+<I>atosubnet</I>
+
+are:
+no
+<B>/</B>
+
+in
+<I>src</I>;
+
+<I>atoaddr</I>
+
+error in conversion of
+<I>network</I>
+
+or
+<I>mask</I>;
+
+bit-count mask too big;
+mask non-contiguous.
+<P>
+
+Fatal errors in
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+<B>10/24</B>
+
+means
+<B>10.0.0.0/24</B>)
+
+differs from that of some older conversion
+functions, e.g. those of
+<I><A HREF="inet.3.html">inet</A></I>(3).
+
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+<P>
+
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+<P>
+
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+<P>
+
+<I><A HREF="Getnetbyname.3.html">Getnetbyname</A></I>(3)
+
+is a historical dreg.
+<P>
+
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_atoul.3.html b/doc/manpage.d/ipsec_atoul.3.html
new file mode 100644
index 000000000..923a16131
--- /dev/null
+++ b/doc/manpage.d/ipsec_atoul.3.html
@@ -0,0 +1,266 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOUL</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOUL</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atoul, ultoa - convert unsigned-long numbers to and from ASCII
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atoul(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int base, unsigned long *n);</B>
+
+<BR>
+
+<B>size_t ultoa(unsigned long n, int base, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_ttoul.3.html">ipsec_ttoul</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Atoul</I>
+
+converts an ASCII number into a binary
+<B>unsigned long</B>
+
+value.
+<I>Ultoa</I>
+
+does the reverse conversion, back to an ASCII version.
+<P>
+
+Numbers are specified in ASCII as
+decimal (e.g.
+<B>123</B>),
+
+octal with a leading zero (e.g.
+<B>012</B>,
+
+which has value 10),
+or hexadecimal with a leading
+<B>0x</B>
+
+(e.g.
+<B>0x1f</B>,
+
+which has value 31)
+in either upper or lower case.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atoul</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>base</I>
+
+parameter of
+<I>atoul</I>
+
+can be
+<B>8</B>,
+
+<B>10</B>,
+
+or
+<B>16</B>,
+
+in which case the number supplied is assumed to be of that form
+(and in the case of
+<B>16</B>,
+
+to lack any
+<B>0x</B>
+
+prefix).
+It can also be
+<B>0</B>,
+
+in which case the number is examined for a leading zero
+or a leading
+<B>0x</B>
+
+to determine its base,
+or
+<B>13</B>
+
+(halfway between 10 and 16),
+which has the same effect as
+<B>0</B>
+
+except that a non-hexadecimal
+number is considered decimal regardless of any leading zero.
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>ultoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+<P>
+
+The
+<I>base</I>
+
+parameter of
+<I>ultoa</I>
+
+must be
+<B>8</B>,
+
+<B>10</B>,
+
+or
+<B>16</B>.
+
+<P>
+
+<I>Atoul</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Ultoa</I>
+
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="atol.3.html">atol</A>(3), <A HREF="strtoul.3.html">strtoul</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atoul</I>
+
+are:
+empty input;
+unknown
+<I>base</I>;
+
+non-digit character found;
+number too large for an
+<B>unsigned long</B>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+There is no provision for reporting an invalid
+<I>base</I>
+
+parameter given to
+<I>ultoa</I>.
+
+<P>
+
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoul( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_auto.8.html b/doc/manpage.d/ipsec_auto.8.html
new file mode 100644
index 000000000..68ca61bdc
--- /dev/null
+++ b/doc/manpage.d/ipsec_auto.8.html
@@ -0,0 +1,416 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_AUTO</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_AUTO</H1>
+Section: Maintenance Commands (8)<BR>Updated: 31 Jan 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec auto - control automatically-keyed IPsec connections
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>auto</B>
+
+[
+<B>--show</B>
+
+] [
+<B>--showonly</B>
+
+] [
+<B>--asynchronous</B>
+
+]
+<BR>
+
+&nbsp;&nbsp;&nbsp;[
+<B>--config</B>
+
+configfile
+] [
+<B>--verbose</B>
+
+]
+<BR>
+
+&nbsp;&nbsp;&nbsp;operation
+connection
+<P>
+<B>ipsec</B>
+
+<B>auto</B>
+
+[
+<B>--show</B>
+
+] [
+<B>--showonly</B>
+
+] operation
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Auto</I>
+
+manipulates automatically-keyed FreeS/WAN IPsec connections,
+setting them up and shutting them down
+based on the information in the IPsec configuration file.
+In the normal usage,
+<I>connection</I>
+
+is the name of a connection specification in the configuration file;
+<I>operation</I>
+
+is
+<B>--add</B>,
+
+<B>--delete</B>,
+
+<B>--replace</B>,
+
+<B>--up</B>,
+
+<B>--down</B>,
+
+<B>--route</B>,
+
+or
+<B>--unroute</B>.
+
+The
+<B>--ready</B>,
+
+<B>--rereadsecrets</B>,
+
+<B>--rereadgroups</B>,
+
+and
+<B>--status</B>
+
+<I>operations</I>
+
+do not take a connection name.
+<I>Auto</I>
+
+generates suitable
+commands and feeds them to a shell for execution.
+<P>
+
+The
+<B>--add</B>
+
+operation adds a connection specification to the internal database
+within
+<I>pluto</I>;
+
+it will fail if
+<I>pluto</I>
+
+already has a specification by that name.
+The
+<B>--delete</B>
+
+operation deletes a connection specification from
+<I>pluto</I>'s
+
+internal database (also tearing down any connections based on it);
+it will fail if the specification does not exist.
+The
+<B>--replace</B>
+
+operation is equivalent to
+<B>--delete</B>
+
+(if there is already a specification by the given name)
+followed by
+<B>--add</B>,
+
+and is a convenience for updating
+<I>pluto</I>'s
+
+internal specification to match an external one.
+(Note that a
+<B>--rereadsecrets</B>
+
+may also be needed.)
+The
+<B>--rereadgroups</B>
+
+operation causes any changes to the policy group files to take effect
+(this is currently a synonym for
+<B>--ready</B>,
+
+but that may change).
+None of the other operations alters the internal database.
+<P>
+
+The
+<B>--up</B>
+
+operation asks
+<I>pluto</I>
+
+to establish a connection based on an entry in its internal database.
+The
+<B>--down</B>
+
+operation tells
+<I>pluto</I>
+
+to tear down such a connection.
+<P>
+
+Normally,
+<I>pluto</I>
+
+establishes a route to the destination specified for a connection as
+part of the
+<B>--up</B>
+
+operation.
+However, the route and only the route can be established with the
+<B>--route</B>
+
+operation.
+Until and unless an actual connection is established,
+this discards any packets sent there,
+which may be preferable to having them sent elsewhere based on a more
+general route (e.g., a default route).
+<P>
+
+Normally,
+<I>pluto</I>'s
+
+route to a destination remains in place when a
+<B>--down</B>
+
+operation is used to take the connection down
+(or if connection setup, or later automatic rekeying, fails).
+This permits establishing a new connection (perhaps using a
+different specification; the route is altered as necessary)
+without having a ``window'' in which packets might go elsewhere
+based on a more general route.
+Such a route can be removed using the
+<B>--unroute</B>
+
+operation
+(and is implicitly removed by
+<B>--delete</B>).
+
+<P>
+
+The
+<B>--ready</B>
+
+operation tells
+<I>pluto</I>
+
+to listen for connection-setup requests from other hosts.
+Doing an
+<B>--up</B>
+
+operation before doing
+<B>--ready</B>
+
+on both ends is futile and will not work,
+although this is now automated as part of IPsec startup and
+should not normally be an issue.
+<P>
+
+The
+<B>--status</B>
+
+operation asks
+<I>pluto</I>
+
+for current connection status.
+The output format is ad-hoc and likely to change.
+<P>
+
+The
+<B>--rereadsecrets</B>
+
+operation tells
+<I>pluto</I>
+
+to re-read the
+<I>/etc/ipsec.secrets</I>
+
+secret-keys file,
+which it normally reads only at startup time.
+(This is currently a synonym for
+<B>--ready</B>,
+
+but that may change.)
+<P>
+
+The
+<B>--show</B>
+
+option turns on the
+<B>-x</B>
+
+option of the shell used to execute the commands,
+so each command is shown as it is executed.
+<P>
+
+The
+<B>--showonly</B>
+
+option causes
+<I>auto</I>
+
+to show the commands it would run, on standard output,
+and not run them.
+<P>
+
+The
+<B>--asynchronous</B>
+
+option, applicable only to the
+<B>up</B>
+
+operation,
+tells
+<I>pluto</I>
+
+to attempt to establish the connection,
+but does not delay to report results.
+This is especially useful to start multiple connections in parallel
+when network links are slow.
+<P>
+
+The
+<B>--verbose</B>
+
+option instructs
+<I>auto</I>
+
+to pass through all output from
+<I><A HREF="ipsec_whack.8.html">ipsec_whack</A></I>(8),
+
+including log output that is normally filtered out as uninteresting.
+<P>
+
+The
+<B>--config</B>
+
+option specifies a non-standard location for the IPsec
+configuration file (default
+<I>/etc/ipsec.conf</I>).
+
+<P>
+
+See
+<I><A HREF="ipsec.conf.5.html">ipsec.conf</A></I>(5)
+
+for details of the configuration file.
+Apart from the basic parameters which specify the endpoints and routing
+of a connection (<B>left</B>
+and
+<B>right</B>,
+
+plus possibly
+<B>leftsubnet</B>,
+
+<B>leftnexthop</B>,
+
+<B>leftfirewall</B>,
+
+their
+<B>right</B>
+
+equivalents,
+and perhaps
+<B>type</B>),
+
+an
+<I>auto</I>
+
+connection almost certainly needs a
+<B>keyingtries</B>
+
+parameter (since the
+<B>keyingtries</B>
+
+default is poorly chosen).
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+
+
+/etc/ipsec.conf<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>default IPSEC configuration file<BR>
+<BR>
+
+/var/run/ipsec.info<TT>&nbsp;&nbsp;&nbsp;</TT><B>%defaultroute</B> information<BR>
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.conf.5.html">ipsec.conf</A>(5), <A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_pluto.8.html">ipsec_pluto</A>(8), <A HREF="ipsec_whack.8.html">ipsec_whack</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+Although an
+<B>--up</B>
+
+operation does connection setup on both ends,
+<B>--down</B>
+
+tears only one end of the connection down
+(although the orphaned end will eventually time out).
+<P>
+
+There is no support for
+<B>passthrough</B>
+
+connections.
+<P>
+
+A connection description which uses
+<B>%defaultroute</B>
+
+for one of its
+<B>nexthop</B>
+
+parameters but not the other may be falsely
+rejected as erroneous in some circumstances.
+<P>
+
+The exit status of
+<B>--showonly</B>
+
+does not always reflect errors discovered during processing of the request.
+(This is fine for human inspection, but not so good for use in scripts.)
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_barf.8.html b/doc/manpage.d/ipsec_barf.8.html
new file mode 100644
index 000000000..e7b7200e0
--- /dev/null
+++ b/doc/manpage.d/ipsec_barf.8.html
@@ -0,0 +1,150 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_BARF</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_BARF</H1>
+Section: Maintenance Commands (8)<BR>Updated: 17 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec barf - spew out collected IPsec debugging information
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>barf</B>
+
+[
+<B>--short</B>
+
+]
+<P>
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Barf</I>
+
+outputs (on standard output) a collection of debugging information
+(contents of files, selections from logs, etc.)
+related to the IPsec encryption/authentication system.
+It is primarily a convenience for remote debugging,
+a single command which packages up (and labels) all information
+that might be relevant to diagnosing a problem in IPsec.
+<P>
+
+<P>
+
+The
+<B>--short</B>
+
+option limits the length of
+the log portion of
+<I>barf</I>'s
+
+output, which can otherwise be extremely voluminous
+if debug logging is turned on.
+<P>
+
+<I>Barf</I>
+
+censors its output,
+replacing keys
+and secrets with brief checksums to avoid revealing sensitive information.
+<P>
+
+Beware that the output of both commands is aimed at humans,
+not programs,
+and the output format is subject to change without warning.
+<P>
+
+<I>Barf</I>
+
+has to figure out which files in
+<I>/var/log</I>
+
+contain the IPsec log messages.
+It looks for KLIPS and general log messages first in
+<I>messages</I>
+
+and
+<I>syslog</I>,
+
+and for Pluto messages first in
+<I>secure</I>,
+
+<I>auth.log</I>,
+
+and
+<I>debug</I>.
+
+In both cases,
+if it does not find what it is looking for in one of those ``likely'' places,
+it will resort to a brute-force search of most (non-compressed) files in
+<I>/var/log</I>.
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+<PRE>
+/proc/net/*
+/var/log/*
+/etc/ipsec.conf
+/etc/ipsec.secrets
+</PRE>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+<I>Barf</I>
+
+uses heuristics to try to pick relevant material out of the logs,
+and relevant messages
+which are not labelled with any of the tags that
+<I>barf</I>
+
+looks for will be lost.
+We think we've eliminated the last such case, but one never knows...
+<P>
+
+Finding
+<I>updown</I>
+
+scripts (so they can be included in output) is, in general, difficult.
+<I>Barf</I>
+
+uses a very simple heuristic that is easily fooled.
+<P>
+
+The brute-force search for the right log files can get expensive on
+systems with a lot of clutter in
+<I>/var/log</I>.
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_bitstomask.3.html b/doc/manpage.d/ipsec_bitstomask.3.html
new file mode 100644
index 000000000..a67a08d83
--- /dev/null
+++ b/doc/manpage.d/ipsec_bitstomask.3.html
@@ -0,0 +1,122 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_GOODMASK</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_GOODMASK</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec goodmask - is this Internet subnet mask a valid one?
+<BR>
+
+ipsec masktobits - convert Internet subnet mask to bit count
+<BR>
+
+ipsec bitstomask - convert bit count to Internet subnet mask
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int goodmask(struct in_addr mask);</B>
+
+<BR>
+
+<B>int masktobits(struct in_addr mask);</B>
+
+<BR>
+
+<B>struct in_addr bitstomask(int n);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete;
+see
+<I><A HREF="ipsec_masktocount.3.html">ipsec_masktocount</A></I>(3)
+
+for a partial replacement.
+<P>
+
+<I>Goodmask</I>
+
+reports whether the subnet
+<I>mask</I>
+
+is a valid one,
+i.e. consists of a (possibly empty) sequence of
+<B>1</B>s
+
+followed by a (possibly empty) sequence of
+<B>0</B>s.
+
+<I>Masktobits</I>
+
+takes a (valid) subnet mask and returns the number of
+<B>1</B>
+
+bits in it.
+<I>Bitstomask</I>
+
+reverses this,
+returning the subnet mask corresponding to bit count
+<I>n</I>.
+
+<P>
+
+All masks are in network byte order.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+<I>Masktobits</I>
+
+returns
+<B>-1</B>
+
+for an invalid mask.
+<I>Bitstomask</I>
+
+returns an all-zeros mask for a negative or out-of-range
+<I>n</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The error-reporting convention of
+<I>bitstomask</I>
+
+is less than ideal;
+zero is sometimes a legitimate mask.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_broadcastof.3.html b/doc/manpage.d/ipsec_broadcastof.3.html
new file mode 100644
index 000000000..57d4a5648
--- /dev/null
+++ b/doc/manpage.d/ipsec_broadcastof.3.html
@@ -0,0 +1,107 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SUBNETOF</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SUBNETOF</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec subnetof - given Internet address and subnet mask, return subnet number
+<BR>
+
+ipsec hostof - given Internet address and subnet mask, return host part
+<BR>
+
+ipsec broadcastof - given Internet address and subnet mask, return broadcast address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>struct in_addr subnetof(struct in_addr addr,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr mask);</B>
+
+<BR>
+
+<B>struct in_addr hostof(struct in_addr addr,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr mask);</B>
+
+<BR>
+
+<B>struct in_addr broadcastof(struct in_addr addr,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr mask);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_networkof.3.html">ipsec_networkof</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Subnetof</I>
+
+takes an Internet
+<I>address</I>
+
+and a subnet
+<I>mask</I>
+
+and returns the network part of the address
+(all in network byte order).
+<I>Hostof</I>
+
+similarly returns the host part, and
+<I>broadcastof</I>
+
+returns the broadcast address (all-1s convention) for the network.
+<P>
+
+These functions are provided to hide the Internet bit-munging inside
+an API, in hopes of easing the eventual transition to IPv6.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+Calling functions for this is more costly than doing it yourself.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_calcgoo.8.html b/doc/manpage.d/ipsec_calcgoo.8.html
new file mode 100644
index 000000000..8379ac6a4
--- /dev/null
+++ b/doc/manpage.d/ipsec_calcgoo.8.html
@@ -0,0 +1,78 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_CALCGOO</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_CALCGOO</H1>
+Section: Maintenance Commands (8)<BR>Updated: 8 June 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec calcgoo - calculate hex value for matching modules and kernels
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>calcgoo</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>calcgoo</I>
+
+accepts the output of
+<B>nm -ao</B>
+
+or
+<B>/proc/ksyms</B>
+
+and extracts a release dependant list of symbols from it. The symbols
+are processed to extract the values assigned during the MODVERSIONS
+process. This process makes sure that Linux modules are only loaded
+on matching kernels.
+
+This routine is used to find an appropriate module to match the currently
+running kernel by _startklips.
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+<PRE>
+/proc/ksyms
+</PRE>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec__startklips.8.html">ipsec__startklips</A>(8), <A HREF="genksyms.8.html">genksyms</A>(8)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Michael Richardson.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_copyright_notice.3.html b/doc/manpage.d/ipsec_copyright_notice.3.html
new file mode 100644
index 000000000..c832e01f7
--- /dev/null
+++ b/doc/manpage.d/ipsec_copyright_notice.3.html
@@ -0,0 +1,94 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_VERSION</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_VERSION</H1>
+Section: C Library Functions (3)<BR>Updated: 21 Nov 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ipsec_version_code - get IPsec version code
+<BR>
+
+ipsec ipsec_version_string - get full IPsec version string
+<BR>
+
+ipsec ipsec_copyright_notice - get IPsec copyright notice
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ipsec_version_code(void);</B>
+
+<BR>
+
+<B>const char *ipsec_version_string(void);</B>
+
+<BR>
+
+<B>const char **ipsec_copyright_notice(void);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions provide information on version numbering and copyright
+of the Linux FreeS/WAN IPsec implementation.
+<P>
+
+<I>Ipsec_version_code</I>
+
+returns a pointer to a string constant
+containing the current IPsec version code,
+such as ``1.92'' or ``snap2001Nov19b''.
+<P>
+
+<I>Ipsec_version_string</I>
+
+returns a pointer to a string constant giving a full version identification,
+consisting of the version code preceded by a prefix identifying the software,
+e.g. ``Linux FreeS/WAN 1.92''.
+<P>
+
+<I>Ipsec_copyright_notice</I>
+
+returns a pointer to a vector of pointers,
+terminated by a
+<B>NULL</B>,
+
+which is the text of a suitable copyright notice.
+Each pointer points to a string constant (possibly empty) which is one line
+of the somewhat-verbose copyright notice.
+The strings are NUL-terminated and do not contain a newline;
+supplying suitable line termination for the output device is
+the caller's responsibility.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_datatot.3.html b/doc/manpage.d/ipsec_datatot.3.html
new file mode 100644
index 000000000..628558001
--- /dev/null
+++ b/doc/manpage.d/ipsec_datatot.3.html
@@ -0,0 +1,439 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTODATA</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTODATA</H1>
+Section: C Library Functions (3)<BR>Updated: 16 August 2003<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttodata, datatot - convert binary data bytes from and to text formats
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ttodata(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int base, char *dst, size_t dstlen, size_t *lenp);</B>
+
+<BR>
+
+<B>const char *ttodatav(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int base, char *dst, size_t dstlen, size_t *lenp,</B>
+
+<BR>
+&nbsp;
+<B>char *errp, size_t errlen, int flags);</B>
+
+<BR>
+
+<B>size_t datatot(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int format, char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttodata</I>,
+
+<I>ttodatav</I>,
+
+and
+<I>datatot</I>
+
+convert arbitrary binary data (e.g. encryption or authentication keys)
+from and to more-or-less human-readable text formats.
+<P>
+
+Currently supported formats are hexadecimal, base64, and characters.
+<P>
+
+A hexadecimal text value begins with a
+<B>0x</B>
+
+(or
+<B>0X</B>)
+
+prefix and continues with two-digit groups
+of hexadecimal digits (0-9, and a-f or A-F),
+each group encoding the value of one binary byte, high-order digit first.
+A single
+<B>_</B>
+
+(underscore)
+between consecutive groups is ignored, permitting punctuation to improve
+readability; doing this every eight digits seems about right.
+<P>
+
+A base64 text value begins with a
+<B>0s</B>
+
+(or
+<B>0S</B>)
+
+prefix
+and continues with four-digit groups of base64 digits (A-Z, a-z, 0-9, +, and /),
+each group encoding the value of three binary bytes as described in
+section 6.8 of RFC 2045.
+If
+<B>flags</B>
+
+has the
+<B>TTODATAV_IGNORESPACE</B>
+
+bit on, blanks are ignore (after the prefix).
+Note that the last one or two digits of a base64 group can be
+<B>=</B>
+
+to indicate that fewer than three binary bytes are encoded.
+<P>
+
+A character text value begins with a
+<B>0t</B>
+
+(or
+<B>0T</B>)
+
+prefix
+and continues with text characters, each being the value of one binary byte.
+<P>
+
+All these functions basically copy data from
+<I>src</I>
+
+(whose size is specified by
+<I>srclen</I>)
+
+to
+<I>dst</I>
+
+(whose size is specified by
+<I>dstlen</I>),
+
+doing the conversion en route.
+If the result will not fit in
+<I>dst</I>,
+
+it is truncated;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes of result written to
+<I>dst</I>.
+
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result bytes are written at all.
+<P>
+
+The
+<I>base</I>
+
+parameter of
+<I>ttodata</I>
+
+and
+<I>ttodatav</I>
+
+specifies what format the input is in;
+normally it should be
+<B>0</B>
+
+to signify that this gets figured out from the prefix.
+Values of
+<B>16</B>,
+
+<B>64</B>,
+
+and
+<B>256</B>
+
+respectively signify hexadecimal, base64, and character-text formats
+without prefixes.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>datatot</I>,
+
+a single character used as a type code,
+specifies which text format is wanted.
+The value
+<B>0</B>
+
+(not ASCII
+<B>'0'</B>,
+
+but a zero value) specifies a reasonable default.
+Other currently-supported values are:
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT><B>'x'</B>
+
+<DD>
+continuous lower-case hexadecimal with a
+<B>0x</B>
+
+prefix
+<DT><B>'h'</B>
+
+<DD>
+lower-case hexadecimal with a
+<B>0x</B>
+
+prefix and a
+<B>_</B>
+
+every eight digits
+<DT><B>':'</B>
+
+<DD>
+lower-case hexadecimal with no prefix and a
+<B>:</B>
+
+(colon) every two digits
+<DT><B>16</B>
+
+<DD>
+lower-case hexadecimal with no prefix or
+<B>_</B>
+
+<DT><B>'s'</B>
+
+<DD>
+continuous base64 with a
+<B>0s</B>
+
+prefix
+<DT><B>64</B>
+
+<DD>
+continuous base64 with no prefix
+</DL>
+</DL>
+
+<P>
+
+The default format is currently
+<B>'h'</B>.
+
+<P>
+
+<I>Ttodata</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+On success,
+if and only if
+<I>lenp</I>
+
+is non-NULL,
+<B>*lenp</B>
+
+is set to the number of bytes required to contain the full untruncated result.
+It is the caller's responsibility to check this against
+<I>dstlen</I>
+
+to determine whether he has obtained a complete result.
+The
+<B>*lenp</B>
+
+value is correct even if
+<I>dstlen</I>
+
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+<P>
+
+<I>Ttodatav</I>
+
+is just like
+<I>ttodata</I>
+
+except that in certain cases,
+if
+<I>errp</I>
+
+is non-NULL,
+the buffer pointed to by
+<I>errp</I>
+
+(whose length is given by
+<I>errlen</I>)
+
+is used to hold a more detailed error message.
+The return value is NULL for success,
+and is either
+<I>errp</I>
+
+or a pointer to a string literal for failure.
+If the size of the error-message buffer is
+inadequate for the desired message,
+<I>ttodatav</I>
+
+will fall back on returning a pointer to a literal string instead.
+The
+<I>freeswan.h</I>
+
+header file defines a constant
+<B>TTODATAV_BUF</B>
+
+which is the size of a buffer large enough for worst-case results.
+<P>
+
+The normal return value of
+<I>datatot</I>
+
+is the number of bytes required
+to contain the full untruncated result.
+It is the caller's responsibility to check this against
+<I>dstlen</I>
+
+to determine whether he has obtained a complete result.
+The return value is correct even if
+<I>dstlen</I>
+
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+A return value of
+<B>0</B>
+
+signals a fatal error of some kind
+(see DIAGNOSTICS).
+<P>
+
+A zero value for
+<I>srclen</I>
+
+in
+<I>ttodata</I>
+
+(but not
+<I>datatot</I>!)
+
+is synonymous with
+<B>strlen(src)</B>.
+
+A non-zero
+<I>srclen</I>
+
+in
+<I>ttodata</I>
+
+must not include the terminating NUL.
+<P>
+
+Unless
+<I>dstlen</I>
+
+is zero,
+the result supplied by
+<I>datatot</I>
+
+is always NUL-terminated,
+and its needed-size return value includes space for the terminating NUL.
+<P>
+
+Several obsolete variants of these functions
+(<I>atodata</I>,
+
+<I>datatoa</I>,
+
+<I>atobytes</I>,
+
+and
+<I>bytestoa</I>)
+
+are temporarily also supported.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="sprintf.3.html">sprintf</A>(3), <A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttodata</I>
+
+and
+<I>ttodatav</I>
+
+are:
+unknown characters in the input;
+unknown or missing prefix;
+unknown base;
+incomplete digit group;
+non-zero padding in a base64 less-than-three-bytes digit group;
+zero-length input.
+<P>
+
+Fatal errors in
+<I>datatot</I>
+
+are:
+unknown format code;
+zero-length input.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+<I>Datatot</I>
+
+should have a format code to produce character-text output.
+<P>
+
+The
+<B>0s</B>
+
+and
+<B>0t</B>
+
+prefixes are the author's inventions and are not a standard
+of any kind.
+They have been chosen to avoid collisions with existing practice
+(some C implementations use
+<B>0b</B>
+
+for binary)
+and possible confusion with unprefixed hexadecimal.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_eroute.5.html b/doc/manpage.d/ipsec_eroute.5.html
new file mode 100644
index 000000000..158b57015
--- /dev/null
+++ b/doc/manpage.d/ipsec_eroute.5.html
@@ -0,0 +1,370 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_EROUTE</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_EROUTE</H1>
+Section: File Formats (5)<BR>Updated: 20 Sep 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec_eroute - list of existing eroutes
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>eroute</B>
+
+<P>
+
+<B>cat</B>
+
+<B>/proc/net/ipsec_eroute</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>/proc/net/ipsec_eroute</I>
+
+lists the IPSEC extended routing tables,
+which control what (if any) processing is applied
+to non-encrypted packets arriving for IPSEC processing and forwarding.
+At this point it is a read-only file.
+<P>
+
+A table entry consists of:
+<DL COMPACT>
+<DT>+<DD>
+packet count,
+<DT>+<DD>
+source address with mask,
+<DT>+<DD>
+a '-&gt;' separator for visual and automated parsing between src and dst
+<DT>+<DD>
+destination address with mask
+<DT>+<DD>
+a '=&gt;' separator for visual and automated parsing between selection
+criteria and SAID to use
+<DT>+<DD>
+SAID (Security Association IDentifier), comprised of:
+<DT>+<DD>
+protocol
+(<I>proto</I>),
+<DT>+<DD>
+address family
+(<I>af</I>),
+where '.' stands for IPv4 and ':' for IPv6
+<DT>+<DD>
+Security Parameters Index
+(<I>SPI</I>),
+<DT>+<DD>
+effective destination
+(<I>edst</I>),
+where the packet should be forwarded after processing
+(normally the other security gateway)
+together indicate which Security Association should be used to process
+the packet,
+<DT>+<DD>
+source identity text string with no whitespace, in parens,
+<DT>+<DD>
+destination identity text string with no whitespace, in parens
+</DL>
+<P>
+
+Addresses are written as IPv4 dotted quads or IPv6 coloned hex,
+protocol is one of &quot;ah&quot;, &quot;esp&quot;, &quot;comp&quot; or &quot;tun&quot;
+and
+SPIs are prefixed hexadecimal numbers where the prefix '.' is for IPv4 and the prefix ':' is for IPv6
+<P>
+
+SAIDs are written as &quot;<A HREF="mailto:protoafSPI@edst">protoafSPI@edst</A>&quot;. There are also 5
+&quot;magic&quot; SAIDs which have special meaning:
+<DL COMPACT>
+<DT>+<DD>
+<B>%drop</B>
+
+means that matches are to be dropped
+<DT>+<DD>
+<B>%reject</B>
+
+means that matches are to be dropped and an ICMP returned, if
+possible to inform
+<DT>+<DD>
+<B>%trap</B>
+
+means that matches are to trigger an ACQUIRE message to the Key
+Management daemon(s) and a hold eroute will be put in place to
+prevent subsequent packets also triggering ACQUIRE messages.
+<DT>+<DD>
+<B>%hold</B>
+
+means that matches are to stored until the eroute is replaced or
+until that eroute gets reaped
+<DT>+<DD>
+<B>%pass</B>
+
+means that matches are to allowed to pass without IPSEC processing
+<BR>
+
+
+</DL>
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<P>
+
+<B>1867 172.31.252.0/24 -&gt; 0.0.0.0/0 =&gt; <A HREF="mailto:tun.130@192.168.43.1">tun.130@192.168.43.1</A> </B>
+
+<BR>
+
+<B> ()<TT>&nbsp;&nbsp;&nbsp;&nbsp;</TT>()</B>
+
+<P>
+
+means that 1,867 packets have been sent to an<BR>
+<B>eroute</B>
+
+that has been set up to protect traffic between the subnet
+<B>172.31.252.0</B>
+
+with a subnet mask of
+<B>24</B>
+
+bits and the default address/mask represented by an address of
+<B>0.0.0.0</B>
+
+with a subnet mask of
+<B>0</B>
+
+bits using the local machine as a security gateway on this end of the
+tunnel and the machine
+<B>192.168.43.1</B>
+
+on the other end of the tunnel with a Security Association IDentifier of
+<B><A HREF="mailto:tun0x130@192.168.43.1">tun0x130@192.168.43.1</A></B>
+
+which means that it is a tunnel mode connection (4, IPPROTO_IPIP) with a
+Security Parameters Index of
+<B>130</B>
+
+in hexadecimal with no identies defined for either end.
+<P>
+
+<B>125 3049:1::/64 -&gt; 0:0/0 =&gt; tun:<A HREF="mailto:130@3058">130@3058</A>:4::5<TT>&nbsp;</TT>()<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>()</B>
+
+<P>
+
+means that 125 packets have been sent to an<BR>
+<B>eroute</B>
+
+that has been set up to protect traffic between the subnet
+<B>3049:1::</B>
+
+with a subnet mask of
+<B>64</B>
+
+bits and the default address/mask represented by an address of
+<B>0:0</B>
+
+with a subnet mask of
+<B>0</B>
+
+bits using the local machine as a security gateway on this end of the
+tunnel and the machine
+<B>3058:4::5</B>
+
+on the other end of the tunnel with a Security Association IDentifier of
+<B>tun:<A HREF="mailto:130@3058">130@3058</A>:4::5</B>
+
+which means that it is a tunnel mode connection with a
+Security Parameters Index of
+<B>130</B>
+
+in hexadecimal with no identies defined for either end.
+<P>
+
+<B>42 192.168.6.0/24 -&gt; 192.168.7.0/24 =&gt; %passthrough</B>
+
+<P>
+
+means that 42 packets have been sent to an
+<B>eroute</B>
+
+that has been set up to pass the traffic from the subnet
+<B>192.168.6.0</B>
+
+with a subnet mask of
+<B>24</B>
+
+bits and to subnet
+<B>192.168.7.0</B>
+
+with a subnet mask of
+<B>24</B>
+
+bits without any IPSEC processing with no identies defined for either end.
+<P>
+
+<B>2112 192.168.8.55/32 -&gt; 192.168.9.47/24 =&gt; %hold<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>(east)<TT>&nbsp;&nbsp;</TT>()</B>
+
+<P>
+
+means that 2112 packets have been sent to an<BR>
+<B>eroute</B>
+
+that has been set up to hold the traffic from the host
+<B>192.168.8.55</B>
+
+and to host
+<B>192.168.9.47</B>
+
+until a key exchange from a Key Management daemon
+succeeds and puts in an SA or fails and puts in a pass
+or drop eroute depending on the default configuration with the local client
+defined as &quot;east&quot; and no identy defined for the remote end.
+<P>
+
+<B>2001 192.168.2.110/32 -&gt; 192.168.2.120/32 =&gt; </B>
+
+<BR>
+
+<B> <A HREF="mailto:esp.e6de@192.168.2.120">esp.e6de@192.168.2.120</A><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>()<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>()</B>
+
+<P>
+
+means that 2001 packets have been sent to an<BR>
+<B>eroute</B>
+
+that has been set up to protect traffic between the host
+<B>192.168.2.110</B>
+
+and the host
+<B>192.168.2.120</B>
+
+using
+<B>192.168.2.110</B>
+
+as a security gateway on this end of the
+connection and the machine
+<B>192.168.2.120</B>
+
+on the other end of the connection with a Security Association IDentifier of
+<B><A HREF="mailto:esp.e6de@192.168.2.120">esp.e6de@192.168.2.120</A></B>
+
+which means that it is a transport mode connection with a Security
+Parameters Index of
+<B>e6de</B>
+
+in hexadecimal using Encapsuation Security Payload protocol (50,
+IPPROTO_ESP) with no identies defined for either end.
+<P>
+
+<B>1984 3049:1::110/128 -&gt; 3049:1::120/128 =&gt; </B>
+
+<BR>
+
+<B> ah:<A HREF="mailto:f5ed@3049">f5ed@3049</A>:1::120<TT>&nbsp;&nbsp;&nbsp;</TT>()<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>()</B>
+
+<P>
+
+means that 1984 packets have been sent to an<BR>
+<B>eroute</B>
+
+that has been set up to authenticate traffic between the host
+<B>3049:1::110</B>
+
+and the host
+<B>3049:1::120</B>
+
+using
+<B>3049:1::110</B>
+
+as a security gateway on this end of the
+connection and the machine
+<B>3049:1::120</B>
+
+on the other end of the connection with a Security Association IDentifier of
+<B>ah:<A HREF="mailto:f5ed@3049">f5ed@3049</A>:1::120</B>
+
+which means that it is a transport mode connection with a Security
+Parameters Index of
+<B>f5ed</B>
+
+in hexadecimal using Authentication Header protocol (51,
+IPPROTO_AH) with no identies defined for either end.
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_eroute, /usr/local/bin/ipsec
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_tncfg.5.html">ipsec_tncfg</A>(5), <A HREF="ipsec_spi.5.html">ipsec_spi</A>(5),
+<A HREF="ipsec_spigrp.5.html">ipsec_spigrp</A>(5), <A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5), <A HREF="ipsec_eroute.8.html">ipsec_eroute</A>(8), <A HREF="ipsec_version.5.html">ipsec_version</A>(5),
+<A HREF="ipsec_pf_key.5.html">ipsec_pf_key</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_eroute.8.html b/doc/manpage.d/ipsec_eroute.8.html
new file mode 100644
index 000000000..7489462d7
--- /dev/null
+++ b/doc/manpage.d/ipsec_eroute.8.html
@@ -0,0 +1,421 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_EROUTE</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_EROUTE</H1>
+Section: Maintenance Commands (8)<BR>Updated: 21 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec eroute - manipulate IPSEC extended routing tables
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>eroute</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>eroute</B>
+
+<B>--add</B>
+
+<B>--eraf (inet | inet6)</B>
+
+<B>--src</B>
+
+src/srcmaskbits|srcmask
+<B>--dst</B>
+
+dst/dstmaskbits|dstmask
+&lt;SAID&gt;
+<P>
+
+<B>ipsec</B>
+
+<B>eroute</B>
+
+<B>--replace</B>
+
+<B>--eraf (inet | inet6)</B>
+
+<B>--src</B>
+
+src/srcmaskbits|srcmask
+<B>--dst</B>
+
+dst/dstmaskbits|dstmask
+&lt;SAID&gt;
+<P>
+
+<B>ipsec</B>
+
+<B>eroute</B>
+
+<B>--del</B>
+
+<B>--eraf (inet | inet6)</B>
+
+<B>--src</B>
+
+src/srcmaskbits|srcmask
+<B>--dst</B>
+
+dst/dstmaskbits|dstmask
+<P>
+
+<B>ipsec</B>
+
+<B>eroute</B>
+
+<B>--clear</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>eroute</B>
+
+<B>--help</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>eroute</B>
+
+<B>--version</B>
+
+<P>
+
+Where &lt;SAID&gt; is
+<B>--af</B>
+
+(inet | inet6)
+<B>--edst</B>
+
+edst
+<B>--spi</B>
+
+spi
+<B>--proto</B>
+
+proto
+OR
+<B>--said</B>
+
+said
+OR
+<B>--said</B>
+
+<B>(%passthrough | %passthrough4 | %passthrough6)</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Eroute</I>
+
+manages the IPSEC extended routing tables,
+which control what (if any) processing is applied
+to non-encrypted packets arriving for IPSEC processing and forwarding.
+The form with no additional arguments lists the contents of
+/proc/net/ipsec_eroute.
+The
+<B>--add</B>
+
+form adds a table entry, the
+<B>--replace</B>
+
+form replaces a table entry, while the
+<B>--del</B>
+
+form deletes one. The
+<B>--clear</B>
+
+form deletes the entire table.
+<P>
+
+A table entry consists of:
+<DL COMPACT>
+<DT>+<DD>
+source and destination addresses,
+with masks,
+for selection of packets
+<DT>+<DD>
+Security Association IDentifier, comprised of:
+<DT>+<DD>
+protocol
+(<I>proto</I>), indicating (together with the
+effective destination and the security parameters index)
+which Security Association should be used to process the packet
+<DT>+<DD>
+address family
+(<I>af</I>),
+<DT>+<DD>
+Security Parameters Index
+(<I>spi</I>), indicating (together with the
+effective destination and protocol)
+which Security Association should be used to process the packet
+(must be larger than or equal to 0x100)
+<DT>+<DD>
+effective destination
+(<I>edst</I>),
+where the packet should be forwarded after processing
+(normally the other security gateway)
+<DT>+<DD>
+OR
+<DT>+<DD>
+SAID
+(<I>said</I>), indicating
+which Security Association should be used to process the packet
+</DL>
+<P>
+
+Addresses are written as IPv4 dotted quads or IPv6 coloned hex,
+protocol is one of &quot;ah&quot;, &quot;esp&quot;, &quot;comp&quot; or &quot;tun&quot; and SPIs are
+prefixed hexadecimal numbers where '.' represents IPv4 and ':'
+stands for IPv6.
+<P>
+
+SAIDs are written as &quot;<A HREF="mailto:protoafSPI@address">protoafSPI@address</A>&quot;. There are also 5
+&quot;magic&quot; SAIDs which have special meaning:
+<DL COMPACT>
+<DT>+<DD>
+<B>%drop</B>
+
+means that matches are to be dropped
+<DT>+<DD>
+<B>%reject</B>
+
+means that matches are to be dropped and an ICMP returned, if
+possible to inform
+<DT>+<DD>
+<B>%trap</B>
+
+means that matches are to trigger an ACQUIRE message to the Key
+Management daemon(s) and a hold eroute will be put in place to
+prevent subsequent packets also triggering ACQUIRE messages.
+<DT>+<DD>
+<B>%hold</B>
+
+means that matches are to stored until the eroute is replaced or
+until that eroute gets reaped
+<DT>+<DD>
+<B>%pass</B>
+
+means that matches are to allowed to pass without IPSEC processing
+</DL>
+<P>
+
+The format of /proc/net/ipsec_eroute is listed in <A HREF="ipsec_eroute.5.html">ipsec_eroute</A>(5).
+<BR>
+
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<P>
+
+<B>ipsec eroute --add --eraf inet --src 192.168.0.1/32 \</B>
+
+<BR>
+
+<B> --dst 192.168.2.0/24 --af inet --edst 192.168.0.2 \</B>
+
+<BR>
+
+<B> --spi 0x135 --proto tun</B>
+
+<P>
+
+sets up an
+<B>eroute</B>
+
+on a Security Gateway to protect traffic between the host
+<B>192.168.0.1</B>
+
+and the subnet
+<B>192.168.2.0</B>
+
+with
+<B>24</B>
+
+bits of subnet mask via Security Gateway
+<B>192.168.0.2</B>
+
+using the Security Association with address
+<B>192.168.0.2</B>,
+
+Security Parameters Index
+<B>0x135</B>
+
+and protocol
+<B>tun</B>
+
+(50, IPPROTO_ESP).
+<P>
+
+<B>ipsec eroute --add --eraf inet6 --src 3049:1::1/128 \</B>
+
+<BR>
+
+<B> --dst 3049:2::/64 --af inet6 --edst 3049:1::2 \</B>
+
+<BR>
+
+<B> --spi 0x145 --proto tun</B>
+
+<P>
+
+sets up an
+<B>eroute</B>
+
+on a Security Gateway to protect traffic between the host
+<B>3049:1::1</B>
+
+and the subnet
+<B>3049:2::</B>
+
+with
+<B>64</B>
+
+bits of subnet mask via Security Gateway
+<B>3049:1::2</B>
+
+using the Security Association with address
+<B>3049:1::2</B>,
+
+Security Parameters Index
+<B>0x145</B>
+
+and protocol
+<B>tun</B>
+
+(50, IPPROTO_ESP).
+<P>
+
+<B>ipsec eroute --replace --eraf inet --src company.com/24 \</B>
+
+<BR>
+
+<B> --dst <A HREF="ftp://ftp.ngo.org">ftp.ngo.org</A>/32 --said <A HREF="mailto:tun.135@gw.ngo.org">tun.135@gw.ngo.org</A></B>
+
+<P>
+
+replaces an
+<B>eroute</B>
+
+on a Security Gateway to protect traffic between the subnet
+<B>company.com</B>
+
+with
+<B>24</B>
+
+bits of subnet mask and the host
+<B><A HREF="ftp://ftp.ngo.org">ftp.ngo.org</A></B>
+
+via Security Gateway
+<B>gw.ngo.org</B>
+
+using the Security Association with Security Association ID
+<B><A HREF="mailto:tun0x135@gw.ngo.org">tun0x135@gw.ngo.org</A></B>
+
+<P>
+
+<B>ipsec eroute --del --eraf inet --src company.com/24 \</B>
+
+<BR>
+
+<B> --dst <A HREF="http://www.ietf.org">www.ietf.org</A>/32 --said %passthrough4</B>
+
+<P>
+
+deletes an
+<B>eroute</B>
+
+on a Security Gateway that allowed traffic between the subnet
+<B>company.com</B>
+
+with
+<B>24</B>
+
+bits of subnet mask and the host
+<B><A HREF="http://www.ietf.org">www.ietf.org</A></B>
+
+to pass in the clear, unprocessed.
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_eroute, /usr/local/bin/ipsec
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_spi.8.html">ipsec_spi</A>(8),
+<A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A>(8), <A HREF="ipsec_klipsdebug.8.html">ipsec_klipsdebug</A>(8), <A HREF="ipsec_eroute.5.html">ipsec_eroute</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_goodmask.3.html b/doc/manpage.d/ipsec_goodmask.3.html
new file mode 100644
index 000000000..a67a08d83
--- /dev/null
+++ b/doc/manpage.d/ipsec_goodmask.3.html
@@ -0,0 +1,122 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_GOODMASK</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_GOODMASK</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec goodmask - is this Internet subnet mask a valid one?
+<BR>
+
+ipsec masktobits - convert Internet subnet mask to bit count
+<BR>
+
+ipsec bitstomask - convert bit count to Internet subnet mask
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int goodmask(struct in_addr mask);</B>
+
+<BR>
+
+<B>int masktobits(struct in_addr mask);</B>
+
+<BR>
+
+<B>struct in_addr bitstomask(int n);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete;
+see
+<I><A HREF="ipsec_masktocount.3.html">ipsec_masktocount</A></I>(3)
+
+for a partial replacement.
+<P>
+
+<I>Goodmask</I>
+
+reports whether the subnet
+<I>mask</I>
+
+is a valid one,
+i.e. consists of a (possibly empty) sequence of
+<B>1</B>s
+
+followed by a (possibly empty) sequence of
+<B>0</B>s.
+
+<I>Masktobits</I>
+
+takes a (valid) subnet mask and returns the number of
+<B>1</B>
+
+bits in it.
+<I>Bitstomask</I>
+
+reverses this,
+returning the subnet mask corresponding to bit count
+<I>n</I>.
+
+<P>
+
+All masks are in network byte order.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+<I>Masktobits</I>
+
+returns
+<B>-1</B>
+
+for an invalid mask.
+<I>Bitstomask</I>
+
+returns an all-zeros mask for a negative or out-of-range
+<I>n</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The error-reporting convention of
+<I>bitstomask</I>
+
+is less than ideal;
+zero is sometimes a legitimate mask.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_hostof.3.html b/doc/manpage.d/ipsec_hostof.3.html
new file mode 100644
index 000000000..57d4a5648
--- /dev/null
+++ b/doc/manpage.d/ipsec_hostof.3.html
@@ -0,0 +1,107 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SUBNETOF</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SUBNETOF</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec subnetof - given Internet address and subnet mask, return subnet number
+<BR>
+
+ipsec hostof - given Internet address and subnet mask, return host part
+<BR>
+
+ipsec broadcastof - given Internet address and subnet mask, return broadcast address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>struct in_addr subnetof(struct in_addr addr,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr mask);</B>
+
+<BR>
+
+<B>struct in_addr hostof(struct in_addr addr,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr mask);</B>
+
+<BR>
+
+<B>struct in_addr broadcastof(struct in_addr addr,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr mask);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_networkof.3.html">ipsec_networkof</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Subnetof</I>
+
+takes an Internet
+<I>address</I>
+
+and a subnet
+<I>mask</I>
+
+and returns the network part of the address
+(all in network byte order).
+<I>Hostof</I>
+
+similarly returns the host part, and
+<I>broadcastof</I>
+
+returns the broadcast address (all-1s convention) for the network.
+<P>
+
+These functions are provided to hide the Internet bit-munging inside
+an API, in hopes of easing the eventual transition to IPv6.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+Calling functions for this is more costly than doing it yourself.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_ikeping.8.html b/doc/manpage.d/ipsec_ikeping.8.html
new file mode 100644
index 000000000..03ed961f3
--- /dev/null
+++ b/doc/manpage.d/ipsec_ikeping.8.html
@@ -0,0 +1,137 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_IKEPING</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_IKEPING</H1>
+Section: Maintenance Commands (8)<BR>Updated: 23 Feb 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ikeping - send/receive ISAKMP/IKE echo requests/replies
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>ikeping</B>
+
+[
+<B>--listen</B>
+
+] [
+<B>--verbose</B>
+
+] [
+<B>--wait </B>
+
+time ] [
+<B>--exchangenum </B>
+
+num ] [
+<B>--ikeport </B>
+
+localport ] [
+<B>--ikeaddress </B>
+
+address ] [
+<B>--inet</B>
+
+] [
+<B>--inet6</B>
+
+] destaddr[/dstport] ...
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ikeping</I>
+
+sends and receives ISAKMP/IKE echo request and echo reply packets. These
+packets are intended for diagnostics purposes, in a manner similar to
+<I><A HREF="ping.8.html">ping</A></I>(8)
+
+does for ICMP echo request/reply packets.
+<P>
+
+At the time of this writing, the ISAKMP echo request/reply exchange is still
+an internet-draft, and is therefore completely non-standard.
+<P>
+
+<I>Ikeping</I>
+
+will bind to the local address given by
+<B>--ikeaddress</B>
+
+and the port number given by
+<B>--ikeport</B>
+
+defaulting to the wildcard address and the ISAKMP port 500. An ISAKMP
+exchange of type 244 (a private use number) is sent to each of the
+address/ports listed on the command line. The exchange number may be
+overridden by the
+<B>--exchangenum </B>
+
+option.
+<P>
+
+<I>Ikeping</I>
+
+then listens for replies, printing them as they are received. Replies
+are of exchange type 245 or the specified exchange number plus 1.
+<I>Ikeping </I>
+
+will keep listening until it either receives as many echo responses as it sent,
+or until the timeout period (10 seconds) has been reached. Receipt of a
+packet will reset the timer. The
+<B>--wait</B>
+
+option can be used to specify a different timeout period.
+<P>
+
+If the
+<B>--listen</B>
+
+option is given, then
+<I>ikeping</I>
+
+will not send any packets. Instead, it will listen for them and reply to
+each request received.
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+no external files
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ping.8.html">ping</A>(8), <A HREF="ipsec_pluto.8.html">ipsec_pluto</A>(8)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Michael Richardson.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_initaddr.3.html b/doc/manpage.d/ipsec_initaddr.3.html
new file mode 100644
index 000000000..ca1f857e7
--- /dev/null
+++ b/doc/manpage.d/ipsec_initaddr.3.html
@@ -0,0 +1,232 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initaddr - initialize an ip_address
+<BR>
+
+ipsec addrtypeof - get address type of an ip_address
+<BR>
+
+ipsec addrlenof - get length of address within an ip_address
+<BR>
+
+ipsec addrbytesof - get copy of address within an ip_address
+<BR>
+
+ipsec addrbytesptr - get pointer to address within an ip_address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int addrtypeof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrlenof(const ip_address *src);</B>
+
+<BR>
+
+<B>size_t addrbytesof(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>unsigned char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>size_t addrbytesptr(const ip_address *src,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char **dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_address</I>
+
+to contain one of the (currently two) types of IP address.
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initaddr</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_address</I>
+
+from an address
+(in network byte order,
+indicated by a pointer
+<I>src</I>
+
+and a length
+<I>srclen</I>)
+
+and an address family
+<I>af</I>
+
+(typically
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The length must be consistent with the address family.
+<P>
+
+<I>Addrtypeof</I>
+
+returns the address type of an address,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Addrlenof</I>
+
+returns the size (in bytes) of the address within an
+<I>ip_address</I>,
+
+to permit storage allocation etc.
+<P>
+
+<I>Addrbytesof</I>
+
+copies the address within the
+<I>ip_address</I>
+
+<I>src</I>
+
+to the buffer indicated by the pointer
+<I>dst</I>
+
+and the length
+<I>dstlen</I>,
+
+and returns the address length (in bytes).
+If the address will not fit,
+as many bytes as will fit are copied;
+the returned length is still the full length.
+It is the caller's responsibility to check the
+returned value to ensure that there was enough room.
+<P>
+
+<I>Addrbytesptr</I>
+
+sets
+<I>*dst</I>
+
+to a pointer to the internal address within the
+<I>ip_address</I>,
+
+and returns the address length (in bytes).
+If
+<I>dst</I>
+
+is
+<B>NULL</B>,
+
+it just returns the address length.
+The pointer points to
+<B>const</B>
+
+to discourage misuse.
+<P>
+
+<I>Initaddr</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+The functions which return
+<I>size_t</I>
+
+return
+<B>0</B>
+
+for a failure.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+An unknown address family is a fatal error for any of these functions
+except
+<I>addrtypeof</I>.
+
+An address-size mismatch is a fatal error for
+<I>initaddr</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+<I>Addrtypeof</I>
+
+should probably have been named
+<I>addrfamilyof</I>.
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_initsaid.3.html b/doc/manpage.d/ipsec_initsaid.3.html
new file mode 100644
index 000000000..2ba79a8ac
--- /dev/null
+++ b/doc/manpage.d/ipsec_initsaid.3.html
@@ -0,0 +1,453 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOSA</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOSA</H1>
+Section: C Library Functions (3)<BR>Updated: 26 Nov 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttosa, satot - convert IPsec Security Association IDs to and from text
+<BR>
+
+ipsec initsaid - initialize an SA ID
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>typedef struct {</B>
+
+<BR>
+&nbsp;
+<B>ip_address dst;</B>
+
+<BR>
+&nbsp;
+<B>ipsec_spi_t spi;</B>
+
+<BR>
+&nbsp;
+<B>int proto;</B>
+
+<BR>
+
+<B>} ip_said;</B>
+
+<P>
+<B>const char *ttosa(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>ip_said *sa);</B>
+
+<BR>
+
+<B>size_t satot(const ip_said *sa, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>void initsaid(const ip_address *addr, ipsec_spi_t spi,</B>
+
+<BR>
+&nbsp;
+<B>int proto, ip_said *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttosa</I>
+
+converts an ASCII Security Association (SA) specifier into an
+<B>ip_said</B>
+
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+<I>Satot</I>
+
+does the reverse conversion, back to a text SA specifier.
+<I>Initsaid</I>
+
+initializes an
+<B>ip_said</B>
+
+from separate items of information.
+<P>
+
+An SA is specified in text with a mail-like syntax, e.g.
+<B><A HREF="mailto:esp.5a7@1.2.3.4">esp.5a7@1.2.3.4</A></B>.
+
+An SA specifier contains
+a protocol prefix (currently
+<B>ah</B>,
+
+<B>esp</B>,
+
+<B>tun</B>,
+
+<B>comp</B>,
+
+or
+<B>int</B>),
+
+a single character indicating the address family
+(<B>.</B>
+
+for IPv4,
+<B>:</B>
+
+for IPv6),
+an unsigned integer SPI number in hexadecimal (with no
+<B>0x</B>
+
+prefix),
+and an IP address.
+The IP address can be any form accepted by
+<I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3),
+
+e.g. dotted-decimal IPv4 address,
+colon-hex IPv6 address,
+or DNS name.
+<P>
+
+As a special case, the SA specifier
+<B>%passthrough4</B>
+
+or
+<B>%passthrough6</B>
+
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, these are synonyms for
+<B><A HREF="mailto:tun.0@0.0.0.0">tun.0@0.0.0.0</A></B>
+
+and
+<B>tun:0@::</B>
+
+respectively,
+but that is subject to change without notice.)
+<B>%passthrough</B>
+
+is a historical synonym for
+<B>%passthrough4</B>.
+
+These forms are known to both
+<I>ttosa</I>
+
+and
+<I>satot</I>,
+
+so the internal representation is never visible.
+<P>
+
+Similarly, the SA specifiers
+<B>%pass</B>,
+
+<B>%drop</B>,
+
+<B>%reject</B>,
+
+<B>%hold</B>,
+
+<B>%trap</B>,
+
+and
+<B>%trapsubnet</B>
+
+signify special ``magic'' SAs used to indicate that packets should be
+passed, dropped, rejected (dropped with ICMP notification),
+held,
+and trapped (sent up to
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8),
+
+with either of two forms of
+<B>%hold</B>
+
+automatically installed)
+respectively.
+These forms too are known to both routines,
+so the internal representation of the magic SAs should never be visible.
+<P>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file supplies the
+<B>ip_said</B>
+
+structure, as well as a data type
+<B>ipsec_spi_t</B>
+
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+<P>
+
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+defines the names
+<B>SA_ESP</B>,
+
+<B>SA_AH</B>,
+
+<B>SA_IPIP</B>,
+
+and
+<B>SA_COMP</B>
+
+to have the same values as the kernel names
+<B>IPPROTO_ESP</B>,
+
+<B>IPPROTO_AH</B>,
+
+<B>IPPROTO_IPIP</B>,
+
+and
+<B>IPPROTO_COMP</B>.
+
+<P>
+
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+also defines
+<B>SA_INT</B>
+
+to have the value
+<B>61</B>
+
+(reserved by IANA for ``any host internal protocol'')
+and
+<B>SPI_PASS</B>,
+
+<B>SPI_DROP</B>,
+
+<B>SPI_REJECT</B>,
+
+<B>SPI_HOLD</B>,
+
+and
+<B>SPI_TRAP</B>
+
+to have the values 256-260 (in <I>host</I> byte order) respectively.
+These are used in constructing the magic SAs
+(which always have address
+<B>0.0.0.0</B>).
+
+<P>
+
+If
+<I>satot</I>
+
+encounters an unknown protocol code, e.g. 77,
+it yields output using a prefix
+showing the code numerically, e.g. ``unk77''.
+This form is
+<I>not</I>
+
+recognized by
+<I>ttosa</I>.
+
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttosa</I>
+
+specifies the length of the string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>satot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file defines a constant,
+<B>SATOT_BUF</B>,
+
+which is the size of a buffer just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>satot</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI,
+dotted-decimal or colon-hex address).
+The value
+<B>'f'</B>
+
+is similar except that the SPI is padded with
+<B>0</B>s
+
+to a fixed 32-bit width, to ease aligning displayed tables.
+<P>
+
+<I>Ttosa</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Satot</I>
+
+returns
+<B>0</B>
+
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<P>
+
+There is also, temporarily, support for some obsolete
+forms of SA specifier which lack the address-family indicator.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_ttoul.3.html">ipsec_ttoul</A>(3), <A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A>(3), <A HREF="ipsec_samesaid.3.html">ipsec_samesaid</A>(3), <A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttosa</I>
+
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+<B>@</B>
+
+in input;
+unknown protocol prefix;
+conversion error in
+<I>ttoul</I>
+
+or
+<I>ttoaddr</I>.
+
+<P>
+
+Fatal errors in
+<I>satot</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttosa( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_initsubnet.3.html b/doc/manpage.d/ipsec_initsubnet.3.html
new file mode 100644
index 000000000..e442a9100
--- /dev/null
+++ b/doc/manpage.d/ipsec_initsubnet.3.html
@@ -0,0 +1,238 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITSUBNET</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITSUBNET</H1>
+Section: C Library Functions (3)<BR>Updated: 12 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initsubnet - initialize an ip_subnet
+<BR>
+
+ipsec addrtosubnet - initialize a singleton ip_subnet
+<BR>
+
+ipsec subnettypeof - get address type of an ip_subnet
+<BR>
+
+ipsec masktocount - convert subnet mask to bit count
+<BR>
+
+ipsec networkof - get base address of an ip_subnet
+<BR>
+
+ipsec maskof - get subnet mask of an ip_subnet
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initsubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>int maskbits, int clash, ip_subnet *dst);</B>
+
+<BR>
+
+<B>const char *addrtosubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>ip_subnet *dst);</B>
+
+<P>
+<B>int subnettypeof(const ip_subnet *src);</B>
+
+<BR>
+
+<B>int masktocount(const ip_address *src);</B>
+
+<BR>
+
+<B>void networkof(const ip_subnet *src, ip_address *dst);</B>
+
+<BR>
+
+<B>void maskof(const ip_subnet *src, ip_address *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_subnet</I>
+
+to contain a description of an IP subnet
+(base address plus mask).
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initsubnet</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_subnet</I>
+
+from a base address and
+a count of mask bits.
+The
+<I>clash</I>
+
+parameter specifies what to do if the base address includes
+<B>1</B>
+
+bits outside the prefix specified by the mask
+(that is, in the ``host number'' part of the address):
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT>'0'<DD>
+zero out host-number bits
+<DT>'x'<DD>
+non-zero host-number bits are an error
+</DL>
+</DL>
+
+<P>
+
+<I>Initsubnet</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+<I>Addrtosubnet</I>
+
+initializes an
+<I>ip_subnet</I>
+
+variable
+<I>*dst</I>
+
+to a ``singleton subnet'' containing the single address
+<I>*addr</I>.
+
+It returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure.
+<P>
+
+<I>Subnettypeof</I>
+
+returns the address type of a subnet,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Masktocount</I>
+
+converts a subnet mask, expressed as an address, to a bit count
+suitable for use with
+<I>initsubnet</I>.
+
+It returns
+<B>-1</B>
+
+for error; see DIAGNOSTICS.
+<P>
+
+<I>Networkof</I>
+
+fills in
+<I>*dst</I>
+
+with the base address of subnet
+<I>src</I>.
+
+<P>
+
+<I>Maskof</I>
+
+fills in
+<I>*dst</I>
+
+with the subnet mask of subnet
+<I>src</I>,
+
+expressed as an address.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttosubnet.3.html">ipsec_ttosubnet</A>(3), <A HREF="ipsec_rangetosubnet.3.html">ipsec_rangetosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>initsubnet</I>
+
+are:
+unknown address family;
+unknown
+<I>clash</I>
+
+value;
+impossible mask bit count;
+non-zero host-number bits and
+<I>clash</I>
+
+is
+<B>'x'</B>.
+
+Fatal errors in
+<I>addrtosubnet</I>
+
+are:
+unknown address family.
+Fatal errors in
+<I>masktocount</I>
+
+are:
+unknown address family;
+mask bits not contiguous.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_isanyaddr.3.html b/doc/manpage.d/ipsec_isanyaddr.3.html
new file mode 100644
index 000000000..974236005
--- /dev/null
+++ b/doc/manpage.d/ipsec_isanyaddr.3.html
@@ -0,0 +1,166 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec anyaddr - get &quot;any&quot; address
+<BR>
+
+ipsec isanyaddr - test address for equality to &quot;any&quot; address
+<BR>
+
+ipsec unspecaddr - get &quot;unspecified&quot; address
+<BR>
+
+ipsec isunspecaddr - test address for equality to &quot;unspecified&quot; address
+<BR>
+
+ipsec loopbackaddr - get loopback address
+<BR>
+
+ipsec isloopbackaddr - test address for equality to loopback address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *anyaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isanyaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *unspecaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isunspecaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *loopbackaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isloopbackaddr(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions fill in, and test for, special values of the
+<I>ip_address</I>
+
+type.
+<P>
+
+<I>Anyaddr</I>
+
+fills in the destination
+<I>*dst</I>
+
+with the ``any'' address of address family
+<I>af</I>
+
+(normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The IPv4 ``any'' address is the one embodied in the old
+<B>INADDR_ANY</B>
+
+macro.
+<P>
+
+<I>Isanyaddr</I>
+
+returns
+<B>1</B>
+
+if the
+<I>src</I>
+
+address equals the ``any'' address,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+Similarly,
+<I>unspecaddr</I>
+
+supplies, and
+<I>isunspecaddr</I>
+
+tests for,
+the ``unspecified'' address,
+which may be the same as the ``any'' address.
+<P>
+
+Similarly,
+<I>loopbackaddr</I>
+
+supplies, and
+<I>islookbackaddr</I>
+
+tests for,
+the loopback address.
+<P>
+
+<I>Anyaddr</I>,
+
+<I>unspecaddr</I>,
+
+and
+<I>loopbackaddr</I>
+
+return
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_addrtot.3.html">ipsec_addrtot</A>(3), <A HREF="ipsec_sameaddr.3.html">ipsec_sameaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in the address-supplying functions are:
+unknown address family.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_isloopbackaddr.3.html b/doc/manpage.d/ipsec_isloopbackaddr.3.html
new file mode 100644
index 000000000..974236005
--- /dev/null
+++ b/doc/manpage.d/ipsec_isloopbackaddr.3.html
@@ -0,0 +1,166 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec anyaddr - get &quot;any&quot; address
+<BR>
+
+ipsec isanyaddr - test address for equality to &quot;any&quot; address
+<BR>
+
+ipsec unspecaddr - get &quot;unspecified&quot; address
+<BR>
+
+ipsec isunspecaddr - test address for equality to &quot;unspecified&quot; address
+<BR>
+
+ipsec loopbackaddr - get loopback address
+<BR>
+
+ipsec isloopbackaddr - test address for equality to loopback address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *anyaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isanyaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *unspecaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isunspecaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *loopbackaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isloopbackaddr(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions fill in, and test for, special values of the
+<I>ip_address</I>
+
+type.
+<P>
+
+<I>Anyaddr</I>
+
+fills in the destination
+<I>*dst</I>
+
+with the ``any'' address of address family
+<I>af</I>
+
+(normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The IPv4 ``any'' address is the one embodied in the old
+<B>INADDR_ANY</B>
+
+macro.
+<P>
+
+<I>Isanyaddr</I>
+
+returns
+<B>1</B>
+
+if the
+<I>src</I>
+
+address equals the ``any'' address,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+Similarly,
+<I>unspecaddr</I>
+
+supplies, and
+<I>isunspecaddr</I>
+
+tests for,
+the ``unspecified'' address,
+which may be the same as the ``any'' address.
+<P>
+
+Similarly,
+<I>loopbackaddr</I>
+
+supplies, and
+<I>islookbackaddr</I>
+
+tests for,
+the loopback address.
+<P>
+
+<I>Anyaddr</I>,
+
+<I>unspecaddr</I>,
+
+and
+<I>loopbackaddr</I>
+
+return
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_addrtot.3.html">ipsec_addrtot</A>(3), <A HREF="ipsec_sameaddr.3.html">ipsec_sameaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in the address-supplying functions are:
+unknown address family.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_isunspecaddr.3.html b/doc/manpage.d/ipsec_isunspecaddr.3.html
new file mode 100644
index 000000000..974236005
--- /dev/null
+++ b/doc/manpage.d/ipsec_isunspecaddr.3.html
@@ -0,0 +1,166 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec anyaddr - get &quot;any&quot; address
+<BR>
+
+ipsec isanyaddr - test address for equality to &quot;any&quot; address
+<BR>
+
+ipsec unspecaddr - get &quot;unspecified&quot; address
+<BR>
+
+ipsec isunspecaddr - test address for equality to &quot;unspecified&quot; address
+<BR>
+
+ipsec loopbackaddr - get loopback address
+<BR>
+
+ipsec isloopbackaddr - test address for equality to loopback address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *anyaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isanyaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *unspecaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isunspecaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *loopbackaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isloopbackaddr(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions fill in, and test for, special values of the
+<I>ip_address</I>
+
+type.
+<P>
+
+<I>Anyaddr</I>
+
+fills in the destination
+<I>*dst</I>
+
+with the ``any'' address of address family
+<I>af</I>
+
+(normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The IPv4 ``any'' address is the one embodied in the old
+<B>INADDR_ANY</B>
+
+macro.
+<P>
+
+<I>Isanyaddr</I>
+
+returns
+<B>1</B>
+
+if the
+<I>src</I>
+
+address equals the ``any'' address,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+Similarly,
+<I>unspecaddr</I>
+
+supplies, and
+<I>isunspecaddr</I>
+
+tests for,
+the ``unspecified'' address,
+which may be the same as the ``any'' address.
+<P>
+
+Similarly,
+<I>loopbackaddr</I>
+
+supplies, and
+<I>islookbackaddr</I>
+
+tests for,
+the loopback address.
+<P>
+
+<I>Anyaddr</I>,
+
+<I>unspecaddr</I>,
+
+and
+<I>loopbackaddr</I>
+
+return
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_addrtot.3.html">ipsec_addrtot</A>(3), <A HREF="ipsec_sameaddr.3.html">ipsec_sameaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in the address-supplying functions are:
+unknown address family.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:17 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_keyblobtoid.3.html b/doc/manpage.d/ipsec_keyblobtoid.3.html
new file mode 100644
index 000000000..109cfafa7
--- /dev/null
+++ b/doc/manpage.d/ipsec_keyblobtoid.3.html
@@ -0,0 +1,174 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_KEYBLOBTOID</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_KEYBLOBTOID</H1>
+Section: C Library Functions (3)<BR>Updated: 25 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec keyblobtoid, splitkeytoid - generate key IDs from RSA keys
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>size_t keyblobtoid(const unsigned char *blob,</B>
+
+<BR>
+&nbsp;
+<B>size_t bloblen, char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>size_t splitkeytoid(const unsigned char *e, size_t elen,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char *m, size_t mlen, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Keyblobtoid</I>
+
+and
+<I>splitkeytoid</I>
+
+generate
+key IDs
+from RSA keys,
+for use in messages and reporting,
+writing the result to
+<I>dst</I>.
+
+A
+<I>key ID</I>
+
+is a short ASCII string identifying a key;
+currently it is just the first nine characters of the base64
+encoding of the RFC 2537/3110 ``byte blob'' representation of the key.
+(Beware that no finite key ID can be collision-proof:
+there is always some small chance of two random keys having the
+same ID.)
+<P>
+
+<I>Keyblobtoid</I>
+
+generates a key ID from a key which is already in the form of an
+RFC 2537/3110 binary key
+<I>blob</I>
+
+(encoded exponent length, exponent, modulus).
+<P>
+
+<I>Splitkeytoid</I>
+
+generates a key ID from a key given in the form of a separate
+(binary) exponent
+<I>e</I>
+
+and modulus
+<I>m</I>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of either
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines a constant
+<B>KEYID_BUF</B>
+
+which is the size of a buffer large enough for worst-case results.
+<P>
+
+Both functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+
+With keys generated by
+<I><A HREF="ipsec_rsasigkey.3.html">ipsec_rsasigkey</A></I>(3),
+
+the first two base64 digits are always the same,
+and the third carries only about one bit of information.
+It's worse with keys using longer fixed exponents,
+e.g. the 24-bit exponent that's common in X.509 certificates.
+However, being able to relate key IDs to the full
+base64 text form of keys by eye is sufficiently useful that this
+waste of space seems justifiable.
+The choice of nine digits is a compromise between bulk and
+probability of collision.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+RFC 3110,
+<I>RSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)</I>,
+Eastlake, 2001
+(superseding the older but better-known RFC 2537).
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors are:
+key too short to supply enough bits to construct a complete key ID
+(almost certainly indicating a garbage key);
+exponent too long for its length to be representable.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_klipsdebug.5.html b/doc/manpage.d/ipsec_klipsdebug.5.html
new file mode 100644
index 000000000..964329256
--- /dev/null
+++ b/doc/manpage.d/ipsec_klipsdebug.5.html
@@ -0,0 +1,229 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_KLIPSDEBUG</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_KLIPSDEBUG</H1>
+Section: File Formats (5)<BR>Updated: 26 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec_klipsdebug - list KLIPS (kernel IPSEC support) debug features and level
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>klipsdebug</B>
+
+<P>
+
+<B>cat</B>
+
+<B>/proc/net/ipsec_klipsdebug</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>/proc/net/ipsec_klipsdebug</I>
+
+lists flags that control various parts of the debugging output of Klips
+(the kernel portion of FreeS/WAN IPSEC).
+At this point it is a read-only file.
+<P>
+
+A table entry consists of:
+<DL COMPACT>
+<DT>+<DD>
+a KLIPS debug variable
+<DT>+<DD>
+a '=' separator for visual and automated parsing between the variable
+name and its current value
+<DT>+<DD>
+hexadecimal bitmap of variable's flags.
+</DL>
+<P>
+
+The variable names roughly describe the scope of the debugging variable.
+Currently, no flags are documented or individually accessible yet except
+tunnel-xmit.
+
+<P>
+
+The variable names are:
+<DL COMPACT>
+<DT><B>tunnel</B>
+
+<DD>
+tunnelling code
+<DT><B>netlink</B>
+
+<DD>
+userspace communication code (obsolete)
+<DT><B>xform</B>
+
+<DD>
+transform selection and manipulation code
+<DT><B>eroute</B>
+
+<DD>
+eroute table manipulation code
+<DT><B>spi</B>
+
+<DD>
+SA table manipulation code
+<DT><B>radij</B>
+
+<DD>
+radij tree manipulation code
+<DT><B>esp</B>
+
+<DD>
+encryptions transforms code
+<DT><B>ah</B>
+
+<DD>
+authentication transforms code
+<DT><B>rcv</B>
+
+<DD>
+receive code
+<DT><B>ipcomp</B>
+
+<DD>
+ip compression transforms code
+<DT><B>verbose</B>
+
+<DD>
+give even more information, beware this will probably trample the 4k kernel printk buffer giving inaccurate output
+</DL>
+<P>
+
+All KLIPS debug output appears as
+<B>kernel.info</B>
+
+messages to
+<I><A HREF="syslogd.8.html">syslogd</A></I>(8).
+
+Most systems are set up
+to log these messages to
+<I>/var/log/messages</I>.
+
+<P>
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<P>
+
+<B>debug_tunnel=00000010.</B>
+
+<BR>
+
+<B>debug_netlink=00000000.</B>
+
+<BR>
+
+<B>debug_xform=00000000.</B>
+
+<BR>
+
+<B>debug_eroute=00000000.</B>
+
+<BR>
+
+<B>debug_spi=00000000.</B>
+
+<BR>
+
+<B>debug_radij=00000000.</B>
+
+<BR>
+
+<B>debug_esp=00000000.</B>
+
+<BR>
+
+<B>debug_ah=00000000.</B>
+
+<BR>
+
+<B>debug_rcv=00000000.</B>
+
+<BR>
+
+<B>debug_pfkey=ffffffff.</B>
+
+<P>
+
+means that one
+<B>tunnel</B>
+
+flag has been set (tunnel-xmit),
+full
+<B>pfkey</B>
+
+sockets debugging has been set and everything else is not set.
+<P>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_klipsdebug, /usr/local/bin/ipsec
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_eroute.8.html">ipsec_eroute</A>(8),
+<A HREF="ipsec_spi.8.html">ipsec_spi</A>(8), <A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A>(8), <A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5), <A HREF="ipsec_version.5.html">ipsec_version</A>(5),
+<A HREF="ipsec_pf_key.5.html">ipsec_pf_key</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_klipsdebug.8.html b/doc/manpage.d/ipsec_klipsdebug.8.html
new file mode 100644
index 000000000..67b1c3a5d
--- /dev/null
+++ b/doc/manpage.d/ipsec_klipsdebug.8.html
@@ -0,0 +1,264 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_KLIPSDEBUG</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_KLIPSDEBUG</H1>
+Section: Maintenance Commands (8)<BR>Updated: 21 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec klipsdebug - set KLIPS (kernel IPSEC support) debug features and level
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>klipsdebug</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>klipsdebug</B>
+
+<B>--set</B>
+
+flagname
+<P>
+
+<B>ipsec</B>
+
+<B>klipsdebug</B>
+
+<B>--clear</B>
+
+flagname
+<P>
+
+<B>ipsec</B>
+
+<B>klipsdebug</B>
+
+<B>--all</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>klipsdebug</B>
+
+<B>--none</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>klipsdebug</B>
+
+<B>--help</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>klipsdebug</B>
+
+<B>--version</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Klipsdebug</I>
+
+sets and clears flags that control
+various parts of the debugging output of Klips
+(the kernel portion of FreeS/WAN IPSEC).
+The form with no additional arguments lists the present contents of
+/proc/net/ipsec_klipsdebug.
+The
+<B>--set</B>
+
+form turns the specified flag on,
+while the
+<B>--clear</B>
+
+form turns the specified flag off.
+The
+<B>--all</B>
+
+form
+turns all flags on except verbose, while the
+<B>--none</B>
+
+form turns all flags off.
+<P>
+
+The current flag names are:
+<DL COMPACT>
+<DT><B>tunnel</B>
+
+<DD>
+tunnelling code
+<DT><B>tunnel-xmit</B>
+
+<DD>
+tunnelling transmit only code
+<DT><B>pfkey</B>
+
+<DD>
+userspace communication code
+<DT><B>xform</B>
+
+<DD>
+transform selection and manipulation code
+<DT><B>eroute</B>
+
+<DD>
+eroute table manipulation code
+<DT><B>spi</B>
+
+<DD>
+SA table manipulation code
+<DT><B>radij</B>
+
+<DD>
+radij tree manipulation code
+<DT><B>esp</B>
+
+<DD>
+encryptions transforms code
+<DT><B>ah</B>
+
+<DD>
+authentication transforms code
+<B>rcv</B>
+
+receive code
+<DT><B>ipcomp</B>
+
+<DD>
+ip compression transforms code
+<DT><B>verbose</B>
+
+<DD>
+give even more information, BEWARE:
+a)this will print authentication and encryption keys in the logs
+b)this will probably trample the 4k kernel printk buffer giving inaccurate output
+</DL>
+<P>
+
+All Klips debug output appears as
+<B>kernel.info</B>
+
+messages to
+<I><A HREF="syslogd.8.html">syslogd</A></I>(8).
+
+Most systems are set up
+to log these messages to
+<I>/var/log/messages</I>.
+
+Beware that
+<B>klipsdebug</B>
+
+<B>--all</B>
+
+produces a lot of output and the log file will grow quickly.
+<P>
+
+The file format for /proc/net/ipsec_klipsdebug is discussed in
+<A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5).
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<DL COMPACT>
+<DT><B>klipsdebug --all</B>
+
+<DD>
+turns on all KLIPS debugging except verbose.
+<DT><B>klipsdebug --clear tunnel</B>
+
+<DD>
+turns off only the
+<B>tunnel</B>
+
+debugging messages.
+</DL>
+<P>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_klipsdebug, /usr/local/bin/ipsec
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_eroute.8.html">ipsec_eroute</A>(8),
+<A HREF="ipsec_spi.8.html">ipsec_spi</A>(8), <A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A>(8), <A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+<A NAME="lbAI">&nbsp;</A>
+<H2>BUGS</H2>
+
+It really ought to be possible to set or unset selective combinations
+of flags.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+<DT><A HREF="#lbAI">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_look.8.html b/doc/manpage.d/ipsec_look.8.html
new file mode 100644
index 000000000..ffe07a57c
--- /dev/null
+++ b/doc/manpage.d/ipsec_look.8.html
@@ -0,0 +1,76 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of look</TITLE>
+</HEAD><BODY>
+<H1>look</H1>
+Section: Maintenance Commands (8)<BR>Updated: 25 Apr 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec look - get a quick summary of FreeS/WAN status
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<I>look</I>
+
+is used to get a quick overview of what the status of FreeSWAN is.
+It is equivalent to:
+&nbsp;&nbsp;&nbsp;ipsec eroute
+<P>
+&nbsp;&nbsp;&nbsp;ipsec spigrp
+<P>
+&nbsp;&nbsp;&nbsp;ipsec tncfg
+<P>
+&nbsp;&nbsp;&nbsp;ipsec spi
+<P>
+&nbsp;&nbsp;&nbsp;netstat -rn
+<P>
+<P>
+
+However a bit of processing is done to combine the outputs.
+<A NAME="lbAD">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_spi.8.html">ipsec_spi</A>(8), <A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A>(8), <A HREF="ipsec_eroute.5.html">ipsec_eroute</A>(5),
+<A HREF="netstat.8.html">netstat</A>(8).
+<A NAME="lbAE">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Man page written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson. Original program written by Henry Spencer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">SEE ALSO</A><DD>
+<DT><A HREF="#lbAE">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_loopbackaddr.3.html b/doc/manpage.d/ipsec_loopbackaddr.3.html
new file mode 100644
index 000000000..92f69d99c
--- /dev/null
+++ b/doc/manpage.d/ipsec_loopbackaddr.3.html
@@ -0,0 +1,166 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec anyaddr - get &quot;any&quot; address
+<BR>
+
+ipsec isanyaddr - test address for equality to &quot;any&quot; address
+<BR>
+
+ipsec unspecaddr - get &quot;unspecified&quot; address
+<BR>
+
+ipsec isunspecaddr - test address for equality to &quot;unspecified&quot; address
+<BR>
+
+ipsec loopbackaddr - get loopback address
+<BR>
+
+ipsec isloopbackaddr - test address for equality to loopback address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *anyaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isanyaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *unspecaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isunspecaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *loopbackaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isloopbackaddr(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions fill in, and test for, special values of the
+<I>ip_address</I>
+
+type.
+<P>
+
+<I>Anyaddr</I>
+
+fills in the destination
+<I>*dst</I>
+
+with the ``any'' address of address family
+<I>af</I>
+
+(normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The IPv4 ``any'' address is the one embodied in the old
+<B>INADDR_ANY</B>
+
+macro.
+<P>
+
+<I>Isanyaddr</I>
+
+returns
+<B>1</B>
+
+if the
+<I>src</I>
+
+address equals the ``any'' address,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+Similarly,
+<I>unspecaddr</I>
+
+supplies, and
+<I>isunspecaddr</I>
+
+tests for,
+the ``unspecified'' address,
+which may be the same as the ``any'' address.
+<P>
+
+Similarly,
+<I>loopbackaddr</I>
+
+supplies, and
+<I>islookbackaddr</I>
+
+tests for,
+the loopback address.
+<P>
+
+<I>Anyaddr</I>,
+
+<I>unspecaddr</I>,
+
+and
+<I>loopbackaddr</I>
+
+return
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_addrtot.3.html">ipsec_addrtot</A>(3), <A HREF="ipsec_sameaddr.3.html">ipsec_sameaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in the address-supplying functions are:
+unknown address family.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_lwdnsq.8.html b/doc/manpage.d/ipsec_lwdnsq.8.html
new file mode 100644
index 000000000..1122b188a
--- /dev/null
+++ b/doc/manpage.d/ipsec_lwdnsq.8.html
@@ -0,0 +1,400 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC LWDNSQ</TITLE>
+</HEAD><BODY>
+<H1>IPSEC LWDNSQ</H1>
+Section:  (8)<BR>Updated: <BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+lwdnsq - lookup items in DNS to help pluto (and others)
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<P>
+<PRE>
+<B>ipsec lwdnsq</B> lwdnsq [<B>--prompt</B>] [<B>--serial</B>]
+</PRE>
+
+<P>
+<PRE>
+<B>ipsec lwdnsq</B> lwdnsq [<B>--help</B>]
+</PRE>
+
+<P>
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<P>
+<P>
+
+The <B>ipsec lwdnsq</B> is a helper program that does DNS lookups for other programs. It implements an asynchronous interface on stdin/stdout, with an ASCII driven command language.
+<P>
+<P>
+
+If stdin is a tty or if the <B>--prompt</B> option is given, then it issues a prompt to the user. Otherwise, it is silent, except for results.
+<P>
+<P>
+
+The program will accept multiple queries concurrently, with each result being marked with the ID provided on the output. The IDs are strings.
+<P>
+<P>
+
+If the <B>--serial</B> option is given, then the program will not attempt to execute concurrent queries, but will serialize all input and output.
+<P>
+<A NAME="lbAE">&nbsp;</A>
+<H2>QUERY LANGUAGE</H2>
+
+<P>
+<P>
+
+There are eleven command that the program understands. This is to lookup different types of records in both the forward and reverse maps. Every query includes a queryid, which is returned in the output, on every single line to identify the transaction.
+<P>
+<A NAME="lbAF">&nbsp;</A>
+<H3>KEY queryid FQDN</H3>
+
+<P>
+<P>
+
+This request looks up the KEY resource record for the given <B>FQDN.</B>.
+<P>
+<A NAME="lbAG">&nbsp;</A>
+<H3>KEY4 queryid A.B.C.D</H3>
+
+<P>
+<P>
+
+This request looks up the KEY resource record found in the reverse map for the IP version 4 address <B>A.B.C.D</B>, i.e. it looks up D.C.B.A.in-addr.arpa.
+<P>
+<A NAME="lbAH">&nbsp;</A>
+<H3>KEY6 queryid A:B::C:D</H3>
+
+<P>
+<P>
+
+This request looks up the KEY resource record found in the reverse map for the IPv6 address <B>A:B::C:D</B>, i.e. it looks the 32-nibble long entry in ip6.arpa (and ip6.int).
+<P>
+<A NAME="lbAI">&nbsp;</A>
+<H3>TXT4 queryid A.B.C.D</H3>
+
+<P>
+<P>
+
+This request looks up the TXT resource record found in the reverse map for the IP version 4 address <B>A.B.C.D</B>, i.e. it looks up D.C.B.A.in-addr.arpa.
+<P>
+<A NAME="lbAJ">&nbsp;</A>
+<H3>TXT6 queryid A:B::C:D</H3>
+
+<P>
+<P>
+
+This request looks up the TXT resource record found in the reverse map for the IPv6 address <B>A:B::C:D</B>, i.e. it looks the 32-nibble long entry in ip6.arpa (and ip6.int).
+<P>
+<A NAME="lbAK">&nbsp;</A>
+<H3>KEY queryid FQDN</H3>
+
+<P>
+<P>
+
+This request looks up the IPSECKEY resource record for the given <B>FQDN.</B>. See note about IPSECKEY processing, below.
+<P>
+<A NAME="lbAL">&nbsp;</A>
+<H3>IPSECKEY4 queryid A.B.C.D</H3>
+
+<P>
+<P>
+
+This request looks up the IPSECKEY resource record found in the reverse map for the IP version 4 address <B>A.B.C.D</B>, i.e. it looks up D.C.B.A.in-addr.arpa. See special note about IPSECKEY processing, below.
+<P>
+<A NAME="lbAM">&nbsp;</A>
+<H3>IPSECKEY6 queryid A:B::C:D</H3>
+
+<P>
+<P>
+
+This request looks up the IPSECKEY resource record found in the reverse map for the IPv6 address <B>A:B::C:D</B>, i.e. it looks the 32-nibble long entry in ip6.arpa (and ip6.int). See special note about IPSECKEY processing, below.
+<P>
+<A NAME="lbAN">&nbsp;</A>
+<H3>OE4 queryid A.B.C.D</H3>
+
+<P>
+<P>
+
+This request looks an appropriate record for Opportunistic Encryption for the given IP address. This attempts to look for the delegation record. This may be one of IPSECKEY, KEY, or TXT record. Unless configured otherwise, (see OE4 Directives, below), then a query type of ANY will be used to retrieve all relevant records, and all will be returned.
+<P>
+<A NAME="lbAO">&nbsp;</A>
+<H3>OE6 queryid A:B::C:D</H3>
+
+<P>
+<P>
+
+This request looks an appropriate record for Opportunistic Encryption for the given IPv6 address. This attempts to look for the delegation record. This may be one of IPSECKEY, KEY, or TXT record. Unless configured otherwise, (see OE Directives, below), then a query type of ALL will be used to retrieve all relevant records, and all will be returned. i.e. it looks the 32-nibble long entry in ip6.arpa (and ip6.int).
+<P>
+<A NAME="lbAP">&nbsp;</A>
+<H3>A queryid FQDN</H3>
+
+<P>
+<P>
+
+This request looks up the A (IPv4) resource record for the given <B>FQDN.</B>.
+<P>
+<A NAME="lbAQ">&nbsp;</A>
+<H3>AAAA queryid FQDN</H3>
+
+<P>
+<P>
+
+This request looks up the AAAA (IPv6) resource record for the given <B>FQDN.</B>.
+<P>
+<A NAME="lbAR">&nbsp;</A>
+<H2>REPLIES TO QUERIES</H2>
+
+<P>
+<P>
+
+All replies from the queries are in the following format:
+<P>
+<PRE>
+
+&lt;ID&gt; &lt;TIME&gt; &lt;TTL&gt; &lt;TYPE&gt; &lt;TYPE-SPECIFIC&gt; \n
+
+</PRE>
+
+<BR>&nbsp;&nbsp;
+<P>
+<DL COMPACT>
+<DT><I>ID</I><DD>
+this is the <B>queryid</B> value that was provided in the query. It is repeated on every line to permit the replies to be properly associated with the query. When the response is not ascribable to particular query (such as for a mis-formed query), then the query ID &quot;0&quot; will be used.
+<P>
+<DT><I>TIME</I><DD>
+this is the current time in seconds since epoch.
+<P>
+<DT><I>TTL</I><DD>
+for answers which have a time to live, this is the current value. The answer is valid for this number of seconds. If there is no useful value here, then the number 0 is used.
+<P>
+<DT><I>TYPE</I><DD>
+This is the type of the record that is being returned. The types are described in the next section. The TYPE specific data that follows is specific to the type.
+<BR>&nbsp;
+<P>
+</DL>
+<P>
+
+The replies are limited to 4096 bytes, a value defined as <B>LWDNSQ_RESULT_LEN_MAX</B>. This is defined in <I>freeswan.h</I>.
+<P>
+<P>
+
+All of the replies which include resource records use the standard presentation format (with no line feeds or carriage returns) in their answer.
+<P>
+<A NAME="lbAS">&nbsp;</A>
+<H3>START</H3>
+
+<P>
+<P>
+
+This reply indicates that a query has been received and has been started. It serves as an anchor point for timing, as well as an acknowledgement.
+<P>
+<A NAME="lbAT">&nbsp;</A>
+<H3>DONE</H3>
+
+<P>
+<P>
+
+This reply indicates that a query is entirely over, and no further information from this query will be sent.
+<P>
+<A NAME="lbAU">&nbsp;</A>
+<H3>RETRY</H3>
+
+<P>
+<P>
+
+This reply indicates that a query is entirely over, but that no data was found. The records may exist, but appropriate servers could not be reached.
+<P>
+<A NAME="lbAV">&nbsp;</A>
+<H3>FATAL</H3>
+
+<P>
+<P>
+
+This reply indicates that a query is entirely over, and that no data of the type requested could be found. There were no timeouts, and all servers were available and confirmed non-existances. There may be NXT records returned prior to this.
+<P>
+<A NAME="lbAW">&nbsp;</A>
+<H3>CNAME</H3>
+
+<P>
+<P>
+
+This is an interim reply, and indicates that a CNAME was found (and followed) while performing the query. The value of the CNAME is present in the type specific section.
+<P>
+<A NAME="lbAX">&nbsp;</A>
+<H3>CNAMEFROM</H3>
+
+<P>
+<P>
+
+This is an interim reply, and indicates that a CNAME was found. The original name that was queries for was not the canonical name, and this reply indicates the name that was actually followed.
+<P>
+<A NAME="lbAY">&nbsp;</A>
+<H3>NAME</H3>
+
+<P>
+<P>
+
+This is an interim reply. The original name that was queries for was not the canonical name. This reply indicates the canonical name.
+<P>
+<A NAME="lbAZ">&nbsp;</A>
+<H3>DNSSEC</H3>
+
+<P>
+<P>
+
+This is an interim reply. It is followed either by &quot;OKAY&quot; or &quot;not present. It indicates if DNSSEC was available on the reply.
+<P>
+<A NAME="lbBA">&nbsp;</A>
+<H3>TXT and AD-TXT</H3>
+
+<P>
+<P>
+
+This is an interim reply. If there are TXT resource records in the reply, then each one is presented using this type. If preceeded by AD-, then this record was signed with DNSSEC.
+<P>
+<A NAME="lbBB">&nbsp;</A>
+<H3>A and AD-A</H3>
+
+<P>
+<P>
+
+This is an interim reply. If there are A resource records in the reply, then each one is presented using this type. If preceeded by AD-, then this record was signed with DNSSEC.
+<P>
+<A NAME="lbBC">&nbsp;</A>
+<H3>AAAA and AD-AAAA</H3>
+
+<P>
+<P>
+
+This is an interim reply. If there are AAAA resource records in the reply, then each one is presented using this type. If preceeded by AD-, then this record was signed with DNSSEC.
+<P>
+<A NAME="lbBD">&nbsp;</A>
+<H3>PTR and AD-PTR</H3>
+
+<P>
+<P>
+
+This is an interim reply. If there are PTR resource records in the reply, then each one is presented using this type. If preceeded by AD-, then this record was signed with DNSSEC.
+<P>
+<A NAME="lbBE">&nbsp;</A>
+<H3>KEY and AD-KEY</H3>
+
+<P>
+<P>
+
+This is an interim reply. If there are KEY resource records in the reply, then each one is presented using this type. If preceeded by AD-, then this record was signed with DNSSEC.
+<P>
+<A NAME="lbBF">&nbsp;</A>
+<H3>IPSECKEY and AD-IPSECKEY</H3>
+
+<P>
+<P>
+
+This is an interim reply. If there are IPSEC resource records in the reply, then each one is presented using this type. If preceeded by AD-, then this record was signed with DNSSEC.
+<P>
+<A NAME="lbBG">&nbsp;</A>
+<H2>SPECIAL IPSECKEY PROCESSING</H2>
+
+<P>
+<P>
+
+At the time of this writing, the IPSECKEY resource record is not entirely specified. In particular no resource record number has been assigned. This program assumes that it is resource record number 45. If the file /etc/ipsec.d/lwdnsq.conf exists, and contains a line like
+<P>
+<PRE>
+
+ipseckey_rr=<B>number</B>
+
+</PRE>
+
+<BR>&nbsp;then&nbsp;this&nbsp;number&nbsp;will&nbsp;be&nbsp;used&nbsp;instead.&nbsp;The&nbsp;file&nbsp;is&nbsp;read&nbsp;only&nbsp;once&nbsp;at&nbsp;startup.
+<P>
+<A NAME="lbBH">&nbsp;</A>
+<H2>OE DIRECTIVES</H2>
+
+<P>
+<P>
+
+If the file /etc/ipsec.d/lwdnsq.conf exists, and contains a line like
+<P>
+<PRE>
+
+queryany=false
+
+</PRE>
+
+<BR>&nbsp;then&nbsp;instead&nbsp;of&nbsp;doing&nbsp;an&nbsp;ALL&nbsp;query&nbsp;when&nbsp;looking&nbsp;for&nbsp;OE&nbsp;delegation&nbsp;records,&nbsp;lwdnsq&nbsp;will&nbsp;do&nbsp;a&nbsp;series&nbsp;of&nbsp;queries.&nbsp;It&nbsp;will&nbsp;first&nbsp;look&nbsp;for&nbsp;IPSECKEY,&nbsp;and&nbsp;then&nbsp;TXT&nbsp;record.&nbsp;If&nbsp;it&nbsp;finds&nbsp;neither,&nbsp;it&nbsp;will&nbsp;then&nbsp;look&nbsp;for&nbsp;KEY&nbsp;records&nbsp;of&nbsp;all&nbsp;kinds,&nbsp;although&nbsp;they&nbsp;do&nbsp;not&nbsp;contain&nbsp;delegation&nbsp;information.
+<P>
+<A NAME="lbBI">&nbsp;</A>
+<H2>SPECIAL IPSECKEY PROCESSING</H2>
+
+<P>
+<PRE>
+
+/etc/ipsec.d/lwdnsq.conf
+
+</PRE>
+
+<P>
+<A NAME="lbBJ">&nbsp;</A>
+<H2>AUTHOR</H2>
+
+Michael Richardson &lt;<A HREF="mailto:mcr@sandelman.ottawa.on.ca">mcr@sandelman.ottawa.on.ca</A>&gt;.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">QUERY LANGUAGE</A><DD>
+<DL>
+<DT><A HREF="#lbAF">KEY queryid FQDN</A><DD>
+<DT><A HREF="#lbAG">KEY4 queryid A.B.C.D</A><DD>
+<DT><A HREF="#lbAH">KEY6 queryid A:B::C:D</A><DD>
+<DT><A HREF="#lbAI">TXT4 queryid A.B.C.D</A><DD>
+<DT><A HREF="#lbAJ">TXT6 queryid A:B::C:D</A><DD>
+<DT><A HREF="#lbAK">KEY queryid FQDN</A><DD>
+<DT><A HREF="#lbAL">IPSECKEY4 queryid A.B.C.D</A><DD>
+<DT><A HREF="#lbAM">IPSECKEY6 queryid A:B::C:D</A><DD>
+<DT><A HREF="#lbAN">OE4 queryid A.B.C.D</A><DD>
+<DT><A HREF="#lbAO">OE6 queryid A:B::C:D</A><DD>
+<DT><A HREF="#lbAP">A queryid FQDN</A><DD>
+<DT><A HREF="#lbAQ">AAAA queryid FQDN</A><DD>
+</DL>
+<DT><A HREF="#lbAR">REPLIES TO QUERIES</A><DD>
+<DL>
+<DT><A HREF="#lbAS">START</A><DD>
+<DT><A HREF="#lbAT">DONE</A><DD>
+<DT><A HREF="#lbAU">RETRY</A><DD>
+<DT><A HREF="#lbAV">FATAL</A><DD>
+<DT><A HREF="#lbAW">CNAME</A><DD>
+<DT><A HREF="#lbAX">CNAMEFROM</A><DD>
+<DT><A HREF="#lbAY">NAME</A><DD>
+<DT><A HREF="#lbAZ">DNSSEC</A><DD>
+<DT><A HREF="#lbBA">TXT and AD-TXT</A><DD>
+<DT><A HREF="#lbBB">A and AD-A</A><DD>
+<DT><A HREF="#lbBC">AAAA and AD-AAAA</A><DD>
+<DT><A HREF="#lbBD">PTR and AD-PTR</A><DD>
+<DT><A HREF="#lbBE">KEY and AD-KEY</A><DD>
+<DT><A HREF="#lbBF">IPSECKEY and AD-IPSECKEY</A><DD>
+</DL>
+<DT><A HREF="#lbBG">SPECIAL IPSECKEY PROCESSING</A><DD>
+<DT><A HREF="#lbBH">OE DIRECTIVES</A><DD>
+<DT><A HREF="#lbBI">SPECIAL IPSECKEY PROCESSING</A><DD>
+<DT><A HREF="#lbBJ">AUTHOR</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_mailkey.8.html b/doc/manpage.d/ipsec_mailkey.8.html
new file mode 100644
index 000000000..83a532563
--- /dev/null
+++ b/doc/manpage.d/ipsec_mailkey.8.html
@@ -0,0 +1,97 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_MAILKEY</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_MAILKEY</H1>
+Section: Maintenance Commands (8)<BR>Updated: 21 Feb 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec mailkey - mail DNS records for Opportunistic Encryption
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>mailkey</B>
+
+--me
+<A HREF="mailto:my@address.tld">my@address.tld</A>
+[
+<B>--reverse</B>
+
+1.2.3.4
+] [
+<B>--forward</B>
+
+hostname.domain.tld
+]
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>mailkey</I>
+
+is a meta-program. It generates a script which will attempt to mail the TXT
+records required to enable Opportunistic Encryption (OE).
+<P>
+
+An e-mail address for the domain's DNS administrator is derived from SOA records.
+The mail body and destination address are freely editable in the script.
+<P>
+
+If no administrator can be located, the output file will not be executable.
+<P>
+
+<DL COMPACT>
+<DT><B>--me</B>&nbsp;<I><A HREF="mailto:my@address.tld">my@address.tld</A></I><DD>
+set the Reply-To: address of the mail to be sent.
+<DT><B>--forward</B>&nbsp;<I>hostname.domain.tld</I><DD>
+the domain name to be used for initator-only OE.
+<DT><B>--reverse</B>&nbsp;<I>1.2.3.4</I><DD>
+the IP address to be used for full Opportunistic Encryption.
+</DL>
+<P>
+
+Only one of --forward or --reverse may be specified.
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+<PRE>
+/etc/ipsec.secrets
+</PRE>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_showhostkey.8.html">ipsec_showhostkey</A>(8), <A HREF="host.8.html">host</A>(8)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project &lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt; by Sam Sgro.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+May produce indeterminate results when processing non-routable IPs.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_manual.8.html b/doc/manpage.d/ipsec_manual.8.html
new file mode 100644
index 000000000..77134f7d0
--- /dev/null
+++ b/doc/manpage.d/ipsec_manual.8.html
@@ -0,0 +1,414 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_MANUAL</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_MANUAL</H1>
+Section: Maintenance Commands (8)<BR>Updated: 17 July 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec manual - take manually-keyed IPsec connections up and down
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>manual</B>
+
+[
+<B>--show</B>
+
+] [
+<B>--showonly</B>
+
+] [
+<B>--other</B>
+
+]
+<BR>
+
+&nbsp;&nbsp;&nbsp;[
+<B>--iam</B>
+
+address<B>@</B>interface
+
+] [
+<B>--config</B>
+
+configfile
+]
+<BR>
+
+&nbsp;&nbsp;&nbsp;operation connection
+<P>
+<B>ipsec</B>
+
+<B>manual</B>
+
+[
+<I>options</I>
+
+]
+<B>--union</B>
+
+operation part ...
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Manual</I>
+
+manipulates manually-keyed FreeS/WAN IPsec connections,
+setting them up and shutting them down,
+based on the information in the IPsec configuration file.
+In the normal usage,
+<I>connection</I>
+
+is the name of a connection specification in the configuration file;
+<I>operation</I>
+
+is
+<B>--up</B>,
+
+<B>--down</B>,
+
+<B>--route</B>,
+
+or
+<B>--unroute</B>.
+
+<I>Manual</I>
+
+generates setup (<B>--route</B>
+
+or
+<B>--up</B>)
+
+or
+teardown (<B>--down</B>
+
+or
+<B>--unroute</B>)
+
+commands for the connection and feeds them to a shell for execution.
+<P>
+
+The
+<B>--up</B>
+
+operation brings the specified connection up, including establishing a
+suitable route for it if necessary.
+<P>
+
+The
+<B>--route</B>
+
+operation just establishes the route for a connection.
+Unless and until an
+<B>--up</B>
+
+operation is done, packets routed by that route will simply be discarded.
+<P>
+
+The
+<B>--down</B>
+
+operation tears the specified connection down,
+<I>except</I>
+
+that it leaves the route in place.
+Unless and until an
+<B>--unroute</B>
+
+operation is done, packets routed by that route will simply be discarded.
+This permits establishing another connection to the same destination
+without any ``window'' in which packets can pass without encryption.
+<P>
+
+The
+<B>--unroute</B>
+
+operation (and only the
+<B>--unroute</B>
+
+operation) deletes any route established for a connection.
+<P>
+
+In the
+<B>--union</B>
+
+usage, each
+<I>part</I>
+
+is the name of a partial connection specification in the configuration file,
+and the union of all the partial specifications is the
+connection specification used.
+The effect is as if the contents of the partial specifications were
+concatenated together;
+restrictions on duplicate parameters, etc., do apply to the result.
+(The same effect can now be had, more gracefully, using the
+<B>also</B>
+
+parameter in connection descriptions;
+see
+<I><A HREF="ipsec.conf.5.html">ipsec.conf</A></I>(5)
+
+for details.)
+<P>
+
+The
+<B>--show</B>
+
+option turns on the
+<B>-x</B>
+
+option of the shell used to execute the commands,
+so each command is shown as it is executed.
+<P>
+
+The
+<B>--showonly</B>
+
+option causes
+<I>manual</I>
+
+to show the commands it would run, on standard output,
+and not run them.
+<P>
+
+The
+<B>--other</B>
+
+option causes
+<I>manual</I>
+
+to pretend it is the other end of the connection.
+This is probably not useful except in combination with
+<B>--showonly</B>.
+
+<P>
+
+The
+<B>--iam</B>
+
+option causes
+<I>manual</I>
+
+to believe it is running on the host with the specified IP
+<I>address</I>,
+
+and that it should use the specified
+<I>interface</I>
+
+(normally it determines all this automatically,
+based on what IPsec interfaces are up and how they are configured).
+<P>
+
+The
+<B>--config</B>
+
+option specifies a non-standard location for the FreeS/WAN IPsec
+configuration file (default
+<I>/etc/ipsec.conf</I>).
+
+<P>
+
+See
+<I><A HREF="ipsec.conf.5.html">ipsec.conf</A></I>(5)
+
+for details of the configuration file.
+Apart from the basic parameters which specify the endpoints and routing
+of a connection (<B>left</B>
+and
+<B>right</B>,
+
+plus possibly
+<B>leftsubnet</B>,
+
+<B>leftnexthop</B>,
+
+<B>leftfirewall</B>,
+
+their
+<B>right</B>
+
+equivalents,
+and perhaps
+<B>type</B>),
+
+a non-<B>passthrough</B>
+<I>manual</I>
+
+connection needs an
+<B>spi</B>
+
+or
+<B>spibase</B>
+
+parameter and some parameters specifying encryption, authentication, or
+both, most simply
+<B>esp</B>,
+
+<B>espenckey</B>,
+
+and
+<B>espauthkey</B>.
+
+Moderately-secure keys can be obtained from
+<I><A HREF="ipsec_ranbits.8.html">ipsec_ranbits</A></I>(8).
+
+For production use of manually-keyed connections,
+it is strongly recommended that the keys be kept in a separate file
+(with permissions
+<B>rw-------</B>)
+
+using the
+<B>include</B>
+
+and
+<B>also</B>
+
+facilities of the configuration file (see
+<I><A HREF="ipsec.conf.5.html">ipsec.conf</A></I>(5)).
+
+<P>
+
+If an
+<B>spi</B>
+
+parameter is given,
+<I>manual</I>
+
+uses that value as the SPI number for all the SAs
+(which are in separate number spaces anyway).
+If an
+<B>spibase</B>
+
+parameter is given instead,
+<I>manual</I>
+
+assigns SPI values by altering the bottom digit
+of that value;
+SAs going from left to right get even digits starting at 0,
+SAs going from right to left get odd digits starting at 1.
+Either way, it is suggested that manually-keyed connections use
+three-digit SPIs with the first digit non-zero,
+i.e. in the range
+<B>0x100</B>
+
+through
+<B>0xfff</B>;
+
+FreeS/WAN reserves those for manual keying and will not
+attempt to use them for automatic keying (unless requested to,
+presumably by a non-FreeS/WAN other end).
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+
+
+/etc/ipsec.conf<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>default IPsec configuration file<BR>
+<BR>
+
+/var/run/ipsec.info<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><B>%defaultroute</B> information<BR>
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec.conf.5.html">ipsec.conf</A>(5), <A HREF="ipsec_spi.8.html">ipsec_spi</A>(8), <A HREF="ipsec_eroute.8.html">ipsec_eroute</A>(8), <A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A>(8),
+<A HREF="route.8.html">route</A>(8)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+It's not nearly as generous about the syntax of subnets,
+addresses, etc. as the usual FreeS/WAN user interfaces.
+Four-component dotted-decimal must be used for all addresses.
+It
+<I>is</I>
+
+smart enough to translate bit-count netmasks to dotted-decimal form.
+<P>
+
+If the connection specification for a connection is changed between an
+<B>--up</B>
+
+and the ensuing
+<B>--down</B>,
+
+chaos may ensue.
+<P>
+
+The
+<B>--up</B>
+
+operation is not smart enough to notice whether the connection is already up.
+<P>
+
+<I>Manual</I>
+
+is not smart enough to reject insecure combinations of algorithms,
+e.g. encryption with no authentication at all.
+<P>
+
+Any non-IPsec route to the other end which is replaced by the
+<B>--up</B>
+
+or
+<B>--route</B>
+
+operation will not be re-established by
+<B>--unroute</B>.
+
+Whether this is a feature or a bug depends on your viewpoint.
+<P>
+
+The optional parameters which
+override the automatic
+<B>spibase</B>-based
+
+SPI assignment are a messy area of the code and bugs are likely.
+<P>
+
+``Road warrior'' handling,
+and other special forms of setup which
+require negotiation between the two security gateways,
+inherently cannot be done with
+<I>manual</I>.
+
+<P>
+
+<I>Manual</I>
+
+generally lags behind
+<I>auto</I>
+
+in support of various features,
+even when implementation <I>would</I> be possible.
+For example, currently it does not do IPComp content compression.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_maskof.3.html b/doc/manpage.d/ipsec_maskof.3.html
new file mode 100644
index 000000000..ea0f83f82
--- /dev/null
+++ b/doc/manpage.d/ipsec_maskof.3.html
@@ -0,0 +1,238 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITSUBNET</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITSUBNET</H1>
+Section: C Library Functions (3)<BR>Updated: 12 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initsubnet - initialize an ip_subnet
+<BR>
+
+ipsec addrtosubnet - initialize a singleton ip_subnet
+<BR>
+
+ipsec subnettypeof - get address type of an ip_subnet
+<BR>
+
+ipsec masktocount - convert subnet mask to bit count
+<BR>
+
+ipsec networkof - get base address of an ip_subnet
+<BR>
+
+ipsec maskof - get subnet mask of an ip_subnet
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initsubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>int maskbits, int clash, ip_subnet *dst);</B>
+
+<BR>
+
+<B>const char *addrtosubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>ip_subnet *dst);</B>
+
+<P>
+<B>int subnettypeof(const ip_subnet *src);</B>
+
+<BR>
+
+<B>int masktocount(const ip_address *src);</B>
+
+<BR>
+
+<B>void networkof(const ip_subnet *src, ip_address *dst);</B>
+
+<BR>
+
+<B>void maskof(const ip_subnet *src, ip_address *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_subnet</I>
+
+to contain a description of an IP subnet
+(base address plus mask).
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initsubnet</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_subnet</I>
+
+from a base address and
+a count of mask bits.
+The
+<I>clash</I>
+
+parameter specifies what to do if the base address includes
+<B>1</B>
+
+bits outside the prefix specified by the mask
+(that is, in the ``host number'' part of the address):
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT>'0'<DD>
+zero out host-number bits
+<DT>'x'<DD>
+non-zero host-number bits are an error
+</DL>
+</DL>
+
+<P>
+
+<I>Initsubnet</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+<I>Addrtosubnet</I>
+
+initializes an
+<I>ip_subnet</I>
+
+variable
+<I>*dst</I>
+
+to a ``singleton subnet'' containing the single address
+<I>*addr</I>.
+
+It returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure.
+<P>
+
+<I>Subnettypeof</I>
+
+returns the address type of a subnet,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Masktocount</I>
+
+converts a subnet mask, expressed as an address, to a bit count
+suitable for use with
+<I>initsubnet</I>.
+
+It returns
+<B>-1</B>
+
+for error; see DIAGNOSTICS.
+<P>
+
+<I>Networkof</I>
+
+fills in
+<I>*dst</I>
+
+with the base address of subnet
+<I>src</I>.
+
+<P>
+
+<I>Maskof</I>
+
+fills in
+<I>*dst</I>
+
+with the subnet mask of subnet
+<I>src</I>,
+
+expressed as an address.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttosubnet.3.html">ipsec_ttosubnet</A>(3), <A HREF="ipsec_rangetosubnet.3.html">ipsec_rangetosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>initsubnet</I>
+
+are:
+unknown address family;
+unknown
+<I>clash</I>
+
+value;
+impossible mask bit count;
+non-zero host-number bits and
+<I>clash</I>
+
+is
+<B>'x'</B>.
+
+Fatal errors in
+<I>addrtosubnet</I>
+
+are:
+unknown address family.
+Fatal errors in
+<I>masktocount</I>
+
+are:
+unknown address family;
+mask bits not contiguous.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_masktobits.3.html b/doc/manpage.d/ipsec_masktobits.3.html
new file mode 100644
index 000000000..6eccdd8d5
--- /dev/null
+++ b/doc/manpage.d/ipsec_masktobits.3.html
@@ -0,0 +1,122 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_GOODMASK</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_GOODMASK</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec goodmask - is this Internet subnet mask a valid one?
+<BR>
+
+ipsec masktobits - convert Internet subnet mask to bit count
+<BR>
+
+ipsec bitstomask - convert bit count to Internet subnet mask
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int goodmask(struct in_addr mask);</B>
+
+<BR>
+
+<B>int masktobits(struct in_addr mask);</B>
+
+<BR>
+
+<B>struct in_addr bitstomask(int n);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete;
+see
+<I><A HREF="ipsec_masktocount.3.html">ipsec_masktocount</A></I>(3)
+
+for a partial replacement.
+<P>
+
+<I>Goodmask</I>
+
+reports whether the subnet
+<I>mask</I>
+
+is a valid one,
+i.e. consists of a (possibly empty) sequence of
+<B>1</B>s
+
+followed by a (possibly empty) sequence of
+<B>0</B>s.
+
+<I>Masktobits</I>
+
+takes a (valid) subnet mask and returns the number of
+<B>1</B>
+
+bits in it.
+<I>Bitstomask</I>
+
+reverses this,
+returning the subnet mask corresponding to bit count
+<I>n</I>.
+
+<P>
+
+All masks are in network byte order.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+<I>Masktobits</I>
+
+returns
+<B>-1</B>
+
+for an invalid mask.
+<I>Bitstomask</I>
+
+returns an all-zeros mask for a negative or out-of-range
+<I>n</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The error-reporting convention of
+<I>bitstomask</I>
+
+is less than ideal;
+zero is sometimes a legitimate mask.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_masktocount.3.html b/doc/manpage.d/ipsec_masktocount.3.html
new file mode 100644
index 000000000..ea0f83f82
--- /dev/null
+++ b/doc/manpage.d/ipsec_masktocount.3.html
@@ -0,0 +1,238 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITSUBNET</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITSUBNET</H1>
+Section: C Library Functions (3)<BR>Updated: 12 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initsubnet - initialize an ip_subnet
+<BR>
+
+ipsec addrtosubnet - initialize a singleton ip_subnet
+<BR>
+
+ipsec subnettypeof - get address type of an ip_subnet
+<BR>
+
+ipsec masktocount - convert subnet mask to bit count
+<BR>
+
+ipsec networkof - get base address of an ip_subnet
+<BR>
+
+ipsec maskof - get subnet mask of an ip_subnet
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initsubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>int maskbits, int clash, ip_subnet *dst);</B>
+
+<BR>
+
+<B>const char *addrtosubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>ip_subnet *dst);</B>
+
+<P>
+<B>int subnettypeof(const ip_subnet *src);</B>
+
+<BR>
+
+<B>int masktocount(const ip_address *src);</B>
+
+<BR>
+
+<B>void networkof(const ip_subnet *src, ip_address *dst);</B>
+
+<BR>
+
+<B>void maskof(const ip_subnet *src, ip_address *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_subnet</I>
+
+to contain a description of an IP subnet
+(base address plus mask).
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initsubnet</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_subnet</I>
+
+from a base address and
+a count of mask bits.
+The
+<I>clash</I>
+
+parameter specifies what to do if the base address includes
+<B>1</B>
+
+bits outside the prefix specified by the mask
+(that is, in the ``host number'' part of the address):
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT>'0'<DD>
+zero out host-number bits
+<DT>'x'<DD>
+non-zero host-number bits are an error
+</DL>
+</DL>
+
+<P>
+
+<I>Initsubnet</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+<I>Addrtosubnet</I>
+
+initializes an
+<I>ip_subnet</I>
+
+variable
+<I>*dst</I>
+
+to a ``singleton subnet'' containing the single address
+<I>*addr</I>.
+
+It returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure.
+<P>
+
+<I>Subnettypeof</I>
+
+returns the address type of a subnet,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Masktocount</I>
+
+converts a subnet mask, expressed as an address, to a bit count
+suitable for use with
+<I>initsubnet</I>.
+
+It returns
+<B>-1</B>
+
+for error; see DIAGNOSTICS.
+<P>
+
+<I>Networkof</I>
+
+fills in
+<I>*dst</I>
+
+with the base address of subnet
+<I>src</I>.
+
+<P>
+
+<I>Maskof</I>
+
+fills in
+<I>*dst</I>
+
+with the subnet mask of subnet
+<I>src</I>,
+
+expressed as an address.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttosubnet.3.html">ipsec_ttosubnet</A>(3), <A HREF="ipsec_rangetosubnet.3.html">ipsec_rangetosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>initsubnet</I>
+
+are:
+unknown address family;
+unknown
+<I>clash</I>
+
+value;
+impossible mask bit count;
+non-zero host-number bits and
+<I>clash</I>
+
+is
+<B>'x'</B>.
+
+Fatal errors in
+<I>addrtosubnet</I>
+
+are:
+unknown address family.
+Fatal errors in
+<I>masktocount</I>
+
+are:
+unknown address family;
+mask bits not contiguous.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_networkof.3.html b/doc/manpage.d/ipsec_networkof.3.html
new file mode 100644
index 000000000..ea0f83f82
--- /dev/null
+++ b/doc/manpage.d/ipsec_networkof.3.html
@@ -0,0 +1,238 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITSUBNET</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITSUBNET</H1>
+Section: C Library Functions (3)<BR>Updated: 12 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initsubnet - initialize an ip_subnet
+<BR>
+
+ipsec addrtosubnet - initialize a singleton ip_subnet
+<BR>
+
+ipsec subnettypeof - get address type of an ip_subnet
+<BR>
+
+ipsec masktocount - convert subnet mask to bit count
+<BR>
+
+ipsec networkof - get base address of an ip_subnet
+<BR>
+
+ipsec maskof - get subnet mask of an ip_subnet
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initsubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>int maskbits, int clash, ip_subnet *dst);</B>
+
+<BR>
+
+<B>const char *addrtosubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>ip_subnet *dst);</B>
+
+<P>
+<B>int subnettypeof(const ip_subnet *src);</B>
+
+<BR>
+
+<B>int masktocount(const ip_address *src);</B>
+
+<BR>
+
+<B>void networkof(const ip_subnet *src, ip_address *dst);</B>
+
+<BR>
+
+<B>void maskof(const ip_subnet *src, ip_address *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_subnet</I>
+
+to contain a description of an IP subnet
+(base address plus mask).
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initsubnet</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_subnet</I>
+
+from a base address and
+a count of mask bits.
+The
+<I>clash</I>
+
+parameter specifies what to do if the base address includes
+<B>1</B>
+
+bits outside the prefix specified by the mask
+(that is, in the ``host number'' part of the address):
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT>'0'<DD>
+zero out host-number bits
+<DT>'x'<DD>
+non-zero host-number bits are an error
+</DL>
+</DL>
+
+<P>
+
+<I>Initsubnet</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+<I>Addrtosubnet</I>
+
+initializes an
+<I>ip_subnet</I>
+
+variable
+<I>*dst</I>
+
+to a ``singleton subnet'' containing the single address
+<I>*addr</I>.
+
+It returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure.
+<P>
+
+<I>Subnettypeof</I>
+
+returns the address type of a subnet,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Masktocount</I>
+
+converts a subnet mask, expressed as an address, to a bit count
+suitable for use with
+<I>initsubnet</I>.
+
+It returns
+<B>-1</B>
+
+for error; see DIAGNOSTICS.
+<P>
+
+<I>Networkof</I>
+
+fills in
+<I>*dst</I>
+
+with the base address of subnet
+<I>src</I>.
+
+<P>
+
+<I>Maskof</I>
+
+fills in
+<I>*dst</I>
+
+with the subnet mask of subnet
+<I>src</I>,
+
+expressed as an address.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttosubnet.3.html">ipsec_ttosubnet</A>(3), <A HREF="ipsec_rangetosubnet.3.html">ipsec_rangetosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>initsubnet</I>
+
+are:
+unknown address family;
+unknown
+<I>clash</I>
+
+value;
+impossible mask bit count;
+non-zero host-number bits and
+<I>clash</I>
+
+is
+<B>'x'</B>.
+
+Fatal errors in
+<I>addrtosubnet</I>
+
+are:
+unknown address family.
+Fatal errors in
+<I>masktocount</I>
+
+are:
+unknown address family;
+mask bits not contiguous.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_newhostkey.8.html b/doc/manpage.d/ipsec_newhostkey.8.html
new file mode 100644
index 000000000..e6cf302bf
--- /dev/null
+++ b/doc/manpage.d/ipsec_newhostkey.8.html
@@ -0,0 +1,196 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_NEWHOSTKEY</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_NEWHOSTKEY</H1>
+Section: Maintenance Commands (8)<BR>Updated: 4 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec newhostkey - generate a new host authentication key
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>newhostkey</B>
+
+<B>--output</B>
+
+filename
+[
+<B>--quiet</B>
+
+]
+<B>\</B>
+
+<BR>
+
+
+[
+<B>--bits</B>
+
+n
+]
+[
+<B>--hostname</B>
+
+host
+]
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Newhostkey</I>
+
+outputs (into
+<I>filename</I>,
+
+which can be `<B>-</B>' for standard output)
+an RSA private key suitable for this host,
+in
+<I>/etc/ipsec.secrets</I>
+
+format
+(see
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5)).
+
+Normally,
+<I>newhostkey</I>
+
+invokes
+<I>rsasigkey</I>
+
+(see
+<I><A HREF="ipsec_rsasigkey.8.html">ipsec_rsasigkey</A></I>(8))
+
+with the
+<B>--verbose</B>
+
+option, so a narrative of what is being done appears on standard error.
+<P>
+
+The
+<B>--output</B>
+
+specifier, although it is syntactically an option and can appear at
+any point among the options (it doesn't have to be first),
+is not optional.
+The specified
+<I>filename</I>
+
+is created under umask
+<B>077</B>
+
+if nonexistent;
+if it already exists and is non-empty,
+a warning message about that is sent to standard error,
+and the output is appended to the file.
+<P>
+
+The
+<B>--quiet</B>
+
+option suppresses both the
+<I>rsasigkey</I>
+
+narrative and the existing-file warning message.
+<P>
+
+The
+<B>--bits</B>
+
+option specifies the number of bits in the key;
+the current default is 2192 and we do not recommend use of anything
+shorter unless unusual constraints demand it.
+<P>
+
+The
+<B>--hostname</B>
+
+option is passed through to
+<I>rsasigkey</I>
+
+to tell it what host name to label the output with
+(via its
+<B>--hostname</B>
+
+option).
+<P>
+
+The output format is that of
+<I>rsasigkey</I>,
+
+with bracketing added to complete the
+<I>ipsec.secrets</I>
+
+format.
+In the usual case, where
+<I>ipsec.secrets</I>
+
+contains only the host's own private key,
+the output of
+<I>newhostkey</I>
+
+is sufficient as a complete
+<I>ipsec.secrets</I>
+
+file.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.secrets.5.html">ipsec.secrets</A>(5), <A HREF="ipsec_rsasigkey.8.html">ipsec_rsasigkey</A>(8)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+As with
+<I>rsasigkey</I>,
+
+the run time is difficult to predict,
+since depletion of the system's randomness pool can cause
+arbitrarily long waits for random bits,
+and the prime-number searches can also take unpredictable
+(and potentially large) amounts of CPU time.
+See
+<I><A HREF="ipsec_rsasigkey.8.html">ipsec_rsasigkey</A></I>(8)
+
+for some typical performance numbers.
+<P>
+
+A higher-level tool which could handle the clerical details
+of changing to a new key would be helpful.
+<P>
+
+The requirement for
+<B>--output</B>
+
+is a blemish,
+but private keys are extremely sensitive information
+and unusual precautions seem justified.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_optionsfrom.3.html b/doc/manpage.d/ipsec_optionsfrom.3.html
new file mode 100644
index 000000000..05d045e4d
--- /dev/null
+++ b/doc/manpage.d/ipsec_optionsfrom.3.html
@@ -0,0 +1,275 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_OPTIONSFROM</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_OPTIONSFROM</H1>
+Section: C Library Functions (3)<BR>Updated: 16 Oct 1998<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec optionsfrom - read additional ``command-line'' options from file
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *optionsfrom(char *filename, int *argcp,</B>
+
+<BR>
+&nbsp;
+<B>char ***argvp, int optind, FILE *errsto);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Optionsfrom</I>
+
+is called from within a
+<I><A HREF="getopt_long.3.html">getopt_long</A></I>(3)
+
+scan,
+as the result of the appearance of an option (preferably
+<B>--optionsfrom</B>)
+
+to insert additional ``command-line'' arguments
+into the scan immediately after
+the option.
+Typically this would be done to pick up options which are
+security-sensitive and should not be visible to
+<I><A HREF="ps.1.html">ps</A></I>(1)
+
+and similar commands,
+and hence cannot be supplied as part
+of the actual command line or the environment.
+<P>
+
+<I>Optionsfrom</I>
+
+reads the additional arguments from the specified
+<I>filename</I>,
+
+allocates a new argument vector to hold pointers to the existing
+arguments plus the new ones,
+and amends
+<I>argc</I>
+
+and
+<I>argv</I>
+
+(via the pointers
+<I>argcp</I>
+
+and
+<I>argvp</I>,
+
+which must point to the
+<I>argc</I>
+
+and
+<I>argv</I>
+
+being supplied to
+<I><A HREF="getopt_long.3.html">getopt_long</A></I>(3))
+
+accordingly.
+<I>Optind</I>
+
+must be the index, in the original argument vector,
+of the next argument.
+<P>
+
+If
+<I>errsto</I>
+
+is NULL,
+<I>optionsfrom</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+If
+<I>errsto</I>
+
+is non-NULL and an error occurs,
+<I>optionsfrom</I>
+
+prints a suitable complaint onto the
+<I>errsto</I>
+
+descriptor and invokes
+<I>exit</I>
+
+with an exit status of 2;
+this is a convenience for cases where more sophisticated
+responses are not required.
+<P>
+
+The text of existing arguments is not disturbed by
+<I>optionsfrom</I>,
+
+so pointers to them and into them remain valid.
+<P>
+
+The file of additional arguments is an ASCII text file.
+Lines consisting solely of white space,
+and lines beginning with
+<B>#</B>,
+
+are comments and are ignored.
+Otherwise, a line which does not begin with
+<B>-</B>
+
+is taken to be a single argument;
+if it both begins and ends with double-quote (&quot;),
+those quotes are stripped off (note, no other processing is done within
+the line!).
+A line beginning with
+<B>-</B>
+
+is considered to contain multiple arguments separated by white space.
+<P>
+
+Because
+<I>optionsfrom</I>
+
+reads its entire file before the
+<I><A HREF="getopt_long.3.html">getopt_long</A></I>(3)
+
+scan is resumed, an
+<I>optionsfrom</I>
+
+file can contain another
+<B>--optionsfrom</B>
+
+option.
+Obviously, infinite loops are possible here.
+If
+<I>errsto</I>
+
+is non-NULL,
+<I>optionsfrom</I>
+
+considers it an error to be called more than 100 times.
+If
+<I>errsto</I>
+
+is NULL,
+loop detection is up to the caller
+(and the internal loop counter is zeroed out).
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLE</H2>
+
+A reasonable way to invoke
+<I>optionsfrom</I>
+
+would be like so:
+<P>
+
+<PRE>
+<B>#include &lt;<A HREF="file:/usr/include/getopt.h">getopt.h</A>&gt;
+
+struct option opts[] = {
+ /* ... */
+ &quot;optionsfrom&quot;, 1, NULL, '+',
+ /* ... */
+};
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int opt;
+ extern char *optarg;
+ extern int optind;
+
+ while ((opt = getopt_long(argc, argv, &quot;&quot;, opts, NULL)) != EOF)
+ switch (opt) {
+ /* ... */
+ case '+': /* optionsfrom */
+ optionsfrom(optarg, &amp;argc, &amp;argv, optind, stderr);
+ /* does not return on error */
+ break;
+ /* ... */
+ }
+ /* ... */
+</B></PRE>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="getopt_long.3.html">getopt_long</A>(3)
+<A NAME="lbAG">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Errors in
+<I>optionsfrom</I>
+
+are:
+unable to open file;
+attempt to allocate temporary storage for argument or
+argument vector failed;
+read error in file;
+line too long.
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAI">&nbsp;</A>
+<H2>BUGS</H2>
+
+The double-quote convention is rather simplistic.
+<P>
+
+Line length is currently limited to 1023 bytes,
+and there is no continuation convention.
+<P>
+
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+<P>
+
+There is a certain element of unwarranted chumminess with
+the insides of
+<I><A HREF="getopt_long.3.html">getopt_long</A></I>(3)
+
+here.
+No non-public interfaces are actually used, but
+<I>optionsfrom</I>
+
+does rely on
+<I><A HREF="getopt_long.3.html">getopt_long</A></I>(3)
+
+being well-behaved in certain ways that are not actually
+promised by the specs.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLE</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+<DT><A HREF="#lbAI">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_pf_key.5.html b/doc/manpage.d/ipsec_pf_key.5.html
new file mode 100644
index 000000000..420c12900
--- /dev/null
+++ b/doc/manpage.d/ipsec_pf_key.5.html
@@ -0,0 +1,176 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PF_KEY</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PF_KEY</H1>
+Section: File Formats (5)<BR>Updated: 29 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec_pf_key - lists PF_KEY sockets registered with KLIPS
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>cat</B>
+
+<B>/proc/net/pf_key</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>/proc/net/pf_key</I>
+
+is a read-only file which lists the presently open PF_KEY sockets on the
+local system and their parameters.
+<P>
+
+Each line lists one PF_KEY socket.
+A table entry consists of:
+<DL COMPACT>
+<DT>+<DD>
+sock pointer (sock)
+<DT>+<DD>
+PID of the socket owner (pid)
+<DT>+<DD>
+flag to indicate if the socket is dead (d)
+<DT>+<DD>
+socket wait queue (sleep)
+<DT>+<DD>
+socket pointer (socket)
+<DT>+<DD>
+next socket in chain (next)
+<DT>+<DD>
+previous socket in chain (prev)
+<DT>+<DD>
+last socket error (e)
+<DT>+<DD>
+pointer to destruct routine (destruct)
+<DT>+<DD>
+is this a reused socket (r)
+<DT>+<DD>
+has this socket been zapped (z)
+<DT>+<DD>
+socket family to which this socket belongs (fa)
+<DT>+<DD>
+local port number (n)
+<DT>+<DD>
+protocol version number (p)
+<DT>+<DD>
+Receive queue bytes committed (r)
+<DT>+<DD>
+Transmit queue bytes committed (w)
+<DT>+<DD>
+option memory allocations (o)
+<DT>+<DD>
+size of send buffer in bytes (sndbf)
+<DT>+<DD>
+timestamp in seconds (stamp)
+<DT>+<DD>
+socket flags (Flags)
+<DT>+<DD>
+socket type (Type)
+<DT>+<DD>
+connection state (St)
+<B>.SH</B>EXAMPLES
+
+<DT>
+<DD>
+<DT><B>c3b8c140 3553 0 c0599818 c05997fc 0 0 0 0 1 0 15 0 2 0 0 0 65535 0.103232 00000000 00000003 01</B>
+
+<DD>
+</DL>
+<P>
+
+shows that there is one pf_key socket set up that starts at
+<B>c3b8c140</B>,
+
+whose owning process has PID
+<B>3553</B>,
+
+the socket is not dead, its wait queue is at
+<B>c0599818</B>,
+
+whose owning socket is at
+<B>c05997fc</B>,
+
+with no other sockets in the chain, no errors, no destructor, it is a
+reused socket which has not been zapped, from protocol family
+<B>15</B>
+
+(PF_KEY), local port number
+<B>0</B>,
+
+protocol socket version
+<B>2</B>,
+
+no memory allocated to transmit, receive or option queues, a send buffer
+of almost
+<B>64kB</B>,
+
+a timestamp of
+<B>0.103232</B>,
+
+no flags set, type
+<B>3</B>,
+
+in state
+<B>1</B>.
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/pf_key
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_eroute.5.html">ipsec_eroute</A>(5), <A HREF="ipsec_spi.5.html">ipsec_spi</A>(5),
+<A HREF="ipsec_spigrp.5.html">ipsec_spigrp</A>(5), <A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_version.5.html">ipsec_version</A>(5)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_pf_key.8.html b/doc/manpage.d/ipsec_pf_key.8.html
new file mode 100644
index 000000000..e40cfb15b
--- /dev/null
+++ b/doc/manpage.d/ipsec_pf_key.8.html
@@ -0,0 +1,122 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PF_KEY</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PF_KEY</H1>
+Section: User Commands (1)<BR>Updated: 17 Oct 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+pf_key - shows pfkey messages emitted by the kernel
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>pf_key</B>
+
+<B>--ah</B>
+
+<B>--esp</B>
+
+<B>--ipip</B>
+
+<B>--ipcomp</B>
+
+<B>--daemon </B>
+
+<I>file</I>
+
+<B>hmac-md5-96</B>|<B>hmac-sha1-96</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<B>pf_key</B>
+
+is a program to open a PF_KEY socket and print all messages that are received
+from it. With no options, it will register itself to receive key requests for
+AH, ESP, IPIP and IPCOMP security associations. If given more specific
+options, then it will listen only to those protocols which are listed.
+<P>
+
+If the messages are recognized, the messages will be decoded.
+<P>
+
+If the option
+<B>--daemon</B>
+
+is provided, then after doing the registrations, the program will fork
+into the background. The provided file will be opened and the process ID of
+the background process will be written to it. This option is present to
+present race conditions in regression testing.
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<DL COMPACT>
+<DT>
+<DD>
+</DL>
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/pf_key
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="pf_key.5.html">pf_key</A>(5), <A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_eroute.5.html">ipsec_eroute</A>(5), <A HREF="ipsec_spi.5.html">ipsec_spi</A>(5),
+<A HREF="ipsec_spigrp.5.html">ipsec_spigrp</A>(5), <A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_version.5.html">ipsec_version</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson &lt;<A HREF="mailto:mcr@freeswan.org">mcr@freeswan.org</A>&gt;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_pluto.8.html b/doc/manpage.d/ipsec_pluto.8.html
new file mode 100644
index 000000000..2e2ce4c2f
--- /dev/null
+++ b/doc/manpage.d/ipsec_pluto.8.html
@@ -0,0 +1,1824 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PLUTO</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PLUTO</H1>
+Section: Maintenance Commands (8)<BR>Updated: 28 March 1999<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec pluto - IPsec IKE keying daemon
+<BR>
+
+ipsec whack - control interface for IPSEC keying daemon
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+
+
+<DL COMPACT>
+<DT>
+<B>
+<DD>ipsec pluto
+[--help]
+[--version]
+[--optionsfrom&nbsp;</B><I>filename</I>]
+[--nofork]
+[--stderrlog]
+[--noklips]
+[--uniqueids]
+[<B>--interface</B> <I>interfacename</I>]
+[--ikeport&nbsp;<I>portnumber</I>]
+[--ctlbase&nbsp;<I>path</I>]
+[--secretsfile&nbsp;<I>secrets-file</I>]
+[--adns <I>pathname</I>]
+[--lwdnsq <I>pathname</I>]
+[--perpeerlog]
+[--perpeerlogbase&nbsp;<I>dirname</I>]
+[--debug-none]
+[--debug-all]
+[--debug-raw]
+[--debug-crypt]
+[--debug-parsing]
+[--debug-emitting]
+[--debug-control]
+[--debug-lifecycle]
+[--debug-klips]
+[--debug-dns]
+[--debug-oppo]
+[--debug-private]
+<DT>
+<B>
+<DD>ipsec whack
+[--help]
+[--version]
+<DT>
+
+<DD>ipsec whack
+--name&nbsp;</B><I>connection-name</I>
+<BR>
+
+[--id&nbsp;<I>id</I>] [--host&nbsp;<I>ip-address</I>]
+[--ikeport&nbsp;<I>port-number</I>]
+[--nexthop&nbsp;<I>ip-address</I>]
+[--client&nbsp;<I>subnet</I>]
+[--dnskeyondemand]
+[--updown&nbsp;<I>updown</I>]
+<BR>
+
+--to
+<BR>
+
+[--id&nbsp;<I>id</I>]
+[--host&nbsp;<I>ip-address</I>]
+[--ikeport&nbsp;<I>port-number</I>]
+[--nexthop&nbsp;<I>ip-address</I>]
+[--client&nbsp;<I>subnet</I>]
+[--dnskeyondemand]
+[--updown&nbsp;<I>updown</I>]
+<BR>
+
+[--psk]
+[--rsasig]
+[--encrypt]
+[--authenticate]
+[--compress]
+[--tunnel]
+[--pfs]
+[--disablearrivalcheck]
+[--ipv4]
+[--ipv6]
+[--tunnelipv4]
+[--tunnelipv6]
+[--ikelifetime&nbsp;<I>seconds</I>]
+[--ipseclifetime&nbsp;<I>seconds</I>]
+[--rekeymargin&nbsp;<I>seconds</I>]
+[--rekeyfuzz&nbsp;<I>percentage</I>]
+[--keyingtries&nbsp;<I>count</I>]
+[--dontrekey]
+[--delete]
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--keyid&nbsp;</B><I>id</I>
+[--addkey]
+[--pubkeyrsa&nbsp;<I>key</I>]
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--myid&nbsp;</B><I>id</I>
+<DT>
+<B>
+<DD>ipsec whack
+--listen|--unlisten
+[--ctlbase&nbsp;</B><I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--route|--unroute
+--name&nbsp;</B><I>connection-name</I>
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--initiate|--terminate
+--name&nbsp;</B><I>connection-name</I>
+[--asynchronous]
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+[--tunnelipv4]
+[--tunnelipv6]
+--oppohere </B><I>ip-address</I>
+--oppothere <I>ip-address</I>
+<DT>
+<B>
+<DD>ipsec whack
+--delete
+--name&nbsp;</B><I>connection-name</I>
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--deletestate&nbsp;</B><I>state-number</I>
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+[--name&nbsp;</B><I>connection-name</I>]
+[--debug-none]
+[--debug-all]
+[--debug-raw]
+[--debug-crypt]
+[--debug-parsing]
+[--debug-emitting]
+[--debug-control]
+[--debug-lifecycle]
+[--debug-klips]
+[--debug-dns]
+[--debug-oppo]
+[--debug-private]
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--status
+[--ctlbase&nbsp;</B><I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--shutdown
+[--ctlbase&nbsp;</B><I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+
+
+
+</DL>
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<B>pluto</B>
+
+is an IKE (``IPsec Key Exchange'') daemon.
+<B>whack</B>
+
+is an auxiliary program to allow requests to be made to a running
+<B>pluto</B>.
+
+<P>
+
+<B>pluto</B>
+
+is used to automatically build shared ``security associations'' on a
+system that has IPsec, the secure IP protocol.
+In other words,
+<B>pluto</B>
+
+can eliminate much of the work of manual keying.
+The actual
+secure transmission of packets is the responsibility of other parts of
+the system (see
+<B>KLIPS</B>,
+
+the companion implementation of IPsec).
+<I><A HREF="ipsec_auto.8.html">ipsec_auto</A></I>(8) provides a more convenient interface to
+<B>pluto</B> and <B>whack</B>.
+<A NAME="lbAE">&nbsp;</A>
+<H3>IKE's Job</H3>
+
+<P>
+
+A <I>Security Association</I> (<I>SA</I>) is an agreement between two network nodes on
+how to process certain traffic between them. This processing involves
+encapsulation, authentication, encryption, or compression.
+<P>
+
+IKE can be deployed on a network node to negotiate Security
+Associations for that node. These IKE implementations can only
+negotiate with other IKE implementations, so IKE must be on each node
+that is to be an endpoint of an IKE-negotiated Security Association.
+No other nodes need to be running IKE.
+<P>
+
+An IKE instance (i.e. an IKE implementation on a particular network
+node) communicates with another IKE instance using UDP IP packets, so
+there must be a route between the nodes in each direction.
+<P>
+
+The negotiation of Security Associations requires a number of choices
+that involve tradeoffs between security, convenience, trust, and
+efficiency. These are policy issues and are normally specified to the
+IKE instance by the system administrator.
+<P>
+
+IKE deals with two kinds of Security Associations. The first part of
+a negotiation between IKE instances is to build an ISAKMP SA. An
+ISAKMP SA is used to protect communication between the two IKEs.
+IPsec SAs can then be built by the IKEs - these are used to carry
+protected IP traffic between the systems.
+<P>
+
+The negotiation of the ISAKMP SA is known as Phase 1. In theory,
+Phase 1 can be accomplished by a couple of different exchange types,
+but we only implement one called Main Mode (we don't implement
+Aggressive Mode).
+<P>
+
+Any negotiation under the protection of an ISAKMP SA, including the
+negotiation of IPsec SAs, is part of Phase 2. The exchange type
+that we use to negotiate an IPsec SA is called Quick Mode.
+<P>
+
+IKE instances must be able to authenticate each other as part of their
+negotiation of an ISAKMP SA. This can be done by several mechanisms
+described in the draft standards.
+<P>
+
+IKE negotiation can be initiated by any instance with any other. If
+both can find an agreeable set of characteristics for a Security
+Association, and both recognize each others authenticity, they can set
+up a Security Association. The standards do not specify what causes
+an IKE instance to initiate a negotiation.
+<P>
+
+In summary, an IKE instance is prepared to automate the management of
+Security Associations in an IPsec environment, but a number of issues
+are considered policy and are left in the system administrator's hands.
+<A NAME="lbAF">&nbsp;</A>
+<H3>Pluto</H3>
+
+<P>
+
+<B>pluto</B> is an implementation of IKE. It runs as a daemon on a network
+node. Currently, this network node must be a LINUX system running the
+<B>KLIPS</B> implementation of IPsec.
+<P>
+
+<B>pluto</B> only implements a subset of IKE. This is enough for it to
+interoperate with other instances of <B>pluto</B>, and many other IKE
+implementations. We are working on implementing more of IKE.
+<P>
+
+The policy for acceptable characteristics for Security Associations is
+mostly hardwired into the code of <B>pluto</B> (spdb.c). Eventually
+this will be moved into a security policy database with reasonable
+expressive power and more convenience.
+<P>
+
+<B>pluto</B> uses shared secrets or RSA signatures to authenticate
+peers with whom it is negotiating.
+<P>
+
+<B>pluto</B> initiates negotiation of a Security Association when it is
+manually prodded: the program <B>whack</B> is run to trigger this.
+It will also initiate a negotiation when <B>KLIPS</B> traps an outbound packet
+for Opportunistic Encryption.
+<P>
+
+<B>pluto</B> implements ISAKMP SAs itself. After it has negotiated the
+characteristics of an IPsec SA, it directs <B>KLIPS</B> to implement it.
+It also invokes a script to adjust any firewall and issue <I><A HREF="route.8.html">route</A></I>(8)
+commands to direct IP packets through <B>KLIPS</B>.
+<P>
+
+When <B>pluto</B> shuts down, it closes all Security Associations.
+<A NAME="lbAG">&nbsp;</A>
+<H3>Before Running Pluto</H3>
+
+<P>
+
+<B>pluto</B> runs as a daemon with userid root. Before running it, a few
+things must be set up.
+<P>
+
+<B>pluto</B> requires <B>KLIPS</B>, the FreeS/WAN implementation of IPsec.
+All of the components of <B>KLIPS</B> and <B>pluto</B> should be installed.
+<P>
+
+<B>pluto</B> supports multiple public networks (that is, networks
+that are considered insecure and thus need to have their traffic
+encrypted or authenticated). It discovers the
+public interfaces to use by looking at all interfaces that are
+configured (the <B>--interface</B> option can be used to limit
+the interfaces considered).
+It does this only when <B>whack</B> tells it to --listen,
+so the interfaces must be configured by then. Each interface with a name of the form
+<B>ipsec</B>[<B>0</B>-<B>9</B>] is taken as a <B>KLIPS</B> virtual public interface.
+Another network interface with the same IP address (there should be only
+one) is taken as the corresponding real public
+interface. <I><A HREF="ifconfig.8.html">ifconfig</A></I>(8) with the <B>-a</B> flag will show
+the name and status of each network interface.
+<P>
+
+<B>pluto</B> requires a database of preshared secrets and RSA private keys.
+This is described in the
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5).
+
+<B>pluto</B> is told of RSA public keys via <B>whack</B> commands.
+If the connection is Opportunistic, and no RSA public key is known,
+<B>pluto</B> will attempt to fetch RSA keys using the Domain Name System.
+<A NAME="lbAH">&nbsp;</A>
+<H3>Setting up <B>KLIPS</B> for <B>pluto</B></H3>
+
+<P>
+
+The most basic network topology that <B>pluto</B> supports has two security
+gateways negotiating on behalf of client subnets. The diagram of RGB's
+testbed is a good example (see <I>klips/doc/rgb_setup.txt</I>).
+<P>
+
+The file <I>INSTALL</I> in the base directory of this distribution
+explains how to start setting up the whole system, including <B>KLIPS</B>.
+<P>
+
+Make sure that the security gateways have routes to each other. This
+is usually covered by the default route, but may require issuing
+<I><A HREF="route.8.html">route</A></I>(8)
+
+commands. The route must go through a particular IP
+interface (we will assume it is <I>eth0</I>, but it need not be). The
+interface that connects the security gateway to its client must be a
+different one.
+<P>
+
+It is necessary to issue a
+<I><A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A></I>(8)
+
+command on each gateway. The required command is:
+<P>
+&nbsp;&nbsp;&nbsp;ipsec tncfg --attach&nbsp;--virtual&nbsp;ipsec0 --physical&nbsp;eth0
+<P>
+A command to set up the ipsec0 virtual interface will also need to be
+run. It will have the same parameters as the command used to set up
+the physical interface to which it has just been connected using
+<I><A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A></I>(8).
+
+<A NAME="lbAI">&nbsp;</A>
+<H3>ipsec.secrets file</H3>
+
+<P>
+
+A <B>pluto</B> daemon and another IKE daemon (for example, another instance
+of <B>pluto</B>) must convince each other that they are who they are supposed
+to be before any negotiation can succeed. This authentication is
+accomplished by using either secrets that have been shared beforehand
+(manually) or by using RSA signatures. There are other techniques,
+but they have not been implemented in <B>pluto</B>.
+<P>
+
+The file <I>/etc/ipsec.secrets</I> is used to keep preshared secret keys
+and RSA private keys for
+authentication with other IKE daemons. For debugging, there is an
+argument to the <B>pluto</B> command to use a different file.
+This file is described in
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5).
+
+<A NAME="lbAJ">&nbsp;</A>
+<H3>Running Pluto</H3>
+
+<P>
+
+To fire up the daemon, just type <B>pluto</B> (be sure to be running as
+the superuser).
+The default IKE port number is 500, the UDP port assigned by IANA for IKE Daemons.
+<B>pluto</B> must be run by the superuser to be able to use the UDP 500 port.
+<P>
+
+<B>pluto</B> attempts to create a lockfile with the name
+<I>/var/run/pluto.pid</I>. If the lockfile cannot be created,
+<B>pluto</B> exits - this prevents multiple <B>pluto</B>s from
+competing Any ``leftover'' lockfile must be removed before
+<B>pluto</B> will run. <B>pluto</B> writes its pid into this file so
+that scripts can find it. This lock will not function properly if it
+is on an NFS volume (but sharing locks on multiple machines doesn't
+make sense anyway).
+<P>
+
+<B>pluto</B> then forks and the parent exits. This is the conventional
+``daemon fork''. It can make debugging awkward, so there is an option
+to suppress this fork.
+<P>
+
+All logging, including diagnostics, is sent to
+<I><A HREF="syslog.3.html">syslog</A></I>(3)
+
+with facility=authpriv;
+it decides where to put these messages (possibly in /var/log/secure).
+Since this too can make debugging awkward, there is an option to
+steer logging to stderr.
+<P>
+
+If the <B>--perpeerlog</B> option is given, then pluto will open
+a log file per connection. By default, this is in /var/log/pluto/peer,
+in a subdirectory formed by turning all dot (.) [IPv4} or colon (:)
+[IPv6] into slashes (/).
+<P>
+
+The base directory can be changed with the <B>--perpeerlogbase</B>.
+<P>
+
+Once <B>pluto</B> is started, it waits for requests from <B>whack</B>.
+<A NAME="lbAK">&nbsp;</A>
+<H3>Pluto's Internal State</H3>
+
+<P>
+
+To understand how to use <B>pluto</B>, it is helpful to understand a little
+about its internal state. Furthermore, the terminology is needed to decipher
+some of the diagnostic messages.
+<P>
+
+The <I>(potential) connection</I> database describes attributes of a
+connection. These include the IP addresses of the hosts and client
+subnets and the security characteristics desired. <B>pluto</B>
+requires this information (simply called a connection) before it can
+respond to a request to build an SA. Each connection is given a name
+when it is created, and all references are made using this name.
+<P>
+
+During the IKE exchange to build an SA, the information about the
+negotiation is represented in a <I>state object</I>. Each state object
+reflects how far the negotiation has reached. Once the negotiation is
+complete and the SA established, the state object remains to represent
+the SA. When the SA is terminated, the state object is discarded.
+Each State object is given a serial number and this is used to refer
+to the state objects in logged messages.
+<P>
+
+Each state object corresponds to a connection and can be thought of
+as an instantiation of that connection.
+At any particular time, there may be any number of state objects
+corresponding to a particular connection.
+Often there is one representing an ISAKMP SA and another representing
+an IPsec SA.
+<P>
+
+<B>KLIPS</B> hooks into the routing code in a LINUX kernel.
+Traffic to be processed by an IPsec SA must be directed through
+<B>KLIPS</B> by routing commands. Furthermore, the processing to be
+done is specified by <I>ipsec <A HREF="eroute.8.html">eroute</A>(8)</I> commands.
+<B>pluto</B> takes the responsibility of managing both of these special
+kinds of routes.
+<P>
+
+Each connection may be routed, and must be while it has an IPsec SA.
+The connection specifies the characteristics of the route: the
+interface on this machine, the ``gateway'' (the nexthop),
+and the peer's client subnet. Two
+connections may not be simultaneously routed if they are for the same
+peer's client subnet but use different interfaces or gateways
+(<B>pluto</B>'s logic does not reflect any advanced routing capabilities).
+<P>
+
+Each eroute is associated with the state object for an IPsec SA
+because it has the particular characteristics of the SA.
+Two eroutes conflict if they specify the identical local
+and remote clients (unlike for routes, the local clients are
+taken into account).
+<P>
+
+When <B>pluto</B> needs to install a route for a connection,
+it must make sure that no conflicting route is in use. If another
+connection has a conflicting route, that route will be taken down, as long
+as there is no IPsec SA instantiating that connection.
+If there is such an IPsec SA, the attempt to install a route will fail.
+<P>
+
+There is an exception. If <B>pluto</B>, as Responder, needs to install
+a route to a fixed client subnet for a connection, and there is
+already a conflicting route, then the SAs using the route are deleted
+to make room for the new SAs. The rationale is that the new
+connection is probably more current. The need for this usually is a
+product of Road Warrior connections (these are explained later; they
+cannot be used to initiate).
+<P>
+
+When <B>pluto</B> needs to install an eroute for an IPsec SA (for a
+state object), first the state object's connection must be routed (if
+this cannot be done, the eroute and SA will not be installed).
+If a conflicting eroute is already in place for another connection,
+the eroute and SA will not be installed (but note that the routing
+exception mentioned above may have already deleted potentially conflicting SAs).
+If another IPsec
+SA for the same connection already has an eroute, all its outgoing traffic
+is taken over by the new eroute. The incoming traffic will still be
+processed. This characteristic is exploited during rekeying.
+<P>
+
+All of these routing characteristics are expected change when
+<B>KLIPS</B> is modified to use the firewall hooks in the LINUX 2.4.x
+kernel.
+<A NAME="lbAL">&nbsp;</A>
+<H3>Using Whack</H3>
+
+<P>
+
+<B>whack</B> is used to command a running <B>pluto</B>.
+<B>whack</B> uses a UNIX domain socket to speak to <B>pluto</B>
+(by default, <I>/var/pluto.ctl</I>).
+<P>
+
+<B>whack</B> has an intricate argument syntax.
+This syntax allows many different functions to be specified.
+The help form shows the usage or version information.
+The connection form gives <B>pluto</B> a description of a potential connection.
+The public key form informs <B>pluto</B> of the RSA public key for a potential peer.
+The delete form deletes a connection description and all SAs corresponding
+to it.
+The listen form tells <B>pluto</B> to start or stop listening on the public interfaces
+for IKE requests from peers.
+The route form tells <B>pluto</B> to set up routing for a connection;
+the unroute form undoes this.
+The initiate form tells <B>pluto</B> to negotiate an SA corresponding to a connection.
+The terminate form tells <B>pluto</B> to remove all SAs corresponding to a connection,
+including those being negotiated.
+The status form displays the <B>pluto</B>'s internal state.
+The debug form tells <B>pluto</B> to change the selection of debugging output
+``on the fly''. The shutdown form tells
+<B>pluto</B> to shut down, deleting all SAs.
+<P>
+
+Most options are specific to one of the forms, and will be described
+with that form. There are three options that apply to all forms.
+<DL COMPACT>
+<DT><B>--ctlbase</B>&nbsp;<I>path</I><DD>
+<I>path</I>.ctl is used as the UNIX domain socket for talking
+to <B>pluto</B>.
+This option facilitates debugging.
+<DT><B>--optionsfrom</B>&nbsp;<I>filename</I><DD>
+adds the contents of the file to the argument list.
+<DT><B>--label</B>&nbsp;<I>string</I><DD>
+adds the string to all error messages generated by <B>whack</B>.
+</DL>
+<P>
+
+The help form of <B>whack</B> is self-explanatory.
+<DL COMPACT>
+<DT><B>--help</B><DD>
+display the usage message.
+<DT><B>--version</B><DD>
+display the version of <B>whack</B>.
+</DL>
+<P>
+
+The connection form describes a potential connection to <B>pluto</B>.
+<B>pluto</B> needs to know what connections can and should be negotiated.
+When <B>pluto</B> is the initiator, it needs to know what to propose.
+When <B>pluto</B> is the responder, it needs to know enough to decide whether
+is is willing to set up the proposed connection.
+<P>
+
+The description of a potential connection can specify a large number
+of details. Each connection has a unique name. This name will appear
+in a updown shell command, so it should not contain punctuation
+that would make the command ill-formed.
+<DL COMPACT>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The topology of
+a connection is symmetric, so to save space here is half a picture:
+<P>
+&nbsp;&nbsp;&nbsp;client_subnet&lt;--&gt;host:ikeport&lt;--&gt;nexthop&lt;---
+<P>
+A similar trick is used in the flags. The same flag names are used for
+both ends. Those before the <B>--to</B> flag describe the left side
+and those afterwards describe the right side. When <B>pluto</B> attempts
+to use the connection, it decides whether it is the left side or the right
+side of the connection, based on the IP numbers of its interfaces.
+<DL COMPACT>
+<DT><B>--id</B>&nbsp;<I>id</I><DD>
+the identity of the end. Currently, this can be an IP address (specified
+as dotted quad or as a Fully Qualified Domain Name, which will be resolved
+immediately) or as a Fully Qualified Domain Name itself (prefixed by ``@''
+to signify that it should not be resolved), or as <A HREF="mailto:user@FQDN">user@FQDN</A>, or as the
+magic value <B>%myid</B>.
+<B>Pluto</B> only authenticates the identity, and does not use it for
+addressing, so, for example, an IP address need not be the one to which
+packets are to be sent. If the option is absent, the
+identity defaults to the IP address specified by <B>--host</B>.
+<B>%myid</B> allows the identity to be separately specified (by the <B>pluto</B> or <B>whack</B> option <B>--myid</B>
+or by the <B><A HREF="ipsec.conf.5.html">ipsec.conf</A></B>(5) <B>config setup</B> parameter myid).
+Otherwise, <B>pluto</B> tries to guess what <B>%myid</B> should stand for:
+the IP address of <B>%defaultroute</B>, if it is supported by a suitable TXT record in the reverse domain for that IP address,
+or the system's hostname, if it is supported by a suitable TXT record in its forward domain.
+
+<DT><B>--host</B>&nbsp;<I>ip-address</I><DD>
+<DT><B>--host</B>&nbsp;<B>%any</B><DD>
+<DT><B>--host</B>&nbsp;<B>%opportunistic</B><DD>
+the IP address of the end (generally the public interface).
+If <B>pluto</B> is to act as a responder
+for IKE negotiations initiated from unknown IP addresses (the
+``Road Warrior'' case), the
+IP address should be specified as <B>%any</B> (currently,
+the obsolete notation <B>0.0.0.0</B> is also accepted for this).
+If <B>pluto</B> is to opportunistically initiate the connection,
+use <B>%opportunistic</B>
+<DT><B>--ikeport</B>&nbsp;<I>port-number</I><DD>
+the UDP port that IKE listens to on that host. The default is 500.
+(<B>pluto</B> on this machine uses the port specified by its own command
+line argument, so this only affects where <B>pluto</B> sends messages.)
+<DT><B>--nexthop</B>&nbsp;<I>ip-address</I><DD>
+where to route packets for the peer's client (presumably for the peer too,
+but it will not be used for this).
+When <B>pluto</B> installs an IPsec SA, it issues a route command.
+It uses the nexthop as the gateway.
+The default is the peer's IP address (this can be explicitly written as
+<B>%direct</B>; the obsolete notation <B>0.0.0.0</B> is accepted).
+This option is necessary if <B>pluto</B>'s host's interface used for sending
+packets to the peer is neither point-to-point nor directly connected to the
+peer.
+<DT><B>--client</B>&nbsp;<I>subnet</I><DD>
+the subnet for which the IPsec traffic will be destined. If not specified,
+the host will be the client.
+The subnet can be specified in any of the forms supported by <I><A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A></I>(3).
+The general form is <I>address</I>/<I>mask</I>. The <I>address</I> can be either
+a domain name or four decimal numbers (specifying octets) separated by dots.
+The most convenient form of the <I>mask</I> is a decimal integer, specifying
+the number of leading one bits in the mask. So, for example, 10.0.0.0/8
+would specify the class A network ``Net 10''.
+<DT><B>--dnskeyondemand]</B><DD>
+specifies that when an RSA public key is needed to authenticate this
+host, and it isn't already known, fetch it from DNS.
+<DT><B>--updown</B>&nbsp;<I>updown</I><DD>
+specifies an external shell command to be run whenever <B>pluto</B>
+brings up or down a connection.
+The script is used to build a shell command, so it may contain positional
+parameters, but ought not to have punctuation that would cause the
+resulting command to be ill-formed.
+The default is <I>ipsec _updown</I>.
+<DT><B>--to</B><DD>
+separates the specification of the left and right ends of the connection.
+</DL>
+<P>
+
+The potential connection description also specifies characteristics of
+rekeying and security.
+<DL COMPACT>
+<DT><B>--psk</B><DD>
+Propose and allow preshared secret authentication for IKE peers. This authentication
+requires that each side use the same secret. May be combined with <B>--rsasig</B>;
+at least one must be specified.
+<DT><B>--rsasig</B><DD>
+Propose and allow RSA signatures for authentication of IKE peers. This authentication
+requires that each side have have a private key of its own and know the
+public key of its peer. May be combined with <B>--psk</B>;
+at least one must be specified.
+<DT><B>--encrypt</B><DD>
+All proposed or accepted IPsec SAs will include non-null ESP.
+The actual choices of transforms are wired into <B>pluto</B>.
+<DT><B>--authenticate</B><DD>
+All proposed IPsec SAs will include AH.
+All accepted IPsec SAs will include AH or ESP with authentication.
+The actual choices of transforms are wired into <B>pluto</B>.
+Note that this has nothing to do with IKE authentication.
+<DT><B>--compress</B><DD>
+All proposed IPsec SAs will include IPCOMP (compression).
+This will be ignored if KLIPS is not configured with IPCOMP support.
+<DT><B>--tunnel</B><DD>
+the IPsec SA should use tunneling. Implicit if the SA is for clients.
+Must only be used with <B>--authenticate</B> or <B>--encrypt</B>.
+<DT><B>--ipv4</B><DD>
+The host addresses will be interpreted as IPv4 addresses. This is the
+default. Note that for a connection, all host addresses must be of
+the same Address Family (IPv4 and IPv6 use different Address Families).
+<DT><B>--ipv6</B><DD>
+The host addresses (including nexthop) will be interpreted as IPv6 addresses.
+Note that for a connection, all host addresses must be of
+the same Address Family (IPv4 and IPv6 use different Address Families).
+<DT><B>--tunnelipv4</B><DD>
+The client addresses will be interpreted as IPv4 addresses. The default is
+to match what the host will be. This does not imply <B>--tunnel</B> so the
+flag can be safely used when no tunnel is actually specified.
+Note that for a connection, all tunnel addresses must be of the same
+Address Family.
+<DT><B>--tunnelipv6</B><DD>
+The client addresses will be interpreted as IPv6 addresses. The default is
+to match what the host will be. This does not imply <B>--tunnel</B> so the
+flag can be safely used when no tunnel is actually specified.
+Note that for a connection, all tunnel addresses must be of the same
+Address Family.
+<DT><B>--pfs</B><DD>
+There should be Perfect Forward Secrecy - new keying material will
+be generated for each IPsec SA rather than being derived from the ISAKMP
+SA keying material.
+Since the group to be used cannot be negotiated (a dubious feature of the
+standard), <B>pluto</B> will propose the same group that was used during Phase 1.
+We don't implement a stronger form of PFS which would require that the
+ISAKMP SA be deleted after the IPSEC SA is negotiated.
+<DT><B>--disablearrivalcheck</B><DD>
+If the connection is a tunnel, allow packets arriving through the tunnel
+to have any source and destination addresses.
+</DL>
+<P>
+
+If none of the <B>--encrypt</B>, <B>--authenticate</B>, <B>--compress</B>,
+or <B>--pfs</B> flags is given, the initiating the connection will
+only build an ISAKMP SA. For such a connection, client subnets have
+no meaning and must not be specified.
+<P>
+
+More work is needed to allow for flexible policies. Currently
+policy is hardwired in the source file spdb.c. The ISAKMP SAs may use
+Oakley groups MODP1024 and MODP1536; 3DES encryption; SHA1-96
+and MD5-96 authentication. The IPsec SAs may use 3DES and
+MD5-96 or SHA1-96 for ESP, or just MD5-96 or SHA1-96 for AH.
+IPCOMP Compression is always Deflate.
+<DL COMPACT>
+<DT><B>--ikelifetime</B>&nbsp;<I>seconds</I><DD>
+how long <B>pluto</B> will propose that an ISAKMP SA be allowed to live.
+The default is 3600 (one hour) and the maximum is 28800 (8 hours).
+This option will not affect what is accepted.
+<B>pluto</B> will reject proposals that exceed the maximum.
+<DT><B>--ipseclifetime</B>&nbsp;<I>seconds</I><DD>
+how long <B>pluto</B> will propose that an IPsec SA be allowed to live.
+The default is 28800 (eight hours) and the maximum is 86400 (one day).
+This option will not affect what is accepted.
+<B>pluto</B> will reject proposals that exceed the maximum.
+<DT><B>--rekeymargin</B>&nbsp;<I>seconds</I><DD>
+how long before an SA's expiration should <B>pluto</B> try to negotiate
+a replacement SA. This will only happen if <B>pluto</B> was the initiator.
+The default is 540 (nine minutes).
+<DT><B>--rekeyfuzz</B>&nbsp;<I>percentage</I><DD>
+maximum size of random component to add to rekeymargin, expressed as
+a percentage of rekeymargin. <B>pluto</B> will select a delay uniformly
+distributed within this range. By default, the percentage will be 100.
+If greater determinism is desired, specify 0. It may be appropriate
+for the percentage to be much larger than 100.
+<DT><B>--keyingtries</B>&nbsp;<I>count</I><DD>
+how many times <B>pluto</B> should try to negotiate an SA,
+either for the first time or for rekeying.
+A value of 0 is interpreted as a very large number: never give up.
+The default is three.
+<DT><B>--dontrekey</B><DD>
+A misnomer.
+Only rekey a connection if we were the Initiator and there was recent
+traffic on the existing connection.
+This applies to Phase 1 and Phase 2.
+This is currently the only automatic way for a connection to terminate.
+It may be useful with Road Warrior or Opportunistic connections.
+<BR>
+
+Since SA lifetime negotiation is take-it-or-leave it, a Responder
+normally uses the shorter of the negotiated or the configured lifetime.
+This only works because if the lifetime is shorter than negotiated,
+the Responder will rekey in time so that everything works.
+This interacts badly with <B>--dontrekey</B>. In this case,
+the Responder will end up rekeying to rectify a shortfall in an IPsec SA
+lifetime; for an ISAKMP SA, the Responder will accept the negotiated
+lifetime.
+<DT><B>--delete</B><DD>
+when used in the connection form, it causes any previous connection
+with this name to be deleted before this one is added. Unlike a
+normal delete, no diagnostic is produced if there was no previous
+connection to delete. Any routing in place for the connection is undone.
+</DL>
+<P>
+
+The delete form deletes a named connection description and any
+SAs established or negotiations initiated using this connection.
+Any routing in place for the connection is undone.
+<DL COMPACT>
+<DT><B>--delete</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The deletestate form deletes the state object with the specified serial number.
+This is useful for selectively deleting instances of connections.
+<DL COMPACT>
+<DT><B>--deletestate</B>&nbsp;<I>state-number</I><DD>
+</DL>
+<P>
+
+The route form of the <B>whack</B> command tells <B>pluto</B> to set up
+routing for a connection.
+Although like a traditional route, it uses an ipsec device as a
+virtual interface.
+Once routing is set up, no packets will be
+sent ``in the clear'' to the peer's client specified in the connection.
+A TRAP shunt eroute will be installed; if outbound traffic is caught,
+Pluto will initiate the connection.
+An explicit <B>whack</B> route is not always needed: if it hasn't been
+done when an IPsec SA is being installed, one will be automatically attempted.
+<P>
+
+When a routing is attempted for a connection, there must not already
+be a routing for a different connection with the same subnet but different
+interface or destination, or if
+there is, it must not be being used by an IPsec SA. Otherwise the
+attempt will fail.
+<DL COMPACT>
+<DT><B>--route</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The unroute form of the <B>whack</B> command tells <B>pluto</B> to undo
+a routing. <B>pluto</B> will refuse if an IPsec SA is using the connection.
+If another connection is sharing the same routing, it will be left in place.
+Without a routing, packets will be sent without encryption or authentication.
+<DL COMPACT>
+<DT><B>--unroute</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The initiate form tells <B>pluto</B> to initiate a negotiation with another
+<B>pluto</B> (or other IKE daemon) according to the named connection.
+Initiation requires a route that <B>--route</B> would provide;
+if none is in place at the time an IPsec SA is being installed,
+<B>pluto</B> attempts to set one up.
+<DL COMPACT>
+<DT><B>--initiate</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+<DT><B>--asynchronous<DD>
+</DL>
+<P>
+
+The initiate form of the whack</B> command will relay back from
+<B>pluto</B> status information via the UNIX domain socket (unless
+--asynchronous is specified). The status information is meant to
+look a bit like that from <B>FTP</B>. Currently <B>whack</B> simply
+copies this to stderr. When the request is finished (eg. the SAs are
+established or <B>pluto</B> gives up), <B>pluto</B> closes the channel,
+causing <B>whack</B> to terminate.
+<P>
+
+The opportunistic initiate form is mainly used for debugging.
+<DL COMPACT>
+<DT><B>--tunnelipv4</B><DD>
+<DT><B>--tunnelipv6</B><DD>
+<DT><B>--oppohere</B>&nbsp;<I>ip-address</I><DD>
+<DT><B>--oppothere</B>&nbsp;<I>ip-address</I><DD>
+</DL>
+<P>
+
+This will cause <B>pluto</B> to attempt to opportunistically initiate a
+connection from here to the there, even if a previous attempt
+had been made.
+The whack log will show the progress of this attempt.
+<P>
+
+The terminate form tells <B>pluto</B> to delete any SAs that use the specified
+connection and to stop any negotiations in process.
+It does not prevent new negotiations from starting (the delete form
+has this effect).
+<DL COMPACT>
+<DT><B>--terminate</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The public key for informs <B>pluto</B> of the RSA public key for a potential peer.
+Private keys must be kept secret, so they are kept in
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5).
+
+<DL COMPACT>
+<DT><B>--keyid&nbsp;</B><I>id</I><DD>
+specififies the identity of the peer for which a public key should be used.
+Its form is identical to the identity in the connection.
+If no public key is specified, <B>pluto</B> attempts to find KEY records
+from DNS for the id (if a FQDN) or through reverse lookup (if an IP address).
+Note that there several interesting ways in which this is not secure.
+<DT><B>--addkey</B><DD>
+specifies that the new key is added to the collection; otherwise the
+new key replaces any old ones.
+<DT><B>--pubkeyrsa&nbsp;</B><I>key</I><DD>
+specifies the value of the RSA public key. It is a sequence of bytes
+as described in RFC 2537 ``RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)''.
+It is denoted in a way suitable for <I><A HREF="ipsec_ttodata.3.html">ipsec_ttodata</A></I>(3).
+For example, a base 64 numeral starts with 0s.
+</DL>
+<P>
+
+The listen form tells <B>pluto</B> to start listening for IKE requests
+on its public interfaces. To avoid race conditions, it is normal to
+load the appropriate connections into <B>pluto</B> before allowing it
+to listen. If <B>pluto</B> isn't listening, it is pointless to
+initiate negotiations, so it will refuse requests to do so. Whenever
+the listen form is used, <B>pluto</B> looks for public interfaces and
+will notice when new ones have been added and when old ones have been
+removed. This is also the trigger for <B>pluto</B> to read the
+<I>ipsec.secrets</I> file. So listen may useful more than once.
+<DL COMPACT>
+<DT><B>--listen</B><DD>
+start listening for IKE traffic on public interfaces.
+<DT><B>--unlisten</B><DD>
+stop listening for IKE traffic on public interfaces.
+</DL>
+<P>
+
+The status form will display information about the internal state of
+<B>pluto</B>: information about each potential connection, about
+each state object, and about each shunt that <B>pluto</B> is managing
+without an associated connection.
+<DL COMPACT>
+<DT><B>--status</B><DD>
+</DL>
+<P>
+
+The shutdown form is the proper way to shut down <B>pluto</B>.
+It will tear down the SAs on this machine that <B>pluto</B> has negotiated.
+It does not inform its peers, so the SAs on their machines remain.
+<DL COMPACT>
+<DT><B>--shutdown</B><DD>
+</DL>
+<A NAME="lbAM">&nbsp;</A>
+<H3>Examples</H3>
+
+<P>
+
+It would be normal to start <B>pluto</B> in one of the system initialization
+scripts. It needs to be run by the superuser. Generally, no arguments are needed.
+To run in manually, the superuser can simply type
+<P>
+&nbsp;&nbsp;&nbsp;ipsec pluto
+<P>
+The command will immediately return, but a <B>pluto</B> process will be left
+running, waiting for requests from <B>whack</B> or a peer.
+<P>
+
+Using <B>whack</B>, several potential connections would be described:
+<DL COMPACT>
+<DT>
+
+&nbsp;&nbsp;&nbsp;ipsec whack --name&nbsp;silly
+--host&nbsp;127.0.0.1 --to --host&nbsp;127.0.0.2
+--ikelifetime&nbsp;900 --ipseclifetime&nbsp;800 --keyingtries&nbsp;3
+
+</DL>
+<P>
+
+<DD>Since this silly connection description specifies neither encryption,
+authentication, nor tunneling, it could only be used to establish
+an ISAKMP SA.
+<DL COMPACT>
+<DT>
+
+&nbsp;&nbsp;&nbsp;ipsec whack --name&nbsp;secret --host&nbsp;10.0.0.1 --client&nbsp;10.0.1.0/24
+--to --host&nbsp;10.0.0.2 --client&nbsp;10.0.2.0/24
+--encrypt
+
+</DL>
+<P>
+
+<DD>This is something that must be done on both sides. If the other
+side is <B>pluto</B>, the same <B>whack</B> command could be used on it
+(the command syntax is designed to not distinguish which end is ours).
+<P>
+
+Now that the connections are specified, <B>pluto</B> is ready to handle
+requests and replies via the public interfaces. We must tell it to discover
+those interfaces and start accepting messages from peers:
+<P>
+&nbsp;&nbsp;&nbsp;ipsec whack --listen
+<P>
+
+If we don't immediately wish to bring up a secure connection between
+the two clients, we might wish to prevent insecure traffic.
+The routing form asks <B>pluto</B> to cause the packets sent from
+our client to the peer's client to be routed through the ipsec0
+device; if there is no SA, they will be discarded:
+<P>
+&nbsp;&nbsp;&nbsp;ipsec whack --route secret
+<P>
+
+Finally, we are ready to get <B>pluto</B> to initiate negotiation
+for an IPsec SA (and implicitly, an ISAKMP SA):
+<P>
+&nbsp;&nbsp;&nbsp;ipsec whack --initiate&nbsp;--name&nbsp;secret
+<P>
+A small log of interesting events will appear on standard output
+(other logging is sent to syslog).
+<P>
+
+<B>whack</B> can also be used to terminate <B>pluto</B> cleanly, tearing down
+all SAs that it has negotiated.
+<P>
+&nbsp;&nbsp;&nbsp;ipsec whack --shutdown
+<P>
+Notification of any IPSEC SA deletion, but not ISAKMP SA deletion
+is sent to the peer. Unfortunately, such Notification is not reliable.
+Furthermore, <B>pluto</B> itself ignores Notifications.
+<A NAME="lbAN">&nbsp;</A>
+<H3>The updown command</H3>
+
+<P>
+
+Whenever <B>pluto</B> brings a connection up or down, it invokes
+the updown command. This command is specified using the <B>--updown</B>
+option. This allows for customized control over routing and firewall manipulation.
+<P>
+
+The updown is invoked for five different operations. Each of
+these operations can be for our client subnet or for our host itself.
+<DL COMPACT>
+<DT><B>prepare-host</B> or <B>prepare-client</B><DD>
+is run before bringing up a new connection if no other connection
+with the same clients is up. Generally, this is useful for deleting a
+route that might have been set up before <B>pluto</B> was run or
+perhaps by some agent not known to <B>pluto</B>.
+<DT><B>route-host</B> or <B>route-client</B><DD>
+is run when bringing up a connection for a new peer client subnet
+(even if <B>prepare-host</B> or <B>prepare-client</B> was run). The
+command should install a suitable route. Routing decisions are based
+only on the destination (peer's client) subnet address, unlike eroutes
+which discriminate based on source too.
+<DT><B>unroute-host</B> or <B>unroute-client</B><DD>
+is run when bringing down the last connection for a particular peer
+client subnet. It should undo what the <B>route-host</B> or <B>route-client</B>
+did.
+<DT><B>up-host</B> or <B>up-client</B><DD>
+is run when bringing up a tunnel eroute with a pair of client subnets
+that does not already have a tunnel eroute.
+This command should install firewall rules as appropriate.
+It is generally a good idea to allow IKE messages (UDP port 500)
+travel between the hosts.
+<DT><B>down-host</B> or <B>down-client</B><DD>
+is run when bringing down the eroute for a pair of client subnets.
+This command should delete firewall rules as appropriate. Note that
+there may remain some inbound IPsec SAs with these client subnets.
+</DL>
+<P>
+
+The script is passed a large number of environment variables to specify
+what needs to be done.
+<DL COMPACT>
+<DT><B>PLUTO_VERSION</B><DD>
+indicates what version of this interface is being used. This document
+describes version 1.1. This is upwardly compatible with version 1.0.
+<DT><B>PLUTO_VERB</B><DD>
+specifies the name of the operation to be performed
+(<B>prepare-host</B>,r <B>prepare-client</B>,
+<B>up-host</B>, <B>up-client</B>,
+<B>down-host</B>, or <B>down-client</B>). If the address family for
+security gateway to security gateway communications is IPv6, then
+a suffix of -v6 is added to the verb.
+<DT><B>PLUTO_CONNECTION</B><DD>
+is the name of the connection for which we are routing.
+<DT><B>PLUTO_NEXT_HOP</B><DD>
+is the next hop to which packets bound for the peer must be sent.
+<DT><B>PLUTO_INTERFACE</B><DD>
+is the name of the ipsec interface to be used.
+<DT><B>PLUTO_ME</B><DD>
+is the IP address of our host.
+<DT><B>PLUTO_MY_CLIENT</B><DD>
+is the IP address / count of our client subnet.
+If the client is just the host, this will be the host's own IP address / max
+(where max is 32 for IPv4 and 128 for IPv6).
+<DT><B>PLUTO_MY_CLIENT_NET</B><DD>
+is the IP address of our client net.
+If the client is just the host, this will be the host's own IP address.
+<DT><B>PLUTO_MY_CLIENT_MASK</B><DD>
+is the mask for our client net.
+If the client is just the host, this will be 255.255.255.255.
+<DT><B>PLUTO_PEER</B><DD>
+is the IP address of our peer.
+<DT><B>PLUTO_PEER_CLIENT</B><DD>
+is the IP address / count of the peer's client subnet.
+If the client is just the peer, this will be the peer's own IP address / max
+(where max is 32 for IPv4 and 128 for IPv6).
+<DT><B>PLUTO_PEER_CLIENT_NET</B><DD>
+is the IP address of the peer's client net.
+If the client is just the peer, this will be the peer's own IP address.
+<DT><B>PLUTO_PEER_CLIENT_MASK</B><DD>
+is the mask for the peer's client net.
+If the client is just the peer, this will be 255.255.255.255.
+</DL>
+<P>
+
+All output sent by the script to stderr or stdout is logged. The
+script should return an exit status of 0 if and only if it succeeds.
+<P>
+
+<B>Pluto</B> waits for the script to finish and will not do any other
+processing while it is waiting.
+The script may assume that <B>pluto</B> will not change anything
+while the script runs.
+The script should avoid doing anything that takes much time and it
+should not issue any command that requires processing by <B>pluto</B>.
+Either of these activities could be performed by a background
+subprocess of the script.
+<A NAME="lbAO">&nbsp;</A>
+<H3>Rekeying</H3>
+
+<P>
+
+When an SA that was initiated by <B>pluto</B> has only a bit of
+lifetime left,
+<B>pluto</B> will initiate the creation of a new SA. This applies to
+ISAKMP and IPsec SAs.
+The rekeying will be initiated when the SA's remaining lifetime is
+less than the rekeymargin plus a random percentage, between 0 and
+rekeyfuzz, of the rekeymargin.
+<P>
+
+Similarly, when an SA that was initiated by the peer has only a bit of
+lifetime left, <B>pluto</B> will try to initiate the creation of a
+replacement.
+To give preference to the initiator, this rekeying will only be initiated
+when the SA's remaining lifetime is half of rekeymargin.
+If rekeying is done by the responder, the roles will be reversed: the
+responder for the old SA will be the initiator for the replacement.
+The former initiator might also initiate rekeying, so there may
+be redundant SAs created.
+To avoid these complications, make sure that rekeymargin is generous.
+<P>
+
+One risk of having the former responder initiate is that perhaps
+none of its proposals is acceptable to the former initiator
+(they have not been used in a successful negotiation).
+To reduce the chances of this happening, and to prevent loss of security,
+the policy settings are taken from the old SA (this is the case even if
+the former initiator is initiating).
+These may be stricter than those of the connection.
+<P>
+
+<B>pluto</B> will not rekey an SA if that SA is not the most recent of its
+type (IPsec or ISAKMP) for its potential connection.
+This avoids creating redundant SAs.
+<P>
+
+The random component in the rekeying time (rekeyfuzz) is intended to
+make certain pathological patterns of rekeying unstable. If both
+sides decide to rekey at the same time, twice as many SAs as necessary
+are created. This could become a stable pattern without the
+randomness.
+<P>
+
+Another more important case occurs when a security gateway has SAs
+with many other security gateways. Each of these connections might
+need to be rekeyed at the same time. This would cause a high peek
+requirement for resources (network bandwidth, CPU time, entropy for
+random numbers). The rekeyfuzz can be used to stagger the rekeying
+times.
+<P>
+
+Once a new set of SAs has been negotiated, <B>pluto</B> will never send
+traffic on a superseded one. Traffic will be accepted on an old SA
+until it expires.
+<A NAME="lbAP">&nbsp;</A>
+<H3>Selecting a Connection When Responding: Road Warrior Support</H3>
+
+<P>
+
+When <B>pluto</B> receives an initial Main Mode message, it needs to
+decide which connection this message is for. It picks based solely on
+the source and destination IP addresses of the message. There might
+be several connections with suitable IP addresses, in which case one
+of them is arbitrarily chosen. (The ISAKMP SA proposal contained in
+the message could be taken into account, but it is not.)
+<P>
+
+The ISAKMP SA is negotiated before the parties pass further
+identifying information, so all ISAKMP SA characteristics specified in
+the connection description should be the same for every connection
+with the same two host IP addresses. At the moment, the only
+characteristic that might differ is authentication method.
+<P>
+
+Up to this point,
+all configuring has presumed that the IP addresses
+are known to all parties ahead of time. This will not work
+when either end is mobile (or assigned a dynamic IP address for other
+reasons). We call this situation ``Road Warrior''. It is fairly tricky
+and has some important limitations, most of which are features of
+the IKE protocol.
+<P>
+
+Only the initiator may be mobile:
+the initiator may have an IP number unknown to the responder. When
+the responder doesn't recognize the IP address on the first Main Mode
+packet, it looks for a connection with itself as one end and <B>%any</B>
+as the other.
+If it cannot find one, it refuses to negotiate. If it
+does find one, it creates a temporary connection that is a duplicate
+except with the <B>%any</B> replaced by the source IP address from the
+packet; if there was no identity specified for the peer, the new IP
+address will be used.
+<P>
+
+When <B>pluto</B> is using one of these temporary connections and
+needs to find the preshared secret or RSA private key in <I>ipsec.secrets</I>,
+and and the connection specified no identity for the peer, <B>%any</B>
+is used as its identity. After all, the real IP address was apparently
+unknown to the configuration, so it is unreasonable to require that
+it be used in this table.
+<P>
+
+Part way into the Phase 1 (Main Mode) negotiation using one of these
+temporary connection descriptions, <B>pluto</B> will be receive an
+Identity Payload. At this point, <B>pluto</B> checks for a more
+appropriate connection, one with an identity for the peer that matches
+the payload but which would use the same keys so-far used for
+authentication. If it finds one, it will switch to using this better
+connection (or a temporary derived from this, if it has <B>%any</B>
+for the peer's IP address). It may even turn out that no connection
+matches the newly discovered identity, including the current connection;
+if so, <B>pluto</B> terminates negotiation.
+<P>
+
+Unfortunately, if preshared secret authentication is being used, the
+Identity Payload is encrypted using this secret, so the secret must be
+selected by the responder without knowing this payload. This
+limits there to being at most one preshared secret for all Road Warrior
+systems connecting to a host. RSA Signature authentications does not
+require that the responder know how to select the initiator's public key
+until after the initiator's Identity Payload is decoded (using the
+responder's private key, so that must be preselected).
+<P>
+
+When <B>pluto</B> is responding to a Quick Mode negotiation via one of these
+temporary connection descriptions, it may well find that the subnets
+specified by the initiator don't match those in the temporary
+connection description. If so, it will look for a connection with
+matching subnets, its own host address, a peer address of <B>%any</B>
+and matching identities.
+If it finds one, a new temporary connection is derived from this one
+and used for the Quick Mode negotiation of IPsec SAs. If it does not
+find one, <B>pluto</B> terminates negotiation.
+<P>
+
+Be sure to specify an appropriate nexthop for the responder
+to send a message to the initiator: <B>pluto</B> has no way of guessing
+it (if forwarding isn't required, use an explicit <B>%direct</B> as the nexthop
+and the IP address of the initiator will be filled in; the obsolete
+notation <B>0.0.0.0</B> is still accepted).
+<P>
+
+<B>pluto</B> has no special provision for the initiator side. The current
+(possibly dynamic) IP address and nexthop must be used in defining
+connections. These must be
+properly configured each time the initiator's IP address changes.
+<B>pluto</B> has no mechanism to do this automatically.
+<P>
+
+Although we call this Road Warrior Support, it could also be used to
+support encrypted connections with anonymous initiators. The
+responder's organization could announce the preshared secret that would be used
+with unrecognized initiators and let anyone connect. Of course the initiator's
+identity would not be authenticated.
+<P>
+
+If any Road Warrior connections are supported, <B>pluto</B> cannot
+reject an exchange initiated by an unknown host until it has
+determined that the secret is not shared or the signature is invalid.
+This must await the
+third Main Mode message from the initiator. If no Road Warrior
+connection is supported, the first message from an unknown source
+would be rejected. This has implications for ease of debugging
+configurations and for denial of service attacks.
+<P>
+
+Although a Road Warrior connection must be initiated by the mobile
+side, the other side can and will rekey using the temporary connection
+it has created. If the Road Warrior wishes to be able to disconnect,
+it is probably wise to set <B>--keyingtries</B> to 1 in the
+connection on the non-mobile side to prevent it trying to rekey the
+connection. Unfortunately, there is no mechanism to unroute the
+connection automatically.
+<A NAME="lbAQ">&nbsp;</A>
+<H3>Debugging</H3>
+
+<P>
+
+<B>pluto</B> accepts several optional arguments, useful mostly for debugging.
+Except for <B>--interface</B>, each should appear at most once.
+<DL COMPACT>
+<DT><B>--interface</B> <I>interfacename</I><DD>
+specifies that the named real public network interface should be considered.
+The interface name specified should not be <B>ipsec</B><I>N</I>.
+If the option doesn't appear, all interfaces are considered.
+To specify several interfaces, use the option once for each.
+One use of this option is to specify which interface should be used
+when two or more share the same IP address.
+<DT><B>--ikeport</B> <I>port-number</I><DD>
+changes the UDP port that <B>pluto</B> will use
+(default, specified by IANA: 500)
+<DT><B>--ctlbase</B> <I>path</I><DD>
+basename for control files.
+<I>path</I>.ctl is the socket through which <B>whack</B> communicates with
+<B>pluto</B>.
+<I>path</I>.pid is the lockfile to prevent multiple <B>pluto</B> instances.
+The default is <I>/var/run/pluto</I>).
+<DT><B>--secretsfile</B> <I>file</I><DD>
+specifies the file for authentication secrets
+(default: <I>/etc/ipsec.secrets</I>).
+This name is subject to ``globbing'' as in <I><A HREF="sh.1.html">sh</A></I>(1),
+so every file with a matching name is processed.
+Quoting is generally needed to prevent the shell from doing the globbing.
+<DT><B>--adns</B> <I>pathname</I><DD>
+<DT><B>--lwdnsq</B> <I>pathname</I><DD>
+specifies where to find <B>pluto</B>'s helper program for asynchronous DNS lookup.
+<B>pluto</B> can be built to use one of two helper programs: <B>_pluto_adns</B>
+or <B>lwdnsq</B>. You must use the program for which it was built.
+By default, <B>pluto</B> will look for the program in
+<B>$IPSEC_DIR</B> (if that environment variable is defined) or, failing that,
+in the same directory as <B>pluto</B>.
+<DT><B>--nofork</B><DD>
+disable ``daemon fork'' (default is to fork). In addition, after the
+lock file and control socket are created, print the line ``Pluto
+initialized'' to standard out.
+<DT><B>--noklips</B><DD>
+don't actually implement negotiated IPsec SAs
+<DT><B>--uniqueids</B><DD>
+if this option has been selected, whenever a new ISAKMP SA is
+established, any connection with the same Peer ID but a different
+Peer IP address is unoriented (causing all its SAs to be deleted).
+This helps clean up dangling SAs when a connection is lost and
+then regained at another IP address.
+<DT><B>--stderrlog</B><DD>
+log goes to standard out {default is to use <I><A HREF="syslogd.8.html">syslogd</A></I>(8))
+</DL>
+<P>
+
+For example
+<DL COMPACT>
+<DT>pluto --secretsfile&nbsp;ipsec.secrets --ctlbase&nbsp;pluto.base --ikeport&nbsp;8500 --nofork --noklips --stderrlog<DD>
+</DL>
+<P>
+
+lets one test <B>pluto</B> without using the superuser account.
+<P>
+
+<B>pluto</B> is willing to produce a prodigious amount of debugging
+information. To do so, it must be compiled with -DDEBUG. There are
+several classes of debugging output, and <B>pluto</B> may be directed to
+produce a selection of them. All lines of
+debugging output are prefixed with ``|&nbsp;'' to distinguish them from error
+messages.
+<P>
+
+When <B>pluto</B> is invoked, it may be given arguments to specify
+which classes to output. The current options are:
+<DL COMPACT>
+<DT><B>--debug-raw</B><DD>
+show the raw bytes of messages
+<DT><B>--debug-crypt</B><DD>
+show the encryption and decryption of messages
+<DT><B>--debug-parsing</B><DD>
+show the structure of input messages
+<DT><B>--debug-emitting</B><DD>
+show the structure of output messages
+<DT><B>--debug-control</B><DD>
+show <B>pluto</B>'s decision making
+<DT><B>--debug-lifecycle</B><DD>
+[this option is temporary] log more detail of lifecycle of SAs
+<DT><B>--debug-klips</B><DD>
+show <B>pluto</B>'s interaction with <B>KLIPS</B>
+<DT><B>--debug-dns</B><DD>
+show <B>pluto</B>'s interaction with <B>DNS</B> for KEY and TXT records
+<DT><B>--debug-oppo</B><DD>
+show why <B>pluto</B> didn't find a suitable DNS TXT record to authorize opportunistic initiation
+<DT><B>--debug-all</B><DD>
+all of the above
+<DT><B>--debug-private</B><DD>
+allow debugging output with private keys.
+<DT><B>--debug-none</B><DD>
+none of the above
+</DL>
+<P>
+
+The debug form of the
+<B>whack</B> command will change the selection in a running
+<B>pluto</B>.
+If a connection name is specified, the flags are added whenever
+<B>pluto</B> has identified that it is dealing with that connection.
+Unfortunately, this is often part way into the operation being observed.
+<P>
+
+For example, to start a <B>pluto</B> with a display of the structure of input
+and output:
+<DL COMPACT>
+<DT><DD>
+pluto --debug-emitting --debug-parsing
+</DL>
+<P>
+
+To later change this <B>pluto</B> to only display raw bytes:
+<DL COMPACT>
+<DT><DD>
+whack --debug-raw
+</DL>
+<P>
+
+For testing, SSH's IKE test page is quite useful:
+<DL COMPACT>
+<DT><DD>
+<I><A HREF="http://isakmp-test.ssh.fi/">http://isakmp-test.ssh.fi/</A></I>
+</DL>
+<P>
+
+Hint: ISAKMP SAs are often kept alive by IKEs even after the IPsec SA
+is established. This allows future IPsec SA's to be negotiated
+directly. If one of the IKEs is restarted, the other may try to use
+the ISAKMP SA but the new IKE won't know about it. This can lead to
+much confusion. <B>pluto</B> is not yet smart enough to get out of such a
+mess.
+<A NAME="lbAR">&nbsp;</A>
+<H3>Pluto's Behaviour When Things Go Wrong</H3>
+
+<P>
+
+When <B>pluto</B> doesn't understand or accept a message, it just
+ignores the message. It is not yet capable of communicating the
+problem to the other IKE daemon (in the future it might use
+Notifications to accomplish this in many cases). It does log a diagnostic.
+<P>
+
+When <B>pluto</B> gets no response from a message, it resends the same
+message (a message will be sent at most three times). This is
+appropriate: UDP is unreliable.
+<P>
+
+When pluto gets a message that it has already seen, there are many
+cases when it notices and discards it. This too is appropriate for UDP.
+<P>
+
+Combine these three rules, and you can explain many apparently
+mysterious behaviours. In a <B>pluto</B> log, retrying isn't usually the
+interesting event. The critical thing is either earlier (<B>pluto</B>
+got a message which it didn't like and so ignored, so it was still
+awaiting an acceptable message and got impatient) or on the other
+system (<B>pluto</B> didn't send a reply because it wasn't happy with
+the previous message).
+<A NAME="lbAS">&nbsp;</A>
+<H3>Notes</H3>
+
+<P>
+
+If <B>pluto</B> is compiled without -DKLIPS, it negotiates Security
+Associations but never ask the kernel to put them in place and never
+makes routing changes. This allows <B>pluto</B> to be tested on systems
+without <B>KLIPS</B>, but makes it rather useless.
+<P>
+
+Each IPsec SA is assigned an SPI, a 32-bit number used to refer to the SA.
+The IKE protocol lets the destination of the SA choose the SPI.
+The range 0 to 0xFF is reserved for IANA.
+<B>Pluto</B> also avoids choosing an SPI in the range 0x100 to 0xFFF,
+leaving these SPIs free for manual keying.
+Remember that the peer, if not <B>pluto</B>, may well chose
+SPIs in this range.
+<A NAME="lbAT">&nbsp;</A>
+<H3>Policies</H3>
+
+<P>
+
+This catalogue of policies may be of use when trying to configure
+<B>Pluto</B> and another IKE implementation to interoperate.
+<P>
+
+In Phase 1, only Main Mode is supported. We are not sure that
+Aggressive Mode is secure. For one thing, it does not support
+identity protection. It may allow more severe Denial Of Service
+attacks.
+<P>
+
+No Informational Exchanges are supported. These are optional and
+since their delivery is not assured, they must not matter.
+It is the case that some IKE implementations won't interoperate
+without Informational Exchanges, but we feel they are broken.
+<P>
+
+No Informational Payloads are supported. These are optional, but
+useful. It is of concern that these payloads are not authenticated in
+Phase 1, nor in those Phase 2 messages authenticated with <A HREF="HASH.3.html">HASH</A>(3).
+<DL COMPACT>
+<DT>*<DD>
+Diffie Hellman Groups MODP 1024 and MODP 1536 (2 and 5)
+are supported.
+Group MODP768 (1) is not supported because it is too weak.
+<DT>*<DD>
+Host authetication can be done by RSA Signatures or Pre-Shared
+Secrets.
+<DT>*<DD>
+3DES CBC (Cypher Block Chaining mode) is the only encryption
+supported, both for ISAKMP SAs and IPSEC SAs.
+<DT>*<DD>
+MD5 and SHA1 hashing are supported for packet authentication in both
+kinds of SAs.
+<DT>*<DD>
+The ESP, AH, or AH plus ESP are supported. If, and only if, AH and
+ESP are combined, the ESP need not have its own authentication
+component. The selection is controlled by the --encrypt and
+--authenticate flags.
+<DT>*<DD>
+Each of these may be combined with IPCOMP Deflate compression,
+but only if the potential connection specifies compression and only
+if KLIPS is configured with IPCOMP support.
+<DT>*<DD>
+The IPSEC SAs may be tunnel or transport mode, where appropriate.
+The --tunnel flag controls this when <B>pluto</B> is initiating.
+<DT>*<DD>
+When responding to an ISAKMP SA proposal, the maximum acceptable
+lifetime is eight hours. The default is one hour. There is no
+minimum. The --ikelifetime flag controls this when <B>pluto</B>
+is initiating.
+<DT>*<DD>
+When responding to an IPSEC SA proposal, the maximum acceptable
+lifetime is one day. The default is eight hours. There is no
+minimum. The --ipseclifetime flag controls this when <B>pluto</B>
+is initiating.
+<DT>*<DD>
+PFS is acceptable, and will be proposed if the --pfs flag was
+specified. The DH group proposed will be the same as negotiated for
+Phase 1.
+</DL>
+<A NAME="lbAU">&nbsp;</A>
+<H2>SIGNALS</H2>
+
+<P>
+
+<B>Pluto</B> responds to <B>SIGHUP</B> by issuing a suggestion that ``<B>whack</B>
+--listen'' might have been intended.
+<P>
+
+<B>Pluto</B> exits when it recieves <B>SIGTERM</B>.
+<A NAME="lbAV">&nbsp;</A>
+<H2>EXIT STATUS</H2>
+
+<P>
+
+<B>pluto</B> normally forks a daemon process, so the exit status is
+normally a very preliminary result.
+<DL COMPACT>
+<DT>0<DD>
+means that all is OK so far.
+<DT>1<DD>
+means that something was wrong.
+<DT>10<DD>
+means that the lock file already exists.
+</DL>
+<P>
+
+If <B>whack</B> detects a problem, it will return an exit status of 1.
+If it received progress messages from <B>pluto</B>, it returns as status
+the value of the numeric prefix from the last such message
+that was not a message sent to syslog or a comment
+(but the prefix for success is treated as 0).
+Otherwise, the exit status is 0.
+<A NAME="lbAW">&nbsp;</A>
+<H2>FILES</H2>
+
+<I>/var/run/pluto.pid</I>
+<BR>
+
+<I>/var/run/pluto.ctl</I>
+<BR>
+
+<I>/etc/ipsec.secrets</I>
+<BR>
+
+<I>$IPSEC_LIBDIR/_pluto_adns</I>
+<BR>
+
+<I>$IPSEC_EXECDIR/lwdnsq</I>
+<BR>
+
+<I>/dev/urandom</I>
+<A NAME="lbAX">&nbsp;</A>
+<H2>ENVIRONMENT</H2>
+
+<I>IPSEC_LIBDIR</I>
+<BR>
+
+<I>IPSEC_EXECDIR</I>
+<BR>
+
+<I>IPSECmyid</I>
+<A NAME="lbAY">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<P>
+
+The rest of the FreeS/WAN distribution, in particular <I><A HREF="ipsec.8.html">ipsec</A></I>(8).
+<P>
+
+<I><A HREF="ipsec_auto.8.html">ipsec_auto</A></I>(8) is designed to make using <B>pluto</B> more pleasant.
+Use it!
+<P>
+
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5)
+
+describes the format of the secrets file.
+<P>
+
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3), part of the FreeS/WAN distribution, describes the
+forms that IP addresses may take.
+<I><A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A></I>(3), part of the FreeS/WAN distribution, describes the
+forms that subnet specifications.
+<P>
+
+For more information on IPsec, the mailing list, and the relevant
+documents, see:
+<DL COMPACT>
+<DT><DD>
+
+<I><A HREF="http://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html">http://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html</A></I>
+
+</DL>
+<P>
+
+At the time of writing, the most relevant IETF RFCs are:
+<DL COMPACT>
+<DT><DD>
+RFC2409 The Internet Key Exchange (IKE)
+<DT><DD>
+RFC2408 Internet Security Association and Key Management Protocol (ISAKMP)
+<DT><DD>
+RFC2407 The Internet IP Security Domain of Interpretation for ISAKMP
+</DL>
+<P>
+
+The FreeS/WAN web site &lt;<A HREF="htp://www.freeswan.org">htp://www.freeswan.org</A>&gt;
+and the mailing lists described there.
+<A NAME="lbAZ">&nbsp;</A>
+<H2>HISTORY</H2>
+
+This code is released under the GPL terms.
+See the accompanying file COPYING-2.0 for more details.
+The GPL does NOT apply to those pieces of code written by others
+which are included in this distribution, except as noted by the
+individual authors.
+<P>
+
+This software was originally written
+for the FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Angelos D. Keromytis
+(<A HREF="mailto:angelos@dsl.cis.upenn.edu">angelos@dsl.cis.upenn.edu</A>), in May/June 1997, in Athens, Greece.
+Thanks go to John Ioannidis for his help.
+<P>
+
+It is currently (2000)
+being developed and maintained by D. Hugh Redelmeier
+(<A HREF="mailto:hugh@mimosa.com">hugh@mimosa.com</A>), in Canada. The regulations of Greece and Canada
+allow us to make the code freely redistributable.
+<P>
+
+Kai Martius (<A HREF="mailto:admin@imib.med.tu-dresden.de">admin@imib.med.tu-dresden.de</A>) contributed the initial
+version of the code supporting PFS.
+<P>
+
+Richard Guy Briggs &lt;<A HREF="mailto:rgb@conscoop.ottawa.on.ca">rgb@conscoop.ottawa.on.ca</A>&gt; and Peter Onion
+&lt;<A HREF="mailto:ponion@srd.bt.co.uk">ponion@srd.bt.co.uk</A>&gt; added the PFKEY2 support.
+<P>
+
+We gratefully acknowledge that we use parts of Eric Young's <I>libdes</I>
+package; see <I>../libdes/COPYRIGHT</I>.
+<A NAME="lbBA">&nbsp;</A>
+<H2>BUGS</H2>
+
+<B>pluto</B>
+
+is a work-in-progress. It currently has many limitations.
+For example, it ignores notification messages that it receives, and
+it generates only Delete Notifications and those only for IPSEC SAs.
+<P>
+
+<B>pluto</B> does not support the Commit Flag.
+The Commit Flag is a bad feature of the IKE protocol.
+It isn't protected -- neither encrypted nor authenticated.
+A man in the middle could turn it on, leading to DoS.
+We just ignore it, with a warning.
+This should let us interoperate with
+implementations that insist on it, with minor damage.
+<P>
+
+<B>pluto</B> does not check that the SA returned by the Responder
+is actually one that was proposed. It only checks that the SA is
+acceptable. The difference is not large, but can show up in attributes
+such as SA lifetime.
+<P>
+
+There is no good way for a connection to be automatically terminated.
+This is a problem for Road Warrior and Opportunistic connections.
+The <B>--dontrekey</B> option does prevent the SAs from
+being rekeyed on expiry.
+Additonally, if a Road Warrior connection has a client subnet with a fixed IP
+address, a negotiation with that subnet will cause any other
+connection instantiations with that same subnet to be unoriented
+(deleted, in effect).
+See also the --uniqueids option for an extension of this.
+<P>
+
+When <B>pluto</B> sends a message to a peer that has disappeared,
+<B>pluto</B> receives incomplete information from the kernel, so it
+logs the unsatisfactory message ``some IKE message we sent has been
+rejected with ECONNREFUSED (kernel supplied no details)''. John
+Denker suggests that this command is useful for tracking down the
+source of these problems:
+<BR>
+
+<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>tcpdump -i eth0 icmp[0] != 8 and icmp[0] != 0<BR>
+<BR>
+
+Substitute your public interface for eth0 if it is different.
+<P>
+
+The word ``authenticate'' is used for two different features. We must
+authenticate each IKE peer to the other. This is an important task of
+Phase 1. Each packet must be authenticated, both in IKE and in IPsec,
+and the method for IPsec is negotiated as an AH SA or part of an ESP SA.
+Unfortunately, the protocol has no mechanism for authenticating the Phase 2
+identities.
+<P>
+
+Bugs should be reported to the &lt;<A HREF="mailto:users@lists.freeswan.org">users@lists.freeswan.org</A>&gt; mailing list.
+Caution: we cannot accept
+actual code from US residents, or even US citizens living outside the
+US, because that would bring FreeS/WAN under US export law. Some
+other countries cause similar problems. In general, we would prefer
+that you send detailed problem reports rather than code: we want
+FreeS/WAN to be unquestionably freely exportable, which means being
+very careful about where the code comes from, and for a small bug fix,
+that is often more time-consuming than just reinventing the fix
+ourselves.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DL>
+<DT><A HREF="#lbAE">IKE's Job</A><DD>
+<DT><A HREF="#lbAF">Pluto</A><DD>
+<DT><A HREF="#lbAG">Before Running Pluto</A><DD>
+<DT><A HREF="#lbAH">Setting up <B>KLIPS</B> for <B>pluto</B></A><DD>
+<DT><A HREF="#lbAI">ipsec.secrets file</A><DD>
+<DT><A HREF="#lbAJ">Running Pluto</A><DD>
+<DT><A HREF="#lbAK">Pluto's Internal State</A><DD>
+<DT><A HREF="#lbAL">Using Whack</A><DD>
+<DT><A HREF="#lbAM">Examples</A><DD>
+<DT><A HREF="#lbAN">The updown command</A><DD>
+<DT><A HREF="#lbAO">Rekeying</A><DD>
+<DT><A HREF="#lbAP">Selecting a Connection When Responding: Road Warrior Support</A><DD>
+<DT><A HREF="#lbAQ">Debugging</A><DD>
+<DT><A HREF="#lbAR">Pluto's Behaviour When Things Go Wrong</A><DD>
+<DT><A HREF="#lbAS">Notes</A><DD>
+<DT><A HREF="#lbAT">Policies</A><DD>
+</DL>
+<DT><A HREF="#lbAU">SIGNALS</A><DD>
+<DT><A HREF="#lbAV">EXIT STATUS</A><DD>
+<DT><A HREF="#lbAW">FILES</A><DD>
+<DT><A HREF="#lbAX">ENVIRONMENT</A><DD>
+<DT><A HREF="#lbAY">SEE ALSO</A><DD>
+<DT><A HREF="#lbAZ">HISTORY</A><DD>
+<DT><A HREF="#lbBA">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_portof.3.html b/doc/manpage.d/ipsec_portof.3.html
new file mode 100644
index 000000000..3965ca62d
--- /dev/null
+++ b/doc/manpage.d/ipsec_portof.3.html
@@ -0,0 +1,143 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PORTOF</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PORTOF</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec portof - get port field of an ip_address
+<BR>
+
+ipsec setportof - set port field of an ip_address
+<BR>
+
+ipsec sockaddrof - get pointer to internal sockaddr of an ip_address
+<BR>
+
+ipsec sockaddrlenof - get length of internal sockaddr of an ip_address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int portof(const ip_address *src);</B>
+
+<BR>
+
+<B>void setportof(int port, ip_address *dst);</B>
+
+<BR>
+
+<B>struct sockaddr *sockaddrof(ip_address *src);</B>
+
+<BR>
+
+<B>size_t sockaddrlenof(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+internal type
+<I>ip_address</I>
+
+contains one of the
+<I>sockaddr</I>
+
+types internally.
+<I>Reliance on this feature is discouraged</I>,
+but it may occasionally be necessary.
+These functions provide low-level tools for this purpose.
+<P>
+
+<I>Portof</I>
+
+and
+<I>setportof</I>
+
+respectively read and write the port-number field of the internal
+<I>sockaddr</I>.
+
+The values are in network byte order.
+<P>
+
+<I>Sockaddrof</I>
+
+returns a pointer to the internal
+<I>sockaddr</I>,
+
+for passing to other functions.
+<P>
+
+<I>Sockaddrlenof</I>
+
+reports the size of the internal
+<I>sockaddr</I>,
+
+for use in storage allocation.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+<I>Portof</I>
+
+returns
+<B>-1</B>,
+
+<I>sockaddrof</I>
+
+returns
+<B>NULL</B>,
+
+and
+<I>sockaddrlenof</I>
+
+returns
+<B>0</B>
+
+if an unknown address family is found within the
+<I>ip_address</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+These functions all depend on low-level details of the
+<I>ip_address</I>
+
+type, which are in principle subject to change.
+Avoid using them unless really necessary.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_prng.3.html b/doc/manpage.d/ipsec_prng.3.html
new file mode 100644
index 000000000..27763a2bb
--- /dev/null
+++ b/doc/manpage.d/ipsec_prng.3.html
@@ -0,0 +1,204 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PRNG</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PRNG</H1>
+Section: C Library Functions (3)<BR>Updated: 1 April 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec prng_init - initialize IPsec pseudorandom-number generator
+<BR>
+
+ipsec prng_bytes - get bytes from IPsec pseudorandom-number generator
+<BR>
+
+ipsec prng_final - close down IPsec pseudorandom-number generator
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>void prng_init(struct prng *prng,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char *key, size_t keylen);</B>
+
+<BR>
+
+<B>void prng_bytes(struct prng *prng, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<BR>
+
+<B>unsigned long prng_count(struct prng *prng);</B>
+
+<BR>
+
+<B>void prng_final(struct prng *prng);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Prng_init</I>
+
+initializes a crypto-quality pseudo-random-number generator from a key;
+<I>prng_bytes</I>
+
+obtains pseudo-random bytes from it;
+<I>prng_count</I>
+
+reports the number of bytes extracted from it to date;
+<I>prng_final</I>
+
+closes it down.
+It is the user's responsibility to initialize a PRNG before using it,
+and not to use it again after it is closed down.
+<P>
+
+<I>Prng_init</I>
+
+initializes,
+or re-initializes,
+the specified
+<I>prng</I>
+
+from the
+<I>key</I>,
+
+whose length is given by
+<I>keylen</I>.
+
+The user must allocate the
+<B>struct prng</B>
+
+pointed to by
+<I>prng</I>.
+
+There is no particular constraint on the length of the key,
+although a key longer than 256 bytes is unnecessary because
+only the first 256 would be used.
+Initialization requires on the order of 3000 integer operations,
+independent of key length.
+<P>
+
+<I>Prng_bytes</I>
+
+obtains
+<I>dstlen</I>
+
+pseudo-random bytes from the PRNG and puts them in
+<I>buf</I>.
+
+This is quite fast,
+on the order of 10 integer operations per byte.
+<P>
+
+<I>Prng_count</I>
+
+reports the number of bytes obtained from the PRNG
+since it was (last) initialized.
+<P>
+
+<I>Prng_final</I>
+
+closes down a PRNG by
+zeroing its internal memory,
+obliterating all trace of the state used to generate its previous output.
+This requires on the order of 250 integer operations.
+<P>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file supplies the definition of the
+<B>prng</B>
+
+structure.
+Examination of its innards is discouraged, as they may change.
+<P>
+
+The PRNG algorithm
+used by these functions is currently identical to that of RC4(TM).
+This algorithm is cryptographically strong,
+sufficiently unpredictable that even a hostile observer will
+have difficulty determining the next byte of output from past history,
+provided it is initialized from a reasonably large key composed of
+highly random bytes (see
+<I><A HREF="random.4.html">random</A></I>(4)).
+
+The usual run of software pseudo-random-number generators
+(e.g.
+<I><A HREF="random.3.html">random</A></I>(3))
+
+are
+<I>not</I>
+
+cryptographically strong.
+<P>
+
+The well-known attacks against RC4(TM),
+e.g. as found in 802.11b's WEP encryption system,
+apply only if multiple PRNGs are initialized with closely-related keys
+(e.g., using a counter appended to a base key).
+If such keys are used, the first few hundred pseudo-random bytes
+from each PRNG should be discarded,
+to give the PRNGs a chance to randomize their innards properly.
+No useful attacks are known if the key is well randomized to begin with.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="random.3.html">random</A>(3), <A HREF="random.4.html">random</A>(4)
+<BR>
+
+Bruce Schneier,
+<I>Applied Cryptography</I>, 2nd ed., 1996, ISBN 0-471-11709-9,
+pp. 397-8.
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+If an attempt is made to obtain more than 4e9 bytes
+between initializations,
+the PRNG will continue to work but
+<I>prng_count</I>'s
+
+output will stick at
+<B>4000000000</B>.
+
+Fixing this would require a longer integer type and does
+not seem worth the trouble,
+since you should probably re-initialize before then anyway...
+<P>
+
+``RC4'' is a trademark of RSA Data Security, Inc.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_prng_bytes.3.html b/doc/manpage.d/ipsec_prng_bytes.3.html
new file mode 100644
index 000000000..27763a2bb
--- /dev/null
+++ b/doc/manpage.d/ipsec_prng_bytes.3.html
@@ -0,0 +1,204 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PRNG</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PRNG</H1>
+Section: C Library Functions (3)<BR>Updated: 1 April 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec prng_init - initialize IPsec pseudorandom-number generator
+<BR>
+
+ipsec prng_bytes - get bytes from IPsec pseudorandom-number generator
+<BR>
+
+ipsec prng_final - close down IPsec pseudorandom-number generator
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>void prng_init(struct prng *prng,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char *key, size_t keylen);</B>
+
+<BR>
+
+<B>void prng_bytes(struct prng *prng, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<BR>
+
+<B>unsigned long prng_count(struct prng *prng);</B>
+
+<BR>
+
+<B>void prng_final(struct prng *prng);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Prng_init</I>
+
+initializes a crypto-quality pseudo-random-number generator from a key;
+<I>prng_bytes</I>
+
+obtains pseudo-random bytes from it;
+<I>prng_count</I>
+
+reports the number of bytes extracted from it to date;
+<I>prng_final</I>
+
+closes it down.
+It is the user's responsibility to initialize a PRNG before using it,
+and not to use it again after it is closed down.
+<P>
+
+<I>Prng_init</I>
+
+initializes,
+or re-initializes,
+the specified
+<I>prng</I>
+
+from the
+<I>key</I>,
+
+whose length is given by
+<I>keylen</I>.
+
+The user must allocate the
+<B>struct prng</B>
+
+pointed to by
+<I>prng</I>.
+
+There is no particular constraint on the length of the key,
+although a key longer than 256 bytes is unnecessary because
+only the first 256 would be used.
+Initialization requires on the order of 3000 integer operations,
+independent of key length.
+<P>
+
+<I>Prng_bytes</I>
+
+obtains
+<I>dstlen</I>
+
+pseudo-random bytes from the PRNG and puts them in
+<I>buf</I>.
+
+This is quite fast,
+on the order of 10 integer operations per byte.
+<P>
+
+<I>Prng_count</I>
+
+reports the number of bytes obtained from the PRNG
+since it was (last) initialized.
+<P>
+
+<I>Prng_final</I>
+
+closes down a PRNG by
+zeroing its internal memory,
+obliterating all trace of the state used to generate its previous output.
+This requires on the order of 250 integer operations.
+<P>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file supplies the definition of the
+<B>prng</B>
+
+structure.
+Examination of its innards is discouraged, as they may change.
+<P>
+
+The PRNG algorithm
+used by these functions is currently identical to that of RC4(TM).
+This algorithm is cryptographically strong,
+sufficiently unpredictable that even a hostile observer will
+have difficulty determining the next byte of output from past history,
+provided it is initialized from a reasonably large key composed of
+highly random bytes (see
+<I><A HREF="random.4.html">random</A></I>(4)).
+
+The usual run of software pseudo-random-number generators
+(e.g.
+<I><A HREF="random.3.html">random</A></I>(3))
+
+are
+<I>not</I>
+
+cryptographically strong.
+<P>
+
+The well-known attacks against RC4(TM),
+e.g. as found in 802.11b's WEP encryption system,
+apply only if multiple PRNGs are initialized with closely-related keys
+(e.g., using a counter appended to a base key).
+If such keys are used, the first few hundred pseudo-random bytes
+from each PRNG should be discarded,
+to give the PRNGs a chance to randomize their innards properly.
+No useful attacks are known if the key is well randomized to begin with.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="random.3.html">random</A>(3), <A HREF="random.4.html">random</A>(4)
+<BR>
+
+Bruce Schneier,
+<I>Applied Cryptography</I>, 2nd ed., 1996, ISBN 0-471-11709-9,
+pp. 397-8.
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+If an attempt is made to obtain more than 4e9 bytes
+between initializations,
+the PRNG will continue to work but
+<I>prng_count</I>'s
+
+output will stick at
+<B>4000000000</B>.
+
+Fixing this would require a longer integer type and does
+not seem worth the trouble,
+since you should probably re-initialize before then anyway...
+<P>
+
+``RC4'' is a trademark of RSA Data Security, Inc.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_prng_final.3.html b/doc/manpage.d/ipsec_prng_final.3.html
new file mode 100644
index 000000000..27763a2bb
--- /dev/null
+++ b/doc/manpage.d/ipsec_prng_final.3.html
@@ -0,0 +1,204 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PRNG</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PRNG</H1>
+Section: C Library Functions (3)<BR>Updated: 1 April 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec prng_init - initialize IPsec pseudorandom-number generator
+<BR>
+
+ipsec prng_bytes - get bytes from IPsec pseudorandom-number generator
+<BR>
+
+ipsec prng_final - close down IPsec pseudorandom-number generator
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>void prng_init(struct prng *prng,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char *key, size_t keylen);</B>
+
+<BR>
+
+<B>void prng_bytes(struct prng *prng, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<BR>
+
+<B>unsigned long prng_count(struct prng *prng);</B>
+
+<BR>
+
+<B>void prng_final(struct prng *prng);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Prng_init</I>
+
+initializes a crypto-quality pseudo-random-number generator from a key;
+<I>prng_bytes</I>
+
+obtains pseudo-random bytes from it;
+<I>prng_count</I>
+
+reports the number of bytes extracted from it to date;
+<I>prng_final</I>
+
+closes it down.
+It is the user's responsibility to initialize a PRNG before using it,
+and not to use it again after it is closed down.
+<P>
+
+<I>Prng_init</I>
+
+initializes,
+or re-initializes,
+the specified
+<I>prng</I>
+
+from the
+<I>key</I>,
+
+whose length is given by
+<I>keylen</I>.
+
+The user must allocate the
+<B>struct prng</B>
+
+pointed to by
+<I>prng</I>.
+
+There is no particular constraint on the length of the key,
+although a key longer than 256 bytes is unnecessary because
+only the first 256 would be used.
+Initialization requires on the order of 3000 integer operations,
+independent of key length.
+<P>
+
+<I>Prng_bytes</I>
+
+obtains
+<I>dstlen</I>
+
+pseudo-random bytes from the PRNG and puts them in
+<I>buf</I>.
+
+This is quite fast,
+on the order of 10 integer operations per byte.
+<P>
+
+<I>Prng_count</I>
+
+reports the number of bytes obtained from the PRNG
+since it was (last) initialized.
+<P>
+
+<I>Prng_final</I>
+
+closes down a PRNG by
+zeroing its internal memory,
+obliterating all trace of the state used to generate its previous output.
+This requires on the order of 250 integer operations.
+<P>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file supplies the definition of the
+<B>prng</B>
+
+structure.
+Examination of its innards is discouraged, as they may change.
+<P>
+
+The PRNG algorithm
+used by these functions is currently identical to that of RC4(TM).
+This algorithm is cryptographically strong,
+sufficiently unpredictable that even a hostile observer will
+have difficulty determining the next byte of output from past history,
+provided it is initialized from a reasonably large key composed of
+highly random bytes (see
+<I><A HREF="random.4.html">random</A></I>(4)).
+
+The usual run of software pseudo-random-number generators
+(e.g.
+<I><A HREF="random.3.html">random</A></I>(3))
+
+are
+<I>not</I>
+
+cryptographically strong.
+<P>
+
+The well-known attacks against RC4(TM),
+e.g. as found in 802.11b's WEP encryption system,
+apply only if multiple PRNGs are initialized with closely-related keys
+(e.g., using a counter appended to a base key).
+If such keys are used, the first few hundred pseudo-random bytes
+from each PRNG should be discarded,
+to give the PRNGs a chance to randomize their innards properly.
+No useful attacks are known if the key is well randomized to begin with.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="random.3.html">random</A>(3), <A HREF="random.4.html">random</A>(4)
+<BR>
+
+Bruce Schneier,
+<I>Applied Cryptography</I>, 2nd ed., 1996, ISBN 0-471-11709-9,
+pp. 397-8.
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+If an attempt is made to obtain more than 4e9 bytes
+between initializations,
+the PRNG will continue to work but
+<I>prng_count</I>'s
+
+output will stick at
+<B>4000000000</B>.
+
+Fixing this would require a longer integer type and does
+not seem worth the trouble,
+since you should probably re-initialize before then anyway...
+<P>
+
+``RC4'' is a trademark of RSA Data Security, Inc.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_prng_init.3.html b/doc/manpage.d/ipsec_prng_init.3.html
new file mode 100644
index 000000000..27763a2bb
--- /dev/null
+++ b/doc/manpage.d/ipsec_prng_init.3.html
@@ -0,0 +1,204 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PRNG</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PRNG</H1>
+Section: C Library Functions (3)<BR>Updated: 1 April 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec prng_init - initialize IPsec pseudorandom-number generator
+<BR>
+
+ipsec prng_bytes - get bytes from IPsec pseudorandom-number generator
+<BR>
+
+ipsec prng_final - close down IPsec pseudorandom-number generator
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>void prng_init(struct prng *prng,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char *key, size_t keylen);</B>
+
+<BR>
+
+<B>void prng_bytes(struct prng *prng, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<BR>
+
+<B>unsigned long prng_count(struct prng *prng);</B>
+
+<BR>
+
+<B>void prng_final(struct prng *prng);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Prng_init</I>
+
+initializes a crypto-quality pseudo-random-number generator from a key;
+<I>prng_bytes</I>
+
+obtains pseudo-random bytes from it;
+<I>prng_count</I>
+
+reports the number of bytes extracted from it to date;
+<I>prng_final</I>
+
+closes it down.
+It is the user's responsibility to initialize a PRNG before using it,
+and not to use it again after it is closed down.
+<P>
+
+<I>Prng_init</I>
+
+initializes,
+or re-initializes,
+the specified
+<I>prng</I>
+
+from the
+<I>key</I>,
+
+whose length is given by
+<I>keylen</I>.
+
+The user must allocate the
+<B>struct prng</B>
+
+pointed to by
+<I>prng</I>.
+
+There is no particular constraint on the length of the key,
+although a key longer than 256 bytes is unnecessary because
+only the first 256 would be used.
+Initialization requires on the order of 3000 integer operations,
+independent of key length.
+<P>
+
+<I>Prng_bytes</I>
+
+obtains
+<I>dstlen</I>
+
+pseudo-random bytes from the PRNG and puts them in
+<I>buf</I>.
+
+This is quite fast,
+on the order of 10 integer operations per byte.
+<P>
+
+<I>Prng_count</I>
+
+reports the number of bytes obtained from the PRNG
+since it was (last) initialized.
+<P>
+
+<I>Prng_final</I>
+
+closes down a PRNG by
+zeroing its internal memory,
+obliterating all trace of the state used to generate its previous output.
+This requires on the order of 250 integer operations.
+<P>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file supplies the definition of the
+<B>prng</B>
+
+structure.
+Examination of its innards is discouraged, as they may change.
+<P>
+
+The PRNG algorithm
+used by these functions is currently identical to that of RC4(TM).
+This algorithm is cryptographically strong,
+sufficiently unpredictable that even a hostile observer will
+have difficulty determining the next byte of output from past history,
+provided it is initialized from a reasonably large key composed of
+highly random bytes (see
+<I><A HREF="random.4.html">random</A></I>(4)).
+
+The usual run of software pseudo-random-number generators
+(e.g.
+<I><A HREF="random.3.html">random</A></I>(3))
+
+are
+<I>not</I>
+
+cryptographically strong.
+<P>
+
+The well-known attacks against RC4(TM),
+e.g. as found in 802.11b's WEP encryption system,
+apply only if multiple PRNGs are initialized with closely-related keys
+(e.g., using a counter appended to a base key).
+If such keys are used, the first few hundred pseudo-random bytes
+from each PRNG should be discarded,
+to give the PRNGs a chance to randomize their innards properly.
+No useful attacks are known if the key is well randomized to begin with.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="random.3.html">random</A>(3), <A HREF="random.4.html">random</A>(4)
+<BR>
+
+Bruce Schneier,
+<I>Applied Cryptography</I>, 2nd ed., 1996, ISBN 0-471-11709-9,
+pp. 397-8.
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+If an attempt is made to obtain more than 4e9 bytes
+between initializations,
+the PRNG will continue to work but
+<I>prng_count</I>'s
+
+output will stick at
+<B>4000000000</B>.
+
+Fixing this would require a longer integer type and does
+not seem worth the trouble,
+since you should probably re-initialize before then anyway...
+<P>
+
+``RC4'' is a trademark of RSA Data Security, Inc.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_ranbits.8.html b/doc/manpage.d/ipsec_ranbits.8.html
new file mode 100644
index 000000000..036b2a351
--- /dev/null
+++ b/doc/manpage.d/ipsec_ranbits.8.html
@@ -0,0 +1,147 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_RANBITS</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_RANBITS</H1>
+Section: Maintenance Commands (8)<BR>Updated: 22 Aug 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ranbits - generate random bits in ASCII form
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>ranbits</B>
+
+[
+<B>--quick</B>
+
+] [
+<B>--continuous</B>
+
+] [
+<B>--bytes</B>
+
+] nbits
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ranbits</I>
+
+obtains
+<I>nbits</I>
+
+(rounded up to the nearest byte)
+high-quality random bits from
+<I><A HREF="random.4.html">random</A></I>(4),
+
+and emits them on standard output as an ASCII string.
+The default output format is
+<I><A HREF="datatot.3.html">datatot</A></I>(3)
+
+<B>h</B>
+
+format:
+lowercase hexadecimal with a
+<B>0x</B>
+
+prefix and an underscore every 32 bits.
+<P>
+
+The
+<B>--quick</B>
+
+option produces quick-and-dirty random bits:
+instead of using the high-quality random bits from
+<I>/dev/random</I>,
+
+which may take some time to supply the necessary bits if
+<I>nbits</I>
+
+is large,
+<I>ranbits</I>
+
+uses
+<I>/dev/urandom</I>,
+
+which yields prompt results but lower-quality randomness.
+<P>
+
+The
+<B>--continuous</B>
+
+option uses
+<I><A HREF="datatot.3.html">datatot</A></I>(3)
+
+<B>x</B>
+
+output format, like
+<B>h</B>
+
+but without the underscores.
+<P>
+
+The
+<B>--bytes</B>
+
+option causes
+<I>nbits</I>
+
+to be interpreted as a byte count rather than a bit count.
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+/dev/random, /dev/urandom
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_datatot.3.html">ipsec_datatot</A>(3), <A HREF="random.4.html">random</A>(4)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+There is an internal limit on
+<I>nbits</I>,
+
+currently 20000.
+<P>
+
+Without
+<B>--quick</B>,
+
+<I>ranbits</I>'s
+
+run time is difficult to predict.
+A request for a large number of bits,
+at a time when the system's entropy pool is low on randomness,
+may take quite a while to satisfy.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_rangetoa.3.html b/doc/manpage.d/ipsec_rangetoa.3.html
new file mode 100644
index 000000000..3bacd5943
--- /dev/null
+++ b/doc/manpage.d/ipsec_rangetoa.3.html
@@ -0,0 +1,294 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOASR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOASR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atoasr - convert ASCII to Internet address, subnet, or range
+<BR>
+
+ipsec rangetoa - convert Internet address range to ASCII
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atoasr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>char *type, struct in_addr *addrs);</B>
+
+<BR>
+
+<B>size_t rangetoa(struct in_addr *addrs, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete;
+there is no current equivalent,
+because so far they have not proved useful.
+<P>
+
+<I>Atoasr</I>
+
+converts an ASCII address, subnet, or address range
+into a suitable combination of binary addresses
+(in network byte order).
+<I>Rangetoa</I>
+
+converts an address range back into ASCII,
+using dotted-decimal form for the addresses
+(the other reverse conversions are handled by
+<I><A HREF="ipsec_addrtoa.3.html">ipsec_addrtoa</A></I>(3)
+
+and
+<I><A HREF="ipsec_subnettoa.3.html">ipsec_subnettoa</A></I>(3)).
+
+<P>
+
+A single address can be any form acceptable to
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3):
+
+dotted decimal, DNS name, or hexadecimal number.
+A subnet
+specification uses the form <I>network</I><B>/</B><I>mask</I>
+interpreted by
+<I><A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A></I>(3).
+
+<P>
+
+An address range is two
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3)
+
+addresses separated by a
+<B>...</B>
+
+delimiter.
+If there are four dots rather than three, the first is taken as
+part of the begin address,
+e.g. for a complete DNS name which ends with
+<B>.</B>
+
+to suppress completion attempts.
+The begin address of a range must be
+less than or equal to the end address.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atoasr</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>type</I>
+
+parameter of
+<I>atoasr</I>
+
+must point to a
+<B>char</B>
+
+variable used to record which form was found.
+The
+<I>addrs</I>
+
+parameter must point to a two-element array of
+<B>struct in_addr</B>
+
+which receives the results.
+The values stored into
+<B>*type</B>,
+
+and the corresponding values in the array, are:
+<P>
+
+
+
+<TT>&nbsp;&nbsp;&nbsp;</TT>*typeaddrs[0]addrs[1]<BR>
+<P>
+address<B>'a'</B>address-<BR>
+<BR>
+
+subnet<TT>&nbsp;</TT><B>'s'</B>networkmask<BR>
+<BR>
+
+range<TT>&nbsp;&nbsp;</TT><B>'r'</B>beginend<BR>
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>rangetoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines a constant,
+<B>RANGETOA_BUF</B>,
+
+which is the size of a buffer just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>rangetoa</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+<P>
+
+<I>Atoasr</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Rangetoa</I>
+
+returns
+<B>0</B>
+
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A>(3), <A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atoasr</I>
+
+are:
+empty input;
+error in
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3)
+
+or
+<I><A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A></I>(3)
+
+during conversion;
+begin address of range exceeds end address.
+<P>
+
+Fatal errors in
+<I>rangetoa</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoasr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_rangetosubnet.3.html b/doc/manpage.d/ipsec_rangetosubnet.3.html
new file mode 100644
index 000000000..9e03244ea
--- /dev/null
+++ b/doc/manpage.d/ipsec_rangetosubnet.3.html
@@ -0,0 +1,116 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_RANGETOSUBNET</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_RANGETOSUBNET</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec rangetosubnet - convert address range to subnet
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *rangetosubnet(const ip_address *start,</B>
+
+<BR>
+&nbsp;
+<B>const ip_address *stop, ip_subnet *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Rangetosubnet</I>
+
+accepts two IP addresses which define an address range,
+from
+<I>start</I>
+
+to
+<I>stop</I>
+
+inclusive,
+and converts this to a subnet if possible.
+The addresses must both be IPv4 or both be IPv6,
+and the address family of the resulting subnet is the same.
+<P>
+
+<I>Rangetosubnet</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_initsubnet.3.html">ipsec_initsubnet</A>(3), <A HREF="ipsec_ttosubnet.3.html">ipsec_ttosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>rangetosubnet</I>
+
+are:
+mixed address families;
+unknown address family;
+<I>start</I>
+
+and
+<I>stop</I>
+
+do not define a subnet.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = rangetosubnet( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_rsasigkey.8.html b/doc/manpage.d/ipsec_rsasigkey.8.html
new file mode 100644
index 000000000..3173a9f13
--- /dev/null
+++ b/doc/manpage.d/ipsec_rsasigkey.8.html
@@ -0,0 +1,401 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_RSASIGKEY</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_RSASIGKEY</H1>
+Section: Maintenance Commands (8)<BR>Updated: 22 July 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec rsasigkey - generate RSA signature key
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>rsasigkey</B>
+
+[
+<B>--verbose</B>
+
+] [
+<B>--random</B>
+
+filename
+]
+<B>\</B>
+
+<BR>
+
+&nbsp;&nbsp;&nbsp;[
+<B>--rounds</B>
+
+nr
+] [
+<B>--hostname</B>
+
+host ] [
+<B>--noopt</B>
+
+] nbits
+<BR>
+
+<B>ipsec</B>
+
+<B>rsasigkey</B>
+
+[
+<B>--verbose</B>
+
+] [
+<B>--hostname</B>
+
+host ]
+<B>\</B>
+
+<BR>
+
+&nbsp;&nbsp;&nbsp;
+[
+<B>--noopt</B>
+
+]
+<B>--oldkey</B>
+
+file
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Rsasigkey</I>
+
+generates an RSA public/private key pair,
+suitable for digital signatures,
+of (exactly)
+<I>nbits</I>
+
+bits (that is, two primes each of exactly
+<I>nbits</I>/2
+
+bits,
+and related numbers)
+and emits it on standard output as ASCII (mostly hex) data.
+<I>nbits</I>
+
+must be a multiple of 16.
+<P>
+
+The public exponent is forced to the value
+<B>3</B>,
+
+which has important speed advantages for signature checking.
+Beware that the resulting keys have known weaknesses as encryption keys
+<I>and should not be used for that purpose</I>.
+<P>
+
+The
+<B>--verbose</B>
+
+option makes
+<I>rsasigkey</I>
+
+give a running commentary on standard error.
+By default, it works in silence until it is ready to generate output.
+<P>
+
+The
+<B>--random</B>
+
+option specifies a source for random bits.
+The default is
+<I>/dev/random</I>
+
+(see
+<I><A HREF="random.4.html">random</A></I>(4)).
+
+Normally,
+<I>rsasigkey</I>
+
+reads exactly
+<I>nbits</I>
+
+random bits from the source;
+in extremely-rare circumstances it may need more.
+<P>
+
+The
+<B>--rounds</B>
+
+option specifies the number of rounds to be done by the
+<I>mpz_probab_prime_p</I>
+
+probabilistic primality checker.
+The default, 30, is fairly rigorous and should not normally
+have to be overridden.
+<P>
+
+The
+<B>--hostname</B>
+
+option specifies what host name to use in
+the first line of the output (see below);
+the default is what
+<I><A HREF="gethostname.2.html">gethostname</A></I>(2)
+
+returns.
+<P>
+
+The
+<B>--noopt</B>
+
+option suppresses an optimization of the private key
+(to be precise, setting of the decryption exponent to
+<B>lcm(p-1,q-1)</B>
+
+rather than
+<B>(p-1)*(q-1)</B>)
+
+which speeds up operations on it slightly
+but can cause it to flunk a validity check in old RSA implementations
+(notably, obsolete versions of
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8)).
+
+<P>
+
+The
+<B>--oldkey</B>
+
+option specifies that rather than generate a new key,
+<I>rsasigkey</I>
+
+should read an old key from the
+<I>file</I>
+
+(the name
+<B>-</B>
+
+means ``standard input'')
+and use that to generate its output.
+Input lines which do not look like
+<I>rsasigkey</I>
+
+output are silently ignored.
+This permits updating old keys to the current format.
+<P>
+
+The output format looks like this (with long numbers trimmed down
+for clarity):
+<P>
+
+
+<PRE>
+ # RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ # for signatures only, UNSAFE FOR ENCRYPTION
+ #pubkey=0sAQOF8tZ2NZt...Y1P+buFuFn/
+ Modulus: 0xcc2a86fcf440...cf1011abb82d1
+ PublicExponent: 0x03
+ # everything after this point is secret
+ PrivateExponent: 0x881c59fdf8...ab05c8c77d23
+ Prime1: 0xf49fd1f779...46504c7bf3
+ Prime2: 0xd5a9108453...321d43cb2b
+ Exponent1: 0xa31536a4fb...536d98adda7f7
+ Exponent2: 0x8e70b5ad8d...9142168d7dcc7
+ Coefficient: 0xafb761d001...0c13e98d98
+</PRE>
+
+<P>
+
+The first (comment) line,
+indicating the nature and date of the key,
+and giving a host name,
+is used by
+<I><A HREF="ipsec_showhostkey.8.html">ipsec_showhostkey</A></I>(8)
+
+when generating some forms of key output.
+<P>
+
+The commented-out
+<B>pubkey=</B>
+
+line contains the public key---the public exponent and the modulus---combined
+in approximately RFC 2537 format
+(the one deviation is that the combined value is given with a
+<B>0s</B>
+
+prefix, rather than in unadorned base-64),
+suitable for use in the
+<I>ipsec.conf</I>
+
+file.
+<P>
+
+The
+<B>Modulus</B>,
+
+<B>PublicExponent</B>,
+
+and
+<B>PrivateExponent</B>
+
+lines give the basic signing and verification data.
+<P>
+
+The
+<B>Prime1</B>
+
+and
+<B>Prime2</B>
+
+lines give the primes themselves (aka
+<I>p</I>
+
+and
+<I>q</I>),
+
+largest first.
+The
+<B>Exponent1</B>
+
+and
+<B>Exponent2</B>
+
+lines give
+the private exponent mod
+<I>p-1</I>
+
+and
+<I>q-1</I>
+
+respectively.
+The
+<B>Coefficient</B>
+
+line gives the Chinese Remainder Theorem coefficient,
+which is the inverse of
+<I>q</I>,
+
+mod
+<I>p</I>.
+
+These additional numbers (which must all be kept as secret as the
+private exponent) are precomputed aids to rapid signature generation.
+<P>
+
+No attempt is made to break long lines.
+<P>
+
+The US patent on the RSA algorithm expired 20 Sept 2000.
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<DL COMPACT>
+<DT><B>ipsec rsasigkey --verbose 2192 &gt;mykey</B>
+
+<DD>
+generates a 2192-bit signature key and puts it in the file
+<I>mykey</I>,
+
+with running commentary on standard error.
+The file contents can be inserted verbatim into a suitable entry in the
+<I>ipsec.secrets</I>
+
+file (see
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5)),
+
+and the public key can then be extracted and edited into the
+<I>ipsec.conf</I>
+
+file (see
+<I><A HREF="ipsec.conf.5.html">ipsec.conf</A></I>(5)).
+
+<DT><B>ipsec rsasigkey --verbose --oldkey oldie &gt;latest</B>
+
+<DD>
+takes the old signature key from file
+<I>oldie</I>
+
+and puts a version in the current format into the file
+<I>latest</I>,
+
+with running commentary on standard error.
+</DL>
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/dev/random
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="random.4.html">random</A>(4), <A HREF="ipsec_showhostkey.8.html">ipsec_showhostkey</A>(8)
+<BR>
+
+<I>Applied Cryptography</I>, 2nd. ed., by Bruce Schneier, Wiley 1996.
+<BR>
+
+RFCs 2537, 2313.
+<BR>
+
+<I>GNU MP, the GNU multiple precision arithmetic library, edition 2.0.2</I>,
+by Torbj Granlund.
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<A NAME="lbAI">&nbsp;</A>
+<H2>BUGS</H2>
+
+There is an internal limit on
+<I>nbits</I>,
+
+currently 20000.
+<P>
+
+<I>Rsasigkey</I>'s
+
+run time is difficult to predict,
+since
+<I>/dev/random</I>
+
+output can be arbitrarily delayed if
+the system's entropy pool is low on randomness,
+and the time taken by the search for primes is also somewhat unpredictable.
+A reasonably typical time for a 1024-bit key on a quiet 200MHz Pentium MMX
+with plenty of randomness available is 20 seconds,
+almost all of it in the prime searches.
+Generating a 2192-bit key on the same system usually takes several minutes.
+A 4096-bit key took an hour and a half of CPU time.
+<P>
+
+The
+<B>--oldkey</B>
+
+option does not check its input format as rigorously as it might.
+Corrupted
+<I>rsasigkey</I>
+
+output may confuse it.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+<DT><A HREF="#lbAI">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_sameaddr.3.html b/doc/manpage.d/ipsec_sameaddr.3.html
new file mode 100644
index 000000000..414a0d513
--- /dev/null
+++ b/doc/manpage.d/ipsec_sameaddr.3.html
@@ -0,0 +1,274 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Nov 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec sameaddr - are two addresses the same?
+<BR>
+
+ipsec addrcmp - ordered comparison of addresses
+<BR>
+
+ipsec samesubnet - are two subnets the same?
+<BR>
+
+ipsec addrinsubnet - is an address within a subnet?
+<BR>
+
+ipsec subnetinsubnet - is a subnet within another subnet?
+<BR>
+
+ipsec subnetishost - is a subnet a single host?
+<BR>
+
+ipsec samesaid - are two SA IDs the same?
+<BR>
+
+ipsec sameaddrtype - are two addresses of the same address family?
+<BR>
+
+ipsec samesubnettype - are two subnets of the same address family?
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int sameaddr(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int addrcmp(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int addrinsubnet(const ip_address *a, const ip_subnet *s);</B>
+
+<BR>
+
+<B>int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int subnetishost(const ip_subnet *s);</B>
+
+<BR>
+
+<B>int samesaid(const ip_said *a, const ip_said *b);</B>
+
+<BR>
+
+<B>int sameaddrtype(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnettype(const ip_subnet *a, const ip_subnet *b);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions do various comparisons and tests on the
+<I>ip_address</I>
+
+type and
+<I>ip_subnet</I>
+
+types.
+<P>
+
+<I>Sameaddr</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Addresses of different families are never identical.
+<P>
+
+<I>Addrcmp</I>
+
+returns
+<B>-1</B>,
+
+<B>0</B>,
+
+or
+<B>1</B>
+
+respectively
+if address
+<I>a</I>
+
+is less than, equal to, or greater than
+<I>b</I>.
+
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+<P>
+
+<I>Samesubnet</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Subnets of different address families are never identical.
+<P>
+
+<I>Addrinsubnet</I>
+
+returns
+non-zero
+if address
+<I>a</I>
+
+is within subnet
+<I>s</I>
+
+and
+<B>0</B>
+
+otherwise.
+An address is never within a
+subnet of a different address family.
+<P>
+
+<I>Subnetinsubnet</I>
+
+returns
+non-zero
+if subnet
+<I>a</I>
+
+is a subset of subnet
+<I>b</I>
+
+and
+<B>0</B>
+
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+<P>
+
+<I>Subnetishost</I>
+
+returns
+non-zero
+if subnet
+<I>s</I>
+
+is in fact only a single host,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesaid</I>
+
+returns
+non-zero
+if SA IDs
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Sameaddrtype</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesubnettype</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_sameaddrtype.3.html b/doc/manpage.d/ipsec_sameaddrtype.3.html
new file mode 100644
index 000000000..414a0d513
--- /dev/null
+++ b/doc/manpage.d/ipsec_sameaddrtype.3.html
@@ -0,0 +1,274 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Nov 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec sameaddr - are two addresses the same?
+<BR>
+
+ipsec addrcmp - ordered comparison of addresses
+<BR>
+
+ipsec samesubnet - are two subnets the same?
+<BR>
+
+ipsec addrinsubnet - is an address within a subnet?
+<BR>
+
+ipsec subnetinsubnet - is a subnet within another subnet?
+<BR>
+
+ipsec subnetishost - is a subnet a single host?
+<BR>
+
+ipsec samesaid - are two SA IDs the same?
+<BR>
+
+ipsec sameaddrtype - are two addresses of the same address family?
+<BR>
+
+ipsec samesubnettype - are two subnets of the same address family?
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int sameaddr(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int addrcmp(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int addrinsubnet(const ip_address *a, const ip_subnet *s);</B>
+
+<BR>
+
+<B>int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int subnetishost(const ip_subnet *s);</B>
+
+<BR>
+
+<B>int samesaid(const ip_said *a, const ip_said *b);</B>
+
+<BR>
+
+<B>int sameaddrtype(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnettype(const ip_subnet *a, const ip_subnet *b);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions do various comparisons and tests on the
+<I>ip_address</I>
+
+type and
+<I>ip_subnet</I>
+
+types.
+<P>
+
+<I>Sameaddr</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Addresses of different families are never identical.
+<P>
+
+<I>Addrcmp</I>
+
+returns
+<B>-1</B>,
+
+<B>0</B>,
+
+or
+<B>1</B>
+
+respectively
+if address
+<I>a</I>
+
+is less than, equal to, or greater than
+<I>b</I>.
+
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+<P>
+
+<I>Samesubnet</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Subnets of different address families are never identical.
+<P>
+
+<I>Addrinsubnet</I>
+
+returns
+non-zero
+if address
+<I>a</I>
+
+is within subnet
+<I>s</I>
+
+and
+<B>0</B>
+
+otherwise.
+An address is never within a
+subnet of a different address family.
+<P>
+
+<I>Subnetinsubnet</I>
+
+returns
+non-zero
+if subnet
+<I>a</I>
+
+is a subset of subnet
+<I>b</I>
+
+and
+<B>0</B>
+
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+<P>
+
+<I>Subnetishost</I>
+
+returns
+non-zero
+if subnet
+<I>s</I>
+
+is in fact only a single host,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesaid</I>
+
+returns
+non-zero
+if SA IDs
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Sameaddrtype</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesubnettype</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_samesaid.3.html b/doc/manpage.d/ipsec_samesaid.3.html
new file mode 100644
index 000000000..414a0d513
--- /dev/null
+++ b/doc/manpage.d/ipsec_samesaid.3.html
@@ -0,0 +1,274 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Nov 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec sameaddr - are two addresses the same?
+<BR>
+
+ipsec addrcmp - ordered comparison of addresses
+<BR>
+
+ipsec samesubnet - are two subnets the same?
+<BR>
+
+ipsec addrinsubnet - is an address within a subnet?
+<BR>
+
+ipsec subnetinsubnet - is a subnet within another subnet?
+<BR>
+
+ipsec subnetishost - is a subnet a single host?
+<BR>
+
+ipsec samesaid - are two SA IDs the same?
+<BR>
+
+ipsec sameaddrtype - are two addresses of the same address family?
+<BR>
+
+ipsec samesubnettype - are two subnets of the same address family?
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int sameaddr(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int addrcmp(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int addrinsubnet(const ip_address *a, const ip_subnet *s);</B>
+
+<BR>
+
+<B>int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int subnetishost(const ip_subnet *s);</B>
+
+<BR>
+
+<B>int samesaid(const ip_said *a, const ip_said *b);</B>
+
+<BR>
+
+<B>int sameaddrtype(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnettype(const ip_subnet *a, const ip_subnet *b);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions do various comparisons and tests on the
+<I>ip_address</I>
+
+type and
+<I>ip_subnet</I>
+
+types.
+<P>
+
+<I>Sameaddr</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Addresses of different families are never identical.
+<P>
+
+<I>Addrcmp</I>
+
+returns
+<B>-1</B>,
+
+<B>0</B>,
+
+or
+<B>1</B>
+
+respectively
+if address
+<I>a</I>
+
+is less than, equal to, or greater than
+<I>b</I>.
+
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+<P>
+
+<I>Samesubnet</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Subnets of different address families are never identical.
+<P>
+
+<I>Addrinsubnet</I>
+
+returns
+non-zero
+if address
+<I>a</I>
+
+is within subnet
+<I>s</I>
+
+and
+<B>0</B>
+
+otherwise.
+An address is never within a
+subnet of a different address family.
+<P>
+
+<I>Subnetinsubnet</I>
+
+returns
+non-zero
+if subnet
+<I>a</I>
+
+is a subset of subnet
+<I>b</I>
+
+and
+<B>0</B>
+
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+<P>
+
+<I>Subnetishost</I>
+
+returns
+non-zero
+if subnet
+<I>s</I>
+
+is in fact only a single host,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesaid</I>
+
+returns
+non-zero
+if SA IDs
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Sameaddrtype</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesubnettype</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_samesubnet.3.html b/doc/manpage.d/ipsec_samesubnet.3.html
new file mode 100644
index 000000000..414a0d513
--- /dev/null
+++ b/doc/manpage.d/ipsec_samesubnet.3.html
@@ -0,0 +1,274 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Nov 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec sameaddr - are two addresses the same?
+<BR>
+
+ipsec addrcmp - ordered comparison of addresses
+<BR>
+
+ipsec samesubnet - are two subnets the same?
+<BR>
+
+ipsec addrinsubnet - is an address within a subnet?
+<BR>
+
+ipsec subnetinsubnet - is a subnet within another subnet?
+<BR>
+
+ipsec subnetishost - is a subnet a single host?
+<BR>
+
+ipsec samesaid - are two SA IDs the same?
+<BR>
+
+ipsec sameaddrtype - are two addresses of the same address family?
+<BR>
+
+ipsec samesubnettype - are two subnets of the same address family?
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int sameaddr(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int addrcmp(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int addrinsubnet(const ip_address *a, const ip_subnet *s);</B>
+
+<BR>
+
+<B>int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int subnetishost(const ip_subnet *s);</B>
+
+<BR>
+
+<B>int samesaid(const ip_said *a, const ip_said *b);</B>
+
+<BR>
+
+<B>int sameaddrtype(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnettype(const ip_subnet *a, const ip_subnet *b);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions do various comparisons and tests on the
+<I>ip_address</I>
+
+type and
+<I>ip_subnet</I>
+
+types.
+<P>
+
+<I>Sameaddr</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Addresses of different families are never identical.
+<P>
+
+<I>Addrcmp</I>
+
+returns
+<B>-1</B>,
+
+<B>0</B>,
+
+or
+<B>1</B>
+
+respectively
+if address
+<I>a</I>
+
+is less than, equal to, or greater than
+<I>b</I>.
+
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+<P>
+
+<I>Samesubnet</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Subnets of different address families are never identical.
+<P>
+
+<I>Addrinsubnet</I>
+
+returns
+non-zero
+if address
+<I>a</I>
+
+is within subnet
+<I>s</I>
+
+and
+<B>0</B>
+
+otherwise.
+An address is never within a
+subnet of a different address family.
+<P>
+
+<I>Subnetinsubnet</I>
+
+returns
+non-zero
+if subnet
+<I>a</I>
+
+is a subset of subnet
+<I>b</I>
+
+and
+<B>0</B>
+
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+<P>
+
+<I>Subnetishost</I>
+
+returns
+non-zero
+if subnet
+<I>s</I>
+
+is in fact only a single host,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesaid</I>
+
+returns
+non-zero
+if SA IDs
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Sameaddrtype</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesubnettype</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_samesubnettype.3.html b/doc/manpage.d/ipsec_samesubnettype.3.html
new file mode 100644
index 000000000..414a0d513
--- /dev/null
+++ b/doc/manpage.d/ipsec_samesubnettype.3.html
@@ -0,0 +1,274 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Nov 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec sameaddr - are two addresses the same?
+<BR>
+
+ipsec addrcmp - ordered comparison of addresses
+<BR>
+
+ipsec samesubnet - are two subnets the same?
+<BR>
+
+ipsec addrinsubnet - is an address within a subnet?
+<BR>
+
+ipsec subnetinsubnet - is a subnet within another subnet?
+<BR>
+
+ipsec subnetishost - is a subnet a single host?
+<BR>
+
+ipsec samesaid - are two SA IDs the same?
+<BR>
+
+ipsec sameaddrtype - are two addresses of the same address family?
+<BR>
+
+ipsec samesubnettype - are two subnets of the same address family?
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int sameaddr(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int addrcmp(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int addrinsubnet(const ip_address *a, const ip_subnet *s);</B>
+
+<BR>
+
+<B>int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int subnetishost(const ip_subnet *s);</B>
+
+<BR>
+
+<B>int samesaid(const ip_said *a, const ip_said *b);</B>
+
+<BR>
+
+<B>int sameaddrtype(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnettype(const ip_subnet *a, const ip_subnet *b);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions do various comparisons and tests on the
+<I>ip_address</I>
+
+type and
+<I>ip_subnet</I>
+
+types.
+<P>
+
+<I>Sameaddr</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Addresses of different families are never identical.
+<P>
+
+<I>Addrcmp</I>
+
+returns
+<B>-1</B>,
+
+<B>0</B>,
+
+or
+<B>1</B>
+
+respectively
+if address
+<I>a</I>
+
+is less than, equal to, or greater than
+<I>b</I>.
+
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+<P>
+
+<I>Samesubnet</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Subnets of different address families are never identical.
+<P>
+
+<I>Addrinsubnet</I>
+
+returns
+non-zero
+if address
+<I>a</I>
+
+is within subnet
+<I>s</I>
+
+and
+<B>0</B>
+
+otherwise.
+An address is never within a
+subnet of a different address family.
+<P>
+
+<I>Subnetinsubnet</I>
+
+returns
+non-zero
+if subnet
+<I>a</I>
+
+is a subset of subnet
+<I>b</I>
+
+and
+<B>0</B>
+
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+<P>
+
+<I>Subnetishost</I>
+
+returns
+non-zero
+if subnet
+<I>s</I>
+
+is in fact only a single host,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesaid</I>
+
+returns
+non-zero
+if SA IDs
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Sameaddrtype</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesubnettype</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_satoa.3.html b/doc/manpage.d/ipsec_satoa.3.html
new file mode 100644
index 000000000..2b2c7425c
--- /dev/null
+++ b/doc/manpage.d/ipsec_satoa.3.html
@@ -0,0 +1,347 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOSA</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOSA</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atosa, satoa - convert IPsec Security Association IDs to and from ASCII
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atosa(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct sa_id *sa);</B>
+
+<BR>
+
+<B>size_t satoa(struct sa_id sa, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>struct sa_id {</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr dst;</B>
+
+<BR>
+&nbsp;
+<B>ipsec_spi_t spi;</B>
+
+<BR>
+&nbsp;
+<B>int proto;</B>
+
+<BR>
+
+<B>};</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_ttosa.3.html">ipsec_ttosa</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Atosa</I>
+
+converts an ASCII Security Association (SA) specifier into an
+<B>sa_id</B>
+
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+<I>Satoa</I>
+
+does the reverse conversion, back to an ASCII SA specifier.
+<P>
+
+An SA is specified in ASCII with a mail-like syntax, e.g.
+<B><A HREF="mailto:esp507@1.2.3.4">esp507@1.2.3.4</A></B>.
+
+An SA specifier contains
+a protocol prefix (currently
+<B>ah</B>,
+
+<B>esp</B>,
+
+or
+<B>tun</B>),
+
+an unsigned integer SPI number,
+and an IP address.
+The SPI number can be decimal or hexadecimal
+(with
+<B>0x</B>
+
+prefix), as accepted by
+<I><A HREF="ipsec_atoul.3.html">ipsec_atoul</A></I>(3).
+
+The IP address can be any form accepted by
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3),
+
+e.g. dotted-decimal address or DNS name.
+<P>
+
+As a special case, the SA specifier
+<B>%passthrough</B>
+
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, this is a synonym for
+<B><A HREF="mailto:tun0x0@0.0.0.0">tun0x0@0.0.0.0</A></B>,
+
+but that is subject to change without notice.)
+This form is known to both
+<I>atosa</I>
+
+and
+<I>satoa</I>,
+
+so the internal form of
+<B>%passthrough</B>
+
+is never visible.
+<P>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file supplies the
+<B>sa_id</B>
+
+structure, as well as a data type
+<B>ipsec_spi_t</B>
+
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+<P>
+
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+defines the names
+<B>SA_ESP</B>,
+
+<B>SA_AH</B>,
+
+and
+<B>SA_IPIP</B>
+
+to have the same values as the kernel names
+<B>IPPROTO_ESP</B>,
+
+<B>IPPROTO_AH</B>,
+
+and
+<B>IPPROTO_IPIP</B>.
+
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atosa</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>satoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines a constant,
+<B>SATOA_BUF</B>,
+
+which is the size of a buffer just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>satoa</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI, dotted-decimal address).
+The value
+<B>d</B>
+
+causes the SPI to be generated in decimal instead.
+<P>
+
+<I>Atosa</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Satoa</I>
+
+returns
+<B>0</B>
+
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_atoul.3.html">ipsec_atoul</A>(3), <A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A>(3), <A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atosa</I>
+
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+<B>@</B>
+
+in input;
+unknown protocol prefix;
+conversion error in
+<I>atoul</I>
+
+or
+<I>atoaddr</I>.
+
+<P>
+
+Fatal errors in
+<I>satoa</I>
+
+are:
+unknown format; unknown protocol code.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The
+<B>tun</B>
+
+protocol code is a FreeS/WANism which may eventually disappear.
+<P>
+
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_satot.3.html b/doc/manpage.d/ipsec_satot.3.html
new file mode 100644
index 000000000..1e457fc24
--- /dev/null
+++ b/doc/manpage.d/ipsec_satot.3.html
@@ -0,0 +1,453 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOSA</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOSA</H1>
+Section: C Library Functions (3)<BR>Updated: 26 Nov 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttosa, satot - convert IPsec Security Association IDs to and from text
+<BR>
+
+ipsec initsaid - initialize an SA ID
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>typedef struct {</B>
+
+<BR>
+&nbsp;
+<B>ip_address dst;</B>
+
+<BR>
+&nbsp;
+<B>ipsec_spi_t spi;</B>
+
+<BR>
+&nbsp;
+<B>int proto;</B>
+
+<BR>
+
+<B>} ip_said;</B>
+
+<P>
+<B>const char *ttosa(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>ip_said *sa);</B>
+
+<BR>
+
+<B>size_t satot(const ip_said *sa, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>void initsaid(const ip_address *addr, ipsec_spi_t spi,</B>
+
+<BR>
+&nbsp;
+<B>int proto, ip_said *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttosa</I>
+
+converts an ASCII Security Association (SA) specifier into an
+<B>ip_said</B>
+
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+<I>Satot</I>
+
+does the reverse conversion, back to a text SA specifier.
+<I>Initsaid</I>
+
+initializes an
+<B>ip_said</B>
+
+from separate items of information.
+<P>
+
+An SA is specified in text with a mail-like syntax, e.g.
+<B><A HREF="mailto:esp.5a7@1.2.3.4">esp.5a7@1.2.3.4</A></B>.
+
+An SA specifier contains
+a protocol prefix (currently
+<B>ah</B>,
+
+<B>esp</B>,
+
+<B>tun</B>,
+
+<B>comp</B>,
+
+or
+<B>int</B>),
+
+a single character indicating the address family
+(<B>.</B>
+
+for IPv4,
+<B>:</B>
+
+for IPv6),
+an unsigned integer SPI number in hexadecimal (with no
+<B>0x</B>
+
+prefix),
+and an IP address.
+The IP address can be any form accepted by
+<I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3),
+
+e.g. dotted-decimal IPv4 address,
+colon-hex IPv6 address,
+or DNS name.
+<P>
+
+As a special case, the SA specifier
+<B>%passthrough4</B>
+
+or
+<B>%passthrough6</B>
+
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, these are synonyms for
+<B><A HREF="mailto:tun.0@0.0.0.0">tun.0@0.0.0.0</A></B>
+
+and
+<B>tun:0@::</B>
+
+respectively,
+but that is subject to change without notice.)
+<B>%passthrough</B>
+
+is a historical synonym for
+<B>%passthrough4</B>.
+
+These forms are known to both
+<I>ttosa</I>
+
+and
+<I>satot</I>,
+
+so the internal representation is never visible.
+<P>
+
+Similarly, the SA specifiers
+<B>%pass</B>,
+
+<B>%drop</B>,
+
+<B>%reject</B>,
+
+<B>%hold</B>,
+
+<B>%trap</B>,
+
+and
+<B>%trapsubnet</B>
+
+signify special ``magic'' SAs used to indicate that packets should be
+passed, dropped, rejected (dropped with ICMP notification),
+held,
+and trapped (sent up to
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8),
+
+with either of two forms of
+<B>%hold</B>
+
+automatically installed)
+respectively.
+These forms too are known to both routines,
+so the internal representation of the magic SAs should never be visible.
+<P>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file supplies the
+<B>ip_said</B>
+
+structure, as well as a data type
+<B>ipsec_spi_t</B>
+
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+<P>
+
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+defines the names
+<B>SA_ESP</B>,
+
+<B>SA_AH</B>,
+
+<B>SA_IPIP</B>,
+
+and
+<B>SA_COMP</B>
+
+to have the same values as the kernel names
+<B>IPPROTO_ESP</B>,
+
+<B>IPPROTO_AH</B>,
+
+<B>IPPROTO_IPIP</B>,
+
+and
+<B>IPPROTO_COMP</B>.
+
+<P>
+
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+also defines
+<B>SA_INT</B>
+
+to have the value
+<B>61</B>
+
+(reserved by IANA for ``any host internal protocol'')
+and
+<B>SPI_PASS</B>,
+
+<B>SPI_DROP</B>,
+
+<B>SPI_REJECT</B>,
+
+<B>SPI_HOLD</B>,
+
+and
+<B>SPI_TRAP</B>
+
+to have the values 256-260 (in <I>host</I> byte order) respectively.
+These are used in constructing the magic SAs
+(which always have address
+<B>0.0.0.0</B>).
+
+<P>
+
+If
+<I>satot</I>
+
+encounters an unknown protocol code, e.g. 77,
+it yields output using a prefix
+showing the code numerically, e.g. ``unk77''.
+This form is
+<I>not</I>
+
+recognized by
+<I>ttosa</I>.
+
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttosa</I>
+
+specifies the length of the string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>satot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file defines a constant,
+<B>SATOT_BUF</B>,
+
+which is the size of a buffer just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>satot</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI,
+dotted-decimal or colon-hex address).
+The value
+<B>'f'</B>
+
+is similar except that the SPI is padded with
+<B>0</B>s
+
+to a fixed 32-bit width, to ease aligning displayed tables.
+<P>
+
+<I>Ttosa</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Satot</I>
+
+returns
+<B>0</B>
+
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<P>
+
+There is also, temporarily, support for some obsolete
+forms of SA specifier which lack the address-family indicator.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_ttoul.3.html">ipsec_ttoul</A>(3), <A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A>(3), <A HREF="ipsec_samesaid.3.html">ipsec_samesaid</A>(3), <A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttosa</I>
+
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+<B>@</B>
+
+in input;
+unknown protocol prefix;
+conversion error in
+<I>ttoul</I>
+
+or
+<I>ttoaddr</I>.
+
+<P>
+
+Fatal errors in
+<I>satot</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttosa( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_send-pr.8.html b/doc/manpage.d/ipsec_send-pr.8.html
new file mode 100644
index 000000000..19026543a
--- /dev/null
+++ b/doc/manpage.d/ipsec_send-pr.8.html
@@ -0,0 +1,427 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of SEND-PR</TITLE>
+</HEAD><BODY>
+<H1>SEND-PR</H1>
+Section: User Commands (1)<BR>Updated: xVERSIONx<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec send-pr - send problem report (PR) to a central support site
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec send-pr</B>
+
+[
+<I>site</I>
+
+]
+[
+<B>-f</B>
+
+<I>problem-report</I>
+
+]
+[
+<B>-t</B>
+
+<I>mail-address</I>
+
+]
+<BR>
+
+
+[
+<B>-P</B>
+
+]
+[
+<B>-L</B>
+
+]
+[
+<B>-s</B>
+
+<I>severity</I>
+
+]
+[
+<B>-c</B>
+
+<I>address</I>
+
+]
+<BR>
+
+[
+<B>--request-id</B>
+
+]
+[
+<B>-V</B>
+
+]
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<B>ipsec send-pr</B>
+
+is a tool used to submit
+<I>problem reports </I>
+
+
+(PRs) to a central support site. In most cases the correct
+<I>site</I>
+
+will be the default. This argument indicates the support site which
+is responsible for the category of problem involved. Some sites may
+use a local address as a default.
+<I>site</I>
+
+values are defined by using the
+<B><A HREF="aliases.5.html">aliases</A></B>(5).
+
+<P>
+
+<B>ipsec send-pr</B>
+
+invokes an editor on a problem report template (after trying to fill
+in some fields with reasonable default values). When you exit the
+editor,
+<B>ipsec send-pr </B>
+
+sends the completed form to the
+<I>Problem Report Management System</I>
+
+(<B>GNATS</B>) at a central support site. At the support site, the PR
+is assigned a unique number and is stored in the <B>GNATS</B> database
+according to its category and submitter-id. <B>GNATS</B> automatically
+replies with an acknowledgement, citing the category and the PR
+number.
+<P>
+
+To ensure that a PR is handled promptly, it should contain your (unique)
+<I>submitter-id</I> and one of the available <I>categories</I> to identify the
+problem area. (Use
+<B>`ipsec send-pr -L'</B>
+
+to see a list of categories.)
+<P>
+
+The
+<B>ipsec send-pr</B>
+
+template at your site should already be customized with your
+submitter-id (running `<B>install-sid</B> <I>submitter-id</I>' to
+accomplish this is part of the installation procedures for
+<B>ipsec</B>send-pr<B>).</B>
+
+If this hasn't been done, see your system administrator for your
+submitter-id, or request one from your support site by invoking
+<B>`ipsec send-pr --request-id'.</B>
+
+If your site does not distinguish between different user sites, or if
+you are not affiliated with the support site, use
+<B>`net'</B>
+
+for this field.
+<P>
+
+The more precise your problem description and the more complete your
+information, the faster your support team can solve your problems.
+<A NAME="lbAE">&nbsp;</A>
+<H2>OPTIONS</H2>
+
+<DL COMPACT>
+<DT><B>-f</B><I> problem-report</I>
+
+<DD>
+specify a file (<I>problem-report</I>) which already contains a
+complete problem report.
+<B>ipsec send-pr</B>
+
+sends the contents of the file without invoking the editor. If
+the value for
+<I>problem-report</I>
+
+is
+<B>`-'</B>,
+
+then
+<B>ipsec send-pr</B>
+
+reads from standard input.
+<DT><B>-s</B><I> severity</I>
+
+<DD>
+Give the problem report the severity
+<I>severity</I>.
+
+<DT><B>-t</B><I> mail-address</I>
+
+<DD>
+Change mail address at the support site for problem reports. The
+default
+<I>mail-address</I>
+
+is the address used for the default
+<I>site</I>.
+
+Use the
+<I>site</I>
+
+argument rather than this option in nearly all cases.
+<DT><B>-c</B><I> address</I>
+
+<DD>
+Put
+<I>address</I>
+
+in the
+<B>Cc:</B>
+
+header of the message.
+<DT><B>-P</B>
+
+<DD>
+print the form specified by the environment variable
+<B>PR_FORM </B>
+
+on standard output. If
+<B>PR_FORM</B>
+
+is not set, print the standard blank PR template. No mail is sent.
+<DT><B>-L</B>
+
+<DD>
+print the list of available categories. No mail is sent.
+<DT><B>--request-id</B>
+
+<DD>
+sends mail to the default support site, or
+<I>site</I>
+
+if specified, with a request for your
+<I>submitter-id</I>.
+
+If you are
+not affiliated with
+<I>site</I>,
+
+use a
+<I>submitter-id</I>
+
+of
+<B>net</B>'.
+
+<DT><B>-V</B>
+
+<DD>
+Display the
+<B>ipsec send-pr</B>
+
+version number.
+</DL>
+<P>
+
+Note: use
+<B>ipsec send-pr</B>
+
+to submit problem reports rather than mailing them directly. Using
+both the template and
+<B>ipsec send-pr</B>
+
+itself will help ensure all necessary information will reach the
+support site.
+<A NAME="lbAF">&nbsp;</A>
+<H2>ENVIRONMENT</H2>
+
+The environment variable
+<B>EDITOR</B>
+
+specifies the editor to invoke on the template.
+<BR>
+
+default:
+<B>vi</B>
+
+<P>
+If the environment variable
+<B>PR_FORM</B>
+
+is set, then its value is used as the file name of the template for
+your problem-report editing session. You can use this to start with a
+partially completed form (for example, a form with the identification
+fields already completed).
+<A NAME="lbAG">&nbsp;</A>
+<H2>HOW TO FILL OUT A PROBLEM REPORT</H2>
+
+Problem reports have to be in a particular form so that a program can
+easily manage them. Please remember the following guidelines:
+<DL COMPACT>
+<DT>*<DD>
+describe only
+<B>one problem</B>
+
+with each problem report.
+<DT>*<DD>
+For follow-up mail, use the same subject line as the one in the automatic
+acknowledgent. It consists of category, PR number and the original synopsis
+line. This allows the support site to relate several mail messages to a
+particular PR and to record them automatically.
+<DT>*<DD>
+Please try to be as accurate as possible in the subject and/or synopsis line.
+<DT>*<DD>
+The subject and the synopsis line are not confidential. This is
+because open-bugs lists are compiled from them. Avoid confidential
+information there.
+</DL>
+<P>
+
+See the GNU
+<B>Info </B>
+
+file
+<B>send-pr.info</B>
+
+or the document <I>Reporting Problems With send-pr</I>&nbsp;for detailed
+information on reporting problems
+<A NAME="lbAH">&nbsp;</A>
+<H2>HOW TO SUBMIT TEST CASES, CODE, ETC.</H2>
+
+Submit small code samples with the PR. Contact the support site for
+instructions on submitting larger test cases and problematic source
+code.
+<A NAME="lbAI">&nbsp;</A>
+<H2>FILES</H2>
+
+
+
+/tmp/p$$<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>copy of PR used in editing session<BR>
+<BR>
+
+/tmp/pf$$<TT>&nbsp;&nbsp;&nbsp;</TT>copy of empty PR form, for testing purposes<BR>
+<BR>
+
+/tmp/pbad$$<TT>&nbsp;</TT>file for rejected PRs<BR>
+<BR>
+
+@IPSEC_DIR@/send-pr.confscript to customize send-pr.<BR>
+<A NAME="lbAJ">&nbsp;</A>
+<H2>EMACS USER INTERFACE</H2>
+
+An Emacs user interface for
+<B>send-pr</B>
+
+with completion of field values is part of the
+<B>send-pr</B>
+
+distribution (invoked with
+<B>M-x send-pr</B>).
+
+See the file
+<B>send-pr.info</B>
+
+or the ASCII file
+<B>INSTALL</B>
+
+in the top level directory of the distribution for configuration and
+installation information. The Emacs LISP template file is
+<B>send-pr-el.in</B>
+
+and is installed as
+<B>send-pr.el</B>.
+
+<A NAME="lbAK">&nbsp;</A>
+<H2>INSTALLATION AND CONFIGURATION</H2>
+
+See
+<B>send-pr.info</B>
+
+or
+<B>INSTALL</B>
+
+for installation instructions.
+<A NAME="lbAL">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<I>Reporting Problems Using send-pr</I>
+
+(also installed as the GNU Info file
+<B>send-pr.info</B>).
+
+<P>
+
+<B><A HREF="http://localhost/cgi-bin/man/man2html?l+gnats">gnats</A></B>(l),
+
+<B><A HREF="query-pr.1.html">query-pr</A></B>(1),
+
+<B><A HREF="edit-pr.1.html">edit-pr</A></B>(1),
+
+<B><A HREF="gnats.8.html">gnats</A></B>(8),
+
+<B><A HREF="queue-pr.8.html">queue-pr</A></B>(8),
+
+<B><A HREF="at-pr.8.html">at-pr</A></B>(8),
+
+<B><A HREF="mkcat.8.html">mkcat</A></B>(8),
+
+<B><A HREF="mkdist.8.html">mkdist</A></B>(8).
+
+<A NAME="lbAM">&nbsp;</A>
+<H2>AUTHORS</H2>
+
+Jeffrey Osier, Brendan Kehoe, Jason Merrill, Heinz G. Seidl (Cygnus
+Support)
+<A NAME="lbAN">&nbsp;</A>
+<H2>COPYING</H2>
+
+Copyright (c) 1992, 1993 Free Software Foundation, Inc.
+<P>
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+<P>
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+<P>
+
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
+<P>
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">OPTIONS</A><DD>
+<DT><A HREF="#lbAF">ENVIRONMENT</A><DD>
+<DT><A HREF="#lbAG">HOW TO FILL OUT A PROBLEM REPORT</A><DD>
+<DT><A HREF="#lbAH">HOW TO SUBMIT TEST CASES, CODE, ETC.</A><DD>
+<DT><A HREF="#lbAI">FILES</A><DD>
+<DT><A HREF="#lbAJ">EMACS USER INTERFACE</A><DD>
+<DT><A HREF="#lbAK">INSTALLATION AND CONFIGURATION</A><DD>
+<DT><A HREF="#lbAL">SEE ALSO</A><DD>
+<DT><A HREF="#lbAM">AUTHORS</A><DD>
+<DT><A HREF="#lbAN">COPYING</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_setportof.3.html b/doc/manpage.d/ipsec_setportof.3.html
new file mode 100644
index 000000000..3965ca62d
--- /dev/null
+++ b/doc/manpage.d/ipsec_setportof.3.html
@@ -0,0 +1,143 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PORTOF</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PORTOF</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec portof - get port field of an ip_address
+<BR>
+
+ipsec setportof - set port field of an ip_address
+<BR>
+
+ipsec sockaddrof - get pointer to internal sockaddr of an ip_address
+<BR>
+
+ipsec sockaddrlenof - get length of internal sockaddr of an ip_address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int portof(const ip_address *src);</B>
+
+<BR>
+
+<B>void setportof(int port, ip_address *dst);</B>
+
+<BR>
+
+<B>struct sockaddr *sockaddrof(ip_address *src);</B>
+
+<BR>
+
+<B>size_t sockaddrlenof(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+internal type
+<I>ip_address</I>
+
+contains one of the
+<I>sockaddr</I>
+
+types internally.
+<I>Reliance on this feature is discouraged</I>,
+but it may occasionally be necessary.
+These functions provide low-level tools for this purpose.
+<P>
+
+<I>Portof</I>
+
+and
+<I>setportof</I>
+
+respectively read and write the port-number field of the internal
+<I>sockaddr</I>.
+
+The values are in network byte order.
+<P>
+
+<I>Sockaddrof</I>
+
+returns a pointer to the internal
+<I>sockaddr</I>,
+
+for passing to other functions.
+<P>
+
+<I>Sockaddrlenof</I>
+
+reports the size of the internal
+<I>sockaddr</I>,
+
+for use in storage allocation.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+<I>Portof</I>
+
+returns
+<B>-1</B>,
+
+<I>sockaddrof</I>
+
+returns
+<B>NULL</B>,
+
+and
+<I>sockaddrlenof</I>
+
+returns
+<B>0</B>
+
+if an unknown address family is found within the
+<I>ip_address</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+These functions all depend on low-level details of the
+<I>ip_address</I>
+
+type, which are in principle subject to change.
+Avoid using them unless really necessary.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_setup.8.html b/doc/manpage.d/ipsec_setup.8.html
new file mode 100644
index 000000000..7197e2b18
--- /dev/null
+++ b/doc/manpage.d/ipsec_setup.8.html
@@ -0,0 +1,237 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SETUP</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SETUP</H1>
+Section: Maintenance Commands (8)<BR>Updated: 23 July 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec setup - control IPsec subsystem
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>setup</B>
+
+[
+<B>--show</B>
+
+|
+<B>--showonly</B>
+
+]
+command
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Setup</I>
+
+controls the FreeS/WAN IPsec subsystem,
+including both the Klips kernel code and the Pluto key-negotiation daemon.
+(It is a synonym for the ``rc'' script for the subsystem;
+the system runs the equivalent of
+<B>ipsec setup start</B>
+
+at boot time,
+and
+<B>ipsec setup stop</B>
+
+at shutdown time, more or less.)
+<P>
+
+The action taken depends on the specific
+<I>command</I>,
+
+and on the contents of the
+<B>config</B>
+
+<B>setup</B>
+
+section of the
+IPsec configuration file (<I>/etc/ipsec.conf</I>,
+
+see
+<I><A HREF="ipsec.conf.5.html">ipsec.conf</A></I>(5)).
+
+Current
+<I>command</I>s
+
+are:
+<DL COMPACT>
+<DT><B>start</B>
+
+<DD>
+start Klips and Pluto,
+including setting up Klips to do crypto operations on the
+interface(s) specified in the configuration file,
+and (if the configuration file so specifies)
+setting up manually-keyed connections and/or
+asking Pluto to negotiate automatically-keyed connections
+to other security gateways
+<DT><B>stop</B>
+
+<DD>
+shut down Klips and Pluto,
+including tearing down all existing crypto connections
+<DT><B>restart</B>
+
+<DD>
+equivalent to
+<B>stop</B>
+
+followed by
+<B>start</B>
+
+<DT><B>status</B>
+
+<DD>
+report the status of the subsystem;
+normally just reports
+<B>IPsec running</B>
+
+and
+<B>pluto pid </B><I>nnn</I>,
+
+or
+<B>IPsec stopped</B>,
+
+and exits with status 0,
+but will go into more detail (and exit with status 1)
+if something strange is found.
+(An ``illicit'' Pluto is one that does not match the process ID in
+Pluto's lock file;
+an ``orphaned'' Pluto is one with no lock file.)
+</DL>
+<P>
+
+The
+<B>stop</B>
+
+operation tries to clean up properly even if assorted accidents
+have occurred,
+e.g. Pluto having died without removing its lock file.
+If
+<B>stop</B>
+
+discovers that the subsystem is (supposedly) not running,
+it will complain,
+but will do its cleanup anyway before exiting with status 1.
+<P>
+
+Although a number of configuration-file parameters influence
+<I>setup</I>'s
+
+operations, the key one is the
+<B>interfaces</B>
+
+parameter, which must be right or chaos will ensue.
+<P>
+
+The
+<B>--show</B>
+
+and
+<B>--showonly</B>
+
+options cause
+<I>setup</I>
+
+to display the shell commands that it would execute.
+<B>--showonly</B>
+
+suppresses their execution.
+Only
+<B>start</B>,
+
+<B>stop</B>,
+
+and
+<B>restart</B>
+
+commands recognize these flags.
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+
+
+/etc/rc.d/init.d/ipsec<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>the script itself<BR>
+<BR>
+
+/etc/init.d/ipsec<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>alternate location for the script<BR>
+<BR>
+
+/etc/ipsec.conf<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>IPsec configuration file<BR>
+<BR>
+
+/proc/sys/net/ipv4/ip_forward<TT>&nbsp;</TT>forwarding control<BR>
+<BR>
+
+/var/run/ipsec.info<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>saved information<BR>
+<BR>
+
+/var/run/pluto.pid<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>Pluto lock file<BR>
+<BR>
+
+/var/run/ipsec_setup.pid<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>IPsec lock file<BR>
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.conf.5.html">ipsec.conf</A>(5), <A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_auto.8.html">ipsec_auto</A>(8), <A HREF="route.8.html">route</A>(8)
+<A NAME="lbAG">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+All output from the commands
+<B>start</B>
+
+and
+<B>stop</B>
+
+goes both to standard
+output and to
+<I><A HREF="syslogd.8.html">syslogd</A></I>(8),
+
+via
+<I><A HREF="logger.1.html">logger</A></I>(1).
+
+Selected additional information is logged only to
+<I><A HREF="syslogd.8.html">syslogd</A></I>(8).
+
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<A NAME="lbAI">&nbsp;</A>
+<H2>BUGS</H2>
+
+Old versions of
+<I><A HREF="logger.1.html">logger</A></I>(1)
+
+inject spurious extra newlines onto standard output.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+<DT><A HREF="#lbAI">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_showdefaults.8.html b/doc/manpage.d/ipsec_showdefaults.8.html
new file mode 100644
index 000000000..e1786dc0a
--- /dev/null
+++ b/doc/manpage.d/ipsec_showdefaults.8.html
@@ -0,0 +1,82 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SHOWDEFAULTS</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SHOWDEFAULTS</H1>
+Section: Maintenance Commands (8)<BR>Updated: 23 Jan 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec showdefaults - show %defaultroute defaults
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>showdefaults</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Showdefaults</I>
+
+outputs (on standard output) a terse description of the defaults
+used by the
+<B>%defaultroute</B>
+
+facilities in
+<I><A HREF="ipsec_auto.8.html">ipsec_auto</A></I>(8)
+
+and
+<I><A HREF="ipsec_manual.8.html">ipsec_manual</A></I>(8).
+
+<P>
+
+Beware that the exact output format is subject to change.
+<A NAME="lbAE">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Normal exit status is 0.
+If no defaults are available,
+i.e. the
+<B>interfaces</B>
+
+parameter in
+<B>config setup</B>
+
+is not
+<B>%defaultroute</B>,
+
+produces a message on standard error and exits with status 1.
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/var/run/ipsec.info
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_showhostkey.8.html b/doc/manpage.d/ipsec_showhostkey.8.html
new file mode 100644
index 000000000..90a16d5ee
--- /dev/null
+++ b/doc/manpage.d/ipsec_showhostkey.8.html
@@ -0,0 +1,269 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SHOWHOSTKEY</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SHOWHOSTKEY</H1>
+Section: Maintenance Commands (8)<BR>Updated: 5 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec showhostkey - show host's authentication key
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>showhostkey</B>
+
+[
+<B>--key</B>
+
+] [
+<B>--left</B>
+
+] [
+<B>--right</B>
+
+] [
+<B>--txt</B>
+
+gateway
+] [
+<B>--dhclient</B>
+
+] [
+<B>--file</B>
+
+secretfile
+] [
+<B>--id</B>
+
+identity
+]
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Showhostkey</I>
+
+outputs (on standard output) a public key suitable for this host,
+in the format specified,
+using the host key information stored in
+<I>/etc/ipsec.secrets</I>.
+
+In general only the super-user can run this command,
+since only he can read
+<I>ipsec.secrets</I>.
+
+<P>
+
+The
+<B>--txt</B>
+
+option causes the output to be in opportunistic-encryption DNS TXT record
+format,
+with the specified
+<I>gateway</I>
+
+value.
+If information about how the key was generated is available,
+that is provided as a DNS-file comment.
+For example,
+<B>--txt 10.11.12.13</B>
+
+might give (with the key data trimmed for clarity):
+<P>
+
+<PRE>
+ ; RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=10.11.12.13 AQOF8tZ2...+buFuFn/&quot;
+</PRE>
+
+<P>
+
+No name is supplied in the TXT record
+because there are too many possibilities,
+depending on how it will be used.
+If the text string is longer than 255 bytes,
+it is split up into multiple strings (matching the restrictions of
+the DNS TXT binary format).
+If any split is needed, the first split will be at the start of the key:
+this increases the chances that later hand editing will work.
+<P>
+
+The
+<B>--left</B>
+
+and
+<B>--right</B>
+
+options cause the output to be in
+<I><A HREF="ipsec.conf.5.html">ipsec.conf</A></I>(5)
+
+format, as a
+<B>leftrsasigkey</B>
+
+or
+<B>rightrsasigkey</B>
+
+parameter respectively.
+Again, generation information is included if available.
+For example,
+<B>--left</B>
+
+might give (with the key data trimmed down for clarity):
+<P>
+
+<PRE>
+ # RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ leftrsasigkey=0sAQOF8tZ2...+buFuFn/
+</PRE>
+
+<P>
+
+The
+<B>--dhclient</B>
+
+option cause the output to be suitable for inclusion in
+<I><A HREF="dhclient.conf.5.html">dhclient.conf</A></I>(5)
+
+as part of configuring WAVEsec.
+See &lt;<A HREF="http://www.wavesec.org">http://www.wavesec.org</A>&gt;.
+<P>
+
+If
+<B>--key</B>
+
+is specified,
+the output format is the text form of a DNS KEY record;
+the host name is the one included in the key information
+(or, if that is not available,
+the output of
+<B>hostname&nbsp;--fqdn</B>),
+
+with a
+<B>.</B>
+
+appended.
+Again, generation information is included if available.
+For example (with the key data trimmed down for clarity):
+<P>
+
+<PRE>
+ ; RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ xy.example.com. IN KEY 0x4200 4 1 AQOF8tZ2...+buFuFn/
+</PRE>
+
+<P>
+
+Normally, the default key for this host
+(the one with no host identities specified for it) is the one extracted.
+The
+<B>--id</B>
+
+option overrides this,
+causing extraction of the key labeled with the specified
+<I>identity</I>,
+
+if any.
+The specified
+<I>identity</I>
+
+must
+<I>exactly</I>
+
+match the identity in the file;
+in particular, the comparison is case-sensitive.
+<P>
+
+The
+<B>--file</B>
+
+option overrides the default for where the key information should be
+found, and takes it from the specified
+<I>secretfile</I>.
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+A complaint about ``no pubkey line found'' indicates that the
+host has a key but it was generated with an old version of FreeS/WAN
+and does not contain the information that
+<I>showhostkey</I>
+
+needs.
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/etc/ipsec.secrets
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.secrets.5.html">ipsec.secrets</A>(5), <A HREF="ipsec.conf.5.html">ipsec.conf</A>(5), <A HREF="ipsec_rsasigkey.8.html">ipsec_rsasigkey</A>(8)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Henry Spencer.
+<A NAME="lbAI">&nbsp;</A>
+<H2>BUGS</H2>
+
+Arguably,
+rather than just reporting the no-IN-KEY-line-found problem,
+<I>showhostkey</I>
+
+should be smart enough to run the existing key through
+<I>rsasigkey</I>
+
+with the
+<B>--oldkey</B>
+
+option, to generate a suitable output line.
+<P>
+
+The need to specify the gateway address (etc.) for
+<B>--txt</B>
+
+is annoying, but there is no good way to determine it automatically.
+<P>
+
+There should be a way to specify the priority value for TXT records;
+currently it is hardwired to
+<B>10</B>.
+
+<P>
+
+The
+<B>--id</B>
+
+option assumes that the
+<I>identity</I>
+
+appears on the same line as the
+<B>:&nbsp;RSA&nbsp;{</B>
+
+that begins the key proper.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+<DT><A HREF="#lbAI">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_showpolicy.8.html b/doc/manpage.d/ipsec_showpolicy.8.html
new file mode 100644
index 000000000..470c40879
--- /dev/null
+++ b/doc/manpage.d/ipsec_showpolicy.8.html
@@ -0,0 +1,88 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SHOWPOLICY</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SHOWPOLICY</H1>
+Section: Maintenance Commands (8)<BR>Updated: 7 May 2003<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec showpolicy - dump policy of socket found as stdin
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<P>
+
+<B>ipsec</B>
+
+<B>showpolicy</B>
+
+<P>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>showpolicy</I>
+
+calls the
+<I><A HREF="ipsec_policy_lookup.3.html">ipsec_policy_lookup</A></I>(3)
+
+function on the file description which is its stdin.
+<P>
+
+It then dumps the resulting query in a human readable form.
+<P>
+
+This is a test program. One might run it from inetd, via:
+<DL COMPACT>
+<DT>discard stream tcp nowait nobody /usr/local/libexec/ipsec/showpolicy showpolicy<DD>
+</DL>
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+/var/run/ipsecpolicy.ctl
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_policy_query.3.html">ipsec_policy_query</A>(3), <A HREF="ipsec_pluto.8.html">ipsec_pluto</A>(8)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael Richardson
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_sockaddrlenof.3.html b/doc/manpage.d/ipsec_sockaddrlenof.3.html
new file mode 100644
index 000000000..3965ca62d
--- /dev/null
+++ b/doc/manpage.d/ipsec_sockaddrlenof.3.html
@@ -0,0 +1,143 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PORTOF</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PORTOF</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec portof - get port field of an ip_address
+<BR>
+
+ipsec setportof - set port field of an ip_address
+<BR>
+
+ipsec sockaddrof - get pointer to internal sockaddr of an ip_address
+<BR>
+
+ipsec sockaddrlenof - get length of internal sockaddr of an ip_address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int portof(const ip_address *src);</B>
+
+<BR>
+
+<B>void setportof(int port, ip_address *dst);</B>
+
+<BR>
+
+<B>struct sockaddr *sockaddrof(ip_address *src);</B>
+
+<BR>
+
+<B>size_t sockaddrlenof(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+internal type
+<I>ip_address</I>
+
+contains one of the
+<I>sockaddr</I>
+
+types internally.
+<I>Reliance on this feature is discouraged</I>,
+but it may occasionally be necessary.
+These functions provide low-level tools for this purpose.
+<P>
+
+<I>Portof</I>
+
+and
+<I>setportof</I>
+
+respectively read and write the port-number field of the internal
+<I>sockaddr</I>.
+
+The values are in network byte order.
+<P>
+
+<I>Sockaddrof</I>
+
+returns a pointer to the internal
+<I>sockaddr</I>,
+
+for passing to other functions.
+<P>
+
+<I>Sockaddrlenof</I>
+
+reports the size of the internal
+<I>sockaddr</I>,
+
+for use in storage allocation.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+<I>Portof</I>
+
+returns
+<B>-1</B>,
+
+<I>sockaddrof</I>
+
+returns
+<B>NULL</B>,
+
+and
+<I>sockaddrlenof</I>
+
+returns
+<B>0</B>
+
+if an unknown address family is found within the
+<I>ip_address</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+These functions all depend on low-level details of the
+<I>ip_address</I>
+
+type, which are in principle subject to change.
+Avoid using them unless really necessary.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_sockaddrof.3.html b/doc/manpage.d/ipsec_sockaddrof.3.html
new file mode 100644
index 000000000..3965ca62d
--- /dev/null
+++ b/doc/manpage.d/ipsec_sockaddrof.3.html
@@ -0,0 +1,143 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PORTOF</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PORTOF</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec portof - get port field of an ip_address
+<BR>
+
+ipsec setportof - set port field of an ip_address
+<BR>
+
+ipsec sockaddrof - get pointer to internal sockaddr of an ip_address
+<BR>
+
+ipsec sockaddrlenof - get length of internal sockaddr of an ip_address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int portof(const ip_address *src);</B>
+
+<BR>
+
+<B>void setportof(int port, ip_address *dst);</B>
+
+<BR>
+
+<B>struct sockaddr *sockaddrof(ip_address *src);</B>
+
+<BR>
+
+<B>size_t sockaddrlenof(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+internal type
+<I>ip_address</I>
+
+contains one of the
+<I>sockaddr</I>
+
+types internally.
+<I>Reliance on this feature is discouraged</I>,
+but it may occasionally be necessary.
+These functions provide low-level tools for this purpose.
+<P>
+
+<I>Portof</I>
+
+and
+<I>setportof</I>
+
+respectively read and write the port-number field of the internal
+<I>sockaddr</I>.
+
+The values are in network byte order.
+<P>
+
+<I>Sockaddrof</I>
+
+returns a pointer to the internal
+<I>sockaddr</I>,
+
+for passing to other functions.
+<P>
+
+<I>Sockaddrlenof</I>
+
+reports the size of the internal
+<I>sockaddr</I>,
+
+for use in storage allocation.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+<I>Portof</I>
+
+returns
+<B>-1</B>,
+
+<I>sockaddrof</I>
+
+returns
+<B>NULL</B>,
+
+and
+<I>sockaddrlenof</I>
+
+returns
+<B>0</B>
+
+if an unknown address family is found within the
+<I>ip_address</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+These functions all depend on low-level details of the
+<I>ip_address</I>
+
+type, which are in principle subject to change.
+Avoid using them unless really necessary.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_spi.5.html b/doc/manpage.d/ipsec_spi.5.html
new file mode 100644
index 000000000..b1cf89033
--- /dev/null
+++ b/doc/manpage.d/ipsec_spi.5.html
@@ -0,0 +1,305 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SPI</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SPI</H1>
+Section: File Formats (5)<BR>Updated: 26 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec_spi - list IPSEC Security Associations
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<P>
+
+<B>cat</B>
+
+<B>/proc/net/ipsec_spi</B>
+
+<P>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>/proc/net/ipsec_spi</I>
+
+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).
+<P>
+
+When a packet is passed from a higher networking layer through an IPSEC
+virtual interface, a search in the extended routing table (see
+<I><A HREF="ipsec_eroute.5.html">ipsec_eroute</A></I>(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
+<I><A HREF="ipsec_spigrp.5.html">ipsec_spigrp</A></I>(5)
+
+for discussion of how multiple transforms are combined.)
+<P>
+
+An
+<I>spi ,</I>
+
+<I>proto, </I>
+
+<I>daddr</I>
+
+and
+<I>address_family</I>
+
+arguments specify an SAID.
+<I>Proto</I>
+
+is an ASCII string, &quot;ah&quot;, &quot;esp&quot;, &quot;comp&quot; or &quot;tun&quot;, specifying the IP protocol.
+<I>Spi</I>
+
+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</B>
+
+and
+<B>0xffffffff</B>;
+
+values from
+<B>0x0</B>
+
+to
+<B>0xff</B>
+
+are reserved.
+<I>Daddr</I>
+
+is a dotted-decimal IPv4 destination address or a coloned hex IPv6 destination address.
+<P>
+
+An
+<I>SAID</I>
+
+combines the three parameters above, such as: &quot;<A HREF="mailto:tun.101@1.2.3.4">tun.101@1.2.3.4</A>&quot; for IPv4 or &quot;tun:<A HREF="mailto:101@3049">101@3049</A>:1::1&quot; for IPv6
+<P>
+
+A table entry consists of:
+<DL COMPACT>
+<DT>+<DD>
+<B>SAID</B>
+
+<DT>+<DD>
+&lt;transform name (proto,encalg,authalg)&gt;:
+<DT>+<DD>
+direction (dir=)
+<DT>+<DD>
+source address (src=)
+<DT>+<DD>
+source and destination addresses and masks for inner header policy check
+addresses (policy=), as dotted-quads or coloned hex, separated by '-&gt;',
+for IPv4-in-IPv4 or IPv6-in-IPv6 SAs only
+<DT>+<DD>
+initialisation vector length and value (iv_bits=, iv=) if non-zero
+<DT>+<DD>
+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
+<DT>+<DD>
+extra flags (flags=) if any are set
+<DT>+<DD>
+authenticator length in bits (alen=) if non-zero
+<DT>+<DD>
+authentication key length in bits (aklen=) if non-zero
+<DT>+<DD>
+authentication errors (auth_errs=) if non-zero
+<DT>+<DD>
+encryption key length in bits (eklen=) if non-zero
+<DT>+<DD>
+encryption size errors (encr_size_errs=) if non-zero
+<DT>+<DD>
+encryption padding error warnings (encr_pad_errs=) if non-zero
+<DT>+<DD>
+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)=)
+<DT>+<DD>
+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
+<DT>+<DD>
+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
+<DT>+<DD>
+time since the SA was added (c), until rekey (s), until expiry (h), in seconds (add=)
+<DT>+<DD>
+time since the SA was first used (c), until rekey (s), until expiry (h), in seconds (used=),
+if any value is non-zero
+<DT>+<DD>
+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
+<DT>+<DD>
+time since the last packet was processed, in seconds (idle=), if SA has
+been used
+<DT><DD>
+average compression ratio (ratio=)
+</DL>
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<B><A HREF="mailto:tun.12a@192.168.43.1">tun.12a@192.168.43.1</A> IPIP: dir=out src=192.168.43.2</B>
+
+<BR>
+
+<B> life(c,s,h)=bytes(14073,0,0)add(269,0,0)</B>
+
+<BR>
+
+<B> use(149,0,0)packets(14,0,0)</B>
+
+<BR>
+
+<B> idle=23</B>
+
+<P>
+
+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.
+<P>
+
+<B>esp:<A HREF="mailto:9a35fc02@3049">9a35fc02@3049</A>:1::1 ESP_3DES_HMAC_MD5:</B>
+
+<BR>
+
+<B> dir=in src=<A HREF="mailto:9a35fc02@3049">9a35fc02@3049</A>:1::2</B>
+
+<BR>
+
+<B> ooowin=32 seq=7149 bit=0xffffffff</B>
+
+<BR>
+
+<B> alen=128 aklen=128 eklen=192</B>
+
+<BR>
+
+<B> life(c,s,h)=bytes(1222304,0,0)add(4593,0,0)</B>
+
+<BR>
+
+<B> use(3858,0,0)packets(7149,0,0)</B>
+
+<BR>
+
+<B> idle=23</B>
+
+<P>
+
+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.
+<P>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_spi, /usr/local/bin/ipsec
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_tncfg.5.html">ipsec_tncfg</A>(5), <A HREF="ipsec_eroute.5.html">ipsec_eroute</A>(5),
+<A HREF="ipsec_spigrp.5.html">ipsec_spigrp</A>(5), <A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5), <A HREF="ipsec_spi.8.html">ipsec_spi</A>(8), <A HREF="ipsec_version.5.html">ipsec_version</A>(5),
+<A HREF="ipsec_pf_key.5.html">ipsec_pf_key</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+<A NAME="lbAI">&nbsp;</A>
+<H2>BUGS</H2>
+
+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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+<DT><A HREF="#lbAI">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_spi.8.html b/doc/manpage.d/ipsec_spi.8.html
new file mode 100644
index 000000000..a40d06d9b
--- /dev/null
+++ b/doc/manpage.d/ipsec_spi.8.html
@@ -0,0 +1,790 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SPI</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SPI</H1>
+Section: Maintenance Commands (8)<BR>Updated: 23 Oct 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec spi - manage IPSEC Security Associations
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<BR>
+
+Note: In the following,
+<BR>
+
+<B>&lt;SA&gt;</B>
+
+means:
+<B>--af</B>
+
+(inet | inet6)
+<B>--edst</B>
+
+daddr
+<B>--spi</B>
+
+spi
+<B>--proto</B>
+
+proto OR
+<B>--said</B>
+
+said,
+<BR>
+
+<B>&lt;life&gt;</B>
+
+means:
+<B>--life</B>
+
+(soft | hard)-(allocations | bytes | addtime | usetime | packets)=value[,...]
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>&lt;SA&gt;</B>
+
+<B>--src</B>
+
+src
+<B>--ah</B>
+
+<B>hmac-md5-96</B>|<B>hmac-sha1-96</B>
+
+[
+<B>--replay_window</B>
+
+replayw ]
+[
+<B>&lt;life&gt;</B>
+
+]
+<B>--authkey</B>
+
+akey
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>&lt;SA&gt;</B>
+
+<B>--src</B>
+
+src
+<B>--esp</B>
+
+<B>3des</B>
+
+[
+<B>--replay_window</B>
+
+replayw ]
+[
+<B>&lt;life&gt;</B>
+
+]
+<B>--enckey</B>
+
+ekey
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>&lt;SA&gt;</B>
+
+<B>--src</B>
+
+src
+<B>--esp</B>
+
+<B>3des-md5-96</B>|<B>3des-sha1-96</B>
+
+[
+<B>--replay_window</B>
+
+replayw ]
+[
+<B>&lt;life&gt;</B>
+
+]
+<B>--enckey</B>
+
+ekey
+<B>--authkey</B>
+
+akey
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>&lt;SA&gt;</B>
+
+<B>--src</B>
+
+src
+<B>--comp</B>
+
+<B>deflate</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>&lt;SA&gt;</B>
+
+<B>--ip4</B>
+
+<B>--src</B>
+
+encap-src
+<B>--dst</B>
+
+encap-dst
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>&lt;SA&gt;</B>
+
+<B>--ip6</B>
+
+<B>--src</B>
+
+encap-src
+<B>--dst</B>
+
+encap-dst
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>&lt;SA&gt;</B>
+
+<B>--del</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>--help</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>--version</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>spi</B>
+
+<B>--clear</B>
+
+<P>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Spi</I>
+
+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).
+<P>
+
+When a packet is passed from a higher networking layer
+through an IPSEC virtual interface,
+a search in the extended routing table (see
+<I><A HREF="ipsec_eroute.8.html">ipsec_eroute</A></I>(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
+<I><A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A></I>(8)
+
+for discussion of how multiple transforms are combined.)
+<P>
+
+The
+<I>af</I>,
+
+<I>daddr</I>,
+
+<I>spi</I>
+
+and
+<I>proto</I>
+
+arguments specify the SA to be created or deleted.
+<I>af</I>
+
+is the address family (inet for IPv4, inet6 for IPv6).
+<I>Daddr</I>
+
+is a destination address
+in dotted-decimal notation for IPv4
+or in a coloned hex notation for IPv6.
+<I>Spi</I>
+
+is a number, preceded by '0x' for hexadecimal,
+between
+<B>0x100</B>
+
+and
+<B>0xffffffff</B>;
+
+values from
+<B>0x0</B>
+
+to
+<B>0xff</B>
+
+are reserved.
+<I>Proto</I>
+
+is an ASCII string, &quot;ah&quot;, &quot;esp&quot;, &quot;comp&quot; or &quot;tun&quot;, specifying the IP protocol.
+The protocol must agree with the algorithm selected.
+<P>
+
+Alternatively, the
+<I>said</I>
+
+argument can also specify an SA to be created or deleted.
+<I>Said</I>
+
+combines the three parameters above, such as: &quot;<A HREF="mailto:tun.101@1.2.3.4">tun.101@1.2.3.4</A>&quot; or &quot;tun:101@1:2::3:4&quot;,
+where the address family is specified by &quot;.&quot; for IPv4 and &quot;:&quot; for IPv6. The address
+family indicators substitute the &quot;0x&quot; for hexadecimal.
+<P>
+
+The source address,
+<I>src</I>,
+
+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.
+<P>
+
+Keys vectors must be entered as hexadecimal or base64 numbers.
+They should be cryptographically strong random numbers.
+<P>
+
+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
+<BR>&nbsp;(0-9,&nbsp;A-Z,&nbsp;a-z,&nbsp;'+'&nbsp;and&nbsp;'/'),&nbsp;without&nbsp;spaces,&nbsp;preceded&nbsp;by&nbsp;'0s',
+where each hexadecimal digit represents 6 bits and '=' is used for padding.
+<P>
+
+The deletion of an SA which has been grouped will result in the entire chain
+being deleted.
+<P>
+
+The form with no additional arguments lists the contents of
+/proc/net/ipsec_spi. The format of /proc/net/ipsec_spi is discussed in
+<A HREF="ipsec_spi.5.html">ipsec_spi</A>(5).
+<P>
+
+The lifetime severity of
+<B>soft</B>
+
+sets a limit when the key management daemons are asked to rekey the SA.
+The lifetime severity of
+<B>hard</B>
+
+sets a limit when the SA must expire.
+The lifetime type
+<B>allocations</B>
+
+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</B>
+
+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</B>
+
+tells the system to expire the SA a certain number of seconds after the SA was
+installed. The lifetime type of
+<B>usetime</B>
+
+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</B>
+
+tells the system to expire the SA after a certain number of packets have been
+processed with that SA.
+<A NAME="lbAE">&nbsp;</A>
+<H2>OPTIONS</H2>
+
+<DL COMPACT>
+<DT><B>--af</B>
+
+<DD>
+specifies the address family (inet for IPv4, inet6 for IPv6)
+<DT><B>--edst</B>
+
+<DD>
+specifies the effective destination
+<I>daddr</I>
+
+of the Security Association
+<DT><B>--spi</B>
+
+<DD>
+specifies the Security Parameters Index
+<I>spi</I>
+
+of the Security Association
+<DT><B>--proto</B>
+
+<DD>
+specifies the IP protocol
+<I>proto</I>
+
+of the Security Association
+<DT><B>--said</B>
+
+<DD>
+specifies the Security Association in monolithic format
+<DT><B>--ah</B>
+
+<DD>
+add an SA for an IPSEC Authentication Header,
+specified by the following transform identifier
+(<B>hmac-md5-96</B>
+
+or
+<B>hmac-sha1-96</B>)
+
+(RFC2402, obsoletes RFC1826)
+<DT><B>hmac-md5-96</B>
+
+<DD>
+transform following the HMAC and MD5 standards,
+using a 128-bit
+<I>key</I>
+
+to produce a 96-bit authenticator (RFC2403)
+<DT><B>hmac-sha1-96</B>
+
+<DD>
+transform following the HMAC and SHA1 standards,
+using a 160-bit
+<I>key</I>
+
+to produce a 96-bit authenticator (RFC2404)
+<DT><B>--esp</B>
+
+<DD>
+add an SA for an IPSEC Encapsulation Security Payload,
+specified by the following
+transform identifier (<B>3des</B>,
+
+or
+<B>3des-md5-96</B>)
+
+(RFC2406, obsoletes RFC1827)
+<DT><B>3des</B>
+
+<DD>
+encryption transform following the Triple-DES standard in
+Cipher-Block-Chaining mode using a 64-bit
+<I>iv</I>
+
+(internally generated) and a 192-bit 3DES
+<I>ekey</I>
+
+(RFC2451)
+<DT><B>3des-md5-96</B>
+
+<DD>
+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
+<I>iv</I>
+
+(internally generated), a 192-bit 3DES
+<I>ekey</I>
+
+and a 128-bit HMAC-MD5
+<I>akey</I>
+
+(RFC2451, RFC2403)
+<DT><B>3des-sha1-96</B>
+
+<DD>
+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
+<I>iv</I>
+
+(internally generated), a 192-bit 3DES
+<I>ekey</I>
+
+and a 160-bit HMAC-SHA1
+<I>akey</I>
+
+(RFC2451, RFC2404)
+<DT><B>--replay_window</B> replayw
+
+<DD>
+sets the replay window size; valid values are decimal, 1 to 64
+<DT><B>--life</B> life_param[,life_param]
+
+<DD>
+sets the lifetime expiry; the format of
+<B>life_param</B>
+
+consists of a comma-separated list of lifetime specifications without spaces;
+a lifetime specification is comprised of a severity of
+<B>soft</B> or <B>hard</B>
+
+followed by a '-', followed by a lifetime type of
+<B>allocations</B>, <B>bytes</B>, <B>addtime</B>, <B>usetime</B> or <B>packets</B>
+
+followed by an '=' and finally by a value
+<DT><B>--comp</B>
+
+<DD>
+add an SA for IPSEC IP Compression,
+specified by the following
+transform identifier (<B>deflate</B>)
+
+(RFC2393)
+<DT><B>deflate</B>
+
+<DD>
+compression transform following the patent-free Deflate compression algorithm
+(RFC2394)
+<DT><B>--ip4</B>
+
+<DD>
+add an SA for an IPv4-in-IPv4
+tunnel from
+<I>encap-src</I>
+
+to
+<I>encap-dst</I>
+
+<DT><B>--ip6</B>
+
+<DD>
+add an SA for an IPv6-in-IPv6
+tunnel from
+<I>encap-src</I>
+
+to
+<I>encap-dst</I>
+
+<DT><B>--src</B>
+
+<DD>
+specify the source end of an IP-in-IP tunnel from
+<I>encap-src</I>
+
+to
+<I>encap-dst</I>
+
+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</I>
+
+and
+<I>edst</I>
+
+<DT><B>--dst</B>
+
+<DD>
+specify the destination end of an IP-in-IP tunnel from
+<I>encap-src</I>
+
+to
+<I>encap-dst</I>
+
+<DT><B>--del</B>
+
+<DD>
+delete the specified SA
+<DT><B>--clear</B>
+
+<DD>
+clears the table of
+<B>SA</B>s
+
+<DT><B>--help</B>
+
+<DD>
+display synopsis
+<DT><B>--version</B>
+
+<DD>
+display version information
+</DL>
+<A NAME="lbAF">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+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
+``<I>...</I>''.
+
+Keys used when the programs are actually run must,
+of course, be the full length required for the particular algorithm.
+<P>
+
+<B>ipsec spi --af inet --edst gw2 --spi 0x125 --proto esp \</B>
+
+<BR>
+
+<B> --src gw1 \</B>
+
+<BR>
+
+<B> --esp 3des-md5-96 \</B>
+
+<BR>
+
+<B>&nbsp;&nbsp;&nbsp;--enckey&nbsp;0x6630</B><I>...</I><B>97ce&nbsp;\</B>
+
+<BR>
+
+<B> --authkey 0x9941</B><I>...</I><B>71df</B>
+
+<P>
+
+sets up an SA from
+<B>gw1</B>
+
+to
+<B>gw2</B>
+
+with an SPI of
+<B>0x125</B>
+
+and protocol
+<B>ESP</B>
+
+(50) using
+<B>3DES</B>
+
+encryption with integral
+<B>MD5-96</B>
+
+authentication transform, using an encryption key of
+<B>0x6630</B><I>...</I><B>97ce</B>
+
+and an authentication key of
+<B>0x9941</B><I>...</I><B>71df</B>
+
+(see note above about abbreviated keys).
+<P>
+
+<B>ipsec spi --af inet6 --edst 3049:9::9000:3100 --spi 0x150 --proto ah \</B>
+
+<BR>
+
+<B> --src 3049:9::9000:3101 \</B>
+
+<BR>
+
+<B> --ah hmac-md5-96 \</B>
+
+<BR>
+
+<B>&nbsp;&nbsp;&nbsp;--authkey&nbsp;0x1234</B><I>...</I><B>2eda&nbsp;\</B>
+
+<P>
+
+sets up an SA from
+<B>3049:9::9000:3101</B>
+
+to
+<B>3049:9::9000:3100</B>
+
+with an SPI of
+<B>0x150</B>
+
+and protocol
+<B>AH</B>
+
+(50) using
+<B>MD5-96</B>
+
+authentication transform, using an authentication key of
+<B>0x1234</B><I>...</I><B>2eda</B>
+
+(see note above about abbreviated keys).
+<P>
+
+<B>ipsec spi --said <A HREF="mailto:tun.987@192.168.100.100">tun.987@192.168.100.100</A> --del </B>
+
+<P>
+
+deletes an SA to
+<B>192.168.100.100</B>
+
+with an SPI of
+<B>0x987</B>
+
+and protocol
+<B>IPv4-in-IPv4</B>
+
+(4).
+<P>
+
+<B>ipsec spi --said tun:<A HREF="mailto:500@3049">500@3049</A>:9::1000:1 --del </B>
+
+<P>
+
+deletes an SA to
+<B>3049:9::1000:1</B>
+
+with an SPI of
+<B>0x500</B>
+
+and protocol
+<B>IPv6-in-IPv6</B>
+
+(4).
+<P>
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_spi, /usr/local/bin/ipsec
+<A NAME="lbAH">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_eroute.8.html">ipsec_eroute</A>(8),
+<A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A>(8), <A HREF="ipsec_klipsdebug.8.html">ipsec_klipsdebug</A>(8), <A HREF="ipsec_spi.5.html">ipsec_spi</A>(5)
+<A NAME="lbAI">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+<A NAME="lbAJ">&nbsp;</A>
+<H2>BUGS</H2>
+
+The syntax is messy and the transform naming needs work.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">OPTIONS</A><DD>
+<DT><A HREF="#lbAF">EXAMPLES</A><DD>
+<DT><A HREF="#lbAG">FILES</A><DD>
+<DT><A HREF="#lbAH">SEE ALSO</A><DD>
+<DT><A HREF="#lbAI">HISTORY</A><DD>
+<DT><A HREF="#lbAJ">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_spigrp.5.html b/doc/manpage.d/ipsec_spigrp.5.html
new file mode 100644
index 000000000..e0efcb73e
--- /dev/null
+++ b/doc/manpage.d/ipsec_spigrp.5.html
@@ -0,0 +1,193 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SPIGRP</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SPIGRP</H1>
+Section: File Formats (5)<BR>Updated: 27 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec_spigrp - list IPSEC Security Association groupings
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>spigrp</B>
+
+<P>
+
+<B>cat</B>
+
+<B>/proc/net/ipsec_spigrp</B>
+
+<P>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>/proc/net/ipsec_spigrp</I>
+
+is a read-only file that lists groups of IPSEC Security Associations
+(SAs).
+<P>
+
+An entry in the IPSEC extended routing table can only point (via an
+SAID) to one SA. If more than one transform must be applied to a given
+type of packet, this can be accomplished by setting up several SAs with
+the same destination address but potentially different SPIs and
+protocols, and grouping them with
+<I><A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A>(8)</I>.
+
+<P>
+
+The SA groups are listed, one line per connection/group, as a sequence
+of SAs to be applied (or that should have been applied, in the case of
+an incoming packet) from inside to outside the packet. An SA is
+identified by its SAID, which consists of protocol (&quot;ah&quot;, &quot;esp&quot;, &quot;comp&quot; or
+&quot;tun&quot;), SPI (with '.' for IPv4 or ':' for IPv6 prefixed hexadecimal number ) and destination address
+(IPv4 dotted quad or IPv6 coloned hex) prefixed by '@', in the format &lt;proto&gt;&lt;af&gt;&lt;spi&gt;@&lt;dest&gt;.
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<DL COMPACT>
+<DT><B><A HREF="mailto:tun.3d0@192.168.2.110">tun.3d0@192.168.2.110</A></B>
+
+<DD>
+<B><A HREF="mailto:comp.3d0@192.168.2.110">comp.3d0@192.168.2.110</A></B>
+
+<B><A HREF="mailto:esp.187a101b@192.168.2.110">esp.187a101b@192.168.2.110</A></B>
+
+<B><A HREF="mailto:ah.187a101a@192.168.2.110">ah.187a101a@192.168.2.110</A> </B>
+
+</DL>
+<P>
+
+is a group of 3 SAs, destined for
+<B>192.168.2.110</B>
+
+with an IPv4-in-IPv4 tunnel SA applied first with an SPI of
+<B>3d0</B>
+
+in hexadecimal, followed by a Deflate compression header to compress
+the packet with CPI of
+<B>3d0</B>
+
+in hexadecimal, followed by an Encapsulating Security Payload header to
+encrypt the packet with SPI
+<B>187a101b</B>
+
+in hexadecimal, followed by an Authentication Header to authenticate the
+packet with SPI
+<B>187a101a</B>
+
+in hexadecimal, applied from inside to outside the packet. This could
+be an incoming or outgoing group, depending on the address of the local
+machine.
+<P>
+
+<DL COMPACT>
+<DT><B>tun:<A HREF="mailto:3d0@3049">3d0@3049</A>:1::2</B>
+
+<DD>
+<B>comp:<A HREF="mailto:3d0@3049">3d0@3049</A>:1::2</B>
+
+<B>esp:<A HREF="mailto:187a101b@3049">187a101b@3049</A>:1::2</B>
+
+<B>ah:<A HREF="mailto:187a101a@3049">187a101a@3049</A>:1::2 </B>
+
+</DL>
+<P>
+
+is a group of 3 SAs, destined for
+<B>3049:1::2</B>
+
+with an IPv6-in-IPv6 tunnel SA applied first with an SPI of
+<B>3d0</B>
+
+in hexadecimal, followed by a Deflate compression header to compress
+the packet with CPI of
+<B>3d0</B>
+
+in hexadecimal, followed by an Encapsulating Security Payload header to
+encrypt the packet with SPI
+<B>187a101b</B>
+
+in hexadecimal, followed by an Authentication Header to authenticate the
+packet with SPI
+<B>187a101a</B>
+
+in hexadecimal, applied from inside to outside the packet. This could
+be an incoming or outgoing group, depending on the address of the local
+machine.
+<P>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_spigrp, /usr/local/bin/ipsec
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_tncfg.5.html">ipsec_tncfg</A>(5), <A HREF="ipsec_eroute.5.html">ipsec_eroute</A>(5),
+<A HREF="ipsec_spi.5.html">ipsec_spi</A>(5), <A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5), <A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A>(8), <A HREF="ipsec_version.5.html">ipsec_version</A>(5),
+<A HREF="ipsec_pf_key.5.html">ipsec_pf_key</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+<A NAME="lbAI">&nbsp;</A>
+<H2>BUGS</H2>
+
+:-)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+<DT><A HREF="#lbAI">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_spigrp.8.html b/doc/manpage.d/ipsec_spigrp.8.html
new file mode 100644
index 000000000..2e96c0574
--- /dev/null
+++ b/doc/manpage.d/ipsec_spigrp.8.html
@@ -0,0 +1,280 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SPIGRP</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SPIGRP</H1>
+Section: Maintenance Commands (8)<BR>Updated: 21 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec spigrp - group/ungroup IPSEC Security Associations
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>spigrp</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>spigrp</B>
+
+[
+<B>--label</B>
+
+label ]
+af1 dst1 spi1 proto1 [ af2 dst2 spi2 proto2 [ af3 dst3 spi3 proto3 [ af4 dst4 spi4 proto4 ] ] ]
+<P>
+
+<B>ipsec</B>
+
+<B>spigrp</B>
+
+[
+<B>--label</B>
+
+label ]
+<B>--said</B>
+
+SA1 [ SA2 [ SA3 [ SA4 ] ] ]
+<P>
+
+<B>ipsec</B>
+
+<B>spigrp</B>
+
+<B>--help</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>spigrp</B>
+
+<B>--version</B>
+
+<P>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Spigrp</I>
+
+groups IPSEC Security Associations (SAs) together or ungroups
+previously grouped SAs.
+An entry in the IPSEC extended
+routing table can only point
+(via a destination address, a Security Parameters Index (SPI) and
+a protocol identifier) to one SA.
+If more than one transform must be applied to a given type of packet,
+this can be accomplished by setting up several SAs
+with the same destination address but potentially different SPIs and protocols,
+and grouping them with
+<I>spigrp</I>.
+
+<P>
+
+The SAs to be grouped,
+specified by destination address (DNS name lookup, IPv4 dotted quad or IPv6 coloned hex), SPI
+('0x'-prefixed hexadecimal number) and protocol (&quot;ah&quot;, &quot;esp&quot;, &quot;comp&quot; or &quot;tun&quot;),
+are listed from the inside transform to the
+outside;
+in other words, the transforms are applied in
+the order of the command line and removed in the reverse
+order.
+The resulting SA group is referred to by its first SA (by
+<I>af1</I>,
+
+<I>dst1</I>,
+
+<I>spi1</I>
+
+and
+<I>proto1</I>).
+
+<P>
+
+The --said option indicates that the SA IDs are to be specified as
+one argument each, in the format &lt;proto&gt;&lt;af&gt;&lt;spi&gt;@&lt;dest&gt;. The SA IDs must
+all be specified as separate parameters without the --said option or
+all as monolithic parameters after the --said option.
+<P>
+
+The SAs must already exist and must not already
+be part of a group.
+<P>
+
+If
+<I>spigrp</I>
+
+is invoked with only one SA specification,
+it ungroups the previously-grouped set of SAs containing
+the SA specified.
+<P>
+
+The --label option identifies all responses from that command
+invocation with a user-supplied label, provided as an argument to the
+label option. This can be helpful for debugging one invocation of the
+command out of a large number.
+<P>
+
+The command form with no additional arguments lists the contents of
+/proc/net/ipsec_spigrp. The format of /proc/net/ipsec_spigrp is
+discussed in <A HREF="ipsec_spigrp.5.html">ipsec_spigrp</A>(5).
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<DL COMPACT>
+<DT><B>ipsec spigrp inet gw2 0x113 tun inet gw2 0x115 esp inet gw2 0x116 ah</B>
+
+<DD>
+groups 3 SAs together, all destined for
+<B>gw2</B>,
+
+but with an IPv4-in-IPv4 tunnel SA applied first with SPI
+<B>0x113</B>,
+
+then an ESP header to encrypt the packet with SPI
+<B>0x115</B>,
+
+and finally an AH header to authenticate the packet with SPI
+<B>0x116</B>.
+
+</DL>
+<P>
+
+<DL COMPACT>
+<DT><B>ipsec spigrp --said tun.113@gw2 esp.115@gw2 ah.116@gw2 </B>
+
+<DD>
+groups 3 SAs together, all destined for
+<B>gw2</B>,
+
+but with an IPv4-in-IPv4 tunnel SA applied first with SPI
+<B>0x113</B>,
+
+then an ESP header to encrypt the packet with SPI
+<B>0x115</B>,
+
+and finally an AH header to authenticate the packet with SPI
+<B>0x116</B>.
+
+</DL>
+<P>
+
+<DL COMPACT>
+<DT><B>ipsec spigrp --said tun:<A HREF="mailto:233@3049">233@3049</A>:1::1 esp:<A HREF="mailto:235@3049">235@3049</A>:1::1 ah:<A HREF="mailto:236@3049">236@3049</A>:1::1 </B>
+
+<DD>
+groups 3 SAs together, all destined for
+<B>3049:1::1,</B>
+
+but with an IPv6-in-IPv6 tunnel SA applied first with SPI
+<B>0x233</B>,
+
+then an ESP header to encrypt the packet with SPI
+<B>0x235</B>,
+
+and finally an AH header to authenticate the packet with SPI
+<B>0x236</B>.
+
+</DL>
+<P>
+
+<DL COMPACT>
+<DT><B>ipsec spigrp inet6 3049:1::1 0x233 tun inet6 3049:1::1 0x235 esp inet6 3049:1::1 0x236 ah</B>
+
+<DD>
+groups 3 SAs together, all destined for
+<B>3049:1::1,</B>
+
+but with an IPv6-in-IPv6 tunnel SA applied first with SPI
+<B>0x233</B>,
+
+then an ESP header to encrypt the packet with SPI
+<B>0x235</B>,
+
+and finally an AH header to authenticate the packet with SPI
+<B>0x236</B>.
+
+</DL>
+<P>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_spigrp, /usr/local/bin/ipsec
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_eroute.8.html">ipsec_eroute</A>(8),
+<A HREF="ipsec_spi.8.html">ipsec_spi</A>(8), <A HREF="ipsec_klipsdebug.8.html">ipsec_klipsdebug</A>(8), <A HREF="ipsec_spigrp.5.html">ipsec_spigrp</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+<A NAME="lbAI">&nbsp;</A>
+<H2>BUGS</H2>
+
+Yes, it really is limited to a maximum of four SAs,
+although admittedly it's hard to see why you would need more.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+<DT><A HREF="#lbAI">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_splitkeytoid.3.html b/doc/manpage.d/ipsec_splitkeytoid.3.html
new file mode 100644
index 000000000..109cfafa7
--- /dev/null
+++ b/doc/manpage.d/ipsec_splitkeytoid.3.html
@@ -0,0 +1,174 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_KEYBLOBTOID</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_KEYBLOBTOID</H1>
+Section: C Library Functions (3)<BR>Updated: 25 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec keyblobtoid, splitkeytoid - generate key IDs from RSA keys
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>size_t keyblobtoid(const unsigned char *blob,</B>
+
+<BR>
+&nbsp;
+<B>size_t bloblen, char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>size_t splitkeytoid(const unsigned char *e, size_t elen,</B>
+
+<BR>
+&nbsp;
+<B>const unsigned char *m, size_t mlen, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Keyblobtoid</I>
+
+and
+<I>splitkeytoid</I>
+
+generate
+key IDs
+from RSA keys,
+for use in messages and reporting,
+writing the result to
+<I>dst</I>.
+
+A
+<I>key ID</I>
+
+is a short ASCII string identifying a key;
+currently it is just the first nine characters of the base64
+encoding of the RFC 2537/3110 ``byte blob'' representation of the key.
+(Beware that no finite key ID can be collision-proof:
+there is always some small chance of two random keys having the
+same ID.)
+<P>
+
+<I>Keyblobtoid</I>
+
+generates a key ID from a key which is already in the form of an
+RFC 2537/3110 binary key
+<I>blob</I>
+
+(encoded exponent length, exponent, modulus).
+<P>
+
+<I>Splitkeytoid</I>
+
+generates a key ID from a key given in the form of a separate
+(binary) exponent
+<I>e</I>
+
+and modulus
+<I>m</I>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of either
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines a constant
+<B>KEYID_BUF</B>
+
+which is the size of a buffer large enough for worst-case results.
+<P>
+
+Both functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+
+With keys generated by
+<I><A HREF="ipsec_rsasigkey.3.html">ipsec_rsasigkey</A></I>(3),
+
+the first two base64 digits are always the same,
+and the third carries only about one bit of information.
+It's worse with keys using longer fixed exponents,
+e.g. the 24-bit exponent that's common in X.509 certificates.
+However, being able to relate key IDs to the full
+base64 text form of keys by eye is sufficiently useful that this
+waste of space seems justifiable.
+The choice of nine digits is a compromise between bulk and
+probability of collision.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+RFC 3110,
+<I>RSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)</I>,
+Eastlake, 2001
+(superseding the older but better-known RFC 2537).
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors are:
+key too short to supply enough bits to construct a complete key ID
+(almost certainly indicating a garbage key);
+exponent too long for its length to be representable.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_subnetinsubnet.3.html b/doc/manpage.d/ipsec_subnetinsubnet.3.html
new file mode 100644
index 000000000..414a0d513
--- /dev/null
+++ b/doc/manpage.d/ipsec_subnetinsubnet.3.html
@@ -0,0 +1,274 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Nov 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec sameaddr - are two addresses the same?
+<BR>
+
+ipsec addrcmp - ordered comparison of addresses
+<BR>
+
+ipsec samesubnet - are two subnets the same?
+<BR>
+
+ipsec addrinsubnet - is an address within a subnet?
+<BR>
+
+ipsec subnetinsubnet - is a subnet within another subnet?
+<BR>
+
+ipsec subnetishost - is a subnet a single host?
+<BR>
+
+ipsec samesaid - are two SA IDs the same?
+<BR>
+
+ipsec sameaddrtype - are two addresses of the same address family?
+<BR>
+
+ipsec samesubnettype - are two subnets of the same address family?
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int sameaddr(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int addrcmp(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int addrinsubnet(const ip_address *a, const ip_subnet *s);</B>
+
+<BR>
+
+<B>int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int subnetishost(const ip_subnet *s);</B>
+
+<BR>
+
+<B>int samesaid(const ip_said *a, const ip_said *b);</B>
+
+<BR>
+
+<B>int sameaddrtype(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnettype(const ip_subnet *a, const ip_subnet *b);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions do various comparisons and tests on the
+<I>ip_address</I>
+
+type and
+<I>ip_subnet</I>
+
+types.
+<P>
+
+<I>Sameaddr</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Addresses of different families are never identical.
+<P>
+
+<I>Addrcmp</I>
+
+returns
+<B>-1</B>,
+
+<B>0</B>,
+
+or
+<B>1</B>
+
+respectively
+if address
+<I>a</I>
+
+is less than, equal to, or greater than
+<I>b</I>.
+
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+<P>
+
+<I>Samesubnet</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Subnets of different address families are never identical.
+<P>
+
+<I>Addrinsubnet</I>
+
+returns
+non-zero
+if address
+<I>a</I>
+
+is within subnet
+<I>s</I>
+
+and
+<B>0</B>
+
+otherwise.
+An address is never within a
+subnet of a different address family.
+<P>
+
+<I>Subnetinsubnet</I>
+
+returns
+non-zero
+if subnet
+<I>a</I>
+
+is a subset of subnet
+<I>b</I>
+
+and
+<B>0</B>
+
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+<P>
+
+<I>Subnetishost</I>
+
+returns
+non-zero
+if subnet
+<I>s</I>
+
+is in fact only a single host,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesaid</I>
+
+returns
+non-zero
+if SA IDs
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Sameaddrtype</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesubnettype</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_subnetishost.3.html b/doc/manpage.d/ipsec_subnetishost.3.html
new file mode 100644
index 000000000..414a0d513
--- /dev/null
+++ b/doc/manpage.d/ipsec_subnetishost.3.html
@@ -0,0 +1,274 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Nov 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec sameaddr - are two addresses the same?
+<BR>
+
+ipsec addrcmp - ordered comparison of addresses
+<BR>
+
+ipsec samesubnet - are two subnets the same?
+<BR>
+
+ipsec addrinsubnet - is an address within a subnet?
+<BR>
+
+ipsec subnetinsubnet - is a subnet within another subnet?
+<BR>
+
+ipsec subnetishost - is a subnet a single host?
+<BR>
+
+ipsec samesaid - are two SA IDs the same?
+<BR>
+
+ipsec sameaddrtype - are two addresses of the same address family?
+<BR>
+
+ipsec samesubnettype - are two subnets of the same address family?
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>int sameaddr(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int addrcmp(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int addrinsubnet(const ip_address *a, const ip_subnet *s);</B>
+
+<BR>
+
+<B>int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);</B>
+
+<BR>
+
+<B>int subnetishost(const ip_subnet *s);</B>
+
+<BR>
+
+<B>int samesaid(const ip_said *a, const ip_said *b);</B>
+
+<BR>
+
+<B>int sameaddrtype(const ip_address *a, const ip_address *b);</B>
+
+<BR>
+
+<B>int samesubnettype(const ip_subnet *a, const ip_subnet *b);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions do various comparisons and tests on the
+<I>ip_address</I>
+
+type and
+<I>ip_subnet</I>
+
+types.
+<P>
+
+<I>Sameaddr</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Addresses of different families are never identical.
+<P>
+
+<I>Addrcmp</I>
+
+returns
+<B>-1</B>,
+
+<B>0</B>,
+
+or
+<B>1</B>
+
+respectively
+if address
+<I>a</I>
+
+is less than, equal to, or greater than
+<I>b</I>.
+
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+<P>
+
+<I>Samesubnet</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+Subnets of different address families are never identical.
+<P>
+
+<I>Addrinsubnet</I>
+
+returns
+non-zero
+if address
+<I>a</I>
+
+is within subnet
+<I>s</I>
+
+and
+<B>0</B>
+
+otherwise.
+An address is never within a
+subnet of a different address family.
+<P>
+
+<I>Subnetinsubnet</I>
+
+returns
+non-zero
+if subnet
+<I>a</I>
+
+is a subset of subnet
+<I>b</I>
+
+and
+<B>0</B>
+
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+<P>
+
+<I>Subnetishost</I>
+
+returns
+non-zero
+if subnet
+<I>s</I>
+
+is in fact only a single host,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesaid</I>
+
+returns
+non-zero
+if SA IDs
+<I>a</I>
+
+and
+<I>b</I>
+
+are identical,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Sameaddrtype</I>
+
+returns
+non-zero
+if addresses
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+<I>Samesubnettype</I>
+
+returns
+non-zero
+if subnets
+<I>a</I>
+
+and
+<I>b</I>
+
+are of the same address family,
+and
+<B>0</B>
+
+otherwise.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_initaddr.3.html">ipsec_initaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_subnetof.3.html b/doc/manpage.d/ipsec_subnetof.3.html
new file mode 100644
index 000000000..a185d716b
--- /dev/null
+++ b/doc/manpage.d/ipsec_subnetof.3.html
@@ -0,0 +1,107 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_SUBNETOF</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_SUBNETOF</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec subnetof - given Internet address and subnet mask, return subnet number
+<BR>
+
+ipsec hostof - given Internet address and subnet mask, return host part
+<BR>
+
+ipsec broadcastof - given Internet address and subnet mask, return broadcast address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>struct in_addr subnetof(struct in_addr addr,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr mask);</B>
+
+<BR>
+
+<B>struct in_addr hostof(struct in_addr addr,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr mask);</B>
+
+<BR>
+
+<B>struct in_addr broadcastof(struct in_addr addr,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr mask);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_networkof.3.html">ipsec_networkof</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Subnetof</I>
+
+takes an Internet
+<I>address</I>
+
+and a subnet
+<I>mask</I>
+
+and returns the network part of the address
+(all in network byte order).
+<I>Hostof</I>
+
+similarly returns the host part, and
+<I>broadcastof</I>
+
+returns the broadcast address (all-1s convention) for the network.
+<P>
+
+These functions are provided to hide the Internet bit-munging inside
+an API, in hopes of easing the eventual transition to IPv6.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+Calling functions for this is more costly than doing it yourself.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_subnettoa.3.html b/doc/manpage.d/ipsec_subnettoa.3.html
new file mode 100644
index 000000000..718fa935a
--- /dev/null
+++ b/doc/manpage.d/ipsec_subnettoa.3.html
@@ -0,0 +1,448 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atoaddr, addrtoa - convert Internet addresses to and from ASCII
+<BR>
+
+ipsec atosubnet, subnettoa - convert subnet/mask ASCII form to and from addresses
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr *addr);</B>
+
+<BR>
+
+<B>size_t addrtoa(struct in_addr addr, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>const char *atosubnet(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>struct in_addr *addr, struct in_addr *mask);</B>
+
+<BR>
+
+<B>size_t subnettoa(struct in_addr addr, struct in_addr mask,</B>
+
+<BR>
+&nbsp;
+<B>int format, char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Atoaddr</I>
+
+converts an ASCII name or dotted-decimal address into a binary address
+(in network byte order).
+<I>Addrtoa</I>
+
+does the reverse conversion, back to an ASCII dotted-decimal address.
+<I>Atosubnet</I>
+
+and
+<I>subnettoa</I>
+
+do likewise for the ``address/mask'' ASCII form used to write a
+specification of a subnet.
+<P>
+
+An address is specified in ASCII as a
+dotted-decimal address (e.g.
+<B>1.2.3.4</B>),
+
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+<B>0x01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>),
+
+an eight-digit host-order hexadecimal number with a
+<B>0h</B>
+
+prefix (e.g.
+<B>0h01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>
+
+on a big-endian host and
+<B>4.3.2.1</B>
+
+on a little-endian host),
+a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3),
+
+or an old-style network name to be looked up via
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3).
+
+<P>
+
+A dotted-decimal address may be incomplete, in which case
+ASCII-to-binary conversion implicitly appends
+as many instances of
+<B>.0</B>
+
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+<B>10</B>
+
+is synonymous with
+<B>10.0.0.0</B>,
+
+and
+<B>128.009.000.032</B>
+
+is synonymous with
+<B>128.9.0.32</B>
+
+(the latter example is verbatim from RFC 1166).
+The result of
+<I>addrtoa</I>
+
+is always complete and does not contain leading zeros.
+<P>
+
+The letters in
+a hexadecimal address may be uppercase or lowercase or any mixture thereof.
+Use of hexadecimal addresses is
+<B>strongly</B>
+
+<B>discouraged</B>;
+
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+<P>
+
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+<I><A HREF="resolver.5.html">resolver</A></I>(5)).
+
+The
+<I>h_addr</I>
+
+value returned by
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3)
+
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+Name lookup resorts to
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3)
+
+only if
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3)
+
+fails.
+<P>
+
+A subnet specification is of the form <I>network</I><B>/</B><I>mask</I>.
+The
+<I>network</I>
+
+and
+<I>mask</I>
+
+can be any form acceptable to
+<I>atoaddr</I>.
+
+In addition, the
+<I>mask</I>
+
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+<B>24</B>
+
+means
+<B>255.255.255.0</B>).
+
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+<B>%default</B>
+
+is a synonym for
+<B>0.0.0.0/0</B>.
+
+<P>
+
+<I>Atosubnet</I>
+
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+<B>10.1.2.3/24</B>
+
+is synonymous with
+<B>10.1.2.0/24</B>).
+
+<I>Subnettoa</I>
+
+generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros,
+unless the mask is non-contiguous.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atoaddr</I>
+
+and
+<I>atosubnet</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines constants,
+<B>ADDRTOA_BUF</B>
+
+and
+<B>SUBNETTOA_BUF</B>,
+
+which are the sizes of buffers just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+<P>
+
+The ASCII-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-ASCII functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atoaddr</I>
+
+are:
+empty input;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal form;
+dotted-decimal component too large to fit in 8 bits.
+<P>
+
+Fatal errors in
+<I>atosubnet</I>
+
+are:
+no
+<B>/</B>
+
+in
+<I>src</I>;
+
+<I>atoaddr</I>
+
+error in conversion of
+<I>network</I>
+
+or
+<I>mask</I>;
+
+bit-count mask too big;
+mask non-contiguous.
+<P>
+
+Fatal errors in
+<I>addrtoa</I>
+
+and
+<I>subnettoa</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+<B>10/24</B>
+
+means
+<B>10.0.0.0/24</B>)
+
+differs from that of some older conversion
+functions, e.g. those of
+<I><A HREF="inet.3.html">inet</A></I>(3).
+
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+<P>
+
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+<P>
+
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+<P>
+
+<I><A HREF="Getnetbyname.3.html">Getnetbyname</A></I>(3)
+
+is a historical dreg.
+<P>
+
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_subnettot.3.html b/doc/manpage.d/ipsec_subnettot.3.html
new file mode 100644
index 000000000..199937a35
--- /dev/null
+++ b/doc/manpage.d/ipsec_subnettot.3.html
@@ -0,0 +1,569 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Sept 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttoaddr, tnatoaddr, addrtot - convert Internet addresses to and from text
+<BR>
+
+ipsec ttosubnet, subnettot - convert subnet/mask text form to and from addresses
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ttoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>const char *tnatoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>size_t addrtot(const ip_address *addr, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>const char *ttosubnet(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_subnet *dst);</B>
+
+<BR>
+
+<B>size_t subnettot(const ip_subnet *sub, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttoaddr</I>
+
+converts a text-string name or numeric address into a binary address
+(in network byte order).
+<I>Tnatoaddr</I>
+
+does the same conversion,
+but the only text forms it accepts are
+the ``official'' forms of
+numeric address (dotted-decimal for IPv4, colon-hex for IPv6).
+<I>Addrtot</I>
+
+does the reverse conversion, from binary address back to a text form.
+<I>Ttosubnet</I>
+
+and
+<I>subnettot</I>
+
+do likewise for the ``address/mask'' form used to write a
+specification of a subnet.
+<P>
+
+An IPv4 address is specified in text as a
+dotted-decimal address (e.g.
+<B>1.2.3.4</B>),
+
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+<B>0x01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>),
+
+an eight-digit host-order hexadecimal number with a
+<B>0h</B>
+
+prefix (e.g.
+<B>0h01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>
+
+on a big-endian host and
+<B>4.3.2.1</B>
+
+on a little-endian host),
+a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3),
+
+or an old-style network name to be looked up via
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3).
+
+<P>
+
+A dotted-decimal address may be incomplete, in which case
+text-to-binary conversion implicitly appends
+as many instances of
+<B>.0</B>
+
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+<B>10</B>
+
+is synonymous with
+<B>10.0.0.0</B>,
+
+and
+<B>128.009.000.032</B>
+
+is synonymous with
+<B>128.9.0.32</B>
+
+(the latter example is verbatim from RFC 1166).
+The result of applying
+<I>addrtot</I>
+
+to an IPv4 address is always complete and does not contain leading zeros.
+<P>
+
+Use of hexadecimal addresses is
+<B>strongly</B>
+
+<B>discouraged</B>;
+
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+<P>
+
+An IPv6 address is specified in text with
+colon-hex notation (e.g.
+<B>0:56:78ab:22:33:44:55:66</B>),
+
+colon-hex with
+<B>::</B>
+
+abbreviating at most one subsequence of multiple zeros (e.g.
+<B>99:ab::54:068</B>,
+
+which is synonymous with
+<B>99:ab:0:0:0:0:54:68</B>),
+
+or a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3).
+
+The result of applying
+<I>addrtot</I>
+
+to an IPv6 address will use
+<B>::</B>
+
+abbreviation if possible,
+and will not contain leading zeros.
+<P>
+
+The letters in hexadecimal
+may be uppercase or lowercase or any mixture thereof.
+<P>
+
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+<I><A HREF="resolver.5.html">resolver</A></I>(5)).
+
+The
+<I>h_addr</I>
+
+value returned by
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+IPv4 name lookup resorts to
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3)
+
+only if
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+fails.
+<P>
+
+A subnet specification is of the form <I>network</I><B>/</B><I>mask</I>.
+The
+<I>network</I>
+
+and
+<I>mask</I>
+
+can be any form acceptable to
+<I>ttoaddr</I>.
+
+In addition, and preferably, the
+<I>mask</I>
+
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+<B>24</B>
+
+in IPv4 means
+<B>255.255.255.0</B>).
+
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+<B>%default</B>
+
+is a synonym for
+<B>0.0.0.0/0</B>
+
+or
+<B>::/0</B>
+
+in IPv4 or IPv6 respectively.
+<P>
+
+<I>Ttosubnet</I>
+
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+<B>10.1.2.3/24</B>
+
+is synonymous with
+<B>10.1.2.0/24</B>).
+
+<I>Subnettot</I>
+
+always generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the length of the text string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>af</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the address family of interest.
+It should be either
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines constants,
+<B>ADDRTOT_BUF</B>
+
+and
+<B>SUBNETTOT_BUF</B>,
+
+which are the sizes of buffers just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available in
+<I>subnettot</I>.
+
+<I>Addrtot</I>
+
+also accepts format values
+<B>'r'</B>
+
+(signifying a text form suitable for DNS reverse lookups,
+e.g.
+<B>4.3.2.1.IN-ADDR.ARPA.</B>
+
+for IPv4 and
+RFC 2874 format for IPv6),
+and
+<B>'R'</B>
+
+(signifying an alternate reverse-lookup form,
+an error for IPv4 and RFC 1886 format for IPv6).
+Reverse-lookup names always end with a ``.''.
+<P>
+
+The text-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-text functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttoaddr</I>
+
+are:
+empty input;
+unknown address family;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal or colon-hex form;
+dotted-decimal or colon-hex component too large.
+<P>
+
+Fatal errors in
+<I>ttosubnet</I>
+
+are:
+no
+<B>/</B>
+
+in
+<I>src</I>;
+
+<I>ttoaddr</I>
+
+error in conversion of
+<I>network</I>
+
+or
+<I>mask</I>;
+
+bit-count mask too big;
+mask non-contiguous.
+<P>
+
+Fatal errors in
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+<B>10/24</B>
+
+means
+<B>10.0.0.0/24</B>)
+
+differs from that of some older conversion
+functions, e.g. those of
+<I><A HREF="inet.3.html">inet</A></I>(3).
+
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+<P>
+
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+<P>
+
+<I>Ttoaddr</I>
+
+does not support the mixed colon-hex-dotted-decimal
+convention used to embed an IPv4 address in an IPv6 address.
+<P>
+
+<I>Addrtot</I>
+
+always uses the
+<B>::</B>
+
+abbreviation (which can appear only once in an address) for the
+<I>first</I>
+
+sequence of multiple zeros in an IPv6 address.
+One can construct addresses (unlikely ones) in which this is suboptimal.
+<P>
+
+<I>Addrtot</I>
+
+<B>'r'</B>
+
+conversion of an IPv6 address uses lowercase hexadecimal,
+not the uppercase used in RFC 2874's examples.
+It takes careful reading of RFCs 2874, 2673, and 2234 to realize
+that lowercase is technically legitimate here,
+and there may be software which botches this
+and hence would have trouble with lowercase hex.
+<P>
+
+Possibly
+<I>subnettot</I>
+
+ought to recognize the
+<B>%default</B>
+
+case and generate that string as its output.
+Currently it doesn't.
+<P>
+
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+<P>
+
+<I><A HREF="Getnetbyname.3.html">Getnetbyname</A></I>(3)
+
+is a historical dreg.
+<P>
+
+<I>Tnatoaddr</I>
+
+probably should enforce completeness of dotted-decimal addresses.
+<P>
+
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_subnettypeof.3.html b/doc/manpage.d/ipsec_subnettypeof.3.html
new file mode 100644
index 000000000..ea0f83f82
--- /dev/null
+++ b/doc/manpage.d/ipsec_subnettypeof.3.html
@@ -0,0 +1,238 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_INITSUBNET</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_INITSUBNET</H1>
+Section: C Library Functions (3)<BR>Updated: 12 March 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec initsubnet - initialize an ip_subnet
+<BR>
+
+ipsec addrtosubnet - initialize a singleton ip_subnet
+<BR>
+
+ipsec subnettypeof - get address type of an ip_subnet
+<BR>
+
+ipsec masktocount - convert subnet mask to bit count
+<BR>
+
+ipsec networkof - get base address of an ip_subnet
+<BR>
+
+ipsec maskof - get subnet mask of an ip_subnet
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *initsubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>int maskbits, int clash, ip_subnet *dst);</B>
+
+<BR>
+
+<B>const char *addrtosubnet(const ip_address *addr,</B>
+
+<BR>
+&nbsp;
+<B>ip_subnet *dst);</B>
+
+<P>
+<B>int subnettypeof(const ip_subnet *src);</B>
+
+<BR>
+
+<B>int masktocount(const ip_address *src);</B>
+
+<BR>
+
+<B>void networkof(const ip_subnet *src, ip_address *dst);</B>
+
+<BR>
+
+<B>void maskof(const ip_subnet *src, ip_address *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+library uses an internal type
+<I>ip_subnet</I>
+
+to contain a description of an IP subnet
+(base address plus mask).
+These functions provide basic tools for creating and examining this type.
+<P>
+
+<I>Initsubnet</I>
+
+initializes a variable
+<I>*dst</I>
+
+of type
+<I>ip_subnet</I>
+
+from a base address and
+a count of mask bits.
+The
+<I>clash</I>
+
+parameter specifies what to do if the base address includes
+<B>1</B>
+
+bits outside the prefix specified by the mask
+(that is, in the ``host number'' part of the address):
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT>'0'<DD>
+zero out host-number bits
+<DT>'x'<DD>
+non-zero host-number bits are an error
+</DL>
+</DL>
+
+<P>
+
+<I>Initsubnet</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<P>
+
+<I>Addrtosubnet</I>
+
+initializes an
+<I>ip_subnet</I>
+
+variable
+<I>*dst</I>
+
+to a ``singleton subnet'' containing the single address
+<I>*addr</I>.
+
+It returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure.
+<P>
+
+<I>Subnettypeof</I>
+
+returns the address type of a subnet,
+normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+(The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file arranges to include the necessary headers for these
+names to be known.)
+<P>
+
+<I>Masktocount</I>
+
+converts a subnet mask, expressed as an address, to a bit count
+suitable for use with
+<I>initsubnet</I>.
+
+It returns
+<B>-1</B>
+
+for error; see DIAGNOSTICS.
+<P>
+
+<I>Networkof</I>
+
+fills in
+<I>*dst</I>
+
+with the base address of subnet
+<I>src</I>.
+
+<P>
+
+<I>Maskof</I>
+
+fills in
+<I>*dst</I>
+
+with the subnet mask of subnet
+<I>src</I>,
+
+expressed as an address.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_ttosubnet.3.html">ipsec_ttosubnet</A>(3), <A HREF="ipsec_rangetosubnet.3.html">ipsec_rangetosubnet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>initsubnet</I>
+
+are:
+unknown address family;
+unknown
+<I>clash</I>
+
+value;
+impossible mask bit count;
+non-zero host-number bits and
+<I>clash</I>
+
+is
+<B>'x'</B>.
+
+Fatal errors in
+<I>addrtosubnet</I>
+
+are:
+unknown address family.
+Fatal errors in
+<I>masktocount</I>
+
+are:
+unknown address family;
+mask bits not contiguous.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_tnatoaddr.3.html b/doc/manpage.d/ipsec_tnatoaddr.3.html
new file mode 100644
index 000000000..199937a35
--- /dev/null
+++ b/doc/manpage.d/ipsec_tnatoaddr.3.html
@@ -0,0 +1,569 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Sept 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttoaddr, tnatoaddr, addrtot - convert Internet addresses to and from text
+<BR>
+
+ipsec ttosubnet, subnettot - convert subnet/mask text form to and from addresses
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ttoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>const char *tnatoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>size_t addrtot(const ip_address *addr, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>const char *ttosubnet(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_subnet *dst);</B>
+
+<BR>
+
+<B>size_t subnettot(const ip_subnet *sub, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttoaddr</I>
+
+converts a text-string name or numeric address into a binary address
+(in network byte order).
+<I>Tnatoaddr</I>
+
+does the same conversion,
+but the only text forms it accepts are
+the ``official'' forms of
+numeric address (dotted-decimal for IPv4, colon-hex for IPv6).
+<I>Addrtot</I>
+
+does the reverse conversion, from binary address back to a text form.
+<I>Ttosubnet</I>
+
+and
+<I>subnettot</I>
+
+do likewise for the ``address/mask'' form used to write a
+specification of a subnet.
+<P>
+
+An IPv4 address is specified in text as a
+dotted-decimal address (e.g.
+<B>1.2.3.4</B>),
+
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+<B>0x01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>),
+
+an eight-digit host-order hexadecimal number with a
+<B>0h</B>
+
+prefix (e.g.
+<B>0h01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>
+
+on a big-endian host and
+<B>4.3.2.1</B>
+
+on a little-endian host),
+a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3),
+
+or an old-style network name to be looked up via
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3).
+
+<P>
+
+A dotted-decimal address may be incomplete, in which case
+text-to-binary conversion implicitly appends
+as many instances of
+<B>.0</B>
+
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+<B>10</B>
+
+is synonymous with
+<B>10.0.0.0</B>,
+
+and
+<B>128.009.000.032</B>
+
+is synonymous with
+<B>128.9.0.32</B>
+
+(the latter example is verbatim from RFC 1166).
+The result of applying
+<I>addrtot</I>
+
+to an IPv4 address is always complete and does not contain leading zeros.
+<P>
+
+Use of hexadecimal addresses is
+<B>strongly</B>
+
+<B>discouraged</B>;
+
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+<P>
+
+An IPv6 address is specified in text with
+colon-hex notation (e.g.
+<B>0:56:78ab:22:33:44:55:66</B>),
+
+colon-hex with
+<B>::</B>
+
+abbreviating at most one subsequence of multiple zeros (e.g.
+<B>99:ab::54:068</B>,
+
+which is synonymous with
+<B>99:ab:0:0:0:0:54:68</B>),
+
+or a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3).
+
+The result of applying
+<I>addrtot</I>
+
+to an IPv6 address will use
+<B>::</B>
+
+abbreviation if possible,
+and will not contain leading zeros.
+<P>
+
+The letters in hexadecimal
+may be uppercase or lowercase or any mixture thereof.
+<P>
+
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+<I><A HREF="resolver.5.html">resolver</A></I>(5)).
+
+The
+<I>h_addr</I>
+
+value returned by
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+IPv4 name lookup resorts to
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3)
+
+only if
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+fails.
+<P>
+
+A subnet specification is of the form <I>network</I><B>/</B><I>mask</I>.
+The
+<I>network</I>
+
+and
+<I>mask</I>
+
+can be any form acceptable to
+<I>ttoaddr</I>.
+
+In addition, and preferably, the
+<I>mask</I>
+
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+<B>24</B>
+
+in IPv4 means
+<B>255.255.255.0</B>).
+
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+<B>%default</B>
+
+is a synonym for
+<B>0.0.0.0/0</B>
+
+or
+<B>::/0</B>
+
+in IPv4 or IPv6 respectively.
+<P>
+
+<I>Ttosubnet</I>
+
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+<B>10.1.2.3/24</B>
+
+is synonymous with
+<B>10.1.2.0/24</B>).
+
+<I>Subnettot</I>
+
+always generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the length of the text string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>af</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the address family of interest.
+It should be either
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines constants,
+<B>ADDRTOT_BUF</B>
+
+and
+<B>SUBNETTOT_BUF</B>,
+
+which are the sizes of buffers just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available in
+<I>subnettot</I>.
+
+<I>Addrtot</I>
+
+also accepts format values
+<B>'r'</B>
+
+(signifying a text form suitable for DNS reverse lookups,
+e.g.
+<B>4.3.2.1.IN-ADDR.ARPA.</B>
+
+for IPv4 and
+RFC 2874 format for IPv6),
+and
+<B>'R'</B>
+
+(signifying an alternate reverse-lookup form,
+an error for IPv4 and RFC 1886 format for IPv6).
+Reverse-lookup names always end with a ``.''.
+<P>
+
+The text-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-text functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttoaddr</I>
+
+are:
+empty input;
+unknown address family;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal or colon-hex form;
+dotted-decimal or colon-hex component too large.
+<P>
+
+Fatal errors in
+<I>ttosubnet</I>
+
+are:
+no
+<B>/</B>
+
+in
+<I>src</I>;
+
+<I>ttoaddr</I>
+
+error in conversion of
+<I>network</I>
+
+or
+<I>mask</I>;
+
+bit-count mask too big;
+mask non-contiguous.
+<P>
+
+Fatal errors in
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+<B>10/24</B>
+
+means
+<B>10.0.0.0/24</B>)
+
+differs from that of some older conversion
+functions, e.g. those of
+<I><A HREF="inet.3.html">inet</A></I>(3).
+
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+<P>
+
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+<P>
+
+<I>Ttoaddr</I>
+
+does not support the mixed colon-hex-dotted-decimal
+convention used to embed an IPv4 address in an IPv6 address.
+<P>
+
+<I>Addrtot</I>
+
+always uses the
+<B>::</B>
+
+abbreviation (which can appear only once in an address) for the
+<I>first</I>
+
+sequence of multiple zeros in an IPv6 address.
+One can construct addresses (unlikely ones) in which this is suboptimal.
+<P>
+
+<I>Addrtot</I>
+
+<B>'r'</B>
+
+conversion of an IPv6 address uses lowercase hexadecimal,
+not the uppercase used in RFC 2874's examples.
+It takes careful reading of RFCs 2874, 2673, and 2234 to realize
+that lowercase is technically legitimate here,
+and there may be software which botches this
+and hence would have trouble with lowercase hex.
+<P>
+
+Possibly
+<I>subnettot</I>
+
+ought to recognize the
+<B>%default</B>
+
+case and generate that string as its output.
+Currently it doesn't.
+<P>
+
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+<P>
+
+<I><A HREF="Getnetbyname.3.html">Getnetbyname</A></I>(3)
+
+is a historical dreg.
+<P>
+
+<I>Tnatoaddr</I>
+
+probably should enforce completeness of dotted-decimal addresses.
+<P>
+
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_tncfg.5.html b/doc/manpage.d/ipsec_tncfg.5.html
new file mode 100644
index 000000000..e4082a28f
--- /dev/null
+++ b/doc/manpage.d/ipsec_tncfg.5.html
@@ -0,0 +1,175 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TNCFG</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TNCFG</H1>
+Section: File Formats (5)<BR>Updated: 27 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec_tncfg - lists IPSEC virtual interfaces attached to real interfaces
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>tncfg</B>
+
+<P>
+
+<B>cat</B>
+
+<B>/proc/net/ipsec_tncfg</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>/proc/net/ipsec_tncfg</I>
+
+is a read-only file which lists which IPSEC virtual interfaces are
+attached to which real interfaces, through which packets will be
+forwarded once processed by IPSEC.
+<P>
+
+Each line lists one ipsec I/F.
+A table entry consists of:
+<DL COMPACT>
+<DT>+<DD>
+an ipsec virtual I/F name
+<DT>+<DD>
+a visual and machine parsable separator '-&gt;', separating the virtual I/F
+and the physical I/F,
+<DT>+<DD>
+a physical I/F name, to which the ipsec virtual I/F is attached or NULL
+if it is not attached,
+<DT>+<DD>
+the keyword
+<B>mtu=</B>,
+
+<DT>+<DD>
+the MTU of the ipsec virtual I/F,
+<DT>+<DD>
+the automatically adjusted effective MTU for PMTU discovery, in brackets,
+<DT>+<DD>
+a visual and machine parsable separator '-&gt;', separating the virtual I/F
+MTU and the physical I/F MTU,
+<DT>+<DD>
+the MTU of the attached physical I/F.
+<B>.SH</B>EXAMPLES
+
+<DT><B>ipsec2 -&gt; eth3 mtu=16260(1443) -&gt; 1500</B>
+
+<DD>
+</DL>
+<P>
+
+shows that virtual device
+<B>ipsec2</B>
+
+with an MTU of
+<B>16260</B>
+
+is connected to physical device
+<B>eth3</B>
+
+with an MTU of
+<B>1500</B>
+
+and that the effective MTU as a result of PMTU discovery has been
+automatically set to
+<B>1443.</B>
+
+<DL COMPACT>
+<DT><B>ipsec0 -&gt; wvlan0 mtu=1400(16260) -&gt; 1500</B>
+
+<DD>
+</DL>
+<P>
+
+shows that virtual device
+<B>ipsec0</B>
+
+with an MTU of
+<B>1400</B>
+
+is connected to physical device
+<B>wvlan0</B>
+
+with an MTU of
+<B>1500</B>
+
+and no PMTU packets have gotten far enough to bump down the effective MTU
+from its default of 16260.
+<DL COMPACT>
+<DT><B>ipsec3 -&gt; NULL mtu=0(0) -&gt; 0</B>
+
+<DD>
+</DL>
+<P>
+
+shows that virtual device
+<B>ipsec3</B>
+
+is not connected to any physical device.
+<P>
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_tncfg, /usr/local/bin/ipsec
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_eroute.5.html">ipsec_eroute</A>(5), <A HREF="ipsec_spi.5.html">ipsec_spi</A>(5),
+<A HREF="ipsec_spigrp.5.html">ipsec_spigrp</A>(5), <A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_version.5.html">ipsec_version</A>(5),
+<A HREF="ipsec_pf_key.5.html">ipsec_pf_key</A>(5)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_tncfg.8.html b/doc/manpage.d/ipsec_tncfg.8.html
new file mode 100644
index 000000000..e5965267c
--- /dev/null
+++ b/doc/manpage.d/ipsec_tncfg.8.html
@@ -0,0 +1,195 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TNCFG</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TNCFG</H1>
+Section: Maintenance Commands (8)<BR>Updated: 21 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec tncfg - associate IPSEC virtual interface with physical interface
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>tncfg</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>tncfg</B>
+
+<B>--attach</B>
+
+<B>--virtual</B>
+
+virtual
+<B>--physical</B>
+
+physical
+<P>
+
+<B>ipsec</B>
+
+<B>tncfg</B>
+
+<B>--detach</B>
+
+<B>--virtual</B>
+
+virtual
+<P>
+
+<B>ipsec</B>
+
+<B>tncfg</B>
+
+<B>--clear</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>tncfg</B>
+
+<B>--version</B>
+
+<P>
+
+<B>ipsec</B>
+
+<B>tncfg</B>
+
+<B>--help</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Tncfg</I>
+
+attaches/detaches IPSEC virtual interfaces to/from
+physical interfaces,
+through which packets will be forwarded once processed by IPSEC.
+<P>
+
+The form with no additional arguments lists the contents of
+/proc/net/ipsec_tncfg. The format of /proc/net/ipsec_tncfg is discussed
+in <A HREF="ipsec_tncfg.5.html">ipsec_tncfg</A>(5).
+The
+<B>--attach</B>
+
+form attaches the
+<I>virtual</I>
+
+interface to the
+<I>physical</I>
+
+one.
+The
+<B>--detach</B>
+
+form detaches the
+<I>virtual</I>
+
+interface from whichever physical interface it is attached to.
+The
+<B>--clear</B>
+
+form clears all the
+<I>virtual</I>
+
+interfaces from whichever physical interfaces they were attached to.
+<P>
+
+Virtual interfaces typically have names like
+<B>ipsec0</B>,
+
+while physical interfaces typically have names like
+<B>eth0</B>
+
+or
+<B>ppp0</B>.
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<DL COMPACT>
+<DT><B>ipsec tncfg --attach --virtual ipsec0 --physical eth0</B>
+
+<DD>
+attaches the
+<B>ipsec0</B>
+
+virtual device to the
+<B>eth0</B>
+
+physical device.
+</DL>
+<P>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_tncfg, /usr/local/bin/ipsec
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_eroute.8.html">ipsec_eroute</A>(8), <A HREF="ipsec_spi.8.html">ipsec_spi</A>(8),
+<A HREF="ipsec_spigrp.8.html">ipsec_spigrp</A>(8), <A HREF="ipsec_klipsdebug.8.html">ipsec_klipsdebug</A>(8), <A HREF="ipsec_tncfg.5.html">ipsec_tncfg</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_trap_count.5.html b/doc/manpage.d/ipsec_trap_count.5.html
new file mode 100644
index 000000000..8da655f77
--- /dev/null
+++ b/doc/manpage.d/ipsec_trap_count.5.html
@@ -0,0 +1,74 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TRAP_COUNT</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TRAP_COUNT</H1>
+Section: File Formats (5)<BR>Updated: 19 Jun 2003<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+trap_count - KLIPS statistic on number of ACQUIREs
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>cat</B>
+
+<B>/proc/net/ipsec/stats/trap_count</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>/proc/net/ipsec/stats/trap_count</I>
+
+is a read-only file. It contains a hexadecimal number which records the
+number of attempts to send PF_ACQUIRE messages. Only those recorded by
+trap_sendcount were actually successfully passed to userland. Note that the
+userland may still have lost them on its own.
+<P>
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec/stats/trap_sendcount
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_pf_key.5.html">ipsec_pf_key</A>(5), <A HREF="trap_sendcount.5.html">trap_sendcount</A>(5), <A HREF="pluto.8.html">pluto</A>(8)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael C. Richardson &lt;<A HREF="mailto:mcr@freeswan.org">mcr@freeswan.org</A>&gt;
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_trap_sendcount.5.html b/doc/manpage.d/ipsec_trap_sendcount.5.html
new file mode 100644
index 000000000..94f56b3a7
--- /dev/null
+++ b/doc/manpage.d/ipsec_trap_sendcount.5.html
@@ -0,0 +1,72 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TRAP_SENDCOUNT</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TRAP_SENDCOUNT</H1>
+Section: File Formats (5)<BR>Updated: 19 Jun 2003<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+trap_sendcount - KLIPS statistic on number of successful ACQUIREs
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>cat</B>
+
+<B>/proc/net/ipsec/stats/trap_sendcount</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>/proc/net/ipsec/stats/trap_sendcount</I>
+
+is a read-only file. It contains a hexadecimal number which records the
+number of successful PF_ACQUIRE messages that were sent.
+<P>
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec/stats/trap_sendcount
+<A NAME="lbAF">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_pf_key.5.html">ipsec_pf_key</A>(5), <A HREF="trap_count.5.html">trap_count</A>(5), <A HREF="pluto.8.html">pluto</A>(8)
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Michael C. Richardson &lt;<A HREF="mailto:mcr@freeswan.org">mcr@freeswan.org</A>&gt;
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">SEE ALSO</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_ttoaddr.3.html b/doc/manpage.d/ipsec_ttoaddr.3.html
new file mode 100644
index 000000000..199937a35
--- /dev/null
+++ b/doc/manpage.d/ipsec_ttoaddr.3.html
@@ -0,0 +1,569 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Sept 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttoaddr, tnatoaddr, addrtot - convert Internet addresses to and from text
+<BR>
+
+ipsec ttosubnet, subnettot - convert subnet/mask text form to and from addresses
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ttoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>const char *tnatoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>size_t addrtot(const ip_address *addr, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>const char *ttosubnet(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_subnet *dst);</B>
+
+<BR>
+
+<B>size_t subnettot(const ip_subnet *sub, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttoaddr</I>
+
+converts a text-string name or numeric address into a binary address
+(in network byte order).
+<I>Tnatoaddr</I>
+
+does the same conversion,
+but the only text forms it accepts are
+the ``official'' forms of
+numeric address (dotted-decimal for IPv4, colon-hex for IPv6).
+<I>Addrtot</I>
+
+does the reverse conversion, from binary address back to a text form.
+<I>Ttosubnet</I>
+
+and
+<I>subnettot</I>
+
+do likewise for the ``address/mask'' form used to write a
+specification of a subnet.
+<P>
+
+An IPv4 address is specified in text as a
+dotted-decimal address (e.g.
+<B>1.2.3.4</B>),
+
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+<B>0x01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>),
+
+an eight-digit host-order hexadecimal number with a
+<B>0h</B>
+
+prefix (e.g.
+<B>0h01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>
+
+on a big-endian host and
+<B>4.3.2.1</B>
+
+on a little-endian host),
+a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3),
+
+or an old-style network name to be looked up via
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3).
+
+<P>
+
+A dotted-decimal address may be incomplete, in which case
+text-to-binary conversion implicitly appends
+as many instances of
+<B>.0</B>
+
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+<B>10</B>
+
+is synonymous with
+<B>10.0.0.0</B>,
+
+and
+<B>128.009.000.032</B>
+
+is synonymous with
+<B>128.9.0.32</B>
+
+(the latter example is verbatim from RFC 1166).
+The result of applying
+<I>addrtot</I>
+
+to an IPv4 address is always complete and does not contain leading zeros.
+<P>
+
+Use of hexadecimal addresses is
+<B>strongly</B>
+
+<B>discouraged</B>;
+
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+<P>
+
+An IPv6 address is specified in text with
+colon-hex notation (e.g.
+<B>0:56:78ab:22:33:44:55:66</B>),
+
+colon-hex with
+<B>::</B>
+
+abbreviating at most one subsequence of multiple zeros (e.g.
+<B>99:ab::54:068</B>,
+
+which is synonymous with
+<B>99:ab:0:0:0:0:54:68</B>),
+
+or a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3).
+
+The result of applying
+<I>addrtot</I>
+
+to an IPv6 address will use
+<B>::</B>
+
+abbreviation if possible,
+and will not contain leading zeros.
+<P>
+
+The letters in hexadecimal
+may be uppercase or lowercase or any mixture thereof.
+<P>
+
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+<I><A HREF="resolver.5.html">resolver</A></I>(5)).
+
+The
+<I>h_addr</I>
+
+value returned by
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+IPv4 name lookup resorts to
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3)
+
+only if
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+fails.
+<P>
+
+A subnet specification is of the form <I>network</I><B>/</B><I>mask</I>.
+The
+<I>network</I>
+
+and
+<I>mask</I>
+
+can be any form acceptable to
+<I>ttoaddr</I>.
+
+In addition, and preferably, the
+<I>mask</I>
+
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+<B>24</B>
+
+in IPv4 means
+<B>255.255.255.0</B>).
+
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+<B>%default</B>
+
+is a synonym for
+<B>0.0.0.0/0</B>
+
+or
+<B>::/0</B>
+
+in IPv4 or IPv6 respectively.
+<P>
+
+<I>Ttosubnet</I>
+
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+<B>10.1.2.3/24</B>
+
+is synonymous with
+<B>10.1.2.0/24</B>).
+
+<I>Subnettot</I>
+
+always generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the length of the text string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>af</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the address family of interest.
+It should be either
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines constants,
+<B>ADDRTOT_BUF</B>
+
+and
+<B>SUBNETTOT_BUF</B>,
+
+which are the sizes of buffers just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available in
+<I>subnettot</I>.
+
+<I>Addrtot</I>
+
+also accepts format values
+<B>'r'</B>
+
+(signifying a text form suitable for DNS reverse lookups,
+e.g.
+<B>4.3.2.1.IN-ADDR.ARPA.</B>
+
+for IPv4 and
+RFC 2874 format for IPv6),
+and
+<B>'R'</B>
+
+(signifying an alternate reverse-lookup form,
+an error for IPv4 and RFC 1886 format for IPv6).
+Reverse-lookup names always end with a ``.''.
+<P>
+
+The text-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-text functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttoaddr</I>
+
+are:
+empty input;
+unknown address family;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal or colon-hex form;
+dotted-decimal or colon-hex component too large.
+<P>
+
+Fatal errors in
+<I>ttosubnet</I>
+
+are:
+no
+<B>/</B>
+
+in
+<I>src</I>;
+
+<I>ttoaddr</I>
+
+error in conversion of
+<I>network</I>
+
+or
+<I>mask</I>;
+
+bit-count mask too big;
+mask non-contiguous.
+<P>
+
+Fatal errors in
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+<B>10/24</B>
+
+means
+<B>10.0.0.0/24</B>)
+
+differs from that of some older conversion
+functions, e.g. those of
+<I><A HREF="inet.3.html">inet</A></I>(3).
+
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+<P>
+
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+<P>
+
+<I>Ttoaddr</I>
+
+does not support the mixed colon-hex-dotted-decimal
+convention used to embed an IPv4 address in an IPv6 address.
+<P>
+
+<I>Addrtot</I>
+
+always uses the
+<B>::</B>
+
+abbreviation (which can appear only once in an address) for the
+<I>first</I>
+
+sequence of multiple zeros in an IPv6 address.
+One can construct addresses (unlikely ones) in which this is suboptimal.
+<P>
+
+<I>Addrtot</I>
+
+<B>'r'</B>
+
+conversion of an IPv6 address uses lowercase hexadecimal,
+not the uppercase used in RFC 2874's examples.
+It takes careful reading of RFCs 2874, 2673, and 2234 to realize
+that lowercase is technically legitimate here,
+and there may be software which botches this
+and hence would have trouble with lowercase hex.
+<P>
+
+Possibly
+<I>subnettot</I>
+
+ought to recognize the
+<B>%default</B>
+
+case and generate that string as its output.
+Currently it doesn't.
+<P>
+
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+<P>
+
+<I><A HREF="Getnetbyname.3.html">Getnetbyname</A></I>(3)
+
+is a historical dreg.
+<P>
+
+<I>Tnatoaddr</I>
+
+probably should enforce completeness of dotted-decimal addresses.
+<P>
+
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_ttodata.3.html b/doc/manpage.d/ipsec_ttodata.3.html
new file mode 100644
index 000000000..960392fe0
--- /dev/null
+++ b/doc/manpage.d/ipsec_ttodata.3.html
@@ -0,0 +1,439 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTODATA</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTODATA</H1>
+Section: C Library Functions (3)<BR>Updated: 16 August 2003<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttodata, datatot - convert binary data bytes from and to text formats
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ttodata(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int base, char *dst, size_t dstlen, size_t *lenp);</B>
+
+<BR>
+
+<B>const char *ttodatav(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int base, char *dst, size_t dstlen, size_t *lenp,</B>
+
+<BR>
+&nbsp;
+<B>char *errp, size_t errlen, int flags);</B>
+
+<BR>
+
+<B>size_t datatot(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int format, char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttodata</I>,
+
+<I>ttodatav</I>,
+
+and
+<I>datatot</I>
+
+convert arbitrary binary data (e.g. encryption or authentication keys)
+from and to more-or-less human-readable text formats.
+<P>
+
+Currently supported formats are hexadecimal, base64, and characters.
+<P>
+
+A hexadecimal text value begins with a
+<B>0x</B>
+
+(or
+<B>0X</B>)
+
+prefix and continues with two-digit groups
+of hexadecimal digits (0-9, and a-f or A-F),
+each group encoding the value of one binary byte, high-order digit first.
+A single
+<B>_</B>
+
+(underscore)
+between consecutive groups is ignored, permitting punctuation to improve
+readability; doing this every eight digits seems about right.
+<P>
+
+A base64 text value begins with a
+<B>0s</B>
+
+(or
+<B>0S</B>)
+
+prefix
+and continues with four-digit groups of base64 digits (A-Z, a-z, 0-9, +, and /),
+each group encoding the value of three binary bytes as described in
+section 6.8 of RFC 2045.
+If
+<B>flags</B>
+
+has the
+<B>TTODATAV_IGNORESPACE</B>
+
+bit on, blanks are ignore (after the prefix).
+Note that the last one or two digits of a base64 group can be
+<B>=</B>
+
+to indicate that fewer than three binary bytes are encoded.
+<P>
+
+A character text value begins with a
+<B>0t</B>
+
+(or
+<B>0T</B>)
+
+prefix
+and continues with text characters, each being the value of one binary byte.
+<P>
+
+All these functions basically copy data from
+<I>src</I>
+
+(whose size is specified by
+<I>srclen</I>)
+
+to
+<I>dst</I>
+
+(whose size is specified by
+<I>dstlen</I>),
+
+doing the conversion en route.
+If the result will not fit in
+<I>dst</I>,
+
+it is truncated;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes of result written to
+<I>dst</I>.
+
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result bytes are written at all.
+<P>
+
+The
+<I>base</I>
+
+parameter of
+<I>ttodata</I>
+
+and
+<I>ttodatav</I>
+
+specifies what format the input is in;
+normally it should be
+<B>0</B>
+
+to signify that this gets figured out from the prefix.
+Values of
+<B>16</B>,
+
+<B>64</B>,
+
+and
+<B>256</B>
+
+respectively signify hexadecimal, base64, and character-text formats
+without prefixes.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>datatot</I>,
+
+a single character used as a type code,
+specifies which text format is wanted.
+The value
+<B>0</B>
+
+(not ASCII
+<B>'0'</B>,
+
+but a zero value) specifies a reasonable default.
+Other currently-supported values are:
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT><B>'x'</B>
+
+<DD>
+continuous lower-case hexadecimal with a
+<B>0x</B>
+
+prefix
+<DT><B>'h'</B>
+
+<DD>
+lower-case hexadecimal with a
+<B>0x</B>
+
+prefix and a
+<B>_</B>
+
+every eight digits
+<DT><B>':'</B>
+
+<DD>
+lower-case hexadecimal with no prefix and a
+<B>:</B>
+
+(colon) every two digits
+<DT><B>16</B>
+
+<DD>
+lower-case hexadecimal with no prefix or
+<B>_</B>
+
+<DT><B>'s'</B>
+
+<DD>
+continuous base64 with a
+<B>0s</B>
+
+prefix
+<DT><B>64</B>
+
+<DD>
+continuous base64 with no prefix
+</DL>
+</DL>
+
+<P>
+
+The default format is currently
+<B>'h'</B>.
+
+<P>
+
+<I>Ttodata</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+On success,
+if and only if
+<I>lenp</I>
+
+is non-NULL,
+<B>*lenp</B>
+
+is set to the number of bytes required to contain the full untruncated result.
+It is the caller's responsibility to check this against
+<I>dstlen</I>
+
+to determine whether he has obtained a complete result.
+The
+<B>*lenp</B>
+
+value is correct even if
+<I>dstlen</I>
+
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+<P>
+
+<I>Ttodatav</I>
+
+is just like
+<I>ttodata</I>
+
+except that in certain cases,
+if
+<I>errp</I>
+
+is non-NULL,
+the buffer pointed to by
+<I>errp</I>
+
+(whose length is given by
+<I>errlen</I>)
+
+is used to hold a more detailed error message.
+The return value is NULL for success,
+and is either
+<I>errp</I>
+
+or a pointer to a string literal for failure.
+If the size of the error-message buffer is
+inadequate for the desired message,
+<I>ttodatav</I>
+
+will fall back on returning a pointer to a literal string instead.
+The
+<I>freeswan.h</I>
+
+header file defines a constant
+<B>TTODATAV_BUF</B>
+
+which is the size of a buffer large enough for worst-case results.
+<P>
+
+The normal return value of
+<I>datatot</I>
+
+is the number of bytes required
+to contain the full untruncated result.
+It is the caller's responsibility to check this against
+<I>dstlen</I>
+
+to determine whether he has obtained a complete result.
+The return value is correct even if
+<I>dstlen</I>
+
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+A return value of
+<B>0</B>
+
+signals a fatal error of some kind
+(see DIAGNOSTICS).
+<P>
+
+A zero value for
+<I>srclen</I>
+
+in
+<I>ttodata</I>
+
+(but not
+<I>datatot</I>!)
+
+is synonymous with
+<B>strlen(src)</B>.
+
+A non-zero
+<I>srclen</I>
+
+in
+<I>ttodata</I>
+
+must not include the terminating NUL.
+<P>
+
+Unless
+<I>dstlen</I>
+
+is zero,
+the result supplied by
+<I>datatot</I>
+
+is always NUL-terminated,
+and its needed-size return value includes space for the terminating NUL.
+<P>
+
+Several obsolete variants of these functions
+(<I>atodata</I>,
+
+<I>datatoa</I>,
+
+<I>atobytes</I>,
+
+and
+<I>bytestoa</I>)
+
+are temporarily also supported.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="sprintf.3.html">sprintf</A>(3), <A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttodata</I>
+
+and
+<I>ttodatav</I>
+
+are:
+unknown characters in the input;
+unknown or missing prefix;
+unknown base;
+incomplete digit group;
+non-zero padding in a base64 less-than-three-bytes digit group;
+zero-length input.
+<P>
+
+Fatal errors in
+<I>datatot</I>
+
+are:
+unknown format code;
+zero-length input.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+<I>Datatot</I>
+
+should have a format code to produce character-text output.
+<P>
+
+The
+<B>0s</B>
+
+and
+<B>0t</B>
+
+prefixes are the author's inventions and are not a standard
+of any kind.
+They have been chosen to avoid collisions with existing practice
+(some C implementations use
+<B>0b</B>
+
+for binary)
+and possible confusion with unprefixed hexadecimal.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_ttosa.3.html b/doc/manpage.d/ipsec_ttosa.3.html
new file mode 100644
index 000000000..1e457fc24
--- /dev/null
+++ b/doc/manpage.d/ipsec_ttosa.3.html
@@ -0,0 +1,453 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOSA</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOSA</H1>
+Section: C Library Functions (3)<BR>Updated: 26 Nov 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttosa, satot - convert IPsec Security Association IDs to and from text
+<BR>
+
+ipsec initsaid - initialize an SA ID
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>typedef struct {</B>
+
+<BR>
+&nbsp;
+<B>ip_address dst;</B>
+
+<BR>
+&nbsp;
+<B>ipsec_spi_t spi;</B>
+
+<BR>
+&nbsp;
+<B>int proto;</B>
+
+<BR>
+
+<B>} ip_said;</B>
+
+<P>
+<B>const char *ttosa(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>ip_said *sa);</B>
+
+<BR>
+
+<B>size_t satot(const ip_said *sa, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<BR>
+
+<B>void initsaid(const ip_address *addr, ipsec_spi_t spi,</B>
+
+<BR>
+&nbsp;
+<B>int proto, ip_said *dst);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttosa</I>
+
+converts an ASCII Security Association (SA) specifier into an
+<B>ip_said</B>
+
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+<I>Satot</I>
+
+does the reverse conversion, back to a text SA specifier.
+<I>Initsaid</I>
+
+initializes an
+<B>ip_said</B>
+
+from separate items of information.
+<P>
+
+An SA is specified in text with a mail-like syntax, e.g.
+<B><A HREF="mailto:esp.5a7@1.2.3.4">esp.5a7@1.2.3.4</A></B>.
+
+An SA specifier contains
+a protocol prefix (currently
+<B>ah</B>,
+
+<B>esp</B>,
+
+<B>tun</B>,
+
+<B>comp</B>,
+
+or
+<B>int</B>),
+
+a single character indicating the address family
+(<B>.</B>
+
+for IPv4,
+<B>:</B>
+
+for IPv6),
+an unsigned integer SPI number in hexadecimal (with no
+<B>0x</B>
+
+prefix),
+and an IP address.
+The IP address can be any form accepted by
+<I><A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A></I>(3),
+
+e.g. dotted-decimal IPv4 address,
+colon-hex IPv6 address,
+or DNS name.
+<P>
+
+As a special case, the SA specifier
+<B>%passthrough4</B>
+
+or
+<B>%passthrough6</B>
+
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, these are synonyms for
+<B><A HREF="mailto:tun.0@0.0.0.0">tun.0@0.0.0.0</A></B>
+
+and
+<B>tun:0@::</B>
+
+respectively,
+but that is subject to change without notice.)
+<B>%passthrough</B>
+
+is a historical synonym for
+<B>%passthrough4</B>.
+
+These forms are known to both
+<I>ttosa</I>
+
+and
+<I>satot</I>,
+
+so the internal representation is never visible.
+<P>
+
+Similarly, the SA specifiers
+<B>%pass</B>,
+
+<B>%drop</B>,
+
+<B>%reject</B>,
+
+<B>%hold</B>,
+
+<B>%trap</B>,
+
+and
+<B>%trapsubnet</B>
+
+signify special ``magic'' SAs used to indicate that packets should be
+passed, dropped, rejected (dropped with ICMP notification),
+held,
+and trapped (sent up to
+<I><A HREF="ipsec_pluto.8.html">ipsec_pluto</A></I>(8),
+
+with either of two forms of
+<B>%hold</B>
+
+automatically installed)
+respectively.
+These forms too are known to both routines,
+so the internal representation of the magic SAs should never be visible.
+<P>
+
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file supplies the
+<B>ip_said</B>
+
+structure, as well as a data type
+<B>ipsec_spi_t</B>
+
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+<P>
+
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+defines the names
+<B>SA_ESP</B>,
+
+<B>SA_AH</B>,
+
+<B>SA_IPIP</B>,
+
+and
+<B>SA_COMP</B>
+
+to have the same values as the kernel names
+<B>IPPROTO_ESP</B>,
+
+<B>IPPROTO_AH</B>,
+
+<B>IPPROTO_IPIP</B>,
+
+and
+<B>IPPROTO_COMP</B>.
+
+<P>
+
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+also defines
+<B>SA_INT</B>
+
+to have the value
+<B>61</B>
+
+(reserved by IANA for ``any host internal protocol'')
+and
+<B>SPI_PASS</B>,
+
+<B>SPI_DROP</B>,
+
+<B>SPI_REJECT</B>,
+
+<B>SPI_HOLD</B>,
+
+and
+<B>SPI_TRAP</B>
+
+to have the values 256-260 (in <I>host</I> byte order) respectively.
+These are used in constructing the magic SAs
+(which always have address
+<B>0.0.0.0</B>).
+
+<P>
+
+If
+<I>satot</I>
+
+encounters an unknown protocol code, e.g. 77,
+it yields output using a prefix
+showing the code numerically, e.g. ``unk77''.
+This form is
+<I>not</I>
+
+recognized by
+<I>ttosa</I>.
+
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttosa</I>
+
+specifies the length of the string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>satot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<B>&lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+header file defines a constant,
+<B>SATOT_BUF</B>,
+
+which is the size of a buffer just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>satot</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the ASCII character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI,
+dotted-decimal or colon-hex address).
+The value
+<B>'f'</B>
+
+is similar except that the SPI is padded with
+<B>0</B>s
+
+to a fixed 32-bit width, to ease aligning displayed tables.
+<P>
+
+<I>Ttosa</I>
+
+returns
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Satot</I>
+
+returns
+<B>0</B>
+
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<P>
+
+There is also, temporarily, support for some obsolete
+forms of SA specifier which lack the address-family indicator.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec_ttoul.3.html">ipsec_ttoul</A>(3), <A HREF="ipsec_ttoaddr.3.html">ipsec_ttoaddr</A>(3), <A HREF="ipsec_samesaid.3.html">ipsec_samesaid</A>(3), <A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttosa</I>
+
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+<B>@</B>
+
+in input;
+unknown protocol prefix;
+conversion error in
+<I>ttoul</I>
+
+or
+<I>ttoaddr</I>.
+
+<P>
+
+Fatal errors in
+<I>satot</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttosa( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_ttosubnet.3.html b/doc/manpage.d/ipsec_ttosubnet.3.html
new file mode 100644
index 000000000..199937a35
--- /dev/null
+++ b/doc/manpage.d/ipsec_ttosubnet.3.html
@@ -0,0 +1,569 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 28 Sept 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttoaddr, tnatoaddr, addrtot - convert Internet addresses to and from text
+<BR>
+
+ipsec ttosubnet, subnettot - convert subnet/mask text form to and from addresses
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ttoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>const char *tnatoaddr(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_address *addr);</B>
+
+<BR>
+
+<B>size_t addrtot(const ip_address *addr, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<P>
+<B>const char *ttosubnet(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int af, ip_subnet *dst);</B>
+
+<BR>
+
+<B>size_t subnettot(const ip_subnet *sub, int format,</B>
+
+<BR>
+&nbsp;
+<B>char *dst, size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttoaddr</I>
+
+converts a text-string name or numeric address into a binary address
+(in network byte order).
+<I>Tnatoaddr</I>
+
+does the same conversion,
+but the only text forms it accepts are
+the ``official'' forms of
+numeric address (dotted-decimal for IPv4, colon-hex for IPv6).
+<I>Addrtot</I>
+
+does the reverse conversion, from binary address back to a text form.
+<I>Ttosubnet</I>
+
+and
+<I>subnettot</I>
+
+do likewise for the ``address/mask'' form used to write a
+specification of a subnet.
+<P>
+
+An IPv4 address is specified in text as a
+dotted-decimal address (e.g.
+<B>1.2.3.4</B>),
+
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+<B>0x01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>),
+
+an eight-digit host-order hexadecimal number with a
+<B>0h</B>
+
+prefix (e.g.
+<B>0h01020304</B>,
+
+which is synonymous with
+<B>1.2.3.4</B>
+
+on a big-endian host and
+<B>4.3.2.1</B>
+
+on a little-endian host),
+a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3),
+
+or an old-style network name to be looked up via
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3).
+
+<P>
+
+A dotted-decimal address may be incomplete, in which case
+text-to-binary conversion implicitly appends
+as many instances of
+<B>.0</B>
+
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+<B>10</B>
+
+is synonymous with
+<B>10.0.0.0</B>,
+
+and
+<B>128.009.000.032</B>
+
+is synonymous with
+<B>128.9.0.32</B>
+
+(the latter example is verbatim from RFC 1166).
+The result of applying
+<I>addrtot</I>
+
+to an IPv4 address is always complete and does not contain leading zeros.
+<P>
+
+Use of hexadecimal addresses is
+<B>strongly</B>
+
+<B>discouraged</B>;
+
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+<P>
+
+An IPv6 address is specified in text with
+colon-hex notation (e.g.
+<B>0:56:78ab:22:33:44:55:66</B>),
+
+colon-hex with
+<B>::</B>
+
+abbreviating at most one subsequence of multiple zeros (e.g.
+<B>99:ab::54:068</B>,
+
+which is synonymous with
+<B>99:ab:0:0:0:0:54:68</B>),
+
+or a DNS name to be looked up via
+<I><A HREF="gethostbyname.3.html">gethostbyname</A></I>(3).
+
+The result of applying
+<I>addrtot</I>
+
+to an IPv6 address will use
+<B>::</B>
+
+abbreviation if possible,
+and will not contain leading zeros.
+<P>
+
+The letters in hexadecimal
+may be uppercase or lowercase or any mixture thereof.
+<P>
+
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+<I><A HREF="resolver.5.html">resolver</A></I>(5)).
+
+The
+<I>h_addr</I>
+
+value returned by
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+IPv4 name lookup resorts to
+<I><A HREF="getnetbyname.3.html">getnetbyname</A></I>(3)
+
+only if
+<I><A HREF="gethostbyname2.3.html">gethostbyname2</A></I>(3)
+
+fails.
+<P>
+
+A subnet specification is of the form <I>network</I><B>/</B><I>mask</I>.
+The
+<I>network</I>
+
+and
+<I>mask</I>
+
+can be any form acceptable to
+<I>ttoaddr</I>.
+
+In addition, and preferably, the
+<I>mask</I>
+
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+<B>24</B>
+
+in IPv4 means
+<B>255.255.255.0</B>).
+
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+<B>%default</B>
+
+is a synonym for
+<B>0.0.0.0/0</B>
+
+or
+<B>::/0</B>
+
+in IPv4 or IPv6 respectively.
+<P>
+
+<I>Ttosubnet</I>
+
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+<B>10.1.2.3/24</B>
+
+is synonymous with
+<B>10.1.2.0/24</B>).
+
+<I>Subnettot</I>
+
+always generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the length of the text string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>af</I>
+
+parameter of
+<I>ttoaddr</I>
+
+and
+<I>ttosubnet</I>
+
+specifies the address family of interest.
+It should be either
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>.
+
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines constants,
+<B>ADDRTOT_BUF</B>
+
+and
+<B>SUBNETTOT_BUF</B>,
+
+which are the sizes of buffers just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+specifies what format is to be used for the conversion.
+The value
+<B>0</B>
+
+(not the character
+<B>'0'</B>,
+
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available in
+<I>subnettot</I>.
+
+<I>Addrtot</I>
+
+also accepts format values
+<B>'r'</B>
+
+(signifying a text form suitable for DNS reverse lookups,
+e.g.
+<B>4.3.2.1.IN-ADDR.ARPA.</B>
+
+for IPv4 and
+RFC 2874 format for IPv6),
+and
+<B>'R'</B>
+
+(signifying an alternate reverse-lookup form,
+an error for IPv4 and RFC 1886 format for IPv6).
+Reverse-lookup names always end with a ``.''.
+<P>
+
+The text-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-text functions return
+<B>0</B>
+
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttoaddr</I>
+
+are:
+empty input;
+unknown address family;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal or colon-hex form;
+dotted-decimal or colon-hex component too large.
+<P>
+
+Fatal errors in
+<I>ttosubnet</I>
+
+are:
+no
+<B>/</B>
+
+in
+<I>src</I>;
+
+<I>ttoaddr</I>
+
+error in conversion of
+<I>network</I>
+
+or
+<I>mask</I>;
+
+bit-count mask too big;
+mask non-contiguous.
+<P>
+
+Fatal errors in
+<I>addrtot</I>
+
+and
+<I>subnettot</I>
+
+are:
+unknown format.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+<B>10/24</B>
+
+means
+<B>10.0.0.0/24</B>)
+
+differs from that of some older conversion
+functions, e.g. those of
+<I><A HREF="inet.3.html">inet</A></I>(3).
+
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+<P>
+
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+<P>
+
+<I>Ttoaddr</I>
+
+does not support the mixed colon-hex-dotted-decimal
+convention used to embed an IPv4 address in an IPv6 address.
+<P>
+
+<I>Addrtot</I>
+
+always uses the
+<B>::</B>
+
+abbreviation (which can appear only once in an address) for the
+<I>first</I>
+
+sequence of multiple zeros in an IPv6 address.
+One can construct addresses (unlikely ones) in which this is suboptimal.
+<P>
+
+<I>Addrtot</I>
+
+<B>'r'</B>
+
+conversion of an IPv6 address uses lowercase hexadecimal,
+not the uppercase used in RFC 2874's examples.
+It takes careful reading of RFCs 2874, 2673, and 2234 to realize
+that lowercase is technically legitimate here,
+and there may be software which botches this
+and hence would have trouble with lowercase hex.
+<P>
+
+Possibly
+<I>subnettot</I>
+
+ought to recognize the
+<B>%default</B>
+
+case and generate that string as its output.
+Currently it doesn't.
+<P>
+
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+<P>
+
+<I><A HREF="Getnetbyname.3.html">Getnetbyname</A></I>(3)
+
+is a historical dreg.
+<P>
+
+<I>Tnatoaddr</I>
+
+probably should enforce completeness of dotted-decimal addresses.
+<P>
+
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttoaddr( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_ttoul.3.html b/doc/manpage.d/ipsec_ttoul.3.html
new file mode 100644
index 000000000..b722dcc13
--- /dev/null
+++ b/doc/manpage.d/ipsec_ttoul.3.html
@@ -0,0 +1,310 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOUL</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOUL</H1>
+Section: C Library Functions (3)<BR>Updated: 16 Aug 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttoul, ultot - convert unsigned-long numbers to and from text
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ttoul(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int base, unsigned long *n);</B>
+
+<BR>
+
+<B>size_t ultot(unsigned long n, int format, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttoul</I>
+
+converts a text-string number into a binary
+<B>unsigned long</B>
+
+value.
+<I>Ultot</I>
+
+does the reverse conversion, back to a text version.
+<P>
+
+Numbers are specified in text as
+decimal (e.g.
+<B>123</B>),
+
+octal with a leading zero (e.g.
+<B>012</B>,
+
+which has value 10),
+or hexadecimal with a leading
+<B>0x</B>
+
+(e.g.
+<B>0x1f</B>,
+
+which has value 31)
+in either upper or lower case.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttoul</I>
+
+specifies the length of the string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>base</I>
+
+parameter of
+<I>ttoul</I>
+
+can be
+<B>8</B>,
+
+<B>10</B>,
+
+or
+<B>16</B>,
+
+in which case the number supplied is assumed to be of that form
+(and in the case of
+<B>16</B>,
+
+to lack any
+<B>0x</B>
+
+prefix).
+It can also be
+<B>0</B>,
+
+in which case the number is examined for a leading zero
+or a leading
+<B>0x</B>
+
+to determine its base.
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>ultot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines a constant,
+<B>ULTOT_BUF</B>,
+
+which is the size of a buffer just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>ultot</I>
+
+must be one of:
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT><B>'o'</B><DD>
+octal conversion with leading
+<B>0</B>
+
+<DT><B>&nbsp;8</B><DD>
+octal conversion with no leading
+<B>0</B>
+
+<DT><B>'d'</B><DD>
+decimal conversion
+<DT><B>10</B><DD>
+same as
+<B>d</B>
+
+<DT><B>'x'</B><DD>
+hexadecimal conversion, including leading
+<B>0x</B>
+
+<DT><B>16</B><DD>
+hexadecimal conversion with no leading
+<B>0x</B>
+
+<DT><B>17</B><DD>
+like
+<B>16</B>
+
+except padded on left with
+<B>0</B>s
+
+to eight digits (full width of a 32-bit number)
+</DL>
+</DL>
+
+<P>
+
+<I>Ttoul</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Ultot</I>
+
+returns
+<B>0</B>
+
+for a failure, and otherwise
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL
+(it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred).
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="atol.3.html">atol</A>(3), <A HREF="strtoul.3.html">strtoul</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttoul</I>
+
+are:
+empty input;
+unknown
+<I>base</I>;
+
+non-digit character found;
+number too large for an
+<B>unsigned long</B>.
+
+<P>
+
+Fatal errors in
+<I>ultot</I>
+
+are:
+unknown
+<I>format</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+Conversion of
+<B>0</B>
+
+with format
+<B>o</B>
+
+yields
+<B>00</B>.
+
+<P>
+
+<I>Ultot</I>
+
+format
+<B>17</B>
+
+is a bit of a kludge.
+<P>
+
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttoul( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_ultoa.3.html b/doc/manpage.d/ipsec_ultoa.3.html
new file mode 100644
index 000000000..7669dce52
--- /dev/null
+++ b/doc/manpage.d/ipsec_ultoa.3.html
@@ -0,0 +1,266 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ATOUL</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ATOUL</H1>
+Section: C Library Functions (3)<BR>Updated: 11 June 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec atoul, ultoa - convert unsigned-long numbers to and from ASCII
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *atoul(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int base, unsigned long *n);</B>
+
+<BR>
+
+<B>size_t ultoa(unsigned long n, int base, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions are obsolete; see
+<I><A HREF="ipsec_ttoul.3.html">ipsec_ttoul</A></I>(3)
+
+for their replacements.
+<P>
+
+<I>Atoul</I>
+
+converts an ASCII number into a binary
+<B>unsigned long</B>
+
+value.
+<I>Ultoa</I>
+
+does the reverse conversion, back to an ASCII version.
+<P>
+
+Numbers are specified in ASCII as
+decimal (e.g.
+<B>123</B>),
+
+octal with a leading zero (e.g.
+<B>012</B>,
+
+which has value 10),
+or hexadecimal with a leading
+<B>0x</B>
+
+(e.g.
+<B>0x1f</B>,
+
+which has value 31)
+in either upper or lower case.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>atoul</I>
+
+specifies the length of the ASCII string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>base</I>
+
+parameter of
+<I>atoul</I>
+
+can be
+<B>8</B>,
+
+<B>10</B>,
+
+or
+<B>16</B>,
+
+in which case the number supplied is assumed to be of that form
+(and in the case of
+<B>16</B>,
+
+to lack any
+<B>0x</B>
+
+prefix).
+It can also be
+<B>0</B>,
+
+in which case the number is examined for a leading zero
+or a leading
+<B>0x</B>
+
+to determine its base,
+or
+<B>13</B>
+
+(halfway between 10 and 16),
+which has the same effect as
+<B>0</B>
+
+except that a non-hexadecimal
+number is considered decimal regardless of any leading zero.
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>ultoa</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+<P>
+
+The
+<I>base</I>
+
+parameter of
+<I>ultoa</I>
+
+must be
+<B>8</B>,
+
+<B>10</B>,
+
+or
+<B>16</B>.
+
+<P>
+
+<I>Atoul</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Ultoa</I>
+
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="atol.3.html">atol</A>(3), <A HREF="strtoul.3.html">strtoul</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>atoul</I>
+
+are:
+empty input;
+unknown
+<I>base</I>;
+
+non-digit character found;
+number too large for an
+<B>unsigned long</B>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+There is no provision for reporting an invalid
+<I>base</I>
+
+parameter given to
+<I>ultoa</I>.
+
+<P>
+
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = atoul( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_ultot.3.html b/doc/manpage.d/ipsec_ultot.3.html
new file mode 100644
index 000000000..b722dcc13
--- /dev/null
+++ b/doc/manpage.d/ipsec_ultot.3.html
@@ -0,0 +1,310 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_TTOUL</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_TTOUL</H1>
+Section: C Library Functions (3)<BR>Updated: 16 Aug 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ttoul, ultot - convert unsigned-long numbers to and from text
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ttoul(const char *src, size_t srclen,</B>
+
+<BR>
+&nbsp;
+<B>int base, unsigned long *n);</B>
+
+<BR>
+
+<B>size_t ultot(unsigned long n, int format, char *dst,</B>
+
+<BR>
+&nbsp;
+<B>size_t dstlen);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>Ttoul</I>
+
+converts a text-string number into a binary
+<B>unsigned long</B>
+
+value.
+<I>Ultot</I>
+
+does the reverse conversion, back to a text version.
+<P>
+
+Numbers are specified in text as
+decimal (e.g.
+<B>123</B>),
+
+octal with a leading zero (e.g.
+<B>012</B>,
+
+which has value 10),
+or hexadecimal with a leading
+<B>0x</B>
+
+(e.g.
+<B>0x1f</B>,
+
+which has value 31)
+in either upper or lower case.
+<P>
+
+The
+<I>srclen</I>
+
+parameter of
+<I>ttoul</I>
+
+specifies the length of the string pointed to by
+<I>src</I>;
+
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+<I>srclen</I>
+
+value of
+<B>0</B>
+
+is taken to mean
+<B>strlen(src)</B>.
+
+<P>
+
+The
+<I>base</I>
+
+parameter of
+<I>ttoul</I>
+
+can be
+<B>8</B>,
+
+<B>10</B>,
+
+or
+<B>16</B>,
+
+in which case the number supplied is assumed to be of that form
+(and in the case of
+<B>16</B>,
+
+to lack any
+<B>0x</B>
+
+prefix).
+It can also be
+<B>0</B>,
+
+in which case the number is examined for a leading zero
+or a leading
+<B>0x</B>
+
+to determine its base.
+<P>
+
+The
+<I>dstlen</I>
+
+parameter of
+<I>ultot</I>
+
+specifies the size of the
+<I>dst</I>
+
+parameter;
+under no circumstances are more than
+<I>dstlen</I>
+
+bytes written to
+<I>dst</I>.
+
+A result which will not fit is truncated.
+<I>Dstlen</I>
+
+can be zero, in which case
+<I>dst</I>
+
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+<I>freeswan.h</I>
+
+header file defines a constant,
+<B>ULTOT_BUF</B>,
+
+which is the size of a buffer just large enough for worst-case results.
+<P>
+
+The
+<I>format</I>
+
+parameter of
+<I>ultot</I>
+
+must be one of:
+<DL COMPACT><DT><DD>
+<DL COMPACT>
+<DT><B>'o'</B><DD>
+octal conversion with leading
+<B>0</B>
+
+<DT><B>&nbsp;8</B><DD>
+octal conversion with no leading
+<B>0</B>
+
+<DT><B>'d'</B><DD>
+decimal conversion
+<DT><B>10</B><DD>
+same as
+<B>d</B>
+
+<DT><B>'x'</B><DD>
+hexadecimal conversion, including leading
+<B>0x</B>
+
+<DT><B>16</B><DD>
+hexadecimal conversion with no leading
+<B>0x</B>
+
+<DT><B>17</B><DD>
+like
+<B>16</B>
+
+except padded on left with
+<B>0</B>s
+
+to eight digits (full width of a 32-bit number)
+</DL>
+</DL>
+
+<P>
+
+<I>Ttoul</I>
+
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<I>Ultot</I>
+
+returns
+<B>0</B>
+
+for a failure, and otherwise
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL
+(it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred).
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="atol.3.html">atol</A>(3), <A HREF="strtoul.3.html">strtoul</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in
+<I>ttoul</I>
+
+are:
+empty input;
+unknown
+<I>base</I>;
+
+non-digit character found;
+number too large for an
+<B>unsigned long</B>.
+
+<P>
+
+Fatal errors in
+<I>ultot</I>
+
+are:
+unknown
+<I>format</I>.
+
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<A NAME="lbAH">&nbsp;</A>
+<H2>BUGS</H2>
+
+Conversion of
+<B>0</B>
+
+with format
+<B>o</B>
+
+yields
+<B>00</B>.
+
+<P>
+
+<I>Ultot</I>
+
+format
+<B>17</B>
+
+is a bit of a kludge.
+<P>
+
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+<P>
+
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+<P>
+
+<DL COMPACT><DT><DD>
+<PRE>
+<B>const char *error;</B>
+
+<B>error = ttoul( /* ... */ );</B>
+<B>if (error != NULL) {</B>
+<B> /* something went wrong */</B>
+</PRE>
+
+</DL>
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+<DT><A HREF="#lbAH">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_unspecaddr.3.html b/doc/manpage.d/ipsec_unspecaddr.3.html
new file mode 100644
index 000000000..92f69d99c
--- /dev/null
+++ b/doc/manpage.d/ipsec_unspecaddr.3.html
@@ -0,0 +1,166 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_ANYADDR</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_ANYADDR</H1>
+Section: C Library Functions (3)<BR>Updated: 8 Sept 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec anyaddr - get &quot;any&quot; address
+<BR>
+
+ipsec isanyaddr - test address for equality to &quot;any&quot; address
+<BR>
+
+ipsec unspecaddr - get &quot;unspecified&quot; address
+<BR>
+
+ipsec isunspecaddr - test address for equality to &quot;unspecified&quot; address
+<BR>
+
+ipsec loopbackaddr - get loopback address
+<BR>
+
+ipsec isloopbackaddr - test address for equality to loopback address
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *anyaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isanyaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *unspecaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isunspecaddr(const ip_address *src);</B>
+
+<BR>
+
+<B>const char *loopbackaddr(int af, ip_address *dst);</B>
+
+<BR>
+
+<B>int isloopbackaddr(const ip_address *src);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions fill in, and test for, special values of the
+<I>ip_address</I>
+
+type.
+<P>
+
+<I>Anyaddr</I>
+
+fills in the destination
+<I>*dst</I>
+
+with the ``any'' address of address family
+<I>af</I>
+
+(normally
+<B>AF_INET</B>
+
+or
+<B>AF_INET6</B>).
+
+The IPv4 ``any'' address is the one embodied in the old
+<B>INADDR_ANY</B>
+
+macro.
+<P>
+
+<I>Isanyaddr</I>
+
+returns
+<B>1</B>
+
+if the
+<I>src</I>
+
+address equals the ``any'' address,
+and
+<B>0</B>
+
+otherwise.
+<P>
+
+Similarly,
+<I>unspecaddr</I>
+
+supplies, and
+<I>isunspecaddr</I>
+
+tests for,
+the ``unspecified'' address,
+which may be the same as the ``any'' address.
+<P>
+
+Similarly,
+<I>loopbackaddr</I>
+
+supplies, and
+<I>islookbackaddr</I>
+
+tests for,
+the loopback address.
+<P>
+
+<I>Anyaddr</I>,
+
+<I>unspecaddr</I>,
+
+and
+<I>loopbackaddr</I>
+
+return
+<B>NULL</B>
+
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="inet.3.html">inet</A>(3), <A HREF="ipsec_addrtot.3.html">ipsec_addrtot</A>(3), <A HREF="ipsec_sameaddr.3.html">ipsec_sameaddr</A>(3)
+<A NAME="lbAF">&nbsp;</A>
+<H2>DIAGNOSTICS</H2>
+
+Fatal errors in the address-supplying functions are:
+unknown address family.
+<A NAME="lbAG">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">DIAGNOSTICS</A><DD>
+<DT><A HREF="#lbAG">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_verify.8.html b/doc/manpage.d/ipsec_verify.8.html
new file mode 100644
index 000000000..09d04894b
--- /dev/null
+++ b/doc/manpage.d/ipsec_verify.8.html
@@ -0,0 +1,107 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_VERIFY</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_VERIFY</H1>
+Section: Maintenance Commands (8)<BR>Updated: 8 June 2002<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec verify - see if FreeSWAN has been installed correctly
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>ipsec</B>
+
+<B>verify</B>
+
+[
+<B>--host</B>
+
+&nbsp;name&nbsp;]
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<P>
+
+Invoked without argument,
+<I>verify </I>
+
+examines the local system for a number of common system faults:
+IPsec not in path, no secrets file generated,
+pluto not running, and IPsec support not present in kernel
+(or IPsec module not loaded).
+If two or more interfaces are found, it performs checks relevant on an
+IPsec gateway: whether IP forwarding is allowed, and if so,
+whether MASQ or NAT rules are in play.
+<P>
+
+In addition,
+<I>verify </I>
+
+performs checks relevant to Opportunistic Encryption.
+It looks in forward DNS for a TXT record for the system's hostname, and
+in reverse DNS for a TXT record for the system's IP addresses.
+It checks whether the system has a public IP.
+<P>
+
+The
+<B>--host</B>
+
+option causes
+<B>verify</B>
+
+to look for a TXT record for
+<I>name</I>
+
+in forward and reverse DNS.
+<A NAME="lbAE">&nbsp;</A>
+<H2>FILES</H2>
+
+<PRE>
+/proc/net/ipsec_eroute
+/etc/ipsec.secrets
+</PRE>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Michael Richardson.
+<A NAME="lbAG">&nbsp;</A>
+<H2>BUGS</H2>
+
+<I>Verify </I>
+
+does not check for
+<B>ipchains</B>
+
+masquerading.
+<P>
+
+<I>Verify</I>
+
+does not look for TXT records for Opportunistic clients behind the system.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">FILES</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+<DT><A HREF="#lbAG">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_version.3.html b/doc/manpage.d/ipsec_version.3.html
new file mode 100644
index 000000000..bcad75a46
--- /dev/null
+++ b/doc/manpage.d/ipsec_version.3.html
@@ -0,0 +1,94 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_VERSION</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_VERSION</H1>
+Section: C Library Functions (3)<BR>Updated: 21 Nov 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ipsec_version_code - get IPsec version code
+<BR>
+
+ipsec ipsec_version_string - get full IPsec version string
+<BR>
+
+ipsec ipsec_copyright_notice - get IPsec copyright notice
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ipsec_version_code(void);</B>
+
+<BR>
+
+<B>const char *ipsec_version_string(void);</B>
+
+<BR>
+
+<B>const char **ipsec_copyright_notice(void);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions provide information on version numbering and copyright
+of the Linux FreeS/WAN IPsec implementation.
+<P>
+
+<I>Ipsec_version_code</I>
+
+returns a pointer to a string constant
+containing the current IPsec version code,
+such as ``1.92'' or ``snap2001Nov19b''.
+<P>
+
+<I>Ipsec_version_string</I>
+
+returns a pointer to a string constant giving a full version identification,
+consisting of the version code preceded by a prefix identifying the software,
+e.g. ``Linux FreeS/WAN 1.92''.
+<P>
+
+<I>Ipsec_copyright_notice</I>
+
+returns a pointer to a vector of pointers,
+terminated by a
+<B>NULL</B>,
+
+which is the text of a suitable copyright notice.
+Each pointer points to a string constant (possibly empty) which is one line
+of the somewhat-verbose copyright notice.
+The strings are NUL-terminated and do not contain a newline;
+supplying suitable line termination for the output device is
+the caller's responsibility.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_version.5.html b/doc/manpage.d/ipsec_version.5.html
new file mode 100644
index 000000000..89bee0f97
--- /dev/null
+++ b/doc/manpage.d/ipsec_version.5.html
@@ -0,0 +1,103 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_VERSION</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_VERSION</H1>
+Section: File Formats (5)<BR>Updated: 29 Jun 2000<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec_version - lists KLIPS version information
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>cat</B>
+
+<B>/proc/net/ipsec_version</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<I>/proc/net/ipsec_version</I>
+
+is a read-only file which lists the currently running KLIPS version
+information.
+<P>
+
+<A NAME="lbAE">&nbsp;</A>
+<H2>EXAMPLES</H2>
+
+<DL COMPACT>
+<DT><B>FreeS/WAN version: 1.4</B>
+
+<DD>
+</DL>
+<P>
+
+shows that the currently loaded
+<B>KLIPS</B>
+
+is from
+<B>FreeS/WAN 1.4.</B>
+
+<P>
+
+<A NAME="lbAF">&nbsp;</A>
+<H2>FILES</H2>
+
+/proc/net/ipsec_version
+<A NAME="lbAG">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8), <A HREF="ipsec_manual.8.html">ipsec_manual</A>(8), <A HREF="ipsec_eroute.5.html">ipsec_eroute</A>(5), <A HREF="ipsec_spi.5.html">ipsec_spi</A>(5),
+<A HREF="ipsec_spigrp.5.html">ipsec_spigrp</A>(5), <A HREF="ipsec_klipsdebug.5.html">ipsec_klipsdebug</A>(5), <A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A>(8), <A HREF="ipsec_pf_key.5.html">ipsec_pf_key</A>(5)
+<A NAME="lbAH">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the Linux FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org/">http://www.freeswan.org/</A>&gt;
+by Richard Guy Briggs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">EXAMPLES</A><DD>
+<DT><A HREF="#lbAF">FILES</A><DD>
+<DT><A HREF="#lbAG">SEE ALSO</A><DD>
+<DT><A HREF="#lbAH">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_version_code.3.html b/doc/manpage.d/ipsec_version_code.3.html
new file mode 100644
index 000000000..bcad75a46
--- /dev/null
+++ b/doc/manpage.d/ipsec_version_code.3.html
@@ -0,0 +1,94 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_VERSION</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_VERSION</H1>
+Section: C Library Functions (3)<BR>Updated: 21 Nov 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ipsec_version_code - get IPsec version code
+<BR>
+
+ipsec ipsec_version_string - get full IPsec version string
+<BR>
+
+ipsec ipsec_copyright_notice - get IPsec copyright notice
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ipsec_version_code(void);</B>
+
+<BR>
+
+<B>const char *ipsec_version_string(void);</B>
+
+<BR>
+
+<B>const char **ipsec_copyright_notice(void);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions provide information on version numbering and copyright
+of the Linux FreeS/WAN IPsec implementation.
+<P>
+
+<I>Ipsec_version_code</I>
+
+returns a pointer to a string constant
+containing the current IPsec version code,
+such as ``1.92'' or ``snap2001Nov19b''.
+<P>
+
+<I>Ipsec_version_string</I>
+
+returns a pointer to a string constant giving a full version identification,
+consisting of the version code preceded by a prefix identifying the software,
+e.g. ``Linux FreeS/WAN 1.92''.
+<P>
+
+<I>Ipsec_copyright_notice</I>
+
+returns a pointer to a vector of pointers,
+terminated by a
+<B>NULL</B>,
+
+which is the text of a suitable copyright notice.
+Each pointer points to a string constant (possibly empty) which is one line
+of the somewhat-verbose copyright notice.
+The strings are NUL-terminated and do not contain a newline;
+supplying suitable line termination for the output device is
+the caller's responsibility.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_version_string.3.html b/doc/manpage.d/ipsec_version_string.3.html
new file mode 100644
index 000000000..bcad75a46
--- /dev/null
+++ b/doc/manpage.d/ipsec_version_string.3.html
@@ -0,0 +1,94 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_VERSION</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_VERSION</H1>
+Section: C Library Functions (3)<BR>Updated: 21 Nov 2001<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec ipsec_version_code - get IPsec version code
+<BR>
+
+ipsec ipsec_version_string - get full IPsec version string
+<BR>
+
+ipsec ipsec_copyright_notice - get IPsec copyright notice
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+<B>#include &lt;<A HREF="file:/usr/include/freeswan.h">freeswan.h</A>&gt;</B>
+
+<P>
+<B>const char *ipsec_version_code(void);</B>
+
+<BR>
+
+<B>const char *ipsec_version_string(void);</B>
+
+<BR>
+
+<B>const char **ipsec_copyright_notice(void);</B>
+
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+These functions provide information on version numbering and copyright
+of the Linux FreeS/WAN IPsec implementation.
+<P>
+
+<I>Ipsec_version_code</I>
+
+returns a pointer to a string constant
+containing the current IPsec version code,
+such as ``1.92'' or ``snap2001Nov19b''.
+<P>
+
+<I>Ipsec_version_string</I>
+
+returns a pointer to a string constant giving a full version identification,
+consisting of the version code preceded by a prefix identifying the software,
+e.g. ``Linux FreeS/WAN 1.92''.
+<P>
+
+<I>Ipsec_copyright_notice</I>
+
+returns a pointer to a vector of pointers,
+terminated by a
+<B>NULL</B>,
+
+which is the text of a suitable copyright notice.
+Each pointer points to a string constant (possibly empty) which is one line
+of the somewhat-verbose copyright notice.
+The strings are NUL-terminated and do not contain a newline;
+supplying suitable line termination for the output device is
+the caller's responsibility.
+<A NAME="lbAE">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<A HREF="ipsec.8.html">ipsec</A>(8)
+<A NAME="lbAF">&nbsp;</A>
+<H2>HISTORY</H2>
+
+Written for the FreeS/WAN project by Henry Spencer.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DT><A HREF="#lbAE">SEE ALSO</A><DD>
+<DT><A HREF="#lbAF">HISTORY</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpage.d/ipsec_whack.8.html b/doc/manpage.d/ipsec_whack.8.html
new file mode 100644
index 000000000..2e2ce4c2f
--- /dev/null
+++ b/doc/manpage.d/ipsec_whack.8.html
@@ -0,0 +1,1824 @@
+Content-type: text/html
+
+<HTML><HEAD><TITLE>Manpage of IPSEC_PLUTO</TITLE>
+</HEAD><BODY>
+<H1>IPSEC_PLUTO</H1>
+Section: Maintenance Commands (8)<BR>Updated: 28 March 1999<BR><A HREF="#index">Index</A>
+<A HREF="http://localhost/cgi-bin/man/man2html">Return to Main Contents</A><HR>
+
+<A NAME="lbAB">&nbsp;</A>
+<H2>NAME</H2>
+
+ipsec pluto - IPsec IKE keying daemon
+<BR>
+
+ipsec whack - control interface for IPSEC keying daemon
+<A NAME="lbAC">&nbsp;</A>
+<H2>SYNOPSIS</H2>
+
+
+
+<DL COMPACT>
+<DT>
+<B>
+<DD>ipsec pluto
+[--help]
+[--version]
+[--optionsfrom&nbsp;</B><I>filename</I>]
+[--nofork]
+[--stderrlog]
+[--noklips]
+[--uniqueids]
+[<B>--interface</B> <I>interfacename</I>]
+[--ikeport&nbsp;<I>portnumber</I>]
+[--ctlbase&nbsp;<I>path</I>]
+[--secretsfile&nbsp;<I>secrets-file</I>]
+[--adns <I>pathname</I>]
+[--lwdnsq <I>pathname</I>]
+[--perpeerlog]
+[--perpeerlogbase&nbsp;<I>dirname</I>]
+[--debug-none]
+[--debug-all]
+[--debug-raw]
+[--debug-crypt]
+[--debug-parsing]
+[--debug-emitting]
+[--debug-control]
+[--debug-lifecycle]
+[--debug-klips]
+[--debug-dns]
+[--debug-oppo]
+[--debug-private]
+<DT>
+<B>
+<DD>ipsec whack
+[--help]
+[--version]
+<DT>
+
+<DD>ipsec whack
+--name&nbsp;</B><I>connection-name</I>
+<BR>
+
+[--id&nbsp;<I>id</I>] [--host&nbsp;<I>ip-address</I>]
+[--ikeport&nbsp;<I>port-number</I>]
+[--nexthop&nbsp;<I>ip-address</I>]
+[--client&nbsp;<I>subnet</I>]
+[--dnskeyondemand]
+[--updown&nbsp;<I>updown</I>]
+<BR>
+
+--to
+<BR>
+
+[--id&nbsp;<I>id</I>]
+[--host&nbsp;<I>ip-address</I>]
+[--ikeport&nbsp;<I>port-number</I>]
+[--nexthop&nbsp;<I>ip-address</I>]
+[--client&nbsp;<I>subnet</I>]
+[--dnskeyondemand]
+[--updown&nbsp;<I>updown</I>]
+<BR>
+
+[--psk]
+[--rsasig]
+[--encrypt]
+[--authenticate]
+[--compress]
+[--tunnel]
+[--pfs]
+[--disablearrivalcheck]
+[--ipv4]
+[--ipv6]
+[--tunnelipv4]
+[--tunnelipv6]
+[--ikelifetime&nbsp;<I>seconds</I>]
+[--ipseclifetime&nbsp;<I>seconds</I>]
+[--rekeymargin&nbsp;<I>seconds</I>]
+[--rekeyfuzz&nbsp;<I>percentage</I>]
+[--keyingtries&nbsp;<I>count</I>]
+[--dontrekey]
+[--delete]
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--keyid&nbsp;</B><I>id</I>
+[--addkey]
+[--pubkeyrsa&nbsp;<I>key</I>]
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--myid&nbsp;</B><I>id</I>
+<DT>
+<B>
+<DD>ipsec whack
+--listen|--unlisten
+[--ctlbase&nbsp;</B><I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--route|--unroute
+--name&nbsp;</B><I>connection-name</I>
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--initiate|--terminate
+--name&nbsp;</B><I>connection-name</I>
+[--asynchronous]
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+[--tunnelipv4]
+[--tunnelipv6]
+--oppohere </B><I>ip-address</I>
+--oppothere <I>ip-address</I>
+<DT>
+<B>
+<DD>ipsec whack
+--delete
+--name&nbsp;</B><I>connection-name</I>
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--deletestate&nbsp;</B><I>state-number</I>
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+[--name&nbsp;</B><I>connection-name</I>]
+[--debug-none]
+[--debug-all]
+[--debug-raw]
+[--debug-crypt]
+[--debug-parsing]
+[--debug-emitting]
+[--debug-control]
+[--debug-lifecycle]
+[--debug-klips]
+[--debug-dns]
+[--debug-oppo]
+[--debug-private]
+[--ctlbase&nbsp;<I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--status
+[--ctlbase&nbsp;</B><I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+<DT>
+<B>
+<DD>ipsec whack
+--shutdown
+[--ctlbase&nbsp;</B><I>path</I>]
+[--optionsfrom&nbsp;<I>filename</I>]
+[--label&nbsp;<I>string</I>]
+
+
+
+</DL>
+<A NAME="lbAD">&nbsp;</A>
+<H2>DESCRIPTION</H2>
+
+<B>pluto</B>
+
+is an IKE (``IPsec Key Exchange'') daemon.
+<B>whack</B>
+
+is an auxiliary program to allow requests to be made to a running
+<B>pluto</B>.
+
+<P>
+
+<B>pluto</B>
+
+is used to automatically build shared ``security associations'' on a
+system that has IPsec, the secure IP protocol.
+In other words,
+<B>pluto</B>
+
+can eliminate much of the work of manual keying.
+The actual
+secure transmission of packets is the responsibility of other parts of
+the system (see
+<B>KLIPS</B>,
+
+the companion implementation of IPsec).
+<I><A HREF="ipsec_auto.8.html">ipsec_auto</A></I>(8) provides a more convenient interface to
+<B>pluto</B> and <B>whack</B>.
+<A NAME="lbAE">&nbsp;</A>
+<H3>IKE's Job</H3>
+
+<P>
+
+A <I>Security Association</I> (<I>SA</I>) is an agreement between two network nodes on
+how to process certain traffic between them. This processing involves
+encapsulation, authentication, encryption, or compression.
+<P>
+
+IKE can be deployed on a network node to negotiate Security
+Associations for that node. These IKE implementations can only
+negotiate with other IKE implementations, so IKE must be on each node
+that is to be an endpoint of an IKE-negotiated Security Association.
+No other nodes need to be running IKE.
+<P>
+
+An IKE instance (i.e. an IKE implementation on a particular network
+node) communicates with another IKE instance using UDP IP packets, so
+there must be a route between the nodes in each direction.
+<P>
+
+The negotiation of Security Associations requires a number of choices
+that involve tradeoffs between security, convenience, trust, and
+efficiency. These are policy issues and are normally specified to the
+IKE instance by the system administrator.
+<P>
+
+IKE deals with two kinds of Security Associations. The first part of
+a negotiation between IKE instances is to build an ISAKMP SA. An
+ISAKMP SA is used to protect communication between the two IKEs.
+IPsec SAs can then be built by the IKEs - these are used to carry
+protected IP traffic between the systems.
+<P>
+
+The negotiation of the ISAKMP SA is known as Phase 1. In theory,
+Phase 1 can be accomplished by a couple of different exchange types,
+but we only implement one called Main Mode (we don't implement
+Aggressive Mode).
+<P>
+
+Any negotiation under the protection of an ISAKMP SA, including the
+negotiation of IPsec SAs, is part of Phase 2. The exchange type
+that we use to negotiate an IPsec SA is called Quick Mode.
+<P>
+
+IKE instances must be able to authenticate each other as part of their
+negotiation of an ISAKMP SA. This can be done by several mechanisms
+described in the draft standards.
+<P>
+
+IKE negotiation can be initiated by any instance with any other. If
+both can find an agreeable set of characteristics for a Security
+Association, and both recognize each others authenticity, they can set
+up a Security Association. The standards do not specify what causes
+an IKE instance to initiate a negotiation.
+<P>
+
+In summary, an IKE instance is prepared to automate the management of
+Security Associations in an IPsec environment, but a number of issues
+are considered policy and are left in the system administrator's hands.
+<A NAME="lbAF">&nbsp;</A>
+<H3>Pluto</H3>
+
+<P>
+
+<B>pluto</B> is an implementation of IKE. It runs as a daemon on a network
+node. Currently, this network node must be a LINUX system running the
+<B>KLIPS</B> implementation of IPsec.
+<P>
+
+<B>pluto</B> only implements a subset of IKE. This is enough for it to
+interoperate with other instances of <B>pluto</B>, and many other IKE
+implementations. We are working on implementing more of IKE.
+<P>
+
+The policy for acceptable characteristics for Security Associations is
+mostly hardwired into the code of <B>pluto</B> (spdb.c). Eventually
+this will be moved into a security policy database with reasonable
+expressive power and more convenience.
+<P>
+
+<B>pluto</B> uses shared secrets or RSA signatures to authenticate
+peers with whom it is negotiating.
+<P>
+
+<B>pluto</B> initiates negotiation of a Security Association when it is
+manually prodded: the program <B>whack</B> is run to trigger this.
+It will also initiate a negotiation when <B>KLIPS</B> traps an outbound packet
+for Opportunistic Encryption.
+<P>
+
+<B>pluto</B> implements ISAKMP SAs itself. After it has negotiated the
+characteristics of an IPsec SA, it directs <B>KLIPS</B> to implement it.
+It also invokes a script to adjust any firewall and issue <I><A HREF="route.8.html">route</A></I>(8)
+commands to direct IP packets through <B>KLIPS</B>.
+<P>
+
+When <B>pluto</B> shuts down, it closes all Security Associations.
+<A NAME="lbAG">&nbsp;</A>
+<H3>Before Running Pluto</H3>
+
+<P>
+
+<B>pluto</B> runs as a daemon with userid root. Before running it, a few
+things must be set up.
+<P>
+
+<B>pluto</B> requires <B>KLIPS</B>, the FreeS/WAN implementation of IPsec.
+All of the components of <B>KLIPS</B> and <B>pluto</B> should be installed.
+<P>
+
+<B>pluto</B> supports multiple public networks (that is, networks
+that are considered insecure and thus need to have their traffic
+encrypted or authenticated). It discovers the
+public interfaces to use by looking at all interfaces that are
+configured (the <B>--interface</B> option can be used to limit
+the interfaces considered).
+It does this only when <B>whack</B> tells it to --listen,
+so the interfaces must be configured by then. Each interface with a name of the form
+<B>ipsec</B>[<B>0</B>-<B>9</B>] is taken as a <B>KLIPS</B> virtual public interface.
+Another network interface with the same IP address (there should be only
+one) is taken as the corresponding real public
+interface. <I><A HREF="ifconfig.8.html">ifconfig</A></I>(8) with the <B>-a</B> flag will show
+the name and status of each network interface.
+<P>
+
+<B>pluto</B> requires a database of preshared secrets and RSA private keys.
+This is described in the
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5).
+
+<B>pluto</B> is told of RSA public keys via <B>whack</B> commands.
+If the connection is Opportunistic, and no RSA public key is known,
+<B>pluto</B> will attempt to fetch RSA keys using the Domain Name System.
+<A NAME="lbAH">&nbsp;</A>
+<H3>Setting up <B>KLIPS</B> for <B>pluto</B></H3>
+
+<P>
+
+The most basic network topology that <B>pluto</B> supports has two security
+gateways negotiating on behalf of client subnets. The diagram of RGB's
+testbed is a good example (see <I>klips/doc/rgb_setup.txt</I>).
+<P>
+
+The file <I>INSTALL</I> in the base directory of this distribution
+explains how to start setting up the whole system, including <B>KLIPS</B>.
+<P>
+
+Make sure that the security gateways have routes to each other. This
+is usually covered by the default route, but may require issuing
+<I><A HREF="route.8.html">route</A></I>(8)
+
+commands. The route must go through a particular IP
+interface (we will assume it is <I>eth0</I>, but it need not be). The
+interface that connects the security gateway to its client must be a
+different one.
+<P>
+
+It is necessary to issue a
+<I><A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A></I>(8)
+
+command on each gateway. The required command is:
+<P>
+&nbsp;&nbsp;&nbsp;ipsec tncfg --attach&nbsp;--virtual&nbsp;ipsec0 --physical&nbsp;eth0
+<P>
+A command to set up the ipsec0 virtual interface will also need to be
+run. It will have the same parameters as the command used to set up
+the physical interface to which it has just been connected using
+<I><A HREF="ipsec_tncfg.8.html">ipsec_tncfg</A></I>(8).
+
+<A NAME="lbAI">&nbsp;</A>
+<H3>ipsec.secrets file</H3>
+
+<P>
+
+A <B>pluto</B> daemon and another IKE daemon (for example, another instance
+of <B>pluto</B>) must convince each other that they are who they are supposed
+to be before any negotiation can succeed. This authentication is
+accomplished by using either secrets that have been shared beforehand
+(manually) or by using RSA signatures. There are other techniques,
+but they have not been implemented in <B>pluto</B>.
+<P>
+
+The file <I>/etc/ipsec.secrets</I> is used to keep preshared secret keys
+and RSA private keys for
+authentication with other IKE daemons. For debugging, there is an
+argument to the <B>pluto</B> command to use a different file.
+This file is described in
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5).
+
+<A NAME="lbAJ">&nbsp;</A>
+<H3>Running Pluto</H3>
+
+<P>
+
+To fire up the daemon, just type <B>pluto</B> (be sure to be running as
+the superuser).
+The default IKE port number is 500, the UDP port assigned by IANA for IKE Daemons.
+<B>pluto</B> must be run by the superuser to be able to use the UDP 500 port.
+<P>
+
+<B>pluto</B> attempts to create a lockfile with the name
+<I>/var/run/pluto.pid</I>. If the lockfile cannot be created,
+<B>pluto</B> exits - this prevents multiple <B>pluto</B>s from
+competing Any ``leftover'' lockfile must be removed before
+<B>pluto</B> will run. <B>pluto</B> writes its pid into this file so
+that scripts can find it. This lock will not function properly if it
+is on an NFS volume (but sharing locks on multiple machines doesn't
+make sense anyway).
+<P>
+
+<B>pluto</B> then forks and the parent exits. This is the conventional
+``daemon fork''. It can make debugging awkward, so there is an option
+to suppress this fork.
+<P>
+
+All logging, including diagnostics, is sent to
+<I><A HREF="syslog.3.html">syslog</A></I>(3)
+
+with facility=authpriv;
+it decides where to put these messages (possibly in /var/log/secure).
+Since this too can make debugging awkward, there is an option to
+steer logging to stderr.
+<P>
+
+If the <B>--perpeerlog</B> option is given, then pluto will open
+a log file per connection. By default, this is in /var/log/pluto/peer,
+in a subdirectory formed by turning all dot (.) [IPv4} or colon (:)
+[IPv6] into slashes (/).
+<P>
+
+The base directory can be changed with the <B>--perpeerlogbase</B>.
+<P>
+
+Once <B>pluto</B> is started, it waits for requests from <B>whack</B>.
+<A NAME="lbAK">&nbsp;</A>
+<H3>Pluto's Internal State</H3>
+
+<P>
+
+To understand how to use <B>pluto</B>, it is helpful to understand a little
+about its internal state. Furthermore, the terminology is needed to decipher
+some of the diagnostic messages.
+<P>
+
+The <I>(potential) connection</I> database describes attributes of a
+connection. These include the IP addresses of the hosts and client
+subnets and the security characteristics desired. <B>pluto</B>
+requires this information (simply called a connection) before it can
+respond to a request to build an SA. Each connection is given a name
+when it is created, and all references are made using this name.
+<P>
+
+During the IKE exchange to build an SA, the information about the
+negotiation is represented in a <I>state object</I>. Each state object
+reflects how far the negotiation has reached. Once the negotiation is
+complete and the SA established, the state object remains to represent
+the SA. When the SA is terminated, the state object is discarded.
+Each State object is given a serial number and this is used to refer
+to the state objects in logged messages.
+<P>
+
+Each state object corresponds to a connection and can be thought of
+as an instantiation of that connection.
+At any particular time, there may be any number of state objects
+corresponding to a particular connection.
+Often there is one representing an ISAKMP SA and another representing
+an IPsec SA.
+<P>
+
+<B>KLIPS</B> hooks into the routing code in a LINUX kernel.
+Traffic to be processed by an IPsec SA must be directed through
+<B>KLIPS</B> by routing commands. Furthermore, the processing to be
+done is specified by <I>ipsec <A HREF="eroute.8.html">eroute</A>(8)</I> commands.
+<B>pluto</B> takes the responsibility of managing both of these special
+kinds of routes.
+<P>
+
+Each connection may be routed, and must be while it has an IPsec SA.
+The connection specifies the characteristics of the route: the
+interface on this machine, the ``gateway'' (the nexthop),
+and the peer's client subnet. Two
+connections may not be simultaneously routed if they are for the same
+peer's client subnet but use different interfaces or gateways
+(<B>pluto</B>'s logic does not reflect any advanced routing capabilities).
+<P>
+
+Each eroute is associated with the state object for an IPsec SA
+because it has the particular characteristics of the SA.
+Two eroutes conflict if they specify the identical local
+and remote clients (unlike for routes, the local clients are
+taken into account).
+<P>
+
+When <B>pluto</B> needs to install a route for a connection,
+it must make sure that no conflicting route is in use. If another
+connection has a conflicting route, that route will be taken down, as long
+as there is no IPsec SA instantiating that connection.
+If there is such an IPsec SA, the attempt to install a route will fail.
+<P>
+
+There is an exception. If <B>pluto</B>, as Responder, needs to install
+a route to a fixed client subnet for a connection, and there is
+already a conflicting route, then the SAs using the route are deleted
+to make room for the new SAs. The rationale is that the new
+connection is probably more current. The need for this usually is a
+product of Road Warrior connections (these are explained later; they
+cannot be used to initiate).
+<P>
+
+When <B>pluto</B> needs to install an eroute for an IPsec SA (for a
+state object), first the state object's connection must be routed (if
+this cannot be done, the eroute and SA will not be installed).
+If a conflicting eroute is already in place for another connection,
+the eroute and SA will not be installed (but note that the routing
+exception mentioned above may have already deleted potentially conflicting SAs).
+If another IPsec
+SA for the same connection already has an eroute, all its outgoing traffic
+is taken over by the new eroute. The incoming traffic will still be
+processed. This characteristic is exploited during rekeying.
+<P>
+
+All of these routing characteristics are expected change when
+<B>KLIPS</B> is modified to use the firewall hooks in the LINUX 2.4.x
+kernel.
+<A NAME="lbAL">&nbsp;</A>
+<H3>Using Whack</H3>
+
+<P>
+
+<B>whack</B> is used to command a running <B>pluto</B>.
+<B>whack</B> uses a UNIX domain socket to speak to <B>pluto</B>
+(by default, <I>/var/pluto.ctl</I>).
+<P>
+
+<B>whack</B> has an intricate argument syntax.
+This syntax allows many different functions to be specified.
+The help form shows the usage or version information.
+The connection form gives <B>pluto</B> a description of a potential connection.
+The public key form informs <B>pluto</B> of the RSA public key for a potential peer.
+The delete form deletes a connection description and all SAs corresponding
+to it.
+The listen form tells <B>pluto</B> to start or stop listening on the public interfaces
+for IKE requests from peers.
+The route form tells <B>pluto</B> to set up routing for a connection;
+the unroute form undoes this.
+The initiate form tells <B>pluto</B> to negotiate an SA corresponding to a connection.
+The terminate form tells <B>pluto</B> to remove all SAs corresponding to a connection,
+including those being negotiated.
+The status form displays the <B>pluto</B>'s internal state.
+The debug form tells <B>pluto</B> to change the selection of debugging output
+``on the fly''. The shutdown form tells
+<B>pluto</B> to shut down, deleting all SAs.
+<P>
+
+Most options are specific to one of the forms, and will be described
+with that form. There are three options that apply to all forms.
+<DL COMPACT>
+<DT><B>--ctlbase</B>&nbsp;<I>path</I><DD>
+<I>path</I>.ctl is used as the UNIX domain socket for talking
+to <B>pluto</B>.
+This option facilitates debugging.
+<DT><B>--optionsfrom</B>&nbsp;<I>filename</I><DD>
+adds the contents of the file to the argument list.
+<DT><B>--label</B>&nbsp;<I>string</I><DD>
+adds the string to all error messages generated by <B>whack</B>.
+</DL>
+<P>
+
+The help form of <B>whack</B> is self-explanatory.
+<DL COMPACT>
+<DT><B>--help</B><DD>
+display the usage message.
+<DT><B>--version</B><DD>
+display the version of <B>whack</B>.
+</DL>
+<P>
+
+The connection form describes a potential connection to <B>pluto</B>.
+<B>pluto</B> needs to know what connections can and should be negotiated.
+When <B>pluto</B> is the initiator, it needs to know what to propose.
+When <B>pluto</B> is the responder, it needs to know enough to decide whether
+is is willing to set up the proposed connection.
+<P>
+
+The description of a potential connection can specify a large number
+of details. Each connection has a unique name. This name will appear
+in a updown shell command, so it should not contain punctuation
+that would make the command ill-formed.
+<DL COMPACT>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The topology of
+a connection is symmetric, so to save space here is half a picture:
+<P>
+&nbsp;&nbsp;&nbsp;client_subnet&lt;--&gt;host:ikeport&lt;--&gt;nexthop&lt;---
+<P>
+A similar trick is used in the flags. The same flag names are used for
+both ends. Those before the <B>--to</B> flag describe the left side
+and those afterwards describe the right side. When <B>pluto</B> attempts
+to use the connection, it decides whether it is the left side or the right
+side of the connection, based on the IP numbers of its interfaces.
+<DL COMPACT>
+<DT><B>--id</B>&nbsp;<I>id</I><DD>
+the identity of the end. Currently, this can be an IP address (specified
+as dotted quad or as a Fully Qualified Domain Name, which will be resolved
+immediately) or as a Fully Qualified Domain Name itself (prefixed by ``@''
+to signify that it should not be resolved), or as <A HREF="mailto:user@FQDN">user@FQDN</A>, or as the
+magic value <B>%myid</B>.
+<B>Pluto</B> only authenticates the identity, and does not use it for
+addressing, so, for example, an IP address need not be the one to which
+packets are to be sent. If the option is absent, the
+identity defaults to the IP address specified by <B>--host</B>.
+<B>%myid</B> allows the identity to be separately specified (by the <B>pluto</B> or <B>whack</B> option <B>--myid</B>
+or by the <B><A HREF="ipsec.conf.5.html">ipsec.conf</A></B>(5) <B>config setup</B> parameter myid).
+Otherwise, <B>pluto</B> tries to guess what <B>%myid</B> should stand for:
+the IP address of <B>%defaultroute</B>, if it is supported by a suitable TXT record in the reverse domain for that IP address,
+or the system's hostname, if it is supported by a suitable TXT record in its forward domain.
+
+<DT><B>--host</B>&nbsp;<I>ip-address</I><DD>
+<DT><B>--host</B>&nbsp;<B>%any</B><DD>
+<DT><B>--host</B>&nbsp;<B>%opportunistic</B><DD>
+the IP address of the end (generally the public interface).
+If <B>pluto</B> is to act as a responder
+for IKE negotiations initiated from unknown IP addresses (the
+``Road Warrior'' case), the
+IP address should be specified as <B>%any</B> (currently,
+the obsolete notation <B>0.0.0.0</B> is also accepted for this).
+If <B>pluto</B> is to opportunistically initiate the connection,
+use <B>%opportunistic</B>
+<DT><B>--ikeport</B>&nbsp;<I>port-number</I><DD>
+the UDP port that IKE listens to on that host. The default is 500.
+(<B>pluto</B> on this machine uses the port specified by its own command
+line argument, so this only affects where <B>pluto</B> sends messages.)
+<DT><B>--nexthop</B>&nbsp;<I>ip-address</I><DD>
+where to route packets for the peer's client (presumably for the peer too,
+but it will not be used for this).
+When <B>pluto</B> installs an IPsec SA, it issues a route command.
+It uses the nexthop as the gateway.
+The default is the peer's IP address (this can be explicitly written as
+<B>%direct</B>; the obsolete notation <B>0.0.0.0</B> is accepted).
+This option is necessary if <B>pluto</B>'s host's interface used for sending
+packets to the peer is neither point-to-point nor directly connected to the
+peer.
+<DT><B>--client</B>&nbsp;<I>subnet</I><DD>
+the subnet for which the IPsec traffic will be destined. If not specified,
+the host will be the client.
+The subnet can be specified in any of the forms supported by <I><A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A></I>(3).
+The general form is <I>address</I>/<I>mask</I>. The <I>address</I> can be either
+a domain name or four decimal numbers (specifying octets) separated by dots.
+The most convenient form of the <I>mask</I> is a decimal integer, specifying
+the number of leading one bits in the mask. So, for example, 10.0.0.0/8
+would specify the class A network ``Net 10''.
+<DT><B>--dnskeyondemand]</B><DD>
+specifies that when an RSA public key is needed to authenticate this
+host, and it isn't already known, fetch it from DNS.
+<DT><B>--updown</B>&nbsp;<I>updown</I><DD>
+specifies an external shell command to be run whenever <B>pluto</B>
+brings up or down a connection.
+The script is used to build a shell command, so it may contain positional
+parameters, but ought not to have punctuation that would cause the
+resulting command to be ill-formed.
+The default is <I>ipsec _updown</I>.
+<DT><B>--to</B><DD>
+separates the specification of the left and right ends of the connection.
+</DL>
+<P>
+
+The potential connection description also specifies characteristics of
+rekeying and security.
+<DL COMPACT>
+<DT><B>--psk</B><DD>
+Propose and allow preshared secret authentication for IKE peers. This authentication
+requires that each side use the same secret. May be combined with <B>--rsasig</B>;
+at least one must be specified.
+<DT><B>--rsasig</B><DD>
+Propose and allow RSA signatures for authentication of IKE peers. This authentication
+requires that each side have have a private key of its own and know the
+public key of its peer. May be combined with <B>--psk</B>;
+at least one must be specified.
+<DT><B>--encrypt</B><DD>
+All proposed or accepted IPsec SAs will include non-null ESP.
+The actual choices of transforms are wired into <B>pluto</B>.
+<DT><B>--authenticate</B><DD>
+All proposed IPsec SAs will include AH.
+All accepted IPsec SAs will include AH or ESP with authentication.
+The actual choices of transforms are wired into <B>pluto</B>.
+Note that this has nothing to do with IKE authentication.
+<DT><B>--compress</B><DD>
+All proposed IPsec SAs will include IPCOMP (compression).
+This will be ignored if KLIPS is not configured with IPCOMP support.
+<DT><B>--tunnel</B><DD>
+the IPsec SA should use tunneling. Implicit if the SA is for clients.
+Must only be used with <B>--authenticate</B> or <B>--encrypt</B>.
+<DT><B>--ipv4</B><DD>
+The host addresses will be interpreted as IPv4 addresses. This is the
+default. Note that for a connection, all host addresses must be of
+the same Address Family (IPv4 and IPv6 use different Address Families).
+<DT><B>--ipv6</B><DD>
+The host addresses (including nexthop) will be interpreted as IPv6 addresses.
+Note that for a connection, all host addresses must be of
+the same Address Family (IPv4 and IPv6 use different Address Families).
+<DT><B>--tunnelipv4</B><DD>
+The client addresses will be interpreted as IPv4 addresses. The default is
+to match what the host will be. This does not imply <B>--tunnel</B> so the
+flag can be safely used when no tunnel is actually specified.
+Note that for a connection, all tunnel addresses must be of the same
+Address Family.
+<DT><B>--tunnelipv6</B><DD>
+The client addresses will be interpreted as IPv6 addresses. The default is
+to match what the host will be. This does not imply <B>--tunnel</B> so the
+flag can be safely used when no tunnel is actually specified.
+Note that for a connection, all tunnel addresses must be of the same
+Address Family.
+<DT><B>--pfs</B><DD>
+There should be Perfect Forward Secrecy - new keying material will
+be generated for each IPsec SA rather than being derived from the ISAKMP
+SA keying material.
+Since the group to be used cannot be negotiated (a dubious feature of the
+standard), <B>pluto</B> will propose the same group that was used during Phase 1.
+We don't implement a stronger form of PFS which would require that the
+ISAKMP SA be deleted after the IPSEC SA is negotiated.
+<DT><B>--disablearrivalcheck</B><DD>
+If the connection is a tunnel, allow packets arriving through the tunnel
+to have any source and destination addresses.
+</DL>
+<P>
+
+If none of the <B>--encrypt</B>, <B>--authenticate</B>, <B>--compress</B>,
+or <B>--pfs</B> flags is given, the initiating the connection will
+only build an ISAKMP SA. For such a connection, client subnets have
+no meaning and must not be specified.
+<P>
+
+More work is needed to allow for flexible policies. Currently
+policy is hardwired in the source file spdb.c. The ISAKMP SAs may use
+Oakley groups MODP1024 and MODP1536; 3DES encryption; SHA1-96
+and MD5-96 authentication. The IPsec SAs may use 3DES and
+MD5-96 or SHA1-96 for ESP, or just MD5-96 or SHA1-96 for AH.
+IPCOMP Compression is always Deflate.
+<DL COMPACT>
+<DT><B>--ikelifetime</B>&nbsp;<I>seconds</I><DD>
+how long <B>pluto</B> will propose that an ISAKMP SA be allowed to live.
+The default is 3600 (one hour) and the maximum is 28800 (8 hours).
+This option will not affect what is accepted.
+<B>pluto</B> will reject proposals that exceed the maximum.
+<DT><B>--ipseclifetime</B>&nbsp;<I>seconds</I><DD>
+how long <B>pluto</B> will propose that an IPsec SA be allowed to live.
+The default is 28800 (eight hours) and the maximum is 86400 (one day).
+This option will not affect what is accepted.
+<B>pluto</B> will reject proposals that exceed the maximum.
+<DT><B>--rekeymargin</B>&nbsp;<I>seconds</I><DD>
+how long before an SA's expiration should <B>pluto</B> try to negotiate
+a replacement SA. This will only happen if <B>pluto</B> was the initiator.
+The default is 540 (nine minutes).
+<DT><B>--rekeyfuzz</B>&nbsp;<I>percentage</I><DD>
+maximum size of random component to add to rekeymargin, expressed as
+a percentage of rekeymargin. <B>pluto</B> will select a delay uniformly
+distributed within this range. By default, the percentage will be 100.
+If greater determinism is desired, specify 0. It may be appropriate
+for the percentage to be much larger than 100.
+<DT><B>--keyingtries</B>&nbsp;<I>count</I><DD>
+how many times <B>pluto</B> should try to negotiate an SA,
+either for the first time or for rekeying.
+A value of 0 is interpreted as a very large number: never give up.
+The default is three.
+<DT><B>--dontrekey</B><DD>
+A misnomer.
+Only rekey a connection if we were the Initiator and there was recent
+traffic on the existing connection.
+This applies to Phase 1 and Phase 2.
+This is currently the only automatic way for a connection to terminate.
+It may be useful with Road Warrior or Opportunistic connections.
+<BR>
+
+Since SA lifetime negotiation is take-it-or-leave it, a Responder
+normally uses the shorter of the negotiated or the configured lifetime.
+This only works because if the lifetime is shorter than negotiated,
+the Responder will rekey in time so that everything works.
+This interacts badly with <B>--dontrekey</B>. In this case,
+the Responder will end up rekeying to rectify a shortfall in an IPsec SA
+lifetime; for an ISAKMP SA, the Responder will accept the negotiated
+lifetime.
+<DT><B>--delete</B><DD>
+when used in the connection form, it causes any previous connection
+with this name to be deleted before this one is added. Unlike a
+normal delete, no diagnostic is produced if there was no previous
+connection to delete. Any routing in place for the connection is undone.
+</DL>
+<P>
+
+The delete form deletes a named connection description and any
+SAs established or negotiations initiated using this connection.
+Any routing in place for the connection is undone.
+<DL COMPACT>
+<DT><B>--delete</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The deletestate form deletes the state object with the specified serial number.
+This is useful for selectively deleting instances of connections.
+<DL COMPACT>
+<DT><B>--deletestate</B>&nbsp;<I>state-number</I><DD>
+</DL>
+<P>
+
+The route form of the <B>whack</B> command tells <B>pluto</B> to set up
+routing for a connection.
+Although like a traditional route, it uses an ipsec device as a
+virtual interface.
+Once routing is set up, no packets will be
+sent ``in the clear'' to the peer's client specified in the connection.
+A TRAP shunt eroute will be installed; if outbound traffic is caught,
+Pluto will initiate the connection.
+An explicit <B>whack</B> route is not always needed: if it hasn't been
+done when an IPsec SA is being installed, one will be automatically attempted.
+<P>
+
+When a routing is attempted for a connection, there must not already
+be a routing for a different connection with the same subnet but different
+interface or destination, or if
+there is, it must not be being used by an IPsec SA. Otherwise the
+attempt will fail.
+<DL COMPACT>
+<DT><B>--route</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The unroute form of the <B>whack</B> command tells <B>pluto</B> to undo
+a routing. <B>pluto</B> will refuse if an IPsec SA is using the connection.
+If another connection is sharing the same routing, it will be left in place.
+Without a routing, packets will be sent without encryption or authentication.
+<DL COMPACT>
+<DT><B>--unroute</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The initiate form tells <B>pluto</B> to initiate a negotiation with another
+<B>pluto</B> (or other IKE daemon) according to the named connection.
+Initiation requires a route that <B>--route</B> would provide;
+if none is in place at the time an IPsec SA is being installed,
+<B>pluto</B> attempts to set one up.
+<DL COMPACT>
+<DT><B>--initiate</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+<DT><B>--asynchronous<DD>
+</DL>
+<P>
+
+The initiate form of the whack</B> command will relay back from
+<B>pluto</B> status information via the UNIX domain socket (unless
+--asynchronous is specified). The status information is meant to
+look a bit like that from <B>FTP</B>. Currently <B>whack</B> simply
+copies this to stderr. When the request is finished (eg. the SAs are
+established or <B>pluto</B> gives up), <B>pluto</B> closes the channel,
+causing <B>whack</B> to terminate.
+<P>
+
+The opportunistic initiate form is mainly used for debugging.
+<DL COMPACT>
+<DT><B>--tunnelipv4</B><DD>
+<DT><B>--tunnelipv6</B><DD>
+<DT><B>--oppohere</B>&nbsp;<I>ip-address</I><DD>
+<DT><B>--oppothere</B>&nbsp;<I>ip-address</I><DD>
+</DL>
+<P>
+
+This will cause <B>pluto</B> to attempt to opportunistically initiate a
+connection from here to the there, even if a previous attempt
+had been made.
+The whack log will show the progress of this attempt.
+<P>
+
+The terminate form tells <B>pluto</B> to delete any SAs that use the specified
+connection and to stop any negotiations in process.
+It does not prevent new negotiations from starting (the delete form
+has this effect).
+<DL COMPACT>
+<DT><B>--terminate</B><DD>
+<DT><B>--name</B>&nbsp;<I>connection-name</I><DD>
+</DL>
+<P>
+
+The public key for informs <B>pluto</B> of the RSA public key for a potential peer.
+Private keys must be kept secret, so they are kept in
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5).
+
+<DL COMPACT>
+<DT><B>--keyid&nbsp;</B><I>id</I><DD>
+specififies the identity of the peer for which a public key should be used.
+Its form is identical to the identity in the connection.
+If no public key is specified, <B>pluto</B> attempts to find KEY records
+from DNS for the id (if a FQDN) or through reverse lookup (if an IP address).
+Note that there several interesting ways in which this is not secure.
+<DT><B>--addkey</B><DD>
+specifies that the new key is added to the collection; otherwise the
+new key replaces any old ones.
+<DT><B>--pubkeyrsa&nbsp;</B><I>key</I><DD>
+specifies the value of the RSA public key. It is a sequence of bytes
+as described in RFC 2537 ``RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)''.
+It is denoted in a way suitable for <I><A HREF="ipsec_ttodata.3.html">ipsec_ttodata</A></I>(3).
+For example, a base 64 numeral starts with 0s.
+</DL>
+<P>
+
+The listen form tells <B>pluto</B> to start listening for IKE requests
+on its public interfaces. To avoid race conditions, it is normal to
+load the appropriate connections into <B>pluto</B> before allowing it
+to listen. If <B>pluto</B> isn't listening, it is pointless to
+initiate negotiations, so it will refuse requests to do so. Whenever
+the listen form is used, <B>pluto</B> looks for public interfaces and
+will notice when new ones have been added and when old ones have been
+removed. This is also the trigger for <B>pluto</B> to read the
+<I>ipsec.secrets</I> file. So listen may useful more than once.
+<DL COMPACT>
+<DT><B>--listen</B><DD>
+start listening for IKE traffic on public interfaces.
+<DT><B>--unlisten</B><DD>
+stop listening for IKE traffic on public interfaces.
+</DL>
+<P>
+
+The status form will display information about the internal state of
+<B>pluto</B>: information about each potential connection, about
+each state object, and about each shunt that <B>pluto</B> is managing
+without an associated connection.
+<DL COMPACT>
+<DT><B>--status</B><DD>
+</DL>
+<P>
+
+The shutdown form is the proper way to shut down <B>pluto</B>.
+It will tear down the SAs on this machine that <B>pluto</B> has negotiated.
+It does not inform its peers, so the SAs on their machines remain.
+<DL COMPACT>
+<DT><B>--shutdown</B><DD>
+</DL>
+<A NAME="lbAM">&nbsp;</A>
+<H3>Examples</H3>
+
+<P>
+
+It would be normal to start <B>pluto</B> in one of the system initialization
+scripts. It needs to be run by the superuser. Generally, no arguments are needed.
+To run in manually, the superuser can simply type
+<P>
+&nbsp;&nbsp;&nbsp;ipsec pluto
+<P>
+The command will immediately return, but a <B>pluto</B> process will be left
+running, waiting for requests from <B>whack</B> or a peer.
+<P>
+
+Using <B>whack</B>, several potential connections would be described:
+<DL COMPACT>
+<DT>
+
+&nbsp;&nbsp;&nbsp;ipsec whack --name&nbsp;silly
+--host&nbsp;127.0.0.1 --to --host&nbsp;127.0.0.2
+--ikelifetime&nbsp;900 --ipseclifetime&nbsp;800 --keyingtries&nbsp;3
+
+</DL>
+<P>
+
+<DD>Since this silly connection description specifies neither encryption,
+authentication, nor tunneling, it could only be used to establish
+an ISAKMP SA.
+<DL COMPACT>
+<DT>
+
+&nbsp;&nbsp;&nbsp;ipsec whack --name&nbsp;secret --host&nbsp;10.0.0.1 --client&nbsp;10.0.1.0/24
+--to --host&nbsp;10.0.0.2 --client&nbsp;10.0.2.0/24
+--encrypt
+
+</DL>
+<P>
+
+<DD>This is something that must be done on both sides. If the other
+side is <B>pluto</B>, the same <B>whack</B> command could be used on it
+(the command syntax is designed to not distinguish which end is ours).
+<P>
+
+Now that the connections are specified, <B>pluto</B> is ready to handle
+requests and replies via the public interfaces. We must tell it to discover
+those interfaces and start accepting messages from peers:
+<P>
+&nbsp;&nbsp;&nbsp;ipsec whack --listen
+<P>
+
+If we don't immediately wish to bring up a secure connection between
+the two clients, we might wish to prevent insecure traffic.
+The routing form asks <B>pluto</B> to cause the packets sent from
+our client to the peer's client to be routed through the ipsec0
+device; if there is no SA, they will be discarded:
+<P>
+&nbsp;&nbsp;&nbsp;ipsec whack --route secret
+<P>
+
+Finally, we are ready to get <B>pluto</B> to initiate negotiation
+for an IPsec SA (and implicitly, an ISAKMP SA):
+<P>
+&nbsp;&nbsp;&nbsp;ipsec whack --initiate&nbsp;--name&nbsp;secret
+<P>
+A small log of interesting events will appear on standard output
+(other logging is sent to syslog).
+<P>
+
+<B>whack</B> can also be used to terminate <B>pluto</B> cleanly, tearing down
+all SAs that it has negotiated.
+<P>
+&nbsp;&nbsp;&nbsp;ipsec whack --shutdown
+<P>
+Notification of any IPSEC SA deletion, but not ISAKMP SA deletion
+is sent to the peer. Unfortunately, such Notification is not reliable.
+Furthermore, <B>pluto</B> itself ignores Notifications.
+<A NAME="lbAN">&nbsp;</A>
+<H3>The updown command</H3>
+
+<P>
+
+Whenever <B>pluto</B> brings a connection up or down, it invokes
+the updown command. This command is specified using the <B>--updown</B>
+option. This allows for customized control over routing and firewall manipulation.
+<P>
+
+The updown is invoked for five different operations. Each of
+these operations can be for our client subnet or for our host itself.
+<DL COMPACT>
+<DT><B>prepare-host</B> or <B>prepare-client</B><DD>
+is run before bringing up a new connection if no other connection
+with the same clients is up. Generally, this is useful for deleting a
+route that might have been set up before <B>pluto</B> was run or
+perhaps by some agent not known to <B>pluto</B>.
+<DT><B>route-host</B> or <B>route-client</B><DD>
+is run when bringing up a connection for a new peer client subnet
+(even if <B>prepare-host</B> or <B>prepare-client</B> was run). The
+command should install a suitable route. Routing decisions are based
+only on the destination (peer's client) subnet address, unlike eroutes
+which discriminate based on source too.
+<DT><B>unroute-host</B> or <B>unroute-client</B><DD>
+is run when bringing down the last connection for a particular peer
+client subnet. It should undo what the <B>route-host</B> or <B>route-client</B>
+did.
+<DT><B>up-host</B> or <B>up-client</B><DD>
+is run when bringing up a tunnel eroute with a pair of client subnets
+that does not already have a tunnel eroute.
+This command should install firewall rules as appropriate.
+It is generally a good idea to allow IKE messages (UDP port 500)
+travel between the hosts.
+<DT><B>down-host</B> or <B>down-client</B><DD>
+is run when bringing down the eroute for a pair of client subnets.
+This command should delete firewall rules as appropriate. Note that
+there may remain some inbound IPsec SAs with these client subnets.
+</DL>
+<P>
+
+The script is passed a large number of environment variables to specify
+what needs to be done.
+<DL COMPACT>
+<DT><B>PLUTO_VERSION</B><DD>
+indicates what version of this interface is being used. This document
+describes version 1.1. This is upwardly compatible with version 1.0.
+<DT><B>PLUTO_VERB</B><DD>
+specifies the name of the operation to be performed
+(<B>prepare-host</B>,r <B>prepare-client</B>,
+<B>up-host</B>, <B>up-client</B>,
+<B>down-host</B>, or <B>down-client</B>). If the address family for
+security gateway to security gateway communications is IPv6, then
+a suffix of -v6 is added to the verb.
+<DT><B>PLUTO_CONNECTION</B><DD>
+is the name of the connection for which we are routing.
+<DT><B>PLUTO_NEXT_HOP</B><DD>
+is the next hop to which packets bound for the peer must be sent.
+<DT><B>PLUTO_INTERFACE</B><DD>
+is the name of the ipsec interface to be used.
+<DT><B>PLUTO_ME</B><DD>
+is the IP address of our host.
+<DT><B>PLUTO_MY_CLIENT</B><DD>
+is the IP address / count of our client subnet.
+If the client is just the host, this will be the host's own IP address / max
+(where max is 32 for IPv4 and 128 for IPv6).
+<DT><B>PLUTO_MY_CLIENT_NET</B><DD>
+is the IP address of our client net.
+If the client is just the host, this will be the host's own IP address.
+<DT><B>PLUTO_MY_CLIENT_MASK</B><DD>
+is the mask for our client net.
+If the client is just the host, this will be 255.255.255.255.
+<DT><B>PLUTO_PEER</B><DD>
+is the IP address of our peer.
+<DT><B>PLUTO_PEER_CLIENT</B><DD>
+is the IP address / count of the peer's client subnet.
+If the client is just the peer, this will be the peer's own IP address / max
+(where max is 32 for IPv4 and 128 for IPv6).
+<DT><B>PLUTO_PEER_CLIENT_NET</B><DD>
+is the IP address of the peer's client net.
+If the client is just the peer, this will be the peer's own IP address.
+<DT><B>PLUTO_PEER_CLIENT_MASK</B><DD>
+is the mask for the peer's client net.
+If the client is just the peer, this will be 255.255.255.255.
+</DL>
+<P>
+
+All output sent by the script to stderr or stdout is logged. The
+script should return an exit status of 0 if and only if it succeeds.
+<P>
+
+<B>Pluto</B> waits for the script to finish and will not do any other
+processing while it is waiting.
+The script may assume that <B>pluto</B> will not change anything
+while the script runs.
+The script should avoid doing anything that takes much time and it
+should not issue any command that requires processing by <B>pluto</B>.
+Either of these activities could be performed by a background
+subprocess of the script.
+<A NAME="lbAO">&nbsp;</A>
+<H3>Rekeying</H3>
+
+<P>
+
+When an SA that was initiated by <B>pluto</B> has only a bit of
+lifetime left,
+<B>pluto</B> will initiate the creation of a new SA. This applies to
+ISAKMP and IPsec SAs.
+The rekeying will be initiated when the SA's remaining lifetime is
+less than the rekeymargin plus a random percentage, between 0 and
+rekeyfuzz, of the rekeymargin.
+<P>
+
+Similarly, when an SA that was initiated by the peer has only a bit of
+lifetime left, <B>pluto</B> will try to initiate the creation of a
+replacement.
+To give preference to the initiator, this rekeying will only be initiated
+when the SA's remaining lifetime is half of rekeymargin.
+If rekeying is done by the responder, the roles will be reversed: the
+responder for the old SA will be the initiator for the replacement.
+The former initiator might also initiate rekeying, so there may
+be redundant SAs created.
+To avoid these complications, make sure that rekeymargin is generous.
+<P>
+
+One risk of having the former responder initiate is that perhaps
+none of its proposals is acceptable to the former initiator
+(they have not been used in a successful negotiation).
+To reduce the chances of this happening, and to prevent loss of security,
+the policy settings are taken from the old SA (this is the case even if
+the former initiator is initiating).
+These may be stricter than those of the connection.
+<P>
+
+<B>pluto</B> will not rekey an SA if that SA is not the most recent of its
+type (IPsec or ISAKMP) for its potential connection.
+This avoids creating redundant SAs.
+<P>
+
+The random component in the rekeying time (rekeyfuzz) is intended to
+make certain pathological patterns of rekeying unstable. If both
+sides decide to rekey at the same time, twice as many SAs as necessary
+are created. This could become a stable pattern without the
+randomness.
+<P>
+
+Another more important case occurs when a security gateway has SAs
+with many other security gateways. Each of these connections might
+need to be rekeyed at the same time. This would cause a high peek
+requirement for resources (network bandwidth, CPU time, entropy for
+random numbers). The rekeyfuzz can be used to stagger the rekeying
+times.
+<P>
+
+Once a new set of SAs has been negotiated, <B>pluto</B> will never send
+traffic on a superseded one. Traffic will be accepted on an old SA
+until it expires.
+<A NAME="lbAP">&nbsp;</A>
+<H3>Selecting a Connection When Responding: Road Warrior Support</H3>
+
+<P>
+
+When <B>pluto</B> receives an initial Main Mode message, it needs to
+decide which connection this message is for. It picks based solely on
+the source and destination IP addresses of the message. There might
+be several connections with suitable IP addresses, in which case one
+of them is arbitrarily chosen. (The ISAKMP SA proposal contained in
+the message could be taken into account, but it is not.)
+<P>
+
+The ISAKMP SA is negotiated before the parties pass further
+identifying information, so all ISAKMP SA characteristics specified in
+the connection description should be the same for every connection
+with the same two host IP addresses. At the moment, the only
+characteristic that might differ is authentication method.
+<P>
+
+Up to this point,
+all configuring has presumed that the IP addresses
+are known to all parties ahead of time. This will not work
+when either end is mobile (or assigned a dynamic IP address for other
+reasons). We call this situation ``Road Warrior''. It is fairly tricky
+and has some important limitations, most of which are features of
+the IKE protocol.
+<P>
+
+Only the initiator may be mobile:
+the initiator may have an IP number unknown to the responder. When
+the responder doesn't recognize the IP address on the first Main Mode
+packet, it looks for a connection with itself as one end and <B>%any</B>
+as the other.
+If it cannot find one, it refuses to negotiate. If it
+does find one, it creates a temporary connection that is a duplicate
+except with the <B>%any</B> replaced by the source IP address from the
+packet; if there was no identity specified for the peer, the new IP
+address will be used.
+<P>
+
+When <B>pluto</B> is using one of these temporary connections and
+needs to find the preshared secret or RSA private key in <I>ipsec.secrets</I>,
+and and the connection specified no identity for the peer, <B>%any</B>
+is used as its identity. After all, the real IP address was apparently
+unknown to the configuration, so it is unreasonable to require that
+it be used in this table.
+<P>
+
+Part way into the Phase 1 (Main Mode) negotiation using one of these
+temporary connection descriptions, <B>pluto</B> will be receive an
+Identity Payload. At this point, <B>pluto</B> checks for a more
+appropriate connection, one with an identity for the peer that matches
+the payload but which would use the same keys so-far used for
+authentication. If it finds one, it will switch to using this better
+connection (or a temporary derived from this, if it has <B>%any</B>
+for the peer's IP address). It may even turn out that no connection
+matches the newly discovered identity, including the current connection;
+if so, <B>pluto</B> terminates negotiation.
+<P>
+
+Unfortunately, if preshared secret authentication is being used, the
+Identity Payload is encrypted using this secret, so the secret must be
+selected by the responder without knowing this payload. This
+limits there to being at most one preshared secret for all Road Warrior
+systems connecting to a host. RSA Signature authentications does not
+require that the responder know how to select the initiator's public key
+until after the initiator's Identity Payload is decoded (using the
+responder's private key, so that must be preselected).
+<P>
+
+When <B>pluto</B> is responding to a Quick Mode negotiation via one of these
+temporary connection descriptions, it may well find that the subnets
+specified by the initiator don't match those in the temporary
+connection description. If so, it will look for a connection with
+matching subnets, its own host address, a peer address of <B>%any</B>
+and matching identities.
+If it finds one, a new temporary connection is derived from this one
+and used for the Quick Mode negotiation of IPsec SAs. If it does not
+find one, <B>pluto</B> terminates negotiation.
+<P>
+
+Be sure to specify an appropriate nexthop for the responder
+to send a message to the initiator: <B>pluto</B> has no way of guessing
+it (if forwarding isn't required, use an explicit <B>%direct</B> as the nexthop
+and the IP address of the initiator will be filled in; the obsolete
+notation <B>0.0.0.0</B> is still accepted).
+<P>
+
+<B>pluto</B> has no special provision for the initiator side. The current
+(possibly dynamic) IP address and nexthop must be used in defining
+connections. These must be
+properly configured each time the initiator's IP address changes.
+<B>pluto</B> has no mechanism to do this automatically.
+<P>
+
+Although we call this Road Warrior Support, it could also be used to
+support encrypted connections with anonymous initiators. The
+responder's organization could announce the preshared secret that would be used
+with unrecognized initiators and let anyone connect. Of course the initiator's
+identity would not be authenticated.
+<P>
+
+If any Road Warrior connections are supported, <B>pluto</B> cannot
+reject an exchange initiated by an unknown host until it has
+determined that the secret is not shared or the signature is invalid.
+This must await the
+third Main Mode message from the initiator. If no Road Warrior
+connection is supported, the first message from an unknown source
+would be rejected. This has implications for ease of debugging
+configurations and for denial of service attacks.
+<P>
+
+Although a Road Warrior connection must be initiated by the mobile
+side, the other side can and will rekey using the temporary connection
+it has created. If the Road Warrior wishes to be able to disconnect,
+it is probably wise to set <B>--keyingtries</B> to 1 in the
+connection on the non-mobile side to prevent it trying to rekey the
+connection. Unfortunately, there is no mechanism to unroute the
+connection automatically.
+<A NAME="lbAQ">&nbsp;</A>
+<H3>Debugging</H3>
+
+<P>
+
+<B>pluto</B> accepts several optional arguments, useful mostly for debugging.
+Except for <B>--interface</B>, each should appear at most once.
+<DL COMPACT>
+<DT><B>--interface</B> <I>interfacename</I><DD>
+specifies that the named real public network interface should be considered.
+The interface name specified should not be <B>ipsec</B><I>N</I>.
+If the option doesn't appear, all interfaces are considered.
+To specify several interfaces, use the option once for each.
+One use of this option is to specify which interface should be used
+when two or more share the same IP address.
+<DT><B>--ikeport</B> <I>port-number</I><DD>
+changes the UDP port that <B>pluto</B> will use
+(default, specified by IANA: 500)
+<DT><B>--ctlbase</B> <I>path</I><DD>
+basename for control files.
+<I>path</I>.ctl is the socket through which <B>whack</B> communicates with
+<B>pluto</B>.
+<I>path</I>.pid is the lockfile to prevent multiple <B>pluto</B> instances.
+The default is <I>/var/run/pluto</I>).
+<DT><B>--secretsfile</B> <I>file</I><DD>
+specifies the file for authentication secrets
+(default: <I>/etc/ipsec.secrets</I>).
+This name is subject to ``globbing'' as in <I><A HREF="sh.1.html">sh</A></I>(1),
+so every file with a matching name is processed.
+Quoting is generally needed to prevent the shell from doing the globbing.
+<DT><B>--adns</B> <I>pathname</I><DD>
+<DT><B>--lwdnsq</B> <I>pathname</I><DD>
+specifies where to find <B>pluto</B>'s helper program for asynchronous DNS lookup.
+<B>pluto</B> can be built to use one of two helper programs: <B>_pluto_adns</B>
+or <B>lwdnsq</B>. You must use the program for which it was built.
+By default, <B>pluto</B> will look for the program in
+<B>$IPSEC_DIR</B> (if that environment variable is defined) or, failing that,
+in the same directory as <B>pluto</B>.
+<DT><B>--nofork</B><DD>
+disable ``daemon fork'' (default is to fork). In addition, after the
+lock file and control socket are created, print the line ``Pluto
+initialized'' to standard out.
+<DT><B>--noklips</B><DD>
+don't actually implement negotiated IPsec SAs
+<DT><B>--uniqueids</B><DD>
+if this option has been selected, whenever a new ISAKMP SA is
+established, any connection with the same Peer ID but a different
+Peer IP address is unoriented (causing all its SAs to be deleted).
+This helps clean up dangling SAs when a connection is lost and
+then regained at another IP address.
+<DT><B>--stderrlog</B><DD>
+log goes to standard out {default is to use <I><A HREF="syslogd.8.html">syslogd</A></I>(8))
+</DL>
+<P>
+
+For example
+<DL COMPACT>
+<DT>pluto --secretsfile&nbsp;ipsec.secrets --ctlbase&nbsp;pluto.base --ikeport&nbsp;8500 --nofork --noklips --stderrlog<DD>
+</DL>
+<P>
+
+lets one test <B>pluto</B> without using the superuser account.
+<P>
+
+<B>pluto</B> is willing to produce a prodigious amount of debugging
+information. To do so, it must be compiled with -DDEBUG. There are
+several classes of debugging output, and <B>pluto</B> may be directed to
+produce a selection of them. All lines of
+debugging output are prefixed with ``|&nbsp;'' to distinguish them from error
+messages.
+<P>
+
+When <B>pluto</B> is invoked, it may be given arguments to specify
+which classes to output. The current options are:
+<DL COMPACT>
+<DT><B>--debug-raw</B><DD>
+show the raw bytes of messages
+<DT><B>--debug-crypt</B><DD>
+show the encryption and decryption of messages
+<DT><B>--debug-parsing</B><DD>
+show the structure of input messages
+<DT><B>--debug-emitting</B><DD>
+show the structure of output messages
+<DT><B>--debug-control</B><DD>
+show <B>pluto</B>'s decision making
+<DT><B>--debug-lifecycle</B><DD>
+[this option is temporary] log more detail of lifecycle of SAs
+<DT><B>--debug-klips</B><DD>
+show <B>pluto</B>'s interaction with <B>KLIPS</B>
+<DT><B>--debug-dns</B><DD>
+show <B>pluto</B>'s interaction with <B>DNS</B> for KEY and TXT records
+<DT><B>--debug-oppo</B><DD>
+show why <B>pluto</B> didn't find a suitable DNS TXT record to authorize opportunistic initiation
+<DT><B>--debug-all</B><DD>
+all of the above
+<DT><B>--debug-private</B><DD>
+allow debugging output with private keys.
+<DT><B>--debug-none</B><DD>
+none of the above
+</DL>
+<P>
+
+The debug form of the
+<B>whack</B> command will change the selection in a running
+<B>pluto</B>.
+If a connection name is specified, the flags are added whenever
+<B>pluto</B> has identified that it is dealing with that connection.
+Unfortunately, this is often part way into the operation being observed.
+<P>
+
+For example, to start a <B>pluto</B> with a display of the structure of input
+and output:
+<DL COMPACT>
+<DT><DD>
+pluto --debug-emitting --debug-parsing
+</DL>
+<P>
+
+To later change this <B>pluto</B> to only display raw bytes:
+<DL COMPACT>
+<DT><DD>
+whack --debug-raw
+</DL>
+<P>
+
+For testing, SSH's IKE test page is quite useful:
+<DL COMPACT>
+<DT><DD>
+<I><A HREF="http://isakmp-test.ssh.fi/">http://isakmp-test.ssh.fi/</A></I>
+</DL>
+<P>
+
+Hint: ISAKMP SAs are often kept alive by IKEs even after the IPsec SA
+is established. This allows future IPsec SA's to be negotiated
+directly. If one of the IKEs is restarted, the other may try to use
+the ISAKMP SA but the new IKE won't know about it. This can lead to
+much confusion. <B>pluto</B> is not yet smart enough to get out of such a
+mess.
+<A NAME="lbAR">&nbsp;</A>
+<H3>Pluto's Behaviour When Things Go Wrong</H3>
+
+<P>
+
+When <B>pluto</B> doesn't understand or accept a message, it just
+ignores the message. It is not yet capable of communicating the
+problem to the other IKE daemon (in the future it might use
+Notifications to accomplish this in many cases). It does log a diagnostic.
+<P>
+
+When <B>pluto</B> gets no response from a message, it resends the same
+message (a message will be sent at most three times). This is
+appropriate: UDP is unreliable.
+<P>
+
+When pluto gets a message that it has already seen, there are many
+cases when it notices and discards it. This too is appropriate for UDP.
+<P>
+
+Combine these three rules, and you can explain many apparently
+mysterious behaviours. In a <B>pluto</B> log, retrying isn't usually the
+interesting event. The critical thing is either earlier (<B>pluto</B>
+got a message which it didn't like and so ignored, so it was still
+awaiting an acceptable message and got impatient) or on the other
+system (<B>pluto</B> didn't send a reply because it wasn't happy with
+the previous message).
+<A NAME="lbAS">&nbsp;</A>
+<H3>Notes</H3>
+
+<P>
+
+If <B>pluto</B> is compiled without -DKLIPS, it negotiates Security
+Associations but never ask the kernel to put them in place and never
+makes routing changes. This allows <B>pluto</B> to be tested on systems
+without <B>KLIPS</B>, but makes it rather useless.
+<P>
+
+Each IPsec SA is assigned an SPI, a 32-bit number used to refer to the SA.
+The IKE protocol lets the destination of the SA choose the SPI.
+The range 0 to 0xFF is reserved for IANA.
+<B>Pluto</B> also avoids choosing an SPI in the range 0x100 to 0xFFF,
+leaving these SPIs free for manual keying.
+Remember that the peer, if not <B>pluto</B>, may well chose
+SPIs in this range.
+<A NAME="lbAT">&nbsp;</A>
+<H3>Policies</H3>
+
+<P>
+
+This catalogue of policies may be of use when trying to configure
+<B>Pluto</B> and another IKE implementation to interoperate.
+<P>
+
+In Phase 1, only Main Mode is supported. We are not sure that
+Aggressive Mode is secure. For one thing, it does not support
+identity protection. It may allow more severe Denial Of Service
+attacks.
+<P>
+
+No Informational Exchanges are supported. These are optional and
+since their delivery is not assured, they must not matter.
+It is the case that some IKE implementations won't interoperate
+without Informational Exchanges, but we feel they are broken.
+<P>
+
+No Informational Payloads are supported. These are optional, but
+useful. It is of concern that these payloads are not authenticated in
+Phase 1, nor in those Phase 2 messages authenticated with <A HREF="HASH.3.html">HASH</A>(3).
+<DL COMPACT>
+<DT>*<DD>
+Diffie Hellman Groups MODP 1024 and MODP 1536 (2 and 5)
+are supported.
+Group MODP768 (1) is not supported because it is too weak.
+<DT>*<DD>
+Host authetication can be done by RSA Signatures or Pre-Shared
+Secrets.
+<DT>*<DD>
+3DES CBC (Cypher Block Chaining mode) is the only encryption
+supported, both for ISAKMP SAs and IPSEC SAs.
+<DT>*<DD>
+MD5 and SHA1 hashing are supported for packet authentication in both
+kinds of SAs.
+<DT>*<DD>
+The ESP, AH, or AH plus ESP are supported. If, and only if, AH and
+ESP are combined, the ESP need not have its own authentication
+component. The selection is controlled by the --encrypt and
+--authenticate flags.
+<DT>*<DD>
+Each of these may be combined with IPCOMP Deflate compression,
+but only if the potential connection specifies compression and only
+if KLIPS is configured with IPCOMP support.
+<DT>*<DD>
+The IPSEC SAs may be tunnel or transport mode, where appropriate.
+The --tunnel flag controls this when <B>pluto</B> is initiating.
+<DT>*<DD>
+When responding to an ISAKMP SA proposal, the maximum acceptable
+lifetime is eight hours. The default is one hour. There is no
+minimum. The --ikelifetime flag controls this when <B>pluto</B>
+is initiating.
+<DT>*<DD>
+When responding to an IPSEC SA proposal, the maximum acceptable
+lifetime is one day. The default is eight hours. There is no
+minimum. The --ipseclifetime flag controls this when <B>pluto</B>
+is initiating.
+<DT>*<DD>
+PFS is acceptable, and will be proposed if the --pfs flag was
+specified. The DH group proposed will be the same as negotiated for
+Phase 1.
+</DL>
+<A NAME="lbAU">&nbsp;</A>
+<H2>SIGNALS</H2>
+
+<P>
+
+<B>Pluto</B> responds to <B>SIGHUP</B> by issuing a suggestion that ``<B>whack</B>
+--listen'' might have been intended.
+<P>
+
+<B>Pluto</B> exits when it recieves <B>SIGTERM</B>.
+<A NAME="lbAV">&nbsp;</A>
+<H2>EXIT STATUS</H2>
+
+<P>
+
+<B>pluto</B> normally forks a daemon process, so the exit status is
+normally a very preliminary result.
+<DL COMPACT>
+<DT>0<DD>
+means that all is OK so far.
+<DT>1<DD>
+means that something was wrong.
+<DT>10<DD>
+means that the lock file already exists.
+</DL>
+<P>
+
+If <B>whack</B> detects a problem, it will return an exit status of 1.
+If it received progress messages from <B>pluto</B>, it returns as status
+the value of the numeric prefix from the last such message
+that was not a message sent to syslog or a comment
+(but the prefix for success is treated as 0).
+Otherwise, the exit status is 0.
+<A NAME="lbAW">&nbsp;</A>
+<H2>FILES</H2>
+
+<I>/var/run/pluto.pid</I>
+<BR>
+
+<I>/var/run/pluto.ctl</I>
+<BR>
+
+<I>/etc/ipsec.secrets</I>
+<BR>
+
+<I>$IPSEC_LIBDIR/_pluto_adns</I>
+<BR>
+
+<I>$IPSEC_EXECDIR/lwdnsq</I>
+<BR>
+
+<I>/dev/urandom</I>
+<A NAME="lbAX">&nbsp;</A>
+<H2>ENVIRONMENT</H2>
+
+<I>IPSEC_LIBDIR</I>
+<BR>
+
+<I>IPSEC_EXECDIR</I>
+<BR>
+
+<I>IPSECmyid</I>
+<A NAME="lbAY">&nbsp;</A>
+<H2>SEE ALSO</H2>
+
+<P>
+
+The rest of the FreeS/WAN distribution, in particular <I><A HREF="ipsec.8.html">ipsec</A></I>(8).
+<P>
+
+<I><A HREF="ipsec_auto.8.html">ipsec_auto</A></I>(8) is designed to make using <B>pluto</B> more pleasant.
+Use it!
+<P>
+
+<I><A HREF="ipsec.secrets.5.html">ipsec.secrets</A></I>(5)
+
+describes the format of the secrets file.
+<P>
+
+<I><A HREF="ipsec_atoaddr.3.html">ipsec_atoaddr</A></I>(3), part of the FreeS/WAN distribution, describes the
+forms that IP addresses may take.
+<I><A HREF="ipsec_atosubnet.3.html">ipsec_atosubnet</A></I>(3), part of the FreeS/WAN distribution, describes the
+forms that subnet specifications.
+<P>
+
+For more information on IPsec, the mailing list, and the relevant
+documents, see:
+<DL COMPACT>
+<DT><DD>
+
+<I><A HREF="http://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html">http://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html</A></I>
+
+</DL>
+<P>
+
+At the time of writing, the most relevant IETF RFCs are:
+<DL COMPACT>
+<DT><DD>
+RFC2409 The Internet Key Exchange (IKE)
+<DT><DD>
+RFC2408 Internet Security Association and Key Management Protocol (ISAKMP)
+<DT><DD>
+RFC2407 The Internet IP Security Domain of Interpretation for ISAKMP
+</DL>
+<P>
+
+The FreeS/WAN web site &lt;<A HREF="htp://www.freeswan.org">htp://www.freeswan.org</A>&gt;
+and the mailing lists described there.
+<A NAME="lbAZ">&nbsp;</A>
+<H2>HISTORY</H2>
+
+This code is released under the GPL terms.
+See the accompanying file COPYING-2.0 for more details.
+The GPL does NOT apply to those pieces of code written by others
+which are included in this distribution, except as noted by the
+individual authors.
+<P>
+
+This software was originally written
+for the FreeS/WAN project
+&lt;<A HREF="http://www.freeswan.org">http://www.freeswan.org</A>&gt;
+by Angelos D. Keromytis
+(<A HREF="mailto:angelos@dsl.cis.upenn.edu">angelos@dsl.cis.upenn.edu</A>), in May/June 1997, in Athens, Greece.
+Thanks go to John Ioannidis for his help.
+<P>
+
+It is currently (2000)
+being developed and maintained by D. Hugh Redelmeier
+(<A HREF="mailto:hugh@mimosa.com">hugh@mimosa.com</A>), in Canada. The regulations of Greece and Canada
+allow us to make the code freely redistributable.
+<P>
+
+Kai Martius (<A HREF="mailto:admin@imib.med.tu-dresden.de">admin@imib.med.tu-dresden.de</A>) contributed the initial
+version of the code supporting PFS.
+<P>
+
+Richard Guy Briggs &lt;<A HREF="mailto:rgb@conscoop.ottawa.on.ca">rgb@conscoop.ottawa.on.ca</A>&gt; and Peter Onion
+&lt;<A HREF="mailto:ponion@srd.bt.co.uk">ponion@srd.bt.co.uk</A>&gt; added the PFKEY2 support.
+<P>
+
+We gratefully acknowledge that we use parts of Eric Young's <I>libdes</I>
+package; see <I>../libdes/COPYRIGHT</I>.
+<A NAME="lbBA">&nbsp;</A>
+<H2>BUGS</H2>
+
+<B>pluto</B>
+
+is a work-in-progress. It currently has many limitations.
+For example, it ignores notification messages that it receives, and
+it generates only Delete Notifications and those only for IPSEC SAs.
+<P>
+
+<B>pluto</B> does not support the Commit Flag.
+The Commit Flag is a bad feature of the IKE protocol.
+It isn't protected -- neither encrypted nor authenticated.
+A man in the middle could turn it on, leading to DoS.
+We just ignore it, with a warning.
+This should let us interoperate with
+implementations that insist on it, with minor damage.
+<P>
+
+<B>pluto</B> does not check that the SA returned by the Responder
+is actually one that was proposed. It only checks that the SA is
+acceptable. The difference is not large, but can show up in attributes
+such as SA lifetime.
+<P>
+
+There is no good way for a connection to be automatically terminated.
+This is a problem for Road Warrior and Opportunistic connections.
+The <B>--dontrekey</B> option does prevent the SAs from
+being rekeyed on expiry.
+Additonally, if a Road Warrior connection has a client subnet with a fixed IP
+address, a negotiation with that subnet will cause any other
+connection instantiations with that same subnet to be unoriented
+(deleted, in effect).
+See also the --uniqueids option for an extension of this.
+<P>
+
+When <B>pluto</B> sends a message to a peer that has disappeared,
+<B>pluto</B> receives incomplete information from the kernel, so it
+logs the unsatisfactory message ``some IKE message we sent has been
+rejected with ECONNREFUSED (kernel supplied no details)''. John
+Denker suggests that this command is useful for tracking down the
+source of these problems:
+<BR>
+
+<TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT>tcpdump -i eth0 icmp[0] != 8 and icmp[0] != 0<BR>
+<BR>
+
+Substitute your public interface for eth0 if it is different.
+<P>
+
+The word ``authenticate'' is used for two different features. We must
+authenticate each IKE peer to the other. This is an important task of
+Phase 1. Each packet must be authenticated, both in IKE and in IPsec,
+and the method for IPsec is negotiated as an AH SA or part of an ESP SA.
+Unfortunately, the protocol has no mechanism for authenticating the Phase 2
+identities.
+<P>
+
+Bugs should be reported to the &lt;<A HREF="mailto:users@lists.freeswan.org">users@lists.freeswan.org</A>&gt; mailing list.
+Caution: we cannot accept
+actual code from US residents, or even US citizens living outside the
+US, because that would bring FreeS/WAN under US export law. Some
+other countries cause similar problems. In general, we would prefer
+that you send detailed problem reports rather than code: we want
+FreeS/WAN to be unquestionably freely exportable, which means being
+very careful about where the code comes from, and for a small bug fix,
+that is often more time-consuming than just reinventing the fix
+ourselves.
+<P>
+
+<HR>
+<A NAME="index">&nbsp;</A><H2>Index</H2>
+<DL>
+<DT><A HREF="#lbAB">NAME</A><DD>
+<DT><A HREF="#lbAC">SYNOPSIS</A><DD>
+<DT><A HREF="#lbAD">DESCRIPTION</A><DD>
+<DL>
+<DT><A HREF="#lbAE">IKE's Job</A><DD>
+<DT><A HREF="#lbAF">Pluto</A><DD>
+<DT><A HREF="#lbAG">Before Running Pluto</A><DD>
+<DT><A HREF="#lbAH">Setting up <B>KLIPS</B> for <B>pluto</B></A><DD>
+<DT><A HREF="#lbAI">ipsec.secrets file</A><DD>
+<DT><A HREF="#lbAJ">Running Pluto</A><DD>
+<DT><A HREF="#lbAK">Pluto's Internal State</A><DD>
+<DT><A HREF="#lbAL">Using Whack</A><DD>
+<DT><A HREF="#lbAM">Examples</A><DD>
+<DT><A HREF="#lbAN">The updown command</A><DD>
+<DT><A HREF="#lbAO">Rekeying</A><DD>
+<DT><A HREF="#lbAP">Selecting a Connection When Responding: Road Warrior Support</A><DD>
+<DT><A HREF="#lbAQ">Debugging</A><DD>
+<DT><A HREF="#lbAR">Pluto's Behaviour When Things Go Wrong</A><DD>
+<DT><A HREF="#lbAS">Notes</A><DD>
+<DT><A HREF="#lbAT">Policies</A><DD>
+</DL>
+<DT><A HREF="#lbAU">SIGNALS</A><DD>
+<DT><A HREF="#lbAV">EXIT STATUS</A><DD>
+<DT><A HREF="#lbAW">FILES</A><DD>
+<DT><A HREF="#lbAX">ENVIRONMENT</A><DD>
+<DT><A HREF="#lbAY">SEE ALSO</A><DD>
+<DT><A HREF="#lbAZ">HISTORY</A><DD>
+<DT><A HREF="#lbBA">BUGS</A><DD>
+</DL>
+<HR>
+This document was created by
+<A HREF="http://localhost/cgi-bin/man/man2html">man2html</A>,
+using the manual pages.<BR>
+Time: 21:40:18 GMT, November 11, 2003
+</BODY>
+</HTML>
diff --git a/doc/manpages.html b/doc/manpages.html
new file mode 100644
index 000000000..81ca11ae0
--- /dev/null
+++ b/doc/manpages.html
@@ -0,0 +1,145 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="faq.html">Previous</A>
+<A HREF="firewall.html">Next</A>
+<HR>
+<H1><A name="manpages">FreeS/WAN manual pages</A></H1>
+<P>The various components of Linux FreeS/WAN are of course documented in
+ standard Unix manual pages, accessible via the man(1) command.</P>
+<P>Links here take you to an HTML version of the man pages.</P>
+<H2><A name="man.file">Files</A></H2>
+<DL>
+<DT><A href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A></DT>
+<DD>IPsec configuration and connections</DD>
+<DT><A href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</A></DT>
+<DD>secrets for IKE authentication, either pre-shared keys or RSA
+ private keys</DD>
+</DL>
+<P>These files are also discussed in the<A href="config.html">
+ configuration</A> section.</P>
+<H2><A name="man.command">Commands</A></H2>
+<P>Many users will never give most of the FreeS/WAN commands directly.
+ Configure the files listed above correctly and everything should be
+ automatic.</P>
+<P>The exceptions are commands for mainpulating the<A href="glossary.html#RSA">
+ RSA</A> keys used in Pluto authentication:</P>
+<DL>
+<DT><A href="manpage.d/ipsec_rsasigkey.8.html">ipsec_rsasigkey(8)</A></DT>
+<DD>generate keys</DD>
+<DT><A href="manpage.d/ipsec_newhostkey.8.html">ipsec_newhostkey(8)</A></DT>
+<DD>generate keys in a convenient format</DD>
+<DT><A href="manpage.d/ipsec_showhostkey.8.html">ipsec_showhostkey(8)</A>
+</DT>
+<DD>extract<A href="glossary.html#RSA"> RSA</A> keys from<A href="manpage.d/ipsec.secrets.5.html">
+ ipsec.secrets(5)</A> (or optionally, another file) and format them for
+ insertion in<A href="manpage.d/ipsec.conf.5.html"> ipsec.conf(5)</A> or
+ in DNS records</DD>
+</DL>
+<P>Note that:</P>
+<UL>
+<LI>These keys are for<STRONG> authentication only</STRONG>. They are<STRONG>
+ not secure for encryption</STRONG>.</LI>
+<LI>The utility uses random(4) as a source of<A href="glossary.html#random">
+ random numbers</A>. This may block for some time if there is not enough
+ activity on the machine to provide the required entropy. You may want
+ to give it some bogus activity such as random mouse movements or some
+ command such as<NOBR> <TT>du /usr &gt; /dev/null &amp;</TT>.</LI>
+</UL>
+<P>The following commands are fairly likely to be used, if only for
+ testing and status checks:</P>
+<DL>
+<DT><A href="manpage.d/ipsec.8.html">ipsec(8)</A></DT>
+<DD>invoke IPsec utilities</DD>
+<DT><A href="manpage.d/ipsec_setup.8.html">ipsec_setup(8)</A></DT>
+<DD>control IPsec subsystem</DD>
+<DT><A href="manpage.d/ipsec_auto.8.html">ipsec_auto(8)</A></DT>
+<DD>control automatically-keyed IPsec connections</DD>
+<DT><A href="manpage.d/ipsec_manual.8.html">ipsec_manual(8)</A></DT>
+<DD>take manually-keyed IPsec connections up and down</DD>
+<DT><A href="manpage.d/ipsec_ranbits.8.html">ipsec_ranbits(8)</A></DT>
+<DD>generate random bits in ASCII form</DD>
+<DT><A href="manpage.d/ipsec_look.8.html">ipsec_look(8)</A></DT>
+<DD>show minimal debugging information</DD>
+<DT><A href="manpage.d/ipsec_barf.8.html">ipsec_barf(8)</A></DT>
+<DD>spew out collected IPsec debugging information</DD>
+</DL>
+<P>The lower-level utilities listed below are normally invoked via
+ scripts listed above, but they can also be used directly when required.</P>
+<DL>
+<DT><A href="manpage.d/ipsec_eroute.8.html">ipsec_eroute(8)</A></DT>
+<DD>manipulate IPsec extended routing tables</DD>
+<DT><A href="manpage.d/ipsec_klipsdebug.8.html">ipsec_klipsdebug(8)</A></DT>
+<DD>set Klips (kernel IPsec support) debug features and level</DD>
+<DT><A href="manpage.d/ipsec_pluto.8.html">ipsec_pluto(8)</A></DT>
+<DD>IPsec IKE keying daemon</DD>
+<DT><A href="manpage.d/ipsec_spi.8.html">ipsec_spi(8)</A></DT>
+<DD>manage IPsec Security Associations</DD>
+<DT><A href="manpage.d/ipsec_spigrp.8.html">ipsec_spigrp(8)</A></DT>
+<DD>group/ungroup IPsec Security Associations</DD>
+<DT><A href="manpage.d/ipsec_tncfg.8.html">ipsec_tncfg(8)</A></DT>
+<DD>associate IPsec virtual interface with real interface</DD>
+<DT><A href="manpage.d/ipsec_whack.8.html">ipsec_whack(8)</A></DT>
+<DD>control interface for IPsec keying daemon</DD>
+</DL>
+<H2><A name="man.lib">Library routines</A></H2>
+<DL>
+<DT><A href="manpage.d/ipsec_atoaddr.3.html">ipsec_atoaddr(3)</A></DT>
+<DT><A href="manpage.d/ipsec_addrtoa.3.html">ipsec_addrtoa(3)</A></DT>
+<DD>convert Internet addresses to and from ASCII</DD>
+<DT><A href="manpage.d/ipsec_atosubnet.3.html">ipsec_atosubnet(3)</A></DT>
+<DT><A href="manpage.d/ipsec_subnettoa.3.html">ipsec_subnettoa(3)</A></DT>
+<DD>convert subnet/mask ASCII form to and from addresses</DD>
+<DT><A href="manpage.d/ipsec_atoasr.3.html">ipsec_atoasr(3)</A></DT>
+<DD>convert ASCII to Internet address, subnet, or range</DD>
+<DT><A href="manpage.d/ipsec_rangetoa.3.html">ipsec_rangetoa(3)</A></DT>
+<DD>convert Internet address range to ASCII</DD>
+<DT>ipsec_atodata(3)</DT>
+<DT><A href="manpage.d/ipsec_datatoa.3.html">ipsec_datatoa(3)</A></DT>
+<DD>convert binary data from and to ASCII formats</DD>
+<DT><A href="manpage.d/ipsec_atosa.3.html">ipsec_atosa(3)</A></DT>
+<DT><A href="manpage.d/ipsec_satoa.3.html">ipsec_satoa(3)</A></DT>
+<DD>convert IPsec Security Association IDs to and from ASCII</DD>
+<DT><A href="manpage.d/ipsec_atoul.3.html">ipsec_atoul(3)</A></DT>
+<DT><A href="manpage.d/ipsec_ultoa.3.html">ipsec_ultoa(3)</A></DT>
+<DD>convert unsigned-long numbers to and from ASCII</DD>
+<DT><A href="manpage.d/ipsec_goodmask.3.html">ipsec_goodmask(3)</A></DT>
+<DD>is this Internet subnet mask a valid one?</DD>
+<DT><A href="manpage.d/ipsec_masktobits.3.html">ipsec_masktobits(3)</A></DT>
+<DD>convert Internet subnet mask to bit count</DD>
+<DT><A href="manpage.d/ipsec_bitstomask.3.html">ipsec_bitstomask(3)</A></DT>
+<DD>convert bit count to Internet subnet mask</DD>
+<DT><A href="manpage.d/ipsec_optionsfrom.3.html">ipsec_optionsfrom(3)</A>
+</DT>
+<DD>read additional ``command-line'' options from file</DD>
+<DT><A href="manpage.d/ipsec_subnetof.3.html">ipsec_subnetof(3)</A></DT>
+<DD>given Internet address and subnet mask, return subnet number</DD>
+<DT><A href="manpage.d/ipsec_hostof.3.html">ipsec_hostof(3)</A></DT>
+<DD>given Internet address and subnet mask, return host part</DD>
+<DT><A href="manpage.d/ipsec_broadcastof.3.html">ipsec_broadcastof(3)</A>
+</DT>
+<DD>given Internet address and subnet mask, return broadcast address</DD>
+</DL>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="faq.html">Previous</A>
+<A HREF="firewall.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/nightly.html b/doc/nightly.html
new file mode 100644
index 000000000..580fc0fc5
--- /dev/null
+++ b/doc/nightly.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="makecheck.html">Previous</A>
+<HR>
+<H1><A name="nightly">Nightly regression testing</A></H1>
+<P> The nightly regression testing system consists of several shell
+ scripts and some perl scripts. The goal is to check out a fresh tree,
+ run &quot;make check&quot; on it, record the results and summarize the results to
+ the team and to the web site.</P>
+<P> Output can be found on<A HREF="http://bugs.freeswan.org:81/"> adams</A>
+, although the tests are actually run on another project machine.</P>
+<H1><A name="nightlyhowto">How to setup the nightly build</A></H1>
+<P> The best way to do nightly testing is to setup a new account. We
+ call the account &quot;build&quot; - you could call it something else, but there
+ may still be some references to ~build in the scripts.</P>
+<H2><A NAME="42_1"> Files you need to know about</A></H2>
+<P> As few files as possible need to be extracted from the source tree -
+ files are run from the source tree whenever possible. However, there
+ are some bootstrap and configuration files that are necessary.</P>
+<P> There are 7 files in testing/utils that are involved:</P>
+<DL>
+<DT> nightly-sample.sh</DT>
+<DD> This is the root of the build process. This file should be copied
+ out of the CVS tree, to $HOME/bin/nightly.sh of the build account. This
+ file should be invoked from cron.</DD>
+<DT> freeswan-regress-env-sample.sh</DT>
+<DD> This file should be copied to $HOME/freeswan-regress-env.sh. It
+ should be edited to localize the values. See below.</DD>
+<DT> regress-cleanup.pl</DT>
+<DD> This file needs to be copied to $HOME/bin/regress-cleanup.pl. It is
+ invoked by the nightly file before doing anything else. It removes
+ previous nights builds in order to free up disk space for the build
+ about to be done.</DD>
+<DT> teammail-sample.sh</DT>
+<DD> A script used to send results email to the &quot;team&quot;. This sample
+ script could be copied to $HOME/bin/teammail.sh. This version will PGP
+ encrypt all the output to the team members. If this script is used,
+ then PGP will have to be properly setup to have the right keys.</DD>
+<DT> regress-nightly.sh</DT>
+<DD> This is the first stage of the nightly build. This stage will call
+ other scripts as appropriate, and will extract the source code from
+ CVS. This script should be copied to $HOME/bin/regress-nightly.sh</DD>
+<DT> regress-stage2.sh</DT>
+<DD> This is the second stage of the nightly build. It is called in
+ place. It essentially sets up the UML setup in umlsetup.sh, and calls
+ &quot;make check&quot;.</DD>
+<DT> regress-summarize-results.pl</DT>
+<DD> This script will summarize the results from the tests to a
+ permanent directory set by $REGRESSRESULTS. It is invoked from the
+ stage2 nightly script.</DD>
+<DT> regress-chart.sh</DT>
+<DD> This script is called at the end of the build process, and will
+ summarize each night's results (as saved into $REGRESSRESULTS by
+ regress-summarize-results.pl) as a chart using gnuplot. Note that this
+ requires at least gnuplot 3.7.2.</DD>
+</DL>
+<H2><A NAME="42_2">Configuring freeswan-regress-env.sh</A></H2>
+<P>For more info on KERNPOOL, UMLPATCH, BASICROOT and SHAREDIR, see<A HREF="umltesting.html">
+ User-Mode-Linux testing guide</A>.</P>
+<DL>
+<DT> KERNPOOL</DT>
+<DD> Extract copy of some kernel source to be used for UML builds</DD>
+<DT> UMLPATCH</DT>
+<DD> matching User-Mode-Linux patch.</DD>
+<DT> BASICROOT</DT>
+<DD> the root file system image (see<A HREF="umltesting.html">
+ User-Mode-Linux testing guide</A>).</DD>
+<DT> SHAREDIR=${BASICROOT}/usr/share</DT>
+<DD> The /usr/share to use.</DD>
+<DT> REGRESSTREE</DT>
+<DD> A directory in which to store the nightly regression results.
+ Directories will be created by date in this tree.</DD>
+<DT> TCPDUMP=tcpdump-3.7.1</DT>
+<DD> The path to the<A HREF="http://www.tcpdump.org/"> tcpdump</A> to
+ use. This must have crypto compiled in, and must be at least 3.7.1</DD>
+<DT> KERNEL_RH7_2_SRC=/a3/kernel_sources/linux-2.4.9-13/</DT>
+<DD> An extracted copy of the RedHat 7.2. kernel source. If set, then
+ the packaging/rpm-rh72-install-01 test will be run, and an RPM will be
+ built as a test.</DD>
+<DT> KERNEL_RH7_3_SRC=/a3/kernel_sources/rh/linux-2.4.18-5</DT>
+<DD> An extracted copy of the RedHat 7.3. kernel source. If set, then
+ the packaging/rpm-rh73-install-01 test will be run, and an RPM will be
+ built as a test.</DD>
+<DT> NIGHTLY_WATCHERS=&quot;userid,userid,userid&quot;</DT>
+<DD> The list of people who should receive nightly output. This is used
+ by teammail.sh</DD>
+<DT> FAILLINES=128</DT>
+<DD> How many lines of failed test output to include in the nightly
+ output</DD>
+<DT> PATH=$PATH:/sandel/bin export PATH</DT>
+<DD> You can also override the path if necessary here.</DD>
+<DT> CVSROOT=:pserver:anoncvs@ip212.xs4net.freeswan.org:/freeswan/MASTER</DT>
+<DD> The CVSROOT to use. This example may work for anonymous CVS, but
+ will be 12 hours behind the primary, and is still experimental</DD>
+<DT> SNAPSHOTSIGDIR=$HOME/snapshot-sig</DT>
+<DD> For the release tools, where to put the generated per-snapshot
+ signature keys</DD>
+<DT> LASTREL=1.97</DT>
+<DD> the name of the last release branch (to find the right per-snapshot
+ signature</DD>
+<DD></DD>
+</DL>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="makecheck.html">Previous</A>
+</BODY>
+</HTML>
diff --git a/doc/oppimpl.txt b/doc/oppimpl.txt
new file mode 100644
index 000000000..fe4527d4e
--- /dev/null
+++ b/doc/oppimpl.txt
@@ -0,0 +1,514 @@
+Implementing Opportunistic Encryption
+
+Henry Spencer & D. Hugh Redelmeier
+
+Version 4+, 15 Dec 2000
+
+
+
+Updates
+
+Major changes since last version: "Negotiation Issues" section discussing
+some interoperability matters, plus some wording cleanup. Some issues
+arising from discussions at OLS are not yet resolved, so there will almost
+certainly be another version soon.
+
+xxx incoming could be opportunistic or RW. xxx any way of saving unaware
+implementations??? xxx compression needs mention.
+
+
+
+Introduction
+
+A major long-term goal of the FreeS/WAN project is opportunistic
+encryption: a security gateway intercepts an outgoing packet aimed at a
+new remote host, and quickly attempts to negotiate an IPsec tunnel to that
+host's security gateway, so that traffic can be encrypted and
+authenticated without changes to the host software. (This generalizes
+trivially to the end-to-end case where host and security gateway are one
+and the same.) If the attempt fails, the packet (or a retry thereof)
+passes through in clear or is dropped, depending on local policy.
+Prearranged tunnels bypass all this, so static VPNs can coexist with
+opportunistic encryption.
+
+xxx here Although significant intelligence about all this is necessary at the
+initiator end, it's highly desirable for little or no special machinery
+to be needed at the responder end. In particular, if none were needed,
+then a security gateway which knows nothing about opportunistic encryption
+could nevertheless participate in some opportunistic connections.
+
+IPSEC gives us the low-level mechanisms, and the key-exchange machinery,
+but there are some vague spots (to put it mildly) at higher levels.
+
+One constraint which deserves comment is that the process of tunnel setup
+should be quick. Moreover, the decision that no tunnel can be created
+should also be quick, since that will be a common case, at least in the
+beginning. People will be reluctant to use opportunistic encryption if it
+causes gross startup delays on every connection, even connections which see
+no benefit from it. Win or lose, the process must be rapid.
+
+There's nothing much we can do to speed up the key exchange itself. (The
+one thing which conceivably might be done is to use Aggressive Mode, which
+involves fewer round trips, but it has limitations and possible security
+problems, and we're reluctant to touch it.) What we can do, is to make the
+other parts of the setup process as quick as possible. This desire will
+come back to haunt us below. :-)
+
+A further note is that we must consider the processing at the responder
+end as well as the initiator end.
+
+Several pieces of new machinery are needed to make this work. Here's a
+brief list, with details considered below.
+
++ Outgoing Packet Interception. KLIPS needs to intercept packets which
+likely would benefit from tunnel setup, and bring them to Pluto's
+attention. There needs to be enough memory in the process that the same
+tunnel doesn't get proposed too often (win or lose).
+
++ Smart Connection Management. Not only do we need to establish tunnels
+on request, once a tunnel is set up, it needs to be torn down eventually
+if it's not in use. It's also highly desirable to detect the fact that it
+has stopped working, and do something useful. Status changes should be
+coordinated between the two security gateways unless one has crashed,
+and even then, they should get back into sync eventually.
+
++ Security Gateway Discovery. Given a packet destination, we must decide
+who to attempt to negotiate a tunnel with. This must be done quickly, win
+or lose, and reliably even in the presence of diverse network setups.
+
++ Authentication Without Prearrangement. We need to be sure we're really
+talking to the intended security gateway, without being able to prearrange
+any shared information. He needs the same assurance about us.
+
++ More Flexible Policy. In particular, the responding Pluto needs a way
+to figure out whether the connection it is being asked to make is okay.
+This isn't as simple as just searching our existing conn database -- we
+probably have to specify *classes* of legitimate connections.
+
+Conveniently, we have a three-letter acronym for each of these. :-)
+
+Note on philosophy: we have deliberately avoided providing six different
+ways to do each step, in favor of specifying one good one. Choices are
+provided only when they appear to be necessary. (Or when we are not yet
+quite sure yet how best to do something...)
+
+
+
+OPI, SCM
+
+Smart Connection Management would be quite useful even by itself,
+requiring manual triggering. (Right now, we do the manual triggering, but
+not the other parts of SCM.) Outgoing Packet Interception fits together
+with SCM quite well, and improves its usefulness further. Going through a
+connection's life cycle from the start...
+
+OPI itself is relatively straightforward, aside from the nagging question
+of whether the intercepted packet is put on hold and then released, or
+dropped. Putting it on hold is preferable; the alternative is to rely on
+the application or the transport layer re-trying. The downside of packet
+hold is extra resources; the downside of packet dropping is that IPSEC
+knows *when* the packet can finally go out, and the higher layers don't.
+Either way, life gets a little tricky because a quickly-retrying
+application may try more than once before we know for sure whether a
+tunnel can be set up, and something has to detect and filter out the
+duplications. Some ARP implementations use the approach of keeping one
+packet for an as-yet-unresolved address, and throwing away any more that
+appear; that seems a reasonable choice.
+
+(Is it worth intercepting *incoming* packets, from the outside world, and
+attempting tunnel setup based on them? Perhaps... if, and only if, we
+organize AWP so that non-opportunistic SGs can do it somehow. Otherwise,
+if the other end has not initiated tunnel setup itself, it will not be
+prepared to do so at our request.)
+
+Once a tunnel is up, packets going into it naturally are not intercepted
+by OPI. However, we need to do something about the flip side of this too:
+after deciding that we *cannot* set up a tunnel, either because we don't
+have enough information or because the other security gateway is
+uncooperative, we have to remember that for a while, so we don't keep
+knocking on the same locked door. One plausible way of doing that is to
+set up a bypass "tunnel" -- the equivalent of our current %passthrough
+connection -- and have it managed like a real SCM tunnel (finite lifespan
+etc.). This sounds a bit heavyweight, but in practice, the alternatives
+all end up doing something very similar when examined closely. Note that
+we need an extra variant of this, a block rather than a bypass, to cover
+the case where local policy dictates that packets *not* be passed through;
+we still have to remember the fact that we can't set up a real tunnel.
+
+When to tear tunnels down is a bit problematic, but if we're setting up a
+potentially unbounded number of them, we have to tear them down *somehow*
+*sometime*. It seems fairly obvious that we set a tentative lifespan,
+probably fairly short (say 1min), and when it expires, we look to see if
+the tunnel is still in use (say, has had traffic in the last half of the
+lifespan). If so, we assign it a somewhat longer lifespan (say 10min),
+after which we look again. If not, we close it down. (This lifespan is
+independent of key lifetime; it is just the time when the tunnel's future
+is next considered. This should happen reasonably frequently, unlike
+rekeying, which is costly and shouldn't be too frequent.) Multi-step
+backoff algorithms probably are not worth the trouble; looking every
+10min doesn't seem onerous.
+
+For the tunnel-expiry decision, we need to know how long it has been since
+the last traffic went through. A more detailed history of the traffic
+does not seem very useful; a simple idle timer (or last-traffic timestamp)
+is both necessary and sufficient. And KLIPS already has this.
+
+As noted, default initial lifespan should be short. However, Pluto should
+keep a history of recently-closed tunnels, to detect cases where a tunnel
+is being repeatedly re-established and should be given a longer lifespan.
+(Not only is tunnel setup costly, but it adds user-visible delay, so
+keeping a tunnel alive is preferable if we have reason to suspect more
+traffic soon.) Any tunnel re-established within 10min of dying should have
+10min added to its initial lifespan. (Just leaving all tunnels open longer
+is unappealing -- adaptive lifetimes which are sensitive to the behavior
+of a particular tunnel are wanted. Tunnels are relatively cheap entities
+for us, but that is not necessarily true of all implementations, and there
+may also be administrative problems in sorting through large accumulations
+of idle tunnels.)
+
+It might be desirable to have detailed information about the initial
+packet when determining lifespans. HTTP connections in particular are
+notoriously bursty and repetitive.
+
+Arguably it would be nice to monitor TCP connection status. A still-open
+TCP connection is almost a guarantee that more traffic is coming, while
+the closing of the only TCP connection through a tunnel is a good hint
+that none is. But the monitoring is complex, and it doesn't seem worth
+the trouble.
+
+IKE connections likewise should be torn down when it appears the need has
+passed. They should linger longer than the last tunnel they administer,
+just in case they are needed again; the cost of retaining them is low. An
+SG with only a modest number of them open might want to simply retain each
+until rekeying time, with more aggressive management cutting in only when
+the number gets large. (They should be torn down eventually, if only to
+minimize the length of a status report, but rekeying is the only expensive
+event for them.)
+
+It's worth remembering that tunnels sometimes go down because the other
+end crashes, or disconnects, or has a network link break, and we don't get
+any notice of this in the general case. (Even in the event of a crash and
+successful reboot, we won't hear about it unless the other end has
+specific reason to talk IKE to us immediately.) Of course, we have to
+guard against being too quick to respond to temporary network outages,
+but it's not quite the same issue for us as for TCP, because we can tear
+down and then re-establish a tunnel without any user-visible effect except
+a pause in traffic. And if the other end does go down and come back up,
+we and it can't communicate *at all* (except via IKE) until we tear down
+our tunnel.
+
+So... we need some kind of heartbeat mechanism. Currently there is none
+in IKE, but there is discussion of changing that, and this seems like the
+best approach. Doing a heartbeat at the IP level will not tell us about a
+crash/reboot event, and sending heartbeat packets through tunnels has
+various complications (they should stop at the far mouth of the tunnel
+instead of going on to a subnet; they should not count against idle
+timers; etc.). Heartbeat exchanges obviously should be done only when
+there are tunnels established *and* there has been no recent incoming
+traffic through them. It seems reasonable to do them at lifespan ends,
+subject to appropriate rate limiting when more than one tunnel goes to the
+same other SG. When all traffic between the two ends is supposed to go
+via the tunnel, it might be reasonable to do a heartbeat -- subject to a
+rate limiter to avoid DOS attacks -- if the kernel sees a non-tunnel
+non-IKE packet from the other end.
+
+If a heartbeat gets no response, try a few (say 3) pings to check IP
+connectivity; if one comes back, try another heartbeat; if it gets no
+response, the other end has rebooted, or otherwise been re-initialized,
+and its tunnels should be torn down. If there's no response to the pings,
+note the fact and try the sequence again at the next lifespan end; if
+there's nothing then either, declare the tunnels dead.
+
+Finally... except in cases where we've decided that the other end is dead
+or has rebooted, tunnel teardown should always be coordinated with the
+other end. This means interpreting and sending Delete notifications, and
+also Initial-Contacts. Receiving a Delete for the other party's tunnel
+SAs should lead us to tear down our end too -- SAs (SA bundles, really)
+need to be considered as paired bidirectional entities, even though the
+low-level protocols don't think of them that way.
+
+
+
+SGD, AWP
+
+Given a packet destination, how do we decide who to (attempt to) negotiate
+a tunnel with? And as a related issue, how do the negotiating parties
+authenticate each other? DNSSEC obviously provides the tools for the
+latter, but how exactly do we use them?
+
+Having intercepted a packet, what we know is basically the IP addresses of
+source and destination (plus, in principle, some information about the
+desired communication, like protocol and port). We might be able to map
+the source address to more information about the source, depending on how
+well we control our local networks, but we know nothing further about the
+destination.
+
+The obvious first thing to do is a DNS reverse lookup on the destination
+address; that's about all we can do with available data. Ideally, we'd
+like to get all necessary information with this one DNS lookup, because
+DNS lookups are time-consuming -- all the more so if they involve a DNSSEC
+signature-checking treewalk by the name server -- and we've got to hurry.
+While it is unusual for a reverse lookup to yield records other than PTR
+records (or possibly CNAME records, for RFC 2317 classless delegation),
+there's no reason why it can't.
+
+(For purposes like logging, a reverse lookup is usually followed by a
+forward lookup, to verify that the reverse lookup wasn't lying about the
+host name. For our purposes, this is not vital, since we use stronger
+authentication methods anyway.)
+
+While we want to get as much data as possible (ideally all of it) from one
+lookup, it is useful to first consider how the necessary information would
+be obtained if DNS lookups were instantaneous. Two pieces of information
+are absolutely vital at this point: the IP address of the other end's
+security gateway, and the SG's public key*.
+
+(* Actually, knowledge of the key can be postponed slightly -- it's not
+needed until the second exchange of the negotiations, while we can't even
+start negotiations without knowing the IP address. The SG is not
+necessarily on the plain-IP route to the destination, especially when
+multiple SGs are present.)
+
+Given instantaneous DNS lookups, we would:
+
++ Start with a reverse lookup to turn the address into a name.
+
++ Look for something like RFC-2782 SRV records using the name, to find out
+who provides this particular service. If none comes back, we can abandon
+the whole process.
+
++ Select one SRV record, which gives us the name of a target host (plus
+possibly one or more addresses, if the name server has supplied address
+records as Additional Data for the SRV records -- this is recommended
+behavior but is not required).
+
++ Use the target name to look up a suitable KEY record, and also address
+record(s) if they are still needed.
+
+This gives us the desired address(es) and key. However, it requires three
+lookups, and we don't even find out whether there's any point in trying
+until after the second.
+
+With real DNS lookups, which are far from instantaneous, some optimization
+is needed. At the very least, typical cases should need fewer lookups.
+
+So when we do the reverse lookup on the IP address, instead of asking for
+PTR, we ask for TXT. If we get none, we abandon opportunistic
+negotiation, and set up a bypass/block with a relatively long life (say
+6hr) because it's not worth trying again soon. (Note, there needs to be a
+way to manually force an early retry -- say, by just clearing out all
+memory of a particular address -- to cover cases where a configuration
+error is discovered and fixed.)
+
+xxx need to discuss multi-string TXTs
+
+In the results, we look for at least one TXT record with content
+"X-IPsec-Server(nnn)=a.b.c.d kkk", following RFC 1464 attribute/value
+notation. (The "X-" indicates that this is tentative and experimental;
+this design will probably need modification after initial experiments.)
+Again, if there is no such record, we abandon opportunistic negotiation.
+
+"nnn" and the parentheses surrounding it are optional. If present, it
+specifies a priority (low number high priority), as for MX records, to
+control the order in which multiple servers are tried. If there are no
+priorities, or there are ties, pick one randomly.
+
+"a.b.c.d" is the dotted-decimal IP address of the SG. (Suitable extensions
+for IPv6, when the time comes, are straightforward.)
+
+"kkk" is either an RSA-MD5 public key in base-64 notation, as in the text
+form of an RFC 2535 KEY record, or "@hhh". In the latter case, hhh is a
+DNS name, under which one Host/Authentication/IPSEC/RSA-MD5 KEY record is
+present, giving the server's authentication key. (The delay of the extra
+lookup is undesirable, but practical issues of key management may make it
+advisable not to duplicate the key itself in DNS entries for many
+clients.)
+
+It unfortunately does appear that the authentication key has to be
+associated with the server, not the client behind it. At the time when
+the responder has to authenticate our SG, it does not know which of its
+clients we are interested in (i.e., which key to use), and there is no
+good way to tell it. (There are some bad ways; this decision may merit
+re-examination after experimental use.)
+
+The responder authenticates our SG by doing a reverse lookup on its IP
+address to get a Host/Authentication/IPSEC/RSA-MD5 KEY record. He can
+attempt this in parallel with the early parts of the negotiation (since he
+knows our SG IP address from the first negotiation packet), at the risk of
+having to abandon the attempt and do a different lookup if we use
+something different as our ID (see below). Unfortunately, he doesn't yet
+know what client we will claim to represent, so he'll need to do another
+lookup as part of phase 2 negotiation (unless the client *is* our SG), to
+confirm that the client has a TXT X-IPsec-Server record pointing to our
+SG. (Checking that the record specifies the same key is not important,
+since the responder already has a trustworthy key for our SG.)
+
+Also unfortunately, opportunistic tunnels can only have degenerate subnets
+(/32 subnets, containing one host) at their ends. It's superficially
+attractive to negotiate broader connections... but without prearrangement,
+you don't know whether you can trust the other end's claim to have a
+specific subnet behind it. Fixing this would require a way to do a
+reverse lookup on the *subnet* (you cannot trust information in DNS
+records for a name or a single address, which may be controlled by people
+who do not control the whole subnet) with both the address and the mask
+included in the name. Except in the special case of a subnet masked on a
+byte boundary (in which case RFC 1035's convention of an incomplete
+in-addr.arpa name could be used), this would need extensions to the
+reverse-map name space, which is awkward, especially in the presence of
+RFC 2317 delegation. (IPv6 delegation is more flexible and it might be
+easier there.)
+
+There is a question of what ID should be used in later steps of
+negotiation. However, the desire not to put more DNS lookups in the
+critical path suggests avoiding the extra complication of varied IDs,
+except in the Road Warrior case (where an extra lookup is inevitable).
+Also, figuring out what such IDs *mean* gets messy. To keep things simple,
+except in the RW case, all IDs should be IP addresses identical to those
+used in the packet headers.
+
+For Road Warrior, the RW must be the initiator, since the home-base SG has
+no idea what address the RW will appear at. Moreover, in general the RW
+does not control the DNS entries for his address. This inherently denies
+the home base any authentication of the RW's IP address; the most it can
+do is to verify an identity he provides, and perhaps decide whether it
+wishes to talk to someone with that identity, but this does not verify his
+right to use that IP address -- nothing can, really.
+
+(That may sound like it would permit some man-in-the-middle attacks, but
+the RW can still do full authentication of the home base, so a man in the
+middle cannot successfully impersonate home base. Furthermore, a man in
+the middle must impersonate both sides for the DH exchange to work. So
+either way, the IKE negotiation falls apart.)
+
+A Road Warrior provides an FQDN ID, used for a forward lookup to obtain a
+Host/Authentication/IPSEC/RSA-MD5 KEY record. (Note, an FQDN need not
+actually correspond to a host -- e.g., the DNS data for it need not
+include an A record.) This suffices, since the RW is the initiator and
+the responder knows his address from his first packet.
+
+Certain situations where a host has a more-or-less permanent IP address,
+but does not control its DNS entries, must be treated essentially like
+Road Warrior. It is unfortunate that DNS's old inverse-query feature
+cannot be used (nonrecursively) to ask the initiator's local DNS server
+whether it has a name for the address, because the address will almost
+always have been obtained from a DNS name lookup, and it might be a lookup
+of a name whose DNS entries the host *does* control. (Real examples of
+this exist: the host has a preferred name whose host-controlled entry
+includes an A record, but a reverse lookup on the address sends you to an
+ISP-controlled name whose entry has an A record but not much else.) Alas,
+inverse query is long obsolete and is not widely implemented now.
+
+There are some questions in failure cases. If we cannot acquire the info
+needed to set up a tunnel, this is the no-tunnel-possible case. If we
+reach an SG but negotiation fails, this too is the no-tunnel-possible
+case, with a relatively long bypass/block lifespan (say 1hr) since
+fruitless negotiations are expensive. (In the multiple-SG case, it seems
+unlikely to be worthwhile to try other SGs just in case one of them might
+have a configuration permitting successful negotiation.)
+
+Finally, there is a sticky problem with timeouts. If the other SG is down
+or otherwise inaccessible, in the worst case we won't hear about this
+except by not getting responses. Some other, more pathological or even
+evil, failure cases can have the same result. The problem is that in the
+case where a bypass is permitted, we want to decide whether a tunnel is
+possible quickly. It gets even worse if there are multiple SGs, in which
+case conceivably we might want to try them all (since some SGs being up
+when others are down is much more likely than SGs differing in policy).
+
+The patience setting needs to be configurable policy, with a reasonable
+default (to be determined by experiment). If it expires, we simply have
+to declare the attempt a failure, and set up a bypass/block. (Setting up
+a tentative bypass/block, and replacing it with a real tunnel if remaining
+attempts do produce one, looks attractive at first glance... but exposing
+the first few seconds of a connection is often almost as bad as exposing
+the whole thing!) Such a bypass/block should have a short lifespan, say
+10min, because the SG(s) might be only temporarily unavailable.
+
+The flip side of IKE waiting for a timeout is that all other forms of
+feedback, e.g. "host not reachable", should be *ignored*, because you
+cannot trust them! This may need kernel changes.
+
+Can AWP be done by non-opportunistic SGs? Probably not; existing SG
+implementations generally aren't prepared to do anything suitable, except
+perhaps via the messy business of certificates. There is one borderline
+exception: some implementations rely on LDAP for at least some of their
+information fetching, and it might be possible to substitute a custom LDAP
+server which does the right things for them. Feasibility of this depends
+on details, which we don't know well enough.
+
+[This could do with a full example, a complete packet by packet walkthrough
+including all DNS and IKE traffic.]
+
+
+
+MFP
+
+Our current conn database simply isn't flexible enough to cover all this
+properly. In particular, the responding Pluto needs a way to figure out
+whether the connection it is being asked to make is legitimate.
+
+This is more subtle than it sounds, given the problem noted earlier, that
+there's no clear way to authenticate claims to represent a non-degenerate
+subnet. Our database has to be able to say "a connection to any host in
+this subnet is okay" or "a connection to any subnet within this subnet is
+okay", rather than "a connection to exactly this subnet is okay". (There
+is some analogy to the Road Warrior case here, which may be relevant.)
+This will require at least a re-interpretation of ipsec.conf.
+
+Interim stages of implementation of this will require a bit of thought.
+Notably, we need some way of dealing with the lack of fully signed DNSSEC
+records. Without user interaction, probably the best we can do is to
+remember the results of old fetches, compare them to the results of new
+fetches, and complain and disbelieve all of it if there's a mismatch.
+This does mean that somebody who gets fake data into our very first fetch
+will fool us, at least for a while, but that seems an acceptable tradeoff.
+
+
+
+Negotiation Issues
+
+There are various options which are nominally open to negotiation as part
+of setup, but which have to be nailed down at least well enough that
+opportunistic SGs can reliably interoperate. Somewhat arbitrarily and
+tentatively, opportunistic SGs must support Main Mode, Oakley group 5 for
+D-H, 3DES encryption and MD5 authentication for both ISAKMP and IPsec SAs,
+RSA digital-signature authentication with keys between 2048 and 8192 bits,
+and ESP doing both encryption and authentication. They must do key PFS
+in Quick Mode, but not identity PFS.
+
+
+
+What we need from DNS
+
+Fortunately, we don't need any new record types or suchlike to make this
+all work. We do, however, need attention to a couple of areas in DNS
+implementation.
+
+First, size limits. Although the information we directly need from a
+lookup is not enormous -- the only potentially-big item is the KEY record,
+and there should be only one of those -- there is still a problem with
+DNSSEC authentication signatures. With a 2048-bit key and assorted
+supporting information, we will fill most of a 512-byte DNS UDP packet...
+and if the data is to have DNSSEC authentication, at least one quite large
+SIG record will come too. Plus maybe a TSIG signature on the whole
+response, to authenticate it to our resolver. So: DNSSEC-capable name
+servers must fix the 512-byte UDP limit. We're told there are provisions
+for this; implementation of them is mandatory.
+
+Second, interface. It is unclear how the resolver interface will let us
+ask for DNSSEC authentication. We would prefer to ask for "authentication
+where possible", and get back the data with each item flagged by whether
+authentication was available (and successful!) or not available. Having
+to ask separately for authenticated and non-authenticated data would
+probably be acceptable, *provided* both will be cached on the first
+request, so the two requests incur only one set of (non-local) network
+traffic. Either way, we want to see the name server and resolver do this
+for us; that makes sense in any case, since it's important that
+verification be done somewhere where it can be cached, the more centrally
+the better.
+
+Finally, a wistful note: the ability to do a limited form of inverse
+queries (an almost forgotten feature), to ask the local name server which
+hostname it recently mapped to a particular address, would be quite
+helpful. Note, this is *NOT* the same as a reverse lookup, and crude
+fakes like putting a dotted-decimal address in brackets do not suffice.
diff --git a/doc/opportunism-spec.txt b/doc/opportunism-spec.txt
new file mode 100644
index 000000000..fbe319a57
--- /dev/null
+++ b/doc/opportunism-spec.txt
@@ -0,0 +1,1254 @@
+
+
+
+
+
+
+
+
+
+ Opportunistic Encryption
+
+ Henry Spencer
+ D. Hugh Redelmeier
+ henry@spsystems.net
+ hugh@mimosa.com
+ Linux FreeS/WAN Project
+
+
+
+ Opportunistic encryption permits secure
+ (encrypted, authenticated) communication via IPsec
+ without connection-by-connection prearrangement,
+ either explicitly between hosts (when the hosts
+ are capable of it) or transparently via packet-
+ intercepting security gateways. It uses DNS
+ records (authenticated with DNSSEC) to provide the
+ necessary information for gateway discovery and
+ gateway authentication, and constrains negotiation
+ enough to guarantee success.
+
+ Substantive changes since draft 3: write off
+ inverse queries as a lost cause; use Invalid-SPI
+ rather than Delete as notification of unknown SA;
+ minor wording improvements and clarifications.
+ This document takes over from the older ``Imple-
+ menting Opportunistic Encryption'' document.
+
+
+1. Introduction
+
+A major goal of the FreeS/WAN project is opportunistic
+encryption: a (security) gateway intercepts an outgoing
+packet aimed at a remote host, and quickly attempts to nego-
+tiate an IPsec tunnel to that host's security gateway. If
+the attempt succeeds, traffic can then be secure, transpar-
+ently (without changes to the host software). If the
+attempt fails, the packet (or a retry thereof) passes
+through in clear or is dropped, depending on local policy.
+Prearranged tunnels bypass the packet interception etc., so
+static VPNs can coexist with opportunistic encryption.
+
+This generalizes trivially to the end-to-end case: host and
+security gateway simply are one and the same. Some opti-
+mizations are possible in that case, but the basic scheme
+need not change.
+
+The objectives for security systems need to be explicitly
+stated. Opportunistic encryption is meant to achieve secure
+communication, without prearrangement of the individual con-
+nection (although some prearrangement on a per-host basis is
+
+
+
+Draft 4 3 May 2001 1
+
+
+
+
+
+ Opportunistic Encryption
+
+
+required), between any two hosts which implement the proto-
+col (and, if they act as security gateways, between hosts
+behind them). Here ``secure'' means strong encryption and
+authentication of packets, with authentication of partici-
+pants--to prevent man-in-the-middle and impersonation
+attacks--dependent on several factors. The biggest factor
+is the authentication of DNS records, via DNSSEC or equiva-
+lent means. A lesser factor is which exact variant of the
+setup procedure (see section 2.2) is used, because there is
+a tradeoff between strong authentication of the other end
+and ability to negotiate opportunistic encryption with hosts
+which have limited or no control of their reverse-map DNS
+records: without reverse-map information, we can verify that
+the host has the right to use a particular FQDN (Fully Qual-
+ified Domain Name), but not whether that FQDN is authorized
+to use that IP address. Local policy must decide whether
+authentication or connectivity has higher priority.
+
+Apart from careful attention to detail in various areas,
+there are three crucial design problems for opportunistic
+encryption. It needs a way to quickly identify the remote
+host's security gateway. It needs a way to quickly obtain
+an authentication key for the security gateway. And the
+numerous options which can be specified with IKE must be
+constrained sufficiently that two independent implementa-
+tions are guaranteed to reach agreement, without any
+explicit prearrangement or preliminary negotiation. The
+first two problems are solved using DNS, with DNSSEC ensur-
+ing that the data obtained is reliable; the third is solved
+by specifying a minimum standard which must be supported.
+
+A note on philosophy: we have deliberately avoided providing
+six different ways to do each job, in favor of specifying
+one good one. Choices are provided only when they appear to
+be necessary, or at least important.
+
+A note on terminology: to avoid constant circumlocutions, an
+ISAKMP/IKE SA, possibly recreated occasionally by rekeying,
+will be referred to as a ``keying channel'', and a set of
+IPsec SAs providing bidirectional communication between two
+IPsec hosts, possibly recreated occasionally by rekeying,
+will be referred to as a ``tunnel'' (it could conceivably
+use transport mode in the host-to-host case, but we advocate
+using tunnel mode even there). The word ``connection'' is
+here used in a more generic sense. The word ``lifetime''
+will be avoided in favor of ``rekeying interval'', since
+many of the connections will have useful lives far shorter
+than any reasonable rekeying interval, and hence the two
+concepts must be separated.
+
+A note on document structure: Discussions of why things were
+done a particular way, or not done a particular way, are
+broken out in paragraphs headed ``Rationale:'' (to preserve
+the flow of the text, many such paragraphs are deferred to
+
+
+
+Draft 4 3 May 2001 2
+
+
+
+
+
+ Opportunistic Encryption
+
+
+the ends of sections). Paragraphs headed ``Ahem:'' are dis-
+cussions of where the problem is being made significantly
+harder by problems elsewhere, and how that might be cor-
+rected. Some meta-comments are enclosed in [].
+
+Rationale: The motive is to get the Internet encrypted.
+That requires encryption without connection-by-connection
+prearrangement: a system must be able to reliably negotiate
+an encrypted, authenticated connection with a total
+stranger. While end-to-end encryption is preferable, doing
+opportunistic encryption in security gateways gives enormous
+leverage for quick deployment of this technology, in a world
+where end-host software is often primitive, rigid, and out-
+dated.
+
+Rationale: Speed is of the essence in tunnel setup: a con-
+nection-establishment delay longer than about 10 seconds
+begins to cause problems for users and applications. Thus
+the emphasis on rapidity in gateway discovery and key fetch-
+ing.
+
+Ahem: Host-to-host opportunistic encryption would be utterly
+trivial if a fast public-key encryption/signature algorithm
+was available. You would do a reverse lookup on the desti-
+nation address to obtain a public key for that address, and
+simply encrypt all packets going to it with that key, sign-
+ing them with your own private key. Alas, this is impracti-
+cal with current CPU speeds and current algorithms (although
+as noted later, it might be of some use for limited pur-
+poses). Nevertheless, it is a useful model.
+
+2. Connection Setup
+
+For purposes of discussion, the network is taken to look
+like this:
+
+ Source----Initiator----...----Responder----Destination
+
+The intercepted packet comes from the Source, bound for the
+Destination, and is intercepted at the Initiator. The Ini-
+tiator communicates over the insecure Internet to the
+Responder. The Source and the Initiator might be the same
+host, or the Source might be an end-user host and the Ini-
+tiator a security gateway (SG). Likewise for the Responder
+and the Destination.
+
+Given an intercepted packet, whose useful information (for
+our purposes) is essentially only the Destination's IP
+address, the Initiator must quickly determine the Responder
+(the Destination's SG) and fetch everything needed to
+authenticate it. The Responder must do likewise for the
+Initiator. Both must eventually also confirm that the other
+is authorized to act on behalf of the client host behind it
+(if any).
+
+
+
+Draft 4 3 May 2001 3
+
+
+
+
+
+ Opportunistic Encryption
+
+
+An important subtlety here is that if the alternative to an
+IPsec tunnel is plaintext transmission, negative results
+must be obtained quickly. That is, the decision that no
+tunnel can be established must also be made rapidly.
+
+2.1. Packet Interception
+
+Interception of outgoing packets is relatively straightfor-
+ward in principle. It is preferable to put the intercepted
+packet on hold rather than dropping it, since higher-level
+retries are not necessarily well-timed. There is a problem
+of hosts and applications retrying during negotiations. ARP
+implementations, which face the same problem, use the
+approach of keeping the most recent packet for an as-yet-
+unresolved address, and throwing away older ones. (Incre-
+menting of request numbers etc. means that replies to older
+ones may no longer be accepted.)
+
+Is it worth intercepting incoming packets, from the outside
+world, and attempting tunnel setup based on them? No,
+unless and until a way can be devised to initiate oppor-
+tunistic encryption to a non-opportunistic responder,
+because if the other end has not initiated tunnel setup
+itself, it will not be prepared to do so at our request.
+
+Rationale: Note, however, that most incoming packets will
+promptly be followed by an outgoing packet in response!
+Conceivably it might be useful to start early stages of
+negotiation, at least as far as looking up information, in
+response to an incoming packet.
+
+Rationale: If a plaintext incoming packet indicates that the
+other end is not prepared to do opportunistic encryption, it
+might seem that this fact should be noted, to avoid consum-
+ing resources and delaying traffic in an attempt at oppor-
+tunistic setup which is doomed to fail. However, this would
+be a major security hole, since the plaintext packet is not
+authenticated; see section 2.5.
+
+2.2. Algorithm
+
+For clarity, the following defers most discussion of error
+handling to the end.
+
+Step 1. Initiator does a DNS reverse lookup on the Destina-
+ tion address, asking not for the usual PTR records,
+ but for TXT records. Meanwhile, Initiator also
+ sends a ping to the Destination, to cause any other
+ dynamic setup actions to start happening. (Ping
+ replies are disregarded; the host might not be
+ reachable with plaintext pings.)
+
+Step 2A. If at least one suitable TXT record (see section
+ 2.3) comes back, each contains a potential
+
+
+
+Draft 4 3 May 2001 4
+
+
+
+
+
+ Opportunistic Encryption
+
+
+ Responder's IP address and that Responder's public
+ key (or where to find it). Initiator picks one TXT
+ record, based on priority (see 2.3), thus picking a
+ Responder. If there was no public key in the TXT
+ record, the Initiator also starts a DNS lookup (as
+ specified by the TXT record) to get KEY records.
+
+Step 2B. If no suitable TXT record is available, and policy
+ permits, Initiator designates the Destination
+ itself as the Responder (see section 2.4). If pol-
+ icy does not permit, or the Destination is unre-
+ sponsive to the negotiation, then opportunistic
+ encryption is not possible, and Initiator gives up
+ (see section 2.5).
+
+Step 3. If there already is a keying channel to the Respon-
+ der's IP address, the Initiator uses the existing
+ keying channel; skip to step 10. Otherwise, the
+ Initiator starts an IKE Phase 1 negotiation (see
+ section 2.7 for details) with the Responder. The
+ address family of the Responder's IP address dic-
+ tates whether the keying channel and the outside of
+ the tunnel should be IPv4 or IPv6.
+
+Step 4. Responder gets the first IKE message, and responds.
+ It also starts a DNS reverse lookup on the Initia-
+ tor's IP address, for KEY records, on speculation.
+
+Step 5. Initiator gets Responder's reply, and sends first
+ message of IKE's D-H exchange (see 2.4).
+
+Step 6. Responder gets Initiator's D-H message, and
+ responds with a matching one.
+
+Step 7. Initiator gets Responder's D-H message; encryption
+ is now established, authentication remains to be
+ done. Initiator sends IKE authentication message,
+ with an FQDN identity if a reverse lookup on its
+ address will not yield a suitable KEY record.
+ (Note, an FQDN need not actually correspond to a
+ host--e.g., the DNS data for it need not include an
+ A record.)
+
+Step 8. Responder gets Initiator's authentication message.
+ If there is no identity included, Responder waits
+ for step 4's speculative DNS lookup to finish; it
+ should yield a suitable KEY record (see 2.3). If
+ there is an FQDN identity, responder discards any
+ data obtained from step 4's DNS lookup; does a for-
+ ward lookup on the FQDN, for a KEY record; waits
+ for that lookup to return; it should yield a suit-
+ able KEY record. Either way, Responder uses the
+ KEY data to verify the message's hash. Responder
+ replies with an authentication message, with an
+
+
+
+Draft 4 3 May 2001 5
+
+
+
+
+
+ Opportunistic Encryption
+
+
+ FQDN identity if a reverse lookup on its address
+ will not yield a suitable KEY record.
+
+Step 9A. (If step 2A was used.) The Initiator gets the
+ Responder's authentication message. Step 2A has
+ provided a key (from the TXT record or via DNS
+ lookup). Verify message's hash. Encrypted and
+ authenticated keying channel established, man-in-
+ middle attack precluded.
+
+Step 9B. (If step 2B was used.) The Initiator gets the
+ Responder's authentication message, which must con-
+ tain an FQDN identity (if the Responder can't put a
+ TXT in his reverse map he presumably can't do a KEY
+ either). Do forward lookup on the FQDN, get suit-
+ able KEY record, verify hash. Encrypted keying
+ channel established, man-in-middle attack pre-
+ cluded, but authentication weak (see 2.4).
+
+Step 10. Initiator initiates IKE Phase 2 negotiation (see
+ 2.7) to establish tunnel, specifying Source and
+ Destination identities as IP addresses (see 2.6).
+ The address family of those addresses also deter-
+ mines whether the inside of the tunnel should be
+ IPv4 or IPv6.
+
+Step 11. Responder gets first Phase 2 message. Now the
+ Responder finally knows what's going on! Unless
+ the specified Source is identical to the Initiator,
+ Responder initiates DNS reverse lookup on Source IP
+ address, for TXT records; waits for result; gets
+ suitable TXT record(s) (see 2.3), which should con-
+ tain either the Initiator's IP address or an FQDN
+ identity identical to that supplied by the Initia-
+ tor in step 7. This verifies that the Initiator is
+ authorized to act as SG for the Source. Responder
+ replies with second Phase 2 message, selecting
+ acceptable details (see 2.7), and establishes tun-
+ nel.
+
+Step 12. Initiator gets second Phase 2 message, establishes
+ tunnel (if he didn't already), and releases the
+ intercepted packet into it, finally.
+
+Step 13. Communication proceeds. See section 3 for what
+ happens later.
+
+As additional information becomes available, notably in
+steps 1, 2, 4, 8, 9, 11, and 12, there is always a possibil-
+ity that local policy (e.g., access limitations) might pre-
+vent further progress. Whenever possible, at least attempt
+to inform the other end of this.
+
+
+
+
+
+Draft 4 3 May 2001 6
+
+
+
+
+
+ Opportunistic Encryption
+
+
+At any time, there is a possibility of the negotiation fail-
+ing due to unexpected responses, e.g. the Responder not
+responding at all or rejecting all Initiator's proposals.
+If multiple SGs were found as possible Responders, the Ini-
+tiator should try at least one more before giving up. The
+number tried should be influenced by what the alternative
+is: if the traffic will otherwise be discarded, trying the
+full list is probably appropriate, while if the alternative
+is plaintext transmission, it might be based on how long the
+tries are taking. The Initiator should try as many as it
+reasonably can, ideally all of them.
+
+There is a sticky problem with timeouts. If the Responder
+is down or otherwise inaccessible, in the worst case we
+won't hear about this except by not getting responses. Some
+other, more pathological or even evil, failure cases can
+have the same result. The problem is that in the case where
+plaintext is permitted, we want to decide whether a tunnel
+is possible quickly. There is no good solution to this,
+alas; we just have to take the time and do it right. (Pass-
+ing plaintext meanwhile looks attractive at first glance...
+but exposing the first few seconds of a connection is often
+almost as bad as exposing the whole thing. Worse, if the
+user checks the status of the connection, after that brief
+window it looks secure!)
+
+The flip side of waiting for a timeout is that all other
+forms of feedback, e.g. ``host not reachable'', arguably
+should be ignored, because in the absence of authenticated
+ICMP, you cannot trust them!
+
+Rationale: An alternative, sometimes suggested, to the use
+of explicit DNS records for SG discovery is to directly
+attempt IKE negotiation with the destination host, and
+assume that any relevant SG will be on the packet path, will
+intercept the IKE packets, and will impersonate the destina-
+tion host for the IKE negotiation. This is superficially
+attractive but is a very bad idea. It assumes that routing
+is stable throughout negotiation, that the SG is on the
+plaintext-packets path, and that the destination host is
+routable (yes, it is possible to have (private) DNS data for
+an unroutable host). Playing extra games in the plaintext-
+packet path hurts performance and can be expected to be
+unpopular. Various difficulties ensue when there are multi-
+ple SGs along the path (there is already bad experience with
+this, in RSVP), and the presence of even one can make it
+impossible to do IKE direct to the host when that is what's
+wanted. Worst of all, such impersonation breaks the IP net-
+work model badly, making problems difficult to diagnose and
+impossible to work around (and there is already bad experi-
+ence with this, in areas like web caching).
+
+Rationale: (Step 1.) Dynamic setup actions might include
+establishment of demand-dialed links. These might be
+
+
+
+Draft 4 3 May 2001 7
+
+
+
+
+
+ Opportunistic Encryption
+
+
+present anywhere along the path, so one cannot rely on out-
+of-band communication at the Initiator to trigger them.
+Hence the ping.
+
+Rationale: (Step 2.) In many cases, the IP address on the
+intercepted packet will be the result of a name lookup just
+done. Inverse queries, an obscure DNS feature from the dis-
+tant past, in theory can be used to ask a DNS server to
+reverse that lookup, giving the name that produced the
+address. This is not the same as a reverse lookup, and the
+difference can matter a great deal in cases where a host
+does not control its reverse map (e.g., when the host's IP
+address is dynamically assigned). Unfortunately, inverse
+queries were never widely implemented and are now considered
+obsolete. Phooey.
+
+Ahem: Support for a small subset of this admittedly-obscure
+feature would be useful. Unfortunately, it seems unlikely.
+
+Rationale: (Step 3.) Using only IP addresses to decide
+whether there is already a relevant keying channel avoids
+some difficult problems. In particular, it might seem that
+this should be based on identities, but those are not known
+until very late in IKE Phase 1 negotiations.
+
+Rationale: (Step 4.) The DNS lookup is done on speculation
+because the data will probably be useful and the lookup can
+be done in parallel with IKE activity, potentially speeding
+things up.
+
+Rationale: (Steps 7 and 8.) If an SG does not control its
+reverse map, there is no way it can prove its right to use
+an IP address, but it can nevertheless supply both an iden-
+tity (as an FQDN) and proof of its right to use that iden-
+tity. This is somewhat better than nothing, and may be
+quite useful if the SG is representing a client host which
+can prove its right to its IP address. (For example, a
+fixed-address subnet might live behind an SG with a dynami-
+cally-assigned address; such an SG has to be the Initiator,
+not the Responder, so the subnet's TXT records can contain
+FQDN identities, but with that restriction, this works.) It
+might sound like this would permit some man-in-the-middle
+attacks in important cases like Road Warrior, but the RW can
+still do full authentication of the home base, so a man in
+the middle cannot successfully impersonate home base, and
+the D-H exchange doesn't work unless the man in the middle
+impersonates both ends.
+
+Rationale: (Steps 7 and 8.) Another situation where proof
+of the right to use an identity can be very useful is when
+access is deliberately limited. While opportunistic encryp-
+tion is intended as a general-purpose connection mechanism
+between strangers, it may well be convenient for prearranged
+connections to use the same mechanism.
+
+
+
+Draft 4 3 May 2001 8
+
+
+
+
+
+ Opportunistic Encryption
+
+
+Rationale: (Steps 7 and 8.) FQDNs as identities are avoided
+where possible, since they can involve synchronous DNS
+lookups.
+
+Rationale: (Step 11.) Note that only here, in Phase 2, does
+the Responder actually learn who the Source and Destination
+hosts are. This unfortunately demands a synchronous DNS
+lookup to verify that the Initiator is authorized to repre-
+sent the Source, unless they are one and the same. This and
+the initial TXT lookup are the only synchronous DNS lookups
+absolutely required by the algorithm, and they appear to be
+unavoidable.
+
+Rationale: While it might seem unlikely that a refusal to
+cooperate from one SG could be remedied by trying another--
+presumably they all use the same policies--it's conceivable
+that one might be misconfigured. Preferably they should all
+be tried, but it may be necessary to set some limits on this
+if alternatives exist.
+
+2.3. DNS Records
+
+Gateway discovery and key lookup are based on TXT and KEY
+DNS records. The TXT record specifies IP address or other
+identity of a host's SG, and possibly supplies its public
+key as well, while the KEY record supplies public keys not
+found in TXT records.
+
+2.3.1. TXT
+
+Opportunistic-encryption SG discovery uses TXT records with
+the content:
+
+ X-IPsec-Gateway(nnn)=iii kkk
+
+following RFC 1464 attribute/value notation. Records which
+do not contain an ``='', or which do not have exactly the
+specified form to the left of it, are ignored. (Near misses
+perhaps should be reported.)
+
+The nnn is an unsigned integer which will fit in 16 bits,
+specifying an MX-style preference (lower number = stronger
+preference) to control the order in which multiple SGs are
+tried. If there are ties, pick one, randomly enough that
+the choice will probably be different each time. The pref-
+erence field is not optional; use ``0'' if there is no mean-
+ingful preference ordering.
+
+The iii part identifies the SG. Normally this is a dotted-
+decimal IPv4 address or a colon-hex IPv6 address. The sole
+exception is if the SG has no fixed address (see 2.4) but
+the host(s) behind it do, in which case iii is of the form
+``@fqdn'', where fqdn is the FQDN that the SG will use to
+identify itself (in step 7 of section 2.2); such a record
+
+
+
+Draft 4 3 May 2001 9
+
+
+
+
+
+ Opportunistic Encryption
+
+
+cannot be used for SG discovery by an Initiator, but can be
+used for SG verification (step 11 of 2.2) by a Responder.
+
+The kkk part is optional. If it is present, it is an RSA-
+MD5 public key in base-64 notation, as in the text form of
+an RFC 2535 KEY record. If it is not present, this speci-
+fies that the public key can be found in a KEY record
+located based on the SG's identification: if iii is an IP
+address, do a reverse lookup on that address, else do a for-
+ward lookup on the FQDN.
+
+Rationale: While it is unusual for a reverse lookup to go
+for records other than PTR records (or possibly CNAME
+records, for RFC 2317 classless delegation), there's no rea-
+son why it can't. The TXT record is a temporary stand-in
+for (we hope, someday) a new DNS record for SG identifica-
+tion and keying. Keeping the setup process fast requires
+minimizing the number of DNS lookups, hence the desire to
+put all the information in one place.
+
+Rationale: The use of RFC 1464 notation avoids collisions
+with other uses of TXT records. The ``X-'' in the attribute
+name indicates that this format is tentative and experimen-
+tal; this design will probably need modification after ini-
+tial experiments. The format is chosen with an eye on even-
+tual binary encoding. Note, in particular, that the TXT
+record normally contains the address of the SG, not (repeat,
+not) its name. Name-to-address conversion is the job of
+whatever generates the TXT record, which is expected to be a
+program, not a human--this is conceptually a binary record,
+temporarily using a text encoding. The ``@fqdn'' form of
+the SG identity is for specialized uses and is never mapped
+to an address.
+
+Ahem: A DNS TXT record contains one or more character
+strings, but RFC 1035 does not describe exactly how a multi-
+string TXT record is interpreted. This is relevant because
+a string can be at most 255 characters, and public keys can
+exceed this. Empirically, the standard pattern is that each
+string which is both less than 255 characters and not the
+final string of the record should have a blank appended to
+it, and the strings of the record should then be concate-
+nated. (This observation is based on how BIND 8 transforms
+a TXT record from text to DNS binary.)
+
+2.3.2. KEY
+
+An opportunistic-encryption KEY record is an Authentication-
+permitted, Entity (host), non-Signatory, IPsec, RSA/MD5
+record (that is, its first four bytes are 0x42000401), as
+per RFCs 2535 and 2537. KEY records with other flags, pro-
+tocol, or algorithm values are ignored.
+
+
+
+
+
+Draft 4 3 May 2001 10
+
+
+
+
+
+ Opportunistic Encryption
+
+
+Rationale: Unfortunately, the public key has to be associ-
+ated with the SG, not the client host behind it. The
+Responder does not know which client it is supposed to be
+representing, or which client the Initiator is representing,
+until far too late.
+
+Ahem: Per-client keys would reduce vulnerability to key com-
+promise, and simplify key changes, but they would require
+changes to IKE Phase 1, to separately identify the SG and
+its initial client(s). (At present, the client identities
+are not known to the Responder until IKE Phase 2.) While
+the current IKE standard does not actually specify (!) who
+is being identified by identity payloads, the overwhelming
+consensus is that they identify the SG, and as seen earlier,
+this has important uses.
+
+2.3.3. Summary
+
+For reference, the minimum set of DNS records needed to make
+this all work is either:
+
+1. TXT in Destination reverse map, identifying Responder
+ and providing public key.
+
+2. KEY in Initiator reverse map, providing public key.
+
+3. TXT in Source reverse map, verifying relationship to
+ Initiator.
+
+or:
+
+1. TXT in Destination reverse map, identifying Responder.
+
+2. KEY in Responder reverse map, providing public key.
+
+3. KEY in Initiator reverse map, providing public key.
+
+4. TXT in Source reverse map, verifying relationship to
+ Initiator.
+
+Slight complications ensue for dynamic addresses, lack of
+control over reverse maps, etc.
+
+2.3.4. Implementation
+
+In the long run, we need either a tree of trust or a web of
+trust, so we can trust our DNS data. The obvious approach
+for DNS is a tree of trust, but there are various practical
+problems with running all of this through the root servers,
+and a web of trust is arguably more robust anyway. This is
+logically independent of opportunistic encryption, and a
+separate design proposal will be prepared.
+
+
+
+
+
+Draft 4 3 May 2001 11
+
+
+
+
+
+ Opportunistic Encryption
+
+
+Interim stages of implementation of this will require a bit
+of thought. Notably, we need some way of dealing with the
+lack of fully signed DNSSEC records right away. Without
+user interaction, probably the best we can do is to remember
+the results of old fetches, compare them to the results of
+new fetches, and complain and disbelieve all of it if
+there's a mismatch. This does mean that somebody who gets
+fake data into our very first fetch will fool us, at least
+for a while, but that seems an acceptable tradeoff. (Obvi-
+ously there needs to be a way to manually flush the remem-
+bered results for a specific host, to permit deliberate
+changes.)
+
+2.4. Responders Without Credentials
+
+In cases where the Destination simply does not control its
+DNS reverse-map entries, there is no verifiable way to
+determine a suitable SG. This does not make communication
+utterly impossible, though.
+
+Simply attempting negotiation directly with the host is a
+last resort. (An aggressive implementation might wish to
+attempt it in parallel, rather than waiting until other
+options are known to be unavailable.) In particular, in
+many cases involving dynamic addresses, it will work. It
+has the disadvantage of delaying the discovery that oppor-
+tunistic encryption is entirely impossible, but the case
+seems common enough to justify the overhead.
+
+However, there are policy issues here either way, because it
+is possible to impersonate such a host. The host can supply
+an FQDN identity and verify its right to use that identity,
+but except by prearrangement, there is no way to verify that
+the FQDN is the right one for that IP address. (The data
+from forward lookups may be controlled by people who do not
+own the address, so it cannot be trusted.) The encryption
+is still solid, though, so in many cases this may be useful.
+
+2.5. Failure of Opportunism
+
+When there is no way to do opportunistic encryption, a pol-
+icy issue arises: whether to put in a bypass (which allows
+plaintext traffic through) or a block (which discards it,
+perhaps with notification back to the sender). The choice
+is very much a matter of local policy, and may depend on
+details such as the higher-level protocol being used. For
+example, an SG might well permit plaintext HTTP but forbid
+plaintext Telnet, in which case both a block and a bypass
+would be set up if opportunistic encryption failed.
+
+A bypass/block must, in practice, be treated much like an
+IPsec tunnel. It should persist for a while, so that high-
+overhead processing doesn't have to be done for every
+packet, but should go away eventually to return resources.
+
+
+
+Draft 4 3 May 2001 12
+
+
+
+
+
+ Opportunistic Encryption
+
+
+It may be simplest to treat it as a degenerate tunnel. It
+should have a relatively long lifetime (say 6h) to keep the
+frequency of negotiation attempts down, except in the case
+where the other SG simply did not respond to IKE packets,
+where the lifetime should be short (say 10min) because the
+other SG is presumably down and might come back up again.
+(Cases where the other SG responded to IKE with unauthenti-
+cated error reports like ``port unreachable'' are border-
+line, and might deserve to be treated as an intermediate
+case: while such reports cannot be trusted unreservedly, in
+the absence of any other response, they do give some reason
+to suspect that the other SG is unable or unwilling to par-
+ticipate in opportunistic encryption.)
+
+As noted in section 2.1, one might think that arrival of a
+plaintext incoming packet should cause a bypass/block to be
+set up for its source host: such a packet is almost always
+followed by an outgoing reply packet; the incoming packet is
+clear evidence that opportunistic encryption is not avail-
+able at the other end; attempting it will waste resources
+and delay traffic to no good purpose. Unfortunately, this
+means that anyone out on the Internet who can forge a source
+address can prevent encrypted communication! Since their
+source addresses are not authenticated, plaintext packets
+cannot be taken as evidence of anything, except perhaps that
+communication from that host is likely to occur soon.
+
+There needs to be a way for local administrators to remove a
+bypass/block ahead of its normal expiry time, to force a
+retry after a problem at the other end is known to have been
+fixed.
+
+2.6. Subnet Opportunism
+
+In principle, when the Source or Destination host belongs to
+a subnet and the corresponding SG is willing to provide tun-
+nels to the whole subnet, this should be done. There is no
+extra overhead, and considerable potential for avoiding
+later overhead if similar communication occurs with other
+members of the subnet. Unfortunately, at the moment, oppor-
+tunistic tunnels can only have degenerate subnets (single
+hosts) at their ends. (This does, at least, set up the key-
+ing channel, so that negotiations for tunnels to other hosts
+in the same subnets will be considerably faster.)
+
+The crucial problem is step 11 of section 2.2: the Responder
+must verify that the Initiator is authorized to represent
+the Source, and this is impossible for a subnet because
+there is no way to do a reverse lookup on it. Information
+in DNS records for a name or a single address cannot be
+trusted, because they may be controlled by people who do not
+control the whole subnet.
+
+
+
+
+
+Draft 4 3 May 2001 13
+
+
+
+
+
+ Opportunistic Encryption
+
+
+Ahem: Except in the special case of a subnet masked on a
+byte boundary (in which case RFC 1035's convention of an
+incomplete in-addr.arpa name could be used), subnet lookup
+would need extensions to the reverse-map name space, perhaps
+along the lines of that commonly done for RFC 2317 delega-
+tion. IPv6 already has suitable name syntax, as in RFC
+2874, but has no specific provisions for subnet entries in
+its reverse maps. Fixing all this is is not conceptually
+difficult, but is logically independent of opportunistic
+encryption, and will be proposed separately.
+
+A less-troublesome problem is that the Initiator, in step 10
+of 2.2, must know exactly what subnet is present on the
+Responder's end so he can propose a tunnel to it. This
+information could be included in the TXT record of the Des-
+tination (it would have to be verified with a subnet lookup,
+but that could be done in parallel with other operations).
+The Initiator presumably can be configured to know what sub-
+net(s) are present on its end.
+
+2.7. Option Settings
+
+IPsec and IKE have far too many useless options, and a few
+useful ones. IKE negotiation is quite simplistic, and can-
+not handle even simple discrepancies between the two SGs.
+So it is necessary to be quite specific about what should be
+done and what should be proposed, to guarantee interoper-
+ability without prearrangement or other negotiation proto-
+cols.
+
+Rationale: The prohibition of other negotiations is simply
+because there is no time. The setup algorithm (section 2.2)
+is lengthy already.
+
+[Open question: should opportunistic IKE use a different
+port than normal IKE?]
+
+Somewhat arbitrarily and tentatively, opportunistic SGs must
+support Main Mode, Oakley group 5 for D-H, 3DES encryption
+and MD5 authentication for both ISAKMP and IPsec SAs,
+RSA/MD5 digital-signature authentication with keys between
+2048 and 8192 bits, and ESP doing both encryption and
+authentication. They must do key PFS in Quick Mode, but not
+identity PFS. They may support IPComp, preferably using
+Deflate, but must not insist on it. They may support AES as
+an alternative to 3DES, but must not insist on it.
+
+Rationale: Identity PFS essentially requires establishing a
+complete new keying channel for each new tunnel, but key PFS
+just does a new Diffie-Hellman exchange for each rekeying,
+which is relatively cheap.
+
+Keying channels must remain in existence at least as long as
+any tunnel created with them remains (they are not costly,
+
+
+
+Draft 4 3 May 2001 14
+
+
+
+
+
+ Opportunistic Encryption
+
+
+and keeping the management path up and available simplifies
+various issues). See section 3.1 for related issues. Given
+the use of key PFS, frequent rekeying does not seem critical
+here. In the absence of strong reason to do otherwise, the
+Initiator should propose rekeying at 8hr-or-1MB. The
+Responder must accept any proposal which specifies a rekey-
+ing time between 1hr and 24hr inclusive and a rekeying vol-
+ume between 100KB and 10MB inclusive.
+
+Given the short expected useful life of most tunnels (see
+section 3.1), very few of them will survive long enough to
+be rekeyed. In the absence of strong reason to do other-
+wise, the Initiator should propose rekeying at 1hr-or-100MB.
+The Responder must accept any proposal which specifies a
+rekeying time between 10min and 8hr inclusive and a rekeying
+volume between 1MB and 1000MB inclusive.
+
+It is highly desirable to add some random jitter to the
+times of actual rekeying attempts, to break up ``convoys''
+of rekeying events; this and certain other aspects of robust
+rekeying practice will be the subject of a separate design
+proposal.
+
+Rationale: The numbers used here for rekeying intervals are
+chosen quite arbitrarily and should be re-assessed after
+some implementation experience is gathered.
+
+3. Renewal and Teardown
+
+3.1. Aging
+
+When to tear tunnels down is a bit problematic, but if we're
+setting up a potentially unbounded number of them, we have
+to tear them down somehow sometime.
+
+Set a short initial tentative lifespan, say 1min, since most
+net flows in fact last only a few seconds. When that
+expires, look to see if the tunnel is still in use (defini-
+tion: has had traffic, in either direction, in the last half
+of the tentative lifespan). If so, assign it a somewhat
+longer tentative lifespan, say 20min, after which, look
+again. If not, close it down. (This tentative lifespan is
+independent of rekeying; it is just the time when the tun-
+nel's future is next considered. This should happen reason-
+ably frequently, unlike rekeying, which is costly and
+shouldn't be too frequent.) Multi-step backoff algorithms
+are not worth the trouble; looking every 20min doesn't seem
+onerous.
+
+If the security gateway and the client host are one and the
+same, tunnel teardown decisions might wish to pay attention
+to TCP connection status, as reported by the local TCP
+layer. A still-open TCP connection is almost a guarantee
+that more traffic is coming, while the demise of the only
+
+
+
+Draft 4 3 May 2001 15
+
+
+
+
+
+ Opportunistic Encryption
+
+
+TCP connection through a tunnel is a strong hint that none
+is. If the SG and the client host are separate machines,
+though, tracking TCP connection status requires packet
+snooping, which is complicated and probably not worthwhile.
+
+IKE keying channels likewise are torn down when it appears
+the need has passed. They always linger longer than the
+last tunnel they administer, in case they are needed again;
+the cost of retaining them is low. Other than that, unless
+the number of keying channels on the SG gets large, the SG
+should simply retain all of them until rekeying time, since
+rekeying is the only costly event. When about to rekey a
+keying channel which has no current tunnels, note when the
+last actual keying-channel traffic occurred, and close the
+keying channel down if it wasn't in the last, say, 30min.
+When rekeying a keying channel (or perhaps shortly before
+rekeying is expected), Initiator and Responder should re-
+fetch the public keys used for SG authentication, against
+the possibility that they have changed or disappeared.
+
+See section 2.7 for discussion of rekeying intervals.
+
+Given the low user impact of tearing down and rebuilding a
+connection (a tunnel or a keying channel), rekeying attempts
+should not be too persistent: one can always just rebuild
+when needed, so heroic efforts to preserve an existing con-
+nection are unnecessary. Say, try every 10s for a minute
+and every minute for 5min, and then give up and declare the
+connection (and all other connections to that IKE peer)
+dead.
+
+Rationale: In future, more sophisticated, versions of this
+protocol, examining the initial packet might permit a more
+intelligent guess at the tunnel's useful life. HTTP connec-
+tions in particular are notoriously bursty and repetitive.
+
+Rationale: Note that rekeying a keying connection basically
+consists of building a new keying connection from scratch,
+using IKE Phase 1, and abandoning the old one.
+
+3.2. Teardown and Cleanup
+
+Teardown should always be coordinated with the other end.
+This means interpreting and sending Delete notifications.
+
+On receiving a Delete for the outbound SAs of a tunnel (or
+some subset of them), tear down the inbound ones too, and
+notify the other end with a Delete. Tunnels need to be con-
+sidered as bidirectional entities, even though the low-level
+protocols don't think of them that way.
+
+When the deletion is initiated locally, rather than as a
+response to a received Delete, send a Delete for (all) the
+inbound SAs of a tunnel. If no responding Delete is
+
+
+
+Draft 4 3 May 2001 16
+
+
+
+
+
+ Opportunistic Encryption
+
+
+received for the outbound SAs, try re-sending the original
+Delete. Three tries spaced 10s apart seems a reasonable
+level of effort. (Indefinite persistence is not necessary;
+whether the other end isn't cooperating because it doesn't
+feel like it, or because it is down/disconnected/etc., the
+problem will eventually be cleared up by other means.)
+
+After rekeying, transmission should switch to using the new
+SAs (ISAKMP or IPsec) immediately, and the old leftover SAs
+should be cleared out promptly (and Deletes sent) rather
+than waiting for them to expire. This reduces clutter and
+minimizes confusion.
+
+Since there is only one keying channel per remote IP
+address, the question of whether a Delete notification has
+appeared on a ``suitable'' keying channel does not arise.
+
+Rationale: The pairing of Delete notifications effectively
+constitutes an acknowledged Delete, which is highly desir-
+able.
+
+3.3. Outages and Reboots
+
+Tunnels sometimes go down because the other end crashes, or
+disconnects, or has a network link break, and there is no
+notice of this in the general case. (Even in the event of a
+crash and successful reboot, other SGs don't hear about it
+unless the rebooted SG has specific reason to talk to them
+immediately.) Over-quick response to temporary network out-
+ages is undesirable... but note that a tunnel can be torn
+down and then re-established without any user-visible effect
+except a pause in traffic, whereas if one end does reboot,
+the other end can't get packets to it at all (except via
+IKE) until the situation is noticed. So a bias toward quick
+response is appropriate, even at the cost of occasional
+false alarms.
+
+Heartbeat mechanisms are somewhat unsatisfactory for this.
+Unless they are very frequent, which causes other problems,
+they do not detect the problem promptly.
+
+Ahem: What is really wanted is authenticated ICMP. This
+might be a case where public-key encryption/authentication
+of network packets is the right thing to do, despite the
+expense.
+
+In the absence of that, a two-part approach seems warranted.
+
+First, when an SG receives an IPsec packet that is addressed
+to it, and otherwise appears healthy, but specifies an
+unknown SA and is from a host that the receiver currently
+has no keying channel to, the receiver must attempt to
+inform the sender via an IKE Initial-Contact notification
+(necessarily sent in plaintext, since there is no suitable
+
+
+
+Draft 4 3 May 2001 17
+
+
+
+
+
+ Opportunistic Encryption
+
+
+keying channel). This must be severely rate-limited on both
+ends; one notification per SG pair per minute seems ample.
+
+Second, there is an obvious difficulty with this: the Ini-
+tial-Contact notification is unauthenticated and cannot be
+trusted. So it must be taken as a hint only: there must be
+a way to confirm it.
+
+What is needed here is something that's desirable for debug-
+ging and testing anyway: an IKE-level ping mechanism. Ping-
+ing direct at the IP level instead will not tell us about a
+crash/reboot event. Sending pings through tunnels has vari-
+ous complications (they should stop at the far mouth of the
+tunnel instead of going on to a subnet; they should not
+count against idle timers; etc.). What is needed is a con-
+tinuity check on a keying channel. (This could also be used
+as a heartbeat, should that seem useful.)
+
+IKE Ping delivery need not be reliable, since the whole
+point of a ping is simply to provoke an acknowledgement.
+They should preferably be authenticated, but it is not clear
+that this is absolutely necessary, although if they are not
+they need encryption plus a timestamp or a nonce, to foil
+replay mischief. How they are implemented is a secondary
+issue, and a separate design proposal will be prepared.
+
+Ahem: Some existing implementations are already using (pri-
+vate) notify value 30000 (``LIKE_HELLO'') as ping and (pri-
+vate) notify value 30002 (``SHUT_UP'') as ping reply.
+
+If an IKE Ping gets no response, try some (say 8) IP pings,
+spaced a few seconds apart, to check IP connectivity; if one
+comes back, try another IKE Ping; if that gets no response,
+the other end probably has rebooted, or otherwise been re-
+initialized, and its tunnels and keying channel(s) should be
+torn down.
+
+In a similar vein, giving limited rekeying persistence, a
+short network outage could take some tunnels down without
+disrupting others. On receiving a packet for an unknown SA
+from a host that a keying channel is currently open to, send
+that host a Invalid-SPI notification for that SA. The other
+host can then tear down the half-torn-down tunnel, and nego-
+tiate a new tunnel for the traffic it presumably still wants
+to send.
+
+Finally, it would be helpful if SGs made some attempt to
+deal intelligently with crashes and reboots. A deliberate
+shutdown should include an attempt to notify all other SGs
+currently connected by keying channels, using Deletes, that
+communication is about to fail. (Again, these will be taken
+as teardowns; attempts by the other SGs to negotiate new
+tunnels as replacements should be ignored at this point.)
+And when possible, SGs should attempt to preserve
+
+
+
+Draft 4 3 May 2001 18
+
+
+
+
+
+ Opportunistic Encryption
+
+
+information about currently-connected SGs in non-volatile
+storage, so that after a crash, an Initial-Contact can be
+sent to previous partners to indicate loss of all previ-
+ously-established connections.
+
+4. Conclusions
+
+This design appears to achieve the objective of setting up
+encryption with strangers. The authentication aspects also
+seem adequately addressed if the destination controls its
+reverse-map DNS entries and the DNS data itself can be reli-
+ably authenticated as having originated from the legitimate
+administrators of that subnet/FQDN. The authentication sit-
+uation is less satisfactory when DNS is less helpful, but it
+is difficult to see what else could be done about it.
+
+5. References
+
+[TBW]
+
+6. Appendix: Separate Design Proposals TBW
+
+o How can we build a web of trust with DNSSEC? (See sec-
+ tion 2.3.4.)
+
+o How can we extend DNS reverse lookups to permit reverse
+ lookup on a subnet? (Both address and mask must appear
+ in the name to be looked up.) (See section 2.6.)
+
+o How can rekeying be done as robustly as possible? (At
+ least partly, this is just documenting current FreeS/WAN
+ practice.) (See section 2.7.)
+
+o How should IKE Pings be implemented? (See section 3.3.)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Draft 4 3 May 2001 19
+
+
diff --git a/doc/opportunism.howto b/doc/opportunism.howto
new file mode 100644
index 000000000..14b5ed5a2
--- /dev/null
+++ b/doc/opportunism.howto
@@ -0,0 +1,415 @@
+FreeS/WAN Opportunism HowTo
+===========================
+
+RCSID $Id: opportunism.howto,v 1.1 2004/03/15 20:35:21 as Exp $
+
+D. Hugh Redelmeier
+
+
+FreeS/WAN, the LINUX IPSEC implementation, is intended to allow
+systems to connect through secure tunnels with or without prearrangement.
+We use the term "Opportunism" to describe tunnels set up without
+prearrangement. This HowTo will show you how to set your system up
+for Opportunism.
+
+You are expected to already have built and used FreeS/WAN. Much more
+information about FreeS/WAN is provided at http://www.freeswan.org.
+This document is only intended to describe the support for
+opportunism. The features described here are available in FreeS/WAN
+version 1.91 or later (there were important bugs up until 1.95).
+
+For a more complete description of the design of Opportunism, see our
+paper "Opportunistic Encryption" (available as opportunism.spec in
+the same directory as this document).
+
+
+Steps
+=====
+
+- Understand what you are attempting. Security requires care.
+ Problems are hard to untangle. Be sure to read the last section
+ "Important Limitations".
+
+- Install FreeS/WAN (version 1.91 or later).
+
+- Add appropriate DNS records to your reverse-map domains.
+
+- Add suitable conns to /etc/ipsec.conf.
+
+- Try it out: start it, monitor it, fix it.
+
+- Now you understand the system better, reread "Important Limitations"
+
+These steps are also an outline of this document.
+
+
+Theory
+======
+
+FreeS/WAN runs on a machine that we will call a "Security Gateway".
+Usually this machine is a gateway to the internet. It may be that the
+only machine for which it provides gateway services is itself, but
+that is just a special case -- we will still call it a Security
+Gateway.
+
+A FreeS/WAN Security Gateway implements secure tunnels to other
+Security Gateways. One problem is to arrange for these tunnels to be
+created and used. If opportunism is enabled, a Security Gateway
+running FreeS/WAN will intercept the first outbound packet to a
+particular destination (IP address), and try to negotiate a security
+tunnel suitable for traffic to that destination.
+
+To make this work going the other way, the Security Gateway must be
+willing to negotiate with peers trying to protect traffic initiated
+from their side.
+
+The first novel problem is that our Security Gateway needs to discover
+the IP address of the other Security Gateway for the packet that
+prompted the negotiation. Oh, and quickly discover if there is none
+-- that negotiation will be impossible.
+
+The second novel problem is that our Security Gateway needs to
+authenticate the other Security Gateway. This authentication needs to
+ensure that the other Security Gateway is who it claims to be AND that
+it is authorized to represent the client for which it claims to be the
+gateway.
+
+The roles in a particular negotiation are:
+ Source----Initiator----...----Responder----Destination
+
+The Source and Destination are endpoints of the traffic that is to be
+protected. The Source is the one that happened to send the first
+packet of traffic. Neither needs to be aware of IPSEC or FreeS/WAN.
+That is the job of their respective Security Gateways, Initiator and
+Responder. The names "Initiator" and "Responder" match those used in
+the IPSEC standards for IKE negotiation. Remember that Source and
+Initiator could be the same machine; similarly, Destination and
+Responder could be the same. All traffic from Source or Destination
+must flow through their Security Gateways if it is to be considered
+for protection. These roles are fluid -- they can be different for
+each negotiation.
+
+We use the DNS (the Domain Name System) as a distributed database to
+publish the required information.
+
+
+DNS Records Required
+====================
+
+See section 2.3 of "Opportunistic Encryption" for a fuller
+explanation.
+
+Generally, we need to add records to the reverse-map DNS entries for
+the client machine and its Security Gateway machine. There are
+special cases that are exceptions.
+
+A Security Gateway that is going to initiate an Opportunistic
+negotiation needs to provide a way for the Responding SG to find a
+public key for the Initiator to allow authentication. This is
+accomplished by putting the public key in a KEY record in the
+reverse-map of the Initiator. Conveniently, the KEY record can
+be generated by the ipsec_showhostkey(8) command.
+
+ ipsec showhostkey
+
+Here is an example of the output, with many characters of the key
+itself left out:
+
+ ; RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ xy.example.com. IN KEY 0x4200 4 1 AQOF8tZ2...+buFuFn/
+
+=> Copy the output of the command into the zone information for the
+ reverse-map of the Security Gateway's public interface.
+
+Each client that is to be protected by Opportunistic Encryption must
+include a special TXT record in its reverse-map. The
+ipsec_showhostkey(8) command can create this too. Remember: this
+command must be run on the Security Gateway where the ipsec.secrets
+file resides. You must tell the command what IP address to put in the
+TXT record. The IP address is that of the Security Gateway.
+
+ ipsec showhostkey --txt 10.11.12.13
+
+This command might produce the output:
+
+ ; RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ IN TXT "X-IPsec-Server(10)=10.11.12.13 AQOF8tZ2...+buFuFn/"
+
+- The quotes matter: this is a single string, as far as DNS is
+ concerned.
+
+- The X-IPsec-Server is a prefix that signifies that the TXT record
+ contains Opportunism configuration information.
+
+- The (10) specifies a precedence for this record. This is similar
+ to MX record preferences. Lower numbers have stronger preference.
+
+- 10.11.12.13 specifies the IP address of the Security Gateway for
+ this machine.
+
+- AQOF8tZ2...+buFuFn/ is the (shortened) encoding of the RSA Public
+ key of the Security Gateway.
+
+=> Added this output to the zone information for the reverse-map for
+ each client machine. This gets a bit dull and repetitive.
+
+Unfortunately, not every administrator has control over the contents
+of the reverse-map. The only case where we can work around this is
+where the Initiator has no suitable reverse map. In this case, the
+Source's TXT record gives @FQDN ("Fully Qualified Domain Name") in
+place of its Security Gateway's IP address. This FQDN must match the
+ID-payload used by the Initiator. Furthermore, a forward lookup for a
+KEY record on the FQDN must yield the Initiator's public key.
+
+If the Source's IP address is the same as the Initiator's IP address,
+the Responder will assume that the Initiator is authorized to talk for
+the Source (itself!). In this case, the Responder won't try to fetch
+the Source's TXT record from the reverse map for the Source's IP
+address.
+
+These two features can be combined. If the Source and the Initiator
+are the same (i.e. the Security Gateway is protecting itself), and the
+Initiator uses a @FQDN ID (leftid=@example.com), then the
+administrator of that machine need only have installed a KEY record in
+the FQDN domain -- he need not control any reverse map.
+
+Obscure fact: the forward lookup is only done by a Responder, and then
+only when the Initiator's ID payload specifies the FQDN. There is no
+provision for a Responder with no control over its reverse-map.
+
+Beware: DNS changes sometimes take a long time to propagate.
+
+
+Configuring FreeS/WAN
+=====================
+
+To enable opportunism, you must include a suitable conn in
+/etc/ipsec.conf and you must enable it.
+
+A suitable conn looks roughly like an ordinary conn. It more closely
+resembles a Road Warrior conn (a Road Warrior conn is one that has a
+wildcard %any specified as the other Security Gateway). But in the
+Opportunistic case, both the other Security Gateway AND its client are
+unknown ahead of time.
+
+conn client-to-anyone # for our client subnet
+ leftsubnet=10.3.2.1.0/24 # any single client in our subnet
+ also=sg-to-anyone # rest is same as for SG
+
+conn sg-to-anyone # for our Security Gateway
+ left=%defaultroute # our SG (defaults leftnexthop too)
+ right=%opportunistic
+ authby=rsasig # almost always the right choice
+ keyingtries=2 # don't be persistent -- peer might disappear
+ auto=route # enable at ipsec startup
+
+(%defaultroute only works if you have specified
+interfaces=%defaultroute. Since this isn't the topic of the howto,
+you will have to look at the other documentation to find out how to
+handle other cases.)
+
+You can have any number of opportunistic conns, but generally it only
+makes sense to have one for each client subnet and one for the
+Security Gateway itself.
+
+Currently only one interface may be used for opportunism: Pluto knows
+nothing about routing, so would be unable to choose amongst several.
+Almost certainly our side's nexthop must be predetermined
+(%defaultroute will do that).
+
+Note: the routing done for outbound Opportunism will catch any packets
+not covered by a more specific route. This is what you want for
+packets that are also covered by an eroute. But packets caught by the
+route and not an eroute will be subject to the no-eroute policy of
+KLIPS, which defaults to %drop. Remember that routing ignores the
+packet's source address, but erouting pays attention to it. So if
+Opportunism is enabled, it is best to provide for it covering all IP
+addresses behind or on the Security Gateway.
+
+To enable these conns for inbound opportunistic negotiation, they must be
+--added. auto=add would accomplish this at ipsec startup, but if you cannot
+wait:
+ ipsec auto --add sg-to-anyone
+ ipsec auto --add client-to-anyone
+
+To enable these conns for outbound opportunistic negotiation, they must
+be both --added and --routed. Outbound packets will then be trapped
+and will trigger negotiation. auto=route would cause this to happen
+at startup, but if you wish to do this at another time:
+ ipsec auto --add sg-to-anyone
+ ipsec auto --add client-to-anyone
+ ipsec auto --route sg-to-anyone
+ ipsec auto --route client-to-anyone
+
+
+Getting DNS Through
+===================
+
+There is a serious chicken-and-egg problem. Outbound Opportunism blocks
+communication with an IP address until Pluto discovers whether that IP
+address can have an IPSEC connection negotiated. This discovery takes
+DNS queries. These DNS queries might involve communicating with
+arbitrary IP addresses. Thus we require DNS queries to succeed before
+any communication succeeds, including those same DNS queries! The way
+out of this conundrum is to exempt at least some DNS query IP traffic
+from Opportunism.
+
+There are several possible solutions, all of which have advantages and
+disadvantages.
+
+1. If you use a single machine, outside your Security Gateway, as DNS
+server, you can build a clear path (or even an IPSEC tunnel, but not
+opportunistically) directly to that machine.
+
+- you could use a type=passthrough conn to provide a clear path
+ between your machine and the DNS machine.
+
+- better still, you could explicitly create an IPSEC connection to
+ your DNS server. Just be sure that Pluto does not need to access
+ DNS to find the IP addresses or RSA public keys for that connection!
+
+- you could install an explicit route to the DNS machine through
+ your public interface (not ipsecN). This will bypass KLIPS
+ processing. You might have to adjust your firewall. For example:
+
+ route add host -net ns.example.com gw gw.example.com dev eth1
+
+2. Generally, it is better to run DNS on your Security Gateway. This
+leads to a need for non-opportunistic paths to an arbitrary number of
+DNS servers in the internet. One way to accomplish this is to NOT
+have outbound opportunism cover the SG itself, but only the subnet
+behind it. In other words, leave out the
+ ipsec auto --route sg-to-anyone
+You must also add a type=passthrough eroute specifically for
+sg-to-anyone (without this, the traffic will be handled by the KLIPS
+no-eroute policy).
+
+3. It is actually possible to use a single machine inside your client
+subnet as a DNS server. The techniques listed in 1 could be used to
+let it communicate with other DNS servers without interference. This
+might have advantages over 1 if the DNS machine *only* did DNS.
+Another technique (not often possible or reasonable) is to give this
+machine another route to the internet, one that avoids the SG.
+
+4. DNS queries will eventually time out and then Pluto will give up
+and establish %pass eroutes. So communications should start flowing.
+
+We would like to have better solutions. Perhaps we will in the
+future. Suggestions are welcome.
+
+
+Figuring out what is going on
+=============================
+
+Since Opportunism lets your SG operate with less supervision, you may
+be puzzled by what it is up to. The usual tools exist, but their use
+is more important. To look at what Pluto is doing, use:
+ ipsec auto --status
+To look at what KLIPS is doing, use
+ ipsec look
+
+To just see the kernel's eroute table, look at the "file"
+/proc/net/ipsec_eroute. It contains a description of all the eroutes
+in the kernel. Here is an example:
+
+10 10.2.1.0/24 -> 0.0.0.0/0 => %trap
+259 10.2.1.115/32 -> 10.19.75.161/32 => tun0x1002@10.19.75.145
+71 10.44.73.97/32 -> 0.0.0.0/0 => %trap
+4119 10.44.73.97/32 -> 10.114.121.41/32 => %pass
+
+You read each line as: a packet from within the first subnet, destined
+for the second subnet, will be processed by the Security Association
+Identity (SAID) specified last. The first column is the number of
+(outbound) packets processed by this eroute.
+
+For shunt eroutes, the SAID is printed as just the type of shunt:
+%pass pass the packet through with no processing
+%drop discard the packet
+%reject discard the packet and notify sender
+%hold keep the last packet; discard others
+%trap cause any trapped packet to generate a PF_KEY ACQUIRE
+ to request negotiation; install a corresponding %hold
+ shunt and attach this packet to the %hold
+
+For other eroutes, the SAID is printed as a triple: protocol (three
+letters), SPI (32-bit number in hex), and destination IP address.
+Protocols include:
+
+tun IP in IP encapsulation (used for most tunnels)
+esp ESP encapsulation -- part of an IPSEC SA group
+ah AH packet authentication -- part of an IPSEC SA group
+
+So, looking at our sample eroutes:
+
+10 10.2.1.0/24 -> 0.0.0.0/0 => %trap
+
+ This is a TRAP (int0x104) shunt eroute. It was installed by
+ Pluto so that it can catch all traffic from its client subnet
+ to the world at large. Ten outbound packets have been trapped.
+
+259 10.2.1.115/32 -> 10.19.75.161/32 => tun0x1002@10.19.75.145
+
+ This is a tunnel eroute: packets from 10.2.1.115 (within
+ our client subnet) going to 10.19.75.161 will be encrypted
+ and sent to the peer SG 10.19.75.145. This was the product
+ of an Opportunistic negotiation (a hint is that each client
+ subnet has only one member). 259 packets have been sent
+ through this tunnel.
+
+71 10.44.73.97/32 -> 0.0.0.0/0 => %trap
+
+ This is another TRAP shunt eroute. It is to catch traffic
+ from the Security Gateway to the world. It has caught
+ 71 outbound packets.
+
+4119 10.44.73.97/32 -> 10.114.121.41/32 => %pass
+
+ This is a %pass (0x100) shunt eroute. It was installed when an
+ attempted Opportunistic negotiation failed because the reverse
+ domain of 10.114.121.41 had no suitable TXT record. 4119
+ outbound packets have been passed.
+
+
+Important Limitations
+=====================
+
+Pluto's DNS lookup is synchronous (single-threaded). Not only does
+this slow things down, but it turns out that in extreme cases where
+there are a lot of ACQUIRE messages from KLIPS at once, some of those
+messages can be lost and communications will be blocked by the %hold
+eroute that Pluto doesn't know about. Pluto now looks every 2 minutes
+for any %holds that it missed.
+
+DNS lookup is not verified -- we don't use Secure DNS. A spoofed DNS
+could compromise Opportunism.
+
+There are several new opportunities for Denial of Service attacks.
+For example, a Bad Guy could spray our system with pings with forged
+source addresses. For each unique source address, our system would do
+a (synchronous!) DNS lookup.
+
+Once a %pass eroute is added for a failed negotiation, it will stay
+until it has been inactive for about 15 minutes. The only activity
+that counts is outbound -- not surprising since a %pass only affects
+outbound traffic.
+
+If a destination's DNS entry specifies the information we need for
+negotiation, Pluto will not let communications proceed without
+negotiating a Security Tunnel.
+
+There is currently no way to tear down a tunnel that is no longer in
+use. To add insult to injury, when the lifetime is about to be
+exceeded, the initiating Pluto will rekey! Restarting will clear
+these out. rekey=no doesn't solve this since SA expiry would be
+uncoordinated and hence cause packets to be lost.
+
+If one side of a Security Tunnel restarts, but doesn't initiate
+negotiation with its peer, the peer will not be able to communicate
+with it until the peer thinks the tunnel needs rekeying due to
+lifetime, or the restarted Security Gateway decides to negotiate for
+its own reasons.
+
+It isn't clear what firewall policies make sense with Opportunism.
+
+If VPN and Opportunism connections coexist, security policies
+implemented via a firewall can only distinguish traffic by IP address.
diff --git a/doc/opportunism.known-issues b/doc/opportunism.known-issues
new file mode 100644
index 000000000..90752dee3
--- /dev/null
+++ b/doc/opportunism.known-issues
@@ -0,0 +1,287 @@
+Known issues with Opportunistic Encryption Claudia Schmeing
+------------------------------------------
+
+
+This is an overview of known issues with OE.
+
+
+This document supplements:
+
+
+FreeS/WAN Quickstart Guide doc/quickstart.html
+
+Opportunism HOWTO doc/opportunism.howto
+
+Opportunism spec doc/opportunism.spec
+
+Internet Draft doc/draft-richardson-ipsec-opportunistic.txt
+
+
+
+* Use the most recent Linux FreeS/WAN 2.x release from ftp.xs4all.nl
+ to try OE.
+
+
+DESIGN LIMITATIONS
+
+
+* Because Opportunistic Encryption relies on DNS:
+ - to authenticate one FreeS/WAN to another, and
+ - to prove that we have the right to protect traffic for a given IP,
+ this authentication/authorization is only as strong as your DNS is
+ secure.
+
+ Without secure DNS, OE protects against passive snooping only.
+ Because the public key and gateway information that FreeS/WAN gets from
+ DNS is not authenticated, a man-in-the-middle attack is still possible.
+ We hope that as DNSsec is widely adopted, OE with strong authentication
+ will become more widespread.
+
+ However, our software does not yet distinguish between strongly and weakly
+ authenticated OE. This information might be useful for defining local
+ security policy.
+
+
+* Denial of service attacks are possible against OE. If you rely on OE rather
+ than VPN to connect several offices, a determined attacker could prevent you
+ from communicating securely.
+
+
+* OE challenges the notion that all IPsec peers are "friends". With OE,
+ strangers can potentially tunnel IPsec packets _through_ your defenses
+ against cleartext packets. This may call for a re-visit to firewall policy.
+
+
+* FreeS/WAN only creates OE connections when it traps an outgoing packet.
+ Since most traffic is two-way, for most traffic, FreeS/WAN 2.x may soon
+ trap an outgoing packet and create an IPsec connection to
+ protect both incoming and outgoing traffic. However, if a local
+ FreeS/WAN box accepts inbound traffic from a remote peer but
+ generates no outbound traffic in response, the local FreeS/WAN will not
+ attempt to initiate OE. Of course, the peer may also initiate OE upon
+ trapping its own outbound traffic.
+
+
+* OE is only as reliable as your DNS is.
+
+ If your DNS service is flaky, you will not be able to reliably establish
+ OE connections to known OE-capable peers.
+
+ If you ping a peer, but your FreeS/WAN does not find a TXT record signifying
+ the peer's ability to respond to OE negotiation), FreeS/WAN will not try to
+ opportunistically initiate, and communication will fallback to clear.
+
+ For more secure and reliable DNS, we recommend that you run DNS
+ within your security perimeter, either on your security gateway, or
+ on a machine to which you have a VPN connection. It is also possible
+ to have your DNS server located elsewhere on your LAN, though this may
+ cause lag on startup.
+
+ This mailing list message explains how to run a local caching name server:
+ http://lists.freeswan.org/pipermail/design/2003-January/004205.html
+
+ See also "Getting DNS through" in opportunism.howto
+ http://lists.freeswan.org/pipermail/design/2002-April/002285.html .
+
+
+
+CURRENT ISSUES
+
+* There are several special issues re: using OE when running FreeS/WAN with
+ kernel native IPsec, introduced in the 2.6 kernel. Please see
+ doc/2.6.known-issues.
+
+* If A and B have an OE connection, but A is rebooted, normally A will try to
+ re-connect to B and (if it has no DNS-related failures) it will succeed.
+ But, if A is set up for responder-only OE, you will have a one-way
+ connection until B notices that its original tunnel has expired. For details
+ see:
+
+ http://lists.freeswan.org/pipermail/design/2002-May/002582.html
+ http://lists.freeswan.org/pipermail/design/2002-June/002610.html
+
+ TIP: If an OE connection isn't behaving, you can recreate it with
+
+ ipsec whack --oppohere sourceIPaddress --oppothere targetIPaddress
+
+
+* There is no good clean facility to delete OE connections.
+ Available are:
+
+ ipsec auto --status to list connections
+ ipsec whack --deletestate to delete by state#.
+
+
+* You may experience seeming gaps at rekey time. Once you generate traffic,
+ you will find that the OE connection returns.
+
+ By default, OE connections are not rekeyed; if they were we'd have a
+ mountain of useless connections. As a consequence, if your OE connection is
+ idle at rekey time, it will go down until you generate further traffic.
+ To ensure prompt rekeying, you can run a ping thorough the OE tunnel.
+
+
+* At the moment, you can only run active OE on one physical interface.
+
+ Active means --routed, to trap outbound packets. It is this route
+ that is a problem.
+
+ Untested theory: you can have multiple active OE conns, for different
+ source addresses, but they all have to point their traffic out the single
+ interface.
+
+ When responding: you can only define one OE connection (per host or subnet)
+ in ipsec.conf, and that conn will apply to one interface. Normally this
+ will be the public interface which your default route uses; it is, however,
+ configurable.
+
+ Theoretically, it might make sense to select between multiple OE conns
+ based on some criterion, such as address ranges. This might be useful for
+ local OE, or in a complex routing scenario.
+
+ Currently, Pluto expects only one OE connection. If you add another,
+ Pluto may choose randomly between them, producing unpredictable results.
+
+
+* Building OE conns between nodes on a LAN is not possible.
+
+ This is a side effect of conflicts about ARP entries
+ in the rt_cache and our "stupid routing tricks".
+ There is no known workaround at this time.
+
+ "Stupid routing tricks" are an ongoing issue, and should
+ go away in a future software revision.
+
+ See these explanations:
+ http://lists.freeswan.org/pipermail/design/2002-April/002285.html
+ http://lists.freeswan.org/pipermail/design/2002-August/003249.html
+
+
+* FreeS/WAN may not correctly follow a CNAME (Canonical Name) trail resulting
+ from reverse DNS delegation.
+
+ Solution: Use a recent Bind 9 (we tested with Bind snap-pre9.3) for the
+ DNS services which the FreeS/WAN box relies on.
+
+ Reason: This Bind correctly implements "implied helper support" for
+ traditional DNS records, and so can follow a properly constructed CNAME
+ record trail which ends in a TXT record. Thus, in cases where a reverse
+ domain has been delegated, FreeS/WAN + Bind 9 can find a TXT record and
+ create an OE connection.
+
+ For more on the problem, see "OLD ISSUES", below.
+
+
+* To make OE operation smoother, we may need a script that runs and warns
+ if we have the reverse DNS records, but not the software running.
+ The reverse records advertise that we can do OE, but when the software is
+ not running this is false advertising.
+
+
+
+OLD ISSUES
+
+* Coterminal OE doesn't work in practise. This includes OE-in-WAVEsec.
+ Solved in 2.02.
+
+ Old diagnosis:
+
+ If you have coterminal OE connections (two OE connections which share
+ one endpoint), you should have use of one of the encrypted links, but it
+ is not clear which one KLIPS will prefer. In particular, the behaviour
+ may not be symmetrical.
+
+ Worse yet, it just seems to trip over itself and be generally
+ unworkable.
+
+ Weird but predictable:
+
+ If you have both a gateway and a host who advertise (via DNS) an
+ ability to do OE you need to be serious about doing host-based
+ OE, or you will be stuck in initiator-only mode. If your host
+ advertises but does not run OE, then when a peer tries to connect to
+ your host, it will fail to clear. The peer will then not try to encrypt
+ traffic bound for that host as it travels to the gateway. To remedy
+ the situation, restart ipsec on the peer (or otherwise flush out
+ the %pass eroute), and ping the peer from your host to initiate
+ OE.
+
+
+* One-way connection was created on rekey. Solved in 2.0.
+
+ If one side (A) has a shorter _keylife_ than the other,
+ and that side also has _rekey=no_, then when the keylife has
+ expired, it will expect that its peer (B) will make a new conn to replace
+ the existing one. Unfortunately, B has no idea.
+
+ B continues to send out encrypted packets on the original connection,
+ while A passes the return packets along in the clear.
+
+ There is a proposed patch for (A) here:
+ http://lists.freeswan.org/pipermail/design/2002-July/003114.html
+
+
+* Failure to look up own host name is a show stopper.
+ Solved in 1.98 and 1.98b.
+
+ Solution: new setting %dnsondemand. Usage:
+
+ leftrsasigkey=%dnsondemand # now in sample ipsec.conf
+ rightrsasigkey=%dnsondemand.
+
+ From man ipsec.conf:
+
+ The value %dnsondemand means the key is to fetched from DNS
+ at the time it is needed.
+
+ If Linux FreeS/WAN can't get the key for your public interface from
+ DNS, it will not keep trying, and you will not be able to do OE.
+
+ The error message is:
+
+ May 14 09:40:24 road Pluto[21210]: failure to fetch key for 193.110.157.18
+ from DNS: failure querying DNS for KEY of 18.157.110.193.in-addr.arpa.:
+ Host name lookup failure
+
+ Workaround: 1 or 2
+ 1. Supply a key in the conn. leftrsasigkey=0s...
+ 2. Fix the KEY lookup failure and try again.
+
+
+* Assertion failure at OE rekey time. Fixed in 2.0pre0. Patch for 1.98b posted
+ at http://lists.freeswan.org/pipermail/design/2002-August/003347.html
+
+
+* 1.91 to 1.94 have serious problems with %trap and %hold bugs. These bugs,
+ introduced while coding the support structure for OE, affect both OE and VPN
+ connections.
+
+
+* OE may not work with reverse delegation (CNAMEs). This problem was once
+ capable of being a show stopper.
+
+ When relying on Bind versions before 9 for local DNS services, FreeS/WAN
+ could not follow a well constructed CNAME trail that ended in a TXT or KEY
+ record. Although OE required both record types, in practise we noticed the
+ problem with the more common TXT lookups, rather than the rarer KEY lookups.
+ Bind 9 largely solves the problem, by correctly seeking TXT records in
+ delegated reverse domains. In addition, OE between two FreeS/WAN 2.02 or
+ later boxes no longer relies on KEY records.
+
+ Old symptoms:
+
+ When a DNS server queried by Linux FreeS/WAN follows a CNAME,
+ it seems to forget what record type it is looking for, and it
+ returns a PTR, despite the fact that another record type was requested.
+
+ Workaround:
+
+ Send your provider KEY and TXT records for direct insertion into the
+ reverse ZONE files, rather than asking your provider to delegate authority
+ using CNAME.
+
+ People who own IP blocks, rather than leasing them, may not
+ experience this problem. If you were assigned IPs more than
+ five years ago, you may own your IPs.
+
+
diff --git a/doc/opportunism.nr b/doc/opportunism.nr
new file mode 100644
index 000000000..c5cae757a
--- /dev/null
+++ b/doc/opportunism.nr
@@ -0,0 +1,1115 @@
+.DA "3 May 2001"
+.ds LH "
+.ds CH "Opportunistic Encryption
+.ds RH "
+.ds LF "Draft 4+
+.ds CF "\\*(DY
+.ds RF %
+.de P
+.LP
+..
+.de R
+.LP
+\fBRationale:\fR
+..
+.de A
+.LP
+\fBAhem:\fR
+..
+.TL
+Opportunistic Encryption
+.AU
+Henry Spencer
+D. Hugh Redelmeier
+.AI
+henry@spsystems.net
+hugh@mimosa.com
+Linux FreeS/WAN Project
+.AB no
+xxx cases where reverses not controlled, all possibilities.
+xxx DHR suggests okay if gateway doesn't control reverse but destination does.
+xxx level of patience where Responder just doesn't answer the phone.
+xxx IKE finger to get basic keying info, to be confirmed via DNSSEC?
+xxx packets from some OE connections might get special status,
+if the other end is definitely someone we trust.
+Opportunistic encryption permits secure (encrypted, authenticated)
+communication via IPsec without connection-by-connection prearrangement,
+either explicitly between hosts (when the hosts are capable of it) or
+transparently via packet-intercepting security gateways.
+It uses DNS records (authenticated with DNSSEC) to provide
+the necessary information for gateway discovery and gateway authentication,
+and constrains negotiation enough to guarantee success.
+.sp
+Substantive changes since draft 3:
+write off inverse queries as a lost cause;
+use Invalid-SPI rather than Delete as notification of unknown SA;
+minor wording improvements and clarifications.
+This document takes over from the older ``Implementing Opportunistic
+Encryption'' document.
+.AE
+.NH 1
+Introduction
+.P
+A major goal of the FreeS/WAN project is opportunistic encryption:
+a (security) gateway intercepts an outgoing packet aimed at a
+remote host, and quickly attempts to negotiate an IPsec tunnel to that
+host's security gateway.
+If the attempt succeeds, traffic can then be secure,
+transparently (without changes to the host software).
+If the attempt fails,
+the packet (or a retry thereof) passes through in clear or is dropped,
+depending on local policy.
+Prearranged tunnels bypass the packet interception etc., so static VPNs
+can coexist with opportunistic encryption.
+.P
+This generalizes trivially to the end-to-end case:
+host and security gateway simply are one and the same.
+Some optimizations are possible in that case,
+but the basic scheme need not change.
+.P
+The objectives for security systems need to be explicitly stated.
+Opportunistic encryption is meant to achieve secure communication,
+without prearrangement of the individual connection
+(although some prearrangement on a per-host basis is required),
+between any two hosts which implement the protocol
+(and, if they act as security gateways,
+between hosts behind them).
+Here ``secure'' means strong encryption and authentication of packets,
+with authentication of participants\(emto prevent man-in-the-middle
+and impersonation attacks\(emdependent on several factors.
+The biggest factor is the authentication of DNS records,
+via DNSSEC or equivalent means.
+A lesser factor is which exact variant
+of the setup procedure (see section 2.2) is used,
+because there is a tradeoff between strong authentication of the other end
+and ability
+to negotiate opportunistic encryption with hosts which have limited
+or no control of their reverse-map DNS records:
+without reverse-map information,
+we can verify that the host has the right to use a particular FQDN
+(Fully Qualified Domain Name),
+but not whether that FQDN is authorized to use that IP address.
+Local policy must decide whether authentication
+or connectivity has higher priority.
+.P
+Apart from careful attention to detail in various areas,
+there are three crucial design problems for opportunistic encryption.
+It needs a way to quickly identify the remote host's security gateway.
+It needs a way to quickly obtain an authentication key for the
+security gateway.
+And the numerous options which can be specified with IKE
+must be constrained sufficiently that two independent implementations are
+guaranteed to reach agreement,
+without any explicit prearrangement or preliminary negotiation.
+The first two problems are solved using DNS,
+with DNSSEC ensuring that the data obtained is reliable;
+the third is solved by specifying a minimum standard which must be supported.
+.P
+A note on philosophy:
+we have deliberately avoided providing six different
+ways to do each job, in favor of specifying one good one.
+Choices are
+provided only when they appear to be necessary,
+or at least important.
+.P
+A note on terminology:
+to avoid constant circumlocutions,
+an ISAKMP/IKE SA, possibly recreated occasionally by rekeying,
+will be referred to as a ``keying channel'',
+and a set of IPsec SAs providing bidirectional communication between
+two IPsec hosts,
+possibly recreated occasionally by rekeying,
+will be referred to as a ``tunnel''
+(it could conceivably use transport mode in the host-to-host case,
+but we advocate using tunnel mode even there).
+The word ``connection'' is here used in a more generic sense.
+The word ``lifetime'' will be avoided in favor of ``rekeying interval'',
+since many of the connections will have useful lives far shorter
+than any reasonable rekeying interval,
+and hence the two concepts must be separated.
+.P
+A note on document structure:
+Discussions of \fIwhy\fR things were done a particular way,
+or not done a particular way,
+are broken out in paragraphs headed ``Rationale:''
+(to preserve the flow of the text, many such paragraphs are deferred
+to the ends of sections).
+Paragraphs headed ``Ahem:'' are discussions of where the problem is being
+made significantly harder by problems elsewhere,
+and how that might be corrected.
+Some meta-comments are enclosed in [].
+.R
+The motive is to get the Internet encrypted.
+That requires encryption without connection-by-connection prearrangement:
+a system must be able to
+reliably negotiate an encrypted, authenticated
+connection with a total stranger.
+While end-to-end encryption is preferable,
+doing opportunistic encryption in security gateways
+gives enormous leverage for quick deployment of this technology,
+in a world where end-host software is often primitive, rigid, and outdated.
+.R
+Speed is of the essence in tunnel setup:
+a connection-establishment delay longer than about 10 seconds
+begins to cause problems for users and applications.
+Thus the emphasis on rapidity in gateway discovery and key fetching.
+.A
+Host-to-host opportunistic encryption
+would be utterly trivial if a fast public-key
+encryption/signature
+algorithm was available.
+You would do a reverse lookup on the destination address to obtain a
+public key for that address,
+and simply encrypt all packets going to it with that key,
+signing them with your own private key.
+Alas, this is impractical with current CPU speeds and current algorithms
+(although as noted later, it might be of some use for limited purposes).
+Nevertheless, it is a useful model.
+.NH 1
+Connection Setup
+.P
+For purposes of discussion, the network is taken to look like this:
+.DS
+Source----Initiator----...----Responder----Destination
+.DE
+The intercepted packet comes from the Source,
+bound for the Destination,
+and is intercepted at the Initiator.
+The Initiator communicates over the insecure Internet to the Responder.
+The Source and the Initiator might be the same host,
+or the Source might be an end-user host and the Initiator a
+security gateway (SG).
+Likewise for the Responder and the Destination.
+.P
+Given an intercepted packet,
+whose useful information (for our purposes)
+is essentially only the Destination's IP address,
+the Initiator
+must quickly determine the Responder (the Destination's SG) and
+fetch everything needed to authenticate it.
+The Responder must do likewise for the Initiator.
+Both must eventually also confirm that the other is authorized to act
+on behalf of the client host behind it (if any).
+.P
+An important subtlety here is that if the alternative to an IPsec tunnel
+is plaintext transmission, negative results must be obtained quickly.
+That is,
+the decision that \fIno\fR tunnel can be established must also be made rapidly.
+.NH 2
+Packet Interception
+.P
+Interception of outgoing packets is relatively straightforward
+in principle.
+It is preferable to put the intercepted packet on hold rather than
+dropping it, since higher-level retries are not necessarily well-timed.
+There is a problem of hosts and applications retrying during negotiations.
+ARP implementations, which face the same problem,
+use the approach of keeping the \fImost recent\fR
+packet for an as-yet-unresolved address,
+and throwing away older ones.
+(Incrementing of request numbers etc. means that replies to older ones may no
+longer be accepted.)
+.P
+Is it worth intercepting \fIincoming\fR packets, from the outside world, and
+attempting tunnel setup based on them?
+No, unless and until a way can be devised to initiate opportunistic encryption
+to a non-opportunistic responder,
+because
+if the other end has not initiated tunnel setup itself, it will not be
+prepared to do so at our request.
+.R
+Note, however, that most incoming packets will promptly be followed by
+an outgoing packet in response!
+Conceivably it might be useful to start early stages of negotiation,
+at least as far as looking up information,
+in response to an incoming packet.
+.R
+If a plaintext incoming packet indicates that the other
+end is not prepared to do opportunistic encryption,
+it might seem that this fact should be noted, to
+avoid consuming resources and delaying
+traffic in an attempt at opportunistic setup which is doomed to fail.
+However, this would be a major security hole,
+since the plaintext packet is not authenticated;
+see section 2.5.
+.NH 2
+Algorithm
+.P
+For clarity,
+the following defers most discussion of error handling to the end.
+.nr x \w'Step 3A.'u+1n
+.de S
+.IP "Step \\$1." \nxu
+..
+.S 1
+Initiator does a DNS reverse lookup on the Destination address,
+asking not for the usual PTR records,
+but for TXT records.
+Meanwhile, Initiator also sends a ping to the Destination,
+to cause any other dynamic setup actions to start happening.
+(Ping replies are disregarded;
+the host might not be reachable with plaintext pings.)
+.S 2A
+If at least one suitable TXT record (see section 2.3) comes back,
+each contains a potential Responder's IP address
+and that Responder's public key (or where to find it).
+Initiator picks one TXT record, based on priority (see 2.3),
+thus picking a Responder.
+If there was no public key in the TXT record,
+the Initiator also starts a DNS lookup (as specified by the TXT record)
+to get KEY records.
+.S 2B
+If no suitable TXT record is available,
+and policy permits,
+Initiator designates the Destination itself as the Responder
+(see section 2.4).
+If policy does not permit,
+or the Destination is unresponsive to the negotiation,
+then opportunistic encryption is not possible,
+and Initiator gives up (see section 2.5).
+.S 3
+If there already is a keying channel to the Responder's IP address,
+the Initiator uses the existing keying channel;
+skip to step 10.
+Otherwise, the Initiator starts an IKE Phase 1 negotiation
+(see section 2.7 for details)
+with the Responder.
+The address family of the Responder's IP address dictates whether
+the keying channel and the outside of the tunnel should be IPv4 or IPv6.
+.S 4
+Responder gets the first IKE message,
+and responds.
+It also starts a DNS reverse lookup on the Initiator's IP address,
+for KEY records, on speculation.
+.S 5
+Initiator gets Responder's reply,
+and sends first message of IKE's D-H exchange (see 2.4).
+.S 6
+Responder gets Initiator's D-H message,
+and responds with a matching one.
+.S 7
+Initiator gets Responder's D-H message;
+encryption is now established, authentication remains to be done.
+Initiator sends IKE authentication message,
+with an FQDN identity if a reverse lookup on its address will not yield a
+suitable KEY record.
+(Note, an FQDN need not
+actually correspond to a host\(eme.g., the DNS data for it need not
+include an A record.)
+.S 8
+Responder gets Initiator's authentication message.
+If there is no identity included,
+Responder waits for step 4's speculative DNS lookup to finish;
+it should yield a suitable KEY record (see 2.3).
+If there is an FQDN identity,
+responder discards any data obtained from step 4's DNS lookup;
+does a forward lookup on the FQDN, for a KEY record;
+waits for that lookup to return;
+it should yield a suitable KEY record.
+Either way, Responder uses the KEY data to verify the message's hash.
+Responder replies with an authentication message,
+with an FQDN identity if a reverse lookup on its address will not yield a
+suitable KEY record.
+.S 9A
+(If step 2A was used.)
+The Initiator gets the Responder's authentication message.
+Step 2A has provided a key (from the TXT record or via DNS lookup).
+Verify message's hash.
+Encrypted and authenticated keying channel established,
+man-in-middle attack precluded.
+.S 9B
+(If step 2B was used.)
+The Initiator gets the Responder's authentication message,
+which must contain an FQDN identity (if the Responder can't put a TXT in his
+reverse map he presumably can't do a KEY either).
+Do forward lookup on the FQDN,
+get suitable KEY record, verify hash.
+Encrypted keying channel established,
+man-in-middle attack precluded,
+but authentication weak (see 2.4).
+.S 10
+Initiator initiates IKE Phase 2 negotiation (see 2.7) to establish tunnel,
+specifying Source and Destination identities as IP addresses (see 2.6).
+The address family of those addresses also determines whether the inside
+of the tunnel should be IPv4 or IPv6.
+.S 11
+Responder gets first Phase 2 message.
+Now the Responder finally knows what's going on!
+Unless the specified Source is identical to the Initiator,
+Responder initiates DNS reverse lookup on Source IP address,
+for TXT records;
+waits for result;
+gets suitable TXT record(s) (see 2.3),
+which should contain either the Initiator's IP address
+or an FQDN identity identical to that supplied by the Initiator in step 7.
+This verifies that the Initiator is authorized
+to act as SG for the Source.
+Responder replies with second Phase 2 message,
+selecting acceptable details (see 2.7),
+and establishes tunnel.
+.S 12
+Initiator gets second Phase 2 message,
+establishes tunnel (if he didn't already),
+and releases the intercepted packet into it, finally.
+.S 13
+Communication proceeds.
+See section 3 for what happens later.
+.P
+As additional information becomes available,
+notably in steps 1, 2, 4, 8, 9, 11, and 12,
+there is always a possibility that local policy
+(e.g., access limitations) might prevent further progress.
+Whenever possible,
+at least attempt to inform the other end of this.
+.P
+At any time, there is a possibility of the negotiation failing due to
+unexpected responses, e.g. the Responder not responding at all
+or rejecting all Initiator's proposals.
+If multiple SGs were found as possible Responders,
+the Initiator should try at least one more before giving up.
+The number tried should be influenced by what the alternative is:
+if the traffic will otherwise be discarded, trying the full list is
+probably appropriate,
+while if the alternative is plaintext transmission,
+it might be based on how long the tries are taking.
+The Initiator should try as many as it reasonably can,
+ideally all of them.
+.P
+There is a sticky problem with timeouts.
+If the Responder is down
+or otherwise inaccessible, in the worst case we won't hear about this
+except by not getting responses.
+Some other, more pathological or even
+evil, failure cases can have the same result.
+The problem is that in the
+case where plaintext is permitted, we want to decide whether a tunnel is
+possible quickly.
+There is no good solution to this, alas;
+we just have to take the time and do it right.
+(Passing plaintext meanwhile
+looks attractive at first glance... but exposing
+the first few seconds of a connection is often almost as bad as exposing
+the whole thing.
+Worse, if the user checks the status of the connection,
+after that brief window it looks secure!)
+.P
+The flip side of waiting for a timeout is that all other forms of
+feedback, e.g. ``host not reachable'',
+arguably should be \fIignored\fR,
+because in the absence of authenticated ICMP,
+you cannot trust them!
+.R
+An alternative, sometimes suggested, to the use of explicit DNS records
+for SG discovery is to directly attempt IKE negotiation with the
+destination host,
+and assume that any relevant SG will be on the packet path,
+will intercept the IKE packets,
+and will impersonate the destination host for the IKE negotiation.
+This is superficially attractive but is a very bad idea.
+It assumes that routing is stable throughout negotiation,
+that the SG is on the plaintext-packets path,
+and that the destination host is routable
+(yes, it is possible to have (private) DNS data for an unroutable host).
+Playing extra games in the plaintext-packet path hurts performance and
+can be expected to be unpopular.
+Various difficulties ensue when there are multiple SGs along the path
+(there is already bad experience with this, in RSVP),
+and the presence of even one can make it impossible
+to do IKE direct to the host when that is what's wanted.
+Worst of all, such impersonation breaks the IP network model badly,
+making problems difficult to diagnose and impossible to work around
+(and there is already bad experience with this, in areas like web caching).
+.R
+(Step 1.)
+Dynamic setup actions might include establishment of demand-dialed links.
+These might be present anywhere along the path,
+so one cannot rely on out-of-band communication at the Initiator to
+trigger them.
+Hence the ping.
+.R
+(Step 2.)
+In many cases, the IP address on the intercepted packet will be the
+result of a name lookup just done.
+Inverse queries, an obscure DNS feature from the distant past,
+in theory can be used to ask a DNS server to reverse that lookup,
+giving the name that produced the address.
+This is not the same as a reverse lookup,
+and the difference can matter a great deal in cases where a host
+does not control its reverse map
+(e.g., when the host's IP address is dynamically assigned).
+Unfortunately, inverse queries were never widely implemented and
+are now considered obsolete.
+Phooey.
+.A
+Support for a small subset of this admittedly-obscure feature
+would be useful.
+Unfortunately, it seems unlikely.
+.R
+(Step 3.)
+Using only IP addresses to decide whether there is already a relevant
+keying channel avoids some
+difficult problems.
+In particular, it might seem that this should be based on identities,
+but those are not known until very late in IKE Phase 1 negotiations.
+.R
+(Step 4.)
+The DNS lookup is done on speculation
+because the data will probably be useful and the lookup can be done
+in parallel with IKE activity,
+potentially speeding things up.
+.R
+(Steps 7 and 8.)
+If an SG does not control its reverse map,
+there is no way it can prove its right to use an IP address,
+but it can nevertheless supply both an identity (as an FQDN) and
+proof of its right to use that identity.
+This is somewhat better than nothing,
+and may be quite useful if the SG is representing a client host
+which \fIcan\fR prove its right to \fIits\fR IP address.
+(For example, a fixed-address subnet might live behind an SG with
+a dynamically-assigned address;
+such an SG has to be the Initiator, not the Responder,
+so the subnet's TXT records can contain FQDN identities,
+but with that restriction, this works.)
+It might sound like this would permit some man-in-the-middle attacks
+in important cases like Road Warrior,
+but the RW can still do full authentication of the home base,
+so a man in the middle cannot successfully impersonate home base,
+and the D-H exchange doesn't work unless the man in the middle
+impersonates \fIboth\fR ends.
+.R
+(Steps 7 and 8.)
+Another situation where proof of the right to use an identity can be
+very useful is when access is deliberately limited.
+While opportunistic encryption is intended as a general-purpose
+connection mechanism between strangers,
+it may well be convenient for prearranged connections to use
+the same mechanism.
+.R
+(Steps 7 and 8.)
+FQDNs as identities are avoided where possible,
+since they can involve synchronous DNS lookups.
+.R
+(Step 11.)
+Note that only here, in Phase 2,
+does the Responder actually learn who the
+Source and Destination hosts are.
+This unfortunately demands a synchronous DNS lookup to verify that the
+Initiator is authorized to represent the Source,
+unless they are one and the same.
+This and the initial TXT lookup are the only synchronous DNS lookups
+absolutely required by the algorithm,
+and they appear to be unavoidable.
+.R
+While it might seem unlikely that a refusal to cooperate from one SG
+could be remedied by trying another\(empresumably they all use the
+same policies\(emit's conceivable that one might be misconfigured.
+Preferably they should all be tried,
+but it may be necessary to set some limits on this
+if alternatives exist.
+.NH 2
+DNS Records
+.P
+Gateway discovery and key lookup are based on TXT and KEY DNS records.
+The TXT record specifies IP address or other identity of a host's SG,
+and possibly supplies its public key as well,
+while the KEY record supplies public keys not found in TXT records.
+.NH 3
+TXT
+.P
+Opportunistic-encryption SG discovery uses TXT records with the content:
+.DS
+X-IPsec-Gateway(\fInnn\fR)=\fIiii\fR\ \fIkkk\fR
+.DE
+following RFC 1464 attribute/value
+notation.
+Records which
+do not contain an ``='',
+or which do not have exactly the specified form to the left of it,
+are ignored.
+(Near misses perhaps should be reported.)
+.P
+The \fInnn\fR is an unsigned integer which will fit in 16 bits,
+specifying an MX-style preference
+(lower number = stronger preference) to
+control the order in which multiple SGs are tried.
+If there are ties, pick one,
+randomly enough that the choice will probably be different each time.
+xxx rollover.
+The preference field is not optional;
+use ``0'' if there is no meaningful preference ordering.
+.P
+The \fIiii\fR part identifies the SG.
+Normally this is a dotted-decimal IPv4 address or
+a colon-hex IPv6 address.
+The sole exception is if the SG has no fixed address (see 2.4) but
+the host(s) behind it do,
+in which case \fIiii\fR is of the form ``@fqdn'',
+where \fIfqdn\fR is the FQDN that the SG will use to
+identify itself (in step 7 of section 2.2);
+such a record cannot be used for SG discovery by an Initiator,
+but can be used for
+SG verification (step 11 of 2.2) by a Responder.
+.P
+The \fIkkk\fR part is optional.
+If it is present,
+it is an RSA-MD5 public key in base-64 notation, as in the text
+form of an RFC 2535 KEY record.
+If it is not present,
+this specifies that the public key can be found in a KEY
+record located based on the SG's identification:
+if \fIiii\fR is an IP address,
+do a reverse lookup on that address,
+else do a forward lookup on the FQDN.
+.R
+While it is unusual for a reverse lookup to go for records other than PTR
+records (or possibly CNAME records, for RFC 2317 classless delegation),
+there's no reason why it can't.
+The TXT record is a temporary stand-in
+for (we hope, someday) a new DNS record for SG identification and keying.
+Keeping the setup process fast requires minimizing the number of DNS
+lookups, hence the desire to put all the information in one place.
+.R
+The use of RFC 1464 notation avoids collisions with other uses of TXT
+records.
+The ``X-'' in the attribute name
+indicates that this format is tentative and experimental;
+this design will probably need modification after initial experiments.
+The format is chosen with an eye on eventual binary encoding.
+Note, in particular,
+that the TXT record normally contains the \fIaddress\fR of the SG,
+not (repeat, not) its name.
+Name-to-address conversion is the job of
+whatever generates the TXT record,
+which is expected to be a program, not a human\(emthis is conceptually
+a \fIbinary\fR record, temporarily using a text encoding.
+The ``@fqdn'' form of the SG identity is
+for specialized uses and is never mapped to an address.
+.A
+A DNS TXT record contains one or more character strings,
+but RFC 1035 does not describe exactly how
+a multi-string TXT record is interpreted.
+This is relevant because a string can be at most 255 characters,
+and public keys can exceed this.
+Empirically, the standard pattern is that
+each string which is
+both less than 255 characters \fIand\fR not the final string of the
+record should have a blank appended to it,
+and the strings of the record
+should then be concatenated.
+(This observation is based on how BIND 8 transforms a TXT record
+from text to DNS binary.)
+.NH 3
+KEY
+.P
+An opportunistic-encryption KEY record
+is an Authentication-permitted,
+Entity (host),
+non-Signatory,
+IPsec,
+RSA/MD5 record
+(that is, its first four bytes are 0x42000401),
+as per RFCs 2535 and 2537.
+KEY records with other \fIflags\fR, \fIprotocol\fR, or \fIalgorithm\fR
+values are ignored.
+.R
+Unfortunately, the public key has to be
+associated with the SG, not the client host behind it.
+The Responder does not know which client it is supposed to be representing,
+or which client the Initiator is representing,
+until far too late.
+.A
+Per-client keys would reduce vulnerability to key compromise,
+and simplify key changes,
+but they would require changes to IKE Phase 1, to separately identify
+the SG and its initial client(s).
+(At present, the client identities are not known to the Responder
+until IKE Phase 2.)
+While the current IKE standard does not actually specify (!) who is
+being identified by identity payloads,
+the overwhelming consensus is that they identify the SG,
+and as seen earlier,
+this has important uses.
+.NH 3
+Summary
+.P
+For reference, the minimum set of DNS records needed to make this
+all work is either:
+.IP 1. \w'1.'u+2n
+TXT in Destination reverse map, identifying Responder and providing public key.
+.IP 2.
+KEY in Initiator reverse map, providing public key.
+.IP 3.
+TXT in Source reverse map, verifying relationship to Initiator.
+.P
+or:
+.IP 1. \w'1.'u+2n
+TXT in Destination reverse map, identifying Responder.
+.IP 2.
+KEY in Responder reverse map, providing public key.
+.IP 3.
+KEY in Initiator reverse map, providing public key.
+.IP 4.
+TXT in Source reverse map, verifying relationship to Initiator.
+.P
+Slight complications ensue for dynamic addresses,
+lack of control over reverse maps, etc.
+.NH 3
+Implementation
+.P
+In the long run, we need either a tree of trust or a web of trust,
+so we can trust our DNS data.
+The obvious approach for DNS is a tree of trust,
+but there are various practical problems with running all of this
+through the root servers,
+and a web of trust is arguably more robust anyway.
+This is logically independent of opportunistic encryption,
+and a separate design proposal will be prepared.
+.P
+Interim stages of implementation of this will require a bit of thought.
+Notably, we need some way of dealing with the lack of fully signed DNSSEC
+records right away.
+Without user interaction, probably the best we can do is to
+remember the results of old fetches, compare them to the results of new
+fetches, and complain and disbelieve all of it if there's a mismatch.
+This does mean that somebody who gets fake data into our very first fetch
+will fool us, at least for a while, but that seems an acceptable tradeoff.
+(Obviously there needs to be a way to manually flush the remembered results
+for a specific host, to permit deliberate changes.)
+.NH 2
+Responders Without Credentials
+.P
+In cases where the Destination simply does not control its
+DNS reverse-map entries,
+there is no verifiable way to determine a suitable SG.
+This does not make communication utterly impossible, though.
+.P
+Simply attempting negotiation directly with the host is a last resort.
+(An aggressive implementation might wish to attempt it in parallel,
+rather than waiting until other options are known to be unavailable.)
+In particular, in many cases involving dynamic addresses, it will work.
+It has the disadvantage of delaying the discovery that opportunistic
+encryption is entirely impossible,
+but the case seems common enough to justify the overhead.
+.P
+However, there are policy issues here either way, because
+it is possible to impersonate such a host.
+The host can supply an FQDN identity and verify its right to use that
+identity,
+but except by prearrangement,
+there is no way to verify that the FQDN is the right one for that
+IP address.
+(The data from forward lookups may be controlled by people
+who do not own the address, so it cannot be trusted.)
+The encryption is still solid, though,
+so in many cases this may be useful.
+.NH 2
+Failure of Opportunism
+.P
+When there is no way to do opportunistic encryption, a policy issue arises:
+whether to put in a bypass (which allows plaintext traffic through)
+or a block (which discards it, perhaps with notification back to the sender).
+The choice is very much a matter of local policy,
+and may depend on details such as the higher-level protocol being used.
+For example,
+an SG might well permit plaintext HTTP but forbid plaintext Telnet,
+in which case \fIboth\fR a block and a bypass would be set up if
+opportunistic encryption failed.
+.P
+A bypass/block must, in practice,
+be treated much like an IPsec tunnel.
+It should persist for a while,
+so that high-overhead processing doesn't have to be done for every packet,
+but should go away eventually to return resources.
+It may be simplest to treat it as a degenerate tunnel.
+It should have a relatively long lifetime (say 6h) to keep the frequency
+of negotiation attempts down,
+except in the case where the other SG simply did not respond to IKE packets,
+where the lifetime should be short (say 10min) because
+the other SG is presumably down and might come back up again.
+(Cases where the other SG responded to IKE with unauthenticated error
+reports like ``port unreachable'' are borderline,
+and might deserve to be treated as an intermediate case:
+while such reports cannot be trusted unreservedly,
+in the absence of any other response,
+they do give some reason to suspect that the other SG is unable or
+unwilling to participate in opportunistic encryption.)
+.P
+As noted in section 2.1, one might think that
+arrival of a plaintext incoming packet should cause a
+bypass/block to be set up for its source host:
+such a packet is almost always followed by an outgoing reply packet;
+the incoming packet is clear evidence that opportunistic encryption is
+not available at the other end;
+attempting it will waste resources and delay traffic to no good purpose.
+Unfortunately, this means that anyone out on the Internet
+who can forge a source address can prevent encrypted communication!
+Since their source addresses are not authenticated,
+plaintext packets cannot be taken as evidence of anything,
+except perhaps that communication from that host is likely to occur soon.
+.P
+There needs to be a way for local administrators to remove a bypass/block
+ahead of its normal expiry time,
+to force a retry after a problem at the other end is known to have been fixed.
+.NH 2
+Subnet Opportunism
+.P
+In principle, when the Source or Destination host belongs to a subnet
+and the corresponding SG is willing to provide tunnels to the whole subnet,
+this should be done.
+There is no extra overhead,
+and considerable potential for avoiding later overhead if
+similar communication occurs with other members of the subnet.
+Unfortunately,
+at the moment,
+opportunistic tunnels can only have degenerate subnets (single hosts)
+at their ends.
+(This does, at least, set up the keying channel,
+so that negotiations for tunnels to other hosts in the same subnets
+will be considerably faster.)
+.P
+The crucial problem is step 11 of section 2.2:
+the Responder must verify that the Initiator is authorized to represent
+the Source,
+and this is impossible for a subnet because
+there is no way to do a reverse lookup on it.
+Information in DNS
+records for a name or a single address cannot be trusted,
+because they may be controlled by people who do not control the whole subnet.
+.A
+Except in the special case of a subnet masked on a
+byte boundary (in which case RFC 1035's convention of an incomplete
+in-addr.arpa name could be used), subnet lookup would need extensions to the
+reverse-map name space, perhaps along the lines of that commonly done for
+RFC 2317 delegation.
+IPv6 already has suitable name syntax, as in RFC 2874,
+but has no specific provisions for subnet entries in its reverse maps.
+Fixing all this is is not conceptually difficult,
+but is logically independent of opportunistic encryption,
+and will be proposed separately.
+.P
+A less-troublesome problem is that the Initiator,
+in step 10 of 2.2,
+must know exactly what subnet is present on the Responder's end
+so he can propose a tunnel to it.
+This information could be included in the TXT record
+of the Destination
+(it would have to be verified with a subnet lookup,
+but that could be done in parallel with other operations).
+The Initiator presumably
+can be configured to know what subnet(s) are present on its end.
+.NH 2
+Option Settings
+.P
+IPsec and IKE have far too many useless options, and a few useful ones.
+IKE negotiation is quite simplistic, and cannot handle even simple
+discrepancies between the two SGs.
+So it is necessary to be quite specific about what should be done and
+what should be proposed,
+to guarantee interoperability without prearrangement or
+other negotiation protocols.
+.R
+The prohibition of other negotiations is simply because there is no time.
+The setup algorithm (section 2.2) is lengthy already.
+.P
+[Open question:
+should opportunistic IKE use a different port than normal IKE?]
+.P
+Somewhat arbitrarily and
+tentatively, opportunistic SGs must support Main Mode, Oakley group 5 for
+D-H, 3DES encryption and MD5 authentication for both ISAKMP and IPsec SAs,
+RSA/MD5 digital-signature authentication with keys between 2048 and 8192 bits,
+and ESP doing both encryption and authentication.
+They must do key PFS
+in Quick Mode, but not identity PFS.
+They may support IPComp, preferably using Deflate,
+but must not insist on it.
+They may support AES as an alternative to 3DES,
+but must not insist on it.
+.R
+Identity PFS essentially requires establishing
+a complete new keying channel for each new tunnel,
+but key PFS just does a new Diffie-Hellman exchange for each rekeying,
+which is relatively cheap.
+.P
+Keying channels must remain in existence at least as long as any
+tunnel created with them remains (they are not costly, and keeping
+the management path up and available simplifies various issues).
+See section 3.1 for related issues.
+Given the use of key PFS,
+frequent rekeying does not seem critical here.
+In the absence of strong reason to do otherwise,
+the Initiator should propose rekeying at 8hr-or-1MB.
+The Responder must accept any proposal which specifies
+a rekeying time between 1hr and 24hr inclusive
+and a rekeying volume between 100KB and 10MB inclusive.
+.P
+Given the short expected useful life of most tunnels (see section 3.1),
+very few of them will survive long enough to be rekeyed.
+In the absence of strong reason to do otherwise,
+the Initiator should propose rekeying at 1hr-or-100MB.
+The Responder must accept any proposal which specifies
+a rekeying time between 10min and 8hr inclusive
+and a rekeying volume between 1MB and 1000MB inclusive.
+.P
+It is highly desirable to add some random jitter
+to the times of actual rekeying attempts,
+to break up ``convoys'' of rekeying events;
+this and certain other aspects of robust rekeying practice will be the subject
+of a separate design proposal.
+.R
+The numbers used here for rekeying intervals are chosen quite arbitrarily
+and should be re-assessed after some implementation experience is gathered.
+.NH 1
+Renewal and Teardown
+.NH 2
+Aging
+.P
+When to tear tunnels down is a bit problematic, but if we're setting up a
+potentially unbounded number of them,
+we have to tear them down \fIsomehow sometime\fR.
+.P
+Set a short initial tentative lifespan, say 1min,
+since most net flows in fact last only a few seconds.
+When that expires, look to see if
+the tunnel is still in use (definition:
+has had traffic, in either direction,
+in the last half of the tentative lifespan).
+If so, assign it a somewhat longer tentative lifespan, say 20min,
+after which, look again.
+If not, close it down.
+(This tentative lifespan is
+independent of rekeying; it is just the time when the tunnel's future
+is next considered.
+This should happen reasonably frequently, unlike
+rekeying, which is costly and shouldn't be too frequent.)
+Multi-step backoff algorithms are not worth the trouble; looking every
+20min doesn't seem onerous.
+.P
+If the security gateway and the client host are one and the same,
+tunnel teardown decisions might wish to pay attention to TCP connection status,
+as reported by the local TCP layer.
+A still-open
+TCP connection is almost a guarantee that more traffic is coming, while
+the demise of the only TCP connection through a tunnel is a strong hint
+that none is.
+If the SG and the client host are separate machines,
+though, tracking TCP connection status requires packet snooping,
+which is complicated and probably not worthwhile.
+.P
+IKE keying channels likewise are torn down when it appears the need has
+passed.
+They always linger longer than the last tunnel they administer,
+in case they are needed again; the cost of retaining them is low.
+Other than that,
+unless the number of keying channels on the SG gets large,
+the SG should simply retain all of them until rekeying time,
+since rekeying is the only costly event.
+When about to rekey a keying channel which has no current tunnels,
+note when the last actual keying-channel traffic occurred,
+and close the keying channel down if it wasn't in the last, say, 30min.
+When rekeying a keying channel (or perhaps shortly before rekeying is expected),
+Initiator and Responder should re-fetch the public keys used for
+SG authentication,
+against the possibility that they have changed or disappeared.
+.P
+See section 2.7 for discussion of rekeying intervals.
+.P
+Given the low user impact of tearing down and rebuilding a connection
+(a tunnel or a keying channel),
+rekeying attempts should not be too persistent:
+one can always just rebuild when needed,
+so heroic efforts to preserve an existing connection are unnecessary.
+Say, try every 10s for a minute and every minute for 5min,
+and then give up and declare the connection
+(and all other connections to that IKE peer) dead.
+.R
+In future, more sophisticated, versions of this protocol,
+examining the initial packet might permit a more intelligent guess at
+the tunnel's useful life.
+HTTP connections in particular are
+notoriously bursty and repetitive.
+.R
+Note that rekeying a keying connection basically consists of building a
+new keying connection from scratch,
+using IKE Phase 1,
+and abandoning the old one.
+.NH 2
+Teardown and Cleanup
+.P
+Teardown should always be coordinated with the other end.
+This means interpreting and sending Delete notifications.
+.P
+On receiving a Delete for the outbound SAs of a tunnel
+(or some subset of them),
+tear down the inbound ones too, and notify the other end
+with a Delete.
+Tunnels need to be considered as bidirectional entities,
+even though the low-level protocols don't think of them that way.
+.P
+When the deletion is initiated locally,
+rather than as a response to a received Delete,
+send a Delete for (all) the inbound SAs of a tunnel.
+If no responding Delete is received for the outbound SAs,
+try re-sending the original Delete.
+Three tries spaced 10s apart seems a reasonable level of effort.
+(Indefinite persistence is not necessary;
+whether the other end isn't cooperating because it doesn't feel like
+it, or because it is down/disconnected/etc.,
+the problem will eventually be cleared up by other means.)
+.P
+After rekeying,
+transmission should switch to using the new SAs (ISAKMP or IPsec)
+immediately,
+and the old leftover SAs should be cleared out promptly
+(and Deletes sent) rather than waiting for them to expire.
+This reduces clutter and minimizes confusion.
+.P
+Since there is only one keying channel per remote IP address,
+the question of whether a Delete notification has appeared on a
+``suitable'' keying channel does not arise.
+.R
+The pairing of Delete notifications effectively constitutes an
+acknowledged Delete, which is highly desirable.
+.NH 2
+Outages and Reboots
+.P
+Tunnels sometimes go down because the other
+end crashes, or disconnects, or has a network link break,
+and there is no notice of this in the general case.
+(Even in the event of a crash and
+successful reboot, other SGs don't hear about it unless the
+rebooted SG has specific reason to talk to them immediately.)
+Over-quick response to temporary network outages is undesirable...
+but note that a tunnel can be torn
+down and then re-established without any user-visible effect except
+a pause in traffic,
+whereas if one end does reboot,
+the other end can't get packets to it \fIat all\fR (except via IKE)
+until the situation is noticed.
+So a bias toward quick response is appropriate,
+even at the cost of occasional false alarms.
+.P
+Heartbeat mechanisms are somewhat unsatisfactory for this.
+Unless they are very frequent, which causes other problems,
+they do not detect the problem promptly.
+.A
+What is really wanted is authenticated ICMP.
+This might be a case where public-key encryption/authentication
+of network packets is the right thing to do,
+despite the expense.
+.P
+In the absence of that, a two-part approach seems warranted.
+.P
+First,
+when an SG receives an IPsec packet that is addressed to it,
+and otherwise appears healthy,
+but specifies an unknown SA and is from a host that the receiver currently
+has no keying channel to,
+the receiver must attempt to inform the sender
+via an IKE Initial-Contact notification
+(necessarily sent in plaintext,
+since there is no suitable keying channel).
+This must be severely rate-limited on \fIboth\fR ends;
+one notification per SG pair per minute seems ample.
+.P
+Second, there is an obvious difficulty with this:
+the Initial-Contact notification is unauthenticated
+and cannot be trusted.
+So it must be taken as a hint only:
+there must be a way to confirm it.
+.P
+What is needed here is something that's desirable for
+debugging and testing anyway:
+an IKE-level ping mechanism.
+Pinging direct at the IP level instead will not tell us about a
+crash/reboot event.
+Sending pings through tunnels has
+various complications (they should stop at the far mouth of the tunnel
+instead of going on to a subnet; they should not count against idle
+timers; etc.).
+What is needed is a continuity check on a keying channel.
+(This could also be used as a heartbeat,
+should that seem useful.)
+.P
+IKE Ping delivery need not be reliable, since the whole point of a ping is
+simply to provoke an acknowledgement.
+They should preferably be authenticated,
+but it is not clear that this is absolutely necessary,
+although if they are not they need
+encryption plus a timestamp or a nonce,
+to foil replay mischief.
+How they are implemented is a secondary issue,
+and a separate design proposal will be prepared.
+.A
+Some existing implementations are already using
+(private) notify value 30000 (``LIKE_HELLO'') as ping
+and (private) notify value 30002 (``SHUT_UP'') as ping reply.
+.P
+If an IKE Ping gets no response, try some (say 8) IP pings,
+spaced a few seconds apart, to check IP connectivity;
+if one comes back, try another IKE Ping;
+if that gets no response,
+the other end probably has rebooted, or otherwise been re-initialized,
+and its tunnels and keying channel(s) should be torn down.
+.P
+In a similar vein,
+giving limited rekeying persistence,
+a short network outage could take some tunnels down without
+disrupting others.
+On receiving a packet for an unknown SA from a host that a keying
+channel is currently open to,
+send that host a Invalid-SPI notification for that SA.
+xxx that's not what Invalid-SPI is for.
+The other host can then tear down the half-torn-down tunnel,
+and negotiate a new tunnel for the traffic
+it presumably still wants to send.
+.P
+Finally,
+it would be helpful if SGs made some attempt to deal intelligently
+with crashes and reboots.
+A deliberate shutdown should include an attempt to notify all other SGs
+currently connected by keying channels,
+using Deletes,
+that communication is about to fail.
+(Again, these will be taken as teardowns;
+attempts by the other SGs to negotiate new tunnels as replacements
+should be ignored at this point.)
+And when possible, SGs should attempt to preserve information
+about currently-connected SGs in non-volatile storage,
+so that after a crash,
+an Initial-Contact can be sent to previous partners to
+indicate loss of all previously-established connections.
+.NH 1
+Conclusions
+.P
+This design appears to achieve the objective of setting up encryption
+with strangers.
+The authentication aspects also seem adequately addressed if the
+destination controls its reverse-map DNS entries
+and the DNS data itself can be reliably authenticated
+as having originated from the legitimate administrators of that
+subnet/FQDN.
+The authentication situation is less satisfactory when DNS is less helpful,
+but it is difficult to see what else could be done about it.
+.NH 1
+References
+.P
+[TBW]
+.NH 1
+Appendix: Separate Design Proposals TBW
+.IP \(bu \w'\(bu'u+2n
+How can we build a web of trust with DNSSEC?
+(See section 2.3.4.)
+.IP \(bu
+How can we extend DNS reverse lookups to permit reverse lookup
+on a subnet?
+(Both address and mask must appear in the name to be looked up.)
+(See section 2.6.)
+.IP \(bu
+How can rekeying be done as robustly as possible?
+(At least partly, this is just documenting current FreeS/WAN practice.)
+(See section 2.7.)
+.IP \(bu
+How should IKE Pings be implemented?
+(See section 3.3.)
diff --git a/doc/performance.html b/doc/performance.html
new file mode 100644
index 000000000..2258eeeda
--- /dev/null
+++ b/doc/performance.html
@@ -0,0 +1,458 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="interop.html">Previous</A>
+<A HREF="testing.html">Next</A>
+<HR>
+<H1><A name="performance">Performance of FreeS/WAN</A></H1>
+ The performance of FreeS/WAN is adequate for most applications.
+<P>In normal operation, the main concern is the overhead for encryption,
+ decryption and authentication of the actual IPsec (<A href="glossary.html#ESP">
+ESP</A> and/or<A href="glossary.html#AH"> AH</A>) data packets. Tunnel
+ setup and rekeying occur so much less frequently than packet processing
+ that, in general, their overheads are not worth worrying about.</P>
+<P>At startup, however, tunnel setup overheads may be significant. If
+ you reboot a gateway and it needs to establish many tunnels, expect
+ some delay. This and other issues for large gateways are discussed<A href="#biggate">
+ below</A>.</P>
+<H2><A name="pub.bench">Published material</A></H2>
+<P>The University of Wales at Aberystwyth has done quite detailed speed
+ tests and put<A href="http://tsc.llwybr.org.uk/public/reports/SWANTIME/">
+ their results</A> on the web.</P>
+<P>Davide Cerri's<A href="http://www.linux.it/~davide/doc/"> thesis (in
+ Italian)</A> includes performance results for FreeS/WAN and for<A href="glossary.html#TLS">
+ TLS</A>. He posted an<A href="http://lists.freeswan.org/pipermail/users/2001-December/006303.html">
+ English summary</A> on the mailing list.</P>
+<P>Steve Bellovin used one of AT&amp;T Research's FreeS/WAN gateways as his
+ data source for an analysis of the cache sizes required for key
+ swapping in IPsec. Available as<A href="http://www.research.att.com/~smb/talks/key-agility.email.txt">
+ text</A> or<A href="http://www.research.att.com/~smb/talks/key-agility.pdf">
+ PDF slides</A> for a talk on the topic.</P>
+<P>See also the NAI work mentioned in the next section.</P>
+<H2><A name="perf.estimate">Estimating CPU overheads</A></H2>
+<P>We can come up with a formula that roughly relates CPU speed to the
+ rate of IPsec processing possible. It is far from exact, but should be
+ usable as a first approximation.</P>
+<P>An analysis of authentication overheads for high-speed networks,
+ including some tests using FreeS/WAN, is on the<A href="http://www.pgp.com/research/nailabs/cryptographic/adaptive-cryptographic.asp">
+ NAI Labs site</A>. In particular, see figure 3 in this<A href="http://download.nai.com/products/media/pgp/pdf/acsa_final_report.pdf">
+ PDF document</A>. Their estimates of overheads, measured in Pentium II
+ cycles per byte processed are:</P>
+<TABLE align="center" border="1"><TBODY></TBODY>
+<TR><TH></TH><TH>IPsec</TH><TH>authentication</TH><TH>encryption</TH><TH>
+cycles/byte</TH></TR>
+<TR><TD>Linux IP stack alone</TD><TD>no</TD><TD>no</TD><TD>no</TD><TD align="right">
+5</TD></TR>
+<TR><TD>IPsec without crypto</TD><TD>yes</TD><TD>no</TD><TD>no</TD><TD align="right">
+11</TD></TR>
+<TR><TD>IPsec, authentication only</TD><TD>yes</TD><TD>SHA-1</TD><TD>no</TD><TD
+align="right">24</TD></TR>
+<TR><TD>IPsec with encryption</TD><TD>yes</TD><TD>yes</TD><TD>yes</TD><TD
+align="right">not tested</TD></TR>
+</TABLE>
+<P>Overheads for IPsec with encryption were not tested in the NAI work,
+ but Antoon Bosselaers'<A href="http://www.esat.kuleuven.ac.be/~bosselae/fast.html">
+ web page</A> gives cost for his optimised Triple DES implementation as
+ 928 Pentium cycles per block, or 116 per byte. Adding that to the 24
+ above, we get 140 cycles per byte for IPsec with encryption.</P>
+<P>At 140 cycles per byte, a 140 MHz machine can handle a megabyte -- 8
+ megabits -- per second. Speeds for other machines will be proportional
+ to this. To saturate a link with capacity C megabits per second, you
+ need a machine running at<VAR> C * 140/8 = C * 17.5</VAR> MHz.</P>
+<P>However, that estimate is not precise. It ignores the differences
+ between:</P>
+<UL>
+<LI>NAI's test packets and real traffic</LI>
+<LI>NAI's Pentium II cycles, Bosselaers' Pentium cycles, and your
+ machine's cycles</LI>
+<LI>different 3DES implementations</LI>
+<LI>SHA-1 and MD5</LI>
+</UL>
+<P>and does not account for some overheads you will almost certainly
+ have:</P>
+<UL>
+<LI>communication on the client-side interface</LI>
+<LI>switching between multiple tunnels -- re-keying, cache reloading and
+ so on</LI>
+</UL>
+<P>so we suggest using<VAR> C * 25</VAR> to get an estimate with a bit
+ of a built-in safety factor.</P>
+<P>This covers only IP and IPsec processing. If you have other loads on
+ your gateway -- for example if it is also working as a firewall -- then
+ you will need to add your own safety factor atop that.</P>
+<P>This estimate matches empirical data reasonably well. For example,
+ Metheringham's tests, described<A href="#klips.bench"> below</A>, show
+ a 733 topping out between 32 and 36 Mbit/second, pushing data as fast
+ as it can down a 100 Mbit link. Our formula suggests you need at least
+ an 800 to handle a fully loaded 32 Mbit link. The two results are
+ consistent.</P>
+<P>Some examples using this estimation method:</P>
+<TABLE align="center" border="1"><TBODY></TBODY>
+<TR><TH colspan="2">Interface</TH><TH colspan="3">Machine speed in MHz</TH>
+</TR>
+<TR><TH>Type</TH><TH>Mbit per
+<BR> second</TH><TH>Estimate
+<BR> Mbit*25</TH><TH>Minimum IPSEC gateway</TH><TH>Minimum with other
+ load
+<P>(e.g. firewall)</P>
+</TH></TR>
+<TR><TD>DSL</TD><TD align="right">1</TD><TD align="right">25 MHz</TD><TD rowspan="2">
+whatever you have</TD><TD rowspan="2">133, or better if you have it</TD></TR>
+<TR><TD>cable modem</TD><TD align="right">3</TD><TD align="right">75 MHz</TD>
+</TR>
+<TR><TD><STRONG>any link, light load</STRONG></TD><TD align="right"><STRONG>
+5</STRONG></TD><TD align="right">125 MHz</TD><TD>133</TD><TD>200+,<STRONG>
+ almost any surplus machine</STRONG></TD></TR>
+<TR><TD>Ethernet</TD><TD align="right">10</TD><TD align="right">250 MHz</TD><TD>
+surplus 266 or 300</TD><TD>500+</TD></TR>
+<TR><TD><STRONG>fast link, moderate load</STRONG></TD><TD align="right"><STRONG>
+20</STRONG></TD><TD align="right">500 MHz</TD><TD>500</TD><TD>800+,<STRONG>
+ any current off-the-shelf PC</STRONG></TD></TR>
+<TR><TD>T3 or E3</TD><TD align="right">45</TD><TD align="right">1125 MHz</TD><TD>
+1200</TD><TD>1500+</TD></TR>
+<TR><TD>fast Ethernet</TD><TD align="right">100</TD><TD align="right">
+2500 MHz</TD><TD align="center" colspan="2" rowspan="2">// not feasible
+ with 3DES in software on current machines //</TD></TR>
+<TR><TD>OC3</TD><TD align="right">155</TD><TD align="right">3875 MHz</TD>
+</TR>
+</TABLE>
+<P>Such an estimate is far from exact, but should be usable as minimum
+ requirement for planning. The key observations are:</P>
+<UL>
+<LI>older<STRONG> surplus machines</STRONG> are fine for IPsec gateways
+ at loads up to<STRONG> 5 megabits per second</STRONG> or so</LI>
+<LI>a<STRONG> mid-range new machine</STRONG> can handle IPsec at rates
+ up to<STRONG> 20 megabits per second</STRONG> or more</LI>
+</UL>
+<H3><A name="perf.more">Higher performance alternatives</A></H3>
+<P><A href="glossary.html#AES">AES</A> is a new US government block
+ cipher standard, designed to replace the obsolete<A href="glossary.html#DES">
+ DES</A>. If FreeS/WAN using<A href="glossary.html#3DES"> 3DES</A> is
+ not fast enough for your application, the AES<A href="web.html#patch">
+ patch</A> may help.</P>
+<P>To date (March 2002) we have had only one<A href="http://lists.freeswan.org/pipermail/users/2002-February/007771.html">
+ mailing list report</A> of measurements with the patch applied. It
+ indicates that, at least for the tested load on that user's network,<STRONG>
+ AES roughly doubles IPsec throughput</STRONG>. If further testing
+ confirms this, it may prove possible to saturate an OC3 link in
+ software on a high-end box.</P>
+<P>Also, some work is being done toward support of<A href="compat.html#hardware">
+ hardware IPsec acceleration</A> which might extend the range of
+ requirements FreeS/WAN could meet.</P>
+<H3><A NAME="11_2_2">Other considerations</A></H3>
+<P>CPU speed may be the main issue for IPsec performance, but of course
+ it isn't the only one.</P>
+<P>You need good ethernet cards or other network interface hardware to
+ get the best performance. See this<A href="http://www.ethermanage.com/ethernet/ethernet.html">
+ ethernet information</A> page and this<A href="http://www.scyld.com/diag">
+ Linux network driver</A> page.</P>
+<P>The current FreeS/WAN kernel code is largely single-threaded. It is
+ SMP safe, and will run just fine on a multiprocessor machine (<A href="compat.html#multiprocessor">
+discussion</A>), but the load within the kernel is not shared
+ effectively. This means that, for example to saturate a T3 -- which
+ needs about a 1200 MHz machine -- you cannot expect something like a
+ dual 800 to do the job.</P>
+<P>On the other hand, SMP machines do tend to share loads well so --
+ provided one CPU is fast enough for the IPsec work -- a multiprocessor
+ machine may be ideal for a gateway with a mixed load.</P>
+<H2><A name="biggate">Many tunnels from a single gateway</A></H2>
+<P>FreeS/WAN allows a single gateway machine to build tunnels to many
+ others. There may, however, be some problems for large numbers as
+ indicated in this message from the mailing list:</P>
+<PRE>Subject: Re: Maximum number of ipsec tunnels?
+ Date: Tue, 18 Apr 2000
+ From: &quot;John S. Denker&quot; &lt;jsd@research.att.com&gt;
+
+Christopher Ferris wrote:
+
+&gt;&gt; What are the maximum number ipsec tunnels FreeS/WAN can handle??
+
+Henry Spencer wrote:
+
+&gt;There is no particular limit. Some of the setup procedures currently
+&gt;scale poorly to large numbers of connections, but there are (clumsy)
+&gt;workarounds for that now, and proper fixes are coming.
+
+1) &quot;Large&quot; numbers means anything over 50 or so. I routinely run boxes
+with about 200 tunnels. Once you get more than 50 or so, you need to worry
+about several scalability issues:
+
+a) You need to put a &quot;-&quot; sign in syslogd.conf, and rotate the logs daily
+not weekly.
+
+b) Processor load per tunnel is small unless the tunnel is not up, in which
+case a new half-key gets generated every 90 seconds, which can add up if
+you've got a lot of down tunnels.
+
+c) There's other bits of lore you need when running a large number of
+tunnels. For instance, systematically keeping the .conf file free of
+conflicts requires tools that aren't shipped with the standard freeswan
+package.
+
+d) The pluto startup behavior is quadratic. With 200 tunnels, this eats up
+several minutes at every restart. I'm told fixes are coming soon.
+
+2) Other than item (1b), the CPU load depends mainly on the size of the
+pipe attached, not on the number of tunnels.
+</PRE>
+<P>It is worth noting that item (1b) applies only to repeated attempts
+ to re-key a data connection (IPsec SA, Phase 2) over an established
+ keying connection (ISAKMP SA, Phase 1). There are two ways to reduce
+ this overhead using settings in<A href="manpage.d/ipsec.conf.5.html">
+ ipsec.conf(5)</A>:</P>
+<UL>
+<LI>set<VAR> keyingtries</VAR> to some small value to limit repetitions</LI>
+<LI>set<VAR> keylife</VAR> to a short time so that a failing data
+ connection will be cleaned up when the keying connection is reset.</LI>
+</UL>
+<P>The overheads for establishing keying connections (ISAKMP SAs, Phase
+ 1) are lower because for these Pluto does not perform expensive
+ operations before receiving a reply from the peer.</P>
+<P>A gateway that does a lot of rekeying -- many tunnels and/or low
+ settings for tunnel lifetimes -- will also need a lot of<A href="glossary.html#random">
+ random numbers</A> from the random(4) driver.</P>
+<H2><A name="low-end">Low-end systems</A></H2>
+<P><EM>Even a 486 can handle a T1 line</EM>, according to this mailing
+ list message:</P>
+<PRE>Subject: Re: linux-ipsec: IPSec Masquerade
+ Date: Fri, 15 Jan 1999 11:13:22 -0500
+ From: Michael Richardson
+
+. . . A 486/66 has been clocked by Phil Karn to do
+10Mb/s encryption.. that uses all the CPU, so half that to get some CPU,
+and you have 5Mb/s. 1/3 that for 3DES and you get 1.6Mb/s....</PRE>
+<P>and a piece of mail from project technical lead Henry Spencer:</P>
+<PRE>Oh yes, and a new timing point for Sandy's docs... A P60 -- yes, a 60MHz
+Pentium, talk about antiques -- running a host-to-host tunnel to another
+machine shows an FTP throughput (that is, end-to-end results with a real
+protocol) of slightly over 5Mbit/s either way. (The other machine is much
+faster, the network is 100Mbps, and the ether cards are good ones... so
+the P60 is pretty definitely the bottleneck.)</PRE>
+<P>From the above, and from general user experience as reported on the
+ list, it seems clear that a cheap surplus machine -- a reasonable 486,
+ a minimal Pentium box, a Sparc 5, ... -- can easily handle a home
+ office or a small company connection using any of:</P>
+<UL>
+<LI>ADSL service</LI>
+<LI>cable modem</LI>
+<LI>T1</LI>
+<LI>E1</LI>
+</UL>
+<P>If available, we suggest using a Pentium 133 or better. This should
+ ensure that, even under maximum load, IPsec will use less than half the
+ CPU cycles. You then have enough left for other things you may want on
+ your gateway -- firewalling, web caching, DNS and such.</P>
+<H2><A name="klips.bench">Measuring KLIPS</A></H2>
+<P>Here is some additional data from the mailing list.</P>
+<PRE>Subject: FreeSWAN (specically KLIPS) performance measurements
+ Date: Thu, 01 Feb 2001
+ From: Nigel Metheringham &lt;Nigel.Metheringham@intechnology.co.uk&gt;
+
+I've spent a happy morning attempting performance tests against KLIPS
+(this is due to me not being able to work out the CPU usage of KLIPS so
+resorting to the crude measurements of maximum throughput to give a
+baseline to work out loading of a box).
+
+Measurements were done using a set of 4 boxes arranged in a line, each
+connected to the next by 100Mbit duplex ethernet. The inner 2 had an
+ipsec tunnel between them (shared secret, but I was doing measurements
+when the tunnel was up and running - keying should not be an issue
+here). The outer pair of boxes were traffic generators or traffic sink.
+
+The crypt boxes are Compaq DL380s - Uniprocessor PIII/733 with 256K
+cache. They have 128M main memory. Nothing significant was running on
+the boxes other than freeswan. The kernel was a 2.2.19pre7 patched
+with freeswan and ext3.
+
+Without an ipsec tunnel in the chain (ie the 2 inner boxes just being
+100BaseT routers), throughput (measured with ttcp) was between 10644
+and 11320 KB/sec
+
+With an ipsec tunnel in place, throughput was between 3268 and 3402
+KB/sec
+
+These measurements are for data pushed across a TCP link, so the
+traffic on the wire between the 2 ipsec boxes would have been higher
+than this....
+
+vmstat (run during some other tests, so not affecting those figures) on
+the encrypting box shows approx 50% system &amp; 50% idle CPU - which I
+don't believe at all. Interactive feel of the box was significantly
+sluggish.
+
+I also tried running the kernel profiler (see man readprofile) during
+test runs.
+
+A box doing primarily decrypt work showed basically nothing happening -
+I assume interrupts were off.
+A box doing encrypt work showed the following:-
+ Ticks Function Load
+ ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~
+ 956 total 0.0010
+ 532 des_encrypt2 0.1330
+ 110 MD5Transform 0.0443
+ 97 kmalloc 0.1880
+ 39 des_encrypt3 0.1336
+ 23 speedo_interrupt 0.0298
+ 14 skb_copy_expand 0.0250
+ 13 ipsec_tunnel_start_xmit 0.0009
+ 13 Decode 0.1625
+ 11 handle_IRQ_event 0.1019
+ 11 .des_ncbc_encrypt_end 0.0229
+ 10 speedo_start_xmit 0.0188
+ 9 satoa 0.0225
+ 8 kfree 0.0118
+ 8 ip_fragment 0.0121
+ 7 ultoa 0.0365
+ 5 speedo_rx 0.0071
+ 5 .des_encrypt2_end 5.0000
+ 4 _stext 0.0140
+ 4 ip_fw_check 0.0035
+ 2 rj_match 0.0034
+ 2 ipfw_output_check 0.0200
+ 2 inet_addr_type 0.0156
+ 2 eth_copy_and_sum 0.0139
+ 2 dev_get 0.0294
+ 2 addrtoa 0.0143
+ 1 speedo_tx_buffer_gc 0.0024
+ 1 speedo_refill_rx_buf 0.0022
+ 1 restore_all 0.0667
+ 1 number 0.0020
+ 1 net_bh 0.0021
+ 1 neigh_connected_output 0.0076
+ 1 MD5Final 0.0083
+ 1 kmem_cache_free 0.0016
+ 1 kmem_cache_alloc 0.0022
+ 1 __kfree_skb 0.0060
+ 1 ipsec_rcv 0.0001
+ 1 ip_rcv 0.0014
+ 1 ip_options_fragment 0.0071
+ 1 ip_local_deliver 0.0023
+ 1 ipfw_forward_check 0.0139
+ 1 ip_forward 0.0011
+ 1 eth_header 0.0040
+ 1 .des_encrypt3_end 0.0833
+ 1 des_decrypt3 0.0034
+ 1 csum_partial_copy_generic 0.0045
+ 1 call_out_firewall 0.0125
+
+Hope this data is helpful to someone... however the lack of visibility
+into the decrypt side makes things less clear</PRE>
+<H2><A name="speed.compress">Speed with compression</A></H2>
+<P>Another user reported some results for connections with and without
+ IP compression:</P>
+<PRE>Subject: [Users] Speed with compression
+ Date: Fri, 29 Jun 2001
+ From: John McMonagle &lt;johnm@advocap.org&gt;
+
+Did a couple tests with compression using the new 1.91 freeswan.
+
+Running between 2 sites with cable modems. Both using approximately
+130 mhz pentium.
+
+Transferred files with ncftp.
+
+Compressed file was a 6mb compressed installation file.
+Non compressed was 18mb /var/lib/rpm/packages.rpm
+
+ Compressed vpn regular vpn
+Compress file 42.59 kBs 42.08 kBs
+regular file 110.84 kBs 41.66 kBs
+
+Load was about 0 either way.
+Ping times were very similar a bit above 9 ms.
+
+Compression looks attractive to me.</PRE>
+ Later in the same thread, project technical lead Henry Spencer added:
+<PRE>&gt; is there a reason not to switch compression on? I have large gateway boxes
+&gt; connecting 3 connections, one of them with a measly DS1 link...
+
+Run some timing tests with and without, with data and loads representative
+of what you expect in production. That's the definitive way to decide.
+If compression is a net loss, then obviously, leave it turned off. If it
+doesn't make much difference, leave it off for simplicity and hence
+robustness. If there's a substantial gain, by all means turn it on.
+
+If both ends support compression and can successfully negotiate a
+compressed connection (trivially true if both are FreeS/WAN 1.91), then
+the crucial question is CPU cycles.
+
+Compression has some overhead, so one question is whether *your* data
+compresses well enough to save you more CPU cycles (by reducing the volume
+of data going through CPU-intensive encryption/decryption) than it costs
+you. Last time I ran such tests on data that was reasonably compressible
+but not deliberately contrived to be so, this generally was not true --
+compression cost extra CPU cycles -- so compression was worthwhile only if
+the link, not the CPU, was the bottleneck. However, that was before the
+slow-compression bug was fixed. I haven't had a chance to re-run those
+tests yet, but it sounds like I'd probably see a different result. </PRE>
+ The bug he refers to was a problem with the compression libraries that
+ had us using C code, rather than assembler, for compression. It was
+ fixed before 1.91.
+<H2><A name="methods">Methods of measuring</A></H2>
+<P>If you want to measure the loads FreeS/WAN puts on a system, note
+ that tools such as top or measurements such as load average are
+ more-or-less useless for this. They are not designed to measure
+ something that does most of its work inside the kernel.</P>
+<P>Here is a message from FreeS/WAN kernel programmer Richard Guy Briggs
+ on this:</P>
+<PRE>&gt; I have a batch of boxes doing Freeswan stuff.
+&gt; I want to measure the CPU loading of the Freeswan tunnels, but am
+&gt; having trouble seeing how I get some figures out...
+&gt;
+&gt; - Keying etc is in userspace so will show up on the per-process
+&gt; and load average etc (ie pluto's load)
+
+Correct.
+
+&gt; - KLIPS is in the kernel space, and does not show up in load average
+&gt; I think also that the KLIPS per-packet processing stuff is running
+&gt; as part of an interrupt handler so it does not show up in the
+&gt; /proc/stat system_cpu or even idle_cpu figures
+
+It is not running in interrupt handler. It is in the bottom half.
+This is somewhere between user context (careful, this is not
+userspace!) and hardware interrupt context.
+
+&gt; Is this correct, and is there any means of instrumenting how much the
+&gt; cpu is being loaded - I don't like the idea of a system running out of
+&gt; steam whilst still showing 100% idle CPU :-)
+
+vmstat seems to do a fairly good job, but use a running tally to get a
+good idea. A one-off call to vmstat gives different numbers than a
+running stat. To do this, put an interval on your vmstat command
+line.</PRE>
+ and another suggestion from the same thread:
+<PRE>Subject: Re: Measuring the CPU usage of Freeswan
+ Date: Mon, 29 Jan 2001
+ From: Patrick Michael Kane &lt;modus@pr.es.to&gt;
+
+The only truly accurate way to accurately track FreeSWAN CPU usage is to use
+a CPU soaker. You run it on an unloaded system as a benchmark, then start up
+FreeSWAN and take the difference to determine how much FreeSWAN is eating.
+I believe someone has done this in the past, so you may find something in
+the FreeSWAN archives. If not, someone recently posted a URL to a CPU
+soaker benchmark tool on linux-kernel.</PRE>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="interop.html">Previous</A>
+<A HREF="testing.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/policygroups.html b/doc/policygroups.html
new file mode 100644
index 000000000..6a507b1f6
--- /dev/null
+++ b/doc/policygroups.html
@@ -0,0 +1,341 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="quickstart.html">Previous</A>
+<A HREF="faq.html">Next</A>
+<HR>
+<H1><A NAME="4">How to Configure Linux FreeS/WAN with Policy Groups</A></H1>
+<A NAME="policygroups"></A>
+<H2><A NAME="4_1">What are Policy Groups?</A></H2>
+<P><STRONG>Policy Groups</STRONG> are an elegant general mechanism to
+ configure FreeS/WAN. They are useful for many FreeS/WAN users.</P>
+<P>In previous FreeS/WAN versions, you needed to configure each IPsec
+ connection explicitly, on both local and remote hosts. This could
+ become complex.</P>
+<P>By contrast, Policy Groups allow you to set local IPsec policy for
+ lists of remote hosts and networks, simply by listing the hosts and
+ networks which you wish to have special treatment in one of several
+ Policy Group files. FreeS/WAN then internally creates the connections
+ needed to implement each policy.</P>
+<P>In the next section we describe our five Base Policy Groups, which
+ you can use to configure IPsec in many useful ways. Later, we will show
+ you how to create an IPsec VPN using one line of configuration for each
+ remote host or network.</P>
+<A NAME="builtin_policygroups"></A>
+<H3><A NAME="4_1_1">Built-In Security Options</A></H3>
+<P>FreeS/WAN offers these Base Policy Groups:</P>
+<DL>
+<DT>private</DT>
+<DD> FreeS/WAN only communicates privately with the listed<A HREF="glossary.html#CIDR">
+ CIDR</A> blocks. If needed, FreeS/WAN attempts to create a connection
+ opportunistically. If this fails, FreeS/WAN blocks communication.
+ Inbound blocking is assumed to be done by the firewall. FreeS/WAN
+ offers firewall hooks but no modern firewall rules to help with inbound
+ blocking.</DD>
+<DT>private-or-clear</DT>
+<DD> FreeS/WAN prefers private communication with the listed CIDR
+ blocks. If needed, FreeS/WAN attempts to create a connection
+ opportunistically. If this fails, FreeS/WAN allows traffic in the
+ clear.</DD>
+<DT>clear-or-private</DT>
+<DD> FreeS/WAN communicates cleartext with the listed CIDR blocks, but
+ also accepts inbound OE connection requests from them. Also known as<A HREF="glossary.html#passive.OE">
+ passive OE (pOE)</A>, this policy may be used to create an<A HREF="glossary.html#responder">
+ opportunistic responder</A>.</DD>
+<DT>clear</DT>
+<DD> FreeS/WAN only communicates cleartext with the listed CIDR blocks.</DD>
+<DT>block</DT>
+<DD>FreeS/WAN blocks traffic to and from and the listed CIDR blocks.
+ Inbound blocking is assumed to be done by the firewall. FreeS/WAN
+ offers firewall hooks but no modern firewall rules to help with inbound
+ blocking.
+<!-- also called "blockdrop".-->
+</DD>
+</DL>
+<A NAME="policy.group.notes"></A>
+<P>Notes:</P>
+<UL>
+<LI>Base Policy Groups apply to communication with this host only.</LI>
+<LI>The most specific rule (whether policy or pre-configured connection)
+ applies. This has several practical applications:
+<UL>
+<LI>If CIDR blocks overlap, FreeS/WAN chooses the most specific
+ applicable block.</LI>
+<LI>This decision also takes into account any pre-configured connections
+ you may have.</LI>
+<LI>If the most specific connection is a pre-configured connection, the
+ following procedure applies. If that connection is up, it will be used.
+ If it is routed, it will be brought up. If it is added, no action will
+ be taken.</LI>
+</UL>
+</LI>
+<LI>Base Policy Groups are created using built-in connections. Details
+ in<A HREF="manpage.d/ipsec.conf.5.html"> man ipsec.conf</A>.</LI>
+<LI>All Policy Groups are bidirectional.<A HREF="src/policy-groups-table.html">
+ This chart</A> shows some technical details. FreeS/WAN does not support
+ one-way encryption, since it can give users a false sense of security.</LI>
+</UL>
+<H2><A NAME="4_2">Using Policy Groups</A></H2>
+<P>The Base Policy Groups which build IPsec connections rely on
+ Opportunistic Encryption. To use the following examples, you must first
+ become OE-capable, as described in our<A HREF="quickstart.html#quickstart">
+ quickstart guide</A>.<A NAME="example1"></A></P>
+<H3><A NAME="4_2_1">Example 1: Using a Base Policy Group</A></H3>
+<P>Simply place CIDR blocks (<A HREF="#dnswarning">names</A>, IPs or IP
+ ranges) in /etc/ipsec.d/policies/<VAR>[groupname]</VAR>, and reread the
+ policy group files.</P>
+<P>For example, the<VAR> private-or-clear</VAR> policy tells FreeS/WAN
+ to prefer encrypted communication to the listed CIDR blocks. Failing
+ that, it allows talk in the clear.</P>
+<P>To make this your default policy, place<A HREF="glossary.html#fullnet">
+ fullnet</A> in the<VAR> private-or-clear</VAR> policy group file:</P>
+<PRE> [root@xy root]# cat /etc/ipsec.d/policies/private-or-clear
+ # This file defines the set of CIDRs (network/mask-length) to which
+ # communication should be private, if possible, but in the clear otherwise.
+ ....
+ 0.0.0.0/0</PRE>
+<P>and reload your policies with</P>
+<PRE> ipsec auto --rereadgroups</PRE>
+<P>Use<A HREF="quickstart.html#opp.test"> this test</A> to verify
+ opportunistic connections.</P>
+<A NAME="example2"></A>
+<H3><A NAME="4_2_2">Example 2: Defining IPsec Security Policy with
+ Groups</A></H3>
+<P>Defining IPsec security policy with Base Policy Groups is like
+ creating a shopping list: just put CIDR blocks in the appropriate group
+ files. For example:</P>
+<PRE> [root@xy root]# cd /etc/ipsec.d/policies
+ [root@xy policies]# cat private
+ 192.0.2.96/27 # The finance department
+ 192.0.2.192/29 # HR
+ 192.0.2.12 # HR gateway
+ irc.private.example.com # Private IRC server
+
+ [root@xy policies]# cat private-or-clear
+ 0.0.0.0/0 # My default policy: try to encrypt.
+
+ [root@xy policies]# cat clear
+ 192.0.2.18/32 # My POP3 server
+ 192.0.2.19/32 # My Web proxy
+
+ [root@xy policies]# cat block
+ spamsource.example.com</PRE>
+<P>To make these settings take effect, type:</P>
+<PRE> ipsec auto --rereadgroups</PRE>
+<P>Notes:</P>
+<UL>
+<LI>For opportunistic connection attempts to succeed, all participating
+ FreeS/WAN hosts and gateways must be configured for OE.</LI>
+<LI>Examples 3 through 5 show how to implement a detailed<VAR> private</VAR>
+ policy.</LI>
+<LI><A NAME="dnswarning"></A><FONT COLOR="RED"> Warning:</FONT> Using
+ DNS names in policy files and ipsec.conf can be tricky. If the name
+ does not resolve, the policy will not be implemented for that name. It
+ is therefore safer either to use IPs, or to put any critical names in
+ /etc/hosts. We plan to implement periodic DNS retry to help with this.
+<BR> Names are resolved at FreeS/WAN startup, or when the policies are
+ reloaded. Unfortunately, name lookup can hold up the startup process.
+ If you have fast DNS servers, the problem may be less severe.</LI>
+</UL>
+<A HREF="example3"></A>
+<H3><A NAME="4_2_3">Example 3: Creating a Simple IPsec VPN with the<VAR>
+ private</VAR> Group</A></H3>
+<P>You can create an IPsec VPN between several hosts, with only one line
+ of configuration per host, using the<VAR> private</VAR> policy group.</P>
+<P>First, use our<A HREF="quickstart.html"> quickstart guide</A> to set
+ up each participating host with a FreeS/WAN install and OE.</P>
+<P>In one host's<VAR> /etc/ipsec.d/policies/private</VAR>, list the
+ peers to which you wish to protect traffic. For example:</P>
+<PRE> [root@xy root]# cd /etc/ipsec.d/policies
+ [root@xy policies]# cat private
+ 192.0.2.9 # several hosts at example.com
+ 192.0.2.11
+ 192.0.2.12
+ irc.private.example.com
+</PRE>
+<P>Copy the<VAR> private</VAR> file to each host. Remove the local host,
+ and add the initial host.</P>
+<PRE> scp2 /etc/ipsec.d/policies/private root@192.0.2.12:/etc/ipsec.d/policies/private</PRE>
+<P>On each host, reread the policy groups with</P>
+<PRE> ipsec auto --rereadgroups</PRE>
+<P>That's it! You're configured.</P>
+<P>Test by pinging between two hosts. After a second or two, traffic
+ should flow, and</P>
+<PRE> ipsec eroute</PRE>
+<P>should yield something like</P>
+<PRE> 192.0.2.11/32 -&gt; 192.0.2.8/32 =&gt; tun0x149f@192.0.2.8</PRE>
+<P>where your host IPs are substituted for 192.0.2.11 and 192.0.2.8.</P>
+<P>If traffic does not flow, there may be an error in your OE setup.
+ Revisit our<A HREF="quickstart.html"> quickstart guide</A>.</P>
+<P>Our next two examples show you how to add subnets to this IPsec VPN.</P>
+<A NAME="example4"></A>
+<H3><A NAME="4_2_4">Example 4: New Policy Groups to Protect a Subnet</A></H3>
+<P>To protect traffic to a subnet behind your FreeS/WAN gateway, you'll
+ need additional DNS records, and new policy groups. To set up the DNS,
+ see our<A HREF="quickstart.html#opp.gate"> quickstart guide</A>. To
+ create five new policy groups for your subnet, copy these connections
+ to<VAR> /etc/ipsec.conf</VAR>. Substitute your subnet's IPs for
+ 192.0.2.128/29.</P>
+<PRE>
+conn private-net
+ also=private # inherits settings (eg. auto=start) from built in conn
+ leftsubnet=192.0.2.128/29 # your subnet's IPs here
+
+conn private-or-clear-net
+ also=private-or-clear
+ leftsubnet=192.0.2.128/29
+
+conn clear-or-private-net
+ also=clear-or-private
+ leftsubnet=192.0.2.128/29
+
+conn clear-net
+ also=clear
+ leftsubnet=192.0.2.128/29
+
+conn block-net
+ also=block
+ leftsubnet=192.0.2.128/29
+</PRE>
+<P>Copy the gateway's files to serve as the initial policy group files
+ for the new groups:</P>
+<PRE>
+ cp -p /etc/ipsec.d/policies/private /etc/ipsec.d/policies/private-net
+ cp -p /etc/ipsec.d/policies/private-or-clear /etc/ipsec.d/policies/private-or-clear-net
+ cp -p /etc/ipsec.d/policies/clear-or-private /etc/ipsec.d/policies/clear-or-private-net
+ cp -p /etc/ipsec.d/policies/clear /etc/ipsec.d/policies/clear-net
+ cp -p /etc/ipsec.d/policies/block /etc/ipsec.d/policies/block
+</PRE>
+<P><STRONG>Tip: Since a missing policy group file is equivalent to a
+ file with no entries, you need only create files for the connections
+ you'll use.</STRONG></P>
+<P>To test one of your new groups, place the fullnet 0.0.0.0/0 in<VAR>
+ private-or-clear-net</VAR>. Perform the subnet test in<A HREF="quickstart.html#opp.test">
+ our quickstart guide</A>. You should see a connection, and</P>
+<PRE> ipsec eroute</PRE>
+<P>should include an entry which mentions the subnet node's IP and the
+ OE test site IP, like this:</P>
+<PRE> 192.0.2.131/32 -&gt; 192.139.46.77/32 =&gt; tun0x149f@192.0.2.11</PRE>
+<A HREF="example5"></A>
+<H3><A NAME="4_2_5">Example 5: Adding a Subnet to the VPN</A></H3>
+<P>Suppose you wish to secure traffic to a subnet 192.0.2.192/29 behind
+ a FreeS/WAN box 192.0.2.12.</P>
+<P>First, add DNS entries to configure 192.0.2.12 as an opportunistic
+ gateway for that subnet. Instructions are in our<A HREF="quickstart.html#opp.gate">
+ quickstart guide</A>. Next, create a<VAR> private-net</VAR> group on
+ 192.0.2.12 as described in<A HREF="#example4"> Example 4</A>.</P>
+<P>On each other host, add the subnet 192.0.2.192/29 to<VAR> private</VAR>
+, yielding for example</P>
+<PRE> [root@xy root]# cd /etc/ipsec.d/policies
+ [root@xy policies]# cat private
+ 192.0.2.9 # several hosts at example.com
+ 192.0.2.11
+ 192.0.2.12 # HR department gateway
+ 192.0.2.192/29 # HR subnet
+ irc.private.example.com
+</PRE>
+<P>and reread policy groups with</P>
+<PRE> ipsec auto --rereadgroups</PRE>
+<P>That's all the configuration you need.</P>
+<P>Test your VPN by pinging from a machine on 192.0.2.192/29 to any
+ other host:</P>
+<PRE> [root@192.0.2.194]# ping 192.0.2.11</PRE>
+<P>After a second or two, traffic should flow, and</P>
+<PRE> ipsec eroute</PRE>
+<P>should yield something like</P>
+<PRE> 192.0.2.11/32 -&gt; 192.0.2.194/32 =&gt; tun0x149f@192.0.2.12
+</PRE>
+<P>Key:</P>
+<TABLE>
+<TR><TD>1.</TD><TD>192.0.2.11/32</TD><TD>Local start point of the
+ protected traffic.</TD></TR>
+<TR><TD>2.</TD><TD>192.0.2.194/32</TD><TD>Remote end point of the
+ protected traffic.</TD></TR>
+<TR><TD>3.</TD><TD>192.0.2.12</TD><TD>Remote FreeS/WAN node (gateway or
+ host). May be the same as (2).</TD></TR>
+<TR><TD>4.</TD><TD>[not shown]</TD><TD>Local FreeS/WAN node (gateway or
+ host), where you've produced the output. May be the same as (1).</TD></TR>
+</TABLE>
+<P>For additional assurance, you can verify with a packet sniffer that
+ the traffic is being encrypted.</P>
+<P>Note</P>
+<UL>
+<LI>Because strangers may also connect via OE, this type of VPN may
+ require a stricter firewalling policy than a conventional VPN.</LI>
+</UL>
+<H2><A NAME="4_3">Appendix</A></H2>
+<A NAME="hiddenconn"></A>
+<H3><A NAME="4_3_1">Our Hidden Connections</A></H3>
+<P>Our Base Policy Groups are created using hidden connections. These
+ are spelled out in<A HREF="manpage.d/ipsec.conf.5.html"> man ipsec.conf</A>
+ and defined in<VAR> /usr/local/lib/ipsec/_confread</VAR>.</P>
+<A NAME="custom_policygroups"></A>
+<H3><A NAME="4_3_2">Custom Policy Groups</A></H3>
+<P>A policy group is built using a special connection description in<VAR>
+ ipsec.conf</VAR>, which:</P>
+<UL>
+<LI>is<STRONG> generic</STRONG>. It uses<VAR>
+ right=[%group|%opportunisticgroup]</VAR> rather than specific IPs. The
+ connection is cloned for every name or IP range listed in its Policy
+ Group file.</LI>
+<LI>often has a<STRONG> failure rule</STRONG>. This rule, written<VAR>
+ failureshunt=[passthrough|drop|reject|none]</VAR>, tells FreeS/WAN what
+ to do with packets for these CIDRs if it fails to establish the
+ connection. Default is<VAR> none</VAR>.</LI>
+</UL>
+<P>To create a new group:</P>
+<OL>
+<LI>Create its connection definition in<VAR> ipsec.conf</VAR>.</LI>
+<LI>Create a Policy Group file in<VAR> /etc/ipsec.d/policies</VAR> with
+ the same name as your connection.</LI>
+<LI>Put a CIDR block in that file.</LI>
+<LI>Reread groups with<VAR> ipsec auto --rereadgroups</VAR>.</LI>
+<LI>Test:<VAR> ping</VAR> to activate any OE connection, and view
+ results with<VAR> ipsec eroute</VAR>.</LI>
+</OL>
+<A NAME="disable_oe"></A><A NAME="disable_policygroups"></A>
+<H3><A NAME="4_3_3">Disabling Opportunistic Encryption</A></H3>
+<P>To disable OE (eg. policy groups and packetdefault), cut and paste
+ the following lines to<VAR> /etc/ipsec.conf</VAR>:</P>
+<PRE>conn block
+ auto=ignore
+
+conn private
+ auto=ignore
+
+conn private-or-clear
+ auto=ignore
+
+conn clear-or-private
+ auto=ignore
+
+conn clear
+ auto=ignore
+
+conn packetdefault
+ auto=ignore</PRE>
+<P>Restart FreeS/WAN so that the changes take effect:</P>
+<PRE> ipsec setup restart</PRE>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="quickstart.html">Previous</A>
+<A HREF="faq.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/politics.html b/doc/politics.html
new file mode 100644
index 000000000..5dd1e9f96
--- /dev/null
+++ b/doc/politics.html
@@ -0,0 +1,1231 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="umltesting.html">Previous</A>
+<A HREF="ipsec.html">Next</A>
+<HR>
+<H1><A name="politics">History and politics of cryptography</A></H1>
+<P>Cryptography has a long and interesting history, and has been the
+ subject of considerable political controversy.</P>
+<H2><A name="intro.politics">Introduction</A></H2>
+<H3><A NAME="26_1_1">History</A></H3>
+<P>The classic book on the history of cryptography is David Kahn's<A href="biblio.html#Kahn">
+ The Codebreakers</A>. It traces codes and codebreaking from ancient
+ Egypt to the 20th century.</P>
+<P>Diffie and Landau<A href="biblio.html#diffie"> Privacy on the Line:
+ The Politics of Wiretapping and Encryption</A> covers the history from
+ the First World War to the 1990s, with an emphasis on the US.</P>
+<H4>World War II</H4>
+<P>During the Second World War, the British &quot;Ultra&quot; project achieved one
+ of the greatest intelligence triumphs in the history of warfare,
+ breaking many Axis codes. One major target was the Enigma cipher
+ machine, a German device whose users were convinced it was unbreakable.
+ The American &quot;Magic&quot; project had some similar triumphs against Japanese
+ codes.</P>
+<P>There are many books on this period. See our bibliography for
+ several. Two I particularly like are:</P>
+<UL>
+<LI>Andrew Hodges has done a superb<A href="http://www.turing.org.uk/book/">
+ biography</A> of Alan Turing, a key player among the Ultra
+ codebreakers. Turing was also an important computer pioneer. The terms<A
+href="http://www.abelard.org/turpap/turpap.htm"> Turing test</A> and<A href="http://plato.stanford.edu/entries/turing-machine/">
+ Turing machine</A> are named for him, as is the<A href="http://www.acm.org">
+ ACM</A>'s highest technical<A href="http://www.acm.org/awards/taward.html">
+ award</A>.</LI>
+<LI>Neal Stephenson's<A href="biblio.html#neal"> Cryptonomicon</A> is a
+ novel with cryptography central to the plot. Parts of it take place
+ during WW II, other parts today.</LI>
+</UL>
+<P>Bletchley Park, where much of the Ultra work was done, now has a
+ museum and a<A href="http://www.bletchleypark.org.uk/"> web site</A>.</P>
+<P>The Ultra work introduced three major innovations.</P>
+<UL>
+<LI>The first break of Enigma was achieved by Polish Intelligence in
+ 1931. Until then most code-breakers had been linguists, but a different
+ approach was needed to break machine ciphers. Polish Intelligence
+ recruited bright young mathematicians to crack the &quot;unbreakable&quot;
+ Enigma. When war came in 1939, the Poles told their allies about this,
+ putting Britain on the road to Ultra. The British also adopted a
+ mathematical approach.</LI>
+<LI>Machines were extensively used in the attacks. First the Polish
+ &quot;Bombe&quot; for attacking Enigma, then British versions of it, then
+ machines such as Collosus for attacking other codes. By the end of the
+ war, some of these machines were beginning to closely resemble digital
+ computers. After the war, a team at Manchester University, several old
+ Ultra hands included, built one of the world's first actual
+ general-purpose digital computers.</LI>
+<LI>Ultra made codebreaking a large-scale enterprise, producing
+ intelligence on an industrial scale. This was not a &quot;black chamber&quot;,
+ not a hidden room in some obscure government building with a small crew
+ of code-breakers. The whole operation -- from wholesale interception of
+ enemy communications by stations around the world, through large-scale
+ code-breaking and analysis of the decrypted material (with an enormous
+ set of files for cross-referencing), to delivery of intelligence to
+ field commanders -- was huge, and very carefully managed.</LI>
+</UL>
+<P>So by the end of the war, Allied code-breakers were expert at
+ large-scale mechanised code-breaking. The payoffs were enormous.</P>
+<H4><A name="postwar">Postwar and Cold War</A></H4>
+<P>The wartime innovations were enthusiastically adopted by post-war and
+ Cold War signals intelligence agencies. Presumably many nations now
+ have some agency capable of sophisticated attacks on communications
+ security, and quite a few engage in such activity on a large scale.</P>
+<P>America's<A href="glossary.html#NSA"> NSA</A>, for example, is said
+ to be both the world's largest employer of mathematicians and the
+ world's largest purchaser of computer equipment. Such claims may be
+ somewhat exaggerated, but beyond doubt the NSA -- and similar agencies
+ in other countries -- have some excellent mathematicians, lots of
+ powerful computers, sophisticated software, and the organisation and
+ funding to apply them on a large scale. Details of the NSA budget are
+ secret, but there are some published<A href="http://www.fas.org/irp/nsa/nsabudget.html">
+ estimates</A>.</P>
+<P>Changes in the world's communications systems since WW II have
+ provided these agencies with new targets. Cracking the codes used on an
+ enemy's military or diplomatic communications has been common practice
+ for centuries. Extensive use of radio in war made large-scale attacks
+ such as Ultra possible. Modern communications make it possible to go
+ far beyond that. Consider listening in on cell phones, or intercepting
+ electronic mail, or tapping into the huge volumes of data on new media
+ such as fiber optics or satellite links. None of these targets existed
+ in 1950. All of them can be attacked today, and almost certainly are
+ being attacked.</P>
+<P>The Ultra story was not made public until the 1970s. Much of the
+ recent history of codes and code-breaking has not been made public, and
+ some of it may never be. Two important books are:</P>
+<UL>
+<LI>Bamford's<A href="biblio.html#puzzle"> The Puzzle Palace</A>, a
+ history of the NSA</LI>
+<LI>Hager's<A href="http://www.fas.org/irp/eprint/sp/index.html"> Secret
+ Power</A>, about the<A href="http://sg.yahoo.com/government/intelligence/echelon_network/">
+ Echelon</A> system -- the US, UK, Canada, Australia and New Zealand
+ co-operating to monitor much of the world's communications.</LI>
+</UL>
+<P>Note that these books cover only part of what is actually going on,
+ and then only the activities of nations open and democratic enough that
+ (some of) what they are doing can be discovered. A full picture,
+ including:</P>
+<UL>
+<LI>actions of the English-speaking democracies not covered in those
+ books</LI>
+<LI>actions of other more-or-less sane governments</LI>
+<LI>the activities of various more-or-less insane governments</LI>
+<LI>possibilities for unauthorized action by government employees</LI>
+<LI>possible actions by large non-government organisations:
+ corporations, criminals, or conspiracies</LI>
+</UL>
+<P>might be really frightening.</P>
+<H4><A name="recent">Recent history -- the crypto wars</A></H4>
+<P>Until quite recently, cryptography was primarily a concern of
+ governments, especially of the military, of spies, and of diplomats.
+ Much of it was extremely secret.</P>
+<P>In recent years, that has changed a great deal. With computers and
+ networking becoming ubiquitous, cryptography is now important to almost
+ everyone. Among the developments since the 1970s:</P>
+<UL>
+<LI>The US gov't established the Data Encryption Standard,<A href="glossary.html#DES">
+ DES</A>, a<A href="glossary.html#block"> block cipher</A> for
+ cryptographic protection of unclassfied documents.</LI>
+<LI>DES also became widely used in industry, especially regulated
+ industries such as banking.</LI>
+<LI>Other nations produced their own standards, such as<A href="glossary.html#GOST">
+ GOST</A> in the Soviet Union.</LI>
+<LI><A href="glossary.html#public">Public key</A> cryptography was
+ invented by Diffie and Hellman.</LI>
+<LI>Academic conferences such as<A href="http://www-cse.ucsd.edu/users/mihir/crypto2k.html">
+ Crypto</A> and<A href="http://www.esat.kuleuven.ac.be/cosic/eurocrypt2000/">
+ Eurocrypt</A> began.</LI>
+<LI>Several companies began offerring cryptographic products:<A href="glossary.html#RSAco">
+ RSA</A>,<A href="glossary.html#PGPI"> PGP</A>, the many vendors with<A href="glossary.html#PKI">
+ PKI</A> products, ...</LI>
+<LI>Cryptography appeared in other products: operating systems, word
+ processors, ...</LI>
+<LI>Network protocols based on crypto were developed:<A href="glossary.html#SSH">
+ SSH</A>,<A href="glossary.html#SSL"> SSL</A>,<A href="glossary.html#IPsec">
+ IPsec</A>, ...</LI>
+<LI>Crytography came into widespread use to secure bank cards,
+ terminals, ...</LI>
+<LI>The US government replaced<A href="glossary.html#DES"> DES</A> with
+ the much stronger Advanced Encryption Standard,<A href="glossary.html#AES">
+ AES</A></LI>
+</UL>
+<P>This has led to a complex ongoing battle between various mainly
+ government groups wanting to control the spread of crypto and various
+ others, notably the computer industry and the<A href="http://online.offshore.com.ai/security/">
+ cypherpunk</A> crypto advocates, wanting to encourage widespread use.</P>
+<P>Steven Levy has written a fine history of much of this, called<A href="biblio.html#crypto">
+ Crypto: How the Code rebels Beat the Government -- Saving Privacy in
+ the Digital Age</A>.</P>
+<P>The FreeS/WAN project is to a large extent an outgrowth of cypherpunk
+ ideas. Our reasons for doing the project can be seen in these quotes
+ from the<A href="http://www.eff.org/pub/Privacy/Crypto_misc/cypherpunk.manifesto">
+ Cypherpunk Manifesto</A>:</P>
+<BLOCKQUOTE> Privacy is necessary for an open society in the electronic
+ age. ...
+<P>We cannot expect governments, corporations, or other large, faceless
+ organizations to grant us privacy out of their beneficence. It is to
+ their advantage to speak of us, and we should expect that they will
+ speak. ...</P>
+<P>We must defend our own privacy if we expect to have any. ...</P>
+<P>Cypherpunks write code. We know that someone has to write software to
+ defend privacy, and since we can't get privacy unless we all do, we're
+ going to write it. We publish our code so that our fellow Cypherpunks
+ may practice and play with it. Our code is free for all to use,
+ worldwide. We don't much care if you don't approve of the software we
+ write. We know that software can't be destroyed and that a widely
+ dispersed system can't be shut down.</P>
+<P>Cypherpunks deplore regulations on cryptography, for encryption is
+ fundamentally a private act. ...</P>
+<P>For privacy to be widespread it must be part of a social contract.
+ People must come and together deploy these systems for the common good.
+ ...</P>
+</BLOCKQUOTE>
+<P>To quote project leader John Gilmore:</P>
+<BLOCKQUOTE> We are literally in a race between our ability to build and
+ deploy technology, and their ability to build and deploy laws and
+ treaties. Neither side is likely to back down or wise up until it has
+ definitively lost the race.</BLOCKQUOTE>
+<P>If FreeS/WAN reaches its goal of making<A href="intro.html#opp.intro">
+ opportunistic encryption</A> widespread so that secure communication
+ can become the default for a large part of the net, we will have struck
+ a major blow.</P>
+<H3><A name="intro.poli">Politics</A></H3>
+<P>The political problem is that nearly all governments want to monitor
+ their enemies' communications, and some want to monitor their citizens.
+ They may be very interested in protecting some of their own
+ communications, and often some types of business communication, but not
+ in having everyone able to communicate securely. They therefore attempt
+ to restrict availability of strong cryptography as much as possible.</P>
+<P>Things various governments have tried or are trying include:</P>
+<UL>
+<LI>Echelon, a monitor-the-world project of the US, UK, NZ, Australian
+ and Canadian<A href="glossary.html#SIGINT"> signals intelligence</A>
+ agencies. See this<A href="http://sg.yahoo.com/government/intelligence/echelon_network/">
+ collection</A> of links and this<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2640682,00.html">
+ story</A> on the French Parliament's reaction.</LI>
+<LI>Others governments may well have their own Echelon-like projects. To
+ quote the Dutch Minister of Defense, as reported in a German<A href="http://www.heise.de/tp/english/inhalt/te/4729/1.html">
+ magazine</A>:<BLOCKQUOTE> The government believes not only the
+ governments associated with Echelon are able to intercept communication
+ systems, but that it is an activity of the investigative authorities
+ and intelligence services of many countries with governments of
+ different political signature.</BLOCKQUOTE> Even if they have nothing
+ on the scale of Echelon, most intelligence agencies and police forces
+ certainly have some interception capability.</LI>
+<LI><A href="glossary.html#NSA">NSA</A> tapping of submarine
+ communication cables, described in<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2764372,00.html">
+ this article</A></LI>
+<LI>A proposal for international co-operation on<A href="http://www.heise.de/tp/english/special/enfo/4306/1.html">
+ Internet surveillance</A>.</LI>
+<LI>Alleged<A href="http://cryptome.org/nsa-sabotage.htm"> sabotage</A>
+ of security products by the<A href="glossary.html#NSA"> NSA</A> (the US
+ signals intelligence agency).</LI>
+<LI>The German armed forces and some government departments will stop
+ using American software for fear of NSA &quot;back doors&quot;, according to this<A
+href="http://www.theregister.co.uk/content/4/17679.html"> news story</A>
+.</LI>
+<LI>The British Regulation of Investigatory Powers bill. See this<A href="http://www.fipr.org/rip/index.html">
+ web page.</A> and perhaps this<A href="http://ars.userfriendly.org/cartoons/?id=20000806&amp;mode=classic">
+ cartoon</A>.</LI>
+<LI>A Russian<A href="http://www.eff.org/pub/Privacy/Foreign_and_local/Russia/russian_crypto_ban_english.edict">
+ ban</A> on cryptography</LI>
+<LI>Chinese<A href="http://www.eff.org/pub/Misc/Publications/Declan_McCullagh/www/global/china">
+ controls</A> on net use.</LI>
+<LI>The FBI's carnivore system for covert searches of email. See this<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2601502,00.html">
+ news coverage</A> and this<A href="http://www.crypto.com/papers/carnivore-risks.html">
+ risk assessment</A>. The government had an external review of some
+ aspects of this system done. See this<A href="http://www.crypto.com/papers/carnivore_report_comments.html">
+ analysis</A> of that review. Possible defenses against Carnivore
+ include:
+<UL>
+<LI><A href="glossary.html#PGP">PGP</A> for end-to-end mail encryption</LI>
+<LI><A href="http://www.home.aone.net.au/qualcomm/">secure sendmail</A>
+ for server-to-server encryption</LI>
+<LI>IPsec encryption on the underlying IP network</LI>
+</UL>
+</LI>
+<LI>export laws restricting strong cryptography as a munition. See<A href="#exlaw">
+ discussion</A> below.</LI>
+<LI>various attempts to convince people that fundamentally flawed
+ cryptography, such as encryption with a<A href="#escrow"> back door</A>
+ for government access to data or with<A href="#shortkeys"> inadequate
+ key lengths</A>, was adequate for their needs.</LI>
+</UL>
+<P>Of course governments are by no means the only threat to privacy and
+ security on the net. Other threats include:</P>
+<UL>
+<LI>industrial espionage, as for example in this<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2626931,00.html">
+ news story</A></LI>
+<LI>attacks by organised criminals, as in this<A href="http://www.sans.org/newlook/alerts/NTE-bank.htm">
+ large-scale attack</A></LI>
+<LI>collection of personal data by various companies.
+<UL>
+<LI>for example, consider the various corporate winners of Privacy
+ International's<A href="http://www.privacyinternational.org/bigbrother/">
+ Big Brother Awards</A>.</LI>
+<LI><A href="http://www.zeroknowledge.com">Zero Knowledge</A> sell tools
+ to defend against this</LI>
+</UL>
+</LI>
+<LI>individuals may also be a threat in a variety of ways and for a
+ variety of reasons</LI>
+<LI>in particular, an individual with access to government or industry
+ data collections could do considerable damage using that data in
+ unauthorized ways.</LI>
+</UL>
+<P>One<A href="http://www.zdnet.com/zdnn/stories/news/0,4586,2640674,00.html">
+ study</A> enumerates threats and possible responses for small and
+ medium businesses. VPNs are a key part of the suggested strategy.</P>
+<P>We consider privacy a human right. See the UN's<A href="http://www.un.org/Overview/rights.html">
+ Universal Declaration of Human Rights</A>, article twelve:</P>
+<BLOCKQUOTE> No one shall be subjected to arbitrary interference with
+ his privacy, family, home or correspondence, nor to attacks upon his
+ honor and reputation. Everyone has the right to the protection of the
+ law against such interference or attacks.</BLOCKQUOTE>
+<P>Our objective is to help make privacy possible on the Internet using
+ cryptography strong enough not even those well-funded government
+ agencies are likely to break it. If we can do that, the chances of
+ anyone else breaking it are negliible.</P>
+<H3><A NAME="26_1_3">Links</A></H3>
+<P>Many groups are working in different ways to defend privacy on the
+ net and elsewhere. Please consider contributing to one or more of these
+ groups:</P>
+<UL>
+<LI>the EFF's<A href="http://www.eff.org/crypto/"> Privacy Now!</A>
+ campaign</LI>
+<LI>the<A href="http://www.gilc.org"> Global Internet Liberty Campaign</A>
+</LI>
+<LI><A href="http://www.cpsr.org/program/privacy/privacy.html">Computer
+ Professionals for Social Responsibility</A></LI>
+</UL>
+<P>For more on these issues see:</P>
+<UL>
+<LI>Steven Levy (Newsweek's chief technology writer and author of the
+ classic &quot;Hackers&quot;) new book<A href="biblio.html#crypto"> Crypto: How
+ the Code Rebels Beat the Government--Saving Privacy in the Digital Age</A>
+</LI>
+<LI>Simson Garfinkel (Boston Globe columnist and author of books on<A href="biblio.html#PGP">
+ PGP</A> and<A href="biblio.html#practical"> Unix Security</A>) book<A href="biblio.html#Garfinkel">
+ Database Nation: the death of privacy in the 21st century</A></LI>
+</UL>
+<P>There are several collections of<A href="web.html#quotes"> crypto
+ quotes</A> on the net.</P>
+<P>See also the<A href="biblio.html"> bibliography</A> and our list of<A href="web.html#policy">
+ web references</A> on cryptography law and policy.</P>
+<H3><A NAME="26_1_4">Outline of this section</A></H3>
+<P>The remainder of this section includes two pieces of writing by our
+ project leader</P>
+<UL>
+<LI>his<A href="#gilmore"> rationale</A> for starting this</LI>
+<LI>another<A href="#policestate"> discussion</A> of project goals</LI>
+</UL>
+<P>and discussions of:</P>
+<UL>
+<LI><A href="#desnotsecure">why we do not use DES</A></LI>
+<LI><A href="#exlaw">cryptography export laws</A></LI>
+<LI>why<A href="#escrow"> government access to keys</A> is not a good
+ idea</LI>
+<LI>the myth that<A href="#shortkeys"> short keys</A> are adequate for
+ some security requirements</LI>
+</UL>
+<P>and a section on<A href="#press"> press coverage of FreeS/WAN</A>.</P>
+<H2><A name="leader">From our project leader</A></H2>
+<P>FreeS/WAN project founder John Gilmore wrote a web page about why we
+ are doing this. The version below is slightly edited, to fit this
+ format and to update some links. For a version without these edits, see
+ his<A href="http://www.toad.com/gnu/"> home page</A>.</P>
+<CENTER>
+<H3><A name="gilmore">Swan: Securing the Internet against Wiretapping</A>
+</H3>
+</CENTER>
+<P>My project for 1996 was to<B> secure 5% of the Internet traffic
+ against passive wiretapping</B>. It didn't happen in 1996, so I'm still
+ working on it in 1997, 1998, and 1999! If we get 5% in 1999 or 2000, we
+ can secure 20% the next year, against both active and passive attacks;
+ and 80% the following year. Soon the whole Internet will be private and
+ secure. The project is called S/WAN or S/Wan or Swan for Secure Wide
+ Area Network; since it's free software, we call it FreeSwan to
+ distinguish it from various commercial implementations.<A href="http://www.rsa.com/rsa/SWAN/">
+ RSA</A> came up with the term &quot;S/WAN&quot;. Our main web site is at<A href="http://www.freeswan.org/">
+ http://www.freeswan.org/</A>. Want to help?</P>
+<P>The idea is to deploy PC-based boxes that will sit between your local
+ area network and the Internet (near your firewall or router) which
+ opportunistically encrypt your Internet packets. Whenever you talk to a
+ machine (like a Web site) that doesn't support encryption, your traffic
+ goes out &quot;in the clear&quot; as usual. Whenever you connect to a machine
+ that does support this kind of encryption, this box automatically
+ encrypts all your packets, and decrypts the ones that come in. In
+ effect, each packet gets put into an &quot;envelope&quot; on one side of the net,
+ and removed from the envelope when it reaches its destination. This
+ works for all kinds of Internet traffic, including Web access, Telnet,
+ FTP, email, IRC, Usenet, etc.</P>
+<P>The encryption boxes are standard PC's that use freely available
+ Linux software that you can download over the Internet or install from
+ a cheap CDROM.</P>
+<P>This wasn't just my idea; lots of people have been working on it for
+ years. The encryption protocols for these boxes are called<A href="glossary.html#IPsec">
+ IPSEC (IP Security)</A>. They have been developed by the<A href="http://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html">
+ IP Security Working Group</A> of the<A href="http://www.ietf.org/">
+ Internet Engineering Task Force</A>, and will be a standard part of the
+ next major version of the Internet protocols (<A href="http://playground.sun.com/pub/ipng/html/ipng-main.html">
+IPv6</A>). For today's (IP version 4) Internet, they are an option.</P>
+<P>The<A href="http://www.iab.org/iab"> Internet Architecture Board</A>
+ and<A href="http://www.ietf.org/"> Internet Engineering Steering Group</A>
+ have taken a<A href="iab-iesg.stmt"> strong stand</A> that the Internet
+ should use powerful encryption to provide security and privacy. I think
+ these protocols are the best chance to do that, because they can be
+ deployed very easily, without changing your hardware or software or
+ retraining your users. They offer the best security we know how to
+ build, using the Triple-DES, RSA, and Diffie-Hellman algorithms.</P>
+<P>This &quot;opportunistic encryption box&quot; offers the &quot;fax effect&quot;. As each
+ person installs one for their own use, it becomes more valuable for
+ their neighbors to install one too, because there's one more person to
+ use it with. The software automatically notices each newly installed
+ box, and doesn't require a network administrator to reconfigure it.
+ Instead of &quot;virtual private networks&quot; we have a &quot;REAL private network&quot;;
+ we add privacy to the real network instead of layering a
+ manually-maintained virtual network on top of an insecure Internet.</P>
+<H4>Deployment of IPSEC</H4>
+<P>The US government would like to control the deployment of IP Security
+ with its<A href="#exlaw"> crypto export laws</A>. This isn't a problem
+ for my effort, because the cryptographic work is happening outside the
+ United States. A foreign philanthropist, and others, have donated the
+ resources required to add these protocols to the Linux operating
+ system.<A href="http://www.linux.org/"> Linux</A> is a complete, freely
+ available operating system for IBM PC's and several kinds of
+ workstation, which is compatible with Unix. It was written by Linus
+ Torvalds, and is still maintained by a talented team of expert
+ programmers working all over the world and coordinating over the
+ Internet. Linux is distributed under the<A href="glossary.html#GPL">
+ GNU Public License</A>, which gives everyone the right to copy it,
+ improve it, give it to their friends, sell it commercially, or do just
+ about anything else with it, without paying anyone for the privilege.</P>
+<P>Organizations that want to secure their network will be able to put
+ two Ethernet cards into an IBM PC, install Linux on it from a $30 CDROM
+ or by downloading it over the net, and plug it in between their
+ Ethernet and their Internet link or firewall. That's all they'll have
+ to do to encrypt their Internet traffic everywhere outside their own
+ local area network.</P>
+<P>Travelers will be able to run Linux on their laptops, to secure their
+ connection back to their home network (and to everywhere else that they
+ connect to, such as customer sites). Anyone who runs Linux on a
+ standalone PC will also be able to secure their network connections,
+ without changing their application software or how they operate their
+ computer from day to day.</P>
+<P>There will also be numerous commercially available firewalls that use
+ this technology.<A href="http://www.rsa.com/"> RSA Data Security</A> is
+ coordinating the<A href="http://www.rsa.com/rsa/SWAN"> S/Wan (Secure
+ Wide Area Network)</A> project among more than a dozen vendors who use
+ these protocols. There's a<A href="http://www.rsa.com/rsa/SWAN/swan_test.htm">
+ compatability chart</A> that shows which vendors have tested their
+ boxes against which other vendors to guarantee interoperatility.</P>
+<P>Eventually it will also move into the operating systems and
+ networking protocol stacks of major vendors. This will probably take
+ longer, because those vendors will have to figure out what they want to
+ do about the export controls.</P>
+<H4>Current status</H4>
+<P>My initial goal of securing 5% of the net by Christmas '96 was not
+ met. It was an ambitious goal, and inspired me and others to work hard,
+ but was ultimately too ambitious. The protocols were in an early stage
+ of development, and needed a lot more protocol design before they could
+ be implemented. As of April 1999, we have released version 1.0 of the
+ software (<A href="ftp://ftp.xs4all.nl/freeswan/freeswan-1.0.tar.gz">
+freeswan-1.0.tar.gz</A>), which is suitable for setting up Virtual
+ Private Networks using shared secrets for authentication. It does not
+ yet do opportunistic encryption, or use DNSSEC for authentication;
+ those features are coming in a future release.</P>
+<DL>
+<DT>Protocols</DT>
+<DD>The low-level encrypted packet formats are defined. The system for
+ publishing keys and providing secure domain name service is defined.
+ The IP Security working group has settled on an NSA-sponsored protocol
+ for key agreement (called ISAKMP/Oakley), but it is still being worked
+ on, as the protocol and its documentation is too complex and
+ incomplete. There are prototype implementations of ISAKMP. The protocol
+ is not yet defined to enable opportunistic encryption or the use of
+ DNSSEC keys.</DD>
+<DT>Linux Implementation</DT>
+<DD>The Linux implementation has reached its first major release and is
+ ready for production use in manually-configured networks, using Linux
+ kernel version 2.0.36.</DD>
+<DT>Domain Name System Security</DT>
+<DD>There is now a release of BIND 8.2 that includes most DNS Security
+ features.
+<P>The first prototype implementation of Domain Name System Security was
+ funded by<A href="glossary.html#DARPA"> DARPA</A> as part of their<A href="http://www.darpa.mil/ito/research/is/index.html">
+ Information Survivability program</A>.<A href="http://www.tis.com">
+ Trusted Information Systems</A> wrote a modified version of<A href="http://www.isc.org/bind.html">
+ BIND</A>, the widely-used Berkeley implementation of the Domain Name
+ System.</P>
+<P>TIS, ISC, and I merged the prototype into the standard version of
+ BIND. The first production version that supports KEY and SIG records is<B>
+ bind-4.9.5</B>. This or any later version of BIND will do for
+ publishing keys. It is available from the<A href="http://www.isc.org/bind.html">
+ Internet Software Consortium</A>. This version of BIND is not
+ export-controlled since it does not contain any cryptography. Later
+ releases starting with BIND 8.2 include cryptography for authenticating
+ DNS records, which is also exportable. Better documentation is needed.</P>
+</DD>
+</DL>
+<H4>Why?</H4>
+<P>Because I can. I have made enough money from several successful
+ startup companies, that for a while I don't have to work to support
+ myself. I spend my energies and money creating the kind of world that
+ I'd like to live in and that I'd like my (future) kids to live in.
+ Keeping and improving on the civil rights we have in the United States,
+ as we move more of our lives into cyberspace, is a particular goal of
+ mine.</P>
+<H4>What You Can Do</H4>
+<DL>
+<DT>Install the latest BIND at your site.</DT>
+<DD>You won't be able to publish any keys for your domain, until you
+ have upgraded your copy of BIND. The thing you really need from it is
+ the new version of<I> named</I>, the Name Daemon, which knows about the
+ new KEY and SIG record types. So, download it from the<A href="http://www.isc.org/bind.html">
+ Internet Software Consortium</A> and install it on your name server
+ machine (or get your system administrator, or Internet Service
+ Provider, to install it). Both your primary DNS site and all of your
+ secondary DNS sites will need the new release before you will be able
+ to publish your keys. You can tell which sites this is by running the
+ Unix command &quot;dig MYDOMAIN ns&quot; and seeing which sites are mentioned in
+ your NS (name server) records.</DD>
+<DT>Set up a Linux system and run a 2.0.x kernel on it</DT>
+<DD>Get a machine running Linux (say the 5.2 release from<A href="http://www.redhat.com">
+ Red Hat</A>). Give the machine two Ethernet cards.</DD>
+<DT>Install the Linux IPSEC (Freeswan) software</DT>
+<DD>If you're an experienced sysadmin or Linux hacker, install the
+ freeswan-1.0 release, or any later release or snapshot. These releases
+ do NOT provide automated &quot;opportunistic&quot; operation; they must be
+ manually configured for each site you wish to encrypt with.</DD>
+<DT>Get on the linux-ipsec mailing list</DT>
+<DD>The discussion forum for people working on the project, and testing
+ the code and documentation, is: linux-ipsec@clinet.fi. To join this
+ mailing list, send email to<A href="mailto:linux-ipsec-REQUEST@clinet.fi">
+ linux-ipsec-REQUEST@clinet.fi</A> containing a line of text that says
+ &quot;subscribe linux-ipsec&quot;. (You can later get off the mailing list the
+ same way -- just send &quot;unsubscribe linux-ipsec&quot;).</DD>
+<P></P>
+<DT>Check back at this web page every once in a while</DT>
+<DD>I update this page periodically, and there may be new information in
+ it that you haven't seen. My intent is to send email to the mailing
+ list when I update the page in any significant way, so subscribing to
+ the list is an alternative.</DD>
+</DL>
+<P>Would you like to help? I can use people who are willing to write
+ documentation, install early releases for testing, write cryptographic
+ code outside the United States, sell pre-packaged software or systems
+ including this technology, and teach classes for network administrators
+ who want to install this technology. To offer to help, send me email at
+ gnu@toad.com. Tell me what country you live in and what your
+ citizenship is (it matters due to the export control laws; personally I
+ don't care). Include a copy of your resume and the URL of your home
+ page. Describe what you'd like to do for the project, and what you're
+ uniquely qualified for. Mention what other volunteer projects you've
+ been involved in (and how they worked out). Helping out will require
+ that you be able to commit to doing particular things, meet your
+ commitments, and be responsive by email. Volunteer projects just don't
+ work without those things.</P>
+<H4>Related projects</H4>
+<DL>
+<DT>IPSEC for NetBSD</DT>
+<DD>This prototype implementation of the IP Security protocols is for
+ another free operating system.<A href="ftp://ftp.funet.fi/pub/unix/security/net/ip/BSDipsec.tar.gz">
+ Download BSDipsec.tar.gz</A>.</DD>
+<DT>IPSEC for<A href="http://www.openbsd.org"> OpenBSD</A></DT>
+<DD>This prototype implementation of the IP Security protocols is for
+ yet another free operating system. It is directly integrated into the
+ OS release, since the OS is maintained in Canada, which has freedom of
+ speech in software.</DD>
+</DL>
+<H3><A name="policestate">Stopping wholesale monitoring</A></H3>
+<P>From a message project leader John Gilmore posted to the mailing
+ list:</P>
+<PRE>John Denker wrote:
+
+&gt; Indeed there are several ways in which the documentation overstates the
+&gt; scope of what this project does -- starting with the name
+&gt; FreeS/WAN. There's a big difference between having an encrypted IP tunnel
+&gt; versus having a Secure Wide-Area Network. This software does a fine job of
+&gt; the former, which is necessary but not sufficient for the latter.
+
+The goal of the project is to make it very hard to tap your wide area
+communications. The current system provides very good protection
+against passive attacks (wiretapping and those big antenna farms).
+Active attacks, which involve the intruder sending packets to your
+system (like packets that break into sendmail and give them a root
+shell :-) are much harder to guard against. Active attacks that
+involve sending people (breaking into your house and replacing parts
+of your computer with ones that transmit what you're doing) are also
+much harder to guard against. Though we are putting effort into
+protecting against active attacks, it's a much bigger job than merely
+providing strong encryption. It involves general computer security,
+and general physical security, which are two very expensive problems
+for even a site to solve, let alone to build into a whole society.
+
+The societal benefit of building an infrastructure that protects
+well against passive attacks is that it makes it much harder to do
+undetected bulk monitoring of the population. It's a defense against
+police-states, not against policemen.
+
+Policemen can put in the effort required to actively attack sites that
+they have strong suspicions about. But police states won't be able to
+build systems that automatically monitor everyone's communications.
+Either they will be able to monitor only a small subset of the
+populace (by targeting those who screwed up their passive security),
+or their monitoring activities will be detectable by those monitored
+(active attacks leave packet traces or footprints), which can then be
+addressed through the press and through political means if they become
+too widespread.
+
+FreeS/WAN does not protect very well against traffic analysis, which
+is a kind of widespread police-state style monitoring that still
+reveals significant information (who's talking to who) without
+revealing the contents of what was said. Defenses against traffic
+analysis are an open research problem. Zero Knowledge Systems is
+actively deploying a system designed to thwart it, designed by Ian
+Goldberg. The jury is out on whether it actually works; a lot more
+experience with it will be needed.</PRE>
+<P>Notes on things mentioned in that message:</P>
+<UL>
+<LI>Denker is a co-author of a<A href="intro.html#applied"> paper</A> on
+ a large FreeS/WAN application.</LI>
+<LI>Information on Zero Knowledge is on their<A href="http://www.zks.net/">
+ web site</A>. Their Freedom product, designed to provide untracable
+ pseudonyms for use on the net, is no longer marketed.</LI>
+<LI>Another section of our documentation discusses ways to<A href="ipsec.html#traffic.resist">
+ resist traffic analysis</A>.</LI>
+</UL>
+<H2><A name="weak">Government promotion of weak crypto</A></H2>
+<P>Various groups, especially governments and especially the US
+ government, have a long history of advocating various forms of bogus
+ security.</P>
+<P>We regard bogus security as extremely dangerous. If users are
+ deceived into relying on bogus security, then they may be exposed to
+ large risks. They would be better off having no security and knowing
+ it. At least then they would be careful about what they said.</P>
+<P><STRONG>Avoiding bogus security is a key design criterion for
+ everything we do in FreeS/WAN</STRONG>. The most conspicuous example is
+ our refusal to support<A href="#desnotsecure"> single DES</A>. Other
+ IPsec &quot;features&quot; which we do not implement are discussed in our<A href="compat.html#dropped">
+ compatibility</A> document.</P>
+<H3><A name="escrow">Escrowed encryption</A></H3>
+<P>Various governments have made persistent attempts to encourage or
+ mandate &quot;escrowed encrytion&quot;, also called &quot;key recovery&quot;, or GAK for
+ &quot;government access to keys&quot;. The idea is that cryptographic keys be
+ held by some third party and turned over to law enforcement or security
+ agencies under some conditions.</P>
+<PRE> Mary had a little key - she kept it in escrow,
+ and every thing that Mary said,
+ the feds were sure to know.</PRE>
+<P>A<A href="web.html#quotes"> crypto quotes</A> page attributes this to<A
+href="http://www.scramdisk.clara.net/"> Sam Simpson</A>.</P>
+<P>There is an excellent paper available on<A href="http://www.cdt.org/crypto/risks98/">
+ Risks of Escrowed Encryption</A>, from a group of cryptographic
+ luminaries which included our project leader.</P>
+<P>Like any unnecessary complication, GAK tends to weaken security of
+ any design it infects. For example:</P>
+<UL>
+<LI>Matt Blaze found a fatal flaw in the US government's Clipper chip
+ shortly after design information became public. See his paper &quot;Protocol
+ Failure in the Escrowed Encryption Standard&quot; on his<A href="http://www.crypto.com/papers/">
+ papers</A> page.</LI>
+<LI>a rather<A href="http://www.pgp.com/other/advisories/adk.asp"> nasty
+ bug</A> was found in the &quot;additional decryption keys&quot; &quot;feature&quot; of some
+ releases of<A href="glossary.html#PGP"> PGP</A></LI>
+</UL>
+<P>FreeS/WAN does not support escrowed encryption, and never will.</P>
+<H3><A name="shortkeys">Limited key lengths</A></H3>
+<P>Various governments, and some vendors, have also made persistent
+ attempts to convince people that:</P>
+<UL>
+<LI>weak systems are sufficient for some data</LI>
+<LI>strong cryptography should be reserved for cases where the extra
+ overheads are justified</LI>
+</UL>
+<P><STRONG>This is utter nonsense</STRONG>.</P>
+<P>Weak systems touted include:</P>
+<UL>
+<LI>the ludicrously weak (deliberately crippled) 40-bit ciphers that
+ until recently were all various<A href="#exlaw"> export laws</A>
+ allowed</LI>
+<LI>56-bit single DES, discussed<A href="#desnotsecure"> below</A></LI>
+<LI>64-bit symmetric ciphers and 512-bit RSA, the maximums for
+ unrestricted export under various current laws</LI>
+</UL>
+<P>The notion that choice of ciphers or keysize should be determined by
+ a trade-off between security requirements and overheads is pure
+ bafflegab.</P>
+<UL>
+<LI>For most<A href="glossary.html#symmetric"> symmetric ciphers</A>, it
+ is simply a lie. Any block cipher has some natural maximum keysize
+ inherent in the design -- 128 bits for<A href="glossary.html#IDEA">
+ IDEA</A> or<A href="glossary.html#CAST128"> CAST-128</A>, 256 for
+ Serpent or Twofish, 448 for<A href="glossary.html#Blowfish"> Blowfish</A>
+ and 2048 for<A href="glossary.html#RC4"> RC4</A>. Using a key size
+ smaller than that limit gives<EM> exactly zero</EM> savings in
+ overhead. The crippled 40-bit or 64-bit version of the cipher provides<EM>
+ no advantage whatsoever</EM>.</LI>
+<LI><A href="glossary.html#AES">AES</A> uses 10 rounds with 128-bit
+ keys, 12 rounds for 192-bit and 14 rounds for 256-bit, so there
+ actually is a small difference in overhead, but not enough to matter in
+ most applications.</LI>
+<LI>For<A href="glossary.html#3DES"> triple DES</A> there is a grain of
+ truth in the argument. 3DES is indeed three times slower than single
+ DES. However, the solution is not to use the insecure single DES, but
+ to pick a faster secure cipher.<A href="glossary.html#CAST128">
+ CAST-128</A>,<A href="glossary.html#Blowfish"> Blowfish</A> and the<A href="glossary.html#AES">
+ AES candidate</A> ciphers are are all considerably faster in software
+ than DES (let alone 3DES!), and apparently secure.</LI>
+<LI>For<A href="glossary.html#public"> public key</A> techniques, there
+ are extra overheads for larger keys, but they generally do not affect
+ overall performance significantly. Practical public key applications
+ are usually<A href="glossary.html#hybrid"> hybrid</A> systems in which
+ the bulk of the work is done by a symmetric cipher. The effect of
+ increasing the cost of the public key operations is typically
+ negligible because the public key operations use only a tiny fraction
+ of total resources.
+<P>For example, suppose public key operations use use 1% of the time in
+ a hybrid system and you triple the cost of public key operations. The
+ cost of symmetric cipher operations is unchanged at 99% of the original
+ total cost, so the overall effect is a jump from 99 + 1 = 100 to 99 + 3
+ = 102, a 2% rise in system cost.</P>
+</LI>
+</UL>
+<P>In short,<STRONG> there has never been any technical reason to use
+ inadequate ciphers</STRONG>. The only reason there has ever been for
+ anyone to use such ciphers is that government agencies want weak
+ ciphers used so that they can crack them. The alleged savings are
+ simply propaganda.</P>
+<PRE> Mary had a little key (It's all she could export),
+ and all the email that she sent was opened at the Fort.</PRE>
+<P>A<A href="web.html#quotes"> crypto quotes</A> page attributes this to<A
+href="http://theory.lcs.mit.edu:80/~rivest/"> Ron Rivest</A>. NSA
+ headquarters is at Fort Meade, Maryland.</P>
+<P>Our policy in FreeS/WAN is to use only cryptographic components with
+ adequate keylength and no known weaknesses.</P>
+<UL>
+<LI>We do not implement single DES because it is clearly<A href="#desnotsecure">
+ insecure</A>, so implemeting it would violate our policy of avoiding
+ bogus security. Our default cipher is<A href="glossary.html#3DES"> 3DES</A>
+</LI>
+<LI>Similarly, we do not implement the 768-bit Group 1 for<A href="glossary.html#DH">
+ Diffie-Hellman</A> key negotiation. We provide only the 1024-bit Group
+ 2 and 1536-bit Group 5.</LI>
+</UL>
+<P>Detailed discussion of which IPsec features we implement or omit is
+ in out<A href="compat.html"> compatibility document</A>.</P>
+<P>These decisions imply that we cannot fully conform to the IPsec RFCs,
+ since those have DES as the only required cipher and Group 1 as the
+ only required DH group. (In our view, the standards were subverted into
+ offerring bogus security.) Fortunately, we can still interoperate with
+ most other IPsec implementations since nearly all implementers provide
+ at least 3DES and Group 2 as well.</P>
+<P>We hope that eventually the RFCs will catch up with our (and others')
+ current practice and reject dubious components. Some of our team and a
+ number of others are working on this in<A href="glossary.html#IETF">
+ IETF</A> working groups.</P>
+<H4>Some real trade-offs</H4>
+<P>Of course, making systems secure does involve costs, and trade-offs
+ can be made between cost and security. However, the real trade-offs
+ have nothing to do with using weaker ciphers.</P>
+<P>There can be substantial hardware and software costs. There are often
+ substantial training costs, both to train administrators and to
+ increase user awareness of security issues and procedures. There are
+ almost always substantial staff or contracting costs.</P>
+<P>Security takes staff time for planning, implementation, testing and
+ auditing. Some of the issues are subtle; you need good (hence often
+ expensive) people for this. You also need people to monitor your
+ systems and respond to problems. The best safe ever built is insecure
+ if an attacker can work on it for days without anyone noticing. Any
+ computer is insecure if the administrator is &quot;too busy&quot; to check the
+ logs.</P>
+<P>Moreover, someone in your organisation (or on contract to it) needs
+ to spend considerable time keeping up with new developments. EvilDoers<EM>
+ will</EM> know about new attacks shortly after they are found. You need
+ to know about them before your systems are attacked. If your vendor
+ provides a patch, you need to apply it. If the vendor does nothing, you
+ need to complain or start looking for another vendor.</P>
+<P>For a fairly awful example, see this<A href="http://www.sans.org/newlook/alerts/NTE-bank.htm">
+ report</A>. In that case over a million credit card numbers were taken
+ from e-commerce sites, using security flaws in Windows NT servers.
+ Microsoft had long since released patches for most or all of the flaws,
+ but the site administrators had not applied them.</P>
+<P>At an absolute minimum, you must do something about such issues<EM>
+ before</EM> an exploitation tool is posted to the net for downloading
+ by dozens of &quot;script kiddies&quot;. Such a tool might appear at any time
+ from the announcement of the security hole to several months later.
+ Once it appears, anyone with a browser and an attitude can break any
+ system whose administrators have done nothing about the flaw.</P>
+<P>Compared to those costs, cipher overheads are an insignificant factor
+ in the cost of security.</P>
+<P>The only thing using a weak cipher can do for you is to cause all
+ your other investment to be wasted.</P>
+<H2><A name="exlaw">Cryptography Export Laws</A></H2>
+<P>Many nations restrict the export of cryptography and some restrict
+ its use by their citizens or others within their borders.</P>
+<H3><A name="USlaw">US Law</A></H3>
+<P>US laws, as currently interpreted by the US government, forbid export
+ of most cryptographic software from the US in machine-readable form
+ without government permission. In general, the restrictions apply even
+ if the software is widely-disseminated or public-domain and even if it
+ came from outside the US originally. Cryptography is legally a munition
+ and export is tightly controlled under the<A href="glossary.html#EAR">
+ EAR</A> Export Administration Regulations.</P>
+<P>If you are a US citizen, your brain is considered US territory no
+ matter where it is physically located at the moment. The US believes
+ that its laws apply to its citizens everywhere, not just within the US.
+ Providing technical assistance or advice to foreign &quot;munitions&quot;
+ projects is illegal. The US government has very little sense of humor
+ about this issue and does not consider good intentions to be sufficient
+ excuse. Beware.</P>
+<P>The<A href="http://www.bxa.doc.gov/Encryption/"> official website</A>
+ for these regulations is run by the Commerce Department's Bureau of
+ Export Administration (BXA).</P>
+<P>The<A href="http://www.eff.org/bernstein/"> Bernstein case</A>
+ challenges the export restrictions on Constitutional grounds. Code is
+ speech so restrictions on export of code violate the First Amendment's
+ free speech provisions. This argument has succeeded in two levels of
+ court so far. It is quite likely to go on to the Supreme Court.</P>
+<P>The regulations were changed substantially in January 2000,
+ apparently as a government attempt to get off the hook in the Bernstein
+ case. It is now legal to export public domain source code for
+ encryption, provided you notify the<A href="glossary.html#BXA"> BXA</A>
+.</P>
+<P>There are, however, still restrictions in force. Moreover, the
+ regulations can still be changed again whenever the government chooses
+ to do so. Short of a Supreme Court ruling (in the Berstein case or
+ another) that overturns the regulations completely, the problem of
+ export regulation is not likely to go away in the forseeable future.</P>
+<H4><A name="UScontrib">US contributions to FreeS/WAN</A></H4>
+<P>The FreeS/WAN project<STRONG> cannot accept software contributions,<EM>
+ not even small bug fixes</EM>, from US citizens or residents</STRONG>.
+ We want it to be absolutely clear that our distribution is not subject
+ to US export law. Any contribution from an American might open that
+ question to a debate we'd prefer to avoid. It might also put the
+ contributor at serious legal risk.</P>
+<P>Of course Americans can still make valuable contributions (many
+ already have) by reporting bugs, or otherwise contributing to
+ discussions, on the project<A href="mail.html"> mailing list</A>. Since
+ the list is public, this is clearly constitutionally protected free
+ speech.</P>
+<P>Note, however, that the export laws restrict Americans from providing
+ technical assistance to foreign &quot;munitions&quot; projects. The government
+ might claim that private discussions or correspondence with FreeS/WAN
+ developers were covered by this. It is not clear what the courts would
+ do with such a claim, so we strongly encourage Americans to use the
+ list rather than risk the complications.</P>
+<H3><A name="wrong">What's wrong with restrictions on cryptography</A></H3>
+<P>Some quotes from prominent cryptography experts:</P>
+<BLOCKQUOTE> The real aim of current policy is to ensure the continued
+ effectiveness of US information warfare assets against individuals,
+ businesses and governments in Europe and elsewhere.
+<BR><A href="http://www.cl.cam.ac.uk/users/rja14"> Ross Anderson,
+ Cambridge University</A></BLOCKQUOTE><BLOCKQUOTE> If the government
+ were honest about its motives, then the debate about crypto export
+ policy would have ended years ago.
+<BR><A href="http://www.counterpane.com"> Bruce Schneier, Counterpane
+ Systems</A></BLOCKQUOTE><BLOCKQUOTE> The NSA regularly lies to people
+ who ask it for advice on export control. They have no reason not to;
+ accomplishing their goal by any legal means is fine by them. Lying by
+ government employees is legal.
+<BR> John Gilmore.</BLOCKQUOTE>
+<P>The Internet Architecture Board (IAB) and the Internet Engineering
+ Steering Group (IESG) made a<A href="iab-iesg.stmt"> strong statement</A>
+ in favour of worldwide access to strong cryptography. Essentially the
+ same statement is in the appropriately numbered<A href="ftp://ftp.isi.edu/in-notes/rfc1984.txt">
+ RFC 1984</A>. Two critical paragraphs are:</P>
+<BLOCKQUOTE> ... various governments have actual or proposed policies on
+ access to cryptographic technology ...
+<P>(a) ... export controls ...
+<BR> (b) ... short cryptographic keys ...
+<BR> (c) ... keys should be in the hands of the government or ...
+<BR> (d) prohibit the use of cryptology ...</P>
+<P>We believe that such policies are against the interests of consumers
+ and the business community, are largely irrelevant to issues of
+ military security, and provide only a marginal or illusory benefit to
+ law enforcement agencies, ...</P>
+<P>The IAB and IESG would like to encourage policies that allow ready
+ access to uniform strong cryptographic technology for all Internet
+ users in all countries.</P>
+</BLOCKQUOTE>
+<P>Our goal in the FreeS/WAN project is to build just such &quot;strong
+ cryptographic technology&quot; and to distribute it &quot;for all Internet users
+ in all countries&quot;.</P>
+<P>More recently, the same two bodies (IESG and IAB) have issued<A href="ftp://ftp.isi.edu/in-notes/rfc2804.txt">
+ RFC 2804</A> on why the IETF should not build wiretapping capabilities
+ into protocols for the convenience of security or law enforcement
+ agenicies. The abstract from that document is:</P>
+<BLOCKQUOTE> The Internet Engineering Task Force (IETF) has been asked
+ to take a position on the inclusion into IETF standards-track documents
+ of functionality designed to facilitate wiretapping.
+<P>This memo explains what the IETF thinks the question means, why its
+ answer is &quot;no&quot;, and what that answer means.</P>
+</BLOCKQUOTE> A quote from the debate leading up to that RFC:<BLOCKQUOTE>
+ We should not be building surveillance technology into standards. Law
+ enforcement was not supposed to be easy. Where it is easy, it's called
+ a police state.
+<BR> Jeff Schiller of MIT, in a discussion of FBI demands for wiretap
+ capability on the net, as quoted by<A href="http://www.wired.com/news/politics/0,1283,31895,00.html">
+ Wired</A>.</BLOCKQUOTE>
+<P>The<A href="http://www.ietf.org/mailman/listinfo/raven"> Raven</A>
+ mailing list was set up for this IETF discussion.</P>
+<P>Our goal is to go beyond that RFC and prevent Internet wiretapping
+ entirely.</P>
+<H3><A name="Wassenaar">The Wassenaar Arrangement</A></H3>
+<P>Restrictions on the export of cryptography are not just US policy,
+ though some consider the US at least partly to blame for the policies
+ of other nations in this area.</P>
+<P>A number of countries:</P>
+<P>Argentina, Australia, Austria, Belgium, Bulgaria, Canada, Czech
+ Republic, Denmark, Finland, France, Germany, Greece, Hungary, Ireland,
+ Italy, Japan, Luxembourg, Netherlands, New Zealand, Norway, Poland,
+ Portugal, Republic of Korea, Romania, Russian Federation, Slovak
+ Republic, Spain, Sweden, Switzerland, Turkey, Ukraine, United Kingdom
+ and United States</P>
+<P>have signed the Wassenaar Arrangement which restricts export of
+ munitions and other tools of war. Cryptographic sofware is covered
+ there.</P>
+<P>Wassenaar details are available from the<A href="http://www.wassenaar.org/">
+ Wassenaar Secretariat</A>, and elsewhere in a more readable<A href="http://www.fitug.de/news/wa/index.html">
+ HTML version</A>.</P>
+<P>For a critique see the<A href="http://www.gilc.org/crypto/wassenaar">
+ GILC site</A>:</P>
+<BLOCKQUOTE> The Global Internet Liberty Campaign (GILC) has begun a
+ campaign calling for the removal of cryptography controls from the
+ Wassenaar Arrangement.
+<P>The aim of the Wassenaar Arrangement is to prevent the build up of
+ military capabilities that threaten regional and international security
+ and stability . . .</P>
+<P>There is no sound basis within the Wassenaar Arrangement for the
+ continuation of any export controls on cryptographic products.</P>
+</BLOCKQUOTE>
+<P>We agree entirely.</P>
+<P>An interesting analysis of Wassenaar can be found on the<A href="http://www.cyber-rights.org/crypto/wassenaar.htm">
+ cyber-rights.org</A> site.</P>
+<H3><A name="status">Export status of Linux FreeS/WAN</A></H3>
+<P>We believe our software is entirely exempt from these controls since
+ the Wassenaar<A href="http://www.wassenaar.org/list/GTN%20and%20GSN%20-%2099.pdf">
+ General Software Note</A> says:</P>
+<BLOCKQUOTE> The Lists do not control &quot;software&quot; which is either:
+<OL>
+<LI>Generally available to the public by . . . retail . . . or</LI>
+<LI>&quot;In the public domain&quot;.</LI>
+</OL>
+</BLOCKQUOTE>
+<P>There is a note restricting some of this, but it is a sub-heading
+ under point 1, so it appears not to apply to public domain software.</P>
+<P>Their glossary defines &quot;In the public domain&quot; as:</P>
+<BLOCKQUOTE> . . . &quot;technology&quot; or &quot;software&quot; which has been made
+ available without restrictions upon its further dissemination.
+<P>N.B. Copyright restrictions do not remove &quot;technology&quot; or &quot;software&quot;
+ from being &quot;in the public domain&quot;.</P>
+</BLOCKQUOTE>
+<P>We therefore believe that software freely distributed under the<A href="glossary.html#GPL">
+ GNU Public License</A>, such as Linux FreeS/WAN, is exempt from
+ Wassenaar restrictions.</P>
+<P>Most of the development work is being done in Canada. Our
+ understanding is that the Canadian government accepts this
+ interpretation.</P>
+<UL>
+<LI>A web statement of<A href="http://www.dfait-maeci.gc.ca/~eicb/notices/ser113-e.htm">
+ Canadian policy</A> is available from the Department of Foreign Affairs
+ and International Trade.</LI>
+<LI>Another document from that department states that<A href="http://www.dfait-maeci.gc.ca/~eicb/export/gr1_e.htm">
+ public domain software</A> is exempt from the export controls.</LI>
+<LI>A researcher's<A href="http://insight.mcmaster.ca/org/efc/pages/doc/crypto-export.html">
+ analysis</A> of Canadian policy is also available.</LI>
+</UL>
+<P>Recent copies of the freely modifiable and distributable source code
+ exist in many countries. Citizens all over the world participate in its
+ use and evolution, and guard its ongoing distribution. Even if Canadian
+ policy were to change, the software would continue to evolve in
+ countries which do not restrict exports, and would continue to be
+ imported from there into unfree countries. &quot;The Net culture treats
+ censorship as damage, and routes around it.&quot;</P>
+<H3><A name="help">Help spread IPsec around</A></H3>
+<P>You can help. If you don't know of a Linux FreeS/WAN archive in your
+ own country, please download it now to your personal machine, and
+ consider making it publicly accessible if that doesn't violate your own
+ laws. If you have the resources, consider going one step further and
+ setting up a mirror site for the whole<A href="intro.html#munitions">
+ munitions</A> Linux crypto software archive.</P>
+<P>If you make Linux CD-ROMs, please consider including this code, in a
+ way that violates no laws (in a free country, or in a domestic-only CD
+ product).</P>
+<P>Please send a note about any new archive mirror sites or CD
+ distributions to linux-ipsec@clinet.fi so we can update the
+ documentation.</P>
+<P>Lists of current<A href="intro.html#sites"> mirror sites</A> and of<A href="intro.html#distwith">
+ distributions</A> which include FreeS/WAN are in our introduction
+ section.</P>
+<H2><A name="desnotsecure">DES is Not Secure</A></H2>
+<P>DES, the<STRONG> D</STRONG>ata<STRONG> E</STRONG>ncryption<STRONG> S</STRONG>
+tandard, can no longer be considered secure. While no major flaws in its
+ innards are known, it is fundamentally inadequate because its<STRONG>
+ 56-bit key is too short</STRONG>. It is vulnerable to<A href="glossary.html#brute">
+ brute-force search</A> of the whole key space, either by large
+ collections of general-purpose machines or even more quickly by
+ specialized hardware. Of course this also applies to<STRONG> any other
+ cipher with only a 56-bit key</STRONG>. The only reason anyone could
+ have for using a 56 or 64-bit key is to comply with various<A href="exportlaw.html">
+ export laws</A> intended to ensure the use of breakable ciphers.</P>
+<P>Non-government cryptologists have been saying DES's 56-bit key was
+ too short for some time -- some of them were saying it in the 70's when
+ DES became a standard -- but the US government has consistently
+ ridiculed such suggestions.</P>
+<P>A group of well-known cryptographers looked at key lengths in a<A href="http://www.counterpane.com/keylength.html">
+ 1996 paper</A>. They suggested a<EM> minimum</EM> of 75 bits to
+ consider an existing cipher secure and a<EM> minimum of 90 bits for new
+ ciphers</EM>. More recent papers, covering both<A href="glossary.html#symmetric">
+ symmetric</A> and<A href="glossary.html#public"> public key</A> systems
+ are at<A href="http://www.cryptosavvy.com/"> cryptosavvy.com</A> and<A href="http://www.rsasecurity.com/rsalabs/bulletins/bulletin13.html">
+ rsa.com</A>. For all algorithms, the minimum keylengths recommended in
+ such papers are significantly longer than the maximums allowed by
+ various export laws.</P>
+<P>In a<A href="http://www.privacy.nb.ca/cryptography/archives/cryptography/html/1998-09/0095.html">
+ 1998 ruling</A>, a German court described DES as &quot;out-of-date and not
+ safe enough&quot; and held a bank liable for using it.</P>
+<H3><A name="deshware">Dedicated hardware breaks DES in a few days</A></H3>
+<P>The question of DES security has now been settled once and for all.
+ In early 1998, the<A href="http://www.eff.org/"> Electronic Frontier
+ Foundation</A> built a<A href="http://www.eff.org/descracker.html">
+ DES-cracking machine</A>. It can find a DES key in an average of a few
+ days' search. The details of all this, including complete code listings
+ and complete plans for the machine, have been published in<A href="biblio.html#EFF">
+<CITE> Cracking DES</CITE></A>, by the Electronic Frontier Foundation.</P>
+<P>That machine cost just over $200,000 to design and build. &quot;Moore's
+ Law&quot; is that machines get faster (or cheaper, for the same speed) by
+ roughly a factor of two every 18 months. At that rate, their $200,000
+ in 1998 becomes $50,000 in 2001.</P>
+<P>However, Moore's Law is not exact and the $50,000 estimate does not
+ allow for the fact that a copy based on the published EFF design would
+ cost far less than the original. We cannot say exactly what such a
+ cracker would cost today, but it would likely be somewhere between
+ $10,000 and $100,000.</P>
+<P>A large corporation could build one of these out of petty cash. The
+ cost is low enough for a senior manager to hide it in a departmental
+ budget and avoid having to announce or justify the project. Any
+ government agency, from a major municipal police force up, could afford
+ one. Or any other group with a respectable budget -- criminal
+ organisations, political groups, labour unions, religious groups, ...
+ Or any millionaire with an obsession or a grudge, or just strange taste
+ in toys.</P>
+<P>One might wonder if a private security or detective agency would have
+ one for rent. They wouldn't need many clients to pay off that
+ investment.</P>
+<H3><A name="spooks">Spooks may break DES faster yet</A></H3>
+<P>As for the security and intelligence agencies of various nations,
+ they may have had DES crackers for years, and theirs may be much
+ faster. It is difficult to make most computer applications work well on
+ parallel machines, or to design specialised hardware to accelerate
+ them. Cipher-cracking is one of the very few exceptions. It is entirely
+ straightforward to speed up cracking by just adding hardware. Within
+ very broad limits, you can make it as fast as you like if you have the
+ budget. The EFF's $200,000 machine breaks DES in a few days. An<A href="http://www.planepage.com/">
+ aviation website</A> gives the cost of a B1 bomber as $200,000,000.
+ Spending that much, an intelligence agency could break DES in an
+ average time of<EM> six and a half minutes</EM>.</P>
+<P>That estimate assumes they use the EFF's 1998 technology and just
+ spend more money. They may have an attack that is superior to brute
+ force, they quite likely have better chip technology (Moore's law, a
+ bigger budget, and whatever secret advances they may have made) and of
+ course they may have spent the price of an aircraft carrier, not just
+ one aircraft.</P>
+<P>In short, we have<EM> no idea</EM> how quickly these organisations
+ can break DES. Unless they're spectacularly incompetent or horribly
+ underfunded, they can certainly break it, but we cannot guess how
+ quickly. Pick any time unit between days and milliseconds; none is
+ entirely unbelievable. More to the point, none of them is of any
+ comfort if you don't want such organisations reading your
+ communications.</P>
+<P>Note that this may be a concern even if nothing you do is a threat to
+ anyone's national security. An intelligence agency might well consider
+ it to be in their national interest for certain companies to do well.
+ If you're competing against such companies in a world market and that
+ agency can read your secrets, you have a serious problem.</P>
+<P>One might wonder about technology the former Soviet Union and its
+ allies developed for cracking DES during the Cold War. They must have
+ tried; the cipher was an American standard and widely used. Certainly
+ those countries have some fine mathematicians, and those agencies had
+ budget. How well did they succeed? Is their technology now for sale or
+ rent?</P>
+<H3><A name="desnet">Networks break DES in a few weeks</A></H3>
+<P>Before the definitive EFF effort, DES had been cracked several times
+ by people using many machines. See this<A href="http://www.distributed.net/pressroom/DESII-1-PR.html">
+ press release</A> for example.</P>
+<P>A major corporation, university, or government department could break
+ DES by using spare cycles on their existing collection of computers, by
+ dedicating a group of otherwise surplus machines to the problem, or by
+ combining the two approaches. It might take them weeks or months,
+ rather than the days required for the EFF machine, but they could do
+ it.</P>
+<P>What about someone working alone, without the resources of a large
+ organisation? For them, cracking DES will not be easy, but it may be
+ possible. A few thousand dollars buys a lot of surplus workstations. A
+ pile of such machines will certainly heat your garage nicely and might
+ break DES in a few months or years. Or enroll at a university and use
+ their machines. Or use an employer's machines. Or crack security
+ somewhere and steal the resources to crack a DES key. Or write a virus
+ that steals small amounts of resources on many machines. Or . . .</P>
+<P>None of these approaches are easy or break DES really quickly, but an
+ attacker only needs to find one that is feasible and breaks DES quickly
+ enough to be dangerous. How much would you care to bet that this will
+ be impossible if the attacker is clever and determined? How valuable is
+ your data? Are you authorised to risk it on a dubious bet?</P>
+<H3><A name="no_des">We disable DES</A></H3>
+<P>In short, it is now absolutely clear that<STRONG> DES is not secure</STRONG>
+ against</P>
+<UL>
+<LI>any<STRONG> well-funded opponent</STRONG></LI>
+<LI>any opponent (even a penniless one) with access (even stolen access)
+ to<STRONG> enough general purpose computers</STRONG></LI>
+</UL>
+<P>That is why<STRONG> Linux FreeS/WAN disables all transforms which use
+ plain DES</STRONG> for encryption.</P>
+<P>DES is in the source code, because we need DES to implement our
+ default encryption transform,<A href="glossary.html#3DES"> Triple DES</A>
+.<STRONG> We urge you not to use single DES</STRONG>. We do not provide
+ any easy way to enable it in FreeS/WAN, and our policy is to provide no
+ assistance to anyone wanting to do so.</P>
+<H3><A name="40joke">40-bits is laughably weak</A></H3>
+<P>The same is true, in spades, of ciphers -- DES or others -- crippled
+ by 40-bit keys, as many ciphers were required to be until recently
+ under various<A href="#exlaw"> export laws</A>. A brute force search of
+ such a cipher's keyspace is 2<SUP>16</SUP> times faster than a similar
+ search against DES. The EFF's machine can do a brute-force search of a
+ 40-bit key space in<EM> seconds</EM>. One contest to crack a 40-bit
+ cipher was won by a student<A href="http://catless.ncl.ac.uk/Risks/18.80.html#subj1">
+ using a few hundred idle machines at his university</A>. It took only
+ three and half hours.</P>
+<P>We do not, and will not, implement any 40-bit cipher.</P>
+<H3><A name="altdes">Triple DES is almost certainly secure</A></H3>
+<P><A href="glossary.html#3DES">Triple DES</A>, usually abbreviated
+ 3DES, applies DES three times, with three different keys. DES seems to
+ be basically an excellent cipher design; it has withstood several
+ decades of intensive analysis without any disastrous flaws being found.
+ It's only major flaw is that the small keyspace allows brute force
+ attacks to succeeed. Triple DES enlarges the key space to 168 bits,
+ making brute-force search a ridiculous impossibility.</P>
+<P>3DES is currently the only block cipher implemented in FreeS/WAN.
+ 3DES is, unfortunately, about 1/3 the speed of DES, but modern CPUs
+ still do it at quite respectable speeds. Some<A href="glossary.html#benchmarks">
+ speed measurements</A> for our code are available.</P>
+<H3><A name="aes.ipsec">AES in IPsec</A></H3>
+<P>The<A href="glossary.html#AES"> AES</A> project has chosen a
+ replacement for DES, a new standard cipher for use in non-classified US
+ government work and in regulated industries such as banking. This
+ cipher will almost certainly become widely used for many applications,
+ including IPsec.</P>
+<P>The winner, announced in October 2000 after several years of analysis
+ and discussion, was the<A href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">
+ Rijndael</A> cipher from two Belgian designers.</P>
+<P>It is almost certain that FreeS/WAN will add AES support.<A href="web.html#patch">
+ AES patches</A> are already available.</P>
+<H2><A name="press">Press coverage of Linux FreeS/WAN:</A></H2>
+<H3><A NAME="26_6_1">FreeS/WAN 1.0 press</A></H3>
+<UL>
+<LI><A href="http://www.wired.com/news/news/technology/story/19136.html">
+Wired</A> &quot;Linux-Based Crypto Stops Snoops&quot;, James Glave April 15 1999</LI>
+<LI><A href="http://slashdot.org/articles/99/04/15/1851212.shtml">
+Slashdot</A></LI>
+<LI><A href="http://dgl.com/itinfo/1999/it990415.html">DGL</A>, Damar
+ Group Limited; looking at FreeS/WAN from a perspective of business
+ computing</LI>
+<LI><A href="http://linuxtoday.com/stories/5010.html">Linux Today</A></LI>
+<LI><A href="http://www.tbtf.com/archive/1999-04-21.html#Tcep">TBTF</A>,
+ Tasty Bits from the Technology Front</LI>
+<LI><A href="http://www.salonmagazine.com/tech/log/1999/04/16/encryption/index.html">
+Salon Magazine</A> &quot;Free Encryption Takes a Big Step&quot;</LI>
+</UL>
+<H3><A name="release">Press release for version 1.0</A></H3>
+<PRE> Strong Internet Privacy Software Free for Linux Users Worldwide
+
+Toronto, ON, April 14, 1999 -
+
+The Linux FreeS/WAN project today released free software to protect
+the privacy of Internet communications using strong encryption codes.
+FreeS/WAN automatically encrypts data as it crosses the Internet, to
+prevent unauthorized people from receiving or modifying it. One
+ordinary PC per site runs this free software under Linux to become a
+secure gateway in a Virtual Private Network, without having to modify
+users' operating systems or application software. The project built
+and released the software outside the United States, avoiding US
+government regulations which prohibit good privacy protection.
+FreeS/WAN version 1.0 is available immediately for downloading at
+http://www.xs4all.nl/~freeswan/.
+
+&quot;Today's FreeS/WAN release allows network administrators to build
+excellent secure gateways out of old PCs at no cost, or using a cheap
+new PC,&quot; said John Gilmore, the entrepreneur who instigated the
+project in 1996. &quot;They can build operational experience with strong
+network encryption and protect their users' most important
+communications worldwide.&quot;
+
+&quot;The software was written outside the United States, and we do not
+accept contributions from US citizens or residents, so that it can be
+freely published for use in every country,&quot; said Henry Spencer, who
+built the release in Toronto, Canada. &quot;Similar products based in the
+US require hard-to-get government export licenses before they can be
+provided to non-US users, and can never be simply published on a Web
+site. Our product is freely available worldwide for immediate
+downloading, at no cost.&quot;
+
+FreeS/WAN provides privacy against both quiet eavesdropping (such as
+&quot;packet sniffing&quot;) and active attempts to compromise communications
+(such as impersonating participating computers). Secure &quot;tunnels&quot; carry
+information safely across the Internet between locations such as a
+company's main office, distant sales offices, and roaming laptops. This
+protects the privacy and integrity of all information sent among those
+locations, including sensitive intra-company email, financial transactions
+such as mergers and acquisitions, business negotiations, personal medical
+records, privileged correspondence with lawyers, and information about
+crimes or civil rights violations. The software will be particularly
+useful to frequent wiretapping targets such as private companies competing
+with government-owned companies, civil rights groups and lawyers,
+opposition political parties, and dissidents.
+
+FreeS/WAN provides privacy for Internet packets using the proposed
+standard Internet Protocol Security (IPSEC) protocols. FreeS/WAN
+negotiates strong keys using Diffie-Hellman key agreement with 1024-bit
+keys, and encrypts each packet with 168-bit Triple-DES (3DES). A modern
+$500 PC can set up a tunnel in less than a second, and can encrypt
+6 megabits of packets per second, easily handling the whole available
+bandwidth at the vast majority of Internet sites. In preliminary testing,
+FreeS/WAN interoperated with 3DES IPSEC products from OpenBSD, PGP, SSH,
+Cisco, Raptor, and Xedia. Since FreeS/WAN is distributed as source code,
+its innards are open to review by outside experts and sophisticated users,
+reducing the chance of undetected bugs or hidden security compromises.
+
+The software has been in development for several years. It has been
+funded by several philanthropists interested in increased privacy on
+the Internet, including John Gilmore, co-founder of the Electronic
+Frontier Foundation, a leading online civil rights group.
+
+Press contacts:
+Hugh Daniel, +1 408 353 8124, hugh@toad.com
+Henry Spencer, +1 416 690 6561, henry@spsystems.net
+
+* FreeS/WAN derives its name from S/WAN, which is a trademark of RSA Data
+ Security, Inc; used by permission.</PRE>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="umltesting.html">Previous</A>
+<A HREF="ipsec.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/quickstart.html b/doc/quickstart.html
new file mode 100644
index 000000000..44d73abc5
--- /dev/null
+++ b/doc/quickstart.html
@@ -0,0 +1,323 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="upgrading.html">Previous</A>
+<A HREF="policygroups.html">Next</A>
+<HR>
+<H1><A name="quickstart">Quickstart Guide to Opportunistic Encryption</A>
+</H1>
+<A name="quick_guide"></A>
+<H2><A name="opp.setup">Purpose</A></H2>
+<P>This page will get you started using Linux FreeS/WAN with
+ opportunistic encryption (OE). OE enables you to set up IPsec tunnels
+ without co-ordinating with another site administrator, and without hand
+ configuring each tunnel. If enough sites support OE, a &quot;FAX effect&quot;
+ occurs, and many of us can communicate without eavesdroppers.</P>
+<H3><A NAME="3_1_1">OE &quot;flag day&quot;</A></H3>
+<P>As of FreeS/WAN 2.01, OE uses DNS TXT resource records (RRs) only
+ (rather than TXT with KEY). This change causes a<A href="http://jargon.watson-net.com/jargon.asp?w=flag+day">
+ &quot;flag day&quot;</A>. Users of FreeS/WAN 2.00 (or earlier) OE who are
+ upgrading may require additional resource records, as detailed in our<A href="upgrading.html#upgrading.flagday">
+ upgrading document</A>. OE setup instructions here are for 2.02 or
+ later.</P>
+<H2><A name="opp.dns">Requirements</A></H2>
+<P>To set up opportunistic encryption, you will need:</P>
+<UL>
+<LI>a Linux box. For OE to the public Internet, this box must NOT be
+ behind<A HREF="glossary.html#NAT.gloss"> Network Address Translation</A>
+ (NAT).</LI>
+<LI>to install Linux FreeS/WAN 2.02 or later</LI>
+<LI>either control over your reverse DNS (for full opportunism) or the
+ ability to write to some forward domain (for initiator-only).<A HREF="http://www.fdns.net">
+ This free DNS service</A> explicitly supports forward TXT records for
+ FreeS/WAN use.</LI>
+<LI>(for full opportunism) a static IP</LI>
+</UL>
+<P>Note: Currently, only Linux FreeS/WAN supports opportunistic
+ encryption.</P>
+<H2><A name="easy.install">RPM install</A></H2>
+<P>Our instructions are for a recent Red Hat with a 2.4-series stock or
+ Red Hat updated kernel. For other ways to install, see our<A href="install.html#install">
+ install document</A>.</P>
+<H3><A NAME="3_3_1">Download RPMs</A></H3>
+<P>If we have prebuilt RPMs for your Red Hat system, this command will
+ get them:</P>
+<PRE> ncftpget ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs/`uname -r | tr -d 'a-wy-z'`/\*</PRE>
+<P>If that fails, you will need to try<A HREF="install.html"> another
+ install method</A>. Our kernel modules<B> will only work on the Red Hat
+ kernel they were built for</B>, since they are very sensitive to small
+ changes in the kernel.</P>
+<P>If it succeeds, you will have userland tools, a kernel module, and an
+ RPM signing key:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm
+ freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm
+ freeswan-rpmsign.asc</PRE>
+<H3><A NAME="3_3_2">Check signatures</A></H3>
+<P>If you're running RedHat 8.x or later, import the RPM signing key
+ into the RPM database:</P>
+<PRE> rpm --import freeswan-rpmsign.asc</PRE>
+<P>For RedHat 7.x systems, you'll need to add it to your<A HREF="glossary.html#PGP">
+ PGP</A> keyring:</P>
+<PRE> pgp -ka freeswan-rpmsign.asc</PRE>
+<P>Check the digital signatures on both RPMs using:</P>
+<PRE> rpm --checksig freeswan*.rpm </PRE>
+<P>You should see that these signatures are good:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK
+ freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK</PRE>
+<H3><A NAME="3_3_3">Install the RPMs</A></H3>
+<P>Become root:</P>
+<PRE> su</PRE>
+<P>Install your RPMs with:</P>
+<P></P>
+<PRE> rpm -ivh freeswan*.rpm</PRE>
+<P>If you're upgrading from FreeS/WAN 1.x RPMs, and have problems with
+ that command, see<A HREF="upgrading.html#upgrading.rpms"> this note</A>
+.</P>
+<P>Then, start FreeS/WAN:</P>
+<PRE> service ipsec start</PRE>
+<H3><A name="testinstall">Test</A></H3>
+<P>To check that you have a successful install, run:</P>
+<PRE> ipsec verify</PRE>
+<P>You should see as part of the<VAR> verify</VAR> output:</P>
+<PRE>
+ Checking your system to see if IPsec got installed and started correctly
+ Version check and ipsec on-path [OK]
+ Checking for KLIPS support in kernel [OK]
+ Checking for RSA private key (/etc/ipsec.secrets) [OK]
+ Checking that pluto is running [OK]
+ ...</PRE>
+<P>If any of these first four checks fails, see our<A href="trouble.html#install.check">
+ troubleshooting guide</A>.</P>
+<H2><A name="opp.setups.list">Our Opportunistic Setups</A></H2>
+<H3><A NAME="3_4_1">Full or partial opportunism?</A></H3>
+<P>Determine the best form of opportunism your system can support.</P>
+<UL>
+<LI>For<A HREF="#opp.incoming"> full opportunism</A>, you'll need a
+ static IP and and either control over your reverse DNS or an ISP that
+ can add the required TXT record for you.</LI>
+<LI>If you have a dynamic IP, and/or write access to forward DNS only,
+ you can do<A HREF="#opp.client"> initiate-only opportunism</A></LI>
+<LI>To protect traffic bound for real IPs behind your gateway, use<A HREF="adv_config.html#opp.gate">
+ this form of full opportunism</A>.</LI>
+</UL>
+<H2><A name="opp.client">Initiate-only setup</A></H2>
+<H3><A NAME="3_5_1">Restrictions</A></H3>
+<P>When you set up initiate-only Opportunistic Encryption (iOE):</P>
+<UL>
+<LI>there will be<STRONG> no incoming connection requests</STRONG>; you
+ can initiate all the IPsec connections you need.</LI>
+<LI><STRONG>only one machine is visible</STRONG> on your end of the
+ connection.</LI>
+<LI>iOE also protects traffic on behalf of<A HREF="glossary.html#NAT.gloss">
+ NATted</A> hosts behind the iOE box.</LI>
+</UL>
+<P>You cannot network a group of initiator-only machines if none of
+ these is capable of responding to OE. If one is capable of responding,
+ you may be able to create a hub topology using routing.</P>
+<H3><A name="forward.dns">Create and publish a forward DNS record</A></H3>
+<H4>Find a domain you can use</H4>
+<P>Find a DNS forward domain (e.g. example.com) where you can publish
+ your key. You'll need access to the DNS zone files for that domain.
+ This is common for a domain you own. Some free DNS providers, such as<A HREF="http://www.fdns.net">
+ this one</A>, also provide this service.</P>
+<P>Dynamic IP users take note: the domain where you place your key need
+ not be associated with the IP address for your system, or even with
+ your system's usual hostname.</P>
+<H4>Choose your ID</H4>
+<P>Choose a name within that domain which you will use to identify your
+ machine. It's convenient if this can be the same as your hostname:</P>
+<PRE> [root@xy root]# hostname --fqdn
+ xy.example.com</PRE>
+<P>This name in FQDN (fully-qualified domain name) format will be your
+ ID, for DNS key lookup and IPsec negotiation.</P>
+<H4>Create a forward TXT record</H4>
+<P>Generate a forward TXT record containing your system's public key
+ with a command like:</P>
+<PRE> ipsec showhostkey --txt @xy.example.com</PRE>
+<P>using your chosen ID in place of xy.example.com. This command takes
+ the contents of /etc/ipsec.secrets and reformats it into something
+ usable by ISC's BIND. The result should look like this (with the key
+ data trimmed down for clarity):</P>
+<PRE>
+ ; RSA 2192 bits xy.example.com Thu Jan 2 12:41:44 2003
+ IN TXT &quot;X-IPsec-Server(10)=@xy.example.com&quot;
+ &quot;AQOF8tZ2... ...+buFuFn/&quot;
+</PRE>
+<H4>Publish the forward TXT record</H4>
+<P>Insert the record into DNS, or have a system adminstrator do it for
+ you. It may take up to 48 hours for the record to propagate, but it's
+ usually much quicker.</P>
+<H3><A NAME="3_5_3">Test that your key has been published</A></H3>
+<P>Check your DNS work</P>
+<PRE> ipsec verify --host xy.example.com</PRE>
+<P>As part of the<VAR> verify</VAR> output, you ought to see something
+ like:</P>
+<PRE> ...
+ Looking for TXT in forward map: xy.example.com [OK]
+ ...</PRE>
+<P>For this type of opportunism, only the forward test is relevant; you
+ can ignore the tests designed to find reverse records.</P>
+<H3><A NAME="3_5_4">Configure, if necessary</A></H3>
+<P> If your ID is the same as your hostname, you're ready to go.
+ FreeS/WAN will use its<A HREF="policygroups.html"> built-in connections</A>
+ to create your iOE functionality.</P>
+<P>If you have chosen a different ID, you must tell FreeS/WAN about it
+ via<A HREF="manpage.d/ipsec.conf.5.html"><VAR> ipsec.conf</VAR></A>:</P>
+<PRE> config setup
+ myid=@myname.freedns.example.com</PRE>
+<P>and restart FreeS/WAN:</P>
+<PRE> service ipsec restart</PRE>
+<P>The new ID will be applied to the built-in connections.</P>
+<P>Note: you can create more complex iOE configurations as explained in
+ our<A HREF="policygroups.html#policygroups"> policy groups document</A>
+, or disable OE using<A HREF="policygroups.html#disable_policygroups">
+ these instructions</A>.</P>
+<H3><A NAME="3_5_5">Test</A></H3>
+<P>That's it!<A HREF="#opp.test"> Test your connections</A>.</P>
+<A name="opp.incoming"></A>
+<H2><A NAME="3_6">Full Opportunism</A></H2>
+<P>Full opportunism allows you to initiate and receive opportunistic
+ connections on your machine.</P>
+<A name="incoming.opp.dns"></A>
+<H3><A NAME="3_6_1">Put a TXT record in a Forward Domain</A></H3>
+<P>To set up full opportunism, first<A HREF="#forward.dns"> set up a
+ forward TXT record</A> as for<A HREF="#opp.client"> initiator-only OE</A>
+, using an ID (for example, your hostname) that resolves to your IP. Do
+ not configure<VAR> /etc/ipsec.conf</VAR>, but continue with the
+ instructions for full opportunism, below.</P>
+<P>Note that this forward record is not currently necessary for full OE,
+ but will facilitate future features.</P>
+<A name="incoming.opp.dns"></A>
+<H3><A NAME="3_6_2">Put a TXT record in Reverse DNS</A></H3>
+<P>You must be able to publish your DNS RR directly in the reverse
+ domain. FreeS/WAN will not follow a PTR which appears in the reverse,
+ since a second lookup at connection start time is too costly.</P>
+<H4>Create a Reverse DNS TXT record</H4>
+<P>This record serves to publicize your FreeS/WAN public key. In
+ addition, it lets others know that this machine can receive
+ opportunistic connections, and asserts that the machine is authorized
+ to encrypt on its own behalf.</P>
+<P>Use the command:</P>
+<PRE> ipsec showhostkey --txt 192.0.2.11</PRE>
+<P>where you replace 192.0.2.11 with your public IP.</P>
+<P>The record (with key shortened) looks like:</P>
+<PRE> ; RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+<H4>Publish your TXT record</H4>
+<P>Send these records to your ISP, to be published in your IP's reverse
+ map. It may take up to 48 hours for these to propagate, but usually
+ takes much less time.</P>
+<H3><A NAME="3_6_3">Test your DNS record</A></H3>
+<P>Check your DNS work with</P>
+<PRE> ipsec verify --host xy.example.com</PRE>
+<P>As part of the<VAR> verify</VAR> output, you ought to see something
+ like:</P>
+<PRE> ...
+ Looking for TXT in reverse map: 11.2.0.192.in-addr.arpa [OK]
+ ...</PRE>
+<P>which indicates that you've passed the reverse-map test.</P>
+<H3><A NAME="3_6_4">No Configuration Needed</A></H3>
+<P>FreeS/WAN 2.x ships with full OE enabled, so you don't need to
+ configure anything. To enable OE out of the box, FreeS/WAN 2.x uses the
+ policy group<VAR> private-or-clear</VAR>, which creates IPsec
+ connections if possible (using OE if needed), and allows traffic in the
+ clear otherwise. You can create more complex OE configurations as
+ described in our<A HREF="policygroups.html#policygroups"> policy groups
+ document</A>, or disable OE using<A HREF="policygroups.html#disable_policygroups">
+ these instructions</A>.</P>
+<P>If you've previously configured for initiator-only opportunism,
+ remove<VAR> myid=</VAR> from<VAR> config setup</VAR>, so that peer
+ FreeS/WANs will look up your key by IP. Restart FreeS/WAN so that your
+ change will take effect, with</P>
+<PRE> service ipsec restart</PRE>
+<H3><A NAME="3_6_5">Consider Firewalling</A></H3>
+<P>If you are running a default install of RedHat 8.x, take note: you
+ will need to alter your iptables rule setup to allow IPSec traffic
+ through your firewall. See<A HREF="firewall.html#simple.rules"> our
+ firewall document</A> for sample<VAR> iptables</VAR> rules.</P>
+<H3><A NAME="3_6_6">Test</A></H3>
+<P>That's it. Now,<A HREF="#opp.test"> test your connection</A>.</P>
+<H3><A NAME="3_6_7">Test</A></H3>
+<P>Instructions are in the next section.</P>
+<H2><A NAME="opp.test">Testing opportunistic connections</A></H2>
+<P>Be sure IPsec is running. You can see whether it is with:</P>
+<PRE> ipsec setup status</PRE>
+<P>If need be, you can restart it with:</P>
+<PRE> service ipsec restart</PRE>
+<P>Load a FreeS/WAN test website from the host on which you're running
+ FreeS/WAN. Note: the feds may be watching these sites. Type one of:</P>
+<P></P>
+<PRE> links oetest.freeswan.org</PRE>
+<PRE> links oetest.freeswan.nl</PRE>
+
+<!--<PRE> links oetest.freeswan.ca</PRE>-->
+<P>A positive result looks like this:</P>
+<PRE>
+ You seem to be connecting from: 192.0.2.11 which DNS says is:
+ gateway.example.com
+ _________________________________________________________________
+
+ Status E-route
+ OE enabled 16 192.139.46.73/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x2097@192.0.2.11
+ OE enabled 176 192.139.46.77/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x208a@192.0.2.11
+</PRE>
+<P>If you see this, congratulations! Your OE host or gateway will now
+ encrypt its own traffic whenever it can. For more OE tests, please see
+ our<A HREF="testing.html#test.oe"> testing document</A>. If you have
+ difficulty, see our<A HREF="#oe.trouble"> OE troubleshooting tips</A>.</P>
+<H2><A NAME="3_8">Now what?</A></H2>
+<P>Please see our<A HREF="policygroups.html"> policy groups document</A>
+ for more ways to set up Opportunistic Encryption.</P>
+<P>You may also wish to make some<A HREF="config.html"> pre-configured
+ connections</A>.</P>
+<H2><A NAME="3_9">Notes</A></H2>
+<UL>
+<LI>We assume some facts about your system in order to make
+ Opportunistic Encryption easier to configure. For example, we assume
+ that you wish to have FreeS/WAN secure your default interface.</LI>
+<LI>You may change this, and other settings, by altering the<VAR> config
+ setup</VAR> section in<VAR> /etc/ipsec.conf</VAR>.</LI>
+<LI>Note that the built-in connections used to build policy groups do
+ not inherit from<VAR> conn default</VAR>.</LI>
+
+<!--
+<LI>If you do not define your local identity
+(eg. <VAR>leftid</VAR>), this will be the IP address of your default
+FreeS/WAN interface.
+-->
+<LI> If you fail to define your local identity and do not fill in your
+ reverse DNS entry, you will not be able to use OE.</LI>
+</UL>
+<A NAME="oe.trouble"></A>
+<H2><A NAME="3_10">Troubleshooting OE</A></H2>
+<P>See the OE troubleshooting hints in our<A HREF="trouble.html#oe.trouble">
+ troubleshooting guide</A>.</P>
+<A NAME="oe.known-issues"></A>
+<H2><A NAME="3_11">Known Issues</A></H2>
+<P>Please see<A HREF="opportunism.known-issues"> this list</A> of known
+ issues with Opportunistic Encryption.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="upgrading.html">Previous</A>
+<A HREF="policygroups.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/rfc.html b/doc/rfc.html
new file mode 100644
index 000000000..29785d8de
--- /dev/null
+++ b/doc/rfc.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="biblio.html">Previous</A>
+<A HREF="roadmap.html">Next</A>
+<HR>
+<H1><A name="RFC">IPsec RFCs and related documents</A></H1>
+<H2><A name="RFCfile">The RFCs.tar.gz Distribution File</A></H2>
+<P>The Linux FreeS/WAN distribution is available from<A href="http://www.xs4all.nl/~freeswan">
+ our primary distribution site</A> and various mirror sites. To give
+ people more control over their downloads, the RFCs that define IP
+ security are bundled separately in the file RFCs.tar.gz.</P>
+<P>The file you are reading is included in the main distribution and is
+ available on the web site. It describes the RFCs included in the<A href="#RFCs.tar.gz">
+ RFCs.tar.gz</A> bundle and gives some pointers to<A href="#sources">
+ other ways to get them</A>.</P>
+<H2><A name="sources">Other sources for RFCs &amp; Internet drafts</A></H2>
+<H3><A name="RFCdown">RFCs</A></H3>
+<P>RFCs are downloadble at many places around the net such as:</P>
+<UL>
+<LI><A href="http://www.rfc-editor.org">http://www.rfc-editor.org</A></LI>
+<LI><A href="http://nis.nsf.net/internet/documents/rfc">NSF.net</A></LI>
+<LI><A href="http://sunsite.doc.ic.ac.uk/computing/internet/rfc">Sunsite
+ in the UK</A></LI>
+</UL>
+<P>browsable in HTML form at others such as:</P>
+<UL>
+<LI><A href="http://www.landfield.com/rfcs/index.html">landfield.com</A></LI>
+<LI><A href="http://www.library.ucg.ie/Connected/RFC">Connected Internet
+ Encyclopedia</A></LI>
+</UL>
+<P>and some of them are available in translation:</P>
+<UL>
+<LI><A href="http://www.eisti.fr/eistiweb/docs/normes/">French</A></LI>
+</UL>
+<P>There is also a published<A href="biblio.html#RFCs"> Big Book of
+ IPSEC RFCs</A>.</P>
+<H3><A name="drafts">Internet Drafts</A></H3>
+<P>Internet Drafts, working documents which sometimes evolve into RFCs,
+ are also available.</P>
+<UL>
+<LI><A href="http://www.ietf.org/ID.html">Overall reference page</A></LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/ipsec.html">IPsec</A> working
+ group</LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/ipsra.html">IPSRA (IPsec
+ Remote Access)</A> working group</LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/ipsp.html">IPsec Policy</A>
+ working group</LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/kink.html">KINK (Kerberized
+ Internet Negotiation of Keys)</A> working group</LI>
+</UL>
+<P>Note: some of these may be obsolete, replaced by later drafts or by
+ RFCs.</P>
+<H3><A name="FIPS1">FIPS standards</A></H3>
+<P>Some things used by<A href="glossary.html#IPSEC"> IPsec</A>, such as<A
+href="glossary.html#DES"> DES</A> and<A href="glossary.html#SHA"> SHA</A>
+, are defined by US government standards called<A href="glossary.html#FIPS">
+ FIPS</A>. The issuing organisation,<A href="glossary.html#NIST"> NIST</A>
+, have a<A href="http://www.itl.nist.gov/div897/pubs"> FIPS home page</A>
+.</P>
+<H2><A name="RFCs.tar.gz">What's in the RFCs.tar.gz bundle?</A></H2>
+<P>All filenames are of the form rfc*.txt, with the * replaced with the
+ RFC number.</P>
+<PRE>RFC# Title</PRE>
+<H3><A name="rfc.ov">Overview RFCs</A></H3>
+<PRE>2401 Security Architecture for the Internet Protocol
+2411 IP Security Document Roadmap</PRE>
+<H3><A name="basic.prot">Basic protocols</A></H3>
+<PRE>2402 IP Authentication Header
+2406 IP Encapsulating Security Payload (ESP)</PRE>
+<H3><A name="key.ike">Key management</A></H3>
+<PRE>2367 PF_KEY Key Management API, Version 2
+2407 The Internet IP Security Domain of Interpretation for ISAKMP
+2408 Internet Security Association and Key Management Protocol (ISAKMP)
+2409 The Internet Key Exchange (IKE)
+2412 The OAKLEY Key Determination Protocol
+2528 Internet X.509 Public Key Infrastructure</PRE>
+<H3><A name="rfc.detail">Details of various things used</A></H3>
+<PRE>2085 HMAC-MD5 IP Authentication with Replay Prevention
+2104 HMAC: Keyed-Hashing for Message Authentication
+2202 Test Cases for HMAC-MD5 and HMAC-SHA-1
+2207 RSVP Extensions for IPSEC Data Flows
+2403 The Use of HMAC-MD5-96 within ESP and AH
+2404 The Use of HMAC-SHA-1-96 within ESP and AH
+2405 The ESP DES-CBC Cipher Algorithm With Explicit IV
+2410 The NULL Encryption Algorithm and Its Use With IPsec
+2451 The ESP CBC-Mode Cipher Algorithms
+2521 ICMP Security Failures Messages</PRE>
+<H3><A name="rfc.ref">Older RFCs which may be referenced</A></H3>
+<PRE>1321 The MD5 Message-Digest Algorithm
+1828 IP Authentication using Keyed MD5
+1829 The ESP DES-CBC Transform
+1851 The ESP Triple DES Transform
+1852 IP Authentication using Keyed SHA</PRE>
+<H3><A name="rfc.dns">RFCs for secure DNS service, which IPsec may use</A>
+</H3>
+<PRE>2137 Secure Domain Name System Dynamic Update
+2230 Key Exchange Delegation Record for the DNS
+2535 Domain Name System Security Extensions
+2536 DSA KEYs and SIGs in the Domain Name System (DNS)
+2537 RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)
+2538 Storing Certificates in the Domain Name System (DNS)
+2539 Storage of Diffie-Hellman Keys in the Domain Name System (DNS)</PRE>
+<H3><A name="rfc.exp">RFCs labelled &quot;experimental&quot;</A></H3>
+<PRE>2521 ICMP Security Failures Messages
+2522 Photuris: Session-Key Management Protocol
+2523 Photuris: Extended Schemes and Attributes</PRE>
+<H3><A name="rfc.rel">Related RFCs</A></H3>
+<PRE>1750 Randomness Recommendations for Security
+1918 Address Allocation for Private Internets
+1984 IAB and IESG Statement on Cryptographic Technology and the Internet
+2144 The CAST-128 Encryption Algorithm</PRE>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="biblio.html">Previous</A>
+<A HREF="roadmap.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/roadmap.html b/doc/roadmap.html
new file mode 100644
index 000000000..ce547582c
--- /dev/null
+++ b/doc/roadmap.html
@@ -0,0 +1,167 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="rfc.html">Previous</A>
+<A HREF="umltesting.html">Next</A>
+<HR>
+<H1><A name="roadmap">Distribution Roadmap: What's Where in Linux
+ FreeS/WAN</A></H1>
+<P> This file is a guide to the locations of files within the FreeS/WAN
+ distribution. Everything described here should be on your system once
+ you download, gunzip, and untar the distribution.</P>
+<P>This distribution contains two major subsystems</P>
+<DL>
+<DT><A href="#klips.roadmap">KLIPS</A></DT>
+<DD>the kernel code</DD>
+<DT><A href="#pluto.roadmap">Pluto</A></DT>
+<DD>the user-level key-management daemon</DD>
+</DL>
+<P>plus assorted odds and ends.</P>
+<H2><A name="top">Top directory</A></H2>
+<P>The top directory has essential information in text files:</P>
+<DL>
+<DT>README</DT>
+<DD>introduction to the software</DD>
+<DT>INSTALL</DT>
+<DD>short experts-only installation procedures. More detalied procedures
+ are in<A href="install.html"> installation</A> and<A href="config.html">
+ configuration</A> HTML documents.</DD>
+<DT>BUGS</DT>
+<DD>major known bugs in the current release.</DD>
+<DT>CHANGES</DT>
+<DD>changes from previous releases</DD>
+<DT>CREDITS</DT>
+<DD>acknowledgement of contributors</DD>
+<DT>COPYING</DT>
+<DD>licensing and distribution information</DD>
+</DL>
+<H2><A name="doc">Documentation</A></H2>
+<P> The doc directory contains the bulk of the documentation, most of it
+ in HTML format. See the<A href="index.html"> index file</A> for
+ details.</P>
+<H2><A name="klips.roadmap">KLIPS: kernel IP security</A></H2>
+<P><A href="glossary.html#KLIPS"> KLIPS</A> is<STRONG> K</STRONG>erne<STRONG>
+L</STRONG><STRONG> IP</STRONG><STRONG> S</STRONG>ecurity. It lives in
+ the klips directory, of course.</P>
+<DL>
+<DT>klips/doc</DT>
+<DD>documentation</DD>
+<DT>klips/patches</DT>
+<DD>patches for existing kernel files</DD>
+<DT>klips/test</DT>
+<DD>test stuff</DD>
+<DT>klips/utils</DT>
+<DD>low-level user utilities</DD>
+<DT>klips/net/ipsec</DT>
+<DD>actual klips kernel files</DD>
+<DT>klips/src</DT>
+<DD>symbolic link to klips/net/ipsec
+<P>The &quot;make insert&quot; step of installation installs the patches and makes
+ a symbolic link from the kernel tree to klips/net/ipsec. The odd name
+ of klips/net/ipsec is dictated by some annoying limitations of the
+ scripts which build the Linux kernel. The symbolic-link business is a
+ bit messy, but all the alternatives are worse.</P>
+<P></P>
+</DD>
+<DT>klips/utils</DT>
+<DD>Utility programs:
+<P></P>
+<DL>
+<DT>eroute</DT>
+<DD>manipulate IPsec extended routing tables</DD>
+<DT>klipsdebug</DT>
+<DD>set Klips (kernel IPsec support) debug features and level</DD>
+<DT>spi</DT>
+<DD>manage IPsec Security Associations</DD>
+<DT>spigrp</DT>
+<DD>group/ungroup IPsec Security Associations</DD>
+<DT>tncfg</DT>
+<DD>associate IPsec virtual interface with real interface</DD>
+</DL>
+<P>These are all normally invoked by ipsec(8) with commands such as</P>
+<PRE> ipsec tncfg <VAR>arguments</VAR></PRE>
+ There are section 8 man pages for all of these; the names have &quot;ipsec_&quot;
+ as a prefix, so your man command should be something like:
+<PRE> man 8 ipsec_tncfg</PRE>
+</DD>
+</DL>
+<H2><A name="pluto.roadmap">Pluto key and connection management daemon</A>
+</H2>
+<P><A href="glossary.html#Pluto"> Pluto</A> is our key management and
+ negotiation daemon. It lives in the pluto directory, along with its
+ low-level user utility, whack.</P>
+<P> There are no subdirectories. Documentation is a man page,<A href="manpage.d/ipsec_pluto.8.html">
+ pluto.8</A>. This covers whack as well.</P>
+<H2><A name="utils">Utils</A></H2>
+<P> The utils directory contains a growing collection of higher-level
+ user utilities, the commands that administer and control the software.
+ Most of the things that you will actually have to run yourself are in
+ there.</P>
+<DL>
+<DT>ipsec</DT>
+<DD>invoke IPsec utilities
+<P>ipsec(8) is normally the only program installed in a standard
+ directory, /usr/local/sbin. It is used to invoke the others, both those
+ listed below and the ones in klips/utils mentioned above.</P>
+<P></P>
+</DD>
+<DT>auto</DT>
+<DD>control automatically-keyed IPsec connections</DD>
+<DT>manual</DT>
+<DD>take manually-keyed IPsec connections up and down</DD>
+<DT>barf</DT>
+<DD>generate copious debugging output</DD>
+<DT>look</DT>
+<DD>generate moderate amounts of debugging output</DD>
+</DL>
+<P> There are .8 manual pages for these. look is covered in barf.8. The
+ man pages have an &quot;ipsec_&quot; prefix so your man command should be
+ something like:</P>
+<PRE>
+ man 8 ipsec_auto
+</PRE>
+<P> Examples are in various files with names utils/*.eg</P>
+<H2><A name="lib">Libraries</A></H2>
+<H3><A name="fswanlib">FreeS/WAN Library</A></H3>
+<P> The lib directory is the FreeS/WAN library, also steadily growing,
+ used by both user-level and kernel code.
+<BR /> It includes section 3<A href="manpages.html"> man pages</A> for
+ the library routines.</P>
+<H3><A name="otherlib">Imported Libraries</A></H3>
+<H4>LibDES</H4>
+ The libdes library, originally from SSLeay, is used by both Klips and
+ Pluto for<A href="glossary.html#3DES"> Triple DES</A> encryption.
+ Single DES is not used because<A href="politics.html#desnotsecure"> it
+ is insecure</A>.
+<P> Note that this library has its own license, different from the<A href="glossary.html#GPL">
+ GPL</A> used for other code in FreeS/WAN.</P>
+<P> The library includes its own documentation.</P>
+<H4>GMP</H4>
+ The GMP (GNU multi-precision) library is used for multi-precision
+ arithmetic in Pluto's key-exchange code and public key code.
+<P> Older versions (up to 1.7) of FreeS/WAN included a copy of this
+ library in the FreeS/WAN distribution.</P>
+<P> Since 1.8, we have begun to rely on the system copy of GMP.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="rfc.html">Previous</A>
+<A HREF="umltesting.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/src/.cvsignore b/doc/src/.cvsignore
new file mode 100644
index 000000000..3ed29bc59
--- /dev/null
+++ b/doc/src/.cvsignore
@@ -0,0 +1,3 @@
+foo.xml
+foobar.html
+makecheck-2.html
diff --git a/doc/src/adv_config.html b/doc/src/adv_config.html
new file mode 100644
index 000000000..ab6901b5e
--- /dev/null
+++ b/doc/src/adv_config.html
@@ -0,0 +1,1412 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>Advanced FreeS/WAN configuration</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, configuration">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Maintained by Claudia Schmeing for same.
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: adv_config.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="adv_config">Other configuration possibilities</a></h1>
+
+<p>This document describes various options for FreeS/WAN configuration which
+are less used or more complex (often both) than the standard cases described
+in our <a href="config.html#config">config</a> and
+<a href="quickstart.html#quick_guide">quickstart</a> documents.</p>
+
+<h2><a name="thumb">Some rules of thumb about configuration</a></h2>
+
+<h3><a name="cheap.tunnel">Tunnels are cheap</a></h3>
+
+<p>Nearly all of the overhead in IPsec processing is in the encryption and
+authentication of packets. Our <a href="performance.html">performance</a>
+document discusses these overheads.</p>
+
+<p>Beside those overheads, the cost of managing additional tunnels is
+trivial. Whether your gateway supports one tunnel or ten just does not
+matter. A hundred might be a problem; there is a <a
+href="performance.html#biggate">section</a> on this in the performance
+document.</p>
+
+<p>So, in nearly all cases, if using multiple tunnels gives you a reasonable
+way to describe what you need to do, you should describe it that way in your
+configuration files.</p>
+
+<p>For example, one user recently asked on a mailing list about this network
+configuration:</p>
+<pre> netA---gwA---gwB---netB
+ |----netC
+
+ netA and B are secured netC not.
+ netA and gwA can not access netC</pre>
+
+<p>The user had constructed only one tunnel, netA to netB, and wanted to know
+how to use ip-route to get netC packets into it. This is entirely
+unnecessary. One of the replies was:</p>
+<pre> The simplest way and indeed the right way to
+ solve this problem is to set up two connections:
+
+ leftsubnet=NetA
+ left=gwA
+ right=gwB
+ rightsubnet=NetB
+ and
+ leftsubnet=NetA
+ left=gwA
+ right=gwB
+ rightsubnet=NetC</pre>
+
+<p>This would still be correct even if we added nets D, E, F,
+... to the above diagram and needed twenty tunnels.</p>
+
+<p>Of course another possibility would be to just use one tunnel, with a
+subnet mask that includes both netB and netC (or B, C, D, ...). See next
+section.</p>
+
+<p>In general, you can construct as many tunnels as you need. Networks like
+netC in this example that do not connect directly to the gateway are fine, as
+long as the gateway can route to them.</p>
+
+<p>The number of tunnels can become an issue if it reaches 50 or so. This is
+discussed in the <a href="performance.html#biggate">performance</a> document.
+Look there for information on supporting hundreds of Road Warriors from one
+gateway.</p>
+
+<p>If you find yourself with too many tunnels for some reason like having
+eight subnets at one location and nine at another so you end up with
+9*8=72 tunnels, read the next section here.</p>
+
+<h3><a name="subnet.size">Subnet sizes</a></h3>
+
+<p>The subnets used in <var>leftsubnet</var> and <var>rightsubnet</var> can
+be of any size that fits your needs, and they need not correspond to physical
+networks.</p>
+
+<p>You adjust the size by changing the <a href="glossary.html#subnet">subnet
+mask</a>, the number after the slash in the subnet description. For
+example</p>
+<ul>
+ <li>in 192.168.100.0/24 the /24 mask says 24 bits are used to designate the
+ network. This leave 8 bits to label machines. This subnet has 256
+ addresses. .0 and .255 are reserved, so it can have 254 machines.</li>
+ <li>A subnet with a /23 mask would be twice as large, 512 addresses.</li>
+ <li>A subnet with a /25 mask would be half the size, 128 addresses.</li>
+ <li>/0 is the whole Internet</li>
+ <li>/32 is a single machine</li>
+</ul>
+
+<p>As an example of using these in connection descriptions, suppose your
+company's head office has four physical networks using the address ranges:</p>
+<dl>
+ <dt>192.168.100.0/24</dt>
+ <dd>development</dd>
+ <dt>192.168.101.0/24</dt>
+ <dd>production</dd>
+ <dt>192.168.102.0/24</dt>
+ <dd>marketing</dd>
+ <dt>192.168.103.0/24</dt>
+ <dd>administration</dd>
+</dl>
+
+<p>You can use exactly those subnets in your connection descriptions, or use
+larger subnets to grant broad access if required:</p>
+<dl>
+ <dt>leftsubnet=192.168.100.0/24</dt>
+ <dd>remote hosts can access only development</dd>
+ <dt>leftsubnet=192.168.100.0/23</dt>
+ <dd>remote hosts can access development or production</dd>
+ <dt>leftsubnet=192.168.102.0/23</dt>
+ <dd>remote hosts can access marketing or administration</dd>
+ <dt>leftsubnet=192.168.100.0/22</dt>
+ <dd>remote hosts can access any of the four departments</dd>
+</dl>
+
+<p>or use smaller subnets to restrict access:</p>
+<dl>
+ <dt>leftsubnet=192.168.103.0/24</dt>
+ <dd>remote hosts can access any machine in administration</dd>
+ <dt>leftsubnet=192.168.103.64/28</dt>
+ <dd>remote hosts can access only certain machines in administration.</dd>
+ <dt>leftsubnet=192.168.103.42/32</dt>
+ <dd>remote hosts can access only one particular machine in
+ administration</dd>
+</dl>
+
+<p>To be exact, 192.68.103.64/28 means all addresses whose top 28 bits match
+192.168.103.64. There are 16 of these because there are 16 possibilities for
+the remainingg 4 bits. Their addresses are 192.168.103.64 to
+192.168.103.79.</p>
+
+<p>Each connection description can use a different subnet if required.</p>
+
+<p>It is possible to use all the examples above on the same FreeS/WAN
+gateway, each in a different connection description, perhaps for different
+classes of user or for different remote offices.</p>
+
+<p>It is also possible to have multiple tunnels using different
+<var>leftsubnet</var> descriptions with the same <var>right</var>. For
+example, when the marketing manager is on the road he or she might have
+access to:</p>
+<dl>
+ <dt>leftsubnet=192.168.102.0/24</dt>
+ <dd>all machines in marketing</dd>
+ <dt>192.168.101.32/29</dt>
+ <dd>some machines in production</dd>
+ <dt>leftsubnet=192.168.103.42/32</dt>
+ <dd>one particular machine in administration</dd>
+</dl>
+
+<p>This takes three tunnels, but tunnels are cheap. If the laptop is set up
+to build all three tunnels automatically, then he or she can access all these
+machines concurrently, perhaps from different windows.</p>
+
+<h3><a name="example.more">Other network layouts</a></h3>
+
+<p>Here is the usual network picture for a site-to-site VPN::</p>
+<pre> Sunset==========West------------------East=========Sunrise
+ local net untrusted net local net</pre>
+
+<p>and for the Road Warrior::</p>
+<pre> telecommuter's PC or
+ traveller's laptop
+ Sunset==========West------------------East
+ corporate LAN untrusted net</pre>
+
+<p>Other configurations are also possible.</p>
+
+<h4><a name="internet.subnet">The Internet as a big subnet</a></h4>
+
+<p>A telecommuter might have:</p>
+<pre> Sunset==========West------------------East ================= firewall --- the Internet
+ home network untrusted net corporate network</pre>
+
+<p>This can be described as a special case of the general subnet-to-subnet
+connection. The subnet on the right is 0.0.0.0/0, the whole Internet.</p>
+
+<p>West (the home gateway) can have its firewall rules set up so that only
+IPsec packets to East are allowed out. It will then behave as if its only
+connection to the world was a wire to East.</p>
+
+<p>When machines on the home network need to reach the Internet, they do so
+via the tunnel, East and the corporate firewall. From the viewpoint of the
+Internet (perhaps of some EvilDoer trying to break in!), those home office
+machines are behind the firewall and protected by it.</p>
+
+<h4><a name="wireless.config">Wireless</a></h4>
+
+<p>Another possible configuration comes up when you do not trust the local
+network, either because you have very high security standards or because your
+are using easily-intercepted wireless signals.</p>
+
+<p>Some wireless networks have built-in encryption called <a
+href="glossary.html#WEP">WEP</a>, but its security is dubious. It is a fairly
+common practice to use IPsec instead.</p>
+
+<p>In this case, part of your network may look like this:</p>
+<pre> West-----------------------------East == the rest of your network
+ workstation untrusted wireless net</pre>
+
+<p>Of course, there would likely be several wireless workstations, each with
+its own IPsec tunnel to the East gateway.</p>
+
+<p>The connection descriptions look much like Road Warrior descriptions:</p>
+<ul>
+ <li>each workstation should have its own unique
+ <ul>
+ <li>identifier for IPsec</li>
+ <li>RSA key</li>
+ <li>connection description.</li>
+ </ul>
+ </li>
+ <li>on the gateway, use <var>left=%any</var>, or the workstation IP
+ address</li>
+ <li>on workstations, <var>left=%defaultroute</var>, or the workstation IP
+ address</li>
+ <li><var>leftsubnet=</var> is not used.</li>
+</ul>
+
+<p>The <var>rightsubnet=</var> parameter might be set in any of several
+ways:</p>
+<dl>
+ <dt>rightsubnet=0.0.0.0/0</dt>
+ <dd>allowing workstations to access the entire Internet (see <a
+ href="#internet.subnet">above</a>)</dd>
+ <dt>rightsubnet=a.b.c.0/24</dt>
+ <dd>allowing access to your entire local network</dd>
+ <dt>rightsubnet=a.b.c.d/32</dt>
+ <dd>restricting the workstation to connecting to a particular server</dd>
+</dl>
+
+<p>Of course you can mix and match these as required. For example, a
+university might allow faculty full Internet access while letting student
+laptops connect only to a group of lab machines.</p>
+
+<h2><a name="choose">Choosing connection types</a></h2>
+
+<p>One choice you need to make before configuring additional connections is
+what type or types of connections you will use. There are several options,
+and you can use more than one concurrently.</p>
+
+<h3><a name="man-auto">Manual vs. automatic keying</a></h3>
+
+<p>IPsec allows two types of connections, with manual or automatic keying.
+FreeS/WAN starts them with commands such as:</p>
+<pre> ipsec manual --up <var>name</var>
+ ipsec auto --up <var>name</var></pre>
+
+<p>The difference is in how they are keyed.</p>
+<dl>
+ <dt><a href="glossary.html#manual">Manually keyed</a> connections</dt>
+ <dd>use keys stored in <a
+ href="manpage.d/ipsec.conf.5.html">ipsec.conf</a>.</dd>
+ <dt><a href="glossary.html#auto">Automatically keyed</a> connections</dt>
+ <dd>use keys automatically generated by the Pluto key negotiation daemon.
+ The key negotiation protocol, <a href="glossary.html#IKE">IKE</a>, must
+ authenticate the other system. (It is vulnerable to a <a
+ href="glossary.html#middle">man-in-the-middle attack</a> if used
+ without authentication.) We currently support two authentication
+ methods:
+ <ul>
+ <li>using shared secrets stored in <a
+ href="manpage.d/ipsec.secrets.5.html">ipsec.secrets</a>.</li>
+ <li>RSA <a href="glossary.html#public">public key</a> authentication,
+ with our machine's private key in <a
+ href="manpage.d/ipsec.secrets.5.html">ipsec.secrets</a>. Public
+ keys for other machines may either be placed in <a
+ href="manpage.d/ipsec.conf.5.html">ipsec.conf</a> or provided via
+ DNS.</li>
+ </ul>
+ <p>A third method, using RSA keys embedded in <a
+ href="glossary.html#X509">X.509</a> certtificates, is provided by
+ user <a href="web.html#patch">patches</a>.</p>
+ </dd>
+</dl>
+
+<p><a href="glossary.html#manual">Manually keyed</a> connections provide
+weaker security than <a href="glossary.html#auto">automatically keyed</a>
+connections. An opponent who reads ipsec.secrets(5) gets your encryption key
+and can read all data encrypted by it. If he or she has an archive of old
+messages, all of them back to your last key change are also readable.</p>
+
+<p>With automatically-(re)-keyed connections, an opponent who reads
+ipsec.secrets(5) gets the key used to authenticate your system in IKE -- the
+shared secret or your private key, depending what authentication mechanism is
+in use. However, he or she does not automatically gain access to any
+encryption keys or any data.</p>
+
+<p>An attacker who has your authentication key can mount a <a
+href="glossary.html#middle">man-in-the-middle attack</a> and, if that
+succeeds, he or she will get encryption keys and data. This is a serious
+danger, but it is better than having the attacker read everyting as soon as
+he or she breaks into ipsec.secrets(5).. Moreover, the keys change often so
+an opponent who gets one key does not get a large amount of data. To read all
+your data, he or she would have to do a man-in-the-middle attack at every key
+change.</p>
+
+<p>We discuss using <a href="#prodman">manual keying in production</a> below,
+but this is <strong>not recommended</strong> except in special circumstances,
+such as needing to communicate with some implementation that offers no
+auto-keyed mode compatible with FreeS/WAN.</p>
+
+<p>Manual keying may also be useful for testing. There is some discussion of
+this in our <a href="faq.html#man4debug">FAQ</a>.</p>
+
+<h3><a name="auto-auth">Authentication methods for auto-keying</a></h3>
+
+<p>The IKE protocol which Pluto uses to negotiate connections between
+gateways must use some form of authentication of peers. A gateway must know
+who it is talking to before it can create a secure connection. We support two
+basic methods for this authentication:</p>
+<ul>
+ <li>shared secrets, stored in <a
+ href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</a></li>
+ <li>RSA authentication</li>
+</ul>
+
+<p>There are, howver, several variations on the RSA theme, using different
+methods of managing the RSA keys:</p>
+<ul>
+ <li>our RSA private key in <a
+ href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</a> with other
+ gateways' public keys
+ <dl>
+ <dt>either</dt>
+ <dd>stored in <a
+ href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a></dd>
+ <dt>or</dt>
+ <dd>looked up via <a href="glossary.html#DNS">DNS</a></dd>
+ </dl>
+ </li>
+ <li>authentication with <a href="glossary.html#x509">x.509</a>
+ certificates.; See our <a href="web.html#patch">links section</a> for
+ information on user-contributed patches for this.:</li>
+</ul>
+
+<p>Public keys in <a href="manpage.d/ipsec.conf.5.html">ipsec.conf(5</a>)
+give a reasonably straightforward method of specifying keys for explicitly
+configured connections.</p>
+
+<p>Putting public keys in DNS allows us to support <a
+href="glossary.html#carpediem">opportunistic encryption</a>. Any two
+FreeS/WAN gateways can provide secure communication, without either of them
+having any preset information about the other.</p>
+
+<p>X.509 certificates may be required to interface to various <a
+href="glossary.html#PKI">PKI</a>s.</p>
+
+<h3><a name="adv-pk">Advantages of public key methods</a></h3>
+
+<p>Authentication with a <a href="glossary.html#public">public key</a> method
+such as <a href="glossary.html#RSA">RSA</a> has some important advantages
+over using shared secrets.</p>
+<ul>
+ <li>no problem of secure transmission of secrets
+ <ul>
+ <li>A shared secret must be shared, so you have the problem of
+ transmitting it securely to the other party. If you get this wrong,
+ you have no security.</li>
+ <li>With a public key technique, you transmit only your public key. The
+ system is designed to ensure that it does not matter if an enemy
+ obtains public keys. The private key never leaves your machine.</li>
+ </ul>
+ </li>
+ <li>easier management
+ <ul>
+ <li>Suppose you have 20 branch offices all connecting to one gateway at
+ head office, and all using shared secrets. Then the head office admin
+ has 20 secrets to manage. Each of them must be kept secret not only
+ from outsiders, but also from 19 of the branch office admins. The
+ branch office admins have only one secret each to manage.
+ <p>If the branch offices need to talk to each other, this becomes
+ problematic. You need another 20*19/2 = 190 secrets for
+ branch-to-branch communication, each known to exactly two branches.
+ Now all the branch admins have the headache of handling 20 keys, each
+ shared with exactly one other branch or with head office.</p>
+ <p>For larger numbers of branches, the number of connections and
+ secrets increases quadratically and managing them becomes a
+ nightmare. A 1000-gateway fully connected network needs 499,500
+ secrets, each known to exactly two players. There are ways to reduce
+ this problem, for example by introducing a central key server, but
+ these involve additional communication overheads, more administrative
+ work, and new threats that must be carefully guarded against.</p>
+ </li>
+ <li>With public key techniques, the <em>only</em> thing you have to
+ keep secret is your private key, and <em>you keep that secret from
+ everyone</em>.
+ <p>As network size increaes, the number of public keys used increases
+ linearly with the number of nodes. This still requires careful
+ administration in large applications, but is nothing like the
+ disaster of a quadratic increase. On a 1000-gateway network, you have
+ 1000 private keys, each of which must be kept secure on one machine,
+ and 1000 public keys which must be distributed. This is not a trivial
+ problem, but it is manageable.</p>
+ </li>
+ </ul>
+ </li>
+ <li>does not require fixed IP addresses
+ <ul>
+ <li>When shared secrets are used in IPsec, the responder must be able
+ to tell which secret to use by looking at the IP address on the
+ incoming packets. When the other parties do not have a fixed IP
+ address to be identified by (for example, on nearly all dialup ISP
+ connections and many cable or ADSL links), this does not work well --
+ all must share the same secret!</li>
+ <li>When RSA authentication is in use, the initiator can identify
+ itself by name before the key must be determined. The responder then
+ checks that the message is signed with the public key corresponding
+ to that name.</li>
+ </ul>
+ </li>
+</ul>
+
+<p>There is also a disadvantage:</p>
+<ul>
+ <li>your private key is a single point of attack, extremely valuable to an
+ enemy
+ <ul>
+ <li>with shared secrets, an attacker who steals your ipsec.secrets file
+ can impersonate you or try <a
+ href="glossary.html#middle">man-in-the-middle</a> attacks, but can
+ only attack connections described in that file</li>
+ <li>an attacker who steals your private key gains the chance to attack
+ not only existing connections <em>but also any future
+ connections</em> created using that key</li>
+ </ul>
+ </li>
+</ul>
+
+<p>This is partly counterbalanced by the fact that the key is never
+transmitted and remains under your control at all times. It is likely
+necessary, however, to take account of this in setting security policy. For
+example, you should change gateway keys when an administrator leaves the
+company, and should change them periodically in any case.</p>
+
+<p>Overall, public key methods are <strong>more secure, more easily managed
+and more flexible</strong>. We recommend that they be used for all
+connections, unless there is a compelling reason to do otherwise.</p>
+
+<h2><a name="prodsecrets">Using shared secrets in production</a></h2>
+
+<p>Generally, public key methods are preferred for reasons given above, but
+shared secrets can be used with no loss of security, just more work and
+perhaps more need to take precautions.</p>
+
+<p>What I call "shared secrets" are sometimes also called "pre-shared keys".
+They are used only for for authentication, never for encryption. Calling them
+"pre-shared keys" has confused some users into thinking they were encryption
+keys, so I prefer to avoid the term..</p>
+
+<p>If you are interoperating with another IPsec implementation, you may find
+its documentation calling them "passphrases".</p>
+
+<h3><a name="secrets">Putting secrets in ipsec.secrets(5)</a></h3>
+
+<p>If shared secrets are to be used to <a
+href="glossary.html#authentication">authenticate</a> communication for the <a
+href="glossary.html#DH">Diffie-Hellman</a> key exchange in the <a
+href="glossary.html#IKE">IKE</a> protocol, then those secrets must be stored
+in <var>/etc/ipsec.secrets</var>. For details, see the <a
+href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</a> man page.</p>
+
+<p>A few considerations are vital:</p>
+<ul>
+ <li>make the secrets long and unguessable. Since they need not be
+ remembered by humans, very long ugly strings may be used. We suggest
+ using our <a href="manpage.d/ipsec_ranbits.8.html">ipsec_ranbits(8)</a>
+ utility to generate long (128 bits or more) random strings.</li>
+ <li>transmit secrets securely. You have to share them with other systems,
+ but you lose if they are intercepted and used against you. Use <a
+ href="glossary.html#PGP">PGP</a>, <a href="glossary.html#SSH">SSH</a>,
+ hand delivery of a floppy disk which is then destroyed, or some other
+ trustworthy method to deliver them.</li>
+ <li>store secrets securely, in root-owned files with permissions
+ rw------.</li>
+ <li>limit sharing of secrets. Alice, Bob, Carol and Dave may all talk to
+ each other, but only Alice and Bob should know the secret for an
+ Alice-Bob link.</li>
+ <li><strong>do not share private keys</strong>. The private key for RSA
+ authentication of your system is stored in <a
+ href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</a>, but it is a
+ different class of secret from the pre-shared keys used for the "shared
+ secret" authentication. No-one but you should have the RSA private
+ key.</li>
+</ul>
+
+<p>Each line has the IP addresses of the two gateways plus the secret. It
+should look something like this:</p>
+<pre> 10.0.0.1 11.0.0.1 : PSK "jxTR1lnmSjuj33n4W51uW3kTR55luUmSmnlRUuWnkjRj3UuTV4T3USSu23Uk55nWu5TkTUnjT"</pre>
+
+<p><var>PSK</var> indicates the use of a
+<strong>p</strong>re-<strong>s</strong>hared <strong>k</strong>ey. The quotes
+and the whitespace shown are required.</p>
+
+<p>You can use any character string as your secret. For security, it should
+be both long and extremely hard to guess. We provide a utility to generate
+such strings, <a
+href="manpage.d/ipsec_ranbits.8.html">ipsec_ranbits(8)</a>.</p>
+
+<p>You want the same secret on the two gateways used, so you create a line
+with that secret and the two gateway IP addresses. The installation process
+supplies an example secret, useful <em>only</em> for testing. You must change
+it for production use.</p>
+
+<h3><a name="securing.secrets">File security</a></h3>
+
+<p>You must deliver this file, or the relevant part of it, to the other
+gateway machine by some <strong>secure</strong> means. <em>Don't just FTP or
+mail the file!</em> It is vital that the secrets in it remain secret. An
+attacker who knew those could easily have <em>all the data on your "secure"
+connection</em>.</p>
+
+<p>This file must be owned by root and should have permissions
+<var>rw-------</var>.</p>
+
+<h3><a name="notroadshared">Shared secrets for road warriors</a></h3>
+
+<p>You can use a shared secret to support a single road warrior connecting to
+your gateway, and this is a reasonable thing to do in some circumstances.
+Public key methods have advantages, discussed <a href="#choose">above</a>,
+but they are not critical in this case.</p>
+
+<p>To do this, the line in ipsec.secrets(5) is something like:</p>
+<pre> 10.0.0.1 0.0.0.0 : PSK "jxTR1lnmSjuj33n4W51uW3kTR55luUmSmnlRUuWnkjRj3UuTV4T3USSu23Uk55nWu5TkTUnjT"</pre>
+where the <var>0.0.0.0</var> means that any IP address is acceptable.
+
+<p><strong>For more than one road warrior, shared secrets are <em>not</em>
+recommended.</strong> If shared secrets are used, then when the responder
+needs to look up the secret, all it knows about the sender is an IP address.
+This is fine if the sender is at a fixed IP address specified in the config
+file. It is also fine if only one road warrior uses the wildcard
+<var>0.0.0.0</var> address. However, if you have more than one road warrior
+using shared secret authentication, then they must all use that wildcard and
+therefore <strong>all road warriors using PSK autentication must use the same
+secret</strong>. Obviously, this is insecure.</p>
+
+<p><strong>For multiple road warriors, use public key
+authentication.</strong> Each roadwarrior can then have its own identity (our
+<var>leftid=</var> or <var>rightid=</var> parameters), its own public/private
+key pair, and its own secure connection.</p>
+
+<h2><a name="prodman">Using manual keying in production</a></h2>
+
+<p>Generally, <a href="glossary.html#auto">automatic keying</a> is preferred
+over <a href="glossary.html#manual">manual keying</a> for production use
+because it is both easier to manage and more secure. Automatic keying frees
+the admin from much of the burden of managing keys securely, and can provide
+<a href="glossary.html#PFS">perfect forward secrecy</a>. This is discussed in
+more detail <a href="#man-auto">above</a>.</p>
+
+<p>However, it is possible to use manual keying in production if that is what
+you want to do. This might be necessary, for example, in order to
+interoperate with some device that either does not provide automatic keying
+or provides it in some version we cannot talk to.</p>
+
+<p>Note that with manual keying <strong>all security rests with the
+keys</strong>. If an adversary acquires your keys, you've had it. He or she
+can read everything ever sent with those keys, including old messages he or
+she may have archived.</p>
+
+<p>You need to <strong>be really paranoid about keys</strong> if you're going
+to rely on manual keying for anything important.</p>
+<ul>
+ <li>keep keys in files with 600 permissions, owned by root</li>
+ <li>be extremely careful about security of your gateway systems. Anyone who
+ breaks into a gateway and gains root privileges can get all your keys and
+ read everything ever encrypted with those keys, both old messages he has
+ archived and any new ones you may send.</li>
+ <li>change keys regularly. This can be a considerable bother, (and provides
+ an excellent reason to consider automatic keying instead), but it is
+ <em>absolutely essential</em> for security. Consider a manually keyed
+ system in which you leave the same key in place for months:
+ <ul>
+ <li>an attacker can have a very large sample of text sent with that key
+ to work with. This makes various cryptographic attacks much more
+ likely to succeed.</li>
+ <li>The chances of the key being compromised in some non-cryptographic
+ manner -- a spy finds it on a discarded notepad, someone breaks into
+ your server or your building and steals it, a staff member is bribed,
+ tricked, seduced or coerced into revealing it, etc. -- also increase
+ over time.</li>
+ <li>a successful attacker can read everything ever sent with that key.
+ This makes any successful attack extremely damaging.</li>
+ </ul>
+ It is clear that you must change keys often to have any useful security.
+ The only question is how often.</li>
+ <li>use <a href="glossary.html#PGP">PGP</a> or <a
+ href="glossary.html#SSH">SSH</a> for all key transfers</li>
+ <li>don't edit files with keys in them when someone can look over your
+ shoulder</li>
+ <li>worry about network security; could someone get keys by snooping
+ packets on the LAN between your X desktop and the gateway?</li>
+ <li>lock up your backup tapes for the gateway system</li>
+ <li>... and so on</li>
+</ul>
+
+<p>Linux FreeS/WAN provides some facilities to help with this. In particular,
+it is good policy to <strong>keep keys in separate files</strong> so you can
+edit configuration information in /etc/ipsec.conf without exposing keys to
+"shoulder surfers" or network snoops. We support this with the
+<var>also=</var> and <var>include</var> syntax in <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a>.</p>
+
+<p>See the last example in our <a href="examples">examples</a> file. In the
+/etc/ipsec.conf <var>conn samplesep</var> section, it has the line:</p>
+<pre> also=samplesep-keys</pre>
+
+<p>which tells the "ipsec manual" script to insert the configuration
+description labelled "samplesep-keys" if it can find it. The /etc/ipsec.conf
+file must also have a line such as:</p>
+<pre>include ipsec.*.conf</pre>
+
+<p>which tells it to read other files. One of those other files then might
+contain the additional data:</p>
+<pre>conn samplesep-keys
+ spi=0x200
+ esp=3des-md5-96
+ espenckey=0x01234567_89abcdef_02468ace_13579bdf_12345678_9abcdef0
+ espauthkey=0x12345678_9abcdef0_2468ace0_13579bdf</pre>
+
+<p>The first line matches the label in the "also=" line, so the indented
+lines are inserted. The net effect is exactly as if the inserted lines had
+occurred in the original file in place of the "also=" line.</p>
+
+<p>Variables set here are:</p>
+<dl>
+ <dt>spi</dt>
+ <dd>A number needed by the manual keying code. Any 3-digit hex number
+ will do, but if you have more than one manual connection then
+ <strong>spi must be different</strong> for each connection.</dd>
+ <dt>esp</dt>
+ <dd>Options for <a href="glossary.html#ESP">ESP</a> (Encapsulated
+ Security Payload), the usual IPsec encryption mode. Settings here are
+ for <a href="glossary.html#encryption">encryption</a> using <a
+ href="glossary.html#3DES">triple DES</a> and <a
+ href="glossary.html#authentication">authentication</a> using <a
+ href="glossary.html#MD5">MD5</a>. Note that encryption without
+ authentication should not be used; it is insecure.</dd>
+ <dt>espenkey</dt>
+ <dd>Key for ESP encryption. Here, a 192-bit hex number for triple
+ DES.</dd>
+ <dt>espauthkey</dt>
+ <dd>Key for ESP authentication. Here, a 128-bit hex number for MD5.</dd>
+</dl>
+
+<p><strong>Note</strong> that the <strong>example keys we supply</strong> are
+intended <strong>only for testing</strong>. For real use, you should go to
+automatic keying. If that is not possible, create your own keys for manual
+mode and keep them secret</p>
+
+<p>Of course, any files containing keys <strong>must</strong> have 600
+permissions and be owned by root.</p>
+
+<p>If you connect in this way to multiple sites, we recommend that you keep
+keys for each site in a separate file and adopt some naming convention that
+lets you pick them all up with a single "include" line. This minimizes the
+risk of losing several keys to one error or attack and of accidentally giving
+another site admin keys which he or she has no business knowing.</p>
+
+<p>Also note that if you have multiple manually keyed connections on a single
+machine, then the <var>spi</var> parameter must be different for each one.
+Any 3-digit hex number is OK, provided they are different for each
+connection. We reserve the range 0x100 to 0xfff for manual connections. Pluto
+assigns SPIs from 0x1000 up for automatically keyed connections.</p>
+
+<p>If <a href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> contains keys
+for manual mode connections, then it too must have permissions
+<var>rw-------</var>. We recommend instead that, if you must manual keying in
+production, you keep the keys in separate files.</p>
+
+<p>Note also that <a href="manpage.d/ipsec.conf.5.html">ipsec.conf</a> is
+installed with permissions <var>rw-r--r--</var>. If you plan to use manually
+keyed connections for anything more than initial testing, you <b>must</b>:</p>
+<ul>
+ <li>either change permissions to <var>rw-------</var></li>
+ <li>or store keys separately in secure files and access them via include
+ statements in <a href="manpage.d/ipsec.conf.5.html">ipsec.conf</a>.</li>
+</ul>
+
+<p>We recommend the latter method for all but the simplest configurations.</p>
+
+<h3><a name="ranbits">Creating keys with ranbits</a></h3>
+
+<p>You can create new <a href="glossary.html#random">random</a> keys with the
+<a href="manpage.d/ipsec_ranbits.8.html">ranbits(8)</a> utility. For example,
+the commands:</p>
+<pre> umask 177
+ ipsec ranbits 192 &gt; temp
+ ipsec ranbits 128 &gt;&gt; temp</pre>
+
+<p>create keys in the sizes needed for our default algorithms:</p>
+<ul>
+ <li>192-bit key for <a href="glossary.html#3DES">3DES</a> encryption <br>
+ (only 168 bits are used; parity bits are ignored)</li>
+ <li>128-bit key for keyed <a href="glossary.html#MD5">MD5</a>
+ authentication</li>
+</ul>
+
+<p>If you want to use <a href="glossary.html#SHA">SHA</a> instead of <a
+href="glossary.html#MD5">MD5</a>, that requires a 160-bit key</p>
+
+<p>Note that any <strong>temporary files</strong> used must be kept
+<strong>secure</strong> since they contain keys. That is the reason for the
+umask command above. The temporary file should be deleted as soon as you are
+done with it. You may also want to change the umask back to its default value
+after you are finished working on keys.</p>
+
+<p>The ranbits utility may pause for a few seconds if not enough entropy is
+available immediately. See ipsec_ranbits(8) and random(4) for details. You
+may wish to provide some activity to feed entropy into the system. For
+example, you might move the mouse around, type random characters, or do
+<var>du /usr &gt; /dev/null</var> in the background.</p>
+
+<h2><a name="boot">Setting up connections at boot time</a></h2>
+
+<p>You can tell the system to set up connections automatically at boot time
+by putting suitable stuff in /etc/ipsec.conf on both systems. The relevant
+section of the file is labelled by a line reading <var>config setup</var>.</p>
+
+<p>Details can be found in the <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> man page. We also
+provide a file of <a href="examples">example configurations</a>.</p>
+
+<p>The most likely options are something like:</p>
+<dl>
+ <dt>interfaces="ipsec0=eth0 ipsec1=ppp0"</dt>
+ <dd>Tells KLIPS which interfaces to use. Up to four interfaces numbered
+ ipsec[0-3] are supported. Each interface can support an arbitrary
+ number of tunnels.
+ <p>Note that for PPP, you give the ppp[0-9] device name here, not the
+ underlying device such as modem (or eth1 if you are using PPPoE).</p>
+ </dd>
+ <dt>interfaces=%defaultroute</dt>
+ <dd>Alternative setting, useful in simple cases. KLIPS will pick up both
+ its interface and the next hop information from the settings of the
+ Linux default route.</dd>
+ <dt>forwardcontrol=no</dt>
+ <dd>Normally "no". Set to "yes" if the IP forwarding option is disabled
+ in your network configuration. (This can be set as a kernel
+ configuration option or later. e.g. on Redhat, it's in
+ /etc/sysconfig/network and on SuSE you can adjust it with Yast.) Linux
+ FreeS/WAN will then enable forwarding when starting up and turn it off
+ when going down. This is used to ensure that no packets will be
+ forwarded before IPsec comes up and takes control.</dd>
+ <dt>syslog=daemon.error</dt>
+ <dd>Used in messages to the system logging daemon (syslogd) to specify
+ what type of software is sending the messages. If the settings are
+ "daemon.error" as in our example, then syslogd treats the messages as
+ error messages from a daemon.
+ <p>Note that <a href="glossary.html#Pluto">Pluto</a> does not currently
+ pay attention to this variable. The variable controls setup messages
+ only.</p>
+ </dd>
+ <dt>klipsdebug=</dt>
+ <dd>Debug settings for <a href="glossary.html#KLIPS">KLIPS</a>.</dd>
+ <dt>plutodebug=</dt>
+ <dd>Debug settings for <a href="glossary.html#Pluto">Pluto</a>.</dd>
+ <dt>... for both the above DEBUG settings</dt>
+ <dd>Normally, leave empty as shown above for no debugging output.<br>
+ Use "all" for maximum information.<br>
+ See ipsec_klipsdebug(8) and ipsec_pluto(8) man page for other options.
+ Beware that if you set /etc/ipsec.conf to enable debug output, your
+ system's log files may get large quickly.</dd>
+ <dt>dumpdir=/safe/directory</dt>
+ <dd>Normally, programs started by ipsec setup don't crash. If they do, by
+ default, no core dump will be produced because such dumps would contain
+ secrets. If you find you need to debug such crashes, you can set
+ dumpdir to the name of a directory in which to collect the core
+ file.</dd>
+ <dt>manualstart=</dt>
+ <dd>List of manually keyed connections to be automatically started at
+ boot time. Useful for testing, but not for long term use. Connections
+ which are automatically started should also be automatically
+ re-keyed.</dd>
+ <dt>pluto=yes</dt>
+ <dd>Whether to start <a href="glossary.html#Pluto">Pluto</a> when ipsec
+ startup is done.<br>
+ This parameter is optional and defaults to "yes" if not present.
+ <p>"yes" is strongly recommended for production use so that the keying
+ daemon (Pluto) will automatically re-key the connections regularly. The
+ ipsec-auto parameters ikelifetime, ipseclifetime and reykeywindow give
+ you control over frequency of rekeying.</p>
+ </dd>
+ <dt>plutoload="reno-van reno-adam reno-nyc"</dt>
+ <dd>List of tunnels (by name, e.g. fred-susan or reno-van in our
+ examples) to be loaded into Pluto's internal database at startup. In
+ this example, Pluto loads three tunnels into its database when it is
+ started.
+ <p>If plutoload is "%search", Pluto will load any connections whose
+ description includes "auto=add" or "auto=start".</p>
+ </dd>
+ <dt>plutostart="reno-van reno-adam reno-nyc"</dt>
+ <dd>List of tunnels to attempt to negotiate when Pluto is started.
+ <p>If plutostart is "%search", Pluto will start any connections whose
+ description includes "auto=start".</p>
+ <p>Note that, for a connection intended to be permanent, <strong>both
+ gateways should be set try to start</strong> the tunnel. This allows
+ quick recovery if either gateway is rebooted or has its IPsec
+ restarted. If only one gateway is set to start the tunnel and the other
+ gateway restarts, the tunnel may not be rebuilt.</p>
+ </dd>
+ <dt>plutowait=no</dt>
+ <dd>Controls whether Pluto waits for one tunnel to be established before
+ starting to negotiate the next. You might set this to "yes"
+ <ul>
+ <li>if your gateway is a very limited machine and you need to
+ conserve resources.</li>
+ <li>for debugging; the logs are clearer if only one connection is
+ brought up at a time</li>
+ </ul>
+ For a busy and resource-laden production gateway, you likely want "no"
+ so that connections are brought up in parallel and the whole process
+ takes less time.</dd>
+</dl>
+
+<p>The example assumes you are at the Reno office and will use IPsec to
+Vancouver, New York City and Amsterdam.</p>
+
+<h2><a name="multitunnel">Multiple tunnels between the same two
+gateways</a></h2>
+
+<p>Consider a pair of subnets, each with a security gateway, connected via
+the Internet:</p>
+<pre> 192.168.100.0/24 left subnet
+ |
+ 192.168.100.1
+ North Gateway
+ 101.101.101.101 left
+ |
+ 101.101.101.1 left next hop
+ [Internet]
+ 202.202.202.1 right next hop
+ |
+ 202.202.202.202 right
+ South gateway
+ 192.168.200.1
+ |
+ 192.168.200.0/24 right subnet</pre>
+
+<p>A tunnel specification such as:</p>
+<pre>conn northnet-southnet
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ leftsubnet=192.168.100.0/24
+ leftfirewall=yes
+ right=202.202.202.202
+ rightnexthop=202.202.202.1
+ rightsubnet=192.168.200.0/24
+ rightfirewall=yes</pre>
+will allow machines on the two subnets to talk to each other. You might test
+this by pinging from polarbear (192.168.100.7) to penguin (192.168.200.5).
+
+<p>However, <strong>this does not cover other traffic you might want to
+secure</strong>. To handle all the possibilities, you might also want these
+connection descriptions:</p>
+<pre>conn northgate-southnet
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ right=202.202.202.202
+ rightnexthop=202.202.202.1
+ rightsubnet=192.168.200.0/24
+ rightfirewall=yes
+
+conn northnet-southgate
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ leftsubnet=192.168.100.0/24
+ leftfirewall=yes
+ right=202.202.202.202
+ rightnexthop=202.202.202.1</pre>
+
+<p>Without these, neither gateway can do IPsec to the remote subnet. There is
+no IPsec tunnel or eroute set up for the traffic.</p>
+
+<p>In our example, with the non-routable 192.168.* addresses used, packets
+would simply be discarded. In a different configuration, with routable
+addresses for the remote subnet, <strong>they would be sent
+unencrypted</strong> since there would be no IPsec eroute and there would be
+a normal IP route.</p>
+
+<p>You might also want:</p>
+<pre>conn northgate-southgate
+ left=101.101.101.101
+ leftnexthop=101.101.101.1
+ right=202.202.202.202
+ rightnexthop=202.202.202.1</pre>
+
+<p>This is required if you want the two gateways to speak IPsec to each
+other.</p>
+
+<p>This requires a lot of duplication of details. Judicious use of
+<var>also=</var> and <var>include</var> can reduce this problem.</p>
+
+<p>Note that, while FreeS/WAN supports all four tunnel types, not all
+implementations do. In particular, some versions of Windows 2000 and the
+freely downloadable version of PGP provide only "client" functionality. You
+cannot use them as gateways with a subnet behind them. To get that
+functionality, you must upgrade to Windows 2000 server or the commercially
+available PGP products.</p>
+
+<h3><a name="advroute">One tunnel plus advanced routing</a></h3>
+It is also possible to use the new routing features in 2.2 and later kernels
+to avoid most needs for multple tunnels. Here is one mailing list message on
+the topic:
+<pre>Subject: Re: linux-ipsec: IPSec packets not entering tunnel?
+ Date: Mon, 20 Nov 2000
+ From: Justin Guyett &lt;jfg@sonicity.com&gt;
+
+On Mon, 20 Nov 2000, Claudia Schmeing wrote:
+
+&gt; Right Left
+&gt; "home" "office"
+&gt; 10.92.10.0/24 ---- 24.93.85.110 ========= 216.175.164.91 ---- 10.91.10.24/24
+&gt;
+&gt; I've created all four tunnels, and can ping to test each of them,
+&gt; *except* homegate-officenet.
+
+I keep wondering why people create all four tunnels. Why not route
+traffic generated from home to 10.91.10.24/24 out ipsec0 with iproute2?
+And 99% of the time you don't need to access "office" directly, which
+means you can eliminate all but the subnet&lt;-&gt;subnet connection.</pre>
+and FreeS/WAN technical lead Henry Spencer's comment:
+<pre>&gt; I keep wondering why people create all four tunnels. Why not route
+&gt; traffic generated from home to 10.91.10.24/24 out ipsec0 with iproute2?
+
+This is feasible, given some iproute2 attention to source addresses, but
+it isn't something we've documented yet... (partly because we're still
+making some attempt to support 2.0.xx kernels, which can't do this, but
+mostly because we haven't caught up with it yet).
+
+&gt; And 99% of the time you don't need to access "office" directly, which
+&gt; means you can eliminate all but the subnet&lt;-&gt;subnet connection.
+
+Correct in principle, but people will keep trying to ping to or from the
+gateways during testing, and sometimes they want to run services on the
+gateway machines too.</pre>
+
+
+<!-- Is this in the right spot in this document? -->
+<H2><A name="opp.gate">An Opportunistic Gateway</A></H2>
+
+<H3>Start from full opportunism</H3>
+
+<P>Full opportunism
+allows you to initiate and receive opportunistic connections on your
+machine. The remaining instructions in this section assume
+you have first set up full opportunism on your gateway using
+<A HREF="quickstart.html#opp.incoming">these instructions</A>.
+Both sets of instructions require mailing DNS records to your ISP. Collect
+DNS records for both the gateway (above) and the
+subnet nodes (below) before contacting your ISP.</P>
+
+
+<H3>Reverse DNS TXT records for each protected machine</H3>
+
+<P>You need these so that your Opportunistic peers can:
+<UL>
+<LI>discover the gateway's address, knowing only the IP address
+ that packets are bound for</LI>
+<LI>verify that the gateway is authorised to encrypt for that endpoint</LI>
+</UL>
+
+<P>On the gateway, generate a TXT record with:
+<PRE> ipsec showhostkey --txt 192.0.2.11</PRE>
+<P>Use your gateway address in place of 192.0.2.11.</P>
+
+<P>You should see (keys are trimmed for clarity throughout our example):</P>
+<PRE> ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+
+<P><B>This MUST BE the same key as in your gateway's TXT record, or nothing
+will work.</B></P>
+
+<P>In a text file, make one copy of this TXT record for each subnet
+ node:</P>
+<PRE> ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+
+<P>Above each entry, insert a line like this:</P>
+<PRE> 98.2.0.192.in-addr.arpa. IN PTR arthur.example.com.</PRE>
+
+<P>It must include:</P>
+<UL>
+<LI>The subnet node's address in reverse map format. For example, 192.0.2.120
+becomes <VAR>120.2.0.192.in-addr.arpa.</VAR>. Note the final period.</LI>
+<LI><VAR>IN PTR</VAR></LI>
+<LI>The node's name, ie. <VAR>arthur.example.com.</VAR>. Note
+the final period.</LI>
+</UL>
+
+<P>The result will be a file of TXT records, like this:</P>
+<PRE> 98.2.0.192.in-addr.arpa. IN PTR arthur.example.com.
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ 99.2.0.192.in-addr.arpa. IN PTR ford.example.com.
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;
+
+ 100.2.0.192.in-addr.arpa. IN PTR trillian.example.com.
+ ; RSA 2048 bits gateway.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+
+
+<H3>Publish your records</H3>
+
+<P>Ask your ISP to publish all the reverse DNS records you have collected.
+There may be a delay of up to 48 hours as the records propagate.</P>
+
+
+<H3>...and test them</H3>
+
+<P>Check a couple of records with commands like this one:</P>
+
+<PRE> ipsec verify --host ford.example.com
+ ipsec verify --host trillian.example.com</PRE>
+
+<P>The <var>verify</var> command checks for TXT records for both the
+subnet host and its gateway. You should see output like:</P>
+<PRE> ...
+ Looking for TXT in reverse map: 99.2.0.192.in-addr.arpa [OK]
+ ...
+ Looking for TXT in reverse map: 11.2.0.192.in-addr.arpa [OK]
+ ...
+ Looking for TXT in reverse map: 100.2.0.192.in-addr.arpa [OK]
+ ...
+ Looking for TXT in reverse map: 11.2.0.192.in-addr.arpa [OK]
+ ...</PRE>
+<H3>No Configuration Needed</H3>
+
+<P>FreeS/WAN 2.x ships with a built-in, automatically
+enabled OE connection <VAR>conn packetdefault</VAR>
+which applies OE, if possible, to all outbound traffic routed
+through the FreeS/WAN box.
+
+The
+<A HREF="manpage.d/ipsec.conf.5.html">ipsec.conf(5) manual</A>
+describes this connection in detail.
+While the effect is much the same as <VAR>private-or-clear</VAR>,
+the implementation is different: notably, it does not use policy
+groups.</P>
+
+<P>You can create more complex OE configurations
+for traffic forwarded through a FreeS/WAN box, as explained in our
+<A HREF="policygroups.html#policygroups">policy groups document</A>,
+or disable OE using
+<A HREF="policygroups.html#disable_policygroups">these instructions</A>.</P>
+
+
+
+<h2><a name="extruded.config">Extruded Subnets</a></h2>
+
+<p>What we call <a href="glossary.html#extruded">extruded subnets</a> are a
+special case of <a href="glossary.html#VPN.gloss">VPNs</a>.</p>
+
+<p>If your buddy has some unused IP addresses, in his subnet far off at the
+other side of the Internet, he can loan them to you... provided that the
+connection between you and him is fast enough to carry all the traffic
+between your machines and the rest of the Internet. In effect, he "extrudes"
+a part of his address space over the network to you, with your Internet
+traffic appearing to originate from behind his Internet gateway.</p>
+
+<p>As far as the Internet is concerned, your new extruded net is behind your
+buddy's gateway. You route all your packets for the Internet at large
+out his gateway, and receive return packets the same way. You route your
+local packets locally.</p>
+
+<p>Suppose your friend has a.b.c.0/24 and wants to give you a.b.c.240/28. The
+initial situation is:</p>
+<pre> subnet gateway Internet
+ a.b.c.0/24 a.b.c.1 p.q.r.s</pre>
+where anything from the Internet destined for any machine in a.b.c.0/24 is
+routed via p.q.r.s and that gateway knows what to do from there.
+
+<p>Of course it is quite normal for various smaller subnets to exist behind
+your friend's gateway. For example, your friend's company might have
+a.b.c.16/28=development, a.b.c.32/28=marketing and so on. The Internet
+neither knows not cares about this; it just delivers packets to the p.q.r.s
+and lets the gateway do whatever needs to be done from there.</p>
+
+<p>What we want to do is take a subnet, perhaps a.b.c.240/28, out of your
+friend's physical location <em>while still having your friend's gateway route
+to it</em>. As far as the Internet is concerned, you remain behind that
+gateway.</p>
+<pre> subnet gateway Internet your gate extruded
+
+ a.b.c.0/24 a.b.c.1 p.q.r.s d.e.f.g a.b.c.240/28
+
+ ========== tunnel ==========</pre>
+
+<p>The extruded addresses have to be a complete subnet.</p>
+
+<p>In our example, the friend's security gateway is also his Internet
+gateway, but this is not necessary. As long as all traffic from the Internet
+to his addresses passes through the Internet gate, the security gate could be
+a machine behind that. The IG would need to route all traffic for the
+extruded subnet to the SG, and the SG could handle the rest.</p>
+
+<p>First, configure your subnet using the extruded addresses. Your security
+gateway's interface to your subnet needs to have an extruded address
+(possibly using a Linux <a href="glossary.html#virtual">virtual
+interface</a>, if it also has to have a different address). Your gateway
+needs to have a route to the extruded subnet, pointing to that interface. The
+other machines at your site need to have addresses in that subnet, and
+default routes pointing to your gateway.</p>
+
+<p>If any of your friend's machines need to talk to the extruded subnet,
+<em>they</em> need to have a route for the extruded subnet, pointing at his
+gateway.</p>
+
+<p>Then set up an IPsec subnet-to-subnet tunnel between your gateway and his,
+with your subnet specified as the extruded subnet, and his subnet specified
+as "0.0.0.0/0".</p>
+
+<p>The tunnel description should be:</p>
+<pre>conn extruded
+ left=p.q.r.s
+ leftsubnet=0.0.0.0/0
+ right=d.e.f.g
+ rightsubnet=a.b.c.0/28</pre>
+
+<p>If either side was doing firewalling for the extruded subnet before the
+IPsec connection is set up, you'll need to poke holes in your
+<A HREF="firewall.html#firewall">firewall</A> to allow packets through.
+</p>
+
+<p>And it all just works. Your SG routes traffic for 0.0.0.0/0 -- that is,
+the whole Internet -- through the tunnel to his SG, which then sends it
+onward as if it came from his subnet. When traffic for the extruded subnet
+arrives at his SG, it gets sent through the tunnel to your SG, which passes
+it to the right machine.</p>
+
+<p>Remember that when ipsec_manual or ipsec_auto takes a connection down, it
+<em>does not undo the route</em> it made for that connection. This lets you
+take a connection down and bring up a new one, or a modified version of the
+old one, without having to rebuild the route it uses and without any risk of
+packets which should use IPsec accidentally going out in the clear. Because
+the route always points into KLIPS, the packets will always go there. Because
+KLIPS temporarily has no idea what to do with them (no eroute for them), they
+will be discarded.</p>
+
+<p>If you <em>do</em> want to take the route down, this is what the "unroute"
+operation in manual and auto is for. Just do an unroute after doing the
+down.</p>
+
+<p>Note that the route for a connection may have replaced an existing
+non-IPsec route. Nothing in Linux FreeS/WAN will put that pre-IPsec route
+back. If you need it back, you have to create it with the route command.</p>
+
+<h2><a name="roadvirt">Road Warrior with virtual IP address</a></h2>
+
+<p>Please note that <A HREF="http://www.freeswan.ca/download.php">Super
+FreeS/WAN</A> now features DHCP-over-IPsec, which is an alternate procedure
+for Virtual IP address assignment.
+<p>
+
+<p>Here is a mailing list message about another way to configure for road
+warrior support:</p>
+<pre>Subject: Re: linux-ipsec: understanding the vpn
+ Date: Thu, 28 Oct 1999 10:43:22 -0400
+ From: Irving Reid &lt;irving@nevex.com&gt;
+
+&gt; local-------linux------internet------mobile
+&gt; LAN box user
+&gt; ...
+
+&gt; now when the mobile user connects to the linux box
+&gt; it is given a virtual IP address, i have configured it to
+&gt; be in the 10.x.x.x range. mobile user and linux box
+&gt; have a tunnel between them with these IP addresses.
+
+&gt; Uptil this all is fine.
+
+If it is possible to configure your mobile client software *not* to
+use a virtual IP address, that will make your life easier. It is easier
+to configure FreeS/WAN to use the actual address the mobile user gets
+from its ISP.
+
+Unfortunately, some Windows clients don't let you choose.
+
+&gt; what i would like to know is that how does the mobile
+&gt; user communicate with other computers on the local
+&gt; LAN , of course with the vpn ?
+
+&gt; what IP address should the local LAN
+&gt; computers have ? I guess their default gateway
+&gt; should be the linux box ? and does the linux box need
+&gt; to be a 2 NIC card box or one is fine.
+
+As someone else stated, yes, the Linux box would usually be the default
+IP gateway for the local lan.
+
+However...
+
+If you mobile user has software that *must* use a virtual IP address,
+the whole picture changes. Nobody has put much effort into getting
+FreeS/WAN to play well in this environment, but here's a sketch of one
+approach:
+
+Local Lan 1.0.0.0/24
+ |
+ +- Linux FreeS/WAN 1.0.0.2
+ |
+ | 1.0.0.1
+ Router
+ | 2.0.0.1
+ |
+Internet
+ |
+ | 3.0.0.1
+Mobile User
+ Virtual Address: 1.0.0.3
+
+Note that the Local Lan network (1.0.0.x) can be registered, routable
+addresses.
+
+Now, the Mobile User sets up an IPSec security association with the
+Linux box (1.0.0.2); it should ESP encapsulate all traffic to the
+network 1.0.0.x **EXCEPT** UDP port 500. 500/udp is required for the key
+negotiation, which needs to work outside of the IPSec tunnel.
+
+On the Linux side, there's a bunch of stuff you need to do by hand (for
+now). FreeS/WAN should correctly handle setting up the IPSec SA and
+routes, but I haven't tested it so this may not work...
+
+The FreeS/WAN conn should look like:
+
+conn mobile
+ right=1.0.0.2
+ rightsubnet=1.0.0.0/24
+ rightnexthop=1.0.0.1
+ left=0.0.0.0 # The infamous "road warrior"
+ leftsubnet=1.0.0.3/32
+
+Note that the left subnet contains *only* the remote host's virtual
+address.
+
+Hopefully the routing table on the FreeS/WAN box ends up looking like
+this:
+
+% netstat -rn
+Kernel IP routing table
+Destination Gateway Genmask Flags MSS Window irtt Iface
+1.0.0.0 0.0.0.0 255.255.255.0 U 1500 0 0 eth0
+127.0.0.0 0.0.0.0 255.0.0.0 U 3584 0 0 lo
+0.0.0.0 1.0.0.1 0.0.0.0 UG 1500 0 0 eth0
+1.0.0.3 1.0.0.1 255.255.255.255 UG 1433 0 0 ipsec0
+
+So, if anybody sends a packet for 1.0.0.3 to the Linux box, it should
+get bundled up and sent through the tunnel. To get the packets for
+1.0.0.3 to the Linux box in the first place, you need to use "proxy
+ARP".
+
+How this works is: when a host or router on the local Ethernet segment
+wants to send a packet to 1.0.0.3, it sends out an Ethernet level
+broadcast "ARP request". If 1.0.0.3 was on the local LAN, it would
+reply, saying "send IP packets for 1.0.0.3 to my Ethernet address".
+
+Instead, you need to set up the Linux box so that _it_ answers ARP
+requests for 1.0.0.3, even though that isn't its IP address. That
+convinces everyone else on the lan to send 1.0.0.3 packets to the Linux
+box, where the usual FreeS/WAN processing and routing take over.
+
+% arp -i eth0 -s 1.0.0.3 -D eth0 pub
+
+This says, if you see an ARP request on interface eth0 asking for
+1.0.0.3, respond with the Ethernet address of interface eth0.
+
+Now, as I said at the very beginning, if it is *at all* possible to
+configure your client *not* to use the virtual IP address, you can avoid
+this whole mess.</pre>
+
+<h2><a name="dynamic">Dynamic Network Interfaces</a></h2>
+
+<p>Sometimes you have to cope with a situation where the network interface(s)
+aren't all there at boot. The common example is notebooks with PCMCIA.</p>
+
+<h3><a name="basicdyn">Basics</a></h3>
+
+<p>The key issue here is that the <var>config setup</var> section of the
+<var>/etc/ipsec.conf</var> configuration file lists the connection between
+ipsecN and hardware interfaces, in the <var>interfaces=</var> variable. At
+any time when <var>ipsec setup start</var> or <var>ipsec setup restart</var>
+is run this variable <strong>must</strong> correspond to the current real
+situation. More precisely, it <strong>must not</strong> mention any hardware
+interfaces which don't currently exist. The difficulty is that an <var>ipsec
+setup start</var> command is normally run at boot time so interfaces that are
+not up then are mis-handled.</p>
+
+<h3><a name="bootdyn">Boot Time</a></h3>
+
+<p>Normally, an <var>ipsec setup start</var> is run at boot time. However, if
+the hardware situation at boot time is uncertain, one of two things must be
+done.</p>
+<ul>
+ <li>One possibility is simply not to have IPsec brought up at boot time. To
+ do this:
+ <pre> chkconfig --level 2345 ipsec off</pre>
+ That's for modern Red Hats or other Linuxes with chkconfig. Systems which
+ lack this will require fiddling with symlinks in /etc/rc.d/rc?.d or the
+ equivalent.</li>
+ <li>Another possibility is to bring IPsec up with no interfaces, which is
+ less aesthetically satisfying but simpler. Just put
+ <pre> interfaces=</pre>
+ in the configuration file. KLIPS and Pluto will be started, but won't do
+ anything.</li>
+</ul>
+
+<h3><a name="changedyn">Change Time</a></h3>
+
+<p>When the hardware *is* in place, IPsec has to be made aware of it. Someday
+there may be a nice way to do this.</p>
+
+<p>Right now, the way to do it is to fix the <var>/etc/ipsec.conf</var> file
+appropriately, so <var>interfaces</var> reflects the new situation, and then
+restart the IPsec subsystem. This does break any existing IPsec
+connections.</p>
+
+<p>If IPsec wasn't brought up at boot time, do</p>
+<pre> ipsec setup start</pre>
+while if it was, do
+<pre> ipsec setup restart</pre>
+which won't be as quick.
+
+<p>If some of the hardware is to be taken out, before doing that, amend the
+configuration file so interfaces no longer includes it, and do</p>
+<pre> ipsec setup restart</pre>
+
+<p>Again, this breaks any existing connections.</p>
+
+<h2><a name="unencrypted">Unencrypted tunnels</a></h2>
+
+<p>Sometimes you might want to create a tunnel without encryption. Often this
+is a bad idea, even if you have some data which need not be private. See this
+<a href="ipsec.html#traffic.resist">discussion</a>.</p>
+
+<p>The IPsec protocols provide two ways to do build such tunnels:</p>
+<dl>
+ <dt>using ESP with null encryption</dt>
+ <dd>not supported by FreeS/WAN</dd>
+ <dt>using <a href="glossary.html#AH">AH</a> without <a
+ href="glossary.html#ESP">ESP</a></dt>
+ <dd>supported for manually keyed connections</dd>
+ <dd>possible with explicit commands via <a
+ href="manpage.d/ipsec_whack.8.html">ipsec_whack(8)</a> (see this <a
+ href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00190.html">list
+ message</a>)</dd>
+ <dd>not supported in the <a
+ href="manpage.d/ipsec_auto.8.html">ipsec_auto(8)</a> scripts.</dd>
+</dl>
+One situation in which this comes up is when otherwise some data would be
+encrypted twice. Alice wants a secure tunnel from her machine to Bob's. Since
+she's behind one security gateway and he's behind another, part of the tunnel
+that they build passes through the tunnel that their site admins have built
+between the gateways. All of Alice and Bob's messages are encrypted twice.
+
+<p>There are several ways to handle this.</p>
+<ul>
+ <li>Just accept the overhead of double encryption. The site admins might
+ choose this if any of the following apply:
+ <ul>
+ <li>policy says encrypt everything (usually, it should)</li>
+ <li>they don't entirely trust Alice and Bob (usually, if they don't
+ have to, they shouldn't)</li>
+ <li>if they don't feel the saved cycles are worth the time they'd need
+ to build a non-encrypted tunnel for Alice and Bob's packets (often,
+ they aren't)</li>
+ </ul>
+ </li>
+ <li>Use a plain IP-in-IP tunnel. These are not well documented. A good
+ starting point is in the Linux kernel source tree, in
+ /usr/src/linux/drivers/net/README.tunnel.</li>
+ <li>Use a manually-keyed AH-only tunnel.</li>
+</ul>
+
+<p>Note that if Alice and Bob want end-to-end security, they must build a
+tunnel end-to-end between their machines or use some other end-to-end tool
+such as PGP or SSL that suits their data. The only question is whether the
+admins build some special unencrypted tunnel for those already-encrypted
+packets.</p>
+</body>
+</html>
diff --git a/doc/src/background.html b/doc/src/background.html
new file mode 100644
index 000000000..e25b9da03
--- /dev/null
+++ b/doc/src/background.html
@@ -0,0 +1,376 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN background</title>
+ <meta name="keywords" content="Linux, IPSEC, VPN, security, FreeSWAN">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: background.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="background">Linux FreeS/WAN background</a></h1>
+
+<p>This section discusses a number of issues which have three things in
+common:</p>
+<ul>
+ <li>They are not specifically FreeS/WAN problems</li>
+ <li>You may have to understand them to get FreeS/WAN working right</li>
+ <li>They are not simple questions</li>
+</ul>
+
+<p>Grouping them here lets us provide the explanations some users will need
+without unduly complicating the main text.</p>
+
+<p>The explanations here are intended to be adequate for FreeS/WAN purposes
+(please comment to the <a href="mail.html">users mailing list</a> if you
+don't find them so), but they are not trying to be complete or definitive. If
+you need more information, see the references provided in each section.</p>
+
+<h2><a name="dns.background">Some DNS background</a></h2>
+
+<p><a href="glossary.html#carpediem">Opportunistic encryption</a> requires
+that the gateway systems be able to fetch public keys, and other
+IPsec-related information, from each other's DNS (Domain Name Service)
+records.</p>
+
+<p><a href="glossary.html#DNS">DNS</a> is a distributed database that maps
+names to IP addresses and vice versa.</p>
+
+<p>Much good reference material is available for DNS, including:</p>
+<ul>
+ <li>the <a href="http://www.linuxdoc.org/HOWTO/DNS-HOWTO.html">DNS
+ HowTo</a></li>
+ <li>the standard <a href="biblio.html#DNS.book">DNS reference</a> book</li>
+ <li><a href="http://www.linuxdoc.org/LDP/nag2/index.html">Linux Network
+ Administrator's Guide</a></li>
+ <li><a
+ href="http://www.nominum.com/resources/whitepapers/bind-white-paper.html">BIND
+ overview</a></li>
+ <li><a
+ href="http://www.nominum.com/resources/documentation/Bv9ARM.pdf">BIND 9
+ Administrator's Reference</a></li>
+</ul>
+
+<p>We give only a brief overview here, intended to help you use DNS for
+FreeS/WAN purposes.</p>
+
+<h3><a name="forward.reverse">Forward and reverse maps</a></h3>
+
+<p>Although the implementation is distributed, it is often useful to speak of
+DNS as if it were just two enormous tables:</p>
+<ul>
+ <li>the forward map: look up a name, get an IP address</li>
+ <li>the reverse map: look up an IP address, get a name</li>
+</ul>
+
+<p>Both maps can optionally contain additional data. For opportunistic
+encryption, we insert the data need for IPsec authentication.</p>
+
+<p>A system named gateway.example.com with IP address 10.20.30.40 should have
+at least two DNS records, one in each map:</p>
+<dl>
+ <dt>gateway.example.com. IN A 10.20.30.40</dt>
+ <dd>used to look up the name and get an IP address</dd>
+ <dt>40.30.20.10.in-addr.arpa. IN PTR gateway.example.com.</dt>
+ <dd>used for reverse lookups, looking up an address to get the associated
+ name. Notice that the digits here are in reverse order; the actual
+ address is 10.20.30.40 but we use 40.30.20.10 here.</dd>
+</dl>
+
+<h3>Hierarchy and delegation</h3>
+
+<p>For both maps there is a hierarchy of DNS servers and a system of
+delegating authority so that, for example:</p>
+<ul>
+ <li>the DNS administrator for example.com can create entries of the form
+ <var>name</var>.example.com</li>
+ <li>the example.com admin cannot create an entry for counterexample.com;
+ only someone with authority for .com can do that</li>
+ <li>an admin might have authority for 20.10.in-addr.arpa.</li>
+ <li>in either map, authority can be delegated
+ <ul>
+ <li>the example.com admin could give you authority for
+ westcoast.example.com</li>
+ <li>the 20.10.in-addr.arpa admin could give you authority for
+ 30.20.10.in-addr.arpa</li>
+ </ul>
+ </li>
+</ul>
+
+<p>DNS zones are the units of delegation. There is a hierarchy of zones.</p>
+
+<h3>Syntax of DNS records</h3>
+
+<p>Returning to the example records:</p>
+<pre> gateway.example.com. IN A 10.20.30.40
+ 40.30.20.10.in-addr.arpa. IN PTR gateway.example.com.</pre>
+
+<p>some syntactic details are:</p>
+<ul>
+ <li>the IN indicates that these records are for <strong>In</strong>ternet
+ addresses</li>
+ <li>The final periods in '.com.' and '.arpa.' are required. They indicate
+ the root of the domain name system.</li>
+</ul>
+
+<p>The capitalised strings after IN indicate the type of record. Possible
+types include:</p>
+<ul>
+ <li><strong>A</strong>ddress, for forward lookups</li>
+ <li><strong>P</strong>oin<strong>T</strong>e<strong>R</strong>, for reverse
+ lookups</li>
+ <li><strong>C</strong>anonical <strong>NAME</strong>, records to support
+ aliasing, multiple names for one address</li>
+ <li><strong>M</strong>ail e<strong>X</strong>change, used in mail
+ routing</li>
+ <li><strong>SIG</strong>nature, used in <a href="glossary.html#SDNS">secure
+ DNS</a></li>
+ <li><strong>KEY</strong>, used in <a href="glossary.html#SDNS">secure
+ DNS</a></li>
+ <li><strong>T</strong>e<strong>XT</strong>, a multi-purpose record type</li>
+</ul>
+
+<p>To set up for opportunistic encryption, you add some TXT records
+to your DNS data. Details are in our <a href="quickstart.html">quickstart</a>
+document.</p>
+
+<h3>Cacheing, TTL and propagation delay</h3>
+
+<p>DNS information is extensively cached. With no caching, a lookup by your
+system of "www.freeswan.org" might involve:</p>
+<ul>
+ <li>your system asks your nameserver for "www.freeswan.org"</li>
+ <li>local nameserver asks root server about ".org", gets reply</li>
+ <li>local nameserver asks .org nameserver about "freeswan.org", gets
+ reply</li>
+ <li>local nameserver asks freeswan.org nameserver about "www.freeswan.org",
+ gets reply</li>
+</ul>
+
+<p>However, this can be a bit inefficient. For example, if you are in the
+Phillipines, the closest a root server is in Japan. That might send you to a
+.org server in the US, and then to freeswan.org in Holland. If everyone did
+all those lookups every time they clicked on a web link, the net would grind
+to a halt.</p>
+
+<p>Nameservers therefore cache information they look up. When you click on
+another link at www.freeswan.org, your local nameserver has the IP address
+for that server in its cache, and no further lookups are required. </p>
+
+<p>Intermediate results are also cached. If you next go to
+lists.freeswan.org, your nameserver can just ask the freeswan.org nameserver
+for that address; it does not need to query the root or .org nameservers
+because it has a cached address for the freeswan.org zone server.</p>
+
+<p>Of course, like any cacheing mechanism, this can create problems of
+consistency. What if the administrator for freeswan.org changes the IP
+address, or the authentication key, for www.freeswan.org? If you use old
+information from the cache, you may get it wrong. On the other hand, you
+cannot afford to look up fresh information every time. Nor can you expect the
+freeswan.org server to notify you; that isn't in the protocols.</p>
+
+<p>The solution that is in the protocols is fairly simple. Cacheable records
+are marked with Time To Live (TTL) information. When the time expires, the
+caching server discards the record. The next time someone asks for it, the
+server fetches a fresh copy. Of course, a server may also discard records
+before their TTL expires if it is running out of cache space.</p>
+
+<p>This implies that there will be some delay before the new version of a
+changed record propagates around the net. Until the TTLs on all copies of the
+old record expire, some users will see it because that is what is in their
+cache. Other users may see the new record immediately because they don't have
+an old one cached.</p>
+
+<h2><a name="MTU.trouble">Problems with packet fragmentation</a></h2>
+
+<p>It seems, from mailing list reports, to be moderately common for problems
+to crop up in which small packets pass through the IPsec tunnels just fine
+but larger packets fail.</p>
+
+<p>These problems are caused by various devices along the way mis-handling
+either packet fragments or <a href="glossary.html#pathMTU">path MTU
+discovery</a>.</p>
+
+<p>IPsec makes packets larger by adding an ESP or AH header. This can tickle
+assorted bugs in fragment handling in routers and firewalls, or in path MTU
+discovery mechanisms, and cause a variety of symptoms which are both annoying
+and, often, quite hard to diagnose.</p>
+
+<p>An explanation from project technical lead Henry Spencer:</p>
+<pre>The problem is IP fragmentation; more precisely, the problem is that the
+second, third, etc. fragments of an IP packet are often difficult for
+filtering mechanisms to classify.
+
+Routers cannot rely on reassembling the packet, or remembering what was in
+earlier fragments, because the fragments may be out of order or may even
+follow different routes. So any general, worst-case filtering decision
+pretty much has to be made on each fragment independently. (If the router
+knows that it is the only route to the destination, so all fragments
+*must* pass through it, reassembly would be possible... but most routers
+don't want to bother with the complications of that.)
+
+All fragments carry roughly the original IP header, but any higher-level
+header is (for IP purposes) just the first part of the packet data... so
+only the first fragment carries that. So, for example, on examining the
+second fragment of a TCP packet, you could tell that it's TCP, but not
+what port number it is destined for -- that information is in the TCP
+header, which appears in the first fragment only.
+
+The result of this classification difficulty is that stupid routers and
+over-paranoid firewalls may just throw fragments away. To get through
+them, you must reduce your MTU enough that fragmentation will not occur.
+(In some cases, they might be willing to attempt reassembly, but have very
+limited resources to devote to it, meaning that packets must be small and
+fragments few in number, leading to the same conclusion: smaller MTU.)</pre>
+
+<p>In addition to the problem Henry describes, you may also have trouble with
+<a href="glossary.html#pathMTU">path MTU discovery</a>.</p>
+
+<p>By default, FreeS/WAN uses a large <a href="glossary.html#MTU">MTU</a> for
+the ipsec device. This avoids some problems, but may complicate others.
+Here's an explanation from Claudia:</p>
+<pre>Here are a couple of pieces of background information. Apologies if you
+have seen these already. An excerpt from one of my old posts:
+
+ An MTU of 16260 on ipsec0 is usual. The IPSec device defaults to this
+ high MTU so that it does not fragment incoming packets before encryption
+ and encapsulation. If after IPSec processing packets are larger than 1500,
+ [ie. the mtu of eth0] then eth0 will fragment them.
+
+ Adding IPSec headers adds a certain number of bytes to each packet.
+ The MTU of the IPSec interface refers to the maximum size of the packet
+ before the IPSec headers are added. In some cases, people find it helpful
+ to set ipsec0's MTU to 1500-(IPSec header size), which IIRC is about 1430.
+
+ That way, the resulting encapsulated packets don't exceed 1500. On most
+ networks, packets less than 1500 will not need to be fragmented.
+
+and... (from Henry Spencer)
+
+ The way it *ought* to work is that the MTU advertised by the ipsecN
+ interface should be that of the underlying hardware interface, less a
+ pinch for the extra headers needed.
+
+ Unfortunately, in certain situations this breaks many applications.
+ There is a widespread implicit assumption that the smallest MTUs are
+ at the ends of paths, not in the middle, and another that MTUs are
+ never less than 1500. A lot of code is unprepared to handle paths
+ where there is an "interior minimum" in the MTU, especially when it's
+ less than 1500. So we advertise a big MTU and just let the resulting
+ big packets fragment.
+
+This usually works, but we do get bitten in cases where some intermediate
+point can't handle all that fragmentation. We can't win on this one.</pre>
+
+<p>The MTU can be changed with an <var>overridemtu=</var> statement in the
+<var>config setup</var> section of <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf.5</a>.</p>
+
+<p>For a discussion of MTU issues and some possible solutions using Linux
+advanced routing facilities, see the <a
+href="http://www.linuxguruz.org/iptables/howto/2.4routing-15.html#ss15.6">Linux
+2.4 Advanced Routing HOWTO</a>.
+
+For a discussion of MTU and NAT (Network Address Translation), see
+<A HREF="http://harlech.math.ucla.edu/services/ipsec.html">James Carter's MTU
+notes</A>.</p>
+
+<h2><a name="nat.background">Network address translation (NAT)</a></h2>
+
+<p><strong>N</strong>etwork <strong>A</strong>ddress
+<strong>T</strong>ranslation is a service provided by some gateway machines.
+Calling it NAPT (adding the word <strong>P</strong>ort) would be more
+precise, but we will follow the widespread usage.</p>
+
+<p>A gateway doing NAT rewrites the headers of packets it is forwarding,
+changing one or more of:</p>
+<ul>
+ <li>source address</li>
+ <li>source port</li>
+ <li>destination address</li>
+ <li>destination port</li>
+</ul>
+
+<p>On Linux 2.4, NAT services are provided by the <a
+href="http://netfilter.samba.org">netfilter(8)</a> firewall code. There are
+several <a
+href="http://netfilter.samba.org/documentation/index.html#HOWTO">Netfilter
+HowTos</a> including one on NAT.</p>
+
+<p>For older versions of Linux, this was referred to as "IP masquerade" and
+different tools were used. See this <a
+href="http://www.e-infomax.com/ipmasq/">resource page</a>.</p>
+
+<p>Putting an IPsec gateway behind a NAT gateway is not recommended. See our
+<a href="firewall.html#NAT">firewalls document</a>.</p>
+
+<h3>NAT to non-routable addresses</h3>
+
+<p>The most common application of NAT uses private <a
+href="glossary.html#non-routable">non-routable</a> addresses.</p>
+
+<p>Often a home or small office network will have:</p>
+<ul>
+ <li>one connection to the Internet</li>
+ <li>one assigned publicly visible IP address</li>
+ <li>several machines that all need access to the net</li>
+</ul>
+
+<p>Of course this poses a problem since several machines cannot use one
+address. The best solution might be to obtain more addresses, but often this
+is impractical or uneconomical.</p>
+
+<p>A common solution is to have:</p>
+<ul>
+ <li><a href="glossary.html#non-routable">non-routable</a> addresses on the
+ local network</li>
+ <li>the gateway machine doing NAT</li>
+ <li>all packets going outside the LAN rewritten to have the gateway as
+ their source address</li>
+</ul>
+
+<p>The client machines are set up with reserved <a
+href="#non-routable">non-routable</a> IP addresses defined in RFC 1918. The
+masquerading gateway, the machine with the actual link to the Internet,
+rewrites packet headers so that all packets going onto the Internet appear to
+come from one IP address, that of its Internet interface. It then gets all
+the replies, does some table lookups and more header rewriting, and delivers
+the replies to the appropriate client machines.</p>
+
+<p>As far as anyone else on the Internet is concerned, the systems behind the
+gateway are completely hidden. Only one machine with one IP address is
+visible.</p>
+
+<p>For IPsec on such a gateway, you can entirely ignore the NAT in:</p>
+<ul>
+ <li><a href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a></li>
+ <li>firewall rules affecting your Internet-side interface</li>
+</ul>
+
+<p>Those can be set up exactly as they would be if your gateway had no other
+systems behind it.</p>
+
+<p>You do, however, have to take account of the NAT in firewall rules which
+affect packet forwarding.</p>
+
+<h3>NAT to routable addresses</h3>
+
+<p>NAT to routable addresses is also possible, but is less common and may
+make for rather tricky routing problems. We will not discuss it here. See the
+<a href="http://netfilter.samba.org/documentation/index.html#HOWTO">Netfilter
+HowTos</a>.</p>
+</body>
+</html>
diff --git a/doc/src/biblio.html b/doc/src/biblio.html
new file mode 100644
index 000000000..d84e4c2cb
--- /dev/null
+++ b/doc/src/biblio.html
@@ -0,0 +1,354 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN bibliography</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, bibliography">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: biblio.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="biblio">Bibliography for the Linux FreeS/WAN project</a></h1>
+
+<p>For extensive bibliographic links, see the <a
+href="http://liinwww.ira.uka.de/bibliography/index.html">Collection of
+Computer Science Bibliographies</a></p>
+
+<p>See our <a href="web.html">web links</a> for material available online.</p>
+<hr>
+<a name="adams">Carlisle Adams and Steve Lloyd <cite>Understanding Public Key
+Infrastructure</cite><br>
+</a>Macmillan 1999 ISBN 1-57870-166-x
+
+<p>An overview, mainly concentrating on policy and strategic issues rather
+than the technical details. Both authors work for <a
+href="glossary.html#PKI">PKI</a> vendor <a
+href="http://www.entrust.com/">Entrust</a>.</p>
+<hr>
+<a name="DNS.book">Albitz, Liu &amp; Loukides <cite>DNS &amp; BIND</cite> 3rd
+edition<br>
+</a> O'Reilly 1998 ISBN 1-56592-512-2
+
+<p>The standard reference on the <a href="glossary.html#DNS">Domain Name
+Service</a> and <a href="glossary.html#BIND">Berkeley Internet Name
+Daemon</a>.</p>
+<hr>
+<a name="anderson">Ross Anderson</a>, <cite>Security Engineering - a Guide to
+Building Dependable Distributed Systems</cite><br>
+Wiley, 2001, ISBN 0471389226
+
+<p>Easily the best book for the security professional I have seen.
+<strong>Highly recommended</strong>. See the <a
+href="http://www.cl.cam.ac.uk/~rja14/book.html">book web page</a>.</p>
+
+<p>This is quite readable, but Schneier's <a href="#secrets">Secrets and
+Lies</a> might be an easier introduction.</p>
+<hr>
+<a name="puzzle">Bamford <cite>The Puzzle Palace, A report on NSA, Americas's
+most Secret Agency</cite><br>
+Houghton Mifflin 1982 ISBN 0-395-31286-8</a>
+<hr>
+Bamford <cite>Body of Secrets</cite>
+
+<p>The sequel.</p>
+<hr>
+<a name="bander">David Bander</a>, <cite>Linux Security Toolkit</cite><br>
+IDG Books, 2000, ISBN: 0764546902
+
+<p>This book has a short section on FreeS/WAN and includes Caldera Linux on
+CD.</p>
+<hr>
+<a name="CZR">Chapman, Zwicky &amp; Russell</a>, <cite>Building Internet
+Firewalls</cite><br>
+O'Reilly 1995 ISBN 1-56592-124-0
+<hr>
+<a name="firewall.book">Cheswick and Bellovin</a> <cite>Firewalls and
+Internet Security: Repelling the Wily Hacker</cite><br>
+Addison-Wesley 1994 ISBN 0201633574
+
+<p>A fine book on firewalls in particular and security in general from two of
+AT&amp;T's system adminstrators.</p>
+
+<p>Bellovin has also done a number of <a href="web.html#papers">papers</a> on
+IPsec and co-authored a <a href="intro.html#applied">paper</a> on a large
+FreeS/WAN application.</p>
+<hr>
+<a name="comer">Comer <cite>Internetworking with TCP/IP</cite><br>
+Prentice Hall</a>
+<ul>
+ <li>Vol. I: Principles, Protocols, &amp; Architecture, 3rd Ed. 1995
+ ISBN:0-13-216987-8</li>
+ <li>Vol. II: Design, Implementation, &amp; Internals, 2nd Ed. 1994
+ ISBN:0-13-125527-4</li>
+ <li>Vol. III: Client/Server Programming &amp; Applications
+ <ul>
+ <li>AT&amp;T TLI Version 1994 ISBN:0-13-474230-3</li>
+ <li>BSD Socket Version 1996 ISBN:0-13-260969-X</li>
+ <li>Windows Sockets Version 1997 ISBN:0-13-848714-6</li>
+ </ul>
+ </li>
+</ul>
+
+<p>If you need to deal with the details of the network protocols, read either
+this series or the <a href="#stevens">Stevens and Wright</a> series before
+you start reading the RFCs.</p>
+<hr>
+<a name="diffie">Diffie and Landau</a> <cite>Privacy on the Line: The
+Politics of Wiretapping and Encryption</cite><br>
+MIT press 1998 ISBN 0-262-04167-7 (hardcover) or 0-262-54100-9<br>
+
+<hr>
+<a name="d_and_hark">Doraswamy and Harkins <cite>IP Sec: The New Security
+Standard for the Internet, Intranets and Virtual Private Networks</cite><br>
+Prentice Hall 1999 ISBN: 0130118982</a>
+<hr>
+<a name="EFF"> Electronic Frontier Foundation <cite>Cracking DES: Secrets of
+Encryption Research, Wiretap Politics and Chip Design</cite><br>
+</a> O'Reilly 1998 ISBN 1-56592-520-3
+
+<p>To conclusively demonstrate that DES is inadequate for continued use, the
+<a href="glossary.html#EFF">EFF</a> built a machine for just over $200,000
+that breaks DES encryption in under five days on average, under nine in the
+worst case.</p>
+
+<p>The book provides details of their design and, perhaps even more
+important, discusses why they felt the project was necessary. Recommended for
+anyone interested in any of the three topics mentioned in the subtitle.</p>
+
+<p>See also the <a href="http://www.eff.org/descracker.html"> EFF page on
+this project </a> and our discussion of <a
+href="politics.html#desnotsecure">DES insecurity</a>.</p>
+<hr>
+Martin Freiss <cite>Protecting Networks with SATAN</cite><br>
+O'Reilly 1998 ISBN 1-56592-425-8<br>
+translated from a 1996 work in German
+
+<p>SATAN is a Security Administrator's Tool for Analysing Networks. This book
+is a tutorial in its use.</p>
+<hr>
+Gaidosch and Kunzinger<cite> A Guide to Virtual Private Networks</cite><br>
+Prentice Hall 1999 ISBN: 0130839647
+<hr>
+<a name="Garfinkel">Simson Garfinkel</a> <cite>Database Nation: the death of
+privacy in the 21st century</cite><br>
+O'Reilly 2000 ISBN 1-56592-653-6
+
+<p>A thoughtful and rather scary book.</p>
+<hr>
+<a name="PGP">Simson Garfinkel</a> <cite>PGP: Pretty Good Privacy</cite><br>
+O'Reilly 1995 ISBN 1-56592-098-8
+
+<p>An excellent introduction and user manual for the <a
+href="glossary.html#PGP">PGP</a> email-encryption package. PGP is a good
+package with a complex and poorly-designed user interface. This book or one
+like it is a must for anyone who has to use it at length.</p>
+
+<p>The book covers using PGP in Unix, PC and Macintosh environments, plus
+considerable background material on both the technical and political issues
+around cryptography.</p>
+
+<p>The book is now seriously out of date. It does not cover recent
+developments such as commercial versions since PGP 5, the Open PGP standard
+or GNU PG..</p>
+<hr>
+<a name="practical">Garfinkel and Spafford</a> <cite>Practical Unix
+Security</cite><br>
+O'Reilly 1996 ISBN 1-56592-148-8
+
+<p>A standard reference.</p>
+
+<p>Spafford's web page has an excellent collection of<a
+href="http://www.cs.purdue.edu/coast/hotlist"> crypto and security
+links</a>.</p>
+<hr>
+<a name="Kahn">David Kahn</a> <cite>The Codebreakers: the Comprehensive
+History of Secret Communications from Ancient Times to the Internet</cite><br>
+second edition Scribner 1996 ISBN 0684831309
+
+<p>A history of codes and code-breaking from ancient Egypt to the 20th
+century. Well-written and exhaustively researched. <strong>Highly
+recommended</strong>, even though it does not have much on computer
+cryptography.</p>
+<hr>
+David Kahn <cite>Seizing the Enigma, The Race to Break the German U-Boat
+codes, 1939-1943</cite><br>
+Houghton Mifflin 1991 ISBN 0-395-42739-8
+<hr>
+<a name="kirch">Olaf Kirch</a> <cite>Linux Network Administrator's
+Guide</cite><br>
+O'Reilly 1995 ISBN 1-56592-087-2
+
+<p>Now becoming somewhat dated in places, but still a good introductory book
+and general reference.</p>
+<hr>
+<a name="LinVPN">Kolesnikov and Hatch</a>, <cite>Building Linux Virtual
+Private Networks (VPNs)</cite><br>
+New Riders 2002
+
+<p>This has had a number of favorable reviews, including <a
+href="http://www.slashdot.org/article.pl?sid=02/02/27/0115214&amp;mode=thread&amp;tid=172">this
+one</a> on Slashdot. The book has a <a
+href="http://www.buildinglinuxvpns.net/">web site</a>.</p>
+<hr>
+<a name="RFCs">Pete Loshin <cite>Big Book of IPsec RFCs</cite><br>
+Morgan Kaufmann 2000 ISBN: 0-12-455839-9</a>
+<hr>
+<a name="crypto">Steven Levy <cite>Crypto: How the Code Rebels Beat the
+Government -- Saving Privacy in the Digital Age</cite></a><br>
+Penguin 2001, ISBN 0-670--85950-8
+
+<p><strong>Highly recommended</strong>. A fine history of recent (about
+1970-2000) developments in the field, and the related political
+controversies. FreeS/WAN project founder and leader John Gilmore appears
+several times.</p>
+
+<p>The book does not cover IPsec or FreeS/WAN, but this project is very much
+another battle in the same war. See our discussion of the <a
+href="politics.html">politics</a>.</p>
+<hr>
+<a name="GTR">Matyas, Anderson et al.</a> <cite>The Global Trust
+Register</cite><br>
+Northgate Consultants Ltd 1998 ISBN: 0953239705<br>
+hard cover edition MIT Press 1999 ISBN 0262511053
+
+<p>From<a href="http://www.cl.cam.ac.uk/Research/Security/Trust-Register">
+their web page:</a></p>
+
+<blockquote>
+ This book is a register of the fingerprints of the world's most important
+ public keys; it implements a top-level certification authority (CA) using
+ paper and ink rather than in an electronic system.</blockquote>
+<hr>
+<a name="handbook">Menezies, van Oorschot and Vanstone <cite>Handbook of
+Applied Cryptography</cite></a><br>
+CRC Press 1997<br>
+ISBN 0-8493-8523-7
+
+<p>An excellent reference. Read <a href="#schneier">Schneier</a> before
+tackling this.</p>
+<hr>
+Michael Padlipsky <cite>Elements of Networking Style</cite><br>
+Prentice-Hall 1985 ISBN 0-13-268111-0 or 0-13-268129-3
+
+<p>Probably <strong>the funniest technical book ever written</strong>, this
+is a vicious but well-reasoned attack on the OSI "seven layer model" and all
+that went with it. Several chapters of it are also available as RFCs 871 to
+875.</p>
+<hr>
+<a name="matrix">John S. Quarterman</a> <cite>The Matrix: Computer Networks
+and Conferencing Systems Worldwide</cite><br>
+Digital Press 1990 ISBN 155558-033-5<br>
+Prentice-Hall ISBN 0-13-565607-9
+
+<p>The best general treatment of computer-mediated communication we have
+seen. It naturally has much to say about the Internet, but also covers UUCP,
+Fidonet and so on.</p>
+<hr>
+<a name="ranch">David Ranch</a> <cite>Securing Linux Step by Step</cite><br>
+SANS Institute, 1999
+
+<p><a href="http://www.sans.org/">SANS</a> is a respected organisation, this
+guide is part of a well-known series, and Ranch has previously written the
+useful <a
+href=" http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos">Trinity
+OS</a> guide to securing Linux, so my guess would be this is a pretty good
+book. I haven't read it yet, so I'm not certain. It can be ordered online
+from <a href="http://www.sans.org/">SANS</a>.</p>
+
+<p>Note (Mar 1, 2002): a new edition with different editors in the works.
+Expect it this year.</p>
+<hr>
+<a name="schneier">Bruce Schneier</a> <cite>Applied Cryptography, Second
+Edition</cite><br>
+John Wiley &amp; Sons, 1996<br>
+ISBN 0-471-12845-7 hardcover<br>
+ISBN 0-471-11709-9 paperback
+
+<p>A standard reference on computer cryptography. For more recent essays, see
+the <a href="http://www.counterpane.com/">author's company's web site</a>.</p>
+<hr>
+<a name="secrets">Bruce Schneier</a><cite> Secrets and Lies</cite><br>
+Wiley 2000, ISBN 0-471-25311-1
+
+<p>An interesting discussion of security and privacy issues, written with
+more of an "executive overview" approach rather than a narrow focus on the
+technical issues. <strong>Highly recommended</strong>.</p>
+
+<p>This is worth reading even if you already understand security issues, or
+think you do. To go deeper, follow it with Anderson's <a
+href="#anderson">Security Engineering</a>.</p>
+<hr>
+<a name="VPNbook">Scott, Wolfe and Irwin <cite>Virtual Private
+Networks</cite></a><br>
+2nd edition, O'Reilly 1999 ISBN: 1-56592-529-7
+
+<p>This is the only O'Reilly book, out of a dozen I own, that I'm
+disappointed with. It deals mainly with building VPNs with various
+proprietary tools -- <a href="glossary.html#PPTP">PPTP</a>, <a
+href="glossary.html#SSH">SSH</a>, Cisco PIX, ... -- and touches only lightly
+on IPsec-based approaches.</p>
+
+<p>That said, it appears to deal competently with what it does cover and it
+has readable explanations of many basic VPN and security concepts. It may be
+exactly what some readers require, even if I find the emphasis
+unfortunate.</p>
+<hr>
+<a name="LASG">Kurt Seifried <cite>Linux Administrator's Security
+Guide</cite></a>
+
+<p>Available online from <a
+href="http://www.securityportal.com/lasg/">Security Portal</a>. It has fairly
+extensive coverage of IPsec.</p>
+<hr>
+<a name="Smith">Richard E Smith <cite>Internet Cryptography</cite><br>
+</a>ISBN 0-201-92480-3, Addison Wesley, 1997
+
+<p>See the book's <a
+href="http://www.visi.com/crypto/inet-crypto/index.html">home page</a></p>
+<hr>
+<a name="neal">Neal Stephenson <cite>Cryptonomicon</cite></a><br>
+Hardcover ISBN -380-97346-4, Avon, 1999.
+
+<p>A novel in which cryptography and the net figure prominently.
+<strong>Highly recommended</strong>: I liked it enough I immediately went out
+and bought all the author's other books.</p>
+
+<p>There is also a paperback edition. Sequels are expected.</p>
+<hr>
+<a name="stevens">Stevens and Wright</a> <cite>TCP/IP Illustrated</cite><br>
+Addison-Wesley
+<ul>
+ <li>Vol. I: The Protocols 1994 ISBN:0-201-63346-9</li>
+ <li>Vol. II: The Implementation 1995 ISBN:0-201-63354-X</li>
+ <li>Vol. III: TCP for Transactions, HTTP, NNTP, and the UNIX Domain
+ Protocols 1996 ISBN: 0-201-63495-3</li>
+</ul>
+
+<p>If you need to deal with the details of the network protocols, read either
+this series or the <a href="#comer">Comer</a> series before you start reading
+the RFCs.</p>
+<hr>
+<a name="Rubini">Rubini</a> <cite>Linux Device Drivers</cite><br>
+O'Reilly &amp; Associates, Inc. 1998 ISBN 1-56592-292-1
+<hr>
+<a name="Zeigler">Robert Zeigler</a> <cite>Linux Firewalls</cite><br>
+Newriders Publishing, 2000 ISBN 0-7537-0900-9
+
+<p>A good book, with detailed coverage of ipchains(8) firewalls and of many
+related issues.</p>
+</body>
+</html>
diff --git a/doc/src/buildtools.html b/doc/src/buildtools.html
new file mode 100644
index 000000000..c8cfa1fc8
--- /dev/null
+++ b/doc/src/buildtools.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+ <HEAD>
+ <TITLE>Tools used to build FreeSWAN releases (08-Mar-2002)</TITLE>
+ <!-- Created by: Michael Richardson, 08-Mar-2002 -->
+
+
+ </HEAD>
+ <BODY>
+ <H1>Tools used to build FreeSWAN releases</H1>
+
+<H2>man2html</H2>
+
+<P>
+If you are not running RedHat, you will need man2html. This is part of the
+"man" RPM on RedHat, whose sources can be found at <A HREF="ftp://ftp.win.tue.nl/pub/linux-local/utils/man/">ftp://ftp.win.tue.nl/pub/linux-local/utils/man/</A>.
+</P>
+
+<P>
+Note that the Debian package <A HREF="http://packages.debian.org/man2html">man2html</A>
+and the one listed on Freshmeat at
+<A HREF="http://freshmeat.net/projects/man2html/">man2html</A> will
+not work.
+</P>
+
+ </BODY>
+</HTML> \ No newline at end of file
diff --git a/doc/src/compat.html b/doc/src/compat.html
new file mode 100644
index 000000000..a8e1455bf
--- /dev/null
+++ b/doc/src/compat.html
@@ -0,0 +1,795 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN compatibility guide</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, compatibility">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: compat.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="compat">Linux FreeS/WAN Compatibility Guide</a></h1>
+
+<p>Much of this document is quoted directly from the Linux FreeS/WAN <a
+href="mail.html">mailing list</a>. Thanks very much to the community of
+testers, patchers and commenters there, especially the ones quoted below but
+also various contributors we haven't quoted.</p>
+
+<h2><a name="spec">Implemented parts of the IPsec Specification</a></h2>
+
+<p>In general, do not expect Linux FreeS/WAN to do everything yet. This is a
+work-in-progress and some parts of the IPsec specification are not yet
+implemented.</p>
+
+<h3><a name="in">In Linux FreeS/WAN</a></h3>
+
+<p>Things we do, as of version 1.96:</p>
+<ul>
+ <li>key management methods
+ <dl>
+ <dt>manually keyed</dt>
+ <dd>using keys stored in /etc/ipsec.conf</dd>
+ <dt>automatically keyed</dt>
+ <dd>Automatically negotiating session keys as required. All
+ connections are automatically re-keyed periodically. The <a
+ href="glossary.html#Pluto">Pluto</a> daemon implements this using
+ the <a href="glossary.html#IKE">IKE</a> protocol.</dd>
+ </dl>
+ </li>
+ <li>Methods of authenticating gateways for IKE
+ <dl>
+ <dt>shared secrets</dt>
+ <dd>stored in <a
+ href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</a></dd>
+ <dt><a href="glossary.html#RSA">RSA</a> signatures</dt>
+ <dd>For details, see <a
+ href="manpage.d/ipsec_pluto.8.html">pluto(8)</a>.</dd>
+ <dt>looking up RSA authentication keys from <a
+ href="glossary.html#DNS">DNS</a>.</dt>
+ <dd>Note that this technique cannot be fully secure until <a
+ href="glossary.html#SDNS">secure DNS</a> is widely deployed.</dd>
+ </dl>
+ </li>
+ <li>groups for <a href="glossary.html#DH">Diffie-Hellman</a> key negotiation
+ <dl>
+ <dt>group 2, modp 1024-bit</dt>
+ <dt>group 5, modp 1536-bit</dt>
+ <dd>We implement these two groups.
+ <p>In negotiating a keying connection (ISAKMP SA, Phase 1) we
+ propose both groups when we are the initiator, and accept either
+ when a peer proposes them. Once the keying connection is made, we
+ propose only the alternative agreed there for data connections
+ (IPsec SA's, Phase 2) negotiated over that keying connection.</p>
+ </dd>
+ </dl>
+ </li>
+ <li>encryption transforms
+ <dl>
+ <dt><a href="glossary.html#DES">DES</a></dt>
+ <dd>DES is in the source code since it is needed to implement 3DES,
+ but single DES is not made available to users because <a
+ href="politics.html#desnotsecure">DES is insecure</a>.</dd>
+ <dt><a href="glossary.html#3DES">Triple DES</a></dt>
+ <dd>implemented, and used as the default encryption in Linux
+ FreeS/WAN.</dd>
+ </dl>
+ </li>
+ <li>authentication transforms
+ <dl>
+ <dt><a href="glossary.html#HMAC">HMAC</a> using <a
+ href="glossary.html#MD5">MD5</a></dt>
+ <dd>implemented, may be used in IKE or by by AH or ESP
+ transforms.</dd>
+ <dt><a href="glossary.html#HMAC">HMAC</a> using <a
+ href="glossary.html#SHA">SHA</a></dt>
+ <dd>implemented, may be used in IKE or by AH or ESP transforms.</dd>
+ </dl>
+ <p>In negotiations, we propose both of these and accept either.</p>
+ </li>
+ <li>compression transforms
+ <dl>
+ <dt>IPComp</dt>
+ <dd>IPComp as described in RFC 2393 was added for FreeS/WAN 1.6. Note
+ that Pluto becomes confused if you ask it to do IPComp when the
+ kernel cannot.</dd>
+ </dl>
+ </li>
+</ul>
+
+<p>All combinations of implemented transforms are supported. Note that some
+form of packet-level <strong>authentication is required whenever encryption
+is used</strong>. Without it, the encryption will not be secure.</p>
+
+<h3><a name="dropped">Deliberately omitted</a></h3>
+We do not implement everything in the RFCs because some of those things are
+insecure. See our discussions of avoiding <a href="politics.html#weak">bogus
+security</a>.
+
+<p>Things we deliberately omit which are required in the RFCs are:</p>
+<ul>
+ <li>null encryption (to use ESP as an authentication-only service)</li>
+ <li>single DES</li>
+ <li>DH group 1, a 768-bit modp group</li>
+</ul>
+
+<p>Since these are the only encryption algorithms and DH group the RFCs
+require, it is possible in theory to have a standards-conforming
+implementation which will not interpoperate with FreeS/WAN. Such an
+implementation would be inherently insecure, so we do not consider this a
+problem.</p>
+
+<p>Anyway, most implementations sensibly include more secure options as well,
+so dropping null encryption, single DES and Group 1 does not greatly hinder
+interoperation in practice.</p>
+
+<p>We also do not implement some optional features allowed by the RFCs:</p>
+<ul>
+ <li>aggressive mode for negotiation of the keying channel or ISAKMP SA.
+ This mode is a little faster than main mode, but exposes more information
+ to an eavesdropper.</li>
+</ul>
+
+<p>In theory, this should cause no interoperation problems since all
+implementations are required to support the more secure main mode, whether or
+not they also allow aggressive mode.</p>
+
+<p>In practice, it does sometimes produce problems with implementations such
+as Windows 2000 where aggressive mode is the default. Typically, these are
+easily solved with a configuration change that overrides that default.</p>
+
+<h3><a name="not">Not (yet) in Linux FreeS/WAN</a></h3>
+
+<p>Things we don't yet do, as of version 1.96:</p>
+<ul>
+ <li>key management methods
+ <ul>
+ <li>authenticate key negotiations via local <a
+ href="glossary.html#PKI">PKI</a> server, but see links to user <a
+ href="web.html#patch">patches</a></li>
+ <li>authenticate key negotiations via <a
+ href="glossary.html#SDNS">secure DNS</a></li>
+ <li>unauthenticated key management, using <a
+ href="glossary.html#DH">Diffie-Hellman</a> key agreement protocol
+ without authentication. Arguably, this would be worth doing since it
+ is secure against all passive attacks. On the other hand, it is
+ vulnerable to an active <a
+ href="glossary.html#middle">man-in-the-middle attack</a>.</li>
+ </ul>
+ </li>
+ <li>encryption transforms
+ <p>Currently <a href="glossary.html#3DES">Triple DES</a> is the only
+ encryption method Pluto will negotiate.</p>
+ <p>No additional encryption transforms are implemented, though the RFCs
+ allow them and some other IPsec implementations support various of them.
+ We are not eager to add more. See this <a
+ href="faq.html#other.cipher">FAQ question</a>.</p>
+ <p><a href="glossary.html#AES">AES</a>, the successor to the DES
+ standard, is an excellent candidate for inclusion in FreeS/WAN, see links
+ to user <a href="web.html#patch">patches</a>.</p>
+ </li>
+ <li>authentication transforms
+ <p>No optional additional authentication transforms are currently
+ implemented. Likely <a href="glossary.html#SHA-256">SHA-256, SHA-384 and
+ SHA-512</a> will be added when AES is.</p>
+ </li>
+ <li>Policy checking on decrypted packets
+ <p>To fully comply with the RFCs, it is not enough just to accept only
+ packets which survive any firewall rules in place to limit what IPsec
+ packets get in, and then pass KLIPS authentication. That is what
+ FreeS/WAN currently does.</p>
+ <p>We should also apply additional tests, for example ensuring that all
+ packets emerging from a particular tunnel have source and destination
+ addresses that fall within the subnets defined for that tunnel, and that
+ packets with those addresses that did not emerge from the appropriate
+ tunnel are disallowed.</p>
+ <p>This will be done as part of a KLIPS rewrite. See these <a
+ href="intro.html#applied">links</a> and the <a href="mail.html">design
+ mailing list</a> for discussion.</p>
+ </li>
+</ul>
+
+<h2><a name="pfkey">Our PF-Key implementation</a></h2>
+
+<p>We use PF-key Version Two for communication between the KLIPS kernel code
+and the Pluto Daemon. PF-Key v2 is defined by <a
+href="http://www.normos.org/ietf/rfc/rfc2367.txt">RFC 2367</a>.</p>
+
+<p>The "PF" stands for Protocol Family. PF-Inet defines a kernel/userspace
+interface for the TCP/IP Internet protocols (TCP/IP), and other members of
+the PF series handle Netware, Appletalk, etc. PF-Key is just a PF for
+key-related matters.</p>
+
+<h3><a name="pfk.port">PF-Key portability</a></h3>
+
+<p>PF-Key came out of Berkeley Unix work and is used in the various BSD IPsec
+implementations, and in Solaris. This means there is some hope of porting our
+Pluto(8) to one of the BSD distributions, or of running their photurisd(8) on
+Linux if you prefer <a href="glossary.html#photuris">Photuris</a> key
+management over IKE.</p>
+
+<p>It is, however, more complex than that. The PK-Key RFC deliberately deals
+only with keying, not policy management. The three PF-Key implementations we
+have looked at -- ours, OpenBSD and KAME -- all have extensions to deal with
+security policy, and the extensions are different. There have been
+discussions aimed at sorting out the differences, perhaps for a version three
+PF-Key spec. All players are in favour of this, but everyone involved is busy
+and it is not clear whether or when these discussions might bear fruit.</p>
+
+<h2><a name="otherk">Kernels other than the latest 2.2.x and 2.4.y</a></h2>
+
+<p>We develop and test on Redhat Linux using the most recent kernel in the
+2.2 and 2.4 series. In general, we recommend you use the latest kernel in one
+of those series. Complications and caveats are discussed below.</p>
+
+<h3><a name="kernel.2.0">2.0.x kernels</a></h3>
+
+<p>Consider upgrading to the 2.2 kernel series. If you want to stay with the
+2.0 series, then we strongly recommend 2.0.39. Some useful security patches
+were added in 2.0.38.</p>
+
+<p>Various versions of the code have run at various times on most 2.0.xx
+kernels, but the current version is only lightly tested on 2.0.39, and not at
+all on older kernels.</p>
+
+<p>Some of our patches for older kernels are shipped in 2.0.37 and later, so
+they are no longer provided in FreeS/WAN. This means recent versions of
+FreeS/WAN will probably not compile on anything earlier than 2.0.37.</p>
+
+<h3><a name="kernel.production">2.2 and 2.4 kernels</a></h3>
+<dl>
+ <dt>FreeS/WAN 1.0</dt>
+ <dd>ran only on 2.0 kernels</dd>
+ <dt>FreeS/WAN 1.1 to 1.8</dt>
+ <dd>ran on 2.0 or 2.2 kernels<br>
+ ran on some development kernels, 2.3 or 2.4-test</dd>
+ <dt>FreeS/WAN 1.9 to 1.96</dt>
+ <dd>runs on 2.0, 2.2 or 2.4 kernels</dd>
+</dl>
+
+<p>In general, <strong>we suggest the latest 2.2 kernel or 2.4 for production
+use</strong>.</p>
+
+<p>Of course no release can be guaranteed to run on kernels more recent than
+it is, so quite often there will be no stable FreeS/WAN for the absolute
+latest kernel. See the <a href="faq.html#k.versions">FAQ</a> for
+discussion.</p>
+
+<h2><a name="otherdist">Intel Linux distributions other than Redhat</a></h2>
+
+<p>We develop and test on Redhat 6.1 for 2.2 kernels, and on Redhat 7.1 or
+7.2 for 2.4, so minor changes may be required for other distributions.</p>
+
+<h3><a name="rh7">Redhat 7.0</a></h3>
+
+<p>There are some problems with FreeS/WAN on Redhat 7.0. They are soluble,
+but we recommend you upgrade to a later Redhat instead..</p>
+
+<p>Redhat 7 ships with two compilers.</p>
+<ul>
+ <li>Their <var>gcc</var> is version 2.96. Various people, including the GNU
+ compiler developers and Linus, have said fairly emphatically that using
+ this was a mistake. 2.96 is a development version, not intended for
+ production use. In particular, it will not compile a Linux kernel.</li>
+ <li>Redhat therefore also ship a separate compiler, which they call
+ <var>kgcc</var>, for compiling kernels.</li>
+</ul>
+
+<p>Kernel Makefiles have <var>gcc</var> as a default, and must be adjusted to
+use <var>kgcc</var> before a kernel will compile on 7.0. This mailing list
+message gives details:</p>
+<pre>Subject: Re: AW: Installing IPsec on Redhat 7.0
+ Date: Thu, 1 Feb 2001 14:32:52 -0200 (BRST)
+ From: Mads Rasmussen &lt;mads@cit.com.br&gt;
+
+&gt; From www.redhat.com/support/docs/gotchas/7.0/gotchas-7-6.html#ss6.1
+
+cd to /usr/src/linux and open the Makefile in your favorite editor. You
+will need to look for a line similar to this:
+
+CC = $(CROSS_COMPILE)gcc -D__KERNEL__ -I$(HPATH)
+
+This line specifies which C compiler to use to build the kernel. It should
+be changed to:
+
+CC = $(CROSS_COMPILE)kgcc -D__KERNEL__ -I$(HPATH)
+
+for Red Hat Linux 7. The kgcc compiler is egcs 2.91.66. From here you can
+proceed with the typical compiling steps.</pre>
+
+<p>Check the <a href="mail.html">mailing list</a> archive for more recent
+news.</p>
+
+<h3><a name="suse">SuSE Linux</a></h3>
+
+<p>SuSE 6.3 and later versions, at least in Europe, ship with FreeS/WAN
+included.</p>
+
+<P>FreeS/WAN packages distributed for SuSE 7.0-7.2 were somehow
+miscompiled. You can find fixed packages on
+<A HREF="http://www.suse.de/~garloff/linux/FreeSWAN">
+Kurt Garloff's page</A>.</P>
+
+<p>Here are some notes for an earlier SuSE version.</p>
+
+<h4>SuSE Linux 5.3</h4>
+<pre>Date: Mon, 30 Nov 1998
+From: Peter Onion &lt;ponion@srd.bt.co.uk&gt;
+
+... I got Saturdays snapshot working between my two SUSE5.3 machines at home.
+
+The mods to the install process are quite simple. From memory and looking at
+the files on the SUSE53 machine here at work....
+
+And extra link in each of the /etc/init.d/rc?.d directories called K35ipsec
+which SUSE use to shut a service down.
+
+A few mods in /etc/init.d/ipsec to cope with the different places that SUSE
+put config info, and remove the inculsion of /etc/rc.d/init.d/functions and .
+/etc/sysconfig/network as they don't exists and 1st one isn't needed anyway.
+
+insert ". /etc/rc.config" to pick up the SUSE config info and use
+
+ if test -n "$NETCONFIG" -a "$NETCONFIG" != "YAST_ASK" ; then
+
+to replace
+
+ [ ${NETWORKING} = "no" ] &amp;&amp; exit 0
+
+Create /etc/sysconfig as SUSE doesn't have one.
+
+I think that was all (but I prob forgot something)....</pre>
+
+<p>You may also need to fiddle initialisation scripts to ensure that
+<var>/var/run/pluto.pid</var> is removed when rebooting. If this file is
+present, Pluto does not come up correctly.</p>
+
+<h3><a name="slack">Slackware</a></h3>
+<pre>Subject: Re: linux-IPsec: Slackware distribution
+ Date: Thu, 15 Apr 1999 12:07:01 -0700
+ From: Evan Brewer &lt;dmessiah@silcon.com&gt;
+
+&gt; Very shortly, I will be needing to install IPsec on at least gateways that
+&gt; are running Slackware. . . .
+
+The only trick to getting it up is that on the slackware dist there is no
+init.d directory in /etc/rc.d .. so create one. Then, what I do is take the
+IPsec startup script which normally gets put into the init.d directory, and
+put it in /etc/rc.d and name ir rc.ipsec .. then I symlink it to the file
+in init.d. The only file in the dist you need to really edit is the
+utils/Makefile, setup4:
+
+Everything else should be just fine.</pre>
+
+<p>A year or so later:</p>
+<pre>Subject: Re: HTML Docs- Need some cleanup?
+ Date: Mon, 8 Jan 2001
+ From: Jody McIntyre &lt;jodym@oeone.com&gt;
+
+I have successfully installed FreeS/WAN on several Slackware 7.1 machines.
+FreeS/WAN installed its rc.ipsec file in /etc/rc.d. I had to manually call
+this script from rc.inet2. This seems to be an easier method than Evan
+Brewer's.</pre>
+
+<h3><a name="deb">Debian</a></h3>
+
+<p>A recent (Nov 2001) mailing list points to a <a
+href="http://www.thing.dyndns.org/debian/vpn.htm">web page</a> on setting up
+several types of tunnel, including IPsec, on Debian.</p>
+
+<p>Some older information:</p>
+<pre>Subject: FreeS/WAN 1.0 on Debian 2.1
+ Date: Tue, 20 Apr 1999
+ From: Tim Miller &lt;cerebus+counterpane@haybaler.sackheads.org&gt;
+
+ Compiled and installed without error on a Debian 2.1 system
+with kernel-source-2.0.36 after pointing RCDIR in utils/Makefile to
+/etc/init.d.
+
+ /var/lock/subsys/ doesn't exist on Debian boxen, needs to be
+created; not a fatal error.
+
+ Finally, IPsec scripts appear to be dependant on GNU awk
+(gawk); the default Debian awk (mawk-1.3.3-2) had fatal difficulties.
+With gawk installed and /etc/alternatives/awk linked to /usr/bin/gawk
+operation appears flawless.</pre>
+
+<p>The scripts in question have been modified since this was posted. Awk
+versions should no longer be a problem.</p>
+
+<h3><a name="caldera">Caldera</a></h3>
+<pre>Subject: Re: HTML Docs- Need some cleanup?
+ Date: Mon, 08 Jan 2001
+ From: Andy Bradford &lt;andyb@calderasystems.com&gt;
+
+On Sun, 07 Jan 2001 22:59:05 EST, Sandy Harris wrote:
+
+&gt; Intel Linux distributions other than Redhat 5.x and 6.x
+&gt; Redhat 7.0
+&gt; SuSE Linux
+&gt; SuSE Linux 5.3
+&gt; Slackware
+&gt; Debian
+
+Can you please include Caldera in this list? I have tested it since
+FreeS/Wan 1.1 and it works great with our systems---provided one
+follows the FreeS/Wan documentation. :-)
+
+Thank you,
+Andy</pre>
+
+<h2><a name="CPUs">CPUs other than Intel</a></h2>
+
+<p>FreeS/WAN has been run sucessfully on a number of different CPU
+architectures. If you have tried it on one not listed here, please post to
+the <a href="mail.html">mailing list</a>.</p>
+
+<h3><a name=" strongarm">Corel Netwinder (StrongARM CPU)</a></h3>
+<pre>Subject: linux-ipsec: Netwinder diffs
+Date: Wed, 06 Jan 1999
+From: rhatfield@plaintree.com
+
+I had a mistake in my IPsec-auto, so I got things working this morning.
+
+Following are the diffs for my changes. Probably not the best and cleanest way
+of doing it, but it works. . . . </pre>
+
+<p>These diffs are in the 0.92 and later distributions, so these should work
+out-of-the-box on Netwinder.</p>
+
+<h3><a name="yellowdog">Yellow Dog Linux on Power PC</a></h3>
+<pre>Subject: Compiling FreeS/WAN 1.1 on YellowDog Linux (PPC)
+ Date: 11 Dec 1999
+ From: Darron Froese &lt;darron@fudgehead.com&gt;
+
+I'm summarizing here for the record - because it's taken me many hours to do
+this (multiple times) and because I want to see IPsec on more linuxes than
+just x86.
+
+Also, I can't remember if I actually did summarize it before... ;-) I'm
+working too many late hours.
+
+That said - here goes.
+
+1. Get your linux kernel and unpack into /usr/src/linux/ - I used 2.2.13.
+&lt;http://www.kernel.org/pub/linux/kernel/v2.2/linux-2.2.13.tar.bz2&gt;
+
+2. Get FreeS/WAN and unpack into /usr/src/freeswan-1.1
+&lt;ftp://ftp.xs4all.nl/pub/crypto/freeswan/freeswan-1.1.tar.gz&gt;
+
+3. Get the gmp src rpm from here:
+&lt;ftp://ftp.yellowdoglinux.com//pub/yellowdog/champion-1.1/SRPMS/SRPMS/gmp-2.0.2-9a.src.rpm&gt;
+
+4. Su to root and do this: rpm --rebuild gmp-2.0.2-9a.src.rpm
+
+You will see a lot of text fly by and when you start to see the rpm
+recompiling like this:
+
+Executing: %build
++ umask 022
++ cd /usr/src/redhat/BUILD
++ cd gmp-2.0.2
++ libtoolize --copy --force
+Remember to add `AM_PROG_LIBTOOL' to `configure.in'.
+You should add the contents of `/usr/share/aclocal/libtool.m4' to
+`aclocal.m4'.
++ CFLAGS=-O2 -fsigned-char
++ ./configure --prefix=/usr
+
+Hit Control-C to stop the rebuild. NOTE: We're doing this because for some
+reason the gmp source provided with FreeS/WAN 1.1 won't build properly on
+ydl.
+
+cd /usr/src/redhat/BUILD/
+cp -ar gmp-2.0.2 /usr/src/freeswan-1.1/
+cd /usr/src/freeswan-1.1/
+rm -rf gmp
+mv gmp-2.0.2 gmp
+
+5. Open the freeswan Makefile and change the line that says:
+KERNEL=$(b)zimage (or something like that) to
+KERNEL=vmlinux
+
+6. cd ../linux/
+
+7. make menuconfig
+Select an option or two and then exit - saving your changes.
+
+8. cd ../freeswan-1.1/ ; make menugo
+
+That will start the whole process going - once that's finished compiling,
+you have to install your new kernel and reboot.
+
+That should build FreeS/WAN on ydl (I tried it on 1.1).</pre>
+And a later message on the same topic:
+<pre>Subject: Re: FreeS/WAN, PGPnet and E-mail
+ Date: Sat, 22 Jan 2000
+ From: Darron Froese &lt;darron@fudgehead.com&gt;
+
+on 1/22/00 6:47 PM, Philip Trauring at philip@trauring.com wrote:
+
+&gt; I have a PowerMac G3 ...
+
+The PowerMac G3 can run YDL 1.1 just fine. It should also be able to run
+FreeS/WAN 1.2patch1 with a couple minor modifications:
+
+1. In the Makefile it specifies a bzimage for the kernel compile - you have
+to change that to vmlinux for the PPC.
+
+2. The gmp source that comes with FreeS/WAN (for whatever reason) fails to
+compile. I have gotten around this by getting the gmp src rpm from here:
+
+ftp://ftp.yellowdoglinux.com//pub/yellowdog/champion-1.1/SRPMS/SRPMS/gmp-2.0.2-9a.src.rpm
+
+If you rip the source out of there - and place it where the gmp source
+resides it will compile just fine.</pre>
+
+<p>FreeS/WAN no longer includes GMP source.</p>
+
+<h3><a name="mklinux">Mklinux</a></h3>
+
+<p>One user reports success on the Mach-based
+<strong>m</strong>icro<strong>k</strong>ernel Linux.</p>
+<pre>Subject: Smiles on sparc and ppc
+ Date: Fri, 10 Mar 2000
+ From: Jake Hill &lt;jah@alien.bt.co.uk&gt;
+
+You may or may not be interested to know that I have successfully built
+FreeS/WAN on a number of non intel alpha architectures; namely on ppc
+and sparc and also on osfmach3/ppc (MkLinux). I can report that it just
+works, mostly, with few changes.</pre>
+
+<h3><a name="alpha">Alpha 64-bit processors</a></h3>
+<pre>Subject: IT WORKS (again) between intel &amp; alpha :-)))))
+ Date: Fri, 29 Jan 1999
+ From: Peter Onion &lt;ponion@srd.bt.co.uk&gt;
+
+Well I'm happy to report that I've got an IPsec connection between by intel &amp; alpha machines again :-))
+
+If you look back on this list to 7th of December I wrote...
+
+-On 07-Dec-98 Peter Onion wrote:
+-&gt;
+-&gt; I've about had enuf of wandering around inside the kernel trying to find out
+-&gt; just what is corrupting outgoing packets...
+-
+-Its 7:30 in the evening .....
+-
+-I FIXED IT :-))))))))))))))))))))))))))))))))
+-
+-It was my own fault :-((((((((((((((((((
+-
+-If you ask me very nicly I'll tell you where I was a little too over keen to
+-change unsigned long int __u32 :-) OPSE ...
+-
+-So tomorrow it will full steam ahead to produce a set of diffs/patches against
+-0.91
+-
+-Peter Onion.</pre>
+
+<p>In general (there have been some glitches), FreeS/WAN has been running on
+Alphas since then.</p>
+
+<h3><a name="SPARC">Sun SPARC processors</a></h3>
+
+<p>Several users have reported success with FreeS/WAN on SPARC Linux. Here is
+one mailing list message:</p>
+<pre>Subject: Smiles on sparc and ppc
+ Date: Fri, 10 Mar 2000
+ From: Jake Hill &lt;jah@alien.bt.co.uk&gt;
+
+You may or may not be interested to know that I have successfully built
+FreeS/WAN on a number of non intel alpha architectures; namely on ppc
+and sparc and also on osfmach3/ppc (MkLinux). I can report that it just
+works, mostly, with few changes.
+
+I have a question, before I make up some patches. I need to hack
+gmp/mpn/powerpc32/*.s to build them. Is this ok? The changes are
+trivial, but could I also use a different version of gmp? Is it vanilla
+here?
+
+I guess my only real headache is from ipchains, which appears to stop
+running when IPsec has been started for a while. This is with 2.2.14 on
+sparc.</pre>
+
+<p>This message, from a different mailing list, may be relevant for anyone
+working with FreeS/WAN on Suns:</p>
+<pre>Subject: UltraSPARC DES assembler
+ Date: Thu, 13 Apr 2000
+ From: svolaf@inet.uni2.dk (Svend Olaf Mikkelsen)
+ To: coderpunks@toad.com
+
+An UltraSPARC assembler version of the LibDES/SSLeay/OpenSSL des_enc.c
+file is available at http://inet.uni2.dk/~svolaf/des.htm.
+
+This brings DES on UltraSPARC from slower than Pentium at the same
+clock speed to significantly faster.</pre>
+
+<h3><a name="mips">MIPS processors</a></h3>
+
+<p>We know FreeS/WAN runs on at least some MIPS processors because <a
+href="http://www.lasat.com">Lasat</a> manufacture an IPsec box based on an
+embedded MIPS running Linux with FreeS/WAN. We have no details.</p>
+
+<h3><a name="crusoe">Transmeta Crusoe</a></h3>
+
+<p>The Merilus <a
+href="http://www.merilus.com/products/fc/index.shtml">Firecard</a>, a Linux
+firewall on a PCI card, is based on a Crusoe processor and supports
+FreeS/WAN.</p>
+
+<h3><a name="coldfire">Motorola Coldfire</a></h3>
+<pre>Subject: Re: Crypto hardware support
+ Date: Mon, 03 Jul 2000
+ From: Dan DeVault &lt;devault@tampabay.rr.com&gt;
+
+.... I have been running
+uClinux with FreeS/WAN 1.4 on a system built by Moreton Bay (
+http://www.moretonbay.com ) and it was using a Coldfire processor
+and was able to do the Triple DES encryption at just about
+1 mbit / sec rate....... they put a Hi/Fn 7901 hardware encryption
+chip on their board and now their system does over 25 mbit of 3DES
+encryption........ pretty significant increase if you ask me.</pre>
+
+<h2><a name="multiprocessor">Multiprocessor machines</a></h2>
+
+<p>FreeS/WAN is designed to work on SMP (symmetric multi-processing) Linux
+machines and is regularly tested on dual processor x86 machines.</p>
+
+<p>We do not know of any testing on multi-processor machines with other CPU
+architectures or with more than two CPUs. Anyone who does test this, please
+report results to the <a href="mail.html">mailing list</a>.</p>
+
+<p>The current design does not make particularly efficient use of
+multiprocessor machines; some of the kernel work is single-threaded.</p>
+
+<h2><a name="hardware">Support for crypto hardware</a></h2>
+
+<p>Supporting hardware cryptography accelerators has not been a high priority
+for the development team because it raises a number of fairly complex
+issues:</p>
+<ul>
+ <li>Can you trust the hardware? If it is not Open Source, how do you audit
+ its security? Even if it is, how do you check that the design has no
+ concealed traps?</li>
+ <li>If an interface is added for such hardware, can that interface be
+ subverted or misused?</li>
+ <li>Is hardware acceleration actually a performance win? It clearly is in
+ many cases, but on a fast machine it might be better to use the CPU for
+ the encryption than to pay the overheads of moving data to and from a
+ crypto board.</li>
+ <li>the current KLIPS code does not provide a clean interface for hardware
+ accelerators</li>
+</ul>
+
+<p>That said, we have a <a href="#coldfire">report</a> of FreeS/WAN working
+with one crypto accelerator and some work is going on to modify KLIPS to
+create a clean generic interface to such products. See this <a
+href="http://www.jukie.net/~bart/linux-ipsec/">web page</a> for some of the
+design discussion.</p>
+
+<p>More recently, a patch to support some hardware accelerators has been
+posted:</p>
+<pre>Subject: [Design] [PATCH] H/W acceleration patch
+ Date: Tue, 18 Sep 2001
+ From: "Martin Gadbois" &lt;martin.gadbois@colubris.com&gt;
+
+Finally!!
+Here's a web site with H/W acceleration patch for FreeS/WAN 1.91, including
+S/W and Hifn 7901 crypto support.
+
+http://sources.colubris.com/
+
+Martin Gadbois</pre>
+
+<p>Hardware accelerators could take performance well beyond what FreeS/WAN
+can do in software (discussed <a href="performance.html">here</a>). Here is
+some discussion off the IETF IPsec list, October 2001:</p>
+<pre> ... Currently shipping chips deliver, 600 mbps throughput on a single
+ stream of 3DES IPsec traffic. There are also chips that use multiple
+ cores to do 2.4 gbps. We (Cavium) and others have announced even faster
+ chips. ... Mid 2002 versions will handle at line rate (OC48 and OC192)
+ IPsec and SSL/TLS traffic not only 3DES CBC but also AES and arc4.</pre>
+
+<p>The patches to date support chips that have been in production for some
+time, not the state-of-the-art latest-and-greatest devices described in that
+post. However, they may still outperform software and they almost certainly
+reduce CPU overhead.</p>
+
+<h2><a name="ipv6">IP version 6 (IPng)</a></h2>
+
+<p>The Internet currently runs on version four of the IP protocols. IPv4 is
+what is in the standard Linux IP stack, and what FreeS/WAN was built for. In
+IPv4, IPsec is an optional feature.</p>
+
+<p>The next version of the IP protocol suite is version six, usually
+abbreviated either as "IPv6" or as "IPng" for "IP: the next generation". For
+IPv6, IPsec is a required feature. Any machine doing IPv6 is required to
+support IPsec, much as any machine doing (any version of) IP is required to
+support ICMP.</p>
+
+<p>There is a Linux implementation of IPv6 in Linux kernels 2.2 and above.
+For details, see the <a
+href="http://www.cs-ipv6.lancs.ac.uk/ipv6/systems/linux/faq/">FAQ</a>. It
+does not yet support IPsec. The <a
+href="http://www.linux-ipv6.org/">USAGI</a> project are also working on IPv6
+for Linux.</p>
+
+<p>FreeS/WAN was originally built for the current standard, IPv4, but we are
+interested in seeing it work with IPv6. Some progress has been made, and a
+patched version with IPv6 support is <a
+href="http://www.ipv6.iabg.de/downloadframe/index.html">available</a>. For
+more recent information, check the <a href="mail.html">mailing list</a>.</p>
+
+<h3><a name="v6.back">IPv6 background</a></h3>
+
+<p>IPv6 has been specified by an IETF <a
+href="http://www.ietf.org/html.charters/ipngwg-charter.html">working
+group</a>. The group's page lists over 30 RFCs to date, and many Internet
+Drafts as well. The overview is <a
+href="http://www.ietf.org/rfc/rfc2460.txt">RFC 2460</a>. Major features
+include:</p>
+<ul>
+ <li>expansion of the address space from 32 to 128 bits,</li>
+ <li>changes to improve support for
+ <ul>
+ <li>mobile IP</li>
+ <li>automatic network configuration</li>
+ <li>quality of service routing</li>
+ <li>...</li>
+ </ul>
+ </li>
+ <li>improved security via IPsec</li>
+</ul>
+
+<p>A number of projects are working on IPv6 implementation. A prominent Open
+Source effort is <a href="http://www.kame.net/">KAME</a>, a collaboration
+among several large Japanese companies to implement IPv6 for Berkeley Unix.
+Other major players are also working on IPv6. For example, see pages at:</p>
+<ul>
+ <li><a
+ href="http://playground.sun.com/pub/ipng/html/ipng-main.html">Sun</a></li>
+ <li><a
+ href="http://www.cisco.com/warp/public/732/ipv6/index.html">Cisco</a></li>
+ <li><a
+ href="http://www.microsoft.com/windows2000/techinfo/howitworks/communications/networkbasics/IPv6.asp">Microsoft</a></li>
+</ul>
+
+<p>The <a href="http://www.6bone.net/">6bone</a> (IPv6 backbone) testbed
+network has been up for some time. There is an active <a
+href="http://www.ipv6.org/">IPv6 user group</a>.</p>
+
+<p>One of the design goals for IPv6 was that it must be possible to convert
+from v4 to v6 via a gradual transition process. Imagine the mess if there
+were a "flag day" after which the entire Internet used v6, and all software
+designed for v4 stopped working. Almost every computer on the planet would
+need major software changes! There would be huge costs to replace older
+equipment. Implementers would be worked to death before "the day", systems
+administrators and technical support would be completely swamped after it.
+The bugs in every implementation would all bite simultaneously. Large chunks
+of the net would almost certainly be down for substantial time periods.
+...</p>
+
+<p>Fortunately, the design avoids any "flag day". It is therefore a little
+tricky to tell how quickly IPv6 will take over. The transition has certainly
+begun. For examples, see announcements from <a
+href="http://www.mailbase.ac.uk/lists/internet2/2000-03/0016.html">NTT</a>
+and <a href="http://www.vnunet.com/News/1102383">Nokia</a>. However, it is
+not yet clear how quickly the process will gain momentum, or when it will be
+completed. Likely large parts of the Internet will remain with IPv4 for years
+to come.</p>
+</body>
+</html>
diff --git a/doc/src/config.html b/doc/src/config.html
new file mode 100644
index 000000000..b98e452db
--- /dev/null
+++ b/doc/src/config.html
@@ -0,0 +1,394 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN configuration</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, installation, quickstart">
+ <!--
+
+ Written by Claudia Schmeing for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: config.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+<BODY>
+<H1><A NAME="config">How to configure FreeS/WAN</A></H1>
+
+<P>This page will teach you how to configure a simple network-to-network
+link or a Road Warrior connection between two Linux FreeS/WAN boxes.
+</P>
+
+<P>See also these related documents:</P>
+<UL>
+<LI>our <A HREF="quickstart.html#quickstart">quickstart</A> guide
+to <A HREF="glossary.html#carpediem">opportunistic encryption</A></LI>
+<LI>our guide to configuration with
+<A HREF="policygroups.html#policygroups">policy groups</A></LI>
+<LI>our
+<A HREF="adv_config.html#adv_config">advanced configuration</A>
+document</LI>
+</UL>
+<P>
+The network-to-network setup allows you to connect two office
+networks into one Virtual Private Network, while the Road Warrior
+connection secures a laptop's telecommute to work.
+Our examples also show the basic procedure on the Linux FreeS/WAN side where
+another IPsec peer is in play.</P>
+
+<P>
+Shortcut to <A HREF="#config.netnet">net-to-net</A>.<BR>
+Shortcut to <A HREF="#config.rw">Road Warrior</A>.
+</P>
+
+<H2>Requirements</H2>
+
+<P>To configure the network-to-network connection you must have:</P>
+<UL>
+<LI>two Linux gateways with static IPs</LI>
+<LI>a network behind each gate. Networks must have non-overlapping IP ranges.</LI>
+<LI>Linux FreeS/WAN <A HREF="install.html#install">installed</A>
+ on both gateways</LI>
+<LI><A HREF="http://www.tcpdump.org"><VAR>tcpdump</VAR></A> on the local gate,
+ to test the connection</LI>
+</UL>
+<P>For the Road Warrior you need:</P>
+<UL>
+<LI>one Linux box with a static IP</LI>
+<LI>a Linux laptop with a dynamic IP</LI>
+<LI>Linux FreeS/WAN installed on both</LI>
+<LI>for testing, <VAR>tcpdump</VAR> on your gateway or laptop</LI>
+</UL>
+
+<P>If both IPs are dynamic, your situation is a bit trickier. Your best bet
+is a variation on the <A HREF="#config.rw">Road Warrior</A>, as described
+in <A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00282.html">this mailing list message</A>.
+
+<H2><A name="config.netnet"></A>Net-to-Net connection</H2>
+
+
+<H3><A name="netnet.info.ex">Gather information</A></H3>
+
+<P>For each gateway, compile the following information:</P>
+<UL>
+<LI>gateway IP</LI>
+<LI>IP range of the subnet you will be protecting. This doesn't have to
+ be your whole physical subnet.</LI>
+<LI>a name by which that gateway can identify itself for IPsec
+negotiations. Its form is a Fully Qualified Domain Name preceded by
+an @ sign, ie. @xy.example.com.
+<BR>It does not need to be within a domain that you own. It can be a made-up
+name.</LI>
+</UL>
+
+
+<H4>Get your leftrsasigkey</H4>
+<P>On your local Linux FreeS/WAN gateway, print your IPsec public key:</P>
+<PRE> ipsec showhostkey --left</PRE>
+<P>The output should look like this (with the key shortened for easy
+ reading):</P>
+<PRE> # RSA 2048 bits xy.example.com Fri Apr 26 15:01:41 2002
+ leftrsasigkey=0sAQOnwiBPt...</PRE>
+
+<P>Don't have a key? Use
+<A HREF="manpage.d/ipsec_newhostkey.8.html"><VAR>ipsec newhostkey</VAR></A>
+to create one.
+
+<H4>...and your rightrsasigkey</H4>
+<P>Get a console on the remote side:</P>
+<PRE> ssh2 ab.example.com</PRE>
+<P>In that window, type:</P>
+<PRE> ipsec showhostkey --right</PRE>
+<P>You'll see something like:</P>
+<PRE> # RSA 2192 bits ab.example.com Thu May 16 15:26:20 2002
+ rightrsasigkey=0sAQOqH55O...</PRE>
+
+<H3>Edit <VAR>/etc/ipsec.conf</VAR></H3>
+
+<P>Back on the local gate, copy our template to <VAR>/etc/ipsec.conf</VAR>.
+(on Mandrake, <VAR>/etc/freeswan/ipsec.conf</VAR>).
+Substitute the information you've gathered for our example data.</P>
+<PRE>conn net-to-net
+ left=192.0.2.2 # Local vitals
+ leftsubnet=192.0.2.128/29 #
+ leftid=@xy.example.com #
+ leftrsasigkey=0s1LgR7/oUM... #
+ leftnexthop=%defaultroute # correct in many situations
+ right=192.0.2.9 # Remote vitals
+ rightsubnet=10.0.0.0/24 #
+ rightid=@ab.example.com #
+ rightrsasigkey=0sAQOqH55O... #
+ rightnexthop=%defaultroute # correct in many situations
+ auto=add # authorizes but doesn't start this
+ # connection at startup</PRE>
+
+<P>
+"Left" and "right" should represent the machines that have FreeS/WAN installed
+on them, and "leftsubnet" and "rightsubnet" machines that are being protected.
+/32 is assumed for left/right and left/rightsubnet parameters.
+</P>
+
+<P>Copy <VAR>conn net-to-net</VAR> to the remote-side /etc/ipsec.conf.
+If you've made no other modifications to either <VAR>ipsec.conf</VAR>,
+simply:</P>
+<PRE> scp2 ipsec.conf root@ab.example.com:/etc/ipsec.conf</PRE>
+
+<H3>Start your connection</H3>
+
+<P>Locally, type:</P>
+<PRE> ipsec auto --up net-to-net</PRE>
+
+<P>You should see:</P>
+<PRE> 104 "net-net" #223: STATE_MAIN_I1: initiate
+ 106 "net-net" #223: STATE_MAIN_I2: sent MI2, expecting MR2
+ 108 "net-net" #223: STATE_MAIN_I3: sent MI3, expecting MR3
+ 004 "net-net" #223: STATE_MAIN_I4: ISAKMP SA established
+ 112 "net-net" #224: STATE_QUICK_I1: initiate
+ 004 "net-net" #224: STATE_QUICK_I2: sent QI2, IPsec SA established</PRE>
+
+<P>The important thing is <VAR>IPsec SA established</VAR>. If you're
+unsuccessful, see our
+<A HREF="trouble.html#trouble">troubleshooting tips</A>.</P>
+
+
+<H3>Do not MASQ or NAT packets to be tunneled</H3>
+
+<P>If you are using <A HREF="glossary.html#masq">IP masquerade</A> or
+<A HREF="glossary.html#NAT.gloss">Network Address Translation (NAT)</A>
+on either gateway,
+you must now exempt the packets you wish to tunnel from this treatment.
+For example, if you have a rule like:</P>
+
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -j MASQUERADE
+</PRE>
+
+<P>change it to something like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -d \! 192.0.2.128/29 -j MASQUERADE</PRE>
+
+<P>This may be necessary on both gateways.</P>
+
+
+<H3>Test your connection</H3>
+
+<P>Sit at one of your local subnet nodes (not the gateway), and ping a subnet
+node on the other (again, not the gateway).</P>
+
+<PRE> ping fileserver.toledo.example.com</PRE>
+
+<P>While still pinging, go to the local gateway and snoop your outgoing
+interface, for example:</P>
+<PRE> tcpdump -i ppp0</PRE>
+<P>You want to see ESP (Encapsulating Security Payload) packets moving
+<B>back and forth</B> between the two gateways at the same frequency as
+your pings:</P>
+<PRE> 19:16:32.046220 192.0.2.2 > 192.0.2.9: ESP(spi=0x3be6c4dc,seq=0x3)
+ 19:16:32.085630 192.0.2.9 > 192.0.2.2: ESP(spi=0x5fdd1cf8,seq=0x6)</PRE>
+
+<P>If you see this, congratulations are in order! You have a tunnel which
+will protect any IP data from one subnet
+to the other, as it passes between the two gates.
+If not, go and <A HREF="trouble.html#trouble">troubleshoot</A>.</P>
+
+<P>Note: your new tunnel protects only net-net traffic, not
+gateway-gateway, or gateway-subnet. If you need this (for example, if
+machines on one net need to securely contact a fileserver on the
+IPsec gateway), you'll need to create
+<A HREF="adv_config.html#adv_config">extra connections</A>.</P>
+
+
+<H3>Finishing touches</H3>
+
+<P>Now that your connection works, name it something sensible, like:</P>
+<PRE>conn winstonnet-toledonet</PRE>
+<P>To have the tunnel come up on-boot, replace</P>
+<PRE> auto=add</PRE>
+<P>with:</P>
+<PRE> auto=start</PRE>
+<P>Copy these changes to the other side, for example:</P>
+<PRE> scp2 ipsec.conf root@ab.example.com:/etc/ipsec.conf</PRE>
+<P>Enjoy!</P>
+
+
+
+<H2><A name="config.rw"></A>Road Warrior Configuration</H2>
+
+<H3><A name="rw.info.ex">Gather information</A></H3>
+
+<P>You'll need to know:</P>
+<UL>
+<LI>the gateway's static IP</LI>
+<LI>the IP range of the subnet behind that gateway</LI>
+<LI>a name by which each side can identify itself for IPsec
+negotiations. Its form is a Fully Qualified Domain Name preceded by
+an @ sign, ie. @road.example.com.
+<BR>It does not need to be within a domain that you own. It can be a made-up
+name.</LI>
+</UL>
+
+<H4>Get your leftrsasigkey...</H4>
+<P>On your laptop, print your IPsec public key:</P>
+<PRE> ipsec showhostkey --left</PRE>
+<P>The output should look like this (with the key shortened for easy
+ reading):</P>
+<PRE> # RSA 2192 bits road.example.com Sun Jun 9 02:45:02 2002
+ leftrsasigkey=0sAQPIPN9uI...</PRE>
+
+<P>Don't have a key? See
+<A HREF="old_config.html#genrsakey">these instructions</A>.
+
+
+<H4>...and your rightrsasigkey</H4>
+<P>Get a console on the gateway:</P>
+<PRE> ssh2 xy.example.com</PRE>
+<P>View the gateway's public key with:</P>
+<PRE> ipsec showhostkey --right</PRE>
+<P>This will yield something like</P>
+<PRE> # RSA 2048 bits xy.example.com Fri Apr 26 15:01:41 2002
+ rightrsasigkey=0sAQOnwiBPt...</PRE>
+
+
+<H3>Customize <VAR>/etc/ipsec.conf</VAR></H3>
+
+<P>On your laptop, copy this template to <VAR>/etc/ipsec.conf</VAR>.
+(on Mandrake, <VAR>/etc/freeswan/ipsec.conf</VAR>).
+Substitute the information you've gathered for our example data.</P>
+<PRE>conn road
+ left=%defaultroute # Picks up our dynamic IP
+ leftnexthop=%defaultroute #
+ leftid=@road.example.com # Local information
+ leftrsasigkey=0sAQPIPN9uI... #
+ right=192.0.2.10 # Remote information
+ rightsubnet=10.0.0.0/24 #
+ rightid=@xy.example.com #
+ rightrsasigkey=0sAQOnwiBPt... #
+ auto=add # authorizes but doesn't start this
+ # connection at startup</PRE>
+
+<P>The template for the gateway is different. Notice how it
+reverses <VAR>left</VAR> and <VAR>right</VAR>, in keeping with our
+convention that <STRONG>L</STRONG>eft is <STRONG>L</STRONG>ocal,
+<STRONG>R</STRONG>ight <STRONG>R</STRONG>emote. Be sure to switch your
+rsasigkeys in keeping with this.</P>
+
+<PRE> ssh2 xy.example.com
+ vi /etc/ipsec.conf</PRE>
+
+<P>and add:</P>
+
+<PRE>conn road
+ left=192.0.2.2 # Gateway's information
+ leftid=@xy.example.com #
+ leftsubnet=192.0.2.128/29 #
+ leftrsasigkey=0sAQOnwiBPt... #
+ rightnexthop=%defaultroute # correct in many situations
+ right=%any # Wildcard: we don't know the laptop's IP
+ rightid=@road.example.com #
+ rightrsasigkey=0sAQPIPN9uI... #
+ auto=add # authorizes but doesn't start this
+ # connection at startup</PRE>
+
+
+
+<H3>Start your connection</H3>
+
+<P>You must start the connection from the Road Warrior side. On your laptop,
+type:</P>
+<PRE> ipsec auto --start net-to-net</PRE>
+
+<P>You should see:</P>
+<PRE>104 "net-net" #223: STATE_MAIN_I1: initiate
+106 "road" #301: STATE_MAIN_I2: sent MI2, expecting MR2
+108 "road" #301: STATE_MAIN_I3: sent MI3, expecting MR3
+004 "road" #301: STATE_MAIN_I4: ISAKMP SA established
+112 "road" #302: STATE_QUICK_I1: initiate
+004 "road" #302: STATE_QUICK_I2: sent QI2, IPsec SA established</PRE>
+
+<P>Look for <VAR>IPsec SA established</VAR>. If you're
+unsuccessful, see our
+<A HREF="trouble.html#trouble">troubleshooting tips</A>.</P>
+
+
+
+<H3>Do not MASQ or NAT packets to be tunneled</H3>
+
+<P>If you are using <A HREF="glossary.html#masq">IP masquerade</A> or
+<A HREF="glossary.html#NAT.gloss">Network Address Translation (NAT)</A>
+on either gateway,
+you must now exempt the packets you wish to tunnel from this treatment.
+For example, if you have a rule like:</P>
+
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -j MASQUERADE
+</PRE>
+
+<P>change it to something like:</P>
+<PRE>iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 -d \! 192.0.2.128/29 -j MASQUERADE</PRE>
+
+
+<H3>Test your connection</H3>
+
+<P>From your laptop, ping a subnet node behind the remote gateway. Do not
+choose the gateway itself for this test.</P>
+
+<PRE> ping ns.winston.example.com</PRE>
+
+<P>Snoop the packets exiting the laptop, with a command like:</P>
+<PRE> tcpdump -i wlan0</PRE>
+<P>You have success if you see (Encapsulating Security Payload) packets
+travelling <B>in both directions</B>:</P>
+
+<PRE> 19:16:32.046220 192.0.2.2 > 192.0.2.9: ESP(spi=0x3be6c4dc,seq=0x3)
+ 19:16:32.085630 192.0.2.9 > 192.0.2.2: ESP(spi=0x5fdd1cf8,seq=0x6)</PRE>
+
+
+<P>If you do, great! Traffic between your Road Warrior and the net
+behind your gateway is protected.
+If not, see our
+<A HREF="trouble.html#trouble">troubleshooting hints</A>.</P>
+
+<P>Your new tunnel protects only traffic addressed to the net, not to
+the IPsec gateway itself. If you need the latter, you'll want to make an
+<A HREF="adv_config.html#adv_config">extra tunnel.</A>.</P>
+
+<H3>Finishing touches</H3>
+
+<P>On both ends, name your connection wisely, like:</P>
+<PRE>conn mike-to-office</PRE>
+<P><B>On the laptop only,</B> replace</P>
+<PRE> auto=add</PRE>
+<P>with:</P>
+<PRE> auto=start</PRE>
+<P>so that you'll be connected on-boot.</P>
+<P>Happy telecommuting!</P>
+
+<H3>Multiple Road Warriors</H3>
+
+<P>If you're using RSA keys, as we did in this example, you can add
+as many Road Warriors as you like. The left/rightid
+parameter lets Linux FreeS/WAN distinguish between multiple Road Warrior
+peers, each with its own public key.</P>
+
+<P>The situation is different for shared secrets (PSK). During a
+PSK negotiation, ID information is not available at the time Pluto
+is trying to determine which secret to use, so, effectively, you can
+only define one Roadwarrior connection. All your PSK road warriors
+must therefore share one secret.</P>
+
+
+<H2>What next?</H2>
+
+<P>Using the principles illustrated here, you can try variations such as:
+<UL>
+<LI>a telecommuter with a static IP</LI>
+<LI>a road warrior with a subnet behind it</LI>
+</UL>
+<P>Or, look at some of our <A HREF="adv_config.html#adv_config">more complex configuration examples.</A>.</P>
+</BODY>
+</HTML>
diff --git a/doc/src/crosscompile.html b/doc/src/crosscompile.html
new file mode 100644
index 000000000..c488957c8
--- /dev/null
+++ b/doc/src/crosscompile.html
@@ -0,0 +1,105 @@
+<HTML>
+<HEAD>
+ <TITLE>Cross Compiling FreeS/WAN</TITLE>
+ <meta name="keywords" content="Linux, IPSEC, VPN, Security, FreeSWAN, cross, compile">
+<!--
+ Written by Ken Bantoft <ken@freeswan.ca> for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+CVS information:
+RCS ID: $Id: crosscompile.html,v 1.1 2004/03/15 20:35:24 as Exp $
+Last changed: $Date: 2004/03/15 20:35:24 $
+Revision number: $Revision: 1.1 $
+
+CVS revision numbers do not correspond to FreeS/WAN release numbers.
+-->
+
+</HEAD>
+<BODY>
+
+<H1><A NAME="guide"></A>Linux FreeS/WAN Cross Compiling Guide</H1>
+
+<H2><A NAME="overview"></A>Overview</H2>
+
+<P>
+This document provides general instructions on how to cross compile
+FreeS/WAN,
+that is - compile it for another architecture (eg: StrongARM)</P>
+<OL>
+ <LI><A HREF="#setup">Setting up your environment</A>.</LI>
+ <LI><A HREF="#building">Building</A>.</LI>
+ <LI><A HREF="#common">Common Problems</A>.</LI>
+</OL>
+<H2><A NAME="setup"></A>Setting up your Environment</H2>
+<H3>Enviroment Variables</H3>
+<P>There are a number of environment variables you can set to help facilitate
+cross compiling FreeS/WAN. All examples will are using the bash shell.
+</P>
+<P>The following is an example of the how to set the environment variables if
+you were cross compiling using the Embedix ARM toolchain, to build for an embedded
+device like the Sharp Zaurus. Set these while you are in the FreeS/WAN directory.
+It is often simpler to put the entire list into a script (eg: cross-setup.sh), and
+then "source cross-setup.sh" or similar.
+<pre>
+export ARCH=arm
+export CC=/opt/Embedix/tools/bin/arm-linux-gcc
+export LD=/opt/Embedix/tools/bin/arm-linux-ld
+export RANLIB=/opt/Embedix/tools/bin/arm-linux-ranlib
+export AR=/opt/Embedix/tools/bin/arm-linux-ar
+export AS=/opt/Embedix/tools/bin/arm-linux-as
+export STRIP=/opt/Embedix/tools/bin/arm-linux-strip
+export KERNELSRC=/zaurus/kernel-2.4.6
+export LD_LIBRARY_PATH=/opt/Embedix/tools/lib/gcc-lib/arm-linux/2.95.2/
+export PATH=$PATH:/opt/Embedix/tools/bin
+export DESTDIR=/zaurus/binaries
+</pre>
+In the example above, we setup all of the usual gcc + bin-utils programs,
+as well as setting the LD_LIBRARY_PATH to our cross-compiled system libraries,
+and DESTDIR to our output directory.
+</P>
+
+<H3>Kernel Source</H3>
+<P>Place a copy of the kernel source, setup for your target device somewhere on
+your filesystem and set KERNELSRC= to this directory. You will need to prepare
+your kernel source treefirst, by running "make menuconfig && make dep && make
+modules". Once this is done, you can move on to building FreeS/WAN</P>
+
+<H2><A NAME="building"></A>Building</H2>
+<H3>The Make Process</H3>
+<P>There are two parts to building FreeS/WAN - the userland programs and utilities,
+and the ipsec.o kernel module. Each can be built seperatly, making debugging the
+build process simpler.
+</P>
+<P>Step 1 is to run "make programs". This will build the required libs
+(libfreeswan.a) as well as all of the userland tools (pluto, whack, etc...).
+Provided your environment variables are set correctly, you should see the output
+using your specified gcc (arm-linux-gcc for our example), ld, as, ar and
+ranlib.</P>
+<P>If this completes successfully, you can run "make install" to install a copy of
+all of the binaries, man pages and other documentation to DESTDIR.</P>
+<P>Step 2 is to build the ipsec.o module. This is done with "make oldmod", which
+should change into the KERNELSRC directory and then compile and link the required
+files to generate an ipsec.o file. If this is successful, you will end up with an
+ipsec.o file in your FreeS/WAN directory, under linux/net/ipsec/.</P>
+<P>Remember to install this to /lib/modules/$kernelversion/kernel/net/ipsec/ on
+your target machine.</P>
+
+
+
+<H2><A NAME="common"></A>Common Problems Building</H2>
+<P>Here is a list of common problems/errors you may run into when cross compiling
+FreeS/WAN.</P>
+<UL>
+<LI>gmp.h, libgmp not found, error with -lgmp. All of these refer to the GNU Math
+Precision Library. You will need to have already built this for your target
+system. Place libgmp.so in LD_LIBRARY_PATH, and ensure the headers are in your
+include path as well.
+</UL>
+
+<P><BR><BR>
+</P>
+</BODY>
+</HTML>
diff --git a/doc/src/draft-richardson-ipsec-opportunistic.html b/doc/src/draft-richardson-ipsec-opportunistic.html
new file mode 100644
index 000000000..87a13365a
--- /dev/null
+++ b/doc/src/draft-richardson-ipsec-opportunistic.html
@@ -0,0 +1,2456 @@
+<html><head><title>Opportunistic Encryption using The Internet Key Exchange (IKE)</title>
+<STYLE type='text/css'>
+ .title { color: #990000; font-size: 22px; line-height: 22px; font-weight: bold; text-align: right;
+ font-family: helvetica, arial, sans-serif }
+ .filename { color: #666666; font-size: 18px; line-height: 28px; font-weight: bold; text-align: right;
+ font-family: helvetica, arial, sans-serif }
+ p.copyright { color: #000000; font-size: 10px;
+ font-family: verdana, charcoal, helvetica, arial, sans-serif }
+ p { margin-left: 2em; margin-right: 2em; }
+ li { margin-left: 3em; }
+ ol { margin-left: 2em; margin-right: 2em; }
+ ul.text { margin-left: 2em; margin-right: 2em; }
+ pre { margin-left: 3em; color: #333333 }
+ ul.toc { color: #000000; line-height: 16px;
+ font-family: verdana, charcoal, helvetica, arial, sans-serif }
+ H3 { color: #333333; font-size: 16px; line-height: 16px; font-family: helvetica, arial, sans-serif }
+ H4 { color: #000000; font-size: 14px; font-family: helvetica, arial, sans-serif }
+ TD.header { color: #ffffff; font-size: 10px; font-family: arial, helvetica, san-serif; valign: top }
+ TD.author-text { color: #000000; font-size: 10px;
+ font-family: verdana, charcoal, helvetica, arial, sans-serif }
+ TD.author { color: #000000; font-weight: bold; margin-left: 4em; font-size: 10px; font-family: verdana, charcoal, helvetica, arial, sans-serif }
+ A:link { color: #990000; font-weight: bold;
+ font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
+ A:visited { color: #333333; font-weight: bold;
+ font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
+ A:name { color: #333333; font-weight: bold;
+ font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
+ .link2 { color:#ffffff; font-weight: bold; text-decoration: none;
+ font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
+ font-size: 9px }
+ .RFC { color:#666666; font-weight: bold; text-decoration: none;
+ font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
+ font-size: 9px }
+ .hotText { color:#ffffff; font-weight: normal; text-decoration: none;
+ font-family: charcoal, monaco, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
+ font-size: 9px }
+</style>
+</head>
+<body bgcolor="#ffffff" text="#000000" alink="#000000" vlink="#666666" link="#990000">
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<table width="66%" border="0" cellpadding="0" cellspacing="0"><tr><td><table width="100%" border="0" cellpadding="2" cellspacing="1">
+<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Independent submission</td><td width="33%" bgcolor="#666666" class="header">M. Richardson</td></tr>
+<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Internet-Draft</td><td width="33%" bgcolor="#666666" class="header">SSW</td></tr>
+<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Expires: November 19, 2003</td><td width="33%" bgcolor="#666666" class="header">D. Redelmeier</td></tr>
+<tr valign="top"><td width="33%" bgcolor="#666666" class="header">&nbsp;</td><td width="33%" bgcolor="#666666" class="header">Mimosa</td></tr>
+<tr valign="top"><td width="33%" bgcolor="#666666" class="header">&nbsp;</td><td width="33%" bgcolor="#666666" class="header">May 21, 2003</td></tr>
+</table></td></tr></table>
+<div align="right"><font face="monaco, MS Sans Serif" color="#990000" size="+3"><b><br><span class="title">Opportunistic Encryption using The Internet Key Exchange (IKE)</span></b></font></div>
+<div align="right"><font face="monaco, MS Sans Serif" color="#666666" size="+2"><b><span class="filename">draft-richardson-ipsec-opportunistic-11.txt</span></b></font></div>
+<font face="verdana, helvetica, arial, sans-serif" size="2">
+
+<h3>Status of this Memo</h3>
+<p>
+This document is an Internet-Draft and is in full conformance with all provisions of Section 10 of RFC2026.</p>
+<p>
+Internet-Drafts are working documents of the Internet Engineering
+Task Force (IETF), its areas, and its working groups.
+Note that other groups may also distribute working documents as
+Internet-Drafts.</p>
+<p>
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any time.
+It is inappropriate to use Internet-Drafts as reference material or to cite
+them other than as "work in progress."</p>
+<p>
+The list of current Internet-Drafts can be accessed at
+<a href='http://www.ietf.org/ietf/1id-abstracts.txt'>http://www.ietf.org/ietf/1id-abstracts.txt</a>.</p>
+<p>
+The list of Internet-Draft Shadow Directories can be accessed at
+<a href='http://www.ietf.org/shadow.html'>http://www.ietf.org/shadow.html</a>.</p>
+<p>
+This Internet-Draft will expire on November 19, 2003.</p>
+
+<h3>Copyright Notice</h3>
+<p>
+Copyright (C) The Internet Society (2003). All Rights Reserved.</p>
+
+<h3>Abstract</h3>
+
+<p>
+This document describes opportunistic encryption (OE) using the Internet Key
+Exchange (IKE) and IPsec.
+Each system administrator adds new
+resource records to his or her Domain Name System (DNS) to support
+opportunistic encryption. The objective is to allow encryption for secure communication without
+any pre-arrangement specific to the pair of systems involved.
+
+</p>
+<p>
+DNS is used to distribute the public keys of each
+system involved. This is resistant to passive attacks. The use of DNS
+Security (DNSSEC) secures this system against active attackers as well.
+
+</p>
+<p>
+As a result, the administrative overhead is reduced
+from the square of the number of systems to a linear dependence, and it becomes
+possible to make secure communication the default even
+when the partner is not known in advance.
+
+</p>
+<p>
+This document is offered up as an Informational RFC.
+
+</p><a name="toc"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<h3>Table of Contents</h3>
+<ul compact class="toc">
+<b><a href="#anchor1">1.</a>&nbsp;
+Introduction<br></b>
+<b><a href="#anchor6">2.</a>&nbsp;
+Overview<br></b>
+<b><a href="#anchor13">3.</a>&nbsp;
+Specification<br></b>
+<b><a href="#anchor31">4.</a>&nbsp;
+Impacts on IKE<br></b>
+<b><a href="#anchor38">5.</a>&nbsp;
+DNS issues<br></b>
+<b><a href="#anchor42">6.</a>&nbsp;
+Network address translation interaction<br></b>
+<b><a href="#anchor46">7.</a>&nbsp;
+Host implementations<br></b>
+<b><a href="#anchor47">8.</a>&nbsp;
+Multi-homing<br></b>
+<b><a href="#anchor48">9.</a>&nbsp;
+Failure modes<br></b>
+<b><a href="#anchor52">10.</a>&nbsp;
+Unresolved issues<br></b>
+<b><a href="#anchor54">11.</a>&nbsp;
+Examples<br></b>
+<b><a href="#securityconsiderations">12.</a>&nbsp;
+Security considerations<br></b>
+<b><a href="#anchor79">13.</a>&nbsp;
+IANA Considerations<br></b>
+<b><a href="#anchor80">14.</a>&nbsp;
+Acknowledgments<br></b>
+<b><a href="#rfc.references1">&#167;</a>&nbsp;
+Normative references<br></b>
+<b><a href="#rfc.authors">&#167;</a>&nbsp;
+Authors' Addresses<br></b>
+<b><a href="#rfc.copyright">&#167;</a>&nbsp;
+Full Copyright Statement<br></b>
+</ul>
+<br clear="all">
+
+<a name="anchor1"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.1"></a><h3>1.&nbsp;Introduction</h3>
+
+<a name="rfc.section.1.1"></a><h4><a name="anchor2">1.1</a>&nbsp;Motivation</h4>
+
+<p>
+The objective of opportunistic encryption is to allow encryption without
+any pre-arrangement specific to the pair of systems involved. Each
+system administrator adds
+public key information to DNS records to support opportunistic
+encryption and then enables this feature in the nodes' IPsec stack.
+Once this is done, any two such nodes can communicate securely.
+
+</p>
+<p>
+This document describes opportunistic encryption as designed and
+mostly implemented by the Linux FreeS/WAN project.
+For project information, see http://www.freeswan.org.
+
+</p>
+<p>
+The Internet Architecture Board (IAB) and Internet Engineering
+Steering Group (IESG) have taken a strong stand that the Internet
+should use powerful encryption to provide security and
+privacy <a href="#RFC1984">[4]</a>.
+The Linux FreeS/WAN project attempts to provide a practical means to implement this policy.
+
+</p>
+<p>
+The project uses the IPsec, ISAKMP/IKE, DNS and DNSSEC
+protocols because they are
+standardized, widely available and can often be deployed very easily
+without changing hardware or software or retraining users.
+
+</p>
+<p>
+The extensions to support opportunistic encryption are simple. No
+changes to any on-the-wire formats are needed. The only changes are to
+the policy decision making system. This means that opportunistic
+encryption can be implemented with very minimal changes to an existing
+IPsec implementation.
+
+</p>
+<p>
+Opportunistic encryption creates a "fax effect". The proliferation
+of the fax machine was possible because it did not require that everyone
+buy one overnight. Instead, as each person installed one, the value
+of having one increased - as there were more people that could receive faxes.
+Once opportunistic encryption is installed it
+automatically recognizes
+other boxes using opportunistic encryption, without any further configuration
+by the network
+administrator. So, as opportunistic encryption software is installed on more
+boxes, its value
+as a tool increases.
+
+</p>
+<p>
+This document describes the infrastructure to permit deployment of
+Opportunistic Encryption.
+
+</p>
+<p>
+The term S/WAN is a trademark of RSA Data Systems, and is used with permission
+by this project.
+
+</p>
+<a name="rfc.section.1.2"></a><h4><a name="anchor3">1.2</a>&nbsp;Types of network traffic</h4>
+
+<p>
+ To aid in understanding the relationship between security processing and IPsec
+ we divide network traffic into four categories:
+
+<blockquote class="text"><dl>
+<dt>* Deny:</dt>
+<dd> networks to which traffic is always forbidden.
+</dd>
+<dt>* Permit:</dt>
+<dd> networks to which traffic in the clear is permitted.
+</dd>
+<dt>* Opportunistic tunnel:</dt>
+<dd> networks to which traffic is encrypted if possible, but otherwise is in the clear
+ or fails depending on the default policy in place.
+
+</dd>
+<dt>* Configured tunnel:</dt>
+<dd> networks to which traffic must be encrypted, and traffic in the clear is never permitted.
+</dd>
+</dl></blockquote><p>
+</p>
+<p>
+Traditional firewall devices handle the first two categories. No authentication is required.
+The permit policy is currently the default on the Internet.
+
+</p>
+<p>
+This document describes the third category - opportunistic tunnel, which is
+proposed as the new default for the Internet.
+
+</p>
+<p>
+ Category four, encrypt traffic or drop it, requires authentication of the
+ end points. As the number of end points is typically bounded and is typically
+ under a single authority, arranging for distribution of
+ authentication material, while difficult, does not require any new
+ technology. The mechanism described here provides an additional way to
+ distribute the authentication materials, that of a public key method that does not
+ require deployment of an X.509 based infrastructure.
+
+</p>
+<p>
+Current Virtual Private Networks can often be replaced by an "OE paranoid"
+policy as described herein.
+
+</p>
+<a name="rfc.section.1.3"></a><h4><a name="anchor4">1.3</a>&nbsp;Peer authentication in opportunistic encryption</h4>
+
+<p>
+ Opportunistic encryption creates tunnels between nodes that
+ are essentially strangers. This is done without any prior bilateral
+ arrangement.
+ There is, therefore, the difficult question of how one knows to whom one is
+ talking.
+
+</p>
+<p>
+ One possible answer is that since no useful
+ authentication can be done, none should be tried. This mode of operation is
+ named "anonymous encryption". An active man-in-the-middle attack can be
+ used to thwart the privacy of this type of communication.
+ Without peer authentication, there is no way to prevent this kind of attack.
+
+</p>
+<p>
+Although a useful mode, anonymous encryption is not the goal of this
+project. Simpler methods are available that can achieve anonymous
+encryption only, but authentication of the peer is a desireable goal.
+The latter is achieved through key distribution in DNS, leveraging upon
+the authentication of the DNS in DNSSEC.
+
+</p>
+<p>
+ Peers are, therefore, authenticated with DNSSEC when available. Local policy
+determines how much trust to extend when DNSSEC is not available.
+
+</p>
+<p>
+ However, an essential premise of building private connections with
+ strangers is that datagrams received through opportunistic tunnels
+ are no more special than datagrams that arrive in the clear.
+ Unlike in a VPN, these datagrams should not be given any special
+ exceptions when it comes to auditing, further authentication or
+ firewalling.
+
+</p>
+<p>
+ When initiating outbound opportunistic encryption, local
+ configuration determines what happens if tunnel setup fails. It may be that
+ the packet goes out in the clear, or it may be dropped.
+
+</p>
+<a name="rfc.section.1.4"></a><h4><a name="anchor5">1.4</a>&nbsp;Use of RFC2119 terms</h4>
+
+<p>
+ The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD,
+ SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this
+ document, are to be interpreted as described in <a href="#RFC2119">[5]</a>
+</p>
+<a name="anchor6"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.2"></a><h3>2.&nbsp;Overview</h3>
+
+<a name="rfc.section.2.1"></a><h4><a name="anchor7">2.1</a>&nbsp;Reference diagram</h4>
+<br><hr size="1" shade="0">
+<a name="networkdiagram"></a>
+
+<p>The following network diagram is used in the rest of
+ this document as the canonical diagram:
+</p></font><pre>
+ [Q] [R]
+ . . AS2
+ [A]----+----[SG-A].......+....+.......[SG-B]-------[B]
+ | ......
+ AS1 | ..PI..
+ | ......
+ [D]----+----[SG-D].......+....+.......[C] AS3
+
+
+ </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+
+<p>
+</p><table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Reference Network Diagram&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
+
+<p>
+ In this diagram, there are four end-nodes: A, B, C and D.
+ There are three gateways, SG-A, SG-B, SG-D. A, D, SG-A and SG-D are part
+ of the same administrative authority, AS1. SG-A and SG-D are on two different exit
+ paths from organization 1. SG-B/B is an independent organization, AS2.
+ Nodes Q and R are nodes on the Internet. PI is the Public
+ Internet ("The Wild").
+
+</p>
+<a name="rfc.section.2.2"></a><h4><a name="anchor8">2.2</a>&nbsp;Terminology</h4>
+
+<p>
+ The following terminology is used in this document:
+
+</p>
+<blockquote class="text"><dl>
+<dt>Security gateway:</dt>
+<dd> a system that performs IPsec tunnel
+ mode encapsulation/decapsulation. [SG-x] in the diagram.
+</dd>
+<dt>Alice:</dt>
+<dd> node [A] in the diagram. When an IP address is needed, this is 192.1.0.65.
+</dd>
+<dt>Bob:</dt>
+<dd> node [B] in the diagram. When an IP address is needed, this is 192.2.0.66.
+</dd>
+<dt>Carol:</dt>
+<dd> node [C] in the diagram. When an IP address is needed, this is 192.1.1.67.
+</dd>
+<dt>Dave:</dt>
+<dd> node [D] in the diagram. When an IP address is needed, this is 192.3.0.68.
+</dd>
+<dt>SG-A:</dt>
+<dd> Alice's security gateway. Internally it is 192.1.0.1, externally it is 192.1.1.4.
+</dd>
+<dt>SG-B:</dt>
+<dd> Bob's security gateway. Internally it is 192.2.0.1, externally it is 192.1.1.5.
+</dd>
+<dt>SG-D:</dt>
+<dd> Dave's security gateway. Also Alice's backup security gateway. Internally it is 192.3.0.1, externally it is 192.1.1.6.
+</dd>
+<dt>-</dt>
+<dd> A single dash represents clear-text datagrams.
+</dd>
+<dt>=</dt>
+<dd> An equals sign represents phase 2 (IPsec) cipher-text
+ datagrams.
+</dd>
+<dt>~</dt>
+<dd> A single tilde represents clear-text phase 1 datagrams.
+</dd>
+<dt>#</dt>
+<dd> A hash sign represents phase 1 (IKE) cipher-text
+ datagrams.
+</dd>
+<dt>.</dt>
+<dd> A period represents an untrusted network of unknown
+ type.
+</dd>
+<dt>Configured tunnel:</dt>
+<dd> a tunnel that
+ is directly and deliberately hand configured on participating gateways.
+ Configured tunnels are typically given a higher level of
+ trust than opportunistic tunnels.
+</dd>
+<dt>Road warrior tunnel:</dt>
+<dd> a configured tunnel connecting one
+ node with a fixed IP address and one node with a variable IP address.
+ A road warrior (RW) connection must be initiated by the
+ variable node, since the fixed node cannot know the
+ current address for the road warrior.
+</dd>
+<dt>Anonymous encryption:</dt>
+<dd>
+ the process of encrypting a session without any knowledge of who the
+ other parties are. No authentication of identities is done.
+</dd>
+<dt>Opportunistic encryption:</dt>
+<dd>
+ the process of encrypting a session with authenticated knowledge of
+ who the other parties are.
+</dd>
+<dt>Lifetime:</dt>
+<dd>
+ the period in seconds (bytes or datagrams) for which a security
+ association will remain alive before needing to be re-keyed.
+</dd>
+<dt>Lifespan:</dt>
+<dd>
+ the effective time for which a security association remains useful. A
+ security association with a lifespan shorter than its lifetime would
+ be removed when no longer needed. A security association with a
+ lifespan longer than its lifetime would need to be re-keyed one or
+ more times.
+</dd>
+<dt>Phase 1 SA:</dt>
+<dd> an ISAKMP/IKE security association sometimes
+ referred to as a keying channel.
+</dd>
+<dt>Phase 2 SA:</dt>
+<dd> an IPsec security association.
+</dd>
+<dt>Tunnel:</dt>
+<dd> another term for a set of phase 2 SA (one in each direction).
+</dd>
+<dt>NAT:</dt>
+<dd> Network Address Translation
+ (see <a href="#RFC2663">[20]</a>).
+</dd>
+<dt>NAPT:</dt>
+<dd> Network Address and Port Translation
+ (see <a href="#RFC2663">[20]</a>).
+</dd>
+<dt>AS:</dt>
+<dd> an autonomous system (AS) is a group of systems (a network) that
+ are under the administrative control of a single organization.
+</dd>
+<dt>Default-free zone:</dt>
+<dd>
+ a set of routers that maintain a complete set of routes to
+ all currently reachable destinations. Having such a list, these routers
+ never make use of a default route. A datagram with a destination address
+ not matching any route will be dropped by such a router.
+
+</dd>
+</dl></blockquote><p>
+<a name="rfc.section.2.3"></a><h4><a name="anchor9">2.3</a>&nbsp;Model of operation</h4>
+
+<p>
+The opportunistic encryption security gateway (OE gateway) is a regular
+gateway node as described in <a href="#RFC0791">[2]</a> section 2.4 and
+<a href="#RFC1009">[3]</a> with the additional capabilities described here and
+in <a href="#RFC2401">[7]</a>.
+The algorithm described here provides a way to determine, for each datagram,
+whether or not to encrypt and tunnel the datagram. Two important things
+that must be determined are whether or not to encrypt and tunnel and, if
+so, the destination address or name of the tunnel end point which should be used.
+
+</p>
+<a name="rfc.section.2.3.1"></a><h4><a name="anchor10">2.3.1</a>&nbsp;Tunnel authorization</h4>
+
+<p>
+The OE gateway determines whether or not to create a tunnel based on
+the destination address of each packet. Upon receiving a packet with a destination
+address not recently seen, the OE gateway performs a lookup in DNS for an
+authorization resource record (see <a href="#TXT">Use of TXT delegation record</a>). The record is located using
+the IP address to perform a search in the in-addr.arpa (IPv4) or ip6.arpa
+(IPv6) maps. If an authorization record is found, the OE gateway
+interprets this as a request for a tunnel to be formed.
+
+</p>
+<a name="rfc.section.2.3.2"></a><h4><a name="anchor11">2.3.2</a>&nbsp;Tunnel end-point discovery</h4>
+
+<p>
+The authorization resource record also provides the address or name of the tunnel
+end point which should be used.
+
+</p>
+<p>
+The record may also provide the public RSA key of the tunnel end point
+itself. This is provided for efficiency only. If the public RSA key is not
+present, the OE gateway performs a second lookup to find a KEY
+resource record for the end point address or name.
+
+</p>
+<p>
+Origin and integrity protection of the resource records is provided by
+DNSSEC (<a href="#RFC2535">[16]</a>). <a href="#nodnssec">Restriction on unauthenticated TXT delegation records</a>
+documents an optional restriction on the tunnel end point if DNSSEC signatures
+are not available for the relevant records.
+
+</p>
+<a name="rfc.section.2.3.3"></a><h4><a name="anchor12">2.3.3</a>&nbsp;Caching of authorization results</h4>
+
+<p>
+The OE gateway maintains a cache, in the forwarding plane, of
+source/destination pairs for which opportunistic encryption has been
+attempted. This cache maintains a record of whether or not OE was
+successful so that subsequent datagrams can be forwarded properly
+without additional delay.
+
+</p>
+<p>
+Successful negotiation of OE instantiates a new security association.
+Failure to negotiate OE results in creation of a
+forwarding policy entry either to drop or transmit in the clear future
+datagrams. This negative cache is necessary to avoid the possibly lengthy process of repeatedly looking
+up the same information.
+
+</p>
+<p>
+The cache is timed out periodically, as described in <a href="#teardown">Renewal and teardown</a>.
+This removes entries that are no longer
+being used and permits the discovery of changes in authorization policy.
+
+</p>
+<a name="anchor13"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.3"></a><h3>3.&nbsp;Specification</h3>
+
+<p>
+The OE gateway is modeled to have a forwarding plane and a control
+plane. A control channel, such as PF_KEY, connects the two planes.
+(See <a href="#RFC2367">[6]</a>.)
+The forwarding plane performs per datagram operations. The control plane
+contains a keying
+daemon, such as ISAKMP/IKE, and performs all authorization, peer authentication and
+key derivation functions.
+
+</p>
+<a name="rfc.section.3.1"></a><h4><a name="anchor14">3.1</a>&nbsp;Datagram state machine</h4>
+
+<p>
+Let the OE gateway maintain a collection of objects -- a superset of the
+security policy database (SPD) specified in <a href="#RFC2401">[7]</a>. For
+each combination of source and destination address, an SPD
+object exists in one of five following states.
+Prior to forwarding each datagram, the
+responder uses the source and destination addresses to pick an entry from the SPD.
+The SPD then determines if and how the packet is forwarded.
+
+</p>
+<a name="rfc.section.3.1.1"></a><h4><a name="anchor15">3.1.1</a>&nbsp;Non-existent policy</h4>
+
+<p>
+If the responder does not find an entry, then this policy applies.
+The responder creates an entry with an initial state of "hold policy" and requests
+keying material from the keying daemon. The responder does not forward the datagram,
+rather it attaches the datagram to the SPD entry as the "first" datagram and retains it
+for eventual transmission in a new state.
+
+
+</p>
+<a name="rfc.section.3.1.2"></a><h4><a name="anchor16">3.1.2</a>&nbsp;Hold policy</h4>
+
+<p>
+The responder requests keying material. If the interface to the keying
+system is lossy (PF_KEY, for instance, can be), the implementation
+SHOULD include a mechanism to retransmit the
+keying request at a rate limited to less than 1 request per second.
+The responder does not forward the datagram. It attaches the
+datagram to the SPD entry as the "last" datagram where it is retained
+for eventual transmission. If there is
+a datagram already so stored, then that already stored datagram is discarded.
+
+</p>
+<p>
+Because the "first" datagram is probably a TCP SYN packet, the
+responder retains the "first" datagram in an attempt to avoid waiting for a
+TCP retransmit. The responder retains the "last"
+datagram in deference to streaming protocols that find it useful to know
+how much data has been lost. These are recommendations to
+decrease latency. There are no operational requirements for this.
+
+</p>
+<a name="rfc.section.3.1.3"></a><h4><a name="anchor17">3.1.3</a>&nbsp;Pass-through policy</h4>
+
+<p>
+The responder forwards the datagram using the normal forwarding table.
+The responder enters this state only by command from the keying daemon,
+and upon entering this state, also forwards the "first" and "last" datagrams.
+
+</p>
+<a name="rfc.section.3.1.4"></a><h4><a name="anchor18">3.1.4</a>&nbsp;Deny policy</h4>
+
+<p>
+The responder discards the datagram. The responder enters this state only by
+command
+from the keying daemon, and upon entering this state, discards the "first"
+and "last" datagrams.
+Local administration decides if further datagrams cause ICMP messages
+to be generated (i.e. ICMP Destination Unreachable, Communication
+Administratively Prohibited. type=3, code=13).
+
+</p>
+<a name="rfc.section.3.1.5"></a><h4><a name="anchor19">3.1.5</a>&nbsp;Encrypt policy</h4>
+
+<p>
+The responder encrypts the datagram using the indicated security association database
+(SAD) entry. The responder enters this state only by command from the keying daemon, and upon entering
+this state, releases and forwards the "first" and "last" datagrams using the
+new encrypt policy.
+
+</p>
+<p>
+If the associated SAD entry expires because of byte, packet or time limits, then
+the entry returns to the Hold policy, and an expire message is sent to the keying daemon.
+
+</p>
+<p>
+All states may be created directly by the keying daemon while acting as a
+responder.
+
+</p>
+<a name="rfc.section.3.2"></a><h4><a name="initclasses">3.2</a>&nbsp;Keying state machine - initiator</h4>
+
+<p>
+Let the keying daemon maintain a collection of objects. Let them be
+called "connections" or "conn"s. There are two categories of
+connection objects: classes and instances. A class represents an
+abstract policy - what could be. An instance represents an actual connection -
+what is implemented at the time.
+
+</p>
+<p>
+Let there be two further subtypes of connections: keying channels (Phase
+1 SAs) and data channels (Phase 2 SAs). Each data channel object may have
+a corresponding SPD and SAD entry maintained by the datagram state machine.
+
+</p>
+<p>
+For the purposes of opportunistic encryption, there MUST, at least, be
+connection classes known as "deny", "always-clear-text", "OE-permissive", and
+"OE-paranoid".
+The latter two connection classes define a set of source and/or destination
+addresses for which opportunistic encryption will be attempted. The administrator MAY set policy
+options in a number of additional places. An implementation MAY create additional connection classes to further refine
+these policies.
+
+</p>
+<p>
+The simplest system may need only the "OE-permissive" connection, and would
+list its own (single) IP address as the source address of this policy and
+the wild-card address 0.0.0.0/0 as the destination IPv4 address. That is, the
+simplest policy is to try opportunistic encryption with all destinations.
+
+</p>
+<p>
+The distinction between permissive and paranoid OE use will become clear
+in the state transition differences. In general a permissive OE will, on
+failure, install a pass-through policy, while a paranoid OE will, on failure,
+install a drop policy.
+
+</p>
+<p>
+In this description of the keying machine's state transitions, the states
+associated with the keying system itself are omitted because they are best documented in the keying system
+(<a href="#RFC2407">[8]</a>,
+<a href="#RFC2408">[9]</a> and <a href="#RFC2409">[10]</a> for ISAKMP/IKE),
+and the details are keying system specific. Opportunistic encryption is not
+dependent upon any specific keying protocol, but this document does provide
+requirements for those using ISAKMP/IKE to assure that implementations inter-operate.
+
+</p>
+<p>
+The state transitions that may be involved in communicating with the
+forwarding plane are omitted. PF_KEY and similar protocols have their own
+set of states required for message sends and completion notifications.
+
+</p>
+<p>
+Finally, the retransmits and recursive lookups that are normal for DNS are
+not included in this description of the state machine.
+
+</p>
+<a name="rfc.section.3.2.1"></a><h4><a name="anchor20">3.2.1</a>&nbsp;Nonexistent connection</h4>
+
+<p>
+There is no connection instance for a given source/destination address pair.
+Upon receipt of a request for keying material for this
+source/destination pair, the initiator searches through the connection classes to
+determine the most appropriate policy. Upon determining an appropriate
+connection class, an instance object is created of that type.
+Both of the OE types result in a potential OE connection.
+
+</p>
+<p>Failure to find an appropriate connection class results in an
+administrator defined default.
+
+</p>
+<p>
+In each case, when the initiator finds an appropriate class for the new flow,
+an instance connection is made of the class which matched.
+
+</p>
+<a name="rfc.section.3.2.2"></a><h4><a name="anchor21">3.2.2</a>&nbsp;Clear-text connection</h4>
+
+<p>
+The non-existent connection makes a transition to this state when an
+always-clear-text class is instantiated, or when an OE-permissive
+connection fails. During the transition, the initiator creates a pass-through
+policy object in the forwarding plane for the appropriate flow.
+
+</p>
+<p>
+Timing out is the only way to leave this state
+(see <a href="#expiring">Expiring connection</a>).
+
+</p>
+<a name="rfc.section.3.2.3"></a><h4><a name="anchor22">3.2.3</a>&nbsp;Deny connection</h4>
+
+<p>
+The empty connection makes a transition to this state when a
+deny class is instantiated, or when an OE-paranoid connection fails.
+During the transition, the initiator creates a deny policy object in the forwarding plane
+for the appropriate flow.
+
+</p>
+<p>
+Timing out is the only way to leave this state
+(see <a href="#expiring">Expiring connection</a>).
+
+</p>
+<a name="rfc.section.3.2.4"></a><h4><a name="anchor23">3.2.4</a>&nbsp;Potential OE connection</h4>
+
+<p>
+The empty connection makes a transition to this state when one of either OE class is instantiated.
+During the transition to this state, the initiator creates a hold policy object in the
+forwarding plane for the appropriate flow.
+
+</p>
+<p>
+In addition, when making a transition into this state, DNS lookup is done in
+the reverse-map for a TXT delegation resource record (see <a href="#TXT">Use of TXT delegation record</a>).
+The lookup key is the destination address of the flow.
+
+</p>
+<p>
+There are three ways to exit this state:
+
+<ol class="text">
+<li>DNS lookup finds a TXT delegation resource record.
+</li>
+<li>DNS lookup does not find a TXT delegation resource record.
+</li>
+<li>DNS lookup times out.
+</li>
+</ol><p>
+</p>
+<p>
+Based upon the results of the DNS lookup, the potential OE connection makes a
+transition to the pending OE connection state. The conditions for a
+successful DNS look are:
+
+<ol class="text">
+<li>DNS finds an appropriate resource record
+</li>
+<li>It is properly formatted according to <a href="#TXT">Use of TXT delegation record</a>
+</li>
+<li> if DNSSEC is enabled, then the signature has been vouched for.
+</li>
+</ol><p>
+
+Note that if the initiator does not find the public key
+present in the TXT delegation record, then the public key must
+be looked up as a sub-state. Only successful completion of all the
+DNS lookups is considered a success.
+
+</p>
+<p>
+If DNS lookup does not find a resource record or DNS times out, then the
+initiator considers the receiver not OE capable. If this is an OE-paranoid instance,
+then the potential OE connection makes a transition to the deny connection state.
+If this is an OE-permissive instance, then the potential OE connection makes a transition to the
+clear-text connection state.
+
+</p>
+<p>
+If the initiator finds a resource record but it is not properly formatted, or
+if DNSSEC is
+enabled and reports a failure to authenticate, then the potential OE
+connection should make a
+transition to the deny connection state. This action SHOULD be logged. If the
+administrator wishes to override this transition between states, then an
+always-clear class can be installed for this flow. An implementation MAY make
+this situation a new class.
+
+</p>
+<a name="rfc.section.3.2.4.1"></a><h4><a name="nodnssec">3.2.4.1</a>&nbsp;Restriction on unauthenticated TXT delegation records</h4>
+
+<p>
+An implementation SHOULD also provide an additional administrative control
+on delegation records and DNSSEC. This control would apply to delegation
+records (the TXT records in the reverse-map) that are not protected by
+DNSSEC.
+Records of this type are only permitted to delegate to their own address as
+a gateway. When this option is enabled, an active attack on DNS will be
+unable to redirect packets to other than the original destination.
+
+</p>
+<a name="rfc.section.3.2.5"></a><h4><a name="anchor24">3.2.5</a>&nbsp;Pending OE connection</h4>
+
+<p>
+The potential OE connection makes a transition to this state when
+the initiator determines that all the information required from the DNS lookup is present.
+Upon entering this state, the initiator attempts to initiate keying to the gateway
+provided.
+
+</p>
+<p>
+Exit from this state occurs either with a successfully created IPsec SA, or
+with a failure of some kind. Successful SA creation results in a transition
+to the key connection state.
+
+</p>
+<p>
+Three failures have caused significant problems. They are clearly not the
+only possible failures from keying.
+
+</p>
+<p>
+Note that if there are multiple gateways available in the TXT delegation
+records, then a failure can only be declared after all have been
+tried. Further, creation of a phase 1 SA does not constitute success. A set
+of phase 2 SAs (a tunnel) is considered success.
+
+</p>
+<p>
+The first failure occurs when an ICMP port unreachable is consistently received
+without any other communication, or when there is silence from the remote
+end. This usually means that either the gateway is not alive, or the
+keying daemon is not functional. For an OE-permissive connection, the initiator makes a transition
+to the clear-text connection but with a low lifespan. For an OE-pessimistic connection,
+the initiator makes a transition to the deny connection again with a low lifespan. The lifespan in both
+cases is kept low because the remote gateway may
+be in the process of rebooting or be otherwise temporarily unavailable.
+
+</p>
+<p>
+The length of time to wait for the remote keying daemon to wake up is
+a matter of some debate. If there is a routing failure, 5 minutes is usually long enough for the network to
+re-converge. Many systems can reboot in that amount of
+time as well. However, 5 minutes is far too long for most users to wait to
+hear that they can not connect using OE. Implementations SHOULD make this a
+tunable parameter.
+
+</p>
+<p>
+The second failure occurs after a phase 1 SA has been created, but there is
+either no response to the phase 2 proposal, or the initiator receives a
+negative notify (the notify must be
+authenticated). The remote gateway is not prepared to do OE at this time.
+As before, the initiator makes a transition to the clear-text or the deny
+connection based upon connection class, but this
+time with a normal lifespan.
+
+</p>
+<p>
+The third failure occurs when there is signature failure while authenticating
+the remote gateway. This can occur when there has been a
+key roll-over, but DNS has not caught up. In this case again, the initiator makes a
+transition to the clear-text or the deny connection based
+upon the connection class. However, the lifespan depends upon the remaining
+time to live in the DNS. (Note that DNSSEC signed resource records have a different
+expiry time than non-signed records.)
+
+</p>
+<a name="rfc.section.3.2.6"></a><h4><a name="keyed">3.2.6</a>&nbsp;Keyed connection</h4>
+
+<p>
+The pending OE connection makes a transition to this state when
+session keying material (the phase 2 SAs) is derived. The initiator creates an encrypt
+policy in the forwarding plane for this flow.
+
+</p>
+<p>
+There are three ways to exit this state. The first is by receipt of an
+authenticated delete message (via the keying channel) from the peer. This is
+normal teardown and results in a transition to the expired connection state.
+
+</p>
+<p>
+The second exit is by expiry of the forwarding plane keying material. This
+starts a re-key operation with a transition back to pending OE
+connection. In general, the soft expiry occurs with sufficient time left
+to continue to use the keys. A re-key can fail, which may
+result in the connection failing to clear-text or deny as
+appropriate. In the event of a failure, the forwarding plane
+policy does not change until the phase 2 SA (IPsec SA) reaches its
+hard expiry.
+
+</p>
+<p>
+The third exit is in response to a negotiation from a remote
+gateway. If the forwarding plane signals the control plane that it has received an
+unknown SPI from the remote gateway, or an ICMP is received from the remote gateway
+indicating an unknown SPI, the initiator should consider that
+the remote gateway has rebooted or restarted. Since these
+indications are easily forged, the implementation must
+exercise care. The initiator should make a cautious
+(rate-limited) attempt to re-key the connection.
+
+</p>
+<a name="rfc.section.3.2.7"></a><h4><a name="expiring">3.2.7</a>&nbsp;Expiring connection</h4>
+
+<p>
+The initiator will periodically place each of the deny, clear-text, and keyed
+connections into this
+sub-state. See <a href="#teardown">Renewal and teardown</a> for more details of how often this
+occurs.
+The initiator queries the forwarding plane for last use time of the
+appropriate
+policy. If the last use time is relatively recent, then the connection
+returns to the
+previous deny, clear-text or keyed connection state. If not, then the
+connection enters
+the expired connection state.
+
+</p>
+<p>
+The DNS query and answer that lead to the expiring connection state are also
+examined. The DNS query may become stale. (A negative, i.e. no such record, answer
+is valid for the period of time given by the MINIMUM field in an attached SOA
+record. See <a href="#RFC1034">[12]</a> section 4.3.4.)
+If the DNS query is stale, then a new query is made. If the results change, then the connection
+makes a transition to a new state as described in potential OE connection state.
+
+</p>
+<p>
+Note that when considering how stale a connection is, both outgoing SPD and
+incoming SAD must be queried as some flows may be unidirectional for some time.
+
+</p>
+<p>
+Also note that the policy at the forwarding plane is not updated unless there
+is a conclusion that there should be a change.
+
+</p>
+<a name="rfc.section.3.2.8"></a><h4><a name="anchor25">3.2.8</a>&nbsp;Expired connection</h4>
+
+<p>
+Entry to this state occurs when no datagrams have been forwarded recently via the
+appropriate SPD and SAD objects. The objects in the forwarding plane are
+removed (logging any final byte and packet counts if appropriate) and the
+connection instance in the keying plane is deleted.
+
+</p>
+<p>
+The initiator sends an ISAKMP/IKE delete to clean up the phase 2 SAs as described in
+<a href="#teardown">Renewal and teardown</a>.
+
+</p>
+<p>
+Whether or not to delete the phase 1 SAs
+at this time is left as a local implementation issue. Implementations
+that do delete the phase 1 SAs MUST send authenticated delete messages to
+indicate that they are doing so. There is an advantage to keeping
+the phase 1 SAs until they expire - they may prove useful again in the
+near future.
+
+</p>
+<a name="rfc.section.3.3"></a><h4><a name="anchor26">3.3</a>&nbsp;Keying state machine - responder</h4>
+
+<p>
+The responder has a set of objects identical to those of the initiator.
+
+</p>
+<p>
+The responder receives an invitation to create a keying channel from an initiator.
+
+</p>
+<a name="rfc.section.3.3.1"></a><h4><a name="anchor27">3.3.1</a>&nbsp;Unauthenticated OE peer</h4>
+
+<p>
+Upon entering this state, the responder starts a DNS lookup for a KEY record for the
+initiator.
+The responder looks in the reverse-map for a KEY record for the initiator if the
+initiator has offered an ID_IPV4_ADDR, and in the forward map if the
+initiator has offered an ID_FQDN type. (See <a href="#RFC2407">[8]</a> section
+4.6.2.1.)
+
+</p>
+<p>
+The responder exits this state upon successful receipt of a KEY from DNS, and use of the key
+to verify the signature of the initiator.
+
+</p>
+<p>
+Successful authentication of the peer results in a transition to the
+authenticated OE Peer state.
+
+</p>
+<p>
+Note that the unauthenticated OE peer state generally occurs in the middle of the key negotiation
+protocol. It is really a form of pseudo-state.
+
+</p>
+<a name="rfc.section.3.3.2"></a><h4><a name="anchor28">3.3.2</a>&nbsp;Authenticated OE Peer</h4>
+
+<p>
+The peer will eventually propose one or more phase 2 SAs. The responder uses the source and
+destination address in the proposal to
+finish instantiating the connection state
+using the connection class table.
+The responder MUST search for an identical connection object at this point.
+
+</p>
+<p>
+If an identical connection is found, then the responder deletes the old instance,
+and the new object makes a transition to the pending OE connection state. This means
+that new ISAKMP connections with a given peer will always use the latest
+instance, which is the correct one if the peer has rebooted in the interim.
+
+</p>
+<p>
+If an identical connection is not found, then the responder makes the transition according to the
+rules given for the initiator.
+
+</p>
+<p>
+Note that if the initiator is in OE-paranoid mode and the responder is in
+either always-clear-text or deny, then no communication is possible according
+to policy. An implementation is permitted to create new types of policies
+such as "accept OE but do not initiate it". This is a local matter.
+
+</p>
+<a name="rfc.section.3.4"></a><h4><a name="teardown">3.4</a>&nbsp;Renewal and teardown</h4>
+
+<a name="rfc.section.3.4.1"></a><h4><a name="anchor29">3.4.1</a>&nbsp;Aging</h4>
+
+<p>
+A potentially unlimited number of tunnels may exist. In practice, only a few
+tunnels are used during a period of time. Unused tunnels MUST, therefore, be
+torn down. Detecting when tunnels are no longer in use is the subject of this section.
+
+</p>
+<p>
+There are two methods for removing tunnels: explicit deletion or expiry.
+
+</p>
+<p>
+Explicit deletion requires an IKE delete message. As the deletes
+MUST be authenticated, both ends of the tunnel must maintain the
+key channel (phase 1 ISAKMP SA). An implementation which refuses to either maintain or
+recreate the keying channel SA will be unable to use this method.
+
+</p>
+<p>
+The tunnel expiry method, simply allows the IKE daemon to
+expire normally without attempting to re-key it.
+
+</p>
+<p>
+Regardless of which method is used to remove tunnels, the implementation requires
+a method to determine if the tunnel is still in use. The specifics are a
+local matter, but the FreeS/WAN project uses the following criteria. These
+criteria are currently implemented in the key management daemon, but could
+also be implemented at the SPD layer using an idle timer.
+
+</p>
+<p>
+Set a short initial (soft) lifespan of 1 minute since many net flows last
+only a few seconds.
+
+</p>
+<p>
+At the end of the lifespan, check to see if the tunnel was used by
+traffic in either direction during the last 30 seconds. If so, assign a
+longer tentative lifespan of 20 minutes after which, look again. If the
+tunnel is not in use, then close the tunnel.
+
+</p>
+<p>
+The expiring state in the key management
+system (see <a href="#expiring">Expiring connection</a>) implements these timeouts.
+The timer above may be in the forwarding plane,
+but then it must be re-settable.
+
+</p>
+<p>
+The tentative lifespan is independent of re-keying; it is just the time when
+the tunnel's future is next considered.
+(The term lifespan is used here rather than lifetime for this reason.)
+Unlike re-keying, this tunnel use check is not costly and should happen
+reasonably frequently.
+
+</p>
+<p>
+A multi-step back-off algorithm is not considered worth the effort here.
+
+</p>
+<p>
+If the security gateway and the client host are the
+same and not a Bump-in-the-Stack or Bump-in-the-Wire implementation, tunnel
+teardown decisions MAY pay attention to TCP connection status as reported
+by the local TCP layer. A still-open TCP connection is almost a guarantee that more traffic is
+expected. Closing of the only TCP connection through a tunnel is a
+strong hint that no more traffic is expected.
+
+</p>
+<a name="rfc.section.3.4.2"></a><h4><a name="anchor30">3.4.2</a>&nbsp;Teardown and cleanup</h4>
+
+<p>
+Teardown should always be coordinated between the two ends of the tunnel by
+interpreting and sending delete notifications. There is a
+detailed sub-state in the expired connection state of the key manager that
+relates to retransmits of the delete notifications, but this is considered to
+be a keying system detail.
+
+</p>
+<p>
+On receiving a delete for the outbound SAs of a tunnel (or some subset of
+them), tear down the inbound ones also and notify the remote end with a
+delete. If the local system receives a delete for a tunnel which is no longer in
+existence, then two delete messages have crossed paths. Ignore the delete.
+The operation has already been completed. Do not generate any messages in this
+situation.
+
+</p>
+<p>
+Tunnels are to be considered as bidirectional entities, even though the
+low-level protocols don't treat them this way.
+
+</p>
+<p>
+When the deletion is initiated locally, rather than as a
+response to a received delete, send a delete for (all) the
+inbound SAs of a tunnel. If the local system does not receive a responding delete
+for the outbound SAs, try re-sending the original
+delete. Three tries spaced 10 seconds apart seems a reasonable
+level of effort. A failure of the other end to respond after 3 attempts,
+indicates that the possibility of further communication is unlikely. Remove the outgoing SAs.
+(The remote system may be a mobile node that is no longer present or powered on.)
+
+</p>
+<p>
+After re-keying, transmission should switch to using the new
+outgoing SAs (ISAKMP or IPsec) immediately, and the old leftover
+outgoing SAs should be cleared out promptly (delete should be sent
+for the outgoing SAs) rather than waiting for them to expire. This
+reduces clutter and minimizes confusion for the operator doing diagnostics.
+
+</p>
+<a name="anchor31"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.4"></a><h3>4.&nbsp;Impacts on IKE</h3>
+
+<a name="rfc.section.4.1"></a><h4><a name="anchor32">4.1</a>&nbsp;ISAKMP/IKE protocol</h4>
+
+<p>
+ The IKE wire protocol needs no modifications. The major changes are
+ implementation issues relating to how the proposals are interpreted, and from
+ whom they may come.
+
+</p>
+<p>
+ As opportunistic encryption is designed to be useful between peers without
+ prior operator configuration, an IKE daemon must be prepared to negotiate
+ phase 1 SAs with any node. This may require a large amount of resources to
+ maintain cookie state, as well as large amounts of entropy for nonces,
+ cookies and so on.
+
+</p>
+<p>
+ The major changes to support opportunistic encryption are at the IKE daemon
+ level. These changes relate to handling of key acquisition requests, lookup
+ of public keys and TXT records, and interactions with firewalls and other
+ security facilities that may be co-resident on the same gateway.
+
+</p>
+<a name="rfc.section.4.2"></a><h4><a name="anchor33">4.2</a>&nbsp;Gateway discovery process</h4>
+
+<p>
+ In a typical configured tunnel, the address of SG-B is provided
+ via configuration. Furthermore, the mapping of an SPD entry to a gateway is
+ typically a 1:1 mapping. When the 0.0.0.0/0 SPD entry technique is used, then
+ the mapping to a gateway is determined by the reverse DNS records.
+
+</p>
+<p>
+ The need to do a DNS lookup and wait for a reply will typically introduce a
+ new state and a new event source (DNS replies) to IKE. Although a
+synchronous DNS request can be implemented for proof of concept, experience
+is that it can cause very high latencies when a queue of queries must
+all timeout in series.
+
+</p>
+<p>
+ Use of an asynchronous DNS lookup will also permit overlap of DNS lookups with
+ some of the protocol steps.
+
+</p>
+<a name="rfc.section.4.3"></a><h4><a name="anchor34">4.3</a>&nbsp;Self identification</h4>
+
+<p>
+ SG-A will have to establish its identity. Use an
+ IPv4 ID in phase 1.
+
+</p>
+<p> There are many situations where the administrator of SG-A may not be
+ able to control the reverse DNS records for SG-A's public IP address.
+ Typical situations include dialup connections and most residential-type broadband Internet access
+ (ADSL, cable-modem) connections. In these situations, a fully qualified domain
+ name that is under the control of SG-A's administrator may be used
+ when acting as an initiator only.
+ The FQDN ID should be used in phase 1. See <a href="#fqdn">Use of FQDN IDs</a>
+ for more details and restrictions.
+
+</p>
+<a name="rfc.section.4.4"></a><h4><a name="anchor35">4.4</a>&nbsp;Public key retrieval process</h4>
+
+<p>
+ Upon receipt of a phase 1 SA proposal with either an IPv4 (IPv6) ID or
+ an FQDN ID, an IKE daemon needs to examine local caches and
+ configuration files to determine if this is part of a configured tunnel.
+ If no configured tunnels are found, then the implementation should attempt to retrieve
+ a KEY record from the reverse DNS in the case of an IPv4/IPv6 ID, or
+ from the forward DNS in the case of FQDN ID.
+
+</p>
+<p>
+ It is reasonable that if other non-local sources of policy are used
+ (COPS, LDAP), they be consulted concurrently but some
+ clear ordering of policy be provided. Note that due to variances in
+ latency, implementations must wait for positive or negative replies from all sources
+ of policy before making any decisions.
+
+</p>
+<a name="rfc.section.4.5"></a><h4><a name="anchor36">4.5</a>&nbsp;Interactions with DNSSEC</h4>
+
+<p>
+ The implementation described (1.98) neither uses DNSSEC directly to
+ explicitly verify the authenticity of zone information, nor uses the NXT
+ records to provide authentication of the absence of a TXT or KEY
+ record. Rather, this implementation uses a trusted path to a DNSSEC
+ capable caching resolver.
+
+</p>
+<p>
+ To distinguish between an authenticated and an unauthenticated DNS
+ resource record, a stub resolver capable of returning DNSSEC
+ information MUST be used.
+
+</p>
+<a name="rfc.section.4.6"></a><h4><a name="anchor37">4.6</a>&nbsp;Required proposal types</h4>
+
+<a name="rfc.section.4.6.1"></a><h4><a name="phase1id">4.6.1</a>&nbsp;Phase 1 parameters</h4>
+
+<p>
+ Main mode MUST be used.
+
+</p>
+<p>
+ The initiator MUST offer at least one proposal using some combination
+ of: 3DES, HMAC-MD5 or HMAC-SHA1, DH group 2 or 5. Group 5 SHOULD be
+ proposed first.
+ <a href="#RFC3526">[11]</a>
+</p>
+<p>
+ The initiator MAY offer additional proposals, but the cipher MUST not
+ be weaker than 3DES. The initiator SHOULD limit the number of proposals
+ such that the IKE datagrams do not need to be fragmented.
+
+</p>
+<p>
+ The responder MUST accept one of the proposals. If any configuration
+ of the responder is required then the responder is not acting in an
+ opportunistic way.
+
+</p>
+<p>
+ SG-A SHOULD use an ID_IPV4_ADDR (ID_IPV6_ADDR for IPv6) of the external
+ interface of SG-A for phase 1. (There is an exception, see <a href="#fqdn">Use of FQDN IDs</a>.) The authentication method MUST be RSA public key signatures.
+ The RSA key for SG-A SHOULD be placed into a DNS KEY record in
+ the reverse space of SG-A (i.e. using in-addr.arpa).
+
+</p>
+<a name="rfc.section.4.6.2"></a><h4><a name="phase2id">4.6.2</a>&nbsp;Phase 2 parameters</h4>
+
+<p>
+ SG-A MUST propose a tunnel between Alice and Bob, using 3DES-CBC
+ mode, MD5 or SHA1 authentication. Perfect Forward Secrecy MUST be specified.
+
+</p>
+<p>
+ Tunnel mode MUST be used.
+
+</p>
+<p>
+ Identities MUST be ID_IPV4_ADDR_SUBNET with the mask being /32.
+
+</p>
+<p>
+ Authorization for SG-A to act on Alice's behalf is determined by
+ looking for a TXT record in the reverse-map at Alice's address.
+
+</p>
+<p>
+ Compression SHOULD NOT be mandatory. It may be offered as an option.
+
+</p>
+<a name="anchor38"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.5"></a><h3>5.&nbsp;DNS issues</h3>
+
+<a name="rfc.section.5.1"></a><h4><a name="KEY">5.1</a>&nbsp;Use of KEY record</h4>
+
+<p>
+ In order to establish their own identities, SG-A and SG-B SHOULD publish
+ their public keys in their reverse DNS via
+ DNSSEC's KEY record.
+ See section 3 of <a href="#RFC2535">RFC 2535</a>[16].
+
+</p>
+<p>
+<p>For example:
+</p></font><pre>
+KEY 0x4200 4 1 AQNJjkKlIk9...nYyUkKK8
+</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+
+<blockquote class="text"><dl>
+<dt>0x4200:</dt>
+<dd> The flag bits, indicating that this key is prohibited
+ for confidentiality use (it authenticates the peer only, a separate
+ Diffie-Hellman exchange is used for
+ confidentiality), and that this key is associated with the non-zone entity
+ whose name is the RR owner name. No other flags are set.
+</dd>
+<dt>4:</dt>
+<dd>This indicates that this key is for use by IPsec.
+</dd>
+<dt>1:</dt>
+<dd>An RSA key is present.
+</dd>
+<dt>AQNJjkKlIk9...nYyUkKK8:</dt>
+<dd>The public key of the host as described in <a href="#RFC3110">[17]</a>.
+</dd>
+</dl></blockquote><p>
+</p>
+<p>Use of several KEY records allows for key rollover. The SIG Payload in
+ IKE phase 1 SHOULD be accepted if the public key given by any KEY RR
+ validates it.
+
+</p>
+<a name="rfc.section.5.2"></a><h4><a name="TXT">5.2</a>&nbsp;Use of TXT delegation record</h4>
+
+<p>
+Alice publishes a TXT record to provide authorization for SG-A to act on
+Alice's behalf.
+
+Bob publishes a TXT record to provide authorization for SG-B to act on Bob's
+behalf.
+
+These records are located in the reverse DNS (in-addr.arpa) for their
+respective IP addresses. The reverse DNS SHOULD be secured by DNSSEC, when
+it is deployed. DNSSEC is required to defend against active attacks.
+
+</p>
+<p>
+ If Alice's address is P.Q.R.S, then she can authorize another node to
+ act on her behalf by publishing records at:
+ </p>
+</font><pre>
+S.R.Q.P.in-addr.arpa
+ </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+
+</p>
+<p>
+ The contents of the resource record are expected to be a string that
+ uses the following syntax, as suggested in <a href="#RFC1464">[15]</a>.
+ (Note that the reply to query may include other TXT resource
+ records used by other applications.)
+
+ <br><hr size="1" shade="0">
+<a name="txtformat"></a>
+</p>
+</font><pre>
+X-IPsec-Server(P)=A.B.C.D KEY
+ </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Format of reverse delegation record&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
+
+</p>
+<blockquote class="text"><dl>
+<dt>P:</dt>
+<dd> Specifies a precedence for this record. This is
+ similar to MX record preferences. Lower numbers have stronger
+ preference.
+
+</dd>
+<dt>A.B.C.D:</dt>
+<dd> Specifies the IP address of the Security Gateway
+ for this client machine.
+
+</dd>
+<dt>KEY:</dt>
+<dd> Is the encoded RSA Public key of the Security
+ Gateway. The key is provided here to avoid a second DNS lookup. If this
+ field is absent, then a KEY resource record should be looked up in the
+ reverse-map of A.B.C.D. The key is transmitted in base64 format.
+
+</dd>
+</dl></blockquote><p>
+<p>
+ The pieces of the record are separated by any whitespace
+ (space, tab, newline, carriage return). An ASCII space SHOULD
+ be used.
+
+</p>
+<p>
+ In the case where Alice is located at a public address behind a
+ security gateway that has no fixed address (or no control over its
+ reverse-map), then Alice may delegate to a public key by domain name.
+
+ <br><hr size="1" shade="0">
+<a name="txtfqdnformat"></a>
+</p>
+</font><pre>
+X-IPsec-Server(P)=@FQDN KEY
+ </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Format of reverse delegation record (FQDN version)&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
+
+</p>
+<blockquote class="text"><dl>
+<dt>P:</dt>
+<dd> Is as above.
+
+</dd>
+<dt>FQDN:</dt>
+<dd> Specifies the FQDN that the Security Gateway
+ will identify itself with.
+
+</dd>
+<dt>KEY:</dt>
+<dd> Is the encoded RSA Public key of the Security
+ Gateway.
+</dd>
+</dl></blockquote><p>
+<p>
+ If there is more than one such TXT record with strongest (lowest
+ numbered) precedence, one Security Gateway is picked arbitrarily from
+ those specified in the strongest-preference records.
+
+</p>
+<a name="rfc.section.5.2.1"></a><h4><a name="anchor39">5.2.1</a>&nbsp;Long TXT records</h4>
+
+<p>
+ When packed into transport format, TXT records which are longer than 255
+ characters are divided into smaller &lt;character-strings&gt;.
+ (See <a href="#RFC1035">[13]</a> section 3.3 and 3.3.14.) These MUST
+ be reassembled into a single string for processing.
+ Whitespace characters in the base64 encoding are to be ignored.
+
+</p>
+<a name="rfc.section.5.2.2"></a><h4><a name="anchor40">5.2.2</a>&nbsp;Choice of TXT record</h4>
+
+<p>
+ It has been suggested to use the KEY, OPT, CERT, or KX records
+ instead of a TXT record. None is satisfactory.
+
+</p>
+<p> The KEY RR has a protocol field which could be used to indicate a new protocol,
+and an algorithm field which could be used to
+ indicate different contents in the key data. However, the KEY record
+ is clearly not intended for storing what are really authorizations,
+ it is just for identities. Other uses have been discouraged.
+
+</p>
+<p> OPT resource records, as defined in <a href="#RFC2671">[14]</a> are not
+ intended to be used for storage of information. They are not to be loaded,
+ cached or forwarded. They are, therefore, inappropriate for use here.
+
+</p>
+<p>
+ CERT records <a href="#RFC2538">[18]</a> can encode almost any set of
+ information. A custom type code could be used permitting any suitable
+ encoding to be stored, not just X.509. According to
+ the RFC, the certificate RRs are to be signed internally which may add undesirable
+and unnecessary bulk. Larger DNS records may require TCP instead of UDP transfers.
+
+</p>
+<p>
+ At the time of protocol design, the CERT RR was not widely deployed and
+ could not be counted upon. Use of CERT records will be investigated,
+ and may be proposed in a future revision of this document.
+
+</p>
+<p>
+ KX records are ideally suited for use instead of TXT records, but had not been deployed at
+ the time of implementation.
+
+</p>
+<a name="rfc.section.5.3"></a><h4><a name="fqdn">5.3</a>&nbsp;Use of FQDN IDs</h4>
+
+<p>
+ Unfortunately, not every administrator has control over the contents
+ of the reverse-map. Where the initiator (SG-A) has no suitable reverse-map, the
+ authorization record present in the reverse-map of Alice may refer to a
+ FQDN instead of an IP address.
+
+</p>
+<p>
+ In this case, the client's TXT record gives the fully qualified domain
+ name (FQDN) in place of its security gateway's IP address.
+ The initiator should use the ID_FQDN ID-payload in phase 1.
+ A forward lookup for a KEY record on the FQDN must yield the
+ initiator's public key.
+
+</p>
+<p>
+ This method can also be used when the external address of SG-A is
+ dynamic.
+
+</p>
+<p>
+ If SG-A is acting on behalf of Alice, then Alice must still delegate
+ authority for SG-A to do so in her reverse-map. When Alice and SG-A
+ are one and the same (i.e. Alice is acting as an end-node) then there
+ is no need for this when initiating only.
+</p>
+<p>However, Alice must still delegate to herself if she wishes others to
+ initiate OE to her. See <a href="#txtfqdnformat">Format of reverse delegation record (FQDN version)</a>.
+
+</p>
+<a name="rfc.section.5.4"></a><h4><a name="anchor41">5.4</a>&nbsp;Key roll-over</h4>
+
+<p>
+Good cryptographic hygiene says that one should replace public/private key pairs
+periodically. Some administrators may wish to do this as often as daily. Typical DNS
+propagation delays are determined by the SOA Resource Record MINIMUM
+parameter, which controls how long DNS replies may be cached. For reasonable
+operation of DNS servers, administrators usually want this value to be at least several
+hours, sometimes as a long as a day. This presents a problem - a new key MUST
+not be used prior to it propagating through DNS.
+
+</p>
+<p>
+This problem is dealt with by having the Security Gateway generate a new
+public/private key pair at least MINIMUM seconds in advance of using it. It
+then adds this key to the DNS (both as a second KEY record and in additional TXT
+delegation records) at key generation time. Note: only one key is allowed in
+each TXT record.
+
+</p>
+<p>
+When authenticating, all gateways MUST have available all public keys
+that are found in DNS for this entity. This permits the authenticating end
+to check both the key for "today" and the key for "tomorrow". Note that it is
+the end which is creating the signature (possesses the private key) that
+determines which key is to be used.
+
+</p>
+<a name="anchor42"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.6"></a><h3>6.&nbsp;Network address translation interaction</h3>
+
+<p>
+ There are no fundamentally new issues for implementing opportunistic encryption
+ in the presence of network address translation. Rather there are
+ only the regular IPsec issues with NAT traversal.
+
+</p>
+<p>
+ There are several situations to consider for NAT.
+
+</p>
+<a name="rfc.section.6.1"></a><h4><a name="anchor43">6.1</a>&nbsp;Co-located NAT/NAPT</h4>
+
+<p>
+ If SG-A is also performing network address translation on
+ behalf of Alice, then the packet should be translated prior to
+ being subjected to opportunistic encryption. This is in contrast to
+ typically configured tunnels which often exist to bridge islands of
+ private network address space. SG-A will use the translated source
+ address for phase 2, and so SG-B will look up that address to
+ confirm SG-A's authorization.
+
+</p>
+<p> In the case of NAT (1:1), the address space into which the
+ translation is done MUST be globally unique, and control over the
+ reverse-map is assumed.
+ Placing of TXT records is possible.
+
+</p>
+<p> In the case of NAPT (m:1), the address will be SG-A. The ability to get
+ KEY and TXT records in place will again depend upon whether or not
+ there is administrative control over the reverse-map. This is
+ identical to situations involving a single host acting on behalf of
+ itself.
+
+ FQDN style can be used to get around a lack of a reverse-map for
+ initiators only.
+
+</p>
+<a name="rfc.section.6.2"></a><h4><a name="anchor44">6.2</a>&nbsp;SG-A behind NAT/NAPT</h4>
+
+<p>
+ If there is a NAT or NAPT between SG-A and SG-B, then normal IPsec
+ NAT traversal rules apply. In addition to the transport problem
+ which may be solved by other mechanisms, there
+ is the issue of what phase 1 and phase 2 IDs to use. While FQDN could
+ be used during phase 1 for SG-A, there is no appropriate ID for phase 2
+ that permits SG-B to determine that SG-A is in fact authorized to speak for Alice.
+
+</p>
+<a name="rfc.section.6.3"></a><h4><a name="anchor45">6.3</a>&nbsp;Bob is behind a NAT/NAPT</h4>
+
+<p>
+ If Bob is behind a NAT (perhaps SG-B), then there is, in fact, no way for
+ Alice to address a packet to Bob. Not only is opportunistic encryption
+ impossible, but it is also impossible for Alice to initiate any
+ communication to Bob. It may be possible for Bob to initiate in such
+ a situation. This creates an asymmetry, but this is common for
+ NAPT.
+
+</p>
+<a name="anchor46"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.7"></a><h3>7.&nbsp;Host implementations</h3>
+
+<p>
+ When Alice and SG-A are components of the same system, they are
+ considered to be a host implementation. The packet sequence scenario remains unchanged.
+
+</p>
+<p>
+ Components marked Alice are the upper layers (TCP, UDP, the
+ application), and SG-A is the IP layer.
+
+</p>
+<p>
+ Note that tunnel mode is still required.
+
+</p>
+<p>
+ As Alice and SG-A are acting on behalf of themselves, no TXT based delegation
+ record is necessary for Alice to initiate. She can rely on FQDN in a
+ forward map. This is particularly attractive to mobile nodes such as
+ notebook computers at conferences.
+ To respond, Alice/SG-A will still need an entry in Alice's reverse-map.
+
+</p>
+<a name="anchor47"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.8"></a><h3>8.&nbsp;Multi-homing</h3>
+
+<p>
+If there are multiple paths between Alice and Bob (as illustrated in
+the diagram with SG-D), then additional DNS records are required to establish
+authorization.
+
+</p>
+<p>
+In <a href="#networkdiagram">Reference Network Diagram</a>, Alice has two ways to
+exit her network: SG-A and SG-D. Previously SG-D has been ignored. Postulate
+that there are routers between Alice and her set of security gateways
+(denoted by the + signs and the marking of an autonomous system number for
+Alice's network). Datagrams may, therefore, travel to either SG-A or SG-D en
+route to Bob.
+
+</p>
+<p>
+As long as all network connections are in good order, it does not matter how
+datagrams exit Alice's network. When they reach either security gateway, the
+security gateway will find the TXT delegation record in Bob's reverse-map,
+and establish an SA with SG-B.
+
+</p>
+<p>
+SG-B has no problem establishing that either of SG-A or SG-D may speak for
+Alice, because Alice has published two equally weighted TXT delegation records:
+ <br><hr size="1" shade="0">
+<a name="txtmultiexample"></a>
+</p>
+</font><pre>
+X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
+X-IPsec-Server(10)=192.1.1.6 AAJN...j8r9==
+ </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Multiple gateway delegation example for Alice&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
+
+</p>
+<p>
+Alice's routers can now do any kind of load sharing needed. Both SG-A and SG-D send datagrams addressed to Bob through
+their tunnel to SG-B.
+
+</p>
+<p>
+Alice's use of non-equal weight delegation records to show preference of one gateway over another, has relevance only when SG-B
+is initiating to Alice.
+
+</p>
+<p>
+If the precedences are the same, then SG-B has a more difficult time. It
+must decide which of the two tunnels to use. SG-B has no information about
+which link is less loaded, nor which security gateway has more cryptographic
+resources available. SG-B, in fact, has no knowledge of whether both gateways
+are even reachable.
+
+</p>
+<p>
+The Public Internet's default-free zone may well know a good route to Alice,
+but the datagrams that SG-B creates must be addressed to either SG-A or SG-D;
+they can not be addressed to Alice directly.
+
+</p>
+<p>
+SG-B may make a number of choices:
+
+<ol class="text">
+<li>It can ignore the problem and round robin among the tunnels. This
+ causes losses during times when one or the other security gateway is
+ unreachable. If this worries Alice, she can change the weights in her
+ TXT delegation records.
+</li>
+<li>It can send to the gateway from which it most recently received datagrams.
+ This assumes that routing and reachability are symmetrical.
+</li>
+<li>It can listen to BGP information from the Internet to decide which
+ system is currently up. This is clearly much more complicated, but if SG-B is already participating
+ in the BGP peering system to announce Bob, the results data may already
+ be available to it.
+</li>
+<li>It can refuse to negotiate the second tunnel. (It is unclear whether or
+not this is even an option.)
+</li>
+<li>It can silently replace the outgoing portion of the first tunnel with the
+second one while still retaining the incoming portions of both. SG-B can,
+thus, accept datagrams from either SG-A or SG-D, but
+send only to the gateway that most recently re-keyed with it.
+</li>
+</ol><p>
+</p>
+<p>
+Local policy determines which choice SG-B makes. Note that even if SG-B has perfect
+knowledge about the reachability of SG-A and SG-D, Alice may not be reachable
+from either of these security gateways because of internal reachability
+issues.
+
+</p>
+<p>
+FreeS/WAN implements option 5. Implementing a different option is
+being considered. The multi-homing aspects of OE are not well developed and may
+be the subject of a future document.
+
+</p>
+<a name="anchor48"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.9"></a><h3>9.&nbsp;Failure modes</h3>
+
+<a name="rfc.section.9.1"></a><h4><a name="anchor49">9.1</a>&nbsp;DNS failures</h4>
+
+<p>
+ If a DNS server fails to respond, local policy decides
+ whether or not to permit communication in the clear as embodied in
+ the connection classes in <a href="#initclasses">Keying state machine - initiator</a>.
+ It is easy to mount a denial of service attack on the DNS server
+ responsible for a particular network's reverse-map.
+ Such an attack may cause all communication with that network to go in
+ the clear if the policy is permissive, or fail completely
+ if the policy is paranoid. Please note that this is an active attack.
+
+</p>
+<p>
+ There are still many networks
+ that do not have properly configured reverse-maps. Further, if the policy is not to communicate,
+ the above denial of service attack isolates the target network. Therefore, the decision of whether
+or not to permit communication in the clear MUST be a matter of local policy.
+
+</p>
+<a name="rfc.section.9.2"></a><h4><a name="anchor50">9.2</a>&nbsp;DNS configured, IKE failures</h4>
+
+<p>
+ DNS records claim that opportunistic encryption should
+ occur, but the target gateway either does not respond on port 500, or
+ refuses the proposal. This may be because of a crash or reboot, a
+ faulty configuration, or a firewall filtering port 500.
+
+</p>
+<p>
+ The receipt of ICMP port, host or network unreachable
+ messages indicates a potential problem, but MUST NOT cause communication
+ to fail
+ immediately. ICMP messages are easily forged by attackers. If such a
+ forgery caused immediate failure, then an active attacker could easily
+ prevent any
+ encryption from ever occurring, possibly preventing all communication.
+
+</p>
+<p>
+ In these situations a clear log should be produced
+ and local policy should dictate if communication is then
+ permitted in the clear.
+
+</p>
+<a name="rfc.section.9.3"></a><h4><a name="anchor51">9.3</a>&nbsp;System reboots</h4>
+
+<p>
+Tunnels sometimes go down because the remote end crashes,
+disconnects, or has a network link break. In general there is no
+notification of this. Even in the event of a crash and successful reboot,
+other SGs don't hear about it unless the rebooted SG has specific
+reason to talk to them immediately. Over-quick response to temporary
+network outages is undesirable. Note that a tunnel can be torn
+down and then re-established without any effect visible to the user
+except a pause in traffic. On the other hand, if one end reboots,
+the other end can't get datagrams to it at all (except via
+IKE) until the situation is noticed. So a bias toward quick
+response is appropriate even at the cost of occasional
+false alarms.
+
+</p>
+<p>
+A mechanism for recovery after reboot is a topic of current research and is not specified in this
+document.
+
+</p>
+<p>
+A deliberate shutdown should include an attempt, using deletes, to notify all other SGs
+currently connected by phase 1 SAs that communication is
+about to fail. Again, a remote SG will assume this is a teardown. Attempts by the
+remote SGs to negotiate new tunnels as replacements should be ignored. When possible,
+SGs should attempt to preserve information about currently-connected SGs in non-volatile storage, so
+that after a crash, an Initial-Contact can be sent to previous partners to
+indicate loss of all previously established connections.
+
+</p>
+<a name="anchor52"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.10"></a><h3>10.&nbsp;Unresolved issues</h3>
+
+<a name="rfc.section.10.1"></a><h4><a name="anchor53">10.1</a>&nbsp;Control of reverse DNS</h4>
+
+<p>
+ The method of obtaining information by reverse DNS lookup causes
+ problems for people who cannot control their reverse DNS
+ bindings. This is an unresolved problem in this version, and is out
+ of scope.
+
+</p>
+<a name="anchor54"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.11"></a><h3>11.&nbsp;Examples</h3>
+
+<a name="rfc.section.11.1"></a><h4><a name="anchor55">11.1</a>&nbsp;Clear-text usage (permit policy)</h4>
+
+<p>
+Two example scenarios follow. In the first example GW-A
+(Gateway A) and GW-B (Gateway B) have always-clear-text policies, and in the second example they have an OE
+policy.
+
+</p><br><hr size="1" shade="0">
+<a name="regulartiming"></a>
+</font><pre>
+ Alice SG-A DNS SG-B Bob
+ (1)
+ ------(2)-------------->
+ &lt;-----(3)---------------
+ (4)----(5)----->
+ ----------(6)------>
+ ------(7)----->
+ &lt;------(8)------
+ &lt;----------(9)------
+ &lt;----(10)-----
+ (11)----------->
+ ----------(12)----->
+ -------------->
+ &lt;---------------
+ &lt;-------------------
+ &lt;-------------
+ </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Timing of regular transaction&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
+
+<p>
+Alice wants to communicate with Bob. Perhaps she wants to retrieve a
+web page from Bob's web server. In the absence of opportunistic
+encryptors, the following events occur:
+
+<blockquote class="text"><dl>
+<dt>(1)</dt>
+<dd>Human or application 'clicks' with a name.
+</dd>
+<dt>(2)</dt>
+<dd>Application looks up name in DNS to get IP address.
+</dd>
+<dt>(3)</dt>
+<dd>Resolver returns A record to application.
+</dd>
+<dt>(4)</dt>
+<dd>Application starts a TCP session or UDP session and OS sends datagram.
+</dd>
+<dt>(5)</dt>
+<dd>Datagram is seen at first gateway from Alice (SG-A). (SG-A
+makes a transition through Empty connection to always-clear connection and
+instantiates a pass-through policy at the forwarding plane.)
+</dd>
+<dt>(6)</dt>
+<dd>Datagram is seen at last gateway before Bob (SG-B).
+</dd>
+<dt>(7)</dt>
+<dd>First datagram from Alice is seen by Bob.
+</dd>
+<dt>(8)</dt>
+<dd>First return datagram is sent by Bob.
+</dd>
+<dt>(9)</dt>
+<dd>Datagram is seen at Bob's gateway. (SG-B makes a transition through
+Empty connection to always-clear connection and instantiates a pass-through
+policy at the forwarding plane.)
+</dd>
+<dt>(10)</dt>
+<dd>Datagram is seen at Alice's gateway.
+</dd>
+<dt>(11)</dt>
+<dd>OS hands datagram to application. Alice sends another datagram.
+</dd>
+<dt>(12)</dt>
+<dd>A second datagram traverses the Internet.
+</dd>
+</dl></blockquote><p>
+</p>
+<a name="rfc.section.11.2"></a><h4><a name="anchor56">11.2</a>&nbsp;Opportunistic encryption</h4>
+
+<p>
+In the presence of properly configured opportunistic encryptors, the
+event list is extended.
+
+<br><hr size="1" shade="0">
+<a name="opportunistictiming"></a>
+</p>
+</font><pre>
+ Alice SG-A DNS SG-B Bob
+ (1)
+ ------(2)-------------->
+ &lt;-----(3)---------------
+ (4)----(5)----->+
+ ----(5B)->
+ &lt;---(5C)--
+ ~~~~~~~~~~~~~(5D)~~~>
+ &lt;~~~~~~~~~~~~(5E1)~~~
+ ~~~~~~~~~~~~~(5E2)~~>
+ &lt;~~~~~~~~~~~~(5E3)~~~
+ #############(5E4)##>
+ &lt;############(5E5)###
+ &lt;----(5F1)--
+ -----(5F2)->
+ #############(5G1)##>
+ &lt;----(5H1)--
+ -----(5H2)->
+ &lt;############(5G2)###
+ #############(5G3)##>
+ ============(6)====>
+ ------(7)----->
+ &lt;------(8)------
+ &lt;==========(9)======
+ &lt;-----(10)----
+ (11)----------->
+ ==========(12)=====>
+ -------------->
+ &lt;---------------
+ &lt;===================
+ &lt;-------------
+ </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Timing of opportunistic encryption transaction&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
+
+<blockquote class="text"><dl>
+<dt>(1)</dt>
+<dd>Human or application clicks with a name.
+</dd>
+<dt>(2)</dt>
+<dd>Application initiates DNS mapping.
+</dd>
+<dt>(3)</dt>
+<dd>Resolver returns A record to application.
+</dd>
+<dt>(4)</dt>
+<dd>Application starts a TCP session or UDP.
+</dd>
+<dt>(5)</dt>
+<dd>SG-A (host or SG) sees datagram to target, and buffers it.
+</dd>
+<dt>(5B)</dt>
+<dd>SG-A asks DNS for TXT record.
+</dd>
+<dt>(5C)</dt>
+<dd>DNS returns TXT record(s).
+</dd>
+<dt>(5D)</dt>
+<dd>Initial IKE Main Mode Packet goes out.
+</dd>
+<dt>(5E)</dt>
+<dd>IKE ISAKMP phase 1 succeeds.
+</dd>
+<dt>(5F)</dt>
+<dd>SG-B asks DNS for TXT record to prove SG-A is an agent for Alice.
+</dd>
+<dt>(5G)</dt>
+<dd>IKE phase 2 negotiation.
+</dd>
+<dt>(5H)</dt>
+<dd>DNS lookup by responder (SG-B).
+</dd>
+<dt>(6)</dt>
+<dd>Buffered datagram is sent by SG-A.
+</dd>
+<dt>(7)</dt>
+<dd>Datagram is received by SG-B, decrypted, and sent to Bob.
+</dd>
+<dt>(8)</dt>
+<dd>Bob replies, and datagram is seen by SG-B.
+</dd>
+<dt>(9)</dt>
+<dd>SG-B already has tunnel up with SG-A, and uses it.
+</dd>
+<dt>(10)</dt>
+<dd>SG-A decrypts datagram and gives it to Alice.
+</dd>
+<dt>(11)</dt>
+<dd>Alice receives datagram. Sends new packet to Bob.
+</dd>
+<dt>(12)</dt>
+<dd>SG-A gets second datagram, sees that tunnel is up, and uses it.
+</dd>
+</dl></blockquote><p>
+</p>
+<p>
+ For the purposes of this section, we will describe only the changes that
+ occur between <a href="#regulartiming">Timing of regular transaction</a> and
+ <a href="#opportunistictiming">Timing of opportunistic encryption transaction</a>. This corresponds to time points 5, 6, 7, 9 and 10 on the list above.
+
+</p>
+<a name="rfc.section.11.2.1"></a><h4><a name="anchor57">11.2.1</a>&nbsp;(5) IPsec datagram interception</h4>
+
+<p>
+ At point (5), SG-A intercepts the datagram because this source/destination pair lacks a policy
+(the non-existent policy state). SG-A creates a hold policy, and buffers the datagram. SG-A requests keys from the keying daemon.
+
+</p>
+<a name="rfc.section.11.2.2"></a><h4><a name="anchor58">11.2.2</a>&nbsp;(5B) DNS lookup for TXT record</h4>
+
+<p>
+ SG-A's IKE daemon, having looked up the source/destination pair in the connection
+ class list, creates a new Potential OE connection instance. SG-A starts DNS
+ queries.
+
+</p>
+<a name="rfc.section.11.2.3"></a><h4><a name="anchor59">11.2.3</a>&nbsp;(5C) DNS returns TXT record(s)</h4>
+
+<p>
+ DNS returns properly formed TXT delegation records, and SG-A's IKE daemon
+ causes this instance to make a transition from Potential OE connection to Pending OE
+ connection.
+
+</p>
+<p>
+ Using the example above, the returned record might contain:
+
+ <br><hr size="1" shade="0">
+<a name="txtexample"></a>
+</p>
+</font><pre>
+X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
+ </pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+<table border="0" cellpadding="0" cellspacing="2" align="center"><tr><td align="center"><font face="monaco, MS Sans Serif" size="1"><b>&nbsp;Example of reverse delegation record for Bob&nbsp;</b></font><br></td></tr></table><hr size="1" shade="0">
+
+ with SG-B's IP address and public key listed.
+
+</p>
+<a name="rfc.section.11.2.4"></a><h4><a name="anchor60">11.2.4</a>&nbsp;(5D) Initial IKE main mode packet goes out</h4>
+
+<p>Upon entering Pending OE connection, SG-A sends the initial ISAKMP
+ message with proposals. See <a href="#phase1id">Phase 1 parameters</a>.
+
+</p>
+<a name="rfc.section.11.2.5"></a><h4><a name="anchor61">11.2.5</a>&nbsp;(5E1) Message 2 of phase 1 exchange</h4>
+
+<p>
+ SG-B receives the message. A new connection instance is created in the
+ unauthenticated OE peer state.
+
+</p>
+<a name="rfc.section.11.2.6"></a><h4><a name="anchor62">11.2.6</a>&nbsp;(5E2) Message 3 of phase 1 exchange</h4>
+
+<p>
+ SG-A sends a Diffie-Hellman exponent. This is an internal state of the
+ keying daemon.
+
+</p>
+<a name="rfc.section.11.2.7"></a><h4><a name="anchor63">11.2.7</a>&nbsp;(5E3) Message 4 of phase 1 exchange</h4>
+
+<p>
+ SG-B responds with a Diffie-Hellman exponent. This is an internal state of the
+ keying protocol.
+
+</p>
+<a name="rfc.section.11.2.8"></a><h4><a name="anchor64">11.2.8</a>&nbsp;(5E4) Message 5 of phase 1 exchange</h4>
+
+<p>
+ SG-A uses the phase 1 SA to send its identity under encryption.
+ The choice of identity is discussed in <a href="#phase1id">Phase 1 parameters</a>.
+ This is an internal state of the keying protocol.
+
+</p>
+<a name="rfc.section.11.2.9"></a><h4><a name="anchor65">11.2.9</a>&nbsp;(5F1) Responder lookup of initiator key</h4>
+
+<p>
+ SG-B asks DNS for the public key of the initiator.
+ DNS looks for a KEY record by IP address in the reverse-map.
+ That is, a KEY resource record is queried for 4.1.1.192.in-addr.arpa
+ (recall that SG-A's external address is 192.1.1.4).
+ SG-B uses the resulting public key to authenticate the initiator. See <a href="#KEY">Use of KEY record</a> for further details.
+
+</p>
+<a name="rfc.section.11.2.10"></a><h4><a name="anchor66">11.2.10</a>&nbsp;(5F2) DNS replies with public key of initiator</h4>
+
+<p>
+Upon successfully authenticating the peer, the connection instance makes a
+transition to authenticated OE peer on SG-B.
+
+</p>
+<p>
+The format of the TXT record returned is described in
+<a href="#TXT">Use of TXT delegation record</a>.
+
+</p>
+<a name="rfc.section.11.2.11"></a><h4><a name="anchor67">11.2.11</a>&nbsp;(5E5) Responder replies with ID and authentication</h4>
+
+<p>
+ SG-B sends its ID along with authentication material. This is an internal
+ state for the keying protocol.
+
+</p>
+<a name="rfc.section.11.2.12"></a><h4><a name="anchor68">11.2.12</a>&nbsp;(5G) IKE phase 2</h4>
+
+<a name="rfc.section.11.2.12.1"></a><h4><a name="anchor69">11.2.12.1</a>&nbsp;(5G1) Initiator proposes tunnel</h4>
+
+<p>
+ Having established mutually agreeable authentications (via KEY) and
+ authorizations (via TXT), SG-A proposes to create an IPsec tunnel for
+ datagrams transiting from Alice to Bob. This tunnel is established only for
+ the Alice/Bob combination, not for any subnets that may be behind SG-A and SG-B.
+
+</p>
+<a name="rfc.section.11.2.12.2"></a><h4><a name="anchor70">11.2.12.2</a>&nbsp;(5H1) Responder determines initiator's authority</h4>
+
+<p>
+ While the identity of SG-A has been established, its authority to
+ speak for Alice has not yet been confirmed. SG-B does a reverse
+ lookup on Alice's address for a TXT record.
+
+</p>
+<p>Upon receiving this specific proposal, SG-B's connection instance
+ makes a transition into the potential OE connection state. SG-B may already have an
+ instance, and the check is made as described above.
+</p>
+<a name="rfc.section.11.2.12.3"></a><h4><a name="anchor71">11.2.12.3</a>&nbsp;(5H2) DNS replies with TXT record(s)</h4>
+
+<p>
+ The returned key and IP address should match that of SG-A.
+
+</p>
+<a name="rfc.section.11.2.12.4"></a><h4><a name="anchor72">11.2.12.4</a>&nbsp;(5G2) Responder agrees to proposal</h4>
+
+<p>
+ Should additional communication occur between, for instance, Dave and Bob using
+ SG-A and SG-B, a new tunnel (phase 2 SA) would be established. The phase 1 SA
+ may be reusable.
+
+</p>
+<p>SG-A, having successfully keyed the tunnel, now makes a transition from
+ Pending OE connection to Keyed OE connection.
+
+</p>
+<p>The responder MUST setup the inbound IPsec SAs before sending its reply.
+</p>
+<a name="rfc.section.11.2.12.5"></a><h4><a name="anchor73">11.2.12.5</a>&nbsp;(5G3) Final acknowledgment from initiator</h4>
+
+<p>
+ The initiator agrees with the responder's choice and sets up the tunnel.
+ The initiator sets up the inbound and outbound IPsec SAs.
+
+</p>
+<p>
+ The proper authorization returned with keys prompts SG-B to make a transition
+ to the keyed OE connection state.
+
+</p>
+<p>Upon receipt of this message, the responder may now setup the outbound
+ IPsec SAs.
+</p>
+<a name="rfc.section.11.2.13"></a><h4><a name="anchor74">11.2.13</a>&nbsp;(6) IPsec succeeds, and sets up tunnel for communication between Alice and Bob</h4>
+
+<p>
+ SG-A sends the datagram saved at step (5) through the newly created
+ tunnel to SG-B, where it gets decrypted and forwarded.
+ Bob receives it at (7) and replies at (8).
+
+</p>
+<a name="rfc.section.11.2.14"></a><h4><a name="anchor75">11.2.14</a>&nbsp;(9) SG-B already has tunnel up with G1 and uses it</h4>
+
+<p>
+ At (9), SG-B has already established an SPD entry mapping Bob->Alice via a
+ tunnel, so this tunnel is simply applied. The datagram is encrypted to SG-A,
+ decrypted by SG-A and passed to Alice at (10).
+
+</p>
+<a name="securityconsiderations"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.12"></a><h3>12.&nbsp;Security considerations</h3>
+
+<a name="rfc.section.12.1"></a><h4><a name="anchor76">12.1</a>&nbsp;Configured vs opportunistic tunnels</h4>
+
+<p>
+ Configured tunnels are those which are setup using bilateral mechanisms: exchanging
+public keys (raw RSA, DSA, PKIX), pre-shared secrets, or by referencing keys that
+are in known places (distinguished name from LDAP, DNS). These keys are then used to
+configure a specific tunnel.
+
+</p>
+<p>
+A pre-configured tunnel may be on all the time, or may be keyed only when needed.
+The end points of the tunnel are not necessarily static: many mobile
+applications (road warrior) are considered to be configured tunnels.
+
+</p>
+<p>
+The primary characteristic is that configured tunnels are assigned specific
+security properties. They may be trusted in different ways relating to exceptions to
+firewall rules, exceptions to NAT processing, and to bandwidth or other quality of service restrictions.
+
+</p>
+<p>
+Opportunistic tunnels are not inherently trusted in any strong way. They are
+created without prior arrangement. As the two parties are strangers, there
+MUST be no confusion of datagrams that arrive from opportunistic peers and
+those that arrive from configured tunnels. A security gateway MUST take care
+that an opportunistic peer can not impersonate a configured peer.
+
+</p>
+<p>
+Ingress filtering MUST be used to make sure that only datagrams authorized by
+negotiation (and the concomitant authentication and authorization) are
+accepted from a tunnel. This is to prevent one peer from impersonating another.
+
+</p>
+<p>
+An implementation suggestion is to treat opportunistic tunnel
+datagrams as if they arrive on a logical interface distinct from other
+configured tunnels. As the number of opportunistic tunnels that may be
+created automatically on a system is potentially very high, careful attention
+to scaling should be taken into account.
+
+</p>
+<p>
+As with any IKE negotiation, opportunistic encryption cannot be secure
+without authentication. Opportunistic encryption relies on DNS for its
+authentication information and, therefore, cannot be fully secure without
+a secure DNS. Without secure DNS, opportunistic encryption can protect against passive
+eavesdropping but not against active man-in-the-middle attacks.
+
+</p>
+<a name="rfc.section.12.2"></a><h4><a name="anchor77">12.2</a>&nbsp;Firewalls versus Opportunistic Tunnels</h4>
+
+<p>
+ Typical usage of per datagram access control lists is to implement various
+kinds of security gateways. These are typically called "firewalls".
+
+</p>
+<p>
+ Typical usage of a virtual private network (VPN) within a firewall is to
+bypass all or part of the access controls between two networks. Additional
+trust (as outlined in the previous section) is given to datagrams that arrive
+in the VPN.
+
+</p>
+<p>
+ Datagrams that arrive via opportunistically configured tunnels MUST not be
+trusted. Any security policy that would apply to a datagram arriving in the
+clear SHOULD also be applied to datagrams arriving opportunistically.
+
+</p>
+<a name="rfc.section.12.3"></a><h4><a name="anchor78">12.3</a>&nbsp;Denial of service</h4>
+
+<p>
+ There are several different forms of denial of service that an implementor
+ should concern themselves with. Most of these problems are shared with
+ security gateways that have large numbers of mobile peers (road warriors).
+
+</p>
+<p>
+ The design of ISAKMP/IKE, and its use of cookies, defend against many kinds
+ of denial of service. Opportunism changes the assumption that if the phase 1 (ISAKMP)
+ SA is authenticated, that it was worthwhile creating. Because the gateway will communicate with any machine, it is
+ possible to form phase 1 SAs with any machine on the Internet.
+
+</p>
+<a name="anchor79"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.13"></a><h3>13.&nbsp;IANA Considerations</h3>
+
+<p>
+ There are no known numbers which IANA will need to manage.
+
+</p>
+<a name="anchor80"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.14"></a><h3>14.&nbsp;Acknowledgments</h3>
+
+<p>
+ Substantive portions of this document are based upon previous work by
+ Henry Spencer.
+
+</p>
+<p>
+ Thanks to Tero Kivinen, Sandy Harris, Wes Hardarker, Robert Moskowitz,
+ Jakob Schlyter, Bill Sommerfeld, John Gilmore and John Denker for their
+ comments and constructive criticism.
+
+</p>
+<p>
+ Sandra Hoffman and Bill Dickie did the detailed proof reading and editing.
+
+</p>
+<a name="rfc.references1"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<h3>Normative references</h3>
+<table width="99%" border="0">
+<tr><td class="author-text" valign="top"><b><a name="OEspec">[1]</a></b></td>
+<td class="author-text"><a href="mailto:hugh@mimosa.com">Redelmeier, D.</a> and <a href="mailto:henry@spsystems.net">H. Spencer</a>, "Opportunistic Encryption", paper http://www.freeswan.org/freeswan_trees/freeswan-1.91/doc/opportunism.spec, May 2001.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC0791">[2]</a></b></td>
+<td class="author-text">Defense Advanced Research Projects Agency (DARPA), Information Processing Techniques Office and University of Southern California (USC)/Information Sciences Institute, "<a href="ftp://ftp.isi.edu/in-notes/rfc791.txt">Internet Protocol</a>", STD 5, RFC 791, September 1981.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC1009">[3]</a></b></td>
+<td class="author-text"><a href="mailto:">Braden, R.</a> and <a href="mailto:">J. Postel</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1009.txt">Requirements for Internet gateways</a>", RFC 1009, June 1987.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC1984">[4]</a></b></td>
+<td class="author-text">IAB, IESG, <a href="mailto:brian@dxcoms.cern.ch">Carpenter, B.</a> and <a href="mailto:fred@cisco.com">F. Baker</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1984.txt">IAB and IESG Statement on Cryptographic Technology and the Internet</a>", RFC 1984, August 1996.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2119">[5]</a></b></td>
+<td class="author-text"><a href="mailto:-">Bradner, S.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2119.txt">Key words for use in RFCs to Indicate Requirement Levels</a>", BCP 14, RFC 2119, March 1997.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2367">[6]</a></b></td>
+<td class="author-text"><a href="mailto:danmcd@eng.sun.com">McDonald, D.</a>, <a href="mailto:cmetz@inner.net">Metz, C.</a> and <a href="mailto:phan@itd.nrl.navy.mil">B. Phan</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2367.txt">PF_KEY Key Management API, Version 2</a>", RFC 2367, July 1998.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2401">[7]</a></b></td>
+<td class="author-text"><a href="mailto:kent@bbn.com">Kent, S.</a> and <a href="mailto:rja@corp.home.net">R. Atkinson</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2401.txt">Security Architecture for the Internet Protocol</a>", RFC 2401, November 1998.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2407">[8]</a></b></td>
+<td class="author-text"><a href="mailto:ddp@network-alchemy.com">Piper, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2407.txt">The Internet IP Security Domain of Interpretation for ISAKMP</a>", RFC 2407, November 1998.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2408">[9]</a></b></td>
+<td class="author-text"><a href="mailto:wdm@tycho.ncsc.mil">Maughan, D.</a>, <a href="mailto:mss@tycho.ncsc.mil">Schneider, M.</a> and <a href="er@raba.com">M. Schertler</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2408.txt">Internet Security Association and Key Management Protocol (ISAKMP)</a>", RFC 2408, November 1998.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2409">[10]</a></b></td>
+<td class="author-text"><a href="mailto:dharkins@cisco.com">Harkins, D.</a> and <a href="mailto:carrel@ipsec.org">D. Carrel</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2409.txt">The Internet Key Exchange (IKE)</a>", RFC 2409, November 1998.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC3526">[11]</a></b></td>
+<td class="author-text"><a href="mailto:kivinen@ssh.fi">Kivinen, T.</a> and <a href="mailto:mrskojo@cc.helsinki.fi">M. Kojo</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc3526.txt">More MODP Diffie-Hellman groups for IKE</a>", RFC 3526, March 2003.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC1034">[12]</a></b></td>
+<td class="author-text">Mockapetris, P., "<a href="ftp://ftp.isi.edu/in-notes/rfc1034.txt">Domain names - concepts and facilities</a>", STD 13, RFC 1034, November 1987.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC1035">[13]</a></b></td>
+<td class="author-text"><a href="mailto:">Mockapetris, P.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1035.txt">Domain names - implementation and specification</a>", STD 13, RFC 1035, November 1987.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2671">[14]</a></b></td>
+<td class="author-text"><a href="mailto:vixie@isc.org">Vixie, P.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2671.txt">Extension Mechanisms for DNS (EDNS0)</a>", RFC 2671, August 1999.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC1464">[15]</a></b></td>
+<td class="author-text"><a href="mailto:rosenbaum@lkg.dec.com">Rosenbaum, R.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1464.txt">Using the Domain Name System To Store Arbitrary String Attributes</a>", RFC 1464, May 1993.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2535">[16]</a></b></td>
+<td class="author-text"><a href="mailto:dee3@us.ibm.com">Eastlake, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2535.txt">Domain Name System Security Extensions</a>", RFC 2535, March 1999.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC3110">[17]</a></b></td>
+<td class="author-text">Eastlake, D., "<a href="ftp://ftp.isi.edu/in-notes/rfc3110.txt">RSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)</a>", RFC 3110, May 2001.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2538">[18]</a></b></td>
+<td class="author-text"><a href="mailto:dee3@us.ibm.com">Eastlake, D.</a> and <a href="mailto:ogud@tislabs.com">O. Gudmundsson</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2538.txt">Storing Certificates in the Domain Name System (DNS)</a>", RFC 2538, March 1999.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2748">[19]</a></b></td>
+<td class="author-text"><a href="mailto:David.Durham@intel.com">Durham, D.</a>, <a href="mailto:jboyle@Level3.net">Boyle, J.</a>, <a href="mailto:ronc@cisco.com">Cohen, R.</a>, <a href="mailto:herzog@iphighway.com">Herzog, S.</a>, <a href="mailto:rajan@research.att.com">Rajan, R.</a> and <a href="mailto:asastry@cisco.com">A. Sastry</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2748.txt">The COPS (Common Open Policy Service) Protocol</a>", RFC 2748, January 2000.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2663">[20]</a></b></td>
+<td class="author-text"><a href="mailto:srisuresh@lucent.com">Srisuresh, P.</a> and <a href="mailto:holdrege@lucent.com">M. Holdrege</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2663.txt">IP Network Address Translator (NAT) Terminology and Considerations</a>", RFC 2663, August 1999.</td></tr>
+</table>
+
+<a name="rfc.authors"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<h3>Authors' Addresses</h3>
+<table width="99%" border="0" cellpadding="0" cellspacing="0">
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">Michael C. Richardson</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">Sandelman Software Works</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">470 Dawson Avenue</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">Ottawa, ON K1Z 5V7</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">CA</td></tr>
+<tr><td class="author" align="right">EMail:&nbsp;</td>
+<td class="author-text"><a href="mailto:mcr@sandelman.ottawa.on.ca">mcr@sandelman.ottawa.on.ca</a></td></tr>
+<tr><td class="author" align="right">URI:&nbsp;</td>
+<td class="author-text"><a href="http://www.sandelman.ottawa.on.ca/">http://www.sandelman.ottawa.on.ca/</a></td></tr>
+<tr cellpadding="3"><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">D. Hugh Redelmeier</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">Mimosa</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">Toronto, ON</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">CA</td></tr>
+<tr><td class="author" align="right">EMail:&nbsp;</td>
+<td class="author-text"><a href="mailto:hugh@mimosa.com">hugh@mimosa.com</a></td></tr>
+</table>
+<a name="rfc.copyright"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<h3>Full Copyright Statement</h3>
+<p class='copyright'>
+Copyright (C) The Internet Society (2003). All Rights Reserved.</p>
+<p class='copyright'>
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published and
+distributed, in whole or in part, without restriction of any kind,
+provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.</p>
+<p class='copyright'>
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.</p>
+<p class='copyright'>
+This document and the information contained herein is provided on an
+&quot;AS IS&quot; basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.</p>
+<h3>Acknowledgement</h3>
+<p class='copyright'>
+Funding for the RFC Editor function is currently provided by the
+Internet Society.</p>
+</font></body></html>
diff --git a/doc/src/draft-richardson-ipsec-opportunistic.xml b/doc/src/draft-richardson-ipsec-opportunistic.xml
new file mode 100644
index 000000000..d587df693
--- /dev/null
+++ b/doc/src/draft-richardson-ipsec-opportunistic.xml
@@ -0,0 +1,2519 @@
+<?xml version="1.0"?>
+<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
+<?rfc toc="yes"?>
+<?rfc tocdepth='2' ?>
+
+<rfc ipr="full2026" docName="draft-richardson-ipsec-opportunistic-12.txt">
+
+<front>
+ <area>Security</area>
+ <workgroup>Independent submission</workgroup>
+ <title abbrev="opportunistic">
+ Opportunistic Encryption using The Internet Key Exchange (IKE)
+ </title>
+
+ <author initials="M." surname="Richardson" fullname="Michael C. Richardson">
+ <organization abbrev="SSW">Sandelman Software Works</organization>
+ <address>
+ <postal>
+ <street>470 Dawson Avenue</street>
+ <city>Ottawa</city>
+ <region>ON</region>
+ <code>K1Z 5V7</code>
+ <country>CA</country>
+ </postal>
+ <email>mcr@sandelman.ottawa.on.ca</email>
+ <uri>http://www.sandelman.ottawa.on.ca/</uri>
+ </address>
+ </author>
+
+ <author initials="D.H." surname="Redelmeier"
+ fullname="D. Hugh Redelmeier">
+ <organization abbrev="Mimosa">Mimosa</organization>
+ <address>
+ <postal>
+ <city>Toronto</city>
+ <region>ON</region>
+ <country>CA</country>
+ </postal>
+ <email>hugh@mimosa.com</email>
+ </address>
+ </author>
+
+ <date month="June" year="2003"></date>
+
+<abstract>
+ <t>
+This document describes opportunistic encryption (OE) using the Internet Key
+Exchange (IKE) and IPsec.
+Each system administrator adds new
+resource records to his or her Domain Name System (DNS) to support
+opportunistic encryption. The objective is to allow encryption for secure communication without
+any pre-arrangement specific to the pair of systems involved.
+ </t>
+ <t>
+DNS is used to distribute the public keys of each
+system involved. This is resistant to passive attacks. The use of DNS
+Security (DNSSEC) secures this system against active attackers as well.
+ </t>
+ <t>
+As a result, the administrative overhead is reduced
+from the square of the number of systems to a linear dependence, and it becomes
+possible to make secure communication the default even
+when the partner is not known in advance.
+ </t>
+ <t>
+This document is offered up as an Informational RFC.
+ </t>
+</abstract>
+
+</front>
+
+<middle>
+
+<section title="Introduction">
+
+<section title="Motivation">
+
+<t>
+The objective of opportunistic encryption is to allow encryption without
+any pre-arrangement specific to the pair of systems involved. Each
+system administrator adds
+public key information to DNS records to support opportunistic
+encryption and then enables this feature in the nodes' IPsec stack.
+Once this is done, any two such nodes can communicate securely.
+</t>
+
+<t>
+This document describes opportunistic encryption as designed and
+implemented by the Linux FreeS/WAN project in revisions up and including 2.00.
+Note that 2.01 and beyond implements RFC3445, in a backward compatible way.
+For project information, see http://www.freeswan.org.
+</t>
+
+ <t>
+The Internet Architecture Board (IAB) and Internet Engineering
+Steering Group (IESG) have taken a strong stand that the Internet
+should use powerful encryption to provide security and
+privacy <xref target="RFC1984" />.
+The Linux FreeS/WAN project attempts to provide a practical means to implement this policy.
+ </t>
+
+ <t>
+The project uses the IPsec, ISAKMP/IKE, DNS and DNSSEC
+protocols because they are
+standardized, widely available and can often be deployed very easily
+without changing hardware or software or retraining users.
+ </t>
+
+ <t>
+The extensions to support opportunistic encryption are simple. No
+changes to any on-the-wire formats are needed. The only changes are to
+the policy decision making system. This means that opportunistic
+encryption can be implemented with very minimal changes to an existing
+IPsec implementation.
+ </t>
+
+ <t>
+Opportunistic encryption creates a "fax effect". The proliferation
+of the fax machine was possible because it did not require that everyone
+buy one overnight. Instead, as each person installed one, the value
+of having one increased - as there were more people that could receive faxes.
+Once opportunistic encryption is installed it
+automatically recognizes
+other boxes using opportunistic encryption, without any further configuration
+by the network
+administrator. So, as opportunistic encryption software is installed on more
+boxes, its value
+as a tool increases.
+</t>
+
+ <t>
+This document describes the infrastructure to permit deployment of
+Opportunistic Encryption.
+</t>
+
+ <t>
+The term S/WAN is a trademark of RSA Data Systems, and is used with permission
+by this project.
+ </t>
+
+</section>
+
+<section title="Types of network traffic">
+ <t>
+ To aid in understanding the relationship between security processing and IPsec
+ we divide network traffic into four categories:
+ <list style="hanging">
+ <t hangText="* Deny:"> networks to which traffic is always forbidden.</t>
+ <t hangText="* Permit:"> networks to which traffic in the clear is permitted.</t>
+ <t hangText="* Opportunistic tunnel:"> networks to which traffic is encrypted if possible, but otherwise is in the clear
+ or fails depending on the default policy in place.
+ </t>
+ <t hangText="* Configured tunnel:"> networks to which traffic
+must be encrypted, and traffic in the clear is never permitted.
+A Virtual Private Network (VPN) is a form of configured tunnel.
+</t>
+ </list>
+ </t>
+
+<t>
+Traditional firewall devices handle the first two categories.
+No authentication is required.
+The permit policy is currently the default on the Internet.
+</t>
+
+<t>
+This document describes the third category - opportunistic tunnel, which is
+proposed as the new default for the Internet.
+</t>
+
+<t>
+ Category four, encrypt traffic or drop it, requires authentication of the
+ end points. As the number of end points is typically bounded and is typically
+ under a single authority, arranging for distribution of
+ authentication material, while difficult, does not require any new
+ technology. The mechanism described here provides an additional way to
+ distribute the authentication materials, that of a public key method that does not
+ require deployment of an X.509 based infrastructure.
+</t>
+<t>
+Current Virtual Private Networks can often be replaced by an "OE paranoid"
+policy as described herein.
+</t>
+</section>
+
+<section title="Peer authentication in opportunistic encryption">
+
+ <t>
+ Opportunistic encryption creates tunnels between nodes that
+ are essentially strangers. This is done without any prior bilateral
+ arrangement.
+ There is, therefore, the difficult question of how one knows to whom one is
+ talking.
+ </t>
+
+ <t>
+ One possible answer is that since no useful
+ authentication can be done, none should be tried. This mode of operation is
+ named "anonymous encryption". An active man-in-the-middle attack can be
+ used to thwart the privacy of this type of communication.
+ Without peer authentication, there is no way to prevent this kind of attack.
+ </t>
+
+ <t>
+Although a useful mode, anonymous encryption is not the goal of this
+project. Simpler methods are available that can achieve anonymous
+encryption only, but authentication of the peer is a desireable goal.
+The latter is achieved through key distribution in DNS, leveraging upon
+the authentication of the DNS in DNSSEC.
+</t>
+
+ <t>
+ Peers are, therefore, authenticated with DNSSEC when available. Local policy
+determines how much trust to extend when DNSSEC is not available.
+ </t>
+
+ <t>
+ However, an essential premise of building private connections with
+ strangers is that datagrams received through opportunistic tunnels
+ are no more special than datagrams that arrive in the clear.
+ Unlike in a VPN, these datagrams should not be given any special
+ exceptions when it comes to auditing, further authentication or
+ firewalling.
+ </t>
+
+ <t>
+ When initiating outbound opportunistic encryption, local
+ configuration determines what happens if tunnel setup fails. It may be that
+ the packet goes out in the clear, or it may be dropped.
+ </t>
+
+ </section>
+
+<section title="Use of RFC2119 terms">
+<t>
+ The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD,
+ SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this
+ document, are to be interpreted as described in <xref target="RFC2119" />
+</t>
+</section>
+
+</section>
+
+<section title="Overview">
+
+ <section title="Reference diagram">
+
+ <figure anchor="networkdiagram" title="Reference Network Diagram">
+ <preamble>The following network diagram is used in the rest of
+ this document as the canonical diagram:</preamble>
+ <artwork>
+ [Q] [R]
+ . . AS2
+ [A]----+----[SG-A].......+....+.......[SG-B]-------[B]
+ | ......
+ AS1 | ..PI..
+ | ......
+ [D]----+----[SG-D].......+....+.......[C] AS3
+
+
+ </artwork>
+ <postamble></postamble>
+
+ </figure>
+
+ <t>
+ In this diagram, there are four end-nodes: A, B, C and D.
+ There are three security gateways, SG-A, SG-B, SG-D. A, D, SG-A and
+ SG-D are part
+ of the same administrative authority, AS1. SG-A and SG-D are on two
+ different exit
+ paths from organization 1. SG-B/B is an independent organization, AS2.
+ Nodes Q and R are nodes on the Internet. PI is the Public
+ Internet ("The Wild").
+ </t>
+
+ </section>
+
+ <section title="Terminology">
+
+ <t>
+ The following terminology is used in this document:
+ </t>
+
+ <list style="hanging">
+ <t hangText="Security gateway (or simply gateway):"> a system that performs IPsec tunnel
+ mode encapsulation/decapsulation. [SG-x] in the diagram.</t>
+ <t hangText="Alice:"> node [A] in the diagram. When an IP address is needed, this is 192.1.0.65.</t>
+ <t hangText="Bob:"> node [B] in the diagram. When an IP address is needed, this is 192.2.0.66.</t>
+ <t hangText="Carol:"> node [C] in the diagram. When an IP address is needed, this is 192.1.1.67.</t>
+ <t hangText="Dave:"> node [D] in the diagram. When an IP address is needed, this is 192.3.0.68.</t>
+ <t hangText="SG-A:"> Alice's security gateway. Internally it is 192.1.0.1, externally it is 192.1.1.4.</t>
+ <t hangText="SG-B:"> Bob's security gateway. Internally it is 192.2.0.1, externally it is 192.1.1.5.</t>
+ <t hangText="SG-D:"> Dave's security gateway. Also Alice's backup security gateway. Internally it is 192.3.0.1, externally it is 192.1.1.6.</t>
+ <t hangText="."> A period represents an untrusted network of unknown
+ type.</t>
+ <t hangText="Configured tunnel:"> a tunnel that
+ is directly and deliberately hand configured on participating gateways.
+ Configured tunnels are typically given a higher level of
+ trust than opportunistic tunnels.</t>
+
+ <t hangText="Road warrior tunnel:"> a configured tunnel connecting one
+ node with a fixed IP address and one node with a variable IP address.
+ A road warrior (RW) connection must be initiated by the
+ variable node, since the fixed node cannot know the
+ current address for the road warrior. </t>
+
+ <t hangText="Anonymous encryption:">
+ the process of encrypting a session without any knowledge of who the
+ other parties are. No authentication of identities is done.</t>
+
+ <t hangText="Opportunistic encryption:">
+ the process of encrypting a session with authenticated knowledge of
+ who the other party is.</t>
+
+ <t hangText="Lifetime:">
+ the period in seconds (bytes or datagrams) for which a security
+ association will remain alive before needing to be re-keyed.</t>
+
+ <t hangText="Lifespan:">
+ the effective time for which a security association remains useful. A
+ security association with a lifespan shorter than its lifetime would
+ be removed when no longer needed. A security association with a
+ lifespan longer than its lifetime would need to be re-keyed one or
+ more times.</t>
+
+ <t hangText="Phase 1 SA:"> an ISAKMP/IKE security association sometimes
+ referred to as a keying channel.</t>
+
+ <t hangText="Phase 2 SA:"> an IPsec security association.</t>
+
+ <t hangText="Tunnel:"> another term for a set of phase 2 SA (one in each direction).</t>
+
+ <t hangText="NAT:"> Network Address Translation
+ (see <xref target="RFC2663" />).</t>
+
+ <t hangText="NAPT:"> Network Address and Port Translation
+ (see <xref target="RFC2663" />).</t>
+
+ <t hangText="AS:"> an autonomous system </t>
+
+ <t hangText="FQDN:"> Fully-Qualified Domain Name </t>
+
+ <t hangText="Default-free zone:">
+ a set of routers that maintain a complete set of routes to
+ all currently reachable destinations. Having such a list, these routers
+ never make use of a default route. A datagram with a destination address
+ not matching any route will be dropped by such a router.
+ </t>
+
+ </list>
+ </section>
+
+<section title="Model of operation">
+
+<t>
+The opportunistic encryption security gateway (OE gateway) is a regular
+gateway node as described in <xref target="RFC0791" /> section 2.4 and
+<xref target="RFC1009" /> with the additional capabilities described here and
+in <xref target="RFC2401" />.
+The algorithm described here provides a way to determine, for each datagram,
+whether or not to encrypt and tunnel the datagram. Two important things
+that must be determined are whether or not to encrypt and tunnel and, if
+so, the destination address or name of the tunnel end point which should be used.
+</t>
+
+<section title="Tunnel authorization">
+<t>
+The OE gateway determines whether or not to create a tunnel based on
+the destination address of each packet. Upon receiving a packet with a destination
+address not recently seen, the OE gateway performs a lookup in DNS for an
+authorization resource record (see <xref target="TXT"/>). The record is located using
+the IP address to perform a search in the in-addr.arpa (IPv4) or ip6.arpa
+(IPv6) maps. If an authorization record is found, the OE gateway
+interprets this as a request for a tunnel to be formed.
+</t>
+</section>
+
+<section title="Tunnel end-point discovery">
+
+<t>
+The authorization resource record also provides the address or name of the tunnel
+end point which should be used.
+</t>
+<t>
+The record may also provide the public RSA key of the tunnel end point
+itself. This is provided for efficiency only. If the public RSA key is not
+present, the OE gateway performs a second lookup to find a KEY
+resource record for the end point address or name.
+</t>
+<t>
+Origin and integrity protection of the resource records is provided by
+DNSSEC (<xref target="RFC2535"/>). <xref target="nodnssec"/>
+documents an optional restriction on the tunnel end point if DNSSEC signatures
+are not available for the relevant records.
+</t>
+
+</section>
+
+<section title="Caching of authorization results">
+<t>
+The OE gateway maintains a cache, in the forwarding plane, of
+source/destination pairs for which opportunistic encryption has been
+attempted. This cache maintains a record of whether or not OE was
+successful so that subsequent datagrams can be forwarded properly
+without additional delay.
+</t>
+
+<t>
+Successful negotiation of OE instantiates a new security association.
+Failure to negotiate OE results in creation of a
+forwarding policy entry either to drop or transmit in the clear future
+datagrams. This negative cache is necessary to avoid the possibly lengthy process of repeatedly looking
+up the same information.
+</t>
+
+<t>
+The cache is timed out periodically, as described in <xref target="teardown" />.
+This removes entries that are no longer
+being used and permits the discovery of changes in authorization policy.
+</t>
+</section>
+
+</section> <!-- "Model of operation" -->
+
+</section> <!-- "Overview" -->
+
+<section title="Protocol Specification">
+
+<t>
+The OE gateway is modeled to have a forwarding plane and a control
+plane. A control channel, such as PF_KEY, connects the two planes.
+(See <xref target="RFC2367" />.)
+The forwarding plane performs per datagram operations. The control plane
+contains a keying daemon, such as ISAKMP/IKE, and performs all
+authorization, peer authentication and key derivation functions.
+</t>
+
+<section title="Forwarding plane state machine">
+
+<t>
+Let the OE gateway maintain a collection of objects -- a superset of the
+security policy database (SPD) specified in <xref target="RFC2401" />. For
+each combination of source and destination address, an SPD
+object exists in one of five following states.
+Prior to forwarding each datagram, the responder uses the source and
+destination addresses to pick an entry from the SPD.
+The SPD then determines if and how the packet is forwarded.
+</t>
+
+<!-- from file forwardingstate.txt -->
+<artwork><![CDATA[
+ .--------------.
+ | non-existant |
+ | policy |
+ `--------------'
+ |
+ | PF_ACQUIRE
+ |
+ |<---------.
+ V | new packet
+ .--------------. | (maybe resend PF_ACQUIRE)
+ | hold policy |--'
+ | |--.
+ `--------------' \ pass
+ | | \ msg .---------.
+ | | \ V | forward
+ | | .-------------. | packet
+ create | | | pass policy |--'
+ IPsec | | `-------------'
+ SA | |
+ | \
+ | \
+ V \ deny
+ .---------. \ msg
+ | encrypt | \
+ | policy | \ ,---------.
+ `---------' \ | | discard
+ \ V | packet
+ .-------------. |
+ | deny policy |--'
+ '-------------'
+]]></artwork>
+
+
+<section title="Non-existent policy">
+<t>
+If the gateway does not find an entry, then this policy applies.
+The gateway creates an entry with an initial state of "hold policy" and requests
+keying material from the keying daemon. The gateway does not forward the datagram,
+rather it SHOULD attach the datagram to the SPD entry as the "first" datagram and retain it
+for eventual transmission in a new state.
+
+</t>
+</section>
+
+<section title="Hold policy">
+<t>
+The gateway requests keying material. If the interface to the keying
+system is lossy (PF_KEY, for instance, can be), the implementation
+SHOULD include a mechanism to retransmit the
+keying request at a rate limited to less than 1 request per second.
+The gateway does not forward the datagram. The gateway SHOULD attach the
+datagram to the SPD entry as the "last" datagram where it is retained
+for eventual transmission.
+If there is a datagram already so stored, then that already stored datagram is discarded.
+</t>
+<t>
+The rational behind saving the the "first" and "last" datagrams are as follows:
+The "first" datagram is probably a TCP SYN packet. Once there is keying
+established, the gateway will release this datagram, avoiding the need to
+for the end-point to retransmit the datagram. In the case where the connection
+was not a TCP connection, buyt was instead a streaming protocol or a DNS request,
+the "last" datagram that was retained is likely the most recent data. The difference
+between "first" and "last" may also help the end-points determine
+which data awas dropped while negotiation took place.
+</t>
+</section>
+
+<section title="Pass-through policy">
+<t>
+The gateway forwards the datagram using the normal forwarding table.
+The gateway enters this state only by command from the keying daemon,
+and upon entering this state, also forwards the "first" and "last" datagrams.
+</t>
+</section>
+
+<section title="Deny policy">
+<t>
+The gateway discards the datagram. The gateway enters this state only by
+command
+from the keying daemon, and upon entering this state, discards the "first"
+and "last" datagrams.
+An implementation MAY provide the administator with a control to determine
+if further datagrams cause ICMP messages
+to be generated (i.e. ICMP Destination Unreachable, Communication
+Administratively Prohibited. type=3, code=13).
+</t>
+</section>
+
+<section title="Encrypt policy">
+<t>
+The gateway encrypts the datagram using the indicated security association database
+(SAD) entry. The gateway enters this state only by command from the keying daemon, and upon entering
+this state, releases and forwards the "first" and "last" datagrams using the
+new encrypt policy.
+</t>
+<t>
+If the associated SAD entry expires because of byte, packet or time limits, then
+the entry returns to the Hold policy, and an expire message is sent to the keying daemon.
+</t>
+</section>
+
+<t>
+All states may be created directly by the keying daemon while acting as a
+gateway.
+</t>
+
+</section> <!-- "Datagram state machine" -->
+
+
+<section anchor="initclasses" title="Keying Daemon -- initiator">
+<t>
+Let the keying daemon maintain a collection of objects. Let them be
+called "connections" or "conn"s. There are two categories of
+connection objects: classes and instances. A class represents an
+abstract policy - what could be. An instance represents an actual connection -
+what is implemented at the time.
+</t>
+
+<t>
+Let there be two further subtypes of connections: keying channels (Phase
+1 SAs) and data channels (Phase 2 SAs). Each data channel object may have
+a corresponding SPD and SAD entry maintained by the datagram state machine.
+</t>
+
+<t>
+For the purposes of opportunistic encryption, there MUST, at least, be
+connection classes known as "deny", "always-clear-text", "OE-permissive", and
+"OE-paranoid".
+The latter two connection classes define a set of source and/or destination
+addresses for which opportunistic encryption will be attempted.
+The administrator MAY set policy options in a number of additional places.
+An implementation MAY create additional connection classes to further refine
+these policies.
+</t>
+
+<t>
+The simplest system may need only the "OE-permissive" connection, and would
+list its own (single) IP address as the source address of this policy and
+the wild-card address 0.0.0.0/0 as the destination IPv4 address. That is, the
+simplest policy is to try opportunistic encryption with all destinations.
+</t>
+
+<t>
+The distinction between permissive and paranoid OE use will become clear
+in the state transition differences. In general a permissive OE will, on
+failure, install a pass-through policy, while a paranoid OE will, on failure,
+install a drop policy.
+</t>
+
+<t>
+In this description of the keying machine's state transitions, the states
+associated with the keying system itself are omitted because they are best documented in the keying system
+(<xref target="RFC2407" />,
+<xref target="RFC2408" /> and <xref target="RFC2409" /> for ISAKMP/IKE),
+and the details are keying system specific. Opportunistic encryption is not
+dependent upon any specific keying protocol, but this document does provide
+requirements for those using ISAKMP/IKE to assure that implementations inter-operate.
+</t>
+<t>
+The state transitions that may be involved in communicating with the
+forwarding plane are omitted. PF_KEY and similar protocols have their own
+set of states required for message sends and completion notifications.
+</t>
+<t>
+Finally, the retransmits and recursive lookups that are normal for DNS are
+not included in this description of the state machine.
+</t>
+
+<!-- from file initiatorstate.txt -->
+<artwork><![CDATA[
+
+ |
+ | PF_ACQUIRE
+ |
+ V
+ .---------------.
+ | non-existant |
+ | connection |
+ `---------------'
+ | | |
+ send , | \
+expired pass / | \ send
+conn. msg / | \ deny
+ ^ / | \ msg
+ | V | do \
+.---------------. | DNS \ .---------------.
+| clear-text | | lookup `->| deny |---> expired
+| connection | | for | connection | connection
+`---------------' | destination `---------------'
+ ^ ^ | ^
+ | | no record | |
+ | | OE-permissive V | no record
+ | | .---------------. | OE-paranoid
+ | `------------| potential OE |---------'
+ | | connection | ^
+ | `---------------' |
+ | | |
+ | | got TXT record | DNSSEC failure
+ | | reply |
+ | V | wrong
+ | .---------------. | failure
+ | | authenticate |---------'
+ | | & parse TXT RR| ^
+ | repeated `---------------' |
+ | ICMP | |
+ | failures | initiate IKE to |
+ | (short-timeout) | responder |
+ | V |
+ | phase-2 .---------------. | failure
+ | failure | pending |---------'
+ | (normal | OE | ^
+ | timeout) | |invalid | phase-2 failure (short-timeout)
+ | | |<--.SPI | ICMP failures (normal timeout)
+ | | | | |
+ | | +=======+ |---' |
+ | | | IKE | | ^ |
+ `--------------| | states|---------------'
+ | +=======+ | |
+ `---------------' |
+ | IPsec SA | invalid SPI
+ | established |
+ V | rekey time
+ .--------------. |
+ | keyed |<---|-------------------------------.
+ | connection |----' |
+ `--------------' |
+ | timer |
+ | |
+ V |
+ .--------------. connection still active |
+ clear-text----->| expired |------------------------------------'
+ deny----->| connection |
+ `--------------'
+ | dead connected - deleted
+ V
+]]></artwork>
+
+
+<section title="Nonexistent connection">
+<t>
+There is no connection instance for a given source/destination address pair.
+Upon receipt of a request for keying material for this
+source/destination pair, the initiator searches through the connection classes to
+determine the most appropriate policy. Upon determining an appropriate
+connection class, an instance object is created of that type.
+Both of the OE types result in a potential OE connection.
+</t>
+<t>Failure to find an appropriate connection class results in an
+administrator defined default.
+</t>
+<t>
+In each case, when the initiator finds an appropriate class for the new flow,
+an instance connection is made of the class which matched.
+</t>
+</section>
+
+<section title="Clear-text connection">
+<t>
+The non-existent connection makes a transition to this state when an
+always-clear-text class is instantiated, or when an OE-permissive
+connection fails. During the transition, the initiator creates a pass-through
+policy object in the forwarding plane for the appropriate flow.
+</t>
+<t>
+Timing out is the only way to leave this state
+(see <xref target="expiring" />).
+</t>
+</section>
+
+<section title="Deny connection">
+<t>
+The empty connection makes a transition to this state when a
+deny class is instantiated, or when an OE-paranoid connection fails.
+During the transition, the initiator creates a deny policy object in the forwarding plane
+for the appropriate flow.
+</t>
+<t>
+Timing out is the only way to leave this state
+(see <xref target="expiring" />).
+</t>
+</section>
+
+<section title="Potential OE connection">
+<t>
+The empty connection makes a transition to this state when one of either OE class is instantiated.
+During the transition to this state, the initiator creates a hold policy object in the
+forwarding plane for the appropriate flow.
+</t>
+<t>
+In addition, when making a transition into this state, DNS lookup is done in
+the reverse-map for a TXT delegation resource record (see <xref target="TXT" />).
+The lookup key is the destination address of the flow.
+</t>
+<t>
+There are three ways to exit this state:
+<list style="numbers">
+<t>DNS lookup finds a TXT delegation resource record.</t>
+<t>DNS lookup does not find a TXT delegation resource record.</t>
+<t>DNS lookup times out.</t>
+</list>
+</t>
+
+<t>
+Based upon the results of the DNS lookup, the potential OE connection makes a
+transition to the pending OE connection state. The conditions for a
+successful DNS look are:
+<list style="numbers">
+<t>DNS finds an appropriate resource record</t>
+<t>It is properly formatted according to <xref target="TXT" /></t>
+<t> if DNSSEC is enabled, then the signature has been vouched for.</t>
+</list>
+
+Note that if the initiator does not find the public key
+present in the TXT delegation record, then the public key must
+be looked up as a sub-state. Only successful completion of all the
+DNS lookups is considered a success.
+</t>
+<t>
+If DNS lookup does not find a resource record or DNS times out, then the
+initiator considers the receiver not OE capable. If this is an OE-paranoid instance,
+then the potential OE connection makes a transition to the deny connection state.
+If this is an OE-permissive instance, then the potential OE connection makes a transition to the
+clear-text connection state.
+</t>
+<t>
+If the initiator finds a resource record but it is not properly formatted, or
+if DNSSEC is
+enabled and reports a failure to authenticate, then the potential OE
+connection makes a
+transition to the deny connection state. This action SHOULD be logged. If the
+administrator wishes to override this transition between states, then an
+always-clear class can be installed for this flow. An implementation MAY make
+this situation a new class.
+</t>
+
+<section anchor="nodnssec" title="Restriction on unauthenticated TXT delegation records">
+<t>
+An implementation SHOULD also provide an additional administrative control
+on delegation records and DNSSEC. This control would apply to delegation
+records (the TXT records in the reverse-map) that are not protected by
+DNSSEC.
+Records of this type are only permitted to delegate to their own address as
+a gateway. When this option is enabled, an active attack on DNS will be
+unable to redirect packets to other than the original destination.
+<!-- This was asked for by Bill Sommerfeld -->
+</t>
+</section>
+</section>
+
+<section title="Pending OE connection">
+<t>
+The potential OE connection makes a transition to this state when
+the initiator determines that all the information required from the DNS lookup is present.
+Upon entering this state, the initiator attempts to initiate keying to the gateway
+provided.
+</t>
+<t>
+Exit from this state occurs either with a successfully created IPsec SA, or
+with a failure of some kind. Successful SA creation results in a transition
+to the key connection state.
+</t>
+<t>
+Three failures have caused significant problems. They are clearly not the
+only possible failures from keying.
+</t>
+<t>
+Note that if there are multiple gateways available in the TXT delegation
+records, then a failure can only be declared after all have been
+tried. Further, creation of a phase 1 SA does not constitute success. A set
+of phase 2 SAs (a tunnel) is considered success.
+</t>
+<t>
+The first failure occurs when an ICMP port unreachable is consistently received
+without any other communication, or when there is silence from the remote
+end. This usually means that either the gateway is not alive, or the
+keying daemon is not functional. For an OE-permissive connection, the initiator makes a transition
+to the clear-text connection but with a low lifespan. For an OE-pessimistic connection,
+the initiator makes a transition to the deny connection again with a low lifespan. The
+lifespan in both
+cases is kept low because the remote gateway may
+be in the process of rebooting or be otherwise temporarily unavailable.
+</t>
+<t>
+The length of time to wait for the remote keying daemon to wake up is
+a matter of some debate. If there is a routing failure, 5 minutes is usually long
+enough for the network to
+re-converge. Many systems can reboot in that amount of
+time as well. However, 5 minutes is far too long for most users to wait to
+hear that they can not connect using OE. Implementations SHOULD make this a
+tunable parameter.
+</t>
+<t>
+The second failure occurs after a phase 1 SA has been created, but there is
+either no response to the phase 2 proposal, or the initiator receives a
+negative notify (the notify must be
+authenticated). The remote gateway is not prepared to do OE at this time.
+As before, the initiator makes a transition to the clear-text or the deny
+connection based upon connection class, but this
+time with a normal lifespan.
+</t>
+<t>
+The third failure occurs when there is signature failure while authenticating
+the remote gateway. This can occur when there has been a
+key roll-over, but DNS has not caught up. In this case again, the initiator makes a
+transition to the clear-text or the deny connection based
+upon the connection class. However, the lifespan depends upon the remaining
+time to live in the DNS. (Note that DNSSEC signed resource records have a different
+expiry time than non-signed records.)
+<!-- dig @gateway would also work here -->
+</t>
+
+</section>
+
+<section anchor="keyed" title="Keyed connection">
+<t>
+The pending OE connection makes a transition to this state when
+session keying material (the phase 2 SAs) is derived. The initiator creates an encrypt
+policy in the forwarding plane for this flow.
+</t>
+<t>
+There are three ways to exit this state. The first is by receipt of an
+authenticated delete message (via the keying channel) from the peer. This is
+normal teardown and results in a transition to the expired connection state.
+</t>
+<t>
+The second exit is by expiry of the forwarding plane keying material. This
+starts a re-key operation with a transition back to pending OE
+connection. In general, the soft expiry occurs with sufficient time left
+to continue to use the keys. A re-key can fail, which may
+result in the connection failing to clear-text or deny as
+appropriate. In the event of a failure, the forwarding plane
+policy does not change until the phase 2 SA (IPsec SA) reaches its
+hard expiry.
+</t>
+<t>
+The third exit is in response to a negotiation from a remote
+gateway. If the forwarding plane signals the control plane that it has received an
+unknown SPI from the remote gateway, or an ICMP is received from the remote gateway
+indicating an unknown SPI, the initiator should consider that
+the remote gateway has rebooted or restarted. Since these
+indications are easily forged, the implementation must
+exercise care. The initiator should make a cautious
+(rate-limited) attempt to re-key the connection.
+</t>
+</section>
+
+<section anchor="expiring" title="Expiring connection">
+<t>
+The initiator will periodically place each of the deny, clear-text, and keyed
+connections into this
+sub-state. See <xref target="teardown" /> for more details of how often this
+occurs.
+The initiator queries the forwarding plane for last use time of the
+appropriate
+policy. If the last use time is relatively recent, then the connection
+returns to the
+previous deny, clear-text or keyed connection state. If not, then the
+connection enters
+the expired connection state.
+</t>
+<t>
+The DNS query and answer that lead to the expiring connection state are also
+examined. The DNS query may become stale. (A negative, i.e. no such record, answer
+is valid for the period of time given by the MINIMUM field in an attached SOA
+record. See <xref target="RFC1034" /> section 4.3.4.)
+If the DNS query is stale, then a new query is made. If the results change, then the connection
+makes a transition to a new state as described in potential OE connection state.
+</t>
+<t>
+Note that when considering how stale a connection is, both outgoing SPD and
+incoming SAD must be queried as some flows may be unidirectional for some time.
+</t>
+<t>
+Also note that the policy at the forwarding plane is not updated unless there
+is a conclusion that there should be a change.
+</t>
+
+</section>
+<section title="Expired connection">
+<t>
+Entry to this state occurs when no datagrams have been forwarded recently via the
+appropriate SPD and SAD objects. The objects in the forwarding plane are
+removed (logging any final byte and packet counts if appropriate) and the
+connection instance in the keying plane is deleted.
+</t>
+<t>
+The initiator sends an ISAKMP/IKE delete to clean up the phase 2 SAs as described in
+<xref target="teardown" />.
+</t>
+<t>
+Whether or not to delete the phase 1 SAs
+at this time is left as a local implementation issue. Implementations
+that do delete the phase 1 SAs MUST send authenticated delete messages to
+indicate that they are doing so. There is an advantage to keeping
+the phase 1 SAs until they expire - they may prove useful again in the
+near future.
+</t>
+</section>
+
+</section> <!-- "Keying state machine - initiator" -->
+
+<section title="Keying Daemon - responder">
+<t>
+The responder has a set of objects identical to those of the initiator.
+</t>
+<t>
+The responder receives an invitation to create a keying channel from an initiator.
+</t>
+
+<!-- from file responderstate.txt -->
+<artwork><![CDATA[
+ |
+ | IKE main mode
+ | phase 1
+ V
+ .-----------------.
+ | unauthenticated |
+ | OE peer |
+ `-----------------'
+ |
+ | lookup KEY RR in in-addr.arpa
+ | (if ID_IPV4_ADDR)
+ | lookup KEY RR in forward
+ | (if ID_FQDN)
+ V
+ .-----------------. RR not found
+ | received DNS |---------------> log failure
+ | reply |
+ `----+--------+---'
+ phase 2 | \ misformatted
+ proposal | `------------------> log failure
+ V
+ .----------------.
+ | authenticated | identical initiator
+ | OE peer |--------------------> initiator
+ `----------------' connection found state machine
+ |
+ | look for TXT record for initiator
+ |
+ V
+ .---------------.
+ | authorized |---------------------> log failure
+ | OE peer |
+ `---------------'
+ |
+ |
+ V
+ potential OE
+ connection in
+ initiator state
+ machine
+
+
+$Id: draft-richardson-ipsec-opportunistic.xml,v 1.1 2004/03/15 20:35:24 as Exp $
+]]></artwork>
+
+
+<section title="Unauthenticated OE peer">
+<t>
+Upon entering this state, the responder starts a DNS lookup for a KEY record for the
+initiator.
+The responder looks in the reverse-map for a KEY record for the initiator if the
+initiator has offered an ID_IPV4_ADDR, and in the forward map if the
+initiator has offered an ID_FQDN type. (See <xref target="RFC2407" /> section
+4.6.2.1.)
+</t>
+<t>
+The responder exits this state upon successful receipt of a KEY from DNS, and use of the key
+to verify the signature of the initiator.
+</t>
+
+<!--
+<t>
+The public key that is retrieved should be stored in stable storage for an
+administratively defined period of time, (typically several months if
+possible). If a key has previously been stored on disk, then the returned key
+should be compared to what has been received, and the key considered valid
+only if they match.
+</t>
+-->
+
+<t>
+Successful authentication of the peer results in a transition to the
+authenticated OE Peer state.
+</t>
+<t>
+Note that the unauthenticated OE peer state generally occurs in the middle of the key negotiation
+protocol. It is really a form of pseudo-state.
+</t>
+</section>
+
+<section title="Authenticated OE Peer">
+<t>
+The peer will eventually propose one or more phase 2 SAs. The responder uses the source and
+destination address in the proposal to
+finish instantiating the connection state
+using the connection class table.
+The responder MUST search for an identical connection object at this point.
+</t>
+<t>
+If an identical connection is found, then the responder deletes the old instance,
+and the new object makes a transition to the pending OE connection state. This means
+that new ISAKMP connections with a given peer will always use the latest
+instance, which is the correct one if the peer has rebooted in the interim.
+</t>
+<t>
+If an identical connection is not found, then the responder makes the transition according to the
+rules given for the initiator.
+</t>
+<t>
+Note that if the initiator is in OE-paranoid mode and the responder is in
+either always-clear-text or deny, then no communication is possible according
+to policy. An implementation is permitted to create new types of policies
+such as "accept OE but do not initiate it". This is a local matter.
+ </t>
+</section>
+
+</section> <!-- "Keying state machine - responder" -->
+
+<section anchor="teardown" title="Renewal and teardown">
+ <section title="Aging">
+<t>
+A potentially unlimited number of tunnels may exist. In practice, only a few
+tunnels are used during a period of time. Unused tunnels MUST, therefore, be
+torn down. Detecting when tunnels are no longer in use is the subject of this section.
+</t>
+
+<t>
+There are two methods for removing tunnels: explicit deletion or expiry.
+</t>
+
+<t>
+Explicit deletion requires an IKE delete message. As the deletes
+MUST be authenticated, both ends of the tunnel must maintain the
+key channel (phase 1 ISAKMP SA). An implementation which refuses to either maintain or
+recreate the keying channel SA will be unable to use this method.
+</t>
+
+<t>
+The tunnel expiry method simply allows the IKE daemon to
+expire normally without attempting to re-key it.
+</t>
+
+<t>
+Regardless of which method is used to remove tunnels, the implementation MUST
+a method to determine if the tunnel is still in use. The specifics are a
+local matter, but the FreeS/WAN project uses the following criteria. These
+criteria are currently implemented in the key management daemon, but could
+also be implemented at the SPD layer using an idle timer.
+</t>
+
+<t>
+Set a short initial (soft) lifespan of 1 minute since many net flows last
+only a few seconds.
+</t>
+
+<t>
+At the end of the lifespan, check to see if the tunnel was used by
+traffic in either direction during the last 30 seconds. If so, assign a
+longer tentative lifespan of 20 minutes after which, look again. If the
+tunnel is not in use, then close the tunnel.
+</t>
+
+<t>
+The expiring state in the key management
+system (see <xref target="expiring" />) implements these timeouts.
+The timer above may be in the forwarding plane,
+but then it must be re-settable.
+</t>
+
+<t>
+The tentative lifespan is independent of re-keying; it is just the time when
+the tunnel's future is next considered.
+(The term lifespan is used here rather than lifetime for this reason.)
+Unlike re-keying, this tunnel use check is not costly and should happen
+reasonably frequently.
+</t>
+
+<t>
+A multi-step back-off algorithm is not considered worth the effort here.
+</t>
+
+<t>
+If the security gateway and the client host are the
+same and not a Bump-in-the-Stack or Bump-in-the-Wire implementation, tunnel
+teardown decisions MAY pay attention to TCP connection status as reported
+by the local TCP layer. A still-open TCP connection is almost a guarantee that more traffic is
+expected. Closing of the only TCP connection through a tunnel is a
+strong hint that no more traffic is expected.
+</t>
+
+</section> <!-- "Aging" -->
+
+<section title="Teardown and cleanup">
+
+<t>
+Teardown should always be coordinated between the two ends of the tunnel by
+interpreting and sending delete notifications. There is a
+detailed sub-state in the expired connection state of the key manager that
+relates to retransmits of the delete notifications, but this is considered to
+be a keying system detail.
+</t>
+
+<t>
+On receiving a delete for the outbound SAs of a tunnel (or some subset of
+them), tear down the inbound ones also and notify the remote end with a
+delete. If the local system receives a delete for a tunnel which is no longer in
+existence, then two delete messages have crossed paths. Ignore the delete.
+The operation has already been completed. Do not generate any messages in this
+situation.
+</t>
+<t>
+Tunnels are to be considered as bidirectional entities, even though the
+low-level protocols don't treat them this way.
+</t>
+
+<t>
+When the deletion is initiated locally, rather than as a
+response to a received delete, send a delete for (all) the
+inbound SAs of a tunnel. If the local system does not receive a responding delete
+for the outbound SAs, try re-sending the original
+delete. Three tries spaced 10 seconds apart seems a reasonable
+level of effort. A failure of the other end to respond after 3 attempts,
+indicates that the possibility of further communication is unlikely. Remove the outgoing SAs.
+(The remote system may be a mobile node that is no longer present or powered on.)
+</t>
+
+<t>
+After re-keying, transmission should switch to using the new
+outgoing SAs (ISAKMP or IPsec) immediately, and the old leftover
+outgoing SAs should be cleared out promptly (delete should be sent
+for the outgoing SAs) rather than waiting for them to expire. This
+reduces clutter and minimizes confusion for the operator doing diagnostics.
+</t>
+
+</section>
+
+</section>
+
+</section> <!-- "Specification" -->
+
+<section title="Impacts on IKE">
+
+ <section title="ISAKMP/IKE protocol">
+ <t>
+ The IKE wire protocol needs no modifications. The major changes are
+ implementation issues relating to how the proposals are interpreted, and from
+ whom they may come.
+ </t>
+ <t>
+ As opportunistic encryption is designed to be useful between peers without
+ prior operator configuration, an IKE daemon must be prepared to negotiate
+ phase 1 SAs with any node. This may require a large amount of resources to
+ maintain cookie state, as well as large amounts of entropy for nonces,
+ cookies and so on.
+ </t>
+ <t>
+ The major changes to support opportunistic encryption are at the IKE daemon
+ level. These changes relate to handling of key acquisition requests, lookup
+ of public keys and TXT records, and interactions with firewalls and other
+ security facilities that may be co-resident on the same gateway.
+ </t>
+ </section>
+
+ <section title="Gateway discovery process">
+ <t>
+ In a typical configured tunnel, the address of SG-B is provided
+ via configuration. Furthermore, the mapping of an SPD entry to a gateway is
+ typically a 1:1 mapping. When the 0.0.0.0/0 SPD entry technique is used, then
+ the mapping to a gateway is determined by the reverse DNS records.
+ </t>
+ <t>
+ The need to do a DNS lookup and wait for a reply will typically introduce a
+ new state and a new event source (DNS replies) to IKE. Although a
+synchronous DNS request can be implemented for proof of concept, experience
+is that it can cause very high latencies when a queue of queries must
+all timeout in series.
+ </t>
+ <t>
+ Use of an asynchronous DNS lookup will also permit overlap of DNS lookups with
+ some of the protocol steps.
+ </t>
+ </section>
+
+ <section title="Self identification">
+ <t>
+ SG-A will have to establish its identity. Use an
+ IPv4 ID in phase 1.
+ </t>
+ <t> There are many situations where the administrator of SG-A may not be
+ able to control the reverse DNS records for SG-A's public IP address.
+ Typical situations include dialup connections and most residential-type broadband Internet access
+ (ADSL, cable-modem) connections. In these situations, a fully qualified domain
+ name that is under the control of SG-A's administrator may be used
+ when acting as an initiator only.
+ The FQDN ID should be used in phase 1. See <xref target="fqdn" />
+ for more details and restrictions.
+ </t>
+ </section>
+
+ <section title="Public key retrieval process">
+ <t>
+ Upon receipt of a phase 1 SA proposal with either an IPv4 (IPv6) ID or
+ an FQDN ID, an IKE daemon needs to examine local caches and
+ configuration files to determine if this is part of a configured tunnel.
+ If no configured tunnels are found, then the implementation should attempt to retrieve
+ a KEY record from the reverse DNS in the case of an IPv4/IPv6 ID, or
+ from the forward DNS in the case of FQDN ID.
+ </t>
+ <t>
+ It is reasonable that if other non-local sources of policy are used
+ (COPS, LDAP), they be consulted concurrently but some
+ clear ordering of policy be provided. Note that due to variances in
+ latency, implementations must wait for positive or negative replies from all sources
+ of policy before making any decisions.
+ </t>
+ </section>
+
+ <section title="Interactions with DNSSEC">
+ <t>
+ The implementation described (1.98) neither uses DNSSEC directly to
+ explicitly verify the authenticity of zone information, nor uses the NXT
+ records to provide authentication of the absence of a TXT or KEY
+ record. Rather, this implementation uses a trusted path to a DNSSEC
+ capable caching resolver.
+ </t>
+ <t>
+ To distinguish between an authenticated and an unauthenticated DNS
+ resource record, a stub resolver capable of returning DNSSEC
+ information MUST be used.
+ </t>
+
+ </section>
+
+<!--
+ <section title="Interactions with COPS">
+ <t>
+ At this time there is no experience with implementations that interact
+ with COPS Policy Decision Points (PDP) <xref target="RFC2748" />. It is
+ suggested that it may be
+ appropriate for many of
+ the policy and discovery mechanisms outlined here to be done by a PDP.
+ In this context, the IKE daemon present in the Policy Enforcement Point
+ (PEP) may not need any modifications.
+ </t>
+ </section>
+-->
+
+ <section title="Required proposal types">
+
+ <section anchor="phase1id" title="Phase 1 parameters">
+ <t>
+ Main mode MUST be used.
+ </t>
+ <t>
+ The initiator MUST offer at least one proposal using some combination
+ of: 3DES, HMAC-MD5 or HMAC-SHA1, DH group 2 or 5. Group 5 SHOULD be
+ proposed first.
+ <xref target="RFC3526" />
+ </t>
+ <t>
+ The initiator MAY offer additional proposals, but the cipher MUST not
+ be weaker than 3DES. The initiator SHOULD limit the number of proposals
+ such that the IKE datagrams do not need to be fragmented.
+ </t>
+ <t>
+ The responder MUST accept one of the proposals. If any configuration
+ of the responder is required then the responder is not acting in an
+ opportunistic way.
+ </t>
+ <t>
+ The initiator SHOULD use an ID_IPV4_ADDR (ID_IPV6_ADDR for IPv6) of the external
+ interface of the initiator for phase 1. (There is an exception, see <xref
+ target="fqdn" />.) The authentication method MUST be RSA public key signatures.
+ The RSA key for the initiator SHOULD be placed into a DNS KEY record in
+ the reverse space of the initiator (i.e. using in-addr.arpa or
+ ip6.arpa).
+ </t>
+ </section>
+
+ <section anchor="phase2id" title="Phase 2 parameters">
+ <t>
+ The initiator MUST propose a tunnel between the ultimate
+ sender ("Alice" or "A") and ultimate recipient ("Bob" or "B")
+ using 3DES-CBC
+ mode, MD5 or SHA1 authentication. Perfect Forward Secrecy MUST be specified.
+ </t>
+ <t>
+ Tunnel mode MUST be used.
+ </t>
+ <t>
+ Identities MUST be ID_IPV4_ADDR_SUBNET with the mask being /32.
+ </t>
+ <t>
+ Authorization for the initiator to act on Alice's behalf is determined by
+ looking for a TXT record in the reverse-map at Alice's IP address.
+ </t>
+ <t>
+ Compression SHOULD NOT be mandatory. It MAY be offered as an option.
+ </t>
+ </section>
+ </section>
+
+</section>
+
+<section title="DNS issues">
+ <section anchor="KEY" title="Use of KEY record">
+ <t>
+ In order to establish their own identities, security gateways SHOULD publish
+ their public keys in their reverse DNS via
+ DNSSEC's KEY record.
+ See section 3 of <xref target="RFC2535">RFC 2535</xref>.
+ </t>
+ <t>
+ <preamble>For example:</preamble>
+ <artwork><![CDATA[
+KEY 0x4200 4 1 AQNJjkKlIk9...nYyUkKK8
+]]></artwork>
+
+ <list style="hanging">
+ <t hangText="0x4200:"> The flag bits, indicating that this key is prohibited
+ for confidentiality use (it authenticates the peer only, a separate
+ Diffie-Hellman exchange is used for
+ confidentiality), and that this key is associated with the non-zone entity
+ whose name is the RR owner name. No other flags are set.</t>
+ <t hangText="4:">This indicates that this key is for use by IPsec.</t>
+ <t hangText="1:">An RSA key is present.</t>
+ <t hangText="AQNJjkKlIk9...nYyUkKK8:">The public key of the host as described in <xref target="RFC3110" />.</t>
+ </list>
+ </t>
+ <t>Use of several KEY records allows for key rollover. The SIG Payload in
+ IKE phase 1 SHOULD be accepted if the public key given by any KEY RR
+ validates it.
+ </t>
+ </section>
+
+ <section anchor="TXT" title="Use of TXT delegation record">
+ <t>
+If, for example, machine Alice wishes SG-A to act on her behalf, then
+she publishes a TXT record to provide authorization for SG-A to act on
+Alice's behalf. Similarly for Bob and SG-B.
+</t>
+
+<t>
+These records are located in the reverse DNS (in-addr.arpa or ip6.arpa) for their
+respective IP addresses. The reverse DNS SHOULD be secured by DNSSEC.
+DNSSEC is required to defend against active attacks.
+ </t>
+ <t>
+ If Alice's address is P.Q.R.S, then she can authorize another node to
+ act on her behalf by publishing records at:
+ <artwork><![CDATA[
+S.R.Q.P.in-addr.arpa
+ ]]></artwork>
+ </t>
+
+ <t>
+ The contents of the resource record are expected to be a string that
+ uses the following syntax, as suggested in <xref target="RFC1464">RFC1464</xref>.
+ (Note that the reply to query may include other TXT resource
+ records used by other applications.)
+
+ <figure anchor="txtformat" title="Format of reverse delegation record">
+ <artwork><![CDATA[
+X-IPsec-Server(P)=A.B.C.D KEY
+ ]]></artwork>
+ </figure>
+ </t>
+
+ where the record is formed by the following fields:
+
+ <list style="hanging">
+ <t hangText="P:"> Specifies a precedence for this record. This is
+ similar to MX record preferences. Lower numbers have stronger
+ preference.
+ </t>
+
+ <t hangText="A.B.C.D:"> Specifies the IP address of the Security Gateway
+ for this client machine.
+ </t>
+
+ <t hangText="KEY:"> Is the encoded RSA Public key of the Security
+ Gateway. The key is provided here to avoid a second DNS lookup. If this
+ field is absent, then a KEY resource record should be looked up in the
+ reverse-map of A.B.C.D. The key is transmitted in base64 format.
+ </t>
+ </list>
+
+ <t>
+ The fields of the record MUST be separated by whitespace. This
+ MAY be: space, tab, newline, or carriage return. A space is preferred.
+ </t>
+
+ <t>
+ In the case where Alice is located at a public address behind a
+ security gateway that has no fixed address (or no control over its
+ reverse-map), then Alice may delegate to a public key by domain name.
+
+ <figure anchor="txtfqdnformat"
+ title="Format of reverse delegation record (FQDN version)">
+ <artwork><![CDATA[
+X-IPsec-Server(P)=@FQDN KEY
+ ]]></artwork>
+ </figure>
+ </t>
+
+ <list style="hanging">
+ <t hangText="P:"> Is as above.
+ </t>
+
+ <t hangText="FQDN:"> Specifies the FQDN that the Security Gateway
+ will identify itself with.
+ </t>
+
+ <t hangText="KEY:"> Is the encoded RSA Public key of the Security
+ Gateway. </t>
+ </list>
+
+ <t>
+ If there is more than one such TXT record with strongest (lowest
+ numbered) precedence, one Security Gateway is picked arbitrarily from
+ those specified in the strongest-preference records.
+ </t>
+
+ <section title="Long TXT records">
+ <t>
+ When packed into transport format, TXT records which are longer than 255
+ characters are divided into smaller &lt;character-strings&gt;.
+ (See <xref target="RFC1035" /> section 3.3 and 3.3.14.) These MUST
+ be reassembled into a single string for processing.
+ Whitespace characters in the base64 encoding are to be ignored.
+ </t>
+ </section>
+
+ <section title="Choice of TXT record">
+ <t>
+ It has been suggested to use the KEY, OPT, CERT, or KX records
+ instead of a TXT record. None is satisfactory.
+ </t>
+ <t> The KEY RR has a protocol field which could be used to indicate a new protocol,
+and an algorithm field which could be used to
+ indicate different contents in the key data. However, the KEY record
+ is clearly not intended for storing what are really authorizations,
+ it is just for identities. Other uses have been discouraged.
+ </t>
+ <t> OPT resource records, as defined in <xref target="RFC2671" /> are not
+ intended to be used for storage of information. They are not to be loaded,
+ cached or forwarded. They are, therefore, inappropriate for use here.
+ </t>
+ <t>
+ CERT records <xref target="RFC2538" /> can encode almost any set of
+ information. A custom type code could be used permitting any suitable
+ encoding to be stored, not just X.509. According to
+ the RFC, the certificate RRs are to be signed internally which may add undesirable
+and unnecessary bulk. Larger DNS records may require TCP instead of UDP transfers.
+ </t>
+ <t>
+ At the time of protocol design, the CERT RR was not widely deployed and
+ could not be counted upon. Use of CERT records will be investigated,
+ and may be proposed in a future revision of this document.
+ </t>
+ <t>
+ KX records are ideally suited for use instead of TXT records, but had not been deployed at
+ the time of implementation.
+<!-- Jakob Schlyter <j@crt.se> confirmed -->
+ </t>
+ </section>
+ </section>
+
+ <section anchor="fqdn" title="Use of FQDN IDs">
+ <t>
+ Unfortunately, not every administrator has control over the contents
+ of the reverse-map. Where the initiator (SG-A) has no suitable reverse-map, the
+ authorization record present in the reverse-map of Alice may refer to a
+ FQDN instead of an IP address.
+ </t>
+ <t>
+ In this case, the client's TXT record gives the fully qualified domain
+ name (FQDN) in place of its security gateway's IP address.
+ The initiator should use the ID_FQDN ID-payload in phase 1.
+ A forward lookup for a KEY record on the FQDN must yield the
+ initiator's public key.
+ </t>
+ <t>
+ This method can also be used when the external address of SG-A is
+ dynamic.
+ </t>
+ <t>
+ If SG-A is acting on behalf of Alice, then Alice must still delegate
+ authority for SG-A to do so in her reverse-map. When Alice and SG-A
+ are one and the same (i.e. Alice is acting as an end-node) then there
+ is no need for this when initiating only. </t>
+ <t>However, Alice must still delegate to herself if she wishes others to
+ initiate OE to her. See <xref target="txtfqdnformat" />.
+ </t>
+ <
+ </section>
+
+<section title="Key roll-over">
+<t>
+Good cryptographic hygiene says that one should replace public/private key pairs
+periodically. Some administrators may wish to do this as often as daily. Typical DNS
+propagation delays are determined by the SOA Resource Record MINIMUM
+parameter, which controls how long DNS replies may be cached. For reasonable
+operation of DNS servers, administrators usually want this value to be at least several
+hours, sometimes as a long as a day. This presents a problem - a new key MUST
+not be used prior to it propagating through DNS.
+</t>
+<t>
+This problem is dealt with by having the Security Gateway generate a new
+public/private key pair at least MINIMUM seconds in advance of using it. It
+then adds this key to the DNS (both as a second KEY record and in additional TXT
+delegation records) at key generation time. Note: only one key is allowed in
+each TXT record.
+</t>
+<t>
+When authenticating, all gateways MUST have available all public keys
+that are found in DNS for this entity. This permits the authenticating end
+to check both the key for "today" and the key for "tomorrow". Note that it is
+the end which is creating the signature (possesses the private key) that
+determines which key is to be used.
+</t>
+
+ </section>
+</section>
+
+
+<section title="Network address translation interaction">
+ <t>
+ There are no fundamentally new issues for implementing opportunistic encryption
+ in the presence of network address translation. Rather there are
+ only the regular IPsec issues with NAT traversal.
+ </t>
+ <t>
+ There are several situations to consider for NAT.
+ </t>
+ <section title="Co-located NAT/NAPT">
+ <t>
+ If a security gateway is also performing network address translation on
+ behalf of an end-system, then the packet should be translated prior to
+ being subjected to opportunistic encryption. This is in contrast to
+ typically configured tunnels which often exist to bridge islands of
+ private network address space. The security gateway will use the translated source
+ address for phase 2, and so the responding security gateway will look up that address to
+ confirm SG-A's authorization.
+ </t>
+ <t> In the case of NAT (1:1), the address space into which the
+ translation is done MUST be globally unique, and control over the
+ reverse-map is assumed.
+ Placing of TXT records is possible.
+ </t>
+ <t> In the case of NAPT (m:1), the address will be the security
+ gateway itself. The ability to get
+ KEY and TXT records in place will again depend upon whether or not
+ there is administrative control over the reverse-map. This is
+ identical to situations involving a single host acting on behalf of
+ itself.
+
+ FQDN style can be used to get around a lack of a reverse-map for
+ initiators only.
+ </t>
+ </section>
+
+ <section title="Security Gateway behind NAT/NAPT">
+ <t>
+ If there is a NAT or NAPT between the security gateways, then normal IPsec
+ NAT traversal problems occur. In addition to the transport problem
+ which may be solved by other mechanisms, there is the issue of
+ what phase 1 and phase 2 IDs to use. While FQDN could
+ be used during phase 1 for the security gateway, there is no appropriate ID for phase 2.
+ Due to the NAT, the end systems live in different IP address spaces.
+ </t>
+ </section>
+
+ <section title="End System is behind a NAT/NAPT">
+ <t>
+ If the end system is behind a NAT (perhaps SG-B), then there is, in fact, no way for
+ another end system to address a packet to this end system.
+ Not only is opportunistic encryption
+ impossible, but it is also impossible for any communication to
+ be initiate to the end system. It may be possible for this end
+ system to initiate in such communication. This creates an asymmetry, but this is common for
+ NAPT.
+ </t>
+ </section>
+</section>
+
+<section title="Host implementations">
+<t>
+ When Alice and SG-A are components of the same system, they are
+ considered to be a host implementation. The packet sequence scenario remains unchanged.
+</t>
+<t>
+ Components marked Alice are the upper layers (TCP, UDP, the
+ application), and SG-A is the IP layer.
+</t>
+<t>
+ Note that tunnel mode is still required.
+</t>
+<t>
+ As Alice and SG-A are acting on behalf of themselves, no TXT based delegation
+ record is necessary for Alice to initiate. She can rely on FQDN in a
+ forward map. This is particularly attractive to mobile nodes such as
+ notebook computers at conferences.
+ To respond, Alice/SG-A will still need an entry in Alice's reverse-map.
+</t>
+</section>
+
+<section title="Multi-homing">
+<t>
+If there are multiple paths between Alice and Bob (as illustrated in
+the diagram with SG-D), then additional DNS records are required to establish
+authorization.
+</t>
+<t>
+In <xref target="networkdiagram" />, Alice has two ways to
+exit her network: SG-A and SG-D. Previously SG-D has been ignored. Postulate
+that there are routers between Alice and her set of security gateways
+(denoted by the + signs and the marking of an autonomous system number for
+Alice's network). Datagrams may, therefore, travel to either SG-A or SG-D en
+route to Bob.
+</t>
+<t>
+As long as all network connections are in good order, it does not matter how
+datagrams exit Alice's network. When they reach either security gateway, the
+security gateway will find the TXT delegation record in Bob's reverse-map,
+and establish an SA with SG-B.
+</t>
+<t>
+SG-B has no problem establishing that either of SG-A or SG-D may speak for
+Alice, because Alice has published two equally weighted TXT delegation records:
+ <figure anchor="txtmultiexample"
+ title="Multiple gateway delegation example for Alice">
+ <artwork><![CDATA[
+X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
+X-IPsec-Server(10)=192.1.1.6 AAJN...j8r9==
+ ]]></artwork>
+ </figure>
+</t>
+<t>
+Alice's routers can now do any kind of load sharing needed. Both SG-A and SG-D send datagrams addressed to Bob through
+their tunnel to SG-B.
+</t>
+<t>
+Alice's use of non-equal weight delegation records to show preference of one gateway over another, has relevance only when SG-B
+is initiating to Alice.
+</t>
+<t>
+If the precedences are the same, then SG-B has a more difficult time. It
+must decide which of the two tunnels to use. SG-B has no information about
+which link is less loaded, nor which security gateway has more cryptographic
+resources available. SG-B, in fact, has no knowledge of whether both gateways
+are even reachable.
+</t>
+<t>
+The Public Internet's default-free zone may well know a good route to Alice,
+but the datagrams that SG-B creates must be addressed to either SG-A or SG-D;
+they can not be addressed to Alice directly.
+</t>
+<t>
+SG-B may make a number of choices:
+<list style="numbers">
+<t>It can ignore the problem and round robin among the tunnels. This
+ causes losses during times when one or the other security gateway is
+ unreachable. If this worries Alice, she can change the weights in her
+ TXT delegation records.</t>
+
+<t>It can send to the gateway from which it most recently received datagrams.
+ This assumes that routing and reachability are symmetrical.</t>
+
+<t>It can listen to BGP information from the Internet to decide which
+ system is currently up. This is clearly much more complicated, but if SG-B is already participating
+ in the BGP peering system to announce Bob, the results data may already
+ be available to it. </t>
+
+<t>It can refuse to negotiate the second tunnel. (It is unclear whether or
+not this is even an option.)</t>
+
+<t>It can silently replace the outgoing portion of the first tunnel with the
+second one while still retaining the incoming portions of both. SG-B can,
+thus, accept datagrams from either SG-A or SG-D, but
+send only to the gateway that most recently re-keyed with it.</t>
+</list>
+</t>
+
+<t>
+Local policy determines which choice SG-B makes. Note that even if SG-B has perfect
+knowledge about the reachability of SG-A and SG-D, Alice may not be reachable
+from either of these security gateways because of internal reachability
+issues.
+</t>
+
+<t>
+FreeS/WAN implements option 5. Implementing a different option is
+being considered. The multi-homing aspects of OE are not well developed and may
+be the subject of a future document.
+</t>
+
+</section>
+
+<section title="Failure modes">
+ <section title="DNS failures">
+ <t>
+ If a DNS server fails to respond, local policy decides
+ whether or not to permit communication in the clear as embodied in
+ the connection classes in <xref target="initclasses" />.
+ It is easy to mount a denial of service attack on the DNS server
+ responsible for a particular network's reverse-map.
+ Such an attack may cause all communication with that network to go in
+ the clear if the policy is permissive, or fail completely
+ if the policy is paranoid. Please note that this is an active attack.
+ </t>
+ <t>
+ There are still many networks
+ that do not have properly configured reverse-maps. Further, if the policy is not to communicate,
+ the above denial of service attack isolates the target network. Therefore, the decision of whether
+or not to permit communication in the clear MUST be a matter of local policy.
+ </t>
+ </section>
+
+ <section title="DNS configured, IKE failures">
+ <t>
+ DNS records claim that opportunistic encryption should
+ occur, but the target gateway either does not respond on port 500, or
+ refuses the proposal. This may be because of a crash or reboot, a
+ faulty configuration, or a firewall filtering port 500.
+ </t>
+ <t>
+ The receipt of ICMP port, host or network unreachable
+ messages indicates a potential problem, but MUST NOT cause communication
+ to fail
+ immediately. ICMP messages are easily forged by attackers. If such a
+ forgery caused immediate failure, then an active attacker could easily
+ prevent any
+ encryption from ever occurring, possibly preventing all communication.
+ </t>
+ <t>
+ In these situations a clear log should be produced
+ and local policy should dictate if communication is then
+ permitted in the clear.
+ </t>
+ </section>
+
+ <section title="System reboots">
+<t>
+Tunnels sometimes go down because the remote end crashes,
+disconnects, or has a network link break. In general there is no
+notification of this. Even in the event of a crash and successful reboot,
+other SGs don't hear about it unless the rebooted SG has specific
+reason to talk to them immediately. Over-quick response to temporary
+network outages is undesirable. Note that a tunnel can be torn
+down and then re-established without any effect visible to the user
+except a pause in traffic. On the other hand, if one end reboots,
+the other end can't get datagrams to it at all (except via
+IKE) until the situation is noticed. So a bias toward quick
+response is appropriate even at the cost of occasional
+false alarms.
+</t>
+
+<t>
+A mechanism for recovery after reboot is a topic of current research and is not specified in this
+document.
+</t>
+
+<t>
+A deliberate shutdown should include an attempt, using deletes, to notify all other SGs
+currently connected by phase 1 SAs that communication is
+about to fail. Again, a remote SG will assume this is a teardown. Attempts by the
+remote SGs to negotiate new tunnels as replacements should be ignored. When possible,
+SGs should attempt to preserve information about currently-connected SGs in non-volatile storage, so
+that after a crash, an Initial-Contact can be sent to previous partners to
+indicate loss of all previously established connections.
+</t>
+
+ </section>
+</section>
+
+<!--
+<section title="Performance experiences">
+
+ Claudia> Is it useful to point out (or to clarify for our own discussion) any of the
+ Claudia> following:
+
+ Claudia> * how much time this is likely to take on typical current hardware?
+ Claudia> * what steps are likely to be time consuming
+ Claudia> * how any added time could affect a typical transaction, such as hitting
+ Claudia> a web site
+ Claudia> * any ways to minimize such time delays
+
+ <section title="Introduced latency">
+ </section>
+
+ <section title="Cryptographic performance">
+ </section>
+
+ <section title="Phase 1 SA performance">
+ </section>
+
+</section>
+-->
+
+<section title="Unresolved issues">
+ <section title="Control of reverse DNS">
+ <t>
+ The method of obtaining information by reverse DNS lookup causes
+ problems for people who cannot control their reverse DNS
+ bindings. This is an unresolved problem in this version, and is out
+ of scope.
+ </t>
+ </section>
+</section>
+
+<section title="Examples">
+
+<section title="Clear-text usage (permit policy)">
+
+<t>
+Two example scenarios follow. In the first example GW-A
+(Gateway A) and GW-B (Gateway B) have always-clear-text policies, and in the second example they have an OE
+policy. The clear-text policy serves as a reference for what occurs in
+TCP/IP in the absence of Opportunistic Encryption.
+
+<t>
+Alice wants to communicate with Bob. Perhaps she wants to retrieve a
+web page from Bob's web server. In the absence of opportunistic
+encryptors, the following events occur:
+</t>
+
+ <figure anchor="regulartiming" title="Timing of regular transaction">
+ <artwork><![CDATA[
+ Alice SG-A DNS SG-B Bob
+ Human or application
+ 'clicks' with a name.
+ (1)
+
+ ------(2)-------------->
+ Application looks up
+ name in DNS to get
+ IP address.
+
+ <-----(3)---------------
+ Resolver returns "A" RR
+ to application with IP
+ address.
+
+ (4)
+ Application starts a TCP session
+ or UDP session and OS sends
+ first datagram
+
+ ----(5)----->
+ Datagram is seen at first gateway
+ from Alice (SG-A).
+
+ ----------(6)------>
+ Datagram traverses
+ network.
+
+ ------(7)----->
+ Datagram arrives
+ at Bob, is provided
+ to TCP.
+
+ <------(8)------
+ A reply is sent.
+
+ <----------(9)------
+ Datagram traverses
+ network.
+ <----(10)-----
+ Alice receives
+ answer.
+
+ (11)----------->
+ A second exchange
+ occurs.
+ ----------(12)----->
+ -------------->
+ <---------------
+ <-------------------
+ <-------------
+ ]]></artwork>
+</figure>
+
+</t>
+</section>
+
+<section title="Opportunistic encryption">
+
+<t>
+In the presence of properly configured opportunistic encryptors, the
+event list is extended. Only changes are annotated.
+</t>
+
+<t>The following symbols are used in the time-sequence diagram</t>
+
+<t>
+<list style="hanging">
+ <t hangText="-"> A single dash represents clear-text datagrams.</t>
+ <t hangText="="> An equals sign represents phase 2 (IPsec) cipher-text
+ datagrams.</t>
+ <t hangText="~"> A single tilde represents clear-text phase 1 datagrams.</t>
+ <t hangText="#"> A hash sign represents phase 1 (IKE) cipher-text
+ datagrams.</t>
+</list>
+</t>
+
+<t>
+<figure anchor="opportunistictiming" title="Timing of opportunistic encryption transaction">
+ <artwork><![CDATA[
+ Alice SG-A DNS SG-B Bob
+ (1)
+ ------(2)-------------->
+ <-----(3)---------------
+ (4)----(5)----->+
+ SG-A sees datagram
+ to new target and
+ saves it as "first"
+
+ ----(5B)->
+ SG-A asks DNS
+ for TXT RR.
+
+ <---(5C)--
+ DNS returns TXT RR.
+
+ ~~~~~~~~~~~~~(5D)~~~>
+ initial IKE main mode
+ packet is sent.
+
+ <~~~~~~~~~~~~(5E1)~~~
+ ~~~~~~~~~~~~~(5E2)~~>
+ <~~~~~~~~~~~~(5E3)~~~
+ IKE phase 1 - privacy.
+
+ #############(5E4)##>
+ SG-A sends ID to SG-B
+ <----(5F1)--
+ SG-B asks DNS
+ for SG-A's public
+ KEY
+ -----(5F2)->
+ DNS provides KEY RR.
+ SG-B authenticates SG-A
+
+ <############(5E5)###
+ IKE phase 1 - complete
+
+ #############(5G1)##>
+ IKE phase 2 - Alice<->Bob
+ tunnel is proposed.
+
+ <----(5H1)--
+ SG-B asks DNS for
+ Alice's TXT record.
+ -----(5H2)->
+ DNS replies with TXT
+ record. SG-B checks
+ SG-A's authorization.
+
+ <############(5G2)###
+ SG-B accepts proposal.
+
+ #############(5G3)##>
+ SG-A confirms.
+
+ ============(6)====>
+ SG-A sends "first"
+ packet in new IPsec
+ SA.
+ ------(7)----->
+ packet is decrypted
+ and forward to Bob.
+ <------(8)------
+ <==========(9)======
+ return packet also
+ encrypted.
+ <-----(10)----
+
+ (11)----------->
+ a second packet
+ is sent by Alice
+ ==========(12)=====>
+ existing tunnel is used
+ -------------->
+ <---------------
+ <===================
+ <-------------
+ ]]></artwork>
+</figure>
+
+</t>
+
+ <t>
+ For the purposes of this section, we will describe only the changes that
+ occur between <xref target="regulartiming" /> and
+ <xref target="opportunistictiming" />. This corresponds to time points 5, 6, 7, 9 and 10 on the list above.
+ </t>
+
+<list style="symbols">
+ <t>
+ At point (5), SG-A intercepts the datagram because this source/destination pair lacks a policy
+(the non-existent policy state). SG-A creates a hold policy, and buffers the datagram. SG-A requests keys from the keying daemon.
+ </t>
+
+ <t>
+ SG-A's IKE daemon, having looked up the source/destination pair in the connection
+ class list, creates a new Potential OE connection instance. SG-A starts DNS
+ queries.
+ </t>
+ </section>
+
+ <section title="(5C) DNS returns TXT record(s)">
+
+ <t>
+ DNS returns properly formed TXT delegation records, and SG-A's IKE daemon
+ causes this instance to make a transition from Potential OE connection to Pending OE
+ connection.
+ </t>
+
+ <t>
+ Using the example above, the returned record might contain:
+
+ <figure anchor="txtexample"
+ title="Example of reverse delegation record for Bob">
+ <artwork><![CDATA[
+X-IPsec-Server(10)=192.1.1.5 AQMM...3s1Q==
+ ]]></artwork>
+ </figure>
+ with SG-B's IP address and public key listed.
+ </t>
+
+ </section>
+
+ <section title="(5D) Initial IKE main mode packet goes out">
+ <t>Upon entering Pending OE connection, SG-A sends the initial ISAKMP
+ message with proposals. See <xref target="phase1id" />.
+ </t>
+ </section>
+
+ <section title="(5E1) Message 2 of phase 1 exchange">
+ <t>
+ SG-B receives the message. A new connection instance is created in the
+ unauthenticated OE peer state.
+ </t>
+ </section>
+
+ <section title="(5E2) Message 3 of phase 1 exchange">
+ <t>
+ SG-A sends a Diffie-Hellman exponent. This is an internal state of the
+ keying daemon.
+ </t>
+ </section>
+
+ <section title="(5E3) Message 4 of phase 1 exchange">
+ <t>
+ SG-B responds with a Diffie-Hellman exponent. This is an internal state of the
+ keying protocol.
+ </t>
+ </section>
+
+ <section title="(5E4) Message 5 of phase 1 exchange">
+ <t>
+ SG-A uses the phase 1 SA to send its identity under encryption.
+ The choice of identity is discussed in <xref target="phase1id" />.
+ This is an internal state of the keying protocol.
+ </t>
+ </section>
+
+ <section title="(5F1) Responder lookup of initiator key">
+ <t>
+ SG-B asks DNS for the public key of the initiator.
+ DNS looks for a KEY record by IP address in the reverse-map.
+ That is, a KEY resource record is queried for 4.1.1.192.in-addr.arpa
+ (recall that SG-A's external address is 192.1.1.4).
+ SG-B uses the resulting public key to authenticate the initiator. See <xref
+ target="KEY" /> for further details.
+ </t>
+ </section>
+
+<section title="(5F2) DNS replies with public key of initiator">
+<t>
+Upon successfully authenticating the peer, the connection instance makes a
+transition to authenticated OE peer on SG-B.
+</t>
+<t>
+The format of the TXT record returned is described in
+<xref target="TXT" />.
+</t>
+</section>
+
+ <section title="(5E5) Responder replies with ID and authentication">
+ <t>
+ SG-B sends its ID along with authentication material. This is an internal
+ state for the keying protocol.
+ </t>
+ </section>
+
+ <section title="(5G) IKE phase 2">
+ <section title="(5G1) Initiator proposes tunnel">
+ <t>
+ Having established mutually agreeable authentications (via KEY) and
+ authorizations (via TXT), SG-A proposes to create an IPsec tunnel for
+ datagrams transiting from Alice to Bob. This tunnel is established only for
+ the Alice/Bob combination, not for any subnets that may be behind SG-A and SG-B.
+ </t>
+ </section>
+
+ <section title="(5H1) Responder determines initiator's authority">
+ <t>
+ While the identity of SG-A has been established, its authority to
+ speak for Alice has not yet been confirmed. SG-B does a reverse
+ lookup on Alice's address for a TXT record.
+ </t>
+ <t>Upon receiving this specific proposal, SG-B's connection instance
+ makes a transition into the potential OE connection state. SG-B may already have an
+ instance, and the check is made as described above.</t>
+ </section>
+
+ <section title="(5H2) DNS replies with TXT record(s)">
+ <t>
+ The returned key and IP address should match that of SG-A.
+ </t>
+ </section>
+
+ <section title="(5G2) Responder agrees to proposal">
+ <t>
+ Should additional communication occur between, for instance, Dave and Bob using
+ SG-A and SG-B, a new tunnel (phase 2 SA) would be established. The phase 1 SA
+ may be reusable.
+ </t>
+ <t>SG-A, having successfully keyed the tunnel, now makes a transition from
+ Pending OE connection to Keyed OE connection.
+ </t>
+ <t>The responder MUST setup the inbound IPsec SAs before sending its reply.</t>
+ </section>
+
+ <section title="(5G3) Final acknowledgment from initiator">
+ <t>
+ The initiator agrees with the responder's choice and sets up the tunnel.
+ The initiator sets up the inbound and outbound IPsec SAs.
+ </t>
+ <t>
+ The proper authorization returned with keys prompts SG-B to make a transition
+ to the keyed OE connection state.
+ </t>
+ <t>Upon receipt of this message, the responder may now setup the outbound
+ IPsec SAs.</t>
+ </section>
+ </section>
+
+ <section title="(6) IPsec succeeds, and sets up tunnel for communication between Alice and Bob">
+ <t>
+ SG-A sends the datagram saved at step (5) through the newly created
+ tunnel to SG-B, where it gets decrypted and forwarded.
+ Bob receives it at (7) and replies at (8).
+ </t>
+ </section>
+
+ <section title="(9) SG-B already has tunnel up with G1 and uses it">
+ <t>
+ At (9), SG-B has already established an SPD entry mapping Bob->Alice via a
+ tunnel, so this tunnel is simply applied. The datagram is encrypted to SG-A,
+ decrypted by SG-A and passed to Alice at (10).
+ </t>
+
+ </section>
+</section> <!-- OE example -->
+
+</section> <!-- Examples -->
+
+<section anchor="securityconsiderations" title="Security considerations">
+
+ <section title="Configured vs opportunistic tunnels">
+<t>
+ Configured tunnels are those which are setup using bilateral mechanisms: exchanging
+public keys (raw RSA, DSA, PKIX), pre-shared secrets, or by referencing keys that
+are in known places (distinguished name from LDAP, DNS). These keys are then used to
+configure a specific tunnel.
+</t>
+<t>
+A pre-configured tunnel may be on all the time, or may be keyed only when needed.
+The end points of the tunnel are not necessarily static: many mobile
+applications (road warrior) are considered to be configured tunnels.
+</t>
+<t>
+The primary characteristic is that configured tunnels are assigned specific
+security properties. They may be trusted in different ways relating to exceptions to
+firewall rules, exceptions to NAT processing, and to bandwidth or other quality of service restrictions.
+</t>
+<t>
+Opportunistic tunnels are not inherently trusted in any strong way. They are
+created without prior arrangement. As the two parties are strangers, there
+MUST be no confusion of datagrams that arrive from opportunistic peers and
+those that arrive from configured tunnels. A security gateway MUST take care
+that an opportunistic peer can not impersonate a configured peer.
+</t>
+<t>
+Ingress filtering MUST be used to make sure that only datagrams authorized by
+negotiation (and the concomitant authentication and authorization) are
+accepted from a tunnel. This is to prevent one peer from impersonating another.
+</t>
+<t>
+An implementation suggestion is to treat opportunistic tunnel
+datagrams as if they arrive on a logical interface distinct from other
+configured tunnels. As the number of opportunistic tunnels that may be
+created automatically on a system is potentially very high, careful attention
+to scaling should be taken into account.
+</t>
+<t>
+As with any IKE negotiation, opportunistic encryption cannot be secure
+without authentication. Opportunistic encryption relies on DNS for its
+authentication information and, therefore, cannot be fully secure without
+a secure DNS. Without secure DNS, opportunistic encryption can protect against passive
+eavesdropping but not against active man-in-the-middle attacks.
+</t>
+ </section>
+
+ <section title="Firewalls versus Opportunistic Tunnels">
+<t>
+ Typical usage of per datagram access control lists is to implement various
+kinds of security gateways. These are typically called "firewalls".
+</t>
+<t>
+ Typical usage of a virtual private network (VPN) within a firewall is to
+bypass all or part of the access controls between two networks. Additional
+trust (as outlined in the previous section) is given to datagrams that arrive
+in the VPN.
+</t>
+<t>
+ Datagrams that arrive via opportunistically configured tunnels MUST not be
+trusted. Any security policy that would apply to a datagram arriving in the
+clear SHOULD also be applied to datagrams arriving opportunistically.
+</t>
+ </section>
+
+ <section title="Denial of service">
+<t>
+ There are several different forms of denial of service that an implementor
+ should concern themselves with. Most of these problems are shared with
+ security gateways that have large numbers of mobile peers (road warriors).
+</t>
+<t>
+ The design of ISAKMP/IKE, and its use of cookies, defend against many kinds
+ of denial of service. Opportunism changes the assumption that if the phase 1 (ISAKMP)
+ SA is authenticated, that it was worthwhile creating. Because the gateway will communicate with any machine, it is
+ possible to form phase 1 SAs with any machine on the Internet.
+</t>
+
+</section>
+</section>
+
+<section title="IANA Considerations">
+<t>
+ There are no known numbers which IANA will need to manage.
+</t>
+</section>
+
+<section title="Acknowledgments">
+<t>
+ Substantive portions of this document are based upon previous work by
+ Henry Spencer.
+</t>
+<t>
+ Thanks to Tero Kivinen, Sandy Harris, Wes Hardarker, Robert Moskowitz,
+ Jakob Schlyter, Bill Sommerfeld, John Gilmore and John Denker for their
+ comments and constructive criticism.
+</t>
+<t>
+ Sandra Hoffman and Bill Dickie did the detailed proof reading and editing.
+</t>
+</section>
+
+</middle>
+
+<back>
+<references title="Normative references">
+<?rfc include="reference.OEspec" ?>
+<!-- renumber according to reference order -->
+<?rfc include="reference.RFC.0791" ?>
+<?rfc include="reference.RFC.1009" ?>
+<?rfc include="reference.RFC.1984" ?>
+<?rfc include="reference.RFC.2119" ?>
+<!-- IPsec -->
+<?rfc include="reference.RFC.2367" ?>
+<?rfc include="reference.RFC.2401" ?>
+<?rfc include="reference.RFC.2407" ?>
+<?rfc include="reference.RFC.2408" ?>
+<?rfc include="reference.RFC.2409" ?>
+<!-- MODPGROUPS -->
+<?rfc include="reference.RFC.3526" ?>
+<!-- DNSSEC -->
+<?rfc include="reference.RFC.1034" ?>
+<?rfc include="reference.RFC.1035" ?>
+<?rfc include="reference.RFC.2671" ?>
+<?rfc include="reference.RFC.1464" ?>
+<?rfc include="reference.RFC.2535" ?>
+<?rfc include="reference.RFC.3110" ?>
+<?rfc include="reference.RFC.2538" ?>
+<!-- COPS -->
+<?rfc include="reference.RFC.2748" ?>
+<!-- NAT -->
+<?rfc include="reference.RFC.2663" ?>
+</references>
+<!-- <references title="Non-normative references"> -->
+<!-- ESPUDP -->
+<!-- <?rfc include="reference.ESPUDP" ?> -->
+<!-- </references> -->
+</back>
+</rfc>
+<!--
+ $Id: draft-richardson-ipsec-opportunistic.xml,v 1.1 2004/03/15 20:35:24 as Exp $
+
+ $Log: draft-richardson-ipsec-opportunistic.xml,v $
+ Revision 1.1 2004/03/15 20:35:24 as
+ added files from freeswan-2.04-x509-1.5.3
+
+ Revision 1.33 2003/06/30 03:19:59 mcr
+ timing-diagram with inline explanation.
+
+ Revision 1.32 2003/06/30 01:57:44 mcr
+ initial edits per-Bob Braden.
+
+ Revision 1.31 2003/05/26 19:31:23 mcr
+ updates to drafts - IPSEC RR - SC versions, and RFC3526
+ reference in OE draft.
+
+ Revision 1.30 2003/05/21 15:42:34 mcr
+ updates due to publication of RFC 3526.
+
+ Revision 1.29 2003/01/17 16:22:55 mcr
+ rev 11 of OE draft.
+
+ Revision 1.28 2002/07/25 19:27:31 mcr
+ added DHR's minor edits.
+
+ Revision 1.27 2002/07/21 16:26:26 mcr
+ slides from presentation at OLS
+ draft-10 of OE draft.
+
+ Revision 1.26 2002/07/16 03:46:53 mcr
+ second edits from Sandra.
+
+ Revision 1.25 2002/07/16 03:36:14 mcr
+ removed HS from authors list
+ updated reference inclusion to use <?rfc-include directive.
+ Revision 1.24 2002/07/11 02:08:21 mcr
+ updated XML file from Sandra
+
+ Revision 1.23 2002/06/06 17:18:53 mcr
+ spellcheck.
+
+ Revision 1.22 2002/06/06 17:14:19 mcr
+ results of hand-editing session from May 28th.
+ This is FINAL OE draft.
+
+ Revision 1.21 2002/06/06 02:25:44 mcr
+ results of hand-editing session from May 28th.
+ This is FINAL OE draft.
+
+ Revision 1.20 2002/05/24 03:28:37 mcr
+ changes as requested by RFC editor.
+
+ Revision 1.19 2002/04/09 16:01:05 mcr
+ comments from PHB.
+
+ Revision 1.18 2002/04/08 02:14:34 mcr
+ RGBs changes to rev6.
+
+ Revision 1.17 2002/03/12 21:23:55 mcr
+ adjusted definition of default-free zone.
+ moved text on key rollover from format description to new
+ section.
+
+ Revision 1.16 2002/02/22 01:23:21 mcr
+ revisions from MCR (2002/2/18) and net.
+
+ Revision 1.15 2002/02/21 20:44:12 mcr
+ extensive from DHR.
+
+ Revision 1.14 2002/02/10 16:20:39 mcr
+ -05 draft. Many revisions to do "OE system in world of OE systems"
+ view of the universe.
+
+ Revision 1.13 2001/12/20 04:35:22 mcr
+ fixed reference to rfc1984.
+
+ Revision 1.12 2001/12/20 03:35:19 mcr
+ comments from Henry, Tero, and Sandy.
+
+ Revision 1.11 2001/12/19 07:26:22 mcr
+ added comment about KX records.
+
+ Revision 1.10 2001/11/09 04:28:10 mcr
+ fixed some typos with XML, and one s/SG-B/SG-D/.
+
+ Revision 1.9 2001/11/09 04:07:13 mcr
+ expanded section 10: multihoming, with an example.
+
+ Revision 1.8 2001/11/09 02:16:51 mcr
+ added lifetime/lifespan definitions.
+ moved example from 5B to 5C.
+ added reference to phase 1 IDs to 5D.
+ cleared up text in aging section.
+ added text about delegation of DNSSEC activity to a DNS server.
+ spelt out DH group names.
+ added text about ignoring TXT records unless DNSSEC is deployed (somerfeld)
+ added example of TXT delegation using FQDN.
+ clarified some text in NAT interaction section.
+ clarified absense of TXT record need for host implementation
+
+ Revision 1.7 2001/11/08 23:09:37 mcr
+ changed revision of draft to 03.
+
+ Revision 1.6 2001/11/08 19:37:14 mcr
+ fixed some formatting of Aging section.
+
+ Revision 1.5 2001/11/08 19:19:30 mcr
+ fixed address for DHR, updated address for MCR,
+ added reference to original HS/DHR OE specification paper.
+
+ Revision 1.4 2001/11/08 19:08:24 mcr
+ section 10, "Renewal and Teardown" added moved between 4/5, and
+ slightly rewritten.
+
+ Revision 1.3 2001/11/08 18:56:34 mcr
+ sections 4.2, 5.6, 5.7.1 and 6.2 edited as per HS.
+ section 10, "Renewal and Teardown" added.
+ section 11, "Failure modes" completed.
+
+ Revision 1.2 2001/11/05 20:31:31 mcr
+ added section from OE spec on aging and teardown.
+
+ Revision 1.1 2001/11/05 04:27:58 mcr
+ OE draft added to documentation.
+
+ Revision 1.12 2001/10/10 01:12:31 mcr
+ removed impact on DNS servers section.
+ removed nested comments.
+ adjusted data of issue
+
+ Revision 1.11 2001/09/17 02:55:50 mcr
+ outline is now stable.
+
+ Revision 1.5 2001/08/19 02:53:32 mcr
+ version 00d formatted.
+
+ Revision 1.10 2001/08/19 02:34:04 mcr
+ version 00d formatted.
+
+ Revision 1.9 2001/08/19 02:21:54 mcr
+ version 00d
+
+ Revision 1.8 2001/07/20 19:07:06 mcr
+ commented out section 1.1
+
+ Revision 1.7 2001/07/20 14:14:22 mcr
+ HS and HD comments.
+
+ Revision 1.6 2001/07/19 00:56:50 mcr
+ version 00b.
+
+ Revision 1.5 2001/07/12 23:57:07 mcr
+ OE ID, 00.
+
+
+!>
diff --git a/doc/src/draft-richardson-ipsec-rr.html b/doc/src/draft-richardson-ipsec-rr.html
new file mode 100644
index 000000000..08473104f
--- /dev/null
+++ b/doc/src/draft-richardson-ipsec-rr.html
@@ -0,0 +1,659 @@
+<html><head><title>A method for storing IPsec keying material in DNS.</title>
+<STYLE type='text/css'>
+ .title { color: #990000; font-size: 22px; line-height: 22px; font-weight: bold; text-align: right;
+ font-family: helvetica, arial, sans-serif }
+ .filename { color: #666666; font-size: 18px; line-height: 28px; font-weight: bold; text-align: right;
+ font-family: helvetica, arial, sans-serif }
+ p.copyright { color: #000000; font-size: 10px;
+ font-family: verdana, charcoal, helvetica, arial, sans-serif }
+ p { margin-left: 2em; margin-right: 2em; }
+ li { margin-left: 3em; }
+ ol { margin-left: 2em; margin-right: 2em; }
+ ul.text { margin-left: 2em; margin-right: 2em; }
+ pre { margin-left: 3em; color: #333333 }
+ ul.toc { color: #000000; line-height: 16px;
+ font-family: verdana, charcoal, helvetica, arial, sans-serif }
+ H3 { color: #333333; font-size: 16px; line-height: 16px; font-family: helvetica, arial, sans-serif }
+ H4 { color: #000000; font-size: 14px; font-family: helvetica, arial, sans-serif }
+ TD.header { color: #ffffff; font-size: 10px; font-family: arial, helvetica, san-serif; valign: top }
+ TD.author-text { color: #000000; font-size: 10px;
+ font-family: verdana, charcoal, helvetica, arial, sans-serif }
+ TD.author { color: #000000; font-weight: bold; margin-left: 4em; font-size: 10px; font-family: verdana, charcoal, helvetica, arial, sans-serif }
+ A:link { color: #990000; font-weight: bold;
+ font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
+ A:visited { color: #333333; font-weight: bold;
+ font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
+ A:name { color: #333333; font-weight: bold;
+ font-family: MS Sans Serif, verdana, charcoal, helvetica, arial, sans-serif }
+ .link2 { color:#ffffff; font-weight: bold; text-decoration: none;
+ font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
+ font-size: 9px }
+ .RFC { color:#666666; font-weight: bold; text-decoration: none;
+ font-family: monaco, charcoal, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
+ font-size: 9px }
+ .hotText { color:#ffffff; font-weight: normal; text-decoration: none;
+ font-family: charcoal, monaco, geneva, MS Sans Serif, helvetica, monotype, verdana, sans-serif;
+ font-size: 9px }
+</style>
+</head>
+<body bgcolor="#ffffff" text="#000000" alink="#000000" vlink="#666666" link="#990000">
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<table width="66%" border="0" cellpadding="0" cellspacing="0"><tr><td><table width="100%" border="0" cellpadding="2" cellspacing="1">
+<tr valign="top"><td width="33%" bgcolor="#666666" class="header">IPSECKEY WG</td><td width="33%" bgcolor="#666666" class="header">M. Richardson</td></tr>
+<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Internet-Draft</td><td width="33%" bgcolor="#666666" class="header">SSW</td></tr>
+<tr valign="top"><td width="33%" bgcolor="#666666" class="header">Expires: March 4, 2004</td><td width="33%" bgcolor="#666666" class="header">September 4, 2003</td></tr>
+</table></td></tr></table>
+<div align="right"><font face="monaco, MS Sans Serif" color="#990000" size="+3"><b><br><span class="title">A method for storing IPsec keying material in DNS.</span></b></font></div>
+<div align="right"><font face="monaco, MS Sans Serif" color="#666666" size="+2"><b><span class="filename">draft-ietf-ipseckey-rr-07.txt</span></b></font></div>
+<font face="verdana, helvetica, arial, sans-serif" size="2">
+
+<h3>Status of this Memo</h3>
+<p>
+This document is an Internet-Draft and is in full conformance with all provisions of Section 10 of RFC2026.</p>
+<p>
+Internet-Drafts are working documents of the Internet Engineering
+Task Force (IETF), its areas, and its working groups.
+Note that other groups may also distribute working documents as
+Internet-Drafts.</p>
+<p>
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any time.
+It is inappropriate to use Internet-Drafts as reference material or to cite
+them other than as "work in progress."</p>
+<p>
+The list of current Internet-Drafts can be accessed at
+<a href='http://www.ietf.org/ietf/1id-abstracts.txt'>http://www.ietf.org/ietf/1id-abstracts.txt</a>.</p>
+<p>
+The list of Internet-Draft Shadow Directories can be accessed at
+<a href='http://www.ietf.org/shadow.html'>http://www.ietf.org/shadow.html</a>.</p>
+<p>
+This Internet-Draft will expire on March 4, 2004.</p>
+
+<h3>Copyright Notice</h3>
+<p>
+Copyright (C) The Internet Society (2003). All Rights Reserved.</p>
+
+<h3>Abstract</h3>
+
+<p>
+This document describes a new resource record for DNS. This record may be
+used to store public keys for use in IPsec systems.
+
+</p>
+<p>
+This record replaces the functionality of the sub-type #1 of the KEY Resource
+Record, which has been obsoleted by RFC3445.
+
+</p><a name="toc"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<h3>Table of Contents</h3>
+<ul compact class="toc">
+<b><a href="#anchor1">1.</a>&nbsp;
+Introduction<br></b>
+<b><a href="#anchor2">1.1</a>&nbsp;
+Overview<br></b>
+<b><a href="#anchor3">1.2</a>&nbsp;
+Usage Criteria<br></b>
+<b><a href="#anchor4">2.</a>&nbsp;
+Storage formats<br></b>
+<b><a href="#anchor5">2.1</a>&nbsp;
+IPSECKEY RDATA format<br></b>
+<b><a href="#anchor6">2.2</a>&nbsp;
+RDATA format - precedence<br></b>
+<b><a href="#algotype">2.3</a>&nbsp;
+RDATA format - algorithm type<br></b>
+<b><a href="#gatewaytype">2.4</a>&nbsp;
+RDATA format - gateway type<br></b>
+<b><a href="#anchor7">2.5</a>&nbsp;
+RDATA format - gateway<br></b>
+<b><a href="#anchor8">2.6</a>&nbsp;
+RDATA format - public keys<br></b>
+<b><a href="#anchor9">3.</a>&nbsp;
+Presentation formats<br></b>
+<b><a href="#anchor10">3.1</a>&nbsp;
+Representation of IPSECKEY RRs<br></b>
+<b><a href="#anchor11">3.2</a>&nbsp;
+Examples<br></b>
+<b><a href="#anchor12">4.</a>&nbsp;
+Security Considerations<br></b>
+<b><a href="#anchor13">4.1</a>&nbsp;
+Active attacks against unsecured IPSECKEY resource records<br></b>
+<b><a href="#anchor14">5.</a>&nbsp;
+IANA Considerations<br></b>
+<b><a href="#anchor15">6.</a>&nbsp;
+Acknowledgments<br></b>
+<b><a href="#rfc.references1">&#167;</a>&nbsp;
+Normative references<br></b>
+<b><a href="#rfc.references2">&#167;</a>&nbsp;
+Non-normative references<br></b>
+<b><a href="#rfc.authors">&#167;</a>&nbsp;
+Author's Address<br></b>
+<b><a href="#rfc.copyright">&#167;</a>&nbsp;
+Full Copyright Statement<br></b>
+</ul>
+<br clear="all">
+
+<a name="anchor1"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.1"></a><h3>1.&nbsp;Introduction</h3>
+
+<p>
+ The type number for the IPSECKEY RR is TBD.
+
+</p>
+<a name="rfc.section.1.1"></a><h4><a name="anchor2">1.1</a>&nbsp;Overview</h4>
+
+<p>
+ The IPSECKEY resource record (RR) is used to publish a public key that is
+ to be associated with a Domain Name System (DNS) name for use with the
+ IPsec protocol suite. This can be the public key of a host,
+ network, or application (in the case of per-port keying).
+
+</p>
+<p>
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
+ NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
+ "OPTIONAL" in this document are to be interpreted as described in
+ RFC2119 <a href="#RFC2119">[8]</a>.
+
+</p>
+<a name="rfc.section.1.2"></a><h4><a name="anchor3">1.2</a>&nbsp;Usage Criteria</h4>
+
+<p>
+ An IPSECKEY resource record SHOULD be used in combination with DNSSEC
+unless some other means of authenticating the IPSECKEY resource record
+is available.
+
+</p>
+<p>
+ It is expected that there will often be multiple IPSECKEY resource
+ records at the same name. This will be due to the presence
+ of multiple gateways and the need to rollover keys.
+
+
+</p>
+<p>
+ This resource record is class independent.
+
+</p>
+<a name="anchor4"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.2"></a><h3>2.&nbsp;Storage formats</h3>
+
+<a name="rfc.section.2.1"></a><h4><a name="anchor5">2.1</a>&nbsp;IPSECKEY RDATA format</h4>
+
+<p>
+ The RDATA for an IPSECKEY RR consists of a precedence value, a public key,
+ algorithm type, and an optional gateway address.
+
+</p></font><pre>
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | precedence | gateway type | algorithm | gateway |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------+ +
+ ~ gateway ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | /
+ / public key /
+ / /
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
+</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+
+<a name="rfc.section.2.2"></a><h4><a name="anchor6">2.2</a>&nbsp;RDATA format - precedence</h4>
+
+<p>
+This is an 8-bit precedence for this record. This is interpreted in
+the same way as the PREFERENCE field described in section
+3.3.9 of RFC1035 <a href="#RFC1035">[2]</a>.
+
+</p>
+<p>
+Gateways listed in IPSECKEY records with lower precedence are
+to be attempted first. Where there is a tie in precedence, the order
+should be non-deterministic.
+
+</p>
+<a name="rfc.section.2.3"></a><h4><a name="algotype">2.3</a>&nbsp;RDATA format - algorithm type</h4>
+
+<p>
+The algorithm type field identifies the public key's cryptographic
+algorithm and determines the format of the public key field.
+
+</p>
+<p>
+A value of 0 indicates that no key is present.
+
+</p>
+<p>
+The following values are defined:
+
+<blockquote class="text"><dl>
+<dt>1</dt>
+<dd>A DSA key is present, in the format defined in RFC2536 <a href="#RFC2536">[11]</a>
+</dd>
+<dt>2</dt>
+<dd>A RSA key is present, in the format defined in RFC3110 <a href="#RFC3110">[12]</a>
+</dd>
+</dl></blockquote><p>
+</p>
+<a name="rfc.section.2.4"></a><h4><a name="gatewaytype">2.4</a>&nbsp;RDATA format - gateway type</h4>
+
+<p>
+The gateway type field indicates the format of the information that
+is stored in the gateway field.
+
+</p>
+<p>
+The following values are defined:
+
+<blockquote class="text"><dl>
+<dt>0</dt>
+<dd>No gateway is present
+</dd>
+<dt>1</dt>
+<dd>A 4-byte IPv4 address is present
+</dd>
+<dt>2</dt>
+<dd>A 16-byte IPv6 address is present
+</dd>
+<dt>3</dt>
+<dd>A wire-encoded domain name is present. The wire-encoded
+format is self-describing, so the length is implicit. The domain name
+MUST NOT be compressed.
+</dd>
+</dl></blockquote><p>
+</p>
+<a name="rfc.section.2.5"></a><h4><a name="anchor7">2.5</a>&nbsp;RDATA format - gateway</h4>
+
+<p>
+The gateway field indicates a gateway to which an IPsec tunnel may be
+created in order to reach the entity named by this resource record.
+
+</p>
+<p>
+There are three formats:
+
+</p>
+<p>
+A 32-bit IPv4 address is present in the gateway field. The data
+portion is an IPv4 address as described in section 3.4.1 of
+<a href="#RFC1035">RFC1035</a>[2]. This is a 32-bit number in network byte order.
+
+</p>
+<p>A 128-bit IPv6 address is present in the gateway field.
+The data portion is an IPv6 address as described in section 2.2 of
+<a href="#RFC1886">RFC1886</a>[7]. This is a 128-bit number in network byte order.
+
+</p>
+<p>
+The gateway field is a normal wire-encoded domain name, as described
+in section 3.3 of RFC1035 <a href="#RFC1035">[2]</a>. Compression MUST NOT be used.
+
+</p>
+<a name="rfc.section.2.6"></a><h4><a name="anchor8">2.6</a>&nbsp;RDATA format - public keys</h4>
+
+<p>
+Both of the public key types defined in this document (RSA and DSA)
+inherit their public key formats from the corresponding KEY RR formats.
+Specifically, the public key field contains the algorithm-specific
+portion of the KEY RR RDATA, which is all of the KEY RR DATA after the
+first four octets. This is the same portion of the KEY RR that must be
+specified by documents that define a DNSSEC algorithm.
+Those documents also specify a message digest to be used for generation
+of SIG RRs; that specification is not relevant for IPSECKEY RR.
+
+</p>
+<p>
+Future algorithms, if they are to be used by both DNSSEC (in the KEY
+RR) and IPSECKEY, are likely to use the same public key encodings in
+both records. Unless otherwise specified, the IPSECKEY public key
+field will contain the algorithm-specific portion of the KEY RR RDATA
+for the corresponding algorithm. The algorithm must still be
+designated for use by IPSECKEY, and an IPSECKEY algorithm type number
+(which might be different than the DNSSEC algorithm number) must be
+assigned to it.
+
+</p>
+<p>The DSA key format is defined in RFC2536 <a href="#RFC2536">[11]</a>
+</p>
+<p>The RSA key format is defined in RFC3110 <a href="#RFC3110">[12]</a>,
+with the following changes:
+</p>
+<p>
+The earlier definition of RSA/MD5 in RFC2065 limited the exponent and
+modulus to 2552 bits in length. RFC3110 extended that limit to 4096
+bits for RSA/SHA1 keys. The IPSECKEY RR imposes no length limit on
+RSA public keys, other than the 65535 octet limit imposed by the
+two-octet length encoding. This length extension is applicable only
+to IPSECKEY and not to KEY RRs.
+
+</p>
+<a name="anchor9"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.3"></a><h3>3.&nbsp;Presentation formats</h3>
+
+<a name="rfc.section.3.1"></a><h4><a name="anchor10">3.1</a>&nbsp;Representation of IPSECKEY RRs</h4>
+
+<p>
+ IPSECKEY RRs may appear in a zone data master file.
+ The precedence, gateway type and algorithm and gateway fields are REQUIRED.
+ The base64 encoded public key block is OPTIONAL; if not present,
+ then the public key field of the resource record MUST be construed
+ as being zero octets in length.
+
+</p>
+<p>
+ The algorithm field is an unsigned integer. No mnemonics are defined.
+
+</p>
+<p>
+ If no gateway is to be indicated, then the gateway type field MUST
+ be zero, and the gateway field MUST be "."
+
+</p>
+<p>
+ The Public Key field is represented as a Base64 encoding of the
+ Public Key. Whitespace is allowed within the Base64 text. For a
+ definition of Base64 encoding, see
+<a href="#RFC1521">RFC1521</a>[3] Section 5.2.
+
+</p>
+<p>
+ The general presentation for the record as as follows:
+</p>
+</font><pre>
+IN IPSECKEY ( precedence gateway-type algorithm
+ gateway base64-encoded-public-key )
+</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+
+</p>
+<a name="rfc.section.3.2"></a><h4><a name="anchor11">3.2</a>&nbsp;Examples</h4>
+
+<p>
+An example of a node 192.0.2.38 that will accept IPsec tunnels on its
+own behalf.
+</p>
+</font><pre>
+38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2
+ 192.0.2.38
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+
+</p>
+<p>
+An example of a node, 192.0.2.38 that has published its key only.
+</p>
+</font><pre>
+38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2
+ .
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+
+</p>
+<p>
+An example of a node, 192.0.2.38 that has delegated authority to the node
+192.0.2.3.
+</p>
+</font><pre>
+38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2
+ 192.0.2.3
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+
+</p>
+<p>
+An example of a node, 192.0.1.38 that has delegated authority to the node
+with the identity "mygateway.example.com".
+</p>
+</font><pre>
+38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2
+ mygateway.example.com.
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+
+</p>
+<p>
+An example of a node, 2001:0DB8:0200:1:210:f3ff:fe03:4d0 that has
+delegated authority to the node 2001:0DB8:c000:0200:2::1
+</p>
+</font><pre>
+$ORIGIN 1.0.0.0.0.0.2.8.B.D.0.1.0.0.2.ip6.int.
+0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2
+ 2001:0DB8:0:8002::2000:1
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+</pre><font face="verdana, helvetica, arial, sans-serif" size="2">
+<p>
+
+</p>
+<a name="anchor12"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.4"></a><h3>4.&nbsp;Security Considerations</h3>
+
+<p>
+ This entire memo pertains to the provision of public keying material
+ for use by key management protocols such as ISAKMP/IKE (RFC2407)
+ <a href="#RFC2407">[9]</a>.
+
+</p>
+<p>
+The IPSECKEY resource record contains information that SHOULD be
+communicated to the end client in an integral fashion - i.e. free from
+modification. The form of this channel is up to the consumer of the
+data - there must be a trust relationship between the end consumer of this
+resource record and the server. This relationship may be end-to-end
+DNSSEC validation, a TSIG or SIG(0) channel to another secure source,
+a secure local channel on the host, or some combination of the above.
+
+</p>
+<p>
+The keying material provided by the IPSECKEY resource record is not
+sensitive to passive attacks. The keying material may be freely
+disclosed to any party without any impact on the security properties
+of the resulting IPsec session: IPsec and IKE provide for defense
+against both active and passive attacks.
+
+</p>
+<p>
+ Any user of this resource record MUST carefully document their trust
+ model, and why the trust model of DNSSEC is appropriate, if that is
+ the secure channel used.
+
+</p>
+<a name="rfc.section.4.1"></a><h4><a name="anchor13">4.1</a>&nbsp;Active attacks against unsecured IPSECKEY resource records</h4>
+
+<p>
+This section deals with active attacks against the DNS. These attacks
+require that DNS requests and responses be intercepted and changed.
+DNSSEC is designed to defend against attacks of this kind.
+
+</p>
+<p>
+The first kind of active attack is when the attacker replaces the
+keying material with either a key under its control or with garbage.
+
+</p>
+<p>
+If the attacker is not able to mount a subsequent
+man-in-the-middle attack on the IKE negotiation after replacing the
+public key, then this will result in a denial of service, as the
+authenticator used by IKE would fail.
+
+</p>
+<p>
+If the attacker is able to both to mount active attacks against DNS
+and is also in a position to perform a man-in-the-middle attack on IKE and
+IPsec negotiations, then the attacker will be in a position to compromise
+the resulting IPsec channel. Note that an attacker must be able to
+perform active DNS attacks on both sides of the IKE negotiation in
+order for this to succeed.
+
+</p>
+<p>
+The second kind of active attack is one in which the attacker replaces
+the the gateway address to point to a node under the attacker's
+control. The attacker can then either replace the public key or remove
+it, thus providing an IPSECKEY record of its own to match the
+gateway address.
+
+</p>
+<p>
+This later form creates a simple man-in-the-middle since the attacker
+can then create a second tunnel to the real destination. Note that, as before,
+this requires that the attacker also mount an active attack against
+the responder.
+
+</p>
+<p>
+Note that the man-in-the-middle can not just forward cleartext
+packets to the original destination. While the destination may be
+willing to speak in the clear, replying to the original sender,
+the sender will have already created a policy expecting ciphertext.
+Thus, the attacker will need to intercept traffic from both sides. In some
+cases, the attacker may be able to accomplish the full intercept by use
+of Network Addresss/Port Translation (NAT/NAPT) technology.
+
+</p>
+<p>
+Note that the danger here only applies to cases where the gateway
+field of the IPSECKEY RR indicates a different entity than the owner
+name of the IPSECKEY RR. In cases where the end-to-end integrity of
+the IPSECKEY RR is suspect, the end client MUST restrict its use
+of the IPSECKEY RR to cases where the RR owner name matches the
+content of the gateway field.
+
+</p>
+<a name="anchor14"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.5"></a><h3>5.&nbsp;IANA Considerations</h3>
+
+<p>
+This document updates the IANA Registry for DNS Resource Record Types
+by assigning type X to the IPSECKEY record.
+
+</p>
+<p>
+This document creates an IANA registry for the algorithm type field.
+
+</p>
+<p>
+Values 0, 1 and 2 are defined in <a href="#algotype">RDATA format - algorithm type</a>. Algorithm numbers
+3 through 255 can be assigned by IETF Consensus (<a href="#RFC2434">see RFC2434</a>[6]).
+
+</p>
+<p>
+This document creates an IANA registry for the gateway type field.
+
+</p>
+<p>
+Values 0, 1, 2 and 3 are defined in <a href="#gatewaytype">RDATA format - gateway type</a>.
+Algorithm numbers 4 through 255 can be assigned by
+Standards Action (<a href="#RFC2434">see RFC2434</a>[6]).
+
+</p>
+<a name="anchor15"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<a name="rfc.section.6"></a><h3>6.&nbsp;Acknowledgments</h3>
+
+<p>
+My thanks to Paul Hoffman, Sam Weiler, Jean-Jacques Puig, Rob Austein,
+and Olafur Gurmundsson who reviewed this document carefully.
+Additional thanks to Olafur Gurmundsson for a reference implementation.
+
+</p>
+<a name="rfc.references1"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<h3>Normative references</h3>
+<table width="99%" border="0">
+<tr><td class="author-text" valign="top"><b><a name="RFC1034">[1]</a></b></td>
+<td class="author-text">Mockapetris, P., "<a href="ftp://ftp.isi.edu/in-notes/rfc1034.txt">Domain names - concepts and facilities</a>", STD 13, RFC 1034, November 1987.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC1035">[2]</a></b></td>
+<td class="author-text"><a href="mailto:">Mockapetris, P.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1035.txt">Domain names - implementation and specification</a>", STD 13, RFC 1035, November 1987.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC1521">[3]</a></b></td>
+<td class="author-text"><a href="mailto:nsb@bellcore.com">Borenstein, N.</a> and <a href="mailto:">N. Freed</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1521.txt">MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies</a>", RFC 1521, September 1993.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2026">[4]</a></b></td>
+<td class="author-text"><a href="mailto:sob@harvard.edu">Bradner, S.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2026.txt">The Internet Standards Process -- Revision 3</a>", BCP 9, RFC 2026, October 1996.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2065">[5]</a></b></td>
+<td class="author-text"><a href="mailto:dee@cybercash.com">Eastlake, D.</a> and <a href="mailto:charlie_kaufman@iris.com">C. Kaufman</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2065.txt">Domain Name System Security Extensions</a>", RFC 2065, January 1997.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2434">[6]</a></b></td>
+<td class="author-text"><a href="mailto:narten@raleigh.ibm.com">Narten, T.</a> and <a href="mailto:Harald@Alvestrand.no">H. Alvestrand</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2434.txt">Guidelines for Writing an IANA Considerations Section in RFCs</a>", BCP 26, RFC 2434, October 1998.</td></tr>
+</table>
+
+<a name="rfc.references2"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<h3>Non-normative references</h3>
+<table width="99%" border="0">
+<tr><td class="author-text" valign="top"><b><a name="RFC1886">[7]</a></b></td>
+<td class="author-text"><a href="mailto:set@thumper.bellcore.com">Thomson, S.</a> and <a href="mailto:Christian.Huitema@MIRSA.INRIA.FR">C. Huitema</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc1886.txt">DNS Extensions to support IP version 6</a>", RFC 1886, December 1995.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2119">[8]</a></b></td>
+<td class="author-text"><a href="mailto:-">Bradner, S.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2119.txt">Key words for use in RFCs to Indicate Requirement Levels</a>", BCP 14, RFC 2119, March 1997.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2407">[9]</a></b></td>
+<td class="author-text"><a href="mailto:ddp@network-alchemy.com">Piper, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2407.txt">The Internet IP Security Domain of Interpretation for ISAKMP</a>", RFC 2407, November 1998.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2535">[10]</a></b></td>
+<td class="author-text"><a href="mailto:dee3@us.ibm.com">Eastlake, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2535.txt">Domain Name System Security Extensions</a>", RFC 2535, March 1999.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC2536">[11]</a></b></td>
+<td class="author-text"><a href="mailto:dee3@us.ibm.com">Eastlake, D.</a>, "<a href="ftp://ftp.isi.edu/in-notes/rfc2536.txt">DSA KEYs and SIGs in the Domain Name System (DNS)</a>", RFC 2536, March 1999.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC3110">[12]</a></b></td>
+<td class="author-text">Eastlake, D., "<a href="ftp://ftp.isi.edu/in-notes/rfc3110.txt">RSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)</a>", RFC 3110, May 2001.</td></tr>
+<tr><td class="author-text" valign="top"><b><a name="RFC3445">[13]</a></b></td>
+<td class="author-text">Massey, D. and S. Rose, "<a href="ftp://ftp.isi.edu/in-notes/rfc3445.txt">Limiting the Scope of the KEY Resource Record (RR)</a>", RFC 3445, December 2002.</td></tr>
+</table>
+
+<a name="rfc.authors"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<h3>Author's Address</h3>
+<table width="99%" border="0" cellpadding="0" cellspacing="0">
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">Michael C. Richardson</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">Sandelman Software Works</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">470 Dawson Avenue</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">Ottawa, ON K1Z 5V7</td></tr>
+<tr><td class="author-text">&nbsp;</td>
+<td class="author-text">CA</td></tr>
+<tr><td class="author" align="right">EMail:&nbsp;</td>
+<td class="author-text"><a href="mailto:mcr@sandelman.ottawa.on.ca">mcr@sandelman.ottawa.on.ca</a></td></tr>
+<tr><td class="author" align="right">URI:&nbsp;</td>
+<td class="author-text"><a href="http://www.sandelman.ottawa.on.ca/">http://www.sandelman.ottawa.on.ca/</a></td></tr>
+</table>
+<a name="rfc.copyright"><br><hr size="1" shade="0"></a>
+<table border="0" cellpadding="0" cellspacing="2" width="30" height="15" align="right"><tr><td bgcolor="#990000" align="center" width="30" height="15"><a href="#toc" CLASS="link2"><font face="monaco, MS Sans Serif" color="#ffffff" size="1"><b>&nbsp;TOC&nbsp;</b></font></a><br></td></tr></table>
+<h3>Full Copyright Statement</h3>
+<p class='copyright'>
+Copyright (C) The Internet Society (2003). All Rights Reserved.</p>
+<p class='copyright'>
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published and
+distributed, in whole or in part, without restriction of any kind,
+provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.</p>
+<p class='copyright'>
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.</p>
+<p class='copyright'>
+This document and the information contained herein is provided on an
+&quot;AS IS&quot; basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.</p>
+<h3>Acknowledgement</h3>
+<p class='copyright'>
+Funding for the RFC Editor function is currently provided by the
+Internet Society.</p>
+</font></body></html>
diff --git a/doc/src/draft-richardson-ipsec-rr.xml b/doc/src/draft-richardson-ipsec-rr.xml
new file mode 100644
index 000000000..e51b32615
--- /dev/null
+++ b/doc/src/draft-richardson-ipsec-rr.xml
@@ -0,0 +1,560 @@
+<?xml version="1.0"?>
+<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
+<?rfc toc="yes"?>
+
+<rfc ipr="full2026" docName="draft-ietf-ipseckey-rr-07.txt">
+
+<front>
+ <area>Security</area>
+ <workgroup>IPSECKEY WG</workgroup>
+ <title abbrev="ipsecrr">
+ A method for storing IPsec keying material in DNS.
+ </title>
+
+ <author initials="M." surname="Richardson" fullname="Michael C. Richardson">
+ <organization abbrev="SSW">Sandelman Software Works</organization>
+ <address>
+ <postal>
+ <street>470 Dawson Avenue</street>
+ <city>Ottawa</city>
+ <region>ON</region>
+ <code>K1Z 5V7</code>
+ <country>CA</country>
+ </postal>
+ <email>mcr@sandelman.ottawa.on.ca</email>
+ <uri>http://www.sandelman.ottawa.on.ca/</uri>
+ </address>
+ </author>
+
+ <date month="September" year="2003" />
+
+<abstract>
+ <t>
+This document describes a new resource record for DNS. This record may be
+used to store public keys for use in IPsec systems.
+</t>
+
+<t>
+This record replaces the functionality of the sub-type #1 of the KEY Resource
+Record, which has been obsoleted by RFC3445.
+</t>
+</abstract>
+
+</front>
+
+<middle>
+
+<section title="Introduction">
+<t>
+ The type number for the IPSECKEY RR is TBD.
+</t>
+
+<section title="Overview">
+<t>
+ The IPSECKEY resource record (RR) is used to publish a public key that is
+ to be associated with a Domain Name System (DNS) name for use with the
+ IPsec protocol suite. This can be the public key of a host,
+ network, or application (in the case of per-port keying).
+</t>
+
+<t>
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
+ NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
+ "OPTIONAL" in this document are to be interpreted as described in
+ RFC2119 <xref target="RFC2119" />.
+</t>
+</section>
+
+<section title="Usage Criteria">
+<t>
+ An IPSECKEY resource record SHOULD be used in combination with DNSSEC
+unless some other means of authenticating the IPSECKEY resource record
+is available.
+</t>
+
+<t>
+ It is expected that there will often be multiple IPSECKEY resource
+ records at the same name. This will be due to the presence
+ of multiple gateways and the need to rollover keys.
+
+</t>
+
+<t>
+ This resource record is class independent.
+</t>
+</section>
+</section>
+
+<section title="Storage formats">
+
+<section title="IPSECKEY RDATA format">
+
+<t>
+ The RDATA for an IPSECKEY RR consists of a precedence value, a public key,
+ algorithm type, and an optional gateway address.
+</t>
+
+<artwork><![CDATA[
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | precedence | gateway type | algorithm | gateway |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------+ +
+ ~ gateway ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | /
+ / public key /
+ / /
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
+]]></artwork>
+</section>
+
+<section title="RDATA format - precedence">
+<t>
+This is an 8-bit precedence for this record. This is interpreted in
+the same way as the PREFERENCE field described in section
+3.3.9 of RFC1035 <xref target="RFC1035" />.
+</t>
+<t>
+Gateways listed in IPSECKEY records with lower precedence are
+to be attempted first. Where there is a tie in precedence, the order
+should be non-deterministic.
+</t>
+</section>
+
+<section anchor="algotype" title="RDATA format - algorithm type">
+<t>
+The algorithm type field identifies the public key's cryptographic
+algorithm and determines the format of the public key field.
+</t>
+
+<t>
+A value of 0 indicates that no key is present.
+</t>
+
+<t>
+The following values are defined:
+ <list style="hanging">
+ <t hangText="1">A DSA key is present, in the format defined in RFC2536 <xref target="RFC2536" /></t>
+ <t hangText="2">A RSA key is present, in the format defined in RFC3110 <xref target="RFC3110" /></t>
+ </list>
+</t>
+
+</section>
+
+<section anchor="gatewaytype" title="RDATA format - gateway type">
+<t>
+The gateway type field indicates the format of the information that
+is stored in the gateway field.
+</t>
+
+<t>
+The following values are defined:
+ <list style="hanging">
+ <t hangText="0">No gateway is present</t>
+ <t hangText="1">A 4-byte IPv4 address is present</t>
+ <t hangText="2">A 16-byte IPv6 address is present</t>
+ <t hangText="3">A wire-encoded domain name is present. The wire-encoded
+format is self-describing, so the length is implicit. The domain name
+MUST NOT be compressed.</t>
+ </list>
+</t>
+
+</section>
+
+<section title="RDATA format - gateway">
+<t>
+The gateway field indicates a gateway to which an IPsec tunnel may be
+created in order to reach the entity named by this resource record.
+</t>
+<t>
+There are three formats:
+</t>
+
+<t>
+A 32-bit IPv4 address is present in the gateway field. The data
+portion is an IPv4 address as described in section 3.4.1 of
+<xref target="RFC1035">RFC1035</xref>. This is a 32-bit number in network byte order.
+</t>
+
+<t>A 128-bit IPv6 address is present in the gateway field.
+The data portion is an IPv6 address as described in section 2.2 of
+<xref target="RFC1886">RFC1886</xref>. This is a 128-bit number in network byte order.
+</t>
+
+<t>
+The gateway field is a normal wire-encoded domain name, as described
+in section 3.3 of RFC1035 <xref target="RFC1035" />. Compression MUST NOT be used.
+</t>
+
+</section>
+
+<section title="RDATA format - public keys">
+<t>
+Both of the public key types defined in this document (RSA and DSA)
+inherit their public key formats from the corresponding KEY RR formats.
+Specifically, the public key field contains the algorithm-specific
+portion of the KEY RR RDATA, which is all of the KEY RR DATA after the
+first four octets. This is the same portion of the KEY RR that must be
+specified by documents that define a DNSSEC algorithm.
+Those documents also specify a message digest to be used for generation
+of SIG RRs; that specification is not relevant for IPSECKEY RR.
+</t>
+
+<t>
+Future algorithms, if they are to be used by both DNSSEC (in the KEY
+RR) and IPSECKEY, are likely to use the same public key encodings in
+both records. Unless otherwise specified, the IPSECKEY public key
+field will contain the algorithm-specific portion of the KEY RR RDATA
+for the corresponding algorithm. The algorithm must still be
+designated for use by IPSECKEY, and an IPSECKEY algorithm type number
+(which might be different than the DNSSEC algorithm number) must be
+assigned to it.
+</t>
+
+<t>The DSA key format is defined in RFC2536 <xref target="RFC2536" /></t>.
+
+<t>The RSA key format is defined in RFC3110 <xref target="RFC3110" />,
+with the following changes:</t>
+
+<t>
+The earlier definition of RSA/MD5 in RFC2065 limited the exponent and
+modulus to 2552 bits in length. RFC3110 extended that limit to 4096
+bits for RSA/SHA1 keys. The IPSECKEY RR imposes no length limit on
+RSA public keys, other than the 65535 octet limit imposed by the
+two-octet length encoding. This length extension is applicable only
+to IPSECKEY and not to KEY RRs.
+</t>
+
+</section>
+
+</section>
+
+
+
+<section title="Presentation formats">
+
+<section title="Representation of IPSECKEY RRs">
+<t>
+ IPSECKEY RRs may appear in a zone data master file.
+ The precedence, gateway type and algorithm and gateway fields are REQUIRED.
+ The base64 encoded public key block is OPTIONAL; if not present,
+ then the public key field of the resource record MUST be construed
+ as being zero octets in length.
+</t>
+<t>
+ The algorithm field is an unsigned integer. No mnemonics are defined.
+</t>
+<t>
+ If no gateway is to be indicated, then the gateway type field MUST
+ be zero, and the gateway field MUST be "."
+</t>
+
+<t>
+ The Public Key field is represented as a Base64 encoding of the
+ Public Key. Whitespace is allowed within the Base64 text. For a
+ definition of Base64 encoding, see
+<xref target="RFC1521">RFC1521</xref> Section 5.2.
+</t>
+
+
+<t>
+ The general presentation for the record as as follows:
+<artwork><![CDATA[
+IN IPSECKEY ( precedence gateway-type algorithm
+ gateway base64-encoded-public-key )
+]]></artwork>
+</t>
+</section>
+
+
+<section title="Examples">
+<t>
+An example of a node 192.0.2.38 that will accept IPsec tunnels on its
+own behalf.
+<artwork><![CDATA[
+38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2
+ 192.0.2.38
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+]]></artwork>
+</t>
+
+<t>
+An example of a node, 192.0.2.38 that has published its key only.
+<artwork><![CDATA[
+38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2
+ .
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+]]></artwork>
+</t>
+
+<t>
+An example of a node, 192.0.2.38 that has delegated authority to the node
+192.0.2.3.
+<artwork><![CDATA[
+38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2
+ 192.0.2.3
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+]]></artwork>
+</t>
+
+<t>
+An example of a node, 192.0.1.38 that has delegated authority to the node
+with the identity "mygateway.example.com".
+<artwork><![CDATA[
+38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2
+ mygateway.example.com.
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+]]></artwork>
+</t>
+
+<t>
+An example of a node, 2001:0DB8:0200:1:210:f3ff:fe03:4d0 that has
+delegated authority to the node 2001:0DB8:c000:0200:2::1
+<artwork><![CDATA[
+$ORIGIN 1.0.0.0.0.0.2.8.B.D.0.1.0.0.2.ip6.int.
+0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2
+ 2001:0DB8:0:8002::2000:1
+ AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )
+]]></artwork>
+</t>
+
+</section>
+</section>
+
+<section title="Security Considerations">
+<t>
+ This entire memo pertains to the provision of public keying material
+ for use by key management protocols such as ISAKMP/IKE (RFC2407)
+ <xref target="RFC2407" />.
+</t>
+
+<t>
+The IPSECKEY resource record contains information that SHOULD be
+communicated to the end client in an integral fashion - i.e. free from
+modification. The form of this channel is up to the consumer of the
+data - there must be a trust relationship between the end consumer of this
+resource record and the server. This relationship may be end-to-end
+DNSSEC validation, a TSIG or SIG(0) channel to another secure source,
+a secure local channel on the host, or some combination of the above.
+</t>
+
+<t>
+The keying material provided by the IPSECKEY resource record is not
+sensitive to passive attacks. The keying material may be freely
+disclosed to any party without any impact on the security properties
+of the resulting IPsec session: IPsec and IKE provide for defense
+against both active and passive attacks.
+</t>
+
+<t>
+ Any user of this resource record MUST carefully document their trust
+ model, and why the trust model of DNSSEC is appropriate, if that is
+ the secure channel used.
+</t>
+
+<section title="Active attacks against unsecured IPSECKEY resource records">
+<t>
+This section deals with active attacks against the DNS. These attacks
+require that DNS requests and responses be intercepted and changed.
+DNSSEC is designed to defend against attacks of this kind.
+</t>
+
+<t>
+The first kind of active attack is when the attacker replaces the
+keying material with either a key under its control or with garbage.
+</t>
+
+<t>
+If the attacker is not able to mount a subsequent
+man-in-the-middle attack on the IKE negotiation after replacing the
+public key, then this will result in a denial of service, as the
+authenticator used by IKE would fail.
+</t>
+
+<t>
+If the attacker is able to both to mount active attacks against DNS
+and is also in a position to perform a man-in-the-middle attack on IKE and
+IPsec negotiations, then the attacker will be in a position to compromise
+the resulting IPsec channel. Note that an attacker must be able to
+perform active DNS attacks on both sides of the IKE negotiation in
+order for this to succeed.
+</t>
+
+<t>
+The second kind of active attack is one in which the attacker replaces
+the the gateway address to point to a node under the attacker's
+control. The attacker can then either replace the public key or remove
+it, thus providing an IPSECKEY record of its own to match the
+gateway address.
+</t>
+
+<t>
+This later form creates a simple man-in-the-middle since the attacker
+can then create a second tunnel to the real destination. Note that, as before,
+this requires that the attacker also mount an active attack against
+the responder.
+</t>
+
+<t>
+Note that the man-in-the-middle can not just forward cleartext
+packets to the original destination. While the destination may be
+willing to speak in the clear, replying to the original sender,
+the sender will have already created a policy expecting ciphertext.
+Thus, the attacker will need to intercept traffic from both sides. In some
+cases, the attacker may be able to accomplish the full intercept by use
+of Network Addresss/Port Translation (NAT/NAPT) technology.
+</t>
+
+<t>
+Note that the danger here only applies to cases where the gateway
+field of the IPSECKEY RR indicates a different entity than the owner
+name of the IPSECKEY RR. In cases where the end-to-end integrity of
+the IPSECKEY RR is suspect, the end client MUST restrict its use
+of the IPSECKEY RR to cases where the RR owner name matches the
+content of the gateway field.
+</t>
+</section>
+
+</section>
+
+<section title="IANA Considerations">
+<t>
+This document updates the IANA Registry for DNS Resource Record Types
+by assigning type X to the IPSECKEY record.
+</t>
+
+<t>
+This document creates an IANA registry for the algorithm type field.
+</t>
+<t>
+Values 0, 1 and 2 are defined in <xref target="algotype" />. Algorithm numbers
+3 through 255 can be assigned by IETF Consensus (<xref target="RFC2434">see RFC2434</xref>).
+</t>
+
+<t>
+This document creates an IANA registry for the gateway type field.
+</t>
+<t>
+Values 0, 1, 2 and 3 are defined in <xref target="gatewaytype" />.
+Algorithm numbers 4 through 255 can be assigned by
+Standards Action (<xref target="RFC2434">see RFC2434</xref>).
+</t>
+
+
+
+</section>
+
+<section title="Acknowledgments">
+<t>
+My thanks to Paul Hoffman, Sam Weiler, Jean-Jacques Puig, Rob Austein,
+and Olafur Gurmundsson who reviewed this document carefully.
+Additional thanks to Olafur Gurmundsson for a reference implementation.
+</t>
+</section>
+
+</middle>
+
+<back>
+<references title="Normative references">
+<!-- DNSSEC -->
+<?rfc include="reference.RFC.1034" ?>
+<?rfc include="reference.RFC.1035" ?>
+<?rfc include="reference.RFC.1521" ?>
+<?rfc include="reference.RFC.2026" ?>
+<?rfc include="reference.RFC.2065" ?>
+<?rfc include="reference.RFC.2434" ?>
+</references>
+
+<references title="Non-normative references">
+<?rfc include="reference.RFC.1886" ?>
+<?rfc include="reference.RFC.2119" ?>
+<?rfc include="reference.RFC.2407" ?>
+<?rfc include="reference.RFC.2535" ?>
+<?rfc include="reference.RFC.2536" ?>
+<?rfc include="reference.RFC.3110" ?>
+<?rfc include="reference.RFC.3445" ?>
+</references>
+</back>
+</rfc>
+<!--
+ $Id: draft-richardson-ipsec-rr.xml,v 1.1 2004/03/15 20:35:24 as Exp $
+
+ $Log: draft-richardson-ipsec-rr.xml,v $
+ Revision 1.1 2004/03/15 20:35:24 as
+ added files from freeswan-2.04-x509-1.5.3
+
+ Revision 1.23 2003/09/04 23:26:09 mcr
+ more nits.
+
+ Revision 1.22 2003/08/16 15:55:35 mcr
+ fixed version to -06.
+
+ Revision 1.21 2003/08/16 15:52:32 mcr
+ Sam's comments on IANA considerations.
+
+ Revision 1.20 2003/07/27 22:57:54 mcr
+ updated document with new text about a seperate registry
+ for the algorithm type.
+
+ Revision 1.19 2003/06/30 01:51:50 mcr
+ minor typo fixes.
+
+ Revision 1.18 2003/06/16 17:45:00 mcr
+ adjusted date on rev-04.
+
+ Revision 1.17 2003/06/16 17:41:30 mcr
+ revision -04
+
+ Revision 1.16 2003/06/16 17:39:20 mcr
+ adjusted typos, and adjusted IANA considerations.
+
+ Revision 1.15 2003/05/26 19:31:23 mcr
+ updates to drafts - IPSEC RR - SC versions, and RFC3526
+ reference in OE draft.
+
+ Revision 1.14 2003/05/23 13:57:40 mcr
+ updated draft ##.
+
+ Revision 1.13 2003/05/23 13:54:45 mcr
+ updated month on draft.
+
+ Revision 1.12 2003/05/21 15:42:49 mcr
+ new SC section with comments from Rob Austein.
+
+ Revision 1.11 2003/05/20 20:52:22 mcr
+ new security considerations section.
+
+ Revision 1.10 2003/05/20 19:07:47 mcr
+ rewrote Security Considerations.
+
+ Revision 1.9 2003/05/20 18:17:09 mcr
+ nits from Rob Austein.
+
+ Revision 1.8 2003/04/29 00:44:59 mcr
+ updates according to WG consensus: restored three-way
+ gateway field type.
+
+ Revision 1.7 2003/03/30 17:00:29 mcr
+ updates according to community feedback.
+
+ Revision 1.6 2003/03/19 02:20:24 mcr
+ updated draft based upon comments from working group
+
+ Revision 1.5 2003/02/23 22:39:22 mcr
+ updates to IPSECKEY draft.
+
+ Revision 1.4 2003/02/21 04:39:04 mcr
+ updated drafts, and added crosscompile.html
+
+ Revision 1.3 2003/01/17 16:26:34 mcr
+ updated IPSEC KEY draft with restrictions.
+
+ Revision 1.2 2002/08/26 18:20:54 mcr
+ updated documents
+
+ Revision 1.1 2002/08/10 20:05:33 mcr
+ document proposing IPSECKEY Resource Record
+
+
+!>
diff --git a/doc/src/faq.html b/doc/src/faq.html
new file mode 100644
index 000000000..f62fc1c88
--- /dev/null
+++ b/doc/src/faq.html
@@ -0,0 +1,2770 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN FAQ</title>
+ <meta name="keywords" content="Linux, IPsec, VPN, security, FreeSWAN, FAQ">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: faq.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1>FreeS/WAN FAQ</h1>
+
+<p>This is a collection of questions and answers, mostly taken from the
+FreeS/WAN <a href="mail.html">mailing list</a>. See the project <a
+href="http://www.freeswan.org/">web site</a> for more information. All the
+FreeS/WAN documentation is online there.</p>
+
+<p>Contributions to the FAQ are welcome. Please send them to the project <a
+href="mail.html">mailing list</a>.</p>
+<hr>
+
+<h2><a name="questions">Index of FAQ questions</a></h2>
+<ul>
+ <li><a href="#whatzit">What is FreeS/WAN?</a></li>
+ <li><a href="#problems">How do I report a problem or seek help?</a></li>
+ <li><a href="#generic">Can I get ...</a>
+ <ul>
+ <li><a href="#lemme_out">... an off-the-shelf system that includes
+ FreeS/WAN?</a></li>
+ <li><a href="#contractor">... contractors or staff who know
+ FreeS/WAN?</a></li>
+ <li><a href="#commercial">... commercial support?</a></li>
+ </ul>
+ </li>
+ <li><a href="#release">Release questions</a>
+ <ul>
+ <li><a href="#rel.current">What is the current release?</a></li>
+ <li><a href="#relwhen">When is the next release?</a></li>
+ <li><a href="#rel.bugs">Are there known bugs in the current
+ release?</a></li>
+ </ul>
+ </li>
+ <li><a href="mod_cons">Modifications and contributions</a>
+ <ul>
+ <li><a href="#modify.faq">Can I modify FreeS/WAN to ...?</a></li>
+ <li><a href="#contrib.faq">Can I contribute to the project?</a></li>
+ <li><a href="#ddoc.faq">Is there detailed design documentation?</a></li>
+ </ul>
+ </li>
+ <li><a href="#interact">Will FreeS/WAN work in my environment?</a>
+ <ul>
+ <li><a href="#interop.faq">Can FreeS/WAN talk to ... ?</a></li>
+ <li><a href="#old_to_new">Can different FreeS/WAN versions talk to each
+ other?</a></li>
+ <li><a href="#faq.bandwidth">Is there a limit on throughput?</a></li>
+ <li><a href="#faq.number">Is there a limit on number of
+ connections?</a></li>
+ <li><a href="#faq.speed">Is a ... fast enough to handle FreeS/WAN with
+ my loads?</a></li>
+ </ul>
+ </li>
+ <li><a href="#work_on">Will FreeS/WAN work on ...</a>
+ <ul>
+ <li><a href="#versions">... my version of Linux?</a></li>
+ <li><a href="#nonIntel.faq">... non-Intel CPUs?</a></li>
+ <li><a href="#multi.faq">... multiprocessors?</a></li>
+ <li><a href="#k.old">... an older kernel?</a></li>
+ <li><a href="#k.versions">... the latest kernel version?</a></li>
+ <li><a href="#interface.faq">... unusual network hardware?</a></li>
+ <li><a href="#vlan">... a VLAN (802.1q) network?</a></li>
+ </ul>
+ </li>
+ <li><a href="#features.faq">Does FreeS/WAN support ...</a>
+ <ul>
+ <li><a href="#VPN.faq">... site-to-site VPN applications</a></li>
+ <li><a href="#warrior.faq">... remote users connecting to a LAN</a></li>
+ <li><a href="#road.shared.possible">... remote users using shared
+ secret authentication?</a></li>
+ <li><a href="#wireless.faq">... wireless networks</a></li>
+ <li><a href="#PKIcert">... X.509 or other PKI certificates?</a></li>
+ <li><a href="#Radius">... user authentication (Radius, SecureID,
+ Smart Card ...)?</a></li>
+ <li><a href="#NATtraversal">... NAT traversal</a></li>
+ <li><a href="#virtID">... assigning a "virtual identity" to a remote
+ system?</a></li>
+ <li><a href="#noDES.faq">... single DES encryption?</a></li>
+ <li><a href="#AES.faq">... AES encryption?</a></li>
+ <li><a href="#other.cipher">... other encryption algorithms?</a></li>
+ </ul>
+ </li>
+ <li><a href="#canI">Can I ...</a>
+ <ul>
+ <li><a href="#policy.preconfig">...use policy groups along with
+ explicitly configured connections?</a></li>
+ <li><a href="#policy.off">...turn off policy groups?</a></li>
+<!--
+ <li><a href="#policy.otherinterface">...use policy groups
+ on an interface other than <VAR>%defaultroute</VAR>?</a></li>
+-->
+ <li><a href="#reload">... reload connection info without
+ restarting?</a></li>
+ <li><a href="#masq.faq">... use several masqueraded subnets?</a></li>
+ <li><a href="#dup_route">... use subnets masqueraded to the same
+ addresses?</a></li>
+ <li><a href="#road.masq">... assign a road warrior an address on my net
+ (a virtual identity)?</a></li>
+ <li><a href="#road.many">... support many road warriors with one
+ gateway?</a></li>
+ <li><a href="#road.PSK">... have many road warriors using shared secret
+ authentication?</a></li>
+ <li><a href="#QoS">... use Quality of Service routing with
+ FreeS/WAN?</a></li>
+ <li><a href="#deadtunnel">... recognise dead tunnels and shut them
+ down?</a></li>
+ <li><a href="#demanddial">... build IPsec tunnels over a demand-dialed
+ link?</a></li>
+ <li><a href="#GRE">... build GRE, L2TP or PPTP tunnels over IPsec?</a></li>
+ <li><a href="#NetBIOS">... use Network Neighborhood (Samba, NetBIOS) over IPsec?</a></li>
+ </ul>
+ </li>
+ <li><a href="#setup.faq">Life's little mysteries</a>
+ <ul>
+ <li><a href="#cantping">I cannot ping ....</a></li>
+ <li><a href="#forever">It takes forever to ...</a></li>
+ <li><a href="#route">I send packets to the tunnel with route(8) but
+ they vanish</a></li>
+ <li><a href="#down_route">When a tunnel goes down, packets
+ vanish</a></li>
+ <li><a href="#firewall_ate">The firewall ate my packets!</a></li>
+ <li><a href="#dropconn">Dropped connections</a></li>
+ <li><a href="#defaultroutegone">Disappearing %defaultroute</a></li>
+ <li><a href="#tcpdump.faq">TCPdump on the gateway shows strange
+ things</a></li>
+ <li><a href="#no_trace">Traceroute does not show anything between the
+ gateways</a></li>
+ </ul>
+ </li>
+ <li><a href="#man4debug">Testing in stages (or .... works but ...
+ doesn't)</a>
+ <ul>
+ <li><a href="#nomanual">Manually keyed connections don't work</a></li>
+ <li><a href="#spi_error">One manual connection works, but second one
+ fails</a></li>
+ <li><a href="#man_no_auto">Manual connections work, but automatic
+ keying doesn't</a></li>
+ <li><a href="#nocomp">IPsec works, but connections using compression
+ fail</a></li>
+ <li><a href="#pmtu.broken">Small packets work, but large transfers
+ fail</a></li>
+ <li><a href="#subsub">Subnet-to-subnet works, but tests from the
+ gateways don't</a></li>
+ </ul>
+ </li>
+ <li><a href="#compile.faq">Compilation problems</a>
+ <ul>
+ <li><a href="#gmp.h_missing">gmp.h: No such file or directory</a></li>
+ <li><a href="#noVM">... virtual memory exhausted</a></li>
+ </ul>
+ </li>
+ <li><a href="#error">Interpreting error messages</a>
+ <ul>
+ <li><a href="#route-client">route-client (or host) exited with status
+ 7</a></li>
+ <li><a href="#unreachable">SIOCADDRT:Network is unreachable</a></li>
+ <li><a href="#modprobe">ipsec_setup: modprobe: Can't locate
+ moduleipsec</a></li>
+ <li><a href="#noKLIPS">ipsec_setup: Fatal error, kernel appears to lack
+ KLIPS</a></li>
+ <li><a href="#noDNS">ipsec_setup: ... failure to fetch key for ... from
+ DNS</a></li>
+ <li><a href="#dup_address">ipsec_setup: ... interfaces ... and ...
+ share address ...</a></li>
+ <li><a href="#kflags">ipsec_setup: Cannot adjust kernel flags</a></li>
+ <li><a href="#message_num">Message numbers (MI3, QR1, et cetera) in
+ Pluto messages</a></li>
+ <li><a href="#conn_name">Connection names in Pluto error
+ messages</a></li>
+ <li><a href="#cantorient">Pluto: ... can't orient connection</a></li>
+ <li><a href="#no.interface">... we have no ipsecN interface for either
+ end of this connection</a></li>
+ <li><a href="#noconn">Pluto: ... no connection is known</a></li>
+ <li><a href="#nosuit">Pluto: ... no suitable connection ...</a></li>
+ <li><a href="#noconn.auth">Pluto: ... no connection has been
+ authorized</a></li>
+ <li><a href="#noDESsupport">Pluto: ... OAKLEY_DES_CBC is not
+ supported.</a></li>
+ <li><a href="#notransform">Pluto: ... no acceptable transform</a></li>
+ <li><a href="#rsasigkey">rsasigkey dumps core</a></li>
+ <li><a href="#sig4">!Pluto failure!: ... exited with ... signal
+ 4</a></li>
+ <li><a href="#econnrefused">ECONNREFUSED error message</a></li>
+ <li><a href="#no_eroute">klips_debug: ... no eroute!</a></li>
+ <li><a href="#SAused">... trouble writing to /dev/ipsec ... SA already
+ in use</a></li>
+ <li><a href="#ignore">... ignoring ... payload</a></li>
+ <li><a href="#unknown_rightcert">unknown parameter name "rightcert"</a></li>
+ </ul>
+ <li><a href="#spam">Why don't you restrict the mailing lists to reduce
+ spam?</a></li>
+</ul>
+<hr>
+
+<h2><a name="whatzit">What is FreeS/WAN?</a></h2>
+
+<p>FreeS/WAN is a Linux implementation of the <a
+href="glossary.html#IPSEC">IPsec</a> protocols, providing security services
+at the IP (Internet Protocol) level of the network.</p>
+
+<p>For more detail, see our <a href="intro.html">introduction</a> document or
+the FreeS/WAN project <a href="http://www.freeswan.org/">web site</a>.</p>
+
+<p>To start setting it up, go to our <a href="quickstart.html">quickstart
+guide</a>.</p>
+
+<p>Our <a href="web.html">web links</a> document has information on <a
+href="web.html#implement">IPsec for other systems</a>.</p>
+
+<h2><a name="problems">How do I report a problem or seek help?</a></h2>
+
+<DL>
+<DT>Read our <a href="trouble.html">troubleshooting</a> document.</DT>
+<DD><p>It may guide you to a solution. If not, see its
+<a href="trouble.html#prob.report">problem reporting</a> section.</p>
+
+<p>Basically, what it says is <strong>give us the output from <var>ipsec
+barf</var> from both gateways</strong>. Without full information, we cannot
+diagnose a problem. However, <var>ipsec barf</var> produces a lot of output.
+If at all possible, <strong>please make barfs accessible via the web or
+FTP</strong> rather than sending enormous mail messages.</p>
+</DD>
+
+<DT><strong>Use the <a href="mail.html">users mailing list</a> for problem
+reports</strong>, rather than mailing developers directly.
+</DT>
+
+<DD>
+<ul>
+ <li>This gives you access to more expertise, including users who may have
+ encountered and solved the same problems.</li>
+ <li>It is more likely to get a quick response. Developers may get behind on
+ email, or even ignore it entirely for a while, but a list message (given
+ a reasonable Subject: line) is certain to be read by a fair number of
+ people within hours.</li>
+ <li>It may also be important because of <a
+ href="politics.html#exlaw">cryptography export laws</a>. A US citizen who
+ provides technical assistance to foreign cryptographic work might be
+ charged under the arms export regulations. Such a charge would be easier
+ to defend if the discussion took place on a public mailing list than if
+ it were done in private mail.</li>
+</ul>
+</DD>
+
+<DT>Try irc.freenode.net#freeswan.</DT>
+
+<DD>
+<p>FreeS/WAN developers, volunteers and users can often be found there.
+Be patient and be
+prepared to provide lots of information to support your question.</p>
+
+<p>If your question was really interesting, and you found an answer,
+please share that with the class by posting to the
+<a href="mail.html">users mailing list</a>. That way others with the
+same problem can find your answer in the archives.</p>
+</DD>
+
+<DT>Premium support is also available.</DT>
+<DD>
+<p>See the next several questions.</p>
+</DD>
+</DL>
+
+<h2><a name="generic">Can I get ...</a></h2>
+
+<h3><a name="lemme_out">Can I get an off-the-shelf system that includes
+FreeS/WAN?</a></h3>
+
+<p>There are a number of Linux distributions or firewall products which
+include FreeS/WAN. See this <a href="intro.html#products">list</a>. Using one
+of these, chosen to match your requirements and budget, may save you
+considerable time and effort.</p>
+
+<p>If you don't know your requirements, start by reading Schneier's <a
+href="biblio.html#secrets">Secrets and Lies</a>. That gives the best overview
+of security issues I have seen. Then consider hiring a consultant (see next
+question) to help define your requirements.</p>
+
+<h3><a name="consultant">Can I hire consultants or staff who know
+FreeS/WAN?</a></h3>
+
+<p>If you want the help of a contractor, or to hire staff with FreeS/WAN
+expertise, you could:</p>
+<ul>
+ <li>check availability in your area through your local Linux User Group (<a
+ href="http://lugww.counter.li.org/">LUG Index</a>)</li>
+ <li>try asking on our <a href="mail.html">mailing list</a></li>
+</ul>
+
+<p>For companies offerring support, see the next question.</p>
+
+<h3><a name="commercial">Can I get commercial support?</a></h3>
+
+<p>Many of the distributions or firewall products which include FreeS/WAN
+(see this <a href="intro.html#products">list</a>) come with commercial
+support or have it available as an option.</p>
+
+<p>Various companies specialize in commercial support of open source
+software. Our project leader was a founder of the first such company, Cygnus
+Support. It has since been bought by <a
+href="http://www.redhat.com">Redhat</a>. Another such firm is <a
+href="http://www.linuxcare.com">Linuxcare</a>.</p>
+
+<h2><a name="release">Release questions</a></h2>
+
+<h3><a name="rel.current">What is the current release?</a></h3>
+
+<p>The current release is the highest-numbered tarball on our <a
+href="ftp://ftp.xs4all.nl/pub/crypto/freeswan">distribution site</a>. Almost
+always, any of <a href="intro.html#mirrors">the mirrors</a> will have the
+same file, though perhaps not for a day or so after a release.</p>
+
+<p>Unfortunately, the web site is not always updated as quickly as it should
+be.</p>
+
+<h3><a name="relwhen">When is the next release?</a></h3>
+
+<p>We try to do a release approximately every six to eight weeks.
+</p>
+
+<p>If pre-release tests fail and the fix appears complex, or more generally
+if the code does not appear stable when a release is scheduled, we will just
+skip that release.</p>
+
+<p>For serious bugs, we may bring out an extra bug-fix release. These get
+numbers in the normal release series. For example, there was a bug found in
+FreeS/WAN 1.6, so we did another release less than two weeks later. The
+bug-fix release was called 1.7.</p>
+
+<h3><a name="rel.bugs">Are there known bugs in the current release?</a></h3>
+
+<p>Any problems we are aware of at the time of a release are documented in
+the <a href="../BUGS">BUGS</a> file for that release. You should also look at
+the <a href="../CHANGES">CHANGES</a> file.</p>
+
+<p>Bugs discovered after a release are discussed on the <a
+href="mail.html">mailing lists</a>. The easiest way to check for any problems
+in the current code would be to peruse the
+<a href="http://lists.freeswan.org/pipermail/briefs">List In Brief</a>.</p>
+
+<h2><a name="mod_cons">Modifications and contributions</a></h2>
+
+<h3><a name="modify.faq">Can I modify FreeS/WAN to ...?</a></h3>
+
+<p>You are free to modify FreeS/WAN in any way. See the discussion of <a
+href="intro.html#licensing">licensing</a> in our introduction document.</p>
+
+<p>Before investing much energy in any such project, we suggest that you</p>
+<ul>
+ <li>check the list of <a href="web.html#patch">existing patches</a></li>
+ <li>post something about your project to the <a href="mail.html">design
+ mailing list</a></li>
+</ul>
+
+<p>This may prevent duplicated effort, or lead to interesting
+collaborations.</p>
+
+<h3><a name="contrib.faq">Can I contribute to the project?</a></h3>
+In general, we welcome contributions from the community. Various contributed
+patches, either to fix bugs or to add features, have been incorporated into
+our distribution. Other patches, not yet included in the distribution, are
+listed in our <a href="web.html#patch">web links</a> section.
+
+<p>Users have also contributed heavily to documentation, both by creating
+their own <a href="intro.html#howto">HowTos</a> and by posting things on the
+<a href="mail.html">mailing lists</a> which I have quoted in these HTML
+docs.</p>
+
+<p>There are, however, some caveats.</p>
+
+<p>FreeS/WAN is being implemented in Canada, by Canadians, largely to ensure
+that is it is entirely free of export restrictions. See this <a
+href="politics.html#status">discussion</a>. We <strong>cannot accept code
+contributions from US residents or citizens</strong>, not even one-line bugs
+fixes. The reasons for this were recently discussed extensively on the
+mailing list, in a thread starting <a
+href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/01/msg00111.html">here</a>.</p>
+
+<p>Not all contributions are of interest to us. The project has a set of
+fairly ambitious and quite specific goals, described in our <a
+href="intro.html#goals">introduction</a>. Contributions that lead toward
+these goals are likely to be welcomed enthusiastically. Other contributions
+may be seen as lower priority, or even as a distraction.</p>
+
+<p>Discussion of possible contributions takes place on the <a
+href="mail.html">design mailing list</a>.</p>
+
+<h3><a name="ddoc.faq">Is there detailed design documentation?</a></h3>
+There are:
+<ul>
+ <li><a href="rfc.html">RFCs</a> specifying the protocols we implement</li>
+ <li><a href="manpages.html">man pages</a> for our utilities, library
+ functions and file formats</li>
+ <li>comments in the source code</li>
+ <li><a href="index.html">HTML documentation</a> written primarily for
+ users</li>
+ <li>archived discussions from the <a href="mail.html">mailing lists</a></li>
+ <li>other papers mentioned in our <a
+ href="intro.html#applied">introduction</a></li>
+</ul>
+
+<p>The only formal design documents are a few papers in the last category
+above. All the other categories, however, have things to say about design as
+well.</p>
+
+<h2><a name="interact">Will FreeS/WAN work in my environment?</a></h2>
+
+<h3><a name="interop.faq">Can FreeS/WAN talk to ...?</a></h3>
+
+<p>The IPsec protocols are designed to support interoperation. In theory, any
+two IPsec implementations should be able to talk to each other. In practice,
+it is considerably more complex. We have a whole <a
+href="interop.html">interoperation document</a> devoted to this problem.</p>
+
+<p>An important part of that document is links to the many <a
+href="interop.html#otherpub">user-written HowTos</a> on interoperation
+between FreeS/WAN and various other implementations. Often the users know
+more than the developers about these issues (and almost always more than me
+:-), so these documents may be your best resource.</p>
+
+<h3><a name="old_to_new">Can different FreeS/WAN versions talk to each
+other?</a></h3>
+
+<p>Linux FreeS/WAN can interoperate with many IPsec implementations,
+including earlier versions of Linux FreeS/WAN itself.</p>
+
+<p>In a few cases, there are some complications. See our <a
+href="interop.html#oldswan">interoperation</a> document for details.</p>
+
+<h3><a name="faq.bandwidth">Is there a limit on throughput?</a></h3>
+
+<p>There is no hard limit, but see below.</p>
+
+<h3><a name="faq.number">Is there a limit on number of tunnels?</a></h3>
+
+<p>There is no hard limit, but see next question.</p>
+
+<h3><a name="faq.speed">Is a ... fast enough to handle FreeS/WAN with my
+loads?</a></h3>
+
+<p>A quick summary:</p>
+<dl>
+ <dt>Even a limited machine can be useful</dt>
+ <dd>A 486 can handle a T1, ADSL or cable link, though the machine may be
+ breathing hard.</dd>
+ <dt>A mid-range PC (say 800 MHz with good network cards) can do a lot of
+ IPsec</dt>
+ <dd>With up to roughly 50 tunnels and aggregate bandwidth of 20 Megabits
+ per second, it willl have cycles left over for other tasks.</dd>
+ <dt>There are limits</dt>
+ <dd>Even a high end CPU will not come close to handling a fully loaded
+ 100 Mbit/second Ethernet link.
+ <p>Beyond about 50 tunnels it needs careful management.</p>
+ </dd>
+</dl>
+
+<p>See our <a href="performance.html">FreeS/WAN performance</a> document for
+details.</p>
+
+<h2><a name="work_on">Will FreeS/WAN work on ... ?</a></h2>
+
+<h3><a name="versions">Will FreeS/WAN run on my version of Linux?</a></h3>
+
+<p>We build and test on Redhat distributions, but FreeS/WAN runs just fine on
+several other distributions, sometimes with minor fiddles to adapt to the
+local environment. Details are in our <a
+href="compat.html#otherdist">compatibility</a> document. Also, some
+distributions or products come with <a href="intro.html#products">FreeS/WAN
+included</a>.</p>
+
+<h3><a name="nonIntel.faq">Will FreeS/WAN run on non-Intel CPUs?</a></h3>
+
+<p>FreeS/WAN is <strong>intended to run on all CPUs Linux supports</strong>.
+We know of it being used in production on x86, ARM, Alpha and MIPS. It has
+also had successful tests on PPC and SPARC, though we don't know of actual
+use there. Details are in our <a href="compat.html#CPUs">compatibility</a>
+document.</p>
+
+<h3><a name="multi.faq">Will FreeS/WAN run on multiprocessors?</a></h3>
+
+<p>FreeS/WAN is designed to work on any SMP architecture Linux supports, and
+has been tested successfully on at least dual processor Intel architecture
+machines. Details are in our <a
+href="compat.html#multiprocessor">compatibility</a> document.</p>
+
+<h3><a name="k.old">Will FreeS/WAN work on an older kernel?</a></h3>
+
+<p>It might, but we strongly recommend using a recent 2.2 or 2.4 series
+kernel. Sometimes the newer versions include security fixes which can be
+quite important on a gateway.</p>
+
+<p>Also, we use recent kernels for development and testing, so those are
+better tested and, if you do encounter a problem, more easily supported. If
+something breaks applying recent FreeS/WAN patches to an older kernel, then
+"update your kernel" is almost certain to be the first thing we suggest. It
+may be the only suggestion we have.</p>
+
+<p>The precise kernel versions supported by a particular FreeS/WAN release
+are given in the <a href="XX">README</a> file of that release.</p>
+
+<p>See the following question for more on kernels.</p>
+
+<h3><a name="k.versions">Will FreeS/WAN run on the latest kernel
+version?</a></h3>
+
+<p>Sometimes yes, but quite often, no.</p>
+
+<p>Kernel versions supported are given in the <a href="../README">README</a>
+file of each FreeS/WAN release. Typically, they are whatever production
+kernels were current at the time of our release (or shortly before; we might
+release for kernel <var>n</var> just as Linus releases <var>n+1</var>). Often
+FreeS/WAN will work on slightly later kernels as well, but of course this
+cannot be guaranteed.</p>
+
+<p>For example, FreeS/WAN 1.91 was released for kernels 2.2.19 or 2.4.5, the
+current kernels at the time. It also worked on 2.4.6, 2.4.7 and 2.4.8, but
+2.4.9 had changes that caused compilation errors if it was patched with
+FreeS/WAN 1.91.</p>
+
+<p>When such changes appear, we put a fix in the FreeS/WAN snapshots, and
+distribute it with our next release. However, this is not a high priority for
+us, and it may take anything from a few days to several weeks for such a
+problem to find its way to the top of our kernel programmer's To-Do list. In
+the meanwhile, you have two choices:</p>
+<ul>
+ <li>either stick with a slightly older kernel, even if it is not the latest
+ and greatest. This is recommended for production systems; new versions
+ may have new bugs.</li>
+ <li>or fix the problem yourself and send us a patch, via the <a
+ href="mail.html">Users mailing list</a>.</li>
+</ul>
+
+<p>We don't even try to keep up with kernel changes outside the main 2.2 and
+2.4 branches, such as the 2.4.x-ac patched versions from Alan Cox or the 2.5
+series of development kernels. We'd rather work on developing the FreeS/WAN
+code than on chasing these moving targets. We are, however, happy to get
+patches for problems discovered there.</p>
+
+<p>See also the <a href="install.html#choosek">Choosing a kernel</a> section
+of our installation document.</p>
+
+<h3><a name="interface.faq">Will FreeS/WAN work on unusual network
+hardware?</a></h3>
+
+<p>IPsec is designed to work over any network that IP works over, and
+FreeS/WAN is intended to work over any network interface hardware that Linux
+supports.</p>
+
+<p>If you have working IP on some unusual interface -- perhaps Arcnet, Token
+Ring, ATM or Gigabit Ethernet -- then IPsec should "just work".</p>
+
+<p>That said, practice is sometimes less tractable than theory. Our testing
+is done almost entirely on:</p>
+<ul>
+ <li>10 or 100 Mbit Ethernet</li>
+ <li>ADSL or cable connections, with and without PPPoE</li>
+ <li>IEEE 802.11 wireless LANs (see <a href="#wireless.faq">below</a>)</li>
+</ul>
+
+<p>If you have some other interface, especially an uncommon one, it is
+entirely possible you will get bitten either by a FreeS/WAN bug which our
+testing did not turn up, or by a bug in the driver that shows up only with
+our loads.</p>
+
+<p>If IP works on your interface and FreeS/WAN doesn't, seek help on the <a
+href="mail.html">mailing lists</a>.</p>
+
+<p>Another FAQ section describes <a href="#pmtu.broken">MTU problems</a>.
+These are a possibility for some interfaces.</p>
+
+<h3><a name="vlan">Will FreeS/WAN work on a VLAN (802.1q) network?</a></h3>
+
+<p>
+ Yes, FreeSwan works fine, though some network drivers have problems
+ with jumbo sized ethernet frames. If you used interfaces=%defaultroute
+ you do not need to change anything, but if you specified an interface
+ (eg eth0) then remember you must change that to reflect the VLAN
+ interface (eg eth0.2 for VLAN ID 2).
+</p>
+<p>
+ The "eepro100" module is known to be broken, use the e100 driver
+ for those cards instead (included in 2.4 as 'alternative driver' for
+ the Intel EtherExpressPro/100.
+</p>
+<p>
+ You do not need to change any MTU setting (those are workarounds
+ that are only needed for buggy drivers)
+</p>
+
+<p><em>This FAQ contributed by Paul Wouters.</em></p>
+
+<h2><a name="features.faq">Does FreeS/WAN support ...</a></h2>
+
+<p>For a discussion of which parts of the IPsec specifications FreeS/WAN does
+and does not implement, see our <a href="compat.html#spec">compatibility</a>
+document.</p>
+
+<p>For information on some often-requested features, see below.</p>
+
+<h3><a name="VPN.faq"></a>Does FreeS/WAN support site-to-site VPN
+(<A HREF="glossary.html#VPN">Virtual Private Network</A>)
+applications?</h3>
+
+<p>Absolutely. See this FreeS/WAN-FreeS/WAN
+<A HREF="config.html">configuration example</A>.
+If only one site is using FreeS/WAN, there may be a relevant HOWTO on our
+<A HREF="interop.html">interop page</A>.
+</p>
+
+<h3><a name="warrior.faq">Does FreeS/WAN support remote users connecting to a
+LAN?</a></h3>
+
+<p>Yes. We call the remote users "Road Warriors". Check out our
+FreeS/WAN-FreeS/WAN
+<A HREF="config.html#config.rw">Road Warrior Configuration Example</A>.</P>
+
+<p>If your Road Warrior is a Windows or Mac PC, you may need to
+install an IPsec implementation on that machine.
+Our <A HREF="interop.html">interop</A> page lists many available brands,
+and features links to several HOWTOs.
+
+
+<h3><a name="road.shared.possible">Does FreeS/WAN support remote users using
+shared secret authentication?</a></h3>
+
+<p><strong>Yes, but</strong> there are severe restrictions, so <strong>we
+strongly recommend using </strong><a
+href="glossary.html#RSA"><strong>RSA</strong></a><strong> keys for
+</strong> <a
+href="glossary.html#authentication"><strong>authentication</strong></a>
+<strong>
+instead</strong>.</p>
+
+<p>See this <a href="#road.PSK">FAQ question</a>.</p>
+
+<h3><a name="wireless.faq">Does FreeS/WAN support wireless networks?</a></h3>
+
+<p>Yes, it is a common practice to use IPsec over wireless networks because
+their built-in encryption, <a href="glossary.html#WEP">WEP</a>, is
+insecure.</p>
+
+<p>There is some <a href="adv_config.html#wireless.config">discussion</a> in
+our advanced configuration document. See also the
+<A HREF="http://www.wavesec.org">WaveSEC site</A>.</p>
+
+<h3><a name="PKIcert">Does FreeS/WAN support X.509 or other PKI
+certificates?</a></h3>
+
+<P>Vanilla FreeS/WAN does not support X.509, but Andreas Steffen
+and others have provided a popular, well-supported X.509 patch.</P>
+
+<UL>
+<LI><A HREF="http://www.strongsec.com/freeswan">patch</A>
+</LI>
+<LI><A HREF="http://www.freeswan.ca">Super FreeS/WAN</A> incorporates
+this and other user-contributed patches.
+</LI>
+<LI>
+Kai Martius' <A HREF="http://www.strongsec.com/freeswan/install.htm">X.509
+Installation and Configuration Guide</A>
+</LI>
+</UL>
+
+<P>
+Linux FreeS/WAN features
+<A HREF="quickstart.html">Opportunistic Encryption</A>, an alternative
+Public Key Infrastructure based on Secure DNS.
+</P>
+
+<h3><a name="Radius">Does FreeS/WAN support user authentication (Radius,
+SecureID, Smart Card...)?</a></h3>
+
+<P>Andreas Steffen's <A HREF="http://www.strongsec.com/freeswan">X.509 patch</A> (v. 1.42+) supports Smart Cards. The patch
+does not ship with vanilla FreeS/WAN, but will be incorporated into
+<A HREF="http://www.freeswan.ca/">Super FreeS/WAN
+2.01+</A>. The patch implements the PCKS#15
+Cryptographic Token Information Format Standard, using the OpenSC smartcard
+library functions.</P>
+
+<P>Older news:</P>
+
+<P>A user-supported patch to FreeS/WAN 1.3, for smart card style
+authentication, is available on
+<A HREF="http://alcatraz.webcriminals.com/~bastiaan/ipsec">Bastiaan's site</A>.
+It supports skeyid and ibutton.
+This patch is not part of Super FreeS/WAN.</p>
+
+<p>For a while progress on this front was impeded by a lack of standard.
+The IETF <a
+href="http://www.ietf.org/html.charters/ipsra-charter.html">working group</a>
+has now nearly completed its recommended solution to the problem; meanwhile
+several vendors have implemented various things.</p>
+
+<!--
+<p>The <a href="web.html#patch">patches</a> section of our web links document
+has links to some user work on this.</p>
+-->
+
+<p>Of course, there are various ways to avoid any requirement for user
+authentication in IPsec. Consider the situation where road warriors build
+IPsec tunnels to your office net and you are considering requiring user
+authentication during tunnel negotiation. Alternatives include:</p>
+<ul>
+ <li>If you can trust the road warrior machines, then set them up so that
+ only authorised users can create tunnels. If your road warriors use
+ laptops, consider the possibility of theft.</li>
+ <li>If the tunnel only provides access to particular servers and you can
+ trust those servers, then set the servers up to require user
+ authentication.</li>
+</ul>
+
+<p>If either of those is trustworthy, it is not clear that you need user
+authentication in IPsec.</p>
+
+
+<h3><a name="NATtraversal">Does FreeS/WAN support NAT traversal?</a></h3>
+
+<p>Vanilla FreeS/WAN does not, but thanks to Mathieu Lafon and
+Arkoon Network Security, there's a patch to support this.</P>
+
+<UL>
+<LI><A HREF="http://open-source.arkoon.net">patch and documentation</A>
+</LI>
+<LI><A HREF="http://www.freeswan.ca">Super FreeS/WAN</A> incorporates
+this and other user-contributed patches.
+</LI>
+</UL>
+
+<P>The NAT traversal patch has some issues with PSKs, so you may wish to
+authenticate with RSA keys, or X.509 (requires a patch which is also
+included in Super FreeS/WAN). Doing the latter also has
+advantages when dealing with large numbers of clients who may be behind NAT;
+instead of having to make an individual Roadwarrior connection for each
+virtual IP, you can use the "rightsubnetwithin" parameter to specify a range.
+See
+<A HREF="http://www.strongsec.com/freeswan/install.htm#section_4.4">these
+<VAR>rightsubnetwithin</VAR> instructions</A>.
+</P>
+
+
+<h3><a name="virtID">Does FreeS/WAN support assigning a "virtual identity" to
+a remote system?</a></h3>
+
+<p>Some IPsec implementations allow you to make the source address on packets
+sent by a Road Warrior machine be something other than the address of its
+interface to the Internet. This is sometimes described as assigning a virtual
+identity to that machine.</p>
+
+<p>FreeS/WAN does not directly support this, but it can be done. See this <a
+href="#road.masq">FAQ question</a>.</p>
+
+<h3><a name="noDES.faq">Does FreeS/WAN support single DES encryption?</a></h3>
+
+<p><strong>No</strong>, single DES is not used either at the <a
+href="glossary.html#IKE">IKE</a> level for negotiating connections or at the
+<a href="glossary.html#IPsec">IPsec</a> level for actually building them.</p>
+
+<p>Single DES is <a href="politics.html#desnotsecure">insecure</a>. As we see
+it, it is more important to deliver real security than to comply with a
+standard which has been subverted into allowing use of inadequate methods.
+See this <a href="politics.html#weak">discussion</a>.</p>
+
+<p>If you want to interoperate with an IPsec implementation which offers only
+DES, see our <a href="interop.html#noDES">interoperation</a> document.</p>
+
+<h3><a name="AES.faq">Does FreeS/WAN support AES encryption?</a></h3>
+
+<p><a href="glossary.html#AES">AES</a> is a new US government <a
+href="glossary.html#block">block cipher</a> standard to replace the obsolete
+<a href="glossary.html#DES">DES</a>.</p>
+
+<p>At time of writing (March 2002), the FreeS/WAN distribution does not yet
+support AES but user-written <a href="web.html#patch">patches</a> are
+available to add it. Our kernel programmer is working on integrating those
+patches into the distribution, and there is active discussion of this on the
+design mailimg list.</p>
+
+<h3><a name="other.cipher">Does FreeS/WAN support other encryption
+algorithms?</a></h3>
+
+<p>Currently <a href="glossary.html#3DES">triple DES</a> is the only cipher
+supported. AES will almost certainly be added (see previous question), and it
+is likely that in the process we will also add the other two AES finalists
+with open licensing, Twofish and Serpent.</p>
+
+<p>We are extremely reluctant to add other ciphers. This would make both use
+and maintenance of FreeS/WAN more complex without providing any clear
+benefit. Complexity is emphatically not desirable in a security product.</p>
+
+<p>Various users have written patches to add other ciphers. We provide <a
+href="web.html#patch">links</a> to these.</p>
+
+<h2><a name="canI">Can I ...</a></h2>
+
+
+<h3><a name="policy.preconfig">Can I use policy groups along with
+explicitly configured connections?</a></h3>
+
+<p>Yes, you can, so long as you pay attention to the selection rule,
+which can be summarized "the most specific
+connection wins". We describe the rule in our
+<A HREF="policygroups.html#policy.group.notes">policy groups</A> document,
+and provide a more technical explanation in
+<A HREF="manpage.d/ipsec.conf.5.html">man ipsec.conf</A>.
+</p>
+
+<p>A good guideline: If you have a regular connection defined in
+<VAR>ipsec.conf</VAR>, ensure that a subset of that connection
+is not listed in a less restrictive policy group. Otherwise,
+FreeS/WAN will use the subset, with its more specific source/destination
+pair.</p>
+
+<p>Here's an example. Suppose you are the system administrator at 192.0.2.2.
+You have this connection in ipsec.conf:
+<VAR>ipsec.conf</VAR>:
+
+<PRE>conn net-to-net
+ left=192.0.2.2 # you are here
+ right=192.0.2.8
+ rightsubnet=192.0.2.96/27
+ ....
+</PRE>
+
+<p>If you then place a host or net within <VAR>rightsubnet</VAR>,
+(let's say 192.0.2.98) in <VAR>private-or-clear</VAR>, you may find
+that 192.0.2.2 at times communicates in the
+clear with 192.0.2.98. That's consistent with the rule, but may be
+contrary to your expectations.</p>
+
+<p>On the other hand, it's safe to put a larger subnet in a less
+restrictive policy group file. If <VAR>private-or-clear</VAR>
+contains 192.0.2.0/24, then the more specific <VAR>net-to-net</VAR>
+connection is used for any communication to 192.0.2.96/27. The
+more general policy applies only to communication with hosts or subnets in
+192.0.2.0/24 without a more specific policy or connection.</p>
+
+
+<h3><a name="policy.off">Can I turn off policy groups?</a></h3>
+
+<p>Yes. Use <A HREF="policygroups.html#disable_policygroups">these
+instructions</A>.</p>
+
+<!--
+<h3><a name="policy.otherinterface">Can I use policy groups
+ on an interface other than <VAR>%defaultroute</VAR>?</a></h3>
+
+<p>??<p>
+-->
+
+<h3><a name="reload">Can I reload connection info without restarting?</a></h3>
+
+<p>Yes, you can do this. Here are the details, in a mailing list message from
+Pluto programmer Hugh Redelmeier:</p>
+<pre>| How can I reload config's without restarting all of pluto and klips? I am using
+| FreeSWAN -&gt; PGPNet in a medium sized production environment, and would like to be
+| able to add new connections ( i am using include config/* ) without dropping current
+| SA's.
+|
+| Can this be done?
+|
+| If not, are there plans to add this kind of feature?
+
+ ipsec auto --add whatever
+This will look in the usual place (/etc/ipsec.conf) for a conn named
+whatever and add it.
+
+If you added new secrets, you need to do
+ ipsec auto --rereadsecrets
+before Pluto needs to know those secrets.
+
+| I have looked (perhaps not thoroughly enough tho) to see how to do this:
+
+There may be more bits to look for, depending on what you are trying
+to do.</pre>
+
+<p>Another useful command here is <var>ipsec auto --replace
+&lt;conn_name&gt;</var> which re-reads data for a named connection.</p>
+
+<h3><a name="masq.faq">Can I use several masqueraded subnets?</a></h3>
+
+<p>Yes. This is done all the time. See the discussion in our <a
+href="config.html#route_or_not">setup</a> document. The only restriction is
+that the subnets on the two ends must not overlap. See the next question.</p>
+
+<p>Here is a mailing list message on the topic. The user incorrectly thinks
+you need a 2.4 kernel for this -- actually various people have been doing it
+on 2.0 and 2.2 for quite some time -- but he has it right for 2.4.</p>
+<pre>Subject: Double NAT and freeswan working :)
+ Date: Sun, 11 Mar 2001
+ From: Paul Wouters &lt;paul@xtdnet.nl&gt;
+
+Just to share my pleasure, and make an entry for people who are searching
+the net on how to do this. Here's the very simple solution to have a double
+NAT'ed network working with freeswan. (Not sure if this is old news, but I'm
+not on the list (too much spam) and I didn't read this in any HOWTO/FAQ/doc
+on the freeswan site yet (Sandy, put it in! :)
+
+10.0.0.0/24 --- 10.0.0.1 a.b.c.d ---- a.b.c.e {internet} ----+
+ |
+10.0.1.0/24 --- 10.0.1.1 f.g.h.i ---- f.g.h.j {internet} ----+
+
+the goal is to have the first network do a VPN to the second one, yet also
+have NAT in place for connections not destinated for the other side of the
+NAT. Here the two Linux security gateways have one real IP number (cable
+modem, dialup, whatever.
+
+The problem with NAT is you don't want packets from 10.*.*.* to 10.*.*.*
+to be NAT'ed. While with Linux 2.2, you can't, with Linux 2.4 you can.
+
+(This has been tested and works for 2.4.2 with Freeswan snapshot2001mar8b)
+
+relevant parts of /etc/ipsec.conf:
+
+ left=f.g.h.i
+ leftsubnet=10.0.1.0/24
+ leftnexthop=f.g.h.j
+ leftfirewall=yes
+ leftid=@firewall.netone.nl
+ leftrsasigkey=0x0........
+ right=a.b.c.d
+ rightsubnet=10.0.0.0/24
+ rightnexthop=a.b.c.e
+ rightfirewall=yes
+ rightid=@firewall.nettwo.nl
+ rightrsasigkey=0x0......
+ # To authorize this connection, but not actually start it, at startup,
+ # uncomment this.
+ auto=add
+
+and now the real trick. Setup the NAT correctly on both sites:
+
+iptables -t nat -F
+iptables -t nat -A POSTROUTING -o eth0 -d \! 10.0.0.0/8 -j MASQUERADE
+
+This tells the NAT code to only do NAT for packets with destination other then
+10.* networks. note the backslash to mask the exclamation mark to protect it
+against the shell.
+
+Happy painting :)
+
+Paul</pre>
+
+<h3><a name="dup_route">Can I use subnets masqueraded to the same
+addresses?</a></h3>
+
+<p><strong>No.</strong> The notion that IP addresses are unique is one of the
+fundamental principles of the IP protocol. Messing with it is exceedingly
+perilous.</p>
+
+<p>Fairly often a situation comes up where a company has several branches,
+all using the same <a href="glossary.html#non-routable">non-routable
+addresses</a>, perhaps 192.168.0.0/24. This works fine as long as those nets
+are kept distinct. The <a href="glossary.html#masq">IP masquerading</a> on
+their firewalls ensures that packets reaching the Internet carry the firewall
+address, not the private address.</p>
+
+<p>This can break down when IPsec enters the picture. FreeS/WAN builds a
+tunnel that pokes through both masquerades and delivers packets from
+<var>leftsubnet</var> to <var>rightsubnet</var> and vice versa. For this to
+work, the two subnets <em>must</em> be distinct.</p>
+
+<p>There are several solutions to this problem.</p>
+
+<p>Usually, you <strong>re-number the subnets</strong>. Perhaps the Vancouver
+office becomes 192.168.101.0/24, Calgary 192.168.102.0/24 and so on.
+FreeS/WAN can happily handle this. With, for example
+<var>leftsubnet=192.168.101.0/24</var> and
+<var>rightsubnet=192.168.102.0/24</var> in a connection description, any
+machine in Calgary can talk to any machine in Vancouver. If you want to be
+more restrictive and use something like
+<var>leftsubnet=192.168.101.128/25</var> and
+<var>rightsubnet=192.168.102.240/28</var> so only certain machines on each
+end have access to the tunnel, that's fine too.</p>
+
+<p>You could also <strong>split the subnet</strong> into smaller ones, for
+example using <var>192.168.1.0/25</var> in Vancouver and
+<var>rightsubnet=192.168.0.128/25</var> in Calgary.</p>
+
+<p>Alternately, you can just <strong>give up routing</strong> directly to
+machines on the subnets. Omit the <var>leftsubnet</var> and
+<var>rightsubnet</var> parameters from your connection descriptions. Your
+IPsec tunnels will then run between the public interfaces of the two
+firewalls. Packets will be masqueraded both before they are put into tunnels
+and after they emerge. Your Vancouver client machines will see only one
+Calgary machine, the firewall.</p>
+
+<h3><a name="road.masq">Can I assign a road warrior an address on my net (a
+virtual identity)?</a></h3>
+
+<p>Often it would be convenient to be able to give a Road Warrior an IP
+address which appears to be on the local network. Some IPsec implementations
+have support for this, sometimes calling the feature "virtual identity".</p>
+
+<p>Currently (Sept 2002) FreeS/WAN does not support this, and we have
+no definite plans to add it. The difficulty is that is not yet a standard
+mechanism for it. There is an Internet Draft for a method of doing it using
+<a href="#DHCP">DHCP</a> which looks promising. FreeS/WAN may support that in
+a future release.</p>
+
+<p>In the meanwhile, you can do it yourself using the Linux iproute2(8)
+facilities. Details are in <a
+href="http://www.av8n.com/vpn/iproute2.htm">this
+paper</a>.</p>
+
+<p>Another method has also been discussed on the mailing list.:</p>
+<ul>
+ <li>You can use a variant of the <a
+ href="adv_config.html#extruded.config">extruded subnet</a> procedure.</li>
+ <li>You have to avoid having the road warrior's assigned address within the
+ range you actually use at home base. See previous question.</li>
+ <li>On the other hand, you want the roadwarrior's address to be within the
+ range that <em>seems</em> to be on your network.</li>
+</ul>
+
+<p>For example, you might have:</p>
+<dl>
+ <dt>leftsubnet=a.b.c.0/25</dt>
+ <dd>head office network</dd>
+ <dt>rightsubnet=a.b.c.129/32</dt>
+ <dd>extruded to a road warrior. Note that this is not in a.b.c.0/25</dd>
+ <dt>a.b.c.0/24</dt>
+ <dd>whole network, including both the above</dd>
+</dl>
+
+<p>You then set up routing so that the office machines use the IPsec gateway
+as their route to a.b.c.128/25. The leftsubnet parameter tells the road
+warriors to use tunnels to reach a.b.c.0/25, so you should have two-way
+communication. Depending or your network and applications, there may be some
+additional work to do on DNS or Windows configuration</p>
+
+<h3><a name="road.many">Can I support many road warriors with one
+gateway?</a></h3>
+
+<p>Yes. This is easily done, using</p>
+<dl>
+ <dt>either RSA authentication</dt>
+ <dd>standard in the FreeS/WAN distribution</dd>
+ <dt>or X.509 certificates</dt>
+ <dd>requires <a href="#PKIcert">Super FreeS/WAN or a patch</a>.</dd>
+</dl>
+
+<p>In either case, each Road Warrior must have a different key or
+certificate.</p>
+
+<p>It is also possible using pre-shared key authentication,
+though we don't recommend this; see the
+<a href="#road.PSK">next question</a> for details.</p>
+
+<p>If you expect to have more than a few dozen Road Warriors connecting
+simultaneously, you may need a fairly powerful gateway machine. See our
+document on <a href="performance.html">FreeS/WAN performance</a>.</p>
+
+<h3><a name="road.PSK">Can I have many road warriors using shared secret
+authentication?</a></h3>
+
+<p><STRONG>Yes, but avoid it if possible</STRONG>.</p>
+
+<p>You can have multiple Road Warriors using shared secret authentication
+<strong>only if they all use the same secret</strong>. You must also
+set:<p>
+
+<PRE> uniqueids=no </PRE>
+
+<p>in the connection definition.</p>
+
+
+<p>Why it's less secure:</p>
+<ul>
+ <li>If you have many users, it becomes almost certain the secret will
+ leak</li>
+ <li>The secret becomes quite valuable to an attacker</li>
+ <li>All users authenticate the same way, so the gateway cannot tell them
+ apart for logging or access control purposes</li>
+ <li>Changing the secret is difficult. You have to securely notify all
+ users.</li>
+ <li>If you find out the secret has been compromised, you can change it, but
+ then what? None of your users can connect without the new secret. How
+ will you notify them all, quickly and securely, without using the
+ VPN?</li>
+</ul>
+
+<p>This is a designed-in limitation of the <a
+href="glossary.html#IKE">IKE</a> key negotiation protocol, not a problem with
+our implementation.</p>
+
+<p><strong>We very strongly recommend that you avoid using shared secret
+authentication for multiple Road Warriors.</strong> Use RSA authentication
+instead.</p>
+
+<p>The longer story: When using shared secrets, the protocol requires
+that the responding
+gateway be able to determine which secret to use at a time when all it knows
+about the initiator is an IP address. This works fine if you know the
+initiator's address in advance and can use it to look up the appropiriate
+secret. However, it fails for Road Warriors since the gateway cannot know
+their IP addresses in advance.</p>
+
+<p>With RSA signatures (or certificates) the protocol is slightly different.
+The initiator provides an identifier early in the exchange and the responder
+can use that identifier to look up the correct key or certificate. See <a
+href="#road.many">above</a>.</p>
+
+<h3><a name="QoS">Can I use Quality of Service routing with
+FreeS/WAN?</a></h3>
+
+<p>From project technical lead Henry Spencer:</p>
+<pre>&gt; Do QoS add to FreeS/WAN?
+&gt; For example integrating DiffServ and FreeS/WAN?
+
+With a current version of FreeS/WAN, you will have to add hidetos=no to
+the config-setup section of your configuration file. By default, the TOS
+field of tunnel packets is zeroed; with hidetos=no, it is copied from the
+packet inside. (This is a modest security hole, which is why it is no
+longer the default.)
+
+DiffServ does not interact well with tunneling in general. Ways of
+improving this are being studied.</pre>
+
+<p>Copying the <a href="glossary.html#TOS">TOS</a> (type of service)
+information from the encapsulated packet to the outer header reveals the TOS
+information to an eavesdropper. This does not tell him much, but it might be
+of use in <a href="glossary.html#traffic">traffic analysis</a>. Since we do
+not have to give it to him, our default is not to.</p>
+
+<P>Even with the TOS hidden, you can still:</P>
+<UL>
+<LI>apply QOS rules to the tunneled (ESP) packets; for example, by
+giving ESP packets a certain priority.</LI>
+<LI>apply QOS rules to the packets as they enter or exit the tunnel
+via an IPsec virtual interface (eg. <VAR>ipsec0</VAR>).</LI>
+</UL>
+
+<p>See <a href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> for more on
+the <var>hidetos=</var> parameter.</p>
+
+
+<h3><a name="deadtunnel">Can I recognise dead tunnels and shut them
+down?</a></h3>
+
+<p>There is no general mechanism to do this is in the IPsec protocols.</p>
+
+<p>From time to time, there is discussion on the IETF Working Group <a
+href="mail.html#ietf">mailing list</a> of adding a "keep-alive" mechanism
+(which some say should be called "make-dead"), but it is a fairly complex
+problem and no consensus has been reached on whether or how it should be
+done.</p>
+
+<p>The protocol does have optional <a href="#ignore">delete-SA</a> messages
+which one side can send when it closes a connection in hopes this will cause
+the other side to do the same. FreeS/WAN does not currently support these. In
+any case, they would not solve the problem since:</p>
+<ul>
+ <li>a gateway that crashes or hangs would not send the messages</li>
+ <li>the sender is not required to send them</li>
+ <li>they are not authenticated, so any receiver that trusts them leaves
+ itself open to a <a href="glossary.html#DOS">denial of service</a>
+ attack</li>
+ <li>the receiver is not required to do anything about them</li>
+ <li>the receiver cannot acknowledge them; the protocol provides no
+ mechanism for that</li>
+ <li>since they are not acknowledged, the sender cannot rely on them</li>
+</ul>
+
+<p>However, connections do have limited lifetimes and you can control how
+many attempts your gateway makes to rekey before giving up. For example, you
+can set:</p>
+<pre>conn default
+ keyingtries=3
+ keylife=30m</pre>
+
+<p>With these settings old connections will be cleaned up. Within 30 minutes
+of the other end dying, rekeying will be attempted. If it succeeds, the new
+connection replaces the old one. If it fails, no new connection is created.
+Either way, the old connection is taken down when its lifetime expires.</p>
+
+<p>Here is a mailing list message on the topic from FreeS/WAN tech support
+person Claudia Schmeing:</p>
+<pre>You ask how to determine whether a tunnel is redundant:
+
+&gt; Can anybody explain the best way to determine this. Esp when a RW has
+&gt; disconnected? I thought 'ipsec auto --status' might be one way.
+
+If a tunnel goes down from one end, Linux FreeS/WAN on the
+other end has no way of knowing this until it attempts to rekey.
+Once it tries to rekey and fails, it will 'know' that the tunnel is
+down.
+
+Because it doesn't have a way of knowing the state until this point,
+it will also not be able to tell you the state via ipsec auto --status.
+
+&gt; However, comparing output from a working tunnel with that of one that
+&gt; was closed
+&gt; did not show clearly show tunnel status.
+
+If your tunnel is down but not 'unrouted' (see man ipsec_auto), you
+should not be able to ping the opposite side of the tunnel. You can
+use this as an indicator of tunnel status.
+
+On a related note, you may be interested to know that as of 1.7,
+redundant tunnels caused by RW disconnections are likely to be
+less of a pain. From doc/CHANGES:
+
+ There is a new configuration parameter, uniqueids, to control a new Pluto
+ option: when a new connection is negotiated with the same ID as an old
+ one, the old one is deleted immediately. This should help eliminate
+ dangling Road Warrior connections when the same Road Warrior reconnects.
+ It thus requires that IDs not be shared by hosts (a previously legal but
+ probably useless capability). NOTE WELL: the sample ipsec.conf now has
+ uniqueids=yes in its config-setup section.
+
+
+Cheers,
+
+Claudia</pre>
+
+<h3><a name="demanddial">Can I build IPsec tunnels over a demand-dialed
+link?</a></h3>
+
+<p>This is possible, but not easy. FreeS/WAN technical lead Henry Spencer
+wrote:</p>
+<pre>&gt; 5. If the ISDN link goes down in between and is reestablished, the SAs
+&gt; are still up but the eroute are deleted and the IPsec interface shows
+&gt; garbage (with ifconfig)
+&gt; 6. Only restarting IPsec will bring the VPN back online.
+
+This one is awkward to solve. If the real interface that the IPsec
+interface is mounted on goes down, it takes most of the IPsec machinery
+down with it, and a restart is the only good way to recover.
+
+The only really clean fix, right now, is to split the machines in two:
+
+1. A minimal machine serves as the network router, and only it is aware
+that the link goes up and down.
+
+2. The IPsec is done on a separate gateway machine, which thinks it has
+a permanent network connection, via the router.
+
+This is clumsy but it does work. Trying to do both functions within a
+single machine is tricky. There is a software package (diald) which will
+give the illusion of a permanent connection for demand-dialed modem
+connections; I don't know whether it's usable for ISDN, or whether it can
+be made to cooperate properly with FreeS/WAN.
+
+Doing a restart each time the interface comes up *does* work, although it
+is a bit painful. I did that with PPP when I was running on a modem link;
+it wasn't hard to arrange the PPP scripts to bring IPsec up and down at
+the right times. (I'd meant to investigate diald but never found time.)
+
+In principle you don't need to do a complete restart on reconnect, but you
+do have to rebuild some things, and we have no nice clean way of doing
+only the necessary parts.</pre>
+
+<p>In the same thread, one user commented:</p>
+<pre>Subject: Re: linux-ipsec: IPsec and Dial Up Connections
+ Date: Wed, 22 Nov 2000
+ From: Andy Bradford &lt;andyb@calderasystems.com&gt;
+
+On Wed, 22 Nov 2000 19:47:11 +0100, Philip Reetz wrote:
+
+&gt; Are there any ideas what might be the cause of the problem and any way
+&gt; to work around it.
+&gt; Any help is highly appreciated.
+
+On my laptop, when using ppp there is a ip-up script in /etc/ppp that
+will be executed each time that the ppp interface is brought up.
+Likewise there is an ip-down script that is called when it is taken
+down. You might consider custimzing those to stop and start FreeS/WAN
+with each connection. I believe that ISDN uses the same files, though
+I could be wrong---there should be something similar though.</pre>
+
+<h3><a name="GRE">Can I build GRE, L2TP or PPTP tunnels over IPsec?</a></h3>
+
+<p>Yes. Normally this is not necessary, but it is useful in a few special
+cases. For example, if you must route non-IP packets such as IPX, you
+will need to use a tunneling protocol that can route these packets. IPsec
+can be layered around it for extra security. Another example: you
+can provide failover protection for high availability (HA) environments by
+combining IPsec with other tools. Ken Bantoft describes one such setup in
+<A HREF="http://www.freeswan.ca/docs/HA">Using FreeS/WAN with Linux-HA, GRE,
+OSPF and BGP for enterprise grade VPN solutions</A>.</P>
+
+<p>GRE over IPsec is covered as part of
+<A HREF="http://www.freeswan.ca/docs/HA">that document</A>.
+<a href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/07/msg00209.html">
+Here are links</a> to other GRE resources.
+
+Jacco de Leuw has created
+<A HREF="http://www.jacco2.dds.nl/networking/">this page on L2TP over IPsec</A>
+with instructions for FreeS/WAN and several other brands of IPsec software.
+</P>
+
+<P>Please let us know of other useful links via the
+<A HREF="mail.html">mailing lists</A>.
+
+
+<h3><a name="NetBIOS">... use Network Neighborhood (Samba, NetBIOS) over IPsec?</a></h3>
+
+<p>Your local PC needs to know how to translate NetBIOS names to IP addresses.
+It may do this either via a local LMHOSTS file, or using a local or remote
+WINS server. The WINS server is preferable since it provides a centralized
+source of the information to the entire network. To use a WINS server over
+the <A HREF="glossary.html#VPN">VPN</A>
+(or any IP-based network), you must enable "NetBIOS over TCP".</p>
+
+<p><A HREF="http://www.samba.org">Samba</A> can emulate a WINS server
+on Linux.</p>
+
+<p>
+See also several discussions in our
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-September/thread.html">September
+2002 Users archives</A></p>
+
+
+<h2><a name="setup.faq">Life's little mysteries</a></h2>
+
+<p>FreeS/WAN is a fairly complex product. (Neither the networks it runs on
+nor the protocols it uses are simple, so it could hardly be otherwise.) It
+therefore sometimes exhibits behaviour which can be somewhat confusing, or
+has problems which are not easy to diagnose. This section tries to explain
+those problems.</p>
+
+<p>Setup and configuration of FreeS/WAN are covered in other documentation
+sections:</p>
+<ul>
+ <li><a href="quickstart.html">basic setup and configuration</a></li>
+ <li><a href="adv_config.html">advanced configuration</a></li>
+ <li><a href="trouble.html">Troubleshooting</a></li>
+</ul>
+
+<p>However, we also list some of the commonest problems here.</p>
+
+<h3><a name="cantping">I cannot ping ....</a></h3>
+
+<p>This question is dealt with in the advanced configuration section under
+the heading <a href="adv_config.html#multitunnel">multiple tunnels</a>.</p>
+
+<p>The standard subnet-to-subnet tunnel protects traffic <strong>only between
+the subnets</strong>. To test it, you must use pings that go from one subnet
+to the other.</p>
+
+<p>For example, suppose you have:</p>
+<pre> subnet a.b.c.0/24
+ |
+ eth1 = a.b.c.1
+ gate1
+ eth0 = 192.0.2.8
+ |
+
+ ~ internet ~
+
+ |
+ eth0 = 192.0.2.11
+ gate2
+ eth1 = x.y.z.1
+ |
+ subnet x.y.z.0/24</pre>
+
+<p>and the connection description:</p>
+<pre>conn abc-xyz
+ left=192.0.2.8
+ leftsubnet=a.b.c.0/24
+ right=192.0.2.11
+ rightsubnet=x.y.z.0/24</pre>
+
+<p>You can test this connection description only by sending a ping that will
+actually go through the tunnel. Assuming you have machines at addresses
+a.b.c.2 and x.y.z.2, pings you might consider trying are:</p>
+<dl>
+ <dt>ping from x.y.z.2 to a.b.c.2 or vice versa</dt>
+ <dd>Succeeds if tunnel is working. This is the <strong>only valid test of
+ the tunnel</strong>.</dd>
+ <dt>ping from gate2 to a.b.c.2 or vice versa</dt>
+ <dd><strong>Does not use tunnel</strong>. gate2 is not on protected
+ subnet.</dd>
+ <dt>ping from gate1 to x.y.z.2 or vice versa</dt>
+ <dd><strong>Does not use tunnel</strong>. gate1 is not on protected
+ subnet.</dd>
+ <dt>ping from gate1 to gate2 or vice versa</dt>
+ <dd><strong>Does not use tunnel</strong>. Neither gate is on a protected
+ subnet.</dd>
+</dl>
+
+<p>Only the first of these is a useful test of this tunnel. The others do not
+use the tunnel. Depending on other details of your setup and routing,
+they:</p>
+<ul>
+ <li>either fail, telling you nothing about the tunnel</li>
+ <li>or succeed, telling you nothing about the tunnel since these packets
+ use some other route</li>
+</ul>
+
+<p>In some cases, you may be able to get around this. For the example network
+above, you could use:</p>
+<pre> ping -I a.b.c.1 x.y.z.1</pre>
+
+<p>Both the adresses given are within protected subnets, so this should go
+through the tunnel.</p>
+
+<p>If required, you can build additional tunnels so that all the machines
+involved can talk to all the others. See <a
+href="adv_config.html#multitunnel">multiple tunnels</a> in the advanced
+configuration document for details.</p>
+
+<h3><a name="forever">It takes forever to ...</a></h3>
+
+<p>Users fairly often report various problems involving long delays,
+sometimes on tunnel setup and sometimes on operations done through the
+tunnel, occasionally on simple things like ping or more often on more complex
+operations like doing NFS or Samba through the tunnel.</p>
+
+<p>Almost always, these turn out to involve failure of a DNS lookup. The
+timeouts waiting for DNS are typically set long so that you won't time out
+when a query involves multiple lookups or long paths. Genuine failures
+therefore produce long delays before they are detected.</p>
+
+<p>A mailing list message from project technical lead Henry Spencer:</p>
+<pre>&gt; ... when i run /etc/rc.d/init.d/ipsec start, i get:
+&gt; ipsec_setup: Starting FreeS/WAN IPsec 1.5...
+&gt; and it just sits there, doesn't give back my bash prompt.
+
+Almost certainly, the problem is that you're using DNS names in your
+ipsec.conf, but DNS lookups are not working for some reason. You will
+get your prompt back... eventually. But the DNS timeouts are long.
+Doing something about this is on our list, but it is not easy.</pre>
+
+<p>In the meanwhile, we recommend that connection descriptions in <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> use numeric IP addresses
+rather than names which will require a DNS lookup.</p>
+
+<p>Names that do not require a lookup are fine. For example:</p>
+<ul>
+ <li>a road warrior might use the identity
+ <var>rightid=@lancelot.example.org</var></li>
+ <li>the gateway might use <var>leftid=@camelot.example.org</var></li>
+</ul>
+
+<p>These are fine. The @ sign prevents any DNS lookup. However, do not
+attempt to give the gateway address as <var>left=camelot.example.org</var>.
+That requires a lookup.</p>
+
+<p>A post from one user after solving a problem with long delays:</p>
+<pre>Subject: Final Answer to Delay!!!
+ Date: Mon, 19 Feb 2001
+ From: "Felippe Solutions" &lt;felippe@solutionstecnologia.com.br&gt;
+
+Sorry people, but seems like the Delay problem had nothing to do with
+freeswan.
+
+The problem was DNS as some people sad from the beginning, but not the way
+they thought it was happening. Samba, ssh, telnet and other apps try to
+reverse lookup addresses when you use IP numbers (Stupid that ahh).
+
+I could ping very fast because I always ping with "-n" option, but I don't
+know the option on the other apps to stop reverse addressing so I don't use
+it.</pre>
+
+<p>This post is fairly typical. These problems are often tricky and
+frustrating to diagnose, and most turn out to be DNS-related.</p>
+
+<p>One suggestion for diagnosis: test with both names and addresses if
+possible. For example, try all of:</p>
+<ul>
+ <li>ping <var>address</var></li>
+ <li>ping -n <var>address</var></li>
+ <li>ping <var>name</var></li>
+</ul>
+
+<p>If these behave differently, the problem must be DNS-related since the
+three commands do exactly the same thing except for DNS lookups.</p>
+
+<h3><a name="route">I send packets to the tunnel with route(8) but they
+vanish</a></h3>
+
+<p>IPsec connections are designed to carry only packets travelling between
+pre-defined connection endpoints. As project technical lead Henry Spencer put
+it:</p>
+
+<blockquote>
+ IPsec tunnels are not just virtual wires; they are virtual wires with
+ built-in access controls. Negotiation of an IPsec tunnel includes
+ negotiation of access rights for it, which don't include packets to/from
+ other IP addresses. (The protocols themselves are quite inflexible about
+ this, so there are limits to what we can do about it.)</blockquote>
+
+<p>For fairly obvious security reasons, and to comply with the IPsec RFCs, <a
+href="glossary.html#KLIPS">KLIPS</a> drops any packets it receives that are
+not allowed on the tunnels currently defined. So if you send it packets with
+<var>route(8)</var>, and suitable tunnels are not defined, the packets
+vanish. Whether this is reported in the logs depends on the setting of
+<var>klipsdebug</var> in your <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> file.</p>
+
+<p>To rescue vanishing packets, you must ensure that suitable tunnels for
+them exist, by editing the connection descriptions in <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a>. For example, supposing
+you have a simple setup:</p>
+<pre> leftsubnet -- leftgateway === internet === roadwarrior</pre>
+
+<p>If you want to give the roadwarrior access to some resource that is
+located behind the left gateway but is not in the currently defined left
+subnet, then the usual procedure is to define an additional tunnel for those
+packets by creating a new connection description.</p>
+
+<p>In some cases, it may be easier to alter an existing connection
+description, enlarging the definition of <var>leftsubnet</var>. For example,
+instead of two connection descriptions with 192.168.8.0/24 and 192.168.9.0/24
+as their <var>leftsubnet</var> parameters, you can use a single description
+with 192.168.8.0/23.</p>
+
+<p>If you have multiple endpoints on each side, you need to ensure that there
+is a route for each pair of endpoints. See this <a
+href="adv_config.html#multitunnel">example</a>.</p>
+
+<h3><a name="down_route">When a tunnel goes down, packets vanish</a></h3>
+
+<p>This is a special case of the vanishing packet problem described in the
+previous question. Whenever KLIPS sees packets for which it does not have a
+tunnel, it drops them.</p>
+
+<p>When a tunnel goes away, either because negotiations with the other
+gateway failed or because you gave an <var>ipsec auto --down</var> command,
+the route to its other end is left pointing into KLIPS, and KLIPS will drop
+packets it has no tunnel for.</p>
+
+<p>This is a documented design decision, not a bug. FreeS/WAN must not
+automatically adjust things to send packets via another route. The other
+route might be insecure.</p>
+
+<p>Of course, re-routing may be necessary in many cases. In those cases, you
+have to do it manually or via scripts. We provide the <var>ipsec auto
+--unroute</var> command for these cases.</p>
+
+<p>From <a href="manpage.d/ipsec_auto.8.html">ipsec_auto(8)</a>:</p>
+
+<blockquote>
+ Normally, pluto establishes a route to the destination specified for a
+ connection as part of the --up operation. However, the route and only
+ the route can be established with the --route operation. Until and unless
+ an actual connection is established, this discards any packets sent
+ there, which may be preferable to having them sent elsewhere based on a
+ more general route (e.g., a default route).</blockquote>
+
+<blockquote>
+ Normally, pluto's route to a destination remains in place when a --down
+ operation is used to take the connection down (or if connection setup, or
+ later automatic rekeying, fails). This permits establishing a new
+ connection (perhaps using a different specification; the route is altered
+ as necessary) without having a ``window'' in which packets might go
+ elsewhere based on a more general route. Such a route can be removed
+ using the --unroute operation (and is implicitly removed by
+--delete).</blockquote>
+
+<p>See also this mailing list <a
+href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00523.html">message</a>.</p>
+
+<h3><a name="firewall_ate">The firewall ate my packets!</a></h3>
+
+<p>If firewalls filter out:</p>
+<ul>
+ <li>either the UDP port 500 packets used in IKE negotiations</li>
+ <li>or the ESP and AH (protocols 50 and 51) packets used to implement the
+ IPsec tunnel</li>
+</ul>
+
+<p>then IPsec cannot work. The first thing to check if packets seem to be
+vanishing is the firewall rules on the two gateway machines and any other
+machines along the path that you have access to.</p>
+
+<p>For details, see our document on <a href="firewall.html">firewalls</a>.</p>
+
+<p>Some advice from technical lead Henry Spencer on diagnosing such
+problems:</p>
+<pre>&gt; &gt; Packets vanishing between the hardware interface and the ipsecN interface
+&gt; &gt; is usually the result of firewalls not being configured to let them in...
+&gt;
+&gt; Thanks for the suggestion. If only it were that simple! My ipchains startup
+&gt; script does take care of that, but just in case I manually inserted rules
+&gt; accepting everything from london on dublin. No difference.
+
+The other thing to check is whether the "RX packets dropped" count on the
+ipsecN interface (run "ifconfig ipsecN", for N=1 or whatever, to see the
+counts) is rising. If so, then there's some sort of configuration mismatch
+between the two ends, and IPsec itself is rejecting them. If none of the
+ipsecN counts is rising, then the packets are never reaching the IPsec
+machinery, and the problem is almost certainly in firewalls etc.</pre>
+
+<h3><a name="dropconn">Dropped connections</a></h3>
+
+<p>Networks being what they are, IPsec connections can be broken for any
+number of reasons, ranging from hardware failures to various software
+problems such as the path MTU problems discussed <a
+href="#pmtu.broken">elsewhere in the FAQ</a>. Fortunately, various diagnostic
+tools exist that help you sort out many of the possible problems.</p>
+
+<p>There is one situation, however, where FreeS/WAN (using default settings)
+may destroy a connection for no readily apparent reason. This occurs when
+things are <strong>misconfigured</strong> so that <strong>two
+tunnels</strong> from the same gateway expect <strong>the same subnet on the
+far end</strong>.</p>
+
+<p>In this situation, the first tunnel comes up fine and works until the
+second is established. At that point, because of the way we track connections
+internally, the first tunnel ceases to exist as far as this gateway is
+concerned. Of course the far end does not know that, and a storm of error
+messages appears on both systems as it tries to use the tunnel.</p>
+
+<p>If the far end gives up, goes back to square one and negotiates a new
+tunnel, then that wipes out the second tunnel and ...</p>
+
+<p>The solution is simple. <strong>Do not build multiple conn descriptions
+with the same remote subnet</strong>.</p>
+
+<p>This is actually intended to be a feature, rather than a bug. Consider the
+situation where a single remote system goes down, then comes back up and
+reconnects to the gateway. It is useful to have the gateway tear down the old
+tunnel and recover resources when the reconnection is made. It recognises
+that situation by checking the remote subnet for each tunnel it builds and
+discarding duplicates. This works fine as long as you don't configure
+multiple tunnels with the same remote subnet.</p>
+
+<p>If this behaviour is inconvenient for you, you can disable it by setting
+<var>uniqueids=no</var> in <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a>.</p>
+
+
+<h3><a name="defaultroutegone">Disappearing %defaultroute</a></h3>
+
+<p>When an underlying connection (eg. ppp) goes down, FreeS/WAN will not
+recover properly without a little help. Here are the symptoms that FreeS/WAN
+user Michael Carmody noticed:
+<pre>
+&gt; After about 24 hours the freeswan connection takes over the default route.
+&gt;
+&gt; i.e instead of deafult gateway pointing to the router via eth0, it becomes a
+&gt; pointer to the router via ipsec0.
+
+&gt; All internet access is then lost as all replies (and not just the link I
+&gt; wanted) are routed out ipsec0 and the router doesn't respond to the ipsec
+&gt; traffic.
+</pre>
+
+<p>If you're using a
+FreeS/WAN 2.x/KLIPS system, simply re-attach the IPsec virtual
+interface with <em>ipsec tnconfig</em> command such as:</p>
+<pre> ipsec tnconfig --attach --virtual ipsec0 --physical ppp0</pre>
+<p>In your command, name the physical and virtual interfaces as they
+appear paired on your system during regular uptime. For a system with several
+physical/virtual interface pairs on flaky links, you'll need more than
+one such command.
+If you're using FreeS/WAN 1.x, you must restart FreeS/WAN, which is more time
+consuming.</p>
+
+<p>
+<A href="http://lists.freeswan.org/pipermail/design/2002-July/003070.html">Here</A>
+is a script which can help to automate the process of FreeS/WAN restart at
+need.
+It could easily be adapted to use tnconfig instead.</p>
+
+<h3><a name="tcpdump.faq">TCPdump on the gateway shows strange things</a></h3>
+
+As another user pointed out, keeping the connect
+<p>Attempting to look at IPsec packets by running monitoring tools on the
+IPsec gateway machine can produce silly results. That machine is mangling the
+packets for IPsec, and possibly for firewall or NAT purposes as well. If the
+internals of the machine's IP stack are not what the monitoring tool expects,
+then the tool can misinterpret them and produce nonsense output.</p>
+
+<p>See our <a href="testing.html#tcpdump.test">testing</a> document for more
+detail.</p>
+
+<h3><a name="no_trace">Traceroute does not show anything between the
+gateways</a></h3>
+
+<p>As far as traceroute can see, the two gateways are one hop apart; the data
+packet goes directly from one to the other through the tunnel. Of course the
+outer packets that implement the tunnel pass through whatever lies between
+the gateways, but those packets are built and dismantled by the gateways.
+Traceroute does not see them and cannot report anything about their path.</p>
+
+<p>Here is a mailing list message with more detail.</p>
+<pre>Date: Mon, 14 May 2001
+To: linux-ipsec@freeswan.org
+From: "John S. Denker" &lt;jsd@research.att.com&lt;
+Subject: Re: traceroute: one virtual hop
+
+At 02:20 PM 5/14/01 -0400, Claudia Schmeing wrote:
+&gt;
+&gt;&gt; &gt; A bonus question: traceroute in subnet to subnet enviroment looks like:
+&gt;&gt; &gt;
+&gt;&gt; &gt; traceroute to andris.dmz (172.20.24.10), 30 hops max, 38 byte packets
+&gt;&gt; &gt; 1 drama (172.20.1.1) 0.716 ms 0.942 ms 0.434 ms
+&gt;&gt; &gt; 2 * * *
+&gt;&gt; &gt; 3 andris.dmz (172.20.24.10) 73.576 ms 78.858 ms 79.434 ms
+&gt;&gt; &gt;
+&gt;&gt; &gt; Why aren't there the other hosts which take part in the delivery during
+&gt; * * * ?
+&gt;
+&gt;If there is an ipsec tunnel between GateA and Gate B, this tunnel forms a
+&gt;'virtual wire'. When it is tunneled, the original packet becomes an inner
+&gt;packet, and new ESP and/or AH headers are added to create an outer packet
+&gt;around it. You can see an example of how this is done for AH at
+&gt;doc/ipsec.html#AH . For ESP it is similar.
+&gt;
+&gt;Think about the packet's path from the inner packet's perspective.
+&gt;It leaves the subnet, goes into the tunnel, and re-emerges in the second
+&gt;subnet. This perspective is also the only one available to the
+&gt;'traceroute' command when the IPSec tunnel is up.
+
+Claudia got this exactly right. Let me just expand on a couple of points:
+
+*) GateB is exactly one (virtual) hop away from GateA. This is how it
+would be if there were a physically private wire from A to B. The
+virtually private connection should work the same, and it does.
+
+*) While the information is in transit from GateA to GateB, the hop count
+of the outer header (the "envelope") is being decremented. The hop count
+of the inner header (the "contents" of the envelope) is not decremented and
+should not be decremented. The hop count of the outer header is not
+derived from and should not be derived from the hop count of the inner header.
+
+Indeed, even if the packets did time out in transit along the tunnel, there
+would be no way for traceroute to find out what happened. Just as
+information cannot leak _out_ of the tunnel to the outside, information
+cannot leak _into_ the tunnel from outside, and this includes ICMP messages
+from routers along the path.
+
+There are some cases where one might wish for information about what is
+happening at the IP layer (below the tunnel layer) -- but the protocol
+makes no provision for this. This raises all sorts of conceptual issues.
+AFAIK nobody has ever cared enough to really figure out what _should_
+happen, let alone implement it and standardize it.
+
+*) I consider the "* * *" to be a slight bug. One might wish for it to be
+replaced by "GateB GateB GateB". It has to do with treating host-to-subnet
+traffic different from subnet-to-subnet traffic (and other gory details).
+I fervently hope KLIPS2 will make this problem go away.
+
+*) If you want to ask questions about the link from GateA to GateB at the
+IP level (below the tunnel level), you have to ssh to GateA and launch a
+traceroute from there.</pre>
+
+<h2><a name="man4debug">Testing in stages</a></h2>
+
+<p>It is often useful in debugging to test things one at a time:</p>
+<ul>
+ <li>disable IPsec entirely, for example by turning it off with
+ chkconfig(8), and make sure routing works</li>
+ <li>Once that works, try a manually keyed connection. This does not require
+ key negotiation between Pluto and the key daemon on the other end.</li>
+ <li>Once that works, try automatically keyed connections</li>
+ <li>Once IPsec works, add packet compression</li>
+ <li>Once everything seems to work, try stress tests with large transfers,
+ many connections, frequent re-keying, ...</li>
+</ul>
+
+<p>FreeS/WAN releases are tested for all of these, so you can be reasonably
+certain they <em>can</em> do them all. Of course, that does not mean they
+<em>will</em> on the first try, especially if you have some unusual
+configuration.</p>
+
+<p>The rest of this section gives information on diagnosing the problem when
+each of the above steps fails.</p>
+
+<h3><a name="nomanual">Manually keyed connections don't work</a></h3>
+
+<p>Suspect one of:</p>
+<ul>
+ <li>mis-configuration of IPsec system in the /etc/ipsec.conf file<br>
+ common errors are incorrect interface or next hop information</li>
+ <li>mis-configuration of manual connection in the /etc/ipsec.conf file</li>
+ <li>routing problems causing IPsec packets to be lost</li>
+ <li>bugs in KLIPS</li>
+ <li>mismatch between the transforms we support and those another IPsec
+ implementation offers.</li>
+</ul>
+
+<h3><a name="spi_error">One manual connection works, but second one
+fails</a></h3>
+
+<p>This is a fairly common problem when attempting to configure multiple
+manually keyed connections from a single gateway.</p>
+
+<p>Each connection must be identified by a unique <a
+href="glossary.html#SPI">SPI</a> value. For automatic connections, these
+values are assigned automatically. For manual connections, you must set them
+with <var>spi=</var> statements in <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a>.</p>
+
+<p>Each manual connection must have a unique SPI value in the range 0x100 to
+0x999. Two or more with the same value will fail. For details, see our doc
+section <a href="adv_config.html#prodman">Using manual keying in
+production</a> and the man page <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a>.</p>
+
+<h3><a name="man_no_auto">Manual connections work, but automatic keying
+doesn't</a></h3>
+
+<p>The most common reason for this behaviour is a firewall dropping the UDP
+port 500 packets used in key negotiation.</p>
+
+<p>Other possibilities:</p>
+<ul>
+ <li>mis-configuration of auto connection in the /etc/ipsec.conf file.
+ <p>One common configuration error is forgetting that you need
+ <var>auto=add</var> to load the connection description on the receiving
+ end so it recognises the connection when the other end asks for it.</p>
+ </li>
+ <li>error in shared secret in /etc/ipsec.secrets</li>
+ <li>one gateway lacks a route to the other so Pluto's UDP packets are
+ lost</li>
+ <li>bugs in Pluto</li>
+ <li>incompatibilities between Pluto's <a href="glossary.html#IKE">IKE</a>
+ implementation and the IKE at the other end of the tunnel.
+ <p>Some possibile problems are discussed in out <a
+ href="interop.html#interop.problem">interoperation</a> document.</p>
+ </li>
+</ul>
+
+<h3><a name="nocomp">IPsec works, but connections using compression
+fail</a></h3>
+
+<p>When we first added compression, we saw some problems:</p>
+<ul>
+ <li>compatibility issues with other implementations. We followed the RFCs
+ and omitted some extra material that many compression libraries add by
+ default. Some other implementations left the extras in</li>
+ <li>bugs in assembler compression routines on non-Intel CPUs. The
+ workaround is to use C code instead of possibly problematic
+ assembler.</li>
+</ul>
+
+<p>We have not seen either problem in some time (at least six months as I
+write in March 2002), but if you have some unusual configuration then you may
+see them.</p>
+
+<h3><a name="pmtu.broken">Small packets work, but large transfers
+fail</a></h3>
+
+<p>If tests with ping(1) and a small packet size succeed, but tests or
+transfers with larger packet sizes fail, suspect problems with packet
+fragmentation and perhaps <a href="glossary.html#pathMTU">path MTU
+discovery</a>.</p>
+
+<p>Our <a href="trouble.html#bigpacket">troubleshooting document</a> covers
+these problems. Information on the underlying mechanism is in our <a
+href="background.html#MTU.trouble">background</a> document.</p>
+
+<h3><a name="subsub">Subnet-to-subnet works, but tests from the gateways
+don't</a></h3>
+
+<p>This is described under <a href="#cantping">I cannot ping...</a> above.</p>
+
+<h2><a name="compile.faq">Compilation problems</a></h2>
+
+<h3><a name="gmp.h_missing">gmp.h: No such file or directory</a></h3>
+
+<p>Pluto needs the GMP (<strong>G</strong>NU</p>
+
+<p><strong>M</strong>ulti-<strong>P</strong>recision) library for the large
+integer calculations it uses in <a href="glossary.html#public">public key</a>
+cryptography. This error message indicates a failure to find the library. You
+must install it before Pluto will compile.</p>
+
+<p>The GMP library is included in most Linux distributions. Typically, there
+are two RPMs, libgmp and libgmp-devel, You need to <em>install both</em>,
+either from your distribution CDs or from your vendor's web site.</p>
+
+<p>On Debian, a mailing list message reports that the command to give is
+<var>apt-get install gmp2</var>.</p>
+
+<p>For more information and the latest version, see the <a
+href="http://www.swox.com/gmp/">GMP home page</a>.</p>
+
+<h3><a name="noVM">... virtual memory exhausted</a></h3>
+
+<p>We have had several reports of this message appearing, all on SPARC Linux.
+Here is a mailing message on a solution:</p>
+<pre>&gt; ipsec_sha1.c: In function `SHA1Transform':
+&gt; ipsec_sha1.c:95: virtual memory exhausted
+
+I'm seeing exactly the same problem on an Ultra with 256MB ram and 500
+MB swap. Except I am compiling version 1.5 and its Red Hat 6.2.
+
+I can get around this by using -O instead of -O2 for the optimization
+level. So it is probably a bug in the optimizer on the sparc complier.
+I'll try and chase this down on the sparc lists.</pre>
+
+<h2><a name="error">Interpreting error messages</a></h2>
+
+<h3><a name="route-client">route-client (or host) exited with status
+7</a></h3>
+
+<p>Here is a discussion of this error from FreeS/WAN "listress" (mailing list
+tech support person) Claudia Schmeing. The "FAQ on the network unreachable
+error" which she refers to is the next question below.</p>
+<pre>&gt; I reached the point where the two boxes (both on dial-up connections, but
+&gt; treated as static IPs by getting the IP and editing ipsec.conf after the
+&gt; connection is established) to the point where they exchange some info, but I
+&gt; get an error like "route-client command exited with status 7 \n internal
+&gt; error".
+&gt; Where can I find a description of this error?
+
+In general, if the FAQ doesn't cover it, you can search the mailing list
+archives - I like to use
+http://www.sandelman.ottawa.on.ca/linux-ipsec/
+but you can see doc/mail.html for different archive formats.
+
+
+Your error comes from the _updown script, which performs some
+routing and firewall functions to help Linux FreeS/WAN. More info
+is available at doc/firewall.html and man ipsec.conf. Its routing
+is integral to the health of Linux FreeS/WAN; it also provides facility
+to insert custom firewall rules to be executed when you create or destroy
+a connection.
+
+Yours is, of course, a routing error. You can be fairly sure the routing
+machinery is saying "network is unreachable". There's a FAQ on the
+"network is unreachable" error, but more information is available now; read on.
+
+If your _updown script is recent (for example if it shipped with
+Linux FreeS/WAN 1.91), you will see another debugging line in your logs
+that looks something like this:
+
+&gt; output: /usr/local/lib/ipsec/_updown: `route add -net 128.174.253.83
+&gt; netmask 255.255.255.255 dev ipsec0 gw 66.92.93.161' failed
+
+This is, of course, the system route command that exited with status 7,
+(ie. failed). Man route for details. Seeing the command typed out yields
+more information. If your _updown script is older, you may wish to update
+it to show the command explicitly.
+
+Three parameters fed to the route command: net, netmask and gw [gateway]
+are derived from things you've put in ipsec.conf.
+
+Net and netmask are derived from the peer's IP and mask. In more detail:
+
+You may see a routing error when routing to a client (ie. subnet), or
+to a host (IPSec gateway or freestanding host; a box that does IPSec for
+itself). In _updown, the "route-client" section is responsible to set up
+the route for IPSec'd (usually, read 'tunneled') packets headed to a
+peer subnet. Similarly, route-host routes IPSec'd packets to a peer host
+or IPSec gateway.
+
+When routing to a 'client', net and netmask are ipsec.conf's left- or
+rightsubnet (whichever is not local). Similarly, when routing to a
+'host' the net is left or right. Host netmask is always /32, indicating a
+single machine.
+
+Gw is nexthop's value. Again, the value in question is left- or rightnexthop,
+whichever is local. Where left/right or left-/rightnexthop has the special
+value %defaultroute (described in man ipsec.conf), gw will automagically get
+the value of the next hop on the default route.
+
+Q: "What's a nexthop and why do I need one?"
+
+A: 'nexthop' is a routing kluge; its value is the next hop away
+ from the machine that's doing IPSec, and toward your IPSec peer.
+ You need it to get the processed packets out of the local system and
+ onto the wire. While we often route other packets through the machine
+ that's now doing IPSec, and are done with it, this does not suffice here.
+ After packets are processed with IPSec, this machine needs to know where
+ they go next. Of course using the 'IPSec gateway' as their routing gateway
+ would cause an infinite loop! [To visualize this, see the packet flow
+ diagram at doc/firewall.html.] To avoid this, we route packets through
+ the next hop down their projected path.
+
+Now that you know the background, consider:
+1. Did you test routing between the gateways in the absence of Linux
+ FreeS/WAN, as recommended? You need to ensure the two machines that
+ will be running Linux FreeS/WAN can route to one another before trying to
+ make a secure connection.
+2. Is there anything obviously wrong with the sense of your route command?
+
+Normally, this problem is caused by an incorrect local nexthop parameter.
+Check out the use of %defaultroute, described in man ipsec.conf. This is
+a simple way to set nexthop for most people. To figure nexthop out by hand,
+traceroute in-the-clear to your IPSec peer. Nexthop is the traceroute's
+first hop after your IPSec gateway.</pre>
+
+<h3><a name="unreachable">SIOCADDRT:Network is unreachable</a></h3>
+
+<p>This message is not from FreeS/WAN, but from the Linux IP stack itself.
+That stack is seeing packets it has no route for, either because your routing
+was broken before FreeS/WAN started or because FreeS/WAN's changes broke
+it.</p>
+
+<p>Here is a message from Claudia suggesting ways to diagnose and fix such
+problems:</p>
+<pre>You write,
+&gt; I have correctly installed freeswan-1.8 on RH7.0 kernel 2.2.17, but when
+&gt; I setup a VPN connection with the other machine(RH5.2 Kernel 2.0.36
+&gt; freeswan-1.0, it works well.) it told me that
+&gt; "SIOCADDRT:Network is unreachable"! But the network connection is no
+&gt; problem.
+
+Often this error is the result of a misconfiguration.
+
+Be sure that you can route successfully in the absence of Linux
+FreeS/WAN. (You say this is no problem, so proceed to the next step.)
+
+Use a custom copy of the default updownscript. Do not change the route
+commands, but add a diagnostic message revealing the exact text of the
+route command. Is there a problem with the sense of the route command
+that you can see? If so, then re-examine those ipsec.conf settings
+that are being sent to the route command.
+
+You may wish to use the ipsec auto --route and --unroute commands to
+troubleshoot the problem. See man ipsec_auto for details.</pre>
+
+<p>Since the above message was written, we have modified the updown script to
+provide a better diagnostic for this problem. Check
+<var>/var/log/messages</var>.</p>
+
+<p>See also the FAQ question <a href="#route-client">route-client (or host)
+exited with status 7</a>.</p>
+
+<h3><a name="modprobe">ipsec_setup: modprobe: Can't locate module
+ipsec</a></h3>
+
+<h3><a name="noKLIPS">ipsec_setup: Fatal error, kernel appears to lack
+KLIPS</a></h3>
+
+<p>These messages indicate an installation failure. The kernel you are
+running does not contain the <a href="glossary.html#KLIPS">KLIPS (kernel
+IPsec)</a> code.</p>
+
+<p>Note that the "modprobe: Can't locate module ipsec" message appears even
+if you are not using modules. If there is no KLIPS in your kernel, FreeS/WAN
+tries to load it as a module. If that fails, you get this message.</p>
+
+<p>Commands you can quickly try are:</p>
+<dl>
+ <dt><var>uname -a</var></dt>
+ <dd>to get details, including compilation date and time, of the currently
+ running kernel</dd>
+ <dt><var>ls /</var></dt>
+ <dt><var>ls /boot</var></dt>
+ <dd>to ensure a new kernel is where it should be. If kernel compilation
+ puts it in <var>/</var> but <var>lilo</var> wants it in
+ <var>/boot</var>, then you should uncomment the
+ <var>INSTALL_PATH=/boot</var> line in the kernel
+ <var>Makefile</var>.</dd>
+ <dt><var>more /etc/lilo.conf</var></dt>
+ <dd>to see that <var>lilo</var> has correct information</dd>
+ <dt><var>lilo</var></dt>
+ <dd>to ensure that information in <var>/etc/lilo.conf</var> has been
+ transferred to the boot sector</dd>
+</dl>
+
+<p>If those don't find the problem, you have to go back and check through the
+<a href="install.html">install</a> procedure to see what was missed.</p>
+
+<p>Here is one of Claudia's messages on the topic:</p>
+<pre>&gt; I tried to install freeswan 1.8 on my mandrake 7.2 test box. ...
+
+&gt; It does show version and some output for whack.
+
+Yes, because the Pluto (daemon) part of ipsec is installed correctly, but
+as we see below the kernel portion is not.
+
+&gt; However, I get the following from /var/log/messages:
+&gt;
+&gt; Mar 11 22:11:55 pavillion ipsec_setup: Starting FreeS/WAN IPsec 1.8...
+&gt; Mar 11 22:12:02 pavillion ipsec_setup: modprobe: Can't locate module ipsec
+&gt; Mar 11 22:12:02 pavillion ipsec_setup: Fatal error, kernel appears to lack
+&gt; KLIPS.
+
+This is your problem. You have not successfully installed a kernel with
+IPSec machinery in it.
+
+Did you build Linux FreeS/WAN as a module? If so, you need to ensure that
+your new module has been installed in the directory where your kernel
+loader normally finds your modules. If not, you need to ensure
+that the new IPSec-enabled kernel is being loaded correctly.
+
+See also doc/install.html, and INSTALL in the distro.</pre>
+
+<h3><a name="noDNS">ipsec_setup: ... failure to fetch key for ... from
+DNS</a></h3>
+
+<p>Quoting Henry:</p>
+<pre>Note that by default, FreeS/WAN is now set up to
+ (a) authenticate with RSA keys, and
+ (b) fetch the public key of the far end from DNS.
+Explicit attention to ipsec.conf will be needed if you want
+to do something different.</pre>
+
+<p>and Claudia, responding to the same user:</p>
+<pre>You write,
+
+&gt; My current setup in ipsec.conf is leftrsasigkey=%dns I have
+&gt; commented this and authby=rsasig out. I am able to get ipsec running,
+&gt; but what I find is that the documentation only specifies for %dns are
+&gt; there any other values that can be placed in this variable other than
+&gt; %dns and the key? I am also assuming that this is where I would place
+&gt; my public key for the left and right side as well is this correct?
+
+Valid values for authby= are rsasig and secret, which entail authentication
+by RSA signature or by shared secret, respectively. Because you have
+commented authby=rsasig out, you are using the default value of authby=secret.
+
+When using RSA signatures, there are two ways to get the public key for the
+IPSec peer: either copy it directly into *rsasigkey= in ipsec.conf, or
+fetch it from dns. The magic value %dns for *rsasigkey parameters says to
+try to fetch the peer's key from dns.
+
+For any parameters, you may find their significance and special values in
+man ipsec.conf. If you are setting up keys or secrets, be sure also to
+reference man ipsec.secrets.</pre>
+
+<h3><a name="dup_address">ipsec_setup: ... interfaces ... and ... share
+address ...</a></h3>
+
+<p>This is a fatal error. FreeS/WAN cannot cope with two or more interfaces
+using the same IP address. You must re-configure to avoid this.</p>
+
+<p>A mailing list message on the topic from Pluto developer Hugh
+Redelmeier:</p>
+<pre>| I'm trying to get freeswan working between two machine where one has a ppp
+| interface.
+| I've already suceeded with two machines with ethernet ports but the ppp
+| interface is causing me problems.
+| basically when I run ipsec start i get
+| ipsec_setup: Starting FreeS/WAN IPsec 1.7...
+| ipsec_setup: 003 IP interfaces ppp1 and ppp0 share address 192.168.0.10!
+| ipsec_setup: 003 IP interfaces ppp1 and ppp2 share address 192.168.0.10!
+| ipsec_setup: 003 IP interfaces ppp0 and ppp2 share address 192.168.0.10!
+| ipsec_setup: 003 no public interfaces found
+|
+| followed by lots of cannot work out interface for connection messages
+|
+| now I can specify the interface in ipsec.conf to be ppp0 , but this does
+| not affect the above behaviour. A quick look in server.c indicates that the
+| interfaces value is not used but some sort of raw detect happens.
+|
+| I guess I could prevent the formation of the extra ppp interfaces or
+| allocate them different ip but I'd rather not. if at all possible. Any
+| suggestions please.
+
+Pluto won't touch an interface that shares an IP address with another.
+This will eventually change, but it probably won't happen soon.
+
+For now, you will have to give the ppp1 and ppp2 different addresses.</pre>
+
+<h3><a name="kflags">ipsec_setup: Cannot adjust kernel flags</a></h3>
+
+<p>A mailing list message form technical lead Henry Spencer:</p>
+<pre>&gt; When FreeS/WAN IPsec 1.7 is starting on my 2.0.38 Linux kernel the following
+&gt; error message is generated:
+&gt; ipsec_setup: Cannot adjust kernel flags, no /proc/sys/net/ipsec directory!
+&gt; What is supposed to create this directory and how can I fix this problem?
+
+I think that directory is a 2.2ism, although I'm not certain (I don't have
+a 2.0.xx system handy any more for testing). Without it, some of the
+ipsec.conf config-setup flags won't work, but otherwise things should
+function. </pre>
+
+<p>You also need to enable the <var>/proc</var> filesystem in your kernel
+configuration for these operations to work.</p>
+
+<h3><a name="message_num">Message numbers (MI3, QR1, et cetera) in Pluto
+messages</a></h3>
+
+<p>Pluto messages often indicate where Pluto is in the IKE protocols. The
+letters indicate <strong>M</strong>ain mode or <strong>Q</strong>uick mode
+and <strong>I</strong>nitiator or <strong>R</strong>esponder. The numerals
+are message sequence numbers. For more detail, see our <a
+href="ipsec.html#sequence">IPsec section</a>.</p>
+
+<h3><a name="conn_name">Connection names in Pluto error messages</a></h3>
+
+<p>From Pluto programmer Hugh Redelmeier:</p>
+<pre>| Jan 17 16:21:10 remus Pluto[13631]: "jumble" #1: responding to Main Mode from Road Warrior 130.205.82.46
+| Jan 17 16:21:11 remus Pluto[13631]: "jumble" #1: no suitable connection for peer @banshee.wittsend.com
+|
+| The connection "jumble" has nothing to do with the incoming
+| connection requests, which were meant for the connection "banshee".
+
+You are right. The message tells you which Connection Pluto is
+currently using, which need not be the right one. It need not be the
+right one now for the negotiation to eventually succeed! This is
+described in ipsec_pluto(8) in the section "Road Warrior Support".
+
+There are two times when Pluto will consider switching Connections for
+a state object. Both are in response to receiving ID payloads (one in
+Phase 1 / Main Mode and one in Phase 2 / Quick Mode). The second is
+not unique to Road Warriors. In fact, neither is the first any more
+(two connections for the same pair of hosts could differ in Phase 1 ID
+payload; probably nobody else has tried this).</pre>
+
+<h3><a name="cantorient">Pluto: ... can't orient connection</a></h3>
+
+<p>Older versions of FreeS/WAN used this message. The same error now gives
+the "we have no ipsecN ..." error described just below.</p>
+
+<h3><a name="no.interface">... we have no ipsecN interface for either end of
+this connection</a></h3>
+
+<p>Your tunnel has no IP address which matches the IP
+address of any of the available IPsec interfaces. Either you've
+misconfigured the connection, or you need to define an appropriate
+IPsec interface connection. <VAR>interfaces=%defaultroute</VAR> works
+in many cases.</p>
+
+<p>A longer story: Pluto needs to know whether it is running on
+the machine which the
+connection description calls <var>left</var> or on <var>right</var>. It
+figures that out by:</p>
+<ul>
+ <li>looking at the interfaces given in <var>interfaces=</var> lines in the
+ <var>config setup</var> section</li>
+ <li>discovering the IP addresses for those interfaces</li>
+ <li>searching for a match between those addresses and the ones given in
+ <var>left=</var> or <var>right=</var> lines.</li>
+</ul>
+
+<p>Normally a match is found. Then Pluto knows where it is and can set up
+other things (for example, if it is <var>left</var>) using parameters such as
+<var>leftsubnet</var> and <var>leftnexthop</var>, and sending its outgoing
+packets to <var>right</var>.</p>
+
+<p>If no match is found, it emits the above error message.</p>
+
+<h3><a name="noconn">Pluto: ... no connection is known</a></h3>
+
+<p>This error message occurs when a remote system attempts to negotiate a
+connection and Pluto does not have a connection description that matches what
+the remote system has requested. The most common cause is a configuration
+error on one end or the other.</p>
+
+<p>Parameters involved in this match are <var>left</var>, <var>right</var>,
+<var>leftsubnet</var> and <var>rightsubnet</var>.</p>
+
+<p><strong>The match must be exact</strong>. For example, if your left subnet
+is a.b.c.0/24 then neither a single machine in that net nor a smaller subnet
+such as a.b.c.64/26 will be considered a match.</p>
+
+<p>The message can also occur when an appropriate description exists but
+Pluto has not loaded it. Use an <var>auto=add</var> statement in the
+connection description, or an <var>ipsec auto --add &lt;conn_name&gt;</var>
+command, to correct this.</p>
+
+<p>An explanation from the Pluto developer:</p>
+<pre>| Jul 12 15:00:22 sohar58 Pluto[574]: "corp_road" #2: cannot respond to IPsec
+| SA request because no connection is known for
+| 216.112.83.112/32===216.112.83.112...216.67.25.118
+
+This is the first message from the Pluto log showing a problem. It
+means that PGPnet is trying to negotiate a set of SAs with this
+topology:
+
+216.112.83.112/32===216.112.83.112...216.67.25.118
+^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
+client on our side our host PGPnet host, no client
+
+None of the conns you showed look like this.
+
+Use
+ ipsec auto --status
+to see a snapshot of what connections are in pluto, what
+negotiations are going on, and what SAs are established.
+
+The leftsubnet= (client) in your conn is 216.112.83.64/26. It must
+exactly match what pluto is looking for, and it does not.</pre>
+
+<h3><a name="nosuit">Pluto: ... no suitable connection ...</a></h3>
+
+<p>This is similar to the <a href="#noconn">no connection known</a> error,
+but occurs at a different point in Pluto processing.</p>
+
+<p>Here is one of Claudia's messages explaining the problem:</p>
+<pre>You write,
+
+&gt; What could be the reason of the following error?
+&gt; "no suitable connection for peer '@xforce'"
+
+When a connection is initiated by the peer, Pluto must choose which entry in
+the conf file best matches the incoming connection. A preliminary choice is
+made on the basis of source and destination IPs, since that information is
+available at that time.
+
+A payload containing an ID arrives later in the negotiation. Based on this
+id and the *id= parameters, Pluto refines its conn selection. ...
+
+The message "no suitable connection" indicates that in this refining step,
+Pluto does not find a connection that matches that ID.
+
+Please see "Selecting a connection when responding" in man ipsec_pluto for
+more details.</pre>
+
+<p>See also <a href="#conn_name">Connection names in Pluto error
+messages</a>.</p>
+
+<h3><a name="noconn.auth">Pluto: ... no connection has been
+authorized</a></h3>
+
+<p>Here is one of Claudia's messages discussing this problem:</p>
+<pre>You write,
+
+&gt; May 22 10:46:31 debian Pluto[25834]: packet from x.y.z.p:10014:
+&gt; initial Main Mode message from x.y.z.p:10014
+ but no connection has been authorized
+
+This error occurs early in the connection negotiation process,
+at the first step of IKE negotiation (Main Mode), which is itself the
+first of two negotiation phases involved in creating an IPSec connection.
+
+Here, Linux FreeS/WAN receives a packet from a potential peer, which
+requests that they begin discussing a connection.
+
+The "no connection has been authorized" means that there is no connection
+description in Linux FreeS/WAN's internal database that can be used to
+link your ipsec interface with that peer.
+
+"But of course I configured that connection!"
+
+It may be that the appropriate connection description exists in ipsec.conf
+but has not been added to the database with ipsec auto --add myconn or the
+auto=add method. Or, the connection description may be misconfigured.
+
+The only parameters that are relevant in this decision are left= and right= .
+Local and remote ports are also taken into account -- we see that the port
+is printed in the message above -- but there is no way to control these
+in ipsec.conf.
+
+
+Failure at "no connection has been authorized" is similar to the
+"no connection is known for..." error in the FAQ, and the "no suitable
+connection" error described in the snapshot's FAQ. In all three cases,
+Linux FreeS/WAN is trying to match parameters received in the
+negotiation with the connection description in the local config file.
+
+As it receives more information, its matches take more parameters into
+account, and become more precise: first the pair of potential peers,
+then the peer IDs, then the endpoints (including any subnets).
+
+The "no suitable connection for peer *" occurs toward the end of IKE
+(Main Mode) negotiation, when the IDs are matched.
+
+"no connection is known for a/b===c...d" is seen at the beginning of IPSec
+(Quick Mode, phase 2) negotiation, when the connections are matched using
+left, right, and any information about the subnets.</pre>
+
+<h3><a name="noDESsupport">Pluto: ... OAKLEY_DES_CBC is not
+supported.</a></h3>
+
+<p>This message occurs when the other system attempts to negotiate a
+connection using <a href="glossary.html#DES">single DES</a>, which we do not
+support because it is <a href="politics.html#desnotsecure">insecure</a>.</p>
+
+<p>Our interoperation document has suggestions for <a
+href="interop.html#noDES">how to deal with</a> systems that attempt to use
+single DES.</p>
+
+<h3><a name="notransform">Pluto: ... no acceptable transform</a></h3>
+
+<p>This message means that the other gateway has made a proposal for
+connection parameters, but nothing they proposed is acceptable to Pluto.
+Possible causes include:</p>
+<ul>
+ <li>misconfiguration on either end</li>
+ <li>policy incompatibilities, for example we require encrypted connections
+ but they are trying to create one with just authentication</li>
+ <li>interoperation problems, for example they offer only single DES and
+ FreeS/WAN does not support that. See <a
+ href="interop.html#interop.problem">discussion</a> in our interoperation
+ document.</li>
+</ul>
+
+<p>A more detailed explanation, from Pluto programmer Hugh Redelmeier:</p>
+<pre>Background:
+
+When one IKE system (for example, Pluto) is negotiating with another
+to create an SA, the Initiator proposes a bunch of choices and the
+Responder replies with one that it has selected.
+
+The structure of the choices is fairly complicated. An SA payload
+contains a list of lists of "Proposals". The outer list is a set of
+choices: the selection must be from one element of this list.
+
+Each of these elements is a list of Proposals. A selection must be
+made from each of the elements of the inner list. In other words,
+*all* of them apply (that is how, for example, both AH and ESP can
+apply at once).
+
+Within each of these Proposals is a list of Transforms. For each
+Proposal selected, one Transform must be selected (in other words,
+each Proposal provides a choice of Transforms).
+
+Each Transform is made up of a list of Attributes describing, well,
+attributes. Such as lifetime of the SA. Such as algorithm to be
+used. All the Attributes apply to a Transform.
+
+You will have noticed a pattern here: layers alternate between being
+disjunctions ("or") and conjunctions ("and").
+
+For Phase 1 / Main Mode (negotiating an ISAKMP SA), this structure is
+cut back. There must be exactly one Proposal. So this degenerates to
+a list of Transforms, one of which must be chosen.
+
+In your case, no proposal was considered acceptable to Pluto (the
+Responder). So negotiation ceased. Pluto logs the reason it rejects
+each Transform. So look back in the log to see what is going wrong.</pre>
+
+<h3><a name="rsasigkey">rsasigkey dumps core</a></h3>
+A comment on this error from Henry:
+<pre>On Fri, 29 Jun 2001, Rodrigo Gruppelli wrote:
+&gt; ...Well, it seem that there's
+&gt; another problem with it. When I try to generate a pair of RSA keys,
+&gt; rsasigkey cores dump...
+
+*That* is a neon sign flashing "GMP LIBRARY IS BROKEN". Rsasigkey calls
+GMP a lot, and our own library a little bit, and that's very nearly all it
+does. Barring bugs in its code or our library -- which have happened, but
+not very often -- a problem in rsasigkey is a problem in GMP.</pre>
+
+<p>See the next question for how to deal with GMP errors.</p>
+
+<h3><a name="sig4">!Pluto failure!: ... exited with ... signal 4</a></h3>
+
+<p>Pluto has died. Signal 4 is SIGILL, illegal instruction.</p>
+
+<p>The most likely cause is that your <a href="glossary.html#GMP">GMP</a>
+(GNU multi-precision) library is compiled for a different processor than what
+you are running on. Pluto uses that library for its public key
+calculations.</p>
+
+<p>Try getting the GMP sources and recompile for your processor type. Most
+Linux distributions will include this source, or you can download it from the
+<a href="http://www.swox.com/gmp/">GMP home page</a>.</p>
+
+<h3><a name="econnrefused">ECONNREFUSED error message</a></h3>
+
+<p>From John Denker, on the mailing list:</p>
+<pre>1) The log message
+ some IKE message we sent has been rejected with
+ ECONNREFUSED (kernel supplied no details)
+is much more suitable than the previous version. Thanks.
+
+2) Minor suggestion for further improvement: it might be worth mentioning
+that the command
+ tcpdump -i eth1 icmp[0] != 8 and icmp[0] != 0
+is useful for tracking down the details in question. We shouldn't expect
+all IPsec users to figure that out on their own. The log message might
+even provide a hint as to where to look in the docs.</pre>
+
+<p>Reply From Pluto developer Hugh Redelmeier</p>
+<pre>Good idea.
+
+I've added a bit pluto(8)'s BUGS section along these lines.
+I didn't have the heart to lengthen this message.</pre>
+
+<h3><a name="no_eroute">klips_debug: ... no eroute!</a></h3>
+
+<p>This message means <a href="glossary.html#KLIPS">KLIPS</a> has received a
+packet for which no IPsec tunnel has been defined.</p>
+
+<p>Here is a more detailed duscussion from the team's tech support person
+Claudia Schmeing, responding to a query on the mailing list:</p>
+<pre>&gt; Why ipsec reports no eroute! ???? IP Masq... is disabled.
+
+In general, more information is required so that people on the list may
+give you informed input. See doc/prob.report.</pre>
+
+<p>The document she refers to has since been replaced by a <a
+href="trouble.html#prob.report">section</a> of the troubleshooting
+document.</p>
+<pre>However, I can make some general comments on this type of error.
+
+This error usually looks something like this (clipped from an archived
+message):
+
+&gt; ttl:64 proto:1 chk:45459 saddr:192.168.1.2 daddr:192.168.100.1
+&gt; ... klips_debug:ipsec_findroute: 192.168.1.2-&gt;192.168.100.1
+&gt; ... klips_debug:rj_match: * See if we match exactly as a host destination
+&gt; ... klips_debug:rj_match: ** try to match a leaf, t=0xc1a260b0
+&gt; ... klips_debug:rj_match: *** start searching up the tree, t=0xc1a260b0
+&gt; ... klips_debug:rj_match: **** t=0xc1a260c8
+&gt; ... klips_debug:rj_match: **** t=0xc1fe5960
+&gt; ... klips_debug:rj_match: ***** not found.
+&gt; ... klips_debug:ipsec_tunnel_start_xmit: Original head/tailroom: 2, 28
+&gt; ... klips_debug:ipsec_tunnel_start_xmit: no eroute!: ts=47.3030, dropping.
+
+
+What does this mean?
+- --------------------
+
+"eroute" stands for "extended route", and is a special type of route
+internal to Linux FreeS/WAN. For more information about this type of route,
+see the section of man ipsec_auto on ipsec auto --route.
+
+"no eroute!" here means, roughly, that Linux FreeS/WAN cannot find an
+appropriate tunnel that should have delivered this packet. Linux
+FreeS/WAN therefore drops the packet, with the message "no eroute! ...
+dropping", on the assumption that this packet is not a legitimate
+transmission through a properly constructed tunnel.
+
+
+How does this situation come about?
+- -----------------------------------
+
+Linux FreeS/WAN has a number of connection descriptions defined in
+ipsec.conf. These must be successfully brought "up" to form actual tunnels.
+(see doc/setup.html's step 15, man ipsec.conf and man ipsec_auto
+for details).
+
+Such connections are often specific to the endpoints' IPs. However, in
+some cases they may be more general, for example in the case of
+Road Warriors where left or right is the special value %any.
+
+When Linux FreeS/WAN receives a packet, it verifies that the packet has
+come through a legitimate channel, by checking that there is an
+appropriate tunnel through which this packet might legitimately have
+arrived. This is the process we see above.
+
+First, it checks for an eroute that exactly matches the packet. In the
+example above, we see it checking for a route that begins at 192.168.1.2
+and ends at 192.168.100.1. This search favours the most specific match that
+would apply to the route between these IPs. So, if there is a connection
+description exactly matching these IPs, the search will end there. If not,
+the code will search for a more general description matching the IPs.
+If there is no match, either specific or general, the packet will be
+dropped, as we see, above.
+
+Unless you are working with Road Warriors, only the first, specific part
+of the matching process is likely to be relevant to you.
+
+
+"But I defined the tunnel, and it came up, why do I have this error?"
+- ---------------------------------------------------------------------
+
+One of the most common causes of this error is failure to specify enough
+connection descriptions to cover all needed tunnels between any two
+gateways and their respective subnets. As you have noticed, troubleshooting
+this error may be complicated by the use of IP Masq. However, this error is
+not limited to cases where IP Masq is used.
+
+See doc/configuration.html#multitunnel for a detailed example of the
+solution to this type of problem.</pre>
+
+<p>The documentation section she refers to is now <a
+href="adv_config.html#multitunnel">here</a>.</p>
+
+<h3><a name="SAused">... trouble writing to /dev/ipsec ... SA already in
+use</a></h3>
+
+<p>This error message occurs when two manual connections are set up with the
+same SPI value. </p>
+
+<p>See the FAQ for <a href="#spi_error">One manual connection works, but
+second one fails</a>.</p>
+
+<h3><a name="ignore">... ignoring ... payload</a></h3>
+
+<p>This message is harmless. The IKE protocol provides for a number of
+optional messages types:</p>
+<ul>
+ <li>delete SA</li>
+ <li>initial contact</li>
+ <li>vendor ID</li>
+ <li>...</li>
+</ul>
+
+<p>An implementation is never required to send these, but they are allowed
+to. The receiver is not required to do anything with them. FreeS/WAN ignores
+them, but notifies you via the logs.</p>
+
+<p>For the "ignoring delete SA Payload" message, see also our discussion of
+cleaning up <a href="#deadtunnel">dead tunnels</a>.</p>
+
+<h3><a name="unknown_rightcert">unknown parameter name "rightcert"</a></h3>
+
+<P>This message can appear when you've upgraded an X.509-enabled
+Linux FreeS/WAN with a vanilla Linux FreeS/WAN. To use your X.509 configs
+you will need to overwrite the new install with
+<A HREF="http://www.freeswan.ca">Super FreeS/WAN</A>, or add the
+<A HREF="http://www.strongsec.ca/freeswan">X.509 patch</A> by hand.
+</P>
+
+<h2><a name="spam">Why don't you restrict the mailing lists to reduce
+spam?</a></h2>
+
+<p>As a matter of policy, some of our <a href="mail.html">mailing lists</a>
+need to be open to non-subscribers. Project management feel strongly that
+maintaining this openness is more important than blocking spam.</p>
+<ul>
+ <li>Users should be able to get help or report bugs without
+ subscribing.</li>
+ <li>Even a user who is subscribed may not have access to his or her
+ subscribed account when he or she needs help, miles from home base in the
+ middle of setting up a client's gateway.</li>
+ <li>There is arguably a legal requirement for this policy. A US resident or
+ citizen could be charged under munitions export laws for providing
+ technical assistance to a foreign cryptographic project. Such a charge
+ would be more easily defended if the discussion takes place in public, on
+ an open list.</li>
+</ul>
+
+<p>This has been discussed several times at some length on the list. See the
+<a href="mail.html#archive">list archives</a>. Bringing the topic up again is
+unlikely to be useful. Please don't. Or at the very least, please don't
+without reading the archives and being certain that whatever you are about to
+suggest has not yet been discussed.</p>
+
+<p>Project technical lead Henry Spencer summarised one discussion:</p>
+
+<blockquote>
+ For the third and last time: this list *will* *not* do address-based
+ filtering. This is a policy decision, not an implementation problem. The
+ decision is final, and is not open to discussion. This needs to be
+ communicated better to people, and steps are being taken to do
+that.</blockquote>
+
+<p>Adding this FAQ section is one of the steps he refers to.</p>
+
+<p>You have various options other than just putting up with the spam,
+filtering it yourself, or unsubscribing:</p>
+<ul>
+ <li>subscribe only to one or both of our lists with restricted posting
+ rules:
+ <ul>
+ <li><a
+ href="mailto:briefs@lists.freeswan.org?body=subscribe">briefs</a>,
+ weekly list summaries</li>
+ <li><a
+ href="mailto:announce@lists.freeswan.org?body=subscribe">announce</a>,
+ project-related announcements</li>
+ </ul>
+ </li>
+ <li>read the other lists via the <a
+ href="mail.html#archive">archives</a></li>
+</ul>
+
+<p>A number of tools are available to filter mail.</p>
+<ul>
+ <li>Many mail readers include some filtering capability.</li>
+ <li>Many Linux distributions include <a
+ href="http://www.procmail.org/">procmail(8)</a> for server-side
+ filtering.</li>
+ <li>The <a href="http://www.spambouncer.org/">Spam Bouncer</a> is a set of
+ procmail(8) filters designed to combat spam.</li>
+ <li>Roaring Penguin have a <a
+ href="http://www.roaringpenguin.com/mimedefang/">MIME defanger</a> that
+ removes potentially dangerous attachments.</li>
+</ul>
+
+<p>If you use your ISP's mail server rather than running your own, consider
+suggesting to the ISP that they tag suspected spam as <a
+href="http://www.msen.com/1997/spam.html#SUSPECTED">this ISP</a> does. They
+could just refuse mail from dubious sources, but that is tricky and runs some
+risk of losing valuable mail or senselessly annoying senders and their
+admins. However, they can safely tag and deliver dubious mail. The tags can
+greatly assist your filtering.</p>
+
+<p>For information on tracking down spammers, see these <a
+href="http://www.rahul.net/falk/#howtos">HowTos</a>, or the <a
+href="http://www.sputum.com/index2.html">Sputum</a> site. Sputum have a Linux
+anti-spam screensaver available for download.</p>
+
+<p>Here is a more detailed message from Henry:</p>
+<pre>On Mon, 15 Jan 2001, Jay Vaughan wrote:
+&gt; I know I'm flogging a dead horse here, but I'm curious as to the reasons for
+&gt; an aversion for a subscriber-only mailing list?
+
+Once again: for legal reasons, it is important that discussions of these
+things be held in a public place -- the list -- and we do not want to
+force people to subscribe to the list just to ask one question, because
+that may be more than merely inconvenient for them. There are also real
+difficulties with people who are temporarily forced to use alternate
+addresses; that is precisely the time when they may be most in need of
+help, yet a subscribers-only policy shuts them out.
+
+These issues do not apply to most mailing lists, but for a list that is
+(necessarily) the primary user support route for a crypto package, they
+are very important. This is *not* an ordinary mailing list; it has to
+function under awkward constraints that make various simplistic solutions
+inapplicable or undesirable.
+
+&gt; We're *ALL* sick of hearing about list management problems, not just you
+&gt; old-timers, so why don't you DO SOMETHING EFFECTIVE ABOUT IT...
+
+Because it's a lot harder than it looks, and many existing "solutions"
+have problems when examined closely.
+
+&gt; A suggestion for you, based on 10 years of experience with management of my
+&gt; own mailing lists would be to use mailman, which includes pretty much every
+&gt; feature under the sun that you guys need and want, plus some. The URL for
+&gt; mailman...
+
+I assure you, we're aware of mailman. Along with a whole bunch of others,
+including some you almost certainly have never heard of (I hadn't!).
+
+&gt; As for the argument that the list shouldn't be configured to enforce
+&gt; subscription - I contend that it *SHOULD* AT LEAST require manual address
+&gt; verification in order for posts to be redirected.
+
+You do realize, I hope, that interposing such a manual step might cause
+your government to decide that this is not truly a public forum, and thus
+you could go to jail if you don't get approval from them before mailing to
+it? If you think this sounds irrational, your government is noted for
+making irrational decisions in this area; we can't assume that they will
+suddenly start being sensible. See above about awkward constraints. You
+may be willing to take the risk, but we can't, in good conscience, insist
+that all users with problems do so.
+
+ Henry Spencer
+ henry@spsystems.net</pre>
+
+<p>and a message on the topic from project leader John Gilmore:</p>
+<pre>Subject: Re: The linux-ipsec list's topic
+ Date: Sat, 30 Dec 2000
+ From: John Gilmore &lt;gnu@toad.com&gt;
+
+I'll post this single message, once only, in this discussion, and then
+not burden the list with any further off-topic messages. I encourage
+everyone on the list to restrain themself from posting ANY off-topic
+messages to the linux-ipsec list.
+
+The topic of the linux-ipsec mailing list is the FreeS/WAN software.
+
+I frequently see "discussions about spam on a list" overwhelm the
+volume of "actual spam" on a list. BOTH kinds of messages are
+off-topic messages. Twenty anti-spam messages take just as long to
+detect and discard as twenty spam messages.
+
+The Linux-ipsec list encourages on-topic messages from people who have
+not joined the list itself. We will not censor messages to the list
+based on where they originate, or what return address they contain.
+In other words, non-subscribers ARE allowed to post, and this will not
+change. My own valid contributions have been rejected out-of-hand by
+too many other mailing lists for me to want to impose that censorship
+on anybody else's contributions. And every day I see the damage that
+anti-spam zeal is causing in many other ways; that zeal is far more
+damaging to the culture of the Internet than the nuisance of spam.
+
+In general, it is the responsibility of recipients to filter,
+prioritize, or otherwise manage the handling of email that comes to
+them. It is not the responsibility of the rest of the Internet
+community to refrain from sending messages to recipients that they
+might not want to see. If your software infrastructure for managing
+your incoming email is insufficient, then improve it. If you think
+the signal-to-noise ratio on linux-ipsec is too poor, then please
+unsubscribe. But don't further increase the noise by posting to the
+linux-ipsec list about those topics.
+
+ John Gilmore
+ founder &amp; sponsor, FreeS/WAN project</pre>
+</body>
+</html>
diff --git a/doc/src/firewall.html b/doc/src/firewall.html
new file mode 100644
index 000000000..5051b458d
--- /dev/null
+++ b/doc/src/firewall.html
@@ -0,0 +1,895 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN and firewalls</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, firewall, ipchains, iptables">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: firewall.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="firewall">FreeS/WAN and firewalls</a></h1>
+
+<p>FreeS/WAN, or other IPsec implementations, frequently run on gateway
+machines, the same machines running firewall or packet filtering code. This
+document discusses the relation between the two.</p>
+
+<p>The firewall code in 2.4 and later kernels is called Netfilter. The
+user-space utility to manage a firewall is iptables(8). See the <a
+href="http://netfilter.samba.org">netfilter/iptables web site</a> for
+details.</p>
+
+<h2><a name="filters">Filtering rules for IPsec packets</a></h2>
+
+<p>The basic constraint is that <strong>an IPsec gateway must have packet
+filters that allow IPsec packets</strong>, at least when talking to other
+IPsec gateways:</p>
+<ul>
+ <li>UDP port 500 for <a href="glossary.html#IKE">IKE</a> negotiations</li>
+ <li>protocol 50 if you use <a href="glossary.html#ESP">ESP</a> encryption
+ and/or authentication (the typical case)</li>
+ <li>protocol 51 if you use <a href="glossary.html#AH">AH</a> packet-level
+ authentication</li>
+</ul>
+
+<p>Your gateway and the other IPsec gateways it communicates with must be
+able to exchange these packets for IPsec to work. Firewall rules must allow
+UDP 500 and at least one of <a href="glossary.html#AH">AH</a> or
+<a href="glossary.html#ESP">ESP</a> on
+the interface that communicates with the other gateway.</p>
+
+<p>For nearly all FreeS/WAN applications, you must allow UDP port 500 and the
+ESP protocol.</p>
+
+<p>There are two ways to set this up:</p>
+<dl>
+ <dt>easier but less flexible</dt>
+ <dd>Just set up your firewall scripts at boot time to allow IPsec packets
+ to and from your gateway. Let FreeS/WAN reject any bogus packets.</dd>
+ <dt>more work, giving you more precise control</dt>
+ <dd>Have the <a href="manpage.d/ipsec_pluto.8.html">ipsec_pluto(8)</a>
+ daemon call scripts to adjust firewall rules dynamically as required.
+ This is done by naming the scripts in the <a
+ href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> variables
+ <var>prepluto=</var>, <var>postpluto=</var>, <var>leftupdown=</var> and
+ <var>rightupdown=</var>.</dd>
+</dl>
+
+<p>Both methods are described in more detail below.</p>
+
+<h2><a name="examplefw">Firewall configuration at boot</a></h2>
+
+<p>It is possible to set up both firewalling and IPsec with appropriate
+scripts at boot and then not use <var>leftupdown=</var> and
+<var>rightupdown=</var>, or use them only for simple up and down
+operations.</p>
+
+<p>Basically, the technique is</p>
+<ul>
+ <li>allow IPsec packets (typically, IKE on UDP port 500 plus ESP, protocol
+ 50)
+ <ul>
+ <li>incoming, if the destination address is your gateway (and
+ optionally, only from known senders)</li>
+ <li>outgoing, with the from address of your gateway (and optionally,
+ only to known receivers)</li>
+ </ul>
+ </li>
+ <li>let <a href="glossary.html#Pluto">Pluto</a> deal with IKE</li>
+ <li>let <a href="glossary.html#KLIPS">KLIPS</a> deal with ESP</li>
+</ul>
+
+<p>Since Pluto authenticates its partners during the negotiation, and KLIPS
+drops packets for which no tunnel has been negotiated, this may be all you
+need.</p>
+
+<h3><a name="simple.rules">A simple set of rules</a></h3>
+
+<p>In simple cases, you need only a few rules, as in this example:</p>
+<pre># allow IPsec
+#
+# IKE negotiations
+iptables -I INPUT -p udp --sport 500 --dport 500 -j ACCEPT
+iptables -I OUTPUT -p udp --sport 500 --dport 500 -j ACCEPT
+# ESP encryption and authentication
+iptables -I INPUT -p 50 -j ACCEPT
+iptables -I OUTPUT -p 50 -j ACCEPT
+</pre>
+
+<P>This should be all you need to allow IPsec through <var>lokkit</var>,
+which ships with Red Hat 9, on its medium security setting.
+Once you've tweaked to your satisfaction, save your active rule set with:</P>
+<PRE>service iptables save</PRE>
+
+<h3><a name="complex.rules">Other rules</a></h3>
+You can add additional rules, or modify existing ones, to work with IPsec and
+with your network and policies. We give a some examples in this section.
+
+<p>However, while it is certainly possible to create an elaborate set of
+rules yourself (please let us know via the <a href="mail.html">mailing
+list</a> if you do), it may be both easier and more secure to use a set which
+has already been published and tested.</p>
+
+<p>The published rule sets we know of are described in the <a
+href="#rules.pub">next section</a>.</p>
+
+<h4>Adding additional rules</h4>
+If necessary, you can add additional rules to:
+<dl>
+ <dt>reject IPsec packets that are not to or from known gateways</dt>
+ <dd>This possibility is discussed in more detail <a
+ href="#unknowngate">later</a></dd>
+ <dt>allow systems behind your gateway to build IPsec tunnels that pass
+ through the gateway</dt>
+ <dd>This possibility is discussed in more detail <a
+ href="#through">later</a></dd>
+ <dt>filter incoming packets emerging from KLIPS.</dt>
+ <dd>Firewall rules can recognise packets emerging from IPsec. They are
+ marked as arriving on an interface such as <var>ipsec0</var>, rather
+ than <var>eth0</var>, <var>ppp0</var> or whatever.</dd>
+</dl>
+
+<p>It is therefore reasonably straightforward to filter these packets in
+whatever way suits your situation.</p>
+
+<h4>Modifying existing rules</h4>
+
+<p>In some cases rules that work fine before you add IPsec may require
+modification to work with IPsec.</p>
+
+<p>This is especially likely for rules that deal with interfaces on the
+Internet side of your system. IPsec adds a new interface; often the rules
+must change to take account of that.</p>
+
+<p>For example, consider the rules given in <a
+href="http://www.netfilter.org/documentation/HOWTO//packet-filtering-HOWTO-5.html">this
+section</a> of the Netfilter documentation:</p>
+<pre>Most people just have a single PPP connection to the Internet, and don't
+want anyone coming back into their network, or the firewall:
+
+ ## Insert connection-tracking modules (not needed if built into kernel).
+ # insmod ip_conntrack
+ # insmod ip_conntrack_ftp
+
+ ## Create chain which blocks new connections, except if coming from inside.
+ # iptables -N block
+ # iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
+ # iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
+ # iptables -A block -j DROP
+
+ ## Jump to that chain from INPUT and FORWARD chains.
+ # iptables -A INPUT -j block
+ # iptables -A FORWARD -j block</pre>
+
+<p>On an IPsec gateway, those rules may need to be modified. The above allows
+new connections from <em>anywhere except ppp0</em>. That means new
+connections from ipsec0 are allowed.</p>
+
+<p>Do you want to allow anyone who can establish an IPsec connection to your
+gateway to initiate TCP connections to any service on your network? Almost
+certainly not if you are using opportunistic encryption. Quite possibly not
+even if you have only explicitly configured connections.</p>
+
+<p>To disallow incoming connections from ipsec0, change the middle section
+above to:</p>
+<pre> ## Create chain which blocks new connections, except if coming from inside.
+ # iptables -N block
+ # iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
+ # iptables -A block -m state --state NEW -i ppp+ -j DROP
+ # iptables -A block -m state --state NEW -i ipsec+ -j DROP
+ # iptables -A block -m state --state NEW -i -j ACCEPT
+ # iptables -A block -j DROP</pre>
+
+<p>The original rules accepted NEW connections from anywhere except ppp0.
+This version drops NEW connections from any PPP interface (ppp+) and from any
+ipsec interface (ipsec+), then accepts the survivors.</p>
+
+<p>Of course, these are only examples. You will need to adapt them to your
+own situation.</p>
+
+<h3><a name="rules.pub">Published rule sets</a></h3>
+
+<p>Several sets of firewall rules that work with FreeS/WAN are available.</p>
+
+<h4><a name="Ranch.trinity">Scripts based on Ranch's work</a></h4>
+
+<p>One user, Rob Hutton, posted his boot time scripts to the mailing list,
+and we included them in previous versions of this documentation. They are
+still available from our <a
+href="http://www.freeswan.org/freeswan_trees/freeswan-1.5/doc/firewall.html#examplefw">web
+site</a>. However, they were for an earlier FreeS/WAN version so we no longer
+recommend them. Also, they had some bugs. See this <a
+href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/04/msg00316.html">message</a>.</p>
+
+<p>Those scripts were based on David Ranch's scripts for his "Trinity OS" for
+setting up a secure Linux. Check his <a
+href="http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html">home
+page</a> for the latest version and for information on his <a
+href="biblio.html#ranch">book</a> on securing Linux. If you are going to base
+your firewalling on Ranch's scripts, we recommend using his latest version,
+and sending him any IPsec modifications you make for incorporation into later
+versions.</p>
+
+<h4><a name="seawall">The Seattle firewall</a></h4>
+
+<p>We have had several mailing lists reports of good results using FreeS/WAN
+with Seawall (the Seattle Firewall). See that project's <a
+href="http://seawall.sourceforge.net/">home page</a> on Sourceforge.</p>
+
+<h4><a name="rcf">The RCF scripts</a></h4>
+
+<p>Another set of firewall scripts with IPsec support are the RCF or
+rc.firewall scripts. See their <a
+href="http://jsmoriss.mvlan.net/linux/rcf.html">home page</a>.</p>
+
+<h4><a name="asgard">Asgard scripts</a></h4>
+
+<p><a href="http://heimdall.asgardsrealm.net/linux/firewall/">Asgard's
+Realm</a> has set of firewall scripts with FreeS/WAN support, for 2.4 kernels
+and iptables.</p>
+
+<h4><a name="user.scripts">User scripts from the mailing list</a></h4>
+
+<p>One user gave considerable detail on his scripts, including supporting <a
+href="glossary.html#IPX">IPX</a> through the tunnel. His message was too long
+to conveniently be quoted here, so I've put it in a <a
+href="user_examples.html">separate file</a>.</p>
+
+<h2><a name="updown">Calling firewall scripts, named in ipsec.conf(5)</a></h2>
+
+<p>The <a href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> configuration
+file has three pairs of parameters used to specify an interface between
+FreeS/WAN and firewalling code.</p>
+
+<p>Note that using these is not required if you have a static firewall setup.
+In that case, you just set your firewall up at boot time (in a way that
+permits the IPsec connections you want) and do not change it thereafter. Omit
+all the FreeS/WAN firewall parameters and FreeS/WAN will not attempt to
+adjust firewall rules at all. See <a href="#examplefw">above</a> for some
+information on appropriate scripts.</p>
+
+<p>However, if you want your firewall rules to change when IPsec connections
+change, then you need to use these parameters.</p>
+
+<h3><a name="pre_post">Scripts called at IPsec start and stop</a></h3>
+
+<p>One pair of parmeters are set in the <var>config setup</var> section of
+the <a href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> file and affect
+all connections:</p>
+<dl>
+ <dt>prepluto=</dt>
+ <dd>script to be called before <a
+ href="manpage.d/ipsec_pluto.8.html">pluto(8)</a> IKE daemon is
+ started.</dd>
+ <dt>postpluto=</dt>
+ <dd>script to be called after <a
+ href="manpage.d/ipsec_pluto.8.html">pluto(8)</a> IKE daemon is
+ stopped.</dd>
+</dl>
+These parameters allow you to change firewall parameters whenever IPsec is
+started or stopped.
+
+<p>They can also be used in other ways. For example, you might have
+<var>prepluto</var> add a module to your kernel for the secure network
+interface or make a dialup connection, and then have <var>postpluto</var>
+remove the module or take the connection down.</p>
+
+<h3><a name="up_down">Scripts called at connection up and down</a></h3>
+
+<p>The other parameters are set in connection descriptions. They can be set
+in individual connection descriptions, and could even call different scripts
+for each connection for maximum flexibility. In most applications, however,
+it makes sense to use only one script and to call it from <var>conn
+%default</var> section so that it applies to all connections.</p>
+
+<p>You can:</p>
+<dl>
+ <dt><strong>either</strong></dt>
+ <dd>set <var>leftfirewall=yes</var> or <var>rightfirewall=yes</var> to
+ use our supplied default script</dd>
+ <dt><strong>or</strong></dt>
+ <dd>assign a name in a <var>leftupdown=</var> or <var>rightupdown=</var>
+ line to use your own script</dd>
+</dl>
+
+<p>Note that <strong>only one of these should be used</strong>. You cannot
+sensibly use both. Since <strong>our default script is obsolete</strong>
+(designed for firewalls using <var>ipfwadm(8)</var> on 2.0 kernels), most
+users who need this service will <strong>need to write a custom
+script</strong>.</p>
+
+<h4><a name="fw.default">The default script</a></h4>
+
+<p>We supply a default script named <var>_updown</var>.</p>
+<dl>
+ <dt>leftfirewall=</dt>
+ <dd></dd>
+ <dt>rightfirewall=</dt>
+ <dd>indicates that the gateway is doing firewalling and that <a
+ href="manpage.d/ipsec_pluto.8.html">pluto(8)</a> should poke holes in
+ the firewall as required.</dd>
+</dl>
+
+<p>Set these to <var>yes</var> and Pluto will call our default script
+<var>_updown</var> with appropriate arguments whenever it:</p>
+<ul>
+ <li>starts or stops IPsec services</li>
+ <li>brings a connection up or down</li>
+</ul>
+
+<p>The supplied default <var>_updown</var> script is appropriate for simple
+cases using the <var>ipfwadm(8)</var> firewalling package.</p>
+
+<h4><a name="userscript">User-written scripts</a></h4>
+
+<p>You can also write your own script and have Pluto call it. Just put the
+script's name in one of these <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> lines:</p>
+<dl>
+ <dt>leftupdown=</dt>
+ <dd></dd>
+ <dt>rightupdown=</dt>
+ <dd>specifies a script to call instead of our default script
+ <var>_updown</var>.</dd>
+</dl>
+
+<p>Your script should take the same arguments and use the same environment
+variables as <var>_updown</var>. See the "updown command" section of the <a
+href="manpage.d/ipsec_pluto.8.html">ipsec_pluto(8)</a> man page for
+details.</p>
+
+<p>Note that <strong>you should not modify our _updown script in
+place</strong>. If you did that, then upgraded FreeS/WAN, the upgrade would
+install a new default script, overwriting your changes.</p>
+
+<h3><a name="ipchains.script">Scripts for ipchains or iptables</a></h3>
+
+<p>Our <var>_updown</var> is for firewalls using <var>ipfwadm(8)</var>, the
+firewall code for the 2.0 series of Linux kernels. If you are using the more
+recent packages <var>ipchains(8)</var> (for 2.2 kernels) or
+<var>iptables(8)</var> (2.4 kernels), then you must do one of:</p>
+<ul>
+ <li>use static firewall rules which are set up at boot time as described <a
+ href="#examplefw">above</a> and do not need to be changed by Pluto</li>
+ <li>limit yourself to ipchains(8)'s ipfwadm(8) emulation mode in order to
+ use our script</li>
+ <li>write your own script and call it with <var>leftupdown</var> and
+ <var>rightupdown</var>.</li>
+</ul>
+
+<p>You can write a script to do whatever you need with firewalling. Specify
+its name in a <var>[left|right]updown=</var> parameter in <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> and Pluto will
+automatically call it for you.</p>
+
+<p>The arguments Pluto passes such a script are the same ones it passes to
+our default _updown script, so the best way to build yours is to copy ours
+and modify the copy.</p>
+
+<p>Note, however, that <strong>you should not modify our _updown script in
+place</strong>. If you did that, then upgraded FreeS/WAN, the upgrade would
+install a new default script, overwriting your changes.</p>
+
+<h2><a name="NAT">A complication: IPsec vs. NAT</a></h2>
+
+<p><a href="glossary.html#NAT.gloss">Network Address Translation</a>, also
+known as IP masquerading, is a method of allocating IP addresses dynamically,
+typically in circumstances where the total number of machines which need to
+access the Internet exceeds the supply of IP addresses.</p>
+
+<p>Any attempt to perform NAT operations on IPsec packets <em>between the
+IPsec gateways</em> creates a basic conflict:</p>
+<ul>
+ <li>IPsec wants to authenticate packets and ensure they are unaltered on a
+ gateway-to-gateway basis</li>
+ <li>NAT rewrites packet headers as they go by</li>
+ <li>IPsec authentication fails if packets are rewritten anywhere between
+ the IPsec gateways</li>
+</ul>
+
+<p>For <a href="glossary.html#AH">AH</a>, which authenticates parts of the
+packet header including source and destination IP addresses, this is fatal.
+If NAT changes those fields, AH authentication fails.</p>
+
+<p>For <a href="glossary.html#IKE">IKE</a> and <a
+href="glossary.html#ESP">ESP</a> it is not necessarily fatal, but is
+certainly an unwelcome complication.</p>
+
+<h3><a name="nat_ok">NAT on or behind the IPsec gateway works</a></h3>
+
+<p>This problem can be avoided by having the masquerading take place <em>on
+or behind</em> the IPsec gateway.</p>
+
+<p>This can be done physically with two machines, one physically behind the
+other. A picture, using SG to indicate IPsec <strong>S</strong>ecurity
+<strong>G</strong>ateways, is:</p>
+<pre> clients --- NAT ----- SG ---------- SG
+ two machines</pre>
+
+<p>In this configuration, the actual client addresses need not be given in
+the <var>leftsubnet=</var> parameter of the FreeS/WAN connection description.
+The security gateway just delivers packets to the NAT box; it needs only that
+machine's address. What that machine does with them does not affect
+FreeS/WAN.</p>
+
+<p>A more common setup has one machine performing both functions:</p>
+<pre> clients ----- NAT/SG ---------------SG
+ one machine</pre>
+
+<p>Here you have a choice of techniques depending on whether you want to make
+your client subnet visible to clients on the other end:</p>
+<ul>
+ <li>If you want the single gateway to behave like the two shown above, with
+ your clients hidden behind the NAT, then omit the <var>leftsubnet=</var>
+ parameter. It then defaults to the gateway address. Clients on the other
+ end then talk via the tunnel only to your gateway. The gateway takes
+ packets emerging from the tunnel, applies normal masquerading, and
+ forwards them to clients.</li>
+ <li>If you want to make your client machines visible, then give the client
+ subnet addresses as the <var>leftsubnet=</var> parameter in the
+ connection description and
+ <dl>
+ <dt>either</dt>
+ <dd>set <var>leftfirewall=yes</var> to use the default
+ <var>updown</var> script</dd>
+ <dt>or</dt>
+ <dd>use your own script by giving its name in a
+ <var>leftupdown=</var> parameter</dd>
+ </dl>
+ These scripts are described in their own <a href="#updown">section</a>.
+ <p>In this case, no masquerading is done. Packets to or from the client
+ subnet are encrypted or decrypted without any change to their client
+ subnet addresses, although of course the encapsulating packets use
+ gateway addresses in their headers. Clients behind the right security
+ gateway see a route via that gateway to the left subnet.</p>
+ </li>
+</ul>
+
+<h3><a name="nat_bad">NAT between gateways is problematic</a></h3>
+
+<p>We recommend not trying to build IPsec connections which pass through a
+NAT machine. This setup poses problems:</p>
+<pre> clients --- SG --- NAT ---------- SG</pre>
+
+<p>If you must try it, some references are:</p>
+<ul>
+ <li>Jean_Francois Nadeau's document on doing <a
+ href="http://jixen.tripod.com/#NATed gateways">IPsec behind NAT</a></li>
+ <li><a href="web.html#VPN.masq">VPN masquerade patches</a> to make a Linux
+ NAT box handle IPsec packets correctly</li>
+</ul>
+
+<h3><a name="NAT.ref">Other references on NAT and IPsec</a></h3>
+
+<p>Other documents which may be relevant include:</p>
+<ul>
+ <li>an Internet Draft on <a
+ href="http://search.ietf.org/internet-drafts/draft-aboba-nat-ipsec-04.txt">IPsec
+ and NAT</a> which may eventually evolve into a standard solution for this
+ problem.</li>
+ <li>an informational <a
+ href="http://www.cis.ohio-state.edu/rfc/rfc2709.txt">RFC</a>,
+ <cite>Security Model with Tunnel-mode IPsec for NAT Domains</cite>.</li>
+ <li>an <a
+ href="http://www.cisco.com/warp/public/759/ipj_3-4/ipj_3-4_nat.html">article</a>
+ in Cisco's <cite>Internet Protocol Journal</cite></li>
+</ul>
+
+<h2><a name="complications">Other complications</a></h2>
+
+<p>Of course simply allowing UDP 500 and ESP packets is not the whole story.
+Various other issues arise in making IPsec and packet filters co-exist and
+even co-operate. Some of them are summarised below.</p>
+
+<h3><a name="through">IPsec <em>through</em></a> the gateway</h3>
+
+<p>Basic IPsec packet filtering rules deal only with packets addressed to or
+sent from your IPsec gateway.</p>
+
+<p>It is a separate policy decision whether to permit such packets to pass
+through the gateway so that client machines can build end-to-end IPsec
+tunnels of their own. This may not be practical if you are using <a
+href="#NAT">NAT (IP masquerade)</a> on your gateway, and may conflict with
+some corporate security policies.</p>
+
+<p>Where possible, allowing this is almost certainly a good idea. Using IPsec
+on an end-to-end basis is more secure than gateway-to-gateway.</p>
+
+<p>Doing it is quite simple. You just need firewall rules that allow UDP port
+500 and protocols 50 and 51 to pass through your gateway. If you wish, you
+can of course restrict this to certain hosts.</p>
+
+<h3><a name="ipsec_only">Preventing non-IPsec traffic</a></h3>
+You can also filter <em>everything but</em> UDP port 500 and ESP or AH to
+restrict traffic to IPsec only, either for anyone communicating with your
+host or just for specific partners.
+
+<p>One application of this is for the telecommuter who might have:</p>
+<pre> Sunset==========West------------------East ================= firewall --- the Internet
+ home network untrusted net corporate network</pre>
+
+<p>The subnet on the right is 0.0.0.0/0, the whole Internet. The West gateway
+is set up so that it allows only IPsec packets to East in or out.</p>
+
+<p>This configuration is used in AT&amp;T Research's network. For details,
+see the <a href="intro.html#applied">papers</a> links in our introduction.</p>
+
+<p>Another application would be to set up firewall rules so that an internal
+machine, such as an employees-only web server, could not talk to the outside
+world except via specific IPsec tunnels.</p>
+
+<h3><a name="unknowngate">Filtering packets from unknown gateways</a></h3>
+
+<p>It is possible to use firewall rules to restrict UDP 500, ESP and AH
+packets so that these packets are accepted only from known gateways. This is
+not strictly necessary since FreeS/WAN will discard packets from unknown
+gateways. You might, however, want to do it for any of a number of reasons.
+For example:</p>
+<ul>
+ <li>Arguably, "belt and suspenders" is the sensible approach to security.
+ If you can block a potential attack in two ways, use both. The only
+ question is whether to look for a third way after implementing the first
+ two.</li>
+ <li>Some admins may prefer to use the firewall code this way because they
+ prefer firewall logging to FreeS/WAN's logging.</li>
+ <li>You may need it to implement your security policy. Consider an employee
+ working at home, and a policy that says traffic from the home system to
+ the Internet at large must go first via IPsec to the corporate LAN and
+ then out to the Internet via the corporate firewall. One way to do that
+ is to make <var>ipsec0</var> the default route on the home gateway and
+ provide exceptions only for UDP 500 and ESP to the corporate gateway.
+ Everything else is then routed via the tunnel to the corporate
+ gateway.</li>
+</ul>
+
+<p>It is not possible to use only static firewall rules for this filtering if
+you do not know the other gateways' IP addresses in advance, for example if
+you have "road warriors" who may connect from a different address each time
+or if want to do <a href="glossary.html#carpediem">opportunistic
+encryption</a> to arbitrary gateways. In these cases, you can accept UDP 500
+IKE packets from anywhere, then use the <a href="#updown">updown</a> script
+feature of <a href="manpage.d/ipsec_pluto.8.html">pluto(8)</a> to dynamically
+adjust firewalling for each negotiated tunnel.</p>
+
+<p>Firewall packet filtering does not much reduce the risk of a <a
+href="glossary.html#DOS">denial of service attack</a> on FreeS/WAN. The
+firewall can drop packets from unknown gateways, but KLIPS does that quite
+efficiently anyway, so you gain little. The firewall cannot drop otherwise
+legitmate packets that fail KLIPS authentication, so it cannot protect
+against an attack designed to exhaust resources by making FreeS/WAN perform
+many expensive authentication operations.</p>
+
+<p>In summary, firewall filtering of IPsec packets from unknown gateways is
+possible but not strictly necessary.</p>
+
+<h2><a name="otherfilter">Other packet filters</a></h2>
+
+<p>When the IPsec gateway is also acting as your firewall, other packet
+filtering rules will be in play. In general, those are outside the scope of
+this document. See our <a href="web.html#firewall.linux">Linux firewall
+links</a> for information. There are a few types of packet, however, which
+can affect the operation of FreeS/WAN or of diagnostic tools commonly used
+with it. These are discussed below.</p>
+
+<h3><a name="ICMP">ICMP filtering</a></h3>
+
+<p><a href="glossary.html#ICMP.gloss">ICMP</a> is the
+<strong>I</strong>nternet <strong>C</strong>ontrol <strong>M</strong>essage
+<strong>P</strong>rotocol. It is used for messages between IP implementations
+themselves, whereas IP used is used between the clients of those
+implementations. ICMP is, unsurprisingly, used for control messages. For
+example, it is used to notify a sender that a desination is not reachable, or
+to tell a router to reroute certain packets elsewhere.</p>
+
+<p>ICMP handling is tricky for firewalls.</p>
+<ul>
+ <li>You definitely want some ICMP messages to get through; things won't
+ work without them. For example, your clients need to know if some
+ destination they ask for is unreachable.</li>
+ <li>On the other hand, you do equally definitely do not want untrusted folk
+ sending arbitrary control messages to your machines. Imagine what someone
+ moderately clever and moderately malicious could do to you, given control
+ of your network's routing.</li>
+</ul>
+
+<p>ICMP does not use ports. Messages are distinguished by a "message type"
+field and, for some types, by an additional "code" field. The definitive list
+of types and codes is on the <a href="http://www.iana.org">IANA</a> site.</p>
+
+<p>One expert uses this definition for ICMP message types to be dropped at
+the firewall.</p>
+<pre># ICMP types which lack socially redeeming value.
+# 5 Redirect
+# 9 Router Advertisement
+# 10 Router Selection
+# 15 Information Request
+# 16 Information Reply
+# 17 Address Mask Request
+# 18 Address Mask Reply
+
+badicmp='5 9 10 15 16 17 18'</pre>
+
+<p>A more conservative approach would be to make a list of allowed types and
+drop everything else.</p>
+
+<p>Whichever way you do it, your ICMP filtering rules on a FreeS/WAN gateway
+should allow at least the following ICMP packet types:</p>
+<dl>
+ <dt>echo (type 8)</dt>
+ <dd></dd>
+ <dt>echo reply (type 0)</dt>
+ <dd>These are used by ping(1). We recommend allowing both types through
+ the tunnel and to or from your gateway's external interface, since
+ ping(1) is an essential testing tool.
+ <p>It is fairly common for firewalls to drop ICMP echo packets
+ addressed to machines behind the firewall. If that is your policy,
+ please create an exception for such packets arriving via an IPsec
+ tunnel, at least during intial testing of those tunnels.</p>
+ </dd>
+ <dt>destination unreachable (type 3)</dt>
+ <dd>This is used, with code 4 (Fragmentation Needed and Don't Fragment
+ was Set) in the code field, to control <a
+ href="glossary.html#pathMTU">path MTU discovery</a>. Since IPsec
+ processing adds headers, enlarges packets and may cause fragmentation,
+ an IPsec gateway should be able to send and receive these ICMP messages
+ <strong>on both inside and outside interfaces</strong>.</dd>
+</dl>
+
+<h3><a name="traceroute">UDP packets for traceroute</a></h3>
+
+<p>The traceroute(1) utility uses UDP port numbers from 33434 to
+approximately 33633. Generally, these should be allowed through for
+troubleshooting.</p>
+
+<p>Some firewalls drop these packets to prevent outsiders exploring the
+protected network with traceroute(1). If that is your policy, consider
+creating an exception for such packets arriving via an IPsec tunnel, at least
+during intial testing of those tunnels.</p>
+
+<h3><a name="l2tp">UDP for L2TP</a></h3>
+<p>
+Windows 2000 does, and products designed for compatibility with it may, build
+<a href="glossary.html#L2TP">L2TP</a> tunnels over IPsec connections.
+
+<p>For this to work, you must allow UDP protocol 1701 packets coming out of
+your tunnels to continue to their destination. You can, and probably should,
+block such packets to or from your external interfaces, but allow them from
+<var>ipsec0</var>.</p>
+
+<p>See also our Windows 2000 <a href="interop.html#win2k">interoperation
+discussion</a>.</p>
+
+<h2><a name="packets">How it all works: IPsec packet details</a></h2>
+
+<p>IPsec uses three main types of packet:</p>
+<dl>
+ <dt><a href="glossary.html#IKE">IKE</a> uses <strong>the UDP protocol and
+ port 500</strong>.</dt>
+ <dd>Unless you are using only (less secure, not recommended) manual
+ keying, you need IKE to negotiate connection parameters, acceptable
+ algorithms, key sizes and key setup. IKE handles everything required to
+ set up, rekey, repair or tear down IPsec connections.</dd>
+ <dt><a href="glossary.html#ESP">ESP</a> is <strong>protocol number
+ 50</strong></dt>
+ <dd>This is required for encrypted connections.</dd>
+ <dt><a href="glossary.html#AH">AH</a> is <strong>protocol number
+ 51</strong></dt>
+ <dd>This can be used where only authentication, not encryption, is
+ required.</dd>
+</dl>
+
+<p>All of those packets should have appropriate IPsec gateway addresses in
+both the to and from IP header fields. Firewall rules can check this if you
+wish, though it is not strictly necessary. This is discussed in more detail
+<a href="#unknowngate">later</a>.</p>
+
+<p>IPsec processing of incoming packets authenticates them then removes the
+ESP or AH header and decrypts if necessary. Successful processing exposes an
+inner packet which is then delivered back to the firewall machinery, marked
+as having arrived on an <var>ipsec[0-3]</var> interface. Firewall rules can
+use that interface label to distinguish these packets from unencrypted
+packets which are labelled with the physical interface they arrived on (or
+perhaps with a non-IPsec virtual interface such as <var>ppp0</var>).</p>
+
+<p>One of our users sent a mailing list message with a <a
+href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00006.html">diagram</a>
+of the packet flow.</p>
+
+<h3><a name="noport">ESP and AH do not have ports</a></h3>
+
+<p>Some protocols, such as TCP and UDP, have the notion of ports. Others
+protocols, including ESP and AH, do not. Quite a few IPsec newcomers have
+become confused on this point. There are no ports <em>in</em> the ESP or AH
+protocols, and no ports used <em>for</em> them. For these protocols, <em>the
+idea of ports is completely irrelevant</em>.</p>
+
+<h3><a name="header">Header layout</a></h3>
+
+<p>The protocol numbers for ESP or AH are used in the 'next header' field of
+the IP header. On most non-IPsec packets, that field would have one of:</p>
+<ul>
+ <li>1 for ICMP</li>
+ <li>4 for IP-in-IP encapsulation</li>
+ <li>6 for TCP</li>
+ <li>17 for UDP</li>
+ <li>... or one of about 100 other possibilities listed by <a
+ href="http://www.iana.org">IANA</a></li>
+</ul>
+
+<p>Each header in the sequence tells what the next header will be. IPsec adds
+headers for ESP or AH near the beginning of the sequence. The original
+headers are kept and the 'next header' fields adjusted so that all headers
+can be correctly interpreted.</p>
+
+<p>For example, using <strong>[</strong> <strong>]</strong> to indicate data
+protected by ESP and unintelligible to an eavesdropper between the
+gateways:</p>
+<ul>
+ <li>a simple packet might have only IP and TCP headers with:
+ <ul>
+ <li>IP header says next header --&gt; TCP</li>
+ <li>TCP header port number --&gt; which process to send data to</li>
+ <li>data</li>
+ </ul>
+ </li>
+ <li>with ESP <a href="glossary.html#transport">transport mode</a>
+ encapsulation, that packet would have:
+ <ul>
+ <li>IP header says next header --&gt; ESP</li>
+ <li>ESP header <strong>[</strong> says next --&gt; TCP</li>
+ <li>TCP header port number --&gt; which process to send data to</li>
+ <li>data <strong>]</strong></li>
+ </ul>
+ Note that the IP header is outside ESP protection, visible to an
+ attacker, and that the final destination must be the gateway.</li>
+ <li>with ESP in <a href="glossary.html#tunnel">tunnel mode</a>, we might
+ have:
+ <ul>
+ <li>IP header says next header --&gt; ESP</li>
+ <li>ESP header <strong>[</strong> says next --&gt; IP</li>
+ <li>IP header says next header --&gt; TCP</li>
+ <li>TCP header port number --&gt; which process to send data to</li>
+ <li>data <strong>]</strong></li>
+ </ul>
+ Here the inner IP header is protected by ESP, unreadable by an attacker.
+ Also, the inner header can have a different IP address than the outer IP
+ header, so the decrypted packet can be routed from the IPsec gateway to a
+ final destination which may be another machine.</li>
+</ul>
+
+<p>Part of the ESP header itself is encrypted, which is why the
+<strong>[</strong> indicating protected data appears in the middle of some
+lines above. The next header field of the ESP header is protected. This makes
+<a href="glossary.html#traffic">traffic analysis</a> more difficult. The next
+header field would tell an eavesdropper whether your packet was UDP to the
+gateway, TCP to the gateway, or encapsulated IP. It is better not to give
+this information away. A clever attacker may deduce some of it from the
+pattern of packet sizes and timings, but we need not make it easy.</p>
+
+<p>IPsec allows various combinations of these to match local policies,
+including combinations that use both AH and ESP headers or that nest multiple
+copies of these headers.</p>
+
+<p>For example, suppose my employer has an IPsec VPN running between two
+offices so all packets travelling between the gateways for those offices are
+encrypted. If gateway policies allow it (The admins could block UDP 500 and
+protocols 50 and 51 to disallow it), I can build an IPsec tunnel from my
+desktop to a machine in some remote office. Those packets will have one ESP
+header throughout their life, for my end-to-end tunnel. For part of the
+route, however, they will also have another ESP layer for the corporate VPN's
+encapsulation. The whole header scheme for a packet on the Internet might
+be:</p>
+<ul>
+ <li>IP header (with gateway address) says next header --&gt; ESP</li>
+ <li>ESP header <strong>[</strong> says next --&gt; IP</li>
+ <li>IP header (with receiving machine address) says next header --&gt;
+ ESP</li>
+ <li>ESP header <strong>[</strong> says next --&gt; TCP</li>
+ <li>TCP header port number --&gt; which process to send data to</li>
+ <li>data <strong>]]</strong></li>
+</ul>
+
+<p>The first ESP (outermost) header is for the corporate VPN. The inner ESP
+header is for the secure machine-to-machine link.</p>
+
+<h3><a name="dhr">DHR on the updown script</a></h3>
+
+<p>Here are some mailing list comments from <a
+href="manpage.d/ipsec_pluto.8.html">pluto(8)</a> developer Hugh Redelmeier on
+an earlier draft of this document:</p>
+<pre>There are many important things left out
+
+- firewalling is important but must reflect (implement) policy. Since
+ policy isn't the same for all our customers, and we're not experts,
+ we should concentrate on FW and MASQ interactions with FreeS/WAN.
+
+- we need a diagram to show packet flow WITHIN ONE MACHINE, assuming
+ IKE, IPsec, FW, and MASQ are all done on that machine. The flow is
+ obvious if the components are run on different machines (trace the
+ cables).
+
+ IKE input:
+ + packet appears on public IF, as UDP port 500
+ + input firewalling rules are applied (may discard)
+ + Pluto sees the packet.
+
+ IKE output:
+ + Pluto generates the packet &amp; writes to public IF, UDP port 500
+ + output firewalling rules are applied (may discard)
+ + packet sent out public IF
+
+ IPsec input, with encapsulated packet, outer destination of this host:
+ + packet appears on public IF, protocol 50 or 51. If this
+ packet is the result of decapsulation, it will appear
+ instead on the paired ipsec IF.
+ + input firewalling rules are applied (but packet is opaque)
+ + KLIPS decapsulates it, writes result to paired ipsec IF
+ + input firewalling rules are applied to resulting packet
+ as input on ipsec IF
+ + if the destination of the packet is this machine, the
+ packet is passed on to the appropriate protocol handler.
+ If the original packet was encapsulated more than once
+ and the new outer destination is this machine, that
+ handler will be KLIPS.
+ + otherwise:
+ * routing is done for the resulting packet. This may well
+ direct it into KLIPS for encoding or encrypting. What
+ happens then is described elsewhere.
+ * forwarding firewalling rules are applied
+ * output firewalling rules are applied
+ * the packet is sent where routing specified
+
+ IPsec input, with encapsulated packet, outer destination of another host:
+ + packet appears on some IF, protocol 50 or 51
+ + input firewalling rules are applied (but packet is opaque)
+ + routing selects where to send the packet
+ + forwarding firewalling rules are applied (but packet is opaque)
+ + packet forwarded, still encapsulated
+
+ IPsec output, from this host or from a client:
+ + if from a client, input firewalling rules are applied as the
+ packet arrives on the private IF
+ + routing directs the packet to an ipsec IF (this is how the
+ system decides KLIPS processing is required)
+ + if from a client, forwarding firewalling rules are applied
+ + KLIPS eroute mechanism matches the source and destination
+ to registered eroutes, yielding a SPI group. This dictates
+ processing, and where the resulting packet is to be sent
+ (the destinations SG and the nexthop).
+ + output firewalling is not applied to the resulting
+ encapsulated packet
+
+- Until quite recently, KLIPS would double encapsulate packets that
+ didn't strictly need to be. Firewalling should be prepared for
+ those packets showing up as ESP and AH protocol input packets on
+ an ipsec IF.
+
+- MASQ processing seems to be done as if it were part of the
+ forwarding firewall processing (this should be verified).
+
+- If a firewall is being used, it is likely the case that it needs to
+ be adjusted whenever IPsec SAs are added or removed. Pluto invokes
+ a script to do this (and to adjust routing) at suitable times. The
+ default script is only suitable for ipfwadm-managed firewalls. Under
+ LINUX 2.2.x kernels, ipchains can be managed by ipfwadm (emulation),
+ but ipchains more powerful if manipulated using the ipchains command.
+ In this case, a custom updown script must be used.
+
+ We think that the flexibility of ipchains precludes us supplying an
+ updown script that would be widely appropriate.</pre>
+</body>
+</html>
diff --git a/doc/src/forwardingstate.txt b/doc/src/forwardingstate.txt
new file mode 100644
index 000000000..8853ac84e
--- /dev/null
+++ b/doc/src/forwardingstate.txt
@@ -0,0 +1,35 @@
+
+
+ .--------------.
+ | non-existant |
+ | policy |
+ `--------------'
+ |
+ | PF_ACQUIRE
+ |
+ |<---------.
+ V | new packet
+ .--------------. | (maybe resend PF_ACQUIRE)
+ | hold policy |--'
+ | |--.
+ `--------------' \ pass
+ | | \ msg .---------.
+ | | \ V | forward
+ | | .-------------. | packet
+ create | | | pass policy |--'
+ IPsec | | `-------------'
+ SA | |
+ | \
+ | \
+ V \ deny
+ .---------. \ msg
+ | encrypt | \
+ | policy | \ ,---------.
+ `---------' \ | | discard
+ \ V | packet
+ .-------------. |
+ | deny policy |--'
+ '-------------'
+
+
+$Id: forwardingstate.txt,v 1.1 2004/03/15 20:35:24 as Exp $
diff --git a/doc/src/glossary.html b/doc/src/glossary.html
new file mode 100644
index 000000000..38d0db7bb
--- /dev/null
+++ b/doc/src/glossary.html
@@ -0,0 +1,2257 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN glossary</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, glossary, cryptography">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: glossary.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="ourgloss">Glossary for the Linux FreeS/WAN project</a></h1>
+
+<p>Entries are in alphabetical order. Some entries are only one line or one
+paragraph long. Others run to several paragraphs. I have tried to put the
+essential information in the first paragraph so you can skip the other
+paragraphs if that seems appropriate.</p>
+<hr>
+
+<h2><a name="jump">Jump to a letter in the glossary</a></h2>
+
+<center>
+<big><b><a href="#0">numeric</a> <a href="#A">A</a> <a href="#B">B</a> <a
+href="#C">C</a> <a href="#D">D</a> <a href="#E">E</a> <a href="#F">F</a> <a
+href="#G">G</a> <a href="#H">H</a> <a href="#I">I</a> <a href="#J">J</a> <a
+href="#K">K</a> <a href="#L">L</a> <a href="#M">M</a> <a href="#N">N</a> <a
+href="#O">O</a> <a href="#P">P</a> <a href="#Q">Q</a> <a href="#R">R</a> <a
+href="#S">S</a> <a href="#T">T</a> <a href="#U">U</a> <a href="#V">V</a> <a
+href="#W">W</a> <a href="#X">X</a> <a href="#Y">Y</a> <a
+href="#Z">Z</a></b></big></center>
+<hr>
+
+<h2><a name="gloss">Other glossaries</a></h2>
+
+<p>Other glossaries which overlap this one include:</p>
+<ul>
+ <li>The VPN Consortium's glossary of <a
+ href="http://www.vpnc.org/terms.html">VPN terms</a>.</li>
+ <li>glossary portion of the <a
+ href="http://www.rsa.com/rsalabs/faq/B.html">Cryptography FAQ</a></li>
+ <li>an extensive crytographic glossary on <a
+ href="http://www.ciphersbyritter.com/GLOSSARY.HTM">Terry Ritter's</a>
+ page.</li>
+ <li>The <a href="#NSA">NSA</a>'s <a
+ href="http://www.sans.org/newlook/resources/glossary.htm">glossary of
+ computer security</a> on the <a href="http://www.sans.org">SANS
+ Institute</a> site.</li>
+ <li>a small glossary for Internet Security at <a
+ href="http://www5.zdnet.com/pcmag/pctech/content/special/glossaries/internetsecurity.html">
+ PC magazine</a></li>
+ <li>The <a
+ href="http://www.visi.com/crypto/inet-crypto/glossary.html">glossary</a>
+ from Richard Smith's book <a href="#Smith">Internet Cryptography</a></li>
+</ul>
+
+<p>Several Internet glossaries are available as RFCs:</p>
+<ul>
+ <li><a href="http://www.rfc-editor.org/rfc/rfc1208.txt">Glossary of
+ Networking Terms</a></li>
+ <li><a href="http://www.rfc-editor.org/rfc/rfc1983.txt">Internet User's
+ Glossary</a></li>
+ <li><a href="http://www.rfc-editor.org/rfc/rfc2828.txt">Internet Security
+ Glossary</a></li>
+</ul>
+
+<p>More general glossary or dictionary information:</p>
+<ul>
+ <li>Free Online Dictionary of Computing (FOLDOC)
+ <ul>
+ <li><a href="http://www.nightflight.com/foldoc">North America</a></li>
+ <li><a
+ href="http://wombat.doc.ic.ac.uk/foldoc/index.html">Europe</a></li>
+ <li><a href="http://www.nue.org/foldoc/index.html">Japan</a></li>
+ </ul>
+ <p>There are many more mirrors of this dictionary.</p>
+ </li>
+ <li>The Jargon File, the definitive resource for hacker slang and folklore
+ <ul>
+ <li><a href="http://www.netmeg.net/jargon">North America</a></li>
+ <li><a href="http://info.wins.uva.nl/~mes/jargon/">Holland</a></li>
+ <li><a href="http://www.tuxedo.org/~esr/jargon">home page</a></li>
+ </ul>
+ <p>There are also many mirrors of this. See the home page for a list.</p>
+ </li>
+ <li>A general <a
+ href="http://www.trinity.edu/~rjensen/245glosf.htm#Navigate"> technology
+ glossary</a></li>
+ <li>An <a href="http://www.yourdictionary.com/">online dictionary resource
+ page</a> with pointers to many dictionaries for many languages</li>
+ <li>A <a href="http://www.onelook.com/">search engine</a> that accesses
+ several hundred online dictionaries</li>
+ <li>O'Reilly <a href="http://www.ora.com/reference/dictionary/">Dictionary
+ of PC Hardware and Data Communications Terms</a></li>
+ <li><a href="http://www.FreeSoft.org/CIE/index.htm">Connected</a> Internet
+ encyclopedia</li>
+ <li><a href="http://www.whatis.com/">whatis.com</a></li>
+</ul>
+<hr>
+
+<h2><a name="definitions">Definitions</a></h2>
+<dl>
+ <dt><a name="0">0</a></dt>
+ <dt><a name="3DES">3DES (Triple DES)</a></dt>
+ <dd>Using three <a href="#DES">DES</a> encryptions on a single data
+ block, with at least two different keys, to get higher security than is
+ available from a single DES pass. The three-key version of 3DES is the
+ default encryption algorithm for <a href="#FreeSWAN">Linux
+ FreeS/WAN</a>.
+ <p><a href="#IPSEC">IPsec</a> always does 3DES with three different
+ keys, as required by RFC 2451. For an explanation of the two-key
+ variant, see <a href="#2key">two key triple DES</a>. Both use an <a
+ href="#EDE">EDE</a> encrypt-decrypt-encrpyt sequence of operations.</p>
+ <p>Single <a href="#DES">DES</a> is <a
+ href="politics.html#desnotsecure">insecure</a>.</p>
+ <p>Double DES is ineffective. Using two 56-bit keys, one might expect
+ an attacker to have to do 2<sup>112</sup> work to break it. In fact,
+ only 2<sup>57</sup> work is required with a <a
+ href="#meet">meet-in-the-middle attack</a>, though a large amount of
+ memory is also required. Triple DES is vulnerable to a similar attack,
+ but that just reduces the work factor from the 2<sup>168</sup> one
+ might expect to 2<sup>112</sup>. That provides adequate protection
+ against <a href="#brute">brute force</a> attacks, and no better attack
+ is known.</p>
+ <p>3DES can be somewhat slow compared to other ciphers. It requires
+ three DES encryptions per block. DES was designed for hardware
+ implementation and includes some operations which are difficult in
+ software. However, the speed we get is quite acceptable for many uses.
+ See our <a href="performance.html">performance</a> document for
+ details.</p>
+ </dd>
+ <dt><a name="A">A</a></dt>
+ <dt><a name="active">Active attack</a></dt>
+ <dd>An attack in which the attacker does not merely eavesdrop (see <a
+ href="#passive">passive attack</a>) but takes action to change, delete,
+ reroute, add, forge or divert data. Perhaps the best-known active
+ attack is <a href="#middle">man-in-the-middle</a>. In general, <a
+ href="#authentication">authentication</a> is a useful defense against
+ active attacks.</dd>
+ <dt><a name="AES">AES</a></dt>
+ <dd>The <b>A</b>dvanced <b>E</b>ncryption <b>S</b>tandard -- a new <a
+ href="#block">block cipher</a> standard to replace <a
+ href="politics.html#desnotsecure">DES</a> -- developed by <a
+ href="#NIST">NIST</a>, the US National Institute of Standards and
+ Technology. DES used 64-bit blocks and a 56-bit key. AES ciphers use a
+ 128-bit block and 128, 192 or 256-bit keys. The larger block size helps
+ resist <a href="#birthday">birthday attacks</a> while the large key
+ size prevents <a href="#brute">brute force attacks</a>.
+ <p>Fifteen proposals meeting NIST's basic criteria were submitted in
+ 1998 and subjected to intense discussion and analysis, "round one"
+ evaluation. In August 1999, NIST narrowed the field to five "round two"
+ candidates:</p>
+ <ul>
+ <li><a href="http://www.research.ibm.com/security/mars.html">Mars</a>
+ from IBM</li>
+ <li><a href="http://www.rsa.com/rsalabs/aes/">RC6</a> from RSA</li>
+ <li><a
+ href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">Rijndael</a>
+ from two Belgian researchers</li>
+ <li><a
+ href="http://www.cl.cam.ac.uk/~rja14/serpent.html">Serpent</a>, a
+ British-Norwegian-Israeli collaboration</li>
+ <li><a href="http://www.counterpane.com/twofish.html">Twofish</a>
+ from the consulting firm <a
+ href="http://www.counterpane.com">Counterpane</a></li>
+ </ul>
+ <p>Three of the five finalists -- Rijndael, Serpent and Twofish -- have
+ completely open licenses.</p>
+ <p>In October 2000, NIST announced the winner -- Rijndael.</p>
+ <p>For more information, see:</p>
+ <ul>
+ <li>NIST's <a
+ href="http://csrc.nist.gov/encryption/aes/aes_home.htm">AES home
+ page</a></li>
+ <li>the Block Cipher Lounge <a
+ href="http://www.ii.uib.no/~larsr/aes.html">AES page</a></li>
+ <li>Brian Gladman's <a
+ href="http://fp.gladman.plus.com/cryptography_technology/index.htm">code
+ and benchmarks</a></li>
+ <li>Helger Lipmaa's <a
+ href="http://www.tcs.hut.fi/~helger/aes/">survey of
+ implementations</a></li>
+ </ul>
+ <p>AES will be added to a future release of <a href="#FreeSWAN">Linux
+ FreeS/WAN</a>. Likely we will add all three of the finalists with good
+ licenses. User-written <a href="web.html#patch">AES patches</a> are
+ already available.</p>
+ <p>Adding AES may also require adding stronger hashes, <a
+ href="#SHA-256">SHA-256, SHA-384 and SHA-512</a>.</p>
+ </dd>
+ <dt><a name="AH">AH</a></dt>
+ <dd>The <a href="#IPSEC">IPsec</a> <b>A</b>uthentication <b>H</b>eader,
+ added after the IP header. For details, see our <a
+ href="ipsec.html#AH.ipsec">IPsec</a> document and/or RFC 2402.</dd>
+ <dt><a name="alicebob">Alice and Bob</a></dt>
+ <dd>A and B, the standard example users in writing on cryptography and
+ coding theory. Carol and Dave join them for protocols which require
+ more players.
+ <p>Bruce Schneier extends these with many others such as Eve the
+ Eavesdropper and Victor the Verifier. His extensions seem to be in the
+ process of becoming standard as well. See page 23 of <a
+ href="biblio.html#schneier">Applied Cryptography</a></p>
+ <p>Alice and Bob have an amusing <a
+ href="http://www.conceptlabs.co.uk/alicebob.html"> biography</a> on the
+ web.</p>
+ </dd>
+ <dt>ARPA</dt>
+ <dd>see <a href="#DARPA">DARPA</a></dd>
+ <dt><a name="ASIO">ASIO</a></dt>
+ <dd>Australian Security Intelligence Organisation.</dd>
+ <dt>Asymmetric cryptography</dt>
+ <dd>See <a href="#public">public key cryptography</a>.</dd>
+ <dt><a name="authentication">Authentication</a></dt>
+ <dd>Ensuring that a message originated from the expected sender and has
+ not been altered on route. <a href="#IPSEC">IPsec</a> uses
+ authentication in two places:
+ <ul>
+ <li>peer authentication, authenticating the players in <a
+ href="#IKE">IKE</a>'s <a href="#DH">Diffie-Hellman</a> key
+ exchanges to prevent <a href="#middle">man-in-the-middle
+ attacks</a>. This can be done in a number of ways. The methods
+ supported by FreeS/WAN are discussed in our <a
+ href="adv_config.html#choose">advanced configuration</a>
+ document.</li>
+ <li>packet authentication, authenticating packets on an established
+ <a href="#SA">SA</a>, either with a separate <a
+ href="#AH">authentication header</a> or with the optional
+ authentication in the <a href="#ESP">ESP</a> protocol. In either
+ case, packet authentication uses a <a href="#HMAC">hashed message
+ athentication code</a> technique.</li>
+ </ul>
+ <p>Outside IPsec, passwords are perhaps the most common authentication
+ mechanism. Their function is essentially to authenticate the person's
+ identity to the system. Passwords are generally only as secure as the
+ network they travel over. If you send a cleartext password over a
+ tapped phone line or over a network with a packet sniffer on it, the
+ security provided by that password becomes zero. Sending an encrypted
+ password is no better; the attacker merely records it and reuses it at
+ his convenience. This is called a <a href="#replay">replay</a>
+ attack.</p>
+ <p>A common solution to this problem is a <a
+ href="#challenge">challenge-response</a> system. This defeats simple
+ eavesdropping and replay attacks. Of course an attacker might still try
+ to break the cryptographic algorithm used, or the <a
+ href="#random">random number</a> generator.</p>
+ </dd>
+ <dt><a name="auto">Automatic keying</a></dt>
+ <dd>A mode in which keys are automatically generated at connection
+ establisment and new keys automaically created periodically thereafter.
+ Contrast with <a href="#manual">manual keying</a> in which a single
+ stored key is used.
+ <p>IPsec uses the <a href="#DH">Diffie-Hellman key exchange
+ protocol</a> to create keys. An <a
+ href="#authentication">authentication</a> mechansim is required for
+ this. FreeS/WAN normally uses <a href="#RSA">RSA</a> for this. Other
+ methods supported are discussed in our <a
+ href="adv_config.html#choose">advanced configuration</a> document.</p>
+ <p>Having an attacker break the authentication is emphatically not a
+ good idea. An attacker that breaks authentication, and manages to
+ subvert some other network entities (DNS, routers or gateways), can use
+ a <a href="#middle">man-in-the middle attack</a> to break the security
+ of your IPsec connections.</p>
+ <p>However, having an attacker break the authentication in automatic
+ keying is not quite as bad as losing the key in manual keying.</p>
+ <ul>
+ <li>An attacker who reads /etc/ipsec.conf and gets the keys for a
+ manually keyed connection can, without further effort, read all
+ messages encrypted with those keys, including any old messages he
+ may have archived.</li>
+ <li>Automatic keying has a property called <a href="#PFS">perfect
+ forward secrecy</a>. An attacker who breaks the authentication gets
+ none of the automatically generated keys and cannot immediately
+ read any messages. He has to mount a successful <a
+ href="#middle">man-in-the-middle attack</a> in real time before he
+ can read anything. He cannot read old archived messages at all and
+ will not be able to read any future messages not caught by
+ man-in-the-middle tricks.</li>
+ </ul>
+ <p>That said, the secrets used for authentication, stored in <a
+ href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</a>, should
+ still be protected as tightly as cryptographic keys.</p>
+ </dd>
+ <dt><a name="B">B</a></dt>
+ <dt><a href="http://www.nortelnetworks.com">Bay Networks</a></dt>
+ <dd>A vendor of routers, hubs and related products, now a subsidiary of
+ Nortel. Interoperation between their IPsec products and Linux FreeS/WAN
+ was problematic at last report; see our <a
+ href="interop.html#bay">interoperation</a> section.</dd>
+ <dt><a name="benchmarks">benchmarks</a></dt>
+ <dd>Our default block cipher, <a href="#3DES">triple DES</a>, is slower
+ than many alternate ciphers that might be used. Speeds achieved,
+ however, seem adequate for many purposes. For example, the assembler
+ code from the <a href="#LIBDES">LIBDES</a> library we use encrypts 1.6
+ megabytes per second on a Pentium 200, according to the test program
+ supplied with the library.
+ <p>For more detail, see our document on <a
+ href="performance.html">FreeS/WAN performance</a>.</p>
+ </dd>
+ <dt><a name="BIND">BIND</a></dt>
+ <dd><b>B</b>erkeley <b>I</b>nternet <b>N</b>ame <b>D</b>aemon, a widely
+ used implementation of <a href="#DNS">DNS</a> (Domain Name Service).
+ See our bibliography for a <a href="#DNS">useful reference</a>. See the
+ <a href="http://www.isc.org/bind.html">BIND home page</a> for more
+ information and the latest version.</dd>
+ <dt><a name="birthday">Birthday attack</a></dt>
+ <dd>A cryptographic attack based on the mathematics exemplified by the <a
+ href="#paradox">birthday paradox</a>. This math turns up whenever the
+ question of two cryptographic operations producing the same result
+ becomes an issue:
+ <ul>
+ <li><a href="#collision">collisions</a> in <a href="#digest">message
+ digest</a> functions.</li>
+ <li>identical output blocks from a <a href="#block">block
+ cipher</a></li>
+ <li>repetition of a challenge in a <a
+ href="#challenge">challenge-response</a> system</li>
+ </ul>
+ <p>Resisting such attacks is part of the motivation for:</p>
+ <ul>
+ <li>hash algorithms such as <a href="#SHA">SHA</a> and <a
+ href="#RIPEMD">RIPEMD-160</a> giving a 160-bit result rather than
+ the 128 bits of <a href="#MD4">MD4</a>, <a href="#MD5">MD5</a> and
+ <a href="#RIPEMD">RIPEMD-128</a>.</li>
+ <li><a href="#AES">AES</a> block ciphers using a 128-bit block
+ instead of the 64-bit block of most current ciphers</li>
+ <li><a href="#IPSEC">IPsec</a> using a 32-bit counter for packets
+ sent on an <a href="#auto">automatically keyed</a> <a
+ href="#SA">SA</a> and requiring that the connection always be
+ rekeyed before the counter overflows.</li>
+ </ul>
+ </dd>
+ <dt><a name="paradox">Birthday paradox</a></dt>
+ <dd>Not really a paradox, just a rather counter-intuitive mathematical
+ fact. In a group of 23 people, the chance of a least one pair having
+ the same birthday is over 50%.
+ <p>The second person has 1 chance in 365 (ignoring leap years) of
+ matching the first. If they don't match, the third person's chances of
+ matching one of them are 2/365. The 4th, 3/365, and so on. The total of
+ these chances grows more quickly than one might guess.</p>
+ </dd>
+ <dt><a name="block">Block cipher</a></dt>
+ <dd>A <a href="#symmetric">symmetric cipher</a> which operates on
+ fixed-size blocks of plaintext, giving a block of ciphertext for each.
+ Contrast with <a href="#stream"> stream cipher</a>. Block ciphers can
+ be used in various <a href="#mode">modes</a> when multiple block are to
+ be encrypted.
+ <p><a href="#DES">DES</a> is among the the best known and widely used
+ block ciphers, but is now obsolete. Its 56-bit key size makes it <a
+ href="#desnotsecure">highly insecure</a> today. <a href="#3DES">Triple
+ DES</a> is the default block cipher for <a href="#FreeSWAN">Linux
+ FreeS/WAN</a>.</p>
+ <p>The current generation of block ciphers -- such as <a
+ href="#Blowfish">Blowfish</a>, <a href="#CAST128">CAST-128</a> and <a
+ href="#IDEA">IDEA</a> -- all use 64-bit blocks and 128-bit keys. The
+ next generation, <a href="#AES">AES</a>, uses 128-bit blocks and
+ supports key sizes up to 256 bits.</p>
+ <p>The <a href="http://www.ii.uib.no/~larsr/bc.html"> Block Cipher
+ Lounge</a> web site has more information.</p>
+ </dd>
+ <dt><a name="Blowfish">Blowfish</a></dt>
+ <dd>A <a href="#block">block cipher</a> using 64-bit blocks and keys of
+ up to 448 bits, designed by <a href="#schneier">Bruce Schneier</a> and
+ used in several products.
+ <p>This is not required by the <a href="#IPSEC">IPsec</a> RFCs and not
+ currently used in <a href="#FreeSWAN">Linux FreeS/WAN</a>.</p>
+ </dd>
+ <dt><a name="brute">Brute force attack (exhaustive search)</a></dt>
+ <dd>Breaking a cipher by trying all possible keys. This is always
+ possible in theory (except against a <a href="#OTP">one-time pad</a>),
+ but it becomes practical only if the key size is inadequate. For an
+ important example, see our document on the <a
+ href="#desnotsecure">insecurity of DES</a> with its 56-bit key. For an
+ analysis of key sizes required to resist plausible brute force attacks,
+ see <a href="http://www.counterpane.com/keylength.html">this paper</a>.
+ <p>Longer keys protect against brute force attacks. Each extra bit in
+ the key doubles the number of possible keys and therefore doubles the
+ work a brute force attack must do. A large enough key defeats
+ <strong>any</strong> brute force attack.</p>
+ <p>For example, the EFF's <a href="#EFF">DES Cracker</a> searches a
+ 56-bit key space in an average of a few days. Let us assume an attacker
+ that can find a 64-bit key (256 times harder) by brute force search in
+ a second (a few hundred thousand times faster). For a 96-bit key, that
+ attacker needs 2<sup>32</sup> seconds, about 135 years. Against a
+ 128-bit key, he needs 2<sup>32</sup> times that, over 500,000,000,000
+ years. Your data is then obviously secure against brute force attacks.
+ Even if our estimate of the attacker's speed is off by a factor of a
+ million, it still takes him over 500,000 years to crack a message.</p>
+ <p>This is why</p>
+ <ul>
+ <li>single <a href="#DES">DES</a> is now considered <a
+ href="#desnotsecure">dangerously insecure</a></li>
+ <li>all of the current generation of <a href="#block">block
+ ciphers</a> use a 128-bit or longer key</li>
+ <li><a href="#AES">AES</a> ciphers support keysizes 128, 192 and 256
+ bits</li>
+ <li>any cipher we add to Linux FreeS/WAN will have <em>at least</em>
+ a 128-bit key</li>
+ </ul>
+ <p><strong>Cautions:</strong><br>
+ <em>Inadequate keylength always indicates a weak cipher</em> but it is
+ important to note that <em>adequate keylength does not necessarily
+ indicate a strong cipher</em>. There are many attacks other than brute
+ force, and adequate keylength <em>only</em> guarantees resistance to
+ brute force. Any cipher, whatever its key size, will be weak if design
+ or implementation flaws allow other attacks.</p>
+ <p>Also, <em>once you have adequate keylength</em> (somewhere around 90
+ or 100 bits), <em>adding more key bits make no practical
+ difference</em>, even against brute force. Consider our 128-bit example
+ above that takes 500,000,000,000 years to break by brute force. We
+ really don't care how many zeroes there are on the end of that, as long
+ as the number remains ridiculously large. That is, we don't care
+ exactly how large the key is as long as it is large enough.</p>
+ <p>There may be reasons of convenience in the design of the cipher to
+ support larger keys. For example <a href="#Blowfish">Blowfish</a>
+ allows up to 448 bits and <a href="#RC4">RC4</a> up to 2048, but beyond
+ 100-odd bits it makes no difference to practical security.</p>
+ </dd>
+ <dt>Bureau of Export Administration</dt>
+ <dd>see <a href="#BXA">BXA</a></dd>
+ <dt><a name="BXA">BXA</a></dt>
+ <dd>The US Commerce Department's <b>B</b>ureau of E<b>x</b>port
+ <b>A</b>dministration which administers the <a href="#EAR">EAR</a>
+ Export Administration Regulations controling the export of, among other
+ things, cryptography.</dd>
+ <dt><a name="C">C</a></dt>
+ <dt><a name="CA">CA</a></dt>
+ <dd><b>C</b>ertification <b>A</b>uthority, an entity in a <a
+ href="#PKI">public key infrastructure</a> that can certify keys by
+ signing them. Usually CAs form a hierarchy. The top of this hierarchy
+ is called the <a href="#rootCA">root CA</a>.
+ <p>See <a href="#web">Web of Trust</a> for an alternate model.</p>
+ </dd>
+ <dt><a name="CAST128">CAST-128</a></dt>
+ <dd>A <a href="#block">block cipher</a> using 64-bit blocks and 128-bit
+ keys, described in RFC 2144 and used in products such as <a
+ href="#Entrust">Entrust</a> and recent versions of <a
+ href="#PGP">PGP</a>.
+ <p>This is not required by the <a href="#IPSEC">IPsec</a> RFCs and not
+ currently used in <a href="#FreeSWAN">Linux FreeS/WAN</a>.</p>
+ </dd>
+ <dt>CAST-256</dt>
+ <dd><a href="#Entrust">Entrust</a>'s candidate cipher for the <a
+ href="#AES">AES standard</a>, largely based on the <a
+ href="#CAST128">CAST-128</a> design.</dd>
+ <dt><a name="CBC">CBC mode</a></dt>
+ <dd><b>C</b>ipher <b>B</b>lock <b>C</b>haining <a href="#mode">mode</a>,
+ a method of using a <a href="#block">block cipher</a> in which for each
+ block except the first, the result of the previous encryption is XORed
+ into the new block before it is encrypted. CBC is the mode used in <a
+ href="#IPSEC">IPsec</a>.
+ <p>An <a href="#IV">initialisation vector</a> (IV) must be provided. It
+ is XORed into the first block before encryption. The IV need not be
+ secret but should be different for each message and unpredictable.</p>
+ </dd>
+ <dt><a name="CIDR">CIDR</a></dt>
+ <dd><b>C</b>lassless <b>I</b>nter-<b>D</b>omain <b>R</b>outing,
+ an addressing scheme used to describe networks not
+ restricted to the old Class A, B, and C sizes.
+ A CIDR block is written
+ <VAR>address</VAR>/<VAR>mask</VAR>, where <VAR>address</VAR> is
+ a 32-bit Internet address.
+ The first <VAR>mask</VAR> bits of <VAR>address</VAR>
+ are part of the gateway address, while the remaining bits designate
+ other host addresses.
+ For example, the CIDR block 192.0.2.96/27 describes a network with
+ gateway
+ 192.0.2.96, hosts 192.0.2.96 through 192.0.2.126 and broadcast
+ 192.0.2.127.
+ <p>FreeS/WAN policy group files accept CIDR blocks of the format
+ <VAR>address</VAR>/[<VAR>mask</VAR>], where <VAR>address</VAR> may
+ take the form <VAR>name.domain.tld</VAR>. An absent <VAR>mask</VAR>
+ is assumed to be /32.
+ </p>
+ </dd>
+
+ <dt>Certification Authority</dt>
+ <dd>see <a href="#CA">CA</a></dd>
+ <dt><a name="challenge">Challenge-response authentication</a></dt>
+ <dd>An <a href="#authentication">authentication</a> system in which one
+ player generates a <a href="#random">random number</a>, encrypts it and
+ sends the result as a challenge. The other player decrypts and sends
+ back the result. If the result is correct, that proves to the first
+ player that the second player knew the appropriate secret, required for
+ the decryption. Variations on this technique exist using <a
+ href="#public">public key</a> or <a href="#symmetric">symmetric</a>
+ cryptography. Some provide two-way authentication, assuring each player
+ of the other's identity.
+ <p>This is more secure than passwords against two simple attacks:</p>
+ <ul>
+ <li>If cleartext passwords are sent across the wire (e.g. for
+ telnet), an eavesdropper can grab them. The attacker may even be
+ able to break into other systems if the user has chosen the same
+ password for them.</li>
+ <li>If an encrypted password is sent, an attacker can record the
+ encrypted form and use it later. This is called a replay
+ attack.</li>
+ </ul>
+ <p>A challenge-response system never sends a password, either cleartext
+ or encrypted. An attacker cannot record the response to one challenge
+ and use it as a response to a later challenge. The random number is
+ different each time.</p>
+ <p>Of course an attacker might still try to break the cryptographic
+ algorithm used, or the <a href="#random">random number</a>
+ generator.</p>
+ </dd>
+ <dt><a name="mode">Cipher Modes</a></dt>
+ <dd>Different ways of using a block cipher when encrypting multiple
+ blocks.
+ <p>Four standard modes were defined for <a href="#DES">DES</a> in <a
+ href="#FIPS">FIPS</a> 81. They can actually be applied with any block
+ cipher.</p>
+
+ <table>
+ <tbody>
+ <tr>
+ <td></td>
+ <td><a href="#ECB">ECB</a></td>
+ <td>Electronic CodeBook</td>
+ <td>encrypt each block independently</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td><a href="#CBC">CBC</a></td>
+ <td>Cipher Block Chaining<br>
+ </td>
+ <td>XOR previous block ciphertext into new block plaintext before
+ encrypting new block</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>CFB</td>
+ <td>Cipher FeedBack</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>OFB</td>
+ <td>Output FeedBack</td>
+ <td></td>
+ </tr>
+ </tbody>
+ </table>
+ <p><a href="#IPSEC">IPsec</a> uses <a href="#CBC">CBC</a> mode since
+ this is only marginally slower than <a href="#ECB">ECB</a> and is more
+ secure. In ECB mode the same plaintext always encrypts to the same
+ ciphertext, unless the key is changed. In CBC mode, this does not
+ occur.</p>
+ <p>Various other modes are also possible, but none of them are used in
+ IPsec.</p>
+ </dd>
+ <dt><a name="ciphertext">Ciphertext</a></dt>
+ <dd>The encrypted output of a cipher, as opposed to the unencrypted <a
+ href="#plaintext">plaintext</a> input.</dd>
+ <dt><a href="http://www.cisco.com">Cisco</a></dt>
+ <dd>A vendor of routers, hubs and related products. Their IPsec products
+ interoperate with Linux FreeS/WAN; see our <a
+ href="interop.html#Cisco">interop</a> section.</dd>
+ <dt><a name="client">Client</a></dt>
+ <dd>This term has at least two distinct uses in discussing IPsec:
+ <ul>
+ <li>The <strong>clients of an IPsec gateway</strong> are the machines
+ it protects, typically on one or more subnets behind the gateway.
+ In this usage, all the machines on an office network are clients of
+ that office's IPsec gateway. Laptop or home machines connecting to
+ the office, however, are <em>not</em> clients of that gateway. They
+ are remote gateways, running the other end of an IPsec connection.
+ Each of them is also its own client.</li>
+ <li><strong>IPsec client software</strong> is used to describe
+ software which runs on various standalone machines to let them
+ connect to IPsec networks. In this usage, a laptop or home machine
+ connecting to the office is a client, and the office gateway is the
+ server.</li>
+ </ul>
+ <p>We generally use the term in the first sense. Vendors of Windows
+ IPsec solutions often use it in the second. See this <a
+ href="interop.html#client.server">discussion</a>.</p>
+ </dd>
+ <dt><a name="cc">Common Criteria</a></dt>
+ <dd>A set of international security classifications which are replacing
+ the old US <a href="#rainbow">Rainbow Book</a> standards and similar
+ standards in other countries.
+ <p>Web references include this <a href="http://csrc.nist.gov/cc">US
+ government site</a> and this <a
+ href="http://www.commoncriteria.org">global home page</a>.</p>
+ </dd>
+ <dt>Conventional cryptography</dt>
+ <dd>See <a href="#symmetric">symmetric cryptography</a></dd>
+ <dt><a name="collision">Collision resistance</a></dt>
+ <dd>The property of a <a href="#digest">message digest</a> algorithm
+ which makes it hard for an attacker to find or construct two inputs
+ which hash to the same output.</dd>
+ <dt>Copyleft</dt>
+ <dd>see GNU <a href="#GPL">General Public License</a></dd>
+ <dt><a name="CSE">CSE</a></dt>
+ <dd><a href="http://www.cse-cst.gc.ca/">Communications Security
+ Establishment</a>, the Canadian organisation for <a
+ href="#SIGINT">signals intelligence</a>.</dd>
+ <dt><a name="D">D</a></dt>
+ <dt><a name="DARPA">DARPA (sometimes just ARPA)</a></dt>
+ <dd>The US government's <b>D</b>efense <b>A</b>dvanced <b>R</b>esearch
+ <b>P</b>rojects <b>A</b>gency. Projects they have funded over the years
+ have included the Arpanet which evolved into the Internet, the TCP/IP
+ protocol suite (as a replacement for the original Arpanet suite), the
+ Berkeley 4.x BSD Unix projects, and <a href="#SDNS">Secure DNS</a>.
+ <p>For current information, see their <a
+ href="http://www.darpa.mil/ito">web site</a>.</p>
+ </dd>
+ <dt><a name="DOS">Denial of service (DoS) attack</a></dt>
+ <dd>An attack that aims at denying some service to legitimate users of a
+ system, rather than providing a service to the attacker.
+ <ul>
+ <li>One variant is a flooding attack, overwhelming the system with
+ too many packets, to much email, or whatever.</li>
+ <li>A closely related variant is a resource exhaustion attack. For
+ example, consider a "TCP SYN flood" attack. Setting up a TCP
+ connection involves a three-packet exchange:
+ <ul>
+ <li>Initiator: Connection please (SYN)</li>
+ <li>Responder: OK (ACK)</li>
+ <li>Initiator: OK here too</li>
+ </ul>
+ <p>If the attacker puts bogus source information in the first
+ packet, such that the second is never delivered, the responder may
+ wait a long time for the third to come back. If responder has
+ already allocated memory for the connection data structures, and if
+ many of these bogus packets arrive, the responder may run out of
+ memory.</p>
+ </li>
+ <li>Another variant is to feed the system undigestible data, hoping
+ to make it sick. For example, IP packets are limited in size to 64K
+ bytes and a fragment carries information on where it starts within
+ that 64K and how long it is. The "ping of death" delivers fragments
+ that say, for example, that they start at 60K and are 20K long.
+ Attempting to re-assemble these without checking for overflow can
+ be fatal.</li>
+ </ul>
+ <p>The two example attacks discussed were both quite effective when
+ first discovered, capable of crashing or disabling many operating
+ systems. They were also well-publicised, and today far fewer systems
+ are vulnerable to them.</p>
+ </dd>
+ <dt><a name="DES">DES</a></dt>
+ <dd>The <b>D</b>ata <b>E</b>ncryption <b>S</b>tandard, a <a
+ href="#block">block cipher</a> with 64-bit blocks and a 56-bit key.
+ Probably the most widely used <a href="#symmetric">symmetric cipher</a>
+ ever devised. DES has been a US government standard for their own use
+ (only for unclassified data), and for some regulated industries such as
+ banking, since the late 70's. It is now being replaced by <a
+ href="#AES">AES</a>.
+ <p><a href="politics.html#desnotsecure">DES is seriously insecure
+ against current attacks.</a></p>
+ <p><a href="#FreeSWAN">Linux FreeS/WAN</a> does not include DES, even
+ though the RFCs specify it. <b>We strongly recommend that single DES
+ not be used.</b></p>
+ <p>See also <a href="#3DES">3DES</a> and <a href="#DESX">DESX</a>,
+ stronger ciphers based on DES.</p>
+ </dd>
+ <dt><a name="DESX">DESX</a></dt>
+ <dd>An improved <a href="#DES">DES</a> suggested by Ron Rivest of RSA
+ Data Security. It XORs extra key material into the text before and
+ after applying the DES cipher.
+ <p>This is not required by the <a href="#IPSEC">IPsec</a> RFCs and not
+ currently used in <a href="#FreeSWAN">Linux FreeS/WAN</a>. DESX would
+ be the easiest additional transform to add; there would be very little
+ code to write. It would be much faster than 3DES and almost certainly
+ more secure than DES. However, since it is not in the RFCs other IPsec
+ implementations cannot be expected to have it.</p>
+ </dd>
+ <dt>DH</dt>
+ <dd>see <a href="#DH">Diffie-Hellman</a></dd>
+ <dt><a name="DHCP">DHCP</a></dt>
+ <dd><strong>D</strong>ynamic <strong>H</strong>ost
+ <strong>C</strong>onfiguration <strong>P</strong>rotocol, a method of
+ assigning <a href="#dynamic">dynamic IP addresses</a>, and providing
+ additional information such as addresses of DNS servers and of
+ gateways. See this <a href="http://www.dhcp.org">DHCP resource
+ page.</a></dd>
+ <dt><a name="DH">Diffie-Hellman (DH) key exchange protocol</a></dt>
+ <dd>A protocol that allows two parties without any initial shared secret
+ to create one in a manner immune to eavesdropping. Once they have done
+ this, they can communicate privately by using that shared secret as a
+ key for a block cipher or as the basis for key exchange.
+ <p>The protocol is secure against all <a href="#passive">passive
+ attacks</a>, but it is not at all resistant to active <a
+ href="#middle">man-in-the-middle attacks</a>. If a third party can
+ impersonate Bob to Alice and vice versa, then no useful secret can be
+ created. Authentication of the participants is a prerequisite for safe
+ Diffie-Hellman key exchange. IPsec can use any of several <a
+ href="#authentication">authentication</a> mechanisims. Those supported
+ by FreeS/WAN are discussed in our <a
+ href="config.html#choose">configuration</a> section.</p>
+ <p>The Diffie-Hellman key exchange is based on the <a
+ href="#dlog">discrete logarithm</a> problem and is secure unless
+ someone finds an efficient solution to that problem.</p>
+ <p>Given a prime <var>p</var> and generator <var>g</var> (explained
+ under <a href="#dlog">discrete log</a> below), Alice:</p>
+ <ul>
+ <li>generates a random number <var>a</var></li>
+ <li>calculates <var>A = g^a modulo p</var></li>
+ <li>sends <var>A</var> to Bob</li>
+ </ul>
+ <p>Meanwhile Bob:</p>
+ <ul>
+ <li>generates a random number <var>b</var></li>
+ <li>calculates <var>B = g^b modulo p</var></li>
+ <li>sends <var>B</var> to Alice</li>
+ </ul>
+ <p>Now Alice and Bob can both calculate the shared secret <var>s =
+ g^(ab)</var>. Alice knows <var>a</var> and <var>B</var>, so she
+ calculates <var>s = B^a</var>. Bob knows <var>A</var> and <var>b</var>
+ so he calculates <var>s = A^b</var>.</p>
+ <p>An eavesdropper will know <var>p</var> and <var>g</var> since these
+ are made public, and can intercept <var>A</var> and <var>B</var> but,
+ short of solving the <a href="#dlog">discrete log</a> problem, these do
+ not let him or her discover the secret <var>s</var>.</p>
+ </dd>
+ <dt><a name="signature">Digital signature</a></dt>
+ <dd>Sender:
+ <ul>
+ <li>calculates a <a href="#digest">message digest</a> of a
+ document</li>
+ <li>encrypts the digest with his or her private key, using some <a
+ href="#public">public key cryptosystem</a>.</li>
+ <li>attaches the encrypted digest to the document as a signature</li>
+ </ul>
+ <p>Receiver:</p>
+ <ul>
+ <li>calculates a digest of the document (not including the
+ signature)</li>
+ <li>decrypts the signature with the signer's public key</li>
+ <li>verifies that the two results are identical</li>
+ </ul>
+ <p>If the public-key system is secure and the verification succeeds,
+ then the receiver knows</p>
+ <ul>
+ <li>that the document was not altered between signing and
+ verification</li>
+ <li>that the signer had access to the private key</li>
+ </ul>
+ <p>Such an encrypted message digest can be treated as a signature since
+ it cannot be created without <em>both</em> the document <em>and</em>
+ the private key which only the sender should possess. The <a
+ href="web.html#legal">legal issues</a> are complex, but several
+ countries are moving in the direction of legal recognition for digital
+ signatures.</p>
+ </dd>
+ <dt><a name="dlog">discrete logarithm problem</a></dt>
+ <dd>The problem of finding logarithms in a finite field. Given a field
+ defintion (such definitions always include some operation analogous to
+ multiplication) and two numbers, a base and a target, find the power
+ which the base must be raised to in order to yield the target.
+ <p>The discrete log problem is the basis of several cryptographic
+ systems, including the <a href="#DH">Diffie-Hellman</a> key exchange
+ used in the <a href="#IKE">IKE</a> protocol. The useful property is
+ that exponentiation is relatively easy but the inverse operation,
+ finding the logarithm, is hard. The cryptosystems are designed so that
+ the user does only easy operations (exponentiation in the field) but an
+ attacker must solve the hard problem (discrete log) to crack the
+ system.</p>
+ <p>There are several variants of the problem for different types of
+ field. The IKE/Oakley key determination protocol uses two variants,
+ either over a field modulo a prime or over a field defined by an
+ elliptic curve. We give an example modulo a prime below. For the
+ elliptic curve version, consult an advanced text such as <a
+ href="biblio.html#handbook">Handbook of Applied Cryptography</a>.</p>
+ <p>Given a prime <var>p</var>, a generator <var>g</var> for the field
+ modulo that prime, and a number <var>x</var> in the field, the problem
+ is to find <var>y</var> such that <var>g^y = x</var>.</p>
+ <p>For example, let p = 13. The field is then the integers from 0 to
+ 12. Any integer equals one of these modulo 13. That is, the remainder
+ when any integer is divided by 13 must be one of these.</p>
+ <p>2 is a generator for this field. That is, the powers of two modulo
+ 13 run through all the non-zero numbers in the field. Modulo 13 we
+ have:</p>
+ <pre> y x
+ 2^0 == 1
+ 2^1 == 2
+ 2^2 == 4
+ 2^3 == 8
+ 2^4 == 3 that is, the remainder from 16/13 is 3
+ 2^5 == 6 the remainder from 32/13 is 6
+ 2^6 == 12 and so on
+ 2^7 == 11
+ 2^8 == 9
+ 2^9 == 5
+ 2^10 == 10
+ 2^11 == 7
+ 2^12 == 1</pre>
+ <p>Exponentiation in such a field is not difficult. Given, say,
+ <nobr><var>y = 11</var>,</nobr>calculating <nobr><var>x =
+ 7</var></nobr>is straightforward. One method is just to calculate
+ <nobr><var>2^11 = 2048</var>,</nobr>then <nobr><var>2048 mod 13 ==
+ 7</var>.</nobr>When the field is modulo a large prime (say a few 100
+ digits) you need a silghtly cleverer method and even that is moderately
+ expensive in computer time, but the calculation is still not
+ problematic in any basic way.</p>
+ <p>The discrete log problem is the reverse. In our example, given
+ <nobr><var>x = 7</var>,</nobr>find the logarithm <nobr><var>y =
+ 11</var>.</nobr>When the field is modulo a large prime (or is based on
+ a suitable elliptic curve), this is indeed problematic. No solution
+ method that is not catastrophically expensive is known. Quite a few
+ mathematicians have tackled this problem. No efficient method has been
+ found and mathematicians do not expect that one will be. It seems
+ likely no efficient solution to either of the main variants the
+ discrete log problem exists.</p>
+ <p>Note, however, that no-one has proven such methods do not exist. If
+ a solution to either variant were found, the security of any crypto
+ system using that variant would be destroyed. This is one reason <a
+ href="#IKE">IKE</a> supports two variants. If one is broken, we can
+ switch to the other.</p>
+ </dd>
+ <dt><a name="discretionary">discretionary access control</a></dt>
+ <dd>access control mechanisms controlled by the user, for example Unix
+ rwx file permissions. These contrast with <a
+ href="#mandatory">mandatory access controls</a>.</dd>
+ <dt><a name="DNS">DNS</a></dt>
+ <dd><b>D</b>omain <b>N</b>ame <b>S</b>ervice, a distributed database
+ through which names are associated with numeric addresses and other
+ information in the Internet Protocol Suite. See also the <a
+ href="background.html#dns.background">DNS background</a> section of our
+ documentation.</dd>
+ <dt>DOS attack</dt>
+ <dd>see <a href="#DOS">Denial Of Service</a> attack</dd>
+ <dt><a name="dynamic">dynamic IP address</a></dt>
+ <dd>an IP address which is automatically assigned, either by <a
+ href="#DHCP">DHCP</a> or by some protocol such as <a
+ href="#PPP">PPP</a> or <a href="#PPPoE">PPPoE</a> which the machine
+ uses to connect to the Internet. This is the opposite of a <a
+ href="#static">static IP address</a>, pre-set on the machine
+ itself.</dd>
+ <dt><a name="E">E</a></dt>
+ <dt><a name="EAR">EAR</a></dt>
+ <dd>The US government's <b>E</b>xport <b>A</b>dministration
+ <b>R</b>egulations, administered by the <a href="#BXA">Bureau of Export
+ Administration</a>. These have replaced the earlier <a
+ href="#ITAR">ITAR</a> regulations as the controls on export of
+ cryptography.</dd>
+ <dt><a name="ECB">ECB mode</a></dt>
+ <dd><b>E</b>lectronic <b>C</b>ode<b>B</b>ook mode, the simplest way to
+ use a block cipher. See <a href="#mode">Cipher Modes</a>.</dd>
+ <dt><a name="EDE">EDE</a></dt>
+ <dd>The sequence of operations normally used in either the three-key
+ variant of <a href="#3DES">triple DES</a> used in <a
+ href="#IPSEC">IPsec</a> or the <a href="#2key">two-key</a> variant used
+ in some other systems.
+ <p>The sequence is:</p>
+ <ul>
+ <li><b>E</b>ncrypt with key1</li>
+ <li><b>D</b>ecrypt with key2</li>
+ <li><b>E</b>ncrypt with key3</li>
+ </ul>
+ <p>For the two-key version, key1=key3.</p>
+ <p>The "advantage" of this EDE order of operations is that it makes it
+ simple to interoperate with older devices offering only single DES. Set
+ key1=key2=key3 and you have the worst of both worlds, the overhead of
+ triple DES with the "security" of single DES. Since both the <a
+ href="politics.html#desnotsecure">security of single DES</a> and the
+ overheads of triple DES are seriously inferior to many other ciphers,
+ this is a spectacularly dubious "advantage".</p>
+ </dd>
+ <dt><a name="Entrust">Entrust</a></dt>
+ <dd>A Canadian company offerring enterprise <a href="#PKI">PKI</a>
+ products using <a href="#CAST128">CAST-128</a> symmetric crypto, <a
+ href="#RSA">RSA</a> public key and <a href="#X509">X.509</a>
+ directories. <a href="http://www.entrust.com">Web site</a></dd>
+ <dt><a name="EFF">EFF</a></dt>
+ <dd><a href="http://www.eff.org">Electronic Frontier Foundation</a>, an
+ advocacy group for civil rights in cyberspace.</dd>
+ <dt><a name="encryption">Encryption</a></dt>
+ <dd>Techniques for converting a readable message (<a
+ href="#plaintext">plaintext</a>) into apparently random material (<a
+ href="#ciphertext">ciphertext</a>) which cannot be read if intercepted.
+ A key is required to read the message.
+ <p>Major variants include <a href="#symmetric">symmetric</a> encryption
+ in which sender and receiver use the same secret key and <a
+ href="#public">public key</a> methods in which the sender uses one of a
+ matched pair of keys and the receiver uses the other. Many current
+ systems, including <a href="#IPSEC">IPsec</a>, are <a
+ href="#hybrid">hybrids</a> combining the two techniques.</p>
+ </dd>
+ <dt><a name="ESP">ESP</a></dt>
+ <dd><b>E</b>ncapsulated <b>S</b>ecurity <b>P</b>ayload, the <a
+ href="#IPSEC">IPsec</a> protocol which provides <a
+ href="#encryption">encryption</a>. It can also provide <a
+ href="#authentication">authentication</a> service and may be used with
+ null encryption (which we do not recommend). For details see our <a
+ href="ipsec.html#ESP.ipsec">IPsec</a> document and/or RFC 2406.</dd>
+ <dt><a name="#extruded">Extruded subnet</a></dt>
+ <dd>A situation in which something IP sees as one network is actually in
+ two or more places.
+ <p>For example, the Internet may route all traffic for a particular
+ company to that firm's corporate gateway. It then becomes the company's
+ problem to get packets to various machines on their <a
+ href="#subnet">subnets</a> in various departments. They may decide to
+ treat a branch office like a subnet, giving it IP addresses "on" their
+ corporate net. This becomes an extruded subnet.</p>
+ <p>Packets bound for it are delivered to the corporate gateway, since
+ as far as the outside world is concerned, that subnet is part of the
+ corporate network. However, instead of going onto the corporate LAN (as
+ they would for, say, the accounting department) they are then
+ encapsulated and sent back onto the Internet for delivery to the branch
+ office.</p>
+ <p>For information on doing this with Linux FreeS/WAN, look in our <a
+ href="adv_config.html#extruded.config">advanced configuration</a>
+ section.</p>
+ </dd>
+ <dt>Exhaustive search</dt>
+ <dd>See <a href="#brute">brute force attack</a>.</dd>
+ <dt><a name="F">F</a></dt>
+ <dt><a name="FIPS">FIPS</a></dt>
+ <dd><b>F</b>ederal <b>I</b>nformation <b>P</b>rocessing <b>S</b>tandard,
+ the US government's standards for products it buys. These are issued by
+ <a href="#NIST">NIST</a>. Among other things, <a href="#DES">DES</a>
+ and <a href="#SHA">SHA</a> are defined in FIPS documents. NIST have a
+ <a href="http://www.itl.nist.gov/div897/pubs">FIPS home page</a>.</dd>
+ <dt><a name="FSF">Free Software Foundation (FSF)</a></dt>
+ <dd>An organisation to promote free software, free in the sense of these
+ quotes from their web pages</dd>
+ <dd>
+ <blockquote>
+ "Free software" is a matter of liberty, not price. To understand the
+ concept, you should think of "free speech", not "free beer."
+ <p>"Free software" refers to the users' freedom to run, copy,
+ distribute, study, change and improve the software.</p>
+ </blockquote>
+ <p>See also <a href="#GNU">GNU</a>, <a href="#GPL">GNU General Public
+ License</a>, and <a href="http://www.fsf.org">the FSF site</a>.</p>
+ </dd>
+ <dt>FreeS/WAN</dt>
+ <dd>see <a href="#FreeSWAN">Linux FreeS/WAN</a></dd>
+ <dt><a name="fullnet">Fullnet</A></dt>
+ <dd>The CIDR block containing all IPs of its IP version.
+ The <A HREF="#IPv4">IPv4</A> fullnet is written 0.0.0.0/0.
+ Also known as "all" and "default",
+ fullnet may be used in a routing table
+ to specify a default route,
+ and in a FreeS/WAN
+ <A HREF="policygroups.html#policygroups">policy group</A> file to
+ specify a default IPsec policy.</dd>
+ <dt>FSF</dt>
+ <dd>see <a href="#FSF">Free software Foundation</a></dd>
+ <dt><a name="G">G</a></dt>
+ <dt><a name="GCHQ">GCHQ</a></dt>
+ <dd><a href="http://www.gchq.gov.uk">Government Communications
+ Headquarters</a>, the British organisation for <a
+ href="#SIGINT">signals intelligence</a>.</dd>
+ <dt>generator of a prime field</dt>
+ <dd>see <a href="#dlog">discrete logarithm problem</a></dd>
+ <dt><a name="GILC">GILC</a></dt>
+ <dd><a href="http://www.gilc.org">Global Internet Liberty Campaign</a>,
+ an international organisation advocating, among other things, free
+ availability of cryptography. They have a <a
+ href="http://www.gilc.org/crypto/wassenaar">campaign</a> to remove
+ cryptographic software from the <a href="#Wassenaar.gloss">Wassenaar
+ Arrangement</a>.</dd>
+ <dt>Global Internet Liberty Campaign</dt>
+ <dd>see <a href="#GILC">GILC</a>.</dd>
+ <dt><a name="GTR">Global Trust Register</a></dt>
+ <dd>An attempt to create something like a <a href="#rootCA">root CA</a>
+ for <a href="#PGP">PGP</a> by publishing both <a
+ href="biblio.html#GTR">as a book</a> and <a
+ href="http://www.cl.cam.ac.uk/Research/Security/Trust-Register"> on the
+ web</a> the fingerprints of a set of verified keys for well-known users
+ and organisations.</dd>
+ <dt><a name="GMP">GMP</a></dt>
+ <dd>The <b>G</b>NU <b>M</b>ulti-<b>P</b>recision library code, used in <a
+ href="#FreeSWAN">Linux FreeS/WAN</a> by <a href="#Pluto">Pluto</a> for
+ <a href="#public">public key</a> calculations. See the <a
+ href="http://www.swox.com/gmp">GMP home page</a>.</dd>
+ <dt><a name="GNU">GNU</a></dt>
+ <dd><b>G</b>NU's <b>N</b>ot <b>U</b>nix, the <a href="#FSF">Free Software
+ Foundation's</a> project aimed at creating a free system with at least
+ the capabilities of Unix. <a href="#Linux">Linux</a> uses GNU utilities
+ extensively.</dd>
+ <dt><a name="#GOST">GOST</a></dt>
+ <dd>a Soviet government standard <a href="#block">block cipher</a>. <a
+ href="biblio.html#schneier">Applied Cryptography</a> has details.</dd>
+ <dt>GPG</dt>
+ <dd>see <a href="#GPG">GNU Privacy Guard</a></dd>
+ <dt><a name="GPL">GNU General Public License</a>(GPL, copyleft)</dt>
+ <dd>The license developed by the <a href="#FSF">Free Software
+ Foundation</a> under which <a href="#Linux">Linux</a>, <a
+ href="#FreeSWAN">Linux FreeS/WAN</a> and many other pieces of software
+ are distributed. The license allows anyone to redistribute and modify
+ the code, but forbids anyone from distributing executables without
+ providing access to source code. For more details see the file <a
+ href="../COPYING">COPYING</a> included with GPLed source distributions,
+ including ours, or <a href="http://www.fsf.org/copyleft/gpl.html"> the
+ GNU site's GPL page</a>.</dd>
+ <dt><a name="GPG">GNU Privacy Guard</a></dt>
+ <dd>An open source implementation of Open <a href="#PGP">PGP</a> as
+ defined in RFC 2440. See their <a href="http://www.gnupg.org">web
+ site</a></dd>
+ <dt>GPL</dt>
+ <dd>see <a href="#GPL">GNU General Public License</a>.</dd>
+ <dt><a name="H">H</a></dt>
+ <dt><a name="hash">Hash</a></dt>
+ <dd>see <a href="#digest">message digest</a></dd>
+ <dt><a name="HMAC">Hashed Message Authentication Code (HMAC)</a></dt>
+ <dd>using keyed <a href="#digest">message digest</a> functions to
+ authenticate a message. This differs from other uses of these functions:
+ <ul>
+ <li>In normal usage, the hash function's internal variable are
+ initialised in some standard way. Anyone can reproduce the hash to
+ check that the message has not been altered.</li>
+ <li>For HMAC usage, you initialise the internal variables from the
+ key. Only someone with the key can reproduce the hash. A successful
+ check of the hash indicates not only that the message is unchanged
+ but also that the creator knew the key.</li>
+ </ul>
+ <p>The exact techniques used in <a href="#IPSEC">IPsec</a> are defined
+ in RFC 2104. They are referred to as HMAC-MD5-96 and HMAC-SHA-96
+ because they output only 96 bits of the hash. This makes some attacks
+ on the hash functions harder.</p>
+ </dd>
+ <dt>HMAC</dt>
+ <dd>see <a href="#HMAC">Hashed Message Authentication Code</a></dd>
+ <dt>HMAC-MD5-96</dt>
+ <dd>see <a href="#HMAC">Hashed Message Authentication Code</a></dd>
+ <dt>HMAC-SHA-96</dt>
+ <dd>see <a href="#HMAC">Hashed Message Authentication Code</a></dd>
+ <dt><a name="hybrid">Hybrid cryptosystem</a></dt>
+ <dd>A system using both <a href="#public">public key</a> and <a
+ href="#symmetric">symmetric cipher</a> techniques. This works well.
+ Public key methods provide key management and <a
+ href="#signature">digital signature</a> facilities which are not
+ readily available using symmetric ciphers. The symmetric cipher,
+ however, can do the bulk of the encryption work much more efficiently
+ than public key methods.</dd>
+ <dt><a name="I">I</a></dt>
+ <dt><a name="IAB">IAB</a></dt>
+ <dd><a href="http://www.iab.org/iab">Internet Architecture Board</a>.</dd>
+ <dt><a name="ICMP.gloss">ICMP</a></dt>
+ <dd><strong>I</strong>nternet <strong>C</strong>ontrol
+ <strong>M</strong>essage <strong>P</strong>rotocol. This is used for
+ various IP-connected devices to manage the network.</dd>
+ <dt><a name="IDEA">IDEA</a></dt>
+ <dd><b>I</b>nternational <b>D</b>ata <b>E</b>ncrypion <b>A</b>lgorithm,
+ developed in Europe as an alternative to exportable American ciphers
+ such as <a href="#DES">DES</a> which were <a href="#desnotsecure">too
+ weak for serious use</a>. IDEA is a <a href="#block">block cipher</a>
+ using 64-bit blocks and 128-bit keys, and is used in products such as
+ <a href="#PGP">PGP</a>.
+ <p>IDEA is not required by the <a href="#IPSEC">IPsec</a> RFCs and not
+ currently used in <a href="#FreeSWAN">Linux FreeS/WAN</a>.</p>
+ <p>IDEA is patented and, with strictly limited exceptions for personal
+ use, using it requires a license from <a
+ href="http://www.ascom.com">Ascom</a>.</p>
+ </dd>
+ <dt><a name="IEEE">IEEE</a></dt>
+ <dd><a href="http://www.ieee.org">Institute of Electrical and Electronic
+ Engineers</a>, a professional association which, among other things,
+ sets some technical standards</dd>
+ <dt><a name="IESG">IESG</a></dt>
+ <dd><a href="http://www.iesg.org">Internet Engineering Steering
+ Group</a>.</dd>
+ <dt><a name="IETF">IETF</a></dt>
+ <dd><a href="http://www.ietf.org">Internet Engineering Task Force</a>,
+ the umbrella organisation whose various working groups make most of the
+ technical decisions for the Internet. The IETF <a
+ href="http://www.ietf.org/html.charters/ipsec-charter.html"> IPsec
+ working group</a> wrote the <a href="#RFC">RFCs</a> we are
+ implementing.</dd>
+ <dt><a name="IKE">IKE</a></dt>
+ <dd><b>I</b>nternet <b>K</b>ey <b>E</b>xchange, based on the <a
+ href="#DH">Diffie-Hellman</a> key exchange protocol. For details, see
+ RFC 2409 and our <a href="ipsec.html">IPsec</a> document. IKE is
+ implemented in <a href="#FreeSWAN">Linux FreeS/WAN</a> by the <a
+ href="#Pluto">Pluto daemon</a>.</dd>
+ <dt>IKE v2</dt>
+ <dd>A proposed replacement for <a href="#IKE">IKE</a>. There are other
+ candidates, such as <a href="#JFK">JFK</a>, and at time of writing
+ (March 2002) the choice between them has not yet been made and does not
+ appear imminent.</dd>
+ <dt><a name="iOE">iOE</a></dt>
+ <dd>See <A HREF="#initiate-only">Initiate-only opportunistic
+ encryption</A>.</dd>
+ <dt><a name="IP">IP</a></dt>
+ <dd><b>I</b>nternet <b>P</b>rotocol.</dd>
+ <dt><a name="masq">IP masquerade</a></dt>
+ <dd>A mostly obsolete term for a method of allowing multiple machines to
+ communicate over the Internet when only one IP address is available for
+ their use. The more current term is Network Address Translation or <a
+ href="#NAT.gloss">NAT</a>.</dd>
+ <dt><a name="IPng">IPng</a></dt>
+ <dd>"IP the Next Generation", see <a href="#ipv6.gloss">IPv6</a>.</dd>
+ <dt><a name="IPv4">IPv4</a></dt>
+ <dd>The current version of the <a href="#IP">Internet protocol
+ suite</a>.</dd>
+ <dt><a name="ipv6.gloss">IPv6 (IPng)</a></dt>
+ <dd>Version six of the <a href="#IP">Internet protocol suite</a>,
+ currently being developed. It will replace the current <a
+ href="#IPv4">version four</a>. IPv6 has <a href="#IPSEC">IPsec</a> as a
+ mandatory component.
+ <p>See this <a
+ href="http://playground.sun.com/pub/ipng/html/ipng-main.html">web
+ site</a> for more details, and our <a
+ href="compat.html#ipv6">compatibility</a> document for information on
+ FreeS/WAN and the Linux implementation of IPv6.</p>
+ </dd>
+ <dt><a name="IPSEC">IPsec</a> or IPSEC</dt>
+ <dd><b>I</b>nternet <b>P</b>rotocol <b>SEC</b>urity, security functions
+ (<a href="#authentication">authentication</a> and <a
+ href="#encryption">encryption</a>) implemented at the IP level of the
+ protocol stack. It is optional for <a href="#IPv4">IPv4</a> and
+ mandatory for <a href="#ipv6.gloss">IPv6</a>.
+ <p>This is the standard <a href="#FreeSWAN">Linux FreeS/WAN</a> is
+ implementing. For more details, see our <a href="ipsec.html">IPsec
+ Overview</a>. For the standards, see RFCs listed in our <a
+ href="rfc.html#RFC">RFCs document</a>.</p>
+ </dd>
+ <dt><a name="IPX">IPX</a></dt>
+ <dd>Novell's Netware protocol tunnelled over an IP link. Our <a
+ href="firewall.html#user.scripts">firewalls</a> document includes an
+ example of using this through an IPsec tunnel.</dd>
+ <dt><a name="ISAKMP">ISAKMP</a></dt>
+ <dd><b>I</b>nternet <b>S</b>ecurity <b>A</b>ssociation and <b>K</b>ey
+ <b>M</b>anagement <b>P</b>rotocol, defined in RFC 2408.</dd>
+ <dt><a name="ITAR">ITAR</a></dt>
+ <dd><b>I</b>nternational <b>T</b>raffic in <b>A</b>rms
+ <b>R</b>egulations, US regulations administered by the State Department
+ which until recently limited export of, among other things,
+ cryptographic technology and software. ITAR still exists, but the
+ limits on cryptography have now been transferred to the <a
+ href="#EAR">Export Administration Regulations</a> under the Commerce
+ Department's <a href="#BXA">Bureau of Export Administration</a>.</dd>
+ <dt>IV</dt>
+ <dd>see <a href="#IV">Initialisation vector</a></dd>
+ <dt><a name="IV">Initialisation Vector (IV)</a></dt>
+ <dd>Some cipher <a href="#mode">modes</a>, including the <a
+ href="#CBC">CBC</a> mode which IPsec uses, require some extra data at
+ the beginning. This data is called the initialisation vector. It need
+ not be secret, but should be different for each message. Its function
+ is to prevent messages which begin with the same text from encrypting
+ to the same ciphertext. That might give an analyst an opening, so it is
+ best prevented.</dd>
+ <dt><a name="initiate-only">Initiate-only opportunistic
+ encryption (iOE)</a></dt>
+ <dd>A form of
+ <A HREF="#carpediem">opportunistic encryption</A> (OE) in which
+ a host proposes opportunistic connections, but lacks the reverse DNS
+ records necessary to support incoming opportunistic connection requests.
+ Common among hosts on cable or pppoe connections where the system
+ administrator does not have write access to the DNS reverse map
+ for the host's external IP.
+ <p>Configuring for initiate-only opportunistic encryption
+ is described in our
+ <a href="quickstart.html#opp.client">quickstart</a> document.</p>
+ </dd>
+ <dt><a name="J">J</a></dt>
+ <dt><a name="JFK">JFK</a></dt>
+ <dd><strong>J</strong>ust <strong>F</strong>ast <strong>K</strong>eying,
+ a proposed simpler replacement for <a href="#IKE">IKE.</a></dd>
+ <dt><a name="K">K</a></dt>
+ <dt><a name="kernel">Kernel</a></dt>
+ <dd>The basic part of an operating system (e.g. Linux) which controls the
+ hardware and provides services to all other programs.
+ <p>In the Linux release numbering system, an even second digit as in
+ 2.<strong>2</strong>.x indicates a stable or production kernel while an
+ odd number as in 2.<strong>3</strong>.x indicates an experimental or
+ development kernel. Most users should run a recent kernel version from
+ the production series. The development kernels are primarily for people
+ doing kernel development. Others should consider using development
+ kernels only if they have an urgent need for some feature not yet
+ available in production kernels.</p>
+ </dd>
+ <dt>Keyed message digest</dt>
+ <dd>See <a href="#HMAC">HMAC</a>.</dd>
+ <dt>Key length</dt>
+ <dd>see <a href="#brute">brute force attack</a></dd>
+ <dt><a name="KLIPS">KLIPS</a></dt>
+ <dd><b>K</b>erne<b>l</b> <b>IP</b> <b>S</b>ecurity, the <a
+ href="#FreeSWAN">Linux FreeS/WAN</a> project's changes to the <a
+ href="#Linux">Linux</a> kernel to support the <a
+ href="#IPSEC">IPsec</a> protocols.</dd>
+ <dt><a name="L">L</a></dt>
+ <dt><a name="LDAP">LDAP</a></dt>
+ <dd><b>L</b>ightweight <b>D</b>irectory <b>A</b>ccess <b>P</b>rotocol,
+ defined in RFCs 1777 and 1778, a method of accessing information
+ stored in directories. LDAP is used by several <a href="#PKI">PKI</a>
+ implementations, often with X.501 directories and <a
+ href="#X509">X.509</a> certificates. It may also be used by <a
+ href="#IPSEC">IPsec</a> to obtain key certifications from those PKIs.
+ This is not yet implemented in <a href="#FreeSWAN">Linux
+ FreeS/WAN</a>.</dd>
+ <dt><a name="LIBDES">LIBDES</a></dt>
+ <dd>A publicly available library of <a href="#DES">DES</a> code, written
+ by Eric Young, which <a href="#FreeSWAN">Linux FreeS/WAN</a> uses in
+ both <a href="#KLIPS">KLIPS</a> and <a href="#Pluto">Pluto</a>.</dd>
+ <dt><a name="Linux">Linux</a></dt>
+ <dd>A freely available Unix-like operating system based on a kernel
+ originally written for the Intel 386 architecture by (then) student
+ Linus Torvalds. Once his 32-bit kernel was available, the <a
+ href="#GNU">GNU</a> utilities made it a usable system and contributions
+ from many others led to explosive growth.
+ <p>Today Linux is a complete Unix replacement available for several CPU
+ architectures -- Intel, DEC/Compaq Alpha, Power PC, both 32-bit SPARC
+ and the 64-bit UltraSPARC, SrongARM, . . . -- with support for multiple
+ CPUs on some architectures.</p>
+ <p><a href="#FreeSWAN">Linux FreeS/WAN</a> is intended to run on all
+ CPUs supported by Linux and is known to work on several. See our <a
+ href="compat.html#CPUs">compatibility</a> section for a list.</p>
+ </dd>
+ <dt><a name="FreeSWAN">Linux FreeS/WAN</a></dt>
+ <dd>Our implementation of the <a href="#IPSEC">IPsec</a> protocols,
+ intended to be freely redistributable source code with <a href="#GPL">a
+ GNU GPL license</a> and no constraints under US or other <a
+ href="politics.html#exlaw">export laws</a>. Linux FreeS/WAN is intended
+ to interoperate with other <a href="#IPSEC">IPsec</a> implementations.
+ The name is partly taken, with permission, from the <a
+ href="#SWAN">S/WAN</a> multi-vendor IPsec compatability effort. Linux
+ FreeS/WAN has two major components, <a href="#KLIPS">KLIPS</a> (KerneL
+ IPsec Support) and the <a href="#Pluto">Pluto</a> daemon which manages
+ the whole thing.
+ <p>See our <a href="ipsec.html">IPsec section</a> for more detail. For
+ the code see our <a href="http://freeswan.org"> primary site</a> or one
+ of the mirror sites on <a href="intro.html#mirrors">this list</a>.</p>
+ </dd>
+ <dt><a name="LSM">Linux Security Modules (LSM)</a></dt>
+ <dd>a project to create an interface in the Linux kernel that supports
+ plug-in modules for various security policies.
+ <p>This allows multiple security projects to take different approaches
+ to security enhancement without tying the kernel down to one particular
+ approach. As I understand the history, several projects were pressing
+ Linus to incorporate their changes, the various sets of changes were
+ incompatible, and his answer was more-or-less "a plague on all your
+ houses; I'll give you an interface, but I won't incorporate
+ anything".</p>
+ <p>It seems to be working. There is a fairly active <a
+ href="http://mail.wirex.com/mailman/listinfo/linux-security-module">LSM
+ mailing list</a>, and several projects are already using the
+ interface.</p>
+ </dd>
+ <dt>LSM</dt>
+ <dd>see <a href="#LSM">Linux Security Modules</a></dd>
+ <dt><a name="M">M</a></dt>
+ <dt><a name="list">Mailing list</a></dt>
+ <dd>The <a href="#FreeSWAN">Linux FreeS/WAN</a> project has several
+ public email lists for bug reports and software development
+ discussions. See our document on <a href="mail.html">mailing
+ lists</a>.</dd>
+ <dt><a name="middle">Man-in-the-middle attack</a></dt>
+ <dd>An <a href="#active">active attack</a> in which the attacker
+ impersonates each of the legitimate players in a protocol to the other.
+ <p>For example, if <a href="#alicebob">Alice and Bob</a> are
+ negotiating a key via the <a href="#DH">Diffie-Hellman</a> key
+ agreement, and are not using <a
+ href="#authentication">authentication</a> to be certain they are
+ talking to each other, then an attacker able to insert himself in the
+ communication path can deceive both players.</p>
+ <p>Call the attacker Mallory. For Bob, he pretends to be Alice. For
+ Alice, he pretends to be Bob. Two keys are then negotiated,
+ Alice-to-Mallory and Bob-to-Mallory. Alice and Bob each think the key
+ they have is Alice-to-Bob.</p>
+ <p>A message from Alice to Bob then goes to Mallory who decrypts it,
+ reads it and/or saves a copy, re-encrypts using the Bob-to-Mallory key
+ and sends it along to Bob. Bob decrypts successfully and sends a reply
+ which Mallory decrypts, reads, re-encrypts and forwards to Alice.</p>
+ <p>To make this attack effective, Mallory must</p>
+ <ul>
+ <li>subvert some part of the network in some way that lets him carry
+ out the deception<br>
+ possible targets: DNS, router, Alice or Bob's machine, mail server,
+ ...</li>
+ <li>beat any authentication mechanism Alice and Bob use<br>
+ strong authentication defeats the attack entirely; this is why <a
+ href="#IKE">IKE</a> requires authentication</li>
+ <li>work in real time, delivering messages without introducing a
+ delay large enough to alert the victims<br>
+ not hard if Alice and Bob are using email; quite difficult in some
+ situations.</li>
+ </ul>
+ <p>If he manages it, however, it is devastating. He not only gets to
+ read all the messages; he can alter messages, inject his own, forge
+ anything he likes, . . . In fact, he controls the communication
+ completely.</p>
+ </dd>
+ <dt><a name="mandatory">mandatory access control</a></dt>
+ <dd>access control mechanisims which are not settable by the user (see <a
+ href="#discretionary">discretionary access control</a>), but are
+ enforced by the system.
+ <p>For example, a document labelled "secret, zebra" might be readable
+ only by someone with secret clearance working on Project Zebra.
+ Ideally, the system will prevent any transfer outside those boundaries.
+ For example, even if you can read it, you should not be able to e-mail
+ it (unless the recipient is appropriately cleared) or print it (unless
+ certain printers are authorised for that classification).</p>
+ <p>Mandatory access control is a required feature for some levels of <a
+ href="#rainbow">Rainbow Book</a> or <a href="#cc">Common Criteria</a>
+ classification, but has not been widely used outside the military and
+ government. There is a good discussion of the issues in Anderson's <a
+ href="biblio.html#anderson">Security Engineering</a>.</p>
+ <p>The <a href="#SElinux">Security Enhanced Linux</a> project is adding
+ mandatory access control to Linux.</p>
+ </dd>
+ <dt><a name="manual">Manual keying</a></dt>
+ <dd>An IPsec mode in which the keys are provided by the administrator. In
+ FreeS/WAN, they are stored in /etc/ipsec.conf. The alternative, <a
+ href="#auto">automatic keying</a>, is preferred in most cases. See this
+ <a href="adv_config.html#man-auto">discussion</a>.</dd>
+ <dt><a name="MD4">MD4</a></dt>
+ <dd><a href="#digest">Message Digest Algorithm</a> Four from Ron Rivest
+ of <a href="#RSAco">RSA</a>. MD4 was widely used a few years ago, but
+ is now considered obsolete. It has been replaced by its descendants <a
+ href="#MD5">MD5</a> and <a href="#SHA">SHA</a>.</dd>
+ <dt><a name="MD5">MD5</a></dt>
+ <dd><a href="#digest">Message Digest Algorithm</a> Five from Ron Rivest
+ of <a href="#RSAco">RSA</a>, an improved variant of his <a
+ href="#MD4">MD4</a>. Like MD4, it produces a 128-bit hash. For details
+ see RFC 1321.
+ <p>MD5 is one of two message digest algorithms available in IPsec. The
+ other is <a href="#SHA">SHA</a>. SHA produces a longer hash and is
+ therefore more resistant to <a href="#birthday">birthday attacks</a>,
+ but this is not a concern for IPsec. The <a href="#HMAC">HMAC</a>
+ method used in IPsec is secure even if the underlying hash is not
+ particularly strong against this attack.</p>
+ <p>Hans Dobbertin found a weakness in MD5, and people often ask whether
+ this means MD5 is unsafe for IPsec. It doesn't. The IPsec RFCs discuss
+ Dobbertin's attack and conclude that it does not affect MD5 as used for
+ HMAC in IPsec.</p>
+ </dd>
+ <dt><a name="meet">Meet-in-the-middle attack</a></dt>
+ <dd>A divide-and-conquer attack which breaks a cipher into two parts,
+ works against each separately, and compares results. Probably the best
+ known example is an attack on double DES. This applies in principle to
+ any pair of block ciphers, e.g. to an encryption system using, say,
+ CAST-128 and Blowfish, but we will describe it for double DES.
+ <p>Double DES encryption and decryption can be written:</p>
+ <pre> C = E(k2,E(k1,P))
+ P = D(k1,D(k2,C))</pre>
+ <p>Where C is ciphertext, P is plaintext, E is encryption, D is
+ decryption, k1 is one key, and k2 is the other key. If we know a P, C
+ pair, we can try and find the keys with a brute force attack, trying
+ all possible k1, k2 pairs. Since each key is 56 bits, there are
+ 2<sup>112</sup> such pairs and this attack is painfully inefficient.</p>
+ <p>The meet-in-the middle attack re-writes the equations to calculate a
+ middle value M:</p>
+ <pre> M = E(k1,P)
+ M = D(k2,C)</pre>
+ <p>Now we can try some large number of D(k2,C) decryptions with various
+ values of k2 and store the results in a table. Then start doing E(k1,P)
+ encryptions, checking each result to see if it is in the table.</p>
+ <p>With enough table space, this breaks double DES with
+ <nobr>2<sup>56</sup> + 2<sup>56</sup> = 2<sup>57</sup></nobr>work.
+ Against triple DES, you need <nobr>2<sup>56</sup> + 2<sup>112</sup> ~=
+ 2<sup>112</sup></nobr>.</p>
+ <p>The memory requirements for such attacks can be prohibitive, but
+ there is a whole body of research literature on methods of reducing
+ them.</p>
+ </dd>
+ <dt><a name="digest">Message Digest Algorithm</a></dt>
+ <dd>An algorithm which takes a message as input and produces a hash or
+ digest of it, a fixed-length set of bits which depend on the message
+ contents in some highly complex manner. Design criteria include making
+ it extremely difficult for anyone to counterfeit a digest or to change
+ a message without altering its digest. One essential property is <a
+ href="#collision">collision resistance</a>. The main applications are
+ in message <a href="#authentication">authentication</a> and <a
+ href="#signature">digital signature</a> schemes. Widely used algorithms
+ include <a href="#MD5">MD5</a> and <a href="#SHA">SHA</a>. In IPsec,
+ message digests are used for <a href="#HMAC">HMAC</a> authentication of
+ packets.</dd>
+ <dt><a name="MTU">MTU</a></dt>
+ <dd><strong>M</strong>aximum <strong>T</strong>ransmission
+ <strong>U</strong>nit, the largest size of packet that can be sent over
+ a link. This is determined by the underlying network, but must be taken
+ account of at the IP level.
+ <p>IP packets, which can be up to 64K bytes each, must be packaged into
+ lower-level packets of the appropriate size for the underlying
+ network(s) and re-assembled on the other end. When a packet must pass
+ over multiple networks, each with its own MTU, and many of the MTUs are
+ unknown to the sender, this becomes a fairly complex problem. See <a
+ href="#pathMTU">path MTU discovery</a> for details.</p>
+ <p>Often the MTU is a few hundred bytes on serial links and 1500 on
+ Ethernet. There are, however, serial link protocols which use a larger
+ MTU to avoid fragmentation at the ethernet/serial boundary, and newer
+ (especially gigabit) Ethernet networks sometimes support much larger
+ packets because these are more efficient in some applications.</p>
+ </dd>
+ <dt><a name="N">N</a></dt>
+ <dt><a name="NAI">NAI</a></dt>
+ <dd><a href="http://www.nai.com">Network Associates</a>, a conglomerate
+ formed from <a href="#PGPI">PGP Inc.</a>, TIS (Trusted Information
+ Systems, a firewall vendor) and McAfee anti-virus products. Among other
+ things, they offer an IPsec-based VPN product.</dd>
+ <dt><a name="NAT.gloss">NAT</a></dt>
+ <dd><b>N</b>etwork <b>A</b>ddress <b>T</b>ranslation, a process by which
+ firewall machines may change the addresses on packets as they go
+ through. For discussion, see our <a
+ href="background.html#nat.background">background</a> section.</dd>
+ <dt><a name="NIST">NIST</a></dt>
+ <dd>The US <a href="http://www.nist.gov"> National Institute of Standards
+ and Technology</a>, responsible for <a href="#FIPS">FIPS standards</a>
+ including <a href="#DES">DES</a> and its replacement, <a
+ href="#AES">AES</a>.</dd>
+ <dt><a name="nonce">Nonce</a></dt>
+ <dd>A <a href="#random">random</a> value used in an <a
+ href="#authentication">authentication</a> protocol.</dd>
+ <dt></dt>
+ <dt><a name="non-routable">Non-routable IP address</a></dt>
+ <dd>An IP address not normally allowed in the "to" or "from" IP address
+ field header of IP packets.
+ <p>Almost invariably, the phrase "non-routable address" means one of
+ the addresses reserved by RFC 1918 for private networks:</p>
+ <ul>
+ <li>10.anything</li>
+ <li>172.x.anything with 16 &lt;= x &lt;= 31</li>
+ <li>192.168.anything</li>
+ </ul>
+ <p>These addresses are commonly used on private networks, e.g. behind a
+ Linux machines doing <a href="#masq">IP masquerade</a>. Machines within
+ the private network can address each other with these addresses. All
+ packets going outside that network, however, have these addresses
+ replaced before they reach the Internet.</p>
+ <p>If any packets using these addresses do leak out, they do not go
+ far. Most routers automatically discard all such packets.</p>
+ <p>Various other addresses -- the 127.0.0.0/8 block reserved for local
+ use, 0.0.0.0, various broadcast and network addresses -- cannot be
+ routed over the Internet, but are not normally included in the meaning
+ when the phrase "non-routable address" is used.</p>
+ </dd>
+ <dt><a name="NSA">NSA</a></dt>
+ <dd>The US <a href="http://www.nsa.gov"> National Security Agency</a>,
+ the American organisation for <a href="#SIGINT">signals
+ intelligence</a>, the protection of US government messages and the
+ interception and analysis of other messages. For details, see Bamford's
+ <a href="biblio.html#puzzle">"The Puzzle Palace"</a>.
+ <p>Some <a
+ href="http://www.gwu.edu/~nsarchiv/NSAEBB/NSAEBB23/index.html">history
+ of NSA</a> documents were declassified in response to a FOIA (Freedom
+ of Information Act) request.</p>
+ </dd>
+ <dt><a name="O">O</a></dt>
+ <dt><a name="oakley">Oakley</a></dt>
+ <dd>A key determination protocol, defined in RFC 2412.</dd>
+ <dt>Oakley groups</dt>
+ <dd>The groups used as the basis of <a href="#DH">Diffie-Hellman</a> key
+ exchange in the Oakley protocol, and in <a href="#IKE">IKE</a>. Four
+ were defined in the original RFC, and a fifth has been <a
+ href="http://www.lounge.org/ike_doi_errata.html">added since</a>.
+ <p>Linux FreeS/WAN currently supports the three groups based on finite
+ fields modulo a prime (Groups 1, 2 and 5) and does not support the
+ elliptic curve groups (3 and 4). For a description of the difference of
+ the types, see <a href="#dlog">discrete logarithms</a>.</p>
+ </dd>
+ <dt><a name="OTP">One time pad</a></dt>
+ <dd>A cipher in which the key is:
+ <ul>
+ <li>as long as the total set of messages to be enciphered</li>
+ <li>absolutely <a href="#random">random</a></li>
+ <li>never re-used</li>
+ </ul>
+ <p>Given those three conditions, it can easily be proved that the
+ cipher is perfectly secure, in the sense that an attacker with
+ intercepted message in hand has no better chance of guessing the
+ message than an attacker who has not intercepted the message and only
+ knows the message length. No such proof exists for any other cipher.</p>
+ <p>There are, however, several problems with this "perfect" cipher.</p>
+ <p>First, it is <strong>wildly impractical</strong> for most
+ applications. Key management is at best difficult, often completely
+ impossible.</p>
+ <p>Second, it is <strong>extremely fragile</strong>. Small changes
+ which violate the conditions listed above do not just weaken the cipher
+ liitle. Quite often they destroy its security completely.</p>
+ <ul>
+ <li>Re-using the pad weakens the cipher to the point where it can be
+ broken with pencil and paper. With a computer, the attack is
+ trivially easy.</li>
+ <li>Using <em>anything</em> less than truly <a
+ href="#random">random</a> numbers <em>completely</em> invalidates
+ the security proof.</li>
+ <li>In particular, using computer-generated pseudo-random numbers may
+ give an extremely weak cipher. It might also produce a good stream
+ cipher, if the pseudo-random generator is both well-designed and
+ properely seeded.</li>
+ </ul>
+ <p>Marketing claims about the "unbreakable" security of various
+ products which somewhat resemble one-time pads are common. Such claims
+ are one of the surest signs of cryptographic <a href="#snake">snake
+ oil</a>; most systems marketed with such claims are worthless.</p>
+ <p>Finally, even if the system is implemented and used correctly, it is
+ <strong>highly vulnerable to a substitution attack</strong>. If an
+ attacker knows some plaintext and has an intercepted message, he can
+ discover the pad.</p>
+ <ul>
+ <li>This does not matter if the attacker is just a <a
+ href="#passive">passive</a> eavesdropper. It gives him no plaintext
+ he didn't already know and we don't care that he learns a pad which
+ we will never re-use.</li>
+ <li>However, an <a href="#active">active</a> attacker who knows the
+ plaintext can recover the pad, then use it to encode with whatever
+ he chooses. If he can get his version delivered instead of yours,
+ this may be a disaster. If you send "attack at dawn", the delivered
+ message can be anything the same length -- perhaps "retreat to
+ east" or "shoot generals".</li>
+ <li>An active attacker with only a reasonable guess at the plaintext
+ can try the same attack. If the guess is correct, this works and
+ the attacker's bogus message is delivered. If the guess is wrong, a
+ garbled message is delivered.</li>
+ </ul>
+ <p>In general then, despite its theoretical perfection, the
+ one-time-pad has very limited practical application.</p>
+ <p>See also the <a href="http://pubweb.nfr.net/~mjr/pubs/otpfaq/">one
+ time pad FAQ</a>.</p>
+ </dd>
+ <dt><a name="carpediem">Opportunistic encryption (OE)</a></dt>
+ <dd>A situation in which any two IPsec-aware machines can secure their
+ communications, without a pre-shared secret and without a common <a
+ href="#PKI">PKI</a> or previous exchange of public keys. This is one of
+ the goals of the Linux FreeS/WAN project, discussed in our <a
+ href="intro.html#goals">introduction</a> section.
+ <p>Setting up for opportunistic encryption is described in our <a
+ href="quickstart.html#quickstart">quickstart</a> document.</p>
+ </dd>
+ <dt><a name="responder">Opportunistic responder</a></dt>
+ <dd>A host which accepts, but does not initiate, requests for
+ <A HREF="#carpediem">opportunistic encryption</A> (OE).
+ An opportunistic responder has enabled OE in its
+ <A HREF="#passive.OE">passive</A> form (pOE) only.
+ A web server or file server may be usefully set up as an opportunistic
+ responder.
+ <p>Configuring passive OE is described in our
+ <a href="policygroups.html#policygroups">policy groups</a> document.</p>
+ </dd>
+ <dt><a name="orange">Orange book</a></dt>
+ <dd>the most basic and best known of the US government's <a
+ href="#rainbow">Rainbow Book</a> series of computer security
+ standards.</dd>
+ <dt><a name="P">P</a></dt>
+ <dt><a name="P1363">P1363 standard</a></dt>
+ <dd>An <a href="#IEEE">IEEE</a> standard for public key cryptography. <a
+ href="http://grouper.ieee.org/groups/1363">Web page</a>.</dd>
+ <dt><a name="pOE">pOE</a></dt>
+ <dd>See <a href="#passive.OE">Passive opportunistic encryption</a>.</dd>
+ <dt><a name="passive">Passive attack</a></dt>
+ <dd>An attack in which the attacker only eavesdrops and attempts to
+ analyse intercepted messages, as opposed to an <a href="#active">active
+ attack</a> in which he diverts messages or generates his own.</dd>
+ <dt><a name="passive.OE">Passive opportunistic encryption (pOE)</a></dt>
+ <dd>A form of
+ <A HREF="#carpediem">opportunistic encryption</A> (OE) in which the
+ host will accept opportunistic connection requests, but will not
+ initiate such requests. A host which runs OE in its passive form only
+ is known as an <A HREF="#responder">opportunistic responder</A>.
+ <p>Configuring passive OE is described in our
+ <a href="policygroups.html#policygroups">policy groups</a> document.</p>
+ </dd>
+ <dt><a name="pathMTU">Path MTU discovery</a></dt>
+ <dd>The process of discovering the largest packet size which all links on
+ a path can handle without fragmentation -- that is, without any router
+ having to break the packet up into smaller pieces to match the <a
+ href="#MTU">MTU</a> of its outgoing link.
+ <p>This is done as follows:</p>
+ <ul>
+ <li>originator sends the largest packets allowed by <a
+ href="#MTU">MTU</a> of the first link, setting the DF
+ (<strong>d</strong>on't <strong>f</strong>ragment) bit in the
+ packet header</li>
+ <li>any router which cannot send the packet on (outgoing MTU is too
+ small for it, and DF prevents fragmenting it to match) sends back
+ an <a href="#ICMP.gloss">ICMP</a> packet reporting the problem</li>
+ <li>originator looks at ICMP message and tries a smaller size</li>
+ <li>eventually, you settle on a size that can pass all routers</li>
+ <li>thereafter, originator just sends that size and no-one has to
+ fragment</li>
+ </ul>
+ <p>Since this requires co-operation of many systems, and since the next
+ packet may travel a different path, this is one of the trickier areas
+ of IP programming. Bugs that have shown up over the years have
+ included:</p>
+ <ul>
+ <li>malformed ICMP messages</li>
+ <li>hosts that ignore or mishandle these ICMP messages</li>
+ <li>firewalls blocking the ICMP messages so host does not see
+ them</li>
+ </ul>
+ <p>Since IPsec adds a header, it increases packet size and may require
+ fragmentation even where incoming and outgoing MTU are equal.</p>
+ </dd>
+ <dt><a name="PFS">Perfect forward secrecy (PFS)</a></dt>
+ <dd>A property of systems such as <a href="#DH">Diffie-Hellman</a> key
+ exchange which use a long-term key (such as the shared secret in IKE)
+ and generate short-term keys as required. If an attacker who acquires
+ the long-term key <em>provably</em> can
+ <ul>
+ <li><em>neither</em> read previous messages which he may have
+ archived</li>
+ <li><em>nor</em> read future messages without performing additional
+ successful attacks</li>
+ </ul>
+ <p>then the system has PFS. The attacker needs the short-term keys in
+ order to read the trafiic and merely having the long-term key does not
+ allow him to infer those. Of course, it may allow him to conduct
+ another attack (such as <a href="#middle">man-in-the-middle</a>) which
+ gives him some short-term keys, but he does not automatically get them
+ just by acquiring the long-term key.</p>
+ <p>See also
+<a href="http://sandelman.ottawa.on.ca/ipsec/1996/08/msg00123.html">Phil
+Karn's definition</a>.
+ </dd>
+ <dt>PFS</dt>
+ <dd>see Perfect Forward Secrecy</dd>
+ <dt><a name="PGP">PGP</a></dt>
+ <dd><b>P</b>retty <b>G</b>ood <b>P</b>rivacy, a personal encryption
+ system for email based on public key technology, written by Phil
+ Zimmerman.
+ <p>The 2.xx versions of PGP used the <a href="#RSA">RSA</a> public key
+ algorithm and used <a href="#IDEA">IDEA</a> as the symmetric cipher.
+ These versions are described in RFC 1991 and in <a
+ href="#PGP">Garfinkel's book</a>. Since version 5, the products from <a
+ href="#PGPI">PGP Inc</a>. have used <a href="#DH">Diffie-Hellman</a>
+ public key methods and <a href="#CAST128">CAST-128</a> symmetric
+ encryption. These can verify signatures from the 2.xx versions, but
+ cannot exchange encryted messages with them.</p>
+ <p>An <a href="#IETF">IETF</a> working group has issued RFC 2440 for an
+ "Open PGP" standard, similar to the 5.x versions. PGP Inc. staff were
+ among the authors. A free <a href="#GPG">Gnu Privacy Guard</a> based on
+ that standard is now available.</p>
+ <p>For more information on PGP, including how to obtain it, see our
+ cryptography <a href="web.html#tools">links</a>.</p>
+ </dd>
+ <dt><a name="PGPI">PGP Inc.</a></dt>
+ <dd>A company founded by Zimmerman, the author of <a href="#PGP">PGP</a>,
+ now a division of <a href="#NAI">NAI</a>. See the <a
+ href="http://www.pgp.com">corporate website</a>. Zimmerman left in
+ 2001, and early in 2002 NAI announced that they would no longer sell
+ PGP..
+ <p>Versions 6.5 and later of the PGP product include PGPnet, an IPsec
+ client for Macintosh or for Windows 95/98/NT. See our <a
+ href="interop.html#pgpnet">interoperation documen</a>t.</p>
+ </dd>
+ <dt><a name="photuris">Photuris</a></dt>
+ <dd>Another key negotiation protocol, an alternative to <a
+ href="#IKE">IKE</a>, described in RFCs 2522 and 2523.</dd>
+ <dt><a name="PPP">PPP</a></dt>
+ <dd><b>P</b>oint-to-<b>P</b>oint <b>P</b>rotocol, originally a method of
+ connecting over modems or serial lines, but see also PPPoE.</dd>
+ <dt><a name="PPPoE">PPPoE</a></dt>
+ <dd><b>PPP</b> <b>o</b>ver <b>E</b>thernet, a somewhat odd protocol that
+ makes Ethernet look like a point-to-point serial link. It is widely
+ used for cable or ADSL Internet services, apparently mainly because it
+ lets the providers use access control and address assignmment
+ mechanisms developed for dialup networks. <a
+ href="http://www.roaringpenguin.com">Roaring Penguin</a> provide a
+ widely used Linux implementation.</dd>
+ <dt><a name="PPTP">PPTP</a></dt>
+ <dd><b>P</b>oint-to-<b>P</b>oint <b>T</b>unneling <b>P</b>rotocol, used
+ in some Microsoft VPN implementations. Papers discussing weaknesses in
+ it are on <a
+ href="http://www.counterpane.com/publish.html">counterpane.com</a>. It
+ is now largely obsolete, replaced by L2TP.</dd>
+ <dt><a name="PKI">PKI</a></dt>
+ <dd><b>P</b>ublic <b>K</b>ey <b>I</b>nfrastructure, the things an
+ organisation or community needs to set up in order to make <a
+ href="#public">public key</a> cryptographic technology a standard part
+ of their operating procedures.
+ <p>There are several PKI products on the market. Typically they use a
+ hierarchy of <a href="#CA">Certification Authorities (CAs)</a>. Often
+ they use <a href="#LDAP">LDAP</a> access to <a href="#X509">X.509</a>
+ directories to implement this.</p>
+ <p>See <a href="#web">Web of Trust</a> for a different sort of
+ infrastructure.</p>
+ </dd>
+ <dt><a name="PKIX">PKIX</a></dt>
+ <dd><b>PKI</b> e<b>X</b>change, an <a href="#IETF">IETF</a> standard that
+ allows <a href="#PKI">PKI</a>s to talk to each other.
+ <p>This is required, for example, when users of a corporate PKI need to
+ communicate with people at client, supplier or government
+ organisations, any of which may have a different PKI in place. I should
+ be able to talk to you securely whenever:</p>
+ <ul>
+ <li>your organisation and mine each have a PKI in place</li>
+ <li>you and I are each set up to use those PKIs</li>
+ <li>the two PKIs speak PKIX</li>
+ <li>the configuration allows the conversation</li>
+ </ul>
+ <p>At time of writing (March 1999), this is not yet widely implemented
+ but is under quite active development by several groups.</p>
+ </dd>
+ <dt><a name="plaintext">Plaintext</a></dt>
+ <dd>The unencrypted input to a cipher, as opposed to the encrypted <a
+ href="#ciphertext">ciphertext</a> output.</dd>
+ <dt><a name="Pluto">Pluto</a></dt>
+ <dd>The <a href="#FreeSWAN">Linux FreeS/WAN</a> daemon which handles key
+ exchange via the <a href="#IKE">IKE</a> protocol, connection
+ negotiation, and other higher-level tasks. Pluto calls the <a
+ href="#KLIPS">KLIPS</a> kernel code as required. For details, see the
+ manual page ipsec_pluto(8).</dd>
+ <dt><a name="public">Public Key Cryptography</a></dt>
+ <dd>In public key cryptography, keys are created in matched pairs.
+ Encrypt with one half of a pair and only the matching other half can
+ decrypt it. This contrasts with <a href="#symmetric">symmetric or
+ secret key cryptography</a> in which a single key known to both parties
+ is used for both encryption and decryption.
+ <p>One half of each pair, called the public key, is made public. The
+ other half, called the private key, is kept secret. Messages can then
+ be sent by anyone who knows the public key to the holder of the private
+ key. Encrypt with the public key and you know that only someone with
+ the matching private key can decrypt.</p>
+ <p>Public key techniques can be used to create <a
+ href="#signature">digital signatures</a> and to deal with key
+ management issues, perhaps the hardest part of effective deployment of
+ <a href="#symmetric"> symmetric ciphers</a>. The resulting <a
+ href="#hybrid">hybrid cryptosystems</a> use public key methods to
+ manage keys for symmetric ciphers.</p>
+ <p>Many organisations are currently creating <a href="#PKI">PKIs,
+ public key infrastructures</a> to make these benefits widely
+ available.</p>
+ </dd>
+ <dt>Public Key Infrastructure</dt>
+ <dd>see <a href="#PKI">PKI</a></dd>
+ <dt><a name="Q">Q</a></dt>
+ <dt><a name="R">R</a></dt>
+ <dt><a name="rainbow">Rainbow books</a></dt>
+ <dd>A set of US government standards for evaluation of "trusted computer
+ systems", of which the best known was the <a href="#orange">Orange
+ Book</a>. One fairly often hears references to "C2 security" or a
+ product "evaluated at B1". The Rainbow books define the standards
+ referred to in those comments.
+ <p>See this <a href="http://www.fas.org/irp/nsa/rainbow.htm">reference
+ page</a>.</p>
+ <p>The Rainbow books are now mainly obsolete, replaced by the
+ international <a href="#cc">Common Criteria</a> standards.</p>
+ </dd>
+ <dt><a name="random">Random</a></dt>
+ <dd>A remarkably tricky term, far too much so for me to attempt a
+ definition here. Quite a few cryptosystems have been broken via attacks
+ on weak random number generators, even when the rest of the system was
+ sound.
+ <p>See <a
+ href="http://nis.nsf.net/internet/documents/rfc/rfc1750.txt">RFC
+ 1750</a> for the theory.</p>
+ <p>See the manual pages for <a
+ href="manpage.d/ipsec_ranbits.8.html">ipsec_ranbits(8)</a> and
+ ipsec_prng(3) for more on FreeS/WAN's use of randomness. Both depend on
+ the random(4) device driver..</p>
+ <p>A couple of years ago, there was extensive mailing list discussion
+ (archived <a
+ href="http://www.openpgp.net/random/index.html">here</a>)of Linux
+ /dev/random and FreeS/WAN. Since then, the design of the random(4)
+ driver has changed considerably. Linux 2.4 kernels have the new
+ driver..</p>
+ </dd>
+ <dt>Raptor</dt>
+ <dd>A firewall product for Windows NT offerring IPsec-based VPN services.
+ Linux FreeS/WAN interoperates with Raptor; see our <a
+ href="interop.html#Raptor">interop</a> document for details. Raptor
+ have recently merged with Axent.</dd>
+ <dt><a name="RC4">RC4</a></dt>
+ <dd><b>R</b>ivest <b>C</b>ipher four, designed by Ron Rivest of <a
+ href="#RSAco">RSA</a> and widely used. Believed highly secure with
+ adequate key length, but often implemented with inadequate key length
+ to comply with export restrictions.</dd>
+ <dt><a name="RC6">RC6</a></dt>
+ <dd><b>R</b>ivest <b>C</b>ipher six, <a href="#RSAco">RSA</a>'s <a
+ href="#AES">AES</a> candidate cipher.</dd>
+ <dt><a name="replay">Replay attack</a></dt>
+ <dd>An attack in which the attacker records data and later replays it in
+ an attempt to deceive the recipient.</dd>
+ <dt><a name="reverse">Reverse map</a></dt>
+ <dd>In <a href="#DNS">DNS</a>, a table where IP addresses can be used as
+ the key for lookups which return a system name and/or other
+ information.</dd>
+ <dt>RFC</dt>
+ <dd><b>R</b>equest <b>F</b>or <b>C</b>omments, an Internet document. Some
+ RFCs are just informative. Others are standards.
+ <p>Our list of <a href="#IPSEC">IPsec</a> and other security-related
+ RFCs is <a href="rfc.html#RFC">here</a>, along with information on
+ methods of obtaining them.</p>
+ </dd>
+ <dt><a name="rijndael">Rijndael</a></dt>
+ <dd>a <a href="#block">block cipher</a> designed by two Belgian
+ cryptographers, winner of the US government's <a href="#AES">AES</a>
+ contest to pick a replacement for <a href="#DES">DES</a>. See the <a
+ href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael">Rijndael home
+ page</a>.</dd>
+ <dt><a name="RIPEMD">RIPEMD</a></dt>
+ <dd>A <a href="#digest">message digest</a> algorithm. The current version
+ is RIPEMD-160 which gives a 160-bit hash.</dd>
+ <dt><a name="rootCA">Root CA</a></dt>
+ <dd>The top level <a href="#CA">Certification Authority</a> in a hierachy
+ of such authorities.</dd>
+ <dt><a name="routable">Routable IP address</a></dt>
+ <dd>Most IP addresses can be used as "to" and "from" addresses in packet
+ headers. These are the routable addresses; we expect routing to be
+ possible for them. If we send a packet to one of them, we expect (in
+ most cases; there are various complications) that it will be delivered
+ if the address is in use and will cause an <a
+ href="#ICMP.gloss">ICMP</a> error packet to come back to us if not.
+ <p>There are also several classes of <a
+ href="#non-routable">non-routable</a> IP addresses.</p>
+ </dd>
+ <dt><a name="RSA">RSA algorithm</a></dt>
+ <dd><b>R</b>ivest <b>S</b>hamir <b>A</b>dleman <a href="#public">public
+ key</a> algorithm, named for its three inventors. It is widely used and
+ likely to become moreso since it became free of patent encumbrances in
+ September 2000.
+ <p>RSA can be used to provide either <a
+ href="#encryption">encryption</a> or <a href="#signature">digital
+ signatures</a>. In IPsec, it is used only for signatures. These provide
+ gateway-to-gateway <a href="#authentication">authentication</a> for <a
+ href="#IKE">IKE </a>negotiations.</p>
+ <p>For a full explanation of the algorithm, consult one of the standard
+ references such as <a href="biblio.html#schneier">Applied
+ Cryptography</a>. A simple explanation is:</p>
+ <p>The great 17th century French mathematician <a
+ href="http://www-groups.dcs.st-andrews.ac.uk/~history/Mathematicians/Fermat.html">Fermat</a>
+ proved that,</p>
+ <p>for any prime p and number x, 0 &lt;= x &lt; p:</p>
+ <pre> x^p == x modulo p
+ x^(p-1) == 1 modulo p, non-zero x
+ </pre>
+ <p>From this it follows that if we have a pair of primes p, q and two
+ numbers e, d such that:</p>
+ <pre> ed == 1 modulo lcm( p-1, q-1)
+ </pre>
+ where lcm() is least common multiple, then<br>
+ for all x, 0 &lt;= x &lt; pq:
+ <pre> x^ed == x modulo pq
+ </pre>
+ <p>So we construct such as set of numbers p, q, e, d and publish the
+ product N=pq and e as the public key. Using c for <a
+ href="#ciphertext">ciphertext</a> and i for the input <a
+ href="#plaintext">plaintext</a>, encryption is then:</p>
+ <pre> c = i^e modulo N
+ </pre>
+ <p>An attacker cannot deduce i from the cyphertext c, short of either
+ factoring N or solving the <a href="#dlog">discrete logarithm</a>
+ problem for this field. If p, q are large primes (hundreds or thousands
+ of bits) no efficient solution to either problem is known.</p>
+ <p>The receiver, knowing the private key (N and d), can readily recover
+ the plaintext p since:</p>
+ <pre> c^d == (i^e)^d modulo N
+ == i^ed modulo N
+ == i modulo N
+ </pre>
+ <p>This gives an effective public key technique, with only a couple of
+ problems. It uses a good deal of computer time, since calculations with
+ large integers are not cheap, and there is no proof it is necessarily
+ secure since no-one has proven either factoring or discrete log cannot
+ be done efficiently. Quite a few good mathematicians have tried both
+ problems, and no-one has announced success, but there is no proof they
+ are insoluble.</p>
+ </dd>
+ <dt><a name="RSAco">RSA Data Security</a></dt>
+ <dd>A company founded by the inventors of the <a href="#RSA">RSA</a>
+ public key algorithm.</dd>
+ <dt><a name="S">S</a></dt>
+ <dt><a name="SA">SA</a></dt>
+ <dd><b>S</b>ecurity <b>A</b>ssociation, the channel negotiated by the
+ higher levels of an <a href="#IPSEC">IPsec</a> implementation (<a
+ href="#IKE">IKE</a>) and used by the lower (<a href="#ESP">ESP</a> and
+ <a href="#AH">AH</a>). SAs are unidirectional; you need a pair of them
+ for two-way communication.
+ <p>An SA is defined by three things -- the destination, the protocol
+ (<a href="#AH">AH</a> or<a href="#ESP">ESP</a>) and the <a
+ href="SPI">SPI</a>, security parameters index. It is used as an index
+ to look up other things such as session keys and intialisation
+ vectors.</p>
+ <p>For more detail, see our section on <a href="ipsec.html">IPsec</a>
+ and/or RFC 2401.</p>
+ </dd>
+ <dt><a name="SElinux">SE Linux</a></dt>
+ <dd><strong>S</strong>ecurity <strong>E</strong>nhanced Linux, an <a
+ href="#NSA">NSA</a>-funded project to add <a
+ href="#mandatory">mandatory access control</a> to Linux. See the <a
+ href="http://www.nsa.gov/selinux">project home page</a>.
+ <p>According to their web pages, this work will include extending
+ mandatory access controls to IPsec tunnels.</p>
+ <p>Recent versions of SE Linux code use the <a href="#LSM">Linux
+ Security Module</a> interface.</p>
+ </dd>
+ <dt><a name="SDNS">Secure DNS</a></dt>
+ <dd>A version of the <a href="#DNS">DNS or Domain Name Service</a>
+ enhanced with authentication services. This is being designed by the <a
+ href="#IETF">IETF</a> DNS security <a
+ href="http://www.ietf.org/ids.by.wg/dnssec.html">working group</a>.
+ Check the <a href="http://www.isc.org/bind.html">Internet Software
+ Consortium</a> for information on implementation progress and for the
+ latest version of <a href="#BIND">BIND</a>. Another site has <a
+ href="http://www.toad.com/~dnssec">more information</a>.
+ <p><a href="#IPSEC">IPsec</a> can use this plus <a
+ href="#DH">Diffie-Hellman key exchange</a> to bootstrap itself. This
+ allows <a href="#carpediem">opportunistic encryption</a>. Any pair of
+ machines which can authenticate each other via DNS can communicate
+ securely, without either a pre-existing shared secret or a shared <a
+ href="#PKI">PKI</a>.</p>
+ </dd>
+ <dt>Secret key cryptography</dt>
+ <dd>See <a href="#symmetric">symmetric cryptography</a></dd>
+ <dt>Security Association</dt>
+ <dd>see <a href="#SA">SA</a></dd>
+ <dt>Security Enhanced Linux</dt>
+ <dd>see <a href="#SElinux">SE Linux</a></dd>
+ <dt><a name="sequence">Sequence number</a></dt>
+ <dd>A number added to a packet or message which indicates its position in
+ a sequence of packets or messages. This provides some security against
+ <a href="#replay">replay attacks</a>.
+ <p>For <a href="#auto">automatic keying</a> mode, the <a
+ href="#IPSEC">IPsec</a> RFCs require that the sender generate sequence
+ numbers for each packet, but leave it optional whether the receiver
+ does anything with them.</p>
+ </dd>
+ <dt><a name="SHA">SHA</a></dt>
+ <dt>SHA-1</dt>
+ <dd><b>S</b>ecure <b>H</b>ash <b>A</b>lgorithm, a <a
+ href="#digest">message digest algorithm</a> developed by the <a
+ href="#NSA">NSA</a> for use in the Digital Signature standard, <a
+ href="#FIPS">FIPS</a> number 186 from <a href="#NIST">NIST</a>. SHA is
+ an improved variant of <a href="#MD4">MD4</a> producing a 160-bit hash.
+ <p>SHA is one of two message digest algorithms available in IPsec. The
+ other is <a href="#MD5">MD5</a>. Some people do not trust SHA because
+ it was developed by the <a href="#NSA">NSA</a>. There is, as far as we
+ know, no cryptographic evidence that SHA is untrustworthy, but this
+ does not prevent that view from being strongly held.</p>
+ <p>The NSA made one small change after the release of the original SHA.
+ They did not give reasons. Iit may be a defense against some attack
+ they found and do not wish to disclose. Technically the modified
+ algorithm should be called SHA-1, but since it has replaced the
+ original algorithm in nearly all applications, it is generally just
+ referred to as SHA..</p>
+ </dd>
+ <dt><a name="SHA-256">SHA-256</a></dt>
+ <dt>SHA-384</dt>
+ <dt>SHA-512</dt>
+ <dd>Newer variants of SHA designed to match the strength of the 128, 192
+ and 256-bit keys of <a href="#AES">AES</a>. The work to break an
+ encryption algorithm's strength by <a href="#brute">brute force</a> is
+ 2
+ <math xmlns="http://www.w3.org/1998/Math/MathML">
+ <msup>
+ <mi>keylength</mi>
+ </msup>
+ </math>
+ operations but a <a href="birthday">birthday attack </a>on a hash
+ needs only 2
+ <math xmlns="http://www.w3.org/1998/Math/MathML">
+ <msup>
+ <mrow>
+ <mi>hashlength</mi>
+ <mo>/</mo>
+ <mn>2</mn>
+ </mrow>
+ </msup>
+ </math>
+ , so as a general rule you need a hash twice the size of the key to
+ get similar strength. SHA-256, SHA-384 and SHA-512 are designed to
+ match the 128, 192 and 256-bit key sizes of AES, respectively.</dd>
+ <dt><a name="SIGINT">Signals intelligence (SIGINT)</a></dt>
+ <dd>Activities of government agencies from various nations aimed at
+ protecting their own communications and reading those of others.
+ Cryptography, cryptanalysis, wiretapping, interception and monitoring
+ of various sorts of signals. The players include the American <a
+ href="#NSA">NSA</a>, British <a href="#GCHQ">GCHQ</a> and Canadian <a
+ href="#CSE">CSE</a>.</dd>
+ <dt><a name="SKIP">SKIP</a></dt>
+ <dd><b>S</b>imple <b>K</b>ey management for <b>I</b>nternet
+ <b>P</b>rotocols, an alternative to <a href="#IKE">IKE</a> developed by
+ Sun and being marketed by their <a
+ href="http://skip.incog.com">Internet Commerce Group</a>.</dd>
+ <dt><a name="snake">Snake oil</a></dt>
+ <dd>Bogus cryptography. See the <a
+ href="http://www.interhack.net/people/cmcurtin/snake-oil-faq.html">
+ Snake Oil FAQ</a> or <a
+ href="http://www.counterpane.com/crypto-gram-9902.html#snakeoil">this
+ paper</a> by Schneier.</dd>
+ <dt><a name="SPI">SPI</a></dt>
+ <dd><b>S</b>ecurity <b>P</b>arameter <b>I</b>ndex, an index used within
+ <a href="#IPSEC">IPsec</a> to keep connections distinct. A <a
+ href="#SA">Security Association (SA)</a> is defined by destination,
+ protocol and SPI. Without the SPI, two connections to the same gateway
+ using the same protocol could not be distinguished.
+ <p>For more detail, see our <a href="ipsec.html">IPsec</a> section
+ and/or RFC 2401.</p>
+ </dd>
+ <dt><a name="SSH">SSH</a></dt>
+ <dd><b>S</b>ecure <b>SH</b>ell, an encrypting replacement for the
+ insecure Berkeley commands whose names begin with "r" for "remote":
+ rsh, rlogin, etc.
+ <p>For more information on SSH, including how to obtain it, see our
+ cryptography <a href="web.html#tools">links</a>.</p>
+ </dd>
+ <dt><a name="SSHco">SSH Communications Security</a></dt>
+ <dd>A company founded by the authors of <a href="#SSH">SSH</a>. Offices
+ are in <a href="http://www.ssh.fi">Finland</a> and <a
+ href="http://www.ipsec.com">California</a>. They have a toolkit for
+ developers of IPsec applications.</dd>
+ <dt><a name="SSL">SSL</a></dt>
+ <dd><a href="http://home.netscape.com/eng/ssl3">Secure Sockets Layer</a>,
+ a set of encryption and authentication services for web browsers,
+ developed by Netscape. Widely used in Internet commerce. Also known as
+ <a href="#TLS">TLS</a>.</dd>
+ <dt>SSLeay</dt>
+ <dd>A free implementation of <a href="#SSL">SSL</a> by Eric Young (eay)
+ and others. Developed in Australia; not subject to US export
+ controls.</dd>
+ <dt><a name="static">static IP address</a></dt>
+ <dd>an IP adddress which is pre-set on the machine itself, as opposed to
+ a <a href="#dynamic">dynamic address</a> which is assigned by a <a
+ href="#DHCP">DHCP</a> server or obtained as part of the process of
+ establishing a <a href="#PPP">PPP</a> or <a href="#PPPoE">PPPoE</a>
+ connection</dd>
+ <dt><a name="stream">Stream cipher</a></dt>
+ <dd>A <a href="#symmetric">symmetric cipher</a> which produces a stream
+ of output which can be combined (often using XOR or bytewise addition)
+ with the plaintext to produce ciphertext. Contrasts with <a
+ href="#block">block cipher</a>.
+ <p><a href="#IPSEC">IPsec</a> does not use stream ciphers. Their main
+ application is link-level encryption, for example of voice, video or
+ data streams on a wire or a radio signal.</p>
+ </dd>
+ <dt><a name="subnet">subnet</a></dt>
+ <dd>A group of IP addresses which are logically one network, typically
+ (but not always) assigned to a group of physically connected machines.
+ The range of addresses in a subnet is described using a subnet mask.
+ See next entry.</dd>
+ <dt>subnet mask</dt>
+ <dd>A method of indicating the addresses included in a subnet. Here are
+ two equivalent examples:
+ <ul>
+ <li>101.101.101.0/24</li>
+ <li>101.101.101.0 with mask 255.255.255.0</li>
+ </ul>
+ <p>The '24' is shorthand for a mask with the top 24 bits one and the
+ rest zero. This is exactly the same as 255.255.255.0 which has three
+ all-ones bytes and one all-zeros byte.</p>
+ <p>These indicate that, for this range of addresses, the top 24 bits
+ are to be treated as naming a network (often referred to as "the
+ 101.101.101.0/24 subnet") while most combinations of the low 8 bits can
+ be used to designate machines on that network. Two addresses are
+ reserved; 101.101.101.0 refers to the subnet rather than a specific
+ machine while 101.101.101.255 is a broadcast address. 1 to 254 are
+ available for machines.</p>
+ <p>It is common to find subnets arranged in a hierarchy. For example, a
+ large company might have a /16 subnet and allocate /24 subnets within
+ that to departments. An ISP might have a large subnet and allocate /26
+ subnets (64 addresses, 62 usable) to business customers and /29 subnets
+ (8 addresses, 6 usable) to residential clients.</p>
+ </dd>
+ <dt><a name="SWAN">S/WAN</a></dt>
+ <dd>Secure Wide Area Network, a project involving <a href="#RSAco">RSA
+ Data Security</a> and a number of other companies. The goal was to
+ ensure that all their <a href="#IPSEC">IPsec</a> implementations would
+ interoperate so that their customers can communicate with each other
+ securely.</dd>
+ <dt><a name="symmetric">Symmetric cryptography</a></dt>
+ <dd>Symmetric cryptography, also referred to as conventional or secret
+ key cryptography, relies on a <em>shared secret key</em>, identical for
+ sender and receiver. Sender encrypts with that key, receiver decrypts
+ with it. The idea is that an eavesdropper without the key be unable to
+ read the messages. There are two main types of symmetric cipher, <a
+ href="#block">block ciphers</a> and <a href="#stream">stream
+ ciphers</a>.
+ <p>Symmetric cryptography contrasts with <a href="#public">public
+ key</a> or asymmetric systems where the two players use different
+ keys.</p>
+ <p>The great difficulty in symmetric cryptography is, of course, key
+ management. Sender and receiver <em>must</em> have identical keys and
+ those keys <em>must</em> be kept secret from everyone else. Not too
+ much of a problem if only two people are involved and they can
+ conveniently meet privately or employ a trusted courier. Quite a
+ problem, though, in other circumstances.</p>
+ <p>It gets much worse if there are many people. An application might be
+ written to use only one key for communication among 100 people, for
+ example, but there would be serious problems. Do you actually trust all
+ of them that much? Do they trust each other that much? Should they?
+ What is at risk if that key is compromised? How are you going to
+ distribute that key to everyone without risking its secrecy? What do
+ you do when one of them leaves the company? Will you even know?</p>
+ <p>On the other hand, if you need unique keys for every possible
+ connection between a group of 100, then each user must have 99 keys.
+ You need either 99*100/2 = 4950 <em>secure</em> key exchanges between
+ users or a central authority that <em>securely</em> distributes 100 key
+ packets, each with a different set of 99 keys.</p>
+ <p>Either of these is possible, though tricky, for 100 users. Either
+ becomes an administrative nightmare for larger numbers. Moreover, keys
+ <em>must</em> be changed regularly, so the problem of key distribution
+ comes up again and again. If you use the same key for many messages
+ then an attacker has more text to work with in an attempt to crack that
+ key. Moreover, one successful crack will give him or her the text of
+ all those messages.</p>
+ <p>In short, the <em>hardest part of conventional cryptography is key
+ management</em>. Today the standard solution is to build a <a
+ href="#hybrid">hybrid system</a> using <a href="#public">public key</a>
+ techniques to manage keys.</p>
+ </dd>
+ <dt><a name="T">T</a></dt>
+ <dt><a name="TIS">TIS</a></dt>
+ <dd>Trusted Information Systems, a firewall vendor now part of <a
+ href="#NAI">NAI</a>. Their Gauntlet product offers IPsec VPN services.
+ TIS implemented the first version of <a href="#SDNS">Secure DNS</a> on
+ a <a href="#DARPA">DARPA</a> contract.</dd>
+ <dt><a name="TLS">TLS</a></dt>
+ <dd><b>T</b>ransport <b>L</b>ayer <b>S</b>ecurity, a newer name for <a
+ href="#SSL">SSL</a>.</dd>
+ <dt><a name="TOS">TOS field</a></dt>
+ <dd>The <strong>T</strong>ype <strong>O</strong>f
+ <strong>S</strong>ervice field in an IP header, used to control
+ qualkity of service routing.</dd>
+ <dt><a name="traffic">Traffic analysis</a></dt>
+ <dd>Deducing useful intelligence from patterns of message traffic,
+ without breaking codes or reading the messages. In one case during
+ World War II, the British guessed an attack was coming because all
+ German radio traffic stopped. The "radio silence" order, intended to
+ preserve security, actually gave the game away.
+ <p>In an industrial espionage situation, one might deduce something
+ interesting just by knowing that company A and company B were talking,
+ especially if one were able to tell which departments were involved, or
+ if one already knew that A was looking for acquisitions and B was
+ seeking funds for expansion.</p>
+ <p>In general, traffic analysis by itself is not very useful. However,
+ in the context of a larger intelligence effort where quite a bit is
+ already known, it can be very useful. When you are solving a complex
+ puzzle, every little bit helps.</p>
+ <p><a href="#IPSEC">IPsec</a> itself does not defend against traffic
+ analysis, but carefully thought out systems using IPsec can provide at
+ least partial protection. In particular, one might want to encrypt more
+ traffic than was strictly necessary, route things in odd ways, or even
+ encrypt dummy packets, to confuse the analyst. We discuss this <a
+ href="ipsec.html#traffic.resist">here</a>.</p>
+ </dd>
+ <dt><a name="transport">Transport mode</a></dt>
+ <dd>An IPsec application in which the IPsec gateway is the destination of
+ the protected packets, a machine acts as its own gateway. Contrast with
+ <a href="#tunnel">tunnel mode</a>.</dd>
+ <dt>Triple DES</dt>
+ <dd>see <a href="#3DES">3DES</a></dd>
+ <dt><a name="TTL">TTL</a></dt>
+ <dd><strong>T</strong>ime <strong>T</strong>o <strong>L</strong>ive, used
+ to control <a href="#DNS">DNS</a> caching. Servers discard cached
+ records whose TTL expires</dd>
+ <dt><a name="tunnel">Tunnel mode</a></dt>
+ <dd>An IPsec application in which an IPsec gateway provides protection
+ for packets to and from other systems. Contrast with <a
+ href="#transport">transport mode</a>.</dd>
+ <dt><a name="2key">Two-key Triple DES</a></dt>
+ <dd>A variant of <a href="#3DES">triple DES or 3DES</a> in which only two
+ keys are used. As in the three-key version, the order of operations is
+ <a href="#EDE">EDE</a> or encrypt-decrypt-encrypt, but in the two-key
+ variant the first and third keys are the same.
+ <p>3DES with three keys has 3*56 = 168 bits of key but has only 112-bit
+ strength against a <a href="#meet">meet-in-the-middle</a> attack, so it
+ is possible that the two key version is just as strong. Last I looked,
+ this was an open question in the research literature.</p>
+ <p>RFC 2451 defines triple DES for <a href="#IPSEC">IPsec</a> as the
+ three-key variant. The two-key variant should not be used and is not
+ implemented directly in <a href="#FreeSWAN">Linux FreeS/WAN</a>. It
+ cannot be used in automatically keyed mode without major fiddles in the
+ source code. For manually keyed connections, you could make Linux
+ FreeS/WAN talk to a two-key implementation by setting two keys the same
+ in /etc/ipsec.conf.</p>
+ </dd>
+ <dt><a name="U">U</a></dt>
+ <dt><a name="V">V</a></dt>
+ <dt><a name="virtual">Virtual Interface</a></dt>
+ <dd>A <a href="#Linux">Linux</a> feature which allows one physical
+ network interface to have two or more IP addresses. See the <cite>Linux
+ Network Administrator's Guide</cite> in <a
+ href="biblio.html#kirch">book form</a> or <a
+ href="http://metalab.unc.edu/LDP/LDP/nag/node1.html">on the web</a> for
+ details.</dd>
+ <dt>Virtual Private Network</dt>
+ <dd>see <a href="#VPN">VPN</a></dd>
+ <dt><a name="VPN">VPN</a></dt>
+ <dd><b>V</b>irtual <b>P</b>rivate <b>N</b>etwork, a network which can
+ safely be used as if it were private, even though some of its
+ communication uses insecure connections. All traffic on those
+ connections is encrypted.
+ <p><a href="#IPSEC">IPsec</a> is not the only technique available for
+ building VPNs, but it is the only method defined by <a
+ href="#RFC">RFCs</a> and supported by many vendors. VPNs are by no
+ means the only thing you can do with IPsec, but they may be the most
+ important application for many users.</p>
+ </dd>
+ <dt><a name="VPNC">VPNC</a></dt>
+ <dd><a href="http://www.vpnc.org">Virtual Private Network Consortium</a>,
+ an association of vendors of VPN products.</dd>
+ <dt><a name="W">W</a></dt>
+ <dt><a name="Wassenaar.gloss">Wassenaar Arrangement</a></dt>
+ <dd>An international agreement restricting export of munitions and other
+ tools of war. Unfortunately, cryptographic software is also restricted
+ under the current version of the agreement. <a
+ href="politics.html#Wassenaar">Discussion</a>.</dd>
+ <dt><a name="web">Web of Trust</a></dt>
+ <dd><a href="#PGP">PGP</a>'s method of certifying keys. Any user can sign
+ a key; you decide which signatures or combinations of signatures to
+ accept as certification. This contrasts with the hierarchy of <a
+ href="#CA">CAs (Certification Authorities)</a> used in many <a
+ href="#PKI">PKIs (Public Key Infrastructures)</a>.
+ <p>See <a href="#GTR">Global Trust Register</a> for an interesting
+ addition to the web of trust.</p>
+ </dd>
+ <dt><a name="WEP">WEP (Wired Equivalent Privacy)</a></dt>
+ <dd>The cryptographic part of the <a href="#IEEE">IEEE</a> standard for
+ wireless LANs. As the name suggests, this is designed to be only as
+ secure as a normal wired ethernet. Anyone with a network conection can
+ tap it. Its advocates would claim this is good design, refusing to
+ build in complex features beyond the actual requirements.
+ <p>Critics refer to WEP as "Wire<em>tap</em> Equivalent Privacy", and
+ consider it a horribly flawed design based on bogus "requirements". You
+ do not control radio waves as you might control your wires, so the
+ metaphor in the rationale is utterly inapplicable. A security policy
+ that chooses not to invest resources in protecting against certain
+ attacks which can only be conducted by people physically plugged into
+ your LAN may or may not be reasonable. The same policy is completely
+ unreasonable when someone can "plug in" from a laptop half a block
+ away..</p>
+ <p>There has been considerable analysis indicating that WEP is
+ seriously flawed. A FAQ on attacks against WEP is available. Part of it
+ reads:</p>
+
+ <blockquote>
+ ... attacks are practical to mount using only inexpensive
+ off-the-shelf equipment. We recommend that anyone using an 802.11
+ wireless network not rely on WEP for security, and employ other
+ security measures to protect their wireless network. Note that our
+ attacks apply to both 40-bit and the so-called 128-bit versions of
+ WEP equally well.</blockquote>
+ <p>WEP appears to be yet another instance of governments, and
+ unfortunately some vendors and standards bodies, deliberately promoting
+ hopelessly flawed "security" products, apparently mainly for the
+ benefit of eavesdropping agencies. See this <a
+ href="politics.html#weak">discussion</a>.</p>
+ </dd>
+ <dt><a name="X">X</a></dt>
+ <dt><a name="X509">X.509</a></dt>
+ <dd>A standard from the <a href="http://www.itu.int">ITU (International
+ Telecommunication Union)</a>, for hierarchical directories with
+ authentication services, used in many <a href="#PKI">PKI</a>
+ implementations.
+ <p>Use of X.509 services, via the <a href="#LDAP">LDAP protocol</a>,
+ for certification of keys is allowed but not required by the <a
+ href="#IPSEC">IPsec</a> RFCs. It is not yet implemented in <a
+ href="#FreeSWAN">Linux FreeS/WAN</a>.</p>
+ </dd>
+ <dt>Xedia</dt>
+ <dd>A vendor of router and Internet access products, now part of Lucent.
+ Their QVPN products interoperate with Linux FreeS/WAN; see our <a
+ href="interop.html#Xedia">interop document</a>.</dd>
+ <dt><a name="Y">Y</a></dt>
+ <dt><a name="Z">Z</a></dt>
+</dl>
+</body>
+</html>
diff --git a/doc/src/index.html b/doc/src/index.html
new file mode 100644
index 000000000..e2530d711
--- /dev/null
+++ b/doc/src/index.html
@@ -0,0 +1,55 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN index</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, encryption, cryptography, FreeS/WAN, FreeSWAN">
+ <!--
+
+ Written by Claudia Schmeing for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: index.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1>FreeS/WAN documentation</h1>
+
+<ul>
+ <li><a href="intro.html">Introduction</a></li>
+ <li><a href="upgrading.html">Upgrading to 2.x</a></li>
+</ul>
+
+<ul>
+ <li><a href="quickstart.html">Quickstart guide to Opportunistic Encryption</a></li>
+ <li><a href="install.html">Installing</a></li>
+ <li><a href="config.html">Configuring</a></li>
+ <li><a href="policygroups.html">Policy Groups</a>
+ </li>
+ <li><a href="interop.html">Interoperating</a>
+<FONT COLOR="#FF0000">New and improved!</FONT></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="trouble.html">Troubleshooting and problem reporting</a></li>
+</ul>
+
+<ul>
+ <li><a href="toc.html">Full table of contents, with much more</a></li>
+ <li><a href="HowTo.html">All our docs as one big file</a></li>
+</ul>
+
+<p>For technical support and other questions, use our <a
+href="mail.html">mailing lists</a>.</p>
+
+<pre> This index last changed: $Date: 2004/03/15 20:35:24 $</pre>
+
+</body>
+</html>
diff --git a/doc/src/initiatorstate.txt b/doc/src/initiatorstate.txt
new file mode 100644
index 000000000..315f6da4c
--- /dev/null
+++ b/doc/src/initiatorstate.txt
@@ -0,0 +1,66 @@
+
+ |
+ | PF_ACQUIRE
+ |
+ V
+ .---------------.
+ | non-existant |
+ | connection |
+ `---------------'
+ | | |
+ send , | \
+expired pass / | \ send
+conn. msg / | \ deny
+ ^ / | \ msg
+ | V | do \
+.---------------. | DNS \ .---------------.
+| clear-text | | lookup `->| deny |---> expired
+| connection | | for | connection | connection
+`---------------' | destination `---------------'
+ ^ ^ | ^
+ | | no record | |
+ | | OE-permissive V | no record
+ | | .---------------. | OE-paranoid
+ | `------------| potential OE |---------'
+ | | connection | ^
+ | `---------------' |
+ | | |
+ | | got TXT record | DNSSEC failure
+ | | reply |
+ | V | wrong
+ | .---------------. | failure
+ | | authenticate |---------'
+ | | & parse TXT RR| ^
+ | repeated `---------------' |
+ | ICMP | |
+ | failures | initiate IKE to |
+ | (short-timeout) | responder |
+ | V |
+ | phase-2 .---------------. | failure
+ | failure | pending |---------'
+ | (normal | OE | ^
+ | timeout) | |invalid | phase-2 failure (short-timeout)
+ | | |<--.SPI | ICMP failures (normal timeout)
+ | | | | |
+ | | +=======+ |---' |
+ | | | IKE | | ^ |
+ `--------------| | states|---------------'
+ | +=======+ | |
+ `---------------' |
+ | | invalid SPI
+ | |
+ V | rekey time
+ .--------------. |
+ | keyed |<---|-------------------------------.
+ | connection |----' |
+ `--------------' |
+ | |
+ | |
+ V |
+ .--------------. connection still active |
+ clear-text----->| expired |------------------------------------'
+ deny----->| connection |
+ `--------------'
+
+
+$Id: initiatorstate.txt,v 1.1 2004/03/15 20:35:24 as Exp $
diff --git a/doc/src/install.html b/doc/src/install.html
new file mode 100644
index 000000000..09d7c5a67
--- /dev/null
+++ b/doc/src/install.html
@@ -0,0 +1,378 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>Installing FreeS/WAN</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, installation, quickstart">
+ <!--
+
+ Written by Claudia Schmeing for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: install.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+<BODY>
+<H1><A name="install">Installing FreeS/WAN</A></H1>
+
+<P>This document will teach you how to install Linux FreeS/WAN.
+If your distribution comes with Linux FreeS/WAN, we offer
+ tips to get you started.</P>
+
+<H2>Requirements</H2>
+
+<P>To install FreeS/WAN you must:</P>
+<UL>
+<LI>be running Linux with the 2.4 or 2.2 kernel series. See
+this <A HREF="http://www.freeswan.ca/download.php#contact">kernel
+compatibility table</A>.<BR>We also have experimental support for
+2.6 kernels. Here are two basic approaches:
+<UL><LI>
+install FreeS/WAN, including its <A HREF="ipsec.html#parts">KLIPS</A>
+kernel code. This will remove the native IPsec stack and replace it
+with KLIPS.</LI>
+<LI>
+install the FreeS/WAN <A HREF="ipsec.html#parts">userland tools</A>
+(keying daemon and supporting
+scripts) for use with
+<A HREF="http://lartc.org/howto/lartc.ipsec.html">2.6 kernel native IPsec</A>,
+</LI>
+</UL>
+See also these <A HREF="2.6.known-issues">known issues with 2.6</A>.
+<LI>have root access to your Linux box</LI>
+<LI>choose the version of FreeS/WAN you wish to install based on
+<A HREF="http://www.freeswan.org/mail.html">mailing list reports</A> <!-- or
+our updates page (coming soon)--></LI>
+</UL>
+
+<H2>Choose your install method</H2>
+
+<P>There are three basic ways to get FreeS/WAN onto your system:</P>
+<UL>
+<LI>activating and testing a FreeS/WAN that <A HREF="#distroinstall">shipped
+with your Linux distribution</A></LI>
+<LI><A HREF="#rpminstall">RPM install</A></LI>
+<LI><A HREF="#srcinstall">Install from source</A></LI>
+</UL>
+
+<A NAME="distroinstall"></A><H2>FreeS/WAN ships with some Linuxes</H2>
+
+<P>FreeS/WAN comes with <A HREF="intro.html#distwith">these distributions</A>.
+
+<P>If you're running one of these, include FreeS/WAN in the choices you
+make during installation, or add it later using the distribution's tools.
+</P>
+
+<H3>FreeS/WAN may be altered...</H3>
+<P>Your distribution may have integrated extra features, such as Andreas
+Steffen's X.509 patch, into FreeS/WAN. It may also use custom
+startup script locations or directory names.</P>
+
+<H3>You might need to create an authentication keypair</H3>
+
+<P>If your FreeS/WAN came with your distribution, you may wish to
+ generate a fresh RSA key pair. FreeS/WAN will use these keys
+ for authentication.
+
+<P>
+To do this, become root, and type:
+</P>
+
+<PRE> ipsec newhostkey --output /etc/ipsec.secrets --hostname xy.example.com
+ chmod 600 /etc/ipsec.secrets</PRE>
+
+<P>where you replace xy.example.com with your machine's fully-qualified
+domain name. Generate some randomness, for example by wiggling your mouse,
+to speed the process.
+</P>
+
+<P>The resulting ipsec.secrets looks like:</P>
+<PRE>: RSA {
+ # RSA 2192 bits xy.example.com Sun Jun 8 13:42:19 2003
+ # for signatures only, UNSAFE FOR ENCRYPTION
+ #pubkey=0sAQOFppfeE3cC7wqJi...
+ Modulus: 0x85a697de137702ef0...
+ # everything after this point is secret
+ PrivateExponent: 0x16466ea5033e807...
+ Prime1: 0xdfb5003c8947b7cc88759065...
+ Prime2: 0x98f199b9149fde11ec956c814...
+ Exponent1: 0x9523557db0da7a885af90aee...
+ Exponent2: 0x65f6667b63153eb69db8f300dbb...
+ Coefficient: 0x90ad00415d3ca17bebff123413fc518...
+ }
+# do not change the indenting of that "}"</PRE>
+
+<P>In the actual file, the strings are much longer.</P>
+
+
+<H3>Start and test FreeS/WAN</H3>
+
+<P>You can now <A HREF="install.html#starttest">start FreeS/WAN and
+test whether it's been successfully installed.</A>.</P>
+
+
+<A NAME="rpminstall"></A><H2>RPM install</H2>
+
+<P>These instructions are for a recent Red Hat with a stock Red Hat kernel.
+We know that Mandrake and SUSE also produce FreeS/WAN RPMs. If you're
+running either, install using your distribution's tools.</P>
+
+<H3>Download RPMs</H3>
+
+<P>Decide which functionality you need:</P>
+<UL>
+<LI>standard FreeS/WAN RPMs. Use these shortcuts:<BR>
+<UL>
+<LI>(for 2.6 kernels: userland only)<BR>
+ncftpget ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs/\*userland*</LI>
+
+<LI>(for 2.4 kernels)<BR>
+ncftpget ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs/`uname -r | tr -d 'a-wy-z'`/\*</LI>
+<LI>
+or view all the offerings at our
+<A href="ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs">FTP site</A>.
+</LI></UL>
+</LI>
+<LI>unofficial
+<A href="http://www.freeswan.ca/download.php">Super FreeS/WAN</A>
+RPMs, which include Andreas Steffen's X.509 patch and more.
+Super FreeS/WAN RPMs do not currently include
+<A HREF="glossary.html#NAT.gloss">Network Address Translation</A>
+(NAT) traversal, but Super FreeS/WAN source does.</LI>
+</UL>
+
+<A NAME="2.6.rpm"></A>
+<P>For 2.6 kernels, get the latest FreeS/WAN userland RPM, for example:</P>
+<PRE> freeswan-userland-2.04.9-0.i386.rpm</PRE>
+
+<P>Note: FreeS/WAN's support for 2.6 kernel IPsec is preliminary. Please see
+<A HREf="2.6.known-issues">2.6.known-issues</A>, and the latest
+<A HREF="http://www.freeswan.org/mail.html">mailing list reports</A>.</P>
+<P>Change to your new FreeS/WAN directory, and make and install the
+
+<P>For 2.4 kernels, get both kernel and userland RPMs.
+Check your kernel version with</P>
+<PRE> uname -r</PRE>
+
+<P>Get a kernel module which matches that version. For example:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<P>Note: These modules
+<B>will only work on the Red Hat kernel they were built for</B>,
+since they are very sensitive to small changes in the kernel.</P>
+
+
+<P>Get FreeS/WAN utilities to match. For example:</P>
+<PRE> freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+
+
+<H3>For freeswan.org RPMs: check signatures</H3>
+
+<P>While you're at our ftp site, grab the RPM signing key</P>
+<PRE> freeswan-rpmsign.asc</PRE>
+
+<P>If you're running RedHat 8.x or later, import this key into the RPM
+database:</P>
+<PRE> rpm --import freeswan-rpmsign.asc</PRE>
+
+<P>For RedHat 7.x systems, you'll need to add it to your
+<A HREF="glossary.html#PGP">PGP</A> keyring:</P>
+<PRE> pgp -ka freeswan-rpmsign.asc</PRE>
+
+
+<P>Check the digital signatures on both RPMs using:</P>
+<PRE> rpm --checksig freeswan*.rpm </PRE>
+
+<P>You should see that these signatures are good:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK
+ freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK</PRE>
+
+
+<H3>Install the RPMs</H3>
+
+<P>Become root:</P>
+<PRE> su</PRE>
+
+<P>For a first time install, use:</P>
+<PRE> rpm -ivh freeswan*.rpm</PRE>
+
+<P>To upgrade existing RPMs (and keep all .conf files in place), use:</P>
+<PRE> rpm -Uvh freeswan*.rpm</PRE>
+
+<P>If you're upgrading from FreeS/WAN 1.x to 2.x RPMs, and encounter problems,
+see <A HREF="upgrading.html#upgrading.rpms">this note</A>.</P>
+
+
+<H3>Start and Test FreeS/WAN</H3>
+
+<P>Now, <A HREF="install.html#starttest">start FreeS/WAN and test your
+install</A>.</P>
+
+
+<A NAME="srcinstall"></A><H2>Install from Source</H2>
+<!-- Most of this section, along with "Start and Test", can replace
+INSTALL. -->
+
+<H3>Decide what functionality you need</H3>
+
+<P>Your choices are:</P>
+<UL>
+<LI><A HREF="ftp://ftp.xs4all.nl/pub/crypto/freeswan">standard
+FreeS/WAN</A>,</LI>
+<LI>standard FreeS/WAN plus any of these
+ <A HREF="web.html#patch">user-supported patches</A>, or</LI>
+<LI><A HREF="http://www.freeswan.ca/download">Super FreeS/WAN</A>,
+an unofficial FreeS/WAN pre-patched with many of the above. Provides
+additional algorithms, X.509, SA deletion, dead peer detection, and
+<A HREF="glossary.html#NAT.gloss">Network Address Translation</A>
+(NAT) traversal.</LI>
+</UL>
+
+<H3>Download FreeS/WAN</H3>
+
+<P>Download the source tarball you've chosen, along with any patches.</P>
+
+<H3>For freeswan.org source: check its signature</H3>
+
+<P>While you're at our ftp site, get our source signing key</P>
+<PRE> freeswan-sigkey.asc</PRE>
+
+<P>Add it to your PGP keyring:</P>
+<PRE> pgp -ka freeswan-sigkey.asc</PRE>
+
+
+<P>Check the signature using:</P>
+<PRE> pgp freeswan-2.04.tar.gz.sig freeswan-2.04.tar.gz</PRE>
+<P>You should see something like:</P>
+<PRE> Good signature from user "Linux FreeS/WAN Software Team (build@freeswan.org)".
+ Signature made 2002/06/26 21:04 GMT using 2047-bit key, key ID 46EAFCE1</PRE>
+<!-- Note to self: build@freeswan.org has angled brackets in the original.
+ Changed because it conflicts with HTML tags. -->
+
+<H3>Untar, unzip</H3>
+
+<P>As root, unpack your FreeS/WAN source into <VAR>/usr/src</VAR>.</P>
+<PRE> su
+ mv freeswan-2.04.tar.gz /usr/src
+ cd /usr/src
+ tar -xzf freeswan-2.04.tar.gz
+</PRE>
+
+<H3>Patch if desired</H3>
+
+<P>Now's the time to add any patches. The contributor may have special
+instructions, or you may simply use the patch command.</P>
+
+<H3>... and Make</H3>
+
+<P>Choose one of the methods below.</P>
+
+<H4>Userland-only Install for 2.6 kernels</H4>
+<A NAME="2.6.src"></A>
+
+<P>Note: FreeS/WAN's support for 2.6 kernel IPsec is preliminary. Please see
+<A HREf="2.6.known-issues">2.6.known-issues</A>, and the latest
+<A HREF="http://www.freeswan.org/mail.html">mailing list reports</A>.</P>
+<P>Change to your new FreeS/WAN directory, and make and install the
+FreeS/WAN userland tools.</P>
+<PRE> cd /usr/src/freeswan-2.04
+ make programs
+ make install</PRE>
+
+<P>Now, <A HREF="install.html#starttest">start FreeS/WAN and
+test your install</A>.</P>
+
+
+
+<H4>KLIPS install for 2.2, 2.4, or 2.6 kernels</H4>
+
+<A NAME="modinstall"></A>
+
+<P>To make a modular version of KLIPS, along with other FreeS/WAN programs
+you'll need, use the command sequence below. This will
+change to your new FreeS/WAN directory, make the FreeS/WAN module (and other
+stuff), and install it all.</P>
+<PRE> cd /usr/src/freeswan-2.04
+ make oldmod
+ make minstall</PRE>
+
+<P><A HREF="install.html#starttest">Start FreeS/WAN and
+test your install</A>.</P>
+
+
+
+<P>To link KLIPS statically into your kernel (using your old kernel settings),
+and install other FreeS/WAN components, do:
+</P>
+<PRE> cd /usr/src/freeswan-2.04
+ make oldmod
+ make minstall</PRE>
+
+
+<P>Reboot your system and <A HREF="install.html#testonly">test your
+install</A>.</P>
+
+<P>For other ways to compile KLIPS, see our Makefile.</P>
+
+
+
+<A name="starttest"></A><H2>Start FreeS/WAN and test your install</H2>
+
+<P>Bring FreeS/WAN up with:</P>
+<PRE> service ipsec start</PRE>
+
+<P>This is not necessary if you've rebooted.</P>
+
+<A name="testonly"></A><H2>Test your install</H2>
+
+<P>To check that you have a successful install, run:</P>
+<PRE> ipsec verify</PRE>
+
+<P>You should see at least:</P>
+<PRE>
+ Checking your system to see if IPsec got installed and started correctly
+ Version check and ipsec on-path [OK]
+ Checking for KLIPS support in kernel [OK]
+ Checking for RSA private key (/etc/ipsec.secrets) [OK]
+ Checking that pluto is running [OK]
+</PRE>
+
+<P>If any of these first four checks fails, see our
+<A href="trouble.html#install.check">troubleshooting guide</A>.
+</P>
+
+
+<H2>Making FreeS/WAN play well with others</H2>
+
+<P>There are at least a couple of things on your system that might
+interfere with FreeS/WAN, and now's a good time to check these:</P>
+<UL>
+ <LI>Firewalling. You need to allow UDP 500 through your firewall, plus
+ ESP (protocol 50) and AH (protocol 51). For more information, see our
+ updated firewalls document (coming soon).
+ </LI>
+ <LI>Network address translation.
+Do not NAT the packets you will be tunneling.</LI>
+</UL>
+
+
+<H2>Configure for your needs</H2>
+
+<P>You'll need to configure FreeS/WAN for your local site. Have a look at our
+<A HREF="quickstart.html">opportunism quickstart guide</A> to see if that
+easy method is right for your needs. Or, see how to <A HREF="config.html">
+configure a network-to-network or Road Warrior style VPN</A>.
+</P>
+
+
+
+
+</BODY>
+</HTML>
diff --git a/doc/src/interop.html b/doc/src/interop.html
new file mode 100644
index 000000000..dd4f8c577
--- /dev/null
+++ b/doc/src/interop.html
@@ -0,0 +1,1802 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN interoperation Grid</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, interoperation">
+ <!--
+
+ Written by Claudia Schmeing for the Linux FreeS/WAN project
+ With notes from Sandy Harris.
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: interop.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<A NAME="interop"></A><H1>Interoperating with FreeS/WAN</H1>
+
+
+<P>The FreeS/WAN project needs you! We rely on the user community to keep
+up to date. Mail users@lists.freeswan.org with your
+interop success stories.</P>
+
+<P><STRONG>Please note</STRONG>: Most of our interop examples feature
+Linux FreeS/WAN 1.x config files. You can convert them to 2.x files fairly
+easily with the patch in our
+<A HREF="upgrading.html#ipsec.conf_v2">Upgrading Guide</A>.
+</P>
+
+<H2>Interop at a Glance</H2>
+
+
+
+<TABLE BORDER="1">
+
+<TR>
+<TD>&nbsp;</TD>
+<TD colspan="5">FreeS/WAN VPN</TD>
+<TD>Road Warrior</TD>
+<TD>OE</TD>
+</TR>
+
+<TR>
+<TD>&nbsp;</TD>
+<TD>PSK</TD>
+<TD>RSA Secret</TD>
+<TD>X.509<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD>
+<TD>NAT-Traversal<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD>
+<TD>Manual<BR>Keying</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+</TR>
+
+
+<TR><TD colspan="8">More Compatible</TD></TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#freeswan">FreeS/WAN</A>
+<A NAME="freeswan.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#isakmpd">isakmpd (OpenBSD)</A>
+<A NAME="isakmpd.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No&nbsp;&nbsp;&nbsp;&nbsp;</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#kame">Kame (FreeBSD,
+<BR>NetBSD, MacOSX)
+<BR> <SMALL>aka racoon</SMALL></A>
+<A NAME="kame.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#mcafee">McAfee VPN<BR><SMALL>was PGPNet</SMALL></A>
+<A NAME="mcafee.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#microsoft">Microsoft <BR>Windows 2000/XP</A>
+<A NAME="microsoft.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+<TR>
+<TD><A HREF="#ssh">SSH Sentinel</A>
+<A NAME="ssh.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#safenet">Safenet SoftPK<BR>/SoftRemote</A>
+<A NAME="safenet.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<TR><TD colspan="8">Other</TD></TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#6wind">6Wind</A>
+<A NAME="6wind.top">&nbsp;</A></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#alcatel">Alcatel Timestep</A>
+<A NAME="alcatel.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#apple">Apple Macintosh<br>System 10+</A>
+<A NAME="apple.top">&nbsp;</A></TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#ashleylaurent">AshleyLaurent <BR>VPCom</A>
+<A NAME="ashleylaurent.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#borderware">Borderware</A>
+<A NAME="borderware.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+<!--
+http://www.cequrux.com/vpn-guides.php3
+"coming soon" guide to connect with FreeS/WAN.
+-->
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#checkpoint">Check Point FW-1/VPN-1</A>
+<A NAME="checkpoint.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#cisco">Cisco with 3DES</A>
+<A NAME="cisco.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#equinux">Equinux VPN Tracker <BR>
+(for Mac OS X)
+</A>
+<A NAME="equinux.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#fsecure">F-Secure</A>
+<A NAME="fsecure.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#gauntlet">Gauntlet GVPN</A>
+<A NAME="gauntlet.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#aix">IBM AIX</A>
+<A NAME="aix.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#as400">IBM AS/400</A>
+<A NAME="as400">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#intel">Intel Shiva<BR>LANRover/Net Structure</A>
+<A NAME="intel.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#lancom">LanCom (formerly ELSA)</A>
+<A NAME="lancom.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#linksys">Linksys</A>
+<A NAME="linksys.top">&nbsp;</A></TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#lucent">Lucent</A>
+<A NAME="lucent.top">&nbsp;</A></TD>
+<TD><FONT color="#cccc00">Partial</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#netasq">Netasq</A>
+<A NAME="netasq.top">&nbsp;</A></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#netcelo">netcelo</A>
+<A NAME="netcelo.top">&nbsp;</A></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#netgear">Netgear fvs318</A>
+<A NAME="netgear.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#netscreen">Netscreen 100<BR>or 5xp</A>
+<A NAME="netscreen.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#nortel">Nortel Contivity</A>
+<A NAME="nortel.top">&nbsp;</A></TD>
+<TD><FONT color="#cccc00">Partial</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#radguard">RadGuard</A>
+<A NAME="radguard.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#raptor">Raptor</A>
+<A NAME="raptor">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#redcreek">Redcreek Ravlin</A>
+<A NAME="redcreek.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT><FONT color="#cccc00">/Partial</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#sonicwall">SonicWall</A>
+<A NAME="sonicwall.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#sun">Sun Solaris</A>
+<A NAME="sun.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#symantec">Symantec</A>
+<A NAME="symantec.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#watchguard">Watchguard <BR>Firebox</A>
+<A NAME="watchguard.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#xedia">Xedia Access Point<BR>/QVPN</A>
+<A NAME="xedia.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+<TR>
+<TD><A HREF="#zyxel">Zyxel Zywall<BR>/Prestige</A>
+<A NAME="zyxel.top">&nbsp;</A></TD>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE
+
+
+<TR>
+<TD><A HREF="#sample">sample</A></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+<TD><FONT color="#cc0000">No</FONT></TD>
+</TR>
+
+-->
+
+<TR>
+<TD>&nbsp;</TD>
+<TD>PSK</TD>
+<TD>RSA Secret</TD>
+<TD>X.509<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD>
+<TD>NAT-Traversal<BR><SMALL><A HREF="#interoprules">(requires patch)</A></SMALL></TD>
+<TD>Manual<BR>Keying</TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD>&nbsp;</TD>
+<TD colspan="5">FreeS/WAN VPN</TD>
+<TD>Road Warrior</TD>
+<TD>OE</TD>
+</TR>
+
+
+
+<!-- PSK RSA X.509 NAT-T Manual RW OE -->
+
+</TABLE>
+
+
+
+
+<H3>Key</H3>
+<TABLE BORDER="1">
+
+<TR>
+<TD><FONT color="#00cc00">Yes</FONT></TD>
+<TD>People report that this works for them.</TD>
+</TR>
+
+<TR>
+<TD>[Blank]</TD>
+<TD>We don't know.</TD>
+</TR>
+
+<TR>
+<TD><FONT color="#cc0000">No</FONT></TD>
+<TD>We have reason to believe
+it was, at some point, not possible to get this to work.</TD>
+</TR>
+
+<TR>
+<TD><FONT color="#cccc00">Partial</FONT></TD>
+<TD>Partial success. For example, a connection can be
+created from one end only.</TD>
+</TR>
+
+<TR>
+<TD><FONT color="#00cc00">Yes</FONT><FONT color="#cccc00">/Partial</FONT></TD>
+<TD>Mixed reports.</TD>
+</TR>
+
+
+<TR>
+<TD><FONT color="#cccc00">Maybe</FONT></TD>
+<TD>We think the answer is "yes", but need confirmation.</TD>
+</TR>
+
+
+</TABLE>
+
+<A NAME="interoprules"></A><h2>Basic Interop Rules</h2>
+
+<P>Vanilla
+FreeS/WAN implements <A HREF="compat.html#compat">these parts</A> of the
+IPSec specifications. You can add more with
+<A HREF="http://www.freeswan.ca">Super FreeS/WAN</A>,
+but what we offer may be enough for many users.</P>
+<UL>
+<LI>
+To use X.509 certificates with FreeS/WAN, you will need
+the <A HREF="http://www.strongsec.org/freeswan">X.509 patch</a>
+or <A HREF="http://www.freeswan.ca">Super FreeS/WAN</A>,
+which includes that patch.</LI>
+<LI>
+To use
+<A HREF="glossary.html#NAT.gloss">Network Address Translation</A>
+(NAT) traversal
+with FreeS/WAN, you will need Arkoon Network Security's
+<A HREF="http://open-source.arkoon.net">NAT traversal patch</A>
+or <A HREF="http://www.freeswan.ca">Super FreeS/WAN</A>, which includes it.
+</LI>
+</UL>
+
+
+<P>We offer a set of proposals which is not user-adjustable, but covers
+all combinations that we can offer.
+FreeS/WAN always proposes triple DES encryption and
+Perfect Forward Secrecy (PFS).
+In addition, we propose Diffie Hellman groups 5 and 2
+(in that order), and MD5 and SHA-1 hashes.
+We accept the same proposals, in the same order of preference.
+</P>
+
+<P>Other interop notes:</P>
+<UL>
+<LI>
+A <A HREF="http://lists.freeswan.org/archives/users/2003-September/msg00462.html">SHA-1
+bug in FreeS/WAN 2.00, 2.01 and 2.02</A> may affect some
+interop scenarios. It does not affect 1.x versions, and is fixed in 2.03 and
+later.
+</LI>
+<LI>
+Some other implementations will close a connection with FreeS/WAN
+after some time. This may be a problem with rekey lifetimes. Please see
+<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00293.html">
+this tip</A> and
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-December/005758.html">
+this workaround</A>.
+</LI>
+</UL>
+
+<H2>Longer Stories</H2>
+
+
+<H3>For <EM>More Compatible</EM> Implementations</H3>
+
+
+<H4><A NAME="freeswan">FreeS/WAN</A></H4>
+
+<P>
+See our documentation at <A HREF="http://www.freeswan.org">freeswan.org</A>
+and the Super FreeS/WAN docs at
+<A HREF="http://www.freeswan.ca">freeswan.ca</A>.
+Some user-written HOWTOs for FreeS/WAN-FreeS/WAN connections
+are listed in <A HREF="intro.html#howto">our Introduction</A>.
+</P>
+
+<P>See also:</P>
+
+<UL>
+<LI>
+<A HREF="http://lugbe.ch/action/reports/ipsec_htbe.phtml">A German FreeS/WAN-FreeS/WAN page by Markus Wernig (X.509)</A>
+</LI>
+</UL>
+
+
+<P><A HREF="#freeswan.top">Back to chart</A></P>
+
+
+<H4><A NAME="isakmpd">isakmpd (OpenBSD)</A></H4>
+
+<P><A HREF="http://www.openbsd.org/faq/faq13.html">OpenBSD FAQ: Using IPsec</A><BR>
+<A HREF="http://www.rommel.stw.uni-erlangen.de/~hshoexer/ipsec-howto/HOWTO.html">Hans-Joerg Hoexer's interop Linux-OpenBSD (PSK)</A><BR>
+<A HREF="http://www.segfault.net/ipsec/">Skyper's configuration (PSK)</A>
+<BR>
+<A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+French page with configs (X.509)</A>
+
+
+</P>
+
+<P><A HREF="#isakmpd.top">Back to chart</A></P>
+
+
+<H4><A NAME="kame">Kame</A></H4>
+
+<UL>
+<LI>For FreeBSD and NetBSD. Ships with Mac OS X; see also our
+<A HREF="#apple">Mac</A> section.</LI>
+<LI>Also known as <EM>racoon</EM>, its keying daemon.</LI>
+</UL>
+
+<P><A HREF="http://www.kame.net">Kame homepage, with FAQ</A><BR>
+<A HREF="http://www.netbsd.org/Documentation/network/ipsec">NetBSD's IPSec FAQ</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00560.html">Ghislaine's post explaining some interop peculiarities</A>
+</P>
+<P>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/09/msg00511.html">Itojun's Kame-FreeS/WAN interop tips (PSK)</A><BR>
+<A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2000">Ghislaine Labouret's French page with links to matching FreeS/WAN and Kame configs (RSA)</A><BR>
+<A HREF="http://lugbe.ch/lostfound/contrib/freebsd_router/">Markus Wernig's
+HOWTO (X.509, BSD gateway)</A><BR>
+<A HREF="http://web.morgul.net/~frodo/docs/kame+freeswan_interop.html">Frodo's Kame-FreeS/WAN interop (X.509)</A><BR>
+<A HREF="http://www.wavesec.org/kame.phtml">Kame as a WAVEsec client.</A>
+</P>
+
+<P><A HREF="#kame.top">Back to chart</A></P>
+
+
+<H4><A NAME="mcafee">PGPNet/McAfee</A></H4>
+
+<P>
+<UL>
+<LI>Now called McAfee VPN Client.</LI>
+<LI>PGPNet also came in a freeware version which did not support subnets</LI>
+<LI>To support dhcp-over-ipsec, you need the X.509 patch, which is included in
+<A HREF="http://www.freeswan.ca">Super FreeS/WAN</A>.
+</LI>
+</UL>
+<P>
+<A HREF="http://www.freeswan.ca/docs/WindowsInterop">Tim Carr's Windows Interop Guide (X.509)</A><BR>
+<A HREF="http://www.rommel.stw.uni-erlangen.de/~hshoexer/ipsec-howto/HOWTO.html#Interop2"
+>Hans-Joerg Hoexer's Guide for Linux-PGPNet (PSK)</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/04/msg00339.html">Kai Martius' instructions using RSA Key-Extractor Tool (RSA)</A><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.zengl.net/freeswan/english.html">Christian Zeng's page (RSA)</A> based on Kai's work. English or German.<BR>
+<A HREF="http://tirnanog.ls.fi.upm.es/CriptoLab/Biblioteca/InfTech/InfTech_CriptoLab.htm">
+Oscar Delgado's PDF (X.509, no configs)</A><BR>
+<A HREF="http://www-ec.njit.edu/~rxt1077/Howto.txt">Ryan's HOWTO for FreeS/WAN-PGPNet (X.509)</A>. Through a Linksys Router with IPsec Passthru enabled.<BR>
+<A HREF="http://jixen.tripod.com/#RW-PGP-to-Fwan">Jean-Francois Nadeau's Practical Configuration (Road Warrior with PSK)</A><BR>
+<A HREF="http://www.evolvedatacom.nl/freeswan.html#toc">Wouter Prins' HOWTO (Road Warrior with X.509)</A><BR>
+</P>
+<P>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/01/msg00271.html">Rekeying problem with FreeS/WAN and older PGPNets</A><BR>
+</P>
+
+<P><A HREF="http://www.strongsec.com/freeswan/dhcprelay/index.htm">
+DHCP over IPSEC HOWTO for FreeS/WAN (requires X.509 and dhcprelay patches)
+</A>
+</P>
+
+<P><A HREF="#mcafee.top">Back to chart</A></P>
+
+
+<H4><A NAME="microsoft">Microsoft Windows 2000/XP</A></H4>
+
+<UL>
+<LI>IPsec comes with Win2k, and with XP Support Tools. May require
+<A HREF="http://www.microsoft.com/windows2000/downloads/recommended/encryption/default.asp"> High Encryption Pack</A>. WinXP users have also reported better
+results with Service Pack 1.</LI>
+<LI>The Road Warrior setup works either way round. Windows (XP or 2K) IPsec
+can connect as a Road Warrior to FreeS/WAN.
+However, FreeS/WAN can also successfully connect as a Road
+Warrior to Windows IPsec (see Nate Carlson's configs below).</LI>
+<LI>FreeS/WAN version 1.92 or later is required to avoid an interoperation
+problem with Windows native IPsec. Earlier FreeS/WAN versions
+did not process the Commit Bit as Windows native IPsec expected.</LI>
+</UL>
+
+<P>
+<A HREF="http://www.freeswan.ca/docs/WindowsInterop">Tim Carr's Windows Interop Guide (X.509)</A><BR>
+
+<A HREF="http://ipsec.math.ucla.edu/services/ipsec.html">James Carter's
+instructions (X.509, NAT-T)</A><BR>
+
+<A HREF="http://jixen.tripod.com/#Win2000-Fwan">
+Jean-Francois Nadeau's Net-net Configuration (PSK)</A><BR>
+
+<A HREF="http://security.nta.no/freeswan-w2k.html">
+Telenor's Node-node Config (Transport-mode PSK)</A><BR>
+
+<A HREF="http://vpn.ebootis.de">Marcus Mueller's HOWTO using his VPN config tool (X.509).</A> Tool also works with PSK.<BR>
+
+<A HREF="http://www.natecarlson.com/include/showpage.php?cat=linux&page=ipsec-x509">
+Nate Carlson's HOWTO using same tool (Road Warrior with X.509)</A>. Unusually,
+FreeS/WAN is the Road Warrior here.<BR>
+
+<A HREF="http://tirnanog.ls.fi.upm.es/CriptoLab/Biblioteca/InfTech/InfTech_CriptoLab.htm">
+Oscar Delgado's PDF (X.509, no configs)</A><BR>
+
+<A HREF="http://lists.freeswan.org/pipermail/users/2003-July/022425.html">Tim Scannell's Windows XP Additional Checklist (X.509)</A><BR>
+</P>
+
+<!-- Note to self: Include L2TP references? -->
+
+<P>
+<A HREF="http://www.microsoft.com/windows2000/en/server/help/default.asp?url=/windows2000/en/server/help/sag_TCPIP_ovr_secfeatures.htm">
+Microsoft's page on Win2k TCP/IP security features</A><BR>
+
+<A HREF="http://support.microsoft.com/support/kb/articles/Q257/2/25.ASP">
+Microsoft's Win2k IPsec debugging tips</A><BR>
+
+<!-- Alt-URL http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257225
+Perhaps newer? -->
+
+<A HREF="http://www.wired.com/news/technology/0,1282,36336,00.html">MS VPN may fall back to 1DES</A>
+</P>
+
+<P><A HREF="#microsoft.top">Back to chart</A></P>
+
+
+<H4><A NAME="ssh">SSH Sentinel</A></H4>
+
+<UL>
+<LI>Popular and well tested.</LI>
+<LI>Also rebranded in <A HREF="http://www.zyxel.com">Zyxel Zywall</A>.
+Our Zyxel interop notes are <A HREF="#zyxel">here</A>.</LI>
+<LI>
+SSH supports IPsec-over-UDP NAT traversal.
+</LI>
+<LI>There is this
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/12/msg00370.html">
+potential problem</A> if you're not using the Legacy Proposal option.
+</UL>
+
+<P>
+<A HREF="http://www.ssh.com/support/sentinel/documents.cfm">SSH's Sentinel-FreeSWAN interop PDF (X.509)</A><BR>
+<A HREF="http://www.nadmm.com/show.php?story=articles/vpn.inc">Nadeem Hassan's
+SUSE-to-Sentinel article (Road warrior with X.509)</A><BR>
+<A HREF="http://www.zerozone.it/documents/Linux/HowTo/VPN-IPsec-Freeswan-HOWTO.html">O-Zone's Italian HOWTO (Road Warrior, X.509, DHCP)</A><BR>
+</P>
+
+
+<P><A HREF="#ssh.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="safenet">Safenet SoftPK/SoftRemote</A></H4>
+
+<UL>
+<LI>People recommend SafeNet as a low cost Windows client.</LI>
+<LI>SoftRemote seems to be the newer name for SoftPK.</LI>
+</UL>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005061.html">
+Whit Blauvelt's SoftRemote tips</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015591.html">
+Tim Wilson's tips (X.509)</A>
+<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00607.html">Workaround for a "gotcha"</A>
+</P>
+
+<P>
+<A HREF="http://jixen.tripod.com/#Rw-IRE-to-Fwan">Jean-Francois Nadeau's
+Practical Configuration (Road Warrior with PSK)</A><BR>
+<A HREF="http://www.terradoncommunications.com/security/whitepapers/safe_net-to-free_swan.pdf">
+Terradon Communications' PDF (Road Warrior with PSK)</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-October/?????.html">
+Seaan.net's PDF (Road Warrior to Subnet, with PSK)
+</A><BR>
+<A HREF="http://www.redbaronconsulting.com/freeswan/fswansafenet.pdf">
+Red Baron Consulting's PDF (Road Warrior with X.509)</A>
+</P>
+
+<P><A HREF="#safenet.top">Back to chart</A></P>
+
+
+
+
+
+
+
+
+<H3>For <EM>Other Implementations</EM></H3>
+
+
+
+<H4><A NAME="6wind">6Wind</A></H4>
+
+<P>
+
+<A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+French page with configs (X.509)</A>
+
+</P>
+
+<P><A HREF="#6wind.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="alcatel">Alcatel Timestep</A></H4>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-June/011878.html">
+Alain Sabban's settings (PSK or PSK road warrior; through static NAT)</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/1999/06/msg00100.html">
+Derick Cassidy's configs (PSK)</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/1999/08/msg00194.html">
+David Kerry's Timestep settings (PSK)</A>
+<BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013711.html">
+Kevin Gerbracht's ipsec.conf (X.509)</A>
+</P>
+
+<P><A HREF="#alcatel.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="apple">Apple Macintosh System 10+</A></H4>
+
+<UL>
+<LI>Since the system is based on FreeBSD, this should
+interoperate <A HREF="#kame">just like FreeBSD</A>.
+</LI>
+
+<LI>
+To use Appletalk over IPsec tunnels,
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005116.html">run
+it over TCP/IP</A>, or use
+Open Door Networks' Shareway IP tool,
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005426.html">described
+here.</A>
+</LI>
+
+<LI>See also the <A HREF="#equinux">Equinux VPN Tracker</A>
+for Mac OS X.</LI>
+</UL>
+
+
+<P>
+<A HREF="http://ipsec.math.ucla.edu/services/ipsec.html">James Carter's
+instructions (X.509, NAT-T)</A>
+</P>
+
+
+<P><A HREF="#apple.top">Back to chart</A></P>
+
+
+
+
+
+
+<H4><A NAME="ashleylaurent">AshleyLaurent VPCom</A></H4>
+
+<P>
+<A HREF="http://www.ashleylaurent.com/newsletter/01-28-00.htm">
+Successful interop report, no details</A>
+</P>
+
+<P><A HREF="#ashleylaurent.top">Back to chart</A></P>
+
+
+<H4><A NAME="borderware">Borderware</A></H4>
+
+<UL>
+<LI>I suspect the Borderware client is a rebranded Safenet.
+If that's true, our <A HREF="#safenet">Safenet section</A> will help.</LI>
+</UL>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-March/008288.html">
+Philip Reetz' configs (PSK)</A><BR>
+
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/09/msg00217.html">
+Borderware server does not support FreeS/WAN road warriors</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007733.html">
+Older Borderware may not support Diffie Hellman groups 2, 5</A><BR>
+</P>
+
+
+<P><A HREF="#borderware.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="checkpoint">Check Point VPN-1 or FW-1</A></H4>
+
+<UL>
+<LI>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00099.html">
+Caveat about IP-range inclusion on Check Point.</A>
+</LI>
+<LI>
+Some versions of Check Point may require an aggressive mode patch to
+interoperate with FreeS/WAN.<BR>
+<A HREF="http://www.freeswan.ca/code/super-freeswan">Super FreeS/WAN</A>
+now features this patch.
+<!--
+<A HREF="http://www.freeswan.ca/patches/aggressivemode">Steve Harvey's
+aggressive mode patch for FreeS/WAN 1.5</A>
+-->
+</LI>
+<LI>
+<LI>A Linux FreeS/WAN-Checkpoint connection may close after some time. Try
+<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00293.html">this tip</A> toward a workaround.
+</LI>
+</UL>
+
+<P>
+<A HREF="http://www.fw-1.de/aerasec/ng/vpn-freeswan/CPNG+Linux-FreeSWAN.html">
+AERAsec's Firewall-1 NG site (PSK, X.509, Road Warrior with X.509,
+other algorithms)</A><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;
+<A HREF="http://www.fw-1.de/aerasec/ng/vpn-freeswan/CPNG+Linux-FreeSWAN.html#support-matrix">
+AERAsec's detailed Check Point-FreeS/WAN support matrix</A><BR>
+<A HREF="http://support.checkpoint.com/kb/docs/public/firewall1/4_1/pdf/fw-linuxvpn.pdf">Checkpoint.com PDF: Linux as a VPN Client to FW-1 (PSK)</A><BR>
+
+<A HREF="http://www.phoneboy.com">PhoneBoy's Check Point FAQ (on Check Point
+only, not FreeS/WAN)</A><BR>
+
+</P>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-August/002351.html">Chris
+Harwell's tips & FreeS/WAN configs (PSK)</A><BR>
+
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009362.html">Daniel
+Tombeil's configs (PSK)</A>
+
+</P>
+
+<P><A HREF="#checkpoint.top">Back to chart</A></P>
+
+
+<H4><A NAME="cisco">Cisco</A></H4>
+
+<UL>
+<LI>
+Cisco supports IPsec-over-UDP NAT traversal.
+</LI>
+<LI>Cisco VPN Client appears to use nonstandard IPsec and
+does not work with FreeS/WAN. <A HREF="https://mj2.freeswan.org/archives/2003-August/maillist.html">This message</A> concerns Cisco VPN Client 4.01.
+<!-- fix link -->
+</LI>
+<LI>A Linux FreeS/WAN-Cisco connection may close after some time.
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-December/005758.html">
+Here</A>
+is a workaround, and
+<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00293.html">here</A>
+ is another comment on the same subject.</LI>
+<LI><A HREF="http://www.cisco.com/univercd/cc/td/doc/product/software/ios120/120newft/120t/120t2/3desips.htm">Older Ciscos</A>
+purchased outside the United States may not have 3DES, which FreeS/WAN requires.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2001-June/000406.html">RSA keying may not be possible between Cisco and FreeS/WAN.</A>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2001-October/004357.html">In
+ipsec.conf, VPN3000 DN (distinguished name) must be in binary (X.509 only)</A></LI>
+
+
+</UL>
+
+
+<P>
+<A HREF="http://rr.sans.org/encryption/cisco_router.php">SANS Institute HOWTO (PSK).</A> Detailed, with extensive references.<BR>
+<A HREF="http://www.worldbank.ro/IPSEC/cisco-linux.txt">Short HOWTO (PSK)</A><BR>
+<A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+French page with configs for Cisco IOS, PIX and VPN 3000 (X.509)</A>
+<BR>
+
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-August/002966.html">Dave
+McFerren's sample configs (PSK)</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-September/003422.html">Wolfgang
+Tremmel's sample configs (PSK road warrior)</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00578.html">
+Old doc from Pete Davis, with William Watson's updated Tips (PSK)</A><BR>
+</P>
+
+<P><STRONG>Some PIX specific information:</STRONG><BR>
+
+<A HREF="http://www.wlug.org.nz/FreeSwanToCiscoPix">
+Waikato Linux Users' Group HOWTO. Nice detail (PSK)
+</A><BR>
+<A HREF="http://www.johnleach.co.uk/documents/freeswan-pix/freeswan-pix.html">
+John Leach's configs (PSK)
+</A><BR>
+<A HREF="http://www.diverdown.cc/vpn/freeswanpix.html">
+Greg Robinson's settings (PSK)
+</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007901.html">
+Scott's ipsec.conf for PIX (PSK, FreeS/WAN side only)</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-October/003949.html">Rick
+Trimble's PIX and FreeS/WAN settings (PSK)</A><BR>
+</P>
+
+
+
+<P><A href="http://www.cisco.com/public/support/tac">
+Cisco VPN support page</A><BR>
+<A href="http://www.ieng.com/warp/public/707/index.shtml#ipsec">
+Cisco IPsec information page</A>
+</P>
+
+<P><A HREF="#cisco.top">Back to chart</A></P>
+
+
+
+
+<H4><A NAME="equinux">Equinux VPN tracker (for Mac OS X)</A></H4>
+
+<UL>
+<LI>Graphical configurator for Mac OS X IPsec. May be an interface
+to the <A HREF="#apple">native Mac OS X IPsec</A>, which is essentially
+<A HREF="#kame">KAME</A>.</LI>
+<LI>To use Appletalk over IPsec tunnels,
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005116.html">run
+it over TCP/IP</A>, or use
+Open Door Networks' Shareway IP tool,
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005426.html">described
+here.</A> </LI>
+</UL>
+
+
+<P>
+Equinux provides <A HREF="http://www.equinux.com/download/HowTo_FreeSWAN.pdf">this
+excellent interop PDF</A> (PSK, RSA, X.509).
+</P>
+
+<P><A HREF="#equinux.top">Back to chart</A></P>
+
+
+<H4><A NAME="fsecure">F-Secure</A></H4>
+
+<UL>
+<LI>
+<!-- <A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007596.html"> -->
+F-Secure supports IPsec-over-UDP NAT traversal.
+</LI>
+</UL>
+
+<P><A HREF="http://www.pingworks.de/tech/vpn/vpn.txt">pingworks.de's
+ "Connecting F-Secure's VPN+ to Linux FreeS/WAN" (PSK road warrior)</A><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="http://www.pingworks.de/tech/vpn/vpn.pdf">Same thing as PDF</A><BR>
+<A HREF="http://www.exim.org/pipermail/linux-ipsec/Week-of-Mon-20010122/000061.html">Success report, no detail (PSK)</A><BR>
+<A HREF="http://www.exim.org/pipermail/linux-ipsec/Week-of-Mon-20010122/000041.html">Success report, no detail (Manual)</A>
+</P>
+
+<!-- Other NAT traversers:
+http://lists.freeswan.org/pipermail/users/2002-April/009136.html
+and ssh sentinel:
+http://lists.freeswan.org/pipermail/users/2001-September/003108.html
+-->
+
+<P><A HREF="#fsecure.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="gauntlet">Gauntlet GVPN</A></H4>
+
+<P>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00535.html">Richard Reiner's ipsec.conf (PSK)</A>
+<BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-June/011434.html">
+Might work without that pesky firewall... (PSK)</A><BR>
+<!-- insert archive link -->
+In late July, 2003 Alexandar Antik reported success interoperating
+with Gauntlet 6.0 for Solaris (X.509). Unfortunately the message is not
+properly archived at this time.
+</P>
+
+<P><A HREF="#gauntlet.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="aix">IBM AIX</A></H4>
+
+<P><A HREF="http://www-1.ibm.com/servers/esdd/articles/security.html">
+IBM's "Built-In Network Security with AIX" (PSK, X.509)</A><BR>
+<A HREF="http://www-1.ibm.com/servers/aix/products/ibmsw/security/vpn/faqandtips/#ques20">
+IBM's tip: importing Linux FreeS/WAN settings into AIX's <VAR>ikedb</VAR>
+(PSK)</A>
+</P>
+
+<P><A HREF="#aix.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="as400">IBM AS/400</A></H4>
+
+<UL>
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009106.html">Road
+ Warriors may act flaky</A>.
+</LI>
+</UL>
+
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-September/014264.html">
+Richard Welty's tips and tricks</A><BR>
+</P>
+
+<P><A HREF="#as400.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="intel">Intel Shiva LANRover / Net Structure</A></H4>
+
+<UL>
+<LI>Intel Shiva LANRover is now known as Intel Net Structure.</LI>
+<LI>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/01/msg00298.html">
+Shiva seems to have two modes: IPsec or the proprietary
+"Shiva Tunnel".</A>
+Of course, FreeS/WAN will only create IPsec tunnels.
+</LI>
+
+<LI>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00293.html">
+AH may not work for Shiva-FreeS/WAN.</A>
+That's OK, since FreeS/WAN has phased out the use of AH.
+</LI>
+</UL>
+
+<P>
+<A HREF="http://snowcrash.tdyc.com/freeswan/">
+Snowcrash's configs (PSK)</A><BR>
+
+<A HREF="http://www.opus1.com/vpn/index.html">
+Old configs from an interop (PSK)</A><BR>
+
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-October/003831.html">
+The day Shiva tickled a Pluto bug (PSK)</A><BR>
+
+&nbsp;&nbsp;&nbsp;&nbsp;
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-October/004270.html">
+Follow up: success!</A>
+</P>
+
+<P><A HREF="#intel.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="lancom">LanCom (formerly ELSA)</A></H4>
+
+<UL>
+<LI>This router is popular in Germany.
+</UL>
+
+<P>
+Jakob Curdes successfully created a PSK connection with the LanCom 1612 in
+August 2003.
+<!-- add ML link when it appears -->
+</P>
+
+<P><A HREF="#lancom.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="linksys">Linksys</A></H4>
+
+<UL>
+<LI>Linksys may be used as an IPsec tunnel endpoint, <STRONG>OR</STRONG>
+as a router in "IPsec passthrough" mode, so that the IPsec tunnel
+passes through the Linksys.
+</LI>
+</UL>
+
+<H5>As tunnel endpoint</H5>
+<P>
+<A HREF="http://www.freeswan.ca/docs/BEFVP41/">
+Ken Bantoft's instructions (Road Warrior with PSK)</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-February/007814.html">
+Nate Carlson's caveats</A>
+</P>
+
+<H5>In IPsec passthrough mode</H5>
+<P>
+<A HREF="http://www-ec.njit.edu/~rxt1077/Howto.txt">
+Sample HOWTO through a Linksys Router</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2002/02/msg00114.html">
+Nadeem Hasan's configs</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2002/02/msg00180.html">
+Brock Nanson's tips</A><BR>
+</P>
+
+<P><A HREF="#linksys.top">Back to chart</A></P>
+
+
+<H4><A NAME="lucent">Lucent</A></H4>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010976.html">
+Partial success report; see also the next message in thread</A>
+</P>
+<!-- section done -->
+
+<P><A HREF="#lucent.top">Back to chart</A></P>
+
+
+<H4><A NAME="netasq">Netasq</A></H4>
+
+<P>
+<A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+French page with configs (X.509)</A>
+
+</P>
+<!-- section done -->
+
+<P><A HREF="#netasq.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="netcelo">Netcelo</A></H4>
+
+<P>
+<A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+French page with configs (X.509)</A>
+
+<!-- section done -->
+
+</P>
+
+<P><A HREF="#netcelo.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="netgear">Netgear fvs318</A></H4>
+
+<UL>
+<LI>With a recent Linux FreeS/WAN, you will require the latest
+(12/2002) Netgear firmware, which supports Diffie-Hellman (DH) group 2.
+For security reasons, we phased out DH 1 after Linux FreeS/WAN 1.5.
+</LI>
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-June/011833.html">
+This message</A> reports the incompatibility between Linux FreeS/WAN 1.6+
+and Netgear fvs318 without the firmware upgrade.
+</LI>
+<LI>We believe Linux FreeS/WAN 1.5 and earlier will interoperate with
+any NetGear firmware.
+</LI>
+</UL>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2003-February/017891.html">
+John Morris' setup (PSK)</A>
+</P>
+
+<P><A HREF="#netgear.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="netscreen">Netscreen 100 or 5xp</A></H4>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013409.html">
+Errol Neal's settings (PSK)</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015265.html">
+Corey Rogers' configs (PSK, no PFS)</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013051.html">
+Jordan Share's configs (PSK, 2 subnets, through static NAT)</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/08/msg00404.html">
+Set src proxy_id to your protected subnet/mask</A><BR>
+
+<A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+French page with ipsec.conf, Netscreen screen shots (X.509, may
+need to revert to PSK...)</A>
+
+</P>
+<P>
+<A HREF="http://archives.neohapsis.com/archives/sf/linux/2001-q2/0123.html">
+A report of a company using Netscreen with FreeS/WAN on a large scale
+(FreeS/WAN road warriors?)</A>
+</P>
+
+<P><A HREF="#netscreen.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="nortel">Nortel Contivity</A></H4>
+
+<UL>
+<LI>
+Nortel supports IPsec-over-UDP NAT traversal.
+</LI>
+
+<LI>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00417.html">
+Some older versions of Contivity and FreeS/WAN will not communicate.</A>
+</LI>
+
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010924.html">
+FreeS/WAN cannot be used as a "client" to a Nortel Contivity server,
+but can be used as a branch-office tunnel.</A>
+</LI>
+
+<!-- Probably obsoleted by Ken's post
+<LI>
+(Matthias siebler from old interop)
+At one point you could not configure Nortel-FreeS/WAN tunnels as
+"Client Tunnels" since FreeS/WAN does not support Aggressive Mode.
+Current status of this problem: unknown.
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/004612.html">
+How do we map group and user passwords onto the data that FreeS/WAN wants?
+</A>
+</LI>
+-->
+
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015455.html">
+Contivity does not send Distinguished Names in the order FS wants them (X.509).
+</A>
+</LI>
+
+<LI>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/03/msg00137.html">
+Connections may time out after 30-40 minutes idle.</A>
+</LI>
+
+</UL>
+
+<P>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/03/msg00137.html">
+JJ Streicher-Bremer's mini HOWTO for old & new software. (PSK with two subnets)
+</A><BR>
+<A HREF="http://www.hsc.fr/ressources/ipsec/ipsec2001/#config">
+French page with configs (X.509)</A>. This succeeds using the above X.509 tip.
+</P>
+
+<!-- I could do more searching but this is a solid start. -->
+
+<P><A HREF="#nortel.top">Back to chart</A></P>
+
+
+<H4><A NAME="radguard">Radguard</A></H4>
+
+<P>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/05/msg00009.html">
+Marko Hausalo's configs (PSK).</A> Note: These do create a connection,
+as you can see by "IPsec SA established".<BR>
+
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-October/???.html">
+Claudia Schmeing's comments</A>
+</P>
+
+<P><A HREF="#radguard.top">Back to chart</A></P>
+
+
+<H4><A NAME="raptor">Raptor (NT or Solaris)</A></H4>
+
+<P>
+
+<UL>
+<LI>Now known as Symantec Enterprise Firewall.</LI>
+<LI>The Raptor does not normally come with X.509, but this may be available as
+an add-on.</LI>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010256.html">
+Raptor requires alphanumberic PSK values, whereas FreeS/WAN uses hex.</A>
+</LI>
+<LI>Raptor's tunnel endpoint may be a host, subnet or group of subnets
+(see
+<A HREF="http://lists.freeswan.org/pipermail/design/2001-November/001295.html">
+this message</A>
+). FreeS/WAN cannot handle the group of subnets; you
+must create separate connections for each in order to interoperate.</LI>
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010113.html">
+Some versions of Raptor accept only single DES.
+</A>
+According to this German message,
+<A HREF="http://radawana.cg.tuwien.ac.at/mail-archives/lll/200012/msg00065.html">
+the Raptor Mobile Client demo offers single DES only.</A>
+</LI>
+</UL>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-January/006935.html">
+Peter Mazinger's settings (PSK)</A><BR>
+
+<A HREF="http://lists.freeswan.org/pipermail/users/2001-November/005522.html">
+Peter Gerland's configs (PSK)</A><BR>
+
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/07/msg00597.html">
+Charles Griebel's configs (PSK).</A><BR>
+
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-July/012275.html">
+Lumir Srch's tips (PSK)
+</A>
+</P>
+
+<P>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/05/msg00214.html">
+John Hardy's configs (Manual)</A><BR>
+
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/01/msg00236.html">
+Older Raptors want 3DES keys in 3 parts (Manual).</A><BR>
+
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/06/msg00480.html">
+Different keys for each direction? (Manual)</A><BR>
+
+</P>
+
+<P><A HREF="#raptor.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="redcreek">Redcreek Ravlin</A></H4>
+
+<UL>
+<LI>Known issue #1: The Ravlin expects a quick mode renegotiation right
+after every Main Mode negotiation.
+</LI>
+<LI>
+Known issue #2: The Ravlin tries to negotiate a zero
+connection lifetime, which it takes to mean "infinite".
+<A HREF="http://www.bear-cave.org.uk/linux/ravlin/">Jim Hague's patch</A>
+addresses both issues.
+</LI>
+<LI>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/03/msg00191.html">
+Interop works with Ravlin Firmware > 3.33. Includes tips (PSK).</A>
+</LI>
+</UL>
+
+<P><A HREF="#redcreek.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="sonicwall">SonicWall</A></H4>
+
+<UL>
+<LI><A HREF="http://lists.freeswan.org/pipermail/users/2001-June/000998.html">
+Sonicwall cannot be used for Road Warrior setups</A></LI>
+<LI>
+At one point, <A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/05/msg00217.html">
+only Sonicwall PRO supported triple DES</A>.</LI>
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-March/008600.html">
+Older Sonicwalls (before Nov 2001) feature Diffie Hellman group 1
+only</A>.</LI>
+</UL>
+
+<P>
+<A HREF="http://www.xinit.cx/docs/freeswan.html">Paul Wouters' config (PSK)</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00073.html">
+Dilan Arumainathan's configuration (PSK)</A><BR>
+<A HREF="http://www.gravitas.co.uk/vpndebug">Dariush's setup... only opens
+one way (PSK)</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2003-July/022302.html">
+Andreas Steffen's tips (X.509)</A><BR>
+
+</P>
+
+<P><A HREF="#sonicwall.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="sun">Sun Solaris</A></H4>
+
+<UL>
+<LI>
+Solaris 8+ has a native (in kernel) IPsec implementation.
+</LI>
+<LI>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-May/010503.html">
+Solaris does not seem to support tunnel mode, but you can make
+IP-in-IP tunnels instead, like this.</A>
+</LI>
+</UL>
+<P>
+
+<A HREF="http://lists.freeswan.org/pipermail/users/2003-June/022216.html">Reports of some successful interops</A> from a fellow @sun.com.
+See also <A HREF="http://lists.freeswan.org/pipermail/users/2003-July/022247.html">these follow up posts</A>.<BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/03/msg00332.html">
+Aleks Shenkman's configs (Manual in transport mode)
+</A><BR>
+<!--sparc 64 stuff goes where?-->
+</P>
+
+<P><A HREF="#solaris.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="symantec">Symantec</A></H4>
+
+<UL>
+<LI>The Raptor, covered <A HREF="#raptor">above</A>, is now known as
+Symantec Enterprise Firewall.</LI>
+<LI>Symantec's "distinguished name" is a KEY_ID. See Andreas Steffen's post,
+below.</LI>
+</UL>
+
+<P><A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009037.html">
+Andreas Steffen's configs for Symantec 200R (PSK)</A>
+</P>
+
+<P><A HREF="#symantec.top">Back to chart</A></P>
+
+
+
+
+<H4><A NAME="watchguard">Watchguard Firebox</A></H4>
+
+<UL>
+<LI>Automatic keying works with WatchGuard 5.0+ only.</LI>
+<LI>Seen to interoperate with WatchGuard 1000, II, III; firmware v. 5, 6..</LI>
+<LI>For manual keying, Watchguard's Policy Manager expects SPI numbers and
+encryption and authentication keys in decimal (not hex).</LI>
+</UL>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-July/012595.html">
+WatchGuard's HOWTO (PSK)</A><BR>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-August/013342.html">
+Ronald C. Riviera's Settings (PSK)</A><BR>
+<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00179.html">
+Walter Wickersham's Notes (PSK)</A><BR>
+
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-October/015587.html">
+Max Enders' Configs (Manual)</A>
+</P>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/users/2002-April/009404.html">
+Old known issue with auto keying</A><BR>
+
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/02/msg00124.html">
+Tips on key generation and format (Manual)</A><BR>
+</P>
+
+<P><A HREF="#watchguard.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="xedia">Xedia Access Point/QVPN</A></H4>
+
+<P>
+<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2001/12/msg00520.html">
+Hybrid IPsec/L2TP connection settings (X.509)
+</A><BR>
+<A HREF="http://www.sandelman.ottawa.on.ca/ipsec/1999/08/msg00140.html">
+ Xedia's LAN-LAN links don't use multiple tunnels
+</A><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;
+<A HREF="http://www.sandelman.ottawa.on.ca/ipsec/1999/08/msg00140.html">
+ That explanation, continued
+</A>
+</P>
+
+<P><A HREF="#xedia.top">Back to chart</A></P>
+
+
+
+<H4><A NAME="zyxel">Zyxel</A></H4>
+
+<UL>
+<LI>The Zyxel Zywall is a rebranded SSH Sentinel box. See also our section
+on <A HREF="#ssh">SSH</A>.</LI>
+<LI>There seems to be a problem with keeping this connection alive. This is
+caused at the Zyxel end. See this brief
+<A HREF="http://lists.freeswan.org/archives/users/2003-October/msg00141.html">
+discussion and solution.
+</A>
+</LI>
+</UL>
+<P>
+<A HREF="http://www.zyxel.com/support/supportnote/zywall/app/zw_freeswan.htm">
+Zyxel's Zywall to FreeS/WAN instructions (PSK)</A><BR>
+<A HREF="http://www.zyxel.com/support/supportnote/p652/app/zw_freeswan.htm">
+Zyxel's Prestige to FreeS/WAN instructions (PSK)</A>. Note: not all Prestige
+versions include VPN software.<BR>
+
+<A HREF="http://www.lancry.net/techdocs/freeswan-zyxel.txt">Fabrice Cahen's
+ HOWTO (PSK)</A><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;
+</P>
+
+<P><A HREF="#zyxel.top">Back to chart</A></P>
+
+
+
+<!-- SAMPLE ENTRY
+
+<H4><A NAME="timestep">Timestep</A></H4>
+
+<P>Text goes here.
+</P>
+
+-->
+</BODY></HTML>
+
diff --git a/doc/src/intro.html b/doc/src/intro.html
new file mode 100644
index 000000000..09c352c00
--- /dev/null
+++ b/doc/src/intro.html
@@ -0,0 +1,887 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>Introduction to FreeS/WAN</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, introduction">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: intro.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="intro">Introduction</a></h1>
+
+<p>This section gives an overview of:</p>
+<ul>
+ <li>what IP Security (IPsec) does</li>
+ <li>how IPsec works</li>
+ <li>why we are implementing it for Linux</li>
+ <li>how this implementation works</li>
+</ul>
+
+<p>This section is intended to cover only the essentials, <em>things you
+should know before trying to use FreeS/WAN.</em></p>
+
+<p>For more detailed background information, see the <a
+href="politics.html#politics">history and politics</a> and
+<a href="ipsec.html#ipsec.detail">IPsec protocols</a> sections.</p>
+
+<h2><a name="ipsec.intro">IPsec, Security for the Internet Protocol</a></h2>
+
+<p>FreeS/WAN is a Linux implementation of the IPsec (IP security) protocols.
+IPsec provides <a href="glossary.html#encryption">encryption</a> and <a
+href="glossary.html#authentication">authentication</a> services at the IP
+(Internet Protocol) level of the network protocol stack.</p>
+
+<p>Working at this level, IPsec can protect any traffic carried over IP,
+unlike other encryption which generally protects only a particular
+higher-level protocol -- <a href="glossary.html#PGP">PGP</a> for mail, <a
+href="glossary.html#SSH">SSH</a> for remote login, <a
+href="glossary.html#SSL">SSL</a> for web work, and so on. This approach has
+both considerable advantages and some limitations. For discussion, see our <a
+href="ipsec.html#others">IPsec section</a></p>
+
+<p>IPsec can be used on any machine which does IP networking. Dedicated IPsec
+gateway machines can be installed wherever required to protect traffic. IPsec
+can also run on routers, on firewall machines, on various application
+servers, and on end-user desktop or laptop machines.</p>
+
+<p>Three protocols are used</p>
+<ul>
+ <li><a href="glossary.html#AH">AH</a> (Authentication Header) provides a
+ packet-level authentication service</li>
+ <li><a href="glossary.html#ESP">ESP</a> (Encapsulating Security Payload)
+ provides encryption plus authentication</li>
+ <li><a href="glossary.html#IKE">IKE</a> (Internet Key Exchange) negotiates
+ connection parameters, including keys, for the other two</li>
+</ul>
+
+<p>Our implementation has three main parts:</p>
+<ul>
+ <li><a href="glossary.html#KLIPS">KLIPS</a> (kernel IPsec) implements AH,
+ ESP, and packet handling within the kernel</li>
+ <li><a href="glossary.html#Pluto">Pluto</a> (an IKE daemon) implements IKE,
+ negotiating connections with other systems</li>
+ <li>various scripts provide an adminstrator's interface to the
+ machinery</li>
+</ul>
+
+<p>IPsec is optional for the current (version 4) Internet Protocol. FreeS/WAN
+adds IPsec to the Linux IPv4 network stack. Implementations of <a
+href="glossary.html#ipv6.gloss">IP version 6</a> are required to include
+IPsec. Work toward integrating FreeS/WAN into the Linux IPv6 stack has <a
+href="compat.html#ipv6">started</a>.</p>
+
+<p>For more information on IPsec, see our
+<a href="ipsec.html#ipsec.detail">IPsec protocols</a> section,
+our collection of <a href="web.html#ipsec.link">IPsec
+links</a> or the <a href="rfc.html#RFC">RFCs</a> which are the official
+definitions of these protocols.</p>
+
+<h3><a name="intro.interop">Interoperating with other IPsec
+implementations</a></h3>
+
+<p>IPsec is designed to let different implementations work together. We
+provide:</p>
+<ul>
+ <li>a <a href="web.html#implement">list</a> of some other
+ implementations</li>
+ <li>information on <a href="interop.html#interop">using FreeS/WAN
+ with other implementations</a></li>
+</ul>
+
+<p>The VPN Consortium fosters cooperation among implementers and
+interoperability among implementations. Their <a
+href="http://www.vpnc.org/">web site</a> has much more information.</p>
+
+<h3><a name="advantages">Advantages of IPsec</a></h3>
+
+<p>IPsec has a number of security advantages. Here are some independently
+written articles which discuss these:</p>
+
+<P>
+<A HREF="http://www.sans.org/rr/">SANS institute papers</A>. See the section
+on Encryption &amp;VPNs.
+<BR>
+<A HREF="http://www.cisco.com/en/US/netsol/ns110/ns170/ns171/ns128/networking_solutions_white_papers_list.html">Cisco's
+white papers on "Networking Solutions"</A>.
+<BR>
+<A HREF="http://iscs.sourceforge.net/HowWhyBrief/HowWhyBrief.html">
+Advantages of ISCS (Linux Integrated Secure Communications System;
+includes FreeS/WAN and other software)</A>.
+
+</P>
+
+
+<h3><a name="applications">Applications of IPsec</a></h3>
+
+<p>Because IPsec operates at the network layer, it is remarkably flexible and
+can be used to secure nearly any type of Internet traffic. Two applications,
+however, are extremely widespread:</p>
+<ul>
+ <li>a <a href="glossary.html#VPN">Virtual Private Network</a>, or VPN,
+ allows multiple sites to communicate securely over an insecure Internet
+ by encrypting all communication between the sites.</li>
+ <li>"Road Warriors" connect to the office from home, or perhaps from a
+ hotel somewhere</li>
+</ul>
+
+<p>There is enough opportunity in these applications that vendors are
+flocking to them. IPsec is being built into routers, into firewall products,
+and into major operating systems, primarily to support these applications.
+See our <a href="web.html#implement">list</a> of implementations for
+details.</p>
+
+<p>We support both of those applications, and various less common IPsec
+applications as well, but we also add one of our own:</p>
+<ul>
+ <li>opportunistic encryption, the ability to set up FreeS/WAN gateways so
+ that any two of them can encrypt to each other, and will do so whenever
+ packets pass between them.</li>
+</ul>
+
+<p>This is an extension we are adding to the protocols. FreeS/WAN is the
+first prototype implementation, though we hope other IPsec implementations
+will adopt the technique once we demonstrate it. See <a href="#goals">project
+goals</a> below for why we think this is important.</p>
+
+<p>A somewhat more detailed description of each of these applications is
+below. Our <a href="quickstart.html#quick_guide">quickstart</a> section will
+show you how to build each of them.</p>
+
+<h4><a name="makeVPN">Using secure tunnels to create a VPN</a></h4>
+
+<p>A VPN, or <strong>V</strong>irtual <strong>P</strong>rivate
+<strong>N</strong>etwork lets two networks communicate securely when the only
+connection between them is over a third network which they do not trust.</p>
+
+<p>The method is to put a security gateway machine between each of the
+communicating networks and the untrusted network. The gateway machines
+encrypt packets entering the untrusted net and decrypt packets leaving it,
+creating a secure tunnel through it.</p>
+
+<p>If the cryptography is strong, the implementation is careful, and the
+administration of the gateways is competent, then one can reasonably trust
+the security of the tunnel. The two networks then behave like a single large
+private network, some of whose links are encrypted tunnels through untrusted
+nets.</p>
+
+<p>Actual VPNs are often more complex. One organisation may have fifty branch
+offices, plus some suppliers and clients, with whom it needs to communicate
+securely. Another might have 5,000 stores, or 50,000 point-of-sale devices.
+The untrusted network need not be the Internet. All the same issues arise on
+a corporate or institutional network whenever two departments want to
+communicate privately with each other.</p>
+
+<p>Administratively, the nice thing about many VPN setups is that large parts
+of them are static. You know the IP addresses of most of the machines
+involved. More important, you know they will not change on you. This
+simplifies some of the admin work. For cases where the addresses do change,
+see the next section.</p>
+
+<h4><a name="road.intro">Road Warriors</a></h4>
+
+<p>The prototypical "Road Warrior" is a traveller connecting to home base
+from a laptop machine. Administratively, most of the same problems arise for
+a telecommuter connecting from home to the office, especially if the
+telecommuter does not have a static IP address.</p>
+
+<p>For purposes of this document:</p>
+<ul>
+ <li>anyone with a dynamic IP address is a "Road Warrior".</li>
+ <li>any machine doing IPsec processing is a "gateway". Think of the
+ single-user road warrior machine as a gateway with a degenerate subnet
+ (one machine, itself) behind it.</li>
+</ul>
+
+<p>These require somewhat different setup than VPN gateways with static
+addresses and with client systems behind them, but are basically not
+problematic.</p>
+
+<p>There are some difficulties which appear for some road warrior
+connections:</p>
+<ul>
+ <li>Road Wariors who get their addresses via DHCP may have a problem.
+ FreeS/WAN can quite happily build and use a tunnel to such an address,
+ but when the DHCP lease expires, FreeS/WAN does not know that. The tunnel
+ fails, and the only recovery method is to tear it down and re-build
+ it.</li>
+ <li>If <a href="glossary.html#NAT.gloss">Network Address Translation</a>
+ (NAT) is applied between the two IPsec Gateways, this breaks IPsec. IPsec
+ authenticates packets on an end-to-end basis, to ensure they are not
+ altered en route. NAT rewrites packets as they go by. See our <a
+ href="firewall.html#NAT">firewalls</a> document for details.</li>
+</ul>
+
+<p>In most situations, however, FreeS/WAN supports road warrior connections
+just fine.</p>
+
+<h4><a name="opp.intro">Opportunistic encryption</a></h4>
+
+<p>One of the reasons we are working on FreeS/WAN is that it gives us the
+opportunity to add what we call opportuntistic encryption. This means that
+any two FreeS/WAN gateways will be able to encrypt their traffic, even if the
+two gateway administrators have had no prior contact and neither system has
+any preset information about the other.</p>
+
+<p>Both systems pick up the authentication information they need from the <a
+href="glossary.html#DNS">DNS</a> (domain name service), the service they
+already use to look up IP addresses. Of course the administrators must put
+that information in the DNS, and must set up their gateways with
+opportunistic encryption enabled. Once that is done, everything is automatic.
+The gateways look for opportunities to encrypt, and encrypt whatever they
+can. Whether they also accept unencrypted communication is a policy decision
+the administrator can make.</p>
+
+<p>This technique can give two large payoffs:</p>
+<ul>
+ <li>It reduces the administrative overhead for IPsec enormously. You
+ configure your gateway and thereafter everything is automatic. The need
+ to configure the system on a per-tunnel basis disappears. Of course,
+ FreeS/WAN allows specifically configured tunnels to co-exist with
+ opportunistic encryption, but we hope to make them unnecessary in most
+ cases.</li>
+ <li>It moves us toward a more secure Internet, allowing users to create an
+ environment where message privacy is the default. All messages can be
+ encrypted, provided the other end is willing to co-operate. See our <a
+ href="politics.html#politics">history and politics of cryptography</a>
+ section for discussion of why we think this is needed.</li>
+</ul>
+
+<p>Opportunistic encryption is not (yet?) a standard part of the IPsec
+protocols, but an extension we are proposing and demonstrating. For details
+of our design, see <a href="#applied">links</a> below.</p>
+
+<p>Only one current product we know of implements a form of opportunistic
+encryption. <a href="web.html#ssmail">Secure sendmail</a> will automatically
+encrypt server-to-server mail transfers whenever possible.</p>
+
+<h3><a name="types">The need to authenticate gateways</a></h3>
+
+<p>A complication, which applies to any type of connection -- VPN, Road
+Warrior or opportunistic -- is that a secure connection cannot be created
+magically. <em>There must be some mechanism which enables the gateways to
+reliably identify each other.</em> Without this, they cannot sensibly trust
+each other and cannot create a genuinely secure link.</p>
+
+<p>Any link they do create without some form of <a
+href="glossary.html#authentication">authentication</a> will be vulnerable to
+a <a href="glossary.html#middle">man-in-the-middle attack</a>. If <a
+href="glossary.html#alicebob">Alice and Bob</a> are the people creating the
+connection, a villian who can re-route or intercept the packets can pose as
+Alice while talking to Bob and pose as Bob while talking to Alice. Alice and
+Bob then both talk to the man in the middle, thinking they are talking to
+each other, and the villain gets everything sent on the bogus "secure"
+connection.</p>
+
+<p>There are two ways to build links securely, both of which exclude the
+man-in-the middle:</p>
+<ul>
+ <li>with <strong>manual keying</strong>, Alice and Bob share a secret key
+ (which must be transmitted securely, perhaps in a note or via PGP or SSH)
+ to encrypt their messages. For FreeS/WAN, such keys are stored in the <a
+ href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> file. Of course, if
+ an enemy gets the key, all is lost.</li>
+ <li>with <strong>automatic keying</strong>, the two systems authenticate
+ each other and negotiate their own secret keys. The keys are
+ automatically changed periodically.</li>
+</ul>
+
+<p>Automatic keying is much more secure, since if an enemy gets one key only
+messages between the previous re-keying and the next are exposed. It is
+therefore the usual mode of operation for most IPsec deployment, and the mode
+we use in our setup examples. FreeS/WAN does support manual keying for
+special circumstanes. See this <a
+href="adv_config.html#prodman">section</a>.</p>
+
+<p>For automatic keying, the two systems must authenticate each other during
+the negotiations. There is a choice of methods for this:</p>
+<ul>
+ <li>a <strong>shared secret</strong> provides authentication. If Alice and
+ Bob are the only ones who know a secret and Alice recives a message which
+ could not have been created without that secret, then Alice can safely
+ believe the message came from Bob.</li>
+ <li>a <a href="glossary.html#public">public key</a> can also provide
+ authentication. If Alice receives a message signed with Bob's private key
+ (which of course only he should know) and she has a trustworthy copy of
+ his public key (so that she can verify the signature), then she can
+ safely believe the message came from Bob.</li>
+</ul>
+
+<p>Public key techniques are much preferable, for reasons discussed <a
+href="config.html#choose">later</a>, and will be used in all our setup
+examples. FreeS/WAN does also support auto-keying with shared secret
+authentication. See this <a
+href="adv_config.html#prodsecrets">section</a>.</p>
+
+<h2><a name="project">The FreeS/WAN project</a></h2>
+
+<p>For complete information on the project, see our web site, <a
+href="http://liberty.freeswan.org">freeswan.org</a>.</p>
+
+<p>In summary, we are implementing the <a
+href="glossary.html#IPsec">IPsec</a> protocols for Linux and extending them
+to do <a href="glossary.html#carpediem">opportunistic encryption</a>.</p>
+
+<h3><a name="goals">Project goals</a></h3>
+
+<p>Our overall goal in FreeS/WAN is to make the Internet more secure and more
+private.</p>
+
+<p>Our IPsec implementation supports VPNs and Road Warriors of course. Those
+are important applications. Many users will want FreeS/WAN to build corporate
+VPNs or to provide secure remote access.</p>
+
+<p>However, our goals in building it go beyond that. We are trying to help
+<strong>build security into the fabric of the Internet</strong> so that
+anyone who choses to communicate securely can do so, as easily as they can do
+anything else on the net.</p>
+
+<p>More detailed objectives are:</p>
+<ul>
+ <li>extend IPsec to do <a href="glossary.html#carpediem">opportunistic
+ encryption</a> so that
+ <ul>
+ <li>any two systems can secure their communications without a
+ pre-arranged connection</li>
+ <li><strong>secure connections can be the default</strong>, falling
+ back to unencrypted connections only if:
+ <ul>
+ <li><em>both</em> the partner is not set up to co-operate on
+ securing the connection</li>
+ <li><em>and</em> your policy allows insecure connections</li>
+ </ul>
+ </li>
+ <li>a significant fraction of all Internet traffic is encrypted</li>
+ <li>wholesale monitoring of the net (<a
+ href="politics.html#intro.poli">examples</a>) becomes difficult or
+ impossible</li>
+ </ul>
+ </li>
+ <li>help make IPsec widespread by providing an implementation with no
+ restrictions:
+ <ul>
+ <li>freely available in source code under the <a
+ href="glossary.html#GPL">GNU General Public License</a></li>
+ <li>running on a range of readily available hardware</li>
+ <li>not subject to US or other nations' <a
+ href="politics.html#exlaw">export restrictions</a>.<br>
+ Note that in order to avoid <em>even the appearance</em> of being
+ subject to those laws, the project cannot accept software
+ contributions -- <em>not even one-line bug fixes</em> -- from US
+ residents or citizens.</li>
+ </ul>
+ </li>
+ <li>provide a high-quality IPsec implementation for Linux
+ <ul>
+ <li>portable to all CPUs Linux supports: <a
+ href="compat.html#CPUs">(current list)</a></li>
+ <li>interoperable with other IPsec implementations: <a
+ href="interop.html#interop">(current list)</a></li>
+ </ul>
+ </li>
+</ul>
+
+<p>If we can get opportunistic encryption implemented and widely deployed,
+then it becomes impossible for even huge well-funded agencies to monitor the
+net.</p>
+
+<p>See also our section on <a href="politics.html#politics">history and
+politics</a> of cryptography, which includes our project leader's <a
+href="politics.html#gilmore">rationale</a> for starting the project.</p>
+
+<h3><a name="staff">Project team</a></h3>
+
+<p>Two of the team are from the US and can therefore contribute no code:</p>
+<ul>
+ <li>John Gilmore: founder and policy-maker (<a
+ href="http://www.toad.com/gnu/">home page</a>)</li>
+ <li>Hugh Daniel: project manager, Most Demented Tester, and occasionally
+ Pointy-Haired Boss</li>
+</ul>
+
+<p>The rest of the team are Canadians, working in Canada. (<a
+href="politics.html#status">Why Canada?</a>)</p>
+<ul>
+ <li>Hugh Redelmeier: <a href="glossary.html#Pluto">Pluto daemon</a>
+ programmer</li>
+ <li>Richard Guy Briggs: <a href="glossary.html#KLIPS">KLIPS</a>
+ programmer</li>
+ <li>Michael Richardson: hacker without portfolio</li>
+ <li>Claudia Schmeing: documentation</li>
+ <li>Sam Sgro: technical support via the <a href="mail.html#lists">mailing
+ lists</a></li>
+</ul>
+
+<p>The project is funded by civil libertarians who consider our goals
+worthwhile. Most of the team are paid for this work.</p>
+
+<p>People outside this core team have made substantial contributions. See</p>
+<ul>
+ <li>our <a href="../CREDITS">CREDITS</a> file</li>
+ <li>the <a href="web.html#patch">patches and add-ons</a> section of our web
+ references file</li>
+ <li>lists below of user-written <a href="#howto">HowTos</a> and <a
+ href="#applied">other papers</a></li>
+</ul>
+
+<p>Additional contributions are welcome. See the <a
+href="faq.html#contrib.faq">FAQ</a> for details.</p>
+
+<h2><a name="products">Products containing FreeS/WAN</a></h2>
+
+<p>Unfortunately the <a href="politics.html#exlaw">export laws</a> of some
+countries restrict the distribution of strong cryptography. FreeS/WAN is
+therefore not in the standard Linux kernel and not in all CD or web
+distributions.</p>
+
+<p>FreeS/WAN is, however, quite widely used. Products we know of that use it
+are listed below. We would appreciate hearing, via the <a
+href="mail.html#lists">mailing lists</a>, of any we don't know of.</p>
+
+<h3><a name="distwith">Full Linux distributions</a></h3>
+
+<p>FreeS/WAN is included in various general-purpose Linux distributions,
+mostly from countries (shown in brackets) with more sensible laws:</p>
+<ul>
+ <li><a href="http://www.suse.com/">SuSE Linux</a> (Germany)</li>
+ <li><a href="http://www.conectiva.com">Conectiva</a> (Brazil)</li>
+ <li><a href="http://www.linux-mandrake.com/en/">Mandrake</a> (France)</li>
+ <li><a href="http://www.debian.org">Debian</a></li>
+ <li>the <a href="http://www.pld.org.pl/">Polish(ed) Linux Distribution</a>
+ (Poland)</li>
+ <li><a>Best Linux</a> (Finland)</li>
+</ul>
+
+<p>For distributions which do not include FreeS/WAN and are not Redhat (which
+we develop and test on), there is additional information in our <a
+href="compat.html#otherdist">compatibility</a> section.</p>
+
+<p>The server edition of <a href="http://www.corel.com">Corel</a> Linux
+(Canada) also had FreeS/WAN, but Corel have dropped that product line.</p>
+
+<h3><a name="kernel_dist">Linux kernel distributions</a></h3>
+
+<ul>
+<li><a href="http://sourceforge.net/projects/wolk/">Working Overloaded Linux Kernel (WOLK)</a></li>
+</ul>
+
+
+<h3><a name="office_dist">Office server distributions</a></h3>
+
+<p>FreeS/WAN is also included in several distributions aimed at the market
+for turnkey business servers:</p>
+<ul>
+ <li><a href="http://www.e-smith.com/">e-Smith</a> (Canada), which has
+ recently been acquired and become the Network Server Solutions group of
+ <a href="http://www.mitel.com/">Mitel Networks</a> (Canada)</li>
+ <li><a href="http://www.clarkconnect.org/">ClarkConnect</a> from Point Clark Networks (Canada)</li>
+ <li><a href="http://www.trustix.net/">Trustix Secure Linux</a> (Norway)</li>
+
+</ul>
+
+<h3><a name="fw_dist">Firewall distributions</a></h3>
+
+<p>Several distributions intended for firewall and router applications
+include FreeS/WAN:</p>
+<ul>
+ <li>The <a href="http://www.linuxrouter.org/">Linux Router Project</a>
+ produces a Linux distribution that will boot from a single floppy. The <a
+ href="http://leaf.sourceforge.net">LEAF</a> firewall project provides
+ several different LRP-based firewall packages. At least one of them,
+ Charles Steinkuehler's Dachstein, includes FreeS/WAN with X.509
+ patches.</li>
+ <li>there are several distributions bootable directly from CD-ROM, usable
+ on a machine without hard disk.
+ <ul>
+ <li>Dachstein (see above) can be used this way</li>
+ <li><a href="http://www.gibraltar.at/">Gibraltar</a> is based on Debian
+ GNU/Linux.</li>
+ <li>at time of writing, <a href="www.xiloo.com">Xiloo</a> is available
+ only in Chinese. An English version is expected.</li>
+ </ul>
+ </li>
+ <li><a href="http://www.astaro.com/products/index.html">Astaro Security
+ Linux</a> includes FreeS/WAN. It has some web-based tools for managing
+ the firewall that include FreeS/WAN configuration management.</li>
+ <li><a href="http://www.linuxwall.de">Linuxwall</a></li>
+ <li><a href="http://www.smoothwall.org/">Smoothwall</a></li>
+ <li><a href="http://www.devil-linux.org/">Devil Linux</a></li>
+ <li>Coyote Linux has a <a
+ href="http://embedded.coyotelinux.com/wolverine/index.php">Wolverine</a>
+ firewall/VPN server</li>
+</ul>
+
+<p>There are also several sets of scripts available for managing a firewall
+which is also acting as a FreeS/WAN IPsec gateway. See this <a
+href="firewall.html#rules.pub">list</a>.</p>
+
+<h3><a name="turnkey">Firewall and VPN products</a></h3>
+
+<p>Several vendors use FreeS/WAN as the IPsec component of a turnkey firewall
+or VPN product.</p>
+
+<p>Software-only products:</p>
+<ul>
+ <li><a href="http://www.linuxmagic.com/vpn/index.html">Linux Magic</a>
+ offer a VPN/Firewall product using FreeS/WAN</li>
+ <li>The Software Group's <a
+ href="http://www.wanware.com/sentinet/">Sentinet</a> product uses
+ FreeS/WAN</li>
+ <li><a href="http://www.merilus.com">Merilus</a> use FreeS/WAN in their
+ Gateway Guardian firewall product</li>
+</ul>
+
+<p>Products that include the hardware:</p>
+<ul>
+ <li>The <a href="http://www.lasat.com">LASAT SafePipe[tm]</a> series. is an
+ IPsec box based on an embedded MIPS running Linux with FreeS/WAN and a
+ web-config front end. This company also host our freeswan.org web
+ site.</li>
+ <li>Merilus <a
+ href="http://www.merilus.com/products/fc/index.shtml">Firecard</a> is a
+ Linux firewall on a PCI card.</li>
+ <li><a href="http://www.kyzo.com/">Kyzo</a> have a "pizza box" product line
+ with various types of server, all running from flash. One of them is an
+ IPsec/PPTP VPN server</li>
+ <li><a href="http://www.pfn.com">PFN</a> use FreeS/WAN in some of their
+ products</li>
+</ul>
+
+<p><a href="www.rebel.com">Rebel.com</a>, makers of the Netwinder Linux
+machines (ARM or Crusoe based), had a product that used FreeS/WAN. The
+company is in receivership so the future of the Netwinder is at best unclear.
+<a href="web.html#patch">PKIX patches</a> for FreeS/WAN developed at Rebel
+are listed in our web links document.</p>
+
+
+<h2><a name="docs">Information sources</a></h2>
+
+<h3><a name="docformats">This HowTo, in multiple formats</a></h3>
+
+<p>FreeS/WAN documentation up to version 1.5 was available only in HTML. Now
+we ship two formats:</p>
+<ul>
+ <li>as HTML, one file for each doc section plus a global <a
+ href="toc.html">Table of Contents</a></li>
+ <li><a href="HowTo.html">one big HTML file</a> for easy searching</li>
+</ul>
+
+<p>and provide a Makefile to generate other formats if required:</p>
+<ul>
+ <li><a href="HowTo.pdf">PDF</a></li>
+ <li><a href="HowTo.ps">Postscript</a></li>
+ <li><a href="HowTo.txt">ASCII text</a></li>
+</ul>
+
+<p>The Makefile assumes the htmldoc tool is available. You can download it
+from <a href="http://www.easysw.com">Easy Software</a>.</p>
+
+<p>All formats should be available at the following websites:</p>
+<ul>
+ <li><a href="http://www.freeswan.org/doc.html">FreeS/WAN project</a></li>
+ <li><a href="http://www.linuxdoc.org">Linux Documentation Project</a></li>
+</ul>
+
+<p>The distribution tarball has only the two HTML formats.</p>
+
+<p><strong>Note:</strong> If you need the latest doc version, for example to
+see if anyone has managed to set up interoperation between FreeS/WAN and
+whatever, then you should download the current snapshot. What is on the web
+is documentation as of the last release. Snapshots have all changes I've
+checked in to date.</p>
+
+<h3><a name="rtfm">RTFM (please Read The Fine Manuals)</a></h3>
+
+<p>As with most things on any Unix-like system, most parts of Linux FreeS/WAN
+are documented in online manual pages. We provide a list of <a
+href="/mnt/floppy/manpages.html">FreeS/WAN man pages</a>, with links to HTML
+versions of them.</p>
+
+<p>The man pages describing configuration files are:</p>
+<ul>
+ <li><a href="/mnt/floppy/manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a></li>
+ <li><a
+ href="/mnt/floppy/manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</a></li>
+</ul>
+
+<p>Man pages for common commands include:</p>
+<ul>
+ <li><a href="/mnt/floppy/manpage.d/ipsec.8.html">ipsec(8)</a></li>
+ <li><a
+ href="/mnt/floppy/manpage.d/ipsec_pluto.8.html">ipsec_pluto(8)</a></li>
+ <li><a
+ href="/mnt/floppy/manpage.d/ipsec_newhostkey.8.html">ipsec_newhostkey(8)</a></li>
+ <li><a href="/mnt/floppy/manpage.d/ipsec_auto.8.html">ipsec_auto(8)</a></li>
+</ul>
+
+<p>You can read these either in HTML using the links above or with the
+<var>man(1)</var> command.</p>
+
+<p>In the event of disagreement between this HTML documentation and the man
+pages, the man pages are more likely correct since they are written by the
+implementers. Please report any such inconsistency on the <a
+href="mail.html#lists">mailing list</a>.</p>
+
+<h3><a name="text">Other documents in the distribution</a></h3>
+
+<p>Text files in the main distribution directory are README, INSTALL,
+CREDITS, CHANGES, BUGS and COPYING.</p>
+
+<p>The Libdes encryption library we use has its own documentation. You can
+find it in the library directory..</p>
+
+<h3><a name="assumptions">Background material</a></h3>
+
+<p>Throughout this documentation, I write as if the reader had at least a
+general familiarity with Linux, with Internet Protocol networking, and with
+the basic ideas of system and network security. Of course that will certainly
+not be true for all readers, and quite likely not even for a majority.</p>
+
+<p>However, I must limit amount of detail on these topics in the main text.
+For one thing, I don't understand all the details of those topics myself.
+Even if I did, trying to explain everything here would produce extremely long
+and almost completely unreadable documentation.</p>
+
+<p>If one or more of those areas is unknown territory for you, there are
+plenty of other resources you could look at:</p>
+<dl>
+ <dt>Linux</dt>
+ <dd>the <a href="http://www.linuxdoc.org">Linux Documentation Project</a>
+ or a local <a href="http://www.linux.org/groups/">Linux User Group</a>
+ and these <a href="web.html#linux.link">links</a></dd>
+ <dt>IP networks</dt>
+ <dd>Rusty Russell's <a
+ href="http://netfilter.samba.org/unreliable-guides/networking-concepts-HOWTO/index.html">Networking
+ Concepts HowTo</a> and these <a
+ href="web.html#IP.background">links</a></dd>
+ <dt>Security</dt>
+ <dd>Schneier's book <a href="biblio.html#secrets">Secrets and Lies</a>
+ and these <a href="web.html#crypto.link">links</a></dd>
+</dl>
+
+<p>Also, I do make an effort to provide some background material in these
+documents. All the basic ideas behind IPsec and FreeS/WAN are explained here.
+Explanations that do not fit in the main text, or that not everyone will
+need, are often in the <a href="glossary.html#ourgloss">glossary</a>, which is
+the largest single file in this document set. There is also a <a
+href="background.html#background">background</a> file containing various
+explanations too long to fit in glossary definitions. All files are heavily
+sprinkled with links to each other and to the glossary. <strong>If some passage
+makes no sense to you, try the links</strong>.</p>
+
+<p>For other reference material, see the <a
+href="biblio.html#biblio">bibliography</a> and our collection of <a
+href="web.html#weblinks">web links</a>.</p>
+
+<p>Of course, no doubt I get this (and other things) wrong sometimes.
+Feedback via the <a href="mail.html#lists">mailing lists</a> is welcome.</p>
+
+<h3><a name="archives">Archives of the project mailing list</a></h3>
+
+<p>Until quite recently, there was only one FreeS/WAN mailing list, and
+archives of it were:</p>
+<ul>
+ <li><a href="http://www.sandelman.ottawa.on.ca/linux-ipsec">Canada</a></li>
+ <li><a href="http://www.nexial.com">Holland</a></li>
+</ul>
+The two archives use completely different search engines. You might want to
+try both.
+
+<p>More recently we have expanded to five lists, each with its own
+archive.</p>
+
+<p><a href="mail.html#lists">More information</a> on mailing lists.</p>
+
+<h3><a name="howto">User-written HowTo information</a></h3>
+
+<p>Various user-written HowTo documents are available. The ones covering
+FreeS/WAN-to-FreeS/WAN connections are:</p>
+<ul>
+ <li>Jean-Francois Nadeau's <a href="http://jixen.tripod.com/">practical
+ configurations</a> document</li>
+ <li>Jens Zerbst's HowTo on <a href="http://dynipsec.tripod.com/">Using
+ FreeS/WAN with dynamic IP addresses</a>.</li>
+ <li>an entry in Kurt Seifried's <a
+ href="http://www.securityportal.com/lskb/kben00000013.html">Linux
+ Security Knowledge Base</a>.</li>
+ <li>a section of David Ranch's <a
+ href="http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos">Trinity
+ OS Guide</a></li>
+ <li>a section in David Bander's book <a href="biblio.html#bander">Linux
+ Security Toolkit</a></li>
+</ul>
+
+<p>User-wriiten HowTo material may be <strong>especially helpful if you need
+to interoperate with another IPsec implementation</strong>. We have neither
+the equipment nor the manpower to test such configurations. Users seem to be
+doing an admirable job of filling the gaps.</p>
+<ul>
+ <li>list of user-written <a href="interop.html#otherpub">interoperation
+ HowTos</a> in our interop document</li>
+</ul>
+
+<p>Check what version of FreeS/WAN user-written documents cover. The software
+is under active development and the current version may be significantly
+different from what an older document describes.</p>
+
+<h3><a name="applied">Papers on FreeS/WAN</a></h3>
+
+<p>Two design documents show team thinking on new developments:</p>
+<ul>
+ <li><a href="opportunism.spec">Opportunistic Encryption</a> by technical
+ lead Henry Spencer and Pluto programmer Hugh Redelemeier</li>
+ <li>discussion of <a
+ href="http://www.sandelman.ottawa.on.ca/SSW/freeswan/klips2req/">KLIPS
+ redesign</a></li>
+</ul>
+
+<p>Both documents are works in progress and are frequently revised. For the
+latest version, see the <a href="mail.html#lists">design mailing list</a>. Comments
+should go to that list.</p>
+
+<p>There is now an <a
+href="http://www.ietf.org/internet-drafts/draft-richardson-ipsec-opportunistic-06.txt">Internet
+Draft on Opportunistic Encryption</a> by Michael Richardson, Hugh Redelmeier
+and Henry Spencer. This is a first step toward getting the protocol
+standardised so there can be multiple implementations of it. Discussion of it
+takes place on the <a
+href="http://www.ietf.org/html.charters/ipsec-charter.html">IETF IPsec
+Working Group</a> mailing list.</p>
+
+<p>A number of papers giving further background on FreeS/WAN, or exploring
+its future or its applications, are also available:</p>
+<ul>
+ <li>Both Henry and Richard gave talks on FreeS/WAN at the 2000 <a
+ href="http://www.linuxsymposium.org">Ottawa Linux Symposium</a>.
+ <ul>
+ <li>Richard's <a
+ href="http://www.conscoop.ottawa.on.ca/rgb/freeswan/ols2k/">slides</a></li>
+ <li>Henry's paper</li>
+ <li>MP3 audio of their talks is available from the <a
+ href="http://www.linuxsymposium.org/">conference page</a></li>
+ </ul>
+ </li>
+ <li><cite>Moat: A Virtual Private Network Appliances and Services
+ Platform</cite> is a paper about large-scale (a few 100 links) use of
+ FreeS/WAN in a production application at AT&amp;T Research. It is
+ available in Postscript or PDF from co-author Steve Bellovin's <a
+ href="http://www.research.att.com/~smb/papers/index.html">papers list
+ page</a>.</li>
+ <li>One of the Moat co-authors, John Denker, has also written
+ <ul>
+ <li>a <a
+ href="http://www.av8n.com/vpn/ipsec+routing.htm">proposal</a>
+ for how future versions of FreeS/WAN might interact with routing
+ protocols</li>
+ <li>a <a
+ href="http://www.av8n.com/vpn/wishlist.htm">wishlist</a>
+ of possible new features</li>
+ </ul>
+ </li>
+ <li>Bart Trojanowski's web page has a draft design for <a
+ href="http://www.jukie.net/~bart/linux-ipsec/">hardware acceleration</a>
+ of FreeS/WAN</li>
+</ul>
+
+<p>Several of these provoked interesting discussions on the mailing lists,
+worth searching for in the <a href="mail.html#archive">archives</a>.</p>
+
+<p>There are also several papers in languages other than English, see our <a
+href="web.html#otherlang">web links</a>.</p>
+
+<h3><a name="licensing">License and copyright information</a></h3>
+
+<p>All code and documentation written for this project is distributed under
+either the GNU General Public License (<a href="glossary.html#GPL">GPL</a>)
+or the GNU Library General Public License. For details see the COPYING file
+in the distribution.</p>
+
+<p>Not all code in the distribution is ours, however. See the CREDITS file
+for details. In particular, note that the <a
+href="glossary.html#LIBDES">Libdes</a> library and the version of <a
+href="glossary.html#MD5">MD5</a> that we use each have their own license.</p>
+
+<h2><a name="sites">Distribution sites</a></h2>
+
+<p>FreeS/WAN is available from a number of sites.</p>
+
+<h3>Primary site</h3>
+
+<p>Our primary site, is at xs4all (Thanks, folks!) in Holland:</p>
+<ul>
+ <li><a href="http://www.xs4all.nl/~freeswan">HTTP</a></li>
+ <li><a href="ftp://ftp.xs4all.nl/pub/crypto/freeswan">FTP</a></li>
+</ul>
+
+<h3><a name="mirrors">Mirrors</a></h3>
+
+<p>There are also mirror sites all over the world:</p>
+<ul>
+ <li><a href="http://www.flora.org/freeswan">Eastern Canada</a> (limited
+ resouces)</li>
+ <li><a href="ftp://ludwig.doculink.com/pub/freeswan/">Eastern Canada</a>
+ (has older versions too)</li>
+ <li><a href="ftp://ntsc.notBSD.org/pub/crypto/freeswan/">Eastern Canada</a>
+ (has older versions too)</li>
+ <li><a href="ftp://ftp.kame.net/pub/freeswan/">Japan</a></li>
+ <li><a href="ftp://ftp.futuredynamics.com/freecrypto/FreeSWAN/">Hong
+ Kong</a></li>
+ <li><a href="ftp://ipsec.dk/pub/freeswan/">Denmark</a></li>
+ <li><a href="ftp://ftp.net.lut.ac.uk/freeswan">the UK</a></li>
+ <li><a href="http://storm.alert.sk/comp/mirrors/freeswan/">Slovak
+ Republic</a></li>
+ <li><a
+ href="http://the.wiretapped.net/security/vpn-tunnelling/freeswan/">Australia</a></li>
+ <li><a href="http://freeswan.technolust.cx/">technolust</a></li>
+ <li><a href="http://freeswan.devguide.de/">Germany</a></li>
+ <li>Ivan Moore's <a href="http://snowcrash.tdyc.com/freeswan/">site</a></li>
+ <li>the <a href="http://www.cryptoarchive.net/">Crypto Archive</a> on the
+ <a href="http://www.securityportal.com/">Security Portal</a> site</li>
+ <li><a href="http://www.wiretapped.net/">Wiretapped.net</a> in
+ Australia</li>
+</ul>
+
+<p>Thanks to those folks as well.</p>
+
+<h3><a name="munitions">The "munitions" archive of Linux crypto
+software</a></h3>
+
+<p>There is also an archive of Linux crypto software called "munitions", with
+its own mirrors in a number of countries. It includes FreeS/WAN, though not
+always the latest version. Some of its sites are:</p>
+<ul>
+ <li><a href="http://munitions.vipul.net/">Germany</a></li>
+ <li><a href="http://munitions.iglu.cjb.net/">Italy</a></li>
+ <li><a href="http://munitions2.xs4all.nl/">Netherlands</a></li>
+</ul>
+
+<p>Any of those will have a list of other "munitions" mirrors. There is also
+a CD available.</p>
+
+<h2>Links to other sections</h2>
+
+<p>For more detailed background information, see:</p>
+<ul>
+ <li><a href="politics.html#politics">history and politics</a> of
+ cryptography</li>
+ <li><a href="ipsec.html#ipsec.detail">IPsec protocols</a></li>
+</ul>
+
+<p>To begin working with FreeS/WAN, go to our <a
+href="quickstart.html#quick.guide">quickstart</a> guide.</p>
+</body>
+</html>
diff --git a/doc/src/ipsec.html b/doc/src/ipsec.html
new file mode 100644
index 000000000..4647eaf66
--- /dev/null
+++ b/doc/src/ipsec.html
@@ -0,0 +1,1206 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>IPsec protocols</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, protocol, ESP, AH, IKE">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: ipsec.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="ipsec.detail">The IPsec protocols</a></h1>
+
+<p>This section provides information on the IPsec protocols which FreeS/WAN
+implements. For more detail, see the <a href="rfc.html">RFCs</a>.</p>
+
+<p>The basic idea of IPsec is to provide security functions, <a
+href="glossary.html#authentication">authentication</a> and <a
+href="glossary.html#encryption">encryption</a>, at the IP (Internet Protocol)
+level. This requires a higher-level protocol (IKE) to set things up for the
+IP-level services (ESP and AH).</p>
+
+<h2>Protocols and phases</h2>
+
+<p>Three protocols are used in an IPsec implementation:</p>
+<dl>
+ <dt>ESP, Encapsulating Security Payload</dt>
+ <dd>Encrypts and/or authenticates data</dd>
+ <dt>AH, Authentication Header</dt>
+ <dd>Provides a packet authentication service</dd>
+ <dt>IKE, Internet Key Exchange</dt>
+ <dd>Negotiates connection parameters, including keys, for the other
+ two</dd>
+</dl>
+
+<p>The term "IPsec" (also written as IPSEC) is slightly ambiguous. In some
+contexts, it includes all three of the above but in other contexts it refers
+only to AH and ESP.</p>
+
+<p>There is more detail below, but a quick summary of how the whole thing
+works is:</p>
+<dl>
+ <dt>Phase one IKE (main mode exchange)</dt>
+ <dd>sets up a keying channel (ISAKMP SA) between the two gateways</dd>
+ <dt>Phase two IKE (quick mode exchange)</dt>
+ <dd>sets up data channels (IPsec SAs)</dd>
+ <dt>IPsec proper</dt>
+ <dd>exchanges data using AH or ESP</dd>
+</dl>
+
+<p>Both phases of IKE are repeated periodically to automate re-keying.</p>
+
+<h2><a name="others">Applying IPsec</a></h2>
+
+<p>Authentication and encryption functions for network data can, of course,
+be provided at other levels. Many security protocols work at levels above
+IP.</p>
+<ul>
+ <li><a href="glossary.html#PGP">PGP</a> encrypts and authenticates mail
+ messages</li>
+ <li><a href="glossary.html#SSH">SSH</a> authenticates remote logins and
+ then encrypts the session</li>
+ <li><a href="glossary.html#SSL">SSL</a> or <a
+ href="glossary.html#TLS">TLS</a> provides security at the sockets layer,
+ e.g. for secure web browsing</li>
+</ul>
+
+<p>and so on. Other techniques work at levels below IP. For example, data on
+a communications circuit or an entire network can be encrypted by specialised
+hardware. This is common practice in high-security applications.</p>
+
+<h3><a name="advantages">Advantages of IPsec</a></h3>
+
+<p>There are, however, advantages to doing it at the IP level instead of, or
+as well as, at other levels.</p>
+
+<p>IPsec is the <strong>most general way to provide these services for the
+Internet</strong>.</p>
+<ul>
+ <li>Higher-level services protect a <em>single protocol</em>; for example
+ PGP protects mail.</li>
+ <li>Lower level services protect a <em>single medium</em>; for example a
+ pair of encryption boxes on the ends of a line make wiretaps on that line
+ useless unless the attacker is capable of breaking the encryption.</li>
+</ul>
+
+<p>IPsec, however, can protect <em>any protocol</em> running above IP and
+<em>any medium</em> which IP runs over. More to the point, it can protect a
+mixture of application protocols running over a complex combination of media.
+This is the normal situation for Internet communication; IPsec is the only
+general solution.</p>
+
+<p>IPsec can also provide some security services "in the background", with
+<strong>no visible impact on users</strong>. To use <a
+href="glossary.html#PGP">PGP</a> encryption and signatures on mail, for
+example, the user must at least:</p>
+<ul>
+ <li>remember his or her passphrase,</li>
+ <li>keep it secure</li>
+ <li>follow procedures to validate correspondents' keys</li>
+</ul>
+
+<p>These systems can be designed so that the burden on users is not onerous,
+but any system will place some requirements on users. No such system can hope
+to be secure if users are sloppy about meeting those requirements. The author
+has seen username and password stuck on terminals with post-it notes in an
+allegedly secure environment, for example.</p>
+
+<h3><a name="limitations">Limitations of IPsec</a></h3>
+
+<p>IPsec is designed to secure IP links between machines. It does that well,
+but it is important to remember that there are many things it does not do.
+Some of the important limitations are:</p>
+<dl>
+ <dt><a name="depends">IPsec cannot be secure if your system isn't</a></dt>
+ <dd>System security on IPsec gateway machines is an essential requirement
+ if IPsec is to function as designed. No system can be trusted if the
+ underlying machine has been subverted. See books on Unix security such
+ as <a href="biblio.html#practical">Garfinkel and Spafford</a> or our
+ web references for <a href="web.html#linsec">Linux security</a> or more
+ general <a href="web.html#compsec">computer security</a>.
+ <p>Of course, there is another side to this. IPsec can be a powerful
+ tool for improving system and network security. For example, requiring
+ packet authentication makes various spoofing attacks harder and IPsec
+ tunnels can be extremely useful for secure remote administration of
+ various things.</p>
+ </dd>
+ <dt><a name="not-end-to-end">IPsec is not end-to-end</a></dt>
+ <dd>IPsec cannot provide the same end-to-end security as systems working
+ at higher levels. IPsec encrypts an IP connection between two machines,
+ which is quite a different thing than encrypting messages between users
+ or between applications.
+ <p>For example, if you need mail encrypted from the sender's desktop to
+ the recipient's desktop and decryptable only by the recipient, use <a
+ href="glossary.html#PGP">PGP</a> or another such system. IPsec can
+ encrypt any or all of the links involved -- between the two mail
+ servers, or between either server and its clients. It could even be
+ used to secure a direct IP link from the sender's desktop machine to
+ the recipient's, cutting out any sort of network snoop. What it cannot
+ ensure is end-to-end user-to-user security. If only IPsec is used to
+ secure mail, then anyone with appropriate privileges on any machine
+ where that mail is stored (at either end or on any store-and-forward
+ servers in the path) can read it.</p>
+ <p>In another common setup, IPsec encrypts packets at a security
+ gateway machine as they leave the sender's site and decrypts them on
+ arrival at the gateway to the recipient's site. This does provide a
+ useful security service -- only encrypted data is passed over the
+ Internet -- but it does not even come close to providing an end-to-end
+ service. In particular, anyone with appropriate privileges on either
+ site's LAN can intercept the message in unencrypted form.</p>
+ </dd>
+ <dt><a name="notpanacea">IPsec cannot do everything</a></dt>
+ <dd>IPsec also cannot provide all the functions of systems working at
+ higher levels of the protocol stack. If you need a document
+ electronically signed by a particular person, then you need his or her
+ <a href="glossary.html#signature">digital signature</a> and a <a
+ href="glossary.html#public">public key cryptosystem</a> to verify it
+ with.
+ <p>Note, however, that IPsec authentication of the underlying
+ communication can make various attacks on higher-level protocols more
+ difficult. In particular, authentication prevents <a
+ href="glossary.html#middle">man-in-the-middle attacks</a>.</p>
+ </dd>
+ <dt><a name="no_user">IPsec authenticates machines, not users</a></dt>
+ <dd>IPsec uses strong authentication mechanisms to control which messages
+ go to which machines, but it does not have the concept of user ID,
+ which is vital to many other security mechansims and policies. This
+ means some care must be taken in fitting the various security
+ mechansims on a network together. For example, if you need to control
+ which users access your database server, you need some non-IPsec
+ mechansim for that. IPsec can control which machines connect to the
+ server, and can ensure that data transfer to those machines is done
+ securely, but that is all. Either the machines themselves must control
+ user access or there must be some form of user authentication to the
+ database, independent of IPsec.</dd>
+ <dt><a name="DoS">IPsec does not stop denial of service attacks</a></dt>
+ <dd><a href="glossary.html#DOS">Denial of service</a> attacks aim at
+ causing a system to crash, overload, or become confused so that
+ legitimate users cannot get whatever services the system is supposed to
+ provide. These are quite different from attacks in which the attacker
+ seeks either to use the service himself or to subvert the service into
+ delivering incorrect results.
+ <p>IPsec shifts the ground for DoS attacks; the attacks possible
+ against systems using IPsec are different than those that might be used
+ against other systems. It does not, however, eliminate the possibility
+ of such attacks.</p>
+ </dd>
+ <dt><a name="traffic">IPsec does not stop traffic analysis</a></dt>
+ <dd><a href="glossary.html#traffic">Traffic analysis</a> is the attempt
+ to derive intelligence from messages without regard for their contents.
+ In the case of IPsec, it would mean analysis based on things visible in
+ the unencrypted headers of encrypted packets -- source and destination
+ gateway addresses, packet size, et cetera. Given the resources to
+ acquire such data and some skill in analysing it (both of which any
+ national intelligence agency should have), this can be a very powerful
+ technique.
+ <p>IPsec is not designed to defend against this. Partial defenses are
+ certainly possible, and some are <a href="#traffic.resist">described
+ below</a>, but it is not clear that any complete defense can be
+ provided.</p>
+ </dd>
+</dl>
+
+<h3><a name="uses">IPsec is a general mechanism for securing IP</a></h3>
+
+<p>While IPsec does not provide all functions of a mail encryption package,
+it can encrypt your mail. In particular, it can ensure that all mail passing
+between a pair or a group of sites is encrypted. An attacker looking only at
+external traffic, without access to anything on or behind the IPsec gateway,
+cannot read your mail. He or she is stymied by IPsec just as he or she would
+be by <a href="glossary.html#PGP">PGP</a>.</p>
+
+<p>The advantage is that IPsec can provide the same protection for <strong>
+anything transmitted over IP</strong>. In a corporate network example, PGP
+lets the branch offices exchange secure mail with head office. SSL and SSH
+allow them to securely view web pages, connect as terminals to machines, and
+so on. IPsec can support all those applications, plus database queries, file
+sharing (NFS or Windows), other protocols encapsulated in IP (Netware,
+Appletalk, ...), phone-over-IP, video-over-IP, ... anything-over-IP. The only
+limitation is that IP Multicast is not yet supported, though there are
+Internet Draft documents for that.</p>
+
+<p>IPsec creates <strong>secure tunnels through untrusted networks</strong>.
+Sites connected by these tunnels form VPNs, <a
+href="glossary.html#VPN">Virtual Private Networks</a>.</p>
+
+<p>IPsec gateways can be installed wherever they are required.</p>
+<ul>
+ <li>One organisation might choose to install IPsec only on firewalls
+ between their LANs and the Internet. This would allow them to create a
+ VPN linking several offices. It would provide protection against anyone
+ outside their sites.</li>
+ <li>Another might install IPsec on departmental servers so everything on
+ the corporate backbone net was encrypted. This would protect messages on
+ that net from everyone except the sending and receiving department.</li>
+ <li>Another might be less concerned with information secrecy and more with
+ controlling access to certain resources. They might use IPsec packet
+ authentication as part of an access control mechanism, with or without
+ also using the IPsec encryption service.</li>
+ <li>It is even possible (assuming adequate processing power and an IPsec
+ implementation in each node) to make every machine its own IPsec gateway
+ so that everything on a LAN is encrypted. This protects information from
+ everyone outside the sending and receiving machine.</li>
+ <li>These techniques can be combined in various ways. One might, for
+ example, require authentication everywhere on a network while using
+ encryption only for a few links.</li>
+</ul>
+
+<p>Which of these, or of the many other possible variants, to use is up to
+you. <strong>IPsec provides mechanisms; you provide the policy</strong>.</p>
+
+<p><strong>No end user action is required</strong> for IPsec security to be
+used; they don't even have to know about it. The site administrators, of
+course, do have to know about it and to put some effort into making it work.
+Poor administration can compromise IPsec as badly as the post-it notes
+mentioned above. It seems reasonable, though, for organisations to hope their
+system administrators are generally both more security-conscious than end
+users and more able to follow computer security procedures. If not, at least
+there are fewer of them to educate or replace.</p>
+
+<p>IPsec can be, and often should be, used with along with security protocols
+at other levels. If two sites communicate with each other via the Internet,
+then IPsec is the obvious way to protect that communication. If two others
+have a direct link between them, either link encryption or IPsec would make
+sense. Choose one or use both. Whatever you use at and below the IP level,
+use other things as required above that level. Whatever you use above the IP
+level, consider what can be done with IPsec to make attacks on the higher
+levels harder. For example, <a href="glossary.html#middle">man-in-the-middle
+attacks</a> on various protocols become difficult if authentication at packet
+level is in use on the potential victims' communication channel.</p>
+
+<h3><a name="authonly">Using authentication without encryption</a></h3>
+
+<p>Where appropriate, IPsec can provide authentication without encryption.
+One might do this, for example:</p>
+<ul>
+ <li>where the data is public but one wants to be sure of getting the right
+ data, for example on some web sites</li>
+ <li>where encryption is judged unnecessary, for example on some company or
+ department LANs</li>
+ <li>where strong encryption is provided at link level, below IP</li>
+ <li>where strong encryption is provided in other protocols, above IP<br>
+ Note that IPsec authentication may make some attacks on those protocols
+ harder.</li>
+</ul>
+
+<p>Authentication has lower overheads than encryption.</p>
+
+<p>The protocols provide four ways to build such connections, using either an
+AH-only connection or ESP using null encryption, and in either manually or
+automatically keyed mode. FreeS/WAN supports only one of these, manually
+keyed AH-only connections, and <strong>we do not recommend using
+that</strong>. Our reasons are discussed under <a
+href="#traffic.resist">Resisting traffic analysis</a> a few sections further
+along.</p>
+
+<h3><a name="encnoauth">Encryption without authentication is
+dangerous</a></h3>
+
+<p>Originally, the IPsec encryption protocol <a
+href="glossary.html#ESP">ESP</a> didn't do integrity checking. It only did
+encryption. Steve Bellovin found many ways to attack ESP used without
+authentication. See his paper <a
+href="http://www.research.att.com/~smb/papers/badesp.ps">Problem areas for
+the IP Security Protocols</a>. To make a secure connection, you had to add an
+<a href="glossary.html#AH">AH</a> Authentication Header as well as ESP.
+Rather than incur the overhead of several layers (and rather than provide an
+ESP layer that didn't actually protect the traffic), the IPsec working group
+built integrity and replay checking directly into ESP.</p>
+
+<p>Today, typical usage is one of:</p>
+<ul>
+ <li>ESP for encryption and authentication</li>
+ <li>AH for authentication alone</li>
+</ul>
+
+<p>Other variants are allowed by the standard, but not much used:</p>
+<dl>
+ <dt>ESP encryption without authentication</dt>
+ <dd><strong>Bellovin has demonstrated fatal flaws in this. Do not
+ use.</strong></dd>
+ <dt>ESP encryption with AH authentication</dt>
+ <dd>This has higher overheads than using the authentication in ESP, and
+ no obvious benefit in most cases. The exception might be a network
+ where AH authentication was widely or universally used. If you're going
+ to do AH to conform with network policy, why authenticate again in the
+ ESP layer?</dd>
+ <dt>Authenticate twice, with AH and with ESP</dt>
+ <dd>Why? Of course, some folk consider "belt and suspenders" the sensible
+ approach to security. If you're among them, you might use both
+ protocols here. You might also use both to satisfy different parts of a
+ security policy. For example, an organisation might require AH
+ authentication everywhere but two users within the organisation might
+ use ESP as well.</dd>
+ <dt>ESP authentication without encryption</dt>
+ <dd>The standard allows this, calling it "null encryption". FreeS/WAN
+ does not support it. We recommend that you use AH instead if
+ authentication is all you require. AH authenticates parts of the IP
+ header, which ESP-null does not do.</dd>
+</dl>
+
+<p>Some of these variants cannot be used with FreeS/WAN because we do not
+support ESP-null and do not support automatic keying of AH-only
+connections.</p>
+
+<p>There are fairly frequent suggestions that AH be dropped entirely from the
+IPsec specifications since ESP and null encryption can handle that situation.
+It is not clear whether this will occur. My guess is that it is unlikely.</p>
+
+<h3><a name="multilayer">Multiple layers of IPsec processing are
+possible</a></h3>
+
+<p>The above describes combinations possible on a single IPsec connection. In
+a complex network you may have several layers of IPsec in play, with any of
+the above combinations at each layer.</p>
+
+<p>For example, a connection from a desktop machine to a database server
+might require AH authentication. Working with other host, network and
+database security measures, AH might be just the thing for access control.
+You might decide not to use ESP encryption on such packets, since it uses
+resources and might complicate network debugging. Within the site where the
+server is, then, only AH would be used on those packets.</p>
+
+<p>Users at another office, however, might have their whole connection (AH
+headers and all) passing over an IPsec tunnel connecting their office to the
+one with the database server. Such a tunnel should use ESP encryption and
+authentication. You need authentication in this layer because without
+authentication the encryption is vulnerable and the gateway cannot verify the
+AH authentication. The AH is between client and database server; the gateways
+aren't party to it.</p>
+
+<p>In this situation, some packets would get multiple layers of IPsec applied
+to them, AH on an end-to-end client-to-server basis and ESP from one office's
+security gateway to the other.</p>
+
+<h3><a name="traffic.resist">Resisting traffic analysis</a></h3>
+
+<p><a href="glossary.html#traffic">Traffic analysis</a> is the attempt to
+derive useful intelligence from encrypted traffic without breaking the
+encryption.</p>
+
+<p>Is your CEO exchanging email with a venture capital firm? With bankruptcy
+trustees? With an executive recruiting agency? With the holder of some
+important patents? If an eavesdropper learns about any of those, then he has
+interesting intelligence on your company, whether or not he can read the
+messages themselves.</p>
+
+<p>Even just knowing that there is network traffic between two sites may tell
+an analyst something useful, especially when combined with whatever other
+information he or she may have. For example, if you know Company A is having
+cashflow problems and Company B is looking for aquisitions, then knowing that
+packets are passing between the two is interesting. It is more interesting if
+you can tell it is email, and perhaps yet more if you know the sender and
+recipient.</p>
+
+<p>Except in the simplest cases, traffic analysis is hard to do well. It
+requires both considerable resources and considerable analytic skill.
+However, intelligence agencies of various nations have been doing it for
+centuries and many of them are likely quite good at it by now. Various
+commercial organisations, especially those working on "targeted marketing"
+may also be quite good at analysing certain types of traffic.</p>
+
+<p>In general, defending against traffic analysis is also difficult.
+Inventing a really good defense could get you a PhD and some interesting job
+offers.</p>
+
+<p>IPsec is not designed to stop traffic analysis and we know of no plausible
+method of extending it to do so. That said, there are ways to make traffic
+analysis harder. This section describes them.</p>
+
+<h4><a name="extra">Using "unnecessary" encryption</a></h4>
+
+<p>One might choose to use encryption even where it appears unnecessary in
+order to make analysis more difficult. Consider two offices which pass a
+small volume of business data between them using IPsec and also transfer
+large volumes of Usenet news. At first glance, it would seem silly to encrypt
+the newsfeed, except possibly for any newsgroups that are internal to the
+company. Why encrypt data that is all publicly available from many sites?</p>
+
+<p>However, if we encrypt a lot of news and send it down the same connection
+as our business data, we make <a href="glossary.html#traffic">traffic
+analysis</a> much harder. A snoop cannot now make inferences based on
+patterns in the volume, direction, sizes, sender, destination, or timing of
+our business messages. Those messages are hidden in a mass of news messages
+encapsulated in the same way.</p>
+
+<p>If we're going to do this we need to ensure that keys change often enough
+to remain secure even with high volumes and with the adversary able to get
+plaintext of much of the data. We also need to look at other attacks this
+might open up. For example, can the adversary use a chosen plaintext attack,
+deliberately posting news articles which, when we receive and encrypt them,
+will help break our encryption? Or can he block our business data
+transmission by flooding us with silly news articles? Or ...</p>
+
+<p>Also, note that this does not provide complete protection against traffic
+analysis. A clever adversary might still deduce useful intelligence from
+statistical analysis (perhaps comparing the input newsfeed to encrypted
+output, or comparing the streams we send to different branch offices), or by
+looking for small packets which might indicate establishment of TCP
+connections, or ...</p>
+
+<p>As a general rule, though, to improve resistance to traffic analysis, you
+should <strong>encrypt as much traffic as possible, not just as much as seems
+necessary.</strong></p>
+
+<h4><a name="multi-encrypt">Using multiple encryption</a></h4>
+
+<p>This also applies to using multiple layers of encryption. If you have an
+IPsec tunnel between two branch offices, it might appear silly to send <a
+href="glossary.html#PGP">PGP</a>-encrypted email through that tunnel.
+However, if you suspect someone is snooping your traffic, then it does make
+sense:</p>
+<ul>
+ <li>it protects the mail headers; they cannot even see who is mailing
+ who</li>
+ <li>it protects against user bungles or software malfunctions that
+ accidentally send messages in the clear</li>
+ <li>it makes any attack on the mail encryption much harder; they have to
+ break IPsec or break into your network before they can start on the mail
+ encryption</li>
+</ul>
+
+<p>Similar arguments apply for <a href="glossary.html#SSL">SSL</a>-encrypted
+web traffic or <a href="glossary.html#SSH">SSH</a>-encrypted remote login
+sessions, even for end-to-end IPsec tunnels between systems in the two
+offices.</p>
+
+<h4><a name="fewer">Using fewer tunnels</a></h4>
+
+<p>It may also help to use fewer tunnels. For example, if all you actually
+need encrypted is connections between:</p>
+<ul>
+ <li>mail servers at branch and head offices</li>
+ <li>a few branch office users and the head office database server</li>
+</ul>
+
+<p>You might build one tunnel per mail server and one per remote database
+user, restricting traffic to those applications. This gives the traffic
+analyst some information, however. He or she can distinguish the tunnels by
+looking at information in the ESP header and, given that distinction and the
+patterns of tunnel usage, might be able to figure out something useful.
+Perhaps not, but why take the risk?</p>
+
+<p>We suggest instead that you build one tunnel per branch office, encrypting
+everything passing from head office to branches. This has a number of
+advantages:</p>
+<ul>
+ <li>it is easier to build and administer</li>
+ <li>it resists traffic analysis somewhat better</li>
+ <li>it provides security for whatever you forgot. For example, if some user
+ at a remote office browses proprietary company data on some head office
+ web page (that the security people may not even know about!), then that
+ data is encrypted before it reaches the Internet.</li>
+</ul>
+
+<p>Of course you might also want to add additional tunnels. For example, if
+some of the database data is confidential and should not be exposed even
+within the company, then you need protection from the user's desktop to the
+database server. We suggest you do that in whatever way seems appropriate --
+IPsec, SSH or SSL might fit -- but, whatever you choose, pass it between
+locations via a gateway-to-gateway IPsec tunnel to provide some resistance to
+traffic analysis.</p>
+
+<h2><a name="primitives">Cryptographic components</a></h2>
+
+<p>IPsec combines a number of cryptographic techniques, all of them
+well-known and well-analyzed. The overall design approach was conservative;
+no new or poorly-understood components were included.</p>
+
+<p>This section gives a brief overview of each technique. It is intended only
+as an introduction. There is more information, and links to related topics,
+in our <a href="glossary.html">glossary</a>. See also our <a
+href="biblio.html">bibliography</a> and cryptography <a
+href="web.html#crypto.link">web links</a>.</p>
+
+<h3><a name="block.cipher">Block ciphers</a></h3>
+
+<p>The <a href="glossary.html#encryption">encryption</a> in the <a
+href="glossary.html#ESP">ESP</a> encapsulation protocol is done with a <a
+href="glossary.html#block">block cipher</a>.</p>
+
+<p>We do not implement <a href="glossary.html#DES">single DES</a>. It is <a
+href="politics.html#desnotsecure">insecure</a>. Our default, and currently
+only, block cipher is <a href="glossary.html#3DES">triple DES</a>.</p>
+
+<p>The <a href="glossary.html#rijndael">Rijndael</a> block cipher has won the
+<a href="glossary.html#AES">AES</a> competition to choose a relacement for
+DES. It will almost certainly be added to FreeS/WAN and to other IPsec
+implementations. <a href="web.html#patch">Patches</a> are already
+available.</p>
+
+<h3><a name="hash.ipsec">Hash functions</a></h3>
+
+<h4><a name="hmac.ipsec">The HMAC construct</a></h4>
+
+<p>IPsec packet authentication is done with the <a
+href="glossary.html#HMAC">HMAC</a> construct. This is not just a hash of the
+packet data, but a more complex operation which uses both a hashing algorithm
+and a key. It therefore does more than a simple hash would. A simple hash
+would only tell you that the packet data was not changed in transit, or that
+whoever changed it also regenerated the hash. An HMAC also tells you that the
+sender knew the HMAC key.</p>
+
+<p>For IPsec HMAC, the output of the hash algorithm is truncated to 96 bits.
+This saves some space in the packets. More important, it prevents an attacker
+from seeing all the hash output bits and perhaps creating some sort of attack
+based on that knowledge.</p>
+
+<h4>Choice of hash algorithm</h4>
+
+<p>The IPsec RFCs require two hash algorithms -- <a
+href="glossary.html#MD5">MD5</a> and <a href="glossary.html#SHA">SHA-1</a> --
+both of which FreeS/WAN implements.</p>
+
+<p>Various other algorithms -- such as RIPEMD and Tiger -- are listed in the
+RFCs as optional. None of these are in the FreeS/WAN distribution, or are
+likely to be added, although user <a href="web.html#patch">patches</a> exist
+for several of them.</p>
+
+<p>Additional hash algorithms -- <a href="glossary.html#SHA-256">SHA-256,
+SHA-384 and SHA-512</a> -- may be required to give hash strength matching the
+strength of <a href="glossary.html#AES">AES</a>. These are likely to be added
+to FreeS/WAN along with AES.</p>
+
+<h3><a name="DH.keying">Diffie-Hellman key agreement</a></h3>
+
+<p>The <a href="glossary.html#DH">Diffie-Hellman</a> key agreement protocol
+allows two parties (A and B or <a href="glossary.html#alicebob">Alice and
+Bob</a>) to agree on a key in such a way that an eavesdropper who intercepts
+the entire conversation cannot learn the key.</p>
+
+<p>The protocol is based on the <a href="glossary.html#dlog">discrete
+logarithm</a> problem and is therefore thought to be secure. Mathematicians
+have been working on that problem for years and seem no closer to a solution,
+though there is no proof that an efficient solution is impossible.</p>
+
+<h3><a name="RSA.auth">RSA authentication</a></h3>
+
+<p>The <a href="glossary.html#RSA">RSA</a> algorithm (named for its inventors
+-- Rivest, Shamir and Adleman) is a very widely used <a
+href="glossary.html#">public key</a> cryptographic technique. It is used in
+IPsec as one method of authenticating gateways for Diffie-Hellman key
+negotiation.</p>
+
+<h2><a name="structure">Structure of IPsec</a></h2>
+
+<p>There are three protocols used in an IPsec implementation:</p>
+<dl>
+ <dt>ESP, Encapsulating Security Payload</dt>
+ <dd>Encrypts and/or authenticates data</dd>
+ <dt>AH, Authentication Header</dt>
+ <dd>Provides a packet authentication service</dd>
+ <dt>IKE, Internet Key Exchange</dt>
+ <dd>Negotiates connection parameters, including keys, for the other
+ two</dd>
+</dl>
+
+<p>The term "IPsec" is slightly ambiguous. In some contexts, it includes all
+three of the above but in other contexts it refers only to AH and ESP.</p>
+
+<h3><a name="IKE.ipsec">IKE (Internet Key Exchange)</a></h3>
+
+<p>The IKE protocol sets up IPsec (ESP or AH) connections after negotiating
+appropriate parameters (algorithms to be used, keys, connection lifetimes)
+for them. This is done by exchanging packets on UDP port 500 between the two
+gateways.</p>
+
+<p>IKE (RFC 2409) was the outcome of a long, complex process in which quite a
+number of protocols were proposed and debated. Oversimplifying mildly, IKE
+combines:</p>
+<dl>
+ <dt>ISAKMP (RFC 2408)</dt>
+ <dd>The <strong>I</strong>nternet <strong>S</strong>ecurity
+ <strong>A</strong>ssociation and <strong>K</strong>ey
+ <strong>M</strong>anagement <strong>P</strong>rotocol manages
+ negotiation of connections and defines <a
+ href="glossary.html#SA">SA</a>s (Security Associations) as a means of
+ describing connection properties.</dd>
+ <dt>IPsec DOI for ISAKMP (RFC 2407)</dt>
+ <dd>A <strong>D</strong>omain <strong>O</strong>f
+ <strong>I</strong>nterpretation fills in the details necessary to turn
+ the rather abstract ISAKMP protocol into a more tightly specified
+ protocol, so it becomes applicable in a particular domain.</dd>
+ <dt>Oakley key determination protocol (RFC 2412)</dt>
+ <dd>Oakley creates keys using the <a
+ href="glossary.html#DH">Diffie-Hellman</a> key agreement protocol.</dd>
+</dl>
+
+<p>For all the details, you would need to read the four <a
+href="rfc.html">RFCs</a> just mentioned (over 200 pages) and a number of
+others. We give a summary below, but it is far from complete.</p>
+
+<h4><a name="phases">Phases of IKE</a></h4>
+
+<p>IKE negotiations have two phases.</p>
+<dl>
+ <dt>Phase one</dt>
+ <dd>The two gateways negotiate and set up a two-way ISAKMP SA which they
+ can then use to handle phase two negotiations. One such SA between a
+ pair of gateways can handle negotiations for multiple tunnels.</dd>
+ <dt>Phase two</dt>
+ <dd>Using the ISAKMP SA, the gateways negotiate IPsec (ESP and/or AH) SAs
+ as required. IPsec SAs are unidirectional (a different key is used in
+ each direction) and are always negotiated in pairs to handle two-way
+ traffic. There may be more than one pair defined between two
+ gateways.</dd>
+</dl>
+
+<p>Both of these phases use the UDP protocol and port 500 for their
+negotiations.</p>
+
+<p>After both IKE phases are complete, you have IPsec SAs to carry your
+encrypted data. These use the ESP or AH protocols. These protocols do not
+have ports. Ports apply only to UDP or TCP.</p>
+
+<p>The IKE protocol is designed to be extremely flexible. Among the things
+that can be negotiated (separately for each SA) are:</p>
+<ul>
+ <li>SA lifetime before rekeying</li>
+ <li>encryption algorithm used. We currently support only <a
+ href="glossary.html#3DES">triple DES</a>. Single DES is <a
+ href="politics.html#desnotsecure">insecure</a>. The RFCs say you MUST do
+ DES, SHOULD do 3DES and MAY do various others. We do not do any of the
+ others.</li>
+ <li>authentication algorithms. We support <a
+ href="glossary.html#MD5">MD5</a> and <a href="glossary.html#SHA">SHA</a>.
+ These are the two the RFCs require.</li>
+ <li>choice of group for <a href="glossary.html#DH">Diffie-Hellman</a> key
+ agreement. We currently support Groups 2 and 5 (which are defined modulo
+ primes of various lengths) and do not support Group 1 (defined modulo a
+ shorter prime, and therefore cryptographically weak) or groups 3 and 4
+ (defined using elliptic curves). The RFCs require only Group 1.</li>
+</ul>
+
+<p>The protocol also allows implementations to add their own encryption
+algorithms, authentication algorithms or Diffie-Hellman groups. We do not
+support any such extensions, but there are some <a
+href="web.html#patch">patches</a> that do.</p>
+
+<p>There are a number of complications:</p>
+<ul>
+ <li>The gateways must be able to authenticate each other's identities
+ before they can create a secure connection. This host authentication is
+ part of phase one negotiations, and is a required prerequisite for packet
+ authentication used later. Host authentication can be done in a variety
+ of ways. Those supported by FreeS/WAN are discussed in our <a
+ href="adv_config.html#auto-auth">advanced configuration</a> document.</li>
+ <li>Phase one can be done in two ways.
+ <ul>
+ <li>Main Mode is required by the RFCs and supported in FreeS/WAN. It
+ uses a 6-packet exzchange.</li>
+ <li>Aggressive Mode is somewhat faster (only 3 packets) but reveals
+ more to an eavesdropper. This is optional in the RFCs, not currently
+ supported by FreeS/WAN, and not likely to be.</li>
+ </ul>
+ </li>
+ <li>A new group exchange may take place after phase one but before phase
+ two, defining an additional group for use in the <a
+ href="glossary.html#DH">Diffie-Hellman</a> key agreement part of phase
+ two. FreeS/WAN does not currently support this.</li>
+ <li>Phase two always uses Quick Mode, but there are two variants of that:
+ <ul>
+ <li>One variant provides <a href="glossary.html#PFS">Perfect Forward
+ Secrecy (PFS)</a>. An attacker that obtains your long-term host
+ authentication key does not immediately get any of your short-term
+ packet encryption of packet authentication keys. He must conduct
+ another successful attack each time you rekey to get the short-term
+ keys. Having some short-term keys does not help him learn others. In
+ particular, breaking your system today does not let him read messages
+ he archived yestarday, assuming you've changed short-term keys in the
+ meanwhile. We enable PFS as the default.</li>
+ <li>The other variant disables PFS and is therefore slightly faster. We
+ do not recommend this since it is less secure, but FreeS/WAN does
+ support it. You can enable it with a <var>pfs=no</var> statement in
+ <a href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a>.</li>
+ <li>The protocol provides no way to negotiate which variant will be
+ used. If one gateway is set for PFS and the other is not, the
+ negotiation fails. This has proved a fairly common source of
+ interoperation problems.</li>
+ </ul>
+ </li>
+ <li>Several types of notification message may be sent by either side during
+ either phase, or later. FreeS/WAN does not currently support these, but
+ they are a likely addition in future releases.</li>
+ <li>There is a commit flag which may optionally be set on some messages.
+ The <a href="http://www.lounge.org/ike_doi_errata.html">errata</a> page
+ for the RFCs includes two changes related to this, one to clarify the
+ description of its use and one to block a <a
+ href="glossary.html#DOS">denial of service</a> attack which uses it. We
+ currently do not implement this feature.</li>
+</ul>
+
+<p>These complications can of course lead to problems, particularly when two
+different implementations attempt to interoperate. For example, we have seen
+problems such as:</p>
+<ul>
+ <li>Some implementations (often products crippled by <a
+ href="politics.html#exlaw">export laws</a>) have the insecure DES
+ algorithm as their only supported encryption method. Other parts of our
+ documentation discuss the <a
+ href="politics.html#desnotsecure">reasons we do not implement single
+ DES</a>, and <a href="interop.html#noDES">how to cope with crippled
+ products</a>.</li>
+ <li>Windows 2000 IPsec tries to negotiate using Aggressive Mode, which we
+ don't support. Later on, it uses the commit bit, which we also don't
+ support.</li>
+ <li>Various implementations disable PFS by default, and therefore will not
+ talk to FreeS/WAN until you either turn on PFS on their end or turn it
+ off in FreeS/WAN with a <var>pfs=no</var> entry in the connection
+ description.</li>
+ <li>FreeS/WAN's interaction with PGPnet is complicated by their use of
+ notification messages we do not yet support.</li>
+</ul>
+
+<p>Despite this, we do interoperate successfully with many implementations,
+including both Windows 2000 and PGPnet. Details are in our <a
+href="interop.html">interoperability</a> document.</p>
+
+<h4><a name="sequence">Sequence of messages in IKE</a></h4>
+
+<p>Each phase (see <a href="#phases">previous section</a>)of IKE involves a
+series of messages. In Pluto error messages, these are abbreviated using:</p>
+<dl>
+ <dt>M</dt>
+ <dd><strong>M</strong>ain mode, settting up the keying channel (ISAKMP
+ SA)</dd>
+ <dt>Q</dt>
+ <dd><strong>Q</strong>uick mode, setting up the data channel (IPsec
+ SA)</dd>
+ <dt>I</dt>
+ <dd><strong>I</strong>nitiator, the machine that starts the
+ negotiation</dd>
+ <dt>R</dt>
+ <dd><strong>R</strong>esponder</dd>
+</dl>
+
+<p>For example, the six messages of a main mode negotiation, in sequence, are
+labelled:</p>
+<pre> MI1 ----------&gt;
+ &lt;---------- MR1
+ MI2 ----------&gt;
+ &lt;---------- MR2
+ MI3 ----------&gt;
+ &lt;---------- MR3</pre>
+
+<h4><a name="struct.exchange">Structure of IKE messages</a></h4>
+
+<p>Here is our Pluto developer explaining some of this on the mailing
+list:</p>
+<pre>When one IKE system (for example, Pluto) is negotiating with another
+to create an SA, the Initiator proposes a bunch of choices and the
+Responder replies with one that it has selected.
+
+The structure of the choices is fairly complicated. An SA payload
+contains a list of lists of "Proposals". The outer list is a set of
+choices: the selection must be from one element of this list.
+
+Each of these elements is a list of Proposals. A selection must be
+made from each of the elements of the inner list. In other words,
+*all* of them apply (that is how, for example, both AH and ESP can
+apply at once).
+
+Within each of these Proposals is a list of Transforms. For each
+Proposal selected, one Transform must be selected (in other words,
+each Proposal provides a choice of Transforms).
+
+Each Transform is made up of a list of Attributes describing, well,
+attributes. Such as lifetime of the SA. Such as algorithm to be
+used. All the Attributes apply to a Transform.
+
+You will have noticed a pattern here: layers alternate between being
+disjunctions ("or") and conjunctions ("and").
+
+For Phase 1 / Main Mode (negotiating an ISAKMP SA), this structure is
+cut back. There must be exactly one Proposal. So this degenerates to
+a list of Transforms, one of which must be chosen.</pre>
+
+<h3><a name="services">IPsec Services, AH and ESP</a></h3>
+
+<p>IPsec offers two services, <a
+href="glossary.html#authentication">authentication</a> and <a
+href="glossary.html#encryption">encryption</a>. These can be used separately
+but are often used together.</p>
+<dl>
+ <dt>Authentication</dt>
+ <dd>Packet-level authentication allows you to be confident that a packet
+ came from a particular machine and that its contents were not altered
+ en route to you. No attempt is made to conceal or protect the contents,
+ only to assure their integrity. Packet authentication can be provided
+ separately using an <a href="glossary.html#AH">Authentication
+ Header</a>, described just below, or it can be included as part of the
+ <a href="glossary.html#ESP">ESP</a> (Encapsulated Security Payload)
+ service, described in the following section. That service offers
+ encryption as well as authentication. In either case, the <a
+ href="glossary.html#HMAC">HMAC</a> construct is used as the
+ authentication mechanism.
+ <p>There is a separate authentication operation at the IKE level, in
+ which each gateway authenticates the other. This can be done in a
+ variety of ways.</p>
+ </dd>
+ <dt>Encryption</dt>
+ <dd>Encryption allows you to conceal the contents of a message from
+ eavesdroppers.
+ <p>In IPsec this is done using a <a href="glossary.html#block">block
+ cipher</a> (normally <a href="glossary.html#3DES">Triple DES</a> for
+ Linux). In the most used setup, keys are automatically negotiated, and
+ periodically re-negotiated, using the <a
+ href="glossary.html#IKE">IKE</a> (Internet Key Exchange) protocol. In
+ Linux FreeS/WAN this is handled by the Pluto Daemon.</p>
+ <p>The IPsec protocol offering encryption is <a
+ href="glossary.html#ESP">ESP</a>, Encapsulated Security Payload. It can
+ also include a packet authentication service.</p>
+ </dd>
+</dl>
+
+<p>Note that <strong>encryption should always be used with some packet
+authentication service</strong>. Unauthenticated encryption is vulnerable to
+<a href="glossary.html#middle">man-in-the-middle attacks</a>. Also note that
+encryption does not prevent <a href="glossary.html#traffic">traffic
+analysis</a>.</p>
+
+<h3><a name="AH.ipsec">The Authentication Header (AH)</a></h3>
+
+<p>Packet authentication can be provided separately from encryption by adding
+an authentication header (AH) after the IP header but before the other
+headers on the packet. This is the subject of this section. Details are in
+RFC 2402.</p>
+
+<p>Each of the several headers on a packet header contains a "next protocol"
+field telling the system what header to look for next. IP headers generally
+have either TCP or UDP in this field. When IPsec authentication is used, the
+packet IP header has AH in this field, saying that an Authentication Header
+comes next. The AH header then has the next header type -- usually TCP, UDP
+or encapsulated IP.</p>
+
+<p>IPsec packet authentication can be added in transport mode, as a
+modification of standard IP transport. This is shown in this diagram from the
+RFC:</p>
+<pre> BEFORE APPLYING AH
+ ----------------------------
+ IPv4 |orig IP hdr | | |
+ |(any options)| TCP | Data |
+ ----------------------------
+
+ AFTER APPLYING AH
+ ---------------------------------
+ IPv4 |orig IP hdr | | | |
+ |(any options)| AH | TCP | Data |
+ ---------------------------------
+ ||
+ except for mutable fields</pre>
+
+<p>Athentication can also be used in tunnel mode, encapsulating the
+underlying IP packet beneath AH and an additional IP header.</p>
+<pre> ||
+IPv4 | new IP hdr* | | orig IP hdr* | | |
+ |(any options)| AH | (any options) |TCP | Data |
+ ------------------------------------------------
+ ||
+ | in the new IP hdr |</pre>
+
+<p>This would normally be used in a gateway-to-gateway tunnel. The receiving
+gateway then strips the outer IP header and the AH header and forwards the
+inner IP packet.</p>
+
+<p>The mutable fields referred to are things like the time-to-live field in
+the IP header. These cannot be included in authentication calculations
+because they change as the packet travels.</p>
+
+<h4><a name="keyed">Keyed MD5 and Keyed SHA</a></h4>
+
+<p>The actual authentication data in the header is typically 96 bits and
+depends both on a secret shared between sender and receiver and on every byte
+of the data being authenticated. The technique used is <a
+href="glossary.html#HMAC">HMAC</a>, defined in RFC 2104.</p>
+
+<p>The algorithms involved are the <a href="glossary.html#MD5">MD5</a>
+Message Digest Algorithm or <a href="glossary.html#SHA">SHA</a>, the Secure
+Hash Algorithm. For details on their use in this application, see RFCs 2403
+and 2404 respectively.</p>
+
+<p>For descriptions of the algorithms themselves, see RFC 1321 for MD5 and <a
+href="glossary.html#FIPS">FIPS</a> (Federal Information Processing Standard)
+number 186 from <a href="glossary.html#NIST">NIST</a>, the US National
+Institute of Standards and Technology for SHA. <a
+href="biblio.html#schneier"><cite>Applied Cryptography</cite></a> covers both
+in some detail, MD5 starting on page 436 and SHA on 442.</p>
+
+<p>These algorithms are intended to make it nearly impossible for anyone to
+alter the authenticated data in transit. The sender calculates a digest or
+hash value from that data and includes the result in the authentication
+header. The recipient does the same calculation and compares results. For
+unchanged data, the results will be identical. The hash algorithms are
+designed to make it extremely difficult to change the data in any way and
+still get the correct hash.</p>
+
+<p>Since the shared secret key is also used in both calculations, an
+interceptor cannot simply alter the authenticated data and change the hash
+value to match. Without the key, he or she (or even the dreaded They) cannot
+produce a usable hash.</p>
+
+<h4><a name="sequence">Sequence numbers</a></h4>
+
+<p>The authentication header includes a sequence number field which the
+sender is required to increment for each packet. The receiver can ignore it
+or use it to check that packets are indeed arriving in the expected
+sequence.</p>
+
+<p>This provides partial protection against <a
+href="glossary.html#replay">replay attacks</a> in which an attacker resends
+intercepted packets in an effort to confuse or subvert the receiver. Complete
+protection is not possible since it is necessary to handle legitmate packets
+which are lost, duplicated, or delivered out of order, but use of sequence
+numbers makes the attack much more difficult.</p>
+
+<p>The RFCs require that sequence numbers never cycle, that a new key always
+be negotiated before the sequence number reaches 2^32-1. This protects both
+against replays attacks using packets from a previous cyclce and against <a
+href="glossary.html#birthday">birthday attacks</a> on the the packet
+authentication algorithm.</p>
+
+<p>In Linux FreeS/WAN, the sequence number is ignored for manually keyed
+connections and checked for automatically keyed ones. In manual mode, there
+is no way to negotiate a new key, or to recover from a sequence number
+problem, so we don't use sequence numbers.</p>
+
+<h3><a name="ESP.ipsec">Encapsulated Security Payload (ESP)</a></h3>
+
+<p>The ESP protocol is defined in RFC 2406. It provides one or both of
+encryption and packet authentication. It may be used with or without AH
+packet authentication.</p>
+
+<p>Note that <strong>some form of packet authentication should
+<em>always</em> be used whenever data is encrypted</strong>. Without
+authentication, the encryption is vulnerable to active attacks which may
+allow an enemy to break the encryption. ESP should <strong>always</strong>
+either include its own authentication or be used with AH authentication.</p>
+
+<p>The RFCs require support for only two mandatory encryption algorithms --
+<a href="glossary.html#DES">DES</a>, and null encryption -- and for two
+authentication methods -- keyed MD5 and keyed SHA. Implementers may choose to
+support additional algorithms in either category.</p>
+
+<p>The authentication algorithms are the same ones used in the IPsec <a
+href="#AH">authentication header</a>.</p>
+
+<p>We do not implement single DES since <a
+href="politics.html#desnotsecure">DES is insecure</a>. Instead we provide <a
+href="glossary.html#3DES">triple DES or 3DES</a>. This is currently the only
+encryption algorithm supported.</p>
+
+<p>We do not implement null encryption since it is obviously insecure.</p>
+
+<h2><a name="modes">IPsec modes</a></h2>
+
+<p>IPsec can connect in two modes. Transport mode is a host-to-host
+connection involving only two machines. In tunnel mode, the IPsec machines
+act as gateways and trafiic for any number of client machines may be
+carried.</p>
+
+<h3><a name="tunnel.ipsec">Tunnel mode</a></h3>
+
+<p>Security gateways are required to support tunnel mode connections. In this
+mode the gateways provide tunnels for use by client machines behind the
+gateways. The client machines need not do any IPsec processing; all they have
+to do is route things to gateways.</p>
+
+<h3><a name="transport.ipsec">Transport mode</a></h3>
+
+<p>Host machines (as opposed to security gateways) with IPsec implementations
+must also support transport mode. In this mode, the host does its own IPsec
+processing and routes some packets via IPsec.</p>
+
+<h2><a name="parts">FreeS/WAN parts</a></h2>
+
+<h3><a name="KLIPS.ipsec">KLIPS: Kernel IPsec Support</a></h3>
+
+<p>KLIPS is <strong>K</strong>erne<strong>L</strong> <strong>IP</strong>SEC
+<strong>S</strong>upport, the modifications necessary to support IPsec within
+the Linux kernel. KILPS does all the actual IPsec packet-handling,
+including</p>
+<ul>
+ <li>encryption</li>
+ <li>packet authentication calculations</li>
+ <li>creation of ESP and AH headers for outgoing packets</li>
+ <li>interpretation of those headers on incoming packets</li>
+</ul>
+
+<p>KLIPS also checks all non-IPsec packets to ensure they are not bypassing
+IPsec security policies.</p>
+
+<h3><a name="Pluto.ipsec">The Pluto daemon</a></h3>
+
+<p><a href="manpage.d/ipsec_pluto.8.html">Pluto(8)</a> is a daemon which
+implements the IKE protocol. It</p>
+<ul>
+ <li>handles all the Phase one ISAKMP SAs</li>
+ <li>performs host authentication and negotiates with other gateways</li>
+ <li>creates IPsec SAs and passes the data required to run them to KLIPS</li>
+ <li>adjust routing and firewall setup to meet IPsec requirements. See our
+ <a href="firewall.html">IPsec and firewalling</a> document for
+ details.</li>
+</ul>
+
+<p>Pluto is controlled mainly by the <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> configuration file.</p>
+
+<h3><a name="command">The ipsec(8) command</a></h3>
+
+<p>The <a href="manpage.d/ipsec.8.html">ipsec(8)</a> command is a front end
+shellscript that allows control over IPsec activity.</p>
+
+<h3><a name="ipsec.conf">Linux FreeS/WAN configuration file</a></h3>
+
+<p>The configuration file for Linux FreeS/WAN is</p>
+<pre> /etc/ipsec.conf</pre>
+
+<p>For details see the <a
+href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> manual page .</p>
+
+<h2><a name="key">Key management</a></h2>
+
+<p>There are several ways IPsec can manage keys. Not all are implemented in
+Linux FreeS/WAN.</p>
+
+<h3><a name="current">Currently Implemented Methods</a></h3>
+
+<h4><a name="manual">Manual keying</a></h4>
+
+<p>IPsec allows keys to be manually set. In Linux FreeS/WAN, such keys are
+stored with the connection definitions in /etc/ipsec.conf.</p>
+
+<p><a href="glossary.html#manual">Manual keying</a> is useful for debugging
+since it allows you to test the <a href="glossary.html#KLIPS">KLIPS</a>
+kernel IPsec code without the <a href="glossary.html#Pluto">Pluto</a> daemon
+doing key negotiation.</p>
+
+<p>In general, however, automatic keying is preferred because it is more
+secure.</p>
+
+<h4><a name="auto">Automatic keying</a></h4>
+
+<p>In automatic keying, the <a href="glossary.html#Pluto">Pluto</a> daemon
+negotiates keys using the <a href="glossary.html#IKE">IKE</a> Internet Key
+Exchange protocol. Connections are automatically re-keyed periodically.</p>
+
+<p>This is considerably more secure than manual keying. In either case an
+attacker who acquires a key can read every message encrypted with that key,
+but automatic keys can be changed every few hours or even every few minutes
+without breaking the connection or requiring intervention by the system
+administrators. Manual keys can only be changed manually; you need to shut
+down the connection and have the two admins make changes. Moreover, they have
+to communicate the new keys securely, perhaps with <a
+href="glossary.html#PGP">PGP</a> or <a href="glossary.html#SSH">SSH</a>. This
+may be possible in some cases, but as a general solution it is expensive,
+bothersome and unreliable. Far better to let <a
+href="glossary.html#Pluto">Pluto</a> handle these chores; no doubt the
+administrators have enough to do.</p>
+
+<p>Also, automatic keying is inherently more secure against an attacker who
+manages to subvert your gateway system. If manual keying is in use and an
+adversary acquires root privilege on your gateway, he reads your keys from
+/etc/ipsec.conf and then reads all messages encrypted with those keys.</p>
+
+<p>If automatic keying is used, an adversary with the same privileges can
+read /etc/ipsec.secrets, but this does not contain any keys, only the secrets
+used to authenticate key exchanges. Having an adversary able to authenticate
+your key exchanges need not worry you overmuch. Just having the secrets does
+not give him any keys. You are still secure against <a
+href="glossary.html#passive">passive</a> attacks. This property of automatic
+keying is called <a href="glossary.html#PFS">perfect forward secrecy</a>,
+abbreviated PFS.</p>
+
+<p>Unfortunately, having the secrets does allow an <a
+href="glossary.html#active">active attack</a>, specifically a <a
+href="glossary.html#middle">man-in-the-middle</a> attack. Losing these
+secrets to an attacker may not be quite as disastrous as losing the actual
+keys, but it is <em>still a serious security breach</em>. These secrets
+should be guarded as carefully as keys.</p>
+
+<h3><a name="notyet">Methods not yet implemented</a></h3>
+
+<h4><a name="noauth">Unauthenticated key exchange</a></h4>
+
+<p>It would be possible to exchange keys without authenticating the players.
+This would support <a href="glossary.html#carpediem">opportunistic
+encryption</a> -- allowing any two systems to encrypt their communications
+without requiring a shared PKI or a previously negotiated secret -- and would
+be secure against <a href="glossary.html#passive">passive attacks</a>. It
+would, however, be highly vulnerable to active <a
+href="glossary.html#middle">man-in-the-middle</a> attacks. RFC 2408 therefore
+specifies that all <a href="glossary.html#ISAKMP">ISAKMP</a> key management
+interactions <em>must</em> be authenticated.</p>
+
+<p>There is room for debate here. Should we provide immediate security
+against <a href="glossary.html#passive">passive attacks</a> and encourage
+widespread use of encryption, at the expense of risking the more difficult <a
+href="glossary.html#active">active attacks</a>? Or should we wait until we
+can implement a solution that can both be widespread and offer security
+against active attacks?</p>
+
+<p>So far, we have chosen the second course, complying with the RFCs and
+waiting for secure DNS (see <a href="glossary.html#DNS">below</a>) so that we
+can do <a href="glossary.html#carpediem">opportunistic encryption</a>
+right.</p>
+
+<h4><a name="DNS">Key exchange using DNS</a></h4>
+
+<p>The IPsec RFCs allow key exchange based on authentication services
+provided by <a href="glossary.html#SDNS">Secure DNS</a>. Once Secure DNS
+service becomes widely available, we expect to make this the <em>primary key
+management method for Linux FreeS/WAN</em>. It is the best way we know of to
+support <a href="glossary.html#carpediem">opportunistic encryption</a>,
+allowing two systems without a common PKI or previous negotiation to secure
+their communication.</p>
+
+<p>We currently have code to acquire RSA keys from DNS but do not yet have
+code to validate Secure DNS signatures.</p>
+
+<h4><a name="PKI">Key exchange using a PKI</a></h4>
+
+<p>The IPsec RFCs allow key exchange based on authentication services
+provided by a <a href="glossary.html#PKI">PKI</a> or Public Key
+Infrastructure. With many vendors selling such products and many large
+organisations building these infrastructures, this will clearly be an
+important application of IPsec and one Linux FreeS/WAN will eventually
+support.</p>
+
+<p>On the other hand, this is not as high a priority for Linux FreeS/WAN as
+solutions based on <a href="glossary.html#SDNS">secure DNS</a>. We do not
+expect any PKI to become as universal as DNS.</p>
+
+<p>Some <a href="web.html#patch">patches</a> to handle authentication with
+X.509 certificates, which most PKIs use, are available.</p>
+
+<h4><a name="photuris">Photuris</a></h4>
+
+<p><a href="glossary.html#photuris">Photuris</a> is another key management
+protocol, an alternative to IKE and ISAKMP, described in RFCs 2522 and 2523
+which are labelled "experimental". Adding Photuris support to Linux FreeS/WAN
+might be a good project for a volunteer. The likely starting point would be
+the OpenBSD photurisd code.</p>
+
+<h4><a name="skip">SKIP</a></h4>
+
+<p><a href="glossary.html#SKIP">SKIP</a> is yet another key management
+protocol, developed by Sun. At one point it was fairly widely used, but it
+now seems moribund, displaced by IKE. Sun now (as of Solaris 8.0) ship an
+IPsec implementation using IKE. We have no plans to implement SKIP. If a user
+were to implement it, we would almost certainly not want to add the code to
+our distribution.</p>
+</body>
+</html>
diff --git a/doc/src/kernel.html b/doc/src/kernel.html
new file mode 100644
index 000000000..a4beab417
--- /dev/null
+++ b/doc/src/kernel.html
@@ -0,0 +1,392 @@
+<html>
+<head>
+<title>Kernel configuration for FreeS/WAN</title>
+<meta name="keywords" content="Linux, IPsec, VPN, security, FreeSWAN, kernel">
+
+<!--
+
+Written by Sandy Harris for the Linux FreeS/WAN project
+Freely distributable under the GNU General Public License
+
+More information at www.freeswan.org
+Feedback to users@lists.freeswan.org
+
+CVS information:
+RCS ID: $Id: kernel.html,v 1.1 2004/03/15 20:35:24 as Exp $
+Last changed: $Date: 2004/03/15 20:35:24 $
+Revision number: $Revision: 1.1 $
+
+CVS revision numbers do not correspond to FreeS/WAN release numbers.
+-->
+</head>
+
+<body>
+
+<h1><a name="kernelconfig">Kernel configuration for FreeS/WAN</a></h1>
+
+<p>
+This section lists many of the options available when configuring a Linux
+ kernel, and explains how they should be set on a FreeS/WAN IPsec
+ gateway.</p>
+
+ <h2><a name="notall">Not everyone needs to worry about kernel configuration</a></h2>
+
+ <p>Note that in many cases you do not need to mess with these.</p>
+
+<p>
+You may have a Linux distribution which comes with FreeS/WAN installed
+(see this <a href="intro.html#products">list</a>).
+ In that case, you need not do a FreeS/WAN installation or a kernel
+ configuration. Of course, you might still want to configure and rebuild your
+ kernel to improve performance or security. This can be done with standard
+ tools described in the <a href="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">Kernel HowTo</a>.</p>
+
+ <p>If you need to install FreeS/WAN, then you do need to configure a kernel.
+ However, you may choose to do that using the simplest procedure:</p>
+ <ul>
+ <li>Configure, build and test a kernel for your system before adding FreeS/WAN. See the <a
+ href="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">Kernel HowTo</a> for details. <strong>This step cannot be
+ skipped</strong>. FreeS/WAN needs the results of your configuration.</li>
+ <li>Then use FreeS/WAN's <var>make oldgo</var> command. This sets
+ everything FreeS/WAN needs and retains your values everywhere else.</li>
+ </ul>
+
+<p>
+This document is for those who choose to configure their FreeS/WAN kernel
+themselves.</p>
+
+<h2><a name="assume">Assumptions and notation</a></h2>
+
+<p>
+Help text for most kernel options is included with the kernel files, and
+is accessible from within the configuration utilities. We assume
+you will refer to that, and to the <a href="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">Kernel HowTo</a>, as
+necessary. This document covers only the FreeS/WAN-specific aspects of the
+problem.</p>
+
+<p>
+To avoid duplication, this document section does not cover settings for
+the additional IPsec-related kernel options which become available after you
+have patched your kernel with FreeS/WAN patches. There is help text for
+those available from within the configuration utility.</p>
+
+ <p>
+We assume a common configuration in which the FreeS/WAN IPsec gateway is
+also doing ipchains(8) firewalling for a local network, and possibly
+masquerading as well.</p>
+
+<p>
+Some suggestions below are labelled as appropriate for "a true paranoid".
+By this we mean they may cause inconvenience and it is not entirely clear
+ they are necessary, but they appear to be the safest choice. Not using them
+ might entail some risk. Of course one suggested mantra for security
+ administrators is: "I know I'm paranoid. I wonder if I'm paranoid
+ enough."</p>
+
+ <h3><a name="labels">Labels used</a></h3>
+
+<p>
+Six labels are used to indicate how options should be set. We mark the
+labels with [square brackets]. For two of these labels, you have no
+choice:</p>
+ <dl>
+ <dt>[required]</dt>
+ <dd>essential for FreeS/WAN operation.</dd>
+ <dt>[incompatible]</dt>
+ <dd>incompatible with FreeS/WAN.</dd>
+ </dl>
+
+ <p>those must be set correctly or FreeS/WAN will not work</p>
+
+ <p>FreeS/WAN should work with any settings of the others, though of course
+ not all combinations have been tested. We do label these in various ways,
+ but <em>these labels are only suggestions</em>.</p>
+ <dl>
+ <dt>[recommended]</dt>
+ <dd>useful on most FreeS/WAN gateways</dd>
+ <dt>[disable]</dt>
+ <dd>an unwelcome complication on a FreeS/WAN gateway.</dd>
+ <dt>[optional]</dt>
+ <dd>Your choice. We outline issues you might consider.</dd>
+ <dt>[anything]</dt>
+ <dd>This option has no direct effect on FreeS/WAN and related tools, so
+ you should be able to set it as you please.</dd>
+ </dl>
+
+<p>
+Of course complexity is an enemy in any effort to build secure systems.
+<strong>For maximum security, any feature that can reasonably be turned off
+should be</strong>. "If in doubt, leave it out."</p>
+
+ <h2><a name="kernelopt">Kernel options for FreeS/WAN</a></h2>
+
+<p>
+Indentation is based on the nesting shown by 'make menuconfig' with a
+2.2.16 kernel for the i386 architecture.</p>
+<dl>
+ <dt><a name="maturity">Code maturity and level options</a></dt>
+ <dd>
+ <dl>
+ <dt><a name="devel">Prompt for development ...
+ code/drivers</a></dt>
+ <dd>[optional] If this is <var>no</var>, experimental drivers are
+ not shown in later menus.
+ <p>For most FreeS/WAN work, <var>no</var> is the preferred
+ setting. Using new or untested components is too risky for a
+ security gateway.</p>
+ <p>However, for some hardware (such as the author's network
+ cards) the only drivers available are marked
+ <var>new/experimental</var>. In such cases, you must enable this
+ option or your cards will not appear under &quot;network device
+ support&quot;. A true paranoid would leave this option off and
+ replace the cards.</p>
+ </dd>
+ <dt>Processor type and features</dt>
+ <dd>[anything]</dd>
+ <dt>Loadable module support</dt>
+ <dd>
+ <dl>
+ <dt>Enable loadable module support</dt>
+ <dd>[optional] A true paranoid would disable this. An attacker who
+ has root access to your machine can fairly easily install a
+ bogus module that does awful things, provided modules are
+ enabled. A common tool for attackers is a &quot;rootkit&quot;, a set
+ of tools the attacker uses once he or she has become root on your system.
+ The kit introduces assorted additional compromises so that the attacker
+ will continue to &quot;own&quot; your system despite most things you might
+ do to recovery the situation. For Linux, there is a tool called
+ <a href="http://www.sans.org/newlook/resources/IDFAQ/knark.htm">knark</a>
+ which is basically a rootkit packaged as a kernel module.
+ <p>With modules disabled, an attacker cannot install a bogus module.
+ The only way
+ he can achieve the same effects is to install a new kernel and
+ reboot. This is considerably more likely to be noticed.
+ <p>Many FreeS/WAN gateways run with modules enabled. This
+ simplifies some administrative tasks and some ipchains features
+ are available only as modules. Once an enemy has root on your
+ machine your security is nil, so arguably defenses which come
+ into play only in that situation are pointless.</p>
+ <p>
+
+ </dd>
+ <dt>Set version information ....</dt>
+ <dd>[optional] This provides a check to prevent loading modules
+ compiled for a different kernel.</dd>
+ <dt>Kernel module loader</dt>
+ <dd>[disable] It gives little benefit on a typical FreeS/WAN gate
+ and entails some risk.</dd>
+ </dl>
+ </dd>
+ <dt>General setup</dt>
+ <dd>We list here only the options that matter for FreeS/WAN.
+ <dl>
+ <dt>Networking support</dt>
+ <dd>[required]</dd>
+ <dt>Sysctl interface</dt>
+ <dd>[optional] If this option is turned on and the
+ <var>/proc</var> filesystem installed, then you can control
+ various system behaviours by writing to files under
+ <var>/proc/sys</var>. For example:
+ <pre> echo 1 &gt; /proc/sys/net/ipv4/ipforward</pre>
+ turns IP forwarding on.
+ <p>Disabling this option breaks many firewall scripts. A true
+ paranoid would disable it anyway since it might conceivably be
+ of use to an attacker.</p>
+ </dd>
+ </dl>
+ </dd>
+ <dt>Plug and Play support</dt>
+ <dd>[anything]</dd>
+ <dt>Block devices</dt>
+ <dd>[anything]</dd>
+ <dt>Networking options</dt>
+ <dd>
+ <dl>
+ <dt>Packet socket</dt>
+ <dd>[optional] This kernel feature supports tools such as
+ tcpdump(8) which communicate directly with network hardware,
+ bypassing kernel protocols. This is very much a two-edged sword:
+ <ul>
+ <li>such tools can be very useful to the firewall admin,
+ especially during initial testing</li>
+ <li>should an evildoer breach your firewall, such tools could
+ give him or her a great deal of information about the rest
+ of your network</li>
+ </ul>
+ We recommend disabling this option on production gateways.</dd>
+ <dt><a name="netlink">Kernel/User netlink socket</a></dt>
+ <dd>[optional] Required if you want to use <a href="#adv">advanced
+ router</a> features.</dd>
+ <dt>Routing messages</dt>
+ <dd>[optional]</dd>
+ <dt>Netlink device emulation</dt>
+ <dd>[optional]</dd>
+ <dt>Network firewalls</dt>
+ <dd>[recommended] You need this if the IPsec gateway also
+ functions as a firewall.
+ <p>Even if the IPsec gateway is not your primary firewall, we
+ suggest setting this so that you can protect the gateway with at
+ least basic local packet filters.</p>
+ </dd>
+ <dt>Socket filtering</dt>
+ <dd>[disable] This enables an older filtering interface. We suggest
+ using ipchains(8) instead. To do that, set the &quot;Network
+ firewalls&quot; option just above, and not this one.</dd>
+ <dt>Unix domain sockets</dt>
+ <dd>[required] These sockets are used for communication between the
+ <a href="manpage.d/ipsec.8.html">ipsec(8)</a>
+ commands and the <a href="manpage.d/ipsec_pluto.8.html">ipsec_pluto(8)</a>
+ daemon.</dd>
+ <dt>TCP/IP networking</dt>
+ <dd>[required]
+ <dl>
+ <dt>IP: multicasting</dt>
+ <dd>[anything]</dd>
+ <dt><a name="adv">IP: advanced router</a></dt>
+ <dd>[optional] This gives you policy routing, which some
+ people have used to good advantage in their scripts for
+ FreeS/WAN gateway management. It is not used in our
+ distributed scripts, so not required unless you want it
+ for custom scripts. It requires the <a
+ href="#netlink">netlink</a> interface between kernel code
+ and the iproute2(8) command.</dd>
+ <dt>IP: kernel level autoconfiguration</dt>
+ <dd>[disable] It gives little benefit on a typical FreeS/WAN
+ gate and entails some risk.</dd>
+ <dt>IP: firewall packet netlink device</dt>
+ <dd>[disable]</dd>
+ <dt>IP: transparent proxy support</dt>
+ <dd>[optional] This is required in some firewall configurations,
+ but should be disabled unless you have a definite need for it.
+ </dd>
+ <dt>IP: masquerading</dt>
+ <dd>[optional] Required if you want to use
+ <a href="glossary.html#non-routable">non-routable</a> private
+ IP addresses for your local network.</dd>
+ <dt>IP: Optimize as router not host</dt>
+ <dd>[recommended]</dd>
+ <dt>IP: tunneling</dt>
+ <dd>[required]</dd>
+ <dt>IP: GRE tunnels over IP</dt>
+ <dd>[anything]</dd>
+ <dt>IP: aliasing support</dt>
+ <dd>[anything]</dd>
+ <dt>IP: ARP daemon support (EXPERIMENTAL)</dt>
+ <dd>Not required on most systems, but might prove useful on
+ heavily-loaded gateways.</dd>
+ <dt>IP: TCP syncookie support</dt>
+ <dd>[recommended] It provides a defense against a <a
+ href="glossary.html#DOS">denial of
+ service attack</a> which uses bogus TCP connection
+ requests to waste resources on the victim machine.</dd>
+ <dt>IP: Reverse ARP</dt>
+ <dd></dd>
+ <dt>IP: large window support</dt>
+ <dd>[recommended] unless you have less than 16 meg RAM</dd>
+ </dl>
+ </dd>
+ <dt>IPv6</dt>
+ <dd>[optional] FreeS/WAN does not currently support IPv6, though work on
+ integrating FreeS/WAN with the Linux IPv6 stack has begun.
+ <a href="compat.html#ipv6">Details</a>.
+ <p>
+ It should be possible to use IPv4 FreeS/WAN on a machine which also
+ does IPv6. This combination is not yet well tested. We would be quite
+ interested in hearing results from anyone expermenting with it, via the
+ <a href="mail.html">mailing list</a>.
+ <p>
+ We do not recommend using IPv6 on production FreeS/WAN gateways until
+ more testing has been done.
+ </dd>
+ <dt>Novell IPX</dt>
+ <dd>[disable]</dd>
+ <dt>Appletalk</dt>
+ <dd>[disable] Quite a few Linux installations use IP but also have
+ some other protocol, such as Appletalk or IPX, for communication
+ with local desktop machines. In theory it should be possible to
+ configure IPsec for the IP side of things without interfering
+ with the second protocol.
+ <p>We do not recommend this. Keep the software on your gateway
+ as simple as possible. If you need a Linux-based Appletalk or
+ IPX server, use a separate machine.</p>
+ </dd>
+ </dl>
+ </dd>
+ <dt>Telephony support</dt>
+ <dd>[anything]</dd>
+ <dt>SCSI support</dt>
+ <dd>[anything]</dd>
+ <dt>I2O device support</dt>
+ <dd>[anything]</dd>
+ <dt>Network device support</dt>
+ <dd>[anything] should work, but there are some points to note.
+ <p>The development team test almost entirely on 10 or 100 megabit
+ Ethernet and modems. In principle, any device that can do IP should be
+ just fine for IPsec, but in the real world any device that has not
+ been well-tested is somewhat risky. By all means try it, but don't bet
+ your project on it until you have solid test results.</p>
+ <p>If you disabled experimental drivers in the <a
+ href="#maturity">Code maturity</a> section above, then those drivers
+ will not be shown here. Check that option before going off to hunt for
+ missing drivers.</p>
+ <p>If you want Linux to automatically find more than one ethernet
+ interface at boot time, you need to:</p>
+ <ul>
+ <li>compile the appropriate driver(s) into your kernel. Modules will
+ not work for this</li>
+ <li>add a line such as
+<pre>
+ append="ether=0,0,eth0 ether=0,0,eth1"
+</pre>
+ to your /etc/lilo.conf file. In some cases you may need to specify
+ parameters such as IRQ or base address. The example uses &quot;0,0&quot;
+ for these, which tells the system to search. If the search does not
+ succeed on your hardware, then you should retry with explicit parameters.
+ See the lilo.conf(5) man page for details.</li>
+ <li>run lilo(8)</li>
+ </ul>
+ Having Linux find the cards this way is not necessary, but is usually more
+ convenient than loading modules in your boot scripts.</dd>
+ <dt>Amateur radio support</dt>
+ <dd>[anything]</dd>
+ <dt>IrDA (infrared) support</dt>
+ <dd>[anything]</dd>
+ <dt>ISDN subsystem</dt>
+ <dd>[anything]</dd>
+ <dt>Old CDROM drivers</dt>
+ <dd>[anything]</dd>
+ <dt>Character devices</dt>
+ <dd>The only required character device is:
+ <dl>
+ <dt>random(4)</dt>
+ <dd>[required] This is a source of <a href="glossary.html#random">random</a>
+ numbers which are required for many cryptographic protocols,
+ including several used in IPsec.
+ <p>If you are comfortable with C source code, it is likely a
+ good idea to go in and adjust the <var>#define</var> lines in
+ <var>/usr/src/linux/drivers/char/random.c</var> to ensure that
+ all sources of randomness are enabled. Relying solely on
+ keyboard and mouse randomness is dubious procedure for a gateway
+ machine. You could also increase the randomness pool size from
+ the default 512 bytes (128 32-bit words).</p>
+ </dd>
+ </dl>
+ <dt>Filesystems</dt>
+ <dd>[anything] should work, but we suggest limiting a gateway
+ machine to the standard Linux ext2 filesystem in most
+ cases.</dd>
+ <dt>Network filesystems</dt>
+ <dd>[disable] These systems are an unnecessary risk on an IPsec
+ gateway.</dd>
+ <dt>Console drivers</dt>
+ <dd>[anything]</dd>
+ <dt>Sound</dt>
+ <dd>[anything] should work, but we suggest enabling sound only if
+ you plan to use audible alarms for firewall problems.</dd>
+ <dt>Kernel hacking</dt>
+ <dd>[disable] This might be enabled on test machines, but should
+ not be on production gateways.</dd>
+ </dl>
+ </dl>
+</body>
+</html>
diff --git a/doc/src/mail.html b/doc/src/mail.html
new file mode 100644
index 000000000..e26f025a0
--- /dev/null
+++ b/doc/src/mail.html
@@ -0,0 +1,250 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN mailing lists</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, mailing, list">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: mail.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="lists">Mailing lists and newsgroups</a></h1>
+
+<h2><a name="list.fs">Mailing lists about FreeS/WAN</a></h2>
+
+<h3><a name="projlist">The project mailing lists</a></h3>
+
+<p>The Linux FreeS/WAN project has several email lists for user support, bug
+reports and software development discussions.</p>
+
+<p>We had a single list on clinet.fi for several years (Thanks, folks!), then
+one list on freeswan.org, but now we've split into several lists:</p>
+<dl>
+ <dt><a
+ href="mailto:users-request@lists.freeswan.org?body=subscribe">users</a></dt>
+ <dd><ul>
+ <li>The general list for discussing use of the software</li>
+ <li>The place for seeking <strong>help with problems</strong> (but
+ please check the <a href="faq.html">FAQ</a> first).</li>
+ <li>Anyone can post.</li>
+ </ul>
+ </dd>
+ <dt><a
+ href="mailto:bugs-request@lists.freeswan.org?body=subscribe">bugs</a></dt>
+ <dd><ul>
+ <li>For <strong>bug reports</strong>.</li>
+ <li>If you are not certain what is going on -- could be a bug, a
+ configuration error, a network problem, ... -- please post to the
+ users list instead.</li>
+ <li>Anyone can post.</li>
+ </ul>
+ </dd>
+ <dt><a
+ href="mailto:design-request@lists.freeswan.org?body=subscribe">design</a></dt>
+ <dd><ul>
+ <li><strong>Design discussions</strong>, for people working on
+ FreeS/WAN development or others with an interest in design and
+ security issues.</li>
+ <li>It would be a good idea to read the existing design papers (see
+ this <a href="intro.html#applied">list</a>) before posting.</li>
+ <li>Anyone can post.</li>
+ </ul>
+ </dd>
+ <dt><a
+ href="mailto:announce-request@lists.freeswan.org?body=subscribe">announce</a></dt>
+ <dd><ul>
+ <li>A <strong>low-traffic</strong> list.</li>
+ <li><strong>Announcements</strong> about FreeS/WAN and related
+ software.</li>
+ <li>All posts here are also sent to the users list. You need not
+ subscribe to both.</li>
+ <li>Only the FreeS/WAN team can post.</li>
+ <li>If you have something you feel should go on this list, send it to
+ <var>announce-admin@lists.freeswan.org</var>. Unless it is obvious,
+ please include a short note explaining why we should post it.</li>
+ </ul>
+ </dd>
+ <dt><a
+ href="mailto:briefs-request@lists.freeswan.org?body=subscribe">briefs</a></dt>
+ <dd><ul>
+ <li>A <strong>low-traffic</strong> list.</li>
+ <li><strong>Weekly summaries</strong> of activity on the users
+ list.</li>
+ <li>All posts here are also sent to the users list. You need not
+ subscribe to both.</li>
+ <li>Only the FreeS/WAN team can post.</li>
+ </ul>
+ </dd>
+</dl>
+
+<p>To subscribe to any of these, you can:</p>
+<ul>
+ <li>just follow the links above</li>
+ <li>use our <a href="http://www.freeswan.org/mail.html">web
+ interface</a></li>
+ <li>send mail to <var>listname</var>-request@lists.freeswan.org with a
+ one-line message body "subscribe"</li>
+</ul>
+
+<p>Archives of these lists are available via the <a
+href="http://www.freeswan.org/mail.html">web interface</a>.</p>
+
+<h4><a name="which.list">Which list should I use?</a></h4>
+
+<p>For most questions, please check the <a href="faq.html">FAQ</a> first, and
+if that does not have an answer, ask on the users list. "My configuration
+doesn't work." does not belong on the bugs list, and "Can FreeS/WAN do
+such-and-such" or "How do I configure it to..." do not belong in design
+discussions.</p>
+
+<p>Cross-posting the same message to two or more of these lists is
+discouraged. Quite a few people read more than one list and getting multiple
+copies is annoying.</p>
+
+<h4><a name="policy.list">List policies</a></h4>
+
+<p><strong>US citizens or residents are asked not to post code to the lists,
+not even one-line bug fixes</strong>. The project cannot accept code which
+might entangle it in US <a href="politics.html#exlaw">export
+restrictions</a>.</p>
+
+<p>Non-subscribers can post to some of these lists. This is necessary;
+someone working on a gateway install who encounters a problem may not have
+access to a subscribed account.</p>
+
+<p>Some spam turns up on these lists from time to time. For discussion of why
+we do not attempt to filter it, see the <a href="faq.html#spam">FAQ</a>.
+Please do not clutter the lists with complaints about this.</p>
+
+<h3><a name="archive">Archives of the lists</a></h3>
+
+<p>Searchable archives of the old single list have existed for some time. At
+time of writing, it is not yet clear how they will change for the new
+multi-list structure.</p>
+<ul>
+ <li><a href="http://www.sandelman.ottawa.on.ca/linux-ipsec">Canada</a></li>
+ <li><a href="http://www.nexial.com">Holland</a></li>
+</ul>
+
+<p>Note that these use different search engines. Try both.</p>
+
+<p>Archives of the new lists are available via the <a
+href="http://www.freeswan.org/mail.html">web interface</a>.</p>
+
+<h2><a name="indexes">Indexes of mailing lists</a></h2>
+
+<p><a href="http://paml.net/">PAML</a> is the standard reference for
+<strong>P</strong>ublicly <strong>A</strong>ccessible
+<strong>M</strong>ailing <strong>L</strong>ists. When we last checked, it had
+over 7500 lists on an amazing variety of topics. It also has FAQ information
+and a search engine.</p>
+
+<p>There is an index of <a
+href="http://oslab.snu.ac.kr/~djshin/linux/mail-list/index.shtml">Linux
+mailing lists</a> available.</p>
+
+<p>A list of <a
+href="http://xforce.iss.net/maillists/otherlists.php">computer security
+mailing lists</a>, with descriptions.</p>
+
+<h2><a name="otherlists">Lists for related software and topics</a></h2>
+
+<p>Most links in this section point to subscription addresses for the various
+lists. Send the one-line message "subscribe <var>list_name</var>" to
+subscribe to any of them.</p>
+
+<h3>Products that include FreeS/WAN</h3>
+
+<p>Our introduction document gives a <a href="intro.html#products">list of
+products that include FreeS/WAN</a>. If you have, or are considering, one of
+those, check the supplier's web site for information on mailing lists for
+their users.</p>
+
+<h3><a name="linux.lists">Linux mailing lists</a></h3>
+<ul>
+ <li><a
+ href="mailto:majordomo@vger.kernel.org">linux-admin@vger.kernel.org</a>,
+ for Linux system administrators</li>
+ <li><a
+ href="mailto:netfilter-request@lists.samba.org">netfilter@lists.samba.org</a>,
+ about Netfilter, which replaces IPchains in kernels 2.3.15 and later</li>
+ <li><a
+ href="mailto:security-audit-request@ferret.lmh.ox.ac.uk">security-audit@ferret.lmh.ox.ac.uk</a>,
+ for people working on security audits of various Linux programs</li>
+ <li><a
+ href="mailto:securedistros-request@humbolt.geo.uu.nl">securedistros@humbolt.geo.uu.nl</a>,
+ for discussion of issues common to all the half dozen projects working on
+ secure Linux distributions.</li>
+</ul>
+
+<p>Each of the scure distribution projects also has its own web site and
+mailing list. Some of the sites are:</p>
+<ul>
+ <li><a href="http://bastille-linux.org/">Bastille Linux</a> scripts to
+ harden Redhat, e.g. by changing permissions and modifying inialisation
+ scripts</li>
+ <li><a href="http://immunix.org/">Immunix</a> take a different approach,
+ using a modified compiler to build kernel and utilities with better
+ resistance to various types of overflow and exploit</li>
+ <li>the <a href="glossary.html#NSA">NSA</a> have contractors working on a
+ <a href="glossary.html#SElinux">Security Enhanced Linux</a>, primarily
+ adding stronger access control mechanisms. You can download the current
+ version (which interestingly is under GPL and not export resrtricted) or
+ subscribe to the mailing list from the <a
+ href="http://www.nsa.gov/selinux">project web page</a>.</li>
+</ul>
+
+<h3><a name="ietf">Lists for IETF working groups</a></h3>
+
+<p>Each <a href="glossary.html#IETF">IETF</a> working group has an associated
+mailing list where much of the work takes place.</p>
+<ul>
+ <li><a
+ href="mailto:majordomo@lists.tislabs.com">ipsec@lists.tislabs.com</a>,
+ the IPsec <a
+ href="http://www.ietf.org/html.charters/ipsec-charter.html">working
+ group</a>. This is where the protocols are discussed, new drafts
+ announced, and so on. By now, the IPsec working group is winding down
+ since the work is essentially complete. A <a
+ href="http://www.sandelman.ottawa.on.ca/ipsec/">list archive</a> is
+ available.</li>
+ <li><a href="mailto:ipsec-policy-request@vpnc.org">IPsec policy</a> list,
+ and its <a href="http://www.vpnc.org/ipsec-policy/">archive</a></li>
+ <li><a href="mailto:ietf-ipsra-request@vpnc.org">IP secure remote
+ access</a> list, and its <a
+ href="http://www.vpnc.org/ietf-ipsra/mail-archive/">archive</a></li>
+</ul>
+
+<h3><a name="other">Other mailing lists</a></h3>
+<ul>
+ <li><a
+ href="mailto:ipc-announce-request@privacy.org">ipc-announce@privacy.org</a>
+ a low-traffic list with announcements of developments in privacy,
+ encryption and online civil rights</li>
+ <li>a VPN mailing list's <a
+ href="http://kubarb.phsx.ukans.edu/~tbird/vpn.html">home page</a></li>
+</ul>
+
+<h2><a name="newsgroups">Usenet newsgroups</a></h2>
+<ul>
+ <li>sci.crypt</li>
+ <li>sci.crypt.research</li>
+ <li>comp.dcom.vpn</li>
+ <li>talk.politics.crypto</li>
+</ul>
+</body>
+</html>
diff --git a/doc/src/makecheck.html b/doc/src/makecheck.html
new file mode 100644
index 000000000..7fa3a3bcb
--- /dev/null
+++ b/doc/src/makecheck.html
@@ -0,0 +1,684 @@
+<html>
+<head>
+<title>FreeS/WAN "make check" guide</title>
+<!-- Changed by: Michael Richardson, 02-Apr-2003 -->
+<meta name="keywords" content="Linux, IPsec, VPN, security, FreeSWAN, testing, User-Mode-Linux, UML">
+
+<!--
+
+Written by Michael Richardson for the Linux FreeS/WAN project
+Freely distributable under the GNU General Public License
+
+More information at www.freeswan.org
+Feedback to users@lists.freeswan.org
+
+$Id: makecheck.html,v 1.1 2004/03/15 20:35:24 as Exp $
+
+$Log: makecheck.html,v $
+Revision 1.1 2004/03/15 20:35:24 as
+added files from freeswan-2.04-x509-1.5.3
+
+Revision 1.25 2003/04/02 20:28:33 mcr
+ document for NETJIGVERBOSE environment variable.
+
+Revision 1.24 2003/04/02 02:17:52 mcr
+ added documentation on "PACKETRATE"
+
+Revision 1.23 2003/02/27 09:28:24 mcr
+ added documentation for *_RUN2_SCRIPT.
+
+Revision 1.22 2003/02/20 20:00:44 mcr
+ added documentation for ${host}HOST.
+
+Revision 1.21 2003/02/20 19:56:11 mcr
+ documented new umlXhost test case.
+
+Revision 1.20 2002/12/06 02:11:42 mcr
+ added new test type, module_compile.
+
+Revision 1.19 2002/12/04 03:47:06 mcr
+ added documentation of various *TESTDEBUG options in
+ the testing environment.
+
+Revision 1.18 2002/10/31 19:01:31 mcr
+ documentation for RUN_*_SCRIPT.
+
+Revision 1.17 2002/09/11 19:43:36 mcr
+ added documentation on format of TESTLIST.
+
+Revision 1.16 2002/09/11 19:26:48 mcr
+ renamed umlpluto -> umlplutotest.
+
+Revision 1.15 2002/07/29 22:27:12 mcr
+ added kernel_patch_test test type.
+
+Revision 1.14 2002/06/19 18:24:44 mcr
+ renamed SCRIPT to INIT_SCRIPT.
+
+Revision 1.13 2002/06/19 10:06:07 mcr
+ added nightly.html to the documentation tree.
+
+Revision 1.12 2002/06/19 09:19:26 mcr
+ wrote documentation for umlpluto parts of makecheck,
+ and adjusted scripts for consistency.
+
+Revision 1.11 2002/06/19 07:26:31 mcr
+ added FINAL_SCRIPT to be run after sending packets through.
+ renamed "SCRIPT" to "INIT_SCRIPT" (left compat variable)
+
+Revision 1.10 2002/06/17 05:40:57 mcr
+ Added test cases for the "make rpm" machinery.
+
+Revision 1.9 2002/06/08 17:12:49 mcr
+ added new libtest test type for use in testing libfreeswan
+
+Revision 1.8 2002/05/27 00:19:38 mcr
+ removed reference to single_netjig.png because mkhtml does not
+ grok it.
+
+Revision 1.7 2002/05/07 01:31:52 mcr
+ documented the new "mkinsttest" target type.
+
+Revision 1.6 2002/05/05 23:10:50 mcr
+ added documentation of $TEST_TYPE variable.
+
+Revision 1.5 2002/04/19 22:48:41 mcr
+ added documentation on NETJIGDEBUG and CONSOLEDIFFDEBUG.
+
+Revision 1.4 2002/04/01 23:59:46 mcr
+ added documentation on REF_{PUB,PRIV}_FILTER.
+
+Revision 1.3 2002/04/01 23:38:46 mcr
+ redo of updates to makecheck
+
+Revision 1.2 2002/03/12 21:12:07 mcr
+ initial stab at documentation on klips testing infrastructure.
+
+
+-->
+</head>
+
+<body>
+
+<h1><a name="makecheck">How to configure to use "make check"</a></h1>
+
+<H2>What is "make check"</H2>
+<p>
+"make check" is a target in the top level makefile. It takes care of
+running a number of unit and system tests to confirm that FreeSWAN has
+been compiled correctly, and that no new bugs have been introduced.
+</p>
+<p>
+As FreeSWAN contains both kernel and userspace components, doing testing
+of FreeSWAN requires that the kernel be simulated. This is typically difficult
+to do as a kernel requires that it be run on bare hardware. A technology
+has emerged that makes this simpler. This is
+<A HREF="http://user-mode-linux.sourceforge.net">User Mode Linux</A>.
+</p>
+
+<p>
+User-Mode Linux is a way to build a Linux kernel such that it can run as a process
+under another Linux (or in the future other) kernel. Presently, this can only be
+done for 2.4 guest kernels. The host kernel can be 2.2 or 2.4.
+</p>
+
+<p>
+"make check" expects to be able to build User-Mode Linux kernels with FreeSWAN included.
+To do this it needs to have some files downloaded and extracted prior
+to running "make check". This is described in the
+<A HREF="umltesting.html">UML testing</A> document.
+</p>
+
+<p>
+After having run the example in the UML testing document and
+successfully brought up the four machine combination, you are ready to
+use "make check"
+</p>
+
+<h2>Running "make check"</h2>
+<p>
+"make check" works by walking the FreeSWAN source tree invoking the
+"check" target at each node. At present there are tests defined only
+for the <CODE>klips</CODE> directory. These tests will use the UML
+infrastructure to test out pieces of the <CODE>klips</CODE> code.
+</p>
+<p>
+The results of the tests can be recorded. If the environment variable
+<CODE>$REGRESSRESULTS</CODE> is non-null, then the results of each
+test will be recorded. This can be used as part of a nightly
+regression testing system, see
+<A HREF="nightly.html">Nightly testing</A> for more details.
+</p>
+<p>
+"make check" otherwise prints a minimal amount of output for each
+test, and indicates pass/fail status of each test as they are run.
+Failed tests do not cause failure of the target in the form of exit
+codes.
+</p>
+
+<H1>How to write a "make check" test</H1>
+
+<h2>Structure of a test</h2>
+
+<p>
+Each test consists of a set of directories under <CODE>testing/</CODE>.
+There are directories for <CODE>klips</CODE>, <CODE>pluto</CODE>, <CODE>packaging</CODE>
+and <CODE>libraries</CODE>.
+Each directory has a list of tests to run is stored in a file called <CODE>TESTLIST</CODE> in that directory. e.g. <CODE>testing/klips/TESTLIST</CODE>.
+</P>
+
+<H2 NAME="TESTLIST">The TESTLIST</H2>
+<P>
+This isn't actually a shell script. It just looks like one. Some tools other than
+/bin/sh process it. Lines that start with # are comments. </P>
+
+<PRE>
+# test-kind directory-containing-test expectation [PR#]
+</PRE>
+
+<P>The first word provides the test type, detailed below. </P>
+<P> The second word is the name of the test to run. This the directory
+in which the test case is to be found..</P>
+<P>The third word may be one of:
+<DL>
+<DT> blank/good</DT>
+<DD>the test is believed to function, report failure</DD>
+<DT> bad</DT>
+<DD> the test is known to fail, report unexpected success</DD>
+<DT> suspended</DT>
+<DD> the test should not be run</DD>
+</DL>
+
+<P>
+The fourth word may be a number, which is a PR# if the test is
+failing.
+</P>
+
+<H2>Test kinds</H2>
+The test types are:
+
+<DL>
+<DT>skiptest</DT>
+<DD>means run no test.</DD>
+<DT>ctltest</DT>
+<DD>means run a single system without input/output.</DD>
+<DT>klipstest</DT>
+<DD>means run a single system with input/output networks</DD>
+<DT><A HREF="#umlplutotest">umlplutotest</A></DT>
+<DD>means run a pair of systems</DD>
+<DT><A HREF="#umlXhost">umlXhost</A></DT>
+<DD>run an arbitrary number of systems</DT>
+<DT>suntest (TBD)</DT>
+<DD>means run a quad of east/west/sunrise/sunset</DD>
+<DT>roadtest (TBD)</DT>
+<DD>means run a trio of east-sunrise + warrior</DD>
+<DT>extrudedtest (TBD)</DT>
+<DD>means run a quad of east-sunrise + warriorsouth + park</DD>
+<DT>mkinsttest</TD>
+<DD>a test of the "make install" machinery.</DD>
+<DT>kernel_test_patch</TD>
+<DD>a test of the "make kernelpatch" machinery.</DD>
+</DL>
+
+Tests marked (TBD) have yet to be fully defined.
+</p>
+
+<p>
+Each test directory has a file in it called <CODE>testparams.sh</CODE>.
+This file sets a number of environment variables to define the
+parameters of the test.
+</p>
+
+<H2>Common parameters</H2>
+<DL>
+<DT>TESTNAME</DT>
+<DD>the name of the test (repeated for checking purposes)</DD>
+
+<DT>TEST_TYPE</DT>
+<DD>the type of the test (repeat of type type above)</DD>
+
+<DT>TESTHOST</DT>
+<DD>the name of the UML machine to run for the test, typically "east"
+ or "west"</DD>
+
+<DT>TEST_PURPOSE</DT>
+<DD>The purpose of the test is one of:
+
+<DL>
+<DT>goal</DT>
+<DD>The goal purpose is where a test is defined for code that is not yet
+finished. The test indicates when the goals have in fact been reached.</DD>
+<DT>regress</DT>
+<DD>This is a test to determine that a previously existing bug has been repaired. This
+test will initially be created to reproduce the bug in isolation, and then the bug will
+be fixed.</DD>
+<DT>exploit</DT>
+<DD>This is a set of packets/programs that causes a vulnerability to be
+exposed. It is a specific variation of the regress option.</DD>
+</DL>
+</DD>
+
+<DT>TEST_GOAL_ITEM<DT>
+<DD>in the case of a goal test, this is a reference to the requirements document</DD>
+
+<DT>TEST_PROB_REPORT</DT>
+<DD>in the case of regression test, this the problem report number from GNATS</DD>
+
+<DT>TEST_EXPLOIT_URL</DT>
+<DD>in the case of an exploit, this is a URL referencing the paper explaining
+the origin of the test and the origin of exploit software</DD>
+
+<DT>REF_CONSOLE_OUTPUT</DT>
+<DD>a file in the test directory that contains the sanitized console
+ output against which to compare the output of the actual test.</DD>
+<DT>REF_CONSOLE_FIXUPS</DT>
+<DD>a list of scripts (found in <CODE>klips/test/fixups</CODE>) to
+ apply to sanitize the console output of the machine under test.
+ These are typically perl, awk or sed scripts that remove things in
+ the kernel output that change each time the test is run and/or
+ compiled.
+</DD>
+<DT>INIT_SCRIPT</DT>
+<DD><p>a file of commands that is fed into the virtual machine's console
+ in single user mode prior to starting the tests. This file will
+ usually set up any eroute's and SADB entries that are required for
+ the test. </p>
+<p>Lines beginning with # are skipped. Blank lines are
+ skipped. Otherwise, a shell prompted is waited for each time
+ (consisting of <CODE>\n#</CODE>) and then the command is sent.
+ Note that the prompt is waited for before the command and not after,
+ so completion of the last command in the script is not
+ required. This is often used to invoke a program to monitor the
+ system, e.g. <CODE>ipsec pf_key</CODE>.
+</P>
+<DT>RUN_SCRIPT</DT>
+<DD><P>a file of commands that is fed into the virtual machine's console
+ in single user mode, before the packets are sent. On single machine
+ tests, this script doesn't provide any more power than INIT_SCRIPT,
+ but is implemented for consistency's sake.</P>
+<DT>FINAL_SCRIPT</DT>
+<DD><p>a file of commands that is fed into the virtual machine's console
+ in single user mode after the final packet is sent. Similar to INIT_SCRIPT,
+ above. If not specified, then the single command "halt" is sent.
+ If specified, then the script should end with a halt command to
+ nicely shutdown the UML.
+</P>
+<DT>CONSOLEDIFFDEBUG</DT>
+<DD>If set to "true" then the series of console fixups (see REF_CONSOLE_FIXUPS) will be output after it is constructed. (It should be set to "false", or unset otherwise)</DD>
+<DT>NETJIGDEBUG</DT>
+<DD>If set to "true" then the series of console fixups (see REF_CONSOLE_FIXUPS) will be output after it is constructed. (It should be set to "false", or unset otherwise)</DD>
+<DT>NETJIGTESTDEBUG</DT>
+<DD> If set to "netjig", then the results of talking to the <CODE>uml_netjig</CODE>
+will be printed to stderr during the test. In addition, the jig will
+be invoked with --debug, which causes it to log its process ID, and
+wait 60 seconds before continuing. This can be used if you are trying
+to debug the <CODE>uml_netjig</CODE> program itself.</DT>
+<DT>HOSTTESTDEBUG</DT>
+<DD> If set to "hosttest", then the results of taling to the consoles of the UMLs will
+be printed to stderr during the test.</DT>
+<DT>NETJIGWAITUSER</DT>
+<DD> If set to "waituser", then the scripts will wait forever for user
+ input before they shut the tests down. Use this is if you are
+ debugging through the kernel.</DD>
+
+<DT>PACKETRATE</DT>
+<DD> A number, in miliseconds (default is 500ms) at which packets will
+ be replayed by the netjig.</DD>
+</DL>
+
+
+<H2>KLIPStest paramaters</H2>
+<P>
+The klipstest function starts a program
+(<CODE>testing/utils/uml_netjig/uml_netjig</CODE>) to
+setup a bunch of I/O sockets (that simulate network interfaces). It
+then exports the references to these sockets to the environment and
+invokes (using system()) a given script. It waits for the script to
+finish.
+</P>
+
+<!-- <IMG SRC="single_netjig.png" ALT="block diagram of uml_netjig"> -->
+
+<P>
+The script invoked (<CODE>testing/utils/host-test.tcl</CODE>) is a TCL
+<A HREF="http://expect.nist.gov/">expect</A> script that arranges to start the UML
+and configure it appropriately for the test. The configuration is done
+with the script given above for <VAR>INIT_SCRIPT</VAR>. The TCL script then forks,
+leaves the UML in the background and exits. uml_netjig continues. It then
+starts listening to the simulated network answering ARPs and inserting
+packets as appropriate.
+</P>
+
+<P>
+The klipstest function invokes <CODE>uml_netjig</CODE> with arguments
+to capture output from network interface(s) and insert packets as
+appropriate:
+<DL>
+<DT>PUB_INPUT</DT>
+<DD>a <A HREF="http://www.tcpdump.org/">pcap</A> file to feed in on
+ the public (encrypted) interface. (typically, eth1)</DD>
+<DT>PRIV_INPUT</DT>
+<DD>a pcap file to feed in on the private (plain-text) interface
+ (typically, eth0).</DD>
+<DT>REF_PUB_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the public
+ (eth1) interface are captured to a
+ <A HREF="http://www.tcpdump.org/">pcap</A> file by
+ <CODE>uml_netjig</CODE>. The klipstest function then uses tcpdump on
+ the file to produce text output, which is compared to the file given.</DD>
+<DT>REF_PUB_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further processing. Defaults to "cat".</DD>
+<DT>REF_PRIV_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the private
+ (eth0) interface are captured and compared after conversion by
+ tcpdump, as with <VAR>REFPUBOUTPUT</VAR>.</DD>
+<DT>REF_PRIV_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further processing. Defaults to "cat".</DD>
+<DT>EXITONEMPTY</DT>
+<DD>a flag for <CODE>uml_netjig</CODE>. It should contain
+ "--exitonempty" of uml_netjig should exit when all of the input
+ (<VAR>PUBINPUT</VAR>,<VAR>PRIVINPUT</VAR>) packets have been injected.</DD>
+<DT>ARPREPLY</DT>
+<DD>a flag for <CODE>uml_netjig</CODE>. It should contain "--arpreply"
+ if <CODE>uml_netjig</CODE> should reply to ARP requests. One will
+ typically set this to avoid having to fudge the ARP cache manually.</DD>
+<DT>TCPDUMPFLAGS</DT>
+<DD>a set of flags for the tcpdump used when converting captured
+ output. Typical values will include "-n" to turn off DNS, and often
+ "-E" to set the decryption key (tcpdump 3.7.1 and higher only) for
+ ESP packets. The "-t" flag (turn off timestamps) is provided automatically</DD>
+
+<DT>NETJIG_EXTRA</DT>
+<DD>additional comments to be sent to the netjig. This may arrange to
+ record or create additional networks, or may toggle options.
+</DL>
+
+<H2>mkinsttest paramaters</H2>
+<P>
+The basic concept of the <CODE>mkinsttest</CODE> test type is that it
+performs a "make install" to a temporary $DESTDIR. The resulting tree can then
+be examined to determine if it was done properly. The files can be uninstalled
+to determine if the file list was correct, or the contents of files can be
+examined more precisely.
+</P>
+
+<DL>
+<DT>INSTALL_FLAGS</DT>
+<DD>If set, then an install will be done. This provides the set of flags to
+provide for the install. The target to be used (usually "install") must be
+among the flags. </DD>
+<DT>POSTINSTALL_SCRIPT</DT>
+<DD>If set, a script to run after initial "make install". Two arguments are provided: an absolute path to the root of the FreeSWAN src tree, and an absolute path to the temporary installation area.</DD>
+<DT>INSTALL2_FLAGS</DT>
+<DD>If set, a second install will be done using these flags. Similarly to
+INSTALL_FLAGS, the target must be among the flags. </DD>
+<DT>UNINSTALL_FLAGS</DT>
+<DD>If set, an uninstall will be done using these flags. Similarly to
+INSTALL_FLAGS, the target (usually "uninstall") must be among the flags.</DD>
+<DT>REF_FIND_f_l_OUTPUT</DT>
+<DD>If set, a <CODE>find $ROOT ( -type f -or -type -l )</CODE> will be done to get a list of a real files and symlinks. The resulting file will be compared
+to the file listed by this option.</DD>
+<DT>REF_FILE_CONTENTS</DT>
+<DD>If set, it should point to a file containing records for the form:
+<PRE>
+ <VARIABLE>reffile</VARIABLE> <VARIABLE>samplefile</VARIABLE>
+</PRE>
+one record per line. A diff between the provided reference file, and the
+sample file (located in the temporary installation root) will be done for
+each record.
+</DD>
+</DL>
+
+<H2>rpm_build_install_test paramaters</H2>
+<P>
+The <CODE>rpm_build_install_test</CODE> type is to verify that the proper
+packing list is produced by "make rpm", and that the mechanisms for
+building the kernel modules produce consistent results.
+</P>
+
+<DL>
+<DT>RPM_KERNEL_SOURCE</DT>
+<DD>Point to an extracted copy of the RedHat kernel source code. Variables
+from the environment may be used.</DD>
+<DT>REF_RPM_CONTENTS</DT>
+<DD>This is a file containing one record per line. Each record consists
+of a RPM name (may contain wildcards) and a filename to compare the
+contents to. The RPM will be located and a file list will be produced with
+rpm2cpio.</DD>
+</DL>
+
+<H2>libtest paramaters</H2>
+<P>
+The libtest test is for testing library routines. The library file is
+expected to provided an <CODE>#ifdef</CODE> by the name of
+<VAR>library</VAR><CODE_MAIN</CODE>.
+The libtest type invokes the C compiler to compile this file, links it against
+<CODE>libfreeswan.a</CODE> (to resolve any other dependancies) and runs the
+test with the <CODE>-r</CODE> argument to invoke a regression test.</P>
+<P>The library test case is expected to do a self-test, exiting with status code 0 if everything is okay, and with non-zero otherwise. A core dump (exit code greater than 128) is noted specifically.
+</P>
+<P>
+Unlike other tests, there are no subdirectories required, or other
+parameters to set.
+</P>
+
+<H2 NAME="umlplutotest">umlplutotest paramaters</H2>
+<P>
+The umlplutotest function starts a pair of user mode line processes.
+This is a 2-host version of umlXhost. The "EAST" and "WEST" slots are defined.
+</P>
+
+<H2 NAME="umlXhost">umlXhost parameters</H2>
+<P>
+The umlXtest function starts an arbitrary number of user mode line processes.
+</P>
+
+<!-- <IMG SRC="single_netjig.png" ALT="block diagram of uml_netjig"> -->
+
+<P>
+The script invoked (<CODE>testing/utils/Xhost-test.tcl</CODE>) is a TCL
+<A HREF="http://expect.nist.gov/">expect</A> script that arranges to start each
+UML
+and configure it appropriately for the test. It then starts listening
+(using uml_netjig) to the simulated network answering ARPs and
+inserting packets as appropriate.
+</P>
+
+<P>
+umlXtest has a series of slots, each of which should be filled by a host.
+The list of slots is controlled by the variable, XHOST_LIST. This variable
+should be set to a space seperated list of slots. The former umlplutotest
+is now implemented as a variation of the umlXhost test,
+with XHOST_LIST="EAST WEST".
+</P>
+
+<P>
+For each host slot that is defined, a series of variables should be
+filled in, defining what configuration scripts to use for that host.
+</P>
+
+<P>
+The following are used to control the console input and output to the system.
+Where the string ${host} is present, the host slot should be filled in.
+I.e. for the two host system with XHOST_LIST="EAST WEST", then the
+variables: EAST_INIT_SCRIPT and WEST_INIT_SCRIPT will exist.
+<DL>
+<DT>${host}HOST</DT>
+<DD>The name of the UML host which will fill this slot</DD>
+<DT>${host}_INIT_SCRIPT</DT>
+<DD><p>a file of commands that is fed into the virtual machine's console
+ in single user mode prior to starting the tests. This file will
+ usually set up any eroute's and SADB entries that are required for
+ the test. Similar to INIT_SCRIPT, above.</p>
+<DT>${host}_RUN_SCRIPT</DT>
+<DD><P>a file of commands that is fed into the virtual machine's console
+ in single user mode, before the packets are sent. This set of
+ commands is run after all of the virtual machines are initialized.
+ I.e. after EAST_INIT_SCRIPT <B>AND</B> WEST_INIT_SCRIPT. This script
+ can therefore do things that require that all machines are properly
+ configured.</P>
+<DT>${host}_RUN2_SCRIPT</DT>
+<DD><P>a file of commands that is fed into the virtual machine's console
+ in single user mode, after the packets are sent. This set of
+ commands is run before any of the virtual machines have been shut
+ down. (I.e. before EAST_FINAL_SCRIPT <B>AND</B> WEST_FINAL_SCRIPT.)
+ This script can therefore catch post-activity status reports.</P>
+<DT>${host}_FINAL_SCRIPT</DT>
+<DD><p>a file of commands that is fed into the virtual machine's console
+ in single user mode after the final packet is sent. Similar to INIT_SCRIPT,
+ above. If not specified, then the single command "halt" is sent. Note that
+ when this script is run, the other virtual machines may already have been killed.
+ If specified, then the script should end with a halt command to nicely
+ shutdown the UML.
+</P>
+<DT>REF_${host}_CONSOLE_OUTPUT</DT>
+<DD>Similar to REF_CONSOLE_OUTPUT, above.</DT>
+</DL>
+</P>
+
+<P>Some additional flags apply to all hosts:
+<DL>
+<DT>REF_CONSOLE_FIXUPS</DT>
+<DD>a list of scripts (found in <CODE>klips/test/fixups</CODE>) to
+ apply to sanitize the console output of the machine under test.
+ These are typically perl, awk or sed scripts that remove things in
+ the kernel output that change each time the test is run and/or
+ compiled.
+</DD>
+</DL>
+</P>
+
+<P> In addition to input to the console, the networks may have input
+fed to them:
+<DL>
+<DT>EAST_INPUT/WEST_INPUT</DT>
+<DD>a <A HREF="http://www.tcpdump.org/">pcap</A> file to feed in on
+ the private network side of each network. The "EAST" and "WEST" here
+refer to the networks, not the hosts.</DD>
+<DT>REF_PUB_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further processing. Defaults to "cat".</DD>
+<DT>REF_EAST_FILTER/REF_WEST_FILTER</DT>
+<DD>a program that will filter the TCPDUMP output to do further processing. Defaults to "cat".</DD><
+<DT>TCPDUMPFLAGS</DT>
+<DD>a set of flags for the tcpdump used when converting captured
+ output. Typical values will include "-n" to turn off DNS, and often
+ "-E" to set the decryption key (tcpdump 3.7.1 and higher only) for
+ ESP packets. The "-t" flag (turn off timestamps) is provided automatically</DD>
+<DT>REF_EAST_OUTPUT/REF_WEST_OUTPUT</DT>
+<DD>a text file containing tcpdump output. Packets on the private
+ (eth0) interface are captured and compared after conversion by
+ tcpdump, as with <VAR>REF_PUB_OUTPUT</VAR>.</DD>
+</P>
+
+<P>
+There are two additional environment variables that may be set on the
+command line:
+<DL>
+<DT> NETJIGVERBOSE=verbose export NETJIGVERBOSE</DT>
+<DD> If set, then the test output will be "chatty", and let you know what
+ commands it is running, and as packets are sent. Without it set, the
+ output is limited to success/failure messages.</DD>
+<DT> NETJIGTESTDEBUG=netjig export NETJIGTESTDEBUG</DT>
+<DD> This will enable debugging of the communication with uml_netjig,
+ and turn on debugging in this utility.
+ This does not imply NETJIGVERBOSE.</DL>
+<DT> HOSTTESTDEBUG=hosttest export HOSTTESTDEBUG</DT>
+<DD> This will show all interactions with the user-mode-linux
+ consoles</DD>
+</DL>
+</P>
+
+<H2 NAME="kernelpatch">kernel_patch_test paramaters</H2>
+<P>
+The kernel_patch_test function takes some kernel source, copies it with
+lndir, and then applies the patch as produced by "make kernelpatch".
+</P>
+<P>
+The following are used to control the input and output to the system:
+<DL>
+<DT>KERNEL_NAME</DT>
+<DD>the kernel name, typically something like "linus" or "rh"</DD>
+<DT>KERNEL_VERSION</DT>
+<DD>the kernel version number, as in "2.2" or "2.4".</DD>
+<DT>KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC</DT>
+<DD>This variable should set in the environment, probably in
+ ~/freeswan-regress-env.sh. Examples of this variables would be
+ KERNEL_LINUS2_0_SRC or KERNEL_RH7_3_SRC. This variable should point
+ to an extracted copy of the kernel source in question.</DD>
+<DT>REF_PATCH_OUTPUT</DT>
+<DD>a copy of the patch output to compare against</DD>
+<DT>KERNEL_PATCH_LEAVE_SOURCE</DT>
+<DD>If set to a non-empty string, then the patched kernel source is not
+ removed at the end of the test. This will typically be set in the
+ environment while debugging.</DD>
+</DL>
+</P>
+
+<H2 NAME="modtest">module_compile paramaters</H2>
+<P>
+The module_compile test attempts to build the KLIPS module against a
+given set of kernel source. This is also done by the RPM tests, but
+in a very specific manner.
+</P>
+<P>
+There are two variations of this test - one where the kernel either
+doesn't need to be configured, or is already done, and tests were there
+is a local configuration file.
+</P>
+<P>
+Where the kernel doesn't need to be configured, the kernel source that
+is found is simply used. It may be a RedHat-style kernel, where one
+can cause it to configure itself via rhconfig.h-style definitions. Or,
+it may just be a kernel tree that has been configured.
+</P>
+<P>
+If the variable KERNEL_CONFIG_FILE is set, then a new directory is
+created for the kernel source. It is populated with lndir(1). The referenced
+file is then copied in as .config, and "make oldconfig" is used to configure
+the kernel. This resulting kernel is then used as the reference source.
+</P>
+<p>
+In all cases, the kernel source is found the same was for the kernelpatch
+test, i.e. via KERNEL_VERSION/KERNEL_NAME and KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC.</P>
+<P>
+Once there is kernel source, the module is compiled using the top-level
+"make module" target.
+</P>
+<P>
+The test is considered successful if an executable is found in OUTPUT/module/ipsec.o at the end of the test.
+</P>
+<DL>
+<DT>KERNEL_NAME</DT>
+<DD>the kernel name, typically something like "linus" or "rh"</DD>
+<DT>KERNEL_VERSION</DT>
+<DD>the kernel version number, as in "2.2" or "2.4".</DD>
+<DT>KERNEL_${KERNEL_NAME}${KERNEL_VERSION}_SRC</DT>
+<DD>This variable should set in the environment, probably in
+ ~/freeswan-regress-env.sh. Examples of this variables would be
+ KERNEL_LINUS2_0_SRC or KERNEL_RH7_3_SRC. This variable should point
+ to an extracted copy of the kernel source in question.</DD>
+<DT>KERNEL_CONFIG_FILE</DT>
+<DD>The configuration file for the kernel.</DD>
+<DT>KERNEL_PATCH_LEAVE_SOURCE</DT>
+<DD>If set to a non-empty string, then the configured kernel source is not
+ removed at the end of the test. This will typically be set in the
+ environment while debugging.</DD>
+<DT>MODULE_DEF_INCLUDE</DT>
+<DD>The include file that will be used to configure the KLIPS module, and
+ possibly the kernel source. </DD>
+</DL>
+
+<H1>Current pitfalls</H1>
+
+<DL>
+<DT> "tcpdump dissector" not available. </DT>
+<DD> This is a non-fatal warning. If uml_netjig is invoked with the -t
+ option, then it will attempt to use tcpdump's dissector to decode
+ each packet that it processes. The dissector is presently not
+ available, so this option it normally turned off at compile time.
+ The dissector library will be released with tcpdump version
+ 4.0.</DD>
+</DL>
+
+</body>
+</html> \ No newline at end of file
diff --git a/doc/src/manpages.html b/doc/src/manpages.html
new file mode 100644
index 000000000..27a9aa7b3
--- /dev/null
+++ b/doc/src/manpages.html
@@ -0,0 +1,155 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN man pages</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, manpage, manual, page">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: manpages.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="manpages">FreeS/WAN manual pages</a></h1>
+
+<p>The various components of Linux FreeS/WAN are of course documented in
+standard Unix manual pages, accessible via the man(1) command.</p>
+
+<p>Links here take you to an HTML version of the man pages.</p>
+
+<h2><a name="man.file">Files</a></h2>
+<dl>
+ <dt><a href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a></dt>
+ <dd>IPsec configuration and connections</dd>
+ <dt><a href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</a></dt>
+ <dd>secrets for IKE authentication, either pre-shared keys or RSA private
+ keys</dd>
+</dl>
+
+<p>These files are also discussed in the <a
+href="config.html">configuration</a> section.</p>
+
+<h2><a name="man.command">Commands</a></h2>
+
+<p>Many users will never give most of the FreeS/WAN commands directly.
+Configure the files listed above correctly and everything should be
+automatic.</p>
+
+<p>The exceptions are commands for mainpulating the <a
+href="glossary.html#RSA">RSA</a> keys used in Pluto authentication:</p>
+<dl>
+ <dt><a href="manpage.d/ipsec_rsasigkey.8.html">ipsec_rsasigkey(8)</a></dt>
+ <dd>generate keys</dd>
+ <dt><a href="manpage.d/ipsec_newhostkey.8.html">ipsec_newhostkey(8)</a></dt>
+ <dd>generate keys in a convenient format</dd>
+ <dt><a
+ href="manpage.d/ipsec_showhostkey.8.html">ipsec_showhostkey(8)</a></dt>
+ <dd>extract <a href="glossary.html#RSA">RSA</a> keys from <a
+ href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</a> (or
+ optionally, another file) and format them for insertion in <a
+ href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a> or in DNS
+ records</dd>
+</dl>
+
+<p>Note that:</p>
+<ul>
+ <li>These keys are for <strong>authentication only</strong>. They are
+ <strong>not secure for encryption</strong>.</li>
+ <li>The utility uses random(4) as a source of <a
+ href="glossary.html#random">random numbers</a>. This may block for some
+ time if there is not enough activity on the machine to provide the
+ required entropy. You may want to give it some bogus activity such as
+ random mouse movements or some command such as <nobr><tt>du /usr &gt; /dev/null
+ &amp;</tt></nobr>.</li>
+</ul>
+
+<p>The following commands are fairly likely to be used, if only for testing
+and status checks:</p>
+<dl>
+ <dt><a href="manpage.d/ipsec.8.html">ipsec(8)</a></dt>
+ <dd>invoke IPsec utilities</dd>
+ <dt><a href="manpage.d/ipsec_setup.8.html">ipsec_setup(8)</a></dt>
+ <dd>control IPsec subsystem</dd>
+ <dt><a href="manpage.d/ipsec_auto.8.html">ipsec_auto(8)</a></dt>
+ <dd>control automatically-keyed IPsec connections</dd>
+ <dt><a href="manpage.d/ipsec_manual.8.html">ipsec_manual(8)</a></dt>
+ <dd>take manually-keyed IPsec connections up and down</dd>
+ <dt><a href="manpage.d/ipsec_ranbits.8.html">ipsec_ranbits(8)</a></dt>
+ <dd>generate random bits in ASCII form</dd>
+ <dt><a href="manpage.d/ipsec_look.8.html">ipsec_look(8)</a></dt>
+ <dd>show minimal debugging information</dd>
+ <dt><a href="manpage.d/ipsec_barf.8.html">ipsec_barf(8)</a></dt>
+ <dd>spew out collected IPsec debugging information</dd>
+</dl>
+
+<p>The lower-level utilities listed below are normally invoked via scripts
+listed above, but they can also be used directly when required.</p>
+<dl>
+ <dt><a href="manpage.d/ipsec_eroute.8.html">ipsec_eroute(8)</a></dt>
+ <dd>manipulate IPsec extended routing tables</dd>
+ <dt><a href="manpage.d/ipsec_klipsdebug.8.html">ipsec_klipsdebug(8)</a></dt>
+ <dd>set Klips (kernel IPsec support) debug features and level</dd>
+ <dt><a href="manpage.d/ipsec_pluto.8.html">ipsec_pluto(8)</a></dt>
+ <dd>IPsec IKE keying daemon</dd>
+ <dt><a href="manpage.d/ipsec_spi.8.html">ipsec_spi(8)</a></dt>
+ <dd>manage IPsec Security Associations</dd>
+ <dt><a href="manpage.d/ipsec_spigrp.8.html">ipsec_spigrp(8)</a></dt>
+ <dd>group/ungroup IPsec Security Associations</dd>
+ <dt><a href="manpage.d/ipsec_tncfg.8.html">ipsec_tncfg(8)</a></dt>
+ <dd>associate IPsec virtual interface with real interface</dd>
+ <dt><a href="manpage.d/ipsec_whack.8.html">ipsec_whack(8)</a></dt>
+ <dd>control interface for IPsec keying daemon</dd>
+</dl>
+
+<h2><a name="man.lib">Library routines</a></h2>
+<dl>
+ <dt><a href="manpage.d/ipsec_atoaddr.3.html">ipsec_atoaddr(3)</a></dt>
+ <dt><a href="manpage.d/ipsec_addrtoa.3.html">ipsec_addrtoa(3)</a></dt>
+ <dd>convert Internet addresses to and from ASCII</dd>
+ <dt><a href="manpage.d/ipsec_atosubnet.3.html">ipsec_atosubnet(3)</a></dt>
+ <dt><a href="manpage.d/ipsec_subnettoa.3.html">ipsec_subnettoa(3)</a></dt>
+ <dd>convert subnet/mask ASCII form to and from addresses</dd>
+ <dt><a href="manpage.d/ipsec_atoasr.3.html">ipsec_atoasr(3)</a></dt>
+ <dd>convert ASCII to Internet address, subnet, or range</dd>
+ <dt><a href="manpage.d/ipsec_rangetoa.3.html">ipsec_rangetoa(3)</a></dt>
+ <dd>convert Internet address range to ASCII</dd>
+ <dt>ipsec_atodata(3)</dt>
+ <dt><a href="manpage.d/ipsec_datatoa.3.html">ipsec_datatoa(3)</a></dt>
+ <dd>convert binary data from and to ASCII formats</dd>
+ <dt><a href="manpage.d/ipsec_atosa.3.html">ipsec_atosa(3)</a></dt>
+ <dt><a href="manpage.d/ipsec_satoa.3.html">ipsec_satoa(3)</a></dt>
+ <dd>convert IPsec Security Association IDs to and from ASCII</dd>
+ <dt><a href="manpage.d/ipsec_atoul.3.html">ipsec_atoul(3)</a></dt>
+ <dt><a href="manpage.d/ipsec_ultoa.3.html">ipsec_ultoa(3)</a></dt>
+ <dd>convert unsigned-long numbers to and from ASCII</dd>
+ <dt><a href="manpage.d/ipsec_goodmask.3.html">ipsec_goodmask(3)</a></dt>
+ <dd>is this Internet subnet mask a valid one?</dd>
+ <dt><a href="manpage.d/ipsec_masktobits.3.html">ipsec_masktobits(3)</a></dt>
+ <dd>convert Internet subnet mask to bit count</dd>
+ <dt><a href="manpage.d/ipsec_bitstomask.3.html">ipsec_bitstomask(3)</a></dt>
+ <dd>convert bit count to Internet subnet mask</dd>
+ <dt><a
+ href="manpage.d/ipsec_optionsfrom.3.html">ipsec_optionsfrom(3)</a></dt>
+ <dd>read additional ``command-line'' options from file</dd>
+ <dt><a href="manpage.d/ipsec_subnetof.3.html">ipsec_subnetof(3)</a></dt>
+ <dd>given Internet address and subnet mask, return subnet number</dd>
+ <dt><a href="manpage.d/ipsec_hostof.3.html">ipsec_hostof(3)</a></dt>
+ <dd>given Internet address and subnet mask, return host part</dd>
+ <dt><a
+ href="manpage.d/ipsec_broadcastof.3.html">ipsec_broadcastof(3)</a></dt>
+ <dd>given Internet address and subnet mask, return broadcast address</dd>
+</dl>
+</body>
+</html>
diff --git a/doc/src/nightly.html b/doc/src/nightly.html
new file mode 100644
index 000000000..d86037884
--- /dev/null
+++ b/doc/src/nightly.html
@@ -0,0 +1,164 @@
+<html>
+<head>
+<title>FreeS/WAN nightly testing guide</title>
+<!-- Changed by: Michael Richardson, 23-Jul-2002 -->
+<meta name="keywords" content="Linux, IPsec, VPN, security, FreeSWAN, testing, User-Mode-Linux, UML">
+
+<!--
+
+Written by Michael Richardson for the Linux FreeS/WAN project
+Freely distributable under the GNU General Public License
+
+More information at www.freeswan.org
+Feedback to users@lists.freeswan.org
+
+$Id: nightly.html,v 1.1 2004/03/15 20:35:24 as Exp $
+
+$Log: nightly.html,v $
+Revision 1.1 2004/03/15 20:35:24 as
+added files from freeswan-2.04-x509-1.5.3
+
+Revision 1.3 2002/07/23 18:42:16 mcr
+ added instructions on setup of nightly build.
+
+Revision 1.2 2002/06/19 10:06:07 mcr
+ added nightly.html to the documentation tree.
+
+Revision 1.1 2002/05/24 03:33:30 mcr
+ start at document on nightly regression testing.
+
+
+-->
+</head>
+
+<body>
+
+<h1><a name="nightly">Nightly regression testing</a></h1>
+
+<p>
+The nightly regression testing system consists of several shell scripts
+and some perl scripts. The goal is to check out a fresh tree, run "make check" on it,
+record the results and summarize the results to the team and to the web site.
+</p>
+
+<P>
+Output can be found on <A HREF="http://bugs.freeswan.org:81/">adams</A>,
+although the tests are actually run on another project machine.</P>
+
+<H1><A name="nightlyhowto">How to setup the nightly build</A></h1>
+
+<P>
+The best way to do nightly testing is to setup a new account. We call the
+account "build" - you could call it something else, but there may
+still be some references to ~build in the scripts.
+</P>
+
+<H2> Files you need to know about </H2>
+<P>
+As few files as possible need to be extracted from the source tree -
+files are run from the source tree whenever possible. However, there
+are some bootstrap and configuration files that are necessary.
+</P>
+
+<P>
+There are 7 files in testing/utils that are involved:
+<DL>
+<DT> nightly-sample.sh </DT>
+<DD> This is the root of the build process. This file should be copied out
+of the CVS tree, to $HOME/bin/nightly.sh of the build account. This
+file should be invoked from cron. </DD>
+<DT> freeswan-regress-env-sample.sh </DT>
+<DD> This file should be copied to $HOME/freeswan-regress-env.sh. It
+ should be edited to localize the values. See below.</DD>
+<DT> regress-cleanup.pl </DT>
+<DD> This file needs to be copied to $HOME/bin/regress-cleanup.pl. It
+ is invoked by the nightly file before doing anything else. It
+ removes previous nights builds in order to free up disk space for
+ the build about to be done.</DD>
+<DT> teammail-sample.sh </DT>
+<DD> A script used to send results email to the "team". This sample
+ script could be copied to $HOME/bin/teammail.sh. This version will
+ PGP encrypt all the output to the team members. If this script is used,
+ then PGP will have to be properly setup to have the right keys.</DD>
+<DT> regress-nightly.sh </DT>
+<DD> This is the first stage of the nightly build. This stage will
+ call other scripts as appropriate, and will extract the source code
+ from CVS. This script should be copied to $HOME/bin/regress-nightly.sh</DD>
+<DT> regress-stage2.sh </DT>
+<DD> This is the second stage of the nightly build. It is called in
+ place. It essentially sets up the UML setup in umlsetup.sh, and
+ calls "make check".</DD>
+<DT> regress-summarize-results.pl
+<DD> This script will summarize the results from the tests to a
+ permanent directory set by $REGRESSRESULTS. It is invoked from the
+ stage2 nightly script.
+<DT> regress-chart.sh </DT>
+<DD> This script is called at the end of the build process, and will
+ summarize each night's results (as saved into $REGRESSRESULTS by
+ regress-summarize-results.pl) as a chart using gnuplot. Note that
+ this requires at least gnuplot 3.7.2.</DD>
+</DL>
+
+<H2>Configuring freeswan-regress-env.sh</H2>
+
+<P>For more info on KERNPOOL, UMLPATCH, BASICROOT and SHAREDIR, see
+ <A HREF="umltesting.html">User-Mode-Linux testing guide</A>.
+</P>
+
+<DL>
+<DT> KERNPOOL </DT>
+<DD> Extract copy of some kernel source to be used for UML builds</DD>
+<DT> UMLPATCH </DT>
+<DD> matching User-Mode-Linux patch.</DD>
+<DT> BASICROOT</DT>
+<DD> the root file system image (see
+ <A HREF="umltesting.html">User-Mode-Linux testing guide</A>).</DD>
+<DT> SHAREDIR=${BASICROOT}/usr/share</DT>
+<DD> The /usr/share to use.</DD>
+<DT> REGRESSTREE</DT>
+<DD> A directory in which to store the nightly regression
+ results. Directories will be created by date in this tree.</DD>
+
+<DT> TCPDUMP=tcpdump-3.7.1</DT>
+<DD> The path to the <A HREF="http://www.tcpdump.org/">tcpdump</A>
+ to use. This must have crypto compiled in, and must be at least 3.7.1</DT>
+
+<DT> KERNEL_RH7_2_SRC=/a3/kernel_sources/linux-2.4.9-13/</DT>
+<DD> An extracted copy of the RedHat 7.2. kernel source. If set, then
+ the packaging/rpm-rh72-install-01 test will be run, and an RPM will
+ be built as a test.</DD>
+
+<DT> KERNEL_RH7_3_SRC=/a3/kernel_sources/rh/linux-2.4.18-5</DT>
+<DD> An extracted copy of the RedHat 7.3. kernel source. If set, then
+ the packaging/rpm-rh73-install-01 test will be run, and an RPM will
+ be built as a test.</DD>
+
+<DT> NIGHTLY_WATCHERS="userid,userid,userid"</DT>
+<DD> The list of people who should receive nightly output. This is
+ used by teammail.sh</DD>
+
+<DT> FAILLINES=128</DT>
+<DD> How many lines of failed test output to include in the nightly
+ output</DD>
+
+<DT> PATH=$PATH:/sandel/bin export PATH</DT>
+<DD> You can also override the path if necessary here.</DD>
+
+<DT> CVSROOT=:pserver:anoncvs@ip212.xs4net.freeswan.org:/freeswan/MASTER</DT>
+<DD> The CVSROOT to use. This example may work for anonymous CVS, but
+ will be 12 hours behind the primary, and is still experimental</DD>
+
+<DT> SNAPSHOTSIGDIR=$HOME/snapshot-sig</DT>
+<DD> For the release tools, where to put the generated per-snapshot
+ signature keys</DD>
+
+<DT> LASTREL=1.97</DT>
+<DD> the name of the last release branch (to find the right
+ per-snapshot signature</DT>
+
+<DD>
+
+</DL>
+
+</body>
+</html> \ No newline at end of file
diff --git a/doc/src/performance.html b/doc/src/performance.html
new file mode 100755
index 000000000..9d90acc62
--- /dev/null
+++ b/doc/src/performance.html
@@ -0,0 +1,576 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN performance</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, performance, benchmark">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: performance.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="performance">Performance of FreeS/WAN</a></h1>
+The performance of FreeS/WAN is adequate for most applications.
+
+<p>In normal operation, the main concern is the overhead for encryption,
+decryption and authentication of the actual IPsec (<a
+href="glossary.html#ESP">ESP</a> and/or <a href="glossary.html#AH">AH</a>)
+data packets. Tunnel setup and rekeying occur so much less frequently than
+packet processing that, in general, their overheads are not worth worrying
+about.</p>
+
+<p>At startup, however, tunnel setup overheads may be significant. If you
+reboot a gateway and it needs to establish many tunnels, expect some delay.
+This and other issues for large gateways are discussed <a
+href="#biggate">below</a>.</p>
+
+<h2><a name="pub.bench">Published material</a></h2>
+
+<p>The University of Wales at Aberystwyth has done quite detailed speed tests
+and put <a href="http://tsc.llwybr.org.uk/public/reports/SWANTIME/">their
+results</a> on the web.</p>
+
+<p>Davide Cerri's <a href="http://www.linux.it/~davide/doc/">thesis (in
+Italian)</a> includes performance results for FreeS/WAN and for <a
+href="glossary.html#TLS">TLS</a>. He posted an <a
+href="http://lists.freeswan.org/pipermail/users/2001-December/006303.html">English
+summary</a> on the mailing list.</p>
+
+<p>Steve Bellovin used one of AT&amp;T Research's FreeS/WAN gateways as his
+data source for an analysis of the cache sizes required for key swapping in
+IPsec. Available as <a
+href="http://www.research.att.com/~smb/talks/key-agility.email.txt">text</a>
+or <a href="http://www.research.att.com/~smb/talks/key-agility.pdf">PDF
+slides</a> for a talk on the topic.</p>
+
+<p>See also the NAI work mentioned in the next section.</p>
+
+<h2><a name="perf.estimate">Estimating CPU overheads</a></h2>
+
+<p>We can come up with a formula that roughly relates CPU speed to the rate
+of IPsec processing possible. It is far from exact, but should be usable as a
+first approximation.</p>
+
+<p>An analysis of authentication overheads for high-speed networks, including
+some tests using FreeS/WAN, is on the <a
+href="http://www.pgp.com/research/nailabs/cryptographic/adaptive-cryptographic.asp">NAI
+Labs site</a>. In particular, see figure 3 in this <a
+href="http://download.nai.com/products/media/pgp/pdf/acsa_final_report.pdf">PDF
+document</a>. Their estimates of overheads, measured in Pentium II cycles per
+byte processed are:</p>
+
+<table border="1" align="center">
+ <tbody>
+ <tr>
+ <th></th>
+ <th>IPsec</th>
+ <th>authentication</th>
+ <th>encryption</th>
+ <th>cycles/byte</th>
+ </tr>
+ <tr>
+ <td>Linux IP stack alone</td>
+ <td>no</td>
+ <td>no</td>
+ <td>no</td>
+ <td align="right">5</td>
+ </tr>
+ <tr>
+ <td>IPsec without crypto</td>
+ <td>yes</td>
+ <td>no</td>
+ <td>no</td>
+ <td align="right">11</td>
+ </tr>
+ <tr>
+ <td>IPsec, authentication only</td>
+ <td>yes</td>
+ <td>SHA-1</td>
+ <td>no</td>
+ <td align="right">24</td>
+ </tr>
+ <tr>
+ <td>IPsec with encryption</td>
+ <td>yes</td>
+ <td>yes</td>
+ <td>yes</td>
+ <td align="right">not tested</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>Overheads for IPsec with encryption were not tested in the NAI work, but
+Antoon Bosselaers' <a
+href="http://www.esat.kuleuven.ac.be/~bosselae/fast.html">web page</a> gives
+cost for his optimised Triple DES implementation as 928 Pentium cycles per
+block, or 116 per byte. Adding that to the 24 above, we get 140 cycles per
+byte for IPsec with encryption.</p>
+
+<p>At 140 cycles per byte, a 140 MHz machine can handle a megabyte -- 8
+megabits -- per second. Speeds for other machines will be proportional to
+this. To saturate a link with capacity C megabits per second, you need a
+machine running at <var>C * 140/8 = C * 17.5</var> MHz.</p>
+
+<p>However, that estimate is not precise. It ignores the differences
+between:</p>
+<ul>
+ <li>NAI's test packets and real traffic</li>
+ <li>NAI's Pentium II cycles, Bosselaers' Pentium cycles, and your machine's
+ cycles</li>
+ <li>different 3DES implementations</li>
+ <li>SHA-1 and MD5</li>
+</ul>
+
+<p>and does not account for some overheads you will almost certainly have:</p>
+<ul>
+ <li>communication on the client-side interface</li>
+ <li>switching between multiple tunnels -- re-keying, cache reloading and so
+ on</li>
+</ul>
+
+<p>so we suggest using <var>C * 25</var> to get an estimate with a bit of a
+built-in safety factor.</p>
+
+<p>This covers only IP and IPsec processing. If you have other loads on your
+gateway -- for example if it is also working as a firewall -- then you will
+need to add your own safety factor atop that.</p>
+
+<p>This estimate matches empirical data reasonably well. For example,
+Metheringham's tests, described <a href="#klips.bench">below</a>, show a 733
+topping out between 32 and 36 Mbit/second, pushing data as fast as it can
+down a 100 Mbit link. Our formula suggests you need at least an 800 to handle
+a fully loaded 32 Mbit link. The two results are consistent.</p>
+
+<p>Some examples using this estimation method:</p>
+
+<table border="1" align="center">
+ <tbody>
+ <tr>
+ <th colspan="2">Interface</th>
+ <th colspan="3">Machine speed in MHz</th>
+ </tr>
+ <tr>
+ <th>Type</th>
+ <th>Mbit per<br>
+ second</th>
+ <th>Estimate<br>
+ Mbit*25</th>
+ <th>Minimum IPSEC gateway</th>
+ <th>Minimum with other load
+
+ <p>(e.g. firewall)</p>
+ </th>
+ </tr>
+ <tr>
+ <td>DSL</td>
+ <td align="right">1</td>
+ <td align="right">25 MHz</td>
+ <td rowspan="2">whatever you have</td>
+ <td rowspan="2">133, or better if you have it</td>
+ </tr>
+ <tr>
+ <td>cable modem</td>
+ <td align="right">3</td>
+ <td align="right">75 MHz</td>
+ </tr>
+ <tr>
+ <td><strong>any link, light load</strong></td>
+ <td align="right"><strong>5</strong></td>
+ <td align="right">125 MHz</td>
+ <td>133</td>
+ <td>200+, <strong>almost any surplus machine</strong></td>
+ </tr>
+ <tr>
+ <td>Ethernet</td>
+ <td align="right">10</td>
+ <td align="right">250 MHz</td>
+ <td>surplus 266 or 300</td>
+ <td>500+</td>
+ </tr>
+ <tr>
+ <td><strong>fast link, moderate load</strong></td>
+ <td align="right"><strong>20</strong></td>
+ <td align="right">500 MHz</td>
+ <td>500</td>
+ <td>800+, <strong>any current off-the-shelf PC</strong></td>
+ </tr>
+ <tr>
+ <td>T3 or E3</td>
+ <td align="right">45</td>
+ <td align="right">1125 MHz</td>
+ <td>1200</td>
+ <td>1500+</td>
+ </tr>
+ <tr>
+ <td>fast Ethernet</td>
+ <td align="right">100</td>
+ <td align="right">2500 MHz</td>
+ <td rowspan="2" colspan="2" align="center">// not feasible with 3DES in
+ software on current machines //</td>
+ </tr>
+ <tr>
+ <td>OC3</td>
+ <td align="right">155</td>
+ <td align="right">3875 MHz</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>Such an estimate is far from exact, but should be usable as minimum
+requirement for planning. The key observations are:</p>
+<ul>
+ <li>older <strong>surplus machines</strong> are fine for IPsec gateways at
+ loads up to <strong>5 megabits per second</strong> or so</li>
+ <li>a <strong>mid-range new machine</strong> can handle IPsec at rates up
+ to <strong>20 megabits per second</strong> or more</li>
+</ul>
+ <h3><a name="perf.more">Higher performance alternatives</a></h3>
+
+ <p><a href="glossary.html#AES">AES</a> is a new US government block cipher
+ standard, designed to replace the obsolete <a
+ href="glossary.html#DES">DES</a>. If FreeS/WAN using <a
+ href="glossary.html#3DES">3DES</a> is not fast enough for your application,
+ the AES <a href="web.html#patch">patch</a> may help.</p>
+
+ <p>To date (March 2002) we have had only one <a
+ href="http://lists.freeswan.org/pipermail/users/2002-February/007771.html">mailing
+ list report</a> of measurements with the patch applied. It indicates that,
+ at least for the tested load on that user's network, <strong>AES roughly
+ doubles IPsec throughput</strong>. If further testing confirms this, it may
+ prove possible to saturate an OC3 link in software on a high-end box.</p>
+
+ <p>Also, some work is being done toward support of <a
+ href="compat.html#hardware">hardware IPsec acceleration</a> which might
+ extend the range of requirements FreeS/WAN could meet.</p>
+
+ <h3>Other considerations</h3>
+
+ <p>CPU speed may be the main issue for IPsec performance, but of course it
+ isn't the only one.</p>
+
+ <p>You need good ethernet cards or other network interface hardware to get
+ the best performance. See this <a
+ href="http://www.ethermanage.com/ethernet/ethernet.html">ethernet
+ information</a> page and this <a href="http://www.scyld.com/diag">Linux
+ network driver</a> page.</p>
+
+ <p>The current FreeS/WAN kernel code is largely single-threaded. It is SMP
+ safe, and will run just fine on a multiprocessor machine (<a
+ href="compat.html#multiprocessor">discussion</a>), but the load within the
+ kernel is not shared effectively. This means that, for example to saturate
+ a T3 -- which needs about a 1200 MHz machine -- you cannot expect something
+ like a dual 800 to do the job. </p>
+
+ <p>On the other hand, SMP machines do tend to share loads well so --
+ provided one CPU is fast enough for the IPsec work -- a multiprocessor
+ machine may be ideal for a gateway with a mixed load.</p>
+
+ <h2><a name="biggate">Many tunnels from a single gateway</a></h2>
+
+ <p>FreeS/WAN allows a single gateway machine to build tunnels to many
+ others. There may, however, be some problems for large numbers as indicated
+ in this message from the mailing list:</p>
+
+<pre>Subject: Re: Maximum number of ipsec tunnels?
+ Date: Tue, 18 Apr 2000
+ From: "John S. Denker" &lt;jsd@research.att.com&gt;
+
+Christopher Ferris wrote:
+
+&gt;&gt; What are the maximum number ipsec tunnels FreeS/WAN can handle??
+
+Henry Spencer wrote:
+
+&gt;There is no particular limit. Some of the setup procedures currently
+&gt;scale poorly to large numbers of connections, but there are (clumsy)
+&gt;workarounds for that now, and proper fixes are coming.
+
+1) "Large" numbers means anything over 50 or so. I routinely run boxes
+with about 200 tunnels. Once you get more than 50 or so, you need to worry
+about several scalability issues:
+
+a) You need to put a "-" sign in syslogd.conf, and rotate the logs daily
+not weekly.
+
+b) Processor load per tunnel is small unless the tunnel is not up, in which
+case a new half-key gets generated every 90 seconds, which can add up if
+you've got a lot of down tunnels.
+
+c) There's other bits of lore you need when running a large number of
+tunnels. For instance, systematically keeping the .conf file free of
+conflicts requires tools that aren't shipped with the standard freeswan
+package.
+
+d) The pluto startup behavior is quadratic. With 200 tunnels, this eats up
+several minutes at every restart. I'm told fixes are coming soon.
+
+2) Other than item (1b), the CPU load depends mainly on the size of the
+pipe attached, not on the number of tunnels.
+</pre>
+
+<p>It is worth noting that item (1b) applies only to repeated attempts to
+re-key a data connection (IPsec SA, Phase 2) over an established keying
+connection (ISAKMP SA, Phase 1). There are two ways to reduce this overhead
+using settings in <a href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</a>:</p>
+<ul>
+ <li>set <var>keyingtries</var> to some small value to limit repetitions</li>
+ <li>set <var>keylife</var> to a short time so that a failing data
+ connection will be cleaned up when the keying connection is reset.</li>
+</ul>
+
+<p>The overheads for establishing keying connections (ISAKMP SAs, Phase 1)
+are lower because for these Pluto does not perform expensive operations
+before receiving a reply from the peer.</p>
+
+<p>A gateway that does a lot of rekeying -- many tunnels and/or low settings
+for tunnel lifetimes -- will also need a lot of <a
+href="glossary.html#random">random numbers</a> from the random(4) driver.</p>
+
+<h2><a name="low-end">Low-end systems</a></h2>
+
+<p><em>Even a 486 can handle a T1 line</em>, according to this mailing list
+message:</p>
+<pre>Subject: Re: linux-ipsec: IPSec Masquerade
+ Date: Fri, 15 Jan 1999 11:13:22 -0500
+ From: Michael Richardson
+
+. . . A 486/66 has been clocked by Phil Karn to do
+10Mb/s encryption.. that uses all the CPU, so half that to get some CPU,
+and you have 5Mb/s. 1/3 that for 3DES and you get 1.6Mb/s....</pre>
+
+<p>and a piece of mail from project technical lead Henry Spencer:</p>
+<pre>Oh yes, and a new timing point for Sandy's docs... A P60 -- yes, a 60MHz
+Pentium, talk about antiques -- running a host-to-host tunnel to another
+machine shows an FTP throughput (that is, end-to-end results with a real
+protocol) of slightly over 5Mbit/s either way. (The other machine is much
+faster, the network is 100Mbps, and the ether cards are good ones... so
+the P60 is pretty definitely the bottleneck.)</pre>
+
+<p>From the above, and from general user experience as reported on the list,
+it seems clear that a cheap surplus machine -- a reasonable 486, a minimal
+Pentium box, a Sparc 5, ... -- can easily handle a home office or a small
+company connection using any of:</p>
+<ul>
+ <li>ADSL service</li>
+ <li>cable modem</li>
+ <li>T1</li>
+ <li>E1</li>
+</ul>
+
+<p>If available, we suggest using a Pentium 133 or better. This should ensure
+that, even under maximum load, IPsec will use less than half the CPU cycles.
+You then have enough left for other things you may want on your gateway --
+firewalling, web caching, DNS and such.</p>
+
+<h2><a name="klips.bench">Measuring KLIPS</a></h2>
+
+<p>Here is some additional data from the mailing list.</p>
+<pre>Subject: FreeSWAN (specically KLIPS) performance measurements
+ Date: Thu, 01 Feb 2001
+ From: Nigel Metheringham &lt;Nigel.Metheringham@intechnology.co.uk&gt;
+
+I've spent a happy morning attempting performance tests against KLIPS
+(this is due to me not being able to work out the CPU usage of KLIPS so
+resorting to the crude measurements of maximum throughput to give a
+baseline to work out loading of a box).
+
+Measurements were done using a set of 4 boxes arranged in a line, each
+connected to the next by 100Mbit duplex ethernet. The inner 2 had an
+ipsec tunnel between them (shared secret, but I was doing measurements
+when the tunnel was up and running - keying should not be an issue
+here). The outer pair of boxes were traffic generators or traffic sink.
+
+The crypt boxes are Compaq DL380s - Uniprocessor PIII/733 with 256K
+cache. They have 128M main memory. Nothing significant was running on
+the boxes other than freeswan. The kernel was a 2.2.19pre7 patched
+with freeswan and ext3.
+
+Without an ipsec tunnel in the chain (ie the 2 inner boxes just being
+100BaseT routers), throughput (measured with ttcp) was between 10644
+and 11320 KB/sec
+
+With an ipsec tunnel in place, throughput was between 3268 and 3402
+KB/sec
+
+These measurements are for data pushed across a TCP link, so the
+traffic on the wire between the 2 ipsec boxes would have been higher
+than this....
+
+vmstat (run during some other tests, so not affecting those figures) on
+the encrypting box shows approx 50% system &amp; 50% idle CPU - which I
+don't believe at all. Interactive feel of the box was significantly
+sluggish.
+
+I also tried running the kernel profiler (see man readprofile) during
+test runs.
+
+A box doing primarily decrypt work showed basically nothing happening -
+I assume interrupts were off.
+A box doing encrypt work showed the following:-
+ Ticks Function Load
+ ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~
+ 956 total 0.0010
+ 532 des_encrypt2 0.1330
+ 110 MD5Transform 0.0443
+ 97 kmalloc 0.1880
+ 39 des_encrypt3 0.1336
+ 23 speedo_interrupt 0.0298
+ 14 skb_copy_expand 0.0250
+ 13 ipsec_tunnel_start_xmit 0.0009
+ 13 Decode 0.1625
+ 11 handle_IRQ_event 0.1019
+ 11 .des_ncbc_encrypt_end 0.0229
+ 10 speedo_start_xmit 0.0188
+ 9 satoa 0.0225
+ 8 kfree 0.0118
+ 8 ip_fragment 0.0121
+ 7 ultoa 0.0365
+ 5 speedo_rx 0.0071
+ 5 .des_encrypt2_end 5.0000
+ 4 _stext 0.0140
+ 4 ip_fw_check 0.0035
+ 2 rj_match 0.0034
+ 2 ipfw_output_check 0.0200
+ 2 inet_addr_type 0.0156
+ 2 eth_copy_and_sum 0.0139
+ 2 dev_get 0.0294
+ 2 addrtoa 0.0143
+ 1 speedo_tx_buffer_gc 0.0024
+ 1 speedo_refill_rx_buf 0.0022
+ 1 restore_all 0.0667
+ 1 number 0.0020
+ 1 net_bh 0.0021
+ 1 neigh_connected_output 0.0076
+ 1 MD5Final 0.0083
+ 1 kmem_cache_free 0.0016
+ 1 kmem_cache_alloc 0.0022
+ 1 __kfree_skb 0.0060
+ 1 ipsec_rcv 0.0001
+ 1 ip_rcv 0.0014
+ 1 ip_options_fragment 0.0071
+ 1 ip_local_deliver 0.0023
+ 1 ipfw_forward_check 0.0139
+ 1 ip_forward 0.0011
+ 1 eth_header 0.0040
+ 1 .des_encrypt3_end 0.0833
+ 1 des_decrypt3 0.0034
+ 1 csum_partial_copy_generic 0.0045
+ 1 call_out_firewall 0.0125
+
+Hope this data is helpful to someone... however the lack of visibility
+into the decrypt side makes things less clear</pre>
+
+<h2><a name="speed.compress">Speed with compression</a></h2>
+
+<p>Another user reported some results for connections with and without IP
+compression:</p>
+<pre>Subject: [Users] Speed with compression
+ Date: Fri, 29 Jun 2001
+ From: John McMonagle &lt;johnm@advocap.org&gt;
+
+Did a couple tests with compression using the new 1.91 freeswan.
+
+Running between 2 sites with cable modems. Both using approximately
+130 mhz pentium.
+
+Transferred files with ncftp.
+
+Compressed file was a 6mb compressed installation file.
+Non compressed was 18mb /var/lib/rpm/packages.rpm
+
+ Compressed vpn regular vpn
+Compress file 42.59 kBs 42.08 kBs
+regular file 110.84 kBs 41.66 kBs
+
+Load was about 0 either way.
+Ping times were very similar a bit above 9 ms.
+
+Compression looks attractive to me.</pre>
+Later in the same thread, project technical lead Henry Spencer added:
+<pre>&gt; is there a reason not to switch compression on? I have large gateway boxes
+&gt; connecting 3 connections, one of them with a measly DS1 link...
+
+Run some timing tests with and without, with data and loads representative
+of what you expect in production. That's the definitive way to decide.
+If compression is a net loss, then obviously, leave it turned off. If it
+doesn't make much difference, leave it off for simplicity and hence
+robustness. If there's a substantial gain, by all means turn it on.
+
+If both ends support compression and can successfully negotiate a
+compressed connection (trivially true if both are FreeS/WAN 1.91), then
+the crucial question is CPU cycles.
+
+Compression has some overhead, so one question is whether *your* data
+compresses well enough to save you more CPU cycles (by reducing the volume
+of data going through CPU-intensive encryption/decryption) than it costs
+you. Last time I ran such tests on data that was reasonably compressible
+but not deliberately contrived to be so, this generally was not true --
+compression cost extra CPU cycles -- so compression was worthwhile only if
+the link, not the CPU, was the bottleneck. However, that was before the
+slow-compression bug was fixed. I haven't had a chance to re-run those
+tests yet, but it sounds like I'd probably see a different result. </pre>
+The bug he refers to was a problem with the compression libraries that had us
+using C code, rather than assembler, for compression. It was fixed before
+1.91.
+
+<h2><a name="methods">Methods of measuring</a></h2>
+
+<p>If you want to measure the loads FreeS/WAN puts on a system, note that
+tools such as top or measurements such as load average are more-or-less
+useless for this. They are not designed to measure something that does most
+of its work inside the kernel.</p>
+
+<p>Here is a message from FreeS/WAN kernel programmer Richard Guy Briggs on
+this:</p>
+<pre>&gt; I have a batch of boxes doing Freeswan stuff.
+&gt; I want to measure the CPU loading of the Freeswan tunnels, but am
+&gt; having trouble seeing how I get some figures out...
+&gt;
+&gt; - Keying etc is in userspace so will show up on the per-process
+&gt; and load average etc (ie pluto's load)
+
+Correct.
+
+&gt; - KLIPS is in the kernel space, and does not show up in load average
+&gt; I think also that the KLIPS per-packet processing stuff is running
+&gt; as part of an interrupt handler so it does not show up in the
+&gt; /proc/stat system_cpu or even idle_cpu figures
+
+It is not running in interrupt handler. It is in the bottom half.
+This is somewhere between user context (careful, this is not
+userspace!) and hardware interrupt context.
+
+&gt; Is this correct, and is there any means of instrumenting how much the
+&gt; cpu is being loaded - I don't like the idea of a system running out of
+&gt; steam whilst still showing 100% idle CPU :-)
+
+vmstat seems to do a fairly good job, but use a running tally to get a
+good idea. A one-off call to vmstat gives different numbers than a
+running stat. To do this, put an interval on your vmstat command
+line.</pre>
+and another suggestion from the same thread:
+<pre>Subject: Re: Measuring the CPU usage of Freeswan
+ Date: Mon, 29 Jan 2001
+ From: Patrick Michael Kane &lt;modus@pr.es.to&gt;
+
+The only truly accurate way to accurately track FreeSWAN CPU usage is to use
+a CPU soaker. You run it on an unloaded system as a benchmark, then start up
+FreeSWAN and take the difference to determine how much FreeSWAN is eating.
+I believe someone has done this in the past, so you may find something in
+the FreeSWAN archives. If not, someone recently posted a URL to a CPU
+soaker benchmark tool on linux-kernel.</pre>
+</body>
+</html>
diff --git a/doc/src/policy-groups-table.html b/doc/src/policy-groups-table.html
new file mode 100644
index 000000000..8e84809cf
--- /dev/null
+++ b/doc/src/policy-groups-table.html
@@ -0,0 +1,297 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <meta name="Author" content="Richard Guy Briggs">
+
+ <meta name="GENERATOR" content="Mozilla/4.78 [en] (X11; U; Linux 2.4.18 i686) [Netscape]">
+ <title></title>
+</head>
+ <body>
+Policy Groups Table<br>
+<br>
+This table lists all the policy group combinations and expected packet flows.<br>
+<br>
+<br>
+
+<table border="1" cols="14" width="100%" nosave="">
+ <tbody>
+ <tr>
+ <th bgcolor="#cccccc">policy</th>
+ <th bgcolor="#cccccc"><br>
+ </th>
+ <th bgcolor="#cccccc" colspan="2">none</th>
+ <th bgcolor="#cccccc" colspan="2">clear</th>
+ <th bgcolor="#cccccc" colspan="2">clear-or-private</th>
+ <th bgcolor="#cccccc" colspan="2">private-or-clear</th>
+ <th bgcolor="#cccccc" colspan="2">private</th>
+ <th bgcolor="#cccccc" colspan="2">block</th>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc"><br>
+ </th>
+ <th bgcolor="#cccccc">key?</th>
+ <th bgcolor="#cccccc">no</th>
+ <th bgcolor="#cccccc">yes</th>
+ <th bgcolor="#cccccc">no</th>
+ <th bgcolor="#cccccc">yes</th>
+ <th bgcolor="#cccccc">no</th>
+ <th bgcolor="#cccccc">yes</th>
+ <th bgcolor="#cccccc">no</th>
+ <th bgcolor="#cccccc">yes</th>
+ <th bgcolor="#cccccc">no</th>
+ <th bgcolor="#cccccc">yes</th>
+ <th bgcolor="#cccccc">no</th>
+ <th bgcolor="#cccccc">yes</th>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc" rowspan="2">none</th>
+ <th bgcolor="#cccccc">no</th>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc">yes</th>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c,f?</td>
+ <td>c,f?</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc" rowspan="2">clear</th>
+ <th bgcolor="#cccccc">no</th>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c,c(f?)</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc">yes</th>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c,f?</td>
+ <td>c,f?</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc" rowspan="2">clear-or-private</th>
+ <th bgcolor="#cccccc">no</th>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c,f?</td>
+ <td>c,c(f?)</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc">yes</th>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c</td>
+ <td>c,f?</td>
+ <td>c,e</td>
+ <td>c,f</td>
+ <td>c,e</td>
+ <td>c,f</td>
+ <td>c,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc" rowspan="2">private-or-clear</th>
+ <th bgcolor="#cccccc">no</th>
+ <td>t,c</td>
+ <td>t,f?</td>
+ <td>t,c</td>
+ <td>t,f?</td>
+ <td>t,c</td>
+ <td>t,f?</td>
+ <td>t,f?</td>
+ <td>t,f?</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc">yes</th>
+ <td>t,c</td>
+ <td>t,f?</td>
+ <td>t,c</td>
+ <td>t,f?</td>
+ <td>t,c</td>
+ <td>t,e</td>
+ <td>t,c(f?)</td>
+ <td>t,e</td>
+ <td>t,f</td>
+ <td>t,e</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc" rowspan="2">private</th>
+ <th bgcolor="#cccccc">no</th>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc">yes</th>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ <td>t,e</td>
+ <td>t,f</td>
+ <td>t,e</td>
+ <td>t,f</td>
+ <td>t,e</td>
+ <td>t,f</td>
+ <td>t,f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc" rowspan="2">block</th>
+ <th bgcolor="#cccccc">no</th>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ </tr>
+ <tr>
+ <th bgcolor="#cccccc">yes</th>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ <td>f</td>
+ </tr>
+
+ </tbody>
+</table>
+ <br>
+ &nbsp;
+<table border="1" cols="2" nosave="">
+ <tbody>
+ <tr nosave="">
+ <th nosave="">legend</th>
+ <th>packet fate</th>
+ </tr>
+ <tr>
+ <td>c</td>
+ <td>clear</td>
+ </tr>
+ <tr>
+ <td>f</td>
+ <td>fail</td>
+ </tr>
+ <tr>
+ <td>e</td>
+ <td>encrypt</td>
+ </tr>
+ <tr>
+ <td>t</td>
+ <td>trap</td>
+ </tr>
+ <tr>
+ <td valign="Top">c,f<br>
+ </td>
+ <td valign="Top">first packet clear, then fail<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="Top">c,e<br>
+ </td>
+ <td valign="Top">first packet clear, then encrypt<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="Top">t,f<br>
+ </td>
+ <td valign="Top">trap, then fail<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="Top">t,c<br>
+ </td>
+ <td valign="Top">trap, then clear<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="Top">t,e<br>
+ </td>
+ <td valign="Top">trap, then encrypt<br>
+ </td>
+ </tr>
+
+ </tbody>
+</table>
+
+</body>
+</html>
diff --git a/doc/src/policygroups.html b/doc/src/policygroups.html
new file mode 100644
index 000000000..0425ade39
--- /dev/null
+++ b/doc/src/policygroups.html
@@ -0,0 +1,489 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>Configuring FreeS/WAN with policy groups</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, encryption, cryptography, FreeS/WAN, FreeSWAN">
+ <!--
+
+ Written by Claudia Schmeing for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: policygroups.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1>How to Configure Linux FreeS/WAN with Policy Groups</h1>
+
+
+<A NAME="policygroups"></A>
+
+<H2>What are Policy Groups?</H2>
+
+
+<P><STRONG>Policy Groups</STRONG> are an elegant general mechanism
+to configure FreeS/WAN. They are useful for
+many FreeS/WAN users.</P>
+
+<P>In previous FreeS/WAN versions, you needed to configure each IPsec
+connection explicitly, on both local and remote hosts.
+ This could become complex.</P>
+
+<P>By contrast, Policy Groups allow you to set local IPsec policy
+for lists of remote hosts and networks,
+simply by listing the hosts and networks which you wish to
+have special treatment in one of several Policy Group files.
+FreeS/WAN then internally creates the connections
+needed to implement each policy.</P>
+
+<P>In the next section we describe our five Base Policy Groups, which
+you can use to configure IPsec in many useful ways. Later, we will
+show you how to create an IPsec VPN using one line of configuration for
+each remote host or network.</P>
+
+
+<A NAME="builtin_policygroups"></A><H3>Built-In Security Options</H3>
+
+<P>FreeS/WAN offers these Base Policy Groups:</P>
+
+<DL>
+
+<DT>private</DT>
+
+<DD>
+FreeS/WAN only communicates privately with the listed
+<A HREF="glossary.html#CIDR">CIDR</A> blocks.
+If needed, FreeS/WAN attempts to create a connection opportunistically.
+If this fails, FreeS/WAN blocks communication.
+Inbound blocking is assumed to be done by the firewall. FreeS/WAN offers
+firewall hooks but no modern firewall rules to help with inbound blocking.
+
+</DD>
+
+<DT>private-or-clear</DT>
+<DD>
+
+FreeS/WAN prefers private communication with the listed CIDR blocks.
+If needed, FreeS/WAN attempts to create a connection opportunistically.
+If this fails, FreeS/WAN allows traffic in the clear.
+
+</DD>
+
+<DT>clear-or-private</DT>
+
+<DD>
+FreeS/WAN communicates cleartext with the listed CIDR blocks, but
+also accepts inbound OE connection requests from them.
+Also known as <A HREF="glossary.html#passive.OE">passive OE (pOE)</A>,
+this policy may be used to create an
+<A HREF="glossary.html#responder">opportunistic responder</A>.
+</DD>
+
+<DT>clear</DT>
+<DD>
+FreeS/WAN only communicates cleartext with the listed CIDR blocks.
+</DD>
+
+<DT>block</DT>
+<DD>FreeS/WAN blocks traffic to and from and the listed CIDR blocks.
+Inbound blocking is assumed to be done by the firewall. FreeS/WAN offers
+firewall hooks but no modern firewall rules to help with inbound blocking.
+<!-- also called "blockdrop".-->
+
+</DD>
+
+</DL>
+
+<A NAME="policy.group.notes"></A><P>Notes:</P>
+
+<UL>
+<LI>Base Policy Groups apply to communication with this host only.</LI>
+<LI>The most specific rule (whether policy or pre-configured connection)
+applies.
+This has several practical applications:
+<UL>
+<LI>If CIDR blocks overlap, FreeS/WAN chooses
+the most specific applicable block.</LI>
+<LI>This decision also takes into account any pre-configured connections
+you may have.</LI>
+<LI>If the most specific connection is a pre-configured connection,
+the following procedure applies. If that connection is up, it will be
+used. If it is routed, it will be brought up. If it is added,
+no action will be taken.</LI>
+</UL>
+<LI>Base Policy Groups are created using built-in connections.
+Details in
+<A HREF="manpage.d/ipsec.conf.5.html">man ipsec.conf</A>.</LI>
+<LI>All Policy Groups are bidirectional.
+<A HREF="src/policy-groups-table.html">This chart</A> shows some technical
+details.
+FreeS/WAN does not support one-way encryption, since it can give users
+a false sense of security.</LI>
+</UL>
+
+
+<H2>Using Policy Groups</H2>
+
+<P>The Base Policy Groups which build IPsec connections rely on Opportunistic
+Encryption. To use the following examples, you
+must first become OE-capable, as described
+in our <A HREF="quickstart.html#quickstart">quickstart guide</A>.
+
+<A NAME="example1"></A><H3>Example 1: Using a Base Policy Group</H3>
+
+<P>Simply place CIDR blocks (<A HREF="#dnswarning">names</A>,
+IPs or IP ranges) in /etc/ipsec.d/policies/<VAR>[groupname]</VAR>,
+and reread the policy group files.</P>
+
+<P>For example, the <VAR>private-or-clear</VAR> policy tells
+FreeS/WAN to prefer encrypted communication to the listed CIDR blocks.
+Failing that, it allows talk in the clear.</P>
+
+<P>To make this your default policy, place
+<A HREF="glossary.html#fullnet">fullnet</A>
+in the <VAR>private-or-clear</VAR> policy group file:</P>
+
+<PRE> [root@xy root]# cat /etc/ipsec.d/policies/private-or-clear
+ # This file defines the set of CIDRs (network/mask-length) to which
+ # communication should be private, if possible, but in the clear otherwise.
+ ....
+ 0.0.0.0/0</PRE>
+
+<P>and reload your policies with</P>
+
+<PRE> ipsec auto --rereadgroups</PRE>
+
+<P>Use <A HREF="quickstart.html#opp.test">this test</A> to verify
+opportunistic connections.</P>
+
+
+
+<A NAME="example2"></A><H3>Example 2: Defining IPsec Security Policy
+with Groups</H3>
+
+<P>Defining IPsec security policy with Base Policy Groups is like creating
+a shopping list: just put CIDR blocks in the appropriate group files.
+For example:</P>
+
+
+<PRE> [root@xy root]# cd /etc/ipsec.d/policies
+ [root@xy policies]# cat private
+ 192.0.2.96/27 # The finance department
+ 192.0.2.192/29 # HR
+ 192.0.2.12 # HR gateway
+ irc.private.example.com # Private IRC server
+
+ [root@xy policies]# cat private-or-clear
+ 0.0.0.0/0 # My default policy: try to encrypt.
+
+ [root@xy policies]# cat clear
+ 192.0.2.18/32 # My POP3 server
+ 192.0.2.19/32 # My Web proxy
+
+ [root@xy policies]# cat block
+ spamsource.example.com</PRE>
+
+<P>To make these settings take effect, type:</P>
+<PRE> ipsec auto --rereadgroups</PRE>
+
+
+<P>Notes:</P>
+<UL>
+<LI>For opportunistic connection attempts to succeed, all participating
+FreeS/WAN hosts and gateways must be configured for OE.</LI>
+<LI>Examples 3 through 5 show how to implement a detailed <VAR>private</VAR>
+policy.</LI>
+<LI>
+<A NAME="dnswarning"></A>
+<FONT COLOR=RED>Warning:</FONT> Using DNS names in policy files and ipsec.conf
+can be tricky. If the name does not resolve, the policy will not be
+implemented for that name.
+It is therefore safer either to use IPs, or to put any critical names
+in /etc/hosts.
+We plan to implement periodic DNS retry to help with this.
+<BR>
+Names are resolved at FreeS/WAN startup, or when the policies are reloaded.
+Unfortunately, name lookup can hold up the startup process.
+If you have fast DNS servers, the problem may be less severe.
+</LI>
+</UL>
+
+
+<A HREF="example3"></A><H3>Example 3: Creating a Simple IPsec VPN with the
+<VAR>private</VAR> Group</H3>
+
+
+<P>You can create an IPsec VPN between several hosts, with
+only one line of configuration per host, using the <VAR>private</VAR>
+policy group.</P>
+
+<P>First, use our <A HREF="quickstart.html">quickstart
+guide</A> to set up each participating host
+with a FreeS/WAN install and OE.</P>
+
+<P>In one host's <VAR>/etc/ipsec.d/policies/private</VAR>,
+list the peers to which you wish to protect traffic.
+For example:</P>
+
+<PRE> [root@xy root]# cd /etc/ipsec.d/policies
+ [root@xy policies]# cat private
+ 192.0.2.9 # several hosts at example.com
+ 192.0.2.11
+ 192.0.2.12
+ irc.private.example.com
+</PRE>
+
+<P>Copy the <VAR>private</VAR> file to each host. Remove the local host, and
+add the initial host.</P>
+
+<PRE> scp2 /etc/ipsec.d/policies/private root@192.0.2.12:/etc/ipsec.d/policies/private</PRE>
+
+<P>On each host, reread the policy groups with</P>
+
+<PRE> ipsec auto --rereadgroups</PRE>
+
+
+<P>That's it! You're configured.</P>
+
+<P>Test by pinging between two hosts. After a second or two,
+traffic should flow, and</P>
+
+<PRE> ipsec eroute</PRE>
+
+<P>should yield something like</P>
+
+<PRE> 192.0.2.11/32 -> 192.0.2.8/32 => tun0x149f@192.0.2.8</PRE>
+
+<P>where your host IPs are substituted for 192.0.2.11 and 192.0.2.8.</P>
+
+<P>If traffic does not flow, there may be an error in your OE setup.
+Revisit our <A HREF="quickstart.html">quickstart guide</A>.</P>
+
+
+<P>Our next two examples show you how to add subnets to this IPsec VPN.</P>
+
+
+<A NAME="example4"></A><H3>Example 4: New Policy Groups to Protect a
+Subnet</H3>
+
+<P>To protect traffic to a subnet behind your FreeS/WAN gateway,
+you'll need additional DNS records, and new policy groups.
+To set up the DNS, see our <A HREF="quickstart.html#opp.gate">quickstart
+guide</A>. To create five new policy groups for your subnet,
+copy these connections to <VAR>/etc/ipsec.conf</VAR>.
+Substitute your subnet's IPs for 192.0.2.128/29.</P>
+
+<PRE>
+conn private-net
+ also=private # inherits settings (eg. auto=start) from built in conn
+ leftsubnet=192.0.2.128/29 # your subnet's IPs here
+
+conn private-or-clear-net
+ also=private-or-clear
+ leftsubnet=192.0.2.128/29
+
+conn clear-or-private-net
+ also=clear-or-private
+ leftsubnet=192.0.2.128/29
+
+conn clear-net
+ also=clear
+ leftsubnet=192.0.2.128/29
+
+conn block-net
+ also=block
+ leftsubnet=192.0.2.128/29
+</PRE>
+
+<P>Copy the gateway's files to serve as the initial policy group files for the
+new groups:</P>
+
+<PRE>
+ cp -p /etc/ipsec.d/policies/private /etc/ipsec.d/policies/private-net
+ cp -p /etc/ipsec.d/policies/private-or-clear /etc/ipsec.d/policies/private-or-clear-net
+ cp -p /etc/ipsec.d/policies/clear-or-private /etc/ipsec.d/policies/clear-or-private-net
+ cp -p /etc/ipsec.d/policies/clear /etc/ipsec.d/policies/clear-net
+ cp -p /etc/ipsec.d/policies/block /etc/ipsec.d/policies/block
+</PRE>
+
+<P><STRONG>Tip: Since a missing policy group file is equivalent to a file with
+no entries, you need only create files for the connections
+you'll use.</STRONG></P>
+
+<P>To test one of your new groups, place the fullnet 0.0.0.0/0 in
+<VAR>private-or-clear-net</VAR>.
+Perform the subnet test in
+<A HREF="quickstart.html#opp.test">our quickstart guide</A>. You should
+see a connection, and</P>
+
+<PRE> ipsec eroute</PRE>
+
+<P>should include an entry which mentions the subnet node's IP and the
+OE test site IP, like this:</P>
+
+<PRE> 192.0.2.131/32 -> 192.139.46.77/32 => tun0x149f@192.0.2.11</PRE>
+
+
+<A HREF="example5"></A><H3>Example 5: Adding a Subnet to the VPN</H3>
+
+<P>Suppose you wish to secure traffic to a subnet 192.0.2.192/29
+behind a FreeS/WAN box 192.0.2.12.</P>
+
+<P>First, add DNS entries to configure 192.0.2.12 as an opportunistic
+gateway for that subnet. Instructions are in
+ our <A HREF="quickstart.html#opp.gate">quickstart guide</A>.
+Next, create a <VAR>private-net</VAR> group on 192.0.2.12 as described in
+<A HREF="#example4">Example 4</A>.
+</P>
+
+<P>On each other host, add the subnet 192.0.2.192/29 to <VAR>private</VAR>,
+yielding for example</P>
+
+<PRE> [root@xy root]# cd /etc/ipsec.d/policies
+ [root@xy policies]# cat private
+ 192.0.2.9 # several hosts at example.com
+ 192.0.2.11
+ 192.0.2.12 # HR department gateway
+ 192.0.2.192/29 # HR subnet
+ irc.private.example.com
+</PRE>
+
+
+<P>and reread policy groups with </P>
+
+<PRE> ipsec auto --rereadgroups</PRE>
+
+<P>That's all the configuration you need.</P>
+
+<P>Test your VPN by pinging from a machine on 192.0.2.192/29 to any other host:
+</P>
+
+<PRE> [root@192.0.2.194]# ping 192.0.2.11</PRE>
+
+
+<P>After a second or two, traffic should flow, and</P>
+
+<PRE> ipsec eroute</PRE>
+
+<P>should yield something like</P>
+
+<PRE> 192.0.2.11/32 -> 192.0.2.194/32 => tun0x149f@192.0.2.12
+</PRE>
+
+<P>Key:</P>
+<TABLE>
+<TR><TD>1.</TD>
+ <TD>192.0.2.11/32</TD>
+ <TD>Local start point of the protected traffic.
+ </TD></TR>
+<TR><TD>2.</TD>
+ <TD>192.0.2.194/32</TD>
+ <TD>Remote end point of the protected traffic.
+ </TD></TR>
+<TR><TD>3.</TD>
+ <TD>192.0.2.12</TD>
+ <TD>Remote FreeS/WAN node (gateway or host).
+ May be the same as (2).
+ </TD></TR>
+<TR><TD>4.</TD>
+ <TD>[not shown]</TD>
+ <TD>Local FreeS/WAN node (gateway or host),
+ where you've produced the output.
+ May be the same as (1).
+ </TD></TR>
+</TABLE>
+
+<P>For additional assurance, you can verify with a packet sniffer
+that the traffic is being encrypted.</P>
+
+
+<P>Note</P>
+<UL>
+<LI>Because strangers may also connect via OE,
+this type of VPN may require a stricter firewalling policy than a
+conventional VPN.</LI></UL>
+
+
+
+<H2>Appendix</H2>
+
+<A NAME="hiddenconn"></A><H3>Our Hidden Connections</H3>
+
+
+<P>Our Base Policy Groups are created using hidden connections.
+These are spelled out in
+<A HREF="manpage.d/ipsec.conf.5.html">man ipsec.conf</A>
+ and defined in <VAR>/usr/local/lib/ipsec/_confread</VAR>.
+</P>
+
+
+<A NAME="custom_policygroups"></A><H3>Custom Policy Groups</H3>
+
+<P>A policy group is built using a special connection description
+in <VAR>ipsec.conf</VAR>, which:</P>
+
+<UL>
+<LI>is <STRONG>generic</STRONG>. It uses
+<VAR>right=[%group|%opportunisticgroup]</VAR> rather than specific IPs.
+The connection is cloned for every name or IP range listed in its Policy Group
+file.</LI>
+<LI>often has a <STRONG>failure rule</STRONG>. This rule, written
+<VAR>failureshunt=[passthrough|drop|reject|none]</VAR>, tells FreeS/WAN
+what to do with packets for these CIDRs if it fails to establish the connection.
+Default is <VAR>none</VAR>.
+</LI>
+</UL>
+
+<P>To create a new group:</P>
+<OL>
+<LI>Create its connection definition in <VAR>ipsec.conf</VAR>.</LI>
+<LI>Create a Policy Group file in <VAR>/etc/ipsec.d/policies</VAR>
+with the same name as your connection.
+</LI>
+<LI>Put a CIDR block in that file.</LI>
+<LI>Reread groups with <VAR>ipsec auto --rereadgroups</VAR>.</LI>
+<LI>Test: <VAR>ping</VAR> to activate any OE connection, and view
+results with <VAR>ipsec eroute</VAR>.</LI>
+</OL>
+
+<A NAME="disable_oe"></A>
+<A NAME="disable_policygroups"></A><H3>Disabling Opportunistic Encryption</H3>
+
+<P>To disable OE (eg. policy groups and packetdefault), cut and paste the following lines
+to <VAR>/etc/ipsec.conf</VAR>:</P>
+
+<PRE>conn block
+ auto=ignore
+
+conn private
+ auto=ignore
+
+conn private-or-clear
+ auto=ignore
+
+conn clear-or-private
+ auto=ignore
+
+conn clear
+ auto=ignore
+
+conn packetdefault
+ auto=ignore</PRE>
+
+<P>Restart FreeS/WAN so that the changes take effect:</P>
+
+<PRE> ipsec setup restart</PRE>
+
+</body>
+</html>
+
+
diff --git a/doc/src/politics.html b/doc/src/politics.html
new file mode 100644
index 000000000..9e87d4f05
--- /dev/null
+++ b/doc/src/politics.html
@@ -0,0 +1,1466 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>History and politics of cryptography</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, cryptography, history, politics">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: politics.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="politics">History and politics of cryptography</a></h1>
+
+<p>Cryptography has a long and interesting history, and has been the subject
+of considerable political controversy.</p>
+
+<h2><a name="intro.politics">Introduction</a></h2>
+
+<h3>History</h3>
+
+<p>The classic book on the history of cryptography is David Kahn's <a
+href="biblio.html#Kahn">The Codebreakers</a>. It traces codes and
+codebreaking from ancient Egypt to the 20th century.</p>
+
+<p>Diffie and Landau <a href="biblio.html#diffie">Privacy on the Line: The
+Politics of Wiretapping and Encryption</a> covers the history from the First
+World War to the 1990s, with an emphasis on the US.</p>
+
+<h4>World War II</h4>
+
+<p>During the Second World War, the British "Ultra" project achieved one of
+the greatest intelligence triumphs in the history of warfare, breaking many
+Axis codes. One major target was the Enigma cipher machine, a German device
+whose users were convinced it was unbreakable. The American "Magic" project
+had some similar triumphs against Japanese codes.</p>
+
+<p>There are many books on this period. See our bibliography for several. Two
+I particularly like are:</p>
+<ul>
+ <li>Andrew Hodges has done a superb <a
+ href="http://www.turing.org.uk/book/">biography</a> of Alan Turing, a key
+ player among the Ultra codebreakers. Turing was also an important
+ computer pioneer. The terms <a
+ href="http://www.abelard.org/turpap/turpap.htm">Turing test</a> and <a
+ href="http://plato.stanford.edu/entries/turing-machine/">Turing
+ machine</a> are named for him, as is the <a
+ href="http://www.acm.org">ACM</a>'s highest technical <a
+ href="http://www.acm.org/awards/taward.html">award</a>.</li>
+ <li>Neal Stephenson's <a href="biblio.html#neal">Cryptonomicon</a> is a
+ novel with cryptography central to the plot. Parts of it take place
+ during WW II, other parts today.</li>
+</ul>
+
+<p>Bletchley Park, where much of the Ultra work was done, now has a museum
+and a <a href="http://www.bletchleypark.org.uk/">web site</a>.</p>
+
+<p>The Ultra work introduced three major innovations.</p>
+<ul>
+ <li>The first break of Enigma was achieved by Polish Intelligence in 1931.
+ Until then most code-breakers had been linguists, but a different
+ approach was needed to break machine ciphers. Polish Intelligence
+ recruited bright young mathematicians to crack the "unbreakable" Enigma.
+ When war came in 1939, the Poles told their allies about this, putting
+ Britain on the road to Ultra. The British also adopted a mathematical
+ approach.</li>
+ <li>Machines were extensively used in the attacks. First the Polish "Bombe"
+ for attacking Enigma, then British versions of it, then machines such as
+ Collosus for attacking other codes. By the end of the war, some of these
+ machines were beginning to closely resemble digital computers. After the
+ war, a team at Manchester University, several old Ultra hands included,
+ built one of the world's first actual general-purpose digital
+ computers.</li>
+ <li>Ultra made codebreaking a large-scale enterprise, producing
+ intelligence on an industrial scale. This was not a "black chamber", not
+ a hidden room in some obscure government building with a small crew of
+ code-breakers. The whole operation -- from wholesale interception of
+ enemy communications by stations around the world, through large-scale
+ code-breaking and analysis of the decrypted material (with an enormous
+ set of files for cross-referencing), to delivery of intelligence to field
+ commanders -- was huge, and very carefully managed.</li>
+</ul>
+
+<p>So by the end of the war, Allied code-breakers were expert at large-scale
+mechanised code-breaking. The payoffs were enormous.</p>
+
+<h4><a name="postwar">Postwar and Cold War</a></h4>
+
+<p>The wartime innovations were enthusiastically adopted by post-war and Cold
+War signals intelligence agencies. Presumably many nations now have some
+agency capable of sophisticated attacks on communications security, and quite
+a few engage in such activity on a large scale.</p>
+
+<p>America's <a href="glossary.html#NSA">NSA</a>, for example, is said to be
+both the world's largest employer of mathematicians and the world's largest
+purchaser of computer equipment. Such claims may be somewhat exaggerated, but
+beyond doubt the NSA -- and similar agencies in other countries -- have some
+excellent mathematicians, lots of powerful computers, sophisticated software,
+and the organisation and funding to apply them on a large scale. Details of
+the NSA budget are secret, but there are some published <a
+href="http://www.fas.org/irp/nsa/nsabudget.html">estimates</a>.</p>
+
+<p>Changes in the world's communications systems since WW II have provided
+these agencies with new targets. Cracking the codes used on an enemy's
+military or diplomatic communications has been common practice for centuries.
+Extensive use of radio in war made large-scale attacks such as Ultra
+possible. Modern communications make it possible to go far beyond that.
+Consider listening in on cell phones, or intercepting electronic mail, or
+tapping into the huge volumes of data on new media such as fiber optics or
+satellite links. None of these targets existed in 1950. All of them can be
+attacked today, and almost certainly are being attacked.</p>
+
+<p>The Ultra story was not made public until the 1970s. Much of the recent
+history of codes and code-breaking has not been made public, and some of it
+may never be. Two important books are:</p>
+<ul>
+ <li>Bamford's <a href="biblio.html#puzzle">The Puzzle Palace</a>, a history
+ of the NSA</li>
+ <li>Hager's <a href="http://www.fas.org/irp/eprint/sp/index.html">Secret
+ Power</a>, about the <a
+ href="http://sg.yahoo.com/government/intelligence/echelon_network/">Echelon</a>
+ system -- the US, UK, Canada, Australia and New Zealand co-operating to
+ monitor much of the world's communications.</li>
+</ul>
+
+<p>Note that these books cover only part of what is actually going on, and
+then only the activities of nations open and democratic enough that (some of)
+what they are doing can be discovered. A full picture, including:</p>
+<ul>
+ <li>actions of the English-speaking democracies not covered in those
+ books</li>
+ <li>actions of other more-or-less sane governments</li>
+ <li>the activities of various more-or-less insane governments</li>
+ <li>possibilities for unauthorized action by government employees</li>
+ <li>possible actions by large non-government organisations: corporations,
+ criminals, or conspiracies</li>
+</ul>
+
+<p>might be really frightening.</p>
+
+<h4><a name="recent">Recent history -- the crypto wars</a></h4>
+
+<p>Until quite recently, cryptography was primarily a concern of governments,
+especially of the military, of spies, and of diplomats. Much of it was
+extremely secret.</p>
+
+<p>In recent years, that has changed a great deal. With computers and
+networking becoming ubiquitous, cryptography is now important to almost
+everyone. Among the developments since the 1970s:</p>
+<ul>
+ <li>The US gov't established the Data Encryption Standard, <a
+ href="glossary.html#DES">DES</a>, a <a href="glossary.html#block">block
+ cipher</a> for cryptographic protection of unclassfied documents.</li>
+ <li>DES also became widely used in industry, especially regulated
+ industries such as banking.</li>
+ <li>Other nations produced their own standards, such as <a
+ href="glossary.html#GOST">GOST</a> in the Soviet Union.</li>
+ <li><a href="glossary.html#public">Public key</a> cryptography was invented
+ by Diffie and Hellman.</li>
+ <li>Academic conferences such as <a
+ href="http://www-cse.ucsd.edu/users/mihir/crypto2k.html">Crypto</a> and
+ <a
+ href="http://www.esat.kuleuven.ac.be/cosic/eurocrypt2000/">Eurocrypt</a>
+ began.</li>
+ <li>Several companies began offerring cryptographic products: <a
+ href="glossary.html#RSAco">RSA</a>, <a href="glossary.html#PGPI">PGP</a>,
+ the many vendors with <a href="glossary.html#PKI">PKI</a> products,
+ ...</li>
+ <li>Cryptography appeared in other products: operating systems, word
+ processors, ...</li>
+ <li>Network protocols based on crypto were developed: <a
+ href="glossary.html#SSH">SSH</a>, <a href="glossary.html#SSL">SSL</a>, <a
+ href="glossary.html#IPsec">IPsec</a>, ...</li>
+ <li>Crytography came into widespread use to secure bank cards, terminals,
+ ...</li>
+ <li>The US government replaced <a href="glossary.html#DES">DES</a> with the
+ much stronger Advanced Encryption Standard, <a
+ href="glossary.html#AES">AES</a></li>
+</ul>
+
+<p>This has led to a complex ongoing battle between various mainly government
+groups wanting to control the spread of crypto and various others, notably
+the computer industry and the <a
+href="http://online.offshore.com.ai/security/">cypherpunk</a> crypto
+advocates, wanting to encourage widespread use.</p>
+
+<p>Steven Levy has written a fine history of much of this, called <a
+href="biblio.html#crypto">Crypto: How the Code rebels Beat the Government --
+Saving Privacy in the Digital Age</a>.</p>
+
+<p>The FreeS/WAN project is to a large extent an outgrowth of cypherpunk
+ideas. Our reasons for doing the project can be seen in these quotes from the
+<a
+href="http://www.eff.org/pub/Privacy/Crypto_misc/cypherpunk.manifesto">Cypherpunk
+Manifesto</a>:</p>
+
+<blockquote>
+ Privacy is necessary for an open society in the electronic age. ...
+
+ <p>We cannot expect governments, corporations, or other large, faceless
+ organizations to grant us privacy out of their beneficence. It is to their
+ advantage to speak of us, and we should expect that they will speak.
+ ...</p>
+
+ <p>We must defend our own privacy if we expect to have any. ...</p>
+
+ <p>Cypherpunks write code. We know that someone has to write software to
+ defend privacy, and since we can't get privacy unless we all do, we're
+ going to write it. We publish our code so that our fellow Cypherpunks may
+ practice and play with it. Our code is free for all to use, worldwide. We
+ don't much care if you don't approve of the software we write. We know
+ that software can't be destroyed and that a widely dispersed system can't
+ be shut down.</p>
+
+ <p>Cypherpunks deplore regulations on cryptography, for encryption is
+ fundamentally a private act. ...</p>
+
+ <p>For privacy to be widespread it must be part of a social contract.
+ People must come and together deploy these systems for the common good.
+ ...</p>
+</blockquote>
+
+<p>To quote project leader John Gilmore:</p>
+
+<blockquote>
+ We are literally in a race between our ability to build and deploy
+ technology, and their ability to build and deploy laws and treaties.
+ Neither side is likely to back down or wise up until it has definitively
+ lost the race.</blockquote>
+
+<p>If FreeS/WAN reaches its goal of making <a
+href="intro.html#opp.intro">opportunistic encryption</a> widespread so that
+secure communication can become the default for a large part of the net, we
+will have struck a major blow.</p>
+
+<h3><a name="intro.poli">Politics</a></h3>
+
+<p>The political problem is that nearly all governments want to monitor their
+enemies' communications, and some want to monitor their citizens. They may be
+very interested in protecting some of their own communications, and often
+some types of business communication, but not in having everyone able to
+communicate securely. They therefore attempt to restrict availability of
+strong cryptography as much as possible.</p>
+
+<p>Things various governments have tried or are trying include:</p>
+<ul>
+ <li>Echelon, a monitor-the-world project of the US, UK, NZ, Australian and
+ Canadian <a href="glossary.html#SIGINT">signals intelligence</a>
+ agencies. See this <a
+ href="http://sg.yahoo.com/government/intelligence/echelon_network/">collection</a>
+ of links and this <a
+ href="http://www.zdnet.com/zdnn/stories/news/0,4586,2640682,00.html">story</a>
+ on the French Parliament's reaction.</li>
+ <li>Others governments may well have their own Echelon-like projects. To
+ quote the Dutch Minister of Defense, as reported in a German <a
+ href="http://www.heise.de/tp/english/inhalt/te/4729/1.html">magazine</a>:
+
+ <blockquote>
+ The government believes not only the governments associated with
+ Echelon are able to intercept communication systems, but that it is an
+ activity of the investigative authorities and intelligence services of
+ many countries with governments of different political
+ signature.</blockquote>
+ Even if they have nothing on the scale of Echelon, most intelligence
+ agencies and police forces certainly have some interception
+ capability.</li>
+ <li><a href="glossary.html#NSA">NSA</a> tapping of submarine communication
+ cables, described in <a
+ href="http://www.zdnet.com/zdnn/stories/news/0,4586,2764372,00.html">this
+ article</a></li>
+ <li>A proposal for international co-operation on <a
+ href="http://www.heise.de/tp/english/special/enfo/4306/1.html">Internet
+ surveillance</a>.</li>
+ <li>Alleged <a href="http://cryptome.org/nsa-sabotage.htm">sabotage</a> of
+ security products by the <a href="glossary.html#NSA">NSA</a> (the US
+ signals intelligence agency).</li>
+ <li>The German armed forces and some government departments will stop using
+ American software for fear of NSA "back doors", according to this <a
+ href="http://www.theregister.co.uk/content/4/17679.html">news
+ story</a>.</li>
+ <li>The British Regulation of Investigatory Powers bill. See this <a
+ href="http://www.fipr.org/rip/index.html">web page.</a> and perhaps this
+ <a
+ href="http://ars.userfriendly.org/cartoons/?id=20000806&amp;mode=classic">cartoon</a>.</li>
+ <li>A Russian <a
+ href="http://www.eff.org/pub/Privacy/Foreign_and_local/Russia/russian_crypto_ban_english.edict">ban</a>
+ on cryptography</li>
+ <li>Chinese <a
+ href="http://www.eff.org/pub/Misc/Publications/Declan_McCullagh/www/global/china">controls</a>
+ on net use.</li>
+ <li>The FBI's carnivore system for covert searches of email. See this <a
+ href="http://www.zdnet.com/zdnn/stories/news/0,4586,2601502,00.html">news
+ coverage</a> and this <a
+ href="http://www.crypto.com/papers/carnivore-risks.html">risk
+ assessment</a>. The government had an external review of some aspects of
+ this system done. See this <a
+ href="http://www.crypto.com/papers/carnivore_report_comments.html">analysis</a>
+ of that review. Possible defenses against Carnivore include:
+ <ul>
+ <li><a href="glossary.html#PGP">PGP</a> for end-to-end mail
+ encryption</li>
+ <li><a href="http://www.home.aone.net.au/qualcomm/">secure sendmail</a>
+ for server-to-server encryption</li>
+ <li>IPsec encryption on the underlying IP network</li>
+ </ul>
+ </li>
+ <li>export laws restricting strong cryptography as a munition. See <a
+ href="#exlaw">discussion</a> below.</li>
+ <li>various attempts to convince people that fundamentally flawed
+ cryptography, such as encryption with a <a href="#escrow">back door</a>
+ for government access to data or with <a href="#shortkeys">inadequate key
+ lengths</a>, was adequate for their needs.</li>
+</ul>
+
+<p>Of course governments are by no means the only threat to privacy and
+security on the net. Other threats include:</p>
+<ul>
+ <li>industrial espionage, as for example in this <a
+ href="http://www.zdnet.com/zdnn/stories/news/0,4586,2626931,00.html">news
+ story</a></li>
+ <li>attacks by organised criminals, as in this <a
+ href="http://www.sans.org/newlook/alerts/NTE-bank.htm">large-scale
+ attack</a></li>
+ <li>collection of personal data by various companies.
+ <ul>
+ <li>for example, consider the various corporate winners of Privacy
+ International's <a
+ href="http://www.privacyinternational.org/bigbrother/">Big Brother
+ Awards</a>.</li>
+ <li><a href="http://www.zeroknowledge.com">Zero Knowledge</a> sell
+ tools to defend against this</li>
+ </ul>
+ </li>
+ <li>individuals may also be a threat in a variety of ways and for a variety
+ of reasons</li>
+ <li>in particular, an individual with access to government or industry data
+ collections could do considerable damage using that data in unauthorized
+ ways.</li>
+</ul>
+
+<p>One <a
+href="http://www.zdnet.com/zdnn/stories/news/0,4586,2640674,00.html">study</a>
+enumerates threats and possible responses for small and medium businesses.
+VPNs are a key part of the suggested strategy.</p>
+
+<p>We consider privacy a human right. See the UN's <a href="http://www.un.org/Overview/rights.html">Universal
+Declaration of Human Rights</a>, article twelve:</p>
+
+<blockquote>
+ No one shall be subjected to arbitrary interference with his privacy,
+ family, home or correspondence, nor to attacks upon his honor and
+ reputation. Everyone has the right to the protection of the law against
+ such interference or attacks.</blockquote>
+
+<p>Our objective is to help make privacy possible on the Internet using
+cryptography strong enough not even those well-funded government agencies are
+likely to break it. If we can do that, the chances of anyone else breaking it
+are negliible.</p>
+
+<h3>Links</h3>
+
+<p>Many groups are working in different ways to defend privacy on the net and
+elsewhere. Please consider contributing to one or more of these groups:</p>
+<ul>
+ <li>the EFF's <a href="http://www.eff.org/crypto/">Privacy Now!</a>
+ campaign</li>
+ <li>the <a href="http://www.gilc.org">Global Internet Liberty
+ Campaign</a></li>
+ <li><a href="http://www.cpsr.org/program/privacy/privacy.html">Computer
+ Professionals for Social Responsibility</a></li>
+</ul>
+
+<p>For more on these issues see:</p>
+<ul>
+ <li>Steven Levy (Newsweek's chief technology writer and author of the
+ classic "Hackers") new book <a href="biblio.html#crypto">Crypto: How the
+ Code Rebels Beat the Government--Saving Privacy in the Digital
+ Age</a></li>
+ <li>Simson Garfinkel (Boston Globe columnist and author of books on <a
+ href="biblio.html#PGP">PGP</a> and <a href="biblio.html#practical">Unix
+ Security</a>) book <a href="biblio.html#Garfinkel">Database Nation: the
+ death of privacy in the 21st century</a></li>
+</ul>
+
+<p>There are several collections of <a href="web.html#quotes">crypto
+quotes</a> on the net.</p>
+
+<p>See also the <a href="biblio.html">bibliography</a> and our list of <a
+href="web.html#policy">web references</a> on cryptography law and policy.</p>
+
+<h3>Outline of this section</h3>
+
+<p>The remainder of this section includes two pieces of writing by our
+project leader</p>
+<ul>
+ <li>his <a href="#gilmore">rationale</a> for starting this</li>
+ <li>another <a href="#policestate">discussion</a> of project goals</li>
+</ul>
+
+<p>and discussions of:</p>
+<ul>
+ <li><a href="#desnotsecure">why we do not use DES</a></li>
+ <li><a href="#exlaw">cryptography export laws</a></li>
+ <li>why <a href="#escrow">government access to keys</a> is not a good
+ idea</li>
+ <li>the myth that <a href="#shortkeys">short keys</a> are adequate for some
+ security requirements</li>
+</ul>
+
+<p>and a section on <a href="#press">press coverage of FreeS/WAN</a>.</p>
+
+<h2><a name="leader">From our project leader</a></h2>
+
+<p>FreeS/WAN project founder John Gilmore wrote a web page about why we are
+doing this. The version below is slightly edited, to fit this format and to
+update some links. For a version without these edits, see his <a
+href="http://www.toad.com/gnu/">home page</a>.</p>
+
+<center>
+<h3><a name="gilmore">Swan: Securing the Internet against Wiretapping</a></h3>
+</center>
+
+<p>My project for 1996 was to <b>secure 5% of the Internet traffic against
+passive wiretapping</b>. It didn't happen in 1996, so I'm still working on it
+in 1997, 1998, and 1999! If we get 5% in 1999 or 2000, we can secure 20% the
+next year, against both active and passive attacks; and 80% the following
+year. Soon the whole Internet will be private and secure. The project is
+called S/WAN or S/Wan or Swan for Secure Wide Area Network; since it's free
+software, we call it FreeSwan to distinguish it from various commercial
+implementations. <a href="http://www.rsa.com/rsa/SWAN/">RSA</a> came up with
+the term "S/WAN". Our main web site is at <a
+href="http://www.freeswan.org/">http://www.freeswan.org/</a>. Want to
+help?</p>
+
+<p>The idea is to deploy PC-based boxes that will sit between your local area
+network and the Internet (near your firewall or router) which
+opportunistically encrypt your Internet packets. Whenever you talk to a
+machine (like a Web site) that doesn't support encryption, your traffic goes
+out "in the clear" as usual. Whenever you connect to a machine that does
+support this kind of encryption, this box automatically encrypts all your
+packets, and decrypts the ones that come in. In effect, each packet gets put
+into an "envelope" on one side of the net, and removed from the envelope when
+it reaches its destination. This works for all kinds of Internet traffic,
+including Web access, Telnet, FTP, email, IRC, Usenet, etc.</p>
+
+<p>The encryption boxes are standard PC's that use freely available Linux
+software that you can download over the Internet or install from a cheap
+CDROM.</p>
+
+<p>This wasn't just my idea; lots of people have been working on it for
+years. The encryption protocols for these boxes are called <a
+href="glossary.html#IPsec">IPSEC (IP Security)</a>. They have been developed
+by the <a
+href="http://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html">IP
+Security Working Group</a> of the <a href="http://www.ietf.org/">Internet
+Engineering Task Force</a>, and will be a standard part of the next major
+version of the Internet protocols (<a
+href="http://playground.sun.com/pub/ipng/html/ipng-main.html">IPv6</a>). For
+today's (IP version 4) Internet, they are an option.</p>
+
+<p>The <a href="http://www.iab.org/iab">Internet Architecture Board</a> and
+<a href="http://www.ietf.org/">Internet Engineering Steering Group</a> have
+taken a <a href="iab-iesg.stmt">strong stand</a> that the Internet should use
+powerful encryption to provide security and privacy. I think these protocols
+are the best chance to do that, because they can be deployed very easily,
+without changing your hardware or software or retraining your users. They
+offer the best security we know how to build, using the Triple-DES, RSA, and
+Diffie-Hellman algorithms.</p>
+
+<p>This "opportunistic encryption box" offers the "fax effect". As each
+person installs one for their own use, it becomes more valuable for their
+neighbors to install one too, because there's one more person to use it with.
+The software automatically notices each newly installed box, and doesn't
+require a network administrator to reconfigure it. Instead of "virtual
+private networks" we have a "REAL private network"; we add privacy to the
+real network instead of layering a manually-maintained virtual network on top
+of an insecure Internet.</p>
+
+<h4>Deployment of IPSEC</h4>
+
+<p>The US government would like to control the deployment of IP Security with
+its <a href="#exlaw">crypto export laws</a>. This isn't a problem for my
+effort, because the cryptographic work is happening outside the United
+States. A foreign philanthropist, and others, have donated the resources
+required to add these protocols to the Linux operating system. <a
+href="http://www.linux.org/">Linux</a> is a complete, freely available
+operating system for IBM PC's and several kinds of workstation, which is
+compatible with Unix. It was written by Linus Torvalds, and is still
+maintained by a talented team of expert programmers working all over the
+world and coordinating over the Internet. Linux is distributed under the <a
+href="glossary.html#GPL">GNU Public License</a>, which gives everyone the
+right to copy it, improve it, give it to their friends, sell it commercially,
+or do just about anything else with it, without paying anyone for the
+privilege.</p>
+
+<p>Organizations that want to secure their network will be able to put two
+Ethernet cards into an IBM PC, install Linux on it from a $30 CDROM or by
+downloading it over the net, and plug it in between their Ethernet and their
+Internet link or firewall. That's all they'll have to do to encrypt their
+Internet traffic everywhere outside their own local area network.</p>
+
+<p>Travelers will be able to run Linux on their laptops, to secure their
+connection back to their home network (and to everywhere else that they
+connect to, such as customer sites). Anyone who runs Linux on a standalone PC
+will also be able to secure their network connections, without changing their
+application software or how they operate their computer from day to day.</p>
+
+<p>There will also be numerous commercially available firewalls that use this
+technology. <a href="http://www.rsa.com/">RSA Data Security</a> is
+coordinating the <a href="http://www.rsa.com/rsa/SWAN">S/Wan (Secure Wide
+Area Network)</a> project among more than a dozen vendors who use these
+protocols. There's a <a
+href="http://www.rsa.com/rsa/SWAN/swan_test.htm">compatability chart</a> that
+shows which vendors have tested their boxes against which other vendors to
+guarantee interoperatility.</p>
+
+<p>Eventually it will also move into the operating systems and networking
+protocol stacks of major vendors. This will probably take longer, because
+those vendors will have to figure out what they want to do about the export
+controls.</p>
+
+<h4>Current status</h4>
+
+<p>My initial goal of securing 5% of the net by Christmas '96 was not met. It
+was an ambitious goal, and inspired me and others to work hard, but was
+ultimately too ambitious. The protocols were in an early stage of
+development, and needed a lot more protocol design before they could be
+implemented. As of April 1999, we have released version 1.0 of the software
+(<a
+href="ftp://ftp.xs4all.nl/freeswan/freeswan-1.0.tar.gz">freeswan-1.0.tar.gz</a>),
+which is suitable for setting up Virtual Private Networks using shared
+secrets for authentication. It does not yet do opportunistic encryption, or
+use DNSSEC for authentication; those features are coming in a future
+release.</p>
+<dl>
+ <dt>Protocols</dt>
+ <dd>The low-level encrypted packet formats are defined. The system for
+ publishing keys and providing secure domain name service is defined.
+ The IP Security working group has settled on an NSA-sponsored protocol
+ for key agreement (called ISAKMP/Oakley), but it is still being worked
+ on, as the protocol and its documentation is too complex and
+ incomplete. There are prototype implementations of ISAKMP. The
+ protocol is not yet defined to enable opportunistic encryption or the
+ use of DNSSEC keys.</dd>
+ <dt>Linux Implementation</dt>
+ <dd>The Linux implementation has reached its first major release and is
+ ready for production use in manually-configured networks, using Linux
+ kernel version 2.0.36.</dd>
+ <dt>Domain Name System Security</dt>
+ <dd>There is now a release of BIND 8.2 that includes most DNS Security
+ features.
+ <p>The first prototype implementation of Domain Name System Security
+ was funded by <a href="glossary.html#DARPA">DARPA</a> as part of their
+ <a href="http://www.darpa.mil/ito/research/is/index.html">Information
+ Survivability program</a>. <a href="http://www.tis.com">Trusted
+ Information Systems</a> wrote a modified version of <a
+ href="http://www.isc.org/bind.html">BIND</a>, the widely-used Berkeley
+ implementation of the Domain Name System.</p>
+ <p>TIS, ISC, and I merged the prototype into the standard version of
+ BIND. The first production version that supports KEY and SIG records is
+ <b>bind-4.9.5</b>. This or any later version of BIND will do for
+ publishing keys. It is available from the <a
+ href="http://www.isc.org/bind.html">Internet Software Consortium</a>.
+ This version of BIND is not export-controlled since it does not contain
+ any cryptography. Later releases starting with BIND 8.2 include
+ cryptography for authenticating DNS records, which is also exportable.
+ Better documentation is needed.</p>
+ </dd>
+</dl>
+
+<h4>Why?</h4>
+
+<p>Because I can. I have made enough money from several successful startup
+companies, that for a while I don't have to work to support myself. I spend
+my energies and money creating the kind of world that I'd like to live in and
+that I'd like my (future) kids to live in. Keeping and improving on the civil
+rights we have in the United States, as we move more of our lives into
+cyberspace, is a particular goal of mine.</p>
+
+<h4>What You Can Do</h4>
+<dl>
+ <dt>Install the latest BIND at your site.</dt>
+ <dd>You won't be able to publish any keys for your domain, until you have
+ upgraded your copy of BIND. The thing you really need from it is the
+ new version of <i>named</i>, the Name Daemon, which knows about the new
+ KEY and SIG record types. So, download it from the <a
+ href="http://www.isc.org/bind.html">Internet Software Consortium </a>
+ and install it on your name server machine (or get your system
+ administrator, or Internet Service Provider, to install it). Both your
+ primary DNS site and all of your secondary DNS sites will need the new
+ release before you will be able to publish your keys. You can tell
+ which sites this is by running the Unix command "dig MYDOMAIN ns" and
+ seeing which sites are mentioned in your NS (name server) records.</dd>
+ <dt>Set up a Linux system and run a 2.0.x kernel on it</dt>
+ <dd>Get a machine running Linux (say the 5.2 release from <a
+ href="http://www.redhat.com">Red Hat</a>). Give the machine two
+ Ethernet cards.</dd>
+ <dt>Install the Linux IPSEC (Freeswan) software</dt>
+ <dd>If you're an experienced sysadmin or Linux hacker, install the
+ freeswan-1.0 release, or any later release or snapshot. These releases
+ do NOT provide automated "opportunistic" operation; they must be
+ manually configured for each site you wish to encrypt with.</dd>
+ <dt>Get on the linux-ipsec mailing list</dt>
+ <dd>The discussion forum for people working on the project, and testing
+ the code and documentation, is: linux-ipsec@clinet.fi. To join this
+ mailing list, send email to <a
+ href="mailto:linux-ipsec-REQUEST@clinet.fi">linux-ipsec-REQUEST@clinet.fi</a>
+ containing a line of text that says "subscribe linux-ipsec". (You can
+ later get off the mailing list the same way -- just send "unsubscribe
+ linux-ipsec").</dd>
+
+ <p></p>
+ <dt>Check back at this web page every once in a while</dt>
+ <dd>I update this page periodically, and there may be new information in
+ it that you haven't seen. My intent is to send email to the mailing
+ list when I update the page in any significant way, so subscribing to
+ the list is an alternative.</dd>
+</dl>
+
+<p>Would you like to help? I can use people who are willing to write
+documentation, install early releases for testing, write cryptographic code
+outside the United States, sell pre-packaged software or systems including
+this technology, and teach classes for network administrators who want to
+install this technology. To offer to help, send me email at gnu@toad.com.
+Tell me what country you live in and what your citizenship is (it matters due
+to the export control laws; personally I don't care). Include a copy of your
+resume and the URL of your home page. Describe what you'd like to do for the
+project, and what you're uniquely qualified for. Mention what other
+volunteer projects you've been involved in (and how they worked out). Helping
+out will require that you be able to commit to doing particular things, meet
+your commitments, and be responsive by email. Volunteer projects just don't
+work without those things.</p>
+
+<h4>Related projects</h4>
+<dl>
+ <dt>IPSEC for NetBSD</dt>
+ <dd>This prototype implementation of the IP Security protocols is for
+ another free operating system. <a
+ href="ftp://ftp.funet.fi/pub/unix/security/net/ip/BSDipsec.tar.gz">Download
+ BSDipsec.tar.gz</a>.</dd>
+ <dt>IPSEC for <a href="http://www.openbsd.org">OpenBSD</a></dt>
+ <dd>This prototype implementation of the IP Security protocols is for yet
+ another free operating system. It is directly integrated into the OS
+ release, since the OS is maintained in Canada, which has freedom of
+ speech in software.</dd>
+</dl>
+
+<h3><a name="policestate">Stopping wholesale monitoring</a></h3>
+
+<p>From a message project leader John Gilmore posted to the mailing list:</p>
+<pre>John Denker wrote:
+
+&gt; Indeed there are several ways in which the documentation overstates the
+&gt; scope of what this project does -- starting with the name
+&gt; FreeS/WAN. There's a big difference between having an encrypted IP tunnel
+&gt; versus having a Secure Wide-Area Network. This software does a fine job of
+&gt; the former, which is necessary but not sufficient for the latter.
+
+The goal of the project is to make it very hard to tap your wide area
+communications. The current system provides very good protection
+against passive attacks (wiretapping and those big antenna farms).
+Active attacks, which involve the intruder sending packets to your
+system (like packets that break into sendmail and give them a root
+shell :-) are much harder to guard against. Active attacks that
+involve sending people (breaking into your house and replacing parts
+of your computer with ones that transmit what you're doing) are also
+much harder to guard against. Though we are putting effort into
+protecting against active attacks, it's a much bigger job than merely
+providing strong encryption. It involves general computer security,
+and general physical security, which are two very expensive problems
+for even a site to solve, let alone to build into a whole society.
+
+The societal benefit of building an infrastructure that protects
+well against passive attacks is that it makes it much harder to do
+undetected bulk monitoring of the population. It's a defense against
+police-states, not against policemen.
+
+Policemen can put in the effort required to actively attack sites that
+they have strong suspicions about. But police states won't be able to
+build systems that automatically monitor everyone's communications.
+Either they will be able to monitor only a small subset of the
+populace (by targeting those who screwed up their passive security),
+or their monitoring activities will be detectable by those monitored
+(active attacks leave packet traces or footprints), which can then be
+addressed through the press and through political means if they become
+too widespread.
+
+FreeS/WAN does not protect very well against traffic analysis, which
+is a kind of widespread police-state style monitoring that still
+reveals significant information (who's talking to who) without
+revealing the contents of what was said. Defenses against traffic
+analysis are an open research problem. Zero Knowledge Systems is
+actively deploying a system designed to thwart it, designed by Ian
+Goldberg. The jury is out on whether it actually works; a lot more
+experience with it will be needed.</pre>
+
+<p>Notes on things mentioned in that message:</p>
+<ul>
+ <li>Denker is a co-author of a <a href="intro.html#applied">paper</a> on a
+ large FreeS/WAN application.</li>
+ <li>Information on Zero Knowledge is on their <a
+ href="http://www.zks.net/">web site</a>. Their Freedom product, designed
+ to provide untracable pseudonyms for use on the net, is no longer
+ marketed.</li>
+ <li>Another section of our documentation discusses ways to <a
+ href="ipsec.html#traffic.resist">resist traffic analysis</a>.</li>
+</ul>
+
+<h2><a name="weak">Government promotion of weak crypto</a></h2>
+
+<p>Various groups, especially governments and especially the US government,
+have a long history of advocating various forms of bogus security.</p>
+
+<p>We regard bogus security as extremely dangerous. If users are deceived
+into relying on bogus security, then they may be exposed to large risks. They
+would be better off having no security and knowing it. At least then they
+would be careful about what they said.</p>
+
+<p><strong>Avoiding bogus security is a key design criterion for everything
+we do in FreeS/WAN</strong>. The most conspicuous example is our refusal to
+support <a href="#desnotsecure">single DES</a>. Other IPsec "features" which
+we do not implement are discussed in our <a
+href="compat.html#dropped">compatibility</a> document.</p>
+
+<h3><a name="escrow">Escrowed encryption</a></h3>
+
+<p>Various governments have made persistent attempts to encourage or mandate
+"escrowed encrytion", also called "key recovery", or GAK for "government
+access to keys". The idea is that cryptographic keys be held by some third
+party and turned over to law enforcement or security agencies under some
+conditions.</p>
+<pre> Mary had a little key - she kept it in escrow,
+ and every thing that Mary said,
+ the feds were sure to know.</pre>
+
+<p>A <a href="web.html#quotes">crypto quotes</a> page attributes this to <a
+href="http://www.scramdisk.clara.net/">Sam Simpson</a>.</p>
+
+<p>There is an excellent paper available on <a
+href="http://www.cdt.org/crypto/risks98/">Risks of Escrowed Encryption</a>,
+from a group of cryptographic luminaries which included our project
+leader.</p>
+
+<p>Like any unnecessary complication, GAK tends to weaken security of any
+design it infects. For example:</p>
+<ul>
+ <li>Matt Blaze found a fatal flaw in the US government's Clipper chip
+ shortly after design information became public. See his paper "Protocol
+ Failure in the Escrowed Encryption Standard" on his <a
+ href="http://www.crypto.com/papers/">papers</a> page.</li>
+ <li>a rather <a href="http://www.pgp.com/other/advisories/adk.asp">nasty
+ bug</a> was found in the "additional decryption keys" "feature" of some
+ releases of <a href="glossary.html#PGP">PGP</a></li>
+</ul>
+
+<p>FreeS/WAN does not support escrowed encryption, and never will.</p>
+
+<h3><a name="shortkeys">Limited key lengths</a></h3>
+
+<p>Various governments, and some vendors, have also made persistent attempts
+to convince people that:</p>
+<ul>
+ <li>weak systems are sufficient for some data</li>
+ <li>strong cryptography should be reserved for cases where the extra
+ overheads are justified</li>
+</ul>
+
+<p><strong>This is utter nonsense</strong>.</p>
+
+<p>Weak systems touted include:</p>
+<ul>
+ <li>the ludicrously weak (deliberately crippled) 40-bit ciphers that until
+ recently were all various <a href="#exlaw">export laws</a> allowed</li>
+ <li>56-bit single DES, discussed <a href="#desnotsecure">below</a></li>
+ <li>64-bit symmetric ciphers and 512-bit RSA, the maximums for unrestricted
+ export under various current laws</li>
+</ul>
+
+<p>The notion that choice of ciphers or keysize should be determined by a
+trade-off between security requirements and overheads is pure bafflegab.</p>
+<ul>
+ <li>For most <a href="glossary.html#symmetric">symmetric ciphers</a>, it is
+ simply a lie. Any block cipher has some natural maximum keysize inherent
+ in the design -- 128 bits for <a href="glossary.html#IDEA">IDEA</a> or <a
+ href="glossary.html#CAST128">CAST-128</a>, 256 for Serpent or Twofish,
+ 448 for <a href="glossary.html#Blowfish">Blowfish</a> and 2048 for <a
+ href="glossary.html#RC4">RC4</a>. Using a key size smaller than that
+ limit gives <em>exactly zero </em>savings in overhead. The crippled
+ 40-bit or 64-bit version of the cipher provides <em>no advantage
+ whatsoever</em>.</li>
+ <li><a href="glossary.html#AES">AES</a> uses 10 rounds with 128-bit keys,
+ 12 rounds for 192-bit and 14 rounds for 256-bit, so there actually is a
+ small difference in overhead, but not enough to matter in most
+ applications.</li>
+ <li>For <a href="glossary.html#3DES">triple DES</a> there is a grain of
+ truth in the argument. 3DES is indeed three times slower than single DES.
+ However, the solution is not to use the insecure single DES, but to pick
+ a faster secure cipher. <a href="glossary.html#CAST128">CAST-128</a>, <a
+ href="glossary.html#Blowfish">Blowfish</a> and the <a
+ href="glossary.html#AES">AES candidate</a> ciphers are are all
+ considerably faster in software than DES (let alone 3DES!), and
+ apparently secure.</li>
+ <li>For <a href="glossary.html#public">public key</a> techniques, there are
+ extra overheads for larger keys, but they generally do not affect overall
+ performance significantly. Practical public key applications are usually
+ <a href="glossary.html#hybrid">hybrid</a> systems in which the bulk of
+ the work is done by a symmetric cipher. The effect of increasing the cost
+ of the public key operations is typically negligible because the public
+ key operations use only a tiny fraction of total resources.
+ <p>For example, suppose public key operations use use 1% of the time in a
+ hybrid system and you triple the cost of public key operations. The cost
+ of symmetric cipher operations is unchanged at 99% of the original total
+ cost, so the overall effect is a jump from 99 + 1 = 100 to 99 + 3 = 102,
+ a 2% rise in system cost.</p>
+ </li>
+</ul>
+
+<p>In short, <strong>there has never been any technical reason to use
+inadequate ciphers</strong>. The only reason there has ever been for anyone
+to use such ciphers is that government agencies want weak ciphers used so
+that they can crack them. The alleged savings are simply propaganda.</p>
+<pre> Mary had a little key (It's all she could export),
+ and all the email that she sent was opened at the Fort.</pre>
+
+<p>A <a href="web.html#quotes">crypto quotes</a> page attributes this to <a
+href="http://theory.lcs.mit.edu:80/~rivest/">Ron Rivest</a>. NSA headquarters
+is at Fort Meade, Maryland.</p>
+
+<p>Our policy in FreeS/WAN is to use only cryptographic components with
+adequate keylength and no known weaknesses.</p>
+<ul>
+ <li>We do not implement single DES because it is clearly <a
+ href="#desnotsecure">insecure</a>, so implemeting it would violate our
+ policy of avoiding bogus security. Our default cipher is <a
+ href="glossary.html#3DES">3DES</a></li>
+ <li>Similarly, we do not implement the 768-bit Group 1 for <a
+ href="glossary.html#DH">Diffie-Hellman</a> key negotiation. We provide
+ only the 1024-bit Group 2 and 1536-bit Group 5.</li>
+</ul>
+
+<p>Detailed discussion of which IPsec features we implement or omit is in out
+<a href="compat.html">compatibility document</a>.</p>
+
+<p>These decisions imply that we cannot fully conform to the IPsec RFCs,
+since those have DES as the only required cipher and Group 1 as the only
+required DH group. (In our view, the standards were subverted into offerring
+bogus security.) Fortunately, we can still interoperate with most other IPsec
+implementations since nearly all implementers provide at least 3DES and Group
+2 as well.</p>
+
+<p>We hope that eventually the RFCs will catch up with our (and others')
+current practice and reject dubious components. Some of our team and a number
+of others are working on this in <a href="glossary.html#IETF">IETF</a>
+working groups.</p>
+
+<h4>Some real trade-offs</h4>
+
+<p>Of course, making systems secure does involve costs, and trade-offs can be
+made between cost and security. However, the real trade-offs have nothing to
+do with using weaker ciphers.</p>
+
+<p>There can be substantial hardware and software costs. There are often
+substantial training costs, both to train administrators and to increase user
+awareness of security issues and procedures. There are almost always
+substantial staff or contracting costs.</p>
+
+<p>Security takes staff time for planning, implementation, testing and
+auditing. Some of the issues are subtle; you need good (hence often
+expensive) people for this. You also need people to monitor your systems and
+respond to problems. The best safe ever built is insecure if an attacker can
+work on it for days without anyone noticing. Any computer is insecure if the
+administrator is "too busy" to check the logs.</p>
+
+<p>Moreover, someone in your organisation (or on contract to it) needs to
+spend considerable time keeping up with new developments. EvilDoers
+<em>will</em> know about new attacks shortly after they are found. You need
+to know about them before your systems are attacked. If your vendor provides
+a patch, you need to apply it. If the vendor does nothing, you need to
+complain or start looking for another vendor.</p>
+
+<p>For a fairly awful example, see this <a
+href="http://www.sans.org/newlook/alerts/NTE-bank.htm">report</a>. In that
+case over a million credit card numbers were taken from e-commerce sites,
+using security flaws in Windows NT servers. Microsoft had long since released
+patches for most or all of the flaws, but the site administrators had not
+applied them.</p>
+
+<p>At an absolute minimum, you must do something about such issues
+<em>before</em> an exploitation tool is posted to the net for downloading by
+dozens of "script kiddies". Such a tool might appear at any time from the
+announcement of the security hole to several months later. Once it appears,
+anyone with a browser and an attitude can break any system whose
+administrators have done nothing about the flaw.</p>
+
+<p>Compared to those costs, cipher overheads are an insignificant factor in
+the cost of security.</p>
+
+<p>The only thing using a weak cipher can do for you is to cause all your
+other investment to be wasted.</p>
+
+<h2><a name="exlaw">Cryptography Export Laws</a></h2>
+
+<p>Many nations restrict the export of cryptography and some restrict its use
+by their citizens or others within their borders.</p>
+
+<h3><a name="USlaw">US Law</a></h3>
+
+<p>US laws, as currently interpreted by the US government, forbid export of
+most cryptographic software from the US in machine-readable form without
+government permission. In general, the restrictions apply even if the
+software is widely-disseminated or public-domain and even if it came from
+outside the US originally. Cryptography is legally a munition and export is
+tightly controlled under the <a href="glossary.html#EAR">EAR</a> Export
+Administration Regulations.</p>
+
+<p>If you are a US citizen, your brain is considered US territory no matter
+where it is physically located at the moment. The US believes that its laws
+apply to its citizens everywhere, not just within the US. Providing technical
+assistance or advice to foreign "munitions" projects is illegal. The US
+government has very little sense of humor about this issue and does not
+consider good intentions to be sufficient excuse. Beware.</p>
+
+<p>The <a href="http://www.bxa.doc.gov/Encryption/">official website</a> for
+these regulations is run by the Commerce Department's Bureau of Export
+Administration (BXA).</p>
+
+<p>The <a href="http://www.eff.org/bernstein/">Bernstein case</a> challenges
+the export restrictions on Constitutional grounds. Code is speech so
+restrictions on export of code violate the First Amendment's free speech
+provisions. This argument has succeeded in two levels of court so far. It is
+quite likely to go on to the Supreme Court.</p>
+
+<p>The regulations were changed substantially in January 2000, apparently as
+a government attempt to get off the hook in the Bernstein case. It is now
+legal to export public domain source code for encryption, provided you notify
+the <a href="glossary.html#BXA">BXA</a>.</p>
+
+<p>There are, however, still restrictions in force.
+ Moreover, the regulations can still be changed again whenever the government
+chooses to do so. Short of a Supreme Court ruling (in the Berstein case or
+another) that overturns the regulations completely, the problem of export
+regulation is not likely to go away in the forseeable future.</p>
+
+<h4><a name="UScontrib">US contributions to FreeS/WAN</a></h4>
+
+<p>The FreeS/WAN project <strong>cannot accept software contributions, <em>
+not even small bug fixes</em>, from US citizens or residents</strong>. We
+want it to be absolutely clear that our distribution is not subject to US
+export law. Any contribution from an American might open that question to a
+debate we'd prefer to avoid. It might also put the contributor at serious
+legal risk.</p>
+
+<p>Of course Americans can still make valuable contributions (many already
+have) by reporting bugs, or otherwise contributing to discussions, on the
+project <a href="mail.html">mailing list</a>. Since the list is public, this
+is clearly constitutionally protected free speech.</p>
+
+<p>Note, however, that the export laws restrict Americans from providing
+technical assistance to foreign "munitions" projects. The government might
+claim that private discussions or correspondence with FreeS/WAN developers
+were covered by this. It is not clear what the courts would do with such a
+claim, so we strongly encourage Americans to use the list rather than risk
+the complications.</p>
+
+<h3><a name="wrong">What's wrong with restrictions on cryptography</a></h3>
+
+<p>Some quotes from prominent cryptography experts:</p>
+
+<blockquote>
+ The real aim of current policy is to ensure the continued effectiveness of
+ US information warfare assets against individuals, businesses and
+ governments in Europe and elsewhere.<br>
+ <a href="http://www.cl.cam.ac.uk/users/rja14"> Ross Anderson, Cambridge
+ University</a></blockquote>
+
+<blockquote>
+ If the government were honest about its motives, then the debate about
+ crypto export policy would have ended years ago.<br>
+ <a href="http://www.counterpane.com"> Bruce Schneier, Counterpane
+ Systems</a></blockquote>
+
+<blockquote>
+ The NSA regularly lies to people who ask it for advice on export control.
+ They have no reason not to; accomplishing their goal by any legal means is
+ fine by them. Lying by government employees is legal.<br>
+ John Gilmore.</blockquote>
+
+<p>The Internet Architecture Board (IAB) and the Internet Engineering
+Steering Group (IESG) made a <a href="iab-iesg.stmt">strong statement</a> in
+favour of worldwide access to strong cryptography. Essentially the same
+statement is in the appropriately numbered <a
+href="ftp://ftp.isi.edu/in-notes/rfc1984.txt">RFC 1984</a>. Two critical
+paragraphs are:</p>
+
+<blockquote>
+ ... various governments have actual or proposed policies on access to
+ cryptographic technology ...
+
+ <p>(a) ... export controls ...<br>
+ (b) ... short cryptographic keys ...<br>
+ (c) ... keys should be in the hands of the government or ...<br>
+ (d) prohibit the use of cryptology ...</p>
+
+ <p>We believe that such policies are against the interests of consumers and
+ the business community, are largely irrelevant to issues of military
+ security, and provide only a marginal or illusory benefit to law
+ enforcement agencies, ...</p>
+
+ <p>The IAB and IESG would like to encourage policies that allow ready
+ access to uniform strong cryptographic technology for all Internet users in
+ all countries.</p>
+</blockquote>
+
+<p>Our goal in the FreeS/WAN project is to build just such "strong
+cryptographic technology" and to distribute it "for all Internet users in all
+countries".</p>
+
+<p>More recently, the same two bodies (IESG and IAB) have issued <a
+href="ftp://ftp.isi.edu/in-notes/rfc2804.txt">RFC 2804</a> on why the IETF
+should not build wiretapping capabilities into protocols for the convenience
+of security or law enforcement agenicies. The abstract from that document
+is:</p>
+
+<blockquote>
+ The Internet Engineering Task Force (IETF) has been asked to take a
+ position on the inclusion into IETF standards-track documents of
+ functionality designed to facilitate wiretapping.
+
+ <p>This memo explains what the IETF thinks the question means, why its
+ answer is "no", and what that answer means.</p>
+</blockquote>
+A quote from the debate leading up to that RFC:
+
+<blockquote>
+ We should not be building surveillance technology into standards. Law
+ enforcement was not supposed to be easy. Where it is easy, it's called a
+ police state.<br>
+ Jeff Schiller of MIT, in a discussion of FBI demands for wiretap capability
+ on the net, as quoted by <a
+ href="http://www.wired.com/news/politics/0,1283,31895,00.html">Wired</a>.</blockquote>
+
+<p>The <a href="http://www.ietf.org/mailman/listinfo/raven">Raven</a> mailing
+list was set up for this IETF discussion.</p>
+
+<p>Our goal is to go beyond that RFC and prevent Internet wiretapping
+entirely.</p>
+
+<h3><a name="Wassenaar">The Wassenaar Arrangement</a></h3>
+
+<p>Restrictions on the export of cryptography are not just US policy, though
+some consider the US at least partly to blame for the policies of other
+nations in this area.</p>
+
+<p>A number of countries:</p>
+
+<p>Argentina, Australia, Austria, Belgium, Bulgaria, Canada, Czech Republic,
+Denmark, Finland, France, Germany, Greece, Hungary, Ireland, Italy, Japan,
+Luxembourg, Netherlands, New Zealand, Norway, Poland, Portugal, Republic of
+Korea, Romania, Russian Federation, Slovak Republic, Spain, Sweden,
+Switzerland, Turkey, Ukraine, United Kingdom and United States</p>
+
+<p>have signed the Wassenaar Arrangement which restricts export of munitions
+and other tools of war. Cryptographic sofware is covered there.</p>
+
+<p>Wassenaar details are available from the <a
+href="http://www.wassenaar.org/"> Wassenaar Secretariat</a>, and elsewhere in
+a more readable <a href="http://www.fitug.de/news/wa/index.html"> HTML
+version</a>.</p>
+
+<p>For a critique see the <a href="http://www.gilc.org/crypto/wassenaar">
+GILC site</a>:</p>
+
+<blockquote>
+ The Global Internet Liberty Campaign (GILC) has begun a campaign calling
+ for the removal of cryptography controls from the Wassenaar Arrangement.
+
+ <p>The aim of the Wassenaar Arrangement is to prevent the build up of
+ military capabilities that threaten regional and international security and
+ stability . . .</p>
+
+ <p>There is no sound basis within the Wassenaar Arrangement for the
+ continuation of any export controls on cryptographic products.</p>
+</blockquote>
+
+<p>We agree entirely.</p>
+
+<p>An interesting analysis of Wassenaar can be found on the <a
+href="http://www.cyber-rights.org/crypto/wassenaar.htm">cyber-rights.org</a>
+site.</p>
+
+<h3><a name="status">Export status of Linux FreeS/WAN</a></h3>
+
+<p>We believe our software is entirely exempt from these controls since the
+Wassenaar <a
+href="http://www.wassenaar.org/list/GTN%20and%20GSN%20-%2099.pdf">General
+Software Note</a> says:</p>
+
+<blockquote>
+ The Lists do not control "software" which is either:
+ <ol>
+ <li>Generally available to the public by . . . retail . . . or</li>
+ <li>"In the public domain".</li>
+ </ol>
+</blockquote>
+
+<p>There is a note restricting some of this, but it is a sub-heading under
+point 1, so it appears not to apply to public domain software.</p>
+
+<p>Their glossary defines "In the public domain" as:</p>
+
+<blockquote>
+ . . . "technology" or "software" which has been made available without
+ restrictions upon its further dissemination.
+
+ <p>N.B. Copyright restrictions do not remove "technology" or "software"
+ from being "in the public domain".</p>
+</blockquote>
+
+<p>We therefore believe that software freely distributed under the <a
+href="glossary.html#GPL">GNU Public License</a>, such as Linux FreeS/WAN, is
+exempt from Wassenaar restrictions.</p>
+
+<p>Most of the development work is being done in Canada. Our understanding is
+that the Canadian government accepts this interpretation.</p>
+<ul>
+ <li>A web statement of <a
+ href="http://www.dfait-maeci.gc.ca/~eicb/notices/ser113-e.htm"> Canadian
+ policy</a> is available from the Department of Foreign Affairs and
+ International Trade.</li>
+ <li>Another document from that department states that <a
+ href="http://www.dfait-maeci.gc.ca/~eicb/export/gr1_e.htm">public domain
+ software</a> is exempt from the export controls.</li>
+ <li>A researcher's <a
+ href="http://insight.mcmaster.ca/org/efc/pages/doc/crypto-export.html">analysis</a>
+ of Canadian policy is also available.</li>
+</ul>
+
+<p>Recent copies of the freely modifiable and distributable source code exist
+in many countries. Citizens all over the world participate in its use and
+evolution, and guard its ongoing distribution. Even if Canadian policy were
+to change, the software would continue to evolve in countries which do not
+restrict exports, and would continue to be imported from there into unfree
+countries. "The Net culture treats censorship as damage, and routes around
+it."</p>
+
+<h3><a name="help">Help spread IPsec around</a></h3>
+
+<p>You can help. If you don't know of a Linux FreeS/WAN archive in your own
+country, please download it now to your personal machine, and consider making
+it publicly accessible if that doesn't violate your own laws. If you have the
+resources, consider going one step further and setting up a mirror site for
+the whole <a href="intro.html#munitions">munitions</a> Linux crypto software
+archive.</p>
+
+<p>If you make Linux CD-ROMs, please consider including this code, in a way
+that violates no laws (in a free country, or in a domestic-only CD
+product).</p>
+
+<p>Please send a note about any new archive mirror sites or CD distributions
+to linux-ipsec@clinet.fi so we can update the documentation.</p>
+
+<p>Lists of current <a href="intro.html#sites">mirror sites</a> and of <a
+href="intro.html#distwith">distributions</a> which include FreeS/WAN are in
+our introduction section.</p>
+
+<h2><a name="desnotsecure">DES is Not Secure</a></h2>
+
+<p>DES, the <strong>D</strong>ata <strong>E</strong>ncryption
+<strong>S</strong>tandard, can no longer be considered secure. While no major
+flaws in its innards are known, it is fundamentally inadequate because its
+<strong>56-bit key is too short</strong>. It is vulnerable to <a
+href="glossary.html#brute">brute-force search</a> of the whole key space,
+either by large collections of general-purpose machines or even more quickly
+by specialized hardware. Of course this also applies to <strong>any other
+cipher with only a 56-bit key</strong>. The only reason anyone could have for
+using a 56 or 64-bit key is to comply with various <a
+href="exportlaw.html">export laws</a> intended to ensure the use of breakable
+ciphers.</p>
+
+<p>Non-government cryptologists have been saying DES's 56-bit key was too
+short for some time -- some of them were saying it in the 70's when DES
+became a standard -- but the US government has consistently ridiculed such
+suggestions.</p>
+
+<p>A group of well-known cryptographers looked at key lengths in a <a
+href="http://www.counterpane.com/keylength.html"> 1996 paper</a>. They
+suggested a <em>minimum</em> of 75 bits to consider an existing cipher secure
+and a <em>minimum of 90 bits for new ciphers</em>. More recent papers,
+covering both <a href="glossary.html#symmetric">symmetric</a> and <a
+href="glossary.html#public">public key</a> systems are at <a
+href="http://www.cryptosavvy.com/">cryptosavvy.com</a> and <a
+href="http://www.rsasecurity.com/rsalabs/bulletins/bulletin13.html">rsa.com</a>.
+For all algorithms, the minimum keylengths recommended in such papers are
+significantly longer than the maximums allowed by various export laws.</p>
+
+<p>In a <a
+href="http://www.privacy.nb.ca/cryptography/archives/cryptography/html/1998-09/0095.html">1998
+ruling</a>, a German court described DES as "out-of-date and not safe enough"
+and held a bank liable for using it.</p>
+
+<h3><a name="deshware">Dedicated hardware breaks DES in a few days</a></h3>
+
+<p>The question of DES security has now been settled once and for all. In
+early 1998, the <a href="http://www.eff.org/">Electronic Frontier
+Foundation</a> built a <a
+href="http://www.eff.org/descracker.html">DES-cracking machine</a>. It can
+find a DES key in an average of a few days' search. The details of all this,
+including complete code listings and complete plans for the machine, have
+been published in <a href="biblio.html#EFF"><cite>Cracking DES</cite></a>, by
+the Electronic Frontier Foundation.</p>
+
+<p>That machine cost just over $200,000 to design and build. "Moore's Law" is
+that machines get faster (or cheaper, for the same speed) by roughly a factor
+of two every 18 months. At that rate, their $200,000 in 1998 becomes $50,000
+in 2001.</p>
+
+<p>However, Moore's Law is not exact and the $50,000 estimate does not allow
+for the fact that a copy based on the published EFF design would cost far
+less than the original. We cannot say exactly what such a cracker would cost
+today, but it would likely be somewhere between $10,000 and $100,000.</p>
+
+<p>A large corporation could build one of these out of petty cash. The cost
+is low enough for a senior manager to hide it in a departmental budget and
+avoid having to announce or justify the project. Any government agency, from
+a major municipal police force up, could afford one. Or any other group with
+a respectable budget -- criminal organisations, political groups, labour
+unions, religious groups, ... Or any millionaire with an obsession or a
+grudge, or just strange taste in toys.</p>
+
+<p>One might wonder if a private security or detective agency would have one
+for rent. They wouldn't need many clients to pay off that investment.</p>
+
+<h3><a name="spooks">Spooks may break DES faster yet</a></h3>
+
+<p>As for the security and intelligence agencies of various nations, they may
+have had DES crackers for years, and theirs may be much faster. It is
+difficult to make most computer applications work well on parallel machines,
+or to design specialised hardware to accelerate them. Cipher-cracking is one
+of the very few exceptions. It is entirely straightforward to speed up
+cracking by just adding hardware. Within very broad limits, you can make it
+as fast as you like if you have the budget. The EFF's $200,000 machine breaks
+DES in a few days. An <a href="http://www.planepage.com/">aviation
+website</a> gives the cost of a B1 bomber as $200,000,000. Spending that
+much, an intelligence agency could break DES in an average time of <em>six
+and a half minutes</em>.</p>
+
+<p>That estimate assumes they use the EFF's 1998 technology and just spend
+more money. They may have an attack that is superior to brute force, they
+quite likely have better chip technology (Moore's law, a bigger budget, and
+whatever secret advances they may have made) and of course they may have
+spent the price of an aircraft carrier, not just one aircraft.</p>
+
+<p>In short, we have <em>no idea</em> how quickly these organisations can
+break DES. Unless they're spectacularly incompetent or horribly underfunded,
+they can certainly break it, but we cannot guess how quickly. Pick any time
+unit between days and milliseconds; none is entirely unbelievable. More to
+the point, none of them is of any comfort if you don't want such
+organisations reading your communications.</p>
+
+<p>Note that this may be a concern even if nothing you do is a threat to
+anyone's national security. An intelligence agency might well consider it to
+be in their national interest for certain companies to do well. If you're
+competing against such companies in a world market and that agency can read
+your secrets, you have a serious problem.</p>
+
+<p>One might wonder about technology the former Soviet Union and its allies
+developed for cracking DES during the Cold War. They must have tried; the
+cipher was an American standard and widely used. Certainly those countries
+have some fine mathematicians, and those agencies had budget. How well did
+they succeed? Is their technology now for sale or rent?</p>
+
+<h3><a name="desnet">Networks break DES in a few weeks</a></h3>
+
+<p>Before the definitive EFF effort, DES had been cracked several times by
+people using many machines. See this <a
+href="http://www.distributed.net/pressroom/DESII-1-PR.html"> press
+release</a> for example.</p>
+
+<p>A major corporation, university, or government department could break DES
+by using spare cycles on their existing collection of computers, by
+dedicating a group of otherwise surplus machines to the problem, or by
+combining the two approaches. It might take them weeks or months, rather than
+the days required for the EFF machine, but they could do it.</p>
+
+<p>What about someone working alone, without the resources of a large
+organisation? For them, cracking DES will not be easy, but it may be
+possible. A few thousand dollars buys a lot of surplus workstations. A pile
+of such machines will certainly heat your garage nicely and might break DES
+in a few months or years. Or enroll at a university and use their machines.
+Or use an employer's machines. Or crack security somewhere and steal the
+resources to crack a DES key. Or write a virus that steals small amounts of
+resources on many machines. Or . . .</p>
+
+<p>None of these approaches are easy or break DES really quickly, but an
+attacker only needs to find one that is feasible and breaks DES quickly
+enough to be dangerous. How much would you care to bet that this will be
+impossible if the attacker is clever and determined? How valuable is your
+data? Are you authorised to risk it on a dubious bet?</p>
+
+<h3><a name="no_des">We disable DES</a></h3>
+
+<p>In short, it is now absolutely clear that <strong>DES is not
+secure</strong> against</p>
+<ul>
+ <li>any <strong>well-funded opponent</strong></li>
+ <li>any opponent (even a penniless one) with access (even stolen access) to
+ <strong>enough general purpose computers</strong></li>
+</ul>
+
+<p>That is why <strong>Linux FreeS/WAN disables all transforms which use
+plain DES</strong> for encryption.</p>
+
+<p>DES is in the source code, because we need DES to implement our default
+encryption transform, <a href="glossary.html#3DES">Triple DES</a>. <strong>We
+urge you not to use single DES</strong>. We do not provide any easy way to
+enable it in FreeS/WAN, and our policy is to provide no assistance to anyone
+wanting to do so.</p>
+
+<h3><a name="40joke">40-bits is laughably weak</a></h3>
+
+<p>The same is true, in spades, of ciphers -- DES or others -- crippled by
+40-bit keys, as many ciphers were required to be until recently under various
+<a href="#exlaw">export laws</a>. A brute force search of such a cipher's
+keyspace is 2<sup>16</sup> times faster than a similar search against DES.
+The EFF's machine can do a brute-force search of a 40-bit key space in
+<em>seconds</em>. One contest to crack a 40-bit cipher was won by a student
+<a href="http://catless.ncl.ac.uk/Risks/18.80.html#subj1"> using a few
+hundred idle machines at his university</a>. It took only three and half
+hours.</p>
+
+<p>We do not, and will not, implement any 40-bit cipher.</p>
+
+<h3><a name="altdes">Triple DES is almost certainly secure</a></h3>
+
+<p><a href="glossary.html#3DES">Triple DES</a>, usually abbreviated 3DES,
+applies DES three times, with three different keys. DES seems to be basically
+an excellent cipher design; it has withstood several decades of intensive
+analysis without any disastrous flaws being found. It's only major flaw is
+that the small keyspace allows brute force attacks to succeeed. Triple DES
+enlarges the key space to 168 bits, making brute-force search a ridiculous
+impossibility.</p>
+
+<p>3DES is currently the only block cipher implemented in FreeS/WAN. 3DES is,
+unfortunately, about 1/3 the speed of DES, but modern CPUs still do it at
+quite respectable speeds. Some <a href="glossary.html#benchmarks">speed
+measurements</a> for our code are available.</p>
+
+<h3><a name="aes.ipsec">AES in IPsec</a></h3>
+
+<p>The <a href="glossary.html#AES">AES</a> project has chosen a replacement
+for DES, a new standard cipher for use in non-classified US government work
+and in regulated industries such as banking. This cipher will almost
+certainly become widely used for many applications, including IPsec.</p>
+
+<p>The winner, announced in October 2000 after several years of analysis and
+discussion, was the <a
+href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">Rijndael</a> cipher
+from two Belgian designers.</p>
+
+<p>It is almost certain that FreeS/WAN will add AES support. <a
+href="web.html#patch">AES patches</a> are already available.</p>
+
+<h2><a name="press">Press coverage of Linux FreeS/WAN:</a></h2>
+
+<h3>FreeS/WAN 1.0 press</h3>
+<ul>
+ <li><a
+ href="http://www.wired.com/news/news/technology/story/19136.html">Wired</a>
+ "Linux-Based Crypto Stops Snoops", James Glave April 15 1999</li>
+ <li><a
+ href="http://slashdot.org/articles/99/04/15/1851212.shtml">Slashdot</a></li>
+ <li><a href="http://dgl.com/itinfo/1999/it990415.html">DGL</a>, Damar Group
+ Limited; looking at FreeS/WAN from a perspective of business
+ computing</li>
+ <li><a href="http://linuxtoday.com/stories/5010.html">Linux Today</a></li>
+ <li><a href="http://www.tbtf.com/archive/1999-04-21.html#Tcep">TBTF</a>,
+ Tasty Bits from the Technology Front</li>
+ <li><a
+ href="http://www.salonmagazine.com/tech/log/1999/04/16/encryption/index.html">Salon
+ Magazine</a> "Free Encryption Takes a Big Step"</li>
+</ul>
+
+<h3><a name="release">Press release for version 1.0</a></h3>
+<pre> Strong Internet Privacy Software Free for Linux Users Worldwide
+
+Toronto, ON, April 14, 1999 -
+
+The Linux FreeS/WAN project today released free software to protect
+the privacy of Internet communications using strong encryption codes.
+FreeS/WAN automatically encrypts data as it crosses the Internet, to
+prevent unauthorized people from receiving or modifying it. One
+ordinary PC per site runs this free software under Linux to become a
+secure gateway in a Virtual Private Network, without having to modify
+users' operating systems or application software. The project built
+and released the software outside the United States, avoiding US
+government regulations which prohibit good privacy protection.
+FreeS/WAN version 1.0 is available immediately for downloading at
+http://www.xs4all.nl/~freeswan/.
+
+"Today's FreeS/WAN release allows network administrators to build
+excellent secure gateways out of old PCs at no cost, or using a cheap
+new PC," said John Gilmore, the entrepreneur who instigated the
+project in 1996. "They can build operational experience with strong
+network encryption and protect their users' most important
+communications worldwide."
+
+"The software was written outside the United States, and we do not
+accept contributions from US citizens or residents, so that it can be
+freely published for use in every country," said Henry Spencer, who
+built the release in Toronto, Canada. "Similar products based in the
+US require hard-to-get government export licenses before they can be
+provided to non-US users, and can never be simply published on a Web
+site. Our product is freely available worldwide for immediate
+downloading, at no cost."
+
+FreeS/WAN provides privacy against both quiet eavesdropping (such as
+"packet sniffing") and active attempts to compromise communications
+(such as impersonating participating computers). Secure "tunnels" carry
+information safely across the Internet between locations such as a
+company's main office, distant sales offices, and roaming laptops. This
+protects the privacy and integrity of all information sent among those
+locations, including sensitive intra-company email, financial transactions
+such as mergers and acquisitions, business negotiations, personal medical
+records, privileged correspondence with lawyers, and information about
+crimes or civil rights violations. The software will be particularly
+useful to frequent wiretapping targets such as private companies competing
+with government-owned companies, civil rights groups and lawyers,
+opposition political parties, and dissidents.
+
+FreeS/WAN provides privacy for Internet packets using the proposed
+standard Internet Protocol Security (IPSEC) protocols. FreeS/WAN
+negotiates strong keys using Diffie-Hellman key agreement with 1024-bit
+keys, and encrypts each packet with 168-bit Triple-DES (3DES). A modern
+$500 PC can set up a tunnel in less than a second, and can encrypt
+6 megabits of packets per second, easily handling the whole available
+bandwidth at the vast majority of Internet sites. In preliminary testing,
+FreeS/WAN interoperated with 3DES IPSEC products from OpenBSD, PGP, SSH,
+Cisco, Raptor, and Xedia. Since FreeS/WAN is distributed as source code,
+its innards are open to review by outside experts and sophisticated users,
+reducing the chance of undetected bugs or hidden security compromises.
+
+The software has been in development for several years. It has been
+funded by several philanthropists interested in increased privacy on
+the Internet, including John Gilmore, co-founder of the Electronic
+Frontier Foundation, a leading online civil rights group.
+
+Press contacts:
+Hugh Daniel, +1 408 353 8124, hugh@toad.com
+Henry Spencer, +1 416 690 6561, henry@spsystems.net
+
+* FreeS/WAN derives its name from S/WAN, which is a trademark of RSA Data
+ Security, Inc; used by permission.</pre>
+</body>
+</html>
diff --git a/doc/src/quickstart-configs.html b/doc/src/quickstart-configs.html
new file mode 100644
index 000000000..b2ad21bcc
--- /dev/null
+++ b/doc/src/quickstart-configs.html
@@ -0,0 +1,144 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>Quick FreeS/WAN installation and configuration</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, installation, quickstart">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Revised by Claudia Schmeing for same
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ This is a new file derived from:
+ RCS ID: $Id: quickstart-configs.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+<BODY>
+<H1><A name="quick_configs">FreeS/WAN quick start examples</A></H1>
+<P>These are sample
+<A href="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A>
+configuration files for opportunistic encryption, with comments. Much of
+this configuration will be unnecessary with the new defaults proposed
+for FreeS/WAN 2.x.</P>
+<P>Full instructions are in our
+<A href="quickstart.html#quickstart">quickstart guide</A>.
+
+<H2><A name="qc.opp.client">Configuration for Initiate-only Opportunistic Encryption</A></H2>
+<P>The ipsec.conf file for an initiate-only opportunistic setup is:</P>
+<PRE># general IPsec setup
+config setup
+ # Use the default interface
+ interfaces=%defaultroute
+ # Use auto= parameters in conn descriptions to control startup actions.
+ plutoload=%search
+ plutostart=%search
+ uniqueids=yes
+
+# defaults for subsequent connection descriptions
+conn %default
+ # How to authenticate gateways
+ authby=rsasig
+ # default is
+ # load connection description into Pluto's database
+ # so it can respond if another gatway initiates
+ # individual connection descriptions may override this
+ auto=add
+
+# description for opportunistic connections
+conn me-to-anyone
+ left=%defaultroute # all connections should use default route
+ right=%opportunistic # anyone we can authenticate
+ leftrsasigkey=%dnsondemand # NEW: look up keys in DNS as-needed
+ rightrsasigkey=%dnsondemand # (not at connection load time)
+ rekey=no # let unused connections die
+ keylife=1h # short
+ auto=route # set up for opportunistic
+ leftid=@xy.example.com # our identity for IPSec negotiations
+ # must match DNS and ipsec.secrets</PRE>
+
+<P>Normally, you need to do only two things:</P>
+<UL>
+ <LI>edit <VAR>leftid=</VAR></LI>
+ <LI>set <VAR>auto=route</VAR></LI>
+</UL>
+<P>
+ However, some people may need to customize the <VAR>interfaces=</VAR> line
+ in the "config setup" section. All other sections are identical for any
+ standalone machine doing opportunistic encryption.</P>
+<P>The @ sign in the <VAR>leftid=</VAR> makes the ID go "over the wire"
+ as a Fully Qualified Domain Name (FQDN). Without it, an IP address would
+ be used and this won't work.</P>
+<P>The conn is not used to supply either public key. Your private key
+ is in <A href="manpage.d/ipsec.secrets.5.html">ipsec.secrets(5)</A>
+ and, for opportunistic encryption, the public keys for remote gateways
+ are all looked up in DNS.</P>
+<P>FreeS/WAN authenticates opportunistic encryption by <A href="#gen_rsa">RSA
+ signature</A> only, so "public key" and "private key" refer to these keys.</P>
+<P>While the <VAR>left</VAR> and <VAR>right</VAR> designations
+ here are arbitrary, we follow a convention of using <VAR>left</VAR> for
+ local and <VAR>right</VAR> for remote.</P>
+
+<P><A href="quickstart.html#config.opp.client">Continue configuring
+initiate-only opportunism.</A>
+
+<H2><A name="qc.incoming.opp.conf">ipsec.conf for Incoming Opportunistic Encryption</A></H2>
+Use the ipsec.conf above, except that the section describing opportunistic
+connections is now:</P>
+<PRE>
+# description for opportunistic connections
+conn me-to-anyone
+ left=%defaultroute # all connections should use default route
+ right=%opportunistic # anyone we can authenticate
+ leftrsasigkey=%dnsondemand # NEW: look up keys in DNS as-needed
+ rightrsasigkey=%dnsondemand # (not at connection load time)
+ rekey=no # let unused connections die
+ keylife=1h # short
+ auto=route # set up for opportunistic</PRE>
+
+<P>Note that <VAR>leftid=</VAR> has been removed. With no explicit setting,
+<VAR>leftid=</VAR> defaults to the IP of your public interface.</P>
+
+<P><A href="quickstart.html#incoming.opp.conf">Continue configuring
+full opportunism.</A>
+
+
+<H2><A name="qc.gate.opp.conf">ipsec.conf for Opportunistic Gateway</A></H2>
+Use the ipsec.conf above, plus these connections:
+
+<PRE>conn subnet-to-anyone # must be above me-to-anyone
+ also=me-to-anyone
+ leftsubnet=42.42.42.0/24
+
+conn me-to-anyone # just like for full opportunism
+ left=%defaultroute
+ right=%opportunistic
+ leftrsasigkey=%dnsondemand
+ rightrsasigkey=%dnsondemand
+ keylife=1h
+ rekey=no
+ auto=route # be sure this is enabled
+ # Note there is NO leftid= </PRE>
+
+
+<P>Note that a subnet described in ipsec.conf(5) need not correspond to a
+ physical network segment. This is discussed in more detail in our
+<A href="adv_config.html">advanced configuration</A> document.</P>
+
+<P>If required, a gateway can easily provide this service for more than one
+ subnet. You just add a connection description for each.</P>
+
+<P><A href="quickstart.html#config.opp.gate">Continue configuring an
+opportunistic gateway.</A>
+
+
+</BODY>
+</HTML>
+
diff --git a/doc/src/quickstart-firewall.html b/doc/src/quickstart-firewall.html
new file mode 100644
index 000000000..53c27b5af
--- /dev/null
+++ b/doc/src/quickstart-firewall.html
@@ -0,0 +1,187 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>Quick FreeS/WAN installation and configuration</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, installation, quickstart">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Revised by Claudia Schmeing for same
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ RCS ID: $Id: quickstart-firewall.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+<BODY>
+<H1><A name="quick_firewall">FreeS/WAN quick start on firewalling</A></H1>
+<P>This firewalling information supplements our
+<A HREF="quickstart.html#quick_guide">quickstart guide.</A></P>
+<P>It includes tips for firewalling:</P>
+<UL>
+<LI><A HREF="#firewall.standalone">a standalone system with initiator-only
+opportunism</A></LI>
+<LI><A HREF="#incoming.opp.firewall">incoming opportunistic connections</A></LI>
+<LI><A HREF="#opp.gate.firewall">an opportunistic gateway</A></LI>
+</UL>
+<P>and a list of helpful <A HREF="#resources">resources</A>.</P>
+<H2><A name="firewall.standalone">Firewalling a standalone system</A></H2>
+<P>Firewall rules on a standalone system doing IPsec can be very simple.</P>
+<P>The first step is to allow IPsec packets (IKE on UDP port 500 plus
+ ESP, protocol 50) in and out of your gateway. A script to set up
+ iptables(8) rules for this is:</P>
+<PRE># edit this line to match the interface you use as default route
+# ppp0 is correct for many modem, DSL or cable connections
+# but perhaps not for you
+world=ppp0
+#
+# allow IPsec
+#
+# IKE negotiations
+iptables -A INPUT -p udp -i $world --sport 500 --dport 500 -j ACCEPT
+iptables -A OUTPUT -p udp -o $world --sport 500 --dport 500 -j ACCEPT
+# ESP encryption and authentication
+iptables -A INPUT -p 50 -i $world -j ACCEPT
+iptables -A OUTPUT -p 50 -o $world -j ACCEPT</PRE>
+<P>Optionally, you could restrict this, allowing these packets only to
+ and from a list of known gateways.</P>
+<P>A second firewalling step -- access controls built into the IPsec
+ protocols -- is automatically applied:</P>
+<DL>
+<DT><A href="glossary.html#Pluto">Pluto</A> -- the FreeS/WAN keying
+ daemon -- deals with the IKE packets.</DT>
+<DD>Pluto authenticates its partners during the IKE negotiation, and
+ drops negotiation if authentication fails.</DD>
+<DT><A href="glossary.html#KLIPS">KLIPS</A> -- the FreeS/WAN kernel
+ component -- handles the ESP packets.</DT>
+<DD>
+<DL>
+<DT>KLIPS drops outgoing packets</DT>
+<DD>if they are routed to IPsec, but no tunnel has been negotiated for
+ them</DD>
+<DT>KLIPS drops incoming unencrypted packets</DT>
+<DD>if source and destination addresses match a tunnel; the packets
+ should have been encrypted</DD>
+<DT>KLIPS drops incoming encrypted packets</DT>
+<DD>if source and destination address do not match the negotiated
+ parameters of the tunnel that delivers them</DD>
+<DD>if packet-level authentication fails</DD>
+</DL>
+</DD>
+</DL>
+<P>These errors are logged. See our <A href="trouble.html">
+ troubleshooting</A> document for details.</P>
+<P>As an optional third step, you may wish to filter packets emerging from
+ your opportunistic tunnels.
+ These packets arrive on an interface such as <VAR>ipsec0</VAR>, rather than
+ <VAR>eth0</VAR>, <VAR>ppp0</VAR> or whatever. For example, in an iptables(8)
+ rule set, you would use:</P>
+<DL>
+<DT><VAR>-i ipsec+</VAR></DT>
+<DD>to specify packets arriving on any ipsec device</DD>
+<DT><VAR>-o ipsec+</VAR></DT>
+<DD>to specify packets leaving via any ipsec device</DD>
+</DL>
+<P>In this way, you can apply whatever additional filtering you like to these
+packets.</P>
+<P>The packets emerging on <VAR>ipsec0</VAR> are likely
+ to be things that a client application on your machine requested: web
+ pages, e-mail, file transfers and so on. However, any time you initiate
+ an opportunistic connection, you open a two-way connection to
+ another machine (or network). It is conceivable that a Bad Guy there
+ could take advantage of your link.</P>
+<P>For more information, read the next section.</P>
+</P>
+<H2><A name="incoming.opp.firewall">Firewalling incoming opportunistic
+ connections</A></H2>
+<P>The basic firewalling for IPsec does not change when you support
+ incoming connections as well as connections you initiate. You must
+ still allow IKE (UDP port 500) and ESP (protocol 50) packets to and
+ from your machine, as in the rules given <A href="#firewall.standalone">
+ above</A>.</P>
+<P>However, there is an additional security concern when you allow
+ incoming opportunistic connections. Incoming opportunistic packets
+ enter your machine via an IPSec tunnel. That is, they all appear as
+ ESP (protocol 50) packets, concealing whatever port and protocol
+ characteristics the packet within the tunnel has. Contained
+ in the tunnel as they pass through <VAR>ppp0</VAR> or <VAR>eth0</VAR>,
+ these packets can bypass your usual firewall rules on these interfaces.
+<P>Consequently, you will want to firewall your <VAR>ipsec</VAR> interfaces
+ the way you would any publicly accessible interface.</P>
+<P>A simple way to do this is to create one iptables(8) table with
+ all your filtering rules for incoming packets, and apply the entire table to
+ all public interfaces, including <VAR>ipsec</VAR> interfaces.</P>
+
+<H2><A name="opp.gate.firewall">Firewalling for opportunistic gateways</A></H2>
+<P>On a gateway, the IPsec-related firewall rules applied for input and
+ output on the Internet side are exactly as shown
+<A HREF="#firewall.standalone">above</A>. A gateway
+ exchanges exactly the same things -- UDP 500 packets and IPsec packets
+ -- with other gateways that a standalone system does, so it can use
+ exactly the same firewall rules as a standalone system would.</P>
+<P>However, on a gateway there are additional things to do:</P>
+<UL>
+<LI>you have other interfaces and need rules for them</LI>
+<LI>packets emerging from ipsec processing must be correctly forwarded</LI>
+</UL>
+<P>You need additional rules to handle these things. For example, adding
+ some rules to the set shown above we get:</P>
+<PRE># edit this line to match the interface you use as default route
+# ppp0 is correct for many modem, DSL or cable connections
+# but perhaps not for you
+world=ppp0
+#
+# edit these lines to describe your internal subnet and interface
+localnet=42.42.42.0/24
+internal=eth1
+#
+# allow IPsec
+#
+# IKE negotiations
+iptables -A INPUT -p udp -i $world --sport 500 --dport 500 -j ACCEPT
+iptables -A OUTPUT -p udp -o $world --sport 500 --dport 500 -j ACCEPT
+# ESP encryption and authentication
+iptables -A INPUT -p 50 -i $world -j ACCEPT
+iptables -A OUTPUT -p 50 -o $world -j ACCEPT
+#
+# packet forwarding for an IPsec gateway
+# simplest possible rules
+$ forward everything, with no attempt to filter
+#
+# handle packets emerging from IPsec
+# ipsec+ means any of ipsec0, ipsec1, ...
+iptables -A FORWARD -d $localnet -i ipsec+ -j ACCEPT
+# simple rule for outbound packets
+# let local net send anything
+# IPsec will encrypt some of it
+iptables -A FORWARD -s $localnet -i $internal -j ACCEPT </PRE>
+<P>On a production gateway, you would no doubt need tighter rules than
+ the above.</P>
+<H2><A NAME="resources">Firewall resources</A></H2>
+<P>For more information, see these handy resources:</P>
+<UL>
+<LI><A href="http://www.netfilter.org/documentation/">netfilter
+ documentation</A></LI>
+<LI>books such as:
+<UL>
+<LI>Cheswick and Bellovin, <A href="biblio.html#firewall.book">Firewalls
+ and Internet Security</A></LI>
+<LI>Zeigler, <A href="biblio.html#Zeigler">Linux Firewalls</A>,</LI>
+</UL>
+</LI>
+<LI><A href="firewall.html#firewall">our firewalls document</A></LI>
+<LI><A href="web.html#firewall.web">our firewall links</A></LI>
+</UL>
+<A HREF="quickstart.html#quick.firewall">Back to our quickstart guide.</A>
+</BODY>
+</HTML>
+
+
+
diff --git a/doc/src/quickstart.html b/doc/src/quickstart.html
new file mode 100644
index 000000000..a74c11774
--- /dev/null
+++ b/doc/src/quickstart.html
@@ -0,0 +1,458 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>Quick FreeS/WAN installation and configuration</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, installation, quickstart">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Revised by Claudia Schmeing for same
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: quickstart.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+<BODY>
+<H1><A name="quickstart">Quickstart Guide to Opportunistic Encryption</A></H1>
+<A name="quick_guide"></A>
+
+<H2><A name="opp.setup">Purpose</A></H2>
+
+<P>This page will get you started using Linux FreeS/WAN with opportunistic
+ encryption (OE). OE enables you to set up IPsec tunnels
+ without co-ordinating with another
+ site administrator, and without hand configuring each tunnel.
+ If enough sites support OE, a &quot;FAX effect&quot; occurs, and
+ many of us can communicate without eavesdroppers.</P>
+
+<H3>OE "flag day"</H3>
+
+<P>As of FreeS/WAN 2.01, OE uses DNS TXT resource records (RRs)
+only (rather than TXT with KEY).
+This change causes a
+<a href="http://jargon.watson-net.com/jargon.asp?w=flag+day">"flag day"</a>.
+Users of FreeS/WAN 2.00 (or earlier) OE who are upgrading may require
+additional resource records, as detailed in our
+<a href="upgrading.html#upgrading.flagday">upgrading document</a>.
+OE setup instructions here are for 2.02 or later.</P>
+
+
+<H2><A name="opp.dns">Requirements</A></H2>
+
+<P>To set up opportunistic encryption, you will need:</P>
+<UL>
+<LI>a Linux box. For OE to the public Internet, this box must NOT
+be behind <A HREF="glossary.html#NAT.gloss">Network Address Translation</A>
+(NAT).</LI>
+<LI>to install Linux FreeS/WAN 2.02 or later</LI>
+<LI>either control over your reverse DNS (for full opportunism) or
+the ability to write to some forward domain (for initiator-only).
+<A HREF="http://www.fdns.net">This free DNS service</A> explicitly
+supports forward TXT records for FreeS/WAN use.</LI>
+<LI>(for full opportunism) a static IP</LI>
+</UL>
+
+<P>Note: Currently, only Linux FreeS/WAN supports opportunistic
+encryption.</P>
+
+<H2><A name="easy.install">RPM install</A></H2>
+
+<P>Our instructions are for a recent Red Hat with a 2.4-series stock or
+Red Hat updated kernel. For other ways to install, see our
+<A href="install.html#install">install document</A>.</P>
+
+
+<H3>Download RPMs</H3>
+
+<P>If we have prebuilt RPMs for your Red Hat system,
+this command will get them:
+</P>
+
+<PRE> ncftpget ftp://ftp.xs4all.nl/pub/crypto/freeswan/binaries/RedHat-RPMs/`uname -r | tr -d 'a-wy-z'`/\*</PRE>
+
+<P>If that fails, you will need to try <A HREF="install.html">another install
+method</A>.
+Our kernel modules
+<B>will only work on the Red Hat kernel they were built for</B>,
+since they are very sensitive to small changes in the kernel.</P>
+
+<P>If it succeeds, you will have userland tools, a kernel module, and an
+RPM signing key:</P>
+
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm
+ freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm
+ freeswan-rpmsign.asc</PRE>
+
+
+<H3>Check signatures</H3>
+
+<P>If you're running RedHat 8.x or later, import the RPM signing key into the
+RPM database:</P>
+<PRE> rpm --import freeswan-rpmsign.asc</PRE>
+
+<P>For RedHat 7.x systems, you'll need to add it to your
+<A HREF="glossary.html#PGP">PGP</A> keyring:</P>
+<PRE> pgp -ka freeswan-rpmsign.asc</PRE>
+
+<P>Check the digital signatures on both RPMs using:</P>
+<PRE> rpm --checksig freeswan*.rpm </PRE>
+
+<P>You should see that these signatures are good:</P>
+<PRE> freeswan-module-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK
+ freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm: pgp md5 OK</PRE>
+
+
+<H3>Install the RPMs</H3>
+
+<P>Become root:</P>
+<PRE> su</PRE>
+
+<P>Install your RPMs with:<P>
+<PRE> rpm -ivh freeswan*.rpm</PRE>
+
+<P>If you're upgrading from FreeS/WAN 1.x RPMs, and have problems with that
+command, see
+<A HREF="upgrading.html#upgrading.rpms">this note</A>.</P>
+
+<P>Then, start FreeS/WAN:</P>
+<PRE> service ipsec start</PRE>
+
+
+<H3><A name="testinstall">Test</A></H3>
+<P>To check that you have a successful install, run:</P>
+<PRE> ipsec verify</PRE>
+
+<P>You should see as part of the <var>verify</var> output:</P>
+<PRE>
+ Checking your system to see if IPsec got installed and started correctly
+ Version check and ipsec on-path [OK]
+ Checking for KLIPS support in kernel [OK]
+ Checking for RSA private key (/etc/ipsec.secrets) [OK]
+ Checking that pluto is running [OK]
+ ...</PRE>
+
+<P>If any of these first four checks fails, see our
+<A href="trouble.html#install.check">troubleshooting guide</A>.
+</P>
+
+<H2><A name="opp.setups.list">Our Opportunistic Setups</A></H2>
+<H3>Full or partial opportunism?</H3>
+<P>Determine the best form of opportunism your system can support.</P>
+<UL>
+<LI>For <A HREF="#opp.incoming">full opportunism</A>, you'll need a static
+IP and and either control over your reverse DNS or an ISP
+that can add the required TXT record for you.</LI>
+<LI>If you have a dynamic IP, and/or write access to forward DNS only,
+you can do <A HREF="#opp.client">initiate-only opportunism</A></LI>
+<LI>To protect traffic bound for real IPs behind your gateway, use
+<A HREF="adv_config.html#opp.gate">this form of full opportunism</A>.</LI>
+</UL>
+
+<H2><A name="opp.client">Initiate-only setup</A></H2>
+
+<H3>Restrictions</H3>
+<P>When you set up initiate-only Opportunistic Encryption (iOE):</P>
+<UL>
+<LI>there will be <STRONG> no incoming connection requests</STRONG>; you
+ can initiate all the IPsec connections you need.</LI>
+<LI><STRONG>only one machine is visible</STRONG> on your end of the
+ connection.</LI>
+<LI>iOE also protects traffic on behalf of
+<A HREF="glossary.html#NAT.gloss">NATted</A> hosts behind the iOE box.</LI>
+</UL>
+<P>You cannot network a group of initiator-only machines if none
+of these is capable of responding to OE. If one is capable of responding,
+you may be able to create a hub topology using routing.</P>
+
+
+<H3><A name="forward.dns">Create and publish a forward DNS record</A></H3>
+
+<H4>Find a domain you can use</H4>
+
+<P>Find a DNS forward domain (e.g. example.com) where you can publish your key.
+You'll need access to the DNS zone files for that domain.
+This is common for a domain you own. Some free DNS providers,
+such as <A HREF="http://www.fdns.net">this one</A>, also provide
+this service.</P>
+
+<P>Dynamic IP users take note: the domain where you place your key
+ need not be associated with the IP address for your system,
+ or even with your system's usual hostname.</P>
+
+<H4>Choose your ID</H4>
+
+<P>Choose a name within that domain which you will use to identify your
+ machine. It's convenient if this can be the same as your hostname:</P>
+<PRE> [root@xy root]# hostname --fqdn
+ xy.example.com</PRE>
+<P>This name in FQDN (fully-qualified domain name)
+format will be your ID, for DNS key lookup and IPsec
+negotiation.</P>
+
+
+<H4>Create a forward TXT record</H4>
+
+<P>Generate a forward TXT record containing your system's public key
+ with a command like:</P>
+<PRE> ipsec showhostkey --txt @xy.example.com</PRE>
+<P>using your chosen ID in place of
+xy.example.com.
+This command takes the contents of
+/etc/ipsec.secrets and reformats it into something usable by ISC's BIND.
+ The result should look like this (with the key data trimmed down for
+ clarity):</P>
+<PRE>
+ ; RSA 2192 bits xy.example.com Thu Jan 2 12:41:44 2003
+ IN TXT "X-IPsec-Server(10)=@xy.example.com"
+ "AQOF8tZ2... ...+buFuFn/"
+</PRE>
+
+
+<H4>Publish the forward TXT record</H4>
+
+<P>Insert the record into DNS, or have a system adminstrator do it
+for you. It may take up to 48 hours for the record to propagate, but
+it's usually much quicker.</P>
+
+<H3>Test that your key has been published</H3>
+
+<P>Check your DNS work</P>
+
+<PRE> ipsec verify --host xy.example.com</PRE>
+
+<P>As part of the <var>verify</var> output, you ought to see something
+like:</P>
+
+<PRE> ...
+ Looking for TXT in forward map: xy.example.com [OK]
+ ...</PRE>
+
+<P>For this type of opportunism, only the forward test is relevant;
+you can ignore the tests designed to find reverse records.</P>
+
+
+<H3>Configure, if necessary</H3>
+
+<P>
+If your ID is the same as your hostname,
+you're ready to go.
+FreeS/WAN will use its
+<A HREF="policygroups.html">built-in connections</A> to create
+your iOE functionality.
+</P>
+
+<P>If you have chosen a different ID, you must tell FreeS/WAN about it via
+<A HREF="manpage.d/ipsec.conf.5.html"><VAR>ipsec.conf</VAR></A>:
+
+<PRE> config setup
+ myid=@myname.freedns.example.com</PRE>
+
+<P>and restart FreeS/WAN:
+</P>
+<PRE> service ipsec restart</PRE>
+<P>The new ID will be applied to the built-in connections.</P>
+
+<P>Note: you can create more complex iOE configurations as explained in our
+<A HREF="policygroups.html#policygroups">policy groups document</A>, or
+disable OE using
+<A HREF="policygroups.html#disable_policygroups">these instructions</A>.</P>
+
+
+<H3>Test</H3>
+<P>That's it! <A HREF="#opp.test">Test your connections</A>.</P>
+
+<A name="opp.incoming"></A><H2>Full Opportunism</H2>
+
+<P>Full opportunism
+allows you to initiate and receive opportunistic connections on your
+machine.</P>
+
+<A name="incoming.opp.dns"></A><H3>Put a TXT record in a Forward Domain</H3>
+
+<P>To set up full opportunism, first
+<A HREF="#forward.dns">set up a forward TXT record</A> as for
+<A HREF="#opp.client">initiator-only OE</A>, using
+an ID (for example, your hostname) that resolves to your IP. Do not
+configure <VAR>/etc/ipsec.conf</VAR>, but continue with the
+instructions for full opportunism, below.
+</P>
+
+<P>Note that this forward record is not currently necessary for full OE,
+but will facilitate future features.</P>
+
+
+<A name="incoming.opp.dns"></A><H3>Put a TXT record in Reverse DNS</H3>
+
+<P>You must be able to publish your DNS RR directly in the reverse domain.
+FreeS/WAN will not follow a PTR which appears in the reverse, since
+a second lookup at connection start time is too costly.</P>
+
+
+<H4>Create a Reverse DNS TXT record</H4>
+
+<P>This record serves to publicize your FreeS/WAN public key. In
+ addition, it lets others know that this machine can receive opportunistic
+connections, and asserts that the machine is authorized to encrypt on
+its own behalf.</P>
+
+<P>Use the command:</P>
+<PRE> ipsec showhostkey --txt 192.0.2.11</PRE>
+<P>where you replace 192.0.2.11 with your public IP.</P>
+
+<P>The record (with key shortened) looks like:</P>
+<PRE> ; RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ IN TXT &quot;X-IPsec-Server(10)=192.0.2.11&quot; &quot; AQOF8tZ2...+buFuFn/&quot;</PRE>
+
+
+<H4>Publish your TXT record</H4>
+
+<P>Send these records to your ISP, to be published in your IP's reverse map.
+It may take up to 48 hours for these to propagate, but usually takes
+much less time.</P>
+
+
+<H3>Test your DNS record</H3>
+
+<P>Check your DNS work with</P>
+
+<PRE> ipsec verify --host xy.example.com</PRE>
+
+<P>As part of the <var>verify</var> output, you ought to see something like:</P>
+
+<PRE> ...
+ Looking for TXT in reverse map: 11.2.0.192.in-addr.arpa [OK]
+ ...</PRE>
+
+<P>which indicates that you've passed the reverse-map test.</P>
+
+<H3>No Configuration Needed</H3>
+
+<P>FreeS/WAN 2.x ships with full OE enabled, so you don't need to configure
+anything.
+To enable OE out of the box, FreeS/WAN 2.x uses the policy group
+<VAR>private-or-clear</VAR>,
+which creates IPsec connections if possible (using OE if needed),
+and allows traffic in the clear otherwise. You can create more complex
+OE configurations as described in our
+<A HREF="policygroups.html#policygroups">policy groups document</A>, or
+disable OE using
+<A HREF="policygroups.html#disable_policygroups">these instructions</A>.</P>
+
+<P>If you've previously configured for initiator-only opportunism, remove
+ <VAR>myid=</VAR> from <VAR>config setup</VAR>, so that peer FreeS/WANs
+will look up your key by IP. Restart FreeS/WAN so that your change will
+take effect, with</P>
+
+<PRE> service ipsec restart</PRE>
+
+
+<H3>Consider Firewalling</H3>
+
+<P>If you are running a default install of RedHat 8.x, take note: you will
+need to alter your iptables rule setup to allow IPSec traffic through your
+firewall. See <A HREF="firewall.html#simple.rules">our firewall document</A>
+for sample <VAR>iptables</VAR> rules.</P>
+
+
+<H3>Test</H3>
+
+<P>That's it. Now, <A HREF="#opp.test">test your connection</A>.
+
+
+
+
+<H3>Test</H3>
+
+<P>Instructions are in the next section.</P>
+
+
+<H2><A NAME="opp.test">Testing opportunistic connections</A></H2>
+
+<P>Be sure IPsec is running. You can see whether it is with:</P>
+<PRE> ipsec setup status</PRE>
+<P>If need be, you can restart it with:</P>
+<PRE> service ipsec restart</PRE>
+
+<P>Load a FreeS/WAN test website from the host on which you're running
+FreeS/WAN. Note: the feds may be watching these sites. Type one of:<P>
+<PRE> links oetest.freeswan.org</PRE>
+<PRE> links oetest.freeswan.nl</PRE>
+<!--<PRE> links oetest.freeswan.ca</PRE>-->
+
+<P>A positive result looks like this:</P>
+
+<PRE>
+ You seem to be connecting from: 192.0.2.11 which DNS says is:
+ gateway.example.com
+ _________________________________________________________________
+
+ Status E-route
+ OE enabled 16 192.139.46.73/32 -> 192.0.2.11/32 =>
+ tun0x2097@192.0.2.11
+ OE enabled 176 192.139.46.77/32 -> 192.0.2.11/32 =>
+ tun0x208a@192.0.2.11
+</PRE>
+
+<P>If you see this, congratulations! Your OE host or gateway will now encrypt
+its own traffic whenever it can. For more OE tests, please see our
+<A HREF="testing.html#test.oe">testing document</A>. If you have difficulty,
+see our <A HREF="#oe.trouble">OE troubleshooting tips</A>.
+</P>
+
+
+
+<H2>Now what?</H2>
+
+<P>Please see our <A HREF="policygroups.html">policy groups document</A>
+for more ways to set up Opportunistic Encryption.</P>
+
+<P>You may also wish to make some <A HREF="config.html">
+pre-configured connections</A>.
+</P>
+
+<H2>Notes</H2>
+
+<UL>
+<LI>We assume some facts about your system in order to make Opportunistic
+Encryption easier to configure. For example, we assume that you wish
+to have FreeS/WAN secure your default interface.</LI>
+<LI>You may change this, and other settings, by altering the
+<VAR>config setup</VAR> section in
+<VAR>/etc/ipsec.conf</VAR>.
+</LI>
+<LI>Note that the built-in connections used to build policy groups do
+not inherit from <VAR>conn default</VAR>.</LI>
+<!--
+<LI>If you do not define your local identity
+(eg. <VAR>leftid</VAR>), this will be the IP address of your default
+FreeS/WAN interface.
+-->
+<LI>
+If you fail to define your local identity and
+do not fill in your reverse DNS entry, you will not be able to use OE.</LI>
+</UL>
+
+<A NAME="oe.trouble"></A><H2>Troubleshooting OE</H2>
+
+<P>See the OE troubleshooting hints in our
+<A HREF="trouble.html#oe.trouble">troubleshooting guide</A>.
+</P>
+
+<A NAME="oe.known-issues"></A><H2>Known Issues</H2>
+
+<P>Please see
+<A HREF="opportunism.known-issues">this list</A> of known issues
+with Opportunistic Encryption.</P>
+
+
+</BODY>
+</HTML>
diff --git a/doc/src/reference.ESPUDP.xml b/doc/src/reference.ESPUDP.xml
new file mode 100644
index 000000000..c9b96cef3
--- /dev/null
+++ b/doc/src/reference.ESPUDP.xml
@@ -0,0 +1,34 @@
+<?xml version='1.0'?>
+<!DOCTYPE reference SYSTEM 'rfc2629.dtd'>
+
+<reference anchor='ESPUDP'>
+
+<front>
+<title abbrev='UDPESP'>UDP Encapsulation of IPsec Packets</title>
+<author initials='A.' surname='Huttunen' fullname='Ari Huttunen'>
+<organization>F-Secure Corporation</organization>
+<address>
+<postal>
+<street>Tammasaarenkatu 7</street>
+<street>FIN-00181 HELSINKI</street>
+<country>Finland</country></postal>
+<email>Ari.Huttunen@F-Secure.com</email></address></author>
+
+<author initials='W.' surname='Dixon' fullname='William Dixon'>
+<organization>Microsoft</organization>
+<address>
+<postal>
+<street>One Microsoft Way</street>
+<street>Redmond</street>
+<street>WA 98052</street>
+<country>USA</country></postal>
+<email>wdixon@microsoft.com</email></address></author>
+
+<date month='June' year='2001'></date>
+<area>Security</area>
+<keyword>IP security protocol</keyword>
+<keyword>IPSEC</keyword>
+<keyword>security</keyword></front>
+
+<seriesInfo name='ID' value='internet-draft (draft-ietf-ipsec-udp-encaps-00) (informative)' />
+</reference>
diff --git a/doc/src/reference.KEYRESTRICT.xml b/doc/src/reference.KEYRESTRICT.xml
new file mode 100644
index 000000000..62aa1ef96
--- /dev/null
+++ b/doc/src/reference.KEYRESTRICT.xml
@@ -0,0 +1,31 @@
+<?xml version='1.0'?>
+<!DOCTYPE reference SYSTEM 'rfc2629.dtd'>
+
+<reference anchor='KEYRESTRICT'>
+
+<front>
+<title abbrev='KEYRESTRICT'>Limiting the Scope of the KEY Resource Record</title>
+<author initials='D.' surname='Massey' fullname='Dan Massey'>
+<organization>USC/ISI</organization>
+<address>
+<postal>
+<street>USC Informational Sciences Institute</street>
+<street>3811 North Fairfax Drive, Suite 200</street>
+<street>Arlington, VA 22203</street>
+<country>USA</country></postal>
+<email>masseyd@isi.edu</email></address></author>
+
+<author initials='S.' surname='Rose' fullname='Scott Rose'>
+<organization>National Institute for Standards and Technology</organization>
+<address>
+<postal>
+<street>Gaithersburg, MD</street>
+<country>USA</country></postal>
+<email>scott.rose@nist.gov</email></address></author>
+
+<date month='March' year='2002'></date>
+<area>Internet</area>
+</front>
+
+<seriesInfo name='ID' value='internet-draft (draft-ietf-dnsext-restrict-key-for-dnssec-02) (normative)' />
+</reference>
diff --git a/doc/src/reference.MODPGROUPS.xml b/doc/src/reference.MODPGROUPS.xml
new file mode 100644
index 000000000..5eaf83f89
--- /dev/null
+++ b/doc/src/reference.MODPGROUPS.xml
@@ -0,0 +1,32 @@
+<?xml version='1.0'?>
+<!DOCTYPE reference SYSTEM 'rfc2629.dtd'>
+
+<reference anchor='MODPGROUPS'>
+
+<front>
+<title abbrev='MODPGROUPS'>More MODP Diffie-Hellman groups for IKE</title>
+<author initials='T.' surname='Kivinen' fullname='Tero Kivinen'>
+<organization>SSH Communications Security</organization>
+<address>
+<postal>
+<street>Fredrikinkatu 42</street>
+<street>FIN-00100 HELSINKI</street>
+<country>Finland</country></postal>
+<email>kivinen@ssh.fi</email></address></author>
+
+<author initials='M.' surname='Kojo' fullname='Mika Kojo'>
+<organization>University of Helsinki</organization>
+<address>
+<postal>
+<street>HELSINKI</street>
+<country>Finland</country></postal>
+<email>mrskojo@cc.helsinki.fi</email></address></author>
+
+<date month='November' year='2001'></date>
+<area>Security</area>
+<keyword>IP security protocol</keyword>
+<keyword>IPSEC</keyword>
+<keyword>security</keyword></front>
+
+<seriesInfo name='ID' value='internet-draft (draft-ietf-ipsec-ike-modp-groups-03) (normative)' />
+</reference>
diff --git a/doc/src/reference.OEspec.xml b/doc/src/reference.OEspec.xml
new file mode 100644
index 000000000..29c6d6efd
--- /dev/null
+++ b/doc/src/reference.OEspec.xml
@@ -0,0 +1,45 @@
+<?xml version='1.0'?>
+<!DOCTYPE reference SYSTEM 'rfc2629.dtd'>
+
+<reference anchor='OEspec'>
+
+<front>
+<title abbrev='OEspec'>Opportunistic Encryption</title>
+
+ <author initials="D.H." surname="Redelmeier"
+ fullname="D. Hugh Redelmeier">
+ <organization abbrev="Mimosa">Mimosa</organization>
+ <address>
+ <postal>
+ <street>Somewhere</street>
+ <city>Toronto</city>
+ <region>ON</region>
+ <country>CA</country>
+ </postal>
+ <email>hugh@mimosa.com</email>
+ </address>
+ </author>
+
+ <author initials="H." surname="Spencer"
+ fullname="Henry Spencer">
+ <organization abbrev="SP Systems">SP Systems</organization>
+ <address>
+ <postal>
+ <street>Box 280 Station A</street>
+ <city>Toronto</city>
+ <region>ON</region>
+ <code>M5W 1B2</code>
+ <country>Canada</country>
+ </postal>
+ <email>henry@spsystems.net</email>
+ </address>
+ </author>
+
+<date month='May' year='2001'></date>
+<keyword>IP security protocol</keyword>
+<keyword>IPSEC</keyword>
+<keyword>security</keyword></front>
+
+<seriesInfo name='paper' value='http://www.freeswan.org/freeswan_trees/freeswan-1.91/doc/opportunism.spec' />
+</reference>
+
diff --git a/doc/src/reference.RFC.3526.xml b/doc/src/reference.RFC.3526.xml
new file mode 100644
index 000000000..54fed705a
--- /dev/null
+++ b/doc/src/reference.RFC.3526.xml
@@ -0,0 +1,32 @@
+<?xml version='1.0'?>
+<!DOCTYPE reference SYSTEM 'rfc2629.dtd'>
+
+<reference anchor='RFC3526'>
+
+<front>
+<title abbrev='MODPGROUPS'>More MODP Diffie-Hellman groups for IKE</title>
+<author initials='T.' surname='Kivinen' fullname='Tero Kivinen'>
+<organization>SSH Communications Security</organization>
+<address>
+<postal>
+<street>Fredrikinkatu 42</street>
+<street>FIN-00100 HELSINKI</street>
+<country>Finland</country></postal>
+<email>kivinen@ssh.fi</email></address></author>
+
+<author initials='M.' surname='Kojo' fullname='Mika Kojo'>
+<organization>University of Helsinki</organization>
+<address>
+<postal>
+<street>HELSINKI</street>
+<country>Finland</country></postal>
+<email>mrskojo@cc.helsinki.fi</email></address></author>
+
+<date month='March' year='2003'></date>
+<area>Security</area>
+<keyword>IP security protocol</keyword>
+<keyword>IPSEC</keyword>
+<keyword>security</keyword></front>
+
+<seriesInfo name='RFC' value='3526' />
+</reference>
diff --git a/doc/src/responderstate.txt b/doc/src/responderstate.txt
new file mode 100644
index 000000000..f64b82983
--- /dev/null
+++ b/doc/src/responderstate.txt
@@ -0,0 +1,43 @@
+ |
+ | IKE main mode
+ | phase 1
+ V
+ .-----------------.
+ | unauthenticated |
+ | OE peer |
+ `-----------------'
+ |
+ | lookup KEY RR in in-addr.arpa
+ | (if ID_IPV4_ADDR)
+ | lookup KEY RR in forward
+ | (if ID_FQDN)
+ V
+ .-----------------. RR not found
+ | received DNS |---------------> log failure
+ | reply |
+ `----+--------+---'
+ phase 2 | \ misformatted
+ proposal | `------------------> log failure
+ V
+ .----------------.
+ | authenticated | identical initiator
+ | OE peer |--------------------> initiator
+ `----------------' connection found state machine
+ |
+ | look for TXT record for initiator
+ |
+ V
+ .---------------.
+ | authorized |---------------------> log failure
+ | OE peer |
+ `---------------'
+ |
+ |
+ V
+ potential OE
+ connection in
+ initiator state
+ machine
+
+
+$Id: responderstate.txt,v 1.1 2004/03/15 20:35:24 as Exp $
diff --git a/doc/src/rfc.html b/doc/src/rfc.html
new file mode 100644
index 000000000..762c66c6e
--- /dev/null
+++ b/doc/src/rfc.html
@@ -0,0 +1,158 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>IPsec RFCs</title>
+ <meta name="keywords"
+ content="IPsec, VPN, security, FreeSWAN, RFC, standard">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: rfc.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="RFC">IPsec RFCs and related documents</a></h1>
+
+<h2><a name="RFCfile">The RFCs.tar.gz Distribution File</a></h2>
+
+<p>The Linux FreeS/WAN distribution is available from <a
+href="http://www.xs4all.nl/~freeswan"> our primary distribution site</a> and
+various mirror sites. To give people more control over their downloads, the
+RFCs that define IP security are bundled separately in the file
+RFCs.tar.gz.</p>
+
+<p>The file you are reading is included in the main distribution and is
+available on the web site. It describes the RFCs included in the <a
+href="#RFCs.tar.gz">RFCs.tar.gz</a> bundle and gives some pointers to <a
+href="#sources">other ways to get them</a>.</p>
+
+<h2><a name="sources">Other sources for RFCs &amp; Internet drafts</a></h2>
+
+<h3><a name="RFCdown">RFCs</a></h3>
+
+<p>RFCs are downloadble at many places around the net such as:</p>
+<ul>
+ <li><a href="http://www.rfc-editor.org">http://www.rfc-editor.org</a></li>
+ <li><a href="http://nis.nsf.net/internet/documents/rfc">NSF.net</a></li>
+ <li><a href="http://sunsite.doc.ic.ac.uk/computing/internet/rfc">Sunsite in
+ the UK</a></li>
+</ul>
+
+<p>browsable in HTML form at others such as:</p>
+<ul>
+ <li><a
+ href="http://www.landfield.com/rfcs/index.html">landfield.com</a></li>
+ <li><a href="http://www.library.ucg.ie/Connected/RFC">Connected Internet
+ Encyclopedia</a></li>
+</ul>
+
+<p>and some of them are available in translation:</p>
+<ul>
+ <li><a href="http://www.eisti.fr/eistiweb/docs/normes/">French</a></li>
+</ul>
+
+<p>There is also a published <a href="biblio.html#RFCs">Big Book of IPSEC
+RFCs</a>.</p>
+
+<h3><a name="drafts">Internet Drafts</a></h3>
+
+<p>Internet Drafts, working documents which sometimes evolve into RFCs, are
+also available.</p>
+<ul>
+ <li><a href="http://www.ietf.org/ID.html">Overall reference page</a></li>
+ <li><a href="http://www.ietf.org/ids.by.wg/ipsec.html">IPsec</a> working
+ group</li>
+ <li><a href="http://www.ietf.org/ids.by.wg/ipsra.html">IPSRA (IPsec Remote
+ Access)</a> working group</li>
+ <li><a href="http://www.ietf.org/ids.by.wg/ipsp.html">IPsec Policy</a>
+ working group</li>
+ <li><a href="http://www.ietf.org/ids.by.wg/kink.html">KINK (Kerberized
+ Internet Negotiation of Keys)</a> working group</li>
+</ul>
+
+<p>Note: some of these may be obsolete, replaced by later drafts or by
+RFCs.</p>
+
+<h3><a name="FIPS1">FIPS standards</a></h3>
+
+<p>Some things used by <a href="glossary.html#IPSEC">IPsec</a>, such as <a
+href="glossary.html#DES">DES</a> and <a href="glossary.html#SHA">SHA</a>, are
+defined by US government standards called <a
+href="glossary.html#FIPS">FIPS</a>. The issuing organisation, <a
+href="glossary.html#NIST">NIST</a>, have a <a
+href="http://www.itl.nist.gov/div897/pubs">FIPS home page</a>.</p>
+
+<h2><a name="RFCs.tar.gz">What's in the RFCs.tar.gz bundle?</a></h2>
+
+<p>All filenames are of the form rfc*.txt, with the * replaced with the RFC
+number.</p>
+<pre>RFC# Title</pre>
+
+<h3><a name="rfc.ov">Overview RFCs</a></h3>
+<pre>2401 Security Architecture for the Internet Protocol
+2411 IP Security Document Roadmap</pre>
+
+<h3><a name="basic.prot">Basic protocols</a></h3>
+<pre>2402 IP Authentication Header
+2406 IP Encapsulating Security Payload (ESP)</pre>
+
+<h3><a name="key.ike">Key management</a></h3>
+<pre>2367 PF_KEY Key Management API, Version 2
+2407 The Internet IP Security Domain of Interpretation for ISAKMP
+2408 Internet Security Association and Key Management Protocol (ISAKMP)
+2409 The Internet Key Exchange (IKE)
+2412 The OAKLEY Key Determination Protocol
+2528 Internet X.509 Public Key Infrastructure</pre>
+
+<h3><a name="rfc.detail">Details of various things used</a></h3>
+<pre>2085 HMAC-MD5 IP Authentication with Replay Prevention
+2104 HMAC: Keyed-Hashing for Message Authentication
+2202 Test Cases for HMAC-MD5 and HMAC-SHA-1
+2207 RSVP Extensions for IPSEC Data Flows
+2403 The Use of HMAC-MD5-96 within ESP and AH
+2404 The Use of HMAC-SHA-1-96 within ESP and AH
+2405 The ESP DES-CBC Cipher Algorithm With Explicit IV
+2410 The NULL Encryption Algorithm and Its Use With IPsec
+2451 The ESP CBC-Mode Cipher Algorithms
+2521 ICMP Security Failures Messages</pre>
+
+<h3><a name="rfc.ref">Older RFCs which may be referenced</a></h3>
+<pre>1321 The MD5 Message-Digest Algorithm
+1828 IP Authentication using Keyed MD5
+1829 The ESP DES-CBC Transform
+1851 The ESP Triple DES Transform
+1852 IP Authentication using Keyed SHA</pre>
+
+<h3><a name="rfc.dns">RFCs for secure DNS service, which IPsec may
+use</a></h3>
+<pre>2137 Secure Domain Name System Dynamic Update
+2230 Key Exchange Delegation Record for the DNS
+2535 Domain Name System Security Extensions
+2536 DSA KEYs and SIGs in the Domain Name System (DNS)
+2537 RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)
+2538 Storing Certificates in the Domain Name System (DNS)
+2539 Storage of Diffie-Hellman Keys in the Domain Name System (DNS)</pre>
+
+<h3><a name="rfc.exp">RFCs labelled "experimental"</a></h3>
+<pre>2521 ICMP Security Failures Messages
+2522 Photuris: Session-Key Management Protocol
+2523 Photuris: Extended Schemes and Attributes</pre>
+
+<h3><a name="rfc.rel">Related RFCs</a></h3>
+<pre>1750 Randomness Recommendations for Security
+1918 Address Allocation for Private Internets
+1984 IAB and IESG Statement on Cryptographic Technology and the Internet
+2144 The CAST-128 Encryption Algorithm</pre>
+</body>
+</html>
diff --git a/doc/src/roadmap.html b/doc/src/roadmap.html
new file mode 100644
index 000000000..c9d85047c
--- /dev/null
+++ b/doc/src/roadmap.html
@@ -0,0 +1,203 @@
+<html>
+<head>
+<title>FreeS/WAN roadmap</title>
+<meta name="keywords" content="Linux, IPsec, VPN, security, FreeSWAN">
+
+<!--
+
+Written by Sandy Harris for the Linux FreeS/WAN project
+Freely distributable under the GNU General Public License
+
+More information at www.freeswan.org
+Feedback to users@lists.freeswan.org
+
+CVS information:
+RCS ID: $Id: roadmap.html,v 1.1 2004/03/15 20:35:24 as Exp $
+Last changed: $Date: 2004/03/15 20:35:24 $
+Revision number: $Revision: 1.1 $
+
+CVS revision numbers do not correspond to FreeS/WAN release numbers.
+-->
+</head>
+
+<body>
+<h1><a name="roadmap">Distribution Roadmap: What's Where in Linux FreeS/WAN</a></h1>
+
+<p>
+This file is a guide to the locations of files within the FreeS/WAN
+distribution. Everything described here should be on your system once you
+download, gunzip, and untar the distribution.</p>
+
+<p>This distribution contains two major subsystems
+</p>
+<dl>
+ <dt><a href="#klips.roadmap">KLIPS</a></dt>
+ <dd>the kernel code</dd>
+ <dt><a href="#pluto.roadmap">Pluto</a></dt>
+ <dd>the user-level key-management daemon</dd>
+</dl>
+
+<p>plus assorted odds and ends.
+</p>
+<h2><a name="top">Top directory</a></h2>
+
+<p>The top directory has essential information in text files:</p>
+
+<dl>
+ <dt>README</dt>
+ <dd>introduction to the software</dd>
+ <dt>INSTALL</dt>
+ <dd>short experts-only installation procedures. More detalied procedures are in
+ <a href="install.html">installation</a> and
+ <a href="config.html">configuration</a> HTML documents.</dd>
+ <dt>BUGS</dt>
+ <dd>major known bugs in the current release.</dd>
+ <dt>CHANGES</dt>
+ <dd>changes from previous releases</dd>
+ <dt>CREDITS</dt>
+ <dd>acknowledgement of contributors</dd>
+ <dt>COPYING</dt>
+ <dd>licensing and distribution information</dd>
+</dl>
+
+<h2><a name="doc">Documentation</a></h2>
+
+<p>
+The doc directory contains the bulk of the documentation, most of it in
+HTML format. See the <a href="index.html">index file</a> for details.
+</p>
+
+<h2><a name="klips.roadmap">KLIPS: kernel IP security</a></h2>
+</a>
+<p>
+<a href="glossary.html#KLIPS">KLIPS</a> is <strong>K</strong>erne<strong>L</strong>
+<strong>IP</strong> <strong>S</strong>ecurity. It lives in the klips
+directory, of course.
+</p>
+<dl>
+ <dt>klips/doc</dt>
+ <dd>documentation</dd>
+ <dt>klips/patches</dt>
+ <dd>patches for existing kernel files</dd>
+ <dt>klips/test</dt>
+ <dd>test stuff</dd>
+ <dt>klips/utils</dt>
+ <dd>low-level user utilities</dd>
+ <dt>klips/net/ipsec</dt>
+ <dd>actual klips kernel files</dd>
+ <dt>klips/src</dt>
+ <dd>symbolic link to klips/net/ipsec
+ <p>The "make insert" step of installation installs the patches and makes
+ a symbolic link from the kernel tree to klips/net/ipsec. The odd name of
+ klips/net/ipsec is dictated by some annoying limitations of the scripts
+ which build the Linux kernel. The symbolic-link business is a bit
+ messy, but all the alternatives are worse.</p>
+ <p></p>
+ </dd>
+ <dt>klips/utils</dt>
+ <dd>Utility programs:
+ <p></p>
+ <dl>
+ <dt>eroute</dt>
+ <dd>manipulate IPsec extended routing tables</dd>
+ <dt>klipsdebug</dt>
+ <dd>set Klips (kernel IPsec support) debug features and level</dd>
+ <dt>spi</dt>
+ <dd>manage IPsec Security Associations</dd>
+ <dt>spigrp</dt>
+ <dd>group/ungroup IPsec Security Associations</dd>
+ <dt>tncfg</dt>
+ <dd>associate IPsec virtual interface with real interface</dd>
+ </dl>
+ <p>These are all normally invoked by ipsec(8) with commands such as</p>
+ <pre> ipsec tncfg <var>arguments</var></pre>
+ There are section 8 man pages for all of these; the names have "ipsec_"
+ as a prefix, so your man command should be something like:
+ <pre> man 8 ipsec_tncfg</pre>
+ </dd>
+</dl>
+
+<h2><a name="pluto.roadmap">Pluto key and connection management daemon</a></h2>
+
+<p>
+<a href="glossary.html#Pluto">Pluto</a> is our key management and negotiation daemon. It
+lives in the pluto directory, along with its low-level user utility,
+whack.
+</p>
+<p>
+There are no subdirectories. Documentation is a man page,
+<a href="manpage.d/ipsec_pluto.8.html">pluto.8</a>. This covers whack as well.
+</p>
+
+<h2><a name="utils">Utils</a></h2>
+
+<p>
+The utils directory contains a growing collection of higher-level user
+utilities, the commands that administer and control the software. Most of the
+things that you will actually have to run yourself are in there.
+</p>
+<dl>
+ <dt>ipsec</dt>
+ <dd>invoke IPsec utilities
+ <p>ipsec(8) is normally the only program installed in a standard
+ directory, /usr/local/sbin. It is used to invoke the others, both those
+ listed below and the ones in klips/utils mentioned above.</p>
+ <p></p>
+ </dd>
+ <dt>auto</dt>
+ <dd>control automatically-keyed IPsec connections</dd>
+ <dt>manual</dt>
+ <dd>take manually-keyed IPsec connections up and down</dd>
+ <dt>barf</dt>
+ <dd>generate copious debugging output</dd>
+ <dt>look</dt>
+ <dd>generate moderate amounts of debugging output</dd>
+</dl>
+<p>
+There are .8 manual pages for these. look is covered in barf.8. The man pages
+have an "ipsec_" prefix so your man command should be something like:
+<pre>
+ man 8 ipsec_auto
+</pre>
+<p>
+Examples are in various files with names utils/*.eg</p>
+
+<h2><a name="lib">Libraries</a></h2>
+
+<h3><a name="fswanlib">FreeS/WAN Library</a></h3>
+
+<p>
+The lib directory is the FreeS/WAN library, also steadily growing, used by
+both user-level and kernel code.<br />
+It includes section 3 <a href="manpages.html">man pages</a> for the library routines.
+</p>
+<h3><a name="otherlib">Imported Libraries</a></h3>
+
+<h4>LibDES</h4>
+
+The libdes library, originally from SSLeay, is used by both Klips and Pluto
+for <a href="glossary.html#3DES">Triple DES</a> encryption. Single DES is not
+used because <a href="politics.html#desnotsecure">it is
+insecure</a>.
+<p>
+Note that this library has its own license, different from the
+<a href="glossary.html#GPL">GPL</a> used for other code in FreeS/WAN.
+ </p>
+<p>
+The library includes its own documentation.
+
+
+<h4>GMP</h4>
+
+The GMP (GNU multi-precision) library is used for multi-precision arithmetic
+in Pluto's key-exchange code and public key code.
+<p>
+Older versions (up to 1.7) of FreeS/WAN included a copy of this library in
+the FreeS/WAN distribution.
+<p>
+Since 1.8, we have begun to rely on the system copy of GMP.
+</p>
+
+</body>
+</html>
+
diff --git a/doc/src/testing.html b/doc/src/testing.html
new file mode 100644
index 000000000..8ffcca604
--- /dev/null
+++ b/doc/src/testing.html
@@ -0,0 +1,395 @@
+<html>
+<head>
+<title>Testing FreeS/WAN</title>
+
+<meta name="keywords" content="Linux, IPsec, VPN, security, FreeSWAN, testing">
+
+<!--
+
+Written by Sandy Harris for the Linux FreeS/WAN project
+Freely distributable under the GNU General Public License
+
+More information at www.freeswan.org
+Feedback to users@lists.freeswan.org
+
+CVS information:
+RCS ID: $Id: testing.html,v 1.1 2004/03/15 20:35:24 as Exp $
+Last changed: $Date: 2004/03/15 20:35:24 $
+Revision number: $Revision: 1.1 $
+
+CVS revision numbers do not correspond to FreeS/WAN release numbers.
+-->
+</head>
+
+<body>
+<h1><a name="test.freeswan">Testing FreeS/WAN</a></h1>
+This document discusses testing FreeS/WAN.
+
+<p>Not all types of testing are described here. Other parts of the
+documentation describe some tests:</p>
+<dl>
+ <dt><a href="install.html#testinstall">installation</a> document</dt>
+ <dd>testing for a successful install</dd>
+ <dt><a href="config.html#testsetup">configuration</a> document</dt>
+ <dd>basic tests for a working configuration</dd>
+ <dt><a href="web.html#interop.web">web links</a> document</dt>
+ <dd>General information on tests for interoperability between various
+ IPsec implementations. This includes links to several test sites.</dd>
+ <dt><a href="interop.html">interoperation</a> document.</dt>
+ <dd>More specific information on FreeS/WAN interoperation with other
+ implementations.</dd>
+ <dt><a href="performance.html">performance</a> document</dt>
+ <dd>performance measurements</dd>
+</dl>
+
+<p>The test setups and procedures described here can also be used in other
+testing, but this document focuses on testing the IPsec functionality of
+FreeS/WAN.</p>
+
+<H2><A NAME="test.oe">Testing opportunistic connections</A></H2>
+
+<P>This section teaches you how to test your opportunistically encrypted (OE)
+connections. To set up OE, please see the easy instructions in our
+<A HREF="quickstart.html">quickstart guide</A>.</P>
+
+<H3>Basic OE Test</H3>
+
+
+<P>This test is for basic OE functionality.
+<!-- You may use it on an
+<A HREF="quickstart.html#oppo.client">initiate-only OE</A> box or a
+<A HREF="quickstart.html#opp.incoming">full OE</A> box. -->
+For additional tests, keep reading.</P>
+
+<P>Be sure IPsec is running. You can see whether it is with:</P>
+<PRE> ipsec setup status</PRE>
+<P>If need be, you can restart it with:</P>
+<PRE> service ipsec restart</PRE>
+
+<P>Load a FreeS/WAN test website from the host on which you're running
+FreeS/WAN. Note: the feds may be watching these sites. Type one of:<P>
+<PRE> links oetest.freeswan.org</PRE>
+<PRE> links oetest.freeswan.nl</PRE>
+<!--<PRE> links oetest.freeswan.ca</PRE>-->
+
+<P>A positive result looks like this:</P>
+
+<PRE>
+ You seem to be connecting from: 192.0.2.11 which DNS says is:
+ gateway.example.com
+ _________________________________________________________________
+
+ Status E-route
+ OE enabled 16 192.139.46.73/32 -> 192.0.2.11/32 =>
+ tun0x2097@192.0.2.11
+ OE enabled 176 192.139.46.77/32 -> 192.0.2.11/32 =>
+ tun0x208a@192.0.2.11
+</PRE>
+
+<P>If you see this, congratulations! Your OE box will now encrypt
+its own traffic whenever it can. If you have difficulty,
+see our <A HREF="#oe.trouble">OE troubleshooting tips</A>.
+</P>
+
+<H3>OE Gateway Test</H3>
+<P>If you've set up FreeS/WAN to protect a subnet behind your gateway,
+you'll need to run another simple test, which can be done from a machine
+running any OS. That's right, your Windows box can be protected by
+opportunistic encryption without any FreeS/WAN install or configuration
+on that box. From <STRONG>each protected subnet node</STRONG>,
+load the FreeS/WAN website with:</P>
+
+<PRE> links oetest.freeswan.org</PRE>
+<PRE> links oetest.freeswan.nl</PRE>
+
+<P>A positive result looks like this:</P>
+<PRE>
+ You seem to be connecting from: 192.0.2.98 which DNS says is:
+ box98.example.com
+ _________________________________________________________________
+
+ Status E-route
+ OE enabled 16 192.139.46.73/32 -> 192.0.2.98/32 =>
+ tun0x134ed@192.0.2.11
+ OE enabled 176 192.139.46.77/32 -> 192.0.2.11/32 =>
+ tun0x134d2@192.0.2.11
+</PRE>
+
+<P>If you see this, congratulations! Your OE gateway will now encrypt
+traffic for this subnet node whenever it can. If you have difficulty, see our
+<A HREF="#oe.trouble">OE troubleshooting tips</A>.
+</P>
+
+
+<H3>Additional OE tests</H3>
+
+<P>When testing OE, you will often find it useful to execute this command
+on the FreeS/WAN host:</P>
+<PRE> ipsec eroute</PRE>
+
+<P>If you have established a connection (either for or for a subnet node)
+you will see a result like:</P>
+
+<PRE> 192.0.2.11/32 -> 192.139.46.73/32 => tun0x149f@192.139.46.38
+</PRE>
+
+<P>Key:</P>
+<TABLE>
+<TR><TD>1.</TD>
+ <TD>192.0.2.11/32</TD>
+ <TD>Local start point of the protected traffic.
+ </TD></TR>
+<TR><TD>2.</TD>
+ <TD>192.0.2.194/32</TD>
+ <TD>Remote end point of the protected traffic.
+ </TD></TR>
+<TR><TD>3.</TD>
+ <TD>192.0.48.38</TD>
+ <TD>Remote FreeS/WAN node (gateway or host).
+ May be the same as (2).
+ </TD></TR>
+<TR><TD>4.</TD>
+ <TD>[not shown]</TD>
+ <TD>Local FreeS/WAN node (gateway or host), where you've produced the output.
+ May be the same as (1).
+ </TD></TR>
+</TABLE>
+
+
+<P>For extra assurance, you may wish to use a packet sniffer such as
+<A HREF="http://www.tcpdump.org">tcpdump</A> to verify that packets
+are being encrypted. You should see output that indicates
+<STRONG>ESP</STRONG> encrypted data,
+ for example:</P>
+
+<PRE> 02:17:47.353750 PPPoE [ses 0x1e12] IP 154: xy.example.com > oetest.freeswan.org: ESP(spi=0x87150d16,seq=0x55)</PRE>
+
+
+
+<h2><a name="test.uml">Testing with User Mode Linux</a></h2>
+
+<p><a href="http://user-mode-linux.sourceforge.net/">User Mode Linux</a>
+allows you to run Linux as a user process on another Linux machine.</p>
+
+<p>As of 1.92, the distribution has a new directory named testing. It
+contains a collection of test scripts and sample configurations. Using these,
+you can bring up several copies of Linux in user mode and have them build
+tunnels to each other. This lets you do some testing of a FreeS/WAN
+configuration on a single machine.</p>
+
+<p>You need a moderately well-endowed machine for this to work well. Each UML
+wants about 16 megs of memory by default, which is plenty for FreeS/WAN
+usage. Typical regression testing only occasionally uses as many as 4 UMLs.
+If one is doing nothing else with the machine (in particular, not running X
+on it), then 128 megs and a 500MHz CPU are fine.</p>
+
+Documentation on these
+scripts is <a href="umltesting.html">here</a>. There is also documentation
+on automated testing <A href="makecheck.html">here</a>.
+
+<h2><a name="testnet">Configuration for a testbed network</a></h2>
+
+<p>A common test setup is to put a machine with dual Ethernet cards in
+between two gateways under test. You need at least five machines; two
+gateways, two clients and a testing machine in the middle.</p>
+
+<p>The central machine both routes packets and provides a place to run
+diagnostic software for checking IPsec packets. See next section for
+discussion of <a href="#tcpdump.faq">using tcpdump(8)</a> for this.</p>
+
+<p>This makes things more complicated than if you just connected the two
+gateway machines directly to each other, but it also makes your test setup
+much more like the environment you actually use IPsec in. Those environments
+nearly always involve routing, and quite a few apparent IPsec failures turn
+out to be problems with routing or with firewalls dropping packets. This
+approach lets you deal with those problems on your test setup.</p>
+
+<p>What you end up with looks like:</p>
+
+<h3><a name="testbed">Testbed network</a></h3>
+<pre> subnet a.b.c.0/24
+ |
+ eth1 = a.b.c.1
+ gate1
+ eth0 = 192.168.p.1
+ |
+ |
+ eth0 = 192.168.p.2
+ route/monitor box
+ eth1 = 192.168.q.2
+ |
+ |
+ eth0 = 192.168.q.1
+ gate2
+ eth1 = x.y.z.1
+ |
+ subnet x.y.z.0/24</pre>
+<pre>Where p and q are any convenient values that do not interfere with other
+routes you may have. The ipsec.conf(5) file then has, among other things:</pre>
+<pre>conn abc-xyz
+ left=192.168.p.1
+ leftnexthop=192.168.p.2
+ right=192.168.q.1
+ rightnexthop=192.168.q.2</pre>
+
+<p>Once that works, you can remove the "route/monitor box", and connect the
+two gateways to the Internet. The only parameters in ipsec.conf(5) that need
+to change are the four shown above. You replace them with values appropriate
+for your Internet connection, and change the eth0 IP addresses and the
+default routes on both gateways.</p>
+
+<p>Note that nothing on either subnet needs to change. This lets you test
+most of your IPsec setup before connecting to the insecure Internet.</p>
+
+<h3><a name="tcpdump.test">Using packet sniffers in testing</a></h3>
+
+<p>A number of tools are available for looking at packets. We will discuss
+using <a href="http://www.tcpdump.org/">tcpdump(8)</a>, a common Linux tool
+included in most distributions. Alternatives offerring more-or-less the same
+functionality include:</p>
+<dl>
+ <dt><a href="http://www.ethereal.com">Ethereal</a></dt>
+ <dd>Several people on our mailing list report a preference for this over
+ tcpdump.</dd>
+ <dt><a href="http://netgroup-serv.polito.it/windump/">windump</a></dt>
+ <dd>a Windows version of tcpdump(8), possibly handy if you have Windows
+ boxes in your network</dd>
+ <dt><a
+ href="http://reptile.rug.ac.be/~coder/sniffit/sniffit.html">Sniffit</a></dt>
+ <dd>A linux sniffer that we don't know much about. If you use it, please
+ comment on our mailing list.</dd>
+</dl>
+
+<p>See also this <a
+href="http://www.tlsecurity.net/unix/ids/sniffer/">index</a> of packet
+sniffers.</p>
+
+<p>tcpdump(8) may misbehave if run on the gateways themselves. It is designed
+to look into a normal IP stack and may become confused if you ask it to
+display data from a stack which has IPsec in play.</p>
+
+<p>At one point, the problem was quite severe. Recent versions of tcpdump,
+however, understand IPsec well enough to be usable on a gateway. You can get
+the latest version from <a href="http://www.tcpdump.org/">tcpdump.org</a>.</p>
+
+<p>Even with a recent tcpdump, some care is required. Here is part of a post
+from Henry on the topic:</p>
+<pre>&gt; a) data from sunset to sunrise or the other way is not being
+&gt; encrypted (I am using tcpdump (ver. 3.4) -x/ping -p to check
+&gt; packages)
+
+What *interface* is tcpdump being applied to? Use the -i option to
+control this. It matters! If tcpdump is looking at the ipsecN
+interfaces, e.g. ipsec0, then it is seeing the packets before they are
+encrypted or after they are decrypted, so of course they don't look
+encrypted. You want to have tcpdump looking at the actual hardware
+interfaces, e.g. eth0.
+
+Actually, the only way to be *sure* what you are sending on the wire is to
+have a separate machine eavesdropping on the traffic. Nothing you can do
+on the machines actually running IPsec is 100% guaranteed reliable in this
+area (although tcpdump is a lot better now than it used to be).</pre>
+
+<p>The most certain way to examine IPsec packets is to look at them on the
+wire. For security, you need to be certain, so we recommend doing that. To do
+so, you need a <strong>separate sniffer machine located between the two
+gateways</strong>. This machine can be routing IPsec packets, but it must not
+be an IPsec gateway. Network configuration for such testing is discussed <a
+href="#testnet">above</a>.</p>
+
+<p>Here's another mailing list message with advice on using tcpdump(8):</p>
+<pre>Subject: RE: [Users] Encrypted???
+ Date: Thu, 29 Nov 2001
+ From: "Joe Patterson" &lt;jpatterson@asgardgroup.com&gt;
+
+tcpdump -nl -i $EXT-IF proto 50
+
+-nl tells it not to buffer output or resolve names (if you don't do that it
+may confuse you by not outputing anything for a while), -i $EXT-IF (replace
+with your external interface) tells it what interface to listen on, and
+proto 50 is ESP. Use "proto 51" if for some odd reason you're using AH, and
+"udp port 500" if you want to see the isakmp key exchange/tunnel setup
+packets.
+
+You can also run `tcpdump -nl -i ipsec0` to see what traffic is on that
+virtual interface. Anything you see there *should* be either encrypted or
+dropped (unless you've turned on some strange options in your ipsec.conf
+file)
+
+Another very handy thing is ethereal (http://www.ethereal.com/) which runs
+on just about anything, has a nice gui interface (or a nice text-based
+interface), and does a great job of protocol breakdown. For ESP and AH
+it'll basically just tell you that there's a packet of that protocol, and
+what the spi is, but for isakmp it'll actually show you a lot of the tunnel
+setup information (until it gets to the point in the protocol where isakmp
+is encrypted....)</pre>
+
+<h2><a name="verify.crypt">Verifying encryption</a></h2>
+
+<p>The question of how to verify that messages are actually encrypted has
+been extensively discussed on the mailing list. See this <a
+href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/07/msg00262.html">thread</a>.</p>
+
+<p>If you just want to verify that packets are encrypted, look at them with a
+packet sniffer (see <a href="#tcpdump.test">previous section</a>) located
+between the gateways. The packets should, except for some of the header
+information, be utterly unintelligible. <strong>The output of good encryption
+looks <em>exactly</em> like random noise</strong>. </p>
+
+<p>A packet sniffer can only tell you that the data you looked at was
+encrypted. If you have stronger requirements -- for example if your security
+policy requires verification that plaintext is not leaked during startup or
+under various anomolous conditions -- then you will need to devise much more
+thorough tests. If you do that, please post any results or methodological
+details which your security policy allows you to make public.</p>
+
+<p>You can put recognizable data into ping packets with something like:</p>
+<pre> ping -p feedfacedeadbeef 11.0.1.1</pre>
+
+<p>"feedfacedeadbeef" is a legal hexadecimal pattern that is easy to pick out
+of hex dumps.</p>
+
+<p>For other protocols, you may need to check if you have encrypted data or
+ASCII text. Encrypted data has approximately equal frequencies for all 256
+possible characters. ASCII text has most characters in the printable range
+0x20-0x7f, a few control characters less than 0x20, and none at all in the
+range 0x80-0xff. 0x20, space, is a good character to look for. In normal
+English text space occurs about once in seven characters, versus about once
+in 256 for random or encrypted data.</p>
+
+<p>One thing to watch for: the output of good compression, like that of good
+encryption, looks just like random noise. You cannot tell just by looking at
+a data stream whether it has been compressed, encrypted, or both. You need a
+little care not to mistake compressed data for encrypted data in your
+testing.</p>
+
+<p>Note also that weak encryption also produces random-looking output. You
+cannot tell whether the encryption is strong by looking at the output. To be
+sure of that, you would need to have both the algorithms and the
+implementation examined by experts. </p>
+
+<p>For IPsec, you can get partial assurance from interoperability tests. See
+our <a href="interop.html">interop</a> document. When twenty products all
+claim to implement <a href="glossary.html#3DES">3DES</a>, and they all talk
+to each other, you can be fairly sure they have it right. Of course, you
+might wonder whether all the implementers are consipring to trick you or,
+more plausibly, whether some implementations might have "back doors" so they
+can get also it wrong when required.. If you're seriously worried about
+things like that, you need to get the code you use audited (good luck if it
+is not Open Source), or perhaps to talk to a psychiatrist about treatments
+for paranoia. </p>
+
+<h2><a name="mail.test">Mailing list pointers</a></h2>
+
+<p>Additional information on testing can be found in these <a
+href="mail.html">mailing list</a> messages:</p>
+<ul>
+ <li>a user's detailed <a
+ href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00571.html">setup
+ diary</a> for his testbed network</li>
+ <li>a FreeS/WAN team member's <a
+ href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00425.html">notes</a>
+ from testing at an IPsec interop "bakeoff"</li>
+</ul>
+</body>
+</html>
diff --git a/doc/src/testingtools.html b/doc/src/testingtools.html
new file mode 100644
index 000000000..491b1956c
--- /dev/null
+++ b/doc/src/testingtools.html
@@ -0,0 +1,188 @@
+<html>
+<head>
+<title>FreeS/WAN survey of testing tools</title>
+<!-- Changed by: Michael Richardson, 02-Jan-2002 -->
+<meta name="keywords" content="Linux, IPsec, VPN, security, FreeSWAN, testing, nettools">
+
+<!--
+
+Written by Michael Richardson for the Linux FreeS/WAN project
+Freely distributable under the GNU General Public License
+
+More information at www.freeswan.org
+Feedback to users@lists.freeswan.org
+
+$Id: testingtools.html,v 1.1 2004/03/15 20:35:24 as Exp $
+
+$Log: testingtools.html,v $
+Revision 1.1 2004/03/15 20:35:24 as
+added files from freeswan-2.04-x509-1.5.3
+
+Revision 1.1 2002/03/12 20:57:25 mcr
+ review of tools used for testing FreeSWAN systems.
+
+
+-->
+</head>
+
+<body>
+
+<h1>Survey of testing tools</h1>
+
+<h2><A HREF="http://freshmeat.net/projects/apsend">http://freshmeat.net/projects/apsend</A></h2>
+
+<P>
+About: <A HREF="">APSEND</A> is a TCP/IP packet sender to test firewalls and other
+network applications. It also includes a syn flood option, the land
+DoS attack, a DoS attack against tcpdump running on a UNIX-based
+system, a UDP-flood attack, and a ping flood option. It currently
+supports the following protocols: IP, TCP, UDP, ICMP, Ethernet frames
+and you can also build any other type of protocol using the generic
+option. The scripting language of apsend is already written, but not
+yet public.
+</P>
+
+<P>
+STATUS: The public web site seems to have died
+</P>
+
+<h2><A HREF="http://freshmeat.net/projects/hping2">http://freshmeat.net/projects/hping2</A></h2>
+
+<P>
+About: <A HREF="http://www.hping.org/">hping2</A> is a network tool
+able to send custom ICMP/UDP/TCP packets and to display target replies
+like ping does with ICMP replies. It handles fragmentation and
+arbitrary packet body and size, and can be used to transfer files
+under supported protocols. Using hping2, you can: test firewall rules,
+perform [spoofed] port scanning, test net performance using different
+protocols, packet size, TOS (type of service), and fragmentation, do
+path MTU discovery, tranfer files (even between really Fascist
+firewall rules), perform traceroute-like actions under different
+protocols, fingerprint remote OSs, audit a TCP/IP stack, etc. hping2
+is a good tool for learning TCP/IP.
+</P>
+
+<P>
+This utility has rather complicated usage and no man page at present.
+The documentation is supposed to be in HPING2-HOWTO, but that file
+seems to be absent.
+</P>
+
+<h2><A HREF="http://freshmeat.net/projects/icmpush">http://freshmeat.net/projects/icmpush</A></h2>
+
+<P>
+About: ICMPush is a tool that send ICMP packets fully customized from command
+line. This release supports the ICMP error types Unreach, Parameter
+Problem, Redirect and Source Quench and the ICMP information types
+Timestamp, Address Mask Request, Information Request, Router
+Solicitation, Router Advertisement and Echo Request. Also supports
+ip-spoofing, broadcasting and other useful features. It's really a
+powerful program for testing and debugging TCP/IP stacks and networks.
+</P>
+
+<P>
+</P>
+
+<h2><A HREF="http://freshmeat.net/projects/isic">http://freshmeat.net/projects/isic</A></h2>
+
+<P>
+ISIC sends randomly generated packets to a target computer. Its
+primary uses are to stress-test an IP stack, to find leaks in a
+firewall, and to test the implementation of IDSes and firewalls. The
+user can specify how often the packets will be frags, have IP options,
+TCP options, an urgent pointer, etc. Programs for TCP, UDP, ICMP,
+IP w/ random protocols, and random ethernet frames are included.
+</P>
+
+<h2><A HREF="http://freshmeat.net/projects/sendpacket">http://freshmeat.net/projects/sendpacket</A></h2>
+
+<P>
+Send Packet is a small but powerful program to test how your network
+responds to specific packet content. Via a config file and/or command
+line parameters, you can forge (modify the headers of) your own
+TCP/UDP/ICMP/IP packets and send them through your network. Also,
+following the Easy Sniffer modular philosophy, you can specify wich
+modules you'd like to build.
+</P>
+
+<h2><A HREF="http://freshmeat.net/projects/aicmpsend/">http://freshmeat.net/projects/aicmpsend/</A></h2>
+
+<P>
+AICMPSEND is an ICMP sender with many features including ICMP
+flooding and spoofing. All ICMP flags and codes are implemented. You
+can use this program for various DoS attacks, for ICMP flooding and
+to test firewalls.
+</P>
+
+<h2><A HREF="http://freshmeat.net/projects/sendip/">http://freshmeat.net/projects/sendip/</A></h2>
+
+<P>
+SendIP is a command-line tool to send arbitrary IP packets. It has a
+large number of options to specify the content of every header of a
+RIP, TCP, UDP, ICMP, or raw IPv4/IPv6 packet. It also allows any data
+to be added to the packet. Checksums can be calculated automatically,
+but if you wish to send out wrong checksums, that is supported too.
+</P>
+
+<h2><A HREF="http://laurent.riesterer.free.fr/gasp/index.html">http://laurent.riesterer.free.fr/gasp/index.html</A></h2>
+
+<P>
+GASP stands for 'Generator and Analyzer System for Protocols'. It
+allows you to decode and encode any protocols you specify.
+</P>
+
+<P>
+The main use is probably to test networks applications : you can
+construct packets by hand and test the behavior of your program when
+facing some strange packets. But you can image a lot of other
+application : e.g. manipulating graphical file or executable
+headers. Just describe the specification of the structured data.
+</P>
+
+<P>
+GASP is divided in two parts : a compiler which take the specification
+of the protocols and generate the code to handle it, this code is a
+new Tcl command as GASP in build upon Tcl/Tk and extends the scripting
+facilities provided by Tcl.
+</P>
+
+<h2><A HREF="http://pdump.lucidx.com/">http://pdump.lucidx.com/</A></h2>
+<h2><A HREF="http://freshmeat.net/projects/aps/">http://freshmeat.net/projects/aps/</A></h2>
+<h2><A HREF="http://freshmeat.net/projects/netsed/">http://freshmeat.net/projects/netsed/</A></h2>
+<h2><A HREF="http://www.via.ecp.fr/~bbp/netsh/">http://www.via.ecp.fr/~bbp/netsh/</A></h2>
+<h2><A HREF="http://www.elxsi.de/">http://www.elxsi.de/</A></h2>
+<h2><A HREF="http://www.laurentconstantin.com/us/lcrzo/">http://www.laurentconstantin.com/us/lcrzo/</A></h2>
+<h2><A HREF="http://www.joedog.org/libping/index.html">http://www.joedog.org/libping/index.html</A></h2>
+<h2><A HREF="http://feynman.mme.wilkes.edu/projects/xNetTools/">http://feynman.mme.wilkes.edu/projects/xNetTools/</A></h2>
+<h2><A HREF="http://freshmeat.net/projects/pktsrc/">http://freshmeat.net/projects/pktsrc/</A></h2>
+<h2><A HREF="http://freshmeat.net/projects/lcrzoex/">http://freshmeat.net/projects/lcrzoex/</A></h2>
+<h2><A HREF="http://freshmeat.net/projects/rain/">http://freshmeat.net/projects/rain/</A></h2>
+<P>
+rain is a powerful packet builder for testing the stability of
+hardware and software. Its features include support for all IP
+protocols and the ability to fully customize the packets it sends.
+</P>
+
+<P>(Note, this is not the same as /usr/games/rain)</P>
+
+<h2><A HREF="http://freshmeat.net/projects/libnet">http://freshmeat.net/projects/libnet</A></h2>
+<h2><A HREF="http://freshmeat.net/projects/pftp">http://freshmeat.net/projects/pftp</A></h2>
+<h2><A HREF="http://freshmeat.net/projects/pung">http://freshmeat.net/projects/pung</A></h2>
+
+<P>
+pung is a simple server tester. It tries to connect via TCP/IP to a
+server but does not transfer any data. It is meant to be used in
+scripts that check a list of servers, helping to detect certain common
+problems.
+</P>
+
+<h2><A HREF="http://freshmeat.net/projects/thesunpacketshell">http://freshmeat.net/projects/thesunpacketshell</A></h2>
+<h2><A HREF="http://freshmeat.net/projects/webperformancetrainer">http://freshmeat.net/projects/webperformancetrainer</A></h2>
+<h2><A HREF="http://sourceforge.net/projects/va-ctcs">http://sourceforge.net/projects/va-ctcs</A></h2>
+<h2><A HREF="http://synscan.nss.nu/programs.php">http://synscan.nss.nu/programs.php</A></h2>
+<h2><A HREF="http://sourceforge.net/projects/va-ctcs">http://sourceforge.net/projects/va-ctcs</A></h2>
+<h2><A HREF="http://freshmeat.net/projects/ettercap/">http://freshmeat.net/projects/ettercap/</A></h2>
+<h2><A HREF="http://www.dtek.chalmers.se/~d3august/xt/index.html">http://www.dtek.chalmers.se/~d3august/xt/index.html</A></h2>
+<h2><A HREF="http://www.opersys.com/LTT/">http://www.opersys.com/LTT/</A></h2>
+<h2><A HREF="http://packetstorm.securify.com/DoS/indexdate.shtml">http://packetstorm.securify.com/DoS/indexdate.shtml</A></h2>
+<H2> <A HREF="http://comnet.technion.ac.il/~cn1w02/">TCP/IP noise simulator</A></H2>
diff --git a/doc/src/trouble.html b/doc/src/trouble.html
new file mode 100644
index 000000000..604264c01
--- /dev/null
+++ b/doc/src/trouble.html
@@ -0,0 +1,840 @@
+<HTML>
+<HEAD>
+ <TITLE>FreeS/WAN troubleshooting</TITLE>
+ <meta name="keywords" content="Linux, IPSEC, VPN, security, FreeSWAN, troubleshooting, debugging">
+<!--
+ Written by Claudia Schmeing for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+CVS information:
+RCS ID: $Id: trouble.html,v 1.1 2004/03/15 20:35:24 as Exp $
+Last changed: $Date: 2004/03/15 20:35:24 $
+Revision number: $Revision: 1.1 $
+
+CVS revision numbers do not correspond to FreeS/WAN release numbers.
+-->
+
+</HEAD>
+<BODY>
+
+<H1><A NAME="trouble"></A>Linux FreeS/WAN Troubleshooting Guide</H1>
+
+<H2><A NAME="overview"></A>Overview</H2>
+
+<P>
+This document covers several general places where you might have a problem:</P>
+<OL>
+ <LI><A HREF="#install">During install</A>.</LI>
+ <LI><A HREF="#negotiation">During the negotiation process</A>.</LI>
+ <LI><A HREF="#use">Using an established connection</A>.</LI>
+</OL>
+<P>This document also contains <A HREF="#notes">notes</A> which
+expand on points made in these sections, and tips for
+<A HREF="#prob.report">problem
+reporting</A>. If the other end of your connection is not FreeS/WAN,
+you'll also want to read our
+<A HREF="interop.html#interop.problem">interoperation</A> document.</P>
+<H2><A NAME="install"></A>1. During Install</H2>
+<H3>1.1 RPM install gotchas</H3>
+<P>With the RPM method:</P>
+<UL>
+<LI>Be sure you have installed both the userland tools and the kernel
+ components. One will not work without the other. For example, when using
+ FreeS/WAN-produced RPMs for our 2.04 release, you need both:
+<PRE> freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm
+ freeswan-module-2.04_2.4.20_20.9-0.i386.rpm
+</PRE>
+</LI>
+</UL>
+<H3>1.2 Problems installing from source</H3>
+<P>When installing from source, you may find these problems:</P>
+<UL>
+ <LI>Missing library. See <A HREF="faq.html#gmp.h_missing">this</A>
+ FAQ.</LI>
+ <LI>Missing utilities required for compile. See this
+ <A HREF="install.html#tool.lib">checklist</A>.</LI>
+ <LI>Kernel version incompatibility. See <A HREF="faq.html#k.versions">this</A>
+ FAQ.</LI>
+ <LI>Another compile problem. Find information in the out.* files,
+ ie. out.kpatch, out.kbuild, created at compile time in the top-level
+ Linux FreeS/WAN directory. Error messages generated by KLIPS during
+ the boot sequence are accessible with the <VAR>dmesg</VAR> command.
+ <BR>
+ Check the list archives and the List in Brief to see if this is a
+ known issue. If it is not, report it to the bugs list as described
+ in our <A HREF="#prob.report">problem reporting</A> section. In some
+ cases, you may be asked to provide debugging information using gdb;
+ details <A HREF="#gdb">below</A>.</LI>
+ <LI>If your kernel compiles but you fail to install your new
+ FreeS/WAN-enabled kernel, review the sections on <A HREF="install.html#newk">installing
+ the patched kernel</A>, and <A HREF="install.html#testinstall">testing</A>
+ to see if install succeeded.</LI>
+</UL>
+<H3><A NAME="install.check"></A>1.3 Install checks</H3>
+<P><VAR>ipsec verify</VAR> checks a number
+of FreeS/WAN essentials. Here are some hints on what do to when your
+system doesn't check out:</P>
+<P>
+<TABLE border=1>
+<TR>
+<TD><STRONG>Problem</STRONG></TD>
+<TD><STRONG>Status</STRONG></TD>
+<TD><STRONG>Action</STRONG></TD>
+</TR>
+<TR>
+<TD><VAR>ipsec</VAR> not on-path</TD>
+<TD>&nbsp;</TD>
+<TD><P>Add <VAR>/usr/local/sbin</VAR> to your PATH.</P></TD>
+</TR>
+<TR>
+<TD>Missing KLIPS support</TD>
+<TD><FONT COLOR="#FF0000">critical</FONT></TD>
+<TD>See <A HREF="faq.html#noKLIPS">this FAQ.</A></TD>
+</TR>
+<TR>
+<TD>No RSA private key</TD>
+<TD>&nbsp;</TD>
+<TD>
+<P>Follow <A HREF="install.html#genrsakey">these
+instructions</A> to create an RSA key pair for your host. RSA keys are:</P>
+<UL>
+<LI>required for opportunistic encryption, and</LI>
+<LI>our preferred method to authenticate pre-configured connections.</LI>
+</UL>
+</TD>
+</TR>
+<TR>
+<TD><VAR>pluto</VAR> not running</TD>
+<TD><FONT COLOR="#FF0000">critical</FONT></TD>
+<TD><PRE>service ipsec start</PRE></TD>
+</TR>
+<TR>
+<TD>No port 500 hole</TD>
+<TD><FONT COLOR="#FF0000">critical</FONT></TD>
+<TD>Open port 500 for IKE negotiation.</TD>
+</TR>
+<TR>
+<TD>Port 500 check N/A</TD>
+<TD>&nbsp;</TD>
+<TD>Check that port 500 is open for IKE negotiation.</TD>
+</TR>
+<TR>
+<TD>Failed DNS checks</TD>
+<TD>&nbsp;</TD>
+<TD>Opportunistic encryption requires information from DNS.
+To set this up, see <A HREF="quickstart.html#opp.setup">our instructions</A>.
+</TD>
+</TR>
+<TR>
+<TD>No public IP address</TD>
+<TD>&nbsp;</TD>
+<TD>Check that the interface which you want to protect with IPSec is up and
+running.</TD>
+</TR>
+</TABLE>
+
+
+<H3><A NAME="oe.trouble"></A>1.3 Troubleshooting OE</H3>
+<P>OE should work with no local configuration, if you have posted
+DNS TXT records according to the instructions in our
+<A HREF="quickstart.html">quickstart guide</A>.
+If you encounter trouble, try these hints.
+We welcome additional hints via the
+<A HREF="mail.html">users' mailing list</A>.</P>
+
+<TABLE border=1>
+<TR>
+<TD><STRONG>Symptom</STRONG></TD>
+<TD><STRONG>Problem</STRONG></TD>
+<TD><STRONG>Action</STRONG></TD>
+</TR>
+<TR>
+<TD>
+You're running FreeS/WAN 2.01 (or later),
+and initiating a connection to FreeS/WAN
+2.00 (or earlier).
+In your logs, you see a message like:
+<pre>no RSA public key known for '192.0.2.13';
+DNS search for KEY failed (no KEY record
+for 13.2.0.192.in-addr.arpa.)</pre>
+The older FreeS/WAN logs no error.
+</TD>
+<TD>
+<A NAME="oe.trouble.flagday"></A>
+A protocol level incompatibility between 2.01 (or later) and
+2.00 (or earlier) causes this error. It occurs when a FreeS/WAN 2.01
+(or later) box for which no KEY record is posted attempts to initiate an OE
+connection to older FreeS/WAN versions (2.00 and earlier).
+Note that older versions can initiate to newer versions without this error.
+</TD>
+<TD>If you control the peer host, upgrade its FreeS/WAN to 2.01 (or later), and
+post new style TXT records for it. If not, but if you know its sysadmin,
+perhaps a quick note is in order. If neither option is possible, you can
+ease the transition by posting an old style KEY record (created with a
+command like "ipsec&nbsp;showhostkey&nbsp;--key") to the reverse map for
+the FreeS/WAN 2.01 (or later) box.</TD>
+</TR>
+<TR>
+<TD>OE host is very slow to contact other hosts.</TD>
+<TD>Slow DNS service while running OE.</TD>
+<TD>It's a good idea to run a caching DNS server on your OE host,
+as outlined in <A HREF="http://lists.freeswan.org/pipermail/design/2003-January/004205.html">this
+mailing list message</A>. If your DNS servers are elsewhere,
+put their IPs
+in the <VAR>clear</VAR> policy group, and
+re-read groups with <PRE>ipsec auto --rereadgroups</PRE>
+</TD>
+</TR>
+<TR>
+<TD>
+<PRE>Can't Opportunistically initiate for
+192.0.2.2 to 192.0.2.3: no TXT record
+for 13.2.0.192.in-addr.arpa.</PRE>
+</TD>
+<TD>Peer is not set up for OE.</TD>
+<TD><P>None. Plenty of hosts on the Internet
+do not run OE. If, however, you have set OE up on that peer, this may
+indicate that you need to wait up to 48 hours
+for its DNS records to propagate.</P></TD>
+</TR>
+<TR>
+<TD><VAR>ipsec verify</VAR> does not find DNS records:
+<PRE>...
+Looking for TXT in forward map:
+ xy.example.com...[FAILED]
+Looking for TXT in reverse map...[FAILED]
+...</PRE>
+
+You also experience authentication failure:<BR>
+<PRE>Possible authentication failure:
+no acceptable response to our
+first encrypted message</PRE>
+</TD>
+
+<TD>DNS records are not posted or have not propagated.</TD>
+<TD>Did you post the DNS records necessary for OE? If not,
+do so using the instructions in our
+<A HREF="quickstart.html#quickstart">quickstart guide</A>.
+If so, wait up to 48 hours for the DNS records to propagate.</TD>
+</TR>
+<TR>
+<TD><VAR>ipsec verify</VAR> does not find DNS records, and you experience
+authentication failure.</TD>
+<TD>For iOE, your ID
+does not match location of
+forward DNS record.</TD>
+<TD>In <VAR>config setup</VAR>, change
+<VAR>myid=</VAR> to match the forward DNS where you posted the record.
+Restart FreeS/WAN.
+ For reference, see our
+<A HREF="quickstart.html#opp.client">iOE instructions</A>.</TD>
+</TR>
+<TR>
+<TD><VAR>ipsec verify</VAR> finds DNS records, yet there is
+still authentication failure. ( ? )</TD>
+<TD>DNS records are malformed.</TD>
+<TD>Re-create the records and send new copies to your DNS administrator.</TD>
+</TR>
+<TR>
+<TD><VAR>ipsec verify</VAR> finds DNS records, yet there is
+still authentication failure. ( ? )</TD>
+<TD>DNS records show different keys for a gateway vs. its subnet hosts.</TD>
+<TD>All TXT records for boxes protected by an OE gateway must contain the
+gateway's public key. Re-create and re-post any incorrect records using
+<A HREF="quickstart.html#opp.incoming">these instructions</A>.</TD>
+</TR>
+<TR>
+<TD>OE gateway loses connectivity to its subnet. The gateway's
+routing table shows routes to the subnet through IPsec interfaces.</TD>
+<TD>The subnet is part of the <VAR>private</VAR> or <VAR>block</VAR>
+policy group on the gateway.</TD>
+<TD>Remove the subnet from the group, and reread
+groups with <PRE>ipsec auto --rereadgroups</PRE></TD>
+</TR>
+<TR>
+<TD>OE does not work to hosts on the local LAN.</TD>
+<TD>This is a known issue.</TD>
+<TD>See <A HREF="opportunism.known-issues">this list</A> of known issues
+with OE.
+</TD>
+</TR>
+
+<TR>
+<TD>FreeS/WAN does not seem to be executing your default policy. In your
+logs, you see a message like:
+<PRE>/etc/ipsec.d/policies/iprivate-or-clear"
+line 14: subnet "0.0.0.0/0",
+source 192.0.2.13/32,
+already "private-or-clear"</PRE>
+</TD>
+<TD><A HREF="glossary.html#fullnet">Fullnet</A> in a policy group file defines
+your default policy. Fullnet should normally be present in only one policy
+group file. The fine print: you can have two default policies defined so long
+as they protect different local endpoints (e.g. the FreeS/WAN gateway and a
+subnet).</TD>
+<TD>
+Find all policies which contain fullnet with:<br>
+<PRE>grep -F 0.0.0.0/0 /etc/ipsec.d/policies/*</PRE>
+then remove the unwanted occurrence(s).
+</TD>
+</TR>
+
+</TABLE>
+
+
+<H2><A NAME="negotiation"></A>2. During Negotiation</H2>
+<P>When you fail to bring up a tunnel, you'll need to find out:</P>
+<UL>
+<LI><A HREF="#state">what your connection state is,</A> and often</LI>
+<LI><A HREF="#find.pluto.error">an error message</A>.</LI>
+</UL>
+<P>before you can
+<A HREF="#interpret.pluto.error">diagnose your problem</A>.</P>
+<H3><A NAME="state"></A>2.1 Determine Connection State</H3>
+<H4>Finding current state</H4>
+<P>You can see connection states (STATE_MAIN_I1 and so on) when you
+bring up a connection on the command line. If you have missed this,
+or brought up your connection automatically, use:
+</P>
+<PRE>ipsec auto --status</PRE>
+<P>The most relevant state is the last one reached.</P>
+<H4><VAR>What's this supposed to look like?</VAR></H4>
+<P>Negotiations should proceed though various states, in the processes of:</P>
+<OL>
+<LI>IKE negotiations (aka Phase 1, Main Mode, STATE_MAIN_*)</LI>
+<LI>IPSEC negotiations (aka Phase 2, Quick Mode, STATE_QUICK_*)</LI>
+</OL>
+<P>These are done and a connection is established when you see messages like:</P>
+<PRE> 000 #21: &quot;myconn&quot; STATE_MAIN_I4 (ISAKMP SA established)...
+ 000 #2: &quot;myconn&quot; STATE_QUICK_I2 (sent QI2, IPsec SA established)...</PRE><P>
+Look for the key phrases are &quot;ISAKMP SA established&quot; and &quot;IPSec
+SA established&quot;, with the relevant connection name. Often, this happens
+at STATE_MAIN_I4 and STATE_QUICK_I2, respectively.</P>
+<P><VAR>ipsec auto --status</VAR> will tell you what states <STRONG>have
+been achieved</STRONG>, rather than the current state. Since
+determining the current state is rather more difficult to do, current
+state information is not available from Linux FreeS/WAN. If you are
+actively bringing a connection up, the status report's last states
+for that connection likely reflect its current state. Beware, though,
+of the case where a connection was correctly brought up but is now
+downed: Linux FreeS/WAN will not notice this until it attempts to
+rekey. Meanwhile, the last known state indicates that the connection
+has been established.</P>
+<P>If your connection is stuck at STATE_MAIN_I1, skip straight to
+<A HREF="#ikepath">here</A>.
+
+<H3><A NAME="find.pluto.error"></A>2.2 Finding error text</H3>
+<P>Solving most errors will require you to find verbose error text,
+either on the command line or in the logs.</P>
+<H4>Verbose start for more information</H4>
+<P>
+Note that you can get more detail from <VAR>ipsec auto</VAR> using
+the --verbose flag:</P>
+<PRE STYLE="margin-bottom: 0.2in"> ipsec auto --verbose --up west-east</PRE><P>
+More complete information can be gleaned from the <A HREF="#logusage">log
+files</A>.</P>
+
+<H4>Debug levels count</H4>
+<P>The amount of description you'll get here depends on ipsec.conf debug
+settings, <VAR>klipsdebug</VAR>= and <VAR>plutodebug</VAR>=.
+When troubleshooting, set at least one of these to <VAR>all</VAR>, and
+when done, reset it to <VAR>none</VAR> so your logs don't fill up.
+Note that you must have enabled the <VAR>klipsdebug</VAR>
+<A HREF="install.html#allbut">compile-time option</A> for the
+<VAR>klipsdebug</VAR> configuration switch to work.</P>
+<P>For negotiation problems <VAR>plutodebug</VAR> is most relevant.
+<VAR>klipsdebug</VAR> applies mainly to attempts to use an
+already-established connection. See also <A HREF="ipsec.html#parts">this</A>
+description of the division of duties within Linux FreeS/WAN.</P>
+<P>After raising your debug levels, restart Linux FreeS/WAN to ensure
+that ipsec.conf is reread, then recreate the error to generate
+verbose logs.
+</P>
+<H4><VAR>ipsec barf</VAR> for lots of debugging information</H4>
+<P>
+<A HREF="manpage.d/ipsec_barf.8.html"><VAR>ipsec barf (8)</VAR></A>
+collects a bunch of useful debugging information, including these logs
+Use the command</P>
+<PRE>
+ ipsec barf &gt; barf.west
+</PRE>
+<P>to generate one.</P>
+<H4>Find the error</H4>
+<P>Search out the failure point in your logs.
+ Are there a handful of lines which succinctly describe how
+things are going wrong or contrary to your expectation? Sometimes the
+failure point is not immediately obvious: Linux FreeS/WAN's errors
+are usually not marked &quot;Error&quot;. Have a look in the
+<A HREF="faq.html">FAQ</A>
+for what some common failures look like.</P>
+<P>Tip: problems snowball.
+Focus your efforts on the first problem, which is likely to be the
+cause of later errors.</P>
+<H4>Play both sides</H4>
+<P>Also find error text on the peer IPSec box.
+This gives you two perspectives on the same failure.</P>
+<P>At times you will require information which only one side has.
+The peer can merely indicate the presence of an error, and its
+approximate point in the negotiations. If one side keeps retrying,
+it may be because there is a show stopper on the other side.
+Have a look at the other side and figure out what it doesn't like.</P>
+<P>If the other end is not Linux FreeS/WAN, the principle is the
+same: replicate the error with its most verbose logging on, and
+capture the output to a file.</P>
+<H3><A NAME="interpret.pluto.error"></A>2.3 Interpreting a Negotiation Error</H3>
+<H4><A NAME="ikepath"></A>Connection stuck at STATE_MAIN_I1</H4>
+<P>This error commonly happens because IKE (port 500) packets, needed
+to negotiate an IPSec connection, cannot travel freely between your IPSec
+gateways. See <A HREF="firewall.html#packets">our firewall document</A>
+for details.</P>
+<H4>Other errors</H4>
+<P>Other errors require a bit more digging. Use the following resources:</P>
+<UL>
+ <LI><A HREF="faq.html">the FAQ</A> . Since this document is
+ constantly updated, the snapshot's FAQ may have a new entry relevant
+ to your problem.</LI>
+ <LI>our <A HREF="background.html">background document</A> .
+ Special considerations which, while not central to Linux FreeS/WAN,
+ are often tripped over. Includes problems with
+ <a href="background.html#MTU.trouble">packet fragmentation</a>,
+ and considerations for
+ testing opportunism.</LI>
+ <LI>the <A HREF="mail.html#lists">list archives</A>. Each of the
+ searchable archives works differently, so it's worth checking each.
+ Use a search term which is generic, but identifies your error, for
+ example &quot;No connection is known for&quot;.
+ <BR>
+ Often, you will find that your question has been answered in the
+ past. Finding an archived answer is quicker than asking the list.
+ You may, however, find similar questions without answers. If you do,
+ send their URLs to the list with your trouble report. The additional
+ examples may help the list tech support person find your answer.</LI>
+ <LI>Look into the code where the error is being generated. The
+ pluto code is nicely documented with comments and meaningful
+ variable names.</LI>
+</UL>
+<P>If you have failed to solve your problem with the help of these
+resources, send a detailed problem report to the users list,
+following these <A HREF="#prob.report">guidelines</A>.</P>
+<H2><A NAME="use"></A>3. Using a Connection</H2>
+<H3>3.1 Orienting yourself</H3>
+<H4><VAR>How do I know if it works?</VAR></H4>
+<P>Test your connection by sending packets through it. The simplest way
+to do this is with ping, but the ping needs to <STRONG>test the correct
+tunnel.</STRONG> See <A HREF="#testgates">this example scenario</A> if
+you don't understand this.<P>
+<P>If your ping returns, test any other connections you've brought
+u all check out, great. You may wish to <A HREF="#bigpacket">test
+with large packets</A> for MTU problems.</P>
+<H4><VAR>ipsec barf</VAR> is useful again</H4>
+<P>If your ping fails to return, generate an ipsec barf debugging
+report on each IPSec gateway. On a non-Linux FreeS/WAN
+implementation, gather equivalent information. Use this, and the tips
+in the next sections, to troubleshoot. Are you sure that both
+endpoints are capable of hearing and responding to ping?</P>
+<H3>3.2 Those pesky configuration errors</H3>
+<P>IPSec may be dropping your ping packets since they do not belong in the
+tunnels you have constructed:</P>
+<UL>
+<LI>Your ping may not test the tunnel you intend to test. For details, see our
+<A HREF="faq.html#cantping">&quot;I can't ping&quot;</A> FAQ.
+</LI>
+<LI>
+Alternately, you may have a configuration error.
+For example, you may have configured one of the four possible tunnels between
+two gateways, but not the one required to secure the important
+traffic you're now testing. In this case, add and start the tunnel,
+and try again.
+</LI>
+</UL>
+<P>In either case, you will often see a message like:</P>
+<PRE>klipsdebug... no eroute</PRE>
+<P>which we discuss in <A HREF="faq.html#no_eroute">this
+FAQ</A>.</P>
+<P>Note:</P>
+<UL>
+<LI><A HREF="glossary.html#NAT.gloss">Network Address Translation (NAT)</A>
+and <A HREF="glossary.html#masq">IP masquerade</A> may have an effect on
+which tunnels you need to configure.</LI>
+<LI>When testing a tunnel that protects a multi-node subnet, try several
+subnet nodes as ping targets, in case one node is routing incorrectly.</LI>
+</UL>
+<H3><A NAME="route.firewall"></A>3.3 Check Routing and Firewalling</H3>
+<P>If you've confirmed your configuration assumptions, the problem is
+almost certainly with routing or firewalling. Isolate the problem
+using interface statistics, firewall statistics, or a packet sniffer.</P>
+<H4>Background:</H4>
+<UL>
+ <LI>Linux FreeS/WAN supplies all the special routing it needs;
+ you need only route packets out through your IPSec gateway. Verify
+ that on the <VAR>subnetted</VAR> machines you are using for your
+ ping-test, your routing is as expected. I have seen a tunnel
+ &quot;fail&quot; because the subnet machine sending packets
+ out an alternate gateway (not our IPSec gateway) on their return path.
+ <LI>Linux FreeS/WAN requires particular <A HREF="firewall.html">
+ firewalling considerations</A>.
+ Check the firewall rules on your IPSec gateways and ensure that they
+ allow IPSec traffic through. Be sure that no other machine - for
+ example a router between the gateways - is blocking your IPSec
+ packets.
+</UL>
+<H4><A NAME="ifconfig"></A>View Interface and Firewall
+Statistics</H4>
+<P>Interface reports and firewall statistics can help you track down
+lost packets at a glance. Check any firewall statistics you may be keeping
+on your IPSec gateways, for dropped packets.</P>
+
+<P><STRONG>Tip</STRONG>: You can take a snapshot of the packets processed
+by your firewall with:</P>
+
+<PRE> iptables -L -n -v</PRE>
+
+<P>You can get creative with "diff" to find out what happens to a
+particular packet during transmission.</P>
+
+<P>Both <VAR>cat /proc/net/dev</VAR> and <VAR>ifconfig</VAR> display
+interface statistics, and both are included in <VAR>ipsec barf</VAR>. Use
+either to check if any interface has dropped packets. If you find
+that one has, test whether this is related to your ping. While you
+ping continuously, print that interface's statistics several times.
+Does its drop count increase in proportion to the ping? If so, check
+why the packets are dropped there.</P>
+
+<P>To do this, look at the firewall rules that apply to that interface. If the
+interface is an IPSec interface, more information may be available in
+the log. Grep for the word &quot;drop&quot; in a log which was
+created with <VAR>klipsdebug=all</VAR> as the error happened.</P>
+<P>See also this <A HREF="#ifconfig1">discussion</A> on interpreting
+<VAR>ifconfig</VAR> statistics.</P>
+<H3><A NAME="sniff"></A>3.4 When in doubt, sniff it out</H3>
+<P>If you have checked configuration assumptions, routing, and
+firewall rules, and your interface statistics yield no clue, it
+remains for you to investigate the mystery of the lost packet by the
+most thorough method: with a packet sniffer (providing, of course,
+that this is legal where you are working).
+<P>In order to detect packets on the ipsec virtual interfaces,
+you will need an up-to-date sniffer (tcpdump, ethereal, ksnuffle) on
+your IPSec gateway machines. You may also find it useful to sniff the ping
+endpoints.</P>
+<H4>Anticipate your packets' path</H4>
+<P>Ping, and examine each interface along the projected path, checking for your
+ping's arrival. If it doesn't get to the the next stop, you have narrowed
+down where to look for it. In this way, you can isolate a problem area,
+and narrow your troubleshooting focus.</P>
+<P>Within a machine running Linux FreeS/WAN, this
+<A HREF="firewall.html#packets">packet flow diagram</A> will help you
+anticipate a packet's path.
+<P>Note that:</P>
+<UL>
+<LI>
+from the perspective of the tunneled packet, the entire tunnel is one hop.
+That's explained in <A HREF="faq.html#no_trace">this</A> FAQ.
+</LI>
+<LI>
+ an encapsulated IPSec packet will look different, when
+sniffed, from the plaintext packet which generated it. You
+can see plaintext packets entering an IPSec interface and the
+resulting cyphertext packets as they emerge from the corresponding
+physical interface.
+</LI>
+</UL>
+<P>Once you isolate where the packet is lost, take a closer look at
+firewall rules, routing and configuration assumptions as they affect
+that specific area. If the packet is lost on an IPSec gateway, comb
+through <VAR>klipsdebug</VAR> output for anomalies.
+</P>
+<P>If the packet goes through both gateways successfully and reaches
+the ping target, but does not return, suspect routing. Check that the
+ping target routes packets back to the IPSec gateway.</P>
+<H3><A NAME="find.use.error"></A>3.5 Check your logs</H3>
+<P>Here, too, log information can be useful. Start with the
+<A HREF="#find.pluto.error">guidelines above</A>.</P>
+<P>For connection use problems, set <VAR>klipsdebug=all</VAR>. Note
+that you must have enabled the <VAR>klipsdebug</VAR>
+<A HREF="install.html#allbut">compile-time option</A> to do this.
+Restart Linux FreeS/WAN so that it rereads <VAR>ipsec.conf</VAR>,
+then recreate the error condition. When searching through
+<VAR>klipsdebug</VAR> data, look especially for the keywords
+&quot;drop&quot; (as in dropped packets) and &quot;error&quot;.</P>
+<P>Often the problem with connection use is not software error, but
+rather that the software is behaving contrary to expectation.
+</P>
+<H4><A NAME="interpret.use.error"></A>Interpreting log text</H4>
+<P>To interpret the Linux FreeS/WAN log text you've found, use the
+same resources as indicated for troubleshooting
+connection negotiation:
+<A HREF="faq.html">the FAQ</A> , our
+<A HREF="background.html">background document</A>, and the
+<A HREF="mail.html#lists">list archives</A>.
+Looking in the KLIPS code is only for the very brave.</P>
+<P>If you are still stuck, send a <A HREF="#prob.report">detailed
+problem report</A> to the users' list.</P>
+<H3><A NAME="bigpacket"></A>3.6 More testing for the truly thorough</H3>
+<H4>Large Packets</H4>
+<P>If each of your connections passed the ping test, you may wish to
+test by pinging with large packets (2000 bytes or larger). If it does
+not return, suspect MTU issues, and see this <A HREF="background.html#MTU.trouble">discussion</A>.</P>
+<H4>Stress Tests</H4>
+<P>In most users' view, a simple ping test, and perhaps a
+large-packet ping test suffice to indicate a working IPSec
+connection.</P>
+<P>Some people might like to do additional stress tests prior to
+production use. They may be interested in this <A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00224.html">testing
+protocol</A> we use at interoperation conferences, aka &quot;bakeoffs&quot;.
+We also have a <VAR>testing</VAR> directory that ships with the
+release.</P>
+<H2><A NAME="prob.report"></A>4. Problem Reporting</H2>
+<H3>4.1 How to ask for help</H3>
+<P>Ask for troubleshooting help on the users' mailing list,
+<A HREF="mailto:users@lists.freeswan.org">users@lists.freeswan.org</A>.
+While sometimes an initial query with a quick description of your
+intent and error will twig someone's memory of a similar problem,
+it's often necessary to send a second mail with a complete problem
+report.
+</P>
+
+
+<P>When reporting problems to the mailing list(s), please include:
+</P>
+<UL>
+ <LI>a brief description of the problem</LI>
+ <LI>if it's a compile problem, the actual output from make,
+ showing the problem. Try to edit it down to only the relevant part,
+ but when in doubt, be as complete as you can. If it's a kernel
+ compile problem, any relevant out.* files</LI>
+ <LI>if it's a run-time problem, pointers to where we can find the
+ complete output from &quot;ipsec barf&quot; from BOTH ENDS (not just
+ one of them). Remember that it's common outside the US and Canada to
+ pay for download volume, so if you can't post barfs on the web and
+ send the URL to the mailing list, at least compress them with tar or
+ gzip.<BR>
+ If you can, try to simplify the case that is causing the problem.
+ In particular, if you clear your logs, start FreeS/WAN with no other
+ connections running, cause the problem to happen, and then do <VAR>ipsec
+ barf</VAR> on both ends immediately, that gives the smallest and
+ least cluttered output.</LI>
+ <LI>any other error messages, complaints, etc. that you saw.
+ Please send the complete text of the messages, not just a summary.</LI>
+ <LI>what your network setup is. Include subnets, gateway
+ addresses, etc. A schematic diagram is a
+ good format for this information.</LI>
+ <LI>exactly what you were trying to do with Linux FreeS/WAN, and
+ exactly what went wrong</LI>
+ <LI>a fix, if you have one. But remember, you are sending mail to
+ people all over the world; US residents and US citizens in
+ particular, please read doc/exportlaws.html before sending code --
+ even small bug fixes -- to the list or to us.</LI>
+ <LI>When in doubt about whether to include some seemingly-trivial
+ item of information, include it. It is rare for problem reports to
+ have too much information, and common for them to have too little.</LI>
+</UL>
+
+<P>Here are some good general guidelines on bug reporting:
+<a href="http://tuxedo.org/~esr/faqs/smart-questions.html">How To Ask Questions
+The Smart Way</a> and <a
+href="http://www.chiark.greenend.org.uk/~sgtatham/bugs.html">How to Report
+Bugs Effectively</a>.</p>
+
+
+<H3>4.2 Where to ask</H3>
+<P>To report a problem, send mail about it to the users' list. If you
+are certain that you have found a bug, report it to the bugs list. If
+you encounter a problem while doing your own coding on the Linux
+FreeS/WAN codebase and think it is of interest to the design team,
+notify the design list. When in doubt, default to the users' list.
+More information about the mailing lists is found <A HREF="mail.html#lists">here</A>.</P>
+<P>For a number of reasons -- including export-control regulations
+affecting almost any <STRONG>private</STRONG> discussion of
+encryption software -- we prefer that problem reports and discussions
+go to the lists, not directly to the team. Beware that the list goes
+worldwide; US citizens, read this important information about your
+<A HREF="politics.html#exlaw">export laws</A>. If you're using this
+software, you really should be on the lists. To get onto them, visit
+<A HREF="http://lists.freeswan.org/">lists.freeswan.org</A>.</P>
+<P>If you do send private mail to our coders or want a private reply
+from them, please make sure that the return address on your mail
+(From or Reply-To header) is a valid one. They have more important
+things to do than to unravel addresses that have been mangled in an
+attempt to confuse spammers.
+</P>
+<H2><A NAME="notes"></A>5. Additional Notes on Troubleshooting</H2>
+<P>The following sections supplement the Guide: <A HREF="#system.info">information
+available on your system</A>; <A HREF="#testgates">testing between
+security gateways</A>; <A HREF="#ifconfig1">ifconfig reports for
+KLIPS debugging</A>; <A HREF="#gdb">using GDB on Pluto</A>.</P>
+<H3><A NAME="system.info"></A>5.1 Information available on your
+system</H3>
+<H4><A NAME="logusage"></A>Logs used</H4>
+<P>Linux FreeS/WAN logs to:</P>
+<UL>
+ <LI>/var/log/secure (or, on Debian, /var/log/auth.log)</LI>
+ <LI>/var/log/messages</LI>
+</UL>
+<P>Check both places to get full information. If you find nothing,
+check your <VAR>syslogd.conf(5)</VAR> to see where your
+/etc/syslog.conf or equivalent is directing <VAR>authpriv</VAR>
+messages.</P>
+<H4><A NAME="pages"></A>man pages provided</H4>
+<DL>
+ <DT><A HREF="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A>
+ </DT><DD>
+ Manual page for IPSEC configuration file.
+ </DD><DT>
+ <A HREF="manpage.d/ipsec.8.html">ipsec(8)</A>
+ </DT><DD STYLE="margin-bottom: 0.2in">
+ Primary man page for ipsec utilities.
+ </DD></DL>
+<P>
+Other man pages are on <A HREF="manpages.html">this list</A> and in</P>
+<UL>
+ <LI>/usr/local/man/man3</LI>
+ <LI>/usr/local/man/man5</LI>
+ <LI>/usr/local/man/man8/ipsec_*</LI>
+</UL>
+<H4><A NAME="statusinfo"></A>Status information</H4>
+<DL>
+ <DT>ipsec auto --status
+ </DT><DD>
+ Command to get status report from running system. Displays Pluto's
+ state. Includes the list of connections which are currently &quot;added&quot;
+ to Pluto's internal database; lists state objects reflecting ISAKMP
+ and IPsec SAs being negotiated or installed.
+ </DD><DT>
+ ipsec look
+ </DT><DD>
+ Brief status info.
+ </DD><DT>
+ ipsec barf
+ </DT><DD STYLE="margin-bottom: 0.2in">
+ Copious debugging info.
+ </DD></DL>
+<H3>
+<A NAME="testgates"></A>5.2 Testing between security gateways</H3>
+<P>Sometimes you need to test a subnet-subnet tunnel. This is a
+tunnel between two security gateways, which protects traffic on
+behalf of the subnets behind these gateways. On this network:</P>
+<PRE> Sunset==========West------------------East=========Sunrise
+ IPSec gateway IPSec gateway
+ local net untrusted net local net</PRE><P>
+you might name this tunnel sunset-sunrise. You can test this tunnel
+by having a machine behind one gateway ping a machine behind the
+other gateway, but this is not always convenient or even possible.</P>
+<P>Simply pinging one gateway from the other is not useful. Such a
+ping does not normally go through the tunnel. <STRONG>The tunnel
+handles traffic between the two protected subnets, not between the
+gateways</STRONG> . Depending on the routing in place, a ping might</P>
+<UL>
+ <LI>either succeed by finding an
+ unencrypted route</LI>
+ <LI>or fail by finding no route. Packets without an IPSEC eroute
+ are discarded.</LI>
+</UL>
+<P><STRONG>Neither event tells you anything about the tunnel</STRONG>.
+You can explicitly create an eroute to force such packets through the
+tunnel, or you can create additional tunnels as described in our
+<A HREF="config.html#multitunnel">configuration document</A>, but
+those may be unnecessary complications in your situation.</P>
+<P>The trick is to explicitly test between <STRONG>both gateways'
+private-side IP addresses</STRONG>. Since the private-side interfaces
+are on the protected subnets, the resulting packets do go via the
+tunnel. Use either ping -I or traceroute -i, both of which allow you
+to specify a source interface. (Note: unsupported on older Linuxes).
+The same principles apply for a road warrior (or other) case where
+only one end of your tunnel is a subnet.</P>
+<H3><A NAME="ifconfig1"></A>5.3 ifconfig reports for KLIPS debugging</H3>
+<P>When diagnosing problems using ifconfig statistics, you may wonder
+what type of activity increments a particular counter for an ipsecN
+device. Here's an index, posted by KLIPS developer Richard Guy
+Briggs:</P>
+<PRE>Here is a catalogue of the types of errors that can occur for which
+statistics are kept when transmitting and receiving packets via klips.
+I notice that they are not necessarily logged in the right counter.
+. . .
+
+Sources of ifconfig statistics for ipsec devices
+
+rx-errors:
+- packet handed to ipsec_rcv that is not an ipsec packet.
+- ipsec packet with payload length not modulo 4.
+- ipsec packet with bad authenticator length.
+- incoming packet with no SA.
+- replayed packet.
+- incoming authentication failed.
+- got esp packet with length not modulo 8.
+
+tx_dropped:
+- cannot process ip_options.
+- packet ttl expired.
+- packet with no eroute.
+- eroute with no SA.
+- cannot allocate sk_buff.
+- cannot allocate kernel memory.
+- sk_buff internal error.
+
+
+The standard counters are:
+
+struct enet_statistics
+{
+ int rx_packets; /* total packets received */
+ int tx_packets; /* total packets transmitted */
+ int rx_errors; /* bad packets received */
+ int tx_errors; /* packet transmit problems */
+ int rx_dropped; /* no space in linux buffers */
+ int tx_dropped; /* no space available in linux */
+ int multicast; /* multicast packets received */
+ int collisions;
+
+ /* detailed rx_errors: */
+ int rx_length_errors;
+ int rx_over_errors; /* receiver ring buff overflow */
+ int rx_crc_errors; /* recved pkt with crc error */
+ int rx_frame_errors; /* recv'd frame alignment error */
+ int rx_fifo_errors; /* recv'r fifo overrun */
+ int rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ int tx_aborted_errors;
+ int tx_carrier_errors;
+ int tx_fifo_errors;
+ int tx_heartbeat_errors;
+ int tx_window_errors;
+};
+
+of which I think only the first 6 are useful.</PRE><H3>
+<A NAME="gdb"></A>5.4 Using GDB on Pluto</H3>
+<P>You may need to use the GNU debugger, gdb(1), on Pluto. This
+should be necessary only in unusual cases, for example if you
+encounter a problem which the Pluto developer cannot readily
+reproduce or if you are modifying Pluto.
+</P>
+<P>Here are the Pluto developer's suggestions for doing this:
+</P>
+<PRE>Can you get a core dump and use gdb to find out what Pluto was doing
+when it died?
+
+To get a core dump, you will have to set dumpdir to point to a
+suitable directory (see <A HREF="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A>).
+
+To get gdb to tell you interesting stuff:
+ $ script
+ $ cd dump-directory-you-chose
+ $ gdb /usr/local/lib/ipsec/pluto core
+ (gdb) where
+ (gdb) quit
+ $ exit
+
+The resulting output will have been captured by the script command in
+a file called &quot;typescript&quot;. Send it to the list.
+
+Do not delete the core file. I may need to ask you to print out some
+more relevant stuff.</PRE><P>
+Note that the <VAR>dumpdir</VAR> parameter takes effect only when the
+IPsec subsystem is restarted -- reboot or ipsec setup restart.</P>
+<P><BR><BR>
+</P>
+</BODY>
+</HTML>
diff --git a/doc/src/uml-rhroot-list.txt b/doc/src/uml-rhroot-list.txt
new file mode 100644
index 000000000..198997032
--- /dev/null
+++ b/doc/src/uml-rhroot-list.txt
@@ -0,0 +1,91 @@
+filesystem-2.1.6-2
+glibc-common-2.2.4-13
+slang-1.4.4-4
+newt-0.50.33-1
+mktemp-1.5-11
+syslinux-1.52-2
+which-2.12-3
+zlib-devel-1.1.3-24
+ntsysv-1.2.24-1
+db1-devel-1.85-7
+e2fsprogs-1.23-2
+iputils-20001110-6
+mingetty-0.9.4-18
+pwdb-0.61.1-3
+bash-2.05-8
+bzip2-1.0.1-4
+libstdc++-2.96-98
+logrotate-3.5.9-1
+rootfiles-7.2-1
+bash-doc-2.05-8
+iproute-2.2.4-14
+ncurses-5.2-12
+diffutils-2.7.2-2
+findutils-4.1.7-1
+gzip-1.3-15
+readline-4.2-2
+tmpwatch-2.8-2
+cpio-2.4.2-23
+gawk-3.1.0-3
+less-358-21
+procps-X11-2.0.7-11
+sed-3.02-10
+vim-minimal-5.8-7
+fileutils-4.1-4
+sysklogd-1.4.1-4
+mount-2.11g-5
+rpm-4.0.3-1.03
+glib-devel-1.2.10-5
+bzip2-libs-1.0.1-4
+tar-1.13.19-6
+cracklib-dicts-2.7-12
+passwd-0.64.1-7
+pam-devel-0.75-14
+SysVinit-2.78-19
+krb5-libs-1.2.2-13
+pam_krb5-1.46-1
+krbafs-utils-1.0.9-2
+setup-2.5.7-1
+basesystem-7.0-2
+glibc-2.2.4-13
+popt-1.6.3-1.03
+setuptool-1.8-2
+shadow-utils-20000902-4
+zlib-1.1.3-24
+chkconfig-1.2.24-1
+db1-1.85-7
+db3-3.2.9-4
+file-3.35-2
+losetup-2.11g-5
+net-tools-1.60-3
+netconfig-0.8.11-7
+libtermcap-2.0.8-28
+libtermcap-devel-2.0.8-28
+bzip2-devel-1.0.1-4
+libstdc++-devel-2.96-98
+modutils-2.4.6-4
+crontabs-1.10-1
+MAKEDEV-3.2-5
+grep-2.4.2-7
+psmisc-20.1-2
+readline-devel-4.2-2
+e2fsprogs-devel-1.23-2
+ed-0.2-21
+vim-common-5.8-7
+procps-2.0.7-11
+redhat-release-7.2-1
+time-1.7-14
+cracklib-2.7-12
+console-tools-19990829-36
+textutils-2.0.14-2
+dev-3.2-5
+glib-1.2.10-5
+termcap-11.0.1-10
+info-4.0b-3
+words-2-17
+pam-0.75-14
+util-linux-2.11f-9
+sh-utils-2.0.11-5
+initscripts-6.40-1
+krbafs-1.0.9-2
+krbafs-devel-1.0.9-2
diff --git a/doc/src/uml-rhroot.html b/doc/src/uml-rhroot.html
new file mode 100644
index 000000000..ca05a2073
--- /dev/null
+++ b/doc/src/uml-rhroot.html
@@ -0,0 +1,116 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+ <HEAD>
+ <TITLE>Building a RedHat root image</TITLE>
+ <!-- Created by: Michael Richardson, 22-Nov-2001 -->
+ <!-- Changed by: Michael Richardson, 22-Nov-2001 -->
+
+
+ </HEAD>
+ <BODY>
+ <H1>Building a RedHat root image</H1>
+
+<P>
+The image required to use User-Mode-Linux is just a normal set of executables.
+These can be extracted from a RedHat distribution using the following proceedure.
+</P>
+
+<P>
+There is a script in testing/utils called <CODE>uml-rhroot.sh</CODE>. It takes
+two arguments:
+<UL>
+<LI> a directory in which to put resulting directory tree.
+<LI> a directory tree containing the RedHat distribution RPMs. This may be
+ in one of three forms:
+<UL>
+<LI> a directory containing the directories "disc1" and "disc2". These
+ could be ISO images that are mounted loopback via, for instance:
+<PRE>
+<CODE>
+mkdir -p /distros/redhat/7.2/disc1 /distros/redhat/7.2/disc1
+mount -t iso9660 -o loop,ro /distros/redhat/7.2/enigma-i386-disc1.iso /distros/redhat/7.2/disc1
+mount -t iso9660 -o loop,ro /distros/redhat/7.2/enigma-i386-disc2.iso /distros/redhat/7.2/disc2
+</CODE>
+</PRE>
+or even two real CDroms mounted somewhere. In the example above, use "/distros/redhat/7.2" as the distribution directory.
+</LI>
+<LI> a directory containing a "merged" disc1 and disc2 as suggested by RedHat in <A HREF="http://www.redhat.com/docs/manuals/linux/RHL-7.2-Manual/install-guide/s1-install-network.html#S2-INSTALL-SETUPSERVER">http://www.redhat.com/docs/manuals/linux/RHL-7.2-Manual/install-guide/s1-install-network.html under "Setting up the Server"</A>.
+<LI> a directory containing all the required RPMs. (See <A HREF="uml-rhroot-list7.2.txt">list of RPMs</A>)</LI>
+</UL>
+</UL>
+</P>
+
+<P>The unpacked distribution will take approximately 133Mb. You will
+ want to locate this on the same partition as your intended root
+ trees for your User-Mode-Linux's as this will permit hard links to
+ be used, saving disk space.
+</P>
+
+<P>
+ Because the RPM command used uses the chroot(2) system call and
+ needs to change ownership of the files that it creates, it must be
+ run as root. Afterward, you should chown the entire directory to the
+ userid that you will be using for testing (i.e. probably
+ yours). It should eventually suffices to make sure that you can read
+ every file.
+</P>
+
+<P>
+You should be able to chroot to this directory and run programs. If
+you can not at least run ls, then there is a problem.
+</P>
+<P>
+Expect a couple of errors about install-info.
+</P>
+
+<P>
+An example:
+<PRE>
+<CODE>
+Script started on Thu Nov 22 15:51:15 2001
+cassidy:/c2/user-mode-linux# df
+Filesystem 1k-blocks Used Available Use% Mounted on
+/dev/hda1 3844408 1673528 1975584 46% /
+/dev/hda3 12495048 1823404 10036884 16% /home
+/dev/hdc1 10325748 805056 8996172 9% /c1
+/dev/hdc2 10325780 4815160 4986100 50% /c2
+/dev/hdc3 10325780 2972480 6828780 31% /c3
+/dev/hdc4 7495084 3059640 4054704 44% /c4
+/distros/redhat/7.2/enigma-i386-disc1.iso
+ 662072 662072 0 100% /distros/redhat/7.2/disc1
+/distros/redhat/7.2/enigma-i386-disc2.iso
+ 653740 653740 0 100% /distros/redhat/7.2/disc2
+cassidy:/c2/user-mode-linux# /c2/freeswan/sandbox-main/testing/utils/uml-rhroot.sh
+Usage: /c2/freeswan/sandbox-main/testing/utils/uml-rhroot.sh rootdir cdimagedir
+cassidy:/c2/user-mode-linux# /c2/freeswan/sandbox-main/testing/utils/uml-rhroot.sh /c2/user-mode-linux/rpm-root/root /distros/redhat/7.2
+Assuming RH disc1 at /distros/redhat/7.2/disc1/RedHat/RPMS
+ and disc2 at /distros/redhat/7.2/disc2/RedHat/RPMS
+/var/tmp/rpm-tmp.99149: /sbin/install-info: No such file or directory
+error: execution of %post scriptlet from textutils-2.0.14-2 failed, exit status 127
+cat: /proc/mounts: No such file or directory
+warning: /var/lib/rpm/Basenames created as /var/lib/rpm/Basenames.rpmnew
+warning: /var/lib/rpm/Conflictname created as /var/lib/rpm/Conflictname.rpmnew
+warning: /var/lib/rpm/Group created as /var/lib/rpm/Group.rpmnew
+warning: /var/lib/rpm/Name created as /var/lib/rpm/Name.rpmnew
+warning: /var/lib/rpm/Packages created as /var/lib/rpm/Packages.rpmnew
+warning: /var/lib/rpm/Providename created as /var/lib/rpm/Providename.rpmnew
+warning: /var/lib/rpm/Requirename created as /var/lib/rpm/Requirename.rpmnew
+warning: /var/lib/rpm/Triggername created as /var/lib/rpm/Triggername.rpmnew
+You should now chown it to yourself.
+cassidy:/c2/user-mode-linux# chown -R mcr rpm-root/root
+cassidy:/c2/user-mode-linux# ls rpm-root/root
+bin dev home lib opt root tmp var
+boot etc initrd mnt proc sbin usr
+cassidy:/c2/user-mode-linux# chroot rpm-root/root
+cassidy:/# ls
+bin dev home lib opt root tmp var
+boot etc initrd mnt proc sbin usr
+cassidy:/# exit
+cassidy:/c2/user-mode-linux# exit
+Script done on Thu Nov 22 15:54:33 2001
+</CODE>
+</PRE>
+
+
+ </BODY>
+</HTML> \ No newline at end of file
diff --git a/doc/src/uml-stack-trace.html b/doc/src/uml-stack-trace.html
new file mode 100644
index 000000000..1b08ed7d1
--- /dev/null
+++ b/doc/src/uml-stack-trace.html
@@ -0,0 +1,129 @@
+<PRE>
+To: Michael Richardson <mcr@sandelman.ottawa.on.ca>
+Cc: user-mode-linux-devel@lists.sourceforge.net
+From: Jeff Dike <jdike@karaya.com>
+Subject: [uml-devel] Re: stack trace
+Date: Mon, 16 Sep 2002 22:36:06 -0500
+
+mcr@sandelman.ottawa.on.ca said:
+> Can you post (on list or web site) a "script" output of you trying to
+> get the right stack out of a stuck uml (tracing myself)...?
+
+Yup. Here we go...
+
+Here, I attach to the tracing thread and get the stack of the current thread,
+which happens to be the idle thread.
+
+um 1013: gdb linux 14936
+GNU gdb 5.0rh-5 Red Hat Linux 7.1
+Copyright 2001 Free Software Foundation, Inc.
+GDB is free software, covered by the GNU General Public License, and you are
+welcome to change it and/or distribute copies of it under certain conditions.
+Type "show copying" to see the conditions.
+There is absolutely no warranty for GDB. Type "show warranty" for details.
+This GDB was configured as "i386-redhat-linux"...
+/home/jdike/linux/2.4/um/14936: No such file or directory.
+Attaching to program: /home/jdike/linux/2.4/um/linux, process 14936
+0xa014efe9 in __wait4 ()
+
+# This is how you get the current task in the tracing thread - get_current()
+# only works in a kernel thread.
+(gdb) p (struct task_struct *)cpu_tasks[0].task
+$2 = (struct task_struct *) 0xa01c0000
+
+# Get the host pid of that task.
+(gdb) p $2.thread.extern_pid
+$3 = 14939
+
+# Get the current ip and sp.
+(gdb) shell cat /proc/14939/stat
+14939 (linux) T 14936 14936 883 34816 14936 64 5 3 806 7 62 12 0 0 9 0 0 2
+588043 142770176 5008 4294967295 2684358656 2686348640 3221223520 2686205764
+ sp ^^^^^^^^^^
+ 2685727185 73728 201392128 167776768 268444672 3222308129 0 0 17 0
+ip ^^^^^^^^^^
+
+# the sp and ip are items 4 and 5 after the 4294967295 (on 2.2 hosts, that's
+2^31 - 1 rather than 2^32 - 1).
+
+(gdb) p/x 2686205764
+$4 = 0xa01c3f44
+(gdb) p/x 2685727185
+$5 = 0xa014f1d1
+
+# Where's the ip?
+(gdb) i sym 0xa014f1d1
+nanosleep + 17 in section .text
+
+# look at the stack around the sp
+(gdb) x/32x 0xa01c3f30
+0xa01c3f30 : 0x00000000 0x00000000 0xa01c3f60 0xa00020a8
+0xa01c3f40 : 0x00000004 0xa012e891 0xa01c3f58 0xa01c3f58
+0xa01c3f50 : 0xa01c3f70 0xa0023667 0x00000009 0x3b023380
+0xa01c3f60 : 0xa01c3fa0 0xa012a21d 0x0000000a 0xa01c0000
+0xa01c3f70 : 0xa01c3fa0 0xa012a213 0x00000003 0x00000024
+0xa01c3f80 : 0xa01c3fa0 0xa0011bc4 0xa012b25c 0x00000000
+0xa01c3f90 : 0xa01c3fb0 0x00000000 0xa01c3ffc 0x0000000d
+0xa01c3fa0 : 0xa01c3fb0 0xa000c50e 0xa01812e0 0xa01c3ffc
+
+# The trick here is to locate a frame near the current sp. You're looking
+# for a consecutive pair of longwords (fp, ip) having the properties that:
+# fp is on the current kernel stack and points further up it
+# ip is a text address (if you can't recognize a UML text address by
+# sight, print out &_stext and &_etext)
+#
+# Starting at 0xa01c3f44, the first pair of works satisfying these requirements
+# is at 0xa01c3f50.
+# So, print that pair out as hex.
+(gdb) p/x *((int (*)[2])0xa01c3f50)
+$9 = {0xa01c3f70, 0xa0023667}
+
+# Now, we start climbing the stack.
+(gdb) p/x *((int (*)[2])$[0])
+$10 = {0xa01c3fa0, 0xa012a213}
+(gdb)
+$11 = {0xa01c3fb0, 0xa000c50e}
+(gdb)
+$12 = {0xa01c3fc0, 0xa000356d}
+(gdb)
+$13 = {0xa01c3fd0, 0xa013082f}
+(gdb)
+$14 = {0xa01c3ff0, 0xa012fbdd}
+# Stop when you see a NULL frame pointer or gdb bitches at you.
+(gdb)
+$15 = {0x0, 0xa01513aa}
+
+# Now we get the symbolic version of the stack with 'i sym' of the second item
+# in each pair.
+(gdb) i sym 0xa0023667
+check_pgt_cache + 23 in section .text
+(gdb) i sym 0xa012a213
+cpu_idle + 123 in section .text
+(gdb) i sym 0xa000c50e
+rest_init + 46 in section .text
+(gdb) i sym 0xa000356d
+start_kernel + 361 in section .text.init
+(gdb) i sym 0xa013082f
+start_kernel_proc + 63 in section .text
+(gdb) i sym 0xa012fbdd
+signal_tramp + 209 in section .text
+(gdb) i sym 0xa01513aa
+thread_start + 4 in section .text
+
+# You can also get line number information with 'i line'.
+(gdb) i line *0xa012a213
+Line 488 of "process_kern.c" starts at address 0xa012a213 <cpu_idle+123>
+ and ends at 0xa012a21d <cpu_idle+133>.
+(gdb)
+
+
+-------------------------------------------------------
+Sponsored by: AMD - Your access to the experts on Hammer Technology!
+Open Source & Linux Developers, register now for the AMD Developer
+Symposium. Code: EX8664 http://www.developwithamd.com/developerlab
+_______________________________________________
+User-mode-linux-devel mailing list
+User-mode-linux-devel@lists.sourceforge.net
+https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel
+
+</PRE> \ No newline at end of file
diff --git a/doc/src/umltesting.html b/doc/src/umltesting.html
new file mode 100644
index 000000000..df62a9ae2
--- /dev/null
+++ b/doc/src/umltesting.html
@@ -0,0 +1,478 @@
+<html>
+<head>
+<title>FreeS/WAN User-Mode-Linux testing guide</title>
+<!-- Changed by: Michael Richardson, 05-Mar-2003 -->
+<meta name="keywords" content="Linux, IPsec, VPN, security, FreeSWAN, testing, User-Mode-Linux, UML">
+
+<!--
+
+Written by Michael Richardson for the Linux FreeS/WAN project
+Freely distributable under the GNU General Public License
+
+More information at www.freeswan.org
+Feedback to users@lists.freeswan.org
+
+$Id: umltesting.html,v 1.1 2004/03/15 20:35:24 as Exp $
+
+$Log: umltesting.html,v $
+Revision 1.1 2004/03/15 20:35:24 as
+added files from freeswan-2.04-x509-1.5.3
+
+Revision 1.23 2003/09/18 15:12:11 dhr
+
+fix link to kernel.org mirrors page
+
+Revision 1.22 2003/03/07 03:49:25 dhr
+
+fix recommended version of uml-patch
+
+Revision 1.21 2003/03/06 08:37:03 dhr
+
+capture more of MCR's knowledge about BIND
+
+Revision 1.20 2003/03/06 02:15:44 mcr
+ added note about need for bind9.
+
+Revision 1.19 2003/03/05 23:20:39 mcr
+ updates from -47 to -53.
+
+Revision 1.18 2003/02/27 08:25:48 dhr
+
+update to reflect newer umlfreeroot
+
+Revision 1.17 2003/02/27 08:16:45 dhr
+
+make clear what is the latest version of the UML patch that we've used
+
+Revision 1.16 2003/02/21 01:35:31 mcr
+ updated latest umlfreeroot to 15.1.
+
+Revision 1.15 2003/01/21 03:26:34 mcr
+ updated documentation on UML state.
+
+Revision 1.14 2002/11/11 16:43:35 mcr
+ adjusted formatting of uml_netjig notes.
+
+Revision 1.13 2002/11/08 10:13:05 mcr
+ updated documentation for 2.4.19
+
+Revision 1.12 2002/11/03 23:44:23 mcr
+ fixed some formatting in umltesting.html
+ added some notes about NETJIGWAITUSER re: having tests
+ prompt before they exit. Helps with debugging.
+
+Revision 1.11 2002/10/31 19:01:31 mcr
+ documentation for RUN_*_SCRIPT.
+
+Revision 1.10 2002/09/15 23:57:59 dhr
+
+update suggested umlfreeroot
+
+Revision 1.9 2002/09/15 19:28:05 mcr
+ added some comments about problems with UMLs.
+
+Revision 1.8 2002/09/11 20:00:25 mcr
+ updated umlroot rev to 8.0.
+
+Revision 1.7 2002/09/09 21:37:43 mcr
+ updated document to reference currently working kernel+UML.
+
+Revision 1.6 2002/08/02 22:43:35 mcr
+ added section on debugging with UMLs.
+
+Revision 1.5 2002/05/30 18:47:57 dhr
+
+Update from experience:
+- fixed HTML bugs
+- restructure slightly
+- added another intro paragraph
+- mentioned lack of Super User requirements
+- added tcpdump build and install procedure
+- added uml utils build procedure
+- added invitation to try "make check"
+- fixed minor typos and mistakes
+
+Revision 1.4 2002/03/12 21:10:37 mcr
+ removed instruction on downloading umlminishare, as this is
+ now simply included in umlrootXXX. reformated some other text.
+
+Revision 1.3 2002/01/29 02:21:21 mcr
+ updated instructions for 2.4.17, and for newest UMLroot.
+
+Revision 1.2 2001/11/27 05:24:09 mcr
+ added reference to uml-rhroot, but commented out.
+ This proceedure is not yet ready for prime time.
+
+Revision 1.1 2001/11/05 04:35:57 mcr
+ adapted text from design list posting into HTML for Sandy.
+
+
+-->
+</head>
+
+<body>
+
+<h1><a name="umltesting">User-Mode-Linux Testing guide</a></h1>
+
+<p>
+User mode linux is a way to compile a linux kernel such that it can run as a
+process in another linux system (potentially as a *BSD or Windows process
+later). See <A HREF="http://user-mode-linux.sourceforge.net/">http://user-mode-linux.sourceforge.net/</A>
+</P>
+
+<p>
+UML is a good platform for testing and experimenting with FreeS/WAN.
+It allows several network nodes to be simulated on a single machine.
+Creating, configuring, installing, monitoring, and controling these
+nodes is generally easier and easier to script with UML than real
+hardware.
+</p>
+
+<p>
+You'll need about 500Mb of disk space for a full sunrise-east-west-sunset
+setup. You can possibly get this down by 130Mb if you remove the
+sunrise/sunset kernel build. If you just want to run, then you can even
+remove the east/west kernel build.
+</p>
+<p>
+Nothing need be done as super user. In a couple of steps, we note
+where super user is required to install commands in system-wide
+directories, but ~/bin could be used instead. UML seems to use a
+system-wide /tmp/uml directory so different users may interfere with
+one another. Later UMLs use ~/.uml instead, so multiple users running UML
+tests should not be a problem, but note that a single user running
+the UML tests will only be able run one set. Further, UMLs sometimes
+get stuck and hang around. These "zombies" (most will actually be in
+the "T" state in the process table) will interfere with subsequent tests.
+</P>
+<H2>Preliminary Notes on BIND</H2>
+
+<P>
+As of 2003/3/1, the Light-Weight Resolver is used by pluto. This requires
+that BIND9 be running. It also requires that BIND9 development libraries
+be present in the build environment. The DNSSEC code is only truly functional
+in BIND9 snapshots. The library code could be 9.2.2, we believe. We are
+using BIND9 20021115 snapshot code from
+<A HREF="ftp://ftp.isc.org/isc/bind9/snapshots">ftp://ftp.isc.org/isc/bind9/snapshots</A>.
+</P>
+<P>
+FreeS/WAN may well require a newer BIND than is on your system.
+Many distributions have moved to BIND9.2.2 recently due to a security advisory.
+BIND is five components.
+</P>
+<OL>
+<LI>
+named
+</LI>
+<LI>
+dnssec-*
+</LI>
+<LI>
+client side resolver libraries
+</LI>
+<LI>
+client side utility libraries
+I thought there were lib and named parts to dnsssec...
+</LI>
+<LI>
+dynamic DNS update utilities
+</LI>
+</OL>
+<P>
+The only piece that we need for *building* is #4. That's the only part that has to be on the build host.
+What is the difference between resolver and util libs?
+If you want to edit testing/baseconfigs/all/etc/bind, you'll need a snapshot version.
+The resolver library contains the resolver.
+FreeS/WAN has its own copy of that in lib/liblwres.
+</P>
+<H2>Steps to Install UML for FreeS/WAN</H2>
+<OL>
+<LI> Get the following files:
+<OL type="a">
+<LI> from <A HREF="http://www.sandelman.ottawa.on.ca/freeswan/uml/">http://www.sandelman.ottawa.on.ca/freeswan/uml/</A>
+umlfreeroot-15.1.tar.gz (or highest numbered one). This is a
+ debian potato root file system. You can use this even on a Redhat
+ host, as it has the newer GLIBC2.2 libraries as well.
+
+
+<!-- If you are using
+ Redhat 7.2 or newer as your development machine, you can create the
+ image from your installation media. See <A HREF="uml-rhroot.html">Building a RedHat root"></A>.
+ A future document will explain how to build this from .DEB files as well.
+-->
+
+<!--
+<LI> umlfreesharemini.tar.gz (or umlfreeshareall.tar.gz).
+ If you are a Debian potato user, you don't need it you can use your
+ native /usr/share.
+</UL>
+-->
+
+<LI> From <A HREF="ftp://ftp.xs4all.nl/pub/crypto/freeswan/">ftp://ftp.xs4all.nl/pub/crypto/freeswan/</A>
+a snapshot or release (1.92 or better)
+
+<LI> From a
+ <A HREF="http://www.kernel.org/mirrors/">http://www.kernel.org mirror</A>,
+ the virgin 2.4.19 kernel. Please realize that we have defaults in our
+ tree for kernel configuration. We try to track the latest UML
+ kernels. If you use a newer kernel, you may have faults in the
+ kernel build process. You can see what the latest that is being regularly tested by visiting <A HREF="http://bugs.freeswan.org:81/regress/HEAD/lastgood/freeswan-regress-env.sh">freeswan-regress-env.sh</A>.
+
+<LI>
+<!-- Note: this step is refered to as "step 1d" below. -->
+Get
+ <A HREF="http://ftp.nl.linux.org/uml/">http://ftp.nl.linux.org/uml/</A>
+ uml-patch-2.4.19-47.bz2 or the one associated with your kernel.
+ As of 2003/03/05, uml-patch-2.4.19-47.bz2 works for us.
+<STRONG>More recent versions of the patch have not been tested by us.</STRONG>
+<LI> You'll probably want to visit
+<A
+ HREF="http://user-mode-linux.sourceforge.net">http://user-mode-linux.sourceforge.net</A>
+and get the UML utilities. These are not needed for the build or interactive use (but recommended). They are necessary for the regression testing procedures used by "make check".
+We currently use uml_utilities_20020212.tar.bz2.
+<LI>
+You need tcpdump version 3.7.1 or better.
+This is newer than the version included in most LINUX distributions.
+You can check the version of an installed tcpdump with the --version flag.
+If you need a newer tcpdump
+fetch both tcpdump and libpcap source tar files from
+<A HREF="http://www.tcpdump.org/">http://www.tcpdump.org/</A> or a mirror.
+</OL>
+
+<LI> Pick a suitable place, and extract the following files:
+<OL type="a">
+<LI>
+<!-- Note: this step is refered to as "step 2a" later. -->
+2.4.19 kernel. For instance:
+<PRE>
+<CODE>
+ cd /c2/kernel
+ tar xzvf ../download/pub/linux/kernel/v2.4/linux-2.4.19.tar.gz
+</CODE>
+</PRE>
+
+<LI> extract the umlfreeroot file
+<!-- (unless you <A HREF="uml-rhroot.html">built your own from RPMs</A>) -->
+<PRE>
+<CODE>
+ mkdir -p /c2/user-mode-linux/basic-root
+ cd /c2/user-mode-linux/basic-root
+ tar xzvf ../download/umlfreeroot-15.1.tar.gz
+</CODE>
+</PRE>
+
+<LI> FreeSWAN itself (or checkout "all" from CVS)
+<PRE>
+<CODE>
+ mkdir -p /c2/freeswan/sandbox
+ cd /c2/freeswan/sandbox
+ tar xzvf ../download/snapshot.tar.gz
+</CODE>
+</PRE>
+</OL>
+
+<LI> If you need to build a newer tcpdump:
+<UL>
+<LI>
+Make sure you have OpenSSL installed -- it is needed for cryptographic routines.
+<LI>
+Unpack libpcap and tcpdump source in parallel directories (the tcpdump
+build procedures look for libpcap next door).
+<LI>
+Change directory into the libpcap source directory and then build the library:
+<PRE>
+<CODE>
+ ./configure
+ make
+</CODE>
+</PRE>
+<LI>
+Change into the tcpdump source directory, build tcpdump, and install it.
+<PRE>
+<CODE>
+ ./configure
+ make
+ # Need to be superuser to install in system directories.
+ # Installing in ~/bin would be an alternative.
+ su -c "make install"
+</CODE>
+</PRE>
+</UL>
+<LI> If you need the uml utilities, unpack them somewhere then build and install
+them:
+<PRE>
+<CODE>
+ cd tools
+ make all
+ # Need to be superuser to install in system directories.
+ # Installing in ~/bin would be an alternative.
+ su -c "make install BIN_DIR=/usr/local/bin"
+</CODE>
+</PRE>
+<LI> set up the configuration file
+<UL>
+<LI>
+<CODE>
+cd /c2/freeswan/sandbox/freeswan-1.97/testing/utils
+</CODE>
+<LI> copy umlsetup-sample.sh to ../../umlsetup.sh:
+<CODE>
+ cp umlsetup-sample.sh ../../umlsetup.sh
+</CODE>
+
+<LI> open up ../../umlsetup.sh in your favorite editor.
+<LI> change POOLSPACE= to point to the place with at least 500Mb of
+disk. Best if it is on the same partition as the "umlfreeroot" extraction,
+as it will attempt to use hard links if possible to save disk space.
+
+<LI> Set TESTINGROOT if you intend to run the script outside of the
+ sandbox/snapshot/release directory. Otherwise, it will configure itself.
+
+<LI> KERNPOOL should point to the directory with your 2.4.19 kernel
+ tree. This tree should be unconfigured! This is the directory
+ you used in step 2a.
+
+<LI> UMLPATCH should point at the bz2 file you downloaded at 1d.
+ If using a kernel that already includes the patch, set this to /dev/null.
+
+<LI> FREESWANDIR should point at the directory where you unpacked
+ the snapshot/release. Include the "freeswan-snap2001sep16b"
+ or whatever in it. If you are running from CVS, then
+ you point at the directory where top, klips, etc. are.
+ The script will fix up the directory so that it can be
+ used.
+
+<LI> BASICROOT should be set to the directory used in 2b, or to the directory
+ that you created with RPMs.
+
+<LI> SHAREDIR should be set to the directory used in 2c, to /usr/share
+ for Debian potato users, or to $BASICROOT/usr/share.
+</UL>
+
+<LI> <PRE><CODE>
+cd $TESTINGROOT/utils
+sh make-uml.sh
+</CODE></PRE>
+ It will grind for awhile. If there are errors it will bail.
+ If so, run it under "script" and send the output to bugs@lists.freeswan.org.
+
+<LI> You will have a bunch of stuff under $POOLSPACE.
+ Open four xterms:
+
+<PRE><CODE>
+ for i in sunrise sunset east west
+ do
+ xterm -name $i -title $i -e $POOLSPACE/$i/start.sh &
+ done
+</CODE></PRE>
+
+<LI> Login as root. Password is "root"
+ (Note, these virtual machines are networked together, but are not
+ configured to talk to the rest of the world.)
+
+<LI> verify that pluto started on east/west, run "ipsec look"
+
+<LI> login to sunrise. run "ping sunset"
+
+<LI> login to west. run "tcpdump -p -i eth1 -n"
+ (tcpdump must be version 3.7.1 or newer)
+
+<LI> Closing a console xterm will shut down that UML.
+
+<LI> You can "make check", if you want to.
+It is run from /c2/freeswan/sandbox/freeswan-1.97.</LI>
+
+</OL>
+
+<H1>Debugging the kernel with GDB</H1>
+
+<P>
+With User-Mode-Linux, you can debug the kernel using GDB.
+See <HREF="http://user-mode-linux.sourceforge.net/debugging.html">http://user-mode-linux.sourceforge.net/debugging.html</A>.
+</P>
+
+<P>
+Typically, one will want to address a test case for a failing situation.
+Running GDB from Emacs, or from other front ends is possible. First start GDB.
+</P>
+<P>
+Tell it to open the UMLPOOL/swan/linux program.
+</P>
+<P>
+Note the PID of GDB:
+<PRE>
+marajade-[projects/freeswan/mgmt/planning] mcr 1029 %ps ax | grep gdb
+ 1659 pts/9 SN 0:00 /usr/bin/gdb -fullname -cd /mara4/freeswan/kernpatch/UMLPOOL/swan/ linux
+</PRE>
+</P>
+
+<P>
+Set the following in the environment:
+<PRE>
+UML_east_OPT="debug gdb-pid=1659"
+</PRE>
+</P>
+
+<P>
+Then start the user-mode-linux in the test scheme you wish:
+<PRE>
+marajade-[kernpatch/testing/klips/east-icmp-02] mcr 1220 %../../utils/runme.sh
+</PRE>
+
+The user-mode-linux will stop on boot, giving you a chance to attach to the process:
+
+<PRE>
+(gdb) file linux
+Reading symbols from linux...done.
+(gdb) attach 1
+Attaching to program: /mara4/freeswan/kernpatch/UMLPOOL/swan/linux, process 1
+0xa0118bc1 in kill () at hostfs_kern.c:770
+</PRE>
+
+<P>
+At this point, break points should be created as appropriate.
+</P>
+
+<H2>Other notes about debugging</H2>
+
+<P>
+If you are running a standard test, after all the packets are sent, the UML will
+be shutdown. This can cause problems, because the UML may get terminated while you
+are debugging.
+</P>
+<P>
+The environment variable <CODE>NETJIGWAITUSER</CODE> can be set to "waituser".
+If so, then the testing system will prompt before exiting the test.
+</P>
+
+<H1>User-Mode-Linux mysteries</H1>
+
+<UL>
+<LI> running more than one UML of the same name (e.g. "west") can cause
+ problems.
+<LI> running more than one UML from the same root file system is not
+ a good idea.
+<LI> all this means that running "make check" twice on the same machine
+ is probably not a good idea.
+<LI> occationally, UMLs will get stuck. This can happen like:
+<BLOCK>
+15134 ? T 0:00 /spare/hugh/uml/uml2.4.18-sept5/umlbuild/east/linux (east) [/bin/sh]
+15138 ? T 0:00 /spare/hugh/uml/uml2.4.18-sept5/umlbuild/east/linux (east) [halt]
+ </BLOCK>
+
+these will need to be killed. Note that they are in "T"racing mode.
+<LI> UMLs can also hang, and will report "Tracing myself and I can't get out".
+This is a bug in UML. There are ways to find out what is going on and
+report this to the UML people, but we don't know the magic right now.
+</UL>
+
+<H1>Getting more info from uml_netjig</H1>
+
+<P>
+uml_netjig can be compiled with a built-in tcpdump. This uses not-yet-released
+code from <A HREF="http://www.tcpdump.org/">www.tcpdump.org</A>.
+Please see the instructions in <CODE>testing/utils/uml_netjig/Makefile</CODE>.
+</P>
+
+</body>
+</html>
diff --git a/doc/src/upgrading.html b/doc/src/upgrading.html
new file mode 100644
index 000000000..0d6401b96
--- /dev/null
+++ b/doc/src/upgrading.html
@@ -0,0 +1,260 @@
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>Introduction to FreeS/WAN</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, encryption, cryptography, FreeS/WAN, FreeSWAN">
+ <!--
+
+ Written by Claudia Schmeing for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: upgrading.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<A NAME="upgrading"></A><h1>Upgrading to FreeS/WAN 2.x</h1>
+
+
+<H2>New! Built in Opportunistic connections</H2>
+
+<P>Out of the box, FreeS/WAN 2.x will attempt to encrypt all your IP traffic.
+It will try to establish IPsec connections for:</P>
+<UL><LI>
+IP traffic from the Linux box on which you have installed FreeS/WAN, and</LI>
+<LI>
+outbound IP traffic routed through that Linux box (eg. from a protected subnet).</LI>
+</UL>
+<P>FreeS/WAN 2.x uses <STRONG>hidden, automatically enabled
+ <VAR>ipsec.conf</VAR> connections</STRONG> to do this.</P>
+
+<P>This behaviour is part of our campaign to get Opportunistic
+Encryption (OE) widespread in the Linux world, so that any two Linux boxes can
+encrypt to one another without prearrangement.
+There's one catch, however: you must <A HREF="quickstart.html#quickstart">set
+up a few DNS records</A>
+to distribute RSA public keys and (if applicable) IPsec gateway
+information.</P>
+
+<P>If you start FreeS/WAN before you have set up these DNS
+records, your connectivity will be slow, and
+messages relating to the built in connections will clutter your logs.
+If you are unable to set up DNS for OE, you will wish to
+<A HREF="policygroups.html#disable_policygroups">disable the
+hidden connections</A>.</P>
+
+<A NAME="upgrading.flagday"></A>
+
+<H3>Upgrading Opportunistic Encryption
+to 2.01 (or later)</H3>
+
+<P>As of FreeS/WAN 2.01, Opportunistic Encryption (OE)
+uses DNS TXT resource records (RRs) only (rather than TXT with KEY).
+This change causes a "flag day".
+Users of FreeS/WAN 2.00 (or earlier) OE who are upgrading may
+need to post additional resource records.
+</P>
+
+<P>If you are running
+<A HREF="glossary.html#initiate-only">initiate-only OE</A>,
+you <em>must</em> put up a TXT record in any forward domain as per our
+<A HREF="quickstart.html#opp.client">quickstart instructions</A>. This
+replaces your old forward KEY.
+</P>
+
+<P>
+If you are running full OE, you require no updates. You already have
+the needed TXT record in the reverse domain.
+However, to facilitate future features, you
+may also wish to publish that TXT record in a forward domain as
+instructed <A HREF="quickstart.html#opp.incoming">here</A>.
+</P>
+
+<P>If you are running OE on a gateway (and encrypting on behalf of subnetted
+boxes) you require no updates.
+You already have the required TXT record in your gateway's reverse map,
+and the TXT records for any subnetted boxes require no updating.
+However, to facilitate future features, you may wish to publish your gateway's
+ TXT record in a forward domain as shown
+<A HREF="quickstart.html#opp.incoming">here</A>.
+
+
+<P>
+During the transition, you may wish to leave any old KEY records up for
+some time. They will provide limited backward compatibility.
+<!--
+For more
+detail on that compatibility, see <A HREF="oe.known-issues">Known Issues with
+OE</A>.
+-->
+</P>
+
+<H2>New! Policy Groups</H2>
+
+<P>We want to make it easy for you to declare security policy as it
+applies to IPsec connections.</P>
+
+<P>Policy Groups make it simple to say:
+</P>
+
+<UL>
+<LI>These are the folks I want to talk to in the clear.</LI>
+<LI>These spammers' domains -- I don't want to talk to them at all.</LI>
+<LI>To talk to the finance department, I must use IPsec.</LI>
+<LI>For any other communication, try to encrypt, but it's okay if we can't.</LI></UL>
+
+<P>FreeS/WAN then implements these policies, creating OE connections
+if and when needed.
+You can use Policy Groups along with connections you explicitly
+define in ipsec.conf.</P>
+
+<P>For more information, see our
+<A HREF="policygroups.html">Policy Group HOWTO</A>.</P>
+
+
+<H2>New! Packetdefault Connection</H2>
+
+<P>Free/SWAN 2.x ships with the <STRONG>automatically enabled, hidden
+connection</STRONG> <VAR>packetdefault</VAR>. This configures
+a FreeS/WAN box as an OE gateway for any hosts located
+behind it. As mentioned above, you must configure some
+<A HREF="quickstart.html">DNS records</A> for
+OE to work.</P>
+<P>As the name implies, this connection functions as a default. If you
+have more specific connections, such as policy groups which configure
+your FreeS/WAN box as an OE gateway for a local subnet, these
+will apply before <VAR>packetdefault</VAR>. You can view
+<VAR>packetdefault</VAR>'s specifics in
+<A HREF="manpage.d/ipsec.conf.5.html">man ipsec.conf</A>.
+</P>
+
+
+<H2>FreeS/WAN now disables Reverse Path Filtering</H2>
+
+<P>FreeS/WAN often doesn't work with reverse path filtering. At
+start time, FreeS/WAN now turns rp_filter off, and logs a warning.</P>
+
+<P>FreeS/WAN does not turn it back on again.
+You can do this yourself with a command like:</P>
+
+<PRE> echo 1 > /proc/sys/net/ipv4/conf/eth0/rp_filter</PRE>
+
+<P>For eth0, substitute the interface which FreeS/WAN was affecting.</P>
+
+
+<A NAME="ipsec.conf_v2"></A><H2>Revised <VAR>ipsec.conf</VAR></H2>
+
+<H3>No promise of compatibility</H3>
+
+<P>The FreeS/WAN team promised config-file compatibility throughout
+the 1.x series. That means a 1.5 config file can be directly imported into
+a fresh 1.99 install with no problems.</P>
+
+<P>With FreeS/WAN 2.x, we've given ourselves permission to make the config
+file easier to use. The cost: some FreeS/WAN 1.x configurations will not
+work properly. Many of the new features are, however, backward compatible.</P>
+
+
+<H3>Most <VAR>ipsec.conf</VAR> files will work fine</H3>
+
+<P>... so long as you paste this line, <STRONG>with no preceding
+whitespace</STRONG>,
+ at the top of your config file:
+</P>
+
+<PRE> version 2</PRE>
+
+<H3>Backward compatibility patch</H3>
+
+<P>If the new defaults bite you, use
+<A HREF="ipsec.conf.2_to_1">
+this <VAR>ipsec.conf</VAR> fragment</A> to simulate the old default values.</P>
+
+
+<H3>Details</H3>
+
+<P>
+We've obsoleted various directives which almost no one was using:
+</P>
+<PRE> dump
+ plutobackgroundload
+ no_eroute_pass
+ lifetime
+ rekeystart
+ rekeytries</PRE>
+
+<P>For most of these, there is some other way to elicit the desired behaviour.
+See <A HREF="http://lists.freeswan.org/pipermail/design/2002-August/003243.html">
+this post</A>.
+
+<P>
+We've made some settings, which almost everyone was using, defaults.
+For example:
+</P>
+
+<PRE> interfaces=%defaultroute
+ plutoload=%search
+ plutostart=%search
+ uniqueids=yes</PRE>
+
+<P>We've also changed some default values to help with OE and Policy Groups:</P>
+
+<PRE> authby=rsasig ## not secret!!!
+ leftrsasigkey=%dnsondemand ## looks up missing keys in DNS when needed.
+ rightrsasigkey=%dnsondemand</PRE>
+
+<P>
+Of course, you can still override any defaults by explictly declaring something
+else in your connection.
+</P>
+
+<P>
+<A HREF="http://lists.freeswan.org/pipermail/design/2002-August/003243.html">A post with a list of many ipsec.conf changes.</A><BR>
+<A HREF="manpage.d/ipsec.conf.5.html">Current ipsec.conf manual.</A>
+</P>
+
+
+<A NAME="upgrading.rpms"></A><H3>Upgrading from 1.x RPMs to 2.x RPMs</H3>
+
+<P>Note: When upgrading from 1-series to 2-series RPMs,
+<VAR>rpm -U</VAR> will not work.</P>
+
+<P>You must instead erase the 1.x RPMs, then install the 2.x set:</P>
+<PRE> rpm -e freeswan</PRE>
+<PRE> rpm -e freeswan-module</PRE>
+
+<P>On erasing, your old <VAR>ipsec.conf</VAR> should be moved to
+<VAR>ipsec.conf.rpmsave</VAR>.
+Keep this. You will probably want to copy your existing connections to the
+end of your new 2.x file.</P>
+
+<P>Install the RPMs suitable for your kernel version, such as:</P>
+<PRE> rpm -ivh freeswan-module-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<PRE> rpm -ivh freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+
+
+
+<P>Or, to splice the files:</P>
+
+<PRE> cat /etc/ipsec.conf /etc/ipsec.conf.rpmsave > /etc/ipsec.conf.tmp
+ mv /etc/ipsec.conf.tmp /etc/ipsec.conf</PRE>
+
+<P>Then, remove the redundant <VAR>conn %default</VAR> and
+<VAR>config setup</VAR>
+sections. Unless you have done any special configuring here, you'll likely
+want to remove the 1.x versions. Remove <VAR>conn OEself</VAR>, if
+present.</P>
+
+
+
+</body>
+</html>
diff --git a/doc/src/user_examples.html b/doc/src/user_examples.html
new file mode 100755
index 000000000..5e3784858
--- /dev/null
+++ b/doc/src/user_examples.html
@@ -0,0 +1,322 @@
+<html>
+<head>
+<title>FreeS/WAN examples</title>
+<meta name="keywords" content="Linux, IPsec, VPN, security, FreeSWAN, examples">
+
+<!--
+
+Written by Sandy Harris for the Linux FreeS/WAN project
+Freely distributable under the GNU General Public License
+
+More information at www.freeswan.org
+Feedback to users@lists.freeswan.org
+
+CVS information:
+RCS ID: $Id: user_examples.html,v 1.1 2004/03/15 20:35:24 as Exp $
+Last changed: $Date: 2004/03/15 20:35:24 $
+Revision number: $Revision: 1.1 $
+
+CVS revision numbers do not correspond to FreeS/WAN release numbers.
+-->
+</head>
+
+<body>
+
+<h1><a name="user.examples">FreeS/WAN script examples</a></h1>
+
+This file is intended to hold a collection of user-written example
+scripts or configuration files for use with FreeS/WAN.
+<p>
+So far it has only one entry.
+
+<h2><a name="poltorak">Poltorak's Firewall script</a></h2>
+
+<pre>
+From: Poltorak Serguei &lt;poltorak@dataforce.net&gt;
+Subject: [Users] Using FreeS/WAN
+Date: Tue, 16 Oct 2001
+
+Hello.
+
+I'm using FreeS/WAN IPsec for half a year. I learned a lot of things about
+it and I think it would be interesting for someone to see the result of my
+experiments and usage of FreeS/WAN. If you find a mistake in this
+file, please e-mail me. And excuse me for my english... I'm learning.. :)
+
+I'll talk about vary simple configuration:
+
+addresses prefix = 192.168
+
+ lan1 sgw1 .0.0/24 (Internet) sgw2 lan2
+ .1.0/24---[ .1.1 ; .0.1 ]===================[ .0.10 ; . 2.10 ]---.2.0/24
+
+
+We need to let lan1 see lan2 across Internet like it is behind sgw1. The
+same for lan2. And we need to do IPX bridge for Novel Clients and NDS
+synchronization.
+
+my config:
+------------------- ipsec.conf -------------------
+conn lan1-lan2
+ type=tunnel
+ compress=yes
+ #-------------------
+ left=192.168.0.1
+ leftsubnet=192.168.1.0/24
+ #-------------------
+ right=192.168.0.10
+ rightsubnet=192.168.2.0/24
+ #-------------------
+ auth=esp
+ authby=secret
+--------------- end of ipsec.conf ----------------
+
+ping .2.x from .1.y (y != 1)
+It works?? Fine. Let's continue...
+
+Why y != 1 ?? Because kernel of sgw1 have 2 IP addresses and it will choose
+the first IP (which is used to go to Internet) .0.1 and the packet won't go
+through IPsec tunnel :( But if do ping on .1.1 kernel will respond from
+that address (.1.1) and the packet will be tunneled. The same problem occurred then
+.2.x sends a packet to .1.2 which is down at the moment. What happens? .1.1
+sends ARP requesting .1.2... after 3 tries it send to .2.x an destunreach,
+but from his "natural" IP or .0.1 . So the error message won't be delivered!
+It's a big problem...
+
+Resolution... One can manipulate with ipsec0 or ipsec0:0 to solve the
+problem (if ipsec0 has .1.1 kernel will send packets correctly), but there
+are powerful and elegant iproute2 :) We simply need to change source address
+of packet that goes to other secure lan. This is done with
+
+ip route replace 192.168.2.0/24 via 192.168.0.10 dev ipsec0 src 192.168.1.1
+
+Cool!! Now it works!!
+
+The second step. We want install firewall on sgw1 and sgw2. Encryption of
+traffic without security isn't a good idea. I don't use {left|right}firewall,
+because I'm running firewall from init scripts.
+
+We want IPsec data between lan1-lan2, some ICMP errors (destination
+unreachable, TTL exceeded, parameter problem and source quench), replying on
+pings from both lans and Internet, ipxtunnel data for IPX and of course SSH
+between sgw1 and sgw2 and from/to one specified host.
+
+I'm using ipchains. With iptables there are some changes.
+
+---------------- rc.firewall ---------------------
+#!/bin/sh
+#
+# Firewall for IPsec lan1-lan2
+#
+
+IPC=/sbin/ipchains
+ANY=0.0.0.0/0
+
+# left
+SGW1_EXT=192.168.0.1
+SGW1_INT=192.168.1.1
+LAN1=192.168.1.0/24
+
+# right
+SGW2_EXT=192.168.0.10
+SGW2_INT=192.168.2.10
+LAN2=192.168.2.0/24
+
+# SSH from and to this host
+SSH_PEER_HOST=_SOME_HOST_
+
+# this is for left. exchange these values for right.
+MY_EXT=$SGW1_EXT
+MY_INT=$SGW1_INT
+PEER_EXT=$SGW2_EXT
+PEER_INT=$SGW2_INT
+INT_IF=eth1
+EXT_IF=eth0
+IPSEC_IF=ipsec0
+MY_LAN=$LAN1
+PEER_LAN=$LAN2
+
+$IPC -F
+$IPC -P input DENY
+$IPC -P forward DENY
+$IPC -P output DENY
+
+# Loopback traffic
+$IPC -A input -i lo -j ACCEPT
+$IPC -A output -i lo -j ACCEPT
+
+# for IPsec SGW1-SGW2
+## IKE
+$IPC -A input -p udp -s $PEER_EXT 500 -d $MY_EXT 500 -i $EXT_IF -j ACCEPT
+$IPC -A output -p udp -s $MY_EXT 500 -d $PEER_EXT 500 -i $EXT_IF -j ACCEPT
+## ESP
+$IPC -A input -p 50 -s $PEER_EXT -d $MY_EXT -i $EXT_IF -j ACCEPT
+### we don't need this line ### $IPC -A output -p 50 -s $MY_EXT -d $PEER_EXT -i $EXT_IF -j ACCEPT
+## forward LAN1-LAN2
+$IPC -A forward -s $MY_LAN -d $PEER_LAN -i $IPSEC_IF -j ACCEPT
+$IPC -A forward -s $PEER_LAN -d $MY_LAN -i $INT_IF -j ACCEPT
+$IPC -A output -s $PEER_LAN -d $MY_LAN -i $INT_IF -j ACCEPT
+$IPC -A input -s $PEER_LAN -d $MY_LAN -i $IPSEC_IF -j ACCEPT
+$IPC -A input -s $MY_LAN -d $PEER_LAN -i $INT_IF -j ACCEPT
+$IPC -A output -s $MY_LAN -d $PEER_LAN -i $IPSEC_IF -j ACCEPT
+
+# ICMP
+#
+## Dest unreachable
+### from/to Internet
+$IPC -A input -p icmp --icmp-type destination-unreachable -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type destination-unreachable -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### from/to Lan
+$IPC -A input -p icmp --icmp-type destination-unreachable -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type destination-unreachable -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### from/to Peer Lan
+$IPC -A input -p icmp --icmp-type destination-unreachable -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type destination-unreachable -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+#
+## Source quench
+### from/to Internet
+$IPC -A input -p icmp --icmp-type source-quench -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type source-quench -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### from/to Lan
+$IPC -A input -p icmp --icmp-type source-quench -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type source-quench -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### from/to Peer Lan
+$IPC -A input -p icmp --icmp-type source-quench -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type source-quench -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+#
+## Parameter problem
+### from/to Internet
+$IPC -A input -p icmp --icmp-type parameter-problem -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type parameter-problem -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### from/to Lan
+$IPC -A input -p icmp --icmp-type parameter-problem -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type parameter-problem -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### from/to Peer Lan
+$IPC -A input -p icmp --icmp-type parameter-problem -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type parameter-problem -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+#
+## Time To Live exceeded
+### from/to Internet
+$IPC -A input -p icmp --icmp-type time-exceeded -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type time-exceeded -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### to Lan
+$IPC -A input -p icmp --icmp-type time-exceeded -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type time-exceeded -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### to Peer Lan
+$IPC -A input -p icmp --icmp-type time-exceeded -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type time-exceeded -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+
+# ICMP PINGs
+## from Internet
+$IPC -A input -p icmp -s $ANY -d $MY_EXT --icmp-type echo-request -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp -s $MY_EXT -d $ANY --icmp-type echo-reply -i $EXT_IF -j ACCEPT
+## from LAN
+$IPC -A input -p icmp -s $ANY -d $MY_INT --icmp-type echo-request -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp -s $MY_INT -d $ANY --icmp-type echo-reply -i $INT_IF -j ACCEPT
+## from Peer LAN
+$IPC -A input -p icmp -s $ANY -d $MY_INT --icmp-type echo-request -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp -s $MY_INT -d $ANY --icmp-type echo-reply -i $IPSEC_IF -j ACCEPT
+
+# SSH
+## from SSH_PEER_HOST
+$IPC -A input -p tcp -s $SSH_PEER_HOST -d $MY_EXT 22 -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp \! -y -s $MY_EXT 22 -d $SSH_PEER_HOST -i $EXT_IF -j ACCEPT
+## to SSH_PEER_HOST
+$IPC -A input -p tcp \! -y -s $SSH_PEER_HOST 22 -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp -s $MY_EXT -d $SSH_PEER_HOST 22 -i $EXT_IF -j ACCEPT
+## from PEER
+$IPC -A input -p tcp -s $PEER_EXT -d $MY_EXT 22 -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp \! -y -s $MY_EXT 22 -d $PEER_EXT -i $EXT_IF -j ACCEPT
+## to PEER
+$IPC -A input -p tcp \! -y -s $PEER_EXT 22 -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp -s $MY_EXT -d $PEER_EXT 22 -i $EXT_IF -j ACCEPT
+
+# ipxtunnel
+$IPC -A input -p udp -s $PEER_INT 2005 -d $MY_INT 2005 -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p udp -s $MY_INT 2005 -d $PEER_INT 2005 -i $IPSEC_IF -j ACCEPT
+
+---------------- end of rc.firewall ----------------------
+
+To understand this we need to look on this scheme:
+
+ ++-----------------------&lt;----------------------------+
+ || ipsec0 |
+ \/ |
+ eth0 +--------+ /---------/ yes /---------/ yes +-----------------------+
+------&gt;| INPUT |--&gt;/ ?local? /-----&gt;/ ?IPsec? /-----&gt;| decrypt & decapsulate |
+ eth1 +--------+ /---------/ /---------/ +-----------------------+
+ || no || no
+ \/ \/
+ +----------+ +---------+ +-------+
+ | routing | | local | | local |
+ | decision | | deliver | | send |
+ +----------+ +---------+ +-------+
+ || ||
+ \/ \/
+ +---------+ +----------+
+ | forward | | routing |
+ +---------+ | decision |
+ || +----------+
+ || ||
+ ++----------------&lt;-----------------++
+ ||
+ \/
+ +--------+ eth0
+ | OUTPUT | eth1
+ +--------+ ipsec0
+ ||
+ \/
+ /---------/ yes +-----------------------+
+ / ?IPsec? /-----&gt;| encrypt & encapsulate |
+ /---------/ +-----------------------+
+ || no ||
+ || ||
+ || \/ eth0, eth1
+ ++-----------------------++--------------&gt;
+
+This explain how a packet traverse TCP/IP stack in IPsec capable kernel.
+
+FIX ME, please, if there are any errors
+
+Test the new firewall now.
+
+
+Now about IPX. I tried 3 programs for tunneling IPX: tipxd, SIB and ipxtunnel
+
+tipxd didn't send packets.. :(
+SIB and ipxtunnel worked fine :)
+With ipxtunnel there was a little problem. In sources there are an error.
+
+--------------------- in main.c ------------------------
+&lt; bytes += p.len;
+---
+&gt; bytes += len;
+--------------------------------------------------------
+
+After this FIX everything goes right...
+
+------------------- /etc/ipxtunnel.conf ----------------
+port 2005
+remote 192.168.101.97 2005
+interface eth1
+--------------- end of /etc/ipxtunnel.conf -------------
+
+I use IPX tunnel between .1.1 and .2.10 so we don't need to encrypt nor
+authenticate encapsulated IPX packets, it is done with IPsec.
+
+If you don't wont to use iproute2 to change source IP you need to use SIB
+(it is able to bind local address) or establish tunnel between .0.1 and
+.0.10 (external IPs, you need to do encryption in the program, but it isn't
+strong).
+
+For now I'm using ipxtunnel.
+
+I think that's all for the moment. If there are any error, please e-mail me:
+poltorak@df.ru . It would be cool if someone puts the scheme of TCP/IP in
+kernel and firewall example on FreeS/WAN's manual pages.
+
+PoltoS
+</pre>
+
+</body>
+</html> \ No newline at end of file
diff --git a/doc/src/web.html b/doc/src/web.html
new file mode 100644
index 000000000..19df6ffa6
--- /dev/null
+++ b/doc/src/web.html
@@ -0,0 +1,905 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html">
+ <title>FreeS/WAN web links</title>
+ <meta name="keywords"
+ content="Linux, IPsec, VPN, security, FreeSWAN, links, web">
+ <!--
+
+ Written by Sandy Harris for the Linux FreeS/WAN project
+ Freely distributable under the GNU General Public License
+
+ More information at www.freeswan.org
+ Feedback to users@lists.freeswan.org
+
+ CVS information:
+ RCS ID: $Id: web.html,v 1.1 2004/03/15 20:35:24 as Exp $
+ Last changed: $Date: 2004/03/15 20:35:24 $
+ Revision number: $Revision: 1.1 $
+
+ CVS revision numbers do not correspond to FreeS/WAN release numbers.
+ -->
+</head>
+
+<body>
+<h1><a name="weblink">Web links</a></h1>
+
+<h2><a name="freeswan">The Linux FreeS/WAN Project</a></h2>
+
+<p>The main project web site is <a
+href="http://www.freeswan.org/">www.freeswan.org</a>.</p>
+
+<p>Links to other project-related <a href="intro.html#sites">sites</a> are
+provided in our introduction section.</p>
+
+<h3><a name="patch">Add-ons and patches for FreeS/WAN</a></h3>
+
+<p>Some user-contributed patches have been integrated into the FreeS/WAN
+distribution. For a variety of reasons, those listed below have not.</p>
+
+<p>Note that not all patches are a good idea.</p>
+<ul>
+ <li>There are a number of "features" of IPsec which we do not implement
+ because they reduce security. See this <a
+ href="compat.html#dropped">discussion</a>. We do not recommend using
+ patches that implement these. One example is aggressive mode.</li>
+ <li>We do not recommend adding "features" of any sort unless they are
+ clearly necessary, or at least have clear benefits. For example,
+ FreeS/WAN would not become more secure if it offerred a choice of 14
+ ciphers. If even one was flawed, it would certainly become less secure
+ for anyone using that cipher. Even with 14 wonderful ciphers, it would be
+ harder to maintain and administer, hence more vulnerable to various human
+ errors.</li>
+</ul>
+
+<p>This is not to say that patches are necessarily bad, only that using them
+requires some deliberation. For example, there might be perfectly good
+reasons to add a specific cipher in your application: perhaps GOST to comply
+with government standards in Eastern Europe, or AES for performance
+benefits.</p>
+
+<h4>Current patches</h4>
+
+<p>Patches believed current::</p>
+<ul>
+ <li>patches for <a href="http://www.strongsec.com/freeswan/">X.509
+ certificate support</a>, also available from a <a
+ href="http://www.twi.ch/~sna/strongsec/freeswan/">mirror site</a></li>
+ <li>patches to add <a href="http://www.irrigacion.gov.ar/juanjo/ipsec">AES
+ and other ciphers</a>. There is preliminary data indicating AES gives a
+ substantial <a href="performance.html#perf.more">performance
+ gain</a>.</li>
+</ul>
+
+<p>There is also one add-on that takes the form of a modified FreeS/WAN
+distribution, rather than just patches to the standard distribution:</p>
+<ul>
+ <li><a href="http://www.ipv6.iabg.de/downloadframe/index.html">IPv6
+ support</a></li>
+</ul>
+
+<p>Before using any of the above,, check the <a href="mail.html">mailing
+lists</a> for news of newer versions and to see whether they have been
+incorporated into more recent versions of FreeS/WAN.</p>
+
+<h4>Older patches</h4>
+<ul>
+ <li><a href="http://sources.colubris.com/en/projects/FreeSWAN/">hardware
+ acceleration</a></li>
+ <li>a <a href="http://tzukanov.narod.ru/">series</a> of patches that
+ <ul>
+ <li>provide GOST, a Russian gov't. standard cipher, in MMX
+ assembler</li>
+ <li>add GOST to OpenSSL</li>
+ <li>add GOST to the International kernel patch</li>
+ <li>let FreeS/WAN use International kernel patch ciphers</li>
+ </ul>
+ </li>
+ <li>Neil Dunbar's patches for <a
+ href="ftp://hplose.hpl.hp.com/pub/nd/pluto-openssl.tar.gz">certificate
+ support</a>, using code from <a href="http://www.openssl.org">Open
+ SSL</a>.</li>
+ <li>Luc Lanthier's <a
+ href="ftp://ftp.netwinder.org/users/f/firesoul/">patches</a> for <a
+ href="glossary.html#PKIX">PKIX</a> support.</li>
+ <li><a href="ftp://ftp.heise.de/pub/ct/listings/9916-180.tgz">patches</a>
+ to add <a href="glossary.html#blowfish">Blowfish</a>, <a
+ href="glossary.html#IDEA">IDEA</a> and <a
+ href="glossary.html#CAST128">CAST-128</a> to FreeS/WAN</li>
+ <li>patches for FreeS/WAN 1.3, Pluto support for <a
+ href="http://alcatraz.webcriminals.com/~bastiaan/ipsec/">external
+ authentication</a>, for example with a smartcard or SKEYID.</li>
+ <li><a href="http://www.zengl.net/freeswan/download/">patches and
+ utilities</a> for using FreeS/WAN with PGPnet</li>
+ <li><a
+ href="http://www.freelith.com/lithworks/crypto/freeswan_patch.htm">Blowfish
+ encryption and Tiger hash</a></li>
+ <li><a
+ href="http://www.cendio.se/~bellman/aggressive-pluto.snap.tar.gz">patches</a>
+ for aggressive mode support</li>
+</ul>
+
+<p>These patches are for older versions of FreeS/WAN and will likely not work
+with the current version. Older versions of FreeS/WAN may be available on
+some of the <a href="intro.html#sites">distribution sites</a>, but we
+recommend using the current release.</p>
+
+<h4><a name="VPN.masq">VPN masquerade patches</a></h4>
+
+<p>Finally, there are some patches to other code that may be useful with
+FreeS/WAN:</p>
+<ul>
+ <li>a <a
+ href="ftp://ftp.rubyriver.com/pub/jhardin/masquerade/ip_masq_vpn.html">patch</a>
+ to make IPsec, PPTP and SSH VPNs work through a Linux firewall with <a
+ href="glossary.html#masq">IP masquerade</a>.</li>
+ <li><a href="http://www.linuxdoc.org/HOWTO/VPN-Masquerade-HOWTO.html">Linux
+ VPN Masquerade HOWTO</a></li>
+</ul>
+
+<p>Note that this is not required if the same machine does IPsec and
+masquerading, only if you want a to locate your IPsec gateway on a
+masqueraded network. See our <a href="firewall.html#NAT">firewalls</a>
+document for discussion of why this is problematic.</p>
+
+<p>At last report, this patch could not co-exist with FreeS/WAN on the same
+machine.</p>
+
+<h3><a name="dist">Distributions including FreeS/WAN</a></h3>
+
+<p>The introductory section of our document set lists several <a
+href="intro.html#distwith">Linux distributions</a> which include
+FreeS/WAN.</p>
+
+<h3><a name="used">Things FreeS/WAN uses or could use</a></h3>
+<ul>
+ <li><a href="http://openpgp.net/random">/dev/random</a> support page,
+ discussion of and code for the Linux <a
+ href="glossary.html#random">random number driver</a>. Out-of-date when we
+ last checked (January 2000), but still useful.</li>
+ <li>other programs related to random numbers:
+ <ul>
+ <li><a href="http://www.mindrot.org/audio-entropyd.html">audio entropy
+ daemon</a> to gather noise from a sound card and feed it into
+ /dev/random</li>
+ <li>an <a href="http://www.lothar.com/tech/crypto/">entropy-gathering
+ daemon</a></li>
+ <li>a driver for the random number generator in recent <a
+ href="http://sourceforge.net/projects/gkernel/">Intel chipsets</a>.
+ This driver is included as standard in 2.4 kernels.</li>
+ </ul>
+ </li>
+ <li>a Linux <a href="http://www.marko.net/l2tp/">L2TP Daemon</a> which
+ might be useful for communicating with Windows 2000 which builds L2TP
+ tunnels over its IPsec connections</li>
+ <li>to use opportunistic encryption, you need a recent version of <a
+ href="glossary.html#BIND">BIND</a>. You can get one from the <a
+ href="http://www.isc.org">Internet Software Consortium</a> who maintain
+ BIND.</li>
+</ul>
+
+<h3><a name="alternatives">Other approaches to VPNs for Linux</a></h3>
+<ul>
+ <li>other Linux <a href="#linuxipsec">IPsec implementations</a></li>
+ <li><a href="http://www.tik.ee.ethz.ch/~skip/">ENskip</a>, a free
+ implementation of Sun's <a href="glossary.html#SKIP">SKIP</a>
+ protocol</li>
+ <li><a href="http://sunsite.auc.dk/vpnd/">vpnd</a>, a non-IPsec VPN daemon
+ for Linux which creates tunnels using <a
+ href="glossary.html#Blowfish">Blowfish</a> encryption</li>
+ <li><a href="http://www.winton.org.uk/zebedee/">Zebedee</a>, a simple GPLd
+ tunnel-building program with Linux and Win32 versions. The name is from
+ <strong>Z</strong>lib compression, <strong>B</strong>lowfish encryption
+ and <strong>D</strong>iffie-Hellman key exchange.</li>
+ <li>There are at least two PPTP implementations for Linux
+ <ul>
+ <li>Moreton Bay's <a
+ href="http://www.moretonbay.com/vpn/pptp.html">PoPToP</a></li>
+ <li><a
+ href="http://cag.lcs.mit.edu/~cananian/Projects/PPTP/">PPTP-Linux</a></li>
+ </ul>
+ </li>
+ <li><a href="http://sites.inka.de/sites/bigred/devel/cipe.html">CIPE</a>
+ (crypto IP encapsulation) project, using their own lightweight protocol
+ to encrypt between routers</li>
+ <li><a href="http://tinc.nl.linux.org/">tinc</a>, a VPN Daemon</li>
+</ul>
+
+<p>There is a list of <a
+href="http://www.securityportal.com/lskb/10000000/kben10000005.html">Linux
+VPN</a> software in the <a
+href="http://www.securityportal.com/lskb/kben00000001.html">Linux Security
+Knowledge Base</a>.</p>
+
+<h2><a name="ipsec.link">The IPsec Protocols</a></h2>
+
+<h3><a name="general">General IPsec or VPN information</a></h3>
+<ul>
+ <li>The <a href="http://www.vpnc.org">VPN Consortium</a> is a group for
+ vendors of IPsec products. Among other things, they have a good
+ collection of <a href="http://www.vpnc.org/white-papers.html">IPsec white
+ papers</a>.</li>
+ <li>A VPN mailing list with a <a
+ href="http://kubarb.phsx.ukans.edu/~tbird/vpn.html">home page</a>, a FAQ,
+ some product comparisons, and many links.</li>
+ <li><a href="http://www.opus1.com/vpn/index.html">VPN pointer page</a></li>
+ <li>a <a href="http://www.epm.ornl.gov/~dunigan/vpn.html">collection</a> of
+ VPN links, and some explanation</li>
+</ul>
+
+<h3><a name="overview">IPsec overview documents or slide sets</a></h3>
+<ul>
+ <li>the FreeS/WAN <a href="ipsec.html">document section</a> on these
+ protocols</li>
+</ul>
+
+<h3><a name="otherlang">IPsec information in languages other than
+English</a></h3>
+<ul>
+ <li><a
+ href="http://www.imib.med.tu-dresden.de/imib/Internet/Literatur/ipsec-docu.html">German</a></li>
+ <li><a href="http://www.kame.net/index-j.html">Japanese</a></li>
+ <li>Feczak Szabolcs' thesis in <a
+ href="http://feczo.koli.kando.hu/vpn/">Hungarian</a></li>
+ <li>Davide Cerri's thesis and some presentation slides <a
+ href="http://www.linux.it/~davide/doc/">Italian</a></li>
+</ul>
+
+<h3><a name="RFCs1">RFCs and other reference documents</a></h3>
+<ul>
+ <li><a href="rfc.html">Our document</a> listing the RFCs relevant to Linux
+ FreeS/WAN and giving various ways of obtaining both RFCs and Internet
+ Drafts.</li>
+ <li><a href="http://www.vpnc.org/vpn-standards.html">VPN Standards</a> page
+ maintained by <a href="glossary.html#VPNC">VPNC</a>. This covers both
+ RFCs and Drafts, and classifies them in a fairly helpful way.</li>
+ <li><a href="http://www.rfc-editor.org">RFC archive</a></li>
+ <li><a href="http://www.ietf.org/ids.by.wg/ipsec.html">Internet Drafts</a>
+ related to IPsec</li>
+ <li>US government <a href="http://www.itl.nist.gov/div897/pubs"> site</a>
+ with their <a href="glossary.html#FIPS">FIPS</a> standards</li>
+ <li>Archives of the ipsec@tis.com mailing list where discussion of drafts
+ takes place.
+ <ul>
+ <li><a href="http://www.sandelman.ottawa.on.ca/ipsec">Eastern
+ Canada</a></li>
+ <li><a href="http://www.vpnc.org/ietf-ipsec">California</a>.</li>
+ </ul>
+ </li>
+</ul>
+
+<h3><a name="analysis">Analysis and critiques of IPsec protocols</a></h3>
+<ul>
+ <li>Counterpane's <a
+ href="http://www.counterpane.com/ipsec.pdf">evaluation</a> of the
+ protocols</li>
+ <li>Simpson's <a
+ href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/1999/06/msg00319.html">IKE
+ Considered Dangerous</a> paper. Note that this is a link to an archive of
+ our mailing list. There are several replies in addition to the paper
+ itself.</li>
+ <li>Fate Labs <a href="http://www.fatelabs.com/loki-vpn.pdf">Virual Private
+ Problems: the Broken Dream</a></li>
+ <li>Catherine Meadows' paper <cite>Analysis of the Internet Key Exchange
+ Protocol Using the NRL Protocol Analyzer</cite>, in <a
+ href="http://chacs.nrl.navy.mil/publications/CHACS/1999/1999meadows-IEEE99.pdf">PDF</a>
+ or <a
+ href="http://chacs.nrl.navy.mil/publications/CHACS/1999/1999meadows-IEEE99.ps">Postscript</a>.</li>
+ <li>Perlman and Kaufmnan
+ <ul>
+ <li><a
+ href="http://snoopy.seas.smu.edu/ee8392_summer01/week7/perlman2.pdf">Key
+ Exchange in IPsec</a></li>
+ <li>a newer <a
+ href="http://sec.femto.org/wetice-2001/papers/radia-paper.pdf">PDF
+ paper</a>, <cite>Analysis of the IPsec Key Exchange
+ Standard</cite>.</li>
+ </ul>
+ </li>
+ <li>Bellovin's <a
+ href="http://www.research.att.com/~smb/papers/index.html">papers</a> page
+ including his:
+ <ul>
+ <li><cite>Security Problems in the TCP/IP Protocol Suite</cite>
+ (1989)</li>
+ <li><cite>Problem Areas for the IP Security Protocols</cite> (1996)</li>
+ <li><cite>Probable Plaintext Cryptanalysis of the IP Security
+ Protocols</cite> (1997)</li>
+ </ul>
+ </li>
+ <li>An <a href="http://www.lounge.org/ike_doi_errata.html">errata list</a>
+ for the IPsec RFCs.</li>
+</ul>
+
+<h3><a name="IP.background">Background information on IP</a></h3>
+<ul>
+ <li>An <a href="http://ipprimer.windsorcs.com/">IP tutorial</a> that seems
+ to be written mainly for Netware or Microsoft LAN admins entering a new
+ world</li>
+ <li><a href="http://www.iana.org">IANA</a>, Internet Assigned Numbers
+ Authority</li>
+ <li><a href="http://public.pacbell.net/dedicated/cidr.html">CIDR</a>,
+ Classless Inter-Domain Routing</li>
+ <li>Also see our <a href="biblio.html">bibliography</a></li>
+</ul>
+
+<h2><a name="implement">IPsec Implementations</a></h2>
+
+<h3><a name="linuxprod">Linux products</a></h3>
+
+<p>Vendors using FreeS/WAN in turnkey firewall or VPN products are listed in
+our <a href="intro.html#turnkey">introduction</a>.</p>
+
+<p>Other vendors have Linux IPsec products which, as far as we know, do not
+use FreeS/WAN</p>
+<ul>
+ <li><a href="http://www.redcreek.com/products/shareware.html">Redcreek</a>
+ provide an open source Linux driver for their PCI hardware VPN card. This
+ card has a 100 Mbit Ethernet port, an Intel 960 CPU plus more specialised
+ crypto chips, and claimed encryption performance of 45 Mbit/sec. The PC
+ sees it as an Ethernet board.</li>
+ <li><a href="http://linuxtoday.com/stories/8428.html?nn">Paktronix</a>
+ offer a Linux-based VPN with hardware encryption</li>
+ <li><a href="http://www.watchguard.com/">Watchguard</a> use Linux in their
+ Firebox product.</li>
+ <li><a href="http://www.entrust.com">Entrust</a> offer a developers'
+ toolkit for using their <a href="glossary.html#PKI">PKI</a> for IPsec
+ authentication</li>
+ <li>According to a report on our mailing list, <a
+ href="http://www.axent.com">Axent</a> have a Linux version of their
+ product.</li>
+</ul>
+
+<h3><a name="router">IPsec in router products</a></h3>
+
+<p>All the major router vendors support IPsec, at least in some models.</p>
+<ul>
+ <li><a href="http://www.cisco.com/warp/public/707/16.html">Cisco</a> IPsec
+ information</li>
+ <li>Ascend, now part of <a href="http://www.lucent.com/">Lucent</a>, have
+ some IPsec-based products</li>
+ <li><a href="http://www.nortelnetworks.com/">Bay Networks</a>, now part of
+ Nortel, use IPsec in their Contivity switch product line</li>
+ <li><a href="http://www.3com.com/products/enterprise.html">3Com</a> have a
+ number of VPN products, some using IPsec</li>
+</ul>
+
+<h3><a name="fw.web">IPsec in firewall products</a></h3>
+
+<p>Many firewall vendors offer IPsec, either as a standard part of their
+product, or an optional extra. A few we know about are:</p>
+<ul>
+ <li><a href="http://www.borderware.com/">Borderware</a></li>
+ <li><a href="http://www.ashleylaurent.com/vpn/ipsec_vpn.htm">Ashley
+ Laurent</a></li>
+ <li><a href="http://www.watchguard.com">Watchguard</a></li>
+ <li><a href="http://www.fx.dk/firewall/ipsec.html">Injoy</a> for OS/2</li>
+</ul>
+
+<p>Vendors using FreeS/WAN in turnkey firewall products are listed in our <a
+href="intro.html#turnkey">introduction</a>.</p>
+
+<h3><a name="ipsecos">Operating systems with IPsec support</a></h3>
+
+<p>All the major open source operating systems support IPsec. See below for
+details on <a href="#BSD">BSD-derived</a> Unix variants.</p>
+
+<p>Among commercial OS vendors, IPsec players include:</p>
+<ul>
+ <li><a
+ href="http://msdn.microsoft.com/isapi/msdnlib.idc?theURL=/library/backgrnd/html/msdn_ip_security.htm">Microsoft</a>
+ have put IPsec in their Windows 2000 and XP products</li>
+ <li><a
+ href="http://www.s390.ibm.com/stories/1999/os390v2r8_pr.html">IBM</a>
+ announce a release of OS390 with IPsec support via a crypto
+ co-processor</li>
+ <li><a
+ href="http://www.sun.com/solaris/ds/ds-security/ds-security.pdf">Sun</a>
+ include IPsec in Solaris 8</li>
+ <li><a
+ href="http://www.hp.com/security/products/extranet-security.html">Hewlett
+ Packard</a> offer IPsec for their Unix machines</li>
+ <li>Certicom have IPsec available for the <a
+ href="http://www.certicom.com/products/movian/movianvpn_tech.html">Palm</a>.</li>
+ <li>There were reports before the release that Apple's Mac OS X would have
+ IPsec support built in, but it did not seem to be there when we last
+ checked. If you find, it please let us know via the <a
+ href="mail.html">mailing list</a>.</li>
+</ul>
+
+<h3>IPsec on network cards</h3>
+
+<p>Network cards with built-in IPsec acceleration are available from at least
+Intel, 3Com and Redcreek.</p>
+
+<h3><a name="opensource">Open source IPsec implementations</a></h3>
+
+<h4><a name="linuxipsec">Other Linux IPsec implementations</a></h4>
+
+<p>We like to think of FreeS/WAN as <em>the</em> Linux IPsec implementation,
+but it is not the only one. Others we know of are:</p>
+<ul>
+ <li><a href="http://www.enst.fr/~beyssac/pipsec/">pipsecd</a>, a
+ lightweight implementation of IPsec for Linux. Does not require kernel
+ recompilation.</li>
+ <li>Petr Novak's <a href="ftp://ftp.eunet.cz/icz/ipnsec/">ipnsec</a>, based
+ on the OpenBSD IPsec code and using <a
+ href="glossary.html#photuris">Photuris</a> for key management</li>
+ <li>A now defunct project at <a
+ href="http://www.cs.arizona.edu/security/hpcc-blue/linux.html">U of
+ Arizona</a> (export controlled)</li>
+ <li><a href="http://snad.ncsl.nist.gov/cerberus">NIST Cerebus</a> (export
+ controlled)</li>
+</ul>
+
+<h4><a name="BSD">IPsec for BSD Unix</a></h4>
+<ul>
+ <li><a href="http://www.kame.net/project-overview.html">KAME</a>, several
+ large Japanese companies co-operating on IPv6 and IPsec</li>
+ <li><a href="http://web.mit.edu/network/isakmp">US Naval Research Lab</a>
+ implementation of IPv6 and of IPsec for IPv4 (export controlled)</li>
+ <li><a href="http://www.openbsd.org">OpenBSD</a> includes IPsec as a
+ standard part of the distribution</li>
+ <li><a href="http://www.r4k.net/ipsec">IPsec for FreeBSD</a></li>
+ <li>a <a href="http://www.netbsd.org/Documentation/network/ipsec/">FAQ</a>
+ on NetBSD's IPsec implementation</li>
+</ul>
+
+<h4><a name="misc">IPsec for other systems</a></h4>
+<ul>
+ <li><a href="http://www.tcm.hut.fi/Tutkimus/IPSEC/">Helsinki U of
+ Technolgy</a> have implemented IPsec for Solaris, Java and Macintosh</li>
+</ul>
+
+<h3><a name="interop.web">Interoperability</a></h3>
+
+<p>The IPsec protocols are designed so that different implementations should
+be able to work together. As they say "the devil is in the details". IPsec
+has a lot of details, but considerable success has been achieved.</p>
+
+<h4><a name="result">Interoperability results</a></h4>
+
+<p>Linux FreeS/WAN has been tested for interoperability with many other IPsec
+implementations. Results to date are in our <a
+href="interop.html">interoperability</a> section.</p>
+
+<p>Various other sites have information on interoperability between various
+IPsec implementations:</p>
+<ul>
+ <li><a href="http://www.opus1.com/vpn/atl99display.html">interop
+ results</a> from a bakeoff in Atlanta, September 1999.</li>
+ <li>a French company, HSC's, <a
+ href="http://www.hsc.fr/ressources/presentations/ipsec99/index.html.en">interoperability</a>
+ test data covers FreeS/WAN, Open BSD, KAME, Linux pipsecd, Checkpoint,
+ Red Creek Ravlin, and Cisco IOS</li>
+ <li><a href="http://www.icsa.net/">ICSA</a> offer certification programs
+ for various security-related products. See their list of <a
+ href="http://www.icsa.net/html/communities/ipsec/certification/certified_products/index.shtml">
+ certified IPsec</a> products. Linux FreeS/WAN is not currently on that
+ list, but several products with which we interoperate are.</li>
+ <li>VPNC have a page on why they are not yet doing <a
+ href="http://www.vpnc.org/interop.html">interoperability</a> testing and
+ a page on the <a href="http://www.vpnc.org/conformance.html">spec
+ conformance</a> testing that they are doing</li>
+ <li>a <a href="http://www.commweb.com/article/COM20000912S0009">review</a>
+ comparing a dozen commercial IPsec implemetations. Unfortunately, the
+ reviewers did not look at Open Source implementations such as FreeS/WAN
+ or OpenBSD.</li>
+ <li><a
+ href="http://www.tanu.org/~sakane/doc/public/report-ike-interop0007.html">results</a>
+ from interoperability tests at a conference. FreeS/WAN was not tested
+ there.</li>
+ <li>test results from the <a
+ href="http://www.hsc.fr/ressources/veille/ipsec/ipsec2000/">IPSEC
+ 2000</a> conference</li>
+</ul>
+
+<h4><a name="test1">Interoperability test sites</a></h4>
+<ul>
+ <li><a href="http://www.tahi.org/">TAHI</a>, a Japanese IPv6 testing
+ project with free IPsec validation software</li>
+ <li><a href="http://ipsec-wit.antd.nist.gov">National Institute of
+ Standards and Technology</a></li>
+ <li><a href="http://isakmp-test.ssh.fi/">SSH Communications
+ Security</a></li>
+</ul>
+
+<h2><a name="linux.link">Linux links</a></h2>
+
+<h3><a name="linux.basic">Basic and tutorial Linux information</a></h3>
+<ul>
+ <li>Linux <a
+ href="http://linuxcentral.com/linux/LDP/LDP/gs/gs.html">Getting
+ Started</a> HOWTO document</li>
+ <li>A getting started guide from the <a
+ href="http://darkwing.uoregon.edu/~cchome/linuxgettingstarted.html">U of
+ Oregon</a></li>
+ <li>A large <a href="http://www.herring.org/techie.html">link
+ collection</a> which includes a lot of introductory and tutorial material
+ on Unix, Linux, the net, . . .</li>
+</ul>
+
+<h3><a name="general">General Linux sites</a></h3>
+<ul>
+ <li><a href="http://www.freshmeat.net">Freshmeat</a> Linux news</li>
+ <li><a href="http://slashdot.org">Slashdot</a> "News for Nerds"</li>
+ <li><a href="http://www.linux.org">Linux Online</a></li>
+ <li><a href="http://www.linuxhq.com">Linux HQ</a></li>
+ <li><a href="http://www.tux.org">tux.org</a></li>
+</ul>
+
+<h3><a name="docs.ldp">Documentation</a></h3>
+
+<p>Nearly any Linux documentation you are likely to want can be found at the
+<a href="http://metalab.unc.edu/LDP">Linux Documentation Project</a> or
+LDP.</p>
+<ul>
+ <li><a href="http://metalab.unc.edu/LDP/HOWTO/META-FAQ.html">Meta-FAQ</a>
+ guide to Linux information sources</li>
+ <li>The LDP's HowTo documents are a standard Linux reference. See this <a
+ href="http://www.linuxdoc.org/docs.html#howto">list</a>. Documents there
+ most relevant to a FreeS/WAN gateway are:
+ <ul>
+ <li><a href="http://metalab.unc.edu/LDP/HOWTO/Kernel-HOWTO.html">Kernel
+ HOWTO</a></li>
+ <li><a
+ href="http://metalab.unc.edu/LDP/HOWTO/Networking-Overview-HOWTO.html">Networking
+ Overview HOWTO</a></li>
+ <li><a
+ href="http://metalab.unc.edu/LDP/HOWTO/Security-HOWTO.html">Security
+ HOWTO</a></li>
+ </ul>
+ </li>
+ <li>The LDP do a series of Guides, book-sized publications with more detail
+ (and often more "why do it this way?") than the HowTos. See this <a
+ href="http://www.linuxdoc.org/guides.html">list</a>. Documents there most
+ relevant to a FreeS/WAN gateway are:
+ <ul>
+ <li><a href="http://www.tml.hut.fi/~viu/linux/sag/">System
+ Administrator's Guide</a></li>
+ <li><a href="http://www.linuxdoc.org/LDP/nag2/index.html">Network
+ Adminstrator's Guide</a></li>
+ <li><a href="http://www.seifried.org/lasg/">Linux Administrator's
+ Security Guide</a></li>
+ </ul>
+ </li>
+</ul>
+
+<p>You may not need to go to the LDP to get this material. Most Linux
+distributions include the HowTos on their CDs and several include the Guides
+as well. Also, most of the Guides and some collections of HowTos are
+available in book form from various publishers.</p>
+
+<p>Much of the LDP material is also available in languages other than
+English. See this <a href="http://www.linuxdoc.org/links/nenglish.html">LDP
+page</a>.</p>
+
+<h3><a name="advroute.web">Advanced routing</a></h3>
+
+<p>The Linux IP stack has some new features in 2.4 kernels. Some HowTos have
+been written:</p>
+<ul>
+ <li>several HowTos for the <a
+ href="http://netfilter.samba.org/unreliable-guides/">netfilter</a>
+ firewall code in newer kernels</li>
+ <li><a
+ href="http://www.ds9a.nl/2.4Networking/HOWTO//cvs/2.4routing/output/2.4networking.html">2.4
+ networking</a> HowTo</li>
+ <li><a
+ href="http://www.ds9a.nl/2.4Networking/HOWTO//cvs/2.4routing/output/2.4routing.html">2.4
+ routing</a> HowTo</li>
+</ul>
+
+<h3><a name="linsec">Security for Linux</a></h3>
+
+<p>See also the <a href="#docs.ldp">LDP material</a> above.</p>
+<ul>
+ <li><a
+ href="http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos">Trinity
+ OS guide to setting up Linux</a></li>
+ <li><a href="http://www.deter.com/unix">Unix security</a> page</li>
+ <li><a href="http://linux01.gwdg.de/~alatham/">PPDD</a> encrypting
+ filesystem</li>
+ <li><a href="http://EncryptionHOWTO.sourceforge.net/">Linux Encryption
+ HowTo</a> (outdated when last checked, had an Oct 2000 revision date in
+ March 2002)</li>
+</ul>
+
+<h3><a name="firewall.linux">Linux firewalls</a></h3>
+
+<p>Our <a href="firewall.html">FreeS/WAN and firewalls</a> document includes
+links to several sets of <a href="firewall.html#examplefw">scripts</a> known
+to work with FreeS/WAN.</p>
+
+<p>Other information sources:</p>
+<ul>
+ <li><a href="http://ipmasq.cjb.net/">IP Masquerade resource page</a></li>
+ <li><a href="http://netfilter.samba.org/unreliable-guides/">netfilter</a>
+ firewall code in 2.4 kernels</li>
+ <li>Our list of general <a href="#firewall.web">firewall references</a> on
+ the web</li>
+ <li><a href="http://users.dhp.com/~whisper/mason/">Mason</a>, a tool for
+ automatically configuring Linux firewalls</li>
+ <li>the web cache software <a href="http://www.squid-cache.org/">squid</a>
+ and <a href="http://www.squidguard.org/">squidguard</a> which turns Squid
+ into a filtering web proxy</li>
+</ul>
+
+<h3><a name="linux.misc">Miscellaneous Linux information</a></h3>
+<ul>
+ <li><a href="http://lwn.net/current/dists.php3">Linux distribution
+ vendors</a></li>
+ <li><a href="http://www.linux.org/groups/">Linux User Groups</a></li>
+</ul>
+
+<h2><a name="crypto.link">Crypto and security links</a></h2>
+
+<h3><a name="security">Crypto and security resources</a></h3>
+
+<h4><a name="std.links">The standard link collections</a></h4>
+
+<p>Two enormous collections of links, each the standard reference in its
+area:</p>
+<dl>
+ <dt>Gene Spafford's <a
+ href="http://www.cerias.purdue.edu/coast/hotlist/">COAST hotlist</a></dt>
+ <dd>Computer and network security.</dd>
+ <dt>Peter Gutmann's <a
+ href="http://www.cs.auckland.ac.nz/~pgut001/links.html">Encryption and
+ Security-related Resources</a></dt>
+ <dd>Cryptography.</dd>
+</dl>
+
+<h4><a name="FAQ">Frequently Asked Question (FAQ) documents</a></h4>
+<ul>
+ <li><a href="http://www.faqs.org/faqs/cryptography-faq/">Cryptography
+ FAQ</a></li>
+ <li><a href="http://www.interhack.net/pubs/fwfaq">Firewall FAQ</a></li>
+ <li><a href="http://www.whitefang.com/sup/secure-faq.html">Secure Unix
+ Programming FAQ</a></li>
+ <li>FAQs for specific programs are listed in the <a href="#tools">tools</a>
+ section below.</li>
+</ul>
+
+<h4><a name="cryptover">Tutorials</a></h4>
+<ul>
+ <li>Gary Kessler's <a
+ href="http://www.garykessler.net/library/crypto.html">Overview of
+ Cryptography</a></li>
+ <li>Terry Ritter's <a
+ href="http://www.ciphersbyritter.com/LEARNING.HTM">introduction</a></li>
+ <li>Peter Gutman's <a
+ href="http://www.cs.auckland.ac.nz/~pgut001/tutorial/index.html">cryptography</a>
+ tutorial (500 slides in PDF format)</li>
+ <li>Amir Herzberg of IBM's sildes for his course <a
+ href="http://www.hrl.il.ibm.com/mpay/course.html">Introduction to
+ Cryptography and Electronic Commerce</a></li>
+ <li>the <a href="http://www.gnupg.org/gph/en/manual/c173.html">concepts
+ section</a> of the <a href="glossary.html#GPG">GNU Privacy Guard</a>
+ documentation</li>
+ <li>Bruce Schneier's self-study <a
+ href="http://www.counterpane.com/self-study.html">cryptanalysis</a>
+ course</li>
+</ul>
+
+<p>See also the <a href="#interesting">interesting papers</a> section
+below.</p>
+
+<h4><a name="standards">Crypto and security standards</a></h4>
+<ul>
+ <li><a href="http://csrc.nist.gov/cc">Common Criteria</a>, new
+ international computer and network security standards to replace the
+ "Rainbow" series</li>
+ <li>AES <a href="http://csrc.nist.gov/encryption/aes/aes_home.htm">
+ Advanced Encryption Standard </a> which will replace DES</li>
+ <li><a href="http://grouper.ieee.org/groups/1363">IEEE P-1363 public key
+ standard</a></li>
+ <li>our collection of links for the <a href="#ipsec.link">IPsec</a>
+ standards</li>
+ <li>history of <a
+ href="http://www.visi.com/crypto/evalhist/index.html">formal
+ evaluation</a> of security policies and implementation</li>
+</ul>
+
+<h4><a name="quotes">Crypto quotes</a></h4>
+
+<p>There are several collections of cryptographic quotes on the net:</p>
+<ul>
+ <li><a href="http://www.eff.org/pub/EFF/quotes.eff">the EFF</a></li>
+ <li><a href="http://www.samsimpson.com/cquotes.php">Sam Simpson</a></li>
+ <li><a href="http://www.amk.ca/quotations/cryptography/page-1.html">AM
+ Kutchling</a></li>
+</ul>
+
+<h3><a name="policy">Cryptography law and policy</a></h3>
+
+<h4><a name="legal">Surveys of crypto law</a></h4>
+<ul>
+ <li>International survey of <a
+ href="http://cwis.kub.nl/~FRW/PEOPLE/koops/lawsurvy.htm"> crypto
+ law</a>.</li>
+ <li>International survey of <a
+ href="http://rechten.kub.nl/simone/ds-lawsu.htm"> digital signature
+ law</a></li>
+</ul>
+
+<h4><a name="oppose">Organisations opposing crypto restrictions</a></h4>
+<ul>
+ <li>The <a href="glossary.html#EFF">EFF</a>'s archives on <a
+ href="http://www.eff.org/pub/Privacy/">privacy</a> and <a
+ href="http://www.eff.org/pub/Privacy/ITAR_export/">export
+ control</a>.</li>
+ <li><a href="http://www.gilc.org">Global Internet Liberty Campaign</a></li>
+ <li><a href="http://www.cdt.org/crypto">Center for Democracy and
+ Technology</a></li>
+ <li><a href="http://www.privacyinternational.org/">Privacy
+ International</a>, who give out <a
+ href="http://www.bigbrotherawards.org/">Big Brother Awards</a> to snoopy
+ organisations</li>
+</ul>
+
+<h4><a name="other.policy">Other information on crypto policy</a></h4>
+<ul>
+ <li><a href="ftp://ftp.isi.edu/in-notes/rfc1984.txt">RFC 1984</a>, the <a
+ href="glossary.html#IAB">IAB</a> and <a
+ href="glossary.html#IESG">IESG</a> Statement on Cryptographic Technology
+ and the Internet.</li>
+ <li>John Young's collection of <a href="http://cryptome.org/">documents</a>
+ of interest to the cryptography, open government and privacy movements,
+ organized chronologically</li>
+ <li>AT&amp;T researcher Matt Blaze's Encryption, Privacy and Security <a
+ href="http://www.crypto.com">Resource Page</a></li>
+ <li>A good <a href="http://cryptome.org/crypto97-ne.htm">overview</a> of
+ the issues from Australia.</li>
+</ul>
+
+<p>See also our documentation section on the <a href="politics.html">history
+and politics</a> of cryptography.</p>
+
+<h3><a name="crypto.tech">Cryptography technical information</a></h3>
+
+<h4><a name="cryptolinks">Collections of crypto links</a></h4>
+<ul>
+ <li><a href="http://www.counterpane.com/hotlist.html">Counterpane</a></li>
+ <li><a href="http://www.cs.auckland.ac.nz/~pgut001/links.html">Peter
+ Gutman's links</a></li>
+ <li><a href="http://www.pca.dfn.de/eng/team/ske/pem-dok.html">PKI
+ links</a></li>
+ <li><a href="http://crypto.yashy.com/www/">Robert Guerra's links</a></li>
+</ul>
+
+<h4><a name="papers">Lists of online cryptography papers</a></h4>
+<ul>
+ <li><a href="http://www.counterpane.com/biblio">Counterpane</a></li>
+ <li><a
+ href="http://www.cryptography.com/resources/papers">cryptography.com</a></li>
+ <li><a href="http://www.cryptosoft.com/html/secpub.htm">Cryptosoft</a></li>
+</ul>
+
+<h4><a name="interesting">Particularly interesting papers</a></h4>
+
+<p>These papers emphasize important issues around the use of cryptography,
+and the design and management of secure systems.</p>
+<ul>
+ <li><a href="http://www.counterpane.com/keylength.html">Key length
+ requirements for security</a></li>
+ <li><a href="http://www.cl.cam.ac.uk/users/rja14/wcf.html">Why
+ Cryptosystems Fail</a></li>
+ <li><a href="http://www.cdt.org/crypto/risks98/">Risks of escrowed
+ encryption</a></li>
+ <li><a href="http://www.counterpane.com/pitfalls.html">Security pitfalls in
+ cryptography</a></li>
+ <li><a href="http://www.acm.org/classics/sep95">Reflections on Trusting
+ Trust</a>, Ken Thompson on Trojan horse design</li>
+ <li><a href="http://www.apache-ssl.org/disclosure.pdf">Security against
+ Compelled Disclosure</a>, how to maintain privacy in the face of legal or
+ other coersion</li>
+</ul>
+
+<h3><a name="compsec">Computer and network security</a></h3>
+
+<h4><a name="seclink">Security links</a></h4>
+<ul>
+ <li><a href="http://www.cs.purdue.edu/coast/hotlist">COAST Hotlist</a></li>
+ <li>DMOZ open directory project <a
+ href="http://dmoz.org/Computers/Security/">computer security</a>
+ links</li>
+ <li><a href="http://www-cse.ucsd.edu/users/bsy/sec.html">Bennet Yee</a></li>
+ <li>Mike Fuhr's <a
+ href="http://www.fuhr.org/~mfuhr/computers/security.html">link
+ collection</a></li>
+ <li><a href="http://www.networkintrusion.co.uk/">links</a> with an emphasis
+ on intrusion detection</li>
+</ul>
+
+<h4><a name="firewall.web">Firewall links</a></h4>
+<ul>
+ <li><a href="http://www.cs.purdue.edu/coast/firewalls">COAST
+ firewalls</a></li>
+ <li><a href="http://www.zeuros.co.uk">Firewalls Resource page</a></li>
+</ul>
+
+<h4><a name="vpn">VPN links</a></h4>
+<ul>
+ <li><a href="http://www.vpnc.org">VPN Consortium</a></li>
+ <li>First VPN's <a href="http://www.firstvpn.com/research/rhome.html">white
+ paper</a> collection</li>
+</ul>
+
+<h4><a name="tools">Security tools</a></h4>
+<ul>
+ <li>PGP -- mail encryption
+ <ul>
+ <li><a href="http://www.pgp.com/">PGP Inc.</a> (part of NAI) for
+ commercial versions</li>
+ <li><a href="http://web.mit.edu/network/pgp.html">MIT</a> distributes
+ the NAI product for non-commercial use</li>
+ <li><a href="http://www.pgpi.org/">international</a> distribution
+ site</li>
+ <li><a href="http://gnupg.org">GNU Privacy Guard (GPG)</a></li>
+ <li><a href="http://www.dk.pgp.net/pgpnet/pgp-faq/">PGP FAQ</a></li>
+ </ul>
+ A message in our mailing list archive has considerable detail on <a
+ href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00029.html">available
+ versions</a> of PGP and on IPsec support in them.
+ <p><strong>Note:</strong> A fairly nasty bug exists in all commercial PGP
+ versions from 5.5 through 6.5.3. If you have one of those,
+ <strong>upgrade now</strong>.</p>
+ </li>
+ <li>SSH -- secure remote login
+ <ul>
+ <li><a href="http://www.ssh.fi">SSH Communications Security</a>, for
+ the original software. It is free for trial, academic and
+ non-commercial use.</li>
+ <li><a href="http://www.openssh.com/">Open SSH</a>, the Open BSD team's
+ free replacement</li>
+ <li><a href="http://www.freessh.org/">freessh.org</a>, links to free
+ implementations for many systems</li>
+ <li><a href="http://www.uni-karlsruhe.de/~ig25/ssh-faq">SSH FAQ</a></li>
+ <li><a
+ href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">Putty</a>,
+ an SSH client for Windows</li>
+ </ul>
+ </li>
+ <li>Tripwire saves message digests of your system files. Re-calculate the
+ digests and compare to saved values to detect any file changes. There are
+ several versions available:
+ <ul>
+ <li><a href="http://www.tripwiresecurity.com/">commercial
+ version</a></li>
+ <li><a href="http://www.tripwire.org/">Open Source</a></li>
+ </ul>
+ </li>
+ <li><a href="http://www.snort.org">Snort</a> and <a
+ href="http://www.lids.org">LIDS</a> are intrusion detection system for
+ Linux</li>
+ <li><a href="http://www.fish.com/~zen/satan/satan.html">SATAN</a> System
+ Administrators Tool for Analysing Networks</li>
+ <li><a href="http://www.insecure.org/nmap/">NMAP</a> Network Mapper</li>
+ <li><a href="ftp://ftp.porcupine.org/pub/security/index.html">Wietse
+ Venema's page</a> with various tools</li>
+ <li><a href="http://ita.ee.lbl.gov/index.html">Internet Traffic
+ Archive</a>, various tools to analyze network traffic, mostly scripts to
+ organise and format tcpdump(8) output for specific purposes</li>
+ <li><a name="ssmail">ssmail -- sendmail patched to do</a> <a
+ href="glossary.html#carpediem">opportunistic encryption</a>
+ <ul>
+ <li><a href="http://www.home.aone.net.au/qualcomm/">web page</a> with
+ links to code and to a Usenix paper describing it, in PDF</li>
+ </ul>
+ </li>
+ <li><a href="http://www.openca.org/">Open CA</a> project to develop a
+ freely distributed <a href="glossary.html#CA">Certification Authority</a>
+ for building a open <a href="glossary.html#PKI">Public Key
+ Infrastructure</a>.</li>
+</ul>
+
+<h3><a name="people">Links to home pages</a></h3>
+
+<p>David Wagner at Berkeley provides a set of links to <a
+href="http://www.cs.berkeley.edu/~daw/people/crypto.html">home pages</a> of
+cryptographers, cypherpunks and computer security people.</p>
+</body>
+</html>
diff --git a/doc/testing.html b/doc/testing.html
new file mode 100644
index 000000000..77626ba5d
--- /dev/null
+++ b/doc/testing.html
@@ -0,0 +1,332 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="performance.html">Previous</A>
+<A HREF="kernel.html">Next</A>
+<HR>
+<H1><A name="test.freeswan">Testing FreeS/WAN</A></H1>
+ This document discusses testing FreeS/WAN.
+<P>Not all types of testing are described here. Other parts of the
+ documentation describe some tests:</P>
+<DL>
+<DT><A href="install.html#testinstall">installation</A> document</DT>
+<DD>testing for a successful install</DD>
+<DT><A href="config.html#testsetup">configuration</A> document</DT>
+<DD>basic tests for a working configuration</DD>
+<DT><A href="web.html#interop.web">web links</A> document</DT>
+<DD>General information on tests for interoperability between various
+ IPsec implementations. This includes links to several test sites.</DD>
+<DT><A href="interop.html">interoperation</A> document.</DT>
+<DD>More specific information on FreeS/WAN interoperation with other
+ implementations.</DD>
+<DT><A href="performance.html">performance</A> document</DT>
+<DD>performance measurements</DD>
+</DL>
+<P>The test setups and procedures described here can also be used in
+ other testing, but this document focuses on testing the IPsec
+ functionality of FreeS/WAN.</P>
+<H2><A NAME="test.oe">Testing opportunistic connections</A></H2>
+<P>This section teaches you how to test your opportunistically encrypted
+ (OE) connections. To set up OE, please see the easy instructions in our<A
+HREF="quickstart.html"> quickstart guide</A>.</P>
+<H3><A NAME="12_1_1">Basic OE Test</A></H3>
+<P>This test is for basic OE functionality.
+<!-- You may use it on an
+<A HREF="quickstart.html#oppo.client">initiate-only OE</A> box or a
+<A HREF="quickstart.html#opp.incoming">full OE</A> box. -->
+ For additional tests, keep
+ reading.</P>
+<P>Be sure IPsec is running. You can see whether it is with:</P>
+<PRE> ipsec setup status</PRE>
+<P>If need be, you can restart it with:</P>
+<PRE> service ipsec restart</PRE>
+<P>Load a FreeS/WAN test website from the host on which you're running
+ FreeS/WAN. Note: the feds may be watching these sites. Type one of:</P>
+<P></P>
+<PRE> links oetest.freeswan.org</PRE>
+<PRE> links oetest.freeswan.nl</PRE>
+
+<!--<PRE> links oetest.freeswan.ca</PRE>-->
+<P>A positive result looks like this:</P>
+<PRE>
+ You seem to be connecting from: 192.0.2.11 which DNS says is:
+ gateway.example.com
+ _________________________________________________________________
+
+ Status E-route
+ OE enabled 16 192.139.46.73/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x2097@192.0.2.11
+ OE enabled 176 192.139.46.77/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x208a@192.0.2.11
+</PRE>
+<P>If you see this, congratulations! Your OE box will now encrypt its
+ own traffic whenever it can. If you have difficulty, see our<A HREF="quickstart.html#oe.trouble">
+ OE troubleshooting tips</A>.</P>
+<H3><A NAME="12_1_2">OE Gateway Test</A></H3>
+<P>If you've set up FreeS/WAN to protect a subnet behind your gateway,
+ you'll need to run another simple test, which can be done from a
+ machine running any OS. That's right, your Windows box can be protected
+ by opportunistic encryption without any FreeS/WAN install or
+ configuration on that box. From<STRONG> each protected subnet node</STRONG>
+, load the FreeS/WAN website with:</P>
+<PRE> links oetest.freeswan.org</PRE>
+<PRE> links oetest.freeswan.nl</PRE>
+<P>A positive result looks like this:</P>
+<PRE>
+ You seem to be connecting from: 192.0.2.98 which DNS says is:
+ box98.example.com
+ _________________________________________________________________
+
+ Status E-route
+ OE enabled 16 192.139.46.73/32 -&gt; 192.0.2.98/32 =&gt;
+ tun0x134ed@192.0.2.11
+ OE enabled 176 192.139.46.77/32 -&gt; 192.0.2.11/32 =&gt;
+ tun0x134d2@192.0.2.11
+</PRE>
+<P>If you see this, congratulations! Your OE gateway will now encrypt
+ traffic for this subnet node whenever it can. If you have difficulty,
+ see our<A HREF="quickstart.html#oe.trouble"> OE troubleshooting tips</A>
+.</P>
+<H3><A NAME="12_1_3">Additional OE tests</A></H3>
+<P>When testing OE, you will often find it useful to execute this
+ command on the FreeS/WAN host:</P>
+<PRE> ipsec eroute</PRE>
+<P>If you have established a connection (either for or for a subnet
+ node) you will see a result like:</P>
+<PRE> 192.0.2.11/32 -&gt; 192.139.46.73/32 =&gt; tun0x149f@192.139.46.38
+</PRE>
+<P>Key:</P>
+<TABLE>
+<TR><TD>1.</TD><TD>192.0.2.11/32</TD><TD>Local start point of the
+ protected traffic.</TD></TR>
+<TR><TD>2.</TD><TD>192.0.2.194/32</TD><TD>Remote end point of the
+ protected traffic.</TD></TR>
+<TR><TD>3.</TD><TD>192.0.48.38</TD><TD>Remote FreeS/WAN node (gateway or
+ host). May be the same as (2).</TD></TR>
+<TR><TD>4.</TD><TD>[not shown]</TD><TD>Local FreeS/WAN node (gateway or
+ host), where you've produced the output. May be the same as (1).</TD></TR>
+</TABLE>
+<P>For extra assurance, you may wish to use a packet sniffer such as<A HREF="http://www.tcpdump.org">
+ tcpdump</A> to verify that packets are being encrypted. You should see
+ output that indicates<STRONG> ESP</STRONG> encrypted data, for example:</P>
+<PRE> 02:17:47.353750 PPPoE [ses 0x1e12] IP 154: xy.example.com &gt; oetest.freeswan.org: ESP(spi=0x87150d16,seq=0x55)</PRE>
+<H2><A name="test.uml">Testing with User Mode Linux</A></H2>
+<P><A href="http://user-mode-linux.sourceforge.net/">User Mode Linux</A>
+ allows you to run Linux as a user process on another Linux machine.</P>
+<P>As of 1.92, the distribution has a new directory named testing. It
+ contains a collection of test scripts and sample configurations. Using
+ these, you can bring up several copies of Linux in user mode and have
+ them build tunnels to each other. This lets you do some testing of a
+ FreeS/WAN configuration on a single machine.</P>
+<P>You need a moderately well-endowed machine for this to work well.
+ Each UML wants about 16 megs of memory by default, which is plenty for
+ FreeS/WAN usage. Typical regression testing only occasionally uses as
+ many as 4 UMLs. If one is doing nothing else with the machine (in
+ particular, not running X on it), then 128 megs and a 500MHz CPU are
+ fine.</P>
+ Documentation on these scripts is<A href="umltesting.html"> here</A>.
+ There is also documentation on automated testing<A href="makecheck.html">
+ here</A>.
+<H2><A name="testnet">Configuration for a testbed network</A></H2>
+<P>A common test setup is to put a machine with dual Ethernet cards in
+ between two gateways under test. You need at least five machines; two
+ gateways, two clients and a testing machine in the middle.</P>
+<P>The central machine both routes packets and provides a place to run
+ diagnostic software for checking IPsec packets. See next section for
+ discussion of<A href="faq.html#tcpdump.faq"> using tcpdump(8)</A> for
+ this.</P>
+<P>This makes things more complicated than if you just connected the two
+ gateway machines directly to each other, but it also makes your test
+ setup much more like the environment you actually use IPsec in. Those
+ environments nearly always involve routing, and quite a few apparent
+ IPsec failures turn out to be problems with routing or with firewalls
+ dropping packets. This approach lets you deal with those problems on
+ your test setup.</P>
+<P>What you end up with looks like:</P>
+<H3><A name="testbed">Testbed network</A></H3>
+<PRE> subnet a.b.c.0/24
+ |
+ eth1 = a.b.c.1
+ gate1
+ eth0 = 192.168.p.1
+ |
+ |
+ eth0 = 192.168.p.2
+ route/monitor box
+ eth1 = 192.168.q.2
+ |
+ |
+ eth0 = 192.168.q.1
+ gate2
+ eth1 = x.y.z.1
+ |
+ subnet x.y.z.0/24</PRE>
+<PRE>Where p and q are any convenient values that do not interfere with other
+routes you may have. The ipsec.conf(5) file then has, among other things:</PRE>
+<PRE>conn abc-xyz
+ left=192.168.p.1
+ leftnexthop=192.168.p.2
+ right=192.168.q.1
+ rightnexthop=192.168.q.2</PRE>
+<P>Once that works, you can remove the &quot;route/monitor box&quot;, and connect
+ the two gateways to the Internet. The only parameters in ipsec.conf(5)
+ that need to change are the four shown above. You replace them with
+ values appropriate for your Internet connection, and change the eth0 IP
+ addresses and the default routes on both gateways.</P>
+<P>Note that nothing on either subnet needs to change. This lets you
+ test most of your IPsec setup before connecting to the insecure
+ Internet.</P>
+<H3><A name="tcpdump.test">Using packet sniffers in testing</A></H3>
+<P>A number of tools are available for looking at packets. We will
+ discuss using<A href="http://www.tcpdump.org/"> tcpdump(8)</A>, a
+ common Linux tool included in most distributions. Alternatives
+ offerring more-or-less the same functionality include:</P>
+<DL>
+<DT><A href="http://www.ethereal.com">Ethereal</A></DT>
+<DD>Several people on our mailing list report a preference for this over
+ tcpdump.</DD>
+<DT><A href="http://netgroup-serv.polito.it/windump/">windump</A></DT>
+<DD>a Windows version of tcpdump(8), possibly handy if you have Windows
+ boxes in your network</DD>
+<DT><A href="http://reptile.rug.ac.be/~coder/sniffit/sniffit.html">
+Sniffit</A></DT>
+<DD>A linux sniffer that we don't know much about. If you use it, please
+ comment on our mailing list.</DD>
+</DL>
+<P>See also this<A href="http://www.tlsecurity.net/unix/ids/sniffer/">
+ index</A> of packet sniffers.</P>
+<P>tcpdump(8) may misbehave if run on the gateways themselves. It is
+ designed to look into a normal IP stack and may become confused if you
+ ask it to display data from a stack which has IPsec in play.</P>
+<P>At one point, the problem was quite severe. Recent versions of
+ tcpdump, however, understand IPsec well enough to be usable on a
+ gateway. You can get the latest version from<A href="http://www.tcpdump.org/">
+ tcpdump.org</A>.</P>
+<P>Even with a recent tcpdump, some care is required. Here is part of a
+ post from Henry on the topic:</P>
+<PRE>&gt; a) data from sunset to sunrise or the other way is not being
+&gt; encrypted (I am using tcpdump (ver. 3.4) -x/ping -p to check
+&gt; packages)
+
+What *interface* is tcpdump being applied to? Use the -i option to
+control this. It matters! If tcpdump is looking at the ipsecN
+interfaces, e.g. ipsec0, then it is seeing the packets before they are
+encrypted or after they are decrypted, so of course they don't look
+encrypted. You want to have tcpdump looking at the actual hardware
+interfaces, e.g. eth0.
+
+Actually, the only way to be *sure* what you are sending on the wire is to
+have a separate machine eavesdropping on the traffic. Nothing you can do
+on the machines actually running IPsec is 100% guaranteed reliable in this
+area (although tcpdump is a lot better now than it used to be).</PRE>
+<P>The most certain way to examine IPsec packets is to look at them on
+ the wire. For security, you need to be certain, so we recommend doing
+ that. To do so, you need a<STRONG> separate sniffer machine located
+ between the two gateways</STRONG>. This machine can be routing IPsec
+ packets, but it must not be an IPsec gateway. Network configuration for
+ such testing is discussed<A href="#testnet"> above</A>.</P>
+<P>Here's another mailing list message with advice on using tcpdump(8):</P>
+<PRE>Subject: RE: [Users] Encrypted???
+ Date: Thu, 29 Nov 2001
+ From: &quot;Joe Patterson&quot; &lt;jpatterson@asgardgroup.com&gt;
+
+tcpdump -nl -i $EXT-IF proto 50
+
+-nl tells it not to buffer output or resolve names (if you don't do that it
+may confuse you by not outputing anything for a while), -i $EXT-IF (replace
+with your external interface) tells it what interface to listen on, and
+proto 50 is ESP. Use &quot;proto 51&quot; if for some odd reason you're using AH, and
+&quot;udp port 500&quot; if you want to see the isakmp key exchange/tunnel setup
+packets.
+
+You can also run `tcpdump -nl -i ipsec0` to see what traffic is on that
+virtual interface. Anything you see there *should* be either encrypted or
+dropped (unless you've turned on some strange options in your ipsec.conf
+file)
+
+Another very handy thing is ethereal (http://www.ethereal.com/) which runs
+on just about anything, has a nice gui interface (or a nice text-based
+interface), and does a great job of protocol breakdown. For ESP and AH
+it'll basically just tell you that there's a packet of that protocol, and
+what the spi is, but for isakmp it'll actually show you a lot of the tunnel
+setup information (until it gets to the point in the protocol where isakmp
+is encrypted....)</PRE>
+<H2><A name="verify.crypt">Verifying encryption</A></H2>
+<P>The question of how to verify that messages are actually encrypted
+ has been extensively discussed on the mailing list. See this<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/07/msg00262.html">
+ thread</A>.</P>
+<P>If you just want to verify that packets are encrypted, look at them
+ with a packet sniffer (see<A href="#tcpdump.test"> previous section</A>
+) located between the gateways. The packets should, except for some of
+ the header information, be utterly unintelligible.<STRONG> The output
+ of good encryption looks<EM> exactly</EM> like random noise</STRONG>.</P>
+<P>A packet sniffer can only tell you that the data you looked at was
+ encrypted. If you have stronger requirements -- for example if your
+ security policy requires verification that plaintext is not leaked
+ during startup or under various anomolous conditions -- then you will
+ need to devise much more thorough tests. If you do that, please post
+ any results or methodological details which your security policy allows
+ you to make public.</P>
+<P>You can put recognizable data into ping packets with something like:</P>
+<PRE> ping -p feedfacedeadbeef 11.0.1.1</PRE>
+<P>&quot;feedfacedeadbeef&quot; is a legal hexadecimal pattern that is easy to
+ pick out of hex dumps.</P>
+<P>For other protocols, you may need to check if you have encrypted data
+ or ASCII text. Encrypted data has approximately equal frequencies for
+ all 256 possible characters. ASCII text has most characters in the
+ printable range 0x20-0x7f, a few control characters less than 0x20, and
+ none at all in the range 0x80-0xff. 0x20, space, is a good character to
+ look for. In normal English text space occurs about once in seven
+ characters, versus about once in 256 for random or encrypted data.</P>
+<P>One thing to watch for: the output of good compression, like that of
+ good encryption, looks just like random noise. You cannot tell just by
+ looking at a data stream whether it has been compressed, encrypted, or
+ both. You need a little care not to mistake compressed data for
+ encrypted data in your testing.</P>
+<P>Note also that weak encryption also produces random-looking output.
+ You cannot tell whether the encryption is strong by looking at the
+ output. To be sure of that, you would need to have both the algorithms
+ and the implementation examined by experts.</P>
+<P>For IPsec, you can get partial assurance from interoperability tests.
+ See our<A href="interop.html"> interop</A> document. When twenty
+ products all claim to implement<A href="glossary.html#3DES"> 3DES</A>,
+ and they all talk to each other, you can be fairly sure they have it
+ right. Of course, you might wonder whether all the implementers are
+ consipring to trick you or, more plausibly, whether some
+ implementations might have &quot;back doors&quot; so they can get also it wrong
+ when required.. If you're seriously worried about things like that, you
+ need to get the code you use audited (good luck if it is not Open
+ Source), or perhaps to talk to a psychiatrist about treatments for
+ paranoia.</P>
+<H2><A name="mail.test">Mailing list pointers</A></H2>
+<P>Additional information on testing can be found in these<A href="mail.html">
+ mailing list</A> messages:</P>
+<UL>
+<LI>a user's detailed<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00571.html">
+ setup diary</A> for his testbed network</LI>
+<LI>a FreeS/WAN team member's<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/11/msg00425.html">
+ notes</A> from testing at an IPsec interop &quot;bakeoff&quot;</LI>
+</UL>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="performance.html">Previous</A>
+<A HREF="kernel.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/toc.html b/doc/toc.html
new file mode 100644
index 000000000..047833020
--- /dev/null
+++ b/doc/toc.html
@@ -0,0 +1,1019 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="intro.html#intro">Introduction</A></B>
+<UL>
+<LI><A HREF="intro.html#ipsec.intro">IPsec, Security for the Internet
+ Protocol</A></LI>
+<UL>
+<LI><A HREF="intro.html#intro.interop">Interoperating with other IPsec
+ implementations</A></LI>
+<LI><A HREF="ipsec.html#advantages">Advantages of IPsec</A></LI>
+<LI><A HREF="intro.html#applications">Applications of IPsec</A></LI>
+<LI><A HREF="intro.html#types">The need to authenticate gateways</A></LI>
+</UL>
+<LI><A HREF="intro.html#project">The FreeS/WAN project</A></LI>
+<UL>
+<LI><A HREF="intro.html#goals">Project goals</A></LI>
+<LI><A HREF="intro.html#staff">Project team</A></LI>
+</UL>
+<LI><A HREF="intro.html#products">Products containing FreeS/WAN</A></LI>
+<UL>
+<LI><A HREF="intro.html#distwith">Full Linux distributions</A></LI>
+<LI><A HREF="intro.html#kernel_dist">Linux kernel distributions</A></LI>
+<LI><A HREF="intro.html#office_dist">Office server distributions</A></LI>
+<LI><A HREF="intro.html#fw_dist">Firewall distributions</A></LI>
+<LI><A HREF="intro.html#turnkey">Firewall and VPN products</A></LI>
+</UL>
+<LI><A HREF="intro.html#docs">Information sources</A></LI>
+<UL>
+<LI><A HREF="intro.html#docformats">This HowTo, in multiple formats</A></LI>
+<LI><A HREF="intro.html#rtfm">RTFM (please Read The Fine Manuals)</A></LI>
+<LI><A HREF="intro.html#text">Other documents in the distribution</A></LI>
+<LI><A HREF="intro.html#assumptions">Background material</A></LI>
+<LI><A HREF="intro.html#archives">Archives of the project mailing list</A>
+</LI>
+<LI><A HREF="intro.html#howto">User-written HowTo information</A></LI>
+<LI><A HREF="intro.html#applied">Papers on FreeS/WAN</A></LI>
+<LI><A HREF="intro.html#licensing">License and copyright information</A></LI>
+</UL>
+<LI><A HREF="intro.html#sites">Distribution sites</A></LI>
+<UL>
+<LI><A HREF="intro.html#1_5_1">Primary site</A></LI>
+<LI><A HREF="intro.html#mirrors">Mirrors</A></LI>
+<LI><A HREF="intro.html#munitions">The &quot;munitions&quot; archive of Linux
+ crypto software</A></LI>
+</UL>
+<LI><A HREF="intro.html#1_6">Links to other sections</A></LI>
+</UL>
+<B><A HREF="upgrading.html#2">Upgrading to FreeS/WAN 2.x</A></B>
+<UL>
+<LI><A HREF="upgrading.html#2_1">New! Built in Opportunistic connections</A>
+</LI>
+<UL>
+<LI><A HREF="upgrading.html#2_1_1">Upgrading Opportunistic Encryption to
+ 2.01 (or later)</A></LI>
+</UL>
+<LI><A HREF="upgrading.html#2_2">New! Policy Groups</A></LI>
+<LI><A HREF="upgrading.html#2_3">New! Packetdefault Connection</A></LI>
+<LI><A HREF="upgrading.html#2_4">FreeS/WAN now disables Reverse Path
+ Filtering</A></LI>
+<LI><A HREF="upgrading.html#2_5">Revised ipsec.conf</A></LI>
+<UL>
+<LI><A HREF="upgrading.html#2_5_1">No promise of compatibility</A></LI>
+<LI><A HREF="upgrading.html#2_5_2">Most ipsec.conf files will work fine</A>
+</LI>
+<LI><A HREF="upgrading.html#2_5_3">Backward compatibility patch</A></LI>
+<LI><A HREF="upgrading.html#2_5_4">Details</A></LI>
+<LI><A HREF="upgrading.html#2_5_5">Upgrading from 1.x RPMs to 2.x RPMs</A>
+</LI>
+</UL>
+</UL>
+<B><A HREF="quickstart.html#quickstart">Quickstart Guide to
+ Opportunistic Encryption</A></B>
+<UL>
+<LI><A HREF="quickstart.html#opp.setup">Purpose</A></LI>
+<UL>
+<LI><A HREF="quickstart.html#3_1_1">OE &quot;flag day&quot;</A></LI>
+</UL>
+<LI><A HREF="quickstart.html#opp.dns">Requirements</A></LI>
+<LI><A HREF="quickstart.html#easy.install">RPM install</A></LI>
+<UL>
+<LI><A HREF="quickstart.html#3_3_1">Download RPMs</A></LI>
+<LI><A HREF="quickstart.html#3_3_2">Check signatures</A></LI>
+<LI><A HREF="quickstart.html#3_3_3">Install the RPMs</A></LI>
+<LI><A HREF="quickstart.html#testinstall">Test</A></LI>
+</UL>
+<LI><A HREF="quickstart.html#opp.setups.list">Our Opportunistic Setups</A>
+</LI>
+<UL>
+<LI><A HREF="quickstart.html#3_4_1">Full or partial opportunism?</A></LI>
+</UL>
+<LI><A HREF="quickstart.html#opp.client">Initiate-only setup</A></LI>
+<UL>
+<LI><A HREF="quickstart.html#3_5_1">Restrictions</A></LI>
+<LI><A HREF="quickstart.html#forward.dns">Create and publish a forward
+ DNS record</A></LI>
+<LI><A HREF="quickstart.html#3_5_3">Test that your key has been
+ published</A></LI>
+<LI><A HREF="quickstart.html#3_5_4">Configure, if necessary</A></LI>
+<LI><A HREF="quickstart.html#3_5_5">Test</A></LI>
+</UL>
+<LI><A HREF="quickstart.html#3_6">Full Opportunism</A></LI>
+<UL>
+<LI><A HREF="quickstart.html#3_6_1">Put a TXT record in a Forward Domain</A>
+</LI>
+<LI><A HREF="quickstart.html#3_6_2">Put a TXT record in Reverse DNS</A></LI>
+<LI><A HREF="quickstart.html#3_6_3">Test your DNS record</A></LI>
+<LI><A HREF="quickstart.html#3_6_4">No Configuration Needed</A></LI>
+<LI><A HREF="quickstart.html#3_6_5">Consider Firewalling</A></LI>
+<LI><A HREF="quickstart.html#3_6_6">Test</A></LI>
+<LI><A HREF="quickstart.html#3_6_7">Test</A></LI>
+</UL>
+<LI><A HREF="quickstart.html#opp.test">Testing opportunistic connections</A>
+</LI>
+<LI><A HREF="quickstart.html#3_8">Now what?</A></LI>
+<LI><A HREF="quickstart.html#3_9">Notes</A></LI>
+<LI><A HREF="quickstart.html#3_10">Troubleshooting OE</A></LI>
+<LI><A HREF="quickstart.html#3_11">Known Issues</A></LI>
+</UL>
+<B><A HREF="policygroups.html#4">How to Configure Linux FreeS/WAN with
+ Policy Groups</A></B>
+<UL>
+<LI><A HREF="policygroups.html#4_1">What are Policy Groups?</A></LI>
+<UL>
+<LI><A HREF="policygroups.html#4_1_1">Built-In Security Options</A></LI>
+</UL>
+<LI><A HREF="policygroups.html#4_2">Using Policy Groups</A></LI>
+<UL>
+<LI><A HREF="policygroups.html#4_2_1">Example 1: Using a Base Policy
+ Group</A></LI>
+<LI><A HREF="policygroups.html#4_2_2">Example 2: Defining IPsec Security
+ Policy with Groups</A></LI>
+<LI><A HREF="policygroups.html#4_2_3">Example 3: Creating a Simple IPsec
+ VPN with the private Group</A></LI>
+<LI><A HREF="policygroups.html#4_2_4">Example 4: New Policy Groups to
+ Protect a Subnet</A></LI>
+<LI><A HREF="policygroups.html#4_2_5">Example 5: Adding a Subnet to the
+ VPN</A></LI>
+</UL>
+<LI><A HREF="policygroups.html#4_3">Appendix</A></LI>
+<UL>
+<LI><A HREF="policygroups.html#4_3_1">Our Hidden Connections</A></LI>
+<LI><A HREF="policygroups.html#4_3_2">Custom Policy Groups</A></LI>
+<LI><A HREF="policygroups.html#4_3_3">Disabling Opportunistic Encryption</A>
+</LI>
+</UL>
+</UL>
+<B><A HREF="faq.html#5">FreeS/WAN FAQ</A></B>
+<UL>
+<LI><A HREF="faq.html#questions">Index of FAQ questions</A></LI>
+<LI><A HREF="faq.html#whatzit">What is FreeS/WAN?</A></LI>
+<LI><A HREF="faq.html#problems">How do I report a problem or seek help?</A>
+</LI>
+<LI><A HREF="faq.html#generic">Can I get ...</A></LI>
+<UL>
+<LI><A HREF="faq.html#lemme_out">Can I get an off-the-shelf system that
+ includes FreeS/WAN?</A></LI>
+<LI><A HREF="faq.html#consultant">Can I hire consultants or staff who
+ know FreeS/WAN?</A></LI>
+<LI><A HREF="faq.html#commercial">Can I get commercial support?</A></LI>
+</UL>
+<LI><A HREF="faq.html#release">Release questions</A></LI>
+<UL>
+<LI><A HREF="faq.html#rel.current">What is the current release?</A></LI>
+<LI><A HREF="faq.html#relwhen">When is the next release?</A></LI>
+<LI><A HREF="faq.html#rel.bugs">Are there known bugs in the current
+ release?</A></LI>
+</UL>
+<LI><A HREF="faq.html#mod_cons">Modifications and contributions</A></LI>
+<UL>
+<LI><A HREF="faq.html#modify.faq">Can I modify FreeS/WAN to ...?</A></LI>
+<LI><A HREF="faq.html#contrib.faq">Can I contribute to the project?</A></LI>
+<LI><A HREF="faq.html#ddoc.faq">Is there detailed design documentation?</A>
+</LI>
+</UL>
+<LI><A HREF="faq.html#interact">Will FreeS/WAN work in my environment?</A>
+</LI>
+<UL>
+<LI><A HREF="faq.html#interop.faq">Can FreeS/WAN talk to ...?</A></LI>
+<LI><A HREF="faq.html#old_to_new">Can different FreeS/WAN versions talk
+ to each other?</A></LI>
+<LI><A HREF="faq.html#faq.bandwidth">Is there a limit on throughput?</A></LI>
+<LI><A HREF="faq.html#faq.number">Is there a limit on number of tunnels?</A>
+</LI>
+<LI><A HREF="faq.html#faq.speed">Is a ... fast enough to handle
+ FreeS/WAN with my loads?</A></LI>
+</UL>
+<LI><A HREF="faq.html#work_on">Will FreeS/WAN work on ... ?</A></LI>
+<UL>
+<LI><A HREF="faq.html#versions">Will FreeS/WAN run on my version of
+ Linux?</A></LI>
+<LI><A HREF="faq.html#nonIntel.faq">Will FreeS/WAN run on non-Intel
+ CPUs?</A></LI>
+<LI><A HREF="faq.html#multi.faq">Will FreeS/WAN run on multiprocessors?</A>
+</LI>
+<LI><A HREF="faq.html#k.old">Will FreeS/WAN work on an older kernel?</A></LI>
+<LI><A HREF="faq.html#k.versions">Will FreeS/WAN run on the latest
+ kernel version?</A></LI>
+<LI><A HREF="faq.html#interface.faq">Will FreeS/WAN work on unusual
+ network hardware?</A></LI>
+<LI><A HREF="faq.html#vlan">Will FreeS/WAN work on a VLAN (802.1q)
+ network?</A></LI>
+</UL>
+<LI><A HREF="faq.html#features.faq">Does FreeS/WAN support ...</A></LI>
+<UL>
+<LI><A HREF="faq.html#VPN.faq">Does FreeS/WAN support site-to-site VPN (
+Virtual Private Network) applications?</A></LI>
+<LI><A HREF="faq.html#warrior.faq">Does FreeS/WAN support remote users
+ connecting to a LAN?</A></LI>
+<LI><A HREF="faq.html#road.shared.possible">Does FreeS/WAN support
+ remote users using shared secret authentication?</A></LI>
+<LI><A HREF="faq.html#wireless.faq">Does FreeS/WAN support wireless
+ networks?</A></LI>
+<LI><A HREF="faq.html#PKIcert">Does FreeS/WAN support X.509 or other PKI
+ certificates?</A></LI>
+<LI><A HREF="faq.html#Radius">Does FreeS/WAN support user authentication
+ (Radius, SecureID, Smart Card...)?</A></LI>
+<LI><A HREF="faq.html#NATtraversal">Does FreeS/WAN support NAT
+ traversal?</A></LI>
+<LI><A HREF="faq.html#virtID">Does FreeS/WAN support assigning a
+ &quot;virtual identity&quot; to a remote system?</A></LI>
+<LI><A HREF="faq.html#noDES.faq">Does FreeS/WAN support single DES
+ encryption?</A></LI>
+<LI><A HREF="faq.html#AES.faq">Does FreeS/WAN support AES encryption?</A>
+</LI>
+<LI><A HREF="faq.html#other.cipher">Does FreeS/WAN support other
+ encryption algorithms?</A></LI>
+</UL>
+<LI><A HREF="faq.html#canI">Can I ...</A></LI>
+<UL>
+<LI><A HREF="faq.html#policy.preconfig">Can I use policy groups along
+ with explicitly configured connections?</A></LI>
+<LI><A HREF="faq.html#policy.off">Can I turn off policy groups?</A></LI>
+<LI><A HREF="faq.html#reload">Can I reload connection info without
+ restarting?</A></LI>
+<LI><A HREF="faq.html#masq.faq">Can I use several masqueraded subnets?</A>
+</LI>
+<LI><A HREF="faq.html#dup_route">Can I use subnets masqueraded to the
+ same addresses?</A></LI>
+<LI><A HREF="faq.html#road.masq">Can I assign a road warrior an address
+ on my net (a virtual identity)?</A></LI>
+<LI><A HREF="faq.html#road.many">Can I support many road warriors with
+ one gateway?</A></LI>
+<LI><A HREF="faq.html#road.PSK">Can I have many road warriors using
+ shared secret authentication?</A></LI>
+<LI><A HREF="faq.html#QoS">Can I use Quality of Service routing with
+ FreeS/WAN?</A></LI>
+<LI><A HREF="faq.html#deadtunnel">Can I recognise dead tunnels and shut
+ them down?</A></LI>
+<LI><A HREF="faq.html#demanddial">Can I build IPsec tunnels over a
+ demand-dialed link?</A></LI>
+<LI><A HREF="faq.html#GRE">Can I build GRE, L2TP or PPTP tunnels over
+ IPsec?</A></LI>
+<LI><A HREF="faq.html#NetBIOS">... use Network Neighborhood (Samba,
+ NetBIOS) over IPsec?</A></LI>
+</UL>
+<LI><A HREF="faq.html#setup.faq">Life's little mysteries</A></LI>
+<UL>
+<LI><A HREF="faq.html#cantping">I cannot ping ....</A></LI>
+<LI><A HREF="faq.html#forever">It takes forever to ...</A></LI>
+<LI><A HREF="faq.html#route">I send packets to the tunnel with route(8)
+ but they vanish</A></LI>
+<LI><A HREF="faq.html#down_route">When a tunnel goes down, packets
+ vanish</A></LI>
+<LI><A HREF="faq.html#firewall_ate">The firewall ate my packets!</A></LI>
+<LI><A HREF="faq.html#dropconn">Dropped connections</A></LI>
+<LI><A HREF="faq.html#defaultroutegone">Disappearing %defaultroute</A></LI>
+<LI><A HREF="faq.html#tcpdump.faq">TCPdump on the gateway shows strange
+ things</A></LI>
+<LI><A HREF="faq.html#no_trace">Traceroute does not show anything
+ between the gateways</A></LI>
+</UL>
+<LI><A HREF="faq.html#man4debug">Testing in stages</A></LI>
+<UL>
+<LI><A HREF="faq.html#nomanual">Manually keyed connections don't work</A>
+</LI>
+<LI><A HREF="faq.html#spi_error">One manual connection works, but second
+ one fails</A></LI>
+<LI><A HREF="faq.html#man_no_auto">Manual connections work, but
+ automatic keying doesn't</A></LI>
+<LI><A HREF="faq.html#nocomp">IPsec works, but connections using
+ compression fail</A></LI>
+<LI><A HREF="faq.html#pmtu.broken">Small packets work, but large
+ transfers fail</A></LI>
+<LI><A HREF="faq.html#subsub">Subnet-to-subnet works, but tests from the
+ gateways don't</A></LI>
+</UL>
+<LI><A HREF="faq.html#compile.faq">Compilation problems</A></LI>
+<UL>
+<LI><A HREF="faq.html#gmp.h_missing">gmp.h: No such file or directory</A>
+</LI>
+<LI><A HREF="faq.html#noVM">... virtual memory exhausted</A></LI>
+</UL>
+<LI><A HREF="faq.html#error">Interpreting error messages</A></LI>
+<UL>
+<LI><A HREF="faq.html#route-client">route-client (or host) exited with
+ status 7</A></LI>
+<LI><A HREF="faq.html#unreachable">SIOCADDRT:Network is unreachable</A></LI>
+<LI><A HREF="faq.html#modprobe">ipsec_setup: modprobe: Can't locate
+ module ipsec</A></LI>
+<LI><A HREF="faq.html#noKLIPS">ipsec_setup: Fatal error, kernel appears
+ to lack KLIPS</A></LI>
+<LI><A HREF="faq.html#noDNS">ipsec_setup: ... failure to fetch key for
+ ... from DNS</A></LI>
+<LI><A HREF="faq.html#dup_address">ipsec_setup: ... interfaces ... and
+ ... share address ...</A></LI>
+<LI><A HREF="faq.html#kflags">ipsec_setup: Cannot adjust kernel flags</A>
+</LI>
+<LI><A HREF="faq.html#message_num">Message numbers (MI3, QR1, et cetera)
+ in Pluto messages</A></LI>
+<LI><A HREF="faq.html#conn_name">Connection names in Pluto error
+ messages</A></LI>
+<LI><A HREF="faq.html#cantorient">Pluto: ... can't orient connection</A></LI>
+<LI><A HREF="faq.html#no.interface">... we have no ipsecN interface for
+ either end of this connection</A></LI>
+<LI><A HREF="faq.html#noconn">Pluto: ... no connection is known</A></LI>
+<LI><A HREF="faq.html#nosuit">Pluto: ... no suitable connection ...</A></LI>
+<LI><A HREF="faq.html#noconn.auth">Pluto: ... no connection has been
+ authorized</A></LI>
+<LI><A HREF="faq.html#noDESsupport">Pluto: ... OAKLEY_DES_CBC is not
+ supported.</A></LI>
+<LI><A HREF="faq.html#notransform">Pluto: ... no acceptable transform</A>
+</LI>
+<LI><A HREF="faq.html#rsasigkey">rsasigkey dumps core</A></LI>
+<LI><A HREF="faq.html#sig4">!Pluto failure!: ... exited with ... signal
+ 4</A></LI>
+<LI><A HREF="faq.html#econnrefused">ECONNREFUSED error message</A></LI>
+<LI><A HREF="faq.html#no_eroute">klips_debug: ... no eroute!</A></LI>
+<LI><A HREF="faq.html#SAused">... trouble writing to /dev/ipsec ... SA
+ already in use</A></LI>
+<LI><A HREF="faq.html#ignore">... ignoring ... payload</A></LI>
+<LI><A HREF="faq.html#unknown_rightcert">unknown parameter name
+ &quot;rightcert&quot;</A></LI>
+</UL>
+<LI><A HREF="faq.html#spam">Why don't you restrict the mailing lists to
+ reduce spam?</A></LI>
+</UL>
+<B><A HREF="manpages.html#manpages">FreeS/WAN manual pages</A></B>
+<UL>
+<LI><A HREF="manpages.html#man.file">Files</A></LI>
+<LI><A HREF="manpages.html#man.command">Commands</A></LI>
+<LI><A HREF="manpages.html#man.lib">Library routines</A></LI>
+</UL>
+<B><A HREF="firewall.html#firewall">FreeS/WAN and firewalls</A></B>
+<UL>
+<LI><A HREF="firewall.html#filters">Filtering rules for IPsec packets</A>
+</LI>
+<LI><A HREF="firewall.html#examplefw">Firewall configuration at boot</A></LI>
+<UL>
+<LI><A HREF="firewall.html#simple.rules">A simple set of rules</A></LI>
+<LI><A HREF="firewall.html#complex.rules">Other rules</A></LI>
+<LI><A HREF="firewall.html#rules.pub">Published rule sets</A></LI>
+</UL>
+<LI><A HREF="firewall.html#updown">Calling firewall scripts, named in
+ ipsec.conf(5)</A></LI>
+<UL>
+<LI><A HREF="firewall.html#pre_post">Scripts called at IPsec start and
+ stop</A></LI>
+<LI><A HREF="firewall.html#up_down">Scripts called at connection up and
+ down</A></LI>
+<LI><A HREF="firewall.html#ipchains.script">Scripts for ipchains or
+ iptables</A></LI>
+</UL>
+<LI><A HREF="firewall.html#NAT">A complication: IPsec vs. NAT</A></LI>
+<UL>
+<LI><A HREF="firewall.html#nat_ok">NAT on or behind the IPsec gateway
+ works</A></LI>
+<LI><A HREF="firewall.html#nat_bad">NAT between gateways is problematic</A>
+</LI>
+<LI><A HREF="firewall.html#NAT.ref">Other references on NAT and IPsec</A>
+</LI>
+</UL>
+<LI><A HREF="firewall.html#complications">Other complications</A></LI>
+<UL>
+<LI><A HREF="firewall.html#through">IPsec through the gateway</A></LI>
+<LI><A HREF="firewall.html#ipsec_only">Preventing non-IPsec traffic</A></LI>
+<LI><A HREF="firewall.html#unknowngate">Filtering packets from unknown
+ gateways</A></LI>
+</UL>
+<LI><A HREF="firewall.html#otherfilter">Other packet filters</A></LI>
+<UL>
+<LI><A HREF="firewall.html#ICMP">ICMP filtering</A></LI>
+<LI><A HREF="firewall.html#traceroute">UDP packets for traceroute</A></LI>
+<LI><A HREF="firewall.html#l2tp">UDP for L2TP</A></LI>
+</UL>
+<LI><A HREF="firewall.html#packets">How it all works: IPsec packet
+ details</A></LI>
+<UL>
+<LI><A HREF="firewall.html#noport">ESP and AH do not have ports</A></LI>
+<LI><A HREF="firewall.html#header">Header layout</A></LI>
+<LI><A HREF="firewall.html#dhr">DHR on the updown script</A></LI>
+</UL>
+</UL>
+<B><A HREF="trouble.html#trouble">Linux FreeS/WAN Troubleshooting Guide</A>
+</B>
+<UL>
+<LI><A HREF="trouble.html#overview">Overview</A></LI>
+<LI><A HREF="trouble.html#install">1. During Install</A></LI>
+<UL>
+<LI><A HREF="trouble.html#8_2_1">1.1 RPM install gotchas</A></LI>
+<LI><A HREF="trouble.html#8_2_2">1.2 Problems installing from source</A></LI>
+<LI><A HREF="trouble.html#install.check">1.3 Install checks</A></LI>
+<LI><A HREF="quickstart.html#oe.trouble">1.3 Troubleshooting OE</A></LI>
+</UL>
+<LI><A HREF="trouble.html#negotiation">2. During Negotiation</A></LI>
+<UL>
+<LI><A HREF="trouble.html#state">2.1 Determine Connection State</A></LI>
+<LI><A HREF="trouble.html#find.pluto.error">2.2 Finding error text</A></LI>
+<LI><A HREF="trouble.html#interpret.pluto.error">2.3 Interpreting a
+ Negotiation Error</A></LI>
+</UL>
+<LI><A HREF="trouble.html#use">3. Using a Connection</A></LI>
+<UL>
+<LI><A HREF="trouble.html#8_4_1">3.1 Orienting yourself</A></LI>
+<LI><A HREF="trouble.html#8_4_2">3.2 Those pesky configuration errors</A>
+</LI>
+<LI><A HREF="trouble.html#route.firewall">3.3 Check Routing and
+ Firewalling</A></LI>
+<LI><A HREF="trouble.html#sniff">3.4 When in doubt, sniff it out</A></LI>
+<LI><A HREF="trouble.html#find.use.error">3.5 Check your logs</A></LI>
+<LI><A HREF="trouble.html#bigpacket">3.6 More testing for the truly
+ thorough</A></LI>
+</UL>
+<LI><A HREF="trouble.html#prob.report">4. Problem Reporting</A></LI>
+<UL>
+<LI><A HREF="trouble.html#8_5_1">4.1 How to ask for help</A></LI>
+<LI><A HREF="trouble.html#8_5_2">4.2 Where to ask</A></LI>
+</UL>
+<LI><A HREF="trouble.html#notes">5. Additional Notes on Troubleshooting</A>
+</LI>
+<UL>
+<LI><A HREF="trouble.html#system.info">5.1 Information available on your
+ system</A></LI>
+<LI><A HREF="trouble.html#testgates"> 5.2 Testing between security
+ gateways</A></LI>
+<LI><A HREF="trouble.html#ifconfig1">5.3 ifconfig reports for KLIPS
+ debugging</A></LI>
+<LI><A HREF="trouble.html#gdb"> 5.4 Using GDB on Pluto</A></LI>
+</UL>
+</UL>
+<B><A HREF="compat.html#compat">Linux FreeS/WAN Compatibility Guide</A></B>
+<UL>
+<LI><A HREF="compat.html#spec">Implemented parts of the IPsec
+ Specification</A></LI>
+<UL>
+<LI><A HREF="compat.html#in">In Linux FreeS/WAN</A></LI>
+<LI><A HREF="compat.html#dropped">Deliberately omitted</A></LI>
+<LI><A HREF="compat.html#not">Not (yet) in Linux FreeS/WAN</A></LI>
+</UL>
+<LI><A HREF="compat.html#pfkey">Our PF-Key implementation</A></LI>
+<UL>
+<LI><A HREF="compat.html#pfk.port">PF-Key portability</A></LI>
+</UL>
+<LI><A HREF="compat.html#otherk">Kernels other than the latest 2.2.x and
+ 2.4.y</A></LI>
+<UL>
+<LI><A HREF="compat.html#kernel.2.0">2.0.x kernels</A></LI>
+<LI><A HREF="compat.html#kernel.production">2.2 and 2.4 kernels</A></LI>
+</UL>
+<LI><A HREF="compat.html#otherdist">Intel Linux distributions other than
+ Redhat</A></LI>
+<UL>
+<LI><A HREF="compat.html#rh7">Redhat 7.0</A></LI>
+<LI><A HREF="compat.html#suse">SuSE Linux</A></LI>
+<LI><A HREF="compat.html#slack">Slackware</A></LI>
+<LI><A HREF="compat.html#deb">Debian</A></LI>
+<LI><A HREF="compat.html#caldera">Caldera</A></LI>
+</UL>
+<LI><A HREF="compat.html#CPUs">CPUs other than Intel</A></LI>
+<UL>
+<LI><A HREF="compat.html# strongarm">Corel Netwinder (StrongARM CPU)</A></LI>
+<LI><A HREF="compat.html#yellowdog">Yellow Dog Linux on Power PC</A></LI>
+<LI><A HREF="compat.html#mklinux">Mklinux</A></LI>
+<LI><A HREF="compat.html#alpha">Alpha 64-bit processors</A></LI>
+<LI><A HREF="compat.html#SPARC">Sun SPARC processors</A></LI>
+<LI><A HREF="compat.html#mips">MIPS processors</A></LI>
+<LI><A HREF="compat.html#crusoe">Transmeta Crusoe</A></LI>
+<LI><A HREF="compat.html#coldfire">Motorola Coldfire</A></LI>
+</UL>
+<LI><A HREF="compat.html#multiprocessor">Multiprocessor machines</A></LI>
+<LI><A HREF="compat.html#hardware">Support for crypto hardware</A></LI>
+<LI><A HREF="compat.html#ipv6">IP version 6 (IPng)</A></LI>
+<UL>
+<LI><A HREF="compat.html#v6.back">IPv6 background</A></LI>
+</UL>
+</UL>
+<B><A HREF="interop.html#10">Interoperating with FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="interop.html#10_1">Interop at a Glance</A></LI>
+<UL>
+<LI><A HREF="interop.html#10_1_1">Key</A></LI>
+</UL>
+<LI><A HREF="interop.html#10_2">Basic Interop Rules</A></LI>
+<LI><A HREF="interop.html#10_3">Longer Stories</A></LI>
+<UL>
+<LI><A HREF="interop.html#10_3_1">For More Compatible Implementations</A>
+</LI>
+<LI><A HREF="interop.html#10_3_2">For Other Implementations</A></LI>
+</UL>
+</UL>
+<B><A HREF="performance.html#performance">Performance of FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="performance.html#pub.bench">Published material</A></LI>
+<LI><A HREF="performance.html#perf.estimate">Estimating CPU overheads</A>
+</LI>
+<UL>
+<LI><A HREF="performance.html#perf.more">Higher performance alternatives</A>
+</LI>
+<LI><A HREF="performance.html#11_2_2">Other considerations</A></LI>
+</UL>
+<LI><A HREF="performance.html#biggate">Many tunnels from a single
+ gateway</A></LI>
+<LI><A HREF="performance.html#low-end">Low-end systems</A></LI>
+<LI><A HREF="performance.html#klips.bench">Measuring KLIPS</A></LI>
+<LI><A HREF="performance.html#speed.compress">Speed with compression</A></LI>
+<LI><A HREF="performance.html#methods">Methods of measuring</A></LI>
+</UL>
+<B><A HREF="testing.html#test.freeswan">Testing FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="testing.html#test.oe">Testing opportunistic connections</A></LI>
+<UL>
+<LI><A HREF="testing.html#12_1_1">Basic OE Test</A></LI>
+<LI><A HREF="testing.html#12_1_2">OE Gateway Test</A></LI>
+<LI><A HREF="testing.html#12_1_3">Additional OE tests</A></LI>
+</UL>
+<LI><A HREF="testing.html#test.uml">Testing with User Mode Linux</A></LI>
+<LI><A HREF="testing.html#testnet">Configuration for a testbed network</A>
+</LI>
+<UL>
+<LI><A HREF="testing.html#testbed">Testbed network</A></LI>
+<LI><A HREF="testing.html#tcpdump.test">Using packet sniffers in testing</A>
+</LI>
+</UL>
+<LI><A HREF="testing.html#verify.crypt">Verifying encryption</A></LI>
+<LI><A HREF="testing.html#mail.test">Mailing list pointers</A></LI>
+</UL>
+<B><A HREF="kernel.html#kernelconfig">Kernel configuration for FreeS/WAN</A>
+</B>
+<UL>
+<LI><A HREF="kernel.html#notall">Not everyone needs to worry about
+ kernel configuration</A></LI>
+<LI><A HREF="kernel.html#assume">Assumptions and notation</A></LI>
+<UL>
+<LI><A HREF="kernel.html#labels">Labels used</A></LI>
+</UL>
+<LI><A HREF="kernel.html#kernelopt">Kernel options for FreeS/WAN</A></LI>
+</UL>
+<B><A HREF="adv_config.html#adv_config">Other configuration
+ possibilities</A></B>
+<UL>
+<LI><A HREF="adv_config.html#thumb">Some rules of thumb about
+ configuration</A></LI>
+<UL>
+<LI><A HREF="adv_config.html#cheap.tunnel">Tunnels are cheap</A></LI>
+<LI><A HREF="adv_config.html#subnet.size">Subnet sizes</A></LI>
+<LI><A HREF="adv_config.html#example.more">Other network layouts</A></LI>
+</UL>
+<LI><A HREF="adv_config.html#choose">Choosing connection types</A></LI>
+<UL>
+<LI><A HREF="adv_config.html#man-auto">Manual vs. automatic keying</A></LI>
+<LI><A HREF="adv_config.html#auto-auth">Authentication methods for
+ auto-keying</A></LI>
+<LI><A HREF="adv_config.html#adv-pk">Advantages of public key methods</A>
+</LI>
+</UL>
+<LI><A HREF="adv_config.html#prodsecrets">Using shared secrets in
+ production</A></LI>
+<UL>
+<LI><A HREF="biblio.html#secrets">Putting secrets in ipsec.secrets(5)</A>
+</LI>
+<LI><A HREF="adv_config.html#securing.secrets">File security</A></LI>
+<LI><A HREF="adv_config.html#notroadshared">Shared secrets for road
+ warriors</A></LI>
+</UL>
+<LI><A HREF="adv_config.html#prodman">Using manual keying in production</A>
+</LI>
+<UL>
+<LI><A HREF="adv_config.html#ranbits">Creating keys with ranbits</A></LI>
+</UL>
+<LI><A HREF="adv_config.html#boot">Setting up connections at boot time</A>
+</LI>
+<LI><A HREF="adv_config.html#multitunnel">Multiple tunnels between the
+ same two gateways</A></LI>
+<UL>
+<LI><A HREF="adv_config.html#advroute">One tunnel plus advanced routing</A>
+</LI>
+</UL>
+<LI><A HREF="adv_config.html#opp.gate">An Opportunistic Gateway</A></LI>
+<UL>
+<LI><A HREF="adv_config.html#14_7_1">Start from full opportunism</A></LI>
+<LI><A HREF="adv_config.html#14_7_2">Reverse DNS TXT records for each
+ protected machine</A></LI>
+<LI><A HREF="adv_config.html#14_7_3">Publish your records</A></LI>
+<LI><A HREF="adv_config.html#14_7_4">...and test them</A></LI>
+<LI><A HREF="adv_config.html#14_7_5">No Configuration Needed</A></LI>
+</UL>
+<LI><A HREF="adv_config.html#extruded.config">Extruded Subnets</A></LI>
+<LI><A HREF="adv_config.html#roadvirt">Road Warrior with virtual IP
+ address</A></LI>
+<LI><A HREF="glossary.html#dynamic">Dynamic Network Interfaces</A></LI>
+<UL>
+<LI><A HREF="adv_config.html#basicdyn">Basics</A></LI>
+<LI><A HREF="adv_config.html#bootdyn">Boot Time</A></LI>
+<LI><A HREF="adv_config.html#changedyn">Change Time</A></LI>
+</UL>
+<LI><A HREF="adv_config.html#unencrypted">Unencrypted tunnels</A></LI>
+</UL>
+<B><A HREF="trouble.html#install">Installing FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="install.html#15_1">Requirements</A></LI>
+<LI><A HREF="install.html#15_2">Choose your install method</A></LI>
+<LI><A HREF="install.html#15_3">FreeS/WAN ships with some Linuxes</A></LI>
+<UL>
+<LI><A HREF="install.html#15_3_1">FreeS/WAN may be altered...</A></LI>
+<LI><A HREF="install.html#15_3_2">You might need to create an
+ authentication keypair</A></LI>
+<LI><A HREF="install.html#15_3_3">Start and test FreeS/WAN</A></LI>
+</UL>
+<LI><A HREF="install.html#15_4">RPM install</A></LI>
+<UL>
+<LI><A HREF="install.html#15_4_1">Download RPMs</A></LI>
+<LI><A HREF="install.html#15_4_2">For freeswan.org RPMs: check
+ signatures</A></LI>
+<LI><A HREF="install.html#15_4_3">Install the RPMs</A></LI>
+<LI><A HREF="install.html#15_4_4">Start and Test FreeS/WAN</A></LI>
+</UL>
+<LI><A HREF="install.html#15_5">Install from Source</A></LI>
+<UL>
+<LI><A HREF="install.html#15_5_1">Decide what functionality you need</A></LI>
+<LI><A HREF="install.html#15_5_2">Download FreeS/WAN</A></LI>
+<LI><A HREF="install.html#15_5_3">For freeswan.org source: check its
+ signature</A></LI>
+<LI><A HREF="install.html#15_5_4">Untar, unzip</A></LI>
+<LI><A HREF="install.html#15_5_5">Patch if desired</A></LI>
+<LI><A HREF="install.html#15_5_6">... and Make</A></LI>
+</UL>
+<LI><A HREF="install.html#15_6">Start FreeS/WAN and test your install</A>
+</LI>
+<LI><A HREF="install.html#15_7">Test your install</A></LI>
+<LI><A HREF="install.html#15_8">Making FreeS/WAN play well with others</A>
+</LI>
+<LI><A HREF="install.html#15_9">Configure for your needs</A></LI>
+</UL>
+<B><A HREF="config.html#config">How to configure FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="config.html#16_1">Requirements</A></LI>
+<LI><A HREF="config.html#config.netnet">Net-to-Net connection</A></LI>
+<UL>
+<LI><A HREF="config.html#netnet.info.ex">Gather information</A></LI>
+<LI><A HREF="config.html#16_2_2">Edit /etc/ipsec.conf</A></LI>
+<LI><A HREF="config.html#16_2_3">Start your connection</A></LI>
+<LI><A HREF="config.html#16_2_4">Do not MASQ or NAT packets to be
+ tunneled</A></LI>
+<LI><A HREF="config.html#16_2_5">Test your connection</A></LI>
+<LI><A HREF="config.html#16_2_6">Finishing touches</A></LI>
+</UL>
+<LI><A HREF="config.html#config.rw">Road Warrior Configuration</A></LI>
+<UL>
+<LI><A HREF="config.html#rw.info.ex">Gather information</A></LI>
+<LI><A HREF="config.html#16_3_2">Customize /etc/ipsec.conf</A></LI>
+<LI><A HREF="config.html#16_3_3">Start your connection</A></LI>
+<LI><A HREF="config.html#16_3_4">Do not MASQ or NAT packets to be
+ tunneled</A></LI>
+<LI><A HREF="config.html#16_3_5">Test your connection</A></LI>
+<LI><A HREF="config.html#16_3_6">Finishing touches</A></LI>
+<LI><A HREF="config.html#16_3_7">Multiple Road Warriors</A></LI>
+</UL>
+<LI><A HREF="config.html#16_4">What next?</A></LI>
+</UL>
+<B><A HREF="background.html#background">Linux FreeS/WAN background</A></B>
+<UL>
+<LI><A HREF="background.html#dns.background">Some DNS background</A></LI>
+<UL>
+<LI><A HREF="background.html#forward.reverse">Forward and reverse maps</A>
+</LI>
+<LI><A HREF="background.html#17_1_2">Hierarchy and delegation</A></LI>
+<LI><A HREF="background.html#17_1_3">Syntax of DNS records</A></LI>
+<LI><A HREF="background.html#17_1_4">Cacheing, TTL and propagation delay</A>
+</LI>
+</UL>
+<LI><A HREF="background.html#MTU.trouble">Problems with packet
+ fragmentation</A></LI>
+<LI><A HREF="background.html#nat.background">Network address translation
+ (NAT)</A></LI>
+<UL>
+<LI><A HREF="background.html#17_3_1">NAT to non-routable addresses</A></LI>
+<LI><A HREF="background.html#17_3_2">NAT to routable addresses</A></LI>
+</UL>
+</UL>
+<B><A HREF="user_examples.html#user.examples">FreeS/WAN script examples</A>
+</B>
+<UL>
+<LI><A HREF="user_examples.html#poltorak">Poltorak's Firewall script</A></LI>
+</UL>
+<B><A HREF="makecheck.html#makecheck">How to configure to use &quot;make
+ check&quot;</A></B>
+<UL>
+<LI><A HREF="makecheck.html#19_1">What is &quot;make check&quot;</A></LI>
+<LI><A HREF="makecheck.html#19_2">Running &quot;make check&quot;</A></LI>
+</UL>
+<B><A HREF="makecheck.html#20">How to write a &quot;make check&quot; test</A></B>
+<UL>
+<LI><A HREF="makecheck.html#20_1">Structure of a test</A></LI>
+<LI><A HREF="makecheck.html#20_2">The TESTLIST</A></LI>
+<LI><A HREF="makecheck.html#20_3">Test kinds</A></LI>
+<LI><A HREF="makecheck.html#20_4">Common parameters</A></LI>
+<LI><A HREF="makecheck.html#20_5">KLIPStest paramaters</A></LI>
+<LI><A HREF="makecheck.html#20_6">mkinsttest paramaters</A></LI>
+<LI><A HREF="makecheck.html#20_7">rpm_build_install_test paramaters</A></LI>
+<LI><A HREF="makecheck.html#20_8">libtest paramaters</A></LI>
+<LI><A HREF="makecheck.html#20_9">umlplutotest paramaters</A></LI>
+<LI><A HREF="makecheck.html#20_10">umlXhost parameters</A></LI>
+<LI><A HREF="makecheck.html#20_11">kernel_patch_test paramaters</A></LI>
+<LI><A HREF="makecheck.html#20_12">module_compile paramaters</A></LI>
+</UL>
+<B><A HREF="makecheck.html#21">Current pitfalls</A></B>
+<BR>
+<BR><B><A HREF="umltesting.html#umltesting">User-Mode-Linux Testing
+ guide</A></B>
+<UL>
+<LI><A HREF="umltesting.html#22_1">Preliminary Notes on BIND</A></LI>
+<LI><A HREF="umltesting.html#22_2">Steps to Install UML for FreeS/WAN</A>
+</LI>
+</UL>
+<B><A HREF="umltesting.html#23">Debugging the kernel with GDB</A></B>
+<UL>
+<LI><A HREF="umltesting.html#23_1">Other notes about debugging</A></LI>
+</UL>
+<B><A HREF="umltesting.html#24">User-Mode-Linux mysteries</A></B>
+<BR>
+<BR><B><A HREF="umltesting.html#25">Getting more info from uml_netjig</A>
+</B>
+<BR>
+<BR><B><A HREF="politics.html#politics">History and politics of
+ cryptography</A></B>
+<UL>
+<LI><A HREF="politics.html#intro.politics">Introduction</A></LI>
+<UL>
+<LI><A HREF="politics.html#26_1_1">History</A></LI>
+<LI><A HREF="politics.html#intro.poli">Politics</A></LI>
+<LI><A HREF="politics.html#26_1_3">Links</A></LI>
+<LI><A HREF="politics.html#26_1_4">Outline of this section</A></LI>
+</UL>
+<LI><A HREF="politics.html#leader">From our project leader</A></LI>
+<UL>
+<LI><A HREF="politics.html#gilmore">Swan: Securing the Internet against
+ Wiretapping</A></LI>
+<LI><A HREF="politics.html#policestate">Stopping wholesale monitoring</A>
+</LI>
+</UL>
+<LI><A HREF="politics.html#weak">Government promotion of weak crypto</A></LI>
+<UL>
+<LI><A HREF="politics.html#escrow">Escrowed encryption</A></LI>
+<LI><A HREF="politics.html#shortkeys">Limited key lengths</A></LI>
+</UL>
+<LI><A HREF="politics.html#exlaw">Cryptography Export Laws</A></LI>
+<UL>
+<LI><A HREF="politics.html#USlaw">US Law</A></LI>
+<LI><A HREF="politics.html#wrong">What's wrong with restrictions on
+ cryptography</A></LI>
+<LI><A HREF="politics.html#Wassenaar">The Wassenaar Arrangement</A></LI>
+<LI><A HREF="politics.html#status">Export status of Linux FreeS/WAN</A></LI>
+<LI><A HREF="politics.html#help">Help spread IPsec around</A></LI>
+</UL>
+<LI><A HREF="politics.html#desnotsecure">DES is Not Secure</A></LI>
+<UL>
+<LI><A HREF="politics.html#deshware">Dedicated hardware breaks DES in a
+ few days</A></LI>
+<LI><A HREF="politics.html#spooks">Spooks may break DES faster yet</A></LI>
+<LI><A HREF="politics.html#desnet">Networks break DES in a few weeks</A></LI>
+<LI><A HREF="politics.html#no_des">We disable DES</A></LI>
+<LI><A HREF="politics.html#40joke">40-bits is laughably weak</A></LI>
+<LI><A HREF="politics.html#altdes">Triple DES is almost certainly secure</A>
+</LI>
+<LI><A HREF="politics.html#aes.ipsec">AES in IPsec</A></LI>
+</UL>
+<LI><A HREF="politics.html#press">Press coverage of Linux FreeS/WAN:</A></LI>
+<UL>
+<LI><A HREF="politics.html#26_6_1">FreeS/WAN 1.0 press</A></LI>
+<LI><A HREF="faq.html#release">Press release for version 1.0</A></LI>
+</UL>
+</UL>
+<B><A HREF="ipsec.html#ipsec.detail">The IPsec protocols</A></B>
+<UL>
+<LI><A HREF="ipsec.html#27_1">Protocols and phases</A></LI>
+<LI><A HREF="ipsec.html#others">Applying IPsec</A></LI>
+<UL>
+<LI><A HREF="ipsec.html#advantages">Advantages of IPsec</A></LI>
+<LI><A HREF="ipsec.html#limitations">Limitations of IPsec</A></LI>
+<LI><A HREF="ipsec.html#uses">IPsec is a general mechanism for securing
+ IP</A></LI>
+<LI><A HREF="ipsec.html#authonly">Using authentication without
+ encryption</A></LI>
+<LI><A HREF="ipsec.html#encnoauth">Encryption without authentication is
+ dangerous</A></LI>
+<LI><A HREF="ipsec.html#multilayer">Multiple layers of IPsec processing
+ are possible</A></LI>
+<LI><A HREF="ipsec.html#traffic.resist">Resisting traffic analysis</A></LI>
+</UL>
+<LI><A HREF="ipsec.html#primitives">Cryptographic components</A></LI>
+<UL>
+<LI><A HREF="ipsec.html#block.cipher">Block ciphers</A></LI>
+<LI><A HREF="ipsec.html#hash.ipsec">Hash functions</A></LI>
+<LI><A HREF="ipsec.html#DH.keying">Diffie-Hellman key agreement</A></LI>
+<LI><A HREF="ipsec.html#RSA.auth">RSA authentication</A></LI>
+</UL>
+<LI><A HREF="ipsec.html#structure">Structure of IPsec</A></LI>
+<UL>
+<LI><A HREF="ipsec.html#IKE.ipsec">IKE (Internet Key Exchange)</A></LI>
+<LI><A HREF="ipsec.html#services">IPsec Services, AH and ESP</A></LI>
+<LI><A HREF="ipsec.html#AH.ipsec">The Authentication Header (AH)</A></LI>
+<LI><A HREF="ipsec.html#ESP.ipsec">Encapsulated Security Payload (ESP)</A>
+</LI>
+</UL>
+<LI><A HREF="ipsec.html#modes">IPsec modes</A></LI>
+<UL>
+<LI><A HREF="ipsec.html#tunnel.ipsec">Tunnel mode</A></LI>
+<LI><A HREF="ipsec.html#transport.ipsec">Transport mode</A></LI>
+</UL>
+<LI><A HREF="ipsec.html#parts">FreeS/WAN parts</A></LI>
+<UL>
+<LI><A HREF="ipsec.html#KLIPS.ipsec">KLIPS: Kernel IPsec Support</A></LI>
+<LI><A HREF="ipsec.html#Pluto.ipsec">The Pluto daemon</A></LI>
+<LI><A HREF="ipsec.html#command">The ipsec(8) command</A></LI>
+<LI><A HREF="ipsec.html#ipsec.conf">Linux FreeS/WAN configuration file</A>
+</LI>
+</UL>
+<LI><A HREF="ipsec.html#key">Key management</A></LI>
+<UL>
+<LI><A HREF="ipsec.html#current">Currently Implemented Methods</A></LI>
+<LI><A HREF="ipsec.html#notyet">Methods not yet implemented</A></LI>
+</UL>
+</UL>
+<B><A HREF="mail.html#lists">Mailing lists and newsgroups</A></B>
+<UL>
+<LI><A HREF="mail.html#list.fs">Mailing lists about FreeS/WAN</A></LI>
+<UL>
+<LI><A HREF="mail.html#projlist">The project mailing lists</A></LI>
+<LI><A HREF="mail.html#archive">Archives of the lists</A></LI>
+</UL>
+<LI><A HREF="mail.html#indexes">Indexes of mailing lists</A></LI>
+<LI><A HREF="mail.html#otherlists">Lists for related software and topics</A>
+</LI>
+<UL>
+<LI><A HREF="mail.html#28_3_1">Products that include FreeS/WAN</A></LI>
+<LI><A HREF="mail.html#linux.lists">Linux mailing lists</A></LI>
+<LI><A HREF="mail.html#ietf">Lists for IETF working groups</A></LI>
+<LI><A HREF="mail.html#other">Other mailing lists</A></LI>
+</UL>
+<LI><A HREF="mail.html#newsgroups">Usenet newsgroups</A></LI>
+</UL>
+<B><A HREF="web.html#weblink">Web links</A></B>
+<UL>
+<LI><A HREF="web.html#freeswan">The Linux FreeS/WAN Project</A></LI>
+<UL>
+<LI><A HREF="web.html#patch">Add-ons and patches for FreeS/WAN</A></LI>
+<LI><A HREF="web.html#dist">Distributions including FreeS/WAN</A></LI>
+<LI><A HREF="web.html#used">Things FreeS/WAN uses or could use</A></LI>
+<LI><A HREF="web.html#alternatives">Other approaches to VPNs for Linux</A>
+</LI>
+</UL>
+<LI><A HREF="web.html#ipsec.link">The IPsec Protocols</A></LI>
+<UL>
+<LI><A HREF="web.html#general">General IPsec or VPN information</A></LI>
+<LI><A HREF="trouble.html#overview">IPsec overview documents or slide
+ sets</A></LI>
+<LI><A HREF="web.html#otherlang">IPsec information in languages other
+ than English</A></LI>
+<LI><A HREF="web.html#RFCs1">RFCs and other reference documents</A></LI>
+<LI><A HREF="web.html#analysis">Analysis and critiques of IPsec
+ protocols</A></LI>
+<LI><A HREF="web.html#IP.background">Background information on IP</A></LI>
+</UL>
+<LI><A HREF="web.html#implement">IPsec Implementations</A></LI>
+<UL>
+<LI><A HREF="web.html#linuxprod">Linux products</A></LI>
+<LI><A HREF="web.html#router">IPsec in router products</A></LI>
+<LI><A HREF="web.html#fw.web">IPsec in firewall products</A></LI>
+<LI><A HREF="web.html#ipsecos">Operating systems with IPsec support</A></LI>
+<LI><A HREF="web.html#29_3_5">IPsec on network cards</A></LI>
+<LI><A HREF="web.html#opensource">Open source IPsec implementations</A></LI>
+<LI><A HREF="web.html#interop.web">Interoperability</A></LI>
+</UL>
+<LI><A HREF="web.html#linux.link">Linux links</A></LI>
+<UL>
+<LI><A HREF="web.html#linux.basic">Basic and tutorial Linux information</A>
+</LI>
+<LI><A HREF="web.html#general">General Linux sites</A></LI>
+<LI><A HREF="web.html#docs.ldp">Documentation</A></LI>
+<LI><A HREF="web.html#advroute.web">Advanced routing</A></LI>
+<LI><A HREF="web.html#linsec">Security for Linux</A></LI>
+<LI><A HREF="web.html#firewall.linux">Linux firewalls</A></LI>
+<LI><A HREF="web.html#linux.misc">Miscellaneous Linux information</A></LI>
+</UL>
+<LI><A HREF="web.html#crypto.link">Crypto and security links</A></LI>
+<UL>
+<LI><A HREF="web.html#security">Crypto and security resources</A></LI>
+<LI><A HREF="web.html#policy">Cryptography law and policy</A></LI>
+<LI><A HREF="web.html#crypto.tech">Cryptography technical information</A>
+</LI>
+<LI><A HREF="web.html#compsec">Computer and network security</A></LI>
+<LI><A HREF="web.html#people">Links to home pages</A></LI>
+</UL>
+</UL>
+<B><A HREF="glossary.html#ourgloss">Glossary for the Linux FreeS/WAN
+ project</A></B>
+<UL>
+<LI><A HREF="glossary.html#jump">Jump to a letter in the glossary</A></LI>
+<LI><A HREF="glossary.html#gloss">Other glossaries</A></LI>
+<LI><A HREF="glossary.html#definitions">Definitions</A></LI>
+</UL>
+<B><A HREF="biblio.html#biblio">Bibliography for the Linux FreeS/WAN
+ project</A></B>
+<BR>
+<BR><B><A HREF="rfc.html#RFC">IPsec RFCs and related documents</A></B>
+<UL>
+<LI><A HREF="rfc.html#RFCfile">The RFCs.tar.gz Distribution File</A></LI>
+<LI><A HREF="rfc.html#sources">Other sources for RFCs &amp; Internet drafts</A>
+</LI>
+<UL>
+<LI><A HREF="rfc.html#RFCdown">RFCs</A></LI>
+<LI><A HREF="rfc.html#drafts">Internet Drafts</A></LI>
+<LI><A HREF="rfc.html#FIPS1">FIPS standards</A></LI>
+</UL>
+<LI><A HREF="rfc.html#RFCs.tar.gz">What's in the RFCs.tar.gz bundle?</A></LI>
+<UL>
+<LI><A HREF="rfc.html#rfc.ov">Overview RFCs</A></LI>
+<LI><A HREF="rfc.html#basic.prot">Basic protocols</A></LI>
+<LI><A HREF="rfc.html#key.ike">Key management</A></LI>
+<LI><A HREF="rfc.html#rfc.detail">Details of various things used</A></LI>
+<LI><A HREF="rfc.html#rfc.ref">Older RFCs which may be referenced</A></LI>
+<LI><A HREF="rfc.html#rfc.dns">RFCs for secure DNS service, which IPsec
+ may use</A></LI>
+<LI><A HREF="rfc.html#rfc.exp">RFCs labelled &quot;experimental&quot;</A></LI>
+<LI><A HREF="rfc.html#rfc.rel">Related RFCs</A></LI>
+</UL>
+</UL>
+<B><A HREF="roadmap.html#roadmap">Distribution Roadmap: What's Where in
+ Linux FreeS/WAN</A></B>
+<UL>
+<LI><A HREF="roadmap.html#top">Top directory</A></LI>
+<LI><A HREF="roadmap.html#doc">Documentation</A></LI>
+<LI><A HREF="roadmap.html#klips.roadmap">KLIPS: kernel IP security</A></LI>
+<LI><A HREF="roadmap.html#pluto.roadmap">Pluto key and connection
+ management daemon</A></LI>
+<LI><A HREF="roadmap.html#utils">Utils</A></LI>
+<LI><A HREF="roadmap.html#lib">Libraries</A></LI>
+<UL>
+<LI><A HREF="roadmap.html#fswanlib">FreeS/WAN Library</A></LI>
+<LI><A HREF="roadmap.html#otherlib">Imported Libraries</A></LI>
+</UL>
+</UL>
+<B><A HREF="umltesting.html#umltesting">User-Mode-Linux Testing guide</A>
+</B>
+<UL>
+<LI><A HREF="umltesting.html#34_1">Preliminary Notes on BIND</A></LI>
+<LI><A HREF="umltesting.html#34_2">Steps to Install UML for FreeS/WAN</A>
+</LI>
+</UL>
+<B><A HREF="umltesting.html#35">Debugging the kernel with GDB</A></B>
+<UL>
+<LI><A HREF="umltesting.html#35_1">Other notes about debugging</A></LI>
+</UL>
+<B><A HREF="umltesting.html#36">User-Mode-Linux mysteries</A></B>
+<BR>
+<BR><B><A HREF="umltesting.html#37">Getting more info from uml_netjig</A>
+</B>
+<BR>
+<BR><B><A HREF="makecheck.html#makecheck">How to configure to use &quot;make
+ check&quot;</A></B>
+<UL>
+<LI><A HREF="makecheck.html#38_1">What is &quot;make check&quot;</A></LI>
+<LI><A HREF="makecheck.html#38_2">Running &quot;make check&quot;</A></LI>
+</UL>
+<B><A HREF="makecheck.html#39">How to write a &quot;make check&quot; test</A></B>
+<UL>
+<LI><A HREF="makecheck.html#39_1">Structure of a test</A></LI>
+<LI><A HREF="makecheck.html#39_2">The TESTLIST</A></LI>
+<LI><A HREF="makecheck.html#39_3">Test kinds</A></LI>
+<LI><A HREF="makecheck.html#39_4">Common parameters</A></LI>
+<LI><A HREF="makecheck.html#39_5">KLIPStest paramaters</A></LI>
+<LI><A HREF="makecheck.html#39_6">mkinsttest paramaters</A></LI>
+<LI><A HREF="makecheck.html#39_7">rpm_build_install_test paramaters</A></LI>
+<LI><A HREF="makecheck.html#39_8">libtest paramaters</A></LI>
+<LI><A HREF="makecheck.html#39_9">umlplutotest paramaters</A></LI>
+<LI><A HREF="makecheck.html#39_10">umlXhost parameters</A></LI>
+<LI><A HREF="makecheck.html#39_11">kernel_patch_test paramaters</A></LI>
+<LI><A HREF="makecheck.html#39_12">module_compile paramaters</A></LI>
+</UL>
+<B><A HREF="makecheck.html#40">Current pitfalls</A></B>
+<BR>
+<BR><B><A HREF="nightly.html#nightly">Nightly regression testing</A></B>
+<BR>
+<BR><B><A HREF="nightly.html#nightlyhowto">How to setup the nightly
+ build</A></B>
+<UL>
+<LI><A HREF="nightly.html#42_1"> Files you need to know about</A></LI>
+<LI><A HREF="nightly.html#42_2">Configuring freeswan-regress-env.sh</A></LI>
+</UL>
+</BODY>
+</HTML>
diff --git a/doc/trouble.html b/doc/trouble.html
new file mode 100644
index 000000000..2123f3805
--- /dev/null
+++ b/doc/trouble.html
@@ -0,0 +1,706 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="firewall.html">Previous</A>
+<A HREF="compat.html">Next</A>
+<HR>
+<H1><A NAME="trouble"></A>Linux FreeS/WAN Troubleshooting Guide</H1>
+<H2><A NAME="overview"></A>Overview</H2>
+<P> This document covers several general places where you might have a
+ problem:</P>
+<OL>
+<LI><A HREF="#install">During install</A>.</LI>
+<LI><A HREF="#negotiation">During the negotiation process</A>.</LI>
+<LI><A HREF="#use">Using an established connection</A>.</LI>
+</OL>
+<P>This document also contains<A HREF="#notes"> notes</A> which expand
+ on points made in these sections, and tips for<A HREF="#prob.report">
+ problem reporting</A>. If the other end of your connection is not
+ FreeS/WAN, you'll also want to read our<A HREF="interop.html#interop.problem">
+ interoperation</A> document.</P>
+<H2><A NAME="install"></A>1. During Install</H2>
+<H3><A NAME="8_2_1">1.1 RPM install gotchas</A></H3>
+<P>With the RPM method:</P>
+<UL>
+<LI>Be sure you have installed both the userland tools and the kernel
+ components. One will not work without the other. For example, when
+ using FreeS/WAN-produced RPMs for our 2.04 release, you need both:
+<PRE> freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm
+ freeswan-module-2.04_2.4.20_20.9-0.i386.rpm
+</PRE>
+</LI>
+</UL>
+<H3><A NAME="8_2_2">1.2 Problems installing from source</A></H3>
+<P>When installing from source, you may find these problems:</P>
+<UL>
+<LI>Missing library. See<A HREF="faq.html#gmp.h_missing"> this</A> FAQ.</LI>
+<LI>Missing utilities required for compile. See this<A HREF="install.html#tool.lib">
+ checklist</A>.</LI>
+<LI>Kernel version incompatibility. See<A HREF="faq.html#k.versions">
+ this</A> FAQ.</LI>
+<LI>Another compile problem. Find information in the out.* files, ie.
+ out.kpatch, out.kbuild, created at compile time in the top-level Linux
+ FreeS/WAN directory. Error messages generated by KLIPS during the boot
+ sequence are accessible with the<VAR> dmesg</VAR> command.
+<BR> Check the list archives and the List in Brief to see if this is a
+ known issue. If it is not, report it to the bugs list as described in
+ our<A HREF="#prob.report"> problem reporting</A> section. In some
+ cases, you may be asked to provide debugging information using gdb;
+ details<A HREF="#gdb"> below</A>.</LI>
+<LI>If your kernel compiles but you fail to install your new
+ FreeS/WAN-enabled kernel, review the sections on<A HREF="install.html#newk">
+ installing the patched kernel</A>, and<A HREF="install.html#testinstall">
+ testing</A> to see if install succeeded.</LI>
+</UL>
+<H3><A NAME="install.check"></A>1.3 Install checks</H3>
+<P><VAR>ipsec verify</VAR> checks a number of FreeS/WAN essentials. Here
+ are some hints on what do to when your system doesn't check out:</P>
+<P></P>
+<TABLE border="1">
+<TR><TD><STRONG>Problem</STRONG></TD><TD><STRONG>Status</STRONG></TD><TD>
+<STRONG>Action</STRONG></TD></TR>
+<TR><TD><VAR>ipsec</VAR> not on-path</TD><TD>&nbsp;</TD><TD>
+<P>Add<VAR> /usr/local/sbin</VAR> to your PATH.</P>
+</TD></TR>
+<TR><TD>Missing KLIPS support</TD><TD><FONT COLOR="#FF0000">critical</FONT>
+</TD><TD>See<A HREF="faq.html#noKLIPS"> this FAQ.</A></TD></TR>
+<TR><TD>No RSA private key</TD><TD>&nbsp;</TD><TD>
+<P>Follow<A HREF="install.html#genrsakey"> these instructions</A> to
+ create an RSA key pair for your host. RSA keys are:</P>
+<UL>
+<LI>required for opportunistic encryption, and</LI>
+<LI>our preferred method to authenticate pre-configured connections.</LI>
+</UL>
+</TD></TR>
+<TR><TD><VAR>pluto</VAR> not running</TD><TD><FONT COLOR="#FF0000">
+critical</FONT></TD><TD>
+<PRE>service ipsec start</PRE>
+</TD></TR>
+<TR><TD>No port 500 hole</TD><TD><FONT COLOR="#FF0000">critical</FONT></TD><TD>
+Open port 500 for IKE negotiation.</TD></TR>
+<TR><TD>Port 500 check N/A</TD><TD>&nbsp;</TD><TD>Check that port 500 is open
+ for IKE negotiation.</TD></TR>
+<TR><TD>Failed DNS checks</TD><TD>&nbsp;</TD><TD>Opportunistic encryption
+ requires information from DNS. To set this up, see<A HREF="quickstart.html#opp.setup">
+ our instructions</A>.</TD></TR>
+<TR><TD>No public IP address</TD><TD>&nbsp;</TD><TD>Check that the interface
+ which you want to protect with IPSec is up and running.</TD></TR>
+</TABLE>
+<H3><A NAME="oe.trouble"></A>1.3 Troubleshooting OE</H3>
+<P>OE should work with no local configuration, if you have posted DNS
+ TXT records according to the instructions in our<A HREF="quickstart.html">
+ quickstart guide</A>. If you encounter trouble, try these hints. We
+ welcome additional hints via the<A HREF="mail.html"> users' mailing
+ list</A>.</P>
+<TABLE border="1">
+<TR><TD><STRONG>Symptom</STRONG></TD><TD><STRONG>Problem</STRONG></TD><TD>
+<STRONG>Action</STRONG></TD></TR>
+<TR><TD> You're running FreeS/WAN 2.01 (or later), and initiating a
+ connection to FreeS/WAN 2.00 (or earlier). In your logs, you see a
+ message like:
+<PRE>no RSA public key known for '192.0.2.13';
+DNS search for KEY failed (no KEY record
+for 13.2.0.192.in-addr.arpa.)</PRE>
+ The older FreeS/WAN logs no error.</TD><TD><A NAME="oe.trouble.flagday">
+</A> A protocol level incompatibility between 2.01 (or later) and 2.00
+ (or earlier) causes this error. It occurs when a FreeS/WAN 2.01 (or
+ later) box for which no KEY record is posted attempts to initiate an OE
+ connection to older FreeS/WAN versions (2.00 and earlier). Note that
+ older versions can initiate to newer versions without this error.</TD><TD>
+If you control the peer host, upgrade its FreeS/WAN to 2.01 (or later),
+ and post new style TXT records for it. If not, but if you know its
+ sysadmin, perhaps a quick note is in order. If neither option is
+ possible, you can ease the transition by posting an old style KEY
+ record (created with a command like &quot;ipsec&nbsp;showhostkey&nbsp;--key&quot;) to the
+ reverse map for the FreeS/WAN 2.01 (or later) box.</TD></TR>
+<TR><TD>OE host is very slow to contact other hosts.</TD><TD>Slow DNS
+ service while running OE.</TD><TD>It's a good idea to run a caching DNS
+ server on your OE host, as outlined in<A HREF="http://lists.freeswan.org/pipermail/design/2003-January/004205.html">
+ this mailing list message</A>. If your DNS servers are elsewhere, put
+ their IPs in the<VAR> clear</VAR> policy group, and re-read groups with
+<PRE>ipsec auto --rereadgroups</PRE>
+</TD></TR>
+<TR><TD>
+<PRE>Can't Opportunistically initiate for
+192.0.2.2 to 192.0.2.3: no TXT record
+for 13.2.0.192.in-addr.arpa.</PRE>
+</TD><TD>Peer is not set up for OE.</TD><TD>
+<P>None. Plenty of hosts on the Internet do not run OE. If, however, you
+ have set OE up on that peer, this may indicate that you need to wait up
+ to 48 hours for its DNS records to propagate.</P>
+</TD></TR>
+<TR><TD><VAR>ipsec verify</VAR> does not find DNS records:
+<PRE>...
+Looking for TXT in forward map:
+ xy.example.com...[FAILED]
+Looking for TXT in reverse map...[FAILED]
+...</PRE>
+ You also experience authentication failure:
+<BR>
+<PRE>Possible authentication failure:
+no acceptable response to our
+first encrypted message</PRE>
+</TD><TD>DNS records are not posted or have not propagated.</TD><TD>Did
+ you post the DNS records necessary for OE? If not, do so using the
+ instructions in our<A HREF="quickstart.html#quickstart"> quickstart
+ guide</A>. If so, wait up to 48 hours for the DNS records to propagate.</TD>
+</TR>
+<TR><TD><VAR>ipsec verify</VAR> does not find DNS records, and you
+ experience authentication failure.</TD><TD>For iOE, your ID does not
+ match location of forward DNS record.</TD><TD>In<VAR> config setup</VAR>
+, change<VAR> myid=</VAR> to match the forward DNS where you posted the
+ record. Restart FreeS/WAN. For reference, see our<A HREF="quickstart.html#opp.client">
+ iOE instructions</A>.</TD></TR>
+<TR><TD><VAR>ipsec verify</VAR> finds DNS records, yet there is still
+ authentication failure. ( ? )</TD><TD>DNS records are malformed.</TD><TD>
+Re-create the records and send new copies to your DNS administrator.</TD>
+</TR>
+<TR><TD><VAR>ipsec verify</VAR> finds DNS records, yet there is still
+ authentication failure. ( ? )</TD><TD>DNS records show different keys
+ for a gateway vs. its subnet hosts.</TD><TD>All TXT records for boxes
+ protected by an OE gateway must contain the gateway's public key.
+ Re-create and re-post any incorrect records using<A HREF="quickstart.html#opp.incoming">
+ these instructions</A>.</TD></TR>
+<TR><TD>OE gateway loses connectivity to its subnet. The gateway's
+ routing table shows routes to the subnet through IPsec interfaces.</TD><TD>
+The subnet is part of the<VAR> private</VAR> or<VAR> block</VAR> policy
+ group on the gateway.</TD><TD>Remove the subnet from the group, and
+ reread groups with
+<PRE>ipsec auto --rereadgroups</PRE>
+</TD></TR>
+<TR><TD>OE does not work to hosts on the local LAN.</TD><TD>This is a
+ known issue.</TD><TD>See<A HREF="opportunism.known-issues"> this list</A>
+ of known issues with OE.</TD></TR>
+<TR><TD>FreeS/WAN does not seem to be executing your default policy. In
+ your logs, you see a message like:
+<PRE>/etc/ipsec.d/policies/iprivate-or-clear&quot;
+line 14: subnet &quot;0.0.0.0/0&quot;,
+source 192.0.2.13/32,
+already &quot;private-or-clear&quot;</PRE>
+</TD><TD><A HREF="glossary.html#fullnet">Fullnet</A> in a policy group
+ file defines your default policy. Fullnet should normally be present in
+ only one policy group file. The fine print: you can have two default
+ policies defined so long as they protect different local endpoints
+ (e.g. the FreeS/WAN gateway and a subnet).</TD><TD> Find all policies
+ which contain fullnet with:
+<BR>
+<PRE>grep -F 0.0.0.0/0 /etc/ipsec.d/policies/*</PRE>
+ then remove the unwanted occurrence(s).</TD></TR>
+</TABLE>
+<H2><A NAME="negotiation"></A>2. During Negotiation</H2>
+<P>When you fail to bring up a tunnel, you'll need to find out:</P>
+<UL>
+<LI><A HREF="#state">what your connection state is,</A> and often</LI>
+<LI><A HREF="#find.pluto.error">an error message</A>.</LI>
+</UL>
+<P>before you can<A HREF="#interpret.pluto.error"> diagnose your problem</A>
+.</P>
+<H3><A NAME="state"></A>2.1 Determine Connection State</H3>
+<H4>Finding current state</H4>
+<P>You can see connection states (STATE_MAIN_I1 and so on) when you
+ bring up a connection on the command line. If you have missed this, or
+ brought up your connection automatically, use:</P>
+<PRE>ipsec auto --status</PRE>
+<P>The most relevant state is the last one reached.</P>
+<H4><VAR>What's this supposed to look like?</VAR></H4>
+<P>Negotiations should proceed though various states, in the processes
+ of:</P>
+<OL>
+<LI>IKE negotiations (aka Phase 1, Main Mode, STATE_MAIN_*)</LI>
+<LI>IPSEC negotiations (aka Phase 2, Quick Mode, STATE_QUICK_*)</LI>
+</OL>
+<P>These are done and a connection is established when you see messages
+ like:</P>
+<PRE> 000 #21: &quot;myconn&quot; STATE_MAIN_I4 (ISAKMP SA established)...
+ 000 #2: &quot;myconn&quot; STATE_QUICK_I2 (sent QI2, IPsec SA established)...</PRE>
+<P> Look for the key phrases are &quot;ISAKMP SA established&quot; and &quot;IPSec SA
+ established&quot;, with the relevant connection name. Often, this happens at
+ STATE_MAIN_I4 and STATE_QUICK_I2, respectively.</P>
+<P><VAR>ipsec auto --status</VAR> will tell you what states<STRONG> have
+ been achieved</STRONG>, rather than the current state. Since
+ determining the current state is rather more difficult to do, current
+ state information is not available from Linux FreeS/WAN. If you are
+ actively bringing a connection up, the status report's last states for
+ that connection likely reflect its current state. Beware, though, of
+ the case where a connection was correctly brought up but is now downed:
+ Linux FreeS/WAN will not notice this until it attempts to rekey.
+ Meanwhile, the last known state indicates that the connection has been
+ established.</P>
+<P>If your connection is stuck at STATE_MAIN_I1, skip straight to<A HREF="#ikepath">
+ here</A>.</P>
+<H3><A NAME="find.pluto.error"></A>2.2 Finding error text</H3>
+<P>Solving most errors will require you to find verbose error text,
+ either on the command line or in the logs.</P>
+<H4>Verbose start for more information</H4>
+<P> Note that you can get more detail from<VAR> ipsec auto</VAR> using
+ the --verbose flag:</P>
+<PRE STYLE="margin-bottom: 0.2in"> ipsec auto --verbose --up west-east</PRE>
+<P> More complete information can be gleaned from the<A HREF="#logusage">
+ log files</A>.</P>
+<H4>Debug levels count</H4>
+<P>The amount of description you'll get here depends on ipsec.conf debug
+ settings,<VAR> klipsdebug</VAR>= and<VAR> plutodebug</VAR>=. When
+ troubleshooting, set at least one of these to<VAR> all</VAR>, and when
+ done, reset it to<VAR> none</VAR> so your logs don't fill up. Note that
+ you must have enabled the<VAR> klipsdebug</VAR><A HREF="install.html#allbut">
+ compile-time option</A> for the<VAR> klipsdebug</VAR> configuration
+ switch to work.</P>
+<P>For negotiation problems<VAR> plutodebug</VAR> is most relevant.<VAR>
+ klipsdebug</VAR> applies mainly to attempts to use an
+ already-established connection. See also<A HREF="ipsec.html#parts">
+ this</A> description of the division of duties within Linux FreeS/WAN.</P>
+<P>After raising your debug levels, restart Linux FreeS/WAN to ensure
+ that ipsec.conf is reread, then recreate the error to generate verbose
+ logs.</P>
+<H4><VAR>ipsec barf</VAR> for lots of debugging information</H4>
+<P><A HREF="manpage.d/ipsec_barf.8.html"><VAR> ipsec barf (8)</VAR></A>
+ collects a bunch of useful debugging information, including these logs
+ Use the command</P>
+<PRE>
+ ipsec barf &gt; barf.west
+</PRE>
+<P>to generate one.</P>
+<H4>Find the error</H4>
+<P>Search out the failure point in your logs. Are there a handful of
+ lines which succinctly describe how things are going wrong or contrary
+ to your expectation? Sometimes the failure point is not immediately
+ obvious: Linux FreeS/WAN's errors are usually not marked &quot;Error&quot;. Have
+ a look in the<A HREF="faq.html"> FAQ</A> for what some common failures
+ look like.</P>
+<P>Tip: problems snowball. Focus your efforts on the first problem,
+ which is likely to be the cause of later errors.</P>
+<H4>Play both sides</H4>
+<P>Also find error text on the peer IPSec box. This gives you two
+ perspectives on the same failure.</P>
+<P>At times you will require information which only one side has. The
+ peer can merely indicate the presence of an error, and its approximate
+ point in the negotiations. If one side keeps retrying, it may be
+ because there is a show stopper on the other side. Have a look at the
+ other side and figure out what it doesn't like.</P>
+<P>If the other end is not Linux FreeS/WAN, the principle is the same:
+ replicate the error with its most verbose logging on, and capture the
+ output to a file.</P>
+<H3><A NAME="interpret.pluto.error"></A>2.3 Interpreting a Negotiation
+ Error</H3>
+<H4><A NAME="ikepath"></A>Connection stuck at STATE_MAIN_I1</H4>
+<P>This error commonly happens because IKE (port 500) packets, needed to
+ negotiate an IPSec connection, cannot travel freely between your IPSec
+ gateways. See<A HREF="firewall.html#packets"> our firewall document</A>
+ for details.</P>
+<H4>Other errors</H4>
+<P>Other errors require a bit more digging. Use the following resources:</P>
+<UL>
+<LI><A HREF="faq.html">the FAQ</A> . Since this document is constantly
+ updated, the snapshot's FAQ may have a new entry relevant to your
+ problem.</LI>
+<LI>our<A HREF="background.html"> background document</A> . Special
+ considerations which, while not central to Linux FreeS/WAN, are often
+ tripped over. Includes problems with<A href="background.html#MTU.trouble">
+ packet fragmentation</A>, and considerations for testing opportunism.</LI>
+<LI>the<A HREF="mail.html#lists"> list archives</A>. Each of the
+ searchable archives works differently, so it's worth checking each. Use
+ a search term which is generic, but identifies your error, for example
+ &quot;No connection is known for&quot;.
+<BR> Often, you will find that your question has been answered in the
+ past. Finding an archived answer is quicker than asking the list. You
+ may, however, find similar questions without answers. If you do, send
+ their URLs to the list with your trouble report. The additional
+ examples may help the list tech support person find your answer.</LI>
+<LI>Look into the code where the error is being generated. The pluto
+ code is nicely documented with comments and meaningful variable names.</LI>
+</UL>
+<P>If you have failed to solve your problem with the help of these
+ resources, send a detailed problem report to the users list, following
+ these<A HREF="#prob.report"> guidelines</A>.</P>
+<H2><A NAME="use"></A>3. Using a Connection</H2>
+<H3><A NAME="8_4_1">3.1 Orienting yourself</A></H3>
+<H4><VAR>How do I know if it works?</VAR></H4>
+<P>Test your connection by sending packets through it. The simplest way
+ to do this is with ping, but the ping needs to<STRONG> test the correct
+ tunnel.</STRONG> See<A HREF="#testgates"> this example scenario</A> if
+ you don't understand this.</P>
+<P></P>
+<P>If your ping returns, test any other connections you've brought u all
+ check out, great. You may wish to<A HREF="#bigpacket"> test with large
+ packets</A> for MTU problems.</P>
+<H4><VAR>ipsec barf</VAR> is useful again</H4>
+<P>If your ping fails to return, generate an ipsec barf debugging report
+ on each IPSec gateway. On a non-Linux FreeS/WAN implementation, gather
+ equivalent information. Use this, and the tips in the next sections, to
+ troubleshoot. Are you sure that both endpoints are capable of hearing
+ and responding to ping?</P>
+<H3><A NAME="8_4_2">3.2 Those pesky configuration errors</A></H3>
+<P>IPSec may be dropping your ping packets since they do not belong in
+ the tunnels you have constructed:</P>
+<UL>
+<LI>Your ping may not test the tunnel you intend to test. For details,
+ see our<A HREF="faq.html#cantping"> &quot;I can't ping&quot;</A> FAQ.</LI>
+<LI> Alternately, you may have a configuration error. For example, you
+ may have configured one of the four possible tunnels between two
+ gateways, but not the one required to secure the important traffic
+ you're now testing. In this case, add and start the tunnel, and try
+ again.</LI>
+</UL>
+<P>In either case, you will often see a message like:</P>
+<PRE>klipsdebug... no eroute</PRE>
+<P>which we discuss in<A HREF="faq.html#no_eroute"> this FAQ</A>.</P>
+<P>Note:</P>
+<UL>
+<LI><A HREF="glossary.html#NAT.gloss">Network Address Translation (NAT)</A>
+ and<A HREF="glossary.html#masq"> IP masquerade</A> may have an effect
+ on which tunnels you need to configure.</LI>
+<LI>When testing a tunnel that protects a multi-node subnet, try several
+ subnet nodes as ping targets, in case one node is routing incorrectly.</LI>
+</UL>
+<H3><A NAME="route.firewall"></A>3.3 Check Routing and Firewalling</H3>
+<P>If you've confirmed your configuration assumptions, the problem is
+ almost certainly with routing or firewalling. Isolate the problem using
+ interface statistics, firewall statistics, or a packet sniffer.</P>
+<H4>Background:</H4>
+<UL>
+<LI>Linux FreeS/WAN supplies all the special routing it needs; you need
+ only route packets out through your IPSec gateway. Verify that on the<VAR>
+ subnetted</VAR> machines you are using for your ping-test, your routing
+ is as expected. I have seen a tunnel &quot;fail&quot; because the subnet machine
+ sending packets out an alternate gateway (not our IPSec gateway) on
+ their return path.</LI>
+<LI>Linux FreeS/WAN requires particular<A HREF="firewall.html">
+ firewalling considerations</A>. Check the firewall rules on your IPSec
+ gateways and ensure that they allow IPSec traffic through. Be sure that
+ no other machine - for example a router between the gateways - is
+ blocking your IPSec packets.</LI>
+</UL>
+<H4><A NAME="ifconfig"></A>View Interface and Firewall Statistics</H4>
+<P>Interface reports and firewall statistics can help you track down
+ lost packets at a glance. Check any firewall statistics you may be
+ keeping on your IPSec gateways, for dropped packets.</P>
+<P><STRONG>Tip</STRONG>: You can take a snapshot of the packets
+ processed by your firewall with:</P>
+<PRE> iptables -L -n -v</PRE>
+<P>You can get creative with &quot;diff&quot; to find out what happens to a
+ particular packet during transmission.</P>
+<P>Both<VAR> cat /proc/net/dev</VAR> and<VAR> ifconfig</VAR> display
+ interface statistics, and both are included in<VAR> ipsec barf</VAR>.
+ Use either to check if any interface has dropped packets. If you find
+ that one has, test whether this is related to your ping. While you ping
+ continuously, print that interface's statistics several times. Does its
+ drop count increase in proportion to the ping? If so, check why the
+ packets are dropped there.</P>
+<P>To do this, look at the firewall rules that apply to that interface.
+ If the interface is an IPSec interface, more information may be
+ available in the log. Grep for the word &quot;drop&quot; in a log which was
+ created with<VAR> klipsdebug=all</VAR> as the error happened.</P>
+<P>See also this<A HREF="#ifconfig1"> discussion</A> on interpreting<VAR>
+ ifconfig</VAR> statistics.</P>
+<H3><A NAME="sniff"></A>3.4 When in doubt, sniff it out</H3>
+<P>If you have checked configuration assumptions, routing, and firewall
+ rules, and your interface statistics yield no clue, it remains for you
+ to investigate the mystery of the lost packet by the most thorough
+ method: with a packet sniffer (providing, of course, that this is legal
+ where you are working).</P>
+<P>In order to detect packets on the ipsec virtual interfaces, you will
+ need an up-to-date sniffer (tcpdump, ethereal, ksnuffle) on your IPSec
+ gateway machines. You may also find it useful to sniff the ping
+ endpoints.</P>
+<H4>Anticipate your packets' path</H4>
+<P>Ping, and examine each interface along the projected path, checking
+ for your ping's arrival. If it doesn't get to the the next stop, you
+ have narrowed down where to look for it. In this way, you can isolate a
+ problem area, and narrow your troubleshooting focus.</P>
+<P>Within a machine running Linux FreeS/WAN, this<A HREF="firewall.html#packets">
+ packet flow diagram</A> will help you anticipate a packet's path.</P>
+<P>Note that:</P>
+<UL>
+<LI> from the perspective of the tunneled packet, the entire tunnel is
+ one hop. That's explained in<A HREF="faq.html#no_trace"> this</A> FAQ.</LI>
+<LI> an encapsulated IPSec packet will look different, when sniffed,
+ from the plaintext packet which generated it. You can see plaintext
+ packets entering an IPSec interface and the resulting cyphertext
+ packets as they emerge from the corresponding physical interface.</LI>
+</UL>
+<P>Once you isolate where the packet is lost, take a closer look at
+ firewall rules, routing and configuration assumptions as they affect
+ that specific area. If the packet is lost on an IPSec gateway, comb
+ through<VAR> klipsdebug</VAR> output for anomalies.</P>
+<P>If the packet goes through both gateways successfully and reaches the
+ ping target, but does not return, suspect routing. Check that the ping
+ target routes packets back to the IPSec gateway.</P>
+<H3><A NAME="find.use.error"></A>3.5 Check your logs</H3>
+<P>Here, too, log information can be useful. Start with the<A HREF="#find.pluto.error">
+ guidelines above</A>.</P>
+<P>For connection use problems, set<VAR> klipsdebug=all</VAR>. Note that
+ you must have enabled the<VAR> klipsdebug</VAR><A HREF="install.html#allbut">
+ compile-time option</A> to do this. Restart Linux FreeS/WAN so that it
+ rereads<VAR> ipsec.conf</VAR>, then recreate the error condition. When
+ searching through<VAR> klipsdebug</VAR> data, look especially for the
+ keywords &quot;drop&quot; (as in dropped packets) and &quot;error&quot;.</P>
+<P>Often the problem with connection use is not software error, but
+ rather that the software is behaving contrary to expectation.</P>
+<H4><A NAME="interpret.use.error"></A>Interpreting log text</H4>
+<P>To interpret the Linux FreeS/WAN log text you've found, use the same
+ resources as indicated for troubleshooting connection negotiation:<A HREF="faq.html">
+ the FAQ</A> , our<A HREF="background.html"> background document</A>,
+ and the<A HREF="mail.html#lists"> list archives</A>. Looking in the
+ KLIPS code is only for the very brave.</P>
+<P>If you are still stuck, send a<A HREF="#prob.report"> detailed
+ problem report</A> to the users' list.</P>
+<H3><A NAME="bigpacket"></A>3.6 More testing for the truly thorough</H3>
+<H4>Large Packets</H4>
+<P>If each of your connections passed the ping test, you may wish to
+ test by pinging with large packets (2000 bytes or larger). If it does
+ not return, suspect MTU issues, and see this<A HREF="background.html#MTU.trouble">
+ discussion</A>.</P>
+<H4>Stress Tests</H4>
+<P>In most users' view, a simple ping test, and perhaps a large-packet
+ ping test suffice to indicate a working IPSec connection.</P>
+<P>Some people might like to do additional stress tests prior to
+ production use. They may be interested in this<A HREF="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00224.html">
+ testing protocol</A> we use at interoperation conferences, aka
+ &quot;bakeoffs&quot;. We also have a<VAR> testing</VAR> directory that ships with
+ the release.</P>
+<H2><A NAME="prob.report"></A>4. Problem Reporting</H2>
+<H3><A NAME="8_5_1">4.1 How to ask for help</A></H3>
+<P>Ask for troubleshooting help on the users' mailing list,<A HREF="mailto:users@lists.freeswan.org">
+ users@lists.freeswan.org</A>. While sometimes an initial query with a
+ quick description of your intent and error will twig someone's memory
+ of a similar problem, it's often necessary to send a second mail with a
+ complete problem report.</P>
+<P>When reporting problems to the mailing list(s), please include:</P>
+<UL>
+<LI>a brief description of the problem</LI>
+<LI>if it's a compile problem, the actual output from make, showing the
+ problem. Try to edit it down to only the relevant part, but when in
+ doubt, be as complete as you can. If it's a kernel compile problem, any
+ relevant out.* files</LI>
+<LI>if it's a run-time problem, pointers to where we can find the
+ complete output from &quot;ipsec barf&quot; from BOTH ENDS (not just one of
+ them). Remember that it's common outside the US and Canada to pay for
+ download volume, so if you can't post barfs on the web and send the URL
+ to the mailing list, at least compress them with tar or gzip.
+<BR> If you can, try to simplify the case that is causing the problem.
+ In particular, if you clear your logs, start FreeS/WAN with no other
+ connections running, cause the problem to happen, and then do<VAR>
+ ipsec barf</VAR> on both ends immediately, that gives the smallest and
+ least cluttered output.</LI>
+<LI>any other error messages, complaints, etc. that you saw. Please send
+ the complete text of the messages, not just a summary.</LI>
+<LI>what your network setup is. Include subnets, gateway addresses, etc.
+ A schematic diagram is a good format for this information.</LI>
+<LI>exactly what you were trying to do with Linux FreeS/WAN, and exactly
+ what went wrong</LI>
+<LI>a fix, if you have one. But remember, you are sending mail to people
+ all over the world; US residents and US citizens in particular, please
+ read doc/exportlaws.html before sending code -- even small bug fixes --
+ to the list or to us.</LI>
+<LI>When in doubt about whether to include some seemingly-trivial item
+ of information, include it. It is rare for problem reports to have too
+ much information, and common for them to have too little.</LI>
+</UL>
+<P>Here are some good general guidelines on bug reporting:<A href="http://tuxedo.org/~esr/faqs/smart-questions.html">
+ How To Ask Questions The Smart Way</A> and<A href="http://www.chiark.greenend.org.uk/~sgtatham/bugs.html">
+ How to Report Bugs Effectively</A>.</P>
+<H3><A NAME="8_5_2">4.2 Where to ask</A></H3>
+<P>To report a problem, send mail about it to the users' list. If you
+ are certain that you have found a bug, report it to the bugs list. If
+ you encounter a problem while doing your own coding on the Linux
+ FreeS/WAN codebase and think it is of interest to the design team,
+ notify the design list. When in doubt, default to the users' list. More
+ information about the mailing lists is found<A HREF="mail.html#lists">
+ here</A>.</P>
+<P>For a number of reasons -- including export-control regulations
+ affecting almost any<STRONG> private</STRONG> discussion of encryption
+ software -- we prefer that problem reports and discussions go to the
+ lists, not directly to the team. Beware that the list goes worldwide;
+ US citizens, read this important information about your<A HREF="politics.html#exlaw">
+ export laws</A>. If you're using this software, you really should be on
+ the lists. To get onto them, visit<A HREF="http://lists.freeswan.org/">
+ lists.freeswan.org</A>.</P>
+<P>If you do send private mail to our coders or want a private reply
+ from them, please make sure that the return address on your mail (From
+ or Reply-To header) is a valid one. They have more important things to
+ do than to unravel addresses that have been mangled in an attempt to
+ confuse spammers.</P>
+<H2><A NAME="notes"></A>5. Additional Notes on Troubleshooting</H2>
+<P>The following sections supplement the Guide:<A HREF="#system.info">
+ information available on your system</A>;<A HREF="#testgates"> testing
+ between security gateways</A>;<A HREF="#ifconfig1"> ifconfig reports
+ for KLIPS debugging</A>;<A HREF="#gdb"> using GDB on Pluto</A>.</P>
+<H3><A NAME="system.info"></A>5.1 Information available on your system</H3>
+<H4><A NAME="logusage"></A>Logs used</H4>
+<P>Linux FreeS/WAN logs to:</P>
+<UL>
+<LI>/var/log/secure (or, on Debian, /var/log/auth.log)</LI>
+<LI>/var/log/messages</LI>
+</UL>
+<P>Check both places to get full information. If you find nothing, check
+ your<VAR> syslogd.conf(5)</VAR> to see where your /etc/syslog.conf or
+ equivalent is directing<VAR> authpriv</VAR> messages.</P>
+<H4><A NAME="pages"></A>man pages provided</H4>
+<DL>
+<DT><A HREF="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A></DT>
+<DD> Manual page for IPSEC configuration file.</DD>
+<DT><A HREF="manpage.d/ipsec.8.html"> ipsec(8)</A></DT>
+<DD STYLE="margin-bottom: 0.2in"> Primary man page for ipsec utilities.</DD>
+</DL>
+<P> Other man pages are on<A HREF="manpages.html"> this list</A> and in</P>
+<UL>
+<LI>/usr/local/man/man3</LI>
+<LI>/usr/local/man/man5</LI>
+<LI>/usr/local/man/man8/ipsec_*</LI>
+</UL>
+<H4><A NAME="statusinfo"></A>Status information</H4>
+<DL>
+<DT>ipsec auto --status</DT>
+<DD> Command to get status report from running system. Displays Pluto's
+ state. Includes the list of connections which are currently &quot;added&quot; to
+ Pluto's internal database; lists state objects reflecting ISAKMP and
+ IPsec SAs being negotiated or installed.</DD>
+<DT> ipsec look</DT>
+<DD> Brief status info.</DD>
+<DT> ipsec barf</DT>
+<DD STYLE="margin-bottom: 0.2in"> Copious debugging info.</DD>
+</DL>
+<H3><A NAME="testgates"></A> 5.2 Testing between security gateways</H3>
+<P>Sometimes you need to test a subnet-subnet tunnel. This is a tunnel
+ between two security gateways, which protects traffic on behalf of the
+ subnets behind these gateways. On this network:</P>
+<PRE> Sunset==========West------------------East=========Sunrise
+ IPSec gateway IPSec gateway
+ local net untrusted net local net</PRE>
+<P> you might name this tunnel sunset-sunrise. You can test this tunnel
+ by having a machine behind one gateway ping a machine behind the other
+ gateway, but this is not always convenient or even possible.</P>
+<P>Simply pinging one gateway from the other is not useful. Such a ping
+ does not normally go through the tunnel.<STRONG> The tunnel handles
+ traffic between the two protected subnets, not between the gateways</STRONG>
+ . Depending on the routing in place, a ping might</P>
+<UL>
+<LI>either succeed by finding an unencrypted route</LI>
+<LI>or fail by finding no route. Packets without an IPSEC eroute are
+ discarded.</LI>
+</UL>
+<P><STRONG>Neither event tells you anything about the tunnel</STRONG>.
+ You can explicitly create an eroute to force such packets through the
+ tunnel, or you can create additional tunnels as described in our<A HREF="config.html#multitunnel">
+ configuration document</A>, but those may be unnecessary complications
+ in your situation.</P>
+<P>The trick is to explicitly test between<STRONG> both gateways'
+ private-side IP addresses</STRONG>. Since the private-side interfaces
+ are on the protected subnets, the resulting packets do go via the
+ tunnel. Use either ping -I or traceroute -i, both of which allow you to
+ specify a source interface. (Note: unsupported on older Linuxes). The
+ same principles apply for a road warrior (or other) case where only one
+ end of your tunnel is a subnet.</P>
+<H3><A NAME="ifconfig1"></A>5.3 ifconfig reports for KLIPS debugging</H3>
+<P>When diagnosing problems using ifconfig statistics, you may wonder
+ what type of activity increments a particular counter for an ipsecN
+ device. Here's an index, posted by KLIPS developer Richard Guy Briggs:</P>
+<PRE>Here is a catalogue of the types of errors that can occur for which
+statistics are kept when transmitting and receiving packets via klips.
+I notice that they are not necessarily logged in the right counter.
+. . .
+
+Sources of ifconfig statistics for ipsec devices
+
+rx-errors:
+- packet handed to ipsec_rcv that is not an ipsec packet.
+- ipsec packet with payload length not modulo 4.
+- ipsec packet with bad authenticator length.
+- incoming packet with no SA.
+- replayed packet.
+- incoming authentication failed.
+- got esp packet with length not modulo 8.
+
+tx_dropped:
+- cannot process ip_options.
+- packet ttl expired.
+- packet with no eroute.
+- eroute with no SA.
+- cannot allocate sk_buff.
+- cannot allocate kernel memory.
+- sk_buff internal error.
+
+
+The standard counters are:
+
+struct enet_statistics
+{
+ int rx_packets; /* total packets received */
+ int tx_packets; /* total packets transmitted */
+ int rx_errors; /* bad packets received */
+ int tx_errors; /* packet transmit problems */
+ int rx_dropped; /* no space in linux buffers */
+ int tx_dropped; /* no space available in linux */
+ int multicast; /* multicast packets received */
+ int collisions;
+
+ /* detailed rx_errors: */
+ int rx_length_errors;
+ int rx_over_errors; /* receiver ring buff overflow */
+ int rx_crc_errors; /* recved pkt with crc error */
+ int rx_frame_errors; /* recv'd frame alignment error */
+ int rx_fifo_errors; /* recv'r fifo overrun */
+ int rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ int tx_aborted_errors;
+ int tx_carrier_errors;
+ int tx_fifo_errors;
+ int tx_heartbeat_errors;
+ int tx_window_errors;
+};
+
+of which I think only the first 6 are useful.</PRE>
+<H3><A NAME="gdb"></A> 5.4 Using GDB on Pluto</H3>
+<P>You may need to use the GNU debugger, gdb(1), on Pluto. This should
+ be necessary only in unusual cases, for example if you encounter a
+ problem which the Pluto developer cannot readily reproduce or if you
+ are modifying Pluto.</P>
+<P>Here are the Pluto developer's suggestions for doing this:</P>
+<PRE>Can you get a core dump and use gdb to find out what Pluto was doing
+when it died?
+
+To get a core dump, you will have to set dumpdir to point to a
+suitable directory (see <A HREF="manpage.d/ipsec.conf.5.html">ipsec.conf(5)</A>).
+
+To get gdb to tell you interesting stuff:
+ $ script
+ $ cd dump-directory-you-chose
+ $ gdb /usr/local/lib/ipsec/pluto core
+ (gdb) where
+ (gdb) quit
+ $ exit
+
+The resulting output will have been captured by the script command in
+a file called &quot;typescript&quot;. Send it to the list.
+
+Do not delete the core file. I may need to ask you to print out some
+more relevant stuff.</PRE>
+<P> Note that the<VAR> dumpdir</VAR> parameter takes effect only when
+ the IPsec subsystem is restarted -- reboot or ipsec setup restart.</P>
+<P>
+<BR>
+<BR></P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="firewall.html">Previous</A>
+<A HREF="compat.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/umltesting.html b/doc/umltesting.html
new file mode 100644
index 000000000..35bcef96d
--- /dev/null
+++ b/doc/umltesting.html
@@ -0,0 +1,313 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="roadmap.html">Previous</A>
+<A HREF="makecheck.html">Next</A>
+<HR>
+<H1><A name="umltesting">User-Mode-Linux Testing guide</A></H1>
+<P> User mode linux is a way to compile a linux kernel such that it can
+ run as a process in another linux system (potentially as a *BSD or
+ Windows process later). See<A HREF="http://user-mode-linux.sourceforge.net/">
+ http://user-mode-linux.sourceforge.net/</A></P>
+<P> UML is a good platform for testing and experimenting with FreeS/WAN.
+ It allows several network nodes to be simulated on a single machine.
+ Creating, configuring, installing, monitoring, and controling these
+ nodes is generally easier and easier to script with UML than real
+ hardware.</P>
+<P> You'll need about 500Mb of disk space for a full
+ sunrise-east-west-sunset setup. You can possibly get this down by 130Mb
+ if you remove the sunrise/sunset kernel build. If you just want to run,
+ then you can even remove the east/west kernel build.</P>
+<P> Nothing need be done as super user. In a couple of steps, we note
+ where super user is required to install commands in system-wide
+ directories, but ~/bin could be used instead. UML seems to use a
+ system-wide /tmp/uml directory so different users may interfere with
+ one another. Later UMLs use ~/.uml instead, so multiple users running
+ UML tests should not be a problem, but note that a single user running
+ the UML tests will only be able run one set. Further, UMLs sometimes
+ get stuck and hang around. These &quot;zombies&quot; (most will actually be in
+ the &quot;T&quot; state in the process table) will interfere with subsequent
+ tests.</P>
+<H2><A NAME="34_1">Preliminary Notes on BIND</A></H2>
+<P> As of 2003/3/1, the Light-Weight Resolver is used by pluto. This
+ requires that BIND9 be running. It also requires that BIND9 development
+ libraries be present in the build environment. The DNSSEC code is only
+ truly functional in BIND9 snapshots. The library code could be 9.2.2,
+ we believe. We are using BIND9 20021115 snapshot code from<A HREF="ftp://ftp.isc.org/isc/bind9/snapshots">
+ ftp://ftp.isc.org/isc/bind9/snapshots</A>.</P>
+<P> FreeS/WAN may well require a newer BIND than is on your system. Many
+ distributions have moved to BIND9.2.2 recently due to a security
+ advisory. BIND is five components.</P>
+<OL>
+<LI> named</LI>
+<LI> dnssec-*</LI>
+<LI> client side resolver libraries</LI>
+<LI> client side utility libraries I thought there were lib and named
+ parts to dnsssec...</LI>
+<LI> dynamic DNS update utilities</LI>
+</OL>
+<P> The only piece that we need for *building* is #4. That's the only
+ part that has to be on the build host. What is the difference between
+ resolver and util libs? If you want to edit
+ testing/baseconfigs/all/etc/bind, you'll need a snapshot version. The
+ resolver library contains the resolver. FreeS/WAN has its own copy of
+ that in lib/liblwres.</P>
+<H2><A NAME="34_2">Steps to Install UML for FreeS/WAN</A></H2>
+<OL>
+<LI> Get the following files:
+<OL type="a">
+<LI> from<A HREF="http://www.sandelman.ottawa.on.ca/freeswan/uml/">
+ http://www.sandelman.ottawa.on.ca/freeswan/uml/</A>
+ umlfreeroot-15.1.tar.gz (or highest numbered one). This is a debian
+ potato root file system. You can use this even on a Redhat host, as it
+ has the newer GLIBC2.2 libraries as well.
+<!-- If you are using
+ Redhat 7.2 or newer as your development machine, you can create the
+ image from your installation media. See <A HREF="uml-rhroot.html">Building a RedHat root"></A>.
+ A future document will explain how to build this from .DEB files as well.
+-->
+
+<!--
+<LI> umlfreesharemini.tar.gz (or umlfreeshareall.tar.gz).
+ If you are a Debian potato user, you don't need it you can use your
+ native /usr/share.
+</UL>
+-->
+</LI>
+<LI> From<A HREF="ftp://ftp.xs4all.nl/pub/crypto/freeswan/">
+ ftp://ftp.xs4all.nl/pub/crypto/freeswan/</A> a snapshot or release
+ (1.92 or better)</LI>
+<LI> From a<A HREF="http://www.kernel.org/mirrors/">
+ http://www.kernel.org mirror</A>, the virgin 2.4.19 kernel. Please
+ realize that we have defaults in our tree for kernel configuration. We
+ try to track the latest UML kernels. If you use a newer kernel, you may
+ have faults in the kernel build process. You can see what the latest
+ that is being regularly tested by visiting<A HREF="http://bugs.freeswan.org:81/regress/HEAD/lastgood/freeswan-regress-env.sh">
+ freeswan-regress-env.sh</A>.</LI>
+<LI>
+<!-- Note: this step is refered to as "step 1d" below. -->
+ Get<A HREF="http://ftp.nl.linux.org/uml/">
+ http://ftp.nl.linux.org/uml/</A> uml-patch-2.4.19-47.bz2 or the one
+ associated with your kernel. As of 2003/03/05, uml-patch-2.4.19-47.bz2
+ works for us.<STRONG> More recent versions of the patch have not been
+ tested by us.</STRONG></LI>
+<LI> You'll probably want to visit<A HREF="http://user-mode-linux.sourceforge.net">
+ http://user-mode-linux.sourceforge.net</A> and get the UML utilities.
+ These are not needed for the build or interactive use (but
+ recommended). They are necessary for the regression testing procedures
+ used by &quot;make check&quot;. We currently use uml_utilities_20020212.tar.bz2.</LI>
+<LI> You need tcpdump version 3.7.1 or better. This is newer than the
+ version included in most LINUX distributions. You can check the version
+ of an installed tcpdump with the --version flag. If you need a newer
+ tcpdump fetch both tcpdump and libpcap source tar files from<A HREF="http://www.tcpdump.org/">
+ http://www.tcpdump.org/</A> or a mirror.</LI>
+</OL>
+</LI>
+<LI> Pick a suitable place, and extract the following files:
+<OL type="a">
+<LI>
+<!-- Note: this step is refered to as "step 2a" later. -->
+ 2.4.19 kernel. For instance:
+<PRE>
+ <CODE> cd /c2/kernel
+ tar xzvf ../download/pub/linux/kernel/v2.4/linux-2.4.19.tar.gz
+</CODE>
+</PRE>
+</LI>
+<LI> extract the umlfreeroot file
+<!-- (unless you <A HREF="uml-rhroot.html">built your own from RPMs</A>) -->
+
+<PRE>
+ <CODE> mkdir -p /c2/user-mode-linux/basic-root
+ cd /c2/user-mode-linux/basic-root
+ tar xzvf ../download/umlfreeroot-15.1.tar.gz
+</CODE>
+</PRE>
+</LI>
+<LI> FreeSWAN itself (or checkout &quot;all&quot; from CVS)
+<PRE>
+ <CODE> mkdir -p /c2/freeswan/sandbox
+ cd /c2/freeswan/sandbox
+ tar xzvf ../download/snapshot.tar.gz
+</CODE>
+</PRE>
+</LI>
+</OL>
+</LI>
+<LI> If you need to build a newer tcpdump:
+<UL>
+<LI> Make sure you have OpenSSL installed -- it is needed for
+ cryptographic routines.</LI>
+<LI> Unpack libpcap and tcpdump source in parallel directories (the
+ tcpdump build procedures look for libpcap next door).</LI>
+<LI> Change directory into the libpcap source directory and then build
+ the library:
+<PRE>
+ <CODE> ./configure
+ make
+</CODE>
+</PRE>
+</LI>
+<LI> Change into the tcpdump source directory, build tcpdump, and
+ install it.
+<PRE>
+ <CODE> ./configure
+ make
+ # Need to be superuser to install in system directories.
+ # Installing in ~/bin would be an alternative.
+ su -c &quot;make install&quot;
+</CODE>
+</PRE>
+</LI>
+</UL>
+</LI>
+<LI> If you need the uml utilities, unpack them somewhere then build and
+ install them:
+<PRE>
+ <CODE> cd tools
+ make all
+ # Need to be superuser to install in system directories.
+ # Installing in ~/bin would be an alternative.
+ su -c &quot;make install BIN_DIR=/usr/local/bin&quot;
+</CODE>
+</PRE>
+</LI>
+<LI> set up the configuration file
+<UL>
+<LI> <CODE>cd /c2/freeswan/sandbox/freeswan-1.97/testing/utils</CODE></LI>
+<LI> copy umlsetup-sample.sh to ../../umlsetup.sh: <CODE> cp
+ umlsetup-sample.sh ../../umlsetup.sh</CODE></LI>
+<LI> open up ../../umlsetup.sh in your favorite editor.</LI>
+<LI> change POOLSPACE= to point to the place with at least 500Mb of
+ disk. Best if it is on the same partition as the &quot;umlfreeroot&quot;
+ extraction, as it will attempt to use hard links if possible to save
+ disk space.</LI>
+<LI> Set TESTINGROOT if you intend to run the script outside of the
+ sandbox/snapshot/release directory. Otherwise, it will configure
+ itself.</LI>
+<LI> KERNPOOL should point to the directory with your 2.4.19 kernel
+ tree. This tree should be unconfigured! This is the directory you used
+ in step 2a.</LI>
+<LI> UMLPATCH should point at the bz2 file you downloaded at 1d. If
+ using a kernel that already includes the patch, set this to /dev/null.</LI>
+<LI> FREESWANDIR should point at the directory where you unpacked the
+ snapshot/release. Include the &quot;freeswan-snap2001sep16b&quot; or whatever in
+ it. If you are running from CVS, then you point at the directory where
+ top, klips, etc. are. The script will fix up the directory so that it
+ can be used.</LI>
+<LI> BASICROOT should be set to the directory used in 2b, or to the
+ directory that you created with RPMs.</LI>
+<LI> SHAREDIR should be set to the directory used in 2c, to /usr/share
+ for Debian potato users, or to $BASICROOT/usr/share.</LI>
+</UL>
+</LI>
+<LI>
+<PRE> <CODE>cd $TESTINGROOT/utils
+sh make-uml.sh
+</CODE></PRE>
+ It will grind for awhile. If there are errors it will bail. If so, run
+ it under &quot;script&quot; and send the output to bugs@lists.freeswan.org.</LI>
+<LI> You will have a bunch of stuff under $POOLSPACE. Open four xterms:
+<PRE> <CODE> for i in sunrise sunset east west
+ do
+ xterm -name $i -title $i -e $POOLSPACE/$i/start.sh done
+</CODE></PRE>
+</LI>
+<LI> Login as root. Password is &quot;root&quot; (Note, these virtual machines are
+ networked together, but are not configured to talk to the rest of the
+ world.)</LI>
+<LI> verify that pluto started on east/west, run &quot;ipsec look&quot;</LI>
+<LI> login to sunrise. run &quot;ping sunset&quot;</LI>
+<LI> login to west. run &quot;tcpdump -p -i eth1 -n&quot; (tcpdump must be version
+ 3.7.1 or newer)</LI>
+<LI> Closing a console xterm will shut down that UML.</LI>
+<LI> You can &quot;make check&quot;, if you want to. It is run from
+ /c2/freeswan/sandbox/freeswan-1.97.</LI>
+</OL>
+<H1><A NAME="35">Debugging the kernel with GDB</A></H1>
+<P> With User-Mode-Linux, you can debug the kernel using GDB. See
+<!--HREF="http://user-mode-linux.sourceforge.net/debugging.html"-->
+
+ http://user-mode-linux.sourceforge.net/debugging.html.</(null)></P>
+<P> Typically, one will want to address a test case for a failing
+ situation. Running GDB from Emacs, or from other front ends is
+ possible. First start GDB.</P>
+<P> Tell it to open the UMLPOOL/swan/linux program.</P>
+<P> Note the PID of GDB:</P>
+<PRE>
+marajade-[projects/freeswan/mgmt/planning] mcr 1029 %ps ax | grep gdb
+ 1659 pts/9 SN 0:00 /usr/bin/gdb -fullname -cd /mara4/freeswan/kernpatch/UMLPOOL/swan/ linux
+</PRE>
+<P> Set the following in the environment:</P>
+<PRE>
+UML_east_OPT=&quot;debug gdb-pid=1659&quot;
+</PRE>
+<P> Then start the user-mode-linux in the test scheme you wish:</P>
+<PRE>
+marajade-[kernpatch/testing/klips/east-icmp-02] mcr 1220 %../../utils/runme.sh
+</PRE>
+ The user-mode-linux will stop on boot, giving you a chance to attach to
+ the process:
+<PRE>
+(gdb) file linux
+Reading symbols from linux...done.
+(gdb) attach 1
+Attaching to program: /mara4/freeswan/kernpatch/UMLPOOL/swan/linux, process 1
+0xa0118bc1 in kill () at hostfs_kern.c:770
+</PRE>
+<P> At this point, break points should be created as appropriate.</P>
+<H2><A NAME="35_1">Other notes about debugging</A></H2>
+<P> If you are running a standard test, after all the packets are sent,
+ the UML will be shutdown. This can cause problems, because the UML may
+ get terminated while you are debugging.</P>
+<P> The environment variable <CODE>NETJIGWAITUSER</CODE> can be set to
+ &quot;waituser&quot;. If so, then the testing system will prompt before exiting
+ the test.</P>
+<H1><A NAME="36">User-Mode-Linux mysteries</A></H1>
+<UL>
+<LI> running more than one UML of the same name (e.g. &quot;west&quot;) can cause
+ problems.</LI>
+<LI> running more than one UML from the same root file system is not a
+ good idea.</LI>
+<LI> all this means that running &quot;make check&quot; twice on the same machine
+ is probably not a good idea.</LI>
+<LI> occationally, UMLs will get stuck. This can happen like:
+<!--BLOCK-->
+ 15134 ? T
+ 0:00 /spare/hugh/uml/uml2.4.18-sept5/umlbuild/east/linux (east)
+ [/bin/sh] 15138 ? T 0:00
+ /spare/hugh/uml/uml2.4.18-sept5/umlbuild/east/linux (east) [halt]</(null)>
+ these will need to be killed. Note that they are in &quot;T&quot;racing mode.</LI>
+<LI> UMLs can also hang, and will report &quot;Tracing myself and I can't get
+ out&quot;. This is a bug in UML. There are ways to find out what is going on
+ and report this to the UML people, but we don't know the magic right
+ now.</LI>
+</UL>
+<H1><A NAME="37">Getting more info from uml_netjig</A></H1>
+<P> uml_netjig can be compiled with a built-in tcpdump. This uses
+ not-yet-released code from<A HREF="http://www.tcpdump.org/">
+ www.tcpdump.org</A>. Please see the instructions in <CODE>
+testing/utils/uml_netjig/Makefile</CODE>.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="roadmap.html">Previous</A>
+<A HREF="makecheck.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/upgrading.html b/doc/upgrading.html
new file mode 100644
index 000000000..ce9fba3d2
--- /dev/null
+++ b/doc/upgrading.html
@@ -0,0 +1,184 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="intro.html">Previous</A>
+<A HREF="quickstart.html">Next</A>
+<HR>
+<A NAME="upgrading"></A>
+<H1><A NAME="2">Upgrading to FreeS/WAN 2.x</A></H1>
+<H2><A NAME="2_1">New! Built in Opportunistic connections</A></H2>
+<P>Out of the box, FreeS/WAN 2.x will attempt to encrypt all your IP
+ traffic. It will try to establish IPsec connections for:</P>
+<UL>
+<LI> IP traffic from the Linux box on which you have installed
+ FreeS/WAN, and</LI>
+<LI> outbound IP traffic routed through that Linux box (eg. from a
+ protected subnet).</LI>
+</UL>
+<P>FreeS/WAN 2.x uses<STRONG> hidden, automatically enabled<VAR>
+ ipsec.conf</VAR> connections</STRONG> to do this.</P>
+<P>This behaviour is part of our campaign to get Opportunistic
+ Encryption (OE) widespread in the Linux world, so that any two Linux
+ boxes can encrypt to one another without prearrangement. There's one
+ catch, however: you must<A HREF="quickstart.html#quickstart"> set up a
+ few DNS records</A> to distribute RSA public keys and (if applicable)
+ IPsec gateway information.</P>
+<P>If you start FreeS/WAN before you have set up these DNS records, your
+ connectivity will be slow, and messages relating to the built in
+ connections will clutter your logs. If you are unable to set up DNS for
+ OE, you will wish to<A HREF="policygroups.html#disable_policygroups">
+ disable the hidden connections</A>.</P>
+<A NAME="upgrading.flagday"></A>
+<H3><A NAME="2_1_1">Upgrading Opportunistic Encryption to 2.01 (or
+ later)</A></H3>
+<P>As of FreeS/WAN 2.01, Opportunistic Encryption (OE) uses DNS TXT
+ resource records (RRs) only (rather than TXT with KEY). This change
+ causes a &quot;flag day&quot;. Users of FreeS/WAN 2.00 (or earlier) OE who are
+ upgrading may need to post additional resource records.</P>
+<P>If you are running<A HREF="glossary.html#initiate-only">
+ initiate-only OE</A>, you<EM> must</EM> put up a TXT record in any
+ forward domain as per our<A HREF="quickstart.html#opp.client">
+ quickstart instructions</A>. This replaces your old forward KEY.</P>
+<P> If you are running full OE, you require no updates. You already have
+ the needed TXT record in the reverse domain. However, to facilitate
+ future features, you may also wish to publish that TXT record in a
+ forward domain as instructed<A HREF="quickstart.html#opp.incoming">
+ here</A>.</P>
+<P>If you are running OE on a gateway (and encrypting on behalf of
+ subnetted boxes) you require no updates. You already have the required
+ TXT record in your gateway's reverse map, and the TXT records for any
+ subnetted boxes require no updating. However, to facilitate future
+ features, you may wish to publish your gateway's TXT record in a
+ forward domain as shown<A HREF="quickstart.html#opp.incoming"> here</A>
+.</P>
+<P> During the transition, you may wish to leave any old KEY records up
+ for some time. They will provide limited backward compatibility.
+<!--
+For more
+detail on that compatibility, see <A HREF="oe.known-issues">Known Issues with
+OE</A>.
+-->
+</P>
+<H2><A NAME="2_2">New! Policy Groups</A></H2>
+<P>We want to make it easy for you to declare security policy as it
+ applies to IPsec connections.</P>
+<P>Policy Groups make it simple to say:</P>
+<UL>
+<LI>These are the folks I want to talk to in the clear.</LI>
+<LI>These spammers' domains -- I don't want to talk to them at all.</LI>
+<LI>To talk to the finance department, I must use IPsec.</LI>
+<LI>For any other communication, try to encrypt, but it's okay if we
+ can't.</LI>
+</UL>
+<P>FreeS/WAN then implements these policies, creating OE connections if
+ and when needed. You can use Policy Groups along with connections you
+ explicitly define in ipsec.conf.</P>
+<P>For more information, see our<A HREF="policygroups.html"> Policy
+ Group HOWTO</A>.</P>
+<H2><A NAME="2_3">New! Packetdefault Connection</A></H2>
+<P>Free/SWAN 2.x ships with the<STRONG> automatically enabled, hidden
+ connection</STRONG><VAR> packetdefault</VAR>. This configures a
+ FreeS/WAN box as an OE gateway for any hosts located behind it. As
+ mentioned above, you must configure some<A HREF="quickstart.html"> DNS
+ records</A> for OE to work.</P>
+<P>As the name implies, this connection functions as a default. If you
+ have more specific connections, such as policy groups which configure
+ your FreeS/WAN box as an OE gateway for a local subnet, these will
+ apply before<VAR> packetdefault</VAR>. You can view<VAR> packetdefault</VAR>
+'s specifics in<A HREF="manpage.d/ipsec.conf.5.html"> man ipsec.conf</A>
+.</P>
+<H2><A NAME="2_4">FreeS/WAN now disables Reverse Path Filtering</A></H2>
+<P>FreeS/WAN often doesn't work with reverse path filtering. At start
+ time, FreeS/WAN now turns rp_filter off, and logs a warning.</P>
+<P>FreeS/WAN does not turn it back on again. You can do this yourself
+ with a command like:</P>
+<PRE> echo 1 &gt; /proc/sys/net/ipv4/conf/eth0/rp_filter</PRE>
+<P>For eth0, substitute the interface which FreeS/WAN was affecting.</P>
+<A NAME="ipsec.conf_v2"></A>
+<H2><A NAME="2_5">Revised<VAR> ipsec.conf</VAR></A></H2>
+<H3><A NAME="2_5_1">No promise of compatibility</A></H3>
+<P>The FreeS/WAN team promised config-file compatibility throughout the
+ 1.x series. That means a 1.5 config file can be directly imported into
+ a fresh 1.99 install with no problems.</P>
+<P>With FreeS/WAN 2.x, we've given ourselves permission to make the
+ config file easier to use. The cost: some FreeS/WAN 1.x configurations
+ will not work properly. Many of the new features are, however, backward
+ compatible.</P>
+<H3><A NAME="2_5_2">Most<VAR> ipsec.conf</VAR> files will work fine</A></H3>
+<P>... so long as you paste this line,<STRONG> with no preceding
+ whitespace</STRONG>, at the top of your config file:</P>
+<PRE> version 2</PRE>
+<H3><A NAME="2_5_3">Backward compatibility patch</A></H3>
+<P>If the new defaults bite you, use<A HREF="ipsec.conf.2_to_1"> this<VAR>
+ ipsec.conf</VAR> fragment</A> to simulate the old default values.</P>
+<H3><A NAME="2_5_4">Details</A></H3>
+<P> We've obsoleted various directives which almost no one was using:</P>
+<PRE> dump
+ plutobackgroundload
+ no_eroute_pass
+ lifetime
+ rekeystart
+ rekeytries</PRE>
+<P>For most of these, there is some other way to elicit the desired
+ behaviour. See<A HREF="http://lists.freeswan.org/pipermail/design/2002-August/003243.html">
+ this post</A>.</P>
+<P> We've made some settings, which almost everyone was using, defaults.
+ For example:</P>
+<PRE> interfaces=%defaultroute
+ plutoload=%search
+ plutostart=%search
+ uniqueids=yes</PRE>
+<P>We've also changed some default values to help with OE and Policy
+ Groups:</P>
+<PRE> authby=rsasig ## not secret!!!
+ leftrsasigkey=%dnsondemand ## looks up missing keys in DNS when needed.
+ rightrsasigkey=%dnsondemand</PRE>
+<P> Of course, you can still override any defaults by explictly
+ declaring something else in your connection.</P>
+<P><A HREF="http://lists.freeswan.org/pipermail/design/2002-August/003243.html">
+ A post with a list of many ipsec.conf changes.</A>
+<BR><A HREF="manpage.d/ipsec.conf.5.html"> Current ipsec.conf manual.</A>
+</P>
+<A NAME="upgrading.rpms"></A>
+<H3><A NAME="2_5_5">Upgrading from 1.x RPMs to 2.x RPMs</A></H3>
+<P>Note: When upgrading from 1-series to 2-series RPMs,<VAR> rpm -U</VAR>
+ will not work.</P>
+<P>You must instead erase the 1.x RPMs, then install the 2.x set:</P>
+<PRE> rpm -e freeswan</PRE>
+<PRE> rpm -e freeswan-module</PRE>
+<P>On erasing, your old<VAR> ipsec.conf</VAR> should be moved to<VAR>
+ ipsec.conf.rpmsave</VAR>. Keep this. You will probably want to copy
+ your existing connections to the end of your new 2.x file.</P>
+<P>Install the RPMs suitable for your kernel version, such as:</P>
+<PRE> rpm -ivh freeswan-module-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<PRE> rpm -ivh freeswan-userland-2.04_2.4.20_20.9-0.i386.rpm</PRE>
+<P>Or, to splice the files:</P>
+<PRE> cat /etc/ipsec.conf /etc/ipsec.conf.rpmsave &gt; /etc/ipsec.conf.tmp
+ mv /etc/ipsec.conf.tmp /etc/ipsec.conf</PRE>
+<P>Then, remove the redundant<VAR> conn %default</VAR> and<VAR> config
+ setup</VAR> sections. Unless you have done any special configuring
+ here, you'll likely want to remove the 1.x versions. Remove<VAR> conn
+ OEself</VAR>, if present.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="intro.html">Previous</A>
+<A HREF="quickstart.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/user_examples.html b/doc/user_examples.html
new file mode 100644
index 000000000..d683c92e1
--- /dev/null
+++ b/doc/user_examples.html
@@ -0,0 +1,320 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="background.html">Previous</A>
+<A HREF="makecheck.html">Next</A>
+<HR>
+<H1><A name="user.examples">FreeS/WAN script examples</A></H1>
+ This file is intended to hold a collection of user-written example
+ scripts or configuration files for use with FreeS/WAN.
+<P> So far it has only one entry.</P>
+<H2><A name="poltorak">Poltorak's Firewall script</A></H2>
+<PRE>
+From: Poltorak Serguei &lt;poltorak@dataforce.net&gt;
+Subject: [Users] Using FreeS/WAN
+Date: Tue, 16 Oct 2001
+
+Hello.
+
+I'm using FreeS/WAN IPsec for half a year. I learned a lot of things about
+it and I think it would be interesting for someone to see the result of my
+experiments and usage of FreeS/WAN. If you find a mistake in this
+file, please e-mail me. And excuse me for my english... I'm learning.. :)
+
+I'll talk about vary simple configuration:
+
+addresses prefix = 192.168
+
+ lan1 sgw1 .0.0/24 (Internet) sgw2 lan2
+ .1.0/24---[ .1.1 ; .0.1 ]===================[ .0.10 ; . 2.10 ]---.2.0/24
+
+
+We need to let lan1 see lan2 across Internet like it is behind sgw1. The
+same for lan2. And we need to do IPX bridge for Novel Clients and NDS
+synchronization.
+
+my config:
+------------------- ipsec.conf -------------------
+conn lan1-lan2
+ type=tunnel
+ compress=yes
+ #-------------------
+ left=192.168.0.1
+ leftsubnet=192.168.1.0/24
+ #-------------------
+ right=192.168.0.10
+ rightsubnet=192.168.2.0/24
+ #-------------------
+ auth=esp
+ authby=secret
+--------------- end of ipsec.conf ----------------
+
+ping .2.x from .1.y (y != 1)
+It works?? Fine. Let's continue...
+
+Why y != 1 ?? Because kernel of sgw1 have 2 IP addresses and it will choose
+the first IP (which is used to go to Internet) .0.1 and the packet won't go
+through IPsec tunnel :( But if do ping on .1.1 kernel will respond from
+that address (.1.1) and the packet will be tunneled. The same problem occurred then
+.2.x sends a packet to .1.2 which is down at the moment. What happens? .1.1
+sends ARP requesting .1.2... after 3 tries it send to .2.x an destunreach,
+but from his &quot;natural&quot; IP or .0.1 . So the error message won't be delivered!
+It's a big problem...
+
+Resolution... One can manipulate with ipsec0 or ipsec0:0 to solve the
+problem (if ipsec0 has .1.1 kernel will send packets correctly), but there
+are powerful and elegant iproute2 :) We simply need to change source address
+of packet that goes to other secure lan. This is done with
+
+ip route replace 192.168.2.0/24 via 192.168.0.10 dev ipsec0 src 192.168.1.1
+
+Cool!! Now it works!!
+
+The second step. We want install firewall on sgw1 and sgw2. Encryption of
+traffic without security isn't a good idea. I don't use {left|right}firewall,
+because I'm running firewall from init scripts.
+
+We want IPsec data between lan1-lan2, some ICMP errors (destination
+unreachable, TTL exceeded, parameter problem and source quench), replying on
+pings from both lans and Internet, ipxtunnel data for IPX and of course SSH
+between sgw1 and sgw2 and from/to one specified host.
+
+I'm using ipchains. With iptables there are some changes.
+
+---------------- rc.firewall ---------------------
+#!/bin/sh
+#
+# Firewall for IPsec lan1-lan2
+#
+
+IPC=/sbin/ipchains
+ANY=0.0.0.0/0
+
+# left
+SGW1_EXT=192.168.0.1
+SGW1_INT=192.168.1.1
+LAN1=192.168.1.0/24
+
+# right
+SGW2_EXT=192.168.0.10
+SGW2_INT=192.168.2.10
+LAN2=192.168.2.0/24
+
+# SSH from and to this host
+SSH_PEER_HOST=_SOME_HOST_
+
+# this is for left. exchange these values for right.
+MY_EXT=$SGW1_EXT
+MY_INT=$SGW1_INT
+PEER_EXT=$SGW2_EXT
+PEER_INT=$SGW2_INT
+INT_IF=eth1
+EXT_IF=eth0
+IPSEC_IF=ipsec0
+MY_LAN=$LAN1
+PEER_LAN=$LAN2
+
+$IPC -F
+$IPC -P input DENY
+$IPC -P forward DENY
+$IPC -P output DENY
+
+# Loopback traffic
+$IPC -A input -i lo -j ACCEPT
+$IPC -A output -i lo -j ACCEPT
+
+# for IPsec SGW1-SGW2
+## IKE
+$IPC -A input -p udp -s $PEER_EXT 500 -d $MY_EXT 500 -i $EXT_IF -j ACCEPT
+$IPC -A output -p udp -s $MY_EXT 500 -d $PEER_EXT 500 -i $EXT_IF -j ACCEPT
+## ESP
+$IPC -A input -p 50 -s $PEER_EXT -d $MY_EXT -i $EXT_IF -j ACCEPT
+### we don't need this line ### $IPC -A output -p 50 -s $MY_EXT -d $PEER_EXT -i $EXT_IF -j ACCEPT
+## forward LAN1-LAN2
+$IPC -A forward -s $MY_LAN -d $PEER_LAN -i $IPSEC_IF -j ACCEPT
+$IPC -A forward -s $PEER_LAN -d $MY_LAN -i $INT_IF -j ACCEPT
+$IPC -A output -s $PEER_LAN -d $MY_LAN -i $INT_IF -j ACCEPT
+$IPC -A input -s $PEER_LAN -d $MY_LAN -i $IPSEC_IF -j ACCEPT
+$IPC -A input -s $MY_LAN -d $PEER_LAN -i $INT_IF -j ACCEPT
+$IPC -A output -s $MY_LAN -d $PEER_LAN -i $IPSEC_IF -j ACCEPT
+
+# ICMP
+#
+## Dest unreachable
+### from/to Internet
+$IPC -A input -p icmp --icmp-type destination-unreachable -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type destination-unreachable -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### from/to Lan
+$IPC -A input -p icmp --icmp-type destination-unreachable -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type destination-unreachable -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### from/to Peer Lan
+$IPC -A input -p icmp --icmp-type destination-unreachable -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type destination-unreachable -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+#
+## Source quench
+### from/to Internet
+$IPC -A input -p icmp --icmp-type source-quench -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type source-quench -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### from/to Lan
+$IPC -A input -p icmp --icmp-type source-quench -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type source-quench -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### from/to Peer Lan
+$IPC -A input -p icmp --icmp-type source-quench -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type source-quench -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+#
+## Parameter problem
+### from/to Internet
+$IPC -A input -p icmp --icmp-type parameter-problem -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type parameter-problem -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### from/to Lan
+$IPC -A input -p icmp --icmp-type parameter-problem -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type parameter-problem -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### from/to Peer Lan
+$IPC -A input -p icmp --icmp-type parameter-problem -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type parameter-problem -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+#
+## Time To Live exceeded
+### from/to Internet
+$IPC -A input -p icmp --icmp-type time-exceeded -s $ANY -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type time-exceeded -s $MY_EXT -d $ANY -i $EXT_IF -j ACCEPT
+### to Lan
+$IPC -A input -p icmp --icmp-type time-exceeded -s $ANY -d $MY_INT -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type time-exceeded -s $MY_INT -d $ANY -i $INT_IF -j ACCEPT
+### to Peer Lan
+$IPC -A input -p icmp --icmp-type time-exceeded -s $ANY -d $MY_INT -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp --icmp-type time-exceeded -s $MY_INT -d $ANY -i $IPSEC_IF -j ACCEPT
+
+# ICMP PINGs
+## from Internet
+$IPC -A input -p icmp -s $ANY -d $MY_EXT --icmp-type echo-request -i $EXT_IF -j ACCEPT
+$IPC -A output -p icmp -s $MY_EXT -d $ANY --icmp-type echo-reply -i $EXT_IF -j ACCEPT
+## from LAN
+$IPC -A input -p icmp -s $ANY -d $MY_INT --icmp-type echo-request -i $INT_IF -j ACCEPT
+$IPC -A output -p icmp -s $MY_INT -d $ANY --icmp-type echo-reply -i $INT_IF -j ACCEPT
+## from Peer LAN
+$IPC -A input -p icmp -s $ANY -d $MY_INT --icmp-type echo-request -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p icmp -s $MY_INT -d $ANY --icmp-type echo-reply -i $IPSEC_IF -j ACCEPT
+
+# SSH
+## from SSH_PEER_HOST
+$IPC -A input -p tcp -s $SSH_PEER_HOST -d $MY_EXT 22 -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp \! -y -s $MY_EXT 22 -d $SSH_PEER_HOST -i $EXT_IF -j ACCEPT
+## to SSH_PEER_HOST
+$IPC -A input -p tcp \! -y -s $SSH_PEER_HOST 22 -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp -s $MY_EXT -d $SSH_PEER_HOST 22 -i $EXT_IF -j ACCEPT
+## from PEER
+$IPC -A input -p tcp -s $PEER_EXT -d $MY_EXT 22 -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp \! -y -s $MY_EXT 22 -d $PEER_EXT -i $EXT_IF -j ACCEPT
+## to PEER
+$IPC -A input -p tcp \! -y -s $PEER_EXT 22 -d $MY_EXT -i $EXT_IF -j ACCEPT
+$IPC -A output -p tcp -s $MY_EXT -d $PEER_EXT 22 -i $EXT_IF -j ACCEPT
+
+# ipxtunnel
+$IPC -A input -p udp -s $PEER_INT 2005 -d $MY_INT 2005 -i $IPSEC_IF -j ACCEPT
+$IPC -A output -p udp -s $MY_INT 2005 -d $PEER_INT 2005 -i $IPSEC_IF -j ACCEPT
+
+---------------- end of rc.firewall ----------------------
+
+To understand this we need to look on this scheme:
+
+ ++-----------------------&lt;----------------------------+
+ || ipsec0 |
+ \/ |
+ eth0 +--------+ /---------/ yes /---------/ yes +-----------------------+
+------&gt;| INPUT |--&gt;/ ?local? /-----&gt;/ ?IPsec? /-----&gt;| decrypt decapsulate |
+ eth1 +--------+ /---------/ /---------/ +-----------------------+
+ || no || no
+ \/ \/
+ +----------+ +---------+ +-------+
+ | routing | | local | | local |
+ | decision | | deliver | | send |
+ +----------+ +---------+ +-------+
+ || ||
+ \/ \/
+ +---------+ +----------+
+ | forward | | routing |
+ +---------+ | decision |
+ || +----------+
+ || ||
+ ++----------------&lt;-----------------++
+ ||
+ \/
+ +--------+ eth0
+ | OUTPUT | eth1
+ +--------+ ipsec0
+ ||
+ \/
+ /---------/ yes +-----------------------+
+ / ?IPsec? /-----&gt;| encrypt encapsulate |
+ /---------/ +-----------------------+
+ || no ||
+ || ||
+ || \/ eth0, eth1
+ ++-----------------------++--------------&gt;
+
+This explain how a packet traverse TCP/IP stack in IPsec capable kernel.
+
+FIX ME, please, if there are any errors
+
+Test the new firewall now.
+
+
+Now about IPX. I tried 3 programs for tunneling IPX: tipxd, SIB and ipxtunnel
+
+tipxd didn't send packets.. :(
+SIB and ipxtunnel worked fine :)
+With ipxtunnel there was a little problem. In sources there are an error.
+
+--------------------- in main.c ------------------------
+&lt; bytes += p.len;
+---
+&gt; bytes += len;
+--------------------------------------------------------
+
+After this FIX everything goes right...
+
+------------------- /etc/ipxtunnel.conf ----------------
+port 2005
+remote 192.168.101.97 2005
+interface eth1
+--------------- end of /etc/ipxtunnel.conf -------------
+
+I use IPX tunnel between .1.1 and .2.10 so we don't need to encrypt nor
+authenticate encapsulated IPX packets, it is done with IPsec.
+
+If you don't wont to use iproute2 to change source IP you need to use SIB
+(it is able to bind local address) or establish tunnel between .0.1 and
+.0.10 (external IPs, you need to do encryption in the program, but it isn't
+strong).
+
+For now I'm using ipxtunnel.
+
+I think that's all for the moment. If there are any error, please e-mail me:
+poltorak@df.ru . It would be cool if someone puts the scheme of TCP/IP in
+kernel and firewall example on FreeS/WAN's manual pages.
+
+PoltoS
+</PRE>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="background.html">Previous</A>
+<A HREF="makecheck.html">Next</A>
+</BODY>
+</HTML>
diff --git a/doc/utils/cleanhtml.sed b/doc/utils/cleanhtml.sed
new file mode 100644
index 000000000..59d3866b8
--- /dev/null
+++ b/doc/utils/cleanhtml.sed
@@ -0,0 +1 @@
+/<STYLE>/,/<\/STYLE>/d
diff --git a/doc/utils/cleanhtml.sh b/doc/utils/cleanhtml.sh
new file mode 100755
index 000000000..a3ea2afac
--- /dev/null
+++ b/doc/utils/cleanhtml.sh
@@ -0,0 +1,12 @@
+# script to clean up HTML files
+# removes formatting added by htmldoc
+#
+# first argument is sedscript to use
+f=$1
+shift
+# remaining args are files to process
+for i
+do
+ sed -f $f $i > tmp
+ mv tmp $i
+done
diff --git a/doc/utils/contents.awk b/doc/utils/contents.awk
new file mode 100644
index 000000000..5cc07f246
--- /dev/null
+++ b/doc/utils/contents.awk
@@ -0,0 +1,109 @@
+# table-of-contents extractor
+# Copyright (C) 1999 Sandy Harris.
+#
+# 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: contents.awk,v 1.1 2004/03/15 20:35:24 as Exp $
+BEGIN {
+ # initialise indent counter
+ indent = 0
+ # define variables for section breaks
+ b0 = "==================================================="
+ b1 = "---------------------------------------------------"
+ b2 = "\t------------------------------------------"
+ # TURN OFF HTML formatting
+ print "<html>"
+ print "<body>"
+ print "<pre>"
+ # print a header
+ blurb()
+ print "Section headings printed, indentation shows structure"
+}
+# start of new file
+FNR == 1 {
+ print b0
+ print "HTML file: " "<a href=\"" FILENAME "\">" FILENAME "</a>"
+ print b1
+}
+# print header lines
+# actual printing is done by tagged() function
+# which adds tag if last line was <a name=...>
+$0 ~/<h1>/ {
+ text = $0
+ tabs = ""
+ gsub(/.*<h1>/, "", text)
+ gsub(/<\/h1>/, "", text)
+ tagged( text )
+}
+$0 ~/<h2>/ {
+ text = $0
+ tabs = "\t"
+ gsub(/.*<h2>/, "", text)
+ gsub(/<\/h2>/, "", text)
+ tagged(text)
+}
+$0 ~/<h3>/ {
+ text = $0
+ tabs = "\t\t"
+ gsub(/.*<h3>/, "", text)
+ gsub(/<\/h3>/, "", text)
+ tagged(text)
+}
+$0 ~/<h4>/ {
+ text = $0
+ tabs = "\t\t\t"
+ gsub(/.*<h4>/, "", text)
+ gsub(/<\/h4>/, "", text)
+ tagged( text )
+}
+# if current line is not header
+# and we have stored tag from <a name=..> line
+# make link to that tag
+$0 !~ /<h[1-4]/ {
+ if( length(name) )
+ print "[ <a href=\"" FILENAME "#" name "\">" name "</a>" " ]"
+ name = ""
+}
+# for <a name=whatever> lines
+# save name in a variable
+# not printed until we see next line
+$0 ~ /<a name=.*>/ {
+ name = $0
+ # strip anything before or after name tag
+ gsub(/.*<a name=/, "", name)
+ gsub(/>.*/, "", name)
+ # strip quotes off name
+ gsub(/^"/, "", name)
+ gsub(/"$/, "", name)
+}
+END {
+ print b0
+ blurb()
+ print "Docs & script by Sandy Harris"
+ print "</pre>"
+ print "</body>"
+ print "</html>"
+}
+
+function tagged(text) { # print header with tag if available
+ if( length(name) ) # > 0 if previous line was a name
+ print tabs "<a href=\"" FILENAME "#" name "\">" text "</a>"
+ else
+ print tabs text
+ name = ""
+}
+
+function blurb() {
+ print "Linux FreeSWAN HTML documents"
+ print "Automatically generated Table of Contents"
+ print "Bug reports to the mailing list: linux-ipsec@clinet.fi"
+ print "<p>"
+}
diff --git a/doc/utils/four2perm.1 b/doc/utils/four2perm.1
new file mode 100644
index 000000000..1e5263b5b
--- /dev/null
+++ b/doc/utils/four2perm.1
@@ -0,0 +1,20 @@
+.TH FOUR2PERM 1 "August 1999"
+.\" RCSID $Id: four2perm.1,v 1.1 2004/03/15 20:35:24 as Exp $
+.SH NAME
+four2perm - generate permuted index from four-field lines
+.SH SYNOPSIS
+.B four2perm
+.SH DESCRIPTION
+.I four2perm
+expects input lines with four tab-separated fields, such as that
+created from HTML files by html2four(1). Given that, it does most
+of the work of generating a permuted index, gets things close
+enough that a simple pipeline through sort(1) and awk(1) can
+finish the job.
+.SH SEE ALSO
+.hy 0
+html2four(1)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.xs4all.nl/~freeswan/>
+by Sandy Harris.
diff --git a/doc/utils/four2perm.c b/doc/utils/four2perm.c
new file mode 100644
index 000000000..5b575c1b5
--- /dev/null
+++ b/doc/utils/four2perm.c
@@ -0,0 +1,140 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#define MAX_LINE 512
+
+void die( char * ) ;
+
+char buffer[MAX_LINE+1] ;
+char *prog_name ;
+
+void die( char *message )
+{
+ fflush(stdout) ;
+ fprintf(stderr, "%s: %s\n", prog_name, message) ;
+ exit(1) ;
+}
+
+int main(int argc, char* argv[])
+{
+ int errors ;
+ prog_name = *argv ;
+ if( argc != 1 )
+ die("pure filter, takes no arguments") ;
+ errors = 0 ;
+ while( fgets(buffer, MAX_LINE, stdin))
+ errors += do_line(buffer) ;
+ exit(errors ? 1 : 0 ) ;
+}
+
+int do_line(char *data)
+{
+ char *p, *q, *r, *end, *before, *after ;
+ // expecting two tab-separated fields
+ // point r to 2nd, null terminate 1st
+ for( r = data ; *r && *r != '\t' ; r++ )
+ ;
+ if( *r != '\t' )
+ return(1) ;
+ end = r++ ;
+ *end = '\0' ;
+ for( q = r ; *q ; q++ )
+ if( *q == '\n' )
+ *q = '\0' ;
+ if( !strlen(r) )
+ return(1) ;
+ // within 1st, parse as space-separated
+ // p will point to current word, q past its end
+ // before & after point to rest of text
+ // spaces converted to nulls & back as req'd
+ before = "" ;
+ for( p = data ; p < end ; p = q + 1 ) {
+ if( p > data ) {
+ before = data ;
+ p[-1] = '\0' ;
+ }
+ // find end of word
+ for( q = p ; *q && *q != ' ' ; q++ )
+ ;
+ if( q == end )
+ after = "" ;
+ else if( q < end ) {
+ after = q + 1 ;
+ *q = '\0' ;
+ }
+ else assert(0) ;
+ print_line(before, p, after, r) ;
+ if( q < end )
+ *q = ' ' ;
+ if( p > data )
+ p[-1] = ' ' ;
+ }
+ return(0) ;
+}
+
+// print formatted line for permuted index
+// two tab-separated fields
+// 1st is sort key
+// 2nd is printable line
+// pipe it through something like
+// sort -F | awk -F '\t' '{print $2}'
+// to get final output
+
+print_line( char *before, char *word, char *after, char *tag)
+{
+ int i , x, y, z ;
+/*
+ printf("%s\t%s\t%s\t%s\n", before, word, after, tag) ;
+*/
+ if( list_word(word) )
+ return ;
+ x = strlen(before) ;
+ y = strlen(word) ;
+ z = strlen(after) ;
+ // put in sortable field
+ // strip out with awk after sorting
+ printf("%s %s\t", word, after) ;
+ // shorten before string to fit field
+ for( ; x > 30 ; x-- )
+ before++ ;
+ printf("%30s", before) ;
+ // print keyword, html tagged
+ printf(" %s%s</a> ", tag, word) ;
+ // padding, outside tag
+ for( ; y < 18 ; y++ )
+ putchar(' ') ;
+ if( z )
+ printf("%s", after) ;
+ printf("\n") ;
+}
+
+// avoid indexing on common English words
+
+char *list[] = {
+ "the", "of", "a", "an", "to", "and", "or", "if", "for", "at",
+ "am", "is", "are", "was", "were", "have", "has", "had", "be", "been",
+ "on", "some", "with", "any", "into", "as", "by", "in", "out",
+ "that", "then", "this", "that", "than", "these", "those",
+ "he", "his", "him", "she", "her", "hers", "it", "its",
+ "&", "", "+", "-", "=", "--", "<", ">", "<=", ">=",
+ "!", "?", "#", "$", "%", "/", "\\", "\"", "\'",
+ NULL
+ } ;
+// interrogative words like "how" and "where" deliberately left out of
+// above list because users might want to search for "how to..." etc.
+
+// return 1 if word in list, else 0
+// case-insensitive comparison
+
+list_word( char *p )
+{
+ char **z ;
+ for( z = list ; *z != NULL ; z++ )
+ if( ! strcasecmp( p, *z ) )
+ return 1 ;
+ return 0 ;
+}
+
diff --git a/doc/utils/html2four.1 b/doc/utils/html2four.1
new file mode 100644
index 000000000..456ac5e98
--- /dev/null
+++ b/doc/utils/html2four.1
@@ -0,0 +1,26 @@
+.TH HTML2FOUR 1 "August 1999"
+.\" RCSID $Id: html2four.1,v 1.1 2004/03/15 20:35:24 as Exp $
+.SH NAME
+html2four - extract headers from HTML files into four-field lines
+.SH SYNOPSIS
+.B html2four
+[-digit] file*
+command [ argument ...]
+.SH DESCRIPTION
+.I html2four
+extracts information from HTML files and writes it out with four
+tab-separated fields: filename, last label (<a name=> tag) seen,
+header tag type (H[0-9]), and header text. This is an intermediate
+format convenient for generating a permuted index with four2perm(1)
+or a table of contents with a simple awkscript.
+
+The only option is a digit to limit the header levels extracted.
+For example, with -3 only h1, h2, h3 tags are taken. By default,
+it takes h[0-9], though HTML only defines levels 1 to 6.
+.SH SEE ALSO
+.hy 0
+four2perm(1)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.xs4all.nl/~freeswan/>
+by Sandy Harris.
diff --git a/doc/utils/html2four.c b/doc/utils/html2four.c
new file mode 100644
index 000000000..fc1100d01
--- /dev/null
+++ b/doc/utils/html2four.c
@@ -0,0 +1,298 @@
+/*
+ extract headers from HTML files
+ in format suitable for turning into permuted index
+*/
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ maximum sizes for input line and for name in <a> tag
+*/
+#define MAX_LINE 512
+#define MAX_NAME 64
+
+/*
+ functions
+ all return 0 for OK, 1 for errors
+*/
+int do_file( char *, FILE * ) ;
+int parse_line( char * ) ;
+int print_line( char *, char *) ;
+int print_header_problem( char * ) ;
+int sanity() ;
+
+void die( char * ) ;
+
+char *prog_name ;
+int max_level ;
+char *current_file ;
+
+int main(int argc, char* argv[])
+{
+ char *p ;
+ int temp, done, status ;
+ FILE *fp ;
+
+ prog_name = *argv ;
+ argc--,argv++ ;
+
+ max_level = 9 ;
+ if(argc && *argv ) {
+ p = *argv ;
+ if( p[0] == '-' ) {
+ if( isdigit(p[1]) && p[2] == '\0' ) {
+ max_level = p[1] - 0 ;
+ argc-- ;
+ argv++ ;
+ }
+ else die("unknown option") ;
+ } }
+
+ status = done = 0 ;
+ if( argc == 0) {
+ if( (status = do_file("STDIN", stdin)) == 0 )
+ done++ ;
+ }
+ else {
+/*
+ printf("ARGC = %d\n", argc ) ;
+*/
+ while( argc-- ) {
+ p = *argv++ ;
+/*
+ printf("ARGV P %s %s\n", *argv, p) ;
+*/
+ if( p == NULL ) {
+ fprintf(stderr, "%s: null filename pointer\n", prog_name) ;
+ status++ ;
+ }
+ else if( (fp = fopen(p,"r")) == NULL ) {
+ fprintf(stderr, "%s: cannot open file %s\n", prog_name, p) ;
+ status++ ;
+ }
+ else {
+ if( (temp = do_file(p, fp)) != 0 )
+ status++ ;
+ done++ ;
+ fclose(fp) ;
+ }
+ fflush(stderr) ;
+ fflush(stdout) ;
+ }
+ }
+/*
+ printf("%s: %d files processed, %d with errors\n", prog_name, done, status) ;
+*/
+ return( status ? 1 : 0 ) ;
+}
+
+void die( char *message )
+{
+ fflush(stdout) ;
+ fprintf(stderr, "%s: %s\n", prog_name, message) ;
+ exit(1) ;
+}
+
+int header_flags[10] ;
+int in_header ;
+
+char buffer[MAX_LINE+1] ;
+char label[MAX_NAME+1] ;
+
+int do_file( char *file, FILE *fp )
+{
+ int i, status, x, y ;
+ char *base, *p ;
+
+ status = 0 ;
+ in_header = 0 ;
+ label[0] = '\0' ;
+ for( i = 0 ; i < 10 ; i++ )
+ header_flags[i] = 0 ;
+ current_file = file ;
+
+ while( base = fgets(buffer, MAX_LINE, fp) ) {
+ // count < and > characters in line
+ for( x = y = 0, p = base ; *p ; p++ )
+ switch( *p ) {
+ case '<':
+ x++ ;
+ break ;
+ case '>':
+ y++ ;
+ break ;
+ default:
+ break ;
+ }
+ // skip line if no < or >
+ if( x == 0 && y == 0 )
+ continue ;
+ // report error for unequal count
+ else if( x != y ) {
+ if( strncmp( base, "<!--", 4) && strncmp(base, "-->", 3) ) {
+ fflush(stdout) ;
+ fprintf(stderr, "%s in file %s: unequal < > counts %d %d\n",
+ prog_name, file, x, y ) ;
+ fprintf(stderr, "%s: %s\n", prog_name, base) ;
+ fflush(stderr) ;
+ status = 1 ;
+ }
+ continue ;
+ }
+ // parse lines containing tags
+ else
+ if( parse_line(base) )
+ status = 1 ;
+ // check that header labelling is sane
+ for( i = x = y = 0 ; i < 10 ; i++ ) {
+ // count non-zero entries
+ if( x = header_flags[i] )
+ y++ ;
+ // should be in 0 or 1 headers at a time
+ if( x > 1 || x < 0 )
+ status = 1 ;
+ }
+ if( y > 1 )
+ status = 1 ;
+ }
+ return status ;
+}
+
+int parse_line( char *data )
+{
+ char *p, *q, *end ;
+ int x ;
+
+ // set end pointer
+ for( end = data ; *end ; end++ )
+ ;
+ // trim off trailing returns or newlines
+ for( p = end - 1, q = end ; q > data ; p--,q-- ) {
+ switch( *p ) {
+ case '\012':
+ case '\015':
+ *p = '\0' ;
+ continue ;
+ default:
+ break ; // out of switch()
+ }
+ break ; // out of for()
+ }
+ end = q ;
+ p = data ;
+ while( p < end ) {
+ // find tag delimiters
+ if( *p == '<') {
+ for( q = p + 1 ; *q ; q++ )
+ if( *q == '<' || *q == '>' )
+ break ;
+ // if we find another '<'
+ // restart tag search from it
+ if( *q == '<' ) {
+ p = q ;
+ continue ;
+ }
+ // "<>" is not interesting
+ if( q == p + 1 ) {
+ fflush(stdout) ;
+ fprintf(stderr, "%s: null tag\n", prog_name) ;
+ fprintf(stderr, "%s: line\n", prog_name, data) ;
+ fflush(stderr) ;
+ p = q + 1 ;
+ continue ;
+ }
+ // ignore delimiters once found
+ *q = '\0' ;
+ p++ ;
+ // p points to tag contents, null terminated
+ switch( *p ) {
+ // save contents of <a name= > tags
+ case 'a' :
+ case 'A' :
+ if( p[1] == ' ' &&
+ (p[2] == 'n' || p[2] == 'N') &&
+ (p[3] == 'a' || p[3] == 'A') &&
+ (p[4] == 'm' || p[4] == 'M') &&
+ (p[5] == 'e' || p[5] == 'E') &&
+ p[6] == '=' )
+ strncpy(label, p + 7, MAX_NAME) ;
+ break ;
+ case 'b' :
+ case 'B' :
+ if( in_header && strlen(p) == 2 &&
+ (p[1] == 'r' || p[1] == 'R') )
+ putchar(' ') ;
+ break ;
+ // header tags
+ case 'h' :
+ case 'H' :
+ if( strlen(p) == 2 && isdigit(p[1]) ) {
+ if( in_header )
+ fprintf(stderr, "%s: bad header nesting in %s\n",
+ prog_name, current_file) ;
+ x = p[1] - '0' ;
+ in_header = 1 ;
+ header_flags[x]++ ;
+ printf("%s\t%s\tH%d\t", current_file, label, x) ;
+ }
+ break ;
+ // only care about end-of-header
+ case '/':
+ p++ ;
+ switch( *p ) {
+ case 'h' :
+ case 'H' :
+ if( strlen(p) == 2 && isdigit(p[1]) ) {
+ if( ! in_header )
+ fprintf(stderr, "%s: bad header nesting in %s\n",
+ prog_name, current_file) ;
+ x = p[1] - '0' ;
+ in_header = 0 ;
+ header_flags[x]-- ;
+ printf("\n") ;
+ }
+ break ;
+ }
+ break ;
+ // uninteresting tag, look for next
+ default :
+ break ;
+ }
+ // tag done, point p beyond it
+ p = q + 1 ;
+ }
+ else if( in_header ) {
+ if( isprint(*p) && *p != '\n' )
+ putchar(*p) ;
+ else
+ putchar(' ');
+ p++ ;
+ }
+ else
+ p++ ;
+ }
+ return(0) ;
+}
+
+int print_line( char *tag, char *text)
+{
+ printf("%%s\ts\t%s\t%s\t\n", current_file, label, tag, text) ;
+ return 0 ;
+}
+
+int print_header_problem( char *file )
+{
+ int i ;
+ fflush(stdout) ;
+ fprintf(stderr, "%s: HEADER TAG PROBLEM in file %s\n", prog_name, file) ;
+ fprintf(stderr, "%s: counts", prog_name) ;
+ for ( i = 0 ; i < 10 ; i++ )
+ fprintf(stderr, "\t%d", i) ;
+ fprintf(stderr,"\n") ;
+ fflush(stderr) ;
+ return(0) ;
+}
+
diff --git a/doc/utils/html2txt.sed b/doc/utils/html2txt.sed
new file mode 100644
index 000000000..fc4940991
--- /dev/null
+++ b/doc/utils/html2txt.sed
@@ -0,0 +1,86 @@
+# skip over header material
+# Copyright (C) 1999 Sandy Harris.
+#
+# 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: html2txt.sed,v 1.1 2004/03/15 20:35:24 as Exp $
+/<head>/,/<\/head>/d
+/<HEAD>/,/<\/HEAD>/d
+/<^body$>/d
+s/<body>//
+# eliminate possible DOS crud
+s/\015//
+#get rid of HTML comments
+s/<!--.*-->//
+/<!--/,/-->/d
+# citations & emphasis -> visible
+s/<cite>/"/g
+s/<\/cite>/"/g
+s/<em>/*/g
+s/<\/em>/*/g
+s/<strong>/!->/g
+s/<\/strong>/<-!/g
+s/<b>//g
+s/<\/b>//g
+s/<blockquote>/Quote -->/
+s/<\/blockquote>/<-- End Quote/
+# mark headers
+s/<h1>/Header 1: /
+s/<h2>/Header 2: /
+s/<h3>/Header 3: /
+s/<h4>/Header 4: /
+s/<h5>/Header 5: /
+s/<h6>/Header 6: /
+# remove some cruft
+s/<\/h[1-6]>//
+/^<a name=[a-zA-Z0-9\.]*>$/d
+s/<a name=[a-zA-Z0-9\.]*>//
+# definition lists
+s/<dl>//
+s/<\/dl>//
+s/^<dt>$/-----------------------------------------/
+s/^<dt>/-----------------------------------------\
+/
+s/<dd>/\
+/
+# other types of lists
+s/<li>//
+s/<ol>//
+s/<ul>//
+s/<\/ol>//
+s/<\/ul>//
+# tables
+s/<table>//
+s/<\/table>//
+s/<tr>//
+s/<td>/ /g
+# line break and paragraph markers
+# different subst depending where they are in line
+s/^<br>//
+s/<br>$//
+s/<br>/\
+/
+s/^<p>$//
+s/<p>$/\
+/
+s/^<p>/\
+/
+s/<p>/\
+\
+/
+s/<\/p>//
+# remove more cruft
+s/<pre>//
+s/<\/pre>//
+s/<\/body>//
+s/<\/html//
+s/<\/BODY>//
+s/<\/HTML>//
diff --git a/doc/utils/killtoodeepcontents.pl b/doc/utils/killtoodeepcontents.pl
new file mode 100644
index 000000000..a6fe551d6
--- /dev/null
+++ b/doc/utils/killtoodeepcontents.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+
+$toc=0;
+$memo=0;
+
+while(<>) {
+ if(0 && /^Status of this Memo/) {
+ $memo=1;
+ print;
+ next;
+ }
+
+ if(/^Table of Contents/) {
+ print ".bp\n";
+ $toc=1;
+ print;
+ next;
+ }
+
+ if(!$toc && !$memo) {
+ print;
+ next;
+ }
+
+ if($toc) {
+ if(/^[0-9]*\.[0-9]*\.[0-9]* / ||
+# /^[0-9]*\.[0-9]* / ||
+ /^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]* /) {
+ next;
+ }
+
+ if(/^14./) {
+ $toc=0;
+ }
+ if(/^\.bp/) {
+ next;
+ }
+ print;
+ }
+
+ if($memo) {
+ if(/^\.bp/) {
+ next;
+ }
+
+ if(/^Copyright Notice/) {
+ print ".fi\n";
+ print "This memo provides information for the Internet community. It does\n";
+ print "not specify an Internet standard of any kind. Distribution of this\n";
+ print "memo is unlimited.\n";
+ print "\n.ti 0\n";
+
+ print;
+
+ $memo=0;
+ next;
+ }
+ }
+}
diff --git a/doc/utils/man2html.script b/doc/utils/man2html.script
new file mode 100755
index 000000000..515911c81
--- /dev/null
+++ b/doc/utils/man2html.script
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+# Assumes man2html command in path
+# That is a Perl script downloadable from
+# http://www.oac.uci.edu/indiv/ehood/man2html.html
+
+# also uses our man_xref utility
+
+case $# in
+2) ;;
+*) echo "Usage: $0 mantree destdir" >&2 ; exit 2 ;;
+esac
+
+mkdir -p $2
+rm -f $2/*
+
+# handle all sections just in case
+# only 3 5 8 expected
+for i in `find $1 -name 'ipsec*.[1-9]'`
+do
+ b=`basename $i`
+ # then parse that into section number s
+ # and name n
+ case $b in
+ *.1) s=1 ;;
+ *.2) s=2 ;;
+ *.3) s=3 ;;
+ *.4) s=4 ;;
+ *.5) s=5 ;;
+ *.6) s=6 ;;
+ *.7) s=7 ;;
+ *.8) s=8 ;;
+ *.9) s=9 ;;
+ *) echo "$0 has lost its mind" ; exit 1 ;;
+ esac
+ n=`basename $b \.$s`
+ # the echos are a kluge
+ # without them, the first section head is not tagged
+ (echo ; echo ; man $s $n ) | man2html > $2/$b.html
+done
+# man2html doesn't convert man page cross-references such as
+# ipsec.conf(5) into HTML links
+# So post-process to do that.
+for i in $2/*.html
+do
+ ../utils/man_xref $i > temp
+ mv temp $i
+done
diff --git a/doc/utils/man_xref.c b/doc/utils/man_xref.c
new file mode 100644
index 000000000..fc3afb696
--- /dev/null
+++ b/doc/utils/man_xref.c
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+
+/*
+ look through HTMLized man pages
+ convert references like man(1) into HTML links
+
+ somewhat quick & dirty code
+ various dubious assumptions made:
+
+ [a-zA-Z0-9\-_\.]* defines legal characters in name
+ pagename(x) corresponds to pagename.x.html
+ (Fine *if* it's been converted by my scripts)
+ x in the above must be a single digit
+ (or we ignore it, which does no damage)
+ Lazy parsing: malloc() enough RAM to read in whole file
+ Limited syntax: exactly one input file, results to stdout
+
+ Sandy Harris
+*/
+
+int do_file( char *, char *) ;
+
+main(int argc, char **argv)
+{
+ FILE *in ;
+ char *progname;
+ long lsize ;
+ size_t size, nread;
+ char *buffer, *bufend ;
+ progname = *argv ;
+ if( argc != 2 ) {
+ fprintf(stderr,"usage: %s input-file\n", progname);
+ exit(1) ;
+ }
+ if( (in = fopen(argv[1],"r")) == NULL ) {
+ fprintf(stderr,"%s Can't open input file\n", progname);
+ exit(2) ;
+ }
+ if( (lsize = fseek(in, 0L, SEEK_END)) < 0L ) {
+ fprintf(stderr,"%s fseek() fails\n", progname);
+ exit(3) ;
+ }
+ lsize = ftell(in) ;
+ rewind(in) ;
+ size = (size_t) lsize ;
+ if( lsize != (long) size ) {
+ fprintf(stderr,"%s file too large\n", progname);
+ exit(4) ;
+ }
+ if( (buffer = (char *) malloc(size)) == NULL) {
+ fprintf(stderr,"%s malloc() failed\n", progname);
+ exit(5) ;
+ }
+ bufend = buffer + size ;
+ if( (nread = fread(buffer, size, 1, in)) != 1) {
+ fprintf(stderr,"%s fread() failed\n", progname);
+ exit(6) ;
+ }
+ do_file(buffer,bufend);
+}
+
+do_file(char *start, char *end)
+{
+ /* p is where to start parsing, one past last output */
+ /* q is how far we've parsed */
+ char *p, *q ;
+ int value ;
+ for( p = q = start ; p < end ; q = (q<end) ? (q+1) : q ) {
+ /* if p is beyond q, catch up */
+ if( q < p )
+ continue ;
+ /* move q ahead until we know if we've got manpage name */
+ if( isalnum(*q) )
+ continue ;
+ switch(*q) {
+ /* can appear in manpage name */
+ case '.':
+ case '_':
+ case '-':
+ case '(':
+ continue ;
+ break ;
+ /* whatever's between p and q
+ is not a manpage name
+ so output it
+ */
+ default:
+ /* leave p one past output */
+ for( ; p <= q ; p++ )
+ putchar(*p);
+ break ;
+ /* we may have a manpage name */
+ case ')':
+ value = do_name(p,q);
+ if(value) {
+ p = q ;
+ p++ ;
+ }
+ /* unreached with current do_name() */
+ else
+ for( ; p <= q ; p++ )
+ putchar(*p);
+ break ;
+} } }
+
+do_name(char *p, char *q)
+{
+ *q = '\0' ;
+ /* if end of string matches RE ([0-9])
+ with at least one legal character before it
+ add HTML xref stuff
+ */
+ if( (q-p > 3) && isdigit(q[-1]) && (q[-2]=='(')) {
+ q[-2] = '\0' ;
+ q-- ;
+ printf("<a href=\"%s.%s.html\">", p, q);
+ printf("%s(%s)", p, q);
+ printf("</a>");
+ }
+ // otherwise just print string
+ else printf("%s)", p);
+ return 1 ;
+}
diff --git a/doc/utils/mkhtmlman b/doc/utils/mkhtmlman
new file mode 100755
index 000000000..6d73bd1f2
--- /dev/null
+++ b/doc/utils/mkhtmlman
@@ -0,0 +1,44 @@
+#!/bin/sh
+# gathers manpages up into dir, converts them to HTML, including interlinking
+# Assumes RedHat6.0 man2html available.
+
+PATH=/usr/local/bin:/bin:/usr/bin:/usr/contrib/bin:$PATH ; export PATH
+
+# note, this is always run from freeswan/doc.
+
+TOPDIR=..
+
+case $# in
+1) exit 0 ;;
+0) echo "Usage: $0 destdir manpage ..." >&2 ; exit 1 ;;
+esac
+
+dir=$1
+shift
+mkdir -p $dir
+rm -f $dir/*
+
+for f
+do
+ b=`basename $f`
+ case $b in
+ ipsec*) ;; # ipsec.8, ipsec.conf.5, etc.
+ *) b="ipsec_$b" ;;
+ esac
+ cp $f $dir/$b
+ $TOPDIR/packaging/utils/manlink $f | while read from to
+ do
+ (cd $dir; ln -s ../$f $to)
+ done
+done
+
+# build the html (sed mess fixes overly-smart man2html's crud)
+refpat='"http://localhost/cgi-bin/man/man2html?\([1-8]\)+\([^"]*\)"'
+for f in $dir/*.[1-8]
+do
+ echo Processing $f
+ man2html <$f | sed 's;'"$refpat"';"\2.\1.html";g' >$f.html
+done
+
+# remove the source files (must wait until after all builds, due to symlinks)
+rm -f $dir/*.[1-8]
diff --git a/doc/utils/perm1.awk b/doc/utils/perm1.awk
new file mode 100644
index 000000000..d9f8f5565
--- /dev/null
+++ b/doc/utils/perm1.awk
@@ -0,0 +1 @@
+{ print $4 "\t<a href=\"" $1 "#" $2 "\">" }
diff --git a/doc/utils/perm2.awk b/doc/utils/perm2.awk
new file mode 100644
index 000000000..3c55fef11
--- /dev/null
+++ b/doc/utils/perm2.awk
@@ -0,0 +1,46 @@
+BEGIN {
+ print "<html>\n<body>"
+ print "<h2>Permuted Index of HTML headers in FreeS/WAN documents</h2>"
+ print "<h3>Jump to a letter</h3>"
+ print "<center><big><strong>"
+ print "<a href=\"#0\">numeric</a>"
+ print "<a href=\"#a\">A</a>"
+ print "<a href=\"#b\">B</a>"
+ print "<a href=\"#c\">C</a>"
+ print "<a href=\"#d\">D</a>"
+ print "<a href=\"#e\">E</a>"
+ print "<a href=\"#f\">F</a>"
+ print "<a href=\"#g\">G</a>"
+ print "<a href=\"#h\">H</a>"
+ print "<a href=\"#i\">I</a>"
+ print "<a href=\"#j\">J</a>"
+ print "<a href=\"#k\">K</a>"
+ print "<a href=\"#l\">L</a>"
+ print "<a href=\"#m\">M</a>"
+ print "<a href=\"#n\">N</a>"
+ print "<a href=\"#o\">O</a>"
+ print "<a href=\"#p\">P</a>"
+ print "<a href=\"#q\">Q</a>"
+ print "<a href=\"#r\">R</a>"
+ print "<a href=\"#s\">S</a>"
+ print "<a href=\"#t\">T</a>"
+ print "<a href=\"#u\">U</a>"
+ print "<a href=\"#v\">V</a>"
+ print "<a href=\"#w\">W</a>"
+ print "<a href=\"#x\">X</a>"
+ print "<a href=\"#y\">Y</a>"
+ print "<a href=\"#z\">Z</a>"
+ print "</strong></big></center>"
+ print "<hr>"
+ print "<pre>"
+ print "<a name=0>"
+ old =""
+ }
+{ x = tolower(substr($1,1,1))
+ if( (x ~ /[a-zA-Z]/) && (x != old) )
+ print "<a name=" x ">" $2
+ else
+ print $2
+ old = x
+ }
+END { print "</pre>\n</html>" }
diff --git a/doc/utils/rfc_pg.c b/doc/utils/rfc_pg.c
new file mode 100644
index 000000000..448cc1a36
--- /dev/null
+++ b/doc/utils/rfc_pg.c
@@ -0,0 +1,76 @@
+/*
+ * $Header: /var/cvsroot/strongswan/doc/utils/rfc_pg.c,v 1.1 2004/03/15 20:35:24 as Exp $
+ *
+ * from 2-nroff.template file.
+ *
+ * Remove N lines following any line that contains a form feed (^L).
+ * (Why can't this be done with awk or sed?)
+ *
+ * OPTION:
+ * -n# Number of lines to delete following each ^L (0 default).
+ * $Log: rfc_pg.c,v $
+ * Revision 1.1 2004/03/15 20:35:24 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.1 2002/07/23 18:42:43 mcr
+ * required utility from IETF to help with formatting of drafts.
+ *
+ */
+#include <stdio.h>
+
+#define FORM_FEED '\f'
+#define OPTION "n:N:" /* for getopt() */
+
+extern char *optarg;
+extern int optind;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int c, /* next input char */
+ nlines = 0; /* lines to delete after ^L */
+ void print_and_delete(); /* print line starting with ^L,
+ then delete N lines */
+
+/*********************** Process option (-nlines) ***********************/
+
+ while ((c = getopt(argc, argv, OPTION)) != EOF)
+ switch(c)
+ {
+ case 'n' :
+ case 'N' : nlines = atoi(optarg);
+ break;
+ }
+/************************* READ AND PROCESS CHARS **********************/
+
+ while ((c = getchar()) != EOF)
+ if (c == FORM_FEED)
+ print_and_delete(nlines); /* remove N lines after this one */
+ else
+ putchar(c); /* we write the form feed */
+ exit(0);
+}
+
+
+/*
+ * Print rest of line, then delete next N lines.
+ */
+void print_and_delete(n)
+int n; /* nbr of lines to delete */
+{
+ int c, /* next input char */
+ cntr = 0; /* count of deleted lines */
+
+ while ((c = getchar()) != '\n') /* finish current line */
+ putchar(c);
+ putchar('\n'); /* write the last CR */
+ putchar(FORM_FEED);
+
+ for ( ; cntr < n; cntr++)
+ while ((c = getchar()) != '\n')
+ if (c == EOF)
+ exit(0); /* exit on EOF */
+ putchar(c); /* write that last CR */
+}
+
diff --git a/doc/utils/xref.sed b/doc/utils/xref.sed
new file mode 100644
index 000000000..8c3b442cc
--- /dev/null
+++ b/doc/utils/xref.sed
@@ -0,0 +1,56 @@
+# turn end-of xref tags into <*>
+# Copyright (C) 1999 Sandy Harris.
+#
+# 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: xref.sed,v 1.1 2004/03/15 20:35:24 as Exp $
+s/<\/a>/<*>/g
+# delete all xrefs that point
+# within our document set
+s/<a href="..\/Internet-docs\/rfc....\.txt">//
+# in same doc
+s/<a href="#[a-zA-Z0-9\.]*">//
+# pointer into another doc
+s/<a href="DES.html#[a-zA-Z0-9\.]*">//
+s/<a href="RFCs.html#[a-zA-Z0-9\.]*">//
+s/<a href="WWWref.html#[a-zA-Z0-9\.]*">//
+s/<a href="bibliography.html#[a-zA-Z0-9\.]*">//
+s/<a href="compatibility.html#[a-zA-Z0-9\.]*">//
+s/<a href="configuration.html#[a-zA-Z0-9\.]*">//
+s/<a href="contents.html#[a-zA-Z0-9\.]*">//
+s/<a href="debugging.html#[a-zA-Z0-9\.]*">//
+s/<a href="exportlaws.html#[a-zA-Z0-9\.]*">//
+s/<a href="glossary.html#[a-zA-Z0-9\.]*">//
+s/<a href="index.html#[a-zA-Z0-9\.]*">//
+s/<a href="overview.html#[a-zA-Z0-9\.]*">//
+s/<a href="roadmap.html#[a-zA-Z0-9\.]*">//
+s/<a href="testbed.html#[a-zA-Z0-9\.]*">//
+s/<a href="setup.html#[a-zA-Z0-9\.]*">//
+# pointer to head of doc
+s/<a href="DES.html">//
+s/<a href="RFCs.html">//
+s/<a href="WWWref.html">//
+s/<a href="bibliography.html">//
+s/<a href="compatibility.html">//
+s/<a href="configuration.html">//
+s/<a href="contents.html">//
+s/<a href="debugging.html">//
+s/<a href="exportlaws.html">//
+s/<a href="glossary.html">//
+s/<a href="index.html">//
+s/<a href="overview.html">//
+s/<a href="roadmap.html">//
+s/<a href="testbed.html">//
+s/<a href="setup.html">//
+# xref to non-HTML files
+s/<a href="standards">//
+s/<a href="impl.notes">//
+s/<a href="prob.report">//
diff --git a/doc/web.html b/doc/web.html
new file mode 100644
index 000000000..0c084d289
--- /dev/null
+++ b/doc/web.html
@@ -0,0 +1,749 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>Introduction to FreeS/WAN</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+H1 { font-family: sans-serif }
+H2 { font-family: sans-serif }
+H3 { font-family: sans-serif }
+H4 { font-family: sans-serif }
+H5 { font-family: sans-serif }
+H6 { font-family: sans-serif }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<A HREF="toc.html">Contents</A>
+<A HREF="mail.html">Previous</A>
+<A HREF="glossary.html">Next</A>
+<HR>
+<H1><A name="weblink">Web links</A></H1>
+<H2><A name="freeswan">The Linux FreeS/WAN Project</A></H2>
+<P>The main project web site is<A href="http://www.freeswan.org/">
+ www.freeswan.org</A>.</P>
+<P>Links to other project-related<A href="intro.html#sites"> sites</A>
+ are provided in our introduction section.</P>
+<H3><A name="patch">Add-ons and patches for FreeS/WAN</A></H3>
+<P>Some user-contributed patches have been integrated into the FreeS/WAN
+ distribution. For a variety of reasons, those listed below have not.</P>
+<P>Note that not all patches are a good idea.</P>
+<UL>
+<LI>There are a number of &quot;features&quot; of IPsec which we do not implement
+ because they reduce security. See this<A href="compat.html#dropped">
+ discussion</A>. We do not recommend using patches that implement these.
+ One example is aggressive mode.</LI>
+<LI>We do not recommend adding &quot;features&quot; of any sort unless they are
+ clearly necessary, or at least have clear benefits. For example,
+ FreeS/WAN would not become more secure if it offerred a choice of 14
+ ciphers. If even one was flawed, it would certainly become less secure
+ for anyone using that cipher. Even with 14 wonderful ciphers, it would
+ be harder to maintain and administer, hence more vulnerable to various
+ human errors.</LI>
+</UL>
+<P>This is not to say that patches are necessarily bad, only that using
+ them requires some deliberation. For example, there might be perfectly
+ good reasons to add a specific cipher in your application: perhaps GOST
+ to comply with government standards in Eastern Europe, or AES for
+ performance benefits.</P>
+<H4>Current patches</H4>
+<P>Patches believed current::</P>
+<UL>
+<LI>patches for<A href="http://www.strongsec.com/freeswan/"> X.509
+ certificate support</A>, also available from a<A href="http://www.twi.ch/~sna/strongsec/freeswan/">
+ mirror site</A></LI>
+<LI>patches to add<A href="http://www.irrigacion.gov.ar/juanjo/ipsec">
+ AES and other ciphers</A>. There is preliminary data indicating AES
+ gives a substantial<A href="performance.html#perf.more"> performance
+ gain</A>.</LI>
+</UL>
+<P>There is also one add-on that takes the form of a modified FreeS/WAN
+ distribution, rather than just patches to the standard distribution:</P>
+<UL>
+<LI><A href="http://www.ipv6.iabg.de/downloadframe/index.html">IPv6
+ support</A></LI>
+</UL>
+<P>Before using any of the above,, check the<A href="mail.html"> mailing
+ lists</A> for news of newer versions and to see whether they have been
+ incorporated into more recent versions of FreeS/WAN.</P>
+<H4>Older patches</H4>
+<UL>
+<LI><A href="http://sources.colubris.com/en/projects/FreeSWAN/">hardware
+ acceleration</A></LI>
+<LI>a<A href="http://tzukanov.narod.ru/"> series</A> of patches that
+<UL>
+<LI>provide GOST, a Russian gov't. standard cipher, in MMX assembler</LI>
+<LI>add GOST to OpenSSL</LI>
+<LI>add GOST to the International kernel patch</LI>
+<LI>let FreeS/WAN use International kernel patch ciphers</LI>
+</UL>
+</LI>
+<LI>Neil Dunbar's patches for<A href="ftp://hplose.hpl.hp.com/pub/nd/pluto-openssl.tar.gz">
+ certificate support</A>, using code from<A href="http://www.openssl.org">
+ Open SSL</A>.</LI>
+<LI>Luc Lanthier's<A href="ftp://ftp.netwinder.org/users/f/firesoul/">
+ patches</A> for<A href="glossary.html#PKIX"> PKIX</A> support.</LI>
+<LI><A href="ftp://ftp.heise.de/pub/ct/listings/9916-180.tgz">patches</A>
+ to add<A href="glossary.html#blowfish"> Blowfish</A>,<A href="glossary.html#IDEA">
+ IDEA</A> and<A href="glossary.html#CAST128"> CAST-128</A> to FreeS/WAN</LI>
+<LI>patches for FreeS/WAN 1.3, Pluto support for<A href="http://alcatraz.webcriminals.com/~bastiaan/ipsec/">
+ external authentication</A>, for example with a smartcard or SKEYID.</LI>
+<LI><A href="http://www.zengl.net/freeswan/download/">patches and
+ utilities</A> for using FreeS/WAN with PGPnet</LI>
+<LI><A href="http://www.freelith.com/lithworks/crypto/freeswan_patch.htm">
+Blowfish encryption and Tiger hash</A></LI>
+<LI><A href="http://www.cendio.se/~bellman/aggressive-pluto.snap.tar.gz">
+patches</A> for aggressive mode support</LI>
+</UL>
+<P>These patches are for older versions of FreeS/WAN and will likely not
+ work with the current version. Older versions of FreeS/WAN may be
+ available on some of the<A href="intro.html#sites"> distribution sites</A>
+, but we recommend using the current release.</P>
+<H4><A name="VPN.masq">VPN masquerade patches</A></H4>
+<P>Finally, there are some patches to other code that may be useful with
+ FreeS/WAN:</P>
+<UL>
+<LI>a<A href="ftp://ftp.rubyriver.com/pub/jhardin/masquerade/ip_masq_vpn.html">
+ patch</A> to make IPsec, PPTP and SSH VPNs work through a Linux
+ firewall with<A href="glossary.html#masq"> IP masquerade</A>.</LI>
+<LI><A href="http://www.linuxdoc.org/HOWTO/VPN-Masquerade-HOWTO.html">
+Linux VPN Masquerade HOWTO</A></LI>
+</UL>
+<P>Note that this is not required if the same machine does IPsec and
+ masquerading, only if you want a to locate your IPsec gateway on a
+ masqueraded network. See our<A href="firewall.html#NAT"> firewalls</A>
+ document for discussion of why this is problematic.</P>
+<P>At last report, this patch could not co-exist with FreeS/WAN on the
+ same machine.</P>
+<H3><A name="dist">Distributions including FreeS/WAN</A></H3>
+<P>The introductory section of our document set lists several<A href="intro.html#distwith">
+ Linux distributions</A> which include FreeS/WAN.</P>
+<H3><A name="used">Things FreeS/WAN uses or could use</A></H3>
+<UL>
+<LI><A href="http://openpgp.net/random">/dev/random</A> support page,
+ discussion of and code for the Linux<A href="glossary.html#random">
+ random number driver</A>. Out-of-date when we last checked (January
+ 2000), but still useful.</LI>
+<LI>other programs related to random numbers:
+<UL>
+<LI><A href="http://www.mindrot.org/audio-entropyd.html">audio entropy
+ daemon</A> to gather noise from a sound card and feed it into
+ /dev/random</LI>
+<LI>an<A href="http://www.lothar.com/tech/crypto/"> entropy-gathering
+ daemon</A></LI>
+<LI>a driver for the random number generator in recent<A href="http://sourceforge.net/projects/gkernel/">
+ Intel chipsets</A>. This driver is included as standard in 2.4 kernels.</LI>
+</UL>
+</LI>
+<LI>a Linux<A href="http://www.marko.net/l2tp/"> L2TP Daemon</A> which
+ might be useful for communicating with Windows 2000 which builds L2TP
+ tunnels over its IPsec connections</LI>
+<LI>to use opportunistic encryption, you need a recent version of<A href="glossary.html#BIND">
+ BIND</A>. You can get one from the<A href="http://www.isc.org">
+ Internet Software Consortium</A> who maintain BIND.</LI>
+</UL>
+<H3><A name="alternatives">Other approaches to VPNs for Linux</A></H3>
+<UL>
+<LI>other Linux<A href="#linuxipsec"> IPsec implementations</A></LI>
+<LI><A href="http://www.tik.ee.ethz.ch/~skip/">ENskip</A>, a free
+ implementation of Sun's<A href="glossary.html#SKIP"> SKIP</A> protocol</LI>
+<LI><A href="http://sunsite.auc.dk/vpnd/">vpnd</A>, a non-IPsec VPN
+ daemon for Linux which creates tunnels using<A href="glossary.html#Blowfish">
+ Blowfish</A> encryption</LI>
+<LI><A href="http://www.winton.org.uk/zebedee/">Zebedee</A>, a simple
+ GPLd tunnel-building program with Linux and Win32 versions. The name is
+ from<STRONG> Z</STRONG>lib compression,<STRONG> B</STRONG>lowfish
+ encryption and<STRONG> D</STRONG>iffie-Hellman key exchange.</LI>
+<LI>There are at least two PPTP implementations for Linux
+<UL>
+<LI>Moreton Bay's<A href="http://www.moretonbay.com/vpn/pptp.html">
+ PoPToP</A></LI>
+<LI><A href="http://cag.lcs.mit.edu/~cananian/Projects/PPTP/">PPTP-Linux</A>
+</LI>
+</UL>
+</LI>
+<LI><A href="http://sites.inka.de/sites/bigred/devel/cipe.html">CIPE</A>
+ (crypto IP encapsulation) project, using their own lightweight protocol
+ to encrypt between routers</LI>
+<LI><A href="http://tinc.nl.linux.org/">tinc</A>, a VPN Daemon</LI>
+</UL>
+<P>There is a list of<A href="http://www.securityportal.com/lskb/10000000/kben10000005.html">
+ Linux VPN</A> software in the<A href="http://www.securityportal.com/lskb/kben00000001.html">
+ Linux Security Knowledge Base</A>.</P>
+<H2><A name="ipsec.link">The IPsec Protocols</A></H2>
+<H3><A name="general">General IPsec or VPN information</A></H3>
+<UL>
+<LI>The<A href="http://www.vpnc.org"> VPN Consortium</A> is a group for
+ vendors of IPsec products. Among other things, they have a good
+ collection of<A href="http://www.vpnc.org/white-papers.html"> IPsec
+ white papers</A>.</LI>
+<LI>A VPN mailing list with a<A href="http://kubarb.phsx.ukans.edu/~tbird/vpn.html">
+ home page</A>, a FAQ, some product comparisons, and many links.</LI>
+<LI><A href="http://www.opus1.com/vpn/index.html">VPN pointer page</A></LI>
+<LI>a<A href="http://www.epm.ornl.gov/~dunigan/vpn.html"> collection</A>
+ of VPN links, and some explanation</LI>
+</UL>
+<H3><A name="overview">IPsec overview documents or slide sets</A></H3>
+<UL>
+<LI>the FreeS/WAN<A href="ipsec.html"> document section</A> on these
+ protocols</LI>
+</UL>
+<H3><A name="otherlang">IPsec information in languages other than
+ English</A></H3>
+<UL>
+<LI><A href="http://www.imib.med.tu-dresden.de/imib/Internet/Literatur/ipsec-docu.html">
+German</A></LI>
+<LI><A href="http://www.kame.net/index-j.html">Japanese</A></LI>
+<LI>Feczak Szabolcs' thesis in<A href="http://feczo.koli.kando.hu/vpn/">
+ Hungarian</A></LI>
+<LI>Davide Cerri's thesis and some presentation slides<A href="http://www.linux.it/~davide/doc/">
+ Italian</A></LI>
+</UL>
+<H3><A name="RFCs1">RFCs and other reference documents</A></H3>
+<UL>
+<LI><A href="rfc.html">Our document</A> listing the RFCs relevant to
+ Linux FreeS/WAN and giving various ways of obtaining both RFCs and
+ Internet Drafts.</LI>
+<LI><A href="http://www.vpnc.org/vpn-standards.html">VPN Standards</A>
+ page maintained by<A href="glossary.html#VPNC"> VPNC</A>. This covers
+ both RFCs and Drafts, and classifies them in a fairly helpful way.</LI>
+<LI><A href="http://www.rfc-editor.org">RFC archive</A></LI>
+<LI><A href="http://www.ietf.org/ids.by.wg/ipsec.html">Internet Drafts</A>
+ related to IPsec</LI>
+<LI>US government<A href="http://www.itl.nist.gov/div897/pubs"> site</A>
+ with their<A href="glossary.html#FIPS"> FIPS</A> standards</LI>
+<LI>Archives of the ipsec@tis.com mailing list where discussion of
+ drafts takes place.
+<UL>
+<LI><A href="http://www.sandelman.ottawa.on.ca/ipsec">Eastern Canada</A></LI>
+<LI><A href="http://www.vpnc.org/ietf-ipsec">California</A>.</LI>
+</UL>
+</LI>
+</UL>
+<H3><A name="analysis">Analysis and critiques of IPsec protocols</A></H3>
+<UL>
+<LI>Counterpane's<A href="http://www.counterpane.com/ipsec.pdf">
+ evaluation</A> of the protocols</LI>
+<LI>Simpson's<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/1999/06/msg00319.html">
+ IKE Considered Dangerous</A> paper. Note that this is a link to an
+ archive of our mailing list. There are several replies in addition to
+ the paper itself.</LI>
+<LI>Fate Labs<A href="http://www.fatelabs.com/loki-vpn.pdf"> Virual
+ Private Problems: the Broken Dream</A></LI>
+<LI>Catherine Meadows' paper<CITE> Analysis of the Internet Key Exchange
+ Protocol Using the NRL Protocol Analyzer</CITE>, in<A href="http://chacs.nrl.navy.mil/publications/CHACS/1999/1999meadows-IEEE99.pdf">
+ PDF</A> or<A href="http://chacs.nrl.navy.mil/publications/CHACS/1999/1999meadows-IEEE99.ps">
+ Postscript</A>.</LI>
+<LI>Perlman and Kaufmnan
+<UL>
+<LI><A href="http://snoopy.seas.smu.edu/ee8392_summer01/week7/perlman2.pdf">
+Key Exchange in IPsec</A></LI>
+<LI>a newer<A href="http://sec.femto.org/wetice-2001/papers/radia-paper.pdf">
+ PDF paper</A>,<CITE> Analysis of the IPsec Key Exchange Standard</CITE>
+.</LI>
+</UL>
+</LI>
+<LI>Bellovin's<A href="http://www.research.att.com/~smb/papers/index.html">
+ papers</A> page including his:
+<UL>
+<LI><CITE>Security Problems in the TCP/IP Protocol Suite</CITE> (1989)</LI>
+<LI><CITE>Problem Areas for the IP Security Protocols</CITE> (1996)</LI>
+<LI><CITE>Probable Plaintext Cryptanalysis of the IP Security Protocols</CITE>
+ (1997)</LI>
+</UL>
+</LI>
+<LI>An<A href="http://www.lounge.org/ike_doi_errata.html"> errata list</A>
+ for the IPsec RFCs.</LI>
+</UL>
+<H3><A name="IP.background">Background information on IP</A></H3>
+<UL>
+<LI>An<A href="http://ipprimer.windsorcs.com/"> IP tutorial</A> that
+ seems to be written mainly for Netware or Microsoft LAN admins entering
+ a new world</LI>
+<LI><A href="http://www.iana.org">IANA</A>, Internet Assigned Numbers
+ Authority</LI>
+<LI><A href="http://public.pacbell.net/dedicated/cidr.html">CIDR</A>,
+ Classless Inter-Domain Routing</LI>
+<LI>Also see our<A href="biblio.html"> bibliography</A></LI>
+</UL>
+<H2><A name="implement">IPsec Implementations</A></H2>
+<H3><A name="linuxprod">Linux products</A></H3>
+<P>Vendors using FreeS/WAN in turnkey firewall or VPN products are
+ listed in our<A href="intro.html#turnkey"> introduction</A>.</P>
+<P>Other vendors have Linux IPsec products which, as far as we know, do
+ not use FreeS/WAN</P>
+<UL>
+<LI><A href="http://www.redcreek.com/products/shareware.html">Redcreek</A>
+ provide an open source Linux driver for their PCI hardware VPN card.
+ This card has a 100 Mbit Ethernet port, an Intel 960 CPU plus more
+ specialised crypto chips, and claimed encryption performance of 45
+ Mbit/sec. The PC sees it as an Ethernet board.</LI>
+<LI><A href="http://linuxtoday.com/stories/8428.html?nn">Paktronix</A>
+ offer a Linux-based VPN with hardware encryption</LI>
+<LI><A href="http://www.watchguard.com/">Watchguard</A> use Linux in
+ their Firebox product.</LI>
+<LI><A href="http://www.entrust.com">Entrust</A> offer a developers'
+ toolkit for using their<A href="glossary.html#PKI"> PKI</A> for IPsec
+ authentication</LI>
+<LI>According to a report on our mailing list,<A href="http://www.axent.com">
+ Axent</A> have a Linux version of their product.</LI>
+</UL>
+<H3><A name="router">IPsec in router products</A></H3>
+<P>All the major router vendors support IPsec, at least in some models.</P>
+<UL>
+<LI><A href="http://www.cisco.com/warp/public/707/16.html">Cisco</A>
+ IPsec information</LI>
+<LI>Ascend, now part of<A href="http://www.lucent.com/"> Lucent</A>,
+ have some IPsec-based products</LI>
+<LI><A href="http://www.nortelnetworks.com/">Bay Networks</A>, now part
+ of Nortel, use IPsec in their Contivity switch product line</LI>
+<LI><A href="http://www.3com.com/products/enterprise.html">3Com</A> have
+ a number of VPN products, some using IPsec</LI>
+</UL>
+<H3><A name="fw.web">IPsec in firewall products</A></H3>
+<P>Many firewall vendors offer IPsec, either as a standard part of their
+ product, or an optional extra. A few we know about are:</P>
+<UL>
+<LI><A href="http://www.borderware.com/">Borderware</A></LI>
+<LI><A href="http://www.ashleylaurent.com/vpn/ipsec_vpn.htm">Ashley
+ Laurent</A></LI>
+<LI><A href="http://www.watchguard.com">Watchguard</A></LI>
+<LI><A href="http://www.fx.dk/firewall/ipsec.html">Injoy</A> for OS/2</LI>
+</UL>
+<P>Vendors using FreeS/WAN in turnkey firewall products are listed in
+ our<A href="intro.html#turnkey"> introduction</A>.</P>
+<H3><A name="ipsecos">Operating systems with IPsec support</A></H3>
+<P>All the major open source operating systems support IPsec. See below
+ for details on<A href="#BSD"> BSD-derived</A> Unix variants.</P>
+<P>Among commercial OS vendors, IPsec players include:</P>
+<UL>
+<LI><A href="http://msdn.microsoft.com/isapi/msdnlib.idc?theURL=/library/backgrnd/html/msdn_ip_security.htm">
+Microsoft</A> have put IPsec in their Windows 2000 and XP products</LI>
+<LI><A href="http://www.s390.ibm.com/stories/1999/os390v2r8_pr.html">IBM</A>
+ announce a release of OS390 with IPsec support via a crypto
+ co-processor</LI>
+<LI><A href="http://www.sun.com/solaris/ds/ds-security/ds-security.pdf">
+Sun</A> include IPsec in Solaris 8</LI>
+<LI><A href="http://www.hp.com/security/products/extranet-security.html">
+Hewlett Packard</A> offer IPsec for their Unix machines</LI>
+<LI>Certicom have IPsec available for the<A href="http://www.certicom.com/products/movian/movianvpn_tech.html">
+ Palm</A>.</LI>
+<LI>There were reports before the release that Apple's Mac OS X would
+ have IPsec support built in, but it did not seem to be there when we
+ last checked. If you find, it please let us know via the<A href="mail.html">
+ mailing list</A>.</LI>
+</UL>
+<H3><A NAME="29_3_5">IPsec on network cards</A></H3>
+<P>Network cards with built-in IPsec acceleration are available from at
+ least Intel, 3Com and Redcreek.</P>
+<H3><A name="opensource">Open source IPsec implementations</A></H3>
+<H4><A name="linuxipsec">Other Linux IPsec implementations</A></H4>
+<P>We like to think of FreeS/WAN as<EM> the</EM> Linux IPsec
+ implementation, but it is not the only one. Others we know of are:</P>
+<UL>
+<LI><A href="http://www.enst.fr/~beyssac/pipsec/">pipsecd</A>, a
+ lightweight implementation of IPsec for Linux. Does not require kernel
+ recompilation.</LI>
+<LI>Petr Novak's<A href="ftp://ftp.eunet.cz/icz/ipnsec/"> ipnsec</A>,
+ based on the OpenBSD IPsec code and using<A href="glossary.html#photuris">
+ Photuris</A> for key management</LI>
+<LI>A now defunct project at<A href="http://www.cs.arizona.edu/security/hpcc-blue/linux.html">
+ U of Arizona</A> (export controlled)</LI>
+<LI><A href="http://snad.ncsl.nist.gov/cerberus">NIST Cerebus</A>
+ (export controlled)</LI>
+</UL>
+<H4><A name="BSD">IPsec for BSD Unix</A></H4>
+<UL>
+<LI><A href="http://www.kame.net/project-overview.html">KAME</A>,
+ several large Japanese companies co-operating on IPv6 and IPsec</LI>
+<LI><A href="http://web.mit.edu/network/isakmp">US Naval Research Lab</A>
+ implementation of IPv6 and of IPsec for IPv4 (export controlled)</LI>
+<LI><A href="http://www.openbsd.org">OpenBSD</A> includes IPsec as a
+ standard part of the distribution</LI>
+<LI><A href="http://www.r4k.net/ipsec">IPsec for FreeBSD</A></LI>
+<LI>a<A href="http://www.netbsd.org/Documentation/network/ipsec/"> FAQ</A>
+ on NetBSD's IPsec implementation</LI>
+</UL>
+<H4><A name="misc">IPsec for other systems</A></H4>
+<UL>
+<LI><A href="http://www.tcm.hut.fi/Tutkimus/IPSEC/">Helsinki U of
+ Technolgy</A> have implemented IPsec for Solaris, Java and Macintosh</LI>
+</UL>
+<H3><A name="interop.web">Interoperability</A></H3>
+<P>The IPsec protocols are designed so that different implementations
+ should be able to work together. As they say &quot;the devil is in the
+ details&quot;. IPsec has a lot of details, but considerable success has been
+ achieved.</P>
+<H4><A name="result">Interoperability results</A></H4>
+<P>Linux FreeS/WAN has been tested for interoperability with many other
+ IPsec implementations. Results to date are in our<A href="interop.html">
+ interoperability</A> section.</P>
+<P>Various other sites have information on interoperability between
+ various IPsec implementations:</P>
+<UL>
+<LI><A href="http://www.opus1.com/vpn/atl99display.html">interop results</A>
+ from a bakeoff in Atlanta, September 1999.</LI>
+<LI>a French company, HSC's,<A href="http://www.hsc.fr/ressources/presentations/ipsec99/index.html.en">
+ interoperability</A> test data covers FreeS/WAN, Open BSD, KAME, Linux
+ pipsecd, Checkpoint, Red Creek Ravlin, and Cisco IOS</LI>
+<LI><A href="http://www.icsa.net/">ICSA</A> offer certification programs
+ for various security-related products. See their list of<A href="http://www.icsa.net/html/communities/ipsec/certification/certified_products/index.shtml">
+ certified IPsec</A> products. Linux FreeS/WAN is not currently on that
+ list, but several products with which we interoperate are.</LI>
+<LI>VPNC have a page on why they are not yet doing<A href="http://www.vpnc.org/interop.html">
+ interoperability</A> testing and a page on the<A href="http://www.vpnc.org/conformance.html">
+ spec conformance</A> testing that they are doing</LI>
+<LI>a<A href="http://www.commweb.com/article/COM20000912S0009"> review</A>
+ comparing a dozen commercial IPsec implemetations. Unfortunately, the
+ reviewers did not look at Open Source implementations such as FreeS/WAN
+ or OpenBSD.</LI>
+<LI><A href="http://www.tanu.org/~sakane/doc/public/report-ike-interop0007.html">
+results</A> from interoperability tests at a conference. FreeS/WAN was
+ not tested there.</LI>
+<LI>test results from the<A href="http://www.hsc.fr/ressources/veille/ipsec/ipsec2000/">
+ IPSEC 2000</A> conference</LI>
+</UL>
+<H4><A name="test1">Interoperability test sites</A></H4>
+<UL>
+<LI><A href="http://www.tahi.org/">TAHI</A>, a Japanese IPv6 testing
+ project with free IPsec validation software</LI>
+<LI><A href="http://ipsec-wit.antd.nist.gov">National Institute of
+ Standards and Technology</A></LI>
+<LI><A href="http://isakmp-test.ssh.fi/">SSH Communications Security</A></LI>
+</UL>
+<H2><A name="linux.link">Linux links</A></H2>
+<H3><A name="linux.basic">Basic and tutorial Linux information</A></H3>
+<UL>
+<LI>Linux<A href="http://linuxcentral.com/linux/LDP/LDP/gs/gs.html">
+ Getting Started</A> HOWTO document</LI>
+<LI>A getting started guide from the<A href="http://darkwing.uoregon.edu/~cchome/linuxgettingstarted.html">
+ U of Oregon</A></LI>
+<LI>A large<A href="http://www.herring.org/techie.html"> link collection</A>
+ which includes a lot of introductory and tutorial material on Unix,
+ Linux, the net, . . .</LI>
+</UL>
+<H3><A name="general">General Linux sites</A></H3>
+<UL>
+<LI><A href="http://www.freshmeat.net">Freshmeat</A> Linux news</LI>
+<LI><A href="http://slashdot.org">Slashdot</A> &quot;News for Nerds&quot;</LI>
+<LI><A href="http://www.linux.org">Linux Online</A></LI>
+<LI><A href="http://www.linuxhq.com">Linux HQ</A></LI>
+<LI><A href="http://www.tux.org">tux.org</A></LI>
+</UL>
+<H3><A name="docs.ldp">Documentation</A></H3>
+<P>Nearly any Linux documentation you are likely to want can be found at
+ the<A href="http://metalab.unc.edu/LDP"> Linux Documentation Project</A>
+ or LDP.</P>
+<UL>
+<LI><A href="http://metalab.unc.edu/LDP/HOWTO/META-FAQ.html">Meta-FAQ</A>
+ guide to Linux information sources</LI>
+<LI>The LDP's HowTo documents are a standard Linux reference. See this<A href="http://www.linuxdoc.org/docs.html#howto">
+ list</A>. Documents there most relevant to a FreeS/WAN gateway are:
+<UL>
+<LI><A href="http://metalab.unc.edu/LDP/HOWTO/Kernel-HOWTO.html">Kernel
+ HOWTO</A></LI>
+<LI><A href="http://metalab.unc.edu/LDP/HOWTO/Networking-Overview-HOWTO.html">
+Networking Overview HOWTO</A></LI>
+<LI><A href="http://metalab.unc.edu/LDP/HOWTO/Security-HOWTO.html">
+Security HOWTO</A></LI>
+</UL>
+</LI>
+<LI>The LDP do a series of Guides, book-sized publications with more
+ detail (and often more &quot;why do it this way?&quot;) than the HowTos. See this<A
+href="http://www.linuxdoc.org/guides.html"> list</A>. Documents there
+ most relevant to a FreeS/WAN gateway are:
+<UL>
+<LI><A href="http://www.tml.hut.fi/~viu/linux/sag/">System
+ Administrator's Guide</A></LI>
+<LI><A href="http://www.linuxdoc.org/LDP/nag2/index.html">Network
+ Adminstrator's Guide</A></LI>
+<LI><A href="http://www.seifried.org/lasg/">Linux Administrator's
+ Security Guide</A></LI>
+</UL>
+</LI>
+</UL>
+<P>You may not need to go to the LDP to get this material. Most Linux
+ distributions include the HowTos on their CDs and several include the
+ Guides as well. Also, most of the Guides and some collections of HowTos
+ are available in book form from various publishers.</P>
+<P>Much of the LDP material is also available in languages other than
+ English. See this<A href="http://www.linuxdoc.org/links/nenglish.html">
+ LDP page</A>.</P>
+<H3><A name="advroute.web">Advanced routing</A></H3>
+<P>The Linux IP stack has some new features in 2.4 kernels. Some HowTos
+ have been written:</P>
+<UL>
+<LI>several HowTos for the<A href="http://netfilter.samba.org/unreliable-guides/">
+ netfilter</A> firewall code in newer kernels</LI>
+<LI><A href="http://www.ds9a.nl/2.4Networking/HOWTO//cvs/2.4routing/output/2.4networking.html">
+2.4 networking</A> HowTo</LI>
+<LI><A href="http://www.ds9a.nl/2.4Networking/HOWTO//cvs/2.4routing/output/2.4routing.html">
+2.4 routing</A> HowTo</LI>
+</UL>
+<H3><A name="linsec">Security for Linux</A></H3>
+<P>See also the<A href="#docs.ldp"> LDP material</A> above.</P>
+<UL>
+<LI><A href="http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos">
+Trinity OS guide to setting up Linux</A></LI>
+<LI><A href="http://www.deter.com/unix">Unix security</A> page</LI>
+<LI><A href="http://linux01.gwdg.de/~alatham/">PPDD</A> encrypting
+ filesystem</LI>
+<LI><A href="http://EncryptionHOWTO.sourceforge.net/">Linux Encryption
+ HowTo</A> (outdated when last checked, had an Oct 2000 revision date in
+ March 2002)</LI>
+</UL>
+<H3><A name="firewall.linux">Linux firewalls</A></H3>
+<P>Our<A href="firewall.html"> FreeS/WAN and firewalls</A> document
+ includes links to several sets of<A href="firewall.html#examplefw">
+ scripts</A> known to work with FreeS/WAN.</P>
+<P>Other information sources:</P>
+<UL>
+<LI><A href="http://ipmasq.cjb.net/">IP Masquerade resource page</A></LI>
+<LI><A href="http://netfilter.samba.org/unreliable-guides/">netfilter</A>
+ firewall code in 2.4 kernels</LI>
+<LI>Our list of general<A href="#firewall.web"> firewall references</A>
+ on the web</LI>
+<LI><A href="http://users.dhp.com/~whisper/mason/">Mason</A>, a tool for
+ automatically configuring Linux firewalls</LI>
+<LI>the web cache software<A href="http://www.squid-cache.org/"> squid</A>
+ and<A href="http://www.squidguard.org/"> squidguard</A> which turns
+ Squid into a filtering web proxy</LI>
+</UL>
+<H3><A name="linux.misc">Miscellaneous Linux information</A></H3>
+<UL>
+<LI><A href="http://lwn.net/current/dists.php3">Linux distribution
+ vendors</A></LI>
+<LI><A href="http://www.linux.org/groups/">Linux User Groups</A></LI>
+</UL>
+<H2><A name="crypto.link">Crypto and security links</A></H2>
+<H3><A name="security">Crypto and security resources</A></H3>
+<H4><A name="std.links">The standard link collections</A></H4>
+<P>Two enormous collections of links, each the standard reference in its
+ area:</P>
+<DL>
+<DT>Gene Spafford's<A href="http://www.cerias.purdue.edu/coast/hotlist/">
+ COAST hotlist</A></DT>
+<DD>Computer and network security.</DD>
+<DT>Peter Gutmann's<A href="http://www.cs.auckland.ac.nz/~pgut001/links.html">
+ Encryption and Security-related Resources</A></DT>
+<DD>Cryptography.</DD>
+</DL>
+<H4><A name="FAQ">Frequently Asked Question (FAQ) documents</A></H4>
+<UL>
+<LI><A href="http://www.faqs.org/faqs/cryptography-faq/">Cryptography
+ FAQ</A></LI>
+<LI><A href="http://www.interhack.net/pubs/fwfaq">Firewall FAQ</A></LI>
+<LI><A href="http://www.whitefang.com/sup/secure-faq.html">Secure Unix
+ Programming FAQ</A></LI>
+<LI>FAQs for specific programs are listed in the<A href="#tools"> tools</A>
+ section below.</LI>
+</UL>
+<H4><A name="cryptover">Tutorials</A></H4>
+<UL>
+<LI>Gary Kessler's<A href="http://www.garykessler.net/library/crypto.html">
+ Overview of Cryptography</A></LI>
+<LI>Terry Ritter's<A href="http://www.ciphersbyritter.com/LEARNING.HTM">
+ introduction</A></LI>
+<LI>Peter Gutman's<A href="http://www.cs.auckland.ac.nz/~pgut001/tutorial/index.html">
+ cryptography</A> tutorial (500 slides in PDF format)</LI>
+<LI>Amir Herzberg of IBM's sildes for his course<A href="http://www.hrl.il.ibm.com/mpay/course.html">
+ Introduction to Cryptography and Electronic Commerce</A></LI>
+<LI>the<A href="http://www.gnupg.org/gph/en/manual/c173.html"> concepts
+ section</A> of the<A href="glossary.html#GPG"> GNU Privacy Guard</A>
+ documentation</LI>
+<LI>Bruce Schneier's self-study<A href="http://www.counterpane.com/self-study.html">
+ cryptanalysis</A> course</LI>
+</UL>
+<P>See also the<A href="#interesting"> interesting papers</A> section
+ below.</P>
+<H4><A name="standards">Crypto and security standards</A></H4>
+<UL>
+<LI><A href="http://csrc.nist.gov/cc">Common Criteria</A>, new
+ international computer and network security standards to replace the
+ &quot;Rainbow&quot; series</LI>
+<LI>AES<A href="http://csrc.nist.gov/encryption/aes/aes_home.htm">
+ Advanced Encryption Standard</A> which will replace DES</LI>
+<LI><A href="http://grouper.ieee.org/groups/1363">IEEE P-1363 public key
+ standard</A></LI>
+<LI>our collection of links for the<A href="#ipsec.link"> IPsec</A>
+ standards</LI>
+<LI>history of<A href="http://www.visi.com/crypto/evalhist/index.html">
+ formal evaluation</A> of security policies and implementation</LI>
+</UL>
+<H4><A name="quotes">Crypto quotes</A></H4>
+<P>There are several collections of cryptographic quotes on the net:</P>
+<UL>
+<LI><A href="http://www.eff.org/pub/EFF/quotes.eff">the EFF</A></LI>
+<LI><A href="http://www.samsimpson.com/cquotes.php">Sam Simpson</A></LI>
+<LI><A href="http://www.amk.ca/quotations/cryptography/page-1.html">AM
+ Kutchling</A></LI>
+</UL>
+<H3><A name="policy">Cryptography law and policy</A></H3>
+<H4><A name="legal">Surveys of crypto law</A></H4>
+<UL>
+<LI>International survey of<A href="http://cwis.kub.nl/~FRW/PEOPLE/koops/lawsurvy.htm">
+ crypto law</A>.</LI>
+<LI>International survey of<A href="http://rechten.kub.nl/simone/ds-lawsu.htm">
+ digital signature law</A></LI>
+</UL>
+<H4><A name="oppose">Organisations opposing crypto restrictions</A></H4>
+<UL>
+<LI>The<A href="glossary.html#EFF"> EFF</A>'s archives on<A href="http://www.eff.org/pub/Privacy/">
+ privacy</A> and<A href="http://www.eff.org/pub/Privacy/ITAR_export/">
+ export control</A>.</LI>
+<LI><A href="http://www.gilc.org">Global Internet Liberty Campaign</A></LI>
+<LI><A href="http://www.cdt.org/crypto">Center for Democracy and
+ Technology</A></LI>
+<LI><A href="http://www.privacyinternational.org/">Privacy International</A>
+, who give out<A href="http://www.bigbrotherawards.org/"> Big Brother
+ Awards</A> to snoopy organisations</LI>
+</UL>
+<H4><A name="other.policy">Other information on crypto policy</A></H4>
+<UL>
+<LI><A href="ftp://ftp.isi.edu/in-notes/rfc1984.txt">RFC 1984</A>, the<A href="glossary.html#IAB">
+ IAB</A> and<A href="glossary.html#IESG"> IESG</A> Statement on
+ Cryptographic Technology and the Internet.</LI>
+<LI>John Young's collection of<A href="http://cryptome.org/"> documents</A>
+ of interest to the cryptography, open government and privacy movements,
+ organized chronologically</LI>
+<LI>AT&amp;T researcher Matt Blaze's Encryption, Privacy and Security<A href="http://www.crypto.com">
+ Resource Page</A></LI>
+<LI>A good<A href="http://cryptome.org/crypto97-ne.htm"> overview</A> of
+ the issues from Australia.</LI>
+</UL>
+<P>See also our documentation section on the<A href="politics.html">
+ history and politics</A> of cryptography.</P>
+<H3><A name="crypto.tech">Cryptography technical information</A></H3>
+<H4><A name="cryptolinks">Collections of crypto links</A></H4>
+<UL>
+<LI><A href="http://www.counterpane.com/hotlist.html">Counterpane</A></LI>
+<LI><A href="http://www.cs.auckland.ac.nz/~pgut001/links.html">Peter
+ Gutman's links</A></LI>
+<LI><A href="http://www.pca.dfn.de/eng/team/ske/pem-dok.html">PKI links</A>
+</LI>
+<LI><A href="http://crypto.yashy.com/www/">Robert Guerra's links</A></LI>
+</UL>
+<H4><A name="papers">Lists of online cryptography papers</A></H4>
+<UL>
+<LI><A href="http://www.counterpane.com/biblio">Counterpane</A></LI>
+<LI><A href="http://www.cryptography.com/resources/papers">
+cryptography.com</A></LI>
+<LI><A href="http://www.cryptosoft.com/html/secpub.htm">Cryptosoft</A></LI>
+</UL>
+<H4><A name="interesting">Particularly interesting papers</A></H4>
+<P>These papers emphasize important issues around the use of
+ cryptography, and the design and management of secure systems.</P>
+<UL>
+<LI><A href="http://www.counterpane.com/keylength.html">Key length
+ requirements for security</A></LI>
+<LI><A href="http://www.cl.cam.ac.uk/users/rja14/wcf.html">Why
+ Cryptosystems Fail</A></LI>
+<LI><A href="http://www.cdt.org/crypto/risks98/">Risks of escrowed
+ encryption</A></LI>
+<LI><A href="http://www.counterpane.com/pitfalls.html">Security pitfalls
+ in cryptography</A></LI>
+<LI><A href="http://www.acm.org/classics/sep95">Reflections on Trusting
+ Trust</A>, Ken Thompson on Trojan horse design</LI>
+<LI><A href="http://www.apache-ssl.org/disclosure.pdf">Security against
+ Compelled Disclosure</A>, how to maintain privacy in the face of legal
+ or other coersion</LI>
+</UL>
+<H3><A name="compsec">Computer and network security</A></H3>
+<H4><A name="seclink">Security links</A></H4>
+<UL>
+<LI><A href="http://www.cs.purdue.edu/coast/hotlist">COAST Hotlist</A></LI>
+<LI>DMOZ open directory project<A href="http://dmoz.org/Computers/Security/">
+ computer security</A> links</LI>
+<LI><A href="http://www-cse.ucsd.edu/users/bsy/sec.html">Bennet Yee</A></LI>
+<LI>Mike Fuhr's<A href="http://www.fuhr.org/~mfuhr/computers/security.html">
+ link collection</A></LI>
+<LI><A href="http://www.networkintrusion.co.uk/">links</A> with an
+ emphasis on intrusion detection</LI>
+</UL>
+<H4><A name="firewall.web">Firewall links</A></H4>
+<UL>
+<LI><A href="http://www.cs.purdue.edu/coast/firewalls">COAST firewalls</A>
+</LI>
+<LI><A href="http://www.zeuros.co.uk">Firewalls Resource page</A></LI>
+</UL>
+<H4><A name="vpn">VPN links</A></H4>
+<UL>
+<LI><A href="http://www.vpnc.org">VPN Consortium</A></LI>
+<LI>First VPN's<A href="http://www.firstvpn.com/research/rhome.html">
+ white paper</A> collection</LI>
+</UL>
+<H4><A name="tools">Security tools</A></H4>
+<UL>
+<LI>PGP -- mail encryption
+<UL>
+<LI><A href="http://www.pgp.com/">PGP Inc.</A> (part of NAI) for
+ commercial versions</LI>
+<LI><A href="http://web.mit.edu/network/pgp.html">MIT</A> distributes
+ the NAI product for non-commercial use</LI>
+<LI><A href="http://www.pgpi.org/">international</A> distribution site</LI>
+<LI><A href="http://gnupg.org">GNU Privacy Guard (GPG)</A></LI>
+<LI><A href="http://www.dk.pgp.net/pgpnet/pgp-faq/">PGP FAQ</A></LI>
+</UL>
+ A message in our mailing list archive has considerable detail on<A href="http://www.sandelman.ottawa.on.ca/linux-ipsec/html/2000/12/msg00029.html">
+ available versions</A> of PGP and on IPsec support in them.
+<P><STRONG>Note:</STRONG> A fairly nasty bug exists in all commercial
+ PGP versions from 5.5 through 6.5.3. If you have one of those,<STRONG>
+ upgrade now</STRONG>.</P>
+</LI>
+<LI>SSH -- secure remote login
+<UL>
+<LI><A href="http://www.ssh.fi">SSH Communications Security</A>, for the
+ original software. It is free for trial, academic and non-commercial
+ use.</LI>
+<LI><A href="http://www.openssh.com/">Open SSH</A>, the Open BSD team's
+ free replacement</LI>
+<LI><A href="http://www.freessh.org/">freessh.org</A>, links to free
+ implementations for many systems</LI>
+<LI><A href="http://www.uni-karlsruhe.de/~ig25/ssh-faq">SSH FAQ</A></LI>
+<LI><A href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">Putty</A>
+, an SSH client for Windows</LI>
+</UL>
+</LI>
+<LI>Tripwire saves message digests of your system files. Re-calculate
+ the digests and compare to saved values to detect any file changes.
+ There are several versions available:
+<UL>
+<LI><A href="http://www.tripwiresecurity.com/">commercial version</A></LI>
+<LI><A href="http://www.tripwire.org/">Open Source</A></LI>
+</UL>
+</LI>
+<LI><A href="http://www.snort.org">Snort</A> and<A href="http://www.lids.org">
+ LIDS</A> are intrusion detection system for Linux</LI>
+<LI><A href="http://www.fish.com/~zen/satan/satan.html">SATAN</A> System
+ Administrators Tool for Analysing Networks</LI>
+<LI><A href="http://www.insecure.org/nmap/">NMAP</A> Network Mapper</LI>
+<LI><A href="ftp://ftp.porcupine.org/pub/security/index.html">Wietse
+ Venema's page</A> with various tools</LI>
+<LI><A href="http://ita.ee.lbl.gov/index.html">Internet Traffic Archive</A>
+, various tools to analyze network traffic, mostly scripts to organise
+ and format tcpdump(8) output for specific purposes</LI>
+<LI><A name="ssmail">ssmail -- sendmail patched to do</A><A href="glossary.html#carpediem">
+ opportunistic encryption</A>
+<UL>
+<LI><A href="http://www.home.aone.net.au/qualcomm/">web page</A> with
+ links to code and to a Usenix paper describing it, in PDF</LI>
+</UL>
+</LI>
+<LI><A href="http://www.openca.org/">Open CA</A> project to develop a
+ freely distributed<A href="glossary.html#CA"> Certification Authority</A>
+ for building a open<A href="glossary.html#PKI"> Public Key
+ Infrastructure</A>.</LI>
+</UL>
+<H3><A name="people">Links to home pages</A></H3>
+<P>David Wagner at Berkeley provides a set of links to<A href="http://www.cs.berkeley.edu/~daw/people/crypto.html">
+ home pages</A> of cryptographers, cypherpunks and computer security
+ people.</P>
+<HR>
+<A HREF="toc.html">Contents</A>
+<A HREF="mail.html">Previous</A>
+<A HREF="glossary.html">Next</A>
+</BODY>
+</HTML>
diff --git a/lib/.cvsignore b/lib/.cvsignore
new file mode 100644
index 000000000..aa84dc001
--- /dev/null
+++ b/lib/.cvsignore
@@ -0,0 +1,2 @@
+ktmp
+version.c
diff --git a/lib/COPYING.LIB b/lib/COPYING.LIB
new file mode 100644
index 000000000..92b8903ff
--- /dev/null
+++ b/lib/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 000000000..fa2b27bef
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,41 @@
+# Makefile for the KLIPS interface utilities
+# Copyright (C) 1998, 1999 Henry Spencer.
+# Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:24 as Exp $
+
+FREESWANSRCDIR=..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+SUBDIRS=libfreeswan libdes
+
+ifeq ($(USE_LWRES),true)
+SUBDIRS+=liblwres
+endif
+
+ifeq ($(USE_IPSECPOLICY),true)
+SUBDIRS+=libipsecpolicy
+endif
+
+def:
+ @echo "Please read doc/intro.html or INSTALL before running make"
+ @false
+
+# programs
+
+cleanall distclean mostlyclean realclean install programs checkprograms check clean spotless install_file_list:
+ @for d in $(SUBDIRS) ; \
+ do \
+ (cd $$d && $(MAKE) FREESWANSRCDIR=$(FREESWANSRCDIR)/.. $@ ) || exit 1; \
+ done; \
+
diff --git a/lib/Makefile.kernel b/lib/Makefile.kernel
new file mode 100644
index 000000000..f32a4f0b7
--- /dev/null
+++ b/lib/Makefile.kernel
@@ -0,0 +1,65 @@
+# FreeS/WAN library
+# Copyright (C) 1998-2002 Henry Spencer.
+#
+# 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.kernel,v 1.1 2004/03/15 20:35:24 as Exp $
+
+
+
+include ../Makefile.inc
+include ../Makefile.ver
+
+
+
+ifndef TOPDIR
+TOPDIR := /usr/src/linux
+endif
+
+L_TARGET := libkernel.a
+
+obj-y := addrtoa.o datatot.o goodmask.o \
+ pfkey_v2_build.o pfkey_v2_debug.o pfkey_v2_ext_bits.o pfkey_v2_parse.o \
+ prng.o rangetoa.o satoa.o \
+ subnetof.o subnettoa.o ultoa.o version.o
+
+HDRS=freeswan.h internal.h
+
+EXTRA_CFLAGS += -I. $(KLIPSCOMPILE)
+
+EXTRA_CFLAGS += -Wall
+#EXTRA_CFLAGS += -Wconversion
+#EXTRA_CFLAGS += -Wmissing-prototypes
+EXTRA_CFLAGS += -Wpointer-arith
+#EXTRA_CFLAGS += -Wcast-qual
+#EXTRA_CFLAGS += -Wmissing-declarations
+EXTRA_CFLAGS += -Wstrict-prototypes
+#EXTRA_CFLAGS += -pedantic
+#EXTRA_CFLAGS += -W
+#EXTRA_CFLAGS += -Wwrite-strings
+#EXTRA_CFLAGS += -Wbad-function-cast
+
+active-objs := $(sort $(obj-y) $(obj-m))
+L_OBJS := $(obj-y)
+M_OBJS := $(obj-m)
+MIX_OBJS := $(filter $(export-objs), $(active-objs))
+
+include $(TOPDIR)/Rules.make
+
+$(obj-y): $(HDRS)
+
+# build version.c using version number from Makefile.ver
+version.c: version.in.c
+ sed '/"/s/xxx/$(IPSECVERSION)/' version.in.c >$@
+
+clean:
+ rm -f $(L_TARGET) *.o try* core *.core version.c
+ ( cd des && $(MAKE) clean )
diff --git a/lib/README b/lib/README
new file mode 100644
index 000000000..1834a8792
--- /dev/null
+++ b/lib/README
@@ -0,0 +1,3 @@
+These are general library functions used in many places in FreeS/WAN.
+
+They are under the GNU library license; see COPYING.LIB.
diff --git a/lib/libcrypto/include/cbc_generic.h b/lib/libcrypto/include/cbc_generic.h
new file mode 100644
index 000000000..0dd3a77d6
--- /dev/null
+++ b/lib/libcrypto/include/cbc_generic.h
@@ -0,0 +1,110 @@
+#ifndef _CBC_GENERIC_H
+#define _CBC_GENERIC_H
+/*
+ * CBC macro helpers
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Heavily inspired in loop_AES
+ */
+#define CBC_IMPL_BLK16(name, ctx_type, addr_type, enc_func, dec_func) \
+int name(ctx_type *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt) { \
+ int ret=ilen, pos; \
+ const u_int32_t *iv_i; \
+ if ((ilen) % 16) return 0; \
+ if (encrypt) { \
+ pos=0; \
+ while(pos<ilen) { \
+ if (pos==0) \
+ iv_i=(const u_int32_t*) iv; \
+ else \
+ iv_i=(const u_int32_t*) (out-16); \
+ *((u_int32_t *)(&out[ 0])) = iv_i[0]^*((const u_int32_t *)(&in[ 0])); \
+ *((u_int32_t *)(&out[ 4])) = iv_i[1]^*((const u_int32_t *)(&in[ 4])); \
+ *((u_int32_t *)(&out[ 8])) = iv_i[2]^*((const u_int32_t *)(&in[ 8])); \
+ *((u_int32_t *)(&out[12])) = iv_i[3]^*((const u_int32_t *)(&in[12])); \
+ enc_func(ctx, (addr_type) out, (addr_type) out); \
+ in+=16; \
+ out+=16; \
+ pos+=16; \
+ } \
+ } else { \
+ pos=ilen-16; \
+ in+=pos; \
+ out+=pos; \
+ while(pos>=0) { \
+ dec_func(ctx, (const addr_type) in, (addr_type) out); \
+ if (pos==0) \
+ iv_i=(const u_int32_t*) (iv); \
+ else \
+ iv_i=(const u_int32_t*) (in-16); \
+ *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; \
+ *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; \
+ *((u_int32_t *)(&out[ 8])) ^= iv_i[2]; \
+ *((u_int32_t *)(&out[12])) ^= iv_i[3]; \
+ in-=16; \
+ out-=16; \
+ pos-=16; \
+ } \
+ } \
+ return ret; \
+}
+#define CBC_IMPL_BLK8(name, ctx_type, addr_type, enc_func, dec_func) \
+int name(ctx_type *ctx, u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt) { \
+ int ret=ilen, pos; \
+ const u_int32_t *iv_i; \
+ if ((ilen) % 8) return 0; \
+ if (encrypt) { \
+ pos=0; \
+ while(pos<ilen) { \
+ if (pos==0) \
+ iv_i=(const u_int32_t*) iv; \
+ else \
+ iv_i=(const u_int32_t*) (out-8); \
+ *((u_int32_t *)(&out[ 0])) = iv_i[0]^*((const u_int32_t *)(&in[ 0])); \
+ *((u_int32_t *)(&out[ 4])) = iv_i[1]^*((const u_int32_t *)(&in[ 4])); \
+ enc_func(ctx, (addr_type)out, (addr_type)out); \
+ in+=8; \
+ out+=8; \
+ pos+=8; \
+ } \
+ } else { \
+ pos=ilen-8; \
+ in+=pos; \
+ out+=pos; \
+ while(pos>=0) { \
+ dec_func(ctx, (const addr_type)in, (addr_type)out); \
+ if (pos==0) \
+ iv_i=(const u_int32_t*) (iv); \
+ else \
+ iv_i=(const u_int32_t*) (in-8); \
+ *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; \
+ *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; \
+ in-=8; \
+ out-=8; \
+ pos-=8; \
+ } \
+ } \
+ return ret; \
+}
+#define CBC_DECL(name, ctx_type) \
+int name(ctx_type *ctx, u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt)
+/*
+Eg.:
+CBC_IMPL_BLK16(AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
+CBC_DECL(AES_cbc_encrypt, aes_context);
+*/
+#endif /* _CBC_GENERIC_H */
diff --git a/lib/libcrypto/include/hmac_generic.h b/lib/libcrypto/include/hmac_generic.h
new file mode 100644
index 000000000..a749228e3
--- /dev/null
+++ b/lib/libcrypto/include/hmac_generic.h
@@ -0,0 +1,60 @@
+#ifndef _HMAC_GENERIC_H
+#define _HMAC_GENERIC_H
+/*
+ * HMAC macro helpers
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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.
+ *
+ */
+
+#ifndef DIVUP
+#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */
+#endif
+#ifndef HMAC_IPAD
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5C
+#endif
+#define HMAC_SET_KEY_IMPL(func_name, hctx_t, blocksize, func_init, func_update) \
+void func_name(hctx_t *hctx, const u_int8_t * key, int keylen) { \
+ int i;\
+ u_int8_t kb[blocksize]; \
+ for (i = 0; i < DIVUP(keylen*8, 8); i++) { \
+ kb[i] = key[i] ^ HMAC_IPAD; \
+ } \
+ for (; i < blocksize; i++) { \
+ kb[i] = HMAC_IPAD; \
+ } \
+ func_init(&hctx->ictx); \
+ func_update(&hctx->ictx, kb, blocksize); \
+ for (i = 0; i < blocksize; i++) { \
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD); \
+ } \
+ func_init(&hctx->octx); \
+ func_update(&hctx->octx, kb, blocksize); \
+}
+#define HMAC_HASH_IMPL(func_name, hctx_t, ctx_t, ahlen, func_update, func_result ) \
+void func_name(hctx_t *hctx, const u_int8_t * dat, int len, u_int8_t * hash, int hashlen) { \
+ ctx_t ctx; \
+ ctx=hctx->ictx; \
+ if (dat) func_update(&ctx, dat, len); \
+ if (hash) { \
+ u_int8_t hash_buf[ahlen]; \
+ func_result(&ctx, hash_buf, ahlen); \
+ ctx=hctx->octx; \
+ func_update(&ctx, hash_buf, ahlen); \
+ func_result(&ctx, hash, hashlen); \
+ memset(&ctx, 0, sizeof (ctx)); \
+ memset(&hash_buf, 0, sizeof (hash_buf));\
+ } \
+}
+#endif /* _HMAC_GENERIC_H */
diff --git a/lib/libcrypto/include/md32_common.h b/lib/libcrypto/include/md32_common.h
new file mode 100644
index 000000000..1a404a458
--- /dev/null
+++ b/lib/libcrypto/include/md32_common.h
@@ -0,0 +1,607 @@
+/* crypto/md32_common.h */
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/*
+ * This is a generic 32 bit "collector" for message digest algorithms.
+ * Whenever needed it collects input character stream into chunks of
+ * 32 bit values and invokes a block function that performs actual hash
+ * calculations.
+ *
+ * Porting guide.
+ *
+ * Obligatory macros:
+ *
+ * DATA_ORDER_IS_BIG_ENDIAN or DATA_ORDER_IS_LITTLE_ENDIAN
+ * this macro defines byte order of input stream.
+ * HASH_CBLOCK
+ * size of a unit chunk HASH_BLOCK operates on.
+ * HASH_LONG
+ * has to be at lest 32 bit wide, if it's wider, then
+ * HASH_LONG_LOG2 *has to* be defined along
+ * HASH_CTX
+ * context structure that at least contains following
+ * members:
+ * typedef struct {
+ * ...
+ * HASH_LONG Nl,Nh;
+ * HASH_LONG data[HASH_LBLOCK];
+ * int num;
+ * ...
+ * } HASH_CTX;
+ * HASH_UPDATE
+ * name of "Update" function, implemented here.
+ * HASH_TRANSFORM
+ * name of "Transform" function, implemented here.
+ * HASH_FINAL
+ * name of "Final" function, implemented here.
+ * HASH_BLOCK_HOST_ORDER
+ * name of "block" function treating *aligned* input message
+ * in host byte order, implemented externally.
+ * HASH_BLOCK_DATA_ORDER
+ * name of "block" function treating *unaligned* input message
+ * in original (data) byte order, implemented externally (it
+ * actually is optional if data and host are of the same
+ * "endianess").
+ * HASH_MAKE_STRING
+ * macro convering context variables to an ASCII hash string.
+ *
+ * Optional macros:
+ *
+ * B_ENDIAN or L_ENDIAN
+ * defines host byte-order.
+ * HASH_LONG_LOG2
+ * defaults to 2 if not states otherwise.
+ * HASH_LBLOCK
+ * assumed to be HASH_CBLOCK/4 if not stated otherwise.
+ * HASH_BLOCK_DATA_ORDER_ALIGNED
+ * alternative "block" function capable of treating
+ * aligned input message in original (data) order,
+ * implemented externally.
+ *
+ * MD5 example:
+ *
+ * #define DATA_ORDER_IS_LITTLE_ENDIAN
+ *
+ * #define HASH_LONG MD5_LONG
+ * #define HASH_LONG_LOG2 MD5_LONG_LOG2
+ * #define HASH_CTX MD5_CTX
+ * #define HASH_CBLOCK MD5_CBLOCK
+ * #define HASH_LBLOCK MD5_LBLOCK
+ * #define HASH_UPDATE MD5_Update
+ * #define HASH_TRANSFORM MD5_Transform
+ * #define HASH_FINAL MD5_Final
+ * #define HASH_BLOCK_HOST_ORDER md5_block_host_order
+ * #define HASH_BLOCK_DATA_ORDER md5_block_data_order
+ *
+ * <appro@fy.chalmers.se>
+ */
+
+#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+#error "DATA_ORDER must be defined!"
+#endif
+
+#ifndef HASH_CBLOCK
+#error "HASH_CBLOCK must be defined!"
+#endif
+#ifndef HASH_LONG
+#error "HASH_LONG must be defined!"
+#endif
+#ifndef HASH_CTX
+#error "HASH_CTX must be defined!"
+#endif
+
+#ifndef HASH_UPDATE
+#error "HASH_UPDATE must be defined!"
+#endif
+#ifndef HASH_TRANSFORM
+#error "HASH_TRANSFORM must be defined!"
+#endif
+#ifndef HASH_FINAL
+#error "HASH_FINAL must be defined!"
+#endif
+
+#ifndef HASH_BLOCK_HOST_ORDER
+#error "HASH_BLOCK_HOST_ORDER must be defined!"
+#endif
+
+#if 0
+/*
+ * Moved below as it's required only if HASH_BLOCK_DATA_ORDER_ALIGNED
+ * isn't defined.
+ */
+#ifndef HASH_BLOCK_DATA_ORDER
+#error "HASH_BLOCK_DATA_ORDER must be defined!"
+#endif
+#endif
+
+#ifndef HASH_LBLOCK
+#define HASH_LBLOCK (HASH_CBLOCK/4)
+#endif
+
+#ifndef HASH_LONG_LOG2
+#define HASH_LONG_LOG2 2
+#endif
+
+/*
+ * Engage compiler specific rotate intrinsic function if available.
+ */
+#undef ROTATE
+#ifndef PEDANTIC
+# if defined(_MSC_VER)
+# define ROTATE(a,n) _lrotl(a,n)
+# elif defined(__MWERKS__)
+# if defined(__POWERPC__)
+# define ROTATE(a,n) __rlwinm(a,n,0,31)
+# elif defined(__MC68K__)
+ /* Motorola specific tweak. <appro@fy.chalmers.se> */
+# define ROTATE(a,n) ( n<24 ? __rol(a,n) : __ror(a,32-n) )
+# else
+# define ROTATE(a,n) __rol(a,n)
+# endif
+# elif defined(__GNUC__) && __GNUC__>=2 && !defined(NO_ASM) && !defined(NO_INLINE_ASM)
+ /*
+ * Some GNU C inline assembler templates. Note that these are
+ * rotates by *constant* number of bits! But that's exactly
+ * what we need here...
+ *
+ * <appro@fy.chalmers.se>
+ */
+# if defined(__i386)
+# define ROTATE(a,n) ({ register unsigned int ret; \
+ asm ( \
+ "roll %1,%0" \
+ : "=r"(ret) \
+ : "I"(n), "0"(a) \
+ : "cc"); \
+ ret; \
+ })
+# elif defined(__powerpc) || defined(__ppc)
+# define ROTATE(a,n) ({ register unsigned int ret; \
+ asm ( \
+ "rlwinm %0,%1,%2,0,31" \
+ : "=r"(ret) \
+ : "r"(a), "I"(n)); \
+ ret; \
+ })
+# endif
+# endif
+
+/*
+ * Engage compiler specific "fetch in reverse byte order"
+ * intrinsic function if available.
+ */
+# if defined(__GNUC__) && __GNUC__>=2 && !defined(NO_ASM) && !defined(NO_INLINE_ASM)
+ /* some GNU C inline assembler templates by <appro@fy.chalmers.se> */
+# if defined(__i386) && !defined(I386_ONLY)
+# define BE_FETCH32(a) ({ register unsigned int l=(a);\
+ asm ( \
+ "bswapl %0" \
+ : "=r"(l) : "0"(l)); \
+ l; \
+ })
+# elif defined(__powerpc)
+# define LE_FETCH32(a) ({ register unsigned int l; \
+ asm ( \
+ "lwbrx %0,0,%1" \
+ : "=r"(l) \
+ : "r"(a)); \
+ l; \
+ })
+
+# elif defined(__sparc) && defined(ULTRASPARC)
+# define LE_FETCH32(a) ({ register unsigned int l; \
+ asm ( \
+ "lda [%1]#ASI_PRIMARY_LITTLE,%0"\
+ : "=r"(l) \
+ : "r"(a)); \
+ l; \
+ })
+# endif
+# endif
+#endif /* PEDANTIC */
+
+#if HASH_LONG_LOG2==2 /* Engage only if sizeof(HASH_LONG)== 4 */
+/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */
+#ifdef ROTATE
+/* 5 instructions with rotate instruction, else 9 */
+#define REVERSE_FETCH32(a,l) ( \
+ l=*(const HASH_LONG *)(a), \
+ ((ROTATE(l,8)&0x00FF00FF)|(ROTATE((l&0x00FF00FF),24))) \
+ )
+#else
+/* 6 instructions with rotate instruction, else 8 */
+#define REVERSE_FETCH32(a,l) ( \
+ l=*(const HASH_LONG *)(a), \
+ l=(((l>>8)&0x00FF00FF)|((l&0x00FF00FF)<<8)), \
+ ROTATE(l,16) \
+ )
+/*
+ * Originally the middle line started with l=(((l&0xFF00FF00)>>8)|...
+ * It's rewritten as above for two reasons:
+ * - RISCs aren't good at long constants and have to explicitely
+ * compose 'em with several (well, usually 2) instructions in a
+ * register before performing the actual operation and (as you
+ * already realized:-) having same constant should inspire the
+ * compiler to permanently allocate the only register for it;
+ * - most modern CPUs have two ALUs, but usually only one has
+ * circuitry for shifts:-( this minor tweak inspires compiler
+ * to schedule shift instructions in a better way...
+ *
+ * <appro@fy.chalmers.se>
+ */
+#endif
+#endif
+
+#ifndef ROTATE
+#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+/*
+ * Make some obvious choices. E.g., HASH_BLOCK_DATA_ORDER_ALIGNED
+ * and HASH_BLOCK_HOST_ORDER ought to be the same if input data
+ * and host are of the same "endianess". It's possible to mask
+ * this with blank #define HASH_BLOCK_DATA_ORDER though...
+ *
+ * <appro@fy.chalmers.se>
+ */
+#if defined(B_ENDIAN)
+# if defined(DATA_ORDER_IS_BIG_ENDIAN)
+# if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED) && HASH_LONG_LOG2==2
+# define HASH_BLOCK_DATA_ORDER_ALIGNED HASH_BLOCK_HOST_ORDER
+# endif
+# elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+# ifndef HOST_FETCH32
+# ifdef LE_FETCH32
+# define HOST_FETCH32(p,l) LE_FETCH32(p)
+# elif defined(REVERSE_FETCH32)
+# define HOST_FETCH32(p,l) REVERSE_FETCH32(p,l)
+# endif
+# endif
+# endif
+#elif defined(L_ENDIAN)
+# if defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+# if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED) && HASH_LONG_LOG2==2
+# define HASH_BLOCK_DATA_ORDER_ALIGNED HASH_BLOCK_HOST_ORDER
+# endif
+# elif defined(DATA_ORDER_IS_BIG_ENDIAN)
+# ifndef HOST_FETCH32
+# ifdef BE_FETCH32
+# define HOST_FETCH32(p,l) BE_FETCH32(p)
+# elif defined(REVERSE_FETCH32)
+# define HOST_FETCH32(p,l) REVERSE_FETCH32(p,l)
+# endif
+# endif
+# endif
+#endif
+
+#if !defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+#ifndef HASH_BLOCK_DATA_ORDER
+#error "HASH_BLOCK_DATA_ORDER must be defined!"
+#endif
+#endif
+
+#if defined(DATA_ORDER_IS_BIG_ENDIAN)
+
+#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++))) ), \
+ l)
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
+ case 0: l =((unsigned long)(*((c)++)))<<24; \
+ case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ case 3: l|=((unsigned long)(*((c)++))); \
+ } }
+#define HOST_p_c2l_p(c,l,sc,len) { \
+ switch (sc) { \
+ case 0: l =((unsigned long)(*((c)++)))<<24; \
+ if (--len == 0) break; \
+ case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ if (--len == 0) break; \
+ case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ } }
+/* NOTE the pointer is not incremented at the end of this */
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
+ case 3: l =((unsigned long)(*(--(c))))<< 8; \
+ case 2: l|=((unsigned long)(*(--(c))))<<16; \
+ case 1: l|=((unsigned long)(*(--(c))))<<24; \
+ } }
+#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff), \
+ l)
+
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+
+#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<<24), \
+ l)
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ case 3: l|=((unsigned long)(*((c)++)))<<24; \
+ } }
+#define HOST_p_c2l_p(c,l,sc,len) { \
+ switch (sc) { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ if (--len == 0) break; \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ if (--len == 0) break; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ } }
+/* NOTE the pointer is not incremented at the end of this */
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
+ case 3: l =((unsigned long)(*(--(c))))<<16; \
+ case 2: l|=((unsigned long)(*(--(c))))<< 8; \
+ case 1: l|=((unsigned long)(*(--(c)))); \
+ } }
+#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ l)
+
+#endif
+
+/*
+ * Time for some action:-)
+ */
+
+void HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
+ {
+ const unsigned char *data=data_;
+ register HASH_LONG * p;
+ register unsigned long l;
+ int sw,sc,ew,ec;
+
+ if (len==0) return;
+
+ l=(c->Nl+(len<<3))&0xffffffffL;
+ /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to
+ * Wei Dai <weidai@eskimo.com> for pointing it out. */
+ if (l < c->Nl) /* overflow */
+ c->Nh++;
+ c->Nh+=(len>>29);
+ c->Nl=l;
+
+ if (c->num != 0)
+ {
+ p=c->data;
+ sw=c->num>>2;
+ sc=c->num&0x03;
+
+ if ((c->num+len) >= HASH_CBLOCK)
+ {
+ l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
+ for (; sw<HASH_LBLOCK; sw++)
+ {
+ HOST_c2l(data,l); p[sw]=l;
+ }
+ HASH_BLOCK_HOST_ORDER (c,p,1);
+ len-=(HASH_CBLOCK-c->num);
+ c->num=0;
+ /* drop through and do the rest */
+ }
+ else
+ {
+ c->num+=len;
+ if ((sc+len) < 4) /* ugly, add char's to a word */
+ {
+ l=p[sw]; HOST_p_c2l_p(data,l,sc,len); p[sw]=l;
+ }
+ else
+ {
+ ew=(c->num>>2);
+ ec=(c->num&0x03);
+ l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
+ for (; sw < ew; sw++)
+ {
+ HOST_c2l(data,l); p[sw]=l;
+ }
+ if (ec)
+ {
+ HOST_c2l_p(data,l,ec); p[sw]=l;
+ }
+ }
+ return;
+ }
+ }
+
+ sw=len/HASH_CBLOCK;
+ if (sw > 0)
+ {
+#if defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+ /*
+ * Note that HASH_BLOCK_DATA_ORDER_ALIGNED gets defined
+ * only if sizeof(HASH_LONG)==4.
+ */
+ if ((((unsigned long)data)%4) == 0)
+ {
+ /* data is properly aligned so that we can cast it: */
+ HASH_BLOCK_DATA_ORDER_ALIGNED (c,(HASH_LONG *)data,sw);
+ sw*=HASH_CBLOCK;
+ data+=sw;
+ len-=sw;
+ }
+ else
+#if !defined(HASH_BLOCK_DATA_ORDER)
+ while (sw--)
+ {
+ memcpy (p=c->data,data,HASH_CBLOCK);
+ HASH_BLOCK_DATA_ORDER_ALIGNED(c,p,1);
+ data+=HASH_CBLOCK;
+ len-=HASH_CBLOCK;
+ }
+#endif
+#endif
+#if defined(HASH_BLOCK_DATA_ORDER)
+ {
+ HASH_BLOCK_DATA_ORDER(c,data,sw);
+ sw*=HASH_CBLOCK;
+ data+=sw;
+ len-=sw;
+ }
+#endif
+ }
+
+ if (len!=0)
+ {
+ p = c->data;
+ c->num = len;
+ ew=len>>2; /* words to copy */
+ ec=len&0x03;
+ for (; ew; ew--,p++)
+ {
+ HOST_c2l(data,l); *p=l;
+ }
+ HOST_c2l_p(data,l,ec);
+ *p=l;
+ }
+ }
+
+
+void HASH_TRANSFORM (HASH_CTX *c, const unsigned char *data)
+ {
+#if defined(HASH_BLOCK_DATA_ORDER_ALIGNED)
+ if ((((unsigned long)data)%4) == 0)
+ /* data is properly aligned so that we can cast it: */
+ HASH_BLOCK_DATA_ORDER_ALIGNED (c,(HASH_LONG *)data,1);
+ else
+#if !defined(HASH_BLOCK_DATA_ORDER)
+ {
+ memcpy (c->data,data,HASH_CBLOCK);
+ HASH_BLOCK_DATA_ORDER_ALIGNED (c,c->data,1);
+ }
+#endif
+#endif
+#if defined(HASH_BLOCK_DATA_ORDER)
+ HASH_BLOCK_DATA_ORDER (c,data,1);
+#endif
+ }
+
+
+void HASH_FINAL (unsigned char *md, HASH_CTX *c)
+ {
+ register HASH_LONG *p;
+ register unsigned long l;
+ register int i,j;
+ static const unsigned char end[4]={0x80,0x00,0x00,0x00};
+ const unsigned char *cp=end;
+
+ /* c->num should definitly have room for at least one more byte. */
+ p=c->data;
+ i=c->num>>2;
+ j=c->num&0x03;
+
+#if 0
+ /* purify often complains about the following line as an
+ * Uninitialized Memory Read. While this can be true, the
+ * following p_c2l macro will reset l when that case is true.
+ * This is because j&0x03 contains the number of 'valid' bytes
+ * already in p[i]. If and only if j&0x03 == 0, the UMR will
+ * occur but this is also the only time p_c2l will do
+ * l= *(cp++) instead of l|= *(cp++)
+ * Many thanks to Alex Tang <altitude@cic.net> for pickup this
+ * 'potential bug' */
+#ifdef PURIFY
+ if (j==0) p[i]=0; /* Yeah, but that's not the way to fix it:-) */
+#endif
+ l=p[i];
+#else
+ l = (j==0) ? 0 : p[i];
+#endif
+ HOST_p_c2l(cp,l,j); p[i++]=l; /* i is the next 'undefined word' */
+
+ if (i>(HASH_LBLOCK-2)) /* save room for Nl and Nh */
+ {
+ if (i<HASH_LBLOCK) p[i]=0;
+ HASH_BLOCK_HOST_ORDER (c,p,1);
+ i=0;
+ }
+ for (; i<(HASH_LBLOCK-2); i++)
+ p[i]=0;
+
+#if defined(DATA_ORDER_IS_BIG_ENDIAN)
+ p[HASH_LBLOCK-2]=c->Nh;
+ p[HASH_LBLOCK-1]=c->Nl;
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+ p[HASH_LBLOCK-2]=c->Nl;
+ p[HASH_LBLOCK-1]=c->Nh;
+#endif
+ HASH_BLOCK_HOST_ORDER (c,p,1);
+
+#ifndef HASH_MAKE_STRING
+#error "HASH_MAKE_STRING must be defined!"
+#else
+ HASH_MAKE_STRING(c,md);
+#endif
+
+ c->num=0;
+ /* clear stuff, HASH_BLOCK may be leaving some stuff on the stack
+ * but I'm not worried :-)
+ memset((void *)c,0,sizeof(HASH_CTX));
+ */
+ }
diff --git a/lib/libcrypto/libaes/Makefile b/lib/libcrypto/libaes/Makefile
new file mode 100644
index 000000000..7e4cff6e8
--- /dev/null
+++ b/lib/libcrypto/libaes/Makefile
@@ -0,0 +1,40 @@
+CFLAGS=-O3 -fomit-frame-pointer -D__KERNEL__ -Wall -Wcast-qual $(EXTRA_CFLAGS)
+INC=-I../include
+
+AES_CORE_OBJ:=aes.o
+
+ASM-$(ARCH_ASM):=1
+ASM_X86:=$(ASM-i586)$(ASM-i686)
+ifneq ($(strip $(ASM_X86)),)
+AES_CORE_OBJ:= asm/aes-i586.o
+endif
+
+LIBOBJ := aes_xcbc_mac.o aes_cbc.o $(AES_CORE_OBJ)
+LDLIBS := -laes
+LDFLAGS := -L.
+
+BLIB := libaes.a
+
+L_TARGET := $(BLIB)
+
+.c.o:
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c $< -o $@
+
+.S.o:
+ $(CC) $(AFLAGS) -c $< -o $@
+
+$(BLIB): $(LIBOBJ)
+ /bin/rm -f $(BLIB)
+ ar cr $(BLIB) $(LIBOBJ)
+ -if test -s /bin/ranlib; then /bin/ranlib $(BLIB); \
+ else if test -s /usr/bin/ranlib; then /usr/bin/ranlib $(BLIB); \
+ else exit 0; fi; fi
+
+testx: test_main_mac.o $(BLIB)
+ $(CC) -o $@ $^
+
+test: test_main.o $(BLIB)
+ $(CC) -o $@ $^
+
+clean:
+ rm -f *.[oa] asm/*.o core $(TARGET) test testx
diff --git a/lib/libcrypto/libaes/aes.c b/lib/libcrypto/libaes/aes.c
new file mode 100644
index 000000000..1748119ac
--- /dev/null
+++ b/lib/libcrypto/libaes/aes.c
@@ -0,0 +1,1415 @@
+// I retain copyright in this code but I encourage its free use provided
+// that I don't carry any responsibility for the results. I am especially
+// happy to see it used in free and open source software. If you do use
+// it I would appreciate an acknowledgement of its origin in the code or
+// the product that results and I would also appreciate knowing a little
+// about the use to which it is being put. I am grateful to Frank Yellin
+// for some ideas that are used in this implementation.
+//
+// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
+//
+// This is an implementation of the AES encryption algorithm (Rijndael)
+// designed by Joan Daemen and Vincent Rijmen. This version is designed
+// to provide both fixed and dynamic block and key lengths and can also
+// run with either big or little endian internal byte order (see aes.h).
+// It inputs block and key lengths in bytes with the legal values being
+// 16, 24 and 32.
+
+/*
+ * Modified by Jari Ruusu, May 1 2001
+ * - Fixed some compile warnings, code was ok but gcc warned anyway.
+ * - Changed basic types: byte -> unsigned char, word -> u_int32_t
+ * - Major name space cleanup: Names visible to outside now begin
+ * with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
+ * - Removed C++ and DLL support as part of name space cleanup.
+ * - Eliminated unnecessary recomputation of tables. (actual bug fix)
+ * - Merged precomputed constant tables to aes.c file.
+ * - Removed data alignment restrictions for portability reasons.
+ * - Made block and key lengths accept bit count (128/192/256)
+ * as well byte count (16/24/32).
+ * - Removed all error checks. This change also eliminated the need
+ * to preinitialize the context struct to zero.
+ * - Removed some totally unused constants.
+ */
+
+#include "aes.h"
+
+// CONFIGURATION OPTIONS (see also aes.h)
+//
+// 1. Define UNROLL for full loop unrolling in encryption and decryption.
+// 2. Define PARTIAL_UNROLL to unroll two loops in encryption and decryption.
+// 3. Define FIXED_TABLES for compiled rather than dynamic tables.
+// 4. Define FF_TABLES to use tables for field multiplies and inverses.
+// Do not enable this without understanding stack space requirements.
+// 5. Define ARRAYS to use arrays to hold the local state block. If this
+// is not defined, individually declared 32-bit words are used.
+// 6. Define FAST_VARIABLE if a high speed variable block implementation
+// is needed (essentially three separate fixed block size code sequences)
+// 7. Define either ONE_TABLE or FOUR_TABLES for a fast table driven
+// version using 1 table (2 kbytes of table space) or 4 tables (8
+// kbytes of table space) for higher speed.
+// 8. Define either ONE_LR_TABLE or FOUR_LR_TABLES for a further speed
+// increase by using tables for the last rounds but with more table
+// space (2 or 8 kbytes extra).
+// 9. If neither ONE_TABLE nor FOUR_TABLES is defined, a compact but
+// slower version is provided.
+// 10. If fast decryption key scheduling is needed define ONE_IM_TABLE
+// or FOUR_IM_TABLES for higher speed (2 or 8 kbytes extra).
+
+#define UNROLL
+//#define PARTIAL_UNROLL
+
+#define FIXED_TABLES
+//#define FF_TABLES
+//#define ARRAYS
+#define FAST_VARIABLE
+
+//#define ONE_TABLE
+#define FOUR_TABLES
+
+//#define ONE_LR_TABLE
+#define FOUR_LR_TABLES
+
+//#define ONE_IM_TABLE
+#define FOUR_IM_TABLES
+
+#if defined(UNROLL) && defined (PARTIAL_UNROLL)
+#error both UNROLL and PARTIAL_UNROLL are defined
+#endif
+
+#if defined(ONE_TABLE) && defined (FOUR_TABLES)
+#error both ONE_TABLE and FOUR_TABLES are defined
+#endif
+
+#if defined(ONE_LR_TABLE) && defined (FOUR_LR_TABLES)
+#error both ONE_LR_TABLE and FOUR_LR_TABLES are defined
+#endif
+
+#if defined(ONE_IM_TABLE) && defined (FOUR_IM_TABLES)
+#error both ONE_IM_TABLE and FOUR_IM_TABLES are defined
+#endif
+
+#if defined(AES_BLOCK_SIZE) && AES_BLOCK_SIZE != 16 && AES_BLOCK_SIZE != 24 && AES_BLOCK_SIZE != 32
+#error an illegal block size has been specified
+#endif
+
+// upr(x,n): rotates bytes within words by n positions, moving bytes
+// to higher index positions with wrap around into low positions
+// ups(x,n): moves bytes by n positions to higher index positions in
+// words but without wrap around
+// bval(x,n): extracts a byte from a word
+
+#define upr(x,n) (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n))))
+#define ups(x,n) ((x) << 8 * (n))
+#define bval(x,n) ((unsigned char)((x) >> 8 * (n)))
+#define bytes2word(b0, b1, b2, b3) \
+ ((u_int32_t)(b3) << 24 | (u_int32_t)(b2) << 16 | (u_int32_t)(b1) << 8 | (b0))
+
+
+/* little endian processor without data alignment restrictions: AES_LE_OK */
+/* original code: i386 */
+#if defined(i386) || defined(_I386) || defined(__i386__) || defined(__i386)
+#define AES_LE_OK 1
+/* added (tested): alpha --jjo */
+#elif defined(__alpha__)|| defined (__alpha)
+#define AES_LE_OK 1
+/* added (tested): ia64 --jjo */
+#elif defined(__ia64__)|| defined (__ia64)
+#define AES_LE_OK 1
+#endif
+
+#ifdef AES_LE_OK
+/* little endian processor without data alignment restrictions */
+#define word_in(x) *(u_int32_t*)(x)
+#define const_word_in(x) *(const u_int32_t*)(x)
+#define word_out(x,v) *(u_int32_t*)(x) = (v)
+#define const_word_out(x,v) *(const u_int32_t*)(x) = (v)
+#else
+/* slower but generic big endian or with data alignment restrictions */
+/* some additional "const" touches to stop "gcc -Wcast-qual" complains --jjo */
+#define word_in(x) ((u_int32_t)(((unsigned char *)(x))[0])|((u_int32_t)(((unsigned char *)(x))[1])<<8)|((u_int32_t)(((unsigned char *)(x))[2])<<16)|((u_int32_t)(((unsigned char *)(x))[3])<<24))
+#define const_word_in(x) ((const u_int32_t)(((const unsigned char *)(x))[0])|((const u_int32_t)(((const unsigned char *)(x))[1])<<8)|((const u_int32_t)(((const unsigned char *)(x))[2])<<16)|((const u_int32_t)(((const unsigned char *)(x))[3])<<24))
+#define word_out(x,v) ((unsigned char *)(x))[0]=(v),((unsigned char *)(x))[1]=((v)>>8),((unsigned char *)(x))[2]=((v)>>16),((unsigned char *)(x))[3]=((v)>>24)
+#define const_word_out(x,v) ((const unsigned char *)(x))[0]=(v),((const unsigned char *)(x))[1]=((v)>>8),((const unsigned char *)(x))[2]=((v)>>16),((const unsigned char *)(x))[3]=((v)>>24)
+#endif
+
+// Disable at least some poor combinations of options
+
+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
+#define FIXED_TABLES
+#undef UNROLL
+#undef ONE_LR_TABLE
+#undef FOUR_LR_TABLES
+#undef ONE_IM_TABLE
+#undef FOUR_IM_TABLES
+#elif !defined(FOUR_TABLES)
+#ifdef FOUR_LR_TABLES
+#undef FOUR_LR_TABLES
+#define ONE_LR_TABLE
+#endif
+#ifdef FOUR_IM_TABLES
+#undef FOUR_IM_TABLES
+#define ONE_IM_TABLE
+#endif
+#elif !defined(AES_BLOCK_SIZE)
+#if defined(UNROLL)
+#define PARTIAL_UNROLL
+#undef UNROLL
+#endif
+#endif
+
+// the finite field modular polynomial and elements
+
+#define ff_poly 0x011b
+#define ff_hi 0x80
+
+// multiply four bytes in GF(2^8) by 'x' {02} in parallel
+
+#define m1 0x80808080
+#define m2 0x7f7f7f7f
+#define m3 0x0000001b
+#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * m3))
+
+// The following defines provide alternative definitions of FFmulX that might
+// give improved performance if a fast 32-bit multiply is not available. Note
+// that a temporary variable u needs to be defined where FFmulX is used.
+
+// #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6))
+// #define m4 0x1b1b1b1b
+// #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4)
+
+// perform column mix operation on four bytes in parallel
+
+#define fwd_mcol(x) (f2 = FFmulX(x), f2 ^ upr(x ^ f2,3) ^ upr(x,2) ^ upr(x,1))
+
+#if defined(FIXED_TABLES)
+
+// the S-Box table
+
+static const unsigned char s_box[256] =
+{
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+
+// the inverse S-Box table
+
+static const unsigned char inv_s_box[256] =
+{
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
+ 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+ 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
+ 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
+ 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
+ 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
+ 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+ 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
+ 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
+ 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+ 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
+ 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
+ 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+ 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
+ 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
+ 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+};
+
+#define w0(p) 0x000000##p
+
+// Number of elements required in this table for different
+// block and key lengths is:
+//
+// Nk = 4 6 8
+// ----------
+// Nb = 4 | 10 8 7
+// 6 | 19 12 11
+// 8 | 29 19 14
+//
+// this table can be a table of bytes if the key schedule
+// code is adjusted accordingly
+
+static const u_int32_t rcon_tab[29] =
+{
+ w0(01), w0(02), w0(04), w0(08),
+ w0(10), w0(20), w0(40), w0(80),
+ w0(1b), w0(36), w0(6c), w0(d8),
+ w0(ab), w0(4d), w0(9a), w0(2f),
+ w0(5e), w0(bc), w0(63), w0(c6),
+ w0(97), w0(35), w0(6a), w0(d4),
+ w0(b3), w0(7d), w0(fa), w0(ef),
+ w0(c5)
+};
+
+#undef w0
+
+#define r0(p,q,r,s) 0x##p##q##r##s
+#define r1(p,q,r,s) 0x##q##r##s##p
+#define r2(p,q,r,s) 0x##r##s##p##q
+#define r3(p,q,r,s) 0x##s##p##q##r
+#define w0(p) 0x000000##p
+#define w1(p) 0x0000##p##00
+#define w2(p) 0x00##p##0000
+#define w3(p) 0x##p##000000
+
+#if defined(FIXED_TABLES) && (defined(ONE_TABLE) || defined(FOUR_TABLES))
+
+// data for forward tables (other than last round)
+
+#define f_table \
+ r(a5,63,63,c6), r(84,7c,7c,f8), r(99,77,77,ee), r(8d,7b,7b,f6),\
+ r(0d,f2,f2,ff), r(bd,6b,6b,d6), r(b1,6f,6f,de), r(54,c5,c5,91),\
+ r(50,30,30,60), r(03,01,01,02), r(a9,67,67,ce), r(7d,2b,2b,56),\
+ r(19,fe,fe,e7), r(62,d7,d7,b5), r(e6,ab,ab,4d), r(9a,76,76,ec),\
+ r(45,ca,ca,8f), r(9d,82,82,1f), r(40,c9,c9,89), r(87,7d,7d,fa),\
+ r(15,fa,fa,ef), r(eb,59,59,b2), r(c9,47,47,8e), r(0b,f0,f0,fb),\
+ r(ec,ad,ad,41), r(67,d4,d4,b3), r(fd,a2,a2,5f), r(ea,af,af,45),\
+ r(bf,9c,9c,23), r(f7,a4,a4,53), r(96,72,72,e4), r(5b,c0,c0,9b),\
+ r(c2,b7,b7,75), r(1c,fd,fd,e1), r(ae,93,93,3d), r(6a,26,26,4c),\
+ r(5a,36,36,6c), r(41,3f,3f,7e), r(02,f7,f7,f5), r(4f,cc,cc,83),\
+ r(5c,34,34,68), r(f4,a5,a5,51), r(34,e5,e5,d1), r(08,f1,f1,f9),\
+ r(93,71,71,e2), r(73,d8,d8,ab), r(53,31,31,62), r(3f,15,15,2a),\
+ r(0c,04,04,08), r(52,c7,c7,95), r(65,23,23,46), r(5e,c3,c3,9d),\
+ r(28,18,18,30), r(a1,96,96,37), r(0f,05,05,0a), r(b5,9a,9a,2f),\
+ r(09,07,07,0e), r(36,12,12,24), r(9b,80,80,1b), r(3d,e2,e2,df),\
+ r(26,eb,eb,cd), r(69,27,27,4e), r(cd,b2,b2,7f), r(9f,75,75,ea),\
+ r(1b,09,09,12), r(9e,83,83,1d), r(74,2c,2c,58), r(2e,1a,1a,34),\
+ r(2d,1b,1b,36), r(b2,6e,6e,dc), r(ee,5a,5a,b4), r(fb,a0,a0,5b),\
+ r(f6,52,52,a4), r(4d,3b,3b,76), r(61,d6,d6,b7), r(ce,b3,b3,7d),\
+ r(7b,29,29,52), r(3e,e3,e3,dd), r(71,2f,2f,5e), r(97,84,84,13),\
+ r(f5,53,53,a6), r(68,d1,d1,b9), r(00,00,00,00), r(2c,ed,ed,c1),\
+ r(60,20,20,40), r(1f,fc,fc,e3), r(c8,b1,b1,79), r(ed,5b,5b,b6),\
+ r(be,6a,6a,d4), r(46,cb,cb,8d), r(d9,be,be,67), r(4b,39,39,72),\
+ r(de,4a,4a,94), r(d4,4c,4c,98), r(e8,58,58,b0), r(4a,cf,cf,85),\
+ r(6b,d0,d0,bb), r(2a,ef,ef,c5), r(e5,aa,aa,4f), r(16,fb,fb,ed),\
+ r(c5,43,43,86), r(d7,4d,4d,9a), r(55,33,33,66), r(94,85,85,11),\
+ r(cf,45,45,8a), r(10,f9,f9,e9), r(06,02,02,04), r(81,7f,7f,fe),\
+ r(f0,50,50,a0), r(44,3c,3c,78), r(ba,9f,9f,25), r(e3,a8,a8,4b),\
+ r(f3,51,51,a2), r(fe,a3,a3,5d), r(c0,40,40,80), r(8a,8f,8f,05),\
+ r(ad,92,92,3f), r(bc,9d,9d,21), r(48,38,38,70), r(04,f5,f5,f1),\
+ r(df,bc,bc,63), r(c1,b6,b6,77), r(75,da,da,af), r(63,21,21,42),\
+ r(30,10,10,20), r(1a,ff,ff,e5), r(0e,f3,f3,fd), r(6d,d2,d2,bf),\
+ r(4c,cd,cd,81), r(14,0c,0c,18), r(35,13,13,26), r(2f,ec,ec,c3),\
+ r(e1,5f,5f,be), r(a2,97,97,35), r(cc,44,44,88), r(39,17,17,2e),\
+ r(57,c4,c4,93), r(f2,a7,a7,55), r(82,7e,7e,fc), r(47,3d,3d,7a),\
+ r(ac,64,64,c8), r(e7,5d,5d,ba), r(2b,19,19,32), r(95,73,73,e6),\
+ r(a0,60,60,c0), r(98,81,81,19), r(d1,4f,4f,9e), r(7f,dc,dc,a3),\
+ r(66,22,22,44), r(7e,2a,2a,54), r(ab,90,90,3b), r(83,88,88,0b),\
+ r(ca,46,46,8c), r(29,ee,ee,c7), r(d3,b8,b8,6b), r(3c,14,14,28),\
+ r(79,de,de,a7), r(e2,5e,5e,bc), r(1d,0b,0b,16), r(76,db,db,ad),\
+ r(3b,e0,e0,db), r(56,32,32,64), r(4e,3a,3a,74), r(1e,0a,0a,14),\
+ r(db,49,49,92), r(0a,06,06,0c), r(6c,24,24,48), r(e4,5c,5c,b8),\
+ r(5d,c2,c2,9f), r(6e,d3,d3,bd), r(ef,ac,ac,43), r(a6,62,62,c4),\
+ r(a8,91,91,39), r(a4,95,95,31), r(37,e4,e4,d3), r(8b,79,79,f2),\
+ r(32,e7,e7,d5), r(43,c8,c8,8b), r(59,37,37,6e), r(b7,6d,6d,da),\
+ r(8c,8d,8d,01), r(64,d5,d5,b1), r(d2,4e,4e,9c), r(e0,a9,a9,49),\
+ r(b4,6c,6c,d8), r(fa,56,56,ac), r(07,f4,f4,f3), r(25,ea,ea,cf),\
+ r(af,65,65,ca), r(8e,7a,7a,f4), r(e9,ae,ae,47), r(18,08,08,10),\
+ r(d5,ba,ba,6f), r(88,78,78,f0), r(6f,25,25,4a), r(72,2e,2e,5c),\
+ r(24,1c,1c,38), r(f1,a6,a6,57), r(c7,b4,b4,73), r(51,c6,c6,97),\
+ r(23,e8,e8,cb), r(7c,dd,dd,a1), r(9c,74,74,e8), r(21,1f,1f,3e),\
+ r(dd,4b,4b,96), r(dc,bd,bd,61), r(86,8b,8b,0d), r(85,8a,8a,0f),\
+ r(90,70,70,e0), r(42,3e,3e,7c), r(c4,b5,b5,71), r(aa,66,66,cc),\
+ r(d8,48,48,90), r(05,03,03,06), r(01,f6,f6,f7), r(12,0e,0e,1c),\
+ r(a3,61,61,c2), r(5f,35,35,6a), r(f9,57,57,ae), r(d0,b9,b9,69),\
+ r(91,86,86,17), r(58,c1,c1,99), r(27,1d,1d,3a), r(b9,9e,9e,27),\
+ r(38,e1,e1,d9), r(13,f8,f8,eb), r(b3,98,98,2b), r(33,11,11,22),\
+ r(bb,69,69,d2), r(70,d9,d9,a9), r(89,8e,8e,07), r(a7,94,94,33),\
+ r(b6,9b,9b,2d), r(22,1e,1e,3c), r(92,87,87,15), r(20,e9,e9,c9),\
+ r(49,ce,ce,87), r(ff,55,55,aa), r(78,28,28,50), r(7a,df,df,a5),\
+ r(8f,8c,8c,03), r(f8,a1,a1,59), r(80,89,89,09), r(17,0d,0d,1a),\
+ r(da,bf,bf,65), r(31,e6,e6,d7), r(c6,42,42,84), r(b8,68,68,d0),\
+ r(c3,41,41,82), r(b0,99,99,29), r(77,2d,2d,5a), r(11,0f,0f,1e),\
+ r(cb,b0,b0,7b), r(fc,54,54,a8), r(d6,bb,bb,6d), r(3a,16,16,2c)
+
+// data for inverse tables (other than last round)
+
+#define i_table \
+ r(50,a7,f4,51), r(53,65,41,7e), r(c3,a4,17,1a), r(96,5e,27,3a),\
+ r(cb,6b,ab,3b), r(f1,45,9d,1f), r(ab,58,fa,ac), r(93,03,e3,4b),\
+ r(55,fa,30,20), r(f6,6d,76,ad), r(91,76,cc,88), r(25,4c,02,f5),\
+ r(fc,d7,e5,4f), r(d7,cb,2a,c5), r(80,44,35,26), r(8f,a3,62,b5),\
+ r(49,5a,b1,de), r(67,1b,ba,25), r(98,0e,ea,45), r(e1,c0,fe,5d),\
+ r(02,75,2f,c3), r(12,f0,4c,81), r(a3,97,46,8d), r(c6,f9,d3,6b),\
+ r(e7,5f,8f,03), r(95,9c,92,15), r(eb,7a,6d,bf), r(da,59,52,95),\
+ r(2d,83,be,d4), r(d3,21,74,58), r(29,69,e0,49), r(44,c8,c9,8e),\
+ r(6a,89,c2,75), r(78,79,8e,f4), r(6b,3e,58,99), r(dd,71,b9,27),\
+ r(b6,4f,e1,be), r(17,ad,88,f0), r(66,ac,20,c9), r(b4,3a,ce,7d),\
+ r(18,4a,df,63), r(82,31,1a,e5), r(60,33,51,97), r(45,7f,53,62),\
+ r(e0,77,64,b1), r(84,ae,6b,bb), r(1c,a0,81,fe), r(94,2b,08,f9),\
+ r(58,68,48,70), r(19,fd,45,8f), r(87,6c,de,94), r(b7,f8,7b,52),\
+ r(23,d3,73,ab), r(e2,02,4b,72), r(57,8f,1f,e3), r(2a,ab,55,66),\
+ r(07,28,eb,b2), r(03,c2,b5,2f), r(9a,7b,c5,86), r(a5,08,37,d3),\
+ r(f2,87,28,30), r(b2,a5,bf,23), r(ba,6a,03,02), r(5c,82,16,ed),\
+ r(2b,1c,cf,8a), r(92,b4,79,a7), r(f0,f2,07,f3), r(a1,e2,69,4e),\
+ r(cd,f4,da,65), r(d5,be,05,06), r(1f,62,34,d1), r(8a,fe,a6,c4),\
+ r(9d,53,2e,34), r(a0,55,f3,a2), r(32,e1,8a,05), r(75,eb,f6,a4),\
+ r(39,ec,83,0b), r(aa,ef,60,40), r(06,9f,71,5e), r(51,10,6e,bd),\
+ r(f9,8a,21,3e), r(3d,06,dd,96), r(ae,05,3e,dd), r(46,bd,e6,4d),\
+ r(b5,8d,54,91), r(05,5d,c4,71), r(6f,d4,06,04), r(ff,15,50,60),\
+ r(24,fb,98,19), r(97,e9,bd,d6), r(cc,43,40,89), r(77,9e,d9,67),\
+ r(bd,42,e8,b0), r(88,8b,89,07), r(38,5b,19,e7), r(db,ee,c8,79),\
+ r(47,0a,7c,a1), r(e9,0f,42,7c), r(c9,1e,84,f8), r(00,00,00,00),\
+ r(83,86,80,09), r(48,ed,2b,32), r(ac,70,11,1e), r(4e,72,5a,6c),\
+ r(fb,ff,0e,fd), r(56,38,85,0f), r(1e,d5,ae,3d), r(27,39,2d,36),\
+ r(64,d9,0f,0a), r(21,a6,5c,68), r(d1,54,5b,9b), r(3a,2e,36,24),\
+ r(b1,67,0a,0c), r(0f,e7,57,93), r(d2,96,ee,b4), r(9e,91,9b,1b),\
+ r(4f,c5,c0,80), r(a2,20,dc,61), r(69,4b,77,5a), r(16,1a,12,1c),\
+ r(0a,ba,93,e2), r(e5,2a,a0,c0), r(43,e0,22,3c), r(1d,17,1b,12),\
+ r(0b,0d,09,0e), r(ad,c7,8b,f2), r(b9,a8,b6,2d), r(c8,a9,1e,14),\
+ r(85,19,f1,57), r(4c,07,75,af), r(bb,dd,99,ee), r(fd,60,7f,a3),\
+ r(9f,26,01,f7), r(bc,f5,72,5c), r(c5,3b,66,44), r(34,7e,fb,5b),\
+ r(76,29,43,8b), r(dc,c6,23,cb), r(68,fc,ed,b6), r(63,f1,e4,b8),\
+ r(ca,dc,31,d7), r(10,85,63,42), r(40,22,97,13), r(20,11,c6,84),\
+ r(7d,24,4a,85), r(f8,3d,bb,d2), r(11,32,f9,ae), r(6d,a1,29,c7),\
+ r(4b,2f,9e,1d), r(f3,30,b2,dc), r(ec,52,86,0d), r(d0,e3,c1,77),\
+ r(6c,16,b3,2b), r(99,b9,70,a9), r(fa,48,94,11), r(22,64,e9,47),\
+ r(c4,8c,fc,a8), r(1a,3f,f0,a0), r(d8,2c,7d,56), r(ef,90,33,22),\
+ r(c7,4e,49,87), r(c1,d1,38,d9), r(fe,a2,ca,8c), r(36,0b,d4,98),\
+ r(cf,81,f5,a6), r(28,de,7a,a5), r(26,8e,b7,da), r(a4,bf,ad,3f),\
+ r(e4,9d,3a,2c), r(0d,92,78,50), r(9b,cc,5f,6a), r(62,46,7e,54),\
+ r(c2,13,8d,f6), r(e8,b8,d8,90), r(5e,f7,39,2e), r(f5,af,c3,82),\
+ r(be,80,5d,9f), r(7c,93,d0,69), r(a9,2d,d5,6f), r(b3,12,25,cf),\
+ r(3b,99,ac,c8), r(a7,7d,18,10), r(6e,63,9c,e8), r(7b,bb,3b,db),\
+ r(09,78,26,cd), r(f4,18,59,6e), r(01,b7,9a,ec), r(a8,9a,4f,83),\
+ r(65,6e,95,e6), r(7e,e6,ff,aa), r(08,cf,bc,21), r(e6,e8,15,ef),\
+ r(d9,9b,e7,ba), r(ce,36,6f,4a), r(d4,09,9f,ea), r(d6,7c,b0,29),\
+ r(af,b2,a4,31), r(31,23,3f,2a), r(30,94,a5,c6), r(c0,66,a2,35),\
+ r(37,bc,4e,74), r(a6,ca,82,fc), r(b0,d0,90,e0), r(15,d8,a7,33),\
+ r(4a,98,04,f1), r(f7,da,ec,41), r(0e,50,cd,7f), r(2f,f6,91,17),\
+ r(8d,d6,4d,76), r(4d,b0,ef,43), r(54,4d,aa,cc), r(df,04,96,e4),\
+ r(e3,b5,d1,9e), r(1b,88,6a,4c), r(b8,1f,2c,c1), r(7f,51,65,46),\
+ r(04,ea,5e,9d), r(5d,35,8c,01), r(73,74,87,fa), r(2e,41,0b,fb),\
+ r(5a,1d,67,b3), r(52,d2,db,92), r(33,56,10,e9), r(13,47,d6,6d),\
+ r(8c,61,d7,9a), r(7a,0c,a1,37), r(8e,14,f8,59), r(89,3c,13,eb),\
+ r(ee,27,a9,ce), r(35,c9,61,b7), r(ed,e5,1c,e1), r(3c,b1,47,7a),\
+ r(59,df,d2,9c), r(3f,73,f2,55), r(79,ce,14,18), r(bf,37,c7,73),\
+ r(ea,cd,f7,53), r(5b,aa,fd,5f), r(14,6f,3d,df), r(86,db,44,78),\
+ r(81,f3,af,ca), r(3e,c4,68,b9), r(2c,34,24,38), r(5f,40,a3,c2),\
+ r(72,c3,1d,16), r(0c,25,e2,bc), r(8b,49,3c,28), r(41,95,0d,ff),\
+ r(71,01,a8,39), r(de,b3,0c,08), r(9c,e4,b4,d8), r(90,c1,56,64),\
+ r(61,84,cb,7b), r(70,b6,32,d5), r(74,5c,6c,48), r(42,57,b8,d0)
+
+// generate the required tables in the desired endian format
+
+#undef r
+#define r r0
+
+#if defined(ONE_TABLE)
+static const u_int32_t ft_tab[256] =
+ { f_table };
+#elif defined(FOUR_TABLES)
+static const u_int32_t ft_tab[4][256] =
+{ { f_table },
+#undef r
+#define r r1
+ { f_table },
+#undef r
+#define r r2
+ { f_table },
+#undef r
+#define r r3
+ { f_table }
+};
+#endif
+
+#undef r
+#define r r0
+#if defined(ONE_TABLE)
+static const u_int32_t it_tab[256] =
+ { i_table };
+#elif defined(FOUR_TABLES)
+static const u_int32_t it_tab[4][256] =
+{ { i_table },
+#undef r
+#define r r1
+ { i_table },
+#undef r
+#define r r2
+ { i_table },
+#undef r
+#define r r3
+ { i_table }
+};
+#endif
+
+#endif
+
+#if defined(FIXED_TABLES) && (defined(ONE_LR_TABLE) || defined(FOUR_LR_TABLES))
+
+// data for inverse tables (last round)
+
+#define li_table \
+ w(52), w(09), w(6a), w(d5), w(30), w(36), w(a5), w(38),\
+ w(bf), w(40), w(a3), w(9e), w(81), w(f3), w(d7), w(fb),\
+ w(7c), w(e3), w(39), w(82), w(9b), w(2f), w(ff), w(87),\
+ w(34), w(8e), w(43), w(44), w(c4), w(de), w(e9), w(cb),\
+ w(54), w(7b), w(94), w(32), w(a6), w(c2), w(23), w(3d),\
+ w(ee), w(4c), w(95), w(0b), w(42), w(fa), w(c3), w(4e),\
+ w(08), w(2e), w(a1), w(66), w(28), w(d9), w(24), w(b2),\
+ w(76), w(5b), w(a2), w(49), w(6d), w(8b), w(d1), w(25),\
+ w(72), w(f8), w(f6), w(64), w(86), w(68), w(98), w(16),\
+ w(d4), w(a4), w(5c), w(cc), w(5d), w(65), w(b6), w(92),\
+ w(6c), w(70), w(48), w(50), w(fd), w(ed), w(b9), w(da),\
+ w(5e), w(15), w(46), w(57), w(a7), w(8d), w(9d), w(84),\
+ w(90), w(d8), w(ab), w(00), w(8c), w(bc), w(d3), w(0a),\
+ w(f7), w(e4), w(58), w(05), w(b8), w(b3), w(45), w(06),\
+ w(d0), w(2c), w(1e), w(8f), w(ca), w(3f), w(0f), w(02),\
+ w(c1), w(af), w(bd), w(03), w(01), w(13), w(8a), w(6b),\
+ w(3a), w(91), w(11), w(41), w(4f), w(67), w(dc), w(ea),\
+ w(97), w(f2), w(cf), w(ce), w(f0), w(b4), w(e6), w(73),\
+ w(96), w(ac), w(74), w(22), w(e7), w(ad), w(35), w(85),\
+ w(e2), w(f9), w(37), w(e8), w(1c), w(75), w(df), w(6e),\
+ w(47), w(f1), w(1a), w(71), w(1d), w(29), w(c5), w(89),\
+ w(6f), w(b7), w(62), w(0e), w(aa), w(18), w(be), w(1b),\
+ w(fc), w(56), w(3e), w(4b), w(c6), w(d2), w(79), w(20),\
+ w(9a), w(db), w(c0), w(fe), w(78), w(cd), w(5a), w(f4),\
+ w(1f), w(dd), w(a8), w(33), w(88), w(07), w(c7), w(31),\
+ w(b1), w(12), w(10), w(59), w(27), w(80), w(ec), w(5f),\
+ w(60), w(51), w(7f), w(a9), w(19), w(b5), w(4a), w(0d),\
+ w(2d), w(e5), w(7a), w(9f), w(93), w(c9), w(9c), w(ef),\
+ w(a0), w(e0), w(3b), w(4d), w(ae), w(2a), w(f5), w(b0),\
+ w(c8), w(eb), w(bb), w(3c), w(83), w(53), w(99), w(61),\
+ w(17), w(2b), w(04), w(7e), w(ba), w(77), w(d6), w(26),\
+ w(e1), w(69), w(14), w(63), w(55), w(21), w(0c), w(7d),
+
+// generate the required tables in the desired endian format
+
+#undef r
+#define r(p,q,r,s) w0(q)
+#if defined(ONE_LR_TABLE)
+static const u_int32_t fl_tab[256] =
+ { f_table };
+#elif defined(FOUR_LR_TABLES)
+static const u_int32_t fl_tab[4][256] =
+{ { f_table },
+#undef r
+#define r(p,q,r,s) w1(q)
+ { f_table },
+#undef r
+#define r(p,q,r,s) w2(q)
+ { f_table },
+#undef r
+#define r(p,q,r,s) w3(q)
+ { f_table }
+};
+#endif
+
+#undef w
+#define w w0
+#if defined(ONE_LR_TABLE)
+static const u_int32_t il_tab[256] =
+ { li_table };
+#elif defined(FOUR_LR_TABLES)
+static const u_int32_t il_tab[4][256] =
+{ { li_table },
+#undef w
+#define w w1
+ { li_table },
+#undef w
+#define w w2
+ { li_table },
+#undef w
+#define w w3
+ { li_table }
+};
+#endif
+
+#endif
+
+#if defined(FIXED_TABLES) && (defined(ONE_IM_TABLE) || defined(FOUR_IM_TABLES))
+
+#define m_table \
+ r(00,00,00,00), r(0b,0d,09,0e), r(16,1a,12,1c), r(1d,17,1b,12),\
+ r(2c,34,24,38), r(27,39,2d,36), r(3a,2e,36,24), r(31,23,3f,2a),\
+ r(58,68,48,70), r(53,65,41,7e), r(4e,72,5a,6c), r(45,7f,53,62),\
+ r(74,5c,6c,48), r(7f,51,65,46), r(62,46,7e,54), r(69,4b,77,5a),\
+ r(b0,d0,90,e0), r(bb,dd,99,ee), r(a6,ca,82,fc), r(ad,c7,8b,f2),\
+ r(9c,e4,b4,d8), r(97,e9,bd,d6), r(8a,fe,a6,c4), r(81,f3,af,ca),\
+ r(e8,b8,d8,90), r(e3,b5,d1,9e), r(fe,a2,ca,8c), r(f5,af,c3,82),\
+ r(c4,8c,fc,a8), r(cf,81,f5,a6), r(d2,96,ee,b4), r(d9,9b,e7,ba),\
+ r(7b,bb,3b,db), r(70,b6,32,d5), r(6d,a1,29,c7), r(66,ac,20,c9),\
+ r(57,8f,1f,e3), r(5c,82,16,ed), r(41,95,0d,ff), r(4a,98,04,f1),\
+ r(23,d3,73,ab), r(28,de,7a,a5), r(35,c9,61,b7), r(3e,c4,68,b9),\
+ r(0f,e7,57,93), r(04,ea,5e,9d), r(19,fd,45,8f), r(12,f0,4c,81),\
+ r(cb,6b,ab,3b), r(c0,66,a2,35), r(dd,71,b9,27), r(d6,7c,b0,29),\
+ r(e7,5f,8f,03), r(ec,52,86,0d), r(f1,45,9d,1f), r(fa,48,94,11),\
+ r(93,03,e3,4b), r(98,0e,ea,45), r(85,19,f1,57), r(8e,14,f8,59),\
+ r(bf,37,c7,73), r(b4,3a,ce,7d), r(a9,2d,d5,6f), r(a2,20,dc,61),\
+ r(f6,6d,76,ad), r(fd,60,7f,a3), r(e0,77,64,b1), r(eb,7a,6d,bf),\
+ r(da,59,52,95), r(d1,54,5b,9b), r(cc,43,40,89), r(c7,4e,49,87),\
+ r(ae,05,3e,dd), r(a5,08,37,d3), r(b8,1f,2c,c1), r(b3,12,25,cf),\
+ r(82,31,1a,e5), r(89,3c,13,eb), r(94,2b,08,f9), r(9f,26,01,f7),\
+ r(46,bd,e6,4d), r(4d,b0,ef,43), r(50,a7,f4,51), r(5b,aa,fd,5f),\
+ r(6a,89,c2,75), r(61,84,cb,7b), r(7c,93,d0,69), r(77,9e,d9,67),\
+ r(1e,d5,ae,3d), r(15,d8,a7,33), r(08,cf,bc,21), r(03,c2,b5,2f),\
+ r(32,e1,8a,05), r(39,ec,83,0b), r(24,fb,98,19), r(2f,f6,91,17),\
+ r(8d,d6,4d,76), r(86,db,44,78), r(9b,cc,5f,6a), r(90,c1,56,64),\
+ r(a1,e2,69,4e), r(aa,ef,60,40), r(b7,f8,7b,52), r(bc,f5,72,5c),\
+ r(d5,be,05,06), r(de,b3,0c,08), r(c3,a4,17,1a), r(c8,a9,1e,14),\
+ r(f9,8a,21,3e), r(f2,87,28,30), r(ef,90,33,22), r(e4,9d,3a,2c),\
+ r(3d,06,dd,96), r(36,0b,d4,98), r(2b,1c,cf,8a), r(20,11,c6,84),\
+ r(11,32,f9,ae), r(1a,3f,f0,a0), r(07,28,eb,b2), r(0c,25,e2,bc),\
+ r(65,6e,95,e6), r(6e,63,9c,e8), r(73,74,87,fa), r(78,79,8e,f4),\
+ r(49,5a,b1,de), r(42,57,b8,d0), r(5f,40,a3,c2), r(54,4d,aa,cc),\
+ r(f7,da,ec,41), r(fc,d7,e5,4f), r(e1,c0,fe,5d), r(ea,cd,f7,53),\
+ r(db,ee,c8,79), r(d0,e3,c1,77), r(cd,f4,da,65), r(c6,f9,d3,6b),\
+ r(af,b2,a4,31), r(a4,bf,ad,3f), r(b9,a8,b6,2d), r(b2,a5,bf,23),\
+ r(83,86,80,09), r(88,8b,89,07), r(95,9c,92,15), r(9e,91,9b,1b),\
+ r(47,0a,7c,a1), r(4c,07,75,af), r(51,10,6e,bd), r(5a,1d,67,b3),\
+ r(6b,3e,58,99), r(60,33,51,97), r(7d,24,4a,85), r(76,29,43,8b),\
+ r(1f,62,34,d1), r(14,6f,3d,df), r(09,78,26,cd), r(02,75,2f,c3),\
+ r(33,56,10,e9), r(38,5b,19,e7), r(25,4c,02,f5), r(2e,41,0b,fb),\
+ r(8c,61,d7,9a), r(87,6c,de,94), r(9a,7b,c5,86), r(91,76,cc,88),\
+ r(a0,55,f3,a2), r(ab,58,fa,ac), r(b6,4f,e1,be), r(bd,42,e8,b0),\
+ r(d4,09,9f,ea), r(df,04,96,e4), r(c2,13,8d,f6), r(c9,1e,84,f8),\
+ r(f8,3d,bb,d2), r(f3,30,b2,dc), r(ee,27,a9,ce), r(e5,2a,a0,c0),\
+ r(3c,b1,47,7a), r(37,bc,4e,74), r(2a,ab,55,66), r(21,a6,5c,68),\
+ r(10,85,63,42), r(1b,88,6a,4c), r(06,9f,71,5e), r(0d,92,78,50),\
+ r(64,d9,0f,0a), r(6f,d4,06,04), r(72,c3,1d,16), r(79,ce,14,18),\
+ r(48,ed,2b,32), r(43,e0,22,3c), r(5e,f7,39,2e), r(55,fa,30,20),\
+ r(01,b7,9a,ec), r(0a,ba,93,e2), r(17,ad,88,f0), r(1c,a0,81,fe),\
+ r(2d,83,be,d4), r(26,8e,b7,da), r(3b,99,ac,c8), r(30,94,a5,c6),\
+ r(59,df,d2,9c), r(52,d2,db,92), r(4f,c5,c0,80), r(44,c8,c9,8e),\
+ r(75,eb,f6,a4), r(7e,e6,ff,aa), r(63,f1,e4,b8), r(68,fc,ed,b6),\
+ r(b1,67,0a,0c), r(ba,6a,03,02), r(a7,7d,18,10), r(ac,70,11,1e),\
+ r(9d,53,2e,34), r(96,5e,27,3a), r(8b,49,3c,28), r(80,44,35,26),\
+ r(e9,0f,42,7c), r(e2,02,4b,72), r(ff,15,50,60), r(f4,18,59,6e),\
+ r(c5,3b,66,44), r(ce,36,6f,4a), r(d3,21,74,58), r(d8,2c,7d,56),\
+ r(7a,0c,a1,37), r(71,01,a8,39), r(6c,16,b3,2b), r(67,1b,ba,25),\
+ r(56,38,85,0f), r(5d,35,8c,01), r(40,22,97,13), r(4b,2f,9e,1d),\
+ r(22,64,e9,47), r(29,69,e0,49), r(34,7e,fb,5b), r(3f,73,f2,55),\
+ r(0e,50,cd,7f), r(05,5d,c4,71), r(18,4a,df,63), r(13,47,d6,6d),\
+ r(ca,dc,31,d7), r(c1,d1,38,d9), r(dc,c6,23,cb), r(d7,cb,2a,c5),\
+ r(e6,e8,15,ef), r(ed,e5,1c,e1), r(f0,f2,07,f3), r(fb,ff,0e,fd),\
+ r(92,b4,79,a7), r(99,b9,70,a9), r(84,ae,6b,bb), r(8f,a3,62,b5),\
+ r(be,80,5d,9f), r(b5,8d,54,91), r(a8,9a,4f,83), r(a3,97,46,8d)
+
+#undef r
+#define r r0
+
+#if defined(ONE_IM_TABLE)
+static const u_int32_t im_tab[256] =
+ { m_table };
+#elif defined(FOUR_IM_TABLES)
+static const u_int32_t im_tab[4][256] =
+{ { m_table },
+#undef r
+#define r r1
+ { m_table },
+#undef r
+#define r r2
+ { m_table },
+#undef r
+#define r r3
+ { m_table }
+};
+#endif
+
+#endif
+
+#else
+
+static int tab_gen = 0;
+
+static unsigned char s_box[256]; // the S box
+static unsigned char inv_s_box[256]; // the inverse S box
+static u_int32_t rcon_tab[AES_RC_LENGTH]; // table of round constants
+
+#if defined(ONE_TABLE)
+static u_int32_t ft_tab[256];
+static u_int32_t it_tab[256];
+#elif defined(FOUR_TABLES)
+static u_int32_t ft_tab[4][256];
+static u_int32_t it_tab[4][256];
+#endif
+
+#if defined(ONE_LR_TABLE)
+static u_int32_t fl_tab[256];
+static u_int32_t il_tab[256];
+#elif defined(FOUR_LR_TABLES)
+static u_int32_t fl_tab[4][256];
+static u_int32_t il_tab[4][256];
+#endif
+
+#if defined(ONE_IM_TABLE)
+static u_int32_t im_tab[256];
+#elif defined(FOUR_IM_TABLES)
+static u_int32_t im_tab[4][256];
+#endif
+
+// Generate the tables for the dynamic table option
+
+#if !defined(FF_TABLES)
+
+// It will generally be sensible to use tables to compute finite
+// field multiplies and inverses but where memory is scarse this
+// code might sometimes be better.
+
+// return 2 ^ (n - 1) where n is the bit number of the highest bit
+// set in x with x in the range 1 < x < 0x00000200. This form is
+// used so that locals within FFinv can be bytes rather than words
+
+static unsigned char hibit(const u_int32_t x)
+{ unsigned char r = (unsigned char)((x >> 1) | (x >> 2));
+
+ r |= (r >> 2);
+ r |= (r >> 4);
+ return (r + 1) >> 1;
+}
+
+// return the inverse of the finite field element x
+
+static unsigned char FFinv(const unsigned char x)
+{ unsigned char p1 = x, p2 = 0x1b, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+ if(x < 2) return x;
+
+ for(;;)
+ {
+ if(!n1) return v1;
+
+ while(n2 >= n1)
+ {
+ n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2);
+ }
+
+ if(!n2) return v2;
+
+ while(n1 >= n2)
+ {
+ n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1);
+ }
+ }
+}
+
+// define the finite field multiplies required for Rijndael
+
+#define FFmul02(x) ((((x) & 0x7f) << 1) ^ ((x) & 0x80 ? 0x1b : 0))
+#define FFmul03(x) ((x) ^ FFmul02(x))
+#define FFmul09(x) ((x) ^ FFmul02(FFmul02(FFmul02(x))))
+#define FFmul0b(x) ((x) ^ FFmul02((x) ^ FFmul02(FFmul02(x))))
+#define FFmul0d(x) ((x) ^ FFmul02(FFmul02((x) ^ FFmul02(x))))
+#define FFmul0e(x) FFmul02((x) ^ FFmul02((x) ^ FFmul02(x)))
+
+#else
+
+#define FFinv(x) ((x) ? pow[255 - log[x]]: 0)
+
+#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0)
+#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0)
+#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0)
+#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0)
+#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0)
+#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0)
+
+#endif
+
+// The forward and inverse affine transformations used in the S-box
+
+#define fwd_affine(x) \
+ (w = (u_int32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(unsigned char)(w^(w>>8)))
+
+#define inv_affine(x) \
+ (w = (u_int32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(unsigned char)(w^(w>>8)))
+
+static void gen_tabs(void)
+{ u_int32_t i, w;
+
+#if defined(FF_TABLES)
+
+ unsigned char pow[512], log[256];
+
+ // log and power tables for GF(2^8) finite field with
+ // 0x011b as modular polynomial - the simplest primitive
+ // root is 0x03, used here to generate the tables
+
+ i = 0; w = 1;
+ do
+ {
+ pow[i] = (unsigned char)w;
+ pow[i + 255] = (unsigned char)w;
+ log[w] = (unsigned char)i++;
+ w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0);
+ }
+ while (w != 1);
+
+#endif
+
+ for(i = 0, w = 1; i < AES_RC_LENGTH; ++i)
+ {
+ rcon_tab[i] = bytes2word(w, 0, 0, 0);
+ w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
+ }
+
+ for(i = 0; i < 256; ++i)
+ { unsigned char b;
+
+ s_box[i] = b = fwd_affine(FFinv((unsigned char)i));
+
+ w = bytes2word(b, 0, 0, 0);
+#if defined(ONE_LR_TABLE)
+ fl_tab[i] = w;
+#elif defined(FOUR_LR_TABLES)
+ fl_tab[0][i] = w;
+ fl_tab[1][i] = upr(w,1);
+ fl_tab[2][i] = upr(w,2);
+ fl_tab[3][i] = upr(w,3);
+#endif
+ w = bytes2word(FFmul02(b), b, b, FFmul03(b));
+#if defined(ONE_TABLE)
+ ft_tab[i] = w;
+#elif defined(FOUR_TABLES)
+ ft_tab[0][i] = w;
+ ft_tab[1][i] = upr(w,1);
+ ft_tab[2][i] = upr(w,2);
+ ft_tab[3][i] = upr(w,3);
+#endif
+ inv_s_box[i] = b = FFinv(inv_affine((unsigned char)i));
+
+ w = bytes2word(b, 0, 0, 0);
+#if defined(ONE_LR_TABLE)
+ il_tab[i] = w;
+#elif defined(FOUR_LR_TABLES)
+ il_tab[0][i] = w;
+ il_tab[1][i] = upr(w,1);
+ il_tab[2][i] = upr(w,2);
+ il_tab[3][i] = upr(w,3);
+#endif
+ w = bytes2word(FFmul0e(b), FFmul09(b), FFmul0d(b), FFmul0b(b));
+#if defined(ONE_TABLE)
+ it_tab[i] = w;
+#elif defined(FOUR_TABLES)
+ it_tab[0][i] = w;
+ it_tab[1][i] = upr(w,1);
+ it_tab[2][i] = upr(w,2);
+ it_tab[3][i] = upr(w,3);
+#endif
+#if defined(ONE_IM_TABLE)
+ im_tab[b] = w;
+#elif defined(FOUR_IM_TABLES)
+ im_tab[0][b] = w;
+ im_tab[1][b] = upr(w,1);
+ im_tab[2][b] = upr(w,2);
+ im_tab[3][b] = upr(w,3);
+#endif
+
+ }
+}
+
+#endif
+
+#define no_table(x,box,vf,rf,c) bytes2word( \
+ box[bval(vf(x,0,c),rf(0,c))], \
+ box[bval(vf(x,1,c),rf(1,c))], \
+ box[bval(vf(x,2,c),rf(2,c))], \
+ box[bval(vf(x,3,c),rf(3,c))])
+
+#define one_table(x,op,tab,vf,rf,c) \
+ ( tab[bval(vf(x,0,c),rf(0,c))] \
+ ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
+ ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
+ ^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
+
+#define four_tables(x,tab,vf,rf,c) \
+ ( tab[0][bval(vf(x,0,c),rf(0,c))] \
+ ^ tab[1][bval(vf(x,1,c),rf(1,c))] \
+ ^ tab[2][bval(vf(x,2,c),rf(2,c))] \
+ ^ tab[3][bval(vf(x,3,c),rf(3,c))])
+
+#define vf1(x,r,c) (x)
+#define rf1(r,c) (r)
+#define rf2(r,c) ((r-c)&3)
+
+#if defined(FOUR_LR_TABLES)
+#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c)
+#elif defined(ONE_LR_TABLE)
+#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c)
+#else
+#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c)
+#endif
+
+#if defined(FOUR_IM_TABLES)
+#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0)
+#elif defined(ONE_IM_TABLE)
+#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0)
+#else
+#define inv_mcol(x) \
+ (f9 = (x),f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \
+ f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1))
+#endif
+
+// Subroutine to set the block size (if variable) in bytes, legal
+// values being 16, 24 and 32.
+
+#if defined(AES_BLOCK_SIZE)
+#define nc (AES_BLOCK_SIZE / 4)
+#else
+#define nc (cx->aes_Ncol)
+
+void aes_set_blk(aes_context *cx, int n_bytes)
+{
+#if !defined(FIXED_TABLES)
+ if(!tab_gen) { gen_tabs(); tab_gen = 1; }
+#endif
+
+ switch(n_bytes) {
+ case 32: /* bytes */
+ case 256: /* bits */
+ nc = 8;
+ break;
+ case 24: /* bytes */
+ case 192: /* bits */
+ nc = 6;
+ break;
+ case 16: /* bytes */
+ case 128: /* bits */
+ default:
+ nc = 4;
+ break;
+ }
+}
+
+#endif
+
+// Initialise the key schedule from the user supplied key. The key
+// length is now specified in bytes - 16, 24 or 32 as appropriate.
+// This corresponds to bit lengths of 128, 192 and 256 bits, and
+// to Nk values of 4, 6 and 8 respectively.
+
+#define mx(t,f) (*t++ = inv_mcol(*f),f++)
+#define cp(t,f) *t++ = *f++
+
+#if AES_BLOCK_SIZE == 16
+#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s)
+#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s)
+#elif AES_BLOCK_SIZE == 24
+#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+ cp(d,s); cp(d,s)
+#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+ mx(d,s); mx(d,s)
+#elif AES_BLOCK_SIZE == 32
+#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+ cp(d,s); cp(d,s); cp(d,s); cp(d,s)
+#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+ mx(d,s); mx(d,s); mx(d,s); mx(d,s)
+#else
+
+#define cpy(d,s) \
+switch(nc) \
+{ case 8: cp(d,s); cp(d,s); \
+ case 6: cp(d,s); cp(d,s); \
+ case 4: cp(d,s); cp(d,s); \
+ cp(d,s); cp(d,s); \
+}
+
+#define mix(d,s) \
+switch(nc) \
+{ case 8: mx(d,s); mx(d,s); \
+ case 6: mx(d,s); mx(d,s); \
+ case 4: mx(d,s); mx(d,s); \
+ mx(d,s); mx(d,s); \
+}
+
+#endif
+
+void aes_set_key(aes_context *cx, const unsigned char in_key[], int n_bytes, const int f)
+{ u_int32_t *kf, *kt, rci;
+
+#if !defined(FIXED_TABLES)
+ if(!tab_gen) { gen_tabs(); tab_gen = 1; }
+#endif
+
+ switch(n_bytes) {
+ case 32: /* bytes */
+ case 256: /* bits */
+ cx->aes_Nkey = 8;
+ break;
+ case 24: /* bytes */
+ case 192: /* bits */
+ cx->aes_Nkey = 6;
+ break;
+ case 16: /* bytes */
+ case 128: /* bits */
+ default:
+ cx->aes_Nkey = 4;
+ break;
+ }
+
+ cx->aes_Nrnd = (cx->aes_Nkey > nc ? cx->aes_Nkey : nc) + 6;
+
+ cx->aes_e_key[0] = const_word_in(in_key );
+ cx->aes_e_key[1] = const_word_in(in_key + 4);
+ cx->aes_e_key[2] = const_word_in(in_key + 8);
+ cx->aes_e_key[3] = const_word_in(in_key + 12);
+
+ kf = cx->aes_e_key;
+ kt = kf + nc * (cx->aes_Nrnd + 1) - cx->aes_Nkey;
+ rci = 0;
+
+ switch(cx->aes_Nkey)
+ {
+ case 4: do
+ { kf[4] = kf[0] ^ ls_box(kf[3],3) ^ rcon_tab[rci++];
+ kf[5] = kf[1] ^ kf[4];
+ kf[6] = kf[2] ^ kf[5];
+ kf[7] = kf[3] ^ kf[6];
+ kf += 4;
+ }
+ while(kf < kt);
+ break;
+
+ case 6: cx->aes_e_key[4] = const_word_in(in_key + 16);
+ cx->aes_e_key[5] = const_word_in(in_key + 20);
+ do
+ { kf[ 6] = kf[0] ^ ls_box(kf[5],3) ^ rcon_tab[rci++];
+ kf[ 7] = kf[1] ^ kf[ 6];
+ kf[ 8] = kf[2] ^ kf[ 7];
+ kf[ 9] = kf[3] ^ kf[ 8];
+ kf[10] = kf[4] ^ kf[ 9];
+ kf[11] = kf[5] ^ kf[10];
+ kf += 6;
+ }
+ while(kf < kt);
+ break;
+
+ case 8: cx->aes_e_key[4] = const_word_in(in_key + 16);
+ cx->aes_e_key[5] = const_word_in(in_key + 20);
+ cx->aes_e_key[6] = const_word_in(in_key + 24);
+ cx->aes_e_key[7] = const_word_in(in_key + 28);
+ do
+ { kf[ 8] = kf[0] ^ ls_box(kf[7],3) ^ rcon_tab[rci++];
+ kf[ 9] = kf[1] ^ kf[ 8];
+ kf[10] = kf[2] ^ kf[ 9];
+ kf[11] = kf[3] ^ kf[10];
+ kf[12] = kf[4] ^ ls_box(kf[11],0);
+ kf[13] = kf[5] ^ kf[12];
+ kf[14] = kf[6] ^ kf[13];
+ kf[15] = kf[7] ^ kf[14];
+ kf += 8;
+ }
+ while (kf < kt);
+ break;
+ }
+
+ if(!f)
+ { u_int32_t i;
+
+ kt = cx->aes_d_key + nc * cx->aes_Nrnd;
+ kf = cx->aes_e_key;
+
+ cpy(kt, kf); kt -= 2 * nc;
+
+ for(i = 1; i < cx->aes_Nrnd; ++i)
+ {
+#if defined(ONE_TABLE) || defined(FOUR_TABLES)
+#if !defined(ONE_IM_TABLE) && !defined(FOUR_IM_TABLES)
+ u_int32_t f2, f4, f8, f9;
+#endif
+ mix(kt, kf);
+#else
+ cpy(kt, kf);
+#endif
+ kt -= 2 * nc;
+ }
+
+ cpy(kt, kf);
+ }
+}
+
+// y = output word, x = input word, r = row, c = column
+// for r = 0, 1, 2 and 3 = column accessed for row r
+
+#if defined(ARRAYS)
+#define s(x,c) x[c]
+#else
+#define s(x,c) x##c
+#endif
+
+// I am grateful to Frank Yellin for the following constructions
+// which, given the column (c) of the output state variable that
+// is being computed, return the input state variables which are
+// needed for each row (r) of the state
+
+// For the fixed block size options, compilers reduce these two
+// expressions to fixed variable references. For variable block
+// size code conditional clauses will sometimes be returned
+
+#define unused 77 // Sunset Strip
+
+#define fwd_var(x,r,c) \
+ ( r==0 ? \
+ ( c==0 ? s(x,0) \
+ : c==1 ? s(x,1) \
+ : c==2 ? s(x,2) \
+ : c==3 ? s(x,3) \
+ : c==4 ? s(x,4) \
+ : c==5 ? s(x,5) \
+ : c==6 ? s(x,6) \
+ : s(x,7)) \
+ : r==1 ? \
+ ( c==0 ? s(x,1) \
+ : c==1 ? s(x,2) \
+ : c==2 ? s(x,3) \
+ : c==3 ? nc==4 ? s(x,0) : s(x,4) \
+ : c==4 ? s(x,5) \
+ : c==5 ? nc==8 ? s(x,6) : s(x,0) \
+ : c==6 ? s(x,7) \
+ : s(x,0)) \
+ : r==2 ? \
+ ( c==0 ? nc==8 ? s(x,3) : s(x,2) \
+ : c==1 ? nc==8 ? s(x,4) : s(x,3) \
+ : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
+ : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
+ : c==4 ? nc==8 ? s(x,7) : s(x,0) \
+ : c==5 ? nc==8 ? s(x,0) : s(x,1) \
+ : c==6 ? s(x,1) \
+ : s(x,2)) \
+ : \
+ ( c==0 ? nc==8 ? s(x,4) : s(x,3) \
+ : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
+ : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
+ : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \
+ : c==4 ? nc==8 ? s(x,0) : s(x,1) \
+ : c==5 ? nc==8 ? s(x,1) : s(x,2) \
+ : c==6 ? s(x,2) \
+ : s(x,3)))
+
+#define inv_var(x,r,c) \
+ ( r==0 ? \
+ ( c==0 ? s(x,0) \
+ : c==1 ? s(x,1) \
+ : c==2 ? s(x,2) \
+ : c==3 ? s(x,3) \
+ : c==4 ? s(x,4) \
+ : c==5 ? s(x,5) \
+ : c==6 ? s(x,6) \
+ : s(x,7)) \
+ : r==1 ? \
+ ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \
+ : c==1 ? s(x,0) \
+ : c==2 ? s(x,1) \
+ : c==3 ? s(x,2) \
+ : c==4 ? s(x,3) \
+ : c==5 ? s(x,4) \
+ : c==6 ? s(x,5) \
+ : s(x,6)) \
+ : r==2 ? \
+ ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
+ : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
+ : c==2 ? nc==8 ? s(x,7) : s(x,0) \
+ : c==3 ? nc==8 ? s(x,0) : s(x,1) \
+ : c==4 ? nc==8 ? s(x,1) : s(x,2) \
+ : c==5 ? nc==8 ? s(x,2) : s(x,3) \
+ : c==6 ? s(x,3) \
+ : s(x,4)) \
+ : \
+ ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \
+ : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
+ : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
+ : c==3 ? nc==8 ? s(x,7) : s(x,0) \
+ : c==4 ? nc==8 ? s(x,0) : s(x,1) \
+ : c==5 ? nc==8 ? s(x,1) : s(x,2) \
+ : c==6 ? s(x,2) \
+ : s(x,3)))
+
+#define si(y,x,k,c) s(y,c) = const_word_in(x + 4 * c) ^ k[c]
+#define so(y,x,c) word_out(y + 4 * c, s(x,c))
+
+#if defined(FOUR_TABLES)
+#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c)
+#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c)
+#elif defined(ONE_TABLE)
+#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c)
+#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c)
+#else
+#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c]
+#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c])
+#endif
+
+#if defined(FOUR_LR_TABLES)
+#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c)
+#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c)
+#elif defined(ONE_LR_TABLE)
+#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c)
+#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c)
+#else
+#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c]
+#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]
+#endif
+
+#if AES_BLOCK_SIZE == 16
+
+#if defined(ARRAYS)
+#define locals(y,x) x[4],y[4]
+#else
+#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
+// the following defines prevent the compiler requiring the declaration
+// of generated but unused variables in the fwd_var and inv_var macros
+#define b04 unused
+#define b05 unused
+#define b06 unused
+#define b07 unused
+#define b14 unused
+#define b15 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
+ s(y,2) = s(x,2); s(y,3) = s(x,3);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
+#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
+
+#elif AES_BLOCK_SIZE == 24
+
+#if defined(ARRAYS)
+#define locals(y,x) x[6],y[6]
+#else
+#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \
+ y##0,y##1,y##2,y##3,y##4,y##5
+#define b06 unused
+#define b07 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
+ s(y,2) = s(x,2); s(y,3) = s(x,3); \
+ s(y,4) = s(x,4); s(y,5) = s(x,5);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \
+ si(y,x,k,3); si(y,x,k,4); si(y,x,k,5)
+#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \
+ so(y,x,3); so(y,x,4); so(y,x,5)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \
+ rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5)
+#else
+
+#if defined(ARRAYS)
+#define locals(y,x) x[8],y[8]
+#else
+#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \
+ y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7
+#endif
+#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
+ s(y,2) = s(x,2); s(y,3) = s(x,3); \
+ s(y,4) = s(x,4); s(y,5) = s(x,5); \
+ s(y,6) = s(x,6); s(y,7) = s(x,7);
+
+#if AES_BLOCK_SIZE == 32
+
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \
+ si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7)
+#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \
+ so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \
+ rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7)
+#else
+
+#define state_in(y,x,k) \
+switch(nc) \
+{ case 8: si(y,x,k,7); si(y,x,k,6); \
+ case 6: si(y,x,k,5); si(y,x,k,4); \
+ case 4: si(y,x,k,3); si(y,x,k,2); \
+ si(y,x,k,1); si(y,x,k,0); \
+}
+
+#define state_out(y,x) \
+switch(nc) \
+{ case 8: so(y,x,7); so(y,x,6); \
+ case 6: so(y,x,5); so(y,x,4); \
+ case 4: so(y,x,3); so(y,x,2); \
+ so(y,x,1); so(y,x,0); \
+}
+
+#if defined(FAST_VARIABLE)
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{ case 8: rm(y,x,k,7); rm(y,x,k,6); \
+ rm(y,x,k,5); rm(y,x,k,4); \
+ rm(y,x,k,3); rm(y,x,k,2); \
+ rm(y,x,k,1); rm(y,x,k,0); \
+ break; \
+ case 6: rm(y,x,k,5); rm(y,x,k,4); \
+ rm(y,x,k,3); rm(y,x,k,2); \
+ rm(y,x,k,1); rm(y,x,k,0); \
+ break; \
+ case 4: rm(y,x,k,3); rm(y,x,k,2); \
+ rm(y,x,k,1); rm(y,x,k,0); \
+ break; \
+}
+#else
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{ case 8: rm(y,x,k,7); rm(y,x,k,6); \
+ case 6: rm(y,x,k,5); rm(y,x,k,4); \
+ case 4: rm(y,x,k,3); rm(y,x,k,2); \
+ rm(y,x,k,1); rm(y,x,k,0); \
+}
+
+#endif
+
+#endif
+#endif
+
+void aes_encrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
+{ u_int32_t locals(b0, b1);
+ const u_int32_t *kp = cx->aes_e_key;
+
+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
+ u_int32_t f2;
+#endif
+
+ state_in(b0, in_blk, kp); kp += nc;
+
+#if defined(UNROLL)
+
+ switch(cx->aes_Nrnd)
+ {
+ case 14: round(fwd_rnd, b1, b0, kp );
+ round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc;
+ case 12: round(fwd_rnd, b1, b0, kp );
+ round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc;
+ case 10: round(fwd_rnd, b1, b0, kp );
+ round(fwd_rnd, b0, b1, kp + nc);
+ round(fwd_rnd, b1, b0, kp + 2 * nc);
+ round(fwd_rnd, b0, b1, kp + 3 * nc);
+ round(fwd_rnd, b1, b0, kp + 4 * nc);
+ round(fwd_rnd, b0, b1, kp + 5 * nc);
+ round(fwd_rnd, b1, b0, kp + 6 * nc);
+ round(fwd_rnd, b0, b1, kp + 7 * nc);
+ round(fwd_rnd, b1, b0, kp + 8 * nc);
+ round(fwd_lrnd, b0, b1, kp + 9 * nc);
+ }
+
+#elif defined(PARTIAL_UNROLL)
+ { u_int32_t rnd;
+
+ for(rnd = 0; rnd < (cx->aes_Nrnd >> 1) - 1; ++rnd)
+ {
+ round(fwd_rnd, b1, b0, kp);
+ round(fwd_rnd, b0, b1, kp + nc); kp += 2 * nc;
+ }
+
+ round(fwd_rnd, b1, b0, kp);
+ round(fwd_lrnd, b0, b1, kp + nc);
+ }
+#else
+ { u_int32_t rnd;
+
+ for(rnd = 0; rnd < cx->aes_Nrnd - 1; ++rnd)
+ {
+ round(fwd_rnd, b1, b0, kp);
+ l_copy(b0, b1); kp += nc;
+ }
+
+ round(fwd_lrnd, b0, b1, kp);
+ }
+#endif
+
+ state_out(out_blk, b0);
+}
+
+void aes_decrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
+{ u_int32_t locals(b0, b1);
+ const u_int32_t *kp = cx->aes_d_key;
+
+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
+ u_int32_t f2, f4, f8, f9;
+#endif
+
+ state_in(b0, in_blk, kp); kp += nc;
+
+#if defined(UNROLL)
+
+ switch(cx->aes_Nrnd)
+ {
+ case 14: round(inv_rnd, b1, b0, kp );
+ round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc;
+ case 12: round(inv_rnd, b1, b0, kp );
+ round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc;
+ case 10: round(inv_rnd, b1, b0, kp );
+ round(inv_rnd, b0, b1, kp + nc);
+ round(inv_rnd, b1, b0, kp + 2 * nc);
+ round(inv_rnd, b0, b1, kp + 3 * nc);
+ round(inv_rnd, b1, b0, kp + 4 * nc);
+ round(inv_rnd, b0, b1, kp + 5 * nc);
+ round(inv_rnd, b1, b0, kp + 6 * nc);
+ round(inv_rnd, b0, b1, kp + 7 * nc);
+ round(inv_rnd, b1, b0, kp + 8 * nc);
+ round(inv_lrnd, b0, b1, kp + 9 * nc);
+ }
+
+#elif defined(PARTIAL_UNROLL)
+ { u_int32_t rnd;
+
+ for(rnd = 0; rnd < (cx->aes_Nrnd >> 1) - 1; ++rnd)
+ {
+ round(inv_rnd, b1, b0, kp);
+ round(inv_rnd, b0, b1, kp + nc); kp += 2 * nc;
+ }
+
+ round(inv_rnd, b1, b0, kp);
+ round(inv_lrnd, b0, b1, kp + nc);
+ }
+#else
+ { u_int32_t rnd;
+
+ for(rnd = 0; rnd < cx->aes_Nrnd - 1; ++rnd)
+ {
+ round(inv_rnd, b1, b0, kp);
+ l_copy(b0, b1); kp += nc;
+ }
+
+ round(inv_lrnd, b0, b1, kp);
+ }
+#endif
+
+ state_out(out_blk, b0);
+}
diff --git a/lib/libcrypto/libaes/aes.h b/lib/libcrypto/libaes/aes.h
new file mode 100644
index 000000000..4f1e3b335
--- /dev/null
+++ b/lib/libcrypto/libaes/aes.h
@@ -0,0 +1,97 @@
+// I retain copyright in this code but I encourage its free use provided
+// that I don't carry any responsibility for the results. I am especially
+// happy to see it used in free and open source software. If you do use
+// it I would appreciate an acknowledgement of its origin in the code or
+// the product that results and I would also appreciate knowing a little
+// about the use to which it is being put. I am grateful to Frank Yellin
+// for some ideas that are used in this implementation.
+//
+// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
+//
+// This is an implementation of the AES encryption algorithm (Rijndael)
+// designed by Joan Daemen and Vincent Rijmen. This version is designed
+// to provide both fixed and dynamic block and key lengths and can also
+// run with either big or little endian internal byte order (see aes.h).
+// It inputs block and key lengths in bytes with the legal values being
+// 16, 24 and 32.
+
+/*
+ * Modified by Jari Ruusu, May 1 2001
+ * - Fixed some compile warnings, code was ok but gcc warned anyway.
+ * - Changed basic types: byte -> unsigned char, word -> u_int32_t
+ * - Major name space cleanup: Names visible to outside now begin
+ * with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
+ * - Removed C++ and DLL support as part of name space cleanup.
+ * - Eliminated unnecessary recomputation of tables. (actual bug fix)
+ * - Merged precomputed constant tables to aes.c file.
+ * - Removed data alignment restrictions for portability reasons.
+ * - Made block and key lengths accept bit count (128/192/256)
+ * as well byte count (16/24/32).
+ * - Removed all error checks. This change also eliminated the need
+ * to preinitialize the context struct to zero.
+ * - Removed some totally unused constants.
+ */
+
+#ifndef _AES_H
+#define _AES_H
+
+#if defined(__linux__) && defined(__KERNEL__)
+# include <linux/types.h>
+#else
+# include <sys/types.h>
+#endif
+
+// CONFIGURATION OPTIONS (see also aes.c)
+//
+// Define AES_BLOCK_SIZE to set the cipher block size (16, 24 or 32) or
+// leave this undefined for dynamically variable block size (this will
+// result in much slower code).
+// IMPORTANT NOTE: AES_BLOCK_SIZE is in BYTES (16, 24, 32 or undefined). If
+// left undefined a slower version providing variable block length is compiled
+
+#define AES_BLOCK_SIZE 16
+
+// The number of key schedule words for different block and key lengths
+// allowing for method of computation which requires the length to be a
+// multiple of the key length
+//
+// Nk = 4 6 8
+// -------------
+// Nb = 4 | 60 60 64
+// 6 | 96 90 96
+// 8 | 120 120 120
+
+#if !defined(AES_BLOCK_SIZE) || (AES_BLOCK_SIZE == 32)
+#define AES_KS_LENGTH 120
+#define AES_RC_LENGTH 29
+#else
+#define AES_KS_LENGTH 4 * AES_BLOCK_SIZE
+#define AES_RC_LENGTH (9 * AES_BLOCK_SIZE) / 8 - 8
+#endif
+
+typedef struct
+{
+ u_int32_t aes_Nkey; // the number of words in the key input block
+ u_int32_t aes_Nrnd; // the number of cipher rounds
+ u_int32_t aes_e_key[AES_KS_LENGTH]; // the encryption key schedule
+ u_int32_t aes_d_key[AES_KS_LENGTH]; // the decryption key schedule
+#if !defined(AES_BLOCK_SIZE)
+ u_int32_t aes_Ncol; // the number of columns in the cipher state
+#endif
+} aes_context;
+
+// THE CIPHER INTERFACE
+
+#if !defined(AES_BLOCK_SIZE)
+extern void aes_set_blk(aes_context *, const int);
+#endif
+extern void aes_set_key(aes_context *, const unsigned char [], const int, const int);
+extern void aes_encrypt(const aes_context *, const unsigned char [], unsigned char []);
+extern void aes_decrypt(const aes_context *, const unsigned char [], unsigned char []);
+
+// The block length inputs to aes_set_block and aes_set_key are in numbers
+// of bytes or bits. The calls to subroutines must be made in the above
+// order but multiple calls can be made without repeating earlier calls
+// if their parameters have not changed.
+
+#endif // _AES_H
diff --git a/lib/libcrypto/libaes/aes_cbc.c b/lib/libcrypto/libaes/aes_cbc.c
new file mode 100644
index 000000000..962dd1a35
--- /dev/null
+++ b/lib/libcrypto/libaes/aes_cbc.c
@@ -0,0 +1,13 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#include "aes_cbc.h"
+#include "cbc_generic.h"
+/* returns bool success */
+int AES_set_key(aes_context *aes_ctx, const u_int8_t *key, int keysize) {
+ aes_set_key(aes_ctx, key, keysize, 0);
+ return 1;
+}
+CBC_IMPL_BLK16(AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
diff --git a/lib/libcrypto/libaes/aes_cbc.h b/lib/libcrypto/libaes/aes_cbc.h
new file mode 100644
index 000000000..92f5d77f5
--- /dev/null
+++ b/lib/libcrypto/libaes/aes_cbc.h
@@ -0,0 +1,4 @@
+/* Glue header */
+#include "aes.h"
+int AES_set_key(aes_context *aes_ctx, const u_int8_t * key, int keysize);
+int AES_cbc_encrypt(aes_context *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt);
diff --git a/lib/libcrypto/libaes/aes_xcbc_mac.c b/lib/libcrypto/libaes/aes_xcbc_mac.c
new file mode 100644
index 000000000..89d7bc067
--- /dev/null
+++ b/lib/libcrypto/libaes/aes_xcbc_mac.c
@@ -0,0 +1,67 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/kernel.h>
+#define DEBUG(x)
+#else
+#include <stdio.h>
+#include <sys/types.h>
+#define DEBUG(x) x
+#endif
+
+#include "aes.h"
+#include "aes_xcbc_mac.h"
+
+int AES_xcbc_mac_set_key(aes_context_mac *ctxm, const u_int8_t *key, int keylen)
+{
+ int ret=1;
+ aes_block kn[3] = {
+ { 0x01010101, 0x01010101, 0x01010101, 0x01010101 },
+ { 0x02020202, 0x02020202, 0x02020202, 0x02020202 },
+ { 0x03030303, 0x03030303, 0x03030303, 0x03030303 },
+ };
+ aes_set_key(&ctxm->ctx_k1, key, keylen, 0);
+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[0], (u_int8_t *) kn[0]);
+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[1], (u_int8_t *) ctxm->k2);
+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[2], (u_int8_t *) ctxm->k3);
+ aes_set_key(&ctxm->ctx_k1, (u_int8_t *) kn[0], 16, 0);
+ return ret;
+}
+static void do_pad_xor(u_int8_t *out, const u_int8_t *in, int len) {
+ int pos=0;
+ for (pos=1; pos <= 16; pos++, in++, out++) {
+ if (pos <= len)
+ *out ^= *in;
+ if (pos > len) {
+ DEBUG(printf("put 0x80 at pos=%d\n", pos));
+ *out ^= 0x80;
+ break;
+ }
+ }
+}
+static void xor_block(aes_block res, const aes_block op) {
+ res[0] ^= op[0];
+ res[1] ^= op[1];
+ res[2] ^= op[2];
+ res[3] ^= op[3];
+}
+int AES_xcbc_mac_hash(const aes_context_mac *ctxm, const u_int8_t * in, int ilen, u_int8_t hash[16]) {
+ int ret=ilen;
+ u_int32_t out[4] = { 0, 0, 0, 0 };
+ for (; ilen > 16 ; ilen-=16) {
+ xor_block(out, (const u_int32_t*) &in[0]);
+ aes_encrypt(&ctxm->ctx_k1, in, (u_int8_t *)&out[0]);
+ in+=16;
+ }
+ do_pad_xor((u_int8_t *)&out, in, ilen);
+ if (ilen==16) {
+ DEBUG(printf("using k3\n"));
+ xor_block(out, ctxm->k3);
+ }
+ else
+ {
+ DEBUG(printf("using k2\n"));
+ xor_block(out, ctxm->k2);
+ }
+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *)out, hash);
+ return ret;
+}
diff --git a/lib/libcrypto/libaes/aes_xcbc_mac.h b/lib/libcrypto/libaes/aes_xcbc_mac.h
new file mode 100644
index 000000000..baf438cd4
--- /dev/null
+++ b/lib/libcrypto/libaes/aes_xcbc_mac.h
@@ -0,0 +1,12 @@
+#ifndef _AES_XCBC_MAC_H
+#define _AES_XCBC_MAC_H
+
+typedef u_int32_t aes_block[4];
+typedef struct {
+ aes_context ctx_k1;
+ aes_block k2;
+ aes_block k3;
+} aes_context_mac;
+int AES_xcbc_mac_set_key(aes_context_mac *ctxm, const u_int8_t *key, int keylen);
+int AES_xcbc_mac_hash(const aes_context_mac *ctxm, const u_int8_t * in, int ilen, u_int8_t hash[16]);
+#endif /* _AES_XCBC_MAC_H */
diff --git a/lib/libcrypto/libaes/asm/aes-i586.S b/lib/libcrypto/libaes/asm/aes-i586.S
new file mode 100644
index 000000000..df19d0d62
--- /dev/null
+++ b/lib/libcrypto/libaes/asm/aes-i586.S
@@ -0,0 +1,892 @@
+//
+// Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+// All rights reserved.
+//
+// TERMS
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted subject to the following conditions:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The copyright holder's name must not be used to endorse or promote
+// any products derived from this software without his specific prior
+// written permission.
+//
+// This software is provided 'as is' with no express or implied warranties
+// of correctness or fitness for purpose.
+
+// Modified by Jari Ruusu, December 24 2001
+// - Converted syntax to GNU CPP/assembler syntax
+// - C programming interface converted back to "old" API
+// - Minor portability cleanups and speed optimizations
+
+// An AES (Rijndael) implementation for the Pentium. This version only
+// implements the standard AES block length (128 bits, 16 bytes). This code
+// does not preserve the eax, ecx or edx registers or the artihmetic status
+// flags. However, the ebx, esi, edi, and ebp registers are preserved across
+// calls.
+
+// void aes_set_key(aes_context *cx, const unsigned char key[], const int key_len, const int f)
+// void aes_encrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
+// void aes_decrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
+
+#if defined(USE_UNDERLINE)
+# define aes_set_key _aes_set_key
+# define aes_encrypt _aes_encrypt
+# define aes_decrypt _aes_decrypt
+#endif
+#if !defined(ALIGN32BYTES)
+# define ALIGN32BYTES 32
+#endif
+
+ .file "aes-i586.S"
+ .globl aes_set_key
+ .globl aes_encrypt
+ .globl aes_decrypt
+
+#define tlen 1024 // length of each of 4 'xor' arrays (256 32-bit words)
+
+// offsets to parameters with one register pushed onto stack
+
+#define ctx 8 // AES context structure
+#define in_blk 12 // input byte array address parameter
+#define out_blk 16 // output byte array address parameter
+
+// offsets in context structure
+
+#define nkey 0 // key length, size 4
+#define nrnd 4 // number of rounds, size 4
+#define ekey 8 // encryption key schedule base address, size 256
+#define dkey 264 // decryption key schedule base address, size 256
+
+// This macro performs a forward encryption cycle. It is entered with
+// the first previous round column values in %eax, %ebx, %esi and %edi and
+// exits with the final values in the same registers.
+
+#define fwd_rnd(p1,p2) \
+ mov %ebx,(%esp) ;\
+ movzbl %al,%edx ;\
+ mov %eax,%ecx ;\
+ mov p2(%ebp),%eax ;\
+ mov %edi,4(%esp) ;\
+ mov p2+12(%ebp),%edi ;\
+ xor p1(,%edx,4),%eax ;\
+ movzbl %ch,%edx ;\
+ shr $16,%ecx ;\
+ mov p2+4(%ebp),%ebx ;\
+ xor p1+tlen(,%edx,4),%edi ;\
+ movzbl %cl,%edx ;\
+ movzbl %ch,%ecx ;\
+ xor p1+3*tlen(,%ecx,4),%ebx ;\
+ mov %esi,%ecx ;\
+ mov p1+2*tlen(,%edx,4),%esi ;\
+ movzbl %cl,%edx ;\
+ xor p1(,%edx,4),%esi ;\
+ movzbl %ch,%edx ;\
+ shr $16,%ecx ;\
+ xor p1+tlen(,%edx,4),%ebx ;\
+ movzbl %cl,%edx ;\
+ movzbl %ch,%ecx ;\
+ xor p1+2*tlen(,%edx,4),%eax ;\
+ mov (%esp),%edx ;\
+ xor p1+3*tlen(,%ecx,4),%edi ;\
+ movzbl %dl,%ecx ;\
+ xor p2+8(%ebp),%esi ;\
+ xor p1(,%ecx,4),%ebx ;\
+ movzbl %dh,%ecx ;\
+ shr $16,%edx ;\
+ xor p1+tlen(,%ecx,4),%eax ;\
+ movzbl %dl,%ecx ;\
+ movzbl %dh,%edx ;\
+ xor p1+2*tlen(,%ecx,4),%edi ;\
+ mov 4(%esp),%ecx ;\
+ xor p1+3*tlen(,%edx,4),%esi ;\
+ movzbl %cl,%edx ;\
+ xor p1(,%edx,4),%edi ;\
+ movzbl %ch,%edx ;\
+ shr $16,%ecx ;\
+ xor p1+tlen(,%edx,4),%esi ;\
+ movzbl %cl,%edx ;\
+ movzbl %ch,%ecx ;\
+ xor p1+2*tlen(,%edx,4),%ebx ;\
+ xor p1+3*tlen(,%ecx,4),%eax
+
+// This macro performs an inverse encryption cycle. It is entered with
+// the first previous round column values in %eax, %ebx, %esi and %edi and
+// exits with the final values in the same registers.
+
+#define inv_rnd(p1,p2) \
+ movzbl %al,%edx ;\
+ mov %ebx,(%esp) ;\
+ mov %eax,%ecx ;\
+ mov p2(%ebp),%eax ;\
+ mov %edi,4(%esp) ;\
+ mov p2+4(%ebp),%ebx ;\
+ xor p1(,%edx,4),%eax ;\
+ movzbl %ch,%edx ;\
+ shr $16,%ecx ;\
+ mov p2+12(%ebp),%edi ;\
+ xor p1+tlen(,%edx,4),%ebx ;\
+ movzbl %cl,%edx ;\
+ movzbl %ch,%ecx ;\
+ xor p1+3*tlen(,%ecx,4),%edi ;\
+ mov %esi,%ecx ;\
+ mov p1+2*tlen(,%edx,4),%esi ;\
+ movzbl %cl,%edx ;\
+ xor p1(,%edx,4),%esi ;\
+ movzbl %ch,%edx ;\
+ shr $16,%ecx ;\
+ xor p1+tlen(,%edx,4),%edi ;\
+ movzbl %cl,%edx ;\
+ movzbl %ch,%ecx ;\
+ xor p1+2*tlen(,%edx,4),%eax ;\
+ mov (%esp),%edx ;\
+ xor p1+3*tlen(,%ecx,4),%ebx ;\
+ movzbl %dl,%ecx ;\
+ xor p2+8(%ebp),%esi ;\
+ xor p1(,%ecx,4),%ebx ;\
+ movzbl %dh,%ecx ;\
+ shr $16,%edx ;\
+ xor p1+tlen(,%ecx,4),%esi ;\
+ movzbl %dl,%ecx ;\
+ movzbl %dh,%edx ;\
+ xor p1+2*tlen(,%ecx,4),%edi ;\
+ mov 4(%esp),%ecx ;\
+ xor p1+3*tlen(,%edx,4),%eax ;\
+ movzbl %cl,%edx ;\
+ xor p1(,%edx,4),%edi ;\
+ movzbl %ch,%edx ;\
+ shr $16,%ecx ;\
+ xor p1+tlen(,%edx,4),%eax ;\
+ movzbl %cl,%edx ;\
+ movzbl %ch,%ecx ;\
+ xor p1+2*tlen(,%edx,4),%ebx ;\
+ xor p1+3*tlen(,%ecx,4),%esi
+
+// AES (Rijndael) Encryption Subroutine
+
+ .text
+ .align ALIGN32BYTES
+aes_encrypt:
+ push %ebp
+ mov ctx(%esp),%ebp // pointer to context
+ mov in_blk(%esp),%ecx
+ push %ebx
+ push %esi
+ push %edi
+ mov nrnd(%ebp),%edx // number of rounds
+ lea ekey+16(%ebp),%ebp // key pointer
+
+// input four columns and xor in first round key
+
+ mov (%ecx),%eax
+ mov 4(%ecx),%ebx
+ mov 8(%ecx),%esi
+ mov 12(%ecx),%edi
+ xor -16(%ebp),%eax
+ xor -12(%ebp),%ebx
+ xor -8(%ebp),%esi
+ xor -4(%ebp),%edi
+
+ sub $8,%esp // space for register saves on stack
+
+ sub $10,%edx
+ je aes_15
+ add $32,%ebp
+ sub $2,%edx
+ je aes_13
+ add $32,%ebp
+
+ fwd_rnd(aes_ft_tab,-64) // 14 rounds for 256-bit key
+ fwd_rnd(aes_ft_tab,-48)
+aes_13: fwd_rnd(aes_ft_tab,-32) // 12 rounds for 192-bit key
+ fwd_rnd(aes_ft_tab,-16)
+aes_15: fwd_rnd(aes_ft_tab,0) // 10 rounds for 128-bit key
+ fwd_rnd(aes_ft_tab,16)
+ fwd_rnd(aes_ft_tab,32)
+ fwd_rnd(aes_ft_tab,48)
+ fwd_rnd(aes_ft_tab,64)
+ fwd_rnd(aes_ft_tab,80)
+ fwd_rnd(aes_ft_tab,96)
+ fwd_rnd(aes_ft_tab,112)
+ fwd_rnd(aes_ft_tab,128)
+ fwd_rnd(aes_fl_tab,144) // last round uses a different table
+
+// move final values to the output array.
+
+ mov out_blk+20(%esp),%ebp
+ add $8,%esp
+ mov %eax,(%ebp)
+ mov %ebx,4(%ebp)
+ mov %esi,8(%ebp)
+ mov %edi,12(%ebp)
+ pop %edi
+ pop %esi
+ pop %ebx
+ pop %ebp
+ ret
+
+
+// AES (Rijndael) Decryption Subroutine
+
+ .align ALIGN32BYTES
+aes_decrypt:
+ push %ebp
+ mov ctx(%esp),%ebp // pointer to context
+ mov in_blk(%esp),%ecx
+ push %ebx
+ push %esi
+ push %edi
+ mov nrnd(%ebp),%edx // number of rounds
+ lea dkey+16(%ebp),%ebp // key pointer
+
+// input four columns and xor in first round key
+
+ mov (%ecx),%eax
+ mov 4(%ecx),%ebx
+ mov 8(%ecx),%esi
+ mov 12(%ecx),%edi
+ xor -16(%ebp),%eax
+ xor -12(%ebp),%ebx
+ xor -8(%ebp),%esi
+ xor -4(%ebp),%edi
+
+ sub $8,%esp // space for register saves on stack
+
+ sub $10,%edx
+ je aes_25
+ add $32,%ebp
+ sub $2,%edx
+ je aes_23
+ add $32,%ebp
+
+ inv_rnd(aes_it_tab,-64) // 14 rounds for 256-bit key
+ inv_rnd(aes_it_tab,-48)
+aes_23: inv_rnd(aes_it_tab,-32) // 12 rounds for 192-bit key
+ inv_rnd(aes_it_tab,-16)
+aes_25: inv_rnd(aes_it_tab,0) // 10 rounds for 128-bit key
+ inv_rnd(aes_it_tab,16)
+ inv_rnd(aes_it_tab,32)
+ inv_rnd(aes_it_tab,48)
+ inv_rnd(aes_it_tab,64)
+ inv_rnd(aes_it_tab,80)
+ inv_rnd(aes_it_tab,96)
+ inv_rnd(aes_it_tab,112)
+ inv_rnd(aes_it_tab,128)
+ inv_rnd(aes_il_tab,144) // last round uses a different table
+
+// move final values to the output array.
+
+ mov out_blk+20(%esp),%ebp
+ add $8,%esp
+ mov %eax,(%ebp)
+ mov %ebx,4(%ebp)
+ mov %esi,8(%ebp)
+ mov %edi,12(%ebp)
+ pop %edi
+ pop %esi
+ pop %ebx
+ pop %ebp
+ ret
+
+// AES (Rijndael) Key Schedule Subroutine
+
+// input/output parameters
+
+#define aes_cx 12 // AES context
+#define in_key 16 // key input array address
+#define key_ln 20 // key length, bytes (16,24,32) or bits (128,192,256)
+#define ed_flg 24 // 0=create both encr/decr keys, 1=create encr key only
+
+// offsets for locals
+
+#define cnt -4
+#define kpf -8
+#define slen 8
+
+// This macro performs a column mixing operation on an input 32-bit
+// word to give a 32-bit result. It uses each of the 4 bytes in the
+// the input column to index 4 different tables of 256 32-bit words
+// that are xored together to form the output value.
+
+#define mix_col(p1) \
+ movzbl %bl,%ecx ;\
+ mov p1(,%ecx,4),%eax ;\
+ movzbl %bh,%ecx ;\
+ ror $16,%ebx ;\
+ xor p1+tlen(,%ecx,4),%eax ;\
+ movzbl %bl,%ecx ;\
+ xor p1+2*tlen(,%ecx,4),%eax ;\
+ movzbl %bh,%ecx ;\
+ xor p1+3*tlen(,%ecx,4),%eax
+
+// Key Schedule Macros
+
+#define ksc4(p1) \
+ rol $24,%ebx ;\
+ mix_col(aes_fl_tab) ;\
+ ror $8,%ebx ;\
+ xor 4*p1+aes_rcon_tab,%eax ;\
+ xor %eax,%esi ;\
+ xor %esi,%ebp ;\
+ mov %esi,16*p1(%edi) ;\
+ mov %ebp,16*p1+4(%edi) ;\
+ xor %ebp,%edx ;\
+ xor %edx,%ebx ;\
+ mov %edx,16*p1+8(%edi) ;\
+ mov %ebx,16*p1+12(%edi)
+
+#define ksc6(p1) \
+ rol $24,%ebx ;\
+ mix_col(aes_fl_tab) ;\
+ ror $8,%ebx ;\
+ xor 4*p1+aes_rcon_tab,%eax ;\
+ xor 24*p1-24(%edi),%eax ;\
+ mov %eax,24*p1(%edi) ;\
+ xor 24*p1-20(%edi),%eax ;\
+ mov %eax,24*p1+4(%edi) ;\
+ xor %eax,%esi ;\
+ xor %esi,%ebp ;\
+ mov %esi,24*p1+8(%edi) ;\
+ mov %ebp,24*p1+12(%edi) ;\
+ xor %ebp,%edx ;\
+ xor %edx,%ebx ;\
+ mov %edx,24*p1+16(%edi) ;\
+ mov %ebx,24*p1+20(%edi)
+
+#define ksc8(p1) \
+ rol $24,%ebx ;\
+ mix_col(aes_fl_tab) ;\
+ ror $8,%ebx ;\
+ xor 4*p1+aes_rcon_tab,%eax ;\
+ xor 32*p1-32(%edi),%eax ;\
+ mov %eax,32*p1(%edi) ;\
+ xor 32*p1-28(%edi),%eax ;\
+ mov %eax,32*p1+4(%edi) ;\
+ xor 32*p1-24(%edi),%eax ;\
+ mov %eax,32*p1+8(%edi) ;\
+ xor 32*p1-20(%edi),%eax ;\
+ mov %eax,32*p1+12(%edi) ;\
+ push %ebx ;\
+ mov %eax,%ebx ;\
+ mix_col(aes_fl_tab) ;\
+ pop %ebx ;\
+ xor %eax,%esi ;\
+ xor %esi,%ebp ;\
+ mov %esi,32*p1+16(%edi) ;\
+ mov %ebp,32*p1+20(%edi) ;\
+ xor %ebp,%edx ;\
+ xor %edx,%ebx ;\
+ mov %edx,32*p1+24(%edi) ;\
+ mov %ebx,32*p1+28(%edi)
+
+ .align ALIGN32BYTES
+aes_set_key:
+ pushfl
+ push %ebp
+ mov %esp,%ebp
+ sub $slen,%esp
+ push %ebx
+ push %esi
+ push %edi
+
+ mov aes_cx(%ebp),%edx // edx -> AES context
+
+ mov key_ln(%ebp),%ecx // key length
+ cmpl $128,%ecx
+ jb aes_30
+ shr $3,%ecx
+aes_30: cmpl $32,%ecx
+ je aes_32
+ cmpl $24,%ecx
+ je aes_32
+ mov $16,%ecx
+aes_32: shr $2,%ecx
+ mov %ecx,nkey(%edx)
+
+ lea 6(%ecx),%eax // 10/12/14 for 4/6/8 32-bit key length
+ mov %eax,nrnd(%edx)
+
+ mov in_key(%ebp),%esi // key input array
+ lea ekey(%edx),%edi // key position in AES context
+ cld
+ push %ebp
+ mov %ecx,%eax // save key length in eax
+ rep ; movsl // words in the key schedule
+ mov -4(%esi),%ebx // put some values in registers
+ mov -8(%esi),%edx // to allow faster code
+ mov -12(%esi),%ebp
+ mov -16(%esi),%esi
+
+ cmpl $4,%eax // jump on key size
+ je aes_36
+ cmpl $6,%eax
+ je aes_35
+
+ ksc8(0)
+ ksc8(1)
+ ksc8(2)
+ ksc8(3)
+ ksc8(4)
+ ksc8(5)
+ ksc8(6)
+ jmp aes_37
+aes_35: ksc6(0)
+ ksc6(1)
+ ksc6(2)
+ ksc6(3)
+ ksc6(4)
+ ksc6(5)
+ ksc6(6)
+ ksc6(7)
+ jmp aes_37
+aes_36: ksc4(0)
+ ksc4(1)
+ ksc4(2)
+ ksc4(3)
+ ksc4(4)
+ ksc4(5)
+ ksc4(6)
+ ksc4(7)
+ ksc4(8)
+ ksc4(9)
+aes_37: pop %ebp
+ mov aes_cx(%ebp),%edx // edx -> AES context
+ cmpl $0,ed_flg(%ebp)
+ jne aes_39
+
+// compile decryption key schedule from encryption schedule - reverse
+// order and do mix_column operation on round keys except first and last
+
+ mov nrnd(%edx),%eax // kt = cx->d_key + nc * cx->Nrnd
+ shl $2,%eax
+ lea dkey(%edx,%eax,4),%edi
+ lea ekey(%edx),%esi // kf = cx->e_key
+
+ movsl // copy first round key (unmodified)
+ movsl
+ movsl
+ movsl
+ sub $32,%edi
+ movl $1,cnt(%ebp)
+aes_38: // do mix column on each column of
+ lodsl // each round key
+ mov %eax,%ebx
+ mix_col(aes_im_tab)
+ stosl
+ lodsl
+ mov %eax,%ebx
+ mix_col(aes_im_tab)
+ stosl
+ lodsl
+ mov %eax,%ebx
+ mix_col(aes_im_tab)
+ stosl
+ lodsl
+ mov %eax,%ebx
+ mix_col(aes_im_tab)
+ stosl
+ sub $32,%edi
+
+ incl cnt(%ebp)
+ mov cnt(%ebp),%eax
+ cmp nrnd(%edx),%eax
+ jb aes_38
+
+ movsl // copy last round key (unmodified)
+ movsl
+ movsl
+ movsl
+aes_39: pop %edi
+ pop %esi
+ pop %ebx
+ mov %ebp,%esp
+ pop %ebp
+ popfl
+ ret
+
+
+// finite field multiplies by {02}, {04} and {08}
+
+#define f2(x) ((x<<1)^(((x>>7)&1)*0x11b))
+#define f4(x) ((x<<2)^(((x>>6)&1)*0x11b)^(((x>>6)&2)*0x11b))
+#define f8(x) ((x<<3)^(((x>>5)&1)*0x11b)^(((x>>5)&2)*0x11b)^(((x>>5)&4)*0x11b))
+
+// finite field multiplies required in table generation
+
+#define f3(x) (f2(x) ^ x)
+#define f9(x) (f8(x) ^ x)
+#define fb(x) (f8(x) ^ f2(x) ^ x)
+#define fd(x) (f8(x) ^ f4(x) ^ x)
+#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
+
+// These defines generate the forward table entries
+
+#define u0(x) ((f3(x) << 24) | (x << 16) | (x << 8) | f2(x))
+#define u1(x) ((x << 24) | (x << 16) | (f2(x) << 8) | f3(x))
+#define u2(x) ((x << 24) | (f2(x) << 16) | (f3(x) << 8) | x)
+#define u3(x) ((f2(x) << 24) | (f3(x) << 16) | (x << 8) | x)
+
+// These defines generate the inverse table entries
+
+#define v0(x) ((fb(x) << 24) | (fd(x) << 16) | (f9(x) << 8) | fe(x))
+#define v1(x) ((fd(x) << 24) | (f9(x) << 16) | (fe(x) << 8) | fb(x))
+#define v2(x) ((f9(x) << 24) | (fe(x) << 16) | (fb(x) << 8) | fd(x))
+#define v3(x) ((fe(x) << 24) | (fb(x) << 16) | (fd(x) << 8) | f9(x))
+
+// These defines generate entries for the last round tables
+
+#define w0(x) (x)
+#define w1(x) (x << 8)
+#define w2(x) (x << 16)
+#define w3(x) (x << 24)
+
+// macro to generate inverse mix column tables (needed for the key schedule)
+
+#define im_data0(p1) \
+ .long p1(0x00),p1(0x01),p1(0x02),p1(0x03),p1(0x04),p1(0x05),p1(0x06),p1(0x07) ;\
+ .long p1(0x08),p1(0x09),p1(0x0a),p1(0x0b),p1(0x0c),p1(0x0d),p1(0x0e),p1(0x0f) ;\
+ .long p1(0x10),p1(0x11),p1(0x12),p1(0x13),p1(0x14),p1(0x15),p1(0x16),p1(0x17) ;\
+ .long p1(0x18),p1(0x19),p1(0x1a),p1(0x1b),p1(0x1c),p1(0x1d),p1(0x1e),p1(0x1f)
+#define im_data1(p1) \
+ .long p1(0x20),p1(0x21),p1(0x22),p1(0x23),p1(0x24),p1(0x25),p1(0x26),p1(0x27) ;\
+ .long p1(0x28),p1(0x29),p1(0x2a),p1(0x2b),p1(0x2c),p1(0x2d),p1(0x2e),p1(0x2f) ;\
+ .long p1(0x30),p1(0x31),p1(0x32),p1(0x33),p1(0x34),p1(0x35),p1(0x36),p1(0x37) ;\
+ .long p1(0x38),p1(0x39),p1(0x3a),p1(0x3b),p1(0x3c),p1(0x3d),p1(0x3e),p1(0x3f)
+#define im_data2(p1) \
+ .long p1(0x40),p1(0x41),p1(0x42),p1(0x43),p1(0x44),p1(0x45),p1(0x46),p1(0x47) ;\
+ .long p1(0x48),p1(0x49),p1(0x4a),p1(0x4b),p1(0x4c),p1(0x4d),p1(0x4e),p1(0x4f) ;\
+ .long p1(0x50),p1(0x51),p1(0x52),p1(0x53),p1(0x54),p1(0x55),p1(0x56),p1(0x57) ;\
+ .long p1(0x58),p1(0x59),p1(0x5a),p1(0x5b),p1(0x5c),p1(0x5d),p1(0x5e),p1(0x5f)
+#define im_data3(p1) \
+ .long p1(0x60),p1(0x61),p1(0x62),p1(0x63),p1(0x64),p1(0x65),p1(0x66),p1(0x67) ;\
+ .long p1(0x68),p1(0x69),p1(0x6a),p1(0x6b),p1(0x6c),p1(0x6d),p1(0x6e),p1(0x6f) ;\
+ .long p1(0x70),p1(0x71),p1(0x72),p1(0x73),p1(0x74),p1(0x75),p1(0x76),p1(0x77) ;\
+ .long p1(0x78),p1(0x79),p1(0x7a),p1(0x7b),p1(0x7c),p1(0x7d),p1(0x7e),p1(0x7f)
+#define im_data4(p1) \
+ .long p1(0x80),p1(0x81),p1(0x82),p1(0x83),p1(0x84),p1(0x85),p1(0x86),p1(0x87) ;\
+ .long p1(0x88),p1(0x89),p1(0x8a),p1(0x8b),p1(0x8c),p1(0x8d),p1(0x8e),p1(0x8f) ;\
+ .long p1(0x90),p1(0x91),p1(0x92),p1(0x93),p1(0x94),p1(0x95),p1(0x96),p1(0x97) ;\
+ .long p1(0x98),p1(0x99),p1(0x9a),p1(0x9b),p1(0x9c),p1(0x9d),p1(0x9e),p1(0x9f)
+#define im_data5(p1) \
+ .long p1(0xa0),p1(0xa1),p1(0xa2),p1(0xa3),p1(0xa4),p1(0xa5),p1(0xa6),p1(0xa7) ;\
+ .long p1(0xa8),p1(0xa9),p1(0xaa),p1(0xab),p1(0xac),p1(0xad),p1(0xae),p1(0xaf) ;\
+ .long p1(0xb0),p1(0xb1),p1(0xb2),p1(0xb3),p1(0xb4),p1(0xb5),p1(0xb6),p1(0xb7) ;\
+ .long p1(0xb8),p1(0xb9),p1(0xba),p1(0xbb),p1(0xbc),p1(0xbd),p1(0xbe),p1(0xbf)
+#define im_data6(p1) \
+ .long p1(0xc0),p1(0xc1),p1(0xc2),p1(0xc3),p1(0xc4),p1(0xc5),p1(0xc6),p1(0xc7) ;\
+ .long p1(0xc8),p1(0xc9),p1(0xca),p1(0xcb),p1(0xcc),p1(0xcd),p1(0xce),p1(0xcf) ;\
+ .long p1(0xd0),p1(0xd1),p1(0xd2),p1(0xd3),p1(0xd4),p1(0xd5),p1(0xd6),p1(0xd7) ;\
+ .long p1(0xd8),p1(0xd9),p1(0xda),p1(0xdb),p1(0xdc),p1(0xdd),p1(0xde),p1(0xdf)
+#define im_data7(p1) \
+ .long p1(0xe0),p1(0xe1),p1(0xe2),p1(0xe3),p1(0xe4),p1(0xe5),p1(0xe6),p1(0xe7) ;\
+ .long p1(0xe8),p1(0xe9),p1(0xea),p1(0xeb),p1(0xec),p1(0xed),p1(0xee),p1(0xef) ;\
+ .long p1(0xf0),p1(0xf1),p1(0xf2),p1(0xf3),p1(0xf4),p1(0xf5),p1(0xf6),p1(0xf7) ;\
+ .long p1(0xf8),p1(0xf9),p1(0xfa),p1(0xfb),p1(0xfc),p1(0xfd),p1(0xfe),p1(0xff)
+
+// S-box data - 256 entries
+
+#define sb_data0(p1) \
+ .long p1(0x63),p1(0x7c),p1(0x77),p1(0x7b),p1(0xf2),p1(0x6b),p1(0x6f),p1(0xc5) ;\
+ .long p1(0x30),p1(0x01),p1(0x67),p1(0x2b),p1(0xfe),p1(0xd7),p1(0xab),p1(0x76) ;\
+ .long p1(0xca),p1(0x82),p1(0xc9),p1(0x7d),p1(0xfa),p1(0x59),p1(0x47),p1(0xf0) ;\
+ .long p1(0xad),p1(0xd4),p1(0xa2),p1(0xaf),p1(0x9c),p1(0xa4),p1(0x72),p1(0xc0)
+#define sb_data1(p1) \
+ .long p1(0xb7),p1(0xfd),p1(0x93),p1(0x26),p1(0x36),p1(0x3f),p1(0xf7),p1(0xcc) ;\
+ .long p1(0x34),p1(0xa5),p1(0xe5),p1(0xf1),p1(0x71),p1(0xd8),p1(0x31),p1(0x15) ;\
+ .long p1(0x04),p1(0xc7),p1(0x23),p1(0xc3),p1(0x18),p1(0x96),p1(0x05),p1(0x9a) ;\
+ .long p1(0x07),p1(0x12),p1(0x80),p1(0xe2),p1(0xeb),p1(0x27),p1(0xb2),p1(0x75)
+#define sb_data2(p1) \
+ .long p1(0x09),p1(0x83),p1(0x2c),p1(0x1a),p1(0x1b),p1(0x6e),p1(0x5a),p1(0xa0) ;\
+ .long p1(0x52),p1(0x3b),p1(0xd6),p1(0xb3),p1(0x29),p1(0xe3),p1(0x2f),p1(0x84) ;\
+ .long p1(0x53),p1(0xd1),p1(0x00),p1(0xed),p1(0x20),p1(0xfc),p1(0xb1),p1(0x5b) ;\
+ .long p1(0x6a),p1(0xcb),p1(0xbe),p1(0x39),p1(0x4a),p1(0x4c),p1(0x58),p1(0xcf)
+#define sb_data3(p1) \
+ .long p1(0xd0),p1(0xef),p1(0xaa),p1(0xfb),p1(0x43),p1(0x4d),p1(0x33),p1(0x85) ;\
+ .long p1(0x45),p1(0xf9),p1(0x02),p1(0x7f),p1(0x50),p1(0x3c),p1(0x9f),p1(0xa8) ;\
+ .long p1(0x51),p1(0xa3),p1(0x40),p1(0x8f),p1(0x92),p1(0x9d),p1(0x38),p1(0xf5) ;\
+ .long p1(0xbc),p1(0xb6),p1(0xda),p1(0x21),p1(0x10),p1(0xff),p1(0xf3),p1(0xd2)
+#define sb_data4(p1) \
+ .long p1(0xcd),p1(0x0c),p1(0x13),p1(0xec),p1(0x5f),p1(0x97),p1(0x44),p1(0x17) ;\
+ .long p1(0xc4),p1(0xa7),p1(0x7e),p1(0x3d),p1(0x64),p1(0x5d),p1(0x19),p1(0x73) ;\
+ .long p1(0x60),p1(0x81),p1(0x4f),p1(0xdc),p1(0x22),p1(0x2a),p1(0x90),p1(0x88) ;\
+ .long p1(0x46),p1(0xee),p1(0xb8),p1(0x14),p1(0xde),p1(0x5e),p1(0x0b),p1(0xdb)
+#define sb_data5(p1) \
+ .long p1(0xe0),p1(0x32),p1(0x3a),p1(0x0a),p1(0x49),p1(0x06),p1(0x24),p1(0x5c) ;\
+ .long p1(0xc2),p1(0xd3),p1(0xac),p1(0x62),p1(0x91),p1(0x95),p1(0xe4),p1(0x79) ;\
+ .long p1(0xe7),p1(0xc8),p1(0x37),p1(0x6d),p1(0x8d),p1(0xd5),p1(0x4e),p1(0xa9) ;\
+ .long p1(0x6c),p1(0x56),p1(0xf4),p1(0xea),p1(0x65),p1(0x7a),p1(0xae),p1(0x08)
+#define sb_data6(p1) \
+ .long p1(0xba),p1(0x78),p1(0x25),p1(0x2e),p1(0x1c),p1(0xa6),p1(0xb4),p1(0xc6) ;\
+ .long p1(0xe8),p1(0xdd),p1(0x74),p1(0x1f),p1(0x4b),p1(0xbd),p1(0x8b),p1(0x8a) ;\
+ .long p1(0x70),p1(0x3e),p1(0xb5),p1(0x66),p1(0x48),p1(0x03),p1(0xf6),p1(0x0e) ;\
+ .long p1(0x61),p1(0x35),p1(0x57),p1(0xb9),p1(0x86),p1(0xc1),p1(0x1d),p1(0x9e)
+#define sb_data7(p1) \
+ .long p1(0xe1),p1(0xf8),p1(0x98),p1(0x11),p1(0x69),p1(0xd9),p1(0x8e),p1(0x94) ;\
+ .long p1(0x9b),p1(0x1e),p1(0x87),p1(0xe9),p1(0xce),p1(0x55),p1(0x28),p1(0xdf) ;\
+ .long p1(0x8c),p1(0xa1),p1(0x89),p1(0x0d),p1(0xbf),p1(0xe6),p1(0x42),p1(0x68) ;\
+ .long p1(0x41),p1(0x99),p1(0x2d),p1(0x0f),p1(0xb0),p1(0x54),p1(0xbb),p1(0x16)
+
+// Inverse S-box data - 256 entries
+
+#define ib_data0(p1) \
+ .long p1(0x52),p1(0x09),p1(0x6a),p1(0xd5),p1(0x30),p1(0x36),p1(0xa5),p1(0x38) ;\
+ .long p1(0xbf),p1(0x40),p1(0xa3),p1(0x9e),p1(0x81),p1(0xf3),p1(0xd7),p1(0xfb) ;\
+ .long p1(0x7c),p1(0xe3),p1(0x39),p1(0x82),p1(0x9b),p1(0x2f),p1(0xff),p1(0x87) ;\
+ .long p1(0x34),p1(0x8e),p1(0x43),p1(0x44),p1(0xc4),p1(0xde),p1(0xe9),p1(0xcb)
+#define ib_data1(p1) \
+ .long p1(0x54),p1(0x7b),p1(0x94),p1(0x32),p1(0xa6),p1(0xc2),p1(0x23),p1(0x3d) ;\
+ .long p1(0xee),p1(0x4c),p1(0x95),p1(0x0b),p1(0x42),p1(0xfa),p1(0xc3),p1(0x4e) ;\
+ .long p1(0x08),p1(0x2e),p1(0xa1),p1(0x66),p1(0x28),p1(0xd9),p1(0x24),p1(0xb2) ;\
+ .long p1(0x76),p1(0x5b),p1(0xa2),p1(0x49),p1(0x6d),p1(0x8b),p1(0xd1),p1(0x25)
+#define ib_data2(p1) \
+ .long p1(0x72),p1(0xf8),p1(0xf6),p1(0x64),p1(0x86),p1(0x68),p1(0x98),p1(0x16) ;\
+ .long p1(0xd4),p1(0xa4),p1(0x5c),p1(0xcc),p1(0x5d),p1(0x65),p1(0xb6),p1(0x92) ;\
+ .long p1(0x6c),p1(0x70),p1(0x48),p1(0x50),p1(0xfd),p1(0xed),p1(0xb9),p1(0xda) ;\
+ .long p1(0x5e),p1(0x15),p1(0x46),p1(0x57),p1(0xa7),p1(0x8d),p1(0x9d),p1(0x84)
+#define ib_data3(p1) \
+ .long p1(0x90),p1(0xd8),p1(0xab),p1(0x00),p1(0x8c),p1(0xbc),p1(0xd3),p1(0x0a) ;\
+ .long p1(0xf7),p1(0xe4),p1(0x58),p1(0x05),p1(0xb8),p1(0xb3),p1(0x45),p1(0x06) ;\
+ .long p1(0xd0),p1(0x2c),p1(0x1e),p1(0x8f),p1(0xca),p1(0x3f),p1(0x0f),p1(0x02) ;\
+ .long p1(0xc1),p1(0xaf),p1(0xbd),p1(0x03),p1(0x01),p1(0x13),p1(0x8a),p1(0x6b)
+#define ib_data4(p1) \
+ .long p1(0x3a),p1(0x91),p1(0x11),p1(0x41),p1(0x4f),p1(0x67),p1(0xdc),p1(0xea) ;\
+ .long p1(0x97),p1(0xf2),p1(0xcf),p1(0xce),p1(0xf0),p1(0xb4),p1(0xe6),p1(0x73) ;\
+ .long p1(0x96),p1(0xac),p1(0x74),p1(0x22),p1(0xe7),p1(0xad),p1(0x35),p1(0x85) ;\
+ .long p1(0xe2),p1(0xf9),p1(0x37),p1(0xe8),p1(0x1c),p1(0x75),p1(0xdf),p1(0x6e)
+#define ib_data5(p1) \
+ .long p1(0x47),p1(0xf1),p1(0x1a),p1(0x71),p1(0x1d),p1(0x29),p1(0xc5),p1(0x89) ;\
+ .long p1(0x6f),p1(0xb7),p1(0x62),p1(0x0e),p1(0xaa),p1(0x18),p1(0xbe),p1(0x1b) ;\
+ .long p1(0xfc),p1(0x56),p1(0x3e),p1(0x4b),p1(0xc6),p1(0xd2),p1(0x79),p1(0x20) ;\
+ .long p1(0x9a),p1(0xdb),p1(0xc0),p1(0xfe),p1(0x78),p1(0xcd),p1(0x5a),p1(0xf4)
+#define ib_data6(p1) \
+ .long p1(0x1f),p1(0xdd),p1(0xa8),p1(0x33),p1(0x88),p1(0x07),p1(0xc7),p1(0x31) ;\
+ .long p1(0xb1),p1(0x12),p1(0x10),p1(0x59),p1(0x27),p1(0x80),p1(0xec),p1(0x5f) ;\
+ .long p1(0x60),p1(0x51),p1(0x7f),p1(0xa9),p1(0x19),p1(0xb5),p1(0x4a),p1(0x0d) ;\
+ .long p1(0x2d),p1(0xe5),p1(0x7a),p1(0x9f),p1(0x93),p1(0xc9),p1(0x9c),p1(0xef)
+#define ib_data7(p1) \
+ .long p1(0xa0),p1(0xe0),p1(0x3b),p1(0x4d),p1(0xae),p1(0x2a),p1(0xf5),p1(0xb0) ;\
+ .long p1(0xc8),p1(0xeb),p1(0xbb),p1(0x3c),p1(0x83),p1(0x53),p1(0x99),p1(0x61) ;\
+ .long p1(0x17),p1(0x2b),p1(0x04),p1(0x7e),p1(0xba),p1(0x77),p1(0xd6),p1(0x26) ;\
+ .long p1(0xe1),p1(0x69),p1(0x14),p1(0x63),p1(0x55),p1(0x21),p1(0x0c),p1(0x7d)
+
+// The rcon_table (needed for the key schedule)
+//
+// Here is original Dr Brian Gladman's source code:
+// _rcon_tab:
+// %assign x 1
+// %rep 29
+// dd x
+// %assign x f2(x)
+// %endrep
+//
+// Here is precomputed output (it's more portable this way):
+
+ .align ALIGN32BYTES
+aes_rcon_tab:
+ .long 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
+ .long 0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f
+ .long 0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4
+ .long 0xb3,0x7d,0xfa,0xef,0xc5
+
+// The forward xor tables
+
+ .align ALIGN32BYTES
+aes_ft_tab:
+ sb_data0(u0)
+ sb_data1(u0)
+ sb_data2(u0)
+ sb_data3(u0)
+ sb_data4(u0)
+ sb_data5(u0)
+ sb_data6(u0)
+ sb_data7(u0)
+
+ sb_data0(u1)
+ sb_data1(u1)
+ sb_data2(u1)
+ sb_data3(u1)
+ sb_data4(u1)
+ sb_data5(u1)
+ sb_data6(u1)
+ sb_data7(u1)
+
+ sb_data0(u2)
+ sb_data1(u2)
+ sb_data2(u2)
+ sb_data3(u2)
+ sb_data4(u2)
+ sb_data5(u2)
+ sb_data6(u2)
+ sb_data7(u2)
+
+ sb_data0(u3)
+ sb_data1(u3)
+ sb_data2(u3)
+ sb_data3(u3)
+ sb_data4(u3)
+ sb_data5(u3)
+ sb_data6(u3)
+ sb_data7(u3)
+
+ .align ALIGN32BYTES
+aes_fl_tab:
+ sb_data0(w0)
+ sb_data1(w0)
+ sb_data2(w0)
+ sb_data3(w0)
+ sb_data4(w0)
+ sb_data5(w0)
+ sb_data6(w0)
+ sb_data7(w0)
+
+ sb_data0(w1)
+ sb_data1(w1)
+ sb_data2(w1)
+ sb_data3(w1)
+ sb_data4(w1)
+ sb_data5(w1)
+ sb_data6(w1)
+ sb_data7(w1)
+
+ sb_data0(w2)
+ sb_data1(w2)
+ sb_data2(w2)
+ sb_data3(w2)
+ sb_data4(w2)
+ sb_data5(w2)
+ sb_data6(w2)
+ sb_data7(w2)
+
+ sb_data0(w3)
+ sb_data1(w3)
+ sb_data2(w3)
+ sb_data3(w3)
+ sb_data4(w3)
+ sb_data5(w3)
+ sb_data6(w3)
+ sb_data7(w3)
+
+// The inverse xor tables
+
+ .align ALIGN32BYTES
+aes_it_tab:
+ ib_data0(v0)
+ ib_data1(v0)
+ ib_data2(v0)
+ ib_data3(v0)
+ ib_data4(v0)
+ ib_data5(v0)
+ ib_data6(v0)
+ ib_data7(v0)
+
+ ib_data0(v1)
+ ib_data1(v1)
+ ib_data2(v1)
+ ib_data3(v1)
+ ib_data4(v1)
+ ib_data5(v1)
+ ib_data6(v1)
+ ib_data7(v1)
+
+ ib_data0(v2)
+ ib_data1(v2)
+ ib_data2(v2)
+ ib_data3(v2)
+ ib_data4(v2)
+ ib_data5(v2)
+ ib_data6(v2)
+ ib_data7(v2)
+
+ ib_data0(v3)
+ ib_data1(v3)
+ ib_data2(v3)
+ ib_data3(v3)
+ ib_data4(v3)
+ ib_data5(v3)
+ ib_data6(v3)
+ ib_data7(v3)
+
+ .align ALIGN32BYTES
+aes_il_tab:
+ ib_data0(w0)
+ ib_data1(w0)
+ ib_data2(w0)
+ ib_data3(w0)
+ ib_data4(w0)
+ ib_data5(w0)
+ ib_data6(w0)
+ ib_data7(w0)
+
+ ib_data0(w1)
+ ib_data1(w1)
+ ib_data2(w1)
+ ib_data3(w1)
+ ib_data4(w1)
+ ib_data5(w1)
+ ib_data6(w1)
+ ib_data7(w1)
+
+ ib_data0(w2)
+ ib_data1(w2)
+ ib_data2(w2)
+ ib_data3(w2)
+ ib_data4(w2)
+ ib_data5(w2)
+ ib_data6(w2)
+ ib_data7(w2)
+
+ ib_data0(w3)
+ ib_data1(w3)
+ ib_data2(w3)
+ ib_data3(w3)
+ ib_data4(w3)
+ ib_data5(w3)
+ ib_data6(w3)
+ ib_data7(w3)
+
+// The inverse mix column tables
+
+ .align ALIGN32BYTES
+aes_im_tab:
+ im_data0(v0)
+ im_data1(v0)
+ im_data2(v0)
+ im_data3(v0)
+ im_data4(v0)
+ im_data5(v0)
+ im_data6(v0)
+ im_data7(v0)
+
+ im_data0(v1)
+ im_data1(v1)
+ im_data2(v1)
+ im_data3(v1)
+ im_data4(v1)
+ im_data5(v1)
+ im_data6(v1)
+ im_data7(v1)
+
+ im_data0(v2)
+ im_data1(v2)
+ im_data2(v2)
+ im_data3(v2)
+ im_data4(v2)
+ im_data5(v2)
+ im_data6(v2)
+ im_data7(v2)
+
+ im_data0(v3)
+ im_data1(v3)
+ im_data2(v3)
+ im_data3(v3)
+ im_data4(v3)
+ im_data5(v3)
+ im_data6(v3)
+ im_data7(v3)
diff --git a/lib/libcrypto/libaes/test_main.c b/lib/libcrypto/libaes/test_main.c
new file mode 100644
index 000000000..5fd4599be
--- /dev/null
+++ b/lib/libcrypto/libaes/test_main.c
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "aes_cbc.h"
+#define AES_BLOCK_SIZE 16
+#define KEY_SIZE 128 /* bits */
+#define KEY "1234567890123456"
+#define STR "hola guaso como estaisss ... 012"
+#define STRSZ (sizeof(STR)-1)
+
+#define EMT_AESCBC_BLKLEN AES_BLOCK_SIZE
+#define AES_CONTEXT_T aes_context
+#define EMT_ESPAES_KEY_SZ 16
+int pretty_print(const unsigned char *buf, int count) {
+ int i=0;
+ for (;i<count;i++) {
+ if (i%8==0) putchar(' ');
+ if (i%16==0) putchar('\n');
+ printf ("%02hhx ", buf[i]);
+ }
+ putchar('\n');
+ return i;
+}
+//#define SIZE STRSZ/2
+#define SIZE STRSZ
+int main() {
+ int ret;
+ char buf0[SIZE+1], buf1[SIZE+1];
+ char IV[AES_BLOCK_SIZE]="\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0";
+ aes_context ac;
+ AES_set_key(&ac, KEY, KEY_SIZE);
+ //pretty_print((char *)&ac.aes_e_key, sizeof(ac.aes_e_key));
+ memset(buf0, 0, sizeof (buf0));
+ memset(buf1, 0, sizeof (buf1));
+ ret=AES_cbc_encrypt(&ac, STR, buf0, SIZE, IV, 1);
+ pretty_print(buf0, SIZE);
+ printf("size=%d ret=%d\n%s\n", SIZE, ret, buf0);
+ ret=AES_cbc_encrypt(&ac, buf0, buf1, SIZE, IV, 0);
+ printf("size=%d ret=%d\n%s\n", SIZE, ret, buf1);
+ return 0;
+}
diff --git a/lib/libcrypto/libaes/test_main_mac.c b/lib/libcrypto/libaes/test_main_mac.c
new file mode 100644
index 000000000..eea47dc9c
--- /dev/null
+++ b/lib/libcrypto/libaes/test_main_mac.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include "aes.h"
+#include "aes_xcbc_mac.h"
+#define STR "Hola guasssso c|mo estais ...012"
+void print_hash(const __u8 *hash) {
+ printf("%08x %08x %08x %08x\n",
+ *(__u32*)(&hash[0]),
+ *(__u32*)(&hash[4]),
+ *(__u32*)(&hash[8]),
+ *(__u32*)(&hash[12]));
+}
+int main(int argc, char *argv[]) {
+ aes_block key= { 0xdeadbeef, 0xceedcaca, 0xcafebabe, 0xff010204 };
+ __u8 hash[16];
+ char *str = argv[1];
+ aes_context_mac ctx;
+ if (str==NULL) {
+ fprintf(stderr, "pasame el str\n");
+ return 255;
+ }
+ AES_xcbc_mac_set_key(&ctx, (__u8 *)&key, sizeof(key));
+ AES_xcbc_mac_hash(&ctx, str, strlen(str), hash);
+ print_hash(hash);
+ str[2]='x';
+ AES_xcbc_mac_hash(&ctx, str, strlen(str), hash);
+ print_hash(hash);
+ return 0;
+}
diff --git a/lib/libcrypto/libblowfish/COPYRIGHT b/lib/libcrypto/libblowfish/COPYRIGHT
new file mode 100644
index 000000000..685722350
--- /dev/null
+++ b/lib/libcrypto/libblowfish/COPYRIGHT
@@ -0,0 +1,46 @@
+Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+All rights reserved.
+
+This package is an Blowfish implementation written
+by Eric Young (eay@cryptsoft.com).
+
+This library is free for commercial and non-commercial use as long as
+the following conditions are aheared to. The following conditions
+apply to all code found in this distribution.
+
+Copyright remains Eric Young's, and as such any Copyright notices in
+the code are not to be removed.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by Eric Young (eay@cryptsoft.com)
+
+THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+The license and distribution terms for any publically available version or
+derivative of this code cannot be changed. i.e. this code cannot simply be
+copied and put under another distrubution license
+[including the GNU Public License.]
+
+The reason behind this being stated in this direct manner is past
+experience in code simply being copied and the attribution removed
+from it and then being distributed as part of other packages. This
+implementation was a non-trivial and unpaid effort.
diff --git a/lib/libcrypto/libblowfish/INSTALL b/lib/libcrypto/libblowfish/INSTALL
new file mode 100644
index 000000000..3b2592353
--- /dev/null
+++ b/lib/libcrypto/libblowfish/INSTALL
@@ -0,0 +1,14 @@
+This Eric Young's blowfish implementation, taken from his SSLeay library
+and made available as a separate library.
+
+The version number (0.7.2m) is the SSLeay version that this library was
+taken from.
+
+To build, just unpack and type make.
+If you are not using gcc, edit the Makefile.
+If you are compiling for an x86 box, try the assembler (it needs improving).
+There are also some compile time options that can improve performance,
+these are documented in the Makefile.
+
+eric 15-Apr-1997
+
diff --git a/lib/libcrypto/libblowfish/Makefile b/lib/libcrypto/libblowfish/Makefile
new file mode 100644
index 000000000..62724042b
--- /dev/null
+++ b/lib/libcrypto/libblowfish/Makefile
@@ -0,0 +1,121 @@
+#
+# SSLeay/crypto/blowfish/Makefile
+#
+
+DIR= bf
+TOP= ../..
+CC= cc
+CPP= $(CC) -E
+INC=-I ../include
+CFLAG=-g -D__KERNEL__ -I/usr/src/linux/include
+INSTALL_PREFIX=
+OPENSSLDIR= /usr/local/ssl
+INSTALLTOP=/usr/local/ssl
+MAKE= make -f Makefile.ssl
+MAKEDEPEND= $(TOP)/util/domd $(TOP)
+MAKEFILE= Makefile.ssl
+AR= ar r
+RANLIB= ranlib
+PERL= perl
+
+CFLAGS= $(INC) $(CFLAG)
+
+.c.o:
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c $< -o $@
+
+BF_ASM-i586 := bf-586.pl
+BF_ASM-i686 := bf-686.pl
+BF_ENC := bf_enc.o
+
+ASM-$(ARCH_ASM):=1
+ASM_X86:=$(ASM-i586)$(ASM-i686)
+ifneq ($(strip $(ASM_X86)),)
+ BF_ENC= asm/bx86-elf.o
+ BF_ASM= $(BF_ASM-$(ARCH_ASM))
+endif
+
+
+GENERAL=Makefile
+TEST=bftest.c
+APPS=
+
+LIB=libblowfish.a
+LIBSRC=bf_skey.c bf_enc.c
+LIBOBJ=bf_skey.o $(BF_ENC)
+
+SRC= $(LIBSRC)
+
+EXHEADER= blowfish.h
+HEADER= bf_pi.h bf_locl.h $(EXHEADER)
+
+ALL= $(GENERAL) $(SRC) $(HEADER)
+
+#top:
+# (cd ../..; $(MAKE) DIRS=crypto SDIRS=$(DIR) sub_all)
+
+all: lib
+
+lib: $(LIB)
+
+$(LIB): $(LIBOBJ)
+ $(AR) $(LIB) $(LIBOBJ)
+ $(RANLIB) $(LIB)
+
+# elf
+asm/bx86-elf.o: asm/bx86unix.cpp
+ $(CPP) -DELF -x c asm/bx86unix.cpp | as -o asm/bx86-elf.o
+
+# solaris
+asm/bx86-sol.o: asm/bx86unix.cpp
+ $(CC) -E -DSOL asm/bx86unix.cpp | sed 's/^#.*//' > asm/bx86-sol.s
+ as -o asm/bx86-sol.o asm/bx86-sol.s
+ rm -f asm/bx86-sol.s
+
+# a.out
+asm/bx86-out.o: asm/bx86unix.cpp
+ $(CPP) -DOUT asm/bx86unix.cpp | as -o asm/bx86-out.o
+
+# bsdi
+asm/bx86bsdi.o: asm/bx86unix.cpp
+ $(CPP) -DBSDI asm/bx86unix.cpp | sed 's/ :/:/' | as -o asm/bx86bsdi.o
+
+asm/bx86unix.cpp: asm/$(BF_ASM) ../perlasm/x86asm.pl ../perlasm/cbc.pl
+ (cd asm; $(PERL) $(BF_ASM) cpp $(PROCESSOR) >bx86unix.cpp)
+
+files:
+ $(PERL) $(TOP)/util/files.pl Makefile.ssl >> $(TOP)/MINFO
+
+links:
+ @$(TOP)/util/point.sh Makefile.ssl Makefile
+ @$(PERL) $(TOP)/util/mklink.pl ../../include/openssl $(EXHEADER)
+ @$(PERL) $(TOP)/util/mklink.pl ../../test $(TEST)
+ @$(PERL) $(TOP)/util/mklink.pl ../../apps $(APPS)
+
+install: installs
+
+installs:
+ @for i in $(EXHEADER) ; \
+ do \
+ (cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
+ chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
+ done;
+
+tags:
+ ctags $(SRC)
+
+tests:
+
+lint:
+ lint -DLINT $(INCLUDES) $(SRC)>fluff
+
+depend:
+ $(MAKEDEPEND) $(INCLUDES) $(DEPFLAG) $(PROGS) $(LIBSRC)
+
+dclean:
+ $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new
+ mv -f Makefile.new $(MAKEFILE)
+
+clean:
+ rm -f asm/bx86unix.cpp *.o asm/*.o *.obj $(LIB) tags core .pure .nfs* *.old *.bak fluff
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/lib/libcrypto/libblowfish/Makefile.ssl b/lib/libcrypto/libblowfish/Makefile.ssl
new file mode 100644
index 000000000..adc9eec3c
--- /dev/null
+++ b/lib/libcrypto/libblowfish/Makefile.ssl
@@ -0,0 +1,118 @@
+#
+# SSLeay/crypto/blowfish/Makefile
+#
+
+DIR= bf
+TOP= ../..
+CC= cc
+CPP= $(CC) -E
+INCLUDES=
+CFLAG=-g
+INSTALL_PREFIX=
+OPENSSLDIR= /usr/local/ssl
+INSTALLTOP=/usr/local/ssl
+MAKE= make -f Makefile.ssl
+MAKEDEPEND= $(TOP)/util/domd $(TOP)
+MAKEFILE= Makefile.ssl
+AR= ar r
+
+BF_ENC= bf_enc.o
+# or use
+#DES_ENC= bx86-elf.o
+
+CFLAGS= $(INCLUDES) $(CFLAG)
+
+GENERAL=Makefile
+TEST=bftest.c
+APPS=
+
+LIB=$(TOP)/libcrypto.a
+LIBSRC=bf_skey.c bf_ecb.c bf_enc.c bf_cfb64.c bf_ofb64.c
+LIBOBJ=bf_skey.o bf_ecb.o $(BF_ENC) bf_cfb64.o bf_ofb64.o
+
+SRC= $(LIBSRC)
+
+EXHEADER= blowfish.h
+HEADER= bf_pi.h bf_locl.h $(EXHEADER)
+
+ALL= $(GENERAL) $(SRC) $(HEADER)
+
+top:
+ (cd ../..; $(MAKE) DIRS=crypto SDIRS=$(DIR) sub_all)
+
+all: lib
+
+lib: $(LIBOBJ)
+ $(AR) $(LIB) $(LIBOBJ)
+ $(RANLIB) $(LIB)
+ @touch lib
+
+# elf
+asm/bx86-elf.o: asm/bx86unix.cpp
+ $(CPP) -DELF -x c asm/bx86unix.cpp | as -o asm/bx86-elf.o
+
+# solaris
+asm/bx86-sol.o: asm/bx86unix.cpp
+ $(CC) -E -DSOL asm/bx86unix.cpp | sed 's/^#.*//' > asm/bx86-sol.s
+ as -o asm/bx86-sol.o asm/bx86-sol.s
+ rm -f asm/bx86-sol.s
+
+# a.out
+asm/bx86-out.o: asm/bx86unix.cpp
+ $(CPP) -DOUT asm/bx86unix.cpp | as -o asm/bx86-out.o
+
+# bsdi
+asm/bx86bsdi.o: asm/bx86unix.cpp
+ $(CPP) -DBSDI asm/bx86unix.cpp | sed 's/ :/:/' | as -o asm/bx86bsdi.o
+
+asm/bx86unix.cpp: asm/bf-586.pl ../perlasm/x86asm.pl ../perlasm/cbc.pl
+ (cd asm; $(PERL) bf-586.pl cpp $(PROCESSOR) >bx86unix.cpp)
+
+files:
+ $(PERL) $(TOP)/util/files.pl Makefile.ssl >> $(TOP)/MINFO
+
+links:
+ @$(TOP)/util/point.sh Makefile.ssl Makefile
+ @$(PERL) $(TOP)/util/mklink.pl ../../include/openssl $(EXHEADER)
+ @$(PERL) $(TOP)/util/mklink.pl ../../test $(TEST)
+ @$(PERL) $(TOP)/util/mklink.pl ../../apps $(APPS)
+
+install: installs
+
+installs:
+ @for i in $(EXHEADER) ; \
+ do \
+ (cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
+ chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
+ done;
+
+tags:
+ ctags $(SRC)
+
+tests:
+
+lint:
+ lint -DLINT $(INCLUDES) $(SRC)>fluff
+
+depend:
+ $(MAKEDEPEND) $(INCLUDES) $(DEPFLAG) $(PROGS) $(LIBSRC)
+
+dclean:
+ $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new
+ mv -f Makefile.new $(MAKEFILE)
+
+clean:
+ rm -f asm/bx86unix.cpp *.o asm/*.o *.obj lib tags core .pure .nfs* *.old *.bak fluff
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+bf_cfb64.o: ../../include/openssl/blowfish.h
+bf_cfb64.o: ../../include/openssl/opensslconf.h bf_locl.h
+bf_ecb.o: ../../include/openssl/blowfish.h ../../include/openssl/opensslconf.h
+bf_ecb.o: ../../include/openssl/opensslv.h bf_locl.h
+bf_enc.o: ../../include/openssl/blowfish.h ../../include/openssl/opensslconf.h
+bf_enc.o: bf_locl.h
+bf_ofb64.o: ../../include/openssl/blowfish.h
+bf_ofb64.o: ../../include/openssl/opensslconf.h bf_locl.h
+bf_skey.o: ../../include/openssl/blowfish.h ../../include/openssl/opensslconf.h
+bf_skey.o: bf_locl.h bf_pi.h
diff --git a/lib/libcrypto/libblowfish/README b/lib/libcrypto/libblowfish/README
new file mode 100644
index 000000000..f2712fd0e
--- /dev/null
+++ b/lib/libcrypto/libblowfish/README
@@ -0,0 +1,8 @@
+This is a quick packaging up of my blowfish code into a library.
+It has been lifted from SSLeay.
+The copyright notices seem a little harsh because I have not spent the
+time to rewrite the conditions from the normal SSLeay ones.
+
+Basically if you just want to play with the library, not a problem.
+
+eric 15-Apr-1997
diff --git a/lib/libcrypto/libblowfish/VERSION b/lib/libcrypto/libblowfish/VERSION
new file mode 100644
index 000000000..be995855e
--- /dev/null
+++ b/lib/libcrypto/libblowfish/VERSION
@@ -0,0 +1,6 @@
+The version numbers will follow my SSL implementation
+
+0.7.2r - Some reasonable default compiler options from
+ Peter Gutman <pgut001@cs.auckland.ac.nz>
+
+0.7.2m - the first release
diff --git a/lib/libcrypto/libblowfish/asm/bf-586.pl b/lib/libcrypto/libblowfish/asm/bf-586.pl
new file mode 100644
index 000000000..f00f3f4bf
--- /dev/null
+++ b/lib/libcrypto/libblowfish/asm/bf-586.pl
@@ -0,0 +1,136 @@
+#!/usr/bin/perl
+
+push(@INC,"perlasm","../../perlasm");
+require "x86asm.pl";
+require "cbc.pl";
+
+&asm_init($ARGV[0],"bf-586.pl",$ARGV[$#ARGV] eq "386");
+
+$BF_ROUNDS=16;
+$BF_OFF=($BF_ROUNDS+2)*4;
+$L="edi";
+$R="esi";
+$P="ebp";
+$tmp1="eax";
+$tmp2="ebx";
+$tmp3="ecx";
+$tmp4="edx";
+
+&BF_encrypt("BF_encrypt",1);
+&BF_encrypt("BF_decrypt",0);
+&cbc("BF_cbc_encrypt","BF_encrypt","BF_decrypt",1,4,5,3,-1,-1);
+&asm_finish();
+
+sub BF_encrypt
+ {
+ local($name,$enc)=@_;
+
+ &function_begin_B($name,"");
+
+ &comment("");
+
+ &push("ebp");
+ &push("ebx");
+ &mov($tmp2,&wparam(0));
+ &mov($P,&wparam(1));
+ &push("esi");
+ &push("edi");
+
+ &comment("Load the 2 words");
+ &mov($L,&DWP(0,$tmp2,"",0));
+ &mov($R,&DWP(4,$tmp2,"",0));
+
+ &xor( $tmp1, $tmp1);
+
+ # encrypting part
+
+ if ($enc)
+ {
+ &mov($tmp2,&DWP(0,$P,"",0));
+ &xor( $tmp3, $tmp3);
+
+ &xor($L,$tmp2);
+ for ($i=0; $i<$BF_ROUNDS; $i+=2)
+ {
+ &comment("");
+ &comment("Round $i");
+ &BF_ENCRYPT($i+1,$R,$L,$P,$tmp1,$tmp2,$tmp3,$tmp4,1);
+
+ &comment("");
+ &comment("Round ".sprintf("%d",$i+1));
+ &BF_ENCRYPT($i+2,$L,$R,$P,$tmp1,$tmp2,$tmp3,$tmp4,1);
+ }
+ # &mov($tmp1,&wparam(0)); In last loop
+ &mov($tmp4,&DWP(($BF_ROUNDS+1)*4,$P,"",0));
+ }
+ else
+ {
+ &mov($tmp2,&DWP(($BF_ROUNDS+1)*4,$P,"",0));
+ &xor( $tmp3, $tmp3);
+
+ &xor($L,$tmp2);
+ for ($i=$BF_ROUNDS; $i>0; $i-=2)
+ {
+ &comment("");
+ &comment("Round $i");
+ &BF_ENCRYPT($i,$R,$L,$P,$tmp1,$tmp2,$tmp3,$tmp4,0);
+ &comment("");
+ &comment("Round ".sprintf("%d",$i-1));
+ &BF_ENCRYPT($i-1,$L,$R,$P,$tmp1,$tmp2,$tmp3,$tmp4,0);
+ }
+ # &mov($tmp1,&wparam(0)); In last loop
+ &mov($tmp4,&DWP(0,$P,"",0));
+ }
+
+ &xor($R,$tmp4);
+ &mov(&DWP(4,$tmp1,"",0),$L);
+
+ &mov(&DWP(0,$tmp1,"",0),$R);
+ &function_end($name);
+ }
+
+sub BF_ENCRYPT
+ {
+ local($i,$L,$R,$P,$tmp1,$tmp2,$tmp3,$tmp4,$enc)=@_;
+
+ &mov( $tmp4, &DWP(&n2a($i*4),$P,"",0)); # for next round
+
+ &mov( $tmp2, $R);
+ &xor( $L, $tmp4);
+
+ &shr( $tmp2, 16);
+ &mov( $tmp4, $R);
+
+ &movb( &LB($tmp1), &HB($tmp2)); # A
+ &and( $tmp2, 0xff); # B
+
+ &movb( &LB($tmp3), &HB($tmp4)); # C
+ &and( $tmp4, 0xff); # D
+
+ &mov( $tmp1, &DWP(&n2a($BF_OFF+0x0000),$P,$tmp1,4));
+ &mov( $tmp2, &DWP(&n2a($BF_OFF+0x0400),$P,$tmp2,4));
+
+ &add( $tmp2, $tmp1);
+ &mov( $tmp1, &DWP(&n2a($BF_OFF+0x0800),$P,$tmp3,4));
+
+ &xor( $tmp2, $tmp1);
+ &mov( $tmp4, &DWP(&n2a($BF_OFF+0x0C00),$P,$tmp4,4));
+
+ &add( $tmp2, $tmp4);
+ if (($enc && ($i != 16)) || ((!$enc) && ($i != 1)))
+ { &xor( $tmp1, $tmp1); }
+ else
+ {
+ &comment("Load parameter 0 ($i) enc=$enc");
+ &mov($tmp1,&wparam(0));
+ } # In last loop
+
+ &xor( $L, $tmp2);
+ # delay
+ }
+
+sub n2a
+ {
+ sprintf("%d",$_[0]);
+ }
+
diff --git a/lib/libcrypto/libblowfish/asm/bf-686.pl b/lib/libcrypto/libblowfish/asm/bf-686.pl
new file mode 100644
index 000000000..9222f5e7a
--- /dev/null
+++ b/lib/libcrypto/libblowfish/asm/bf-686.pl
@@ -0,0 +1,127 @@
+#!/usr/bin/perl
+
+push(@INC,"perlasm","../../perlasm");
+require "x86asm.pl";
+require "cbc.pl";
+
+&asm_init($ARGV[0],"bf-686.pl");
+
+$BF_ROUNDS=16;
+$BF_OFF=($BF_ROUNDS+2)*4;
+$L="ecx";
+$R="edx";
+$P="edi";
+$tot="esi";
+$tmp1="eax";
+$tmp2="ebx";
+$tmp3="ebp";
+
+&des_encrypt("BF_encrypt",1);
+&des_encrypt("BF_decrypt",0);
+&cbc("BF_cbc_encrypt","BF_encrypt","BF_decrypt",1,4,5,3,-1,-1);
+
+&asm_finish();
+
+&file_end();
+
+sub des_encrypt
+ {
+ local($name,$enc)=@_;
+
+ &function_begin($name,"");
+
+ &comment("");
+ &comment("Load the 2 words");
+ &mov("eax",&wparam(0));
+ &mov($L,&DWP(0,"eax","",0));
+ &mov($R,&DWP(4,"eax","",0));
+
+ &comment("");
+ &comment("P pointer, s and enc flag");
+ &mov($P,&wparam(1));
+
+ &xor( $tmp1, $tmp1);
+ &xor( $tmp2, $tmp2);
+
+ # encrypting part
+
+ if ($enc)
+ {
+ &xor($L,&DWP(0,$P,"",0));
+ for ($i=0; $i<$BF_ROUNDS; $i+=2)
+ {
+ &comment("");
+ &comment("Round $i");
+ &BF_ENCRYPT($i+1,$R,$L,$P,$tot,$tmp1,$tmp2,$tmp3);
+
+ &comment("");
+ &comment("Round ".sprintf("%d",$i+1));
+ &BF_ENCRYPT($i+2,$L,$R,$P,$tot,$tmp1,$tmp2,$tmp3);
+ }
+ &xor($R,&DWP(($BF_ROUNDS+1)*4,$P,"",0));
+
+ &mov("eax",&wparam(0));
+ &mov(&DWP(0,"eax","",0),$R);
+ &mov(&DWP(4,"eax","",0),$L);
+ &function_end_A($name);
+ }
+ else
+ {
+ &xor($L,&DWP(($BF_ROUNDS+1)*4,$P,"",0));
+ for ($i=$BF_ROUNDS; $i>0; $i-=2)
+ {
+ &comment("");
+ &comment("Round $i");
+ &BF_ENCRYPT($i,$R,$L,$P,$tot,$tmp1,$tmp2,$tmp3);
+ &comment("");
+ &comment("Round ".sprintf("%d",$i-1));
+ &BF_ENCRYPT($i-1,$L,$R,$P,$tot,$tmp1,$tmp2,$tmp3);
+ }
+ &xor($R,&DWP(0,$P,"",0));
+
+ &mov("eax",&wparam(0));
+ &mov(&DWP(0,"eax","",0),$R);
+ &mov(&DWP(4,"eax","",0),$L);
+ &function_end_A($name);
+ }
+
+ &function_end_B($name);
+ }
+
+sub BF_ENCRYPT
+ {
+ local($i,$L,$R,$P,$tot,$tmp1,$tmp2,$tmp3)=@_;
+
+ &rotr( $R, 16);
+ &mov( $tot, &DWP(&n2a($i*4),$P,"",0));
+
+ &movb( &LB($tmp1), &HB($R));
+ &movb( &LB($tmp2), &LB($R));
+
+ &rotr( $R, 16);
+ &xor( $L, $tot);
+
+ &mov( $tot, &DWP(&n2a($BF_OFF+0x0000),$P,$tmp1,4));
+ &mov( $tmp3, &DWP(&n2a($BF_OFF+0x0400),$P,$tmp2,4));
+
+ &movb( &LB($tmp1), &HB($R));
+ &movb( &LB($tmp2), &LB($R));
+
+ &add( $tot, $tmp3);
+ &mov( $tmp1, &DWP(&n2a($BF_OFF+0x0800),$P,$tmp1,4)); # delay
+
+ &xor( $tot, $tmp1);
+ &mov( $tmp3, &DWP(&n2a($BF_OFF+0x0C00),$P,$tmp2,4));
+
+ &add( $tot, $tmp3);
+ &xor( $tmp1, $tmp1);
+
+ &xor( $L, $tot);
+ # delay
+ }
+
+sub n2a
+ {
+ sprintf("%d",$_[0]);
+ }
+
diff --git a/lib/libcrypto/libblowfish/asm/readme b/lib/libcrypto/libblowfish/asm/readme
new file mode 100644
index 000000000..2385fa381
--- /dev/null
+++ b/lib/libcrypto/libblowfish/asm/readme
@@ -0,0 +1,10 @@
+There are blowfish assembler generation scripts.
+bf-586.pl version is for the pentium and
+bf-686.pl is my original version, which is faster on the pentium pro.
+
+When using a bf-586.pl, the pentium pro/II is %8 slower than using
+bf-686.pl. When using a bf-686.pl, the pentium is %16 slower
+than bf-586.pl
+
+So the default is bf-586.pl
+
diff --git a/lib/libcrypto/libblowfish/bf_enc.c b/lib/libcrypto/libblowfish/bf_enc.c
new file mode 100644
index 000000000..aa6c79812
--- /dev/null
+++ b/lib/libcrypto/libblowfish/bf_enc.c
@@ -0,0 +1,306 @@
+/* crypto/bf/bf_enc.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "blowfish.h"
+#include "bf_locl.h"
+
+/* Blowfish as implemented from 'Blowfish: Springer-Verlag paper'
+ * (From LECTURE NOTES IN COMPUTER SCIENCE 809, FAST SOFTWARE ENCRYPTION,
+ * CAMBRIDGE SECURITY WORKSHOP, CAMBRIDGE, U.K., DECEMBER 9-11, 1993)
+ */
+
+#if (BF_ROUNDS != 16) && (BF_ROUNDS != 20)
+#error If you set BF_ROUNDS to some value other than 16 or 20, you will have \
+to modify the code.
+#endif
+
+void BF_encrypt(BF_LONG *data, const BF_KEY *key)
+ {
+#ifndef BF_PTR2
+ const BF_LONG *p,*s;
+ BF_LONG l,r;
+
+ p=key->P;
+ s= &(key->S[0]);
+ l=data[0];
+ r=data[1];
+
+ l^=p[0];
+ BF_ENC(r,l,s,p[ 1]);
+ BF_ENC(l,r,s,p[ 2]);
+ BF_ENC(r,l,s,p[ 3]);
+ BF_ENC(l,r,s,p[ 4]);
+ BF_ENC(r,l,s,p[ 5]);
+ BF_ENC(l,r,s,p[ 6]);
+ BF_ENC(r,l,s,p[ 7]);
+ BF_ENC(l,r,s,p[ 8]);
+ BF_ENC(r,l,s,p[ 9]);
+ BF_ENC(l,r,s,p[10]);
+ BF_ENC(r,l,s,p[11]);
+ BF_ENC(l,r,s,p[12]);
+ BF_ENC(r,l,s,p[13]);
+ BF_ENC(l,r,s,p[14]);
+ BF_ENC(r,l,s,p[15]);
+ BF_ENC(l,r,s,p[16]);
+#if BF_ROUNDS == 20
+ BF_ENC(r,l,s,p[17]);
+ BF_ENC(l,r,s,p[18]);
+ BF_ENC(r,l,s,p[19]);
+ BF_ENC(l,r,s,p[20]);
+#endif
+ r^=p[BF_ROUNDS+1];
+
+ data[1]=l&0xffffffffL;
+ data[0]=r&0xffffffffL;
+#else
+ BF_LONG l,r,t,*k;
+
+ l=data[0];
+ r=data[1];
+ k=(BF_LONG*)key;
+
+ l^=k[0];
+ BF_ENC(r,l,k, 1);
+ BF_ENC(l,r,k, 2);
+ BF_ENC(r,l,k, 3);
+ BF_ENC(l,r,k, 4);
+ BF_ENC(r,l,k, 5);
+ BF_ENC(l,r,k, 6);
+ BF_ENC(r,l,k, 7);
+ BF_ENC(l,r,k, 8);
+ BF_ENC(r,l,k, 9);
+ BF_ENC(l,r,k,10);
+ BF_ENC(r,l,k,11);
+ BF_ENC(l,r,k,12);
+ BF_ENC(r,l,k,13);
+ BF_ENC(l,r,k,14);
+ BF_ENC(r,l,k,15);
+ BF_ENC(l,r,k,16);
+#if BF_ROUNDS == 20
+ BF_ENC(r,l,k,17);
+ BF_ENC(l,r,k,18);
+ BF_ENC(r,l,k,19);
+ BF_ENC(l,r,k,20);
+#endif
+ r^=k[BF_ROUNDS+1];
+
+ data[1]=l&0xffffffffL;
+ data[0]=r&0xffffffffL;
+#endif
+ }
+
+#ifndef BF_DEFAULT_OPTIONS
+
+void BF_decrypt(BF_LONG *data, const BF_KEY *key)
+ {
+#ifndef BF_PTR2
+ const BF_LONG *p,*s;
+ BF_LONG l,r;
+
+ p=key->P;
+ s= &(key->S[0]);
+ l=data[0];
+ r=data[1];
+
+ l^=p[BF_ROUNDS+1];
+#if BF_ROUNDS == 20
+ BF_ENC(r,l,s,p[20]);
+ BF_ENC(l,r,s,p[19]);
+ BF_ENC(r,l,s,p[18]);
+ BF_ENC(l,r,s,p[17]);
+#endif
+ BF_ENC(r,l,s,p[16]);
+ BF_ENC(l,r,s,p[15]);
+ BF_ENC(r,l,s,p[14]);
+ BF_ENC(l,r,s,p[13]);
+ BF_ENC(r,l,s,p[12]);
+ BF_ENC(l,r,s,p[11]);
+ BF_ENC(r,l,s,p[10]);
+ BF_ENC(l,r,s,p[ 9]);
+ BF_ENC(r,l,s,p[ 8]);
+ BF_ENC(l,r,s,p[ 7]);
+ BF_ENC(r,l,s,p[ 6]);
+ BF_ENC(l,r,s,p[ 5]);
+ BF_ENC(r,l,s,p[ 4]);
+ BF_ENC(l,r,s,p[ 3]);
+ BF_ENC(r,l,s,p[ 2]);
+ BF_ENC(l,r,s,p[ 1]);
+ r^=p[0];
+
+ data[1]=l&0xffffffffL;
+ data[0]=r&0xffffffffL;
+#else
+ BF_LONG l,r,t,*k;
+
+ l=data[0];
+ r=data[1];
+ k=(BF_LONG *)key;
+
+ l^=k[BF_ROUNDS+1];
+#if BF_ROUNDS == 20
+ BF_ENC(r,l,k,20);
+ BF_ENC(l,r,k,19);
+ BF_ENC(r,l,k,18);
+ BF_ENC(l,r,k,17);
+#endif
+ BF_ENC(r,l,k,16);
+ BF_ENC(l,r,k,15);
+ BF_ENC(r,l,k,14);
+ BF_ENC(l,r,k,13);
+ BF_ENC(r,l,k,12);
+ BF_ENC(l,r,k,11);
+ BF_ENC(r,l,k,10);
+ BF_ENC(l,r,k, 9);
+ BF_ENC(r,l,k, 8);
+ BF_ENC(l,r,k, 7);
+ BF_ENC(r,l,k, 6);
+ BF_ENC(l,r,k, 5);
+ BF_ENC(r,l,k, 4);
+ BF_ENC(l,r,k, 3);
+ BF_ENC(r,l,k, 2);
+ BF_ENC(l,r,k, 1);
+ r^=k[0];
+
+ data[1]=l&0xffffffffL;
+ data[0]=r&0xffffffffL;
+#endif
+ }
+
+void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
+ const BF_KEY *schedule, unsigned char *ivec, int encrypt)
+ {
+ BF_LONG tin0,tin1;
+ BF_LONG tout0,tout1,xor0,xor1;
+ long l=length;
+ BF_LONG tin[2];
+
+ if (encrypt)
+ {
+ n2l(ivec,tout0);
+ n2l(ivec,tout1);
+ ivec-=8;
+ for (l-=8; l>=0; l-=8)
+ {
+ n2l(in,tin0);
+ n2l(in,tin1);
+ tin0^=tout0;
+ tin1^=tout1;
+ tin[0]=tin0;
+ tin[1]=tin1;
+ BF_encrypt(tin,schedule);
+ tout0=tin[0];
+ tout1=tin[1];
+ l2n(tout0,out);
+ l2n(tout1,out);
+ }
+ if (l != -8)
+ {
+ n2ln(in,tin0,tin1,l+8);
+ tin0^=tout0;
+ tin1^=tout1;
+ tin[0]=tin0;
+ tin[1]=tin1;
+ BF_encrypt(tin,schedule);
+ tout0=tin[0];
+ tout1=tin[1];
+ l2n(tout0,out);
+ l2n(tout1,out);
+ }
+ l2n(tout0,ivec);
+ l2n(tout1,ivec);
+ }
+ else
+ {
+ n2l(ivec,xor0);
+ n2l(ivec,xor1);
+ ivec-=8;
+ for (l-=8; l>=0; l-=8)
+ {
+ n2l(in,tin0);
+ n2l(in,tin1);
+ tin[0]=tin0;
+ tin[1]=tin1;
+ BF_decrypt(tin,schedule);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2n(tout0,out);
+ l2n(tout1,out);
+ xor0=tin0;
+ xor1=tin1;
+ }
+ if (l != -8)
+ {
+ n2l(in,tin0);
+ n2l(in,tin1);
+ tin[0]=tin0;
+ tin[1]=tin1;
+ BF_decrypt(tin,schedule);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2nn(tout0,tout1,out,l+8);
+ xor0=tin0;
+ xor1=tin1;
+ }
+ l2n(xor0,ivec);
+ l2n(xor1,ivec);
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+ }
+
+#endif
diff --git a/lib/libcrypto/libblowfish/bf_locl.h b/lib/libcrypto/libblowfish/bf_locl.h
new file mode 100644
index 000000000..283bf4c43
--- /dev/null
+++ b/lib/libcrypto/libblowfish/bf_locl.h
@@ -0,0 +1,218 @@
+/* crypto/bf/bf_locl.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_BF_LOCL_H
+#define HEADER_BF_LOCL_H
+
+#undef c2l
+#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
+ l|=((unsigned long)(*((c)++)))<< 8L, \
+ l|=((unsigned long)(*((c)++)))<<16L, \
+ l|=((unsigned long)(*((c)++)))<<24L)
+
+/* NOTE - c is not incremented as per c2l */
+#undef c2ln
+#define c2ln(c,l1,l2,n) { \
+ c+=n; \
+ l1=l2=0; \
+ switch (n) { \
+ case 8: l2 =((unsigned long)(*(--(c))))<<24L; \
+ case 7: l2|=((unsigned long)(*(--(c))))<<16L; \
+ case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \
+ case 5: l2|=((unsigned long)(*(--(c)))); \
+ case 4: l1 =((unsigned long)(*(--(c))))<<24L; \
+ case 3: l1|=((unsigned long)(*(--(c))))<<16L; \
+ case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \
+ case 1: l1|=((unsigned long)(*(--(c)))); \
+ } \
+ }
+
+#undef l2c
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24L)&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+#undef l2cn
+#define l2cn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \
+ } \
+ }
+
+/* NOTE - c is not incremented as per n2l */
+#define n2ln(c,l1,l2,n) { \
+ c+=n; \
+ l1=l2=0; \
+ switch (n) { \
+ case 8: l2 =((unsigned long)(*(--(c)))) ; \
+ case 7: l2|=((unsigned long)(*(--(c))))<< 8; \
+ case 6: l2|=((unsigned long)(*(--(c))))<<16; \
+ case 5: l2|=((unsigned long)(*(--(c))))<<24; \
+ case 4: l1 =((unsigned long)(*(--(c)))) ; \
+ case 3: l1|=((unsigned long)(*(--(c))))<< 8; \
+ case 2: l1|=((unsigned long)(*(--(c))))<<16; \
+ case 1: l1|=((unsigned long)(*(--(c))))<<24; \
+ } \
+ }
+
+/* NOTE - c is not incremented as per l2n */
+#define l2nn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1) )&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
+ } \
+ }
+
+#undef n2l
+#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \
+ l|=((unsigned long)(*((c)++)))<<16L, \
+ l|=((unsigned long)(*((c)++)))<< 8L, \
+ l|=((unsigned long)(*((c)++))))
+
+#undef l2n
+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+/* This is actually a big endian algorithm, the most significant byte
+ * is used to lookup array 0 */
+
+#if defined(BF_PTR2)
+
+/*
+ * This is basically a special Intel version. Point is that Intel
+ * doesn't have many registers, but offers a reach choice of addressing
+ * modes. So we spare some registers by directly traversing BF_KEY
+ * structure and hiring the most decorated addressing mode. The code
+ * generated by EGCS is *perfectly* competitive with assembler
+ * implementation!
+ */
+#define BF_ENC(LL,R,KEY,Pi) (\
+ LL^=KEY[Pi], \
+ t= KEY[BF_ROUNDS+2 + 0 + ((R>>24)&0xFF)], \
+ t+= KEY[BF_ROUNDS+2 + 256 + ((R>>16)&0xFF)], \
+ t^= KEY[BF_ROUNDS+2 + 512 + ((R>>8 )&0xFF)], \
+ t+= KEY[BF_ROUNDS+2 + 768 + ((R )&0xFF)], \
+ LL^=t \
+ )
+
+#elif defined(BF_PTR)
+
+#ifndef BF_LONG_LOG2
+#define BF_LONG_LOG2 2 /* default to BF_LONG being 32 bits */
+#endif
+#define BF_M (0xFF<<BF_LONG_LOG2)
+#define BF_0 (24-BF_LONG_LOG2)
+#define BF_1 (16-BF_LONG_LOG2)
+#define BF_2 ( 8-BF_LONG_LOG2)
+#define BF_3 BF_LONG_LOG2 /* left shift */
+
+/*
+ * This is normally very good on RISC platforms where normally you
+ * have to explicitly "multiply" array index by sizeof(BF_LONG)
+ * in order to calculate the effective address. This implementation
+ * excuses CPU from this extra work. Power[PC] uses should have most
+ * fun as (R>>BF_i)&BF_M gets folded into a single instruction, namely
+ * rlwinm. So let'em double-check if their compiler does it.
+ */
+
+#define BF_ENC(LL,R,S,P) ( \
+ LL^=P, \
+ LL^= (((*(BF_LONG *)((unsigned char *)&(S[ 0])+((R>>BF_0)&BF_M))+ \
+ *(BF_LONG *)((unsigned char *)&(S[256])+((R>>BF_1)&BF_M)))^ \
+ *(BF_LONG *)((unsigned char *)&(S[512])+((R>>BF_2)&BF_M)))+ \
+ *(BF_LONG *)((unsigned char *)&(S[768])+((R<<BF_3)&BF_M))) \
+ )
+#else
+
+/*
+ * This is a *generic* version. Seem to perform best on platforms that
+ * offer explicit support for extraction of 8-bit nibbles preferably
+ * complemented with "multiplying" of array index by sizeof(BF_LONG).
+ * For the moment of this writing the list comprises Alpha CPU featuring
+ * extbl and s[48]addq instructions.
+ */
+
+#define BF_ENC(LL,R,S,P) ( \
+ LL^=P, \
+ LL^=((( S[ ((int)(R>>24)&0xff)] + \
+ S[0x0100+((int)(R>>16)&0xff)])^ \
+ S[0x0200+((int)(R>> 8)&0xff)])+ \
+ S[0x0300+((int)(R )&0xff)])&0xffffffffL \
+ )
+#endif
+
+#endif
diff --git a/lib/libcrypto/libblowfish/bf_pi.h b/lib/libcrypto/libblowfish/bf_pi.h
new file mode 100644
index 000000000..9949513c6
--- /dev/null
+++ b/lib/libcrypto/libblowfish/bf_pi.h
@@ -0,0 +1,325 @@
+/* crypto/bf/bf_pi.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+static const BF_KEY bf_init= {
+ {
+ 0x243f6a88L, 0x85a308d3L, 0x13198a2eL, 0x03707344L,
+ 0xa4093822L, 0x299f31d0L, 0x082efa98L, 0xec4e6c89L,
+ 0x452821e6L, 0x38d01377L, 0xbe5466cfL, 0x34e90c6cL,
+ 0xc0ac29b7L, 0xc97c50ddL, 0x3f84d5b5L, 0xb5470917L,
+ 0x9216d5d9L, 0x8979fb1b
+ },{
+ 0xd1310ba6L, 0x98dfb5acL, 0x2ffd72dbL, 0xd01adfb7L,
+ 0xb8e1afedL, 0x6a267e96L, 0xba7c9045L, 0xf12c7f99L,
+ 0x24a19947L, 0xb3916cf7L, 0x0801f2e2L, 0x858efc16L,
+ 0x636920d8L, 0x71574e69L, 0xa458fea3L, 0xf4933d7eL,
+ 0x0d95748fL, 0x728eb658L, 0x718bcd58L, 0x82154aeeL,
+ 0x7b54a41dL, 0xc25a59b5L, 0x9c30d539L, 0x2af26013L,
+ 0xc5d1b023L, 0x286085f0L, 0xca417918L, 0xb8db38efL,
+ 0x8e79dcb0L, 0x603a180eL, 0x6c9e0e8bL, 0xb01e8a3eL,
+ 0xd71577c1L, 0xbd314b27L, 0x78af2fdaL, 0x55605c60L,
+ 0xe65525f3L, 0xaa55ab94L, 0x57489862L, 0x63e81440L,
+ 0x55ca396aL, 0x2aab10b6L, 0xb4cc5c34L, 0x1141e8ceL,
+ 0xa15486afL, 0x7c72e993L, 0xb3ee1411L, 0x636fbc2aL,
+ 0x2ba9c55dL, 0x741831f6L, 0xce5c3e16L, 0x9b87931eL,
+ 0xafd6ba33L, 0x6c24cf5cL, 0x7a325381L, 0x28958677L,
+ 0x3b8f4898L, 0x6b4bb9afL, 0xc4bfe81bL, 0x66282193L,
+ 0x61d809ccL, 0xfb21a991L, 0x487cac60L, 0x5dec8032L,
+ 0xef845d5dL, 0xe98575b1L, 0xdc262302L, 0xeb651b88L,
+ 0x23893e81L, 0xd396acc5L, 0x0f6d6ff3L, 0x83f44239L,
+ 0x2e0b4482L, 0xa4842004L, 0x69c8f04aL, 0x9e1f9b5eL,
+ 0x21c66842L, 0xf6e96c9aL, 0x670c9c61L, 0xabd388f0L,
+ 0x6a51a0d2L, 0xd8542f68L, 0x960fa728L, 0xab5133a3L,
+ 0x6eef0b6cL, 0x137a3be4L, 0xba3bf050L, 0x7efb2a98L,
+ 0xa1f1651dL, 0x39af0176L, 0x66ca593eL, 0x82430e88L,
+ 0x8cee8619L, 0x456f9fb4L, 0x7d84a5c3L, 0x3b8b5ebeL,
+ 0xe06f75d8L, 0x85c12073L, 0x401a449fL, 0x56c16aa6L,
+ 0x4ed3aa62L, 0x363f7706L, 0x1bfedf72L, 0x429b023dL,
+ 0x37d0d724L, 0xd00a1248L, 0xdb0fead3L, 0x49f1c09bL,
+ 0x075372c9L, 0x80991b7bL, 0x25d479d8L, 0xf6e8def7L,
+ 0xe3fe501aL, 0xb6794c3bL, 0x976ce0bdL, 0x04c006baL,
+ 0xc1a94fb6L, 0x409f60c4L, 0x5e5c9ec2L, 0x196a2463L,
+ 0x68fb6fafL, 0x3e6c53b5L, 0x1339b2ebL, 0x3b52ec6fL,
+ 0x6dfc511fL, 0x9b30952cL, 0xcc814544L, 0xaf5ebd09L,
+ 0xbee3d004L, 0xde334afdL, 0x660f2807L, 0x192e4bb3L,
+ 0xc0cba857L, 0x45c8740fL, 0xd20b5f39L, 0xb9d3fbdbL,
+ 0x5579c0bdL, 0x1a60320aL, 0xd6a100c6L, 0x402c7279L,
+ 0x679f25feL, 0xfb1fa3ccL, 0x8ea5e9f8L, 0xdb3222f8L,
+ 0x3c7516dfL, 0xfd616b15L, 0x2f501ec8L, 0xad0552abL,
+ 0x323db5faL, 0xfd238760L, 0x53317b48L, 0x3e00df82L,
+ 0x9e5c57bbL, 0xca6f8ca0L, 0x1a87562eL, 0xdf1769dbL,
+ 0xd542a8f6L, 0x287effc3L, 0xac6732c6L, 0x8c4f5573L,
+ 0x695b27b0L, 0xbbca58c8L, 0xe1ffa35dL, 0xb8f011a0L,
+ 0x10fa3d98L, 0xfd2183b8L, 0x4afcb56cL, 0x2dd1d35bL,
+ 0x9a53e479L, 0xb6f84565L, 0xd28e49bcL, 0x4bfb9790L,
+ 0xe1ddf2daL, 0xa4cb7e33L, 0x62fb1341L, 0xcee4c6e8L,
+ 0xef20cadaL, 0x36774c01L, 0xd07e9efeL, 0x2bf11fb4L,
+ 0x95dbda4dL, 0xae909198L, 0xeaad8e71L, 0x6b93d5a0L,
+ 0xd08ed1d0L, 0xafc725e0L, 0x8e3c5b2fL, 0x8e7594b7L,
+ 0x8ff6e2fbL, 0xf2122b64L, 0x8888b812L, 0x900df01cL,
+ 0x4fad5ea0L, 0x688fc31cL, 0xd1cff191L, 0xb3a8c1adL,
+ 0x2f2f2218L, 0xbe0e1777L, 0xea752dfeL, 0x8b021fa1L,
+ 0xe5a0cc0fL, 0xb56f74e8L, 0x18acf3d6L, 0xce89e299L,
+ 0xb4a84fe0L, 0xfd13e0b7L, 0x7cc43b81L, 0xd2ada8d9L,
+ 0x165fa266L, 0x80957705L, 0x93cc7314L, 0x211a1477L,
+ 0xe6ad2065L, 0x77b5fa86L, 0xc75442f5L, 0xfb9d35cfL,
+ 0xebcdaf0cL, 0x7b3e89a0L, 0xd6411bd3L, 0xae1e7e49L,
+ 0x00250e2dL, 0x2071b35eL, 0x226800bbL, 0x57b8e0afL,
+ 0x2464369bL, 0xf009b91eL, 0x5563911dL, 0x59dfa6aaL,
+ 0x78c14389L, 0xd95a537fL, 0x207d5ba2L, 0x02e5b9c5L,
+ 0x83260376L, 0x6295cfa9L, 0x11c81968L, 0x4e734a41L,
+ 0xb3472dcaL, 0x7b14a94aL, 0x1b510052L, 0x9a532915L,
+ 0xd60f573fL, 0xbc9bc6e4L, 0x2b60a476L, 0x81e67400L,
+ 0x08ba6fb5L, 0x571be91fL, 0xf296ec6bL, 0x2a0dd915L,
+ 0xb6636521L, 0xe7b9f9b6L, 0xff34052eL, 0xc5855664L,
+ 0x53b02d5dL, 0xa99f8fa1L, 0x08ba4799L, 0x6e85076aL,
+ 0x4b7a70e9L, 0xb5b32944L, 0xdb75092eL, 0xc4192623L,
+ 0xad6ea6b0L, 0x49a7df7dL, 0x9cee60b8L, 0x8fedb266L,
+ 0xecaa8c71L, 0x699a17ffL, 0x5664526cL, 0xc2b19ee1L,
+ 0x193602a5L, 0x75094c29L, 0xa0591340L, 0xe4183a3eL,
+ 0x3f54989aL, 0x5b429d65L, 0x6b8fe4d6L, 0x99f73fd6L,
+ 0xa1d29c07L, 0xefe830f5L, 0x4d2d38e6L, 0xf0255dc1L,
+ 0x4cdd2086L, 0x8470eb26L, 0x6382e9c6L, 0x021ecc5eL,
+ 0x09686b3fL, 0x3ebaefc9L, 0x3c971814L, 0x6b6a70a1L,
+ 0x687f3584L, 0x52a0e286L, 0xb79c5305L, 0xaa500737L,
+ 0x3e07841cL, 0x7fdeae5cL, 0x8e7d44ecL, 0x5716f2b8L,
+ 0xb03ada37L, 0xf0500c0dL, 0xf01c1f04L, 0x0200b3ffL,
+ 0xae0cf51aL, 0x3cb574b2L, 0x25837a58L, 0xdc0921bdL,
+ 0xd19113f9L, 0x7ca92ff6L, 0x94324773L, 0x22f54701L,
+ 0x3ae5e581L, 0x37c2dadcL, 0xc8b57634L, 0x9af3dda7L,
+ 0xa9446146L, 0x0fd0030eL, 0xecc8c73eL, 0xa4751e41L,
+ 0xe238cd99L, 0x3bea0e2fL, 0x3280bba1L, 0x183eb331L,
+ 0x4e548b38L, 0x4f6db908L, 0x6f420d03L, 0xf60a04bfL,
+ 0x2cb81290L, 0x24977c79L, 0x5679b072L, 0xbcaf89afL,
+ 0xde9a771fL, 0xd9930810L, 0xb38bae12L, 0xdccf3f2eL,
+ 0x5512721fL, 0x2e6b7124L, 0x501adde6L, 0x9f84cd87L,
+ 0x7a584718L, 0x7408da17L, 0xbc9f9abcL, 0xe94b7d8cL,
+ 0xec7aec3aL, 0xdb851dfaL, 0x63094366L, 0xc464c3d2L,
+ 0xef1c1847L, 0x3215d908L, 0xdd433b37L, 0x24c2ba16L,
+ 0x12a14d43L, 0x2a65c451L, 0x50940002L, 0x133ae4ddL,
+ 0x71dff89eL, 0x10314e55L, 0x81ac77d6L, 0x5f11199bL,
+ 0x043556f1L, 0xd7a3c76bL, 0x3c11183bL, 0x5924a509L,
+ 0xf28fe6edL, 0x97f1fbfaL, 0x9ebabf2cL, 0x1e153c6eL,
+ 0x86e34570L, 0xeae96fb1L, 0x860e5e0aL, 0x5a3e2ab3L,
+ 0x771fe71cL, 0x4e3d06faL, 0x2965dcb9L, 0x99e71d0fL,
+ 0x803e89d6L, 0x5266c825L, 0x2e4cc978L, 0x9c10b36aL,
+ 0xc6150ebaL, 0x94e2ea78L, 0xa5fc3c53L, 0x1e0a2df4L,
+ 0xf2f74ea7L, 0x361d2b3dL, 0x1939260fL, 0x19c27960L,
+ 0x5223a708L, 0xf71312b6L, 0xebadfe6eL, 0xeac31f66L,
+ 0xe3bc4595L, 0xa67bc883L, 0xb17f37d1L, 0x018cff28L,
+ 0xc332ddefL, 0xbe6c5aa5L, 0x65582185L, 0x68ab9802L,
+ 0xeecea50fL, 0xdb2f953bL, 0x2aef7dadL, 0x5b6e2f84L,
+ 0x1521b628L, 0x29076170L, 0xecdd4775L, 0x619f1510L,
+ 0x13cca830L, 0xeb61bd96L, 0x0334fe1eL, 0xaa0363cfL,
+ 0xb5735c90L, 0x4c70a239L, 0xd59e9e0bL, 0xcbaade14L,
+ 0xeecc86bcL, 0x60622ca7L, 0x9cab5cabL, 0xb2f3846eL,
+ 0x648b1eafL, 0x19bdf0caL, 0xa02369b9L, 0x655abb50L,
+ 0x40685a32L, 0x3c2ab4b3L, 0x319ee9d5L, 0xc021b8f7L,
+ 0x9b540b19L, 0x875fa099L, 0x95f7997eL, 0x623d7da8L,
+ 0xf837889aL, 0x97e32d77L, 0x11ed935fL, 0x16681281L,
+ 0x0e358829L, 0xc7e61fd6L, 0x96dedfa1L, 0x7858ba99L,
+ 0x57f584a5L, 0x1b227263L, 0x9b83c3ffL, 0x1ac24696L,
+ 0xcdb30aebL, 0x532e3054L, 0x8fd948e4L, 0x6dbc3128L,
+ 0x58ebf2efL, 0x34c6ffeaL, 0xfe28ed61L, 0xee7c3c73L,
+ 0x5d4a14d9L, 0xe864b7e3L, 0x42105d14L, 0x203e13e0L,
+ 0x45eee2b6L, 0xa3aaabeaL, 0xdb6c4f15L, 0xfacb4fd0L,
+ 0xc742f442L, 0xef6abbb5L, 0x654f3b1dL, 0x41cd2105L,
+ 0xd81e799eL, 0x86854dc7L, 0xe44b476aL, 0x3d816250L,
+ 0xcf62a1f2L, 0x5b8d2646L, 0xfc8883a0L, 0xc1c7b6a3L,
+ 0x7f1524c3L, 0x69cb7492L, 0x47848a0bL, 0x5692b285L,
+ 0x095bbf00L, 0xad19489dL, 0x1462b174L, 0x23820e00L,
+ 0x58428d2aL, 0x0c55f5eaL, 0x1dadf43eL, 0x233f7061L,
+ 0x3372f092L, 0x8d937e41L, 0xd65fecf1L, 0x6c223bdbL,
+ 0x7cde3759L, 0xcbee7460L, 0x4085f2a7L, 0xce77326eL,
+ 0xa6078084L, 0x19f8509eL, 0xe8efd855L, 0x61d99735L,
+ 0xa969a7aaL, 0xc50c06c2L, 0x5a04abfcL, 0x800bcadcL,
+ 0x9e447a2eL, 0xc3453484L, 0xfdd56705L, 0x0e1e9ec9L,
+ 0xdb73dbd3L, 0x105588cdL, 0x675fda79L, 0xe3674340L,
+ 0xc5c43465L, 0x713e38d8L, 0x3d28f89eL, 0xf16dff20L,
+ 0x153e21e7L, 0x8fb03d4aL, 0xe6e39f2bL, 0xdb83adf7L,
+ 0xe93d5a68L, 0x948140f7L, 0xf64c261cL, 0x94692934L,
+ 0x411520f7L, 0x7602d4f7L, 0xbcf46b2eL, 0xd4a20068L,
+ 0xd4082471L, 0x3320f46aL, 0x43b7d4b7L, 0x500061afL,
+ 0x1e39f62eL, 0x97244546L, 0x14214f74L, 0xbf8b8840L,
+ 0x4d95fc1dL, 0x96b591afL, 0x70f4ddd3L, 0x66a02f45L,
+ 0xbfbc09ecL, 0x03bd9785L, 0x7fac6dd0L, 0x31cb8504L,
+ 0x96eb27b3L, 0x55fd3941L, 0xda2547e6L, 0xabca0a9aL,
+ 0x28507825L, 0x530429f4L, 0x0a2c86daL, 0xe9b66dfbL,
+ 0x68dc1462L, 0xd7486900L, 0x680ec0a4L, 0x27a18deeL,
+ 0x4f3ffea2L, 0xe887ad8cL, 0xb58ce006L, 0x7af4d6b6L,
+ 0xaace1e7cL, 0xd3375fecL, 0xce78a399L, 0x406b2a42L,
+ 0x20fe9e35L, 0xd9f385b9L, 0xee39d7abL, 0x3b124e8bL,
+ 0x1dc9faf7L, 0x4b6d1856L, 0x26a36631L, 0xeae397b2L,
+ 0x3a6efa74L, 0xdd5b4332L, 0x6841e7f7L, 0xca7820fbL,
+ 0xfb0af54eL, 0xd8feb397L, 0x454056acL, 0xba489527L,
+ 0x55533a3aL, 0x20838d87L, 0xfe6ba9b7L, 0xd096954bL,
+ 0x55a867bcL, 0xa1159a58L, 0xcca92963L, 0x99e1db33L,
+ 0xa62a4a56L, 0x3f3125f9L, 0x5ef47e1cL, 0x9029317cL,
+ 0xfdf8e802L, 0x04272f70L, 0x80bb155cL, 0x05282ce3L,
+ 0x95c11548L, 0xe4c66d22L, 0x48c1133fL, 0xc70f86dcL,
+ 0x07f9c9eeL, 0x41041f0fL, 0x404779a4L, 0x5d886e17L,
+ 0x325f51ebL, 0xd59bc0d1L, 0xf2bcc18fL, 0x41113564L,
+ 0x257b7834L, 0x602a9c60L, 0xdff8e8a3L, 0x1f636c1bL,
+ 0x0e12b4c2L, 0x02e1329eL, 0xaf664fd1L, 0xcad18115L,
+ 0x6b2395e0L, 0x333e92e1L, 0x3b240b62L, 0xeebeb922L,
+ 0x85b2a20eL, 0xe6ba0d99L, 0xde720c8cL, 0x2da2f728L,
+ 0xd0127845L, 0x95b794fdL, 0x647d0862L, 0xe7ccf5f0L,
+ 0x5449a36fL, 0x877d48faL, 0xc39dfd27L, 0xf33e8d1eL,
+ 0x0a476341L, 0x992eff74L, 0x3a6f6eabL, 0xf4f8fd37L,
+ 0xa812dc60L, 0xa1ebddf8L, 0x991be14cL, 0xdb6e6b0dL,
+ 0xc67b5510L, 0x6d672c37L, 0x2765d43bL, 0xdcd0e804L,
+ 0xf1290dc7L, 0xcc00ffa3L, 0xb5390f92L, 0x690fed0bL,
+ 0x667b9ffbL, 0xcedb7d9cL, 0xa091cf0bL, 0xd9155ea3L,
+ 0xbb132f88L, 0x515bad24L, 0x7b9479bfL, 0x763bd6ebL,
+ 0x37392eb3L, 0xcc115979L, 0x8026e297L, 0xf42e312dL,
+ 0x6842ada7L, 0xc66a2b3bL, 0x12754cccL, 0x782ef11cL,
+ 0x6a124237L, 0xb79251e7L, 0x06a1bbe6L, 0x4bfb6350L,
+ 0x1a6b1018L, 0x11caedfaL, 0x3d25bdd8L, 0xe2e1c3c9L,
+ 0x44421659L, 0x0a121386L, 0xd90cec6eL, 0xd5abea2aL,
+ 0x64af674eL, 0xda86a85fL, 0xbebfe988L, 0x64e4c3feL,
+ 0x9dbc8057L, 0xf0f7c086L, 0x60787bf8L, 0x6003604dL,
+ 0xd1fd8346L, 0xf6381fb0L, 0x7745ae04L, 0xd736fcccL,
+ 0x83426b33L, 0xf01eab71L, 0xb0804187L, 0x3c005e5fL,
+ 0x77a057beL, 0xbde8ae24L, 0x55464299L, 0xbf582e61L,
+ 0x4e58f48fL, 0xf2ddfda2L, 0xf474ef38L, 0x8789bdc2L,
+ 0x5366f9c3L, 0xc8b38e74L, 0xb475f255L, 0x46fcd9b9L,
+ 0x7aeb2661L, 0x8b1ddf84L, 0x846a0e79L, 0x915f95e2L,
+ 0x466e598eL, 0x20b45770L, 0x8cd55591L, 0xc902de4cL,
+ 0xb90bace1L, 0xbb8205d0L, 0x11a86248L, 0x7574a99eL,
+ 0xb77f19b6L, 0xe0a9dc09L, 0x662d09a1L, 0xc4324633L,
+ 0xe85a1f02L, 0x09f0be8cL, 0x4a99a025L, 0x1d6efe10L,
+ 0x1ab93d1dL, 0x0ba5a4dfL, 0xa186f20fL, 0x2868f169L,
+ 0xdcb7da83L, 0x573906feL, 0xa1e2ce9bL, 0x4fcd7f52L,
+ 0x50115e01L, 0xa70683faL, 0xa002b5c4L, 0x0de6d027L,
+ 0x9af88c27L, 0x773f8641L, 0xc3604c06L, 0x61a806b5L,
+ 0xf0177a28L, 0xc0f586e0L, 0x006058aaL, 0x30dc7d62L,
+ 0x11e69ed7L, 0x2338ea63L, 0x53c2dd94L, 0xc2c21634L,
+ 0xbbcbee56L, 0x90bcb6deL, 0xebfc7da1L, 0xce591d76L,
+ 0x6f05e409L, 0x4b7c0188L, 0x39720a3dL, 0x7c927c24L,
+ 0x86e3725fL, 0x724d9db9L, 0x1ac15bb4L, 0xd39eb8fcL,
+ 0xed545578L, 0x08fca5b5L, 0xd83d7cd3L, 0x4dad0fc4L,
+ 0x1e50ef5eL, 0xb161e6f8L, 0xa28514d9L, 0x6c51133cL,
+ 0x6fd5c7e7L, 0x56e14ec4L, 0x362abfceL, 0xddc6c837L,
+ 0xd79a3234L, 0x92638212L, 0x670efa8eL, 0x406000e0L,
+ 0x3a39ce37L, 0xd3faf5cfL, 0xabc27737L, 0x5ac52d1bL,
+ 0x5cb0679eL, 0x4fa33742L, 0xd3822740L, 0x99bc9bbeL,
+ 0xd5118e9dL, 0xbf0f7315L, 0xd62d1c7eL, 0xc700c47bL,
+ 0xb78c1b6bL, 0x21a19045L, 0xb26eb1beL, 0x6a366eb4L,
+ 0x5748ab2fL, 0xbc946e79L, 0xc6a376d2L, 0x6549c2c8L,
+ 0x530ff8eeL, 0x468dde7dL, 0xd5730a1dL, 0x4cd04dc6L,
+ 0x2939bbdbL, 0xa9ba4650L, 0xac9526e8L, 0xbe5ee304L,
+ 0xa1fad5f0L, 0x6a2d519aL, 0x63ef8ce2L, 0x9a86ee22L,
+ 0xc089c2b8L, 0x43242ef6L, 0xa51e03aaL, 0x9cf2d0a4L,
+ 0x83c061baL, 0x9be96a4dL, 0x8fe51550L, 0xba645bd6L,
+ 0x2826a2f9L, 0xa73a3ae1L, 0x4ba99586L, 0xef5562e9L,
+ 0xc72fefd3L, 0xf752f7daL, 0x3f046f69L, 0x77fa0a59L,
+ 0x80e4a915L, 0x87b08601L, 0x9b09e6adL, 0x3b3ee593L,
+ 0xe990fd5aL, 0x9e34d797L, 0x2cf0b7d9L, 0x022b8b51L,
+ 0x96d5ac3aL, 0x017da67dL, 0xd1cf3ed6L, 0x7c7d2d28L,
+ 0x1f9f25cfL, 0xadf2b89bL, 0x5ad6b472L, 0x5a88f54cL,
+ 0xe029ac71L, 0xe019a5e6L, 0x47b0acfdL, 0xed93fa9bL,
+ 0xe8d3c48dL, 0x283b57ccL, 0xf8d56629L, 0x79132e28L,
+ 0x785f0191L, 0xed756055L, 0xf7960e44L, 0xe3d35e8cL,
+ 0x15056dd4L, 0x88f46dbaL, 0x03a16125L, 0x0564f0bdL,
+ 0xc3eb9e15L, 0x3c9057a2L, 0x97271aecL, 0xa93a072aL,
+ 0x1b3f6d9bL, 0x1e6321f5L, 0xf59c66fbL, 0x26dcf319L,
+ 0x7533d928L, 0xb155fdf5L, 0x03563482L, 0x8aba3cbbL,
+ 0x28517711L, 0xc20ad9f8L, 0xabcc5167L, 0xccad925fL,
+ 0x4de81751L, 0x3830dc8eL, 0x379d5862L, 0x9320f991L,
+ 0xea7a90c2L, 0xfb3e7bceL, 0x5121ce64L, 0x774fbe32L,
+ 0xa8b6e37eL, 0xc3293d46L, 0x48de5369L, 0x6413e680L,
+ 0xa2ae0810L, 0xdd6db224L, 0x69852dfdL, 0x09072166L,
+ 0xb39a460aL, 0x6445c0ddL, 0x586cdecfL, 0x1c20c8aeL,
+ 0x5bbef7ddL, 0x1b588d40L, 0xccd2017fL, 0x6bb4e3bbL,
+ 0xdda26a7eL, 0x3a59ff45L, 0x3e350a44L, 0xbcb4cdd5L,
+ 0x72eacea8L, 0xfa6484bbL, 0x8d6612aeL, 0xbf3c6f47L,
+ 0xd29be463L, 0x542f5d9eL, 0xaec2771bL, 0xf64e6370L,
+ 0x740e0d8dL, 0xe75b1357L, 0xf8721671L, 0xaf537d5dL,
+ 0x4040cb08L, 0x4eb4e2ccL, 0x34d2466aL, 0x0115af84L,
+ 0xe1b00428L, 0x95983a1dL, 0x06b89fb4L, 0xce6ea048L,
+ 0x6f3f3b82L, 0x3520ab82L, 0x011a1d4bL, 0x277227f8L,
+ 0x611560b1L, 0xe7933fdcL, 0xbb3a792bL, 0x344525bdL,
+ 0xa08839e1L, 0x51ce794bL, 0x2f32c9b7L, 0xa01fbac9L,
+ 0xe01cc87eL, 0xbcc7d1f6L, 0xcf0111c3L, 0xa1e8aac7L,
+ 0x1a908749L, 0xd44fbd9aL, 0xd0dadecbL, 0xd50ada38L,
+ 0x0339c32aL, 0xc6913667L, 0x8df9317cL, 0xe0b12b4fL,
+ 0xf79e59b7L, 0x43f5bb3aL, 0xf2d519ffL, 0x27d9459cL,
+ 0xbf97222cL, 0x15e6fc2aL, 0x0f91fc71L, 0x9b941525L,
+ 0xfae59361L, 0xceb69cebL, 0xc2a86459L, 0x12baa8d1L,
+ 0xb6c1075eL, 0xe3056a0cL, 0x10d25065L, 0xcb03a442L,
+ 0xe0ec6e0eL, 0x1698db3bL, 0x4c98a0beL, 0x3278e964L,
+ 0x9f1f9532L, 0xe0d392dfL, 0xd3a0342bL, 0x8971f21eL,
+ 0x1b0a7441L, 0x4ba3348cL, 0xc5be7120L, 0xc37632d8L,
+ 0xdf359f8dL, 0x9b992f2eL, 0xe60b6f47L, 0x0fe3f11dL,
+ 0xe54cda54L, 0x1edad891L, 0xce6279cfL, 0xcd3e7e6fL,
+ 0x1618b166L, 0xfd2c1d05L, 0x848fd2c5L, 0xf6fb2299L,
+ 0xf523f357L, 0xa6327623L, 0x93a83531L, 0x56cccd02L,
+ 0xacf08162L, 0x5a75ebb5L, 0x6e163697L, 0x88d273ccL,
+ 0xde966292L, 0x81b949d0L, 0x4c50901bL, 0x71c65614L,
+ 0xe6c6c7bdL, 0x327a140aL, 0x45e1d006L, 0xc3f27b9aL,
+ 0xc9aa53fdL, 0x62a80f00L, 0xbb25bfe2L, 0x35bdd2f6L,
+ 0x71126905L, 0xb2040222L, 0xb6cbcf7cL, 0xcd769c2bL,
+ 0x53113ec0L, 0x1640e3d3L, 0x38abbd60L, 0x2547adf0L,
+ 0xba38209cL, 0xf746ce76L, 0x77afa1c5L, 0x20756060L,
+ 0x85cbfe4eL, 0x8ae88dd8L, 0x7aaaf9b0L, 0x4cf9aa7eL,
+ 0x1948c25cL, 0x02fb8a8cL, 0x01c36ae4L, 0xd6ebe1f9L,
+ 0x90d4f869L, 0xa65cdea0L, 0x3f09252dL, 0xc208e69fL,
+ 0xb74e6132L, 0xce77e25bL, 0x578fdfe3L, 0x3ac372e6L,
+ }
+ };
+
diff --git a/lib/libcrypto/libblowfish/bf_skey.c b/lib/libcrypto/libblowfish/bf_skey.c
new file mode 100644
index 000000000..8cdbbd283
--- /dev/null
+++ b/lib/libcrypto/libblowfish/bf_skey.c
@@ -0,0 +1,122 @@
+/* crypto/bf/bf_skey.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/string.h>
+#else
+#include <stdio.h>
+#include <string.h>
+#endif
+
+#include "blowfish.h"
+#include "bf_locl.h"
+#include "bf_pi.h"
+
+void BF_set_key(BF_KEY *key, int len, const unsigned char *data)
+ {
+ int i;
+ BF_LONG *p,ri,in[2];
+ const unsigned char *d,*end;
+
+
+ memcpy((char *)key,(const char *)&bf_init,sizeof(BF_KEY));
+ p=key->P;
+
+ if (len > ((BF_ROUNDS+2)*4)) len=(BF_ROUNDS+2)*4;
+
+ d=data;
+ end= &(data[len]);
+ for (i=0; i<(BF_ROUNDS+2); i++)
+ {
+ ri= *(d++);
+ if (d >= end) d=data;
+
+ ri<<=8;
+ ri|= *(d++);
+ if (d >= end) d=data;
+
+ ri<<=8;
+ ri|= *(d++);
+ if (d >= end) d=data;
+
+ ri<<=8;
+ ri|= *(d++);
+ if (d >= end) d=data;
+
+ p[i]^=ri;
+ }
+
+ in[0]=0L;
+ in[1]=0L;
+ for (i=0; i<(BF_ROUNDS+2); i+=2)
+ {
+ BF_encrypt(in,key);
+ p[i ]=in[0];
+ p[i+1]=in[1];
+ }
+
+ p=key->S;
+ for (i=0; i<4*256; i+=2)
+ {
+ BF_encrypt(in,key);
+ p[i ]=in[0];
+ p[i+1]=in[1];
+ }
+ }
+
diff --git a/lib/libcrypto/libblowfish/blowfish.h b/lib/libcrypto/libblowfish/blowfish.h
new file mode 100644
index 000000000..ccb97e272
--- /dev/null
+++ b/lib/libcrypto/libblowfish/blowfish.h
@@ -0,0 +1,133 @@
+/* crypto/bf/blowfish.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_BLOWFISH_H
+#define HEADER_BLOWFISH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef NO_BF
+#error BF is disabled.
+#endif
+
+#define BF_ENCRYPT 1
+#define BF_DECRYPT 0
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * ! BF_LONG has to be at least 32 bits wide. If it's wider, then !
+ * ! BF_LONG_LOG2 has to be defined along. !
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+#if defined(WIN16) || defined(__LP32__)
+#define BF_LONG unsigned long
+#elif defined(_CRAY) || defined(__ILP64__)
+#define BF_LONG unsigned long
+#define BF_LONG_LOG2 3
+#endif
+/*
+ * _CRAY note. I could declare short, but I have no idea what impact
+ * does it have on performance on none-T3E machines. I could declare
+ * int, but at least on C90 sizeof(int) can be chosen at compile time.
+ * So I've chosen long...
+ * <appro@fy.chalmers.se>
+ */
+
+/* des.h-like hack <jjo-ipsec@mendoza.gov.ar> */
+#ifndef BF_LONG
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#define BF_LONG u_int32_t
+#endif
+
+#define BF_ROUNDS 16
+#define BF_BLOCK 8
+
+typedef struct bf_key_st
+ {
+ BF_LONG P[BF_ROUNDS+2];
+ BF_LONG S[4*256];
+ } BF_KEY;
+
+
+void BF_set_key(BF_KEY *key, int len, const unsigned char *data);
+
+void BF_encrypt(BF_LONG *data,const BF_KEY *key);
+void BF_decrypt(BF_LONG *data,const BF_KEY *key);
+
+void BF_ecb_encrypt(const unsigned char *in, unsigned char *out,
+ const BF_KEY *key, int enc);
+void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
+ const BF_KEY *schedule, unsigned char *ivec, int enc);
+void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length,
+ const BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
+void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, long length,
+ const BF_KEY *schedule, unsigned char *ivec, int *num);
+const char *BF_options(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/libcrypto/libserpent/Makefile b/lib/libcrypto/libserpent/Makefile
new file mode 100644
index 000000000..51a1e0582
--- /dev/null
+++ b/lib/libcrypto/libserpent/Makefile
@@ -0,0 +1,20 @@
+CFLAGS=-O3 -fomit-frame-pointer -D__KERNEL__ -Wall $(EXTRA_CFLAGS)
+INC=-I../include
+LIBOBJ=serpent.o serpent_cbc.o
+BLIB=libserpent.a
+
+.c.o:
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c $< -o $@
+
+$(BLIB): $(LIBOBJ)
+ /bin/rm -f $(BLIB)
+ ar cr $(BLIB) $(LIBOBJ)
+ -if test -s /bin/ranlib; then /bin/ranlib $(BLIB); \
+ else if test -s /usr/bin/ranlib; then /usr/bin/ranlib $(BLIB); \
+ else exit 0; fi; fi
+
+test: test_main.o $(BLIB)
+ $(CC) -o $@ $^
+
+clean:
+ rm -f *.[oa] core $(TARGET) test
diff --git a/lib/libcrypto/libserpent/serpent.c b/lib/libcrypto/libserpent/serpent.c
new file mode 100644
index 000000000..f2cea250e
--- /dev/null
+++ b/lib/libcrypto/libserpent/serpent.c
@@ -0,0 +1,995 @@
+
+/* Optimized implementation of the Serpent AES candidate algorithm
+ * Designed by Anderson, Biham and Knudsen and Implemented by
+ * Gisle Sælensminde 2000.
+ *
+ * The implementation is based on the pentium optimised sboxes of
+ * Dag Arne Osvik. Even these sboxes are designed to be optimal for x86
+ * processors they are efficient on other processors as well, but the speedup
+ * isn't so impressive compared to other implementations.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifdef __KERNEL__
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+#else
+#include <sys/types.h>
+#include <asm/byteorder.h>
+#endif
+
+#include "serpent.h"
+
+#define rotl(reg, val) ((reg << val) | (reg >> (32 - val)))
+#define rotr(reg, val) ((reg >> val) | (reg << (32 - val)))
+
+#ifdef __cpu_to_be32
+#define BLOCK_SWAP
+#define io_swap(x) __cpu_to_be32(x)
+#else
+#undef BLOCK_SWAP
+#endif
+
+/* The sbox functions. The first four parameters is the input bits, and
+ * the last is a tempoary. These parameters are also used for output, but
+ * the bit order is permuted. The output bit order from S0 is
+ * (1 4 2 0 3), where 3 is the (now useless) tempoary.
+ */
+
+#define S0(r0,r1,r2,r3,r4) \
+ r3 = r3 ^ r0; \
+ r4 = r1; \
+ r1 = r1 & r3; \
+ r4 = r4 ^ r2; \
+ r1 = r1 ^ r0; \
+ r0 = r0 | r3; \
+ r0 = r0 ^ r4; \
+ r4 = r4 ^ r3; \
+ r3 = r3 ^ r2; \
+ r2 = r2 | r1; \
+ r2 = r2 ^ r4; \
+ r4 = -1 ^ r4; \
+ r4 = r4 | r1; \
+ r1 = r1 ^ r3; \
+ r1 = r1 ^ r4; \
+ r3 = r3 | r0; \
+ r1 = r1 ^ r3; \
+ r4 = r4 ^ r3;
+
+#define S1(r0,r1,r2,r3,r4) \
+ r1 = -1 ^ r1; \
+ r4 = r0; \
+ r0 = r0 ^ r1; \
+ r4 = r4 | r1; \
+ r4 = r4 ^ r3; \
+ r3 = r3 & r0; \
+ r2 = r2 ^ r4; \
+ r3 = r3 ^ r1; \
+ r3 = r3 | r2; \
+ r0 = r0 ^ r4; \
+ r3 = r3 ^ r0; \
+ r1 = r1 & r2; \
+ r0 = r0 | r1; \
+ r1 = r1 ^ r4; \
+ r0 = r0 ^ r2; \
+ r4 = r4 | r3; \
+ r0 = r0 ^ r4; \
+ r4 = -1 ^ r4; \
+ r1 = r1 ^ r3; \
+ r4 = r4 & r2; \
+ r1 = -1 ^ r1; \
+ r4 = r4 ^ r0; \
+ r1 = r1 ^ r4;
+
+#define S2(r0,r1,r2,r3,r4) \
+ r4 = r0; \
+ r0 = r0 & r2; \
+ r0 = r0 ^ r3; \
+ r2 = r2 ^ r1; \
+ r2 = r2 ^ r0; \
+ r3 = r3 | r4; \
+ r3 = r3 ^ r1; \
+ r4 = r4 ^ r2; \
+ r1 = r3; \
+ r3 = r3 | r4; \
+ r3 = r3 ^ r0; \
+ r0 = r0 & r1; \
+ r4 = r4 ^ r0; \
+ r1 = r1 ^ r3; \
+ r1 = r1 ^ r4; \
+ r4 = -1 ^ r4;
+
+#define S3(r0,r1,r2,r3,r4) \
+ r4 = r0 ; \
+ r0 = r0 | r3; \
+ r3 = r3 ^ r1; \
+ r1 = r1 & r4; \
+ r4 = r4 ^ r2; \
+ r2 = r2 ^ r3; \
+ r3 = r3 & r0; \
+ r4 = r4 | r1; \
+ r3 = r3 ^ r4; \
+ r0 = r0 ^ r1; \
+ r4 = r4 & r0; \
+ r1 = r1 ^ r3; \
+ r4 = r4 ^ r2; \
+ r1 = r1 | r0; \
+ r1 = r1 ^ r2; \
+ r0 = r0 ^ r3; \
+ r2 = r1; \
+ r1 = r1 | r3; \
+ r1 = r1 ^ r0;
+
+#define S4(r0,r1,r2,r3,r4) \
+ r1 = r1 ^ r3; \
+ r3 = -1 ^ r3; \
+ r2 = r2 ^ r3; \
+ r3 = r3 ^ r0; \
+ r4 = r1; \
+ r1 = r1 & r3; \
+ r1 = r1 ^ r2; \
+ r4 = r4 ^ r3; \
+ r0 = r0 ^ r4; \
+ r2 = r2 & r4; \
+ r2 = r2 ^ r0; \
+ r0 = r0 & r1; \
+ r3 = r3 ^ r0; \
+ r4 = r4 | r1; \
+ r4 = r4 ^ r0; \
+ r0 = r0 | r3; \
+ r0 = r0 ^ r2; \
+ r2 = r2 & r3; \
+ r0 = -1 ^ r0; \
+ r4 = r4 ^ r2;
+
+#define S5(r0,r1,r2,r3,r4) \
+ r0 = r0 ^ r1; \
+ r1 = r1 ^ r3; \
+ r3 = -1 ^ r3; \
+ r4 = r1; \
+ r1 = r1 & r0; \
+ r2 = r2 ^ r3; \
+ r1 = r1 ^ r2; \
+ r2 = r2 | r4; \
+ r4 = r4 ^ r3; \
+ r3 = r3 & r1; \
+ r3 = r3 ^ r0; \
+ r4 = r4 ^ r1; \
+ r4 = r4 ^ r2; \
+ r2 = r2 ^ r0; \
+ r0 = r0 & r3; \
+ r2 = -1 ^ r2; \
+ r0 = r0 ^ r4; \
+ r4 = r4 | r3; \
+ r2 = r2 ^ r4;
+
+#define S6(r0,r1,r2,r3,r4) \
+ r2 = -1 ^ r2; \
+ r4 = r3; \
+ r3 = r3 & r0; \
+ r0 = r0 ^ r4; \
+ r3 = r3 ^ r2; \
+ r2 = r2 | r4; \
+ r1 = r1 ^ r3; \
+ r2 = r2 ^ r0; \
+ r0 = r0 | r1; \
+ r2 = r2 ^ r1; \
+ r4 = r4 ^ r0; \
+ r0 = r0 | r3; \
+ r0 = r0 ^ r2; \
+ r4 = r4 ^ r3; \
+ r4 = r4 ^ r0; \
+ r3 = -1 ^ r3; \
+ r2 = r2 & r4; \
+ r2 = r2 ^ r3;
+
+#define S7(r0,r1,r2,r3,r4) \
+ r4 = r2; \
+ r2 = r2 & r1; \
+ r2 = r2 ^ r3; \
+ r3 = r3 & r1; \
+ r4 = r4 ^ r2; \
+ r2 = r2 ^ r1; \
+ r1 = r1 ^ r0; \
+ r0 = r0 | r4; \
+ r0 = r0 ^ r2; \
+ r3 = r3 ^ r1; \
+ r2 = r2 ^ r3; \
+ r3 = r3 & r0; \
+ r3 = r3 ^ r4; \
+ r4 = r4 ^ r2; \
+ r2 = r2 & r0; \
+ r4 = -1 ^ r4; \
+ r2 = r2 ^ r4; \
+ r4 = r4 & r0; \
+ r1 = r1 ^ r3; \
+ r4 = r4 ^ r1;
+
+/* The inverse sboxes */
+
+#define I0(r0,r1,r2,r3,r4) \
+ r2 = r2 ^ -1; \
+ r4 = r1; \
+ r1 = r1 | r0; \
+ r4 = r4 ^ -1; \
+ r1 = r1 ^ r2; \
+ r2 = r2 | r4; \
+ r1 = r1 ^ r3; \
+ r0 = r0 ^ r4; \
+ r2 = r2 ^ r0; \
+ r0 = r0 & r3; \
+ r4 = r4 ^ r0; \
+ r0 = r0 | r1; \
+ r0 = r0 ^ r2; \
+ r3 = r3 ^ r4; \
+ r2 = r2 ^ r1; \
+ r3 = r3 ^ r0; \
+ r3 = r3 ^ r1; \
+ r2 = r2 & r3; \
+ r4 = r4 ^ r2;
+
+#define I1(r0,r1,r2,r3,r4) \
+ r4 = r1; \
+ r1 = r1 ^ r3; \
+ r3 = r3 & r1; \
+ r4 = r4 ^ r2; \
+ r3 = r3 ^ r0; \
+ r0 = r0 | r1; \
+ r2 = r2 ^ r3; \
+ r0 = r0 ^ r4; \
+ r0 = r0 | r2; \
+ r1 = r1 ^ r3; \
+ r0 = r0 ^ r1; \
+ r1 = r1 | r3; \
+ r1 = r1 ^ r0; \
+ r4 = r4 ^ -1; \
+ r4 = r4 ^ r1; \
+ r1 = r1 | r0; \
+ r1 = r1 ^ r0; \
+ r1 = r1 | r4; \
+ r3 = r3 ^ r1;
+
+#define I2(r0,r1,r2,r3,r4) \
+ r2 = r2 ^ r3; \
+ r3 = r3 ^ r0; \
+ r4 = r3; \
+ r3 = r3 & r2; \
+ r3 = r3 ^ r1; \
+ r1 = r1 | r2; \
+ r1 = r1 ^ r4; \
+ r4 = r4 & r3; \
+ r2 = r2 ^ r3; \
+ r4 = r4 & r0; \
+ r4 = r4 ^ r2; \
+ r2 = r2 & r1; \
+ r2 = r2 | r0; \
+ r3 = r3 ^ -1; \
+ r2 = r2 ^ r3; \
+ r0 = r0 ^ r3; \
+ r0 = r0 & r1; \
+ r3 = r3 ^ r4; \
+ r3 = r3 ^ r0;
+
+#define I3(r0,r1,r2,r3,r4) \
+ r4 = r2; \
+ r2 = r2 ^ r1; \
+ r0 = r0 ^ r2; \
+ r4 = r4 & r2; \
+ r4 = r4 ^ r0; \
+ r0 = r0 & r1; \
+ r1 = r1 ^ r3; \
+ r3 = r3 | r4; \
+ r2 = r2 ^ r3; \
+ r0 = r0 ^ r3; \
+ r1 = r1 ^ r4; \
+ r3 = r3 & r2; \
+ r3 = r3 ^ r1; \
+ r1 = r1 ^ r0; \
+ r1 = r1 | r2; \
+ r0 = r0 ^ r3; \
+ r1 = r1 ^ r4; \
+ r0 = r0 ^ r1;
+
+#define I4(r0,r1,r2,r3,r4) \
+ r4 = r2; \
+ r2 = r2 & r3; \
+ r2 = r2 ^ r1; \
+ r1 = r1 | r3; \
+ r1 = r1 & r0; \
+ r4 = r4 ^ r2; \
+ r4 = r4 ^ r1; \
+ r1 = r1 & r2; \
+ r0 = r0 ^ -1; \
+ r3 = r3 ^ r4; \
+ r1 = r1 ^ r3; \
+ r3 = r3 & r0; \
+ r3 = r3 ^ r2; \
+ r0 = r0 ^ r1; \
+ r2 = r2 & r0; \
+ r3 = r3 ^ r0; \
+ r2 = r2 ^ r4; \
+ r2 = r2 | r3; \
+ r3 = r3 ^ r0; \
+ r2 = r2 ^ r1;
+
+#define I5(r0,r1,r2,r3,r4) \
+ r1 = r1 ^ -1; \
+ r4 = r3; \
+ r2 = r2 ^ r1; \
+ r3 = r3 | r0; \
+ r3 = r3 ^ r2; \
+ r2 = r2 | r1; \
+ r2 = r2 & r0; \
+ r4 = r4 ^ r3; \
+ r2 = r2 ^ r4; \
+ r4 = r4 | r0; \
+ r4 = r4 ^ r1; \
+ r1 = r1 & r2; \
+ r1 = r1 ^ r3; \
+ r4 = r4 ^ r2; \
+ r3 = r3 & r4; \
+ r4 = r4 ^ r1; \
+ r3 = r3 ^ r0; \
+ r3 = r3 ^ r4; \
+ r4 = r4 ^ -1;
+
+
+#define I6(r0,r1,r2,r3,r4) \
+ r0 = r0 ^ r2; \
+ r4 = r2; \
+ r2 = r2 & r0; \
+ r4 = r4 ^ r3; \
+ r2 = r2 ^ -1; \
+ r3 = r3 ^ r1; \
+ r2 = r2 ^ r3; \
+ r4 = r4 | r0; \
+ r0 = r0 ^ r2; \
+ r3 = r3 ^ r4; \
+ r4 = r4 ^ r1; \
+ r1 = r1 & r3; \
+ r1 = r1 ^ r0; \
+ r0 = r0 ^ r3; \
+ r0 = r0 | r2; \
+ r3 = r3 ^ r1; \
+ r4 = r4 ^ r0;
+
+#define I7(r0,r1,r2,r3,r4) \
+ r4 = r2; \
+ r2 = r2 ^ r0; \
+ r0 = r0 & r3; \
+ r4 = r4 | r3; \
+ r2 = r2 ^ -1; \
+ r3 = r3 ^ r1; \
+ r1 = r1 | r0; \
+ r0 = r0 ^ r2; \
+ r2 = r2 & r4; \
+ r3 = r3 & r4; \
+ r1 = r1 ^ r2; \
+ r2 = r2 ^ r0; \
+ r0 = r0 | r2; \
+ r4 = r4 ^ r1; \
+ r0 = r0 ^ r3; \
+ r3 = r3 ^ r4; \
+ r4 = r4 | r0; \
+ r3 = r3 ^ r2; \
+ r4 = r4 ^ r2;
+
+/* forward and inverse linear transformations */
+
+#define LINTRANS(r0,r1,r2,r3,r4) \
+ r0 = rotl(r0, 13); \
+ r2 = rotl(r2, 3); \
+ r3 = r3 ^ r2; \
+ r4 = r0 << 3; \
+ r1 = r1 ^ r0; \
+ r3 = r3 ^ r4; \
+ r1 = r1 ^ r2; \
+ r3 = rotl(r3, 7); \
+ r1 = rotl(r1, 1); \
+ r2 = r2 ^ r3; \
+ r4 = r1 << 7; \
+ r0 = r0 ^ r1; \
+ r2 = r2 ^ r4; \
+ r0 = r0 ^ r3; \
+ r2 = rotl(r2, 22); \
+ r0 = rotl(r0, 5);
+
+#define ILINTRANS(r0,r1,r2,r3,r4) \
+ r2 = rotr(r2, 22); \
+ r0 = rotr(r0, 5); \
+ r2 = r2 ^ r3; \
+ r4 = r1 << 7; \
+ r0 = r0 ^ r1; \
+ r2 = r2 ^ r4; \
+ r0 = r0 ^ r3; \
+ r3 = rotr(r3, 7); \
+ r1 = rotr(r1, 1); \
+ r3 = r3 ^ r2; \
+ r4 = r0 << 3; \
+ r1 = r1 ^ r0; \
+ r3 = r3 ^ r4; \
+ r1 = r1 ^ r2; \
+ r2 = rotr(r2, 3); \
+ r0 = rotr(r0, 13);
+
+
+#define KEYMIX(r0,r1,r2,r3,r4,IN) \
+ r0 = r0 ^ l_key[IN+8]; \
+ r1 = r1 ^ l_key[IN+9]; \
+ r2 = r2 ^ l_key[IN+10]; \
+ r3 = r3 ^ l_key[IN+11];
+
+#define GETKEY(r0, r1, r2, r3, IN) \
+ r0 = l_key[IN+8]; \
+ r1 = l_key[IN+9]; \
+ r2 = l_key[IN+10]; \
+ r3 = l_key[IN+11];
+
+#define SETKEY(r0, r1, r2, r3, IN) \
+ l_key[IN+8] = r0; \
+ l_key[IN+9] = r1; \
+ l_key[IN+10] = r2; \
+ l_key[IN+11] = r3;
+
+/* initialise the key schedule from the user supplied key */
+
+int serpent_set_key(serpent_context *cx, const unsigned char *key, int key_len)
+{ const u32 *in_key = (const u32 *)key;
+ /* l_key - storage for the key schedule */
+ u32 *l_key = cx->keyinfo;
+ u32 i,lk,r0,r1,r2,r3,r4;
+
+ if (key_len != 16 && key_len != 24 && key_len != 32)
+ return -1; /* unsupported key length */
+
+ key_len *= 8;
+
+ i = 0; lk = (key_len + 31) / 32;
+
+ while(i < lk)
+ {
+#ifdef BLOCK_SWAP
+ l_key[i] = io_swap(in_key[lk - i - 1]);
+#else
+ l_key[i] = in_key[i];
+#endif
+ i++;
+ }
+
+ if (key_len < 256)
+ {
+ while(i < 8)
+
+ l_key[i++] = 0;
+
+ i = key_len / 32; lk = 1 << key_len % 32;
+
+ l_key[i] &= lk - 1;
+ l_key[i] |= lk;
+ }
+
+ for(i = 0; i < 132; ++i)
+ {
+ lk = l_key[i] ^ l_key[i + 3] ^ l_key[i + 5]
+ ^ l_key[i + 7] ^ 0x9e3779b9 ^ i;
+
+ l_key[i + 8] = (lk << 11) | (lk >> 21);
+ }
+
+ GETKEY(r0, r1, r2, r3, 0);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 0)
+
+ GETKEY(r0, r1, r2, r3, 4);
+ S2(r0,r1,r2,r3,r4);
+ SETKEY(r2, r3, r1, r4, 4)
+
+ GETKEY(r0, r1, r2, r3, 8);
+ S1(r0,r1,r2,r3,r4);
+ SETKEY(r3, r1, r2, r0, 8)
+
+ GETKEY(r0, r1, r2, r3, 12);
+ S0(r0,r1,r2,r3,r4);
+ SETKEY(r1, r4, r2, r0, 12)
+
+ GETKEY(r0, r1, r2, r3, 16);
+ S7(r0,r1,r2,r3,r4);
+ SETKEY(r2, r4, r3, r0, 16)
+
+ GETKEY(r0, r1, r2, r3, 20);
+ S6(r0,r1,r2,r3,r4)
+ SETKEY(r0, r1, r4, r2, 20)
+
+ GETKEY(r0, r1, r2, r3, 24);
+ S5(r0,r1,r2,r3,r4);
+ SETKEY(r1, r3, r0, r2, 24)
+
+ GETKEY(r0, r1, r2, r3, 28);
+ S4(r0,r1,r2,r3,r4)
+ SETKEY(r1, r4, r0, r3, 28)
+
+ GETKEY(r0, r1, r2, r3, 32);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 32)
+
+ GETKEY(r0, r1, r2, r3, 36);
+ S2(r0,r1,r2,r3,r4);
+ SETKEY(r2, r3, r1, r4, 36)
+
+ GETKEY(r0, r1, r2, r3, 40);
+ S1(r0,r1,r2,r3,r4);
+ SETKEY(r3, r1, r2, r0, 40)
+
+ GETKEY(r0, r1, r2, r3, 44);
+ S0(r0,r1,r2,r3,r4);
+ SETKEY(r1, r4, r2, r0, 44)
+
+ GETKEY(r0, r1, r2, r3, 48);
+ S7(r0,r1,r2,r3,r4);
+ SETKEY(r2, r4, r3, r0, 48)
+
+ GETKEY(r0, r1, r2, r3, 52);
+ S6(r0,r1,r2,r3,r4)
+ SETKEY(r0, r1, r4, r2, 52)
+
+ GETKEY(r0, r1, r2, r3, 56);
+ S5(r0,r1,r2,r3,r4);
+ SETKEY(r1, r3, r0, r2, 56)
+
+ GETKEY(r0, r1, r2, r3, 60);
+ S4(r0,r1,r2,r3,r4)
+ SETKEY(r1, r4, r0, r3, 60)
+
+ GETKEY(r0, r1, r2, r3, 64);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 64)
+
+ GETKEY(r0, r1, r2, r3, 68);
+ S2(r0,r1,r2,r3,r4);
+ SETKEY(r2, r3, r1, r4, 68)
+
+ GETKEY(r0, r1, r2, r3, 72);
+ S1(r0,r1,r2,r3,r4);
+ SETKEY(r3, r1, r2, r0, 72)
+
+ GETKEY(r0, r1, r2, r3, 76);
+ S0(r0,r1,r2,r3,r4);
+ SETKEY(r1, r4, r2, r0, 76)
+
+ GETKEY(r0, r1, r2, r3, 80);
+ S7(r0,r1,r2,r3,r4);
+ SETKEY(r2, r4, r3, r0, 80)
+
+ GETKEY(r0, r1, r2, r3, 84);
+ S6(r0,r1,r2,r3,r4)
+ SETKEY(r0, r1, r4, r2, 84)
+
+ GETKEY(r0, r1, r2, r3, 88);
+ S5(r0,r1,r2,r3,r4);
+ SETKEY(r1, r3, r0, r2, 88)
+
+ GETKEY(r0, r1, r2, r3, 92);
+ S4(r0,r1,r2,r3,r4)
+ SETKEY(r1, r4, r0, r3, 92)
+
+ GETKEY(r0, r1, r2, r3, 96);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 96)
+
+ GETKEY(r0, r1, r2, r3, 100);
+ S2(r0,r1,r2,r3,r4);
+ SETKEY(r2, r3, r1, r4, 100)
+
+ GETKEY(r0, r1, r2, r3, 104);
+ S1(r0,r1,r2,r3,r4);
+ SETKEY(r3, r1, r2, r0, 104)
+
+ GETKEY(r0, r1, r2, r3, 108);
+ S0(r0,r1,r2,r3,r4);
+ SETKEY(r1, r4, r2, r0, 108)
+
+ GETKEY(r0, r1, r2, r3, 112);
+ S7(r0,r1,r2,r3,r4);
+ SETKEY(r2, r4, r3, r0, 112)
+
+ GETKEY(r0, r1, r2, r3, 116);
+ S6(r0,r1,r2,r3,r4)
+ SETKEY(r0, r1, r4, r2, 116)
+
+ GETKEY(r0, r1, r2, r3, 120);
+ S5(r0,r1,r2,r3,r4);
+ SETKEY(r1, r3, r0, r2, 120)
+
+ GETKEY(r0, r1, r2, r3, 124);
+ S4(r0,r1,r2,r3,r4)
+ SETKEY(r1, r4, r0, r3, 124)
+
+ GETKEY(r0, r1, r2, r3, 128);
+ S3(r0,r1,r2,r3,r4);
+ SETKEY(r1, r2, r3, r4, 128)
+
+ return 0;
+};
+
+/* Encryption and decryption functions. The rounds are fully inlined.
+ * The sboxes alters the bit order of the output, and the altered
+ * bit ordrer is used progressivly. */
+
+/* encrypt a block of text */
+
+int serpent_encrypt(serpent_context *cx, const u8 *in,
+ u8 *out)
+{ u32 *l_key = cx->keyinfo;
+ const u32 *in_blk = (const u32 *) in;
+ u32 *out_blk = (u32 *) out;
+ u32 r0,r1,r2,r3,r4;
+
+#ifdef BLOCK_SWAP
+ r0 = io_swap(in_blk[3]); r1 = io_swap(in_blk[2]);
+ r2 = io_swap(in_blk[1]); r3 = io_swap(in_blk[0]);
+#else
+ r0 = in_blk[0]; r1 = in_blk[1]; r2 = in_blk[2]; r3 = in_blk[3];
+#endif
+
+ /* round 1 */
+ KEYMIX(r0,r1,r2,r3,r4,0);
+ S0(r0,r1,r2,r3,r4);
+ LINTRANS(r1,r4,r2,r0,r3);
+
+ /* round 2 */
+ KEYMIX(r1,r4,r2,r0,r3,4);
+ S1(r1,r4,r2,r0,r3);
+ LINTRANS(r0,r4,r2,r1,r3);
+
+ /* round 3 */
+ KEYMIX(r0,r4,r2,r1,r3,8);
+ S2(r0,r4,r2,r1,r3);
+ LINTRANS(r2,r1,r4,r3,r0);
+
+ /* round 4 */
+ KEYMIX(r2,r1,r4,r3,r0,12);
+ S3(r2,r1,r4,r3,r0);
+ LINTRANS(r1,r4,r3,r0,r2);
+
+ /* round 5 */
+ KEYMIX(r1,r4,r3,r0,r2,16);
+ S4(r1,r4,r3,r0,r2)
+ LINTRANS(r4,r2,r1,r0,r3);
+
+ /* round 6 */
+ KEYMIX(r4,r2,r1,r0,r3,20);
+ S5(r4,r2,r1,r0,r3);
+ LINTRANS(r2,r0,r4,r1,r3);
+
+ /* round 7 */
+ KEYMIX(r2,r0,r4,r1,r3,24);
+ S6(r2,r0,r4,r1,r3)
+ LINTRANS(r2,r0,r3,r4,r1);
+
+ /* round 8 */
+ KEYMIX(r2,r0,r3,r4,r1,28);
+ S7(r2,r0,r3,r4,r1);
+ LINTRANS(r3,r1,r4,r2,r0);
+
+ /* round 9 */
+ KEYMIX(r3,r1,r4,r2,r0,32);
+ S0(r3,r1,r4,r2,r0);
+ LINTRANS(r1,r0,r4,r3,r2);
+
+ /* round 10 */
+ KEYMIX(r1,r0,r4,r3,r2,36);
+ S1(r1,r0,r4,r3,r2);
+ LINTRANS(r3,r0,r4,r1,r2);
+
+ /* round 11 */
+ KEYMIX(r3,r0,r4,r1,r2,40);
+ S2(r3,r0,r4,r1,r2);
+ LINTRANS(r4,r1,r0,r2,r3);
+
+ /* round 12 */
+ KEYMIX(r4,r1,r0,r2,r3,44);
+ S3(r4,r1,r0,r2,r3);
+ LINTRANS(r1,r0,r2,r3,r4);
+
+ /* round 13 */
+ KEYMIX(r1,r0,r2,r3,r4,48);
+ S4(r1,r0,r2,r3,r4)
+ LINTRANS(r0,r4,r1,r3,r2);
+
+ /* round 14 */
+ KEYMIX(r0,r4,r1,r3,r2,52);
+ S5(r0,r4,r1,r3,r2);
+ LINTRANS(r4,r3,r0,r1,r2);
+
+ /* round 15 */
+ KEYMIX(r4,r3,r0,r1,r2,56);
+ S6(r4,r3,r0,r1,r2)
+ LINTRANS(r4,r3,r2,r0,r1);
+
+ /* round 16 */
+ KEYMIX(r4,r3,r2,r0,r1,60);
+ S7(r4,r3,r2,r0,r1);
+ LINTRANS(r2,r1,r0,r4,r3);
+
+ /* round 17 */
+ KEYMIX(r2,r1,r0,r4,r3,64);
+ S0(r2,r1,r0,r4,r3);
+ LINTRANS(r1,r3,r0,r2,r4);
+
+ /* round 18 */
+ KEYMIX(r1,r3,r0,r2,r4,68);
+ S1(r1,r3,r0,r2,r4);
+ LINTRANS(r2,r3,r0,r1,r4);
+
+ /* round 19 */
+ KEYMIX(r2,r3,r0,r1,r4,72);
+ S2(r2,r3,r0,r1,r4);
+ LINTRANS(r0,r1,r3,r4,r2);
+
+ /* round 20 */
+ KEYMIX(r0,r1,r3,r4,r2,76);
+ S3(r0,r1,r3,r4,r2);
+ LINTRANS(r1,r3,r4,r2,r0);
+
+ /* round 21 */
+ KEYMIX(r1,r3,r4,r2,r0,80);
+ S4(r1,r3,r4,r2,r0)
+ LINTRANS(r3,r0,r1,r2,r4);
+
+ /* round 22 */
+ KEYMIX(r3,r0,r1,r2,r4,84);
+ S5(r3,r0,r1,r2,r4);
+ LINTRANS(r0,r2,r3,r1,r4);
+
+ /* round 23 */
+ KEYMIX(r0,r2,r3,r1,r4,88);
+ S6(r0,r2,r3,r1,r4)
+ LINTRANS(r0,r2,r4,r3,r1);
+
+ /* round 24 */
+ KEYMIX(r0,r2,r4,r3,r1,92);
+ S7(r0,r2,r4,r3,r1);
+ LINTRANS(r4,r1,r3,r0,r2);
+
+ /* round 25 */
+ KEYMIX(r4,r1,r3,r0,r2,96);
+ S0(r4,r1,r3,r0,r2);
+ LINTRANS(r1,r2,r3,r4,r0);
+
+ /* round 26 */
+ KEYMIX(r1,r2,r3,r4,r0,100);
+ S1(r1,r2,r3,r4,r0);
+ LINTRANS(r4,r2,r3,r1,r0);
+
+ /* round 27 */
+ KEYMIX(r4,r2,r3,r1,r0,104);
+ S2(r4,r2,r3,r1,r0);
+ LINTRANS(r3,r1,r2,r0,r4);
+
+ /* round 28 */
+ KEYMIX(r3,r1,r2,r0,r4,108);
+ S3(r3,r1,r2,r0,r4);
+ LINTRANS(r1,r2,r0,r4,r3);
+
+ /* round 29 */
+ KEYMIX(r1,r2,r0,r4,r3,112);
+ S4(r1,r2,r0,r4,r3)
+ LINTRANS(r2,r3,r1,r4,r0);
+
+ /* round 30 */
+ KEYMIX(r2,r3,r1,r4,r0,116);
+ S5(r2,r3,r1,r4,r0);
+ LINTRANS(r3,r4,r2,r1,r0);
+
+ /* round 31 */
+ KEYMIX(r3,r4,r2,r1,r0,120);
+ S6(r3,r4,r2,r1,r0)
+ LINTRANS(r3,r4,r0,r2,r1);
+
+ /* round 32 */
+ KEYMIX(r3,r4,r0,r2,r1,124);
+ S7(r3,r4,r0,r2,r1);
+ KEYMIX(r0,r1,r2,r3,r4,128);
+
+
+#ifdef BLOCK_SWAP
+ out_blk[3] = io_swap(r0); out_blk[2] = io_swap(r1);
+ out_blk[1] = io_swap(r2); out_blk[0] = io_swap(r3);
+#else
+ out_blk[0] = r0; out_blk[1] = r1; out_blk[2] = r2; out_blk[3] = r3;
+#endif
+ return 0;
+};
+
+/* decrypt a block of text */
+
+int serpent_decrypt(serpent_context *cx, const u8 *in,
+ u8 *out)
+{ u32 *l_key = cx->keyinfo;
+ const u32 *in_blk = (const u32 *)in;
+ u32 *out_blk = (u32 *)out;
+ u32 r0,r1,r2,r3,r4;
+
+#ifdef BLOCK_SWAP
+ r0 = io_swap(in_blk[3]); r1 = io_swap(in_blk[2]);
+ r2 = io_swap(in_blk[1]); r3 = io_swap(in_blk[0]);
+#else
+ r0 = in_blk[0]; r1 = in_blk[1]; r2 = in_blk[2]; r3 = in_blk[3];
+#endif
+
+ /* round 1 */
+ KEYMIX(r0,r1,r2,r3,r4,128);
+ I7(r0,r1,r2,r3,r4);
+ KEYMIX(r3,r0,r1,r4,r2,124);
+
+ /* round 2 */
+ ILINTRANS(r3,r0,r1,r4,r2);
+ I6(r3,r0,r1,r4,r2);
+ KEYMIX(r0,r1,r2,r4,r3,120);
+
+ /* round 3 */
+ ILINTRANS(r0,r1,r2,r4,r3);
+ I5(r0,r1,r2,r4,r3);
+ KEYMIX(r1,r3,r4,r2,r0,116);
+
+ /* round 4 */
+ ILINTRANS(r1,r3,r4,r2,r0);
+ I4(r1,r3,r4,r2,r0);
+ KEYMIX(r1,r2,r4,r0,r3,112);
+
+ /* round 5 */
+ ILINTRANS(r1,r2,r4,r0,r3);
+ I3(r1,r2,r4,r0,r3);
+ KEYMIX(r4,r2,r0,r1,r3,108);
+
+ /* round 6 */
+ ILINTRANS(r4,r2,r0,r1,r3);
+ I2(r4,r2,r0,r1,r3);
+ KEYMIX(r2,r3,r0,r1,r4,104);
+
+ /* round 7 */
+ ILINTRANS(r2,r3,r0,r1,r4);
+ I1(r2,r3,r0,r1,r4);
+ KEYMIX(r4,r2,r1,r0,r3,100);
+
+ /* round 8 */
+ ILINTRANS(r4,r2,r1,r0,r3);
+ I0(r4,r2,r1,r0,r3);
+ KEYMIX(r4,r3,r2,r0,r1,96);
+
+ /* round 9 */
+ ILINTRANS(r4,r3,r2,r0,r1);
+ I7(r4,r3,r2,r0,r1);
+ KEYMIX(r0,r4,r3,r1,r2,92);
+
+ /* round 10 */
+ ILINTRANS(r0,r4,r3,r1,r2);
+ I6(r0,r4,r3,r1,r2);
+ KEYMIX(r4,r3,r2,r1,r0,88);
+
+ /* round 11 */
+ ILINTRANS(r4,r3,r2,r1,r0);
+ I5(r4,r3,r2,r1,r0);
+ KEYMIX(r3,r0,r1,r2,r4,84);
+
+ /* round 12 */
+ ILINTRANS(r3,r0,r1,r2,r4);
+ I4(r3,r0,r1,r2,r4);
+ KEYMIX(r3,r2,r1,r4,r0,80);
+
+ /* round 13 */
+ ILINTRANS(r3,r2,r1,r4,r0);
+ I3(r3,r2,r1,r4,r0);
+ KEYMIX(r1,r2,r4,r3,r0,76);
+
+ /* round 14 */
+ ILINTRANS(r1,r2,r4,r3,r0);
+ I2(r1,r2,r4,r3,r0);
+ KEYMIX(r2,r0,r4,r3,r1,72);
+
+ /* round 15 */
+ ILINTRANS(r2,r0,r4,r3,r1);
+ I1(r2,r0,r4,r3,r1);
+ KEYMIX(r1,r2,r3,r4,r0,68);
+
+ /* round 16 */
+ ILINTRANS(r1,r2,r3,r4,r0);
+ I0(r1,r2,r3,r4,r0);
+ KEYMIX(r1,r0,r2,r4,r3,64);
+
+ /* round 17 */
+ ILINTRANS(r1,r0,r2,r4,r3);
+ I7(r1,r0,r2,r4,r3);
+ KEYMIX(r4,r1,r0,r3,r2,60);
+
+ /* round 18 */
+ ILINTRANS(r4,r1,r0,r3,r2);
+ I6(r4,r1,r0,r3,r2);
+ KEYMIX(r1,r0,r2,r3,r4,56);
+
+ /* round 19 */
+ ILINTRANS(r1,r0,r2,r3,r4);
+ I5(r1,r0,r2,r3,r4);
+ KEYMIX(r0,r4,r3,r2,r1,52);
+
+ /* round 20 */
+ ILINTRANS(r0,r4,r3,r2,r1);
+ I4(r0,r4,r3,r2,r1);
+ KEYMIX(r0,r2,r3,r1,r4,48);
+
+ /* round 21 */
+ ILINTRANS(r0,r2,r3,r1,r4);
+ I3(r0,r2,r3,r1,r4);
+ KEYMIX(r3,r2,r1,r0,r4,44);
+
+ /* round 22 */
+ ILINTRANS(r3,r2,r1,r0,r4);
+ I2(r3,r2,r1,r0,r4);
+ KEYMIX(r2,r4,r1,r0,r3,40);
+
+ /* round 23 */
+ ILINTRANS(r2,r4,r1,r0,r3);
+ I1(r2,r4,r1,r0,r3);
+ KEYMIX(r3,r2,r0,r1,r4,36);
+
+ /* round 24 */
+ ILINTRANS(r3,r2,r0,r1,r4);
+ I0(r3,r2,r0,r1,r4);
+ KEYMIX(r3,r4,r2,r1,r0,32);
+
+ /* round 25 */
+ ILINTRANS(r3,r4,r2,r1,r0);
+ I7(r3,r4,r2,r1,r0);
+ KEYMIX(r1,r3,r4,r0,r2,28);
+
+ /* round 26 */
+ ILINTRANS(r1,r3,r4,r0,r2);
+ I6(r1,r3,r4,r0,r2);
+ KEYMIX(r3,r4,r2,r0,r1,24);
+
+ /* round 27 */
+ ILINTRANS(r3,r4,r2,r0,r1);
+ I5(r3,r4,r2,r0,r1);
+ KEYMIX(r4,r1,r0,r2,r3,20);
+
+ /* round 28 */
+ ILINTRANS(r4,r1,r0,r2,r3);
+ I4(r4,r1,r0,r2,r3);
+ KEYMIX(r4,r2,r0,r3,r1,16);
+
+ /* round 29 */
+ ILINTRANS(r4,r2,r0,r3,r1);
+ I3(r4,r2,r0,r3,r1);
+ KEYMIX(r0,r2,r3,r4,r1,12);
+
+ /* round 30 */
+ ILINTRANS(r0,r2,r3,r4,r1);
+ I2(r0,r2,r3,r4,r1);
+ KEYMIX(r2,r1,r3,r4,r0,8);
+
+ /* round 31 */
+ ILINTRANS(r2,r1,r3,r4,r0);
+ I1(r2,r1,r3,r4,r0);
+ KEYMIX(r0,r2,r4,r3,r1,4);
+
+ /* round 32 */
+ ILINTRANS(r0,r2,r4,r3,r1);
+ I0(r0,r2,r4,r3,r1);
+ KEYMIX(r0,r1,r2,r3,r4,0);
+
+#ifdef BLOCK_SWAP
+ out_blk[3] = io_swap(r0); out_blk[2] = io_swap(r1);
+ out_blk[1] = io_swap(r2); out_blk[0] = io_swap(r3);
+#else
+ out_blk[0] = r0; out_blk[1] = r1; out_blk[2] = r2; out_blk[3] = r3;
+#endif
+ return 0;
+};
+
+
diff --git a/lib/libcrypto/libserpent/serpent.h b/lib/libcrypto/libserpent/serpent.h
new file mode 100644
index 000000000..6357f5bfa
--- /dev/null
+++ b/lib/libcrypto/libserpent/serpent.h
@@ -0,0 +1,17 @@
+#ifndef SERPENT_H
+#define SERPENT_H
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#define u32 u_int32_t
+#define u8 u_int8_t
+#endif
+struct serpent_context {
+ u32 keyinfo[140]; /* storage for the key schedule */
+};
+typedef struct serpent_context serpent_context;
+int serpent_set_key(serpent_context *ctx, const u8 * in_key, int key_len);
+int serpent_decrypt(serpent_context *ctx, const u8 * in_blk, u8 * out_blk);
+int serpent_encrypt(serpent_context *ctx, const u8 * in_blk, u8 * out_blk);
+#endif /* SERPENT_H */
diff --git a/lib/libcrypto/libserpent/serpent_cbc.c b/lib/libcrypto/libserpent/serpent_cbc.c
new file mode 100644
index 000000000..3b546278a
--- /dev/null
+++ b/lib/libcrypto/libserpent/serpent_cbc.c
@@ -0,0 +1,8 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#include "serpent_cbc.h"
+#include "cbc_generic.h"
+CBC_IMPL_BLK16(serpent_cbc_encrypt, serpent_context, u_int8_t *, serpent_encrypt, serpent_decrypt);
diff --git a/lib/libcrypto/libserpent/serpent_cbc.h b/lib/libcrypto/libserpent/serpent_cbc.h
new file mode 100644
index 000000000..3064fa3bc
--- /dev/null
+++ b/lib/libcrypto/libserpent/serpent_cbc.h
@@ -0,0 +1,3 @@
+/* Glue header */
+#include "serpent.h"
+int serpent_cbc_encrypt(serpent_context *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt);
diff --git a/lib/libcrypto/libserpent/test_main.c b/lib/libcrypto/libserpent/test_main.c
new file mode 100644
index 000000000..350068e60
--- /dev/null
+++ b/lib/libcrypto/libserpent/test_main.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <string.h>
+#include "serpent_cbc.h"
+#define BLOCK_SIZE 16
+#define KEY_SIZE 128 /* bits */
+#define KEY "1234567890123456"
+#define STR "hola guaso como estaisss ... 012"
+#define STRSZ (sizeof(STR)-1)
+
+#define BLKLEN BLOCK_SIZE
+#define CONTEXT_T serpent_context
+static int pretty_print(const unsigned char *buf, int count) {
+ int i=0;
+ for (;i<count;i++) printf ("%02hhx ", buf[i]);
+ putchar('\n');
+ return i;
+}
+//#define SIZE STRSZ/2
+#define SIZE STRSZ
+int main() {
+ int ret;
+ char buf0[SIZE+1], buf1[SIZE+1];
+ char IV[BLOCK_SIZE];
+ CONTEXT_T ac;
+ serpent_set_key(&ac, (void *)KEY, KEY_SIZE);
+ memset(buf0, 0, sizeof (buf0));
+ memset(buf1, 0, sizeof (buf1));
+ serpent_cbc_encrypt(&ac, STR, buf0, SIZE, IV, 1);
+ pretty_print(buf0, SIZE);
+ printf("size=%d ret=%d\n%s\n", SIZE, ret, buf0);
+ ret=serpent_cbc_encrypt(&ac, buf0, buf1, SIZE, IV, 0);
+ printf("size=%d ret=%d\n%s\n", SIZE, ret, buf1);
+ return 0;
+}
diff --git a/lib/libcrypto/libsha2/Makefile b/lib/libcrypto/libsha2/Makefile
new file mode 100644
index 000000000..cee7e6109
--- /dev/null
+++ b/lib/libcrypto/libsha2/Makefile
@@ -0,0 +1,21 @@
+CFLAGS=-O3 -fomit-frame-pointer -I../include $(EXTRA_CFLAGS)
+
+LIBOBJ := hmac_sha2.o sha2.o
+
+BLIB := libsha2.a
+
+.S.o:
+ $(CC) $(AFLAGS) -c $< -o $@
+
+$(BLIB): $(LIBOBJ)
+ /bin/rm -f $(BLIB)
+ ar cr $(BLIB) $(LIBOBJ)
+ -if test -s /bin/ranlib; then /bin/ranlib $(BLIB); \
+ else if test -s /usr/bin/ranlib; then /usr/bin/ranlib $(BLIB); \
+ else exit 0; fi; fi
+
+test: test_main.o $(BLIB)
+ $(CC) -o $@ $^
+
+clean:
+ rm -f *.[oa] core $(TARGET) test
diff --git a/lib/libcrypto/libsha2/hmac_sha2.c b/lib/libcrypto/libsha2/hmac_sha2.c
new file mode 100644
index 000000000..ad107eb62
--- /dev/null
+++ b/lib/libcrypto/libsha2/hmac_sha2.c
@@ -0,0 +1,32 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/string.h>
+#else
+#include <sys/types.h>
+#include <string.h>
+#endif
+#include "hmac_generic.h"
+#include "sha2.h"
+#include "hmac_sha2.h"
+
+void inline sha256_result(sha256_context *ctx, u_int8_t * hash, int hashlen) {
+ sha256_final(ctx);
+ memcpy(hash, &ctx->sha_out[0], hashlen);
+}
+void inline sha512_result(sha512_context *ctx, u_int8_t * hash, int hashlen) {
+ sha512_final(ctx);
+ memcpy(hash, &ctx->sha_out[0], hashlen);
+}
+HMAC_SET_KEY_IMPL (sha256_hmac_set_key,
+ sha256_hmac_context, SHA256_BLOCKSIZE,
+ sha256_init, sha256_write)
+HMAC_HASH_IMPL (sha256_hmac_hash,
+ sha256_hmac_context, sha256_context, SHA256_HASHLEN,
+ sha256_write, sha256_result)
+
+HMAC_SET_KEY_IMPL (sha512_hmac_set_key,
+ sha512_hmac_context, SHA512_BLOCKSIZE,
+ sha512_init, sha512_write)
+HMAC_HASH_IMPL (sha512_hmac_hash,
+ sha512_hmac_context, sha512_context, SHA512_HASHLEN,
+ sha512_write, sha512_result)
diff --git a/lib/libcrypto/libsha2/hmac_sha2.h b/lib/libcrypto/libsha2/hmac_sha2.h
new file mode 100644
index 000000000..b7f8c747c
--- /dev/null
+++ b/lib/libcrypto/libsha2/hmac_sha2.h
@@ -0,0 +1,17 @@
+typedef struct {
+ sha256_context ictx,octx;
+} sha256_hmac_context;
+typedef struct {
+ sha512_context ictx,octx;
+} sha512_hmac_context;
+#define SHA256_BLOCKSIZE 64
+#define SHA256_HASHLEN 32
+#define SHA384_BLOCKSIZE 128 /* XXX ok? */
+#define SHA384_HASHLEN 48
+#define SHA512_BLOCKSIZE 128
+#define SHA512_HASHLEN 64
+
+void sha256_hmac_hash(sha256_hmac_context *hctx, const u_int8_t * dat, int len, u_int8_t * hash, int hashlen);
+void sha256_hmac_set_key(sha256_hmac_context *hctx, const u_int8_t * key, int keylen);
+void sha512_hmac_hash(sha512_hmac_context *hctx, const u_int8_t * dat, int len, u_int8_t * hash, int hashlen);
+void sha512_hmac_set_key(sha512_hmac_context *hctx, const u_int8_t * key, int keylen);
diff --git a/lib/libcrypto/libsha2/sha2.c b/lib/libcrypto/libsha2/sha2.c
new file mode 100644
index 000000000..4debdad67
--- /dev/null
+++ b/lib/libcrypto/libsha2/sha2.c
@@ -0,0 +1,437 @@
+/*
+ * sha512.c
+ *
+ * Written by Jari Ruusu, April 16 2001
+ *
+ * Copyright 2001 by Jari Ruusu.
+ * Redistribution of this file is permitted under the GNU Public License.
+ */
+
+#ifdef __KERNEL__
+#include <linux/string.h>
+#include <linux/types.h>
+#else
+#include <string.h>
+#include <sys/types.h>
+#endif
+#include "sha2.h"
+
+/* Define one or more of these. If none is defined, you get all of them */
+#if !defined(SHA256_NEEDED)&&!defined(SHA512_NEEDED)&&!defined(SHA384_NEEDED)
+# define SHA256_NEEDED 1
+# define SHA512_NEEDED 1
+# define SHA384_NEEDED 1
+#endif
+
+#if defined(SHA256_NEEDED)
+static const u_int32_t sha256_hashInit[8] = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
+ 0x1f83d9ab, 0x5be0cd19
+};
+static const u_int32_t sha256_K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+ 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+#endif
+
+#if defined(SHA512_NEEDED)
+static const u_int64_t sha512_hashInit[8] = {
+ 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL,
+ 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
+};
+#endif
+
+#if defined(SHA384_NEEDED)
+static const u_int64_t sha384_hashInit[8] = {
+ 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL,
+ 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
+ 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL
+};
+#endif
+
+#if defined(SHA512_NEEDED) || defined(SHA384_NEEDED)
+static const u_int64_t sha512_K[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+ 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+ 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+ 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+ 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+ 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+ 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+ 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+ 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+ 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+ 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+ 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+ 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+ 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+#endif
+
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define R(x,y) ((y) >> (x))
+
+#if defined(SHA256_NEEDED)
+void sha256_init(sha256_context *ctx)
+{
+ memcpy(&ctx->sha_H[0], &sha256_hashInit[0], sizeof(ctx->sha_H));
+ ctx->sha_blocks = 0;
+ ctx->sha_bufCnt = 0;
+}
+
+#define S(x,y) (((y) >> (x)) | ((y) << (32 - (x))))
+#define uSig0(x) ((S(2,(x))) ^ (S(13,(x))) ^ (S(22,(x))))
+#define uSig1(x) ((S(6,(x))) ^ (S(11,(x))) ^ (S(25,(x))))
+#define lSig0(x) ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x))))
+#define lSig1(x) ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x))))
+
+static void sha256_transform(sha256_context *ctx, const unsigned char *datap)
+{
+ register int j;
+ u_int32_t a, b, c, d, e, f, g, h;
+ u_int32_t T1, T2, W[64], Wm2, Wm15;
+
+ /* read the data, big endian byte order */
+ j = 0;
+ do {
+ W[j] = (((u_int32_t)(datap[0]))<<24) | (((u_int32_t)(datap[1]))<<16) |
+ (((u_int32_t)(datap[2]))<<8 ) | ((u_int32_t)(datap[3]));
+ datap += 4;
+ } while(++j < 16);
+
+ /* initialize variables a...h */
+ a = ctx->sha_H[0];
+ b = ctx->sha_H[1];
+ c = ctx->sha_H[2];
+ d = ctx->sha_H[3];
+ e = ctx->sha_H[4];
+ f = ctx->sha_H[5];
+ g = ctx->sha_H[6];
+ h = ctx->sha_H[7];
+
+ /* apply compression function */
+ j = 0;
+ do {
+ if(j >= 16) {
+ Wm2 = W[j - 2];
+ Wm15 = W[j - 15];
+ W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
+ }
+ T1 = h + uSig1(e) + Ch(e,f,g) + sha256_K[j] + W[j];
+ T2 = uSig0(a) + Maj(a,b,c);
+ h = g; g = f; f = e;
+ e = d + T1;
+ d = c; c = b; b = a;
+ a = T1 + T2;
+ } while(++j < 64);
+
+ /* compute intermediate hash value */
+ ctx->sha_H[0] += a;
+ ctx->sha_H[1] += b;
+ ctx->sha_H[2] += c;
+ ctx->sha_H[3] += d;
+ ctx->sha_H[4] += e;
+ ctx->sha_H[5] += f;
+ ctx->sha_H[6] += g;
+ ctx->sha_H[7] += h;
+
+ ctx->sha_blocks++;
+}
+
+void sha256_write(sha256_context *ctx, const unsigned char *datap, int length)
+{
+ while(length > 0) {
+ if(!ctx->sha_bufCnt) {
+ while(length >= sizeof(ctx->sha_out)) {
+ sha256_transform(ctx, datap);
+ datap += sizeof(ctx->sha_out);
+ length -= sizeof(ctx->sha_out);
+ }
+ if(!length) return;
+ }
+ ctx->sha_out[ctx->sha_bufCnt] = *datap++;
+ length--;
+ if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) {
+ sha256_transform(ctx, &ctx->sha_out[0]);
+ ctx->sha_bufCnt = 0;
+ }
+ }
+}
+
+void sha256_final(sha256_context *ctx)
+{
+ register int j;
+ u_int64_t bitLength;
+ u_int32_t i;
+ unsigned char padByte, *datap;
+
+ bitLength = (ctx->sha_blocks << 9) | (ctx->sha_bufCnt << 3);
+ padByte = 0x80;
+ sha256_write(ctx, &padByte, 1);
+
+ /* pad extra space with zeroes */
+ padByte = 0;
+ while(ctx->sha_bufCnt != 56) {
+ sha256_write(ctx, &padByte, 1);
+ }
+
+ /* write bit length, big endian byte order */
+ ctx->sha_out[56] = bitLength >> 56;
+ ctx->sha_out[57] = bitLength >> 48;
+ ctx->sha_out[58] = bitLength >> 40;
+ ctx->sha_out[59] = bitLength >> 32;
+ ctx->sha_out[60] = bitLength >> 24;
+ ctx->sha_out[61] = bitLength >> 16;
+ ctx->sha_out[62] = bitLength >> 8;
+ ctx->sha_out[63] = bitLength;
+ sha256_transform(ctx, &ctx->sha_out[0]);
+
+ /* return results in ctx->sha_out[0...31] */
+ datap = &ctx->sha_out[0];
+ j = 0;
+ do {
+ i = ctx->sha_H[j];
+ datap[0] = i >> 24;
+ datap[1] = i >> 16;
+ datap[2] = i >> 8;
+ datap[3] = i;
+ datap += 4;
+ } while(++j < 8);
+
+ /* clear sensitive information */
+ memset(&ctx->sha_out[32], 0, sizeof(sha256_context) - 32);
+}
+
+void sha256_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+{
+ sha256_context ctx;
+
+ if(ole < 1) return;
+ memset(ob, 0, ole);
+ if(ole > 32) ole = 32;
+ sha256_init(&ctx);
+ sha256_write(&ctx, ib, ile);
+ sha256_final(&ctx);
+ memcpy(ob, &ctx.sha_out[0], ole);
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+#endif
+
+#if defined(SHA512_NEEDED)
+void sha512_init(sha512_context *ctx)
+{
+ memcpy(&ctx->sha_H[0], &sha512_hashInit[0], sizeof(ctx->sha_H));
+ ctx->sha_blocks = 0;
+ ctx->sha_blocksMSB = 0;
+ ctx->sha_bufCnt = 0;
+}
+#endif
+
+#if defined(SHA512_NEEDED) || defined(SHA384_NEEDED)
+#undef S
+#undef uSig0
+#undef uSig1
+#undef lSig0
+#undef lSig1
+#define S(x,y) (((y) >> (x)) | ((y) << (64 - (x))))
+#define uSig0(x) ((S(28,(x))) ^ (S(34,(x))) ^ (S(39,(x))))
+#define uSig1(x) ((S(14,(x))) ^ (S(18,(x))) ^ (S(41,(x))))
+#define lSig0(x) ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x))))
+#define lSig1(x) ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x))))
+
+static void sha512_transform(sha512_context *ctx, const unsigned char *datap)
+{
+ register int j;
+ u_int64_t a, b, c, d, e, f, g, h;
+ u_int64_t T1, T2, W[80], Wm2, Wm15;
+
+ /* read the data, big endian byte order */
+ j = 0;
+ do {
+ W[j] = (((u_int64_t)(datap[0]))<<56) | (((u_int64_t)(datap[1]))<<48) |
+ (((u_int64_t)(datap[2]))<<40) | (((u_int64_t)(datap[3]))<<32) |
+ (((u_int64_t)(datap[4]))<<24) | (((u_int64_t)(datap[5]))<<16) |
+ (((u_int64_t)(datap[6]))<<8 ) | ((u_int64_t)(datap[7]));
+ datap += 8;
+ } while(++j < 16);
+
+ /* initialize variables a...h */
+ a = ctx->sha_H[0];
+ b = ctx->sha_H[1];
+ c = ctx->sha_H[2];
+ d = ctx->sha_H[3];
+ e = ctx->sha_H[4];
+ f = ctx->sha_H[5];
+ g = ctx->sha_H[6];
+ h = ctx->sha_H[7];
+
+ /* apply compression function */
+ j = 0;
+ do {
+ if(j >= 16) {
+ Wm2 = W[j - 2];
+ Wm15 = W[j - 15];
+ W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
+ }
+ T1 = h + uSig1(e) + Ch(e,f,g) + sha512_K[j] + W[j];
+ T2 = uSig0(a) + Maj(a,b,c);
+ h = g; g = f; f = e;
+ e = d + T1;
+ d = c; c = b; b = a;
+ a = T1 + T2;
+ } while(++j < 80);
+
+ /* compute intermediate hash value */
+ ctx->sha_H[0] += a;
+ ctx->sha_H[1] += b;
+ ctx->sha_H[2] += c;
+ ctx->sha_H[3] += d;
+ ctx->sha_H[4] += e;
+ ctx->sha_H[5] += f;
+ ctx->sha_H[6] += g;
+ ctx->sha_H[7] += h;
+
+ ctx->sha_blocks++;
+ if(!ctx->sha_blocks) ctx->sha_blocksMSB++;
+}
+
+void sha512_write(sha512_context *ctx, const unsigned char *datap, int length)
+{
+ while(length > 0) {
+ if(!ctx->sha_bufCnt) {
+ while(length >= sizeof(ctx->sha_out)) {
+ sha512_transform(ctx, datap);
+ datap += sizeof(ctx->sha_out);
+ length -= sizeof(ctx->sha_out);
+ }
+ if(!length) return;
+ }
+ ctx->sha_out[ctx->sha_bufCnt] = *datap++;
+ length--;
+ if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) {
+ sha512_transform(ctx, &ctx->sha_out[0]);
+ ctx->sha_bufCnt = 0;
+ }
+ }
+}
+
+void sha512_final(sha512_context *ctx)
+{
+ register int j;
+ u_int64_t bitLength, bitLengthMSB;
+ u_int64_t i;
+ unsigned char padByte, *datap;
+
+ bitLength = (ctx->sha_blocks << 10) | (ctx->sha_bufCnt << 3);
+ bitLengthMSB = (ctx->sha_blocksMSB << 10) | (ctx->sha_blocks >> 54);
+ padByte = 0x80;
+ sha512_write(ctx, &padByte, 1);
+
+ /* pad extra space with zeroes */
+ padByte = 0;
+ while(ctx->sha_bufCnt != 112) {
+ sha512_write(ctx, &padByte, 1);
+ }
+
+ /* write bit length, big endian byte order */
+ ctx->sha_out[112] = bitLengthMSB >> 56;
+ ctx->sha_out[113] = bitLengthMSB >> 48;
+ ctx->sha_out[114] = bitLengthMSB >> 40;
+ ctx->sha_out[115] = bitLengthMSB >> 32;
+ ctx->sha_out[116] = bitLengthMSB >> 24;
+ ctx->sha_out[117] = bitLengthMSB >> 16;
+ ctx->sha_out[118] = bitLengthMSB >> 8;
+ ctx->sha_out[119] = bitLengthMSB;
+ ctx->sha_out[120] = bitLength >> 56;
+ ctx->sha_out[121] = bitLength >> 48;
+ ctx->sha_out[122] = bitLength >> 40;
+ ctx->sha_out[123] = bitLength >> 32;
+ ctx->sha_out[124] = bitLength >> 24;
+ ctx->sha_out[125] = bitLength >> 16;
+ ctx->sha_out[126] = bitLength >> 8;
+ ctx->sha_out[127] = bitLength;
+ sha512_transform(ctx, &ctx->sha_out[0]);
+
+ /* return results in ctx->sha_out[0...63] */
+ datap = &ctx->sha_out[0];
+ j = 0;
+ do {
+ i = ctx->sha_H[j];
+ datap[0] = i >> 56;
+ datap[1] = i >> 48;
+ datap[2] = i >> 40;
+ datap[3] = i >> 32;
+ datap[4] = i >> 24;
+ datap[5] = i >> 16;
+ datap[6] = i >> 8;
+ datap[7] = i;
+ datap += 8;
+ } while(++j < 8);
+
+ /* clear sensitive information */
+ memset(&ctx->sha_out[64], 0, sizeof(sha512_context) - 64);
+}
+
+void sha512_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+{
+ sha512_context ctx;
+
+ if(ole < 1) return;
+ memset(ob, 0, ole);
+ if(ole > 64) ole = 64;
+ sha512_init(&ctx);
+ sha512_write(&ctx, ib, ile);
+ sha512_final(&ctx);
+ memcpy(ob, &ctx.sha_out[0], ole);
+ memset(&ctx, 0, sizeof(ctx));
+}
+#endif
+
+#if defined(SHA384_NEEDED)
+void sha384_init(sha512_context *ctx)
+{
+ memcpy(&ctx->sha_H[0], &sha384_hashInit[0], sizeof(ctx->sha_H));
+ ctx->sha_blocks = 0;
+ ctx->sha_blocksMSB = 0;
+ ctx->sha_bufCnt = 0;
+}
+
+void sha384_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+{
+ sha512_context ctx;
+
+ if(ole < 1) return;
+ memset(ob, 0, ole);
+ if(ole > 48) ole = 48;
+ sha384_init(&ctx);
+ sha512_write(&ctx, ib, ile);
+ sha512_final(&ctx);
+ memcpy(ob, &ctx.sha_out[0], ole);
+ memset(&ctx, 0, sizeof(ctx));
+}
+#endif
diff --git a/lib/libcrypto/libsha2/sha2.h b/lib/libcrypto/libsha2/sha2.h
new file mode 100644
index 000000000..2dc03cfa8
--- /dev/null
+++ b/lib/libcrypto/libsha2/sha2.h
@@ -0,0 +1,52 @@
+#ifndef _SHA2_H
+#define _SHA2_H
+/*
+ * sha512.h
+ *
+ * Written by Jari Ruusu, April 16 2001
+ *
+ * Copyright 2001 by Jari Ruusu.
+ * Redistribution of this file is permitted under the GNU Public License.
+ */
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+
+typedef struct {
+ unsigned char sha_out[64]; /* results are here, bytes 0...31 */
+ u_int32_t sha_H[8];
+ u_int64_t sha_blocks;
+ int sha_bufCnt;
+} sha256_context;
+
+typedef struct {
+ unsigned char sha_out[128]; /* results are here, bytes 0...63 */
+ u_int64_t sha_H[8];
+ u_int64_t sha_blocks;
+ u_int64_t sha_blocksMSB;
+ int sha_bufCnt;
+} sha512_context;
+
+/* no sha384_context, use sha512_context */
+
+/* 256 bit hash, provides 128 bits of security against collision attacks */
+extern void sha256_init(sha256_context *);
+extern void sha256_write(sha256_context *, const unsigned char *, int);
+extern void sha256_final(sha256_context *);
+extern void sha256_hash_buffer(unsigned char *, int, unsigned char *, int);
+
+/* 512 bit hash, provides 256 bits of security against collision attacks */
+extern void sha512_init(sha512_context *);
+extern void sha512_write(sha512_context *, const unsigned char *, int);
+extern void sha512_final(sha512_context *);
+extern void sha512_hash_buffer(unsigned char *, int, unsigned char *, int);
+
+/* 384 bit hash, provides 192 bits of security against collision attacks */
+extern void sha384_init(sha512_context *);
+/* no sha384_write(), use sha512_write() */
+/* no sha384_final(), use sha512_final(), result in ctx->sha_out[0...47] */
+extern void sha384_hash_buffer(unsigned char *, int, unsigned char *, int);
+#endif /* _SHA2_H */
diff --git a/lib/libcrypto/libtwofish/Makefile b/lib/libcrypto/libtwofish/Makefile
new file mode 100644
index 000000000..714fd6115
--- /dev/null
+++ b/lib/libcrypto/libtwofish/Makefile
@@ -0,0 +1,21 @@
+CFLAGS=-O3 -fomit-frame-pointer -D__KERNEL__ -Wall $(EXTRA_CFLAGS)
+INC=-I../include
+
+LIBOBJ=twofish.o twofish_cbc.o
+BLIB=libtwofish.a
+
+.c.o:
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c $< -o $@
+
+$(BLIB): $(LIBOBJ)
+ /bin/rm -f $(BLIB)
+ ar cr $(BLIB) $(LIBOBJ)
+ -if test -s /bin/ranlib; then /bin/ranlib $(BLIB); \
+ else if test -s /usr/bin/ranlib; then /usr/bin/ranlib $(BLIB); \
+ else exit 0; fi; fi
+
+test: test_main.o $(BLIB)
+ $(CC) -o $@ $^
+
+clean:
+ rm -f *.[oa] core $(TARGET) test
diff --git a/lib/libcrypto/libtwofish/test_main.c b/lib/libcrypto/libtwofish/test_main.c
new file mode 100644
index 000000000..1e8b0db56
--- /dev/null
+++ b/lib/libcrypto/libtwofish/test_main.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <string.h>
+#include "twofish_cbc.h"
+#define BLOCK_SIZE 16
+#define KEY_SIZE 128 /* bits */
+#define KEY "1234567890123456"
+#define STR "hola guaso como estaisss ... 012"
+#define STRSZ (sizeof(STR)-1)
+
+#define BLKLEN BLOCK_SIZE
+#define CONTEXT_T twofish_context
+static int pretty_print(const unsigned char *buf, int count) {
+ int i=0;
+ for (;i<count;i++) printf ("%02hhx ", buf[i]);
+ putchar('\n');
+ return i;
+}
+//#define SIZE STRSZ/2
+#define SIZE STRSZ
+int main() {
+ int ret;
+ char buf0[SIZE+1], buf1[SIZE+1];
+ char IV[BLOCK_SIZE];
+ CONTEXT_T ac;
+ twofish_set_key(&ac, (void *)KEY, KEY_SIZE);
+ memset(buf0, 0, sizeof (buf0));
+ memset(buf1, 0, sizeof (buf1));
+ twofish_cbc_encrypt(&ac, STR, buf0, SIZE, IV, 1);
+ pretty_print(buf0, SIZE);
+ printf("size=%d ret=%d\n%s\n", SIZE, ret, buf0);
+ ret=twofish_cbc_encrypt(&ac, buf0, buf1, SIZE, IV, 0);
+ printf("size=%d ret=%d\n%s\n", SIZE, ret, buf1);
+ return 0;
+}
diff --git a/lib/libcrypto/libtwofish/twofish.c b/lib/libcrypto/libtwofish/twofish.c
new file mode 100644
index 000000000..0e01a92d2
--- /dev/null
+++ b/lib/libcrypto/libtwofish/twofish.c
@@ -0,0 +1,861 @@
+/* NOTE: This implementation has been changed from the original
+ * source. See ChangeLog for more information.
+ * Maintained by Marc Mutz <Marc@Mutz.com>
+ */
+
+/* Twofish for GPG
+ * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
+ * 256-bit key length added March 20, 1999
+ * Some modifications to reduce the text size by Werner Koch, April, 1998
+ *
+ * The original author has disclaimed all copyright interest in this
+ * code and thus putting it in the public domain.
+ *
+ * This code is a "clean room" implementation, written from the paper
+ * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
+ * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
+ * through http://www.counterpane.com/twofish.html
+ *
+ * For background information on multiplication in finite fields, used for
+ * the matrix operations in the key schedule, see the book _Contemporary
+ * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
+ * Third Edition.
+ *
+ * Only the 128- and 256-bit key sizes are supported. This code is intended
+ * for GNU C on a 32-bit system, but it should work almost anywhere. Loops
+ * are unrolled, precomputation tables are used, etc., for maximum speed at
+ * some cost in memory consumption. */
+
+#ifdef __KERNEL__
+#include <linux/init.h>
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#define u8 u_int8_t
+#define u32 u_int32_t
+#endif
+
+#if 0 /* shouldn't this be #ifdef rotl32 ?
+ * Look at wordops.h: It includes asm/wordops.h.
+ * Anyway, we have to search in the macros for rot's,
+ * since they seem to be defined in a generic way. */
+#define rotl rotl32
+#define rotr rotr32
+#else
+#define rotl generic_rotl32
+#define rotr generic_rotr32
+#endif
+
+#include "twofish.h"
+/* The large precomputed tables for the Twofish cipher (twofish.c)
+ * Taken from the same source as twofish.c
+ * Marc Mutz <Marc@Mutz.com>
+ */
+
+/* These two tables are the q0 and q1 permutations, exactly as described in
+ * the Twofish paper. */
+
+static const u8 q0[256] = {
+ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78,
+ 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
+ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30,
+ 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
+ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE,
+ 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
+ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45,
+ 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
+ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF,
+ 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
+ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED,
+ 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
+ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B,
+ 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
+ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F,
+ 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
+ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17,
+ 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
+ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68,
+ 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
+ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42,
+ 0x4A, 0x5E, 0xC1, 0xE0
+};
+
+static const u8 q1[256] = {
+ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B,
+ 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
+ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B,
+ 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
+ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54,
+ 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
+ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7,
+ 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
+ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF,
+ 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
+ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D,
+ 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
+ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21,
+ 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
+ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E,
+ 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
+ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44,
+ 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
+ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B,
+ 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
+ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56,
+ 0x55, 0x09, 0xBE, 0x91
+};
+
+/* These MDS tables are actually tables of MDS composed with q0 and q1,
+ * because it is only ever used that way and we can save some time by
+ * precomputing. Of course the main saving comes from precomputing the
+ * GF(2^8) multiplication involved in the MDS matrix multiply; by looking
+ * things up in these tables we reduce the matrix multiply to four lookups
+ * and three XORs. Semi-formally, the definition of these tables is:
+ * mds[0][i] = MDS (q1[i] 0 0 0)^T mds[1][i] = MDS (0 q0[i] 0 0)^T
+ * mds[2][i] = MDS (0 0 q1[i] 0)^T mds[3][i] = MDS (0 0 0 q0[i])^T
+ * where ^T means "transpose", the matrix multiply is performed in GF(2^8)
+ * represented as GF(2)[x]/v(x) where v(x)=x^8+x^6+x^5+x^3+1 as described
+ * by Schneier et al, and I'm casually glossing over the byte/word
+ * conversion issues. */
+
+static const u32 mds[4][256] = {
+ {0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B,
+ 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B,
+ 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32,
+ 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
+ 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA,
+ 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B,
+ 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1,
+ 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
+ 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490,
+ 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154,
+ 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0,
+ 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
+ 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228,
+ 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7,
+ 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3,
+ 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
+ 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477,
+ 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF,
+ 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C,
+ 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
+ 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA,
+ 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D,
+ 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72,
+ 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
+ 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76,
+ 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321,
+ 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39,
+ 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
+ 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D,
+ 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E,
+ 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5,
+ 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
+ 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7,
+ 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544,
+ 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E,
+ 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
+ 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A,
+ 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B,
+ 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2,
+ 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
+ 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504,
+ 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756,
+ 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91},
+
+ {0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252,
+ 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A,
+ 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020,
+ 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
+ 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444,
+ 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424,
+ 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A,
+ 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
+ 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383,
+ 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A,
+ 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9,
+ 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
+ 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1,
+ 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898,
+ 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414,
+ 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
+ 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1,
+ 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989,
+ 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5,
+ 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
+ 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E,
+ 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E,
+ 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202,
+ 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
+ 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565,
+ 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A,
+ 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808,
+ 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
+ 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A,
+ 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969,
+ 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505,
+ 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
+ 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D,
+ 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343,
+ 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF,
+ 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
+ 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F,
+ 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646,
+ 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6,
+ 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
+ 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A,
+ 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7,
+ 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8},
+
+ {0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B,
+ 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F,
+ 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A,
+ 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
+ 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70,
+ 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3,
+ 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB,
+ 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
+ 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4,
+ 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41,
+ 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C,
+ 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
+ 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622,
+ 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18,
+ 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035,
+ 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
+ 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84,
+ 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E,
+ 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F,
+ 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
+ 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558,
+ 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40,
+ 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA,
+ 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
+ 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF,
+ 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773,
+ 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D,
+ 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
+ 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C,
+ 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19,
+ 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086,
+ 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
+ 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74,
+ 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755,
+ 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691,
+ 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
+ 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4,
+ 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53,
+ 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E,
+ 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
+ 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705,
+ 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7,
+ 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF},
+
+ {0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98,
+ 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866,
+ 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643,
+ 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
+ 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9,
+ 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C,
+ 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3,
+ 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
+ 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F,
+ 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25,
+ 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF,
+ 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
+ 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4,
+ 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E,
+ 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA,
+ 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
+ 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12,
+ 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A,
+ 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D,
+ 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
+ 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A,
+ 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C,
+ 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B,
+ 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
+ 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B,
+ 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3,
+ 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE,
+ 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
+ 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85,
+ 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA,
+ 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E,
+ 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
+ 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33,
+ 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC,
+ 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718,
+ 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
+ 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8,
+ 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872,
+ 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882,
+ 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
+ 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10,
+ 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6,
+ 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8}
+};
+
+/* The exp_to_poly and poly_to_exp tables are used to perform efficient
+ * operations in GF(2^8) represented as GF(2)[x]/w(x) where
+ * w(x)=x^8+x^6+x^3+x^2+1. We care about doing that because it's part of the
+ * definition of the RS matrix in the key schedule. Elements of that field
+ * are polynomials of degree not greater than 7 and all coefficients 0 or 1,
+ * which can be represented naturally by bytes (just substitute x=2). In that
+ * form, GF(2^8) addition is the same as bitwise XOR, but GF(2^8)
+ * multiplication is inefficient without hardware support. To multiply
+ * faster, I make use of the fact x is a generator for the nonzero elements,
+ * so that every element p of GF(2)[x]/w(x) is either 0 or equal to (x)^n for
+ * some n in 0..254. Note that that caret is exponentiation in GF(2^8),
+ * *not* polynomial notation. So if I want to compute pq where p and q are
+ * in GF(2^8), I can just say:
+ * 1. if p=0 or q=0 then pq=0
+ * 2. otherwise, find m and n such that p=x^m and q=x^n
+ * 3. pq=(x^m)(x^n)=x^(m+n), so add m and n and find pq
+ * The translations in steps 2 and 3 are looked up in the tables
+ * poly_to_exp (for step 2) and exp_to_poly (for step 3). To see this
+ * in action, look at the CALC_S macro. As additional wrinkles, note that
+ * one of my operands is always a constant, so the poly_to_exp lookup on it
+ * is done in advance; I included the original values in the comments so
+ * readers can have some chance of recognizing that this *is* the RS matrix
+ * from the Twofish paper. I've only included the table entries I actually
+ * need; I never do a lookup on a variable input of zero and the biggest
+ * exponents I'll ever see are 254 (variable) and 237 (constant), so they'll
+ * never sum to more than 491. I'm repeating part of the exp_to_poly table
+ * so that I don't have to do mod-255 reduction in the exponent arithmetic.
+ * Since I know my constant operands are never zero, I only have to worry
+ * about zero values in the variable operand, and I do it with a simple
+ * conditional branch. I know conditionals are expensive, but I couldn't
+ * see a non-horrible way of avoiding them, and I did manage to group the
+ * statements so that each if covers four group multiplications. */
+
+static const u8 poly_to_exp[255] = {
+ 0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19,
+ 0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A,
+ 0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C,
+ 0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B,
+ 0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47,
+ 0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D,
+ 0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8,
+ 0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C,
+ 0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83,
+ 0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48,
+ 0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26,
+ 0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E,
+ 0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3,
+ 0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9,
+ 0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A,
+ 0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D,
+ 0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75,
+ 0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84,
+ 0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64,
+ 0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49,
+ 0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF,
+ 0x85, 0xC8, 0xA1
+};
+
+static const u8 exp_to_poly[492] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2,
+ 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03,
+ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6,
+ 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A,
+ 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63,
+ 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C,
+ 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07,
+ 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88,
+ 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12,
+ 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7,
+ 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C,
+ 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8,
+ 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25,
+ 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A,
+ 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE,
+ 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC,
+ 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E,
+ 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92,
+ 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89,
+ 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB,
+ 0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1,
+ 0x8F, 0x53, 0xA6, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D,
+ 0x9A, 0x79, 0xF2, 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC,
+ 0xF5, 0xA7, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3,
+ 0x8B, 0x5B, 0xB6, 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52,
+ 0xA4, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0,
+ 0xED, 0x97, 0x63, 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1,
+ 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A,
+ 0xF4, 0xA5, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11,
+ 0x22, 0x44, 0x88, 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51,
+ 0xA2, 0x09, 0x12, 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66,
+ 0xCC, 0xD5, 0xE7, 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB,
+ 0x1B, 0x36, 0x6C, 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19,
+ 0x32, 0x64, 0xC8, 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D,
+ 0x5A, 0xB4, 0x25, 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56,
+ 0xAC, 0x15, 0x2A, 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE,
+ 0x91, 0x6F, 0xDE, 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9,
+ 0x3F, 0x7E, 0xFC, 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE,
+ 0xB1, 0x2F, 0x5E, 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41,
+ 0x82, 0x49, 0x92, 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E,
+ 0x71, 0xE2, 0x89, 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB
+};
+
+
+/* The table constants are indices of
+ * S-box entries, preprocessed through q0 and q1. */
+static const u8 calc_sb_tbl[512] = {
+ 0xA9, 0x75, 0x67, 0xF3, 0xB3, 0xC6, 0xE8, 0xF4,
+ 0x04, 0xDB, 0xFD, 0x7B, 0xA3, 0xFB, 0x76, 0xC8,
+ 0x9A, 0x4A, 0x92, 0xD3, 0x80, 0xE6, 0x78, 0x6B,
+ 0xE4, 0x45, 0xDD, 0x7D, 0xD1, 0xE8, 0x38, 0x4B,
+ 0x0D, 0xD6, 0xC6, 0x32, 0x35, 0xD8, 0x98, 0xFD,
+ 0x18, 0x37, 0xF7, 0x71, 0xEC, 0xF1, 0x6C, 0xE1,
+ 0x43, 0x30, 0x75, 0x0F, 0x37, 0xF8, 0x26, 0x1B,
+ 0xFA, 0x87, 0x13, 0xFA, 0x94, 0x06, 0x48, 0x3F,
+ 0xF2, 0x5E, 0xD0, 0xBA, 0x8B, 0xAE, 0x30, 0x5B,
+ 0x84, 0x8A, 0x54, 0x00, 0xDF, 0xBC, 0x23, 0x9D,
+ 0x19, 0x6D, 0x5B, 0xC1, 0x3D, 0xB1, 0x59, 0x0E,
+ 0xF3, 0x80, 0xAE, 0x5D, 0xA2, 0xD2, 0x82, 0xD5,
+ 0x63, 0xA0, 0x01, 0x84, 0x83, 0x07, 0x2E, 0x14,
+ 0xD9, 0xB5, 0x51, 0x90, 0x9B, 0x2C, 0x7C, 0xA3,
+ 0xA6, 0xB2, 0xEB, 0x73, 0xA5, 0x4C, 0xBE, 0x54,
+ 0x16, 0x92, 0x0C, 0x74, 0xE3, 0x36, 0x61, 0x51,
+ 0xC0, 0x38, 0x8C, 0xB0, 0x3A, 0xBD, 0xF5, 0x5A,
+ 0x73, 0xFC, 0x2C, 0x60, 0x25, 0x62, 0x0B, 0x96,
+ 0xBB, 0x6C, 0x4E, 0x42, 0x89, 0xF7, 0x6B, 0x10,
+ 0x53, 0x7C, 0x6A, 0x28, 0xB4, 0x27, 0xF1, 0x8C,
+ 0xE1, 0x13, 0xE6, 0x95, 0xBD, 0x9C, 0x45, 0xC7,
+ 0xE2, 0x24, 0xF4, 0x46, 0xB6, 0x3B, 0x66, 0x70,
+ 0xCC, 0xCA, 0x95, 0xE3, 0x03, 0x85, 0x56, 0xCB,
+ 0xD4, 0x11, 0x1C, 0xD0, 0x1E, 0x93, 0xD7, 0xB8,
+ 0xFB, 0xA6, 0xC3, 0x83, 0x8E, 0x20, 0xB5, 0xFF,
+ 0xE9, 0x9F, 0xCF, 0x77, 0xBF, 0xC3, 0xBA, 0xCC,
+ 0xEA, 0x03, 0x77, 0x6F, 0x39, 0x08, 0xAF, 0xBF,
+ 0x33, 0x40, 0xC9, 0xE7, 0x62, 0x2B, 0x71, 0xE2,
+ 0x81, 0x79, 0x79, 0x0C, 0x09, 0xAA, 0xAD, 0x82,
+ 0x24, 0x41, 0xCD, 0x3A, 0xF9, 0xEA, 0xD8, 0xB9,
+ 0xE5, 0xE4, 0xC5, 0x9A, 0xB9, 0xA4, 0x4D, 0x97,
+ 0x44, 0x7E, 0x08, 0xDA, 0x86, 0x7A, 0xE7, 0x17,
+ 0xA1, 0x66, 0x1D, 0x94, 0xAA, 0xA1, 0xED, 0x1D,
+ 0x06, 0x3D, 0x70, 0xF0, 0xB2, 0xDE, 0xD2, 0xB3,
+ 0x41, 0x0B, 0x7B, 0x72, 0xA0, 0xA7, 0x11, 0x1C,
+ 0x31, 0xEF, 0xC2, 0xD1, 0x27, 0x53, 0x90, 0x3E,
+ 0x20, 0x8F, 0xF6, 0x33, 0x60, 0x26, 0xFF, 0x5F,
+ 0x96, 0xEC, 0x5C, 0x76, 0xB1, 0x2A, 0xAB, 0x49,
+ 0x9E, 0x81, 0x9C, 0x88, 0x52, 0xEE, 0x1B, 0x21,
+ 0x5F, 0xC4, 0x93, 0x1A, 0x0A, 0xEB, 0xEF, 0xD9,
+ 0x91, 0xC5, 0x85, 0x39, 0x49, 0x99, 0xEE, 0xCD,
+ 0x2D, 0xAD, 0x4F, 0x31, 0x8F, 0x8B, 0x3B, 0x01,
+ 0x47, 0x18, 0x87, 0x23, 0x6D, 0xDD, 0x46, 0x1F,
+ 0xD6, 0x4E, 0x3E, 0x2D, 0x69, 0xF9, 0x64, 0x48,
+ 0x2A, 0x4F, 0xCE, 0xF2, 0xCB, 0x65, 0x2F, 0x8E,
+ 0xFC, 0x78, 0x97, 0x5C, 0x05, 0x58, 0x7A, 0x19,
+ 0xAC, 0x8D, 0x7F, 0xE5, 0xD5, 0x98, 0x1A, 0x57,
+ 0x4B, 0x67, 0x0E, 0x7F, 0xA7, 0x05, 0x5A, 0x64,
+ 0x28, 0xAF, 0x14, 0x63, 0x3F, 0xB6, 0x29, 0xFE,
+ 0x88, 0xF5, 0x3C, 0xB7, 0x4C, 0x3C, 0x02, 0xA5,
+ 0xB8, 0xCE, 0xDA, 0xE9, 0xB0, 0x68, 0x17, 0x44,
+ 0x55, 0xE0, 0x1F, 0x4D, 0x8A, 0x43, 0x7D, 0x69,
+ 0x57, 0x29, 0xC7, 0x2E, 0x8D, 0xAC, 0x74, 0x15,
+ 0xB7, 0x59, 0xC4, 0xA8, 0x9F, 0x0A, 0x72, 0x9E,
+ 0x7E, 0x6E, 0x15, 0x47, 0x22, 0xDF, 0x12, 0x34,
+ 0x58, 0x35, 0x07, 0x6A, 0x99, 0xCF, 0x34, 0xDC,
+ 0x6E, 0x22, 0x50, 0xC9, 0xDE, 0xC0, 0x68, 0x9B,
+ 0x65, 0x89, 0xBC, 0xD4, 0xDB, 0xED, 0xF8, 0xAB,
+ 0xC8, 0x12, 0xA8, 0xA2, 0x2B, 0x0D, 0x40, 0x52,
+ 0xDC, 0xBB, 0xFE, 0x02, 0x32, 0x2F, 0xA4, 0xA9,
+ 0xCA, 0xD7, 0x10, 0x61, 0x21, 0x1E, 0xF0, 0xB4,
+ 0xD3, 0x50, 0x5D, 0x04, 0x0F, 0xF6, 0x00, 0xC2,
+ 0x6F, 0x16, 0x9D, 0x25, 0x36, 0x86, 0x42, 0x56,
+ 0x4A, 0x55, 0x5E, 0x09, 0xC1, 0xBE, 0xE0, 0x91
+};
+
+/* Macro to perform one column of the RS matrix multiplication. The
+ * parameters a, b, c, and d are the four bytes of output; i is the index
+ * of the key bytes, and w, x, y, and z, are the column of constants from
+ * the RS matrix, preprocessed through the poly_to_exp table. */
+
+#define CALC_S(a, b, c, d, i, w, x, y, z) \
+ if (key[i]) { \
+ tmp = poly_to_exp[key[i] - 1]; \
+ (a) ^= exp_to_poly[tmp + (w)]; \
+ (b) ^= exp_to_poly[tmp + (x)]; \
+ (c) ^= exp_to_poly[tmp + (y)]; \
+ (d) ^= exp_to_poly[tmp + (z)]; \
+ }
+
+/* Macros to calculate the key-dependent S-boxes for a 128-bit key using
+ * the S vector from CALC_S. CALC_SB_2 computes a single entry in all
+ * four S-boxes, where i is the index of the entry to compute, and a and b
+ * are the index numbers preprocessed through the q0 and q1 tables
+ * respectively. */
+
+#define CALC_SB_2(i, a, b) \
+ ctx->s[0][i] = mds[0][q0[(a) ^ sa] ^ se]; \
+ ctx->s[1][i] = mds[1][q0[(b) ^ sb] ^ sf]; \
+ ctx->s[2][i] = mds[2][q1[(a) ^ sc] ^ sg]; \
+ ctx->s[3][i] = mds[3][q1[(b) ^ sd] ^ sh]
+
+/* Macro exactly like CALC_SB_2, but for 192-bit keys. */
+
+#define CALC_SB192_2(i, a, b) \
+ ctx->s[0][i] = mds[0][q0[q0[(b) ^ sa] ^ se] ^ si]; \
+ ctx->s[1][i] = mds[1][q0[q1[(b) ^ sb] ^ sf] ^ sj]; \
+ ctx->s[2][i] = mds[2][q1[q0[(a) ^ sc] ^ sg] ^ sk]; \
+ ctx->s[3][i] = mds[3][q1[q1[(a) ^ sd] ^ sh] ^ sl];
+
+/* Macro exactly like CALC_SB_2, but for 256-bit keys. */
+
+#define CALC_SB256_2(i, a, b) \
+ ctx->s[0][i] = mds[0][q0[q0[q1[(b) ^ sa] ^ se] ^ si] ^ sm]; \
+ ctx->s[1][i] = mds[1][q0[q1[q1[(a) ^ sb] ^ sf] ^ sj] ^ sn]; \
+ ctx->s[2][i] = mds[2][q1[q0[q0[(a) ^ sc] ^ sg] ^ sk] ^ so]; \
+ ctx->s[3][i] = mds[3][q1[q1[q0[(b) ^ sd] ^ sh] ^ sl] ^ sp];
+
+/* Macros to calculate the whitening and round subkeys. CALC_K_2 computes the
+ * last two stages of the h() function for a given index (either 2i or 2i+1).
+ * a, b, c, and d are the four bytes going into the last two stages. For
+ * 128-bit keys, this is the entire h() function and a and c are the index
+ * preprocessed through q0 and q1 respectively; for longer keys they are the
+ * output of previous stages. j is the index of the first key byte to use.
+ * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2
+ * twice, doing the Psuedo-Hadamard Transform, and doing the necessary
+ * rotations. Its parameters are: a, the array to write the results into,
+ * j, the index of the first output entry, k and l, the preprocessed indices
+ * for index 2i, and m and n, the preprocessed indices for index 2i+1.
+ * CALC_K192_2 expands CALC_K_2 to handle 192-bit keys, by doing an
+ * additional lookup-and-XOR stage. The parameters a, b, c and d are the
+ * four bytes going into the last three stages. For 192-bit keys, c = d
+ * are the index preprocessed through q0, and a = b are the index
+ * preprocessed through q1; j is the index of the first key byte to use.
+ * CALC_K192 is identical to CALC_K but for using the CALC_K192_2 macro
+ * instead of CALC_K_2.
+ * CALC_K256_2 expands CALC_K192_2 to handle 256-bit keys, by doing an
+ * additional lookup-and-XOR stage. The parameters a and b are the index
+ * preprocessed through q0 and q1 respectively; j is the index of the first
+ * key byte to use. CALC_K256 is identical to CALC_K but for using the
+ * CALC_K256_2 macro instead of CALC_K_2. */
+
+#define CALC_K_2(a, b, c, d, j) \
+ mds[0][q0[a ^ key[(j) + 8]] ^ key[j]] \
+ ^ mds[1][q0[b ^ key[(j) + 9]] ^ key[(j) + 1]] \
+ ^ mds[2][q1[c ^ key[(j) + 10]] ^ key[(j) + 2]] \
+ ^ mds[3][q1[d ^ key[(j) + 11]] ^ key[(j) + 3]]
+
+#define CALC_K(a, j, k, l, m, n) \
+ x = CALC_K_2 (k, l, k, l, 0); \
+ y = CALC_K_2 (m, n, m, n, 4); \
+ y = (y << 8) + (y >> 24); \
+ x += y; y += x; ctx->a[j] = x; \
+ ctx->a[(j) + 1] = (y << 9) + (y >> 23)
+
+#define CALC_K192_2(a, b, c, d, j) \
+ CALC_K_2 (q0[a ^ key[(j) + 16]], \
+ q1[b ^ key[(j) + 17]], \
+ q0[c ^ key[(j) + 18]], \
+ q1[d ^ key[(j) + 19]], j)
+
+#define CALC_K192(a, j, k, l, m, n) \
+ x = CALC_K192_2 (l, l, k, k, 0); \
+ y = CALC_K192_2 (n, n, m, m, 4); \
+ y = (y << 8) + (y >> 24); \
+ x += y; y += x; ctx->a[j] = x; \
+ ctx->a[(j) + 1] = (y << 9) + (y >> 23)
+
+#define CALC_K256_2(a, b, j) \
+ CALC_K192_2 (q1[b ^ key[(j) + 24]], \
+ q1[a ^ key[(j) + 25]], \
+ q0[a ^ key[(j) + 26]], \
+ q0[b ^ key[(j) + 27]], j)
+
+#define CALC_K256(a, j, k, l, m, n) \
+ x = CALC_K256_2 (k, l, 0); \
+ y = CALC_K256_2 (m, n, 4); \
+ y = (y << 8) + (y >> 24); \
+ x += y; y += x; ctx->a[j] = x; \
+ ctx->a[(j) + 1] = (y << 9) + (y >> 23)
+
+/* Perform the key setup. */
+
+int twofish_set_key (TWOFISH_context *ctx,
+ const unsigned char *key, int key_len)
+{
+
+ int i, j, k;
+
+ /* Temporaries for CALC_K. */
+ u32 x, y;
+
+ /* The S vector used to key the S-boxes, split up into individual bytes.
+ * 128-bit keys use only sa through sh; 256-bit use all of them. */
+ u8 sa = 0, sb = 0, sc = 0, sd = 0, se = 0, sf = 0, sg = 0, sh = 0;
+ u8 si = 0, sj = 0, sk = 0, sl = 0, sm = 0, sn = 0, so = 0, sp = 0;
+
+ /* Temporary for CALC_S. */
+ u8 tmp;
+
+ /* Check key length. */
+ if (key_len != 16 && key_len != 24 && key_len != 32)
+ return -1; /* unsupported key length */
+
+ /* Compute the first two words of the S vector. The magic numbers are
+ * the entries of the RS matrix, preprocessed through poly_to_exp. The
+ * numbers in the comments are the original (polynomial form) matrix
+ * entries. */
+ CALC_S (sa, sb, sc, sd, 0, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+ CALC_S (sa, sb, sc, sd, 1, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+ CALC_S (sa, sb, sc, sd, 2, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+ CALC_S (sa, sb, sc, sd, 3, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+ CALC_S (sa, sb, sc, sd, 4, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+ CALC_S (sa, sb, sc, sd, 5, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+ CALC_S (sa, sb, sc, sd, 6, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+ CALC_S (sa, sb, sc, sd, 7, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+ CALC_S (se, sf, sg, sh, 8, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+ CALC_S (se, sf, sg, sh, 9, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+ CALC_S (se, sf, sg, sh, 10, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+ CALC_S (se, sf, sg, sh, 11, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+ CALC_S (se, sf, sg, sh, 12, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+ CALC_S (se, sf, sg, sh, 13, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+ CALC_S (se, sf, sg, sh, 14, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+ CALC_S (se, sf, sg, sh, 15, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+
+ if (key_len == 24 || key_len == 32) { /* 192- or 256-bit key */
+ /* Calculate the third word of the S vector */
+ CALC_S (si, sj, sk, sl, 16, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+ CALC_S (si, sj, sk, sl, 17, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+ CALC_S (si, sj, sk, sl, 18, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+ CALC_S (si, sj, sk, sl, 19, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+ CALC_S (si, sj, sk, sl, 20, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+ CALC_S (si, sj, sk, sl, 21, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+ CALC_S (si, sj, sk, sl, 22, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+ CALC_S (si, sj, sk, sl, 23, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+ }
+
+ if (key_len == 32) { /* 256-bit key */
+ /* Calculate the fourth word of the S vector */
+ CALC_S (sm, sn, so, sp, 24, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
+ CALC_S (sm, sn, so, sp, 25, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
+ CALC_S (sm, sn, so, sp, 26, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
+ CALC_S (sm, sn, so, sp, 27, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
+ CALC_S (sm, sn, so, sp, 28, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
+ CALC_S (sm, sn, so, sp, 29, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
+ CALC_S (sm, sn, so, sp, 30, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
+ CALC_S (sm, sn, so, sp, 31, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
+
+ /* Compute the S-boxes. */
+ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
+ CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
+ }
+
+ /* Calculate whitening and round subkeys. The constants are
+ * indices of subkeys, preprocessed through q0 and q1. */
+ CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
+ CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
+ CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
+ CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
+ CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
+ CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
+ CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
+ CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
+ CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
+ CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
+ CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71);
+ CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
+ CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F);
+ CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
+ CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
+ CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F);
+ CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
+ CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
+ CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00);
+ CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+ } else if (key_len == 24) { /* 192-bit key */
+ /* Compute the S-boxes. */
+ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
+ CALC_SB192_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
+ }
+
+ /* Calculate whitening and round subkeys. The constants are
+ * indices of subkeys, preprocessed through q0 and q1. */
+ CALC_K192 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
+ CALC_K192 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
+ CALC_K192 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
+ CALC_K192 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
+ CALC_K192 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
+ CALC_K192 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
+ CALC_K192 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
+ CALC_K192 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
+ CALC_K192 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
+ CALC_K192 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
+ CALC_K192 (k, 12, 0x18, 0x37, 0xF7, 0x71);
+ CALC_K192 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
+ CALC_K192 (k, 16, 0x43, 0x30, 0x75, 0x0F);
+ CALC_K192 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
+ CALC_K192 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
+ CALC_K192 (k, 22, 0x94, 0x06, 0x48, 0x3F);
+ CALC_K192 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
+ CALC_K192 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
+ CALC_K192 (k, 28, 0x84, 0x8A, 0x54, 0x00);
+ CALC_K192 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+ } else { /* 128-bit key */
+ /* Compute the S-boxes. */
+ for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
+ CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
+ }
+
+ /* Calculate whitening and round subkeys. The constants are
+ * indices of subkeys, preprocessed through q0 and q1. */
+ CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3);
+ CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
+ CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
+ CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
+ CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
+ CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B);
+ CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
+ CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
+ CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
+ CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD);
+ CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71);
+ CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
+ CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F);
+ CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B);
+ CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA);
+ CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F);
+ CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
+ CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
+ CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00);
+ CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+ }
+
+ return 0;
+}
+
+/* Macros to compute the g() function in the encryption and decryption
+ * rounds. G1 is the straight g() function; G2 includes the 8-bit
+ * rotation for the high 32-bit word. */
+
+#define G1(a) \
+ (ctx->s[0][(a) & 0xFF]) ^ (ctx->s[1][((a) >> 8) & 0xFF]) \
+ ^ (ctx->s[2][((a) >> 16) & 0xFF]) ^ (ctx->s[3][(a) >> 24])
+
+#define G2(b) \
+ (ctx->s[1][(b) & 0xFF]) ^ (ctx->s[2][((b) >> 8) & 0xFF]) \
+ ^ (ctx->s[3][((b) >> 16) & 0xFF]) ^ (ctx->s[0][(b) >> 24])
+
+/* Encryption and decryption Feistel rounds. Each one calls the two g()
+ * macros, does the PHT, and performs the XOR and the appropriate bit
+ * rotations. The parameters are the round number (used to select subkeys),
+ * and the four 32-bit chunks of the text. */
+
+#define ENCROUND(n, a, b, c, d) \
+ x = G1 (a); y = G2 (b); \
+ x += y; y += x + ctx->k[2 * (n) + 1]; \
+ (c) ^= x + ctx->k[2 * (n)]; \
+ (c) = ((c) >> 1) + ((c) << 31); \
+ (d) = (((d) << 1)+((d) >> 31)) ^ y
+
+#define DECROUND(n, a, b, c, d) \
+ x = G1 (a); y = G2 (b); \
+ x += y; y += x; \
+ (d) ^= y + ctx->k[2 * (n) + 1]; \
+ (d) = ((d) >> 1) + ((d) << 31); \
+ (c) = (((c) << 1)+((c) >> 31)); \
+ (c) ^= (x + ctx->k[2 * (n)])
+
+/* Encryption and decryption cycles; each one is simply two Feistel rounds
+ * with the 32-bit chunks re-ordered to simulate the "swap" */
+
+#define ENCCYCLE(n) \
+ ENCROUND (2 * (n), a, b, c, d); \
+ ENCROUND (2 * (n) + 1, c, d, a, b)
+
+#define DECCYCLE(n) \
+ DECROUND (2 * (n) + 1, c, d, a, b); \
+ DECROUND (2 * (n), a, b, c, d)
+
+/* Macros to convert the input and output bytes into 32-bit words,
+ * and simultaneously perform the whitening step. INPACK packs word
+ * number n into the variable named by x, using whitening subkey number m.
+ * OUTUNPACK unpacks word number n from the variable named by x, using
+ * whitening subkey number m. */
+
+#define INPACK(n, x, m) \
+ x = in[4 * (n)] ^ (in[4 * (n) + 1] << 8) \
+ ^ (in[4 * (n) + 2] << 16) ^ (in[4 * (n) + 3] << 24) ^ ctx->w[m]
+
+#define OUTUNPACK(n, x, m) \
+ x ^= ctx->w[m]; \
+ out[4 * (n)] = x; out[4 * (n) + 1] = x >> 8; \
+ out[4 * (n) + 2] = x >> 16; out[4 * (n) + 3] = x >> 24
+
+/* Encrypt one block. in and out may be the same. */
+
+int twofish_encrypt (TWOFISH_context *ctx,
+ const u8 *in, u8 *out)
+{
+ /* The four 32-bit chunks of the text. */
+ u32 a, b, c, d;
+
+ /* Temporaries used by the round function. */
+ u32 x, y;
+
+ /* Input whitening and packing. */
+ INPACK (0, a, 0);
+ INPACK (1, b, 1);
+ INPACK (2, c, 2);
+ INPACK (3, d, 3);
+
+ /* Encryption Feistel cycles. */
+ ENCCYCLE (0);
+ ENCCYCLE (1);
+ ENCCYCLE (2);
+ ENCCYCLE (3);
+ ENCCYCLE (4);
+ ENCCYCLE (5);
+ ENCCYCLE (6);
+ ENCCYCLE (7);
+
+ /* Output whitening and unpacking. */
+ OUTUNPACK (0, c, 4);
+ OUTUNPACK (1, d, 5);
+ OUTUNPACK (2, a, 6);
+ OUTUNPACK (3, b, 7);
+
+ return 0;
+}
+
+/* Decrypt one block. in and out may be the same. */
+
+int twofish_decrypt (TWOFISH_context *ctx,
+ const u8 *in, u8 *out)
+{
+ /* The four 32-bit chunks of the text. */
+ u32 a, b, c, d;
+
+ /* Temporaries used by the round function. */
+ u32 x, y;
+
+ /* Input whitening and packing. */
+ INPACK (0, c, 4);
+ INPACK (1, d, 5);
+ INPACK (2, a, 6);
+ INPACK (3, b, 7);
+
+ /* Encryption Feistel cycles. */
+ DECCYCLE (7);
+ DECCYCLE (6);
+ DECCYCLE (5);
+ DECCYCLE (4);
+ DECCYCLE (3);
+ DECCYCLE (2);
+ DECCYCLE (1);
+ DECCYCLE (0);
+
+ /* Output whitening and unpacking. */
+ OUTUNPACK (0, a, 0);
+ OUTUNPACK (1, b, 1);
+ OUTUNPACK (2, c, 2);
+ OUTUNPACK (3, d, 3);
+
+ return 0;
+}
+
+/* eof */
diff --git a/lib/libcrypto/libtwofish/twofish.h b/lib/libcrypto/libtwofish/twofish.h
new file mode 100644
index 000000000..9b289f265
--- /dev/null
+++ b/lib/libcrypto/libtwofish/twofish.h
@@ -0,0 +1,20 @@
+#ifndef TWOFISH_H
+#define TWOFISH_H
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+/* Structure for an expanded Twofish key. s contains the key-dependent
+ * S-boxes composed with the MDS matrix; w contains the eight "whitening"
+ * subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys. Note
+ * that k[i] corresponds to what the Twofish paper calls K[i+8]. */
+typedef struct {
+ u_int32_t s[4][256], w[8], k[32];
+} TWOFISH_context;
+
+typedef TWOFISH_context twofish_context;
+int twofish_set_key(twofish_context *tf_ctx, const u_int8_t * in_key, int key_len);
+int twofish_encrypt(twofish_context *tf_ctx, const u_int8_t * in, u_int8_t * out);
+int twofish_decrypt(twofish_context * tf_ctx, const u_int8_t * in, u_int8_t * out);
+#endif /* TWOFISH_H */
diff --git a/lib/libcrypto/libtwofish/twofish_cbc.c b/lib/libcrypto/libtwofish/twofish_cbc.c
new file mode 100644
index 000000000..6e5cf9025
--- /dev/null
+++ b/lib/libcrypto/libtwofish/twofish_cbc.c
@@ -0,0 +1,8 @@
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#include "twofish_cbc.h"
+#include "cbc_generic.h"
+CBC_IMPL_BLK16(twofish_cbc_encrypt, twofish_context, u_int8_t *, twofish_encrypt, twofish_decrypt);
diff --git a/lib/libcrypto/libtwofish/twofish_cbc.h b/lib/libcrypto/libtwofish/twofish_cbc.h
new file mode 100644
index 000000000..9fdea3526
--- /dev/null
+++ b/lib/libcrypto/libtwofish/twofish_cbc.h
@@ -0,0 +1,3 @@
+/* Glue header */
+#include "twofish.h"
+int twofish_cbc_encrypt(twofish_context *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t* iv, int encrypt);
diff --git a/lib/libcrypto/perlasm/LICENSE b/lib/libcrypto/perlasm/LICENSE
new file mode 100644
index 000000000..3fd259ac3
--- /dev/null
+++ b/lib/libcrypto/perlasm/LICENSE
@@ -0,0 +1,127 @@
+
+ LICENSE ISSUES
+ ==============
+
+ The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
+ the OpenSSL License and the original SSLeay license apply to the toolkit.
+ See below for the actual license texts. Actually both licenses are BSD-style
+ Open Source licenses. In case of any license issues related to OpenSSL
+ please contact openssl-core@openssl.org.
+
+ OpenSSL License
+ ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
diff --git a/lib/libcrypto/perlasm/alpha.pl b/lib/libcrypto/perlasm/alpha.pl
new file mode 100644
index 000000000..fe69ca5a3
--- /dev/null
+++ b/lib/libcrypto/perlasm/alpha.pl
@@ -0,0 +1,434 @@
+#!/usr/bin/perl
+
+package alpha;
+use Carp qw(croak cluck);
+
+$label="100";
+
+$n_debug=0;
+$smear_regs=1;
+$reg_alloc=1;
+
+$align="3";
+$com_start="#";
+
+sub main'asm_init_output { @out=(); }
+sub main'asm_get_output { return(@out); }
+sub main'get_labels { return(@labels); }
+sub main'external_label { push(@labels,@_); }
+
+# General registers
+
+%regs=( 'r0', '$0',
+ 'r1', '$1',
+ 'r2', '$2',
+ 'r3', '$3',
+ 'r4', '$4',
+ 'r5', '$5',
+ 'r6', '$6',
+ 'r7', '$7',
+ 'r8', '$8',
+ 'r9', '$22',
+ 'r10', '$23',
+ 'r11', '$24',
+ 'r12', '$25',
+ 'r13', '$27',
+ 'r14', '$28',
+ 'r15', '$21', # argc == 5
+ 'r16', '$20', # argc == 4
+ 'r17', '$19', # argc == 3
+ 'r18', '$18', # argc == 2
+ 'r19', '$17', # argc == 1
+ 'r20', '$16', # argc == 0
+ 'r21', '$9', # save 0
+ 'r22', '$10', # save 1
+ 'r23', '$11', # save 2
+ 'r24', '$12', # save 3
+ 'r25', '$13', # save 4
+ 'r26', '$14', # save 5
+
+ 'a0', '$16',
+ 'a1', '$17',
+ 'a2', '$18',
+ 'a3', '$19',
+ 'a4', '$20',
+ 'a5', '$21',
+
+ 's0', '$9',
+ 's1', '$10',
+ 's2', '$11',
+ 's3', '$12',
+ 's4', '$13',
+ 's5', '$14',
+ 'zero', '$31',
+ 'sp', '$30',
+ );
+
+$main'reg_s0="r21";
+$main'reg_s1="r22";
+$main'reg_s2="r23";
+$main'reg_s3="r24";
+$main'reg_s4="r25";
+$main'reg_s5="r26";
+
+@reg=( '$0', '$1' ,'$2' ,'$3' ,'$4' ,'$5' ,'$6' ,'$7' ,'$8',
+ '$22','$23','$24','$25','$20','$21','$27','$28');
+
+
+sub main'sub { &out3("subq",@_); }
+sub main'add { &out3("addq",@_); }
+sub main'mov { &out3("bis",$_[0],$_[0],$_[1]); }
+sub main'or { &out3("bis",@_); }
+sub main'bis { &out3("bis",@_); }
+sub main'br { &out1("br",@_); }
+sub main'ld { &out2("ldq",@_); }
+sub main'st { &out2("stq",@_); }
+sub main'cmpult { &out3("cmpult",@_); }
+sub main'cmplt { &out3("cmplt",@_); }
+sub main'bgt { &out2("bgt",@_); }
+sub main'ble { &out2("ble",@_); }
+sub main'blt { &out2("blt",@_); }
+sub main'mul { &out3("mulq",@_); }
+sub main'muh { &out3("umulh",@_); }
+
+$main'QWS=8;
+
+sub main'asm_add
+ {
+ push(@out,@_);
+ }
+
+sub main'asm_finish
+ {
+ &main'file_end();
+ print &main'asm_get_output();
+ }
+
+sub main'asm_init
+ {
+ ($type,$fn)=@_;
+ $filename=$fn;
+
+ &main'asm_init_output();
+ &main'comment("Don't even think of reading this code");
+ &main'comment("It was automatically generated by $filename");
+ &main'comment("Which is a perl program used to generate the alpha assember.");
+ &main'comment("eric <eay\@cryptsoft.com>");
+ &main'comment("");
+
+ $filename =~ s/\.pl$//;
+ &main'file($filename);
+ }
+
+sub conv
+ {
+ local($r)=@_;
+ local($v);
+
+ return($regs{$r}) if defined($regs{$r});
+ return($r);
+ }
+
+sub main'QWPw
+ {
+ local($off,$reg)=@_;
+
+ return(&main'QWP($off*8,$reg));
+ }
+
+sub main'QWP
+ {
+ local($off,$reg)=@_;
+
+ $ret="$off(".&conv($reg).")";
+ return($ret);
+ }
+
+sub out3
+ {
+ local($name,$p1,$p2,$p3)=@_;
+
+ $p1=&conv($p1);
+ $p2=&conv($p2);
+ $p3=&conv($p3);
+ push(@out,"\t$name\t");
+ $l=length($p1)+1;
+ push(@out,$p1.",");
+ $ll=3-($l+9)/8;
+ $tmp1=sprintf("\t" x $ll);
+ push(@out,$tmp1);
+
+ $l=length($p2)+1;
+ push(@out,$p2.",");
+ $ll=3-($l+9)/8;
+ $tmp1=sprintf("\t" x $ll);
+ push(@out,$tmp1);
+
+ push(@out,&conv($p3)."\n");
+ }
+
+sub out2
+ {
+ local($name,$p1,$p2,$p3)=@_;
+
+ $p1=&conv($p1);
+ $p2=&conv($p2);
+ push(@out,"\t$name\t");
+ $l=length($p1)+1;
+ push(@out,$p1.",");
+ $ll=3-($l+9)/8;
+ $tmp1=sprintf("\t" x $ll);
+ push(@out,$tmp1);
+
+ push(@out,&conv($p2)."\n");
+ }
+
+sub out1
+ {
+ local($name,$p1)=@_;
+
+ $p1=&conv($p1);
+ push(@out,"\t$name\t".$p1."\n");
+ }
+
+sub out0
+ {
+ push(@out,"\t$_[0]\n");
+ }
+
+sub main'file
+ {
+ local($file)=@_;
+
+ local($tmp)=<<"EOF";
+ # DEC Alpha assember
+ # Generated from perl scripts contains in SSLeay
+ .file 1 "$file.s"
+ .set noat
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'function_begin
+ {
+ local($func)=@_;
+
+print STDERR "$func\n";
+ local($tmp)=<<"EOF";
+ .text
+ .align $align
+ .globl $func
+ .ent $func
+${func}:
+${func}..ng:
+ .frame \$30,0,\$26,0
+ .prologue 0
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ }
+
+sub main'function_end
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ ret \$31,(\$26),1
+ .end $func
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main'function_end_A
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ ret \$31,(\$26),1
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'function_end_B
+ {
+ local($func)=@_;
+
+ $func=$under.$func;
+
+ push(@out,"\t.end $func\n");
+ $stack=0;
+ %label=();
+ }
+
+sub main'wparam
+ {
+ local($num)=@_;
+
+ if ($num < 6)
+ {
+ $num=20-$num;
+ return("r$num");
+ }
+ else
+ { return(&main'QWP($stack+$num*8,"sp")); }
+ }
+
+sub main'stack_push
+ {
+ local($num)=@_;
+ $stack+=$num*8;
+ &main'sub("sp",$num*8,"sp");
+ }
+
+sub main'stack_pop
+ {
+ local($num)=@_;
+ $stack-=$num*8;
+ &main'add("sp",$num*8,"sp");
+ }
+
+sub main'swtmp
+ {
+ return(&main'QWP(($_[0])*8,"sp"));
+ }
+
+# Should use swtmp, which is above sp. Linix can trash the stack above esp
+#sub main'wtmp
+# {
+# local($num)=@_;
+#
+# return(&main'QWP(-($num+1)*4,"esp","",0));
+# }
+
+sub main'comment
+ {
+ foreach (@_)
+ {
+ if (/^\s*$/)
+ { push(@out,"\n"); }
+ else
+ { push(@out,"\t$com_start $_ $com_end\n"); }
+ }
+ }
+
+sub main'label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=$label;
+ $label++;
+ }
+ return('$'.$label{$_[0]});
+ }
+
+sub main'set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=$label;
+ $label++;
+ }
+# push(@out,".align $align\n") if ($_[1] != 0);
+ push(@out,'$'."$label{$_[0]}:\n");
+ }
+
+sub main'file_end
+ {
+ }
+
+sub main'data_word
+ {
+ push(@out,"\t.long $_[0]\n");
+ }
+
+@pool_free=();
+@pool_taken=();
+$curr_num=0;
+$max=0;
+
+sub main'init_pool
+ {
+ local($args)=@_;
+ local($i);
+
+ @pool_free=();
+ for ($i=(14+(6-$args)); $i >= 0; $i--)
+ {
+ push(@pool_free,"r$i");
+ }
+ print STDERR "START :register pool:@pool_free\n";
+ $curr_num=$max=0;
+ }
+
+sub main'fin_pool
+ {
+ printf STDERR "END %2d:register pool:@pool_free\n",$max;
+ }
+
+sub main'GR
+ {
+ local($r)=@_;
+ local($i,@n,$_);
+
+ foreach (@pool_free)
+ {
+ if ($r ne $_)
+ { push(@n,$_); }
+ else
+ {
+ $curr_num++;
+ $max=$curr_num if ($curr_num > $max);
+ }
+ }
+ @pool_free=@n;
+print STDERR "GR:@pool_free\n" if $reg_alloc;
+ return(@_);
+ }
+
+sub main'NR
+ {
+ local($num)=@_;
+ local(@ret);
+
+ $num=1 if $num == 0;
+ ($#pool_free >= ($num-1)) || croak "out of registers: want $num, have @pool_free";
+ while ($num > 0)
+ {
+ push(@ret,pop @pool_free);
+ $curr_num++;
+ $max=$curr_num if ($curr_num > $max);
+ $num--
+ }
+ print STDERR "nr @ret\n" if $n_debug;
+print STDERR "NR:@pool_free\n" if $reg_alloc;
+ return(@ret);
+
+ }
+
+sub main'FR
+ {
+ local(@r)=@_;
+ local(@a,$v,$w);
+
+ print STDERR "fr @r\n" if $n_debug;
+# cluck "fr @r";
+ for $w (@pool_free)
+ {
+ foreach $v (@r)
+ {
+ croak "double register free of $v (@pool_free)" if $w eq $v;
+ }
+ }
+ foreach $v (@r)
+ {
+ croak "bad argument to FR" if ($v !~ /^r\d+$/);
+ if ($smear_regs)
+ { unshift(@pool_free,$v); }
+ else { push(@pool_free,$v); }
+ $curr_num--;
+ }
+print STDERR "FR:@pool_free\n" if $reg_alloc;
+ }
+1;
diff --git a/lib/libcrypto/perlasm/cbc.pl b/lib/libcrypto/perlasm/cbc.pl
new file mode 100644
index 000000000..278930579
--- /dev/null
+++ b/lib/libcrypto/perlasm/cbc.pl
@@ -0,0 +1,342 @@
+#!/usr/bin/perl
+
+# void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
+# des_cblock (*input);
+# des_cblock (*output);
+# long length;
+# des_key_schedule schedule;
+# des_cblock (*ivec);
+# int enc;
+#
+# calls
+# des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+#
+
+#&cbc("des_ncbc_encrypt","des_encrypt",0);
+#&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",
+# 1,4,5,3,5,-1);
+#&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",
+# 0,4,5,3,5,-1);
+#&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",
+# 0,6,7,3,4,5);
+#
+# When doing a cipher that needs bigendian order,
+# for encrypt, the iv is kept in bigendian form,
+# while for decrypt, it is kept in little endian.
+sub cbc
+ {
+ local($name,$enc_func,$dec_func,$swap,$iv_off,$enc_off,$p1,$p2,$p3)=@_;
+ # name is the function name
+ # enc_func and dec_func and the functions to call for encrypt/decrypt
+ # swap is true if byte order needs to be reversed
+ # iv_off is parameter number for the iv
+ # enc_off is parameter number for the encrypt/decrypt flag
+ # p1,p2,p3 are the offsets for parameters to be passed to the
+ # underlying calls.
+
+ &function_begin_B($name,"");
+ &comment("");
+
+ $in="esi";
+ $out="edi";
+ $count="ebp";
+
+ &push("ebp");
+ &push("ebx");
+ &push("esi");
+ &push("edi");
+
+ $data_off=4;
+ $data_off+=4 if ($p1 > 0);
+ $data_off+=4 if ($p2 > 0);
+ $data_off+=4 if ($p3 > 0);
+
+ &mov($count, &wparam(2)); # length
+
+ &comment("getting iv ptr from parameter $iv_off");
+ &mov("ebx", &wparam($iv_off)); # Get iv ptr
+
+ &mov($in, &DWP(0,"ebx","",0));# iv[0]
+ &mov($out, &DWP(4,"ebx","",0));# iv[1]
+
+ &push($out);
+ &push($in);
+ &push($out); # used in decrypt for iv[1]
+ &push($in); # used in decrypt for iv[0]
+
+ &mov("ebx", "esp"); # This is the address of tin[2]
+
+ &mov($in, &wparam(0)); # in
+ &mov($out, &wparam(1)); # out
+
+ # We have loaded them all, how lets push things
+ &comment("getting encrypt flag from parameter $enc_off");
+ &mov("ecx", &wparam($enc_off)); # Get enc flag
+ if ($p3 > 0)
+ {
+ &comment("get and push parameter $p3");
+ if ($enc_off != $p3)
+ { &mov("eax", &wparam($p3)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ if ($p2 > 0)
+ {
+ &comment("get and push parameter $p2");
+ if ($enc_off != $p2)
+ { &mov("eax", &wparam($p2)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ if ($p1 > 0)
+ {
+ &comment("get and push parameter $p1");
+ if ($enc_off != $p1)
+ { &mov("eax", &wparam($p1)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ &push("ebx"); # push data/iv
+
+ &cmp("ecx",0);
+ &jz(&label("decrypt"));
+
+ &and($count,0xfffffff8);
+ &mov("eax", &DWP($data_off,"esp","",0)); # load iv[0]
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); # load iv[1]
+
+ &jz(&label("encrypt_finish"));
+
+ #############################################################
+
+ &set_label("encrypt_loop");
+ # encrypt start
+ # "eax" and "ebx" hold iv (or the last cipher text)
+
+ &mov("ecx", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("edx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &xor("eax", "ecx");
+ &xor("ebx", "edx");
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($enc_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP(0,$out,"",0),"eax");
+ &mov(&DWP(4,$out,"",0),"ebx");
+
+ # eax and ebx are the next iv.
+
+ &add($in, 8);
+ &add($out, 8);
+
+ &sub($count, 8);
+ &jnz(&label("encrypt_loop"));
+
+###################################################################3
+ &set_label("encrypt_finish");
+ &mov($count, &wparam(2)); # length
+ &and($count, 7);
+ &jz(&label("finish"));
+ &xor("ecx","ecx");
+ &xor("edx","edx");
+ &mov($count,&DWP(&label("cbc_enc_jmp_table"),"",$count,4));
+ &jmp_ptr($count);
+
+&set_label("ej7");
+ &xor("edx", "edx") if $ppro; # ppro friendly
+ &movb(&HB("edx"), &BP(6,$in,"",0));
+ &shl("edx",8);
+&set_label("ej6");
+ &movb(&HB("edx"), &BP(5,$in,"",0));
+&set_label("ej5");
+ &movb(&LB("edx"), &BP(4,$in,"",0));
+&set_label("ej4");
+ &mov("ecx", &DWP(0,$in,"",0));
+ &jmp(&label("ejend"));
+&set_label("ej3");
+ &movb(&HB("ecx"), &BP(2,$in,"",0));
+ &xor("ecx", "ecx") if $ppro; # ppro friendly
+ &shl("ecx",8);
+&set_label("ej2");
+ &movb(&HB("ecx"), &BP(1,$in,"",0));
+&set_label("ej1");
+ &movb(&LB("ecx"), &BP(0,$in,"",0));
+&set_label("ejend");
+
+ &xor("eax", "ecx");
+ &xor("ebx", "edx");
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($enc_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP(0,$out,"",0),"eax");
+ &mov(&DWP(4,$out,"",0),"ebx");
+
+ &jmp(&label("finish"));
+
+ #############################################################
+ #############################################################
+ &set_label("decrypt",1);
+ # decrypt start
+ &and($count,0xfffffff8);
+ # The next 2 instructions are only for if the jz is taken
+ &mov("eax", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("ebx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+ &jz(&label("decrypt_finish"));
+
+ &set_label("decrypt_loop");
+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($dec_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+
+ &xor("ecx", "eax");
+ &xor("edx", "ebx");
+
+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
+
+ &mov(&DWP(0,$out,"",0),"ecx");
+ &mov(&DWP(4,$out,"",0),"edx");
+
+ &mov(&DWP($data_off+8,"esp","",0), "eax"); # save iv
+ &mov(&DWP($data_off+12,"esp","",0), "ebx"); #
+
+ &add($in, 8);
+ &add($out, 8);
+
+ &sub($count, 8);
+ &jnz(&label("decrypt_loop"));
+############################ ENDIT #######################3
+ &set_label("decrypt_finish");
+ &mov($count, &wparam(2)); # length
+ &and($count, 7);
+ &jz(&label("finish"));
+
+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($dec_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+
+ &xor("ecx", "eax");
+ &xor("edx", "ebx");
+
+ # this is for when we exit
+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
+
+&set_label("dj7");
+ &rotr("edx", 16);
+ &movb(&BP(6,$out,"",0), &LB("edx"));
+ &shr("edx",16);
+&set_label("dj6");
+ &movb(&BP(5,$out,"",0), &HB("edx"));
+&set_label("dj5");
+ &movb(&BP(4,$out,"",0), &LB("edx"));
+&set_label("dj4");
+ &mov(&DWP(0,$out,"",0), "ecx");
+ &jmp(&label("djend"));
+&set_label("dj3");
+ &rotr("ecx", 16);
+ &movb(&BP(2,$out,"",0), &LB("ecx"));
+ &shl("ecx",16);
+&set_label("dj2");
+ &movb(&BP(1,$in,"",0), &HB("ecx"));
+&set_label("dj1");
+ &movb(&BP(0,$in,"",0), &LB("ecx"));
+&set_label("djend");
+
+ # final iv is still in eax:ebx
+ &jmp(&label("finish"));
+
+
+############################ FINISH #######################3
+ &set_label("finish",1);
+ &mov("ecx", &wparam($iv_off)); # Get iv ptr
+
+ #################################################
+ $total=16+4;
+ $total+=4 if ($p1 > 0);
+ $total+=4 if ($p2 > 0);
+ $total+=4 if ($p3 > 0);
+ &add("esp",$total);
+
+ &mov(&DWP(0,"ecx","",0), "eax"); # save iv
+ &mov(&DWP(4,"ecx","",0), "ebx"); # save iv
+
+ &function_end_A($name);
+
+ &set_label("cbc_enc_jmp_table",1);
+ &data_word("0");
+ &data_word(&label("ej1"));
+ &data_word(&label("ej2"));
+ &data_word(&label("ej3"));
+ &data_word(&label("ej4"));
+ &data_word(&label("ej5"));
+ &data_word(&label("ej6"));
+ &data_word(&label("ej7"));
+ &set_label("cbc_dec_jmp_table",1);
+ &data_word("0");
+ &data_word(&label("dj1"));
+ &data_word(&label("dj2"));
+ &data_word(&label("dj3"));
+ &data_word(&label("dj4"));
+ &data_word(&label("dj5"));
+ &data_word(&label("dj6"));
+ &data_word(&label("dj7"));
+
+ &function_end_B($name);
+
+ }
+
+1;
diff --git a/lib/libcrypto/perlasm/readme b/lib/libcrypto/perlasm/readme
new file mode 100644
index 000000000..f02bbee75
--- /dev/null
+++ b/lib/libcrypto/perlasm/readme
@@ -0,0 +1,124 @@
+The perl scripts in this directory are my 'hack' to generate
+multiple different assembler formats via the one origional script.
+
+The way to use this library is to start with adding the path to this directory
+and then include it.
+
+push(@INC,"perlasm","../../perlasm");
+require "x86asm.pl";
+
+The first thing we do is setup the file and type of assember
+
+&asm_init($ARGV[0],$0);
+
+The first argument is the 'type'. Currently
+'cpp', 'sol', 'a.out', 'elf' or 'win32'.
+Argument 2 is the file name.
+
+The reciprocal function is
+&asm_finish() which should be called at the end.
+
+There are 2 main 'packages'. x86ms.pl, which is the microsoft assembler,
+and x86unix.pl which is the unix (gas) version.
+
+Functions of interest are:
+&external_label("des_SPtrans"); declare and external variable
+&LB(reg); Low byte for a register
+&HB(reg); High byte for a register
+&BP(off,base,index,scale) Byte pointer addressing
+&DWP(off,base,index,scale) Word pointer addressing
+&stack_push(num) Basically a 'sub esp, num*4' with extra
+&stack_pop(num) inverse of stack_push
+&function_begin(name,extra) Start a function with pushing of
+ edi, esi, ebx and ebp. extra is extra win32
+ external info that may be required.
+&function_begin_B(name,extra) Same as norma function_begin but no pushing.
+&function_end(name) Call at end of function.
+&function_end_A(name) Standard pop and ret, for use inside functions
+&function_end_B(name) Call at end but with poping or 'ret'.
+&swtmp(num) Address on stack temp word.
+&wparam(num) Parameter number num, that was push
+ in C convention. This all works over pushes
+ and pops.
+&comment("hello there") Put in a comment.
+&label("loop") Refer to a label, normally a jmp target.
+&set_label("loop") Set a label at this point.
+&data_word(word) Put in a word of data.
+
+So how does this all hold together? Given
+
+int calc(int len, int *data)
+ {
+ int i,j=0;
+
+ for (i=0; i<len; i++)
+ {
+ j+=other(data[i]);
+ }
+ }
+
+So a very simple version of this function could be coded as
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+
+ &asm_init($ARGV[0],"cacl.pl");
+
+ &external_label("other");
+
+ $tmp1= "eax";
+ $j= "edi";
+ $data= "esi";
+ $i= "ebp";
+
+ &comment("a simple function");
+ &function_begin("calc");
+ &mov( $data, &wparam(1)); # data
+ &xor( $j, $j);
+ &xor( $i, $i);
+
+ &set_label("loop");
+ &cmp( $i, &wparam(0));
+ &jge( &label("end"));
+
+ &mov( $tmp1, &DWP(0,$data,$i,4));
+ &push( $tmp1);
+ &call( "other");
+ &add( $j, "eax");
+ &pop( $tmp1);
+ &inc( $i);
+ &jmp( &label("loop"));
+
+ &set_label("end");
+ &mov( "eax", $j);
+
+ &function_end("calc");
+
+ &asm_finish();
+
+The above example is very very unoptimised but gives an idea of how
+things work.
+
+There is also a cbc mode function generator in cbc.pl
+
+&cbc( $name,
+ $encrypt_function_name,
+ $decrypt_function_name,
+ $true_if_byte_swap_needed,
+ $parameter_number_for_iv,
+ $parameter_number_for_encrypt_flag,
+ $first_parameter_to_pass,
+ $second_parameter_to_pass,
+ $third_parameter_to_pass);
+
+So for example, given
+void BF_encrypt(BF_LONG *data,BF_KEY *key);
+void BF_decrypt(BF_LONG *data,BF_KEY *key);
+void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length,
+ BF_KEY *ks, unsigned char *iv, int enc);
+
+&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",1,4,5,3,-1,-1);
+
+&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",0,4,5,3,5,-1);
+&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",0,6,7,3,4,5);
+
diff --git a/lib/libcrypto/perlasm/version b/lib/libcrypto/perlasm/version
new file mode 100644
index 000000000..5e62822b4
--- /dev/null
+++ b/lib/libcrypto/perlasm/version
@@ -0,0 +1,5 @@
+version,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
+
+This version of perlasm was copied from the openssl 0.9.6c distribution
+
+The license applying to it is enclose in the LICENSE file
diff --git a/lib/libcrypto/perlasm/x86asm.pl b/lib/libcrypto/perlasm/x86asm.pl
new file mode 100644
index 000000000..8af0fd17f
--- /dev/null
+++ b/lib/libcrypto/perlasm/x86asm.pl
@@ -0,0 +1,118 @@
+#!/usr/bin/perl
+
+# require 'x86asm.pl';
+# &asm_init("cpp","des-586.pl");
+# XXX
+# XXX
+# main'asm_finish
+
+sub main'asm_finish
+ {
+ &file_end();
+ &asm_finish_cpp() if $cpp;
+ print &asm_get_output();
+ }
+
+sub main'asm_init
+ {
+ ($type,$fn,$i386)=@_;
+ $filename=$fn;
+
+ $cpp=$sol=$aout=$win32=$gaswin=0;
+ if ( ($type eq "elf"))
+ { require "x86unix.pl"; }
+ elsif ( ($type eq "a.out"))
+ { $aout=1; require "x86unix.pl"; }
+ elsif ( ($type eq "gaswin"))
+ { $gaswin=1; $aout=1; require "x86unix.pl"; }
+ elsif ( ($type eq "sol"))
+ { $sol=1; require "x86unix.pl"; }
+ elsif ( ($type eq "cpp"))
+ { $cpp=1; require "x86unix.pl"; }
+ elsif ( ($type eq "win32"))
+ { $win32=1; require "x86ms.pl"; }
+ elsif ( ($type eq "win32n"))
+ { $win32=1; require "x86nasm.pl"; }
+ else
+ {
+ print STDERR <<"EOF";
+Pick one target type from
+ elf - linux, FreeBSD etc
+ a.out - old linux
+ sol - x86 solaris
+ cpp - format so x86unix.cpp can be used
+ win32 - Windows 95/Windows NT
+ win32n - Windows 95/Windows NT NASM format
+EOF
+ exit(1);
+ }
+
+ &asm_init_output();
+
+&comment("Don't even think of reading this code");
+&comment("It was automatically generated by $filename");
+&comment("Which is a perl program used to generate the x86 assember for");
+&comment("any of elf, a.out, BSDI, Win32, gaswin (for GNU as on Win32) or Solaris");
+&comment("eric <eay\@cryptsoft.com>");
+&comment("");
+
+ $filename =~ s/\.pl$//;
+ &file($filename);
+ }
+
+sub asm_finish_cpp
+ {
+ return unless $cpp;
+
+ local($tmp,$i);
+ foreach $i (&get_labels())
+ {
+ $tmp.="#define $i _$i\n";
+ }
+ print <<"EOF";
+/* Run the C pre-processor over this file with one of the following defined
+ * ELF - elf object files,
+ * OUT - a.out object files,
+ * BSDI - BSDI style a.out object files
+ * SOL - Solaris style elf
+ */
+
+#define TYPE(a,b) .type a,b
+#define SIZE(a,b) .size a,b
+
+#if defined(OUT) || (defined(BSDI) && !defined(ELF))
+$tmp
+#endif
+
+#ifdef OUT
+#define OK 1
+#define ALIGN 4
+#endif
+
+#if defined(BSDI) && !defined(ELF)
+#define OK 1
+#define ALIGN 4
+#undef SIZE
+#undef TYPE
+#define SIZE(a,b)
+#define TYPE(a,b)
+#endif
+
+#if defined(ELF) || defined(SOL)
+#define OK 1
+#define ALIGN 16
+#endif
+
+#ifndef OK
+You need to define one of
+ELF - elf systems - linux-elf, NetBSD and DG-UX
+OUT - a.out systems - linux-a.out and FreeBSD
+SOL - solaris systems, which are elf with strange comment lines
+BSDI - a.out with a very primative version of as.
+#endif
+
+/* Let the Assembler begin :-) */
+EOF
+ }
+
+1;
diff --git a/lib/libcrypto/perlasm/x86ms.pl b/lib/libcrypto/perlasm/x86ms.pl
new file mode 100644
index 000000000..c6212f434
--- /dev/null
+++ b/lib/libcrypto/perlasm/x86ms.pl
@@ -0,0 +1,365 @@
+#!/usr/bin/perl
+
+package x86ms;
+
+$label="L000";
+
+%lb=( 'eax', 'al',
+ 'ebx', 'bl',
+ 'ecx', 'cl',
+ 'edx', 'dl',
+ 'ax', 'al',
+ 'bx', 'bl',
+ 'cx', 'cl',
+ 'dx', 'dl',
+ );
+
+%hb=( 'eax', 'ah',
+ 'ebx', 'bh',
+ 'ecx', 'ch',
+ 'edx', 'dh',
+ 'ax', 'ah',
+ 'bx', 'bh',
+ 'cx', 'ch',
+ 'dx', 'dh',
+ );
+
+sub main'asm_init_output { @out=(); }
+sub main'asm_get_output { return(@out); }
+sub main'get_labels { return(@labels); }
+sub main'external_label { push(@labels,@_); }
+
+sub main'LB
+ {
+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
+ return($lb{$_[0]});
+ }
+
+sub main'HB
+ {
+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
+ return($hb{$_[0]});
+ }
+
+sub main'BP
+ {
+ &get_mem("BYTE",@_);
+ }
+
+sub main'DWP
+ {
+ &get_mem("DWORD",@_);
+ }
+
+sub main'BC
+ {
+ return @_;
+ }
+
+sub main'DWC
+ {
+ return @_;
+ }
+
+sub main'stack_push
+ {
+ local($num)=@_;
+ $stack+=$num*4;
+ &main'sub("esp",$num*4);
+ }
+
+sub main'stack_pop
+ {
+ local($num)=@_;
+ $stack-=$num*4;
+ &main'add("esp",$num*4);
+ }
+
+sub get_mem
+ {
+ local($size,$addr,$reg1,$reg2,$idx)=@_;
+ local($t,$post);
+ local($ret)="$size PTR ";
+
+ $addr =~ s/^\s+//;
+ if ($addr =~ /^(.+)\+(.+)$/)
+ {
+ $reg2=&conv($1);
+ $addr="_$2";
+ }
+ elsif ($addr =~ /^[_a-zA-Z]/)
+ {
+ $addr="_$addr";
+ }
+
+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
+ if (($addr ne "") && ($addr ne 0))
+ {
+ if ($addr !~ /^-/)
+ { $ret.=$addr; }
+ else { $post=$addr; }
+ }
+ if ($reg2 ne "")
+ {
+ $t="";
+ $t="*$idx" if ($idx != 0);
+ $reg1="+".$reg1 if ("$reg1$post" ne "");
+ $ret.="[$reg2$t$reg1$post]";
+ }
+ else
+ {
+ $ret.="[$reg1$post]"
+ }
+ return($ret);
+ }
+
+sub main'mov { &out2("mov",@_); }
+sub main'movb { &out2("mov",@_); }
+sub main'and { &out2("and",@_); }
+sub main'or { &out2("or",@_); }
+sub main'shl { &out2("shl",@_); }
+sub main'shr { &out2("shr",@_); }
+sub main'xor { &out2("xor",@_); }
+sub main'xorb { &out2("xor",@_); }
+sub main'add { &out2("add",@_); }
+sub main'adc { &out2("adc",@_); }
+sub main'sub { &out2("sub",@_); }
+sub main'rotl { &out2("rol",@_); }
+sub main'rotr { &out2("ror",@_); }
+sub main'exch { &out2("xchg",@_); }
+sub main'cmp { &out2("cmp",@_); }
+sub main'lea { &out2("lea",@_); }
+sub main'mul { &out1("mul",@_); }
+sub main'div { &out1("div",@_); }
+sub main'dec { &out1("dec",@_); }
+sub main'inc { &out1("inc",@_); }
+sub main'jmp { &out1("jmp",@_); }
+sub main'jmp_ptr { &out1p("jmp",@_); }
+sub main'je { &out1("je",@_); }
+sub main'jle { &out1("jle",@_); }
+sub main'jz { &out1("jz",@_); }
+sub main'jge { &out1("jge",@_); }
+sub main'jl { &out1("jl",@_); }
+sub main'jb { &out1("jb",@_); }
+sub main'jc { &out1("jc",@_); }
+sub main'jnc { &out1("jnc",@_); }
+sub main'jnz { &out1("jnz",@_); }
+sub main'jne { &out1("jne",@_); }
+sub main'jno { &out1("jno",@_); }
+sub main'push { &out1("push",@_); $stack+=4; }
+sub main'pop { &out1("pop",@_); $stack-=4; }
+sub main'bswap { &out1("bswap",@_); &using486(); }
+sub main'not { &out1("not",@_); }
+sub main'call { &out1("call",'_'.$_[0]); }
+sub main'ret { &out0("ret"); }
+sub main'nop { &out0("nop"); }
+
+sub out2
+ {
+ local($name,$p1,$p2)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t");
+ $t=&conv($p1).",";
+ $l=length($t);
+ push(@out,$t);
+ $l=4-($l+9)/8;
+ push(@out,"\t" x $l);
+ push(@out,&conv($p2));
+ push(@out,"\n");
+ }
+
+sub out0
+ {
+ local($name)=@_;
+
+ push(@out,"\t$name\n");
+ }
+
+sub out1
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t".&conv($p1)."\n");
+ }
+
+sub conv
+ {
+ local($p)=@_;
+
+ $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
+ return $p;
+ }
+
+sub using486
+ {
+ return if $using486;
+ $using486++;
+ grep(s/\.386/\.486/,@out);
+ }
+
+sub main'file
+ {
+ local($file)=@_;
+
+ local($tmp)=<<"EOF";
+ TITLE $file.asm
+ .386
+.model FLAT
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'function_begin
+ {
+ local($func,$extra)=@_;
+
+ push(@labels,$func);
+
+ local($tmp)=<<"EOF";
+_TEXT SEGMENT
+PUBLIC _$func
+$extra
+_$func PROC NEAR
+ push ebp
+ push ebx
+ push esi
+ push edi
+EOF
+ push(@out,$tmp);
+ $stack=20;
+ }
+
+sub main'function_begin_B
+ {
+ local($func,$extra)=@_;
+
+ local($tmp)=<<"EOF";
+_TEXT SEGMENT
+PUBLIC _$func
+$extra
+_$func PROC NEAR
+EOF
+ push(@out,$tmp);
+ $stack=4;
+ }
+
+sub main'function_end
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+_$func ENDP
+_TEXT ENDS
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main'function_end_B
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+_$func ENDP
+_TEXT ENDS
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main'function_end_A
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'file_end
+ {
+ push(@out,"END\n");
+ }
+
+sub main'wparam
+ {
+ local($num)=@_;
+
+ return(&main'DWP($stack+$num*4,"esp","",0));
+ }
+
+sub main'swtmp
+ {
+ return(&main'DWP($_[0]*4,"esp","",0));
+ }
+
+# Should use swtmp, which is above esp. Linix can trash the stack above esp
+#sub main'wtmp
+# {
+# local($num)=@_;
+#
+# return(&main'DWP(-(($num+1)*4),"esp","",0));
+# }
+
+sub main'comment
+ {
+ foreach (@_)
+ {
+ push(@out,"\t; $_\n");
+ }
+ }
+
+sub main'label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="\$${label}${_[0]}";
+ $label++;
+ }
+ return($label{$_[0]});
+ }
+
+sub main'set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="${label}${_[0]}";
+ $label++;
+ }
+ if((defined $_[2]) && ($_[2] == 1))
+ {
+ push(@out,"$label{$_[0]}::\n");
+ }
+ else
+ {
+ push(@out,"$label{$_[0]}:\n");
+ }
+ }
+
+sub main'data_word
+ {
+ push(@out,"\tDD\t$_[0]\n");
+ }
+
+sub out1p
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t ".&conv($p1)."\n");
+ }
diff --git a/lib/libcrypto/perlasm/x86nasm.pl b/lib/libcrypto/perlasm/x86nasm.pl
new file mode 100644
index 000000000..90d27fca9
--- /dev/null
+++ b/lib/libcrypto/perlasm/x86nasm.pl
@@ -0,0 +1,366 @@
+#!/usr/bin/perl
+
+package x86nasm;
+
+$label="L000";
+
+%lb=( 'eax', 'al',
+ 'ebx', 'bl',
+ 'ecx', 'cl',
+ 'edx', 'dl',
+ 'ax', 'al',
+ 'bx', 'bl',
+ 'cx', 'cl',
+ 'dx', 'dl',
+ );
+
+%hb=( 'eax', 'ah',
+ 'ebx', 'bh',
+ 'ecx', 'ch',
+ 'edx', 'dh',
+ 'ax', 'ah',
+ 'bx', 'bh',
+ 'cx', 'ch',
+ 'dx', 'dh',
+ );
+
+%regs=( 'eax', 'eax',
+ 'ebx', 'ebx',
+ 'ecx', 'ecx',
+ 'edx', 'edx',
+ 'esi', 'esi',
+ 'edi', 'edi',
+ 'ebp', 'ebp',
+ 'esp', 'esp',
+ 'mm0', 'mm0',
+ 'mm1', 'mm1',
+ );
+
+sub main::asm_init_output { @out=(); }
+sub main::asm_get_output { return(@out); }
+sub main::get_labels { return(@labels); }
+
+sub main::external_label
+{
+ push(@labels,@_);
+ foreach (@_) {
+ push(@out, "extern\t_$_\n");
+ }
+}
+
+sub main::LB
+ {
+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
+ return($lb{$_[0]});
+ }
+
+sub main::HB
+ {
+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
+ return($hb{$_[0]});
+ }
+
+sub main::BP
+ {
+ &get_mem("BYTE",@_);
+ }
+
+sub main::DWP
+ {
+ &get_mem("DWORD",@_);
+ }
+
+sub main::BC
+ {
+ return "BYTE @_";
+ }
+
+sub main::DWC
+ {
+ return "DWORD @_";
+ }
+
+sub main::stack_push
+ {
+ my($num)=@_;
+ $stack+=$num*4;
+ &main::sub("esp",$num*4);
+ }
+
+sub main::stack_pop
+ {
+ my($num)=@_;
+ $stack-=$num*4;
+ &main::add("esp",$num*4);
+ }
+
+sub get_mem
+ {
+ my($size,$addr,$reg1,$reg2,$idx)=@_;
+ my($t,$post);
+ my($ret)="[";
+ $addr =~ s/^\s+//;
+ if ($addr =~ /^(.+)\+(.+)$/)
+ {
+ if (defined($regs{$reg2})) {
+ $addr=join('+', &conv($1), "_$2");
+ } else {
+ $reg2=&conv($1);
+ $addr="_$2";
+ }
+ }
+ elsif ($addr =~ /^[_a-zA-Z]/)
+ {
+ $addr="_$addr";
+ }
+
+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
+ if (($addr ne "") && ($addr ne 0))
+ {
+ if ($addr !~ /^-/)
+ { $ret.="${addr}+"; }
+ else { $post=$addr; }
+ }
+ if ($reg2 ne "")
+ {
+ $t="";
+ $t="*$idx" if ($idx != 0);
+ $reg1="+".$reg1 if ("$reg1$post" ne "");
+ $ret.="$reg2$t$reg1$post]";
+ }
+ else
+ {
+ $ret.="$reg1$post]"
+ }
+ return($ret);
+ }
+
+sub main::mov { &out2("mov",@_); }
+sub main::movb { &out2("mov",@_); }
+sub main::and { &out2("and",@_); }
+sub main::or { &out2("or",@_); }
+sub main::shl { &out2("shl",@_); }
+sub main::shr { &out2("shr",@_); }
+sub main::xor { &out2("xor",@_); }
+sub main::xorb { &out2("xor",@_); }
+sub main::add { &out2("add",@_); }
+sub main::adc { &out2("adc",@_); }
+sub main::sub { &out2("sub",@_); }
+sub main::rotl { &out2("rol",@_); }
+sub main::rotr { &out2("ror",@_); }
+sub main::exch { &out2("xchg",@_); }
+sub main::cmp { &out2("cmp",@_); }
+sub main::lea { &out2("lea",@_); }
+sub main::mul { &out1("mul",@_); }
+sub main::div { &out1("div",@_); }
+sub main::dec { &out1("dec",@_); }
+sub main::inc { &out1("inc",@_); }
+sub main::jmp { &out1("jmp",@_); }
+sub main::jmp_ptr { &out1p("jmp",@_); }
+
+# This is a bit of a kludge: declare all branches as NEAR.
+sub main::je { &out1("je NEAR",@_); }
+sub main::jle { &out1("jle NEAR",@_); }
+sub main::jz { &out1("jz NEAR",@_); }
+sub main::jge { &out1("jge NEAR",@_); }
+sub main::jl { &out1("jl NEAR",@_); }
+sub main::jb { &out1("jb NEAR",@_); }
+sub main::jc { &out1("jc NEAR",@_); }
+sub main::jnc { &out1("jnc NEAR",@_); }
+sub main::jnz { &out1("jnz NEAR",@_); }
+sub main::jne { &out1("jne NEAR",@_); }
+sub main::jno { &out1("jno NEAR",@_); }
+
+sub main::push { &out1("push",@_); $stack+=4; }
+sub main::pop { &out1("pop",@_); $stack-=4; }
+sub main::bswap { &out1("bswap",@_); &using486(); }
+sub main::not { &out1("not",@_); }
+sub main::call { &out1("call",'_'.$_[0]); }
+sub main::ret { &out0("ret"); }
+sub main::nop { &out0("nop"); }
+
+sub out2
+ {
+ my($name,$p1,$p2)=@_;
+ my($l,$t);
+
+ push(@out,"\t$name\t");
+ $t=&conv($p1).",";
+ $l=length($t);
+ push(@out,$t);
+ $l=4-($l+9)/8;
+ push(@out,"\t" x $l);
+ push(@out,&conv($p2));
+ push(@out,"\n");
+ }
+
+sub out0
+ {
+ my($name)=@_;
+
+ push(@out,"\t$name\n");
+ }
+
+sub out1
+ {
+ my($name,$p1)=@_;
+ my($l,$t);
+ push(@out,"\t$name\t".&conv($p1)."\n");
+ }
+
+sub conv
+ {
+ my($p)=@_;
+ $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
+ return $p;
+ }
+
+sub using486
+ {
+ return if $using486;
+ $using486++;
+ grep(s/\.386/\.486/,@out);
+ }
+
+sub main::file
+ {
+ push(@out, "segment .text\n");
+ }
+
+sub main::function_begin
+ {
+ my($func,$extra)=@_;
+
+ push(@labels,$func);
+ my($tmp)=<<"EOF";
+global _$func
+_$func:
+ push ebp
+ push ebx
+ push esi
+ push edi
+EOF
+ push(@out,$tmp);
+ $stack=20;
+ }
+
+sub main::function_begin_B
+ {
+ my($func,$extra)=@_;
+ my($tmp)=<<"EOF";
+global _$func
+_$func:
+EOF
+ push(@out,$tmp);
+ $stack=4;
+ }
+
+sub main::function_end
+ {
+ my($func)=@_;
+
+ my($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main::function_end_B
+ {
+ $stack=0;
+ %label=();
+ }
+
+sub main::function_end_A
+ {
+ my($func)=@_;
+
+ my($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+EOF
+ push(@out,$tmp);
+ }
+
+sub main::file_end
+ {
+ }
+
+sub main::wparam
+ {
+ my($num)=@_;
+
+ return(&main::DWP($stack+$num*4,"esp","",0));
+ }
+
+sub main::swtmp
+ {
+ return(&main::DWP($_[0]*4,"esp","",0));
+ }
+
+# Should use swtmp, which is above esp. Linix can trash the stack above esp
+#sub main::wtmp
+# {
+# my($num)=@_;
+#
+# return(&main::DWP(-(($num+1)*4),"esp","",0));
+# }
+
+sub main::comment
+ {
+ foreach (@_)
+ {
+ push(@out,"\t; $_\n");
+ }
+ }
+
+sub main::label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="\$${label}${_[0]}";
+ $label++;
+ }
+ return($label{$_[0]});
+ }
+
+sub main::set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="${label}${_[0]}";
+ $label++;
+ }
+ push(@out,"$label{$_[0]}:\n");
+ }
+
+sub main::data_word
+ {
+ push(@out,"\tDD\t$_[0]\n");
+ }
+
+sub out1p
+ {
+ my($name,$p1)=@_;
+ my($l,$t);
+
+ push(@out,"\t$name\t ".&conv($p1)."\n");
+ }
+
+##
+## Additional functions required for MMX and other ops
+##
+sub main::testb { &out2('test', @_) }
+sub main::movzx { &out2('movzx', @_) }
+sub main::movd { &out2('movd', @_) }
+sub main::emms { &out0('emms', @_) }
diff --git a/lib/libcrypto/perlasm/x86unix.pl b/lib/libcrypto/perlasm/x86unix.pl
new file mode 100644
index 000000000..f804b91c9
--- /dev/null
+++ b/lib/libcrypto/perlasm/x86unix.pl
@@ -0,0 +1,472 @@
+#!/usr/bin/perl
+
+package x86unix;
+
+$label="L000";
+
+$align=($main::aout)?"4":"16";
+$under=($main::aout)?"_":"";
+$com_start=($main::sol)?"/":"#";
+
+sub main::asm_init_output { @out=(); }
+sub main::asm_get_output { return(@out); }
+sub main::get_labels { return(@labels); }
+sub main::external_label { push(@labels,@_); }
+
+if ($main::cpp)
+ {
+ $align="ALIGN";
+ $under="";
+ $com_start='/*';
+ $com_end='*/';
+ }
+
+%lb=( 'eax', '%al',
+ 'ebx', '%bl',
+ 'ecx', '%cl',
+ 'edx', '%dl',
+ 'ax', '%al',
+ 'bx', '%bl',
+ 'cx', '%cl',
+ 'dx', '%dl',
+ );
+
+%hb=( 'eax', '%ah',
+ 'ebx', '%bh',
+ 'ecx', '%ch',
+ 'edx', '%dh',
+ 'ax', '%ah',
+ 'bx', '%bh',
+ 'cx', '%ch',
+ 'dx', '%dh',
+ );
+
+%regs=( 'eax', '%eax',
+ 'ebx', '%ebx',
+ 'ecx', '%ecx',
+ 'edx', '%edx',
+ 'esi', '%esi',
+ 'edi', '%edi',
+ 'ebp', '%ebp',
+ 'esp', '%esp',
+ 'mm0', '%mm0',
+ 'mm1', '%mm1',
+ );
+
+%reg_val=(
+ 'eax', 0x00,
+ 'ebx', 0x03,
+ 'ecx', 0x01,
+ 'edx', 0x02,
+ 'esi', 0x06,
+ 'edi', 0x07,
+ 'ebp', 0x05,
+ 'esp', 0x04,
+ );
+
+sub main::LB
+ {
+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
+ return($lb{$_[0]});
+ }
+
+sub main::HB
+ {
+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
+ return($hb{$_[0]});
+ }
+
+sub main::DWP
+ {
+ local($addr,$reg1,$reg2,$idx)=@_;
+
+ $ret="";
+ $addr =~ s/(^|[+ \t])([A-Za-z_]+[A-Za-z0-9_]+)($|[+ \t])/$1$under$2$3/;
+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
+ $ret.=$addr if ($addr ne "") && ($addr ne 0);
+ if ($reg2 ne "")
+ {
+ if($idx ne "")
+ { $ret.="($reg1,$reg2,$idx)"; }
+ else
+ { $ret.="($reg1,$reg2)"; }
+ }
+ else
+ { $ret.="($reg1)" }
+ return($ret);
+ }
+
+sub main::BP
+ {
+ return(&main::DWP(@_));
+ }
+
+sub main::BC
+ {
+ return @_;
+ }
+
+sub main::DWC
+ {
+ return @_;
+ }
+
+#sub main::BP
+# {
+# local($addr,$reg1,$reg2,$idx)=@_;
+#
+# $ret="";
+#
+# $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
+# $reg1="$regs{$reg1}" if defined($regs{$reg1});
+# $reg2="$regs{$reg2}" if defined($regs{$reg2});
+# $ret.=$addr if ($addr ne "") && ($addr ne 0);
+# if ($reg2 ne "")
+# { $ret.="($reg1,$reg2,$idx)"; }
+# else
+# { $ret.="($reg1)" }
+# return($ret);
+# }
+
+sub main::mov { &out2("movl",@_); }
+sub main::movb { &out2("movb",@_); }
+sub main::and { &out2("andl",@_); }
+sub main::or { &out2("orl",@_); }
+sub main::shl { &out2("sall",@_); }
+sub main::shr { &out2("shrl",@_); }
+sub main::xor { &out2("xorl",@_); }
+sub main::xorb { &out2("xorb",@_); }
+sub main::add { &out2("addl",@_); }
+sub main::adc { &out2("adcl",@_); }
+sub main::sub { &out2("subl",@_); }
+sub main::rotl { &out2("roll",@_); }
+sub main::rotr { &out2("rorl",@_); }
+sub main::exch { &out2("xchg",@_); }
+sub main::cmp { &out2("cmpl",@_); }
+sub main::lea { &out2("leal",@_); }
+sub main::mul { &out1("mull",@_); }
+sub main::div { &out1("divl",@_); }
+sub main::jmp { &out1("jmp",@_); }
+sub main::jmp_ptr { &out1p("jmp",@_); }
+sub main::je { &out1("je",@_); }
+sub main::jle { &out1("jle",@_); }
+sub main::jne { &out1("jne",@_); }
+sub main::jnz { &out1("jnz",@_); }
+sub main::jz { &out1("jz",@_); }
+sub main::jge { &out1("jge",@_); }
+sub main::jl { &out1("jl",@_); }
+sub main::jb { &out1("jb",@_); }
+sub main::jc { &out1("jc",@_); }
+sub main::jnc { &out1("jnc",@_); }
+sub main::jno { &out1("jno",@_); }
+sub main::dec { &out1("decl",@_); }
+sub main::inc { &out1("incl",@_); }
+sub main::push { &out1("pushl",@_); $stack+=4; }
+sub main::pop { &out1("popl",@_); $stack-=4; }
+sub main::not { &out1("notl",@_); }
+sub main::call { &out1("call",$under.$_[0]); }
+sub main::ret { &out0("ret"); }
+sub main::nop { &out0("nop"); }
+
+# The bswapl instruction is new for the 486. Emulate if i386.
+sub main::bswap
+ {
+ if ($main::i386)
+ {
+ &main::comment("bswapl @_");
+ &main::exch(main::HB(@_),main::LB(@_));
+ &main::rotr(@_,16);
+ &main::exch(main::HB(@_),main::LB(@_));
+ }
+ else
+ {
+ &out1("bswapl",@_);
+ }
+ }
+
+sub out2
+ {
+ local($name,$p1,$p2)=@_;
+ local($l,$ll,$t);
+ local(%special)=( "roll",0xD1C0,"rorl",0xD1C8,
+ "rcll",0xD1D0,"rcrl",0xD1D8,
+ "shll",0xD1E0,"shrl",0xD1E8,
+ "sarl",0xD1F8);
+
+ if ((defined($special{$name})) && defined($regs{$p1}) && ($p2 == 1))
+ {
+ $op=$special{$name}|$reg_val{$p1};
+ $tmp1=sprintf(".byte %d\n",($op>>8)&0xff);
+ $tmp2=sprintf(".byte %d\t",$op &0xff);
+ push(@out,$tmp1);
+ push(@out,$tmp2);
+
+ $p2=&conv($p2);
+ $p1=&conv($p1);
+ &main::comment("$name $p2 $p1");
+ return;
+ }
+
+ push(@out,"\t$name\t");
+ $t=&conv($p2).",";
+ $l=length($t);
+ push(@out,$t);
+ $ll=4-($l+9)/8;
+ $tmp1=sprintf("\t" x $ll);
+ push(@out,$tmp1);
+ push(@out,&conv($p1)."\n");
+ }
+
+sub out1
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+ local(%special)=("bswapl",0x0FC8);
+
+ if ((defined($special{$name})) && defined($regs{$p1}))
+ {
+ $op=$special{$name}|$reg_val{$p1};
+ $tmp1=sprintf(".byte %d\n",($op>>8)&0xff);
+ $tmp2=sprintf(".byte %d\t",$op &0xff);
+ push(@out,$tmp1);
+ push(@out,$tmp2);
+
+ $p2=&conv($p2);
+ $p1=&conv($p1);
+ &main::comment("$name $p2 $p1");
+ return;
+ }
+
+ push(@out,"\t$name\t".&conv($p1)."\n");
+ }
+
+sub out1p
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t*".&conv($p1)."\n");
+ }
+
+sub out0
+ {
+ push(@out,"\t$_[0]\n");
+ }
+
+sub conv
+ {
+ local($p)=@_;
+
+# $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
+
+ $p=$regs{$p} if (defined($regs{$p}));
+
+ $p =~ s/^(-{0,1}[0-9A-Fa-f]+)$/\$$1/;
+ $p =~ s/^(0x[0-9A-Fa-f]+)$/\$$1/;
+ return $p;
+ }
+
+sub main::file
+ {
+ local($file)=@_;
+
+ local($tmp)=<<"EOF";
+ .file "$file.s"
+ .version "01.01"
+EOF
+# Removed the next line from previous infile
+#gcc2_compiled.:
+ push(@out,$tmp);
+ }
+
+sub main::function_begin
+ {
+ local($func)=@_;
+
+ &main::external_label($func);
+ $func=$under.$func;
+
+ local($tmp)=<<"EOF";
+.text
+ .align $align
+.globl $func
+EOF
+ push(@out,$tmp);
+ if ($main::cpp)
+ { $tmp=push(@out,"\tTYPE($func,\@function)\n"); }
+ elsif ($main::gaswin)
+ { $tmp=push(@out,"\t.def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
+ else { $tmp=push(@out,"\t.type\t$func,\@function\n"); }
+ push(@out,"$func:\n");
+ $tmp=<<"EOF";
+ pushl %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+EOF
+ push(@out,$tmp);
+ $stack=20;
+ }
+
+sub main::function_begin_B
+ {
+ local($func,$extra)=@_;
+
+ &main::external_label($func);
+ $func=$under.$func;
+
+ local($tmp)=<<"EOF";
+.text
+ .align $align
+.globl $func
+EOF
+ push(@out,$tmp);
+ if ($main::cpp)
+ { push(@out,"\tTYPE($func,\@function)\n"); }
+ elsif ($main::gaswin)
+ { $tmp=push(@out,"\t.def\t$func;\t.scl\t2;\t.type\t32;\t.endef\n"); }
+ else { push(@out,"\t.type $func,\@function\n"); }
+ push(@out,"$func:\n");
+ $stack=4;
+ }
+
+sub main::function_end
+ {
+ local($func)=@_;
+
+ $func=$under.$func;
+
+ local($tmp)=<<"EOF";
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+.${func}_end:
+EOF
+ push(@out,$tmp);
+ if ($main::cpp)
+ { push(@out,"\tSIZE($func,.${func}_end-$func)\n"); }
+ elsif ($main::gaswin)
+ { $tmp=push(@out,"\t.align 4\n"); }
+ else { push(@out,"\t.size\t$func,.${func}_end-$func\n"); }
+ push(@out,".ident \"$func\"\n");
+ $stack=0;
+ %label=();
+ }
+
+sub main::function_end_A
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+EOF
+ push(@out,$tmp);
+ }
+
+sub main::function_end_B
+ {
+ local($func)=@_;
+
+ $func=$under.$func;
+
+ push(@out,".L_${func}_end:\n");
+ if ($main::cpp)
+ { push(@out,"\tSIZE($func,.L_${func}_end-$func)\n"); }
+ elsif ($main::gaswin)
+ { push(@out,"\t.align 4\n"); }
+ else { push(@out,"\t.size\t$func,.L_${func}_end-$func\n"); }
+ push(@out,".ident \"desasm.pl\"\n");
+ $stack=0;
+ %label=();
+ }
+
+sub main::wparam
+ {
+ local($num)=@_;
+
+ return(&main::DWP($stack+$num*4,"esp","",0));
+ }
+
+sub main::stack_push
+ {
+ local($num)=@_;
+ $stack+=$num*4;
+ &main::sub("esp",$num*4);
+ }
+
+sub main::stack_pop
+ {
+ local($num)=@_;
+ $stack-=$num*4;
+ &main::add("esp",$num*4);
+ }
+
+sub main::swtmp
+ {
+ return(&main::DWP($_[0]*4,"esp","",0));
+ }
+
+# Should use swtmp, which is above esp. Linix can trash the stack above esp
+#sub main::wtmp
+# {
+# local($num)=@_;
+#
+# return(&main::DWP(-($num+1)*4,"esp","",0));
+# }
+
+sub main::comment
+ {
+ foreach (@_)
+ {
+ if (/^\s*$/)
+ { push(@out,"\n"); }
+ else
+ { push(@out,"\t$com_start $_ $com_end\n"); }
+ }
+ }
+
+sub main::label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=".${label}${_[0]}";
+ $label++;
+ }
+ return($label{$_[0]});
+ }
+
+sub main::set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=".${label}${_[0]}";
+ $label++;
+ }
+ push(@out,".align $align\n") if ($_[1] != 0);
+ push(@out,"$label{$_[0]}:\n");
+ }
+
+sub main::file_end
+ {
+ }
+
+sub main::data_word
+ {
+ push(@out,"\t.long $_[0]\n");
+ }
+
+##
+## Additional functions required for MMX and other ops
+##
+sub main::testb { &out2('testb', @_) }
+sub main::movzx { &out2('movzx', @_) }
+sub main::movd { &out2('movd', @_) }
+sub main::emms { &out0('emms', @_) }
diff --git a/lib/libdes/.cvsignore b/lib/libdes/.cvsignore
new file mode 100644
index 000000000..e06b80457
--- /dev/null
+++ b/lib/libdes/.cvsignore
@@ -0,0 +1,3 @@
+des_opts
+destest
+speed
diff --git a/lib/libdes/Makefile b/lib/libdes/Makefile
new file mode 100644
index 000000000..e00bb0073
--- /dev/null
+++ b/lib/libdes/Makefile
@@ -0,0 +1,245 @@
+ifndef FREESWANSRCDIR
+FREESWANSRCDIR=../..
+endif
+
+include ${FREESWANSRCDIR}/Makefile.inc
+
+KLIPSD=${FREESWANSRCDIR}/linux
+SRCDIR=${KLIPSD}/crypto/ciphers/des
+
+VPATH =${SRCDIR}
+
+# You must select the correct terminal control system to be used to
+# turn character echo off when reading passwords. There a 5 systems
+# SGTTY - the old BSD system
+# TERMIO - most system V boxes
+# TERMIOS - SGI (ala IRIX).
+# VMS - the DEC operating system
+# MSDOS - we all know what it is :-)
+# read_pwd.c makes a reasonable guess at what is correct.
+
+# Targets
+# make - twidle the options yourself :-)
+# make cc - standard cc options
+# make gcc - standard gcc options
+# make x86-elf - linux-elf etc
+# make x86-out - linux-a.out, FreeBSD etc
+# make x86-solaris
+# make x86-bdsi
+
+# If you are on a DEC Alpha, edit des.h and change the DES_LONG
+# define to 'unsigned int'. I have seen this give a %20 speedup.
+
+OPTS0= -DLIBDES_LIT -DRAND -DTERMIO #-DNOCONST
+
+# Version 1.94 has changed the strings_to_key function so that it is
+# now compatible with MITs when the string is longer than 8 characters.
+# If you wish to keep the old version, uncomment the following line.
+# This will affect the -E/-D options on des(1).
+#OPTS1= -DOLD_STR_TO_KEY
+
+# There are 4 possible performance options
+# -DDES_PTR
+# -DDES_RISC1
+# -DDES_RISC2 (only one of DES_RISC1 and DES_RISC2)
+# -DDES_UNROLL
+# after the initial build, run 'des_opts' to see which options are best
+# for your platform. There are some listed in options.txt
+#OPTS2= -DDES_PTR
+#OPTS3= -DDES_RISC1 # or DES_RISC2
+#OPTS4= -DDES_UNROLL
+
+OPTS= $(OPTS0) $(OPTS1) $(OPTS2) $(OPTS3) $(OPTS4)
+
+MAKE=make -f Makefile
+#CC=cc
+#CFLAG= -O
+
+#CC=gcc
+#CFLAG= -O4 -funroll-loops -fomit-frame-pointer
+# normally overridden by FreeS/WAN Makefiles anyway
+CFLAG= -O3 -fomit-frame-pointer -I${KLIPSD}/include -I${SRCDIR}
+
+CFLAGS=$(OPTS) $(CFLAG) $(USERCOMPILE)
+CPP=$(CC) -E
+
+# Assember version of des_encrypt*().
+DES_ENC=des_enc.o fcrypt_b.o # normal C version
+#DES_ENC=asm/dx86-elf.o asm/yx86-elf.o # elf format x86
+#DES_ENC=asm/dx86-out.o asm/yx86-out.o # a.out format x86
+#DES_ENC=asm/dx86-sol.o asm/yx86-sol.o # solaris format x86
+#DES_ENC=asm/dx86bsdi.o asm/yx86basi.o # bsdi format x86
+
+LIBDIR=$(DESTDIR)$(INC_USRLOCAL)/lib
+INCDIR=$(DESTDIR)$(INC_USRLOCAL)/include
+MANDIR=$(MANTREE)
+MAN1=1
+MAN3=3
+SHELL=/bin/sh
+MAN1=1
+MAN3=3
+SHELL=/bin/sh
+OBJ_LIT=cbc_enc.o ecb_enc.o $(DES_ENC) fcrypt.o set_key.o
+OBJ_FULL=cbc_cksm.o $(OBJ_LIT) pcbc_enc.o \
+ xcbc_enc.o qud_cksm.o \
+ cfb64ede.o cfb64enc.o cfb_enc.o ecb3_enc.o \
+ enc_read.o enc_writ.o ofb64ede.o ofb64enc.o ofb_enc.o \
+ rand_key.o read_pwd.o read2pwd.o rpc_enc.o str2key.o supp.o
+
+GENERAL_LIT=COPYRIGHT INSTALL README VERSION Makefile des_crypt.man \
+ des.doc options.txt asm
+
+GENERAL_FULL=$(GENERAL_LIT) FILES Imakefile times vms.com KERBEROS MODES.DES \
+ des.man DES.pm DES.pod DES.xs Makefile.PL dess.S des3s.S \
+ Makefile.uni typemap t Makefile.ssl makefile.bc Makefile.lit \
+ des.org des_locl.org
+
+TESTING_LIT= destest speed des_opts
+TESTING_FULL= rpw $(TESTING_LIT)
+TESTING_SRC_LIT=destest.c speed.c des_opts.c
+TESTING_SRC_FULL=rpw.c $(TESTING_SRC_LIT)
+HEADERS_LIT=des_ver.h des.h des_locl.h podd.h sk.h spr.h
+HEADERS_FULL= $(HEADERS_LIT) rpc_des.h
+LIBDES_LIT=cbc_enc.c ecb_enc.c fcrypt.c set_key.c des_enc.c fcrypt_b.c
+
+LIBDES_FULL= cbc_cksm.c pcbc_enc.c qud_cksm.c \
+ cfb64ede.c cfb64enc.c cfb_enc.c ecb3_enc.c \
+ enc_read.c enc_writ.c ofb64ede.c ofb64enc.c ofb_enc.c \
+ rand_key.c rpc_enc.c str2key.c supp.c \
+ xcbc_enc.c $(LIBDES_LIT) read_pwd.c read2pwd.c
+
+PERL= des.pl testdes.pl doIP doPC1 doPC2 PC1 PC2 shifts.pl
+
+OBJ= $(OBJ_LIT)
+GENERAL=$(GENERAL_LIT)
+TESTING=$(TESTING_LIT)
+TESTING_SRC=$(TESTING_SRC_LIT)
+HEADERS=$(HEADERS_LIT)
+LIBDES= $(LIBDES_LIT)
+
+ALL= $(GENERAL) $(TESTING_SRC) $(LIBDES) $(PERL) $(HEADERS)
+
+DLIB= libdes.a
+
+.PHONY: all cc gcc x86-elf x86-out x86-solaris x86-bsdi test tar_lit \
+ tar shar depend clean dclean install check checkprograms
+
+all: $(DLIB) $(TESTING)
+programs: $(DLIB)
+
+cc:
+ $(MAKE) CC=cc CFLAGS="-O $(OPTS) $(CFLAG)" all
+
+gcc:
+ $(MAKE) CC=gcc CFLAGS="-O3 -fomit-frame-pointer $(OPTS) $(CFLAG)" all
+
+x86-elf:
+ $(MAKE) DES_ENC='asm/dx86-elf.o asm/yx86-elf.o' CC='$(CC)' CFLAGS="-DELF $(OPTS) $(CFLAG)" all
+
+x86-out:
+ $(MAKE) DES_ENC='asm/dx86-out.o asm/yx86-out.o' CC='$(CC)' CFLAGS="-DOUT $(OPTS) $(CFLAG)" all
+
+x86-solaris:
+ $(MAKE) DES_ENC='asm/dx86-sol.o asm/yx86-sol.o' CC='$(CC)' CFLAGS="-DSOL $(OPTS) $(CFLAG)" all
+
+x86-bsdi:
+ $(MAKE) DES_ENC='asm/dx86bsdi.o asm/yx86bsdi.o' CC='$(CC)' CFLAGS="-DBSDI $(OPTS) $(CFLAG)" all
+
+# elf
+asm/dx86-elf.o: asm/dx86unix.S
+ $(CPP) -DELF asm/dx86unix.S | $(AS) -o asm/dx86-elf.o
+
+asm/yx86-elf.o: asm/yx86unix.S
+ $(CPP) -DELF asm/yx86unix.S | $(AS) -o asm/yx86-elf.o
+
+# solaris
+asm/dx86-sol.o: asm/dx86unix.S
+ $(CC) -E -DSOL asm/dx86unix.S | sed 's/^#.*//' > asm/dx86-sol.s
+ as -o asm/dx86-sol.o asm/dx86-sol.s
+ rm -f asm/dx86-sol.s
+
+asm/yx86-sol.o: asm/yx86unix.S
+ $(CC) -E -DSOL asm/yx86unix.S | sed 's/^#.*//' > asm/yx86-sol.s
+ as -o asm/yx86-sol.o asm/yx86-sol.s
+ rm -f asm/yx86-sol.s
+
+# a.out
+asm/dx86-out.o: asm/dx86unix.S
+ $(CPP) -DOUT asm/dx86unix.S | $(AS) -o asm/dx86-out.o
+
+asm/yx86-out.o: asm/yx86unix.S
+ $(CPP) -DOUT asm/yx86unix.S | $(AS) -o asm/yx86-out.o
+
+# bsdi
+asm/dx86bsdi.o: asm/dx86unix.S
+ $(CPP) -DBSDI asm/dx86unix.S | $(AS) -o asm/dx86bsdi.o
+
+asm/yx86bsdi.o: asm/yx86unix.S
+ $(CPP) -DBSDI asm/yx86unix.S | $(AS) -o asm/yx86bsdi.o
+
+asm/dx86unix.S:
+ (cd asm; perl des-586.pl cpp >dx86unix.S)
+
+asm/yx86unix.S:
+ (cd asm; perl crypt586.pl cpp >yx86unix.S)
+
+test: all
+ ./destest
+
+$(DLIB): $(OBJ)
+ rm -f $(DLIB)
+ $(AR) crs $(DLIB) $(OBJ)
+
+des_opts: des_opts.o $(DLIB)
+ $(CC) $(CFLAGS) -o des_opts des_opts.o $(DLIB)
+
+destest: destest.o $(DLIB)
+ $(CC) $(CFLAGS) -o destest destest.o $(DLIB)
+
+rpw: rpw.o $(DLIB)
+ $(CC) $(CFLAGS) -o rpw rpw.o $(DLIB)
+
+speed: speed.o $(DLIB)
+ $(CC) $(CFLAGS) -o speed speed.o $(DLIB)
+
+des: des.o $(DLIB)
+ $(CC) $(CFLAGS) -o des des.o $(DLIB)
+
+tags:
+ ctags $(TESTING_SRC) $(LIBDES)
+
+tar_lit:
+ /bin/mv Makefile Makefile.tmp
+ /bin/cp Makefile.lit Makefile
+ tar chf libdes-l.tar $(LIBDES_LIT) $(HEADERS_LIT) \
+ $(GENERAL_LIT) $(TESTING_SRC_LIT)
+ /bin/rm -f Makefile
+ /bin/mv Makefile.tmp Makefile
+
+tar:
+ tar chf libdes.tar $(ALL)
+
+shar:
+ shar $(ALL) >libdes.shar
+
+depend:
+ makedepend $(LIBDES) $(TESTING_SRC)
+
+clean:
+ /bin/rm -f *.o tags core $(TESTING) $(DLIB) .nfs* *.old *.bak asm/*.o \
+ asm/*.S
+
+dclean:
+ sed -e '/^# DO NOT DELETE THIS LINE/ q' Makefile >Makefile.new
+ mv -f Makefile.new Makefile
+
+install install_file_list:
+ @true
+
+check:
+ echo no checks in lib right now.
+
+checkprograms:
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
diff --git a/lib/libfreeswan/.cvsignore b/lib/libfreeswan/.cvsignore
new file mode 100644
index 000000000..49cc19caa
--- /dev/null
+++ b/lib/libfreeswan/.cvsignore
@@ -0,0 +1,9 @@
+try
+try1a
+try2
+try3
+try4
+try4a
+try6
+try7
+version.c
diff --git a/lib/libfreeswan/Makefile b/lib/libfreeswan/Makefile
new file mode 100644
index 000000000..b7d4192c8
--- /dev/null
+++ b/lib/libfreeswan/Makefile
@@ -0,0 +1,174 @@
+# FreeS/WAN library
+# Copyright (C) 1998-2001 Henry Spencer.
+#
+# 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:17 as Exp $
+
+
+FREESWANSRCDIR=../..
+
+include ${FREESWANSRCDIR}/Makefile.inc
+include ${FREESWANSRCDIR}/Makefile.ver
+
+
+MANDIR=$(MANTREE)/man3
+
+SRCS=addrtoa.c addrtot.c addrtypeof.c anyaddr.c atoaddr.c \
+ atoasr.c atosa.c atosubnet.c atoul.c copyright.c datatot.c \
+ goodmask.c initaddr.c initsaid.c initsubnet.c keyblobtoid.c \
+ optionsfrom.c pfkey_v2_build.c pfkey_v2_ext_bits.c pfkey_v2_parse.c \
+ pfkey_v2_debug.c prng.c \
+ portof.c rangetoa.c rangetosubnet.c sameaddr.c \
+ satoa.c satot.c subnetof.c subnettoa.c subnettot.c \
+ subnettypeof.c ttoaddr.c ttodata.c ttoprotoport.c \
+ ttosa.c ttosubnet.c ttoul.c ultoa.c ultot.c
+
+OBJS=${SRCS:.c=.o} version.o
+
+KLIPSD=${FREESWANSRCDIR}/linux/include
+SRCDIR=${FREESWANSRCDIR}/linux/lib/libfreeswan
+
+VPATH = ${SRCDIR}
+
+HDRS=${KLIPSD}/freeswan.h ${SRCDIR}/internal.h
+
+LIB=libfreeswan.a
+# Original flags
+CFLAGS=-I. -I${SRCDIR} -I${KLIPSD} -I${FREESWANSRCDIR} $(USERCOMPILE)
+CFLAGS+= -Wall
+#CFLAGS+= -Wconversion
+#CFLAGS+= -Wmissing-prototypes
+CFLAGS+= -Wpointer-arith
+CFLAGS+= -Wcast-qual
+#CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wstrict-prototypes
+#CFLAGS+= -pedantic
+#CFLAGS+= -W
+#CFLAGS+= -Wwrite-strings
+CFLAGS+= -Wbad-function-cast
+CFLAGS+= -DNAT_TRAVERSAL
+
+
+ARFLAGS=crvs
+EXTHDRS=des.h
+EXTLIBS=libdes.a
+MANS=anyaddr.3 atoaddr.3 atoasr.3 atosa.3 atoul.3 goodmask.3 \
+ initaddr.3 initsubnet.3 optionsfrom.3 portof.3 rangetosubnet.3 \
+ sameaddr.3 subnetof.3 ttoaddr.3 ttodata.3 ttosa.3 ttoul.3 version.3
+
+.PHONY: all install clean l t lt tar check depend checkprograms
+
+all: $(LIB)
+programs: $(LIB)
+
+install:
+ @mkdir -p $(MANDIR)
+ @for f in $(MANS) ; \
+ do \
+ $(INSTALL) $(INSTMANFLAGS) $(SRCDIR)/$$f $(MANDIR)/ipsec_$$f || exit 1 ; \
+ done
+ @$(FREESWANSRCDIR)/packaging/utils/manlink $(foreach man, $(MANS), ${SRCDIR}/$(man)) | \
+ while read from to; \
+ do \
+ ln -s -f ipsec_$$from $(MANDIR)/$$to; \
+ done
+
+
+install_file_list:
+ @for f in $(MANS) ; \
+ do \
+ echo $(MANDIR)/ipsec_$$f;\
+ done;
+ @$(FREESWANSRCDIR)/packaging/utils/manlink $(foreach man, $(MANS), ${SRCDIR}/$(man)) | \
+ while read from to; \
+ do \
+ echo $(MANDIR)/$$to; \
+ done
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $(LIB) $(OBJS)
+
+$(OBJS): $(HDRS)
+
+# build version.c using version number from Makefile.ver
+version.c: ${SRCDIR}/version.in.c ${FREESWANSRCDIR}/Makefile.ver
+ sed '/"/s/xxx/$(IPSECVERSION)/' ${SRCDIR}/version.in.c >$@
+
+#libdes.a: ../libdes/libdes.a
+# ln -f -s ../libdes/libdes.a
+#
+# yes, that's CFLAG=, not CFLAGS=
+#../libdes/libdes.a:
+# cd ../libdes ; \
+# if test " `arch | sed 's/^i[3456]/x/'`" = " x86" ; \
+# then $(MAKE) CC='$(CC)' CFLAG='$(CFLAGS)' TESTING='' x86-elf ; \
+# else $(MAKE) CC='$(CC)' CFLAG='$(CFLAGS)' libdes.a ; \
+# fi
+
+clean:
+ rm -f $(LIB) *.o try* core *.core $(EXTHDRS) $(EXTLIBS) version.c
+
+
+# developer-only stuff
+l:
+ $(MAKE) $(LIB) ARFLAGS=crv CFLAGS=-O
+ $(RANLIB) $(LIB)
+
+t: $(LIB)
+ ln -f -s ${SRCDIR}/atosubnet.c try.c
+ ${CC} ${CFLAGS} -DATOSUBNET_MAIN try.c $(LIB) -o try
+ ./try -r
+ ln -f -s ${SRCDIR}/ttosubnet.c try1a.c
+ ${CC} ${CFLAGS} -DTTOSUBNET_MAIN try1a.c $(LIB) -o try1a
+ ./try1a -r
+ ln -f -s ${SRCDIR}/ttodata.c try2.c
+ ${CC} ${CFLAGS} -DTTODATA_MAIN try2.c $(LIB) -o try2
+ ./try2 -r
+ ln -f -s ${SRCDIR}/atoasr.c try3.c
+ ${CC} ${CFLAGS} -DATOASR_MAIN try3.c $(LIB) -o try3
+ ./try3 -r
+ ln -f -s ${SRCDIR}/atosa.c try4.c
+ ${CC} ${CFLAGS} -DATOSA_MAIN try4.c $(LIB) -o try4
+ ./try4 -r
+ ln -f -s ${SRCDIR}/ttosa.c try4a.c
+ ${CC} ${CFLAGS} -DTTOSA_MAIN try4a.c $(LIB) -o try4a
+ ./try4a -r
+ ln -f -s ${SRCDIR}/rangetosubnet.c try6.c
+ ${CC} ${CFLAGS} -DRANGETOSUBNET_MAIN try6.c $(LIB) -o try6
+ ./try6 -r
+ ln -f -s ${SRCDIR}/addrtot.c try7.c
+ ${CC} ${CFLAGS} -DADDRTOT_MAIN try7.c $(LIB) -o try7
+ ./try7 -r
+
+lt: $(LIB)
+ $(MAKE) t
+ cp optionsfrom.c try5.c
+ cc -DTEST try5.c $(LIB) -o try5
+ echo --foo --bar >try5in1
+ echo --optionsfrom >>try5in1
+ echo try5in2 >>try5in1
+ echo --foo >try5in2
+ ./try5 --foo --bar --optionsfrom try5in1 --bar something
+
+tar: clean
+ tar -cvf /tmp/lib.tar Makefile [a-z]*
+
+check:
+ echo no checks in lib right now.
+
+depend:
+ makedepend -Y -- $(CFLAGS) -- $(SRCS)
+
+checkprograms:
+
+# DO NOT DELETE
+
diff --git a/lib/libipsecpolicy/.cvsignore b/lib/libipsecpolicy/.cvsignore
new file mode 100644
index 000000000..17435c875
--- /dev/null
+++ b/lib/libipsecpolicy/.cvsignore
@@ -0,0 +1 @@
+version.c
diff --git a/lib/libipsecpolicy/Makefile b/lib/libipsecpolicy/Makefile
new file mode 100644
index 000000000..a23fa5d04
--- /dev/null
+++ b/lib/libipsecpolicy/Makefile
@@ -0,0 +1,96 @@
+# FreeS/WAN library
+# Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:24 as Exp $
+
+
+FREESWANSRCDIR=../..
+
+include ${FREESWANSRCDIR}/Makefile.inc
+include ${FREESWANSRCDIR}/Makefile.ver
+
+
+MANDIR=$(MANTREE)/man3
+
+SRCS=policyquery.c cgipolicy.c
+
+OBJS=${SRCS:.c=.o} version.o
+
+KLIPSD=${FREESWANSRCDIR}/linux/include
+
+LIB=libipsecpolicy.a
+# Original flags
+CFLAGS=-I. -I${KLIPSD} -I${FREESWANSRCDIR} $(USERCOMPILE)
+CFLAGS+= -Wall
+CFLAGS+= -Wpointer-arith
+CFLAGS+= -Wcast-qual
+CFLAGS+= -Wstrict-prototypes
+CFLAGS+= -Wbad-function-cast
+
+MANS=
+
+.PHONY: all install clean l t lt tar check depend checkprograms
+
+all: $(LIB)
+programs: $(LIB)
+
+install:
+ @mkdir -p $(MANDIR)
+ @for f in $(MANS) ; \
+ do \
+ $(INSTALL) $(INSTMANFLAGS) $(SRCDIR)/$$f $(MANDIR)/ipsec_$$f || exit 1 ; \
+ done
+ @$(FREESWANSRCDIR)/packaging/utils/manlink $(foreach man, $(MANS), ${SRCDIR}/$(man)) | \
+ while read from to; \
+ do \
+ ln -s -f ipsec_$$from $(MANDIR)/$$to; \
+ done
+
+
+install_file_list:
+ @for f in $(MANS) ; \
+ do \
+ echo $(MANDIR)/ipsec_$$f;\
+ done;
+ @$(FREESWANSRCDIR)/packaging/utils/manlink $(foreach man, $(MANS), ${SRCDIR}/$(man)) | \
+ while read from to; \
+ do \
+ echo $(MANDIR)/$$to; \
+ done
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $(LIB) $(OBJS)
+
+$(OBJS): $(HDRS)
+
+# build version.c using version number from Makefile.ver
+version.c: version.in.c ${FREESWANSRCDIR}/Makefile.ver
+ sed '/"/s/xxx/$(IPSECVERSION)/' version.in.c >$@
+
+clean:
+ rm -f $(LIB) *.o try* core *.core $(EXTHDRS) $(EXTLIBS) version.c
+
+
+tar: clean
+ tar -cvf /tmp/lib.tar Makefile [a-z]*
+
+check:
+ echo no checks in lib right now.
+
+depend:
+ makedepend -Y -- $(CFLAGS) -- $(SRCS)
+
+checkprograms:
+
+# DO NOT DELETE
+
diff --git a/lib/libipsecpolicy/cgipolicy.c b/lib/libipsecpolicy/cgipolicy.c
new file mode 100644
index 000000000..d28243e85
--- /dev/null
+++ b/lib/libipsecpolicy/cgipolicy.c
@@ -0,0 +1,77 @@
+/* routines that interface with pluto to get policy information
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: cgipolicy.c,v 1.1 2004/03/15 20:35:24 as Exp $
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "libipsecpolicy.h"
+
+/*
+ * this version is appropriate for when one is called from a perl CGI,
+ * running under Apache. It extracts the appropriate things out of standard
+ * CGI environment variables, namely:
+ * $SERVER_ADDR us
+ * $REMOTE_ADDR them
+ */
+
+err_t ipsec_policy_cgilookup(struct ipsec_policy_cmd_query *result)
+{
+ err_t ret;
+ char *us, *them;
+
+ /* clear it all out */
+ memset(result, 0, sizeof(*result));
+
+ /* setup it up */
+ result->head.ipm_version = IPSEC_POLICY_MSG_REVISION;
+ result->head.ipm_msg_len = sizeof(*result);
+ result->head.ipm_msg_type = IPSEC_CMD_QUERY_HOSTPAIR;
+ result->head.ipm_msg_seq = ipsec_policy_seq();
+
+
+ us = getenv("SERVER_ADDR");
+ them = getenv("REMOTE_ADDR");
+ if(!us || !them) {
+ return "$SERVER_ADDR and $REMOTE_ADDR must be set";
+ }
+
+ ret = ttoaddr(us, 0, AF_INET, &result->query_local);
+ if(ret != NULL) {
+ return ret;
+ }
+
+ ret = ttoaddr(them, 0, AF_INET, &result->query_remote);
+ if(ret != NULL) {
+ return ret;
+ }
+
+ return ipsec_policy_sendrecv((unsigned char *)result, sizeof(*result));
+}
+
diff --git a/lib/libipsecpolicy/libipsecpolicy.h b/lib/libipsecpolicy/libipsecpolicy.h
new file mode 100644
index 000000000..2c4ebdc0c
--- /dev/null
+++ b/lib/libipsecpolicy/libipsecpolicy.h
@@ -0,0 +1,4 @@
+
+extern u_int32_t ipsec_policy_seq(void);
+
+
diff --git a/lib/libipsecpolicy/policyquery.c b/lib/libipsecpolicy/policyquery.c
new file mode 100644
index 000000000..6555bdc08
--- /dev/null
+++ b/lib/libipsecpolicy/policyquery.c
@@ -0,0 +1,167 @@
+/* routines that interface with pluto to get policy information
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: policyquery.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "libipsecpolicy.h"
+
+static int policy_query_socket = -1;
+static u_int32_t policy_seq = 1;
+
+u_int32_t ipsec_policy_seq(void)
+{
+ return ++policy_seq;
+}
+
+err_t ipsec_policy_init(void)
+{
+ struct sockaddr_un sn;
+
+ if(policy_query_socket != -1) {
+ return NULL;
+ }
+
+ policy_query_socket = socket(PF_UNIX, SOCK_STREAM, 0);
+ if(policy_query_socket == -1) {
+ return "failed to open policy socket";
+ }
+
+ /* now connect it */
+ sn.sun_family = AF_UNIX;
+ strcpy(sn.sun_path, IPSEC_POLICY_SOCKET);
+
+ if(connect(policy_query_socket, (struct sockaddr *)&sn, sizeof(sn)) != 0) {
+ int saveerrno = errno;
+ close(policy_query_socket);
+ policy_query_socket=-1;
+ errno = saveerrno;
+ return "failed to connect policy socket";
+ }
+
+ /* okay, I think we are done */
+ return NULL;
+}
+
+err_t ipsec_policy_final(void)
+{
+ if(policy_query_socket != -1) {
+ close(policy_query_socket);
+ policy_query_socket = -1;
+ }
+
+ return NULL;
+}
+
+err_t ipsec_policy_readmsg(int policysock,
+ unsigned char *buf,
+ size_t buflen)
+{
+ struct ipsec_policy_msg_head ipmh;
+
+ if(read(policysock, &ipmh, sizeof(ipmh))
+ != sizeof(ipmh)) {
+ return "read failed";
+ }
+
+ /* got the header, sanitize it, and find out how much more to read */
+ switch(ipmh.ipm_version) {
+ case IPSEC_POLICY_MSG_REVISION:
+ break;
+
+ default:
+ /* XXX go deal with older versions, error for now */
+ fprintf(stderr, "Bad magic header: %u\n", ipmh.ipm_version);
+ return "bad policy msg version magic";
+ }
+
+ if(ipmh.ipm_msg_len > buflen) {
+ return "buffer too small for this message";
+ }
+
+ buflen = ipmh.ipm_msg_len;
+ memcpy(buf, &ipmh, sizeof(ipmh));
+ buf += sizeof(ipmh);
+ buflen -= sizeof(ipmh);
+
+ if(read(policysock, buf, buflen) != buflen) {
+ return "short read from socket";
+ }
+
+ return NULL;
+}
+
+err_t ipsec_policy_sendrecv(unsigned char *buf,
+ size_t buflen)
+{
+ err_t ret;
+ ipsec_policy_init();
+
+ if(write(policy_query_socket, buf, buflen)
+ != buflen) {
+ return "write failed";
+ }
+
+ ret = ipsec_policy_readmsg(policy_query_socket,
+ buf, buflen);
+
+ ipsec_policy_final();
+
+ return ret;
+}
+
+
+err_t ipsec_policy_lookup(int fd, struct ipsec_policy_cmd_query *result)
+{
+ int len;
+
+ /* clear it out */
+ memset(result, 0, sizeof(*result));
+
+ /* setup it up */
+ result->head.ipm_version = IPSEC_POLICY_MSG_REVISION;
+ result->head.ipm_msg_len = sizeof(*result);
+ result->head.ipm_msg_type = IPSEC_CMD_QUERY_HOSTPAIR;
+ result->head.ipm_msg_seq = ipsec_policy_seq();
+
+ /* suck out the data on the sockets */
+ len = sizeof(result->query_local);
+ if(getsockname(fd, (struct sockaddr *)&result->query_local, &len) != 0) {
+ return "getsockname failed";
+ }
+
+ len = sizeof(result->query_remote);
+ if(getpeername(fd, (struct sockaddr *)&result->query_remote, &len) != 0) {
+ return "getpeername failed";
+ }
+
+ return ipsec_policy_sendrecv((unsigned char *)result, sizeof(*result));
+}
+
diff --git a/lib/libipsecpolicy/version.in.c b/lib/libipsecpolicy/version.in.c
new file mode 100644
index 000000000..304c58c0c
--- /dev/null
+++ b/lib/libipsecpolicy/version.in.c
@@ -0,0 +1,38 @@
+/*
+ * libipsecpolicy version information
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: version.in.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+#define V "xxx" /* substituted in by Makefile */
+static const char ipsecpolicy_number[] = V;
+static const char ipsecpolicy_string[] = "Linux FreeS/WAN policylib " V;
+
+/*
+ - ipsec_version_code - return IPsec version number/code, as string
+ */
+const char *
+ipsec_version_code(void)
+{
+ return ipsecpolicy_number;
+}
+
+/*
+ - ipsec_version_string - return full version string
+ */
+const char *
+ipsec_version_string(void)
+{
+ return ipsecpolicy_string;
+}
diff --git a/lib/liblwres/Makefile b/lib/liblwres/Makefile
new file mode 100644
index 000000000..84a7713ab
--- /dev/null
+++ b/lib/liblwres/Makefile
@@ -0,0 +1,73 @@
+# Copyright (C) 2000, 2001 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile,v 1.1 2004/03/15 20:35:25 as Exp $
+
+srcdir = .
+VPATH = .
+top_srcdir = .
+
+CINCLUDES = -I${srcdir}/unix/include \
+ -I. -I./include -I${srcdir}/include
+CDEFINES = -g
+CWARNINGS = -Werror
+
+CFLAGS=${CINCLUDES} ${CDEFINES} ${CWARNINGS}
+
+VERSION="@(\#) freeswan-hacking-9.2.1-for-fs2"
+LIBINTERFACE=2
+LIBREVISION=0
+LIBAGE=1
+RANLIB=ranlib
+
+# Alphabetically
+OBJS = async.o context.o gai_strerror.o getaddrinfo.o gethost.o \
+ getipnode.o getnameinfo.o getrrset.o getrrset2.o herror.o \
+ lwbuffer.o lwconfig.o lwpacket.o lwresutil.o \
+ lwres_gabn.o lwres_gnba.o lwres_grbn.o lwres_noop.o \
+ lwinetaton.o lwinetpton.o lwinetntop.o
+
+# Alphabetically
+SRCS = async.c context.c gai_strerror.c getaddrinfo.c gethost.c \
+ getipnode.c getnameinfo.c getrrset.c getrrset2.c herror.c \
+ lwbuffer.c lwconfig.c lwpacket.c lwresutil.c \
+ lwres_gabn.c lwres_gnba.c lwres_grbn.c lwres_noop.c \
+ lwinetaton.c lwinetpton.c lwinetntop.c
+
+programs all: liblwres.a
+
+version.o: version.c
+ ${LIBTOOL} ${CC} ${ALL_CFLAGS} \
+ -DVERSION=\"${VERSION}\" \
+ -DLIBINTERFACE=${LIBINTERFACE} \
+ -DLIBREVISION=${LIBREVISION} \
+ -DLIBAGE=${LIBAGE} \
+ -c ${srcdir}/version.c
+
+liblwres.a: ${OBJS} version.o
+ ${AR} ${ARFLAGS} $@ ${OBJS} version.o
+ ${RANLIB} $@
+
+timestamp: liblwres.a
+ touch timestamp
+
+clean distclean mostlyclean realclean cleanall spotless::
+ rm -f liblwres.a liblwres.la timestamp $(OBJS)
+
+install checkprograms check install_file_list:
+ @true
+
+TAGS: ${SRCS}
+ etags ${SRCS}
diff --git a/lib/liblwres/api b/lib/liblwres/api
new file mode 100644
index 000000000..f86947031
--- /dev/null
+++ b/lib/liblwres/api
@@ -0,0 +1,3 @@
+LIBINTERFACE = 2
+LIBREVISION = 0
+LIBAGE = 1
diff --git a/lib/liblwres/assert_p.h b/lib/liblwres/assert_p.h
new file mode 100644
index 000000000..0c5718290
--- /dev/null
+++ b/lib/liblwres/assert_p.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: assert_p.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_ASSERT_P_H
+#define LWRES_ASSERT_P_H 1
+
+#include <assert.h> /* Required for assert() prototype. */
+
+#define REQUIRE(x) assert(x)
+#define INSIST(x) assert(x)
+
+#define UNUSED(x) ((void)(x))
+
+#define SPACE_OK(b, s) (LWRES_BUFFER_AVAILABLECOUNT(b) >= (s))
+#define SPACE_REMAINING(b, s) (LWRES_BUFFER_REMAINING(b) >= (s))
+
+#endif /* LWRES_ASSERT_P_H */
diff --git a/lib/liblwres/async.c b/lib/liblwres/async.c
new file mode 100644
index 000000000..b23596a70
--- /dev/null
+++ b/lib/liblwres/async.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2003, Michael Richardson <mcr@freeswawn.org>
+ * Derived from code: Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: async.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h> /* XXX #include <netdb.h> */
+#include <lwres/async.h>
+
+#include "assert_p.h"
+#include "context_p.h"
+
+/*
+ * malloc / calloc functions that guarantee to only
+ * return NULL if there is an error, like they used
+ * to before the ANSI C committee broke them.
+ */
+
+static void *
+sane_malloc(size_t size) {
+ if (size == 0)
+ size = 1;
+ return (malloc(size));
+}
+
+static void *
+sane_calloc(size_t number, size_t size) {
+ size_t len = number * size;
+ void *mem = sane_malloc(len);
+ if (mem != NULL)
+ memset(mem, 0, len);
+ return (mem);
+}
+
+int
+lwres_async_init(lwres_context_t **pctx)
+{
+ lwres_result_t lwresult;
+ lwres_context_t *ctx = NULL;
+ int result;
+
+ lwresult = lwres_context_create(&ctx, NULL, NULL, NULL, 0);
+ if (lwresult != LWRES_R_SUCCESS) {
+ result = lwresult_to_result(lwresult);
+ return(result);
+ }
+ (void) lwres_conf_parse(ctx, lwres_resolv_conf);
+
+ *pctx = ctx;
+ return (ERRSET_SUCCESS);
+}
+
+int
+lwres_getrrsetbyname_init(const char *hostname, unsigned int rdclass,
+ unsigned int rdtype, unsigned int flags,
+ lwres_context_t *ctx,
+ struct lwres_async_state *las)
+{
+ lwres_result_t lwresult;
+ unsigned int i;
+ unsigned int lwflags;
+ unsigned int result;
+
+ int ret;
+ lwres_lwpacket_t pkt;
+ lwres_grbnrequest_t request;
+ char target_name[1024];
+ unsigned int target_length;
+
+ int ret2;
+
+ if (rdclass > 0xffff || rdtype > 0xffff) {
+ result = ERRSET_INVAL;
+ return result;
+ }
+
+ /*
+ * Don't allow queries of class or type ANY
+ */
+ if (rdclass == 0xff || rdtype == 0xff) {
+ result = ERRSET_INVAL;
+ return result;
+ }
+
+ /*
+ * If any input flags were defined, lwflags would be set here
+ * based on them
+ */
+ UNUSED(flags);
+ lwflags = 0;
+
+ las->b_in.base = NULL;
+ las->b_out.base = NULL;
+ las->serial = lwres_context_nextserial(ctx);
+ las->opcode = LWRES_OPCODE_GETRDATABYNAME;
+
+ target_length = strlen(hostname);
+ if (target_length >= sizeof(target_name))
+ return (LWRES_R_FAILURE);
+ strcpy(target_name, hostname); /* strcpy is safe */
+
+ /*
+ * Set up our request and render it to a buffer.
+ */
+ request.rdclass = rdclass;
+ request.rdtype = rdtype;
+ request.flags = lwflags;
+ request.name = target_name;
+ request.namelen = target_length;
+ pkt.pktflags = 0;
+ pkt.serial = las->serial;
+ pkt.result = 0;
+ pkt.recvlength = LWRES_RECVLENGTH;
+
+ /* set up async system */
+ las->next = ctx->pending;
+ ctx->pending = las;
+
+ ret = lwres_grbnrequest_render(ctx, &request, &pkt, &las->b_out);
+
+ return ret;
+}
+
+int
+lwres_getrrsetbyname_xmit(lwres_context_t *ctx,
+ struct lwres_async_state *las)
+{
+ lwres_result_t lwresult;
+ int ret;
+
+ lwresult = lwres_context_send(ctx, las->b_out.base, las->b_out.length);
+
+ return(lwresult_to_result(lwresult));
+}
+
+
+
+unsigned long
+lwres_async_timeout(lwres_context_t *ctx)
+{
+ unsigned long tv_sec;
+
+ /*
+ * Type of tv_sec is long, so make sure the unsigned long timeout
+ * does not overflow it.
+ */
+ if (ctx->timeout <= LONG_MAX)
+ tv_sec = (long)ctx->timeout;
+ else
+ tv_sec = LONG_MAX;
+
+ return tv_sec;
+}
+
+int
+lwres_async_fd(lwres_context_t *ctx)
+{
+ return (ctx->sock);
+}
+
+
+/*
+const char *hostname, unsigned int rdclass,
+ unsigned int rdtype, unsigned int flags,
+*/
+
+int
+lwres_getrrsetbyname_read(struct lwres_async_state **plas,
+ lwres_context_t *ctx,
+ struct rrsetinfo **res)
+{
+ lwres_result_t lwresult;
+ lwres_grbnresponse_t *response = NULL;
+ char *buffer;
+ struct rrsetinfo *rrset = NULL;
+ int recvlen;
+ int ret, result, i;
+ lwres_buffer_t b_in;
+ struct lwres_async_state *las;
+ struct lwres_async_state **las_prev;
+ lwres_lwpacket_t pkt;
+
+ buffer = NULL;
+ buffer = CTXMALLOC(LWRES_RECVLENGTH);
+ if (buffer == NULL) {
+ return ERRSET_NOMEMORY;
+ }
+
+ ret = LWRES_R_SUCCESS;
+ lwresult = lwres_context_recv(ctx, buffer, LWRES_RECVLENGTH, &recvlen);
+ if (lwresult == LWRES_R_RETRY) {
+ ret = LWRES_R_RETRY;
+ goto out;
+ }
+
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ lwres_buffer_init(&b_in, buffer, recvlen);
+ b_in.used = recvlen;
+
+ /*
+ * Parse the packet header.
+ */
+ ret = lwres_lwpacket_parseheader(&b_in, &pkt);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * find an appropriate waiting las entry. This is a linear search.
+ * we can do MUCH better, since we control the serial number!
+ * do that later.
+ */
+ las_prev = &ctx->pending;
+ las = ctx->pending;
+ while(las && las->serial != pkt.serial) {
+ las_prev=&las->next;
+ las=las->next;
+ }
+
+ if(las == NULL) {
+ /* no matching serial number! */
+ return(LWRES_R_RETRY);
+ }
+
+ /* okay, remove it from the receive queue */
+ *las_prev = las->next;
+ las->next = NULL;
+
+ *plas = las;
+
+ /*
+ * Free what we've transmitted, long ago.
+ */
+ CTXFREE(las->b_out.base, las->b_out.length);
+ las->b_out.base = NULL;
+ las->b_out.length = 0;
+
+ if (pkt.result != LWRES_R_SUCCESS) {
+ ret = pkt.result;
+ goto out;
+ }
+
+ /*
+ * Parse the response.
+ */
+ ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response);
+ if (ret != LWRES_R_SUCCESS) {
+ out:
+ if (buffer != NULL)
+ CTXFREE(buffer, LWRES_RECVLENGTH);
+ if (response != NULL)
+ lwres_grbnresponse_free(ctx, &response);
+ result = lwresult_to_result(ret);
+ goto fail;
+ }
+
+ response->base = buffer;
+ response->baselen = LWRES_RECVLENGTH;
+ buffer = NULL; /* don't free this below */
+
+ lwresult = LWRES_R_SUCCESS;
+
+ rrset = sane_malloc(sizeof(struct rrsetinfo));
+ if (rrset == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ rrset->rri_name = NULL;
+ rrset->rri_rdclass = response->rdclass;
+ rrset->rri_rdtype = response->rdtype;
+ rrset->rri_ttl = response->ttl;
+ rrset->rri_flags = 0;
+ rrset->rri_nrdatas = 0;
+ rrset->rri_rdatas = NULL;
+ rrset->rri_nsigs = 0;
+ rrset->rri_sigs = NULL;
+
+ rrset->rri_name = sane_malloc(response->realnamelen + 1);
+ if (rrset->rri_name == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ strncpy(rrset->rri_name, response->realname, response->realnamelen);
+ rrset->rri_name[response->realnamelen] = 0;
+
+ if ((response->flags & LWRDATA_VALIDATED) != 0)
+ rrset->rri_flags |= RRSET_VALIDATED;
+
+ rrset->rri_nrdatas = response->nrdatas;
+ rrset->rri_rdatas = sane_calloc(rrset->rri_nrdatas,
+ sizeof(struct rdatainfo));
+ if (rrset->rri_rdatas == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ for (i = 0; i < rrset->rri_nrdatas; i++) {
+ rrset->rri_rdatas[i].rdi_length = response->rdatalen[i];
+ rrset->rri_rdatas[i].rdi_data =
+ sane_malloc(rrset->rri_rdatas[i].rdi_length);
+ if (rrset->rri_rdatas[i].rdi_data == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ memcpy(rrset->rri_rdatas[i].rdi_data, response->rdatas[i],
+ rrset->rri_rdatas[i].rdi_length);
+ }
+ rrset->rri_nsigs = response->nsigs;
+ rrset->rri_sigs = sane_calloc(rrset->rri_nsigs,
+ sizeof(struct rdatainfo));
+ if (rrset->rri_sigs == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ for (i = 0; i < rrset->rri_nsigs; i++) {
+ rrset->rri_sigs[i].rdi_length = response->siglen[i];
+ rrset->rri_sigs[i].rdi_data =
+ sane_malloc(rrset->rri_sigs[i].rdi_length);
+ if (rrset->rri_sigs[i].rdi_data == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ memcpy(rrset->rri_sigs[i].rdi_data, response->sigs[i],
+ rrset->rri_sigs[i].rdi_length);
+ }
+
+ lwres_grbnresponse_free(ctx, &response);
+
+ *res = rrset;
+ return (ERRSET_SUCCESS);
+ fail:
+ if (rrset != NULL)
+ lwres_freerrset(rrset);
+ if (response != NULL)
+ lwres_grbnresponse_free(ctx, &response);
+ return (result);
+
+}
+
diff --git a/lib/liblwres/config.h b/lib/liblwres/config.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/lib/liblwres/config.h
diff --git a/lib/liblwres/context.c b/lib/liblwres/context.c
new file mode 100644
index 000000000..40f8f3e3d
--- /dev/null
+++ b/lib/liblwres/context.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: context.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/platform.h>
+
+#ifdef LWRES_PLATFORM_NEEDSYSSELECTH
+#include <sys/select.h>
+#endif
+
+#include "context_p.h"
+#include "assert_p.h"
+
+/*
+ * Some systems define the socket length argument as an int, some as size_t,
+ * some as socklen_t. The last is what the current POSIX standard mandates.
+ * This definition is here so it can be portable but easily changed if needed.
+ */
+#ifndef LWRES_SOCKADDR_LEN_T
+#define LWRES_SOCKADDR_LEN_T unsigned int
+#endif
+
+/*
+ * Make a socket nonblocking.
+ */
+#ifndef MAKE_NONBLOCKING
+#define MAKE_NONBLOCKING(sd, retval) \
+do { \
+ retval = fcntl(sd, F_GETFL, 0); \
+ if (retval != -1) { \
+ retval |= O_NONBLOCK; \
+ retval = fcntl(sd, F_SETFL, retval); \
+ } \
+} while (0)
+#endif
+
+lwres_uint16_t lwres_udp_port = LWRES_UDP_PORT;
+const char *lwres_resolv_conf = LWRES_RESOLV_CONF;
+
+static void *
+lwres_malloc(void *, size_t);
+
+static void
+lwres_free(void *, void *, size_t);
+
+static lwres_result_t
+context_connect(lwres_context_t *);
+
+lwres_result_t
+lwres_context_create(lwres_context_t **contextp, void *arg,
+ lwres_malloc_t malloc_function,
+ lwres_free_t free_function,
+ unsigned int flags)
+{
+ lwres_context_t *ctx;
+
+ REQUIRE(contextp != NULL && *contextp == NULL);
+ UNUSED(flags);
+
+ /*
+ * If we were not given anything special to use, use our own
+ * functions. These are just wrappers around malloc() and free().
+ */
+ if (malloc_function == NULL || free_function == NULL) {
+ REQUIRE(malloc_function == NULL);
+ REQUIRE(free_function == NULL);
+ malloc_function = lwres_malloc;
+ free_function = lwres_free;
+ }
+
+ ctx = malloc_function(arg, sizeof(lwres_context_t));
+ if (ctx == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ /*
+ * Set up the context.
+ */
+ ctx->malloc = malloc_function;
+ ctx->free = free_function;
+ ctx->arg = arg;
+ ctx->sock = -1;
+
+ ctx->timeout = LWRES_DEFAULT_TIMEOUT;
+ ctx->serial = time(NULL); /* XXXMLG or BEW */
+
+ /*
+ * Init resolv.conf bits.
+ */
+ lwres_conf_init(ctx);
+
+ *contextp = ctx;
+ return (LWRES_R_SUCCESS);
+}
+
+void
+lwres_context_destroy(lwres_context_t **contextp) {
+ lwres_context_t *ctx;
+
+ REQUIRE(contextp != NULL && *contextp != NULL);
+
+ ctx = *contextp;
+ *contextp = NULL;
+
+ if (ctx->sock != -1) {
+ close(ctx->sock);
+ ctx->sock = -1;
+ }
+
+ CTXFREE(ctx, sizeof(lwres_context_t));
+}
+
+lwres_uint32_t
+lwres_context_nextserial(lwres_context_t *ctx) {
+ REQUIRE(ctx != NULL);
+
+ return (ctx->serial++);
+}
+
+void
+lwres_context_initserial(lwres_context_t *ctx, lwres_uint32_t serial) {
+ REQUIRE(ctx != NULL);
+
+ ctx->serial = serial;
+}
+
+void
+lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len) {
+ REQUIRE(mem != NULL);
+ REQUIRE(len != 0);
+
+ CTXFREE(mem, len);
+}
+
+void *
+lwres_context_allocmem(lwres_context_t *ctx, size_t len) {
+ REQUIRE(len != 0);
+
+ return (CTXMALLOC(len));
+}
+
+static void *
+lwres_malloc(void *arg, size_t len) {
+ void *mem;
+
+ UNUSED(arg);
+
+ mem = malloc(len);
+ if (mem == NULL)
+ return (NULL);
+
+ memset(mem, 0xe5, len);
+
+ return (mem);
+}
+
+static void
+lwres_free(void *arg, void *mem, size_t len) {
+ UNUSED(arg);
+
+ memset(mem, 0xa9, len);
+ free(mem);
+}
+
+static lwres_result_t
+context_connect(lwres_context_t *ctx) {
+ int s;
+ int ret;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr *sa;
+ LWRES_SOCKADDR_LEN_T salen;
+ int domain;
+
+ if (ctx->confdata.lwnext != 0) {
+ memcpy(&ctx->address, &ctx->confdata.lwservers[0],
+ sizeof(lwres_addr_t));
+ LWRES_LINK_INIT(&ctx->address, link);
+ } else {
+ /* The default is the IPv4 loopback address 127.0.0.1. */
+ memset(&ctx->address, 0, sizeof(ctx->address));
+ ctx->address.family = LWRES_ADDRTYPE_V4;
+ ctx->address.length = 4;
+ ctx->address.address[0] = 127;
+ ctx->address.address[1] = 0;
+ ctx->address.address[2] = 0;
+ ctx->address.address[3] = 1;
+ }
+
+ if (ctx->address.family == LWRES_ADDRTYPE_V4) {
+ memcpy(&sin.sin_addr, ctx->address.address,
+ sizeof(sin.sin_addr));
+ sin.sin_port = htons(lwres_udp_port);
+ sin.sin_family = AF_INET;
+ sa = (struct sockaddr *)&sin;
+ salen = sizeof(sin);
+ domain = PF_INET;
+ } else if (ctx->address.family == LWRES_ADDRTYPE_V6) {
+ memcpy(&sin6.sin6_addr, ctx->address.address,
+ sizeof(sin6.sin6_addr));
+ sin6.sin6_port = htons(lwres_udp_port);
+ sin6.sin6_family = AF_INET6;
+ sa = (struct sockaddr *)&sin6;
+ salen = sizeof(sin6);
+ domain = PF_INET6;
+ } else
+ return (LWRES_R_IOERROR);
+
+ s = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 0)
+ return (LWRES_R_IOERROR);
+
+ ret = connect(s, sa, salen);
+ if (ret != 0) {
+ close(s);
+ return (LWRES_R_IOERROR);
+ }
+
+ MAKE_NONBLOCKING(s, ret);
+ if (ret < 0)
+ return (LWRES_R_IOERROR);
+
+ ctx->sock = s;
+
+ return (LWRES_R_SUCCESS);
+}
+
+int
+lwres_context_getsocket(lwres_context_t *ctx) {
+ return (ctx->sock);
+}
+
+lwres_result_t
+lwres_context_send(lwres_context_t *ctx,
+ void *sendbase, int sendlen) {
+ int ret;
+ lwres_result_t lwresult;
+
+ if (ctx->sock == -1) {
+ lwresult = context_connect(ctx);
+ if (lwresult != LWRES_R_SUCCESS)
+ return (lwresult);
+ }
+
+ ret = sendto(ctx->sock, sendbase, sendlen, 0, NULL, 0);
+ if (ret < 0)
+ return (LWRES_R_IOERROR);
+ if (ret != sendlen)
+ return (LWRES_R_IOERROR);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_context_recv(lwres_context_t *ctx,
+ void *recvbase, int recvlen,
+ int *recvd_len)
+{
+ LWRES_SOCKADDR_LEN_T fromlen;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr *sa;
+ int ret;
+
+ if (ctx->address.family == LWRES_ADDRTYPE_V4) {
+ sa = (struct sockaddr *)&sin;
+ fromlen = sizeof(sin);
+ } else {
+ sa = (struct sockaddr *)&sin6;
+ fromlen = sizeof(sin6);
+ }
+
+ /*
+ * The address of fromlen is cast to void * to shut up compiler
+ * warnings, namely on systems that have the sixth parameter
+ * prototyped as a signed int when LWRES_SOCKADDR_LEN_T is
+ * defined as unsigned.
+ */
+ ret = recvfrom(ctx->sock, recvbase, recvlen, 0, sa, (void *)&fromlen);
+
+ if (ret < 0)
+ return (LWRES_R_IOERROR);
+
+ if (ret == recvlen)
+ return (LWRES_R_TOOLARGE);
+
+ /*
+ * If we got something other than what we expect, have the caller
+ * wait for another packet. This can happen if an old result
+ * comes in, or if someone is sending us random stuff.
+ */
+ if (ctx->address.family == LWRES_ADDRTYPE_V4) {
+ if (fromlen != sizeof(sin)
+ || memcmp(&sin.sin_addr, ctx->address.address,
+ sizeof(sin.sin_addr)) != 0
+ || sin.sin_port != htons(lwres_udp_port))
+ return (LWRES_R_RETRY);
+ } else {
+ if (fromlen != sizeof(sin6)
+ || memcmp(&sin6.sin6_addr, ctx->address.address,
+ sizeof(sin6.sin6_addr)) != 0
+ || sin6.sin6_port != htons(lwres_udp_port))
+ return (LWRES_R_RETRY);
+ }
+
+ if (recvd_len != NULL)
+ *recvd_len = ret;
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_context_sendrecv(lwres_context_t *ctx,
+ void *sendbase, int sendlen,
+ void *recvbase, int recvlen,
+ int *recvd_len)
+{
+ lwres_result_t result;
+ int ret2;
+ fd_set readfds;
+ struct timeval timeout;
+
+ /*
+ * Type of tv_sec is long, so make sure the unsigned long timeout
+ * does not overflow it.
+ */
+ if (ctx->timeout <= LONG_MAX)
+ timeout.tv_sec = (long)ctx->timeout;
+ else
+ timeout.tv_sec = LONG_MAX;
+
+ timeout.tv_usec = 0;
+
+ result = lwres_context_send(ctx, sendbase, sendlen);
+ if (result != LWRES_R_SUCCESS)
+ return (result);
+ again:
+ FD_ZERO(&readfds);
+ FD_SET(ctx->sock, &readfds);
+ ret2 = select(ctx->sock + 1, &readfds, NULL, NULL, &timeout);
+
+ /*
+ * What happened with select?
+ */
+ if (ret2 < 0)
+ return (LWRES_R_IOERROR);
+ if (ret2 == 0)
+ return (LWRES_R_TIMEOUT);
+
+ result = lwres_context_recv(ctx, recvbase, recvlen, recvd_len);
+ if (result == LWRES_R_RETRY)
+ goto again;
+
+ return (result);
+}
diff --git a/lib/liblwres/context_p.h b/lib/liblwres/context_p.h
new file mode 100644
index 000000000..52dd870e1
--- /dev/null
+++ b/lib/liblwres/context_p.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: context_p.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_CONTEXT_P_H
+#define LWRES_CONTEXT_P_H 1
+
+/*
+ * Helper functions, assuming the context is always called "ctx" in
+ * the scope these functions are called from.
+ */
+#define CTXMALLOC(len) ctx->malloc(ctx->arg, (len))
+#define CTXFREE(addr, len) ctx->free(ctx->arg, (addr), (len))
+
+#define LWRES_DEFAULT_TIMEOUT 120 /* 120 seconds for a reply */
+
+/*
+ * Not all the attributes here are actually settable by the application at
+ * this time.
+ */
+struct lwres_context {
+ unsigned int timeout; /* time to wait for reply */
+ lwres_uint32_t serial; /* serial number state */
+
+ /*
+ * For network I/O.
+ */
+ int sock; /* socket to send on */
+ lwres_addr_t address; /* address to send to */
+
+ /*
+ * Function pointers for allocating memory.
+ */
+ lwres_malloc_t malloc;
+ lwres_free_t free;
+ void *arg;
+
+ /*
+ * resolv.conf-like data
+ */
+ lwres_conf_t confdata;
+
+ /* linked list of outstanding DNS requests */
+ struct lwres_async_state *pending;
+};
+
+#endif /* LWRES_CONTEXT_P_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 8
+ * End Variables:
+ */
diff --git a/lib/liblwres/gai_strerror.c b/lib/liblwres/gai_strerror.c
new file mode 100644
index 000000000..913b5139f
--- /dev/null
+++ b/lib/liblwres/gai_strerror.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: gai_strerror.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <lwres/netdb.h>
+
+static const char *gai_messages[] = {
+ "no error",
+ "address family for hostname not supported",
+ "temporary failure in name resolution",
+ "invalid value for ai_flags",
+ "non-recoverable failure in name resolution",
+ "ai_family not supported",
+ "memory allocation failure",
+ "no address associated with hostname",
+ "hostname nor servname provided, or not known",
+ "servname not supported for ai_socktype",
+ "ai_socktype not supported",
+ "system error returned in errno",
+ "bad hints",
+ "bad protocol"
+};
+
+char *
+lwres_gai_strerror(int ecode) {
+ union {
+ const char *const_ptr;
+ char *deconst_ptr;
+ } ptr;
+
+ if ((ecode < 0) ||
+ (ecode >= (int)(sizeof(gai_messages)/sizeof(*gai_messages))))
+ ptr.const_ptr = "invalid error code";
+ else
+ ptr.const_ptr = gai_messages[ecode];
+ return (ptr.deconst_ptr);
+}
diff --git a/lib/liblwres/getaddrinfo.c b/lib/liblwres/getaddrinfo.c
new file mode 100644
index 000000000..06cb39ffc
--- /dev/null
+++ b/lib/liblwres/getaddrinfo.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright (C) 1999-2001 Internet Software Consortium.
+ *
+ * This code is derived from software contributed to Internet Software
+ * Consortium by Berkeley Software Design, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM AND
+ * BERKELEY SOFTWARE DESIGN, INC DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE CONSORTIUM OR BERKELEY
+ * SOFTWARE DESIGN, INC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: getaddrinfo.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h>
+
+#define SA(addr) ((struct sockaddr *)(addr))
+#define SIN(addr) ((struct sockaddr_in *)(addr))
+#define SIN6(addr) ((struct sockaddr_in6 *)(addr))
+#define SUN(addr) ((struct sockaddr_un *)(addr))
+
+static struct addrinfo
+ *ai_reverse(struct addrinfo *oai),
+ *ai_clone(struct addrinfo *oai, int family),
+ *ai_alloc(int family, int addrlen);
+#ifdef AF_LOCAL
+static int get_local(const char *name, int socktype, struct addrinfo **res);
+#endif
+
+static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
+ int socktype, int port);
+static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
+ int socktype, int port);
+static void set_order(int, int (**)(const char *, int, struct addrinfo **,
+ int, int));
+
+#define FOUND_IPV4 0x1
+#define FOUND_IPV6 0x2
+#define FOUND_MAX 2
+
+#define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
+
+int
+lwres_getaddrinfo(const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ struct servent *sp;
+ const char *proto;
+ int family, socktype, flags, protocol;
+ struct addrinfo *ai, *ai_list;
+ int port, err, i;
+ int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
+ int, int);
+
+ if (hostname == NULL && servname == NULL)
+ return (EAI_NONAME);
+
+ proto = NULL;
+ if (hints != NULL) {
+ if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
+ return (EAI_BADFLAGS);
+ if (hints->ai_addrlen || hints->ai_canonname ||
+ hints->ai_addr || hints->ai_next) {
+ errno = EINVAL;
+ return (EAI_SYSTEM);
+ }
+ family = hints->ai_family;
+ socktype = hints->ai_socktype;
+ protocol = hints->ai_protocol;
+ flags = hints->ai_flags;
+ switch (family) {
+ case AF_UNSPEC:
+ switch (hints->ai_socktype) {
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ }
+ break;
+ case AF_INET:
+ case AF_INET6:
+ switch (hints->ai_socktype) {
+ case 0:
+ break;
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ case SOCK_RAW:
+ break;
+ default:
+ return (EAI_SOCKTYPE);
+ }
+ break;
+#ifdef AF_LOCAL
+ case AF_LOCAL:
+ switch (hints->ai_socktype) {
+ case 0:
+ break;
+ case SOCK_STREAM:
+ break;
+ case SOCK_DGRAM:
+ break;
+ default:
+ return (EAI_SOCKTYPE);
+ }
+ break;
+#endif
+ default:
+ return (EAI_FAMILY);
+ }
+ } else {
+ protocol = 0;
+ family = 0;
+ socktype = 0;
+ flags = 0;
+ }
+
+#ifdef AF_LOCAL
+ /*
+ * First, deal with AF_LOCAL. If the family was not set,
+ * then assume AF_LOCAL if the first character of the
+ * hostname/servname is '/'.
+ */
+
+ if (hostname != NULL &&
+ (family == AF_LOCAL || (family == 0 && *hostname == '/')))
+ return (get_local(hostname, socktype, res));
+
+ if (servname != NULL &&
+ (family == AF_LOCAL || (family == 0 && *servname == '/')))
+ return (get_local(servname, socktype, res));
+#endif
+
+ /*
+ * Ok, only AF_INET and AF_INET6 left.
+ */
+ ai_list = NULL;
+
+ /*
+ * First, look up the service name (port) if it was
+ * requested. If the socket type wasn't specified, then
+ * try and figure it out.
+ */
+ if (servname != NULL) {
+ char *e;
+
+ port = strtol(servname, &e, 10);
+ if (*e == '\0') {
+ if (socktype == 0)
+ return (EAI_SOCKTYPE);
+ if (port < 0 || port > 65535)
+ return (EAI_SERVICE);
+ port = htons((unsigned short) port);
+ } else {
+ sp = getservbyname(servname, proto);
+ if (sp == NULL)
+ return (EAI_SERVICE);
+ port = sp->s_port;
+ if (socktype == 0) {
+ if (strcmp(sp->s_proto, "tcp") == 0)
+ socktype = SOCK_STREAM;
+ else if (strcmp(sp->s_proto, "udp") == 0)
+ socktype = SOCK_DGRAM;
+ }
+ }
+ } else
+ port = 0;
+
+ /*
+ * Next, deal with just a service name, and no hostname.
+ * (we verified that one of them was non-null up above).
+ */
+ if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
+ if (family == AF_INET || family == 0) {
+ ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
+ if (ai == NULL)
+ return (EAI_MEMORY);
+ ai->ai_socktype = socktype;
+ ai->ai_protocol = protocol;
+ SIN(ai->ai_addr)->sin_port = port;
+ ai->ai_next = ai_list;
+ ai_list = ai;
+ }
+
+ if (family == AF_INET6 || family == 0) {
+ ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
+ if (ai == NULL) {
+ lwres_freeaddrinfo(ai_list);
+ return (EAI_MEMORY);
+ }
+ ai->ai_socktype = socktype;
+ ai->ai_protocol = protocol;
+ SIN6(ai->ai_addr)->sin6_port = port;
+ ai->ai_next = ai_list;
+ ai_list = ai;
+ }
+
+ *res = ai_list;
+ return (0);
+ }
+
+ /*
+ * If the family isn't specified or AI_NUMERICHOST specified,
+ * check first to see if it is a numeric address.
+ * Though the gethostbyname2() routine
+ * will recognize numeric addresses, it will only recognize
+ * the format that it is being called for. Thus, a numeric
+ * AF_INET address will be treated by the AF_INET6 call as
+ * a domain name, and vice versa. Checking for both numerics
+ * here avoids that.
+ */
+ if (hostname != NULL &&
+ (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
+ char abuf[sizeof(struct in6_addr)];
+ char nbuf[NI_MAXHOST];
+ int addrsize, addroff;
+#ifdef LWRES_HAVE_SIN6_SCOPE_ID
+ char *p, *ep;
+ char ntmp[NI_MAXHOST];
+ lwres_uint32_t scopeid;
+#endif
+
+#ifdef LWRES_HAVE_SIN6_SCOPE_ID
+ /*
+ * Scope identifier portion.
+ */
+ ntmp[0] = '\0';
+ if (strchr(hostname, '%') != NULL) {
+ strncpy(ntmp, hostname, sizeof(ntmp) - 1);
+ ntmp[sizeof(ntmp) - 1] = '\0';
+ p = strchr(ntmp, '%');
+ ep = NULL;
+
+ /*
+ * Vendors may want to support non-numeric
+ * scopeid around here.
+ */
+
+ if (p != NULL)
+ scopeid = (lwres_uint32_t)strtoul(p + 1,
+ &ep, 10);
+ if (p != NULL && ep != NULL && ep[0] == '\0')
+ *p = '\0';
+ else {
+ ntmp[0] = '\0';
+ scopeid = 0;
+ }
+ } else
+ scopeid = 0;
+#endif
+
+ if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf)
+ == 1)
+ {
+ if (family == AF_INET6) {
+ /*
+ * Convert to a V4 mapped address.
+ */
+ struct in6_addr *a6 = (struct in6_addr *)abuf;
+ memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
+ memset(&a6->s6_addr[10], 0xff, 2);
+ memset(&a6->s6_addr[0], 0, 10);
+ goto inet6_addr;
+ }
+ addrsize = sizeof(struct in_addr);
+ addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
+ family = AF_INET;
+ goto common;
+#ifdef LWRES_HAVE_SIN6_SCOPE_ID
+ } else if (ntmp[0] != '\0' &&
+ lwres_net_pton(AF_INET6, ntmp, abuf) == 1)
+ {
+ if (family && family != AF_INET6)
+ return (EAI_NONAME);
+ addrsize = sizeof(struct in6_addr);
+ addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
+ family = AF_INET6;
+ goto common;
+#endif
+ } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) {
+ if (family != 0 && family != AF_INET6)
+ return (EAI_NONAME);
+ inet6_addr:
+ addrsize = sizeof(struct in6_addr);
+ addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
+ family = AF_INET6;
+
+ common:
+ ai = ai_clone(ai_list, family);
+ if (ai == NULL)
+ return (EAI_MEMORY);
+ ai_list = ai;
+ ai->ai_socktype = socktype;
+ SIN(ai->ai_addr)->sin_port = port;
+ memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);
+ if (flags & AI_CANONNAME) {
+#if defined(LWRES_HAVE_SIN6_SCOPE_ID)
+ if (ai->ai_family == AF_INET6)
+ SIN6(ai->ai_addr)->sin6_scope_id =
+ scopeid;
+#endif
+ if (lwres_getnameinfo(ai->ai_addr,
+ ai->ai_addrlen, nbuf, sizeof(nbuf),
+ NULL, 0,
+ NI_NUMERICHOST) == 0) {
+ ai->ai_canonname = strdup(nbuf);
+ if (ai->ai_canonname == NULL)
+ return (EAI_MEMORY);
+ } else {
+ /* XXX raise error? */
+ ai->ai_canonname = NULL;
+ }
+ }
+ goto done;
+ } else if ((flags & AI_NUMERICHOST) != 0) {
+ return (EAI_NONAME);
+ }
+ }
+
+ set_order(family, net_order);
+ for (i = 0; i < FOUND_MAX; i++) {
+ if (net_order[i] == NULL)
+ break;
+ err = (net_order[i])(hostname, flags, &ai_list,
+ socktype, port);
+ if (err != 0)
+ return (err);
+ }
+
+ if (ai_list == NULL)
+ return (EAI_NODATA);
+
+done:
+ ai_list = ai_reverse(ai_list);
+
+ *res = ai_list;
+ return (0);
+}
+
+static char *
+lwres_strsep(char **stringp, const char *delim) {
+ char *string = *stringp;
+ char *s;
+ const char *d;
+ char sc, dc;
+
+ if (string == NULL)
+ return (NULL);
+
+ for (s = string; *s != '\0'; s++) {
+ sc = *s;
+ for (d = delim; (dc = *d) != '\0'; d++)
+ if (sc == dc) {
+ *s++ = '\0';
+ *stringp = s;
+ return (string);
+ }
+ }
+ *stringp = NULL;
+ return (string);
+}
+
+static void
+set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
+ int, int))
+{
+ char *order, *tok;
+ int found;
+
+ if (family) {
+ switch (family) {
+ case AF_INET:
+ *net_order++ = add_ipv4;
+ break;
+ case AF_INET6:
+ *net_order++ = add_ipv6;
+ break;
+ }
+ } else {
+ order = getenv("NET_ORDER");
+ found = 0;
+ while (order != NULL) {
+ /*
+ * We ignore any unknown names.
+ */
+ tok = lwres_strsep(&order, ":");
+ if (strcasecmp(tok, "inet6") == 0) {
+ if ((found & FOUND_IPV6) == 0)
+ *net_order++ = add_ipv6;
+ found |= FOUND_IPV6;
+ } else if (strcasecmp(tok, "inet") == 0 ||
+ strcasecmp(tok, "inet4") == 0) {
+ if ((found & FOUND_IPV4) == 0)
+ *net_order++ = add_ipv4;
+ found |= FOUND_IPV4;
+ }
+ }
+
+ /*
+ * Add in anything that we didn't find.
+ */
+ if ((found & FOUND_IPV4) == 0)
+ *net_order++ = add_ipv4;
+ if ((found & FOUND_IPV6) == 0)
+ *net_order++ = add_ipv6;
+ }
+ *net_order = NULL;
+ return;
+}
+
+static char v4_loop[4] = { 127, 0, 0, 1 };
+
+/*
+ * The test against 0 is there to keep the Solaris compiler
+ * from complaining about "end-of-loop code not reached".
+ */
+#define ERR(code) \
+ do { result = (code); \
+ if (result != 0) goto cleanup; \
+ } while (0)
+
+static int
+add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
+ int socktype, int port)
+{
+ struct addrinfo *ai;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gabnresponse_t *by = NULL;
+ lwres_addr_t *addr;
+ lwres_result_t lwres;
+ int result = 0;
+
+ lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (lwres != LWRES_R_SUCCESS)
+ ERR(EAI_FAIL);
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+ if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
+ ai = ai_clone(*aip, AF_INET);
+ if (ai == NULL) {
+ lwres_freeaddrinfo(*aip);
+ ERR(EAI_MEMORY);
+ }
+
+ *aip = ai;
+ ai->ai_socktype = socktype;
+ SIN(ai->ai_addr)->sin_port = port;
+ memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
+ } else {
+ lwres = lwres_getaddrsbyname(lwrctx, hostname,
+ LWRES_ADDRTYPE_V4, &by);
+ if (lwres != LWRES_R_SUCCESS) {
+ if (lwres == LWRES_R_NOTFOUND)
+ goto cleanup;
+ else
+ ERR(EAI_FAIL);
+ }
+ addr = LWRES_LIST_HEAD(by->addrs);
+ while (addr != NULL) {
+ ai = ai_clone(*aip, AF_INET);
+ if (ai == NULL) {
+ lwres_freeaddrinfo(*aip);
+ ERR(EAI_MEMORY);
+ }
+ *aip = ai;
+ ai->ai_socktype = socktype;
+ SIN(ai->ai_addr)->sin_port = port;
+ memcpy(&SIN(ai->ai_addr)->sin_addr,
+ addr->address, 4);
+ if (flags & AI_CANONNAME) {
+ ai->ai_canonname = strdup(by->realname);
+ if (ai->ai_canonname == NULL)
+ ERR(EAI_MEMORY);
+ }
+ addr = LWRES_LIST_NEXT(addr, link);
+ }
+ }
+ cleanup:
+ if (by != NULL)
+ lwres_gabnresponse_free(lwrctx, &by);
+ if (lwrctx != NULL) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ }
+ return (result);
+}
+
+static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+
+static int
+add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
+ int socktype, int port)
+{
+ struct addrinfo *ai;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gabnresponse_t *by = NULL;
+ lwres_addr_t *addr;
+ lwres_result_t lwres;
+ int result = 0;
+
+ lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (lwres != LWRES_R_SUCCESS)
+ ERR(EAI_FAIL);
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+
+ if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
+ ai = ai_clone(*aip, AF_INET6);
+ if (ai == NULL) {
+ lwres_freeaddrinfo(*aip);
+ ERR(EAI_MEMORY);
+ }
+
+ *aip = ai;
+ ai->ai_socktype = socktype;
+ SIN6(ai->ai_addr)->sin6_port = port;
+ memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
+ } else {
+ lwres = lwres_getaddrsbyname(lwrctx, hostname,
+ LWRES_ADDRTYPE_V6, &by);
+ if (lwres != LWRES_R_SUCCESS) {
+ if (lwres == LWRES_R_NOTFOUND)
+ goto cleanup;
+ else
+ ERR(EAI_FAIL);
+ }
+ addr = LWRES_LIST_HEAD(by->addrs);
+ while (addr != NULL) {
+ ai = ai_clone(*aip, AF_INET6);
+ if (ai == NULL) {
+ lwres_freeaddrinfo(*aip);
+ ERR(EAI_MEMORY);
+ }
+ *aip = ai;
+ ai->ai_socktype = socktype;
+ SIN6(ai->ai_addr)->sin6_port = port;
+ memcpy(&SIN6(ai->ai_addr)->sin6_addr,
+ addr->address, 16);
+ if (flags & AI_CANONNAME) {
+ ai->ai_canonname = strdup(by->realname);
+ if (ai->ai_canonname == NULL)
+ ERR(EAI_MEMORY);
+ }
+ addr = LWRES_LIST_NEXT(addr, link);
+ }
+ }
+ cleanup:
+ if (by != NULL)
+ lwres_gabnresponse_free(lwrctx, &by);
+ if (lwrctx != NULL) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ }
+ return (result);
+}
+
+void
+lwres_freeaddrinfo(struct addrinfo *ai) {
+ struct addrinfo *ai_next;
+
+ while (ai != NULL) {
+ ai_next = ai->ai_next;
+ if (ai->ai_addr != NULL)
+ free(ai->ai_addr);
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
+ free(ai);
+ ai = ai_next;
+ }
+}
+
+#ifdef AF_LOCAL
+static int
+get_local(const char *name, int socktype, struct addrinfo **res) {
+ struct addrinfo *ai;
+ struct sockaddr_un *sun;
+
+ if (socktype == 0)
+ return (EAI_SOCKTYPE);
+
+ ai = ai_alloc(AF_LOCAL, sizeof(*sun));
+ if (ai == NULL)
+ return (EAI_MEMORY);
+
+ sun = SUN(ai->ai_addr);
+ strncpy(sun->sun_path, name, sizeof(sun->sun_path));
+
+ ai->ai_socktype = socktype;
+ /*
+ * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
+ * and ai->ai_next were initialized to zero.
+ */
+
+ *res = ai;
+ return (0);
+}
+#endif
+
+/*
+ * Allocate an addrinfo structure, and a sockaddr structure
+ * of the specificed length. We initialize:
+ * ai_addrlen
+ * ai_family
+ * ai_addr
+ * ai_addr->sa_family
+ * ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
+ * and everything else is initialized to zero.
+ */
+static struct addrinfo *
+ai_alloc(int family, int addrlen) {
+ struct addrinfo *ai;
+
+ ai = (struct addrinfo *)calloc(1, sizeof(*ai));
+ if (ai == NULL)
+ return (NULL);
+
+ ai->ai_addr = SA(calloc(1, addrlen));
+ if (ai->ai_addr == NULL) {
+ free(ai);
+ return (NULL);
+ }
+ ai->ai_addrlen = addrlen;
+ ai->ai_family = family;
+ ai->ai_addr->sa_family = family;
+#ifdef LWRES_PLATFORM_HAVESALEN
+ ai->ai_addr->sa_len = addrlen;
+#endif
+ return (ai);
+}
+
+static struct addrinfo *
+ai_clone(struct addrinfo *oai, int family) {
+ struct addrinfo *ai;
+
+ ai = ai_alloc(family, ((family == AF_INET6) ?
+ sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
+
+ if (ai == NULL) {
+ lwres_freeaddrinfo(oai);
+ return (NULL);
+ }
+ if (oai == NULL)
+ return (ai);
+
+ ai->ai_flags = oai->ai_flags;
+ ai->ai_socktype = oai->ai_socktype;
+ ai->ai_protocol = oai->ai_protocol;
+ ai->ai_canonname = NULL;
+ ai->ai_next = oai;
+ return (ai);
+}
+
+static struct addrinfo *
+ai_reverse(struct addrinfo *oai) {
+ struct addrinfo *nai, *tai;
+
+ nai = NULL;
+
+ while (oai != NULL) {
+ /*
+ * Grab one off the old list.
+ */
+ tai = oai;
+ oai = oai->ai_next;
+ /*
+ * Put it on the front of the new list.
+ */
+ tai->ai_next = nai;
+ nai = tai;
+ }
+ return (nai);
+}
diff --git a/lib/liblwres/gethost.c b/lib/liblwres/gethost.c
new file mode 100644
index 000000000..32c8359b4
--- /dev/null
+++ b/lib/liblwres/gethost.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: gethost.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <lwres/net.h>
+#include <lwres/netdb.h>
+
+#include "assert_p.h"
+
+#define LWRES_ALIGNBYTES (sizeof(char *) - 1)
+#define LWRES_ALIGN(p) \
+ (((unsigned long)(p) + LWRES_ALIGNBYTES) &~ LWRES_ALIGNBYTES)
+
+static struct hostent *he = NULL;
+static int copytobuf(struct hostent *, struct hostent *, char *, int);
+
+struct hostent *
+lwres_gethostbyname(const char *name) {
+
+ if (he != NULL)
+ lwres_freehostent(he);
+
+ he = lwres_getipnodebyname(name, AF_INET, 0, &lwres_h_errno);
+ return (he);
+}
+
+struct hostent *
+lwres_gethostbyname2(const char *name, int af) {
+ if (he != NULL)
+ lwres_freehostent(he);
+
+ he = lwres_getipnodebyname(name, af, 0, &lwres_h_errno);
+ return (he);
+}
+
+struct hostent *
+lwres_gethostbyaddr(const char *addr, int len, int type) {
+
+ if (he != NULL)
+ lwres_freehostent(he);
+
+ he = lwres_getipnodebyaddr(addr, len, type, &lwres_h_errno);
+ return (he);
+}
+
+struct hostent *
+lwres_gethostent(void) {
+ if (he != NULL)
+ lwres_freehostent(he);
+
+ return (NULL);
+}
+
+void
+lwres_sethostent(int stayopen) {
+ /*
+ * Empty.
+ */
+ UNUSED(stayopen);
+}
+
+void
+lwres_endhostent(void) {
+ /*
+ * Empty.
+ */
+}
+
+struct hostent *
+lwres_gethostbyname_r(const char *name, struct hostent *resbuf,
+ char *buf, int buflen, int *error)
+{
+ struct hostent *he;
+ int res;
+
+ he = lwres_getipnodebyname(name, AF_INET, 0, error);
+ if (he == NULL)
+ return (NULL);
+ res = copytobuf(he, resbuf, buf, buflen);
+ lwres_freehostent(he);
+ if (res != 0) {
+ errno = ERANGE;
+ return (NULL);
+ }
+ return (resbuf);
+}
+
+struct hostent *
+lwres_gethostbyaddr_r(const char *addr, int len, int type,
+ struct hostent *resbuf, char *buf, int buflen,
+ int *error)
+{
+ struct hostent *he;
+ int res;
+
+ he = lwres_getipnodebyaddr(addr, len, type, error);
+ if (he == NULL)
+ return (NULL);
+ res = copytobuf(he, resbuf, buf, buflen);
+ lwres_freehostent(he);
+ if (res != 0) {
+ errno = ERANGE;
+ return (NULL);
+ }
+ return (resbuf);
+}
+
+struct hostent *
+lwres_gethostent_r(struct hostent *resbuf, char *buf, int buflen, int *error) {
+ UNUSED(resbuf);
+ UNUSED(buf);
+ UNUSED(buflen);
+ *error = 0;
+ return (NULL);
+}
+
+void
+lwres_sethostent_r(int stayopen) {
+ /*
+ * Empty.
+ */
+ UNUSED(stayopen);
+}
+
+void
+lwres_endhostent_r(void) {
+ /*
+ * Empty.
+ */
+}
+
+static int
+copytobuf(struct hostent *he, struct hostent *hptr, char *buf, int buflen) {
+ char *cp;
+ char **ptr;
+ int i, n;
+ int nptr, len;
+
+ /*
+ * Find out the amount of space required to store the answer.
+ */
+ nptr = 2; /* NULL ptrs */
+ len = (char *)LWRES_ALIGN(buf) - buf;
+ for (i = 0; he->h_addr_list[i]; i++, nptr++) {
+ len += he->h_length;
+ }
+ for (i = 0; he->h_aliases[i]; i++, nptr++) {
+ len += strlen(he->h_aliases[i]) + 1;
+ }
+ len += strlen(he->h_name) + 1;
+ len += nptr * sizeof(char*);
+
+ if (len > buflen) {
+ return (-1);
+ }
+
+ /*
+ * Copy address size and type.
+ */
+ hptr->h_addrtype = he->h_addrtype;
+ n = hptr->h_length = he->h_length;
+
+ ptr = (char **)LWRES_ALIGN(buf);
+ cp = (char *)LWRES_ALIGN(buf) + nptr * sizeof(char *);
+
+ /*
+ * Copy address list.
+ */
+ hptr->h_addr_list = ptr;
+ for (i = 0; he->h_addr_list[i]; i++, ptr++) {
+ memcpy(cp, he->h_addr_list[i], n);
+ hptr->h_addr_list[i] = cp;
+ cp += n;
+ }
+ hptr->h_addr_list[i] = NULL;
+ ptr++;
+
+ /*
+ * Copy official name.
+ */
+ n = strlen(he->h_name) + 1;
+ strcpy(cp, he->h_name);
+ hptr->h_name = cp;
+ cp += n;
+
+ /*
+ * Copy aliases.
+ */
+ hptr->h_aliases = ptr;
+ for (i = 0; he->h_aliases[i]; i++) {
+ n = strlen(he->h_aliases[i]) + 1;
+ strcpy(cp, he->h_aliases[i]);
+ hptr->h_aliases[i] = cp;
+ cp += n;
+ }
+ hptr->h_aliases[i] = NULL;
+
+ return (0);
+}
diff --git a/lib/liblwres/getipnode.c b/lib/liblwres/getipnode.c
new file mode 100644
index 000000000..94882cbe4
--- /dev/null
+++ b/lib/liblwres/getipnode.c
@@ -0,0 +1,839 @@
+/*
+ * Copyright (C) 1999-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: getipnode.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h> /* XXX #include <netdb.h> */
+
+#include "assert_p.h"
+
+#ifndef INADDRSZ
+#define INADDRSZ 4
+#endif
+#ifndef IN6ADDRSZ
+#define IN6ADDRSZ 16
+#endif
+
+#ifdef LWRES_PLATFORM_NEEDIN6ADDRANY
+LIBLWRES_EXTERNAL_DATA const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+#endif
+
+#ifndef IN6_IS_ADDR_V4COMPAT
+static const unsigned char in6addr_compat[12] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+#define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
+ ((x)->s6_addr[12] != 0 || \
+ (x)->s6_addr[13] != 0 || \
+ (x)->s6_addr[14] != 0 || \
+ ((x)->s6_addr[15] != 0 && \
+ (x)->s6_addr[15] != 1)))
+#endif
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
+#endif
+
+static const unsigned char in6addr_mapped[12] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff
+};
+
+/***
+ *** Forward declarations.
+ ***/
+
+static int
+scan_interfaces(int *, int *);
+
+static struct hostent *
+copyandmerge(struct hostent *, struct hostent *, int, int *);
+
+static struct hostent *
+hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src);
+
+static struct hostent *
+hostfromname(lwres_gabnresponse_t *name, int af);
+
+/***
+ *** Public functions.
+ ***/
+
+/*
+ * AI_V4MAPPED + AF_INET6
+ * If no IPv6 address then a query for IPv4 and map returned values.
+ *
+ * AI_ALL + AI_V4MAPPED + AF_INET6
+ * Return IPv6 and IPv4 mapped.
+ *
+ * AI_ADDRCONFIG
+ * Only return IPv6 / IPv4 address if there is an interface of that
+ * type active.
+ */
+
+struct hostent *
+lwres_getipnodebyname(const char *name, int af, int flags, int *error_num) {
+ int have_v4 = 1, have_v6 = 1;
+ struct in_addr in4;
+ struct in6_addr in6;
+ struct hostent he, *he1 = NULL, *he2 = NULL, *he3 = NULL;
+ int v4 = 0, v6 = 0;
+ int tmp_err;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gabnresponse_t *by = NULL;
+ int n;
+
+ /*
+ * If we care about active interfaces then check.
+ */
+ if ((flags & AI_ADDRCONFIG) != 0)
+ if (scan_interfaces(&have_v4, &have_v6) == -1) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ /* Check for literal address. */
+ if ((v4 = lwres_net_pton(AF_INET, name, &in4)) != 1)
+ v6 = lwres_net_pton(AF_INET6, name, &in6);
+
+ /*
+ * Impossible combination?
+ */
+ if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
+ (af == AF_INET && v6 == 1) ||
+ (have_v4 == 0 && v4 == 1) ||
+ (have_v6 == 0 && v6 == 1) ||
+ (have_v4 == 0 && af == AF_INET) ||
+ (have_v6 == 0 && af == AF_INET6 &&
+ (((flags & AI_V4MAPPED) != 0 && have_v4) ||
+ (flags & AI_V4MAPPED) == 0))) {
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+
+ /*
+ * Literal address?
+ */
+ if (v4 == 1 || v6 == 1) {
+ char *addr_list[2];
+ char *aliases[1];
+ union {
+ const char *const_name;
+ char *deconst_name;
+ } u;
+
+ u.const_name = name;
+ he.h_name = u.deconst_name;
+ he.h_addr_list = addr_list;
+ he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
+ he.h_addr_list[1] = NULL;
+ he.h_aliases = aliases;
+ he.h_aliases[0] = NULL;
+ he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
+ he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
+ return (copyandmerge(&he, NULL, af, error_num));
+ }
+
+ n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (n != 0) {
+ *error_num = NO_RECOVERY;
+ goto cleanup;
+ }
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+ tmp_err = NO_RECOVERY;
+ if (have_v6 && af == AF_INET6) {
+
+ n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V6, &by);
+ if (n == 0) {
+ he1 = hostfromname(by, AF_INET6);
+ lwres_gabnresponse_free(lwrctx, &by);
+ if (he1 == NULL) {
+ *error_num = NO_RECOVERY;
+ goto cleanup;
+ }
+ } else {
+ tmp_err = HOST_NOT_FOUND;
+ }
+ }
+
+ if (have_v4 &&
+ ((af == AF_INET) ||
+ (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
+ (he1 == NULL || (flags & AI_ALL) != 0)))) {
+ n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V4, &by);
+ if (n == 0) {
+ he2 = hostfromname(by, AF_INET);
+ lwres_gabnresponse_free(lwrctx, &by);
+ if (he2 == NULL) {
+ *error_num = NO_RECOVERY;
+ goto cleanup;
+ }
+ } else if (he1 == NULL) {
+ if (n == LWRES_R_NOTFOUND)
+ *error_num = HOST_NOT_FOUND;
+ else
+ *error_num = NO_RECOVERY;
+ goto cleanup;
+ }
+ } else
+ *error_num = tmp_err;
+
+ he3 = copyandmerge(he1, he2, af, error_num);
+
+ cleanup:
+ if (he1 != NULL)
+ lwres_freehostent(he1);
+ if (he2 != NULL)
+ lwres_freehostent(he2);
+ if (lwrctx != NULL) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ }
+ return (he3);
+}
+
+struct hostent *
+lwres_getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
+ struct hostent *he1, *he2;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gnbaresponse_t *by = NULL;
+ lwres_result_t n;
+ union {
+ const void *konst;
+ struct in6_addr *in6;
+ } u;
+
+ /*
+ * Sanity checks.
+ */
+ if (src == NULL) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ switch (af) {
+ case AF_INET:
+ if (len != INADDRSZ) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ break;
+ case AF_INET6:
+ if (len != IN6ADDRSZ) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ break;
+ default:
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ /*
+ * The de-"const"-ing game is done because at least one
+ * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_*
+ * macros in such a way that they discard the const with
+ * internal casting, and gcc ends up complaining. Rather
+ * than replacing their own (possibly optimized) definitions
+ * with our own, cleanly discarding the const is the easiest
+ * thing to do.
+ */
+ u.konst = src;
+
+ /*
+ * Look up IPv4 and IPv4 mapped/compatible addresses.
+ */
+ if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(u.in6)) ||
+ (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(u.in6)) ||
+ (af == AF_INET)) {
+ const unsigned char *cp = src;
+
+ if (af == AF_INET6)
+ cp += 12;
+ n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (n == LWRES_R_SUCCESS)
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+ if (n == LWRES_R_SUCCESS)
+ n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V4,
+ INADDRSZ, cp, &by);
+ if (n != LWRES_R_SUCCESS) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ if (n == LWRES_R_NOTFOUND)
+ *error_num = HOST_NOT_FOUND;
+ else
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ he1 = hostfromaddr(by, AF_INET, cp);
+ lwres_gnbaresponse_free(lwrctx, &by);
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ if (af != AF_INET6)
+ return (he1);
+
+ /*
+ * Convert from AF_INET to AF_INET6.
+ */
+ he2 = copyandmerge(he1, NULL, af, error_num);
+ lwres_freehostent(he1);
+ if (he2 == NULL)
+ return (NULL);
+ /*
+ * Restore original address.
+ */
+ memcpy(he2->h_addr, src, len);
+ return (he2);
+ }
+
+ /*
+ * Lookup IPv6 address.
+ */
+ if (memcmp(src, &in6addr_any, IN6ADDRSZ) == 0) {
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+
+ n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (n == LWRES_R_SUCCESS)
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+ if (n == LWRES_R_SUCCESS)
+ n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V6, IN6ADDRSZ,
+ src, &by);
+ if (n != 0) {
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+ he1 = hostfromaddr(by, AF_INET6, src);
+ lwres_gnbaresponse_free(lwrctx, &by);
+ if (he1 == NULL)
+ *error_num = NO_RECOVERY;
+ lwres_context_destroy(&lwrctx);
+ return (he1);
+}
+
+void
+lwres_freehostent(struct hostent *he) {
+ char **cpp;
+ int names = 1;
+ int addresses = 1;
+
+ free(he->h_name);
+
+ cpp = he->h_addr_list;
+ while (*cpp != NULL) {
+ free(*cpp);
+ *cpp = NULL;
+ cpp++;
+ addresses++;
+ }
+
+ cpp = he->h_aliases;
+ while (*cpp != NULL) {
+ free(*cpp);
+ cpp++;
+ names++;
+ }
+
+ free(he->h_aliases);
+ free(he->h_addr_list);
+ free(he);
+}
+
+/*
+ * Private
+ */
+
+/*
+ * Scan the interface table and set have_v4 and have_v6 depending
+ * upon whether there are IPv4 and IPv6 interface addresses.
+ *
+ * Returns:
+ * 0 on success
+ * -1 on failure.
+ */
+
+static int
+scan_interfaces(int *have_v4, int *have_v6) {
+#if 1
+ *have_v4 = *have_v6 = 1;
+ return (0);
+#else
+ struct ifconf ifc;
+ struct ifreq ifreq;
+ struct in_addr in4;
+ struct in6_addr in6;
+ char *buf = NULL, *cp, *cplim;
+ static int bufsiz = 4095;
+ int s, cpsize, n;
+
+ /*
+ * Set to zero. Used as loop terminators below.
+ */
+ *have_v4 = *have_v6 = 0;
+
+ /*
+ * Get interface list from system.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ goto err_ret;
+
+ /*
+ * Grow buffer until large enough to contain all interface
+ * descriptions.
+ */
+ for (;;) {
+ buf = malloc(bufsiz);
+ if (buf == NULL)
+ goto err_ret;
+ ifc.ifc_len = bufsiz;
+ ifc.ifc_buf = buf;
+#ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
+ /*
+ * This is a fix for IRIX OS in which the call to ioctl with
+ * the flag SIOCGIFCONF may not return an entry for all the
+ * interfaces like most flavors of Unix.
+ */
+ if (emul_ioctl(&ifc) >= 0)
+ break;
+#else
+ if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
+ /*
+ * Some OS's just return what will fit rather
+ * than set EINVAL if the buffer is too small
+ * to fit all the interfaces in. If
+ * ifc.ifc_len is too near to the end of the
+ * buffer we will grow it just in case and
+ * retry.
+ */
+ if (ifc.ifc_len + 2 * sizeof(ifreq) < bufsiz)
+ break;
+ }
+#endif
+ if ((n == -1) && errno != EINVAL)
+ goto err_ret;
+
+ if (bufsiz > 1000000)
+ goto err_ret;
+
+ free(buf);
+ bufsiz += 4096;
+ }
+
+ /*
+ * Parse system's interface list.
+ */
+ cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */
+ for (cp = buf;
+ (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
+ cp += cpsize) {
+ memcpy(&ifreq, cp, sizeof ifreq);
+#ifdef LWRES_PLATFORM_HAVESALEN
+#ifdef FIX_ZERO_SA_LEN
+ if (ifreq.ifr_addr.sa_len == 0)
+ ifreq.ifr_addr.sa_len = IN6ADDRSZ;
+#endif
+#ifdef HAVE_MINIMUM_IFREQ
+ cpsize = sizeof ifreq;
+ if (ifreq.ifr_addr.sa_len > sizeof (struct sockaddr))
+ cpsize += (int)ifreq.ifr_addr.sa_len -
+ (int)(sizeof(struct sockaddr));
+#else
+ cpsize = sizeof ifreq.ifr_name + ifreq.ifr_addr.sa_len;
+#endif /* HAVE_MINIMUM_IFREQ */
+#elif defined SIOCGIFCONF_ADDR
+ cpsize = sizeof ifreq;
+#else
+ cpsize = sizeof ifreq.ifr_name;
+ /* XXX maybe this should be a hard error? */
+ if (ioctl(s, SIOCGIFADDR, (char *)&ifreq) < 0)
+ continue;
+#endif /* LWRES_PLATFORM_HAVESALEN */
+ switch (ifreq.ifr_addr.sa_family) {
+ case AF_INET:
+ if (*have_v4 == 0) {
+ memcpy(&in4,
+ &((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr,
+ sizeof(in4));
+ if (in4.s_addr == INADDR_ANY)
+ break;
+ n = ioctl(s, SIOCGIFFLAGS, (char *)&ifreq);
+ if (n < 0)
+ break;
+ if ((ifreq.ifr_flags & IFF_UP) == 0)
+ break;
+ *have_v4 = 1;
+ }
+ break;
+ case AF_INET6:
+ if (*have_v6 == 0) {
+ memcpy(&in6,
+ &((struct sockaddr_in6 *)
+ &ifreq.ifr_addr)->sin6_addr,
+ sizeof(in6));
+ if (memcmp(&in6, &in6addr_any,
+ sizeof(in6)) == 0)
+ break;
+ n = ioctl(s, SIOCGIFFLAGS, (char *)&ifreq);
+ if (n < 0)
+ break;
+ if ((ifreq.ifr_flags & IFF_UP) == 0)
+ break;
+ *have_v6 = 1;
+ }
+ break;
+ }
+ }
+ if (buf != NULL)
+ free(buf);
+ close(s);
+ return (0);
+ err_ret:
+ if (buf != NULL)
+ free(buf);
+ if (s != -1)
+ close(s);
+ return (-1);
+#endif
+}
+
+static struct hostent *
+copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num)
+{
+ struct hostent *he = NULL;
+ int addresses = 1; /* NULL terminator */
+ int names = 1; /* NULL terminator */
+ int len = 0;
+ char **cpp, **npp;
+
+ /*
+ * Work out array sizes.
+ */
+ if (he1 != NULL) {
+ cpp = he1->h_addr_list;
+ while (*cpp != NULL) {
+ addresses++;
+ cpp++;
+ }
+ cpp = he1->h_aliases;
+ while (*cpp != NULL) {
+ names++;
+ cpp++;
+ }
+ }
+
+ if (he2 != NULL) {
+ cpp = he2->h_addr_list;
+ while (*cpp != NULL) {
+ addresses++;
+ cpp++;
+ }
+ if (he1 == NULL) {
+ cpp = he2->h_aliases;
+ while (*cpp != NULL) {
+ names++;
+ cpp++;
+ }
+ }
+ }
+
+ if (addresses == 1) {
+ *error_num = NO_ADDRESS;
+ return (NULL);
+ }
+
+ he = malloc(sizeof *he);
+ if (he == NULL)
+ goto no_recovery;
+
+ he->h_addr_list = malloc(sizeof(char *) * (addresses));
+ if (he->h_addr_list == NULL)
+ goto cleanup0;
+ memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
+
+ /*
+ * Copy addresses.
+ */
+ npp = he->h_addr_list;
+ if (he1 != NULL) {
+ cpp = he1->h_addr_list;
+ while (*cpp != NULL) {
+ *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ if (*npp == NULL)
+ goto cleanup1;
+ /*
+ * Convert to mapped if required.
+ */
+ if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
+ memcpy(*npp, in6addr_mapped,
+ sizeof in6addr_mapped);
+ memcpy(*npp + sizeof in6addr_mapped, *cpp,
+ INADDRSZ);
+ } else {
+ memcpy(*npp, *cpp,
+ (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ }
+ cpp++;
+ npp++;
+ }
+ }
+
+ if (he2 != NULL) {
+ cpp = he2->h_addr_list;
+ while (*cpp != NULL) {
+ *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ if (*npp == NULL)
+ goto cleanup1;
+ /*
+ * Convert to mapped if required.
+ */
+ if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
+ memcpy(*npp, in6addr_mapped,
+ sizeof in6addr_mapped);
+ memcpy(*npp + sizeof in6addr_mapped, *cpp,
+ INADDRSZ);
+ } else {
+ memcpy(*npp, *cpp,
+ (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ }
+ cpp++;
+ npp++;
+ }
+ }
+
+ he->h_aliases = malloc(sizeof(char *) * (names));
+ if (he->h_aliases == NULL)
+ goto cleanup1;
+ memset(he->h_aliases, 0, sizeof(char *) * (names));
+
+ /*
+ * Copy aliases.
+ */
+ npp = he->h_aliases;
+ cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases;
+ while (*cpp != NULL) {
+ len = strlen (*cpp) + 1;
+ *npp = malloc(len);
+ if (*npp == NULL)
+ goto cleanup2;
+ strcpy(*npp, *cpp);
+ npp++;
+ cpp++;
+ }
+
+ /*
+ * Copy hostname.
+ */
+ he->h_name = malloc(strlen((he1 != NULL) ?
+ he1->h_name : he2->h_name) + 1);
+ if (he->h_name == NULL)
+ goto cleanup2;
+ strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
+
+ /*
+ * Set address type and length.
+ */
+ he->h_addrtype = af;
+ he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
+ return (he);
+
+ cleanup2:
+ cpp = he->h_aliases;
+ while (*cpp != NULL) {
+ free(*cpp);
+ cpp++;
+ }
+ free(he->h_aliases);
+
+ cleanup1:
+ cpp = he->h_addr_list;
+ while (*cpp != NULL) {
+ free(*cpp);
+ *cpp = NULL;
+ cpp++;
+ }
+ free(he->h_addr_list);
+
+ cleanup0:
+ free(he);
+
+ no_recovery:
+ *error_num = NO_RECOVERY;
+ return (NULL);
+}
+
+static struct hostent *
+hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) {
+ struct hostent *he;
+ int i;
+
+ he = malloc(sizeof *he);
+ if (he == NULL)
+ goto cleanup;
+ memset(he, 0, sizeof(*he));
+
+ /*
+ * Set family and length.
+ */
+ he->h_addrtype = af;
+ switch (af) {
+ case AF_INET:
+ he->h_length = INADDRSZ;
+ break;
+ case AF_INET6:
+ he->h_length = IN6ADDRSZ;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ /*
+ * Copy name.
+ */
+ he->h_name = strdup(addr->realname);
+ if (he->h_name == NULL)
+ goto cleanup;
+
+ /*
+ * Copy aliases.
+ */
+ he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1));
+ if (he->h_aliases == NULL)
+ goto cleanup;
+ for (i = 0 ; i < addr->naliases; i++) {
+ he->h_aliases[i] = strdup(addr->aliases[i]);
+ if (he->h_aliases[i] == NULL)
+ goto cleanup;
+ }
+ he->h_aliases[i] = NULL;
+
+ /*
+ * Copy address.
+ */
+ he->h_addr_list = malloc(sizeof(char *) * 2);
+ if (he->h_addr_list == NULL)
+ goto cleanup;
+ he->h_addr_list[0] = malloc(he->h_length);
+ if (he->h_addr_list[0] == NULL)
+ goto cleanup;
+ memcpy(he->h_addr_list[0], src, he->h_length);
+ he->h_addr_list[1] = NULL;
+ return (he);
+
+ cleanup:
+ if (he != NULL && he->h_addr_list != NULL) {
+ for (i = 0; he->h_addr_list[i] != NULL; i++)
+ free(he->h_addr_list[i]);
+ free(he->h_addr_list);
+ }
+ if (he != NULL && he->h_aliases != NULL) {
+ for (i = 0; he->h_aliases[i] != NULL; i++)
+ free(he->h_aliases[i]);
+ free(he->h_aliases);
+ }
+ if (he != NULL && he->h_name != NULL)
+ free(he->h_name);
+ if (he != NULL)
+ free(he);
+ return (NULL);
+}
+
+static struct hostent *
+hostfromname(lwres_gabnresponse_t *name, int af) {
+ struct hostent *he;
+ int i;
+ lwres_addr_t *addr;
+
+ he = malloc(sizeof *he);
+ if (he == NULL)
+ goto cleanup;
+ memset(he, 0, sizeof(*he));
+
+ /*
+ * Set family and length.
+ */
+ he->h_addrtype = af;
+ switch (af) {
+ case AF_INET:
+ he->h_length = INADDRSZ;
+ break;
+ case AF_INET6:
+ he->h_length = IN6ADDRSZ;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ /*
+ * Copy name.
+ */
+ he->h_name = strdup(name->realname);
+ if (he->h_name == NULL)
+ goto cleanup;
+
+ /*
+ * Copy aliases.
+ */
+ he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1));
+ for (i = 0 ; i < name->naliases; i++) {
+ he->h_aliases[i] = strdup(name->aliases[i]);
+ if (he->h_aliases[i] == NULL)
+ goto cleanup;
+ }
+ he->h_aliases[i] = NULL;
+
+ /*
+ * Copy addresses.
+ */
+ he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1));
+ addr = LWRES_LIST_HEAD(name->addrs);
+ i = 0;
+ while (addr != NULL) {
+ he->h_addr_list[i] = malloc(he->h_length);
+ if (he->h_addr_list[i] == NULL)
+ goto cleanup;
+ memcpy(he->h_addr_list[i], addr->address, he->h_length);
+ addr = LWRES_LIST_NEXT(addr, link);
+ i++;
+ }
+ he->h_addr_list[i] = NULL;
+ return (he);
+
+ cleanup:
+ if (he != NULL && he->h_addr_list != NULL) {
+ for (i = 0; he->h_addr_list[i] != NULL; i++)
+ free(he->h_addr_list[i]);
+ free(he->h_addr_list);
+ }
+ if (he != NULL && he->h_aliases != NULL) {
+ for (i = 0; he->h_aliases[i] != NULL; i++)
+ free(he->h_aliases[i]);
+ free(he->h_aliases);
+ }
+ if (he != NULL && he->h_name != NULL)
+ free(he->h_name);
+ if (he != NULL)
+ free(he);
+ return (NULL);
+}
diff --git a/lib/liblwres/getnameinfo.c b/lib/liblwres/getnameinfo.c
new file mode 100644
index 000000000..36eea3180
--- /dev/null
+++ b/lib/liblwres/getnameinfo.c
@@ -0,0 +1,289 @@
+/*
+ * Portions Copyright (C) 1999-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: getnameinfo.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by WIDE Project and
+ * its contributors.
+ * 4. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * XXX
+ * Issues to be discussed:
+ * - Return values. There seems to be no standard for return value (RFC2553)
+ * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h>
+
+#include "assert_p.h"
+
+#define SUCCESS 0
+
+static struct afd {
+ int a_af;
+ size_t a_addrlen;
+ size_t a_socklen;
+} afdl [] = {
+ /*
+ * First entry is linked last...
+ */
+ { AF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in) },
+ { AF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6) },
+ {0, 0, 0},
+};
+
+#define ENI_NOSERVNAME 1
+#define ENI_NOHOSTNAME 2
+#define ENI_MEMORY 3
+#define ENI_SYSTEM 4
+#define ENI_FAMILY 5
+#define ENI_SALEN 6
+#define ENI_NOSOCKET 7
+
+/*
+ * The test against 0 is there to keep the Solaris compiler
+ * from complaining about "end-of-loop code not reached".
+ */
+#define ERR(code) \
+ do { result = (code); \
+ if (result != 0) goto cleanup; \
+ } while (0)
+
+int
+lwres_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
+ size_t hostlen, char *serv, size_t servlen, int flags)
+{
+ struct afd *afd;
+ struct servent *sp;
+ unsigned short port;
+#ifdef LWRES_PLATFORM_HAVESALEN
+ size_t len;
+#endif
+ int family, i;
+ const void *addr;
+ char *p;
+#if 0
+ unsigned long v4a;
+ unsigned char pfx;
+#endif
+ char numserv[sizeof("65000")];
+ char numaddr[sizeof("abcd:abcd:abcd:abcd:abcd:abcd:255.255.255.255")
+ + 1 + sizeof("4294967295")];
+ const char *proto;
+ lwres_uint32_t lwf = 0;
+ lwres_context_t *lwrctx = NULL;
+ lwres_gnbaresponse_t *by = NULL;
+ int result = SUCCESS;
+ int n;
+
+ if (sa == NULL)
+ ERR(ENI_NOSOCKET);
+
+#ifdef LWRES_PLATFORM_HAVESALEN
+ len = sa->sa_len;
+ if (len != salen)
+ ERR(ENI_SALEN);
+#endif
+
+ family = sa->sa_family;
+ for (i = 0; afdl[i].a_af; i++)
+ if (afdl[i].a_af == family) {
+ afd = &afdl[i];
+ goto found;
+ }
+ ERR(ENI_FAMILY);
+
+ found:
+ if (salen != afd->a_socklen)
+ ERR(ENI_SALEN);
+
+ switch (family) {
+ case AF_INET:
+ port = ((const struct sockaddr_in *)sa)->sin_port;
+ addr = &((const struct sockaddr_in *)sa)->sin_addr.s_addr;
+ break;
+
+ case AF_INET6:
+ port = ((const struct sockaddr_in6 *)sa)->sin6_port;
+ addr = ((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
+ break;
+
+ default:
+ port = 0;
+ addr = NULL;
+ INSIST(0);
+ }
+ proto = (flags & NI_DGRAM) ? "udp" : "tcp";
+
+ if (serv == NULL || servlen == 0) {
+ /*
+ * Caller does not want service.
+ */
+ } else if ((flags & NI_NUMERICSERV) != 0 ||
+ (sp = getservbyport(port, proto)) == NULL) {
+ sprintf(numserv, "%d", ntohs(port));
+ if ((strlen(numserv) + 1) > servlen)
+ ERR(ENI_MEMORY);
+ strcpy(serv, numserv);
+ } else {
+ if ((strlen(sp->s_name) + 1) > servlen)
+ ERR(ENI_MEMORY);
+ strcpy(serv, sp->s_name);
+ }
+
+#if 0
+ switch (sa->sa_family) {
+ case AF_INET:
+ v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+ flags |= NI_NUMERICHOST;
+ v4a >>= IN_CLASSA_NSHIFT;
+ if (v4a == 0 || v4a == IN_LOOPBACKNET)
+ flags |= NI_NUMERICHOST;
+ break;
+
+ case AF_INET6:
+ pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
+ if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
+ flags |= NI_NUMERICHOST;
+ break;
+ }
+#endif
+
+ if (host == NULL || hostlen == 0) {
+ /*
+ * What should we do?
+ */
+ } else if (flags & NI_NUMERICHOST) {
+ if (lwres_net_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ ERR(ENI_SYSTEM);
+#if defined(LWRES_HAVE_SIN6_SCOPE_ID)
+ if (afd->a_af == AF_INET6 &&
+ ((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
+ char *p = numaddr + strlen(numaddr);
+ const char *stringscope = NULL;
+#if 0
+ if ((flags & NI_NUMERICSCOPE) == 0) {
+ /*
+ * Vendors may want to add support for
+ * non-numeric scope identifier.
+ */
+ stringscope = foo;
+ }
+#endif
+ if (stringscope == NULL) {
+ snprintf(p, sizeof(numaddr) - (p - numaddr),
+ "%%%u",
+ ((const struct sockaddr_in6 *)sa)->sin6_scope_id);
+ } else {
+ snprintf(p, sizeof(numaddr) - (p - numaddr),
+ "%%%s", stringscope);
+ }
+ }
+#endif
+ if (strlen(numaddr) + 1 > hostlen)
+ ERR(ENI_MEMORY);
+ strcpy(host, numaddr);
+ } else {
+ switch (family) {
+ case AF_INET:
+ lwf = LWRES_ADDRTYPE_V4;
+ break;
+ case AF_INET6:
+ lwf = LWRES_ADDRTYPE_V6;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (n == 0)
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+
+ if (n == 0)
+ n = lwres_getnamebyaddr(lwrctx, lwf,
+ (lwres_uint16_t)afd->a_addrlen,
+ addr, &by);
+ if (n == 0) {
+ if (flags & NI_NOFQDN) {
+ p = strchr(by->realname, '.');
+ if (p)
+ *p = '\0';
+ }
+ if ((strlen(by->realname) + 1) > hostlen)
+ ERR(ENI_MEMORY);
+ strcpy(host, by->realname);
+ } else {
+ if (flags & NI_NAMEREQD)
+ ERR(ENI_NOHOSTNAME);
+ if (lwres_net_ntop(afd->a_af, addr, numaddr,
+ sizeof(numaddr))
+ == NULL)
+ ERR(ENI_NOHOSTNAME);
+ if ((strlen(numaddr) + 1) > hostlen)
+ ERR(ENI_MEMORY);
+ strcpy(host, numaddr);
+ }
+ }
+ result = SUCCESS;
+ cleanup:
+ if (by != NULL)
+ lwres_gnbaresponse_free(lwrctx, &by);
+ if (lwrctx != NULL) {
+ lwres_conf_clear(lwrctx);
+ lwres_context_destroy(&lwrctx);
+ }
+ return (result);
+}
diff --git a/lib/liblwres/getrrset.c b/lib/liblwres/getrrset.c
new file mode 100644
index 000000000..cf8359268
--- /dev/null
+++ b/lib/liblwres/getrrset.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: getrrset.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h> /* XXX #include <netdb.h> */
+
+#include "assert_p.h"
+
+unsigned int
+lwresult_to_result(lwres_result_t lwresult) {
+ switch (lwresult) {
+ case LWRES_R_SUCCESS: return (ERRSET_SUCCESS);
+ case LWRES_R_NOMEMORY: return (ERRSET_NOMEMORY);
+ case LWRES_R_NOTFOUND: return (ERRSET_NONAME);
+ case LWRES_R_TYPENOTFOUND: return (ERRSET_NODATA);
+ case LWRES_R_RETRY: return (ERRSET_RETRY);
+ default: return (ERRSET_FAIL);
+ }
+}
+
+/*
+ * malloc / calloc functions that guarantee to only
+ * return NULL if there is an error, like they used
+ * to before the ANSI C committee broke them.
+ */
+
+static void *
+sane_malloc(size_t size) {
+ if (size == 0)
+ size = 1;
+ return (malloc(size));
+}
+
+static void *
+sane_calloc(size_t number, size_t size) {
+ size_t len = number * size;
+ void *mem = sane_malloc(len);
+ if (mem != NULL)
+ memset(mem, 0, len);
+ return (mem);
+}
+
+int
+lwres_getrrsetbyname(const char *hostname, unsigned int rdclass,
+ unsigned int rdtype, unsigned int flags,
+ struct rrsetinfo **res)
+{
+ lwres_context_t *lwrctx = NULL;
+ lwres_result_t lwresult;
+ lwres_grbnresponse_t *response = NULL;
+ struct rrsetinfo *rrset = NULL;
+ unsigned int i;
+ unsigned int lwflags;
+ unsigned int result;
+
+ if (rdclass > 0xffff || rdtype > 0xffff) {
+ result = ERRSET_INVAL;
+ goto fail;
+ }
+
+ /*
+ * Don't allow queries of class or type ANY
+ */
+ if (rdclass == 0xff || rdtype == 0xff) {
+ result = ERRSET_INVAL;
+ goto fail;
+ }
+
+ lwresult = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
+ if (lwresult != LWRES_R_SUCCESS) {
+ result = lwresult_to_result(lwresult);
+ goto fail;
+ }
+ (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
+
+ /*
+ * If any input flags were defined, lwflags would be set here
+ * based on them
+ */
+ UNUSED(flags);
+ lwflags = 0;
+
+ lwresult = lwres_getrdatabyname(lwrctx, hostname,
+ (lwres_uint16_t)rdclass,
+ (lwres_uint16_t)rdtype,
+ lwflags, &response);
+ if (lwresult != LWRES_R_SUCCESS) {
+ result = lwresult_to_result(lwresult);
+ goto fail;
+ }
+
+ rrset = sane_malloc(sizeof(struct rrsetinfo));
+ if (rrset == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ rrset->rri_name = NULL;
+ rrset->rri_rdclass = response->rdclass;
+ rrset->rri_rdtype = response->rdtype;
+ rrset->rri_ttl = response->ttl;
+ rrset->rri_flags = 0;
+ rrset->rri_nrdatas = 0;
+ rrset->rri_rdatas = NULL;
+ rrset->rri_nsigs = 0;
+ rrset->rri_sigs = NULL;
+
+ rrset->rri_name = sane_malloc(response->realnamelen + 1);
+ if (rrset->rri_name == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ strncpy(rrset->rri_name, response->realname, response->realnamelen);
+ rrset->rri_name[response->realnamelen] = 0;
+
+ if ((response->flags & LWRDATA_VALIDATED) != 0)
+ rrset->rri_flags |= RRSET_VALIDATED;
+
+ rrset->rri_nrdatas = response->nrdatas;
+ rrset->rri_rdatas = sane_calloc(rrset->rri_nrdatas,
+ sizeof(struct rdatainfo));
+ if (rrset->rri_rdatas == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ for (i = 0; i < rrset->rri_nrdatas; i++) {
+ rrset->rri_rdatas[i].rdi_length = response->rdatalen[i];
+ rrset->rri_rdatas[i].rdi_data =
+ sane_malloc(rrset->rri_rdatas[i].rdi_length);
+ if (rrset->rri_rdatas[i].rdi_data == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ memcpy(rrset->rri_rdatas[i].rdi_data, response->rdatas[i],
+ rrset->rri_rdatas[i].rdi_length);
+ }
+ rrset->rri_nsigs = response->nsigs;
+ rrset->rri_sigs = sane_calloc(rrset->rri_nsigs,
+ sizeof(struct rdatainfo));
+ if (rrset->rri_sigs == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ for (i = 0; i < rrset->rri_nsigs; i++) {
+ rrset->rri_sigs[i].rdi_length = response->siglen[i];
+ rrset->rri_sigs[i].rdi_data =
+ sane_malloc(rrset->rri_sigs[i].rdi_length);
+ if (rrset->rri_sigs[i].rdi_data == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ memcpy(rrset->rri_sigs[i].rdi_data, response->sigs[i],
+ rrset->rri_sigs[i].rdi_length);
+ }
+
+ lwres_grbnresponse_free(lwrctx, &response);
+ lwres_context_destroy(&lwrctx);
+ *res = rrset;
+ return (ERRSET_SUCCESS);
+ fail:
+ if (rrset != NULL)
+ lwres_freerrset(rrset);
+ if (response != NULL)
+ lwres_grbnresponse_free(lwrctx, &response);
+ if (lwrctx != NULL)
+ lwres_context_destroy(&lwrctx);
+ return (result);
+
+}
+
+void
+lwres_freerrset(struct rrsetinfo *rrset) {
+ unsigned int i;
+ for (i = 0; i < rrset->rri_nrdatas; i++) {
+ if (rrset->rri_rdatas[i].rdi_data == NULL)
+ break;
+ free(rrset->rri_rdatas[i].rdi_data);
+ }
+ free(rrset->rri_rdatas);
+ for (i = 0; i < rrset->rri_nsigs; i++) {
+ if (rrset->rri_sigs[i].rdi_data == NULL)
+ break;
+ free(rrset->rri_sigs[i].rdi_data);
+ }
+ free(rrset->rri_sigs);
+ free(rrset->rri_name);
+ free(rrset);
+}
+
diff --git a/lib/liblwres/getrrset2.c b/lib/liblwres/getrrset2.c
new file mode 100644
index 000000000..031021e06
--- /dev/null
+++ b/lib/liblwres/getrrset2.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: getrrset2.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/netdb.h> /* XXX #include <netdb.h> */
+
+#include <lwres/async.h>
+
+#include "assert_p.h"
+
+int
+lwres_getrrsetbyname_async(const char *hostname, unsigned int rdclass,
+ unsigned int rdtype, unsigned int flags,
+ struct rrsetinfo **res)
+{
+ int ret, ret2;
+ lwres_context_t *ctx = NULL;
+ struct lwres_async_state las;
+ struct lwres_async_state *plas;
+ struct timeval timeout;
+ fd_set readfds;
+ int sock;
+
+ ret = lwres_async_init(&ctx);
+ if(ret != ERRSET_SUCCESS) {
+ return(ret);
+ }
+
+ ret = lwres_getrrsetbyname_init(hostname, rdclass,
+ rdtype, flags,
+ ctx, &las);
+
+ if(ret != ERRSET_SUCCESS) {
+ return ret;
+ }
+
+ again:
+
+ lwres_getrrsetbyname_xmit(ctx, &las);
+ timeout.tv_sec = lwres_async_timeout(ctx);
+ sock = lwres_async_fd(ctx);
+
+ FD_ZERO(&readfds);
+ FD_SET(sock, &readfds);
+ ret2 = select(sock + 1, &readfds, NULL, NULL, &timeout);
+
+ /*
+ * What happened with select?
+ */
+ if (ret2 < 0) {
+ ret = LWRES_R_IOERROR;
+ goto out3;
+ }
+ if (ret2 == 0) {
+ ret = LWRES_R_TIMEOUT;
+ goto out3;
+ }
+
+ ret = lwres_getrrsetbyname_read(&plas, ctx, res);
+ if(ret == LWRES_R_RETRY) {
+ /* XXX retransmit */
+ goto again;
+ }
+
+ out3:
+ /* clean stuff up */
+
+ out:
+ if (ctx != NULL)
+ lwres_context_destroy(&ctx);
+
+ return ret;
+}
+
diff --git a/lib/liblwres/herror.c b/lib/liblwres/herror.c
new file mode 100644
index 000000000..7a8bcb2bd
--- /dev/null
+++ b/lib/liblwres/herror.c
@@ -0,0 +1,101 @@
+/*
+ * Portions Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] =
+ "$Id: herror.c,v 1.1 2004/03/15 20:35:25 as Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <lwres/netdb.h>
+#include <lwres/platform.h>
+
+LIBLWRES_EXTERNAL_DATA int lwres_h_errno;
+
+/*
+ * these have never been declared in any header file so make them static
+ */
+
+static const char *h_errlist[] = {
+ "Resolver Error 0 (no error)",
+ "Unknown host", /* 1 HOST_NOT_FOUND */
+ "Host name lookup failure", /* 2 TRY_AGAIN */
+ "Unknown server error", /* 3 NO_RECOVERY */
+ "No address associated with name", /* 4 NO_ADDRESS */
+};
+
+static int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] };
+
+
+/*
+ * herror --
+ * print the error indicated by the h_errno value.
+ */
+void
+lwres_herror(const char *s) {
+ fprintf(stderr, "%s: %s\n", s, lwres_hstrerror(lwres_h_errno));
+}
+
+/*
+ * hstrerror --
+ * return the string associated with a given "host" errno value.
+ */
+const char *
+lwres_hstrerror(int err) {
+ if (err < 0)
+ return ("Resolver internal error");
+ else if (err < h_nerr)
+ return (h_errlist[err]);
+ return ("Unknown resolver error");
+}
diff --git a/lib/liblwres/include/lwres/async.h b/lib/liblwres/include/lwres/async.h
new file mode 100644
index 000000000..6715afaed
--- /dev/null
+++ b/lib/liblwres/include/lwres/async.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2003 Michael Richardson
+ * Contributed by Michael Richardson <mcr@freeswan.org> while working
+ * on the Linux FreeS/WAN project in 2003.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: async.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_ASYNC_H
+#define LWRES_ASYNC_H 1
+
+#include <lwres/lwres.h>
+
+/*
+ * support for asynchronous requests to lwres port
+ */
+struct lwres_async_state {
+ struct lwres_async_state *next;
+
+ lwres_buffer_t b_in, b_out;
+ lwres_uint32_t serial;
+ int opcode;
+
+ int (*callback)(void *uctx, struct rrsetinfo *res);
+ void *uctx;
+};
+
+
+
+/*
+ * The calls for asynchronous requests.
+ */
+
+int lwres_async_init(lwres_context_t **pctx);
+
+int lwres_getrrsetbyname_init(const char *hostname, unsigned int rdclass,
+ unsigned int rdtype, unsigned int flags,
+ lwres_context_t *ctx,
+ struct lwres_async_state *las);
+
+int lwres_getrrsetbyname_xmit(lwres_context_t *ctx,
+ struct lwres_async_state *las);
+
+unsigned long lwres_async_timeout(lwres_context_t *ctx);
+
+int lwres_async_fd(lwres_context_t *ctx);
+
+int lwres_getrrsetbyname_read(struct lwres_async_state **plas,
+ lwres_context_t *ctx,
+ struct rrsetinfo **res);
+
+int lwres_getrrsetbyname_async(const char *hostname, unsigned int rdclass,
+ unsigned int rdtype, unsigned int flags,
+ struct rrsetinfo **res);
+
+#endif /* LWRES_ASYNC_H */
+
+
+
+
+
+
+
+
+
diff --git a/lib/liblwres/include/lwres/context.h b/lib/liblwres/include/lwres/context.h
new file mode 100644
index 000000000..55ca3c7fb
--- /dev/null
+++ b/lib/liblwres/include/lwres/context.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: context.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_CONTEXT_H
+#define LWRES_CONTEXT_H 1
+
+#include <stddef.h>
+
+#include <lwres/lang.h>
+#include <lwres/int.h>
+#include <lwres/result.h>
+
+/*
+ * Used to set various options such as timeout, authentication, etc
+ */
+typedef struct lwres_context lwres_context_t;
+
+LWRES_LANG_BEGINDECLS
+
+typedef void *(*lwres_malloc_t)(void *arg, size_t length);
+typedef void (*lwres_free_t)(void *arg, void *mem, size_t length);
+
+/*
+ * XXXMLG
+ *
+ * Make the server reload /etc/resolv.conf periodically.
+ *
+ * Make the server do sortlist/searchlist.
+ *
+ * Client side can disable the search/sortlist processing.
+ *
+ * Use an array of addresses/masks and searchlist for client-side, and
+ * if added to the client disable the processing on the server.
+ *
+ * Share /etc/resolv.conf data between contexts.
+ */
+
+/*
+ * _SERVERMODE
+ * Don't allocate and connect a socket to the server, since the
+ * caller _is_ a server.
+ */
+#define LWRES_CONTEXT_SERVERMODE 0x00000001U
+
+lwres_result_t
+lwres_context_create(lwres_context_t **contextp, void *arg,
+ lwres_malloc_t malloc_function,
+ lwres_free_t free_function,
+ unsigned int flags);
+/*
+ * Allocate a lwres context. This is used in all lwres calls.
+ *
+ * Memory management can be replaced here by passing in two functions.
+ * If one is non-NULL, they must both be non-NULL. "arg" is passed to
+ * these functions.
+ *
+ * Contexts are not thread safe. Document at the top of the file.
+ * XXXMLG
+ *
+ * If they are NULL, the standard malloc() and free() will be used.
+ *
+ * Requires:
+ *
+ * contextp != NULL && contextp == NULL.
+ *
+ * Returns:
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+
+void
+lwres_context_destroy(lwres_context_t **contextp);
+/*
+ * Frees all memory associated with a lwres context.
+ *
+ * Requires:
+ *
+ * contextp != NULL && contextp == NULL.
+ */
+
+lwres_uint32_t
+lwres_context_nextserial(lwres_context_t *ctx);
+/*
+ * XXXMLG Document
+ */
+
+void
+lwres_context_initserial(lwres_context_t *ctx, lwres_uint32_t serial);
+
+void
+lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len);
+
+void *
+lwres_context_allocmem(lwres_context_t *ctx, size_t len);
+
+int
+lwres_context_getsocket(lwres_context_t *ctx);
+
+lwres_result_t
+lwres_context_send(lwres_context_t *ctx,
+ void *sendbase, int sendlen);
+
+lwres_result_t
+lwres_context_recv(lwres_context_t *ctx,
+ void *recvbase, int recvlen,
+ int *recvd_len);
+
+lwres_result_t
+lwres_context_sendrecv(lwres_context_t *ctx,
+ void *sendbase, int sendlen,
+ void *recvbase, int recvlen,
+ int *recvd_len);
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_CONTEXT_H */
+
diff --git a/lib/liblwres/include/lwres/int.h b/lib/liblwres/include/lwres/int.h
new file mode 100644
index 000000000..470372e77
--- /dev/null
+++ b/lib/liblwres/include/lwres/int.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: int.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_INT_H
+#define LWRES_INT_H 1
+
+typedef char lwres_int8_t;
+typedef unsigned char lwres_uint8_t;
+typedef short lwres_int16_t;
+typedef unsigned short lwres_uint16_t;
+typedef int lwres_int32_t;
+typedef unsigned int lwres_uint32_t;
+typedef long long lwres_int64_t;
+typedef unsigned long long lwres_uint64_t;
+
+#endif /* LWRES_INT_H */
diff --git a/lib/liblwres/include/lwres/ipv6.h b/lib/liblwres/include/lwres/ipv6.h
new file mode 100644
index 000000000..ee7bc0743
--- /dev/null
+++ b/lib/liblwres/include/lwres/ipv6.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ipv6.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_IPV6_H
+#define LWRES_IPV6_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * IPv6 definitions for systems which do not support IPv6.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <lwres/int.h>
+#include <lwres/platform.h>
+
+/***
+ *** Types.
+ ***/
+
+struct in6_addr {
+ union {
+ lwres_uint8_t _S6_u8[16];
+ lwres_uint16_t _S6_u16[8];
+ lwres_uint32_t _S6_u32[4];
+ } _S6_un;
+};
+#define s6_addr _S6_un._S6_u8
+#define s6_addr8 _S6_un._S6_u8
+#define s6_addr16 _S6_un._S6_u16
+#define s6_addr32 _S6_un._S6_u32
+
+#define IN6ADDR_ANY_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
+#define IN6ADDR_LOOPBACK_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}}
+
+LIBLWRES_EXTERNAL_DATA extern const struct in6_addr in6addr_any;
+LIBLWRES_EXTERNAL_DATA extern const struct in6_addr in6addr_loopback;
+
+struct sockaddr_in6 {
+#ifdef LWRES_PLATFORM_HAVESALEN
+ lwres_uint8_t sin6_len;
+ lwres_uint8_t sin6_family;
+#else
+ lwres_uint16_t sin6_family;
+#endif
+ lwres_uint16_t sin6_port;
+ lwres_uint32_t sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ lwres_uint32_t sin6_scope_id;
+};
+
+#ifdef LWRES_PLATFORM_HAVESALEN
+#define SIN6_LEN 1
+#endif
+
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr; /* src/dst IPv6 address */
+ unsigned int ipi6_ifindex; /* send/recv interface index */
+};
+
+/*
+ * Unspecified
+ */
+#define IN6_IS_ADDR_UNSPECIFIED(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] == 0))
+
+/*
+ * Loopback
+ */
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] == htonl(1)))
+
+/*
+ * IPv4 compatible
+ */
+#define IN6_IS_ADDR_V4COMPAT(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == 0) && \
+ ((a)->s6_addr32[3] != 0) && \
+ ((a)->s6_addr32[3] != htonl(1)))
+
+/*
+ * Mapped
+ */
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ (((a)->s6_addr32[0] == 0) && \
+ ((a)->s6_addr32[1] == 0) && \
+ ((a)->s6_addr32[2] == htonl(0x0000ffff)))
+
+#endif /* LWRES_IPV6_H */
diff --git a/lib/liblwres/include/lwres/lang.h b/lib/liblwres/include/lwres/lang.h
new file mode 100644
index 000000000..1de35fd91
--- /dev/null
+++ b/lib/liblwres/include/lwres/lang.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lang.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_LANG_H
+#define LWRES_LANG_H 1
+
+#ifdef __cplusplus
+#define LWRES_LANG_BEGINDECLS extern "C" {
+#define LWRES_LANG_ENDDECLS }
+#else
+#define LWRES_LANG_BEGINDECLS
+#define LWRES_LANG_ENDDECLS
+#endif
+
+#endif /* LWRES_LANG_H */
diff --git a/lib/liblwres/include/lwres/list.h b/lib/liblwres/include/lwres/list.h
new file mode 100644
index 000000000..e90a1b55a
--- /dev/null
+++ b/lib/liblwres/include/lwres/list.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 1997-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: list.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_LIST_H
+#define LWRES_LIST_H 1
+
+#define LWRES_LIST(type) struct { type *head, *tail; }
+#define LWRES_LIST_INIT(list) \
+ do { (list).head = NULL; (list).tail = NULL; } while (0)
+
+#define LWRES_LINK(type) struct { type *prev, *next; }
+#define LWRES_LINK_INIT(elt, link) \
+ do { \
+ (elt)->link.prev = (void *)(-1); \
+ (elt)->link.next = (void *)(-1); \
+ } while (0)
+#define LWRES_LINK_LINKED(elt, link) \
+ ((void *)((elt)->link.prev) != (void *)(-1))
+
+#define LWRES_LIST_HEAD(list) ((list).head)
+#define LWRES_LIST_TAIL(list) ((list).tail)
+#define LWRES_LIST_EMPTY(list) LWRES_TF((list).head == NULL)
+
+#define LWRES_LIST_PREPEND(list, elt, link) \
+ do { \
+ if ((list).head != NULL) \
+ (list).head->link.prev = (elt); \
+ else \
+ (list).tail = (elt); \
+ (elt)->link.prev = NULL; \
+ (elt)->link.next = (list).head; \
+ (list).head = (elt); \
+ } while (0)
+
+#define LWRES_LIST_APPEND(list, elt, link) \
+ do { \
+ if ((list).tail != NULL) \
+ (list).tail->link.next = (elt); \
+ else \
+ (list).head = (elt); \
+ (elt)->link.prev = (list).tail; \
+ (elt)->link.next = NULL; \
+ (list).tail = (elt); \
+ } while (0)
+
+#define LWRES_LIST_UNLINK(list, elt, link) \
+ do { \
+ if ((elt)->link.next != NULL) \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ else \
+ (list).tail = (elt)->link.prev; \
+ if ((elt)->link.prev != NULL) \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ else \
+ (list).head = (elt)->link.next; \
+ (elt)->link.prev = (void *)(-1); \
+ (elt)->link.next = (void *)(-1); \
+ } while (0)
+
+#define LWRES_LIST_PREV(elt, link) ((elt)->link.prev)
+#define LWRES_LIST_NEXT(elt, link) ((elt)->link.next)
+
+#define LWRES_LIST_INSERTBEFORE(list, before, elt, link) \
+ do { \
+ if ((before)->link.prev == NULL) \
+ LWRES_LIST_PREPEND(list, elt, link); \
+ else { \
+ (elt)->link.prev = (before)->link.prev; \
+ (before)->link.prev = (elt); \
+ (elt)->link.prev->link.next = (elt); \
+ (elt)->link.next = (before); \
+ } \
+ } while (0)
+
+#define LWRES_LIST_INSERTAFTER(list, after, elt, link) \
+ do { \
+ if ((after)->link.next == NULL) \
+ LWRES_LIST_APPEND(list, elt, link); \
+ else { \
+ (elt)->link.next = (after)->link.next; \
+ (after)->link.next = (elt); \
+ (elt)->link.next->link.prev = (elt); \
+ (elt)->link.prev = (after); \
+ } \
+ } while (0)
+
+#define LWRES_LIST_APPENDLIST(list1, list2, link) \
+ do { \
+ if (LWRES_LIST_EMPTY(list1)) \
+ (list1) = (list2); \
+ else if (!LWRES_LIST_EMPTY(list2)) { \
+ (list1).tail->link.next = (list2).head; \
+ (list2).head->link.prev = (list1).tail; \
+ (list1).tail = (list2).tail; \
+ } \
+ (list2).head = NULL; \
+ (list2).tail = NULL; \
+ } while (0)
+
+#define LWRES_LIST_ENQUEUE(list, elt, link) LWRES_LIST_APPEND(list, elt, link)
+#define LWRES_LIST_DEQUEUE(list, elt, link) LWRES_LIST_UNLINK(list, elt, link)
+
+#endif /* LWRES_LIST_H */
diff --git a/lib/liblwres/include/lwres/lwbuffer.h b/lib/liblwres/include/lwres/lwbuffer.h
new file mode 100644
index 000000000..7486e8bc3
--- /dev/null
+++ b/lib/liblwres/include/lwres/lwbuffer.h
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwbuffer.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_LWBUFFER_H
+#define LWRES_LWBUFFER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * Buffers
+ *
+ * A buffer is a region of memory, together with a set of related subregions.
+ * Buffers are used for parsing and I/O operations.
+ *
+ * The 'used region' and the 'available' region are disjoint, and their
+ * union is the buffer's region. The used region extends from the beginning
+ * of the buffer region to the last used byte. The available region
+ * extends from one byte greater than the last used byte to the end of the
+ * buffer's region. The size of the used region can be changed using various
+ * buffer commands. Initially, the used region is empty.
+ *
+ * The used region is further subdivided into two disjoint regions: the
+ * 'consumed region' and the 'remaining region'. The union of these two
+ * regions is the used region. The consumed region extends from the beginning
+ * of the used region to the byte before the 'current' offset (if any). The
+ * 'remaining' region the current pointer to the end of the used
+ * region. The size of the consumed region can be changed using various
+ * buffer commands. Initially, the consumed region is empty.
+ *
+ * The 'active region' is an (optional) subregion of the remaining region.
+ * It extends from the current offset to an offset in the remaining region
+ * that is selected with lwres_buffer_setactive(). Initially, the active
+ * region is empty. If the current offset advances beyond the chosen offset,
+ * the active region will also be empty.
+ *
+ * /----- used region -----\/-- available --\
+ * +----------------------------------------+
+ * | consumed | remaining | |
+ * +----------------------------------------+
+ * a b c d e
+ *
+ * a == base of buffer.
+ * b == current pointer. Can be anywhere between a and d.
+ * c == active pointer. Meaningful between b and d.
+ * d == used pointer.
+ * e == length of buffer.
+ *
+ * a-e == entire (length) of buffer.
+ * a-d == used region.
+ * a-b == consumed region.
+ * b-d == remaining region.
+ * b-c == optional active region.
+ *
+ * The following invariants are maintained by all routines:
+ *
+ * length > 0
+ *
+ * base is a valid pointer to length bytes of memory
+ *
+ * 0 <= used <= length
+ *
+ * 0 <= current <= used
+ *
+ * 0 <= active <= used
+ * (although active < current implies empty active region)
+ *
+ * MP:
+ * Buffers have no synchronization. Clients must ensure exclusive
+ * access.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * Memory: 1 pointer + 6 unsigned integers per buffer.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <lwres/lang.h>
+#include <lwres/int.h>
+
+LWRES_LANG_BEGINDECLS
+
+/***
+ *** Magic numbers
+ ***/
+#define LWRES_BUFFER_MAGIC 0x4275663fU /* Buf?. */
+
+#define LWRES_BUFFER_VALID(b) ((b) != NULL && \
+ (b)->magic == LWRES_BUFFER_MAGIC)
+
+/*
+ * The following macros MUST be used only on valid buffers. It is the
+ * caller's responsibility to ensure this by using the LWRES_BUFFER_VALID
+ * check above, or by calling another lwres_buffer_*() function (rather than
+ * another macro.)
+ */
+
+/*
+ * Get the length of the used region of buffer "b"
+ */
+#define LWRES_BUFFER_USEDCOUNT(b) ((b)->used)
+
+/*
+ * Get the length of the available region of buffer "b"
+ */
+#define LWRES_BUFFER_AVAILABLECOUNT(b) ((b)->length - (b)->used)
+
+#define LWRES_BUFFER_REMAINING(b) ((b)->used - (b)->current)
+
+/*
+ * Note that the buffer structure is public. This is principally so buffer
+ * operations can be implemented using macros. Applications are strongly
+ * discouraged from directly manipulating the structure.
+ */
+
+typedef struct lwres_buffer lwres_buffer_t;
+struct lwres_buffer {
+ unsigned int magic;
+ unsigned char *base;
+ /* The following integers are byte offsets from 'base'. */
+ unsigned int length;
+ unsigned int used;
+ unsigned int current;
+ unsigned int active;
+};
+
+/***
+ *** Functions
+ ***/
+
+void
+lwres_buffer_init(lwres_buffer_t *b, void *base, unsigned int length);
+/*
+ * Make 'b' refer to the 'length'-byte region starting at base.
+ *
+ * Requires:
+ *
+ * 'length' > 0
+ *
+ * 'base' is a pointer to a sequence of 'length' bytes.
+ *
+ */
+
+void
+lwres_buffer_invalidate(lwres_buffer_t *b);
+/*
+ * Make 'b' an invalid buffer.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * Ensures:
+ * If assertion checking is enabled, future attempts to use 'b' without
+ * calling lwres_buffer_init() on it will cause an assertion failure.
+ */
+
+void
+lwres_buffer_add(lwres_buffer_t *b, unsigned int n);
+/*
+ * Increase the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * used + n <= length
+ *
+ */
+
+void
+lwres_buffer_subtract(lwres_buffer_t *b, unsigned int n);
+/*
+ * Decrease the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * used >= n
+ *
+ */
+
+void
+lwres_buffer_clear(lwres_buffer_t *b);
+/*
+ * Make the used region empty.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ * used = 0
+ *
+ */
+
+void
+lwres_buffer_first(lwres_buffer_t *b);
+/*
+ * Make the consumed region empty.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ * current == 0
+ *
+ */
+
+void
+lwres_buffer_forward(lwres_buffer_t *b, unsigned int n);
+/*
+ * Increase the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * current + n <= used
+ *
+ */
+
+void
+lwres_buffer_back(lwres_buffer_t *b, unsigned int n);
+/*
+ * Decrease the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer
+ *
+ * n <= current
+ *
+ */
+
+lwres_uint8_t
+lwres_buffer_getuint8(lwres_buffer_t *b);
+/*
+ * Read an unsigned 8-bit integer from 'b' and return it.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer.
+ *
+ * The length of the available region of 'b' is at least 1.
+ *
+ * Ensures:
+ *
+ * The current pointer in 'b' is advanced by 1.
+ *
+ * Returns:
+ *
+ * A 8-bit unsigned integer.
+ */
+
+void
+lwres_buffer_putuint8(lwres_buffer_t *b, lwres_uint8_t val);
+/*
+ * Store an unsigned 8-bit integer from 'val' into 'b'.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * The length of the unused region of 'b' is at least 1.
+ *
+ * Ensures:
+ * The used pointer in 'b' is advanced by 1.
+ */
+
+lwres_uint16_t
+lwres_buffer_getuint16(lwres_buffer_t *b);
+/*
+ * Read an unsigned 16-bit integer in network byte order from 'b', convert
+ * it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer.
+ *
+ * The length of the available region of 'b' is at least 2.
+ *
+ * Ensures:
+ *
+ * The current pointer in 'b' is advanced by 2.
+ *
+ * Returns:
+ *
+ * A 16-bit unsigned integer.
+ */
+
+void
+lwres_buffer_putuint16(lwres_buffer_t *b, lwres_uint16_t val);
+/*
+ * Store an unsigned 16-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * The length of the unused region of 'b' is at least 2.
+ *
+ * Ensures:
+ * The used pointer in 'b' is advanced by 2.
+ */
+
+lwres_uint32_t
+lwres_buffer_getuint32(lwres_buffer_t *b);
+/*
+ * Read an unsigned 32-bit integer in network byte order from 'b', convert
+ * it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ * 'b' is a valid buffer.
+ *
+ * The length of the available region of 'b' is at least 2.
+ *
+ * Ensures:
+ *
+ * The current pointer in 'b' is advanced by 2.
+ *
+ * Returns:
+ *
+ * A 32-bit unsigned integer.
+ */
+
+void
+lwres_buffer_putuint32(lwres_buffer_t *b, lwres_uint32_t val);
+/*
+ * Store an unsigned 32-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * The length of the unused region of 'b' is at least 4.
+ *
+ * Ensures:
+ * The used pointer in 'b' is advanced by 4.
+ */
+
+void
+lwres_buffer_putmem(lwres_buffer_t *b, const unsigned char *base,
+ unsigned int length);
+/*
+ * Copy 'length' bytes of memory at 'base' into 'b'.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * 'base' points to 'length' bytes of valid memory.
+ *
+ */
+
+void
+lwres_buffer_getmem(lwres_buffer_t *b, unsigned char *base,
+ unsigned int length);
+/*
+ * Copy 'length' bytes of memory from 'b' into 'base'.
+ *
+ * Requires:
+ * 'b' is a valid buffer.
+ *
+ * 'base' points to at least 'length' bytes of valid memory.
+ *
+ * 'b' have at least 'length' bytes remaining.
+ */
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_LWBUFFER_H */
diff --git a/lib/liblwres/include/lwres/lwpacket.h b/lib/liblwres/include/lwres/lwpacket.h
new file mode 100644
index 000000000..a0d216e57
--- /dev/null
+++ b/lib/liblwres/include/lwres/lwpacket.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 1999-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwpacket.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_LWPACKET_H
+#define LWRES_LWPACKET_H 1
+
+#include <lwres/lang.h>
+#include <lwres/lwbuffer.h>
+#include <lwres/result.h>
+
+typedef struct lwres_lwpacket lwres_lwpacket_t;
+
+struct lwres_lwpacket {
+ lwres_uint32_t length;
+ lwres_uint16_t version;
+ lwres_uint16_t pktflags;
+ lwres_uint32_t serial;
+ lwres_uint32_t opcode;
+ lwres_uint32_t result;
+ lwres_uint32_t recvlength;
+ lwres_uint16_t authtype;
+ lwres_uint16_t authlength;
+};
+
+#define LWRES_LWPACKET_LENGTH (4 * 5 + 2 * 4)
+
+#define LWRES_LWPACKETFLAG_RESPONSE 0x0001U /* if set, pkt is a response */
+
+
+#define LWRES_LWPACKETVERSION_0 0
+
+/*
+ * "length" is the overall packet length, including the entire packet header.
+ *
+ * "version" specifies the header format. Currently, there is only one
+ * format, LWRES_LWPACKETVERSION_0.
+ *
+ * "flags" specifies library-defined flags for this packet. None of these
+ * are definable by the caller, but library-defined values can be set by
+ * the caller. For example, one bit in this field indicates if the packet
+ * is a request or a response.
+ *
+ * "serial" is set by the requestor and is returned in all replies. If two
+ * packets from the same source have the same serial number and are from
+ * the same source, they are assumed to be duplicates and the latter ones
+ * may be dropped. (The library does not do this by default on replies, but
+ * does so on requests.)
+ *
+ * "opcode" is application defined. Opcodes between 0x04000000 and 0xffffffff
+ * are application defined. Opcodes between 0x00000000 and 0x03ffffff are
+ * reserved for library use.
+ *
+ * "result" is application defined, and valid only on replies.
+ * Results between 0x04000000 and 0xffffffff are application defined.
+ * Results between 0x00000000 and 0x03ffffff are reserved for library use.
+ * (This is the same reserved range defined in <isc/resultclass.h>, so it
+ * would be trivial to map ISC_R_* result codes into packet result codes
+ * when appropriate.)
+ *
+ * "recvlength" is set to the maximum buffer size that the receiver can
+ * handle on requests, and the size of the buffer needed to satisfy a request
+ * when the buffer is too large for replies.
+ *
+ * "authtype" is the packet level auth type used.
+ * Authtypes between 0x1000 and 0xffff are application defined. Authtypes
+ * between 0x0000 and 0x0fff are reserved for library use. This is currently
+ * unused and MUST be set to zero.
+ *
+ * "authlen" is the length of the authentication data. See the specific
+ * authtypes for more information on what is contained in this field. This
+ * is currently unused, and MUST be set to zero.
+ *
+ * The remainder of the packet consists of two regions, one described by
+ * "authlen" and one of "length - authlen - sizeof(lwres_lwpacket_t)".
+ *
+ * That is:
+ *
+ * pkt header
+ * authlen bytes of auth information
+ * data bytes
+ */
+
+/*
+ * Currently defined opcodes:
+ *
+ * NOOP. Success is always returned, with the packet contents echoed.
+ *
+ * GETADDRSBYNAME. Return all known addresses for a given name.
+ * This may return NIS or /etc/hosts info as well as DNS
+ * information. Flags will be provided to indicate ip4/ip6
+ * addresses are desired.
+ *
+ * GETNAMEBYADDR. Return the hostname for the given address. Once
+ * again, it will return data from multiple sources.
+ */
+
+LWRES_LANG_BEGINDECLS
+
+/* XXXMLG document */
+lwres_result_t
+lwres_lwpacket_renderheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt);
+
+lwres_result_t
+lwres_lwpacket_parseheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt);
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_LWPACKET_H */
diff --git a/lib/liblwres/include/lwres/lwres.h b/lib/liblwres/include/lwres/lwres.h
new file mode 100644
index 000000000..e819c8b68
--- /dev/null
+++ b/lib/liblwres/include/lwres/lwres.h
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwres.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_LWRES_H
+#define LWRES_LWRES_H 1
+
+#include <stdio.h>
+
+#include <lwres/context.h>
+#include <lwres/lang.h>
+#include <lwres/list.h>
+#include <lwres/lwpacket.h>
+
+/*
+ * Design notes:
+ *
+ * Each opcode has two structures and three functions which operate on each
+ * structure. For example, using the "no operation/ping" opcode as an
+ * example:
+ *
+ * lwres_nooprequest_t:
+ *
+ * lwres_nooprequest_render() takes a lwres_nooprequest_t and
+ * and renders it into wire format, storing the allocated
+ * buffer information in a passed-in buffer. When this buffer
+ * is no longer needed, it must be freed by
+ * lwres_context_freemem(). All other memory used by the
+ * caller must be freed manually, including the
+ * lwres_nooprequest_t passed in.
+ *
+ * lwres_nooprequest_parse() takes a wire format message and
+ * breaks it out into a lwres_nooprequest_t. The structure
+ * must be freed via lwres_nooprequest_free() when it is no longer
+ * needed.
+ *
+ * lwres_nooprequest_free() releases into the lwres_context_t
+ * any space allocated during parsing.
+ *
+ * lwres_noopresponse_t:
+ *
+ * The functions used are similar to the three used for
+ * requests, just with different names.
+ *
+ * Typically, the client will use request_render, response_parse, and
+ * response_free, while the daemon will use request_parse, response_render,
+ * and request_free.
+ *
+ * The basic flow of a typical client is:
+ *
+ * fill in a request_t, and call the render function.
+ *
+ * Transmit the buffer returned to the daemon.
+ *
+ * Wait for a response.
+ *
+ * When a response is received, parse it into a response_t.
+ *
+ * free the request buffer using lwres_context_freemem().
+ *
+ * free the response structure and its associated buffer using
+ * response_free().
+ */
+
+#define LWRES_UDP_PORT 921
+#define LWRES_RECVLENGTH 16384
+#define LWRES_ADDR_MAXLEN 16 /* changing this breaks ABI */
+#define LWRES_RESOLV_CONF "/etc/resolv.conf"
+
+/*
+ * Flags.
+ *
+ * These flags are only relevant to rrset queries.
+ *
+ * TRUSTNOTREQUIRED: DNSSEC is not required (input)
+ * SECUREDATA: The data was crypto-verified with DNSSEC (output)
+ *
+ */
+#define LWRES_FLAG_TRUSTNOTREQUIRED 0x00000001U
+#define LWRES_FLAG_SECUREDATA 0x00000002U
+
+/*
+ * no-op
+ */
+#define LWRES_OPCODE_NOOP 0x00000000U
+
+typedef struct {
+ /* public */
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_nooprequest_t;
+
+typedef struct {
+ /* public */
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_noopresponse_t;
+
+/*
+ * get addresses by name
+ */
+#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
+
+typedef struct lwres_addr lwres_addr_t;
+typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
+
+struct lwres_addr {
+ lwres_uint32_t family;
+ lwres_uint16_t length;
+ unsigned char address[LWRES_ADDR_MAXLEN];
+ LWRES_LINK(lwres_addr_t) link;
+};
+
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint32_t addrtypes;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_gabnrequest_t;
+
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ /* if base != NULL, it will be freed when this structure is freed. */
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+
+/*
+ * get name by address
+ */
+#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_addr_t addr;
+} lwres_gnbarequest_t;
+
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ /* if base != NULL, it will be freed when this structure is freed. */
+ void *base;
+ size_t baselen;
+} lwres_gnbaresponse_t;
+
+/*
+ * get rdata by name
+ */
+#define LWRES_OPCODE_GETRDATABYNAME 0x00010003U
+
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint16_t rdclass;
+ lwres_uint16_t rdtype;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_grbnrequest_t;
+
+typedef struct {
+ /* public */
+ lwres_uint32_t flags;
+ lwres_uint16_t rdclass;
+ lwres_uint16_t rdtype;
+ lwres_uint32_t ttl;
+ lwres_uint16_t nrdatas;
+ lwres_uint16_t nsigs;
+ char *realname;
+ lwres_uint16_t realnamelen;
+ unsigned char **rdatas;
+ lwres_uint16_t *rdatalen;
+ unsigned char **sigs;
+ lwres_uint16_t *siglen;
+ /* if base != NULL, it will be freed when this structure is freed. */
+ void *base;
+ size_t baselen;
+} lwres_grbnresponse_t;
+
+#define LWRDATA_VALIDATED 0x00000001
+
+/*
+ * resolv.conf data
+ */
+
+#define LWRES_CONFMAXNAMESERVERS 3 /* max 3 "nameserver" entries */
+#define LWRES_CONFMAXLWSERVERS 1 /* max 1 "lwserver" entry */
+#define LWRES_CONFMAXSEARCH 8 /* max 8 domains in "search" entry */
+#define LWRES_CONFMAXLINELEN 256 /* max size of a line */
+#define LWRES_CONFMAXSORTLIST 10
+typedef struct {
+ lwres_context_t *lwctx;
+ lwres_addr_t nameservers[LWRES_CONFMAXNAMESERVERS];
+ lwres_uint8_t nsnext; /* index for next free slot */
+
+ lwres_addr_t lwservers[LWRES_CONFMAXLWSERVERS];
+ lwres_uint8_t lwnext; /* index for next free slot */
+
+ char *domainname;
+
+ char *search[LWRES_CONFMAXSEARCH];
+ lwres_uint8_t searchnxt; /* index for next free slot */
+
+ struct {
+ lwres_addr_t addr;
+ /* mask has a non-zero 'family' and 'length' if set */
+ lwres_addr_t mask;
+ } sortlist[LWRES_CONFMAXSORTLIST];
+ lwres_uint8_t sortlistnxt;
+
+ lwres_uint8_t resdebug; /* non-zero if 'options debug' set */
+ lwres_uint8_t ndots; /* set to n in 'options ndots:n' */
+ lwres_uint8_t no_tld_query; /* non-zero if 'options no_tld_query' */
+} lwres_conf_t;
+
+#define LWRES_ADDRTYPE_V4 0x00000001U /* ipv4 */
+#define LWRES_ADDRTYPE_V6 0x00000002U /* ipv6 */
+
+#define LWRES_MAX_ALIASES 16 /* max # of aliases */
+#define LWRES_MAX_ADDRS 64 /* max # of addrs */
+
+LWRES_LANG_BEGINDECLS
+
+/*
+ * This is in host byte order.
+ */
+extern lwres_uint16_t lwres_udp_port;
+
+extern const char *lwres_resolv_conf;
+
+lwres_result_t
+lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp);
+
+lwres_result_t
+lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt,
+ lwres_gabnresponse_t **structp);
+
+void
+lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp);
+/*
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_contextcreate().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+void
+lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp);
+/*
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_contextcreate().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+
+lwres_result_t
+lwres_gnbarequest_render(lwres_context_t *ctx, lwres_gnbarequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_gnbaresponse_render(lwres_context_t *ctx, lwres_gnbaresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_gnbarequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp);
+
+lwres_result_t
+lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt,
+ lwres_gnbaresponse_t **structp);
+
+void
+lwres_gnbarequest_free(lwres_context_t *ctx, lwres_gnbarequest_t **structp);
+/*
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_contextcreate().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+void
+lwres_gnbaresponse_free(lwres_context_t *ctx, lwres_gnbaresponse_t **structp);
+/*
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_contextcreate().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+lwres_result_t
+lwres_grbnrequest_render(lwres_context_t *ctx, lwres_grbnrequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_grbnresponse_render(lwres_context_t *ctx, lwres_grbnresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_grbnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_grbnrequest_t **structp);
+
+lwres_result_t
+lwres_grbnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt,
+ lwres_grbnresponse_t **structp);
+
+void
+lwres_grbnrequest_free(lwres_context_t *ctx, lwres_grbnrequest_t **structp);
+/*
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_contextcreate().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+void
+lwres_grbnresponse_free(lwres_context_t *ctx, lwres_grbnresponse_t **structp);
+/*
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_contextcreate().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+lwres_result_t
+lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+/*
+ * Allocate space and render into wire format a noop request packet.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_contextcreate().
+ *
+ * b != NULL, and points to a lwres_buffer_t. The contents of the
+ * buffer structure will be initialized to contain the wire-format
+ * noop request packet.
+ *
+ * Caller needs to fill in parts of "pkt" before calling:
+ * serial, maxrecv, result.
+ *
+ * Returns:
+ *
+ * Returns 0 on success, non-zero on failure.
+ *
+ * On successful return, *b will contain data about the wire-format
+ * packet. It can be transmitted in any way, including lwres_sendblock().
+ */
+
+lwres_result_t
+lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+
+lwres_result_t
+lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp);
+/*
+ * Parse a noop request. Note that to get here, the lwpacket must have
+ * already been parsed and removed by the caller, otherwise it would be
+ * pretty hard for it to know this is the right function to call.
+ *
+ * The function verifies bits of the header, but does not modify it.
+ */
+
+lwres_result_t
+lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt,
+ lwres_noopresponse_t **structp);
+
+void
+lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp);
+
+void
+lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp);
+
+/*
+ * Frees any dynamically allocated memory for this structure.
+ *
+ * Requires:
+ *
+ * ctx != NULL, and be a context returned via lwres_contextcreate().
+ *
+ * structp != NULL && *structp != NULL.
+ *
+ * Ensures:
+ *
+ * *structp == NULL.
+ *
+ * All memory allocated by this structure will be returned to the
+ * system via the context's free function.
+ */
+
+lwres_result_t
+lwres_conf_parse(lwres_context_t *ctx, const char *filename);
+/*
+ * parses a resolv.conf-format file and stores the results in the structure
+ * pointed to by *ctx.
+ *
+ * Requires:
+ * ctx != NULL
+ * filename != NULL && strlen(filename) > 0
+ *
+ * Returns:
+ * LWRES_R_SUCCESS on a successful parse.
+ * Anything else on error, although the structure may be partially filled
+ * in.
+ */
+
+lwres_result_t
+lwres_conf_print(lwres_context_t *ctx, FILE *fp);
+/*
+ * Prints a resolv.conf-format of confdata output to fp.
+ *
+ * Requires:
+ * ctx != NULL
+ */
+
+void
+lwres_conf_init(lwres_context_t *ctx);
+/*
+ * sets all internal fields to a default state. Used to initialize a new
+ * lwres_conf_t structure (not reset a used on).
+ *
+ * Requires:
+ * ctx != NULL
+ */
+
+void
+lwres_conf_clear(lwres_context_t *ctx);
+/*
+ * frees all internally allocated memory in confdata. Uses the memory
+ * routines supplied by ctx.
+ *
+ * Requires:
+ * ctx != NULL
+ */
+
+lwres_conf_t *
+lwres_conf_get(lwres_context_t *ctx);
+/*
+ * returns a pointer to the current config structure.
+ * Be extremely cautions in modifying the contents of this structure; it
+ * needs an API to return the various bits of data, walk lists, etc.
+ *
+ * Requires:
+ * ctx != NULL
+ */
+
+/*
+ * Helper functions
+ */
+
+lwres_result_t
+lwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len);
+
+lwres_result_t
+lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len);
+
+lwres_result_t
+lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr);
+
+lwres_result_t
+lwres_getaddrsbyname(lwres_context_t *ctx, const char *name,
+ lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp);
+
+lwres_result_t
+lwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype,
+ lwres_uint16_t addrlen, const unsigned char *addr,
+ lwres_gnbaresponse_t **structp);
+
+lwres_result_t
+lwres_getrdatabyname(lwres_context_t *ctx, const char *name,
+ lwres_uint16_t rdclass, lwres_uint16_t rdtype,
+ lwres_uint32_t flags, lwres_grbnresponse_t **structp);
+
+lwres_result_t
+lwres_getaddrsbyname_setup(lwres_context_t *ctx, const char *name,
+ lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp);
+
+
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_LWRES_H */
diff --git a/lib/liblwres/include/lwres/netdb.h b/lib/liblwres/include/lwres/netdb.h
new file mode 100644
index 000000000..2391d31fb
--- /dev/null
+++ b/lib/liblwres/include/lwres/netdb.h
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: netdb.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_NETDB_H
+#define LWRES_NETDB_H 1
+
+#include <stddef.h> /* Required on FreeBSD (and others?) for size_t. */
+#include <netdb.h> /* Contractual provision. */
+
+#include <lwres/lang.h>
+
+/*
+ * Define if <netdb.h> does not declare struct addrinfo.
+ */
+#undef ISC_LWRES_NEEDADDRINFO
+
+#ifdef ISC_LWRES_NEEDADDRINFO
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* Length of ai_addr */
+ char *ai_canonname; /* Canonical name for hostname */
+ struct sockaddr *ai_addr; /* Binary address */
+ struct addrinfo *ai_next; /* Next structure in linked list */
+};
+#endif
+
+/*
+ * Undefine all #defines we are interested in as <netdb.h> may or may not have
+ * defined them.
+ */
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#undef NETDB_INTERNAL
+#undef NETDB_SUCCESS
+#undef HOST_NOT_FOUND
+#undef TRY_AGAIN
+#undef NO_RECOVERY
+#undef NO_DATA
+#undef NO_ADDRESS
+
+#define NETDB_INTERNAL -1 /* see errno */
+#define NETDB_SUCCESS 0 /* no problem */
+#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */
+#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */
+#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define NO_DATA 4 /* Valid name, no data record of requested type */
+#define NO_ADDRESS NO_DATA /* no address, look for MX record */
+
+/*
+ * Error return codes from getaddrinfo()
+ */
+
+#undef EAI_ADDRFAMILY
+#undef EAI_AGAIN
+#undef EAI_BADFLAGS
+#undef EAI_FAIL
+#undef EAI_FAMILY
+#undef EAI_MEMORY
+#undef EAI_NODATA
+#undef EAI_NONAME
+#undef EAI_SERVICE
+#undef EAI_SOCKTYPE
+#undef EAI_SYSTEM
+#undef EAI_BADHINTS
+#undef EAI_PROTOCOL
+#undef EAI_MAX
+
+#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
+#define EAI_FAMILY 5 /* ai_family not supported */
+#define EAI_MEMORY 6 /* memory allocation failure */
+#define EAI_NODATA 7 /* no address associated with hostname */
+#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#define EAI_SYSTEM 11 /* system error returned in errno */
+#define EAI_BADHINTS 12
+#define EAI_PROTOCOL 13
+#define EAI_MAX 14
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#undef AI_PASSIVE
+#undef AI_CANONNAME
+#undef AI_NUMERICHOST
+
+#define AI_PASSIVE 0x00000001
+#define AI_CANONNAME 0x00000002
+#define AI_NUMERICHOST 0x00000004
+
+/*
+ * Flag values for getipnodebyname()
+ */
+#undef AI_V4MAPPED
+#undef AI_ALL
+#undef AI_ADDRCONFIG
+#undef AI_DEFAULT
+
+#define AI_V4MAPPED 0x00000008
+#define AI_ALL 0x00000010
+#define AI_ADDRCONFIG 0x00000020
+#define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG)
+
+/*
+ * Constants for lwres_getnameinfo()
+ */
+#undef NI_MAXHOST
+#undef NI_MAXSERV
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+/*
+ * Flag values for lwres_getnameinfo()
+ */
+#undef NI_NOFQDN
+#undef NI_NUMERICHOST
+#undef NI_NAMEREQD
+#undef NI_NUMERICSERV
+#undef NI_DGRAM
+#undef NI_NUMERICSCOPE
+
+#define NI_NOFQDN 0x00000001
+#define NI_NUMERICHOST 0x00000002
+#define NI_NAMEREQD 0x00000004
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+#define NI_NUMERICSCOPE 0x00000020 /*2553bis-00*/
+
+/*
+ * Define if <netdb.h> does not declare struct rrsetinfo.
+ */
+#define ISC_LWRES_NEEDRRSETINFO 1
+
+#ifdef ISC_LWRES_NEEDRRSETINFO
+/*
+ * Structures for getrrsetbyname()
+ */
+struct rdatainfo {
+ unsigned int rdi_length;
+ unsigned char *rdi_data;
+};
+
+struct rrsetinfo {
+ unsigned int rri_flags;
+ int rri_rdclass;
+ int rri_rdtype;
+ unsigned int rri_ttl;
+ unsigned int rri_nrdatas;
+ unsigned int rri_nsigs;
+ char *rri_name;
+ struct rdatainfo *rri_rdatas;
+ struct rdatainfo *rri_sigs;
+};
+
+/*
+ * Flags for getrrsetbyname()
+ */
+#define RRSET_VALIDATED 0x00000001
+ /* Set was dnssec validated */
+
+/*
+ * Return codes for getrrsetbyname()
+ */
+#define ERRSET_SUCCESS 0
+#define ERRSET_NOMEMORY 1
+#define ERRSET_FAIL 2
+#define ERRSET_INVAL 3
+#define ERRSET_NONAME 4
+#define ERRSET_NODATA 5
+#define ERRSET_RETRY 6
+#endif
+
+/*
+ * Define to map into lwres_ namespace.
+ */
+
+#define LWRES_NAMESPACE
+
+#ifdef LWRES_NAMESPACE
+
+/*
+ * Use our versions not the ones from the C library.
+ */
+
+#ifdef getnameinfo
+#undef getnameinfo
+#endif
+#define getnameinfo lwres_getnameinfo
+
+#ifdef getaddrinfo
+#undef getaddrinfo
+#endif
+#define getaddrinfo lwres_getaddrinfo
+
+#ifdef freeaddrinfo
+#undef freeaddrinfo
+#endif
+#define freeaddrinfo lwres_freeaddrinfo
+
+#ifdef gai_strerror
+#undef gai_strerror
+#endif
+#define gai_strerror lwres_gai_strerror
+
+#ifdef herror
+#undef herror
+#endif
+#define herror lwres_herror
+
+#ifdef hstrerror
+#undef hstrerror
+#endif
+#define hstrerror lwres_hstrerror
+
+#ifdef getipnodebyname
+#undef getipnodebyname
+#endif
+#define getipnodebyname lwres_getipnodebyname
+
+#ifdef getipnodebyaddr
+#undef getipnodebyaddr
+#endif
+#define getipnodebyaddr lwres_getipnodebyaddr
+
+#ifdef freehostent
+#undef freehostent
+#endif
+#define freehostent lwres_freehostent
+
+#ifdef gethostbyname
+#undef gethostbyname
+#endif
+#define gethostbyname lwres_gethostbyname
+
+#ifdef gethostbyname2
+#undef gethostbyname2
+#endif
+#define gethostbyname2 lwres_gethostbyname2
+
+#ifdef gethostbyaddr
+#undef gethostbyaddr
+#endif
+#define gethostbyaddr lwres_gethostbyaddr
+
+#ifdef gethostent
+#undef gethostent
+#endif
+#define gethostent lwres_gethostent
+
+#ifdef sethostent
+#undef sethostent
+#endif
+#define sethostent lwres_sethostent
+
+#ifdef endhostent
+#undef endhostent
+#endif
+#define endhostent lwres_endhostent
+
+/* #define sethostfile lwres_sethostfile */
+
+#ifdef gethostbyname_r
+#undef gethostbyname_r
+#endif
+#define gethostbyname_r lwres_gethostbyname_r
+
+#ifdef gethostbyaddr_r
+#undef gethostbyaddr_r
+#endif
+#define gethostbyaddr_r lwres_gethostbyaddr_r
+
+#ifdef gethostent_r
+#undef gethostent_r
+#endif
+#define gethostent_r lwres_gethostent_r
+
+#ifdef sethostent_r
+#undef sethostent_r
+#endif
+#define sethostent_r lwres_sethostent_r
+
+#ifdef endhostent_r
+#undef endhostent_r
+#endif
+#define endhostent_r lwres_endhostent_r
+
+#ifdef getrrsetbyname
+#undef getrrsetbyname
+#endif
+#define getrrsetbyname lwres_getrrsetbyname
+
+#ifdef freerrset
+#undef freerrset
+#endif
+#define freerrset lwres_freerrset
+
+#ifdef notyet
+#define getservbyname lwres_getservbyname
+#define getservbyport lwres_getservbyport
+#define getservent lwres_getservent
+#define setservent lwres_setservent
+#define endservent lwres_endservent
+
+#define getservbyname_r lwres_getservbyname_r
+#define getservbyport_r lwres_getservbyport_r
+#define getservent_r lwres_getservent_r
+#define setservent_r lwres_setservent_r
+#define endservent_r lwres_endservent_r
+
+#define getprotobyname lwres_getprotobyname
+#define getprotobynumber lwres_getprotobynumber
+#define getprotoent lwres_getprotoent
+#define setprotoent lwres_setprotoent
+#define endprotoent lwres_endprotoent
+
+#define getprotobyname_r lwres_getprotobyname_r
+#define getprotobynumber_r lwres_getprotobynumber_r
+#define getprotoent_r lwres_getprotoent_r
+#define setprotoent_r lwres_setprotoent_r
+#define endprotoent_r lwres_endprotoent_r
+
+#ifdef getnetbyname
+#undef getnetbyname
+#endif
+#define getnetbyname lwres_getnetbyname
+
+#ifdef getnetbyaddr
+#undef getnetbyaddr
+#endif
+#define getnetbyaddr lwres_getnetbyaddr
+
+#ifdef getnetent
+#undef getnetent
+#endif
+#define getnetent lwres_getnetent
+
+#ifdef setnetent
+#undef setnetent
+#endif
+#define setnetent lwres_setnetent
+
+#ifdef endnetent
+#undef endnetent
+#endif
+#define endnetent lwres_endnetent
+
+
+#ifdef getnetbyname_r
+#undef getnetbyname_r
+#endif
+#define getnetbyname_r lwres_getnetbyname_r
+
+#ifdef getnetbyaddr_r
+#undef getnetbyaddr_r
+#endif
+#define getnetbyaddr_r lwres_getnetbyaddr_r
+
+#ifdef getnetent_r
+#undef getnetent_r
+#endif
+#define getnetent_r lwres_getnetent_r
+
+#ifdef setnetent_r
+#undef setnetent_r
+#endif
+#define setnetent_r lwres_setnetent_r
+
+#ifdef endnetent_r
+#undef endnetent_r
+#endif
+#define endnetent_r lwres_endnetent_r
+#endif /* notyet */
+
+#ifdef h_errno
+#undef h_errno
+#endif
+#define h_errno lwres_h_errno
+
+#endif /* LWRES_NAMESPACE */
+
+LWRES_LANG_BEGINDECLS
+
+extern int lwres_h_errno;
+
+int lwres_getaddrinfo(const char *, const char *,
+ const struct addrinfo *, struct addrinfo **);
+int lwres_getnameinfo(const struct sockaddr *, size_t, char *,
+ size_t, char *, size_t, int);
+void lwres_freeaddrinfo(struct addrinfo *);
+char *lwres_gai_strerror(int);
+
+struct hostent *lwres_gethostbyaddr(const char *, int, int);
+struct hostent *lwres_gethostbyname(const char *);
+struct hostent *lwres_gethostbyname2(const char *, int);
+struct hostent *lwres_gethostent(void);
+struct hostent *lwres_getipnodebyname(const char *, int, int, int *);
+struct hostent *lwres_getipnodebyaddr(const void *, size_t, int, int *);
+void lwres_endhostent(void);
+void lwres_sethostent(int);
+/* void lwres_sethostfile(const char *); */
+void lwres_freehostent(struct hostent *);
+
+int lwres_getrrsetbyname(const char *, unsigned int, unsigned int,
+ unsigned int, struct rrsetinfo **);
+int lwres_getrrsetbyname_all(const char *, unsigned int,
+ unsigned int,
+ unsigned int, struct rrsetinfo **);
+void lwres_freerrset(struct rrsetinfo *);
+
+#ifdef notyet
+struct netent *lwres_getnetbyaddr(unsigned long, int);
+struct netent *lwres_getnetbyname(const char *);
+struct netent *lwres_getnetent(void);
+void lwres_endnetent(void);
+void lwres_setnetent(int);
+
+struct protoent *lwres_getprotobyname(const char *);
+struct protoent *lwres_getprotobynumber(int);
+struct protoent *lwres_getprotoent(void);
+void lwres_endprotoent(void);
+void lwres_setprotoent(int);
+
+struct servent *lwres_getservbyname(const char *, const char *);
+struct servent *lwres_getservbyport(int, const char *);
+struct servent *lwres_getservent(void);
+void lwres_endservent(void);
+void lwres_setservent(int);
+#endif /* notyet */
+
+void lwres_herror(const char *);
+const char *lwres_hstrerror(int);
+
+
+struct hostent *lwres_gethostbyaddr_r(const char *, int, int, struct hostent *,
+ char *, int, int *);
+struct hostent *lwres_gethostbyname_r(const char *, struct hostent *,
+ char *, int, int *);
+struct hostent *lwres_gethostent_r(struct hostent *, char *, int, int *);
+void lwres_sethostent_r(int);
+void lwres_endhostent_r(void);
+
+#ifdef notyet
+struct netent *lwres_getnetbyname_r(const char *, struct netent *,
+ char *, int);
+struct netent *lwres_getnetbyaddr_r(long, int, struct netent *,
+ char *, int);
+struct netent *lwres_getnetent_r(struct netent *, char *, int);
+void lwres_setnetent_r(int);
+void lwres_endnetent_r(void);
+
+struct protoent *lwres_getprotobyname_r(const char *,
+ struct protoent *, char *, int);
+struct protoent *lwres_getprotobynumber_r(int,
+ struct protoent *, char *, int);
+struct protoent *lwres_getprotoent_r(struct protoent *, char *, int);
+void lwres_setprotoent_r(int);
+void lwres_endprotoent_r(void);
+
+struct servent *lwres_getservbyname_r(const char *name, const char *,
+ struct servent *, char *, int);
+struct servent *lwres_getservbyport_r(int port, const char *,
+ struct servent *, char *, int);
+struct servent *lwres_getservent_r(struct servent *, char *, int);
+void lwres_setservent_r(int);
+void lwres_endservent_r(void);
+#endif /* notyet */
+
+LWRES_LANG_ENDDECLS
+
+#ifdef notyet
+/* This is nec'y to make this include file properly replace the sun version. */
+#ifdef sun
+#ifdef __GNU_LIBRARY__
+#include <rpc/netdb.h> /* Required. */
+#else /* !__GNU_LIBRARY__ */
+struct rpcent {
+ char *r_name; /* name of server for this rpc program */
+ char **r_aliases; /* alias list */
+ int r_number; /* rpc program number */
+};
+struct rpcent *lwres_getrpcbyname();
+struct rpcent *lwres_getrpcbynumber(),
+struct rpcent *lwres_getrpcent();
+#endif /* __GNU_LIBRARY__ */
+#endif /* sun */
+#endif /* notyet */
+
+/*
+ * Tell Emacs to use C mode on this file.
+ * Local variables:
+ * mode: c
+ * End:
+ */
+
+#endif /* LWRES_NETDB_H */
diff --git a/lib/liblwres/include/lwres/netdb.h.in b/lib/liblwres/include/lwres/netdb.h.in
new file mode 100644
index 000000000..75446e8f8
--- /dev/null
+++ b/lib/liblwres/include/lwres/netdb.h.in
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: netdb.h.in,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_NETDB_H
+#define LWRES_NETDB_H 1
+
+#include <stddef.h> /* Required on FreeBSD (and others?) for size_t. */
+#include <netdb.h> /* Contractual provision. */
+
+#include <lwres/lang.h>
+
+/*
+ * Define if <netdb.h> does not declare struct addrinfo.
+ */
+@ISC_LWRES_NEEDADDRINFO@
+
+#ifdef ISC_LWRES_NEEDADDRINFO
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* Length of ai_addr */
+ char *ai_canonname; /* Canonical name for hostname */
+ struct sockaddr *ai_addr; /* Binary address */
+ struct addrinfo *ai_next; /* Next structure in linked list */
+};
+#endif
+
+/*
+ * Undefine all #defines we are interested in as <netdb.h> may or may not have
+ * defined them.
+ */
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#undef NETDB_INTERNAL
+#undef NETDB_SUCCESS
+#undef HOST_NOT_FOUND
+#undef TRY_AGAIN
+#undef NO_RECOVERY
+#undef NO_DATA
+#undef NO_ADDRESS
+
+#define NETDB_INTERNAL -1 /* see errno */
+#define NETDB_SUCCESS 0 /* no problem */
+#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */
+#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */
+#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define NO_DATA 4 /* Valid name, no data record of requested type */
+#define NO_ADDRESS NO_DATA /* no address, look for MX record */
+
+/*
+ * Error return codes from getaddrinfo()
+ */
+
+#undef EAI_ADDRFAMILY
+#undef EAI_AGAIN
+#undef EAI_BADFLAGS
+#undef EAI_FAIL
+#undef EAI_FAMILY
+#undef EAI_MEMORY
+#undef EAI_NODATA
+#undef EAI_NONAME
+#undef EAI_SERVICE
+#undef EAI_SOCKTYPE
+#undef EAI_SYSTEM
+#undef EAI_BADHINTS
+#undef EAI_PROTOCOL
+#undef EAI_MAX
+
+#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
+#define EAI_FAMILY 5 /* ai_family not supported */
+#define EAI_MEMORY 6 /* memory allocation failure */
+#define EAI_NODATA 7 /* no address associated with hostname */
+#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#define EAI_SYSTEM 11 /* system error returned in errno */
+#define EAI_BADHINTS 12
+#define EAI_PROTOCOL 13
+#define EAI_MAX 14
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#undef AI_PASSIVE
+#undef AI_CANONNAME
+#undef AI_NUMERICHOST
+
+#define AI_PASSIVE 0x00000001
+#define AI_CANONNAME 0x00000002
+#define AI_NUMERICHOST 0x00000004
+
+/*
+ * Flag values for getipnodebyname()
+ */
+#undef AI_V4MAPPED
+#undef AI_ALL
+#undef AI_ADDRCONFIG
+#undef AI_DEFAULT
+
+#define AI_V4MAPPED 0x00000008
+#define AI_ALL 0x00000010
+#define AI_ADDRCONFIG 0x00000020
+#define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG)
+
+/*
+ * Constants for lwres_getnameinfo()
+ */
+#undef NI_MAXHOST
+#undef NI_MAXSERV
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+/*
+ * Flag values for lwres_getnameinfo()
+ */
+#undef NI_NOFQDN
+#undef NI_NUMERICHOST
+#undef NI_NAMEREQD
+#undef NI_NUMERICSERV
+#undef NI_DGRAM
+#undef NI_NUMERICSCOPE
+
+#define NI_NOFQDN 0x00000001
+#define NI_NUMERICHOST 0x00000002
+#define NI_NAMEREQD 0x00000004
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+#define NI_NUMERICSCOPE 0x00000020 /*2553bis-00*/
+
+/*
+ * Define if <netdb.h> does not declare struct rrsetinfo.
+ */
+@ISC_LWRES_NEEDRRSETINFO@
+
+#ifdef ISC_LWRES_NEEDRRSETINFO
+/*
+ * Structures for getrrsetbyname()
+ */
+struct rdatainfo {
+ unsigned int rdi_length;
+ unsigned char *rdi_data;
+};
+
+struct rrsetinfo {
+ unsigned int rri_flags;
+ int rri_rdclass;
+ int rri_rdtype;
+ unsigned int rri_ttl;
+ unsigned int rri_nrdatas;
+ unsigned int rri_nsigs;
+ char *rri_name;
+ struct rdatainfo *rri_rdatas;
+ struct rdatainfo *rri_sigs;
+};
+
+/*
+ * Flags for getrrsetbyname()
+ */
+#define RRSET_VALIDATED 0x00000001
+ /* Set was dnssec validated */
+
+/*
+ * Return codes for getrrsetbyname()
+ */
+#define ERRSET_SUCCESS 0
+#define ERRSET_NOMEMORY 1
+#define ERRSET_FAIL 2
+#define ERRSET_INVAL 3
+#define ERRSET_NONAME 4
+#define ERRSET_NODATA 5
+#endif
+
+/*
+ * Define to map into lwres_ namespace.
+ */
+
+#define LWRES_NAMESPACE
+
+#ifdef LWRES_NAMESPACE
+
+/*
+ * Use our versions not the ones from the C library.
+ */
+
+#ifdef getnameinfo
+#undef getnameinfo
+#endif
+#define getnameinfo lwres_getnameinfo
+
+#ifdef getaddrinfo
+#undef getaddrinfo
+#endif
+#define getaddrinfo lwres_getaddrinfo
+
+#ifdef freeaddrinfo
+#undef freeaddrinfo
+#endif
+#define freeaddrinfo lwres_freeaddrinfo
+
+#ifdef gai_strerror
+#undef gai_strerror
+#endif
+#define gai_strerror lwres_gai_strerror
+
+#ifdef herror
+#undef herror
+#endif
+#define herror lwres_herror
+
+#ifdef hstrerror
+#undef hstrerror
+#endif
+#define hstrerror lwres_hstrerror
+
+#ifdef getipnodebyname
+#undef getipnodebyname
+#endif
+#define getipnodebyname lwres_getipnodebyname
+
+#ifdef getipnodebyaddr
+#undef getipnodebyaddr
+#endif
+#define getipnodebyaddr lwres_getipnodebyaddr
+
+#ifdef freehostent
+#undef freehostent
+#endif
+#define freehostent lwres_freehostent
+
+#ifdef gethostbyname
+#undef gethostbyname
+#endif
+#define gethostbyname lwres_gethostbyname
+
+#ifdef gethostbyname2
+#undef gethostbyname2
+#endif
+#define gethostbyname2 lwres_gethostbyname2
+
+#ifdef gethostbyaddr
+#undef gethostbyaddr
+#endif
+#define gethostbyaddr lwres_gethostbyaddr
+
+#ifdef gethostent
+#undef gethostent
+#endif
+#define gethostent lwres_gethostent
+
+#ifdef sethostent
+#undef sethostent
+#endif
+#define sethostent lwres_sethostent
+
+#ifdef endhostent
+#undef endhostent
+#endif
+#define endhostent lwres_endhostent
+
+/* #define sethostfile lwres_sethostfile */
+
+#ifdef gethostbyname_r
+#undef gethostbyname_r
+#endif
+#define gethostbyname_r lwres_gethostbyname_r
+
+#ifdef gethostbyaddr_r
+#undef gethostbyaddr_r
+#endif
+#define gethostbyaddr_r lwres_gethostbyaddr_r
+
+#ifdef gethostent_r
+#undef gethostent_r
+#endif
+#define gethostent_r lwres_gethostent_r
+
+#ifdef sethostent_r
+#undef sethostent_r
+#endif
+#define sethostent_r lwres_sethostent_r
+
+#ifdef endhostent_r
+#undef endhostent_r
+#endif
+#define endhostent_r lwres_endhostent_r
+
+#ifdef getrrsetbyname
+#undef getrrsetbyname
+#endif
+#define getrrsetbyname lwres_getrrsetbyname
+
+#ifdef freerrset
+#undef freerrset
+#endif
+#define freerrset lwres_freerrset
+
+#ifdef notyet
+#define getservbyname lwres_getservbyname
+#define getservbyport lwres_getservbyport
+#define getservent lwres_getservent
+#define setservent lwres_setservent
+#define endservent lwres_endservent
+
+#define getservbyname_r lwres_getservbyname_r
+#define getservbyport_r lwres_getservbyport_r
+#define getservent_r lwres_getservent_r
+#define setservent_r lwres_setservent_r
+#define endservent_r lwres_endservent_r
+
+#define getprotobyname lwres_getprotobyname
+#define getprotobynumber lwres_getprotobynumber
+#define getprotoent lwres_getprotoent
+#define setprotoent lwres_setprotoent
+#define endprotoent lwres_endprotoent
+
+#define getprotobyname_r lwres_getprotobyname_r
+#define getprotobynumber_r lwres_getprotobynumber_r
+#define getprotoent_r lwres_getprotoent_r
+#define setprotoent_r lwres_setprotoent_r
+#define endprotoent_r lwres_endprotoent_r
+
+#ifdef getnetbyname
+#undef getnetbyname
+#endif
+#define getnetbyname lwres_getnetbyname
+
+#ifdef getnetbyaddr
+#undef getnetbyaddr
+#endif
+#define getnetbyaddr lwres_getnetbyaddr
+
+#ifdef getnetent
+#undef getnetent
+#endif
+#define getnetent lwres_getnetent
+
+#ifdef setnetent
+#undef setnetent
+#endif
+#define setnetent lwres_setnetent
+
+#ifdef endnetent
+#undef endnetent
+#endif
+#define endnetent lwres_endnetent
+
+
+#ifdef getnetbyname_r
+#undef getnetbyname_r
+#endif
+#define getnetbyname_r lwres_getnetbyname_r
+
+#ifdef getnetbyaddr_r
+#undef getnetbyaddr_r
+#endif
+#define getnetbyaddr_r lwres_getnetbyaddr_r
+
+#ifdef getnetent_r
+#undef getnetent_r
+#endif
+#define getnetent_r lwres_getnetent_r
+
+#ifdef setnetent_r
+#undef setnetent_r
+#endif
+#define setnetent_r lwres_setnetent_r
+
+#ifdef endnetent_r
+#undef endnetent_r
+#endif
+#define endnetent_r lwres_endnetent_r
+#endif /* notyet */
+
+#ifdef h_errno
+#undef h_errno
+#endif
+#define h_errno lwres_h_errno
+
+#endif /* LWRES_NAMESPACE */
+
+LWRES_LANG_BEGINDECLS
+
+extern int lwres_h_errno;
+
+int lwres_getaddrinfo(const char *, const char *,
+ const struct addrinfo *, struct addrinfo **);
+int lwres_getnameinfo(const struct sockaddr *, size_t, char *,
+ size_t, char *, size_t, int);
+void lwres_freeaddrinfo(struct addrinfo *);
+char *lwres_gai_strerror(int);
+
+struct hostent *lwres_gethostbyaddr(const char *, int, int);
+struct hostent *lwres_gethostbyname(const char *);
+struct hostent *lwres_gethostbyname2(const char *, int);
+struct hostent *lwres_gethostent(void);
+struct hostent *lwres_getipnodebyname(const char *, int, int, int *);
+struct hostent *lwres_getipnodebyaddr(const void *, size_t, int, int *);
+void lwres_endhostent(void);
+void lwres_sethostent(int);
+/* void lwres_sethostfile(const char *); */
+void lwres_freehostent(struct hostent *);
+
+int lwres_getrrsetbyname(const char *, unsigned int, unsigned int,
+ unsigned int, struct rrsetinfo **);
+void lwres_freerrset(struct rrsetinfo *);
+
+#ifdef notyet
+struct netent *lwres_getnetbyaddr(unsigned long, int);
+struct netent *lwres_getnetbyname(const char *);
+struct netent *lwres_getnetent(void);
+void lwres_endnetent(void);
+void lwres_setnetent(int);
+
+struct protoent *lwres_getprotobyname(const char *);
+struct protoent *lwres_getprotobynumber(int);
+struct protoent *lwres_getprotoent(void);
+void lwres_endprotoent(void);
+void lwres_setprotoent(int);
+
+struct servent *lwres_getservbyname(const char *, const char *);
+struct servent *lwres_getservbyport(int, const char *);
+struct servent *lwres_getservent(void);
+void lwres_endservent(void);
+void lwres_setservent(int);
+#endif /* notyet */
+
+void lwres_herror(const char *);
+const char *lwres_hstrerror(int);
+
+
+struct hostent *lwres_gethostbyaddr_r(const char *, int, int, struct hostent *,
+ char *, int, int *);
+struct hostent *lwres_gethostbyname_r(const char *, struct hostent *,
+ char *, int, int *);
+struct hostent *lwres_gethostent_r(struct hostent *, char *, int, int *);
+void lwres_sethostent_r(int);
+void lwres_endhostent_r(void);
+
+#ifdef notyet
+struct netent *lwres_getnetbyname_r(const char *, struct netent *,
+ char *, int);
+struct netent *lwres_getnetbyaddr_r(long, int, struct netent *,
+ char *, int);
+struct netent *lwres_getnetent_r(struct netent *, char *, int);
+void lwres_setnetent_r(int);
+void lwres_endnetent_r(void);
+
+struct protoent *lwres_getprotobyname_r(const char *,
+ struct protoent *, char *, int);
+struct protoent *lwres_getprotobynumber_r(int,
+ struct protoent *, char *, int);
+struct protoent *lwres_getprotoent_r(struct protoent *, char *, int);
+void lwres_setprotoent_r(int);
+void lwres_endprotoent_r(void);
+
+struct servent *lwres_getservbyname_r(const char *name, const char *,
+ struct servent *, char *, int);
+struct servent *lwres_getservbyport_r(int port, const char *,
+ struct servent *, char *, int);
+struct servent *lwres_getservent_r(struct servent *, char *, int);
+void lwres_setservent_r(int);
+void lwres_endservent_r(void);
+#endif /* notyet */
+
+LWRES_LANG_ENDDECLS
+
+#ifdef notyet
+/* This is nec'y to make this include file properly replace the sun version. */
+#ifdef sun
+#ifdef __GNU_LIBRARY__
+#include <rpc/netdb.h> /* Required. */
+#else /* !__GNU_LIBRARY__ */
+struct rpcent {
+ char *r_name; /* name of server for this rpc program */
+ char **r_aliases; /* alias list */
+ int r_number; /* rpc program number */
+};
+struct rpcent *lwres_getrpcbyname();
+struct rpcent *lwres_getrpcbynumber(),
+struct rpcent *lwres_getrpcent();
+#endif /* __GNU_LIBRARY__ */
+#endif /* sun */
+#endif /* notyet */
+
+/*
+ * Tell Emacs to use C mode on this file.
+ * Local variables:
+ * mode: c
+ * End:
+ */
+
+#endif /* LWRES_NETDB_H */
diff --git a/lib/liblwres/include/lwres/platform.h b/lib/liblwres/include/lwres/platform.h
new file mode 100644
index 000000000..af4c615d9
--- /dev/null
+++ b/lib/liblwres/include/lwres/platform.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: platform.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_PLATFORM_H
+#define LWRES_PLATFORM_H 1
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+/***
+ *** Network.
+ ***/
+
+/*
+ * Define if this system needs the <netinet/in6.h> header file for IPv6.
+ */
+#undef LWRES_PLATFORM_NEEDNETINETIN6H
+
+/*
+ * Define if this system needs the <netinet6/in6.h> header file for IPv6.
+ */
+#undef LWRES_PLATFORM_NEEDNETINET6IN6H
+
+/*
+ * If sockaddrs on this system have an sa_len field, LWRES_PLATFORM_HAVESALEN
+ * will be defined.
+ */
+#undef LWRES_PLATFORM_HAVESALEN
+
+/*
+ * If this system has the IPv6 structure definitions, LWRES_PLATFORM_HAVEIPV6
+ * will be defined.
+ */
+#define LWRES_PLATFORM_HAVEIPV6 1
+
+/*
+ * If this system is missing in6addr_any, LWRES_PLATFORM_NEEDIN6ADDRANY will
+ * be defined.
+ */
+#undef LWRES_PLATFORM_NEEDIN6ADDRANY
+
+/*
+ * If this system is missing in6addr_loopback,
+ * LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK will be defined.
+ */
+#undef LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK
+
+/*
+ * If this system has in_addr6, rather than in6_addr,
+ * LWRES_PLATFORM_HAVEINADDR6 will be defined.
+ */
+#undef LWRES_PLATFORM_HAVEINADDR6
+
+/*
+ * Defined if unistd.h does not cause fd_set to be delared.
+ */
+#define LWRES_PLATFORM_NEEDSYSSELECTH 1
+
+/*
+ * Used to control how extern data is linked; needed for Win32 platforms.
+ */
+#undef LWRES_PLATFORM_USEDECLSPEC
+
+#ifndef LWRES_PLATFORM_USEDECLSPEC
+#define LIBLWRES_EXTERNAL_DATA
+#else
+#ifdef LIBLWRES_EXPORTS
+#define LIBLWRES_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBLWRES_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#endif
+
+#endif /* LWRES_PLATFORM_H */
diff --git a/lib/liblwres/include/lwres/platform.h.in b/lib/liblwres/include/lwres/platform.h.in
new file mode 100644
index 000000000..c679d8fae
--- /dev/null
+++ b/lib/liblwres/include/lwres/platform.h.in
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: platform.h.in,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_PLATFORM_H
+#define LWRES_PLATFORM_H 1
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+/***
+ *** Network.
+ ***/
+
+/*
+ * Define if this system needs the <netinet/in6.h> header file for IPv6.
+ */
+@LWRES_PLATFORM_NEEDNETINETIN6H@
+
+/*
+ * Define if this system needs the <netinet6/in6.h> header file for IPv6.
+ */
+@LWRES_PLATFORM_NEEDNETINET6IN6H@
+
+/*
+ * If sockaddrs on this system have an sa_len field, LWRES_PLATFORM_HAVESALEN
+ * will be defined.
+ */
+@LWRES_PLATFORM_HAVESALEN@
+
+/*
+ * If this system has the IPv6 structure definitions, LWRES_PLATFORM_HAVEIPV6
+ * will be defined.
+ */
+@LWRES_PLATFORM_HAVEIPV6@
+
+/*
+ * If this system is missing in6addr_any, LWRES_PLATFORM_NEEDIN6ADDRANY will
+ * be defined.
+ */
+@LWRES_PLATFORM_NEEDIN6ADDRANY@
+
+/*
+ * If this system is missing in6addr_loopback,
+ * LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK will be defined.
+ */
+@LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK@
+
+/*
+ * If this system has in_addr6, rather than in6_addr,
+ * LWRES_PLATFORM_HAVEINADDR6 will be defined.
+ */
+@LWRES_PLATFORM_HAVEINADDR6@
+
+/*
+ * Defined if unistd.h does not cause fd_set to be delared.
+ */
+@LWRES_PLATFORM_NEEDSYSSELECTH@
+
+/*
+ * Used to control how extern data is linked; needed for Win32 platforms.
+ */
+@LWRES_PLATFORM_USEDECLSPEC@
+
+#ifndef LWRES_PLATFORM_USEDECLSPEC
+#define LIBLWRES_EXTERNAL_DATA
+#else
+#ifdef LIBLWRES_EXPORTS
+#define LIBLWRES_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBLWRES_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#endif
+
+#endif /* LWRES_PLATFORM_H */
diff --git a/lib/liblwres/include/lwres/result.h b/lib/liblwres/include/lwres/result.h
new file mode 100644
index 000000000..42e1bccea
--- /dev/null
+++ b/lib/liblwres/include/lwres/result.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: result.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_RESULT_H
+#define LWRES_RESULT_H 1
+
+typedef unsigned int lwres_result_t;
+
+#define LWRES_R_SUCCESS 0
+#define LWRES_R_NOMEMORY 1
+#define LWRES_R_TIMEOUT 2
+#define LWRES_R_NOTFOUND 3
+#define LWRES_R_UNEXPECTEDEND 4 /* unexpected end of input */
+#define LWRES_R_FAILURE 5 /* generic failure */
+#define LWRES_R_IOERROR 6
+#define LWRES_R_NOTIMPLEMENTED 7
+#define LWRES_R_UNEXPECTED 8
+#define LWRES_R_TRAILINGDATA 9
+#define LWRES_R_INCOMPLETE 10
+#define LWRES_R_RETRY 11
+#define LWRES_R_TYPENOTFOUND 12
+#define LWRES_R_TOOLARGE 13
+
+#endif /* LWRES_RESULT_H */
diff --git a/lib/liblwres/lwbuffer.c b/lib/liblwres/lwbuffer.c
new file mode 100644
index 000000000..465ad2569
--- /dev/null
+++ b/lib/liblwres/lwbuffer.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwbuffer.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+
+#include "assert_p.h"
+
+void
+lwres_buffer_init(lwres_buffer_t *b, void *base, unsigned int length)
+{
+ /*
+ * Make 'b' refer to the 'length'-byte region starting at base.
+ */
+
+ REQUIRE(b != NULL);
+
+ b->magic = LWRES_BUFFER_MAGIC;
+ b->base = base;
+ b->length = length;
+ b->used = 0;
+ b->current = 0;
+ b->active = 0;
+}
+
+void
+lwres_buffer_invalidate(lwres_buffer_t *b)
+{
+ /*
+ * Make 'b' an invalid buffer.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+
+ b->magic = 0;
+ b->base = NULL;
+ b->length = 0;
+ b->used = 0;
+ b->current = 0;
+ b->active = 0;
+}
+
+void
+lwres_buffer_add(lwres_buffer_t *b, unsigned int n)
+{
+ /*
+ * Increase the 'used' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + n <= b->length);
+
+ b->used += n;
+}
+
+void
+lwres_buffer_subtract(lwres_buffer_t *b, unsigned int n)
+{
+ /*
+ * Decrease the 'used' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used >= n);
+
+ b->used -= n;
+ if (b->current > b->used)
+ b->current = b->used;
+ if (b->active > b->used)
+ b->active = b->used;
+}
+
+void
+lwres_buffer_clear(lwres_buffer_t *b)
+{
+ /*
+ * Make the used region empty.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+
+ b->used = 0;
+ b->current = 0;
+ b->active = 0;
+}
+
+void
+lwres_buffer_first(lwres_buffer_t *b)
+{
+ /*
+ * Make the consumed region empty.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+
+ b->current = 0;
+}
+
+void
+lwres_buffer_forward(lwres_buffer_t *b, unsigned int n)
+{
+ /*
+ * Increase the 'consumed' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->current + n <= b->used);
+
+ b->current += n;
+}
+
+void
+lwres_buffer_back(lwres_buffer_t *b, unsigned int n)
+{
+ /*
+ * Decrease the 'consumed' region of 'b' by 'n' bytes.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(n <= b->current);
+
+ b->current -= n;
+}
+
+lwres_uint8_t
+lwres_buffer_getuint8(lwres_buffer_t *b)
+{
+ unsigned char *cp;
+ lwres_uint8_t result;
+
+ /*
+ * Read an unsigned 8-bit integer from 'b' and return it.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 1);
+
+ cp = b->base;
+ cp += b->current;
+ b->current += 1;
+ result = ((unsigned int)(cp[0]));
+
+ return (result);
+}
+
+void
+lwres_buffer_putuint8(lwres_buffer_t *b, lwres_uint8_t val)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + 1 <= b->length);
+
+ cp = b->base;
+ cp += b->used;
+ b->used += 1;
+ cp[0] = (val & 0x00ff);
+}
+
+lwres_uint16_t
+lwres_buffer_getuint16(lwres_buffer_t *b)
+{
+ unsigned char *cp;
+ lwres_uint16_t result;
+
+ /*
+ * Read an unsigned 16-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 2);
+
+ cp = b->base;
+ cp += b->current;
+ b->current += 2;
+ result = ((unsigned int)(cp[0])) << 8;
+ result |= ((unsigned int)(cp[1]));
+
+ return (result);
+}
+
+void
+lwres_buffer_putuint16(lwres_buffer_t *b, lwres_uint16_t val)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + 2 <= b->length);
+
+ cp = b->base;
+ cp += b->used;
+ b->used += 2;
+ cp[0] = (val & 0xff00) >> 8;
+ cp[1] = (val & 0x00ff);
+}
+
+lwres_uint32_t
+lwres_buffer_getuint32(lwres_buffer_t *b)
+{
+ unsigned char *cp;
+ lwres_uint32_t result;
+
+ /*
+ * Read an unsigned 32-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ */
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= 4);
+
+ cp = b->base;
+ cp += b->current;
+ b->current += 4;
+ result = ((unsigned int)(cp[0])) << 24;
+ result |= ((unsigned int)(cp[1])) << 16;
+ result |= ((unsigned int)(cp[2])) << 8;
+ result |= ((unsigned int)(cp[3]));
+
+ return (result);
+}
+
+void
+lwres_buffer_putuint32(lwres_buffer_t *b, lwres_uint32_t val)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + 4 <= b->length);
+
+ cp = b->base;
+ cp += b->used;
+ b->used += 4;
+ cp[0] = (unsigned char)((val & 0xff000000) >> 24);
+ cp[1] = (unsigned char)((val & 0x00ff0000) >> 16);
+ cp[2] = (unsigned char)((val & 0x0000ff00) >> 8);
+ cp[3] = (unsigned char)(val & 0x000000ff);
+}
+
+void
+lwres_buffer_putmem(lwres_buffer_t *b, const unsigned char *base,
+ unsigned int length)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used + length <= b->length);
+
+ cp = (unsigned char *)b->base + b->used;
+ memcpy(cp, base, length);
+ b->used += length;
+}
+
+void
+lwres_buffer_getmem(lwres_buffer_t *b, unsigned char *base,
+ unsigned int length)
+{
+ unsigned char *cp;
+
+ REQUIRE(LWRES_BUFFER_VALID(b));
+ REQUIRE(b->used - b->current >= length);
+
+ cp = b->base;
+ cp += b->current;
+ b->current += length;
+
+ memcpy(base, cp, length);
+}
diff --git a/lib/liblwres/lwconfig.c b/lib/liblwres/lwconfig.c
new file mode 100644
index 000000000..f1c19b697
--- /dev/null
+++ b/lib/liblwres/lwconfig.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwconfig.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+/***
+ *** Module for parsing resolv.conf files.
+ ***
+ *** entry points are:
+ *** lwres_conf_init(lwres_context_t *ctx)
+ *** intializes data structure for subsequent config parsing.
+ ***
+ *** lwres_conf_parse(lwres_context_t *ctx, const char *filename)
+ *** parses a file and fills in the data structure.
+ ***
+ *** lwres_conf_print(lwres_context_t *ctx, FILE *fp)
+ *** prints the config data structure to the FILE.
+ ***
+ *** lwres_conf_clear(lwres_context_t *ctx)
+ *** frees up all the internal memory used by the config data
+ *** structure, returning it to the lwres_context_t.
+ ***
+ ***/
+
+#include <config.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+#include <lwres/result.h>
+
+#include "assert_p.h"
+#include "context_p.h"
+
+
+#if ! defined(NS_INADDRSZ)
+#define NS_INADDRSZ 4
+#endif
+
+#if ! defined(NS_IN6ADDRSZ)
+#define NS_IN6ADDRSZ 16
+#endif
+
+static lwres_result_t
+lwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp);
+
+static lwres_result_t
+lwres_conf_parseoption(lwres_context_t *ctx, FILE *fp);
+
+static void
+lwres_resetaddr(lwres_addr_t *addr);
+
+static lwres_result_t
+lwres_create_addr(const char *buff, lwres_addr_t *addr, int convert_zero);
+
+static int lwresaddr2af(int lwresaddrtype);
+
+
+static int
+lwresaddr2af(int lwresaddrtype)
+{
+ int af = 0;
+
+ switch (lwresaddrtype) {
+ case LWRES_ADDRTYPE_V4:
+ af = AF_INET;
+ break;
+
+ case LWRES_ADDRTYPE_V6:
+ af = AF_INET6;
+ break;
+ }
+
+ return (af);
+}
+
+
+/*
+ * Eat characters from FP until EOL or EOF. Returns EOF or '\n'
+ */
+static int
+eatline(FILE *fp) {
+ int ch;
+
+ ch = fgetc(fp);
+ while (ch != '\n' && ch != EOF)
+ ch = fgetc(fp);
+
+ return (ch);
+}
+
+
+/*
+ * Eats white space up to next newline or non-whitespace character (of
+ * EOF). Returns the last character read. Comments are considered white
+ * space.
+ */
+static int
+eatwhite(FILE *fp) {
+ int ch;
+
+ ch = fgetc(fp);
+ while (ch != '\n' && ch != EOF && isspace((unsigned char)ch))
+ ch = fgetc(fp);
+
+ if (ch == ';' || ch == '#')
+ ch = eatline(fp);
+
+ return (ch);
+}
+
+
+/*
+ * Skip over any leading whitespace and then read in the next sequence of
+ * non-whitespace characters. In this context newline is not considered
+ * whitespace. Returns EOF on end-of-file, or the character
+ * that caused the reading to stop.
+ */
+static int
+getword(FILE *fp, char *buffer, size_t size) {
+ int ch;
+ char *p = buffer;
+
+ REQUIRE(buffer != NULL);
+ REQUIRE(size > 0);
+
+ *p = '\0';
+
+ ch = eatwhite(fp);
+
+ if (ch == EOF)
+ return (EOF);
+
+ do {
+ *p = '\0';
+
+ if (ch == EOF || isspace((unsigned char)ch))
+ break;
+ else if ((size_t) (p - buffer) == size - 1)
+ return (EOF); /* Not enough space. */
+
+ *p++ = (char)ch;
+ ch = fgetc(fp);
+ } while (1);
+
+ return (ch);
+}
+
+static void
+lwres_resetaddr(lwres_addr_t *addr) {
+ REQUIRE(addr != NULL);
+
+ memset(addr->address, 0, LWRES_ADDR_MAXLEN);
+ addr->family = 0;
+ addr->length = 0;
+}
+
+static char *
+lwres_strdup(lwres_context_t *ctx, const char *str) {
+ char *p;
+
+ REQUIRE(str != NULL);
+ REQUIRE(strlen(str) > 0);
+
+ p = CTXMALLOC(strlen(str) + 1);
+ if (p != NULL)
+ strcpy(p, str);
+
+ return (p);
+}
+
+void
+lwres_conf_init(lwres_context_t *ctx) {
+ int i;
+ lwres_conf_t *confdata;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ confdata->nsnext = 0;
+ confdata->lwnext = 0;
+ confdata->domainname = NULL;
+ confdata->searchnxt = 0;
+ confdata->sortlistnxt = 0;
+ confdata->resdebug = 0;
+ confdata->ndots = 1;
+ confdata->no_tld_query = 0;
+
+ for (i = 0 ; i < LWRES_CONFMAXNAMESERVERS ; i++)
+ lwres_resetaddr(&confdata->nameservers[i]);
+
+ for (i = 0 ; i < LWRES_CONFMAXSEARCH ; i++)
+ confdata->search[i] = NULL;
+
+ for (i = 0 ; i < LWRES_CONFMAXSORTLIST ; i++) {
+ lwres_resetaddr(&confdata->sortlist[i].addr);
+ lwres_resetaddr(&confdata->sortlist[i].mask);
+ }
+}
+
+void
+lwres_conf_clear(lwres_context_t *ctx) {
+ int i;
+ lwres_conf_t *confdata;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ for (i = 0 ; i < confdata->nsnext ; i++)
+ lwres_resetaddr(&confdata->nameservers[i]);
+
+ if (confdata->domainname != NULL) {
+ CTXFREE(confdata->domainname,
+ strlen(confdata->domainname) + 1);
+ confdata->domainname = NULL;
+ }
+
+ for (i = 0 ; i < confdata->searchnxt ; i++) {
+ if (confdata->search[i] != NULL) {
+ CTXFREE(confdata->search[i],
+ strlen(confdata->search[i]) + 1);
+ confdata->search[i] = NULL;
+ }
+ }
+
+ for (i = 0 ; i < LWRES_CONFMAXSORTLIST ; i++) {
+ lwres_resetaddr(&confdata->sortlist[i].addr);
+ lwres_resetaddr(&confdata->sortlist[i].mask);
+ }
+
+ confdata->nsnext = 0;
+ confdata->lwnext = 0;
+ confdata->domainname = NULL;
+ confdata->searchnxt = 0;
+ confdata->sortlistnxt = 0;
+ confdata->resdebug = 0;
+ confdata->ndots = 1;
+ confdata->no_tld_query = 0;
+}
+
+static lwres_result_t
+lwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp) {
+ char word[LWRES_CONFMAXLINELEN];
+ int res;
+ lwres_conf_t *confdata;
+
+ confdata = &ctx->confdata;
+
+ if (confdata->nsnext == LWRES_CONFMAXNAMESERVERS)
+ return (LWRES_R_SUCCESS);
+
+ res = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0)
+ return (LWRES_R_FAILURE); /* Nothing on line. */
+ else if (res == ' ' || res == '\t')
+ res = eatwhite(fp);
+
+ if (res != EOF && res != '\n')
+ return (LWRES_R_FAILURE); /* Extra junk on line. */
+
+ res = lwres_create_addr(word,
+ &confdata->nameservers[confdata->nsnext++], 1);
+ if (res != LWRES_R_SUCCESS)
+ return (res);
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp) {
+ char word[LWRES_CONFMAXLINELEN];
+ int res;
+ lwres_conf_t *confdata;
+
+ confdata = &ctx->confdata;
+
+ if (confdata->lwnext == LWRES_CONFMAXLWSERVERS)
+ return (LWRES_R_SUCCESS);
+
+ res = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0)
+ return (LWRES_R_FAILURE); /* Nothing on line. */
+ else if (res == ' ' || res == '\t')
+ res = eatwhite(fp);
+
+ if (res != EOF && res != '\n')
+ return (LWRES_R_FAILURE); /* Extra junk on line. */
+
+ res = lwres_create_addr(word,
+ &confdata->lwservers[confdata->lwnext++], 1);
+ if (res != LWRES_R_SUCCESS)
+ return (res);
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp) {
+ char word[LWRES_CONFMAXLINELEN];
+ int res, i;
+ lwres_conf_t *confdata;
+
+ confdata = &ctx->confdata;
+
+ res = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0)
+ return (LWRES_R_FAILURE); /* Nothing else on line. */
+ else if (res == ' ' || res == '\t')
+ res = eatwhite(fp);
+
+ if (res != EOF && res != '\n')
+ return (LWRES_R_FAILURE); /* Extra junk on line. */
+
+ if (confdata->domainname != NULL)
+ CTXFREE(confdata->domainname,
+ strlen(confdata->domainname) + 1); /* */
+
+ /*
+ * Search and domain are mutually exclusive.
+ */
+ for (i = 0 ; i < LWRES_CONFMAXSEARCH ; i++) {
+ if (confdata->search[i] != NULL) {
+ CTXFREE(confdata->search[i],
+ strlen(confdata->search[i])+1);
+ confdata->search[i] = NULL;
+ }
+ }
+ confdata->searchnxt = 0;
+
+ confdata->domainname = lwres_strdup(ctx, word);
+
+ if (confdata->domainname == NULL)
+ return (LWRES_R_FAILURE);
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp) {
+ int idx, delim;
+ char word[LWRES_CONFMAXLINELEN];
+ lwres_conf_t *confdata;
+
+ confdata = &ctx->confdata;
+
+ if (confdata->domainname != NULL) {
+ /*
+ * Search and domain are mutually exclusive.
+ */
+ CTXFREE(confdata->domainname,
+ strlen(confdata->domainname) + 1);
+ confdata->domainname = NULL;
+ }
+
+ /*
+ * Remove any previous search definitions.
+ */
+ for (idx = 0 ; idx < LWRES_CONFMAXSEARCH ; idx++) {
+ if (confdata->search[idx] != NULL) {
+ CTXFREE(confdata->search[idx],
+ strlen(confdata->search[idx])+1);
+ confdata->search[idx] = NULL;
+ }
+ }
+ confdata->searchnxt = 0;
+
+ delim = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0)
+ return (LWRES_R_FAILURE); /* Nothing else on line. */
+
+ idx = 0;
+ while (strlen(word) > 0) {
+ if (confdata->searchnxt == LWRES_CONFMAXSEARCH)
+ goto ignore; /* Too many domains. */
+
+ confdata->search[idx] = lwres_strdup(ctx, word);
+ if (confdata->search[idx] == NULL)
+ return (LWRES_R_FAILURE);
+ idx++;
+ confdata->searchnxt++;
+
+ ignore:
+ if (delim == EOF || delim == '\n')
+ break;
+ else
+ delim = getword(fp, word, sizeof(word));
+ }
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_create_addr(const char *buffer, lwres_addr_t *addr, int convert_zero) {
+ struct in_addr v4;
+ struct in6_addr v6;
+
+ if (lwres_net_aton(buffer, &v4) == 1) {
+ if (convert_zero) {
+ unsigned char zeroaddress[] = {0, 0, 0, 0};
+ unsigned char loopaddress[] = {127, 0, 0, 1};
+ if (memcmp(&v4, zeroaddress, 4) == 0)
+ memcpy(&v4, loopaddress, 4);
+ }
+ addr->family = LWRES_ADDRTYPE_V4;
+ addr->length = NS_INADDRSZ;
+ memcpy((void *)addr->address, &v4, NS_INADDRSZ);
+
+ } else if (lwres_net_pton(AF_INET6, buffer, &v6) == 1) {
+ addr->family = LWRES_ADDRTYPE_V6;
+ addr->length = NS_IN6ADDRSZ;
+ memcpy((void *)addr->address, &v6, NS_IN6ADDRSZ);
+ } else {
+ return (LWRES_R_FAILURE); /* Unrecognised format. */
+ }
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp) {
+ int delim, res, idx;
+ char word[LWRES_CONFMAXLINELEN];
+ char *p;
+ lwres_conf_t *confdata;
+
+ confdata = &ctx->confdata;
+
+ delim = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0)
+ return (LWRES_R_FAILURE); /* Empty line after keyword. */
+
+ while (strlen(word) > 0) {
+ if (confdata->sortlistnxt == LWRES_CONFMAXSORTLIST)
+ return (LWRES_R_FAILURE); /* Too many values. */
+
+ p = strchr(word, '/');
+ if (p != NULL)
+ *p++ = '\0';
+
+ idx = confdata->sortlistnxt;
+ res = lwres_create_addr(word, &confdata->sortlist[idx].addr, 1);
+ if (res != LWRES_R_SUCCESS)
+ return (res);
+
+ if (p != NULL) {
+ res = lwres_create_addr(p,
+ &confdata->sortlist[idx].mask,
+ 0);
+ if (res != LWRES_R_SUCCESS)
+ return (res);
+ } else {
+ /*
+ * Make up a mask.
+ */
+ confdata->sortlist[idx].mask =
+ confdata->sortlist[idx].addr;
+
+ memset(&confdata->sortlist[idx].mask.address, 0xff,
+ confdata->sortlist[idx].addr.length);
+ }
+
+ confdata->sortlistnxt++;
+
+ if (delim == EOF || delim == '\n')
+ break;
+ else
+ delim = getword(fp, word, sizeof(word));
+ }
+
+ return (LWRES_R_SUCCESS);
+}
+
+static lwres_result_t
+lwres_conf_parseoption(lwres_context_t *ctx, FILE *fp) {
+ int delim;
+ long ndots;
+ char *p;
+ char word[LWRES_CONFMAXLINELEN];
+ lwres_conf_t *confdata;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ delim = getword(fp, word, sizeof(word));
+ if (strlen(word) == 0)
+ return (LWRES_R_FAILURE); /* Empty line after keyword. */
+
+ while (strlen(word) > 0) {
+ if (strcmp("debug", word) == 0) {
+ confdata->resdebug = 1;
+ } else if (strcmp("no_tld_query", word) == 0) {
+ confdata->no_tld_query = 1;
+ } else if (strncmp("ndots:", word, 6) == 0) {
+ ndots = strtol(word + 6, &p, 10);
+ if (*p != '\0') /* Bad string. */
+ return (LWRES_R_FAILURE);
+ if (ndots < 0 || ndots > 0xff) /* Out of range. */
+ return (LWRES_R_FAILURE);
+ confdata->ndots = (lwres_uint8_t)ndots;
+ }
+
+ if (delim == EOF || delim == '\n')
+ break;
+ else
+ delim = getword(fp, word, sizeof(word));
+ }
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_conf_parse(lwres_context_t *ctx, const char *filename) {
+ FILE *fp = NULL;
+ char word[256];
+ lwres_result_t rval, ret;
+ lwres_conf_t *confdata;
+ int stopchar;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(strlen(filename) > 0);
+ REQUIRE(confdata != NULL);
+
+ errno = 0;
+ if ((fp = fopen(filename, "r")) == NULL)
+ return (LWRES_R_FAILURE);
+
+ ret = LWRES_R_SUCCESS;
+ do {
+ stopchar = getword(fp, word, sizeof(word));
+ if (stopchar == EOF) {
+ rval = LWRES_R_SUCCESS;
+ break;
+ }
+
+ if (strlen(word) == 0)
+ rval = LWRES_R_SUCCESS;
+ else if (strcmp(word, "nameserver") == 0)
+ rval = lwres_conf_parsenameserver(ctx, fp);
+ else if (strcmp(word, "lwserver") == 0)
+ rval = lwres_conf_parselwserver(ctx, fp);
+ else if (strcmp(word, "domain") == 0)
+ rval = lwres_conf_parsedomain(ctx, fp);
+ else if (strcmp(word, "search") == 0)
+ rval = lwres_conf_parsesearch(ctx, fp);
+ else if (strcmp(word, "sortlist") == 0)
+ rval = lwres_conf_parsesortlist(ctx, fp);
+ else if (strcmp(word, "option") == 0)
+ rval = lwres_conf_parseoption(ctx, fp);
+ else {
+ /* unrecognised word. Ignore entire line */
+ rval = LWRES_R_SUCCESS;
+ stopchar = eatline(fp);
+ if (stopchar == EOF) {
+ break;
+ }
+ }
+ if (ret == LWRES_R_SUCCESS && rval != LWRES_R_SUCCESS)
+ ret = rval;
+ } while (1);
+
+ fclose(fp);
+
+ return (ret);
+}
+
+lwres_result_t
+lwres_conf_print(lwres_context_t *ctx, FILE *fp) {
+ int i;
+ int af;
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+ const char *p;
+ lwres_conf_t *confdata;
+ lwres_addr_t tmpaddr;
+
+ REQUIRE(ctx != NULL);
+ confdata = &ctx->confdata;
+
+ REQUIRE(confdata->nsnext <= LWRES_CONFMAXNAMESERVERS);
+
+ for (i = 0 ; i < confdata->nsnext ; i++) {
+ af = lwresaddr2af(confdata->nameservers[i].family);
+
+ p = lwres_net_ntop(af, confdata->nameservers[i].address,
+ tmp, sizeof(tmp));
+ if (p != tmp)
+ return (LWRES_R_FAILURE);
+
+ fprintf(fp, "nameserver %s\n", tmp);
+ }
+
+ for (i = 0 ; i < confdata->lwnext ; i++) {
+ af = lwresaddr2af(confdata->lwservers[i].family);
+
+ p = lwres_net_ntop(af, confdata->lwservers[i].address,
+ tmp, sizeof(tmp));
+ if (p != tmp)
+ return (LWRES_R_FAILURE);
+
+ fprintf(fp, "lwserver %s\n", tmp);
+ }
+
+ if (confdata->domainname != NULL) {
+ fprintf(fp, "domain %s\n", confdata->domainname);
+ } else if (confdata->searchnxt > 0) {
+ REQUIRE(confdata->searchnxt <= LWRES_CONFMAXSEARCH);
+
+ fprintf(fp, "search");
+ for (i = 0 ; i < confdata->searchnxt ; i++)
+ fprintf(fp, " %s", confdata->search[i]);
+ fputc('\n', fp);
+ }
+
+ REQUIRE(confdata->sortlistnxt <= LWRES_CONFMAXSORTLIST);
+
+ if (confdata->sortlistnxt > 0) {
+ fputs("sortlist", fp);
+ for (i = 0 ; i < confdata->sortlistnxt ; i++) {
+ af = lwresaddr2af(confdata->sortlist[i].addr.family);
+
+ p = lwres_net_ntop(af,
+ confdata->sortlist[i].addr.address,
+ tmp, sizeof(tmp));
+ if (p != tmp)
+ return (LWRES_R_FAILURE);
+
+ fprintf(fp, " %s", tmp);
+
+ tmpaddr = confdata->sortlist[i].mask;
+ memset(&tmpaddr.address, 0xff, tmpaddr.length);
+
+ if (memcmp(&tmpaddr.address,
+ confdata->sortlist[i].mask.address,
+ confdata->sortlist[i].mask.length) != 0) {
+ af = lwresaddr2af(
+ confdata->sortlist[i].mask.family);
+ p = lwres_net_ntop
+ (af,
+ confdata->sortlist[i].mask.address,
+ tmp, sizeof(tmp));
+ if (p != tmp)
+ return (LWRES_R_FAILURE);
+
+ fprintf(fp, "/%s", tmp);
+ }
+ }
+ fputc('\n', fp);
+ }
+
+ if (confdata->resdebug)
+ fprintf(fp, "options debug\n");
+
+ if (confdata->ndots > 0)
+ fprintf(fp, "options ndots:%d\n", confdata->ndots);
+
+ if (confdata->no_tld_query)
+ fprintf(fp, "options no_tld_query\n");
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_conf_t *
+lwres_conf_get(lwres_context_t *ctx) {
+ REQUIRE(ctx != NULL);
+
+ return (&ctx->confdata);
+}
diff --git a/lib/liblwres/lwinetaton.c b/lib/liblwres/lwinetaton.c
new file mode 100644
index 000000000..42a2cfa69
--- /dev/null
+++ b/lib/liblwres/lwinetaton.c
@@ -0,0 +1,203 @@
+/*
+ * Portions Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1983, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
+static char rcsid[] = "$Id: lwinetaton.c,v 1.1 2004/03/15 20:35:25 as Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <stddef.h>
+
+#include <lwres/int.h>
+#include <lwres/net.h>
+
+#include "assert_p.h"
+
+/*
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+lwres_net_aton(const char *cp, struct in_addr *addr) {
+ unsigned long val;
+ int base, n;
+ unsigned char c;
+ lwres_uint8_t parts[4];
+ lwres_uint8_t *pp = parts;
+ int digit;
+
+ REQUIRE(cp != NULL);
+
+ c = *cp;
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, isdigit=decimal.
+ */
+ if (!isdigit(c & 0xff))
+ return (0);
+ val = 0;
+ base = 10;
+ digit = 0;
+ if (c == '0') {
+ c = *++cp;
+ if (c == 'x' || c == 'X') {
+ base = 16;
+ c = *++cp;
+ } else {
+ base = 8;
+ digit = 1;
+ }
+ }
+ for (;;) {
+ /*
+ * isascii() is valid for all integer values, and
+ * when it is true, c is known to be in scope
+ * for isdigit(). No cast necessary. Similar
+ * comment applies for later ctype uses.
+ */
+ if (isascii(c) && isdigit(c)) {
+ if (base == 8 && (c == '8' || c == '9'))
+ return (0);
+ val = (val * base) + (c - '0');
+ c = *++cp;
+ digit = 1;
+ } else if (base == 16 && isascii(c) && isxdigit(c)) {
+ val = (val << 4) |
+ (c + 10 - (islower(c) ? 'a' : 'A'));
+ c = *++cp;
+ digit = 1;
+ } else
+ break;
+ }
+ if (c == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16 bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xff)
+ return (0);
+ *pp++ = (lwres_uint8_t)val;
+ c = *++cp;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && (!isascii(c) || !isspace(c)))
+ return (0);
+ /*
+ * Did we get a valid digit?
+ */
+ if (!digit)
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr != NULL)
+ addr->s_addr = htonl(val);
+
+ return (1);
+}
diff --git a/lib/liblwres/lwinetntop.c b/lib/liblwres/lwinetntop.c
new file mode 100644
index 000000000..dfc55a97c
--- /dev/null
+++ b/lib/liblwres/lwinetntop.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] =
+ "$Id: lwinetntop.c,v 1.1 2004/03/15 20:35:25 as Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <lwres/net.h>
+
+#define NS_INT16SZ 2
+#define NS_IN6ADDRSZ 16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4(const unsigned char *src, char *dst,
+ size_t size);
+
+#ifdef AF_INET6
+static const char *inet_ntop6(const unsigned char *src, char *dst,
+ size_t size);
+#endif
+
+/* char *
+ * lwres_net_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *
+lwres_net_ntop(int af, const void *src, char *dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a unsigned char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, size_t size) {
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+
+ if ((size_t)sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) >= size)
+ {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+
+ return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static const char *
+inet_ntop6(const unsigned char *src, char *dst, size_t size) {
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best, cur;
+ unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ cur.base = -1;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp,
+ sizeof tmp - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ tp += sprintf(tp, "%x", words[i]);
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+#endif /* AF_INET6 */
diff --git a/lib/liblwres/lwinetpton.c b/lib/liblwres/lwinetpton.c
new file mode 100644
index 000000000..792a74775
--- /dev/null
+++ b/lib/liblwres/lwinetpton.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$Id: lwinetpton.c,v 1.1 2004/03/15 20:35:25 as Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <lwres/net.h>
+
+#define NS_INT16SZ 2
+#define NS_INADDRSZ 4
+#define NS_IN6ADDRSZ 16
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+static int inet_pton6(const char *src, unsigned char *dst);
+
+/* int
+ * lwres_net_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+lwres_net_pton(int af, const char *src, void *dst) {
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst) {
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int new = *tp * 10 + (pch - digits);
+
+ if (new > 255)
+ return (0);
+ *tp = new;
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
diff --git a/lib/liblwres/lwpacket.c b/lib/liblwres/lwpacket.c
new file mode 100644
index 000000000..7bcdbbd4a
--- /dev/null
+++ b/lib/liblwres/lwpacket.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwpacket.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/result.h>
+
+#include "assert_p.h"
+
+#define LWPACKET_LENGTH \
+ (sizeof(lwres_uint16_t) * 4 + sizeof(lwres_uint32_t) * 5)
+
+lwres_result_t
+lwres_lwpacket_renderheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt) {
+ REQUIRE(b != NULL);
+ REQUIRE(pkt != NULL);
+
+ if (!SPACE_OK(b, LWPACKET_LENGTH))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ lwres_buffer_putuint32(b, pkt->length);
+ lwres_buffer_putuint16(b, pkt->version);
+ lwres_buffer_putuint16(b, pkt->pktflags);
+ lwres_buffer_putuint32(b, pkt->serial);
+ lwres_buffer_putuint32(b, pkt->opcode);
+ lwres_buffer_putuint32(b, pkt->result);
+ lwres_buffer_putuint32(b, pkt->recvlength);
+ lwres_buffer_putuint16(b, pkt->authtype);
+ lwres_buffer_putuint16(b, pkt->authlength);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_lwpacket_parseheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt) {
+ lwres_uint32_t space;
+
+ REQUIRE(b != NULL);
+ REQUIRE(pkt != NULL);
+
+ space = LWRES_BUFFER_REMAINING(b);
+ if (space < LWPACKET_LENGTH)
+ return (LWRES_R_UNEXPECTEDEND);
+
+ pkt->length = lwres_buffer_getuint32(b);
+ /*
+ * XXXBEW/MLG Checking that the buffer is long enough probably
+ * shouldn't be done here, since this function is supposed to just
+ * parse the header.
+ */
+ if (pkt->length > space)
+ return (LWRES_R_UNEXPECTEDEND);
+ pkt->version = lwres_buffer_getuint16(b);
+ pkt->pktflags = lwres_buffer_getuint16(b);
+ pkt->serial = lwres_buffer_getuint32(b);
+ pkt->opcode = lwres_buffer_getuint32(b);
+ pkt->result = lwres_buffer_getuint32(b);
+ pkt->recvlength = lwres_buffer_getuint32(b);
+ pkt->authtype = lwres_buffer_getuint16(b);
+ pkt->authlength = lwres_buffer_getuint16(b);
+
+ return (LWRES_R_SUCCESS);
+}
diff --git a/lib/liblwres/lwres_gabn.c b/lib/liblwres/lwres_gabn.c
new file mode 100644
index 000000000..5e809ba8e
--- /dev/null
+++ b/lib/liblwres/lwres_gabn.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwres_gabn.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "context_p.h"
+#include "assert_p.h"
+
+lwres_result_t
+lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(req->name != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ datalen = strlen(req->name);
+
+ payload_length = 4 + 4 + 2 + req->namelen + 1;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
+ pkt->result = 0;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Flags.
+ */
+ lwres_buffer_putuint32(b, req->flags);
+
+ /*
+ * Address types we'll accept.
+ */
+ lwres_buffer_putuint32(b, req->addrtypes);
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->name, datalen);
+ lwres_buffer_putuint8(b, 0); /* trailing NUL */
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+ lwres_addr_t *addr;
+ int x;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ /* naliases, naddrs */
+ payload_length = 4 + 2 + 2;
+ /* real name encoding */
+ payload_length += 2 + req->realnamelen + 1;
+ /* each alias */
+ for (x = 0 ; x < req->naliases ; x++)
+ payload_length += 2 + req->aliaslen[x] + 1;
+ /* each address */
+ x = 0;
+ addr = LWRES_LIST_HEAD(req->addrs);
+ while (addr != NULL) {
+ payload_length += 4 + 2;
+ payload_length += addr->length;
+ addr = LWRES_LIST_NEXT(addr, link);
+ x++;
+ }
+ INSIST(x == req->naddrs);
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ /*
+ * Check space needed here.
+ */
+ INSIST(SPACE_OK(b, payload_length));
+
+ /* Flags. */
+ lwres_buffer_putuint32(b, req->flags);
+
+ /* encode naliases and naddrs */
+ lwres_buffer_putuint16(b, req->naliases);
+ lwres_buffer_putuint16(b, req->naddrs);
+
+ /* encode the real name */
+ datalen = req->realnamelen;
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
+ lwres_buffer_putuint8(b, 0);
+
+ /* encode the aliases */
+ for (x = 0 ; x < req->naliases ; x++) {
+ datalen = req->aliaslen[x];
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
+ datalen);
+ lwres_buffer_putuint8(b, 0);
+ }
+
+ /* encode the addresses */
+ addr = LWRES_LIST_HEAD(req->addrs);
+ while (addr != NULL) {
+ lwres_buffer_putuint32(b, addr->family);
+ lwres_buffer_putuint16(b, addr->length);
+ lwres_buffer_putmem(b, addr->address, addr->length);
+ addr = LWRES_LIST_NEXT(addr, link);
+ }
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+ INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp)
+{
+ int ret;
+ char *name;
+ lwres_gabnrequest_t *gabn;
+ lwres_uint32_t addrtypes;
+ lwres_uint32_t flags;
+ lwres_uint16_t namelen;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
+ return (LWRES_R_FAILURE);
+
+ if (!SPACE_REMAINING(b, 4 + 4))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ flags = lwres_buffer_getuint32(b);
+ addrtypes = lwres_buffer_getuint32(b);
+
+ /*
+ * Pull off the name itself
+ */
+ ret = lwres_string_parse(b, &name, &namelen);
+ if (ret != LWRES_R_SUCCESS)
+ return (ret);
+
+ if (LWRES_BUFFER_REMAINING(b) != 0)
+ return (LWRES_R_TRAILINGDATA);
+
+ gabn = CTXMALLOC(sizeof(lwres_gabnrequest_t));
+ if (gabn == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ gabn->flags = flags;
+ gabn->addrtypes = addrtypes;
+ gabn->name = name;
+ gabn->namelen = namelen;
+
+ *structp = gabn;
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp)
+{
+ lwres_result_t ret;
+ unsigned int x;
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ lwres_gabnresponse_t *gabn;
+ lwres_addrlist_t addrlist;
+ lwres_addr_t *addr;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ gabn = NULL;
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
+ return (LWRES_R_FAILURE);
+
+ /*
+ * Pull off the name itself
+ */
+ if (!SPACE_REMAINING(b, 4 + 2 + 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ flags = lwres_buffer_getuint32(b);
+ naliases = lwres_buffer_getuint16(b);
+ naddrs = lwres_buffer_getuint16(b);
+
+ gabn = CTXMALLOC(sizeof(lwres_gabnresponse_t));
+ if (gabn == NULL)
+ return (LWRES_R_NOMEMORY);
+ gabn->aliases = NULL;
+ gabn->aliaslen = NULL;
+ LWRES_LIST_INIT(gabn->addrs);
+ gabn->base = NULL;
+
+ gabn->flags = flags;
+ gabn->naliases = naliases;
+ gabn->naddrs = naddrs;
+
+ LWRES_LIST_INIT(addrlist);
+
+ if (naliases > 0) {
+ gabn->aliases = CTXMALLOC(sizeof(char *) * naliases);
+ if (gabn->aliases == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ gabn->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
+ if (gabn->aliaslen == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ }
+
+ for (x = 0 ; x < naddrs ; x++) {
+ addr = CTXMALLOC(sizeof(lwres_addr_t));
+ if (addr == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ LWRES_LINK_INIT(addr, link);
+ LWRES_LIST_APPEND(addrlist, addr, link);
+ }
+
+ /*
+ * Now, pull off the real name.
+ */
+ ret = lwres_string_parse(b, &gabn->realname, &gabn->realnamelen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Parse off the aliases.
+ */
+ for (x = 0 ; x < gabn->naliases ; x++) {
+ ret = lwres_string_parse(b, &gabn->aliases[x],
+ &gabn->aliaslen[x]);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ }
+
+ /*
+ * Pull off the addresses. We already strung the linked list
+ * up above.
+ */
+ addr = LWRES_LIST_HEAD(addrlist);
+ for (x = 0 ; x < gabn->naddrs ; x++) {
+ INSIST(addr != NULL);
+ ret = lwres_addr_parse(b, addr);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ addr = LWRES_LIST_NEXT(addr, link);
+ }
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ gabn->addrs = addrlist;
+
+ *structp = gabn;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (gabn != NULL) {
+ if (gabn->aliases != NULL)
+ CTXFREE(gabn->aliases, sizeof(char *) * naliases);
+ if (gabn->aliaslen != NULL)
+ CTXFREE(gabn->aliaslen,
+ sizeof(lwres_uint16_t) * naliases);
+ addr = LWRES_LIST_HEAD(addrlist);
+ while (addr != NULL) {
+ LWRES_LIST_UNLINK(addrlist, addr, link);
+ CTXFREE(addr, sizeof(lwres_addr_t));
+ addr = LWRES_LIST_HEAD(addrlist);
+ }
+ CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
+ }
+
+ return (ret);
+}
+
+void
+lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp)
+{
+ lwres_gabnrequest_t *gabn;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ gabn = *structp;
+ *structp = NULL;
+
+ CTXFREE(gabn, sizeof(lwres_gabnrequest_t));
+}
+
+void
+lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp)
+{
+ lwres_gabnresponse_t *gabn;
+ lwres_addr_t *addr;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ gabn = *structp;
+ *structp = NULL;
+
+ if (gabn->naliases > 0) {
+ CTXFREE(gabn->aliases, sizeof(char *) * gabn->naliases);
+ CTXFREE(gabn->aliaslen,
+ sizeof(lwres_uint16_t) * gabn->naliases);
+ }
+ addr = LWRES_LIST_HEAD(gabn->addrs);
+ while (addr != NULL) {
+ LWRES_LIST_UNLINK(gabn->addrs, addr, link);
+ CTXFREE(addr, sizeof(lwres_addr_t));
+ addr = LWRES_LIST_HEAD(gabn->addrs);
+ }
+ if (gabn->base != NULL)
+ CTXFREE(gabn->base, gabn->baselen);
+ CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
+}
diff --git a/lib/liblwres/lwres_gnba.c b/lib/liblwres/lwres_gnba.c
new file mode 100644
index 000000000..293eb05ac
--- /dev/null
+++ b/lib/liblwres/lwres_gnba.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwres_gnba.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "context_p.h"
+#include "assert_p.h"
+
+lwres_result_t
+lwres_gnbarequest_render(lwres_context_t *ctx, lwres_gnbarequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(req->addr.family != 0);
+ REQUIRE(req->addr.length != 0);
+ REQUIRE(req->addr.address != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ payload_length = 4 + 4 + 2 + + req->addr.length;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR;
+ pkt->result = 0;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint32(b, req->flags);
+ lwres_buffer_putuint32(b, req->addr.family);
+ lwres_buffer_putuint16(b, req->addr.length);
+ lwres_buffer_putmem(b, (unsigned char *)req->addr.address,
+ req->addr.length);
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_gnbaresponse_render(lwres_context_t *ctx, lwres_gnbaresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+ int x;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ /*
+ * Calculate packet size.
+ */
+ payload_length = 4; /* flags */
+ payload_length += 2; /* naliases */
+ payload_length += 2 + req->realnamelen + 1; /* real name encoding */
+ for (x = 0 ; x < req->naliases ; x++) /* each alias */
+ payload_length += 2 + req->aliaslen[x] + 1;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+ lwres_buffer_putuint32(b, req->flags);
+
+ /* encode naliases */
+ lwres_buffer_putuint16(b, req->naliases);
+
+ /* encode the real name */
+ datalen = req->realnamelen;
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
+ lwres_buffer_putuint8(b, 0);
+
+ /* encode the aliases */
+ for (x = 0 ; x < req->naliases ; x++) {
+ datalen = req->aliaslen[x];
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
+ datalen);
+ lwres_buffer_putuint8(b, 0);
+ }
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_gnbarequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp)
+{
+ int ret;
+ lwres_gnbarequest_t *gnba;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
+ return (LWRES_R_FAILURE);
+
+ gnba = CTXMALLOC(sizeof(lwres_gnbarequest_t));
+ if (gnba == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ if (!SPACE_REMAINING(b, 4))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ gnba->flags = lwres_buffer_getuint32(b);
+
+ ret = lwres_addr_parse(b, &gnba->addr);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ *structp = gnba;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (gnba != NULL)
+ lwres_gnbarequest_free(ctx, &gnba);
+
+ return (ret);
+}
+
+lwres_result_t
+lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_gnbaresponse_t **structp)
+{
+ int ret;
+ unsigned int x;
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_gnbaresponse_t *gnba;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ gnba = NULL;
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
+ return (LWRES_R_FAILURE);
+
+ /*
+ * Pull off flags & naliases
+ */
+ if (!SPACE_REMAINING(b, 4 + 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ flags = lwres_buffer_getuint32(b);
+ naliases = lwres_buffer_getuint16(b);
+
+ gnba = CTXMALLOC(sizeof(lwres_gnbaresponse_t));
+ if (gnba == NULL)
+ return (LWRES_R_NOMEMORY);
+ gnba->base = NULL;
+ gnba->aliases = NULL;
+ gnba->aliaslen = NULL;
+
+ gnba->flags = flags;
+ gnba->naliases = naliases;
+
+ if (naliases > 0) {
+ gnba->aliases = CTXMALLOC(sizeof(char *) * naliases);
+ if (gnba->aliases == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ gnba->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
+ if (gnba->aliaslen == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ }
+
+ /*
+ * Now, pull off the real name.
+ */
+ ret = lwres_string_parse(b, &gnba->realname, &gnba->realnamelen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Parse off the aliases.
+ */
+ for (x = 0 ; x < gnba->naliases ; x++) {
+ ret = lwres_string_parse(b, &gnba->aliases[x],
+ &gnba->aliaslen[x]);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ }
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ *structp = gnba;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (gnba != NULL) {
+ if (gnba->aliases != NULL)
+ CTXFREE(gnba->aliases, sizeof(char *) * naliases);
+ if (gnba->aliaslen != NULL)
+ CTXFREE(gnba->aliaslen,
+ sizeof(lwres_uint16_t) * naliases);
+ CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
+ }
+
+ return (ret);
+}
+
+void
+lwres_gnbarequest_free(lwres_context_t *ctx, lwres_gnbarequest_t **structp)
+{
+ lwres_gnbarequest_t *gnba;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ gnba = *structp;
+ *structp = NULL;
+
+ CTXFREE(gnba, sizeof(lwres_gnbarequest_t));
+}
+
+void
+lwres_gnbaresponse_free(lwres_context_t *ctx, lwres_gnbaresponse_t **structp)
+{
+ lwres_gnbaresponse_t *gnba;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ gnba = *structp;
+ *structp = NULL;
+
+ if (gnba->naliases > 0) {
+ CTXFREE(gnba->aliases, sizeof(char *) * gnba->naliases);
+ CTXFREE(gnba->aliaslen,
+ sizeof(lwres_uint16_t) * gnba->naliases);
+ }
+ if (gnba->base != NULL)
+ CTXFREE(gnba->base, gnba->baselen);
+ CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
+}
diff --git a/lib/liblwres/lwres_grbn.c b/lib/liblwres/lwres_grbn.c
new file mode 100644
index 000000000..fd8de50a2
--- /dev/null
+++ b/lib/liblwres/lwres_grbn.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwres_grbn.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "context_p.h"
+#include "assert_p.h"
+
+lwres_result_t
+lwres_grbnrequest_render(lwres_context_t *ctx, lwres_grbnrequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(req->name != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ datalen = strlen(req->name);
+
+ payload_length = 4 + 2 + 2 + 2 + req->namelen + 1;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETRDATABYNAME;
+ pkt->result = 0;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Flags.
+ */
+ lwres_buffer_putuint32(b, req->flags);
+
+ /*
+ * Class.
+ */
+ lwres_buffer_putuint16(b, req->rdclass);
+
+ /*
+ * Type.
+ */
+ lwres_buffer_putuint16(b, req->rdtype);
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->name, datalen);
+ lwres_buffer_putuint8(b, 0); /* trailing NUL */
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_grbnresponse_render(lwres_context_t *ctx, lwres_grbnresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+ lwres_uint16_t datalen;
+ int x;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ /* flags, class, type, ttl, nrdatas, nsigs */
+ payload_length = 4 + 2 + 2 + 4 + 2 + 2;
+ /* real name encoding */
+ payload_length += 2 + req->realnamelen + 1;
+ /* each rr */
+ for (x = 0 ; x < req->nrdatas ; x++)
+ payload_length += 2 + req->rdatalen[x];
+ for (x = 0 ; x < req->nsigs ; x++)
+ payload_length += 2 + req->siglen[x];
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_GETRDATABYNAME;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ /*
+ * Check space needed here.
+ */
+ INSIST(SPACE_OK(b, payload_length));
+
+ /* Flags. */
+ lwres_buffer_putuint32(b, req->flags);
+
+ /* encode class, type, ttl, and nrdatas */
+ lwres_buffer_putuint16(b, req->rdclass);
+ lwres_buffer_putuint16(b, req->rdtype);
+ lwres_buffer_putuint32(b, req->ttl);
+ lwres_buffer_putuint16(b, req->nrdatas);
+ lwres_buffer_putuint16(b, req->nsigs);
+
+ /* encode the real name */
+ datalen = req->realnamelen;
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
+ lwres_buffer_putuint8(b, 0);
+
+ /* encode the rdatas */
+ for (x = 0 ; x < req->nrdatas ; x++) {
+ datalen = req->rdatalen[x];
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, req->rdatas[x], datalen);
+ }
+
+ /* encode the signatures */
+ for (x = 0 ; x < req->nsigs ; x++) {
+ datalen = req->siglen[x];
+ lwres_buffer_putuint16(b, datalen);
+ lwres_buffer_putmem(b, req->sigs[x], datalen);
+ }
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+ INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_grbnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_grbnrequest_t **structp)
+{
+ int ret;
+ char *name;
+ lwres_grbnrequest_t *grbn;
+ lwres_uint32_t flags;
+ lwres_uint16_t rdclass, rdtype;
+ lwres_uint16_t namelen;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
+ return (LWRES_R_FAILURE);
+
+ if (!SPACE_REMAINING(b, 4 + 2 + 2))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ /*
+ * Pull off the flags, class, and type.
+ */
+ flags = lwres_buffer_getuint32(b);
+ rdclass = lwres_buffer_getuint16(b);
+ rdtype = lwres_buffer_getuint16(b);
+
+ /*
+ * Pull off the name itself
+ */
+ ret = lwres_string_parse(b, &name, &namelen);
+ if (ret != LWRES_R_SUCCESS)
+ return (ret);
+
+ if (LWRES_BUFFER_REMAINING(b) != 0)
+ return (LWRES_R_TRAILINGDATA);
+
+ grbn = CTXMALLOC(sizeof(lwres_grbnrequest_t));
+ if (grbn == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ grbn->flags = flags;
+ grbn->rdclass = rdclass;
+ grbn->rdtype = rdtype;
+ grbn->name = name;
+ grbn->namelen = namelen;
+
+ *structp = grbn;
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_grbnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_grbnresponse_t **structp)
+{
+ lwres_result_t ret;
+ unsigned int x;
+ lwres_uint32_t flags;
+ lwres_uint16_t rdclass, rdtype;
+ lwres_uint32_t ttl;
+ lwres_uint16_t nrdatas, nsigs;
+ lwres_grbnresponse_t *grbn;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ grbn = NULL;
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
+ return (LWRES_R_FAILURE);
+
+ /*
+ * Pull off the flags, class, type, ttl, nrdatas, and nsigs
+ */
+ if (!SPACE_REMAINING(b, 4 + 2 + 2 + 4 + 2 + 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ flags = lwres_buffer_getuint32(b);
+ rdclass = lwres_buffer_getuint16(b);
+ rdtype = lwres_buffer_getuint16(b);
+ ttl = lwres_buffer_getuint32(b);
+ nrdatas = lwres_buffer_getuint16(b);
+ nsigs = lwres_buffer_getuint16(b);
+
+ /*
+ * Pull off the name itself
+ */
+
+ grbn = CTXMALLOC(sizeof(lwres_grbnresponse_t));
+ if (grbn == NULL)
+ return (LWRES_R_NOMEMORY);
+ grbn->rdatas = NULL;
+ grbn->rdatalen = NULL;
+ grbn->sigs = NULL;
+ grbn->siglen = NULL;
+ grbn->base = NULL;
+
+ grbn->flags = flags;
+ grbn->rdclass = rdclass;
+ grbn->rdtype = rdtype;
+ grbn->ttl = ttl;
+ grbn->nrdatas = nrdatas;
+ grbn->nsigs = nsigs;
+
+ if (nrdatas > 0) {
+ grbn->rdatas = CTXMALLOC(sizeof(char *) * nrdatas);
+ if (grbn->rdatas == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ grbn->rdatalen = CTXMALLOC(sizeof(lwres_uint16_t) * nrdatas);
+ if (grbn->rdatalen == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ }
+
+ if (nsigs > 0) {
+ grbn->sigs = CTXMALLOC(sizeof(char *) * nsigs);
+ if (grbn->sigs == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ grbn->siglen = CTXMALLOC(sizeof(lwres_uint16_t) * nsigs);
+ if (grbn->siglen == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+ }
+
+ /*
+ * Now, pull off the real name.
+ */
+ ret = lwres_string_parse(b, &grbn->realname, &grbn->realnamelen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Parse off the rdatas.
+ */
+ for (x = 0 ; x < grbn->nrdatas ; x++) {
+ ret = lwres_data_parse(b, &grbn->rdatas[x],
+ &grbn->rdatalen[x]);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ }
+
+ /*
+ * Parse off the signatures.
+ */
+ for (x = 0 ; x < grbn->nsigs ; x++) {
+ ret = lwres_data_parse(b, &grbn->sigs[x], &grbn->siglen[x]);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ }
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ *structp = grbn;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (grbn != NULL) {
+ if (grbn->rdatas != NULL)
+ CTXFREE(grbn->rdatas, sizeof(char *) * nrdatas);
+ if (grbn->rdatalen != NULL)
+ CTXFREE(grbn->rdatalen,
+ sizeof(lwres_uint16_t) * nrdatas);
+ if (grbn->sigs != NULL)
+ CTXFREE(grbn->sigs, sizeof(char *) * nsigs);
+ if (grbn->siglen != NULL)
+ CTXFREE(grbn->siglen, sizeof(lwres_uint16_t) * nsigs);
+ CTXFREE(grbn, sizeof(lwres_grbnresponse_t));
+ }
+
+ return (ret);
+}
+
+void
+lwres_grbnrequest_free(lwres_context_t *ctx, lwres_grbnrequest_t **structp)
+{
+ lwres_grbnrequest_t *grbn;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ grbn = *structp;
+ *structp = NULL;
+
+ CTXFREE(grbn, sizeof(lwres_grbnrequest_t));
+}
+
+void
+lwres_grbnresponse_free(lwres_context_t *ctx, lwres_grbnresponse_t **structp)
+{
+ lwres_grbnresponse_t *grbn;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ grbn = *structp;
+ *structp = NULL;
+
+ if (grbn->nrdatas > 0) {
+ CTXFREE(grbn->rdatas, sizeof(char *) * grbn->nrdatas);
+ CTXFREE(grbn->rdatalen,
+ sizeof(lwres_uint16_t) * grbn->nrdatas);
+ }
+ if (grbn->nsigs > 0) {
+ CTXFREE(grbn->sigs, sizeof(char *) * grbn->nsigs);
+ CTXFREE(grbn->siglen, sizeof(lwres_uint16_t) * grbn->nsigs);
+ }
+ if (grbn->base != NULL)
+ CTXFREE(grbn->base, grbn->baselen);
+ CTXFREE(grbn, sizeof(lwres_grbnresponse_t));
+}
diff --git a/lib/liblwres/lwres_noop.c b/lib/liblwres/lwres_noop.c
new file mode 100644
index 000000000..a75fba351
--- /dev/null
+++ b/lib/liblwres/lwres_noop.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwres_noop.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwpacket.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "context_p.h"
+#include "assert_p.h"
+
+lwres_result_t
+lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ payload_length = sizeof(lwres_uint16_t) + req->datalength;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_NOOP;
+ pkt->result = 0;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint16(b, req->datalength);
+ lwres_buffer_putmem(b, req->data, req->datalength);
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req,
+ lwres_lwpacket_t *pkt, lwres_buffer_t *b)
+{
+ unsigned char *buf;
+ size_t buflen;
+ int ret;
+ size_t payload_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(req != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(b != NULL);
+
+ payload_length = sizeof(lwres_uint16_t) + req->datalength;
+
+ buflen = LWRES_LWPACKET_LENGTH + payload_length;
+ buf = CTXMALLOC(buflen);
+ if (buf == NULL)
+ return (LWRES_R_NOMEMORY);
+ lwres_buffer_init(b, buf, buflen);
+
+ pkt->length = buflen;
+ pkt->version = LWRES_LWPACKETVERSION_0;
+ pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
+ pkt->opcode = LWRES_OPCODE_NOOP;
+ pkt->authtype = 0;
+ pkt->authlength = 0;
+
+ ret = lwres_lwpacket_renderheader(b, pkt);
+ if (ret != LWRES_R_SUCCESS) {
+ lwres_buffer_invalidate(b);
+ CTXFREE(buf, buflen);
+ return (ret);
+ }
+
+ INSIST(SPACE_OK(b, payload_length));
+
+ /*
+ * Put the length and the data. We know this will fit because we
+ * just checked for it.
+ */
+ lwres_buffer_putuint16(b, req->datalength);
+ lwres_buffer_putmem(b, req->data, req->datalength);
+
+ INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp)
+{
+ int ret;
+ lwres_nooprequest_t *req;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
+ return (LWRES_R_FAILURE);
+
+ req = CTXMALLOC(sizeof(lwres_nooprequest_t));
+ if (req == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
+ ret = LWRES_R_UNEXPECTEDEND;
+ goto out;
+ }
+ req->datalength = lwres_buffer_getuint16(b);
+
+ if (!SPACE_REMAINING(b, req->datalength)) {
+ ret = LWRES_R_UNEXPECTEDEND;
+ goto out;
+ }
+ req->data = b->base + b->current;
+ lwres_buffer_forward(b, req->datalength);
+
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ /* success! */
+ *structp = req;
+ return (LWRES_R_SUCCESS);
+
+ /* Error return */
+ out:
+ CTXFREE(req, sizeof(lwres_nooprequest_t));
+ return (ret);
+}
+
+lwres_result_t
+lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
+ lwres_lwpacket_t *pkt, lwres_noopresponse_t **structp)
+{
+ int ret;
+ lwres_noopresponse_t *req;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(b != NULL);
+ REQUIRE(pkt != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
+ return (LWRES_R_FAILURE);
+
+ req = CTXMALLOC(sizeof(lwres_noopresponse_t));
+ if (req == NULL)
+ return (LWRES_R_NOMEMORY);
+
+ if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
+ ret = LWRES_R_UNEXPECTEDEND;
+ goto out;
+ }
+ req->datalength = lwres_buffer_getuint16(b);
+
+ if (!SPACE_REMAINING(b, req->datalength)) {
+ ret = LWRES_R_UNEXPECTEDEND;
+ goto out;
+ }
+ req->data = b->base + b->current;
+
+ lwres_buffer_forward(b, req->datalength);
+ if (LWRES_BUFFER_REMAINING(b) != 0) {
+ ret = LWRES_R_TRAILINGDATA;
+ goto out;
+ }
+
+ /* success! */
+ *structp = req;
+ return (LWRES_R_SUCCESS);
+
+ /* Error return */
+ out:
+ CTXFREE(req, sizeof(lwres_noopresponse_t));
+ return (ret);
+}
+
+void
+lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp)
+{
+ lwres_noopresponse_t *noop;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ noop = *structp;
+ *structp = NULL;
+
+ CTXFREE(noop, sizeof(lwres_noopresponse_t));
+}
+
+void
+lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp)
+{
+ lwres_nooprequest_t *noop;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(structp != NULL && *structp != NULL);
+
+ noop = *structp;
+ *structp = NULL;
+
+ CTXFREE(noop, sizeof(lwres_nooprequest_t));
+}
diff --git a/lib/liblwres/lwresutil.c b/lib/liblwres/lwresutil.c
new file mode 100644
index 000000000..60f330e76
--- /dev/null
+++ b/lib/liblwres/lwresutil.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lwresutil.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <lwres/lwbuffer.h>
+#include <lwres/lwres.h>
+#include <lwres/result.h>
+
+#include "assert_p.h"
+#include "context_p.h"
+
+/*
+ * Requires:
+ *
+ * The "current" pointer in "b" points to encoded raw data.
+ *
+ * Ensures:
+ *
+ * The address of the first byte of the data is returned via "p",
+ * and the length is returned via "len". If NULL, they are not
+ * set.
+ *
+ * On return, the current pointer of "b" will point to the character
+ * following the data length and the data.
+ *
+ */
+lwres_result_t
+lwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len)
+{
+ lwres_uint16_t datalen;
+ unsigned char *data;
+
+ REQUIRE(b != NULL);
+
+ /*
+ * Pull off the length (2 bytes)
+ */
+ if (!SPACE_REMAINING(b, 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ datalen = lwres_buffer_getuint16(b);
+
+ /*
+ * Set the pointer to this string to the right place, then
+ * advance the buffer pointer.
+ */
+ if (!SPACE_REMAINING(b, datalen))
+ return (LWRES_R_UNEXPECTEDEND);
+ data = b->base + b->current;
+ lwres_buffer_forward(b, datalen);
+
+ if (len != NULL)
+ *len = datalen;
+ if (p != NULL)
+ *p = data;
+
+ return (LWRES_R_SUCCESS);
+}
+
+/*
+ * Requires:
+ *
+ * The "current" pointer in "b" point to an encoded string.
+ *
+ * Ensures:
+ *
+ * The address of the first byte of the string is returned via "c",
+ * and the length is returned via "len". If NULL, they are not
+ * set.
+ *
+ * On return, the current pointer of "b" will point to the character
+ * following the string length, the string, and the trailing NULL.
+ *
+ */
+lwres_result_t
+lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len)
+{
+ lwres_uint16_t datalen;
+ char *string;
+
+ REQUIRE(b != NULL);
+
+ /*
+ * Pull off the length (2 bytes)
+ */
+ if (!SPACE_REMAINING(b, 2))
+ return (LWRES_R_UNEXPECTEDEND);
+ datalen = lwres_buffer_getuint16(b);
+
+ /*
+ * Set the pointer to this string to the right place, then
+ * advance the buffer pointer.
+ */
+ if (!SPACE_REMAINING(b, datalen))
+ return (LWRES_R_UNEXPECTEDEND);
+ string = (char *)b->base + b->current;
+ lwres_buffer_forward(b, datalen);
+
+ /*
+ * Skip the "must be zero" byte.
+ */
+ if (!SPACE_REMAINING(b, 1))
+ return (LWRES_R_UNEXPECTEDEND);
+ if (0 != lwres_buffer_getuint8(b))
+ return (LWRES_R_FAILURE);
+
+ if (len != NULL)
+ *len = datalen;
+ if (c != NULL)
+ *c = string;
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr)
+{
+ REQUIRE(addr != NULL);
+
+ if (!SPACE_REMAINING(b, 6))
+ return (LWRES_R_UNEXPECTEDEND);
+
+ addr->family = lwres_buffer_getuint32(b);
+ addr->length = lwres_buffer_getuint16(b);
+
+ if (!SPACE_REMAINING(b, addr->length))
+ return (LWRES_R_UNEXPECTEDEND);
+ if (addr->length > LWRES_ADDR_MAXLEN)
+ return (LWRES_R_FAILURE);
+
+ lwres_buffer_getmem(b, addr->address, addr->length);
+
+ return (LWRES_R_SUCCESS);
+}
+
+lwres_result_t
+lwres_getaddrsbyname(lwres_context_t *ctx, const char *name,
+ lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp)
+{
+ lwres_gabnrequest_t request;
+ lwres_gabnresponse_t *response;
+ int ret;
+ int recvlen;
+ lwres_buffer_t b_in, b_out;
+ lwres_lwpacket_t pkt;
+ lwres_uint32_t serial;
+ char *buffer;
+ char target_name[1024];
+ unsigned int target_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(addrtypes != 0);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ b_in.base = NULL;
+ b_out.base = NULL;
+ response = NULL;
+ buffer = NULL;
+ serial = lwres_context_nextserial(ctx);
+
+ buffer = CTXMALLOC(LWRES_RECVLENGTH);
+ if (buffer == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ target_length = strlen(name);
+ if (target_length >= sizeof(target_name))
+ return (LWRES_R_FAILURE);
+ strcpy(target_name, name); /* strcpy is safe */
+
+ /*
+ * Set up our request and render it to a buffer.
+ */
+ request.flags = 0;
+ request.addrtypes = addrtypes;
+ request.name = target_name;
+ request.namelen = target_length;
+ pkt.pktflags = 0;
+ pkt.serial = serial;
+ pkt.result = 0;
+ pkt.recvlength = LWRES_RECVLENGTH;
+
+ again:
+ ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b_out);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
+ LWRES_RECVLENGTH, &recvlen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ lwres_buffer_init(&b_in, buffer, recvlen);
+ b_in.used = recvlen;
+
+ /*
+ * Parse the packet header.
+ */
+ ret = lwres_lwpacket_parseheader(&b_in, &pkt);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Sanity check.
+ */
+ if (pkt.serial != serial)
+ goto again;
+ if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME)
+ goto again;
+
+ /*
+ * Free what we've transmitted
+ */
+ CTXFREE(b_out.base, b_out.length);
+ b_out.base = NULL;
+ b_out.length = 0;
+
+ if (pkt.result != LWRES_R_SUCCESS) {
+ ret = pkt.result;
+ goto out;
+ }
+
+ /*
+ * Parse the response.
+ */
+ ret = lwres_gabnresponse_parse(ctx, &b_in, &pkt, &response);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ response->base = buffer;
+ response->baselen = LWRES_RECVLENGTH;
+ buffer = NULL; /* don't free this below */
+
+ *structp = response;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (b_out.base != NULL)
+ CTXFREE(b_out.base, b_out.length);
+ if (buffer != NULL)
+ CTXFREE(buffer, LWRES_RECVLENGTH);
+ if (response != NULL)
+ lwres_gabnresponse_free(ctx, &response);
+
+ return (ret);
+}
+
+
+lwres_result_t
+lwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype,
+ lwres_uint16_t addrlen, const unsigned char *addr,
+ lwres_gnbaresponse_t **structp)
+{
+ lwres_gnbarequest_t request;
+ lwres_gnbaresponse_t *response;
+ int ret;
+ int recvlen;
+ lwres_buffer_t b_in, b_out;
+ lwres_lwpacket_t pkt;
+ lwres_uint32_t serial;
+ char *buffer;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(addrtype != 0);
+ REQUIRE(addrlen != 0);
+ REQUIRE(addr != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ b_in.base = NULL;
+ b_out.base = NULL;
+ response = NULL;
+ buffer = NULL;
+ serial = lwres_context_nextserial(ctx);
+
+ buffer = CTXMALLOC(LWRES_RECVLENGTH);
+ if (buffer == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ /*
+ * Set up our request and render it to a buffer.
+ */
+ request.flags = 0;
+ request.addr.family = addrtype;
+ request.addr.length = addrlen;
+ memcpy(request.addr.address, addr, addrlen);
+ pkt.pktflags = 0;
+ pkt.serial = serial;
+ pkt.result = 0;
+ pkt.recvlength = LWRES_RECVLENGTH;
+
+ again:
+ ret = lwres_gnbarequest_render(ctx, &request, &pkt, &b_out);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
+ LWRES_RECVLENGTH, &recvlen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ lwres_buffer_init(&b_in, buffer, recvlen);
+ b_in.used = recvlen;
+
+ /*
+ * Parse the packet header.
+ */
+ ret = lwres_lwpacket_parseheader(&b_in, &pkt);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Sanity check.
+ */
+ if (pkt.serial != serial)
+ goto again;
+ if (pkt.opcode != LWRES_OPCODE_GETNAMEBYADDR)
+ goto again;
+
+ /*
+ * Free what we've transmitted
+ */
+ CTXFREE(b_out.base, b_out.length);
+ b_out.base = NULL;
+ b_out.length = 0;
+
+ if (pkt.result != LWRES_R_SUCCESS) {
+ ret = pkt.result;
+ goto out;
+ }
+
+ /*
+ * Parse the response.
+ */
+ ret = lwres_gnbaresponse_parse(ctx, &b_in, &pkt, &response);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ response->base = buffer;
+ response->baselen = LWRES_RECVLENGTH;
+ buffer = NULL; /* don't free this below */
+
+ *structp = response;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (b_out.base != NULL)
+ CTXFREE(b_out.base, b_out.length);
+ if (buffer != NULL)
+ CTXFREE(buffer, LWRES_RECVLENGTH);
+ if (response != NULL)
+ lwres_gnbaresponse_free(ctx, &response);
+
+ return (ret);
+}
+
+lwres_result_t
+lwres_getrdatabyname(lwres_context_t *ctx, const char *name,
+ lwres_uint16_t rdclass, lwres_uint16_t rdtype,
+ lwres_uint32_t flags, lwres_grbnresponse_t **structp)
+{
+ int ret;
+ int recvlen;
+ lwres_buffer_t b_in, b_out;
+ lwres_lwpacket_t pkt;
+ lwres_uint32_t serial;
+ char *buffer;
+ lwres_grbnrequest_t request;
+ lwres_grbnresponse_t *response;
+ char target_name[1024];
+ unsigned int target_length;
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(structp != NULL && *structp == NULL);
+
+ b_in.base = NULL;
+ b_out.base = NULL;
+ response = NULL;
+ buffer = NULL;
+ serial = lwres_context_nextserial(ctx);
+
+ buffer = CTXMALLOC(LWRES_RECVLENGTH);
+ if (buffer == NULL) {
+ ret = LWRES_R_NOMEMORY;
+ goto out;
+ }
+
+ target_length = strlen(name);
+ if (target_length >= sizeof(target_name))
+ return (LWRES_R_FAILURE);
+ strcpy(target_name, name); /* strcpy is safe */
+
+ /*
+ * Set up our request and render it to a buffer.
+ */
+ request.rdclass = rdclass;
+ request.rdtype = rdtype;
+ request.flags = flags;
+ request.name = target_name;
+ request.namelen = target_length;
+ pkt.pktflags = 0;
+ pkt.serial = serial;
+ pkt.result = 0;
+ pkt.recvlength = LWRES_RECVLENGTH;
+
+ again:
+ ret = lwres_grbnrequest_render(ctx, &request, &pkt, &b_out);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
+ LWRES_RECVLENGTH, &recvlen);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ lwres_buffer_init(&b_in, buffer, recvlen);
+ b_in.used = recvlen;
+
+ /*
+ * Parse the packet header.
+ */
+ ret = lwres_lwpacket_parseheader(&b_in, &pkt);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+
+ /*
+ * Sanity check.
+ */
+ if (pkt.serial != serial)
+ goto again;
+ if (pkt.opcode != LWRES_OPCODE_GETRDATABYNAME)
+ goto again;
+
+ /*
+ * Free what we've transmitted
+ */
+ CTXFREE(b_out.base, b_out.length);
+ b_out.base = NULL;
+ b_out.length = 0;
+
+ if (pkt.result != LWRES_R_SUCCESS) {
+ ret = pkt.result;
+ goto out;
+ }
+
+ /*
+ * Parse the response.
+ */
+ ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response);
+ if (ret != LWRES_R_SUCCESS)
+ goto out;
+ response->base = buffer;
+ response->baselen = LWRES_RECVLENGTH;
+ buffer = NULL; /* don't free this below */
+
+ *structp = response;
+ return (LWRES_R_SUCCESS);
+
+ out:
+ if (b_out.base != NULL)
+ CTXFREE(b_out.base, b_out.length);
+ if (buffer != NULL)
+ CTXFREE(buffer, LWRES_RECVLENGTH);
+ if (response != NULL)
+ lwres_grbnresponse_free(ctx, &response);
+
+ return (ret);
+}
diff --git a/lib/liblwres/man/Makefile.in b/lib/liblwres/man/Makefile.in
new file mode 100644
index 000000000..d06f370ad
--- /dev/null
+++ b/lib/liblwres/man/Makefile.in
@@ -0,0 +1,232 @@
+# Copyright (C) 2001 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.1 2004/03/15 20:35:25 as Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+@BIND9_MAKE_RULES@
+
+# Alphabetically
+#MANPAGES = lwres.3 lwres_addr_parse.3 lwres_buffer.3 \
+# lwres_buffer_add.3 lwres_buffer_back.3 lwres_buffer_clear.3 \
+# lwres_buffer_first.3 lwres_buffer_forward.3 \
+# lwres_buffer_getmem.3 lwres_buffer_getuint16.3 \
+# lwres_buffer_getuint32.3 lwres_buffer_getuint8.3 \
+# lwres_buffer_init.3 lwres_buffer_invalidate.3 \
+# lwres_buffer_putmem.3 lwres_buffer_putuint16.3 \
+# lwres_buffer_putuint32.3 lwres_buffer_putuint8.3 \
+# lwres_buffer_subtract.3 lwres_conf_clear.3 \
+# lwres_conf_get.3 lwres_conf_init.3 \
+# lwres_conf_parse.3 lwres_conf_print.3 \
+# lwres_config.3 lwres_context.3 \
+# lwres_context_allocmem.3 lwres_context_create.3 \
+# lwres_context_destroy.3 lwres_context_freemem.3 \
+# lwres_context_initserial.3 lwres_context_nextserial.3 \
+# lwres_context_sendrecv.3 lwres_endhostent.3 \
+# lwres_endhostent_r.3 lwres_freeaddrinfo.3 \
+# lwres_freehostent.3 lwres_gabn.3 \
+# lwres_gabnrequest_free.3 lwres_gabnrequest_parse.3 \
+# lwres_gabnrequest_render.3 lwres_gabnresponse_free.3 \
+# lwres_gabnresponse_parse.3 lwres_gabnresponse_render.3 \
+# lwres_gai_strerror.3 lwres_getaddrinfo.3 \
+# lwres_getaddrsbyname.3 lwres_gethostbyaddr.3 \
+# lwres_gethostbyaddr_r.3 lwres_gethostbyname.3 \
+# lwres_gethostbyname2.3 lwres_gethostbyname_r.3 \
+# lwres_gethostent.3 lwres_gethostent_r.3 \
+# lwres_getipnode.3 lwres_getipnodebyaddr.3 \
+# lwres_getipnodebyname.3 lwres_getnamebyaddr.3 \
+# lwres_getnameinfo.3 lwres_getrrsetbyname.3 \
+# lwres_gnba.3 lwres_gnbarequest_free.3 \
+# lwres_gnbarequest_parse.3 lwres_gnbarequest_render.3 \
+# lwres_gnbaresponse_free.3 lwres_gnbaresponse_parse.3 \
+# lwres_gnbaresponse_render.3 lwres_herror.3 \
+# lwres_hstrerror.3 lwres_inetntop.3 \
+# lwres_lwpacket_parseheader.3 lwres_lwpacket_renderheader.3 \
+# lwres_net_ntop.3 lwres_noop.3 \
+# lwres_nooprequest_free.3 lwres_nooprequest_parse.3 \
+# lwres_nooprequest_render.3 lwres_noopresponse_free.3 \
+# lwres_noopresponse_parse.3 lwres_noopresponse_render.3 \
+# lwres_packet.3 lwres_resutil.3 \
+# lwres_sethostent.3 lwres_sethostent_r.3 \
+# lwres_string_parse.3
+
+
+MANPAGES = lwres.3 lwres_buffer.3 lwres_config.3 lwres_context.3 \
+ lwres_gabn.3 lwres_gai_strerror.3 lwres_getaddrinfo.3 \
+ lwres_gethostent.3 lwres_getipnode.3 lwres_getnameinfo.3 \
+ lwres_getrrsetbyname.3 lwres_gnba.3 lwres_hstrerror.3 lwres_inetntop.3 \
+ lwres_noop.3 lwres_packet.3 lwres_resutil.3
+
+HTMLPAGES = lwres.html lwres_buffer.html lwres_config.html lwres_context.html \
+ lwres_gabn.html lwres_gai_strerror.html lwres_getaddrinfo.html \
+ lwres_gethostent.html lwres_getipnode.html lwres_getnameinfo.html \
+ lwres_getrrsetbyname.html lwres_gnba.html lwres_hstrerror.html lwres_inetntop.html \
+ lwres_noop.html lwres_packet.html lwres_resutil.html
+
+MANOBJS = ${MANPAGES} ${HTMLPAGES}
+
+doc man:: ${MANOBJS}
+
+docclean manclean maintainer-clean::
+ rm -f ${MANOBJS}
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man3
+
+man3 = ${DESTDIR}${mandir}/man3
+
+install:: installdirs
+ for m in ${MANPAGES}; do ${INSTALL_DATA} ${srcdir}/$$m ${DESTDIR}${mandir}/man3; done
+ rm -f ${man3}/lwres_addr_parse.3
+ @LN@ ${man3}/lwres_resutil.3 ${man3}/lwres_addr_parse.3
+ rm -f ${man3}/lwres_buffer_add.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_add.3
+ rm -f ${man3}/lwres_buffer_back.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_back.3
+ rm -f ${man3}/lwres_buffer_clear.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_clear.3
+ rm -f ${man3}/lwres_buffer_first.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_first.3
+ rm -f ${man3}/lwres_buffer_forward.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_forward.3
+ rm -f ${man3}/lwres_buffer_getmem.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_getmem.3
+ rm -f ${man3}/lwres_buffer_getuint16.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_getuint16.3
+ rm -f ${man3}/lwres_buffer_getuint32.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_getuint32.3
+ rm -f ${man3}/lwres_buffer_getuint8.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_getuint8.3
+ rm -f ${man3}/lwres_buffer_init.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_init.3
+ rm -f ${man3}/lwres_buffer_invalidate.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_invalidate.3
+ rm -f ${man3}/lwres_buffer_putmem.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_putmem.3
+ rm -f ${man3}/lwres_buffer_putuint16.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_putuint16.3
+ rm -f ${man3}/lwres_buffer_putuint32.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_putuint32.3
+ rm -f ${man3}/lwres_buffer_putuint8.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_putuint8.3
+ rm -f ${man3}/lwres_buffer_subtract.3
+ @LN@ ${man3}/lwres_buffer.3 ${man3}/lwres_buffer_subtract.3
+ rm -f ${man3}/lwres_conf_clear.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_clear.3
+ rm -f ${man3}/lwres_conf_get.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_get.3
+ rm -f ${man3}/lwres_conf_init.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_init.3
+ rm -f ${man3}/lwres_conf_parse.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_parse.3
+ rm -f ${man3}/lwres_conf_print.3
+ @LN@ ${man3}/lwres_config.3 ${man3}/lwres_conf_print.3
+ rm -f ${man3}/lwres_context_allocmem.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_allocmem.3
+ rm -f ${man3}/lwres_context_create.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_create.3
+ rm -f ${man3}/lwres_context_destroy.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_destroy.3
+ rm -f ${man3}/lwres_context_freemem.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_freemem.3
+ rm -f ${man3}/lwres_context_initserial.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_initserial.3
+ rm -f ${man3}/lwres_context_nextserial.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_nextserial.3
+ rm -f ${man3}/lwres_context_sendrecv.3
+ @LN@ ${man3}/lwres_context.3 ${man3}/lwres_context_sendrecv.3
+ rm -f ${man3}/lwres_endhostent.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_endhostent.3
+ rm -f ${man3}/lwres_endhostent_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_endhostent_r.3
+ rm -f ${man3}/lwres_freeaddrinfo.3
+ @LN@ ${man3}/lwres_getaddrinfo.3 ${man3}/lwres_freeaddrinfo.3
+ rm -f ${man3}/lwres_freehostent.3
+ @LN@ ${man3}/lwres_getipnode.3 ${man3}/lwres_freehostent.3
+ rm -f ${man3}/lwres_gabnrequest_free.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnrequest_free.3
+ rm -f ${man3}/lwres_gabnrequest_parse.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnrequest_parse.3
+ rm -f ${man3}/lwres_gabnrequest_render.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnrequest_render.3
+ rm -f ${man3}/lwres_gabnresponse_free.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnresponse_free.3
+ rm -f ${man3}/lwres_gabnresponse_parse.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnresponse_parse.3
+ rm -f ${man3}/lwres_gabnresponse_render.3
+ @LN@ ${man3}/lwres_gabn.3 ${man3}/lwres_gabnresponse_render.3
+ rm -f ${man3}/lwres_getaddrsbyname.3
+ @LN@ ${man3}/lwres_resutil.3 ${man3}/lwres_getaddrsbyname.3
+ rm -f ${man3}/lwres_gethostbyaddr.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyaddr.3
+ rm -f ${man3}/lwres_gethostbyaddr_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyaddr_r.3
+ rm -f ${man3}/lwres_gethostbyname.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyname.3
+ rm -f ${man3}/lwres_gethostbyname2.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyname2.3
+ rm -f ${man3}/lwres_gethostbyname_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostbyname_r.3
+ rm -f ${man3}/lwres_gethostent_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_gethostent_r.3
+ rm -f ${man3}/lwres_getipnodebyaddr.3
+ @LN@ ${man3}/lwres_getipnode.3 ${man3}/lwres_getipnodebyaddr.3
+ rm -f ${man3}/lwres_getipnodebyname.3
+ @LN@ ${man3}/lwres_getipnode.3 ${man3}/lwres_getipnodebyname.3
+ rm -f ${man3}/lwres_getnamebyaddr.3
+ @LN@ ${man3}/lwres_resutil.3 ${man3}/lwres_getnamebyaddr.3
+ rm -f ${man3}/lwres_gnbarequest_free.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbarequest_free.3
+ rm -f ${man3}/lwres_gnbarequest_parse.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbarequest_parse.3
+ rm -f ${man3}/lwres_gnbarequest_render.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbarequest_render.3
+ rm -f ${man3}/lwres_gnbaresponse_free.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbaresponse_free.3
+ rm -f ${man3}/lwres_gnbaresponse_parse.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbaresponse_parse.3
+ rm -f ${man3}/lwres_gnbaresponse_render.3
+ @LN@ ${man3}/lwres_gnba.3 ${man3}/lwres_gnbaresponse_render.3
+ rm -f ${man3}/lwres_herror.3
+ @LN@ ${man3}/lwres_hstrerror.3 ${man3}/lwres_herror.3
+ rm -f ${man3}/lwres_lwpacket_parseheader.3
+ @LN@ ${man3}/lwres_packet.3 ${man3}/lwres_lwpacket_parseheader.3
+ rm -f ${man3}/lwres_lwpacket_renderheader.3
+ @LN@ ${man3}/lwres_packet.3 ${man3}/lwres_lwpacket_renderheader.3
+ rm -f ${man3}/lwres_net_ntop.3
+ @LN@ ${man3}/lwres_inetntop.3 ${man3}/lwres_net_ntop.3
+ rm -f ${man3}/lwres_nooprequest_free.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_nooprequest_free.3
+ rm -f ${man3}/lwres_nooprequest_parse.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_nooprequest_parse.3
+ rm -f ${man3}/lwres_nooprequest_render.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_nooprequest_render.3
+ rm -f ${man3}/lwres_noopresponse_free.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_noopresponse_free.3
+ rm -f ${man3}/lwres_noopresponse_parse.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_noopresponse_parse.3
+ rm -f ${man3}/lwres_noopresponse_render.3
+ @LN@ ${man3}/lwres_noop.3 ${man3}/lwres_noopresponse_render.3
+ rm -f ${man3}/lwres_sethostent.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_sethostent.3
+ rm -f ${man3}/lwres_sethostent_r.3
+ @LN@ ${man3}/lwres_gethostent.3 ${man3}/lwres_sethostent_r.3
+ rm -f ${man3}/lwres_string_parse.3
+ @LN@ ${man3}/lwres_resutil.3 ${man3}/lwres_string_parse.3
diff --git a/lib/liblwres/man/lwres.3 b/lib/liblwres/man/lwres.3
new file mode 100644
index 000000000..f2393912d
--- /dev/null
+++ b/lib/liblwres/man/lwres.3
@@ -0,0 +1,158 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres \- introduction to the lightweight resolver library
+.SH SYNOPSIS
+\fB#include <lwres/lwres.h>\fR
+.SH "DESCRIPTION"
+.PP
+The BIND 9 lightweight resolver library is a simple, name service
+independent stub resolver library. It provides hostname-to-address
+and address-to-hostname lookup services to applications by
+transmitting lookup requests to a resolver daemon
+\fBlwresd\fR
+running on the local host. The resover daemon performs the
+lookup using the DNS or possibly other name service protocols,
+and returns the results to the application through the library.
+The library and resolver daemon communicate using a simple
+UDP-based protocol.
+.SH "OVERVIEW"
+.PP
+The lwresd library implements multiple name service APIs.
+The standard
+\fBgethostbyname()\fR,
+\fBgethostbyaddr()\fR,
+\fBgethostbyname_r()\fR,
+\fBgethostbyaddr_r()\fR,
+\fBgetaddrinfo()\fR,
+\fBgetipnodebyname()\fR,
+and
+\fBgetipnodebyaddr()\fR
+functions are all supported. To allow the lwres library to coexist
+with system libraries that define functions of the same name,
+the library defines these functions with names prefixed by
+lwres_.
+To define the standard names, applications must include the
+header file
+\fI<lwres/netdb.h>\fR
+which contains macro definitions mapping the standard function names
+into
+lwres_
+prefixed ones. Operating system vendors who integrate the lwres
+library into their base distributions should rename the functions
+in the library proper so that the renaming macros are not needed.
+.PP
+The library also provides a native API consisting of the functions
+\fBlwres_getaddrsbyname()\fR
+and
+\fBlwres_getnamebyaddr()\fR.
+These may be called by applications that require more detailed
+control over the lookup process than the standard functions
+provide.
+.PP
+In addition to these name service independent address lookup
+functions, the library implements a new, experimental API
+for looking up arbitrary DNS resource records, using the
+\fBlwres_getaddrsbyname()\fR
+function.
+.PP
+Finally, there is a low-level API for converting lookup
+requests and responses to and from raw lwres protocol packets.
+This API can be used by clients requiring nonblocking operation,
+and is also used when implementing the server side of the lwres
+protocol, for example in the
+\fBlwresd\fR
+resolver daemon. The use of this low-level API in clients
+and servers is outlined in the following sections.
+.SH "CLIENT-SIDE LOW-LEVEL API CALL FLOW"
+.PP
+When a client program wishes to make an lwres request using the
+native low-level API, it typically performs the following
+sequence of actions.
+.PP
+(1) Allocate or use an existing \fBlwres_packet_t\fR,
+called pkt below.
+.PP
+(2) Set \fBpkt.recvlength\fR to the maximum length we will accept.
+This is done so the receiver of our packets knows how large our receive
+buffer is. The "default" is a constant in
+\fIlwres.h\fR: LWRES_RECVLENGTH = 4096.
+.PP
+(3) Set \fBpkt.serial\fR
+to a unique serial number. This value is echoed
+back to the application by the remote server.
+.PP
+(4) Set \fBpkt.pktflags\fR. Usually this is set to 0.
+.PP
+(5) Set \fBpkt.result\fR to 0.
+.PP
+(6) Call \fBlwres_*request_render()\fR,
+or marshall in the data using the primitives
+such as \fBlwres_packet_render()\fR
+and storing the packet data.
+.PP
+(7) Transmit the resulting buffer.
+.PP
+(8) Call \fBlwres_*response_parse()\fR
+to parse any packets received.
+.PP
+(9) Verify that the opcode and serial match a request, and process the
+packet specific information contained in the body.
+.SH "SERVER-SIDE LOW-LEVEL API CALL FLOW"
+.PP
+When implementing the server side of the lightweight resolver
+protocol using the lwres library, a sequence of actions like the
+following is typically involved in processing each request packet.
+.PP
+Note that the same \fBlwres_packet_t\fR is used
+in both the \fB_parse()\fR and \fB_render()\fR calls,
+with only a few modifications made
+to the packet header's contents between uses. This method is recommended
+as it keeps the serial, opcode, and other fields correct.
+.PP
+(1) When a packet is received, call \fBlwres_*request_parse()\fR to
+unmarshall it. This returns a \fBlwres_packet_t\fR (also called pkt, below)
+as well as a data specific type, such as \fBlwres_gabnrequest_t\fR.
+.PP
+(2) Process the request in the data specific type.
+.PP
+(3) Set the \fBpkt.result\fR,
+\fBpkt.recvlength\fR as above. All other fields can
+be left untouched since they were filled in by the \fB*_parse()\fR call
+above. If using \fBlwres_*response_render()\fR,
+\fBpkt.pktflags\fR will be set up
+properly. Otherwise, the LWRES_LWPACKETFLAG_RESPONSE bit should be
+set.
+.PP
+(4) Call the data specific rendering function, such as
+\fBlwres_gabnresponse_render()\fR.
+.PP
+(5) Send the resulting packet to the client.
+.PP
+.SH "SEE ALSO"
+.PP
+\fBlwres_gethostent\fR(3),
+\fBlwres_getipnode\fR(3),
+\fBlwres_getnameinfo\fR(3),
+\fBlwres_noop\fR(3),
+\fBlwres_gabn\fR(3),
+\fBlwres_gnba\fR(3),
+\fBlwres_context\fR(3),
+\fBlwres_config\fR(3),
+\fBresolver\fR(5),
+\fBlwresd\fR(8).
diff --git a/lib/liblwres/man/lwres.docbook b/lib/liblwres/man/lwres.docbook
new file mode 100644
index 000000000..15378e908
--- /dev/null
+++ b/lib/liblwres/man/lwres.docbook
@@ -0,0 +1,244 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+<refentryinfo>
+
+<date>Jun 30, 2000</date>
+</refentryinfo>
+<refmeta>
+<refentrytitle>lwres</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+<refnamediv>
+<refname>lwres</refname>
+<refpurpose>introduction to the lightweight resolver library</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+The BIND 9 lightweight resolver library is a simple, name service
+independent stub resolver library. It provides hostname-to-address
+and address-to-hostname lookup services to applications by
+transmitting lookup requests to a resolver daemon
+<command>lwresd</command>
+running on the local host. The resover daemon performs the
+lookup using the DNS or possibly other name service protocols,
+and returns the results to the application through the library.
+The library and resolver daemon communicate using a simple
+UDP-based protocol.
+</para>
+</refsect1>
+
+<refsect1>
+<title>OVERVIEW</title>
+<para>
+The lwresd library implements multiple name service APIs.
+The standard
+<function>gethostbyname()</function>,
+<function>gethostbyaddr()</function>,
+<function>gethostbyname_r()</function>,
+<function>gethostbyaddr_r()</function>,
+<function>getaddrinfo()</function>,
+<function>getipnodebyname()</function>,
+and
+<function>getipnodebyaddr()</function>
+functions are all supported. To allow the lwres library to coexist
+with system libraries that define functions of the same name,
+the library defines these functions with names prefixed by
+<literal>lwres_</literal>.
+To define the standard names, applications must include the
+header file
+<filename>&lt;lwres/netdb.h&gt;</filename>
+which contains macro definitions mapping the standard function names
+into
+<literal>lwres_</literal>
+prefixed ones. Operating system vendors who integrate the lwres
+library into their base distributions should rename the functions
+in the library proper so that the renaming macros are not needed.
+</para>
+<para>
+The library also provides a native API consisting of the functions
+<function>lwres_getaddrsbyname()</function>
+and
+<function>lwres_getnamebyaddr()</function>.
+These may be called by applications that require more detailed
+control over the lookup process than the standard functions
+provide.
+</para>
+<para>
+In addition to these name service independent address lookup
+functions, the library implements a new, experimental API
+for looking up arbitrary DNS resource records, using the
+<function>lwres_getaddrsbyname()</function>
+function.
+</para>
+<para>
+Finally, there is a low-level API for converting lookup
+requests and responses to and from raw lwres protocol packets.
+This API can be used by clients requiring nonblocking operation,
+and is also used when implementing the server side of the lwres
+protocol, for example in the
+<command>lwresd</command>
+resolver daemon. The use of this low-level API in clients
+and servers is outlined in the following sections.
+</para>
+</refsect1>
+<refsect1>
+<title>CLIENT-SIDE LOW-LEVEL API CALL FLOW</title>
+<para>
+When a client program wishes to make an lwres request using the
+native low-level API, it typically performs the following
+sequence of actions.
+</para>
+<para>
+(1) Allocate or use an existing <type>lwres_packet_t</type>,
+called <varname>pkt</varname> below.
+</para>
+<para>
+(2) Set <structfield>pkt.recvlength</structfield> to the maximum length we will accept.
+This is done so the receiver of our packets knows how large our receive
+buffer is. The "default" is a constant in
+<filename>lwres.h</filename>: <constant>LWRES_RECVLENGTH = 4096</constant>.
+</para>
+<para>
+(3) Set <structfield>pkt.serial</structfield>
+to a unique serial number. This value is echoed
+back to the application by the remote server.
+</para>
+<para>
+(4) Set <structfield>pkt.pktflags</structfield>. Usually this is set to 0.
+</para>
+<para>
+(5) Set <structfield>pkt.result</structfield> to 0.
+</para>
+<para>
+(6) Call <function>lwres_*request_render()</function>,
+or marshall in the data using the primitives
+such as <function>lwres_packet_render()</function>
+and storing the packet data.
+</para>
+<para>
+(7) Transmit the resulting buffer.
+</para>
+<para>
+(8) Call <function>lwres_*response_parse()</function>
+to parse any packets received.
+</para>
+<para>
+(9) Verify that the opcode and serial match a request, and process the
+packet specific information contained in the body.
+</para>
+</refsect1>
+<refsect1>
+<title>SERVER-SIDE LOW-LEVEL API CALL FLOW</title>
+<para>
+When implementing the server side of the lightweight resolver
+protocol using the lwres library, a sequence of actions like the
+following is typically involved in processing each request packet.
+</para>
+<para>
+Note that the same <type>lwres_packet_t</type> is used
+in both the <function>_parse()</function> and <function>_render()</function> calls,
+with only a few modifications made
+to the packet header's contents between uses. This method is recommended
+as it keeps the serial, opcode, and other fields correct.
+</para>
+<para>
+(1) When a packet is received, call <function>lwres_*request_parse()</function> to
+unmarshall it. This returns a <type>lwres_packet_t</type> (also called <varname>pkt</varname>, below)
+as well as a data specific type, such as <type>lwres_gabnrequest_t</type>.
+</para>
+<para>
+(2) Process the request in the data specific type.
+</para>
+<para>
+(3) Set the <structfield>pkt.result</structfield>,
+<structfield>pkt.recvlength</structfield> as above. All other fields can
+be left untouched since they were filled in by the <function>*_parse()</function> call
+above. If using <function>lwres_*response_render()</function>,
+<structfield>pkt.pktflags</structfield> will be set up
+properly. Otherwise, the <constant>LWRES_LWPACKETFLAG_RESPONSE</constant> bit should be
+set.
+</para>
+<para>
+(4) Call the data specific rendering function, such as
+<function>lwres_gabnresponse_render()</function>.
+</para>
+<para>
+(5) Send the resulting packet to the client.
+</para>
+<para>
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>lwres_gethostent</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_getipnode</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_noop</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_gabn</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_gnba</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_context</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_config</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>resolver</refentrytitle><manvolnum>5</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwresd</refentrytitle><manvolnum>8</manvolnum>
+</citerefentry>.
+
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres.html b/lib/liblwres/man/lwres.html
new file mode 100644
index 000000000..7b9f88dcb
--- /dev/null
+++ b/lib/liblwres/man/lwres.html
@@ -0,0 +1,444 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres&nbsp;--&nbsp;introduction to the lightweight resolver library</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN11"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN12"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/lwres.h&gt;</PRE
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN14"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>The BIND 9 lightweight resolver library is a simple, name service
+independent stub resolver library. It provides hostname-to-address
+and address-to-hostname lookup services to applications by
+transmitting lookup requests to a resolver daemon
+<B
+CLASS="COMMAND"
+>lwresd</B
+>
+running on the local host. The resover daemon performs the
+lookup using the DNS or possibly other name service protocols,
+and returns the results to the application through the library.
+The library and resolver daemon communicate using a simple
+UDP-based protocol.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN18"
+></A
+><H2
+>OVERVIEW</H2
+><P
+>The lwresd library implements multiple name service APIs.
+The standard
+<TT
+CLASS="FUNCTION"
+>gethostbyname()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>gethostbyaddr()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>gethostbyname_r()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>gethostbyaddr_r()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>getaddrinfo()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>getipnodebyname()</TT
+>,
+and
+<TT
+CLASS="FUNCTION"
+>getipnodebyaddr()</TT
+>
+functions are all supported. To allow the lwres library to coexist
+with system libraries that define functions of the same name,
+the library defines these functions with names prefixed by
+<TT
+CLASS="LITERAL"
+>lwres_</TT
+>.
+To define the standard names, applications must include the
+header file
+<TT
+CLASS="FILENAME"
+>&lt;lwres/netdb.h&gt;</TT
+>
+which contains macro definitions mapping the standard function names
+into
+<TT
+CLASS="LITERAL"
+>lwres_</TT
+>
+prefixed ones. Operating system vendors who integrate the lwres
+library into their base distributions should rename the functions
+in the library proper so that the renaming macros are not needed.</P
+><P
+>The library also provides a native API consisting of the functions
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrsbyname()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_getnamebyaddr()</TT
+>.
+These may be called by applications that require more detailed
+control over the lookup process than the standard functions
+provide.</P
+><P
+>In addition to these name service independent address lookup
+functions, the library implements a new, experimental API
+for looking up arbitrary DNS resource records, using the
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrsbyname()</TT
+>
+function.</P
+><P
+>Finally, there is a low-level API for converting lookup
+requests and responses to and from raw lwres protocol packets.
+This API can be used by clients requiring nonblocking operation,
+and is also used when implementing the server side of the lwres
+protocol, for example in the
+<B
+CLASS="COMMAND"
+>lwresd</B
+>
+resolver daemon. The use of this low-level API in clients
+and servers is outlined in the following sections.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN38"
+></A
+><H2
+>CLIENT-SIDE LOW-LEVEL API CALL FLOW</H2
+><P
+>When a client program wishes to make an lwres request using the
+native low-level API, it typically performs the following
+sequence of actions.</P
+><P
+>(1) Allocate or use an existing <SPAN
+CLASS="TYPE"
+>lwres_packet_t</SPAN
+>,
+called <TT
+CLASS="VARNAME"
+>pkt</TT
+> below.</P
+><P
+>(2) Set <TT
+CLASS="STRUCTFIELD"
+><I
+>pkt.recvlength</I
+></TT
+> to the maximum length we will accept.
+This is done so the receiver of our packets knows how large our receive
+buffer is. The "default" is a constant in
+<TT
+CLASS="FILENAME"
+>lwres.h</TT
+>: <TT
+CLASS="CONSTANT"
+>LWRES_RECVLENGTH = 4096</TT
+>.</P
+><P
+>(3) Set <TT
+CLASS="STRUCTFIELD"
+><I
+>pkt.serial</I
+></TT
+>
+to a unique serial number. This value is echoed
+back to the application by the remote server.</P
+><P
+>(4) Set <TT
+CLASS="STRUCTFIELD"
+><I
+>pkt.pktflags</I
+></TT
+>. Usually this is set to 0.</P
+><P
+>(5) Set <TT
+CLASS="STRUCTFIELD"
+><I
+>pkt.result</I
+></TT
+> to 0.</P
+><P
+>(6) Call <TT
+CLASS="FUNCTION"
+>lwres_*request_render()</TT
+>,
+or marshall in the data using the primitives
+such as <TT
+CLASS="FUNCTION"
+>lwres_packet_render()</TT
+>
+and storing the packet data.</P
+><P
+>(7) Transmit the resulting buffer.</P
+><P
+>(8) Call <TT
+CLASS="FUNCTION"
+>lwres_*response_parse()</TT
+>
+to parse any packets received.</P
+><P
+>(9) Verify that the opcode and serial match a request, and process the
+packet specific information contained in the body.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN61"
+></A
+><H2
+>SERVER-SIDE LOW-LEVEL API CALL FLOW</H2
+><P
+>When implementing the server side of the lightweight resolver
+protocol using the lwres library, a sequence of actions like the
+following is typically involved in processing each request packet.</P
+><P
+>Note that the same <SPAN
+CLASS="TYPE"
+>lwres_packet_t</SPAN
+> is used
+in both the <TT
+CLASS="FUNCTION"
+>_parse()</TT
+> and <TT
+CLASS="FUNCTION"
+>_render()</TT
+> calls,
+with only a few modifications made
+to the packet header's contents between uses. This method is recommended
+as it keeps the serial, opcode, and other fields correct.</P
+><P
+>(1) When a packet is received, call <TT
+CLASS="FUNCTION"
+>lwres_*request_parse()</TT
+> to
+unmarshall it. This returns a <SPAN
+CLASS="TYPE"
+>lwres_packet_t</SPAN
+> (also called <TT
+CLASS="VARNAME"
+>pkt</TT
+>, below)
+as well as a data specific type, such as <SPAN
+CLASS="TYPE"
+>lwres_gabnrequest_t</SPAN
+>.</P
+><P
+>(2) Process the request in the data specific type.</P
+><P
+>(3) Set the <TT
+CLASS="STRUCTFIELD"
+><I
+>pkt.result</I
+></TT
+>,
+<TT
+CLASS="STRUCTFIELD"
+><I
+>pkt.recvlength</I
+></TT
+> as above. All other fields can
+be left untouched since they were filled in by the <TT
+CLASS="FUNCTION"
+>*_parse()</TT
+> call
+above. If using <TT
+CLASS="FUNCTION"
+>lwres_*response_render()</TT
+>,
+<TT
+CLASS="STRUCTFIELD"
+><I
+>pkt.pktflags</I
+></TT
+> will be set up
+properly. Otherwise, the <TT
+CLASS="CONSTANT"
+>LWRES_LWPACKETFLAG_RESPONSE</TT
+> bit should be
+set.</P
+><P
+>(4) Call the data specific rendering function, such as
+<TT
+CLASS="FUNCTION"
+>lwres_gabnresponse_render()</TT
+>.</P
+><P
+>(5) Send the resulting packet to the client.</P
+><P
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN85"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_gethostent</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_getipnode</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_getnameinfo</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_noop</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_gabn</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_gnba</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_context</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_config</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>resolver</SPAN
+>(5)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwresd</SPAN
+>(8)</SPAN
+>.&#13;</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_buffer.3 b/lib/liblwres/man/lwres_buffer.3
new file mode 100644
index 000000000..8077fc2ef
--- /dev/null
+++ b/lib/liblwres/man/lwres_buffer.3
@@ -0,0 +1,277 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_BUFFER" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_buffer_init, lwres_buffer_invalidate, lwres_buffer_add, lwres_buffer_subtract, lwres_buffer_clear, lwres_buffer_first, lwres_buffer_forward, lwres_buffer_back, lwres_buffer_getuint8, lwres_buffer_putuint8, lwres_buffer_getuint16, lwres_buffer_putuint16, lwres_buffer_getuint32, lwres_buffer_putuint32, lwres_buffer_putmem, lwres_buffer_getmem \- lightweight resolver buffer management
+.SH SYNOPSIS
+\fB#include <lwres/lwbuffer.h>
+.sp
+.na
+void
+lwres_buffer_init(lwres_buffer_t *b, void *base, unsigned int length);
+.ad
+.sp
+.na
+void
+lwres_buffer_invalidate(lwres_buffer_t *b);
+.ad
+.sp
+.na
+void
+lwres_buffer_add(lwres_buffer_t *b, unsigned int n);
+.ad
+.sp
+.na
+void
+lwres_buffer_subtract(lwres_buffer_t *b, unsigned int n);
+.ad
+.sp
+.na
+void
+lwres_buffer_clear(lwres_buffer_t *b);
+.ad
+.sp
+.na
+void
+lwres_buffer_first(lwres_buffer_t *b);
+.ad
+.sp
+.na
+void
+lwres_buffer_forward(lwres_buffer_t *b, unsigned int n);
+.ad
+.sp
+.na
+void
+lwres_buffer_back(lwres_buffer_t *b, unsigned int n);
+.ad
+.sp
+.na
+lwres_uint8_t
+lwres_buffer_getuint8(lwres_buffer_t *b);
+.ad
+.sp
+.na
+void
+lwres_buffer_putuint8(lwres_buffer_t *b, lwres_uint8_t val);
+.ad
+.sp
+.na
+lwres_uint16_t
+lwres_buffer_getuint16(lwres_buffer_t *b);
+.ad
+.sp
+.na
+void
+lwres_buffer_putuint16(lwres_buffer_t *b, lwres_uint16_t val);
+.ad
+.sp
+.na
+lwres_uint32_t
+lwres_buffer_getuint32(lwres_buffer_t *b);
+.ad
+.sp
+.na
+void
+lwres_buffer_putuint32(lwres_buffer_t *b, lwres_uint32_t val);
+.ad
+.sp
+.na
+void
+lwres_buffer_putmem(lwres_buffer_t *b, const unsigned char *base, unsigned int length);
+.ad
+.sp
+.na
+void
+lwres_buffer_getmem(lwres_buffer_t *b, unsigned char *base, unsigned int length);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+These functions provide bounds checked access to a region of memory
+where data is being read or written.
+They are based on, and similar to, the
+isc_buffer_
+functions in the ISC library.
+.PP
+A buffer is a region of memory, together with a set of related
+subregions.
+The \fBused region\fR and the
+\fBavailable\fR region are disjoint, and
+their union is the buffer's region.
+The used region extends from the beginning of the buffer region to the
+last used byte.
+The available region extends from one byte greater than the last used
+byte to the end of the buffer's region.
+The size of the used region can be changed using various
+buffer commands.
+Initially, the used region is empty.
+.PP
+The used region is further subdivided into two disjoint regions: the
+\fBconsumed region\fR and the \fBremaining region\fR.
+The union of these two regions is the used region.
+The consumed region extends from the beginning of the used region to
+the byte before the \fBcurrent\fR offset (if any).
+The \fBremaining\fR region the current pointer to the end of the used
+region.
+The size of the consumed region can be changed using various
+buffer commands.
+Initially, the consumed region is empty.
+.PP
+The \fBactive region\fR is an (optional) subregion of the remaining
+region.
+It extends from the current offset to an offset in the
+remaining region.
+Initially, the active region is empty.
+If the current offset advances beyond the chosen offset,
+the active region will also be empty.
+.PP
+.sp
+.nf
+
+ /------------entire length---------------\\\\
+ /----- used region -----\\\\/-- available --\\\\
+ +----------------------------------------+
+ | consumed | remaining | |
+ +----------------------------------------+
+ a b c d e
+
+ a == base of buffer.
+ b == current pointer. Can be anywhere between a and d.
+ c == active pointer. Meaningful between b and d.
+ d == used pointer.
+ e == length of buffer.
+
+ a-e == entire length of buffer.
+ a-d == used region.
+ a-b == consumed region.
+ b-d == remaining region.
+ b-c == optional active region.
+.sp
+.fi
+.PP
+\fBlwres_buffer_init()\fR
+initializes the
+\fBlwres_buffer_t\fR
+\fI*b\fR
+and assocates it with the memory region of size
+\fIlength\fR
+bytes starting at location
+\fIbase.\fR
+.PP
+\fBlwres_buffer_invalidate()\fR
+marks the buffer
+\fI*b\fR
+as invalid. Invalidating a buffer after use is not required,
+but makes it possible to catch its possible accidental use.
+.PP
+The functions
+\fBlwres_buffer_add()\fR
+and
+\fBlwres_buffer_subtract()\fR
+respectively increase and decrease the used space in
+buffer
+\fI*b\fR
+by
+\fIn\fR
+bytes.
+\fBlwres_buffer_add()\fR
+checks for buffer overflow and
+\fBlwres_buffer_subtract()\fR
+checks for underflow.
+These functions do not allocate or deallocate memory.
+They just change the value of
+\fBused\fR.
+.PP
+A buffer is re-initialised by
+\fBlwres_buffer_clear()\fR.
+The function sets
+\fBused\fR ,
+\fBcurrent\fR
+and
+\fBactive\fR
+to zero.
+.PP
+\fBlwres_buffer_first\fR
+makes the consumed region of buffer
+\fI*p\fR
+empty by setting
+\fBcurrent\fR
+to zero (the start of the buffer).
+.PP
+\fBlwres_buffer_forward()\fR
+increases the consumed region of buffer
+\fI*b\fR
+by
+\fIn\fR
+bytes, checking for overflow.
+Similarly,
+\fBlwres_buffer_back()\fR
+decreases buffer
+\fIb\fR's
+consumed region by
+\fIn\fR
+bytes and checks for underflow.
+.PP
+\fBlwres_buffer_getuint8()\fR
+reads an unsigned 8-bit integer from
+\fI*b\fR
+and returns it.
+\fBlwres_buffer_putuint8()\fR
+writes the unsigned 8-bit integer
+\fIval\fR
+to buffer
+\fI*b\fR.
+.PP
+\fBlwres_buffer_getuint16()\fR
+and
+\fBlwres_buffer_getuint32()\fR
+are identical to
+\fBlwres_buffer_putuint8()\fR
+except that they respectively read an unsigned 16-bit or 32-bit integer
+in network byte order from
+\fIb\fR.
+Similarly,
+\fBlwres_buffer_putuint16()\fR
+and
+\fBlwres_buffer_putuint32()\fR
+writes the unsigned 16-bit or 32-bit integer
+\fIval\fR
+to buffer
+\fIb\fR,
+in network byte order.
+.PP
+Arbitrary amounts of data are read or written from a lightweight
+resolver buffer with
+\fBlwres_buffer_getmem()\fR
+and
+\fBlwres_buffer_putmem()\fR
+respectively.
+\fBlwres_buffer_putmem()\fR
+copies
+\fIlength\fR
+bytes of memory at
+\fIbase\fR
+to
+\fIb\fR.
+Conversely,
+\fBlwres_buffer_getmem()\fR
+copies
+\fIlength\fR
+bytes of memory from
+\fIb\fR
+to
+\fIbase\fR.
diff --git a/lib/liblwres/man/lwres_buffer.docbook b/lib/liblwres/man/lwres_buffer.docbook
new file mode 100644
index 000000000..8f9d55889
--- /dev/null
+++ b/lib/liblwres/man/lwres_buffer.docbook
@@ -0,0 +1,378 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_buffer.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_buffer</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_buffer_init</refname>
+<refname>lwres_buffer_invalidate</refname>
+<refname>lwres_buffer_add</refname>
+<refname>lwres_buffer_subtract</refname>
+<refname>lwres_buffer_clear</refname>
+<refname>lwres_buffer_first</refname>
+<refname>lwres_buffer_forward</refname>
+<refname>lwres_buffer_back</refname>
+<refname>lwres_buffer_getuint8</refname>
+<refname>lwres_buffer_putuint8</refname>
+<refname>lwres_buffer_getuint16</refname>
+<refname>lwres_buffer_putuint16</refname>
+<refname>lwres_buffer_getuint32</refname>
+<refname>lwres_buffer_putuint32</refname>
+<refname>lwres_buffer_putmem</refname>
+<refname>lwres_buffer_getmem</refname>
+<refpurpose>lightweight resolver buffer management</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+
+<funcsynopsis>
+<funcsynopsisinfo>
+#include &lt;lwres/lwbuffer.h&gt;
+</funcsynopsisinfo>
+
+<funcprototype>
+
+<funcdef>
+void
+<function>lwres_buffer_init</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>void *base</paramdef>
+<paramdef>unsigned int length</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_invalidate</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_add</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>unsigned int n</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_subtract</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>unsigned int n</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_clear</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_first</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_forward</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>unsigned int n</paramdef>
+</funcprototype>
+<funcprototype>
+
+<funcdef>
+void
+<function>lwres_buffer_back</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>unsigned int n</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+lwres_uint8_t
+<function>lwres_buffer_getuint8</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_putuint8</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_uint8_t val</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+lwres_uint16_t
+<function>lwres_buffer_getuint16</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_putuint16</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_uint16_t val</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+lwres_uint32_t
+<function>lwres_buffer_getuint32</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_putuint32</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_uint32_t val</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_putmem</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>const unsigned char *base</paramdef>
+<paramdef>unsigned int length</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_buffer_getmem</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>unsigned char *base</paramdef>
+<paramdef>unsigned int length</paramdef>
+</funcprototype>
+
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+
+<title>DESCRIPTION</title>
+<para>
+These functions provide bounds checked access to a region of memory
+where data is being read or written.
+They are based on, and similar to, the
+<literal>isc_buffer_</literal>
+functions in the ISC library.
+</para>
+<para>
+A buffer is a region of memory, together with a set of related
+subregions.
+The <emphasis>used region</emphasis> and the
+<emphasis>available</emphasis> region are disjoint, and
+their union is the buffer's region.
+The used region extends from the beginning of the buffer region to the
+last used byte.
+The available region extends from one byte greater than the last used
+byte to the end of the buffer's region.
+The size of the used region can be changed using various
+buffer commands.
+Initially, the used region is empty.
+</para>
+<para>
+The used region is further subdivided into two disjoint regions: the
+<emphasis>consumed region</emphasis> and the <emphasis>remaining region</emphasis>.
+The union of these two regions is the used region.
+The consumed region extends from the beginning of the used region to
+the byte before the <emphasis>current</emphasis> offset (if any).
+The <emphasis>remaining</emphasis> region the current pointer to the end of the used
+region.
+The size of the consumed region can be changed using various
+buffer commands.
+Initially, the consumed region is empty.
+</para>
+<para>
+The <emphasis>active region</emphasis> is an (optional) subregion of the remaining
+region.
+It extends from the current offset to an offset in the
+remaining region.
+Initially, the active region is empty.
+If the current offset advances beyond the chosen offset,
+the active region will also be empty.
+</para>
+<para>
+<programlisting>
+
+ /------------entire length---------------\\
+ /----- used region -----\\/-- available --\\
+ +----------------------------------------+
+ | consumed | remaining | |
+ +----------------------------------------+
+ a b c d e
+
+ a == base of buffer.
+ b == current pointer. Can be anywhere between a and d.
+ c == active pointer. Meaningful between b and d.
+ d == used pointer.
+ e == length of buffer.
+
+ a-e == entire length of buffer.
+ a-d == used region.
+ a-b == consumed region.
+ b-d == remaining region.
+ b-c == optional active region.
+</programlisting>
+</para>
+<para>
+<function>lwres_buffer_init()</function>
+initializes the
+<type>lwres_buffer_t</type>
+<parameter>*b</parameter>
+and assocates it with the memory region of size
+<parameter>length</parameter>
+bytes starting at location
+<parameter>base.</parameter>
+</para>
+<para>
+<function>lwres_buffer_invalidate()</function>
+marks the buffer
+<parameter>*b</parameter>
+as invalid. Invalidating a buffer after use is not required,
+but makes it possible to catch its possible accidental use.
+</para>
+<para>
+The functions
+<function>lwres_buffer_add()</function>
+and
+<function>lwres_buffer_subtract()</function>
+respectively increase and decrease the used space in
+buffer
+<parameter>*b</parameter>
+by
+<parameter>n</parameter>
+bytes.
+<function>lwres_buffer_add()</function>
+checks for buffer overflow and
+<function>lwres_buffer_subtract()</function>
+checks for underflow.
+These functions do not allocate or deallocate memory.
+They just change the value of
+<structfield>used</structfield>.
+</para>
+<para>
+A buffer is re-initialised by
+<function>lwres_buffer_clear()</function>.
+The function sets
+<structfield>used</structfield> ,
+<structfield>current</structfield>
+and
+<structfield>active</structfield>
+to zero.
+</para>
+<para>
+<function>lwres_buffer_first</function>
+makes the consumed region of buffer
+<parameter>*p</parameter>
+empty by setting
+<structfield>current</structfield>
+to zero (the start of the buffer).
+</para>
+<para>
+<function>lwres_buffer_forward()</function>
+increases the consumed region of buffer
+<parameter>*b</parameter>
+by
+<parameter>n</parameter>
+bytes, checking for overflow.
+Similarly,
+<function>lwres_buffer_back()</function>
+decreases buffer
+<parameter>b</parameter>'s
+consumed region by
+<parameter>n</parameter>
+bytes and checks for underflow.
+</para>
+<para>
+<function>lwres_buffer_getuint8()</function>
+reads an unsigned 8-bit integer from
+<parameter>*b</parameter>
+and returns it.
+<function>lwres_buffer_putuint8()</function>
+writes the unsigned 8-bit integer
+<parameter>val</parameter>
+to buffer
+<parameter>*b</parameter>.
+</para>
+<para>
+<function>lwres_buffer_getuint16()</function>
+and
+<function>lwres_buffer_getuint32()</function>
+are identical to
+<function>lwres_buffer_putuint8()</function>
+except that they respectively read an unsigned 16-bit or 32-bit integer
+in network byte order from
+<parameter>b</parameter>.
+Similarly,
+<function>lwres_buffer_putuint16()</function>
+and
+<function>lwres_buffer_putuint32()</function>
+writes the unsigned 16-bit or 32-bit integer
+<parameter>val</parameter>
+to buffer
+<parameter>b</parameter>,
+in network byte order.
+</para>
+<para>
+Arbitrary amounts of data are read or written from a lightweight
+resolver buffer with
+<function>lwres_buffer_getmem()</function>
+and
+<function>lwres_buffer_putmem()</function>
+respectively.
+<function>lwres_buffer_putmem()</function>
+copies
+<parameter>length</parameter>
+bytes of memory at
+<parameter>base</parameter>
+to
+<parameter>b</parameter>.
+Conversely,
+<function>lwres_buffer_getmem()</function>
+copies
+<parameter>length</parameter>
+bytes of memory from
+<parameter>b</parameter>
+to
+<parameter>base</parameter>.
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_buffer.html b/lib/liblwres/man/lwres_buffer.html
new file mode 100644
index 000000000..ae2ffd50c
--- /dev/null
+++ b/lib/liblwres/man/lwres_buffer.html
@@ -0,0 +1,608 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_buffer</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_buffer</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_buffer_init, lwres_buffer_invalidate, lwres_buffer_add, lwres_buffer_subtract, lwres_buffer_clear, lwres_buffer_first, lwres_buffer_forward, lwres_buffer_back, lwres_buffer_getuint8, lwres_buffer_putuint8, lwres_buffer_getuint16, lwres_buffer_putuint16, lwres_buffer_getuint32, lwres_buffer_putuint32, lwres_buffer_putmem, lwres_buffer_getmem&nbsp;--&nbsp;lightweight resolver buffer management</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN26"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN27"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/lwbuffer.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_init</CODE
+>(lwres_buffer_t *b, void *base, unsigned int length);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_invalidate</CODE
+>(lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_add</CODE
+>(lwres_buffer_t *b, unsigned int n);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_subtract</CODE
+>(lwres_buffer_t *b, unsigned int n);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_clear</CODE
+>(lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_first</CODE
+>(lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_forward</CODE
+>(lwres_buffer_t *b, unsigned int n);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_back</CODE
+>(lwres_buffer_t *b, unsigned int n);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_uint8_t
+lwres_buffer_getuint8</CODE
+>(lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_putuint8</CODE
+>(lwres_buffer_t *b, lwres_uint8_t val);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_uint16_t
+lwres_buffer_getuint16</CODE
+>(lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_putuint16</CODE
+>(lwres_buffer_t *b, lwres_uint16_t val);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_uint32_t
+lwres_buffer_getuint32</CODE
+>(lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_putuint32</CODE
+>(lwres_buffer_t *b, lwres_uint32_t val);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_putmem</CODE
+>(lwres_buffer_t *b, const unsigned char *base, unsigned int length);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_buffer_getmem</CODE
+>(lwres_buffer_t *b, unsigned char *base, unsigned int length);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN106"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>These functions provide bounds checked access to a region of memory
+where data is being read or written.
+They are based on, and similar to, the
+<TT
+CLASS="LITERAL"
+>isc_buffer_</TT
+>
+functions in the ISC library.</P
+><P
+>A buffer is a region of memory, together with a set of related
+subregions.
+The <I
+CLASS="EMPHASIS"
+>used region</I
+> and the
+<I
+CLASS="EMPHASIS"
+>available</I
+> region are disjoint, and
+their union is the buffer's region.
+The used region extends from the beginning of the buffer region to the
+last used byte.
+The available region extends from one byte greater than the last used
+byte to the end of the buffer's region.
+The size of the used region can be changed using various
+buffer commands.
+Initially, the used region is empty.</P
+><P
+>The used region is further subdivided into two disjoint regions: the
+<I
+CLASS="EMPHASIS"
+>consumed region</I
+> and the <I
+CLASS="EMPHASIS"
+>remaining region</I
+>.
+The union of these two regions is the used region.
+The consumed region extends from the beginning of the used region to
+the byte before the <I
+CLASS="EMPHASIS"
+>current</I
+> offset (if any).
+The <I
+CLASS="EMPHASIS"
+>remaining</I
+> region the current pointer to the end of the used
+region.
+The size of the consumed region can be changed using various
+buffer commands.
+Initially, the consumed region is empty.</P
+><P
+>The <I
+CLASS="EMPHASIS"
+>active region</I
+> is an (optional) subregion of the remaining
+region.
+It extends from the current offset to an offset in the
+remaining region.
+Initially, the active region is empty.
+If the current offset advances beyond the chosen offset,
+the active region will also be empty.</P
+><P
+><PRE
+CLASS="PROGRAMLISTING"
+>
+ /------------entire length---------------\\
+ /----- used region -----\\/-- available --\\
+ +----------------------------------------+
+ | consumed | remaining | |
+ +----------------------------------------+
+ a b c d e
+
+ a == base of buffer.
+ b == current pointer. Can be anywhere between a and d.
+ c == active pointer. Meaningful between b and d.
+ d == used pointer.
+ e == length of buffer.
+
+ a-e == entire length of buffer.
+ a-d == used region.
+ a-b == consumed region.
+ b-d == remaining region.
+ b-c == optional active region.</PRE
+></P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_buffer_init()</TT
+>
+initializes the
+<SPAN
+CLASS="TYPE"
+>lwres_buffer_t</SPAN
+>
+<TT
+CLASS="PARAMETER"
+><I
+>*b</I
+></TT
+>
+and assocates it with the memory region of size
+<TT
+CLASS="PARAMETER"
+><I
+>length</I
+></TT
+>
+bytes starting at location
+<TT
+CLASS="PARAMETER"
+><I
+>base.</I
+></TT
+></P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_buffer_invalidate()</TT
+>
+marks the buffer
+<TT
+CLASS="PARAMETER"
+><I
+>*b</I
+></TT
+>
+as invalid. Invalidating a buffer after use is not required,
+but makes it possible to catch its possible accidental use.</P
+><P
+>The functions
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_add()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_subtract()</TT
+>
+respectively increase and decrease the used space in
+buffer
+<TT
+CLASS="PARAMETER"
+><I
+>*b</I
+></TT
+>
+by
+<TT
+CLASS="PARAMETER"
+><I
+>n</I
+></TT
+>
+bytes.
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_add()</TT
+>
+checks for buffer overflow and
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_subtract()</TT
+>
+checks for underflow.
+These functions do not allocate or deallocate memory.
+They just change the value of
+<TT
+CLASS="STRUCTFIELD"
+><I
+>used</I
+></TT
+>.</P
+><P
+>A buffer is re-initialised by
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_clear()</TT
+>.
+The function sets
+<TT
+CLASS="STRUCTFIELD"
+><I
+>used</I
+></TT
+> ,
+<TT
+CLASS="STRUCTFIELD"
+><I
+>current</I
+></TT
+>
+and
+<TT
+CLASS="STRUCTFIELD"
+><I
+>active</I
+></TT
+>
+to zero.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_buffer_first</TT
+>
+makes the consumed region of buffer
+<TT
+CLASS="PARAMETER"
+><I
+>*p</I
+></TT
+>
+empty by setting
+<TT
+CLASS="STRUCTFIELD"
+><I
+>current</I
+></TT
+>
+to zero (the start of the buffer).</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_buffer_forward()</TT
+>
+increases the consumed region of buffer
+<TT
+CLASS="PARAMETER"
+><I
+>*b</I
+></TT
+>
+by
+<TT
+CLASS="PARAMETER"
+><I
+>n</I
+></TT
+>
+bytes, checking for overflow.
+Similarly,
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_back()</TT
+>
+decreases buffer
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>'s
+consumed region by
+<TT
+CLASS="PARAMETER"
+><I
+>n</I
+></TT
+>
+bytes and checks for underflow.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_buffer_getuint8()</TT
+>
+reads an unsigned 8-bit integer from
+<TT
+CLASS="PARAMETER"
+><I
+>*b</I
+></TT
+>
+and returns it.
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_putuint8()</TT
+>
+writes the unsigned 8-bit integer
+<TT
+CLASS="PARAMETER"
+><I
+>val</I
+></TT
+>
+to buffer
+<TT
+CLASS="PARAMETER"
+><I
+>*b</I
+></TT
+>.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_buffer_getuint16()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_getuint32()</TT
+>
+are identical to
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_putuint8()</TT
+>
+except that they respectively read an unsigned 16-bit or 32-bit integer
+in network byte order from
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>.
+Similarly,
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_putuint16()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_putuint32()</TT
+>
+writes the unsigned 16-bit or 32-bit integer
+<TT
+CLASS="PARAMETER"
+><I
+>val</I
+></TT
+>
+to buffer
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>,
+in network byte order.</P
+><P
+>Arbitrary amounts of data are read or written from a lightweight
+resolver buffer with
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_getmem()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_putmem()</TT
+>
+respectively.
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_putmem()</TT
+>
+copies
+<TT
+CLASS="PARAMETER"
+><I
+>length</I
+></TT
+>
+bytes of memory at
+<TT
+CLASS="PARAMETER"
+><I
+>base</I
+></TT
+>
+to
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>.
+Conversely,
+<TT
+CLASS="FUNCTION"
+>lwres_buffer_getmem()</TT
+>
+copies
+<TT
+CLASS="PARAMETER"
+><I
+>length</I
+></TT
+>
+bytes of memory from
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>
+to
+<TT
+CLASS="PARAMETER"
+><I
+>base</I
+></TT
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_config.3 b/lib/liblwres/man/lwres_config.3
new file mode 100644
index 000000000..9a93cc0e7
--- /dev/null
+++ b/lib/liblwres/man/lwres_config.3
@@ -0,0 +1,105 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_CONFIG" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_conf_init, lwres_conf_clear, lwres_conf_parse, lwres_conf_print, lwres_conf_get \- lightweight resolver configuration
+.SH SYNOPSIS
+\fB#include <lwres/lwres.h>
+.sp
+.na
+void
+lwres_conf_init(lwres_context_t *ctx);
+.ad
+.sp
+.na
+void
+lwres_conf_clear(lwres_context_t *ctx);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_conf_parse(lwres_context_t *ctx, const char *filename);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_conf_print(lwres_context_t *ctx, FILE *fp);
+.ad
+.sp
+.na
+lwres_conf_t *
+lwres_conf_get(lwres_context_t *ctx);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+\fBlwres_conf_init()\fR
+creates an empty
+\fBlwres_conf_t\fR
+structure for lightweight resolver context
+\fIctx\fR.
+.PP
+\fBlwres_conf_clear()\fR
+frees up all the internal memory used by
+that
+\fBlwres_conf_t\fR
+structure in resolver context
+\fIctx\fR.
+.PP
+\fBlwres_conf_parse()\fR
+opens the file
+\fIfilename\fR
+and parses it to initialise the resolver context
+\fIctx\fR's
+\fBlwres_conf_t\fR
+structure.
+.PP
+\fBlwres_conf_print()\fR
+prints the
+\fBlwres_conf_t\fR
+structure for resolver context
+\fIctx\fR
+to the
+\fBFILE\fR
+\fIfp\fR.
+.SH "RETURN VALUES"
+.PP
+\fBlwres_conf_parse()\fR
+returns
+LWRES_R_SUCCESS
+if it successfully read and parsed
+\fIfilename\fR.
+It returns
+LWRES_R_FAILURE
+if
+\fIfilename\fR
+could not be opened or contained incorrect
+resolver statements.
+.PP
+\fBlwres_conf_print()\fR
+returns
+LWRES_R_SUCCESS
+unless an error occurred when converting the network addresses to a
+numeric host address string.
+If this happens, the function returns
+LWRES_R_FAILURE.
+.SH "SEE ALSO"
+.PP
+\fBstdio\fR(3),
+\fBresolver\fR(5).
+.SH "FILES"
+.PP
+\fI/etc/resolv.conf\fR
diff --git a/lib/liblwres/man/lwres_config.docbook b/lib/liblwres/man/lwres_config.docbook
new file mode 100644
index 000000000..03ec6c211
--- /dev/null
+++ b/lib/liblwres/man/lwres_config.docbook
@@ -0,0 +1,159 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_config.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+<refentryinfo>
+
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_config</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_conf_init</refname>
+<refname>lwres_conf_clear</refname>
+<refname>lwres_conf_parse</refname>
+<refname>lwres_conf_print</refname>
+<refname>lwres_conf_get</refname>
+<refpurpose>lightweight resolver configuration</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_conf_init</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_conf_clear</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_conf_parse</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>const char *filename</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_conf_print</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>FILE *fp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_conf_t *
+<function>lwres_conf_get</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+<function>lwres_conf_init()</function>
+creates an empty
+<type>lwres_conf_t</type>
+structure for lightweight resolver context
+<parameter>ctx</parameter>.
+</para>
+<para>
+<function>lwres_conf_clear()</function>
+frees up all the internal memory used by
+that
+<type>lwres_conf_t</type>
+structure in resolver context
+<parameter>ctx</parameter>.
+</para>
+<para>
+<function>lwres_conf_parse()</function>
+opens the file
+<parameter>filename</parameter>
+and parses it to initialise the resolver context
+<parameter>ctx</parameter>'s
+<type>lwres_conf_t</type>
+structure.
+</para>
+<para>
+<function>lwres_conf_print()</function>
+prints the
+<type>lwres_conf_t</type>
+structure for resolver context
+<parameter>ctx</parameter>
+to the
+<type>FILE</type>
+<parameter>fp</parameter>.
+</para>
+</refsect1>
+<refsect1>
+
+<title>RETURN VALUES</title>
+<para>
+<function>lwres_conf_parse()</function>
+returns
+<errorcode>LWRES_R_SUCCESS</errorcode>
+if it successfully read and parsed
+<parameter>filename</parameter>.
+It returns
+<errorcode>LWRES_R_FAILURE</errorcode>
+if
+<parameter>filename</parameter>
+could not be opened or contained incorrect
+resolver statements.
+</para>
+<para>
+<function>lwres_conf_print()</function>
+returns
+<errorcode>LWRES_R_SUCCESS</errorcode>
+unless an error occurred when converting the network addresses to a
+numeric host address string.
+If this happens, the function returns
+<errorcode>LWRES_R_FAILURE</errorcode>.
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>stdio</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+<citerefentry>
+<refentrytitle>resolver</refentrytitle><manvolnum>5</manvolnum>
+</citerefentry>.
+</refsect1>
+<refsect1>
+<title>FILES</title>
+<para>
+<filename>/etc/resolv.conf</filename>
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_config.html b/lib/liblwres/man/lwres_config.html
new file mode 100644
index 000000000..67fbcdd88
--- /dev/null
+++ b/lib/liblwres/man/lwres_config.html
@@ -0,0 +1,295 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_config</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_config</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_conf_init, lwres_conf_clear, lwres_conf_parse, lwres_conf_print, lwres_conf_get&nbsp;--&nbsp;lightweight resolver configuration</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN15"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN16"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/lwres.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_conf_init</CODE
+>(lwres_context_t *ctx);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_conf_clear</CODE
+>(lwres_context_t *ctx);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_conf_parse</CODE
+>(lwres_context_t *ctx, const char *filename);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_conf_print</CODE
+>(lwres_context_t *ctx, FILE *fp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_conf_t *
+lwres_conf_get</CODE
+>(lwres_context_t *ctx);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN40"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_conf_init()</TT
+>
+creates an empty
+<SPAN
+CLASS="TYPE"
+>lwres_conf_t</SPAN
+>
+structure for lightweight resolver context
+<TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+>.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_conf_clear()</TT
+>
+frees up all the internal memory used by
+that
+<SPAN
+CLASS="TYPE"
+>lwres_conf_t</SPAN
+>
+structure in resolver context
+<TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+>.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_conf_parse()</TT
+>
+opens the file
+<TT
+CLASS="PARAMETER"
+><I
+>filename</I
+></TT
+>
+and parses it to initialise the resolver context
+<TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+>'s
+<SPAN
+CLASS="TYPE"
+>lwres_conf_t</SPAN
+>
+structure.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_conf_print()</TT
+>
+prints the
+<SPAN
+CLASS="TYPE"
+>lwres_conf_t</SPAN
+>
+structure for resolver context
+<TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+>
+to the
+<SPAN
+CLASS="TYPE"
+>FILE</SPAN
+>
+<TT
+CLASS="PARAMETER"
+><I
+>fp</I
+></TT
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN61"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_conf_parse()</TT
+>
+returns
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>
+if it successfully read and parsed
+<TT
+CLASS="PARAMETER"
+><I
+>filename</I
+></TT
+>.
+It returns
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_FAILURE</SPAN
+>
+if
+<TT
+CLASS="PARAMETER"
+><I
+>filename</I
+></TT
+>
+could not be opened or contained incorrect
+resolver statements.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_conf_print()</TT
+>
+returns
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>
+unless an error occurred when converting the network addresses to a
+numeric host address string.
+If this happens, the function returns
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_FAILURE</SPAN
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN73"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>stdio</SPAN
+>(3)</SPAN
+>,
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>resolver</SPAN
+>(5)</SPAN
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN82"
+></A
+><H2
+>FILES</H2
+><P
+><TT
+CLASS="FILENAME"
+>/etc/resolv.conf</TT
+></P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_context.3 b/lib/liblwres/man/lwres_context.3
new file mode 100644
index 000000000..d55c14fef
--- /dev/null
+++ b/lib/liblwres/man/lwres_context.3
@@ -0,0 +1,194 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_CONTEXT" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_context_create, lwres_context_destroy, lwres_context_nextserial, lwres_context_initserial, lwres_context_freemem, lwres_context_allocmem, lwres_context_sendrecv \- lightweight resolver context management
+.SH SYNOPSIS
+\fB#include <lwres/lwres.h>
+.sp
+.na
+lwres_result_t
+lwres_context_create(lwres_context_t **contextp, void *arg, lwres_malloc_t malloc_function, lwres_free_t free_function);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_context_destroy(lwres_context_t **contextp);
+.ad
+.sp
+.na
+void
+lwres_context_initserial(lwres_context_t *ctx, lwres_uint32_t serial);
+.ad
+.sp
+.na
+lwres_uint32_t
+lwres_context_nextserial(lwres_context_t *ctx);
+.ad
+.sp
+.na
+void
+lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len);
+.ad
+.sp
+.na
+void
+lwres_context_allocmem(lwres_context_t *ctx, size_t len);
+.ad
+.sp
+.na
+void *
+lwres_context_sendrecv(lwres_context_t *ctx, void *sendbase, int sendlen, void *recvbase, int recvlen, int *recvd_len);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+\fBlwres_context_create()\fR
+creates a
+\fBlwres_context_t\fR
+structure for use in lightweight resolver operations.
+It holds a socket and other data needed for communicating
+with a resolver daemon.
+The new
+\fBlwres_context_t\fR
+is returned throught
+\fIcontextp\fR,
+a pointer to a
+\fBlwres_context_t\fR
+pointer. This
+\fBlwres_context_t\fR
+pointer must initially be NULL, and is modified
+to point to the newly created
+\fBlwres_context_t\fR.
+.PP
+When the lightweight resolver needs to perform dynamic memory
+allocation, it will call
+\fImalloc_function\fR
+to allocate memory and
+\fIfree_function\fR
+to free it. If
+\fImalloc_function\fR
+and
+\fIfree_function\fR
+are NULL, memory is allocated using
+\&.Xr malloc 3
+and
+\fBfree\fR(3).
+It is not permitted to have a NULL
+\fImalloc_function\fR
+and a non-NULL
+\fIfree_function\fR
+or vice versa.
+\fIarg\fR
+is passed as the first parameter to the memory
+allocation functions.
+If
+\fImalloc_function\fR
+and
+\fIfree_function\fR
+are NULL,
+\fIarg\fR
+is unused and should be passed as NULL.
+.PP
+Once memory for the structure has been allocated,
+it is initialized using
+\fBlwres_conf_init\fR(3)
+and returned via
+\fI*contextp\fR.
+.PP
+\fBlwres_context_destroy()\fR
+destroys a
+\fBlwres_context_t\fR,
+closing its socket.
+\fIcontextp\fR
+is a pointer to a pointer to the context that is to be destroyed.
+The pointer will be set to NULL when the context has been destroyed.
+.PP
+The context holds a serial number that is used to identify resolver
+request packets and associate responses with the corresponding requests.
+This serial number is controlled using
+\fBlwres_context_initserial()\fR
+and
+\fBlwres_context_nextserial()\fR.
+\fBlwres_context_initserial()\fR
+sets the serial number for context
+\fI*ctx\fR
+to
+\fIserial\fR.
+\fBlwres_context_nextserial()\fR
+increments the serial number and returns the previous value.
+.PP
+Memory for a lightweight resolver context is allocated and freed using
+\fBlwres_context_allocmem()\fR
+and
+\fBlwres_context_freemem()\fR.
+These use whatever allocations were defined when the context was
+created with
+\fBlwres_context_create()\fR.
+\fBlwres_context_allocmem()\fR
+allocates
+\fIlen\fR
+bytes of memory and if successful returns a pointer to the allocated
+storage.
+\fBlwres_context_freemem()\fR
+frees
+\fIlen\fR
+bytes of space starting at location
+\fImem\fR.
+.PP
+\fBlwres_context_sendrecv()\fR
+performs I/O for the context
+\fIctx\fR.
+Data are read and written from the context's socket.
+It writes data from
+\fIsendbase\fR
+\(em typically a lightweight resolver query packet \(em
+and waits for a reply which is copied to the receive buffer at
+\fIrecvbase\fR.
+The number of bytes that were written to this receive buffer is
+returned in
+\fI*recvd_len\fR.
+.SH "RETURN VALUES"
+.PP
+\fBlwres_context_create()\fR
+returns
+LWRES_R_NOMEMORY
+if memory for the
+\fBstruct lwres_context\fR
+could not be allocated,
+LWRES_R_SUCCESS
+otherwise.
+.PP
+Successful calls to the memory allocator
+\fBlwres_context_allocmem()\fR
+return a pointer to the start of the allocated space.
+It returns NULL if memory could not be allocated.
+.PP
+LWRES_R_SUCCESS
+is returned when
+\fBlwres_context_sendrecv()\fR
+completes successfully.
+LWRES_R_IOERROR
+is returned if an I/O error occurs and
+LWRES_R_TIMEOUT
+is returned if
+\fBlwres_context_sendrecv()\fR
+times out waiting for a response.
+.SH "SEE ALSO"
+.PP
+\fBlwres_conf_init\fR(3),
+\fBmalloc\fR(3),
+\fBfree\fR(3).
diff --git a/lib/liblwres/man/lwres_context.docbook b/lib/liblwres/man/lwres_context.docbook
new file mode 100644
index 000000000..9cdfa7525
--- /dev/null
+++ b/lib/liblwres/man/lwres_context.docbook
@@ -0,0 +1,283 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_context.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+<refentryinfo>
+
+
+<date>Jun 30, 2000</date>
+</refentryinfo>
+<refmeta>
+<refentrytitle>lwres_context</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+<refnamediv>
+<refname>lwres_context_create</refname>
+<refname>lwres_context_destroy</refname>
+<refname>lwres_context_nextserial</refname>
+<refname>lwres_context_initserial</refname>
+<refname>lwres_context_freemem</refname>
+<refname>lwres_context_allocmem</refname>
+<refname>lwres_context_sendrecv</refname>
+<refpurpose>lightweight resolver context management</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_context_create</function></funcdef>
+<paramdef>lwres_context_t **contextp</paramdef>
+<paramdef>void *arg</paramdef>
+<paramdef>lwres_malloc_t malloc_function</paramdef>
+<paramdef>lwres_free_t free_function</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_context_destroy</function></funcdef>
+<paramdef>lwres_context_t **contextp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_context_initserial</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_uint32_t serial</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_uint32_t
+<function>lwres_context_nextserial</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_context_freemem</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>void *mem</paramdef>
+<paramdef>size_t len</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_context_allocmem</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>size_t len</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void *
+<function>lwres_context_sendrecv</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>void *sendbase</paramdef>
+<paramdef>int sendlen</paramdef>
+<paramdef>void *recvbase</paramdef>
+<paramdef>int recvlen</paramdef>
+<paramdef>int *recvd_len</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+<function>lwres_context_create()</function>
+creates a
+<type>lwres_context_t</type>
+structure for use in lightweight resolver operations.
+It holds a socket and other data needed for communicating
+with a resolver daemon.
+The new
+<type>lwres_context_t</type>
+is returned throught
+<parameter>contextp</parameter>,
+
+a pointer to a
+<type>lwres_context_t</type>
+pointer. This
+<type>lwres_context_t</type>
+pointer must initially be NULL, and is modified
+to point to the newly created
+<type>lwres_context_t</type>.
+
+</para>
+<para>
+When the lightweight resolver needs to perform dynamic memory
+allocation, it will call
+<parameter>malloc_function</parameter>
+to allocate memory and
+<parameter>free_function</parameter>
+
+to free it. If
+<parameter>malloc_function</parameter>
+and
+<parameter>free_function</parameter>
+
+are NULL, memory is allocated using
+.Xr malloc 3
+and
+<citerefentry>
+<refentrytitle>free</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>.
+
+It is not permitted to have a NULL
+<parameter>malloc_function</parameter>
+and a non-NULL
+<parameter>free_function</parameter>
+or vice versa.
+<parameter>arg</parameter>
+is passed as the first parameter to the memory
+allocation functions.
+If
+<parameter>malloc_function</parameter>
+and
+<parameter>free_function</parameter>
+are NULL,
+<parameter>arg</parameter>
+
+is unused and should be passed as NULL.
+</para>
+<para>
+Once memory for the structure has been allocated,
+it is initialized using
+<citerefentry>
+<refentrytitle>lwres_conf_init</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>
+
+and returned via
+<parameter>*contextp</parameter>.
+
+</para>
+<para>
+<function>lwres_context_destroy()</function>
+destroys a
+<type>lwres_context_t</type>,
+
+closing its socket.
+<parameter>contextp</parameter>
+is a pointer to a pointer to the context that is to be destroyed.
+The pointer will be set to NULL when the context has been destroyed.
+</para>
+<para>
+The context holds a serial number that is used to identify resolver
+request packets and associate responses with the corresponding requests.
+This serial number is controlled using
+<function>lwres_context_initserial()</function>
+and
+<function>lwres_context_nextserial()</function>.
+<function>lwres_context_initserial()</function>
+sets the serial number for context
+<parameter>*ctx</parameter>
+to
+<parameter>serial</parameter>.
+
+<function>lwres_context_nextserial()</function>
+increments the serial number and returns the previous value.
+</para>
+<para>
+Memory for a lightweight resolver context is allocated and freed using
+<function>lwres_context_allocmem()</function>
+and
+<function>lwres_context_freemem()</function>.
+These use whatever allocations were defined when the context was
+created with
+<function>lwres_context_create()</function>.
+<function>lwres_context_allocmem()</function>
+allocates
+<parameter>len</parameter>
+bytes of memory and if successful returns a pointer to the allocated
+storage.
+<function>lwres_context_freemem()</function>
+frees
+<parameter>len</parameter>
+bytes of space starting at location
+<parameter>mem</parameter>.
+
+</para>
+<para>
+<function>lwres_context_sendrecv()</function>
+performs I/O for the context
+<parameter>ctx</parameter>.
+
+Data are read and written from the context's socket.
+It writes data from
+<parameter>sendbase</parameter>
+&mdash; typically a lightweight resolver query packet &mdash;
+and waits for a reply which is copied to the receive buffer at
+<parameter>recvbase</parameter>.
+
+The number of bytes that were written to this receive buffer is
+returned in
+<parameter>*recvd_len</parameter>.
+
+</para>
+</refsect1>
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+<function>lwres_context_create()</function>
+returns
+<errorcode>LWRES_R_NOMEMORY</errorcode>
+if memory for the
+<type>struct lwres_context</type>
+could not be allocated,
+<errorcode>LWRES_R_SUCCESS</errorcode>
+otherwise.
+</para>
+<para>
+Successful calls to the memory allocator
+<function>lwres_context_allocmem()</function>
+return a pointer to the start of the allocated space.
+It returns NULL if memory could not be allocated.
+</para>
+<para>
+<errorcode>LWRES_R_SUCCESS</errorcode>
+is returned when
+<function>lwres_context_sendrecv()</function>
+completes successfully.
+<errorcode>LWRES_R_IOERROR</errorcode>
+is returned if an I/O error occurs and
+<errorcode>LWRES_R_TIMEOUT</errorcode>
+is returned if
+<function>lwres_context_sendrecv()</function>
+times out waiting for a response.
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>lwres_conf_init</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>malloc</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>free</refentrytitle><manvolnum>3
+</manvolnum>
+</citerefentry>.
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_context.html b/lib/liblwres/man/lwres_context.html
new file mode 100644
index 000000000..377125c43
--- /dev/null
+++ b/lib/liblwres/man/lwres_context.html
@@ -0,0 +1,519 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_context</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_context</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_context_create, lwres_context_destroy, lwres_context_nextserial, lwres_context_initserial, lwres_context_freemem, lwres_context_allocmem, lwres_context_sendrecv&nbsp;--&nbsp;lightweight resolver context management</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN17"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN18"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/lwres.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_context_create</CODE
+>(lwres_context_t **contextp, void *arg, lwres_malloc_t malloc_function, lwres_free_t free_function);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_context_destroy</CODE
+>(lwres_context_t **contextp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_context_initserial</CODE
+>(lwres_context_t *ctx, lwres_uint32_t serial);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_uint32_t
+lwres_context_nextserial</CODE
+>(lwres_context_t *ctx);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_context_freemem</CODE
+>(lwres_context_t *ctx, void *mem, size_t len);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_context_allocmem</CODE
+>(lwres_context_t *ctx, size_t len);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void *
+lwres_context_sendrecv</CODE
+>(lwres_context_t *ctx, void *sendbase, int sendlen, void *recvbase, int recvlen, int *recvd_len);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN60"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_context_create()</TT
+>
+creates a
+<SPAN
+CLASS="TYPE"
+>lwres_context_t</SPAN
+>
+structure for use in lightweight resolver operations.
+It holds a socket and other data needed for communicating
+with a resolver daemon.
+The new
+<SPAN
+CLASS="TYPE"
+>lwres_context_t</SPAN
+>
+is returned throught
+<TT
+CLASS="PARAMETER"
+><I
+>contextp</I
+></TT
+>,
+
+a pointer to a
+<SPAN
+CLASS="TYPE"
+>lwres_context_t</SPAN
+>
+pointer. This
+<SPAN
+CLASS="TYPE"
+>lwres_context_t</SPAN
+>
+pointer must initially be NULL, and is modified
+to point to the newly created
+<SPAN
+CLASS="TYPE"
+>lwres_context_t</SPAN
+>.&#13;</P
+><P
+>When the lightweight resolver needs to perform dynamic memory
+allocation, it will call
+<TT
+CLASS="PARAMETER"
+><I
+>malloc_function</I
+></TT
+>
+to allocate memory and
+<TT
+CLASS="PARAMETER"
+><I
+>free_function</I
+></TT
+>
+
+to free it. If
+<TT
+CLASS="PARAMETER"
+><I
+>malloc_function</I
+></TT
+>
+and
+<TT
+CLASS="PARAMETER"
+><I
+>free_function</I
+></TT
+>
+
+are NULL, memory is allocated using
+.Xr malloc 3
+and
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>free</SPAN
+>(3)</SPAN
+>.
+
+It is not permitted to have a NULL
+<TT
+CLASS="PARAMETER"
+><I
+>malloc_function</I
+></TT
+>
+and a non-NULL
+<TT
+CLASS="PARAMETER"
+><I
+>free_function</I
+></TT
+>
+or vice versa.
+<TT
+CLASS="PARAMETER"
+><I
+>arg</I
+></TT
+>
+is passed as the first parameter to the memory
+allocation functions.
+If
+<TT
+CLASS="PARAMETER"
+><I
+>malloc_function</I
+></TT
+>
+and
+<TT
+CLASS="PARAMETER"
+><I
+>free_function</I
+></TT
+>
+are NULL,
+<TT
+CLASS="PARAMETER"
+><I
+>arg</I
+></TT
+>
+
+is unused and should be passed as NULL.</P
+><P
+>Once memory for the structure has been allocated,
+it is initialized using
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_conf_init</SPAN
+>(3)</SPAN
+>
+
+and returned via
+<TT
+CLASS="PARAMETER"
+><I
+>*contextp</I
+></TT
+>.&#13;</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_context_destroy()</TT
+>
+destroys a
+<SPAN
+CLASS="TYPE"
+>lwres_context_t</SPAN
+>,
+
+closing its socket.
+<TT
+CLASS="PARAMETER"
+><I
+>contextp</I
+></TT
+>
+is a pointer to a pointer to the context that is to be destroyed.
+The pointer will be set to NULL when the context has been destroyed.</P
+><P
+>The context holds a serial number that is used to identify resolver
+request packets and associate responses with the corresponding requests.
+This serial number is controlled using
+<TT
+CLASS="FUNCTION"
+>lwres_context_initserial()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_context_nextserial()</TT
+>.
+<TT
+CLASS="FUNCTION"
+>lwres_context_initserial()</TT
+>
+sets the serial number for context
+<TT
+CLASS="PARAMETER"
+><I
+>*ctx</I
+></TT
+>
+to
+<TT
+CLASS="PARAMETER"
+><I
+>serial</I
+></TT
+>.
+
+<TT
+CLASS="FUNCTION"
+>lwres_context_nextserial()</TT
+>
+increments the serial number and returns the previous value.</P
+><P
+>Memory for a lightweight resolver context is allocated and freed using
+<TT
+CLASS="FUNCTION"
+>lwres_context_allocmem()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_context_freemem()</TT
+>.
+These use whatever allocations were defined when the context was
+created with
+<TT
+CLASS="FUNCTION"
+>lwres_context_create()</TT
+>.
+<TT
+CLASS="FUNCTION"
+>lwres_context_allocmem()</TT
+>
+allocates
+<TT
+CLASS="PARAMETER"
+><I
+>len</I
+></TT
+>
+bytes of memory and if successful returns a pointer to the allocated
+storage.
+<TT
+CLASS="FUNCTION"
+>lwres_context_freemem()</TT
+>
+frees
+<TT
+CLASS="PARAMETER"
+><I
+>len</I
+></TT
+>
+bytes of space starting at location
+<TT
+CLASS="PARAMETER"
+><I
+>mem</I
+></TT
+>.&#13;</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_context_sendrecv()</TT
+>
+performs I/O for the context
+<TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+>.
+
+Data are read and written from the context's socket.
+It writes data from
+<TT
+CLASS="PARAMETER"
+><I
+>sendbase</I
+></TT
+>
+&mdash; typically a lightweight resolver query packet &mdash;
+and waits for a reply which is copied to the receive buffer at
+<TT
+CLASS="PARAMETER"
+><I
+>recvbase</I
+></TT
+>.
+
+The number of bytes that were written to this receive buffer is
+returned in
+<TT
+CLASS="PARAMETER"
+><I
+>*recvd_len</I
+></TT
+>.&#13;</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN115"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_context_create()</TT
+>
+returns
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_NOMEMORY</SPAN
+>
+if memory for the
+<SPAN
+CLASS="TYPE"
+>struct lwres_context</SPAN
+>
+could not be allocated,
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>
+otherwise.</P
+><P
+>Successful calls to the memory allocator
+<TT
+CLASS="FUNCTION"
+>lwres_context_allocmem()</TT
+>
+return a pointer to the start of the allocated space.
+It returns NULL if memory could not be allocated.</P
+><P
+><SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>
+is returned when
+<TT
+CLASS="FUNCTION"
+>lwres_context_sendrecv()</TT
+>
+completes successfully.
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_IOERROR</SPAN
+>
+is returned if an I/O error occurs and
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_TIMEOUT</SPAN
+>
+is returned if
+<TT
+CLASS="FUNCTION"
+>lwres_context_sendrecv()</TT
+>
+times out waiting for a response.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN130"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_conf_init</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>malloc</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>free</SPAN
+>(3)</SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_gabn.3 b/lib/liblwres/man/lwres_gabn.3
new file mode 100644
index 000000000..79a22c14f
--- /dev/null
+++ b/lib/liblwres/man/lwres_gabn.3
@@ -0,0 +1,193 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_GABN" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_gabnrequest_render, lwres_gabnresponse_render, lwres_gabnrequest_parse, lwres_gabnresponse_parse, lwres_gabnresponse_free, lwres_gabnrequest_free \- lightweight resolver getaddrbyname message handling
+.SH SYNOPSIS
+\fB#include <lwres/lwres.h>
+.sp
+.na
+lwres_result_t
+lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp);
+.ad
+.sp
+.na
+void
+lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp);
+.ad
+.sp
+.na
+void
+lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+These are low-level routines for creating and parsing
+lightweight resolver name-to-address lookup request and
+response messages.
+.PP
+There are four main functions for the getaddrbyname opcode.
+One render function converts a getaddrbyname request structure \(em
+\fBlwres_gabnrequest_t\fR \(em
+to the lighweight resolver's canonical format.
+It is complemented by a parse function that converts a packet in this
+canonical format to a getaddrbyname request structure.
+Another render function converts the getaddrbyname response structure \(em
+\fBlwres_gabnresponse_t\fR \(em
+to the canonical format.
+This is complemented by a parse function which converts a packet in
+canonical format to a getaddrbyname response structure.
+.PP
+These structures are defined in
+\fI<lwres/lwres.h>\fR.
+They are shown below.
+.sp
+.nf
+#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
+
+typedef struct lwres_addr lwres_addr_t;
+typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint32_t addrtypes;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_gabnrequest_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+.sp
+.fi
+.PP
+\fBlwres_gabnrequest_render()\fR
+uses resolver context
+\fIctx\fR
+to convert getaddrbyname request structure
+\fIreq\fR
+to canonical format.
+The packet header structure
+\fIpkt\fR
+is initialised and transferred to
+buffer
+\fIb\fR.
+The contents of
+\fI*req\fR
+are then appended to the buffer in canonical format.
+\fBlwres_gabnresponse_render()\fR
+performs the same task, except it converts a getaddrbyname response structure
+\fBlwres_gabnresponse_t\fR
+to the lightweight resolver's canonical format.
+.PP
+\fBlwres_gabnrequest_parse()\fR
+uses context
+\fIctx\fR
+to convert the contents of packet
+\fIpkt\fR
+to a
+\fBlwres_gabnrequest_t\fR
+structure.
+Buffer
+\fIb\fR
+provides space to be used for storing this structure.
+When the function succeeds, the resulting
+\fBlwres_gabnrequest_t\fR
+is made available through
+\fI*structp\fR.
+\fBlwres_gabnresponse_parse()\fR
+offers the same semantics as
+\fBlwres_gabnrequest_parse()\fR
+except it yields a
+\fBlwres_gabnresponse_t\fR
+structure.
+.PP
+\fBlwres_gabnresponse_free()\fR
+and
+\fBlwres_gabnrequest_free()\fR
+release the memory in resolver context
+\fIctx\fR
+that was allocated to the
+\fBlwres_gabnresponse_t\fR
+or
+\fBlwres_gabnrequest_t\fR
+structures referenced via
+\fIstructp\fR.
+Any memory associated with ancillary buffers and strings for those
+structures is also discarded.
+.SH "RETURN VALUES"
+.PP
+The getaddrbyname opcode functions
+\fBlwres_gabnrequest_render()\fR,
+\fBlwres_gabnresponse_render()\fR
+\fBlwres_gabnrequest_parse()\fR
+and
+\fBlwres_gabnresponse_parse()\fR
+all return
+LWRES_R_SUCCESS
+on success.
+They return
+LWRES_R_NOMEMORY
+if memory allocation fails.
+LWRES_R_UNEXPECTEDEND
+is returned if the available space in the buffer
+\fIb\fR
+is too small to accommodate the packet header or the
+\fBlwres_gabnrequest_t\fR
+and
+\fBlwres_gabnresponse_t\fR
+structures.
+\fBlwres_gabnrequest_parse()\fR
+and
+\fBlwres_gabnresponse_parse()\fR
+will return
+LWRES_R_UNEXPECTEDEND
+if the buffer is not empty after decoding the received packet.
+These functions will return
+LWRES_R_FAILURE
+if
+\fBpktflags\fR
+in the packet header structure
+\fBlwres_lwpacket_t\fR
+indicate that the packet is not a response to an earlier query.
+.SH "SEE ALSO"
+.PP
+\fBlwres_packet\fR(3)
diff --git a/lib/liblwres/man/lwres_gabn.docbook b/lib/liblwres/man/lwres_gabn.docbook
new file mode 100644
index 000000000..91f549564
--- /dev/null
+++ b/lib/liblwres/man/lwres_gabn.docbook
@@ -0,0 +1,255 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_gabn.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+<refentryinfo>
+
+
+<date>Jun 30, 2000</date>
+</refentryinfo>
+<refmeta>
+<refentrytitle>lwres_gabn</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+<refnamediv>
+<refname>lwres_gabnrequest_render</refname>
+<refname>lwres_gabnresponse_render</refname>
+<refname>lwres_gabnrequest_parse</refname>
+<refname>lwres_gabnresponse_parse</refname>
+<refname>lwres_gabnresponse_free</refname>
+<refname>lwres_gabnrequest_free</refname>
+<refpurpose>lightweight resolver getaddrbyname message handling</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_gabnrequest_render</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_gabnrequest_t *req</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_gabnresponse_render</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_gabnresponse_t *req</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_gabnrequest_parse</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_gabnrequest_t **structp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_gabnresponse_parse</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_gabnresponse_t **structp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_gabnresponse_free</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_gabnresponse_t **structp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_gabnrequest_free</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_gabnrequest_t **structp</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+These are low-level routines for creating and parsing
+lightweight resolver name-to-address lookup request and
+response messages.
+</para><para>
+There are four main functions for the getaddrbyname opcode.
+One render function converts a getaddrbyname request structure &mdash;
+<type>lwres_gabnrequest_t</type> &mdash;
+to the lighweight resolver's canonical format.
+It is complemented by a parse function that converts a packet in this
+canonical format to a getaddrbyname request structure.
+Another render function converts the getaddrbyname response structure &mdash;
+<type>lwres_gabnresponse_t</type> &mdash;
+to the canonical format.
+This is complemented by a parse function which converts a packet in
+canonical format to a getaddrbyname response structure.
+</para>
+<para>
+These structures are defined in
+<filename>&lt;lwres/lwres.h&gt;</filename>.
+They are shown below.
+<programlisting>
+#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
+
+typedef struct lwres_addr lwres_addr_t;
+typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint32_t addrtypes;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_gabnrequest_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+</programlisting>
+</para>
+<para>
+<function>lwres_gabnrequest_render()</function>
+uses resolver context
+<parameter>ctx</parameter>
+to convert getaddrbyname request structure
+<parameter>req</parameter>
+to canonical format.
+The packet header structure
+<parameter>pkt</parameter>
+is initialised and transferred to
+buffer
+<parameter>b</parameter>.
+
+The contents of
+<parameter>*req</parameter>
+are then appended to the buffer in canonical format.
+<function>lwres_gabnresponse_render()</function>
+performs the same task, except it converts a getaddrbyname response structure
+<type>lwres_gabnresponse_t</type>
+to the lightweight resolver's canonical format.
+</para>
+<para>
+<function>lwres_gabnrequest_parse()</function>
+uses context
+<parameter>ctx</parameter>
+to convert the contents of packet
+<parameter>pkt</parameter>
+to a
+<type>lwres_gabnrequest_t</type>
+structure.
+Buffer
+<parameter>b</parameter>
+provides space to be used for storing this structure.
+When the function succeeds, the resulting
+<type>lwres_gabnrequest_t</type>
+is made available through
+<parameter>*structp</parameter>.
+
+<function>lwres_gabnresponse_parse()</function>
+offers the same semantics as
+<function>lwres_gabnrequest_parse()</function>
+except it yields a
+<type>lwres_gabnresponse_t</type>
+structure.
+</para>
+<para>
+<function>lwres_gabnresponse_free()</function>
+and
+<function>lwres_gabnrequest_free()</function>
+release the memory in resolver context
+<parameter>ctx</parameter>
+that was allocated to the
+<type>lwres_gabnresponse_t</type>
+or
+<type>lwres_gabnrequest_t</type>
+structures referenced via
+<parameter>structp</parameter>.
+
+Any memory associated with ancillary buffers and strings for those
+structures is also discarded.
+</para>
+</refsect1>
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+The getaddrbyname opcode functions
+<function>lwres_gabnrequest_render()</function>,
+<function>lwres_gabnresponse_render()</function>
+<function>lwres_gabnrequest_parse()</function>
+and
+<function>lwres_gabnresponse_parse()</function>
+all return
+<errorcode>LWRES_R_SUCCESS</errorcode>
+on success.
+They return
+<errorcode>LWRES_R_NOMEMORY</errorcode>
+if memory allocation fails.
+<errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+is returned if the available space in the buffer
+<parameter>b</parameter>
+is too small to accommodate the packet header or the
+<type>lwres_gabnrequest_t</type>
+and
+<type>lwres_gabnresponse_t</type>
+structures.
+<function>lwres_gabnrequest_parse()</function>
+and
+<function>lwres_gabnresponse_parse()</function>
+will return
+<errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+if the buffer is not empty after decoding the received packet.
+These functions will return
+<errorcode>LWRES_R_FAILURE</errorcode>
+if
+<structfield>pktflags</structfield>
+in the packet header structure
+<type>lwres_lwpacket_t</type>
+indicate that the packet is not a response to an earlier query.
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>lwres_packet</refentrytitle><manvolnum>3
+</manvolnum>
+</citerefentry>
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_gabn.html b/lib/liblwres/man/lwres_gabn.html
new file mode 100644
index 000000000..5611cac6c
--- /dev/null
+++ b/lib/liblwres/man/lwres_gabn.html
@@ -0,0 +1,442 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_gabn</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_gabn</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_gabnrequest_render, lwres_gabnresponse_render, lwres_gabnrequest_parse, lwres_gabnresponse_parse, lwres_gabnresponse_free, lwres_gabnrequest_free&nbsp;--&nbsp;lightweight resolver getaddrbyname message handling</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN16"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN17"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/lwres.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_gabnrequest_render</CODE
+>(lwres_context_t *ctx, lwres_gabnrequest_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_gabnresponse_render</CODE
+>(lwres_context_t *ctx, lwres_gabnresponse_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_gabnrequest_parse</CODE
+>(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_gabnresponse_parse</CODE
+>(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_gabnresponse_free</CODE
+>(lwres_context_t *ctx, lwres_gabnresponse_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_gabnrequest_free</CODE
+>(lwres_context_t *ctx, lwres_gabnrequest_t **structp);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN57"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>These are low-level routines for creating and parsing
+lightweight resolver name-to-address lookup request and
+response messages.</P
+><P
+>There are four main functions for the getaddrbyname opcode.
+One render function converts a getaddrbyname request structure &mdash;
+<SPAN
+CLASS="TYPE"
+>lwres_gabnrequest_t</SPAN
+> &mdash;
+to the lighweight resolver's canonical format.
+It is complemented by a parse function that converts a packet in this
+canonical format to a getaddrbyname request structure.
+Another render function converts the getaddrbyname response structure &mdash;
+<SPAN
+CLASS="TYPE"
+>lwres_gabnresponse_t</SPAN
+> &mdash;
+to the canonical format.
+This is complemented by a parse function which converts a packet in
+canonical format to a getaddrbyname response structure.</P
+><P
+>These structures are defined in
+<TT
+CLASS="FILENAME"
+>&lt;lwres/lwres.h&gt;</TT
+>.
+They are shown below.
+<PRE
+CLASS="PROGRAMLISTING"
+>#define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
+
+typedef struct lwres_addr lwres_addr_t;
+typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint32_t addrtypes;
+ lwres_uint16_t namelen;
+ char *name;
+} lwres_gabnrequest_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;</PRE
+></P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gabnrequest_render()</TT
+>
+uses resolver context
+<TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+>
+to convert getaddrbyname request structure
+<TT
+CLASS="PARAMETER"
+><I
+>req</I
+></TT
+>
+to canonical format.
+The packet header structure
+<TT
+CLASS="PARAMETER"
+><I
+>pkt</I
+></TT
+>
+is initialised and transferred to
+buffer
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>.
+
+The contents of
+<TT
+CLASS="PARAMETER"
+><I
+>*req</I
+></TT
+>
+are then appended to the buffer in canonical format.
+<TT
+CLASS="FUNCTION"
+>lwres_gabnresponse_render()</TT
+>
+performs the same task, except it converts a getaddrbyname response structure
+<SPAN
+CLASS="TYPE"
+>lwres_gabnresponse_t</SPAN
+>
+to the lightweight resolver's canonical format.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gabnrequest_parse()</TT
+>
+uses context
+<TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+>
+to convert the contents of packet
+<TT
+CLASS="PARAMETER"
+><I
+>pkt</I
+></TT
+>
+to a
+<SPAN
+CLASS="TYPE"
+>lwres_gabnrequest_t</SPAN
+>
+structure.
+Buffer
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>
+provides space to be used for storing this structure.
+When the function succeeds, the resulting
+<SPAN
+CLASS="TYPE"
+>lwres_gabnrequest_t</SPAN
+>
+is made available through
+<TT
+CLASS="PARAMETER"
+><I
+>*structp</I
+></TT
+>.
+
+<TT
+CLASS="FUNCTION"
+>lwres_gabnresponse_parse()</TT
+>
+offers the same semantics as
+<TT
+CLASS="FUNCTION"
+>lwres_gabnrequest_parse()</TT
+>
+except it yields a
+<SPAN
+CLASS="TYPE"
+>lwres_gabnresponse_t</SPAN
+>
+structure.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gabnresponse_free()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_gabnrequest_free()</TT
+>
+release the memory in resolver context
+<TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+>
+that was allocated to the
+<SPAN
+CLASS="TYPE"
+>lwres_gabnresponse_t</SPAN
+>
+or
+<SPAN
+CLASS="TYPE"
+>lwres_gabnrequest_t</SPAN
+>
+structures referenced via
+<TT
+CLASS="PARAMETER"
+><I
+>structp</I
+></TT
+>.
+
+Any memory associated with ancillary buffers and strings for those
+structures is also discarded.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN93"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+>The getaddrbyname opcode functions
+<TT
+CLASS="FUNCTION"
+>lwres_gabnrequest_render()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_gabnresponse_render()</TT
+>
+<TT
+CLASS="FUNCTION"
+>lwres_gabnrequest_parse()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_gabnresponse_parse()</TT
+>
+all return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>
+on success.
+They return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_NOMEMORY</SPAN
+>
+if memory allocation fails.
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_UNEXPECTEDEND</SPAN
+>
+is returned if the available space in the buffer
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>
+is too small to accommodate the packet header or the
+<SPAN
+CLASS="TYPE"
+>lwres_gabnrequest_t</SPAN
+>
+and
+<SPAN
+CLASS="TYPE"
+>lwres_gabnresponse_t</SPAN
+>
+structures.
+<TT
+CLASS="FUNCTION"
+>lwres_gabnrequest_parse()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_gabnresponse_parse()</TT
+>
+will return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_UNEXPECTEDEND</SPAN
+>
+if the buffer is not empty after decoding the received packet.
+These functions will return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_FAILURE</SPAN
+>
+if
+<TT
+CLASS="STRUCTFIELD"
+><I
+>pktflags</I
+></TT
+>
+in the packet header structure
+<SPAN
+CLASS="TYPE"
+>lwres_lwpacket_t</SPAN
+>
+indicate that the packet is not a response to an earlier query.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN112"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_packet</SPAN
+>(3)</SPAN
+></P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_gai_strerror.3 b/lib/liblwres/man/lwres_gai_strerror.3
new file mode 100644
index 000000000..a8287e924
--- /dev/null
+++ b/lib/liblwres/man/lwres_gai_strerror.3
@@ -0,0 +1,86 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_GAI_STRERROR" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+gai_strerror \- print suitable error string
+.SH SYNOPSIS
+\fB#include <lwres/netdb.h>
+.sp
+.na
+char *
+gai_strerror(int ecode);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+\fBlwres_gai_strerror()\fR
+returns an error message corresponding to an error code returned by
+\fBgetaddrinfo()\fR.
+The following error codes and their meaning are defined in
+\fIinclude/lwres/netdb.h\fR.
+.TP
+\fBEAI_ADDRFAMILY\fR
+address family for hostname not supported
+.TP
+\fBEAI_AGAIN\fR
+temporary failure in name resolution
+.TP
+\fBEAI_BADFLAGS\fR
+invalid value for
+ai_flags
+.TP
+\fBEAI_FAIL\fR
+non-recoverable failure in name resolution
+.TP
+\fBEAI_FAMILY\fR
+ai_family not supported
+.TP
+\fBEAI_MEMORY\fR
+memory allocation failure
+.TP
+\fBEAI_NODATA\fR
+no address associated with hostname
+.TP
+\fBEAI_NONAME\fR
+hostname or servname not provided, or not known
+.TP
+\fBEAI_SERVICE\fR
+servname not supported for ai_socktype
+.TP
+\fBEAI_SOCKTYPE\fR
+ai_socktype not supported
+.TP
+\fBEAI_SYSTEM\fR
+system error returned in errno
+.PP
+The message \fBinvalid error code\fR is returned if
+\fIecode\fR
+is out of range.
+.PP
+ai_flags,
+ai_family
+and
+ai_socktype
+are elements of the
+\fBstruct addrinfo\fR
+used by
+\fBlwres_getaddrinfo()\fR.
+.SH "SEE ALSO"
+.PP
+\fBstrerror\fR(3),
+\fBlwres_getaddrinfo\fR(3),
+\fBgetaddrinfo\fR(3),
+\fBRFC2133\fR.
diff --git a/lib/liblwres/man/lwres_gai_strerror.docbook b/lib/liblwres/man/lwres_gai_strerror.docbook
new file mode 100644
index 000000000..6ffe8fc47
--- /dev/null
+++ b/lib/liblwres/man/lwres_gai_strerror.docbook
@@ -0,0 +1,161 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_gai_strerror.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+<refentryinfo>
+
+
+<date>Jun 30, 2000</date>
+</refentryinfo>
+<refmeta>
+<refentrytitle>lwres_gai_strerror</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+<refnamediv>
+<refname>gai_strerror</refname>
+<refpurpose>print suitable error string</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+char *
+<function>gai_strerror</function></funcdef>
+<paramdef>int ecode</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+<function>lwres_gai_strerror()</function>
+returns an error message corresponding to an error code returned by
+<function>getaddrinfo()</function>.
+The following error codes and their meaning are defined in
+<filename>include/lwres/netdb.h</filename>.
+<variablelist>
+<varlistentry><term><errorcode>EAI_ADDRFAMILY</errorcode></term>
+<listitem>
+<para>
+address family for hostname not supported
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_AGAIN</errorcode></term>
+<listitem>
+<para>
+temporary failure in name resolution
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_BADFLAGS</errorcode></term>
+<listitem>
+<para>
+invalid value for
+<constant>ai_flags</constant>
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_FAIL</errorcode></term>
+<listitem>
+<para>
+non-recoverable failure in name resolution
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_FAMILY</errorcode></term>
+<listitem>
+<para>
+<constant>ai_family</constant> not supported
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_MEMORY</errorcode></term>
+<listitem>
+<para>
+memory allocation failure
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_NODATA</errorcode></term>
+<listitem>
+<para>
+no address associated with hostname
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_NONAME</errorcode></term>
+<listitem>
+<para>
+hostname or servname not provided, or not known
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_SERVICE</errorcode></term>
+<listitem>
+<para>
+servname not supported for <constant>ai_socktype</constant>
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_SOCKTYPE</errorcode></term>
+<listitem>
+<para>
+<constant>ai_socktype</constant> not supported
+</para>
+</listitem></varlistentry>
+<varlistentry><term><errorcode>EAI_SYSTEM</errorcode></term>
+<listitem>
+<para>
+system error returned in errno
+</para>
+</listitem></varlistentry>
+</variablelist>
+The message <errorname>invalid error code</errorname> is returned if
+<parameter>ecode</parameter>
+is out of range.
+</para>
+<para>
+<constant>ai_flags</constant>,
+<constant>ai_family</constant>
+and
+<constant>ai_socktype</constant>
+are elements of the
+<type>struct addrinfo</type>
+used by
+<function>lwres_getaddrinfo()</function>.
+</para>
+</refsect1>
+
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>strerror</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_getaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>getaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>RFC2133</refentrytitle>
+</citerefentry>.
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_gai_strerror.html b/lib/liblwres/man/lwres_gai_strerror.html
new file mode 100644
index 000000000..7f245ba4e
--- /dev/null
+++ b/lib/liblwres/man/lwres_gai_strerror.html
@@ -0,0 +1,294 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_gai_strerror</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_gai_strerror</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>gai_strerror&nbsp;--&nbsp;print suitable error string</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN11"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN12"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/netdb.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>char *
+gai_strerror</CODE
+>(int ecode);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN18"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gai_strerror()</TT
+>
+returns an error message corresponding to an error code returned by
+<TT
+CLASS="FUNCTION"
+>getaddrinfo()</TT
+>.
+The following error codes and their meaning are defined in
+<TT
+CLASS="FILENAME"
+>include/lwres/netdb.h</TT
+>.
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_ADDRFAMILY</SPAN
+></DT
+><DD
+><P
+>address family for hostname not supported</P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_AGAIN</SPAN
+></DT
+><DD
+><P
+>temporary failure in name resolution</P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_BADFLAGS</SPAN
+></DT
+><DD
+><P
+>invalid value for
+<TT
+CLASS="CONSTANT"
+>ai_flags</TT
+></P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_FAIL</SPAN
+></DT
+><DD
+><P
+>non-recoverable failure in name resolution</P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_FAMILY</SPAN
+></DT
+><DD
+><P
+><TT
+CLASS="CONSTANT"
+>ai_family</TT
+> not supported</P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_MEMORY</SPAN
+></DT
+><DD
+><P
+>memory allocation failure</P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_NODATA</SPAN
+></DT
+><DD
+><P
+>no address associated with hostname</P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_NONAME</SPAN
+></DT
+><DD
+><P
+>hostname or servname not provided, or not known</P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_SERVICE</SPAN
+></DT
+><DD
+><P
+>servname not supported for <TT
+CLASS="CONSTANT"
+>ai_socktype</TT
+></P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_SOCKTYPE</SPAN
+></DT
+><DD
+><P
+><TT
+CLASS="CONSTANT"
+>ai_socktype</TT
+> not supported</P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>EAI_SYSTEM</SPAN
+></DT
+><DD
+><P
+>system error returned in errno</P
+></DD
+></DL
+></DIV
+>
+The message <SPAN
+CLASS="ERRORNAME"
+>invalid error code</SPAN
+> is returned if
+<TT
+CLASS="PARAMETER"
+><I
+>ecode</I
+></TT
+>
+is out of range.</P
+><P
+><TT
+CLASS="CONSTANT"
+>ai_flags</TT
+>,
+<TT
+CLASS="CONSTANT"
+>ai_family</TT
+>
+and
+<TT
+CLASS="CONSTANT"
+>ai_socktype</TT
+>
+are elements of the
+<SPAN
+CLASS="TYPE"
+>struct addrinfo</SPAN
+>
+used by
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrinfo()</TT
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN92"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>strerror</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_getaddrinfo</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>getaddrinfo</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>RFC2133</SPAN
+></SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_getaddrinfo.3 b/lib/liblwres/man/lwres_getaddrinfo.3
new file mode 100644
index 000000000..b7ea46128
--- /dev/null
+++ b/lib/liblwres/man/lwres_getaddrinfo.3
@@ -0,0 +1,247 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_GETADDRINFO" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_getaddrinfo, lwres_freeaddrinfo \- socket address structure to host and service name
+.SH SYNOPSIS
+\fB#include <lwres/netdb.h>
+.sp
+.na
+int
+lwres_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
+.ad
+.sp
+.na
+void
+lwres_freeaddrinfo(struct addrinfo *ai);
+.ad
+\fR.PP
+If the operating system does not provide a
+\fBstruct addrinfo\fR,
+the following structure is used:
+.sp
+.nf
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+.sp
+.fi
+.SH "DESCRIPTION"
+.PP
+\fBlwres_getaddrinfo()\fR
+is used to get a list of IP addresses and port numbers for host
+\fIhostname\fR
+and service
+\fIservname\fR.
+The function is the lightweight resolver's implementation of
+\fBgetaddrinfo()\fR
+as defined in RFC2133.
+\fIhostname\fR
+and
+\fIservname\fR
+are pointers to null-terminated
+strings or
+\fBNULL\fR.
+\fIhostname\fR
+is either a host name or a numeric host address string: a dotted decimal
+IPv4 address or an IPv6 address.
+\fIservname\fR
+is either a decimal port number or a service name as listed in
+\fI/etc/services\fR.
+.PP
+\fIhints\fR
+is an optional pointer to a
+\fBstruct addrinfo\fR.
+This structure can be used to provide hints concerning the type of socket
+that the caller supports or wishes to use.
+The caller can supply the following structure elements in
+\fI*hints\fR:
+.TP
+\fBai_family\fR
+The protocol family that should be used.
+When
+ai_family
+is set to
+\fBPF_UNSPEC\fR,
+it means the caller will accept any protocol family supported by the
+operating system.
+.TP
+\fBai_socktype\fR
+denotes the type of socket \(em
+\fBSOCK_STREAM\fR,
+\fBSOCK_DGRAM\fR
+or
+\fBSOCK_RAW\fR
+\(em that is wanted.
+When
+ai_socktype
+is zero the caller will accept any socket type.
+.TP
+\fBai_protocol\fR
+indicates which transport protocol is wanted: IPPROTO_UDP or
+IPPROTO_TCP.
+If
+ai_protocol
+is zero the caller will accept any protocol.
+.TP
+\fBai_flags\fR
+Flag bits.
+If the
+\fBAI_CANONNAME\fR
+bit is set, a successful call to
+\fBlwres_getaddrinfo()\fR
+will return a a null-terminated string containing the canonical name
+of the specified hostname in
+ai_canonname
+of the first
+\fBaddrinfo\fR
+structure returned.
+Setting the
+\fBAI_PASSIVE\fR
+bit indicates that the returned socket address structure is intended
+for used in a call to
+\fBbind\fR(2).
+In this case, if the hostname argument is a
+\fBNULL\fR
+pointer, then the IP address portion of the socket
+address structure will be set to
+\fBINADDR_ANY\fR
+for an IPv4 address or
+\fBIN6ADDR_ANY_INIT\fR
+for an IPv6 address.
+
+When
+ai_flags
+does not set the
+\fBAI_PASSIVE\fR
+bit, the returned socket address structure will be ready
+for use in a call to
+\fBconnect\fR(2)
+for a connection-oriented protocol or
+\fBconnect\fR(2),
+\fBsendto\fR(2),
+or
+\fBsendmsg\fR(2)
+if a connectionless protocol was chosen.
+The IP address portion of the socket address structure will be
+set to the loopback address if
+\fIhostname\fR
+is a
+\fBNULL\fR
+pointer and
+\fBAI_PASSIVE\fR
+is not set in
+ai_flags.
+
+If
+ai_flags
+is set to
+\fBAI_NUMERICHOST\fR
+it indicates that
+\fIhostname\fR
+should be treated as a numeric string defining an IPv4 or IPv6 address
+and no name resolution should be attempted.
+.PP
+All other elements of the \fBstruct addrinfo\fR passed
+via \fIhints\fR must be zero.
+.PP
+A \fIhints\fR of \fBNULL\fR is treated as if
+the caller provided a \fBstruct addrinfo\fR initialized to zero
+with ai_familyset to
+PF_UNSPEC.
+.PP
+After a successful call to
+\fBlwres_getaddrinfo()\fR,
+\fI*res\fR
+is a pointer to a linked list of one or more
+\fBaddrinfo\fR
+structures.
+Each
+\fBstruct addrinfo\fR
+in this list cn be processed by following
+the
+ai_next
+pointer, until a
+\fBNULL\fR
+pointer is encountered.
+The three members
+ai_family,
+ai_socktype,
+and
+ai_protocol
+in each
+returned
+\fBaddrinfo\fR
+structure contain the corresponding arguments for a call to
+\fBsocket\fR(2).
+For each
+\fBaddrinfo\fR
+structure in the list, the
+ai_addr
+member points to a filled-in socket address structure of length
+ai_addrlen.
+.PP
+All of the information returned by
+\fBlwres_getaddrinfo()\fR
+is dynamically allocated: the addrinfo structures, and the socket
+address structures and canonical host name strings pointed to by the
+addrinfostructures.
+Memory allocated for the dynamically allocated structures created by
+a successful call to
+\fBlwres_getaddrinfo()\fR
+is released by
+\fBlwres_freeaddrinfo()\fR.
+\fIai\fR
+is a pointer to a
+\fBstruct addrinfo\fR
+created by a call to
+\fBlwres_getaddrinfo()\fR.
+.SH "RETURN VALUES"
+.PP
+\fBlwres_getaddrinfo()\fR
+returns zero on success or one of the error codes listed in
+\fBgai_strerror\fR(3)
+if an error occurs.
+If both
+\fIhostname\fR
+and
+\fIservname\fR
+are
+\fBNULL\fR
+\fBlwres_getaddrinfo()\fR
+returns
+EAI_NONAME.
+.SH "SEE ALSO"
+.PP
+\fBlwres\fR(3),
+\fBlwres_getaddrinfo\fR(3),
+\fBlwres_freeaddrinfo\fR(3),
+\fBlwres_gai_strerror\fR(3),
+\fBRFC2133\fR,
+\fBgetservbyname\fR(3),
+\fBbind\fR(2),
+\fBconnect\fR(2),
+\fBsendto\fR(2),
+\fBsendmsg\fR(2),
+\fBsocket\fR(2).
diff --git a/lib/liblwres/man/lwres_getaddrinfo.docbook b/lib/liblwres/man/lwres_getaddrinfo.docbook
new file mode 100644
index 000000000..f89107304
--- /dev/null
+++ b/lib/liblwres/man/lwres_getaddrinfo.docbook
@@ -0,0 +1,372 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_getaddrinfo.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_getaddrinfo</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_getaddrinfo</refname>
+<refname>lwres_freeaddrinfo</refname>
+<refpurpose>socket address structure to host and service name</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+int
+<function>lwres_getaddrinfo</function></funcdef>
+<paramdef>const char *hostname</paramdef>
+<paramdef>const char *servname</paramdef>
+<paramdef>const struct addrinfo *hints</paramdef>
+<paramdef>struct addrinfo **res</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_freeaddrinfo</function></funcdef>
+<paramdef>struct addrinfo *ai</paramdef>
+</funcprototype>
+</funcsynopsis>
+
+<para>
+If the operating system does not provide a
+<type>struct addrinfo</type>,
+the following structure is used:
+
+<programlisting>
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+</programlisting>
+</para>
+
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+<function>lwres_getaddrinfo()</function>
+is used to get a list of IP addresses and port numbers for host
+<parameter>hostname</parameter>
+and service
+<parameter>servname</parameter>.
+
+The function is the lightweight resolver's implementation of
+<function>getaddrinfo()</function>
+as defined in RFC2133.
+<parameter>hostname</parameter>
+and
+<parameter>servname</parameter>
+are pointers to null-terminated
+strings or
+<type>NULL</type>.
+
+<parameter>hostname</parameter>
+is either a host name or a numeric host address string: a dotted decimal
+IPv4 address or an IPv6 address.
+<parameter>servname</parameter>
+is either a decimal port number or a service name as listed in
+<filename>/etc/services</filename>.
+</para>
+
+<para>
+<parameter>hints</parameter>
+is an optional pointer to a
+<type>struct addrinfo</type>.
+This structure can be used to provide hints concerning the type of socket
+that the caller supports or wishes to use.
+The caller can supply the following structure elements in
+<parameter>*hints</parameter>:
+
+<variablelist>
+<varlistentry><term><constant>ai_family</constant></term>
+<listitem>
+<para>The protocol family that should be used.
+When
+<constant>ai_family</constant>
+is set to
+<type>PF_UNSPEC</type>,
+it means the caller will accept any protocol family supported by the
+operating system.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>ai_socktype</constant></term>
+<listitem>
+<para>
+denotes the type of socket &mdash;
+<type>SOCK_STREAM</type>,
+<type>SOCK_DGRAM</type>
+or
+<type>SOCK_RAW</type>
+&mdash; that is wanted.
+When
+<constant>ai_socktype</constant>
+is zero the caller will accept any socket type.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry><term><constant>ai_protocol</constant></term>
+<listitem>
+<para>
+indicates which transport protocol is wanted: IPPROTO_UDP or
+IPPROTO_TCP.
+If
+<constant>ai_protocol</constant>
+is zero the caller will accept any protocol.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry><term><constant>ai_flags</constant></term>
+<listitem>
+<para>
+Flag bits.
+If the
+<type>AI_CANONNAME</type>
+bit is set, a successful call to
+<function>lwres_getaddrinfo()</function>
+will return a a null-terminated string containing the canonical name
+of the specified hostname in
+<constant>ai_canonname</constant>
+of the first
+<type>addrinfo</type>
+structure returned.
+Setting the
+<type>AI_PASSIVE</type>
+bit indicates that the returned socket address structure is intended
+for used in a call to
+<citerefentry>
+<refentrytitle>bind</refentrytitle><manvolnum>2</manvolnum>
+</citerefentry>.
+
+In this case, if the hostname argument is a
+<type>NULL</type>
+pointer, then the IP address portion of the socket
+address structure will be set to
+<type>INADDR_ANY</type>
+for an IPv4 address or
+<type>IN6ADDR_ANY_INIT</type>
+for an IPv6 address.
+</para>
+<para>
+When
+<constant>ai_flags</constant>
+does not set the
+<type>AI_PASSIVE</type>
+bit, the returned socket address structure will be ready
+for use in a call to
+<citerefentry>
+<refentrytitle>connect</refentrytitle><manvolnum>2
+</manvolnum>
+</citerefentry>
+for a connection-oriented protocol or
+<citerefentry>
+<refentrytitle>connect</refentrytitle><manvolnum>2</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>sendto</refentrytitle><manvolnum>2</manvolnum>
+</citerefentry>,
+
+or
+<citerefentry>
+<refentrytitle>sendmsg</refentrytitle><manvolnum>2
+</manvolnum>
+</citerefentry>
+if a connectionless protocol was chosen.
+The IP address portion of the socket address structure will be
+set to the loopback address if
+<parameter>hostname</parameter>
+is a
+<type>NULL</type>
+pointer and
+<type>AI_PASSIVE</type>
+is not set in
+<constant>ai_flags</constant>.
+</para>
+<para>
+If
+<constant>ai_flags</constant>
+is set to
+<type>AI_NUMERICHOST</type>
+it indicates that
+<parameter>hostname</parameter>
+should be treated as a numeric string defining an IPv4 or IPv6 address
+and no name resolution should be attempted.
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</para>
+
+<para>
+All other elements of the <type>struct addrinfo</type> passed
+via <parameter>hints</parameter> must be zero.
+</para>
+
+<para>
+A <parameter>hints</parameter> of <type>NULL</type> is treated as if
+the caller provided a <type>struct addrinfo</type> initialized to zero
+with <constant>ai_family</constant>set to
+<constant>PF_UNSPEC</constant>.
+</para>
+
+<para>
+After a successful call to
+<function>lwres_getaddrinfo()</function>,
+<parameter>*res</parameter>
+is a pointer to a linked list of one or more
+<type>addrinfo</type>
+structures.
+Each
+<type>struct addrinfo</type>
+in this list cn be processed by following
+the
+<constant>ai_next</constant>
+pointer, until a
+<type>NULL</type>
+pointer is encountered.
+The three members
+<constant>ai_family</constant>,
+<constant>ai_socktype</constant>,
+and
+<constant>ai_protocol</constant>
+in each
+returned
+<type>addrinfo</type>
+structure contain the corresponding arguments for a call to
+<citerefentry>
+<refentrytitle>socket</refentrytitle><manvolnum>2</manvolnum>
+</citerefentry>.
+For each
+<type>addrinfo</type>
+structure in the list, the
+<constant>ai_addr</constant>
+member points to a filled-in socket address structure of length
+<constant>ai_addrlen</constant>.
+</para>
+
+<para>
+All of the information returned by
+<function>lwres_getaddrinfo()</function>
+is dynamically allocated: the addrinfo structures, and the socket
+address structures and canonical host name strings pointed to by the
+<constant>addrinfo</constant>structures.
+Memory allocated for the dynamically allocated structures created by
+a successful call to
+<function>lwres_getaddrinfo()</function>
+is released by
+<function>lwres_freeaddrinfo()</function>.
+<parameter>ai</parameter>
+is a pointer to a
+<type>struct addrinfo</type>
+created by a call to
+<function>lwres_getaddrinfo()</function>.
+</para>
+
+</refsect1>
+
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+<function>lwres_getaddrinfo()</function>
+returns zero on success or one of the error codes listed in
+<citerefentry>
+<refentrytitle>gai_strerror</refentrytitle><manvolnum>3
+</manvolnum>
+</citerefentry>
+if an error occurs.
+If both
+<parameter>hostname</parameter>
+and
+<parameter>servname</parameter>
+are
+<type>NULL</type>
+<function>lwres_getaddrinfo()</function>
+returns
+<errorcode>EAI_NONAME</errorcode>.
+
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>lwres</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_getaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_freeaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_gai_strerror</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>RFC2133</refentrytitle>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>getservbyname</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>bind</refentrytitle><manvolnum>2</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>connect</refentrytitle><manvolnum>2</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>sendto</refentrytitle><manvolnum>2</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>sendmsg</refentrytitle><manvolnum>2</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>socket</refentrytitle><manvolnum>2</manvolnum>
+</citerefentry>.
+</para>
+
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_getaddrinfo.html b/lib/liblwres/man/lwres_getaddrinfo.html
new file mode 100644
index 000000000..d04ecc1a2
--- /dev/null
+++ b/lib/liblwres/man/lwres_getaddrinfo.html
@@ -0,0 +1,722 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_getaddrinfo</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_getaddrinfo</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_getaddrinfo, lwres_freeaddrinfo&nbsp;--&nbsp;socket address structure to host and service name</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN12"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN13"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/netdb.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>int
+lwres_getaddrinfo</CODE
+>(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_freeaddrinfo</CODE
+>(struct addrinfo *ai);</CODE
+></P
+><P
+></P
+></DIV
+><P
+>If the operating system does not provide a
+<SPAN
+CLASS="TYPE"
+>struct addrinfo</SPAN
+>,
+the following structure is used:
+
+<PRE
+CLASS="PROGRAMLISTING"
+>struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};</PRE
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN29"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getaddrinfo()</TT
+>
+is used to get a list of IP addresses and port numbers for host
+<TT
+CLASS="PARAMETER"
+><I
+>hostname</I
+></TT
+>
+and service
+<TT
+CLASS="PARAMETER"
+><I
+>servname</I
+></TT
+>.
+
+The function is the lightweight resolver's implementation of
+<TT
+CLASS="FUNCTION"
+>getaddrinfo()</TT
+>
+as defined in RFC2133.
+<TT
+CLASS="PARAMETER"
+><I
+>hostname</I
+></TT
+>
+and
+<TT
+CLASS="PARAMETER"
+><I
+>servname</I
+></TT
+>
+are pointers to null-terminated
+strings or
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+>.
+
+<TT
+CLASS="PARAMETER"
+><I
+>hostname</I
+></TT
+>
+is either a host name or a numeric host address string: a dotted decimal
+IPv4 address or an IPv6 address.
+<TT
+CLASS="PARAMETER"
+><I
+>servname</I
+></TT
+>
+is either a decimal port number or a service name as listed in
+<TT
+CLASS="FILENAME"
+>/etc/services</TT
+>.</P
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>hints</I
+></TT
+>
+is an optional pointer to a
+<SPAN
+CLASS="TYPE"
+>struct addrinfo</SPAN
+>.
+This structure can be used to provide hints concerning the type of socket
+that the caller supports or wishes to use.
+The caller can supply the following structure elements in
+<TT
+CLASS="PARAMETER"
+><I
+>*hints</I
+></TT
+>:
+
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>ai_family</TT
+></DT
+><DD
+><P
+>The protocol family that should be used.
+When
+<TT
+CLASS="CONSTANT"
+>ai_family</TT
+>
+is set to
+<SPAN
+CLASS="TYPE"
+>PF_UNSPEC</SPAN
+>,
+it means the caller will accept any protocol family supported by the
+operating system.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>ai_socktype</TT
+></DT
+><DD
+><P
+>denotes the type of socket &mdash;
+<SPAN
+CLASS="TYPE"
+>SOCK_STREAM</SPAN
+>,
+<SPAN
+CLASS="TYPE"
+>SOCK_DGRAM</SPAN
+>
+or
+<SPAN
+CLASS="TYPE"
+>SOCK_RAW</SPAN
+>
+&mdash; that is wanted.
+When
+<TT
+CLASS="CONSTANT"
+>ai_socktype</TT
+>
+is zero the caller will accept any socket type.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>ai_protocol</TT
+></DT
+><DD
+><P
+>indicates which transport protocol is wanted: IPPROTO_UDP or
+IPPROTO_TCP.
+If
+<TT
+CLASS="CONSTANT"
+>ai_protocol</TT
+>
+is zero the caller will accept any protocol.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>ai_flags</TT
+></DT
+><DD
+><P
+>Flag bits.
+If the
+<SPAN
+CLASS="TYPE"
+>AI_CANONNAME</SPAN
+>
+bit is set, a successful call to
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrinfo()</TT
+>
+will return a a null-terminated string containing the canonical name
+of the specified hostname in
+<TT
+CLASS="CONSTANT"
+>ai_canonname</TT
+>
+of the first
+<SPAN
+CLASS="TYPE"
+>addrinfo</SPAN
+>
+structure returned.
+Setting the
+<SPAN
+CLASS="TYPE"
+>AI_PASSIVE</SPAN
+>
+bit indicates that the returned socket address structure is intended
+for used in a call to
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>bind</SPAN
+>(2)</SPAN
+>.
+
+In this case, if the hostname argument is a
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+>
+pointer, then the IP address portion of the socket
+address structure will be set to
+<SPAN
+CLASS="TYPE"
+>INADDR_ANY</SPAN
+>
+for an IPv4 address or
+<SPAN
+CLASS="TYPE"
+>IN6ADDR_ANY_INIT</SPAN
+>
+for an IPv6 address.</P
+><P
+>When
+<TT
+CLASS="CONSTANT"
+>ai_flags</TT
+>
+does not set the
+<SPAN
+CLASS="TYPE"
+>AI_PASSIVE</SPAN
+>
+bit, the returned socket address structure will be ready
+for use in a call to
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>connect</SPAN
+>(2)</SPAN
+>
+for a connection-oriented protocol or
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>connect</SPAN
+>(2)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>sendto</SPAN
+>(2)</SPAN
+>,
+
+or
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>sendmsg</SPAN
+>(2)</SPAN
+>
+if a connectionless protocol was chosen.
+The IP address portion of the socket address structure will be
+set to the loopback address if
+<TT
+CLASS="PARAMETER"
+><I
+>hostname</I
+></TT
+>
+is a
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+>
+pointer and
+<SPAN
+CLASS="TYPE"
+>AI_PASSIVE</SPAN
+>
+is not set in
+<TT
+CLASS="CONSTANT"
+>ai_flags</TT
+>.</P
+><P
+>If
+<TT
+CLASS="CONSTANT"
+>ai_flags</TT
+>
+is set to
+<SPAN
+CLASS="TYPE"
+>AI_NUMERICHOST</SPAN
+>
+it indicates that
+<TT
+CLASS="PARAMETER"
+><I
+>hostname</I
+></TT
+>
+should be treated as a numeric string defining an IPv4 or IPv6 address
+and no name resolution should be attempted.</P
+></DD
+></DL
+></DIV
+></P
+><P
+>All other elements of the <SPAN
+CLASS="TYPE"
+>struct addrinfo</SPAN
+> passed
+via <TT
+CLASS="PARAMETER"
+><I
+>hints</I
+></TT
+> must be zero.</P
+><P
+>A <TT
+CLASS="PARAMETER"
+><I
+>hints</I
+></TT
+> of <SPAN
+CLASS="TYPE"
+>NULL</SPAN
+> is treated as if
+the caller provided a <SPAN
+CLASS="TYPE"
+>struct addrinfo</SPAN
+> initialized to zero
+with <TT
+CLASS="CONSTANT"
+>ai_family</TT
+>set to
+<TT
+CLASS="CONSTANT"
+>PF_UNSPEC</TT
+>.</P
+><P
+>After a successful call to
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrinfo()</TT
+>,
+<TT
+CLASS="PARAMETER"
+><I
+>*res</I
+></TT
+>
+is a pointer to a linked list of one or more
+<SPAN
+CLASS="TYPE"
+>addrinfo</SPAN
+>
+structures.
+Each
+<SPAN
+CLASS="TYPE"
+>struct addrinfo</SPAN
+>
+in this list cn be processed by following
+the
+<TT
+CLASS="CONSTANT"
+>ai_next</TT
+>
+pointer, until a
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+>
+pointer is encountered.
+The three members
+<TT
+CLASS="CONSTANT"
+>ai_family</TT
+>,
+<TT
+CLASS="CONSTANT"
+>ai_socktype</TT
+>,
+and
+<TT
+CLASS="CONSTANT"
+>ai_protocol</TT
+>
+in each
+returned
+<SPAN
+CLASS="TYPE"
+>addrinfo</SPAN
+>
+structure contain the corresponding arguments for a call to
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>socket</SPAN
+>(2)</SPAN
+>.
+For each
+<SPAN
+CLASS="TYPE"
+>addrinfo</SPAN
+>
+structure in the list, the
+<TT
+CLASS="CONSTANT"
+>ai_addr</TT
+>
+member points to a filled-in socket address structure of length
+<TT
+CLASS="CONSTANT"
+>ai_addrlen</TT
+>.</P
+><P
+>All of the information returned by
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrinfo()</TT
+>
+is dynamically allocated: the addrinfo structures, and the socket
+address structures and canonical host name strings pointed to by the
+<TT
+CLASS="CONSTANT"
+>addrinfo</TT
+>structures.
+Memory allocated for the dynamically allocated structures created by
+a successful call to
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrinfo()</TT
+>
+is released by
+<TT
+CLASS="FUNCTION"
+>lwres_freeaddrinfo()</TT
+>.
+<TT
+CLASS="PARAMETER"
+><I
+>ai</I
+></TT
+>
+is a pointer to a
+<SPAN
+CLASS="TYPE"
+>struct addrinfo</SPAN
+>
+created by a call to
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrinfo()</TT
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN142"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getaddrinfo()</TT
+>
+returns zero on success or one of the error codes listed in
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>gai_strerror</SPAN
+>(3)</SPAN
+>
+if an error occurs.
+If both
+<TT
+CLASS="PARAMETER"
+><I
+>hostname</I
+></TT
+>
+and
+<TT
+CLASS="PARAMETER"
+><I
+>servname</I
+></TT
+>
+are
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+>
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrinfo()</TT
+>
+returns
+<SPAN
+CLASS="ERRORCODE"
+>EAI_NONAME</SPAN
+>.&#13;</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN154"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_getaddrinfo</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_freeaddrinfo</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_gai_strerror</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>RFC2133</SPAN
+></SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>getservbyname</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>bind</SPAN
+>(2)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>connect</SPAN
+>(2)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>sendto</SPAN
+>(2)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>sendmsg</SPAN
+>(2)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>socket</SPAN
+>(2)</SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_gethostent.3 b/lib/liblwres/man/lwres_gethostent.3
new file mode 100644
index 000000000..44811ef4d
--- /dev/null
+++ b/lib/liblwres/man/lwres_gethostent.3
@@ -0,0 +1,270 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_GETHOSTENT" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_gethostbyname, lwres_gethostbyname2, lwres_gethostbyaddr, lwres_gethostent, lwres_sethostent, lwres_endhostent, lwres_gethostbyname_r, lwres_gethostbyaddr_r, lwres_gethostent_r, lwres_sethostent_r, lwres_endhostent_r \- lightweight resolver get network host entry
+.SH SYNOPSIS
+\fB#include <lwres/netdb.h>
+.sp
+.na
+struct hostent *
+lwres_gethostbyname(const char *name);
+.ad
+.sp
+.na
+struct hostent *
+lwres_gethostbyname2(const char *name, int af);
+.ad
+.sp
+.na
+struct hostent *
+lwres_gethostbyaddr(const char *addr, int len, int type);
+.ad
+.sp
+.na
+struct hostent *
+lwres_gethostent(void);
+.ad
+.sp
+.na
+void
+lwres_sethostent(int stayopen);
+.ad
+.sp
+.na
+void
+lwres_endhostent(void);
+.ad
+.sp
+.na
+struct hostent *
+lwres_gethostbyname_r(const char *name, struct hostent *resbuf, char *buf, int buflen, int *error);
+.ad
+.sp
+.na
+struct hostent *
+lwres_gethostbyaddr_r(const char *addr, int len, int type, struct hostent *resbuf, char *buf, int buflen, int *error);
+.ad
+.sp
+.na
+struct hostent *
+lwres_gethostent_r(struct hostent *resbuf, char *buf, int buflen, int *error);
+.ad
+.sp
+.na
+void
+lwres_sethostent_r(int stayopen);
+.ad
+.sp
+.na
+void
+lwres_endhostent_r(void);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+These functions provide hostname-to-address and
+address-to-hostname lookups by means of the lightweight resolver.
+They are similar to the standard
+\fBgethostent\fR(3)
+functions provided by most operating systems.
+They use a
+\fBstruct hostent\fR
+which is usually defined in
+\fI<namedb.h>\fR.
+.sp
+.nf
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+};
+#define h_addr h_addr_list[0] /* address, for backward compatibility */
+.sp
+.fi
+.PP
+The members of this structure are:
+.TP
+\fBh_name\fR
+The official (canonical) name of the host.
+.TP
+\fBh_aliases\fR
+A NULL-terminated array of alternate names (nicknames) for the host.
+.TP
+\fBh_addrtype\fR
+The type of address being returned \(em
+\fBPF_INET\fR
+or
+\fBPF_INET6\fR.
+.TP
+\fBh_length\fR
+The length of the address in bytes.
+.TP
+\fBh_addr_list\fR
+A \fBNULL\fR
+terminated array of network addresses for the host.
+Host addresses are returned in network byte order.
+.PP
+For backward compatibility with very old software,
+h_addr
+is the first address in
+h_addr_list.
+.PP
+\fBlwres_gethostent()\fR,
+\fBlwres_sethostent()\fR,
+\fBlwres_endhostent()\fR,
+\fBlwres_gethostent_r()\fR,
+\fBlwres_sethostent_r()\fR
+and
+\fBlwres_endhostent_r()\fR
+provide iteration over the known host entries on systems that
+provide such functionality through facilities like
+\fI/etc/hosts\fR
+or NIS. The lightweight resolver does not currently implement
+these functions; it only provides them as stub functions that always
+return failure.
+.PP
+\fBlwres_gethostbyname()\fR and
+\fBlwres_gethostbyname2()\fR look up the hostname
+\fIname\fR.
+\fBlwres_gethostbyname()\fR always looks for an IPv4
+address while \fBlwres_gethostbyname2()\fR looks for an
+address of protocol family \fIaf\fR: either
+\fBPF_INET\fR or \fBPF_INET6\fR \(em IPv4 or IPV6
+addresses respectively. Successful calls of the functions return a
+\fBstruct hostent\fRfor the name that was looked up.
+\fBNULL\fR is returned if the lookups by
+\fBlwres_gethostbyname()\fR or
+\fBlwres_gethostbyname2()\fR fail.
+.PP
+Reverse lookups of addresses are performed by
+\fBlwres_gethostbyaddr()\fR.
+\fIaddr\fR is an address of length
+\fIlen\fR bytes and protocol family
+\fItype\fR \(em \fBPF_INET\fR or
+\fBPF_INET6\fR.
+\fBlwres_gethostbyname_r()\fR is a thread-safe function
+for forward lookups. If an error occurs, an error code is returned in
+\fI*error\fR.
+\fIresbuf\fR is a pointer to a \fBstruct
+hostent\fR which is initialised by a successful call to
+\fBlwres_gethostbyname_r()\fR .
+\fIbuf\fR is a buffer of length
+\fIlen\fR bytes which is used to store the
+h_name, h_aliases, and
+h_addr_list elements of the \fBstruct
+hostent\fR returned in \fIresbuf\fR.
+Successful calls to \fBlwres_gethostbyname_r()\fR
+return \fIresbuf\fR,
+which is a pointer to the \fBstruct hostent\fR it created.
+.PP
+\fBlwres_gethostbyaddr_r()\fR is a thread-safe function
+that performs a reverse lookup of address \fIaddr\fR
+which is \fIlen\fR bytes long and is of protocol
+family \fItype\fR \(em \fBPF_INET\fR or
+\fBPF_INET6\fR. If an error occurs, the error code is returned
+in \fI*error\fR. The other function parameters are
+identical to those in \fBlwres_gethostbyname_r()\fR.
+\fIresbuf\fR is a pointer to a \fBstruct
+hostent\fR which is initialised by a successful call to
+\fBlwres_gethostbyaddr_r()\fR.
+\fIbuf\fR is a buffer of length
+\fIlen\fR bytes which is used to store the
+h_name, h_aliases, and
+h_addr_list elements of the \fBstruct
+hostent\fR returned in \fIresbuf\fR. Successful
+calls to \fBlwres_gethostbyaddr_r()\fR return
+\fIresbuf\fR, which is a pointer to the
+\fBstruct hostent()\fR it created.
+.SH "RETURN VALUES"
+.PP
+The functions
+\fBlwres_gethostbyname()\fR,
+\fBlwres_gethostbyname2()\fR,
+\fBlwres_gethostbyaddr()\fR,
+and
+\fBlwres_gethostent()\fR
+return NULL to indicate an error. In this case the global variable
+\fBlwres_h_errno\fR
+will contain one of the following error codes defined in
+\fI<lwres/netdb.h>\fR:
+.TP
+\fBHOST_NOT_FOUND\fR
+The host or address was not found.
+.TP
+\fBTRY_AGAIN\fR
+A recoverable error occurred, e.g., a timeout.
+Retrying the lookup may succeed.
+.TP
+\fBNO_RECOVERY\fR
+A non-recoverable error occurred.
+.TP
+\fBNO_DATA\fR
+The name exists, but has no address information
+associated with it (or vice versa in the case
+of a reverse lookup). The code NO_ADDRESS
+is accepted as a synonym for NO_DATA for backwards
+compatibility.
+.PP
+\fBlwres_hstrerror\fR(3)
+translates these error codes to suitable error messages.
+.PP
+\fBlwres_gethostent()\fR
+and
+\fBlwres_gethostent_r()\fR
+always return
+\fBNULL\fR.
+.PP
+Successful calls to \fBlwres_gethostbyname_r()\fR and
+\fBlwres_gethostbyaddr_r()\fR return
+\fIresbuf\fR, a pointer to the \fBstruct
+hostent\fR that was initialised by these functions. They return
+\fBNULL\fR if the lookups fail or if \fIbuf\fR
+was too small to hold the list of addresses and names referenced by
+the h_name, h_aliases, and
+h_addr_list elements of the \fBstruct
+hostent\fR. If \fIbuf\fR was too small, both
+\fBlwres_gethostbyname_r()\fR and
+\fBlwres_gethostbyaddr_r()\fR set the global variable
+\fBerrno\fR to ERANGE.
+.SH "SEE ALSO"
+.PP
+\fBgethostent\fR(3),
+\fBlwres_getipnode\fR(3),
+\fBlwres_hstrerror\fR(3)
+.SH "BUGS"
+.PP
+\fBlwres_gethostbyname()\fR,
+\fBlwres_gethostbyname2()\fR,
+\fBlwres_gethostbyaddr()\fR
+and
+\fBlwres_endhostent()\fR
+are not thread safe; they return pointers to static data and
+provide error codes through a global variable.
+Thread-safe versions for name and address lookup are provided by
+\fBlwres_gethostbyname_r()\fR,
+and
+\fBlwres_gethostbyaddr_r()\fR
+respectively.
+.PP
+The resolver daemon does not currently support any non-DNS
+name services such as
+\fI/etc/hosts\fR
+or
+\fBNIS\fR,
+consequently the above functions don't, either.
diff --git a/lib/liblwres/man/lwres_gethostent.docbook b/lib/liblwres/man/lwres_gethostent.docbook
new file mode 100644
index 000000000..22717821c
--- /dev/null
+++ b/lib/liblwres/man/lwres_gethostent.docbook
@@ -0,0 +1,407 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_gethostent.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_gethostent</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_gethostbyname</refname>
+<refname>lwres_gethostbyname2</refname>
+<refname>lwres_gethostbyaddr</refname>
+<refname>lwres_gethostent</refname>
+<refname>lwres_sethostent</refname>
+<refname>lwres_endhostent</refname>
+<refname>lwres_gethostbyname_r</refname>
+<refname>lwres_gethostbyaddr_r</refname>
+<refname>lwres_gethostent_r</refname>
+<refname>lwres_sethostent_r</refname>
+<refname>lwres_endhostent_r</refname>
+<refpurpose>lightweight resolver get network host entry</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+struct hostent *
+<function>lwres_gethostbyname</function></funcdef>
+<paramdef>const char *name</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+struct hostent *
+<function>lwres_gethostbyname2</function></funcdef>
+<paramdef>const char *name</paramdef>
+<paramdef>int af</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+struct hostent *
+<function>lwres_gethostbyaddr</function></funcdef>
+<paramdef>const char *addr</paramdef>
+<paramdef>int len</paramdef>
+<paramdef>int type</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+struct hostent *
+<function>lwres_gethostent</function></funcdef>
+<paramdef>void</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_sethostent</function></funcdef>
+<paramdef>int stayopen</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_endhostent</function></funcdef>
+<paramdef>void</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+struct hostent *
+<function>lwres_gethostbyname_r</function></funcdef>
+<paramdef>const char *name</paramdef>
+<paramdef>struct hostent *resbuf</paramdef>
+<paramdef>char *buf</paramdef>
+<paramdef>int buflen</paramdef>
+<paramdef>int *error</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+struct hostent *
+<function>lwres_gethostbyaddr_r</function></funcdef>
+<paramdef>const char *addr</paramdef>
+<paramdef>int len</paramdef>
+<paramdef>int type</paramdef>
+<paramdef>struct hostent *resbuf</paramdef>
+<paramdef>char *buf</paramdef>
+<paramdef>int buflen</paramdef>
+<paramdef>int *error</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+struct hostent *
+<function>lwres_gethostent_r</function></funcdef>
+<paramdef>struct hostent *resbuf</paramdef>
+<paramdef>char *buf</paramdef>
+<paramdef>int buflen</paramdef>
+<paramdef>int *error</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_sethostent_r</function></funcdef>
+<paramdef>int stayopen</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_endhostent_r</function></funcdef>
+<paramdef>void</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+These functions provide hostname-to-address and
+address-to-hostname lookups by means of the lightweight resolver.
+They are similar to the standard
+<citerefentry>
+<refentrytitle>gethostent</refentrytitle><manvolnum>3
+</manvolnum>
+</citerefentry>
+functions provided by most operating systems.
+They use a
+<type>struct hostent</type>
+which is usually defined in
+<filename>&lt;namedb.h&gt;</filename>.
+
+<programlisting>
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+};
+#define h_addr h_addr_list[0] /* address, for backward compatibility */
+</programlisting>
+</para>
+<para>
+The members of this structure are:
+<variablelist>
+<varlistentry><term><constant>h_name</constant></term>
+<listitem>
+<para>
+The official (canonical) name of the host.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>h_aliases</constant></term>
+<listitem>
+<para>
+A NULL-terminated array of alternate names (nicknames) for the host.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>h_addrtype</constant></term>
+<listitem>
+<para>
+The type of address being returned &mdash;
+<type>PF_INET</type>
+or
+<type>PF_INET6</type>.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>h_length</constant></term>
+<listitem>
+<para>
+The length of the address in bytes.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>h_addr_list</constant></term>
+<listitem>
+<para>
+A <type>NULL</type>
+terminated array of network addresses for the host.
+Host addresses are returned in network byte order.
+</para>
+</listitem></varlistentry>
+</variablelist>
+</para>
+<para>
+For backward compatibility with very old software,
+<constant>h_addr</constant>
+is the first address in
+<constant>h_addr_list.</constant>
+</para>
+<para>
+<function>lwres_gethostent()</function>,
+<function>lwres_sethostent()</function>,
+<function>lwres_endhostent()</function>,
+<function>lwres_gethostent_r()</function>,
+<function>lwres_sethostent_r()</function>
+and
+<function>lwres_endhostent_r()</function>
+provide iteration over the known host entries on systems that
+provide such functionality through facilities like
+<filename>/etc/hosts</filename>
+or NIS. The lightweight resolver does not currently implement
+these functions; it only provides them as stub functions that always
+return failure.
+</para>
+
+<para>
+<function>lwres_gethostbyname()</function> and
+<function>lwres_gethostbyname2()</function> look up the hostname
+<parameter>name</parameter>.
+<function>lwres_gethostbyname()</function> always looks for an IPv4
+address while <function>lwres_gethostbyname2()</function> looks for an
+address of protocol family <parameter>af</parameter>: either
+<type>PF_INET</type> or <type>PF_INET6</type> &mdash; IPv4 or IPV6
+addresses respectively. Successful calls of the functions return a
+<type>struct hostent</type>for the name that was looked up.
+<type>NULL</type> is returned if the lookups by
+<function>lwres_gethostbyname()</function> or
+<function>lwres_gethostbyname2()</function> fail.
+</para>
+
+<para>
+Reverse lookups of addresses are performed by
+<function>lwres_gethostbyaddr()</function>.
+<parameter>addr</parameter> is an address of length
+<parameter>len</parameter> bytes and protocol family
+<parameter>type</parameter> &mdash; <type>PF_INET</type> or
+<type>PF_INET6</type>.
+<function>lwres_gethostbyname_r()</function> is a thread-safe function
+for forward lookups. If an error occurs, an error code is returned in
+<parameter>*error</parameter>.
+<parameter>resbuf</parameter> is a pointer to a <type>struct
+hostent</type> which is initialised by a successful call to
+<function>lwres_gethostbyname_r()</function> .
+<parameter>buf</parameter> is a buffer of length
+<parameter>len</parameter> bytes which is used to store the
+<constant>h_name</constant>, <constant>h_aliases</constant>, and
+<constant>h_addr_list</constant> elements of the <type>struct
+hostent</type> returned in <parameter>resbuf</parameter>.
+Successful calls to <function>lwres_gethostbyname_r()</function>
+return <parameter>resbuf</parameter>,
+which is a pointer to the <type>struct hostent</type> it created.
+</para>
+
+<para>
+<function>lwres_gethostbyaddr_r()</function> is a thread-safe function
+that performs a reverse lookup of address <parameter>addr</parameter>
+which is <parameter>len</parameter> bytes long and is of protocol
+family <parameter>type</parameter> &mdash; <type>PF_INET</type> or
+<type>PF_INET6</type>. If an error occurs, the error code is returned
+in <parameter>*error</parameter>. The other function parameters are
+identical to those in <function>lwres_gethostbyname_r()</function>.
+<parameter>resbuf</parameter> is a pointer to a <type>struct
+hostent</type> which is initialised by a successful call to
+<function>lwres_gethostbyaddr_r()</function>.
+<parameter>buf</parameter> is a buffer of length
+<parameter>len</parameter> bytes which is used to store the
+<constant>h_name</constant>, <constant>h_aliases</constant>, and
+<constant>h_addr_list</constant> elements of the <type>struct
+hostent</type> returned in <parameter>resbuf</parameter>. Successful
+calls to <function>lwres_gethostbyaddr_r()</function> return
+<parameter>resbuf</parameter>, which is a pointer to the
+<function>struct hostent()</function> it created.
+</para>
+
+</refsect1>
+
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+The functions
+<function>lwres_gethostbyname()</function>,
+<function>lwres_gethostbyname2()</function>,
+<function>lwres_gethostbyaddr()</function>,
+and
+<function>lwres_gethostent()</function>
+return NULL to indicate an error. In this case the global variable
+<type>lwres_h_errno</type>
+will contain one of the following error codes defined in
+<filename>&lt;lwres/netdb.h&gt;</filename>:
+
+<variablelist>
+<varlistentry><term><constant>HOST_NOT_FOUND</constant></term>
+<listitem>
+<para>
+The host or address was not found.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>TRY_AGAIN</constant></term>
+<listitem>
+<para>
+A recoverable error occurred, e.g., a timeout.
+Retrying the lookup may succeed.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>NO_RECOVERY</constant></term>
+<listitem>
+<para>
+A non-recoverable error occurred.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>NO_DATA</constant></term>
+<listitem>
+<para>
+The name exists, but has no address information
+associated with it (or vice versa in the case
+of a reverse lookup). The code NO_ADDRESS
+is accepted as a synonym for NO_DATA for backwards
+compatibility.
+</para>
+</listitem></varlistentry>
+</variablelist>
+</para>
+
+<para>
+<citerefentry>
+<refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3
+</manvolnum>
+</citerefentry>
+translates these error codes to suitable error messages.
+</para>
+
+<para>
+<function>lwres_gethostent()</function>
+and
+<function>lwres_gethostent_r()</function>
+always return
+<type>NULL</type>.
+</para>
+
+<para>
+Successful calls to <function>lwres_gethostbyname_r()</function> and
+<function>lwres_gethostbyaddr_r()</function> return
+<parameter>resbuf</parameter>, a pointer to the <type>struct
+hostent</type> that was initialised by these functions. They return
+<type>NULL</type> if the lookups fail or if <parameter>buf</parameter>
+was too small to hold the list of addresses and names referenced by
+the <constant>h_name</constant>, <constant>h_aliases</constant>, and
+<constant>h_addr_list</constant> elements of the <type>struct
+hostent</type>. If <parameter>buf</parameter> was too small, both
+<function>lwres_gethostbyname_r()</function> and
+<function>lwres_gethostbyaddr_r()</function> set the global variable
+<type>errno</type> to <errorcode>ERANGE</errorcode>.
+</para>
+
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>gethostent</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_getipnode</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3
+</manvolnum>
+</citerefentry>
+</para>
+</refsect1>
+
+<refsect1>
+<title>BUGS</title>
+<para>
+<function>lwres_gethostbyname()</function>,
+<function>lwres_gethostbyname2()</function>,
+<function>lwres_gethostbyaddr()</function>
+and
+<function>lwres_endhostent()</function>
+are not thread safe; they return pointers to static data and
+provide error codes through a global variable.
+Thread-safe versions for name and address lookup are provided by
+<function>lwres_gethostbyname_r()</function>,
+and
+<function>lwres_gethostbyaddr_r()</function>
+respectively.
+</para>
+<para>
+The resolver daemon does not currently support any non-DNS
+name services such as
+<filename>/etc/hosts</filename>
+or
+<type>NIS</type>,
+consequently the above functions don't, either.
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_gethostent.html b/lib/liblwres/man/lwres_gethostent.html
new file mode 100644
index 000000000..28671b86b
--- /dev/null
+++ b/lib/liblwres/man/lwres_gethostent.html
@@ -0,0 +1,827 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_gethostent</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_gethostent</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_gethostbyname, lwres_gethostbyname2, lwres_gethostbyaddr, lwres_gethostent, lwres_sethostent, lwres_endhostent, lwres_gethostbyname_r, lwres_gethostbyaddr_r, lwres_gethostent_r, lwres_sethostent_r, lwres_endhostent_r&nbsp;--&nbsp;lightweight resolver get network host entry</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN21"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN22"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/netdb.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>struct hostent *
+lwres_gethostbyname</CODE
+>(const char *name);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>struct hostent *
+lwres_gethostbyname2</CODE
+>(const char *name, int af);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>struct hostent *
+lwres_gethostbyaddr</CODE
+>(const char *addr, int len, int type);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>struct hostent *
+lwres_gethostent</CODE
+>(void);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_sethostent</CODE
+>(int stayopen);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_endhostent</CODE
+>(void);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>struct hostent *
+lwres_gethostbyname_r</CODE
+>(const char *name, struct hostent *resbuf, char *buf, int buflen, int *error);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>struct hostent *
+lwres_gethostbyaddr_r</CODE
+>(const char *addr, int len, int type, struct hostent *resbuf, char *buf, int buflen, int *error);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>struct hostent *
+lwres_gethostent_r</CODE
+>(struct hostent *resbuf, char *buf, int buflen, int *error);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_sethostent_r</CODE
+>(int stayopen);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_endhostent_r</CODE
+>(void);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN84"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>These functions provide hostname-to-address and
+address-to-hostname lookups by means of the lightweight resolver.
+They are similar to the standard
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>gethostent</SPAN
+>(3)</SPAN
+>
+functions provided by most operating systems.
+They use a
+<SPAN
+CLASS="TYPE"
+>struct hostent</SPAN
+>
+which is usually defined in
+<TT
+CLASS="FILENAME"
+>&lt;namedb.h&gt;</TT
+>.
+
+<PRE
+CLASS="PROGRAMLISTING"
+>struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+};
+#define h_addr h_addr_list[0] /* address, for backward compatibility */</PRE
+></P
+><P
+>The members of this structure are:
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>h_name</TT
+></DT
+><DD
+><P
+>The official (canonical) name of the host.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>h_aliases</TT
+></DT
+><DD
+><P
+>A NULL-terminated array of alternate names (nicknames) for the host.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>h_addrtype</TT
+></DT
+><DD
+><P
+>The type of address being returned &mdash;
+<SPAN
+CLASS="TYPE"
+>PF_INET</SPAN
+>
+or
+<SPAN
+CLASS="TYPE"
+>PF_INET6</SPAN
+>.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>h_length</TT
+></DT
+><DD
+><P
+>The length of the address in bytes.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>h_addr_list</TT
+></DT
+><DD
+><P
+>A <SPAN
+CLASS="TYPE"
+>NULL</SPAN
+>
+terminated array of network addresses for the host.
+Host addresses are returned in network byte order.</P
+></DD
+></DL
+></DIV
+></P
+><P
+>For backward compatibility with very old software,
+<TT
+CLASS="CONSTANT"
+>h_addr</TT
+>
+is the first address in
+<TT
+CLASS="CONSTANT"
+>h_addr_list.</TT
+></P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gethostent()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_sethostent()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_endhostent()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_gethostent_r()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_sethostent_r()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_endhostent_r()</TT
+>
+provide iteration over the known host entries on systems that
+provide such functionality through facilities like
+<TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+>
+or NIS. The lightweight resolver does not currently implement
+these functions; it only provides them as stub functions that always
+return failure.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gethostbyname()</TT
+> and
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname2()</TT
+> look up the hostname
+<TT
+CLASS="PARAMETER"
+><I
+>name</I
+></TT
+>.
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname()</TT
+> always looks for an IPv4
+address while <TT
+CLASS="FUNCTION"
+>lwres_gethostbyname2()</TT
+> looks for an
+address of protocol family <TT
+CLASS="PARAMETER"
+><I
+>af</I
+></TT
+>: either
+<SPAN
+CLASS="TYPE"
+>PF_INET</SPAN
+> or <SPAN
+CLASS="TYPE"
+>PF_INET6</SPAN
+> &mdash; IPv4 or IPV6
+addresses respectively. Successful calls of the functions return a
+<SPAN
+CLASS="TYPE"
+>struct hostent</SPAN
+>for the name that was looked up.
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+> is returned if the lookups by
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname()</TT
+> or
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname2()</TT
+> fail.</P
+><P
+>Reverse lookups of addresses are performed by
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyaddr()</TT
+>.
+<TT
+CLASS="PARAMETER"
+><I
+>addr</I
+></TT
+> is an address of length
+<TT
+CLASS="PARAMETER"
+><I
+>len</I
+></TT
+> bytes and protocol family
+<TT
+CLASS="PARAMETER"
+><I
+>type</I
+></TT
+> &mdash; <SPAN
+CLASS="TYPE"
+>PF_INET</SPAN
+> or
+<SPAN
+CLASS="TYPE"
+>PF_INET6</SPAN
+>.
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname_r()</TT
+> is a thread-safe function
+for forward lookups. If an error occurs, an error code is returned in
+<TT
+CLASS="PARAMETER"
+><I
+>*error</I
+></TT
+>.
+<TT
+CLASS="PARAMETER"
+><I
+>resbuf</I
+></TT
+> is a pointer to a <SPAN
+CLASS="TYPE"
+>struct
+hostent</SPAN
+> which is initialised by a successful call to
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname_r()</TT
+> .
+<TT
+CLASS="PARAMETER"
+><I
+>buf</I
+></TT
+> is a buffer of length
+<TT
+CLASS="PARAMETER"
+><I
+>len</I
+></TT
+> bytes which is used to store the
+<TT
+CLASS="CONSTANT"
+>h_name</TT
+>, <TT
+CLASS="CONSTANT"
+>h_aliases</TT
+>, and
+<TT
+CLASS="CONSTANT"
+>h_addr_list</TT
+> elements of the <SPAN
+CLASS="TYPE"
+>struct
+hostent</SPAN
+> returned in <TT
+CLASS="PARAMETER"
+><I
+>resbuf</I
+></TT
+>.
+Successful calls to <TT
+CLASS="FUNCTION"
+>lwres_gethostbyname_r()</TT
+>
+return <TT
+CLASS="PARAMETER"
+><I
+>resbuf</I
+></TT
+>,
+which is a pointer to the <SPAN
+CLASS="TYPE"
+>struct hostent</SPAN
+> it created.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gethostbyaddr_r()</TT
+> is a thread-safe function
+that performs a reverse lookup of address <TT
+CLASS="PARAMETER"
+><I
+>addr</I
+></TT
+>
+which is <TT
+CLASS="PARAMETER"
+><I
+>len</I
+></TT
+> bytes long and is of protocol
+family <TT
+CLASS="PARAMETER"
+><I
+>type</I
+></TT
+> &mdash; <SPAN
+CLASS="TYPE"
+>PF_INET</SPAN
+> or
+<SPAN
+CLASS="TYPE"
+>PF_INET6</SPAN
+>. If an error occurs, the error code is returned
+in <TT
+CLASS="PARAMETER"
+><I
+>*error</I
+></TT
+>. The other function parameters are
+identical to those in <TT
+CLASS="FUNCTION"
+>lwres_gethostbyname_r()</TT
+>.
+<TT
+CLASS="PARAMETER"
+><I
+>resbuf</I
+></TT
+> is a pointer to a <SPAN
+CLASS="TYPE"
+>struct
+hostent</SPAN
+> which is initialised by a successful call to
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyaddr_r()</TT
+>.
+<TT
+CLASS="PARAMETER"
+><I
+>buf</I
+></TT
+> is a buffer of length
+<TT
+CLASS="PARAMETER"
+><I
+>len</I
+></TT
+> bytes which is used to store the
+<TT
+CLASS="CONSTANT"
+>h_name</TT
+>, <TT
+CLASS="CONSTANT"
+>h_aliases</TT
+>, and
+<TT
+CLASS="CONSTANT"
+>h_addr_list</TT
+> elements of the <SPAN
+CLASS="TYPE"
+>struct
+hostent</SPAN
+> returned in <TT
+CLASS="PARAMETER"
+><I
+>resbuf</I
+></TT
+>. Successful
+calls to <TT
+CLASS="FUNCTION"
+>lwres_gethostbyaddr_r()</TT
+> return
+<TT
+CLASS="PARAMETER"
+><I
+>resbuf</I
+></TT
+>, which is a pointer to the
+<TT
+CLASS="FUNCTION"
+>struct hostent()</TT
+> it created.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN191"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+>The functions
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname2()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyaddr()</TT
+>,
+and
+<TT
+CLASS="FUNCTION"
+>lwres_gethostent()</TT
+>
+return NULL to indicate an error. In this case the global variable
+<SPAN
+CLASS="TYPE"
+>lwres_h_errno</SPAN
+>
+will contain one of the following error codes defined in
+<TT
+CLASS="FILENAME"
+>&lt;lwres/netdb.h&gt;</TT
+>:
+
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>HOST_NOT_FOUND</TT
+></DT
+><DD
+><P
+>The host or address was not found.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>TRY_AGAIN</TT
+></DT
+><DD
+><P
+>A recoverable error occurred, e.g., a timeout.
+Retrying the lookup may succeed.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>NO_RECOVERY</TT
+></DT
+><DD
+><P
+>A non-recoverable error occurred.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>NO_DATA</TT
+></DT
+><DD
+><P
+>The name exists, but has no address information
+associated with it (or vice versa in the case
+of a reverse lookup). The code NO_ADDRESS
+is accepted as a synonym for NO_DATA for backwards
+compatibility.</P
+></DD
+></DL
+></DIV
+></P
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_hstrerror</SPAN
+>(3)</SPAN
+>
+translates these error codes to suitable error messages.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gethostent()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_gethostent_r()</TT
+>
+always return
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+>.</P
+><P
+>Successful calls to <TT
+CLASS="FUNCTION"
+>lwres_gethostbyname_r()</TT
+> and
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyaddr_r()</TT
+> return
+<TT
+CLASS="PARAMETER"
+><I
+>resbuf</I
+></TT
+>, a pointer to the <SPAN
+CLASS="TYPE"
+>struct
+hostent</SPAN
+> that was initialised by these functions. They return
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+> if the lookups fail or if <TT
+CLASS="PARAMETER"
+><I
+>buf</I
+></TT
+>
+was too small to hold the list of addresses and names referenced by
+the <TT
+CLASS="CONSTANT"
+>h_name</TT
+>, <TT
+CLASS="CONSTANT"
+>h_aliases</TT
+>, and
+<TT
+CLASS="CONSTANT"
+>h_addr_list</TT
+> elements of the <SPAN
+CLASS="TYPE"
+>struct
+hostent</SPAN
+>. If <TT
+CLASS="PARAMETER"
+><I
+>buf</I
+></TT
+> was too small, both
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname_r()</TT
+> and
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyaddr_r()</TT
+> set the global variable
+<SPAN
+CLASS="TYPE"
+>errno</SPAN
+> to <SPAN
+CLASS="ERRORCODE"
+>ERANGE</SPAN
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN245"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>gethostent</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_getipnode</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_hstrerror</SPAN
+>(3)</SPAN
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN257"
+></A
+><H2
+>BUGS</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gethostbyname()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname2()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyaddr()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_endhostent()</TT
+>
+are not thread safe; they return pointers to static data and
+provide error codes through a global variable.
+Thread-safe versions for name and address lookup are provided by
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyname_r()</TT
+>,
+and
+<TT
+CLASS="FUNCTION"
+>lwres_gethostbyaddr_r()</TT
+>
+respectively.</P
+><P
+>The resolver daemon does not currently support any non-DNS
+name services such as
+<TT
+CLASS="FILENAME"
+>/etc/hosts</TT
+>
+or
+<SPAN
+CLASS="TYPE"
+>NIS</SPAN
+>,
+consequently the above functions don't, either.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_getipnode.3 b/lib/liblwres/man/lwres_getipnode.3
new file mode 100644
index 000000000..39dfc984a
--- /dev/null
+++ b/lib/liblwres/man/lwres_getipnode.3
@@ -0,0 +1,187 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_GETIPNODE" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_getipnodebyname, lwres_getipnodebyaddr, lwres_freehostent \- lightweight resolver nodename / address translation API
+.SH SYNOPSIS
+\fB#include <lwres/netdb.h>
+.sp
+.na
+struct hostent *
+lwres_getipnodebyname(const char *name, int af, int flags, int *error_num);
+.ad
+.sp
+.na
+struct hostent *
+lwres_getipnodebyaddr(const void *src, size_t len, int af, int *error_num);
+.ad
+.sp
+.na
+void
+lwres_freehostent(struct hostent *he);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+These functions perform thread safe, protocol independent
+nodename-to-address and address-to-nodename
+translation as defined in RFC2553.
+.PP
+They use a
+\fBstruct hostent\fR
+which is defined in
+\fInamedb.h\fR:
+.sp
+.nf
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+};
+#define h_addr h_addr_list[0] /* address, for backward compatibility */
+.sp
+.fi
+.PP
+The members of this structure are:
+.TP
+\fBh_name\fR
+The official (canonical) name of the host.
+.TP
+\fBh_aliases\fR
+A NULL-terminated array of alternate names (nicknames) for the host.
+.TP
+\fBh_addrtype\fR
+The type of address being returned - usually
+\fBPF_INET\fR
+or
+\fBPF_INET6\fR.
+.TP
+\fBh_length\fR
+The length of the address in bytes.
+.TP
+\fBh_addr_list\fR
+A
+\fBNULL\fR
+terminated array of network addresses for the host.
+Host addresses are returned in network byte order.
+.PP
+\fBlwres_getipnodebyname()\fR
+looks up addresses of protocol family
+\fIaf\fR
+for the hostname
+\fIname\fR.
+The
+\fIflags\fR
+parameter contains ORed flag bits to
+specify the types of addresses that are searched
+for, and the types of addresses that are returned.
+The flag bits are:
+.TP
+\fBAI_V4MAPPED\fR
+This is used with an
+\fIaf\fR
+of AF_INET6, and causes IPv4 addresses to be returned as IPv4-mapped
+IPv6 addresses.
+.TP
+\fBAI_ALL\fR
+This is used with an
+\fIaf\fR
+of AF_INET6, and causes all known addresses (IPv6 and IPv4) to be returned.
+If AI_V4MAPPED is also set, the IPv4 addresses are return as mapped
+IPv6 addresses.
+.TP
+\fBAI_ADDRCONFIG\fR
+Only return an IPv6 or IPv4 address if here is an active network
+interface of that type. This is not currently implemented
+in the BIND 9 lightweight resolver, and the flag is ignored.
+.TP
+\fBAI_DEFAULT\fR
+This default sets the
+AI_V4MAPPED
+and
+AI_ADDRCONFIG
+flag bits.
+.PP
+\fBlwres_getipnodebyaddr()\fR
+performs a reverse lookup
+of address
+\fIsrc\fR
+which is
+\fIlen\fR
+bytes long.
+\fIaf\fR
+denotes the protocol family, typically
+\fBPF_INET\fR
+or
+\fBPF_INET6\fR.
+.PP
+\fBlwres_freehostent()\fR
+releases all the memory associated with
+the
+\fBstruct hostent\fR
+pointer
+\fIhe\fR.
+Any memory allocated for the
+h_name,
+h_addr_list
+and
+h_aliases
+is freed, as is the memory for the
+\fBhostent\fR
+structure itself.
+.SH "RETURN VALUES"
+.PP
+If an error occurs,
+\fBlwres_getipnodebyname()\fR
+and
+\fBlwres_getipnodebyaddr()\fR
+set
+\fI*error_num\fR
+to an approriate error code and the function returns a
+\fBNULL\fR
+pointer.
+The error codes and their meanings are defined in
+\fI<lwres/netdb.h>\fR:
+.TP
+\fBHOST_NOT_FOUND\fR
+No such host is known.
+.TP
+\fBNO_ADDRESS\fR
+The server recognised the request and the name but no address is
+available. Another type of request to the name server for the
+domain might return an answer.
+.TP
+\fBTRY_AGAIN\fR
+A temporary and possibly transient error occurred, such as a
+failure of a server to respond. The request may succeed if
+retried.
+.TP
+\fBNO_RECOVERY\fR
+An unexpected failure occurred, and retrying the request
+is pointless.
+.PP
+\fBlwres_hstrerror\fR(3)
+translates these error codes to suitable error messages.
+.SH "SEE ALSO"
+.PP
+\fBRFC2553\fR,
+\fBlwres\fR(3),
+\fBlwres_gethostent\fR(3),
+\fBlwres_getaddrinfo\fR(3),
+\fBlwres_getnameinfo\fR(3),
+\fBlwres_hstrerror\fR(3).
diff --git a/lib/liblwres/man/lwres_getipnode.docbook b/lib/liblwres/man/lwres_getipnode.docbook
new file mode 100644
index 000000000..3d4fa7f15
--- /dev/null
+++ b/lib/liblwres/man/lwres_getipnode.docbook
@@ -0,0 +1,307 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_getipnode.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_getipnode</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_getipnodebyname</refname>
+<refname>lwres_getipnodebyaddr</refname>
+<refname>lwres_freehostent</refname>
+<refpurpose>lightweight resolver nodename / address translation API</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+struct hostent *
+<function>lwres_getipnodebyname</function></funcdef>
+<paramdef>const char *name</paramdef>
+<paramdef>int af</paramdef>
+<paramdef>int flags</paramdef>
+<paramdef>int *error_num</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+struct hostent *
+<function>lwres_getipnodebyaddr</function></funcdef>
+<paramdef>const void *src</paramdef>
+<paramdef>size_t len</paramdef>
+<paramdef>int af</paramdef>
+<paramdef>int *error_num</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_freehostent</function></funcdef>
+<paramdef>struct hostent *he</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+
+<para>
+These functions perform thread safe, protocol independent
+nodename-to-address and address-to-nodename
+translation as defined in RFC2553.
+</para>
+
+<para>
+They use a
+<type>struct hostent</type>
+which is defined in
+<filename>namedb.h</filename>:
+<programlisting>
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+};
+#define h_addr h_addr_list[0] /* address, for backward compatibility */
+</programlisting>
+</para>
+
+<para>
+The members of this structure are:
+<variablelist>
+<varlistentry><term><constant>h_name</constant></term>
+<listitem>
+<para>
+The official (canonical) name of the host.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>h_aliases</constant></term>
+<listitem>
+<para>
+A NULL-terminated array of alternate names (nicknames) for the host.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>h_addrtype</constant></term>
+<listitem>
+<para>
+The type of address being returned - usually
+<type>PF_INET</type>
+or
+<type>PF_INET6</type>.
+
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>h_length</constant></term>
+<listitem>
+<para>
+The length of the address in bytes.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>h_addr_list</constant></term>
+<listitem>
+<para>
+A
+<type>NULL</type>
+terminated array of network addresses for the host.
+Host addresses are returned in network byte order.
+</para>
+</listitem></varlistentry>
+</variablelist>
+</para>
+<para>
+<function>lwres_getipnodebyname()</function>
+looks up addresses of protocol family
+<parameter>af</parameter>
+
+for the hostname
+<parameter>name</parameter>.
+
+The
+<parameter>flags</parameter>
+parameter contains ORed flag bits to
+specify the types of addresses that are searched
+for, and the types of addresses that are returned.
+The flag bits are:
+<variablelist>
+<varlistentry><term><constant>AI_V4MAPPED</constant></term>
+<listitem>
+<para>
+This is used with an
+<parameter>af</parameter>
+of AF_INET6, and causes IPv4 addresses to be returned as IPv4-mapped
+IPv6 addresses.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>AI_ALL</constant></term>
+<listitem>
+<para>
+This is used with an
+<parameter>af</parameter>
+of AF_INET6, and causes all known addresses (IPv6 and IPv4) to be returned.
+If AI_V4MAPPED is also set, the IPv4 addresses are return as mapped
+IPv6 addresses.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>AI_ADDRCONFIG</constant></term>
+<listitem>
+<para>
+Only return an IPv6 or IPv4 address if here is an active network
+interface of that type. This is not currently implemented
+in the BIND 9 lightweight resolver, and the flag is ignored.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>AI_DEFAULT</constant></term>
+<listitem>
+<para>
+This default sets the
+<constant>AI_V4MAPPED</constant>
+and
+<constant>AI_ADDRCONFIG</constant>
+flag bits.
+</para>
+</listitem></varlistentry>
+</variablelist>
+</para>
+<para>
+<function>lwres_getipnodebyaddr()</function>
+performs a reverse lookup
+of address
+<parameter>src</parameter>
+which is
+<parameter>len</parameter>
+bytes long.
+<parameter>af</parameter>
+denotes the protocol family, typically
+<type>PF_INET</type>
+or
+<type>PF_INET6</type>.
+
+</para>
+<para>
+<function>lwres_freehostent()</function>
+releases all the memory associated with
+the
+<type>struct hostent</type>
+pointer
+<parameter>he</parameter>.
+
+Any memory allocated for the
+<constant>h_name</constant>,
+
+<constant>h_addr_list</constant>
+and
+<constant>h_aliases</constant>
+is freed, as is the memory for the
+<type>hostent</type>
+structure itself.
+</para>
+</refsect1>
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+If an error occurs,
+<function>lwres_getipnodebyname()</function>
+and
+<function>lwres_getipnodebyaddr()</function>
+set
+<parameter>*error_num</parameter>
+to an approriate error code and the function returns a
+<type>NULL</type>
+pointer.
+The error codes and their meanings are defined in
+<filename>&lt;lwres/netdb.h&gt;</filename>:
+<variablelist>
+<varlistentry><term><constant>HOST_NOT_FOUND</constant></term>
+<listitem>
+<para>
+No such host is known.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>NO_ADDRESS</constant></term>
+<listitem>
+<para>
+The server recognised the request and the name but no address is
+available. Another type of request to the name server for the
+domain might return an answer.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>TRY_AGAIN</constant></term>
+<listitem>
+<para>
+A temporary and possibly transient error occurred, such as a
+failure of a server to respond. The request may succeed if
+retried.
+</para>
+</listitem></varlistentry>
+<varlistentry><term><constant>NO_RECOVERY</constant></term>
+<listitem>
+<para>
+An unexpected failure occurred, and retrying the request
+is pointless.
+</para>
+</listitem></varlistentry>
+</variablelist>
+</para>
+<para>
+<citerefentry>
+<refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3
+</manvolnum>
+</citerefentry>
+translates these error codes to suitable error messages.
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>RFC2553</refentrytitle>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_gethostent</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_getaddrinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>.
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_getipnode.html b/lib/liblwres/man/lwres_getipnode.html
new file mode 100644
index 000000000..d0a71e69d
--- /dev/null
+++ b/lib/liblwres/man/lwres_getipnode.html
@@ -0,0 +1,529 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_getipnode</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_getipnode</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_getipnodebyname, lwres_getipnodebyaddr, lwres_freehostent&nbsp;--&nbsp;lightweight resolver nodename / address translation API</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN13"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN14"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/netdb.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>struct hostent *
+lwres_getipnodebyname</CODE
+>(const char *name, int af, int flags, int *error_num);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>struct hostent *
+lwres_getipnodebyaddr</CODE
+>(const void *src, size_t len, int af, int *error_num);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_freehostent</CODE
+>(struct hostent *he);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN34"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>These functions perform thread safe, protocol independent
+nodename-to-address and address-to-nodename
+translation as defined in RFC2553.</P
+><P
+>They use a
+<SPAN
+CLASS="TYPE"
+>struct hostent</SPAN
+>
+which is defined in
+<TT
+CLASS="FILENAME"
+>namedb.h</TT
+>:
+<PRE
+CLASS="PROGRAMLISTING"
+>struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+};
+#define h_addr h_addr_list[0] /* address, for backward compatibility */</PRE
+></P
+><P
+>The members of this structure are:
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>h_name</TT
+></DT
+><DD
+><P
+>The official (canonical) name of the host.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>h_aliases</TT
+></DT
+><DD
+><P
+>A NULL-terminated array of alternate names (nicknames) for the host.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>h_addrtype</TT
+></DT
+><DD
+><P
+>The type of address being returned - usually
+<SPAN
+CLASS="TYPE"
+>PF_INET</SPAN
+>
+or
+<SPAN
+CLASS="TYPE"
+>PF_INET6</SPAN
+>.&#13;</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>h_length</TT
+></DT
+><DD
+><P
+>The length of the address in bytes.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>h_addr_list</TT
+></DT
+><DD
+><P
+>A
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+>
+terminated array of network addresses for the host.
+Host addresses are returned in network byte order.</P
+></DD
+></DL
+></DIV
+></P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getipnodebyname()</TT
+>
+looks up addresses of protocol family
+<TT
+CLASS="PARAMETER"
+><I
+>af</I
+></TT
+>
+
+for the hostname
+<TT
+CLASS="PARAMETER"
+><I
+>name</I
+></TT
+>.
+
+The
+<TT
+CLASS="PARAMETER"
+><I
+>flags</I
+></TT
+>
+parameter contains ORed flag bits to
+specify the types of addresses that are searched
+for, and the types of addresses that are returned.
+The flag bits are:
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>AI_V4MAPPED</TT
+></DT
+><DD
+><P
+>This is used with an
+<TT
+CLASS="PARAMETER"
+><I
+>af</I
+></TT
+>
+of AF_INET6, and causes IPv4 addresses to be returned as IPv4-mapped
+IPv6 addresses.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>AI_ALL</TT
+></DT
+><DD
+><P
+>This is used with an
+<TT
+CLASS="PARAMETER"
+><I
+>af</I
+></TT
+>
+of AF_INET6, and causes all known addresses (IPv6 and IPv4) to be returned.
+If AI_V4MAPPED is also set, the IPv4 addresses are return as mapped
+IPv6 addresses.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>AI_ADDRCONFIG</TT
+></DT
+><DD
+><P
+>Only return an IPv6 or IPv4 address if here is an active network
+interface of that type. This is not currently implemented
+in the BIND 9 lightweight resolver, and the flag is ignored.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>AI_DEFAULT</TT
+></DT
+><DD
+><P
+>This default sets the
+<TT
+CLASS="CONSTANT"
+>AI_V4MAPPED</TT
+>
+and
+<TT
+CLASS="CONSTANT"
+>AI_ADDRCONFIG</TT
+>
+flag bits.</P
+></DD
+></DL
+></DIV
+></P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getipnodebyaddr()</TT
+>
+performs a reverse lookup
+of address
+<TT
+CLASS="PARAMETER"
+><I
+>src</I
+></TT
+>
+which is
+<TT
+CLASS="PARAMETER"
+><I
+>len</I
+></TT
+>
+bytes long.
+<TT
+CLASS="PARAMETER"
+><I
+>af</I
+></TT
+>
+denotes the protocol family, typically
+<SPAN
+CLASS="TYPE"
+>PF_INET</SPAN
+>
+or
+<SPAN
+CLASS="TYPE"
+>PF_INET6</SPAN
+>.&#13;</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_freehostent()</TT
+>
+releases all the memory associated with
+the
+<SPAN
+CLASS="TYPE"
+>struct hostent</SPAN
+>
+pointer
+<TT
+CLASS="PARAMETER"
+><I
+>he</I
+></TT
+>.
+
+Any memory allocated for the
+<TT
+CLASS="CONSTANT"
+>h_name</TT
+>,
+
+<TT
+CLASS="CONSTANT"
+>h_addr_list</TT
+>
+and
+<TT
+CLASS="CONSTANT"
+>h_aliases</TT
+>
+is freed, as is the memory for the
+<SPAN
+CLASS="TYPE"
+>hostent</SPAN
+>
+structure itself.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN116"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+>If an error occurs,
+<TT
+CLASS="FUNCTION"
+>lwres_getipnodebyname()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_getipnodebyaddr()</TT
+>
+set
+<TT
+CLASS="PARAMETER"
+><I
+>*error_num</I
+></TT
+>
+to an approriate error code and the function returns a
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+>
+pointer.
+The error codes and their meanings are defined in
+<TT
+CLASS="FILENAME"
+>&lt;lwres/netdb.h&gt;</TT
+>:
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>HOST_NOT_FOUND</TT
+></DT
+><DD
+><P
+>No such host is known.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>NO_ADDRESS</TT
+></DT
+><DD
+><P
+>The server recognised the request and the name but no address is
+available. Another type of request to the name server for the
+domain might return an answer.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>TRY_AGAIN</TT
+></DT
+><DD
+><P
+>A temporary and possibly transient error occurred, such as a
+failure of a server to respond. The request may succeed if
+retried.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>NO_RECOVERY</TT
+></DT
+><DD
+><P
+>An unexpected failure occurred, and retrying the request
+is pointless.</P
+></DD
+></DL
+></DIV
+></P
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_hstrerror</SPAN
+>(3)</SPAN
+>
+translates these error codes to suitable error messages.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN149"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>RFC2553</SPAN
+></SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_gethostent</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_getaddrinfo</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_getnameinfo</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_hstrerror</SPAN
+>(3)</SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_getnameinfo.3 b/lib/liblwres/man/lwres_getnameinfo.3
new file mode 100644
index 000000000..61f3ba426
--- /dev/null
+++ b/lib/liblwres/man/lwres_getnameinfo.3
@@ -0,0 +1,84 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_GETNAMEINFO" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_getnameinfo \- lightweight resolver socket address structure to hostname and service name
+.SH SYNOPSIS
+\fB#include <lwres/netdb.h>
+.sp
+.na
+int
+lwres_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+This function is equivalent to the \fBgetnameinfo\fR(3) function defined in RFC2133.
+\fBlwres_getnameinfo()\fR returns the hostname for the
+\fBstruct sockaddr\fR \fIsa\fR which is
+\fIsalen\fR bytes long. The hostname is of length
+\fIhostlen\fR and is returned via
+\fI*host.\fR The maximum length of the hostname is
+1025 bytes: NI_MAXHOST.
+.PP
+The name of the service associated with the port number in
+\fIsa\fR is returned in \fI*serv.\fR
+It is \fIservlen\fR bytes long. The maximum length
+of the service name is NI_MAXSERV - 32 bytes.
+.PP
+The \fIflags\fR argument sets the following
+bits:
+.TP
+\fBNI_NOFQDN\fR
+A fully qualified domain name is not required for local hosts.
+The local part of the fully qualified domain name is returned instead.
+.TP
+\fBNI_NUMERICHOST\fR
+Return the address in numeric form, as if calling inet_ntop(),
+instead of a host name.
+.TP
+\fBNI_NAMEREQD\fR
+A name is required. If the hostname cannot be found in the DNS and
+this flag is set, a non-zero error code is returned.
+If the hostname is not found and the flag is not set, the
+address is returned in numeric form.
+.TP
+\fBNI_NUMERICSERV\fR
+The service name is returned as a digit string representing the port number.
+.TP
+\fBNI_DGRAM\fR
+Specifies that the service being looked up is a datagram
+service, and causes getservbyport() to be called with a second
+argument of "udp" instead of its default of "tcp". This is required
+for the few ports (512-514) that have different services for UDP and
+TCP.
+.SH "RETURN VALUES"
+.PP
+\fBlwres_getnameinfo()\fR
+returns 0 on success or a non-zero error code if an error occurs.
+.SH "SEE ALSO"
+.PP
+\fBRFC2133\fR,
+\fBgetservbyport\fR(3),
+\fBlwres\fR(3),
+\fBlwres_getnameinfo\fR(3),
+\fBlwres_getnamebyaddr\fR(3).
+\fBlwres_net_ntop\fR(3).
+.SH "BUGS"
+.PP
+RFC2133 fails to define what the nonzero return values of
+\fBgetnameinfo\fR(3)
+are.
diff --git a/lib/liblwres/man/lwres_getnameinfo.docbook b/lib/liblwres/man/lwres_getnameinfo.docbook
new file mode 100644
index 000000000..56bcd8b9f
--- /dev/null
+++ b/lib/liblwres/man/lwres_getnameinfo.docbook
@@ -0,0 +1,154 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_getnameinfo.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_getnameinfo</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_getnameinfo</refname>
+<refpurpose>lightweight resolver socket address structure to hostname and service name</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+int
+<function>lwres_getnameinfo</function></funcdef>
+<paramdef>const struct sockaddr *sa</paramdef>
+<paramdef>size_t salen</paramdef>
+<paramdef>char *host</paramdef>
+<paramdef>size_t hostlen</paramdef>
+<paramdef>char *serv</paramdef>
+<paramdef>size_t servlen</paramdef>
+<paramdef>int flags</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+
+<para> This function is equivalent to the <citerefentry>
+<refentrytitle>getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry> function defined in RFC2133.
+<function>lwres_getnameinfo()</function> returns the hostname for the
+<type>struct sockaddr</type> <parameter>sa</parameter> which is
+<parameter>salen</parameter> bytes long. The hostname is of length
+<parameter>hostlen</parameter> and is returned via
+<parameter>*host.</parameter> The maximum length of the hostname is
+1025 bytes: <constant>NI_MAXHOST</constant>.</para>
+
+<para> The name of the service associated with the port number in
+<parameter>sa</parameter> is returned in <parameter>*serv.</parameter>
+It is <parameter>servlen</parameter> bytes long. The maximum length
+of the service name is <constant>NI_MAXSERV</constant> - 32 bytes.
+</para>
+
+<para> The <parameter>flags</parameter> argument sets the following
+bits:
+<variablelist>
+<varlistentry><term><constant>NI_NOFQDN</constant></term>
+<listitem>
+<para>
+A fully qualified domain name is not required for local hosts.
+The local part of the fully qualified domain name is returned instead.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>NI_NUMERICHOST</constant></term>
+<listitem>
+<para>
+Return the address in numeric form, as if calling inet_ntop(),
+instead of a host name.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>NI_NAMEREQD</constant></term>
+<listitem>
+<para>
+A name is required. If the hostname cannot be found in the DNS and
+this flag is set, a non-zero error code is returned.
+If the hostname is not found and the flag is not set, the
+address is returned in numeric form.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>NI_NUMERICSERV</constant></term>
+<listitem>
+<para>
+The service name is returned as a digit string representing the port number.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>NI_DGRAM</constant></term>
+<listitem>
+<para>
+Specifies that the service being looked up is a datagram
+service, and causes getservbyport() to be called with a second
+argument of "udp" instead of its default of "tcp". This is required
+for the few ports (512-514) that have different services for UDP and
+TCP.
+</para></listitem></varlistentry>
+</variablelist>
+</para>
+</refsect1>
+
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+<function>lwres_getnameinfo()</function>
+returns 0 on success or a non-zero error code if an error occurs.
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>RFC2133</refentrytitle>
+</citerefentry>,
+<citerefentry>
+<refentrytitle>getservbyport</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+<citerefentry>
+<refentrytitle>lwres</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+<citerefentry>
+<refentrytitle>lwres_getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+<citerefentry>
+<refentrytitle>lwres_getnamebyaddr</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>.
+<citerefentry>
+<refentrytitle>lwres_net_ntop</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>.
+</refsect1>
+<refsect1>
+<title>BUGS</title>
+<para>
+RFC2133 fails to define what the nonzero return values of
+<citerefentry>
+<refentrytitle>getnameinfo</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>
+are.
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_getnameinfo.html b/lib/liblwres/man/lwres_getnameinfo.html
new file mode 100644
index 000000000..b98a92848
--- /dev/null
+++ b/lib/liblwres/man/lwres_getnameinfo.html
@@ -0,0 +1,303 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_getnameinfo</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_getnameinfo</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_getnameinfo&nbsp;--&nbsp;lightweight resolver socket address structure to hostname and service name</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN11"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN12"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/netdb.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>int
+lwres_getnameinfo</CODE
+>(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN24"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+> This function is equivalent to the <SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>getnameinfo</SPAN
+>(3)</SPAN
+> function defined in RFC2133.
+<TT
+CLASS="FUNCTION"
+>lwres_getnameinfo()</TT
+> returns the hostname for the
+<SPAN
+CLASS="TYPE"
+>struct sockaddr</SPAN
+> <TT
+CLASS="PARAMETER"
+><I
+>sa</I
+></TT
+> which is
+<TT
+CLASS="PARAMETER"
+><I
+>salen</I
+></TT
+> bytes long. The hostname is of length
+<TT
+CLASS="PARAMETER"
+><I
+>hostlen</I
+></TT
+> and is returned via
+<TT
+CLASS="PARAMETER"
+><I
+>*host.</I
+></TT
+> The maximum length of the hostname is
+1025 bytes: <TT
+CLASS="CONSTANT"
+>NI_MAXHOST</TT
+>.</P
+><P
+> The name of the service associated with the port number in
+<TT
+CLASS="PARAMETER"
+><I
+>sa</I
+></TT
+> is returned in <TT
+CLASS="PARAMETER"
+><I
+>*serv.</I
+></TT
+>
+It is <TT
+CLASS="PARAMETER"
+><I
+>servlen</I
+></TT
+> bytes long. The maximum length
+of the service name is <TT
+CLASS="CONSTANT"
+>NI_MAXSERV</TT
+> - 32 bytes.</P
+><P
+> The <TT
+CLASS="PARAMETER"
+><I
+>flags</I
+></TT
+> argument sets the following
+bits:
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>NI_NOFQDN</TT
+></DT
+><DD
+><P
+>A fully qualified domain name is not required for local hosts.
+The local part of the fully qualified domain name is returned instead.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>NI_NUMERICHOST</TT
+></DT
+><DD
+><P
+>Return the address in numeric form, as if calling inet_ntop(),
+instead of a host name.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>NI_NAMEREQD</TT
+></DT
+><DD
+><P
+>A name is required. If the hostname cannot be found in the DNS and
+this flag is set, a non-zero error code is returned.
+If the hostname is not found and the flag is not set, the
+address is returned in numeric form.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>NI_NUMERICSERV</TT
+></DT
+><DD
+><P
+>The service name is returned as a digit string representing the port number.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>NI_DGRAM</TT
+></DT
+><DD
+><P
+>Specifies that the service being looked up is a datagram
+service, and causes getservbyport() to be called with a second
+argument of "udp" instead of its default of "tcp". This is required
+for the few ports (512-514) that have different services for UDP and
+TCP.</P
+></DD
+></DL
+></DIV
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN70"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getnameinfo()</TT
+>
+returns 0 on success or a non-zero error code if an error occurs.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN74"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>RFC2133</SPAN
+></SPAN
+>,
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>getservbyport</SPAN
+>(3)</SPAN
+>,
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres</SPAN
+>(3)</SPAN
+>,
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_getnameinfo</SPAN
+>(3)</SPAN
+>,
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_getnamebyaddr</SPAN
+>(3)</SPAN
+>.
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_net_ntop</SPAN
+>(3)</SPAN
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN94"
+></A
+><H2
+>BUGS</H2
+><P
+>RFC2133 fails to define what the nonzero return values of
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>getnameinfo</SPAN
+>(3)</SPAN
+>
+are.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_getrrsetbyname.3 b/lib/liblwres/man/lwres_getrrsetbyname.3
new file mode 100644
index 000000000..301630e23
--- /dev/null
+++ b/lib/liblwres/man/lwres_getrrsetbyname.3
@@ -0,0 +1,142 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_GETRRSETBYNAME" "3" "Oct 18, 2000" "BIND9" ""
+.SH NAME
+lwres_getrrsetbyname, lwres_freerrset \- retrieve DNS records
+.SH SYNOPSIS
+\fB#include <lwres/netdb.h>
+.sp
+.na
+int
+lwres_getrrsetbyname(const char *hostname, unsigned int rdclass, unsigned int rdtype, unsigned int flags, struct rrsetinfo **res);
+.ad
+.sp
+.na
+void
+lwres_freerrset(struct rrsetinfo *rrset);
+.ad
+\fR.PP
+The following structures are used:
+.sp
+.nf
+struct rdatainfo {
+ unsigned int rdi_length; /* length of data */
+ unsigned char *rdi_data; /* record data */
+};
+
+struct rrsetinfo {
+ unsigned int rri_flags; /* RRSET_VALIDATED... */
+ unsigned int rri_rdclass; /* class number */
+ unsigned int rri_rdtype; /* RR type number */
+ unsigned int rri_ttl; /* time to live */
+ unsigned int rri_nrdatas; /* size of rdatas array */
+ unsigned int rri_nsigs; /* size of sigs array */
+ char *rri_name; /* canonical name */
+ struct rdatainfo *rri_rdatas; /* individual records */
+ struct rdatainfo *rri_sigs; /* individual signatures */
+};
+.sp
+.fi
+.SH "DESCRIPTION"
+.PP
+\fBlwres_getrrsetbyname()\fR
+gets a set of resource records associated with a
+\fIhostname\fR,
+\fIclass\fR,
+and
+\fItype\fR.
+\fIhostname\fR
+is
+a pointer a to null-terminated string. The
+\fIflags\fR
+field is currently unused and must be zero.
+.PP
+After a successful call to
+\fBlwres_getrrsetbyname()\fR,
+\fI*res\fR
+is a pointer to an
+\fBrrsetinfo\fR
+structure, containing a list of one or more
+\fBrdatainfo\fR
+structures containing resource records and potentially another list of
+\fBrdatainfo\fR
+structures containing SIG resource records
+associated with those records.
+The members
+rri_rdclass
+and
+rri_rdtype
+are copied from the parameters.
+rri_ttl
+and
+rri_name
+are properties of the obtained rrset.
+The resource records contained in
+rri_rdatas
+and
+rri_sigs
+are in uncompressed DNS wire format.
+Properties of the rdataset are represented in the
+rri_flags
+bitfield. If the RRSET_VALIDATED bit is set, the data has been DNSSEC
+validated and the signatures verified.
+.PP
+All of the information returned by
+\fBlwres_getrrsetbyname()\fR
+is dynamically allocated: the
+rrsetinfo
+and
+rdatainfo
+structures,
+and the canonical host name strings pointed to by the
+rrsetinfostructure.
+Memory allocated for the dynamically allocated structures created by
+a successful call to
+\fBlwres_getrrsetbyname()\fR
+is released by
+\fBlwres_freerrset()\fR.
+\fIrrset\fR
+is a pointer to a
+\fBstruct rrset\fR
+created by a call to
+\fBlwres_getrrsetbyname()\fR.
+.PP
+.SH "RETURN VALUES"
+.PP
+\fBlwres_getrrsetbyname()\fR
+returns zero on success, and one of the following error
+codes if an error occurred:
+.TP
+\fBERRSET_NONAME\fR
+the name does not exist
+.TP
+\fBERRSET_NODATA\fR
+the name exists, but does not have data of the desired type
+.TP
+\fBERRSET_NOMEMORY\fR
+memory could not be allocated
+.TP
+\fBERRSET_INVAL\fR
+a parameter is invalid
+.TP
+\fBERRSET_FAIL\fR
+other failure
+.TP
+\fB\fR
+.SH "SEE ALSO"
+.PP
+\fBlwres\fR(3).
diff --git a/lib/liblwres/man/lwres_getrrsetbyname.docbook b/lib/liblwres/man/lwres_getrrsetbyname.docbook
new file mode 100644
index 000000000..9151c9c57
--- /dev/null
+++ b/lib/liblwres/man/lwres_getrrsetbyname.docbook
@@ -0,0 +1,208 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_getrrsetbyname.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+<refentryinfo>
+
+
+<date>Oct 18, 2000</date>
+</refentryinfo>
+<refmeta>
+<refentrytitle>lwres_getrrsetbyname</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+<refnamediv>
+<refname>lwres_getrrsetbyname</refname>
+<refname>lwres_freerrset</refname>
+<refpurpose>retrieve DNS records</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+int
+<function>lwres_getrrsetbyname</function></funcdef>
+<paramdef>const char *hostname</paramdef>
+<paramdef>unsigned int rdclass</paramdef>
+<paramdef>unsigned int rdtype</paramdef>
+<paramdef>unsigned int flags</paramdef>
+<paramdef>struct rrsetinfo **res</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_freerrset</function></funcdef>
+<paramdef>struct rrsetinfo *rrset</paramdef>
+</funcprototype>
+</funcsynopsis>
+
+<para>
+The following structures are used:
+<programlisting>
+struct rdatainfo {
+ unsigned int rdi_length; /* length of data */
+ unsigned char *rdi_data; /* record data */
+};
+
+struct rrsetinfo {
+ unsigned int rri_flags; /* RRSET_VALIDATED... */
+ unsigned int rri_rdclass; /* class number */
+ unsigned int rri_rdtype; /* RR type number */
+ unsigned int rri_ttl; /* time to live */
+ unsigned int rri_nrdatas; /* size of rdatas array */
+ unsigned int rri_nsigs; /* size of sigs array */
+ char *rri_name; /* canonical name */
+ struct rdatainfo *rri_rdatas; /* individual records */
+ struct rdatainfo *rri_sigs; /* individual signatures */
+};
+</programlisting>
+</para>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+<function>lwres_getrrsetbyname()</function>
+gets a set of resource records associated with a
+<parameter>hostname</parameter>,
+
+<parameter>class</parameter>,
+
+and
+<parameter>type</parameter>.
+
+<parameter>hostname</parameter>
+is
+a pointer a to null-terminated string. The
+<parameter>flags</parameter>
+field is currently unused and must be zero.
+</para>
+<para>
+After a successful call to
+<function>lwres_getrrsetbyname()</function>,
+
+<parameter>*res</parameter>
+is a pointer to an
+<type>rrsetinfo</type>
+structure, containing a list of one or more
+<type>rdatainfo</type>
+structures containing resource records and potentially another list of
+<type>rdatainfo</type>
+structures containing SIG resource records
+associated with those records.
+The members
+<constant>rri_rdclass</constant>
+and
+<constant>rri_rdtype</constant>
+are copied from the parameters.
+<constant>rri_ttl</constant>
+and
+<constant>rri_name</constant>
+are properties of the obtained rrset.
+The resource records contained in
+<constant>rri_rdatas</constant>
+and
+<constant>rri_sigs</constant>
+are in uncompressed DNS wire format.
+Properties of the rdataset are represented in the
+<constant>rri_flags</constant>
+bitfield. If the RRSET_VALIDATED bit is set, the data has been DNSSEC
+validated and the signatures verified.
+</para>
+<para>
+All of the information returned by
+<function>lwres_getrrsetbyname()</function>
+is dynamically allocated: the
+<constant>rrsetinfo</constant>
+and
+<constant>rdatainfo</constant>
+structures,
+and the canonical host name strings pointed to by the
+<constant>rrsetinfo</constant>structure.
+
+Memory allocated for the dynamically allocated structures created by
+a successful call to
+<function>lwres_getrrsetbyname()</function>
+is released by
+<function>lwres_freerrset()</function>.
+
+<parameter>rrset</parameter>
+is a pointer to a
+<type>struct rrset</type>
+created by a call to
+<function>lwres_getrrsetbyname()</function>.
+
+</para>
+<para>
+</para>
+</refsect1>
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+<function>lwres_getrrsetbyname()</function>
+returns zero on success, and one of the following error
+codes if an error occurred:
+<variablelist>
+
+<varlistentry><term><constant>ERRSET_NONAME</constant></term>
+<listitem><para>
+the name does not exist
+</para></listitem></varlistentry>
+
+<varlistentry><term><constant>ERRSET_NODATA</constant></term>
+<listitem><para>
+the name exists, but does not have data of the desired type
+</para></listitem></varlistentry>
+
+<varlistentry><term><constant>ERRSET_NOMEMORY</constant></term>
+<listitem><para>
+memory could not be allocated
+</para></listitem></varlistentry>
+
+<varlistentry><term><constant>ERRSET_INVAL</constant></term>
+<listitem><para>
+a parameter is invalid
+</para></listitem></varlistentry>
+
+<varlistentry><term><constant>ERRSET_FAIL</constant></term>
+<listitem><para>
+other failure
+</para></listitem></varlistentry>
+
+<varlistentry><term><constant></constant></term>
+<listitem><para>
+</para></listitem></varlistentry>
+
+</variablelist>
+
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>lwres</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>.
+</para>
+
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_getrrsetbyname.html b/lib/liblwres/man/lwres_getrrsetbyname.html
new file mode 100644
index 000000000..3e5ab615c
--- /dev/null
+++ b/lib/liblwres/man/lwres_getrrsetbyname.html
@@ -0,0 +1,371 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_getrrsetbyname</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_getrrsetbyname</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_getrrsetbyname, lwres_freerrset&nbsp;--&nbsp;retrieve DNS records</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN12"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN13"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/netdb.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>int
+lwres_getrrsetbyname</CODE
+>(const char *hostname, unsigned int rdclass, unsigned int rdtype, unsigned int flags, struct rrsetinfo **res);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_freerrset</CODE
+>(struct rrsetinfo *rrset);</CODE
+></P
+><P
+></P
+></DIV
+><P
+>The following structures are used:
+<PRE
+CLASS="PROGRAMLISTING"
+>struct rdatainfo {
+ unsigned int rdi_length; /* length of data */
+ unsigned char *rdi_data; /* record data */
+};
+
+struct rrsetinfo {
+ unsigned int rri_flags; /* RRSET_VALIDATED... */
+ unsigned int rri_rdclass; /* class number */
+ unsigned int rri_rdtype; /* RR type number */
+ unsigned int rri_ttl; /* time to live */
+ unsigned int rri_nrdatas; /* size of rdatas array */
+ unsigned int rri_nsigs; /* size of sigs array */
+ char *rri_name; /* canonical name */
+ struct rdatainfo *rri_rdatas; /* individual records */
+ struct rdatainfo *rri_sigs; /* individual signatures */
+};</PRE
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN29"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getrrsetbyname()</TT
+>
+gets a set of resource records associated with a
+<TT
+CLASS="PARAMETER"
+><I
+>hostname</I
+></TT
+>,
+
+<TT
+CLASS="PARAMETER"
+><I
+>class</I
+></TT
+>,
+
+and
+<TT
+CLASS="PARAMETER"
+><I
+>type</I
+></TT
+>.
+
+<TT
+CLASS="PARAMETER"
+><I
+>hostname</I
+></TT
+>
+is
+a pointer a to null-terminated string. The
+<TT
+CLASS="PARAMETER"
+><I
+>flags</I
+></TT
+>
+field is currently unused and must be zero.</P
+><P
+>After a successful call to
+<TT
+CLASS="FUNCTION"
+>lwres_getrrsetbyname()</TT
+>,
+
+<TT
+CLASS="PARAMETER"
+><I
+>*res</I
+></TT
+>
+is a pointer to an
+<SPAN
+CLASS="TYPE"
+>rrsetinfo</SPAN
+>
+structure, containing a list of one or more
+<SPAN
+CLASS="TYPE"
+>rdatainfo</SPAN
+>
+structures containing resource records and potentially another list of
+<SPAN
+CLASS="TYPE"
+>rdatainfo</SPAN
+>
+structures containing SIG resource records
+associated with those records.
+The members
+<TT
+CLASS="CONSTANT"
+>rri_rdclass</TT
+>
+and
+<TT
+CLASS="CONSTANT"
+>rri_rdtype</TT
+>
+are copied from the parameters.
+<TT
+CLASS="CONSTANT"
+>rri_ttl</TT
+>
+and
+<TT
+CLASS="CONSTANT"
+>rri_name</TT
+>
+are properties of the obtained rrset.
+The resource records contained in
+<TT
+CLASS="CONSTANT"
+>rri_rdatas</TT
+>
+and
+<TT
+CLASS="CONSTANT"
+>rri_sigs</TT
+>
+are in uncompressed DNS wire format.
+Properties of the rdataset are represented in the
+<TT
+CLASS="CONSTANT"
+>rri_flags</TT
+>
+bitfield. If the RRSET_VALIDATED bit is set, the data has been DNSSEC
+validated and the signatures verified. </P
+><P
+>All of the information returned by
+<TT
+CLASS="FUNCTION"
+>lwres_getrrsetbyname()</TT
+>
+is dynamically allocated: the
+<TT
+CLASS="CONSTANT"
+>rrsetinfo</TT
+>
+and
+<TT
+CLASS="CONSTANT"
+>rdatainfo</TT
+>
+structures,
+and the canonical host name strings pointed to by the
+<TT
+CLASS="CONSTANT"
+>rrsetinfo</TT
+>structure.
+
+Memory allocated for the dynamically allocated structures created by
+a successful call to
+<TT
+CLASS="FUNCTION"
+>lwres_getrrsetbyname()</TT
+>
+is released by
+<TT
+CLASS="FUNCTION"
+>lwres_freerrset()</TT
+>.
+
+<TT
+CLASS="PARAMETER"
+><I
+>rrset</I
+></TT
+>
+is a pointer to a
+<SPAN
+CLASS="TYPE"
+>struct rrset</SPAN
+>
+created by a call to
+<TT
+CLASS="FUNCTION"
+>lwres_getrrsetbyname()</TT
+>.&#13;</P
+><P
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN62"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getrrsetbyname()</TT
+>
+returns zero on success, and one of the following error
+codes if an error occurred:
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>ERRSET_NONAME</TT
+></DT
+><DD
+><P
+>the name does not exist</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>ERRSET_NODATA</TT
+></DT
+><DD
+><P
+>the name exists, but does not have data of the desired type</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>ERRSET_NOMEMORY</TT
+></DT
+><DD
+><P
+>memory could not be allocated</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>ERRSET_INVAL</TT
+></DT
+><DD
+><P
+>a parameter is invalid</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>ERRSET_FAIL</TT
+></DT
+><DD
+><P
+>other failure</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+></TT
+></DT
+><DD
+><P
+></P
+></DD
+></DL
+></DIV
+>&#13;</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN97"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres</SPAN
+>(3)</SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_gnba.3 b/lib/liblwres/man/lwres_gnba.3
new file mode 100644
index 000000000..515224f77
--- /dev/null
+++ b/lib/liblwres/man/lwres_gnba.3
@@ -0,0 +1,186 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_GNBA" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_gnbarequest_render, lwres_gnbaresponse_render, lwres_gnbarequest_parse, lwres_gnbaresponse_parse, lwres_gnbaresponse_free, lwres_gnbarequest_free \- lightweight resolver getnamebyaddress message handling
+.SH SYNOPSIS
+\fB#include <lwres/lwres.h>
+.sp
+.na
+lwres_result_t
+lwres_gnbarequest_render(lwres_context_t *\fIctx\fB, lwres_gnbarequest_t *\fIreq\fB, lwres_lwpacket_t *\fIpkt\fB, lwres_buffer_t *\fIb\fB);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_gnbaresponse_render(lwres_context_t *ctx, lwres_gnbaresponse_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_gnbarequest_parse(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_gnbaresponse_t **structp);
+.ad
+.sp
+.na
+void
+lwres_gnbaresponse_free(lwres_context_t *ctx, lwres_gnbaresponse_t **structp);
+.ad
+.sp
+.na
+void
+lwres_gnbarequest_free(lwres_context_t *ctx, lwres_gnbarequest_t **structp);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+These are low-level routines for creating and parsing
+lightweight resolver address-to-name lookup request and
+response messages.
+.PP
+There are four main functions for the getnamebyaddr opcode.
+One render function converts a getnamebyaddr request structure \(em
+\fBlwres_gnbarequest_t\fR \(em
+to the lightweight resolver's canonical format.
+It is complemented by a parse function that converts a packet in this
+canonical format to a getnamebyaddr request structure.
+Another render function converts the getnamebyaddr response structure \(em
+\fBlwres_gnbaresponse_t\fR
+to the canonical format.
+This is complemented by a parse function which converts a packet in
+canonical format to a getnamebyaddr response structure.
+.PP
+These structures are defined in
+\fIlwres/lwres.h\fR.
+They are shown below.
+.sp
+.nf
+#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_addr_t addr;
+} lwres_gnbarequest_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ void *base;
+ size_t baselen;
+} lwres_gnbaresponse_t;
+.sp
+.fi
+.PP
+\fBlwres_gnbarequest_render()\fR
+uses resolver context
+ctx
+to convert getnamebyaddr request structure
+req
+to canonical format.
+The packet header structure
+pkt
+is initialised and transferred to
+buffer
+b.
+The contents of
+*req
+are then appended to the buffer in canonical format.
+\fBlwres_gnbaresponse_render()\fR
+performs the same task, except it converts a getnamebyaddr response structure
+\fBlwres_gnbaresponse_t\fR
+to the lightweight resolver's canonical format.
+.PP
+\fBlwres_gnbarequest_parse()\fR
+uses context
+ctx
+to convert the contents of packet
+pkt
+to a
+\fBlwres_gnbarequest_t\fR
+structure.
+Buffer
+b
+provides space to be used for storing this structure.
+When the function succeeds, the resulting
+\fBlwres_gnbarequest_t\fR
+is made available through
+*structp.
+\fBlwres_gnbaresponse_parse()\fR
+offers the same semantics as
+\fBlwres_gnbarequest_parse()\fR
+except it yields a
+\fBlwres_gnbaresponse_t\fR
+structure.
+.PP
+\fBlwres_gnbaresponse_free()\fR
+and
+\fBlwres_gnbarequest_free()\fR
+release the memory in resolver context
+ctx
+that was allocated to the
+\fBlwres_gnbaresponse_t\fR
+or
+\fBlwres_gnbarequest_t\fR
+structures referenced via
+structp.
+Any memory associated with ancillary buffers and strings for those
+structures is also discarded.
+.SH "RETURN VALUES"
+.PP
+The getnamebyaddr opcode functions
+\fBlwres_gnbarequest_render()\fR,
+\fBlwres_gnbaresponse_render()\fR
+\fBlwres_gnbarequest_parse()\fR
+and
+\fBlwres_gnbaresponse_parse()\fR
+all return
+LWRES_R_SUCCESS
+on success.
+They return
+LWRES_R_NOMEMORY
+if memory allocation fails.
+LWRES_R_UNEXPECTEDEND
+is returned if the available space in the buffer
+b
+is too small to accommodate the packet header or the
+\fBlwres_gnbarequest_t\fR
+and
+\fBlwres_gnbaresponse_t\fR
+structures.
+\fBlwres_gnbarequest_parse()\fR
+and
+\fBlwres_gnbaresponse_parse()\fR
+will return
+LWRES_R_UNEXPECTEDEND
+if the buffer is not empty after decoding the received packet.
+These functions will return
+LWRES_R_FAILURE
+if
+\fBpktflags\fR
+in the packet header structure
+\fBlwres_lwpacket_t\fR
+indicate that the packet is not a response to an earlier query.
+.SH "SEE ALSO"
+.PP
+\fBlwres_packet\fR(3).
diff --git a/lib/liblwres/man/lwres_gnba.docbook b/lib/liblwres/man/lwres_gnba.docbook
new file mode 100644
index 000000000..525452085
--- /dev/null
+++ b/lib/liblwres/man/lwres_gnba.docbook
@@ -0,0 +1,259 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_gnba.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_gnba</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_gnbarequest_render</refname>
+<refname>lwres_gnbaresponse_render</refname>
+<refname>lwres_gnbarequest_parse</refname>
+<refname>lwres_gnbaresponse_parse</refname>
+<refname>lwres_gnbaresponse_free</refname>
+<refname>lwres_gnbarequest_free</refname>
+<refpurpose>lightweight resolver getnamebyaddress message handling</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+
+<funcsynopsis>
+<funcsynopsisinfo>
+#include &lt;lwres/lwres.h&gt;
+</funcsynopsisinfo>
+
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_gnbarequest_render</function>
+</funcdef>
+<paramdef>lwres_context_t *<parameter>ctx</parameter></paramdef>
+<paramdef>lwres_gnbarequest_t *<parameter>req</parameter></paramdef>
+<paramdef>lwres_lwpacket_t *<parameter>pkt</parameter></paramdef>
+<paramdef>lwres_buffer_t *<parameter>b</parameter></paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_gnbaresponse_render</function>
+</funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_gnbaresponse_t *req</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_gnbarequest_parse</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_gnbarequest_t **structp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_gnbaresponse_parse</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_gnbaresponse_t **structp</paramdef>
+</funcprototype>
+
+<funcprototype>
+<funcdef>
+void
+<function>lwres_gnbaresponse_free</function>
+</funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_gnbaresponse_t **structp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_gnbarequest_free</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_gnbarequest_t **structp</paramdef>
+</funcprototype>
+</funcsynopsis>
+
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+These are low-level routines for creating and parsing
+lightweight resolver address-to-name lookup request and
+response messages.
+</para>
+<para>
+There are four main functions for the getnamebyaddr opcode.
+One render function converts a getnamebyaddr request structure &mdash;
+<type>lwres_gnbarequest_t</type> &mdash;
+to the lightweight resolver's canonical format.
+It is complemented by a parse function that converts a packet in this
+canonical format to a getnamebyaddr request structure.
+Another render function converts the getnamebyaddr response structure &mdash;
+<type>lwres_gnbaresponse_t</type>
+to the canonical format.
+This is complemented by a parse function which converts a packet in
+canonical format to a getnamebyaddr response structure.
+</para>
+<para>
+These structures are defined in
+<filename>lwres/lwres.h</filename>.
+They are shown below.
+<programlisting>
+#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_addr_t addr;
+} lwres_gnbarequest_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ void *base;
+ size_t baselen;
+} lwres_gnbaresponse_t;
+</programlisting>
+</para>
+<para>
+<function>lwres_gnbarequest_render()</function>
+uses resolver context
+<varname>ctx</varname>
+to convert getnamebyaddr request structure
+<varname>req</varname>
+to canonical format.
+The packet header structure
+<varname>pkt</varname>
+is initialised and transferred to
+buffer
+<varname>b</varname>.
+The contents of
+<varname>*req</varname>
+are then appended to the buffer in canonical format.
+<function>lwres_gnbaresponse_render()</function>
+performs the same task, except it converts a getnamebyaddr response structure
+<type>lwres_gnbaresponse_t</type>
+to the lightweight resolver's canonical format.
+</para>
+<para>
+<function>lwres_gnbarequest_parse()</function>
+uses context
+<varname>ctx</varname>
+to convert the contents of packet
+<varname>pkt</varname>
+to a
+<type>lwres_gnbarequest_t</type>
+structure.
+Buffer
+<varname>b</varname>
+provides space to be used for storing this structure.
+When the function succeeds, the resulting
+<type>lwres_gnbarequest_t</type>
+is made available through
+<varname>*structp</varname>.
+<function>lwres_gnbaresponse_parse()</function>
+offers the same semantics as
+<function>lwres_gnbarequest_parse()</function>
+except it yields a
+<type>lwres_gnbaresponse_t</type>
+structure.
+</para>
+<para>
+<function>lwres_gnbaresponse_free()</function>
+and
+<function>lwres_gnbarequest_free()</function>
+release the memory in resolver context
+<varname>ctx</varname>
+that was allocated to the
+<type>lwres_gnbaresponse_t</type>
+or
+<type>lwres_gnbarequest_t</type>
+structures referenced via
+<varname>structp</varname>.
+Any memory associated with ancillary buffers and strings for those
+structures is also discarded.
+</para>
+</refsect1>
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+The getnamebyaddr opcode functions
+<function>lwres_gnbarequest_render()</function>,
+<function>lwres_gnbaresponse_render()</function>
+<function>lwres_gnbarequest_parse()</function>
+and
+<function>lwres_gnbaresponse_parse()</function>
+all return
+<errorcode>LWRES_R_SUCCESS</errorcode>
+on success.
+They return
+<errorcode>LWRES_R_NOMEMORY</errorcode>
+if memory allocation fails.
+<errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+is returned if the available space in the buffer
+<varname>b</varname>
+is too small to accommodate the packet header or the
+<type>lwres_gnbarequest_t</type>
+and
+<type>lwres_gnbaresponse_t</type>
+structures.
+<function>lwres_gnbarequest_parse()</function>
+and
+<function>lwres_gnbaresponse_parse()</function>
+will return
+<errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+if the buffer is not empty after decoding the received packet.
+These functions will return
+<errorcode>LWRES_R_FAILURE</errorcode>
+if
+<structfield>pktflags</structfield>
+in the packet header structure
+<type>lwres_lwpacket_t</type>
+indicate that the packet is not a response to an earlier query.
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>lwres_packet</refentrytitle>
+<manvolnum>3</manvolnum>
+</citerefentry>.
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_gnba.html b/lib/liblwres/man/lwres_gnba.html
new file mode 100644
index 000000000..98cc04dd6
--- /dev/null
+++ b/lib/liblwres/man/lwres_gnba.html
@@ -0,0 +1,408 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_gnba</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_gnba</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_gnbarequest_render, lwres_gnbaresponse_render, lwres_gnbarequest_parse, lwres_gnbaresponse_parse, lwres_gnbaresponse_free, lwres_gnbarequest_free&nbsp;--&nbsp;lightweight resolver getnamebyaddress message handling</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN16"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN17"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/lwres.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_gnbarequest_render</CODE
+>(lwres_context_t *ctx, lwres_gnbarequest_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_gnbaresponse_render</CODE
+>(lwres_context_t *ctx, lwres_gnbaresponse_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_gnbarequest_parse</CODE
+>(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_gnbaresponse_parse</CODE
+>(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_gnbaresponse_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_gnbaresponse_free</CODE
+>(lwres_context_t *ctx, lwres_gnbaresponse_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_gnbarequest_free</CODE
+>(lwres_context_t *ctx, lwres_gnbarequest_t **structp);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN61"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>These are low-level routines for creating and parsing
+lightweight resolver address-to-name lookup request and
+response messages.</P
+><P
+>There are four main functions for the getnamebyaddr opcode.
+One render function converts a getnamebyaddr request structure &mdash;
+<SPAN
+CLASS="TYPE"
+>lwres_gnbarequest_t</SPAN
+> &mdash;
+to the lightweight resolver's canonical format.
+It is complemented by a parse function that converts a packet in this
+canonical format to a getnamebyaddr request structure.
+Another render function converts the getnamebyaddr response structure &mdash;
+<SPAN
+CLASS="TYPE"
+>lwres_gnbaresponse_t</SPAN
+>
+to the canonical format.
+This is complemented by a parse function which converts a packet in
+canonical format to a getnamebyaddr response structure.</P
+><P
+>These structures are defined in
+<TT
+CLASS="FILENAME"
+>lwres/lwres.h</TT
+>.
+They are shown below.
+<PRE
+CLASS="PROGRAMLISTING"
+>#define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_addr_t addr;
+} lwres_gnbarequest_t;
+
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ void *base;
+ size_t baselen;
+} lwres_gnbaresponse_t;</PRE
+></P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gnbarequest_render()</TT
+>
+uses resolver context
+<TT
+CLASS="VARNAME"
+>ctx</TT
+>
+to convert getnamebyaddr request structure
+<TT
+CLASS="VARNAME"
+>req</TT
+>
+to canonical format.
+The packet header structure
+<TT
+CLASS="VARNAME"
+>pkt</TT
+>
+is initialised and transferred to
+buffer
+<TT
+CLASS="VARNAME"
+>b</TT
+>.
+The contents of
+<TT
+CLASS="VARNAME"
+>*req</TT
+>
+are then appended to the buffer in canonical format.
+<TT
+CLASS="FUNCTION"
+>lwres_gnbaresponse_render()</TT
+>
+performs the same task, except it converts a getnamebyaddr response structure
+<SPAN
+CLASS="TYPE"
+>lwres_gnbaresponse_t</SPAN
+>
+to the lightweight resolver's canonical format.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gnbarequest_parse()</TT
+>
+uses context
+<TT
+CLASS="VARNAME"
+>ctx</TT
+>
+to convert the contents of packet
+<TT
+CLASS="VARNAME"
+>pkt</TT
+>
+to a
+<SPAN
+CLASS="TYPE"
+>lwres_gnbarequest_t</SPAN
+>
+structure.
+Buffer
+<TT
+CLASS="VARNAME"
+>b</TT
+>
+provides space to be used for storing this structure.
+When the function succeeds, the resulting
+<SPAN
+CLASS="TYPE"
+>lwres_gnbarequest_t</SPAN
+>
+is made available through
+<TT
+CLASS="VARNAME"
+>*structp</TT
+>.
+<TT
+CLASS="FUNCTION"
+>lwres_gnbaresponse_parse()</TT
+>
+offers the same semantics as
+<TT
+CLASS="FUNCTION"
+>lwres_gnbarequest_parse()</TT
+>
+except it yields a
+<SPAN
+CLASS="TYPE"
+>lwres_gnbaresponse_t</SPAN
+>
+structure.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_gnbaresponse_free()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_gnbarequest_free()</TT
+>
+release the memory in resolver context
+<TT
+CLASS="VARNAME"
+>ctx</TT
+>
+that was allocated to the
+<SPAN
+CLASS="TYPE"
+>lwres_gnbaresponse_t</SPAN
+>
+or
+<SPAN
+CLASS="TYPE"
+>lwres_gnbarequest_t</SPAN
+>
+structures referenced via
+<TT
+CLASS="VARNAME"
+>structp</TT
+>.
+Any memory associated with ancillary buffers and strings for those
+structures is also discarded.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN97"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+>The getnamebyaddr opcode functions
+<TT
+CLASS="FUNCTION"
+>lwres_gnbarequest_render()</TT
+>,
+<TT
+CLASS="FUNCTION"
+>lwres_gnbaresponse_render()</TT
+>
+<TT
+CLASS="FUNCTION"
+>lwres_gnbarequest_parse()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_gnbaresponse_parse()</TT
+>
+all return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>
+on success.
+They return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_NOMEMORY</SPAN
+>
+if memory allocation fails.
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_UNEXPECTEDEND</SPAN
+>
+is returned if the available space in the buffer
+<TT
+CLASS="VARNAME"
+>b</TT
+>
+is too small to accommodate the packet header or the
+<SPAN
+CLASS="TYPE"
+>lwres_gnbarequest_t</SPAN
+>
+and
+<SPAN
+CLASS="TYPE"
+>lwres_gnbaresponse_t</SPAN
+>
+structures.
+<TT
+CLASS="FUNCTION"
+>lwres_gnbarequest_parse()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_gnbaresponse_parse()</TT
+>
+will return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_UNEXPECTEDEND</SPAN
+>
+if the buffer is not empty after decoding the received packet.
+These functions will return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_FAILURE</SPAN
+>
+if
+<TT
+CLASS="STRUCTFIELD"
+><I
+>pktflags</I
+></TT
+>
+in the packet header structure
+<SPAN
+CLASS="TYPE"
+>lwres_lwpacket_t</SPAN
+>
+indicate that the packet is not a response to an earlier query.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN116"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_packet</SPAN
+>(3)</SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_hstrerror.3 b/lib/liblwres/man/lwres_hstrerror.3
new file mode 100644
index 000000000..dd7fa9c4c
--- /dev/null
+++ b/lib/liblwres/man/lwres_hstrerror.3
@@ -0,0 +1,67 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_HSTRERROR" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_herror, lwres_hstrerror \- lightweight resolver error message generation
+.SH SYNOPSIS
+\fB#include <lwres/netdb.h>
+.sp
+.na
+void
+lwres_herror(const char *s);
+.ad
+.sp
+.na
+const char *
+lwres_hstrerror(int err);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+\fBlwres_herror()\fR prints the string
+\fIs\fR on \fBstderr\fR followed by the string
+generated by \fBlwres_hstrerror()\fR for the error code
+stored in the global variable lwres_h_errno.
+.PP
+\fBlwres_hstrerror()\fR returns an appropriate string
+for the error code gievn by \fIerr\fR. The values of
+the error codes and messages are as follows:
+.TP
+\fBNETDB_SUCCESS\fR
+\fBResolver Error 0 (no error)\fR
+.TP
+\fBHOST_NOT_FOUND\fR
+\fBUnknown host\fR
+.TP
+\fBTRY_AGAIN\fR
+\fBHost name lookup failure\fR
+.TP
+\fBNO_RECOVERY\fR
+\fBUnknown server error\fR
+.TP
+\fBNO_DATA\fR
+\fBNo address associated with name\fR
+.SH "RETURN VALUES"
+.PP
+The string \fBUnknown resolver error\fR is returned by
+\fBlwres_hstrerror()\fR
+when the value of
+lwres_h_errno
+is not a valid error code.
+.SH "SEE ALSO"
+.PP
+\fBherror\fR(3),
+\fBlwres_hstrerror\fR(3).
diff --git a/lib/liblwres/man/lwres_hstrerror.docbook b/lib/liblwres/man/lwres_hstrerror.docbook
new file mode 100644
index 000000000..2f4c06a11
--- /dev/null
+++ b/lib/liblwres/man/lwres_hstrerror.docbook
@@ -0,0 +1,124 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_hstrerror.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_hstrerror</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_herror</refname>
+<refname>lwres_hstrerror</refname>
+<refpurpose>lightweight resolver error message generation</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/netdb.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_herror</function></funcdef>
+<paramdef>const char *s</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+const char *
+<function>lwres_hstrerror</function></funcdef>
+<paramdef>int err</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+
+<para>
+<function>lwres_herror()</function> prints the string
+<parameter>s</parameter> on <type>stderr</type> followed by the string
+generated by <function>lwres_hstrerror()</function> for the error code
+stored in the global variable <constant>lwres_h_errno</constant>.
+</para>
+
+<para>
+<function>lwres_hstrerror()</function> returns an appropriate string
+for the error code gievn by <parameter>err</parameter>. The values of
+the error codes and messages are as follows:
+
+<variablelist>
+<varlistentry><term><errorcode>NETDB_SUCCESS</errorcode></term>
+<listitem>
+<para>
+<errorname>Resolver Error 0 (no error)</errorname>
+</para></listitem></varlistentry>
+<varlistentry><term><errorcode>HOST_NOT_FOUND</errorcode></term>
+<listitem>
+<para>
+<errorname>Unknown host</errorname>
+</para></listitem></varlistentry>
+<varlistentry><term><errorcode>TRY_AGAIN</errorcode></term>
+<listitem>
+<para>
+<errorname>Host name lookup failure</errorname>
+</para></listitem></varlistentry>
+<varlistentry><term><errorcode>NO_RECOVERY</errorcode></term>
+<listitem>
+<para>
+<errorname>Unknown server error</errorname>
+</para></listitem></varlistentry>
+<varlistentry><term><errorcode>NO_DATA</errorcode></term>
+<listitem>
+<para>
+<errorname>No address associated with name</errorname>
+</para></listitem></varlistentry>
+</variablelist>
+</para>
+</refsect1>
+
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+The string <errorname>Unknown resolver error</errorname> is returned by
+<function>lwres_hstrerror()</function>
+when the value of
+<constant>lwres_h_errno</constant>
+is not a valid error code.
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>herror</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_hstrerror</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>.
+</para>
+
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_hstrerror.html b/lib/liblwres/man/lwres_hstrerror.html
new file mode 100644
index 000000000..128b7e4f8
--- /dev/null
+++ b/lib/liblwres/man/lwres_hstrerror.html
@@ -0,0 +1,242 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_hstrerror</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_hstrerror</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_herror, lwres_hstrerror&nbsp;--&nbsp;lightweight resolver error message generation</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN12"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN13"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/netdb.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_herror</CODE
+>(const char *s);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>const char *
+lwres_hstrerror</CODE
+>(int err);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN23"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_herror()</TT
+> prints the string
+<TT
+CLASS="PARAMETER"
+><I
+>s</I
+></TT
+> on <SPAN
+CLASS="TYPE"
+>stderr</SPAN
+> followed by the string
+generated by <TT
+CLASS="FUNCTION"
+>lwres_hstrerror()</TT
+> for the error code
+stored in the global variable <TT
+CLASS="CONSTANT"
+>lwres_h_errno</TT
+>.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_hstrerror()</TT
+> returns an appropriate string
+for the error code gievn by <TT
+CLASS="PARAMETER"
+><I
+>err</I
+></TT
+>. The values of
+the error codes and messages are as follows:
+
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>NETDB_SUCCESS</SPAN
+></DT
+><DD
+><P
+><SPAN
+CLASS="ERRORNAME"
+>Resolver Error 0 (no error)</SPAN
+></P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>HOST_NOT_FOUND</SPAN
+></DT
+><DD
+><P
+><SPAN
+CLASS="ERRORNAME"
+>Unknown host</SPAN
+></P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>TRY_AGAIN</SPAN
+></DT
+><DD
+><P
+><SPAN
+CLASS="ERRORNAME"
+>Host name lookup failure</SPAN
+></P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>NO_RECOVERY</SPAN
+></DT
+><DD
+><P
+><SPAN
+CLASS="ERRORNAME"
+>Unknown server error</SPAN
+></P
+></DD
+><DT
+><SPAN
+CLASS="ERRORCODE"
+>NO_DATA</SPAN
+></DT
+><DD
+><P
+><SPAN
+CLASS="ERRORNAME"
+>No address associated with name</SPAN
+></P
+></DD
+></DL
+></DIV
+></P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN65"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+>The string <SPAN
+CLASS="ERRORNAME"
+>Unknown resolver error</SPAN
+> is returned by
+<TT
+CLASS="FUNCTION"
+>lwres_hstrerror()</TT
+>
+when the value of
+<TT
+CLASS="CONSTANT"
+>lwres_h_errno</TT
+>
+is not a valid error code.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN71"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>herror</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_hstrerror</SPAN
+>(3)</SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_inetntop.3 b/lib/liblwres/man/lwres_inetntop.3
new file mode 100644
index 000000000..983a33d85
--- /dev/null
+++ b/lib/liblwres/man/lwres_inetntop.3
@@ -0,0 +1,52 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_INETNTOP" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_net_ntop \- lightweight resolver IP address presentation
+.SH SYNOPSIS
+\fB#include <lwres/net.h>
+.sp
+.na
+const char *
+lwres_net_ntop(int af, const void *src, char *dst, size_t size);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+\fBlwres_net_ntop()\fR converts an IP address of
+protocol family \fIaf\fR \(em IPv4 or IPv6 \(em
+at location \fIsrc\fR from network format to its
+conventional representation as a string. For IPv4 addresses, that
+string would be a dotted-decimal. An IPv6 address would be
+represented in colon notation as described in RFC1884.
+.PP
+The generated string is copied to \fIdst\fR provided
+\fIsize\fR indicates it is long enough to store the
+ASCII representation of the address.
+.SH "RETURN VALUES"
+.PP
+If successful, the function returns \fIdst\fR:
+a pointer to a string containing the presentation format of the
+address. \fBlwres_net_ntop()\fR returns
+\fBNULL\fR and sets the global variable
+errno to EAFNOSUPPORT if
+the protocol family given in \fIaf\fR is not
+supported.
+.SH "SEE ALSO"
+.PP
+\fBRFC1884\fR,
+\fBinet_ntop\fR(3),
+\fBerrno\fR(3).
diff --git a/lib/liblwres/man/lwres_inetntop.docbook b/lib/liblwres/man/lwres_inetntop.docbook
new file mode 100644
index 000000000..8daa36351
--- /dev/null
+++ b/lib/liblwres/man/lwres_inetntop.docbook
@@ -0,0 +1,99 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_inetntop.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_inetntop</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_net_ntop</refname>
+<refpurpose>lightweight resolver IP address presentation</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/net.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+const char *
+<function>lwres_net_ntop</function></funcdef>
+<paramdef>int af</paramdef>
+<paramdef>const void *src</paramdef>
+<paramdef>char *dst</paramdef>
+<paramdef>size_t size</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+
+<para>
+<function>lwres_net_ntop()</function> converts an IP address of
+protocol family <parameter>af</parameter> &mdash; IPv4 or IPv6 &mdash;
+at location <parameter>src</parameter> from network format to its
+conventional representation as a string. For IPv4 addresses, that
+string would be a dotted-decimal. An IPv6 address would be
+represented in colon notation as described in RFC1884.
+</para>
+
+<para>
+The generated string is copied to <parameter>dst</parameter> provided
+<parameter>size</parameter> indicates it is long enough to store the
+ASCII representation of the address.
+</para>
+
+</refsect1>
+<refsect1>
+<title>RETURN VALUES</title>
+
+<para>
+If successful, the function returns <parameter>dst</parameter>:
+a pointer to a string containing the presentation format of the
+address. <function>lwres_net_ntop()</function> returns
+<type>NULL</type> and sets the global variable
+<constant>errno</constant> to <errorcode>EAFNOSUPPORT</errorcode> if
+the protocol family given in <parameter>af</parameter> is not
+supported.
+</para>
+
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>RFC1884</refentrytitle>
+</citerefentry>,
+<citerefentry>
+<refentrytitle>inet_ntop</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+<citerefentry>
+<refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>.
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_inetntop.html b/lib/liblwres/man/lwres_inetntop.html
new file mode 100644
index 000000000..09d4fea34
--- /dev/null
+++ b/lib/liblwres/man/lwres_inetntop.html
@@ -0,0 +1,186 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_inetntop</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_inetntop</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_net_ntop&nbsp;--&nbsp;lightweight resolver IP address presentation</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN11"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN12"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/net.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>const char *
+lwres_net_ntop</CODE
+>(int af, const void *src, char *dst, size_t size);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN21"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_net_ntop()</TT
+> converts an IP address of
+protocol family <TT
+CLASS="PARAMETER"
+><I
+>af</I
+></TT
+> &mdash; IPv4 or IPv6 &mdash;
+at location <TT
+CLASS="PARAMETER"
+><I
+>src</I
+></TT
+> from network format to its
+conventional representation as a string. For IPv4 addresses, that
+string would be a dotted-decimal. An IPv6 address would be
+represented in colon notation as described in RFC1884.</P
+><P
+>The generated string is copied to <TT
+CLASS="PARAMETER"
+><I
+>dst</I
+></TT
+> provided
+<TT
+CLASS="PARAMETER"
+><I
+>size</I
+></TT
+> indicates it is long enough to store the
+ASCII representation of the address.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN30"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+>If successful, the function returns <TT
+CLASS="PARAMETER"
+><I
+>dst</I
+></TT
+>:
+a pointer to a string containing the presentation format of the
+address. <TT
+CLASS="FUNCTION"
+>lwres_net_ntop()</TT
+> returns
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+> and sets the global variable
+<TT
+CLASS="CONSTANT"
+>errno</TT
+> to <SPAN
+CLASS="ERRORCODE"
+>EAFNOSUPPORT</SPAN
+> if
+the protocol family given in <TT
+CLASS="PARAMETER"
+><I
+>af</I
+></TT
+> is not
+supported.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN39"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>RFC1884</SPAN
+></SPAN
+>,
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>inet_ntop</SPAN
+>(3)</SPAN
+>,
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>errno</SPAN
+>(3)</SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_noop.3 b/lib/liblwres/man/lwres_noop.3
new file mode 100644
index 000000000..50d127029
--- /dev/null
+++ b/lib/liblwres/man/lwres_noop.3
@@ -0,0 +1,160 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_NOOP" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_nooprequest_render, lwres_noopresponse_render, lwres_nooprequest_parse, lwres_noopresponse_parse, lwres_noopresponse_free, lwres_nooprequest_free \- lightweight resolver no-op message handling
+.SH SYNOPSIS
+\fB#include <lwres/lwres.h>
+.sp
+.na
+lwres_result_t
+lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_noopresponse_t **structp);
+.ad
+.sp
+.na
+void
+lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp);
+.ad
+.sp
+.na
+void
+lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+These are low-level routines for creating and parsing
+lightweight resolver no-op request and response messages.
+.PP
+The no-op message is analogous to a \fBping\fR packet:
+a packet is sent to the resolver daemon and is simply echoed back.
+The opcode is intended to allow a client to determine if the server is
+operational or not.
+.PP
+There are four main functions for the no-op opcode.
+One render function converts a no-op request structure \(em
+\fBlwres_nooprequest_t\fR \(em
+to the lighweight resolver's canonical format.
+It is complemented by a parse function that converts a packet in this
+canonical format to a no-op request structure.
+Another render function converts the no-op response structure \(em
+\fBlwres_noopresponse_t\fR
+to the canonical format.
+This is complemented by a parse function which converts a packet in
+canonical format to a no-op response structure.
+.PP
+These structures are defined in
+\fIlwres/lwres.h\fR.
+They are shown below.
+.sp
+.nf
+#define LWRES_OPCODE_NOOP 0x00000000U
+
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_nooprequest_t;
+
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_noopresponse_t;
+.sp
+.fi
+Although the structures have different types, they are identical.
+This is because the no-op opcode simply echos whatever data was sent:
+the response is therefore identical to the request.
+.PP
+\fBlwres_nooprequest_render()\fR uses resolver
+context \fIctx\fR to convert no-op request structure
+\fIreq\fR to canonical format. The packet header
+structure \fIpkt\fR is initialised and transferred to
+buffer \fIb\fR. The contents of
+\fI*req\fR are then appended to the buffer in
+canonical format. \fBlwres_noopresponse_render()\fR
+performs the same task, except it converts a no-op response structure
+\fBlwres_noopresponse_t\fR to the lightweight resolver's
+canonical format.
+.PP
+\fBlwres_nooprequest_parse()\fR uses context
+\fIctx\fR to convert the contents of packet
+\fIpkt\fR to a \fBlwres_nooprequest_t\fR
+structure. Buffer \fIb\fR provides space to be used
+for storing this structure. When the function succeeds, the resulting
+\fBlwres_nooprequest_t\fR is made available through
+\fI*structp\fR.
+\fBlwres_noopresponse_parse()\fR offers the same
+semantics as \fBlwres_nooprequest_parse()\fR except it
+yields a \fBlwres_noopresponse_t\fR structure.
+.PP
+\fBlwres_noopresponse_free()\fR and
+\fBlwres_nooprequest_free()\fR release the memory in
+resolver context \fIctx\fR that was allocated to the
+\fBlwres_noopresponse_t\fR or \fBlwres_nooprequest_t\fR
+structures referenced via \fIstructp\fR.
+.SH "RETURN VALUES"
+.PP
+The no-op opcode functions
+\fBlwres_nooprequest_render()\fR,
+\fBlwres_noopresponse_render()\fR
+\fBlwres_nooprequest_parse()\fR
+and
+\fBlwres_noopresponse_parse()\fR
+all return
+LWRES_R_SUCCESS
+on success.
+They return
+LWRES_R_NOMEMORY
+if memory allocation fails.
+LWRES_R_UNEXPECTEDEND
+is returned if the available space in the buffer
+\fIb\fR
+is too small to accommodate the packet header or the
+\fBlwres_nooprequest_t\fR
+and
+\fBlwres_noopresponse_t\fR
+structures.
+\fBlwres_nooprequest_parse()\fR
+and
+\fBlwres_noopresponse_parse()\fR
+will return
+LWRES_R_UNEXPECTEDEND
+if the buffer is not empty after decoding the received packet.
+These functions will return
+LWRES_R_FAILURE
+if
+pktflags
+in the packet header structure
+\fBlwres_lwpacket_t\fR
+indicate that the packet is not a response to an earlier query.
+.SH "SEE ALSO"
+.PP
+\fBlwres_packet\fR(3)
diff --git a/lib/liblwres/man/lwres_noop.docbook b/lib/liblwres/man/lwres_noop.docbook
new file mode 100644
index 000000000..18762e515
--- /dev/null
+++ b/lib/liblwres/man/lwres_noop.docbook
@@ -0,0 +1,229 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_noop.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_noop</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_nooprequest_render</refname>
+<refname>lwres_noopresponse_render</refname>
+<refname>lwres_nooprequest_parse</refname>
+<refname>lwres_noopresponse_parse</refname>
+<refname>lwres_noopresponse_free</refname>
+<refname>lwres_nooprequest_free</refname>
+<refpurpose>lightweight resolver no-op message handling</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>
+#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_nooprequest_render</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_nooprequest_t *req</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_noopresponse_render</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_noopresponse_t *req</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_nooprequest_parse</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_nooprequest_t **structp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_noopresponse_parse</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+<paramdef>lwres_noopresponse_t **structp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_noopresponse_free</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_noopresponse_t **structp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+void
+<function>lwres_nooprequest_free</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_nooprequest_t **structp</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+These are low-level routines for creating and parsing
+lightweight resolver no-op request and response messages.
+</para>
+<para>
+The no-op message is analogous to a <command>ping</command> packet:
+a packet is sent to the resolver daemon and is simply echoed back.
+The opcode is intended to allow a client to determine if the server is
+operational or not.
+</para>
+<para>
+There are four main functions for the no-op opcode.
+One render function converts a no-op request structure &mdash;
+<type>lwres_nooprequest_t</type> &mdash;
+to the lighweight resolver's canonical format.
+It is complemented by a parse function that converts a packet in this
+canonical format to a no-op request structure.
+Another render function converts the no-op response structure &mdash;
+<type>lwres_noopresponse_t</type>
+to the canonical format.
+This is complemented by a parse function which converts a packet in
+canonical format to a no-op response structure.
+</para>
+<para>
+These structures are defined in
+<filename>lwres/lwres.h</filename>.
+
+They are shown below.
+<programlisting>
+#define LWRES_OPCODE_NOOP 0x00000000U
+
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_nooprequest_t;
+
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_noopresponse_t;
+</programlisting>
+Although the structures have different types, they are identical.
+This is because the no-op opcode simply echos whatever data was sent:
+the response is therefore identical to the request.
+</para>
+
+<para>
+<function>lwres_nooprequest_render()</function> uses resolver
+context <parameter>ctx</parameter> to convert no-op request structure
+<parameter>req</parameter> to canonical format. The packet header
+structure <parameter>pkt</parameter> is initialised and transferred to
+buffer <parameter>b</parameter>. The contents of
+<parameter>*req</parameter> are then appended to the buffer in
+canonical format. <function>lwres_noopresponse_render()</function>
+performs the same task, except it converts a no-op response structure
+<type>lwres_noopresponse_t</type> to the lightweight resolver's
+canonical format.
+</para>
+
+<para>
+<function>lwres_nooprequest_parse()</function> uses context
+<parameter>ctx</parameter> to convert the contents of packet
+<parameter>pkt</parameter> to a <type>lwres_nooprequest_t</type>
+structure. Buffer <parameter>b</parameter> provides space to be used
+for storing this structure. When the function succeeds, the resulting
+<type>lwres_nooprequest_t</type> is made available through
+<parameter>*structp</parameter>.
+<function>lwres_noopresponse_parse()</function> offers the same
+semantics as <function>lwres_nooprequest_parse()</function> except it
+yields a <type>lwres_noopresponse_t</type> structure.
+</para>
+
+<para>
+<function>lwres_noopresponse_free()</function> and
+<function>lwres_nooprequest_free()</function> release the memory in
+resolver context <parameter>ctx</parameter> that was allocated to the
+<type>lwres_noopresponse_t</type> or <type>lwres_nooprequest_t</type>
+structures referenced via <parameter>structp</parameter>.
+</para>
+
+</refsect1>
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+The no-op opcode functions
+<function>lwres_nooprequest_render()</function>,
+
+<function>lwres_noopresponse_render()</function>
+<function>lwres_nooprequest_parse()</function>
+and
+<function>lwres_noopresponse_parse()</function>
+all return
+<errorcode>LWRES_R_SUCCESS</errorcode>
+on success.
+They return
+<errorcode>LWRES_R_NOMEMORY</errorcode>
+if memory allocation fails.
+<errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+is returned if the available space in the buffer
+<parameter>b</parameter>
+is too small to accommodate the packet header or the
+<type>lwres_nooprequest_t</type>
+and
+<type>lwres_noopresponse_t</type>
+structures.
+<function>lwres_nooprequest_parse()</function>
+and
+<function>lwres_noopresponse_parse()</function>
+will return
+<errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+if the buffer is not empty after decoding the received packet.
+These functions will return
+<errorcode>LWRES_R_FAILURE</errorcode>
+if
+<constant>pktflags</constant>
+in the packet header structure
+<type>lwres_lwpacket_t</type>
+indicate that the packet is not a response to an earlier query.
+</para>
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>lwres_packet</refentrytitle><manvolnum>3
+</manvolnum>
+</citerefentry>
+</para>
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_noop.html b/lib/liblwres/man/lwres_noop.html
new file mode 100644
index 000000000..fdb5da103
--- /dev/null
+++ b/lib/liblwres/man/lwres_noop.html
@@ -0,0 +1,409 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_noop</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_noop</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_nooprequest_render, lwres_noopresponse_render, lwres_nooprequest_parse, lwres_noopresponse_parse, lwres_noopresponse_free, lwres_nooprequest_free&nbsp;--&nbsp;lightweight resolver no-op message handling</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN16"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN17"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/lwres.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_nooprequest_render</CODE
+>(lwres_context_t *ctx, lwres_nooprequest_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_noopresponse_render</CODE
+>(lwres_context_t *ctx, lwres_noopresponse_t *req, lwres_lwpacket_t *pkt, lwres_buffer_t *b);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_nooprequest_parse</CODE
+>(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_noopresponse_parse</CODE
+>(lwres_context_t *ctx, lwres_buffer_t *b, lwres_lwpacket_t *pkt, lwres_noopresponse_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_noopresponse_free</CODE
+>(lwres_context_t *ctx, lwres_noopresponse_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>void
+lwres_nooprequest_free</CODE
+>(lwres_context_t *ctx, lwres_nooprequest_t **structp);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN57"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>These are low-level routines for creating and parsing
+lightweight resolver no-op request and response messages.</P
+><P
+>The no-op message is analogous to a <B
+CLASS="COMMAND"
+>ping</B
+> packet:
+a packet is sent to the resolver daemon and is simply echoed back.
+The opcode is intended to allow a client to determine if the server is
+operational or not.</P
+><P
+>There are four main functions for the no-op opcode.
+One render function converts a no-op request structure &mdash;
+<SPAN
+CLASS="TYPE"
+>lwres_nooprequest_t</SPAN
+> &mdash;
+to the lighweight resolver's canonical format.
+It is complemented by a parse function that converts a packet in this
+canonical format to a no-op request structure.
+Another render function converts the no-op response structure &mdash;
+<SPAN
+CLASS="TYPE"
+>lwres_noopresponse_t</SPAN
+>
+to the canonical format.
+This is complemented by a parse function which converts a packet in
+canonical format to a no-op response structure.</P
+><P
+>These structures are defined in
+<TT
+CLASS="FILENAME"
+>lwres/lwres.h</TT
+>.
+
+They are shown below.
+<PRE
+CLASS="PROGRAMLISTING"
+>#define LWRES_OPCODE_NOOP 0x00000000U
+
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_nooprequest_t;
+
+typedef struct {
+ lwres_uint16_t datalength;
+ unsigned char *data;
+} lwres_noopresponse_t;</PRE
+>
+Although the structures have different types, they are identical.
+This is because the no-op opcode simply echos whatever data was sent:
+the response is therefore identical to the request.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_nooprequest_render()</TT
+> uses resolver
+context <TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+> to convert no-op request structure
+<TT
+CLASS="PARAMETER"
+><I
+>req</I
+></TT
+> to canonical format. The packet header
+structure <TT
+CLASS="PARAMETER"
+><I
+>pkt</I
+></TT
+> is initialised and transferred to
+buffer <TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>. The contents of
+<TT
+CLASS="PARAMETER"
+><I
+>*req</I
+></TT
+> are then appended to the buffer in
+canonical format. <TT
+CLASS="FUNCTION"
+>lwres_noopresponse_render()</TT
+>
+performs the same task, except it converts a no-op response structure
+<SPAN
+CLASS="TYPE"
+>lwres_noopresponse_t</SPAN
+> to the lightweight resolver's
+canonical format.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_nooprequest_parse()</TT
+> uses context
+<TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+> to convert the contents of packet
+<TT
+CLASS="PARAMETER"
+><I
+>pkt</I
+></TT
+> to a <SPAN
+CLASS="TYPE"
+>lwres_nooprequest_t</SPAN
+>
+structure. Buffer <TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+> provides space to be used
+for storing this structure. When the function succeeds, the resulting
+<SPAN
+CLASS="TYPE"
+>lwres_nooprequest_t</SPAN
+> is made available through
+<TT
+CLASS="PARAMETER"
+><I
+>*structp</I
+></TT
+>.
+<TT
+CLASS="FUNCTION"
+>lwres_noopresponse_parse()</TT
+> offers the same
+semantics as <TT
+CLASS="FUNCTION"
+>lwres_nooprequest_parse()</TT
+> except it
+yields a <SPAN
+CLASS="TYPE"
+>lwres_noopresponse_t</SPAN
+> structure.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_noopresponse_free()</TT
+> and
+<TT
+CLASS="FUNCTION"
+>lwres_nooprequest_free()</TT
+> release the memory in
+resolver context <TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+> that was allocated to the
+<SPAN
+CLASS="TYPE"
+>lwres_noopresponse_t</SPAN
+> or <SPAN
+CLASS="TYPE"
+>lwres_nooprequest_t</SPAN
+>
+structures referenced via <TT
+CLASS="PARAMETER"
+><I
+>structp</I
+></TT
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN95"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+>The no-op opcode functions
+<TT
+CLASS="FUNCTION"
+>lwres_nooprequest_render()</TT
+>,
+
+<TT
+CLASS="FUNCTION"
+>lwres_noopresponse_render()</TT
+>
+<TT
+CLASS="FUNCTION"
+>lwres_nooprequest_parse()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_noopresponse_parse()</TT
+>
+all return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>
+on success.
+They return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_NOMEMORY</SPAN
+>
+if memory allocation fails.
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_UNEXPECTEDEND</SPAN
+>
+is returned if the available space in the buffer
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>
+is too small to accommodate the packet header or the
+<SPAN
+CLASS="TYPE"
+>lwres_nooprequest_t</SPAN
+>
+and
+<SPAN
+CLASS="TYPE"
+>lwres_noopresponse_t</SPAN
+>
+structures.
+<TT
+CLASS="FUNCTION"
+>lwres_nooprequest_parse()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_noopresponse_parse()</TT
+>
+will return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_UNEXPECTEDEND</SPAN
+>
+if the buffer is not empty after decoding the received packet.
+These functions will return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_FAILURE</SPAN
+>
+if
+<TT
+CLASS="CONSTANT"
+>pktflags</TT
+>
+in the packet header structure
+<SPAN
+CLASS="TYPE"
+>lwres_lwpacket_t</SPAN
+>
+indicate that the packet is not a response to an earlier query.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN114"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_packet</SPAN
+>(3)</SPAN
+></P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_packet.3 b/lib/liblwres/man/lwres_packet.3
new file mode 100644
index 000000000..d7fb6f077
--- /dev/null
+++ b/lib/liblwres/man/lwres_packet.3
@@ -0,0 +1,149 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_PACKET" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_lwpacket_renderheader, lwres_lwpacket_parseheader \- lightweight resolver packet handling functions
+.SH SYNOPSIS
+\fB#include <lwres/lwpacket.h>
+.sp
+.na
+lwres_result_t
+lwres_lwpacket_renderheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_lwpacket_parseheader(lwres_buffer_t *b, lwres_lwpacket_t *pkt);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+These functions rely on a
+\fBstruct lwres_lwpacket\fR
+which is defined in
+\fIlwres/lwpacket.h\fR.
+.sp
+.nf
+typedef struct lwres_lwpacket lwres_lwpacket_t;
+
+struct lwres_lwpacket {
+ lwres_uint32_t length;
+ lwres_uint16_t version;
+ lwres_uint16_t pktflags;
+ lwres_uint32_t serial;
+ lwres_uint32_t opcode;
+ lwres_uint32_t result;
+ lwres_uint32_t recvlength;
+ lwres_uint16_t authtype;
+ lwres_uint16_t authlength;
+};
+.sp
+.fi
+.PP
+The elements of this structure are:
+.TP
+\fBlength\fR
+the overall packet length, including the entire packet header.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.
+.TP
+\fBversion\fR
+the header format. There is currently only one format,
+\fBLWRES_LWPACKETVERSION_0\fR.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.
+.TP
+\fBpktflags\fR
+library-defined flags for this packet: for instance whether the packet
+is a request or a reply. Flag values can be set, but not defined by
+the caller.
+This field is filled in by the application wit the exception of the
+LWRES_LWPACKETFLAG_RESPONSE bit, which is set by the library in the
+lwres_gabn_*() and lwres_gnba_*() calls.
+.TP
+\fBserial\fR
+is set by the requestor and is returned in all replies. If two or more
+packets from the same source have the same serial number and are from
+the same source, they are assumed to be duplicates and the latter ones
+may be dropped.
+This field must be set by the application.
+.TP
+\fBopcode\fR
+indicates the operation.
+Opcodes between 0x00000000 and 0x03ffffff are
+reserved for use by the lightweight resolver library. Opcodes between
+0x04000000 and 0xffffffff are application defined.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.
+.TP
+\fBresult\fR
+is only valid for replies.
+Results between 0x04000000 and 0xffffffff are application defined.
+Results between 0x00000000 and 0x03ffffff are reserved for library use.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.
+.TP
+\fBrecvlength\fR
+is the maximum buffer size that the receiver can handle on requests
+and the size of the buffer needed to satisfy a request when the buffer
+is too large for replies.
+This field is supplied by the application.
+.TP
+\fBauthtype\fR
+defines the packet level authentication that is used.
+Authorisation types between 0x1000 and 0xffff are application defined
+and types between 0x0000 and 0x0fff are reserved for library use.
+Currently these are not used and must be zero.
+.TP
+\fBauthlen\fR
+gives the length of the authentication data.
+Since packet authentication is currently not used, this must be zero.
+.PP
+The following opcodes are currently defined:
+.TP
+\fBNOOP\fR
+Success is always returned and the packet contents are echoed.
+The lwres_noop_*() functions should be used for this type.
+.TP
+\fBGETADDRSBYNAME\fR
+returns all known addresses for a given name.
+The lwres_gabn_*() functions should be used for this type.
+.TP
+\fBGETNAMEBYADDR\fR
+return the hostname for the given address.
+The lwres_gnba_*() functions should be used for this type.
+.PP
+\fBlwres_lwpacket_renderheader()\fR transfers the
+contents of lightweight resolver packet structure
+\fBlwres_lwpacket_t\fR \fI*pkt\fR in network
+byte order to the lightweight resolver buffer,
+\fI*b\fR.
+.PP
+\fBlwres_lwpacket_parseheader()\fR performs the
+converse operation. It transfers data in network byte order from
+buffer \fI*b\fR to resolver packet
+\fI*pkt\fR. The contents of the buffer
+\fIb\fR should correspond to a
+\fBlwres_lwpacket_t\fR.
+.SH "RETURN VALUES"
+.PP
+Successful calls to
+\fBlwres_lwpacket_renderheader()\fR and
+\fBlwres_lwpacket_parseheader()\fR return
+LWRES_R_SUCCESS. If there is insufficient
+space to copy data between the buffer \fI*b\fR and
+lightweight resolver packet \fI*pkt\fR both functions
+return LWRES_R_UNEXPECTEDEND.
diff --git a/lib/liblwres/man/lwres_packet.docbook b/lib/liblwres/man/lwres_packet.docbook
new file mode 100644
index 000000000..7b9ed38b3
--- /dev/null
+++ b/lib/liblwres/man/lwres_packet.docbook
@@ -0,0 +1,218 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_packet.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>lwres_packet</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_lwpacket_renderheader</refname>
+<refname>lwres_lwpacket_parseheader</refname>
+<refpurpose>lightweight resolver packet handling functions</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwpacket.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_lwpacket_renderheader</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_lwpacket_parseheader</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_lwpacket_t *pkt</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+<refsect1>
+<title>DESCRIPTION</title>
+<para>
+These functions rely on a
+<type>struct lwres_lwpacket</type>
+which is defined in
+<filename>lwres/lwpacket.h</filename>.
+
+<programlisting>
+typedef struct lwres_lwpacket lwres_lwpacket_t;
+
+struct lwres_lwpacket {
+ lwres_uint32_t length;
+ lwres_uint16_t version;
+ lwres_uint16_t pktflags;
+ lwres_uint32_t serial;
+ lwres_uint32_t opcode;
+ lwres_uint32_t result;
+ lwres_uint32_t recvlength;
+ lwres_uint16_t authtype;
+ lwres_uint16_t authlength;
+};
+</programlisting>
+</para>
+
+<para>
+The elements of this structure are:
+<variablelist>
+<varlistentry><term><constant>length</constant></term>
+<listitem>
+<para>
+the overall packet length, including the entire packet header.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>version</constant></term>
+<listitem>
+<para>
+the header format. There is currently only one format,
+<type>LWRES_LWPACKETVERSION_0</type>.
+
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>pktflags</constant></term>
+<listitem>
+<para>
+library-defined flags for this packet: for instance whether the packet
+is a request or a reply. Flag values can be set, but not defined by
+the caller.
+This field is filled in by the application wit the exception of the
+LWRES_LWPACKETFLAG_RESPONSE bit, which is set by the library in the
+lwres_gabn_*() and lwres_gnba_*() calls.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>serial</constant></term>
+<listitem>
+<para>
+is set by the requestor and is returned in all replies. If two or more
+packets from the same source have the same serial number and are from
+the same source, they are assumed to be duplicates and the latter ones
+may be dropped.
+This field must be set by the application.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>opcode</constant></term>
+<listitem>
+<para>
+indicates the operation.
+Opcodes between 0x00000000 and 0x03ffffff are
+reserved for use by the lightweight resolver library. Opcodes between
+0x04000000 and 0xffffffff are application defined.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>result</constant></term>
+<listitem>
+<para>
+is only valid for replies.
+Results between 0x04000000 and 0xffffffff are application defined.
+Results between 0x00000000 and 0x03ffffff are reserved for library use.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>recvlength</constant></term>
+<listitem>
+<para>
+is the maximum buffer size that the receiver can handle on requests
+and the size of the buffer needed to satisfy a request when the buffer
+is too large for replies.
+This field is supplied by the application.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>authtype</constant></term>
+<listitem>
+<para>
+defines the packet level authentication that is used.
+Authorisation types between 0x1000 and 0xffff are application defined
+and types between 0x0000 and 0x0fff are reserved for library use.
+Currently these are not used and must be zero.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>authlen</constant></term>
+<listitem>
+<para>
+gives the length of the authentication data.
+Since packet authentication is currently not used, this must be zero.
+</para></listitem></varlistentry>
+</variablelist>
+</para>
+<para>
+The following opcodes are currently defined:
+<variablelist>
+<varlistentry><term><constant>NOOP</constant></term>
+<listitem>
+<para>
+Success is always returned and the packet contents are echoed.
+The lwres_noop_*() functions should be used for this type.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>GETADDRSBYNAME</constant></term>
+<listitem>
+<para>
+returns all known addresses for a given name.
+The lwres_gabn_*() functions should be used for this type.
+</para></listitem></varlistentry>
+<varlistentry><term><constant>GETNAMEBYADDR</constant></term>
+<listitem>
+<para>
+return the hostname for the given address.
+The lwres_gnba_*() functions should be used for this type.
+</para></listitem></varlistentry>
+</variablelist>
+</para>
+
+<para>
+<function>lwres_lwpacket_renderheader()</function> transfers the
+contents of lightweight resolver packet structure
+<type>lwres_lwpacket_t</type> <parameter>*pkt</parameter> in network
+byte order to the lightweight resolver buffer,
+<parameter>*b</parameter>.
+</para>
+
+<para>
+<function>lwres_lwpacket_parseheader()</function> performs the
+converse operation. It transfers data in network byte order from
+buffer <parameter>*b</parameter> to resolver packet
+<parameter>*pkt</parameter>. The contents of the buffer
+<parameter>b</parameter> should correspond to a
+<type>lwres_lwpacket_t</type>.
+</para>
+
+</refsect1>
+
+<refsect1>
+<title>RETURN VALUES</title>
+<para> Successful calls to
+<function>lwres_lwpacket_renderheader()</function> and
+<function>lwres_lwpacket_parseheader()</function> return
+<errorcode>LWRES_R_SUCCESS</errorcode>. If there is insufficient
+space to copy data between the buffer <parameter>*b</parameter> and
+lightweight resolver packet <parameter>*pkt</parameter> both functions
+return <errorcode>LWRES_R_UNEXPECTEDEND</errorcode>.
+</para>
+
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_packet.html b/lib/liblwres/man/lwres_packet.html
new file mode 100644
index 000000000..5c5828f49
--- /dev/null
+++ b/lib/liblwres/man/lwres_packet.html
@@ -0,0 +1,373 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_packet</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_packet</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_lwpacket_renderheader, lwres_lwpacket_parseheader&nbsp;--&nbsp;lightweight resolver packet handling functions</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN12"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN13"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/lwpacket.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_lwpacket_renderheader</CODE
+>(lwres_buffer_t *b, lwres_lwpacket_t *pkt);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_lwpacket_parseheader</CODE
+>(lwres_buffer_t *b, lwres_lwpacket_t *pkt);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN25"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+>These functions rely on a
+<SPAN
+CLASS="TYPE"
+>struct lwres_lwpacket</SPAN
+>
+which is defined in
+<TT
+CLASS="FILENAME"
+>lwres/lwpacket.h</TT
+>.
+
+<PRE
+CLASS="PROGRAMLISTING"
+>typedef struct lwres_lwpacket lwres_lwpacket_t;
+
+struct lwres_lwpacket {
+ lwres_uint32_t length;
+ lwres_uint16_t version;
+ lwres_uint16_t pktflags;
+ lwres_uint32_t serial;
+ lwres_uint32_t opcode;
+ lwres_uint32_t result;
+ lwres_uint32_t recvlength;
+ lwres_uint16_t authtype;
+ lwres_uint16_t authlength;
+};</PRE
+></P
+><P
+>The elements of this structure are:
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>length</TT
+></DT
+><DD
+><P
+>the overall packet length, including the entire packet header.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>version</TT
+></DT
+><DD
+><P
+>the header format. There is currently only one format,
+<SPAN
+CLASS="TYPE"
+>LWRES_LWPACKETVERSION_0</SPAN
+>.
+
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>pktflags</TT
+></DT
+><DD
+><P
+>library-defined flags for this packet: for instance whether the packet
+is a request or a reply. Flag values can be set, but not defined by
+the caller.
+This field is filled in by the application wit the exception of the
+LWRES_LWPACKETFLAG_RESPONSE bit, which is set by the library in the
+lwres_gabn_*() and lwres_gnba_*() calls.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>serial</TT
+></DT
+><DD
+><P
+>is set by the requestor and is returned in all replies. If two or more
+packets from the same source have the same serial number and are from
+the same source, they are assumed to be duplicates and the latter ones
+may be dropped.
+This field must be set by the application.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>opcode</TT
+></DT
+><DD
+><P
+>indicates the operation.
+Opcodes between 0x00000000 and 0x03ffffff are
+reserved for use by the lightweight resolver library. Opcodes between
+0x04000000 and 0xffffffff are application defined.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>result</TT
+></DT
+><DD
+><P
+>is only valid for replies.
+Results between 0x04000000 and 0xffffffff are application defined.
+Results between 0x00000000 and 0x03ffffff are reserved for library use.
+This field is filled in by the lwres_gabn_*() and lwres_gnba_*()
+calls.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>recvlength</TT
+></DT
+><DD
+><P
+>is the maximum buffer size that the receiver can handle on requests
+and the size of the buffer needed to satisfy a request when the buffer
+is too large for replies.
+This field is supplied by the application.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>authtype</TT
+></DT
+><DD
+><P
+>defines the packet level authentication that is used.
+Authorisation types between 0x1000 and 0xffff are application defined
+and types between 0x0000 and 0x0fff are reserved for library use.
+Currently these are not used and must be zero.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>authlen</TT
+></DT
+><DD
+><P
+>gives the length of the authentication data.
+Since packet authentication is currently not used, this must be zero.</P
+></DD
+></DL
+></DIV
+></P
+><P
+>The following opcodes are currently defined:
+<P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="CONSTANT"
+>NOOP</TT
+></DT
+><DD
+><P
+>Success is always returned and the packet contents are echoed.
+The lwres_noop_*() functions should be used for this type.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>GETADDRSBYNAME</TT
+></DT
+><DD
+><P
+>returns all known addresses for a given name.
+The lwres_gabn_*() functions should be used for this type.</P
+></DD
+><DT
+><TT
+CLASS="CONSTANT"
+>GETNAMEBYADDR</TT
+></DT
+><DD
+><P
+>return the hostname for the given address.
+The lwres_gnba_*() functions should be used for this type.</P
+></DD
+></DL
+></DIV
+></P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_lwpacket_renderheader()</TT
+> transfers the
+contents of lightweight resolver packet structure
+<SPAN
+CLASS="TYPE"
+>lwres_lwpacket_t</SPAN
+> <TT
+CLASS="PARAMETER"
+><I
+>*pkt</I
+></TT
+> in network
+byte order to the lightweight resolver buffer,
+<TT
+CLASS="PARAMETER"
+><I
+>*b</I
+></TT
+>.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_lwpacket_parseheader()</TT
+> performs the
+converse operation. It transfers data in network byte order from
+buffer <TT
+CLASS="PARAMETER"
+><I
+>*b</I
+></TT
+> to resolver packet
+<TT
+CLASS="PARAMETER"
+><I
+>*pkt</I
+></TT
+>. The contents of the buffer
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+> should correspond to a
+<SPAN
+CLASS="TYPE"
+>lwres_lwpacket_t</SPAN
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN107"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+> Successful calls to
+<TT
+CLASS="FUNCTION"
+>lwres_lwpacket_renderheader()</TT
+> and
+<TT
+CLASS="FUNCTION"
+>lwres_lwpacket_parseheader()</TT
+> return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>. If there is insufficient
+space to copy data between the buffer <TT
+CLASS="PARAMETER"
+><I
+>*b</I
+></TT
+> and
+lightweight resolver packet <TT
+CLASS="PARAMETER"
+><I
+>*pkt</I
+></TT
+> both functions
+return <SPAN
+CLASS="ERRORCODE"
+>LWRES_R_UNEXPECTEDEND</SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/man/lwres_resutil.3 b/lib/liblwres/man/lwres_resutil.3
new file mode 100644
index 000000000..6db4825b0
--- /dev/null
+++ b/lib/liblwres/man/lwres_resutil.3
@@ -0,0 +1,151 @@
+.\"
+.\" Copyright (C) 2000, 2001 Internet Software Consortium.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "LWRES_RESUTIL" "3" "Jun 30, 2000" "BIND9" ""
+.SH NAME
+lwres_string_parse, lwres_addr_parse, lwres_getaddrsbyname, lwres_getnamebyaddr \- lightweight resolver utility functions
+.SH SYNOPSIS
+\fB#include <lwres/lwres.h>
+.sp
+.na
+lwres_result_t
+lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_getaddrsbyname(lwres_context_t *ctx, const char *name, lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp);
+.ad
+.sp
+.na
+lwres_result_t
+lwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype, lwres_uint16_t addrlen, const unsigned char *addr, lwres_gnbaresponse_t **structp);
+.ad
+\fR.SH "DESCRIPTION"
+.PP
+\fBlwres_string_parse()\fR retrieves a DNS-encoded
+string starting the current pointer of lightweight resolver buffer
+\fIb\fR: i.e. b->current.
+When the function returns, the address of the first byte of the
+encoded string is returned via \fI*c\fR and the
+length of that string is given by \fI*len\fR. The
+buffer's current pointer is advanced to point at the character
+following the string length, the encoded string, and the trailing
+\fBNULL\fR character.
+.PP
+\fBlwres_addr_parse()\fR extracts an address from the
+buffer \fIb\fR. The buffer's current pointer
+b->current is presumed to point at an encoded
+address: the address preceded by a 32-bit protocol family identifier
+and a 16-bit length field. The encoded address is copied to
+addr->address and
+addr->length indicates the size in bytes of
+the address that was copied. b->current is
+advanced to point at the next byte of available data in the buffer
+following the encoded address.
+.PP
+\fBlwres_getaddrsbyname()\fR
+and
+\fBlwres_getnamebyaddr()\fR
+use the
+\fBlwres_gnbaresponse_t\fR
+structure defined below:
+.sp
+.nf
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+.sp
+.fi
+The contents of this structure are not manipulated directly but
+they are controlled through the
+\fBlwres_gabn\fR(3)
+functions.
+.PP
+The lightweight resolver uses
+\fBlwres_getaddrsbyname()\fR to perform foward lookups.
+Hostname \fIname\fR is looked up using the resolver
+context \fIctx\fR for memory allocation.
+\fIaddrtypes\fR is a bitmask indicating which type of
+addresses are to be looked up. Current values for this bitmask are
+\fBLWRES_ADDRTYPE_V4\fR for IPv4 addresses and
+\fBLWRES_ADDRTYPE_V6\fR for IPv6 addresses. Results of the
+lookup are returned in \fI*structp\fR.
+.PP
+\fBlwres_getnamebyaddr()\fR performs reverse lookups.
+Resolver context \fIctx\fR is used for memory
+allocation. The address type is indicated by
+\fIaddrtype\fR: \fBLWRES_ADDRTYPE_V4\fR or
+\fBLWRES_ADDRTYPE_V6\fR. The address to be looked up is given
+by \fIaddr\fR and its length is
+\fIaddrlen\fR bytes. The result of the function call
+is made available through \fI*structp\fR.
+.SH "RETURN VALUES"
+.PP
+Successful calls to
+\fBlwres_string_parse()\fR
+and
+\fBlwres_addr_parse()\fR
+return
+LWRES_R_SUCCESS.
+Both functions return
+LWRES_R_FAILURE
+if the buffer is corrupt or
+LWRES_R_UNEXPECTEDEND
+if the buffer has less space than expected for the components of the
+encoded string or address.
+.PP
+\fBlwres_getaddrsbyname()\fR
+returns
+LWRES_R_SUCCESS
+on success and it returns
+LWRES_R_NOTFOUND
+if the hostname
+\fIname\fR
+could not be found.
+.PP
+LWRES_R_SUCCESS
+is returned by a successful call to
+\fBlwres_getnamebyaddr()\fR.
+.PP
+Both
+\fBlwres_getaddrsbyname()\fR
+and
+\fBlwres_getnamebyaddr()\fR
+return
+LWRES_R_NOMEMORY
+when memory allocation requests fail and
+LWRES_R_UNEXPECTEDEND
+if the buffers used for sending queries and receiving replies are too
+small.
+.SH "SEE ALSO"
+.PP
+\fBlwres_buffer\fR(3),
+\fBlwres_gabn\fR(3).
diff --git a/lib/liblwres/man/lwres_resutil.docbook b/lib/liblwres/man/lwres_resutil.docbook
new file mode 100644
index 000000000..72d6dc614
--- /dev/null
+++ b/lib/liblwres/man/lwres_resutil.docbook
@@ -0,0 +1,221 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<!--
+ - Copyright (C) 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: lwres_resutil.docbook,v 1.1 2004/03/15 20:35:25 as Exp $ -->
+
+<refentry>
+
+<refentryinfo>
+<date>Jun 30, 2000</date>
+</refentryinfo>
+
+<refmeta>
+ <refentrytitle>lwres_resutil</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>lwres_string_parse</refname>
+<refname>lwres_addr_parse</refname>
+<refname>lwres_getaddrsbyname</refname>
+<refname>lwres_getnamebyaddr</refname>
+<refpurpose>lightweight resolver utility functions</refpurpose>
+</refnamediv>
+<refsynopsisdiv>
+<funcsynopsis>
+<funcsynopsisinfo>#include &lt;lwres/lwres.h&gt;</funcsynopsisinfo>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_string_parse</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>char **c</paramdef>
+<paramdef>lwres_uint16_t *len</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_addr_parse</function></funcdef>
+<paramdef>lwres_buffer_t *b</paramdef>
+<paramdef>lwres_addr_t *addr</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_getaddrsbyname</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>const char *name</paramdef>
+<paramdef>lwres_uint32_t addrtypes</paramdef>
+<paramdef>lwres_gabnresponse_t **structp</paramdef>
+</funcprototype>
+<funcprototype>
+<funcdef>
+lwres_result_t
+<function>lwres_getnamebyaddr</function></funcdef>
+<paramdef>lwres_context_t *ctx</paramdef>
+<paramdef>lwres_uint32_t addrtype</paramdef>
+<paramdef>lwres_uint16_t addrlen</paramdef>
+<paramdef>const unsigned char *addr</paramdef>
+<paramdef>lwres_gnbaresponse_t **structp</paramdef>
+</funcprototype>
+</funcsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>DESCRIPTION</title>
+
+<para>
+<function>lwres_string_parse()</function> retrieves a DNS-encoded
+string starting the current pointer of lightweight resolver buffer
+<parameter>b</parameter>: i.e. <constant>b-&gt;current</constant>.
+When the function returns, the address of the first byte of the
+encoded string is returned via <parameter>*c</parameter> and the
+length of that string is given by <parameter>*len</parameter>. The
+buffer's current pointer is advanced to point at the character
+following the string length, the encoded string, and the trailing
+<type>NULL</type> character.
+</para>
+
+<para>
+<function>lwres_addr_parse()</function> extracts an address from the
+buffer <parameter>b</parameter>. The buffer's current pointer
+<constant>b-&gt;current</constant> is presumed to point at an encoded
+address: the address preceded by a 32-bit protocol family identifier
+and a 16-bit length field. The encoded address is copied to
+<constant>addr-&gt;address</constant> and
+<constant>addr-&gt;length</constant> indicates the size in bytes of
+the address that was copied. <constant>b-&gt;current</constant> is
+advanced to point at the next byte of available data in the buffer
+following the encoded address.
+</para>
+
+<para>
+<function>lwres_getaddrsbyname()</function>
+and
+<function>lwres_getnamebyaddr()</function>
+use the
+<type>lwres_gnbaresponse_t</type>
+structure defined below:
+<programlisting>
+typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;
+</programlisting>
+The contents of this structure are not manipulated directly but
+they are controlled through the
+<citerefentry>
+<refentrytitle>lwres_gabn</refentrytitle><manvolnum>3
+</manvolnum>
+</citerefentry>
+functions.
+</para>
+
+<para>
+The lightweight resolver uses
+<function>lwres_getaddrsbyname()</function> to perform foward lookups.
+Hostname <parameter>name</parameter> is looked up using the resolver
+context <parameter>ctx</parameter> for memory allocation.
+<parameter>addrtypes</parameter> is a bitmask indicating which type of
+addresses are to be looked up. Current values for this bitmask are
+<type>LWRES_ADDRTYPE_V4</type> for IPv4 addresses and
+<type>LWRES_ADDRTYPE_V6</type> for IPv6 addresses. Results of the
+lookup are returned in <parameter>*structp</parameter>.
+</para>
+
+<para>
+<function>lwres_getnamebyaddr()</function> performs reverse lookups.
+Resolver context <parameter>ctx</parameter> is used for memory
+allocation. The address type is indicated by
+<parameter>addrtype</parameter>: <type>LWRES_ADDRTYPE_V4</type> or
+<type>LWRES_ADDRTYPE_V6</type>. The address to be looked up is given
+by <parameter>addr</parameter> and its length is
+<parameter>addrlen</parameter> bytes. The result of the function call
+is made available through <parameter>*structp</parameter>.
+</para>
+</refsect1>
+
+<refsect1>
+<title>RETURN VALUES</title>
+<para>
+Successful calls to
+<function>lwres_string_parse()</function>
+and
+<function>lwres_addr_parse()</function>
+return
+<errorcode>LWRES_R_SUCCESS.</errorcode>
+Both functions return
+<errorcode>LWRES_R_FAILURE</errorcode>
+if the buffer is corrupt or
+<errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+if the buffer has less space than expected for the components of the
+encoded string or address.
+</para>
+<para>
+<function>lwres_getaddrsbyname()</function>
+returns
+<errorcode>LWRES_R_SUCCESS</errorcode>
+on success and it returns
+<errorcode>LWRES_R_NOTFOUND</errorcode>
+if the hostname
+<parameter>name</parameter>
+could not be found.
+</para>
+<para>
+<errorcode>LWRES_R_SUCCESS</errorcode>
+is returned by a successful call to
+<function>lwres_getnamebyaddr()</function>.
+</para>
+
+<para>
+Both
+<function>lwres_getaddrsbyname()</function>
+and
+<function>lwres_getnamebyaddr()</function>
+return
+<errorcode>LWRES_R_NOMEMORY</errorcode>
+when memory allocation requests fail and
+<errorcode>LWRES_R_UNEXPECTEDEND</errorcode>
+if the buffers used for sending queries and receiving replies are too
+small.
+</para>
+
+</refsect1>
+<refsect1>
+<title>SEE ALSO</title>
+<para>
+<citerefentry>
+<refentrytitle>lwres_buffer</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>,
+
+<citerefentry>
+<refentrytitle>lwres_gabn</refentrytitle><manvolnum>3</manvolnum>
+</citerefentry>.
+</para>
+
+</refsect1>
+</refentry>
diff --git a/lib/liblwres/man/lwres_resutil.html b/lib/liblwres/man/lwres_resutil.html
new file mode 100644
index 000000000..ae3a2f646
--- /dev/null
+++ b/lib/liblwres/man/lwres_resutil.html
@@ -0,0 +1,412 @@
+<!--
+ - Copyright (C) 2000, 2001 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ - INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ - FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+<HTML
+><HEAD
+><TITLE
+>lwres_resutil</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.61
+"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="AEN1"
+>lwres_resutil</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Name</H2
+>lwres_string_parse, lwres_addr_parse, lwres_getaddrsbyname, lwres_getnamebyaddr&nbsp;--&nbsp;lightweight resolver utility functions</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN14"
+></A
+><H2
+>Synopsis</H2
+><DIV
+CLASS="FUNCSYNOPSIS"
+><A
+NAME="AEN15"
+></A
+><P
+></P
+><PRE
+CLASS="FUNCSYNOPSISINFO"
+>#include &lt;lwres/lwres.h&gt;</PRE
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_string_parse</CODE
+>(lwres_buffer_t *b, char **c, lwres_uint16_t *len);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_addr_parse</CODE
+>(lwres_buffer_t *b, lwres_addr_t *addr);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_getaddrsbyname</CODE
+>(lwres_context_t *ctx, const char *name, lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp);</CODE
+></P
+><P
+><CODE
+><CODE
+CLASS="FUNCDEF"
+>lwres_result_t
+lwres_getnamebyaddr</CODE
+>(lwres_context_t *ctx, lwres_uint32_t addrtype, lwres_uint16_t addrlen, const unsigned char *addr, lwres_gnbaresponse_t **structp);</CODE
+></P
+><P
+></P
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN43"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_string_parse()</TT
+> retrieves a DNS-encoded
+string starting the current pointer of lightweight resolver buffer
+<TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>: i.e. <TT
+CLASS="CONSTANT"
+>b-&gt;current</TT
+>.
+When the function returns, the address of the first byte of the
+encoded string is returned via <TT
+CLASS="PARAMETER"
+><I
+>*c</I
+></TT
+> and the
+length of that string is given by <TT
+CLASS="PARAMETER"
+><I
+>*len</I
+></TT
+>. The
+buffer's current pointer is advanced to point at the character
+following the string length, the encoded string, and the trailing
+<SPAN
+CLASS="TYPE"
+>NULL</SPAN
+> character.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_addr_parse()</TT
+> extracts an address from the
+buffer <TT
+CLASS="PARAMETER"
+><I
+>b</I
+></TT
+>. The buffer's current pointer
+<TT
+CLASS="CONSTANT"
+>b-&gt;current</TT
+> is presumed to point at an encoded
+address: the address preceded by a 32-bit protocol family identifier
+and a 16-bit length field. The encoded address is copied to
+<TT
+CLASS="CONSTANT"
+>addr-&gt;address</TT
+> and
+<TT
+CLASS="CONSTANT"
+>addr-&gt;length</TT
+> indicates the size in bytes of
+the address that was copied. <TT
+CLASS="CONSTANT"
+>b-&gt;current</TT
+> is
+advanced to point at the next byte of available data in the buffer
+following the encoded address.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getaddrsbyname()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_getnamebyaddr()</TT
+>
+use the
+<SPAN
+CLASS="TYPE"
+>lwres_gnbaresponse_t</SPAN
+>
+structure defined below:
+<PRE
+CLASS="PROGRAMLISTING"
+>typedef struct {
+ lwres_uint32_t flags;
+ lwres_uint16_t naliases;
+ lwres_uint16_t naddrs;
+ char *realname;
+ char **aliases;
+ lwres_uint16_t realnamelen;
+ lwres_uint16_t *aliaslen;
+ lwres_addrlist_t addrs;
+ void *base;
+ size_t baselen;
+} lwres_gabnresponse_t;</PRE
+>
+The contents of this structure are not manipulated directly but
+they are controlled through the
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_gabn</SPAN
+>(3)</SPAN
+>
+functions.</P
+><P
+>The lightweight resolver uses
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrsbyname()</TT
+> to perform foward lookups.
+Hostname <TT
+CLASS="PARAMETER"
+><I
+>name</I
+></TT
+> is looked up using the resolver
+context <TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+> for memory allocation.
+<TT
+CLASS="PARAMETER"
+><I
+>addrtypes</I
+></TT
+> is a bitmask indicating which type of
+addresses are to be looked up. Current values for this bitmask are
+<SPAN
+CLASS="TYPE"
+>LWRES_ADDRTYPE_V4</SPAN
+> for IPv4 addresses and
+<SPAN
+CLASS="TYPE"
+>LWRES_ADDRTYPE_V6</SPAN
+> for IPv6 addresses. Results of the
+lookup are returned in <TT
+CLASS="PARAMETER"
+><I
+>*structp</I
+></TT
+>.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getnamebyaddr()</TT
+> performs reverse lookups.
+Resolver context <TT
+CLASS="PARAMETER"
+><I
+>ctx</I
+></TT
+> is used for memory
+allocation. The address type is indicated by
+<TT
+CLASS="PARAMETER"
+><I
+>addrtype</I
+></TT
+>: <SPAN
+CLASS="TYPE"
+>LWRES_ADDRTYPE_V4</SPAN
+> or
+<SPAN
+CLASS="TYPE"
+>LWRES_ADDRTYPE_V6</SPAN
+>. The address to be looked up is given
+by <TT
+CLASS="PARAMETER"
+><I
+>addr</I
+></TT
+> and its length is
+<TT
+CLASS="PARAMETER"
+><I
+>addrlen</I
+></TT
+> bytes. The result of the function call
+is made available through <TT
+CLASS="PARAMETER"
+><I
+>*structp</I
+></TT
+>.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN84"
+></A
+><H2
+>RETURN VALUES</H2
+><P
+>Successful calls to
+<TT
+CLASS="FUNCTION"
+>lwres_string_parse()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_addr_parse()</TT
+>
+return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS.</SPAN
+>
+Both functions return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_FAILURE</SPAN
+>
+if the buffer is corrupt or
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_UNEXPECTEDEND</SPAN
+>
+if the buffer has less space than expected for the components of the
+encoded string or address.</P
+><P
+><TT
+CLASS="FUNCTION"
+>lwres_getaddrsbyname()</TT
+>
+returns
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>
+on success and it returns
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_NOTFOUND</SPAN
+>
+if the hostname
+<TT
+CLASS="PARAMETER"
+><I
+>name</I
+></TT
+>
+could not be found.</P
+><P
+><SPAN
+CLASS="ERRORCODE"
+>LWRES_R_SUCCESS</SPAN
+>
+is returned by a successful call to
+<TT
+CLASS="FUNCTION"
+>lwres_getnamebyaddr()</TT
+>.</P
+><P
+>Both
+<TT
+CLASS="FUNCTION"
+>lwres_getaddrsbyname()</TT
+>
+and
+<TT
+CLASS="FUNCTION"
+>lwres_getnamebyaddr()</TT
+>
+return
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_NOMEMORY</SPAN
+>
+when memory allocation requests fail and
+<SPAN
+CLASS="ERRORCODE"
+>LWRES_R_UNEXPECTEDEND</SPAN
+>
+if the buffers used for sending queries and receiving replies are too
+small.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN105"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_buffer</SPAN
+>(3)</SPAN
+>,
+
+<SPAN
+CLASS="CITEREFENTRY"
+><SPAN
+CLASS="REFENTRYTITLE"
+>lwres_gabn</SPAN
+>(3)</SPAN
+>.</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/lib/liblwres/unix/include/lwres/net.h b/lib/liblwres/unix/include/lwres/net.h
new file mode 100644
index 000000000..cb17700cd
--- /dev/null
+++ b/lib/liblwres/unix/include/lwres/net.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: net.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef LWRES_NET_H
+#define LWRES_NET_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * Basic Networking Types
+ *
+ * This module is responsible for defining the following basic networking
+ * types:
+ *
+ * struct in_addr
+ * struct in6_addr
+ * struct sockaddr
+ * struct sockaddr_in
+ * struct sockaddr_in6
+ *
+ * It ensures that the AF_ and PF_ macros are defined.
+ *
+ * It declares ntoh[sl]() and hton[sl]().
+ *
+ * It declares lwres_net_aton(), lwres_net_ntop(), and lwres_net_pton().
+ *
+ * It ensures that INADDR_LOOPBACK, INADDR_ANY and IN6ADDR_ANY_INIT
+ * are defined.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <lwres/platform.h> /* Required for LWRES_PLATFORM_*. */
+
+#include <sys/types.h>
+#include <sys/socket.h> /* Contractual promise. */
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include <netinet/in.h> /* Contractual promise. */
+#include <arpa/inet.h> /* Contractual promise. */
+#ifdef LWRES_PLATFORM_NEEDNETINETIN6H
+#include <netinet/in6.h> /* Required on UnixWare. */
+#endif
+#ifdef LWRES_PLATFORM_NEEDNETINET6IN6H
+#include <netinet6/in6.h> /* Required on BSD/OS for in6_pktinfo. */
+#endif
+
+#include <lwres/lang.h>
+
+#ifndef LWRES_PLATFORM_HAVEIPV6
+#include <lwres/ipv6.h> /* Contractual promise. */
+#endif
+
+#ifdef LWRES_PLATFORM_HAVEINADDR6
+#define in6_addr in_addr6 /* Required for pre RFC2133 implementations. */
+#endif
+
+/*
+ * Required for some pre RFC2133 implementations.
+ * IN6ADDR_ANY_INIT and IN6ADDR_LOOPBACK_INIT were added in
+ * draft-ietf-ipngwg-bsd-api-04.txt or draft-ietf-ipngwg-bsd-api-05.txt.
+ * If 's6_addr' is defined then assume that there is a union and three
+ * levels otherwise assume two levels required.
+ */
+#ifndef IN6ADDR_ANY_INIT
+#ifdef s6_addr
+#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+#else
+#define IN6ADDR_ANY_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }
+#endif
+#endif
+
+#ifndef IN6ADDR_LOOPBACK_INIT
+#ifdef s6_addr
+#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+#else
+#define IN6ADDR_LOOPBACK_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } }
+#endif
+#endif
+
+#ifndef AF_INET6
+#define AF_INET6 99
+#endif
+
+#ifndef PF_INET6
+#define PF_INET6 AF_INET6
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001UL
+#endif
+
+LWRES_LANG_BEGINDECLS
+
+const char *
+lwres_net_ntop(int af, const void *src, char *dst, size_t size);
+
+int
+lwres_net_pton(int af, const char *src, void *dst);
+
+int
+lwres_net_aton(const char *cp, struct in_addr *addr);
+
+LWRES_LANG_ENDDECLS
+
+#endif /* LWRES_NET_H */
diff --git a/lib/liblwres/version.c b/lib/liblwres/version.c
new file mode 100644
index 000000000..ce0380d23
--- /dev/null
+++ b/lib/liblwres/version.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: version.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+char lwres_version[] = VERSION;
+
+unsigned int lwres_libinterface = LIBINTERFACE;
+unsigned int lwres_librevision = LIBREVISION;
+unsigned int lwres_libage = LIBAGE;
diff --git a/linux/Documentation/Configure.help.fs2_0.patch b/linux/Documentation/Configure.help.fs2_0.patch
new file mode 100644
index 000000000..370b8944e
--- /dev/null
+++ b/linux/Documentation/Configure.help.fs2_0.patch
@@ -0,0 +1,65 @@
+--- linux/Documentation/Configure.help.orig Tue Jan 9 16:29:20 2001
++++ linux/Documentation/Configure.help Fri Aug 9 14:47:14 2002
+@@ -4979,2 +4979,62 @@
+
++IP Security Protocol (IPSEC) (EXPERIMENTAL)
++CONFIG_IPSEC
++ This unit is experimental code.
++ Pick 'y' for static linking, 'm' for module support or 'n' for none.
++ This option adds support for network layer packet encryption and/or
++ authentication with participating hosts. The standards start with:
++ RFCs 2411, 2407 and 2401. Others are mentioned where they refer to
++ specific features below. There are more pending which can be
++ found at: ftp://ftp.ietf.org/internet-drafts/draft-ietf-ipsec-*.
++ A description of each document can also be found at:
++ http://ietf.org/ids.by.wg/ipsec.html.
++ Their charter can be found at:
++ http://www.ietf.org/html.charters/ipsec-charter.html
++ Snapshots and releases of the current work can be found at:
++ http://www.freeswan.org/
++
++IPSEC: IP-in-IP encapsulation
++CONFIG_IPSEC_IPIP
++ This option provides support for tunnel mode IPSEC. It is recommended
++ to enable this.
++
++IPSEC: Authentication Header
++CONFIG_IPSEC_AH
++ This option provides support for the IPSEC Authentication Header
++ (IP protocol 51) which provides packet layer sender and content
++ authentication. It is recommended to enable this. RFC2402
++
++HMAC-MD5 algorithm
++CONFIG_IPSEC_AUTH_HMAC_MD5
++ Provides support for authentication using the HMAC MD5
++ algorithm with 96 bits of hash used as the authenticator. RFC2403
++
++HMAC-SHA1 algorithm
++CONFIG_IPSEC_AUTH_HMAC_SHA1
++ Provides support for Authentication Header using the HMAC SHA1
++ algorithm with 96 bits of hash used as the authenticator. RFC2404
++
++IPSEC: Encapsulating Security Payload
++CONFIG_IPSEC_ESP
++ This option provides support for the IPSEC Encapsulation Security
++ Payload (IP protocol 50) which provides packet layer content
++ hiding. It is recommended to enable this. RFC2406
++
++3DES algorithm
++CONFIG_IPSEC_ENC_3DES
++ Provides support for Encapsulation Security Payload protocol, using
++ the triple DES encryption algorithm. RFC2451
++
++IPSEC Debugging Option
++CONFIG_IPSEC_DEBUG
++ Enables IPSEC kernel debugging. It is further controlled by the
++ user space utility 'klipsdebug'.
++
++IPSEC Regression Testing option
++CONFIG_IPSEC_REGRESS
++ Enables IPSEC regression testing. Creates a number of switches in
++ /proc/sys/net/ipsec which cause various failure modes in KLIPS.
++ For more details see FreeSWAN source under
++ testing/doc/regression_options.txt.
++
+ # need an empty line after last entry, for sed script in Configure.
diff --git a/linux/Documentation/Configure.help.fs2_2.patch b/linux/Documentation/Configure.help.fs2_2.patch
new file mode 100644
index 000000000..52a133410
--- /dev/null
+++ b/linux/Documentation/Configure.help.fs2_2.patch
@@ -0,0 +1,70 @@
+--- /a3/kernel_sources/linux-2.2.20/Documentation/Configure.help Fri Nov 2 11:39:05 2001
++++ linux2.2/Documentation/Configure.help Mon Jul 29 15:42:26 2002
+@@ -15237,5 +15237,66 @@
+
+-#
++
++IP Security Protocol (IPSEC) (EXPERIMENTAL)
++CONFIG_IPSEC
++ This unit is experimental code.
++ Pick 'y' for static linking, 'm' for module support or 'n' for none.
++ This option adds support for network layer packet encryption and/or
++ authentication with participating hosts. The standards start with:
++ RFCs 2411, 2407 and 2401. Others are mentioned where they refer to
++ specific features below. There are more pending which can be found
++ at: ftp://ftp.ietf.org/internet-drafts/draft-ietf-ipsec-*.
++ A description of each document can also be found at:
++ http://ietf.org/ids.by.wg/ipsec.html.
++ Their charter can be found at:
++ http://www.ietf.org/html.charters/ipsec-charter.html
++ Snapshots and releases of the current work can be found at:
++ http://www.freeswan.org/
++
++IPSEC: IP-in-IP encapsulation
++CONFIG_IPSEC_IPIP
++ This option provides support for tunnel mode IPSEC. It is recommended
++ to enable this.
++
++IPSEC: Authentication Header
++CONFIG_IPSEC_AH
++ This option provides support for the IPSEC Authentication Header
++ (IP protocol 51) which provides packet layer sender and content
++ authentication. It is recommended to enable this. RFC2402
++
++HMAC-MD5 algorithm
++CONFIG_IPSEC_AUTH_HMAC_MD5
++ Provides support for authentication using the HMAC MD5
++ algorithm with 96 bits of hash used as the authenticator. RFC2403
++
++HMAC-SHA1 algorithm
++CONFIG_IPSEC_AUTH_HMAC_SHA1
++ Provides support for Authentication Header using the HMAC SHA1
++ algorithm with 96 bits of hash used as the authenticator. RFC2404
++
++IPSEC: Encapsulating Security Payload
++CONFIG_IPSEC_ESP
++ This option provides support for the IPSEC Encapsulation Security
++ Payload (IP protocol 50) which provides packet layer content
++ hiding. It is recommended to enable this. RFC2406
++
++3DES algorithm
++CONFIG_IPSEC_ENC_3DES
++ Provides support for Encapsulation Security Payload protocol, using
++ the triple DES encryption algorithm. RFC2451
++
++IPSEC Debugging Option
++CONFIG_IPSEC_DEBUG
++ Enables IPSEC kernel debugging. It is further controlled by the
++ user space utility 'klipsdebug'.
++
++IPSEC Regression Testing option
++CONFIG_IPSEC_REGRESS
++ Enables IPSEC regression testing. Creates a number of switches in
++ /proc/sys/net/ipsec which cause various failure modes in KLIPS.
++ For more details see FreeSWAN source under
++ testing/doc/regression_options.txt.
++
++#
+ # A couple of things I keep forgetting:
+ # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
+ # Intel, IRQ, Linux, MSDOS, NetWare, NetWinder, NFS,
diff --git a/linux/Documentation/Configure.help.fs2_4.patch b/linux/Documentation/Configure.help.fs2_4.patch
new file mode 100644
index 000000000..863d69c35
--- /dev/null
+++ b/linux/Documentation/Configure.help.fs2_4.patch
@@ -0,0 +1,69 @@
+--- linux/Documentation/Configure.help.orig Fri Dec 21 12:41:53 2001
++++ linux/Documentation/Configure.help Mon Jul 29 16:35:32 2002
+@@ -24237,5 +24237,65 @@
+
+-#
++IP Security Protocol (IPSEC) (EXPERIMENTAL)
++CONFIG_IPSEC
++ This unit is experimental code.
++ Pick 'y' for static linking, 'm' for module support or 'n' for none.
++ This option adds support for network layer packet encryption and/or
++ authentication with participating hosts. The standards start with:
++ RFCs 2411, 2407 and 2401. Others are mentioned where they refer to
++ specific features below. There are more pending which can be found
++ at: ftp://ftp.ietf.org/internet-drafts/draft-ietf-ipsec-*.
++ A description of each document can also be found at:
++ http://ietf.org/ids.by.wg/ipsec.html.
++ Their charter can be found at:
++ http://www.ietf.org/html.charters/ipsec-charter.html
++ Snapshots and releases of the current work can be found at:
++ http://www.freeswan.org/
++
++IPSEC: IP-in-IP encapsulation
++CONFIG_IPSEC_IPIP
++ This option provides support for tunnel mode IPSEC. It is recommended
++ to enable this.
++
++IPSEC: Authentication Header
++CONFIG_IPSEC_AH
++ This option provides support for the IPSEC Authentication Header
++ (IP protocol 51) which provides packet layer sender and content
++ authentication. It is recommended to enable this. RFC2402
++
++HMAC-MD5 algorithm
++CONFIG_IPSEC_AUTH_HMAC_MD5
++ Provides support for authentication using the HMAC MD5
++ algorithm with 96 bits of hash used as the authenticator. RFC2403
++
++HMAC-SHA1 algorithm
++CONFIG_IPSEC_AUTH_HMAC_SHA1
++ Provides support for Authentication Header using the HMAC SHA1
++ algorithm with 96 bits of hash used as the authenticator. RFC2404
++
++IPSEC: Encapsulating Security Payload
++CONFIG_IPSEC_ESP
++ This option provides support for the IPSEC Encapsulation Security
++ Payload (IP protocol 50) which provides packet layer content
++ hiding. It is recommended to enable this. RFC2406
++
++3DES algorithm
++CONFIG_IPSEC_ENC_3DES
++ Provides support for Encapsulation Security Payload protocol, using
++ the triple DES encryption algorithm. RFC2451
++
++IPSEC Debugging Option
++CONFIG_IPSEC_DEBUG
++ Enables IPSEC kernel debugging. It is further controlled by the
++ user space utility 'klipsdebug'.
++
++IPSEC Regression Testing option
++CONFIG_IPSEC_REGRESS
++ Enables IPSEC regression testing. Creates a number of switches in
++ /proc/sys/net/ipsec which cause various failure modes in KLIPS.
++ For more details see FreeSWAN source under
++ testing/doc/regression_options.txt.
++
++#
+ # A couple of things I keep forgetting:
+ # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
+ # Intel, IRQ, ISDN, Linux, MSDOS, NetWare, NetWinder,
diff --git a/linux/Makefile b/linux/Makefile
new file mode 100644
index 000000000..b5715105f
--- /dev/null
+++ b/linux/Makefile
@@ -0,0 +1,32 @@
+# FreeS/WAN subdir makefile
+# Copyright (C) 1998-2001 Henry Spencer.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:25 as Exp $
+
+FREESWANSRCDIR=..
+#SUBDIRS=net/ipsec
+
+include $(FREESWANSRCDIR)/Makefile.inc
+
+def:
+ @echo "Please read doc/intro.html or INSTALL before running make"
+ @false
+
+cleanall distclean mostlyclean realclean install programs checkprograms check clean spotless modules install_file_list:
+ @true
+
+# @for d in $(SUBDIRS); \
+# do \
+# (cd $$d && $(MAKE) TOPDIR=${KERNELSRC} FREESWANSRCDIR=$(FREESWANSRCDIR)/.. $@ ) || exit 1 ; \
+# done
+
diff --git a/linux/README.freeswan b/linux/README.freeswan
new file mode 100644
index 000000000..7d868e4cb
--- /dev/null
+++ b/linux/README.freeswan
@@ -0,0 +1,177 @@
+*
+* RCSID $Id: README.freeswan,v 1.1 2004/03/15 20:35:25 as Exp $
+*
+
+ ****************************************
+ * IPSEC for Linux, Release 2.xx series *
+ ****************************************
+
+
+
+1. Files
+
+The contents of linux/net/ipsec/ (see below) join the linux kernel source tree.
+as provided for higher up.
+
+The programs/ directory contains the user-level utilities which you need
+to run IPSEC. See the top-level top/INSTALL to compile and install them.
+
+The test/ directory contains test scripts.
+
+The doc/ directory contains -- what else -- documentation.
+
+1.1. Kernel files
+
+The following are found in net/ipsec/:
+
+Makefile The Makefile
+Config.in The configuration script for make menuconfig
+defconfig Configuration defaults for first time.
+
+radij.c General-purpose radix-tree operations
+
+ipcomp.c IPCOMP interface code.
+
+pfkey_v2.c PF_KEYv2 socket interface code.
+pfkey_v2_parser.c PF_KEYv2 message parsing and processing code.
+
+ipsec_init.c Initialization code, /proc interface.
+ipsec_radij.c Interface with the radix tree code.
+ipsec_netlink.c Interface with the netlink code.
+ipsec_xform.c Routines and structures common to transforms.
+ipsec_tunnel.c The outgoing packet processing code.
+ipsec_rcv.c The incoming packet processing code.
+ipsec_md5c.c Somewhat modified RSADSI MD5 C code.
+ipsec_sha1.c Somewhat modified Steve Reid SHA-1 C code.
+
+sysctl_net_ipsec.c /proc/sys/net/ipsec/* variable definitions.
+
+version.c symbolic link to project version.
+
+radij.h Headers for radij.c
+
+ipcomp.h Headers used by IPCOMP code.
+
+ipsec_radij.h Interface with the radix tree code.
+ipsec_netlink.h Headers used by the netlink interface.
+ipsec_encap.h Headers defining encapsulation structures.
+ipsec_xform.h Transform headers.
+ipsec_tunnel.h Headers used by tunneling code.
+ipsec_ipe4.h Headers for the IP-in-IP code.
+ipsec_ah.h Headers common to AH transforms.
+ipsec_md5h.h RSADSI MD5 headers.
+ipsec_sha1.h SHA-1 headers.
+ipsec_esp.h Headers common to ESP transfroms.
+ipsec_rcv.h Headers for incoming packet processing code.
+
+1.2. User-level files.
+
+The following are found in utils/:
+
+eroute.c Create an "extended route" source code
+spi.c Set up Security Associations source code
+spigrp.c Link SPIs together source code.
+tncfg.c Configure the tunneling features of the virtual interface
+ source code
+klipsdebug.c Set/reset klips debugging features source code.
+version.c symbolic link to project version.
+
+eroute.8 Create an "extended route" manual page
+spi.8 Set up Security Associations manual page
+spigrp.8 Link SPIs together manual page
+tncfg.8 Configure the tunneling features of the virtual interface
+ manual page
+klipsdebug.8 Set/reset klips debugging features manual page
+
+eroute.5 /proc/net/ipsec_eroute format manual page
+spi.5 /proc/net/ipsec_spi format manual page
+spigrp.5 /proc/net/ipsec_spigrp format manual page
+tncfg.5 /proc/net/ipsec_tncfg format manual page
+klipsdebug.5 /proc/net/ipsec_klipsdebug format manual page
+version.5 /proc/net/ipsec_version format manual page
+pf_key.5 /proc/net/pf_key format manual page
+
+Makefile Utilities makefile.
+
+*.8 Manpages for the respective utils.
+
+
+1.3. Test files
+
+The test scripts are locate in testing/ and and documentation is found
+at doc/src/umltesting.html. Automated testing via "make check" is available
+provided that the User-Mode-Linux patches are available.
+
+*
+* $Log: README.freeswan,v $
+* Revision 1.1 2004/03/15 20:35:25 as
+* added files from freeswan-2.04-x509-1.5.3
+*
+* Revision 1.11 2002/07/28 23:00:14 mcr
+* removed docs on "test" directory.
+* some slight "updates"
+*
+* Revision 1.10 2002/05/06 21:34:19 mcr
+* Moved from linux/README,v
+*
+* Revision 1.9 2002/04/24 07:36:35 mcr
+* Moved from ./klips/README,v
+*
+* Revision 1.8 2000/11/06 05:42:58 rgb
+* Updated file list (had not been done in 2 years?).
+*
+* Revision 1.7 2000/08/21 17:30:09 rgb
+* Remove any references to src/.
+*
+* Revision 1.6 1999/04/06 04:54:22 rgb
+* Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+* patch shell fixes.
+*
+* Revision 1.5 1998/11/25 04:54:34 rgb
+* Updated files section to include newer transforms and other files.
+*
+* Revision 1.4 1998/05/01 03:47:17 rgb
+* Minor cleanup of utils filenames overlooked in major overhaul.
+*
+* Revision 1.3 1998/05/01 03:40:31 rgb
+* Major overhaul.
+* Removed install/initialise section with pointers to top-level INSTALL.txt.
+* Updated filelists and providing descriptions of all files.
+* Removed usage example and moved it to doc/*_setup.txt.
+*
+* Revision 1.2 1998/04/09 03:01:13 henry
+* INSTALL.txt moves up, loses its installation instructions, and turns
+* into the klips README.
+*
+* Revision 1.1.1.1 1998/04/08 05:35:13 henry
+* RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+*
+*
+* Revision 0.7 rgb
+* Cleaned up several transmission bugs.
+*
+* Revision 0.6 1997/09? ak
+* Hooked in esp des-md5-96.
+* Added copyrights.
+*
+* Revision 0.5 1997/06/03 04:28:46 ji
+* Added transport mode.
+* Added esp 3des-md5-96.
+*
+* Revision 0.4 1997/01/14 21:35:31 ji
+* Added new transforms.
+* Cleaned up the user-level programs.
+*
+* Revision 0.3 1996/11/20 11:59:33 ji
+* *** empty log message ***
+*
+*
+* New in this release (0.3; works with the 2.0.24 kernel)
+*
+* > Cleaned up a fair amount of crud.
+* > Fixed truncated names of /proc/net entries.
+* > Made RCS versioning visible to the external release.
+* > Rationalized debugging facilities.
+* > Rationalized untar directory structure.
+* > Fixed non-incrementing IV in DES-CBC
+* > Cleaned up this file a bit and provided additional examples
diff --git a/linux/crypto/ciphers/des/COPYRIGHT b/linux/crypto/ciphers/des/COPYRIGHT
new file mode 100644
index 000000000..5469e1e46
--- /dev/null
+++ b/linux/crypto/ciphers/des/COPYRIGHT
@@ -0,0 +1,50 @@
+Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+All rights reserved.
+
+This package is an DES implementation written by Eric Young (eay@cryptsoft.com).
+The implementation was written so as to conform with MIT's libdes.
+
+This library is free for commercial and non-commercial use as long as
+the following conditions are aheared to. The following conditions
+apply to all code found in this distribution.
+
+Copyright remains Eric Young's, and as such any Copyright notices in
+the code are not to be removed.
+If this package is used in a product, Eric Young should be given attribution
+as the author of that the SSL library. This can be in the form of a textual
+message at program startup or in documentation (online or textual) provided
+with the package.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by Eric Young (eay@cryptsoft.com)
+
+THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+The license and distribution terms for any publically available version or
+derivative of this code cannot be changed. i.e. this code cannot simply be
+copied and put under another distrubution license
+[including the GNU Public License.]
+
+The reason behind this being stated in this direct manner is past
+experience in code simply being copied and the attribution removed
+from it and then being distributed as part of other packages. This
+implementation was a non-trivial and unpaid effort.
diff --git a/linux/crypto/ciphers/des/INSTALL b/linux/crypto/ciphers/des/INSTALL
new file mode 100644
index 000000000..32457d775
--- /dev/null
+++ b/linux/crypto/ciphers/des/INSTALL
@@ -0,0 +1,69 @@
+Check the CC and CFLAGS lines in the makefile
+
+If your C library does not support the times(3) function, change the
+#define TIMES to
+#undef TIMES in speed.c
+If it does, check the HZ value for the times(3) function.
+If your system does not define CLK_TCK it will be assumed to
+be 100.0.
+
+If possible use gcc v 2.7.?
+Turn on the maximum optimising (normally '-O3 -fomit-frame-pointer' for gcc)
+In recent times, some system compilers give better performace.
+
+type 'make'
+
+run './destest' to check things are ok.
+run './rpw' to check the tty code for reading passwords works.
+run './speed' to see how fast those optimisations make the library run :-)
+run './des_opts' to determin the best compile time options.
+
+The output from des_opts should be put in the makefile options and des_enc.c
+should be rebuilt. For 64 bit computers, do not use the DES_PTR option.
+For the DEC Alpha, edit des.h and change DES_LONG to 'unsigned int'
+and then you can use the 'DES_PTR' option.
+
+The file options.txt has the options listed for best speed on quite a
+few systems. Look and the options (UNROLL, PTR, RISC2 etc) and then
+turn on the relevent option in the Makefile
+
+There are some special Makefile targets that make life easier.
+make cc - standard cc build
+make gcc - standard gcc build
+make x86-elf - x86 assembler (elf), linux-elf.
+make x86-out - x86 assembler (a.out), FreeBSD
+make x86-solaris- x86 assembler
+make x86-bsdi - x86 assembler (a.out with primative assembler).
+
+If at all possible use the assembler (for Windows NT/95, use
+asm/win32.obj to link with). The x86 assembler is very very fast.
+
+A make install will by default install
+libdes.a in /usr/local/lib/libdes.a
+des in /usr/local/bin/des
+des_crypt.man in /usr/local/man/man3/des_crypt.3
+des.man in /usr/local/man/man1/des.1
+des.h in /usr/include/des.h
+
+des(1) should be compatible with sunOS's but I have been unable to
+test it.
+
+These routines should compile on MSDOS, most 32bit and 64bit version
+of Unix (BSD and SYSV) and VMS, without modification.
+The only problems should be #include files that are in the wrong places.
+
+These routines can be compiled under MSDOS.
+I have successfully encrypted files using des(1) under MSDOS and then
+decrypted the files on a SparcStation.
+I have been able to compile and test the routines with
+Microsoft C v 5.1 and Turbo C v 2.0.
+The code in this library is in no way optimised for the 16bit
+operation of MSDOS.
+
+When building for glibc, ignore all of the above and just unpack into
+glibc-1.??/des and then gmake as per normal.
+
+As a final note on performace. Certain CPUs like sparcs and Alpha often give
+a %10 speed difference depending on the link order. It is rather anoying
+when one program reports 'x' DES encrypts a second and another reports
+'x*0.9' the speed.
diff --git a/linux/crypto/ciphers/des/Makefile.objs b/linux/crypto/ciphers/des/Makefile.objs
new file mode 100644
index 000000000..4cef95963
--- /dev/null
+++ b/linux/crypto/ciphers/des/Makefile.objs
@@ -0,0 +1,20 @@
+obj-$(CONFIG_IPSEC_ENC_3DES) += cbc_enc.o
+#obj-$(CONFIG_IPSEC_ENC_3DES) += des_opts.o
+obj-$(CONFIG_IPSEC_ENC_3DES) += ecb_enc.o
+#obj-$(CONFIG_IPSEC_ENC_3DES) += fcrypt.o
+obj-$(CONFIG_IPSEC_ENC_3DES) += set_key.o
+
+ifeq ($(strip ${SUBARCH}),)
+SUBARCH:=${ARCH}
+endif
+
+ifeq (${SUBARCH},i386)
+obj-$(CONFIG_IPSEC_ENC_3DES) += dx86unix.o
+else
+obj-$(CONFIG_IPSEC_ENC_3DES) += des_enc.o
+endif
+
+
+
+
+
diff --git a/linux/crypto/ciphers/des/README b/linux/crypto/ciphers/des/README
new file mode 100644
index 000000000..621a5ab46
--- /dev/null
+++ b/linux/crypto/ciphers/des/README
@@ -0,0 +1,54 @@
+
+ libdes, Version 4.01 10-Jan-97
+
+ Copyright (c) 1997, Eric Young
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms specified in COPYRIGHT.
+
+--
+The primary ftp site for this library is
+ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/libdes-x.xx.tar.gz
+libdes is now also shipped with SSLeay. Primary ftp site of
+ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL/SSLeay-x.x.x.tar.gz
+
+The best way to build this library is to build it as part of SSLeay.
+
+This kit builds a DES encryption library and a DES encryption program.
+It supports ecb, cbc, ofb, cfb, triple ecb, triple cbc, triple ofb,
+triple cfb, desx, and MIT's pcbc encryption modes and also has a fast
+implementation of crypt(3).
+It contains support routines to read keys from a terminal,
+generate a random key, generate a key from an arbitrary length string,
+read/write encrypted data from/to a file descriptor.
+
+The implementation was written so as to conform with the manual entry
+for the des_crypt(3) library routines from MIT's project Athena.
+
+destest should be run after compilation to test the des routines.
+rpw should be run after compilation to test the read password routines.
+The des program is a replacement for the sun des command. I believe it
+conforms to the sun version.
+
+The Imakefile is setup for use in the kerberos distribution.
+
+These routines are best compiled with gcc or any other good
+optimising compiler.
+Just turn you optimiser up to the highest settings and run destest
+after the build to make sure everything works.
+
+I believe these routines are close to the fastest and most portable DES
+routines that use small lookup tables (4.5k) that are publicly available.
+The fcrypt routine is faster than ufc's fcrypt (when compiling with
+gcc2 -O2) on the sparc 2 (1410 vs 1270) but is not so good on other machines
+(on a sun3/260 168 vs 336). It is a function of CPU on chip cache size.
+[ 10-Jan-97 and a function of an incorrect speed testing program in
+ ufc which gave much better test figures that reality ].
+
+It is worth noting that on sparc and Alpha CPUs, performance of the DES
+library can vary by upto %10 due to the positioning of files after application
+linkage.
+
+Eric Young (eay@cryptsoft.com)
+
diff --git a/linux/crypto/ciphers/des/README.freeswan b/linux/crypto/ciphers/des/README.freeswan
new file mode 100644
index 000000000..40874d5f8
--- /dev/null
+++ b/linux/crypto/ciphers/des/README.freeswan
@@ -0,0 +1,33 @@
+The only changes the FreeS/WAN project has made to libdes-lite 4.04b are:
+
+We #ifdef-ed the declaration of DES_LONG in des.h, so it's more efficient
+on the Alpha, instead of just noting the issue in a comment.
+
+We #ifdef-ed out the des_options() function in ecb_enc.c, because we don't
+use it, and its call to sprintf() can cause subtle difficulties when KLIPS
+is built as a module (depending on details of Linux configuration options).
+
+We changed some instances of CC=$(CC) in the Makefile to CC='$(CC)' to make
+it cope better with Linux kernel Makefile stupidities, and took out an
+explicit CC=gcc (unwise on systems with strange compilers).
+
+We deleted some references to <stdio.h> and <stdlib.h>, and a declaration
+of one function found only in the full libdes (not in libdes-lite), to
+avoid dragging in bits of stdio/stdlib unnecessarily. (Our thanks to Hans
+Schultz for spotting this and pointing out the fixes.)
+
+We deleted a couple of .obj files in the asm subdirectory, which appear to
+have been included in the original library by accident.
+
+We have added an include of our Makefile.inc file, to permit overriding
+things like choice of compiler (although the libdes Makefile would
+probably need some work to make this effective).
+
+
+
+Note that Eric Young is no longer at the email address listed in these
+files, and is (alas) no longer working on free crypto software.
+
+
+
+This file is RCSID $Id: README.freeswan,v 1.1 2004/03/15 20:35:25 as Exp $
diff --git a/linux/crypto/ciphers/des/VERSION b/linux/crypto/ciphers/des/VERSION
new file mode 100644
index 000000000..345035195
--- /dev/null
+++ b/linux/crypto/ciphers/des/VERSION
@@ -0,0 +1,406 @@
+Version 4.04
+ Fixed a few tests in destest. Also added x86 assember for
+ des_ncbc_encrypt() which is the standard cbc mode function.
+ This makes a very very large performace difference.
+ Ariel Glenn ariel@columbia.edu reports that the terminal
+ 'turn echo off' can return (errno == EINVAL) under solaris
+ when redirection is used. So I now catch that as well as ENOTTY.
+
+
+Version 4.03
+ Left a static out of enc_write.c, which caused to buffer to be
+ continiously malloc()ed. Does anyone use these functions? I keep
+ on feeling like removing them since I only had these in there
+ for a version of kerberised login. Anyway, this was pointed out
+ by Theo de Raadt <deraadt@cvs.openbsd.org>
+ The 'n' bit ofb code was wrong, it was not shifting the shift
+ register. It worked correctly for n == 64. Thanks to
+ Gigi Ankeny <Gigi.Ankeny@Eng.Sun.COM> for pointing this one out.
+
+Version 4.02
+ I was doing 'if (memcmp(weak_keys[i],key,sizeof(key)) == 0)'
+ when checking for weak keys which is wrong :-(, pointed out by
+ Markus F.X.J. Oberhumer <markus.oberhumer@jk.uni-linz.ac.at>.
+
+Version 4.01
+ Even faster inner loop in the DES assembler for x86 and a modification
+ for IP/FP which is faster on x86. Both of these changes are
+ from Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>. His
+ changes make the assembler run %40 faster on a pentium. This is just
+ a case of getting the instruction sequence 'just right'.
+ All credit to 'Svend' :-)
+ Quite a few special x86 'make' targets.
+ A libdes-l (lite) distribution.
+
+Version 4.00
+ After a bit of a pause, I'll up the major version number since this
+ is mostly a performace release. I've added x86 assembler and
+ added more options for performance. A %28 speedup for gcc
+ on a pentium and the assembler is a %50 speedup.
+ MIPS CPU's, sparc and Alpha are the main CPU's with speedups.
+ Run des_opts to work out which options should be used.
+ DES_RISC1/DES_RISC2 use alternative inner loops which use
+ more registers but should give speedups on any CPU that does
+ dual issue (pentium). DES_UNROLL unrolls the inner loop,
+ which costs in code size.
+
+Version 3.26
+ I've finally removed one of the shifts in D_ENCRYPT. This
+ meant I've changed the des_SPtrans table (spr.h), the set_key()
+ function and some things in des_enc.c. This has definitly
+ made things faster :-). I've known about this one for some
+ time but I've been too lazy to follow it up :-).
+ Noticed that in the D_ENCRYPT() macro, we can just do L^=(..)^(..)^..
+ instead of L^=((..)|(..)|(..).. This should save a register at
+ least.
+ Assember for x86. The file to replace is des_enc.c, which is replaced
+ by one of the assembler files found in asm. Look at des/asm/readme
+ for more info.
+
+ /* Modification to fcrypt so it can be compiled to support
+ HPUX 10.x's long password format, define -DLONGCRYPT to use this.
+ Thanks to Jens Kupferschmidt <bt1cu@hpboot.rz.uni-leipzig.de>. */
+
+ SIGWINCH case put in des_read_passwd() so the function does not
+ 'exit' if this function is recieved.
+
+Version 3.25 17/07/96
+ Modified read_pwd.c so that stdin can be read if not a tty.
+ Thanks to Jeff Barber <jeffb@issl.atl.hp.com> for the patches.
+ des_init_random_number_generator() shortened due to VMS linker
+ limits.
+ Added RSA's DESX cbc mode. It is a form of cbc encryption, with 2
+ 8 byte quantites xored before and after encryption.
+ des_xcbc_encryption() - the name is funny to preserve the des_
+ prefix on all functions.
+
+Version 3.24 20/04/96
+ The DES_PTR macro option checked and used by SSLeay configuration
+
+Version 3.23 11/04/96
+ Added DES_LONG. If defined to 'unsigned int' on the DEC Alpha,
+ it gives a %20 speedup :-)
+ Fixed the problem with des.pl under perl5. The patches were
+ sent by Ed Kubaitis (ejk@uiuc.edu).
+ if fcrypt.c, changed values to handle illegal salt values the way
+ normal crypt() implementations do. Some programs apparently use
+ them :-(. The patch was sent by Bjorn Gronvall <bg@sics.se>
+
+Version 3.22 29/11/95
+ Bug in des(1), an error with the uuencoding stuff when the
+ 'data' is small, thanks to Geoff Keating <keagchon@mehta.anu.edu.au>
+ for the patch.
+
+Version 3.21 22/11/95
+ After some emailing back and forth with
+ Colin Plumb <colin@nyx10.cs.du.edu>, I've tweaked a few things
+ and in a future version I will probably put in some of the
+ optimisation he suggested for use with the DES_USE_PTR option.
+ Extra routines from Mark Murray <mark@grondar.za> for use in
+ freeBSD. They mostly involve random number generation for use
+ with kerberos. They involve evil machine specific system calls
+ etc so I would normally suggest pushing this stuff into the
+ application and/or using RAND_seed()/RAND_bytes() if you are
+ using this DES library as part of SSLeay.
+ Redone the read_pw() function so that it is cleaner and
+ supports termios, thanks to Sameer Parekh <sameer@c2.org>
+ for the initial patches for this.
+ Renamed 3ecb_encrypt() to ecb3_encrypt(). This has been
+ done just to make things more consistent.
+ I have also now added triple DES versions of cfb and ofb.
+
+Version 3.20
+ Damn, Damn, Damn, as pointed out by Mike_Spreitzer.PARC@xerox.com,
+ my des_random_seed() function was only copying 4 bytes of the
+ passed seed into the init structure. It is now fixed to copy 8.
+ My own suggestion is to used something like MD5 :-)
+
+Version 3.19
+ While looking at my code one day, I though, why do I keep on
+ calling des_encrypt(in,out,ks,enc) when every function that
+ calls it has in and out the same. So I dropped the 'out'
+ parameter, people should not be using this function.
+
+Version 3.18 30/08/95
+ Fixed a few bit with the distribution and the filenames.
+ 3.17 had been munged via a move to DOS and back again.
+ NO CODE CHANGES
+
+Version 3.17 14/07/95
+ Fixed ede3 cbc which I had broken in 3.16. I have also
+ removed some unneeded variables in 7-8 of the routines.
+
+Version 3.16 26/06/95
+ Added des_encrypt2() which does not use IP/FP, used by triple
+ des routines. Tweaked things a bit elsewhere. %13 speedup on
+ sparc and %6 on a R4400 for ede3 cbc mode.
+
+Version 3.15 06/06/95
+ Added des_ncbc_encrypt(), it is des_cbc mode except that it is
+ 'normal' and copies the new iv value back over the top of the
+ passed parameter.
+ CHANGED des_ede3_cbc_encrypt() so that it too now overwrites
+ the iv. THIS WILL BREAK EXISTING CODE, but since this function
+ only new, I feel I can change it, not so with des_cbc_encrypt :-(.
+ I need to update the documentation.
+
+Version 3.14 31/05/95
+ New release upon the world, as part of my SSL implementation.
+ New copyright and usage stuff. Basically free for all to use
+ as long as you say it came from me :-)
+
+Version 3.13 31/05/95
+ A fix in speed.c, if HZ is not defined, I set it to 100.0
+ which is reasonable for most unixes except SunOS 4.x.
+ I now have a #ifdef sun but timing for SunOS 4.x looked very
+ good :-(. At my last job where I used SunOS 4.x, it was
+ defined to be 60.0 (look at the old INSTALL documentation), at
+ the last release had it changed to 100.0 since I now work with
+ Solaris2 and SVR4 boxes.
+ Thanks to Rory Chisholm <rchishol@math.ethz.ch> for pointing this
+ one out.
+
+Version 3.12 08/05/95
+ As pointed out by The Crypt Keeper <tck@bend.UCSD.EDU>,
+ my D_ENCRYPT macro in crypt() had an un-necessary variable.
+ It has been removed.
+
+Version 3.11 03/05/95
+ Added des_ede3_cbc_encrypt() which is cbc mode des with 3 keys
+ and one iv. It is a standard and I needed it for my SSL code.
+ It makes more sense to use this for triple DES than
+ 3cbc_encrypt(). I have also added (or should I say tested :-)
+ cfb64_encrypt() which is cfb64 but it will encrypt a partial
+ number of bytes - 3 bytes in 3 bytes out. Again this is for
+ my SSL library, as a form of encryption to use with SSL
+ telnet.
+
+Version 3.10 22/03/95
+ Fixed a bug in 3cbc_encrypt() :-(. When making repeated calls
+ to cbc3_encrypt, the 2 iv values that were being returned to
+ be used in the next call were reversed :-(.
+ Many thanks to Bill Wade <wade@Stoner.COM> for pointing out
+ this error.
+
+Version 3.09 01/02/95
+ Fixed des_random_key to far more random, it was rather feeble
+ with regards to picking the initial seed. The problem was
+ pointed out by Olaf Kirch <okir@monad.swb.de>.
+
+Version 3.08 14/12/94
+ Added Makefile.PL so libdes can be built into perl5.
+ Changed des_locl.h so RAND is always defined.
+
+Version 3.07 05/12/94
+ Added GNUmake and stuff so the library can be build with
+ glibc.
+
+Version 3.06 30/08/94
+ Added rpc_enc.c which contains _des_crypt. This is for use in
+ secure_rpc v 4.0
+ Finally fixed the cfb_enc problems.
+ Fixed a few parameter parsing bugs in des (-3 and -b), thanks
+ to Rob McMillan <R.McMillan@its.gu.edu.au>
+
+Version 3.05 21/04/94
+ for unsigned long l; gcc does not produce ((l>>34) == 0)
+ This causes bugs in cfb_enc.
+ Thanks to Hadmut Danisch <danisch@ira.uka.de>
+
+Version 3.04 20/04/94
+ Added a version number to des.c and libdes.a
+
+Version 3.03 12/01/94
+ Fixed a bug in non zero iv in 3cbc_enc.
+
+Version 3.02 29/10/93
+ I now work in a place where there are 6+ architectures and 14+
+ OS versions :-).
+ Fixed TERMIO definition so the most sys V boxes will work :-)
+
+Release upon comp.sources.misc
+Version 3.01 08/10/93
+ Added des_3cbc_encrypt()
+
+Version 3.00 07/10/93
+ Fixed up documentation.
+ quad_cksum definitely compatible with MIT's now.
+
+Version 2.30 24/08/93
+ Triple DES now defaults to triple cbc but can do triple ecb
+ with the -b flag.
+ Fixed some MSDOS uuen/uudecoding problems, thanks to
+ Added prototypes.
+
+Version 2.22 29/06/93
+ Fixed a bug in des_is_weak_key() which stopped it working :-(
+ thanks to engineering@MorningStar.Com.
+
+Version 2.21 03/06/93
+ des(1) with no arguments gives quite a bit of help.
+ Added -c (generate ckecksum) flag to des(1).
+ Added -3 (triple DES) flag to des(1).
+ Added cfb and ofb routines to the library.
+
+Version 2.20 11/03/93
+ Added -u (uuencode) flag to des(1).
+ I have been playing with byte order in quad_cksum to make it
+ compatible with MIT's version. All I can say is avid this
+ function if possible since MIT's output is endian dependent.
+
+Version 2.12 14/10/92
+ Added MSDOS specific macro in ecb_encrypt which gives a %70
+ speed up when the code is compiled with turbo C.
+
+Version 2.11 12/10/92
+ Speedup in set_key (recoding of PC-1)
+ I now do it in 47 simple operations, down from 60.
+ Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
+ for motivating me to look for a faster system :-)
+ The speedup is probably less that 1% but it is still 13
+ instructions less :-).
+
+Version 2.10 06/10/92
+ The code now works on the 64bit ETA10 and CRAY without modifications or
+ #defines. I believe the code should work on any machine that
+ defines long, int or short to be 8 bytes long.
+ Thanks to Shabbir J. Safdar (shabby@mentor.cc.purdue.edu)
+ for helping me fix the code to run on 64bit machines (he had
+ access to an ETA10).
+ Thanks also to John Fletcher <john_fletcher@lccmail.ocf.llnl.gov>
+ for testing the routines on a CRAY.
+ read_password.c has been renamed to read_passwd.c
+ string_to_key.c has been renamed to string2key.c
+
+Version 2.00 14/09/92
+ Made mods so that the library should work on 64bit CPU's.
+ Removed all my uchar and ulong defs. To many different
+ versions of unix define them in their header files in too many
+ different combinations :-)
+ IRIX - Sillicon Graphics mods (mostly in read_password.c).
+ Thanks to Andrew Daviel (advax@erich.triumf.ca)
+
+Version 1.99 26/08/92
+ Fixed a bug or 2 in enc_read.c
+ Fixed a bug in enc_write.c
+ Fixed a pseudo bug in fcrypt.c (very obscure).
+
+Version 1.98 31/07/92
+ Support for the ETA10. This is a strange machine that defines
+ longs and ints as 8 bytes and shorts as 4 bytes.
+ Since I do evil things with long * that assume that they are 4
+ bytes. Look in the Makefile for the option to compile for
+ this machine. quad_cksum appears to have problems but I
+ will don't have the time to fix it right now, and this is not
+ a function that uses DES and so will not effect the main uses
+ of the library.
+
+Version 1.97 20/05/92 eay
+ Fixed the Imakefile and made some changes to des.h to fix some
+ problems when building this package with Kerberos v 4.
+
+Version 1.96 18/05/92 eay
+ Fixed a small bug in string_to_key() where problems could
+ occur if des_check_key was set to true and the string
+ generated a weak key.
+
+Patch2 posted to comp.sources.misc
+Version 1.95 13/05/92 eay
+ Added an alternative version of the D_ENCRYPT macro in
+ ecb_encrypt and fcrypt. Depending on the compiler, one version or the
+ other will be faster. This was inspired by
+ Dana How <how@isl.stanford.edu>, and her pointers about doing the
+ *(ulong *)((uchar *)ptr+(value&0xfc))
+ vs
+ ptr[value&0x3f]
+ to stop the C compiler doing a <<2 to convert the long array index.
+
+Version 1.94 05/05/92 eay
+ Fixed an incompatibility between my string_to_key and the MIT
+ version. When the key is longer than 8 chars, I was wrapping
+ with a different method. To use the old version, define
+ OLD_STR_TO_KEY in the makefile. Thanks to
+ viktor@newsu.shearson.com (Viktor Dukhovni).
+
+Version 1.93 28/04/92 eay
+ Fixed the VMS mods so that echo is now turned off in
+ read_password. Thanks again to brennan@coco.cchs.su.oz.AU.
+ MSDOS support added. The routines can be compiled with
+ Turbo C (v2.0) and MSC (v5.1). Make sure MSDOS is defined.
+
+Patch1 posted to comp.sources.misc
+Version 1.92 13/04/92 eay
+ Changed D_ENCRYPT so that the rotation of R occurs outside of
+ the loop. This required rotating all the longs in sp.h (now
+ called spr.h). Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ speed.c has been changed so it will work without SIGALRM. If
+ times(3) is not present it will try to use ftime() instead.
+
+Version 1.91 08/04/92 eay
+ Added -E/-D options to des(1) so it can use string_to_key.
+ Added SVR4 mods suggested by witr@rwwa.COM
+ Added VMS mods suggested by brennan@coco.cchs.su.oz.AU. If
+ anyone knows how to turn of tty echo in VMS please tell me or
+ implement it yourself :-).
+ Changed FILE *IN/*OUT to *DES_IN/*DES_OUT since it appears VMS
+ does not like IN/OUT being used.
+
+Libdes posted to comp.sources.misc
+Version 1.9 24/03/92 eay
+ Now contains a fast small crypt replacement.
+ Added des(1) command.
+ Added des_rw_mode so people can use cbc encryption with
+ enc_read and enc_write.
+
+Version 1.8 15/10/91 eay
+ Bug in cbc_cksum.
+ Many thanks to Keith Reynolds (keithr@sco.COM) for pointing this
+ one out.
+
+Version 1.7 24/09/91 eay
+ Fixed set_key :-)
+ set_key is 4 times faster and takes less space.
+ There are a few minor changes that could be made.
+
+Version 1.6 19/09/1991 eay
+ Finally go IP and FP finished.
+ Now I need to fix set_key.
+ This version is quite a bit faster that 1.51
+
+Version 1.52 15/06/1991 eay
+ 20% speedup in ecb_encrypt by changing the E bit selection
+ to use 2 32bit words. This also required modification of the
+ sp table. There is still a way to speedup the IP and IP-1
+ (hints from outer@sq.com) still working on this one :-(.
+
+Version 1.51 07/06/1991 eay
+ Faster des_encrypt by loop unrolling
+ Fixed bug in quad_cksum.c (thanks to hughes@logos.ucs.indiana.edu)
+
+Version 1.50 28/05/1991 eay
+ Optimised the code a bit more for the sparc. I have improved the
+ speed of the inner des_encrypt by speeding up the initial and
+ final permutations.
+
+Version 1.40 23/10/1990 eay
+ Fixed des_random_key, it did not produce a random key :-(
+
+Version 1.30 2/10/1990 eay
+ Have made des_quad_cksum the same as MIT's, the full package
+ should be compatible with MIT's
+ Have tested on a DECstation 3100
+ Still need to fix des_set_key (make it faster).
+ Does des_cbc_encrypts at 70.5k/sec on a 3100.
+
+Version 1.20 18/09/1990 eay
+ Fixed byte order dependencies.
+ Fixed (I hope) all the word alignment problems.
+ Speedup in des_ecb_encrypt.
+
+Version 1.10 11/09/1990 eay
+ Added des_enc_read and des_enc_write.
+ Still need to fix des_quad_cksum.
+ Still need to document des_enc_read and des_enc_write.
+
+Version 1.00 27/08/1990 eay
+
diff --git a/linux/crypto/ciphers/des/asm/crypt586.pl b/linux/crypto/ciphers/des/asm/crypt586.pl
new file mode 100644
index 000000000..297e38dec
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/crypt586.pl
@@ -0,0 +1,204 @@
+#!/usr/bin/perl
+#
+# The inner loop instruction sequence and the IP/FP modifications are from
+# Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>
+# I've added the stuff needed for crypt() but I've not worried about making
+# things perfect.
+#
+
+push(@INC,"perlasm","../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"crypt586.pl");
+
+$L="edi";
+$R="esi";
+
+&external_label("des_SPtrans");
+&fcrypt_body("fcrypt_body");
+&asm_finish();
+
+sub fcrypt_body
+ {
+ local($name,$do_ip)=@_;
+
+ &function_begin($name,"EXTRN _des_SPtrans:DWORD");
+
+ &comment("");
+ &comment("Load the 2 words");
+ $ks="ebp";
+
+ &xor( $L, $L);
+ &xor( $R, $R);
+ &mov($ks,&wparam(1));
+
+ &push(25); # add a variable
+
+ &set_label("start");
+ for ($i=0; $i<16; $i+=2)
+ {
+ &comment("");
+ &comment("Round $i");
+ &D_ENCRYPT($i,$L,$R,$i*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
+
+ &comment("");
+ &comment("Round ".sprintf("%d",$i+1));
+ &D_ENCRYPT($i+1,$R,$L,($i+1)*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
+ }
+ &mov("ebx", &swtmp(0));
+ &mov("eax", $L);
+ &dec("ebx");
+ &mov($L, $R);
+ &mov($R, "eax");
+ &mov(&swtmp(0), "ebx");
+ &jnz(&label("start"));
+
+ &comment("");
+ &comment("FP");
+ &mov("edx",&wparam(0));
+
+ &FP_new($R,$L,"eax",3);
+ &mov(&DWP(0,"edx","",0),"eax");
+ &mov(&DWP(4,"edx","",0),$L);
+
+ &pop("ecx"); # remove variable
+
+ &function_end($name);
+ }
+
+sub D_ENCRYPT
+ {
+ local($r,$L,$R,$S,$ks,$desSP,$u,$tmp1,$tmp2,$t)=@_;
+
+ &mov( $u, &wparam(2)); # 2
+ &mov( $t, $R);
+ &shr( $t, 16); # 1
+ &mov( $tmp2, &wparam(3)); # 2
+ &xor( $t, $R); # 1
+
+ &and( $u, $t); # 2
+ &and( $t, $tmp2); # 2
+
+ &mov( $tmp1, $u);
+ &shl( $tmp1, 16); # 1
+ &mov( $tmp2, $t);
+ &shl( $tmp2, 16); # 1
+ &xor( $u, $tmp1); # 2
+ &xor( $t, $tmp2); # 2
+ &mov( $tmp1, &DWP(&n2a($S*4),$ks,"",0)); # 2
+ &xor( $u, $tmp1);
+ &mov( $tmp2, &DWP(&n2a(($S+1)*4),$ks,"",0)); # 2
+ &xor( $u, $R);
+ &xor( $t, $R);
+ &xor( $t, $tmp2);
+
+ &and( $u, "0xfcfcfcfc" ); # 2
+ &xor( $tmp1, $tmp1); # 1
+ &and( $t, "0xcfcfcfcf" ); # 2
+ &xor( $tmp2, $tmp2);
+ &movb( &LB($tmp1), &LB($u) );
+ &movb( &LB($tmp2), &HB($u) );
+ &rotr( $t, 4 );
+ &mov( $ks, &DWP(" $desSP",$tmp1,"",0));
+ &movb( &LB($tmp1), &LB($t) );
+ &xor( $L, $ks);
+ &mov( $ks, &DWP("0x200+$desSP",$tmp2,"",0));
+ &xor( $L, $ks);
+ &movb( &LB($tmp2), &HB($t) );
+ &shr( $u, 16);
+ &mov( $ks, &DWP("0x100+$desSP",$tmp1,"",0));
+ &xor( $L, $ks);
+ &movb( &LB($tmp1), &HB($u) );
+ &shr( $t, 16);
+ &mov( $ks, &DWP("0x300+$desSP",$tmp2,"",0));
+ &xor( $L, $ks);
+ &mov( $ks, &wparam(1));
+ &movb( &LB($tmp2), &HB($t) );
+ &and( $u, "0xff" );
+ &and( $t, "0xff" );
+ &mov( $tmp1, &DWP("0x600+$desSP",$tmp1,"",0));
+ &xor( $L, $tmp1);
+ &mov( $tmp1, &DWP("0x700+$desSP",$tmp2,"",0));
+ &xor( $L, $tmp1);
+ &mov( $tmp1, &DWP("0x400+$desSP",$u,"",0));
+ &xor( $L, $tmp1);
+ &mov( $tmp1, &DWP("0x500+$desSP",$t,"",0));
+ &xor( $L, $tmp1);
+ }
+
+sub n2a
+ {
+ sprintf("%d",$_[0]);
+ }
+
+# now has a side affect of rotating $a by $shift
+sub R_PERM_OP
+ {
+ local($a,$b,$tt,$shift,$mask,$last)=@_;
+
+ &rotl( $a, $shift ) if ($shift != 0);
+ &mov( $tt, $a );
+ &xor( $a, $b );
+ &and( $a, $mask );
+ if ($notlast eq $b)
+ {
+ &xor( $b, $a );
+ &xor( $tt, $a );
+ }
+ else
+ {
+ &xor( $tt, $a );
+ &xor( $b, $a );
+ }
+ &comment("");
+ }
+
+sub IP_new
+ {
+ local($l,$r,$tt,$lr)=@_;
+
+ &R_PERM_OP($l,$r,$tt, 4,"0xf0f0f0f0",$l);
+ &R_PERM_OP($r,$tt,$l,20,"0xfff0000f",$l);
+ &R_PERM_OP($l,$tt,$r,14,"0x33333333",$r);
+ &R_PERM_OP($tt,$r,$l,22,"0x03fc03fc",$r);
+ &R_PERM_OP($l,$r,$tt, 9,"0xaaaaaaaa",$r);
+
+ if ($lr != 3)
+ {
+ if (($lr-3) < 0)
+ { &rotr($tt, 3-$lr); }
+ else { &rotl($tt, $lr-3); }
+ }
+ if ($lr != 2)
+ {
+ if (($lr-2) < 0)
+ { &rotr($r, 2-$lr); }
+ else { &rotl($r, $lr-2); }
+ }
+ }
+
+sub FP_new
+ {
+ local($l,$r,$tt,$lr)=@_;
+
+ if ($lr != 2)
+ {
+ if (($lr-2) < 0)
+ { &rotl($r, 2-$lr); }
+ else { &rotr($r, $lr-2); }
+ }
+ if ($lr != 3)
+ {
+ if (($lr-3) < 0)
+ { &rotl($l, 3-$lr); }
+ else { &rotr($l, $lr-3); }
+ }
+
+ &R_PERM_OP($l,$r,$tt, 0,"0xaaaaaaaa",$r);
+ &R_PERM_OP($tt,$r,$l,23,"0x03fc03fc",$r);
+ &R_PERM_OP($l,$r,$tt,10,"0x33333333",$l);
+ &R_PERM_OP($r,$tt,$l,18,"0xfff0000f",$l);
+ &R_PERM_OP($l,$tt,$r,12,"0xf0f0f0f0",$r);
+ &rotr($tt , 4);
+ }
+
diff --git a/linux/crypto/ciphers/des/asm/des-586.pl b/linux/crypto/ciphers/des/asm/des-586.pl
new file mode 100644
index 000000000..7f2e09fa7
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/des-586.pl
@@ -0,0 +1,251 @@
+#!/usr/bin/perl
+#
+# The inner loop instruction sequence and the IP/FP modifications are from
+# Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>
+#
+
+push(@INC,"perlasm","../../perlasm");
+require "x86asm.pl";
+require "cbc.pl";
+require "desboth.pl";
+
+# base code is in microsft
+# op dest, source
+# format.
+#
+
+&asm_init($ARGV[0],"des-586.pl");
+
+$L="edi";
+$R="esi";
+
+&external_label("des_SPtrans");
+&des_encrypt("des_encrypt",1);
+&des_encrypt("des_encrypt2",0);
+&des_encrypt3("des_encrypt3",1);
+&des_encrypt3("des_decrypt3",0);
+&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",0,4,5,3,5,-1);
+&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",0,6,7,3,4,5);
+
+&asm_finish();
+
+sub des_encrypt
+ {
+ local($name,$do_ip)=@_;
+
+ &function_begin_B($name,"EXTRN _des_SPtrans:DWORD");
+
+ &push("esi");
+ &push("edi");
+
+ &comment("");
+ &comment("Load the 2 words");
+ $ks="ebp";
+
+ if ($do_ip)
+ {
+ &mov($R,&wparam(0));
+ &xor( "ecx", "ecx" );
+
+ &push("ebx");
+ &push("ebp");
+
+ &mov("eax",&DWP(0,$R,"",0));
+ &mov("ebx",&wparam(2)); # get encrypt flag
+ &mov($L,&DWP(4,$R,"",0));
+ &comment("");
+ &comment("IP");
+ &IP_new("eax",$L,$R,3);
+ }
+ else
+ {
+ &mov("eax",&wparam(0));
+ &xor( "ecx", "ecx" );
+
+ &push("ebx");
+ &push("ebp");
+
+ &mov($R,&DWP(0,"eax","",0));
+ &mov("ebx",&wparam(2)); # get encrypt flag
+ &rotl($R,3);
+ &mov($L,&DWP(4,"eax","",0));
+ &rotl($L,3);
+ }
+
+ &mov( $ks, &wparam(1) );
+ &cmp("ebx","0");
+ &je(&label("start_decrypt"));
+
+ for ($i=0; $i<16; $i+=2)
+ {
+ &comment("");
+ &comment("Round $i");
+ &D_ENCRYPT($i,$L,$R,$i*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
+
+ &comment("");
+ &comment("Round ".sprintf("%d",$i+1));
+ &D_ENCRYPT($i+1,$R,$L,($i+1)*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
+ }
+ &jmp(&label("end"));
+
+ &set_label("start_decrypt");
+
+ for ($i=15; $i>0; $i-=2)
+ {
+ &comment("");
+ &comment("Round $i");
+ &D_ENCRYPT(15-$i,$L,$R,$i*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
+ &comment("");
+ &comment("Round ".sprintf("%d",$i-1));
+ &D_ENCRYPT(15-$i+1,$R,$L,($i-1)*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
+ }
+
+ &set_label("end");
+
+ if ($do_ip)
+ {
+ &comment("");
+ &comment("FP");
+ &mov("edx",&wparam(0));
+ &FP_new($L,$R,"eax",3);
+
+ &mov(&DWP(0,"edx","",0),"eax");
+ &mov(&DWP(4,"edx","",0),$R);
+ }
+ else
+ {
+ &comment("");
+ &comment("Fixup");
+ &rotr($L,3); # r
+ &mov("eax",&wparam(0));
+ &rotr($R,3); # l
+ &mov(&DWP(0,"eax","",0),$L);
+ &mov(&DWP(4,"eax","",0),$R);
+ }
+
+ &pop("ebp");
+ &pop("ebx");
+ &pop("edi");
+ &pop("esi");
+ &ret();
+
+ &function_end_B($name);
+ }
+
+sub D_ENCRYPT
+ {
+ local($r,$L,$R,$S,$ks,$desSP,$u,$tmp1,$tmp2,$t)=@_;
+
+ &mov( $u, &DWP(&n2a($S*4),$ks,"",0));
+ &xor( $tmp1, $tmp1);
+ &mov( $t, &DWP(&n2a(($S+1)*4),$ks,"",0));
+ &xor( $u, $R);
+ &xor( $t, $R);
+ &and( $u, "0xfcfcfcfc" );
+ &and( $t, "0xcfcfcfcf" );
+ &movb( &LB($tmp1), &LB($u) );
+ &movb( &LB($tmp2), &HB($u) );
+ &rotr( $t, 4 );
+ &mov( $ks, &DWP(" $desSP",$tmp1,"",0));
+ &movb( &LB($tmp1), &LB($t) );
+ &xor( $L, $ks);
+ &mov( $ks, &DWP("0x200+$desSP",$tmp2,"",0));
+ &xor( $L, $ks); ######
+ &movb( &LB($tmp2), &HB($t) );
+ &shr( $u, 16);
+ &mov( $ks, &DWP("0x100+$desSP",$tmp1,"",0));
+ &xor( $L, $ks); ######
+ &movb( &LB($tmp1), &HB($u) );
+ &shr( $t, 16);
+ &mov( $ks, &DWP("0x300+$desSP",$tmp2,"",0));
+ &xor( $L, $ks);
+ &mov( $ks, &wparam(1) );
+ &movb( &LB($tmp2), &HB($t) );
+ &and( $u, "0xff" );
+ &and( $t, "0xff" );
+ &mov( $tmp1, &DWP("0x600+$desSP",$tmp1,"",0));
+ &xor( $L, $tmp1);
+ &mov( $tmp1, &DWP("0x700+$desSP",$tmp2,"",0));
+ &xor( $L, $tmp1);
+ &mov( $tmp1, &DWP("0x400+$desSP",$u,"",0));
+ &xor( $L, $tmp1);
+ &mov( $tmp1, &DWP("0x500+$desSP",$t,"",0));
+ &xor( $L, $tmp1);
+ }
+
+sub n2a
+ {
+ sprintf("%d",$_[0]);
+ }
+
+# now has a side affect of rotating $a by $shift
+sub R_PERM_OP
+ {
+ local($a,$b,$tt,$shift,$mask,$last)=@_;
+
+ &rotl( $a, $shift ) if ($shift != 0);
+ &mov( $tt, $a );
+ &xor( $a, $b );
+ &and( $a, $mask );
+ if (!$last eq $b)
+ {
+ &xor( $b, $a );
+ &xor( $tt, $a );
+ }
+ else
+ {
+ &xor( $tt, $a );
+ &xor( $b, $a );
+ }
+ &comment("");
+ }
+
+sub IP_new
+ {
+ local($l,$r,$tt,$lr)=@_;
+
+ &R_PERM_OP($l,$r,$tt, 4,"0xf0f0f0f0",$l);
+ &R_PERM_OP($r,$tt,$l,20,"0xfff0000f",$l);
+ &R_PERM_OP($l,$tt,$r,14,"0x33333333",$r);
+ &R_PERM_OP($tt,$r,$l,22,"0x03fc03fc",$r);
+ &R_PERM_OP($l,$r,$tt, 9,"0xaaaaaaaa",$r);
+
+ if ($lr != 3)
+ {
+ if (($lr-3) < 0)
+ { &rotr($tt, 3-$lr); }
+ else { &rotl($tt, $lr-3); }
+ }
+ if ($lr != 2)
+ {
+ if (($lr-2) < 0)
+ { &rotr($r, 2-$lr); }
+ else { &rotl($r, $lr-2); }
+ }
+ }
+
+sub FP_new
+ {
+ local($l,$r,$tt,$lr)=@_;
+
+ if ($lr != 2)
+ {
+ if (($lr-2) < 0)
+ { &rotl($r, 2-$lr); }
+ else { &rotr($r, $lr-2); }
+ }
+ if ($lr != 3)
+ {
+ if (($lr-3) < 0)
+ { &rotl($l, 3-$lr); }
+ else { &rotr($l, $lr-3); }
+ }
+
+ &R_PERM_OP($l,$r,$tt, 0,"0xaaaaaaaa",$r);
+ &R_PERM_OP($tt,$r,$l,23,"0x03fc03fc",$r);
+ &R_PERM_OP($l,$r,$tt,10,"0x33333333",$l);
+ &R_PERM_OP($r,$tt,$l,18,"0xfff0000f",$l);
+ &R_PERM_OP($l,$tt,$r,12,"0xf0f0f0f0",$r);
+ &rotr($tt , 4);
+ }
+
diff --git a/linux/crypto/ciphers/des/asm/des686.pl b/linux/crypto/ciphers/des/asm/des686.pl
new file mode 100644
index 000000000..cf1a82fb5
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/des686.pl
@@ -0,0 +1,230 @@
+#!/usr/bin/perl
+
+$prog="des686.pl";
+
+# base code is in microsft
+# op dest, source
+# format.
+#
+
+# WILL NOT WORK ANYMORE WITH desboth.pl
+require "desboth.pl";
+
+if ( ($ARGV[0] eq "elf"))
+ { require "x86unix.pl"; }
+elsif ( ($ARGV[0] eq "a.out"))
+ { $aout=1; require "x86unix.pl"; }
+elsif ( ($ARGV[0] eq "sol"))
+ { $sol=1; require "x86unix.pl"; }
+elsif ( ($ARGV[0] eq "cpp"))
+ { $cpp=1; require "x86unix.pl"; }
+elsif ( ($ARGV[0] eq "win32"))
+ { require "x86ms.pl"; }
+else
+ {
+ print STDERR <<"EOF";
+Pick one target type from
+ elf - linux, FreeBSD etc
+ a.out - old linux
+ sol - x86 solaris
+ cpp - format so x86unix.cpp can be used
+ win32 - Windows 95/Windows NT
+EOF
+ exit(1);
+ }
+
+&comment("Don't even think of reading this code");
+&comment("It was automatically generated by $prog");
+&comment("Which is a perl program used to generate the x86 assember for");
+&comment("any of elf, a.out, Win32, or Solaris");
+&comment("It can be found in SSLeay 0.6.5+ or in libdes 3.26+");
+&comment("eric <eay\@cryptsoft.com>");
+&comment("");
+
+&file("dx86xxxx");
+
+$L="edi";
+$R="esi";
+
+&des_encrypt("des_encrypt",1);
+&des_encrypt("des_encrypt2",0);
+
+&des_encrypt3("des_encrypt3",1);
+&des_encrypt3("des_decrypt3",0);
+
+&file_end();
+
+sub des_encrypt
+ {
+ local($name,$do_ip)=@_;
+
+ &function_begin($name,"EXTRN _des_SPtrans:DWORD");
+
+ &comment("");
+ &comment("Load the 2 words");
+ &mov("eax",&wparam(0));
+ &mov($L,&DWP(0,"eax","",0));
+ &mov($R,&DWP(4,"eax","",0));
+
+ $ksp=&wparam(1);
+
+ if ($do_ip)
+ {
+ &comment("");
+ &comment("IP");
+ &IP_new($L,$R,"eax");
+ }
+
+ &comment("");
+ &comment("fixup rotate");
+ &rotl($R,3);
+ &rotl($L,3);
+ &exch($L,$R);
+
+ &comment("");
+ &comment("load counter, key_schedule and enc flag");
+ &mov("eax",&wparam(2)); # get encrypt flag
+ &mov("ebp",&wparam(1)); # get ks
+ &cmp("eax","0");
+ &je(&label("start_decrypt"));
+
+ # encrypting part
+
+ for ($i=0; $i<16; $i+=2)
+ {
+ &comment("");
+ &comment("Round $i");
+ &D_ENCRYPT($L,$R,$i*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
+
+ &comment("");
+ &comment("Round ".sprintf("%d",$i+1));
+ &D_ENCRYPT($R,$L,($i+1)*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
+ }
+ &jmp(&label("end"));
+
+ &set_label("start_decrypt");
+
+ for ($i=15; $i>0; $i-=2)
+ {
+ &comment("");
+ &comment("Round $i");
+ &D_ENCRYPT($L,$R,$i*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
+ &comment("");
+ &comment("Round ".sprintf("%d",$i-1));
+ &D_ENCRYPT($R,$L,($i-1)*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
+ }
+
+ &set_label("end");
+
+ &comment("");
+ &comment("Fixup");
+ &rotr($L,3); # r
+ &rotr($R,3); # l
+
+ if ($do_ip)
+ {
+ &comment("");
+ &comment("FP");
+ &FP_new($R,$L,"eax");
+ }
+
+ &mov("eax",&wparam(0));
+ &mov(&DWP(0,"eax","",0),$L);
+ &mov(&DWP(4,"eax","",0),$R);
+
+ &function_end($name);
+ }
+
+
+# The logic is to load R into 2 registers and operate on both at the same time.
+# We also load the 2 R's into 2 more registers so we can do the 'move word down a byte'
+# while also masking the other copy and doing a lookup. We then also accumulate the
+# L value in 2 registers then combine them at the end.
+sub D_ENCRYPT
+ {
+ local($L,$R,$S,$ks,$desSP,$u,$t,$tmp1,$tmp2,$tmp3)=@_;
+
+ &mov( $u, &DWP(&n2a($S*4),$ks,"",0));
+ &mov( $t, &DWP(&n2a(($S+1)*4),$ks,"",0));
+ &xor( $u, $R );
+ &xor( $t, $R );
+ &rotr( $t, 4 );
+
+ # the numbers at the end of the line are origional instruction order
+ &mov( $tmp2, $u ); # 1 2
+ &mov( $tmp1, $t ); # 1 1
+ &and( $tmp2, "0xfc" ); # 1 4
+ &and( $tmp1, "0xfc" ); # 1 3
+ &shr( $t, 8 ); # 1 5
+ &xor( $L, &DWP("0x100+$desSP",$tmp1,"",0)); # 1 7
+ &shr( $u, 8 ); # 1 6
+ &mov( $tmp1, &DWP(" $desSP",$tmp2,"",0)); # 1 8
+
+ &mov( $tmp2, $u ); # 2 2
+ &xor( $L, $tmp1 ); # 1 9
+ &and( $tmp2, "0xfc" ); # 2 4
+ &mov( $tmp1, $t ); # 2 1
+ &and( $tmp1, "0xfc" ); # 2 3
+ &shr( $t, 8 ); # 2 5
+ &xor( $L, &DWP("0x300+$desSP",$tmp1,"",0)); # 2 7
+ &shr( $u, 8 ); # 2 6
+ &mov( $tmp1, &DWP("0x200+$desSP",$tmp2,"",0)); # 2 8
+ &mov( $tmp2, $u ); # 3 2
+
+ &xor( $L, $tmp1 ); # 2 9
+ &and( $tmp2, "0xfc" ); # 3 4
+
+ &mov( $tmp1, $t ); # 3 1
+ &shr( $u, 8 ); # 3 6
+ &and( $tmp1, "0xfc" ); # 3 3
+ &shr( $t, 8 ); # 3 5
+ &xor( $L, &DWP("0x500+$desSP",$tmp1,"",0)); # 3 7
+ &mov( $tmp1, &DWP("0x400+$desSP",$tmp2,"",0)); # 3 8
+
+ &and( $t, "0xfc" ); # 4 1
+ &xor( $L, $tmp1 ); # 3 9
+
+ &and( $u, "0xfc" ); # 4 2
+ &xor( $L, &DWP("0x700+$desSP",$t,"",0)); # 4 3
+ &xor( $L, &DWP("0x600+$desSP",$u,"",0)); # 4 4
+ }
+
+sub PERM_OP
+ {
+ local($a,$b,$tt,$shift,$mask)=@_;
+
+ &mov( $tt, $a );
+ &shr( $tt, $shift );
+ &xor( $tt, $b );
+ &and( $tt, $mask );
+ &xor( $b, $tt );
+ &shl( $tt, $shift );
+ &xor( $a, $tt );
+ }
+
+sub IP_new
+ {
+ local($l,$r,$tt)=@_;
+
+ &PERM_OP($r,$l,$tt, 4,"0x0f0f0f0f");
+ &PERM_OP($l,$r,$tt,16,"0x0000ffff");
+ &PERM_OP($r,$l,$tt, 2,"0x33333333");
+ &PERM_OP($l,$r,$tt, 8,"0x00ff00ff");
+ &PERM_OP($r,$l,$tt, 1,"0x55555555");
+ }
+
+sub FP_new
+ {
+ local($l,$r,$tt)=@_;
+
+ &PERM_OP($l,$r,$tt, 1,"0x55555555");
+ &PERM_OP($r,$l,$tt, 8,"0x00ff00ff");
+ &PERM_OP($l,$r,$tt, 2,"0x33333333");
+ &PERM_OP($r,$l,$tt,16,"0x0000ffff");
+ &PERM_OP($l,$r,$tt, 4,"0x0f0f0f0f");
+ }
+
+sub n2a
+ {
+ sprintf("%d",$_[0]);
+ }
diff --git a/linux/crypto/ciphers/des/asm/desboth.pl b/linux/crypto/ciphers/des/asm/desboth.pl
new file mode 100644
index 000000000..8f939953a
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/desboth.pl
@@ -0,0 +1,79 @@
+#!/usr/bin/perl
+
+$L="edi";
+$R="esi";
+
+sub des_encrypt3
+ {
+ local($name,$enc)=@_;
+
+ &function_begin_B($name,"");
+ &push("ebx");
+ &mov("ebx",&wparam(0));
+
+ &push("ebp");
+ &push("esi");
+
+ &push("edi");
+
+ &comment("");
+ &comment("Load the data words");
+ &mov($L,&DWP(0,"ebx","",0));
+ &mov($R,&DWP(4,"ebx","",0));
+ &stack_push(3);
+
+ &comment("");
+ &comment("IP");
+ &IP_new($L,$R,"edx",0);
+
+ # put them back
+
+ if ($enc)
+ {
+ &mov(&DWP(4,"ebx","",0),$R);
+ &mov("eax",&wparam(1));
+ &mov(&DWP(0,"ebx","",0),"edx");
+ &mov("edi",&wparam(2));
+ &mov("esi",&wparam(3));
+ }
+ else
+ {
+ &mov(&DWP(4,"ebx","",0),$R);
+ &mov("esi",&wparam(1));
+ &mov(&DWP(0,"ebx","",0),"edx");
+ &mov("edi",&wparam(2));
+ &mov("eax",&wparam(3));
+ }
+ &mov(&swtmp(2), (($enc)?"1":"0"));
+ &mov(&swtmp(1), "eax");
+ &mov(&swtmp(0), "ebx");
+ &call("des_encrypt2");
+ &mov(&swtmp(2), (($enc)?"0":"1"));
+ &mov(&swtmp(1), "edi");
+ &mov(&swtmp(0), "ebx");
+ &call("des_encrypt2");
+ &mov(&swtmp(2), (($enc)?"1":"0"));
+ &mov(&swtmp(1), "esi");
+ &mov(&swtmp(0), "ebx");
+ &call("des_encrypt2");
+
+ &stack_pop(3);
+ &mov($L,&DWP(0,"ebx","",0));
+ &mov($R,&DWP(4,"ebx","",0));
+
+ &comment("");
+ &comment("FP");
+ &FP_new($L,$R,"eax",0);
+
+ &mov(&DWP(0,"ebx","",0),"eax");
+ &mov(&DWP(4,"ebx","",0),$R);
+
+ &pop("edi");
+ &pop("esi");
+ &pop("ebp");
+ &pop("ebx");
+ &ret();
+ &function_end_B($name);
+ }
+
+
diff --git a/linux/crypto/ciphers/des/asm/perlasm/cbc.pl b/linux/crypto/ciphers/des/asm/perlasm/cbc.pl
new file mode 100644
index 000000000..278930579
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/perlasm/cbc.pl
@@ -0,0 +1,342 @@
+#!/usr/bin/perl
+
+# void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
+# des_cblock (*input);
+# des_cblock (*output);
+# long length;
+# des_key_schedule schedule;
+# des_cblock (*ivec);
+# int enc;
+#
+# calls
+# des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+#
+
+#&cbc("des_ncbc_encrypt","des_encrypt",0);
+#&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",
+# 1,4,5,3,5,-1);
+#&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",
+# 0,4,5,3,5,-1);
+#&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",
+# 0,6,7,3,4,5);
+#
+# When doing a cipher that needs bigendian order,
+# for encrypt, the iv is kept in bigendian form,
+# while for decrypt, it is kept in little endian.
+sub cbc
+ {
+ local($name,$enc_func,$dec_func,$swap,$iv_off,$enc_off,$p1,$p2,$p3)=@_;
+ # name is the function name
+ # enc_func and dec_func and the functions to call for encrypt/decrypt
+ # swap is true if byte order needs to be reversed
+ # iv_off is parameter number for the iv
+ # enc_off is parameter number for the encrypt/decrypt flag
+ # p1,p2,p3 are the offsets for parameters to be passed to the
+ # underlying calls.
+
+ &function_begin_B($name,"");
+ &comment("");
+
+ $in="esi";
+ $out="edi";
+ $count="ebp";
+
+ &push("ebp");
+ &push("ebx");
+ &push("esi");
+ &push("edi");
+
+ $data_off=4;
+ $data_off+=4 if ($p1 > 0);
+ $data_off+=4 if ($p2 > 0);
+ $data_off+=4 if ($p3 > 0);
+
+ &mov($count, &wparam(2)); # length
+
+ &comment("getting iv ptr from parameter $iv_off");
+ &mov("ebx", &wparam($iv_off)); # Get iv ptr
+
+ &mov($in, &DWP(0,"ebx","",0));# iv[0]
+ &mov($out, &DWP(4,"ebx","",0));# iv[1]
+
+ &push($out);
+ &push($in);
+ &push($out); # used in decrypt for iv[1]
+ &push($in); # used in decrypt for iv[0]
+
+ &mov("ebx", "esp"); # This is the address of tin[2]
+
+ &mov($in, &wparam(0)); # in
+ &mov($out, &wparam(1)); # out
+
+ # We have loaded them all, how lets push things
+ &comment("getting encrypt flag from parameter $enc_off");
+ &mov("ecx", &wparam($enc_off)); # Get enc flag
+ if ($p3 > 0)
+ {
+ &comment("get and push parameter $p3");
+ if ($enc_off != $p3)
+ { &mov("eax", &wparam($p3)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ if ($p2 > 0)
+ {
+ &comment("get and push parameter $p2");
+ if ($enc_off != $p2)
+ { &mov("eax", &wparam($p2)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ if ($p1 > 0)
+ {
+ &comment("get and push parameter $p1");
+ if ($enc_off != $p1)
+ { &mov("eax", &wparam($p1)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ &push("ebx"); # push data/iv
+
+ &cmp("ecx",0);
+ &jz(&label("decrypt"));
+
+ &and($count,0xfffffff8);
+ &mov("eax", &DWP($data_off,"esp","",0)); # load iv[0]
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); # load iv[1]
+
+ &jz(&label("encrypt_finish"));
+
+ #############################################################
+
+ &set_label("encrypt_loop");
+ # encrypt start
+ # "eax" and "ebx" hold iv (or the last cipher text)
+
+ &mov("ecx", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("edx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &xor("eax", "ecx");
+ &xor("ebx", "edx");
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($enc_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP(0,$out,"",0),"eax");
+ &mov(&DWP(4,$out,"",0),"ebx");
+
+ # eax and ebx are the next iv.
+
+ &add($in, 8);
+ &add($out, 8);
+
+ &sub($count, 8);
+ &jnz(&label("encrypt_loop"));
+
+###################################################################3
+ &set_label("encrypt_finish");
+ &mov($count, &wparam(2)); # length
+ &and($count, 7);
+ &jz(&label("finish"));
+ &xor("ecx","ecx");
+ &xor("edx","edx");
+ &mov($count,&DWP(&label("cbc_enc_jmp_table"),"",$count,4));
+ &jmp_ptr($count);
+
+&set_label("ej7");
+ &xor("edx", "edx") if $ppro; # ppro friendly
+ &movb(&HB("edx"), &BP(6,$in,"",0));
+ &shl("edx",8);
+&set_label("ej6");
+ &movb(&HB("edx"), &BP(5,$in,"",0));
+&set_label("ej5");
+ &movb(&LB("edx"), &BP(4,$in,"",0));
+&set_label("ej4");
+ &mov("ecx", &DWP(0,$in,"",0));
+ &jmp(&label("ejend"));
+&set_label("ej3");
+ &movb(&HB("ecx"), &BP(2,$in,"",0));
+ &xor("ecx", "ecx") if $ppro; # ppro friendly
+ &shl("ecx",8);
+&set_label("ej2");
+ &movb(&HB("ecx"), &BP(1,$in,"",0));
+&set_label("ej1");
+ &movb(&LB("ecx"), &BP(0,$in,"",0));
+&set_label("ejend");
+
+ &xor("eax", "ecx");
+ &xor("ebx", "edx");
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($enc_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP(0,$out,"",0),"eax");
+ &mov(&DWP(4,$out,"",0),"ebx");
+
+ &jmp(&label("finish"));
+
+ #############################################################
+ #############################################################
+ &set_label("decrypt",1);
+ # decrypt start
+ &and($count,0xfffffff8);
+ # The next 2 instructions are only for if the jz is taken
+ &mov("eax", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("ebx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+ &jz(&label("decrypt_finish"));
+
+ &set_label("decrypt_loop");
+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($dec_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+
+ &xor("ecx", "eax");
+ &xor("edx", "ebx");
+
+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
+
+ &mov(&DWP(0,$out,"",0),"ecx");
+ &mov(&DWP(4,$out,"",0),"edx");
+
+ &mov(&DWP($data_off+8,"esp","",0), "eax"); # save iv
+ &mov(&DWP($data_off+12,"esp","",0), "ebx"); #
+
+ &add($in, 8);
+ &add($out, 8);
+
+ &sub($count, 8);
+ &jnz(&label("decrypt_loop"));
+############################ ENDIT #######################3
+ &set_label("decrypt_finish");
+ &mov($count, &wparam(2)); # length
+ &and($count, 7);
+ &jz(&label("finish"));
+
+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($dec_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+
+ &xor("ecx", "eax");
+ &xor("edx", "ebx");
+
+ # this is for when we exit
+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
+
+&set_label("dj7");
+ &rotr("edx", 16);
+ &movb(&BP(6,$out,"",0), &LB("edx"));
+ &shr("edx",16);
+&set_label("dj6");
+ &movb(&BP(5,$out,"",0), &HB("edx"));
+&set_label("dj5");
+ &movb(&BP(4,$out,"",0), &LB("edx"));
+&set_label("dj4");
+ &mov(&DWP(0,$out,"",0), "ecx");
+ &jmp(&label("djend"));
+&set_label("dj3");
+ &rotr("ecx", 16);
+ &movb(&BP(2,$out,"",0), &LB("ecx"));
+ &shl("ecx",16);
+&set_label("dj2");
+ &movb(&BP(1,$in,"",0), &HB("ecx"));
+&set_label("dj1");
+ &movb(&BP(0,$in,"",0), &LB("ecx"));
+&set_label("djend");
+
+ # final iv is still in eax:ebx
+ &jmp(&label("finish"));
+
+
+############################ FINISH #######################3
+ &set_label("finish",1);
+ &mov("ecx", &wparam($iv_off)); # Get iv ptr
+
+ #################################################
+ $total=16+4;
+ $total+=4 if ($p1 > 0);
+ $total+=4 if ($p2 > 0);
+ $total+=4 if ($p3 > 0);
+ &add("esp",$total);
+
+ &mov(&DWP(0,"ecx","",0), "eax"); # save iv
+ &mov(&DWP(4,"ecx","",0), "ebx"); # save iv
+
+ &function_end_A($name);
+
+ &set_label("cbc_enc_jmp_table",1);
+ &data_word("0");
+ &data_word(&label("ej1"));
+ &data_word(&label("ej2"));
+ &data_word(&label("ej3"));
+ &data_word(&label("ej4"));
+ &data_word(&label("ej5"));
+ &data_word(&label("ej6"));
+ &data_word(&label("ej7"));
+ &set_label("cbc_dec_jmp_table",1);
+ &data_word("0");
+ &data_word(&label("dj1"));
+ &data_word(&label("dj2"));
+ &data_word(&label("dj3"));
+ &data_word(&label("dj4"));
+ &data_word(&label("dj5"));
+ &data_word(&label("dj6"));
+ &data_word(&label("dj7"));
+
+ &function_end_B($name);
+
+ }
+
+1;
diff --git a/linux/crypto/ciphers/des/asm/perlasm/readme b/linux/crypto/ciphers/des/asm/perlasm/readme
new file mode 100644
index 000000000..f02bbee75
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/perlasm/readme
@@ -0,0 +1,124 @@
+The perl scripts in this directory are my 'hack' to generate
+multiple different assembler formats via the one origional script.
+
+The way to use this library is to start with adding the path to this directory
+and then include it.
+
+push(@INC,"perlasm","../../perlasm");
+require "x86asm.pl";
+
+The first thing we do is setup the file and type of assember
+
+&asm_init($ARGV[0],$0);
+
+The first argument is the 'type'. Currently
+'cpp', 'sol', 'a.out', 'elf' or 'win32'.
+Argument 2 is the file name.
+
+The reciprocal function is
+&asm_finish() which should be called at the end.
+
+There are 2 main 'packages'. x86ms.pl, which is the microsoft assembler,
+and x86unix.pl which is the unix (gas) version.
+
+Functions of interest are:
+&external_label("des_SPtrans"); declare and external variable
+&LB(reg); Low byte for a register
+&HB(reg); High byte for a register
+&BP(off,base,index,scale) Byte pointer addressing
+&DWP(off,base,index,scale) Word pointer addressing
+&stack_push(num) Basically a 'sub esp, num*4' with extra
+&stack_pop(num) inverse of stack_push
+&function_begin(name,extra) Start a function with pushing of
+ edi, esi, ebx and ebp. extra is extra win32
+ external info that may be required.
+&function_begin_B(name,extra) Same as norma function_begin but no pushing.
+&function_end(name) Call at end of function.
+&function_end_A(name) Standard pop and ret, for use inside functions
+&function_end_B(name) Call at end but with poping or 'ret'.
+&swtmp(num) Address on stack temp word.
+&wparam(num) Parameter number num, that was push
+ in C convention. This all works over pushes
+ and pops.
+&comment("hello there") Put in a comment.
+&label("loop") Refer to a label, normally a jmp target.
+&set_label("loop") Set a label at this point.
+&data_word(word) Put in a word of data.
+
+So how does this all hold together? Given
+
+int calc(int len, int *data)
+ {
+ int i,j=0;
+
+ for (i=0; i<len; i++)
+ {
+ j+=other(data[i]);
+ }
+ }
+
+So a very simple version of this function could be coded as
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+
+ &asm_init($ARGV[0],"cacl.pl");
+
+ &external_label("other");
+
+ $tmp1= "eax";
+ $j= "edi";
+ $data= "esi";
+ $i= "ebp";
+
+ &comment("a simple function");
+ &function_begin("calc");
+ &mov( $data, &wparam(1)); # data
+ &xor( $j, $j);
+ &xor( $i, $i);
+
+ &set_label("loop");
+ &cmp( $i, &wparam(0));
+ &jge( &label("end"));
+
+ &mov( $tmp1, &DWP(0,$data,$i,4));
+ &push( $tmp1);
+ &call( "other");
+ &add( $j, "eax");
+ &pop( $tmp1);
+ &inc( $i);
+ &jmp( &label("loop"));
+
+ &set_label("end");
+ &mov( "eax", $j);
+
+ &function_end("calc");
+
+ &asm_finish();
+
+The above example is very very unoptimised but gives an idea of how
+things work.
+
+There is also a cbc mode function generator in cbc.pl
+
+&cbc( $name,
+ $encrypt_function_name,
+ $decrypt_function_name,
+ $true_if_byte_swap_needed,
+ $parameter_number_for_iv,
+ $parameter_number_for_encrypt_flag,
+ $first_parameter_to_pass,
+ $second_parameter_to_pass,
+ $third_parameter_to_pass);
+
+So for example, given
+void BF_encrypt(BF_LONG *data,BF_KEY *key);
+void BF_decrypt(BF_LONG *data,BF_KEY *key);
+void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length,
+ BF_KEY *ks, unsigned char *iv, int enc);
+
+&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",1,4,5,3,-1,-1);
+
+&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",0,4,5,3,5,-1);
+&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",0,6,7,3,4,5);
+
diff --git a/linux/crypto/ciphers/des/asm/perlasm/x86asm.pl b/linux/crypto/ciphers/des/asm/perlasm/x86asm.pl
new file mode 100644
index 000000000..164a942c5
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/perlasm/x86asm.pl
@@ -0,0 +1,111 @@
+#!/usr/bin/perl
+
+# require 'x86asm.pl';
+# &asm_init("cpp","des-586.pl");
+# XXX
+# XXX
+# main'asm_finish
+
+sub main'asm_finish
+ {
+ &file_end();
+ &asm_finish_cpp() if $cpp;
+ print &asm_get_output();
+ }
+
+sub main'asm_init
+ {
+ ($type,$fn)=@_;
+ $filename=$fn;
+
+ $cpp=$sol=$aout=$win32=0;
+ if ( ($type eq "elf"))
+ { require "x86unix.pl"; }
+ elsif ( ($type eq "a.out"))
+ { $aout=1; require "x86unix.pl"; }
+ elsif ( ($type eq "sol"))
+ { $sol=1; require "x86unix.pl"; }
+ elsif ( ($type eq "cpp"))
+ { $cpp=1; require "x86unix.pl"; }
+ elsif ( ($type eq "win32"))
+ { $win32=1; require "x86ms.pl"; }
+ else
+ {
+ print STDERR <<"EOF";
+Pick one target type from
+ elf - linux, FreeBSD etc
+ a.out - old linux
+ sol - x86 solaris
+ cpp - format so x86unix.cpp can be used
+ win32 - Windows 95/Windows NT
+EOF
+ exit(1);
+ }
+
+ &asm_init_output();
+
+&comment("Don't even think of reading this code");
+&comment("It was automatically generated by $filename");
+&comment("Which is a perl program used to generate the x86 assember for");
+&comment("any of elf, a.out, BSDI,Win32, or Solaris");
+&comment("eric <eay\@cryptsoft.com>");
+&comment("");
+
+ $filename =~ s/\.pl$//;
+ &file($filename);
+ }
+
+sub asm_finish_cpp
+ {
+ return unless $cpp;
+
+ local($tmp,$i);
+ foreach $i (&get_labels())
+ {
+ $tmp.="#define $i _$i\n";
+ }
+ print <<"EOF";
+/* Run the C pre-processor over this file with one of the following defined
+ * ELF - elf object files,
+ * OUT - a.out object files,
+ * BSDI - BSDI style a.out object files
+ * SOL - Solaris style elf
+ */
+
+#define TYPE(a,b) .type a,b
+#define SIZE(a,b) .size a,b
+
+#if defined(OUT) || defined(BSDI)
+$tmp
+#endif
+
+#ifdef OUT
+#define OK 1
+#define ALIGN 4
+#endif
+
+#ifdef BSDI
+#define OK 1
+#define ALIGN 4
+#undef SIZE
+#undef TYPE
+#endif
+
+#if defined(ELF) || defined(SOL)
+#define OK 1
+#define ALIGN 16
+#endif
+
+#ifndef OK
+You need to define one of
+ELF - elf systems - linux-elf, NetBSD and DG-UX
+OUT - a.out systems - linux-a.out and FreeBSD
+SOL - solaris systems, which are elf with strange comment lines
+BSDI - a.out with a very primative version of as.
+#endif
+
+/* Let the Assembler begin :-) */
+EOF
+ }
+
+1;
diff --git a/linux/crypto/ciphers/des/asm/perlasm/x86ms.pl b/linux/crypto/ciphers/des/asm/perlasm/x86ms.pl
new file mode 100644
index 000000000..0681ea18c
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/perlasm/x86ms.pl
@@ -0,0 +1,345 @@
+#!/usr/bin/perl
+
+package x86ms;
+
+$label="L000";
+
+%lb=( 'eax', 'al',
+ 'ebx', 'bl',
+ 'ecx', 'cl',
+ 'edx', 'dl',
+ 'ax', 'al',
+ 'bx', 'bl',
+ 'cx', 'cl',
+ 'dx', 'dl',
+ );
+
+%hb=( 'eax', 'ah',
+ 'ebx', 'bh',
+ 'ecx', 'ch',
+ 'edx', 'dh',
+ 'ax', 'ah',
+ 'bx', 'bh',
+ 'cx', 'ch',
+ 'dx', 'dh',
+ );
+
+sub main'asm_init_output { @out=(); }
+sub main'asm_get_output { return(@out); }
+sub main'get_labels { return(@labels); }
+sub main'external_label { push(@labels,@_); }
+
+sub main'LB
+ {
+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
+ return($lb{$_[0]});
+ }
+
+sub main'HB
+ {
+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
+ return($hb{$_[0]});
+ }
+
+sub main'BP
+ {
+ &get_mem("BYTE",@_);
+ }
+
+sub main'DWP
+ {
+ &get_mem("DWORD",@_);
+ }
+
+sub main'stack_push
+ {
+ local($num)=@_;
+ $stack+=$num*4;
+ &main'sub("esp",$num*4);
+ }
+
+sub main'stack_pop
+ {
+ local($num)=@_;
+ $stack-=$num*4;
+ &main'add("esp",$num*4);
+ }
+
+sub get_mem
+ {
+ local($size,$addr,$reg1,$reg2,$idx)=@_;
+ local($t,$post);
+ local($ret)="$size PTR ";
+
+ $addr =~ s/^\s+//;
+ if ($addr =~ /^(.+)\+(.+)$/)
+ {
+ $reg2=&conv($1);
+ $addr="_$2";
+ }
+ elsif ($addr =~ /^[_a-zA-Z]/)
+ {
+ $addr="_$addr";
+ }
+
+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
+ if (($addr ne "") && ($addr ne 0))
+ {
+ if ($addr !~ /^-/)
+ { $ret.=$addr; }
+ else { $post=$addr; }
+ }
+ if ($reg2 ne "")
+ {
+ $t="";
+ $t="*$idx" if ($idx != 0);
+ $reg1="+".$reg1 if ("$reg1$post" ne "");
+ $ret.="[$reg2$t$reg1$post]";
+ }
+ else
+ {
+ $ret.="[$reg1$post]"
+ }
+ return($ret);
+ }
+
+sub main'mov { &out2("mov",@_); }
+sub main'movb { &out2("mov",@_); }
+sub main'and { &out2("and",@_); }
+sub main'or { &out2("or",@_); }
+sub main'shl { &out2("shl",@_); }
+sub main'shr { &out2("shr",@_); }
+sub main'xor { &out2("xor",@_); }
+sub main'xorb { &out2("xor",@_); }
+sub main'add { &out2("add",@_); }
+sub main'adc { &out2("adc",@_); }
+sub main'sub { &out2("sub",@_); }
+sub main'rotl { &out2("rol",@_); }
+sub main'rotr { &out2("ror",@_); }
+sub main'exch { &out2("xchg",@_); }
+sub main'cmp { &out2("cmp",@_); }
+sub main'lea { &out2("lea",@_); }
+sub main'mul { &out1("mul",@_); }
+sub main'div { &out1("div",@_); }
+sub main'dec { &out1("dec",@_); }
+sub main'inc { &out1("inc",@_); }
+sub main'jmp { &out1("jmp",@_); }
+sub main'jmp_ptr { &out1p("jmp",@_); }
+sub main'je { &out1("je",@_); }
+sub main'jle { &out1("jle",@_); }
+sub main'jz { &out1("jz",@_); }
+sub main'jge { &out1("jge",@_); }
+sub main'jl { &out1("jl",@_); }
+sub main'jb { &out1("jb",@_); }
+sub main'jnz { &out1("jnz",@_); }
+sub main'jne { &out1("jne",@_); }
+sub main'push { &out1("push",@_); $stack+=4; }
+sub main'pop { &out1("pop",@_); $stack-=4; }
+sub main'bswap { &out1("bswap",@_); &using486(); }
+sub main'not { &out1("not",@_); }
+sub main'call { &out1("call",'_'.$_[0]); }
+sub main'ret { &out0("ret"); }
+sub main'nop { &out0("nop"); }
+
+sub out2
+ {
+ local($name,$p1,$p2)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t");
+ $t=&conv($p1).",";
+ $l=length($t);
+ push(@out,$t);
+ $l=4-($l+9)/8;
+ push(@out,"\t" x $l);
+ push(@out,&conv($p2));
+ push(@out,"\n");
+ }
+
+sub out0
+ {
+ local($name)=@_;
+
+ push(@out,"\t$name\n");
+ }
+
+sub out1
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t".&conv($p1)."\n");
+ }
+
+sub conv
+ {
+ local($p)=@_;
+
+ $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
+ return $p;
+ }
+
+sub using486
+ {
+ return if $using486;
+ $using486++;
+ grep(s/\.386/\.486/,@out);
+ }
+
+sub main'file
+ {
+ local($file)=@_;
+
+ local($tmp)=<<"EOF";
+ TITLE $file.asm
+ .386
+.model FLAT
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'function_begin
+ {
+ local($func,$extra)=@_;
+
+ push(@labels,$func);
+
+ local($tmp)=<<"EOF";
+_TEXT SEGMENT
+PUBLIC _$func
+$extra
+_$func PROC NEAR
+ push ebp
+ push ebx
+ push esi
+ push edi
+EOF
+ push(@out,$tmp);
+ $stack=20;
+ }
+
+sub main'function_begin_B
+ {
+ local($func,$extra)=@_;
+
+ local($tmp)=<<"EOF";
+_TEXT SEGMENT
+PUBLIC _$func
+$extra
+_$func PROC NEAR
+EOF
+ push(@out,$tmp);
+ $stack=4;
+ }
+
+sub main'function_end
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+_$func ENDP
+_TEXT ENDS
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main'function_end_B
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+_$func ENDP
+_TEXT ENDS
+EOF
+ push(@out,$tmp);
+ $stack=0;
+ %label=();
+ }
+
+sub main'function_end_A
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'file_end
+ {
+ push(@out,"END\n");
+ }
+
+sub main'wparam
+ {
+ local($num)=@_;
+
+ return(&main'DWP($stack+$num*4,"esp","",0));
+ }
+
+sub main'swtmp
+ {
+ return(&main'DWP($_[0]*4,"esp","",0));
+ }
+
+# Should use swtmp, which is above esp. Linix can trash the stack above esp
+#sub main'wtmp
+# {
+# local($num)=@_;
+#
+# return(&main'DWP(-(($num+1)*4),"esp","",0));
+# }
+
+sub main'comment
+ {
+ foreach (@_)
+ {
+ push(@out,"\t; $_\n");
+ }
+ }
+
+sub main'label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="\$${label}${_[0]}";
+ $label++;
+ }
+ return($label{$_[0]});
+ }
+
+sub main'set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}="${label}${_[0]}";
+ $label++;
+ }
+ push(@out,"$label{$_[0]}:\n");
+ }
+
+sub main'data_word
+ {
+ push(@out,"\tDD\t$_[0]\n");
+ }
+
+sub out1p
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t ".&conv($p1)."\n");
+ }
diff --git a/linux/crypto/ciphers/des/asm/perlasm/x86unix.pl b/linux/crypto/ciphers/des/asm/perlasm/x86unix.pl
new file mode 100644
index 000000000..1d661221c
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/perlasm/x86unix.pl
@@ -0,0 +1,403 @@
+#!/usr/bin/perl
+
+package x86unix;
+
+$label="L000";
+
+$align=($main'aout)?"4":"16";
+$under=($main'aout)?"_":"";
+$com_start=($main'sol)?"/":"#";
+
+sub main'asm_init_output { @out=(); }
+sub main'asm_get_output { return(@out); }
+sub main'get_labels { return(@labels); }
+sub main'external_label { push(@labels,@_); }
+
+if ($main'cpp)
+ {
+ $align="ALIGN";
+ $under="";
+ $com_start='/*';
+ $com_end='*/';
+ }
+
+%lb=( 'eax', '%al',
+ 'ebx', '%bl',
+ 'ecx', '%cl',
+ 'edx', '%dl',
+ 'ax', '%al',
+ 'bx', '%bl',
+ 'cx', '%cl',
+ 'dx', '%dl',
+ );
+
+%hb=( 'eax', '%ah',
+ 'ebx', '%bh',
+ 'ecx', '%ch',
+ 'edx', '%dh',
+ 'ax', '%ah',
+ 'bx', '%bh',
+ 'cx', '%ch',
+ 'dx', '%dh',
+ );
+
+%regs=( 'eax', '%eax',
+ 'ebx', '%ebx',
+ 'ecx', '%ecx',
+ 'edx', '%edx',
+ 'esi', '%esi',
+ 'edi', '%edi',
+ 'ebp', '%ebp',
+ 'esp', '%esp',
+ );
+
+%reg_val=(
+ 'eax', 0x00,
+ 'ebx', 0x03,
+ 'ecx', 0x01,
+ 'edx', 0x02,
+ 'esi', 0x06,
+ 'edi', 0x07,
+ 'ebp', 0x05,
+ 'esp', 0x04,
+ );
+
+sub main'LB
+ {
+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
+ return($lb{$_[0]});
+ }
+
+sub main'HB
+ {
+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
+ return($hb{$_[0]});
+ }
+
+sub main'DWP
+ {
+ local($addr,$reg1,$reg2,$idx)=@_;
+
+ $ret="";
+ $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
+ $ret.=$addr if ($addr ne "") && ($addr ne 0);
+ if ($reg2 ne "")
+ { $ret.="($reg1,$reg2,$idx)"; }
+ else
+ { $ret.="($reg1)" }
+ return($ret);
+ }
+
+sub main'BP
+ {
+ return(&main'DWP(@_));
+ }
+
+#sub main'BP
+# {
+# local($addr,$reg1,$reg2,$idx)=@_;
+#
+# $ret="";
+#
+# $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
+# $reg1="$regs{$reg1}" if defined($regs{$reg1});
+# $reg2="$regs{$reg2}" if defined($regs{$reg2});
+# $ret.=$addr if ($addr ne "") && ($addr ne 0);
+# if ($reg2 ne "")
+# { $ret.="($reg1,$reg2,$idx)"; }
+# else
+# { $ret.="($reg1)" }
+# return($ret);
+# }
+
+sub main'mov { &out2("movl",@_); }
+sub main'movb { &out2("movb",@_); }
+sub main'and { &out2("andl",@_); }
+sub main'or { &out2("orl",@_); }
+sub main'shl { &out2("sall",@_); }
+sub main'shr { &out2("shrl",@_); }
+sub main'xor { &out2("xorl",@_); }
+sub main'xorb { &out2("xorb",@_); }
+sub main'add { &out2("addl",@_); }
+sub main'adc { &out2("adcl",@_); }
+sub main'sub { &out2("subl",@_); }
+sub main'rotl { &out2("roll",@_); }
+sub main'rotr { &out2("rorl",@_); }
+sub main'exch { &out2("xchg",@_); }
+sub main'cmp { &out2("cmpl",@_); }
+sub main'lea { &out2("leal",@_); }
+sub main'mul { &out1("mull",@_); }
+sub main'div { &out1("divl",@_); }
+sub main'jmp { &out1("jmp",@_); }
+sub main'jmp_ptr { &out1p("jmp",@_); }
+sub main'je { &out1("je",@_); }
+sub main'jle { &out1("jle",@_); }
+sub main'jne { &out1("jne",@_); }
+sub main'jnz { &out1("jnz",@_); }
+sub main'jz { &out1("jz",@_); }
+sub main'jge { &out1("jge",@_); }
+sub main'jl { &out1("jl",@_); }
+sub main'jb { &out1("jb",@_); }
+sub main'dec { &out1("decl",@_); }
+sub main'inc { &out1("incl",@_); }
+sub main'push { &out1("pushl",@_); $stack+=4; }
+sub main'pop { &out1("popl",@_); $stack-=4; }
+sub main'bswap { &out1("bswapl",@_); }
+sub main'not { &out1("notl",@_); }
+sub main'call { &out1("call",$under.$_[0]); }
+sub main'ret { &out0("ret"); }
+sub main'nop { &out0("nop"); }
+
+sub out2
+ {
+ local($name,$p1,$p2)=@_;
+ local($l,$ll,$t);
+ local(%special)=( "roll",0xD1C0,"rorl",0xD1C8,
+ "rcll",0xD1D0,"rcrl",0xD1D8,
+ "shll",0xD1E0,"shrl",0xD1E8,
+ "sarl",0xD1F8);
+
+ if ((defined($special{$name})) && defined($regs{$p1}) && ($p2 == 1))
+ {
+ $op=$special{$name}|$reg_val{$p1};
+ $tmp1=sprintf ".byte %d\n",($op>>8)&0xff;
+ $tmp2=sprintf ".byte %d\t",$op &0xff;
+ push(@out,$tmp1);
+ push(@out,$tmp2);
+
+ $p2=&conv($p2);
+ $p1=&conv($p1);
+ &main'comment("$name $p2 $p1");
+ return;
+ }
+
+ push(@out,"\t$name\t");
+ $t=&conv($p2).",";
+ $l=length($t);
+ push(@out,$t);
+ $ll=4-($l+9)/8;
+ $tmp1=sprintf "\t" x $ll;
+ push(@out,$tmp1);
+ push(@out,&conv($p1)."\n");
+ }
+
+sub out1
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t".&conv($p1)."\n");
+ }
+
+sub out1p
+ {
+ local($name,$p1)=@_;
+ local($l,$t);
+
+ push(@out,"\t$name\t*".&conv($p1)."\n");
+ }
+
+sub out0
+ {
+ push(@out,"\t$_[0]\n");
+ }
+
+sub conv
+ {
+ local($p)=@_;
+
+# $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
+
+ $p=$regs{$p} if (defined($regs{$p}));
+
+ $p =~ s/^(-{0,1}[0-9A-Fa-f]+)$/\$$1/;
+ $p =~ s/^(0x[0-9A-Fa-f]+)$/\$$1/;
+ return $p;
+ }
+
+sub main'file
+ {
+ local($file)=@_;
+
+ local($tmp)=<<"EOF";
+ .file "$file.s"
+ .version "01.01"
+gcc2_compiled.:
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'function_begin
+ {
+ local($func)=@_;
+
+ $func=$under.$func;
+
+ local($tmp)=<<"EOF";
+.text
+ .align $align
+.globl $func
+EOF
+ push(@out,$tmp);
+ if ($main'cpp)
+ { $tmp=push(@out,"\tTYPE($func,\@function)\n"); }
+ else { $tmp=push(@out,"\t.type\t$func,\@function\n"); }
+ push(@out,"$func:\n");
+ $tmp=<<"EOF";
+ pushl %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+EOF
+ push(@out,$tmp);
+ $stack=20;
+ }
+
+sub main'function_begin_B
+ {
+ local($func,$extra)=@_;
+
+ $func=$under.$func;
+
+ local($tmp)=<<"EOF";
+.text
+ .align $align
+.globl $func
+EOF
+ push(@out,$tmp);
+ if ($main'cpp)
+ { push(@out,"\tTYPE($func,\@function)\n"); }
+ else { push(@out,"\t.type $func,\@function\n"); }
+ push(@out,"$func:\n");
+ $stack=4;
+ }
+
+sub main'function_end
+ {
+ local($func)=@_;
+
+ $func=$under.$func;
+
+ local($tmp)=<<"EOF";
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+.${func}_end:
+EOF
+ push(@out,$tmp);
+ if ($main'cpp)
+ { push(@out,"\tSIZE($func,.${func}_end-$func)\n"); }
+ else { push(@out,"\t.size\t$func,.${func}_end-$func\n"); }
+ push(@out,".ident \"$func\"\n");
+ $stack=0;
+ %label=();
+ }
+
+sub main'function_end_A
+ {
+ local($func)=@_;
+
+ local($tmp)=<<"EOF";
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+EOF
+ push(@out,$tmp);
+ }
+
+sub main'function_end_B
+ {
+ local($func)=@_;
+
+ $func=$under.$func;
+
+ push(@out,".${func}_end:\n");
+ if ($main'cpp)
+ { push(@out,"\tSIZE($func,.${func}_end-$func)\n"); }
+ else { push(@out,"\t.size\t$func,.${func}_end-$func\n"); }
+ push(@out,".ident \"desasm.pl\"\n");
+ $stack=0;
+ %label=();
+ }
+
+sub main'wparam
+ {
+ local($num)=@_;
+
+ return(&main'DWP($stack+$num*4,"esp","",0));
+ }
+
+sub main'stack_push
+ {
+ local($num)=@_;
+ $stack+=$num*4;
+ &main'sub("esp",$num*4);
+ }
+
+sub main'stack_pop
+ {
+ local($num)=@_;
+ $stack-=$num*4;
+ &main'add("esp",$num*4);
+ }
+
+sub main'swtmp
+ {
+ return(&main'DWP($_[0]*4,"esp","",0));
+ }
+
+# Should use swtmp, which is above esp. Linix can trash the stack above esp
+#sub main'wtmp
+# {
+# local($num)=@_;
+#
+# return(&main'DWP(-($num+1)*4,"esp","",0));
+# }
+
+sub main'comment
+ {
+ foreach (@_)
+ {
+ if (/^\s*$/)
+ { push(@out,"\n"); }
+ else
+ { push(@out,"\t$com_start $_ $com_end\n"); }
+ }
+ }
+
+sub main'label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=".${label}${_[0]}";
+ $label++;
+ }
+ return($label{$_[0]});
+ }
+
+sub main'set_label
+ {
+ if (!defined($label{$_[0]}))
+ {
+ $label{$_[0]}=".${label}${_[0]}";
+ $label++;
+ }
+ push(@out,".align $align\n") if ($_[1] != 0);
+ push(@out,"$label{$_[0]}:\n");
+ }
+
+sub main'file_end
+ {
+ }
+
+sub main'data_word
+ {
+ push(@out,"\t.long $_[0]\n");
+ }
diff --git a/linux/crypto/ciphers/des/asm/readme b/linux/crypto/ciphers/des/asm/readme
new file mode 100644
index 000000000..f8529d930
--- /dev/null
+++ b/linux/crypto/ciphers/des/asm/readme
@@ -0,0 +1,131 @@
+First up, let me say I don't like writing in assembler. It is not portable,
+dependant on the particular CPU architecture release and is generally a pig
+to debug and get right. Having said that, the x86 architecture is probably
+the most important for speed due to number of boxes and since
+it appears to be the worst architecture to to get
+good C compilers for. So due to this, I have lowered myself to do
+assembler for the inner DES routines in libdes :-).
+
+The file to implement in assembler is des_enc.c. Replace the following
+4 functions
+des_encrypt(DES_LONG data[2],des_key_schedule ks, int encrypt);
+des_encrypt2(DES_LONG data[2],des_key_schedule ks, int encrypt);
+des_encrypt3(DES_LONG data[2],des_key_schedule ks1,ks2,ks3);
+des_decrypt3(DES_LONG data[2],des_key_schedule ks1,ks2,ks3);
+
+They encrypt/decrypt the 64 bits held in 'data' using
+the 'ks' key schedules. The only difference between the 4 functions is that
+des_encrypt2() does not perform IP() or FP() on the data (this is an
+optimization for when doing triple DES and des_encrypt3() and des_decrypt3()
+perform triple des. The triple DES routines are in here because it does
+make a big difference to have them located near the des_encrypt2 function
+at link time..
+
+Now as we all know, there are lots of different operating systems running on
+x86 boxes, and unfortunately they normally try to make sure their assembler
+formating is not the same as the other peoples.
+The 4 main formats I know of are
+Microsoft Windows 95/Windows NT
+Elf Includes Linux and FreeBSD(?).
+a.out The older Linux.
+Solaris Same as Elf but different comments :-(.
+
+Now I was not overly keen to write 4 different copies of the same code,
+so I wrote a few perl routines to output the correct assembler, given
+a target assembler type. This code is ugly and is just a hack.
+The libraries are x86unix.pl and x86ms.pl.
+des586.pl, des686.pl and des-som[23].pl are the programs to actually
+generate the assembler.
+
+So to generate elf assembler
+perl des-som3.pl elf >dx86-elf.s
+For Windows 95/NT
+perl des-som2.pl win32 >win32.asm
+
+[ update 4 Jan 1996 ]
+I have added another way to do things.
+perl des-som3.pl cpp >dx86-cpp.s
+generates a file that will be included by dx86unix.cpp when it is compiled.
+To build for elf, a.out, solaris, bsdi etc,
+cc -E -DELF asm/dx86unix.cpp | as -o asm/dx86-elf.o
+cc -E -DSOL asm/dx86unix.cpp | as -o asm/dx86-sol.o
+cc -E -DOUT asm/dx86unix.cpp | as -o asm/dx86-out.o
+cc -E -DBSDI asm/dx86unix.cpp | as -o asm/dx86bsdi.o
+This was done to cut down the number of files in the distribution.
+
+Now the ugly part. I acquired my copy of Intels
+"Optimization's For Intel's 32-Bit Processors" and found a few interesting
+things. First, the aim of the exersize is to 'extract' one byte at a time
+from a word and do an array lookup. This involves getting the byte from
+the 4 locations in the word and moving it to a new word and doing the lookup.
+The most obvious way to do this is
+xor eax, eax # clear word
+movb al, cl # get low byte
+xor edi DWORD PTR 0x100+des_SP[eax] # xor in word
+movb al, ch # get next byte
+xor edi DWORD PTR 0x300+des_SP[eax] # xor in word
+shr ecx 16
+which seems ok. For the pentium, this system appears to be the best.
+One has to do instruction interleaving to keep both functional units
+operating, but it is basically very efficient.
+
+Now the crunch. When a full register is used after a partial write, eg.
+mov al, cl
+xor edi, DWORD PTR 0x100+des_SP[eax]
+386 - 1 cycle stall
+486 - 1 cycle stall
+586 - 0 cycle stall
+686 - at least 7 cycle stall (page 22 of the above mentioned document).
+
+So the technique that produces the best results on a pentium, according to
+the documentation, will produce hideous results on a pentium pro.
+
+To get around this, des686.pl will generate code that is not as fast on
+a pentium, should be very good on a pentium pro.
+mov eax, ecx # copy word
+shr ecx, 8 # line up next byte
+and eax, 0fch # mask byte
+xor edi DWORD PTR 0x100+des_SP[eax] # xor in array lookup
+mov eax, ecx # get word
+shr ecx 8 # line up next byte
+and eax, 0fch # mask byte
+xor edi DWORD PTR 0x300+des_SP[eax] # xor in array lookup
+
+Due to the execution units in the pentium, this actually works quite well.
+For a pentium pro it should be very good. This is the type of output
+Visual C++ generates.
+
+There is a third option. instead of using
+mov al, ch
+which is bad on the pentium pro, one may be able to use
+movzx eax, ch
+which may not incur the partial write penalty. On the pentium,
+this instruction takes 4 cycles so is not worth using but on the
+pentium pro it appears it may be worth while. I need access to one to
+experiment :-).
+
+eric (20 Oct 1996)
+
+22 Nov 1996 - I have asked people to run the 2 different version on pentium
+pros and it appears that the intel documentation is wrong. The
+mov al,bh is still faster on a pentium pro, so just use the des586.pl
+install des686.pl
+
+3 Dec 1996 - I added des_encrypt3/des_decrypt3 because I have moved these
+functions into des_enc.c because it does make a massive performance
+difference on some boxes to have the functions code located close to
+the des_encrypt2() function.
+
+9 Jan 1997 - des-som2.pl is now the correct perl script to use for
+pentiums. It contains an inner loop from
+Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk> which does raw ecb DES calls at
+273,000 per second. He had a previous version at 250,000 and the best
+I was able to get was 203,000. The content has not changed, this is all
+due to instruction sequencing (and actual instructions choice) which is able
+to keep both functional units of the pentium going.
+We may have lost the ugly register usage restrictions when x86 went 32 bit
+but for the pentium it has been replaced by evil instruction ordering tricks.
+
+13 Jan 1997 - des-som3.pl, more optimizations from Svend Olaf.
+raw DES at 281,000 per second on a pentium 100.
+
diff --git a/linux/crypto/ciphers/des/cbc_enc.c b/linux/crypto/ciphers/des/cbc_enc.c
new file mode 100644
index 000000000..a06f9f99e
--- /dev/null
+++ b/linux/crypto/ciphers/des/cbc_enc.c
@@ -0,0 +1,135 @@
+/* crypto/des/cbc_enc.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "des_locl.h"
+
+void des_cbc_encrypt(input, output, length, schedule, ivec, enc)
+des_cblock (*input);
+des_cblock (*output);
+long length;
+des_key_schedule schedule;
+des_cblock (*ivec);
+int enc;
+ {
+ register DES_LONG tin0,tin1;
+ register DES_LONG tout0,tout1,xor0,xor1;
+ register unsigned char *in,*out;
+ register long l=length;
+ DES_LONG tin[2];
+ unsigned char *iv;
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ iv=(unsigned char *)ivec;
+
+ if (enc)
+ {
+ c2l(iv,tout0);
+ c2l(iv,tout1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ if (l != -8)
+ {
+ c2ln(in,tin0,tin1,l+8);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ }
+ else
+ {
+ c2l(iv,xor0);
+ c2l(iv,xor1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2c(tout0,out);
+ l2c(tout1,out);
+ xor0=tin0;
+ xor1=tin1;
+ }
+ if (l != -8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2cn(tout0,tout1,out,l+8);
+ /* xor0=tin0;
+ xor1=tin1; */
+ }
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+ }
+
diff --git a/linux/crypto/ciphers/des/des.doc b/linux/crypto/ciphers/des/des.doc
new file mode 100644
index 000000000..1e3015812
--- /dev/null
+++ b/linux/crypto/ciphers/des/des.doc
@@ -0,0 +1,505 @@
+The DES library.
+
+Please note that this library was originally written to operate with
+eBones, a version of Kerberos that had had encryption removed when it left
+the USA and then put back in. As such there are some routines that I will
+advise not using but they are still in the library for historical reasons.
+For all calls that have an 'input' and 'output' variables, they can be the
+same.
+
+This library requires the inclusion of 'des.h'.
+
+All of the encryption functions take what is called a des_key_schedule as an
+argument. A des_key_schedule is an expanded form of the des key.
+A des_key is 8 bytes of odd parity, the type used to hold the key is a
+des_cblock. A des_cblock is an array of 8 bytes, often in this library
+description I will refer to input bytes when the function specifies
+des_cblock's as input or output, this just means that the variable should
+be a multiple of 8 bytes.
+
+The define DES_ENCRYPT is passed to specify encryption, DES_DECRYPT to
+specify decryption. The functions and global variable are as follows:
+
+int des_check_key;
+ DES keys are supposed to be odd parity. If this variable is set to
+ a non-zero value, des_set_key() will check that the key has odd
+ parity and is not one of the known weak DES keys. By default this
+ variable is turned off;
+
+void des_set_odd_parity(
+des_cblock *key );
+ This function takes a DES key (8 bytes) and sets the parity to odd.
+
+int des_is_weak_key(
+des_cblock *key );
+ This function returns a non-zero value if the DES key passed is a
+ weak, DES key. If it is a weak key, don't use it, try a different
+ one. If you are using 'random' keys, the chances of hitting a weak
+ key are 1/2^52 so it is probably not worth checking for them.
+
+int des_set_key(
+des_cblock *key,
+des_key_schedule schedule);
+ Des_set_key converts an 8 byte DES key into a des_key_schedule.
+ A des_key_schedule is an expanded form of the key which is used to
+ perform actual encryption. It can be regenerated from the DES key
+ so it only needs to be kept when encryption or decryption is about
+ to occur. Don't save or pass around des_key_schedule's since they
+ are CPU architecture dependent, DES keys are not. If des_check_key
+ is non zero, zero is returned if the key has the wrong parity or
+ the key is a weak key, else 1 is returned.
+
+int des_key_sched(
+des_cblock *key,
+des_key_schedule schedule);
+ An alternative name for des_set_key().
+
+int des_rw_mode; /* defaults to DES_PCBC_MODE */
+ This flag holds either DES_CBC_MODE or DES_PCBC_MODE (default).
+ This specifies the function to use in the enc_read() and enc_write()
+ functions.
+
+void des_encrypt(
+unsigned long *data,
+des_key_schedule ks,
+int enc);
+ This is the DES encryption function that gets called by just about
+ every other DES routine in the library. You should not use this
+ function except to implement 'modes' of DES. I say this because the
+ functions that call this routine do the conversion from 'char *' to
+ long, and this needs to be done to make sure 'non-aligned' memory
+ access do not occur. The characters are loaded 'little endian',
+ have a look at my source code for more details on how I use this
+ function.
+ Data is a pointer to 2 unsigned long's and ks is the
+ des_key_schedule to use. enc, is non zero specifies encryption,
+ zero if decryption.
+
+void des_encrypt2(
+unsigned long *data,
+des_key_schedule ks,
+int enc);
+ This functions is the same as des_encrypt() except that the DES
+ initial permutation (IP) and final permutation (FP) have been left
+ out. As for des_encrypt(), you should not use this function.
+ It is used by the routines in my library that implement triple DES.
+ IP() des_encrypt2() des_encrypt2() des_encrypt2() FP() is the same
+ as des_encrypt() des_encrypt() des_encrypt() except faster :-).
+
+void des_ecb_encrypt(
+des_cblock *input,
+des_cblock *output,
+des_key_schedule ks,
+int enc);
+ This is the basic Electronic Code Book form of DES, the most basic
+ form. Input is encrypted into output using the key represented by
+ ks. If enc is non zero (DES_ENCRYPT), encryption occurs, otherwise
+ decryption occurs. Input is 8 bytes long and output is 8 bytes.
+ (the des_cblock structure is 8 chars).
+
+void des_ecb3_encrypt(
+des_cblock *input,
+des_cblock *output,
+des_key_schedule ks1,
+des_key_schedule ks2,
+des_key_schedule ks3,
+int enc);
+ This is the 3 key EDE mode of ECB DES. What this means is that
+ the 8 bytes of input is encrypted with ks1, decrypted with ks2 and
+ then encrypted again with ks3, before being put into output;
+ C=E(ks3,D(ks2,E(ks1,M))). There is a macro, des_ecb2_encrypt()
+ that only takes 2 des_key_schedules that implements,
+ C=E(ks1,D(ks2,E(ks1,M))) in that the final encrypt is done with ks1.
+
+void des_cbc_encrypt(
+des_cblock *input,
+des_cblock *output,
+long length,
+des_key_schedule ks,
+des_cblock *ivec,
+int enc);
+ This routine implements DES in Cipher Block Chaining mode.
+ Input, which should be a multiple of 8 bytes is encrypted
+ (or decrypted) to output which will also be a multiple of 8 bytes.
+ The number of bytes is in length (and from what I've said above,
+ should be a multiple of 8). If length is not a multiple of 8, I'm
+ not being held responsible :-). ivec is the initialisation vector.
+ This function does not modify this variable. To correctly implement
+ cbc mode, you need to do one of 2 things; copy the last 8 bytes of
+ cipher text for use as the next ivec in your application,
+ or use des_ncbc_encrypt().
+ Only this routine has this problem with updating the ivec, all
+ other routines that are implementing cbc mode update ivec.
+
+void des_ncbc_encrypt(
+des_cblock *input,
+des_cblock *output,
+long length,
+des_key_schedule sk,
+des_cblock *ivec,
+int enc);
+ For historical reasons, des_cbc_encrypt() did not update the
+ ivec with the value requires so that subsequent calls to
+ des_cbc_encrypt() would 'chain'. This was needed so that the same
+ 'length' values would not need to be used when decrypting.
+ des_ncbc_encrypt() does the right thing. It is the same as
+ des_cbc_encrypt accept that ivec is updates with the correct value
+ to pass in subsequent calls to des_ncbc_encrypt(). I advise using
+ des_ncbc_encrypt() instead of des_cbc_encrypt();
+
+void des_xcbc_encrypt(
+des_cblock *input,
+des_cblock *output,
+long length,
+des_key_schedule sk,
+des_cblock *ivec,
+des_cblock *inw,
+des_cblock *outw,
+int enc);
+ This is RSA's DESX mode of DES. It uses inw and outw to
+ 'whiten' the encryption. inw and outw are secret (unlike the iv)
+ and are as such, part of the key. So the key is sort of 24 bytes.
+ This is much better than cbc des.
+
+void des_3cbc_encrypt(
+des_cblock *input,
+des_cblock *output,
+long length,
+des_key_schedule sk1,
+des_key_schedule sk2,
+des_cblock *ivec1,
+des_cblock *ivec2,
+int enc);
+ This function is flawed, do not use it. I have left it in the
+ library because it is used in my des(1) program and will function
+ correctly when used by des(1). If I removed the function, people
+ could end up unable to decrypt files.
+ This routine implements outer triple cbc encryption using 2 ks and
+ 2 ivec's. Use des_ede2_cbc_encrypt() instead.
+
+void des_ede3_cbc_encrypt(
+des_cblock *input,
+des_cblock *output,
+long length,
+des_key_schedule ks1,
+des_key_schedule ks2,
+des_key_schedule ks3,
+des_cblock *ivec,
+int enc);
+ This function implements inner triple CBC DES encryption with 3
+ keys. What this means is that each 'DES' operation
+ inside the cbc mode is really an C=E(ks3,D(ks2,E(ks1,M))).
+ Again, this is cbc mode so an ivec is requires.
+ This mode is used by SSL.
+ There is also a des_ede2_cbc_encrypt() that only uses 2
+ des_key_schedule's, the first being reused for the final
+ encryption. C=E(ks1,D(ks2,E(ks1,M))). This form of triple DES
+ is used by the RSAref library.
+
+void des_pcbc_encrypt(
+des_cblock *input,
+des_cblock *output,
+long length,
+des_key_schedule ks,
+des_cblock *ivec,
+int enc);
+ This is Propagating Cipher Block Chaining mode of DES. It is used
+ by Kerberos v4. It's parameters are the same as des_ncbc_encrypt().
+
+void des_cfb_encrypt(
+unsigned char *in,
+unsigned char *out,
+int numbits,
+long length,
+des_key_schedule ks,
+des_cblock *ivec,
+int enc);
+ Cipher Feedback Back mode of DES. This implementation 'feeds back'
+ in numbit blocks. The input (and output) is in multiples of numbits
+ bits. numbits should to be a multiple of 8 bits. Length is the
+ number of bytes input. If numbits is not a multiple of 8 bits,
+ the extra bits in the bytes will be considered padding. So if
+ numbits is 12, for each 2 input bytes, the 4 high bits of the
+ second byte will be ignored. So to encode 72 bits when using
+ a numbits of 12 take 12 bytes. To encode 72 bits when using
+ numbits of 9 will take 16 bytes. To encode 80 bits when using
+ numbits of 16 will take 10 bytes. etc, etc. This padding will
+ apply to both input and output.
+
+
+void des_cfb64_encrypt(
+unsigned char *in,
+unsigned char *out,
+long length,
+des_key_schedule ks,
+des_cblock *ivec,
+int *num,
+int enc);
+ This is one of the more useful functions in this DES library, it
+ implements CFB mode of DES with 64bit feedback. Why is this
+ useful you ask? Because this routine will allow you to encrypt an
+ arbitrary number of bytes, no 8 byte padding. Each call to this
+ routine will encrypt the input bytes to output and then update ivec
+ and num. num contains 'how far' we are though ivec. If this does
+ not make much sense, read more about cfb mode of DES :-).
+
+void des_ede3_cfb64_encrypt(
+unsigned char *in,
+unsigned char *out,
+long length,
+des_key_schedule ks1,
+des_key_schedule ks2,
+des_key_schedule ks3,
+des_cblock *ivec,
+int *num,
+int enc);
+ Same as des_cfb64_encrypt() accept that the DES operation is
+ triple DES. As usual, there is a macro for
+ des_ede2_cfb64_encrypt() which reuses ks1.
+
+void des_ofb_encrypt(
+unsigned char *in,
+unsigned char *out,
+int numbits,
+long length,
+des_key_schedule ks,
+des_cblock *ivec);
+ This is a implementation of Output Feed Back mode of DES. It is
+ the same as des_cfb_encrypt() in that numbits is the size of the
+ units dealt with during input and output (in bits).
+
+void des_ofb64_encrypt(
+unsigned char *in,
+unsigned char *out,
+long length,
+des_key_schedule ks,
+des_cblock *ivec,
+int *num);
+ The same as des_cfb64_encrypt() except that it is Output Feed Back
+ mode.
+
+void des_ede3_ofb64_encrypt(
+unsigned char *in,
+unsigned char *out,
+long length,
+des_key_schedule ks1,
+des_key_schedule ks2,
+des_key_schedule ks3,
+des_cblock *ivec,
+int *num);
+ Same as des_ofb64_encrypt() accept that the DES operation is
+ triple DES. As usual, there is a macro for
+ des_ede2_ofb64_encrypt() which reuses ks1.
+
+int des_read_pw_string(
+char *buf,
+int length,
+char *prompt,
+int verify);
+ This routine is used to get a password from the terminal with echo
+ turned off. Buf is where the string will end up and length is the
+ size of buf. Prompt is a string presented to the 'user' and if
+ verify is set, the key is asked for twice and unless the 2 copies
+ match, an error is returned. A return code of -1 indicates a
+ system error, 1 failure due to use interaction, and 0 is success.
+
+unsigned long des_cbc_cksum(
+des_cblock *input,
+des_cblock *output,
+long length,
+des_key_schedule ks,
+des_cblock *ivec);
+ This function produces an 8 byte checksum from input that it puts in
+ output and returns the last 4 bytes as a long. The checksum is
+ generated via cbc mode of DES in which only the last 8 byes are
+ kept. I would recommend not using this function but instead using
+ the EVP_Digest routines, or at least using MD5 or SHA. This
+ function is used by Kerberos v4 so that is why it stays in the
+ library.
+
+char *des_fcrypt(
+const char *buf,
+const char *salt
+char *ret);
+ This is my fast version of the unix crypt(3) function. This version
+ takes only a small amount of space relative to other fast
+ crypt() implementations. This is different to the normal crypt
+ in that the third parameter is the buffer that the return value
+ is written into. It needs to be at least 14 bytes long. This
+ function is thread safe, unlike the normal crypt.
+
+char *crypt(
+const char *buf,
+const char *salt);
+ This function calls des_fcrypt() with a static array passed as the
+ third parameter. This emulates the normal non-thread safe semantics
+ of crypt(3).
+
+void des_string_to_key(
+char *str,
+des_cblock *key);
+ This function takes str and converts it into a DES key. I would
+ recommend using MD5 instead and use the first 8 bytes of output.
+ When I wrote the first version of these routines back in 1990, MD5
+ did not exist but I feel these routines are still sound. This
+ routines is compatible with the one in MIT's libdes.
+
+void des_string_to_2keys(
+char *str,
+des_cblock *key1,
+des_cblock *key2);
+ This function takes str and converts it into 2 DES keys.
+ I would recommend using MD5 and using the 16 bytes as the 2 keys.
+ I have nothing against these 2 'string_to_key' routines, it's just
+ that if you say that your encryption key is generated by using the
+ 16 bytes of an MD5 hash, every-one knows how you generated your
+ keys.
+
+int des_read_password(
+des_cblock *key,
+char *prompt,
+int verify);
+ This routine combines des_read_pw_string() with des_string_to_key().
+
+int des_read_2passwords(
+des_cblock *key1,
+des_cblock *key2,
+char *prompt,
+int verify);
+ This routine combines des_read_pw_string() with des_string_to_2key().
+
+void des_random_seed(
+des_cblock key);
+ This routine sets a starting point for des_random_key().
+
+void des_random_key(
+des_cblock ret);
+ This function return a random key. Make sure to 'seed' the random
+ number generator (with des_random_seed()) before using this function.
+ I personally now use a MD5 based random number system.
+
+int des_enc_read(
+int fd,
+char *buf,
+int len,
+des_key_schedule ks,
+des_cblock *iv);
+ This function will write to a file descriptor the encrypted data
+ from buf. This data will be preceded by a 4 byte 'byte count' and
+ will be padded out to 8 bytes. The encryption is either CBC of
+ PCBC depending on the value of des_rw_mode. If it is DES_PCBC_MODE,
+ pcbc is used, if DES_CBC_MODE, cbc is used. The default is to use
+ DES_PCBC_MODE.
+
+int des_enc_write(
+int fd,
+char *buf,
+int len,
+des_key_schedule ks,
+des_cblock *iv);
+ This routines read stuff written by des_enc_read() and decrypts it.
+ I have used these routines quite a lot but I don't believe they are
+ suitable for non-blocking io. If you are after a full
+ authentication/encryption over networks, have a look at SSL instead.
+
+unsigned long des_quad_cksum(
+des_cblock *input,
+des_cblock *output,
+long length,
+int out_count,
+des_cblock *seed);
+ This is a function from Kerberos v4 that is not anything to do with
+ DES but was needed. It is a cksum that is quicker to generate than
+ des_cbc_cksum(); I personally would use MD5 routines now.
+=====
+Modes of DES
+Quite a bit of the following information has been taken from
+ AS 2805.5.2
+ Australian Standard
+ Electronic funds transfer - Requirements for interfaces,
+ Part 5.2: Modes of operation for an n-bit block cipher algorithm
+ Appendix A
+
+There are several different modes in which DES can be used, they are
+as follows.
+
+Electronic Codebook Mode (ECB) (des_ecb_encrypt())
+- 64 bits are enciphered at a time.
+- The order of the blocks can be rearranged without detection.
+- The same plaintext block always produces the same ciphertext block
+ (for the same key) making it vulnerable to a 'dictionary attack'.
+- An error will only affect one ciphertext block.
+
+Cipher Block Chaining Mode (CBC) (des_cbc_encrypt())
+- a multiple of 64 bits are enciphered at a time.
+- The CBC mode produces the same ciphertext whenever the same
+ plaintext is encrypted using the same key and starting variable.
+- The chaining operation makes the ciphertext blocks dependent on the
+ current and all preceding plaintext blocks and therefore blocks can not
+ be rearranged.
+- The use of different starting variables prevents the same plaintext
+ enciphering to the same ciphertext.
+- An error will affect the current and the following ciphertext blocks.
+
+Cipher Feedback Mode (CFB) (des_cfb_encrypt())
+- a number of bits (j) <= 64 are enciphered at a time.
+- The CFB mode produces the same ciphertext whenever the same
+ plaintext is encrypted using the same key and starting variable.
+- The chaining operation makes the ciphertext variables dependent on the
+ current and all preceding variables and therefore j-bit variables are
+ chained together and can not be rearranged.
+- The use of different starting variables prevents the same plaintext
+ enciphering to the same ciphertext.
+- The strength of the CFB mode depends on the size of k (maximal if
+ j == k). In my implementation this is always the case.
+- Selection of a small value for j will require more cycles through
+ the encipherment algorithm per unit of plaintext and thus cause
+ greater processing overheads.
+- Only multiples of j bits can be enciphered.
+- An error will affect the current and the following ciphertext variables.
+
+Output Feedback Mode (OFB) (des_ofb_encrypt())
+- a number of bits (j) <= 64 are enciphered at a time.
+- The OFB mode produces the same ciphertext whenever the same
+ plaintext enciphered using the same key and starting variable. More
+ over, in the OFB mode the same key stream is produced when the same
+ key and start variable are used. Consequently, for security reasons
+ a specific start variable should be used only once for a given key.
+- The absence of chaining makes the OFB more vulnerable to specific attacks.
+- The use of different start variables values prevents the same
+ plaintext enciphering to the same ciphertext, by producing different
+ key streams.
+- Selection of a small value for j will require more cycles through
+ the encipherment algorithm per unit of plaintext and thus cause
+ greater processing overheads.
+- Only multiples of j bits can be enciphered.
+- OFB mode of operation does not extend ciphertext errors in the
+ resultant plaintext output. Every bit error in the ciphertext causes
+ only one bit to be in error in the deciphered plaintext.
+- OFB mode is not self-synchronising. If the two operation of
+ encipherment and decipherment get out of synchronism, the system needs
+ to be re-initialised.
+- Each re-initialisation should use a value of the start variable
+ different from the start variable values used before with the same
+ key. The reason for this is that an identical bit stream would be
+ produced each time from the same parameters. This would be
+ susceptible to a ' known plaintext' attack.
+
+Triple ECB Mode (des_ecb3_encrypt())
+- Encrypt with key1, decrypt with key2 and encrypt with key3 again.
+- As for ECB encryption but increases the key length to 168 bits.
+ There are theoretic attacks that can be used that make the effective
+ key length 112 bits, but this attack also requires 2^56 blocks of
+ memory, not very likely, even for the NSA.
+- If both keys are the same it is equivalent to encrypting once with
+ just one key.
+- If the first and last key are the same, the key length is 112 bits.
+ There are attacks that could reduce the key space to 55 bit's but it
+ requires 2^56 blocks of memory.
+- If all 3 keys are the same, this is effectively the same as normal
+ ecb mode.
+
+Triple CBC Mode (des_ede3_cbc_encrypt())
+- Encrypt with key1, decrypt with key2 and then encrypt with key3.
+- As for CBC encryption but increases the key length to 168 bits with
+ the same restrictions as for triple ecb mode.
diff --git a/linux/crypto/ciphers/des/des_crypt.man b/linux/crypto/ciphers/des/des_crypt.man
new file mode 100644
index 000000000..0ecc41687
--- /dev/null
+++ b/linux/crypto/ciphers/des/des_crypt.man
@@ -0,0 +1,508 @@
+.TH DES_CRYPT 3
+.SH NAME
+des_read_password, des_read_2password,
+des_string_to_key, des_string_to_2key, des_read_pw_string,
+des_random_key, des_set_key,
+des_key_sched, des_ecb_encrypt, des_ecb3_encrypt, des_cbc_encrypt,
+des_3cbc_encrypt,
+des_pcbc_encrypt, des_cfb_encrypt, des_ofb_encrypt,
+des_cbc_cksum, des_quad_cksum,
+des_enc_read, des_enc_write, des_set_odd_parity,
+des_is_weak_key, crypt \- (non USA) DES encryption
+.SH SYNOPSIS
+.nf
+.nj
+.ft B
+#include <des.h>
+.PP
+.B int des_read_password(key,prompt,verify)
+des_cblock *key;
+char *prompt;
+int verify;
+.PP
+.B int des_read_2password(key1,key2,prompt,verify)
+des_cblock *key1,*key2;
+char *prompt;
+int verify;
+.PP
+.B int des_string_to_key(str,key)
+char *str;
+des_cblock *key;
+.PP
+.B int des_string_to_2keys(str,key1,key2)
+char *str;
+des_cblock *key1,*key2;
+.PP
+.B int des_read_pw_string(buf,length,prompt,verify)
+char *buf;
+int length;
+char *prompt;
+int verify;
+.PP
+.B int des_random_key(key)
+des_cblock *key;
+.PP
+.B int des_set_key(key,schedule)
+des_cblock *key;
+des_key_schedule schedule;
+.PP
+.B int des_key_sched(key,schedule)
+des_cblock *key;
+des_key_schedule schedule;
+.PP
+.B int des_ecb_encrypt(input,output,schedule,encrypt)
+des_cblock *input;
+des_cblock *output;
+des_key_schedule schedule;
+int encrypt;
+.PP
+.B int des_ecb3_encrypt(input,output,ks1,ks2,encrypt)
+des_cblock *input;
+des_cblock *output;
+des_key_schedule ks1,ks2;
+int encrypt;
+.PP
+.B int des_cbc_encrypt(input,output,length,schedule,ivec,encrypt)
+des_cblock *input;
+des_cblock *output;
+long length;
+des_key_schedule schedule;
+des_cblock *ivec;
+int encrypt;
+.PP
+.B int des_3cbc_encrypt(input,output,length,sk1,sk2,ivec1,ivec2,encrypt)
+des_cblock *input;
+des_cblock *output;
+long length;
+des_key_schedule sk1;
+des_key_schedule sk2;
+des_cblock *ivec1;
+des_cblock *ivec2;
+int encrypt;
+.PP
+.B int des_pcbc_encrypt(input,output,length,schedule,ivec,encrypt)
+des_cblock *input;
+des_cblock *output;
+long length;
+des_key_schedule schedule;
+des_cblock *ivec;
+int encrypt;
+.PP
+.B int des_cfb_encrypt(input,output,numbits,length,schedule,ivec,encrypt)
+unsigned char *input;
+unsigned char *output;
+int numbits;
+long length;
+des_key_schedule schedule;
+des_cblock *ivec;
+int encrypt;
+.PP
+.B int des_ofb_encrypt(input,output,numbits,length,schedule,ivec)
+unsigned char *input,*output;
+int numbits;
+long length;
+des_key_schedule schedule;
+des_cblock *ivec;
+.PP
+.B unsigned long des_cbc_cksum(input,output,length,schedule,ivec)
+des_cblock *input;
+des_cblock *output;
+long length;
+des_key_schedule schedule;
+des_cblock *ivec;
+.PP
+.B unsigned long des_quad_cksum(input,output,length,out_count,seed)
+des_cblock *input;
+des_cblock *output;
+long length;
+int out_count;
+des_cblock *seed;
+.PP
+.B int des_check_key;
+.PP
+.B int des_enc_read(fd,buf,len,sched,iv)
+int fd;
+char *buf;
+int len;
+des_key_schedule sched;
+des_cblock *iv;
+.PP
+.B int des_enc_write(fd,buf,len,sched,iv)
+int fd;
+char *buf;
+int len;
+des_key_schedule sched;
+des_cblock *iv;
+.PP
+.B extern int des_rw_mode;
+.PP
+.B void des_set_odd_parity(key)
+des_cblock *key;
+.PP
+.B int des_is_weak_key(key)
+des_cblock *key;
+.PP
+.B char *crypt(passwd,salt)
+char *passwd;
+char *salt;
+.PP
+.fi
+.SH DESCRIPTION
+This library contains a fast implementation of the DES encryption
+algorithm.
+.PP
+There are two phases to the use of DES encryption.
+The first is the generation of a
+.I des_key_schedule
+from a key,
+the second is the actual encryption.
+A des key is of type
+.I des_cblock.
+This type is made from 8 characters with odd parity.
+The least significant bit in the character is the parity bit.
+The key schedule is an expanded form of the key; it is used to speed the
+encryption process.
+.PP
+.I des_read_password
+writes the string specified by prompt to the standard output,
+turns off echo and reads an input string from standard input
+until terminated with a newline.
+If verify is non-zero, it prompts and reads the input again and verifies
+that both entered passwords are the same.
+The entered string is converted into a des key by using the
+.I des_string_to_key
+routine.
+The new key is placed in the
+.I des_cblock
+that was passed (by reference) to the routine.
+If there were no errors,
+.I des_read_password
+returns 0,
+-1 is returned if there was a terminal error and 1 is returned for
+any other error.
+.PP
+.I des_read_2password
+operates in the same way as
+.I des_read_password
+except that it generates 2 keys by using the
+.I des_string_to_2key
+function.
+.PP
+.I des_read_pw_string
+is called by
+.I des_read_password
+to read and verify a string from a terminal device.
+The string is returned in
+.I buf.
+The size of
+.I buf
+is passed to the routine via the
+.I length
+parameter.
+.PP
+.I des_string_to_key
+converts a string into a valid des key.
+.PP
+.I des_string_to_2key
+converts a string into 2 valid des keys.
+This routine is best suited for used to generate keys for use with
+.I des_ecb3_encrypt.
+.PP
+.I des_random_key
+returns a random key that is made of a combination of process id,
+time and an increasing counter.
+.PP
+Before a des key can be used it is converted into a
+.I des_key_schedule
+via the
+.I des_set_key
+routine.
+If the
+.I des_check_key
+flag is non-zero,
+.I des_set_key
+will check that the key passed is of odd parity and is not a week or
+semi-weak key.
+If the parity is wrong,
+then -1 is returned.
+If the key is a weak key,
+then -2 is returned.
+If an error is returned,
+the key schedule is not generated.
+.PP
+.I des_key_sched
+is another name for the
+.I des_set_key
+function.
+.PP
+The following routines mostly operate on an input and output stream of
+.I des_cblock's.
+.PP
+.I des_ecb_encrypt
+is the basic DES encryption routine that encrypts or decrypts a single 8-byte
+.I des_cblock
+in
+.I electronic code book
+mode.
+It always transforms the input data, pointed to by
+.I input,
+into the output data,
+pointed to by the
+.I output
+argument.
+If the
+.I encrypt
+argument is non-zero (DES_ENCRYPT),
+the
+.I input
+(cleartext) is encrypted in to the
+.I output
+(ciphertext) using the key_schedule specified by the
+.I schedule
+argument,
+previously set via
+.I des_set_key.
+If
+.I encrypt
+is zero (DES_DECRYPT),
+the
+.I input
+(now ciphertext)
+is decrypted into the
+.I output
+(now cleartext).
+Input and output may overlap.
+No meaningful value is returned.
+.PP
+.I des_ecb3_encrypt
+encrypts/decrypts the
+.I input
+block by using triple ecb DES encryption.
+This involves encrypting the input with
+.I ks1,
+decryption with the key schedule
+.I ks2,
+and then encryption with the first again.
+This routine greatly reduces the chances of brute force breaking of
+DES and has the advantage of if
+.I ks1
+and
+.I ks2
+are the same, it is equivalent to just encryption using ecb mode and
+.I ks1
+as the key.
+.PP
+.I des_cbc_encrypt
+encrypts/decrypts using the
+.I cipher-block-chaining
+mode of DES.
+If the
+.I encrypt
+argument is non-zero,
+the routine cipher-block-chain encrypts the cleartext data pointed to by the
+.I input
+argument into the ciphertext pointed to by the
+.I output
+argument,
+using the key schedule provided by the
+.I schedule
+argument,
+and initialisation vector provided by the
+.I ivec
+argument.
+If the
+.I length
+argument is not an integral multiple of eight bytes,
+the last block is copied to a temporary area and zero filled.
+The output is always
+an integral multiple of eight bytes.
+To make multiple cbc encrypt calls on a large amount of data appear to
+be one
+.I des_cbc_encrypt
+call, the
+.I ivec
+of subsequent calls should be the last 8 bytes of the output.
+.PP
+.I des_3cbc_encrypt
+encrypts/decrypts the
+.I input
+block by using triple cbc DES encryption.
+This involves encrypting the input with key schedule
+.I ks1,
+decryption with the key schedule
+.I ks2,
+and then encryption with the first again.
+2 initialisation vectors are required,
+.I ivec1
+and
+.I ivec2.
+Unlike
+.I des_cbc_encrypt,
+these initialisation vectors are modified by the subroutine.
+This routine greatly reduces the chances of brute force breaking of
+DES and has the advantage of if
+.I ks1
+and
+.I ks2
+are the same, it is equivalent to just encryption using cbc mode and
+.I ks1
+as the key.
+.PP
+.I des_pcbc_encrypt
+encrypt/decrypts using a modified block chaining mode.
+It provides better error propagation characteristics than cbc
+encryption.
+.PP
+.I des_cfb_encrypt
+encrypt/decrypts using cipher feedback mode. This method takes an
+array of characters as input and outputs and array of characters. It
+does not require any padding to 8 character groups. Note: the ivec
+variable is changed and the new changed value needs to be passed to
+the next call to this function. Since this function runs a complete
+DES ecb encryption per numbits, this function is only suggested for
+use when sending small numbers of characters.
+.PP
+.I des_ofb_encrypt
+encrypt using output feedback mode. This method takes an
+array of characters as input and outputs and array of characters. It
+does not require any padding to 8 character groups. Note: the ivec
+variable is changed and the new changed value needs to be passed to
+the next call to this function. Since this function runs a complete
+DES ecb encryption per numbits, this function is only suggested for
+use when sending small numbers of characters.
+.PP
+.I des_cbc_cksum
+produces an 8 byte checksum based on the input stream (via cbc encryption).
+The last 4 bytes of the checksum is returned and the complete 8 bytes is
+placed in
+.I output.
+.PP
+.I des_quad_cksum
+returns a 4 byte checksum from the input bytes.
+The algorithm can be iterated over the input,
+depending on
+.I out_count,
+1, 2, 3 or 4 times.
+If
+.I output
+is non-NULL,
+the 8 bytes generated by each pass are written into
+.I output.
+.PP
+.I des_enc_write
+is used to write
+.I len
+bytes
+to file descriptor
+.I fd
+from buffer
+.I buf.
+The data is encrypted via
+.I pcbc_encrypt
+(default) using
+.I sched
+for the key and
+.I iv
+as a starting vector.
+The actual data send down
+.I fd
+consists of 4 bytes (in network byte order) containing the length of the
+following encrypted data. The encrypted data then follows, padded with random
+data out to a multiple of 8 bytes.
+.PP
+.I des_enc_read
+is used to read
+.I len
+bytes
+from file descriptor
+.I fd
+into buffer
+.I buf.
+The data being read from
+.I fd
+is assumed to have come from
+.I des_enc_write
+and is decrypted using
+.I sched
+for the key schedule and
+.I iv
+for the initial vector.
+The
+.I des_enc_read/des_enc_write
+pair can be used to read/write to files, pipes and sockets.
+I have used them in implementing a version of rlogin in which all
+data is encrypted.
+.PP
+.I des_rw_mode
+is used to specify the encryption mode to use with
+.I des_enc_read
+and
+.I des_end_write.
+If set to
+.I DES_PCBC_MODE
+(the default), des_pcbc_encrypt is used.
+If set to
+.I DES_CBC_MODE
+des_cbc_encrypt is used.
+These two routines and the variable are not part of the normal MIT library.
+.PP
+.I des_set_odd_parity
+sets the parity of the passed
+.I key
+to odd. This routine is not part of the standard MIT library.
+.PP
+.I des_is_weak_key
+returns 1 is the passed key is a weak key (pick again :-),
+0 if it is ok.
+This routine is not part of the standard MIT library.
+.PP
+.I crypt
+is a replacement for the normal system crypt.
+It is much faster than the system crypt.
+.PP
+.SH FILES
+/usr/include/des.h
+.br
+/usr/lib/libdes.a
+.PP
+The encryption routines have been tested on 16bit, 32bit and 64bit
+machines of various endian and even works under VMS.
+.PP
+.SH BUGS
+.PP
+If you think this manual is sparse,
+read the des_crypt(3) manual from the MIT kerberos (or bones outside
+of the USA) distribution.
+.PP
+.I des_cfb_encrypt
+and
+.I des_ofb_encrypt
+operates on input of 8 bits. What this means is that if you set
+numbits to 12, and length to 2, the first 12 bits will come from the 1st
+input byte and the low half of the second input byte. The second 12
+bits will have the low 8 bits taken from the 3rd input byte and the
+top 4 bits taken from the 4th input byte. The same holds for output.
+This function has been implemented this way because most people will
+be using a multiple of 8 and because once you get into pulling bytes input
+bytes apart things get ugly!
+.PP
+.I des_read_pw_string
+is the most machine/OS dependent function and normally generates the
+most problems when porting this code.
+.PP
+.I des_string_to_key
+is probably different from the MIT version since there are lots
+of fun ways to implement one-way encryption of a text string.
+.PP
+The routines are optimised for 32 bit machines and so are not efficient
+on IBM PCs.
+.PP
+NOTE: extensive work has been done on this library since this document
+was origionally written. Please try to read des.doc from the libdes
+distribution since it is far more upto date and documents more of the
+functions. Libdes is now also being shipped as part of SSLeay, a
+general cryptographic library that amonst other things implements
+netscapes SSL protocoll. The most recent version can be found in
+SSLeay distributions.
+.SH AUTHOR
+Eric Young (eay@cryptsoft.com)
diff --git a/linux/crypto/ciphers/des/des_enc.c b/linux/crypto/ciphers/des/des_enc.c
new file mode 100644
index 000000000..1e1906d25
--- /dev/null
+++ b/linux/crypto/ciphers/des/des_enc.c
@@ -0,0 +1,502 @@
+/* crypto/des/des_enc.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "des_locl.h"
+
+void des_encrypt(data, ks, enc)
+DES_LONG *data;
+des_key_schedule ks;
+int enc;
+ {
+ register DES_LONG l,r,t,u;
+#ifdef DES_PTR
+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
+#endif
+#ifndef DES_UNROLL
+ register int i;
+#endif
+ register DES_LONG *s;
+
+ r=data[0];
+ l=data[1];
+
+ IP(r,l);
+ /* Things have been modified so that the initial rotate is
+ * done outside the loop. This required the
+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
+ * One perl script later and things have a 5% speed up on a sparc2.
+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ * for pointing this out. */
+ /* clear the top bits on machines with 8byte longs */
+ /* shift left by 2 */
+ r=ROTATE(r,29)&0xffffffffL;
+ l=ROTATE(l,29)&0xffffffffL;
+
+ s=(DES_LONG *)ks;
+ /* I don't know if it is worth the effort of loop unrolling the
+ * inner loop */
+ if (enc)
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r, 0); /* 1 */
+ D_ENCRYPT(r,l, 2); /* 2 */
+ D_ENCRYPT(l,r, 4); /* 3 */
+ D_ENCRYPT(r,l, 6); /* 4 */
+ D_ENCRYPT(l,r, 8); /* 5 */
+ D_ENCRYPT(r,l,10); /* 6 */
+ D_ENCRYPT(l,r,12); /* 7 */
+ D_ENCRYPT(r,l,14); /* 8 */
+ D_ENCRYPT(l,r,16); /* 9 */
+ D_ENCRYPT(r,l,18); /* 10 */
+ D_ENCRYPT(l,r,20); /* 11 */
+ D_ENCRYPT(r,l,22); /* 12 */
+ D_ENCRYPT(l,r,24); /* 13 */
+ D_ENCRYPT(r,l,26); /* 14 */
+ D_ENCRYPT(l,r,28); /* 15 */
+ D_ENCRYPT(r,l,30); /* 16 */
+#else
+ for (i=0; i<32; i+=8)
+ {
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ D_ENCRYPT(l,r,i+4); /* 3 */
+ D_ENCRYPT(r,l,i+6); /* 4 */
+ }
+#endif
+ }
+ else
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r,30); /* 16 */
+ D_ENCRYPT(r,l,28); /* 15 */
+ D_ENCRYPT(l,r,26); /* 14 */
+ D_ENCRYPT(r,l,24); /* 13 */
+ D_ENCRYPT(l,r,22); /* 12 */
+ D_ENCRYPT(r,l,20); /* 11 */
+ D_ENCRYPT(l,r,18); /* 10 */
+ D_ENCRYPT(r,l,16); /* 9 */
+ D_ENCRYPT(l,r,14); /* 8 */
+ D_ENCRYPT(r,l,12); /* 7 */
+ D_ENCRYPT(l,r,10); /* 6 */
+ D_ENCRYPT(r,l, 8); /* 5 */
+ D_ENCRYPT(l,r, 6); /* 4 */
+ D_ENCRYPT(r,l, 4); /* 3 */
+ D_ENCRYPT(l,r, 2); /* 2 */
+ D_ENCRYPT(r,l, 0); /* 1 */
+#else
+ for (i=30; i>0; i-=8)
+ {
+ D_ENCRYPT(l,r,i-0); /* 16 */
+ D_ENCRYPT(r,l,i-2); /* 15 */
+ D_ENCRYPT(l,r,i-4); /* 14 */
+ D_ENCRYPT(r,l,i-6); /* 13 */
+ }
+#endif
+ }
+
+ /* rotate and clear the top bits on machines with 8byte longs */
+ l=ROTATE(l,3)&0xffffffffL;
+ r=ROTATE(r,3)&0xffffffffL;
+
+ FP(r,l);
+ data[0]=l;
+ data[1]=r;
+ l=r=t=u=0;
+ }
+
+void des_encrypt2(data, ks, enc)
+DES_LONG *data;
+des_key_schedule ks;
+int enc;
+ {
+ register DES_LONG l,r,t,u;
+#ifdef DES_PTR
+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
+#endif
+#ifndef DES_UNROLL
+ register int i;
+#endif
+ register DES_LONG *s;
+
+ r=data[0];
+ l=data[1];
+
+ /* Things have been modified so that the initial rotate is
+ * done outside the loop. This required the
+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
+ * One perl script later and things have a 5% speed up on a sparc2.
+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ * for pointing this out. */
+ /* clear the top bits on machines with 8byte longs */
+ r=ROTATE(r,29)&0xffffffffL;
+ l=ROTATE(l,29)&0xffffffffL;
+
+ s=(DES_LONG *)ks;
+ /* I don't know if it is worth the effort of loop unrolling the
+ * inner loop */
+ if (enc)
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r, 0); /* 1 */
+ D_ENCRYPT(r,l, 2); /* 2 */
+ D_ENCRYPT(l,r, 4); /* 3 */
+ D_ENCRYPT(r,l, 6); /* 4 */
+ D_ENCRYPT(l,r, 8); /* 5 */
+ D_ENCRYPT(r,l,10); /* 6 */
+ D_ENCRYPT(l,r,12); /* 7 */
+ D_ENCRYPT(r,l,14); /* 8 */
+ D_ENCRYPT(l,r,16); /* 9 */
+ D_ENCRYPT(r,l,18); /* 10 */
+ D_ENCRYPT(l,r,20); /* 11 */
+ D_ENCRYPT(r,l,22); /* 12 */
+ D_ENCRYPT(l,r,24); /* 13 */
+ D_ENCRYPT(r,l,26); /* 14 */
+ D_ENCRYPT(l,r,28); /* 15 */
+ D_ENCRYPT(r,l,30); /* 16 */
+#else
+ for (i=0; i<32; i+=8)
+ {
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ D_ENCRYPT(l,r,i+4); /* 3 */
+ D_ENCRYPT(r,l,i+6); /* 4 */
+ }
+#endif
+ }
+ else
+ {
+#ifdef DES_UNROLL
+ D_ENCRYPT(l,r,30); /* 16 */
+ D_ENCRYPT(r,l,28); /* 15 */
+ D_ENCRYPT(l,r,26); /* 14 */
+ D_ENCRYPT(r,l,24); /* 13 */
+ D_ENCRYPT(l,r,22); /* 12 */
+ D_ENCRYPT(r,l,20); /* 11 */
+ D_ENCRYPT(l,r,18); /* 10 */
+ D_ENCRYPT(r,l,16); /* 9 */
+ D_ENCRYPT(l,r,14); /* 8 */
+ D_ENCRYPT(r,l,12); /* 7 */
+ D_ENCRYPT(l,r,10); /* 6 */
+ D_ENCRYPT(r,l, 8); /* 5 */
+ D_ENCRYPT(l,r, 6); /* 4 */
+ D_ENCRYPT(r,l, 4); /* 3 */
+ D_ENCRYPT(l,r, 2); /* 2 */
+ D_ENCRYPT(r,l, 0); /* 1 */
+#else
+ for (i=30; i>0; i-=8)
+ {
+ D_ENCRYPT(l,r,i-0); /* 16 */
+ D_ENCRYPT(r,l,i-2); /* 15 */
+ D_ENCRYPT(l,r,i-4); /* 14 */
+ D_ENCRYPT(r,l,i-6); /* 13 */
+ }
+#endif
+ }
+ /* rotate and clear the top bits on machines with 8byte longs */
+ data[0]=ROTATE(l,3)&0xffffffffL;
+ data[1]=ROTATE(r,3)&0xffffffffL;
+ l=r=t=u=0;
+ }
+
+void des_encrypt3(data,ks1,ks2,ks3)
+DES_LONG *data;
+des_key_schedule ks1;
+des_key_schedule ks2;
+des_key_schedule ks3;
+ {
+ register DES_LONG l,r;
+
+ l=data[0];
+ r=data[1];
+ IP(l,r);
+ data[0]=l;
+ data[1]=r;
+ des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT);
+ des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT);
+ des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT);
+ l=data[0];
+ r=data[1];
+ FP(r,l);
+ data[0]=l;
+ data[1]=r;
+ }
+
+void des_decrypt3(data,ks1,ks2,ks3)
+DES_LONG *data;
+des_key_schedule ks1;
+des_key_schedule ks2;
+des_key_schedule ks3;
+ {
+ register DES_LONG l,r;
+
+ l=data[0];
+ r=data[1];
+ IP(l,r);
+ data[0]=l;
+ data[1]=r;
+ des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT);
+ des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT);
+ des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT);
+ l=data[0];
+ r=data[1];
+ FP(r,l);
+ data[0]=l;
+ data[1]=r;
+ }
+
+#ifndef DES_DEFAULT_OPTIONS
+
+void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
+des_cblock (*input);
+des_cblock (*output);
+long length;
+des_key_schedule schedule;
+des_cblock (*ivec);
+int enc;
+ {
+ register DES_LONG tin0,tin1;
+ register DES_LONG tout0,tout1,xor0,xor1;
+ register unsigned char *in,*out;
+ register long l=length;
+ DES_LONG tin[2];
+ unsigned char *iv;
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ iv=(unsigned char *)ivec;
+
+ if (enc)
+ {
+ c2l(iv,tout0);
+ c2l(iv,tout1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ if (l != -8)
+ {
+ c2ln(in,tin0,tin1,l+8);
+ tin0^=tout0; tin[0]=tin0;
+ tin1^=tout1; tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+ tout0=tin[0]; l2c(tout0,out);
+ tout1=tin[1]; l2c(tout1,out);
+ }
+ iv=(unsigned char *)ivec;
+ l2c(tout0,iv);
+ l2c(tout1,iv);
+ }
+ else
+ {
+ c2l(iv,xor0);
+ c2l(iv,xor1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2c(tout0,out);
+ l2c(tout1,out);
+ xor0=tin0;
+ xor1=tin1;
+ }
+ if (l != -8)
+ {
+ c2l(in,tin0); tin[0]=tin0;
+ c2l(in,tin1); tin[1]=tin1;
+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
+ tout0=tin[0]^xor0;
+ tout1=tin[1]^xor1;
+ l2cn(tout0,tout1,out,l+8);
+ xor0=tin0;
+ xor1=tin1;
+ }
+
+ iv=(unsigned char *)ivec;
+ l2c(xor0,iv);
+ l2c(xor1,iv);
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+ }
+
+void des_ede3_cbc_encrypt(input, output, length, ks1, ks2, ks3, ivec, enc)
+des_cblock (*input);
+des_cblock (*output);
+long length;
+des_key_schedule ks1;
+des_key_schedule ks2;
+des_key_schedule ks3;
+des_cblock (*ivec);
+int enc;
+ {
+ register DES_LONG tin0,tin1;
+ register DES_LONG tout0,tout1,xor0,xor1;
+ register unsigned char *in,*out;
+ register long l=length;
+ DES_LONG tin[2];
+ unsigned char *iv;
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ iv=(unsigned char *)ivec;
+
+ if (enc)
+ {
+ c2l(iv,tout0);
+ c2l(iv,tout1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+ tin0^=tout0;
+ tin1^=tout1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ l2c(tout0,out);
+ l2c(tout1,out);
+ }
+ if (l != -8)
+ {
+ c2ln(in,tin0,tin1,l+8);
+ tin0^=tout0;
+ tin1^=tout1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ l2c(tout0,out);
+ l2c(tout1,out);
+ }
+ iv=(unsigned char *)ivec;
+ l2c(tout0,iv);
+ l2c(tout1,iv);
+ }
+ else
+ {
+ register DES_LONG t0,t1;
+
+ c2l(iv,xor0);
+ c2l(iv,xor1);
+ for (l-=8; l>=0; l-=8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+
+ t0=tin0;
+ t1=tin1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ tout0^=xor0;
+ tout1^=xor1;
+ l2c(tout0,out);
+ l2c(tout1,out);
+ xor0=t0;
+ xor1=t1;
+ }
+ if (l != -8)
+ {
+ c2l(in,tin0);
+ c2l(in,tin1);
+
+ t0=tin0;
+ t1=tin1;
+
+ tin[0]=tin0;
+ tin[1]=tin1;
+ des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
+ tout0=tin[0];
+ tout1=tin[1];
+
+ tout0^=xor0;
+ tout1^=xor1;
+ l2cn(tout0,tout1,out,l+8);
+ xor0=t0;
+ xor1=t1;
+ }
+
+ iv=(unsigned char *)ivec;
+ l2c(xor0,iv);
+ l2c(xor1,iv);
+ }
+ tin0=tin1=tout0=tout1=xor0=xor1=0;
+ tin[0]=tin[1]=0;
+ }
+
+#endif /* DES_DEFAULT_OPTIONS */
diff --git a/linux/crypto/ciphers/des/des_locl.h b/linux/crypto/ciphers/des/des_locl.h
new file mode 100644
index 000000000..020d6b7ca
--- /dev/null
+++ b/linux/crypto/ciphers/des/des_locl.h
@@ -0,0 +1,515 @@
+/* crypto/des/des_locl.org */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * Always modify des_locl.org since des_locl.h is automatically generated from
+ * it during SSLeay configuration.
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ */
+
+#ifndef HEADER_DES_LOCL_H
+#define HEADER_DES_LOCL_H
+
+#if defined(WIN32) || defined(WIN16)
+#ifndef MSDOS
+#define MSDOS
+#endif
+#endif
+
+#include "crypto/des.h"
+
+#ifndef DES_DEFAULT_OPTIONS
+/* the following is tweaked from a config script, that is why it is a
+ * protected undef/define */
+#ifndef DES_PTR
+#define DES_PTR
+#endif
+
+/* This helps C compiler generate the correct code for multiple functional
+ * units. It reduces register dependancies at the expense of 2 more
+ * registers */
+#ifndef DES_RISC1
+#define DES_RISC1
+#endif
+
+#ifndef DES_RISC2
+#undef DES_RISC2
+#endif
+
+#if defined(DES_RISC1) && defined(DES_RISC2)
+YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
+#endif
+
+/* Unroll the inner loop, this sometimes helps, sometimes hinders.
+ * Very mucy CPU dependant */
+#ifndef DES_UNROLL
+#define DES_UNROLL
+#endif
+
+/* These default values were supplied by
+ * Peter Gutman <pgut001@cs.auckland.ac.nz>
+ * They are only used if nothing else has been defined */
+#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL)
+/* Special defines which change the way the code is built depending on the
+ CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find
+ even newer MIPS CPU's, but at the moment one size fits all for
+ optimization options. Older Sparc's work better with only UNROLL, but
+ there's no way to tell at compile time what it is you're running on */
+
+#if defined( sun ) /* Newer Sparc's */
+ #define DES_PTR
+ #define DES_RISC1
+ #define DES_UNROLL
+#elif defined( __ultrix ) /* Older MIPS */
+ #define DES_PTR
+ #define DES_RISC2
+ #define DES_UNROLL
+#elif defined( __osf1__ ) /* Alpha */
+ #define DES_PTR
+ #define DES_RISC2
+#elif defined ( _AIX ) /* RS6000 */
+ /* Unknown */
+#elif defined( __hpux ) /* HP-PA */
+ /* Unknown */
+#elif defined( __aux ) /* 68K */
+ /* Unknown */
+#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */
+ #define DES_UNROLL
+#elif defined( __sgi ) /* Newer MIPS */
+ #define DES_PTR
+ #define DES_RISC2
+ #define DES_UNROLL
+#elif defined( i386 ) /* x86 boxes, should be gcc */
+ #define DES_PTR
+ #define DES_RISC1
+ #define DES_UNROLL
+#endif /* Systems-specific speed defines */
+#endif
+
+#endif /* DES_DEFAULT_OPTIONS */
+
+#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <io.h>
+#ifndef RAND
+#define RAND
+#endif
+#undef NOPROTO
+#endif
+
+#if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS)
+#ifndef __KERNEL__
+#include <string.h>
+#else
+#include <linux/string.h>
+#endif
+#endif
+
+#ifndef RAND
+#define RAND
+#endif
+
+#ifdef linux
+#undef RAND
+#endif
+
+#ifdef MSDOS
+#define getpid() 2
+#define RAND
+#undef NOPROTO
+#endif
+
+#if defined(NOCONST)
+#define const
+#endif
+
+#ifdef __STDC__
+#undef NOPROTO
+#endif
+
+#ifdef RAND
+#define srandom(s) srand(s)
+#define random rand
+#endif
+
+#define ITERATIONS 16
+#define HALF_ITERATIONS 8
+
+/* used in des_read and des_write */
+#define MAXWRITE (1024*16)
+#define BSIZE (MAXWRITE+4)
+
+#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \
+ l|=((DES_LONG)(*((c)++)))<< 8L, \
+ l|=((DES_LONG)(*((c)++)))<<16L, \
+ l|=((DES_LONG)(*((c)++)))<<24L)
+
+/* NOTE - c is not incremented as per c2l */
+#define c2ln(c,l1,l2,n) { \
+ c+=n; \
+ l1=l2=0; \
+ switch (n) { \
+ case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \
+ case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \
+ case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \
+ case 5: l2|=((DES_LONG)(*(--(c)))); \
+ case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \
+ case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \
+ case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \
+ case 1: l1|=((DES_LONG)(*(--(c)))); \
+ } \
+ }
+
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24L)&0xff))
+
+/* replacements for htonl and ntohl since I have no idea what to do
+ * when faced with machines with 8 byte longs. */
+#define HDRSIZE 4
+
+#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \
+ l|=((DES_LONG)(*((c)++)))<<16L, \
+ l|=((DES_LONG)(*((c)++)))<< 8L, \
+ l|=((DES_LONG)(*((c)++))))
+
+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+#define l2cn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \
+ } \
+ }
+
+#if defined(WIN32)
+#define ROTATE(a,n) (_lrotr(a,n))
+#else
+#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n))))
+#endif
+
+/* Don't worry about the LOAD_DATA() stuff, that is used by
+ * fcrypt() to add it's little bit to the front */
+
+#ifdef DES_FCRYPT
+
+#define LOAD_DATA_tmp(R,S,u,t,E0,E1) \
+ { DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); }
+
+#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
+ t=R^(R>>16L); \
+ u=t&E0; t&=E1; \
+ tmp=(u<<16); u^=R^s[S ]; u^=tmp; \
+ tmp=(t<<16); t^=R^s[S+1]; t^=tmp
+#else
+#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g)
+#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
+ u=R^s[S ]; \
+ t=R^s[S+1]
+#endif
+
+/* The changes to this macro may help or hinder, depending on the
+ * compiler and the achitecture. gcc2 always seems to do well :-).
+ * Inspired by Dana How <how@isl.stanford.edu>
+ * DO NOT use the alternative version on machines with 8 byte longs.
+ * It does not seem to work on the Alpha, even when DES_LONG is 4
+ * bytes, probably an issue of accessing non-word aligned objects :-( */
+#ifdef DES_PTR
+
+/* It recently occured to me that 0^0^0^0^0^0^0 == 0, so there
+ * is no reason to not xor all the sub items together. This potentially
+ * saves a register since things can be xored directly into L */
+
+#if defined(DES_RISC1) || defined(DES_RISC2)
+#ifdef DES_RISC1
+#define D_ENCRYPT(LL,R,S) { \
+ unsigned int u1,u2,u3; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0xfc; \
+ u2&=0xfc; \
+ t=ROTATE(t,4); \
+ u>>=16L; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
+ u3=(int)(u>>8L); \
+ u1=(int)u&0xfc; \
+ u3&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+u3); \
+ u2=(int)t>>8L; \
+ u1=(int)t&0xfc; \
+ u2&=0xfc; \
+ t>>=16L; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
+ u3=(int)t>>8L; \
+ u1=(int)t&0xfc; \
+ u3&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+u3); }
+#endif
+#ifdef DES_RISC2
+#define D_ENCRYPT(LL,R,S) { \
+ unsigned int u1,u2,s1,s2; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0xfc; \
+ u2&=0xfc; \
+ t=ROTATE(t,4); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
+ s1=(int)(u>>16L); \
+ s2=(int)(u>>24L); \
+ s1&=0xfc; \
+ s2&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+s1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+s2); \
+ u2=(int)t>>8L; \
+ u1=(int)t&0xfc; \
+ u2&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
+ s1=(int)(t>>16L); \
+ s2=(int)(t>>24L); \
+ s1&=0xfc; \
+ s2&=0xfc; \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+s1); \
+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+s2); }
+#endif
+#else
+#define D_ENCRYPT(LL,R,S) { \
+ LOAD_DATA_tmp(R,S,u,t,E0,E1); \
+ t=ROTATE(t,4); \
+ LL^= \
+ *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16L)&0xfc))^ \
+ *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24L)&0xfc)); }
+#endif
+
+#else /* original version */
+
+#if defined(DES_RISC1) || defined(DES_RISC2)
+#ifdef DES_RISC1
+#define D_ENCRYPT(LL,R,S) {\
+ unsigned int u1,u2,u3; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u>>=2L; \
+ t=ROTATE(t,6); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0x3f; \
+ u2&=0x3f; \
+ u>>=16L; \
+ LL^=des_SPtrans[0][u1]; \
+ LL^=des_SPtrans[2][u2]; \
+ u3=(int)u>>8L; \
+ u1=(int)u&0x3f; \
+ u3&=0x3f; \
+ LL^=des_SPtrans[4][u1]; \
+ LL^=des_SPtrans[6][u3]; \
+ u2=(int)t>>8L; \
+ u1=(int)t&0x3f; \
+ u2&=0x3f; \
+ t>>=16L; \
+ LL^=des_SPtrans[1][u1]; \
+ LL^=des_SPtrans[3][u2]; \
+ u3=(int)t>>8L; \
+ u1=(int)t&0x3f; \
+ u3&=0x3f; \
+ LL^=des_SPtrans[5][u1]; \
+ LL^=des_SPtrans[7][u3]; }
+#endif
+#ifdef DES_RISC2
+#define D_ENCRYPT(LL,R,S) {\
+ unsigned int u1,u2,s1,s2; \
+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
+ u>>=2L; \
+ t=ROTATE(t,6); \
+ u2=(int)u>>8L; \
+ u1=(int)u&0x3f; \
+ u2&=0x3f; \
+ LL^=des_SPtrans[0][u1]; \
+ LL^=des_SPtrans[2][u2]; \
+ s1=(int)u>>16L; \
+ s2=(int)u>>24L; \
+ s1&=0x3f; \
+ s2&=0x3f; \
+ LL^=des_SPtrans[4][s1]; \
+ LL^=des_SPtrans[6][s2]; \
+ u2=(int)t>>8L; \
+ u1=(int)t&0x3f; \
+ u2&=0x3f; \
+ LL^=des_SPtrans[1][u1]; \
+ LL^=des_SPtrans[3][u2]; \
+ s1=(int)t>>16; \
+ s2=(int)t>>24L; \
+ s1&=0x3f; \
+ s2&=0x3f; \
+ LL^=des_SPtrans[5][s1]; \
+ LL^=des_SPtrans[7][s2]; }
+#endif
+
+#else
+
+#define D_ENCRYPT(LL,R,S) {\
+ LOAD_DATA_tmp(R,S,u,t,E0,E1); \
+ t=ROTATE(t,4); \
+ LL^=\
+ des_SPtrans[0][(u>> 2L)&0x3f]^ \
+ des_SPtrans[2][(u>>10L)&0x3f]^ \
+ des_SPtrans[4][(u>>18L)&0x3f]^ \
+ des_SPtrans[6][(u>>26L)&0x3f]^ \
+ des_SPtrans[1][(t>> 2L)&0x3f]^ \
+ des_SPtrans[3][(t>>10L)&0x3f]^ \
+ des_SPtrans[5][(t>>18L)&0x3f]^ \
+ des_SPtrans[7][(t>>26L)&0x3f]; }
+#endif
+#endif
+
+ /* IP and FP
+ * The problem is more of a geometric problem that random bit fiddling.
+ 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6
+ 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4
+ 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2
+ 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0
+
+ 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7
+ 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5
+ 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3
+ 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1
+
+ The output has been subject to swaps of the form
+ 0 1 -> 3 1 but the odd and even bits have been put into
+ 2 3 2 0
+ different words. The main trick is to remember that
+ t=((l>>size)^r)&(mask);
+ r^=t;
+ l^=(t<<size);
+ can be used to swap and move bits between words.
+
+ So l = 0 1 2 3 r = 16 17 18 19
+ 4 5 6 7 20 21 22 23
+ 8 9 10 11 24 25 26 27
+ 12 13 14 15 28 29 30 31
+ becomes (for size == 2 and mask == 0x3333)
+ t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19
+ 6^20 7^21 -- -- 4 5 20 21 6 7 22 23
+ 10^24 11^25 -- -- 8 9 24 25 10 11 24 25
+ 14^28 15^29 -- -- 12 13 28 29 14 15 28 29
+
+ Thanks for hints from Richard Outerbridge - he told me IP&FP
+ could be done in 15 xor, 10 shifts and 5 ands.
+ When I finally started to think of the problem in 2D
+ I first got ~42 operations without xors. When I remembered
+ how to use xors :-) I got it to its final state.
+ */
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
+
+#define IP(l,r) \
+ { \
+ register DES_LONG tt; \
+ PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \
+ PERM_OP(l,r,tt,16,0x0000ffffL); \
+ PERM_OP(r,l,tt, 2,0x33333333L); \
+ PERM_OP(l,r,tt, 8,0x00ff00ffL); \
+ PERM_OP(r,l,tt, 1,0x55555555L); \
+ }
+
+#define FP(l,r) \
+ { \
+ register DES_LONG tt; \
+ PERM_OP(l,r,tt, 1,0x55555555L); \
+ PERM_OP(r,l,tt, 8,0x00ff00ffL); \
+ PERM_OP(l,r,tt, 2,0x33333333L); \
+ PERM_OP(r,l,tt,16,0x0000ffffL); \
+ PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \
+ }
+
+extern const DES_LONG des_SPtrans[8][64];
+
+#ifndef NOPROTO
+void fcrypt_body(DES_LONG *out,des_key_schedule ks,
+ DES_LONG Eswap0, DES_LONG Eswap1);
+#else
+void fcrypt_body();
+#endif
+
+#endif
diff --git a/linux/crypto/ciphers/des/des_opts.c b/linux/crypto/ciphers/des/des_opts.c
new file mode 100644
index 000000000..b6693c405
--- /dev/null
+++ b/linux/crypto/ciphers/des/des_opts.c
@@ -0,0 +1,620 @@
+/* crypto/des/des_opts.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* define PART1, PART2, PART3 or PART4 to build only with a few of the options.
+ * This is for machines with 64k code segment size restrictions. */
+
+#ifndef MSDOS
+#define TIMES
+#endif
+
+#include <stdio.h>
+#ifndef MSDOS
+#include <unistd.h>
+#else
+#include <io.h>
+extern void exit();
+#endif
+#include <signal.h>
+#ifndef VMS
+#ifndef _IRIX
+#include <time.h>
+#endif
+#ifdef TIMES
+#include <sys/types.h>
+#include <sys/times.h>
+#endif
+#else /* VMS */
+#include <types.h>
+struct tms {
+ time_t tms_utime;
+ time_t tms_stime;
+ time_t tms_uchild; /* I dunno... */
+ time_t tms_uchildsys; /* so these names are a guess :-) */
+ }
+#endif
+#ifndef TIMES
+#include <sys/timeb.h>
+#endif
+
+#ifdef sun
+#include <limits.h>
+#include <sys/param.h>
+#endif
+
+#include "des_locl.h"
+#include "spr.h"
+
+#define DES_DEFAULT_OPTIONS
+
+#if !defined(PART1) && !defined(PART2) && !defined(PART3) && !defined(PART4)
+#define PART1
+#define PART2
+#define PART3
+#define PART4
+#endif
+
+#ifdef PART1
+
+#undef DES_UNROLL
+#undef DES_RISC1
+#undef DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#define des_encrypt des_encrypt_u4_cisc_idx
+#define des_encrypt2 des_encrypt2_u4_cisc_idx
+#define des_encrypt3 des_encrypt3_u4_cisc_idx
+#define des_decrypt3 des_decrypt3_u4_cisc_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#undef DES_RISC1
+#undef DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_cisc_idx
+#define des_encrypt2 des_encrypt2_u16_cisc_idx
+#define des_encrypt3 des_encrypt3_u16_cisc_idx
+#define des_decrypt3 des_decrypt3_u16_cisc_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#undef DES_UNROLL
+#define DES_RISC1
+#undef DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_risc1_idx
+#define des_encrypt2 des_encrypt2_u4_risc1_idx
+#define des_encrypt3 des_encrypt3_u4_risc1_idx
+#define des_decrypt3 des_decrypt3_u4_risc1_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#endif
+
+#ifdef PART2
+
+#undef DES_UNROLL
+#undef DES_RISC1
+#define DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_risc2_idx
+#define des_encrypt2 des_encrypt2_u4_risc2_idx
+#define des_encrypt3 des_encrypt3_u4_risc2_idx
+#define des_decrypt3 des_decrypt3_u4_risc2_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#define DES_RISC1
+#undef DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_risc1_idx
+#define des_encrypt2 des_encrypt2_u16_risc1_idx
+#define des_encrypt3 des_encrypt3_u16_risc1_idx
+#define des_decrypt3 des_decrypt3_u16_risc1_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#undef DES_RISC1
+#define DES_RISC2
+#undef DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_risc2_idx
+#define des_encrypt2 des_encrypt2_u16_risc2_idx
+#define des_encrypt3 des_encrypt3_u16_risc2_idx
+#define des_decrypt3 des_decrypt3_u16_risc2_idx
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#endif
+
+#ifdef PART3
+
+#undef DES_UNROLL
+#undef DES_RISC1
+#undef DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_cisc_ptr
+#define des_encrypt2 des_encrypt2_u4_cisc_ptr
+#define des_encrypt3 des_encrypt3_u4_cisc_ptr
+#define des_decrypt3 des_decrypt3_u4_cisc_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#undef DES_RISC1
+#undef DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_cisc_ptr
+#define des_encrypt2 des_encrypt2_u16_cisc_ptr
+#define des_encrypt3 des_encrypt3_u16_cisc_ptr
+#define des_decrypt3 des_decrypt3_u16_cisc_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#undef DES_UNROLL
+#define DES_RISC1
+#undef DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_risc1_ptr
+#define des_encrypt2 des_encrypt2_u4_risc1_ptr
+#define des_encrypt3 des_encrypt3_u4_risc1_ptr
+#define des_decrypt3 des_decrypt3_u4_risc1_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#endif
+
+#ifdef PART4
+
+#undef DES_UNROLL
+#undef DES_RISC1
+#define DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u4_risc2_ptr
+#define des_encrypt2 des_encrypt2_u4_risc2_ptr
+#define des_encrypt3 des_encrypt3_u4_risc2_ptr
+#define des_decrypt3 des_decrypt3_u4_risc2_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#define DES_RISC1
+#undef DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_risc1_ptr
+#define des_encrypt2 des_encrypt2_u16_risc1_ptr
+#define des_encrypt3 des_encrypt3_u16_risc1_ptr
+#define des_decrypt3 des_decrypt3_u16_risc1_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#define DES_UNROLL
+#undef DES_RISC1
+#define DES_RISC2
+#define DES_PTR
+#undef D_ENCRYPT
+#undef des_encrypt
+#undef des_encrypt2
+#undef des_encrypt3
+#undef des_decrypt3
+#define des_encrypt des_encrypt_u16_risc2_ptr
+#define des_encrypt2 des_encrypt2_u16_risc2_ptr
+#define des_encrypt3 des_encrypt3_u16_risc2_ptr
+#define des_decrypt3 des_decrypt3_u16_risc2_ptr
+#undef HEADER_DES_LOCL_H
+#include "des_enc.c"
+
+#endif
+
+/* The following if from times(3) man page. It may need to be changed */
+#ifndef HZ
+# ifndef CLK_TCK
+# ifndef _BSD_CLK_TCK_ /* FreeBSD fix */
+# ifndef VMS
+# define HZ 100.0
+# else /* VMS */
+# define HZ 100.0
+# endif
+# else /* _BSD_CLK_TCK_ */
+# define HZ ((double)_BSD_CLK_TCK_)
+# endif
+# else /* CLK_TCK */
+# define HZ ((double)CLK_TCK)
+# endif
+#endif
+
+#define BUFSIZE ((long)1024)
+long run=0;
+
+#ifndef NOPROTO
+double Time_F(int s);
+#else
+double Time_F();
+#endif
+
+#ifdef SIGALRM
+#if defined(__STDC__) || defined(sgi)
+#define SIGRETTYPE void
+#else
+#define SIGRETTYPE int
+#endif
+
+#ifndef NOPROTO
+SIGRETTYPE sig_done(int sig);
+#else
+SIGRETTYPE sig_done();
+#endif
+
+SIGRETTYPE sig_done(sig)
+int sig;
+ {
+ signal(SIGALRM,sig_done);
+ run=0;
+#ifdef LINT
+ sig=sig;
+#endif
+ }
+#endif
+
+#define START 0
+#define STOP 1
+
+double Time_F(s)
+int s;
+ {
+ double ret;
+#ifdef TIMES
+ static struct tms tstart,tend;
+
+ if (s == START)
+ {
+ times(&tstart);
+ return(0);
+ }
+ else
+ {
+ times(&tend);
+ ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ;
+ return((ret == 0.0)?1e-6:ret);
+ }
+#else /* !times() */
+ static struct timeb tstart,tend;
+ long i;
+
+ if (s == START)
+ {
+ ftime(&tstart);
+ return(0);
+ }
+ else
+ {
+ ftime(&tend);
+ i=(long)tend.millitm-(long)tstart.millitm;
+ ret=((double)(tend.time-tstart.time))+((double)i)/1000.0;
+ return((ret == 0.0)?1e-6:ret);
+ }
+#endif
+ }
+
+#ifdef SIGALRM
+#define print_name(name) fprintf(stderr,"Doing %s's for 10 seconds\n",name); alarm(10);
+#else
+#define print_name(name) fprintf(stderr,"Doing %s %ld times\n",name,cb);
+#endif
+
+#define time_it(func,name,index) \
+ print_name(name); \
+ Time_F(START); \
+ for (count=0,run=1; COND(cb); count++) \
+ { \
+ unsigned long d[2]; \
+ func(d,&(sch[0]),DES_ENCRYPT); \
+ } \
+ tm[index]=Time_F(STOP); \
+ fprintf(stderr,"%ld %s's in %.2f second\n",count,name,tm[index]); \
+ tm[index]=((double)COUNT(cb))/tm[index];
+
+#define print_it(name,index) \
+ fprintf(stderr,"%s bytes per sec = %12.2f (%5.1fuS)\n",name, \
+ tm[index]*8,1.0e6/tm[index]);
+
+int main(argc,argv)
+int argc;
+char **argv;
+ {
+ long count;
+ static unsigned char buf[BUFSIZE];
+ static des_cblock key ={0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
+ static des_cblock key2={0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
+ static des_cblock key3={0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
+ des_key_schedule sch,sch2,sch3;
+ double d,tm[16],max=0;
+ int rank[16];
+ char *str[16];
+ int max_idx=0,i,num=0,j;
+#ifndef SIGALARM
+ long ca,cb,cc,cd,ce;
+#endif
+
+ for (i=0; i<12; i++)
+ {
+ tm[i]=0.0;
+ rank[i]=0;
+ }
+
+#ifndef TIMES
+ fprintf(stderr,"To get the most acurate results, try to run this\n");
+ fprintf(stderr,"program when this computer is idle.\n");
+#endif
+
+ des_set_key((C_Block *)key,sch);
+ des_set_key((C_Block *)key2,sch2);
+ des_set_key((C_Block *)key3,sch3);
+
+#ifndef SIGALRM
+ fprintf(stderr,"First we calculate the approximate speed ...\n");
+ des_set_key((C_Block *)key,sch);
+ count=10;
+ do {
+ long i;
+ unsigned long data[2];
+
+ count*=2;
+ Time_F(START);
+ for (i=count; i; i--)
+ des_encrypt(data,&(sch[0]),DES_ENCRYPT);
+ d=Time_F(STOP);
+ } while (d < 3.0);
+ ca=count;
+ cb=count*3;
+ cc=count*3*8/BUFSIZE+1;
+ cd=count*8/BUFSIZE+1;
+
+ ce=count/20+1;
+#define COND(d) (count != (d))
+#define COUNT(d) (d)
+#else
+#define COND(c) (run)
+#define COUNT(d) (count)
+ signal(SIGALRM,sig_done);
+ alarm(10);
+#endif
+
+#ifdef PART1
+ time_it(des_encrypt_u4_cisc_idx, "des_encrypt_u4_cisc_idx ", 0);
+ time_it(des_encrypt_u16_cisc_idx, "des_encrypt_u16_cisc_idx ", 1);
+ time_it(des_encrypt_u4_risc1_idx, "des_encrypt_u4_risc1_idx ", 2);
+ num+=3;
+#endif
+#ifdef PART2
+ time_it(des_encrypt_u16_risc1_idx,"des_encrypt_u16_risc1_idx", 3);
+ time_it(des_encrypt_u4_risc2_idx, "des_encrypt_u4_risc2_idx ", 4);
+ time_it(des_encrypt_u16_risc2_idx,"des_encrypt_u16_risc2_idx", 5);
+ num+=3;
+#endif
+#ifdef PART3
+ time_it(des_encrypt_u4_cisc_ptr, "des_encrypt_u4_cisc_ptr ", 6);
+ time_it(des_encrypt_u16_cisc_ptr, "des_encrypt_u16_cisc_ptr ", 7);
+ time_it(des_encrypt_u4_risc1_ptr, "des_encrypt_u4_risc1_ptr ", 8);
+ num+=3;
+#endif
+#ifdef PART4
+ time_it(des_encrypt_u16_risc1_ptr,"des_encrypt_u16_risc1_ptr", 9);
+ time_it(des_encrypt_u4_risc2_ptr, "des_encrypt_u4_risc2_ptr ",10);
+ time_it(des_encrypt_u16_risc2_ptr,"des_encrypt_u16_risc2_ptr",11);
+ num+=3;
+#endif
+
+#ifdef PART1
+ str[0]=" 4 c i";
+ print_it("des_encrypt_u4_cisc_idx ",0);
+ max=tm[0];
+ max_idx=0;
+ str[1]="16 c i";
+ print_it("des_encrypt_u16_cisc_idx ",1);
+ if (max < tm[1]) { max=tm[1]; max_idx=1; }
+ str[2]=" 4 r1 i";
+ print_it("des_encrypt_u4_risc1_idx ",2);
+ if (max < tm[2]) { max=tm[2]; max_idx=2; }
+#endif
+#ifdef PART2
+ str[3]="16 r1 i";
+ print_it("des_encrypt_u16_risc1_idx",3);
+ if (max < tm[3]) { max=tm[3]; max_idx=3; }
+ str[4]=" 4 r2 i";
+ print_it("des_encrypt_u4_risc2_idx ",4);
+ if (max < tm[4]) { max=tm[4]; max_idx=4; }
+ str[5]="16 r2 i";
+ print_it("des_encrypt_u16_risc2_idx",5);
+ if (max < tm[5]) { max=tm[5]; max_idx=5; }
+#endif
+#ifdef PART3
+ str[6]=" 4 c p";
+ print_it("des_encrypt_u4_cisc_ptr ",6);
+ if (max < tm[6]) { max=tm[6]; max_idx=6; }
+ str[7]="16 c p";
+ print_it("des_encrypt_u16_cisc_ptr ",7);
+ if (max < tm[7]) { max=tm[7]; max_idx=7; }
+ str[8]=" 4 r1 p";
+ print_it("des_encrypt_u4_risc1_ptr ",8);
+ if (max < tm[8]) { max=tm[8]; max_idx=8; }
+#endif
+#ifdef PART4
+ str[9]="16 r1 p";
+ print_it("des_encrypt_u16_risc1_ptr",9);
+ if (max < tm[9]) { max=tm[9]; max_idx=9; }
+ str[10]=" 4 r2 p";
+ print_it("des_encrypt_u4_risc2_ptr ",10);
+ if (max < tm[10]) { max=tm[10]; max_idx=10; }
+ str[11]="16 r2 p";
+ print_it("des_encrypt_u16_risc2_ptr",11);
+ if (max < tm[11]) { max=tm[11]; max_idx=11; }
+#endif
+ printf("options des ecb/s\n");
+ printf("%s %12.2f 100.0%%\n",str[max_idx],tm[max_idx]);
+ d=tm[max_idx];
+ tm[max_idx]= -2.0;
+ max= -1.0;
+ for (;;)
+ {
+ for (i=0; i<12; i++)
+ {
+ if (max < tm[i]) { max=tm[i]; j=i; }
+ }
+ if (max < 0.0) break;
+ printf("%s %12.2f %4.1f%%\n",str[j],tm[j],tm[j]/d*100.0);
+ tm[j]= -2.0;
+ max= -1.0;
+ }
+
+ switch (max_idx)
+ {
+ case 0:
+ printf("-DDES_DEFAULT_OPTIONS\n");
+ break;
+ case 1:
+ printf("-DDES_UNROLL\n");
+ break;
+ case 2:
+ printf("-DDES_RISC1\n");
+ break;
+ case 3:
+ printf("-DDES_UNROLL -DDES_RISC1\n");
+ break;
+ case 4:
+ printf("-DDES_RISC2\n");
+ break;
+ case 5:
+ printf("-DDES_UNROLL -DDES_RISC2\n");
+ break;
+ case 6:
+ printf("-DDES_PTR\n");
+ break;
+ case 7:
+ printf("-DDES_UNROLL -DDES_PTR\n");
+ break;
+ case 8:
+ printf("-DDES_RISC1 -DDES_PTR\n");
+ break;
+ case 9:
+ printf("-DDES_UNROLL -DDES_RISC1 -DDES_PTR\n");
+ break;
+ case 10:
+ printf("-DDES_RISC2 -DDES_PTR\n");
+ break;
+ case 11:
+ printf("-DDES_UNROLL -DDES_RISC2 -DDES_PTR\n");
+ break;
+ }
+ exit(0);
+#if defined(LINT) || defined(MSDOS)
+ return(0);
+#endif
+ }
diff --git a/linux/crypto/ciphers/des/des_ver.h b/linux/crypto/ciphers/des/des_ver.h
new file mode 100644
index 000000000..98352bc0d
--- /dev/null
+++ b/linux/crypto/ciphers/des/des_ver.h
@@ -0,0 +1,60 @@
+/* crypto/des/des_ver.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+extern char *DES_version; /* SSLeay version string */
+extern char *libdes_version; /* old libdes version string */
diff --git a/linux/crypto/ciphers/des/destest.c b/linux/crypto/ciphers/des/destest.c
new file mode 100644
index 000000000..ae896499e
--- /dev/null
+++ b/linux/crypto/ciphers/des/destest.c
@@ -0,0 +1,871 @@
+/* crypto/des/destest.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#if defined(WIN32) || defined(WIN16) || defined(WINDOWS)
+#ifndef MSDOS
+#define MSDOS
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef MSDOS
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <string.h>
+#include "des_locl.h"
+
+/* tisk tisk - the test keys don't all have odd parity :-( */
+/* test data */
+#define NUM_TESTS 34
+static unsigned char key_data[NUM_TESTS][8]={
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
+ {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10},
+ {0x7C,0xA1,0x10,0x45,0x4A,0x1A,0x6E,0x57},
+ {0x01,0x31,0xD9,0x61,0x9D,0xC1,0x37,0x6E},
+ {0x07,0xA1,0x13,0x3E,0x4A,0x0B,0x26,0x86},
+ {0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E},
+ {0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6},
+ {0x01,0x13,0xB9,0x70,0xFD,0x34,0xF2,0xCE},
+ {0x01,0x70,0xF1,0x75,0x46,0x8F,0xB5,0xE6},
+ {0x43,0x29,0x7F,0xAD,0x38,0xE3,0x73,0xFE},
+ {0x07,0xA7,0x13,0x70,0x45,0xDA,0x2A,0x16},
+ {0x04,0x68,0x91,0x04,0xC2,0xFD,0x3B,0x2F},
+ {0x37,0xD0,0x6B,0xB5,0x16,0xCB,0x75,0x46},
+ {0x1F,0x08,0x26,0x0D,0x1A,0xC2,0x46,0x5E},
+ {0x58,0x40,0x23,0x64,0x1A,0xBA,0x61,0x76},
+ {0x02,0x58,0x16,0x16,0x46,0x29,0xB0,0x07},
+ {0x49,0x79,0x3E,0xBC,0x79,0xB3,0x25,0x8F},
+ {0x4F,0xB0,0x5E,0x15,0x15,0xAB,0x73,0xA7},
+ {0x49,0xE9,0x5D,0x6D,0x4C,0xA2,0x29,0xBF},
+ {0x01,0x83,0x10,0xDC,0x40,0x9B,0x26,0xD6},
+ {0x1C,0x58,0x7F,0x1C,0x13,0x92,0x4F,0xEF},
+ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
+ {0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E},
+ {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10}};
+
+static unsigned char plain_data[NUM_TESTS][8]={
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
+ {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x01,0xA1,0xD6,0xD0,0x39,0x77,0x67,0x42},
+ {0x5C,0xD5,0x4C,0xA8,0x3D,0xEF,0x57,0xDA},
+ {0x02,0x48,0xD4,0x38,0x06,0xF6,0x71,0x72},
+ {0x51,0x45,0x4B,0x58,0x2D,0xDF,0x44,0x0A},
+ {0x42,0xFD,0x44,0x30,0x59,0x57,0x7F,0xA2},
+ {0x05,0x9B,0x5E,0x08,0x51,0xCF,0x14,0x3A},
+ {0x07,0x56,0xD8,0xE0,0x77,0x47,0x61,0xD2},
+ {0x76,0x25,0x14,0xB8,0x29,0xBF,0x48,0x6A},
+ {0x3B,0xDD,0x11,0x90,0x49,0x37,0x28,0x02},
+ {0x26,0x95,0x5F,0x68,0x35,0xAF,0x60,0x9A},
+ {0x16,0x4D,0x5E,0x40,0x4F,0x27,0x52,0x32},
+ {0x6B,0x05,0x6E,0x18,0x75,0x9F,0x5C,0xCA},
+ {0x00,0x4B,0xD6,0xEF,0x09,0x17,0x60,0x62},
+ {0x48,0x0D,0x39,0x00,0x6E,0xE7,0x62,0xF2},
+ {0x43,0x75,0x40,0xC8,0x69,0x8F,0x3C,0xFA},
+ {0x07,0x2D,0x43,0xA0,0x77,0x07,0x52,0x92},
+ {0x02,0xFE,0x55,0x77,0x81,0x17,0xF1,0x2A},
+ {0x1D,0x9D,0x5C,0x50,0x18,0xF7,0x28,0xC2},
+ {0x30,0x55,0x32,0x28,0x6D,0x6F,0x29,0x5A},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
+
+static unsigned char cipher_data[NUM_TESTS][8]={
+ {0x8C,0xA6,0x4D,0xE9,0xC1,0xB1,0x23,0xA7},
+ {0x73,0x59,0xB2,0x16,0x3E,0x4E,0xDC,0x58},
+ {0x95,0x8E,0x6E,0x62,0x7A,0x05,0x55,0x7B},
+ {0xF4,0x03,0x79,0xAB,0x9E,0x0E,0xC5,0x33},
+ {0x17,0x66,0x8D,0xFC,0x72,0x92,0x53,0x2D},
+ {0x8A,0x5A,0xE1,0xF8,0x1A,0xB8,0xF2,0xDD},
+ {0x8C,0xA6,0x4D,0xE9,0xC1,0xB1,0x23,0xA7},
+ {0xED,0x39,0xD9,0x50,0xFA,0x74,0xBC,0xC4},
+ {0x69,0x0F,0x5B,0x0D,0x9A,0x26,0x93,0x9B},
+ {0x7A,0x38,0x9D,0x10,0x35,0x4B,0xD2,0x71},
+ {0x86,0x8E,0xBB,0x51,0xCA,0xB4,0x59,0x9A},
+ {0x71,0x78,0x87,0x6E,0x01,0xF1,0x9B,0x2A},
+ {0xAF,0x37,0xFB,0x42,0x1F,0x8C,0x40,0x95},
+ {0x86,0xA5,0x60,0xF1,0x0E,0xC6,0xD8,0x5B},
+ {0x0C,0xD3,0xDA,0x02,0x00,0x21,0xDC,0x09},
+ {0xEA,0x67,0x6B,0x2C,0xB7,0xDB,0x2B,0x7A},
+ {0xDF,0xD6,0x4A,0x81,0x5C,0xAF,0x1A,0x0F},
+ {0x5C,0x51,0x3C,0x9C,0x48,0x86,0xC0,0x88},
+ {0x0A,0x2A,0xEE,0xAE,0x3F,0xF4,0xAB,0x77},
+ {0xEF,0x1B,0xF0,0x3E,0x5D,0xFA,0x57,0x5A},
+ {0x88,0xBF,0x0D,0xB6,0xD7,0x0D,0xEE,0x56},
+ {0xA1,0xF9,0x91,0x55,0x41,0x02,0x0B,0x56},
+ {0x6F,0xBF,0x1C,0xAF,0xCF,0xFD,0x05,0x56},
+ {0x2F,0x22,0xE4,0x9B,0xAB,0x7C,0xA1,0xAC},
+ {0x5A,0x6B,0x61,0x2C,0xC2,0x6C,0xCE,0x4A},
+ {0x5F,0x4C,0x03,0x8E,0xD1,0x2B,0x2E,0x41},
+ {0x63,0xFA,0xC0,0xD0,0x34,0xD9,0xF7,0x93},
+ {0x61,0x7B,0x3A,0x0C,0xE8,0xF0,0x71,0x00},
+ {0xDB,0x95,0x86,0x05,0xF8,0xC8,0xC6,0x06},
+ {0xED,0xBF,0xD1,0xC6,0x6C,0x29,0xCC,0xC7},
+ {0x35,0x55,0x50,0xB2,0x15,0x0E,0x24,0x51},
+ {0xCA,0xAA,0xAF,0x4D,0xEA,0xF1,0xDB,0xAE},
+ {0xD5,0xD4,0x4F,0xF7,0x20,0x68,0x3D,0x0D},
+ {0x2A,0x2B,0xB0,0x08,0xDF,0x97,0xC2,0xF2}};
+
+static unsigned char cipher_ecb2[NUM_TESTS-1][8]={
+ {0x92,0x95,0xB5,0x9B,0xB3,0x84,0x73,0x6E},
+ {0x19,0x9E,0x9D,0x6D,0xF3,0x9A,0xA8,0x16},
+ {0x2A,0x4B,0x4D,0x24,0x52,0x43,0x84,0x27},
+ {0x35,0x84,0x3C,0x01,0x9D,0x18,0xC5,0xB6},
+ {0x4A,0x5B,0x2F,0x42,0xAA,0x77,0x19,0x25},
+ {0xA0,0x6B,0xA9,0xB8,0xCA,0x5B,0x17,0x8A},
+ {0xAB,0x9D,0xB7,0xFB,0xED,0x95,0xF2,0x74},
+ {0x3D,0x25,0x6C,0x23,0xA7,0x25,0x2F,0xD6},
+ {0xB7,0x6F,0xAB,0x4F,0xBD,0xBD,0xB7,0x67},
+ {0x8F,0x68,0x27,0xD6,0x9C,0xF4,0x1A,0x10},
+ {0x82,0x57,0xA1,0xD6,0x50,0x5E,0x81,0x85},
+ {0xA2,0x0F,0x0A,0xCD,0x80,0x89,0x7D,0xFA},
+ {0xCD,0x2A,0x53,0x3A,0xDB,0x0D,0x7E,0xF3},
+ {0xD2,0xC2,0xBE,0x27,0xE8,0x1B,0x68,0xE3},
+ {0xE9,0x24,0xCF,0x4F,0x89,0x3C,0x5B,0x0A},
+ {0xA7,0x18,0xC3,0x9F,0xFA,0x9F,0xD7,0x69},
+ {0x77,0x2C,0x79,0xB1,0xD2,0x31,0x7E,0xB1},
+ {0x49,0xAB,0x92,0x7F,0xD0,0x22,0x00,0xB7},
+ {0xCE,0x1C,0x6C,0x7D,0x85,0xE3,0x4A,0x6F},
+ {0xBE,0x91,0xD6,0xE1,0x27,0xB2,0xE9,0x87},
+ {0x70,0x28,0xAE,0x8F,0xD1,0xF5,0x74,0x1A},
+ {0xAA,0x37,0x80,0xBB,0xF3,0x22,0x1D,0xDE},
+ {0xA6,0xC4,0xD2,0x5E,0x28,0x93,0xAC,0xB3},
+ {0x22,0x07,0x81,0x5A,0xE4,0xB7,0x1A,0xAD},
+ {0xDC,0xCE,0x05,0xE7,0x07,0xBD,0xF5,0x84},
+ {0x26,0x1D,0x39,0x2C,0xB3,0xBA,0xA5,0x85},
+ {0xB4,0xF7,0x0F,0x72,0xFB,0x04,0xF0,0xDC},
+ {0x95,0xBA,0xA9,0x4E,0x87,0x36,0xF2,0x89},
+ {0xD4,0x07,0x3A,0xF1,0x5A,0x17,0x82,0x0E},
+ {0xEF,0x6F,0xAF,0xA7,0x66,0x1A,0x7E,0x89},
+ {0xC1,0x97,0xF5,0x58,0x74,0x8A,0x20,0xE7},
+ {0x43,0x34,0xCF,0xDA,0x22,0xC4,0x86,0xC8},
+ {0x08,0xD7,0xB4,0xFB,0x62,0x9D,0x08,0x85}};
+
+static unsigned char cbc_key [8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
+static unsigned char cbc2_key[8]={0xf0,0xe1,0xd2,0xc3,0xb4,0xa5,0x96,0x87};
+static unsigned char cbc3_key[8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
+static unsigned char cbc_iv [8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
+static char cbc_data[40]="7654321 Now is the time for \0001";
+
+static unsigned char cbc_ok[32]={
+ 0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
+ 0xac,0xd8,0xae,0xfd,0xdf,0xd8,0xa1,0xeb,
+ 0x46,0x8e,0x91,0x15,0x78,0x88,0xba,0x68,
+ 0x1d,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4};
+
+static unsigned char xcbc_ok[32]={
+ 0x86,0x74,0x81,0x0D,0x61,0xA4,0xA5,0x48,
+ 0xB9,0x93,0x03,0xE1,0xB8,0xBB,0xBD,0xBD,
+ 0x64,0x30,0x0B,0xB9,0x06,0x65,0x81,0x76,
+ 0x04,0x1D,0x77,0x62,0x17,0xCA,0x2B,0xD2,
+ };
+
+static unsigned char cbc3_ok[32]={
+ 0x3F,0xE3,0x01,0xC9,0x62,0xAC,0x01,0xD0,
+ 0x22,0x13,0x76,0x3C,0x1C,0xBD,0x4C,0xDC,
+ 0x79,0x96,0x57,0xC0,0x64,0xEC,0xF5,0xD4,
+ 0x1C,0x67,0x38,0x12,0xCF,0xDE,0x96,0x75};
+
+static unsigned char pcbc_ok[32]={
+ 0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
+ 0x6d,0xec,0xb4,0x70,0xa0,0xe5,0x6b,0x15,
+ 0xae,0xa6,0xbf,0x61,0xed,0x7d,0x9c,0x9f,
+ 0xf7,0x17,0x46,0x3b,0x8a,0xb3,0xcc,0x88};
+
+static unsigned char cfb_key[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
+static unsigned char cfb_iv[8]={0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef};
+static unsigned char cfb_buf1[40],cfb_buf2[40],cfb_tmp[8];
+static unsigned char plain[24]=
+ {
+ 0x4e,0x6f,0x77,0x20,0x69,0x73,
+ 0x20,0x74,0x68,0x65,0x20,0x74,
+ 0x69,0x6d,0x65,0x20,0x66,0x6f,
+ 0x72,0x20,0x61,0x6c,0x6c,0x20
+ };
+static unsigned char cfb_cipher8[24]= {
+ 0xf3,0x1f,0xda,0x07,0x01,0x14, 0x62,0xee,0x18,0x7f,0x43,0xd8,
+ 0x0a,0x7c,0xd9,0xb5,0xb0,0xd2, 0x90,0xda,0x6e,0x5b,0x9a,0x87 };
+static unsigned char cfb_cipher16[24]={
+ 0xF3,0x09,0x87,0x87,0x7F,0x57, 0xF7,0x3C,0x36,0xB6,0xDB,0x70,
+ 0xD8,0xD5,0x34,0x19,0xD3,0x86, 0xB2,0x23,0xB7,0xB2,0xAD,0x1B };
+static unsigned char cfb_cipher32[24]={
+ 0xF3,0x09,0x62,0x49,0xA4,0xDF, 0xA4,0x9F,0x33,0xDC,0x7B,0xAD,
+ 0x4C,0xC8,0x9F,0x64,0xE4,0x53, 0xE5,0xEC,0x67,0x20,0xDA,0xB6 };
+static unsigned char cfb_cipher48[24]={
+ 0xF3,0x09,0x62,0x49,0xC7,0xF4, 0x30,0xB5,0x15,0xEC,0xBB,0x85,
+ 0x97,0x5A,0x13,0x8C,0x68,0x60, 0xE2,0x38,0x34,0x3C,0xDC,0x1F };
+static unsigned char cfb_cipher64[24]={
+ 0xF3,0x09,0x62,0x49,0xC7,0xF4, 0x6E,0x51,0xA6,0x9E,0x83,0x9B,
+ 0x1A,0x92,0xF7,0x84,0x03,0x46, 0x71,0x33,0x89,0x8E,0xA6,0x22 };
+
+static unsigned char ofb_key[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
+static unsigned char ofb_iv[8]={0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef};
+static unsigned char ofb_buf1[24],ofb_buf2[24],ofb_tmp[8];
+static unsigned char ofb_cipher[24]=
+ {
+ 0xf3,0x09,0x62,0x49,0xc7,0xf4,0x6e,0x51,
+ 0x35,0xf2,0x4a,0x24,0x2e,0xeb,0x3d,0x3f,
+ 0x3d,0x6d,0x5b,0xe3,0x25,0x5a,0xf8,0xc3
+ };
+
+DES_LONG cbc_cksum_ret=0xB462FEF7L;
+unsigned char cbc_cksum_data[8]={0x1D,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4};
+
+#ifndef NOPROTO
+static char *pt(unsigned char *p);
+static int cfb_test(int bits, unsigned char *cfb_cipher);
+static int cfb64_test(unsigned char *cfb_cipher);
+static int ede_cfb64_test(unsigned char *cfb_cipher);
+#else
+static char *pt();
+static int cfb_test();
+static int cfb64_test();
+static int ede_cfb64_test();
+#endif
+
+int main(argc,argv)
+int argc;
+char *argv[];
+ {
+ int i,j,err=0;
+ des_cblock in,out,outin,iv3;
+ des_key_schedule ks,ks2,ks3;
+ unsigned char cbc_in[40];
+ unsigned char cbc_out[40];
+ DES_LONG cs;
+ unsigned char qret[4][4],cret[8];
+ DES_LONG lqret[4];
+ int num;
+ char *str;
+
+ printf("Doing ecb\n");
+ for (i=0; i<NUM_TESTS; i++)
+ {
+ if ((j=des_key_sched((C_Block *)(key_data[i]),ks)) != 0)
+ {
+ printf("Key error %2d:%d\n",i+1,j);
+ err=1;
+ }
+ memcpy(in,plain_data[i],8);
+ memset(out,0,8);
+ memset(outin,0,8);
+ des_ecb_encrypt((C_Block *)in,(C_Block *)out,ks,DES_ENCRYPT);
+ des_ecb_encrypt((C_Block *)out,(C_Block *)outin,ks,DES_DECRYPT);
+
+ if (memcmp(out,cipher_data[i],8) != 0)
+ {
+ printf("Encryption error %2d\nk=%s p=%s o=%s act=%s\n",
+ i+1,pt(key_data[i]),pt(in),pt(cipher_data[i]),
+ pt(out));
+ err=1;
+ }
+ if (memcmp(in,outin,8) != 0)
+ {
+ printf("Decryption error %2d\nk=%s p=%s o=%s act=%s\n",
+ i+1,pt(key_data[i]),pt(out),pt(in),pt(outin));
+ err=1;
+ }
+ }
+
+#ifndef LIBDES_LIT
+ printf("Doing ede ecb\n");
+ for (i=0; i<(NUM_TESTS-1); i++)
+ {
+ if ((j=des_key_sched((C_Block *)(key_data[i]),ks)) != 0)
+ {
+ err=1;
+ printf("Key error %2d:%d\n",i+1,j);
+ }
+ if ((j=des_key_sched((C_Block *)(key_data[i+1]),ks2)) != 0)
+ {
+ printf("Key error %2d:%d\n",i+2,j);
+ err=1;
+ }
+ if ((j=des_key_sched((C_Block *)(key_data[i+2]),ks3)) != 0)
+ {
+ printf("Key error %2d:%d\n",i+3,j);
+ err=1;
+ }
+ memcpy(in,plain_data[i],8);
+ memset(out,0,8);
+ memset(outin,0,8);
+ des_ecb2_encrypt((C_Block *)in,(C_Block *)out,ks,ks2,
+ DES_ENCRYPT);
+ des_ecb2_encrypt((C_Block *)out,(C_Block *)outin,ks,ks2,
+ DES_DECRYPT);
+
+ if (memcmp(out,cipher_ecb2[i],8) != 0)
+ {
+ printf("Encryption error %2d\nk=%s p=%s o=%s act=%s\n",
+ i+1,pt(key_data[i]),pt(in),pt(cipher_ecb2[i]),
+ pt(out));
+ err=1;
+ }
+ if (memcmp(in,outin,8) != 0)
+ {
+ printf("Decryption error %2d\nk=%s p=%s o=%s act=%s\n",
+ i+1,pt(key_data[i]),pt(out),pt(in),pt(outin));
+ err=1;
+ }
+ }
+#endif
+
+ printf("Doing cbc\n");
+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ memset(cbc_out,0,40);
+ memset(cbc_in,0,40);
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_ncbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
+ (long)strlen((char *)cbc_data)+1,ks,
+ (C_Block *)iv3,DES_ENCRYPT);
+ if (memcmp(cbc_out,cbc_ok,32) != 0)
+ printf("cbc_encrypt encrypt error\n");
+
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_ncbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
+ (long)strlen((char *)cbc_data)+1,ks,
+ (C_Block *)iv3,DES_DECRYPT);
+ if (memcmp(cbc_in,cbc_data,strlen((char *)cbc_data)) != 0)
+ {
+ printf("cbc_encrypt decrypt error\n");
+ err=1;
+ }
+
+#ifndef LIBDES_LIT
+ printf("Doing desx cbc\n");
+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ memset(cbc_out,0,40);
+ memset(cbc_in,0,40);
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_xcbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
+ (long)strlen((char *)cbc_data)+1,ks,
+ (C_Block *)iv3,
+ (C_Block *)cbc2_key, (C_Block *)cbc3_key, DES_ENCRYPT);
+ if (memcmp(cbc_out,xcbc_ok,32) != 0)
+ {
+ printf("des_xcbc_encrypt encrypt error\n");
+ }
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_xcbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
+ (long)strlen((char *)cbc_data)+1,ks,
+ (C_Block *)iv3,
+ (C_Block *)cbc2_key, (C_Block *)cbc3_key, DES_DECRYPT);
+ if (memcmp(cbc_in,cbc_data,strlen((char *)cbc_data)+1) != 0)
+ {
+ printf("des_xcbc_encrypt decrypt error\n");
+ err=1;
+ }
+#endif
+
+ printf("Doing ede cbc\n");
+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ if ((j=des_key_sched((C_Block *)cbc2_key,ks2)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ if ((j=des_key_sched((C_Block *)cbc3_key,ks3)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ memset(cbc_out,0,40);
+ memset(cbc_in,0,40);
+ i=strlen((char *)cbc_data)+1;
+ /* i=((i+7)/8)*8; */
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+
+ des_ede3_cbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
+ 16L,ks,ks2,ks3,(C_Block *)iv3,DES_ENCRYPT);
+ des_ede3_cbc_encrypt((C_Block *)&(cbc_data[16]),
+ (C_Block *)&(cbc_out[16]),
+ (long)i-16,ks,ks2,ks3,(C_Block *)iv3,DES_ENCRYPT);
+ if (memcmp(cbc_out,cbc3_ok,
+ (unsigned int)(strlen((char *)cbc_data)+1+7)/8*8) != 0)
+ {
+ printf("des_ede3_cbc_encrypt encrypt error\n");
+ err=1;
+ }
+
+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+ des_ede3_cbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
+ (long)i,ks,ks2,ks3,(C_Block *)iv3,DES_DECRYPT);
+ if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
+ {
+ printf("des_ede3_cbc_encrypt decrypt error\n");
+ err=1;
+ }
+
+#ifndef LIBDES_LIT
+ printf("Doing pcbc\n");
+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
+ {
+ printf("Key error %d\n",j);
+ err=1;
+ }
+ memset(cbc_out,0,40);
+ memset(cbc_in,0,40);
+ des_pcbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,DES_ENCRYPT);
+ if (memcmp(cbc_out,pcbc_ok,32) != 0)
+ {
+ printf("pcbc_encrypt encrypt error\n");
+ err=1;
+ }
+ des_pcbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,DES_DECRYPT);
+ if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
+ {
+ printf("pcbc_encrypt decrypt error\n");
+ err=1;
+ }
+
+ printf("Doing ");
+ printf("cfb8 ");
+ err+=cfb_test(8,cfb_cipher8);
+ printf("cfb16 ");
+ err+=cfb_test(16,cfb_cipher16);
+ printf("cfb32 ");
+ err+=cfb_test(32,cfb_cipher32);
+ printf("cfb48 ");
+ err+=cfb_test(48,cfb_cipher48);
+ printf("cfb64 ");
+ err+=cfb_test(64,cfb_cipher64);
+
+ printf("cfb64() ");
+ err+=cfb64_test(cfb_cipher64);
+
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ for (i=0; i<sizeof(plain); i++)
+ des_cfb_encrypt(&(plain[i]),&(cfb_buf1[i]),
+ 8,(long)1,ks,(C_Block *)cfb_tmp,DES_ENCRYPT);
+ if (memcmp(cfb_cipher8,cfb_buf1,sizeof(plain)) != 0)
+ {
+ printf("cfb_encrypt small encrypt error\n");
+ err=1;
+ }
+
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ for (i=0; i<sizeof(plain); i++)
+ des_cfb_encrypt(&(cfb_buf1[i]),&(cfb_buf2[i]),
+ 8,(long)1,ks,(C_Block *)cfb_tmp,DES_DECRYPT);
+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
+ {
+ printf("cfb_encrypt small decrypt error\n");
+ err=1;
+ }
+
+ printf("ede_cfb64() ");
+ err+=ede_cfb64_test(cfb_cipher64);
+
+ printf("done\n");
+
+ printf("Doing ofb\n");
+ des_key_sched((C_Block *)ofb_key,ks);
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ des_ofb_encrypt(plain,ofb_buf1,64,(long)sizeof(plain)/8,ks,
+ (C_Block *)ofb_tmp);
+ if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
+ {
+ printf("ofb_encrypt encrypt error\n");
+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+ofb_buf1[8+0], ofb_buf1[8+1], ofb_buf1[8+2], ofb_buf1[8+3],
+ofb_buf1[8+4], ofb_buf1[8+5], ofb_buf1[8+6], ofb_buf1[8+7]);
+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+ofb_buf1[8+0], ofb_cipher[8+1], ofb_cipher[8+2], ofb_cipher[8+3],
+ofb_buf1[8+4], ofb_cipher[8+5], ofb_cipher[8+6], ofb_cipher[8+7]);
+ err=1;
+ }
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ des_ofb_encrypt(ofb_buf1,ofb_buf2,64,(long)sizeof(ofb_buf1)/8,ks,
+ (C_Block *)ofb_tmp);
+ if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
+ {
+ printf("ofb_encrypt decrypt error\n");
+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+ofb_buf2[8+0], ofb_buf2[8+1], ofb_buf2[8+2], ofb_buf2[8+3],
+ofb_buf2[8+4], ofb_buf2[8+5], ofb_buf2[8+6], ofb_buf2[8+7]);
+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+plain[8+0], plain[8+1], plain[8+2], plain[8+3],
+plain[8+4], plain[8+5], plain[8+6], plain[8+7]);
+ err=1;
+ }
+
+ printf("Doing ofb64\n");
+ des_key_sched((C_Block *)ofb_key,ks);
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ memset(ofb_buf1,0,sizeof(ofb_buf1));
+ memset(ofb_buf2,0,sizeof(ofb_buf1));
+ num=0;
+ for (i=0; i<sizeof(plain); i++)
+ {
+ des_ofb64_encrypt(&(plain[i]),&(ofb_buf1[i]),1,ks,
+ (C_Block *)ofb_tmp,&num);
+ }
+ if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
+ {
+ printf("ofb64_encrypt encrypt error\n");
+ err=1;
+ }
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ num=0;
+ des_ofb64_encrypt(ofb_buf1,ofb_buf2,(long)sizeof(ofb_buf1),ks,
+ (C_Block *)ofb_tmp,&num);
+ if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
+ {
+ printf("ofb64_encrypt decrypt error\n");
+ err=1;
+ }
+
+ printf("Doing ede_ofb64\n");
+ des_key_sched((C_Block *)ofb_key,ks);
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ memset(ofb_buf1,0,sizeof(ofb_buf1));
+ memset(ofb_buf2,0,sizeof(ofb_buf1));
+ num=0;
+ for (i=0; i<sizeof(plain); i++)
+ {
+ des_ede3_ofb64_encrypt(&(plain[i]),&(ofb_buf1[i]),1,ks,ks,ks,
+ (C_Block *)ofb_tmp,&num);
+ }
+ if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
+ {
+ printf("ede_ofb64_encrypt encrypt error\n");
+ err=1;
+ }
+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
+ num=0;
+ des_ede3_ofb64_encrypt(ofb_buf1,ofb_buf2,(long)sizeof(ofb_buf1),ks,
+ ks,ks,(C_Block *)ofb_tmp,&num);
+ if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
+ {
+ printf("ede_ofb64_encrypt decrypt error\n");
+ err=1;
+ }
+
+ printf("Doing cbc_cksum\n");
+ des_key_sched((C_Block *)cbc_key,ks);
+ cs=des_cbc_cksum((C_Block *)cbc_data,(C_Block *)cret,
+ (long)strlen(cbc_data),ks,(C_Block *)cbc_iv);
+ if (cs != cbc_cksum_ret)
+ {
+ printf("bad return value (%08lX), should be %08lX\n",
+ (unsigned long)cs,(unsigned long)cbc_cksum_ret);
+ err=1;
+ }
+ if (memcmp(cret,cbc_cksum_data,8) != 0)
+ {
+ printf("bad cbc_cksum block returned\n");
+ err=1;
+ }
+
+ printf("Doing quad_cksum\n");
+ cs=quad_cksum((C_Block *)cbc_data,(C_Block *)qret,
+ (long)strlen(cbc_data),2,(C_Block *)cbc_iv);
+ for (i=0; i<4; i++)
+ {
+ lqret[i]=0;
+ memcpy(&(lqret[i]),&(qret[i][0]),4);
+ }
+ { /* Big-endian fix */
+ static DES_LONG l=1;
+ static unsigned char *c=(unsigned char *)&l;
+ DES_LONG ll;
+
+ if (!c[0])
+ {
+ ll=lqret[0]^lqret[3];
+ lqret[0]^=ll;
+ lqret[3]^=ll;
+ ll=lqret[1]^lqret[2];
+ lqret[1]^=ll;
+ lqret[2]^=ll;
+ }
+ }
+ if (cs != 0x70d7a63aL)
+ {
+ printf("quad_cksum error, ret %08lx should be 70d7a63a\n",
+ (unsigned long)cs);
+ err=1;
+ }
+ if (lqret[0] != 0x327eba8dL)
+ {
+ printf("quad_cksum error, out[0] %08lx is not %08lx\n",
+ (unsigned long)lqret[0],0x327eba8dL);
+ err=1;
+ }
+ if (lqret[1] != 0x201a49ccL)
+ {
+ printf("quad_cksum error, out[1] %08lx is not %08lx\n",
+ (unsigned long)lqret[1],0x201a49ccL);
+ err=1;
+ }
+ if (lqret[2] != 0x70d7a63aL)
+ {
+ printf("quad_cksum error, out[2] %08lx is not %08lx\n",
+ (unsigned long)lqret[2],0x70d7a63aL);
+ err=1;
+ }
+ if (lqret[3] != 0x501c2c26L)
+ {
+ printf("quad_cksum error, out[3] %08lx is not %08lx\n",
+ (unsigned long)lqret[3],0x501c2c26L);
+ err=1;
+ }
+#endif
+
+ printf("input word alignment test");
+ for (i=0; i<4; i++)
+ {
+ printf(" %d",i);
+ des_ncbc_encrypt((C_Block *)&(cbc_out[i]),(C_Block *)cbc_in,
+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,
+ DES_ENCRYPT);
+ }
+ printf("\noutput word alignment test");
+ for (i=0; i<4; i++)
+ {
+ printf(" %d",i);
+ des_ncbc_encrypt((C_Block *)cbc_out,(C_Block *)&(cbc_in[i]),
+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,
+ DES_ENCRYPT);
+ }
+ printf("\n");
+ printf("fast crypt test ");
+ str=crypt("testing","ef");
+ if (strcmp("efGnQx2725bI2",str) != 0)
+ {
+ printf("fast crypt error, %s should be efGnQx2725bI2\n",str);
+ err=1;
+ }
+ str=crypt("bca76;23","yA");
+ if (strcmp("yA1Rp/1hZXIJk",str) != 0)
+ {
+ printf("fast crypt error, %s should be yA1Rp/1hZXIJk\n",str);
+ err=1;
+ }
+ printf("\n");
+ exit(err);
+ return(0);
+ }
+
+static char *pt(p)
+unsigned char *p;
+ {
+ static char bufs[10][20];
+ static int bnum=0;
+ char *ret;
+ int i;
+ static char *f="0123456789ABCDEF";
+
+ ret= &(bufs[bnum++][0]);
+ bnum%=10;
+ for (i=0; i<8; i++)
+ {
+ ret[i*2]=f[(p[i]>>4)&0xf];
+ ret[i*2+1]=f[p[i]&0xf];
+ }
+ ret[16]='\0';
+ return(ret);
+ }
+
+#ifndef LIBDES_LIT
+
+static int cfb_test(bits, cfb_cipher)
+int bits;
+unsigned char *cfb_cipher;
+ {
+ des_key_schedule ks;
+ int i,err=0;
+
+ des_key_sched((C_Block *)cfb_key,ks);
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ des_cfb_encrypt(plain,cfb_buf1,bits,(long)sizeof(plain),ks,
+ (C_Block *)cfb_tmp,DES_ENCRYPT);
+ if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("cfb_encrypt encrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf1[i])));
+ }
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ des_cfb_encrypt(cfb_buf1,cfb_buf2,bits,(long)sizeof(plain),ks,
+ (C_Block *)cfb_tmp,DES_DECRYPT);
+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("cfb_encrypt decrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf1[i])));
+ }
+ return(err);
+ }
+
+static int cfb64_test(cfb_cipher)
+unsigned char *cfb_cipher;
+ {
+ des_key_schedule ks;
+ int err=0,i,n;
+
+ des_key_sched((C_Block *)cfb_key,ks);
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ n=0;
+ des_cfb64_encrypt(plain,cfb_buf1,(long)12,ks,
+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
+ des_cfb64_encrypt(&(plain[12]),&(cfb_buf1[12]),
+ (long)sizeof(plain)-12,ks,
+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
+ if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("cfb_encrypt encrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf1[i])));
+ }
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ n=0;
+ des_cfb64_encrypt(cfb_buf1,cfb_buf2,(long)17,ks,
+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
+ des_cfb64_encrypt(&(cfb_buf1[17]),&(cfb_buf2[17]),
+ (long)sizeof(plain)-17,ks,
+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("cfb_encrypt decrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf2[i])));
+ }
+ return(err);
+ }
+
+static int ede_cfb64_test(cfb_cipher)
+unsigned char *cfb_cipher;
+ {
+ des_key_schedule ks;
+ int err=0,i,n;
+
+ des_key_sched((C_Block *)cfb_key,ks);
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ n=0;
+ des_ede3_cfb64_encrypt(plain,cfb_buf1,(long)12,ks,ks,ks,
+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
+ des_ede3_cfb64_encrypt(&(plain[12]),&(cfb_buf1[12]),
+ (long)sizeof(plain)-12,ks,ks,ks,
+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
+ if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("ede_cfb_encrypt encrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf1[i])));
+ }
+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
+ n=0;
+ des_ede3_cfb64_encrypt(cfb_buf1,cfb_buf2,(long)17,ks,ks,ks,
+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
+ des_ede3_cfb64_encrypt(&(cfb_buf1[17]),&(cfb_buf2[17]),
+ (long)sizeof(plain)-17,ks,ks,ks,
+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
+ {
+ err=1;
+ printf("ede_cfb_encrypt decrypt error\n");
+ for (i=0; i<24; i+=8)
+ printf("%s\n",pt(&(cfb_buf2[i])));
+ }
+ return(err);
+ }
+
+#endif
+
diff --git a/linux/crypto/ciphers/des/dx86unix.S b/linux/crypto/ciphers/des/dx86unix.S
new file mode 100644
index 000000000..31dc0d0e1
--- /dev/null
+++ b/linux/crypto/ciphers/des/dx86unix.S
@@ -0,0 +1,3160 @@
+/*
+ * This file was originally generated by Michael Richardson <mcr@freeswan.org>
+ * via the perl scripts found in the ASM subdir. It remains copyright of
+ * Eric Young, see the file COPYRIGHT.
+ *
+ * This was last done on October 9, 2002.
+ *
+ * While this file does not need to go through cpp, we pass it through
+ * CPP by naming it dx86unix.S instead of dx86unix.s because there is
+ * a bug in Rules.make for .s builds - specifically it references EXTRA_CFLAGS
+ * which may contain stuff that AS doesn't understand instead of
+ * referencing EXTRA_AFLAGS.
+ */
+
+ .file "dx86unix.S"
+ .version "01.01"
+.text
+ .align 16
+.globl des_encrypt
+ .type des_encrypt , @function
+des_encrypt:
+ pushl %esi
+ pushl %edi
+
+
+ movl 12(%esp), %esi
+ xorl %ecx, %ecx
+ pushl %ebx
+ pushl %ebp
+ movl (%esi), %eax
+ movl 28(%esp), %ebx
+ movl 4(%esi), %edi
+
+
+ roll $4, %eax
+ movl %eax, %esi
+ xorl %edi, %eax
+ andl $0xf0f0f0f0, %eax
+ xorl %eax, %esi
+ xorl %eax, %edi
+
+ roll $20, %edi
+ movl %edi, %eax
+ xorl %esi, %edi
+ andl $0xfff0000f, %edi
+ xorl %edi, %eax
+ xorl %edi, %esi
+
+ roll $14, %eax
+ movl %eax, %edi
+ xorl %esi, %eax
+ andl $0x33333333, %eax
+ xorl %eax, %edi
+ xorl %eax, %esi
+
+ roll $22, %esi
+ movl %esi, %eax
+ xorl %edi, %esi
+ andl $0x03fc03fc, %esi
+ xorl %esi, %eax
+ xorl %esi, %edi
+
+ roll $9, %eax
+ movl %eax, %esi
+ xorl %edi, %eax
+ andl $0xaaaaaaaa, %eax
+ xorl %eax, %esi
+ xorl %eax, %edi
+
+.byte 209
+.byte 199
+ movl 24(%esp), %ebp
+ cmpl $0, %ebx
+ je .L000start_decrypt
+
+
+ movl (%ebp), %eax
+ xorl %ebx, %ebx
+ movl 4(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 8(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 12(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 16(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 20(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 24(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 28(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 32(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 36(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 40(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 44(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 48(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 52(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 56(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 60(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 64(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 68(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 72(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 76(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 80(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 84(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 88(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 92(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 96(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 100(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 104(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 108(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 112(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 116(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 120(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 124(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+ jmp .L001end
+.L000start_decrypt:
+
+
+ movl 120(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 124(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 112(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 116(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 104(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 108(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 96(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 100(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 88(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 92(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 80(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 84(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 72(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 76(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 64(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 68(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 56(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 60(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 48(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 52(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 40(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 44(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 32(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 36(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 24(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 28(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 16(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 20(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 8(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 12(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl (%ebp), %eax
+ xorl %ebx, %ebx
+ movl 4(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+.L001end:
+
+
+ movl 20(%esp), %edx
+.byte 209
+.byte 206
+ movl %edi, %eax
+ xorl %esi, %edi
+ andl $0xaaaaaaaa, %edi
+ xorl %edi, %eax
+ xorl %edi, %esi
+
+ roll $23, %eax
+ movl %eax, %edi
+ xorl %esi, %eax
+ andl $0x03fc03fc, %eax
+ xorl %eax, %edi
+ xorl %eax, %esi
+
+ roll $10, %edi
+ movl %edi, %eax
+ xorl %esi, %edi
+ andl $0x33333333, %edi
+ xorl %edi, %eax
+ xorl %edi, %esi
+
+ roll $18, %esi
+ movl %esi, %edi
+ xorl %eax, %esi
+ andl $0xfff0000f, %esi
+ xorl %esi, %edi
+ xorl %esi, %eax
+
+ roll $12, %edi
+ movl %edi, %esi
+ xorl %eax, %edi
+ andl $0xf0f0f0f0, %edi
+ xorl %edi, %esi
+ xorl %edi, %eax
+
+ rorl $4, %eax
+ movl %eax, (%edx)
+ movl %esi, 4(%edx)
+ popl %ebp
+ popl %ebx
+ popl %edi
+ popl %esi
+ ret
+.des_encrypt_end:
+ .size des_encrypt , .des_encrypt_end-des_encrypt
+.ident "desasm.pl"
+.text
+ .align 16
+.globl des_encrypt2
+ .type des_encrypt2 , @function
+des_encrypt2:
+ pushl %esi
+ pushl %edi
+
+
+ movl 12(%esp), %eax
+ xorl %ecx, %ecx
+ pushl %ebx
+ pushl %ebp
+ movl (%eax), %esi
+ movl 28(%esp), %ebx
+ roll $3, %esi
+ movl 4(%eax), %edi
+ roll $3, %edi
+ movl 24(%esp), %ebp
+ cmpl $0, %ebx
+ je .L002start_decrypt
+
+
+ movl (%ebp), %eax
+ xorl %ebx, %ebx
+ movl 4(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 8(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 12(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 16(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 20(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 24(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 28(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 32(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 36(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 40(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 44(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 48(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 52(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 56(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 60(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 64(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 68(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 72(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 76(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 80(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 84(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 88(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 92(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 96(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 100(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 104(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 108(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 112(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 116(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 120(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 124(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+ jmp .L003end
+.L002start_decrypt:
+
+
+ movl 120(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 124(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 112(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 116(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 104(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 108(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 96(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 100(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 88(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 92(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 80(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 84(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 72(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 76(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 64(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 68(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 56(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 60(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 48(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 52(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 40(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 44(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 32(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 36(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 24(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 28(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl 16(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 20(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+
+
+ movl 8(%ebp), %eax
+ xorl %ebx, %ebx
+ movl 12(%ebp), %edx
+ xorl %esi, %eax
+ xorl %esi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %edi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %edi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %edi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %edi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %edi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %edi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %edi
+
+
+ movl (%ebp), %eax
+ xorl %ebx, %ebx
+ movl 4(%ebp), %edx
+ xorl %edi, %eax
+ xorl %edi, %edx
+ andl $0xfcfcfcfc, %eax
+ andl $0xcfcfcfcf, %edx
+ movb %al, %bl
+ movb %ah, %cl
+ rorl $4, %edx
+ movl des_SPtrans(%ebx),%ebp
+ movb %dl, %bl
+ xorl %ebp, %esi
+ movl 0x200+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movb %dh, %cl
+ shrl $16, %eax
+ movl 0x100+des_SPtrans(%ebx),%ebp
+ xorl %ebp, %esi
+ movb %ah, %bl
+ shrl $16, %edx
+ movl 0x300+des_SPtrans(%ecx),%ebp
+ xorl %ebp, %esi
+ movl 24(%esp), %ebp
+ movb %dh, %cl
+ andl $0xff, %eax
+ andl $0xff, %edx
+ movl 0x600+des_SPtrans(%ebx),%ebx
+ xorl %ebx, %esi
+ movl 0x700+des_SPtrans(%ecx),%ebx
+ xorl %ebx, %esi
+ movl 0x400+des_SPtrans(%eax),%ebx
+ xorl %ebx, %esi
+ movl 0x500+des_SPtrans(%edx),%ebx
+ xorl %ebx, %esi
+.L003end:
+
+
+ rorl $3, %edi
+ movl 20(%esp), %eax
+ rorl $3, %esi
+ movl %edi, (%eax)
+ movl %esi, 4(%eax)
+ popl %ebp
+ popl %ebx
+ popl %edi
+ popl %esi
+ ret
+.des_encrypt2_end:
+ .size des_encrypt2 , .des_encrypt2_end-des_encrypt2
+.ident "desasm.pl"
+.text
+ .align 16
+.globl des_encrypt3
+ .type des_encrypt3 , @function
+des_encrypt3:
+ pushl %ebx
+ movl 8(%esp), %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+
+
+ movl (%ebx), %edi
+ movl 4(%ebx), %esi
+ subl $12, %esp
+
+
+ roll $4, %edi
+ movl %edi, %edx
+ xorl %esi, %edi
+ andl $0xf0f0f0f0, %edi
+ xorl %edi, %edx
+ xorl %edi, %esi
+
+ roll $20, %esi
+ movl %esi, %edi
+ xorl %edx, %esi
+ andl $0xfff0000f, %esi
+ xorl %esi, %edi
+ xorl %esi, %edx
+
+ roll $14, %edi
+ movl %edi, %esi
+ xorl %edx, %edi
+ andl $0x33333333, %edi
+ xorl %edi, %esi
+ xorl %edi, %edx
+
+ roll $22, %edx
+ movl %edx, %edi
+ xorl %esi, %edx
+ andl $0x03fc03fc, %edx
+ xorl %edx, %edi
+ xorl %edx, %esi
+
+ roll $9, %edi
+ movl %edi, %edx
+ xorl %esi, %edi
+ andl $0xaaaaaaaa, %edi
+ xorl %edi, %edx
+ xorl %edi, %esi
+
+ rorl $3, %edx
+ rorl $2, %esi
+ movl %esi, 4(%ebx)
+ movl 36(%esp), %eax
+ movl %edx, (%ebx)
+ movl 40(%esp), %edi
+ movl 44(%esp), %esi
+ movl $1, 8(%esp)
+ movl %eax, 4(%esp)
+ movl %ebx, (%esp)
+ call des_encrypt2
+ movl $0, 8(%esp)
+ movl %edi, 4(%esp)
+ movl %ebx, (%esp)
+ call des_encrypt2
+ movl $1, 8(%esp)
+ movl %esi, 4(%esp)
+ movl %ebx, (%esp)
+ call des_encrypt2
+ addl $12, %esp
+ movl (%ebx), %edi
+ movl 4(%ebx), %esi
+
+
+ roll $2, %esi
+ roll $3, %edi
+ movl %edi, %eax
+ xorl %esi, %edi
+ andl $0xaaaaaaaa, %edi
+ xorl %edi, %eax
+ xorl %edi, %esi
+
+ roll $23, %eax
+ movl %eax, %edi
+ xorl %esi, %eax
+ andl $0x03fc03fc, %eax
+ xorl %eax, %edi
+ xorl %eax, %esi
+
+ roll $10, %edi
+ movl %edi, %eax
+ xorl %esi, %edi
+ andl $0x33333333, %edi
+ xorl %edi, %eax
+ xorl %edi, %esi
+
+ roll $18, %esi
+ movl %esi, %edi
+ xorl %eax, %esi
+ andl $0xfff0000f, %esi
+ xorl %esi, %edi
+ xorl %esi, %eax
+
+ roll $12, %edi
+ movl %edi, %esi
+ xorl %eax, %edi
+ andl $0xf0f0f0f0, %edi
+ xorl %edi, %esi
+ xorl %edi, %eax
+
+ rorl $4, %eax
+ movl %eax, (%ebx)
+ movl %esi, 4(%ebx)
+ popl %edi
+ popl %esi
+ popl %ebp
+ popl %ebx
+ ret
+.des_encrypt3_end:
+ .size des_encrypt3 , .des_encrypt3_end-des_encrypt3
+.ident "desasm.pl"
+.text
+ .align 16
+.globl des_decrypt3
+ .type des_decrypt3 , @function
+des_decrypt3:
+ pushl %ebx
+ movl 8(%esp), %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+
+
+ movl (%ebx), %edi
+ movl 4(%ebx), %esi
+ subl $12, %esp
+
+
+ roll $4, %edi
+ movl %edi, %edx
+ xorl %esi, %edi
+ andl $0xf0f0f0f0, %edi
+ xorl %edi, %edx
+ xorl %edi, %esi
+
+ roll $20, %esi
+ movl %esi, %edi
+ xorl %edx, %esi
+ andl $0xfff0000f, %esi
+ xorl %esi, %edi
+ xorl %esi, %edx
+
+ roll $14, %edi
+ movl %edi, %esi
+ xorl %edx, %edi
+ andl $0x33333333, %edi
+ xorl %edi, %esi
+ xorl %edi, %edx
+
+ roll $22, %edx
+ movl %edx, %edi
+ xorl %esi, %edx
+ andl $0x03fc03fc, %edx
+ xorl %edx, %edi
+ xorl %edx, %esi
+
+ roll $9, %edi
+ movl %edi, %edx
+ xorl %esi, %edi
+ andl $0xaaaaaaaa, %edi
+ xorl %edi, %edx
+ xorl %edi, %esi
+
+ rorl $3, %edx
+ rorl $2, %esi
+ movl %esi, 4(%ebx)
+ movl 36(%esp), %esi
+ movl %edx, (%ebx)
+ movl 40(%esp), %edi
+ movl 44(%esp), %eax
+ movl $0, 8(%esp)
+ movl %eax, 4(%esp)
+ movl %ebx, (%esp)
+ call des_encrypt2
+ movl $1, 8(%esp)
+ movl %edi, 4(%esp)
+ movl %ebx, (%esp)
+ call des_encrypt2
+ movl $0, 8(%esp)
+ movl %esi, 4(%esp)
+ movl %ebx, (%esp)
+ call des_encrypt2
+ addl $12, %esp
+ movl (%ebx), %edi
+ movl 4(%ebx), %esi
+
+
+ roll $2, %esi
+ roll $3, %edi
+ movl %edi, %eax
+ xorl %esi, %edi
+ andl $0xaaaaaaaa, %edi
+ xorl %edi, %eax
+ xorl %edi, %esi
+
+ roll $23, %eax
+ movl %eax, %edi
+ xorl %esi, %eax
+ andl $0x03fc03fc, %eax
+ xorl %eax, %edi
+ xorl %eax, %esi
+
+ roll $10, %edi
+ movl %edi, %eax
+ xorl %esi, %edi
+ andl $0x33333333, %edi
+ xorl %edi, %eax
+ xorl %edi, %esi
+
+ roll $18, %esi
+ movl %esi, %edi
+ xorl %eax, %esi
+ andl $0xfff0000f, %esi
+ xorl %esi, %edi
+ xorl %esi, %eax
+
+ roll $12, %edi
+ movl %edi, %esi
+ xorl %eax, %edi
+ andl $0xf0f0f0f0, %edi
+ xorl %edi, %esi
+ xorl %edi, %eax
+
+ rorl $4, %eax
+ movl %eax, (%ebx)
+ movl %esi, 4(%ebx)
+ popl %edi
+ popl %esi
+ popl %ebp
+ popl %ebx
+ ret
+.des_decrypt3_end:
+ .size des_decrypt3 , .des_decrypt3_end-des_decrypt3
+.ident "desasm.pl"
+.text
+ .align 16
+.globl des_ncbc_encrypt
+ .type des_ncbc_encrypt , @function
+des_ncbc_encrypt:
+
+ pushl %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ movl 28(%esp), %ebp
+
+ movl 36(%esp), %ebx
+ movl (%ebx), %esi
+ movl 4(%ebx), %edi
+ pushl %edi
+ pushl %esi
+ pushl %edi
+ pushl %esi
+ movl %esp, %ebx
+ movl 36(%esp), %esi
+ movl 40(%esp), %edi
+
+ movl 56(%esp), %ecx
+
+ pushl %ecx
+
+ movl 52(%esp), %eax
+ pushl %eax
+ pushl %ebx
+ cmpl $0, %ecx
+ jz .L004decrypt
+ andl $4294967288, %ebp
+ movl 12(%esp), %eax
+ movl 16(%esp), %ebx
+ jz .L005encrypt_finish
+.L006encrypt_loop:
+ movl (%esi), %ecx
+ movl 4(%esi), %edx
+ xorl %ecx, %eax
+ xorl %edx, %ebx
+ movl %eax, 12(%esp)
+ movl %ebx, 16(%esp)
+ call des_encrypt
+ movl 12(%esp), %eax
+ movl 16(%esp), %ebx
+ movl %eax, (%edi)
+ movl %ebx, 4(%edi)
+ addl $8, %esi
+ addl $8, %edi
+ subl $8, %ebp
+ jnz .L006encrypt_loop
+.L005encrypt_finish:
+ movl 56(%esp), %ebp
+ andl $7, %ebp
+ jz .L007finish
+ xorl %ecx, %ecx
+ xorl %edx, %edx
+ movl .L008cbc_enc_jmp_table(,%ebp,4),%ebp
+ jmp *%ebp
+.L009ej7:
+ movb 6(%esi), %dh
+ sall $8, %edx
+.L010ej6:
+ movb 5(%esi), %dh
+.L011ej5:
+ movb 4(%esi), %dl
+.L012ej4:
+ movl (%esi), %ecx
+ jmp .L013ejend
+.L014ej3:
+ movb 2(%esi), %ch
+ sall $8, %ecx
+.L015ej2:
+ movb 1(%esi), %ch
+.L016ej1:
+ movb (%esi), %cl
+.L013ejend:
+ xorl %ecx, %eax
+ xorl %edx, %ebx
+ movl %eax, 12(%esp)
+ movl %ebx, 16(%esp)
+ call des_encrypt
+ movl 12(%esp), %eax
+ movl 16(%esp), %ebx
+ movl %eax, (%edi)
+ movl %ebx, 4(%edi)
+ jmp .L007finish
+.align 16
+.L004decrypt:
+ andl $4294967288, %ebp
+ movl 20(%esp), %eax
+ movl 24(%esp), %ebx
+ jz .L017decrypt_finish
+.L018decrypt_loop:
+ movl (%esi), %eax
+ movl 4(%esi), %ebx
+ movl %eax, 12(%esp)
+ movl %ebx, 16(%esp)
+ call des_encrypt
+ movl 12(%esp), %eax
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx
+ movl 24(%esp), %edx
+ xorl %eax, %ecx
+ xorl %ebx, %edx
+ movl (%esi), %eax
+ movl 4(%esi), %ebx
+ movl %ecx, (%edi)
+ movl %edx, 4(%edi)
+ movl %eax, 20(%esp)
+ movl %ebx, 24(%esp)
+ addl $8, %esi
+ addl $8, %edi
+ subl $8, %ebp
+ jnz .L018decrypt_loop
+.L017decrypt_finish:
+ movl 56(%esp), %ebp
+ andl $7, %ebp
+ jz .L007finish
+ movl (%esi), %eax
+ movl 4(%esi), %ebx
+ movl %eax, 12(%esp)
+ movl %ebx, 16(%esp)
+ call des_encrypt
+ movl 12(%esp), %eax
+ movl 16(%esp), %ebx
+ movl 20(%esp), %ecx
+ movl 24(%esp), %edx
+ xorl %eax, %ecx
+ xorl %ebx, %edx
+ movl (%esi), %eax
+ movl 4(%esi), %ebx
+.L019dj7:
+ rorl $16, %edx
+ movb %dl, 6(%edi)
+ shrl $16, %edx
+.L020dj6:
+ movb %dh, 5(%edi)
+.L021dj5:
+ movb %dl, 4(%edi)
+.L022dj4:
+ movl %ecx, (%edi)
+ jmp .L023djend
+.L024dj3:
+ rorl $16, %ecx
+ movb %cl, 2(%edi)
+ sall $16, %ecx
+.L025dj2:
+ movb %ch, 1(%esi)
+.L026dj1:
+ movb %cl, (%esi)
+.L023djend:
+ jmp .L007finish
+.align 16
+.L007finish:
+ movl 64(%esp), %ecx
+ addl $28, %esp
+ movl %eax, (%ecx)
+ movl %ebx, 4(%ecx)
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+.align 16
+.L008cbc_enc_jmp_table:
+ .long 0
+ .long .L016ej1
+ .long .L015ej2
+ .long .L014ej3
+ .long .L012ej4
+ .long .L011ej5
+ .long .L010ej6
+ .long .L009ej7
+.align 16
+.L027cbc_dec_jmp_table:
+ .long 0
+ .long .L026dj1
+ .long .L025dj2
+ .long .L024dj3
+ .long .L022dj4
+ .long .L021dj5
+ .long .L020dj6
+ .long .L019dj7
+.des_ncbc_encrypt_end:
+ .size des_ncbc_encrypt , .des_ncbc_encrypt_end-des_ncbc_encrypt
+.ident "desasm.pl"
+.text
+ .align 16
+.globl des_ede3_cbc_encrypt
+ .type des_ede3_cbc_encrypt , @function
+des_ede3_cbc_encrypt:
+
+ pushl %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ movl 28(%esp), %ebp
+
+ movl 44(%esp), %ebx
+ movl (%ebx), %esi
+ movl 4(%ebx), %edi
+ pushl %edi
+ pushl %esi
+ pushl %edi
+ pushl %esi
+ movl %esp, %ebx
+ movl 36(%esp), %esi
+ movl 40(%esp), %edi
+
+ movl 64(%esp), %ecx
+
+ movl 56(%esp), %eax
+ pushl %eax
+
+ movl 56(%esp), %eax
+ pushl %eax
+
+ movl 56(%esp), %eax
+ pushl %eax
+ pushl %ebx
+ cmpl $0, %ecx
+ jz .L028decrypt
+ andl $4294967288, %ebp
+ movl 16(%esp), %eax
+ movl 20(%esp), %ebx
+ jz .L029encrypt_finish
+.L030encrypt_loop:
+ movl (%esi), %ecx
+ movl 4(%esi), %edx
+ xorl %ecx, %eax
+ xorl %edx, %ebx
+ movl %eax, 16(%esp)
+ movl %ebx, 20(%esp)
+ call des_encrypt3
+ movl 16(%esp), %eax
+ movl 20(%esp), %ebx
+ movl %eax, (%edi)
+ movl %ebx, 4(%edi)
+ addl $8, %esi
+ addl $8, %edi
+ subl $8, %ebp
+ jnz .L030encrypt_loop
+.L029encrypt_finish:
+ movl 60(%esp), %ebp
+ andl $7, %ebp
+ jz .L031finish
+ xorl %ecx, %ecx
+ xorl %edx, %edx
+ movl .L032cbc_enc_jmp_table(,%ebp,4),%ebp
+ jmp *%ebp
+.L033ej7:
+ movb 6(%esi), %dh
+ sall $8, %edx
+.L034ej6:
+ movb 5(%esi), %dh
+.L035ej5:
+ movb 4(%esi), %dl
+.L036ej4:
+ movl (%esi), %ecx
+ jmp .L037ejend
+.L038ej3:
+ movb 2(%esi), %ch
+ sall $8, %ecx
+.L039ej2:
+ movb 1(%esi), %ch
+.L040ej1:
+ movb (%esi), %cl
+.L037ejend:
+ xorl %ecx, %eax
+ xorl %edx, %ebx
+ movl %eax, 16(%esp)
+ movl %ebx, 20(%esp)
+ call des_encrypt3
+ movl 16(%esp), %eax
+ movl 20(%esp), %ebx
+ movl %eax, (%edi)
+ movl %ebx, 4(%edi)
+ jmp .L031finish
+.align 16
+.L028decrypt:
+ andl $4294967288, %ebp
+ movl 24(%esp), %eax
+ movl 28(%esp), %ebx
+ jz .L041decrypt_finish
+.L042decrypt_loop:
+ movl (%esi), %eax
+ movl 4(%esi), %ebx
+ movl %eax, 16(%esp)
+ movl %ebx, 20(%esp)
+ call des_decrypt3
+ movl 16(%esp), %eax
+ movl 20(%esp), %ebx
+ movl 24(%esp), %ecx
+ movl 28(%esp), %edx
+ xorl %eax, %ecx
+ xorl %ebx, %edx
+ movl (%esi), %eax
+ movl 4(%esi), %ebx
+ movl %ecx, (%edi)
+ movl %edx, 4(%edi)
+ movl %eax, 24(%esp)
+ movl %ebx, 28(%esp)
+ addl $8, %esi
+ addl $8, %edi
+ subl $8, %ebp
+ jnz .L042decrypt_loop
+.L041decrypt_finish:
+ movl 60(%esp), %ebp
+ andl $7, %ebp
+ jz .L031finish
+ movl (%esi), %eax
+ movl 4(%esi), %ebx
+ movl %eax, 16(%esp)
+ movl %ebx, 20(%esp)
+ call des_decrypt3
+ movl 16(%esp), %eax
+ movl 20(%esp), %ebx
+ movl 24(%esp), %ecx
+ movl 28(%esp), %edx
+ xorl %eax, %ecx
+ xorl %ebx, %edx
+ movl (%esi), %eax
+ movl 4(%esi), %ebx
+.L043dj7:
+ rorl $16, %edx
+ movb %dl, 6(%edi)
+ shrl $16, %edx
+.L044dj6:
+ movb %dh, 5(%edi)
+.L045dj5:
+ movb %dl, 4(%edi)
+.L046dj4:
+ movl %ecx, (%edi)
+ jmp .L047djend
+.L048dj3:
+ rorl $16, %ecx
+ movb %cl, 2(%edi)
+ sall $16, %ecx
+.L049dj2:
+ movb %ch, 1(%esi)
+.L050dj1:
+ movb %cl, (%esi)
+.L047djend:
+ jmp .L031finish
+.align 16
+.L031finish:
+ movl 76(%esp), %ecx
+ addl $32, %esp
+ movl %eax, (%ecx)
+ movl %ebx, 4(%ecx)
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+.align 16
+.L032cbc_enc_jmp_table:
+ .long 0
+ .long .L040ej1
+ .long .L039ej2
+ .long .L038ej3
+ .long .L036ej4
+ .long .L035ej5
+ .long .L034ej6
+ .long .L033ej7
+.align 16
+.L051cbc_dec_jmp_table:
+ .long 0
+ .long .L050dj1
+ .long .L049dj2
+ .long .L048dj3
+ .long .L046dj4
+ .long .L045dj5
+ .long .L044dj6
+ .long .L043dj7
+.des_ede3_cbc_encrypt_end:
+ .size des_ede3_cbc_encrypt , .des_ede3_cbc_encrypt_end-des_ede3_cbc_encrypt
+.ident "desasm.pl"
diff --git a/linux/crypto/ciphers/des/ecb_enc.c b/linux/crypto/ciphers/des/ecb_enc.c
new file mode 100644
index 000000000..0b7afcf3a
--- /dev/null
+++ b/linux/crypto/ciphers/des/ecb_enc.c
@@ -0,0 +1,128 @@
+/* crypto/des/ecb_enc.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "des_locl.h"
+#include "spr.h"
+
+char *libdes_version="libdes v 3.24 - 20-Apr-1996 - eay";
+char *DES_version="DES part of SSLeay 0.8.2b 08-Jan-1998";
+
+/* RCSID $Id: ecb_enc.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
+/* This function ifdef'ed out for FreeS/WAN project. */
+#ifdef notdef
+char *des_options()
+ {
+ static int init=1;
+ static char buf[32];
+
+ if (init)
+ {
+ char *ptr,*unroll,*risc,*size;
+
+ init=0;
+#ifdef DES_PTR
+ ptr="ptr";
+#else
+ ptr="idx";
+#endif
+#if defined(DES_RISC1) || defined(DES_RISC2)
+#ifdef DES_RISC1
+ risc="risc1";
+#endif
+#ifdef DES_RISC2
+ risc="risc2";
+#endif
+#else
+ risc="cisc";
+#endif
+#ifdef DES_UNROLL
+ unroll="16";
+#else
+ unroll="4";
+#endif
+ if (sizeof(DES_LONG) != sizeof(long))
+ size="int";
+ else
+ size="long";
+ sprintf(buf,"des(%s,%s,%s,%s)",ptr,risc,unroll,size);
+ }
+ return(buf);
+ }
+#endif
+
+
+void des_ecb_encrypt(input, output, ks, enc)
+des_cblock (*input);
+des_cblock (*output);
+des_key_schedule ks;
+int enc;
+ {
+ register DES_LONG l;
+ register unsigned char *in,*out;
+ DES_LONG ll[2];
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ c2l(in,l); ll[0]=l;
+ c2l(in,l); ll[1]=l;
+ des_encrypt(ll,ks,enc);
+ l=ll[0]; l2c(l,out);
+ l=ll[1]; l2c(l,out);
+ l=ll[0]=ll[1]=0;
+ }
+
diff --git a/linux/crypto/ciphers/des/fcrypt.c b/linux/crypto/ciphers/des/fcrypt.c
new file mode 100644
index 000000000..8b9d0495b
--- /dev/null
+++ b/linux/crypto/ciphers/des/fcrypt.c
@@ -0,0 +1,152 @@
+/* NOCW */
+
+/* This version of crypt has been developed from my MIT compatable
+ * DES library.
+ * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
+ * Eric Young (eay@cryptsoft.com)
+ */
+
+/* Modification by Jens Kupferschmidt (Cu)
+ * I have included directive PARA for shared memory computers.
+ * I have included a directive LONGCRYPT to using this routine to cipher
+ * passwords with more then 8 bytes like HP-UX 10.x it used. The MAXPLEN
+ * definition is the maximum of lenght of password and can changed. I have
+ * defined 24.
+ */
+
+#include "des_locl.h"
+
+/* Added more values to handle illegal salt values the way normal
+ * crypt() implementations do. The patch was sent by
+ * Bjorn Gronvall <bg@sics.se>
+ */
+static unsigned const char con_salt[128]={
+0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,
+0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,
+0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
+0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,
+0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
+0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x01,
+0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
+0x0A,0x0B,0x05,0x06,0x07,0x08,0x09,0x0A,
+0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,
+0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,
+0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,
+0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24,
+0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,
+0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,
+0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,
+0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,
+};
+
+static unsigned const char cov_2char[64]={
+0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
+0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,
+0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,
+0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,
+0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,
+0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
+0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,
+0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A
+};
+
+#ifndef NOPROTO
+void fcrypt_body(DES_LONG *out,des_key_schedule ks,
+ DES_LONG Eswap0, DES_LONG Eswap1);
+
+#ifdef PERL5
+char *des_crypt(const char *buf,const char *salt);
+#else
+char *crypt(const char *buf,const char *salt);
+#endif
+#else
+void fcrypt_body();
+#ifdef PERL5
+char *des_crypt();
+#else
+char *crypt();
+#endif
+#endif
+
+#ifdef PERL5
+char *des_crypt(buf,salt)
+#else
+char *crypt(buf,salt)
+#endif
+const char *buf;
+const char *salt;
+ {
+ static char buff[14];
+
+ return(des_fcrypt(buf,salt,buff));
+ }
+
+
+char *des_fcrypt(buf,salt,ret)
+const char *buf;
+const char *salt;
+char *ret;
+ {
+ unsigned int i,j,x,y;
+ DES_LONG Eswap0,Eswap1;
+ DES_LONG out[2],ll;
+ des_cblock key;
+ des_key_schedule ks;
+ unsigned char bb[9];
+ unsigned char *b=bb;
+ unsigned char c,u;
+
+ /* eay 25/08/92
+ * If you call crypt("pwd","*") as often happens when you
+ * have * as the pwd field in /etc/passwd, the function
+ * returns *\0XXXXXXXXX
+ * The \0 makes the string look like * so the pwd "*" would
+ * crypt to "*". This was found when replacing the crypt in
+ * our shared libraries. People found that the disbled
+ * accounts effectivly had no passwd :-(. */
+ x=ret[0]=((salt[0] == '\0')?'A':salt[0]);
+ Eswap0=con_salt[x]<<2;
+ x=ret[1]=((salt[1] == '\0')?'A':salt[1]);
+ Eswap1=con_salt[x]<<6;
+
+/* EAY
+r=strlen(buf);
+r=(r+7)/8;
+*/
+ for (i=0; i<8; i++)
+ {
+ c= *(buf++);
+ if (!c) break;
+ key[i]=(c<<1);
+ }
+ for (; i<8; i++)
+ key[i]=0;
+
+ des_set_key((des_cblock *)(key),ks);
+ fcrypt_body(&(out[0]),ks,Eswap0,Eswap1);
+
+ ll=out[0]; l2c(ll,b);
+ ll=out[1]; l2c(ll,b);
+ y=0;
+ u=0x80;
+ bb[8]=0;
+ for (i=2; i<13; i++)
+ {
+ c=0;
+ for (j=0; j<6; j++)
+ {
+ c<<=1;
+ if (bb[y] & u) c|=1;
+ u>>=1;
+ if (!u)
+ {
+ y++;
+ u=0x80;
+ }
+ }
+ ret[i]=cov_2char[c];
+ }
+ ret[13]='\0';
+ return(ret);
+ }
+
diff --git a/linux/crypto/ciphers/des/fcrypt_b.c b/linux/crypto/ciphers/des/fcrypt_b.c
new file mode 100644
index 000000000..5900645e7
--- /dev/null
+++ b/linux/crypto/ciphers/des/fcrypt_b.c
@@ -0,0 +1,148 @@
+/* crypto/des/fcrypt_b.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* #include <stdio.h> */
+
+/* This version of crypt has been developed from my MIT compatable
+ * DES library.
+ * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
+ * Eric Young (eay@cryptsoft.com)
+ */
+
+#define DES_FCRYPT
+#include "des_locl.h"
+#undef DES_FCRYPT
+
+#undef PERM_OP
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
+
+#undef HPERM_OP
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+ (a)=(a)^(t)^(t>>(16-(n))))\
+
+void fcrypt_body(out, ks, Eswap0, Eswap1)
+DES_LONG *out;
+des_key_schedule ks;
+DES_LONG Eswap0;
+DES_LONG Eswap1;
+ {
+ register DES_LONG l,r,t,u;
+#ifdef DES_PTR
+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
+#endif
+ register DES_LONG *s;
+ register int j;
+ register DES_LONG E0,E1;
+
+ l=0;
+ r=0;
+
+ s=(DES_LONG *)ks;
+ E0=Eswap0;
+ E1=Eswap1;
+
+ for (j=0; j<25; j++)
+ {
+#ifdef DES_UNROLL
+ register int i;
+
+ for (i=0; i<32; i+=8)
+ {
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ D_ENCRYPT(l,r,i+4); /* 1 */
+ D_ENCRYPT(r,l,i+6); /* 2 */
+ }
+#else
+ D_ENCRYPT(l,r, 0); /* 1 */
+ D_ENCRYPT(r,l, 2); /* 2 */
+ D_ENCRYPT(l,r, 4); /* 3 */
+ D_ENCRYPT(r,l, 6); /* 4 */
+ D_ENCRYPT(l,r, 8); /* 5 */
+ D_ENCRYPT(r,l,10); /* 6 */
+ D_ENCRYPT(l,r,12); /* 7 */
+ D_ENCRYPT(r,l,14); /* 8 */
+ D_ENCRYPT(l,r,16); /* 9 */
+ D_ENCRYPT(r,l,18); /* 10 */
+ D_ENCRYPT(l,r,20); /* 11 */
+ D_ENCRYPT(r,l,22); /* 12 */
+ D_ENCRYPT(l,r,24); /* 13 */
+ D_ENCRYPT(r,l,26); /* 14 */
+ D_ENCRYPT(l,r,28); /* 15 */
+ D_ENCRYPT(r,l,30); /* 16 */
+#endif
+
+ t=l;
+ l=r;
+ r=t;
+ }
+ l=ROTATE(l,3)&0xffffffffL;
+ r=ROTATE(r,3)&0xffffffffL;
+
+ PERM_OP(l,r,t, 1,0x55555555L);
+ PERM_OP(r,l,t, 8,0x00ff00ffL);
+ PERM_OP(l,r,t, 2,0x33333333L);
+ PERM_OP(r,l,t,16,0x0000ffffL);
+ PERM_OP(l,r,t, 4,0x0f0f0f0fL);
+
+ out[0]=r;
+ out[1]=l;
+ }
+
diff --git a/linux/crypto/ciphers/des/options.txt b/linux/crypto/ciphers/des/options.txt
new file mode 100644
index 000000000..6e2b50f76
--- /dev/null
+++ b/linux/crypto/ciphers/des/options.txt
@@ -0,0 +1,39 @@
+Note that the UNROLL option makes the 'inner' des loop unroll all 16 rounds
+instead of the default 4.
+RISC1 and RISC2 are 2 alternatives for the inner loop and
+PTR means to use pointers arithmatic instead of arrays.
+
+FreeBSD - Pentium Pro 200mhz - gcc 2.7.2.2 - assembler 577,000 4620k/s
+IRIX 6.2 - R10000 195mhz - cc (-O3 -n32) - UNROLL RISC2 PTR 496,000 3968k/s
+solaris 2.5.1 usparc 167mhz?? - SC4.0 - UNROLL RISC1 PTR [1] 459,400 3672k/s
+FreeBSD - Pentium Pro 200mhz - gcc 2.7.2.2 - UNROLL RISC1 433,000 3468k/s
+solaris 2.5.1 usparc 167mhz?? - gcc 2.7.2 - UNROLL 380,000 3041k/s
+linux - pentium 100mhz - gcc 2.7.0 - assembler 281,000 2250k/s
+NT 4.0 - pentium 100mhz - VC 4.2 - assembler 281,000 2250k/s
+AIX 4.1? - PPC604 100mhz - cc - UNROLL 275,000 2200k/s
+IRIX 5.3 - R4400 200mhz - gcc 2.6.3 - UNROLL RISC2 PTR 235,300 1882k/s
+IRIX 5.3 - R4400 200mhz - cc - UNROLL RISC2 PTR 233,700 1869k/s
+NT 4.0 - pentium 100mhz - VC 4.2 - UNROLL RISC1 PTR 191,000 1528k/s
+DEC Alpha 165mhz?? - cc - RISC2 PTR [2] 181,000 1448k/s
+linux - pentium 100mhz - gcc 2.7.0 - UNROLL RISC1 PTR 158,500 1268k/s
+HPUX 10 - 9000/887 - cc - UNROLL [3] 148,000 1190k/s
+solaris 2.5.1 - sparc 10 50mhz - gcc 2.7.2 - UNROLL 123,600 989k/s
+IRIX 5.3 - R4000 100mhz - cc - UNROLL RISC2 PTR 101,000 808k/s
+DGUX - 88100 50mhz(?) - gcc 2.6.3 - UNROLL 81,000 648k/s
+solaris 2.4 486 50mhz - gcc 2.6.3 - assembler 65,000 522k/s
+HPUX 10 - 9000/887 - k&r cc (default compiler) - UNROLL PTR 76,000 608k/s
+solaris 2.4 486 50mhz - gcc 2.6.3 - UNROLL RISC2 43,500 344k/s
+AIX - old slow one :-) - cc - 39,000 312k/s
+
+Notes.
+[1] For the ultra sparc, SunC 4.0
+ cc -xtarget=ultra -xarch=v8plus -Xa -xO5, running 'des_opts'
+ gives a speed of 344,000 des/s while 'speed' gives 459,000 des/s.
+ I'll record the higher since it is coming from the library but it
+ is all rather weird.
+[2] Similar to the ultra sparc ([1]), 181,000 for 'des_opts' vs 175,000.
+[3] I was unable to get access to this machine when it was not heavily loaded.
+ As such, my timing program was never able to get more that %30 of the CPU.
+ This would cause the program to give much lower speed numbers because
+ it would be 'fighting' to stay in the cache with the other CPU burning
+ processes.
diff --git a/linux/crypto/ciphers/des/podd.h b/linux/crypto/ciphers/des/podd.h
new file mode 100644
index 000000000..c00cd6ba0
--- /dev/null
+++ b/linux/crypto/ciphers/des/podd.h
@@ -0,0 +1,75 @@
+/* crypto/des/podd.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+static const unsigned char odd_parity[256]={
+ 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
+ 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
+ 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
+ 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
+ 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
+ 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
+ 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
+112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
+128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
+145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
+161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
+176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
+193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
+208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
+224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
+241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254};
diff --git a/linux/crypto/ciphers/des/set_key.c b/linux/crypto/ciphers/des/set_key.c
new file mode 100644
index 000000000..99ac27348
--- /dev/null
+++ b/linux/crypto/ciphers/des/set_key.c
@@ -0,0 +1,246 @@
+/* crypto/des/set_key.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* set_key.c v 1.4 eay 24/9/91
+ * 1.4 Speed up by 400% :-)
+ * 1.3 added register declarations.
+ * 1.2 unrolled make_key_sched a bit more
+ * 1.1 added norm_expand_bits
+ * 1.0 First working version
+ */
+#include "des_locl.h"
+#include "podd.h"
+#include "sk.h"
+
+#ifndef NOPROTO
+static int check_parity(des_cblock (*key));
+#else
+static int check_parity();
+#endif
+
+int des_check_key=0;
+
+void des_set_odd_parity(key)
+des_cblock (*key);
+ {
+ int i;
+
+ for (i=0; i<DES_KEY_SZ; i++)
+ (*key)[i]=odd_parity[(*key)[i]];
+ }
+
+static int check_parity(key)
+des_cblock (*key);
+ {
+ int i;
+
+ for (i=0; i<DES_KEY_SZ; i++)
+ {
+ if ((*key)[i] != odd_parity[(*key)[i]])
+ return(0);
+ }
+ return(1);
+ }
+
+/* Weak and semi week keys as take from
+ * %A D.W. Davies
+ * %A W.L. Price
+ * %T Security for Computer Networks
+ * %I John Wiley & Sons
+ * %D 1984
+ * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference
+ * (and actual cblock values).
+ */
+#define NUM_WEAK_KEY 16
+static des_cblock weak_keys[NUM_WEAK_KEY]={
+ /* weak keys */
+ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
+ {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE},
+ {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
+ {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0},
+ /* semi-weak keys */
+ {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE},
+ {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01},
+ {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1},
+ {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E},
+ {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1},
+ {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01},
+ {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE},
+ {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E},
+ {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E},
+ {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01},
+ {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
+ {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}};
+
+int des_is_weak_key(key)
+des_cblock (*key);
+ {
+ int i;
+
+ for (i=0; i<NUM_WEAK_KEY; i++)
+ /* Added == 0 to comparision, I obviously don't run
+ * this section very often :-(, thanks to
+ * engineering@MorningStar.Com for the fix
+ * eay 93/06/29
+ * Another problem, I was comparing only the first 4
+ * bytes, 97/03/18 */
+ if (memcmp(weak_keys[i],key,sizeof(des_cblock)) == 0) return(1);
+ return(0);
+ }
+
+/* NOW DEFINED IN des_local.h
+ * See ecb_encrypt.c for a pseudo description of these macros.
+ * #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ * (b)^=(t),\
+ * (a)=((a)^((t)<<(n))))
+ */
+
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+ (a)=(a)^(t)^(t>>(16-(n))))
+
+/* return 0 if key parity is odd (correct),
+ * return -1 if key parity error,
+ * return -2 if illegal weak key.
+ */
+int des_set_key(key, schedule)
+des_cblock (*key);
+des_key_schedule schedule;
+ {
+ static int shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
+ register DES_LONG c,d,t,s,t2;
+ register unsigned char *in;
+ register DES_LONG *k;
+ register int i;
+
+ if (des_check_key)
+ {
+ if (!check_parity(key))
+ return(-1);
+
+ if (des_is_weak_key(key))
+ return(-2);
+ }
+
+ k=(DES_LONG *)schedule;
+ in=(unsigned char *)key;
+
+ c2l(in,c);
+ c2l(in,d);
+
+ /* do PC1 in 60 simple operations */
+/* PERM_OP(d,c,t,4,0x0f0f0f0fL);
+ HPERM_OP(c,t,-2, 0xcccc0000L);
+ HPERM_OP(c,t,-1, 0xaaaa0000L);
+ HPERM_OP(c,t, 8, 0x00ff0000L);
+ HPERM_OP(c,t,-1, 0xaaaa0000L);
+ HPERM_OP(d,t,-8, 0xff000000L);
+ HPERM_OP(d,t, 8, 0x00ff0000L);
+ HPERM_OP(d,t, 2, 0x33330000L);
+ d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L);
+ d=(d>>8)|((c&0xf0000000L)>>4);
+ c&=0x0fffffffL; */
+
+ /* I now do it in 47 simple operations :-)
+ * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
+ * for the inspiration. :-) */
+ PERM_OP (d,c,t,4,0x0f0f0f0fL);
+ HPERM_OP(c,t,-2,0xcccc0000L);
+ HPERM_OP(d,t,-2,0xcccc0000L);
+ PERM_OP (d,c,t,1,0x55555555L);
+ PERM_OP (c,d,t,8,0x00ff00ffL);
+ PERM_OP (d,c,t,1,0x55555555L);
+ d= (((d&0x000000ffL)<<16L)| (d&0x0000ff00L) |
+ ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L));
+ c&=0x0fffffffL;
+
+ for (i=0; i<ITERATIONS; i++)
+ {
+ if (shifts2[i])
+ { c=((c>>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); }
+ else
+ { c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); }
+ c&=0x0fffffffL;
+ d&=0x0fffffffL;
+ /* could be a few less shifts but I am to lazy at this
+ * point in time to investigate */
+ s= des_skb[0][ (c )&0x3f ]|
+ des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]|
+ des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]|
+ des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) |
+ ((c>>22L)&0x38)];
+ t= des_skb[4][ (d )&0x3f ]|
+ des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]|
+ des_skb[6][ (d>>15L)&0x3f ]|
+ des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)];
+
+ /* table contained 0213 4657 */
+ t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL;
+ *(k++)=ROTATE(t2,30)&0xffffffffL;
+
+ t2=((s>>16L)|(t&0xffff0000L));
+ *(k++)=ROTATE(t2,26)&0xffffffffL;
+ }
+ return(0);
+ }
+
+int des_key_sched(key, schedule)
+des_cblock (*key);
+des_key_schedule schedule;
+ {
+ return(des_set_key(key,schedule));
+ }
diff --git a/linux/crypto/ciphers/des/sk.h b/linux/crypto/ciphers/des/sk.h
new file mode 100644
index 000000000..240703070
--- /dev/null
+++ b/linux/crypto/ciphers/des/sk.h
@@ -0,0 +1,204 @@
+/* crypto/des/sk.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+static const DES_LONG des_skb[8][64]={
+{
+/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+0x00000000L,0x00000010L,0x20000000L,0x20000010L,
+0x00010000L,0x00010010L,0x20010000L,0x20010010L,
+0x00000800L,0x00000810L,0x20000800L,0x20000810L,
+0x00010800L,0x00010810L,0x20010800L,0x20010810L,
+0x00000020L,0x00000030L,0x20000020L,0x20000030L,
+0x00010020L,0x00010030L,0x20010020L,0x20010030L,
+0x00000820L,0x00000830L,0x20000820L,0x20000830L,
+0x00010820L,0x00010830L,0x20010820L,0x20010830L,
+0x00080000L,0x00080010L,0x20080000L,0x20080010L,
+0x00090000L,0x00090010L,0x20090000L,0x20090010L,
+0x00080800L,0x00080810L,0x20080800L,0x20080810L,
+0x00090800L,0x00090810L,0x20090800L,0x20090810L,
+0x00080020L,0x00080030L,0x20080020L,0x20080030L,
+0x00090020L,0x00090030L,0x20090020L,0x20090030L,
+0x00080820L,0x00080830L,0x20080820L,0x20080830L,
+0x00090820L,0x00090830L,0x20090820L,0x20090830L,
+},{
+/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
+0x00000000L,0x02000000L,0x00002000L,0x02002000L,
+0x00200000L,0x02200000L,0x00202000L,0x02202000L,
+0x00000004L,0x02000004L,0x00002004L,0x02002004L,
+0x00200004L,0x02200004L,0x00202004L,0x02202004L,
+0x00000400L,0x02000400L,0x00002400L,0x02002400L,
+0x00200400L,0x02200400L,0x00202400L,0x02202400L,
+0x00000404L,0x02000404L,0x00002404L,0x02002404L,
+0x00200404L,0x02200404L,0x00202404L,0x02202404L,
+0x10000000L,0x12000000L,0x10002000L,0x12002000L,
+0x10200000L,0x12200000L,0x10202000L,0x12202000L,
+0x10000004L,0x12000004L,0x10002004L,0x12002004L,
+0x10200004L,0x12200004L,0x10202004L,0x12202004L,
+0x10000400L,0x12000400L,0x10002400L,0x12002400L,
+0x10200400L,0x12200400L,0x10202400L,0x12202400L,
+0x10000404L,0x12000404L,0x10002404L,0x12002404L,
+0x10200404L,0x12200404L,0x10202404L,0x12202404L,
+},{
+/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
+0x00000000L,0x00000001L,0x00040000L,0x00040001L,
+0x01000000L,0x01000001L,0x01040000L,0x01040001L,
+0x00000002L,0x00000003L,0x00040002L,0x00040003L,
+0x01000002L,0x01000003L,0x01040002L,0x01040003L,
+0x00000200L,0x00000201L,0x00040200L,0x00040201L,
+0x01000200L,0x01000201L,0x01040200L,0x01040201L,
+0x00000202L,0x00000203L,0x00040202L,0x00040203L,
+0x01000202L,0x01000203L,0x01040202L,0x01040203L,
+0x08000000L,0x08000001L,0x08040000L,0x08040001L,
+0x09000000L,0x09000001L,0x09040000L,0x09040001L,
+0x08000002L,0x08000003L,0x08040002L,0x08040003L,
+0x09000002L,0x09000003L,0x09040002L,0x09040003L,
+0x08000200L,0x08000201L,0x08040200L,0x08040201L,
+0x09000200L,0x09000201L,0x09040200L,0x09040201L,
+0x08000202L,0x08000203L,0x08040202L,0x08040203L,
+0x09000202L,0x09000203L,0x09040202L,0x09040203L,
+},{
+/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
+0x00000000L,0x00100000L,0x00000100L,0x00100100L,
+0x00000008L,0x00100008L,0x00000108L,0x00100108L,
+0x00001000L,0x00101000L,0x00001100L,0x00101100L,
+0x00001008L,0x00101008L,0x00001108L,0x00101108L,
+0x04000000L,0x04100000L,0x04000100L,0x04100100L,
+0x04000008L,0x04100008L,0x04000108L,0x04100108L,
+0x04001000L,0x04101000L,0x04001100L,0x04101100L,
+0x04001008L,0x04101008L,0x04001108L,0x04101108L,
+0x00020000L,0x00120000L,0x00020100L,0x00120100L,
+0x00020008L,0x00120008L,0x00020108L,0x00120108L,
+0x00021000L,0x00121000L,0x00021100L,0x00121100L,
+0x00021008L,0x00121008L,0x00021108L,0x00121108L,
+0x04020000L,0x04120000L,0x04020100L,0x04120100L,
+0x04020008L,0x04120008L,0x04020108L,0x04120108L,
+0x04021000L,0x04121000L,0x04021100L,0x04121100L,
+0x04021008L,0x04121008L,0x04021108L,0x04121108L,
+},{
+/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+0x00000000L,0x10000000L,0x00010000L,0x10010000L,
+0x00000004L,0x10000004L,0x00010004L,0x10010004L,
+0x20000000L,0x30000000L,0x20010000L,0x30010000L,
+0x20000004L,0x30000004L,0x20010004L,0x30010004L,
+0x00100000L,0x10100000L,0x00110000L,0x10110000L,
+0x00100004L,0x10100004L,0x00110004L,0x10110004L,
+0x20100000L,0x30100000L,0x20110000L,0x30110000L,
+0x20100004L,0x30100004L,0x20110004L,0x30110004L,
+0x00001000L,0x10001000L,0x00011000L,0x10011000L,
+0x00001004L,0x10001004L,0x00011004L,0x10011004L,
+0x20001000L,0x30001000L,0x20011000L,0x30011000L,
+0x20001004L,0x30001004L,0x20011004L,0x30011004L,
+0x00101000L,0x10101000L,0x00111000L,0x10111000L,
+0x00101004L,0x10101004L,0x00111004L,0x10111004L,
+0x20101000L,0x30101000L,0x20111000L,0x30111000L,
+0x20101004L,0x30101004L,0x20111004L,0x30111004L,
+},{
+/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
+0x00000000L,0x08000000L,0x00000008L,0x08000008L,
+0x00000400L,0x08000400L,0x00000408L,0x08000408L,
+0x00020000L,0x08020000L,0x00020008L,0x08020008L,
+0x00020400L,0x08020400L,0x00020408L,0x08020408L,
+0x00000001L,0x08000001L,0x00000009L,0x08000009L,
+0x00000401L,0x08000401L,0x00000409L,0x08000409L,
+0x00020001L,0x08020001L,0x00020009L,0x08020009L,
+0x00020401L,0x08020401L,0x00020409L,0x08020409L,
+0x02000000L,0x0A000000L,0x02000008L,0x0A000008L,
+0x02000400L,0x0A000400L,0x02000408L,0x0A000408L,
+0x02020000L,0x0A020000L,0x02020008L,0x0A020008L,
+0x02020400L,0x0A020400L,0x02020408L,0x0A020408L,
+0x02000001L,0x0A000001L,0x02000009L,0x0A000009L,
+0x02000401L,0x0A000401L,0x02000409L,0x0A000409L,
+0x02020001L,0x0A020001L,0x02020009L,0x0A020009L,
+0x02020401L,0x0A020401L,0x02020409L,0x0A020409L,
+},{
+/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
+0x00000000L,0x00000100L,0x00080000L,0x00080100L,
+0x01000000L,0x01000100L,0x01080000L,0x01080100L,
+0x00000010L,0x00000110L,0x00080010L,0x00080110L,
+0x01000010L,0x01000110L,0x01080010L,0x01080110L,
+0x00200000L,0x00200100L,0x00280000L,0x00280100L,
+0x01200000L,0x01200100L,0x01280000L,0x01280100L,
+0x00200010L,0x00200110L,0x00280010L,0x00280110L,
+0x01200010L,0x01200110L,0x01280010L,0x01280110L,
+0x00000200L,0x00000300L,0x00080200L,0x00080300L,
+0x01000200L,0x01000300L,0x01080200L,0x01080300L,
+0x00000210L,0x00000310L,0x00080210L,0x00080310L,
+0x01000210L,0x01000310L,0x01080210L,0x01080310L,
+0x00200200L,0x00200300L,0x00280200L,0x00280300L,
+0x01200200L,0x01200300L,0x01280200L,0x01280300L,
+0x00200210L,0x00200310L,0x00280210L,0x00280310L,
+0x01200210L,0x01200310L,0x01280210L,0x01280310L,
+},{
+/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
+0x00000000L,0x04000000L,0x00040000L,0x04040000L,
+0x00000002L,0x04000002L,0x00040002L,0x04040002L,
+0x00002000L,0x04002000L,0x00042000L,0x04042000L,
+0x00002002L,0x04002002L,0x00042002L,0x04042002L,
+0x00000020L,0x04000020L,0x00040020L,0x04040020L,
+0x00000022L,0x04000022L,0x00040022L,0x04040022L,
+0x00002020L,0x04002020L,0x00042020L,0x04042020L,
+0x00002022L,0x04002022L,0x00042022L,0x04042022L,
+0x00000800L,0x04000800L,0x00040800L,0x04040800L,
+0x00000802L,0x04000802L,0x00040802L,0x04040802L,
+0x00002800L,0x04002800L,0x00042800L,0x04042800L,
+0x00002802L,0x04002802L,0x00042802L,0x04042802L,
+0x00000820L,0x04000820L,0x00040820L,0x04040820L,
+0x00000822L,0x04000822L,0x00040822L,0x04040822L,
+0x00002820L,0x04002820L,0x00042820L,0x04042820L,
+0x00002822L,0x04002822L,0x00042822L,0x04042822L,
+}};
diff --git a/linux/crypto/ciphers/des/speed.c b/linux/crypto/ciphers/des/speed.c
new file mode 100644
index 000000000..e3d753b2e
--- /dev/null
+++ b/linux/crypto/ciphers/des/speed.c
@@ -0,0 +1,329 @@
+/* crypto/des/speed.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* 11-Sep-92 Andrew Daviel Support for Silicon Graphics IRIX added */
+/* 06-Apr-92 Luke Brennan Support for VMS and add extra signal calls */
+
+#ifndef MSDOS
+#define TIMES
+#endif
+
+#include <stdio.h>
+#ifndef MSDOS
+#include <unistd.h>
+#else
+#include <io.h>
+extern int exit();
+#endif
+#include <signal.h>
+#ifndef VMS
+#ifndef _IRIX
+#include <time.h>
+#endif
+#ifdef TIMES
+#include <sys/types.h>
+#include <sys/times.h>
+#endif
+#else /* VMS */
+#include <types.h>
+struct tms {
+ time_t tms_utime;
+ time_t tms_stime;
+ time_t tms_uchild; /* I dunno... */
+ time_t tms_uchildsys; /* so these names are a guess :-) */
+ }
+#endif
+#ifndef TIMES
+#include <sys/timeb.h>
+#endif
+
+#ifdef sun
+#include <limits.h>
+#include <sys/param.h>
+#endif
+
+#include "des_locl.h"
+
+/* The following if from times(3) man page. It may need to be changed */
+#ifndef HZ
+# ifndef CLK_TCK
+# ifndef _BSD_CLK_TCK_ /* FreeBSD fix */
+# ifndef VMS
+# define HZ 100.0
+# else /* VMS */
+# define HZ 100.0
+# endif
+# else /* _BSD_CLK_TCK_ */
+# define HZ ((double)_BSD_CLK_TCK_)
+# endif
+# else /* CLK_TCK */
+# define HZ ((double)CLK_TCK)
+# endif
+#endif
+
+#define BUFSIZE ((long)1024)
+long run=0;
+
+#ifndef NOPROTO
+double Time_F(int s);
+#else
+double Time_F();
+#endif
+
+#ifdef SIGALRM
+#if defined(__STDC__) || defined(sgi) || defined(_AIX)
+#define SIGRETTYPE void
+#else
+#define SIGRETTYPE int
+#endif
+
+#ifndef NOPROTO
+SIGRETTYPE sig_done(int sig);
+#else
+SIGRETTYPE sig_done();
+#endif
+
+SIGRETTYPE sig_done(sig)
+int sig;
+ {
+ signal(SIGALRM,sig_done);
+ run=0;
+#ifdef LINT
+ sig=sig;
+#endif
+ }
+#endif
+
+#define START 0
+#define STOP 1
+
+double Time_F(s)
+int s;
+ {
+ double ret;
+#ifdef TIMES
+ static struct tms tstart,tend;
+
+ if (s == START)
+ {
+ times(&tstart);
+ return(0);
+ }
+ else
+ {
+ times(&tend);
+ ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ;
+ return((ret == 0.0)?1e-6:ret);
+ }
+#else /* !times() */
+ static struct timeb tstart,tend;
+ long i;
+
+ if (s == START)
+ {
+ ftime(&tstart);
+ return(0);
+ }
+ else
+ {
+ ftime(&tend);
+ i=(long)tend.millitm-(long)tstart.millitm;
+ ret=((double)(tend.time-tstart.time))+((double)i)/1e3;
+ return((ret == 0.0)?1e-6:ret);
+ }
+#endif
+ }
+
+int main(argc,argv)
+int argc;
+char **argv;
+ {
+ long count;
+ static unsigned char buf[BUFSIZE];
+ static des_cblock key ={0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
+ static des_cblock key2={0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
+ static des_cblock key3={0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
+ des_key_schedule sch,sch2,sch3;
+ double a,b,c,d,e;
+#ifndef SIGALRM
+ long ca,cb,cc,cd,ce;
+#endif
+
+#ifndef TIMES
+ printf("To get the most acurate results, try to run this\n");
+ printf("program when this computer is idle.\n");
+#endif
+
+ des_set_key((C_Block *)key2,sch2);
+ des_set_key((C_Block *)key3,sch3);
+
+#ifndef SIGALRM
+ printf("First we calculate the approximate speed ...\n");
+ des_set_key((C_Block *)key,sch);
+ count=10;
+ do {
+ long i;
+ DES_LONG data[2];
+
+ count*=2;
+ Time_F(START);
+ for (i=count; i; i--)
+ des_encrypt(data,&(sch[0]),DES_ENCRYPT);
+ d=Time_F(STOP);
+ } while (d < 3.0);
+ ca=count;
+ cb=count*3;
+ cc=count*3*8/BUFSIZE+1;
+ cd=count*8/BUFSIZE+1;
+ ce=count/20+1;
+ printf("Doing set_key %ld times\n",ca);
+#define COND(d) (count != (d))
+#define COUNT(d) (d)
+#else
+#define COND(c) (run)
+#define COUNT(d) (count)
+ signal(SIGALRM,sig_done);
+ printf("Doing set_key for 10 seconds\n");
+ alarm(10);
+#endif
+
+ Time_F(START);
+ for (count=0,run=1; COND(ca); count++)
+ des_set_key((C_Block *)key,sch);
+ d=Time_F(STOP);
+ printf("%ld set_key's in %.2f seconds\n",count,d);
+ a=((double)COUNT(ca))/d;
+
+#ifdef SIGALRM
+ printf("Doing des_encrypt's for 10 seconds\n");
+ alarm(10);
+#else
+ printf("Doing des_encrypt %ld times\n",cb);
+#endif
+ Time_F(START);
+ for (count=0,run=1; COND(cb); count++)
+ {
+ DES_LONG data[2];
+
+ des_encrypt(data,&(sch[0]),DES_ENCRYPT);
+ }
+ d=Time_F(STOP);
+ printf("%ld des_encrypt's in %.2f second\n",count,d);
+ b=((double)COUNT(cb)*8)/d;
+
+#ifdef SIGALRM
+ printf("Doing des_cbc_encrypt on %ld byte blocks for 10 seconds\n",
+ BUFSIZE);
+ alarm(10);
+#else
+ printf("Doing des_cbc_encrypt %ld times on %ld byte blocks\n",cc,
+ BUFSIZE);
+#endif
+ Time_F(START);
+ for (count=0,run=1; COND(cc); count++)
+ des_ncbc_encrypt((C_Block *)buf,(C_Block *)buf,BUFSIZE,&(sch[0]),
+ (C_Block *)&(key[0]),DES_ENCRYPT);
+ d=Time_F(STOP);
+ printf("%ld des_cbc_encrypt's of %ld byte blocks in %.2f second\n",
+ count,BUFSIZE,d);
+ c=((double)COUNT(cc)*BUFSIZE)/d;
+
+#ifdef SIGALRM
+ printf("Doing des_ede_cbc_encrypt on %ld byte blocks for 10 seconds\n",
+ BUFSIZE);
+ alarm(10);
+#else
+ printf("Doing des_ede_cbc_encrypt %ld times on %ld byte blocks\n",cd,
+ BUFSIZE);
+#endif
+ Time_F(START);
+ for (count=0,run=1; COND(cd); count++)
+ des_ede3_cbc_encrypt((C_Block *)buf,(C_Block *)buf,BUFSIZE,
+ &(sch[0]),
+ &(sch2[0]),
+ &(sch3[0]),
+ (C_Block *)&(key[0]),
+ DES_ENCRYPT);
+ d=Time_F(STOP);
+ printf("%ld des_ede_cbc_encrypt's of %ld byte blocks in %.2f second\n",
+ count,BUFSIZE,d);
+ d=((double)COUNT(cd)*BUFSIZE)/d;
+
+#ifdef SIGALRM
+ printf("Doing crypt for 10 seconds\n");
+ alarm(10);
+#else
+ printf("Doing crypt %ld times\n",ce);
+#endif
+ Time_F(START);
+ for (count=0,run=1; COND(ce); count++)
+ crypt("testing1","ef");
+ e=Time_F(STOP);
+ printf("%ld crypts in %.2f second\n",count,e);
+ e=((double)COUNT(ce))/e;
+
+ printf("set_key per sec = %12.2f (%9.3fuS)\n",a,1.0e6/a);
+ printf("DES raw ecb bytes per sec = %12.2f (%9.3fuS)\n",b,8.0e6/b);
+ printf("DES cbc bytes per sec = %12.2f (%9.3fuS)\n",c,8.0e6/c);
+ printf("DES ede cbc bytes per sec = %12.2f (%9.3fuS)\n",d,8.0e6/d);
+ printf("crypt per sec = %12.2f (%9.3fuS)\n",e,1.0e6/e);
+ exit(0);
+#if defined(LINT) || defined(MSDOS)
+ return(0);
+#endif
+ }
diff --git a/linux/crypto/ciphers/des/spr.h b/linux/crypto/ciphers/des/spr.h
new file mode 100644
index 000000000..a84d6a723
--- /dev/null
+++ b/linux/crypto/ciphers/des/spr.h
@@ -0,0 +1,204 @@
+/* crypto/des/spr.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+const DES_LONG des_SPtrans[8][64]={
+{
+/* nibble 0 */
+0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L,
+0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L,
+0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L,
+0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L,
+0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L,
+0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L,
+0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L,
+0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L,
+0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L,
+0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L,
+0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L,
+0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L,
+0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L,
+0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L,
+0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L,
+0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L,
+},{
+/* nibble 1 */
+0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L,
+0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L,
+0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L,
+0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L,
+0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L,
+0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L,
+0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L,
+0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L,
+0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L,
+0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L,
+0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L,
+0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L,
+0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L,
+0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L,
+0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L,
+0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L,
+},{
+/* nibble 2 */
+0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L,
+0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L,
+0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L,
+0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L,
+0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L,
+0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L,
+0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L,
+0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L,
+0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L,
+0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L,
+0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L,
+0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L,
+0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L,
+0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L,
+0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L,
+0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L,
+},{
+/* nibble 3 */
+0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L,
+0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L,
+0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L,
+0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L,
+0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L,
+0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L,
+0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L,
+0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L,
+0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L,
+0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L,
+0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L,
+0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L,
+0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L,
+0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L,
+0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L,
+0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L,
+},{
+/* nibble 4 */
+0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L,
+0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L,
+0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L,
+0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L,
+0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L,
+0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L,
+0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L,
+0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L,
+0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L,
+0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L,
+0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L,
+0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L,
+0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L,
+0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L,
+0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L,
+0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L,
+},{
+/* nibble 5 */
+0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L,
+0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L,
+0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L,
+0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L,
+0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L,
+0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L,
+0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L,
+0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L,
+0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L,
+0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L,
+0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L,
+0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L,
+0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L,
+0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L,
+0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L,
+0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L,
+},{
+/* nibble 6 */
+0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L,
+0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L,
+0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L,
+0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L,
+0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L,
+0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L,
+0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L,
+0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L,
+0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L,
+0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L,
+0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L,
+0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L,
+0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L,
+0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L,
+0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L,
+0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L,
+},{
+/* nibble 7 */
+0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L,
+0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L,
+0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L,
+0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L,
+0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L,
+0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L,
+0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L,
+0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L,
+0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L,
+0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L,
+0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L,
+0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L,
+0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L,
+0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L,
+0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L,
+0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L,
+}};
diff --git a/linux/include/crypto/des.h b/linux/include/crypto/des.h
new file mode 100644
index 000000000..baddf8647
--- /dev/null
+++ b/linux/include/crypto/des.h
@@ -0,0 +1,308 @@
+/* crypto/des/des.org */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * Always modify des.org since des.h is automatically generated from
+ * it during SSLeay configuration.
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ */
+
+#ifndef HEADER_DES_H
+#define HEADER_DES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a
+ * %20 speed up (longs are 8 bytes, int's are 4). */
+/* Must be unsigned int on ia64/Itanium or DES breaks badly */
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+
+#ifndef DES_LONG
+#define DES_LONG u_int32_t
+#endif
+
+typedef unsigned char des_cblock[8];
+typedef struct des_ks_struct
+ {
+ union {
+ des_cblock _;
+ /* make sure things are correct size on machines with
+ * 8 byte longs */
+ DES_LONG pad[2];
+ } ks;
+#undef _
+#define _ ks._
+ } des_key_schedule[16];
+
+#define DES_KEY_SZ (sizeof(des_cblock))
+#define DES_SCHEDULE_SZ (sizeof(des_key_schedule))
+
+#define DES_ENCRYPT 1
+#define DES_DECRYPT 0
+
+#define DES_CBC_MODE 0
+#define DES_PCBC_MODE 1
+
+#define des_ecb2_encrypt(i,o,k1,k2,e) \
+ des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
+
+#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
+ des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
+
+#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
+ des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
+
+#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
+ des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
+
+#define C_Block des_cblock
+#define Key_schedule des_key_schedule
+#ifdef KERBEROS
+#define ENCRYPT DES_ENCRYPT
+#define DECRYPT DES_DECRYPT
+#endif
+#define KEY_SZ DES_KEY_SZ
+#define string_to_key des_string_to_key
+#define read_pw_string des_read_pw_string
+#define random_key des_random_key
+#define pcbc_encrypt des_pcbc_encrypt
+#define set_key des_set_key
+#define key_sched des_key_sched
+#define ecb_encrypt des_ecb_encrypt
+#define cbc_encrypt des_cbc_encrypt
+#define ncbc_encrypt des_ncbc_encrypt
+#define xcbc_encrypt des_xcbc_encrypt
+#define cbc_cksum des_cbc_cksum
+#define quad_cksum des_quad_cksum
+
+/* For compatibility with the MIT lib - eay 20/05/92 */
+typedef des_key_schedule bit_64;
+#define des_fixup_key_parity des_set_odd_parity
+#define des_check_key_parity check_parity
+
+extern int des_check_key; /* defaults to false */
+extern int des_rw_mode; /* defaults to DES_PCBC_MODE */
+
+/* The next line is used to disable full ANSI prototypes, if your
+ * compiler has problems with the prototypes, make sure this line always
+ * evaluates to true :-) */
+#if defined(MSDOS) || defined(__STDC__)
+#undef NOPROTO
+#endif
+#ifndef NOPROTO
+char *des_options(void);
+void des_ecb3_encrypt(des_cblock *input,des_cblock *output,
+ des_key_schedule ks1,des_key_schedule ks2,
+ des_key_schedule ks3, int enc);
+DES_LONG des_cbc_cksum(des_cblock *input,des_cblock *output,
+ long length,des_key_schedule schedule,des_cblock *ivec);
+void des_cbc_encrypt(des_cblock *input,des_cblock *output,long length,
+ des_key_schedule schedule,des_cblock *ivec,int enc);
+void des_ncbc_encrypt(des_cblock *input,des_cblock *output,long length,
+ des_key_schedule schedule,des_cblock *ivec,int enc);
+void des_xcbc_encrypt(des_cblock *input,des_cblock *output,long length,
+ des_key_schedule schedule,des_cblock *ivec,
+ des_cblock *inw,des_cblock *outw,int enc);
+void des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits,
+ long length,des_key_schedule schedule,des_cblock *ivec,int enc);
+void des_ecb_encrypt(des_cblock *input,des_cblock *output,
+ des_key_schedule ks,int enc);
+void des_encrypt(DES_LONG *data,des_key_schedule ks, int enc);
+void des_encrypt2(DES_LONG *data,des_key_schedule ks, int enc);
+void des_encrypt3(DES_LONG *data, des_key_schedule ks1,
+ des_key_schedule ks2, des_key_schedule ks3);
+void des_decrypt3(DES_LONG *data, des_key_schedule ks1,
+ des_key_schedule ks2, des_key_schedule ks3);
+void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output,
+ long length, des_key_schedule ks1, des_key_schedule ks2,
+ des_key_schedule ks3, des_cblock *ivec, int enc);
+void des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out,
+ long length, des_key_schedule ks1, des_key_schedule ks2,
+ des_key_schedule ks3, des_cblock *ivec, int *num, int enc);
+void des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out,
+ long length, des_key_schedule ks1, des_key_schedule ks2,
+ des_key_schedule ks3, des_cblock *ivec, int *num);
+
+void des_xwhite_in2out(des_cblock (*des_key), des_cblock (*in_white),
+ des_cblock (*out_white));
+
+int des_enc_read(int fd,char *buf,int len,des_key_schedule sched,
+ des_cblock *iv);
+int des_enc_write(int fd,char *buf,int len,des_key_schedule sched,
+ des_cblock *iv);
+char *des_fcrypt(const char *buf,const char *salt, char *ret);
+#ifdef PERL5
+char *des_crypt(const char *buf,const char *salt);
+#else
+/* some stupid compilers complain because I have declared char instead
+ * of const char */
+#ifndef __KERNEL__
+#ifdef HEADER_DES_LOCL_H
+char *crypt(const char *buf,const char *salt);
+#else /* HEADER_DES_LOCL_H */
+char *crypt(void);
+#endif /* HEADER_DES_LOCL_H */
+#endif /* __KERNEL__ */
+#endif /* PERL5 */
+void des_ofb_encrypt(unsigned char *in,unsigned char *out,
+ int numbits,long length,des_key_schedule schedule,des_cblock *ivec);
+void des_pcbc_encrypt(des_cblock *input,des_cblock *output,long length,
+ des_key_schedule schedule,des_cblock *ivec,int enc);
+DES_LONG des_quad_cksum(des_cblock *input,des_cblock *output,
+ long length,int out_count,des_cblock *seed);
+void des_random_seed(des_cblock key);
+void des_random_key(des_cblock ret);
+int des_read_password(des_cblock *key,char *prompt,int verify);
+int des_read_2passwords(des_cblock *key1,des_cblock *key2,
+ char *prompt,int verify);
+int des_read_pw_string(char *buf,int length,char *prompt,int verify);
+void des_set_odd_parity(des_cblock *key);
+int des_is_weak_key(des_cblock *key);
+int des_set_key(des_cblock *key,des_key_schedule schedule);
+int des_key_sched(des_cblock *key,des_key_schedule schedule);
+void des_string_to_key(char *str,des_cblock *key);
+void des_string_to_2keys(char *str,des_cblock *key1,des_cblock *key2);
+void des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length,
+ des_key_schedule schedule, des_cblock *ivec, int *num, int enc);
+void des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length,
+ des_key_schedule schedule, des_cblock *ivec, int *num);
+int des_read_pw(char *buf, char *buff, int size, char *prompt, int verify);
+
+/* Extra functions from Mark Murray <mark@grondar.za> */
+/* The following functions are not in the normal unix build or the
+ * SSLeay build. When using the SSLeay build, use RAND_seed()
+ * and RAND_bytes() instead. */
+int des_new_random_key(des_cblock *key);
+void des_init_random_number_generator(des_cblock *key);
+void des_set_random_generator_seed(des_cblock *key);
+void des_set_sequence_number(des_cblock new_sequence_number);
+void des_generate_random_block(des_cblock *block);
+
+#else
+
+char *des_options();
+void des_ecb3_encrypt();
+DES_LONG des_cbc_cksum();
+void des_cbc_encrypt();
+void des_ncbc_encrypt();
+void des_xcbc_encrypt();
+void des_cfb_encrypt();
+void des_ede3_cfb64_encrypt();
+void des_ede3_ofb64_encrypt();
+void des_ecb_encrypt();
+void des_encrypt();
+void des_encrypt2();
+void des_encrypt3();
+void des_decrypt3();
+void des_ede3_cbc_encrypt();
+int des_enc_read();
+int des_enc_write();
+char *des_fcrypt();
+#ifdef PERL5
+char *des_crypt();
+#else
+char *crypt();
+#endif
+void des_ofb_encrypt();
+void des_pcbc_encrypt();
+DES_LONG des_quad_cksum();
+void des_random_seed();
+void des_random_key();
+int des_read_password();
+int des_read_2passwords();
+int des_read_pw_string();
+void des_set_odd_parity();
+int des_is_weak_key();
+int des_set_key();
+int des_key_sched();
+void des_string_to_key();
+void des_string_to_2keys();
+void des_cfb64_encrypt();
+void des_ofb64_encrypt();
+int des_read_pw();
+void des_xwhite_in2out();
+
+/* Extra functions from Mark Murray <mark@grondar.za> */
+/* The following functions are not in the normal unix build or the
+ * SSLeay build. When using the SSLeay build, use RAND_seed()
+ * and RAND_bytes() instead. */
+#ifdef FreeBSD
+int des_new_random_key();
+void des_init_random_number_generator();
+void des_set_random_generator_seed();
+void des_set_sequence_number();
+void des_generate_random_block();
+#endif
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/linux/include/freeswan.h b/linux/include/freeswan.h
new file mode 100644
index 000000000..4ef948b0a
--- /dev/null
+++ b/linux/include/freeswan.h
@@ -0,0 +1,477 @@
+#ifndef _FREESWAN_H
+/*
+ * header file for FreeS/WAN library functions
+ * Copyright (C) 1998, 1999, 2000 Henry Spencer.
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: freeswan.h,v 1.2 2004/03/22 21:53:17 as Exp $
+ */
+#define _FREESWAN_H /* seen it, no need to see it again */
+
+
+
+/*
+ * We've just got to have some datatypes defined... And annoyingly, just
+ * where we get them depends on whether we're in userland or not.
+ */
+#ifdef __KERNEL__
+
+# include <linux/types.h>
+# include <linux/in.h>
+
+#else /* __KERNEL__ */
+
+# include <stdio.h>
+# include <netinet/in.h>
+
+# define uint8_t u_int8_t
+# define uint16_t u_int16_t
+# define uint32_t u_int32_t
+# define uint64_t u_int64_t
+
+# define DEBUG_NO_STATIC static
+
+#endif /* __KERNEL__ */
+
+#include <freeswan/ipsec_param.h>
+
+
+/*
+ * Grab the kernel version to see if we have NET_21, and therefore
+ * IPv6. Some of this is repeated from ipsec_kversions.h. Of course,
+ * we aren't really testing if the kernel has IPv6, but rather if the
+ * the include files do.
+ */
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#define NET_21
+#endif
+
+#ifndef IPPROTO_COMP
+# define IPPROTO_COMP 108
+#endif /* !IPPROTO_COMP */
+
+#ifndef IPPROTO_INT
+# define IPPROTO_INT 61
+#endif /* !IPPROTO_INT */
+
+#ifdef CONFIG_IPSEC_DEBUG
+# define DEBUG_NO_STATIC
+#else /* CONFIG_IPSEC_DEBUG */
+# define DEBUG_NO_STATIC static
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL /* KERNEL ifdef */
+#ifndef NAT_TRAVERSAL
+#define NAT_TRAVERSAL
+#endif
+#endif
+#ifdef NAT_TRAVERSAL
+#define ESPINUDP_WITH_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
+#define ESPINUDP_WITH_NON_ESP 2 /* draft-ietf-ipsec-nat-t-ike-02 */
+#endif
+
+/*
+ * Basic data types for the address-handling functions.
+ * ip_address and ip_subnet are supposed to be opaque types; do not
+ * use their definitions directly, they are subject to change!
+ */
+
+/* first, some quick fakes in case we're on an old system with no IPv6 */
+#ifndef s6_addr16
+struct in6_addr {
+ union
+ {
+ __u8 u6_addr8[16];
+ __u16 u6_addr16[8];
+ __u32 u6_addr32[4];
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+};
+struct sockaddr_in6 {
+ unsigned short int sin6_family; /* AF_INET6 */
+ __u16 sin6_port; /* Transport layer port # */
+ __u32 sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ __u32 sin6_scope_id; /* scope id (new in RFC2553) */
+};
+#endif /* !s6_addr16 */
+
+/* then the main types */
+typedef struct {
+ union {
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ } u;
+} ip_address;
+typedef struct {
+ ip_address addr;
+ int maskbits;
+} ip_subnet;
+
+/* and the SA ID stuff */
+#ifdef __KERNEL__
+typedef __u32 ipsec_spi_t;
+#else
+typedef u_int32_t ipsec_spi_t;
+#endif
+typedef struct { /* to identify an SA, we need: */
+ ip_address dst; /* A. destination host */
+ ipsec_spi_t spi; /* B. 32-bit SPI, assigned by dest. host */
+# define SPI_PASS 256 /* magic values... */
+# define SPI_DROP 257 /* ...for use... */
+# define SPI_REJECT 258 /* ...with SA_INT */
+# define SPI_HOLD 259
+# define SPI_TRAP 260
+# define SPI_TRAPSUBNET 261
+ int proto; /* C. protocol */
+# define SA_ESP 50 /* IPPROTO_ESP */
+# define SA_AH 51 /* IPPROTO_AH */
+# define SA_IPIP 4 /* IPPROTO_IPIP */
+# define SA_COMP 108 /* IPPROTO_COMP */
+# define SA_INT 61 /* IANA reserved for internal use */
+} ip_said;
+struct sa_id { /* old v4-only version */
+ struct in_addr dst;
+ ipsec_spi_t spi;
+ int proto;
+};
+
+/* misc */
+typedef const char *err_t; /* error message, or NULL for success */
+struct prng { /* pseudo-random-number-generator guts */
+ unsigned char sbox[256];
+ int i, j;
+ unsigned long count;
+};
+
+
+/*
+ * definitions for user space, taken from freeswan/ipsec_sa.h
+ */
+typedef uint32_t IPsecSAref_t;
+
+#define IPSEC_SA_REF_FIELD_WIDTH (8 * sizeof(IPsecSAref_t))
+
+#define IPsecSAref2NFmark(x) ((x) << (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
+#define NFmark2IPsecSAref(x) ((x) >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
+
+#define IPSEC_SAREF_NULL (~((IPsecSAref_t)0))
+
+/* GCC magic for use in function definitions! */
+#ifdef GCC_LINT
+# define PRINTF_LIKE(n) __attribute__ ((format(printf, n, n+1)))
+# define NEVER_RETURNS __attribute__ ((noreturn))
+# define UNUSED __attribute__ ((unused))
+# define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */
+#else
+# define PRINTF_LIKE(n) /* ignore */
+# define NEVER_RETURNS /* ignore */
+# define UNUSED /* ignore */
+# define BLANK_FORMAT ""
+#endif
+
+
+
+
+
+/*
+ * new IPv6-compatible functions
+ */
+
+/* text conversions */
+err_t ttoul(const char *src, size_t srclen, int format, unsigned long *dst);
+size_t ultot(unsigned long src, int format, char *buf, size_t buflen);
+#define ULTOT_BUF (22+1) /* holds 64 bits in octal */
+err_t ttoaddr(const char *src, size_t srclen, int af, ip_address *dst);
+err_t tnatoaddr(const char *src, size_t srclen, int af, ip_address *dst);
+size_t addrtot(const ip_address *src, int format, char *buf, size_t buflen);
+/* RFC 1886 old IPv6 reverse-lookup format is the bulkiest */
+#define ADDRTOT_BUF (32*2 + 3 + 1 + 3 + 1 + 1)
+err_t ttosubnet(const char *src, size_t srclen, int af, ip_subnet *dst);
+size_t subnettot(const ip_subnet *src, int format, char *buf, size_t buflen);
+#define SUBNETTOT_BUF (ADDRTOT_BUF + 1 + 3)
+err_t ttosa(const char *src, size_t srclen, ip_said *dst);
+size_t satot(const ip_said *src, int format, char *bufptr, size_t buflen);
+#define SATOT_BUF (5 + ULTOA_BUF + 1 + ADDRTOT_BUF)
+err_t ttodata(const char *src, size_t srclen, int base, char *buf,
+ size_t buflen, size_t *needed);
+err_t ttodatav(const char *src, size_t srclen, int base,
+ char *buf, size_t buflen, size_t *needed,
+ char *errp, size_t errlen, unsigned int flags);
+#define TTODATAV_BUF 40 /* ttodatav's largest non-literal message */
+#define TTODATAV_IGNORESPACE (1<<1) /* ignore spaces in base64 encodings*/
+#define TTODATAV_SPACECOUNTS 0 /* do not ignore spaces in base64 */
+
+size_t datatot(const char *src, size_t srclen, int format, char *buf,
+ size_t buflen);
+size_t keyblobtoid(const unsigned char *src, size_t srclen, char *dst,
+ size_t dstlen);
+size_t splitkeytoid(const unsigned char *e, size_t elen, const unsigned char *m,
+ size_t mlen, char *dst, size_t dstlen);
+#define KEYID_BUF 10 /* up to 9 text digits plus NUL */
+err_t ttoprotoport(char *src, size_t src_len, u_int8_t *proto, u_int16_t *port,
+ int *has_port_wildcard);
+
+/* initializations */
+void initsaid(const ip_address *addr, ipsec_spi_t spi, int proto, ip_said *dst);
+err_t loopbackaddr(int af, ip_address *dst);
+err_t unspecaddr(int af, ip_address *dst);
+err_t anyaddr(int af, ip_address *dst);
+err_t initaddr(const unsigned char *src, size_t srclen, int af, ip_address *dst);
+err_t initsubnet(const ip_address *addr, int maskbits, int clash, ip_subnet *dst);
+err_t addrtosubnet(const ip_address *addr, ip_subnet *dst);
+
+/* misc. conversions and related */
+err_t rangetosubnet(const ip_address *from, const ip_address *to, ip_subnet *dst);
+int addrtypeof(const ip_address *src);
+int subnettypeof(const ip_subnet *src);
+size_t addrlenof(const ip_address *src);
+size_t addrbytesptr(const ip_address *src, const unsigned char **dst);
+size_t addrbytesof(const ip_address *src, unsigned char *dst, size_t dstlen);
+int masktocount(const ip_address *src);
+void networkof(const ip_subnet *src, ip_address *dst);
+void maskof(const ip_subnet *src, ip_address *dst);
+
+/* tests */
+int sameaddr(const ip_address *a, const ip_address *b);
+int addrcmp(const ip_address *a, const ip_address *b);
+int samesubnet(const ip_subnet *a, const ip_subnet *b);
+int addrinsubnet(const ip_address *a, const ip_subnet *s);
+int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);
+int subnetishost(const ip_subnet *s);
+int samesaid(const ip_said *a, const ip_said *b);
+int sameaddrtype(const ip_address *a, const ip_address *b);
+int samesubnettype(const ip_subnet *a, const ip_subnet *b);
+int isanyaddr(const ip_address *src);
+int isunspecaddr(const ip_address *src);
+int isloopbackaddr(const ip_address *src);
+
+/* low-level grot */
+int portof(const ip_address *src);
+void setportof(int port, ip_address *dst);
+struct sockaddr *sockaddrof(ip_address *src);
+size_t sockaddrlenof(const ip_address *src);
+
+/* PRNG */
+void prng_init(struct prng *prng, const unsigned char *key, size_t keylen);
+void prng_bytes(struct prng *prng, unsigned char *dst, size_t dstlen);
+unsigned long prng_count(struct prng *prng);
+void prng_final(struct prng *prng);
+
+/* odds and ends */
+const char *ipsec_version_code(void);
+const char *ipsec_version_string(void);
+const char **ipsec_copyright_notice(void);
+
+const char *dns_string_rr(int rr, char *buf, int bufsize);
+const char *dns_string_datetime(time_t seconds,
+ char *buf,
+ int bufsize);
+
+
+/*
+ * old functions, to be deleted eventually
+ */
+
+/* unsigned long */
+const char * /* NULL for success, else string literal */
+atoul(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ int base, /* 0 means figure it out */
+ unsigned long *resultp
+);
+size_t /* space needed for full conversion */
+ultoa(
+ unsigned long n,
+ int base,
+ char *dst,
+ size_t dstlen
+);
+#define ULTOA_BUF 21 /* just large enough for largest result, */
+ /* assuming 64-bit unsigned long! */
+
+/* Internet addresses */
+const char * /* NULL for success, else string literal */
+atoaddr(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ struct in_addr *addr
+);
+size_t /* space needed for full conversion */
+addrtoa(
+ struct in_addr addr,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+#define ADDRTOA_BUF 16 /* just large enough for largest result */
+
+/* subnets */
+const char * /* NULL for success, else string literal */
+atosubnet(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ struct in_addr *addr,
+ struct in_addr *mask
+);
+size_t /* space needed for full conversion */
+subnettoa(
+ struct in_addr addr,
+ struct in_addr mask,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+#define SUBNETTOA_BUF 32 /* large enough for worst case result */
+
+/* ranges */
+const char * /* NULL for success, else string literal */
+atoasr(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ char *type, /* 'a', 's', 'r' */
+ struct in_addr *addrs /* two-element array */
+);
+size_t /* space needed for full conversion */
+rangetoa(
+ struct in_addr *addrs, /* two-element array */
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+#define RANGETOA_BUF 34 /* large enough for worst case result */
+
+/* data types for SA conversion functions */
+
+/* SAs */
+const char * /* NULL for success, else string literal */
+atosa(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ struct sa_id *sa
+);
+size_t /* space needed for full conversion */
+satoa(
+ struct sa_id sa,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+#define SATOA_BUF (3+ULTOA_BUF+ADDRTOA_BUF)
+
+/* generic data, e.g. keys */
+const char * /* NULL for success, else string literal */
+atobytes(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ char *dst,
+ size_t dstlen,
+ size_t *lenp /* NULL means don't bother telling me */
+);
+size_t /* 0 failure, else true size */
+bytestoa(
+ const char *src,
+ size_t srclen,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+
+/* old versions of generic-data functions; deprecated */
+size_t /* 0 failure, else true size */
+atodata(
+ const char *src,
+ size_t srclen, /* 0 means strlen(src) */
+ char *dst,
+ size_t dstlen
+);
+size_t /* 0 failure, else true size */
+datatoa(
+ const char *src,
+ size_t srclen,
+ int format, /* character; 0 means default */
+ char *dst,
+ size_t dstlen
+);
+
+/* part extraction and special addresses */
+struct in_addr
+subnetof(
+ struct in_addr addr,
+ struct in_addr mask
+);
+struct in_addr
+hostof(
+ struct in_addr addr,
+ struct in_addr mask
+);
+struct in_addr
+broadcastof(
+ struct in_addr addr,
+ struct in_addr mask
+);
+
+/* mask handling */
+int
+goodmask(
+ struct in_addr mask
+);
+int
+masktobits(
+ struct in_addr mask
+);
+struct in_addr
+bitstomask(
+ int n
+);
+
+
+
+/*
+ * general utilities
+ */
+
+#ifndef __KERNEL__
+/* option pickup from files (userland only because of use of FILE) */
+const char *optionsfrom(const char *filename, int *argcp, char ***argvp,
+ int optind, FILE *errorreport);
+#endif
+
+/*
+ * Debugging levels for pfkey_lib_debug
+ */
+#define PF_KEY_DEBUG_PARSE_NONE 0
+#define PF_KEY_DEBUG_PARSE_PROBLEM 1
+#define PF_KEY_DEBUG_PARSE_STRUCT 2
+#define PF_KEY_DEBUG_PARSE_FLOW 4
+#define PF_KEY_DEBUG_PARSE_MAX 7
+
+extern unsigned int pfkey_lib_debug; /* bits selecting what to report */
+
+/*
+ * pluto and lwdnsq need to know the maximum size of the commands to,
+ * and replies from lwdnsq.
+ */
+
+#define LWDNSQ_CMDBUF_LEN 1024
+#define LWDNSQ_RESULT_LEN_MAX 4096
+
+#endif /* _FREESWAN_H */
diff --git a/linux/include/freeswan/ipcomp.h b/linux/include/freeswan/ipcomp.h
new file mode 100644
index 000000000..ed8095517
--- /dev/null
+++ b/linux/include/freeswan/ipcomp.h
@@ -0,0 +1,61 @@
+/*
+ * IPCOMP zlib interface code.
+ * Copyright (C) 2000 Svenning Soerensen <svenning@post5.tele.dk>
+ * Copyright (C) 2000, 2001 Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
+ *
+ * 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: ipcomp.h,v 1.1 2004/03/15 20:35:25 as Exp $
+
+ */
+
+/* SSS */
+
+#ifndef _IPCOMP_H
+#define _IPCOMP_H
+
+/* Prefix all global deflate symbols with "ipcomp_" to avoid collisions with ppp_deflate & ext2comp */
+#ifndef IPCOMP_PREFIX
+#define IPCOMP_PREFIX
+#endif /* IPCOMP_PREFIX */
+
+#ifndef IPPROTO_COMP
+#define IPPROTO_COMP 108
+#endif /* IPPROTO_COMP */
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int sysctl_ipsec_debug_ipcomp;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+struct ipcomphdr { /* IPCOMP header */
+ __u8 ipcomp_nh; /* Next header (protocol) */
+ __u8 ipcomp_flags; /* Reserved, must be 0 */
+ __u16 ipcomp_cpi; /* Compression Parameter Index */
+};
+
+extern struct inet_protocol comp_protocol;
+extern int sysctl_ipsec_debug_ipcomp;
+
+#define IPCOMP_UNCOMPRESSABLE 0x000000001
+#define IPCOMP_COMPRESSIONERROR 0x000000002
+#define IPCOMP_PARMERROR 0x000000004
+#define IPCOMP_DECOMPRESSIONERROR 0x000000008
+
+#define IPCOMP_ADAPT_INITIAL_TRIES 8
+#define IPCOMP_ADAPT_INITIAL_SKIP 4
+#define IPCOMP_ADAPT_SUBSEQ_TRIES 2
+#define IPCOMP_ADAPT_SUBSEQ_SKIP 8
+
+/* Function prototypes */
+struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
+struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
+
+#endif /* _IPCOMP_H */
diff --git a/linux/include/freeswan/ipsec_ah.h b/linux/include/freeswan/ipsec_ah.h
new file mode 100644
index 000000000..e088288d3
--- /dev/null
+++ b/linux/include/freeswan/ipsec_ah.h
@@ -0,0 +1,235 @@
+/*
+ * Authentication Header declarations
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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: ipsec_ah.h,v 1.2 2004/03/22 21:53:18 as Exp $
+ */
+
+#include "ipsec_md5h.h"
+#include "ipsec_sha1.h"
+
+#ifndef IPPROTO_AH
+#define IPPROTO_AH 51
+#endif /* IPPROTO_AH */
+
+#define AH_FLENGTH 12 /* size of fixed part */
+#define AHMD5_KMAX 64 /* MD5 max 512 bits key */
+#define AHMD5_AMAX 12 /* MD5 96 bits of authenticator */
+
+#define AHMD596_KLEN 16 /* MD5 128 bits key */
+#define AHSHA196_KLEN 20 /* SHA1 160 bits key */
+
+#define AHMD596_ALEN 16 /* MD5 128 bits authentication length */
+#define AHSHA196_ALEN 20 /* SHA1 160 bits authentication length */
+
+#define AHMD596_BLKLEN 64 /* MD5 block length */
+#define AHSHA196_BLKLEN 64 /* SHA1 block length */
+#define AHSHA2_256_BLKLEN 64 /* SHA2-256 block length */
+#define AHSHA2_384_BLKLEN 128 /* SHA2-384 block length (?) */
+#define AHSHA2_512_BLKLEN 128 /* SHA2-512 block length */
+
+#define AH_BLKLEN_MAX 128 /* keep up to date! */
+
+#define AH_AMAX AHSHA196_ALEN /* keep up to date! */
+#define AHHMAC_HASHLEN 12 /* authenticator length of 96bits */
+#define AHHMAC_RPLLEN 4 /* 32 bit replay counter */
+
+#define DB_AH_PKTRX 0x0001
+#define DB_AH_PKTRX2 0x0002
+#define DB_AH_DMP 0x0004
+#define DB_AH_IPSA 0x0010
+#define DB_AH_XF 0x0020
+#define DB_AH_INAU 0x0040
+#define DB_AH_REPLAY 0x0100
+
+#ifdef __KERNEL__
+
+/* General HMAC algorithm is described in RFC 2104 */
+
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5C
+
+struct md5_ctx {
+ MD5_CTX ictx; /* context after H(K XOR ipad) */
+ MD5_CTX octx; /* context after H(K XOR opad) */
+};
+
+struct sha1_ctx {
+ SHA1_CTX ictx; /* context after H(K XOR ipad) */
+ SHA1_CTX octx; /* context after H(K XOR opad) */
+};
+
+struct auth_alg {
+ void (*init)(void *ctx);
+ void (*update)(void *ctx, unsigned char *bytes, __u32 len);
+ void (*final)(unsigned char *hash, void *ctx);
+ int hashlen;
+};
+
+extern struct inet_protocol ah_protocol;
+
+struct options;
+
+extern int
+ah_rcv(struct sk_buff *skb,
+ struct device *dev,
+ struct options *opt,
+ __u32 daddr,
+ unsigned short len,
+ __u32 saddr,
+ int redo,
+ struct inet_protocol *protocol);
+
+struct ahhdr /* Generic AH header */
+{
+ __u8 ah_nh; /* Next header (protocol) */
+ __u8 ah_hl; /* AH length, in 32-bit words */
+ __u16 ah_rv; /* reserved, must be 0 */
+ __u32 ah_spi; /* Security Parameters Index */
+ __u32 ah_rpl; /* Replay prevention */
+ __u8 ah_data[AHHMAC_HASHLEN];/* Authentication hash */
+};
+#define AH_BASIC_LEN 8 /* basic AH header is 8 bytes, nh,hl,rv,spi
+ * and the ah_hl, says how many bytes after that
+ * to cover. */
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_ah;
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* __KERNEL__ */
+
+/*
+ * $Log: ipsec_ah.h,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.20 2003/02/06 02:21:34 rgb
+ *
+ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
+ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
+ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
+ *
+ * Revision 1.19 2002/09/16 21:19:13 mcr
+ * fixes for west-ah-icmp-01 - length of AH header must be
+ * calculated properly, and next_header field properly copied.
+ *
+ * Revision 1.18 2002/05/14 02:37:02 rgb
+ * Change reference from _TDB to _IPSA.
+ *
+ * Revision 1.17 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_ah.h,v
+ *
+ * Revision 1.16 2002/02/20 01:27:06 rgb
+ * Ditched a pile of structs only used by the old Netlink interface.
+ *
+ * Revision 1.15 2001/12/11 02:35:57 rgb
+ * Change "struct net_device" to "struct device" for 2.2 compatibility.
+ *
+ * Revision 1.14 2001/11/26 09:23:47 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.13.2.1 2001/09/25 02:18:24 mcr
+ * replace "struct device" with "struct netdevice"
+ *
+ * Revision 1.13 2001/06/14 19:35:08 rgb
+ * Update copyright date.
+ *
+ * Revision 1.12 2000/09/12 03:21:20 rgb
+ * Cleared out unused htonq.
+ *
+ * Revision 1.11 2000/09/08 19:12:55 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.10 2000/01/21 06:13:10 rgb
+ * Tidied up spacing.
+ * Added macros for HMAC padding magic numbers.(kravietz)
+ *
+ * Revision 1.9 1999/12/07 18:16:23 rgb
+ * Fixed comments at end of #endif lines.
+ *
+ * Revision 1.8 1999/04/11 00:28:56 henry
+ * GPL boilerplate
+ *
+ * Revision 1.7 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.6 1999/01/26 02:06:01 rgb
+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+ *
+ * Revision 1.5 1999/01/22 06:17:49 rgb
+ * Updated macro comments.
+ * Added context types to support algorithm switch code.
+ * 64-bit clean-up -- converting 'u long long' to __u64.
+ *
+ * Revision 1.4 1998/07/14 15:54:56 rgb
+ * Add #ifdef __KERNEL__ to protect kernel-only structures.
+ *
+ * Revision 1.3 1998/06/30 18:05:16 rgb
+ * Comment out references to htonq.
+ *
+ * Revision 1.2 1998/06/25 19:33:46 rgb
+ * Add prototype for protocol receive function.
+ * Rearrange for more logical layout.
+ *
+ * Revision 1.1 1998/06/18 21:27:43 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.4 1998/05/18 22:28:43 rgb
+ * Disable key printing facilities from /proc/net/ipsec_*.
+ *
+ * Revision 1.3 1998/04/21 21:29:07 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.2 1998/04/12 22:03:17 rgb
+ * Updated ESP-3DES-HMAC-MD5-96,
+ * ESP-DES-HMAC-MD5-96,
+ * AH-HMAC-MD5-96,
+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
+ *
+ * Fixed eroute references in /proc/net/ipsec*.
+ *
+ * Started to patch module unloading memory leaks in ipsec_netlink and
+ * radij tree unloading.
+ *
+ * Revision 1.1 1998/04/09 03:05:55 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Added definitions for new AH transforms.
+ *
+ * Revision 0.3 1996/11/20 14:35:48 ji
+ * Minor Cleanup.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_alg.h b/linux/include/freeswan/ipsec_alg.h
new file mode 100644
index 000000000..a393784b1
--- /dev/null
+++ b/linux/include/freeswan/ipsec_alg.h
@@ -0,0 +1,254 @@
+/*
+ * Modular extensions service and registration functions interface
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg.h,v 1.2 2004/03/22 21:53:18 as Exp $
+ *
+ */
+/*
+ * 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.
+ *
+ */
+#ifndef IPSEC_ALG_H
+#define IPSEC_ALG_H
+
+/*
+ * gcc >= 3.2 has removed __FUNCTION__, replaced by C99 __func__
+ * *BUT* its a compiler variable.
+ */
+#if (__GNUC__ >= 3)
+#ifndef __FUNCTION__
+#define __FUNCTION__ __func__
+#endif
+#endif
+
+/* Version 0.8.1-0 */
+#define IPSEC_ALG_VERSION 0x00080100
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+/*
+ * The following structs are used via pointers in ipsec_alg object to
+ * avoid ipsec_alg.h coupling with freeswan headers, thus simplifying
+ * module development
+ */
+struct ipsec_sa;
+struct esp;
+
+/**************************************
+ *
+ * Main registration object
+ *
+ *************************************/
+#define IPSEC_ALG_VERSION_QUAD(v) \
+ (v>>24),((v>>16)&0xff),((v>>8)&0xff),(v&0xff)
+/*
+ * Main ipsec_alg objects: "OOPrograming wannabe"
+ * Hierachy (carefully handled with _minimal_ cast'ing):
+ *
+ * ipsec_alg+
+ * +->ipsec_alg_enc (ixt_alg_type=SADB_EXT_SUPPORTED_ENCRYPT)
+ * +->ipsec_alg_auth (ixt_alg_type=SADB_EXT_SUPPORTED_AUTH)
+ */
+
+/***************************************************************
+ *
+ * INTERFACE object: struct ipsec_alg
+ *
+ ***************************************************************/
+
+/*
+ * common part for every struct ipsec_alg_*
+ * (sortof poor's man OOP)
+ */
+#define IPSEC_ALG_STRUCT_COMMON \
+ unsigned ixt_version; /* only allow this version (or 'near')*/ \
+ struct list_head ixt_list; /* dlinked list */ \
+ struct module *ixt_module; /* THIS_MODULE */ \
+ unsigned ixt_state; /* state flags */ \
+ atomic_t ixt_refcnt; /* ref. count when pointed from ipsec_sa */ \
+ char ixt_name[16]; /* descriptive short name, eg. "3des" */ \
+ void *ixt_data; /* private for algo implementation */ \
+ uint8_t ixt_blocksize; /* blocksize in bytes */ \
+ \
+ /* THIS IS A COPY of struct supported (lib/pfkey.h) \
+ * please keep in sync until we migrate 'supported' stuff \
+ * to ipsec_alg \
+ */ \
+ uint16_t ixt_alg_type; /* correspond to IPSEC_ALG_{ENCRYPT,AUTH} */ \
+ uint8_t ixt_alg_id; /* enc. alg. number, eg. ESP_3DES */ \
+ uint8_t ixt_ivlen; /* ivlen in bits, expected to be multiple of 8! */ \
+ uint16_t ixt_keyminbits;/* min. keybits (of entropy) */ \
+ uint16_t ixt_keymaxbits;/* max. keybits (of entropy) */
+
+#define ixt_support ixt_alg_type
+
+#define IPSEC_ALG_ST_SUPP 0x01
+#define IPSEC_ALG_ST_REGISTERED 0x02
+#define IPSEC_ALG_ST_EXCL 0x04
+struct ipsec_alg {
+ IPSEC_ALG_STRUCT_COMMON
+};
+/*
+ * Note the const in cbc_encrypt IV arg:
+ * some ciphers like to toast passed IV (eg. 3DES): make a local IV copy
+ */
+struct ipsec_alg_enc {
+ IPSEC_ALG_STRUCT_COMMON
+ unsigned ixt_e_keylen; /* raw key length in bytes */
+ unsigned ixt_e_ctx_size; /* sa_p->key_e_size */
+ int (*ixt_e_set_key)(struct ipsec_alg_enc *alg, __u8 *key_e, const __u8 *key, size_t keysize);
+ __u8 *(*ixt_e_new_key)(struct ipsec_alg_enc *alg, const __u8 *key, size_t keysize);
+ void (*ixt_e_destroy_key)(struct ipsec_alg_enc *alg, __u8 *key_e);
+ int (*ixt_e_cbc_encrypt)(struct ipsec_alg_enc *alg, __u8 *key_e, __u8 *in, int ilen, const __u8 *iv, int encrypt);
+};
+struct ipsec_alg_auth {
+ IPSEC_ALG_STRUCT_COMMON
+ unsigned ixt_a_keylen; /* raw key length in bytes */
+ unsigned ixt_a_ctx_size; /* sa_p->key_a_size */
+ unsigned ixt_a_authlen; /* 'natural' auth. hash len (bytes) */
+ int (*ixt_a_hmac_set_key)(struct ipsec_alg_auth *alg, __u8 *key_a, const __u8 *key, int keylen);
+ int (*ixt_a_hmac_hash)(struct ipsec_alg_auth *alg, __u8 *key_a, const __u8 *dat, int len, __u8 *hash, int hashlen);
+};
+/*
+ * These are _copies_ of SADB_EXT_SUPPORTED_{AUTH,ENCRYPT},
+ * to avoid header coupling for true constants
+ * about headers ... "cp is your friend" --Linus
+ */
+#define IPSEC_ALG_TYPE_AUTH 14
+#define IPSEC_ALG_TYPE_ENCRYPT 15
+
+/***************************************************************
+ *
+ * INTERFACE for module loading,testing, and unloading
+ *
+ ***************************************************************/
+/* - registration calls */
+int register_ipsec_alg(struct ipsec_alg *);
+int unregister_ipsec_alg(struct ipsec_alg *);
+/* - optional (simple test) for algos */
+int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int testparm);
+/* inline wrappers (usefull for type validation */
+static inline int register_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
+ return register_ipsec_alg((struct ipsec_alg*)ixt);
+}
+static inline int unregister_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
+ return unregister_ipsec_alg((struct ipsec_alg*)ixt);
+}
+static inline int register_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
+ return register_ipsec_alg((struct ipsec_alg*)ixt);
+}
+static inline int unregister_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
+ return unregister_ipsec_alg((struct ipsec_alg*)ixt);
+}
+
+/*****************************************************************
+ *
+ * INTERFACE for ENC services: key creation, encrypt function
+ *
+ *****************************************************************/
+
+#define IPSEC_ALG_ENCRYPT 1
+#define IPSEC_ALG_DECRYPT 0
+
+/* encryption key context creation function */
+int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p);
+/*
+ * ipsec_alg_esp_encrypt(): encrypt ilen bytes in idat returns
+ * 0 or ERR<0
+ */
+int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 *idat, int ilen, const __u8 *iv, int action);
+
+/***************************************************************
+ *
+ * INTERFACE for AUTH services: key creation, hash functions
+ *
+ ***************************************************************/
+int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p);
+int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) ;
+#define ipsec_alg_sa_esp_update(c,k,l) ipsec_alg_sa_esp_hash(c,k,l,NULL,0)
+
+/* only called from ipsec_init.c */
+int ipsec_alg_init(void);
+
+/* algo module glue for static algos */
+void ipsec_alg_static_init(void);
+typedef int (*ipsec_alg_init_func_t) (void);
+
+/**********************************************
+ *
+ * INTERFACE for ipsec_sa init and wipe
+ *
+ **********************************************/
+
+/* returns true if ipsec_sa has ipsec_alg obj attached */
+/*
+ * Initializes ipsec_sa's ipsec_alg object, using already loaded
+ * proto, authalg, encalg.; links ipsec_alg objects (enc, auth)
+ */
+int ipsec_alg_sa_init(struct ipsec_sa *sa_p);
+/*
+ * Destroys ipsec_sa's ipsec_alg object
+ * unlinking ipsec_alg objects
+ */
+int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p);
+
+/**********************************************
+ *
+ * 2.2 backport for some 2.4 useful module stuff
+ *
+ **********************************************/
+#ifdef MODULE
+#ifndef THIS_MODULE
+#define THIS_MODULE (&__this_module)
+#endif
+#ifndef module_init
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+
+#define module_init(x) \
+ int init_module(void) __attribute__((alias(#x))); \
+ static inline __init_module_func_t __init_module_inline(void) \
+ { return x; }
+#define module_exit(x) \
+ void cleanup_module(void) __attribute__((alias(#x))); \
+ static inline __cleanup_module_func_t __cleanup_module_inline(void) \
+ { return x; }
+#endif
+
+#define IPSEC_ALG_MODULE_INIT( func_name ) \
+ static int func_name(void); \
+ module_init(func_name); \
+ static int __init func_name(void)
+#define IPSEC_ALG_MODULE_EXIT( func_name ) \
+ static void func_name(void); \
+ module_exit(func_name); \
+ static void __exit func_name(void)
+#else /* not MODULE */
+#ifndef THIS_MODULE
+#define THIS_MODULE NULL
+#endif
+/*
+ * I only want module_init() magic
+ * when algo.c file *is THE MODULE*, in all other
+ * cases, initialization is called explicitely from ipsec_alg_init()
+ */
+#define IPSEC_ALG_MODULE_INIT( func_name ) \
+ extern int func_name(void); \
+ int func_name(void)
+#define IPSEC_ALG_MODULE_EXIT( func_name ) \
+ extern void func_name(void); \
+ void func_name(void)
+#endif
+
+#endif /* IPSEC_ALG_H */
diff --git a/linux/include/freeswan/ipsec_encap.h b/linux/include/freeswan/ipsec_encap.h
new file mode 100644
index 000000000..17cd69269
--- /dev/null
+++ b/linux/include/freeswan/ipsec_encap.h
@@ -0,0 +1,143 @@
+/*
+ * declarations relevant to encapsulation-like operations
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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: ipsec_encap.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+#ifndef _IPSEC_ENCAP_H_
+
+#define SENT_IP4 16 /* data is two struct in_addr + proto + ports*/
+ /* (2 * sizeof(struct in_addr)) */
+ /* sizeof(struct sockaddr_encap)
+ - offsetof(struct sockaddr_encap, Sen.Sip4.Src) */
+
+struct sockaddr_encap
+{
+ __u8 sen_len; /* length */
+ __u8 sen_family; /* AF_ENCAP */
+ __u16 sen_type; /* see SENT_* */
+ union
+ {
+ struct /* SENT_IP4 */
+ {
+ struct in_addr Src;
+ struct in_addr Dst;
+ __u8 Proto;
+ __u16 Sport;
+ __u16 Dport;
+ } Sip4;
+ } Sen;
+};
+
+#define sen_ip_src Sen.Sip4.Src
+#define sen_ip_dst Sen.Sip4.Dst
+#define sen_proto Sen.Sip4.Proto
+#define sen_sport Sen.Sip4.Sport
+#define sen_dport Sen.Sip4.Dport
+
+#ifndef AF_ENCAP
+#define AF_ENCAP 26
+#endif /* AF_ENCAP */
+
+#define _IPSEC_ENCAP_H_
+#endif /* _IPSEC_ENCAP_H_ */
+
+/*
+ * $Log: ipsec_encap.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.17 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_encap.h,v
+ *
+ * Revision 1.16 2001/11/26 09:23:47 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.15.2.1 2001/09/25 02:18:54 mcr
+ * struct eroute moved to ipsec_eroute.h
+ *
+ * Revision 1.15 2001/09/14 16:58:36 rgb
+ * Added support for storing the first and last packets through a HOLD.
+ *
+ * Revision 1.14 2001/09/08 21:13:31 rgb
+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
+ *
+ * Revision 1.13 2001/06/14 19:35:08 rgb
+ * Update copyright date.
+ *
+ * Revision 1.12 2001/05/27 06:12:10 rgb
+ * Added structures for pid, packet count and last access time to eroute.
+ * Added packet count to beginning of /proc/net/ipsec_eroute.
+ *
+ * Revision 1.11 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.10 2000/03/22 16:15:36 rgb
+ * Fixed renaming of dev_get (MB).
+ *
+ * Revision 1.9 2000/01/21 06:13:26 rgb
+ * Added a macro for AF_ENCAP
+ *
+ * Revision 1.8 1999/12/31 14:56:55 rgb
+ * MB fix for 2.3 dev-use-count.
+ *
+ * Revision 1.7 1999/11/18 04:09:18 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ *
+ * Revision 1.6 1999/09/24 00:34:13 rgb
+ * Add Marc Boucher's support for 2.3.xx+.
+ *
+ * Revision 1.5 1999/04/11 00:28:57 henry
+ * GPL boilerplate
+ *
+ * Revision 1.4 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.3 1998/10/19 14:44:28 rgb
+ * Added inclusion of freeswan.h.
+ * sa_id structure implemented and used: now includes protocol.
+ *
+ * Revision 1.2 1998/07/14 18:19:33 rgb
+ * Added #ifdef __KERNEL__ directives to restrict scope of header.
+ *
+ * Revision 1.1 1998/06/18 21:27:44 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/21 21:29:10 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.1 1998/04/09 03:05:58 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Minor cosmetic changes.
+ *
+ * Revision 0.3 1996/11/20 14:35:48 ji
+ * Minor Cleanup.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_eroute.h b/linux/include/freeswan/ipsec_eroute.h
new file mode 100644
index 000000000..2ee2a10b8
--- /dev/null
+++ b/linux/include/freeswan/ipsec_eroute.h
@@ -0,0 +1,103 @@
+/*
+ * @(#) declarations of eroute structures
+ *
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * Copyright (C) 2001 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_eroute.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ *
+ * derived from ipsec_encap.h 1.15 on 2001/9/18 by mcr.
+ *
+ */
+
+#ifndef _IPSEC_EROUTE_H_
+
+#include "radij.h"
+#include "ipsec_encap.h"
+#include "ipsec_radij.h"
+
+/*
+ * The "type" is really part of the address as far as the routing
+ * system is concerned. By using only one bit in the type field
+ * for each type, we sort-of make sure that different types of
+ * encapsulation addresses won't be matched against the wrong type.
+ */
+
+/*
+ * An entry in the radix tree
+ */
+
+struct rjtentry
+{
+ struct radij_node rd_nodes[2]; /* tree glue, and other values */
+#define rd_key(r) ((struct sockaddr_encap *)((r)->rd_nodes->rj_key))
+#define rd_mask(r) ((struct sockaddr_encap *)((r)->rd_nodes->rj_mask))
+ short rd_flags;
+ short rd_count;
+};
+
+struct ident
+{
+ __u16 type; /* identity type */
+ __u64 id; /* identity id */
+ __u8 len; /* identity len */
+ caddr_t data; /* identity data */
+};
+
+/*
+ * An encapsulation route consists of a pointer to a
+ * radix tree entry and a SAID (a destination_address/SPI/protocol triple).
+ */
+
+struct eroute
+{
+ struct rjtentry er_rjt;
+ struct sa_id er_said;
+ uint32_t er_pid;
+ uint32_t er_count;
+ uint64_t er_lasttime;
+ struct sockaddr_encap er_eaddr; /* MCR get rid of _encap, it is silly*/
+ struct sockaddr_encap er_emask;
+ struct ident er_ident_s;
+ struct ident er_ident_d;
+ struct sk_buff* er_first;
+ struct sk_buff* er_last;
+};
+
+#define er_dst er_said.dst
+#define er_spi er_said.spi
+
+#define _IPSEC_EROUTE_H_
+#endif /* _IPSEC_EROUTE_H_ */
+
+/*
+ * $Log: ipsec_eroute.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.3 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_eroute.h,v
+ *
+ * Revision 1.2 2001/11/26 09:16:13 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.1.2.1 2001/09/25 02:18:54 mcr
+ * struct eroute moved to ipsec_eroute.h
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_errs.h b/linux/include/freeswan/ipsec_errs.h
new file mode 100644
index 000000000..f14b5e675
--- /dev/null
+++ b/linux/include/freeswan/ipsec_errs.h
@@ -0,0 +1,53 @@
+/*
+ * @(#) definition of ipsec_errs structure
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_errs.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ *
+ */
+
+/*
+ * This file describes the errors/statistics that FreeSWAN collects.
+ *
+ */
+
+struct ipsec_errs {
+ __u32 ips_alg_errs; /* number of algorithm errors */
+ __u32 ips_auth_errs; /* # of authentication errors */
+ __u32 ips_encsize_errs; /* # of encryption size errors*/
+ __u32 ips_encpad_errs; /* # of encryption pad errors*/
+ __u32 ips_replaywin_errs; /* # of pkt sequence errors */
+};
+
+/*
+ * $Log: ipsec_errs.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.3 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_errs.h,v
+ *
+ * Revision 1.2 2001/11/26 09:16:13 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.1.2.1 2001/09/25 02:25:57 mcr
+ * lifetime structure created and common functions created.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_esp.h b/linux/include/freeswan/ipsec_esp.h
new file mode 100644
index 000000000..c7d5ea15d
--- /dev/null
+++ b/linux/include/freeswan/ipsec_esp.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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: ipsec_esp.h,v 1.2 2004/03/22 21:53:18 as Exp $
+ */
+
+#include "freeswan/ipsec_md5h.h"
+#include "freeswan/ipsec_sha1.h"
+
+#include "crypto/des.h"
+
+#ifndef IPPROTO_ESP
+#define IPPROTO_ESP 50
+#endif /* IPPROTO_ESP */
+
+#define ESP_HEADER_LEN 8 /* 64 bits header (spi+rpl)*/
+
+#define EMT_ESPDESCBC_ULEN 20 /* coming from user mode */
+#define EMT_ESPDES_KMAX 64 /* 512 bit secret key enough? */
+#define EMT_ESPDES_KEY_SZ 8 /* 56 bit secret key with parity = 64 bits */
+#define EMT_ESP3DES_KEY_SZ 24 /* 168 bit secret key with parity = 192 bits */
+#define EMT_ESPDES_IV_SZ 8 /* IV size */
+#define ESP_DESCBC_BLKLEN 8 /* DES-CBC block size */
+
+#define ESP_IV_MAXSZ 16 /* This is _critical_ */
+#define ESP_IV_MAXSZ_INT (ESP_IV_MAXSZ/sizeof(int))
+
+#define DB_ES_PKTRX 0x0001
+#define DB_ES_PKTRX2 0x0002
+#define DB_ES_IPSA 0x0010
+#define DB_ES_XF 0x0020
+#define DB_ES_IPAD 0x0040
+#define DB_ES_INAU 0x0080
+#define DB_ES_OINFO 0x0100
+#define DB_ES_OINFO2 0x0200
+#define DB_ES_OH 0x0400
+#define DB_ES_REPLAY 0x0800
+
+#ifdef __KERNEL__
+struct des_eks {
+ des_key_schedule ks;
+};
+
+extern struct inet_protocol esp_protocol;
+
+struct options;
+
+extern int
+esp_rcv(struct sk_buff *skb,
+ struct device *dev,
+ struct options *opt,
+ __u32 daddr,
+ unsigned short len,
+ __u32 saddr,
+ int redo,
+ struct inet_protocol *protocol);
+
+/* Only for 64 bits IVs, eg. ESP_3DES :P */
+struct esphdr
+{
+ __u32 esp_spi; /* Security Parameters Index */
+ __u32 esp_rpl; /* Replay counter */
+ __u8 esp_iv[8]; /* iv */
+};
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_esp;
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* __KERNEL__ */
+
+/*
+ * $Log: ipsec_esp.h,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.21 2003/02/06 02:21:34 rgb
+ *
+ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
+ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
+ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
+ *
+ * Revision 1.20 2002/05/14 02:37:02 rgb
+ * Change reference from _TDB to _IPSA.
+ *
+ * Revision 1.19 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.18 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_esp.h,v
+ *
+ * Revision 1.17 2002/02/20 01:27:07 rgb
+ * Ditched a pile of structs only used by the old Netlink interface.
+ *
+ * Revision 1.16 2001/12/11 02:35:57 rgb
+ * Change "struct net_device" to "struct device" for 2.2 compatibility.
+ *
+ * Revision 1.15 2001/11/26 09:23:48 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.14.2.3 2001/10/23 04:16:42 mcr
+ * get definition of des_key_schedule from des.h
+ *
+ * Revision 1.14.2.2 2001/10/22 20:33:13 mcr
+ * use "des_key_schedule" structure instead of cooking our own.
+ *
+ * Revision 1.14.2.1 2001/09/25 02:18:25 mcr
+ * replace "struct device" with "struct netdevice"
+ *
+ * Revision 1.14 2001/06/14 19:35:08 rgb
+ * Update copyright date.
+ *
+ * Revision 1.13 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.12 2000/08/01 14:51:50 rgb
+ * Removed _all_ remaining traces of DES.
+ *
+ * Revision 1.11 2000/01/10 16:36:20 rgb
+ * Ditch last of EME option flags, including initiator.
+ *
+ * Revision 1.10 1999/12/07 18:16:22 rgb
+ * Fixed comments at end of #endif lines.
+ *
+ * Revision 1.9 1999/04/11 00:28:57 henry
+ * GPL boilerplate
+ *
+ * Revision 1.8 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.7 1999/01/26 02:06:00 rgb
+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+ *
+ * Revision 1.6 1999/01/22 15:22:05 rgb
+ * Re-enable IV in the espblkrply_edata structure to avoid breaking pluto
+ * until pluto can be fixed properly.
+ *
+ * Revision 1.5 1999/01/22 06:18:16 rgb
+ * Updated macro comments.
+ * Added key schedule types to support algorithm switch code.
+ *
+ * Revision 1.4 1998/08/12 00:07:32 rgb
+ * Added data structures for new xforms: null, {,3}dessha1.
+ *
+ * Revision 1.3 1998/07/14 15:57:01 rgb
+ * Add #ifdef __KERNEL__ to protect kernel-only structures.
+ *
+ * Revision 1.2 1998/06/25 19:33:46 rgb
+ * Add prototype for protocol receive function.
+ * Rearrange for more logical layout.
+ *
+ * Revision 1.1 1998/06/18 21:27:45 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.6 1998/06/05 02:28:08 rgb
+ * Minor comment fix.
+ *
+ * Revision 1.5 1998/05/27 22:34:00 rgb
+ * Changed structures to accomodate key separation.
+ *
+ * Revision 1.4 1998/05/18 22:28:43 rgb
+ * Disable key printing facilities from /proc/net/ipsec_*.
+ *
+ * Revision 1.3 1998/04/21 21:29:07 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.2 1998/04/12 22:03:20 rgb
+ * Updated ESP-3DES-HMAC-MD5-96,
+ * ESP-DES-HMAC-MD5-96,
+ * AH-HMAC-MD5-96,
+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
+ *
+ * Fixed eroute references in /proc/net/ipsec*.
+ *
+ * Started to patch module unloading memory leaks in ipsec_netlink and
+ * radij tree unloading.
+ *
+ * Revision 1.1 1998/04/09 03:06:00 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.5 1997/06/03 04:24:48 ji
+ * Added ESP-3DES-MD5-96 transform.
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Added definitions for new ESP transforms.
+ *
+ * Revision 0.3 1996/11/20 14:35:48 ji
+ * Minor Cleanup.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_ipe4.h b/linux/include/freeswan/ipsec_ipe4.h
new file mode 100644
index 000000000..73b6ae899
--- /dev/null
+++ b/linux/include/freeswan/ipsec_ipe4.h
@@ -0,0 +1,68 @@
+/*
+ * IP-in-IP Header declarations
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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: ipsec_ipe4.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+/* The packet header is an IP header! */
+
+struct ipe4_xdata /* transform table data */
+{
+ struct in_addr i4_src;
+ struct in_addr i4_dst;
+};
+
+#define EMT_IPE4_ULEN 8 /* coming from user mode */
+
+
+/*
+ * $Log: ipsec_ipe4.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.5 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_ipe4.h,v
+ *
+ * Revision 1.4 2001/06/14 19:35:08 rgb
+ * Update copyright date.
+ *
+ * Revision 1.3 1999/04/11 00:28:57 henry
+ * GPL boilerplate
+ *
+ * Revision 1.2 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.1 1998/06/18 21:27:47 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.1 1998/04/09 03:06:07 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:03 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:48:53 ji
+ * Release update only.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_kversion.h b/linux/include/freeswan/ipsec_kversion.h
new file mode 100644
index 000000000..7bf56ac7f
--- /dev/null
+++ b/linux/include/freeswan/ipsec_kversion.h
@@ -0,0 +1,227 @@
+#ifndef _FREESWAN_KVERSIONS_H
+/*
+ * header file for FreeS/WAN library functions
+ * Copyright (C) 1998, 1999, 2000 Henry Spencer.
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ipsec_kversion.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#define _FREESWAN_KVERSIONS_H /* seen it, no need to see it again */
+
+/*
+ * this file contains a series of atomic defines that depend upon
+ * kernel version numbers. The kernel versions are arranged
+ * in version-order number (which is often not chronological)
+ * and each clause enables or disables a feature.
+ */
+
+/*
+ * First, assorted kernel-version-dependent trickery.
+ */
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+#define HEADER_CACHE_BIND_21
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#define SPINLOCK
+#define PROC_FS_21
+#define NETLINK_SOCK
+#define NET_21
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,19)
+#define net_device_stats enet_statistics
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#define SPINLOCK_23
+#define NETDEV_23
+# ifndef CONFIG_IP_ALIAS
+# define CONFIG_IP_ALIAS
+# endif
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+# ifdef NETLINK_XFRM
+# define NETDEV_25
+# endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,25)
+#define PROC_FS_2325
+#undef PROC_FS_21
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
+#define PROC_NO_DUMMY
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,35)
+#define SKB_COPY_EXPAND
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,37)
+#define IP_SELECT_IDENT
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,50)) && defined(CONFIG_NETFILTER)
+#define SKB_RESET_NFCT
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,2)
+#define IP_SELECT_IDENT_NEW
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
+#define IPH_is_SKB_PULLED
+#define SKB_COW_NEW
+#define PROTO_HANDLER_SINGLE_PARM
+#define IP_FRAGMENT_LINEARIZE 1
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) */
+# ifdef REDHAT_BOGOSITY
+# define IP_SELECT_IDENT_NEW
+# define IPH_is_SKB_PULLED
+# define SKB_COW_NEW
+# define PROTO_HANDLER_SINGLE_PARM
+# endif /* REDHAT_BOGOSITY */
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
+#define MALLOC_SLAB
+#define LINUX_KERNEL_HAS_SNPRINTF
+#endif
+
+#ifdef NET_21
+# include <linux/in6.h>
+#else
+ /* old kernel in.h has some IPv6 stuff, but not quite enough */
+# define s6_addr16 s6_addr
+# define AF_INET6 10
+# define uint8_t __u8
+# define uint16_t __u16
+# define uint32_t __u32
+# define uint64_t __u64
+#endif
+
+#ifdef NET_21
+# define ipsec_kfree_skb(a) kfree_skb(a)
+#else /* NET_21 */
+# define ipsec_kfree_skb(a) kfree_skb(a, FREE_WRITE)
+#endif /* NET_21 */
+
+#ifdef NETDEV_23
+# define device net_device
+# define ipsec_dev_get dev_get_by_name
+# define __ipsec_dev_get __dev_get_by_name
+# define ipsec_dev_put(x) dev_put(x)
+# define __ipsec_dev_put(x) __dev_put(x)
+# define ipsec_dev_hold(x) dev_hold(x)
+#else /* NETDEV_23 */
+# define ipsec_dev_get dev_get
+# define __ipsec_dev_put(x)
+# define ipsec_dev_put(x)
+# define ipsec_dev_hold(x)
+#endif /* NETDEV_23 */
+
+#ifndef SPINLOCK
+# include <linux/bios32.h>
+ /* simulate spin locks and read/write locks */
+ typedef struct {
+ volatile char lock;
+ } spinlock_t;
+
+ typedef struct {
+ volatile unsigned int lock;
+ } rwlock_t;
+
+# define spin_lock_init(x) { (x)->lock = 0;}
+# define rw_lock_init(x) { (x)->lock = 0; }
+
+# define spin_lock(x) { while ((x)->lock) barrier(); (x)->lock=1;}
+# define spin_lock_irq(x) { cli(); spin_lock(x);}
+# define spin_lock_irqsave(x,flags) { save_flags(flags); spin_lock_irq(x);}
+
+# define spin_unlock(x) { (x)->lock=0;}
+# define spin_unlock_irq(x) { spin_unlock(x); sti();}
+# define spin_unlock_irqrestore(x,flags) { spin_unlock(x); restore_flags(flags);}
+
+# define read_lock(x) spin_lock(x)
+# define read_lock_irq(x) spin_lock_irq(x)
+# define read_lock_irqsave(x,flags) spin_lock_irqsave(x,flags)
+
+# define read_unlock(x) spin_unlock(x)
+# define read_unlock_irq(x) spin_unlock_irq(x)
+# define read_unlock_irqrestore(x,flags) spin_unlock_irqrestore(x,flags)
+
+# define write_lock(x) spin_lock(x)
+# define write_lock_irq(x) spin_lock_irq(x)
+# define write_lock_irqsave(x,flags) spin_lock_irqsave(x,flags)
+
+# define write_unlock(x) spin_unlock(x)
+# define write_unlock_irq(x) spin_unlock_irq(x)
+# define write_unlock_irqrestore(x,flags) spin_unlock_irqrestore(x,flags)
+#endif /* !SPINLOCK */
+
+#ifndef SPINLOCK_23
+# define spin_lock_bh(x) spin_lock_irq(x)
+# define spin_unlock_bh(x) spin_unlock_irq(x)
+
+# define read_lock_bh(x) read_lock_irq(x)
+# define read_unlock_bh(x) read_unlock_irq(x)
+
+# define write_lock_bh(x) write_lock_irq(x)
+# define write_unlock_bh(x) write_unlock_irq(x)
+#endif /* !SPINLOCK_23 */
+
+#endif /* _FREESWAN_KVERSIONS_H */
+
+/*
+ * $Log: ipsec_kversion.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.7 2003/07/31 22:48:08 mcr
+ * derive NET25-ness from presence of NETLINK_XFRM macro.
+ *
+ * Revision 1.6 2003/06/24 20:22:32 mcr
+ * added new global: ipsecdevices[] so that we can keep track of
+ * the ipsecX devices. They will be referenced with dev_hold(),
+ * so 2.2 may need this as well.
+ *
+ * Revision 1.5 2003/04/03 17:38:09 rgb
+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
+ *
+ * Revision 1.4 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_kversion.h,v
+ *
+ * Revision 1.3 2002/04/12 03:21:17 mcr
+ * three parameter version of ip_select_ident appears first
+ * in 2.4.2 (RH7.1) not 2.4.4.
+ *
+ * Revision 1.2 2002/03/08 21:35:22 rgb
+ * Defined LINUX_KERNEL_HAS_SNPRINTF to shut up compiler warnings after
+ * 2.4.9. (Andreas Piesk).
+ *
+ * Revision 1.1 2002/01/29 02:11:42 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_life.h b/linux/include/freeswan/ipsec_life.h
new file mode 100644
index 000000000..4cf270272
--- /dev/null
+++ b/linux/include/freeswan/ipsec_life.h
@@ -0,0 +1,112 @@
+/*
+ * Definitions relevant to IPSEC lifetimes
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_life.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ *
+ * This file derived from ipsec_xform.h on 2001/9/18 by mcr.
+ *
+ */
+
+/*
+ * This file describes the book keeping fields for the
+ * IPsec Security Association Structure. ("ipsec_sa")
+ *
+ * This structure is never allocated directly by kernel code,
+ * (it is always a static/auto or is part of a structure)
+ * so it does not have a reference count.
+ *
+ */
+
+#ifndef _IPSEC_LIFE_H_
+
+/*
+ * _count is total count.
+ * _hard is hard limit (kill SA after this number)
+ * _soft is soft limit (try to renew SA after this number)
+ * _last is used in some special cases.
+ *
+ */
+
+struct ipsec_lifetime64
+{
+ __u64 ipl_count;
+ __u64 ipl_soft;
+ __u64 ipl_hard;
+ __u64 ipl_last;
+};
+
+struct ipsec_lifetimes
+{
+ /* number of bytes processed */
+ struct ipsec_lifetime64 ipl_bytes;
+
+ /* number of packets processed */
+ struct ipsec_lifetime64 ipl_packets;
+
+ /* time since SA was added */
+ struct ipsec_lifetime64 ipl_addtime;
+
+ /* time since SA was first used */
+ struct ipsec_lifetime64 ipl_usetime;
+
+ /* from rfc2367:
+ * For CURRENT, the number of different connections,
+ * endpoints, or flows that the association has been
+ * allocated towards. For HARD and SOFT, the number of
+ * these the association may be allocated towards
+ * before it expires. The concept of a connection,
+ * flow, or endpoint is system specific.
+ *
+ * mcr(2001-9-18) it is unclear what purpose these serve for FreeSWAN.
+ * They are maintained for PF_KEY compatibility.
+ */
+ struct ipsec_lifetime64 ipl_allocations;
+};
+
+enum ipsec_life_alive {
+ ipsec_life_harddied = -1,
+ ipsec_life_softdied = 0,
+ ipsec_life_okay = 1
+};
+
+enum ipsec_life_type {
+ ipsec_life_timebased = 1,
+ ipsec_life_countbased= 0
+};
+
+#define _IPSEC_LIFE_H_
+#endif /* _IPSEC_LIFE_H_ */
+
+
+/*
+ * $Log: ipsec_life.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.3 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_life.h,v
+ *
+ * Revision 1.2 2001/11/26 09:16:14 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.1.2.1 2001/09/25 02:25:58 mcr
+ * lifetime structure created and common functions created.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_md5h.h b/linux/include/freeswan/ipsec_md5h.h
new file mode 100644
index 000000000..3fc54bc82
--- /dev/null
+++ b/linux/include/freeswan/ipsec_md5h.h
@@ -0,0 +1,140 @@
+/*
+ * RCSID $Id: ipsec_md5h.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+/*
+ * The rest of this file is Copyright RSA DSI. See the following comments
+ * for the full Copyright notice.
+ */
+
+#ifndef _IPSEC_MD5H_H_
+#define _IPSEC_MD5H_H_
+
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif /* !PROTOTYPES */
+
+/* POINTER defines a generic pointer type */
+typedef __u8 *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef __u16 UINT2;
+
+/* UINT4 defines a four byte word */
+typedef __u32 UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else /* PROTOTYPES */
+#define PROTO_LIST(list) ()
+#endif /* PROTOTYPES */
+
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((void *));
+void MD5Update PROTO_LIST
+ ((void *, unsigned char *, __u32));
+void MD5Final PROTO_LIST ((unsigned char [16], void *));
+
+#endif /* _IPSEC_MD5H_H_ */
+
+/*
+ * $Log: ipsec_md5h.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.8 2002/09/10 01:45:09 mcr
+ * changed type of MD5_CTX and SHA1_CTX to void * so that
+ * the function prototypes would match, and could be placed
+ * into a pointer to a function.
+ *
+ * Revision 1.7 2002/04/24 07:36:46 mcr
+ * Moved from ./klips/net/ipsec/ipsec_md5h.h,v
+ *
+ * Revision 1.6 1999/12/13 13:59:13 rgb
+ * Quick fix to argument size to Update bugs.
+ *
+ * Revision 1.5 1999/12/07 18:16:23 rgb
+ * Fixed comments at end of #endif lines.
+ *
+ * Revision 1.4 1999/04/06 04:54:26 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.3 1999/01/22 06:19:58 rgb
+ * 64-bit clean-up.
+ *
+ * Revision 1.2 1998/11/30 13:22:54 rgb
+ * Rationalised all the klips kernel file headers. They are much shorter
+ * now and won't conflict under RH5.2.
+ *
+ * Revision 1.1 1998/06/18 21:27:48 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/23 20:54:03 rgb
+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
+ * verified.
+ *
+ * Revision 1.1 1998/04/09 03:04:21 henry
+ * sources moved up from linux/net/ipsec
+ * these two include files modified not to include others except in kernel
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:03 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:48:53 ji
+ * Release update only.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_param.h b/linux/include/freeswan/ipsec_param.h
new file mode 100644
index 000000000..02b36e6a3
--- /dev/null
+++ b/linux/include/freeswan/ipsec_param.h
@@ -0,0 +1,226 @@
+/*
+ * @(#) FreeSWAN tunable paramaters
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_param.h,v 1.2 2004/04/28 08:07:11 as Exp $
+ *
+ */
+
+/*
+ * This file provides a set of #define's which may be tuned by various
+ * people/configurations. It keeps all compile-time tunables in one place.
+ *
+ * This file should be included before all other IPsec kernel-only files.
+ *
+ */
+
+#ifndef _IPSEC_PARAM_H_
+
+#ifdef __KERNEL__
+#include "ipsec_kversion.h"
+
+/* Set number of ipsecX virtual devices here. */
+/* This must be < exp(field width of IPSEC_DEV_FORMAT) */
+/* It must also be reasonable so as not to overload the memory and CPU */
+/* constraints of the host. */
+#define IPSEC_NUM_IF 4
+/* The field width must be < IF_NAM_SIZ - strlen("ipsec") - 1. */
+/* With "ipsec" being 5 characters, that means 10 is the max field width */
+/* but machine memory and CPU constraints are not likely to tollerate */
+/* more than 3 digits. The default is one digit. */
+/* Update: userland scripts get upset if they can't find "ipsec0", so */
+/* for now, no "0"-padding should be used (which would have been helpful */
+/* to make text-searches work */
+#define IPSEC_DEV_FORMAT "ipsec%d"
+/* For, say, 500 virtual ipsec devices, I would recommend: */
+/* #define IPSEC_NUM_IF 500 */
+/* #define IPSEC_DEV_FORMAT "ipsec%03d" */
+/* Note that the "interfaces=" line in /etc/ipsec.conf would be, um, challenging. */
+
+/* use dynamic ipsecX device allocation */
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif /* CONFIG_IPSEC_DYNDEV */
+
+
+#ifdef CONFIG_IPSEC_BIGGATE
+# define SADB_HASHMOD 8069
+#else /* CONFIG_IPSEC_BIGGATE */
+# define SADB_HASHMOD 257
+#endif /* CONFIG_IPSEC_BIGGATE */
+#endif /* __KERNEL__ */
+
+/*
+ * This is for the SA reference table. This number is related to the
+ * maximum number of SAs that KLIPS can concurrently deal with, plus enough
+ * space for keeping expired SAs around.
+ *
+ * TABLE_MAX_WIDTH is the number of bits that we will use.
+ * MAIN_TABLE_WIDTH is the number of bits used for the primary index table.
+ *
+ */
+#ifndef IPSEC_SA_REF_TABLE_IDX_WIDTH
+# define IPSEC_SA_REF_TABLE_IDX_WIDTH 16
+#endif
+
+#ifndef IPSEC_SA_REF_MAINTABLE_IDX_WIDTH
+# define IPSEC_SA_REF_MAINTABLE_IDX_WIDTH 4
+#endif
+
+#ifndef IPSEC_SA_REF_FREELIST_NUM_ENTRIES
+# define IPSEC_SA_REF_FREELIST_NUM_ENTRIES 256
+#endif
+
+#ifndef IPSEC_SA_REF_CODE
+# define IPSEC_SA_REF_CODE 1
+#endif
+
+#ifdef __KERNEL__
+/* This is defined for 2.4, but not 2.2.... */
+#ifndef ARPHRD_VOID
+# define ARPHRD_VOID 0xFFFF
+#endif
+
+/*
+ * Worry about PROC_FS stuff
+ */
+#if defined(PROC_FS_2325)
+/* kernel 2.4 */
+# define IPSEC_PROC_LAST_ARG ,int *eof,void *data
+# define IPSEC_PROCFS_DEBUG_NO_STATIC
+# define IPSEC_PROC_SUBDIRS
+#else
+/* kernel <2.4 */
+# define IPSEC_PROCFS_DEBUG_NO_STATIC DEBUG_NO_STATIC
+
+# ifndef PROC_NO_DUMMY
+# define IPSEC_PROC_LAST_ARG , int dummy
+# else
+# define IPSEC_PROC_LAST_ARG
+# endif /* !PROC_NO_DUMMY */
+#endif /* PROC_FS_2325 */
+
+#if !defined(LINUX_KERNEL_HAS_SNPRINTF)
+/* GNU CPP specific! */
+# define snprintf(buf, len, fmt...) sprintf(buf, ##fmt)
+#endif /* !LINUX_KERNEL_HAS_SNPRINTF */
+
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+
+#ifndef KLIPS_FIXES_DES_PARITY
+# define KLIPS_FIXES_DES_PARITY 1
+#endif /* !KLIPS_FIXES_DES_PARITY */
+
+/* we don't really want to print these unless there are really big problems */
+#ifndef KLIPS_DIVULGE_CYPHER_KEY
+# define KLIPS_DIVULGE_CYPHER_KEY 0
+#endif /* !KLIPS_DIVULGE_CYPHER_KEY */
+
+#ifndef KLIPS_DIVULGE_HMAC_KEY
+# define KLIPS_DIVULGE_HMAC_KEY 0
+#endif /* !KLIPS_DIVULGE_HMAC_KEY */
+
+#ifndef IPSEC_DISALLOW_IPOPTIONS
+# define IPSEC_DISALLOW_IPOPTIONS 1
+#endif /* !KLIPS_DIVULGE_HMAC_KEY */
+
+/* extra toggles for regression testing */
+#ifdef CONFIG_IPSEC_REGRESS
+
+/*
+ * should pfkey_acquire() become 100% lossy?
+ *
+ */
+extern int sysctl_ipsec_regress_pfkey_lossage;
+#ifndef KLIPS_PFKEY_ACQUIRE_LOSSAGE
+# ifdef CONFIG_IPSEC_PFKEY_ACQUIRE_LOSSAGE
+# define KLIPS_PFKEY_ACQUIRE_LOSSAGE 100
+# else /* CONFIG_IPSEC_PFKEY_ACQUIRE_LOSSAGE */
+/* not by default! */
+# define KLIPS_PFKEY_ACQUIRE_LOSSAGE 0
+# endif /* CONFIG_IPSEC_PFKEY_ACQUIRE_LOSSAGE */
+#endif /* KLIPS_PFKEY_ACQUIRE_LOSSAGE */
+
+#endif /* CONFIG_IPSEC_REGRESS */
+
+/*
+ * debugging routines.
+ */
+#ifdef CONFIG_IPSEC_DEBUG
+extern void ipsec_print_ip(struct iphdr *ip);
+
+ #define KLIPS_PRINT(flag, format, args...) \
+ ((flag) ? printk(KERN_INFO format , ## args) : 0)
+ #define KLIPS_PRINTMORE(flag, format, args...) \
+ ((flag) ? printk(format , ## args) : 0)
+ #define KLIPS_IP_PRINT(flag, ip) \
+ ((flag) ? ipsec_print_ip(ip) : 0)
+#else /* CONFIG_IPSEC_DEBUG */
+ #define KLIPS_PRINT(flag, format, args...) do ; while(0)
+ #define KLIPS_PRINTMORE(flag, format, args...) do ; while(0)
+ #define KLIPS_IP_PRINT(flag, ip) do ; while(0)
+#endif /* CONFIG_IPSEC_DEBUG */
+
+
+/*
+ * Stupid kernel API differences in APIs. Not only do some
+ * kernels not have ip_select_ident, but some have differing APIs,
+ * and SuSE has one with one parameter, but no way of checking to
+ * see what is really what.
+ */
+
+#ifdef SUSE_LINUX_2_4_19_IS_STUPID
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph)
+#else
+
+/* simplest case, nothing */
+#if !defined(IP_SELECT_IDENT)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) do { iph->id = htons(ip_id_count++); } while(0)
+#endif
+
+/* kernels > 2.3.37-ish */
+#if defined(IP_SELECT_IDENT) && !defined(IP_SELECT_IDENT_NEW)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst)
+#endif
+
+/* kernels > 2.4.2 */
+#if defined(IP_SELECT_IDENT) && defined(IP_SELECT_IDENT_NEW)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst, NULL)
+#endif
+
+#endif /* SUSE_LINUX_2_4_19_IS_STUPID */
+
+/*
+ * make klips fail test:east-espiv-01.
+ * exploit is at testing/attacks/espiv
+ *
+ */
+#define KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK 0
+
+
+/* IP_FRAGMENT_LINEARIZE is set in freeswan.h if Kernel > 2.4.4 */
+#ifndef IP_FRAGMENT_LINEARIZE
+# define IP_FRAGMENT_LINEARIZE 0
+#endif /* IP_FRAGMENT_LINEARIZE */
+#endif /* __KERNEL__ */
+
+#define _IPSEC_PARAM_H_
+#endif /* _IPSEC_PARAM_H_ */
diff --git a/linux/include/freeswan/ipsec_policy.h b/linux/include/freeswan/ipsec_policy.h
new file mode 100644
index 000000000..90b58ad52
--- /dev/null
+++ b/linux/include/freeswan/ipsec_policy.h
@@ -0,0 +1,225 @@
+#ifndef _IPSEC_POLICY_H
+/*
+ * policy interface file between pluto and applications
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ipsec_policy.h,v 1.4 2004/10/04 22:43:56 as Exp $
+ */
+#define _IPSEC_POLICY_H /* seen it, no need to see it again */
+
+
+/*
+ * this file defines an interface between an application (or rather an
+ * application library) and a key/policy daemon. It provides for inquiries
+ * as to the current state of a connected socket, as well as for general
+ * questions.
+ *
+ * In general, the interface is defined as a series of functional interfaces,
+ * and the policy messages should be internal. However, because this is in
+ * fact an ABI between pieces of the system that may get compiled and revised
+ * seperately, this ABI must be public and revision controlled.
+ *
+ * It is expected that the daemon will always support previous versions.
+ */
+
+#define IPSEC_POLICY_MSG_REVISION (unsigned)200305061
+
+enum ipsec_policy_command {
+ IPSEC_CMD_QUERY_FD = 1,
+ IPSEC_CMD_QUERY_HOSTPAIR = 2,
+ IPSEC_CMD_QUERY_DSTONLY = 3,
+};
+
+struct ipsec_policy_msg_head {
+ u_int32_t ipm_version;
+ u_int32_t ipm_msg_len;
+ u_int32_t ipm_msg_type;
+ u_int32_t ipm_msg_seq;
+};
+
+enum ipsec_privacy_quality {
+ IPSEC_PRIVACY_NONE = 0,
+ IPSEC_PRIVACY_INTEGRAL = 4, /* not private at all. AH-like */
+ IPSEC_PRIVACY_UNKNOWN = 8, /* something is claimed, but details unavail */
+ IPSEC_PRIVACY_ROT13 = 12, /* trivially breakable, i.e. 1DES */
+ IPSEC_PRIVACY_GAK = 16, /* known eavesdroppers */
+ IPSEC_PRIVACY_PRIVATE = 32, /* secure for at least a decade */
+ IPSEC_PRIVACY_STRONG = 64, /* ridiculously secure */
+ IPSEC_PRIVACY_TORTOISE = 192, /* even stronger, but very slow */
+ IPSEC_PRIVACY_OTP = 224, /* some kind of *true* one time pad */
+};
+
+enum ipsec_bandwidth_quality {
+ IPSEC_QOS_UNKNOWN = 0, /* unknown bandwidth */
+ IPSEC_QOS_INTERACTIVE = 16, /* reasonably moderate jitter, moderate fast.
+ Good enough for telnet/ssh. */
+ IPSEC_QOS_VOIP = 32, /* faster crypto, predicable jitter */
+ IPSEC_QOS_FTP = 64, /* higher throughput crypto, perhaps hardware
+ offloaded, but latency/jitter may be bad */
+ IPSEC_QOS_WIRESPEED = 128, /* expect to be able to fill your pipe */
+};
+
+/* moved from programs/pluto/constants.h */
+/* IPsec AH transform values
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.3
+ * and in http://www.iana.org/assignments/isakmp-registry
+ */
+enum ipsec_authentication_algo {
+ AH_NONE = 0,
+ AH_MD5 = 2,
+ AH_SHA = 3,
+ AH_DES = 4,
+ AH_SHA2_256 = 5,
+ AH_SHA2_384 = 6,
+ AH_SHA2_512 = 7,
+ AH_RIPEMD = 8
+};
+
+/* IPsec ESP transform values
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.4
+ * and from http://www.iana.org/assignments/isakmp-registry
+ */
+
+enum ipsec_cipher_algo {
+ ESP_NONE = 0,
+ ESP_DES_IV64 = 1,
+ ESP_DES = 2,
+ ESP_3DES = 3,
+ ESP_RC5 = 4,
+ ESP_IDEA = 5,
+ ESP_CAST = 6,
+ ESP_BLOWFISH = 7,
+ ESP_3IDEA = 8,
+ ESP_DES_IV32 = 9,
+ ESP_RC4 = 10,
+ ESP_NULL = 11,
+ ESP_AES = 12,
+ ESP_AES_CTR = 13,
+ ESP_AES_CCM_8 = 14,
+ ESP_AES_CCM_12 = 15,
+ ESP_AES_CCM_16 = 16,
+ ESP_SERPENT = 252,
+ ESP_TWOFISH = 253
+};
+
+/* IPCOMP transform values
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.5
+ */
+
+enum ipsec_comp_algo {
+ IPSCOMP_NONE = 0,
+ IPCOMP_OUI = 1,
+ IPCOMP_DEFLATE = 2,
+ IPCOMP_LZS = 3,
+ IPCOMP_LZJH = 4
+};
+
+/* Identification type values
+ * RFC 2407 The Internet IP security Domain of Interpretation for ISAKMP 4.6.2.1
+ */
+
+enum ipsec_id_type {
+ ID_IMPOSSIBLE= (-2), /* private to Pluto */
+ ID_MYID= (-1), /* private to Pluto */
+ ID_NONE= 0, /* private to Pluto */
+ ID_IPV4_ADDR= 1,
+ ID_FQDN= 2,
+ ID_USER_FQDN= 3,
+ ID_IPV4_ADDR_SUBNET= 4,
+ ID_IPV6_ADDR= 5,
+ ID_IPV6_ADDR_SUBNET= 6,
+ ID_IPV4_ADDR_RANGE= 7,
+ ID_IPV6_ADDR_RANGE= 8,
+ ID_DER_ASN1_DN= 9,
+ ID_DER_ASN1_GN= 10,
+ ID_KEY_ID= 11
+};
+
+/* Certificate type values
+ * RFC 2408 ISAKMP, chapter 3.9
+ */
+enum ipsec_cert_type {
+ CERT_NONE= 0,
+ CERT_PKCS7_WRAPPED_X509= 1, /* self-signed certificate from disk */
+ CERT_PGP= 2,
+ CERT_DNS_SIGNED_KEY= 3, /* KEY RR from DNS */
+ CERT_X509_SIGNATURE= 4,
+ CERT_X509_KEY_EXCHANGE= 5,
+ CERT_KERBEROS_TOKENS= 6,
+ CERT_CRL= 7,
+ CERT_ARL= 8,
+ CERT_SPKI= 9,
+ CERT_X509_ATTRIBUTE= 10,
+ CERT_RAW_RSA= 11, /* raw RSA from config file */
+};
+
+/* a SIG record in ASCII */
+struct ipsec_dns_sig {
+ char fqdn[256];
+ char dns_sig[768]; /* empty string if not signed */
+};
+
+struct ipsec_raw_key {
+ char id_name[256];
+ char fs_keyid[8];
+};
+
+struct ipsec_identity {
+ enum ipsec_id_type ii_type;
+ enum ipsec_cert_type ii_format;
+ union {
+ struct ipsec_dns_sig ipsec_dns_signed;
+ /* some thing for PGP */
+ /* some thing for PKIX */
+ struct ipsec_raw_key ipsec_raw_key;
+ } ii_credential;
+};
+
+#define IPSEC_MAX_CREDENTIALS 32
+
+struct ipsec_policy_cmd_query {
+ struct ipsec_policy_msg_head head;
+
+ /* Query section */
+ ip_address query_local; /* us */
+ ip_address query_remote; /* them */
+ u_short src_port, dst_port;
+
+ /* Answer section */
+ enum ipsec_privacy_quality strength;
+ enum ipsec_bandwidth_quality bandwidth;
+ enum ipsec_authentication_algo auth_detail;
+ enum ipsec_cipher_algo esp_detail;
+ enum ipsec_comp_algo comp_detail;
+
+ int credential_count;
+
+ struct ipsec_identity credentials[IPSEC_MAX_CREDENTIALS];
+};
+
+#define IPSEC_POLICY_SOCKET "/var/run/pluto.info"
+
+/* prototypes */
+extern err_t ipsec_policy_lookup(int fd, struct ipsec_policy_cmd_query *result);
+extern err_t ipsec_policy_init(void);
+extern err_t ipsec_policy_final(void);
+extern err_t ipsec_policy_readmsg(int policysock,
+ unsigned char *buf, size_t buflen);
+extern err_t ipsec_policy_sendrecv(unsigned char *buf, size_t buflen);
+extern err_t ipsec_policy_cgilookup(struct ipsec_policy_cmd_query *result);
+
+
+extern const char *ipsec_policy_version_code(void);
+extern const char *ipsec_policy_version_string(void);
+
+#endif /* _IPSEC_POLICY_H */
diff --git a/linux/include/freeswan/ipsec_proto.h b/linux/include/freeswan/ipsec_proto.h
new file mode 100644
index 000000000..55f947512
--- /dev/null
+++ b/linux/include/freeswan/ipsec_proto.h
@@ -0,0 +1,111 @@
+/*
+ * @(#) prototypes for FreeSWAN functions
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_proto.h,v 1.3 2004/06/13 19:55:14 as Exp $
+ *
+ */
+
+#ifndef _IPSEC_PROTO_H_
+
+#include "ipsec_param.h"
+
+/*
+ * This file is a kernel only file that declares prototypes for
+ * all intra-module function calls and global data structures.
+ *
+ * Include this file last.
+ *
+ */
+
+/* ipsec_init.c */
+extern struct prng ipsec_prng;
+
+/* ipsec_sa.c */
+extern struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
+extern spinlock_t tdb_lock;
+extern int ipsec_sadb_init(void);
+
+extern struct ipsec_sa *ipsec_sa_getbyid(struct sa_id*);
+extern int ipsec_sa_put(struct ipsec_sa *);
+extern /* void */ int ipsec_sa_del(struct ipsec_sa *);
+extern /* void */ int ipsec_sa_delchain(struct ipsec_sa *);
+extern /* void */ int ipsec_sa_add(struct ipsec_sa *);
+
+extern int ipsec_sadb_cleanup(__u8);
+extern int ipsec_sa_wipe(struct ipsec_sa *);
+
+/* debug declarations */
+
+/* ipsec_proc.c */
+extern int ipsec_proc_init(void);
+extern void ipsec_proc_cleanup(void);
+
+/* ipsec_radij.c */
+extern int ipsec_makeroute(struct sockaddr_encap *ea,
+ struct sockaddr_encap *em,
+ struct sa_id said,
+ uint32_t pid,
+ struct sk_buff *skb,
+ struct ident *ident_s,
+ struct ident *ident_d);
+
+extern int ipsec_breakroute(struct sockaddr_encap *ea,
+ struct sockaddr_encap *em,
+ struct sk_buff **first,
+ struct sk_buff **last);
+
+int ipsec_radijinit(void);
+int ipsec_cleareroutes(void);
+int ipsec_radijcleanup(void);
+
+/* ipsec_life.c */
+extern enum ipsec_life_alive ipsec_lifetime_check(struct ipsec_lifetime64 *il64,
+ const char *lifename,
+ const char *saname,
+ enum ipsec_life_type ilt,
+ enum ipsec_direction idir,
+ struct ipsec_sa *ips);
+
+
+extern int ipsec_lifetime_format(char *buffer,
+ int buflen,
+ char *lifename,
+ enum ipsec_life_type timebaselife,
+ struct ipsec_lifetime64 *lifetime);
+
+extern void ipsec_lifetime_update_hard(struct ipsec_lifetime64 *lifetime,
+ __u64 newvalue);
+
+extern void ipsec_lifetime_update_soft(struct ipsec_lifetime64 *lifetime,
+ __u64 newvalue);
+
+
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+
+extern int debug_xform;
+extern int debug_eroute;
+extern int debug_spi;
+extern int debug_netlink;
+
+#endif /* CONFIG_IPSEC_DEBUG */
+
+
+
+
+#define _IPSEC_PROTO_H
+#endif /* _IPSEC_PROTO_H_ */
diff --git a/linux/include/freeswan/ipsec_radij.h b/linux/include/freeswan/ipsec_radij.h
new file mode 100644
index 000000000..7776dd8e4
--- /dev/null
+++ b/linux/include/freeswan/ipsec_radij.h
@@ -0,0 +1,63 @@
+/*
+ * @(#) Definitions relevant to the IPSEC <> radij tree interfacing
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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: ipsec_radij.h,v 1.3 2004/04/28 05:44:29 as Exp $
+ */
+
+#ifndef _IPSEC_RADIJ_H
+
+#include <freeswan.h>
+
+int ipsec_walk(char *);
+
+int ipsec_rj_walker_procprint(struct radij_node *, void *);
+int ipsec_rj_walker_delete(struct radij_node *, void *);
+
+/* This structure is used to pass information between
+ * ipsec_eroute_get_info and ipsec_rj_walker_procprint
+ * (through rj_walktree) and between calls of ipsec_rj_walker_procprint.
+ */
+struct wsbuf
+{
+ /* from caller of ipsec_eroute_get_info: */
+ char *const buffer; /* start of buffer provided */
+ const int length; /* length of buffer provided */
+ const off_t offset; /* file position of first character of interest */
+ /* accumulated by ipsec_rj_walker_procprint: */
+ int len; /* number of character filled into buffer */
+ off_t begin; /* file position contained in buffer[0] (<=offset) */
+};
+
+
+extern struct radij_node_head *rnh;
+extern spinlock_t eroute_lock;
+
+struct eroute * ipsec_findroute(struct sockaddr_encap *);
+
+#define O1(x) (int)(((x)>>24)&0xff)
+#define O2(x) (int)(((x)>>16)&0xff)
+#define O3(x) (int)(((x)>>8)&0xff)
+#define O4(x) (int)(((x))&0xff)
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_radij;
+void rj_dumptrees(void);
+
+#define DB_RJ_DUMPTREES 0x0001
+#define DB_RJ_FINDROUTE 0x0002
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#define _IPSEC_RADIJ_H
+#endif
diff --git a/linux/include/freeswan/ipsec_rcv.h b/linux/include/freeswan/ipsec_rcv.h
new file mode 100644
index 000000000..3ae239bf9
--- /dev/null
+++ b/linux/include/freeswan/ipsec_rcv.h
@@ -0,0 +1,196 @@
+/*
+ *
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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: ipsec_rcv.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+#define DB_RX_PKTRX 0x0001
+#define DB_RX_PKTRX2 0x0002
+#define DB_RX_DMP 0x0004
+#define DB_RX_IPSA 0x0010
+#define DB_RX_XF 0x0020
+#define DB_RX_IPAD 0x0040
+#define DB_RX_INAU 0x0080
+#define DB_RX_OINFO 0x0100
+#define DB_RX_OINFO2 0x0200
+#define DB_RX_OH 0x0400
+#define DB_RX_REPLAY 0x0800
+
+#ifdef __KERNEL__
+/* struct options; */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <freeswan.h>
+
+#define IPSEC_BIRTH_TEMPLATE_MAXLEN 256
+
+struct ipsec_birth_reply {
+ int packet_template_len;
+ unsigned char packet_template[IPSEC_BIRTH_TEMPLATE_MAXLEN];
+};
+
+extern struct ipsec_birth_reply ipsec_ipv4_birth_packet;
+extern struct ipsec_birth_reply ipsec_ipv6_birth_packet;
+
+extern int
+#ifdef PROTO_HANDLER_SINGLE_PARM
+ipsec_rcv(struct sk_buff *skb);
+#else /* PROTO_HANDLER_SINGLE_PARM */
+ipsec_rcv(struct sk_buff *skb,
+#ifdef NET_21
+ unsigned short xlen);
+#else /* NET_21 */
+ struct device *dev,
+ struct options *opt,
+ __u32 daddr,
+ unsigned short len,
+ __u32 saddr,
+ int redo,
+ struct inet_protocol *protocol);
+#endif /* NET_21 */
+#endif /* PROTO_HANDLER_SINGLE_PARM */
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_rcv;
+#endif /* CONFIG_IPSEC_DEBUG */
+extern int sysctl_ipsec_inbound_policy_check;
+#endif /* __KERNEL__ */
+
+/*
+ * $Log: ipsec_rcv.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.17 2002/09/03 16:32:32 mcr
+ * definitions of ipsec_birth_reply.
+ *
+ * Revision 1.16 2002/05/14 02:36:00 rgb
+ * Change references to _TDB to _IPSA.
+ *
+ * Revision 1.15 2002/04/24 07:36:47 mcr
+ * Moved from ./klips/net/ipsec/ipsec_rcv.h,v
+ *
+ * Revision 1.14 2001/09/07 22:15:48 rgb
+ * Fix for removal of transport layer protocol handler arg in 2.4.4.
+ *
+ * Revision 1.13 2001/06/14 19:35:09 rgb
+ * Update copyright date.
+ *
+ * Revision 1.12 2001/03/16 07:36:44 rgb
+ * Fixed #endif comment to sate compiler.
+ *
+ * Revision 1.11 2000/09/21 04:34:21 rgb
+ * Moved declaration of sysctl_ipsec_inbound_policy_check outside
+ * CONFIG_IPSEC_DEBUG. (MB)
+ *
+ * Revision 1.10 2000/09/18 02:36:10 rgb
+ * Exported sysctl_ipsec_inbound_policy_check for skb_decompress().
+ *
+ * Revision 1.9 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.8 1999/11/18 04:09:19 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ *
+ * Revision 1.7 1999/05/25 01:45:37 rgb
+ * Fix version macros for 2.0.x as a module.
+ *
+ * Revision 1.6 1999/05/08 21:24:27 rgb
+ * Add includes for 2.2.x include into net/ipv4/protocol.c
+ *
+ * Revision 1.5 1999/05/05 22:02:32 rgb
+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
+ *
+ * Revision 1.4 1999/04/11 00:28:59 henry
+ * GPL boilerplate
+ *
+ * Revision 1.3 1999/04/06 04:54:27 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.2 1999/01/22 20:06:59 rgb
+ * Fixed cut-and-paste error from ipsec_esp.h.
+ *
+ * Revision 1.1 1999/01/21 20:29:12 rgb
+ * Converted from transform switching to algorithm switching.
+ *
+ * Log: ipsec_esp.h,v
+ * Revision 1.4 1998/08/12 00:07:32 rgb
+ * Added data structures for new xforms: null, {,3}dessha1.
+ *
+ * Revision 1.3 1998/07/14 15:57:01 rgb
+ * Add #ifdef __KERNEL__ to protect kernel-only structures.
+ *
+ * Revision 1.2 1998/06/25 19:33:46 rgb
+ * Add prototype for protocol receive function.
+ * Rearrange for more logical layout.
+ *
+ * Revision 1.1 1998/06/18 21:27:45 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.6 1998/06/05 02:28:08 rgb
+ * Minor comment fix.
+ *
+ * Revision 1.5 1998/05/27 22:34:00 rgb
+ * Changed structures to accomodate key separation.
+ *
+ * Revision 1.4 1998/05/18 22:28:43 rgb
+ * Disable key printing facilities from /proc/net/ipsec_*.
+ *
+ * Revision 1.3 1998/04/21 21:29:07 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.2 1998/04/12 22:03:20 rgb
+ * Updated ESP-3DES-HMAC-MD5-96,
+ * ESP-DES-HMAC-MD5-96,
+ * AH-HMAC-MD5-96,
+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
+ *
+ * Fixed eroute references in /proc/net/ipsec*.
+ *
+ * Started to patch module unloading memory leaks in ipsec_netlink and
+ * radij tree unloading.
+ *
+ * Revision 1.1 1998/04/09 03:06:00 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.5 1997/06/03 04:24:48 ji
+ * Added ESP-3DES-MD5-96 transform.
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Added definitions for new ESP transforms.
+ *
+ * Revision 0.3 1996/11/20 14:35:48 ji
+ * Minor Cleanup.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
+
+
diff --git a/linux/include/freeswan/ipsec_sa.h b/linux/include/freeswan/ipsec_sa.h
new file mode 100644
index 000000000..555df42d3
--- /dev/null
+++ b/linux/include/freeswan/ipsec_sa.h
@@ -0,0 +1,338 @@
+/*
+ * @(#) Definitions of IPsec Security Association (ipsec_sa)
+ *
+ * Copyright (C) 2001, 2002, 2003
+ * Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_sa.h,v 1.3 2004/04/28 08:07:11 as Exp $
+ *
+ * This file derived from ipsec_xform.h on 2001/9/18 by mcr.
+ *
+ */
+
+/*
+ * This file describes the IPsec Security Association Structure.
+ *
+ * This structure keeps track of a single transform that may be done
+ * to a set of packets. It can describe applying the transform or
+ * apply the reverse. (e.g. compression vs expansion). However, it
+ * only describes one at a time. To describe both, two structures would
+ * be used, but since the sides of the transform are performed
+ * on different machines typically it is usual to have only one side
+ * of each association.
+ *
+ */
+
+#ifndef _IPSEC_SA_H_
+
+#ifdef __KERNEL__
+#include "ipsec_stats.h"
+#include "ipsec_life.h"
+#include "ipsec_eroute.h"
+#endif /* __KERNEL__ */
+#include "ipsec_param.h"
+
+
+/* SAs are held in a table.
+ * Entries in this table are referenced by IPsecSAref_t values.
+ * IPsecSAref_t values are conceptually subscripts. Because
+ * we want to allocate the table piece-meal, the subscripting
+ * is implemented with two levels, a bit like paged virtual memory.
+ * This representation mechanism is known as an Iliffe Vector.
+ *
+ * The Main table (AKA the refTable) consists of 2^IPSEC_SA_REF_MAINTABLE_IDX_WIDTH
+ * pointers to subtables.
+ * Each subtable has 2^IPSEC_SA_REF_SUBTABLE_IDX_WIDTH entries, each of which
+ * is a pointer to an SA.
+ *
+ * An IPsecSAref_t contains either an exceptional value (signified by the
+ * high-order bit being on) or a reference to a table entry. A table entry
+ * reference has the subtable subscript in the low-order
+ * IPSEC_SA_REF_SUBTABLE_IDX_WIDTH bits and the Main table subscript
+ * in the next lowest IPSEC_SA_REF_MAINTABLE_IDX_WIDTH bits.
+ *
+ * The Maintable entry for an IPsecSAref_t x, a pointer to its subtable, is
+ * IPsecSAref2table(x). It is of type struct IPsecSArefSubTable *.
+ *
+ * The pointer to the SA for x is IPsecSAref2SA(x). It is of type
+ * struct ipsec_sa*. The macro definition clearly shows the two-level
+ * access needed to find the SA pointer.
+ *
+ * The Maintable is allocated when IPsec is initialized.
+ * Each subtable is allocated when needed, but the first is allocated
+ * when IPsec is initialized.
+ *
+ * IPsecSAref_t is designed to be smaller than an NFmark so that
+ * they can be stored in NFmarks and still leave a few bits for other
+ * purposes. The spare bits are in the low order of the NFmark
+ * but in the high order of the IPsecSAref_t, so conversion is required.
+ * We pick the upper bits of NFmark on the theory that they are less likely to
+ * interfere with more pedestrian uses of nfmark.
+ */
+
+
+typedef unsigned short int IPsecRefTableUnusedCount;
+
+#define IPSEC_SA_REF_TABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH)
+
+#ifdef __KERNEL__
+#if ((IPSEC_SA_REF_TABLE_IDX_WIDTH - (1 + IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)) < 0)
+#error "IPSEC_SA_REF_TABLE_IDX_WIDTH("IPSEC_SA_REF_TABLE_IDX_WIDTH") MUST be < 1 + IPSEC_SA_REF_MAINTABLE_IDX_WIDTH("IPSEC_SA_REF_MAINTABLE_IDX_WIDTH")"
+#endif
+
+#define IPSEC_SA_REF_SUBTABLE_IDX_WIDTH (IPSEC_SA_REF_TABLE_IDX_WIDTH - IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)
+
+#define IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)
+#define IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
+
+#ifdef CONFIG_NETFILTER
+#define IPSEC_SA_REF_HOST_FIELD(x) ((struct sk_buff*)(x))->nfmark
+#define IPSEC_SA_REF_HOST_FIELD_TYPE typeof(IPSEC_SA_REF_HOST_FIELD(NULL))
+#else /* CONFIG_NETFILTER */
+/* just make it work for now, it doesn't matter, since there is no nfmark */
+#define IPSEC_SA_REF_HOST_FIELD_TYPE unsigned long
+#endif /* CONFIG_NETFILTER */
+#define IPSEC_SA_REF_HOST_FIELD_WIDTH (8 * sizeof(IPSEC_SA_REF_HOST_FIELD_TYPE))
+#define IPSEC_SA_REF_FIELD_WIDTH (8 * sizeof(IPsecSAref_t))
+
+#define IPSEC_SA_REF_MASK (IPSEC_SAREF_NULL >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
+#define IPSEC_SA_REF_TABLE_MASK ((IPSEC_SAREF_NULL >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)) << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
+#define IPSEC_SA_REF_ENTRY_MASK (IPSEC_SAREF_NULL >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_SUBTABLE_IDX_WIDTH))
+
+#define IPsecSAref2table(x) (((x) & IPSEC_SA_REF_TABLE_MASK) >> IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
+#define IPsecSAref2entry(x) ((x) & IPSEC_SA_REF_ENTRY_MASK)
+#define IPsecSArefBuild(x,y) (((x) << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH) + (y))
+
+#define IPsecSAref2SA(x) (ipsec_sadb.refTable[IPsecSAref2table(x)]->entry[IPsecSAref2entry(x)])
+#define IPsecSA2SAref(x) ((x)->ips_ref)
+
+#define EMT_INBOUND 0x01 /* SA direction, 1=inbound */
+
+/* 'struct ipsec_sa' should be 64bit aligned when allocated. */
+struct ipsec_sa
+{
+ IPsecSAref_t ips_ref; /* reference table entry number */
+ atomic_t ips_refcount; /* reference count for this struct */
+ struct ipsec_sa *ips_hnext; /* next in hash chain */
+ struct ipsec_sa *ips_inext; /* pointer to next xform */
+ struct ipsec_sa *ips_onext; /* pointer to prev xform */
+
+ struct ifnet *ips_rcvif; /* related rcv encap interface */
+
+ struct sa_id ips_said; /* SA ID */
+
+ __u32 ips_seq; /* seq num of msg that initiated this SA */
+ __u32 ips_pid; /* PID of process that initiated this SA */
+ __u8 ips_authalg; /* auth algorithm for this SA */
+ __u8 ips_encalg; /* enc algorithm for this SA */
+
+ struct ipsec_stats ips_errs;
+
+ __u8 ips_replaywin; /* replay window size */
+ __u8 ips_state; /* state of SA */
+ __u32 ips_replaywin_lastseq; /* last pkt sequence num */
+ __u64 ips_replaywin_bitmap; /* bitmap of received pkts */
+ __u32 ips_replaywin_maxdiff; /* max pkt sequence difference */
+
+ __u32 ips_flags; /* generic xform flags */
+
+
+ struct ipsec_lifetimes ips_life; /* lifetime records */
+
+ /* selector information */
+ struct sockaddr*ips_addr_s; /* src sockaddr */
+ struct sockaddr*ips_addr_d; /* dst sockaddr */
+ struct sockaddr*ips_addr_p; /* proxy sockaddr */
+ __u16 ips_addr_s_size;
+ __u16 ips_addr_d_size;
+ __u16 ips_addr_p_size;
+ ip_address ips_flow_s;
+ ip_address ips_flow_d;
+ ip_address ips_mask_s;
+ ip_address ips_mask_d;
+
+ __u16 ips_key_bits_a; /* size of authkey in bits */
+ __u16 ips_auth_bits; /* size of authenticator in bits */
+ __u16 ips_key_bits_e; /* size of enckey in bits */
+ __u16 ips_iv_bits; /* size of IV in bits */
+ __u8 ips_iv_size;
+ __u16 ips_key_a_size;
+ __u16 ips_key_e_size;
+
+ caddr_t ips_key_a; /* authentication key */
+ caddr_t ips_key_e; /* encryption key */
+ caddr_t ips_iv; /* Initialisation Vector */
+
+ struct ident ips_ident_s; /* identity src */
+ struct ident ips_ident_d; /* identity dst */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ __u16 ips_comp_adapt_tries; /* ipcomp self-adaption tries */
+ __u16 ips_comp_adapt_skip; /* ipcomp self-adaption to-skip */
+ __u64 ips_comp_ratio_cbytes; /* compressed bytes */
+ __u64 ips_comp_ratio_dbytes; /* decompressed (or uncompressed) bytes */
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ __u8 ips_natt_type;
+ __u8 ips_natt_reserved[3];
+ __u16 ips_natt_sport;
+ __u16 ips_natt_dport;
+
+ struct sockaddr *ips_natt_oa;
+ __u16 ips_natt_oa_size;
+ __u16 ips_natt_reserved2;
+#endif
+
+#if 0
+ __u32 ips_sens_dpd;
+ __u8 ips_sens_sens_level;
+ __u8 ips_sens_sens_len;
+ __u64* ips_sens_sens_bitmap;
+ __u8 ips_sens_integ_level;
+ __u8 ips_sens_integ_len;
+ __u64* ips_sens_integ_bitmap;
+#endif
+ struct ipsec_alg_enc *ips_alg_enc;
+ struct ipsec_alg_auth *ips_alg_auth;
+ IPsecSAref_t ips_ref_rel;
+};
+
+struct IPsecSArefSubTable
+{
+ struct ipsec_sa* entry[IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES];
+};
+
+struct ipsec_sadb {
+ struct IPsecSArefSubTable* refTable[IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES];
+ IPsecSAref_t refFreeList[IPSEC_SA_REF_FREELIST_NUM_ENTRIES];
+ int refFreeListHead;
+ int refFreeListTail;
+ IPsecSAref_t refFreeListCont;
+ IPsecSAref_t said_hash[SADB_HASHMOD];
+ spinlock_t sadb_lock;
+};
+
+extern struct ipsec_sadb ipsec_sadb;
+
+extern int ipsec_SAref_recycle(void);
+extern int ipsec_SArefSubTable_alloc(unsigned table);
+extern int ipsec_saref_freelist_init(void);
+extern int ipsec_sadb_init(void);
+extern struct ipsec_sa *ipsec_sa_alloc(int*error); /* pass in error var by pointer */
+extern IPsecSAref_t ipsec_SAref_alloc(int*erorr); /* pass in error var by pointer */
+extern int ipsec_sa_free(struct ipsec_sa* ips);
+extern struct ipsec_sa *ipsec_sa_getbyid(struct sa_id *said);
+extern int ipsec_sa_put(struct ipsec_sa *ips);
+extern int ipsec_sa_add(struct ipsec_sa *ips);
+extern int ipsec_sa_del(struct ipsec_sa *ips);
+extern int ipsec_sa_delchain(struct ipsec_sa *ips);
+extern int ipsec_sadb_cleanup(__u8 proto);
+extern int ipsec_sadb_free(void);
+extern int ipsec_sa_wipe(struct ipsec_sa *ips);
+#endif /* __KERNEL__ */
+
+enum ipsec_direction {
+ ipsec_incoming = 1,
+ ipsec_outgoing = 2
+};
+
+#define _IPSEC_SA_H_
+#endif /* _IPSEC_SA_H_ */
+
+/*
+ * $Log: ipsec_sa.h,v $
+ * Revision 1.3 2004/04/28 08:07:11 as
+ * added dhr's freeswan-2.06 changes
+ *
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1.2.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.15 2003/05/11 00:53:09 mcr
+ * IPsecSAref_t and macros were moved to freeswan.h.
+ *
+ * Revision 1.14 2003/02/12 19:31:55 rgb
+ * Fixed bug in "file seen" machinery.
+ * Updated copyright year.
+ *
+ * Revision 1.13 2003/01/30 02:31:52 rgb
+ *
+ * Re-wrote comments describing SAref system for accuracy.
+ * Rename SAref table macro names for clarity.
+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
+ * Transmit error code through to caller from callee for better diagnosis of problems.
+ * Enclose all macro arguments in parens to avoid any possible obscrure bugs.
+ *
+ * Revision 1.12 2002/10/07 18:31:19 rgb
+ * Change comment to reflect the flexible nature of the main and sub-table widths.
+ * Added a counter for the number of unused entries in each subtable.
+ * Further break up host field type macro to host field.
+ * Move field width sanity checks to ipsec_sa.c
+ * Define a mask for an entire saref.
+ *
+ * Revision 1.11 2002/09/20 15:40:33 rgb
+ * Re-write most of the SAref macros and types to eliminate any pointer references to Entrys.
+ * Fixed SAref/nfmark macros.
+ * Rework saref freeslist.
+ * Place all ipsec sadb globals into one struct.
+ * Restrict some bits to kernel context for use to klips utils.
+ *
+ * Revision 1.10 2002/09/20 05:00:34 rgb
+ * Update copyright date.
+ *
+ * Revision 1.9 2002/09/17 17:19:29 mcr
+ * make it compile even if there is no netfilter - we lost
+ * functionality, but it works, especially on 2.2.
+ *
+ * Revision 1.8 2002/07/28 22:59:53 mcr
+ * clarified/expanded one comment.
+ *
+ * Revision 1.7 2002/07/26 08:48:31 rgb
+ * Added SA ref table code.
+ *
+ * Revision 1.6 2002/05/31 17:27:48 rgb
+ * Comment fix.
+ *
+ * Revision 1.5 2002/05/27 18:55:03 rgb
+ * Remove final vistiges of tdb references via IPSEC_KLIPS1_COMPAT.
+ *
+ * Revision 1.4 2002/05/23 07:13:36 rgb
+ * Convert "usecount" to "refcount" to remove ambiguity.
+ *
+ * Revision 1.3 2002/04/24 07:36:47 mcr
+ * Moved from ./klips/net/ipsec/ipsec_sa.h,v
+ *
+ * Revision 1.2 2001/11/26 09:16:15 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.1.2.1 2001/09/25 02:24:58 mcr
+ * struct tdb -> struct ipsec_sa.
+ * sa(tdb) manipulation functions renamed and moved to ipsec_sa.c
+ * ipsec_xform.c removed. header file still contains useful things.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_sha1.h b/linux/include/freeswan/ipsec_sha1.h
new file mode 100644
index 000000000..116170e6b
--- /dev/null
+++ b/linux/include/freeswan/ipsec_sha1.h
@@ -0,0 +1,79 @@
+/*
+ * RCSID $Id: ipsec_sha1.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+/*
+ * Here is the original comment from the distribution:
+
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+ * Adapted for use by the IPSEC code by John Ioannidis
+ */
+
+
+#ifndef _IPSEC_SHA1_H_
+#define _IPSEC_SHA1_H_
+
+typedef struct
+{
+ __u32 state[5];
+ __u32 count[2];
+ __u8 buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(__u32 state[5], __u8 buffer[64]);
+void SHA1Init(void *context);
+void SHA1Update(void *context, unsigned char *data, __u32 len);
+void SHA1Final(unsigned char digest[20], void *context);
+
+
+#endif /* _IPSEC_SHA1_H_ */
+
+/*
+ * $Log: ipsec_sha1.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.7 2002/09/10 01:45:09 mcr
+ * changed type of MD5_CTX and SHA1_CTX to void * so that
+ * the function prototypes would match, and could be placed
+ * into a pointer to a function.
+ *
+ * Revision 1.6 2002/04/24 07:36:47 mcr
+ * Moved from ./klips/net/ipsec/ipsec_sha1.h,v
+ *
+ * Revision 1.5 1999/12/13 13:59:13 rgb
+ * Quick fix to argument size to Update bugs.
+ *
+ * Revision 1.4 1999/12/07 18:16:23 rgb
+ * Fixed comments at end of #endif lines.
+ *
+ * Revision 1.3 1999/04/06 04:54:27 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.2 1998/11/30 13:22:54 rgb
+ * Rationalised all the klips kernel file headers. They are much shorter
+ * now and won't conflict under RH5.2.
+ *
+ * Revision 1.1 1998/06/18 21:27:50 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/23 20:54:05 rgb
+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
+ * verified.
+ *
+ * Revision 1.1 1998/04/09 03:04:21 henry
+ * sources moved up from linux/net/ipsec
+ * these two include files modified not to include others except in kernel
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * New transform
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_stats.h b/linux/include/freeswan/ipsec_stats.h
new file mode 100644
index 000000000..e4be11d29
--- /dev/null
+++ b/linux/include/freeswan/ipsec_stats.h
@@ -0,0 +1,38 @@
+/*
+ * @(#) definition of ipsec_stats structure
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_stats.h,v 1.2 2004/03/30 19:33:52 as Exp $
+ *
+ */
+
+/*
+ * This file describes the errors/statistics that FreeSWAN collects.
+ */
+
+#ifndef _IPSEC_STATS_H_
+
+struct ipsec_stats {
+ __u32 ips_alg_errs; /* number of algorithm errors */
+ __u32 ips_auth_errs; /* # of authentication errors */
+ __u32 ips_encsize_errs; /* # of encryption size errors*/
+ __u32 ips_encpad_errs; /* # of encryption pad errors*/
+ __u32 ips_replaywin_errs; /* # of pkt sequence errors */
+};
+
+extern int ipsec_snprintf(char * buf, ssize_t size, const char *fmt, ...);
+
+#define _IPSEC_STATS_H_
+#endif /* _IPSEC_STATS_H_ */
diff --git a/linux/include/freeswan/ipsec_tunnel.h b/linux/include/freeswan/ipsec_tunnel.h
new file mode 100644
index 000000000..3b25e95e1
--- /dev/null
+++ b/linux/include/freeswan/ipsec_tunnel.h
@@ -0,0 +1,265 @@
+/*
+ * IPSEC tunneling code
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 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: ipsec_tunnel.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+
+#ifdef NET_21
+# define DEV_QUEUE_XMIT(skb, device, pri) {\
+ skb->dev = device; \
+ neigh_compat_output(skb); \
+ /* skb->dst->output(skb); */ \
+ }
+# define ICMP_SEND(skb_in, type, code, info, dev) \
+ icmp_send(skb_in, type, code, htonl(info))
+# define IP_SEND(skb, dev) \
+ ip_send(skb);
+#else /* NET_21 */
+# define DEV_QUEUE_XMIT(skb, device, pri) {\
+ dev_queue_xmit(skb, device, pri); \
+ }
+# define ICMP_SEND(skb_in, type, code, info, dev) \
+ icmp_send(skb_in, type, code, info, dev)
+# define IP_SEND(skb, dev) \
+ if(ntohs(iph->tot_len) > physmtu) { \
+ ip_fragment(NULL, skb, dev, 0); \
+ ipsec_kfree_skb(skb); \
+ } else { \
+ dev_queue_xmit(skb, dev, SOPRI_NORMAL); \
+ }
+#endif /* NET_21 */
+
+
+/*
+ * Heavily based on drivers/net/new_tunnel.c. Lots
+ * of ideas also taken from the 2.1.x version of drivers/net/shaper.c
+ */
+
+struct ipsectunnelconf
+{
+ __u32 cf_cmd;
+ union
+ {
+ char cfu_name[12];
+ } cf_u;
+#define cf_name cf_u.cfu_name
+};
+
+#define IPSEC_SET_DEV (SIOCDEVPRIVATE)
+#define IPSEC_DEL_DEV (SIOCDEVPRIVATE + 1)
+#define IPSEC_CLR_DEV (SIOCDEVPRIVATE + 2)
+
+#ifdef __KERNEL__
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+struct ipsecpriv
+{
+ struct sk_buff_head sendq;
+ struct device *dev;
+ struct wait_queue *wait_queue;
+ char locked;
+ int (*hard_start_xmit) (struct sk_buff *skb,
+ struct device *dev);
+ int (*hard_header) (struct sk_buff *skb,
+ struct device *dev,
+ unsigned short type,
+ void *daddr,
+ void *saddr,
+ unsigned len);
+#ifdef NET_21
+ int (*rebuild_header)(struct sk_buff *skb);
+#else /* NET_21 */
+ int (*rebuild_header)(void *buff, struct device *dev,
+ unsigned long raddr, struct sk_buff *skb);
+#endif /* NET_21 */
+ int (*set_mac_address)(struct device *dev, void *addr);
+#ifndef NET_21
+ void (*header_cache_bind)(struct hh_cache **hhp, struct device *dev,
+ unsigned short htype, __u32 daddr);
+#endif /* !NET_21 */
+ void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char * haddr);
+ struct net_device_stats *(*get_stats)(struct device *dev);
+ struct net_device_stats mystats;
+ int mtu; /* What is the desired MTU? */
+};
+
+extern char ipsec_tunnel_c_version[];
+
+extern struct device *ipsecdevices[IPSEC_NUM_IF];
+
+int ipsec_tunnel_init_devices(void);
+
+/* void */ int ipsec_tunnel_cleanup_devices(void);
+
+extern /* void */ int ipsec_init(void);
+
+extern int ipsec_tunnel_start_xmit(struct sk_buff *skb, struct device *dev);
+
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_tunnel;
+extern int sysctl_ipsec_debug_verbose;
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* __KERNEL__ */
+
+#ifdef CONFIG_IPSEC_DEBUG
+#define DB_TN_INIT 0x0001
+#define DB_TN_PROCFS 0x0002
+#define DB_TN_XMIT 0x0010
+#define DB_TN_OHDR 0x0020
+#define DB_TN_CROUT 0x0040
+#define DB_TN_OXFS 0x0080
+#define DB_TN_REVEC 0x0100
+#endif /* CONFIG_IPSEC_DEBUG */
+
+/*
+ * $Log: ipsec_tunnel.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.28 2003/06/24 20:22:32 mcr
+ * added new global: ipsecdevices[] so that we can keep track of
+ * the ipsecX devices. They will be referenced with dev_hold(),
+ * so 2.2 may need this as well.
+ *
+ * Revision 1.27 2003/04/03 17:38:09 rgb
+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
+ *
+ * Revision 1.26 2003/02/12 19:32:20 rgb
+ * Updated copyright year.
+ *
+ * Revision 1.25 2002/05/27 18:56:07 rgb
+ * Convert to dynamic ipsec device allocation.
+ *
+ * Revision 1.24 2002/04/24 07:36:48 mcr
+ * Moved from ./klips/net/ipsec/ipsec_tunnel.h,v
+ *
+ * Revision 1.23 2001/11/06 19:50:44 rgb
+ * Moved IP_SEND, ICMP_SEND, DEV_QUEUE_XMIT macros to ipsec_tunnel.h for
+ * use also by pfkey_v2_parser.c
+ *
+ * Revision 1.22 2001/09/15 16:24:05 rgb
+ * Re-inject first and last HOLD packet when an eroute REPLACE is done.
+ *
+ * Revision 1.21 2001/06/14 19:35:10 rgb
+ * Update copyright date.
+ *
+ * Revision 1.20 2000/09/15 11:37:02 rgb
+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+ * IPCOMP zlib deflate code.
+ *
+ * Revision 1.19 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.18 2000/07/28 13:50:54 rgb
+ * Changed enet_statistics to net_device_stats and added back compatibility
+ * for pre-2.1.19.
+ *
+ * Revision 1.17 1999/11/19 01:12:15 rgb
+ * Purge unneeded proc_info prototypes, now that static linking uses
+ * dynamic proc_info registration.
+ *
+ * Revision 1.16 1999/11/18 18:51:00 rgb
+ * Changed all device registrations for static linking to
+ * dynamic to reduce the number and size of patches.
+ *
+ * Revision 1.15 1999/11/18 04:14:21 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
+ * Added Marc Boucher's 2.3.25 proc patches.
+ *
+ * Revision 1.14 1999/05/25 02:50:10 rgb
+ * Fix kernel version macros for 2.0.x static linking.
+ *
+ * Revision 1.13 1999/05/25 02:41:06 rgb
+ * Add ipsec_klipsdebug support for static linking.
+ *
+ * Revision 1.12 1999/05/05 22:02:32 rgb
+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
+ *
+ * Revision 1.11 1999/04/29 15:19:50 rgb
+ * Add return values to init and cleanup functions.
+ *
+ * Revision 1.10 1999/04/16 16:02:39 rgb
+ * Bump up macro to 4 ipsec I/Fs.
+ *
+ * Revision 1.9 1999/04/15 15:37:25 rgb
+ * Forward check changes from POST1_00 branch.
+ *
+ * Revision 1.5.2.1 1999/04/02 04:26:14 rgb
+ * Backcheck from HEAD, pre1.0.
+ *
+ * Revision 1.8 1999/04/11 00:29:01 henry
+ * GPL boilerplate
+ *
+ * Revision 1.7 1999/04/06 04:54:28 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.6 1999/03/31 05:44:48 rgb
+ * Keep PMTU reduction private.
+ *
+ * Revision 1.5 1999/02/10 22:31:20 rgb
+ * Change rebuild_header member to reflect generality of link layer.
+ *
+ * Revision 1.4 1998/12/01 13:22:04 rgb
+ * Added support for debug printing of version info.
+ *
+ * Revision 1.3 1998/07/29 20:42:46 rgb
+ * Add a macro for clearing all tunnel devices.
+ * Rearrange structures and declarations for sharing with userspace.
+ *
+ * Revision 1.2 1998/06/25 20:01:45 rgb
+ * Make prototypes available for ipsec_init and ipsec proc_dir_entries
+ * for static linking.
+ *
+ * Revision 1.1 1998/06/18 21:27:50 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.3 1998/05/18 21:51:50 rgb
+ * Added macros for num of I/F's and a procfs debug switch.
+ *
+ * Revision 1.2 1998/04/21 21:29:09 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.1 1998/04/09 03:06:13 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:05 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.5 1997/06/03 04:24:48 ji
+ * Added transport mode.
+ * Changed the way routing is done.
+ * Lots of bug fixes.
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:39:04 ji
+ * Minor cleanups.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_xform.h b/linux/include/freeswan/ipsec_xform.h
new file mode 100644
index 000000000..1dc6b6083
--- /dev/null
+++ b/linux/include/freeswan/ipsec_xform.h
@@ -0,0 +1,274 @@
+/*
+ * Definitions relevant to IPSEC transformations
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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: ipsec_xform.h,v 1.3 2004/09/29 22:26:13 as Exp $
+ */
+
+#ifndef _IPSEC_XFORM_H_
+
+#include <freeswan.h>
+#include "ipsec_policy.h"
+
+#define XF_NONE 0 /* No transform set */
+#define XF_IP4 1 /* IPv4 inside IPv4 */
+#define XF_AHMD5 2 /* AH MD5 */
+#define XF_AHSHA 3 /* AH SHA */
+#define XF_ESP3DES 5 /* ESP DES3-CBC */
+#define XF_AHHMACMD5 6 /* AH-HMAC-MD5 with opt replay prot */
+#define XF_AHHMACSHA1 7 /* AH-HMAC-SHA1 with opt replay prot */
+#define XF_ESP3DESMD5 9 /* triple DES, HMAC-MD-5, 128-bits of authentication */
+#define XF_ESP3DESMD596 10 /* triple DES, HMAC-MD-5, 96-bits of authentication */
+#define XF_ESPNULLMD596 12 /* NULL, HMAC-MD-5 with 96-bits of authentication */
+#define XF_ESPNULLSHA196 13 /* NULL, HMAC-SHA-1 with 96-bits of authentication */
+#define XF_ESP3DESSHA196 14 /* triple DES, HMAC-SHA-1, 96-bits of authentication */
+#define XF_IP6 15 /* IPv6 inside IPv6 */
+#define XF_COMPDEFLATE 16 /* IPCOMP deflate */
+
+#define XF_CLR 126 /* Clear SA table */
+#define XF_DEL 127 /* Delete SA */
+
+#define XFT_AUTH 0x0001
+#define XFT_CONF 0x0100
+
+/* available if CONFIG_IPSEC_DEBUG is defined */
+#define DB_XF_INIT 0x0001
+
+#define PROTO2TXT(x) \
+ (x) == IPPROTO_AH ? "AH" : \
+ (x) == IPPROTO_ESP ? "ESP" : \
+ (x) == IPPROTO_IPIP ? "IPIP" : \
+ (x) == IPPROTO_COMP ? "COMP" : \
+ "UNKNOWN_proto"
+static inline const char *enc_name_id (unsigned id) {
+ static char buf[16];
+ snprintf(buf, sizeof(buf), "_ID%d", id);
+ return buf;
+}
+static inline const char *auth_name_id (unsigned id) {
+ static char buf[16];
+ snprintf(buf, sizeof(buf), "_ID%d", id);
+ return buf;
+}
+#define IPS_XFORM_NAME(x) \
+ PROTO2TXT((x)->ips_said.proto), \
+ (x)->ips_said.proto == IPPROTO_COMP ? \
+ ((x)->ips_encalg == SADB_X_CALG_DEFLATE ? \
+ "_DEFLATE" : "_UNKNOWN_comp") : \
+ (x)->ips_encalg == ESP_NONE ? "" : \
+ (x)->ips_encalg == ESP_3DES ? "_3DES" : \
+ (x)->ips_encalg == ESP_AES ? "_AES" : \
+ (x)->ips_encalg == ESP_SERPENT ? "_SERPENT" : \
+ (x)->ips_encalg == ESP_TWOFISH ? "_TWOFISH" : \
+ enc_name_id(x->ips_encalg)/* "_UNKNOWN_encr" */, \
+ (x)->ips_authalg == AH_NONE ? "" : \
+ (x)->ips_authalg == AH_MD5 ? "_HMAC_MD5" : \
+ (x)->ips_authalg == AH_SHA ? "_HMAC_SHA1" : \
+ (x)->ips_authalg == AH_SHA2_256 ? "_HMAC_SHA2_256" : \
+ (x)->ips_authalg == AH_SHA2_384 ? "_HMAC_SHA2_384" : \
+ (x)->ips_authalg == AH_SHA2_512 ? "_HMAC_SHA2_512" : \
+ auth_name_id(x->ips_authalg) /* "_UNKNOWN_auth" */ \
+
+#define _IPSEC_XFORM_H_
+#endif /* _IPSEC_XFORM_H_ */
+
+/*
+ * $Log: ipsec_xform.h,v $
+ * Revision 1.3 2004/09/29 22:26:13 as
+ * included ipsec_policy.h
+ *
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.36 2002/04/24 07:36:48 mcr
+ * Moved from ./klips/net/ipsec/ipsec_xform.h,v
+ *
+ * Revision 1.35 2001/11/26 09:23:51 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.33.2.1 2001/09/25 02:24:58 mcr
+ * struct tdb -> struct ipsec_sa.
+ * sa(tdb) manipulation functions renamed and moved to ipsec_sa.c
+ * ipsec_xform.c removed. header file still contains useful things.
+ *
+ * Revision 1.34 2001/11/06 19:47:17 rgb
+ * Changed lifetime_packets to uint32 from uint64.
+ *
+ * Revision 1.33 2001/09/08 21:13:34 rgb
+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
+ *
+ * Revision 1.32 2001/07/06 07:40:01 rgb
+ * Reformatted for readability.
+ * Added inbound policy checking fields for use with IPIP SAs.
+ *
+ * Revision 1.31 2001/06/14 19:35:11 rgb
+ * Update copyright date.
+ *
+ * Revision 1.30 2001/05/30 08:14:03 rgb
+ * Removed vestiges of esp-null transforms.
+ *
+ * Revision 1.29 2001/01/30 23:42:47 rgb
+ * Allow pfkey msgs from pid other than user context required for ACQUIRE
+ * and subsequent ADD or UDATE.
+ *
+ * Revision 1.28 2000/11/06 04:30:40 rgb
+ * Add Svenning's adaptive content compression.
+ *
+ * Revision 1.27 2000/09/19 00:38:25 rgb
+ * Fixed algorithm name bugs introduced for ipcomp.
+ *
+ * Revision 1.26 2000/09/17 21:36:48 rgb
+ * Added proto2txt macro.
+ *
+ * Revision 1.25 2000/09/17 18:56:47 rgb
+ * Added IPCOMP support.
+ *
+ * Revision 1.24 2000/09/12 19:34:12 rgb
+ * Defined XF_IP6 from Gerhard for ipv6 tunnel support.
+ *
+ * Revision 1.23 2000/09/12 03:23:14 rgb
+ * Cleaned out now unused tdb_xform and tdb_xdata members of struct tdb.
+ *
+ * Revision 1.22 2000/09/08 19:12:56 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ *
+ * Revision 1.21 2000/09/01 18:32:43 rgb
+ * Added (disabled) sensitivity members to tdb struct.
+ *
+ * Revision 1.20 2000/08/30 05:31:01 rgb
+ * Removed all the rest of the references to tdb_spi, tdb_proto, tdb_dst.
+ * Kill remainder of tdb_xform, tdb_xdata, xformsw.
+ *
+ * Revision 1.19 2000/08/01 14:51:52 rgb
+ * Removed _all_ remaining traces of DES.
+ *
+ * Revision 1.18 2000/01/21 06:17:45 rgb
+ * Tidied up spacing.
+ *
+ * Revision 1.17 1999/11/17 15:53:40 rgb
+ * Changed all occurrences of #include "../../../lib/freeswan.h"
+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
+ * klips/net/ipsec/Makefile.
+ *
+ * Revision 1.16 1999/10/16 04:23:07 rgb
+ * Add stats for replaywin_errs, replaywin_max_sequence_difference,
+ * authentication errors, encryption size errors, encryption padding
+ * errors, and time since last packet.
+ *
+ * Revision 1.15 1999/10/16 00:29:11 rgb
+ * Added SA lifetime packet counting variables.
+ *
+ * Revision 1.14 1999/10/01 00:04:14 rgb
+ * Added tdb structure locking.
+ * Add function to initialize tdb hash table.
+ *
+ * Revision 1.13 1999/04/29 15:20:57 rgb
+ * dd return values to init and cleanup functions.
+ * Eliminate unnessessary usage of tdb_xform member to further switch
+ * away from the transform switch to the algorithm switch.
+ * Change gettdb parameter to a pointer to reduce stack loading and
+ * facilitate parameter sanity checking.
+ * Add a parameter to tdbcleanup to be able to delete a class of SAs.
+ *
+ * Revision 1.12 1999/04/15 15:37:25 rgb
+ * Forward check changes from POST1_00 branch.
+ *
+ * Revision 1.9.2.2 1999/04/13 20:35:57 rgb
+ * Fix spelling mistake in comment.
+ *
+ * Revision 1.9.2.1 1999/03/30 17:13:52 rgb
+ * Extend struct tdb to support pfkey.
+ *
+ * Revision 1.11 1999/04/11 00:29:01 henry
+ * GPL boilerplate
+ *
+ * Revision 1.10 1999/04/06 04:54:28 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.9 1999/01/26 02:09:31 rgb
+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+ * Removed dead code.
+ *
+ * Revision 1.8 1999/01/22 06:29:35 rgb
+ * Added algorithm switch code.
+ * Cruft clean-out.
+ *
+ * Revision 1.7 1998/11/10 05:37:35 rgb
+ * Add support for SA direction flag.
+ *
+ * Revision 1.6 1998/10/19 14:44:29 rgb
+ * Added inclusion of freeswan.h.
+ * sa_id structure implemented and used: now includes protocol.
+ *
+ * Revision 1.5 1998/08/12 00:12:30 rgb
+ * Added macros for new xforms. Added prototypes for new xforms.
+ *
+ * Revision 1.4 1998/07/28 00:04:20 rgb
+ * Add macro for clearing the SA table.
+ *
+ * Revision 1.3 1998/07/14 18:06:46 rgb
+ * Added #ifdef __KERNEL__ directives to restrict scope of header.
+ *
+ * Revision 1.2 1998/06/23 03:02:19 rgb
+ * Created a prototype for ipsec_tdbcleanup when it was moved from
+ * ipsec_init.c.
+ *
+ * Revision 1.1 1998/06/18 21:27:51 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.4 1998/06/11 05:55:31 rgb
+ * Added transform version string pointer to xformsw structure definition.
+ * Added extern declarations for transform version strings.
+ *
+ * Revision 1.3 1998/05/18 22:02:54 rgb
+ * Modify the *_zeroize function prototypes to include one parameter.
+ *
+ * Revision 1.2 1998/04/21 21:29:08 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.1 1998/04/09 03:06:14 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:06 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.5 1997/06/03 04:24:48 ji
+ * Added ESP-3DES-MD5-96
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * Added new transforms.
+ *
+ * Revision 0.3 1996/11/20 14:39:04 ji
+ * Minor cleanups.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/include/freeswan/ipsec_xmit.h b/linux/include/freeswan/ipsec_xmit.h
new file mode 100644
index 000000000..033984886
--- /dev/null
+++ b/linux/include/freeswan/ipsec_xmit.h
@@ -0,0 +1,140 @@
+/*
+ * IPSEC tunneling code
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 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: ipsec_xmit.h,v 1.3 2004/06/13 19:37:07 as Exp $
+ */
+
+#include "freeswan/ipsec_sa.h"
+
+enum ipsec_xmit_value
+{
+ IPSEC_XMIT_STOLEN=2,
+ IPSEC_XMIT_PASS=1,
+ IPSEC_XMIT_OK=0,
+ IPSEC_XMIT_ERRMEMALLOC=-1,
+ IPSEC_XMIT_ESP_BADALG=-2,
+ IPSEC_XMIT_BADPROTO=-3,
+ IPSEC_XMIT_ESP_PUSHPULLERR=-4,
+ IPSEC_XMIT_BADLEN=-5,
+ IPSEC_XMIT_AH_BADALG=-6,
+ IPSEC_XMIT_SAIDNOTFOUND=-7,
+ IPSEC_XMIT_SAIDNOTLIVE=-8,
+ IPSEC_XMIT_REPLAYROLLED=-9,
+ IPSEC_XMIT_LIFETIMEFAILED=-10,
+ IPSEC_XMIT_CANNOTFRAG=-11,
+ IPSEC_XMIT_MSSERR=-12,
+ IPSEC_XMIT_ERRSKBALLOC=-13,
+ IPSEC_XMIT_ENCAPFAIL=-14,
+ IPSEC_XMIT_NODEV=-15,
+ IPSEC_XMIT_NOPRIVDEV=-16,
+ IPSEC_XMIT_NOPHYSDEV=-17,
+ IPSEC_XMIT_NOSKB=-18,
+ IPSEC_XMIT_NOIPV6=-19,
+ IPSEC_XMIT_NOIPOPTIONS=-20,
+ IPSEC_XMIT_TTLEXPIRED=-21,
+ IPSEC_XMIT_BADHHLEN=-22,
+ IPSEC_XMIT_PUSHPULLERR=-23,
+ IPSEC_XMIT_ROUTEERR=-24,
+ IPSEC_XMIT_RECURSDETECT=-25,
+ IPSEC_XMIT_IPSENDFAILURE=-26,
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ IPSEC_XMIT_ESPUDP=-27,
+#endif
+};
+
+struct ipsec_xmit_state
+{
+ struct sk_buff *skb; /* working skb pointer */
+ struct device *dev; /* working dev pointer */
+ struct ipsecpriv *prv; /* Our device' private space */
+ struct sk_buff *oskb; /* Original skb pointer */
+ struct net_device_stats *stats; /* This device's statistics */
+ struct iphdr *iph; /* Our new IP header */
+ __u32 newdst; /* The other SG's IP address */
+ __u32 orgdst; /* Original IP destination address */
+ __u32 orgedst; /* 1st SG's IP address */
+ __u32 newsrc; /* The new source SG's IP address */
+ __u32 orgsrc; /* Original IP source address */
+ __u32 innersrc; /* Innermost IP source address */
+ int iphlen; /* IP header length */
+ int pyldsz; /* upper protocol payload size */
+ int headroom;
+ int tailroom;
+ int max_headroom; /* The extra header space needed */
+ int max_tailroom; /* The extra stuffing needed */
+ int ll_headroom; /* The extra link layer hard_header space needed */
+ int tot_headroom; /* The total header space needed */
+ int tot_tailroom; /* The totalstuffing needed */
+ __u8 *saved_header; /* saved copy of the hard header */
+ unsigned short sport, dport;
+
+ struct sockaddr_encap matcher; /* eroute search key */
+ struct eroute *eroute;
+ struct ipsec_sa *ipsp, *ipsq; /* ipsec_sa pointers */
+ char sa_txt[SATOA_BUF];
+ size_t sa_len;
+ int hard_header_stripped; /* has the hard header been removed yet? */
+ int hard_header_len;
+ struct device *physdev;
+/* struct device *virtdev; */
+ short physmtu;
+ short mtudiff;
+#ifdef NET_21
+ struct rtable *route;
+#endif /* NET_21 */
+ struct sa_id outgoing_said;
+#ifdef NET_21
+ int pass;
+#endif /* NET_21 */
+ int error;
+ uint32_t eroute_pid;
+ struct ipsec_sa ips;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ uint8_t natt_type;
+ uint8_t natt_head;
+ uint16_t natt_sport;
+ uint16_t natt_dport;
+#endif
+};
+
+#if 0 /* save for alg refactorisation */
+struct xform_functions
+{
+ enum ipsec_xmit_value (*checks)(struct ipsec_xmit_state *ixs,
+ struct sk_buff *skb);
+ enum ipsec_xmit_value (*encrypt)(struct ipsec_xmit_state *ixs);
+
+ enum ipsec_xmit_value (*setup_auth)(struct ipsec_xmit_state *ixs,
+ struct sk_buff *skb,
+ __u32 *replay,
+ unsigned char **authenticator);
+ enum ipsec_xmit_value (*calc_auth)(struct ipsec_xmit_state *ixs,
+ struct sk_buff *skb);
+};
+#endif
+
+enum ipsec_xmit_value
+ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs);
+
+enum ipsec_xmit_value
+ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs);
+
+enum ipsec_xmit_value
+ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs);
+
+extern int ipsec_xmit_trap_count;
+extern int ipsec_xmit_trap_sendcount;
+
+extern void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er);
diff --git a/linux/include/freeswan/radij.h b/linux/include/freeswan/radij.h
new file mode 100644
index 000000000..2a66093a0
--- /dev/null
+++ b/linux/include/freeswan/radij.h
@@ -0,0 +1,280 @@
+/*
+ * RCSID $Id: radij.h,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+
+/*
+ * This file is defived from ${SRC}/sys/net/radix.h of BSD 4.4lite
+ *
+ * Variable and procedure names have been modified so that they don't
+ * conflict with the original BSD code, as a small number of modifications
+ * have been introduced and we may want to reuse this code in BSD.
+ *
+ * The `j' in `radij' is pronounced as a voiceless guttural (like a Greek
+ * chi or a German ch sound (as `doch', not as in `milch'), or even a
+ * spanish j as in Juan. It is not as far back in the throat like
+ * the corresponding Hebrew sound, nor is it a soft breath like the English h.
+ * It has nothing to do with the Dutch ij sound.
+ *
+ * Here is the appropriate copyright notice:
+ */
+
+/*
+ * Copyright (c) 1988, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)radix.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _RADIJ_H_
+#define _RADIJ_H_
+
+/*
+#define RJ_DEBUG
+*/
+
+#ifdef __KERNEL__
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+/*
+ * Radix search tree node layout.
+ */
+
+struct radij_node
+{
+ struct radij_mask *rj_mklist; /* list of masks contained in subtree */
+ struct radij_node *rj_p; /* parent */
+ short rj_b; /* bit offset; -1-index(netmask) */
+ char rj_bmask; /* node: mask for bit test*/
+ u_char rj_flags; /* enumerated next */
+#define RJF_NORMAL 1 /* leaf contains normal route */
+#define RJF_ROOT 2 /* leaf is root leaf for tree */
+#define RJF_ACTIVE 4 /* This node is alive (for rtfree) */
+ union {
+ struct { /* leaf only data: */
+ caddr_t rj_Key; /* object of search */
+ caddr_t rj_Mask; /* netmask, if present */
+ struct radij_node *rj_Dupedkey;
+ } rj_leaf;
+ struct { /* node only data: */
+ int rj_Off; /* where to start compare */
+ struct radij_node *rj_L;/* progeny */
+ struct radij_node *rj_R;/* progeny */
+ }rj_node;
+ } rj_u;
+#ifdef RJ_DEBUG
+ int rj_info;
+ struct radij_node *rj_twin;
+ struct radij_node *rj_ybro;
+#endif
+};
+
+#define rj_dupedkey rj_u.rj_leaf.rj_Dupedkey
+#define rj_key rj_u.rj_leaf.rj_Key
+#define rj_mask rj_u.rj_leaf.rj_Mask
+#define rj_off rj_u.rj_node.rj_Off
+#define rj_l rj_u.rj_node.rj_L
+#define rj_r rj_u.rj_node.rj_R
+
+/*
+ * Annotations to tree concerning potential routes applying to subtrees.
+ */
+
+extern struct radij_mask {
+ short rm_b; /* bit offset; -1-index(netmask) */
+ char rm_unused; /* cf. rj_bmask */
+ u_char rm_flags; /* cf. rj_flags */
+ struct radij_mask *rm_mklist; /* more masks to try */
+ caddr_t rm_mask; /* the mask */
+ int rm_refs; /* # of references to this struct */
+} *rj_mkfreelist;
+
+#define MKGet(m) {\
+ if (rj_mkfreelist) {\
+ m = rj_mkfreelist; \
+ rj_mkfreelist = (m)->rm_mklist; \
+ } else \
+ R_Malloc(m, struct radij_mask *, sizeof (*(m))); }\
+
+#define MKFree(m) { (m)->rm_mklist = rj_mkfreelist; rj_mkfreelist = (m);}
+
+struct radij_node_head {
+ struct radij_node *rnh_treetop;
+ int rnh_addrsize; /* permit, but not require fixed keys */
+ int rnh_pktsize; /* permit, but not require fixed keys */
+#if 0
+ struct radij_node *(*rnh_addaddr) /* add based on sockaddr */
+ __P((void *v, void *mask,
+ struct radij_node_head *head, struct radij_node nodes[]));
+#endif
+ int (*rnh_addaddr) /* add based on sockaddr */
+ __P((void *v, void *mask,
+ struct radij_node_head *head, struct radij_node nodes[]));
+ struct radij_node *(*rnh_addpkt) /* add based on packet hdr */
+ __P((void *v, void *mask,
+ struct radij_node_head *head, struct radij_node nodes[]));
+#if 0
+ struct radij_node *(*rnh_deladdr) /* remove based on sockaddr */
+ __P((void *v, void *mask, struct radij_node_head *head));
+#endif
+ int (*rnh_deladdr) /* remove based on sockaddr */
+ __P((void *v, void *mask, struct radij_node_head *head, struct radij_node **node));
+ struct radij_node *(*rnh_delpkt) /* remove based on packet hdr */
+ __P((void *v, void *mask, struct radij_node_head *head));
+ struct radij_node *(*rnh_matchaddr) /* locate based on sockaddr */
+ __P((void *v, struct radij_node_head *head));
+ struct radij_node *(*rnh_matchpkt) /* locate based on packet hdr */
+ __P((void *v, struct radij_node_head *head));
+ int (*rnh_walktree) /* traverse tree */
+ __P((struct radij_node_head *head, int (*f)(struct radij_node *rn, void *w), void *w));
+ struct radij_node rnh_nodes[3]; /* empty tree for common case */
+};
+
+
+#define Bcmp(a, b, n) memcmp(((caddr_t)(b)), ((caddr_t)(a)), (unsigned)(n))
+#define Bcopy(a, b, n) memmove(((caddr_t)(b)), ((caddr_t)(a)), (unsigned)(n))
+#define Bzero(p, n) memset((caddr_t)(p), 0, (unsigned)(n))
+#define R_Malloc(p, t, n) ((p = (t) kmalloc((size_t)(n), GFP_ATOMIC)), Bzero((p),(n)))
+#define Free(p) kfree((caddr_t)p);
+
+void rj_init __P((void));
+int rj_inithead __P((void **, int));
+int rj_refines __P((void *, void *));
+int rj_walktree __P((struct radij_node_head *head, int (*f)(struct radij_node *rn, void *w), void *w));
+struct radij_node
+ *rj_addmask __P((void *, int, int)) /* , rgb */ ;
+int /* * */ rj_addroute __P((void *, void *, struct radij_node_head *,
+ struct radij_node [2])) /* , rgb */ ;
+int /* * */ rj_delete __P((void *, void *, struct radij_node_head *, struct radij_node **)) /* , rgb */ ;
+struct radij_node /* rgb */
+ *rj_insert __P((void *, struct radij_node_head *, int *,
+ struct radij_node [2])),
+ *rj_match __P((void *, struct radij_node_head *)),
+ *rj_newpair __P((void *, int, struct radij_node[2])),
+ *rj_search __P((void *, struct radij_node *)),
+ *rj_search_m __P((void *, struct radij_node *, void *));
+
+void rj_deltree(struct radij_node_head *);
+void rj_delnodes(struct radij_node *);
+void rj_free_mkfreelist(void);
+int radijcleartree(void);
+int radijcleanup(void);
+
+extern struct radij_node_head *mask_rjhead;
+extern int maj_keylen;
+#endif /* __KERNEL__ */
+
+#endif /* _RADIJ_H_ */
+
+
+/*
+ * $Log: radij.h,v $
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.12 2002/04/24 07:36:48 mcr
+ * Moved from ./klips/net/ipsec/radij.h,v
+ *
+ * Revision 1.11 2001/09/20 15:33:00 rgb
+ * Min/max cleanup.
+ *
+ * Revision 1.10 1999/11/18 04:09:20 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ *
+ * Revision 1.9 1999/05/05 22:02:33 rgb
+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
+ *
+ * Revision 1.8 1999/04/29 15:24:58 rgb
+ * Add check for existence of macros min/max.
+ *
+ * Revision 1.7 1999/04/11 00:29:02 henry
+ * GPL boilerplate
+ *
+ * Revision 1.6 1999/04/06 04:54:29 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.5 1999/01/22 06:30:32 rgb
+ * 64-bit clean-up.
+ *
+ * Revision 1.4 1998/11/30 13:22:55 rgb
+ * Rationalised all the klips kernel file headers. They are much shorter
+ * now and won't conflict under RH5.2.
+ *
+ * Revision 1.3 1998/10/25 02:43:27 rgb
+ * Change return type on rj_addroute and rj_delete and add and argument
+ * to the latter to be able to transmit more infomation about errors.
+ *
+ * Revision 1.2 1998/07/14 18:09:51 rgb
+ * Add a routine to clear eroute table.
+ * Added #ifdef __KERNEL__ directives to restrict scope of header.
+ *
+ * Revision 1.1 1998/06/18 21:30:22 henry
+ * move sources from klips/src to klips/net/ipsec to keep stupid kernel
+ * build scripts happier about symlinks
+ *
+ * Revision 1.4 1998/05/25 20:34:16 rgb
+ * Remove temporary ipsec_walk, rj_deltree and rj_delnodes functions.
+ *
+ * Rename ipsec_rj_walker (ipsec_walk) to ipsec_rj_walker_procprint and
+ * add ipsec_rj_walker_delete.
+ *
+ * Recover memory for eroute table on unload of module.
+ *
+ * Revision 1.3 1998/04/22 16:51:37 rgb
+ * Tidy up radij debug code from recent rash of modifications to debug code.
+ *
+ * Revision 1.2 1998/04/14 17:30:38 rgb
+ * Fix up compiling errors for radij tree memory reclamation.
+ *
+ * Revision 1.1 1998/04/09 03:06:16 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:44:45 ji
+ * Release update only.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/linux/include/mast.h b/linux/include/mast.h
new file mode 100644
index 000000000..626559b59
--- /dev/null
+++ b/linux/include/mast.h
@@ -0,0 +1,33 @@
+struct mast_callbacks {
+ int (*packet_encap)(struct device *mast, void *context,
+ struct sk_buff *skb, int flowref);
+ int (*link_inquire)(struct device *mast, void *context);
+};
+
+
+struct device *mast_init (int family,
+ struct mast_callbacks *callbacks,
+ unsigned int flags,
+ unsigned int desired_unit,
+ unsigned int max_flowref,
+ void *context);
+
+int mast_destroy(struct device *mast);
+
+int mast_recv(struct device *mast, struct sk_buff *skb, int flowref);
+
+/* free this skb as being useless, increment failure count. */
+int mast_toast(struct device *mast, struct sk_buff *skb, int flowref);
+
+int mast_linkstat (struct device *mast, int flowref,
+ int status);
+
+int mast_setreference (struct device *mast,
+ int defaultSA);
+
+int mast_setneighbor (struct device *mast,
+ struct sockaddr *source,
+ struct sockaddr *destination,
+ int flowref);
+
+
diff --git a/linux/include/pfkey.h b/linux/include/pfkey.h
new file mode 100644
index 000000000..f858cd95e
--- /dev/null
+++ b/linux/include/pfkey.h
@@ -0,0 +1,498 @@
+/*
+ * FreeS/WAN specific PF_KEY headers
+ * 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: pfkey.h,v 1.2 2004/03/22 21:53:18 as Exp $
+ */
+
+#ifndef __NET_IPSEC_PF_KEY_H
+#define __NET_IPSEC_PF_KEY_H
+#ifdef __KERNEL__
+extern struct proto_ops pfkey_proto_ops;
+typedef struct sock pfkey_sock;
+extern int debug_pfkey;
+
+extern /* void */ int pfkey_init(void);
+extern /* void */ int pfkey_cleanup(void);
+
+extern struct sock *pfkey_sock_list;
+struct socket_list
+{
+ struct socket *socketp;
+ struct socket_list *next;
+};
+extern int pfkey_list_insert_socket(struct socket*, struct socket_list**);
+extern int pfkey_list_remove_socket(struct socket*, struct socket_list**);
+extern struct socket_list *pfkey_open_sockets;
+extern struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1];
+
+/*
+ * There is a field-by-field copy in klips/net/ipsec/ipsec_alg.h
+ * please keep in sync until we migrate all support stuff
+ * to ipsec_alg objects
+ */
+struct supported
+{
+ uint16_t supported_alg_exttype;
+ uint8_t supported_alg_id;
+ uint8_t supported_alg_ivlen;
+ uint16_t supported_alg_minbits;
+ uint16_t supported_alg_maxbits;
+};
+extern struct supported_list *pfkey_supported_list[SADB_SATYPE_MAX+1];
+struct supported_list
+{
+ struct supported *supportedp;
+ struct supported_list *next;
+};
+extern int pfkey_list_insert_supported(struct supported*, struct supported_list**);
+extern int pfkey_list_remove_supported(struct supported*, struct supported_list**);
+
+struct sockaddr_key
+{
+ uint16_t key_family; /* PF_KEY */
+ uint16_t key_pad; /* not used */
+ uint32_t key_pid; /* process ID */
+};
+
+struct pfkey_extracted_data
+{
+ struct ipsec_sa* ips;
+ struct ipsec_sa* ips2;
+ struct eroute *eroute;
+};
+
+extern int
+pfkey_alloc_eroute(struct eroute** eroute);
+
+extern int
+pfkey_sa_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_lifetime_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_address_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_key_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_ident_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_sens_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_prop_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_supported_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_spirange_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_x_kmprivate_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_x_satype_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int
+pfkey_x_debug_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data* extr);
+
+extern int pfkey_register_reply(int satype, struct sadb_msg *);
+extern int pfkey_upmsg(struct socket *, struct sadb_msg *);
+extern int pfkey_expire(struct ipsec_sa *, int);
+extern int pfkey_acquire(struct ipsec_sa *);
+#else /* ! __KERNEL__ */
+
+extern void (*pfkey_debug_func)(const char *message, ...);
+
+#endif /* __KERNEL__ */
+
+extern uint8_t satype2proto(uint8_t satype);
+extern uint8_t proto2satype(uint8_t proto);
+extern char* satype2name(uint8_t satype);
+extern char* proto2name(uint8_t proto);
+
+struct key_opt
+{
+ uint32_t key_pid; /* process ID */
+ struct sock *sk;
+};
+
+#define key_pid(sk) ((struct key_opt*)&((sk)->protinfo))->key_pid
+
+#define IPSEC_PFKEYv2_ALIGN (sizeof(uint64_t)/sizeof(uint8_t))
+#define BITS_PER_OCTET 8
+#define OCTETBITS 8
+#define PFKEYBITS 64
+#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */
+#define ALIGN_N(x,y) (DIVUP(x,y) * y) /* align on y boundary */
+
+#define PFKEYv2_MAX_MSGSIZE 4096
+
+/*
+ * PF_KEYv2 permitted and required extensions in and out bitmaps
+ */
+struct pf_key_ext_parsers_def {
+ int (*parser)(struct sadb_ext*);
+ char *parser_name;
+};
+
+
+extern unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/];
+#define EXT_BITS_IN 0
+#define EXT_BITS_OUT 1
+#define EXT_BITS_PERM 0
+#define EXT_BITS_REQ 1
+
+extern void pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
+extern void pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
+extern void pfkey_msg_free(struct sadb_msg **pfkey_msg);
+
+extern int pfkey_msg_parse(struct sadb_msg *pfkey_msg,
+ struct pf_key_ext_parsers_def *ext_parsers[],
+ struct sadb_ext **extensions,
+ int dir);
+
+/*
+ * PF_KEYv2 build function prototypes
+ */
+
+int
+pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext,
+ uint8_t msg_type,
+ uint8_t satype,
+ uint8_t msg_errno,
+ uint32_t seq,
+ uint32_t pid);
+
+int
+pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi, /* in network order */
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags,
+ uint32_t/*IPsecSAref_t*/ ref);
+
+int
+pfkey_sa_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi, /* in network order */
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags);
+
+int
+pfkey_lifetime_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t allocations,
+ uint64_t bytes,
+ uint64_t addtime,
+ uint64_t usetime,
+ uint32_t packets);
+
+int
+pfkey_address_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint8_t proto,
+ uint8_t prefixlen,
+ struct sockaddr* address);
+
+int
+pfkey_key_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t key_bits,
+ char* key);
+
+int
+pfkey_ident_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t ident_type,
+ uint64_t ident_id,
+ uint8_t ident_len,
+ char* ident_string);
+
+#ifdef NAT_TRAVERSAL
+#ifdef __KERNEL__
+extern int pfkey_nat_t_new_mapping(struct ipsec_sa *, struct sockaddr *, __u16);
+extern int pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
+extern int pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
+#endif /* __KERNEL__ */
+int
+pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext,
+ uint8_t type);
+int
+pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t port);
+#endif
+
+int
+pfkey_sens_build(struct sadb_ext** pfkey_ext,
+ uint32_t dpd,
+ uint8_t sens_level,
+ uint8_t sens_len,
+ uint64_t* sens_bitmap,
+ uint8_t integ_level,
+ uint8_t integ_len,
+ uint64_t* integ_bitmap);
+
+int pfkey_x_protocol_build(struct sadb_ext **, uint8_t);
+
+
+int
+pfkey_prop_build(struct sadb_ext** pfkey_ext,
+ uint8_t replay,
+ unsigned int comb_num,
+ struct sadb_comb* comb);
+
+int
+pfkey_supported_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ unsigned int alg_num,
+ struct sadb_alg* alg);
+
+int
+pfkey_spirange_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint32_t min,
+ uint32_t max);
+
+int
+pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext);
+
+int
+pfkey_x_satype_build(struct sadb_ext** pfkey_ext,
+ uint8_t satype);
+
+int
+pfkey_x_debug_build(struct sadb_ext** pfkey_ext,
+ uint32_t tunnel,
+ uint32_t netlink,
+ uint32_t xform,
+ uint32_t eroute,
+ uint32_t spi,
+ uint32_t radij,
+ uint32_t esp,
+ uint32_t ah,
+ uint32_t rcv,
+ uint32_t pfkey,
+ uint32_t ipcomp,
+ uint32_t verbose);
+
+int
+pfkey_msg_build(struct sadb_msg** pfkey_msg,
+ struct sadb_ext* extensions[],
+ int dir);
+
+/* in pfkey_v2_debug.c - routines to decode numbers -> strings */
+const char *
+pfkey_v2_sadb_ext_string(int extnum);
+
+const char *
+pfkey_v2_sadb_type_string(int sadb_type);
+
+
+#endif /* __NET_IPSEC_PF_KEY_H */
+
+/*
+ * $Log: pfkey.h,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1.2.1 2004/03/16 09:48:18 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:25 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.42 2003/08/25 22:08:19 mcr
+ * removed pfkey_proto_init() from pfkey.h for 2.6 support.
+ *
+ * Revision 1.41 2003/05/07 17:28:57 mcr
+ * new function pfkey_debug_func added for us in debugging from
+ * pfkey library.
+ *
+ * Revision 1.40 2003/01/30 02:31:34 rgb
+ *
+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
+ *
+ * Revision 1.39 2002/09/20 15:40:21 rgb
+ * Switch from pfkey_alloc_ipsec_sa() to ipsec_sa_alloc().
+ * Added ref parameter to pfkey_sa_build().
+ * Cleaned out unused cruft.
+ *
+ * Revision 1.38 2002/05/14 02:37:24 rgb
+ * Change all references to tdb, TDB or Tunnel Descriptor Block to ips,
+ * ipsec_sa or ipsec_sa.
+ * Added function prototypes for the functions moved to
+ * pfkey_v2_ext_process.c.
+ *
+ * Revision 1.37 2002/04/24 07:36:49 mcr
+ * Moved from ./lib/pfkey.h,v
+ *
+ * Revision 1.36 2002/01/20 20:34:49 mcr
+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
+ *
+ * Revision 1.35 2001/11/27 05:27:47 mcr
+ * pfkey parses are now maintained by a structure
+ * that includes their name for debug purposes.
+ *
+ * Revision 1.34 2001/11/26 09:23:53 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.33 2001/11/06 19:47:47 rgb
+ * Added packet parameter to lifetime and comb structures.
+ *
+ * Revision 1.32 2001/09/08 21:13:34 rgb
+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
+ *
+ * Revision 1.31 2001/06/14 19:35:16 rgb
+ * Update copyright date.
+ *
+ * Revision 1.30 2001/02/27 07:04:52 rgb
+ * Added satype2name prototype.
+ *
+ * Revision 1.29 2001/02/26 19:59:33 rgb
+ * Ditch unused sadb_satype2proto[], replaced by satype2proto().
+ *
+ * Revision 1.28 2000/10/10 20:10:19 rgb
+ * Added support for debug_ipcomp and debug_verbose to klipsdebug.
+ *
+ * Revision 1.27 2000/09/21 04:20:45 rgb
+ * Fixed array size off-by-one error. (Thanks Svenning!)
+ *
+ * Revision 1.26 2000/09/12 03:26:05 rgb
+ * Added pfkey_acquire prototype.
+ *
+ * Revision 1.25 2000/09/08 19:21:28 rgb
+ * Fix pfkey_prop_build() parameter to be only single indirection.
+ *
+ * Revision 1.24 2000/09/01 18:46:42 rgb
+ * Added a supported algorithms array lists, one per satype and registered
+ * existing algorithms.
+ * Fixed pfkey_list_{insert,remove}_{socket,support}() to allow change to
+ * list.
+ *
+ * Revision 1.23 2000/08/27 01:55:26 rgb
+ * Define OCTETBITS and PFKEYBITS to avoid using 'magic' numbers in code.
+ *
+ * Revision 1.22 2000/08/20 21:39:23 rgb
+ * Added kernel prototypes for kernel funcitions pfkey_upmsg() and
+ * pfkey_expire().
+ *
+ * Revision 1.21 2000/08/15 17:29:23 rgb
+ * Fixes from SZI to untested pfkey_prop_build().
+ *
+ * Revision 1.20 2000/05/10 20:14:19 rgb
+ * Fleshed out sensitivity, proposal and supported extensions.
+ *
+ * Revision 1.19 2000/03/16 14:07:23 rgb
+ * Renamed ALIGN macro to avoid fighting with others in kernel.
+ *
+ * Revision 1.18 2000/01/22 23:24:06 rgb
+ * Added prototypes for proto2satype(), satype2proto() and proto2name().
+ *
+ * Revision 1.17 2000/01/21 06:26:59 rgb
+ * Converted from double tdb arguments to one structure (extr)
+ * containing pointers to all temporary information structures.
+ * Added klipsdebug switching capability.
+ * Dropped unused argument to pfkey_x_satype_build().
+ *
+ * Revision 1.16 1999/12/29 21:17:41 rgb
+ * Changed pfkey_msg_build() I/F to include a struct sadb_msg**
+ * parameter for cleaner manipulation of extensions[] and to guard
+ * against potential memory leaks.
+ * Changed the I/F to pfkey_msg_free() for the same reason.
+ *
+ * Revision 1.15 1999/12/09 23:12:54 rgb
+ * Added macro for BITS_PER_OCTET.
+ * Added argument to pfkey_sa_build() to do eroutes.
+ *
+ * Revision 1.14 1999/12/08 20:33:25 rgb
+ * Changed sa_family_t to uint16_t for 2.0.xx compatibility.
+ *
+ * Revision 1.13 1999/12/07 19:53:40 rgb
+ * Removed unused first argument from extension parsers.
+ * Changed __u* types to uint* to avoid use of asm/types.h and
+ * sys/types.h in userspace code.
+ * Added function prototypes for pfkey message and extensions
+ * initialisation and cleanup.
+ *
+ * Revision 1.12 1999/12/01 22:19:38 rgb
+ * Change pfkey_sa_build to accept an SPI in network byte order.
+ *
+ * Revision 1.11 1999/11/27 11:55:26 rgb
+ * Added extern sadb_satype2proto to enable moving protocol lookup table
+ * to lib/pfkey_v2_parse.c.
+ * Delete unused, moved typedefs.
+ * Add argument to pfkey_msg_parse() for direction.
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ *
+ * Revision 1.10 1999/11/23 22:29:21 rgb
+ * This file has been moved in the distribution from klips/net/ipsec to
+ * lib.
+ * Add macros for dealing with alignment and rounding up more opaquely.
+ * The uint<n>_t type defines have been moved to freeswan.h to avoid
+ * chicken-and-egg problems.
+ * Add macros for dealing with alignment and rounding up more opaque.
+ * Added prototypes for using extention header bitmaps.
+ * Added prototypes of all the build functions.
+ *
+ * Revision 1.9 1999/11/20 21:59:48 rgb
+ * Moved socketlist type declarations and prototypes for shared use.
+ * Slightly modified scope of sockaddr_key declaration.
+ *
+ * Revision 1.8 1999/11/17 14:34:25 rgb
+ * Protect sa_family_t from being used in userspace with GLIBC<2.
+ *
+ * Revision 1.7 1999/10/27 19:40:35 rgb
+ * Add a maximum PFKEY packet size macro.
+ *
+ * Revision 1.6 1999/10/26 16:58:58 rgb
+ * Created a sockaddr_key and key_opt socket extension structures.
+ *
+ * Revision 1.5 1999/06/10 05:24:41 rgb
+ * Renamed variables to reduce confusion.
+ *
+ * Revision 1.4 1999/04/29 15:21:11 rgb
+ * Add pfkey support to debugging.
+ * Add return values to init and cleanup functions.
+ *
+ * Revision 1.3 1999/04/15 17:58:07 rgb
+ * Add RCSID labels.
+ *
+ */
diff --git a/linux/include/pfkeyv2.h b/linux/include/pfkeyv2.h
new file mode 100644
index 000000000..48579e27a
--- /dev/null
+++ b/linux/include/pfkeyv2.h
@@ -0,0 +1,385 @@
+/*
+ * RCSID $Id: pfkeyv2.h,v 1.5 2004/10/04 22:43:56 as Exp $
+ */
+
+/*
+RFC 2367 PF_KEY Key Management API July 1998
+
+
+Appendix D: Sample Header File
+
+This file defines structures and symbols for the PF_KEY Version 2
+key management interface. It was written at the U.S. Naval Research
+Laboratory. This file is in the public domain. The authors ask that
+you leave this credit intact on any copies of this file.
+*/
+#ifndef __PFKEY_V2_H
+#define __PFKEY_V2_H 1
+
+#define PF_KEY_V2 2
+#define PFKEYV2_REVISION 199806L
+
+#define SADB_RESERVED 0
+#define SADB_GETSPI 1
+#define SADB_UPDATE 2
+#define SADB_ADD 3
+#define SADB_DELETE 4
+#define SADB_GET 5
+#define SADB_ACQUIRE 6
+#define SADB_REGISTER 7
+#define SADB_EXPIRE 8
+#define SADB_FLUSH 9
+#define SADB_DUMP 10
+#define SADB_X_PROMISC 11
+#define SADB_X_PCHANGE 12
+#define SADB_X_GRPSA 13
+#define SADB_X_ADDFLOW 14
+#define SADB_X_DELFLOW 15
+#define SADB_X_DEBUG 16
+#ifdef NAT_TRAVERSAL
+#define SADB_X_NAT_T_NEW_MAPPING 17
+#define SADB_MAX 17
+#else
+#define SADB_MAX 16
+#endif
+
+struct sadb_msg {
+ uint8_t sadb_msg_version;
+ uint8_t sadb_msg_type;
+ uint8_t sadb_msg_errno;
+ uint8_t sadb_msg_satype;
+ uint16_t sadb_msg_len;
+ uint16_t sadb_msg_reserved;
+ uint32_t sadb_msg_seq;
+ uint32_t sadb_msg_pid;
+};
+
+struct sadb_ext {
+ uint16_t sadb_ext_len;
+ uint16_t sadb_ext_type;
+};
+
+struct sadb_sa {
+ uint16_t sadb_sa_len;
+ uint16_t sadb_sa_exttype;
+ uint32_t sadb_sa_spi;
+ uint8_t sadb_sa_replay;
+ uint8_t sadb_sa_state;
+ uint8_t sadb_sa_auth;
+ uint8_t sadb_sa_encrypt;
+ uint32_t sadb_sa_flags;
+ uint32_t /*IPsecSAref_t*/ sadb_x_sa_ref; /* 32 bits */
+ uint8_t sadb_x_reserved[4];
+};
+
+struct sadb_sa_v1 {
+ uint16_t sadb_sa_len;
+ uint16_t sadb_sa_exttype;
+ uint32_t sadb_sa_spi;
+ uint8_t sadb_sa_replay;
+ uint8_t sadb_sa_state;
+ uint8_t sadb_sa_auth;
+ uint8_t sadb_sa_encrypt;
+ uint32_t sadb_sa_flags;
+};
+
+struct sadb_lifetime {
+ uint16_t sadb_lifetime_len;
+ uint16_t sadb_lifetime_exttype;
+ uint32_t sadb_lifetime_allocations;
+ uint64_t sadb_lifetime_bytes;
+ uint64_t sadb_lifetime_addtime;
+ uint64_t sadb_lifetime_usetime;
+ uint32_t sadb_x_lifetime_packets;
+ uint32_t sadb_x_lifetime_reserved;
+};
+
+struct sadb_address {
+ uint16_t sadb_address_len;
+ uint16_t sadb_address_exttype;
+ uint8_t sadb_address_proto;
+ uint8_t sadb_address_prefixlen;
+ uint16_t sadb_address_reserved;
+};
+
+struct sadb_key {
+ uint16_t sadb_key_len;
+ uint16_t sadb_key_exttype;
+ uint16_t sadb_key_bits;
+ uint16_t sadb_key_reserved;
+};
+
+struct sadb_ident {
+ uint16_t sadb_ident_len;
+ uint16_t sadb_ident_exttype;
+ uint16_t sadb_ident_type;
+ uint16_t sadb_ident_reserved;
+ uint64_t sadb_ident_id;
+};
+
+struct sadb_sens {
+ uint16_t sadb_sens_len;
+ uint16_t sadb_sens_exttype;
+ uint32_t sadb_sens_dpd;
+ uint8_t sadb_sens_sens_level;
+ uint8_t sadb_sens_sens_len;
+ uint8_t sadb_sens_integ_level;
+ uint8_t sadb_sens_integ_len;
+ uint32_t sadb_sens_reserved;
+};
+
+struct sadb_prop {
+ uint16_t sadb_prop_len;
+ uint16_t sadb_prop_exttype;
+ uint8_t sadb_prop_replay;
+ uint8_t sadb_prop_reserved[3];
+};
+
+struct sadb_comb {
+ uint8_t sadb_comb_auth;
+ uint8_t sadb_comb_encrypt;
+ uint16_t sadb_comb_flags;
+ uint16_t sadb_comb_auth_minbits;
+ uint16_t sadb_comb_auth_maxbits;
+ uint16_t sadb_comb_encrypt_minbits;
+ uint16_t sadb_comb_encrypt_maxbits;
+ uint32_t sadb_comb_reserved;
+ uint32_t sadb_comb_soft_allocations;
+ uint32_t sadb_comb_hard_allocations;
+ uint64_t sadb_comb_soft_bytes;
+ uint64_t sadb_comb_hard_bytes;
+ uint64_t sadb_comb_soft_addtime;
+ uint64_t sadb_comb_hard_addtime;
+ uint64_t sadb_comb_soft_usetime;
+ uint64_t sadb_comb_hard_usetime;
+ uint32_t sadb_x_comb_soft_packets;
+ uint32_t sadb_x_comb_hard_packets;
+};
+
+struct sadb_supported {
+ uint16_t sadb_supported_len;
+ uint16_t sadb_supported_exttype;
+ uint32_t sadb_supported_reserved;
+};
+
+struct sadb_alg {
+ uint8_t sadb_alg_id;
+ uint8_t sadb_alg_ivlen;
+ uint16_t sadb_alg_minbits;
+ uint16_t sadb_alg_maxbits;
+ uint16_t sadb_alg_reserved;
+};
+
+struct sadb_spirange {
+ uint16_t sadb_spirange_len;
+ uint16_t sadb_spirange_exttype;
+ uint32_t sadb_spirange_min;
+ uint32_t sadb_spirange_max;
+ uint32_t sadb_spirange_reserved;
+};
+
+struct sadb_x_kmprivate {
+ uint16_t sadb_x_kmprivate_len;
+ uint16_t sadb_x_kmprivate_exttype;
+ uint32_t sadb_x_kmprivate_reserved;
+};
+
+struct sadb_x_satype {
+ uint16_t sadb_x_satype_len;
+ uint16_t sadb_x_satype_exttype;
+ uint8_t sadb_x_satype_satype;
+ uint8_t sadb_x_satype_reserved[3];
+};
+
+struct sadb_x_policy {
+ uint16_t sadb_x_policy_len;
+ uint16_t sadb_x_policy_exttype;
+ uint16_t sadb_x_policy_type;
+ uint8_t sadb_x_policy_dir;
+ uint8_t sadb_x_policy_reserved;
+ uint32_t sadb_x_policy_id;
+ uint32_t sadb_x_policy_reserved2;
+};
+
+struct sadb_x_debug {
+ uint16_t sadb_x_debug_len;
+ uint16_t sadb_x_debug_exttype;
+ uint32_t sadb_x_debug_tunnel;
+ uint32_t sadb_x_debug_netlink;
+ uint32_t sadb_x_debug_xform;
+ uint32_t sadb_x_debug_eroute;
+ uint32_t sadb_x_debug_spi;
+ uint32_t sadb_x_debug_radij;
+ uint32_t sadb_x_debug_esp;
+ uint32_t sadb_x_debug_ah;
+ uint32_t sadb_x_debug_rcv;
+ uint32_t sadb_x_debug_pfkey;
+ uint32_t sadb_x_debug_ipcomp;
+ uint32_t sadb_x_debug_verbose;
+ uint8_t sadb_x_debug_reserved[4];
+};
+
+#ifdef NAT_TRAVERSAL
+struct sadb_x_nat_t_type {
+ uint16_t sadb_x_nat_t_type_len;
+ uint16_t sadb_x_nat_t_type_exttype;
+ uint8_t sadb_x_nat_t_type_type;
+ uint8_t sadb_x_nat_t_type_reserved[3];
+};
+struct sadb_x_nat_t_port {
+ uint16_t sadb_x_nat_t_port_len;
+ uint16_t sadb_x_nat_t_port_exttype;
+ uint16_t sadb_x_nat_t_port_port;
+ uint16_t sadb_x_nat_t_port_reserved;
+};
+#endif
+
+/*
+ * A protocol structure for passing through the transport level
+ * protocol. It contains more fields than are actually used/needed
+ * but it is this way to be compatible with the structure used in
+ * OpenBSD (http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/pfkeyv2.h)
+ */
+struct sadb_protocol {
+ uint16_t sadb_protocol_len;
+ uint16_t sadb_protocol_exttype;
+ uint8_t sadb_protocol_proto;
+ uint8_t sadb_protocol_direction;
+ uint8_t sadb_protocol_flags;
+ uint8_t sadb_protocol_reserved2;
+};
+
+#define SADB_EXT_RESERVED 0
+#define SADB_EXT_SA 1
+#define SADB_EXT_LIFETIME_CURRENT 2
+#define SADB_EXT_LIFETIME_HARD 3
+#define SADB_EXT_LIFETIME_SOFT 4
+#define SADB_EXT_ADDRESS_SRC 5
+#define SADB_EXT_ADDRESS_DST 6
+#define SADB_EXT_ADDRESS_PROXY 7
+#define SADB_EXT_KEY_AUTH 8
+#define SADB_EXT_KEY_ENCRYPT 9
+#define SADB_EXT_IDENTITY_SRC 10
+#define SADB_EXT_IDENTITY_DST 11
+#define SADB_EXT_SENSITIVITY 12
+#define SADB_EXT_PROPOSAL 13
+#define SADB_EXT_SUPPORTED_AUTH 14
+#define SADB_EXT_SUPPORTED_ENCRYPT 15
+#define SADB_EXT_SPIRANGE 16
+#define SADB_X_EXT_KMPRIVATE 17
+#define SADB_X_EXT_SATYPE2 18
+#ifdef KERNEL26_HAS_KAME_DUPLICATES
+#define SADB_X_EXT_POLICY 18
+#endif
+#define SADB_X_EXT_SA2 19
+#define SADB_X_EXT_ADDRESS_DST2 20
+#define SADB_X_EXT_ADDRESS_SRC_FLOW 21
+#define SADB_X_EXT_ADDRESS_DST_FLOW 22
+#define SADB_X_EXT_ADDRESS_SRC_MASK 23
+#define SADB_X_EXT_ADDRESS_DST_MASK 24
+#define SADB_X_EXT_DEBUG 25
+#define SADB_X_EXT_PROTOCOL 26
+#ifdef NAT_TRAVERSAL
+#define SADB_X_EXT_NAT_T_TYPE 27
+#define SADB_X_EXT_NAT_T_SPORT 28
+#define SADB_X_EXT_NAT_T_DPORT 29
+#define SADB_X_EXT_NAT_T_OA 30
+#define SADB_EXT_MAX 30
+#else
+#define SADB_EXT_MAX 26
+#endif
+
+/* SADB_X_DELFLOW required over and above SADB_X_SAFLAGS_CLEARFLOW */
+#define SADB_X_EXT_ADDRESS_DELFLOW \
+ ( (1<<SADB_X_EXT_ADDRESS_SRC_FLOW) \
+ | (1<<SADB_X_EXT_ADDRESS_DST_FLOW) \
+ | (1<<SADB_X_EXT_ADDRESS_SRC_MASK) \
+ | (1<<SADB_X_EXT_ADDRESS_DST_MASK))
+
+#define SADB_SATYPE_UNSPEC 0
+#define SADB_SATYPE_AH 2
+#define SADB_SATYPE_ESP 3
+#define SADB_SATYPE_RSVP 5
+#define SADB_SATYPE_OSPFV2 6
+#define SADB_SATYPE_RIPV2 7
+#define SADB_SATYPE_MIP 8
+#define SADB_X_SATYPE_IPIP 9
+#ifdef KERNEL26_HAS_KAME_DUPLICATES
+#define SADB_X_SATYPE_IPCOMP 9 /* ICK! */
+#endif
+#define SADB_X_SATYPE_COMP 10
+#define SADB_X_SATYPE_INT 11
+#define SADB_SATYPE_MAX 11
+
+#define SADB_SASTATE_LARVAL 0
+#define SADB_SASTATE_MATURE 1
+#define SADB_SASTATE_DYING 2
+#define SADB_SASTATE_DEAD 3
+#define SADB_SASTATE_MAX 3
+
+#define SADB_SAFLAGS_PFS 1
+#define SADB_X_SAFLAGS_REPLACEFLOW 2
+#define SADB_X_SAFLAGS_CLEARFLOW 4
+#define SADB_X_SAFLAGS_INFLOW 8
+
+/* not obvious, but these are the same values as used in isakmp,
+ * and in freeswan/ipsec_policy.h. If you need to add any, they
+ * should be added as according to
+ * http://www.iana.org/assignments/isakmp-registry
+ *
+ * and if not, then please try to use a private-use value, and
+ * consider asking IANA to assign a value.
+ */
+#define SADB_AALG_NONE 0
+#define SADB_AALG_MD5_HMAC 2
+#define SADB_AALG_SHA1_HMAC 3
+#define SADB_AALG_DES_MAC 4
+#define SADB_AALG_SHA2_256_HMAC 5
+#define SADB_AALG_SHA2_384_HMAC 6
+#define SADB_AALG_SHA2_512_HMAC 7
+#define SADB_AALG_RIPEMD_160_HMAC 8
+#define SADB_AALG_AES_XCBC_MAC 9
+#define SADB_X_AALG_NULL 251 /* kame */
+#define SADB_AALG_MAX 251
+
+#define SADB_EALG_NONE 0
+#define SADB_EALG_DES_CBC 2
+#define SADB_EALG_3DES_CBC 3
+#define SADB_EALG_RC5_CBC 4
+#define SADB_EALG_IDEA_CBC 5
+#define SADB_EALG_CAST_CBC 6
+#define SADB_EALG_BLOWFISH_CBC 7
+#define SADB_EALG_NULL 11
+#define SADB_EALG_AES_CBC 12
+#define SADB_EALG_AES_CTR 13
+#define SADB_X_EALG_SERPENT_CBC 252
+#define SADB_X_EALG_TWOFISH_CBC 253
+#define SADB_EALG_MAX 253
+
+#define SADB_X_CALG_NONE 0
+#define SADB_X_CALG_OUI 1
+#define SADB_X_CALG_DEFLATE 2
+#define SADB_X_CALG_LZS 3
+#define SADB_X_CALG_V42BIS 4
+#ifdef KERNEL26_HAS_KAME_DUPLICATES
+#define SADB_X_CALG_LZJH 4
+#endif
+#define SADB_X_CALG_MAX 4
+
+#define SADB_X_TALG_NONE 0
+#define SADB_X_TALG_IPv4_in_IPv4 1
+#define SADB_X_TALG_IPv6_in_IPv4 2
+#define SADB_X_TALG_IPv4_in_IPv6 3
+#define SADB_X_TALG_IPv6_in_IPv6 4
+#define SADB_X_TALG_MAX 4
+
+
+#define SADB_IDENTTYPE_RESERVED 0
+#define SADB_IDENTTYPE_PREFIX 1
+#define SADB_IDENTTYPE_FQDN 2
+#define SADB_IDENTTYPE_USERFQDN 3
+#define SADB_X_IDENTTYPE_CONNECTION 4
+#define SADB_IDENTTYPE_MAX 4
+
+#define SADB_KEY_FLAGS_MAX 0
+#endif /* __PFKEY_V2_H */
diff --git a/linux/include/zlib/zlib.h b/linux/include/zlib/zlib.h
new file mode 100644
index 000000000..744e3822c
--- /dev/null
+++ b/linux/include/zlib/zlib.h
@@ -0,0 +1,893 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.1.4, March 11th, 2002
+
+ Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.4"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ const char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: ascii or binary */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ the compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out).
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero).
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may some
+ introduce some output latency (reading input without producing any output)
+ except when forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+ output as possible to the output buffer. The flushing behavior of inflate is
+ not specified for values of the flush parameter other than Z_SYNC_FLUSH
+ and Z_FINISH, but the current implementation actually flushes as much output
+ as possible anyway.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ If a preset dictionary is needed at this point (see inflateSetDictionary
+ below), inflate sets strm-adler to the adler32 checksum of the
+ dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
+ it sets strm->adler to the adler32 checksum of all output produced
+ so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+ an error code as described below. At the end of the stream, inflate()
+ checks that its computed adler32 checksum is equal to that saved by the
+ compressor and returns Z_STREAM_END only if the checksum is correct.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect
+ adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+ (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+ enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+ case, the application may then call inflateSync to look for a good
+ compression block.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match). Filtered data consists mostly of small values with a
+ somewhat random distribution. In this case, the compression algorithm is
+ tuned to compress them better. The effect of Z_FILTERED is to force more
+ Huffman coding and less string matching; it is somewhat intermediate
+ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+ the compression ratio but not the correctness of the compressed output even
+ if it is not set appropriately.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front.
+
+ Upon return of this function, strm->adler is set to the Adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The Adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.)
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. If a compressed stream with a larger window size is given as
+ input, inflate() will return with the error code Z_DATA_ERROR instead of
+ trying to allocate a larger window.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+ memLevel). msg is set to null if there is no error message. inflateInit2
+ does not perform any decompression apart from reading the zlib header if
+ present: this will be done by inflate(). (So next_in and avail_in may be
+ modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate
+ if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the Adler32 value returned by this call of
+ inflate. The compressor and decompressor must use exactly the same
+ dictionary (see deflateSetDictionary).
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect Adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h". (See the description
+ of deflateInit2 for more information about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ const voidp buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int err));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/linux/include/zlib/zutil.h b/linux/include/zlib/zutil.h
new file mode 100644
index 000000000..6214815c6
--- /dev/null
+++ b/linux/include/zlib/zutil.h
@@ -0,0 +1,225 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h,v 1.1 2004/03/15 20:35:25 as Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#include <linux/string.h>
+#define HAVE_MEMCPY
+
+#if 0 // #ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifndef __KERNEL__
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#ifdef MSDOS
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+# define OS_CODE 0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0F
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# define fdopen(fd,type) _fdopen(fd,type)
+#endif
+
+
+ /* Common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#ifdef HAVE_STRERROR
+ extern char *strerror OF((int));
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+ uInt len));
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
diff --git a/linux/lib/libfreeswan/Makefile.objs b/linux/lib/libfreeswan/Makefile.objs
new file mode 100644
index 000000000..41a89dba9
--- /dev/null
+++ b/linux/lib/libfreeswan/Makefile.objs
@@ -0,0 +1,18 @@
+obj-y += ultoa.o
+obj-y += addrtoa.o
+obj-y += subnettoa.o
+obj-y += subnetof.o
+obj-y += goodmask.o
+obj-y += datatot.o
+obj-y += rangetoa.o
+obj-y += satoa.o
+obj-y += prng.o
+obj-y += pfkey_v2_parse.o
+obj-y += pfkey_v2_build.o
+obj-y += pfkey_v2_debug.o
+obj-y += pfkey_v2_ext_bits.o
+obj-y += version.o
+
+
+version.c: ${LIBFREESWANDIR}/version.in.c ${FREESWANSRCDIR}/Makefile.ver
+ sed '/"/s/xxx/$(IPSECVERSION)/' ${LIBFREESWANDIR}/version.in.c >$@
diff --git a/linux/lib/libfreeswan/addrtoa.c b/linux/lib/libfreeswan/addrtoa.c
new file mode 100644
index 000000000..b1cc038ed
--- /dev/null
+++ b/linux/lib/libfreeswan/addrtoa.c
@@ -0,0 +1,68 @@
+/*
+ * addresses to ASCII
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: addrtoa.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#define NBYTES 4 /* bytes in an address */
+#define PERBYTE 4 /* three digits plus a dot or NUL */
+#define BUFLEN (NBYTES*PERBYTE)
+
+#if BUFLEN != ADDRTOA_BUF
+#error "ADDRTOA_BUF in freeswan.h inconsistent with addrtoa() code"
+#endif
+
+/*
+ - addrtoa - convert binary address to ASCII dotted decimal
+ */
+size_t /* space needed for full conversion */
+addrtoa(addr, format, dst, dstlen)
+struct in_addr addr;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ unsigned long a = ntohl(addr.s_addr);
+ int i;
+ size_t n;
+ unsigned long byte;
+ char buf[BUFLEN];
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ p = buf;
+ for (i = NBYTES-1; i >= 0; i--) {
+ byte = (a >> (i*8)) & 0xff;
+ p += ultoa(byte, 10, p, PERBYTE);
+ if (i != 0)
+ *(p-1) = '.';
+ }
+ n = p - buf;
+
+ if (dstlen > 0) {
+ if (n > dstlen)
+ buf[dstlen - 1] = '\0';
+ strcpy(dst, buf);
+ }
+ return n;
+}
diff --git a/linux/lib/libfreeswan/addrtot.c b/linux/lib/libfreeswan/addrtot.c
new file mode 100644
index 000000000..f229789f0
--- /dev/null
+++ b/linux/lib/libfreeswan/addrtot.c
@@ -0,0 +1,302 @@
+/*
+ * addresses to text
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: addrtot.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#define IP4BYTES 4 /* bytes in an IPv4 address */
+#define PERBYTE 4 /* three digits plus a dot or NUL */
+#define IP6BYTES 16 /* bytes in an IPv6 address */
+
+/* forwards */
+static size_t normal4(const unsigned char *s, size_t len, char *b, char **dp);
+static size_t normal6(const unsigned char *s, size_t len, char *b, char **dp, int squish);
+static size_t reverse4(const unsigned char *s, size_t len, char *b, char **dp);
+static size_t reverse6(const unsigned char *s, size_t len, char *b, char **dp);
+
+/*
+ - addrtot - convert binary address to text (dotted decimal or IPv6 string)
+ */
+size_t /* space needed for full conversion */
+addrtot(src, format, dst, dstlen)
+const ip_address *src;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ const unsigned char *b;
+ size_t n;
+ char buf[1+ADDRTOT_BUF+1]; /* :address: */
+ char *p;
+ int t = addrtypeof(src);
+# define TF(t, f) (((t)<<8) | (f))
+
+ n = addrbytesptr(src, &b);
+ if (n == 0)
+ return 0;
+
+ switch (TF(t, format)) {
+ case TF(AF_INET, 0):
+ n = normal4(b, n, buf, &p);
+ break;
+ case TF(AF_INET6, 0):
+ n = normal6(b, n, buf, &p, 1);
+ break;
+ case TF(AF_INET, 'Q'):
+ n = normal4(b, n, buf, &p);
+ break;
+ case TF(AF_INET6, 'Q'):
+ n = normal6(b, n, buf, &p, 0);
+ break;
+ case TF(AF_INET, 'r'):
+ n = reverse4(b, n, buf, &p);
+ break;
+ case TF(AF_INET6, 'r'):
+ n = reverse6(b, n, buf, &p);
+ break;
+ default: /* including (AF_INET, 'R') */
+ return 0;
+ break;
+ }
+
+ if (dstlen > 0) {
+ if (dstlen < n)
+ p[dstlen - 1] = '\0';
+ strcpy(dst, p);
+ }
+ return n;
+}
+
+/*
+ - normal4 - normal IPv4 address-text conversion
+ */
+static size_t /* size of text, including NUL */
+normal4(srcp, srclen, buf, dstp)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough */
+char **dstp; /* where to put result pointer */
+{
+ int i;
+ char *p;
+
+ if (srclen != IP4BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ for (i = 0; i < IP4BYTES; i++) {
+ p += ultot(srcp[i], 10, p, PERBYTE);
+ if (i != IP4BYTES - 1)
+ *(p-1) = '.'; /* overwrites the NUL */
+ }
+ *dstp = buf;
+ return p - buf;
+}
+
+/*
+ - normal6 - normal IPv6 address-text conversion
+ */
+static size_t /* size of text, including NUL */
+normal6(srcp, srclen, buf, dstp, squish)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough, plus 2 */
+char **dstp; /* where to put result pointer */
+int squish; /* whether to squish out 0:0 */
+{
+ int i;
+ unsigned long piece;
+ char *p;
+ char *q;
+
+ if (srclen != IP6BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ *p++ = ':';
+ for (i = 0; i < IP6BYTES/2; i++) {
+ piece = (srcp[2*i] << 8) + srcp[2*i + 1];
+ p += ultot(piece, 16, p, 5); /* 5 = abcd + NUL */
+ *(p-1) = ':'; /* overwrites the NUL */
+ }
+ *p = '\0';
+ q = strstr(buf, ":0:0:");
+ if (squish && q != NULL) { /* zero squishing is possible */
+ p = q + 1;
+ while (*p == '0' && *(p+1) == ':')
+ p += 2;
+ q++;
+ *q++ = ':'; /* overwrite first 0 */
+ while (*p != '\0')
+ *q++ = *p++;
+ *q = '\0';
+ if (!(*(q-1) == ':' && *(q-2) == ':'))
+ *--q = '\0'; /* strip final : unless :: */
+ p = buf;
+ if (!(*p == ':' && *(p+1) == ':'))
+ p++; /* skip initial : unless :: */
+ } else {
+ q = p;
+ *--q = '\0'; /* strip final : */
+ p = buf + 1; /* skip initial : */
+ }
+ *dstp = p;
+ return q - p + 1;
+}
+
+/*
+ - reverse4 - IPv4 reverse-lookup conversion
+ */
+static size_t /* size of text, including NUL */
+reverse4(srcp, srclen, buf, dstp)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough */
+char **dstp; /* where to put result pointer */
+{
+ int i;
+ char *p;
+
+ if (srclen != IP4BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ for (i = IP4BYTES-1; i >= 0; i--) {
+ p += ultot(srcp[i], 10, p, PERBYTE);
+ *(p-1) = '.'; /* overwrites the NUL */
+ }
+ strcpy(p, "IN-ADDR.ARPA.");
+ *dstp = buf;
+ return strlen(buf) + 1;
+}
+
+/*
+ - reverse6 - IPv6 reverse-lookup conversion (RFC 1886)
+ * A trifle inefficient, really shouldn't use ultot...
+ */
+static size_t /* size of text, including NUL */
+reverse6(srcp, srclen, buf, dstp)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough */
+char **dstp; /* where to put result pointer */
+{
+ int i;
+ unsigned long piece;
+ char *p;
+
+ if (srclen != IP6BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ for (i = IP6BYTES-1; i >= 0; i--) {
+ piece = srcp[i];
+ p += ultot(piece&0xf, 16, p, 2);
+ *(p-1) = '.';
+ p += ultot(piece>>4, 16, p, 2);
+ *(p-1) = '.';
+ }
+ strcpy(p, "IP6.ARPA.");
+ *dstp = buf;
+ return strlen(buf) + 1;
+}
+
+/*
+ - reverse6 - modern IPv6 reverse-lookup conversion (RFC 2874)
+ * this version removed as it was obsoleted in the end.
+ */
+
+#ifdef ADDRTOT_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n",
+ argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char format;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"1.2.3.0", 0, "1.2.3.0"},
+ {"1:2::3:4", 0, "1:2::3:4"},
+ {"1:2::3:4", 'Q', "1:2:0:0:0:0:3:4"},
+ {"1:2:0:0:3:4:0:0", 0, "1:2::3:4:0:0"},
+ {"1.2.3.4", 'r' , "4.3.2.1.IN-ADDR.ARPA."},
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ {"1:2::3:4", 'r', "4.0.0.0.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.1.0.0.0.IP6.ARPA."},
+ {NULL, 0, NULL}
+};
+
+void
+regress()
+{
+ struct rtab *r;
+ int status = 0;
+ ip_address a;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+
+ /* convert it *to* internal format */
+ oops = ttoaddr(in, strlen(in), 0, &a);
+
+ /* now convert it back */
+
+ n = addrtot(&a, r->format, buf, sizeof(buf));
+
+ if (n == 0 && r->output == NULL)
+ {} /* okay, error expected */
+
+ else if (n == 0) {
+ printf("`%s' atoasr failed\n", r->input);
+ status = 1;
+
+ } else if (r->output == NULL) {
+ printf("`%s' atoasr succeeded unexpectedly '%c'\n",
+ r->input, r->format);
+ status = 1;
+ } else {
+ if (strcasecmp(r->output, buf) != 0) {
+ printf("`%s' '%c' gave `%s', expected `%s'\n",
+ r->input, r->format, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ADDRTOT_MAIN */
diff --git a/linux/lib/libfreeswan/addrtypeof.c b/linux/lib/libfreeswan/addrtypeof.c
new file mode 100644
index 000000000..e63509911
--- /dev/null
+++ b/linux/lib/libfreeswan/addrtypeof.c
@@ -0,0 +1,94 @@
+/*
+ * extract parts of an ip_address
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: addrtypeof.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - addrtypeof - get the type of an ip_address
+ */
+int
+addrtypeof(src)
+const ip_address *src;
+{
+ return src->u.v4.sin_family;
+}
+
+/*
+ - addrbytesptr - get pointer to the address bytes of an ip_address
+ */
+size_t /* 0 for error */
+addrbytesptr(src, dstp)
+const ip_address *src;
+const unsigned char **dstp; /* NULL means just a size query */
+{
+ const unsigned char *p;
+ size_t n;
+
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ p = (const unsigned char *)&src->u.v4.sin_addr.s_addr;
+ n = 4;
+ break;
+ case AF_INET6:
+ p = (const unsigned char *)&src->u.v6.sin6_addr;
+ n = 16;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ if (dstp != NULL)
+ *dstp = p;
+ return n;
+}
+
+/*
+ - addrlenof - get length of the address bytes of an ip_address
+ */
+size_t /* 0 for error */
+addrlenof(src)
+const ip_address *src;
+{
+ return addrbytesptr(src, NULL);
+}
+
+/*
+ - addrbytesof - get the address bytes of an ip_address
+ */
+size_t /* 0 for error */
+addrbytesof(src, dst, dstlen)
+const ip_address *src;
+unsigned char *dst;
+size_t dstlen;
+{
+ const unsigned char *p;
+ size_t n;
+ size_t ncopy;
+
+ n = addrbytesptr(src, &p);
+ if (n == 0)
+ return 0;
+
+ if (dstlen > 0) {
+ ncopy = n;
+ if (ncopy > dstlen)
+ ncopy = dstlen;
+ memcpy(dst, p, ncopy);
+ }
+ return n;
+}
diff --git a/linux/lib/libfreeswan/anyaddr.3 b/linux/lib/libfreeswan/anyaddr.3
new file mode 100644
index 000000000..4594a9ff9
--- /dev/null
+++ b/linux/lib/libfreeswan/anyaddr.3
@@ -0,0 +1,87 @@
+.TH IPSEC_ANYADDR 3 "8 Sept 2000"
+.\" RCSID $Id: anyaddr.3,v 1.1 2004/03/15 20:35:25 as Exp $
+.SH NAME
+ipsec anyaddr \- get "any" address
+.br
+ipsec isanyaddr \- test address for equality to "any" address
+.br
+ipsec unspecaddr \- get "unspecified" address
+.br
+ipsec isunspecaddr \- test address for equality to "unspecified" address
+.br
+ipsec loopbackaddr \- get loopback address
+.br
+ipsec isloopbackaddr \- test address for equality to loopback address
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *anyaddr(int af, ip_address *dst);"
+.br
+.B "int isanyaddr(const ip_address *src);"
+.br
+.B "const char *unspecaddr(int af, ip_address *dst);"
+.br
+.B "int isunspecaddr(const ip_address *src);"
+.br
+.B "const char *loopbackaddr(int af, ip_address *dst);"
+.br
+.B "int isloopbackaddr(const ip_address *src);"
+.SH DESCRIPTION
+These functions fill in, and test for, special values of the
+.I ip_address
+type.
+.PP
+.I Anyaddr
+fills in the destination
+.I *dst
+with the ``any'' address of address family
+.IR af
+(normally
+.B AF_INET
+or
+.BR AF_INET6 ).
+The IPv4 ``any'' address is the one embodied in the old
+.B INADDR_ANY
+macro.
+.PP
+.I Isanyaddr
+returns
+.B 1
+if the
+.I src
+address equals the ``any'' address,
+and
+.B 0
+otherwise.
+.PP
+Similarly,
+.I unspecaddr
+supplies, and
+.I isunspecaddr
+tests for,
+the ``unspecified'' address,
+which may be the same as the ``any'' address.
+.PP
+Similarly,
+.I loopbackaddr
+supplies, and
+.I islookbackaddr
+tests for,
+the loopback address.
+.PP
+.IR Anyaddr ,
+.IR unspecaddr ,
+and
+.I loopbackaddr
+return
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.SH SEE ALSO
+inet(3), ipsec_addrtot(3), ipsec_sameaddr(3)
+.SH DIAGNOSTICS
+Fatal errors in the address-supplying functions are:
+unknown address family.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/anyaddr.c b/linux/lib/libfreeswan/anyaddr.c
new file mode 100644
index 000000000..08aae6334
--- /dev/null
+++ b/linux/lib/libfreeswan/anyaddr.c
@@ -0,0 +1,146 @@
+/*
+ * special addresses
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: anyaddr.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/* these are mostly fallbacks for the no-IPv6-support-in-library case */
+#ifndef IN6ADDR_ANY_INIT
+#define IN6ADDR_ANY_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#define IN6ADDR_LOOPBACK_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}
+#endif
+
+static struct in6_addr v6any = IN6ADDR_ANY_INIT;
+static struct in6_addr v6loop = IN6ADDR_LOOPBACK_INIT;
+
+/*
+ - anyaddr - initialize to the any-address value
+ */
+err_t /* NULL for success, else string literal */
+anyaddr(af, dst)
+int af; /* address family */
+ip_address *dst;
+{
+ uint32_t v4any = htonl(INADDR_ANY);
+
+ switch (af) {
+ case AF_INET:
+ return initaddr((unsigned char *)&v4any, sizeof(v4any), af, dst);
+ break;
+ case AF_INET6:
+ return initaddr((unsigned char *)&v6any, sizeof(v6any), af, dst);
+ break;
+ default:
+ return "unknown address family in anyaddr/unspecaddr";
+ break;
+ }
+}
+
+/*
+ - unspecaddr - initialize to the unspecified-address value
+ */
+err_t /* NULL for success, else string literal */
+unspecaddr(af, dst)
+int af; /* address family */
+ip_address *dst;
+{
+ return anyaddr(af, dst);
+}
+
+/*
+ - loopbackaddr - initialize to the loopback-address value
+ */
+err_t /* NULL for success, else string literal */
+loopbackaddr(af, dst)
+int af; /* address family */
+ip_address *dst;
+{
+ uint32_t v4loop = htonl(INADDR_LOOPBACK);
+
+ switch (af) {
+ case AF_INET:
+ return initaddr((unsigned char *)&v4loop, sizeof(v4loop), af, dst);
+ break;
+ case AF_INET6:
+ return initaddr((unsigned char *)&v6loop, sizeof(v6loop), af, dst);
+ break;
+ default:
+ return "unknown address family in loopbackaddr";
+ break;
+ }
+}
+
+/*
+ - isanyaddr - test for the any-address value
+ */
+int
+isanyaddr(src)
+const ip_address *src;
+{
+ uint32_t v4any = htonl(INADDR_ANY);
+ int cmp;
+
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4any, sizeof(v4any));
+ break;
+ case AF_INET6:
+ cmp = memcmp(&src->u.v6.sin6_addr, &v6any, sizeof(v6any));
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return (cmp == 0) ? 1 : 0;
+}
+
+/*
+ - isunspecaddr - test for the unspecified-address value
+ */
+int
+isunspecaddr(src)
+const ip_address *src;
+{
+ return isanyaddr(src);
+}
+
+/*
+ - isloopbackaddr - test for the loopback-address value
+ */
+int
+isloopbackaddr(src)
+const ip_address *src;
+{
+ uint32_t v4loop = htonl(INADDR_LOOPBACK);
+ int cmp;
+
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4loop, sizeof(v4loop));
+ break;
+ case AF_INET6:
+ cmp = memcmp(&src->u.v6.sin6_addr, &v6loop, sizeof(v6loop));
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return (cmp == 0) ? 1 : 0;
+}
diff --git a/linux/lib/libfreeswan/atoaddr.3 b/linux/lib/libfreeswan/atoaddr.3
new file mode 100644
index 000000000..a7dc8dca3
--- /dev/null
+++ b/linux/lib/libfreeswan/atoaddr.3
@@ -0,0 +1,294 @@
+.TH IPSEC_ATOADDR 3 "11 June 2001"
+.\" RCSID $Id: atoaddr.3,v 1.1 2004/03/15 20:35:25 as Exp $
+.SH NAME
+ipsec atoaddr, addrtoa \- convert Internet addresses to and from ASCII
+.br
+ipsec atosubnet, subnettoa \- convert subnet/mask ASCII form to and from addresses
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atoaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "struct in_addr *addr);"
+.br
+.B "size_t addrtoa(struct in_addr addr, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "const char *atosubnet(const char *src, size_t srclen,"
+.ti +1c
+.B "struct in_addr *addr, struct in_addr *mask);"
+.br
+.B "size_t subnettoa(struct in_addr addr, struct in_addr mask,"
+.ti +1c
+.B "int format, char *dst, size_t dstlen);"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttoaddr (3)
+for their replacements.
+.PP
+.I Atoaddr
+converts an ASCII name or dotted-decimal address into a binary address
+(in network byte order).
+.I Addrtoa
+does the reverse conversion, back to an ASCII dotted-decimal address.
+.I Atosubnet
+and
+.I subnettoa
+do likewise for the ``address/mask'' ASCII form used to write a
+specification of a subnet.
+.PP
+An address is specified in ASCII as a
+dotted-decimal address (e.g.
+.BR 1.2.3.4 ),
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+.BR 0x01020304 ,
+which is synonymous with
+.BR 1.2.3.4 ),
+an eight-digit host-order hexadecimal number with a
+.B 0h
+prefix (e.g.
+.BR 0h01020304 ,
+which is synonymous with
+.B 1.2.3.4
+on a big-endian host and
+.B 4.3.2.1
+on a little-endian host),
+a DNS name to be looked up via
+.IR gethostbyname (3),
+or an old-style network name to be looked up via
+.IR getnetbyname (3).
+.PP
+A dotted-decimal address may be incomplete, in which case
+ASCII-to-binary conversion implicitly appends
+as many instances of
+.B .0
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+.B 10
+is synonymous with
+.BR 10.0.0.0 ,
+and
+.B 128.009.000.032
+is synonymous with
+.BR 128.9.0.32
+(the latter example is verbatim from RFC 1166).
+The result of
+.I addrtoa
+is always complete and does not contain leading zeros.
+.PP
+The letters in
+a hexadecimal address may be uppercase or lowercase or any mixture thereof.
+Use of hexadecimal addresses is
+.B strongly
+.BR discouraged ;
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+.PP
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+.IR resolver (5)).
+The
+.I h_addr
+value returned by
+.IR gethostbyname (3)
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+Name lookup resorts to
+.IR getnetbyname (3)
+only if
+.IR gethostbyname (3)
+fails.
+.PP
+A subnet specification is of the form \fInetwork\fB/\fImask\fR.
+The
+.I network
+and
+.I mask
+can be any form acceptable to
+.IR atoaddr .
+In addition, the
+.I mask
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+.B 24
+means
+.BR 255.255.255.0 ).
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+.B %default
+is a synonym for
+.BR 0.0.0.0/0 .
+.PP
+.I Atosubnet
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+.B 10.1.2.3/24
+is synonymous with
+.BR 10.1.2.0/24 ).
+.I Subnettoa
+generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros,
+unless the mask is non-contiguous.
+.PP
+The
+.I srclen
+parameter of
+.I atoaddr
+and
+.I atosubnet
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I addrtoa
+and
+.I subnettoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines constants,
+.B ADDRTOA_BUF
+and
+.BR SUBNETTOA_BUF ,
+which are the sizes of buffers just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I addrtoa
+and
+.I subnettoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+.PP
+The ASCII-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-ASCII functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atoaddr
+are:
+empty input;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal form;
+dotted-decimal component too large to fit in 8 bits.
+.PP
+Fatal errors in
+.I atosubnet
+are:
+no
+.B /
+in
+.IR src ;
+.I atoaddr
+error in conversion of
+.I network
+or
+.IR mask ;
+bit-count mask too big;
+mask non-contiguous.
+.PP
+Fatal errors in
+.I addrtoa
+and
+.I subnettoa
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+.B 10/24
+means
+.BR 10.0.0.0/24 )
+differs from that of some older conversion
+functions, e.g. those of
+.IR inet (3).
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+.PP
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+.PP
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+.PP
+.IR Getnetbyname (3)
+is a historical dreg.
+.PP
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/atoaddr.c b/linux/lib/libfreeswan/atoaddr.c
new file mode 100644
index 000000000..0c787b10d
--- /dev/null
+++ b/linux/lib/libfreeswan/atoaddr.c
@@ -0,0 +1,238 @@
+/*
+ * conversion from ASCII forms of addresses to internal ones
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atoaddr.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ * Define NOLEADINGZEROS to interpret 032 as an error, not as 32. There
+ * is deliberately no way to interpret it as 26 (i.e., as octal).
+ */
+
+/*
+ * Legal characters in a domain name. Underscore technically is not,
+ * but is a common misunderstanding.
+ */
+static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
+
+static const char *try8hex(const char *, size_t, struct in_addr *);
+static const char *try8hosthex(const char *, size_t, struct in_addr *);
+static const char *trydotted(const char *, size_t, struct in_addr *);
+static const char *getbyte(const char **, const char *, int *);
+
+/*
+ - atoaddr - convert ASCII name or dotted-decimal address to binary address
+ */
+const char * /* NULL for success, else string literal */
+atoaddr(src, srclen, addrp)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct in_addr *addrp;
+{
+ struct hostent *h;
+ struct netent *ne = NULL;
+ const char *oops;
+# define HEXLEN 10 /* strlen("0x11223344") */
+# ifndef ATOADDRBUF
+# define ATOADDRBUF 100
+# endif
+ char namebuf[ATOADDRBUF];
+ char *p = namebuf;
+ char *q;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ /* might it be hex? */
+ if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'x'))
+ return try8hex(src+2, srclen-2, addrp);
+ if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'h'))
+ return try8hosthex(src+2, srclen-2, addrp);
+
+ /* try it as dotted decimal */
+ oops = trydotted(src, srclen, addrp);
+ if (oops == NULL)
+ return NULL; /* it worked */
+ if (*oops != '?')
+ return oops; /* it *was* probably meant as a d.q. */
+
+ /* try it as a name -- first, NUL-terminate it */
+ if (srclen > sizeof(namebuf)-1) {
+ p = (char *) MALLOC(srclen+1);
+ if (p == NULL)
+ return "unable to allocate temporary space for name";
+ }
+ p[0] = '\0';
+ strncat(p, src, srclen);
+
+ /* next, check that it's a vaguely legal name */
+ for (q = p; *q != '\0'; q++)
+ if (!isprint(*q))
+ return "unprintable character in name";
+ if (strspn(p, namechars) != srclen)
+ return "illegal (non-DNS-name) character in name";
+
+ /* try as host name, failing that as /etc/networks network name */
+ h = gethostbyname(p);
+ if (h == NULL)
+ ne = getnetbyname(p);
+ if (p != namebuf)
+ FREE(p);
+ if (h == NULL && ne == NULL)
+ return "name lookup failed";
+
+ if (h != NULL)
+ memcpy(&addrp->s_addr, h->h_addr, sizeof(addrp->s_addr));
+ else
+ addrp->s_addr = htonl(ne->n_net);
+ return NULL;
+}
+
+/*
+ - try8hosthex - try conversion as an eight-digit host-order hex number
+ */
+const char * /* NULL for success, else string literal */
+try8hosthex(src, srclen, addrp)
+const char *src;
+size_t srclen; /* should be 8 */
+struct in_addr *addrp;
+{
+ const char *oops;
+ unsigned long addr;
+
+ if (srclen != 8)
+ return "internal error, try8hex called with bad length";
+
+ oops = atoul(src, srclen, 16, &addr);
+ if (oops != NULL)
+ return oops;
+
+ addrp->s_addr = addr;
+ return NULL;
+}
+
+/*
+ - try8hex - try conversion as an eight-digit network-order hex number
+ */
+const char * /* NULL for success, else string literal */
+try8hex(src, srclen, addrp)
+const char *src;
+size_t srclen; /* should be 8 */
+struct in_addr *addrp;
+{
+ const char *oops;
+
+ oops = try8hosthex(src, srclen, addrp);
+ if (oops != NULL)
+ return oops;
+
+ addrp->s_addr = htonl(addrp->s_addr);
+ return NULL;
+}
+
+/*
+ - trydotted - try conversion as dotted decimal
+ *
+ * If the first char of a complaint is '?', that means "didn't look like
+ * dotted decimal at all".
+ */
+const char * /* NULL for success, else string literal */
+trydotted(src, srclen, addrp)
+const char *src;
+size_t srclen;
+struct in_addr *addrp;
+{
+ const char *stop = src + srclen; /* just past end */
+ int byte;
+ const char *oops;
+ unsigned long addr;
+ int i;
+# define NBYTES 4
+# define BYTE 8
+
+ addr = 0;
+ for (i = 0; i < NBYTES && src < stop; i++) {
+ oops = getbyte(&src, stop, &byte);
+ if (oops != NULL) {
+ if (*oops != '?')
+ return oops; /* bad number */
+ if (i > 1)
+ return oops+1; /* failed number */
+ return oops; /* with leading '?' */
+ }
+ addr = (addr << BYTE) | byte;
+ if (i < 3 && src < stop && *src++ != '.') {
+ if (i == 0)
+ return "?syntax error in dotted-decimal address";
+ else
+ return "syntax error in dotted-decimal address";
+ }
+ }
+ addr <<= (NBYTES - i) * BYTE;
+ if (src != stop)
+ return "extra garbage on end of dotted-decimal address";
+
+ addrp->s_addr = htonl(addr);
+ return NULL;
+}
+
+/*
+ - getbyte - try to scan a byte in dotted decimal
+ * A subtlety here is that all this arithmetic on ASCII digits really is
+ * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
+ * It's easier to just do it ourselves than set up for a call to atoul().
+ *
+ * If the first char of a complaint is '?', that means "didn't look like a
+ * number at all".
+ */
+const char * /* NULL for success, else string literal */
+getbyte(srcp, stop, retp)
+const char **srcp; /* *srcp is updated */
+const char *stop; /* first untouchable char */
+int *retp; /* return-value pointer */
+{
+ char c;
+ const char *p;
+ int no;
+
+ if (*srcp >= stop)
+ return "?empty number in dotted-decimal address";
+
+ if (stop - *srcp >= 3 && **srcp == '0' && CIEQ(*(*srcp+1), 'x'))
+ return "hex numbers not supported in dotted-decimal addresses";
+#ifdef NOLEADINGZEROS
+ if (stop - *srcp >= 2 && **srcp == '0' && isdigit(*(*srcp+1)))
+ return "octal numbers not supported in dotted-decimal addresses";
+#endif /* NOLEADINGZEROS */
+
+ /* must be decimal, if it's numeric at all */
+ no = 0;
+ p = *srcp;
+ while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
+ no = no*10 + (c - '0');
+ p++;
+ }
+ if (p == *srcp)
+ return "?non-numeric component in dotted-decimal address";
+ *srcp = p;
+ if (no > 255)
+ return "byte overflow in dotted-decimal address";
+ *retp = no;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/atoasr.3 b/linux/lib/libfreeswan/atoasr.3
new file mode 100644
index 000000000..1bd805db1
--- /dev/null
+++ b/linux/lib/libfreeswan/atoasr.3
@@ -0,0 +1,186 @@
+.TH IPSEC_ATOASR 3 "11 June 2001"
+.\" RCSID $Id: atoasr.3,v 1.1 2004/03/15 20:35:25 as Exp $
+.SH NAME
+ipsec atoasr \- convert ASCII to Internet address, subnet, or range
+.br
+ipsec rangetoa \- convert Internet address range to ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atoasr(const char *src, size_t srclen,"
+.ti +1c
+.B "char *type, struct in_addr *addrs);"
+.br
+.B "size_t rangetoa(struct in_addr *addrs, int format,
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.SH DESCRIPTION
+These functions are obsolete;
+there is no current equivalent,
+because so far they have not proved useful.
+.PP
+.I Atoasr
+converts an ASCII address, subnet, or address range
+into a suitable combination of binary addresses
+(in network byte order).
+.I Rangetoa
+converts an address range back into ASCII,
+using dotted-decimal form for the addresses
+(the other reverse conversions are handled by
+.IR ipsec_addrtoa (3)
+and
+.IR ipsec_subnettoa (3)).
+.PP
+A single address can be any form acceptable to
+.IR ipsec_atoaddr (3):
+dotted decimal, DNS name, or hexadecimal number.
+A subnet
+specification uses the form \fInetwork\fB/\fImask\fR
+interpreted by
+.IR ipsec_atosubnet (3).
+.PP
+An address range is two
+.IR ipsec_atoaddr (3)
+addresses separated by a
+.B ...
+delimiter.
+If there are four dots rather than three, the first is taken as
+part of the begin address,
+e.g. for a complete DNS name which ends with
+.B .
+to suppress completion attempts.
+The begin address of a range must be
+less than or equal to the end address.
+.PP
+The
+.I srclen
+parameter of
+.I atoasr
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I type
+parameter of
+.I atoasr
+must point to a
+.B char
+variable used to record which form was found.
+The
+.I addrs
+parameter must point to a two-element array of
+.B "struct in_addr"
+which receives the results.
+The values stored into
+.BR *type ,
+and the corresponding values in the array, are:
+.PP
+.ta 3c +2c +3c
+ *type addrs[0] addrs[1]
+.sp 0.8
+address \&\fB'a'\fR address -
+.br
+subnet \&\fB's'\fR network mask
+.br
+range \&\fB'r'\fR begin end
+.PP
+The
+.I dstlen
+parameter of
+.I rangetoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR RANGETOA_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I rangetoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+.PP
+.I Atoasr
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Rangetoa
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+ipsec_atoaddr(3), ipsec_atosubnet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atoasr
+are:
+empty input;
+error in
+.IR ipsec_atoaddr (3)
+or
+.IR ipsec_atosubnet (3)
+during conversion;
+begin address of range exceeds end address.
+.PP
+Fatal errors in
+.I rangetoa
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoasr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/atoasr.c b/linux/lib/libfreeswan/atoasr.c
new file mode 100644
index 000000000..a68409bfb
--- /dev/null
+++ b/linux/lib/libfreeswan/atoasr.c
@@ -0,0 +1,212 @@
+/*
+ * convert from ASCII form of address/subnet/range to binary
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atoasr.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - atoasr - convert ASCII to address, subnet, or range
+ */
+const char * /* NULL for success, else string literal */
+atoasr(src, srclen, typep, addrsp)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+char *typep; /* return type code: 'a', 's', 'r' */
+struct in_addr addrsp[2];
+{
+ const char *punct;
+ const char *stop;
+ const char *oops;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ /* subnet is easy to spot */
+ punct = memchr(src, '/', srclen);
+ if (punct != NULL) {
+ *typep = 's';
+ return atosubnet(src, srclen, &addrsp[0], &addrsp[1]);
+ }
+
+ /* try for a range */
+ stop = src + srclen;
+ for (punct = src; (punct = memchr(punct, '.', stop - punct)) != NULL;
+ punct++)
+ if (stop - punct > 3 && *(punct+1) == '.' && *(punct+2) == '.')
+ break; /* NOTE BREAK OUT */
+ if (punct == NULL) {
+ /* didn't find the range delimiter, must be plain address */
+ *typep = 'a';
+ return atoaddr(src, srclen, &addrsp[0]);
+ }
+
+ /* looks like a range */
+ *typep = 'r';
+ if (stop - punct > 4 && *(punct+3) == '.')
+ punct++; /* first dot is trailing dot of name */
+ oops = atoaddr(src, punct - src, &addrsp[0]);
+ if (oops != NULL)
+ return oops;
+ oops = atoaddr(punct+3, stop - (punct+3), &addrsp[1]);
+ if (oops != NULL)
+ return oops;
+ if (ntohl(addrsp[0].s_addr) > ntohl(addrsp[1].s_addr))
+ return "invalid range, begin > end";
+ return NULL;
+}
+
+
+
+#ifdef ATOASR_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct in_addr a[2];
+ char buf[100];
+ const char *oops;
+ size_t n;
+ char type;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n",
+ argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atoasr(argv[1], 0, &type, a);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ switch (type) {
+ case 'a':
+ n = addrtoa(a[0], 0, buf, sizeof(buf));
+ break;
+ case 's':
+ n = subnettoa(a[0], a[1], 0, buf, sizeof(buf));
+ break;
+ case 'r':
+ n = rangetoa(a, 0, buf, sizeof(buf));
+ break;
+ default:
+ fprintf(stderr, "%s: unknown type '%c'\n", argv[0], type);
+ exit(1);
+ break;
+ }
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion of ", argv[0]);
+ fprintf(stderr, "%s ", inet_ntoa(a[0]));
+ fprintf(stderr, "%s", inet_ntoa(a[1]));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"1.2.3.0", "1.2.3.0"},
+ {"1.2.3.0/255.255.255.0", "1.2.3.0/24"},
+ {"1.2.3.0...1.2.3.5", "1.2.3.0...1.2.3.5"},
+ {"1.2.3.4.5", NULL},
+ {"1.2.3.4/", NULL},
+ {"1.2.3.4...", NULL},
+ {"1.2.3.4....", NULL},
+ {"localhost/32", "127.0.0.1/32"},
+ {"localhost...127.0.0.3", "127.0.0.1...127.0.0.3"},
+ {"127.0.0.0...localhost", "127.0.0.0...127.0.0.1"},
+ {"127.0.0.3...localhost", NULL},
+ {NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ struct in_addr a[2];
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+ char type;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atoasr(in, 0, &type, a);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atoasr failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atoasr succeeded unexpectedly '%c'\n",
+ r->input, type);
+ status = 1;
+ } else {
+ switch (type) {
+ case 'a':
+ n = addrtoa(a[0], 0, buf, sizeof(buf));
+ break;
+ case 's':
+ n = subnettoa(a[0], a[1], 0, buf, sizeof(buf));
+ break;
+ case 'r':
+ n = rangetoa(a, 0, buf, sizeof(buf));
+ break;
+ default:
+ fprintf(stderr, "`%s' unknown type '%c'\n",
+ r->input, type);
+ n = 0;
+ status = 1;
+ break;
+ }
+ if (n > sizeof(buf)) {
+ printf("`%s' '%c' reverse failed: need %ld\n",
+ r->input, type, (long)n);
+ status = 1;
+ } else if (n > 0 && strcmp(r->output, buf) != 0) {
+ printf("`%s' '%c' gave `%s', expected `%s'\n",
+ r->input, type, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOASR_MAIN */
diff --git a/linux/lib/libfreeswan/atosa.3 b/linux/lib/libfreeswan/atosa.3
new file mode 100644
index 000000000..116483a73
--- /dev/null
+++ b/linux/lib/libfreeswan/atosa.3
@@ -0,0 +1,218 @@
+.TH IPSEC_ATOSA 3 "11 June 2001"
+.\" RCSID $Id: atosa.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec atosa, satoa \- convert IPsec Security Association IDs to and from ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atosa(const char *src, size_t srclen,"
+.ti +1c
+.B "struct sa_id *sa);
+.br
+.B "size_t satoa(struct sa_id sa, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "struct sa_id {"
+.ti +1c
+.B "struct in_addr dst;"
+.ti +1c
+.B "ipsec_spi_t spi;"
+.ti +1c
+.B "int proto;"
+.br
+.B "};"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttosa (3)
+for their replacements.
+.PP
+.I Atosa
+converts an ASCII Security Association (SA) specifier into an
+.B sa_id
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+.I Satoa
+does the reverse conversion, back to an ASCII SA specifier.
+.PP
+An SA is specified in ASCII with a mail-like syntax, e.g.
+.BR esp507@1.2.3.4 .
+An SA specifier contains
+a protocol prefix (currently
+.BR ah ,
+.BR esp ,
+or
+.BR tun ),
+an unsigned integer SPI number,
+and an IP address.
+The SPI number can be decimal or hexadecimal
+(with
+.B 0x
+prefix), as accepted by
+.IR ipsec_atoul (3).
+The IP address can be any form accepted by
+.IR ipsec_atoaddr (3),
+e.g. dotted-decimal address or DNS name.
+.PP
+As a special case, the SA specifier
+.B %passthrough
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, this is a synonym for
+.BR tun0x0@0.0.0.0 ,
+but that is subject to change without notice.)
+This form is known to both
+.I atosa
+and
+.IR satoa ,
+so the internal form of
+.B %passthrough
+is never visible.
+.PP
+The
+.B <freeswan.h>
+header file supplies the
+.B sa_id
+structure, as well as a data type
+.B ipsec_spi_t
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+.PP
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+.B <freeswan.h>
+defines the names
+.BR SA_ESP ,
+.BR SA_AH ,
+and
+.B SA_IPIP
+to have the same values as the kernel names
+.BR IPPROTO_ESP ,
+.BR IPPROTO_AH ,
+and
+.BR IPPROTO_IPIP .
+.PP
+The
+.I srclen
+parameter of
+.I atosa
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I satoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR SATOA_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I satoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI, dotted-decimal address).
+The value
+.B d
+causes the SPI to be generated in decimal instead.
+.PP
+.I Atosa
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Satoa
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+ipsec_atoul(3), ipsec_atoaddr(3), inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atosa
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+.B @
+in input;
+unknown protocol prefix;
+conversion error in
+.I atoul
+or
+.IR atoaddr .
+.PP
+Fatal errors in
+.I satoa
+are:
+unknown format; unknown protocol code.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The
+.B tun
+protocol code is a FreeS/WANism which may eventually disappear.
+.PP
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/atosa.c b/linux/lib/libfreeswan/atosa.c
new file mode 100644
index 000000000..cc3b055d0
--- /dev/null
+++ b/linux/lib/libfreeswan/atosa.c
@@ -0,0 +1,200 @@
+/*
+ * convert from ASCII form of SA ID to binary
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atosa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct satype {
+ char *prefix;
+ size_t prelen; /* strlen(prefix) */
+ int proto;
+} satypes[] = {
+ { "ah", 2, SA_AH },
+ { "esp", 3, SA_ESP },
+ { "tun", 3, SA_IPIP },
+ { "comp", 4, SA_COMP },
+ { NULL, 0, 0, }
+};
+
+/*
+ - atosa - convert ASCII "ah507@10.0.0.1" to SA identifier
+ */
+const char * /* NULL for success, else string literal */
+atosa(src, srclen, sa)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct sa_id *sa;
+{
+ const char *at;
+ const char *addr;
+ const char *spi = NULL;
+ struct satype *sat;
+ unsigned long ul;
+ const char *oops;
+# define MINLEN 5 /* ah0@0 is as short as it can get */
+ static char ptname[] = PASSTHROUGHNAME;
+# define PTNLEN (sizeof(ptname)-1) /* -1 for NUL */
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ if (srclen < MINLEN)
+ return "string too short to be SA specifier";
+ if (srclen == PTNLEN && memcmp(src, ptname, PTNLEN) == 0) {
+ src = PASSTHROUGHIS;
+ srclen = strlen(src);
+ }
+
+ at = memchr(src, '@', srclen);
+ if (at == NULL)
+ return "no @ in SA specifier";
+
+ for (sat = satypes; sat->prefix != NULL; sat++)
+ if (sat->prelen < srclen &&
+ strncmp(src, sat->prefix, sat->prelen) == 0) {
+ sa->proto = sat->proto;
+ spi = src + sat->prelen;
+ break; /* NOTE BREAK OUT */
+ }
+ if (sat->prefix == NULL)
+ return "SA specifier lacks valid protocol prefix";
+
+ if (spi >= at)
+ return "no SPI in SA specifier";
+ oops = atoul(spi, at - spi, 13, &ul);
+ if (oops != NULL)
+ return oops;
+ sa->spi = htonl(ul);
+
+ addr = at + 1;
+ oops = atoaddr(addr, srclen - (addr - src), &sa->dst);
+ if (oops != NULL)
+ return oops;
+
+ return NULL;
+}
+
+
+
+#ifdef ATOSA_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct sa_id sa;
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atosa(argv[1], 0, &sa);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = satoa(sa, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto);
+ fprintf(stderr, "%lu@", (long unsigned int)sa.spi);
+ fprintf(stderr, "%s", inet_ntoa(sa.dst));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"esp257@1.2.3.0", "esp257@1.2.3.0"},
+ {"ah0x20@1.2.3.4", "ah32@1.2.3.4"},
+ {"tun011@111.2.3.99", "tun11@111.2.3.99"},
+ {"", NULL},
+ {"_", NULL},
+ {"ah2.2", NULL},
+ {"goo2@1.2.3.4", NULL},
+ {"esp9@1.2.3.4", "esp9@1.2.3.4"},
+ {"espp9@1.2.3.4", NULL},
+ {"es9@1.2.3.4", NULL},
+ {"ah@1.2.3.4", NULL},
+ {"esp7x7@1.2.3.4", NULL},
+ {"esp77@1.0x2.3.4", NULL},
+ {PASSTHROUGHNAME, PASSTHROUGHNAME},
+ {NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ struct sa_id sa;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atosa(in, 0, &sa);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atosa failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atosa succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = satoa(sa, 'd', buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' satoa failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOSA_MAIN */
diff --git a/linux/lib/libfreeswan/atosubnet.c b/linux/lib/libfreeswan/atosubnet.c
new file mode 100644
index 000000000..9300c2895
--- /dev/null
+++ b/linux/lib/libfreeswan/atosubnet.c
@@ -0,0 +1,216 @@
+/*
+ * convert from ASCII form of subnet specification to binary
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atosubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#ifndef DEFAULTSUBNET
+#define DEFAULTSUBNET "%default"
+#endif
+
+/*
+ - atosubnet - convert ASCII "addr/mask" to address and mask
+ * Mask can be integer bit count.
+ */
+const char * /* NULL for success, else string literal */
+atosubnet(src, srclen, addrp, maskp)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct in_addr *addrp;
+struct in_addr *maskp;
+{
+ const char *slash;
+ const char *mask;
+ size_t mlen;
+ const char *oops;
+ unsigned long bc;
+ static char def[] = DEFAULTSUBNET;
+# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */
+ static char defis[] = "0/0";
+# define DEFILEN (sizeof(defis) - 1)
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) {
+ src = defis;
+ srclen = DEFILEN;
+ }
+
+ slash = memchr(src, '/', srclen);
+ if (slash == NULL)
+ return "no / in subnet specification";
+ mask = slash + 1;
+ mlen = srclen - (mask - src);
+
+ oops = atoaddr(src, slash-src, addrp);
+ if (oops != NULL)
+ return oops;
+
+ oops = atoul(mask, mlen, 10, &bc);
+ if (oops == NULL) {
+ /* atoul succeeded, it's a bit-count mask */
+ if (bc > ABITS)
+ return "bit-count mask too large";
+#ifdef NOLEADINGZEROS
+ if (mlen > 1 && *mask == '0')
+ return "octal not allowed in mask";
+#endif /* NOLEADINGZEROS */
+ *maskp = bitstomask((int)bc);
+ } else {
+ oops = atoaddr(mask, mlen, maskp);
+ if (oops != NULL)
+ return oops;
+ if (!goodmask(*maskp))
+ return "non-contiguous mask";
+ }
+
+ addrp->s_addr &= maskp->s_addr;
+ return NULL;
+}
+
+
+
+#ifdef ATOSUBNET_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct in_addr a;
+ struct in_addr m;
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {addr/mask|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atosubnet(argv[1], 0, &a, &m);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = subnettoa(a, m, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion of ", argv[0]);
+ fprintf(stderr, "%s/", inet_ntoa(a));
+ fprintf(stderr, "%s", inet_ntoa(m));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"1.2.3.0/255.255.255.0", "1.2.3.0/24"},
+ {"1.2.3.0/24", "1.2.3.0/24"},
+ {"1.2.3.1/255.255.255.240", "1.2.3.0/28"},
+ {"1.2.3.1/32", "1.2.3.1/32"},
+ {"1.2.3.1/0", "0.0.0.0/0"},
+/* "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0", */
+ {"1.2.3.1/255.255.127.0", NULL},
+ {"128.009.000.032/32", "128.9.0.32/32"},
+ {"128.0x9.0.32/32", NULL},
+ {"0x80090020/32", "128.9.0.32/32"},
+ {"0x800x0020/32", NULL},
+ {"128.9.0.32/0xffFF0000", "128.9.0.0/16"},
+ {"128.9.0.32/0xff0000FF", NULL},
+ {"128.9.0.32/0x0000ffFF", NULL},
+ {"128.9.0.32/0x00ffFF0000", NULL},
+ {"128.9.0.32/0xffFF", NULL},
+ {"128.9.0.32.27/32", NULL},
+ {"128.9.0k32/32", NULL},
+ {"328.9.0.32/32", NULL},
+ {"128.9..32/32", NULL},
+ {"10/8", "10.0.0.0/8"},
+ {"10.0/8", "10.0.0.0/8"},
+ {"10.0.0/8", "10.0.0.0/8"},
+ {"10.0.1/24", "10.0.1.0/24"},
+ {"_", NULL},
+ {"_/_", NULL},
+ {"1.2.3.1", NULL},
+ {"1.2.3.1/_", NULL},
+ {"1.2.3.1/24._", NULL},
+ {"1.2.3.1/99", NULL},
+ {"localhost/32", "127.0.0.1/32"},
+ {"%default", "0.0.0.0/0"},
+ {NULL, NULL}
+};
+
+void
+regress()
+{
+ struct rtab *r;
+ int status = 0;
+ struct in_addr a;
+ struct in_addr m;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atosubnet(in, 0, &a, &m);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atosubnet failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atosubnet succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = subnettoa(a, m, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' subnettoa failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOSUBNET_MAIN */
diff --git a/linux/lib/libfreeswan/atoul.3 b/linux/lib/libfreeswan/atoul.3
new file mode 100644
index 000000000..a606fa4a9
--- /dev/null
+++ b/linux/lib/libfreeswan/atoul.3
@@ -0,0 +1,161 @@
+.TH IPSEC_ATOUL 3 "11 June 2001"
+.\" RCSID $Id: atoul.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec atoul, ultoa \- convert unsigned-long numbers to and from ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atoul(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, unsigned long *n);"
+.br
+.B "size_t ultoa(unsigned long n, int base, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttoul (3)
+for their replacements.
+.PP
+.I Atoul
+converts an ASCII number into a binary
+.B "unsigned long"
+value.
+.I Ultoa
+does the reverse conversion, back to an ASCII version.
+.PP
+Numbers are specified in ASCII as
+decimal (e.g.
+.BR 123 ),
+octal with a leading zero (e.g.
+.BR 012 ,
+which has value 10),
+or hexadecimal with a leading
+.B 0x
+(e.g.
+.BR 0x1f ,
+which has value 31)
+in either upper or lower case.
+.PP
+The
+.I srclen
+parameter of
+.I atoul
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I base
+parameter of
+.I atoul
+can be
+.BR 8 ,
+.BR 10 ,
+or
+.BR 16 ,
+in which case the number supplied is assumed to be of that form
+(and in the case of
+.BR 16 ,
+to lack any
+.B 0x
+prefix).
+It can also be
+.BR 0 ,
+in which case the number is examined for a leading zero
+or a leading
+.B 0x
+to determine its base,
+or
+.B 13
+(halfway between 10 and 16),
+which has the same effect as
+.B 0
+except that a non-hexadecimal
+number is considered decimal regardless of any leading zero.
+.PP
+The
+.I dstlen
+parameter of
+.I ultoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+.PP
+The
+.I base
+parameter of
+.I ultoa
+must be
+.BR 8 ,
+.BR 10 ,
+or
+.BR 16 .
+.PP
+.I Atoul
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Ultoa
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+atol(3), strtoul(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atoul
+are:
+empty input;
+unknown
+.IR base ;
+non-digit character found;
+number too large for an
+.BR "unsigned long" .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+There is no provision for reporting an invalid
+.I base
+parameter given to
+.IR ultoa .
+.PP
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoul( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/atoul.c b/linux/lib/libfreeswan/atoul.c
new file mode 100644
index 000000000..e32a8cdab
--- /dev/null
+++ b/linux/lib/libfreeswan/atoul.c
@@ -0,0 +1,90 @@
+/*
+ * convert from ASCII form of unsigned long to binary
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atoul.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - atoul - convert ASCII substring to unsigned long number
+ */
+const char * /* NULL for success, else string literal */
+atoul(src, srclen, base, resultp)
+const char *src;
+size_t srclen; /* 0 means strlen(src) */
+int base; /* 0 means figure it out */
+unsigned long *resultp;
+{
+ const char *stop;
+ static char hex[] = "0123456789abcdef";
+ static char uchex[] = "0123456789ABCDEF";
+ int d;
+ char c;
+ char *p;
+ unsigned long r;
+ unsigned long rlimit;
+ int dlimit;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ if (base == 0 || base == 13) {
+ if (srclen > 2 && *src == '0' && CIEQ(*(src+1), 'x'))
+ return atoul(src+2, srclen-2, 16, resultp);
+ if (srclen > 1 && *src == '0' && base != 13)
+ return atoul(src+1, srclen-1, 8, resultp);
+ return atoul(src, srclen, 10, resultp);
+ }
+ if (base != 8 && base != 10 && base != 16)
+ return "unsupported number base";
+
+ r = 0;
+ stop = src + srclen;
+ if (base == 16) {
+ while (src < stop) {
+ c = *src++;
+ p = strchr(hex, c);
+ if (p != NULL)
+ d = p - hex;
+ else {
+ p = strchr(uchex, c);
+ if (p == NULL)
+ return "non-hex-digit in hex number";
+ d = p - uchex;
+ }
+ r = (r << 4) | d;
+ }
+ /* defer length check to catch invalid digits first */
+ if (srclen > sizeof(unsigned long) * 2)
+ return "hex number too long";
+ } else {
+ rlimit = ULONG_MAX / base;
+ dlimit = (int)(ULONG_MAX - rlimit*base);
+ while (src < stop) {
+ c = *src++;
+ d = c - '0';
+ if (d < 0 || d >= base)
+ return "non-digit in number";
+ if (r > rlimit || (r == rlimit && d > dlimit))
+ return "unsigned-long overflow";
+ r = r*base + d;
+ }
+ }
+
+ *resultp = r;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/copyright.c b/linux/lib/libfreeswan/copyright.c
new file mode 100644
index 000000000..0e836f6c2
--- /dev/null
+++ b/linux/lib/libfreeswan/copyright.c
@@ -0,0 +1,56 @@
+/*
+ * return IPsec copyright notice
+ * Copyright (C) 2001, 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: copyright.c,v 1.6 2005/11/02 21:51:13 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static const char *co[] = {
+ "Copyright (C) 1999-2005 Henry Spencer, Richard Guy Briggs,",
+ " D. Hugh Redelmeier, Sandy Harris, Claudia Schmeing,",
+ " Michael Richardson, Angelos D. Keromytis, John Ioannidis,",
+ "",
+ " Ken Bantoft, Stephen J. Bevan, JuanJo Ciarlante, Mathieu Lafon,",
+ " Stephane Laroche, Kai Martius, Tuomo Soini, Herbert Xu,",
+ "",
+ " Andreas Steffen, Martin Berner, Marco Bertossa, David Buechi,",
+ " Ueli Galizzi, Christoph Gysin, Andreas Hess, Patric Lichtsteiner,",
+ " Michael Meier, Andreas Schleiss, Ariane Seiler,",
+ " Mario Strasser, Lukas Suter, Roger Wegmann, Simon Zwahlen,",
+ " Zuercher Hochschule Winterthur (Switzerland).",
+ "",
+ " Jan Hutter, Martin Willi, Andreas Steffen,",
+ " Hochschule fuer Technik Rapperswil (Switzerland).",
+ "",
+ "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 (file COPYING in the distribution) for more details.",
+ NULL
+};
+
+/*
+ - ipsec_copyright_notice - return copyright notice, as a vector of strings
+ */
+const char **
+ipsec_copyright_notice()
+{
+ return co;
+}
diff --git a/linux/lib/libfreeswan/datatot.c b/linux/lib/libfreeswan/datatot.c
new file mode 100644
index 000000000..fbeb35fa9
--- /dev/null
+++ b/linux/lib/libfreeswan/datatot.c
@@ -0,0 +1,233 @@
+/*
+ * convert from binary data (e.g. key) to text form
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: datatot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static void convert(const char *src, size_t nreal, int format, char *out);
+
+/*
+ - datatot - convert data bytes to text
+ */
+size_t /* true length (with NUL) for success */
+datatot(src, srclen, format, dst, dstlen)
+const char *src;
+size_t srclen;
+int format; /* character indicating what format */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t inblocksize; /* process this many bytes at a time */
+ size_t outblocksize; /* producing this many */
+ size_t breakevery; /* add a _ every this many (0 means don't) */
+ size_t sincebreak; /* output bytes since last _ */
+ char breakchar; /* character used to break between groups */
+ char inblock[10]; /* enough for any format */
+ char outblock[10]; /* enough for any format */
+ char fake[1]; /* fake output area for dstlen == 0 */
+ size_t needed; /* return value */
+ char *stop; /* where the terminating NUL will go */
+ size_t ntodo; /* remaining input */
+ size_t nreal;
+ char *out;
+ char *prefix;
+
+ breakevery = 0;
+ breakchar = '_';
+
+ switch (format) {
+ case 0:
+ case 'h':
+ format = 'x';
+ breakevery = 8;
+ /* FALLTHROUGH */
+ case 'x':
+ inblocksize = 1;
+ outblocksize = 2;
+ prefix = "0x";
+ break;
+ case ':':
+ format = 'x';
+ breakevery = 2;
+ breakchar = ':';
+ /* FALLTHROUGH */
+ case 16:
+ inblocksize = 1;
+ outblocksize = 2;
+ prefix = "";
+ format = 'x';
+ break;
+ case 's':
+ inblocksize = 3;
+ outblocksize = 4;
+ prefix = "0s";
+ break;
+ case 64: /* beware, equals ' ' */
+ inblocksize = 3;
+ outblocksize = 4;
+ prefix = "";
+ format = 's';
+ break;
+ default:
+ return 0;
+ break;
+ }
+ assert(inblocksize < sizeof(inblock));
+ assert(outblocksize < sizeof(outblock));
+ assert(breakevery % outblocksize == 0);
+
+ if (srclen == 0)
+ return 0;
+ ntodo = srclen;
+
+ if (dstlen == 0) { /* dispose of awkward special case */
+ dst = fake;
+ dstlen = 1;
+ }
+ stop = dst + dstlen - 1;
+
+ nreal = strlen(prefix);
+ needed = nreal; /* for starters */
+ if (dstlen <= nreal) { /* prefix won't fit */
+ strncpy(dst, prefix, dstlen - 1);
+ dst += dstlen - 1;
+ } else {
+ strcpy(dst, prefix);
+ dst += nreal;
+ }
+ assert(dst <= stop);
+ sincebreak = 0;
+
+ while (ntodo > 0) {
+ if (ntodo < inblocksize) { /* incomplete input */
+ memset(inblock, 0, sizeof(inblock));
+ memcpy(inblock, src, ntodo);
+ src = inblock;
+ nreal = ntodo;
+ ntodo = inblocksize;
+ } else
+ nreal = inblocksize;
+ out = (outblocksize > stop - dst) ? outblock : dst;
+
+ convert(src, nreal, format, out);
+ needed += outblocksize;
+ sincebreak += outblocksize;
+ if (dst < stop) {
+ if (out != dst) {
+ assert(outblocksize > stop - dst);
+ memcpy(dst, out, stop - dst);
+ dst = stop;
+ } else
+ dst += outblocksize;
+ }
+
+ src += inblocksize;
+ ntodo -= inblocksize;
+ if (breakevery != 0 && sincebreak >= breakevery && ntodo > 0) {
+ if (dst < stop)
+ *dst++ = breakchar;
+ needed++;
+ sincebreak = 0;
+ }
+ }
+
+ assert(dst <= stop);
+ *dst++ = '\0';
+ needed++;
+
+ return needed;
+}
+
+/*
+ - convert - convert one input block to one output block
+ */
+static void
+convert(src, nreal, format, out)
+const char *src;
+size_t nreal; /* how much of the input block is real */
+int format;
+char *out;
+{
+ static char hex[] = "0123456789abcdef";
+ static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ unsigned char c;
+ unsigned char c1, c2, c3;
+
+ assert(nreal > 0);
+ switch (format) {
+ case 'x':
+ assert(nreal == 1);
+ c = (unsigned char)*src;
+ *out++ = hex[c >> 4];
+ *out++ = hex[c & 0xf];
+ break;
+ case 's':
+ c1 = (unsigned char)*src++;
+ c2 = (unsigned char)*src++;
+ c3 = (unsigned char)*src++;
+ *out++ = base64[c1 >> 2]; /* top 6 bits of c1 */
+ c = (c1 & 0x3) << 4; /* bottom 2 of c1... */
+ c |= c2 >> 4; /* ...top 4 of c2 */
+ *out++ = base64[c];
+ if (nreal == 1)
+ *out++ = '=';
+ else {
+ c = (c2 & 0xf) << 2; /* bottom 4 of c2... */
+ c |= c3 >> 6; /* ...top 2 of c3 */
+ *out++ = base64[c];
+ }
+ if (nreal <= 2)
+ *out++ = '=';
+ else
+ *out++ = base64[c3 & 0x3f]; /* bottom 6 of c3 */
+ break;
+ default:
+ assert(nreal == 0); /* unknown format */
+ break;
+ }
+}
+
+/*
+ - datatoa - convert data to ASCII
+ * backward-compatibility synonym for datatot
+ */
+size_t /* true length (with NUL) for success */
+datatoa(src, srclen, format, dst, dstlen)
+const char *src;
+size_t srclen;
+int format; /* character indicating what format */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ return datatot(src, srclen, format, dst, dstlen);
+}
+
+/*
+ - bytestoa - convert data bytes to ASCII
+ * backward-compatibility synonym for datatot
+ */
+size_t /* true length (with NUL) for success */
+bytestoa(src, srclen, format, dst, dstlen)
+const char *src;
+size_t srclen;
+int format; /* character indicating what format */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ return datatot(src, srclen, format, dst, dstlen);
+}
diff --git a/linux/lib/libfreeswan/goodmask.3 b/linux/lib/libfreeswan/goodmask.3
new file mode 100644
index 000000000..4a573e51e
--- /dev/null
+++ b/linux/lib/libfreeswan/goodmask.3
@@ -0,0 +1,57 @@
+.TH IPSEC_GOODMASK 3 "11 June 2001"
+.\" RCSID $Id: goodmask.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec goodmask \- is this Internet subnet mask a valid one?
+.br
+ipsec masktobits \- convert Internet subnet mask to bit count
+.br
+ipsec bitstomask \- convert bit count to Internet subnet mask
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "int goodmask(struct in_addr mask);"
+.br
+.B "int masktobits(struct in_addr mask);"
+.br
+.B "struct in_addr bitstomask(int n);"
+.SH DESCRIPTION
+These functions are obsolete;
+see
+.IR ipsec_masktocount (3)
+for a partial replacement.
+.PP
+.I Goodmask
+reports whether the subnet
+.I mask
+is a valid one,
+i.e. consists of a (possibly empty) sequence of
+.BR 1 s
+followed by a (possibly empty) sequence of
+.BR 0 s.
+.I Masktobits
+takes a (valid) subnet mask and returns the number of
+.B 1
+bits in it.
+.I Bitstomask
+reverses this,
+returning the subnet mask corresponding to bit count
+.IR n .
+.PP
+All masks are in network byte order.
+.SH SEE ALSO
+inet(3), ipsec_atosubnet(3)
+.SH DIAGNOSTICS
+.I Masktobits
+returns
+.B \-1
+for an invalid mask.
+.I Bitstomask
+returns an all-zeros mask for a negative or out-of-range
+.IR n .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The error-reporting convention of
+.I bitstomask
+is less than ideal;
+zero is sometimes a legitimate mask.
diff --git a/linux/lib/libfreeswan/goodmask.c b/linux/lib/libfreeswan/goodmask.c
new file mode 100644
index 000000000..fe7a42335
--- /dev/null
+++ b/linux/lib/libfreeswan/goodmask.c
@@ -0,0 +1,97 @@
+/*
+ * minor utilities for subnet-mask manipulation
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: goodmask.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - goodmask - is this a good (^1*0*$) subnet mask?
+ * You are not expected to understand this. See Henry S. Warren Jr,
+ * "Functions realizable with word-parallel logical and two's-complement
+ * addition instructions", CACM 20.6 (June 1977), p.439.
+ */
+int /* predicate */
+goodmask(mask)
+struct in_addr mask;
+{
+ unsigned long x = ntohl(mask.s_addr);
+ /* clear rightmost contiguous string of 1-bits */
+# define CRCS1B(x) (((x|(x-1))+1)&x)
+# define TOPBIT (1UL << 31)
+
+ /* either zero, or has one string of 1-bits which is left-justified */
+ if (x == 0 || (CRCS1B(x) == 0 && (x&TOPBIT)))
+ return 1;
+ return 0;
+}
+
+/*
+ - masktobits - how many bits in this mask?
+ * The algorithm is essentially a binary search, but highly optimized
+ * for this particular task.
+ */
+int /* -1 means !goodmask() */
+masktobits(mask)
+struct in_addr mask;
+{
+ unsigned long m = ntohl(mask.s_addr);
+ int masklen;
+
+ if (!goodmask(mask))
+ return -1;
+
+ if (m&0x00000001UL)
+ return 32;
+ masklen = 0;
+ if (m&(0x0000ffffUL<<1)) { /* <<1 for 1-origin numbering */
+ masklen |= 0x10;
+ m <<= 16;
+ }
+ if (m&(0x00ff0000UL<<1)) {
+ masklen |= 0x08;
+ m <<= 8;
+ }
+ if (m&(0x0f000000UL<<1)) {
+ masklen |= 0x04;
+ m <<= 4;
+ }
+ if (m&(0x30000000UL<<1)) {
+ masklen |= 0x02;
+ m <<= 2;
+ }
+ if (m&(0x40000000UL<<1))
+ masklen |= 0x01;
+
+ return masklen;
+}
+
+/*
+ - bitstomask - return a mask with this many high bits on
+ */
+struct in_addr
+bitstomask(n)
+int n;
+{
+ struct in_addr result;
+
+ if (n > 0 && n <= ABITS)
+ result.s_addr = htonl(~((1UL << (ABITS - n)) - 1));
+ else if (n == 0)
+ result.s_addr = 0;
+ else
+ result.s_addr = 0; /* best error report we can do */
+ return result;
+}
diff --git a/linux/lib/libfreeswan/initaddr.3 b/linux/lib/libfreeswan/initaddr.3
new file mode 100644
index 000000000..b963f21cc
--- /dev/null
+++ b/linux/lib/libfreeswan/initaddr.3
@@ -0,0 +1,129 @@
+.TH IPSEC_INITADDR 3 "11 Sept 2000"
+.\" RCSID $Id: initaddr.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec initaddr \- initialize an ip_address
+.br
+ipsec addrtypeof \- get address type of an ip_address
+.br
+ipsec addrlenof \- get length of address within an ip_address
+.br
+ipsec addrbytesof \- get copy of address within an ip_address
+.br
+ipsec addrbytesptr \- get pointer to address within an ip_address
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *initaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_address *dst);"
+.br
+.B "int addrtypeof(const ip_address *src);"
+.br
+.B "size_t addrlenof(const ip_address *src);"
+.br
+.B "size_t addrbytesof(const ip_address *src,"
+.ti +1c
+.B "unsigned char *dst, size_t dstlen);"
+.br
+.B "size_t addrbytesptr(const ip_address *src,"
+.ti +1c
+.B "const unsigned char **dst);"
+.SH DESCRIPTION
+The
+.B <freeswan.h>
+library uses an internal type
+.I ip_address
+to contain one of the (currently two) types of IP address.
+These functions provide basic tools for creating and examining this type.
+.PP
+.I Initaddr
+initializes a variable
+.I *dst
+of type
+.I ip_address
+from an address
+(in network byte order,
+indicated by a pointer
+.I src
+and a length
+.IR srclen )
+and an address family
+.I af
+(typically
+.B AF_INET
+or
+.BR AF_INET6 ).
+The length must be consistent with the address family.
+.PP
+.I Addrtypeof
+returns the address type of an address,
+normally
+.B AF_INET
+or
+.BR AF_INET6 .
+(The
+.B <freeswan.h>
+header file arranges to include the necessary headers for these
+names to be known.)
+.PP
+.I Addrlenof
+returns the size (in bytes) of the address within an
+.IR ip_address ,
+to permit storage allocation etc.
+.PP
+.I Addrbytesof
+copies the address within the
+.I ip_address
+.I src
+to the buffer indicated by the pointer
+.I dst
+and the length
+.IR dstlen ,
+and returns the address length (in bytes).
+If the address will not fit,
+as many bytes as will fit are copied;
+the returned length is still the full length.
+It is the caller's responsibility to check the
+returned value to ensure that there was enough room.
+.PP
+.I Addrbytesptr
+sets
+.I *dst
+to a pointer to the internal address within the
+.IR ip_address ,
+and returns the address length (in bytes).
+If
+.I dst
+is
+.BR NULL ,
+it just returns the address length.
+The pointer points to
+.B const
+to discourage misuse.
+.PP
+.I Initaddr
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.PP
+The functions which return
+.I size_t
+return
+.B 0
+for a failure.
+.SH SEE ALSO
+inet(3), ipsec_ttoaddr(3)
+.SH DIAGNOSTICS
+An unknown address family is a fatal error for any of these functions
+except
+.IR addrtypeof .
+An address-size mismatch is a fatal error for
+.IR initaddr .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+.I Addrtypeof
+should probably have been named
+.IR addrfamilyof .
diff --git a/linux/lib/libfreeswan/initaddr.c b/linux/lib/libfreeswan/initaddr.c
new file mode 100644
index 000000000..c215f6bdf
--- /dev/null
+++ b/linux/lib/libfreeswan/initaddr.c
@@ -0,0 +1,51 @@
+/*
+ * initialize address structure
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: initaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - initaddr - initialize ip_address from bytes
+ */
+err_t /* NULL for success, else string literal */
+initaddr(src, srclen, af, dst)
+const unsigned char *src;
+size_t srclen;
+int af; /* address family */
+ip_address *dst;
+{
+ switch (af) {
+ case AF_INET:
+ if (srclen != 4)
+ return "IPv4 address must be exactly 4 bytes";
+ dst->u.v4.sin_family = af;
+ dst->u.v4.sin_port = 0; /* unused */
+ memcpy((char *)&dst->u.v4.sin_addr.s_addr, src, srclen);
+ break;
+ case AF_INET6:
+ if (srclen != 16)
+ return "IPv6 address must be exactly 16 bytes";
+ dst->u.v6.sin6_family = af;
+ dst->u.v6.sin6_flowinfo = 0; /* unused */
+ dst->u.v6.sin6_port = 0; /* unused */
+ memcpy((char *)&dst->u.v6.sin6_addr, src, srclen);
+ break;
+ default:
+ return "unknown address family in initaddr";
+ break;
+ }
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/initsaid.c b/linux/lib/libfreeswan/initsaid.c
new file mode 100644
index 000000000..4790f6981
--- /dev/null
+++ b/linux/lib/libfreeswan/initsaid.c
@@ -0,0 +1,33 @@
+/*
+ * initialize SA ID structure
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: initsaid.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - initsaid - initialize SA ID from bits
+ */
+void
+initsaid(addr, spi, proto, dst)
+const ip_address *addr;
+ipsec_spi_t spi;
+int proto;
+ip_said *dst;
+{
+ dst->dst = *addr;
+ dst->spi = spi;
+ dst->proto = proto;
+}
diff --git a/linux/lib/libfreeswan/initsubnet.3 b/linux/lib/libfreeswan/initsubnet.3
new file mode 100644
index 000000000..670f71778
--- /dev/null
+++ b/linux/lib/libfreeswan/initsubnet.3
@@ -0,0 +1,137 @@
+.TH IPSEC_INITSUBNET 3 "12 March 2002"
+.\" RCSID $Id: initsubnet.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec initsubnet \- initialize an ip_subnet
+.br
+ipsec addrtosubnet \- initialize a singleton ip_subnet
+.br
+ipsec subnettypeof \- get address type of an ip_subnet
+.br
+ipsec masktocount \- convert subnet mask to bit count
+.br
+ipsec networkof \- get base address of an ip_subnet
+.br
+ipsec maskof \- get subnet mask of an ip_subnet
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *initsubnet(const ip_address *addr,"
+.ti +1c
+.B "int maskbits, int clash, ip_subnet *dst);"
+.br
+.B "const char *addrtosubnet(const ip_address *addr,"
+.ti +1c
+.B "ip_subnet *dst);"
+.sp
+.B "int subnettypeof(const ip_subnet *src);"
+.br
+.B "int masktocount(const ip_address *src);"
+.br
+.B "void networkof(const ip_subnet *src, ip_address *dst);"
+.br
+.B "void maskof(const ip_subnet *src, ip_address *dst);"
+.SH DESCRIPTION
+The
+.B <freeswan.h>
+library uses an internal type
+.I ip_subnet
+to contain a description of an IP subnet
+(base address plus mask).
+These functions provide basic tools for creating and examining this type.
+.PP
+.I Initsubnet
+initializes a variable
+.I *dst
+of type
+.I ip_subnet
+from a base address and
+a count of mask bits.
+The
+.I clash
+parameter specifies what to do if the base address includes
+.B 1
+bits outside the prefix specified by the mask
+(that is, in the ``host number'' part of the address):
+.RS
+.IP '0' 5
+zero out host-number bits
+.IP 'x'
+non-zero host-number bits are an error
+.RE
+.PP
+.I Initsubnet
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.PP
+.I Addrtosubnet
+initializes an
+.I ip_subnet
+variable
+.I *dst
+to a ``singleton subnet'' containing the single address
+.IR *addr .
+It returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure.
+.PP
+.I Subnettypeof
+returns the address type of a subnet,
+normally
+.B AF_INET
+or
+.BR AF_INET6 .
+(The
+.B <freeswan.h>
+header file arranges to include the necessary headers for these
+names to be known.)
+.PP
+.I Masktocount
+converts a subnet mask, expressed as an address, to a bit count
+suitable for use with
+.IR initsubnet .
+It returns
+.B \-1
+for error; see DIAGNOSTICS.
+.PP
+.I Networkof
+fills in
+.I *dst
+with the base address of subnet
+.IR src .
+.PP
+.I Maskof
+fills in
+.I *dst
+with the subnet mask of subnet
+.IR src ,
+expressed as an address.
+.SH SEE ALSO
+inet(3), ipsec_ttosubnet(3), ipsec_rangetosubnet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I initsubnet
+are:
+unknown address family;
+unknown
+.I clash
+value;
+impossible mask bit count;
+non-zero host-number bits and
+.I clash
+is
+.BR 'x' .
+Fatal errors in
+.I addrtosubnet
+are:
+unknown address family.
+Fatal errors in
+.I masktocount
+are:
+unknown address family;
+mask bits not contiguous.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/initsubnet.c b/linux/lib/libfreeswan/initsubnet.c
new file mode 100644
index 000000000..75ca72f36
--- /dev/null
+++ b/linux/lib/libfreeswan/initsubnet.c
@@ -0,0 +1,95 @@
+/*
+ * initialize subnet structure
+ * Copyright (C) 2000, 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: initsubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - initsubnet - initialize ip_subnet from address and count
+ *
+ * The only hard part is checking for host-part bits turned on.
+ */
+err_t /* NULL for success, else string literal */
+initsubnet(addr, count, clash, dst)
+const ip_address *addr;
+int count;
+int clash; /* '0' zero host-part bits, 'x' die on them */
+ip_subnet *dst;
+{
+ unsigned char *p;
+ int n;
+ int c;
+ unsigned m;
+ int die;
+
+ dst->addr = *addr;
+ n = addrbytesptr(&dst->addr, (const unsigned char **)&p);
+ if (n == 0)
+ return "unknown address family";
+
+ switch (clash) {
+ case '0':
+ die = 0;
+ break;
+ case 'x':
+ die = 1;
+ break;
+ default:
+ return "unknown clash-control value in initsubnet";
+ break;
+ }
+
+ c = count / 8;
+ if (c > n)
+ return "impossible mask count";
+ p += c;
+ n -= c;
+
+ m = 0xff;
+ c = count % 8;
+ if (n > 0 && c != 0) /* partial byte */
+ m >>= c;
+ for (; n > 0; n--) {
+ if ((*p & m) != 0) {
+ if (die)
+ return "improper subnet, host-part bits on";
+ *p &= ~m;
+ }
+ m = 0xff;
+ p++;
+ }
+
+ dst->maskbits = count;
+ return NULL;
+}
+
+/*
+ - addrtosubnet - initialize ip_subnet from a single address
+ */
+err_t /* NULL for success, else string literal */
+addrtosubnet(addr, dst)
+const ip_address *addr;
+ip_subnet *dst;
+{
+ int n;
+
+ dst->addr = *addr;
+ n = addrbytesptr(&dst->addr, (const unsigned char **)NULL);
+ if (n == 0)
+ return "unknown address family";
+ dst->maskbits = n*8;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/internal.h b/linux/lib/libfreeswan/internal.h
new file mode 100644
index 000000000..16ad78da0
--- /dev/null
+++ b/linux/lib/libfreeswan/internal.h
@@ -0,0 +1,81 @@
+/*
+ * internal definitions for use within the library; do not export!
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: internal.h,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+#ifndef ABITS
+#define ABITS 32 /* bits in an IPv4 address */
+#endif
+
+/* case-independent ASCII character equality comparison */
+#define CIEQ(c1, c2) ( ((c1)&~040) == ((c2)&~040) )
+
+/* syntax for passthrough SA */
+#ifndef PASSTHROUGHNAME
+#define PASSTHROUGHNAME "%passthrough"
+#define PASSTHROUGH4NAME "%passthrough4"
+#define PASSTHROUGH6NAME "%passthrough6"
+#define PASSTHROUGHIS "tun0@0.0.0.0"
+#define PASSTHROUGH4IS "tun0@0.0.0.0"
+#define PASSTHROUGH6IS "tun0@::"
+#define PASSTHROUGHTYPE "tun"
+#define PASSTHROUGHSPI 0
+#define PASSTHROUGHDST 0
+#endif
+
+/*
+ * Headers, greatly complicated by stupid and unnecessary inconsistencies
+ * between the user environment and the kernel environment. These are done
+ * here so that this mess need exist in only one place.
+ *
+ * It may seem like a -I or two could avoid most of this, but on closer
+ * inspection it is not quite that easy.
+ */
+
+/* things that need to come from one place or the other, depending */
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#define assert(foo) /* nothing */
+#else
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#endif
+
+/* things that exist only in userland */
+#ifndef __KERNEL__
+
+/* You'd think this would be okay in the kernel too -- it's just a */
+/* bunch of constants -- but no, in RH5.1 it screws up other things. */
+/* (Credit: Mike Warfield tracked this problem down. Thanks Mike!) */
+/* Fortunately, we don't need it in the kernel subset of the library. */
+#include <limits.h>
+
+/* header files for things that should never be called in kernel */
+#include <netdb.h>
+
+/* memory allocation, currently user-only, macro-ized just in case */
+#include <stdlib.h>
+#define MALLOC(n) malloc(n)
+#define FREE(p) free(p)
+
+#endif /* __KERNEL__ */
+
diff --git a/linux/lib/libfreeswan/keyblobtoid.3 b/linux/lib/libfreeswan/keyblobtoid.3
new file mode 100644
index 000000000..be381531a
--- /dev/null
+++ b/linux/lib/libfreeswan/keyblobtoid.3
@@ -0,0 +1,103 @@
+.TH IPSEC_KEYBLOBTOID 3 "25 March 2002"
+.\" RCSID $Id: keyblobtoid.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec keyblobtoid, splitkeytoid \- generate key IDs from RSA keys
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "size_t keyblobtoid(const unsigned char *blob,"
+.ti +1c
+.B "size_t bloblen, char *dst, size_t dstlen);"
+.br
+.B "size_t splitkeytoid(const unsigned char *e, size_t elen,"
+.ti +1c
+.B "const unsigned char *m, size_t mlen, char *dst,
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+.I Keyblobtoid
+and
+.I splitkeytoid
+generate
+key IDs
+from RSA keys,
+for use in messages and reporting,
+writing the result to
+.IR dst .
+A
+.I key ID
+is a short ASCII string identifying a key;
+currently it is just the first nine characters of the base64
+encoding of the RFC 2537/3110 ``byte blob'' representation of the key.
+(Beware that no finite key ID can be collision-proof:
+there is always some small chance of two random keys having the
+same ID.)
+.PP
+.I Keyblobtoid
+generates a key ID from a key which is already in the form of an
+RFC 2537/3110 binary key
+.I blob
+(encoded exponent length, exponent, modulus).
+.PP
+.I Splitkeytoid
+generates a key ID from a key given in the form of a separate
+(binary) exponent
+.I e
+and modulus
+.IR m .
+.PP
+The
+.I dstlen
+parameter of either
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant
+.B KEYID_BUF
+which is the size of a buffer large enough for worst-case results.
+.PP
+Both functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.P
+With keys generated by
+.IR ipsec_rsasigkey (3),
+the first two base64 digits are always the same,
+and the third carries only about one bit of information.
+It's worse with keys using longer fixed exponents,
+e.g. the 24-bit exponent that's common in X.509 certificates.
+However, being able to relate key IDs to the full
+base64 text form of keys by eye is sufficiently useful that this
+waste of space seems justifiable.
+The choice of nine digits is a compromise between bulk and
+probability of collision.
+.SH SEE ALSO
+RFC 3110,
+\fIRSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)\fR,
+Eastlake, 2001
+(superseding the older but better-known RFC 2537).
+.SH DIAGNOSTICS
+Fatal errors are:
+key too short to supply enough bits to construct a complete key ID
+(almost certainly indicating a garbage key);
+exponent too long for its length to be representable.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/keyblobtoid.c b/linux/lib/libfreeswan/keyblobtoid.c
new file mode 100644
index 000000000..7798601cf
--- /dev/null
+++ b/linux/lib/libfreeswan/keyblobtoid.c
@@ -0,0 +1,148 @@
+/*
+ * generate printable key IDs
+ * Copyright (C) 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: keyblobtoid.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - keyblobtoid - generate a printable key ID from an RFC 2537/3110 key blob
+ * Current algorithm is just to use first nine base64 digits.
+ */
+size_t
+keyblobtoid(src, srclen, dst, dstlen)
+const unsigned char *src;
+size_t srclen;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[KEYID_BUF];
+ size_t ret;
+# define NDIG 9
+
+ if (srclen < (NDIG*6 + 7)/8) {
+ strcpy(buf, "?len= ?");
+ buf[5] = '0' + srclen;
+ ret = 0;
+ } else {
+ (void) datatot(src, srclen, 64, buf, NDIG+1);
+ ret = NDIG+1;
+ }
+
+ if (dstlen > 0) {
+ if (strlen(buf)+1 > dstlen)
+ *(buf + dstlen - 1) = '\0';
+ strcpy(dst, buf);
+ }
+ return ret;
+}
+
+/*
+ - splitkeytoid - generate a printable key ID from exponent/modulus pair
+ * Just constructs the beginnings of a key blob and calls keyblobtoid().
+ */
+size_t
+splitkeytoid(e, elen, m, mlen, dst, dstlen)
+const unsigned char *e;
+size_t elen;
+const unsigned char *m;
+size_t mlen;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ unsigned char buf[KEYID_BUF]; /* ample room */
+ unsigned char *bufend = buf + sizeof(buf);
+ unsigned char *p;
+ size_t n;
+
+ p = buf;
+ if (elen <= 255)
+ *p++ = elen;
+ else if ((elen &~ 0xffff) == 0) {
+ *p++ = 0;
+ *p++ = (elen>>8) & 0xff;
+ *p++ = elen & 0xff;
+ } else
+ return 0; /* unrepresentable exponent length */
+
+ n = bufend - p;
+ if (elen < n)
+ n = elen;
+ memcpy(p, e, n);
+ p += n;
+
+ n = bufend - p;
+ if (n > 0) {
+ if (mlen < n)
+ n = mlen;
+ memcpy(p, m, n);
+ p += n;
+ }
+
+ return keyblobtoid(buf, p - buf, dst, dstlen);
+}
+
+
+
+#ifdef KEYBLOBTOID_MAIN
+
+#include <stdio.h>
+
+void regress();
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ typedef unsigned char uc;
+ uc hexblob[] = "\x01\x03\x85\xf2\xd6\x76\x9b\x03\x59\xb6\x21\x52";
+ uc hexe[] = "\x03";
+ uc hexm[] = "\x85\xf2\xd6\x76\x9b\x03\x59\xb6\x21\x52\xef\x85";
+ char b64nine[] = "AQOF8tZ2m";
+ char b64six[] = "AQOF8t";
+ char buf[100];
+ size_t n;
+ char *b = b64nine;
+ size_t bl = strlen(b) + 1;
+ int st = 0;
+
+ n = keyblobtoid(hexblob, strlen(hexblob), buf, sizeof(buf));
+ if (n != bl) {
+ fprintf(stderr, "%s: keyblobtoid returned %d not %d\n",
+ argv[0], n, bl);
+ st = 1;
+ }
+ if (strcmp(buf, b) != 0) {
+ fprintf(stderr, "%s: keyblobtoid generated `%s' not `%s'\n",
+ argv[0], buf, b);
+ st = 1;
+ }
+ n = splitkeytoid(hexe, strlen(hexe), hexm, strlen(hexm), buf,
+ sizeof(buf));
+ if (n != bl) {
+ fprintf(stderr, "%s: splitkeytoid returned %d not %d\n",
+ argv[0], n, bl);
+ st = 1;
+ }
+ if (strcmp(buf, b) != 0) {
+ fprintf(stderr, "%s: splitkeytoid generated `%s' not `%s'\n",
+ argv[0], buf, b);
+ st = 1;
+ }
+ exit(st);
+}
+
+#endif /* KEYBLOBTOID_MAIN */
diff --git a/linux/lib/libfreeswan/optionsfrom.3 b/linux/lib/libfreeswan/optionsfrom.3
new file mode 100644
index 000000000..e270475bd
--- /dev/null
+++ b/linux/lib/libfreeswan/optionsfrom.3
@@ -0,0 +1,182 @@
+.TH IPSEC_OPTIONSFROM 3 "16 Oct 1998"
+.\" RCSID $Id: optionsfrom.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec optionsfrom \- read additional ``command-line'' options from file
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *optionsfrom(char *filename, int *argcp,"
+.ti +1c
+.B "char ***argvp, int optind, FILE *errsto);"
+.SH DESCRIPTION
+.I Optionsfrom
+is called from within a
+.IR getopt_long (3)
+scan,
+as the result of the appearance of an option (preferably
+.BR \-\-optionsfrom )
+to insert additional ``command-line'' arguments
+into the scan immediately after
+the option.
+Typically this would be done to pick up options which are
+security-sensitive and should not be visible to
+.IR ps (1)
+and similar commands,
+and hence cannot be supplied as part
+of the actual command line or the environment.
+.PP
+.I Optionsfrom
+reads the additional arguments from the specified
+.IR filename ,
+allocates a new argument vector to hold pointers to the existing
+arguments plus the new ones,
+and amends
+.I argc
+and
+.I argv
+(via the pointers
+.I argcp
+and
+.IR argvp ,
+which must point to the
+.I argc
+and
+.I argv
+being supplied to
+.IR getopt_long (3))
+accordingly.
+.I Optind
+must be the index, in the original argument vector,
+of the next argument.
+.PP
+If
+.I errsto
+is NULL,
+.I optionsfrom
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+If
+.I errsto
+is non-NULL and an error occurs,
+.I optionsfrom
+prints a suitable complaint onto the
+.I errsto
+descriptor and invokes
+.I exit
+with an exit status of 2;
+this is a convenience for cases where more sophisticated
+responses are not required.
+.PP
+The text of existing arguments is not disturbed by
+.IR optionsfrom ,
+so pointers to them and into them remain valid.
+.PP
+The file of additional arguments is an ASCII text file.
+Lines consisting solely of white space,
+and lines beginning with
+.BR # ,
+are comments and are ignored.
+Otherwise, a line which does not begin with
+.BR \-
+is taken to be a single argument;
+if it both begins and ends with double-quote ("),
+those quotes are stripped off (note, no other processing is done within
+the line!).
+A line beginning with
+.B \-
+is considered to contain multiple arguments separated by white space.
+.PP
+Because
+.I optionsfrom
+reads its entire file before the
+.IR getopt_long (3)
+scan is resumed, an
+.I optionsfrom
+file can contain another
+.B \-\-optionsfrom
+option.
+Obviously, infinite loops are possible here.
+If
+.I errsto
+is non-NULL,
+.I optionsfrom
+considers it an error to be called more than 100 times.
+If
+.I errsto
+is NULL,
+loop detection is up to the caller
+(and the internal loop counter is zeroed out).
+.SH EXAMPLE
+A reasonable way to invoke
+.I optionsfrom
+would be like so:
+.PP
+.nf
+.ft B
+#include <getopt.h>
+
+struct option opts[] = {
+ /* ... */
+ "optionsfrom", 1, NULL, '+',
+ /* ... */
+};
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int opt;
+ extern char *optarg;
+ extern int optind;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ /* ... */
+ case '+': /* optionsfrom */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ break;
+ /* ... */
+ }
+ /* ... */
+.ft
+.fi
+.SH SEE ALSO
+getopt_long(3)
+.SH DIAGNOSTICS
+Errors in
+.I optionsfrom
+are:
+unable to open file;
+attempt to allocate temporary storage for argument or
+argument vector failed;
+read error in file;
+line too long.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The double-quote convention is rather simplistic.
+.PP
+Line length is currently limited to 1023 bytes,
+and there is no continuation convention.
+.PP
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+.PP
+There is a certain element of unwarranted chumminess with
+the insides of
+.IR getopt_long (3)
+here.
+No non-public interfaces are actually used, but
+.IR optionsfrom
+does rely on
+.IR getopt_long (3)
+being well-behaved in certain ways that are not actually
+promised by the specs.
diff --git a/linux/lib/libfreeswan/optionsfrom.c b/linux/lib/libfreeswan/optionsfrom.c
new file mode 100644
index 000000000..d96a3124d
--- /dev/null
+++ b/linux/lib/libfreeswan/optionsfrom.c
@@ -0,0 +1,301 @@
+/*
+ * pick up more options from a file, in the middle of an option scan
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: optionsfrom.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#include <stdio.h>
+
+#define MAX 100 /* loop-detection limit */
+
+/* internal work area */
+struct work {
+# define LOTS 1024
+ char buf[LOTS];
+ char *line;
+ char *pending;
+};
+
+static const char *dowork(const char *, int *, char ***, int);
+static const char *getanarg(FILE *, struct work *, char **);
+static char *getline(FILE *, char *, size_t);
+
+/*
+ - optionsfrom - add some options, taken from a file, to argc/argv
+ * If errsto is non-NULL, does not return in event of error.
+ */
+const char * /* NULL for success, else string literal */
+optionsfrom(filename, argcp, argvp, optind, errsto)
+const char *filename;
+int *argcp; /* pointer to argc */
+char ***argvp; /* pointer to argv */
+int optind; /* current optind, number of next argument */
+FILE *errsto; /* where to report errors (NULL means return) */
+{
+ const char *e;
+ static int nuses = 0;
+
+ if (errsto != NULL) {
+ nuses++;
+ if (nuses >= MAX) {
+ fprintf(errsto,
+ "%s: optionsfrom called %d times, looping?\n",
+ (*argvp)[0], nuses);
+ exit(2);
+ }
+ } else
+ nuses = 0;
+
+ e = dowork(filename, argcp, argvp, optind);
+ if (e != NULL && errsto != NULL) {
+ fprintf(errsto, "%s: optionsfrom failed: %s\n", (*argvp)[0], e);
+ exit(2);
+ }
+ return e;
+}
+
+/*
+ - dowork - do all the real work of optionsfrom
+ * Does not alter the existing arguments, but does relocate and alter
+ * the argv pointer vector.
+ */
+static const char * /* NULL for success, else string literal */
+dowork(filename, argcp, argvp, optind)
+const char *filename;
+int *argcp; /* pointer to argc */
+char ***argvp; /* pointer to argv */
+int optind; /* current optind, number of next argument */
+{
+ char **newargv;
+ char **tmp;
+ int newargc;
+ int next; /* place for next argument */
+ int room; /* how many more new arguments we can hold */
+# define SOME 10 /* first guess at how many we'll need */
+ FILE *f;
+ int i;
+ const char *p;
+ struct work wa; /* for getanarg() */
+
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return "unable to open file";
+
+ newargc = *argcp + SOME;
+ newargv = malloc((newargc+1) * sizeof(char *));
+ if (newargv == NULL)
+ return "unable to allocate memory";
+ memcpy(newargv, *argvp, optind * sizeof(char *));
+ room = SOME;
+ next = optind;
+
+ newargv[next] = NULL;
+ wa.pending = NULL;
+ while ((p = getanarg(f, &wa, &newargv[next])) == NULL) {
+ if (room == 0) {
+ newargc += SOME;
+ tmp = realloc(newargv, (newargc+1) * sizeof(char *));
+ if (tmp == NULL) {
+ p = "out of space for new argv";
+ break; /* NOTE BREAK OUT */
+ }
+ newargv = tmp;
+ room += SOME;
+ }
+ next++;
+ room--;
+ }
+ if (p != NULL && !feof(f)) { /* error of some kind */
+ for (i = optind+1; i <= next; i++)
+ if (newargv[i] != NULL)
+ free(newargv[i]);
+ free(newargv);
+ fclose(f);
+ return p;
+ }
+
+ fclose(f);
+ memcpy(newargv + next, *argvp + optind,
+ (*argcp+1-optind) * sizeof(char *));
+ *argcp += next - optind;
+ *argvp = newargv;
+ return NULL;
+}
+
+/*
+ - getanarg - get a malloced argument from the file
+ */
+static const char * /* NULL for success, else string literal */
+getanarg(f, w, linep)
+FILE *f;
+struct work *w;
+char **linep; /* where to store pointer if successful */
+{
+ size_t len;
+ char *p;
+ char *endp;
+
+ while (w->pending == NULL) { /* no pending line */
+ if ((w->line = getline(f, w->buf, sizeof(w->buf))) == NULL)
+ return "error in line read"; /* caller checks EOF */
+ if (w->line[0] != '#' &&
+ *(w->line + strspn(w->line, " \t")) != '\0')
+ w->pending = w->line;
+ }
+
+ if (w->pending == w->line && w->line[0] != '-') {
+ /* fresh plain line */
+ w->pending = NULL;
+ p = w->line;
+ endp = p + strlen(p);
+ if (*p == '"' && endp > p+1 && *(endp-1) == '"') {
+ p++;
+ endp--;
+ *endp = '\0';
+ }
+ if (w->line == w->buf) {
+ *linep = malloc(endp - p + 1);
+ if (*linep == NULL)
+ return "out of memory for new line";
+ strcpy(*linep, p);
+ } else /* getline already malloced it */
+ *linep = p;
+ return NULL;
+ }
+
+ /* chip off a piece of a pending line */
+ p = w->pending;
+ p += strspn(p, " \t");
+ endp = p + strcspn(p, " \t");
+ len = endp - p;
+ if (*endp != '\0') {
+ *endp++ = '\0';
+ endp += strspn(endp, " \t");
+ }
+ /* endp now points to next real character, or to line-end NUL */
+ *linep = malloc(len + 1);
+ if (*linep == NULL) {
+ if (w->line != w->buf)
+ free(w->line);
+ return "out of memory for new argument";
+ }
+ strcpy(*linep, p);
+ if (*endp == '\0') {
+ w->pending = NULL;
+ if (w->line != w->buf)
+ free(w->line);
+ } else
+ w->pending = endp;
+ return NULL;
+}
+
+/*
+ - getline - read a line from the file, trim newline off
+ */
+static char * /* pointer to line, NULL for eof/error */
+getline(f, buf, bufsize)
+FILE *f;
+char *buf; /* buffer to use, if convenient */
+size_t bufsize; /* size of buf */
+{
+ size_t len;
+
+ if (fgets(buf, bufsize, f) == NULL)
+ return NULL;
+ len = strlen(buf);
+
+ if (len < bufsize-1 || buf[bufsize-1] == '\n') {
+ /* it fit */
+ buf[len-1] = '\0';
+ return buf;
+ }
+
+ /* oh crud, buffer overflow */
+ /* for now, to hell with it */
+ return NULL;
+}
+
+
+
+#ifdef TEST
+
+#include <getopt.h>
+
+char usage[] = "Usage: tester [--foo] [--bar] [--optionsfrom file] arg ...";
+struct option opts[] = {
+ "foo", 0, NULL, 'f',
+ "bar", 0, NULL, 'b',
+ "builtin", 0, NULL, 'B',
+ "optionsfrom", 1, NULL, '+',
+ "help", 0, NULL, 'h',
+ "version", 0, NULL, 'v',
+ 0, 0, NULL, 0,
+};
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int opt;
+ extern char *optarg;
+ extern int optind;
+ int errflg = 0;
+ const char *p;
+ int i;
+ FILE *errs = NULL;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ case 'f':
+ case 'b':
+ break;
+ case 'B':
+ errs = stderr;
+ break;
+ case '+': /* optionsfrom */
+ p = optionsfrom(optarg, &argc, &argv, optind, errs);
+ if (p != NULL) {
+ fprintf(stderr, "%s: optionsfrom error: %s\n",
+ argv[0], p);
+ exit(1);
+ }
+ break;
+ case 'h': /* help */
+ printf("%s\n", usage);
+ exit(0);
+ break;
+ case 'v': /* version */
+ printf("1\n");
+ exit(0);
+ break;
+ case '?':
+ default:
+ errflg = 1;
+ break;
+ }
+ if (errflg) {
+ fprintf(stderr, "%s\n", usage);
+ exit(2);
+ }
+
+ for (i = 1; i < argc; i++)
+ printf("%d: `%s'\n", i, argv[i]);
+ exit(0);
+}
+
+
+#endif /* TEST */
diff --git a/linux/lib/libfreeswan/pfkey_v2_build.c b/linux/lib/libfreeswan/pfkey_v2_build.c
new file mode 100644
index 000000000..be58c552f
--- /dev/null
+++ b/linux/lib/libfreeswan/pfkey_v2_build.c
@@ -0,0 +1,1438 @@
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * 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: pfkey_v2_build.c,v 1.4 2005/04/07 19:43:52 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_parser.c.
+ */
+
+char pfkey_v2_build_c_version[] = "$Id: pfkey_v2_build.c,v 1.4 2005/04/07 19:43:52 as Exp $";
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+# include "freeswan/ipsec_kversion.h" /* for malloc switch */
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+# include <linux/ip.h> /* struct iphdr */
+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+# include <linux/ipv6.h> /* struct ipv6hdr */
+# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
+# define MALLOC(size) kmalloc(size, GFP_ATOMIC)
+# define FREE(obj) kfree(obj)
+# include <freeswan.h>
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+# include <malloc.h>
+# include <string.h> /* memset */
+
+# include <freeswan.h>
+unsigned int pfkey_lib_debug = 0;
+
+void (*pfkey_debug_func)(const char *message, ...) PRINTF_LIKE(1);
+
+/* #define PLUTO */
+
+#define DEBUGGING(args...) if(pfkey_lib_debug) { \
+ if(pfkey_debug_func != NULL) { \
+ (*pfkey_debug_func)("pfkey_lib_debug:" args); \
+ } else { \
+ printf("pfkey_lib_debug:" args); \
+ } }
+# define MALLOC(size) malloc(size)
+# define FREE(obj) free(obj)
+#endif /* __KERNEL__ */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef __KERNEL__
+
+#include "freeswan/radij.h" /* rd_nodes */
+#include "freeswan/ipsec_encap.h" /* sockaddr_encap */
+
+# define DEBUGGING(args...) \
+ KLIPS_PRINT(debug_pfkey, "klips_debug:" args)
+#endif /* __KERNEL__ */
+
+#include "freeswan/ipsec_sa.h" /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+void
+pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ int i;
+
+ for (i = 0; i != SADB_EXT_MAX + 1; i++) {
+ extensions[i] = NULL;
+ }
+}
+
+void
+pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ int i;
+
+ if (!extensions) {
+ return;
+ }
+
+ if (extensions[0]) {
+ memset(extensions[0], 0, sizeof(struct sadb_msg));
+ FREE(extensions[0]);
+ extensions[0] = NULL;
+ }
+
+ for (i = 1; i != SADB_EXT_MAX + 1; i++) {
+ if(extensions[i]) {
+ memset(extensions[i], 0, extensions[i]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+ FREE(extensions[i]);
+ extensions[i] = NULL;
+ }
+ }
+}
+
+void
+pfkey_msg_free(struct sadb_msg **pfkey_msg)
+{
+ if (*pfkey_msg) {
+ memset(*pfkey_msg, 0, (*pfkey_msg)->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+ FREE(*pfkey_msg);
+ *pfkey_msg = NULL;
+ }
+}
+
+/* Default extension builders taken from the KLIPS code */
+
+int
+pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext,
+ uint8_t msg_type,
+ uint8_t satype,
+ uint8_t msg_errno,
+ uint32_t seq,
+ uint32_t pid)
+{
+ int error = 0;
+ struct sadb_msg *pfkey_msg = (struct sadb_msg *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_msg_hdr_build:\n");
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "on_entry &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
+ &pfkey_ext,
+ pfkey_ext,
+ *pfkey_ext);
+ /* sanity checks... */
+ if (pfkey_msg) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "why is pfkey_msg already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!msg_type) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "msg type not set, must be non-zero..\n");
+ SENDERR(EINVAL);
+ }
+
+ if (msg_type > SADB_MAX) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "msg type too large:%d.\n",
+ msg_type);
+ SENDERR(EINVAL);
+ }
+
+ if (satype > SADB_SATYPE_MAX) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "satype %d > max %d\n",
+ satype, SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_msg = (struct sadb_msg*)MALLOC(sizeof(struct sadb_msg));
+ *pfkey_ext = (struct sadb_ext*)pfkey_msg;
+
+ if (pfkey_msg == NULL) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_msg, 0, sizeof(struct sadb_msg));
+
+ pfkey_msg->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_msg->sadb_msg_type = msg_type;
+ pfkey_msg->sadb_msg_satype = satype;
+
+ pfkey_msg->sadb_msg_version = PF_KEY_V2;
+ pfkey_msg->sadb_msg_errno = msg_errno;
+ pfkey_msg->sadb_msg_reserved = 0;
+ pfkey_msg->sadb_msg_seq = seq;
+ pfkey_msg->sadb_msg_pid = pid;
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "on_exit &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
+ &pfkey_ext,
+ pfkey_ext,
+ *pfkey_ext);
+errlab:
+ return error;
+}
+
+int
+pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi,
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags,
+ uint32_t/*IPsecSAref_t*/ ref)
+{
+ int error = 0;
+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "spi=%08x replay=%d sa_state=%d auth=%d encrypt=%d flags=%d\n",
+ ntohl(spi), /* in network order */
+ replay_window,
+ sa_state,
+ auth,
+ encrypt,
+ flags);
+ /* sanity checks... */
+ if (pfkey_sa) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "why is pfkey_sa already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (exttype != SADB_EXT_SA
+ && exttype != SADB_X_EXT_SA2) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "invalid exttype=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ if (replay_window > 64) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "replay window size: %d -- must be 0 <= size <= 64\n",
+ replay_window);
+ SENDERR(EINVAL);
+ }
+
+ if (auth > SADB_AALG_MAX) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "auth=%d > SADB_AALG_MAX=%d.\n",
+ auth,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if (encrypt > SADB_EALG_MAX) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "encrypt=%d > SADB_EALG_MAX=%d.\n",
+ encrypt,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if (sa_state > SADB_SASTATE_MAX) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "sa_state=%d exceeds MAX=%d.\n",
+ sa_state,
+ SADB_SASTATE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if (sa_state == SADB_SASTATE_DEAD) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "sa_state=%d is DEAD=%d is not allowed.\n",
+ sa_state,
+ SADB_SASTATE_DEAD);
+ SENDERR(EINVAL);
+ }
+
+ if ((IPSEC_SAREF_NULL != ref) && (ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
+ ref,
+ IPSEC_SAREF_NULL,
+ IPSEC_SA_REF_TABLE_NUM_ENTRIES);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_sa = (struct sadb_sa*)MALLOC(sizeof(struct sadb_sa));
+ *pfkey_ext = (struct sadb_ext*)pfkey_sa;
+
+ if (pfkey_sa == NULL) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_sa, 0, sizeof(struct sadb_sa));
+
+ pfkey_sa->sadb_sa_len = sizeof(*pfkey_sa) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_sa->sadb_sa_exttype = exttype;
+ pfkey_sa->sadb_sa_spi = spi;
+ pfkey_sa->sadb_sa_replay = replay_window;
+ pfkey_sa->sadb_sa_state = sa_state;
+ pfkey_sa->sadb_sa_auth = auth;
+ pfkey_sa->sadb_sa_encrypt = encrypt;
+ pfkey_sa->sadb_sa_flags = flags;
+ pfkey_sa->sadb_x_sa_ref = ref;
+
+errlab:
+ return error;
+}
+
+int
+pfkey_sa_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi,
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags)
+{
+ return pfkey_sa_ref_build(pfkey_ext,
+ exttype,
+ spi,
+ replay_window,
+ sa_state,
+ auth,
+ encrypt,
+ flags,
+ IPSEC_SAREF_NULL);
+}
+
+int
+pfkey_lifetime_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t allocations,
+ uint64_t bytes,
+ uint64_t addtime,
+ uint64_t usetime,
+ uint32_t packets)
+{
+ int error = 0;
+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_lifetime_build:\n");
+ /* sanity checks... */
+ if (pfkey_lifetime) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "why is pfkey_lifetime already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (exttype != SADB_EXT_LIFETIME_CURRENT
+ && exttype != SADB_EXT_LIFETIME_HARD
+ && exttype != SADB_EXT_LIFETIME_SOFT) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "invalid exttype=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_lifetime = (struct sadb_lifetime*)MALLOC(sizeof(struct sadb_lifetime));
+ *pfkey_ext = (struct sadb_ext*)pfkey_lifetime;
+
+ if (pfkey_lifetime == NULL) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_lifetime, 0, sizeof(struct sadb_lifetime));
+
+ pfkey_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_lifetime->sadb_lifetime_exttype = exttype;
+ pfkey_lifetime->sadb_lifetime_allocations = allocations;
+ pfkey_lifetime->sadb_lifetime_bytes = bytes;
+ pfkey_lifetime->sadb_lifetime_addtime = addtime;
+ pfkey_lifetime->sadb_lifetime_usetime = usetime;
+ pfkey_lifetime->sadb_x_lifetime_packets = packets;
+
+errlab:
+ return error;
+}
+
+int
+pfkey_address_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint8_t proto,
+ uint8_t prefixlen,
+ struct sockaddr* address)
+{
+ int error = 0;
+ int saddr_len = 0;
+ char ipaddr_txt[ADDRTOT_BUF + 6/*extra for port number*/];
+ struct sadb_address *pfkey_address = (struct sadb_address *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_address_build: "
+ "exttype=%d proto=%d prefixlen=%d\n",
+ exttype,
+ proto,
+ prefixlen);
+ /* sanity checks... */
+ if (pfkey_address) {
+ DEBUGGING(
+ "pfkey_address_build: "
+ "why is pfkey_address already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!address) {
+ DEBUGGING("pfkey_address_build: "
+ "address is NULL\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_X_EXT_ADDRESS_DST2:
+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
+ case SADB_X_EXT_ADDRESS_DST_FLOW:
+ case SADB_X_EXT_ADDRESS_SRC_MASK:
+ case SADB_X_EXT_ADDRESS_DST_MASK:
+#ifdef NAT_TRAVERSAL
+ case SADB_X_EXT_NAT_T_OA:
+#endif
+ break;
+ default:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "unrecognised ext_type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ switch (address->sa_family) {
+ case AF_INET:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "found address family AF_INET.\n");
+ saddr_len = sizeof(struct sockaddr_in);
+ sprintf(ipaddr_txt, "%d.%d.%d.%d:%d"
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 0) & 0xFF
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 8) & 0xFF
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 16) & 0xFF
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 24) & 0xFF
+ , ntohs(((struct sockaddr_in*)address)->sin_port));
+ break;
+ case AF_INET6:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "found address family AF_INET6.\n");
+ saddr_len = sizeof(struct sockaddr_in6);
+ sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x-%x"
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[0])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[1])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[2])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[3])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[4])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[5])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[6])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[7])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_port));
+ break;
+ default:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "address->sa_family=%d not supported.\n",
+ address->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+
+ DEBUGGING(
+ "pfkey_address_build: "
+ "found address=%s.\n",
+ ipaddr_txt);
+ if (prefixlen != 0) {
+ DEBUGGING(
+ "pfkey_address_build: "
+ "address prefixes not supported yet.\n");
+ SENDERR(EAFNOSUPPORT); /* not supported yet */
+ }
+
+ pfkey_address = (struct sadb_address*)
+ MALLOC(ALIGN_N(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN));
+ *pfkey_ext = (struct sadb_ext*)pfkey_address;
+
+ if (pfkey_address == NULL) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_address,
+ 0,
+ ALIGN_N(sizeof(struct sadb_address) + saddr_len,
+ IPSEC_PFKEYv2_ALIGN));
+
+ pfkey_address->sadb_address_len = DIVUP(sizeof(struct sadb_address) + saddr_len,
+ IPSEC_PFKEYv2_ALIGN);
+
+ pfkey_address->sadb_address_exttype = exttype;
+ pfkey_address->sadb_address_proto = proto;
+ pfkey_address->sadb_address_prefixlen = prefixlen;
+ pfkey_address->sadb_address_reserved = 0;
+
+ memcpy((char*)pfkey_address + sizeof(struct sadb_address),
+ address,
+ saddr_len);
+
+#if 0
+ for (i = 0; i < sizeof(struct sockaddr_in) - offsetof(struct sockaddr_in, sin_zero); i++) {
+ pfkey_address_s_ska.sin_zero[i] = 0;
+ }
+#endif
+ DEBUGGING(
+ "pfkey_address_build: "
+ "successful.\n");
+
+ errlab:
+ return error;
+}
+
+int
+pfkey_key_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t key_bits,
+ char* key)
+{
+ int error = 0;
+ struct sadb_key *pfkey_key = (struct sadb_key *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_key_build:\n");
+ /* sanity checks... */
+ if (pfkey_key) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "why is pfkey_key already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!key_bits) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "key_bits is zero, it must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if ( !((exttype == SADB_EXT_KEY_AUTH) || (exttype == SADB_EXT_KEY_ENCRYPT))) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "unsupported extension type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_key = (struct sadb_key*)
+ MALLOC(sizeof(struct sadb_key) +
+ DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
+ *pfkey_ext = (struct sadb_ext*)pfkey_key;
+
+ if (pfkey_key == NULL) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_key,
+ 0,
+ sizeof(struct sadb_key) +
+ DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
+
+ pfkey_key->sadb_key_len = DIVUP(sizeof(struct sadb_key) * IPSEC_PFKEYv2_ALIGN + key_bits,
+ 64);
+ pfkey_key->sadb_key_exttype = exttype;
+ pfkey_key->sadb_key_bits = key_bits;
+ pfkey_key->sadb_key_reserved = 0;
+ memcpy((char*)pfkey_key + sizeof(struct sadb_key),
+ key,
+ DIVUP(key_bits, 8));
+
+errlab:
+ return error;
+}
+
+int
+pfkey_ident_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t ident_type,
+ uint64_t ident_id,
+ uint8_t ident_len,
+ char* ident_string)
+{
+ int error = 0;
+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)*pfkey_ext;
+ int data_len = ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ DEBUGGING(
+ "pfkey_ident_build:\n");
+ /* sanity checks... */
+ if (pfkey_ident) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "why is pfkey_ident already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if ( !((exttype == SADB_EXT_IDENTITY_SRC) ||
+ (exttype == SADB_EXT_IDENTITY_DST))) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "unsupported extension type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ if (ident_type == SADB_IDENTTYPE_RESERVED) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "ident_type must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if (ident_type > SADB_IDENTTYPE_MAX) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "identtype=%d out of range.\n",
+ ident_type);
+ SENDERR(EINVAL);
+ }
+
+ if ((ident_type == SADB_IDENTTYPE_PREFIX ||
+ ident_type == SADB_IDENTTYPE_FQDN) &&
+ !ident_string) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "string required to allocate size of extension.\n");
+ SENDERR(EINVAL);
+ }
+
+#if 0
+ if (ident_type == SADB_IDENTTYPE_USERFQDN) {
+ }
+#endif
+
+ pfkey_ident = (struct sadb_ident*)
+ MALLOC(ident_len * IPSEC_PFKEYv2_ALIGN);
+ *pfkey_ext = (struct sadb_ext*)pfkey_ident;
+
+ if (pfkey_ident == NULL) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_ident, 0, ident_len * IPSEC_PFKEYv2_ALIGN);
+
+ pfkey_ident->sadb_ident_len = ident_len;
+ pfkey_ident->sadb_ident_exttype = exttype;
+ pfkey_ident->sadb_ident_type = ident_type;
+ pfkey_ident->sadb_ident_reserved = 0;
+ pfkey_ident->sadb_ident_id = ident_id;
+ memcpy((char*)pfkey_ident + sizeof(struct sadb_ident),
+ ident_string,
+ data_len);
+
+errlab:
+ return error;
+}
+
+int
+pfkey_sens_build(struct sadb_ext** pfkey_ext,
+ uint32_t dpd,
+ uint8_t sens_level,
+ uint8_t sens_len,
+ uint64_t* sens_bitmap,
+ uint8_t integ_level,
+ uint8_t integ_len,
+ uint64_t* integ_bitmap)
+{
+ int error = 0;
+ struct sadb_sens *pfkey_sens = (struct sadb_sens *)*pfkey_ext;
+ int i;
+ uint64_t* bitmap;
+
+ DEBUGGING(
+ "pfkey_sens_build:\n");
+ /* sanity checks... */
+ if (pfkey_sens) {
+ DEBUGGING(
+ "pfkey_sens_build: "
+ "why is pfkey_sens already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_sens_build: "
+ "Sorry, I can't build exttype=%d yet.\n",
+ (*pfkey_ext)->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ pfkey_sens = (struct sadb_sens*)
+ MALLOC(sizeof(struct sadb_sens) +
+ (sens_len + integ_len) * sizeof(uint64_t));
+ *pfkey_ext = (struct sadb_ext*)pfkey_sens;
+
+ if (pfkey_sens == NULL) {
+ DEBUGGING(
+ "pfkey_sens_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_sens,
+ 0,
+ sizeof(struct sadb_sens) +
+ (sens_len + integ_len) * sizeof(uint64_t));
+
+ pfkey_sens->sadb_sens_len = (sizeof(struct sadb_sens) +
+ (sens_len + integ_len) * sizeof(uint64_t)) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY;
+ pfkey_sens->sadb_sens_dpd = dpd;
+ pfkey_sens->sadb_sens_sens_level = sens_level;
+ pfkey_sens->sadb_sens_sens_len = sens_len;
+ pfkey_sens->sadb_sens_integ_level = integ_level;
+ pfkey_sens->sadb_sens_integ_len = integ_len;
+ pfkey_sens->sadb_sens_reserved = 0;
+
+ bitmap = (uint64_t*)((char*)pfkey_ext + sizeof(struct sadb_sens));
+ for (i = 0; i < sens_len; i++) {
+ *bitmap = sens_bitmap[i];
+ bitmap++;
+ }
+ for (i = 0; i < integ_len; i++) {
+ *bitmap = integ_bitmap[i];
+ bitmap++;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_prop_build(struct sadb_ext** pfkey_ext,
+ uint8_t replay,
+ unsigned int comb_num,
+ struct sadb_comb* comb)
+{
+ int error = 0;
+ int i;
+ struct sadb_prop *pfkey_prop = (struct sadb_prop *)*pfkey_ext;
+ struct sadb_comb *combp;
+
+ DEBUGGING(
+ "pfkey_prop_build:\n");
+ /* sanity checks... */
+ if (pfkey_prop) {
+ DEBUGGING(
+ "pfkey_prop_build: "
+ "why is pfkey_prop already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ pfkey_prop = (struct sadb_prop*)
+ MALLOC(sizeof(struct sadb_prop) +
+ comb_num * sizeof(struct sadb_comb));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_prop;
+
+ if (pfkey_prop == NULL) {
+ DEBUGGING(
+ "pfkey_prop_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_prop,
+ 0,
+ sizeof(struct sadb_prop) +
+ comb_num * sizeof(struct sadb_comb));
+
+ pfkey_prop->sadb_prop_len = (sizeof(struct sadb_prop) +
+ comb_num * sizeof(struct sadb_comb)) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
+ pfkey_prop->sadb_prop_replay = replay;
+
+ for (i=0; i<3; i++) {
+ pfkey_prop->sadb_prop_reserved[i] = 0;
+ }
+
+ combp = (struct sadb_comb*)((char*)*pfkey_ext + sizeof(struct sadb_prop));
+ for (i = 0; i < comb_num; i++) {
+ memcpy (combp, &(comb[i]), sizeof(struct sadb_comb));
+ combp++;
+ }
+
+#if 0
+ uint8_t sadb_comb_auth;
+ uint8_t sadb_comb_encrypt;
+ uint16_t sadb_comb_flags;
+ uint16_t sadb_comb_auth_minbits;
+ uint16_t sadb_comb_auth_maxbits;
+ uint16_t sadb_comb_encrypt_minbits;
+ uint16_t sadb_comb_encrypt_maxbits;
+ uint32_t sadb_comb_reserved;
+ uint32_t sadb_comb_soft_allocations;
+ uint32_t sadb_comb_hard_allocations;
+ uint64_t sadb_comb_soft_bytes;
+ uint64_t sadb_comb_hard_bytes;
+ uint64_t sadb_comb_soft_addtime;
+ uint64_t sadb_comb_hard_addtime;
+ uint64_t sadb_comb_soft_usetime;
+ uint64_t sadb_comb_hard_usetime;
+ uint32_t sadb_comb_soft_packets;
+ uint32_t sadb_comb_hard_packets;
+#endif
+errlab:
+ return error;
+}
+
+int
+pfkey_supported_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ unsigned int alg_num,
+ struct sadb_alg* alg)
+{
+ int error = 0;
+ unsigned int i;
+ struct sadb_supported *pfkey_supported = (struct sadb_supported *)*pfkey_ext;
+ struct sadb_alg *pfkey_alg;
+
+ /* sanity checks... */
+ if (pfkey_supported) {
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "why is pfkey_supported already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if ( !((exttype == SADB_EXT_SUPPORTED_AUTH) || (exttype == SADB_EXT_SUPPORTED_ENCRYPT))) {
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "unsupported extension type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_supported = (struct sadb_supported*)
+ MALLOC(sizeof(struct sadb_supported) +
+ alg_num * sizeof(struct sadb_alg));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_supported;
+
+ if (pfkey_supported == NULL) {
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_supported,
+ 0,
+ sizeof(struct sadb_supported) +
+ alg_num *
+ sizeof(struct sadb_alg));
+
+ pfkey_supported->sadb_supported_len = (sizeof(struct sadb_supported) +
+ alg_num *
+ sizeof(struct sadb_alg)) /
+ IPSEC_PFKEYv2_ALIGN;
+ pfkey_supported->sadb_supported_exttype = exttype;
+ pfkey_supported->sadb_supported_reserved = 0;
+
+ pfkey_alg = (struct sadb_alg*)((char*)pfkey_supported + sizeof(struct sadb_supported));
+ for(i = 0; i < alg_num; i++) {
+ memcpy (pfkey_alg, &(alg[i]), sizeof(struct sadb_alg));
+ pfkey_alg->sadb_alg_reserved = 0;
+ pfkey_alg++;
+ }
+
+#if 0
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "Sorry, I can't build exttype=%d yet.\n",
+ (*pfkey_ext)->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ uint8_t sadb_alg_id;
+ uint8_t sadb_alg_ivlen;
+ uint16_t sadb_alg_minbits;
+ uint16_t sadb_alg_maxbits;
+ uint16_t sadb_alg_reserved;
+#endif
+errlab:
+ return error;
+}
+
+int
+pfkey_spirange_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint32_t min, /* in network order */
+ uint32_t max) /* in network order */
+{
+ int error = 0;
+ struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)*pfkey_ext;
+
+ /* sanity checks... */
+ if (pfkey_spirange) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "why is pfkey_spirange already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (ntohl(max) < ntohl(min)) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "minspi=%08x must be < maxspi=%08x.\n",
+ ntohl(min),
+ ntohl(max));
+ SENDERR(EINVAL);
+ }
+
+ if (ntohl(min) <= 255) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "minspi=%08x must be > 255.\n",
+ ntohl(min));
+ SENDERR(EEXIST);
+ }
+
+ pfkey_spirange = (struct sadb_spirange*)
+ MALLOC(sizeof(struct sadb_spirange));
+ *pfkey_ext = (struct sadb_ext*)pfkey_spirange;
+
+ if (pfkey_spirange == NULL) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_spirange,
+ 0,
+ sizeof(struct sadb_spirange));
+
+ pfkey_spirange->sadb_spirange_len = sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_spirange->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ pfkey_spirange->sadb_spirange_min = min;
+ pfkey_spirange->sadb_spirange_max = max;
+ pfkey_spirange->sadb_spirange_reserved = 0;
+ errlab:
+ return error;
+}
+
+int
+pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext)
+{
+ int error = 0;
+ struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)*pfkey_ext;
+
+ /* sanity checks... */
+ if (pfkey_x_kmprivate) {
+ DEBUGGING(
+ "pfkey_x_kmprivate_build: "
+ "why is pfkey_x_kmprivate already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
+
+ DEBUGGING(
+ "pfkey_x_kmprivate_build: "
+ "Sorry, I can't build exttype=%d yet.\n",
+ (*pfkey_ext)->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ pfkey_x_kmprivate = (struct sadb_x_kmprivate*)
+ MALLOC(sizeof(struct sadb_x_kmprivate));
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_kmprivate;
+
+ if (pfkey_x_kmprivate == NULL) {
+ DEBUGGING(
+ "pfkey_x_kmprivate_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_x_kmprivate,
+ 0,
+ sizeof(struct sadb_x_kmprivate));
+
+ pfkey_x_kmprivate->sadb_x_kmprivate_len =
+ sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_x_kmprivate->sadb_x_kmprivate_exttype = SADB_X_EXT_KMPRIVATE;
+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
+errlab:
+ return error;
+}
+
+int
+pfkey_x_satype_build(struct sadb_ext** pfkey_ext,
+ uint8_t satype)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_satype_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_satype) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "why is pfkey_x_satype already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!satype) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "SA type not set, must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if (satype > SADB_SATYPE_MAX) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "satype %d > max %d\n",
+ satype, SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_x_satype = (struct sadb_x_satype*)
+ MALLOC(sizeof(struct sadb_x_satype));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_satype;
+
+ if (pfkey_x_satype == NULL) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_x_satype,
+ 0,
+ sizeof(struct sadb_x_satype));
+
+ pfkey_x_satype->sadb_x_satype_len = sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_x_satype->sadb_x_satype_exttype = SADB_X_EXT_SATYPE2;
+ pfkey_x_satype->sadb_x_satype_satype = satype;
+ for (i=0; i<3; i++) {
+ pfkey_x_satype->sadb_x_satype_reserved[i] = 0;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_x_debug_build(struct sadb_ext** pfkey_ext,
+ uint32_t tunnel,
+ uint32_t netlink,
+ uint32_t xform,
+ uint32_t eroute,
+ uint32_t spi,
+ uint32_t radij,
+ uint32_t esp,
+ uint32_t ah,
+ uint32_t rcv,
+ uint32_t pfkey,
+ uint32_t ipcomp,
+ uint32_t verbose)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_debug_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_debug) {
+ DEBUGGING(
+ "pfkey_x_debug_build: "
+ "why is pfkey_x_debug already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_x_debug_build: "
+ "tunnel=%x netlink=%x xform=%x eroute=%x spi=%x radij=%x esp=%x ah=%x rcv=%x pfkey=%x ipcomp=%x verbose=%x?\n",
+ tunnel, netlink, xform, eroute, spi, radij, esp, ah, rcv, pfkey, ipcomp, verbose);
+
+ pfkey_x_debug = (struct sadb_x_debug*)
+ MALLOC(sizeof(struct sadb_x_debug));
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_debug;
+
+ if (pfkey_x_debug == NULL) {
+ DEBUGGING(
+ "pfkey_x_debug_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+#if 0
+ memset(pfkey_x_debug,
+ 0,
+ sizeof(struct sadb_x_debug));
+#endif
+
+ pfkey_x_debug->sadb_x_debug_len = sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_x_debug->sadb_x_debug_exttype = SADB_X_EXT_DEBUG;
+
+ pfkey_x_debug->sadb_x_debug_tunnel = tunnel;
+ pfkey_x_debug->sadb_x_debug_netlink = netlink;
+ pfkey_x_debug->sadb_x_debug_xform = xform;
+ pfkey_x_debug->sadb_x_debug_eroute = eroute;
+ pfkey_x_debug->sadb_x_debug_spi = spi;
+ pfkey_x_debug->sadb_x_debug_radij = radij;
+ pfkey_x_debug->sadb_x_debug_esp = esp;
+ pfkey_x_debug->sadb_x_debug_ah = ah;
+ pfkey_x_debug->sadb_x_debug_rcv = rcv;
+ pfkey_x_debug->sadb_x_debug_pfkey = pfkey;
+ pfkey_x_debug->sadb_x_debug_ipcomp = ipcomp;
+ pfkey_x_debug->sadb_x_debug_verbose = verbose;
+
+ for (i=0; i<4; i++) {
+ pfkey_x_debug->sadb_x_debug_reserved[i] = 0;
+ }
+
+errlab:
+ return error;
+}
+
+#ifdef NAT_TRAVERSAL
+int
+pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext,
+ uint8_t type)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_nat_t_type) {
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build: "
+ "why is pfkey_x_nat_t_type already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build: "
+ "type=%d\n", type);
+
+ pfkey_x_nat_t_type = (struct sadb_x_nat_t_type*)
+ MALLOC(sizeof(struct sadb_x_nat_t_type));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_type;
+ if (pfkey_x_nat_t_type == NULL) {
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_len = sizeof(struct sadb_x_nat_t_type) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type = type;
+ for (i=0; i<3; i++) {
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_reserved[i] = 0;
+ }
+
+errlab:
+ return error;
+}
+int
+pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t port)
+{
+ int error = 0;
+ struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_nat_t_port) {
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build: "
+ "why is pfkey_x_nat_t_port already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ switch (exttype) {
+ case SADB_X_EXT_NAT_T_SPORT:
+ case SADB_X_EXT_NAT_T_DPORT:
+ break;
+ default:
+ DEBUGGING(
+ "pfkey_nat_t_port_build: "
+ "unrecognised ext_type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build: "
+ "ext=%d, port=%d\n", exttype, port);
+
+ pfkey_x_nat_t_port = (struct sadb_x_nat_t_port*)
+ MALLOC(sizeof(struct sadb_x_nat_t_port));
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_port;
+
+ if (pfkey_x_nat_t_port == NULL) {
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype = exttype;
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_port = port;
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_reserved = 0;
+
+errlab:
+ return error;
+}
+#endif
+
+int pfkey_x_protocol_build(struct sadb_ext **pfkey_ext,
+ uint8_t protocol)
+{
+ int error = 0;
+ struct sadb_protocol * p = (struct sadb_protocol *)*pfkey_ext;
+ DEBUGGING("pfkey_x_protocol_build: protocol=%u\n", protocol);
+ /* sanity checks... */
+ if (p != 0) {
+ DEBUGGING("pfkey_x_protocol_build: bogus protocol pointer\n");
+ SENDERR(EINVAL);
+ }
+ if ((p = (struct sadb_protocol*)MALLOC(sizeof(*p))) == 0) {
+ DEBUGGING("pfkey_build: memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ *pfkey_ext = (struct sadb_ext *)p;
+ p->sadb_protocol_len = sizeof(*p) / sizeof(uint64_t);
+ p->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
+ p->sadb_protocol_proto = protocol;
+ p->sadb_protocol_flags = 0;
+ p->sadb_protocol_reserved2 = 0;
+ errlab:
+ return error;
+}
+
+
+#if I_DONT_THINK_THIS_WILL_BE_USEFUL
+int (*ext_default_builders[SADB_EXT_MAX +1])(struct sadb_msg*, struct sadb_ext*)
+ =
+{
+ NULL, /* pfkey_msg_build, */
+ pfkey_sa_build,
+ pfkey_lifetime_build,
+ pfkey_lifetime_build,
+ pfkey_lifetime_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_key_build,
+ pfkey_key_build,
+ pfkey_ident_build,
+ pfkey_ident_build,
+ pfkey_sens_build,
+ pfkey_prop_build,
+ pfkey_supported_build,
+ pfkey_supported_build,
+ pfkey_spirange_build,
+ pfkey_x_kmprivate_build,
+ pfkey_x_satype_build,
+ pfkey_sa_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_x_ext_debug_build
+};
+#endif
+
+int
+pfkey_msg_build(struct sadb_msg **pfkey_msg, struct sadb_ext *extensions[], int dir)
+{
+ int error = 0;
+ unsigned ext;
+ unsigned total_size;
+ struct sadb_ext *pfkey_ext;
+ int extensions_seen = 0;
+ struct sadb_ext *extensions_check[SADB_EXT_MAX + 1];
+
+ if (!extensions[0]) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "extensions[0] must be specified (struct sadb_msg).\n");
+ SENDERR(EINVAL);
+ }
+
+ total_size = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+ for (ext = 1; ext <= SADB_EXT_MAX; ext++) {
+ if(extensions[ext]) {
+ total_size += (extensions[ext])->sadb_ext_len;
+ }
+ }
+
+ if (!(*pfkey_msg = (struct sadb_msg*)MALLOC(total_size * IPSEC_PFKEYv2_ALIGN))) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "pfkey_msg=0p%p allocated %lu bytes, &(extensions[0])=0p%p\n",
+ *pfkey_msg,
+ (unsigned long)(total_size * IPSEC_PFKEYv2_ALIGN),
+ &(extensions[0]));
+ memcpy(*pfkey_msg,
+ extensions[0],
+ sizeof(struct sadb_msg));
+ (*pfkey_msg)->sadb_msg_len = total_size;
+ (*pfkey_msg)->sadb_msg_reserved = 0;
+ extensions_seen = 1 ;
+
+ pfkey_ext = (struct sadb_ext*)(((char*)(*pfkey_msg)) + sizeof(struct sadb_msg));
+
+ for (ext = 1; ext <= SADB_EXT_MAX; ext++) {
+ /* copy from extension[ext] to buffer */
+ if (extensions[ext]) {
+ /* Is this type of extension permitted for this type of message? */
+ if (!(extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type] &
+ 1<<ext)) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "ext type %d not permitted, exts_perm=%08x, 1<<type=%08x\n",
+ ext,
+ extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
+ 1<<ext);
+ SENDERR(EINVAL);
+ }
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "copying %lu bytes from extensions[%u]=0p%p to=0p%p\n",
+ (unsigned long)(extensions[ext]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN),
+ ext,
+ extensions[ext],
+ pfkey_ext);
+ memcpy(pfkey_ext,
+ extensions[ext],
+ (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+ {
+ char *pfkey_ext_c = (char *)pfkey_ext;
+
+ pfkey_ext_c += (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN;
+ pfkey_ext = (struct sadb_ext *)pfkey_ext_c;
+ }
+ /* Mark that we have seen this extension and remember the header location */
+ extensions_seen |= ( 1 << ext );
+ }
+ }
+
+ /* check required extensions */
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "extensions permitted=%08x, seen=%08x, required=%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
+ extensions_seen,
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]);
+
+ if ((extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) !=
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "required extensions missing:%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type] -
+ (extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) );
+ SENDERR(EINVAL);
+ }
+
+ error = pfkey_msg_parse(*pfkey_msg, NULL, extensions_check, dir);
+ if (error) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "Trouble parsing newly built pfkey message, error=%d.\n",
+ error);
+ SENDERR(-error);
+ }
+
+errlab:
+
+ return error;
+}
diff --git a/linux/lib/libfreeswan/pfkey_v2_debug.c b/linux/lib/libfreeswan/pfkey_v2_debug.c
new file mode 100644
index 000000000..2f2ddd3b1
--- /dev/null
+++ b/linux/lib/libfreeswan/pfkey_v2_debug.c
@@ -0,0 +1,179 @@
+/*
+ * @(#) pfkey version 2 debugging messages
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pfkey_v2_debug.c,v 1.2 2004/03/22 21:53:18 as Exp $
+ *
+ */
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+# include "freeswan/ipsec_kversion.h" /* for malloc switch */
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+extern int debug_pfkey;
+
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+
+#endif /* __KERNEL__ */
+
+#include "freeswan.h"
+#include "pfkeyv2.h"
+#include "pfkey.h"
+
+/*
+ * This file provides ASCII translations of PF_KEY magic numbers.
+ *
+ */
+
+static char *pfkey_sadb_ext_strings[]={
+ "reserved", /* SADB_EXT_RESERVED 0 */
+ "security-association", /* SADB_EXT_SA 1 */
+ "lifetime-current", /* SADB_EXT_LIFETIME_CURRENT 2 */
+ "lifetime-hard", /* SADB_EXT_LIFETIME_HARD 3 */
+ "lifetime-soft", /* SADB_EXT_LIFETIME_SOFT 4 */
+ "source-address", /* SADB_EXT_ADDRESS_SRC 5 */
+ "destination-address", /* SADB_EXT_ADDRESS_DST 6 */
+ "proxy-address", /* SADB_EXT_ADDRESS_PROXY 7 */
+ "authentication-key", /* SADB_EXT_KEY_AUTH 8 */
+ "cipher-key", /* SADB_EXT_KEY_ENCRYPT 9 */
+ "source-identity", /* SADB_EXT_IDENTITY_SRC 10 */
+ "destination-identity", /* SADB_EXT_IDENTITY_DST 11 */
+ "sensitivity-label", /* SADB_EXT_SENSITIVITY 12 */
+ "proposal", /* SADB_EXT_PROPOSAL 13 */
+ "supported-auth", /* SADB_EXT_SUPPORTED_AUTH 14 */
+ "supported-cipher", /* SADB_EXT_SUPPORTED_ENCRYPT 15 */
+ "spi-range", /* SADB_EXT_SPIRANGE 16 */
+ "X-kmpprivate", /* SADB_X_EXT_KMPRIVATE 17 */
+ "X-satype2", /* SADB_X_EXT_SATYPE2 18 */
+ "X-security-association", /* SADB_X_EXT_SA2 19 */
+ "X-destination-address2", /* SADB_X_EXT_ADDRESS_DST2 20 */
+ "X-source-flow-address", /* SADB_X_EXT_ADDRESS_SRC_FLOW 21 */
+ "X-dest-flow-address", /* SADB_X_EXT_ADDRESS_DST_FLOW 22 */
+ "X-source-mask", /* SADB_X_EXT_ADDRESS_SRC_MASK 23 */
+ "X-dest-mask", /* SADB_X_EXT_ADDRESS_DST_MASK 24 */
+ "X-set-debug", /* SADB_X_EXT_DEBUG 25 */
+#ifdef NAT_TRAVERSAL
+ "X-NAT-T-type", /* SADB_X_EXT_NAT_T_TYPE 26 */
+ "X-NAT-T-sport", /* SADB_X_EXT_NAT_T_SPORT 27 */
+ "X-NAT-T-dport", /* SADB_X_EXT_NAT_T_DPORT 28 */
+ "X-NAT-T-OA", /* SADB_X_EXT_NAT_T_OA 29 */
+#endif
+};
+
+const char *
+pfkey_v2_sadb_ext_string(int ext)
+{
+ if(ext <= SADB_EXT_MAX) {
+ return pfkey_sadb_ext_strings[ext];
+ } else {
+ return "unknown-ext";
+ }
+}
+
+
+static char *pfkey_sadb_type_strings[]={
+ "reserved", /* SADB_RESERVED */
+ "getspi", /* SADB_GETSPI */
+ "update", /* SADB_UPDATE */
+ "add", /* SADB_ADD */
+ "delete", /* SADB_DELETE */
+ "get", /* SADB_GET */
+ "acquire", /* SADB_ACQUIRE */
+ "register", /* SADB_REGISTER */
+ "expire", /* SADB_EXPIRE */
+ "flush", /* SADB_FLUSH */
+ "dump", /* SADB_DUMP */
+ "x-promisc", /* SADB_X_PROMISC */
+ "x-pchange", /* SADB_X_PCHANGE */
+ "x-groupsa", /* SADB_X_GRPSA */
+ "x-addflow(eroute)", /* SADB_X_ADDFLOW */
+ "x-delflow(eroute)", /* SADB_X_DELFLOW */
+ "x-debug", /* SADB_X_DEBUG */
+};
+
+const char *
+pfkey_v2_sadb_type_string(int sadb_type)
+{
+ if(sadb_type <= SADB_MAX) {
+ return pfkey_sadb_type_strings[sadb_type];
+ } else {
+ return "unknown-sadb-type";
+ }
+}
+
+
+
+
+/*
+ * $Log: pfkey_v2_debug.c,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.7 2002/09/20 05:01:26 rgb
+ * Fixed limit inclusion error in both type and ext string conversion.
+ *
+ * Revision 1.6 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.5 2002/04/24 07:36:40 mcr
+ * Moved from ./lib/pfkey_v2_debug.c,v
+ *
+ * Revision 1.4 2002/01/29 22:25:36 rgb
+ * Re-add ipsec_kversion.h to keep MALLOC happy.
+ *
+ * Revision 1.3 2002/01/29 01:59:09 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ * Revision 1.2 2002/01/20 20:34:50 mcr
+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
+ *
+ * Revision 1.1 2001/11/27 05:30:06 mcr
+ * initial set of debug strings for pfkey debugging.
+ * this will eventually only be included for debug builds.
+ *
+ * Revision 1.1 2001/09/21 04:12:03 mcr
+ * first compilable version.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/lib/libfreeswan/pfkey_v2_ext_bits.c b/linux/lib/libfreeswan/pfkey_v2_ext_bits.c
new file mode 100644
index 000000000..fe3f45306
--- /dev/null
+++ b/linux/lib/libfreeswan/pfkey_v2_ext_bits.c
@@ -0,0 +1,803 @@
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * 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: pfkey_v2_ext_bits.c,v 1.2 2004/03/22 21:53:18 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_parse.c.
+ */
+
+char pfkey_v2_ext_bits_c_version[] = "$Id: pfkey_v2_ext_bits.c,v 1.2 2004/03/22 21:53:18 as Exp $";
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+# include "freeswan/ipsec_kversion.h" /* for malloc switch */
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+# include <linux/ip.h> /* struct iphdr */
+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+# include <linux/ipv6.h>
+# endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+#endif
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/] = {
+
+/* INBOUND EXTENSIONS */
+{
+
+/* PERMITTED IN */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_SPIRANGE
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+#ifdef NAT_TRAVERSAL
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+#ifdef NAT_TRAVERSAL
+| 1<<SADB_X_EXT_NAT_T_TYPE
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+| 1<<SADB_X_EXT_NAT_T_OA
+#endif
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_EXPIRE */
+0
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+},
+
+/* REQUIRED IN */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_SPIRANGE
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+/*| 1<<SADB_EXT_KEY_AUTH*/
+/*| 1<<SADB_EXT_KEY_ENCRYPT*/
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+/*| 1<<SADB_EXT_KEY_AUTH*/
+/*| 1<<SADB_EXT_KEY_ENCRYPT*/
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_EXPIRE */
+0
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+/*| 1<<SADB_X_EXT_SATYPE2*/
+/*| 1<<SADB_X_EXT_SA2*/
+/*| 1<<SADB_X_EXT_ADDRESS_DST2*/
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+/*| 1<<SADB_EXT_SA*/
+#if 0 /* SADB_X_CLREROUTE doesn't need all these... */
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+}
+
+},
+
+/* OUTBOUND EXTENSIONS */
+{
+
+/* PERMITTED OUT */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+#ifdef NAT_TRAVERSAL
+| 1<<SADB_X_EXT_NAT_T_TYPE
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+| 1<<SADB_X_EXT_NAT_T_OA
+#endif
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+,
+/* SADB_EXPIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+},
+
+/* REQUIRED OUT */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+/* | 1<<SADB_EXT_KEY_AUTH */
+/* | 1<<SADB_EXT_KEY_ENCRYPT */
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+/* | 1<<SADB_EXT_SUPPORTED_AUTH
+ | 1<<SADB_EXT_SUPPORTED_ENCRYPT */
+,
+/* SADB_EXPIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+/* | 1<<SADB_EXT_LIFETIME_HARD
+ | 1<<SADB_EXT_LIFETIME_SOFT */
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+/*| 1<<SADB_EXT_SA*/
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+}
+}
+};
+
+/*
+ * $Log: pfkey_v2_ext_bits.c,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.15 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.14 2002/04/24 07:36:40 mcr
+ * Moved from ./lib/pfkey_v2_ext_bits.c,v
+ *
+ * Revision 1.13 2002/01/29 22:25:36 rgb
+ * Re-add ipsec_kversion.h to keep MALLOC happy.
+ *
+ * Revision 1.12 2002/01/29 01:59:10 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ * Revision 1.11 2001/10/18 04:45:24 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.10 2001/09/08 21:13:35 rgb
+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
+ *
+ * Revision 1.9 2001/06/14 19:35:16 rgb
+ * Update copyright date.
+ *
+ * Revision 1.8 2001/03/26 23:07:36 rgb
+ * Remove requirement for auth and enc key from UPDATE.
+ *
+ * Revision 1.7 2000/09/12 22:35:37 rgb
+ * Restructured to remove unused extensions from CLEARFLOW messages.
+ *
+ * Revision 1.6 2000/09/09 06:39:01 rgb
+ * Added comments for clarity.
+ *
+ * Revision 1.5 2000/06/02 22:54:14 rgb
+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
+ *
+ * Revision 1.4 2000/01/21 06:27:56 rgb
+ * Added address cases for eroute flows.
+ * Added comments for each message type.
+ * Added klipsdebug switching capability.
+ * Fixed GRPSA bitfields.
+ *
+ * Revision 1.3 1999/12/01 22:20:27 rgb
+ * Remove requirement for a proxy address in an incoming getspi message.
+ *
+ * Revision 1.2 1999/11/27 11:57:06 rgb
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ * Add CVS log entry to bottom of file.
+ * Cleaned out unused bits.
+ *
+ */
diff --git a/linux/lib/libfreeswan/pfkey_v2_parse.c b/linux/lib/libfreeswan/pfkey_v2_parse.c
new file mode 100644
index 000000000..bb6962fa8
--- /dev/null
+++ b/linux/lib/libfreeswan/pfkey_v2_parse.c
@@ -0,0 +1,1832 @@
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * 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: pfkey_v2_parse.c,v 1.4 2004/06/13 20:35:07 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_parser.c.
+ */
+
+char pfkey_v2_parse_c_version[] = "$Id: pfkey_v2_parse.c,v 1.4 2004/06/13 20:35:07 as Exp $";
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+#include "freeswan/ipsec_kversion.h" /* for malloc switch */
+
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+# include <linux/ip.h> /* struct iphdr */
+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+# include <linux/ipv6.h> /* struct ipv6hdr */
+# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+extern int debug_pfkey;
+
+# include <freeswan.h>
+
+#include "freeswan/ipsec_encap.h"
+
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+
+# include <freeswan.h>
+# include "programs/pluto/constants.h"
+# include "programs/pluto/defs.h" /* for PRINTF_LIKE */
+# include "programs/pluto/log.h" /* for debugging and DBG_log */
+
+/* #define PLUTO */
+
+# ifdef PLUTO
+# define DEBUGGING(level, args...) { DBG_log("pfkey_lib_debug:" args); }
+# else
+# define DEBUGGING(level, args...) if(pfkey_lib_debug & level) { printf("pfkey_lib_debug:" args); } else { ; }
+# endif
+
+#endif /* __KERNEL__ */
+
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef __KERNEL__
+extern int sysctl_ipsec_debug_verbose;
+# define DEBUGGING(level, args...) \
+ KLIPS_PRINT( \
+ ((debug_pfkey & level & (PF_KEY_DEBUG_PARSE_STRUCT | PF_KEY_DEBUG_PARSE_PROBLEM)) \
+ || (sysctl_ipsec_debug_verbose && (debug_pfkey & level & PF_KEY_DEBUG_PARSE_FLOW))) \
+ , "klips_debug:" args)
+#endif /* __KERNEL__ */
+#include "freeswan/ipsec_sa.h" /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
+
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+struct satype_tbl {
+ uint8_t proto;
+ uint8_t satype;
+ char* name;
+} static satype_tbl[] = {
+#ifdef __KERNEL__
+ { IPPROTO_ESP, SADB_SATYPE_ESP, "ESP" },
+ { IPPROTO_AH, SADB_SATYPE_AH, "AH" },
+ { IPPROTO_IPIP, SADB_X_SATYPE_IPIP, "IPIP" },
+#ifdef CONFIG_IPSEC_IPCOMP
+ { IPPROTO_COMP, SADB_X_SATYPE_COMP, "COMP" },
+#endif /* CONFIG_IPSEC_IPCOMP */
+ { IPPROTO_INT, SADB_X_SATYPE_INT, "INT" },
+#else /* __KERNEL__ */
+ { SA_ESP, SADB_SATYPE_ESP, "ESP" },
+ { SA_AH, SADB_SATYPE_AH, "AH" },
+ { SA_IPIP, SADB_X_SATYPE_IPIP, "IPIP" },
+ { SA_COMP, SADB_X_SATYPE_COMP, "COMP" },
+ { SA_INT, SADB_X_SATYPE_INT, "INT" },
+#endif /* __KERNEL__ */
+ { 0, 0, "UNKNOWN" }
+};
+
+uint8_t
+satype2proto(uint8_t satype)
+{
+ int i =0;
+
+ while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
+ i++;
+ }
+ return satype_tbl[i].proto;
+}
+
+uint8_t
+proto2satype(uint8_t proto)
+{
+ int i = 0;
+
+ while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
+ i++;
+ }
+ return satype_tbl[i].satype;
+}
+
+char*
+satype2name(uint8_t satype)
+{
+ int i = 0;
+
+ while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
+ i++;
+ }
+ return satype_tbl[i].name;
+}
+
+char*
+proto2name(uint8_t proto)
+{
+ int i = 0;
+
+ while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
+ i++;
+ }
+ return satype_tbl[i].name;
+}
+
+/* Default extension parsers taken from the KLIPS code */
+
+DEBUG_NO_STATIC int
+pfkey_sa_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
+#if 0
+ struct sadb_sa sav2;
+#endif
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_sa_parse: entry\n");
+ /* sanity checks... */
+ if(!pfkey_sa) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+#if 0
+ /* check if this structure is short, and if so, fix it up.
+ * XXX this is NOT the way to do things.
+ */
+ if(pfkey_sa->sadb_sa_len == sizeof(struct sadb_sa_v1)/IPSEC_PFKEYv2_ALIGN) {
+
+ /* yes, so clear out a temporary structure, and copy first */
+ memset(&sav2, 0, sizeof(sav2));
+ memcpy(&sav2, pfkey_sa, sizeof(struct sadb_sa_v1));
+ sav2.sadb_x_sa_ref=-1;
+ sav2.sadb_sa_len = sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_sa = &sav2;
+ }
+#endif
+
+
+ if(pfkey_sa->sadb_sa_len != sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "length wrong pfkey_sa->sadb_sa_len=%d sizeof(struct sadb_sa)=%d.\n",
+ pfkey_sa->sadb_sa_len,
+ (int)sizeof(struct sadb_sa));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_encrypt > SADB_EALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "pfkey_sa->sadb_sa_encrypt=%d > SADB_EALG_MAX=%d.\n",
+ pfkey_sa->sadb_sa_encrypt,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_auth > SADB_AALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "pfkey_sa->sadb_sa_auth=%d > SADB_AALG_MAX=%d.\n",
+ pfkey_sa->sadb_sa_auth,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_state > SADB_SASTATE_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "state=%d exceeds MAX=%d.\n",
+ pfkey_sa->sadb_sa_state,
+ SADB_SASTATE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_state == SADB_SASTATE_DEAD) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "state=%d is DEAD=%d.\n",
+ pfkey_sa->sadb_sa_state,
+ SADB_SASTATE_DEAD);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_replay > 64) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "replay window size: %d -- must be 0 <= size <= 64\n",
+ pfkey_sa->sadb_sa_replay);
+ SENDERR(EINVAL);
+ }
+
+ if(! ((pfkey_sa->sadb_sa_exttype == SADB_EXT_SA) ||
+ (pfkey_sa->sadb_sa_exttype == SADB_X_EXT_SA2)))
+ {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "unknown exttype=%d, expecting SADB_EXT_SA=%d or SADB_X_EXT_SA2=%d.\n",
+ pfkey_sa->sadb_sa_exttype,
+ SADB_EXT_SA,
+ SADB_X_EXT_SA2);
+ SENDERR(EINVAL);
+ }
+
+ if((IPSEC_SAREF_NULL != pfkey_sa->sadb_x_sa_ref) && (pfkey_sa->sadb_x_sa_ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
+ pfkey_sa->sadb_x_sa_ref,
+ IPSEC_SAREF_NULL,
+ IPSEC_SA_REF_TABLE_NUM_ENTRIES);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_sa_parse: "
+ "successfully found len=%d exttype=%d(%s) spi=%08lx replay=%d state=%d auth=%d encrypt=%d flags=%d ref=%d.\n",
+ pfkey_sa->sadb_sa_len,
+ pfkey_sa->sadb_sa_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_sa->sadb_sa_exttype),
+ (long unsigned int)ntohl(pfkey_sa->sadb_sa_spi),
+ pfkey_sa->sadb_sa_replay,
+ pfkey_sa->sadb_sa_state,
+ pfkey_sa->sadb_sa_auth,
+ pfkey_sa->sadb_sa_encrypt,
+ pfkey_sa->sadb_sa_flags,
+ pfkey_sa->sadb_x_sa_ref);
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_lifetime_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_lifetime_parse:enter\n");
+ /* sanity checks... */
+ if(!pfkey_lifetime) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_lifetime_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_lifetime->sadb_lifetime_len !=
+ sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_lifetime_parse: "
+ "length wrong pfkey_lifetime->sadb_lifetime_len=%d sizeof(struct sadb_lifetime)=%d.\n",
+ pfkey_lifetime->sadb_lifetime_len,
+ (int)sizeof(struct sadb_lifetime));
+ SENDERR(EINVAL);
+ }
+
+ if((pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_HARD) &&
+ (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_SOFT) &&
+ (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_CURRENT)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_lifetime_parse: "
+ "unexpected ext_type=%d.\n",
+ pfkey_lifetime->sadb_lifetime_exttype);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_lifetime_parse: "
+ "life_type=%d(%s) alloc=%u bytes=%u add=%u use=%u pkts=%u.\n",
+ pfkey_lifetime->sadb_lifetime_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_lifetime->sadb_lifetime_exttype),
+ pfkey_lifetime->sadb_lifetime_allocations,
+ (unsigned)pfkey_lifetime->sadb_lifetime_bytes,
+ (unsigned)pfkey_lifetime->sadb_lifetime_addtime,
+ (unsigned)pfkey_lifetime->sadb_lifetime_usetime,
+ pfkey_lifetime->sadb_x_lifetime_packets);
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_address_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int saddr_len = 0;
+ struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
+ struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
+ char ipaddr_txt[ADDRTOT_BUF];
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_address_parse:enter\n");
+ /* sanity checks... */
+ if(!pfkey_address) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_address->sadb_address_len <
+ (sizeof(struct sadb_address) + sizeof(struct sockaddr))/
+ IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "size wrong 1 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
+ pfkey_address->sadb_address_len,
+ (int)sizeof(struct sadb_address),
+ (int)sizeof(struct sockaddr));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_address->sadb_address_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_address->sadb_address_reserved);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_address->sadb_address_exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_X_EXT_ADDRESS_DST2:
+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
+ case SADB_X_EXT_ADDRESS_DST_FLOW:
+ case SADB_X_EXT_ADDRESS_SRC_MASK:
+ case SADB_X_EXT_ADDRESS_DST_MASK:
+#ifdef NAT_TRAVERSAL
+ case SADB_X_EXT_NAT_T_OA:
+#endif
+ break;
+ default:
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "unexpected ext_type=%d.\n",
+ pfkey_address->sadb_address_exttype);
+ SENDERR(EINVAL);
+ }
+
+ switch(s->sa_family) {
+ case AF_INET:
+ saddr_len = sizeof(struct sockaddr_in);
+ sprintf(ipaddr_txt, "%d.%d.%d.%d"
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 0) & 0xFF
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 8) & 0xFF
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 16) & 0xFF
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 24) & 0xFF);
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_address_parse: "
+ "found exttype=%u(%s) family=%d(AF_INET) address=%s proto=%u port=%u.\n",
+ pfkey_address->sadb_address_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
+ s->sa_family,
+ ipaddr_txt,
+ pfkey_address->sadb_address_proto,
+ ntohs(((struct sockaddr_in*)s)->sin_port));
+ break;
+ case AF_INET6:
+ saddr_len = sizeof(struct sockaddr_in6);
+ sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x"
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[0])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[1])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[2])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[3])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[4])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[5])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[6])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[7]));
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_address_parse: "
+ "found exttype=%u(%s) family=%d(AF_INET6) address=%s proto=%u port=%u.\n",
+ pfkey_address->sadb_address_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
+ s->sa_family,
+ ipaddr_txt,
+ pfkey_address->sadb_address_proto,
+ ((struct sockaddr_in6*)s)->sin6_port);
+ break;
+ default:
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "s->sa_family=%d not supported.\n",
+ s->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+
+ if(pfkey_address->sadb_address_len !=
+ DIVUP(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "size wrong 2 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
+ pfkey_address->sadb_address_len,
+ (int)sizeof(struct sadb_address),
+ saddr_len);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_address->sadb_address_prefixlen != 0) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "address prefixes not supported yet.\n");
+ SENDERR(EAFNOSUPPORT); /* not supported yet */
+ }
+
+ /* XXX check if port!=0 */
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_address_parse: successful.\n");
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_key_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_key_parse:enter\n");
+ /* sanity checks... */
+
+ if(!pfkey_key) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_key->sadb_key_len < sizeof(struct sadb_key) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_key->sadb_key_len,
+ (int)sizeof(struct sadb_key));
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_key->sadb_key_bits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "key length set to zero, must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_key->sadb_key_len !=
+ DIVUP(sizeof(struct sadb_key) * OCTETBITS + pfkey_key->sadb_key_bits,
+ PFKEYBITS)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "key length=%d does not agree with extension length=%d.\n",
+ pfkey_key->sadb_key_bits,
+ pfkey_key->sadb_key_len);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_key->sadb_key_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_key->sadb_key_reserved);
+ SENDERR(EINVAL);
+ }
+
+ if(! ( (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_AUTH) ||
+ (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_ENCRYPT))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "expecting extension type AUTH or ENCRYPT, got %d.\n",
+ pfkey_key->sadb_key_exttype);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_key_parse: "
+ "success, found len=%d exttype=%d(%s) bits=%d reserved=%d.\n",
+ pfkey_key->sadb_key_len,
+ pfkey_key->sadb_key_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_key->sadb_key_exttype),
+ pfkey_key->sadb_key_bits,
+ pfkey_key->sadb_key_reserved);
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_ident_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_ident->sadb_ident_len < sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_ident->sadb_ident_len,
+ (int)sizeof(struct sadb_ident));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "ident_type=%d out of range, must be less than %d.\n",
+ pfkey_ident->sadb_ident_type,
+ SADB_IDENTTYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_ident->sadb_ident_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_ident->sadb_ident_reserved);
+ SENDERR(EINVAL);
+ }
+
+ /* string terminator/padding must be zero */
+ if(pfkey_ident->sadb_ident_len > sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
+ if(*((char*)pfkey_ident + pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "string padding must be zero, last is 0x%02x.\n",
+ *((char*)pfkey_ident +
+ pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1));
+ SENDERR(EINVAL);
+ }
+ }
+
+ if( ! ((pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC) ||
+ (pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_DST))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "expecting extension type IDENTITY_SRC or IDENTITY_DST, got %d.\n",
+ pfkey_ident->sadb_ident_exttype);
+ SENDERR(EINVAL);
+ }
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_sens_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_sens *pfkey_sens = (struct sadb_sens *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_sens->sadb_sens_len < sizeof(struct sadb_sens) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sens_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_sens->sadb_sens_len,
+ (int)sizeof(struct sadb_sens));
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sens_parse: "
+ "Sorry, I can't parse exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+#if 0
+ SENDERR(EINVAL); /* don't process these yet */
+#endif
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_prop_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int i, num_comb;
+ struct sadb_prop *pfkey_prop = (struct sadb_prop *)pfkey_ext;
+ struct sadb_comb *pfkey_comb = (struct sadb_comb *)((char*)pfkey_ext + sizeof(struct sadb_prop));
+
+ /* sanity checks... */
+ if((pfkey_prop->sadb_prop_len < sizeof(struct sadb_prop) / IPSEC_PFKEYv2_ALIGN) ||
+ (((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "size wrong ext_len=%d, prop_ext_len=%d comb_ext_len=%d.\n",
+ pfkey_prop->sadb_prop_len,
+ (int)sizeof(struct sadb_prop),
+ (int)sizeof(struct sadb_comb));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_prop->sadb_prop_replay > 64) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "replay window size: %d -- must be 0 <= size <= 64\n",
+ pfkey_prop->sadb_prop_replay);
+ SENDERR(EINVAL);
+ }
+
+ for(i=0; i<3; i++) {
+ if(pfkey_prop->sadb_prop_reserved[i]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "res[%d]=%d, must be zero.\n",
+ i, pfkey_prop->sadb_prop_reserved[i]);
+ SENDERR(EINVAL);
+ }
+ }
+
+ num_comb = ((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) / sizeof(struct sadb_comb);
+
+ for(i = 0; i < num_comb; i++) {
+ if(pfkey_comb->sadb_comb_auth > SADB_AALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth=%d > SADB_AALG_MAX=%d.\n",
+ i,
+ pfkey_comb->sadb_comb_auth,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_auth) {
+ if(!pfkey_comb->sadb_comb_auth_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_minbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(!pfkey_comb->sadb_comb_auth_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_maxbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_auth_minbits > pfkey_comb->sadb_comb_auth_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_minbits=%d > maxbits=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_auth_minbits,
+ pfkey_comb->sadb_comb_auth_maxbits);
+ SENDERR(EINVAL);
+ }
+ } else {
+ if(pfkey_comb->sadb_comb_auth_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_minbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_auth_minbits);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_auth_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_maxbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_auth_maxbits);
+ SENDERR(EINVAL);
+ }
+ }
+
+ if(pfkey_comb->sadb_comb_encrypt > SADB_EALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_comb_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt=%d > SADB_EALG_MAX=%d.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_encrypt) {
+ if(!pfkey_comb->sadb_comb_encrypt_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(!pfkey_comb->sadb_comb_encrypt_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_encrypt_minbits > pfkey_comb->sadb_comb_encrypt_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d > maxbits=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt_minbits,
+ pfkey_comb->sadb_comb_encrypt_maxbits);
+ SENDERR(EINVAL);
+ }
+ } else {
+ if(pfkey_comb->sadb_comb_encrypt_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt_minbits);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_encrypt_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt_maxbits);
+ SENDERR(EINVAL);
+ }
+ }
+
+ /* XXX do sanity check on flags */
+
+ if(pfkey_comb->sadb_comb_hard_allocations && pfkey_comb->sadb_comb_soft_allocations > pfkey_comb->sadb_comb_hard_allocations) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_allocations=%d > hard_allocations=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_soft_allocations,
+ pfkey_comb->sadb_comb_hard_allocations);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_hard_bytes && pfkey_comb->sadb_comb_soft_bytes > pfkey_comb->sadb_comb_hard_bytes) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_bytes=%Ld > hard_bytes=%Ld, fatal.\n",
+ i,
+ (unsigned long long int)pfkey_comb->sadb_comb_soft_bytes,
+ (unsigned long long int)pfkey_comb->sadb_comb_hard_bytes);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_hard_addtime && pfkey_comb->sadb_comb_soft_addtime > pfkey_comb->sadb_comb_hard_addtime) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_addtime=%Ld > hard_addtime=%Ld, fatal.\n",
+ i,
+ (unsigned long long int)pfkey_comb->sadb_comb_soft_addtime,
+ (unsigned long long int)pfkey_comb->sadb_comb_hard_addtime);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_hard_usetime && pfkey_comb->sadb_comb_soft_usetime > pfkey_comb->sadb_comb_hard_usetime) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_usetime=%Ld > hard_usetime=%Ld, fatal.\n",
+ i,
+ (unsigned long long int)pfkey_comb->sadb_comb_soft_usetime,
+ (unsigned long long int)pfkey_comb->sadb_comb_hard_usetime);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_x_comb_hard_packets && pfkey_comb->sadb_x_comb_soft_packets > pfkey_comb->sadb_x_comb_hard_packets) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_x_comb_soft_packets=%d > hard_packets=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_x_comb_soft_packets,
+ pfkey_comb->sadb_x_comb_hard_packets);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "comb[%d].res=%d, must be zero.\n",
+ i,
+ pfkey_comb->sadb_comb_reserved);
+ SENDERR(EINVAL);
+ }
+ pfkey_comb++;
+ }
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_supported_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ unsigned int i, num_alg;
+ struct sadb_supported *pfkey_supported = (struct sadb_supported *)pfkey_ext;
+ struct sadb_alg *pfkey_alg = (struct sadb_alg*)((char*)pfkey_ext + sizeof(struct sadb_supported));
+
+ /* sanity checks... */
+ if((pfkey_supported->sadb_supported_len <
+ sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN) ||
+ (((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) -
+ sizeof(struct sadb_supported)) % sizeof(struct sadb_alg))) {
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "size wrong ext_len=%d, supported_ext_len=%d alg_ext_len=%d.\n",
+ pfkey_supported->sadb_supported_len,
+ (int)sizeof(struct sadb_supported),
+ (int)sizeof(struct sadb_alg));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_supported->sadb_supported_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_supported->sadb_supported_reserved);
+ SENDERR(EINVAL);
+ }
+
+ num_alg = ((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_supported)) / sizeof(struct sadb_alg);
+
+ for(i = 0; i < num_alg; i++) {
+ /* process algo description */
+ if(pfkey_alg->sadb_alg_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], id=%d, ivlen=%d, minbits=%d, maxbits=%d, res=%d, must be zero.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ pfkey_alg->sadb_alg_ivlen,
+ pfkey_alg->sadb_alg_minbits,
+ pfkey_alg->sadb_alg_maxbits,
+ pfkey_alg->sadb_alg_reserved);
+ SENDERR(EINVAL);
+ }
+
+ /* XXX can alg_id auth/enc be determined from info given?
+ Yes, but OpenBSD's method does not iteroperate with rfc2367.
+ rgb, 2000-04-06 */
+
+ switch(pfkey_supported->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ if(pfkey_alg->sadb_alg_id > SADB_AALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], alg_id=%d > SADB_AALG_MAX=%d, fatal.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ if(pfkey_alg->sadb_alg_id > SADB_EALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+ break;
+ default:
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+ pfkey_alg++;
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_spirange_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_spirange->sadb_spirange_len !=
+ sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_spirange->sadb_spirange_len,
+ (int)sizeof(struct sadb_spirange));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_spirange->sadb_spirange_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "reserved=%d must be set to zero.\n",
+ pfkey_spirange->sadb_spirange_reserved);
+ SENDERR(EINVAL);
+ }
+
+ if(ntohl(pfkey_spirange->sadb_spirange_max) < ntohl(pfkey_spirange->sadb_spirange_min)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "minspi=%08x must be < maxspi=%08x.\n",
+ ntohl(pfkey_spirange->sadb_spirange_min),
+ ntohl(pfkey_spirange->sadb_spirange_max));
+ SENDERR(EINVAL);
+ }
+
+ if(ntohl(pfkey_spirange->sadb_spirange_min) <= 255) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "minspi=%08x must be > 255.\n",
+ ntohl(pfkey_spirange->sadb_spirange_min));
+ SENDERR(EEXIST);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_spirange_parse: "
+ "ext_len=%u ext_type=%u(%s) min=%u max=%u res=%u.\n",
+ pfkey_spirange->sadb_spirange_len,
+ pfkey_spirange->sadb_spirange_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_spirange->sadb_spirange_exttype),
+ pfkey_spirange->sadb_spirange_min,
+ pfkey_spirange->sadb_spirange_max,
+ pfkey_spirange->sadb_spirange_reserved);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_kmprivate_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_x_kmprivate->sadb_x_kmprivate_len <
+ sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_kmprivate_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_x_kmprivate->sadb_x_kmprivate_len,
+ (int)sizeof(struct sadb_x_kmprivate));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_x_kmprivate->sadb_x_kmprivate_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_kmprivate_parse: "
+ "reserved=%d must be set to zero.\n",
+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_kmprivate_parse: "
+ "Sorry, I can't parse exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_satype_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_x_satype_parse: enter\n");
+ /* sanity checks... */
+ if(pfkey_x_satype->sadb_x_satype_len !=
+ sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_x_satype->sadb_x_satype_len,
+ (int)sizeof(struct sadb_x_satype));
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_x_satype->sadb_x_satype_satype) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "satype is zero, must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_x_satype->sadb_x_satype_satype > SADB_SATYPE_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "satype %d > max %d, invalid.\n",
+ pfkey_x_satype->sadb_x_satype_satype, SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(!(satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "proto lookup from satype=%d failed.\n",
+ pfkey_x_satype->sadb_x_satype_satype);
+ SENDERR(EINVAL);
+ }
+
+ for(i = 0; i < 3; i++) {
+ if(pfkey_x_satype->sadb_x_satype_reserved[i]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "reserved[%d]=%d must be set to zero.\n",
+ i, pfkey_x_satype->sadb_x_satype_reserved[i]);
+ SENDERR(EINVAL);
+ }
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_x_satype_parse: "
+ "len=%u ext=%u(%s) satype=%u(%s) res=%u,%u,%u.\n",
+ pfkey_x_satype->sadb_x_satype_len,
+ pfkey_x_satype->sadb_x_satype_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_x_satype->sadb_x_satype_exttype),
+ pfkey_x_satype->sadb_x_satype_satype,
+ satype2name(pfkey_x_satype->sadb_x_satype_satype),
+ pfkey_x_satype->sadb_x_satype_reserved[0],
+ pfkey_x_satype->sadb_x_satype_reserved[1],
+ pfkey_x_satype->sadb_x_satype_reserved[2]);
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_ext_debug_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_x_debug_parse: enter\n");
+ /* sanity checks... */
+ if(pfkey_x_debug->sadb_x_debug_len !=
+ sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_debug_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_x_debug->sadb_x_debug_len,
+ (int)sizeof(struct sadb_x_debug));
+ SENDERR(EINVAL);
+ }
+
+ for(i = 0; i < 4; i++) {
+ if(pfkey_x_debug->sadb_x_debug_reserved[i]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_debug_parse: "
+ "reserved[%d]=%d must be set to zero.\n",
+ i, pfkey_x_debug->sadb_x_debug_reserved[i]);
+ SENDERR(EINVAL);
+ }
+ }
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_ext_protocol_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_protocol *p = (struct sadb_protocol *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_protocol_parse:\n");
+ /* sanity checks... */
+
+ if (p->sadb_protocol_len != sizeof(*p)/IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_protocol_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
+ p->sadb_protocol_len, (int)sizeof(*p));
+ SENDERR(EINVAL);
+ }
+
+ if (p->sadb_protocol_reserved2 != 0) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_protocol_parse: res=%d, must be zero.\n",
+ p->sadb_protocol_reserved2);
+ SENDERR(EINVAL);
+ }
+
+ errlab:
+ return error;
+}
+
+#ifdef NAT_TRAVERSAL
+DEBUG_NO_STATIC int
+pfkey_x_ext_nat_t_type_parse(struct sadb_ext *pfkey_ext)
+{
+ return 0;
+}
+DEBUG_NO_STATIC int
+pfkey_x_ext_nat_t_port_parse(struct sadb_ext *pfkey_ext)
+{
+ return 0;
+}
+#endif
+
+#define DEFINEPARSER(NAME) static struct pf_key_ext_parsers_def NAME##_def={NAME, #NAME};
+
+DEFINEPARSER(pfkey_sa_parse);
+DEFINEPARSER(pfkey_lifetime_parse);
+DEFINEPARSER(pfkey_address_parse);
+DEFINEPARSER(pfkey_key_parse);
+DEFINEPARSER(pfkey_ident_parse);
+DEFINEPARSER(pfkey_sens_parse);
+DEFINEPARSER(pfkey_prop_parse);
+DEFINEPARSER(pfkey_supported_parse);
+DEFINEPARSER(pfkey_spirange_parse);
+DEFINEPARSER(pfkey_x_kmprivate_parse);
+DEFINEPARSER(pfkey_x_satype_parse);
+DEFINEPARSER(pfkey_x_ext_debug_parse);
+DEFINEPARSER(pfkey_x_ext_protocol_parse);
+#ifdef NAT_TRAVERSAL
+DEFINEPARSER(pfkey_x_ext_nat_t_type_parse);
+DEFINEPARSER(pfkey_x_ext_nat_t_port_parse);
+#endif
+
+struct pf_key_ext_parsers_def *ext_default_parsers[]=
+{
+ NULL, /* pfkey_msg_parse, */
+ &pfkey_sa_parse_def,
+ &pfkey_lifetime_parse_def,
+ &pfkey_lifetime_parse_def,
+ &pfkey_lifetime_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_key_parse_def,
+ &pfkey_key_parse_def,
+ &pfkey_ident_parse_def,
+ &pfkey_ident_parse_def,
+ &pfkey_sens_parse_def,
+ &pfkey_prop_parse_def,
+ &pfkey_supported_parse_def,
+ &pfkey_supported_parse_def,
+ &pfkey_spirange_parse_def,
+ &pfkey_x_kmprivate_parse_def,
+ &pfkey_x_satype_parse_def,
+ &pfkey_sa_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_x_ext_debug_parse_def,
+ &pfkey_x_ext_protocol_parse_def
+#ifdef NAT_TRAVERSAL
+ ,
+ &pfkey_x_ext_nat_t_type_parse_def,
+ &pfkey_x_ext_nat_t_port_parse_def,
+ &pfkey_x_ext_nat_t_port_parse_def,
+ &pfkey_address_parse_def
+#endif
+};
+
+int
+pfkey_msg_parse(struct sadb_msg *pfkey_msg,
+ struct pf_key_ext_parsers_def *ext_parsers[],
+ struct sadb_ext *extensions[],
+ int dir)
+{
+ int error = 0;
+ int remain;
+ struct sadb_ext *pfkey_ext;
+ int extensions_seen = 0;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_msg_parse: "
+ "parsing message ver=%d, type=%d(%s), errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n",
+ pfkey_msg->sadb_msg_version,
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
+ pfkey_msg->sadb_msg_errno,
+ pfkey_msg->sadb_msg_satype,
+ satype2name(pfkey_msg->sadb_msg_satype),
+ pfkey_msg->sadb_msg_len,
+ pfkey_msg->sadb_msg_reserved,
+ pfkey_msg->sadb_msg_seq,
+ pfkey_msg->sadb_msg_pid);
+
+ if(ext_parsers == NULL) ext_parsers = ext_default_parsers;
+
+ pfkey_extensions_init(extensions);
+
+ remain = pfkey_msg->sadb_msg_len;
+ remain -= sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_ext = (struct sadb_ext*)((char*)pfkey_msg +
+ sizeof(struct sadb_msg));
+
+ extensions[0] = (struct sadb_ext *) pfkey_msg;
+
+
+ if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "not PF_KEY_V2 msg, found %d, should be %d.\n",
+ pfkey_msg->sadb_msg_version,
+ PF_KEY_V2);
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_msg->sadb_msg_type) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "msg type not set, must be non-zero..\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_msg->sadb_msg_type > SADB_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "msg type=%d > max=%d.\n",
+ pfkey_msg->sadb_msg_type,
+ SADB_MAX);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_msg->sadb_msg_type) {
+ case SADB_GETSPI:
+ case SADB_UPDATE:
+ case SADB_ADD:
+ case SADB_DELETE:
+ case SADB_GET:
+ case SADB_X_GRPSA:
+ case SADB_X_ADDFLOW:
+ if(!satype2proto(pfkey_msg->sadb_msg_satype)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "satype %d conversion to proto failed for msg_type %d (%s).\n",
+ pfkey_msg->sadb_msg_satype,
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
+ SENDERR(EINVAL);
+ } else {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "satype %d(%s) conversion to proto gives %d for msg_type %d(%s).\n",
+ pfkey_msg->sadb_msg_satype,
+ satype2name(pfkey_msg->sadb_msg_satype),
+ satype2proto(pfkey_msg->sadb_msg_satype),
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
+ }
+ case SADB_ACQUIRE:
+ case SADB_REGISTER:
+ case SADB_EXPIRE:
+ if(!pfkey_msg->sadb_msg_satype) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "satype is zero, must be non-zero for msg_type %d(%s).\n",
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
+ SENDERR(EINVAL);
+ }
+ default:
+ break;
+ }
+
+ /* errno must not be set in downward messages */
+ /* this is not entirely true... a response to an ACQUIRE could return an error */
+ if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type != SADB_ACQUIRE) && pfkey_msg->sadb_msg_errno) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "errno set to %d.\n",
+ pfkey_msg->sadb_msg_errno);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "remain=%d, ext_type=%d(%s), ext_len=%d.\n",
+ remain,
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ pfkey_ext->sadb_ext_len);
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "extensions permitted=%08x, required=%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
+
+ extensions_seen = 1;
+
+ while( (remain * IPSEC_PFKEYv2_ALIGN) >= sizeof(struct sadb_ext) ) {
+ /* Is there enough message left to support another extension header? */
+ if(remain < pfkey_ext->sadb_ext_len) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "remain %d less than ext len %d.\n",
+ remain, pfkey_ext->sadb_ext_len);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "parsing ext type=%d(%s) remain=%d.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ remain);
+
+ /* Is the extension header type valid? */
+ if((pfkey_ext->sadb_ext_type > SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) invalid, SADB_EXT_MAX=%d.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ SADB_EXT_MAX);
+ SENDERR(EINVAL);
+ }
+
+ /* Have we already seen this type of extension? */
+ if((extensions_seen & ( 1 << pfkey_ext->sadb_ext_type )) != 0)
+ {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) already seen.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
+ SENDERR(EINVAL);
+ }
+
+ /* Do I even know about this type of extension? */
+ if(ext_parsers[pfkey_ext->sadb_ext_type]==NULL) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) unknown, ignoring.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
+ goto next_ext;
+ }
+
+ /* Is this type of extension permitted for this type of message? */
+ if(!(extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type] &
+ 1<<pfkey_ext->sadb_ext_type)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) not permitted, exts_perm_in=%08x, 1<<type=%08x\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
+ 1<<pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_msg_parse: "
+ "remain=%d ext_type=%d(%s) ext_len=%d parsing ext 0p%p with parser %s.\n",
+ remain,
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ pfkey_ext->sadb_ext_len,
+ pfkey_ext,
+ ext_parsers[pfkey_ext->sadb_ext_type]->parser_name);
+
+ /* Parse the extension */
+ if((error =
+ (*ext_parsers[pfkey_ext->sadb_ext_type]->parser)(pfkey_ext))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "extension parsing for type %d(%s) failed with error %d.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ error);
+ SENDERR(-error);
+ }
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "Extension %d(%s) parsed.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
+
+ /* Mark that we have seen this extension and remember the header location */
+ extensions_seen |= ( 1 << pfkey_ext->sadb_ext_type );
+ extensions[pfkey_ext->sadb_ext_type] = pfkey_ext;
+
+ next_ext:
+ /* Calculate how much message remains */
+ remain -= pfkey_ext->sadb_ext_len;
+
+ if(!remain) {
+ break;
+ }
+ /* Find the next extension header */
+ pfkey_ext = (struct sadb_ext*)((char*)pfkey_ext +
+ pfkey_ext->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+ }
+
+ if(remain) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "unexpected remainder of %d.\n",
+ remain);
+ /* why is there still something remaining? */
+ SENDERR(EINVAL);
+ }
+
+ /* check required extensions */
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_msg_parse: "
+ "extensions permitted=%08x, seen=%08x, required=%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
+ extensions_seen,
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
+
+ /* don't check further if it is an error return message since it
+ may not have a body */
+ if(pfkey_msg->sadb_msg_errno) {
+ SENDERR(-error);
+ }
+
+ if((extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) !=
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "required extensions missing:%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type] -
+ (extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]));
+ SENDERR(EINVAL);
+ }
+
+ if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type == SADB_X_DELFLOW)
+ && ((extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW)
+ != SADB_X_EXT_ADDRESS_DELFLOW)
+ && (((extensions_seen & (1<<SADB_EXT_SA)) != (1<<SADB_EXT_SA))
+ || ((((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_flags
+ & SADB_X_SAFLAGS_CLEARFLOW)
+ != SADB_X_SAFLAGS_CLEARFLOW))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "required SADB_X_DELFLOW extensions missing: either %08x must be present or %08x must be present with SADB_X_SAFLAGS_CLEARFLOW set.\n",
+ SADB_X_EXT_ADDRESS_DELFLOW
+ - (extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW),
+ (1<<SADB_EXT_SA) - (extensions_seen & (1<<SADB_EXT_SA)));
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_msg->sadb_msg_type) {
+ case SADB_ADD:
+ case SADB_UPDATE:
+ /* check maturity */
+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state !=
+ SADB_SASTATE_MATURE) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "state=%d for add or update should be MATURE=%d.\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
+ SADB_SASTATE_MATURE);
+ SENDERR(EINVAL);
+ }
+
+ /* check AH and ESP */
+ switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) {
+ case SADB_SATYPE_AH:
+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth !=
+ SADB_AALG_NONE)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "auth alg is zero, must be non-zero for AH SAs.\n");
+ SENDERR(EINVAL);
+ }
+ if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt !=
+ SADB_EALG_NONE) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "AH handed encalg=%d, must be zero.\n",
+ ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt);
+ SENDERR(EINVAL);
+ }
+ break;
+ case SADB_SATYPE_ESP:
+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
+ SADB_EALG_NONE)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
+ SENDERR(EINVAL);
+ }
+ if((((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt ==
+ SADB_EALG_NULL) &&
+ (((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth ==
+ SADB_AALG_NONE) ) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ESP handed encNULL+authNONE, illegal combination.\n");
+ SENDERR(EINVAL);
+ }
+ break;
+ case SADB_X_SATYPE_COMP:
+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
+ SADB_EALG_NONE)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "encrypt alg=%d is zero, must be non-zero for COMP=%d SAs.\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
+ SENDERR(EINVAL);
+ }
+ if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth !=
+ SADB_AALG_NONE) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "COMP handed auth=%d, must be zero.\n",
+ ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth);
+ SENDERR(EINVAL);
+ }
+ break;
+ default:
+ break;
+ }
+ if(ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "spi=%08x must be > 255.\n",
+ ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi));
+ SENDERR(EINVAL);
+ }
+ default:
+ break;
+ }
+errlab:
+
+ return error;
+}
+
+/*
+ * $Log: pfkey_v2_parse.c,v $
+ * Revision 1.4 2004/06/13 20:35:07 as
+ * removed references to ipsec_netlink.h
+ *
+ * Revision 1.3 2004/03/30 10:00:17 as
+ * 64 bit issues
+ *
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.53 2003/01/30 02:32:09 rgb
+ *
+ * Rename SAref table macro names for clarity.
+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
+ *
+ * Revision 1.52 2002/12/30 06:53:07 mcr
+ * deal with short SA structures... #if 0 out for now. Probably
+ * not quite the right way.
+ *
+ * Revision 1.51 2002/12/13 18:16:02 mcr
+ * restored sa_ref code
+ *
+ * Revision 1.50 2002/12/13 18:06:52 mcr
+ * temporarily removed sadb_x_sa_ref reference for 2.xx
+ *
+ * Revision 1.49 2002/10/05 05:02:58 dhr
+ *
+ * C labels go on statements
+ *
+ * Revision 1.48 2002/09/20 15:40:45 rgb
+ * Added sadb_x_sa_ref to struct sadb_sa.
+ *
+ * Revision 1.47 2002/09/20 05:01:31 rgb
+ * Fixed usage of pfkey_lib_debug.
+ * Format for function declaration style consistency.
+ * Added text labels to elucidate numeric values presented.
+ * Re-organised debug output to reduce noise in output.
+ *
+ * Revision 1.46 2002/07/24 18:44:54 rgb
+ * Type fiddling to tame ia64 compiler.
+ *
+ * Revision 1.45 2002/05/23 07:14:11 rgb
+ * Cleaned up %p variants to 0p%p for test suite cleanup.
+ *
+ * Revision 1.44 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.43 2002/04/24 07:36:40 mcr
+ * Moved from ./lib/pfkey_v2_parse.c,v
+ *
+ * Revision 1.42 2002/01/29 22:25:36 rgb
+ * Re-add ipsec_kversion.h to keep MALLOC happy.
+ *
+ * Revision 1.41 2002/01/29 01:59:10 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ * Revision 1.40 2002/01/20 20:34:50 mcr
+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
+ *
+ * Revision 1.39 2001/11/27 05:29:22 mcr
+ * pfkey parses are now maintained by a structure
+ * that includes their name for debug purposes.
+ * DEBUGGING() macro changed so that it takes a debug
+ * level so that pf_key() can use this to decode the
+ * structures without innundanting humans.
+ * Also uses pfkey_v2_sadb_ext_string() in messages.
+ *
+ * Revision 1.38 2001/11/06 19:47:47 rgb
+ * Added packet parameter to lifetime and comb structures.
+ *
+ * Revision 1.37 2001/10/18 04:45:24 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.36 2001/06/14 19:35:16 rgb
+ * Update copyright date.
+ *
+ * Revision 1.35 2001/05/03 19:44:51 rgb
+ * Standardise on SENDERR() macro.
+ *
+ * Revision 1.34 2001/03/16 07:41:51 rgb
+ * Put freeswan.h include before pluto includes.
+ *
+ * Revision 1.33 2001/02/27 07:13:51 rgb
+ * Added satype2name() function.
+ * Added text to default satype_tbl entry.
+ * Added satype2name() conversions for most satype debug output.
+ *
+ * Revision 1.32 2001/02/26 20:01:09 rgb
+ * Added internal IP protocol 61 for magic SAs.
+ * Ditch unused sadb_satype2proto[], replaced by satype2proto().
+ * Re-formatted debug output (split lines, consistent spacing).
+ * Removed acquire, register and expire requirements for a known satype.
+ * Changed message type checking to a switch structure.
+ * Verify expected NULL auth for IPCOMP.
+ * Enforced spi > 0x100 requirement, now that pass uses a magic SA for
+ * appropriate message types.
+ *
+ * Revision 1.31 2000/12/01 07:09:00 rgb
+ * Added ipcomp sanity check to require encalgo is set.
+ *
+ * Revision 1.30 2000/11/17 18:10:30 rgb
+ * Fixed bugs mostly relating to spirange, to treat all spi variables as
+ * network byte order since this is the way PF_KEYv2 stored spis.
+ *
+ * Revision 1.29 2000/10/12 00:02:39 rgb
+ * Removed 'format, ##' nonsense from debug macros for RH7.0.
+ *
+ * Revision 1.28 2000/09/20 16:23:04 rgb
+ * Remove over-paranoid extension check in the presence of sadb_msg_errno.
+ *
+ * Revision 1.27 2000/09/20 04:04:21 rgb
+ * Changed static functions to DEBUG_NO_STATIC to reveal function names in
+ * oopsen.
+ *
+ * Revision 1.26 2000/09/15 11:37:02 rgb
+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+ * IPCOMP zlib deflate code.
+ *
+ * Revision 1.25 2000/09/12 22:35:37 rgb
+ * Restructured to remove unused extensions from CLEARFLOW messages.
+ *
+ * Revision 1.24 2000/09/12 18:59:54 rgb
+ * Added Gerhard's IPv6 support to pfkey parts of libfreeswan.
+ *
+ * Revision 1.23 2000/09/12 03:27:00 rgb
+ * Moved DEBUGGING definition to compile kernel with debug off.
+ *
+ * Revision 1.22 2000/09/09 06:39:27 rgb
+ * Restrict pfkey errno check to downward messages only.
+ *
+ * Revision 1.21 2000/09/08 19:22:34 rgb
+ * Enabled pfkey_sens_parse().
+ * Added check for errno on downward acquire messages only.
+ *
+ * Revision 1.20 2000/09/01 18:48:23 rgb
+ * Fixed reserved check bug and added debug output in
+ * pfkey_supported_parse().
+ * Fixed debug output label bug in pfkey_ident_parse().
+ *
+ * Revision 1.19 2000/08/27 01:55:26 rgb
+ * Define OCTETBITS and PFKEYBITS to avoid using 'magic' numbers in code.
+ *
+ * Revision 1.18 2000/08/24 17:00:36 rgb
+ * Ignore unknown extensions instead of failing.
+ *
+ * Revision 1.17 2000/06/02 22:54:14 rgb
+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
+ *
+ * Revision 1.16 2000/05/10 19:25:11 rgb
+ * Fleshed out proposal and supported extensions.
+ *
+ * Revision 1.15 2000/01/24 21:15:31 rgb
+ * Added disabled pluto pfkey lib debug flag.
+ * Added algo debugging reporting.
+ *
+ * Revision 1.14 2000/01/22 23:24:29 rgb
+ * Added new functions proto2satype() and satype2proto() and lookup
+ * table satype_tbl. Also added proto2name() since it was easy.
+ *
+ * Revision 1.13 2000/01/21 09:43:59 rgb
+ * Cast ntohl(spi) as (unsigned long int) to shut up compiler.
+ *
+ * Revision 1.12 2000/01/21 06:28:19 rgb
+ * Added address cases for eroute flows.
+ * Indented compiler directives for readability.
+ * Added klipsdebug switching capability.
+ *
+ * Revision 1.11 1999/12/29 21:14:59 rgb
+ * Fixed debug text cut and paste typo.
+ *
+ * Revision 1.10 1999/12/10 17:45:24 rgb
+ * Added address debugging.
+ *
+ * Revision 1.9 1999/12/09 23:11:42 rgb
+ * Ditched <string.h> include since we no longer use memset().
+ * Use new pfkey_extensions_init() instead of memset().
+ * Added check for SATYPE in pfkey_msg_build().
+ * Tidy up comments and debugging comments.
+ *
+ * Revision 1.8 1999/12/07 19:55:26 rgb
+ * Removed unused first argument from extension parsers.
+ * Removed static pluto debug flag.
+ * Moved message type and state checking to pfkey_msg_parse().
+ * Changed print[fk] type from lx to x to quiet compiler.
+ * Removed redundant remain check.
+ * Changed __u* types to uint* to avoid use of asm/types.h and
+ * sys/types.h in userspace code.
+ *
+ * Revision 1.7 1999/12/01 22:20:51 rgb
+ * Moved pfkey_lib_debug variable into the library.
+ * Added pfkey version check into header parsing.
+ * Added check for SATYPE only for those extensions that require a
+ * non-zero value.
+ *
+ * Revision 1.6 1999/11/27 11:58:05 rgb
+ * Added ipv6 headers.
+ * Moved sadb_satype2proto protocol lookup table from
+ * klips/net/ipsec/pfkey_v2_parser.c.
+ * Enable lifetime_current checking.
+ * Debugging error messages added.
+ * Add argument to pfkey_msg_parse() for direction.
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ * Add CVS log entry to bottom of file.
+ * Moved auth and enc alg check to pfkey_msg_parse().
+ * Enable accidentally disabled spirange parsing.
+ * Moved protocol/algorithm checks from klips/net/ipsec/pfkey_v2_parser.c
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/lib/libfreeswan/portof.3 b/linux/lib/libfreeswan/portof.3
new file mode 100644
index 000000000..fac0d8bc3
--- /dev/null
+++ b/linux/lib/libfreeswan/portof.3
@@ -0,0 +1,70 @@
+.TH IPSEC_PORTOF 3 "8 Sept 2000"
+.\" RCSID $Id: portof.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec portof \- get port field of an ip_address
+.br
+ipsec setportof \- set port field of an ip_address
+.br
+ipsec sockaddrof \- get pointer to internal sockaddr of an ip_address
+.br
+ipsec sockaddrlenof \- get length of internal sockaddr of an ip_address
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "int portof(const ip_address *src);"
+.br
+.B "void setportof(int port, ip_address *dst);"
+.br
+.B "struct sockaddr *sockaddrof(ip_address *src);"
+.br
+.B "size_t sockaddrlenof(const ip_address *src);"
+.SH DESCRIPTION
+The
+.B <freeswan.h>
+internal type
+.I ip_address
+contains one of the
+.I sockaddr
+types internally.
+\fIReliance on this feature is discouraged\fR,
+but it may occasionally be necessary.
+These functions provide low-level tools for this purpose.
+.PP
+.I Portof
+and
+.I setportof
+respectively read and write the port-number field of the internal
+.IR sockaddr .
+The values are in network byte order.
+.PP
+.I Sockaddrof
+returns a pointer to the internal
+.IR sockaddr ,
+for passing to other functions.
+.PP
+.I Sockaddrlenof
+reports the size of the internal
+.IR sockaddr ,
+for use in storage allocation.
+.SH SEE ALSO
+inet(3), ipsec_initaddr(3)
+.SH DIAGNOSTICS
+.I Portof
+returns
+.BR \-1 ,
+.I sockaddrof
+returns
+.BR NULL ,
+and
+.I sockaddrlenof
+returns
+.B 0
+if an unknown address family is found within the
+.IR ip_address .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+These functions all depend on low-level details of the
+.I ip_address
+type, which are in principle subject to change.
+Avoid using them unless really necessary.
diff --git a/linux/lib/libfreeswan/portof.c b/linux/lib/libfreeswan/portof.c
new file mode 100644
index 000000000..d028ea034
--- /dev/null
+++ b/linux/lib/libfreeswan/portof.c
@@ -0,0 +1,96 @@
+/*
+ * low-level ip_address ugliness
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: portof.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - portof - get the port field of an ip_address
+ */
+int /* network order */
+portof(src)
+const ip_address *src;
+{
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ return src->u.v4.sin_port;
+ break;
+ case AF_INET6:
+ return src->u.v6.sin6_port;
+ break;
+ default:
+ return -1; /* "can't happen" */
+ break;
+ }
+}
+
+/*
+ - setportof - set the port field of an ip_address
+ */
+void
+setportof(port, dst)
+int port; /* network order */
+ip_address *dst;
+{
+ switch (dst->u.v4.sin_family) {
+ case AF_INET:
+ dst->u.v4.sin_port = port;
+ break;
+ case AF_INET6:
+ dst->u.v6.sin6_port = port;
+ break;
+ }
+}
+
+/*
+ - sockaddrof - get a pointer to the sockaddr hiding inside an ip_address
+ */
+struct sockaddr *
+sockaddrof(src)
+ip_address *src;
+{
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ return (struct sockaddr *)&src->u.v4;
+ break;
+ case AF_INET6:
+ return (struct sockaddr *)&src->u.v6;
+ break;
+ default:
+ return NULL; /* "can't happen" */
+ break;
+ }
+}
+
+/*
+ - sockaddrlenof - get length of the sockaddr hiding inside an ip_address
+ */
+size_t /* 0 for error */
+sockaddrlenof(src)
+const ip_address *src;
+{
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ return sizeof(src->u.v4);
+ break;
+ case AF_INET6:
+ return sizeof(src->u.v6);
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
diff --git a/linux/lib/libfreeswan/prng.3 b/linux/lib/libfreeswan/prng.3
new file mode 100644
index 000000000..51f19364f
--- /dev/null
+++ b/linux/lib/libfreeswan/prng.3
@@ -0,0 +1,121 @@
+.TH IPSEC_PRNG 3 "1 April 2002"
+.\" RCSID $Id: prng.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec prng_init \- initialize IPsec pseudorandom-number generator
+.br
+ipsec prng_bytes \- get bytes from IPsec pseudorandom-number generator
+.br
+ipsec prng_final \- close down IPsec pseudorandom-number generator
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "void prng_init(struct prng *prng,"
+.ti +1c
+.B "const unsigned char *key, size_t keylen);"
+.br
+.B "void prng_bytes(struct prng *prng, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.br
+.B "unsigned long prng_count(struct prng *prng);"
+.br
+.B "void prng_final(struct prng *prng);"
+.SH DESCRIPTION
+.I Prng_init
+initializes a crypto-quality pseudo-random-number generator from a key;
+.I prng_bytes
+obtains pseudo-random bytes from it;
+.I prng_count
+reports the number of bytes extracted from it to date;
+.I prng_final
+closes it down.
+It is the user's responsibility to initialize a PRNG before using it,
+and not to use it again after it is closed down.
+.PP
+.I Prng_init
+initializes,
+or re-initializes,
+the specified
+.I prng
+from the
+.IR key ,
+whose length is given by
+.IR keylen .
+The user must allocate the
+.B "struct prng"
+pointed to by
+.IR prng .
+There is no particular constraint on the length of the key,
+although a key longer than 256 bytes is unnecessary because
+only the first 256 would be used.
+Initialization requires on the order of 3000 integer operations,
+independent of key length.
+.PP
+.I Prng_bytes
+obtains
+.I dstlen
+pseudo-random bytes from the PRNG and puts them in
+.IR buf .
+This is quite fast,
+on the order of 10 integer operations per byte.
+.PP
+.I Prng_count
+reports the number of bytes obtained from the PRNG
+since it was (last) initialized.
+.PP
+.I Prng_final
+closes down a PRNG by
+zeroing its internal memory,
+obliterating all trace of the state used to generate its previous output.
+This requires on the order of 250 integer operations.
+.PP
+The
+.B <freeswan.h>
+header file supplies the definition of the
+.B prng
+structure.
+Examination of its innards is discouraged, as they may change.
+.PP
+The PRNG algorithm
+used by these functions is currently identical to that of RC4(TM).
+This algorithm is cryptographically strong,
+sufficiently unpredictable that even a hostile observer will
+have difficulty determining the next byte of output from past history,
+provided it is initialized from a reasonably large key composed of
+highly random bytes (see
+.IR random (4)).
+The usual run of software pseudo-random-number generators
+(e.g.
+.IR random (3))
+are
+.I not
+cryptographically strong.
+.PP
+The well-known attacks against RC4(TM),
+e.g. as found in 802.11b's WEP encryption system,
+apply only if multiple PRNGs are initialized with closely-related keys
+(e.g., using a counter appended to a base key).
+If such keys are used, the first few hundred pseudo-random bytes
+from each PRNG should be discarded,
+to give the PRNGs a chance to randomize their innards properly.
+No useful attacks are known if the key is well randomized to begin with.
+.SH SEE ALSO
+random(3), random(4)
+.br
+Bruce Schneier,
+\fIApplied Cryptography\fR, 2nd ed., 1996, ISBN 0-471-11709-9,
+pp. 397-8.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+If an attempt is made to obtain more than 4e9 bytes
+between initializations,
+the PRNG will continue to work but
+.IR prng_count 's
+output will stick at
+.BR 4000000000 .
+Fixing this would require a longer integer type and does
+not seem worth the trouble,
+since you should probably re-initialize before then anyway...
+.PP
+``RC4'' is a trademark of RSA Data Security, Inc.
diff --git a/linux/lib/libfreeswan/prng.c b/linux/lib/libfreeswan/prng.c
new file mode 100644
index 000000000..e31836783
--- /dev/null
+++ b/linux/lib/libfreeswan/prng.c
@@ -0,0 +1,202 @@
+/*
+ * crypto-class pseudorandom number generator
+ * currently uses same algorithm as RC4(TM), from Schneier 2nd ed p397
+ * Copyright (C) 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: prng.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - prng_init - initialize PRNG from a key
+ */
+void
+prng_init(prng, key, keylen)
+struct prng *prng;
+const unsigned char *key;
+size_t keylen;
+{
+ unsigned char k[256];
+ int i, j;
+ unsigned const char *p;
+ unsigned const char *keyend = key + keylen;
+ unsigned char t;
+
+ for (i = 0; i <= 255; i++)
+ prng->sbox[i] = i;
+ p = key;
+ for (i = 0; i <= 255; i++) {
+ k[i] = *p++;
+ if (p >= keyend)
+ p = key;
+ }
+ j = 0;
+ for (i = 0; i <= 255; i++) {
+ j = (j + prng->sbox[i] + k[i]) & 0xff;
+ t = prng->sbox[i];
+ prng->sbox[i] = prng->sbox[j];
+ prng->sbox[j] = t;
+ k[i] = 0; /* clear out key memory */
+ }
+ prng->i = 0;
+ prng->j = 0;
+ prng->count = 0;
+}
+
+/*
+ - prng_bytes - get some pseudorandom bytes from PRNG
+ */
+void
+prng_bytes(prng, dst, dstlen)
+struct prng *prng;
+unsigned char *dst;
+size_t dstlen;
+{
+ int i, j, t;
+ unsigned char *p = dst;
+ size_t remain = dstlen;
+# define MAX 4000000000ul
+
+ while (remain > 0) {
+ i = (prng->i + 1) & 0xff;
+ prng->i = i;
+ j = (prng->j + prng->sbox[i]) & 0xff;
+ prng->j = j;
+ t = prng->sbox[i];
+ prng->sbox[i] = prng->sbox[j];
+ prng->sbox[j] = t;
+ t = (t + prng->sbox[i]) & 0xff;
+ *p++ = prng->sbox[t];
+ remain--;
+ }
+ if (prng->count < MAX - dstlen)
+ prng->count += dstlen;
+ else
+ prng->count = MAX;
+}
+
+/*
+ - prnt_count - how many bytes have been extracted from PRNG so far?
+ */
+unsigned long
+prng_count(prng)
+struct prng *prng;
+{
+ return prng->count;
+}
+
+/*
+ - prng_final - clear out PRNG to ensure nothing left in memory
+ */
+void
+prng_final(prng)
+struct prng *prng;
+{
+ int i;
+
+ for (i = 0; i <= 255; i++)
+ prng->sbox[i] = 0;
+ prng->i = 0;
+ prng->j = 0;
+ prng->count = 0; /* just for good measure */
+}
+
+
+
+#ifdef PRNG_MAIN
+
+#include <stdio.h>
+
+void regress();
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ struct prng pr;
+ unsigned char buf[100];
+ unsigned char *p;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {key|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ prng_init(&pr, argv[1], strlen(argv[1]));
+ prng_bytes(&pr, buf, 32);
+ printf("0x");
+ for (p = buf, n = 32; n > 0; p++, n--)
+ printf("%02x", *p);
+ printf("\n%lu bytes\n", prng_count(&pr));
+ prng_final(&pr);
+ exit(0);
+}
+
+void
+regress()
+{
+ struct prng pr;
+ unsigned char buf[100];
+ unsigned char *p;
+ size_t n;
+ /* somewhat non-random sample key */
+ unsigned char key[] = "here we go gathering nuts in May";
+ /* first thirty bytes of output from that key */
+ unsigned char good[] = "\x3f\x02\x8e\x4a\x2a\xea\x23\x18\x92\x7c"
+ "\x09\x52\x83\x61\xaa\x26\xce\xbb\x9d\x71"
+ "\x71\xe5\x10\x22\xaf\x60\x54\x8d\x5b\x28";
+ int nzero, none;
+ int show = 0;
+
+ prng_init(&pr, key, strlen(key));
+ prng_bytes(&pr, buf, sizeof(buf));
+ for (p = buf, n = sizeof(buf); n > 0; p++, n--) {
+ if (*p == 0)
+ nzero++;
+ if (*p == 255)
+ none++;
+ }
+ if (nzero > 3 || none > 3) {
+ fprintf(stderr, "suspiciously non-random output!\n");
+ show = 1;
+ }
+ if (memcmp(buf, good, strlen(good)) != 0) {
+ fprintf(stderr, "incorrect output!\n");
+ show = 1;
+ }
+ if (show) {
+ fprintf(stderr, "0x");
+ for (p = buf, n = sizeof(buf); n > 0; p++, n--)
+ fprintf(stderr, "%02x", *p);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+ if (prng_count(&pr) != sizeof(buf)) {
+ fprintf(stderr, "got %u bytes, but count is %lu\n",
+ sizeof(buf), prng_count(&pr));
+ exit(1);
+ }
+ prng_final(&pr);
+ exit(0);
+}
+
+#endif /* PRNG_MAIN */
diff --git a/linux/lib/libfreeswan/rangetoa.c b/linux/lib/libfreeswan/rangetoa.c
new file mode 100644
index 000000000..e63b432f8
--- /dev/null
+++ b/linux/lib/libfreeswan/rangetoa.c
@@ -0,0 +1,61 @@
+/*
+ * convert binary form of address range to ASCII
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: rangetoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - rangetoa - convert address range to ASCII
+ */
+size_t /* space needed for full conversion */
+rangetoa(addrs, format, dst, dstlen)
+struct in_addr addrs[2];
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len;
+ size_t rest;
+ int n;
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = addrtoa(addrs[0], 0, dst, dstlen);
+ if (len < dstlen)
+ for (p = dst + len - 1, n = 3; len < dstlen && n > 0;
+ p++, len++, n--)
+ *p = '.';
+ else
+ p = NULL;
+ if (len < dstlen)
+ rest = dstlen - len;
+ else {
+ if (dstlen > 0)
+ *(dst + dstlen - 1) = '\0';
+ rest = 0;
+ }
+
+ len += addrtoa(addrs[1], 0, p, rest);
+
+ return len;
+}
diff --git a/linux/lib/libfreeswan/rangetosubnet.3 b/linux/lib/libfreeswan/rangetosubnet.3
new file mode 100644
index 000000000..7d707545e
--- /dev/null
+++ b/linux/lib/libfreeswan/rangetosubnet.3
@@ -0,0 +1,59 @@
+.TH IPSEC_RANGETOSUBNET 3 "8 Sept 2000"
+.\" RCSID $Id: rangetosubnet.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec rangetosubnet \- convert address range to subnet
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *rangetosubnet(const ip_address *start,"
+.ti +1c
+.B "const ip_address *stop, ip_subnet *dst);"
+.SH DESCRIPTION
+.I Rangetosubnet
+accepts two IP addresses which define an address range,
+from
+.I start
+to
+.I stop
+inclusive,
+and converts this to a subnet if possible.
+The addresses must both be IPv4 or both be IPv6,
+and the address family of the resulting subnet is the same.
+.PP
+.I Rangetosubnet
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.SH SEE ALSO
+ipsec_initsubnet(3), ipsec_ttosubnet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I rangetosubnet
+are:
+mixed address families;
+unknown address family;
+.I start
+and
+.I stop
+do not define a subnet.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = rangetosubnet( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/rangetosubnet.c b/linux/lib/libfreeswan/rangetosubnet.c
new file mode 100644
index 000000000..048b10556
--- /dev/null
+++ b/linux/lib/libfreeswan/rangetosubnet.c
@@ -0,0 +1,226 @@
+/*
+ * express an address range as a subnet (if possible)
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: rangetosubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - rangetosubnet - turn an address range into a subnet, if possible
+ *
+ * A range which is a valid subnet will have a network part which is the
+ * same in the from value and the to value, followed by a host part which
+ * is all 0 in the from value and all 1 in the to value.
+ */
+err_t
+rangetosubnet(from, to, dst)
+const ip_address *from;
+const ip_address *to;
+ip_subnet *dst;
+{
+ unsigned const char *fp;
+ unsigned const char *tp;
+ unsigned fb;
+ unsigned tb;
+ unsigned const char *f;
+ unsigned const char *t;
+ size_t n;
+ size_t n2;
+ int i;
+ int nnet;
+ unsigned m;
+
+ if (addrtypeof(from) != addrtypeof(to))
+ return "mismatched address types";
+ n = addrbytesptr(from, &fp);
+ if (n == 0)
+ return "unknown address type";
+ n2 = addrbytesptr(to, &tp);
+ if (n != n2)
+ return "internal size mismatch in rangetosubnet";
+
+ f = fp;
+ t = tp;
+ nnet = 0;
+ for (i = n; i > 0 && *f == *t; i--, f++, t++)
+ nnet += 8;
+ if (i > 0 && !(*f == 0x00 && *t == 0xff)) { /* mid-byte bdry. */
+ fb = *f++;
+ tb = *t++;
+ i--;
+ m = 0x80;
+ while ((fb&m) == (tb&m)) {
+ fb &= ~m;
+ tb |= m;
+ m >>= 1;
+ nnet++;
+ }
+ if (fb != 0x00 || tb != 0xff)
+ return "not a valid subnet";
+ }
+ for (; i > 0 && *f == 0x00 && *t == 0xff; i--, f++, t++)
+ continue;
+
+ if (i != 0)
+ return "invalid subnet";
+
+ return initsubnet(from, nnet, 'x', dst);
+}
+
+
+
+#ifdef RANGETOSUBNET_MAIN
+
+#include <stdio.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ ip_address start;
+ ip_address stop;
+ ip_subnet sub;
+ char buf[100];
+ const char *oops;
+ size_t n;
+ int af;
+ int i;
+
+ if (argc == 2 && strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s [-6] start stop\n", argv[0]);
+ fprintf(stderr, " or: %s -r\n", argv[0]);
+ exit(2);
+ }
+
+ af = AF_INET;
+ i = 1;
+ if (strcmp(argv[i], "-6") == 0) {
+ af = AF_INET6;
+ i++;
+ }
+
+ oops = ttoaddr(argv[i], 0, af, &start);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: start conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ oops = ttoaddr(argv[i+1], 0, af, &stop);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: stop conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ oops = rangetosubnet(&start, &stop, &sub);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: rangetosubnet failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = subnettot(&sub, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion", argv[0]);
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ int family;
+ char *start;
+ char *stop;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {4, "1.2.3.0", "1.2.3.255", "1.2.3.0/24"},
+ {4, "1.2.3.0", "1.2.3.7", "1.2.3.0/29"},
+ {4, "1.2.3.240", "1.2.3.255", "1.2.3.240/28"},
+ {4, "0.0.0.0", "255.255.255.255", "0.0.0.0/0"},
+ {4, "1.2.3.4", "1.2.3.4", "1.2.3.4/32"},
+ {4, "1.2.3.0", "1.2.3.254", NULL},
+ {4, "1.2.3.0", "1.2.3.126", NULL},
+ {4, "1.2.3.0", "1.2.3.125", NULL},
+ {4, "1.2.0.0", "1.2.255.255", "1.2.0.0/16"},
+ {4, "1.2.0.0", "1.2.0.255", "1.2.0.0/24"},
+ {4, "1.2.255.0", "1.2.255.255", "1.2.255.0/24"},
+ {4, "1.2.255.0", "1.2.254.255", NULL},
+ {4, "1.2.255.1", "1.2.255.255", NULL},
+ {4, "1.2.0.1", "1.2.255.255", NULL},
+ {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:ffff", "1:2:3:4:5:6:7:0/112"},
+ {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:fff", "1:2:3:4:5:6:7:0/116"},
+ {6, "1:2:3:4:5:6:7:f0", "1:2:3:4:5:6:7:ff", "1:2:3:4:5:6:7:f0/124"},
+ {4, NULL, NULL, NULL},
+};
+
+void
+regress()
+{
+ struct rtab *r;
+ int status = 0;
+ ip_address start;
+ ip_address stop;
+ ip_subnet sub;
+ char buf[100];
+ const char *oops;
+ size_t n;
+ int af;
+
+ for (r = rtab; r->start != NULL; r++) {
+ af = (r->family == 4) ? AF_INET : AF_INET6;
+ oops = ttoaddr(r->start, 0, af, &start);
+ if (oops != NULL) {
+ printf("surprise failure converting `%s'\n", r->start);
+ exit(1);
+ }
+ oops = ttoaddr(r->stop, 0, af, &stop);
+ if (oops != NULL) {
+ printf("surprise failure converting `%s'\n", r->stop);
+ exit(1);
+ }
+ oops = rangetosubnet(&start, &stop, &sub);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s'-`%s' rangetosubnet failed: %s\n",
+ r->start, r->stop, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s'-`%s' rangetosubnet succeeded unexpectedly\n",
+ r->start, r->stop);
+ status = 1;
+ } else {
+ n = subnettot(&sub, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s'-`%s' subnettot failed: need %ld\n",
+ r->start, r->stop, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s'-`%s' gave `%s', expected `%s'\n",
+ r->start, r->stop, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* RANGETOSUBNET_MAIN */
diff --git a/linux/lib/libfreeswan/sameaddr.3 b/linux/lib/libfreeswan/sameaddr.3
new file mode 100644
index 000000000..71be10761
--- /dev/null
+++ b/linux/lib/libfreeswan/sameaddr.3
@@ -0,0 +1,165 @@
+.TH IPSEC_ANYADDR 3 "28 Nov 2000"
+.\" RCSID $Id: sameaddr.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec sameaddr \- are two addresses the same?
+.br
+ipsec addrcmp \- ordered comparison of addresses
+.br
+ipsec samesubnet \- are two subnets the same?
+.br
+ipsec addrinsubnet \- is an address within a subnet?
+.br
+ipsec subnetinsubnet \- is a subnet within another subnet?
+.br
+ipsec subnetishost \- is a subnet a single host?
+.br
+ipsec samesaid \- are two SA IDs the same?
+.br
+ipsec sameaddrtype \- are two addresses of the same address family?
+.br
+ipsec samesubnettype \- are two subnets of the same address family?
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "int sameaddr(const ip_address *a, const ip_address *b);"
+.br
+.B "int addrcmp(const ip_address *a, const ip_address *b);"
+.br
+.B "int samesubnet(const ip_subnet *a, const ip_subnet *b);"
+.br
+.B "int addrinsubnet(const ip_address *a, const ip_subnet *s);"
+.br
+.B "int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);"
+.br
+.B "int subnetishost(const ip_subnet *s);"
+.br
+.B "int samesaid(const ip_said *a, const ip_said *b);"
+.br
+.B "int sameaddrtype(const ip_address *a, const ip_address *b);"
+.br
+.B "int samesubnettype(const ip_subnet *a, const ip_subnet *b);"
+.SH DESCRIPTION
+These functions do various comparisons and tests on the
+.I ip_address
+type and
+.I ip_subnet
+types.
+.PP
+.I Sameaddr
+returns
+non-zero
+if addresses
+.I a
+and
+.IR b
+are identical,
+and
+.B 0
+otherwise.
+Addresses of different families are never identical.
+.PP
+.I Addrcmp
+returns
+.BR \-1 ,
+.BR 0 ,
+or
+.BR 1
+respectively
+if address
+.I a
+is less than, equal to, or greater than
+.IR b .
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+.PP
+.I Samesubnet
+returns
+non-zero
+if subnets
+.I a
+and
+.IR b
+are identical,
+and
+.B 0
+otherwise.
+Subnets of different address families are never identical.
+.PP
+.I Addrinsubnet
+returns
+non-zero
+if address
+.I a
+is within subnet
+.IR s
+and
+.B 0
+otherwise.
+An address is never within a
+subnet of a different address family.
+.PP
+.I Subnetinsubnet
+returns
+non-zero
+if subnet
+.I a
+is a subset of subnet
+.IR b
+and
+.B 0
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+.PP
+.I Subnetishost
+returns
+non-zero
+if subnet
+.I s
+is in fact only a single host,
+and
+.B 0
+otherwise.
+.PP
+.I Samesaid
+returns
+non-zero
+if SA IDs
+.I a
+and
+.IR b
+are identical,
+and
+.B 0
+otherwise.
+.PP
+.I Sameaddrtype
+returns
+non-zero
+if addresses
+.I a
+and
+.IR b
+are of the same address family,
+and
+.B 0
+otherwise.
+.PP
+.I Samesubnettype
+returns
+non-zero
+if subnets
+.I a
+and
+.IR b
+are of the same address family,
+and
+.B 0
+otherwise.
+.SH SEE ALSO
+inet(3), ipsec_initaddr(3)
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/sameaddr.c b/linux/lib/libfreeswan/sameaddr.c
new file mode 100644
index 000000000..efc40796e
--- /dev/null
+++ b/linux/lib/libfreeswan/sameaddr.c
@@ -0,0 +1,190 @@
+/*
+ * comparisons
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: sameaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static int samenbits(const ip_address *a, const ip_address *b, int n);
+
+/*
+ - addrcmp - compare two addresses
+ * Caution, the order of the tests is subtle: doing type test before
+ * size test can yield cases where a<b, b<c, but a>c.
+ */
+int /* like memcmp */
+addrcmp(a, b)
+const ip_address *a;
+const ip_address *b;
+{
+ int at = addrtypeof(a);
+ int bt = addrtypeof(b);
+ const unsigned char *ap;
+ const unsigned char *bp;
+ size_t as = addrbytesptr(a, &ap);
+ size_t bs = addrbytesptr(b, &bp);
+ size_t n = (as < bs) ? as : bs; /* min(as, bs) */
+ int c = memcmp(ap, bp, n);
+
+ if (c != 0) /* bytes differ */
+ return (c < 0) ? -1 : 1;
+ if (as != bs) /* comparison incomplete: lexical order */
+ return (as < bs) ? -1 : 1;
+ if (at != bt) /* bytes same but not same type: break tie */
+ return (at < bt) ? -1 : 1;
+ return 0;
+}
+
+/*
+ - sameaddr - are two addresses the same?
+ */
+int
+sameaddr(a, b)
+const ip_address *a;
+const ip_address *b;
+{
+ return (addrcmp(a, b) == 0) ? 1 : 0;
+}
+
+/*
+ - samesubnet - are two subnets the same?
+ */
+int
+samesubnet(a, b)
+const ip_subnet *a;
+const ip_subnet *b;
+{
+ if (!sameaddr(&a->addr, &b->addr)) /* also does type check */
+ return 0;
+ if (a->maskbits != b->maskbits)
+ return 0;
+ return 1;
+}
+
+/*
+ - subnetishost - is a subnet in fact a single host?
+ */
+int
+subnetishost(a)
+const ip_subnet *a;
+{
+ return (a->maskbits == addrlenof(&a->addr)*8) ? 1 : 0;
+}
+
+/*
+ - samesaid - are two SA IDs the same?
+ */
+int
+samesaid(a, b)
+const ip_said *a;
+const ip_said *b;
+{
+ if (a->spi != b->spi) /* test first, most likely to be different */
+ return 0;
+ if (!sameaddr(&a->dst, &b->dst))
+ return 0;
+ if (a->proto != b->proto)
+ return 0;
+ return 1;
+}
+
+/*
+ - sameaddrtype - do two addresses have the same type?
+ */
+int
+sameaddrtype(a, b)
+const ip_address *a;
+const ip_address *b;
+{
+ return (addrtypeof(a) == addrtypeof(b)) ? 1 : 0;
+}
+
+/*
+ - samesubnettype - do two subnets have the same type?
+ */
+int
+samesubnettype(a, b)
+const ip_subnet *a;
+const ip_subnet *b;
+{
+ return (subnettypeof(a) == subnettypeof(b)) ? 1 : 0;
+}
+
+/*
+ - addrinsubnet - is this address in this subnet?
+ */
+int
+addrinsubnet(a, s)
+const ip_address *a;
+const ip_subnet *s;
+{
+ if (addrtypeof(a) != subnettypeof(s))
+ return 0;
+ if (!samenbits(a, &s->addr, s->maskbits))
+ return 0;
+ return 1;
+}
+
+/*
+ - subnetinsubnet - is one subnet within another?
+ */
+int
+subnetinsubnet(a, b)
+const ip_subnet *a;
+const ip_subnet *b;
+{
+ if (subnettypeof(a) != subnettypeof(b))
+ return 0;
+ if (a->maskbits < b->maskbits) /* a is bigger than b */
+ return 0;
+ if (!samenbits(&a->addr, &b->addr, b->maskbits))
+ return 0;
+ return 1;
+}
+
+/*
+ - samenbits - do two addresses have the same first n bits?
+ */
+static int
+samenbits(a, b, nbits)
+const ip_address *a;
+const ip_address *b;
+int nbits;
+{
+ const unsigned char *ap;
+ const unsigned char *bp;
+ size_t n;
+ int m;
+
+ if (addrtypeof(a) != addrtypeof(b))
+ return 0; /* arbitrary */
+ n = addrbytesptr(a, &ap);
+ if (n == 0)
+ return 0; /* arbitrary */
+ (void) addrbytesptr(b, &bp);
+ if (nbits > n*8)
+ return 0; /* "can't happen" */
+
+ for (; nbits >= 8 && *ap == *bp; nbits -= 8, ap++, bp++)
+ continue;
+ if (nbits >= 8)
+ return 0;
+ if (nbits > 0) { /* partial byte */
+ m = ~(0xff >> nbits);
+ if ((*ap & m) != (*bp & m))
+ return 0;
+ }
+ return 1;
+}
diff --git a/linux/lib/libfreeswan/satoa.c b/linux/lib/libfreeswan/satoa.c
new file mode 100644
index 000000000..410fb8437
--- /dev/null
+++ b/linux/lib/libfreeswan/satoa.c
@@ -0,0 +1,102 @@
+/*
+ * convert from binary form of SA ID to ASCII
+ * Copyright (C) 1998, 1999, 2001 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: satoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct typename {
+ char type;
+ char *name;
+} typenames[] = {
+ { SA_AH, "ah" },
+ { SA_ESP, "esp" },
+ { SA_IPIP, "tun" },
+ { SA_COMP, "comp" },
+ { SA_INT, "int" },
+ { 0, NULL }
+};
+
+/*
+ - satoa - convert SA to ASCII "ah507@1.2.3.4"
+ */
+size_t /* space needed for full conversion */
+satoa(sa, format, dst, dstlen)
+struct sa_id sa;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len = 0; /* 0 means not handled yet */
+ int base;
+ struct typename *tn;
+ char buf[30+ADDRTOA_BUF];
+
+ switch (format) {
+ case 0:
+ base = 16; /* temporarily at least */
+ break;
+ case 'd':
+ base = 10;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ for (tn = typenames; tn->name != NULL; tn++)
+ if (sa.proto == tn->type)
+ break;
+ if (tn->name == NULL)
+ return 0;
+
+ if (strcmp(tn->name, PASSTHROUGHTYPE) == 0 &&
+ sa.spi == PASSTHROUGHSPI &&
+ sa.dst.s_addr == PASSTHROUGHDST) {
+ strcpy(buf, PASSTHROUGHNAME);
+ len = strlen(buf);
+ } else if (sa.proto == SA_INT && sa.dst.s_addr == 0) {
+ char *p;
+
+ switch (ntohl(sa.spi)) {
+ case SPI_PASS: p = "%pass"; break;
+ case SPI_DROP: p = "%drop"; break;
+ case SPI_REJECT: p = "%reject"; break;
+ case SPI_HOLD: p = "%hold"; break;
+ case SPI_TRAP: p = "%trap"; break;
+ case SPI_TRAPSUBNET: p = "%trapsubnet"; break;
+ default: p = NULL; break;
+ }
+ if (p != NULL) {
+ strcpy(buf, p);
+ len = strlen(buf);
+ }
+ }
+
+ if (len == 0) {
+ strcpy(buf, tn->name);
+ len = strlen(buf);
+ len += ultoa(ntohl(sa.spi), base, buf+len, sizeof(buf)-len);
+ *(buf+len-1) = '@';
+ len += addrtoa(sa.dst, 0, buf+len, sizeof(buf)-len);
+ }
+
+ if (dst != NULL) {
+ if (len > dstlen)
+ *(buf+dstlen-1) = '\0';
+ strcpy(dst, buf);
+ }
+ return len;
+}
diff --git a/linux/lib/libfreeswan/satot.c b/linux/lib/libfreeswan/satot.c
new file mode 100644
index 000000000..927f4ca1f
--- /dev/null
+++ b/linux/lib/libfreeswan/satot.c
@@ -0,0 +1,132 @@
+/*
+ * convert from binary form of SA ID to text
+ * Copyright (C) 2000, 2001 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: satot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct typename {
+ char type;
+ char *name;
+} typenames[] = {
+ { SA_AH, "ah" },
+ { SA_ESP, "esp" },
+ { SA_IPIP, "tun" },
+ { SA_COMP, "comp" },
+ { SA_INT, "int" },
+ { 0, NULL }
+};
+
+/*
+ - satot - convert SA to text "ah507@1.2.3.4"
+ */
+size_t /* space needed for full conversion */
+satot(sa, format, dst, dstlen)
+const ip_said *sa;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len = 0; /* 0 means "not recognized yet" */
+ int base;
+ int showversion; /* use delimiter to show IP version? */
+ struct typename *tn;
+ char *p;
+ char *pre;
+ char buf[10+1+ULTOT_BUF+ADDRTOT_BUF];
+ char unk[10];
+
+ switch (format) {
+ case 0:
+ base = 16;
+ showversion = 1;
+ break;
+ case 'f':
+ base = 17;
+ showversion = 1;
+ break;
+ case 'x':
+ base = 'x';
+ showversion = 0;
+ break;
+ case 'd':
+ base = 10;
+ showversion = 0;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ pre = NULL;
+ for (tn = typenames; tn->name != NULL; tn++)
+ if (sa->proto == tn->type) {
+ pre = tn->name;
+ break; /* NOTE BREAK OUT */
+ }
+ if (pre == NULL) { /* unknown protocol */
+ strcpy(unk, "unk");
+ (void) ultot((unsigned char)sa->proto, 10, unk+strlen(unk),
+ sizeof(unk)-strlen(unk));
+ pre = unk;
+ }
+
+ if (strcmp(pre, PASSTHROUGHTYPE) == 0 &&
+ sa->spi == PASSTHROUGHSPI &&
+ isunspecaddr(&sa->dst)) {
+ strcpy(buf, (addrtypeof(&sa->dst) == AF_INET) ?
+ PASSTHROUGH4NAME :
+ PASSTHROUGH6NAME);
+ len = strlen(buf);
+ }
+
+ if (sa->proto == SA_INT && addrtypeof(&sa->dst) == AF_INET &&
+ isunspecaddr(&sa->dst)) {
+ switch (ntohl(sa->spi)) {
+ case SPI_PASS: p = "%pass"; break;
+ case SPI_DROP: p = "%drop"; break;
+ case SPI_REJECT: p = "%reject"; break;
+ case SPI_HOLD: p = "%hold"; break;
+ case SPI_TRAP: p = "%trap"; break;
+ case SPI_TRAPSUBNET: p = "%trapsubnet"; break;
+ default: p = NULL; break;
+ }
+ if (p != NULL) {
+ strcpy(buf, p);
+ len = strlen(buf);
+ }
+ }
+
+ if (len == 0) { /* general case needed */
+ strcpy(buf, pre);
+ len = strlen(buf);
+ if (showversion) {
+ *(buf+len) = (addrtypeof(&sa->dst) == AF_INET) ? '.' :
+ ':';
+ len++;
+ *(buf+len) = '\0';
+ }
+ len += ultot(ntohl(sa->spi), base, buf+len, sizeof(buf)-len);
+ *(buf+len-1) = '@';
+ len += addrtot(&sa->dst, 0, buf+len, sizeof(buf)-len);
+ }
+
+ if (dst != NULL) {
+ if (len > dstlen)
+ *(buf+dstlen-1) = '\0';
+ strcpy(dst, buf);
+ }
+ return len;
+}
diff --git a/linux/lib/libfreeswan/subnetof.3 b/linux/lib/libfreeswan/subnetof.3
new file mode 100644
index 000000000..1911e499f
--- /dev/null
+++ b/linux/lib/libfreeswan/subnetof.3
@@ -0,0 +1,47 @@
+.TH IPSEC_SUBNETOF 3 "11 June 2001"
+.\" RCSID $Id: subnetof.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec subnetof \- given Internet address and subnet mask, return subnet number
+.br
+ipsec hostof \- given Internet address and subnet mask, return host part
+.br
+ipsec broadcastof \- given Internet address and subnet mask, return broadcast address
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "struct in_addr subnetof(struct in_addr addr,"
+.ti +1c
+.B "struct in_addr mask);"
+.br
+.B "struct in_addr hostof(struct in_addr addr,"
+.ti +1c
+.B "struct in_addr mask);"
+.br
+.B "struct in_addr broadcastof(struct in_addr addr,"
+.ti +1c
+.B "struct in_addr mask);"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_networkof (3)
+for their replacements.
+.PP
+.I Subnetof
+takes an Internet
+.I address
+and a subnet
+.I mask
+and returns the network part of the address
+(all in network byte order).
+.I Hostof
+similarly returns the host part, and
+.I broadcastof
+returns the broadcast address (all-1s convention) for the network.
+.PP
+These functions are provided to hide the Internet bit-munging inside
+an API, in hopes of easing the eventual transition to IPv6.
+.SH SEE ALSO
+inet(3), ipsec_atosubnet(3)
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+Calling functions for this is more costly than doing it yourself.
diff --git a/linux/lib/libfreeswan/subnetof.c b/linux/lib/libfreeswan/subnetof.c
new file mode 100644
index 000000000..1b288c591
--- /dev/null
+++ b/linux/lib/libfreeswan/subnetof.c
@@ -0,0 +1,60 @@
+/*
+ * minor network-address manipulation utilities
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: subnetof.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnetof - given address and mask, return subnet part
+ */
+struct in_addr
+subnetof(addr, mask)
+struct in_addr addr;
+struct in_addr mask;
+{
+ struct in_addr result;
+
+ result.s_addr = addr.s_addr & mask.s_addr;
+ return result;
+}
+
+/*
+ - hostof - given address and mask, return host part
+ */
+struct in_addr
+hostof(addr, mask)
+struct in_addr addr;
+struct in_addr mask;
+{
+ struct in_addr result;
+
+ result.s_addr = addr.s_addr & ~mask.s_addr;
+ return result;
+}
+
+/*
+ - broadcastof - given (network) address and mask, return broadcast address
+ */
+struct in_addr
+broadcastof(addr, mask)
+struct in_addr addr;
+struct in_addr mask;
+{
+ struct in_addr result;
+
+ result.s_addr = addr.s_addr | ~mask.s_addr;
+ return result;
+}
diff --git a/linux/lib/libfreeswan/subnettoa.c b/linux/lib/libfreeswan/subnettoa.c
new file mode 100644
index 000000000..36cad8b88
--- /dev/null
+++ b/linux/lib/libfreeswan/subnettoa.c
@@ -0,0 +1,62 @@
+/*
+ * convert binary form of subnet description to ASCII
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: subnettoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnettoa - convert address and mask to ASCII "addr/mask"
+ * Output expresses the mask as a bit count if possible, else dotted decimal.
+ */
+size_t /* space needed for full conversion */
+subnettoa(addr, mask, format, dst, dstlen)
+struct in_addr addr;
+struct in_addr mask;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len;
+ size_t rest;
+ int n;
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = addrtoa(addr, 0, dst, dstlen);
+ if (len < dstlen) {
+ dst[len - 1] = '/';
+ p = dst + len;
+ rest = dstlen - len;
+ } else {
+ p = NULL;
+ rest = 0;
+ }
+
+ n = masktobits(mask);
+ if (n >= 0)
+ len += ultoa((unsigned long)n, 10, p, rest);
+ else
+ len += addrtoa(mask, 0, p, rest);
+
+ return len;
+}
diff --git a/linux/lib/libfreeswan/subnettot.c b/linux/lib/libfreeswan/subnettot.c
new file mode 100644
index 000000000..0385d25e5
--- /dev/null
+++ b/linux/lib/libfreeswan/subnettot.c
@@ -0,0 +1,56 @@
+/*
+ * convert binary form of subnet description to text
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: subnettot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnettot - convert subnet to text "addr/bitcount"
+ */
+size_t /* space needed for full conversion */
+subnettot(sub, format, dst, dstlen)
+const ip_subnet *sub;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len;
+ size_t rest;
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = addrtot(&sub->addr, format, dst, dstlen);
+ if (len < dstlen) {
+ dst[len - 1] = '/';
+ p = dst + len;
+ rest = dstlen - len;
+ } else {
+ p = NULL;
+ rest = 0;
+ }
+
+
+ len += ultoa((unsigned long)sub->maskbits, 10, p, rest);
+
+ return len;
+}
diff --git a/linux/lib/libfreeswan/subnettypeof.c b/linux/lib/libfreeswan/subnettypeof.c
new file mode 100644
index 000000000..6f44b2e4b
--- /dev/null
+++ b/linux/lib/libfreeswan/subnettypeof.c
@@ -0,0 +1,109 @@
+/*
+ * extract parts of an ip_subnet, and related
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: subnettypeof.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnettypeof - get the address type of an ip_subnet
+ */
+int
+subnettypeof(src)
+const ip_subnet *src;
+{
+ return src->addr.u.v4.sin_family;
+}
+
+/*
+ - networkof - get the network address of a subnet
+ */
+void
+networkof(src, dst)
+const ip_subnet *src;
+ip_address *dst;
+{
+ *dst = src->addr;
+}
+
+/*
+ - maskof - get the mask of a subnet, as an address
+ */
+void
+maskof(src, dst)
+const ip_subnet *src;
+ip_address *dst;
+{
+ int b;
+ unsigned char buf[16];
+ size_t n = addrlenof(&src->addr);
+ unsigned char *p;
+
+ if (src->maskbits > n*8 || n > sizeof(buf))
+ return; /* "can't happen" */
+
+ p = buf;
+ for (b = src->maskbits; b >= 8; b -= 8)
+ *p++ = 0xff;
+ if (b != 0)
+ *p++ = (0xff << (8 - b)) & 0xff;
+ while (p - buf < n)
+ *p++ = 0;
+
+ (void) initaddr(buf, n, addrtypeof(&src->addr), dst);
+}
+
+/*
+ - masktocount - convert a mask, expressed as an address, to a bit count
+ */
+int /* -1 if not valid mask */
+masktocount(src)
+const ip_address *src;
+{
+ int b;
+ unsigned const char *bp;
+ size_t n;
+ unsigned const char *p;
+ unsigned const char *stop;
+
+ n = addrbytesptr(src, &bp);
+ if (n == 0)
+ return -1;
+
+ p = bp;
+ stop = bp + n;
+
+ n = 0;
+ while (p < stop && *p == 0xff) {
+ p++;
+ n += 8;
+ }
+ if (p < stop && *p != 0) { /* boundary in mid-byte */
+ b = *p++;
+ while (b&0x80) {
+ b <<= 1;
+ n++;
+ }
+ if ((b&0xff) != 0)
+ return -1; /* bits not contiguous */
+ }
+ while (p < stop && *p == 0)
+ p++;
+
+ if (p != stop)
+ return -1;
+
+ return n;
+}
diff --git a/linux/lib/libfreeswan/ttoaddr.3 b/linux/lib/libfreeswan/ttoaddr.3
new file mode 100644
index 000000000..5bf48d4b2
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoaddr.3
@@ -0,0 +1,377 @@
+.TH IPSEC_TTOADDR 3 "28 Sept 2001"
+.\" RCSID $Id: ttoaddr.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ttoaddr, tnatoaddr, addrtot \- convert Internet addresses to and from text
+.br
+ipsec ttosubnet, subnettot \- convert subnet/mask text form to and from addresses
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *ttoaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_address *addr);"
+.br
+.B "const char *tnatoaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_address *addr);"
+.br
+.B "size_t addrtot(const ip_address *addr, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "const char *ttosubnet(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_subnet *dst);"
+.br
+.B "size_t subnettot(const ip_subnet *sub, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.SH DESCRIPTION
+.I Ttoaddr
+converts a text-string name or numeric address into a binary address
+(in network byte order).
+.I Tnatoaddr
+does the same conversion,
+but the only text forms it accepts are
+the ``official'' forms of
+numeric address (dotted-decimal for IPv4, colon-hex for IPv6).
+.I Addrtot
+does the reverse conversion, from binary address back to a text form.
+.I Ttosubnet
+and
+.I subnettot
+do likewise for the ``address/mask'' form used to write a
+specification of a subnet.
+.PP
+An IPv4 address is specified in text as a
+dotted-decimal address (e.g.
+.BR 1.2.3.4 ),
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+.BR 0x01020304 ,
+which is synonymous with
+.BR 1.2.3.4 ),
+an eight-digit host-order hexadecimal number with a
+.B 0h
+prefix (e.g.
+.BR 0h01020304 ,
+which is synonymous with
+.B 1.2.3.4
+on a big-endian host and
+.B 4.3.2.1
+on a little-endian host),
+a DNS name to be looked up via
+.IR gethostbyname (3),
+or an old-style network name to be looked up via
+.IR getnetbyname (3).
+.PP
+A dotted-decimal address may be incomplete, in which case
+text-to-binary conversion implicitly appends
+as many instances of
+.B .0
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+.B 10
+is synonymous with
+.BR 10.0.0.0 ,
+and
+.B 128.009.000.032
+is synonymous with
+.BR 128.9.0.32
+(the latter example is verbatim from RFC 1166).
+The result of applying
+.I addrtot
+to an IPv4 address is always complete and does not contain leading zeros.
+.PP
+Use of hexadecimal addresses is
+.B strongly
+.BR discouraged ;
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+.PP
+An IPv6 address is specified in text with
+colon-hex notation (e.g.
+.BR 0:56:78ab:22:33:44:55:66 ),
+colon-hex with
+.B ::
+abbreviating at most one subsequence of multiple zeros (e.g.
+.BR 99:ab::54:068 ,
+which is synonymous with
+.BR 99:ab:0:0:0:0:54:68 ),
+or a DNS name to be looked up via
+.IR gethostbyname (3).
+The result of applying
+.I addrtot
+to an IPv6 address will use
+.B ::
+abbreviation if possible,
+and will not contain leading zeros.
+.PP
+The letters in hexadecimal
+may be uppercase or lowercase or any mixture thereof.
+.PP
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+.IR resolver (5)).
+The
+.I h_addr
+value returned by
+.IR gethostbyname2 (3)
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+IPv4 name lookup resorts to
+.IR getnetbyname (3)
+only if
+.IR gethostbyname2 (3)
+fails.
+.PP
+A subnet specification is of the form \fInetwork\fB/\fImask\fR.
+The
+.I network
+and
+.I mask
+can be any form acceptable to
+.IR ttoaddr .
+In addition, and preferably, the
+.I mask
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+.B 24
+in IPv4 means
+.BR 255.255.255.0 ).
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+.B %default
+is a synonym for
+.B 0.0.0.0/0
+or
+.B ::/0
+in IPv4 or IPv6 respectively.
+.PP
+.I Ttosubnet
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+.B 10.1.2.3/24
+is synonymous with
+.BR 10.1.2.0/24 ).
+.I Subnettot
+always generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros.
+.PP
+The
+.I srclen
+parameter of
+.I ttoaddr
+and
+.I ttosubnet
+specifies the length of the text string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I af
+parameter of
+.I ttoaddr
+and
+.I ttosubnet
+specifies the address family of interest.
+It should be either
+.B AF_INET
+or
+.BR AF_INET6 .
+.PP
+The
+.I dstlen
+parameter of
+.I addrtot
+and
+.I subnettot
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines constants,
+.B ADDRTOT_BUF
+and
+.BR SUBNETTOT_BUF ,
+which are the sizes of buffers just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I addrtot
+and
+.I subnettot
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available in
+.IR subnettot .
+.I Addrtot
+also accepts format values
+.B 'r'
+(signifying a text form suitable for DNS reverse lookups,
+e.g.
+.B 4.3.2.1.IN-ADDR.ARPA.
+for IPv4 and
+RFC 2874 format for IPv6),
+and
+.B 'R'
+(signifying an alternate reverse-lookup form,
+an error for IPv4 and RFC 1886 format for IPv6).
+Reverse-lookup names always end with a ``.''.
+.PP
+The text-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-text functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttoaddr
+are:
+empty input;
+unknown address family;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal or colon-hex form;
+dotted-decimal or colon-hex component too large.
+.PP
+Fatal errors in
+.I ttosubnet
+are:
+no
+.B /
+in
+.IR src ;
+.I ttoaddr
+error in conversion of
+.I network
+or
+.IR mask ;
+bit-count mask too big;
+mask non-contiguous.
+.PP
+Fatal errors in
+.I addrtot
+and
+.I subnettot
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+.B 10/24
+means
+.BR 10.0.0.0/24 )
+differs from that of some older conversion
+functions, e.g. those of
+.IR inet (3).
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+.PP
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+.PP
+.I Ttoaddr
+does not support the mixed colon-hex-dotted-decimal
+convention used to embed an IPv4 address in an IPv6 address.
+.PP
+.I Addrtot
+always uses the
+.B ::
+abbreviation (which can appear only once in an address) for the
+.I first
+sequence of multiple zeros in an IPv6 address.
+One can construct addresses (unlikely ones) in which this is suboptimal.
+.PP
+.I Addrtot
+.B 'r'
+conversion of an IPv6 address uses lowercase hexadecimal,
+not the uppercase used in RFC 2874's examples.
+It takes careful reading of RFCs 2874, 2673, and 2234 to realize
+that lowercase is technically legitimate here,
+and there may be software which botches this
+and hence would have trouble with lowercase hex.
+.PP
+Possibly
+.I subnettot
+ought to recognize the
+.B %default
+case and generate that string as its output.
+Currently it doesn't.
+.PP
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+.PP
+.IR Getnetbyname (3)
+is a historical dreg.
+.PP
+.I Tnatoaddr
+probably should enforce completeness of dotted-decimal addresses.
+.PP
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = ttoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/ttoaddr.c b/linux/lib/libfreeswan/ttoaddr.c
new file mode 100644
index 000000000..efcb33e9f
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoaddr.c
@@ -0,0 +1,426 @@
+/*
+ * conversion from text forms of addresses to internal ones
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttoaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ * Legal ASCII characters in a domain name. Underscore technically is not,
+ * but is a common misunderstanding. Non-ASCII characters are simply
+ * exempted from checking at the moment, to allow for UTF-8 encoded stuff;
+ * the purpose of this check is merely to catch blatant errors.
+ */
+static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
+#define ISASCII(c) (((c) & 0x80) == 0)
+
+static err_t tryname(const char *, size_t, int, int, ip_address *);
+static err_t tryhex(const char *, size_t, int, ip_address *);
+static err_t trydotted(const char *, size_t, ip_address *);
+static err_t getbyte(const char **, const char *, int *);
+static err_t colon(const char *, size_t, ip_address *);
+static err_t getpiece(const char **, const char *, unsigned *);
+
+/*
+ - ttoaddr - convert text name or dotted-decimal address to binary address
+ */
+err_t /* NULL for success, else string literal */
+ttoaddr(src, srclen, af, dst)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+int af; /* address family */
+ip_address *dst;
+{
+ err_t oops;
+# define HEXLEN 10 /* strlen("0x11223344") */
+ int nultermd;
+
+ if (srclen == 0) {
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ nultermd = 1;
+ } else
+ nultermd = 0; /* at least, not *known* to be terminated */
+
+ switch (af) {
+ case AF_INET:
+ case AF_INET6:
+ case 0: /* guess */
+ break;
+
+ default:
+ return "invalid address family";
+ }
+
+ if (af == AF_INET && srclen == HEXLEN && *src == '0') {
+ if (*(src+1) == 'x' || *(src+1) == 'X')
+ return tryhex(src+2, srclen-2, 'x', dst);
+ if (*(src+1) == 'h' || *(src+1) == 'H')
+ return tryhex(src+2, srclen-2, 'h', dst);
+ }
+
+ if (memchr(src, ':', srclen) != NULL) {
+ if(af == 0)
+ {
+ af = AF_INET6;
+ }
+
+ if (af != AF_INET6)
+ return "non-ipv6 address may not contain `:'";
+ return colon(src, srclen, dst);
+ }
+
+ if (af == 0 || af == AF_INET) {
+ oops = trydotted(src, srclen, dst);
+ if (oops == NULL)
+ return NULL; /* it worked */
+ if (*oops != '?')
+ return oops; /* probably meant as d-d */
+ }
+
+ return tryname(src, srclen, nultermd, af, dst);
+}
+
+/*
+ - tnatoaddr - convert text numeric address (only) to binary address
+ */
+err_t /* NULL for success, else string literal */
+tnatoaddr(src, srclen, af, dst)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+int af; /* address family */
+ip_address *dst;
+{
+ err_t oops;
+
+ if (srclen == 0) {
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ }
+
+ switch (af) {
+ case 0: /* guess */
+ oops = colon(src, srclen, dst);
+ if(oops == NULL)
+ {
+ return NULL;
+ }
+ oops = trydotted(src, srclen, dst);
+ if(oops == NULL)
+ {
+ return NULL;
+ }
+ return "does not appear to be either IPv4 or IPv6 numeric address";
+ break;
+
+ case AF_INET6:
+ return colon(src, srclen, dst);
+ break;
+ case AF_INET:
+ oops = trydotted(src, srclen, dst);
+ if (oops == NULL)
+ return NULL; /* it worked */
+ if (*oops != '?')
+ return oops; /* probably meant as d-d */
+ return "does not appear to be numeric address";
+ break;
+ default:
+ return "unknown address family in tnatoaddr";
+ break;
+ }
+}
+
+/*
+ - tryname - try it as a name
+ * Slightly complicated by lack of reliable NUL termination in source.
+ */
+static err_t
+tryname(src, srclen, nultermd, af, dst)
+const char *src;
+size_t srclen;
+int nultermd; /* is it known to be NUL-terminated? */
+int af;
+ip_address *dst;
+{
+ struct hostent *h;
+ struct netent *ne = NULL;
+ char namebuf[100]; /* enough for most DNS names */
+ const char *cp;
+ char *p = namebuf;
+ size_t n;
+
+ for (cp = src, n = srclen; n > 0; cp++, n--)
+ if (ISASCII(*cp) && strchr(namechars, *cp) == NULL)
+ return "illegal (non-DNS-name) character in name";
+
+ if (nultermd)
+ cp = src;
+ else {
+ if (srclen+1 > sizeof(namebuf)) {
+ p = (char *) MALLOC(srclen+1);
+ if (p == NULL)
+ return "unable to get temporary space for name";
+ }
+ p[0] = '\0'; /* strncpy semantics are wrong */
+ strncat(p, src, srclen);
+ cp = (const char *)p;
+ }
+
+ h = gethostbyname2(cp, af);
+ if (h == NULL && af == AF_INET)
+ ne = getnetbyname(cp);
+ if (p != namebuf)
+ FREE(p);
+ if (h == NULL && ne == NULL)
+ return "does not look numeric and name lookup failed";
+
+ if (h != NULL) {
+ if (h->h_addrtype != af)
+ return "address-type mismatch from gethostbyname2!!!";
+ return initaddr((unsigned char *)h->h_addr, h->h_length, af, dst);
+ } else {
+ if (ne->n_addrtype != af)
+ return "address-type mismatch from getnetbyname!!!";
+ ne->n_net = htonl(ne->n_net);
+ return initaddr((unsigned char *)&ne->n_net, sizeof(ne->n_net),
+ af, dst);
+ }
+}
+
+/*
+ - tryhex - try conversion as an eight-digit hex number (AF_INET only)
+ */
+static err_t
+tryhex(src, srclen, flavor, dst)
+const char *src;
+size_t srclen; /* should be 8 */
+int flavor; /* 'x' for network order, 'h' for host order */
+ip_address *dst;
+{
+ err_t oops;
+ unsigned long ul;
+ union {
+ uint32_t addr;
+ unsigned char buf[4];
+ } u;
+
+ if (srclen != 8)
+ return "internal error, tryhex called with bad length";
+
+ oops = ttoul(src, srclen, 16, &ul);
+ if (oops != NULL)
+ return oops;
+
+ u.addr = (flavor == 'h') ? ul : htonl(ul);
+ return initaddr(u.buf, sizeof(u.buf), AF_INET, dst);
+}
+
+/*
+ - trydotted - try conversion as dotted decimal (AF_INET only)
+ *
+ * If the first char of a complaint is '?', that means "didn't look like
+ * dotted decimal at all".
+ */
+static err_t
+trydotted(src, srclen, dst)
+const char *src;
+size_t srclen;
+ip_address *dst;
+{
+ const char *stop = src + srclen; /* just past end */
+ int byte;
+ err_t oops;
+# define NBYTES 4
+ unsigned char buf[NBYTES];
+ int i;
+
+ memset(buf, 0, sizeof(buf));
+ for (i = 0; i < NBYTES && src < stop; i++) {
+ oops = getbyte(&src, stop, &byte);
+ if (oops != NULL) {
+ if (*oops != '?')
+ return oops; /* bad number */
+ if (i > 1)
+ return oops+1; /* failed number */
+ return oops; /* with leading '?' */
+ }
+ buf[i] = byte;
+ if (i < 3 && src < stop && *src++ != '.') {
+ if (i == 0)
+ return "?syntax error in dotted-decimal address";
+ else
+ return "syntax error in dotted-decimal address";
+ }
+ }
+ if (src != stop)
+ return "extra garbage on end of dotted-decimal address";
+
+ return initaddr(buf, sizeof(buf), AF_INET, dst);
+}
+
+/*
+ - getbyte - try to scan a byte in dotted decimal
+ * A subtlety here is that all this arithmetic on ASCII digits really is
+ * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
+ * It's easier to just do it ourselves than set up for a call to ttoul().
+ *
+ * If the first char of a complaint is '?', that means "didn't look like a
+ * number at all".
+ */
+err_t
+getbyte(srcp, stop, retp)
+const char **srcp; /* *srcp is updated */
+const char *stop; /* first untouchable char */
+int *retp; /* return-value pointer */
+{
+ char c;
+ const char *p;
+ int no;
+
+ if (*srcp >= stop)
+ return "?empty number in dotted-decimal address";
+
+ no = 0;
+ p = *srcp;
+ while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
+ no = no*10 + (c - '0');
+ p++;
+ }
+ if (p == *srcp)
+ return "?non-numeric component in dotted-decimal address";
+ *srcp = p;
+ if (no > 255)
+ return "byte overflow in dotted-decimal address";
+ *retp = no;
+ return NULL;
+}
+
+/*
+ - colon - convert IPv6 "numeric" address
+ */
+static err_t
+colon(src, srclen, dst)
+const char *src;
+size_t srclen; /* known to be >0 */
+ip_address *dst;
+{
+ const char *stop = src + srclen; /* just past end */
+ unsigned piece;
+ int gapat; /* where was empty piece seen */
+ err_t oops;
+# define NPIECES 8
+ unsigned char buf[NPIECES*2]; /* short may have wrong byte order */
+ int i;
+ int j;
+# define IT "IPv6 numeric address"
+ int naftergap;
+
+ /* leading or trailing :: becomes single empty field */
+ if (*src == ':') { /* legal only if leading :: */
+ if (srclen == 1 || *(src+1) != ':')
+ return "illegal leading `:' in " IT;
+ if (srclen == 2) {
+ unspecaddr(AF_INET6, dst);
+ return NULL;
+ }
+ src++; /* past first but not second */
+ srclen--;
+ }
+ if (*(stop-1) == ':') { /* legal only if trailing :: */
+ if (srclen == 1 || *(stop-2) != ':')
+ return "illegal trailing `:' in " IT;
+ srclen--; /* leave one */
+ }
+
+ gapat = -1;
+ for (i = 0; i < NPIECES && src < stop; i++) {
+ oops = getpiece(&src, stop, &piece);
+ if (oops != NULL && *oops == ':') { /* empty field */
+ if (gapat >= 0)
+ return "more than one :: in " IT;
+ gapat = i;
+ } else if (oops != NULL)
+ return oops;
+ buf[2*i] = piece >> 8;
+ buf[2*i + 1] = piece & 0xff;
+ if (i < NPIECES-1) { /* there should be more input */
+ if (src == stop && gapat < 0)
+ return IT " ends prematurely";
+ if (src != stop && *src++ != ':')
+ return "syntax error in " IT;
+ }
+ }
+ if (src != stop)
+ return "extra garbage on end of " IT;
+
+ if (gapat < 0 && i < NPIECES) /* should have been caught earlier */
+ return "incomplete " IT " (internal error)";
+ if (gapat >= 0 && i == NPIECES)
+ return "non-abbreviating empty field in " IT;
+ if (gapat >= 0) {
+ naftergap = i - (gapat + 1);
+ for (i--, j = NPIECES-1; naftergap > 0; i--, j--, naftergap--) {
+ buf[2*j] = buf[2*i];
+ buf[2*j + 1] = buf[2*i + 1];
+ }
+ for (; j >= gapat; j--)
+ buf[2*j] = buf[2*j + 1] = 0;
+ }
+
+ return initaddr(buf, sizeof(buf), AF_INET6, dst);
+}
+
+/*
+ - getpiece - try to scan one 16-bit piece of an IPv6 address
+ */
+err_t /* ":" means "empty field seen" */
+getpiece(srcp, stop, retp)
+const char **srcp; /* *srcp is updated */
+const char *stop; /* first untouchable char */
+unsigned *retp; /* return-value pointer */
+{
+ const char *p;
+# define NDIG 4
+ int d;
+ unsigned long ret;
+ err_t oops;
+
+ if (*srcp >= stop || **srcp == ':') { /* empty field */
+ *retp = 0;
+ return ":";
+ }
+
+ p = *srcp;
+ d = 0;
+ while (p < stop && d < NDIG && isxdigit(*p)) {
+ p++;
+ d++;
+ }
+ if (d == 0)
+ return "non-hex field in IPv6 numeric address";
+ if (p < stop && d == NDIG && isxdigit(*p))
+ return "field in IPv6 numeric address longer than 4 hex digits";
+
+ oops = ttoul(*srcp, d, 16, &ret);
+ if (oops != NULL) /* shouldn't happen, really... */
+ return oops;
+
+ *srcp = p;
+ *retp = ret;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/ttodata.3 b/linux/lib/libfreeswan/ttodata.3
new file mode 100644
index 000000000..98bbe4ab3
--- /dev/null
+++ b/linux/lib/libfreeswan/ttodata.3
@@ -0,0 +1,281 @@
+.TH IPSEC_TTODATA 3 "16 August 2003"
+.\" RCSID $Id: ttodata.3,v 1.2 2005/07/18 20:13:42 as Exp $
+.SH NAME
+ipsec ttodata, datatot \- convert binary data bytes from and to text formats
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *ttodata(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, char *dst, size_t dstlen, size_t *lenp);"
+.br
+.B "const char *ttodatav(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, char *dst, size_t dstlen, size_t *lenp,"
+.ti +1c
+.B "char *errp, size_t errlen, int flags);"
+.br
+.B "size_t datatot(const char *src, size_t srclen,"
+.ti +1c
+.B "int format, char *dst, size_t dstlen);"
+.SH DESCRIPTION
+.IR Ttodata ,
+.IR ttodatav ,
+and
+.I datatot
+convert arbitrary binary data (e.g. encryption or authentication keys)
+from and to more-or-less human-readable text formats.
+.PP
+Currently supported formats are hexadecimal, base64, and characters.
+.PP
+A hexadecimal text value begins with a
+.B 0x
+(or
+.BR 0X )
+prefix and continues with two-digit groups
+of hexadecimal digits (0-9, and a-f or A-F),
+each group encoding the value of one binary byte, high-order digit first.
+A single
+.B _
+(underscore)
+between consecutive groups is ignored, permitting punctuation to improve
+readability; doing this every eight digits seems about right.
+.PP
+A base64 text value begins with a
+.B 0s
+(or
+.BR 0S )
+prefix
+and continues with four-digit groups of base64 digits (A-Z, a-z, 0-9, +, and /),
+each group encoding the value of three binary bytes as described in
+section 6.8 of RFC 2045.
+If
+.B flags
+has the
+.B TTODATAV_IGNORESPACE
+bit on, blanks are ignore (after the prefix).
+Note that the last one or two digits of a base64 group can be
+.B =
+to indicate that fewer than three binary bytes are encoded.
+.PP
+A character text value begins with a
+.B 0t
+(or
+.BR 0T )
+prefix
+and continues with text characters, each being the value of one binary byte.
+.PP
+All these functions basically copy data from
+.I src
+(whose size is specified by
+.IR srclen )
+to
+.I dst
+(whose size is specified by
+.IR dstlen ),
+doing the conversion en route.
+If the result will not fit in
+.IR dst ,
+it is truncated;
+under no circumstances are more than
+.I dstlen
+bytes of result written to
+.IR dst .
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result bytes are written at all.
+.PP
+The
+.I base
+parameter of
+.I ttodata
+and
+.I ttodatav
+specifies what format the input is in;
+normally it should be
+.B 0
+to signify that this gets figured out from the prefix.
+Values of
+.BR 16 ,
+.BR 64 ,
+and
+.BR 256
+respectively signify hexadecimal, base64, and character-text formats
+without prefixes.
+.PP
+The
+.I format
+parameter of
+.IR datatot ,
+a single character used as a type code,
+specifies which text format is wanted.
+The value
+.B 0
+(not ASCII
+.BR '0' ,
+but a zero value) specifies a reasonable default.
+Other currently-supported values are:
+.RS 2
+.TP 4
+.B 'x'
+continuous lower-case hexadecimal with a
+.B 0x
+prefix
+.TP
+.B 'h'
+lower-case hexadecimal with a
+.B 0x
+prefix and a
+.B _
+every eight digits
+.TP
+.B ':'
+lower-case hexadecimal with no prefix and a
+.B :
+(colon) every two digits
+.TP
+.B 16
+lower-case hexadecimal with no prefix or
+.B _
+.TP
+.B 's'
+continuous base64 with a
+.B 0s
+prefix
+.TP
+.B 64
+continuous base64 with no prefix
+.RE
+.PP
+The default format is currently
+.BR 'h' .
+.PP
+.I Ttodata
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+On success,
+if and only if
+.I lenp
+is non-NULL,
+.B *lenp
+is set to the number of bytes required to contain the full untruncated result.
+It is the caller's responsibility to check this against
+.I dstlen
+to determine whether he has obtained a complete result.
+The
+.B *lenp
+value is correct even if
+.I dstlen
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+.PP
+.I Ttodatav
+is just like
+.I ttodata
+except that in certain cases,
+if
+.I errp
+is non-NULL,
+the buffer pointed to by
+.I errp
+(whose length is given by
+.IR errlen )
+is used to hold a more detailed error message.
+The return value is NULL for success,
+and is either
+.I errp
+or a pointer to a string literal for failure.
+If the size of the error-message buffer is
+inadequate for the desired message,
+.I ttodatav
+will fall back on returning a pointer to a literal string instead.
+The
+.I freeswan.h
+header file defines a constant
+.B TTODATAV_BUF
+which is the size of a buffer large enough for worst-case results.
+.PP
+The normal return value of
+.IR datatot
+is the number of bytes required
+to contain the full untruncated result.
+It is the caller's responsibility to check this against
+.I dstlen
+to determine whether he has obtained a complete result.
+The return value is correct even if
+.I dstlen
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+A return value of
+.B 0
+signals a fatal error of some kind
+(see DIAGNOSTICS).
+.PP
+A zero value for
+.I srclen
+in
+.I ttodata
+(but not
+.IR datatot !)
+is synonymous with
+.BR strlen(src) .
+A non-zero
+.I srclen
+in
+.I ttodata
+must not include the terminating NUL.
+.PP
+Unless
+.I dstlen
+is zero,
+the result supplied by
+.I datatot
+is always NUL-terminated,
+and its needed-size return value includes space for the terminating NUL.
+.PP
+Several obsolete variants of these functions
+.RI ( atodata ,
+.IR datatoa ,
+.IR atobytes ,
+and
+.IR bytestoa )
+are temporarily also supported.
+.SH SEE ALSO
+sprintf(3), ipsec_atoaddr(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttodata
+and
+.I ttodatav
+are:
+unknown characters in the input;
+unknown or missing prefix;
+unknown base;
+incomplete digit group;
+non-zero padding in a base64 less-than-three-bytes digit group;
+zero-length input.
+.PP
+Fatal errors in
+.I datatot
+are:
+unknown format code;
+zero-length input.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+.I Datatot
+should have a format code to produce character-text output.
+.PP
+The
+.B 0s
+and
+.B 0t
+prefixes are the author's inventions and are not a standard
+of any kind.
+They have been chosen to avoid collisions with existing practice
+(some C implementations use
+.B 0b
+for binary)
+and possible confusion with unprefixed hexadecimal.
diff --git a/linux/lib/libfreeswan/ttodata.c b/linux/lib/libfreeswan/ttodata.c
new file mode 100644
index 000000000..e1bf7606a
--- /dev/null
+++ b/linux/lib/libfreeswan/ttodata.c
@@ -0,0 +1,722 @@
+/*
+ * convert from text form of arbitrary data (e.g., keys) to binary
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttodata.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/* converters and misc */
+static int unhex(const char *, char *, size_t);
+static int unb64(const char *, char *, size_t);
+static int untext(const char *, char *, size_t);
+static const char *badch(const char *, int, char *, size_t);
+
+/* internal error codes for converters */
+#define SHORT (-2) /* internal buffer too short */
+#define BADPAD (-3) /* bad base64 padding */
+#define BADCH0 (-4) /* invalid character 0 */
+#define BADCH1 (-5) /* invalid character 1 */
+#define BADCH2 (-6) /* invalid character 2 */
+#define BADCH3 (-7) /* invalid character 3 */
+#define BADOFF(code) (BADCH0-(code))
+
+/*
+ - ttodatav - convert text to data, with verbose error reports
+ * If some of this looks slightly odd, it's because it has changed
+ * repeatedly (from the original atodata()) without a major rewrite.
+ */
+const char * /* NULL on success, else literal or errp */
+ttodatav(src, srclen, base, dst, dstlen, lenp, errp, errlen, flags)
+const char *src;
+size_t srclen; /* 0 means apply strlen() */
+int base; /* 0 means figure it out */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+size_t *lenp; /* where to record length (NULL is nowhere) */
+char *errp; /* error buffer */
+size_t errlen;
+unsigned int flags;
+{
+ size_t ingroup; /* number of input bytes converted at once */
+ char buf[4]; /* output from conversion */
+ int nbytes; /* size of output */
+ int (*decode)(const char *, char *, size_t);
+ char *stop;
+ int ndone;
+ int i;
+ int underscoreok;
+ int skipSpace = 0;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (dstlen == 0)
+ dst = buf; /* point it somewhere valid */
+ stop = dst + dstlen;
+
+ if (base == 0) {
+ if (srclen < 2)
+ return "input too short to be valid";
+ if (*src++ != '0')
+ return "input does not begin with format prefix";
+ switch (*src++) {
+ case 'x':
+ case 'X':
+ base = 16;
+ break;
+ case 's':
+ case 'S':
+ base = 64;
+ break;
+ case 't':
+ case 'T':
+ base = 256;
+ break;
+ default:
+ return "unknown format prefix";
+ }
+ srclen -= 2;
+ }
+ switch (base) {
+ case 16:
+ decode = unhex;
+ underscoreok = 1;
+ ingroup = 2;
+ break;
+ case 64:
+ decode = unb64;
+ underscoreok = 0;
+ ingroup = 4;
+ if(flags & TTODATAV_IGNORESPACE) {
+ skipSpace = 1;
+ }
+ break;
+
+ case 256:
+ decode = untext;
+ ingroup = 1;
+ underscoreok = 0;
+ break;
+ default:
+ return "unknown base";
+ }
+
+ /* proceed */
+ ndone = 0;
+ while (srclen > 0) {
+ char stage[4]; /* staging area for group */
+ size_t sl = 0;
+
+ /* Grab ingroup characters into stage,
+ * squeezing out blanks if we are supposed to ignore them.
+ */
+ for (sl = 0; sl < ingroup; src++, srclen--) {
+ if (srclen == 0)
+ return "input ends in mid-byte, perhaps truncated";
+ else if (!(skipSpace && (*src == ' ' || *src == '\t')))
+ stage[sl++] = *src;
+ }
+
+ nbytes = (*decode)(stage, buf, sizeof(buf));
+ switch (nbytes) {
+ case BADCH0:
+ case BADCH1:
+ case BADCH2:
+ case BADCH3:
+ return badch(stage, nbytes, errp, errlen);
+ case SHORT:
+ return "internal buffer too short (\"can't happen\")";
+ case BADPAD:
+ return "bad (non-zero) padding at end of base64 input";
+ }
+ if (nbytes <= 0)
+ return "unknown internal error";
+ for (i = 0; i < nbytes; i++) {
+ if (dst < stop)
+ *dst++ = buf[i];
+ ndone++;
+ }
+ while (srclen >= 1 && skipSpace && (*src == ' ' || *src == '\t')){
+ src++;
+ srclen--;
+ }
+ if (underscoreok && srclen > 1 && *src == '_') {
+ /* srclen > 1 means not last character */
+ src++;
+ srclen--;
+ }
+ }
+
+ if (ndone == 0)
+ return "no data bytes specified by input";
+ if (lenp != NULL)
+ *lenp = ndone;
+ return NULL;
+}
+
+/*
+ - ttodata - convert text to data
+ */
+const char * /* NULL on success, else literal */
+ttodata(src, srclen, base, dst, dstlen, lenp)
+const char *src;
+size_t srclen; /* 0 means apply strlen() */
+int base; /* 0 means figure it out */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+size_t *lenp; /* where to record length (NULL is nowhere) */
+{
+ return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL,
+ (size_t)0, TTODATAV_SPACECOUNTS);
+}
+
+/*
+ - atodata - convert ASCII to data
+ * backward-compatibility interface
+ */
+size_t /* 0 for failure, true length for success */
+atodata(src, srclen, dst, dstlen)
+const char *src;
+size_t srclen;
+char *dst;
+size_t dstlen;
+{
+ size_t len;
+ const char *err;
+
+ err = ttodata(src, srclen, 0, dst, dstlen, &len);
+ if (err != NULL)
+ return 0;
+ return len;
+}
+
+/*
+ - atobytes - convert ASCII to data bytes
+ * another backward-compatibility interface
+ */
+const char *
+atobytes(src, srclen, dst, dstlen, lenp)
+const char *src;
+size_t srclen;
+char *dst;
+size_t dstlen;
+size_t *lenp;
+{
+ return ttodata(src, srclen, 0, dst, dstlen, lenp);
+}
+
+/*
+ - unhex - convert two ASCII hex digits to byte
+ */
+static int /* number of result bytes, or error code */
+unhex(src, dst, dstlen)
+const char *src; /* known to be full length */
+char *dst;
+size_t dstlen; /* not large enough is a failure */
+{
+ char *p;
+ unsigned byte;
+ static char hex[] = "0123456789abcdef";
+
+ if (dstlen < 1)
+ return SHORT;
+
+ p = strchr(hex, *src);
+ if (p == NULL)
+ p = strchr(hex, tolower(*src));
+ if (p == NULL)
+ return BADCH0;
+ byte = (p - hex) << 4;
+ src++;
+
+ p = strchr(hex, *src);
+ if (p == NULL)
+ p = strchr(hex, tolower(*src));
+ if (p == NULL)
+ return BADCH1;
+ byte |= (p - hex);
+
+ *dst = byte;
+ return 1;
+}
+
+/*
+ - unb64 - convert four ASCII base64 digits to three bytes
+ * Note that a base64 digit group is padded out with '=' if it represents
+ * less than three bytes: one byte is dd==, two is ddd=, three is dddd.
+ */
+static int /* number of result bytes, or error code */
+unb64(src, dst, dstlen)
+const char *src; /* known to be full length */
+char *dst;
+size_t dstlen;
+{
+ char *p;
+ unsigned byte1;
+ unsigned byte2;
+ static char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ if (dstlen < 3)
+ return SHORT;
+
+ p = strchr(base64, *src++);
+
+ if (p == NULL)
+ return BADCH0;
+ byte1 = (p - base64) << 2; /* first six bits */
+
+ p = strchr(base64, *src++);
+ if (p == NULL) {
+ return BADCH1;
+ }
+
+ byte2 = p - base64; /* next six: two plus four */
+ *dst++ = byte1 | (byte2 >> 4);
+ byte1 = (byte2 & 0xf) << 4;
+
+ p = strchr(base64, *src++);
+ if (p == NULL) {
+ if (*(src-1) == '=' && *src == '=') {
+ if (byte1 != 0) /* bad padding */
+ return BADPAD;
+ return 1;
+ }
+ return BADCH2;
+ }
+
+ byte2 = p - base64; /* next six: four plus two */
+ *dst++ = byte1 | (byte2 >> 2);
+ byte1 = (byte2 & 0x3) << 6;
+
+ p = strchr(base64, *src++);
+ if (p == NULL) {
+ if (*(src-1) == '=') {
+ if (byte1 != 0) /* bad padding */
+ return BADPAD;
+ return 2;
+ }
+ return BADCH3;
+ }
+ byte2 = p - base64; /* last six */
+ *dst++ = byte1 | byte2;
+
+ return 3;
+}
+
+/*
+ - untext - convert one ASCII character to byte
+ */
+static int /* number of result bytes, or error code */
+untext(src, dst, dstlen)
+const char *src; /* known to be full length */
+char *dst;
+size_t dstlen; /* not large enough is a failure */
+{
+ if (dstlen < 1)
+ return SHORT;
+
+ *dst = *src;
+ return 1;
+}
+
+/*
+ - badch - produce a nice complaint about an unknown character
+ *
+ * If the compiler complains that the array bigenough[] has a negative
+ * size, that means the TTODATAV_BUF constant has been set too small.
+ */
+static const char * /* literal or errp */
+badch(src, errcode, errp, errlen)
+const char *src;
+int errcode;
+char *errp; /* might be NULL */
+size_t errlen;
+{
+ static const char pre[] = "unknown character (`";
+ static const char suf[] = "') in input";
+ char buf[5];
+# define REQD (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf))
+ struct sizecheck {
+ char bigenough[TTODATAV_BUF - REQD]; /* see above */
+ };
+ char ch;
+
+ if (errp == NULL || errlen < REQD)
+ return "unknown character in input";
+ strcpy(errp, pre);
+ ch = *(src + BADOFF(errcode));
+ if (isprint(ch)) {
+ buf[0] = ch;
+ buf[1] = '\0';
+ } else {
+ buf[0] = '\\';
+ buf[1] = ((ch & 0700) >> 6) + '0';
+ buf[2] = ((ch & 0070) >> 3) + '0';
+ buf[3] = ((ch & 0007) >> 0) + '0';
+ buf[4] = '\0';
+ }
+ strcat(errp, buf);
+ strcat(errp, suf);
+ return (const char *)errp;
+}
+
+
+
+#ifdef TTODATA_MAIN
+
+#include <stdio.h>
+
+struct artab;
+static void check(struct artab *r, char *buf, size_t n, err_t oops, int *status);
+static void regress(char *pgm);
+static void hexout(const char *s, size_t len, FILE *f);
+
+/*
+ - main - convert first argument to hex, or run regression
+ */
+int
+main(int argc, char *argv[])
+{
+ char buf[1024];
+ char buf2[1024];
+ char err[512];
+ size_t n;
+ size_t i;
+ char *p = buf;
+ char *p2 = buf2;
+ char *pgm = argv[0];
+ const char *oops;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {0x<hex>|0s<base64>|-r}\n", pgm);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress(pgm); /* should not return */
+ fprintf(stderr, "%s: regress() returned?!?\n", pgm);
+ exit(1);
+ }
+
+ oops = ttodatav(argv[1], 0, 0, buf, sizeof(buf), &n,
+ err, sizeof(err), TTODATAV_IGNORESPACE);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: ttodata error `%s' in `%s'\n", pgm,
+ oops, argv[1]);
+ exit(1);
+ }
+
+ if (n > sizeof(buf)) {
+ p = (char *)malloc((size_t)n);
+ if (p == NULL) {
+ fprintf(stderr,
+ "%s: unable to malloc %d bytes for result\n",
+ pgm, n);
+ exit(1);
+ }
+ oops = ttodata(argv[1], 0, 0, p, n, &n);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: error `%s' in ttodata retry?!?\n",
+ pgm, oops);
+ exit(1);
+ }
+ }
+
+ hexout(p, n, stdout);
+ printf("\n");
+
+ i = datatot(buf, n, 'h', buf2, sizeof(buf2));
+ if (i == 0) {
+ fprintf(stderr, "%s: datatot reports error in `%s'\n", pgm,
+ argv[1]);
+ exit(1);
+ }
+
+ if (i > sizeof(buf2)) {
+ p2 = (char *)malloc((size_t)i);
+ if (p == NULL) {
+ fprintf(stderr,
+ "%s: unable to malloc %d bytes for result\n",
+ pgm, i);
+ exit(1);
+ }
+ i = datatot(buf, n, 'h', p2, i);
+ if (i == 0) {
+ fprintf(stderr, "%s: error in datatoa retry?!?\n", pgm);
+ exit(1);
+ }
+ }
+
+ printf("%s\n", p2);
+
+ exit(0);
+}
+
+/*
+ - hexout - output an arbitrary-length string in hex
+ */
+static void
+hexout(s, len, f)
+const char *s;
+size_t len;
+FILE *f;
+{
+ size_t i;
+
+ fprintf(f, "0x");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", (unsigned char)s[i]);
+}
+
+struct artab {
+ int base;
+# define IGNORESPACE_BIAS 1000
+ char *ascii; /* NULL for end */
+ char *data; /* NULL for error expected */
+} atodatatab[] = {
+ { 0, "", NULL, },
+ { 0, "0", NULL, },
+ { 0, "0x", NULL, },
+ { 0, "0xa", NULL, },
+ { 0, "0xab", "\xab", },
+ { 0, "0xabc", NULL, },
+ { 0, "0xabcd", "\xab\xcd", },
+ { 0, "0x0123456789", "\x01\x23\x45\x67\x89", },
+ { 0, "0x01x", NULL, },
+ { 0, "0xabcdef", "\xab\xcd\xef", },
+ { 0, "0xABCDEF", "\xab\xcd\xef", },
+ { 0, "0XaBc0eEd81f", "\xab\xc0\xee\xd8\x1f", },
+ { 0, "0XaBc0_eEd8", "\xab\xc0\xee\xd8", },
+ { 0, "0XaBc0_", NULL, },
+ { 0, "0X_aBc0", NULL, },
+ { 0, "0Xa_Bc0", NULL, },
+ { 16, "aBc0eEd8", "\xab\xc0\xee\xd8", },
+ { 0, "0s", NULL, },
+ { 0, "0sA", NULL, },
+ { 0, "0sBA", NULL, },
+ { 0, "0sCBA", NULL, },
+ { 0, "0sDCBA", "\x0c\x20\x40", },
+ { 0, "0SDCBA", "\x0c\x20\x40", },
+ { 0, "0sDA==", "\x0c", },
+ { 0, "0sDC==", NULL, },
+ { 0, "0sDCA=", "\x0c\x20", },
+ { 0, "0sDCB=", NULL, },
+ { 0, "0sDCAZ", "\x0c\x20\x19", },
+ { 0, "0sDCAa", "\x0c\x20\x1a", },
+ { 0, "0sDCAz", "\x0c\x20\x33", },
+ { 0, "0sDCA0", "\x0c\x20\x34", },
+ { 0, "0sDCA9", "\x0c\x20\x3d", },
+ { 0, "0sDCA+", "\x0c\x20\x3e", },
+ { 0, "0sDCA/", "\x0c\x20\x3f", },
+ { 0, "0sAbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0s AbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sA braCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAb raCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbr aCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbra Cadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraC adabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCa dabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCad abra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCada bra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadab ra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadabr a+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadabra +", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadabra+ ", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { 0, "0t", NULL, },
+ { 0, "0tabc_xyz", "abc_xyz", },
+ { 256, "abc_xyz", "abc_xyz", },
+ { 0, NULL, NULL, },
+};
+
+struct drtab {
+ char *data; /* input; NULL for end */
+ char format;
+ int buflen; /* -1 means big buffer */
+ int outlen; /* -1 means strlen(ascii)+1 */
+ char *ascii; /* NULL for error expected */
+} datatoatab[] = {
+ { "", 'x', -1, -1, NULL, },
+ { "", 'X', -1, -1, NULL, },
+ { "", 'n', -1, -1, NULL, },
+ { "0", 'x', -1, -1, "0x30", },
+ { "0", 'x', 0, 5, "---", },
+ { "0", 'x', 1, 5, "", },
+ { "0", 'x', 2, 5, "0", },
+ { "0", 'x', 3, 5, "0x", },
+ { "0", 'x', 4, 5, "0x3", },
+ { "0", 'x', 5, 5, "0x30", },
+ { "0", 'x', 6, 5, "0x30", },
+ { "\xab\xcd", 'x', -1, -1, "0xabcd", },
+ { "\x01\x23\x45\x67\x89", 'x', -1, -1, "0x0123456789", },
+ { "\xab\xcd\xef", 'x', -1, -1, "0xabcdef", },
+ { "\xab\xc0\xee\xd8\x1f", 'x', -1, -1, "0xabc0eed81f", },
+ { "\x01\x02", 'h', -1, -1, "0x0102", },
+ { "\x01\x02\x03\x04\x05\x06", 'h', -1, -1, "0x01020304_0506", },
+ { "\xab\xc0\xee\xd8\x1f", 16, -1, -1, "abc0eed81f", },
+ { "\x0c\x20\x40", 's', -1, -1, "0sDCBA", },
+ { "\x0c\x20\x40", 's', 0, 7, "---", },
+ { "\x0c\x20\x40", 's', 1, 7, "", },
+ { "\x0c\x20\x40", 's', 2, 7, "0", },
+ { "\x0c\x20\x40", 's', 3, 7, "0s", },
+ { "\x0c\x20\x40", 's', 4, 7, "0sD", },
+ { "\x0c\x20\x40", 's', 5, 7, "0sDC", },
+ { "\x0c\x20\x40", 's', 6, 7, "0sDCB", },
+ { "\x0c\x20\x40", 's', 7, 7, "0sDCBA", },
+ { "\x0c\x20\x40", 's', 8, 7, "0sDCBA", },
+ { "\x0c", 's', -1, -1, "0sDA==", },
+ { "\x0c\x20", 's', -1, -1, "0sDCA=", },
+ { "\x0c\x20\x19", 's', -1, -1, "0sDCAZ", },
+ { "\x0c\x20\x1a", 's', -1, -1, "0sDCAa", },
+ { "\x0c\x20\x33", 's', -1, -1, "0sDCAz", },
+ { "\x0c\x20\x34", 's', -1, -1, "0sDCA0", },
+ { "\x0c\x20\x3d", 's', -1, -1, "0sDCA9", },
+ { "\x0c\x20\x3e", 's', -1, -1, "0sDCA+", },
+ { "\x0c\x20\x3f", 's', -1, -1, "0sDCA/", },
+ { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 's', -1, -1, "0sAbraCadabra+", },
+ { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 64, -1, -1, "AbraCadabra+", },
+ { NULL, 'x', -1, -1, NULL, },
+};
+
+/*
+ - regress - regression-test ttodata() and datatot()
+ */
+static void
+check(r, buf, n, oops, status)
+struct artab *r;
+char *buf;
+size_t n;
+err_t oops;
+int *status;
+{
+ if (oops != NULL && r->data == NULL)
+ {} /* error expected */
+ else if (oops != NULL) {
+ printf("`%s' gave error `%s', expecting %d `", r->ascii,
+ oops, strlen(r->data));
+ hexout(r->data, strlen(r->data), stdout);
+ printf("'\n");
+ *status = 1;
+ } else if (r->data == NULL) {
+ printf("`%s' gave %d `", r->ascii, n);
+ hexout(buf, n, stdout);
+ printf("', expecting error\n");
+ *status = 1;
+ } else if (n != strlen(r->data)) {
+ printf("length wrong in `%s': got %d `", r->ascii, n);
+ hexout(buf, n, stdout);
+ printf("', expecting %d `", strlen(r->data));
+ hexout(r->data, strlen(r->data), stdout);
+ printf("'\n");
+ *status = 1;
+ } else if (memcmp(buf, r->data, n) != 0) {
+ printf("`%s' gave %d `", r->ascii, n);
+ hexout(buf, n, stdout);
+ printf("', expecting %d `", strlen(r->data));
+ hexout(r->data, strlen(r->data), stdout);
+ printf("'\n");
+ *status = 1;
+ }
+ fflush(stdout);
+}
+
+static void /* should not return at all, in fact */
+regress(pgm)
+char *pgm;
+{
+ struct artab *r;
+ struct drtab *dr;
+ char buf[100];
+ size_t n;
+ int status = 0;
+
+ for (r = atodatatab; r->ascii != NULL; r++) {
+ int base = r->base;
+ int xbase = 0;
+
+ if ((base == 0 || base == IGNORESPACE_BIAS + 0) && r->ascii[0] == '0') {
+ switch (r->ascii[1]) {
+ case 'x':
+ case 'X':
+ xbase = 16;
+ break;
+ case 's':
+ case 'S':
+ xbase = 64;
+ break;
+ case 't':
+ case 'T':
+ xbase = 256;
+ break;
+ }
+ }
+
+ if (base >= IGNORESPACE_BIAS) {
+ base = base - IGNORESPACE_BIAS;
+ check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ if (xbase != 0)
+ check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ } else {
+ check(r, buf, n, ttodata(r->ascii, 0, base, buf, sizeof(buf), &n), &status);
+ if (base == 64 || xbase == 64)
+ check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ if (xbase != 0) {
+ check(r, buf, n, ttodata(r->ascii+2, 0, xbase, buf, sizeof(buf), &n), &status);
+ if (base == 64 || xbase == 64)
+ check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ }
+ }
+ }
+ for (dr = datatoatab; dr->data != NULL; dr++) {
+ size_t should;
+
+ strcpy(buf, "---");
+ n = datatot(dr->data, strlen(dr->data), dr->format, buf,
+ (dr->buflen == -1) ? sizeof(buf) : dr->buflen);
+ should = (dr->ascii == NULL) ? 0 : strlen(dr->ascii) + 1;
+ if (dr->outlen != -1)
+ should = dr->outlen;
+ if (n == 0 && dr->ascii == NULL)
+ {} /* error expected */
+ else if (n == 0) {
+ printf("`");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("' %c gave error, expecting %d `%s'\n",
+ dr->format, should, dr->ascii);
+ status = 1;
+ } else if (dr->ascii == NULL) {
+ printf("`");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("' %c gave %d `%.*s', expecting error\n",
+ dr->format, n, (int)n, buf);
+ status = 1;
+ } else if (n != should) {
+ printf("length wrong in `");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("': got %d `%s'", n, buf);
+ printf(", expecting %d `%s'\n", should, dr->ascii);
+ status = 1;
+ } else if (strcmp(buf, dr->ascii) != 0) {
+ printf("`");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("' gave %d `%s'", n, buf);
+ printf(", expecting %d `%s'\n", should, dr->ascii);
+ status = 1;
+ }
+ fflush(stdout);
+ }
+ exit(status);
+}
+
+#endif /* TTODATA_MAIN */
diff --git a/linux/lib/libfreeswan/ttoprotoport.c b/linux/lib/libfreeswan/ttoprotoport.c
new file mode 100644
index 000000000..46321838c
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoprotoport.c
@@ -0,0 +1,103 @@
+/*
+ * conversion from protocol/port string to protocol and port
+ * Copyright (C) 2002 Mario Strasser <mast@gmx.net>,
+ * Zuercher Hochschule Winterthur,
+ *
+ * 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: ttoprotoport.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ * ttoprotoport - converts from protocol/port string to protocol and port
+ */
+err_t
+ttoprotoport(src, src_len, proto, port, has_port_wildcard)
+char *src; /* input string */
+size_t src_len; /* length of input string, use strlen() if 0 */
+u_int8_t *proto; /* extracted protocol number */
+u_int16_t *port; /* extracted port number if it exists */
+int *has_port_wildcard; /* set if port is %any */
+{
+ char *end, *service_name;
+ char proto_name[16];
+ int proto_len;
+ long int l;
+ struct protoent *protocol;
+ struct servent *service;
+
+ /* get the length of the string */
+ if (!src_len) src_len = strlen(src);
+
+ /* locate delimiter '/' between protocol and port */
+ end = strchr(src, '/');
+ if (end != NULL) {
+ proto_len = end - src;
+ service_name = end + 1;
+ } else {
+ proto_len = src_len;
+ service_name = src + src_len;
+ }
+
+ /* copy protocol name*/
+ memset(proto_name, '\0', sizeof(proto_name));
+ memcpy(proto_name, src, proto_len);
+
+ /* extract protocol by trying to resolve it by name */
+ protocol = getprotobyname(proto_name);
+ if (protocol != NULL) {
+ *proto = protocol->p_proto;
+ }
+ else /* failed, now try it by number */
+ {
+ l = strtol(proto_name, &end, 0);
+
+ if (*proto_name && *end)
+ return "<protocol> is neither a number nor a valid name";
+
+ if (l < 0 || l > 0xff)
+ return "<protocol> must be between 0 and 255";
+
+ *proto = (u_int8_t)l;
+ }
+
+ /* is there a port wildcard? */
+ *has_port_wildcard = (strcmp(service_name, "%any") == 0);
+
+ if (*has_port_wildcard)
+ {
+ *port = 0;
+ return NULL;
+ }
+
+ /* extract port by trying to resolve it by name */
+ service = getservbyname(service_name, NULL);
+ if (service != NULL) {
+ *port = ntohs(service->s_port);
+ }
+ else /* failed, now try it by number */
+ {
+ l = strtol(service_name, &end, 0);
+
+ if (*service_name && *end)
+ return "<port> is neither a number nor a valid name";
+
+ if (l < 0 || l > 0xffff)
+ return "<port> must be between 0 and 65535";
+
+ *port = (u_int16_t)l;
+ }
+ return NULL;
+}
+
diff --git a/linux/lib/libfreeswan/ttosa.3 b/linux/lib/libfreeswan/ttosa.3
new file mode 100644
index 000000000..bf918e108
--- /dev/null
+++ b/linux/lib/libfreeswan/ttosa.3
@@ -0,0 +1,288 @@
+.TH IPSEC_TTOSA 3 "26 Nov 2001"
+.\" RCSID $Id: ttosa.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ttosa, satot \- convert IPsec Security Association IDs to and from text
+.br
+ipsec initsaid \- initialize an SA ID
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "typedef struct {"
+.ti +1c
+.B "ip_address dst;"
+.ti +1c
+.B "ipsec_spi_t spi;"
+.ti +1c
+.B "int proto;"
+.br
+.B "} ip_said;"
+.sp
+.B "const char *ttosa(const char *src, size_t srclen,"
+.ti +1c
+.B "ip_said *sa);
+.br
+.B "size_t satot(const ip_said *sa, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.br
+.B "void initsaid(const ip_address *addr, ipsec_spi_t spi,"
+.ti +1c
+.B "int proto, ip_said *dst);"
+.SH DESCRIPTION
+.I Ttosa
+converts an ASCII Security Association (SA) specifier into an
+.B ip_said
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+.I Satot
+does the reverse conversion, back to a text SA specifier.
+.I Initsaid
+initializes an
+.B ip_said
+from separate items of information.
+.PP
+An SA is specified in text with a mail-like syntax, e.g.
+.BR esp.5a7@1.2.3.4 .
+An SA specifier contains
+a protocol prefix (currently
+.BR ah ,
+.BR esp ,
+.BR tun ,
+.BR comp ,
+or
+.BR int ),
+a single character indicating the address family
+.RB ( .
+for IPv4,
+.B :
+for IPv6),
+an unsigned integer SPI number in hexadecimal (with no
+.B 0x
+prefix),
+and an IP address.
+The IP address can be any form accepted by
+.IR ipsec_ttoaddr (3),
+e.g. dotted-decimal IPv4 address,
+colon-hex IPv6 address,
+or DNS name.
+.PP
+As a special case, the SA specifier
+.B %passthrough4
+or
+.B %passthrough6
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, these are synonyms for
+.B tun.0@0.0.0.0
+and
+.B tun:0@::
+respectively,
+but that is subject to change without notice.)
+.B %passthrough
+is a historical synonym for
+.BR %passthrough4 .
+These forms are known to both
+.I ttosa
+and
+.IR satot ,
+so the internal representation is never visible.
+.PP
+Similarly, the SA specifiers
+.BR %pass ,
+.BR %drop ,
+.BR %reject ,
+.BR %hold ,
+.BR %trap ,
+and
+.BR %trapsubnet
+signify special ``magic'' SAs used to indicate that packets should be
+passed, dropped, rejected (dropped with ICMP notification),
+held,
+and trapped (sent up to
+.IR ipsec_pluto (8),
+with either of two forms of
+.B %hold
+automatically installed)
+respectively.
+These forms too are known to both routines,
+so the internal representation of the magic SAs should never be visible.
+.PP
+The
+.B <freeswan.h>
+header file supplies the
+.B ip_said
+structure, as well as a data type
+.B ipsec_spi_t
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+.PP
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+.B <freeswan.h>
+defines the names
+.BR SA_ESP ,
+.BR SA_AH ,
+.BR SA_IPIP ,
+and
+.BR SA_COMP
+to have the same values as the kernel names
+.BR IPPROTO_ESP ,
+.BR IPPROTO_AH ,
+.BR IPPROTO_IPIP ,
+and
+.BR IPPROTO_COMP .
+.PP
+.B <freeswan.h>
+also defines
+.BR SA_INT
+to have the value
+.BR 61
+(reserved by IANA for ``any host internal protocol'')
+and
+.BR SPI_PASS ,
+.BR SPI_DROP ,
+.BR SPI_REJECT ,
+.BR SPI_HOLD ,
+and
+.B SPI_TRAP
+to have the values 256-260 (in \fIhost\fR byte order) respectively.
+These are used in constructing the magic SAs
+(which always have address
+.BR 0.0.0.0 ).
+.PP
+If
+.I satot
+encounters an unknown protocol code, e.g. 77,
+it yields output using a prefix
+showing the code numerically, e.g. ``unk77''.
+This form is
+.I not
+recognized by
+.IR ttosa .
+.PP
+The
+.I srclen
+parameter of
+.I ttosa
+specifies the length of the string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I satot
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.B <freeswan.h>
+header file defines a constant,
+.BR SATOT_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I satot
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI,
+dotted-decimal or colon-hex address).
+The value
+.B 'f'
+is similar except that the SPI is padded with
+.BR 0 s
+to a fixed 32-bit width, to ease aligning displayed tables.
+.PP
+.I Ttosa
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Satot
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.PP
+There is also, temporarily, support for some obsolete
+forms of SA specifier which lack the address-family indicator.
+.SH SEE ALSO
+ipsec_ttoul(3), ipsec_ttoaddr(3), ipsec_samesaid(3), inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttosa
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+.B @
+in input;
+unknown protocol prefix;
+conversion error in
+.I ttoul
+or
+.IR ttoaddr .
+.PP
+Fatal errors in
+.I satot
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = ttosa( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/ttosa.c b/linux/lib/libfreeswan/ttosa.c
new file mode 100644
index 000000000..aa2283694
--- /dev/null
+++ b/linux/lib/libfreeswan/ttosa.c
@@ -0,0 +1,280 @@
+/*
+ * convert from text form of SA ID to binary
+ * Copyright (C) 2000, 2001 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttosa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct satype {
+ char *prefix;
+ size_t prelen; /* strlen(prefix) */
+ int proto;
+} satypes[] = {
+ { "ah", 2, SA_AH },
+ { "esp", 3, SA_ESP },
+ { "tun", 3, SA_IPIP },
+ { "comp", 4, SA_COMP },
+ { "int", 3, SA_INT },
+ { NULL, 0, 0, }
+};
+
+static struct magic {
+ char *name;
+ char *really;
+} magic[] = {
+ { PASSTHROUGHNAME, PASSTHROUGH4IS },
+ { PASSTHROUGH4NAME, PASSTHROUGH4IS },
+ { PASSTHROUGH6NAME, PASSTHROUGH6IS },
+ { "%pass", "int256@0.0.0.0" },
+ { "%drop", "int257@0.0.0.0" },
+ { "%reject", "int258@0.0.0.0" },
+ { "%hold", "int259@0.0.0.0" },
+ { "%trap", "int260@0.0.0.0" },
+ { "%trapsubnet", "int261@0.0.0.0" },
+ { NULL, NULL }
+};
+
+/*
+ - ttosa - convert text "ah507@10.0.0.1" to SA identifier
+ */
+err_t /* NULL for success, else string literal */
+ttosa(src, srclen, sa)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+ip_said *sa;
+{
+ const char *at;
+ const char *addr;
+ size_t alen;
+ const char *spi = NULL;
+ struct satype *sat;
+ unsigned long ul;
+ const char *oops;
+ struct magic *mp;
+ size_t nlen;
+# define MINLEN 5 /* ah0@0 is as short as it can get */
+ int af;
+ int base;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ if (srclen < MINLEN)
+ return "string too short to be SA identifier";
+ if (*src == '%') {
+ for (mp = magic; mp->name != NULL; mp++) {
+ nlen = strlen(mp->name);
+ if (srclen == nlen && memcmp(src, mp->name, nlen) == 0)
+ break;
+ }
+ if (mp->name == NULL)
+ return "unknown % keyword";
+ src = mp->really;
+ srclen = strlen(src);
+ }
+
+ at = memchr(src, '@', srclen);
+ if (at == NULL)
+ return "no @ in SA specifier";
+
+ for (sat = satypes; sat->prefix != NULL; sat++)
+ if (sat->prelen < srclen &&
+ strncmp(src, sat->prefix, sat->prelen) == 0) {
+ sa->proto = sat->proto;
+ spi = src + sat->prelen;
+ break; /* NOTE BREAK OUT */
+ }
+ if (sat->prefix == NULL)
+ return "SA specifier lacks valid protocol prefix";
+
+ if (spi >= at)
+ return "no SPI in SA specifier";
+ switch (*spi) {
+ case '.':
+ af = AF_INET;
+ spi++;
+ base = 16;
+ break;
+ case ':':
+ af = AF_INET6;
+ spi++;
+ base = 16;
+ break;
+ default:
+ af = AF_UNSPEC; /* not known yet */
+ base = 0;
+ break;
+ }
+ if (spi >= at)
+ return "no SPI found in SA specifier";
+ oops = ttoul(spi, at - spi, base, &ul);
+ if (oops != NULL)
+ return oops;
+ sa->spi = htonl(ul);
+
+ addr = at + 1;
+ alen = srclen - (addr - src);
+ if (af == AF_UNSPEC)
+ af = (memchr(addr, ':', alen) != NULL) ? AF_INET6 : AF_INET;
+ oops = ttoaddr(addr, alen, af, &sa->dst);
+ if (oops != NULL)
+ return oops;
+
+ return NULL;
+}
+
+
+
+#ifdef TTOSA_MAIN
+
+#include <stdio.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ ip_said sa;
+ char buf[100];
+ char buf2[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = ttosa(argv[1], 0, &sa);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = satot(&sa, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto);
+ fprintf(stderr, "%lx@", (long unsigned int)sa.spi);
+ (void) addrtot(&sa.dst, 0, buf2, sizeof(buf2));
+ fprintf(stderr, "%s", buf2);
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ int format;
+# define FUDGE 0x1000
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {0, "esp257@1.2.3.0", "esp.101@1.2.3.0"},
+ {0, "ah0x20@1.2.3.4", "ah.20@1.2.3.4"},
+ {0, "tun20@1.2.3.4", "tun.14@1.2.3.4"},
+ {0, "comp20@1.2.3.4", "comp.14@1.2.3.4"},
+ {0, "esp257@::1", "esp:101@::1"},
+ {0, "esp257@0bc:12de::1", "esp:101@bc:12de::1"},
+ {0, "esp78@1049:1::8007:2040", "esp:4e@1049:1::8007:2040"},
+ {0, "esp0x78@1049:1::8007:2040", "esp:78@1049:1::8007:2040"},
+ {0, "ah78@1049:1::8007:2040", "ah:4e@1049:1::8007:2040"},
+ {0, "ah0x78@1049:1::8007:2040", "ah:78@1049:1::8007:2040"},
+ {0, "tun78@1049:1::8007:2040", "tun:4e@1049:1::8007:2040"},
+ {0, "tun0x78@1049:1::8007:2040", "tun:78@1049:1::8007:2040"},
+ {0, "duk99@3ffe:370:400:ff::9001:3001", NULL},
+ {0, "esp78x@1049:1::8007:2040", NULL},
+ {0, "esp0x78@1049:1:0xfff::8007:2040", NULL},
+ {0, "es78@1049:1::8007:2040", NULL},
+ {0, "", NULL},
+ {0, "_", NULL},
+ {0, "ah2.2", NULL},
+ {0, "goo2@1.2.3.4", NULL},
+ {0, "esp9@1.2.3.4", "esp.9@1.2.3.4"},
+ {'f', "esp0xa9@1.2.3.4", "esp.000000a9@1.2.3.4"},
+ {0, "espp9@1.2.3.4", NULL},
+ {0, "es9@1.2.3.4", NULL},
+ {0, "ah@1.2.3.4", NULL},
+ {0, "esp7x7@1.2.3.4", NULL},
+ {0, "esp77@1.0x2.3.4", NULL},
+ {0, PASSTHROUGHNAME, PASSTHROUGH4NAME},
+ {0, PASSTHROUGH6NAME, PASSTHROUGH6NAME},
+ {0, "%pass", "%pass"},
+ {0, "int256@0.0.0.0", "%pass"},
+ {0, "%drop", "%drop"},
+ {0, "int257@0.0.0.0", "%drop"},
+ {0, "%reject", "%reject"},
+ {0, "int258@0.0.0.0", "%reject"},
+ {0, "%hold", "%hold"},
+ {0, "int259@0.0.0.0", "%hold"},
+ {0, "%trap", "%trap"},
+ {0, "int260@0.0.0.0", "%trap"},
+ {0, "%trapsubnet", "%trapsubnet"},
+ {0, "int261@0.0.0.0", "%trapsubnet"},
+ {0, "int262@0.0.0.0", "int.106@0.0.0.0"},
+ {FUDGE, "esp9@1.2.3.4", "unk77.9@1.2.3.4"},
+ {0, NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ ip_said sa;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = ttosa(in, 0, &sa);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' ttosa failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' ttosa succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ if (r->format&FUDGE)
+ sa.proto = 77;
+ n = satot(&sa, (char)r->format, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' satot failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* TTOSA_MAIN */
diff --git a/linux/lib/libfreeswan/ttosubnet.c b/linux/lib/libfreeswan/ttosubnet.c
new file mode 100644
index 000000000..7f5cddb82
--- /dev/null
+++ b/linux/lib/libfreeswan/ttosubnet.c
@@ -0,0 +1,296 @@
+/*
+ * convert from text form of subnet specification to binary
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttosubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#ifndef DEFAULTSUBNET
+#define DEFAULTSUBNET "%default"
+#endif
+
+/*
+ - ttosubnet - convert text "addr/mask" to address and mask
+ * Mask can be integer bit count.
+ */
+err_t
+ttosubnet(src, srclen, af, dst)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+int af; /* AF_INET or AF_INET6 */
+ip_subnet *dst;
+{
+ const char *slash;
+ const char *colon;
+ const char *mask;
+ size_t mlen;
+ const char *oops;
+ unsigned long bc;
+ static char def[] = DEFAULTSUBNET;
+# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */
+ static char defis4[] = "0/0";
+# define DEFIS4LEN (sizeof(defis4) - 1)
+ static char defis6[] = "::/0";
+# define DEFIS6LEN (sizeof(defis6) - 1)
+ ip_address addrtmp;
+ ip_address masktmp;
+ int nbits;
+ int i;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ switch (af) {
+ case AF_INET:
+ nbits = 32;
+ break;
+ case AF_INET6:
+ nbits = 128;
+ break;
+ default:
+ return "unknown address family in ttosubnet";
+ break;
+ }
+
+ if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) {
+ src = (af == AF_INET) ? defis4 : defis6;
+ srclen = (af == AF_INET) ? DEFIS4LEN : DEFIS6LEN;
+ }
+
+ slash = memchr(src, '/', srclen);
+ if (slash == NULL)
+ return "no / in subnet specification";
+ mask = slash + 1;
+ mlen = srclen - (mask - src);
+
+ oops = ttoaddr(src, slash-src, af, &addrtmp);
+ if (oops != NULL)
+ return oops;
+
+ /* extract port */
+ colon = memchr(mask, ':', mlen);
+ if (colon == 0)
+ {
+ setportof(0, &addrtmp);
+ }
+ else
+ {
+ long port;
+
+ oops = ttoul(colon+1, mlen-(colon-mask+1), 10, &port);
+ if (oops != NULL)
+ return oops;
+ setportof(htons(port), &addrtmp);
+ mlen = colon - mask;
+ }
+
+ /*extract mask */
+ oops = ttoul(mask, mlen, 10, &bc);
+ if (oops == NULL) {
+ /* ttoul succeeded, it's a bit-count mask */
+ if (bc > nbits)
+ return "subnet mask bit count too large";
+ i = bc;
+ } else {
+ oops = ttoaddr(mask, mlen, af, &masktmp);
+ if (oops != NULL)
+ return oops;
+ i = masktocount(&masktmp);
+ if (i < 0)
+ return "non-contiguous or otherwise erroneous mask";
+ }
+
+ return initsubnet(&addrtmp, i, '0', dst);
+}
+
+
+
+#ifdef TTOSUBNET_MAIN
+
+#include <stdio.h>
+
+void regress(void);
+
+int main(int argc, char *argv[])
+{
+ ip_subnet s;
+ char buf[100];
+ char buf2[100];
+ const char *oops;
+ size_t n;
+ int af;
+ char *p;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [-6] addr/mask\n", argv[0]);
+ fprintf(stderr, " or: %s -r\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ af = AF_INET;
+ p = argv[1];
+ if (strcmp(argv[1], "-6") == 0) {
+ af = AF_INET6;
+ p = argv[2];
+ } else if (strchr(argv[1], ':') != NULL)
+ af = AF_INET6;
+
+ oops = ttosubnet(p, 0, af, &s);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = subnettot(&s, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion of ", argv[0]);
+ (void) addrtot(&s.addr, 0, buf2, sizeof(buf2));
+ fprintf(stderr, "%s/", buf2);
+ fprintf(stderr, "%d", s.maskbits);
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ int family;
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {4, "1.2.3.0/255.255.255.0", "1.2.3.0/24"},
+ {4, "1.2.3.0/24", "1.2.3.0/24"},
+ {4, "1.2.3.0/24:10", "1.2.3.0/24:10"},
+ {4, "1.2.3.0/24:-1", NULL},
+ {4, "1.2.3.0/24:none", NULL},
+ {4, "1.2.3.0/24:", NULL},
+ {4, "1.2.3.0/24:0x10", "1.2.3.0/24:16"},
+ {4, "1.2.3.0/24:0X10", "1.2.3.0/24:16"},
+ {4, "1.2.3.0/24:010", "1.2.3.0/24:8"},
+ {4, "1.2.3.1/255.255.255.240", "1.2.3.0/28"},
+ {4, "1.2.3.1/32", "1.2.3.1/32"},
+ {4, "1.2.3.1/0", "0.0.0.0/0"},
+/* {4, "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0"}, */
+ {4, "1.2.3.1/255.255.127.0", NULL},
+ {4, "128.009.000.032/32", "128.9.0.32/32"},
+ {4, "128.0x9.0.32/32", NULL},
+ {4, "0x80090020/32", "128.9.0.32/32"},
+ {4, "0x800x0020/32", NULL},
+ {4, "128.9.0.32/0xffFF0000", "128.9.0.0/16"},
+ {4, "128.9.0.32/0xff0000FF", NULL},
+ {4, "128.9.0.32/0x0000ffFF", NULL},
+ {4, "128.9.0.32/0x00ffFF0000", NULL},
+ {4, "128.9.0.32/0xffFF", NULL},
+ {4, "128.9.0.32.27/32", NULL},
+ {4, "128.9.0k32/32", NULL},
+ {4, "328.9.0.32/32", NULL},
+ {4, "128.9..32/32", NULL},
+ {4, "10/8", "10.0.0.0/8"},
+ {4, "10.0/8", "10.0.0.0/8"},
+ {4, "10.0.0/8", "10.0.0.0/8"},
+ {4, "10.0.1/24", "10.0.1.0/24"},
+ {4, "_", NULL},
+ {4, "_/_", NULL},
+ {4, "1.2.3.1", NULL},
+ {4, "1.2.3.1/_", NULL},
+ {4, "1.2.3.1/24._", NULL},
+ {4, "1.2.3.1/99", NULL},
+ {4, "localhost/32", "127.0.0.1/32"},
+ {4, "%default", "0.0.0.0/0"},
+ {6, "3049:1::8007:2040/0", "::/0"},
+ {6, "3049:1::8007:2040/128", "3049:1::8007:2040/128"},
+ {6, "3049:1::192.168.0.1/128", NULL}, /*"3049:1::c0a8:1/128",*/
+ {6, "3049:1::8007::2040/128", NULL},
+ {6, "3049:1::8007:2040/ffff::0", "3049::/16"},
+ {6, "3049:1::8007:2040/64", "3049:1::/64"},
+ {6, "3049:1::8007:2040/ffff::", "3049::/16"},
+ {6, "3049:1::8007:2040/0000:ffff::0", NULL},
+ {6, "3049:1::8007:2040/ff1f::0", NULL},
+ {6, "3049:1::8007:x:2040/128", NULL},
+ {6, "3049:1t::8007:2040/128", NULL},
+ {6, "3049:1::80071:2040/128", NULL},
+ {6, "::/21", "::/21"},
+ {6, "::1/128", "::1/128"},
+ {6, "1::/21", "1::/21"},
+ {6, "1::2/128", "1::2/128"},
+ {6, "1:0:0:0:0:0:0:2/128", "1::2/128"},
+ {6, "1:0:0:0:3:0:0:2/128", "1::3:0:0:2/128"},
+ {6, "1:0:0:3:0:0:0:2/128", "1::3:0:0:0:2/128"},
+ {6, "1:0:3:0:0:0:0:2/128", "1:0:3::2/128"},
+ {6, "abcd:ef01:2345:6789:0:00a:000:20/128", "abcd:ef01:2345:6789:0:a:0:20/128"},
+ {6, "3049:1::8007:2040/ffff:ffff:", NULL},
+ {6, "3049:1::8007:2040/ffff:88::", NULL},
+ {6, "3049:12::9000:3200/ffff:fff0::", "3049:10::/28"},
+ {6, "3049:12::9000:3200/28", "3049:10::/28"},
+ {6, "3049:12::9000:3200/ff00:::", NULL},
+ {6, "3049:12::9000:3200/ffff:::", NULL},
+ {6, "3049:12::9000:3200/128_", NULL},
+ {6, "3049:12::9000:3200/", NULL},
+ {6, "%default", "::/0"},
+ {4, NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ ip_subnet s;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+ int af;
+
+ for (r = rtab; r->input != NULL; r++) {
+ af = (r->family == 4) ? AF_INET : AF_INET6;
+ strcpy(in, r->input);
+ oops = ttosubnet(in, 0, af, &s);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' ttosubnet failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' ttosubnet succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = subnettot(&s, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' subnettot failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* TTOSUBNET_MAIN */
diff --git a/linux/lib/libfreeswan/ttoul.3 b/linux/lib/libfreeswan/ttoul.3
new file mode 100644
index 000000000..67d4bd34f
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoul.3
@@ -0,0 +1,192 @@
+.TH IPSEC_TTOUL 3 "16 Aug 2000"
+.\" RCSID $Id: ttoul.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ttoul, ultot \- convert unsigned-long numbers to and from text
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *ttoul(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, unsigned long *n);"
+.br
+.B "size_t ultot(unsigned long n, int format, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+.I Ttoul
+converts a text-string number into a binary
+.B "unsigned long"
+value.
+.I Ultot
+does the reverse conversion, back to a text version.
+.PP
+Numbers are specified in text as
+decimal (e.g.
+.BR 123 ),
+octal with a leading zero (e.g.
+.BR 012 ,
+which has value 10),
+or hexadecimal with a leading
+.B 0x
+(e.g.
+.BR 0x1f ,
+which has value 31)
+in either upper or lower case.
+.PP
+The
+.I srclen
+parameter of
+.I ttoul
+specifies the length of the string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I base
+parameter of
+.I ttoul
+can be
+.BR 8 ,
+.BR 10 ,
+or
+.BR 16 ,
+in which case the number supplied is assumed to be of that form
+(and in the case of
+.BR 16 ,
+to lack any
+.B 0x
+prefix).
+It can also be
+.BR 0 ,
+in which case the number is examined for a leading zero
+or a leading
+.B 0x
+to determine its base.
+.PP
+The
+.I dstlen
+parameter of
+.I ultot
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR ULTOT_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I ultot
+must be one of:
+.RS
+.IP \fB'o'\fR 4
+octal conversion with leading
+.B 0
+.IP \fB\ 8\fR
+octal conversion with no leading
+.B 0
+.IP \fB'd'\fR
+decimal conversion
+.IP \fB10\fR
+same as
+.B d
+.IP \fB'x'\fR
+hexadecimal conversion, including leading
+.B 0x
+.IP \fB16\fR
+hexadecimal conversion with no leading
+.B 0x
+.IP \fB17\fR
+like
+.B 16
+except padded on left with
+.BR 0 s
+to eight digits (full width of a 32-bit number)
+.RE
+.PP
+.I Ttoul
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Ultot
+returns
+.B 0
+for a failure, and otherwise
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL
+(it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred).
+.SH SEE ALSO
+atol(3), strtoul(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttoul
+are:
+empty input;
+unknown
+.IR base ;
+non-digit character found;
+number too large for an
+.BR "unsigned long" .
+.PP
+Fatal errors in
+.I ultot
+are:
+unknown
+.IR format .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+Conversion of
+.B 0
+with format
+.B o
+yields
+.BR 00 .
+.PP
+.I Ultot
+format
+.B 17
+is a bit of a kludge.
+.PP
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = ttoul( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/ttoul.c b/linux/lib/libfreeswan/ttoul.c
new file mode 100644
index 000000000..9c6193c68
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoul.c
@@ -0,0 +1,91 @@
+/*
+ * convert from text form of unsigned long to binary
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttoul.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - ttoul - convert text substring to unsigned long number
+ */
+const char * /* NULL for success, else string literal */
+ttoul(src, srclen, base, resultp)
+const char *src;
+size_t srclen; /* 0 means strlen(src) */
+int base; /* 0 means figure it out */
+unsigned long *resultp;
+{
+ const char *stop;
+ static char hex[] = "0123456789abcdef";
+ static char uchex[] = "0123456789ABCDEF";
+ int d;
+ char c;
+ char *p;
+ unsigned long r;
+ unsigned long rlimit;
+ int dlimit;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ if (base == 0) {
+ if (srclen > 2 && *src == '0' &&
+ (*(src+1) == 'x' || *(src+1) == 'X'))
+ return ttoul(src+2, srclen-2, 16, resultp);
+ if (srclen > 1 && *src == '0')
+ return ttoul(src+1, srclen-1, 8, resultp);
+ return ttoul(src, srclen, 10, resultp);
+ }
+ if (base != 8 && base != 10 && base != 16)
+ return "unsupported number base";
+
+ r = 0;
+ stop = src + srclen;
+ if (base == 16) {
+ while (src < stop) {
+ c = *src++;
+ p = strchr(hex, c);
+ if (p != NULL)
+ d = p - hex;
+ else {
+ p = strchr(uchex, c);
+ if (p == NULL)
+ return "non-hex digit in hex number";
+ d = p - uchex;
+ }
+ r = (r << 4) | d;
+ }
+ /* defer length check to catch invalid digits first */
+ if (srclen > sizeof(unsigned long) * 2)
+ return "hex number too long";
+ } else {
+ rlimit = ULONG_MAX / base;
+ dlimit = (int)(ULONG_MAX - rlimit*base);
+ while (src < stop) {
+ c = *src++;
+ d = c - '0';
+ if (d < 0 || d >= base)
+ return "non-digit in number";
+ if (r > rlimit || (r == rlimit && d > dlimit))
+ return "unsigned-long overflow";
+ r = r*base + d;
+ }
+ }
+
+ *resultp = r;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/ultoa.c b/linux/lib/libfreeswan/ultoa.c
new file mode 100644
index 000000000..2c2644826
--- /dev/null
+++ b/linux/lib/libfreeswan/ultoa.c
@@ -0,0 +1,67 @@
+/*
+ * convert unsigned long to ASCII
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ultoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - ultoa - convert unsigned long to decimal ASCII
+ */
+size_t /* length required for full conversion */
+ultoa(n, base, dst, dstlen)
+unsigned long n;
+int base;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[3*sizeof(unsigned long) + 1];
+ char *bufend = buf + sizeof(buf);
+ size_t len;
+ char *p;
+ static char hex[] = "0123456789abcdef";
+
+ p = bufend;
+ *--p = '\0';
+ if (base == 10) {
+ do {
+ *--p = n%10 + '0';
+ n /= 10;
+ } while (n != 0);
+ } else if (base == 16) {
+ do {
+ *--p = hex[n&0xf];
+ n >>= 4;
+ } while (n != 0);
+ *--p = 'x';
+ *--p = '0';
+ } else if (base == 8) {
+ do {
+ *--p = (n&07) + '0';
+ n >>= 3;
+ } while (n != 0);
+ *--p = '0';
+ } else
+ *--p = '?';
+
+ len = bufend - p;
+
+ if (dstlen > 0) {
+ if (len > dstlen)
+ *(p + dstlen - 1) = '\0';
+ strcpy(dst, p);
+ }
+ return len;
+}
diff --git a/linux/lib/libfreeswan/ultot.c b/linux/lib/libfreeswan/ultot.c
new file mode 100644
index 000000000..edffa4a2d
--- /dev/null
+++ b/linux/lib/libfreeswan/ultot.c
@@ -0,0 +1,83 @@
+/*
+ * convert unsigned long to text
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ultot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - ultot - convert unsigned long to text
+ */
+size_t /* length required for full conversion */
+ultot(n, base, dst, dstlen)
+unsigned long n;
+int base;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[3*sizeof(unsigned long) + 1];
+ char *bufend = buf + sizeof(buf);
+ size_t len;
+ char *p;
+ static char hex[] = "0123456789abcdef";
+# define HEX32 (32/4)
+
+ p = bufend;
+ *--p = '\0';
+ switch (base) {
+ case 10:
+ case 'd':
+ do {
+ *--p = n%10 + '0';
+ n /= 10;
+ } while (n != 0);
+ break;
+ case 16:
+ case 17:
+ case 'x':
+ do {
+ *--p = hex[n&0xf];
+ n >>= 4;
+ } while (n != 0);
+ if (base == 17)
+ while (bufend - p < HEX32 + 1)
+ *--p = '0';
+ if (base == 'x') {
+ *--p = 'x';
+ *--p = '0';
+ }
+ break;
+ case 8:
+ case 'o':
+ do {
+ *--p = (n&07) + '0';
+ n >>= 3;
+ } while (n != 0);
+ if (base == 'o')
+ *--p = '0';
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = bufend - p;
+ if (dstlen > 0) {
+ if (len > dstlen)
+ *(p + dstlen - 1) = '\0';
+ strcpy(dst, p);
+ }
+ return len;
+}
diff --git a/linux/lib/libfreeswan/version.3 b/linux/lib/libfreeswan/version.3
new file mode 100644
index 000000000..06c5f01e3
--- /dev/null
+++ b/linux/lib/libfreeswan/version.3
@@ -0,0 +1,44 @@
+.TH IPSEC_VERSION 3 "21 Nov 2001"
+.\" RCSID $Id: version.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ipsec_version_code \- get IPsec version code
+.br
+ipsec ipsec_version_string \- get full IPsec version string
+.br
+ipsec ipsec_copyright_notice \- get IPsec copyright notice
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *ipsec_version_code(void);"
+.br
+.B "const char *ipsec_version_string(void);"
+.br
+.B "const char **ipsec_copyright_notice(void);"
+.SH DESCRIPTION
+These functions provide information on version numbering and copyright
+of the Linux FreeS/WAN IPsec implementation.
+.PP
+.I Ipsec_version_code
+returns a pointer to a string constant
+containing the current IPsec version code,
+such as ``1.92'' or ``snap2001Nov19b''.
+.PP
+.I Ipsec_version_string
+returns a pointer to a string constant giving a full version identification,
+consisting of the version code preceded by a prefix identifying the software,
+e.g. ``Linux FreeS/WAN 1.92''.
+.PP
+.I Ipsec_copyright_notice
+returns a pointer to a vector of pointers,
+terminated by a
+.BR NULL ,
+which is the text of a suitable copyright notice.
+Each pointer points to a string constant (possibly empty) which is one line
+of the somewhat-verbose copyright notice.
+The strings are NUL-terminated and do not contain a newline;
+supplying suitable line termination for the output device is
+the caller's responsibility.
+.SH SEE ALSO
+ipsec(8)
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/version.in.c b/linux/lib/libfreeswan/version.in.c
new file mode 100644
index 000000000..b3556f721
--- /dev/null
+++ b/linux/lib/libfreeswan/version.in.c
@@ -0,0 +1,44 @@
+/*
+ * return IPsec version information
+ * Copyright (C) 2001 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library 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/lgpl.txt>.
+ *
+ * This library 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 Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: version.in.c,v 1.2 2004/03/16 12:26:32 as Exp $
+ */
+
+#ifdef __KERNEL__
+#include <linux/netdevice.h>
+#endif
+
+#include "freeswan.h"
+
+#define V "xxx" /* substituted in by Makefile */
+static const char strongswan_number[] = V;
+static const char strongswan_string[] = "Linux strongSwan " V;
+
+/*
+ - ipsec_version_code - return IPsec version number/code, as string
+ */
+const char *
+ipsec_version_code()
+{
+ return strongswan_number;
+}
+
+/*
+ - ipsec_version_string - return full version string
+ */
+const char *
+ipsec_version_string()
+{
+ return strongswan_string;
+}
diff --git a/linux/lib/zlib/Makefile b/linux/lib/zlib/Makefile
new file mode 100644
index 000000000..36cbea81f
--- /dev/null
+++ b/linux/lib/zlib/Makefile
@@ -0,0 +1,121 @@
+# (kernel) Makefile for IPCOMP zlib deflate code
+# Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
+# Copyright (C) 2000 Svenning Soerensen
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:26 as Exp $
+#
+
+
+
+include ../Makefile.inc
+
+
+
+ifndef TOPDIR
+TOPDIR := /usr/src/linux
+endif
+
+
+L_TARGET := zlib.a
+
+obj-y :=
+
+include Makefile.objs
+
+EXTRA_CFLAGS += $(KLIPSCOMPILE)
+
+EXTRA_CFLAGS += -Wall
+#EXTRA_CFLAGS += -Wconversion
+#EXTRA_CFLAGS += -Wmissing-prototypes
+EXTRA_CFLAGS += -Wpointer-arith
+#EXTRA_CFLAGS += -Wcast-qual
+#EXTRA_CFLAGS += -Wmissing-declarations
+EXTRA_CFLAGS += -Wstrict-prototypes
+#EXTRA_CFLAGS += -pedantic
+#EXTRA_CFLAGS += -W
+#EXTRA_CFLAGS += -Wwrite-strings
+EXTRA_CFLAGS += -Wbad-function-cast
+EXTRA_CFLAGS += -DIPCOMP_PREFIX
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ -DNO_UNDERLINE -traditional -c $< -o $*.o
+
+asm-obj-$(CONFIG_M586) += match586.o
+asm-obj-$(CONFIG_M586TSC) += match586.o
+asm-obj-$(CONFIG_M586MMX) += match586.o
+asm-obj-$(CONFIG_M686) += match686.o
+asm-obj-$(CONFIG_MPENTIUMIII) += match686.o
+asm-obj-$(CONFIG_MPENTIUM4) += match686.o
+asm-obj-$(CONFIG_MK6) += match586.o
+asm-obj-$(CONFIG_MK7) += match686.o
+asm-obj-$(CONFIG_MCRUSOE) += match586.o
+asm-obj-$(CONFIG_MWINCHIPC6) += match586.o
+asm-obj-$(CONFIG_MWINCHIP2) += match686.o
+asm-obj-$(CONFIG_MWINCHIP3D) += match686.o
+
+obj-y += $(asm-obj-y)
+ifneq ($(strip $(asm-obj-y)),)
+ EXTRA_CFLAGS += -DASMV
+endif
+
+active-objs := $(sort $(obj-y) $(obj-m))
+L_OBJS := $(obj-y)
+M_OBJS := $(obj-m)
+MIX_OBJS := $(filter $(export-objs), $(active-objs))
+
+include $(TOPDIR)/Rules.make
+
+$(obj-y) : $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
+
+
+clean:
+ -rm -f *.o *.a
+
+checkprograms:
+programs: $(L_TARGET)
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:26 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.9 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+# Revision 1.8 2002/04/24 07:36:44 mcr
+# Moved from ./zlib/Makefile,v
+#
+# Revision 1.7 2002/03/27 23:34:35 mcr
+# added programs: target
+#
+# Revision 1.6 2001/12/05 20:19:08 henry
+# use new compile-control variable
+#
+# Revision 1.5 2001/11/27 16:38:08 mcr
+# added new "checkprograms" target to deal with programs that
+# are required for "make check", but that may not be ready to
+# build for every user due to external dependancies.
+#
+# Revision 1.4 2001/10/24 14:46:24 henry
+# Makefile.inc
+#
+# Revision 1.3 2001/04/21 23:05:24 rgb
+# Update asm directives for 2.4 style makefiles.
+#
+# Revision 1.2 2001/01/29 22:22:00 rgb
+# Convert to 2.4 new style with back compat.
+#
+# Revision 1.1.1.1 2000/09/29 18:51:33 rgb
+# zlib_beginnings
+#
+#
diff --git a/linux/lib/zlib/Makefile.objs b/linux/lib/zlib/Makefile.objs
new file mode 100644
index 000000000..94ed12fc9
--- /dev/null
+++ b/linux/lib/zlib/Makefile.objs
@@ -0,0 +1,27 @@
+obj-$(CONFIG_IPSEC_IPCOMP) += adler32.o
+obj-$(CONFIG_IPSEC_IPCOMP) += deflate.o
+obj-$(CONFIG_IPSEC_IPCOMP) += infblock.o
+obj-$(CONFIG_IPSEC_IPCOMP) += infcodes.o
+obj-$(CONFIG_IPSEC_IPCOMP) += inffast.o
+obj-$(CONFIG_IPSEC_IPCOMP) += inflate.o
+obj-$(CONFIG_IPSEC_IPCOMP) += inftrees.o
+obj-$(CONFIG_IPSEC_IPCOMP) += infutil.o
+obj-$(CONFIG_IPSEC_IPCOMP) += trees.o
+obj-$(CONFIG_IPSEC_IPCOMP) += zutil.o
+
+asm-obj-$(CONFIG_M586) += ${LIBZLIBSRCDIR}/match586.o
+asm-obj-$(CONFIG_M586TSC) += ${LIBZLIBSRCDIR}/match586.o
+asm-obj-$(CONFIG_M586MMX) += ${LIBZLIBSRCDIR}/match586.o
+asm-obj-$(CONFIG_M686) += ${LIBZLIBSRCDIR}/match686.o
+asm-obj-$(CONFIG_MPENTIUMIII) += ${LIBZLIBSRCDIR}/match686.o
+asm-obj-$(CONFIG_MPENTIUM4) += ${LIBZLIBSRCDIR}/match686.o
+asm-obj-$(CONFIG_MK6) += ${LIBZLIBSRCDIR}/match586.o
+asm-obj-$(CONFIG_MK7) += ${LIBZLIBSRCDIR}/match686.o
+asm-obj-$(CONFIG_MCRUSOE) += ${LIBZLIBSRCDIR}/match586.o
+asm-obj-$(CONFIG_MWINCHIPC6) += ${LIBZLIBSRCDIR}/match586.o
+asm-obj-$(CONFIG_MWINCHIP2) += ${LIBZLIBSRCDIR}/match686.o
+asm-obj-$(CONFIG_MWINCHIP3D) += ${LIBZLIBSRCDIR}/match686.o
+
+EXTRA_CFLAGS += -DIPCOMP_PREFIX
+
+
diff --git a/linux/lib/zlib/README b/linux/lib/zlib/README
new file mode 100644
index 000000000..29d67146a
--- /dev/null
+++ b/linux/lib/zlib/README
@@ -0,0 +1,147 @@
+zlib 1.1.4 is a general purpose data compression library. All the code
+is thread safe. The data format used by the zlib library
+is described by RFCs (Request for Comments) 1950 to 1952 in the files
+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
+format) and rfc1952.txt (gzip format). These documents are also available in
+other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact jloup@gzip.org). A usage
+example of the library is given in the file example.c which also tests that
+the library is working correctly. Another example is given in the file
+minigzip.c. The compression library itself is composed of all source files
+except example.c and minigzip.c.
+
+To compile all files and run the test program, follow the instructions
+given at the top of Makefile. In short "make test; make install"
+should work for most machines. For Unix: "./configure; make test; make install"
+For MSDOS, use one of the special makefiles such as Makefile.msc.
+For VMS, use Make_vms.com or descrip.mms.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to
+Gilles Vollant <info@winimage.com> for the Windows DLL version.
+The zlib home page is http://www.zlib.org or http://www.gzip.org/zlib/
+Before reporting a problem, please check this site to verify that
+you have the latest version of zlib; otherwise get the latest version and
+check whether the problem still exists or not.
+
+PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html
+before asking for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
+issue of Dr. Dobb's Journal; a copy of the article is available in
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.1.4 are documented in the file ChangeLog.
+The only changes made since 1.1.3 are bug corrections:
+
+- ZFREE was repeated on same allocation on some error conditions.
+ This creates a security problem described in
+ http://www.zlib.org/advisory-2002-03-11.txt
+- Returned incorrect error (Z_MEM_ERROR) on some invalid data
+- Avoid accesses before window for invalid distances with inflate window
+ less than 32K.
+- force windowBits > 8 to avoid a bug in the encoder for a window size
+ of 256 bytes. (A complete fix will be available in 1.1.5).
+
+The beta version 1.1.5beta includes many more changes. A new official
+version 1.1.5 will be released as soon as extensive testing has been
+completed on it.
+
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+See the zlib home page http://www.zlib.org for details.
+
+A Perl interface to zlib written by Paul Marquess <pmarquess@bfsec.bt.co.uk>
+is in the CPAN (Comprehensive Perl Archive Network) sites
+http://www.cpan.org/modules/by-module/Compress/
+
+A Python interface to zlib written by A.M. Kuchling <amk@magnet.com>
+is available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com>
+is availlable at http://www.westend.com/~kupries/doc/trf/man/man.html
+
+An experimental package to read and write files in .zip format,
+written on top of zlib by Gilles Vollant <info@winimage.com>, is
+available at http://www.winimage.com/zLibDll/unzip.html
+and also in the contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- To build a Windows DLL version, include in a DLL project zlib.def, zlib.rc
+ and all .c files except example.c and minigzip.c; compile with -DZLIB_DLL
+ The zlib DLL support was initially done by Alessandro Iacopetti and is
+ now maintained by Gilles Vollant <info@winimage.com>. Check the zlib DLL
+ home page at http://www.winimage.com/zLibDll
+
+ From Visual Basic, you can call the DLL functions which do not take
+ a structure as argument: compress, uncompress and all gz* functions.
+ See contrib/visual-basic.txt for more information, or get
+ http://www.tcfb.com/dowseware/cmp-z-it.zip
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization.
+ With -O, one libpng test fails. The test works in 32 bit mode (with
+ the -n32 compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1
+ it works when compiled with cc.
+
+- on Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1
+ is necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works
+ with other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For Turbo C the small model is supported only with reduced performance to
+ avoid any far allocation; it was tested with -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+
+- For PalmOs, see http://www.cs.uit.no/~perm/PASTA/pilot/software.html
+ Per Harald Myrvang <perm@stud.cs.uit.no>
+
+
+Acknowledgments:
+
+ The deflate format used by zlib was defined by Phil Katz. The deflate
+ and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+ people who reported problems and suggested various improvements in zlib;
+ they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2002 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind. The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes.
diff --git a/linux/lib/zlib/README.freeswan b/linux/lib/zlib/README.freeswan
new file mode 100644
index 000000000..f34b5cfff
--- /dev/null
+++ b/linux/lib/zlib/README.freeswan
@@ -0,0 +1,13 @@
+The only changes made to these files for use in FreeS/WAN are:
+
+ - In zconf.h, macros are defined to prefix global symbols with "ipcomp_"
+ (or "_ipcomp"), when compiled with -DIPCOMP_PREFIX.
+ - The copyright strings are defined local (static)
+
+ The above changes are made to avoid name collisions with ppp_deflate
+ and ext2compr.
+
+ - Files not needed for FreeS/WAN have been removed
+
+ See the "README" file for information about where to obtain the complete
+ zlib package.
diff --git a/linux/lib/zlib/adler32.c b/linux/lib/zlib/adler32.c
new file mode 100644
index 000000000..a383ec643
--- /dev/null
+++ b/linux/lib/zlib/adler32.c
@@ -0,0 +1,49 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: adler32.c,v 1.1 2004/03/15 20:35:26 as Exp $ */
+
+#include <zlib/zlib.h>
+#include "zconf.h"
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
diff --git a/linux/lib/zlib/deflate.c b/linux/lib/zlib/deflate.c
new file mode 100644
index 000000000..7eb133a1a
--- /dev/null
+++ b/linux/lib/zlib/deflate.c
@@ -0,0 +1,1351 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id: deflate.c,v 1.1 2004/03/15 20:35:26 as Exp $ */
+
+#include "deflate.h"
+
+local const char deflate_copyright[] =
+ " deflate 1.1.4 Copyright 1995-2002 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+local block_state deflate_slow OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int noheader = 0;
+ static const char* my_version = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == Z_NULL) {
+ return Z_STREAM_ERROR;
+/* strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;*/
+ }
+ if (strm->zfree == Z_NULL) return Z_STREAM_ERROR; /* strm->zfree = zcfree; */
+
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#ifdef FASTEST
+ level = 1;
+#endif
+
+ if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+ noheader = 1;
+ windowBits = -windowBits;
+ }
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->noheader = noheader;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ strm->msg = ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->status != INIT_STATE) return Z_STREAM_ERROR;
+
+ s = strm->state;
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->noheader < 0) {
+ s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+ }
+ s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+ strm->adler = 1;
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+ if (level == Z_DEFAULT_COMPRESSION) {
+ level = 6;
+ }
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the zlib header */
+ if (s->status == INIT_STATE) {
+
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags = (s->level-1) >> 1;
+
+ if (level_flags > 3) level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = 1L;
+ }
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->noheader) return Z_STREAM_END;
+
+ /* Write the zlib trailer (adler32) */
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ s->noheader = -1; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE && status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ *dest = *source;
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ *ds = *ss;
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (!strm->state->noheader) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+#ifndef FASTEST
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+
+#else /* FASTEST */
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 only
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return len <= s->lookahead ? len : s->lookahead;
+}
+#endif /* FASTEST */
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in hash table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+ (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR))) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
diff --git a/linux/lib/zlib/deflate.h b/linux/lib/zlib/deflate.h
new file mode 100644
index 000000000..2e39b413b
--- /dev/null
+++ b/linux/lib/zlib/deflate.h
@@ -0,0 +1,318 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2002 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: deflate.h,v 1.1 2004/03/15 20:35:26 as Exp $ */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+#include "zlib/zutil.h"
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ int pending; /* nb of bytes in the pending buffer */
+ int noheader; /* suppress zlib header and adler32 */
+ Byte data_type; /* UNKNOWN, BINARY or ASCII */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* _DEFLATE_H */
diff --git a/linux/lib/zlib/infblock.c b/linux/lib/zlib/infblock.c
new file mode 100644
index 000000000..c316ce0c9
--- /dev/null
+++ b/linux/lib/zlib/infblock.c
@@ -0,0 +1,403 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <zlib/zutil.h>
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+ if (c != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens);
+ if (s->mode == CODES)
+ inflate_codes_free(s->sub.decode.codes, z);
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+ Tracev((stderr, "inflate: blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->hufts =
+ (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
+ {
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Tracev((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, Z_NULL);
+ return s;
+}
+
+
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Tracev((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BAD;
+ z->msg = (char*)"invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+ {
+ s->mode = BAD;
+ z->msg = (char*)"invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BAD;
+ z->msg = (char*)"too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, s->hufts, z);
+ if (t != Z_OK)
+ {
+ r = t;
+ if (r == Z_DATA_ERROR)
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ }
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->bits;
+ c = h->base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ z->msg = (char*)"invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td,
+ s->hufts, z);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ }
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok\n"));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.codes = c;
+ }
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONE;
+ case DONE:
+ r = Z_STREAM_END;
+ LEAVE
+ case BAD:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+int inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_blocks_reset(s, z, Z_NULL);
+ ZFREE(z, s->window);
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ Tracev((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt n;
+{
+ zmemcpy(s->window, d, n);
+ s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH.
+ * IN assertion: s != Z_NULL
+ */
+int inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+ return s->mode == LENS;
+}
diff --git a/linux/lib/zlib/infblock.h b/linux/lib/zlib/infblock.h
new file mode 100644
index 000000000..173b2267a
--- /dev/null
+++ b/linux/lib/zlib/infblock.h
@@ -0,0 +1,39 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+ z_streamp z,
+ check_func c, /* check function */
+ uInt w)); /* window size */
+
+extern int inflate_blocks OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int)); /* initial return code */
+
+extern void inflate_blocks_reset OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ uLongf *)); /* check value on output */
+
+extern int inflate_blocks_free OF((
+ inflate_blocks_statef *,
+ z_streamp));
+
+extern void inflate_set_dictionary OF((
+ inflate_blocks_statef *s,
+ const Bytef *d, /* dictionary */
+ uInt n)); /* dictionary length */
+
+extern int inflate_blocks_sync_point OF((
+ inflate_blocks_statef *s));
diff --git a/linux/lib/zlib/infcodes.c b/linux/lib/zlib/infcodes.c
new file mode 100644
index 000000000..f56eae4d7
--- /dev/null
+++ b/linux/lib/zlib/infcodes.c
@@ -0,0 +1,251 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <zlib/zutil.h>
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+inflate_codes_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ inflate_codes_mode mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+ f = q - c->sub.copy.dist;
+ while (f < s->window) /* modulo window size-"while" instead */
+ f += s->end - s->window; /* of "if" handles invalid distances */
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+ ZFREE(z, c);
+ Tracev((stderr, "inflate: codes free\n"));
+}
diff --git a/linux/lib/zlib/infcodes.h b/linux/lib/zlib/infcodes.h
new file mode 100644
index 000000000..27e4a40db
--- /dev/null
+++ b/linux/lib/zlib/infcodes.h
@@ -0,0 +1,31 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFCODES_H
+#define _INFCODES_H
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+ uInt, uInt,
+ inflate_huft *, inflate_huft *,
+ z_streamp ));
+
+extern int inflate_codes OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+extern void inflate_codes_free OF((
+ inflate_codes_statef *,
+ z_streamp ));
+
+#endif /* _INFCODES_H */
diff --git a/linux/lib/zlib/inffast.c b/linux/lib/zlib/inffast.c
new file mode 100644
index 000000000..2a363c5ae
--- /dev/null
+++ b/linux/lib/zlib/inffast.c
@@ -0,0 +1,183 @@
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <zlib/zutil.h>
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ uInt ml; /* mask for literal/length tree */
+ uInt md; /* mask for distance tree */
+ uInt c; /* bytes to copy */
+ uInt d; /* distance back to copy from */
+ Bytef *r; /* copy source pointer */
+
+ /* load input, output, bit values */
+ LOAD
+
+ /* initialize masks */
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ /* do until not enough input or output space for fast loop */
+ do { /* assume called with m >= 258 && n >= 10 */
+ /* get literal/length code */
+ GRABBITS(20) /* max bits for literal/length code */
+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ continue;
+ }
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits for length */
+ e &= 15;
+ c = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * length %u\n", c));
+
+ /* decode distance base of block to copy */
+ GRABBITS(15); /* max bits for distance code */
+ e = (t = td + ((uInt)b & md))->exop;
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits to add to distance base */
+ e &= 15;
+ GRABBITS(e) /* get extra bits (up to 13) */
+ d = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * distance %u\n", d));
+
+ /* do the copy */
+ m -= c;
+ r = q - d;
+ if (r < s->window) /* wrap if needed */
+ {
+ do {
+ r += s->end - s->window; /* force pointer in window */
+ } while (r < s->window); /* covers invalid distances */
+ e = s->end - r;
+ if (c > e)
+ {
+ c -= e; /* wrapped copy */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ else /* normal copy */
+ {
+ *q++ = *r++; c--;
+ *q++ = *r++; c--;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ }
+ else /* normal copy */
+ {
+ *q++ = *r++; c--;
+ *q++ = *r++; c--;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ break;
+ }
+ else if ((e & 64) == 0)
+ {
+ t += t->base;
+ e = (t += ((uInt)b & inflate_mask[e]))->exop;
+ }
+ else
+ {
+ z->msg = (char*)"invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ t += t->base;
+ if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ Tracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ z->msg = (char*)"invalid literal/length code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ } while (m >= 258 && n >= 10);
+
+ /* not enough input or output--restore pointers and return */
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
diff --git a/linux/lib/zlib/inffast.h b/linux/lib/zlib/inffast.h
new file mode 100644
index 000000000..652a0e849
--- /dev/null
+++ b/linux/lib/zlib/inffast.h
@@ -0,0 +1,22 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFFAST_H
+#define _INFFAST_H
+
+extern int inflate_fast OF((
+ uInt,
+ uInt,
+ inflate_huft *,
+ inflate_huft *,
+ inflate_blocks_statef *,
+ z_streamp ));
+
+#endif /* _INFFAST_H */
diff --git a/linux/lib/zlib/inffixed.h b/linux/lib/zlib/inffixed.h
new file mode 100644
index 000000000..77f7e7631
--- /dev/null
+++ b/linux/lib/zlib/inffixed.h
@@ -0,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+ };
+local inflate_huft fixed_td[] = {
+ {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+ {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+ {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+ {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+ {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+ {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+ {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+ {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+ };
diff --git a/linux/lib/zlib/inflate.c b/linux/lib/zlib/inflate.c
new file mode 100644
index 000000000..3266babb4
--- /dev/null
+++ b/linux/lib/zlib/inflate.c
@@ -0,0 +1,368 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <zlib/zutil.h>
+#include "infblock.h"
+
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+
+typedef enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ DICT4, /* four dictionary check bytes to go */
+ DICT3, /* three dictionary check bytes to go */
+ DICT2, /* two dictionary check bytes to go */
+ DICT1, /* one dictionary check byte to go */
+ DICT0, /* waiting for inflateSetDictionary */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+inflate_mode;
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ inflate_mode mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int ZEXPORT inflateReset(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateEnd(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z);
+ ZFREE(z, z->state);
+ z->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != sizeof(z_stream))
+ return Z_VERSION_ERROR;
+
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->msg = Z_NULL;
+ if (z->zalloc == Z_NULL)
+ {
+ return Z_STREAM_ERROR;
+/* z->zalloc = zcalloc;
+ z->opaque = (voidpf)0;
+*/
+ }
+ if (z->zfree == Z_NULL) return Z_STREAM_ERROR; /* z->zfree = zcfree; */
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Tracev((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT inflate(z, f)
+z_streamp z;
+int f;
+{
+ int r;
+ uInt b;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+ return Z_STREAM_ERROR;
+ f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ b = NEXTBYTE;
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ if (!(b & PRESET_DICT))
+ {
+ z->state->mode = BLOCKS;
+ break;
+ }
+ z->state->mode = DICT4;
+ case DICT4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = DICT3;
+ case DICT3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = DICT2;
+ case DICT2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = DICT1;
+ case DICT1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+ z->adler = z->state->sub.check.need;
+ z->state->mode = DICT0;
+ return Z_NEED_DICT;
+ case DICT0:
+ z->state->mode = BAD;
+ z->msg = (char*)"need dictionary";
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_STREAM_ERROR;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r == Z_OK)
+ r = f;
+ if (r != Z_STREAM_END)
+ return r;
+ r = f;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
+
+int ZEXPORT inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ uInt length = dictLength;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+ return Z_STREAM_ERROR;
+
+ if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+ z->adler = 1L;
+
+ if (length >= ((uInt)1<<z->state->wbits))
+ {
+ length = (1<<z->state->wbits)-1;
+ dictionary += dictLength - length;
+ }
+ inflate_set_dictionary(z->state->blocks, dictionary, length);
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateSync(z)
+z_streamp z;
+{
+ uInt n; /* number of bytes to look at */
+ Bytef *p; /* pointer to bytes */
+ uInt m; /* number of marker bytes found in a row */
+ uLong r, w; /* temporaries to save total_in and total_out */
+
+ /* set up */
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->mode != BAD)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0;
+ }
+ if ((n = z->avail_in) == 0)
+ return Z_BUF_ERROR;
+ p = z->next_in;
+ m = z->state->sub.marker;
+
+ /* search */
+ while (n && m < 4)
+ {
+ static const Byte mark[4] = {0, 0, 0xff, 0xff};
+ if (*p == mark[m])
+ m++;
+ else if (*p)
+ m = 0;
+ else
+ m = 4 - m;
+ p++, n--;
+ }
+
+ /* restore */
+ z->total_in += p - z->next_in;
+ z->next_in = p;
+ z->avail_in = n;
+ z->state->sub.marker = m;
+
+ /* return no joy or set up to restart on a new block */
+ if (m != 4)
+ return Z_DATA_ERROR;
+ r = z->total_in; w = z->total_out;
+ inflateReset(z);
+ z->total_in = r; z->total_out = w;
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ * but removes the length bytes of the resulting empty stored block. When
+ * decompressing, PPP checks that at the end of input packet, inflate is
+ * waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+ return Z_STREAM_ERROR;
+ return inflate_blocks_sync_point(z->state->blocks);
+}
diff --git a/linux/lib/zlib/inftrees.c b/linux/lib/zlib/inftrees.c
new file mode 100644
index 000000000..59ffb020c
--- /dev/null
+++ b/linux/lib/zlib/inftrees.c
@@ -0,0 +1,454 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <zlib/zutil.h>
+#include "inftrees.h"
+
+#if !defined(BUILDFIXED) && !defined(STDC)
+# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */
+#endif
+
+local const char inflate_copyright[] =
+ " inflate 1.1.4 Copyright 1995-2002 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ const uIntf *, /* list of base values for non-simple codes */
+ const uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ inflate_huft *, /* space for trees */
+ uInt *, /* hufts used in space */
+ uIntf * )); /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= 288) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+const uIntf *d; /* list of base values for non-simple codes */
+const uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+inflate_huft *hp; /* space for trees */
+uInt *hn; /* hufts used in space */
+uIntf *v; /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), or Z_DATA_ERROR if the input is invalid. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+ n = x[g]; /* set n to length of v */
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = g - w;
+ z = z > (uInt)l ? l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate new table */
+ if (*hn + z > MANY) /* (note: doesn't matter for fixed) */
+ return Z_DATA_ERROR; /* overflow of MANY */
+ u[h] = q = hp + *hn;
+ *hn += z;
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ j = i >> (w - l);
+ r.base = (uInt)(q - u[h-1] - j); /* offset to this table */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ else
+ *t = q; /* first table is returned result */
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ mask = (1 << w) - 1; /* needed on HP, cc -O bug */
+ while ((i & mask) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ mask = (1 << w) - 1;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+ tb, bb, hp, &hn, v);
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR || *bb == 0)
+ {
+ z->msg = (char*)"incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate work area */
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+
+ /* build literal/length tree */
+ r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+ if (r != Z_OK || *bl == 0)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed literal/length tree";
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+ }
+
+ /* build distance tree */
+ r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+ if (r != Z_OK || (*bd == 0 && nl > 257))
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed distance tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ z->msg = (char*)"incomplete distance tree";
+ r = Z_DATA_ERROR;
+ }
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"empty distance tree with lengths";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+#endif
+ }
+
+ /* done */
+ ZFREE(z, v);
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#ifdef BUILDFIXED
+local int fixed_built = 0;
+#define FIXEDH 544 /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+#else
+#include "inffixed.h"
+#endif
+
+
+int inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_streamp z; /* for memory allocation */
+{
+#ifdef BUILDFIXED
+ /* build fixed tables if not already */
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ uInt f = 0; /* number of hufts used in fixed_mem */
+ uIntf *c; /* length list for huft_build */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate memory */
+ if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ {
+ ZFREE(z, c);
+ return Z_MEM_ERROR;
+ }
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 9;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
+ fixed_mem, &f, v);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
+ fixed_mem, &f, v);
+
+ /* done */
+ ZFREE(z, v);
+ ZFREE(z, c);
+ fixed_built = 1;
+ }
+#endif
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
diff --git a/linux/lib/zlib/inftrees.h b/linux/lib/zlib/inftrees.h
new file mode 100644
index 000000000..ef15b1b82
--- /dev/null
+++ b/linux/lib/zlib/inftrees.h
@@ -0,0 +1,63 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+#ifndef _INFTREES_H
+#define _INFTREES_H
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ uInt pad; /* pad structure to a power of 2 (4 bytes for */
+ } word; /* 16-bit, 8 bytes for 32-bit int's) */
+ uInt base; /* literal, length base, distance base,
+ or table offset */
+};
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1004 huft structures (850 for length/literals
+ and 154 for distances, the latter actually the result of an
+ exhaustive search). The actual maximum is not known, but the
+ value below is more than safe. */
+#define MANY 1440
+
+extern int inflate_trees_bits OF((
+ uIntf *, /* 19 code lengths */
+ uIntf *, /* bits tree desired/actual depth */
+ inflate_huft * FAR *, /* bits tree result */
+ inflate_huft *, /* space for trees */
+ z_streamp)); /* for messages */
+
+extern int inflate_trees_dynamic OF((
+ uInt, /* number of literal/length codes */
+ uInt, /* number of distance codes */
+ uIntf *, /* that many (total) code lengths */
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ inflate_huft *, /* space for trees */
+ z_streamp)); /* for messages */
+
+extern int inflate_trees_fixed OF((
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ z_streamp)); /* for memory allocation */
+
+#endif /* _INFTREES_H */
diff --git a/linux/lib/zlib/infutil.c b/linux/lib/zlib/infutil.c
new file mode 100644
index 000000000..b50358ffa
--- /dev/null
+++ b/linux/lib/zlib/infutil.c
@@ -0,0 +1,87 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <zlib/zutil.h>
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt n;
+ Bytef *p;
+ Bytef *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
diff --git a/linux/lib/zlib/infutil.h b/linux/lib/zlib/infutil.h
new file mode 100644
index 000000000..959e12e8c
--- /dev/null
+++ b/linux/lib/zlib/infutil.h
@@ -0,0 +1,98 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONE, /* finished last block, done */
+ BAD} /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+ /* mode */
+ inflate_block_mode mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf *blens; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_codes_statef
+ *codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+ uInt last; /* true if this block is the last block */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ inflate_huft *hufts; /* single malloc for tree space */
+ Bytef *window; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ check_func checkfn; /* check function */
+ uLong check; /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/* update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/* get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/* output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/* load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#endif /* _INFUTIL_H */
diff --git a/linux/lib/zlib/match586.S b/linux/lib/zlib/match586.S
new file mode 100644
index 000000000..9ca33b03a
--- /dev/null
+++ b/linux/lib/zlib/match586.S
@@ -0,0 +1,357 @@
+/* match.s -- Pentium-optimized version of longest_match()
+ * Written for zlib 1.1.2
+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License.
+ */
+
+#ifndef NO_UNDERLINE
+#define match_init _ipcomp_match_init
+#define longest_match _ipcomp_longest_match
+#else
+#define match_init ipcomp_match_init
+#define longest_match ipcomp_longest_match
+#endif
+
+#define MAX_MATCH (258)
+#define MIN_MATCH (3)
+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+
+#define wmask 0 /* local copy of s->wmask */
+#define window 4 /* local copy of s->window */
+#define windowbestlen 8 /* s->window + bestlen */
+#define chainlenscanend 12 /* high word: current chain len */
+ /* low word: last bytes sought */
+#define scanstart 16 /* first two bytes of string */
+#define scanalign 20 /* dword-misalignment of string */
+#define nicematch 24 /* a good enough match size */
+#define bestlen 28 /* size of best match so far */
+#define scan 32 /* ptr to string wanting match */
+
+#define LocalVarsSize (36)
+/* saved ebx 36 */
+/* saved edi 40 */
+/* saved esi 44 */
+/* saved ebp 48 */
+/* return address 52 */
+#define deflatestate 56 /* the function arguments */
+#define curmatch 60
+
+/* Offsets for fields in the deflate_state structure. These numbers
+ * are calculated from the definition of deflate_state, with the
+ * assumption that the compiler will dword-align the fields. (Thus,
+ * changing the definition of deflate_state could easily cause this
+ * program to crash horribly, without so much as a warning at
+ * compile time. Sigh.)
+ */
+#define dsWSize 36
+#define dsWMask 44
+#define dsWindow 48
+#define dsPrev 56
+#define dsMatchLen 88
+#define dsPrevMatch 92
+#define dsStrStart 100
+#define dsMatchStart 104
+#define dsLookahead 108
+#define dsPrevLen 112
+#define dsMaxChainLen 116
+#define dsGoodMatch 132
+#define dsNiceMatch 136
+
+
+.file "match.S"
+
+.globl match_init, longest_match
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+
+longest_match:
+
+/* Save registers that the compiler may be using, and adjust %esp to */
+/* make room for our stack frame. */
+
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ subl $LocalVarsSize, %esp
+
+/* Retrieve the function arguments. %ecx will hold cur_match */
+/* throughout the entire function. %edx will hold the pointer to the */
+/* deflate_state structure during the function's setup (before */
+/* entering the main loop). */
+
+ movl deflatestate(%esp), %edx
+ movl curmatch(%esp), %ecx
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
+
+ movl dsNiceMatch(%edx), %eax
+ movl dsLookahead(%edx), %ebx
+ cmpl %eax, %ebx
+ jl LookaheadLess
+ movl %eax, %ebx
+LookaheadLess: movl %ebx, nicematch(%esp)
+
+/* register Bytef *scan = s->window + s->strstart; */
+
+ movl dsWindow(%edx), %esi
+ movl %esi, window(%esp)
+ movl dsStrStart(%edx), %ebp
+ lea (%esi,%ebp), %edi
+ movl %edi, scan(%esp)
+
+/* Determine how many bytes the scan ptr is off from being */
+/* dword-aligned. */
+
+ movl %edi, %eax
+ negl %eax
+ andl $3, %eax
+ movl %eax, scanalign(%esp)
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
+
+ movl dsWSize(%edx), %eax
+ subl $MIN_LOOKAHEAD, %eax
+ subl %eax, %ebp
+ jg LimitPositive
+ xorl %ebp, %ebp
+LimitPositive:
+
+/* unsigned chain_length = s->max_chain_length; */
+/* if (s->prev_length >= s->good_match) { */
+/* chain_length >>= 2; */
+/* } */
+
+ movl dsPrevLen(%edx), %eax
+ movl dsGoodMatch(%edx), %ebx
+ cmpl %ebx, %eax
+ movl dsMaxChainLen(%edx), %ebx
+ jl LastMatchGood
+ shrl $2, %ebx
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can */
+/* use the sign flag instead of the zero flag for the exit test. */
+/* It is then shifted into the high word, to make room for the scanend */
+/* scanend value, which it will always accompany. */
+
+ decl %ebx
+ shll $16, %ebx
+
+/* int best_len = s->prev_length; */
+
+ movl dsPrevLen(%edx), %eax
+ movl %eax, bestlen(%esp)
+
+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+
+/* register ush scan_start = *(ushf*)scan; */
+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
+
+ movw (%edi), %bx
+ movw %bx, scanstart(%esp)
+ movw -1(%edi,%eax), %bx
+ movl %ebx, chainlenscanend(%esp)
+
+/* Posf *prev = s->prev; */
+/* uInt wmask = s->w_mask; */
+
+ movl dsPrev(%edx), %edi
+ movl dsWMask(%edx), %edx
+ mov %edx, wmask(%esp)
+
+/* Jump into the main loop. */
+
+ jmp LoopEntry
+
+.balign 16
+
+/* do {
+ * match = s->window + cur_match;
+ * if (*(ushf*)(match+best_len-1) != scan_end ||
+ * *(ushf*)match != scan_start) continue;
+ * [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ * && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ *
+ * Within this loop:
+ * %ebx = chainlenscanend - i.e., ((chainlen << 16) | scanend)
+ * %ecx = curmatch
+ * %edx = curmatch & wmask
+ * %esi = windowbestlen - i.e., (window + bestlen)
+ * %edi = prev
+ * %ebp = limit
+ *
+ * Two optimization notes on the choice of instructions:
+ *
+ * The first instruction uses a 16-bit address, which costs an extra,
+ * unpairable cycle. This is cheaper than doing a 32-bit access and
+ * zeroing the high word, due to the 3-cycle misalignment penalty which
+ * would occur half the time. This also turns out to be cheaper than
+ * doing two separate 8-bit accesses, as the memory is so rarely in the
+ * L1 cache.
+ *
+ * The window buffer, however, apparently spends a lot of time in the
+ * cache, and so it is faster to retrieve the word at the end of the
+ * match string with two 8-bit loads. The instructions that test the
+ * word at the beginning of the match string, however, are executed
+ * much less frequently, and there it was cheaper to use 16-bit
+ * instructions, which avoided the necessity of saving off and
+ * subsequently reloading one of the other registers.
+ */
+LookupLoop:
+ /* 1 U & V */
+ movw (%edi,%edx,2), %cx /* 2 U pipe */
+ movl wmask(%esp), %edx /* 2 V pipe */
+ cmpl %ebp, %ecx /* 3 U pipe */
+ jbe LeaveNow /* 3 V pipe */
+ subl $0x00010000, %ebx /* 4 U pipe */
+ js LeaveNow /* 4 V pipe */
+LoopEntry: movb -1(%esi,%ecx), %al /* 5 U pipe */
+ andl %ecx, %edx /* 5 V pipe */
+ cmpb %bl, %al /* 6 U pipe */
+ jnz LookupLoop /* 6 V pipe */
+ movb (%esi,%ecx), %ah
+ cmpb %bh, %ah
+ jnz LookupLoop
+ movl window(%esp), %eax
+ movw (%eax,%ecx), %ax
+ cmpw scanstart(%esp), %ax
+ jnz LookupLoop
+
+/* Store the current value of chainlen. */
+
+ movl %ebx, chainlenscanend(%esp)
+
+/* Point %edi to the string under scrutiny, and %esi to the string we */
+/* are hoping to match it up with. In actuality, %esi and %edi are */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
+/* initialized to -(MAX_MATCH_8 - scanalign). */
+
+ movl window(%esp), %esi
+ movl scan(%esp), %edi
+ addl %ecx, %esi
+ movl scanalign(%esp), %eax
+ movl $(-MAX_MATCH_8), %edx
+ lea MAX_MATCH_8(%edi,%eax), %edi
+ lea MAX_MATCH_8(%esi,%eax), %esi
+
+/* Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %edx so that it is offset to the exact byte that mismatched.
+ *
+ * We already know at this point that the first three bytes of the
+ * strings match each other, and they can be safely passed over before
+ * starting the compare loop. So what this code does is skip over 0-3
+ * bytes, as much as necessary in order to dword-align the %edi
+ * pointer. (%esi will still be misaligned three times out of four.)
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance.
+ */
+LoopCmps:
+ movl (%esi,%edx), %eax
+ movl (%edi,%edx), %ebx
+ xorl %ebx, %eax
+ jnz LeaveLoopCmps
+ movl 4(%esi,%edx), %eax
+ movl 4(%edi,%edx), %ebx
+ xorl %ebx, %eax
+ jnz LeaveLoopCmps4
+ addl $8, %edx
+ jnz LoopCmps
+ jmp LenMaximum
+LeaveLoopCmps4: addl $4, %edx
+LeaveLoopCmps: testl $0x0000FFFF, %eax
+ jnz LenLower
+ addl $2, %edx
+ shrl $16, %eax
+LenLower: subb $1, %al
+ adcl $0, %edx
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
+/* then automatically accept it as the best possible match and leave. */
+
+ lea (%edi,%edx), %eax
+ movl scan(%esp), %edi
+ subl %edi, %eax
+ cmpl $MAX_MATCH, %eax
+ jge LenMaximum
+
+/* If the length of the match is not longer than the best match we */
+/* have so far, then forget it and return to the lookup loop. */
+
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ cmpl %ebx, %eax
+ jg LongerMatch
+ movl chainlenscanend(%esp), %ebx
+ movl windowbestlen(%esp), %esi
+ movl dsPrev(%edx), %edi
+ movl wmask(%esp), %edx
+ andl %ecx, %edx
+ jmp LookupLoop
+
+/* s->match_start = cur_match; */
+/* best_len = len; */
+/* if (len >= nice_match) break; */
+/* scan_end = *(ushf*)(scan+best_len-1); */
+
+LongerMatch: movl nicematch(%esp), %ebx
+ movl %eax, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+ cmpl %ebx, %eax
+ jge LeaveNow
+ movl window(%esp), %esi
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+ movl chainlenscanend(%esp), %ebx
+ movw -1(%edi,%eax), %bx
+ movl dsPrev(%edx), %edi
+ movl %ebx, chainlenscanend(%esp)
+ movl wmask(%esp), %edx
+ andl %ecx, %edx
+ jmp LookupLoop
+
+/* Accept the current string, with the maximum possible length. */
+
+LenMaximum: movl deflatestate(%esp), %edx
+ movl $MAX_MATCH, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
+/* return s->lookahead; */
+
+LeaveNow:
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ movl dsLookahead(%edx), %eax
+ cmpl %eax, %ebx
+ jg LookaheadRet
+ movl %ebx, %eax
+LookaheadRet:
+
+/* Restore the stack and return from whence we came. */
+
+ addl $LocalVarsSize, %esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+match_init: ret
diff --git a/linux/lib/zlib/match686.S b/linux/lib/zlib/match686.S
new file mode 100644
index 000000000..63fce28d4
--- /dev/null
+++ b/linux/lib/zlib/match686.S
@@ -0,0 +1,330 @@
+/* match.s -- Pentium-Pro-optimized version of longest_match()
+ * Written for zlib 1.1.2
+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License.
+ */
+
+#ifndef NO_UNDERLINE
+#define match_init _ipcomp_match_init
+#define longest_match _ipcomp_longest_match
+#else
+#define match_init ipcomp_match_init
+#define longest_match ipcomp_longest_match
+#endif
+
+#define MAX_MATCH (258)
+#define MIN_MATCH (3)
+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+
+#define chainlenwmask 0 /* high word: current chain len */
+ /* low word: s->wmask */
+#define window 4 /* local copy of s->window */
+#define windowbestlen 8 /* s->window + bestlen */
+#define scanstart 16 /* first two bytes of string */
+#define scanend 12 /* last two bytes of string */
+#define scanalign 20 /* dword-misalignment of string */
+#define nicematch 24 /* a good enough match size */
+#define bestlen 28 /* size of best match so far */
+#define scan 32 /* ptr to string wanting match */
+
+#define LocalVarsSize (36)
+/* saved ebx 36 */
+/* saved edi 40 */
+/* saved esi 44 */
+/* saved ebp 48 */
+/* return address 52 */
+#define deflatestate 56 /* the function arguments */
+#define curmatch 60
+
+/* Offsets for fields in the deflate_state structure. These numbers
+ * are calculated from the definition of deflate_state, with the
+ * assumption that the compiler will dword-align the fields. (Thus,
+ * changing the definition of deflate_state could easily cause this
+ * program to crash horribly, without so much as a warning at
+ * compile time. Sigh.)
+ */
+#define dsWSize 36
+#define dsWMask 44
+#define dsWindow 48
+#define dsPrev 56
+#define dsMatchLen 88
+#define dsPrevMatch 92
+#define dsStrStart 100
+#define dsMatchStart 104
+#define dsLookahead 108
+#define dsPrevLen 112
+#define dsMaxChainLen 116
+#define dsGoodMatch 132
+#define dsNiceMatch 136
+
+
+.file "match.S"
+
+.globl match_init, longest_match
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+
+longest_match:
+
+/* Save registers that the compiler may be using, and adjust %esp to */
+/* make room for our stack frame. */
+
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ subl $LocalVarsSize, %esp
+
+/* Retrieve the function arguments. %ecx will hold cur_match */
+/* throughout the entire function. %edx will hold the pointer to the */
+/* deflate_state structure during the function's setup (before */
+/* entering the main loop). */
+
+ movl deflatestate(%esp), %edx
+ movl curmatch(%esp), %ecx
+
+/* uInt wmask = s->w_mask; */
+/* unsigned chain_length = s->max_chain_length; */
+/* if (s->prev_length >= s->good_match) { */
+/* chain_length >>= 2; */
+/* } */
+
+ movl dsPrevLen(%edx), %eax
+ movl dsGoodMatch(%edx), %ebx
+ cmpl %ebx, %eax
+ movl dsWMask(%edx), %eax
+ movl dsMaxChainLen(%edx), %ebx
+ jl LastMatchGood
+ shrl $2, %ebx
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can */
+/* use the sign flag instead of the zero flag for the exit test. */
+/* It is then shifted into the high word, to make room for the wmask */
+/* value, which it will always accompany. */
+
+ decl %ebx
+ shll $16, %ebx
+ orl %eax, %ebx
+ movl %ebx, chainlenwmask(%esp)
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
+
+ movl dsNiceMatch(%edx), %eax
+ movl dsLookahead(%edx), %ebx
+ cmpl %eax, %ebx
+ jl LookaheadLess
+ movl %eax, %ebx
+LookaheadLess: movl %ebx, nicematch(%esp)
+
+/* register Bytef *scan = s->window + s->strstart; */
+
+ movl dsWindow(%edx), %esi
+ movl %esi, window(%esp)
+ movl dsStrStart(%edx), %ebp
+ lea (%esi,%ebp), %edi
+ movl %edi, scan(%esp)
+
+/* Determine how many bytes the scan ptr is off from being */
+/* dword-aligned. */
+
+ movl %edi, %eax
+ negl %eax
+ andl $3, %eax
+ movl %eax, scanalign(%esp)
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
+
+ movl dsWSize(%edx), %eax
+ subl $MIN_LOOKAHEAD, %eax
+ subl %eax, %ebp
+ jg LimitPositive
+ xorl %ebp, %ebp
+LimitPositive:
+
+/* int best_len = s->prev_length; */
+
+ movl dsPrevLen(%edx), %eax
+ movl %eax, bestlen(%esp)
+
+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+
+/* register ush scan_start = *(ushf*)scan; */
+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
+/* Posf *prev = s->prev; */
+
+ movzwl (%edi), %ebx
+ movl %ebx, scanstart(%esp)
+ movzwl -1(%edi,%eax), %ebx
+ movl %ebx, scanend(%esp)
+ movl dsPrev(%edx), %edi
+
+/* Jump into the main loop. */
+
+ movl chainlenwmask(%esp), %edx
+ jmp LoopEntry
+
+.balign 16
+
+/* do {
+ * match = s->window + cur_match;
+ * if (*(ushf*)(match+best_len-1) != scan_end ||
+ * *(ushf*)match != scan_start) continue;
+ * [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ * && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ *
+ * Within this loop:
+ * %ebx = scanend
+ * %ecx = curmatch
+ * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+ * %esi = windowbestlen - i.e., (window + bestlen)
+ * %edi = prev
+ * %ebp = limit
+ */
+LookupLoop:
+ andl %edx, %ecx
+ movzwl (%edi,%ecx,2), %ecx
+ cmpl %ebp, %ecx
+ jbe LeaveNow
+ subl $0x00010000, %edx
+ js LeaveNow
+LoopEntry: movzwl -1(%esi,%ecx), %eax
+ cmpl %ebx, %eax
+ jnz LookupLoop
+ movl window(%esp), %eax
+ movzwl (%eax,%ecx), %eax
+ cmpl scanstart(%esp), %eax
+ jnz LookupLoop
+
+/* Store the current value of chainlen. */
+
+ movl %edx, chainlenwmask(%esp)
+
+/* Point %edi to the string under scrutiny, and %esi to the string we */
+/* are hoping to match it up with. In actuality, %esi and %edi are */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
+/* initialized to -(MAX_MATCH_8 - scanalign). */
+
+ movl window(%esp), %esi
+ movl scan(%esp), %edi
+ addl %ecx, %esi
+ movl scanalign(%esp), %eax
+ movl $(-MAX_MATCH_8), %edx
+ lea MAX_MATCH_8(%edi,%eax), %edi
+ lea MAX_MATCH_8(%esi,%eax), %esi
+
+/* Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %edx so that it is offset to the exact byte that mismatched.
+ *
+ * We already know at this point that the first three bytes of the
+ * strings match each other, and they can be safely passed over before
+ * starting the compare loop. So what this code does is skip over 0-3
+ * bytes, as much as necessary in order to dword-align the %edi
+ * pointer. (%esi will still be misaligned three times out of four.)
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance.
+ */
+LoopCmps:
+ movl (%esi,%edx), %eax
+ xorl (%edi,%edx), %eax
+ jnz LeaveLoopCmps
+ movl 4(%esi,%edx), %eax
+ xorl 4(%edi,%edx), %eax
+ jnz LeaveLoopCmps4
+ addl $8, %edx
+ jnz LoopCmps
+ jmp LenMaximum
+LeaveLoopCmps4: addl $4, %edx
+LeaveLoopCmps: testl $0x0000FFFF, %eax
+ jnz LenLower
+ addl $2, %edx
+ shrl $16, %eax
+LenLower: subb $1, %al
+ adcl $0, %edx
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
+/* then automatically accept it as the best possible match and leave. */
+
+ lea (%edi,%edx), %eax
+ movl scan(%esp), %edi
+ subl %edi, %eax
+ cmpl $MAX_MATCH, %eax
+ jge LenMaximum
+
+/* If the length of the match is not longer than the best match we */
+/* have so far, then forget it and return to the lookup loop. */
+
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ cmpl %ebx, %eax
+ jg LongerMatch
+ movl windowbestlen(%esp), %esi
+ movl dsPrev(%edx), %edi
+ movl scanend(%esp), %ebx
+ movl chainlenwmask(%esp), %edx
+ jmp LookupLoop
+
+/* s->match_start = cur_match; */
+/* best_len = len; */
+/* if (len >= nice_match) break; */
+/* scan_end = *(ushf*)(scan+best_len-1); */
+
+LongerMatch: movl nicematch(%esp), %ebx
+ movl %eax, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+ cmpl %ebx, %eax
+ jge LeaveNow
+ movl window(%esp), %esi
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+ movzwl -1(%edi,%eax), %ebx
+ movl dsPrev(%edx), %edi
+ movl %ebx, scanend(%esp)
+ movl chainlenwmask(%esp), %edx
+ jmp LookupLoop
+
+/* Accept the current string, with the maximum possible length. */
+
+LenMaximum: movl deflatestate(%esp), %edx
+ movl $MAX_MATCH, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
+/* return s->lookahead; */
+
+LeaveNow:
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ movl dsLookahead(%edx), %eax
+ cmpl %eax, %ebx
+ jg LookaheadRet
+ movl %ebx, %eax
+LookaheadRet:
+
+/* Restore the stack and return from whence we came. */
+
+ addl $LocalVarsSize, %esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+match_init: ret
diff --git a/linux/lib/zlib/trees.c b/linux/lib/zlib/trees.c
new file mode 100644
index 000000000..b268ea305
--- /dev/null
+++ b/linux/lib/zlib/trees.c
@@ -0,0 +1,1214 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2002 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id: trees.c,v 1.1 2004/03/15 20:35:26 as Exp $ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, const ct_data *ltree,
+ const ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is ascii or binary */
+ if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute first the block length in bytes*/
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, static_ltree, static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, s->dyn_ltree, s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ const ct_data *ltree; /* literal tree */
+ const ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += s->dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+ s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/linux/lib/zlib/trees.h b/linux/lib/zlib/trees.h
new file mode 100644
index 000000000..72facf900
--- /dev/null
+++ b/linux/lib/zlib/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/linux/lib/zlib/zconf.h b/linux/lib/zlib/zconf.h
new file mode 100644
index 000000000..bf52dced5
--- /dev/null
+++ b/linux/lib/zlib/zconf.h
@@ -0,0 +1,309 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.h,v 1.1 2004/03/15 20:35:26 as Exp $ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef IPCOMP_PREFIX
+# define deflateInit_ ipcomp_deflateInit_
+# define deflate ipcomp_deflate
+# define deflateEnd ipcomp_deflateEnd
+# define inflateInit_ ipcomp_inflateInit_
+# define inflate ipcomp_inflate
+# define inflateEnd ipcomp_inflateEnd
+# define deflateInit2_ ipcomp_deflateInit2_
+# define deflateSetDictionary ipcomp_deflateSetDictionary
+# define deflateCopy ipcomp_deflateCopy
+# define deflateReset ipcomp_deflateReset
+# define deflateParams ipcomp_deflateParams
+# define inflateInit2_ ipcomp_inflateInit2_
+# define inflateSetDictionary ipcomp_inflateSetDictionary
+# define inflateSync ipcomp_inflateSync
+# define inflateSyncPoint ipcomp_inflateSyncPoint
+# define inflateReset ipcomp_inflateReset
+# define compress ipcomp_compress
+# define compress2 ipcomp_compress2
+# define uncompress ipcomp_uncompress
+# define adler32 ipcomp_adler32
+# define crc32 ipcomp_crc32
+# define get_crc_table ipcomp_get_crc_table
+/* SSS: these also need to be prefixed to avoid clash with ppp_deflate and ext2compression */
+# define inflate_blocks ipcomp_deflate_blocks
+# define inflate_blocks_free ipcomp_deflate_blocks_free
+# define inflate_blocks_new ipcomp_inflate_blocks_new
+# define inflate_blocks_reset ipcomp_inflate_blocks_reset
+# define inflate_blocks_sync_point ipcomp_inflate_blocks_sync_point
+# define inflate_set_dictionary ipcomp_inflate_set_dictionary
+# define inflate_codes ipcomp_inflate_codes
+# define inflate_codes_free ipcomp_inflate_codes_free
+# define inflate_codes_new ipcomp_inflate_codes_new
+# define inflate_fast ipcomp_inflate_fast
+# define inflate_trees_bits ipcomp_inflate_trees_bits
+# define inflate_trees_dynamic ipcomp_inflate_trees_dynamic
+# define inflate_trees_fixed ipcomp_inflate_trees_fixed
+# define inflate_flush ipcomp_inflate_flush
+# define inflate_mask ipcomp_inflate_mask
+# define _dist_code _ipcomp_dist_code
+# define _length_code _ipcomp_length_code
+# define _tr_align _ipcomp_tr_align
+# define _tr_flush_block _ipcomp_tr_flush_block
+# define _tr_init _ipcomp_tr_init
+# define _tr_stored_block _ipcomp_tr_stored_block
+# define _tr_tally _ipcomp_tr_tally
+# define zError ipcomp_zError
+# define z_errmsg ipcomp_z_errmsg
+# define zlibVersion ipcomp_zlibVersion
+# define match_init ipcomp_match_init
+# define longest_match ipcomp_longest_match
+#endif
+
+#ifdef Z_PREFIX
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+# define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+# ifndef __32BIT__
+# define __32BIT__
+# endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC)
+# define STDC
+#endif
+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
+# ifndef STDC
+# define STDC
+# endif
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Old Borland C incorrectly complains about missing returns: */
+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+# define NEED_DUMMY_RETURN
+#endif
+
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+# ifndef __32BIT__
+# define SMALL_MEDIUM
+# define FAR _far
+# endif
+#endif
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if defined(ZLIB_DLL)
+# if defined(_WINDOWS) || defined(WINDOWS)
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR _cdecl _export
+# endif
+# endif
+# if defined (__BORLANDC__)
+# if (__BORLANDC__ >= 0x0500) && defined (WIN32)
+# include <windows.h>
+# define ZEXPORT __declspec(dllexport) WINAPI
+# define ZEXPORTRVA __declspec(dllexport) WINAPIV
+# else
+# if defined (_Windows) && defined (__DLL__)
+# define ZEXPORT _export
+# define ZEXPORTVA _export
+# endif
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# if defined (ZLIB_DLL)
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+#endif
+
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(inflate_blocks,"INBL")
+# pragma map(inflate_blocks_new,"INBLNE")
+# pragma map(inflate_blocks_free,"INBLFR")
+# pragma map(inflate_blocks_reset,"INBLRE")
+# pragma map(inflate_codes_free,"INCOFR")
+# pragma map(inflate_codes,"INCO")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_flush,"INFLU")
+# pragma map(inflate_mask,"INMA")
+# pragma map(inflate_set_dictionary,"INSEDI2")
+# pragma map(ipcomp_inflate_copyright,"INCOPY")
+# pragma map(inflate_trees_bits,"INTRBI")
+# pragma map(inflate_trees_dynamic,"INTRDY")
+# pragma map(inflate_trees_fixed,"INTRFI")
+# pragma map(inflate_trees_free,"INTRFR")
+#endif
+
+#endif /* _ZCONF_H */
diff --git a/linux/lib/zlib/zutil.c b/linux/lib/zlib/zutil.c
new file mode 100644
index 000000000..81d602d82
--- /dev/null
+++ b/linux/lib/zlib/zutil.c
@@ -0,0 +1,227 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zutil.c,v 1.1 2004/03/15 20:35:26 as Exp $ */
+
+#include <zlib/zutil.h>
+
+#define MY_ZCALLOC
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char *z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/linux/net/Config.in.fs2_0.patch b/linux/net/Config.in.fs2_0.patch
new file mode 100644
index 000000000..6ff7cf06c
--- /dev/null
+++ b/linux/net/Config.in.fs2_0.patch
@@ -0,0 +1,12 @@
+RCSID $Id: Config.in.fs2_0.patch,v 1.2 2004/03/30 14:15:03 as Exp $
+--- linux/net/Config.in.preipsec Mon Jul 13 16:47:40 1998
++++ linux/net/Config.in Thu Sep 16 11:26:31 1999
+@@ -24,4 +24,8 @@
+ if [ "$CONFIG_NETLINK" = "y" ]; then
+ bool 'Routing messages' CONFIG_RTNETLINK
+ fi
++tristate 'IP Security Protocol (strongSwan IPsec)' CONFIG_IPSEC
++if [ "$CONFIG_IPSEC" != "n" ]; then
++ source net/ipsec/Config.in
++fi
+ endmenu
diff --git a/linux/net/Config.in.fs2_2.patch b/linux/net/Config.in.fs2_2.patch
new file mode 100644
index 000000000..5d7c6de53
--- /dev/null
+++ b/linux/net/Config.in.fs2_2.patch
@@ -0,0 +1,12 @@
+RCSID $Id: Config.in.fs2_2.patch,v 1.2 2004/03/30 14:15:03 as Exp $
+--- linux/net/Config.in.preipsec Thu Feb 25 13:46:47 1999
++++ linux/net/Config.in Sat Aug 28 02:24:59 1999
+@@ -63,4 +63,8 @@
+ endmenu
+ fi
+ fi
++tristate 'IP Security Protocol (strongSwan IPsec)' CONFIG_IPSEC
++if [ "$CONFIG_IPSEC" != "n" ]; then
++ source net/ipsec/Config.in
++fi
+ endmenu
diff --git a/linux/net/Config.in.fs2_4.patch b/linux/net/Config.in.fs2_4.patch
new file mode 100644
index 000000000..82ec14188
--- /dev/null
+++ b/linux/net/Config.in.fs2_4.patch
@@ -0,0 +1,13 @@
+--- linux/net/Config.in.orig Fri Feb 9 14:34:13 2001
++++ linux/net/Config.in Thu Feb 22 19:40:08 2001
+@@ -88,4 +88,10 @@
+ #bool 'Network code profiler' CONFIG_NET_PROFILE
+ endmenu
+
++tristate 'IP Security Protocol (strongSwan IPsec)' CONFIG_IPSEC
++define_tristate CONFIG_IPSEC m
++if [ "$CONFIG_IPSEC" != "n" ]; then
++ source net/ipsec/Config.in
++fi
++
+ endmenu
diff --git a/linux/net/Makefile.fs2_0.patch b/linux/net/Makefile.fs2_0.patch
new file mode 100644
index 000000000..7909f1e6d
--- /dev/null
+++ b/linux/net/Makefile.fs2_0.patch
@@ -0,0 +1,20 @@
+RCSID $Id: Makefile.fs2_0.patch,v 1.1 2004/03/15 20:35:26 as Exp $
+--- linux/net/Makefile.preipsec Mon Jul 13 16:47:40 1998
++++ linux/net/Makefile Thu Sep 16 11:26:31 1999
+@@ -64,6 +64,16 @@
+ endif
+ endif
+
++ifeq ($(CONFIG_IPSEC),y)
++ALL_SUB_DIRS += ipsec
++SUB_DIRS += ipsec
++else
++ ifeq ($(CONFIG_IPSEC),m)
++ ALL_SUB_DIRS += ipsec
++ MOD_SUB_DIRS += ipsec
++ endif
++endif
++
+ L_TARGET := network.a
+ L_OBJS := socket.o protocols.o sysctl_net.o $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
+ ifeq ($(CONFIG_NET),y)
diff --git a/linux/net/Makefile.fs2_2.patch b/linux/net/Makefile.fs2_2.patch
new file mode 100644
index 000000000..70e400de9
--- /dev/null
+++ b/linux/net/Makefile.fs2_2.patch
@@ -0,0 +1,20 @@
+RCSID $Id: Makefile.fs2_2.patch,v 1.1 2004/03/15 20:35:26 as Exp $
+--- linux/net/Makefile.preipsec Tue Jun 20 17:32:27 2000
++++ linux/net/Makefile Fri Jun 30 14:44:38 2000
+@@ -195,6 +195,16 @@
+ endif
+ endif
+
++ifeq ($(CONFIG_IPSEC),y)
++ALL_SUB_DIRS += ipsec
++SUB_DIRS += ipsec
++else
++ ifeq ($(CONFIG_IPSEC),m)
++ ALL_SUB_DIRS += ipsec
++ MOD_SUB_DIRS += ipsec
++ endif
++endif
++
+ # We must attach netsyms.o to socket.o, as otherwise there is nothing
+ # to pull the object file from the archive.
+
diff --git a/linux/net/Makefile.fs2_4.ipsec_alg.patch b/linux/net/Makefile.fs2_4.ipsec_alg.patch
new file mode 100644
index 000000000..9aec86493
--- /dev/null
+++ b/linux/net/Makefile.fs2_4.ipsec_alg.patch
@@ -0,0 +1,10 @@
+--- linux/net/Makefile.dist Mon Dec 17 12:18:26 2001
++++ linux/net/Makefile Tue Jan 22 11:10:24 2002
+@@ -8,6 +8,7 @@
+ O_TARGET := network.o
+
+ mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched
++mod-subdirs += ipsec
+ export-objs := netsyms.o
+
+ subdir-y := core ethernet
diff --git a/linux/net/Makefile.fs2_4.patch b/linux/net/Makefile.fs2_4.patch
new file mode 100644
index 000000000..0d2c82a59
--- /dev/null
+++ b/linux/net/Makefile.fs2_4.patch
@@ -0,0 +1,11 @@
+RCSID $Id: Makefile.fs2_4.patch,v 1.1 2004/03/15 20:35:26 as Exp $
+--- linux/net/Makefile.preipsec Mon Jun 11 22:15:27 2001
++++ linux/net/Makefile Tue Nov 6 21:07:43 2001
+@@ -17,6 +17,7 @@
+ subdir-$(CONFIG_NET) += 802 sched
+ subdir-$(CONFIG_INET) += ipv4
+ subdir-$(CONFIG_NETFILTER) += ipv4/netfilter
++subdir-$(CONFIG_IPSEC) += ipsec
+ subdir-$(CONFIG_UNIX) += unix
+ subdir-$(CONFIG_IPV6) += ipv6
+
diff --git a/linux/net/include.net.sock.h.fs2_2.patch b/linux/net/include.net.sock.h.fs2_2.patch
new file mode 100644
index 000000000..9759dbb7a
--- /dev/null
+++ b/linux/net/include.net.sock.h.fs2_2.patch
@@ -0,0 +1,25 @@
+--- ./include/net/sock.h Fri Nov 2 17:39:16 2001
++++ ./include/net/sock.h Mon Jun 10 19:44:55 2002
+@@ -201,6 +201,12 @@
+ __u32 end_seq;
+ };
+
++#if 1
++struct udp_opt {
++ __u32 esp_in_udp;
++};
++#endif
++
+ struct tcp_opt {
+ int tcp_header_len; /* Bytes of tcp header to send */
+
+@@ -443,6 +449,9 @@
+ #if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
+ struct spx_opt af_spx;
+ #endif /* CONFIG_SPX */
++#if 1
++ struct udp_opt af_udp;
++#endif
+
+ } tp_pinfo;
+
diff --git a/linux/net/include.net.sock.h.fs2_4.patch b/linux/net/include.net.sock.h.fs2_4.patch
new file mode 100644
index 000000000..9466cf686
--- /dev/null
+++ b/linux/net/include.net.sock.h.fs2_4.patch
@@ -0,0 +1,27 @@
+--- ./include/net/sock.h 2002/02/06 15:25:10 1.1
++++ ./include/net/sock.h 2002/05/22 12:14:56
+@@ -488,7 +488,13 @@
+ } bictcp;
+ };
+
+-
++#if 1
++#define UDP_OPT_IN_SOCK 1
++struct udp_opt {
++ __u32 esp_in_udp;
++};
++#endif
++
+ /*
+ * This structure really needs to be cleaned up.
+ * Most of it is for TCP, and not used by any of
+@@ -655,6 +661,9 @@
+ #if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
+ struct spx_opt af_spx;
+ #endif /* CONFIG_SPX */
++#if 1
++ struct udp_opt af_udp;
++#endif
+
+ } tp_pinfo;
+
diff --git a/linux/net/ipsec/.cvsignore b/linux/net/ipsec/.cvsignore
new file mode 100644
index 000000000..63cb2042f
--- /dev/null
+++ b/linux/net/ipsec/.cvsignore
@@ -0,0 +1,47 @@
+.addrtoa.o.flags
+.adler32.o.flags
+.cbc_enc.o.flags
+.datatot.o.flags
+.deflate.o.flags
+.des_enc.o.flags
+.ecb_enc.o.flags
+.goodmask.o.flags
+.infblock.o.flags
+.infcodes.o.flags
+.inffast.o.flags
+.inflate.o.flags
+.inftrees.o.flags
+.infutil.o.flags
+.ipcomp.o.flags
+.ipsec.o.flags
+.ipsec_init.o.flags
+.ipsec_life.o.flags
+.ipsec_md5c.o.flags
+.ipsec_proc.o.flags
+.ipsec_radij.o.flags
+.ipsec_rcv.o.flags
+.ipsec_sa.o.flags
+.ipsec_sha1.o.flags
+.ipsec_tunnel.o.flags
+.pfkey_v2.o.flags
+.pfkey_v2_build.o.flags
+.pfkey_v2_debug.o.flags
+.pfkey_v2_ext_bits.o.flags
+.pfkey_v2_ext_process.o.flags
+.pfkey_v2_parse.o.flags
+.pfkey_v2_parser.o.flags
+.prng.o.flags
+.radij.o.flags
+.rangetoa.o.flags
+.satoa.o.flags
+.set_key.o.flags
+.subnetof.o.flags
+.subnettoa.o.flags
+.sysctl_net_ipsec.o.flags
+.trees.o.flags
+.ultoa.o.flags
+.version.o.flags
+.zutil.o.flags
+version.c
+.*.o.flags
+*.o
diff --git a/linux/net/ipsec/Config.in b/linux/net/ipsec/Config.in
new file mode 100644
index 000000000..379738a69
--- /dev/null
+++ b/linux/net/ipsec/Config.in
@@ -0,0 +1,41 @@
+#
+# IPSEC configuration
+# Copyright (C) 1998, 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: Config.in,v 1.3 2004/03/30 21:11:11 as Exp $
+
+comment 'IPsec options (strongSwan)'
+
+bool ' IPSEC: IP-in-IP encapsulation (tunnel mode)' CONFIG_IPSEC_IPIP
+
+bool ' IPSEC: Authentication Header' CONFIG_IPSEC_AH
+if [ "$CONFIG_IPSEC_AH" = "y" -o "$CONFIG_IPSEC_ESP" = "y" ]; then
+ bool ' HMAC-MD5 authentication algorithm' CONFIG_IPSEC_AUTH_HMAC_MD5
+ bool ' HMAC-SHA1 authentication algorithm' CONFIG_IPSEC_AUTH_HMAC_SHA1
+fi
+
+bool ' IPSEC: Encapsulating Security Payload' CONFIG_IPSEC_ESP
+if [ "$CONFIG_IPSEC_ESP" = "y" ]; then
+ bool ' 3DES encryption algorithm' CONFIG_IPSEC_ENC_3DES
+fi
+
+bool ' IPSEC Modular Extensions' CONFIG_IPSEC_ALG
+if [ "$CONFIG_IPSEC_ALG" != "n" ]; then
+ source net/ipsec/alg/Config.in
+fi
+
+bool ' IPSEC: IP Compression' CONFIG_IPSEC_IPCOMP
+
+bool ' IPSEC Debugging Option' CONFIG_IPSEC_DEBUG
+
+bool ' IPSEC NAT-Traversal' CONFIG_IPSEC_NAT_TRAVERSAL
diff --git a/linux/net/ipsec/Makefile b/linux/net/ipsec/Makefile
new file mode 100644
index 000000000..6d834a067
--- /dev/null
+++ b/linux/net/ipsec/Makefile
@@ -0,0 +1,529 @@
+# Makefile for KLIPS kernel code as a module
+# Copyright (C) 1998, 1999, 2000,2001 Richard Guy Briggs.
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.2 2004/03/22 21:53:19 as Exp $
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+ifeq ($(strip $(KLIPSMODULE)),)
+FREESWANSRCDIR=.
+else
+FREESWANSRCDIR=../../..
+endif
+-include ${FREESWANSRCDIR}/Makefile.ver
+
+ifeq ($(strip $(KLIPS_TOP)),)
+KLIPS_TOP=../..
+endif
+
+ifneq ($(strip $(KLIPSMODULE)),)
+
+ifndef TOPDIR
+TOPDIR:=/usr/src/linux
+endif
+export TOPDIR
+
+endif
+
+#
+# This magic from User-Mode-Linux list. It gets list of -I options, as
+# UML needs some extra, that varry by revision.
+#
+KERNEL_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(CFLAGS)' )
+
+MODULE_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(MODFLAGS)' )
+
+subdir- :=
+subdir-n :=
+subdir-y :=
+subdir-m :=
+
+
+MOD_DESTDIR:=net/ipsec
+
+export TOPDIR
+
+all: ipsec.o
+
+foo:
+ echo KERNEL: ${KERNEL_CFLAGS}
+ echo MODULE: ${MODULE_CFLAGS}
+
+ipsec.o: foo
+
+O_TARGET := ipsec.o
+obj-y := ipsec_init.o ipsec_sa.o ipsec_radij.o radij.o
+obj-y += ipsec_life.o ipsec_proc.o
+obj-y += ipsec_tunnel.o ipsec_xmit.o ipsec_rcv.o
+obj-y += sysctl_net_ipsec.o
+obj-y += pfkey_v2.o pfkey_v2_parser.o pfkey_v2_ext_process.o
+#obj-y += version.o
+
+LIBDESDIR=${KLIPS_TOP}/crypto/ciphers/des
+VPATH+= ${LIBDESDIR}
+
+include ${LIBDESDIR}/Makefile.objs
+
+LIBFREESWANDIR=${KLIPS_TOP}/lib/libfreeswan
+VPATH+=${LIBFREESWANDIR}
+
+include ${LIBFREESWANDIR}/Makefile.objs
+
+# IPcomp stuff
+obj-$(CONFIG_IPSEC_IPCOMP) += ipcomp.o
+
+LIBZLIBSRCDIR=${KLIPS_TOP}/lib/zlib
+VPATH+=${LIBZLIBSRCDIR}
+
+# LIBCRYPTO Will be overriden eg. when doing "make module"
+# from freeswan-2 src root
+# Default value assumes already symlinked libcrypto under $TOPDIR/lib
+LIBCRYPTO=$(TOPDIR)/lib/libcrypto
+VPATH+=${LIBCRYPTO}
+
+alg/static_init_mod.o: dummy
+ $(MAKE) -C alg CC='$(CC)' TOPDIR='$(TOPDIR)' \
+ 'EXTRA_CFLAGS=$(EXTRA_CFLAGS)' \
+ static_init_mod.o
+
+
+alg_modules: dummy
+ $(MAKE) $(MODULE_FLAGS) -C alg CC='$(CC)' TOPDIR='$(TOPDIR)' \
+ 'LIBCRYPTO=$(LIBCRYPTO)' \
+ 'EXTRA_CFLAGS=$(EXTRA_CFLAGS)' \
+ modules
+
+# CFLAGS='$(CFLAGS)' \
+# MODULE_CFLAGS='$(MODULE_CFLAGS)' KERNEL_CFLAGS='$(KERNEL_CFLAGS)' \
+#
+include ${LIBZLIBSRCDIR}/Makefile.objs
+
+export-objs := radij.o
+
+# New handling of KERNEL_CFLAGS and MODULE_CFLAGS introduced in 2.0
+# tosses export-objs logic :(
+CFLAGS_ipsec_alg.o += -DEXPORT_SYMTAB
+obj-$(CONFIG_IPSEC_ALG) +=ipsec_alg.o alg/static_init_mod.o
+export-objs += ipsec_alg.o
+subdir-m += alg
+
+EXTRA_CFLAGS += $(ALGO_FLAGS)
+
+
+# include file with .h-style macros that would otherwise be created by
+# config. Must occur before other includes.
+ifneq ($(strip $(MODULE_DEF_INCLUDE)),)
+EXTRA_CFLAGS += -include ${MODULE_DEF_INCLUDE}
+endif
+
+# 'override CFLAGS' should really be 'EXTRA_CFLAGS'
+#EXTRA_CFLAGS += -nostdinc
+EXTRA_CFLAGS += -I${KLIPS_TOP}/include
+
+EXTRA_CFLAGS += -I${TOPDIR}/include
+EXTRA_CFLAGS += -I${LIBZLIBSRCDIR}
+
+ifeq ($(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION),2.4.2-2)
+EXTRA_CFLAGS += -DREDHAT_BOGOSITY
+endif
+
+ifeq ($(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION),2.4.3-12)
+EXTRA_CFLAGS += -DREDHAT_BOGOSITY
+endif
+
+
+#ifeq ($(CONFIG_IPSEC_DEBUG),y)
+#EXTRA_CFLAGS += -g
+#endif
+
+#ifeq ($(CONFIG_IPSEC_ALG), y)
+EXTRA_CFLAGS += -DCONFIG_IPSEC_ALG
+#endif
+# MOST of these flags are in KERNEL_CFLAGS already!
+
+EXTRA_CFLAGS += $(KLIPSCOMPILE)
+EXTRA_CFLAGS += -Wall
+#EXTRA_CFLAGS += -Werror
+#EXTRA_CFLAGS += -Wconversion
+#EXTRA_CFLAGS += -Wmissing-prototypes
+# cannot use both -Wpointer-arith and -Werror with CONFIG_HIGHMEM
+# include/linux/highmem.h has an inline function definition that uses void* arithmentic.
+ifeq ($(CONFIG_NOHIGHMEM),y)
+EXTRA_CFLAGS += -Wpointer-arith
+endif
+#EXTRA_CFLAGS += -Wcast-qual
+#EXTRA_CFLAGS += -Wmissing-declarations
+#EXTRA_CFLAGS += -Wstrict-prototypes
+#EXTRA_CFLAGS += -pedantic
+#EXTRA_CFLAGS += -O3
+#EXTRA_CFLAGS += -W
+#EXTRA_CFLAGS += -Wwrite-strings
+#EXTRA_CFLAGS += -Wbad-function-cast
+
+ifneq ($(strip $(KLIPSMODULE)),)
+# for when we aren't building in the kernel tree
+EXTRA_CFLAGS += -DARCH=${ARCH}
+EXTRA_CFLAGS += -DMODVERSIONS
+EXTRA_CFLAGS += -include ${TOPDIR}/include/linux/modversions.h
+EXTRA_CFLAGS += ${MODULE_CFLAGS}
+endif
+
+EXTRA_CFLAGS += ${KERNEL_CFLAGS}
+
+
+# GCC 3.2 (and we presume any other 3.x) wants -falign-functions
+# in place of the traditional -malign-functions. Getting this
+# wrong leads to a warning, which is fatal due to our use of -Werror.
+ifeq ($(patsubst 3.%,3,$(shell $(CC) -dumpversion)),3)
+override CFLAGS:=$(subst -malign-functions=,-falign-functions=,$(CFLAGS))
+endif
+
+
+obj-$(CONFIG_IPSEC_AUTH_HMAC_MD5) += ipsec_md5c.o
+obj-$(CONFIG_IPSEC_AUTH_HMAC_SHA1) += ipsec_sha1.o
+
+###
+### Pre Rules.make
+###
+# undo O_TARGET, obj-y if no static
+ifneq ($(CONFIG_IPSEC),y)
+O_TARGET :=
+ipsec_obj-y := $(obj-y)
+obj-y :=
+subdir-y :=
+endif
+
+# Define obj-m if modular ipsec
+ifeq ($(CONFIG_IPSEC),m)
+obj-m += ipsec.o
+endif
+
+
+# These rules translate from new to old makefile rules
+# Translate to Rules.make lists.
+multi-used := $(filter $(list-multi), $(obj-y) $(obj-m))
+multi-objs := $(foreach m, $(multi-used), $($(basename $(m))-objs))
+active-objs := $(sort $(multi-objs) $(obj-y) $(obj-m))
+O_OBJS := $(obj-y)
+M_OBJS := $(obj-m)
+MIX_OBJS := $(filter $(export-objs), $(active-objs))
+OX_OBJS := $(export-objs)
+SUB_DIRS := $(subdir-y)
+ALL_SUB_DIRS := $(subdir-y) $(subdir-m)
+MOD_SUB_DIRS := $(subdir-m)
+
+# dunno why, but some 2.2 setups may need explicit -DEXPORT_SYMTAB
+# uncomment next line if ipsec_alg.c compilation fails with
+# "parse error before `EXPORT_SYMTAB_not_defined'" --Juanjo
+# CFLAGS_ipsec_alg.o += -DEXPORT_SYMTAB
+#
+
+include $(TOPDIR)/Rules.make
+
+###
+### Post Rules.make
+###
+# for modular ipsec, no O_TARGET defined => define ipsec.o creation rules
+ifeq ($(CONFIG_IPSEC),m)
+ipsec.o : $(ipsec_obj-y)
+ rm -f $@
+ $(LD) $(LD_EXTRAFLAGS) -r $(ipsec_obj-y) -o $@
+endif
+
+$(ipsec_obj-y) $(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
+
+#$(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
+
+USE_STANDARD_AS_RULE=true
+
+clean:
+ $(MAKE) -C alg clean
+ -rm -f *.o
+ -rm -f .*.o.flags
+ -rm version.c
+
+tags TAGS: *.c *.h libfreeswan/*.c libfreeswan/*.h
+ etags *.c ../../include/*.h ../../include/freeswan/*.h
+ ctags *.c ../../include/*.h ../../include/freeswan/*.h
+
+tar:
+ tar -cvf /dev/f1 .
+
+#
+# $Log: Makefile,v $
+# Revision 1.2 2004/03/22 21:53:19 as
+# merged alg-0.8.1 branch with HEAD
+#
+# Revision 1.1.4.1 2004/03/16 09:48:19 as
+# alg-0.8.1rc12 patch merged
+#
+# Revision 1.1 2004/03/15 20:35:26 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.61 2003/06/22 21:07:46 mcr
+# adjusted TAGS target in makefile to be useful in 2.00 source layout.
+#
+# Revision 1.60 2003/05/03 23:45:23 mcr
+# rm .o.flags and generated version.c file.
+#
+# Revision 1.59 2003/02/12 19:32:47 rgb
+# Added ipsec_xmit to the list of object files.
+#
+# Revision 1.58 2003/01/03 00:36:44 rgb
+#
+# Added emacs compile-command.
+#
+# Revision 1.57 2002/11/08 23:49:53 mcr
+# use KERNEL_CFLAGS and MODULE_CFLAGS to get proper list
+# of include directories.
+# This also eliminates some of the guesswork in the kernel
+# configuration file.
+#
+# Revision 1.56 2002/11/08 23:23:18 mcr
+# attempt to guess kernel compilation flags (i.e. list of -I)
+# by using some magic targets in the kernel makefile.
+#
+# Revision 1.55 2002/11/08 10:13:33 mcr
+# added additional include directories for module builds for 2.4.19.
+#
+# Revision 1.54 2002/10/20 06:10:30 build
+# CONFIG_NOHIGHMEM for -Wpointer-arith RPM building issues.
+#
+# Revision 1.53 2002/10/17 16:32:01 mcr
+# enable standard AS rules.
+#
+# Revision 1.52 2002/10/06 06:13:44 sam
+# Altering order of includes, so that architecture-specific header files,
+# used for building RPM modules specifically, are processed first.
+#
+# Revision 1.51 2002/10/05 15:06:38 dhr
+#
+# - To allow for gcc3.2 (used in Red Hat Linux 8.0): adjust CFLAGS (set
+# by kernel machinery) to use -falign-functions= in place of
+# -malign-functions=. Eliminates a warning (fatal with -Werror).
+#
+# - When CONFIG_HIGHMEM is on, -Wpointer-arith will warn about
+# include/linux/highmem.h. Since this is fatal with -Werror, we
+# suppress -Wpointer-arith if CONFIG_HIGHMEM is set.
+#
+# Revision 1.50 2002/09/16 21:19:45 mcr
+# enable -Werror for production - this helps a lot (found a bug in ipsec_rcv.c)
+#
+# Revision 1.49 2002/07/29 05:12:39 mcr
+# get rid of some extraneous stuff, now handled by a prefix
+# Makefile when building as a module.
+#
+# Revision 1.48 2002/07/28 23:13:49 mcr
+# set KLIPS_TOP and use it instead of ../..
+# if KLIPSMODULE, then include a bunch of stuff defined in Makefile.inc
+# that gets us the "typical" configuration that we want.
+#
+# Revision 1.47 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.46 2002/05/14 02:35:51 rgb
+# Added file pfkey_v2_ext_process.c.
+#
+# Revision 1.45 2002/05/13 17:21:40 mcr
+# mkdep dies when given a -I to a directory that does not exist.
+# arch/${ARCH}/include is for UM arch only, so include it for that
+# ARCH only.
+#
+# Revision 1.44 2002/04/24 20:38:12 mcr
+# moved more stuff behind $KLIPSMODULE=y to get static linking to work.
+#
+# Revision 1.43 2002/04/24 09:16:18 mcr
+# include local Makefile.ver as well as FS_rootdir version.
+#
+# Revision 1.42 2002/04/24 08:50:08 mcr
+# critical patch is to set TOPDIR with :=.
+#
+# Revision 1.40 2002/04/24 00:41:07 mcr
+# Moved from ./klips/net/ipsec/Makefile,v
+#
+# Revision 1.39 2002/01/17 04:39:40 rgb
+# Take compile options from top level Makefile.inc
+#
+# Revision 1.38 2001/11/27 05:28:07 rgb
+# Shut off -Werror until we figure out a graceful way of quieting down the
+# pfkey_ops defined but not used complaint in the case of SMP in
+# pfkey_v2.c.
+#
+# Revision 1.37 2001/11/27 05:10:15 rgb
+# Added -Ilibdes and removed lib/des* symlinks.
+#
+# Revision 1.36 2001/11/26 09:23:47 rgb
+# Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+#
+# Revision 1.35.2.1 2001/09/25 02:17:50 mcr
+# added ipsec_sa, ipsec_life, ipsec_proc.
+# added -Werror to compile flags (see fix for zlib/zutil.h)
+#
+# Revision 1.3 2001/09/21 04:41:26 mcr
+# actually, ipsec_proc.c and ipsec_life.c were never actually compiled.
+#
+# Revision 1.2 2001/09/21 04:11:33 mcr
+# first compilable version.
+#
+# Revision 1.1.1.2 2001/09/17 01:17:52 mcr
+# snapshot 2001-09-16
+#
+# Revision 1.35 2001/09/07 22:09:12 rgb
+# Quiet down compilation.
+#
+# Revision 1.34 2001/08/11 17:10:23 henry
+# update bogosity stuff to cover RH7.1 update
+#
+# Revision 1.33 2001/06/14 19:35:07 rgb
+# Update copyright date.
+#
+# Revision 1.32 2001/06/13 21:00:50 rgb
+# Added a kludge to get around RedHat kernel version bogosity...
+#
+# Revision 1.31 2001/01/29 22:19:06 rgb
+# Convert to 2.4 new style with back compat.
+#
+# Revision 1.30 2000/09/29 19:51:57 rgb
+# Moved klips/net/ipsec/ipcomp_* to zlib/* (Svenning).
+#
+# Revision 1.29 2000/09/15 11:37:01 rgb
+# Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+# IPCOMP zlib deflate code.
+#
+# Revision 1.28 2000/09/15 04:55:25 rgb
+# Clean up pfkey object inclusion into the default object.
+#
+# Revision 1.27 2000/09/12 03:20:47 rgb
+# Cleared out now unused pfkeyv2 switch.
+# Enabled sysctl.
+#
+# Revision 1.26 2000/09/08 19:12:55 rgb
+# Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+#
+# Revision 1.25 2000/06/16 03:09:16 rgb
+# Shut up cast lost warning due to changes in 2.4.0-test1.
+#
+# Revision 1.24 2000/03/16 06:40:48 rgb
+# Hardcode PF_KEYv2 support.
+#
+# Revision 1.23 2000/02/14 21:10:38 rgb
+# Added gcc debug flag when KLIPS_DEBUG is swtiched on.
+#
+# Revision 1.22 2000/01/21 09:44:29 rgb
+# Added compiler switches to be a lot more fussy.
+#
+# Revision 1.21 1999/11/25 23:35:20 rgb
+# Removed quotes to fix Alpha compile issues.
+#
+# Revision 1.20 1999/11/17 15:49:34 rgb
+# Changed all occurrences of ../../../lib in pathnames to libfreeswan,
+# which refers to the /usr/src/linux/net/ipsec/lib directory setup by the
+# klink target in the top-level Makefile; and libdeslite.o to
+# libdes/libdes.a.
+# Added SUB_DIRS := lib definition for the kernel libraries.
+#
+# Revision 1.19 1999/04/27 19:06:47 rgb
+# dd libs and dependancies to tags generation.
+#
+# Revision 1.18 1999/04/16 16:28:12 rgb
+# Minor bugfix to avoid including DES if only AH is used.
+#
+# Revision 1.17 1999/04/15 15:37:23 rgb
+# Forward check changes from POST1_00 branch.
+#
+# Revision 1.14.2.1 1999/03/30 17:29:17 rgb
+# Add support for pfkey.
+#
+# Revision 1.16 1999/04/11 00:28:56 henry
+# GPL boilerplate
+#
+# Revision 1.15 1999/04/06 04:54:25 rgb
+# Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+# patch shell fixes.
+#
+# Revision 1.14 1999/02/18 16:50:45 henry
+# update for new DES library
+#
+# Revision 1.13 1999/02/12 21:11:45 rgb
+# Prepare for newer LIBDES (patch from P.Onion).
+#
+# Revision 1.12 1999/01/26 02:05:08 rgb
+# Remove references to INET_GET_PROTOCOL.
+# Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+# Change from transform switch to algorithm switch.
+#
+# Revision 1.11 1999/01/22 06:16:09 rgb
+# Added algorithm switch code config option.
+#
+# Revision 1.10 1998/11/08 05:31:21 henry
+# be a little fussier
+#
+# Revision 1.9 1998/11/08 05:29:41 henry
+# revisions for new libdes handling
+#
+# Revision 1.8 1998/08/12 00:05:48 rgb
+# Added new xforms to Makefile (moved des-cbc to des-old).
+#
+# Revision 1.7 1998/07/27 21:48:47 rgb
+# Add libkernel.
+#
+# Revision 1.6 1998/07/14 15:50:47 rgb
+# Add dependancies on linux config files.
+#
+# Revision 1.5 1998/07/09 17:44:06 rgb
+# Added 'clean' and 'tags' targets.
+# Added TOPDIR macro.
+# Change module back from symbol exporting to not.
+#
+# Revision 1.3 1998/06/25 19:25:04 rgb
+# Rearrange to support static linking and objects with exported symbol
+# tables.
+#
+# Revision 1.1 1998/06/18 21:27:42 henry
+# move sources from klips/src to klips/net/ipsec, to keep stupid
+# kernel-build scripts happier in the presence of symlinks
+#
+# Revision 1.3 1998/04/15 23:18:43 rgb
+# Unfixed the ../../libdes fix to avoid messing up Henry's script.
+#
+# Revision 1.2 1998/04/14 17:50:47 rgb
+# Fixed to find the new location of libdes.
+#
+# Revision 1.1 1998/04/09 03:05:22 henry
+# sources moved up from linux/net/ipsec
+# modifications to centralize libdes code
+#
+# Revision 1.1.1.1 1998/04/08 05:35:02 henry
+# RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+#
+# Revision 0.5 1997/06/03 04:24:48 ji
+# Added ESP-3DES-MD5-96
+#
+# Revision 0.4 1997/01/15 01:32:59 ji
+# Added new transforms.
+#
+# Revision 0.3 1996/11/20 14:22:53 ji
+# *** empty log message ***
+#
+#
+# Local Variables:
+# compile-command: "(cd ../../.. && source umlsetup.sh && make -C ${POOLSPACE} module/ipsec.o)"
+# End Variables:
+#
+
diff --git a/linux/net/ipsec/Makefile.algtest b/linux/net/ipsec/Makefile.algtest
new file mode 100644
index 000000000..e68b4ac77
--- /dev/null
+++ b/linux/net/ipsec/Makefile.algtest
@@ -0,0 +1,125 @@
+IPSECVERSION=2.03
+# vim:aw:ai
+#
+# null-patch, non-root GNUmakefile addon for freeswan modules compilation
+#
+# It will not "affect" normal KLIPS building because this GNUmakefile
+# it's not copied to /usr/src/linux
+#
+# Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+# $Id: Makefile.algtest,v 1.2 2004/03/22 21:53:19 as Exp $
+#
+# 1) Copy me to linux/net/ipsec
+# 2)
+# cd klibs/net/ipsec
+# make prep TOPDIR=/path/to/usr/src/linux \
+# [CONFIG=/path/to/.config | CONFIG=/dev/null]
+# 3)
+# make all TOPDIR=.... CONFIG=....
+#CONFIG_IPSEC_ENC_3DES=y
+#CONFIG_IPSEC_AUTH_HMAC_MD5=y
+#CONFIG_IPSEC_AUTH_HMAC_SHA1=y
+CONFIG_IPSEC_ALG_AES=m
+
+ifndef TOPDIR
+$(error You _must_ pass TOPDIR= and optionally CONFIG=)
+endif
+CONFIG=$(TOPDIR)/.config
+include $(CONFIG)
+
+ifdef CONFIG_USERMODE
+ ARCH=um
+endif
+CONFIG_IPSEC=m
+CONFIG_IPSEC_MODULE=y
+CONFIG_IPSEC_IPIP=y
+CONFIG_IPSEC_AH=y
+CONFIG_IPSEC_ESP=y
+CONFIG_IPSEC_ALG=y
+CONFIG_IPSEC_IPCOMP=y
+
+CONFIG_M586 :=$(shell uname -m | sed -n "s/i586/y/p" )
+CONFIG_M686 :=$(shell uname -m | sed -n "s/i686/y/p" )
+export CONFIG_M586 CONFIG_M686
+cflags-arch-$(CONFIG_M586) += -march=i586
+cflags-arch-$(CONFIG_M586_TSC) += -march=i586
+cflags-arch-$(CONFIG_M686) += -march=i686
+cflags-arch-$(CONFIG_MPENTIUMIII) += -march=i686
+cflags-arch-$(CONFIG_MK7) += -march=i686 -malign-functions=4
+CFLAGS_ARCH := $(cflags-arch-y)
+
+ifndef $(CONFIG_SHELL)
+CONFIG_SHELL=/bin/bash
+endif
+export CONFIG_SHELL TOPDIR
+
+ifdef CONFIG_SMP
+EXTRA_CFLAGS += -D__SMP__
+EXTRA_AFLAGS += -D__SMP__
+endif
+
+CFLAGS_IPSEC:=\
+ -DMODVERSIONS \
+ -DCONFIG_IPSEC_MODULE=1\
+ -DCONFIG_IPSEC_IPIP=1\
+ -DCONFIG_IPSEC_AH=1\
+ -DCONFIG_IPSEC_ESP=1\
+ -DCONFIG_IPSEC_IPCOMP=1\
+ -DCONFIG_IPSEC_DEBUG=1 \
+ -DCONFIG_IPSEC_ALG=1 \
+
+# -DCONFIG_IPSEC_DEBUG=1 \
+#
+cflags-ipsec-$(CONFIG_IPSEC_ENC_3DES) += -DCONFIG_IPSEC_ENC_3DES=1
+cflags-ipsec-$(CONFIG_IPSEC_ALG_AES) += -DCONFIG_IPSEC_ALG_AES=1
+cflags-ipsec-$(CONFIG_IPSEC_AUTH_HMAC_MD5)+= -DCONFIG_IPSEC_AUTH_HMAC_MD5=1
+cflags-ipsec-$(CONFIG_IPSEC_AUTH_HMAC_SHA1)+= -DCONFIG_IPSEC_AUTH_HMAC_SHA1=1
+CFLAGS_IPSEC+=$(cflags-ipsec-y)
+export CONFIG_IPSEC
+export CONFIG_IPSEC_MODULE
+
+
+# last bits over CFLAGS ...
+CFLAGS+=$(KINCLUDE) $(CFLAGS_IPSEC) $(CFLAGS_ARCH) $(CFLAGS_KERNEL)
+EXTRA_CFLAGS:=-I$(LOCALKLIPS) -I$(IPSEC_ROOT)/lib
+# libdes options: OPTS1
+OPTS1:=$(CFLAGS) $(EXTRA_CFLAGS)
+export OPTS1 CFLAGS
+
+#include Makefile
+KERNEL_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(CFLAGS)' )
+
+MODULE_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(MODFLAGS)' )
+
+
+ALGO_FLAGS=$(CFLAGS_IPSEC)
+export ALGO_FLAGS
+all: modules alg_modules
+modules:
+ $(MAKE) -C $(TOPDIR) SUBDIRS=$(PWD) modules
+
+ifdef CONFIG_USERMODE
+local_modversions_h:
+ > local_modversions.h
+else
+local_modversions_h:
+ (echo "#ifndef _LINUX_MODVERSIONS_H";\
+ echo "#define _LINUX_MODVERSIONS_H"; \
+ echo "#include <linux/modsetver.h>"; \
+ cd $(TOPDIR)/include/linux/modules; \
+ perl -ne 'print "#define __ver_$$1\t$$2$$3\n#define $$1\t_set_ver($$1)\n" if (/ (.*)_R(smp)?([a-z0-9]{8})\W/);' /proc/ksyms ;\
+ echo "#endif"; \
+ ) > local_modversions.h
+endif
+un_local_modversions_h:
+ @rm -f local_modversions.h
+
+all_alg_modules:
+ (cd alg && \
+ $(MAKE) CC='$(CC)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' \
+ LIBCRYPTO=$(LOCALKLIPS)/../../../lib/libcrypto \
+ all_alg_modules;)
+
+.PHONY: local_modversions_h
+
+
diff --git a/linux/net/ipsec/alg/Config.alg_aes.in b/linux/net/ipsec/alg/Config.alg_aes.in
new file mode 100644
index 000000000..4a2f81a0b
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_aes.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' AES encryption algorithm' CONFIG_IPSEC_ALG_AES
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_blowfish.in b/linux/net/ipsec/alg/Config.alg_blowfish.in
new file mode 100644
index 000000000..a4e5709b0
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_blowfish.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' BLOWFISH encryption algorithm' CONFIG_IPSEC_ALG_BLOWFISH
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_cryptoapi.in b/linux/net/ipsec/alg/Config.alg_cryptoapi.in
new file mode 100644
index 000000000..c2c66eed8
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_cryptoapi.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ dep_tristate ' CRYPTOAPI ciphers support (needs cryptoapi patch)' CONFIG_IPSEC_ALG_CRYPTOAPI $CONFIG_CRYPTO
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_serpent.in b/linux/net/ipsec/alg/Config.alg_serpent.in
new file mode 100644
index 000000000..fb1a88460
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_serpent.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' SERPENT encryption algorithm' CONFIG_IPSEC_ALG_SERPENT
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_sha2.in b/linux/net/ipsec/alg/Config.alg_sha2.in
new file mode 100644
index 000000000..2d26c814b
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_sha2.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' HMAC_SHA2 auth algorithm' CONFIG_IPSEC_ALG_SHA2
+fi
diff --git a/linux/net/ipsec/alg/Config.alg_twofish.in b/linux/net/ipsec/alg/Config.alg_twofish.in
new file mode 100644
index 000000000..13655649d
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.alg_twofish.in
@@ -0,0 +1,3 @@
+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
+ tristate ' TWOFISH encryption algorithm' CONFIG_IPSEC_ALG_TWOFISH
+fi
diff --git a/linux/net/ipsec/alg/Config.in b/linux/net/ipsec/alg/Config.in
new file mode 100644
index 000000000..be5990e3a
--- /dev/null
+++ b/linux/net/ipsec/alg/Config.in
@@ -0,0 +1,7 @@
+#Placeholder
+source net/ipsec/alg/Config.alg_aes.in
+source net/ipsec/alg/Config.alg_blowfish.in
+source net/ipsec/alg/Config.alg_twofish.in
+source net/ipsec/alg/Config.alg_serpent.in
+source net/ipsec/alg/Config.alg_cryptoapi.in
+source net/ipsec/alg/Config.alg_sha2.in
diff --git a/linux/net/ipsec/alg/Makefile b/linux/net/ipsec/alg/Makefile
new file mode 100644
index 000000000..2249668f5
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile
@@ -0,0 +1,112 @@
+# $Id: Makefile,v 1.2 2004/03/22 21:53:19 as Exp $
+ifeq ($(strip $(KLIPSMODULE)),)
+FREESWANSRCDIR=.
+else
+FREESWANSRCDIR=../../../..
+endif
+ifeq ($(strip $(KLIPS_TOP)),)
+KLIPS_TOP=../../..
+override EXTRA_CFLAGS += -I$(KLIPS_TOP)/include
+endif
+
+ifeq ($(CONFIG_IPSEC_DEBUG),y)
+override EXTRA_CFLAGS += -g
+endif
+
+# LIBCRYPTO normally comes as an argument from "parent" Makefile
+# (this applies both to FS' "make module" and eg. Linux' "make modules"
+# But make dep doest follow same evaluations, so we need this default:
+LIBCRYPTO=$(TOPDIR)/lib/libcrypto
+
+override EXTRA_CFLAGS += -I$(LIBCRYPTO)/include
+override EXTRA_CFLAGS += -Wall -Wpointer-arith -Wstrict-prototypes
+
+MOD_LIST_NAME := NET_MISC_MODULES
+
+#O_TARGET := static_init.o
+
+subdir- :=
+subdir-n :=
+subdir-y :=
+subdir-m :=
+
+obj-y := static_init.o
+
+ARCH_ASM-y :=
+ARCH_ASM-$(CONFIG_M586) := i586
+ARCH_ASM-$(CONFIG_M586TSC) := i586
+ARCH_ASM-$(CONFIG_M586MMX) := i586
+ARCH_ASM-$(CONFIG_MK6) := i586
+ARCH_ASM-$(CONFIG_M686) := i686
+ARCH_ASM-$(CONFIG_MPENTIUMIII) := i686
+ARCH_ASM-$(CONFIG_MPENTIUM4) := i686
+ARCH_ASM-$(CONFIG_MK7) := i686
+ARCH_ASM-$(CONFIG_MCRUSOE) := i586
+ARCH_ASM-$(CONFIG_MWINCHIPC6) := i586
+ARCH_ASM-$(CONFIG_MWINCHIP2) := i586
+ARCH_ASM-$(CONFIG_MWINCHIP3D) := i586
+ARCH_ASM-$(CONFIG_USERMODE) := i586
+
+ARCH_ASM :=$(ARCH_ASM-y)
+ifdef NO_ASM
+ARCH_ASM :=
+endif
+
+# The algorithm makefiles may put dependences, short-circuit them
+null:
+
+makefiles=$(filter-out %.preipsec, $(wildcard Makefile.alg_*))
+ifneq ($(makefiles),)
+#include Makefile.alg_aes
+#include Makefile.alg_aes-opt
+include $(makefiles)
+endif
+
+# These rules translate from new to old makefile rules
+# Translate to Rules.make lists.
+multi-used := $(filter $(list-multi), $(obj-y) $(obj-m))
+multi-objs := $(foreach m, $(multi-used), $($(basename $(m))-objs))
+active-objs := $(sort $(multi-objs) $(obj-y) $(obj-m))
+O_OBJS := $(obj-y)
+M_OBJS := $(obj-m)
+MIX_OBJS := $(filter $(export-objs), $(active-objs))
+#OX_OBJS := $(export-objs)
+SUB_DIRS := $(subdir-y)
+ALL_SUB_DIRS := $(subdir-y) $(subdir-m)
+MOD_SUB_DIRS := $(subdir-m)
+
+
+static_init_mod.o: $(obj-y)
+ rm -f $@
+ $(LD) $(LD_EXTRAFLAGS) $(obj-y) -r -o $@
+
+perlasm: $(LIBCRYPTO)/perlasm
+ ln -sf $? $@
+
+$(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h $(KLIPS_TOP)/include/freeswan/ipsec_alg.h
+$(alg_obj-y) $(alg_obj-m): perlasm $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h $(KLIPS_TOP)/include/freeswan/ipsec_alg.h
+
+
+all_alg_modules: perlasm $(ALG_MODULES)
+ @echo "ALG_MODULES=$(ALG_MODULES)"
+
+
+#
+# Construct alg. init. function: call ipsec_ALGO_init() for every static algo
+# Needed when there are static algos (with static or modular ipsec.o)
+#
+static_init.c: $(TOPDIR)/include/linux/autoconf.h Makefile $(makefiles) scripts/mk-static_init.c.sh
+ @echo "Re-creating $@"
+ $(SHELL) scripts/mk-static_init.c.sh $(static_init-func-y) > $@
+
+clean:
+ @for i in $(ALG_SUBDIRS);do test -d $$i && make -C $$i clean;done;exit 0
+ @find . -type l -exec rm -f {} \;
+ -rm -f perlasm
+ -rm -rf $(ALG_SUBDIRS)
+ -rm -f *.o .*.o.flags static_init.c
+
+ifdef TOPDIR
+include $(TOPDIR)/Rules.make
+endif
+
diff --git a/linux/net/ipsec/alg/Makefile.alg_aes b/linux/net/ipsec/alg/Makefile.alg_aes
new file mode 100644
index 000000000..75284c47a
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_aes
@@ -0,0 +1,23 @@
+MOD_AES := ipsec_aes.o
+
+ALG_MODULES += $(MOD_AES)
+ALG_SUBDIRS += libaes
+
+obj-$(CONFIG_IPSEC_ALG_AES) += $(MOD_AES)
+static_init-func-$(CONFIG_IPSEC_ALG_AES)+= ipsec_aes_init
+alg_obj-$(CONFIG_IPSEC_ALG_AES) += ipsec_alg_aes.o
+
+AES_OBJS := ipsec_alg_aes.o libaes/libaes.a
+
+$(MOD_AES): libaes $(AES_OBJS)
+ $(LD) $(EXTRA_LDFLAGS) -r $(AES_OBJS) -o $@
+
+libaes: $(LIBCRYPTO)/libaes
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+ cd $@/asm && ln -sf $?/asm/*.S .
+
+libaes/libaes.a: libaes
+ ( cd libaes && \
+ $(MAKE) CC='$(CC)' 'ARCH_ASM=$(ARCH_ASM)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' libaes.a ;)
diff --git a/linux/net/ipsec/alg/Makefile.alg_blowfish b/linux/net/ipsec/alg/Makefile.alg_blowfish
new file mode 100644
index 000000000..9413a9f1c
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_blowfish
@@ -0,0 +1,23 @@
+MOD_BLOWFISH := ipsec_blowfish.o
+
+ALG_MODULES += $(MOD_BLOWFISH)
+ALG_SUBDIRS += libblowfish
+
+obj-$(CONFIG_IPSEC_ALG_BLOWFISH) += $(MOD_BLOWFISH)
+static_init-func-$(CONFIG_IPSEC_ALG_BLOWFISH)+= ipsec_blowfish_init
+alg_obj-$(CONFIG_IPSEC_ALG_BLOWFISH) += ipsec_alg_blowfish.o
+
+BLOWFISH_OBJS:= ipsec_alg_blowfish.o libblowfish/libblowfish.a
+
+$(MOD_BLOWFISH): libblowfish $(BLOWFISH_OBJS)
+ $(LD) -r $(BLOWFISH_OBJS) -o $@
+
+libblowfish : $(LIBCRYPTO)/libblowfish
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+ cd $@/asm && ln -sf $?/asm/*.pl .
+
+libblowfish/libblowfish.a:
+ ( cd libblowfish && \
+ $(MAKE) CC='$(CC)' 'ARCH_ASM=$(ARCH_ASM)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' EXTRA_CFLAGS='$(EXTRA_CFLAGS)' libblowfish.a ;)
diff --git a/linux/net/ipsec/alg/Makefile.alg_cryptoapi b/linux/net/ipsec/alg/Makefile.alg_cryptoapi
new file mode 100644
index 000000000..77ee6481f
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_cryptoapi
@@ -0,0 +1,14 @@
+MOD_CRYPTOAPI := ipsec_cryptoapi.o
+
+ifneq ($(wildcard $(TOPDIR)/include/linux/crypto.h),)
+ALG_MODULES += $(MOD_CRYPTOAPI)
+obj-$(CONFIG_IPSEC_ALG_CRYPTOAPI) += $(MOD_CRYPTOAPI)
+static_init-func-$(CONFIG_IPSEC_ALG_CRYPTOAPI)+= ipsec_cryptoapi_init
+alg_obj-$(CONFIG_IPSEC_ALG_CRYPTOAPI) += ipsec_alg_cryptoapi.o
+else
+$(warning "Linux CryptoAPI (2.4.22+ or 2.6.x) not found, not building ipsec_cryptoapi.o")
+endif
+
+CRYPTOAPI_OBJS := ipsec_alg_cryptoapi.o
+$(MOD_CRYPTOAPI): $(CRYPTOAPI_OBJS)
+ $(LD) -r $(CRYPTOAPI_OBJS) -o $@
diff --git a/linux/net/ipsec/alg/Makefile.alg_serpent b/linux/net/ipsec/alg/Makefile.alg_serpent
new file mode 100644
index 000000000..1a2383a6a
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_serpent
@@ -0,0 +1,21 @@
+MOD_SERPENT := ipsec_serpent.o
+
+ALG_MODULES += $(MOD_SERPENT)
+ALG_SUBDIRS += libserpent
+
+obj-$(CONFIG_IPSEC_ALG_SERPENT) += $(MOD_SERPENT)
+static_init-func-$(CONFIG_IPSEC_ALG_SERPENT)+= ipsec_serpent_init
+alg_obj-$(CONFIG_IPSEC_ALG_SERPENT) += ipsec_alg_serpent.o
+
+SERPENT_OBJS=ipsec_alg_serpent.o libserpent/libserpent.a
+$(MOD_SERPENT) : libserpent $(SERPENT_OBJS)
+ $(LD) -r $(SERPENT_OBJS) -o $@
+
+libserpent : $(LIBCRYPTO)/libserpent
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+
+libserpent/libserpent.a:
+ ( cd libserpent && \
+ $(MAKE) CC='$(CC)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' EXTRA_CFLAGS='$(EXTRA_CFLAGS)' libserpent.a ;)
diff --git a/linux/net/ipsec/alg/Makefile.alg_sha2 b/linux/net/ipsec/alg/Makefile.alg_sha2
new file mode 100644
index 000000000..956a0f1a3
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_sha2
@@ -0,0 +1,22 @@
+MOD_SHA2 := ipsec_sha2.o
+
+ALG_MODULES += $(MOD_SHA2)
+ALG_SUBDIRS += libsha2
+
+obj-$(CONFIG_IPSEC_ALG_SHA2) += $(MOD_SHA2)
+static_init-func-$(CONFIG_IPSEC_ALG_SHA2)+= ipsec_sha2_init
+alg_obj-$(CONFIG_IPSEC_ALG_SHA2) += ipsec_alg_sha2.o
+
+SHA2_OBJS := ipsec_alg_sha2.o libsha2/libsha2.a
+
+$(MOD_SHA2): libsha2 $(SHA2_OBJS)
+ $(LD) $(EXTRA_LDFLAGS) -r $(SHA2_OBJS) -o $@
+
+libsha2 : $(LIBCRYPTO)/libsha2
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+
+libsha2/libsha2.a:
+ ( cd libsha2 && \
+ $(MAKE) CC='$(CC)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' EXTRA_CFLAGS='$(EXTRA_CFLAGS)' libsha2.a ;)
diff --git a/linux/net/ipsec/alg/Makefile.alg_twofish b/linux/net/ipsec/alg/Makefile.alg_twofish
new file mode 100644
index 000000000..559285ddd
--- /dev/null
+++ b/linux/net/ipsec/alg/Makefile.alg_twofish
@@ -0,0 +1,21 @@
+MOD_TWOFISH := ipsec_twofish.o
+
+ALG_MODULES += $(MOD_TWOFISH)
+ALG_SUBDIRS += libtwofish
+
+obj-$(CONFIG_IPSEC_ALG_TWOFISH) += $(MOD_TWOFISH)
+static_init-func-$(CONFIG_IPSEC_ALG_TWOFISH)+= ipsec_twofish_init
+alg_obj-$(CONFIG_IPSEC_ALG_TWOFISH) += ipsec_alg_twofish.o
+
+TWOFISH_OBJS := ipsec_alg_twofish.o libtwofish/libtwofish.a
+$(MOD_TWOFISH): libtwofish $(TWOFISH_OBJS)
+ $(LD) -r $(TWOFISH_OBJS) -o $@
+
+libtwofish : $(LIBCRYPTO)/libtwofish
+ test -d $@ || mkdir $@ ;exit 0
+ test -d $@/asm || mkdir $@/asm;exit 0
+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
+
+libtwofish/libtwofish.a:
+ ( cd libtwofish && \
+ $(MAKE) CC='$(CC)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' EXTRA_CFLAGS='$(EXTRA_CFLAGS)' libtwofish.a ;)
diff --git a/linux/net/ipsec/alg/ipsec_alg_aes.c b/linux/net/ipsec/alg/ipsec_alg_aes.c
new file mode 100644
index 000000000..c6b390281
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_aes.c
@@ -0,0 +1,253 @@
+/*
+ * ipsec_alg AES cipher stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg_aes.c,v 1.2 2004/03/22 21:53:19 as Exp $
+ *
+ * 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.
+ *
+ * Fixes by:
+ * PK: Pawel Krawczyk <kravietz@aba.krakow.pl>
+ * Fixes list:
+ * PK: make XCBC comply with latest draft (keylength)
+ *
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_AES
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libaes/aes_cbc.h"
+
+#define CONFIG_IPSEC_ALG_AES_MAC 1
+
+#define AES_CONTEXT_T aes_context
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+static int keyminbits=0;
+MODULE_PARM(keyminbits, "i");
+static int keymaxbits=0;
+MODULE_PARM(keymaxbits, "i");
+
+#if CONFIG_IPSEC_ALG_AES_MAC
+#include "libaes/aes_xcbc_mac.h"
+
+/*
+ * Not IANA number yet (draft-ietf-ipsec-ciph-aes-xcbc-mac-00.txt).
+ * We use 9 for non-modular algorithm and none for modular, thus
+ * forcing user to specify one on module load. -kravietz
+ */
+#ifdef MODULE
+static int auth_id=0;
+#else
+static int auth_id=9;
+#endif
+MODULE_PARM(auth_id, "i");
+#endif
+
+#define ESP_AES 12 /* truely _constant_ :) */
+
+/* 128, 192 or 256 */
+#define ESP_AES_KEY_SZ_MIN 16 /* 128 bit secret key */
+#define ESP_AES_KEY_SZ_MAX 32 /* 256 bit secret key */
+#define ESP_AES_CBC_BLK_LEN 16 /* AES-CBC block size */
+
+/* Values according to draft-ietf-ipsec-ciph-aes-xcbc-mac-02.txt
+ * -kravietz
+ */
+#define ESP_AES_MAC_KEY_SZ 16 /* 128 bit MAC key */
+#define ESP_AES_MAC_BLK_LEN 16 /* 128 bit block */
+
+static int _aes_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
+ int ret;
+ AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
+ ret=AES_set_key(ctx, key, keysize)!=0? 0: -EINVAL;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_aes_set_key:"
+ "ret=%d key_e=%p key=%p keysize=%d\n",
+ ret, key_e, key, keysize);
+ return ret;
+}
+static int _aes_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
+ AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_aes_cbc_encrypt:"
+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
+ key_e, in, ilen, iv, encrypt);
+ return AES_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
+}
+#if CONFIG_IPSEC_ALG_AES_MAC
+static int _aes_mac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
+ aes_context_mac *ctxm=(aes_context_mac *)key_a;
+ return AES_xcbc_mac_set_key(ctxm, key, keylen)? 0 : -EINVAL;
+}
+static int _aes_mac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
+ int ret;
+ char hash_buf[16];
+ aes_context_mac *ctxm=(aes_context_mac *)key_a;
+ ret=AES_xcbc_mac_hash(ctxm, dat, len, hash_buf);
+ memcpy(hash, hash_buf, hashlen);
+ return ret;
+}
+static struct ipsec_alg_auth ipsec_alg_AES_MAC = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_AUTH,
+ ixt_alg_id: 0,
+ ixt_name: "aes_mac",
+ ixt_blocksize: ESP_AES_MAC_BLK_LEN,
+ ixt_keyminbits: ESP_AES_MAC_KEY_SZ*8,
+ ixt_keymaxbits: ESP_AES_MAC_KEY_SZ*8,
+ ixt_a_keylen: ESP_AES_MAC_KEY_SZ,
+ ixt_a_ctx_size: sizeof(aes_context_mac),
+ ixt_a_hmac_set_key: _aes_mac_set_key,
+ ixt_a_hmac_hash:_aes_mac_hash,
+};
+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
+static struct ipsec_alg_enc ipsec_alg_AES = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
+ ixt_alg_id: ESP_AES,
+ ixt_name: "aes",
+ ixt_blocksize: ESP_AES_CBC_BLK_LEN,
+ ixt_keyminbits: ESP_AES_KEY_SZ_MIN*8,
+ ixt_keymaxbits: ESP_AES_KEY_SZ_MAX*8,
+ ixt_e_keylen: ESP_AES_KEY_SZ_MAX,
+ ixt_e_ctx_size: sizeof(AES_CONTEXT_T),
+ ixt_e_set_key: _aes_set_key,
+ ixt_e_cbc_encrypt:_aes_cbc_encrypt,
+};
+
+IPSEC_ALG_MODULE_INIT( ipsec_aes_init )
+{
+ int ret, test_ret;
+ if (keyminbits)
+ ipsec_alg_AES.ixt_keyminbits=keyminbits;
+ if (keymaxbits) {
+ ipsec_alg_AES.ixt_keymaxbits=keymaxbits;
+ if (keymaxbits*8>ipsec_alg_AES.ixt_keymaxbits)
+ ipsec_alg_AES.ixt_e_keylen=keymaxbits*8;
+ }
+ if (excl) ipsec_alg_AES.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_enc(&ipsec_alg_AES);
+ printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_AES.ixt_alg_type,
+ ipsec_alg_AES.ixt_alg_id,
+ ipsec_alg_AES.ixt_name,
+ ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_AES.ixt_alg_type,
+ ipsec_alg_AES.ixt_alg_id,
+ test);
+ printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_AES.ixt_alg_type,
+ ipsec_alg_AES.ixt_alg_id,
+ test_ret);
+ }
+#if CONFIG_IPSEC_ALG_AES_MAC
+ if (auth_id!=0){
+ int ret;
+ ipsec_alg_AES_MAC.ixt_alg_id=auth_id;
+ ret=register_ipsec_alg_auth(&ipsec_alg_AES_MAC);
+ printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_AES_MAC.ixt_alg_type,
+ ipsec_alg_AES_MAC.ixt_alg_id,
+ ipsec_alg_AES_MAC.ixt_name,
+ ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_AES_MAC.ixt_alg_type,
+ ipsec_alg_AES_MAC.ixt_alg_id,
+ test);
+ printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_AES_MAC.ixt_alg_type,
+ ipsec_alg_AES_MAC.ixt_alg_id,
+ test_ret);
+ }
+ } else {
+ printk(KERN_DEBUG "klips_debug: experimental ipsec_alg_AES_MAC not registered [Ok] (auth_id=%d)\n", auth_id);
+ }
+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT( ipsec_aes_fini )
+{
+#if CONFIG_IPSEC_ALG_AES_MAC
+ if (auth_id) unregister_ipsec_alg_auth(&ipsec_alg_AES_MAC);
+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
+ unregister_ipsec_alg_enc(&ipsec_alg_AES);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#if 0+NOT_YET
+#ifndef MODULE
+/*
+ * This is intended for static module setups, currently
+ * doesn't work for modular ipsec.o with static algos inside
+ */
+static int setup_keybits(const char *str)
+{
+ unsigned aux;
+ char *end;
+
+ aux = simple_strtoul(str,&end,0);
+ if (aux != 128 && aux != 192 && aux != 256)
+ return 0;
+ keyminbits = aux;
+
+ if (*end == 0 || *end != ',')
+ return 1;
+ str=end+1;
+ aux = simple_strtoul(str, NULL, 0);
+ if (aux != 128 && aux != 192 && aux != 256)
+ return 0;
+ if (aux >= keyminbits)
+ keymaxbits = aux;
+ return 1;
+}
+__setup("ipsec_aes_keybits=", setup_keybits);
+#endif
+#endif
+EXPORT_NO_SYMBOLS;
diff --git a/linux/net/ipsec/alg/ipsec_alg_blowfish.c b/linux/net/ipsec/alg/ipsec_alg_blowfish.c
new file mode 100644
index 000000000..6adc22b22
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_blowfish.c
@@ -0,0 +1,142 @@
+/* ipsec_alg BLOWFISH cipher stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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.
+ *
+ * RCS ID $Id: ipsec_alg_blowfish.c,v 1.3 2004/09/17 18:57:30 as Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_BLOWFISH
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libblowfish/blowfish.h"
+#define blowfish_context BF_KEY
+
+#define ESP_BLOWFISH 7 /* truly _constant_ :) */
+
+#define ESP_BLOWFISH_KEY_SZ_MIN 16 /* 128 bit secret key min */
+#define ESP_BLOWFISH_KEY_SZ 16 /* 128 bit secret key */
+#define ESP_BLOWFISH_KEY_SZ_MAX 56 /* 448 bit secret key max */
+#define ESP_BLOWFISH_CBC_BLK_LEN 8 /* block size */
+
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+static int keyminbits=0;
+MODULE_PARM(keyminbits, "i");
+static int keymaxbits=0;
+MODULE_PARM(keymaxbits, "i");
+
+static int _blowfish_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
+ blowfish_context *ctx=(blowfish_context*)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_blowfish_set_key:"
+ "key_e=%p key=%p keysize=%d\n",
+ key_e, key, keysize);
+ BF_set_key(ctx, keysize, (unsigned char *)key);
+ return 0;
+}
+static int _blowfish_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 *iv, int encrypt) {
+ /* blowfish toasts passed IV */
+ __u8 iv_buf[ESP_BLOWFISH_CBC_BLK_LEN];
+ blowfish_context *ctx=(blowfish_context*)key_e;
+ *((__u32*)&(iv_buf)) = ((__u32*)(iv))[0];
+ *((__u32*)&(iv_buf)+1) = ((__u32*)(iv))[1];
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_blowfish_cbc_encrypt:"
+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
+ key_e, in, ilen, iv_buf, encrypt);
+ BF_cbc_encrypt(in, in, ilen, ctx, iv_buf, encrypt);
+ return ilen;
+}
+static struct ipsec_alg_enc ipsec_alg_BLOWFISH = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
+ ixt_alg_id: ESP_BLOWFISH,
+ ixt_name: "blowfish",
+ ixt_blocksize: ESP_BLOWFISH_CBC_BLK_LEN,
+ ixt_keyminbits: ESP_BLOWFISH_KEY_SZ_MIN*8,
+ ixt_keymaxbits: ESP_BLOWFISH_KEY_SZ_MAX*8,
+ ixt_e_keylen: ESP_BLOWFISH_KEY_SZ,
+ ixt_e_ctx_size: sizeof(blowfish_context),
+ ixt_e_set_key: _blowfish_set_key,
+ ixt_e_cbc_encrypt:_blowfish_cbc_encrypt,
+};
+
+IPSEC_ALG_MODULE_INIT(ipsec_blowfish_init)
+{
+ int ret, test_ret;
+ if (keyminbits)
+ ipsec_alg_BLOWFISH.ixt_keyminbits=keyminbits;
+ if (keymaxbits) {
+ ipsec_alg_BLOWFISH.ixt_keymaxbits=keymaxbits;
+ if (keymaxbits*8>ipsec_alg_BLOWFISH.ixt_keymaxbits)
+ ipsec_alg_BLOWFISH.ixt_e_keylen=keymaxbits*8;
+ }
+ if (excl) ipsec_alg_BLOWFISH.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_enc(&ipsec_alg_BLOWFISH);
+ printk("ipsec_blowfish_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_BLOWFISH.ixt_alg_type,
+ ipsec_alg_BLOWFISH.ixt_alg_id,
+ ipsec_alg_BLOWFISH.ixt_name,
+ ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_BLOWFISH.ixt_alg_type,
+ ipsec_alg_BLOWFISH.ixt_alg_id,
+ test);
+ printk("ipsec_blowfish_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_BLOWFISH.ixt_alg_type,
+ ipsec_alg_BLOWFISH.ixt_alg_id,
+ test_ret);
+ }
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT(ipsec_blowfish_fini)
+{
+ unregister_ipsec_alg_enc(&ipsec_alg_BLOWFISH);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+EXPORT_NO_SYMBOLS;
diff --git a/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c b/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c
new file mode 100644
index 000000000..fc68094c2
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c
@@ -0,0 +1,421 @@
+/*
+ * ipsec_alg to linux cryptoapi GLUE
+ *
+ * Authors: CODE.ar TEAM
+ * Harpo MAxx <harpo@linuxmendoza.org.ar>
+ * JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ * Luciano Ruete <docemeses@softhome.net>
+ *
+ * $Id: ipsec_alg_cryptoapi.c,v 1.3 2004/09/17 18:57:30 as Exp $
+ *
+ * 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.
+ *
+ * Example usage:
+ * modinfo -p ipsec_cryptoapi (quite useful info, including supported algos)
+ * modprobe ipsec_cryptoapi
+ * modprobe ipsec_cryptoapi test=1
+ * modprobe ipsec_cryptoapi excl=1 (exclusive cipher/algo)
+ * modprobe ipsec_cryptoapi noauto=1 aes=1 twofish=1 (only these ciphers)
+ * modprobe ipsec_cryptoapi aes=128,128 (force these keylens)
+ * modprobe ipsec_cryptoapi des_ede3=0 (everything but 3DES)
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_CRYPTOAPI
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* warn the innocent */
+#if !defined (CONFIG_CRYPTO) && !defined (CONFIG_CRYPTO_MODULE)
+#warning "No linux CryptoAPI found, install 2.4.22+ or 2.6.x"
+#define NO_CRYPTOAPI_SUPPORT
+#endif
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+
+#include <linux/crypto.h>
+#ifdef CRYPTO_API_VERSION_CODE
+#warning "Old CryptoAPI is not supported. Only linux-2.4.22+ or linux-2.6.x are supported"
+#define NO_CRYPTOAPI_SUPPORT
+#endif
+
+#ifdef NO_CRYPTOAPI_SUPPORT
+#warning "Building an unusable module :P"
+/* Catch old CryptoAPI by not allowing module to load */
+IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
+{
+ printk(KERN_WARNING "ipsec_cryptoapi.o was not built on stock Linux CryptoAPI (2.4.22+ or 2.6.x), not loading.\n");
+ return -EINVAL;
+}
+#else
+#include <asm/scatterlist.h>
+#include <asm/pgtable.h>
+#include <linux/mm.h>
+
+#define CIPHERNAME_AES "aes"
+#define CIPHERNAME_3DES "des3_ede"
+#define CIPHERNAME_BLOWFISH "blowfish"
+#define CIPHERNAME_CAST "cast5"
+#define CIPHERNAME_SERPENT "serpent"
+#define CIPHERNAME_TWOFISH "twofish"
+
+#define ESP_3DES 3
+#define ESP_AES 12
+#define ESP_BLOWFISH 7 /* truly _constant_ :) */
+#define ESP_CAST 6 /* quite constant :) */
+#define ESP_SERPENT 252 /* from ipsec drafts */
+#define ESP_TWOFISH 253 /* from ipsec drafts */
+
+#define AH_MD5 2
+#define AH_SHA 3
+#define DIGESTNAME_MD5 "md5"
+#define DIGESTNAME_SHA1 "sha1"
+
+MODULE_AUTHOR("Juanjo Ciarlante, Harpo MAxx, Luciano Ruete");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+
+static int noauto = 0;
+MODULE_PARM(noauto,"i");
+MODULE_PARM_DESC(noauto, "Dont try all known algos, just setup enabled ones");
+
+static int des_ede3[] = {-1, -1};
+static int aes[] = {-1, -1};
+static int blowfish[] = {-1, -1};
+static int cast[] = {-1, -1};
+static int serpent[] = {-1, -1};
+static int twofish[] = {-1, -1};
+
+MODULE_PARM(des_ede3,"1-2i");
+MODULE_PARM(aes,"1-2i");
+MODULE_PARM(blowfish,"1-2i");
+MODULE_PARM(cast,"1-2i");
+MODULE_PARM(serpent,"1-2i");
+MODULE_PARM(twofish,"1-2i");
+MODULE_PARM_DESC(des_ede3, "0: disable | 1: force_enable | min,max: dontuse");
+MODULE_PARM_DESC(aes, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(blowfish, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(cast, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(serpent, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(twofish, "0: disable | 1: force_enable | min,max: keybitlens");
+
+struct ipsec_alg_capi_cipher {
+ const char *ciphername; /* cryptoapi's ciphername */
+ unsigned blocksize;
+ unsigned short minbits;
+ unsigned short maxbits;
+ int *parm; /* lkm param for this cipher */
+ struct ipsec_alg_enc alg; /* note it's not a pointer */
+};
+static struct ipsec_alg_capi_cipher alg_capi_carray[] = {
+ { CIPHERNAME_AES , 16, 128, 256, aes , { ixt_alg_id: ESP_AES, }},
+ { CIPHERNAME_TWOFISH , 16, 128, 256, twofish, { ixt_alg_id: ESP_TWOFISH, }},
+ { CIPHERNAME_SERPENT , 16, 128, 256, serpent, { ixt_alg_id: ESP_SERPENT, }},
+ { CIPHERNAME_CAST , 8, 128, 128, cast , { ixt_alg_id: ESP_CAST, }},
+ { CIPHERNAME_BLOWFISH , 8, 128, 448, blowfish,{ ixt_alg_id: ESP_BLOWFISH, }},
+ { CIPHERNAME_3DES , 8, 192, 192, des_ede3,{ ixt_alg_id: ESP_3DES, }},
+ { NULL, 0, 0, 0, NULL, {} }
+};
+#ifdef NOT_YET
+struct ipsec_alg_capi_digest {
+ const char *digestname; /* cryptoapi's digestname */
+ struct digest_implementation *di;
+ struct ipsec_alg_auth alg; /* note it's not a pointer */
+};
+static struct ipsec_alg_capi_cipher alg_capi_darray[] = {
+ { DIGESTNAME_MD5, NULL, { ixt_alg_id: AH_MD5, }},
+ { DIGESTNAME_SHA1, NULL, { ixt_alg_id: AH_SHA, }},
+ { NULL, NULL, {} }
+};
+#endif
+/*
+ * "generic" linux cryptoapi setup_cipher() function
+ */
+int setup_cipher(const char *ciphername)
+{
+ return crypto_alg_available(ciphername, 0);
+}
+
+/*
+ * setups ipsec_alg_capi_cipher "hyper" struct components, calling
+ * register_ipsec_alg for cointaned ipsec_alg object
+ */
+static void _capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e);
+static __u8 * _capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen);
+static int _capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt);
+
+static int
+setup_ipsec_alg_capi_cipher(struct ipsec_alg_capi_cipher *cptr)
+{
+ int ret;
+ cptr->alg.ixt_version = IPSEC_ALG_VERSION;
+ cptr->alg.ixt_module = THIS_MODULE;
+ atomic_set (& cptr->alg.ixt_refcnt, 0);
+ strncpy (cptr->alg.ixt_name , cptr->ciphername, sizeof (cptr->alg.ixt_name));
+
+ cptr->alg.ixt_blocksize=cptr->blocksize;
+ cptr->alg.ixt_keyminbits=cptr->minbits;
+ cptr->alg.ixt_keymaxbits=cptr->maxbits;
+ cptr->alg.ixt_state = 0;
+ if (excl) cptr->alg.ixt_state |= IPSEC_ALG_ST_EXCL;
+ cptr->alg.ixt_e_keylen=cptr->alg.ixt_keymaxbits/8;
+ cptr->alg.ixt_e_ctx_size = 0;
+ cptr->alg.ixt_alg_type = IPSEC_ALG_TYPE_ENCRYPT;
+ cptr->alg.ixt_e_new_key = _capi_new_key;
+ cptr->alg.ixt_e_destroy_key = _capi_destroy_key;
+ cptr->alg.ixt_e_cbc_encrypt = _capi_cbc_encrypt;
+ cptr->alg.ixt_data = cptr;
+
+ ret=register_ipsec_alg_enc(&cptr->alg);
+ printk("setup_ipsec_alg_capi_cipher(): "
+ "alg_type=%d alg_id=%d name=%s "
+ "keyminbits=%d keymaxbits=%d, ret=%d\n",
+ cptr->alg.ixt_alg_type,
+ cptr->alg.ixt_alg_id,
+ cptr->alg.ixt_name,
+ cptr->alg.ixt_keyminbits,
+ cptr->alg.ixt_keymaxbits,
+ ret);
+ return ret;
+}
+/*
+ * called in ipsec_sa_wipe() time, will destroy key contexts
+ * and do 1 unbind()
+ */
+static void
+_capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e)
+{
+ struct crypto_tfm *tfm=(struct crypto_tfm*)key_e;
+
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _capi_destroy_key:"
+ "name=%s key_e=%p \n",
+ alg->ixt_name, key_e);
+ if (!key_e) {
+ printk(KERN_ERR "klips_debug: _capi_destroy_key:"
+ "name=%s NULL key_e!\n",
+ alg->ixt_name);
+ return;
+ }
+ crypto_free_tfm(tfm);
+}
+
+/*
+ * create new key context, need alg->ixt_data to know which
+ * (of many) cipher inside this module is the target
+ */
+static __u8 *
+_capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen)
+{
+ struct ipsec_alg_capi_cipher *cptr;
+ struct crypto_tfm *tfm=NULL;
+
+ cptr = alg->ixt_data;
+ if (!cptr) {
+ printk(KERN_ERR "_capi_new_key(): "
+ "NULL ixt_data (?!) for \"%s\" algo\n"
+ , alg->ixt_name);
+ goto err;
+ }
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
+ "name=%s cptr=%p key=%p keysize=%d\n",
+ alg->ixt_name, cptr, key, keylen);
+
+ /*
+ * alloc tfm
+ */
+ tfm = crypto_alloc_tfm(cptr->ciphername, CRYPTO_TFM_MODE_CBC);
+ if (!tfm) {
+ printk(KERN_ERR "_capi_new_key(): "
+ "NULL tfm for \"%s\" cryptoapi (\"%s\") algo\n"
+ , alg->ixt_name, cptr->ciphername);
+ goto err;
+ }
+ if (crypto_cipher_setkey(tfm, key, keylen) < 0) {
+ printk(KERN_ERR "_capi_new_key(): "
+ "failed new_key() for \"%s\" cryptoapi algo (keylen=%d)\n"
+ , alg->ixt_name, keylen);
+ crypto_free_tfm(tfm);
+ tfm=NULL;
+ }
+err:
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
+ "name=%s key=%p keylen=%d tfm=%p\n",
+ alg->ixt_name, key, keylen, tfm);
+ return (__u8 *) tfm;
+}
+/*
+ * core encryption function: will use cx->ci to call actual cipher's
+ * cbc function
+ */
+static int
+_capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
+ int error =0;
+ struct crypto_tfm *tfm=(struct crypto_tfm *)key_e;
+ struct scatterlist sg = {
+ .page = virt_to_page(in),
+ .offset = (unsigned long)(in) % PAGE_SIZE,
+ .length=ilen,
+ };
+ if (debug > 1)
+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
+ "key_e=%p "
+ "in=%p out=%p ilen=%d iv=%p encrypt=%d\n"
+ , key_e
+ , in, in, ilen, iv, encrypt);
+ crypto_cipher_set_iv(tfm, iv, crypto_tfm_alg_ivsize(tfm));
+ if (encrypt)
+ error = crypto_cipher_encrypt (tfm, &sg, &sg, ilen);
+ else
+ error = crypto_cipher_decrypt (tfm, &sg, &sg, ilen);
+ if (debug > 1)
+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
+ "error=%d\n"
+ , error);
+ return (error<0)? error : ilen;
+}
+/*
+ * main initialization loop: for each cipher in list, do
+ * 1) setup cryptoapi cipher else continue
+ * 2) register ipsec_alg object
+ */
+static int
+setup_cipher_list (struct ipsec_alg_capi_cipher* clist)
+{
+ struct ipsec_alg_capi_cipher *cptr;
+ /* foreach cipher in list ... */
+ for (cptr=clist;cptr->ciphername;cptr++) {
+ /*
+ * see if cipher has been disabled (0) or
+ * if noauto set and not enabled (1)
+ */
+ if (cptr->parm[0] == 0 || (noauto && cptr->parm[0] < 0)) {
+ if (debug>0)
+ printk(KERN_INFO "setup_cipher_list(): "
+ "ciphername=%s skipped at user request: "
+ "noauto=%d parm[0]=%d parm[1]=%d\n"
+ , cptr->ciphername
+ , noauto
+ , cptr->parm[0]
+ , cptr->parm[1]);
+ continue;
+ }
+ /*
+ * use a local ci to avoid touching cptr->ci,
+ * if register ipsec_alg success then bind cipher
+ */
+ if( setup_cipher(cptr->ciphername) ) {
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:"
+ "setup_cipher_list():"
+ "ciphername=%s found\n"
+ , cptr->ciphername);
+ if (setup_ipsec_alg_capi_cipher(cptr) == 0) {
+
+
+ } else {
+ printk(KERN_ERR "klips_debug:"
+ "setup_cipher_list():"
+ "ciphername=%s failed ipsec_alg_register\n"
+ , cptr->ciphername);
+ }
+ } else {
+ if (debug>0)
+ printk(KERN_INFO "setup_cipher_list(): lookup for ciphername=%s: not found \n",
+ cptr->ciphername);
+ }
+ }
+ return 0;
+}
+/*
+ * deregister ipsec_alg objects and unbind ciphers
+ */
+static int
+unsetup_cipher_list (struct ipsec_alg_capi_cipher* clist)
+{
+ struct ipsec_alg_capi_cipher *cptr;
+ /* foreach cipher in list ... */
+ for (cptr=clist;cptr->ciphername;cptr++) {
+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
+ unregister_ipsec_alg_enc(&cptr->alg);
+ }
+ }
+ return 0;
+}
+/*
+ * test loop for registered algos
+ */
+static int
+test_cipher_list (struct ipsec_alg_capi_cipher* clist)
+{
+ int test_ret;
+ struct ipsec_alg_capi_cipher *cptr;
+ /* foreach cipher in list ... */
+ for (cptr=clist;cptr->ciphername;cptr++) {
+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
+ test_ret=ipsec_alg_test(
+ cptr->alg.ixt_alg_type,
+ cptr->alg.ixt_alg_id,
+ test);
+ printk("test_cipher_list(alg_type=%d alg_id=%d): test_ret=%d\n",
+ cptr->alg.ixt_alg_type,
+ cptr->alg.ixt_alg_id,
+ test_ret);
+ }
+ }
+ return 0;
+}
+
+IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
+{
+ int ret, test_ret;
+ if ((ret=setup_cipher_list(alg_capi_carray)) < 0)
+ return -EPROTONOSUPPORT;
+ if (ret==0 && test) {
+ test_ret=test_cipher_list(alg_capi_carray);
+ }
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT( ipsec_cryptoapi_fini )
+{
+ unsetup_cipher_list(alg_capi_carray);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+EXPORT_NO_SYMBOLS;
+#endif /* NO_CRYPTOAPI_SUPPORT */
diff --git a/linux/net/ipsec/alg/ipsec_alg_serpent.c b/linux/net/ipsec/alg/ipsec_alg_serpent.c
new file mode 100644
index 000000000..1f26b0b01
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_serpent.c
@@ -0,0 +1,139 @@
+/*
+ * ipsec_alg SERPENT cipher stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg_serpent.c,v 1.2 2004/03/22 21:53:19 as Exp $
+ *
+ * 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.
+ *
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_SERPENT
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libserpent/serpent.h"
+#include "libserpent/serpent_cbc.h"
+
+#define ESP_SERPENT 252 /* from ipsec drafts */
+
+/* 128, 192 or 256 */
+#define ESP_SERPENT_KEY_SZ_MIN 16 /* 128 bit secret key */
+#define ESP_SERPENT_KEY_SZ_MAX 32 /* 256 bit secret key */
+#define ESP_SERPENT_CBC_BLK_LEN 16 /* SERPENT-CBC block size */
+
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+static int keyminbits=0;
+MODULE_PARM(keyminbits, "i");
+static int keymaxbits=0;
+MODULE_PARM(keymaxbits, "i");
+
+static int _serpent_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
+ serpent_context *ctx=(serpent_context *)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_serpent_set_key:"
+ "key_e=%p key=%p keysize=%d\n",
+ key_e, key, keysize);
+ serpent_set_key(ctx, key, keysize);
+ return 0;
+}
+static int _serpent_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
+ serpent_context *ctx=(serpent_context *)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_serpent_cbc_encrypt:"
+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
+ key_e, in, ilen, iv, encrypt);
+ serpent_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
+ return ilen;
+}
+static struct ipsec_alg_enc ipsec_alg_SERPENT = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
+ ixt_alg_id: ESP_SERPENT,
+ ixt_name: "serpent",
+ ixt_blocksize: ESP_SERPENT_CBC_BLK_LEN,
+ ixt_keyminbits: ESP_SERPENT_KEY_SZ_MIN * 8,
+ ixt_keymaxbits: ESP_SERPENT_KEY_SZ_MAX * 8,
+ ixt_e_keylen: ESP_SERPENT_KEY_SZ_MAX,
+ ixt_e_ctx_size: sizeof(serpent_context),
+ ixt_e_set_key: _serpent_set_key,
+ ixt_e_cbc_encrypt:_serpent_cbc_encrypt,
+};
+
+IPSEC_ALG_MODULE_INIT(ipsec_serpent_init)
+{
+ int ret, test_ret;
+ if (keyminbits)
+ ipsec_alg_SERPENT.ixt_keyminbits=keyminbits;
+ if (keymaxbits) {
+ ipsec_alg_SERPENT.ixt_keymaxbits=keymaxbits;
+ if (keymaxbits*8>ipsec_alg_SERPENT.ixt_keymaxbits)
+ ipsec_alg_SERPENT.ixt_e_keylen=keymaxbits*8;
+ }
+ if (excl) ipsec_alg_SERPENT.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_enc(&ipsec_alg_SERPENT);
+ printk("ipsec_serpent_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_SERPENT.ixt_alg_type,
+ ipsec_alg_SERPENT.ixt_alg_id,
+ ipsec_alg_SERPENT.ixt_name,
+ ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_SERPENT.ixt_alg_type,
+ ipsec_alg_SERPENT.ixt_alg_id,
+ test);
+ printk("ipsec_serpent_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_SERPENT.ixt_alg_type,
+ ipsec_alg_SERPENT.ixt_alg_id,
+ test_ret);
+ }
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT(ipsec_serpent_fini)
+{
+ unregister_ipsec_alg_enc(&ipsec_alg_SERPENT);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+EXPORT_NO_SYMBOLS;
diff --git a/linux/net/ipsec/alg/ipsec_alg_sha2.c b/linux/net/ipsec/alg/ipsec_alg_sha2.c
new file mode 100644
index 000000000..548585c16
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_sha2.c
@@ -0,0 +1,185 @@
+/*
+ * ipsec_alg SHA2 hash stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg_sha2.c,v 1.2 2004/03/22 21:53:19 as Exp $
+ *
+ * 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.
+ *
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_SHA2
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libsha2/sha2.h"
+#include "libsha2/hmac_sha2.h"
+
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+
+/* almost constants ...: draft-ietf-ipsec-ciph-aes-cbc-03.txt */
+#define AH_SHA2_256 5
+#define AH_SHA2_384 6
+#define AH_SHA2_512 7
+
+static int _sha256_hmac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
+ sha256_hmac_context *hctx=(sha256_hmac_context*)(key_a);
+ sha256_hmac_set_key(hctx, key, keylen);
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _sha256_hmac_set_key(): "
+ "key_a=%p key=%p keysize=%d\n",
+ key_a, key, keylen);
+ return 0;
+}
+static int _sha256_hmac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
+ sha256_hmac_context *hctx=(sha256_hmac_context*)(key_a);
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _sha256_hmac_hash(): "
+ "key_a=%p dat=%p len=%d hash=%p hashlen=%d\n",
+ key_a, dat, len, hash, hashlen);
+ sha256_hmac_hash(hctx, dat, len, hash, hashlen);
+ return 0;
+}
+static int _sha512_hmac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
+ sha512_hmac_context *hctx=(sha512_hmac_context*)(key_a);
+ sha512_hmac_set_key(hctx, key, keylen);
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _sha512_hmac_set_key(): "
+ "key_a=%p key=%p keysize=%d\n",
+ key_a, key, keylen);
+ return 0;
+}
+static int _sha512_hmac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
+ sha512_hmac_context *hctx=(sha512_hmac_context*)(key_a);
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _sha512_hmac_hash(): "
+ "key_a=%p dat=%p len=%d hash=%p hashlen=%d\n",
+ key_a, dat, len, hash, hashlen);
+ sha512_hmac_hash(hctx, dat, len, hash, hashlen);
+ return 0;
+}
+static struct ipsec_alg_auth ipsec_alg_SHA2_256 = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_AUTH,
+ ixt_alg_id: AH_SHA2_256,
+ ixt_name: "sha2_256",
+ ixt_blocksize: SHA256_BLOCKSIZE,
+ ixt_keyminbits: 256,
+ ixt_keymaxbits: 256,
+ ixt_a_keylen: 256/8,
+ ixt_a_ctx_size: sizeof(sha256_hmac_context),
+ ixt_a_hmac_set_key: _sha256_hmac_set_key,
+ ixt_a_hmac_hash: _sha256_hmac_hash,
+};
+static struct ipsec_alg_auth ipsec_alg_SHA2_512 = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_AUTH,
+ ixt_alg_id: AH_SHA2_512,
+ ixt_name: "sha2_512",
+ ixt_blocksize: SHA512_BLOCKSIZE,
+ ixt_keyminbits: 512,
+ ixt_keymaxbits: 512,
+ ixt_a_keylen: 512/8,
+ ixt_a_ctx_size: sizeof(sha512_hmac_context),
+ ixt_a_hmac_set_key: _sha512_hmac_set_key,
+ ixt_a_hmac_hash: _sha512_hmac_hash,
+};
+
+IPSEC_ALG_MODULE_INIT( ipsec_sha2_init )
+{
+ int ret, test_ret;
+ if (excl) ipsec_alg_SHA2_256.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_auth(&ipsec_alg_SHA2_256);
+ printk("ipsec_sha2_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_SHA2_256.ixt_alg_type,
+ ipsec_alg_SHA2_256.ixt_alg_id,
+ ipsec_alg_SHA2_256.ixt_name,
+ ret);
+ if (ret != 0)
+ goto out;
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_SHA2_256.ixt_alg_type,
+ ipsec_alg_SHA2_256.ixt_alg_id,
+ test);
+ printk("ipsec_sha2_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_SHA2_256.ixt_alg_type,
+ ipsec_alg_SHA2_256.ixt_alg_id,
+ test_ret);
+ }
+ if (excl) ipsec_alg_SHA2_512.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_auth(&ipsec_alg_SHA2_512);
+ printk("ipsec_sha2_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_SHA2_512.ixt_alg_type,
+ ipsec_alg_SHA2_512.ixt_alg_id,
+ ipsec_alg_SHA2_512.ixt_name,
+ ret);
+ if (ret != 0)
+ goto out_256;
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_SHA2_512.ixt_alg_type,
+ ipsec_alg_SHA2_512.ixt_alg_id,
+ test);
+ printk("ipsec_sha2_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_SHA2_512.ixt_alg_type,
+ ipsec_alg_SHA2_512.ixt_alg_id,
+ test_ret);
+ }
+ goto out;
+out_256:
+ unregister_ipsec_alg_auth(&ipsec_alg_SHA2_256);
+out:
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT( ipsec_sha2_fini )
+{
+ unregister_ipsec_alg_auth(&ipsec_alg_SHA2_512);
+ unregister_ipsec_alg_auth(&ipsec_alg_SHA2_256);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+EXPORT_NO_SYMBOLS;
diff --git a/linux/net/ipsec/alg/ipsec_alg_twofish.c b/linux/net/ipsec/alg/ipsec_alg_twofish.c
new file mode 100644
index 000000000..dfeba1f1b
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_twofish.c
@@ -0,0 +1,138 @@
+/*
+ * ipsec_alg TWOFISH cipher stubs
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg_twofish.c,v 1.2 2004/03/22 21:53:19 as Exp $
+ *
+ * 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.
+ *
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_TWOFISH
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+#include "libtwofish/twofish.h"
+#include "libtwofish/twofish_cbc.h"
+
+#define ESP_TWOFISH 253 /* from ipsec drafts */
+
+/* 128, 192 or 256 */
+#define ESP_TWOFISH_KEY_SZ_MIN 16 /* 128 bit secret key */
+#define ESP_TWOFISH_KEY_SZ_MAX 32 /* 256 bit secret key */
+#define ESP_TWOFISH_CBC_BLK_LEN 16 /* TWOFISH-CBC block size */
+
+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+static int keyminbits=0;
+MODULE_PARM(keyminbits, "i");
+static int keymaxbits=0;
+MODULE_PARM(keymaxbits, "i");
+
+static int _twofish_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
+ twofish_context *ctx=(twofish_context *)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_twofish_set_key:"
+ "key_e=%p key=%p keysize=%d\n",
+ key_e, key, keysize);
+ twofish_set_key(ctx, key, keysize);
+ return 0;
+}
+static int _twofish_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
+ twofish_context *ctx=(twofish_context *)key_e;
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_twofish_cbc_encrypt:"
+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
+ key_e, in, ilen, iv, encrypt);
+ twofish_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
+ return ilen;
+}
+static struct ipsec_alg_enc ipsec_alg_TWOFISH = {
+ ixt_version: IPSEC_ALG_VERSION,
+ ixt_module: THIS_MODULE,
+ ixt_refcnt: ATOMIC_INIT(0),
+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
+ ixt_alg_id: ESP_TWOFISH,
+ ixt_name: "twofish",
+ ixt_blocksize: ESP_TWOFISH_CBC_BLK_LEN,
+ ixt_keyminbits: ESP_TWOFISH_KEY_SZ_MIN * 8,
+ ixt_keymaxbits: ESP_TWOFISH_KEY_SZ_MAX * 8,
+ ixt_e_keylen: ESP_TWOFISH_KEY_SZ_MAX,
+ ixt_e_ctx_size: sizeof(twofish_context),
+ ixt_e_set_key: _twofish_set_key,
+ ixt_e_cbc_encrypt:_twofish_cbc_encrypt,
+};
+
+IPSEC_ALG_MODULE_INIT( ipsec_twofish_init )
+{
+ int ret, test_ret;
+ if (keyminbits)
+ ipsec_alg_TWOFISH.ixt_keyminbits=keyminbits;
+ if (keymaxbits) {
+ ipsec_alg_TWOFISH.ixt_keymaxbits=keymaxbits;
+ if (keymaxbits*8>ipsec_alg_TWOFISH.ixt_keymaxbits)
+ ipsec_alg_TWOFISH.ixt_e_keylen=keymaxbits*8;
+ }
+ if (excl) ipsec_alg_TWOFISH.ixt_state |= IPSEC_ALG_ST_EXCL;
+ ret=register_ipsec_alg_enc(&ipsec_alg_TWOFISH);
+ printk("ipsec_twofish_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
+ ipsec_alg_TWOFISH.ixt_alg_type,
+ ipsec_alg_TWOFISH.ixt_alg_id,
+ ipsec_alg_TWOFISH.ixt_name, ret);
+ if (ret==0 && test) {
+ test_ret=ipsec_alg_test(
+ ipsec_alg_TWOFISH.ixt_alg_type,
+ ipsec_alg_TWOFISH.ixt_alg_id,
+ test);
+ printk("ipsec_twofish_init(alg_type=%d alg_id=%d): test_ret=%d\n",
+ ipsec_alg_TWOFISH.ixt_alg_type,
+ ipsec_alg_TWOFISH.ixt_alg_id,
+ ret);
+ }
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT( ipsec_twofish_fini )
+{
+ unregister_ipsec_alg_enc(&ipsec_alg_TWOFISH);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+#endif
diff --git a/linux/net/ipsec/alg/scripts/mk-static_init.c.sh b/linux/net/ipsec/alg/scripts/mk-static_init.c.sh
new file mode 100644
index 000000000..8a17c670e
--- /dev/null
+++ b/linux/net/ipsec/alg/scripts/mk-static_init.c.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+cat << EOF
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include "freeswan/ipsec_alg.h"
+$(for i in $*; do
+ test -z "$i" && continue
+ echo "extern int $i(void);"
+done)
+void ipsec_alg_static_init(void){
+ int __attribute__ ((unused)) err=0;
+$(for i in $*; do
+ test -z "$i" && continue
+ echo " if ((err=$i()) < 0)"
+ echo " printk(KERN_WARNING \"$i() returned %d\", err);"
+done)
+}
+EOF
diff --git a/linux/net/ipsec/defconfig b/linux/net/ipsec/defconfig
new file mode 100644
index 000000000..84be04318
--- /dev/null
+++ b/linux/net/ipsec/defconfig
@@ -0,0 +1,140 @@
+
+#
+# RCSID $Id: defconfig,v 1.2 2004/03/22 21:53:19 as Exp $
+#
+
+#
+# FreeS/WAN IPSec implementation, KLIPS kernel config defaults
+#
+
+#
+# First, lets override stuff already set or not in the kernel config.
+#
+# We can't even think about leaving this off...
+CONFIG_INET=y
+
+#
+# This must be on for subnet protection.
+CONFIG_IP_FORWARD=y
+
+# Shut off IPSEC masquerading if it has been enabled, since it will
+# break the compile. IPPROTO_ESP and IPPROTO_AH were included in
+# net/ipv4/ip_masq.c when they should have gone into include/linux/in.h.
+CONFIG_IP_MASQUERADE_IPSEC=n
+
+#
+# Next, lets set the recommended FreeS/WAN configuration.
+#
+
+# To config as static (preferred), 'y'. To config as module, 'm'.
+CONFIG_IPSEC=y
+
+# To do tunnel mode IPSec, this must be enabled.
+CONFIG_IPSEC_IPIP=y
+
+# To enable authentication, say 'y'. (Highly recommended)
+CONFIG_IPSEC_AH=y
+
+# Authentication algorithm(s):
+CONFIG_IPSEC_AUTH_HMAC_MD5=y
+CONFIG_IPSEC_AUTH_HMAC_SHA1=y
+
+# To enable encryption, say 'y'. (Highly recommended)
+CONFIG_IPSEC_ESP=y
+
+# Encryption algorithm(s):
+CONFIG_IPSEC_ENC_3DES=y
+
+# modular algo extensions (and new ALGOs)
+CONFIG_IPSEC_ALG=y
+CONFIG_IPSEC_ALG_3DES=m
+CONFIG_IPSEC_ALG_AES=m
+CONFIG_IPSEC_ALG_TWOFISH=m
+CONFIG_IPSEC_ALG_BLOWFISH=m
+CONFIG_IPSEC_ALG_SERPENT=m
+CONFIG_IPSEC_ALG_MD5=m
+CONFIG_IPSEC_ALG_SHA1=m
+CONFIG_IPSEC_ALG_SHA2=m
+#CONFIG_IPSEC_ALG_CAST=n
+#CONFIG_IPSEC_ALG_NULL=n
+
+# Use CryptoAPI for ALG?
+CONFIG_IPSEC_ALG_CRYPTOAPI=m
+
+
+# IP Compression: new, probably still has minor bugs.
+CONFIG_IPSEC_IPCOMP=y
+
+# To enable userspace-switchable KLIPS debugging, say 'y'.
+CONFIG_IPSEC_DEBUG=y
+
+# NAT Traversal
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+
+#
+#
+# $Log: defconfig,v $
+# Revision 1.2 2004/03/22 21:53:19 as
+# merged alg-0.8.1 branch with HEAD
+#
+# Revision 1.1.2.1.2.1 2004/03/16 09:48:19 as
+# alg-0.8.1rc12 patch merged
+#
+# Revision 1.1.2.1 2004/03/15 22:30:06 as
+# nat-0.6c patch merged
+#
+# Revision 1.1 2004/03/15 20:35:26 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.22 2003/02/24 19:37:27 mcr
+# changed default compilation mode to static.
+#
+# Revision 1.21 2002/04/24 07:36:27 mcr
+# Moved from ./klips/net/ipsec/defconfig,v
+#
+# Revision 1.20 2002/04/02 04:07:40 mcr
+# default build is now 'm'odule for KLIPS
+#
+# Revision 1.19 2002/03/08 18:57:17 rgb
+# Added a blank line at the beginning of the file to make it easier for
+# other projects to patch ./arch/i386/defconfig, for example
+# LIDS+grSecurity requested by Jason Pattie.
+#
+# Revision 1.18 2000/11/30 17:26:56 rgb
+# Cleaned out unused options and enabled ipcomp by default.
+#
+# Revision 1.17 2000/09/15 11:37:01 rgb
+# Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+# IPCOMP zlib deflate code.
+#
+# Revision 1.16 2000/09/08 19:12:55 rgb
+# Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+#
+# Revision 1.15 2000/05/24 19:37:13 rgb
+# *** empty log message ***
+#
+# Revision 1.14 2000/05/11 21:14:57 henry
+# just commenting the FOOBAR=y lines out is not enough
+#
+# Revision 1.13 2000/05/10 20:17:58 rgb
+# Comment out netlink defaults, which are no longer needed.
+#
+# Revision 1.12 2000/05/10 19:13:38 rgb
+# Added configure option to shut off no eroute passthrough.
+#
+# Revision 1.11 2000/03/16 07:09:46 rgb
+# Hardcode PF_KEYv2 support.
+# Disable IPSEC_ICMP by default.
+# Remove DES config option from defaults file.
+#
+# Revision 1.10 2000/01/11 03:09:42 rgb
+# Added a default of 'y' to PF_KEYv2 keying I/F.
+#
+# Revision 1.9 1999/05/08 21:23:12 rgb
+# Added support for 2.2.x kernels.
+#
+# Revision 1.8 1999/04/06 04:54:25 rgb
+# Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+# patch shell fixes.
+#
+#
diff --git a/linux/net/ipsec/ipcomp.c b/linux/net/ipsec/ipcomp.c
new file mode 100644
index 000000000..ff12f2cdd
--- /dev/null
+++ b/linux/net/ipsec/ipcomp.c
@@ -0,0 +1,725 @@
+/*
+ * IPCOMP zlib interface code.
+ * Copyright (C) 2000 Svenning Soerensen <svenning@post5.tele.dk>
+ * Copyright (C) 2000, 2001 Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
+ *
+ * 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 ipcomp_c_version[] = "RCSID $Id: ipcomp.c,v 1.2 2004/06/13 19:57:49 as Exp $";
+
+/* SSS */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+
+#include <freeswan.h>
+
+#ifdef NET_21
+# include <net/dst.h>
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define proto_priv cb
+#endif /* NET21 */
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h" /* sysctl_ipsec_inbound_policy_check */
+#include "freeswan/ipcomp.h"
+#include "zlib/zlib.h"
+#include "zlib/zutil.h"
+
+#include <pfkeyv2.h> /* SADB_X_CALG_DEFLATE */
+
+#ifdef CONFIG_IPSEC_DEBUG
+int sysctl_ipsec_debug_ipcomp = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+static
+struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask);
+
+static
+voidpf my_zcalloc(voidpf opaque, uInt items, uInt size)
+{
+ return (voidpf) kmalloc(items*size, GFP_ATOMIC);
+}
+
+static
+void my_zfree(voidpf opaque, voidpf address)
+{
+ kfree(address);
+}
+
+struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
+{
+ struct iphdr *iph;
+ unsigned int iphlen, pyldsz, cpyldsz;
+ unsigned char *buffer;
+ z_stream zs;
+ int zresult;
+
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: .\n");
+
+ if(skb == NULL) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "passed in NULL skb, returning ERROR.\n");
+ if(flags != NULL) {
+ *flags |= IPCOMP_PARMERROR;
+ }
+ return skb;
+ }
+
+ if(ips == NULL) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "passed in NULL ipsec_sa needed for cpi, returning ERROR.\n");
+ if(flags) {
+ *flags |= IPCOMP_PARMERROR;
+ }
+ return skb;
+ }
+
+ if (flags == NULL) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "passed in NULL flags, returning ERROR.\n");
+ ipsec_kfree_skb(skb);
+ return NULL;
+ }
+
+#ifdef NET_21
+ iph = skb->nh.iph;
+#else /* NET_21 */
+ iph = skb->ip_hdr;
+#endif /* NET_21 */
+
+ switch (iph->protocol) {
+ case IPPROTO_COMP:
+ case IPPROTO_AH:
+ case IPPROTO_ESP:
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "skipping compression of packet with ip protocol %d.\n",
+ iph->protocol);
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ return skb;
+ }
+
+ /* Don't compress packets already fragmented */
+ if (iph->frag_off & __constant_htons(IP_MF | IP_OFFSET)) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "skipping compression of fragmented packet.\n");
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ return skb;
+ }
+
+ iphlen = iph->ihl << 2;
+ pyldsz = ntohs(iph->tot_len) - iphlen;
+
+ /* Don't compress less than 90 bytes (rfc 2394) */
+ if (pyldsz < 90) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "skipping compression of tiny packet, len=%d.\n",
+ pyldsz);
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ return skb;
+ }
+
+ /* Adaptive decision */
+ if (ips->ips_comp_adapt_skip) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "skipping compression: ips_comp_adapt_skip=%d.\n",
+ ips->ips_comp_adapt_skip);
+ ips->ips_comp_adapt_skip--;
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ return skb;
+ }
+
+ zs.zalloc = my_zcalloc;
+ zs.zfree = my_zfree;
+ zs.opaque = 0;
+
+ /* We want to use deflateInit2 because we don't want the adler
+ header. */
+ zresult = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -11,
+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ if (zresult != Z_OK) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_compress: "
+ "deflateInit2() returned error %d (%s), "
+ "skipping compression.\n",
+ zresult,
+ zs.msg ? zs.msg : zError(zresult));
+ *flags |= IPCOMP_COMPRESSIONERROR;
+ return skb;
+ }
+
+
+ /* Max output size. Result should be max this size.
+ * Implementation specific tweak:
+ * If it's not at least 32 bytes and 6.25% smaller than
+ * the original packet, it's probably not worth wasting
+ * the receiver's CPU cycles decompressing it.
+ * Your mileage may vary.
+ */
+ cpyldsz = pyldsz - sizeof(struct ipcomphdr) - (pyldsz <= 512 ? 32 : pyldsz >> 4);
+
+ buffer = kmalloc(cpyldsz, GFP_ATOMIC);
+ if (!buffer) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_compress: "
+ "unable to kmalloc(%d, GFP_ATOMIC), "
+ "skipping compression.\n",
+ cpyldsz);
+ *flags |= IPCOMP_COMPRESSIONERROR;
+ deflateEnd(&zs);
+ return skb;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = (__u8*)iph + iphlen;
+ for(i = 0; i < pyldsz; i++, c++) {
+ if(!(i % 16)) {
+ printk(KERN_INFO "skb_compress: before:");
+ }
+ printk("%02x ", *c);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ zs.next_in = (char *) iph + iphlen; /* start of payload */
+ zs.avail_in = pyldsz;
+ zs.next_out = buffer; /* start of compressed payload */
+ zs.avail_out = cpyldsz;
+
+ /* Finish compression in one step */
+ zresult = deflate(&zs, Z_FINISH);
+
+ /* Free all dynamically allocated buffers */
+ deflateEnd(&zs);
+ if (zresult != Z_STREAM_END) {
+ *flags |= IPCOMP_UNCOMPRESSABLE;
+ kfree(buffer);
+
+ /* Adjust adaptive counters */
+ if (++(ips->ips_comp_adapt_tries) == IPCOMP_ADAPT_INITIAL_TRIES) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "first %d packets didn't compress, "
+ "skipping next %d\n",
+ IPCOMP_ADAPT_INITIAL_TRIES,
+ IPCOMP_ADAPT_INITIAL_SKIP);
+ ips->ips_comp_adapt_skip = IPCOMP_ADAPT_INITIAL_SKIP;
+ }
+ else if (ips->ips_comp_adapt_tries == IPCOMP_ADAPT_INITIAL_TRIES + IPCOMP_ADAPT_SUBSEQ_TRIES) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "next %d packets didn't compress, "
+ "skipping next %d\n",
+ IPCOMP_ADAPT_SUBSEQ_TRIES,
+ IPCOMP_ADAPT_SUBSEQ_SKIP);
+ ips->ips_comp_adapt_skip = IPCOMP_ADAPT_SUBSEQ_SKIP;
+ ips->ips_comp_adapt_tries = IPCOMP_ADAPT_INITIAL_TRIES;
+ }
+
+ return skb;
+ }
+
+ /* resulting compressed size */
+ cpyldsz -= zs.avail_out;
+
+ /* Insert IPCOMP header */
+ ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_nh = iph->protocol;
+ ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_flags = 0;
+ /* use the bottom 16 bits of the spi for the cpi. The top 16 bits are
+ for internal reference only. */
+ ((struct ipcomphdr*) (((char*)iph) + iphlen))->ipcomp_cpi = htons((__u16)(ntohl(ips->ips_said.spi) & 0x0000ffff));
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_compress: "
+ "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: raw=%d, comp=%d.\n",
+ ntohl(ips->ips_said.spi),
+ ntohl(ips->ips_said.spi) & 0x0000ffff,
+ ntohs(((struct ipcomphdr*)(((char*)iph)+iphlen))->ipcomp_cpi),
+ pyldsz,
+ cpyldsz);
+
+ /* Update IP header */
+ iph->protocol = IPPROTO_COMP;
+ iph->tot_len = htons(iphlen + sizeof(struct ipcomphdr) + cpyldsz);
+#if 1 /* XXX checksum is done by ipsec_tunnel ? */
+ iph->check = 0;
+ iph->check = ip_fast_csum((char *) iph, iph->ihl);
+#endif
+
+ /* Copy compressed payload */
+ memcpy((char *) iph + iphlen + sizeof(struct ipcomphdr),
+ buffer,
+ cpyldsz);
+ kfree(buffer);
+
+ /* Update skb length/tail by "unputting" the shrinkage */
+ skb_put(skb,
+ cpyldsz + sizeof(struct ipcomphdr) - pyldsz);
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = (__u8*)iph + iphlen + sizeof(struct ipcomphdr);
+ for(i = 0; i < cpyldsz; i++, c++) {
+ if(!(i % 16)) {
+ printk(KERN_INFO "skb_compress: result:");
+ }
+ printk("%02x ", *c);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ ips->ips_comp_adapt_skip = 0;
+ ips->ips_comp_adapt_tries = 0;
+
+ return skb;
+}
+
+struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
+{
+ struct sk_buff *nskb = NULL;
+
+ /* original ip header */
+ struct iphdr *oiph, *iph;
+ unsigned int iphlen, pyldsz, cpyldsz;
+ z_stream zs;
+ int zresult;
+
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_decompress: .\n");
+
+ if(!skb) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "passed in NULL skb, returning ERROR.\n");
+ if (flags) *flags |= IPCOMP_PARMERROR;
+ return skb;
+ }
+
+ if(!ips && sysctl_ipsec_inbound_policy_check) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "passed in NULL ipsec_sa needed for comp alg, returning ERROR.\n");
+ if (flags) *flags |= IPCOMP_PARMERROR;
+ return skb;
+ }
+
+ if (!flags) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "passed in NULL flags, returning ERROR.\n");
+ ipsec_kfree_skb(skb);
+ return NULL;
+ }
+
+#ifdef NET_21
+ oiph = skb->nh.iph;
+#else /* NET_21 */
+ oiph = skb->ip_hdr;
+#endif /* NET_21 */
+
+ iphlen = oiph->ihl << 2;
+
+ if (oiph->protocol != IPPROTO_COMP) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "called with non-IPCOMP packet (protocol=%d),"
+ "skipping decompression.\n",
+ oiph->protocol);
+ *flags |= IPCOMP_PARMERROR;
+ return skb;
+ }
+
+ if ( (((struct ipcomphdr*)((char*) oiph + iphlen))->ipcomp_flags != 0)
+ || ((((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi
+ != htons(SADB_X_CALG_DEFLATE))
+ && sysctl_ipsec_inbound_policy_check
+ && (!ips || (ips && (ips->ips_encalg != SADB_X_CALG_DEFLATE)))) ) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "called with incompatible IPCOMP packet (flags=%d, "
+ "cpi=%d), ips-compalg=%d, skipping decompression.\n",
+ ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_flags),
+ ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi),
+ ips ? ips->ips_encalg : 0);
+ *flags |= IPCOMP_PARMERROR;
+
+ return skb;
+ }
+
+ if (ntohs(oiph->frag_off) & ~0x4000) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "called with fragmented IPCOMP packet, "
+ "skipping decompression.\n");
+ *flags |= IPCOMP_PARMERROR;
+ return skb;
+ }
+
+ /* original compressed payload size */
+ cpyldsz = ntohs(oiph->tot_len) - iphlen - sizeof(struct ipcomphdr);
+
+ zs.zalloc = my_zcalloc;
+ zs.zfree = my_zfree;
+ zs.opaque = 0;
+
+ zs.next_in = (char *) oiph + iphlen + sizeof(struct ipcomphdr);
+ zs.avail_in = cpyldsz;
+
+ /* Maybe we should be a bit conservative about memory
+ requirements and use inflateInit2 */
+ /* Beware, that this might make us unable to decompress packets
+ from other implementations - HINT: check PGPnet source code */
+ /* We want to use inflateInit2 because we don't want the adler
+ header. */
+ zresult = inflateInit2(&zs, -15);
+ if (zresult != Z_OK) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "inflateInit2() returned error %d (%s), "
+ "skipping decompression.\n",
+ zresult,
+ zs.msg ? zs.msg : zError(zresult));
+ *flags |= IPCOMP_DECOMPRESSIONERROR;
+
+ return skb;
+ }
+
+ /* We have no way of knowing the exact length of the resulting
+ decompressed output before we have actually done the decompression.
+ For now, we guess that the packet will not be bigger than the
+ attached ipsec device's mtu or 16260, whichever is biggest.
+ This may be wrong, since the sender's mtu may be bigger yet.
+ XXX This must be dealt with later XXX
+ */
+
+ /* max payload size */
+ pyldsz = skb->dev ? (skb->dev->mtu < 16260 ? 16260 : skb->dev->mtu)
+ : (65520 - iphlen);
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_decompress: "
+ "max payload size: %d\n", pyldsz);
+
+ while (pyldsz > (cpyldsz + sizeof(struct ipcomphdr)) &&
+ (nskb = skb_copy_ipcomp(skb,
+ pyldsz - cpyldsz - sizeof(struct ipcomphdr),
+ GFP_ATOMIC)) == NULL) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "unable to skb_copy_ipcomp(skb, %d, GFP_ATOMIC), "
+ "trying with less payload size.\n",
+ (int)(pyldsz - cpyldsz - sizeof(struct ipcomphdr)));
+ pyldsz >>=1;
+ }
+
+ if (!nskb) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "unable to allocate memory, dropping packet.\n");
+ *flags |= IPCOMP_DECOMPRESSIONERROR;
+ inflateEnd(&zs);
+
+ return skb;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = (__u8*)oiph + iphlen + sizeof(struct ipcomphdr);
+ for(i = 0; i < cpyldsz; i++, c++) {
+ if(!(i % 16)) {
+ printk(KERN_INFO "skb_decompress: before:");
+ }
+ printk("%02x ", *c);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#ifdef NET_21
+ iph = nskb->nh.iph;
+#else /* NET_21 */
+ iph = nskb->ip_hdr;
+#endif /* NET_21 */
+ zs.next_out = (char *)iph + iphlen;
+ zs.avail_out = pyldsz;
+
+ zresult = inflate(&zs, Z_SYNC_FLUSH);
+
+ /* work around a bug in zlib, which sometimes wants to taste an extra
+ * byte when being used in the (undocumented) raw deflate mode.
+ */
+ if (zresult == Z_OK && !zs.avail_in && zs.avail_out) {
+ __u8 zerostuff = 0;
+
+ zs.next_in = &zerostuff;
+ zs.avail_in = 1;
+ zresult = inflate(&zs, Z_FINISH);
+ }
+
+ inflateEnd(&zs);
+ if (zresult != Z_STREAM_END) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_error:skb_decompress: "
+ "inflate() returned error %d (%s), "
+ "skipping decompression.\n",
+ zresult,
+ zs.msg ? zs.msg : zError(zresult));
+ *flags |= IPCOMP_DECOMPRESSIONERROR;
+ ipsec_kfree_skb(nskb);
+
+ return skb;
+ }
+
+ /* Update IP header */
+ /* resulting decompressed size */
+ pyldsz -= zs.avail_out;
+ iph->tot_len = htons(iphlen + pyldsz);
+ iph->protocol = ((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_nh;
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_decompress: "
+ "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: comp=%d, raw=%d, nh=%d.\n",
+ ips ? ntohl(ips->ips_said.spi) : 0,
+ ips ? ntohl(ips->ips_said.spi) & 0x0000ffff : 0,
+ ntohs(((struct ipcomphdr*)(((char*)oiph)+iphlen))->ipcomp_cpi),
+ cpyldsz,
+ pyldsz,
+ iph->protocol);
+
+#if 1 /* XXX checksum is done by ipsec_rcv ? */
+ iph->check = 0;
+ iph->check = ip_fast_csum((char*) iph, iph->ihl);
+#endif
+
+ /* Update skb length/tail by "unputting" the unused data area */
+ skb_put(nskb, -zs.avail_out);
+
+ ipsec_kfree_skb(skb);
+
+ if (iph->protocol == IPPROTO_COMP)
+ {
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp)
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_decompress: "
+ "Eh? inner packet is also compressed, dropping.\n");
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ ipsec_kfree_skb(nskb);
+ return NULL;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = (__u8*)iph + iphlen;
+ for(i = 0; i < pyldsz; i++, c++) {
+ if(!(i % 16)) {
+ printk(KERN_INFO "skb_decompress: result:");
+ }
+ printk("%02x ", *c);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ return nskb;
+}
+
+
+/* this is derived from skb_copy() in linux 2.2.14 */
+/* May be incompatible with other kernel versions!! */
+static
+struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask)
+{
+ struct sk_buff *n;
+ struct iphdr *iph;
+ unsigned long offset;
+ unsigned int iphlen;
+
+ if(!skb) {
+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
+ "klips_debug:skb_copy_ipcomp: "
+ "passed in NULL skb, returning NULL.\n");
+ return NULL;
+ }
+
+ /*
+ * Allocate the copy buffer
+ */
+
+#ifdef NET_21
+ iph = skb->nh.iph;
+#else /* NET_21 */
+ iph = skb->ip_hdr;
+#endif /* NET_21 */
+ if (!iph) return NULL;
+ iphlen = iph->ihl << 2;
+
+ n=alloc_skb(skb->end - skb->head + data_growth, gfp_mask);
+ if(n==NULL)
+ return NULL;
+
+ /*
+ * Shift between the two data areas in bytes
+ */
+
+ offset=n->head-skb->head;
+
+ /* Set the data pointer */
+ skb_reserve(n,skb->data-skb->head);
+ /* Set the tail pointer and length */
+ skb_put(n,skb->len+data_growth);
+ /* Copy the bytes up to and including the ip header */
+ memcpy(n->head,
+ skb->head,
+ ((char *)iph - (char *)skb->head) + iphlen);
+ n->list=NULL;
+ n->next=NULL;
+ n->prev=NULL;
+ n->sk=NULL;
+ n->dev=skb->dev;
+ if (skb->h.raw)
+ n->h.raw=skb->h.raw+offset;
+ else
+ n->h.raw=NULL;
+ n->protocol=skb->protocol;
+#ifdef NET_21
+ n->csum = 0;
+ n->priority=skb->priority;
+ n->dst=dst_clone(skb->dst);
+ n->nh.raw=skb->nh.raw+offset;
+#ifndef NETDEV_23
+ n->is_clone=0;
+#endif /* NETDEV_23 */
+ atomic_set(&n->users, 1);
+ n->destructor = NULL;
+ n->security=skb->security;
+ memcpy(n->cb, skb->cb, sizeof(skb->cb));
+#ifdef CONFIG_IP_FIREWALL
+ n->fwmark = skb->fwmark;
+#endif
+#else /* NET_21 */
+ n->link3=NULL;
+ n->when=skb->when;
+ n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
+ n->saddr=skb->saddr;
+ n->daddr=skb->daddr;
+ n->raddr=skb->raddr;
+ n->seq=skb->seq;
+ n->end_seq=skb->end_seq;
+ n->ack_seq=skb->ack_seq;
+ n->acked=skb->acked;
+ n->free=1;
+ n->arp=skb->arp;
+ n->tries=0;
+ n->lock=0;
+ n->users=0;
+ memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
+#endif /* NET_21 */
+ if (skb->mac.raw)
+ n->mac.raw=skb->mac.raw+offset;
+ else
+ n->mac.raw=NULL;
+#ifndef NETDEV_23
+ n->used=skb->used;
+#endif /* !NETDEV_23 */
+ n->pkt_type=skb->pkt_type;
+#ifndef NETDEV_23
+ n->pkt_bridged=skb->pkt_bridged;
+#endif /* NETDEV_23 */
+ n->ip_summed=0;
+ n->stamp=skb->stamp;
+#ifndef NETDEV_23 /* this seems to have been removed in 2.4 */
+#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
+ n->shapelatency=skb->shapelatency; /* Latency on frame */
+ n->shapeclock=skb->shapeclock; /* Time it should go out */
+ n->shapelen=skb->shapelen; /* Frame length in clocks */
+ n->shapestamp=skb->shapestamp; /* Stamp for shaper */
+ n->shapepend=skb->shapepend; /* Pending */
+#endif /* defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) */
+#endif /* NETDEV_23 */
+#ifdef CONFIG_HIPPI
+ n->private.ifield=skb->private.ifield;
+#endif /* CONFIG_HIPPI */
+
+ return n;
+}
diff --git a/linux/net/ipsec/ipsec_alg.c b/linux/net/ipsec/ipsec_alg.c
new file mode 100644
index 000000000..c402b7e5b
--- /dev/null
+++ b/linux/net/ipsec/ipsec_alg.c
@@ -0,0 +1,927 @@
+/*
+ * Modular extensions service and registration functions
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * Version: 0.8.1
+ *
+ * $Id: ipsec_alg.c,v 1.4 2004/06/13 19:57:49 as Exp $
+ *
+ * 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.
+ *
+ */
+#ifdef CONFIG_IPSEC_ALG
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/types.h>
+#include <linux/string.h> /* memcmp() */
+#include <linux/random.h> /* get_random_bytes() */
+#include <linux/errno.h> /* error codes */
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define proto_priv cb
+#endif /* NET21 */
+#include "freeswan/ipsec_param.h"
+#include <freeswan.h>
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h"
+#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
+# include "freeswan/ipsec_ah.h"
+#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
+#ifdef CONFIG_IPSEC_ESP
+# include "freeswan/ipsec_esp.h"
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_IPCOMP
+# include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_COMP */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_alg.h"
+
+#ifndef CONFIG_IPSEC_ALG
+#error This file _MUST_ be compiled with CONFIG_IPSEC_ALG enabled !
+#endif
+#if SADB_EALG_MAX < 255
+#warning Compiling with limited ESP support ( SADB_EALG_MAX < 256 )
+#endif
+
+static rwlock_t ipsec_alg_lock = RW_LOCK_UNLOCKED;
+#define IPSEC_ALG_HASHSZ 16 /* must be power of 2, even 2^0=1 */
+static struct list_head ipsec_alg_hash_table[IPSEC_ALG_HASHSZ];
+
+/* Old gcc's will fail here */
+#define barf_out(fmt, args...) do { printk(KERN_ERR "%s: (%s) " fmt, __FUNCTION__, ixt->ixt_name , ## args)\
+ ; goto out; } while(0)
+
+/*
+ * Must be already protected by lock
+ */
+static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt) {
+ if (ixt->ixt_module)
+ __MOD_INC_USE_COUNT(ixt->ixt_module);
+ atomic_inc(&ixt->ixt_refcnt);
+}
+static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) {
+ atomic_dec(&ixt->ixt_refcnt);
+ if (ixt->ixt_module)
+ __MOD_DEC_USE_COUNT(ixt->ixt_module);
+}
+/*
+ * simple hash function, optimized for 0-hash (1 list) special
+ * case
+ */
+#if IPSEC_ALG_HASHSZ > 1
+static inline unsigned ipsec_alg_hashfn(int alg_type, int alg_id) {
+ return ((alg_type^alg_id)&(IPSEC_ALG_HASHSZ-1));
+}
+#else
+#define ipsec_alg_hashfn(x,y) (0)
+#endif
+
+/*****************************************************************
+ *
+ * INTERNAL table handling: insert, delete, find
+ *
+ *****************************************************************/
+
+/*
+ * hash table initialization, called from ipsec_alg_init()
+ */
+static void ipsec_alg_hash_init(void) {
+ struct list_head *head = ipsec_alg_hash_table;
+ int i = IPSEC_ALG_HASHSZ;
+ do {
+ INIT_LIST_HEAD(head);
+ head++;
+ i--;
+ } while (i);
+}
+/*
+ * hash list lookup by {alg_type, alg_id} and table head,
+ * must be already protected by lock
+ */
+static struct ipsec_alg *__ipsec_alg_find(unsigned alg_type, unsigned alg_id, struct list_head * head) {
+ struct list_head *p;
+ struct ipsec_alg *ixt=NULL;
+ for (p=head->next; p!=head; p=p->next) {
+ ixt = list_entry(p, struct ipsec_alg, ixt_list);
+ if (ixt->ixt_alg_type == alg_type && ixt->ixt_alg_id==alg_id) {
+ goto out;
+ }
+ }
+ ixt=NULL;
+out:
+ return ixt;
+}
+/*
+ * inserts (in front) a new entry in hash table,
+ * called from ipsec_alg_register() when new algorithm is registered.
+ */
+static int ipsec_alg_insert(struct ipsec_alg *ixt) {
+ int ret=-EINVAL;
+ unsigned hashval=ipsec_alg_hashfn(ixt->ixt_alg_type, ixt->ixt_alg_id);
+ struct list_head *head= ipsec_alg_hash_table + hashval;
+ struct ipsec_alg *ixt_cur;
+ /* new element must be virgin ... */
+ if (ixt->ixt_list.next != &ixt->ixt_list ||
+ ixt->ixt_list.prev != &ixt->ixt_list) {
+ printk(KERN_ERR "ipsec_alg_insert: ixt object \"%s\" "
+ "list head not initialized\n",
+ ixt->ixt_name);
+ return ret;
+ }
+ write_lock_bh(&ipsec_alg_lock);
+ ixt_cur = __ipsec_alg_find(ixt->ixt_alg_type, ixt->ixt_alg_id, head);
+ /* if previous (current) ipsec_alg found check excl flag of _anyone_ */
+ if (ixt_cur && ((ixt->ixt_state|ixt_cur->ixt_state) & IPSEC_ALG_ST_EXCL))
+ barf_out("ipsec_alg for alg_type=%d, alg_id=%d already exist. "
+ "Not loaded (ret=%d).\n",
+ ixt->ixt_alg_type,
+ ixt->ixt_alg_id, ret=-EEXIST);
+ list_add(&ixt->ixt_list, head);
+ ixt->ixt_state |= IPSEC_ALG_ST_REGISTERED;
+ ret=0;
+out:
+ write_unlock_bh(&ipsec_alg_lock);
+ return ret;
+}
+/*
+ * deletes an existing entry in hash table,
+ * called from ipsec_alg_unregister() when algorithm is unregistered.
+ */
+static int ipsec_alg_delete(struct ipsec_alg *ixt) {
+ write_lock_bh(&ipsec_alg_lock);
+ list_del(&ixt->ixt_list);
+ write_unlock_bh(&ipsec_alg_lock);
+ return 0;
+}
+/*
+ * here @user context (read-only when @kernel bh context)
+ * -> no bh disabling
+ *
+ * called from ipsec_sa_init() -> ipsec_alg_sa_init()
+ */
+static struct ipsec_alg *ipsec_alg_get(int alg_type, int alg_id) {
+ unsigned hashval=ipsec_alg_hashfn(alg_type, alg_id);
+ struct list_head *head= ipsec_alg_hash_table + hashval;
+ struct ipsec_alg *ixt;
+ read_lock(&ipsec_alg_lock);
+ ixt=__ipsec_alg_find(alg_type, alg_id, head);
+ if (ixt) __ipsec_alg_usage_inc(ixt);
+ read_unlock(&ipsec_alg_lock);
+ return ixt;
+}
+
+static void ipsec_alg_put(struct ipsec_alg *ixt) {
+ __ipsec_alg_usage_dec((struct ipsec_alg *)ixt);
+}
+
+/*****************************************************************
+ *
+ * INTERFACE for ENC services: key creation, encrypt function
+ *
+ *****************************************************************/
+
+/*
+ * main encrypt service entry point
+ * called from ipsec_rcv() with encrypt=IPSEC_ALG_DECRYPT and
+ * ipsec_tunnel_start_xmit with encrypt=IPSEC_ALG_ENCRYPT
+ */
+int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 * idat, int ilen, const __u8 * iv, int encrypt) {
+ int ret;
+ struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
+ KLIPS_PRINT(debug_rcv||debug_tunnel,
+ "klips_debug:ipsec_alg_esp_encrypt: "
+ "entering with encalg=%d, ixt_e=%p\n",
+ sa_p->ips_encalg, ixt_e);
+ if (!ixt_e) {
+ KLIPS_PRINT(debug_rcv||debug_tunnel,
+ "klips_debug:ipsec_alg_esp_encrypt: "
+ "NULL ipsec_alg_enc object\n");
+ return -1;
+ }
+ KLIPS_PRINT(debug_rcv||debug_tunnel,
+ "klips_debug:ipsec_alg_esp_encrypt: "
+ "calling cbc_encrypt encalg=%d "
+ "ips_key_e=%p idat=%p ilen=%d iv=%p, encrypt=%d\n",
+ sa_p->ips_encalg,
+ sa_p->ips_key_e, idat, ilen, iv, encrypt);
+ ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, sa_p->ips_key_e, idat, ilen, iv, encrypt);
+ KLIPS_PRINT(debug_rcv||debug_tunnel,
+ "klips_debug:ipsec_alg_esp_encrypt: "
+ "returned ret=%d\n",
+ ret);
+ return ret;
+}
+/*
+ * encryption key context creation function
+ * called from pfkey_v2_parser.c:pfkey_ips_init()
+ */
+int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p) {
+ int ret=-EINVAL;
+ int keyminbits, keymaxbits;
+ caddr_t ekp;
+ struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_enc_key_create: "
+ "entering with encalg=%d ixt_e=%p\n",
+ sa_p->ips_encalg, ixt_e);
+ if (!ixt_e) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_enc_key_create: "
+ "NULL ipsec_alg_enc object\n");
+ return -EPROTO;
+ }
+
+ /*
+ * grRRR... DES 7bits jurassic stuff ... f*ckk --jjo
+ */
+ switch(ixt_e->ixt_alg_id) {
+ case ESP_3DES:
+ keyminbits=keymaxbits=192;break;
+ case ESP_DES:
+ keyminbits=keymaxbits=64;break;
+ default:
+ keyminbits=ixt_e->ixt_keyminbits;
+ keymaxbits=ixt_e->ixt_keymaxbits;
+ }
+ if(sa_p->ips_key_bits_e<keyminbits ||
+ sa_p->ips_key_bits_e>keymaxbits) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_enc_key_create: "
+ "incorrect encryption key size for id=%d: %d bits -- "
+ "must be between %d,%d bits\n" /*octets (bytes)\n"*/,
+ ixt_e->ixt_alg_id,
+ sa_p->ips_key_bits_e, keyminbits, keymaxbits);
+ ret=-EINVAL;
+ goto ixt_out;
+ }
+ /* save encryption key pointer */
+ ekp = sa_p->ips_key_e;
+
+
+ if (ixt_e->ixt_e_new_key) {
+ sa_p->ips_key_e = ixt_e->ixt_e_new_key(ixt_e,
+ ekp, sa_p->ips_key_bits_e/8);
+ ret = (sa_p->ips_key_e)? 0 : -EINVAL;
+ } else {
+ if((sa_p->ips_key_e = (caddr_t)
+ kmalloc((sa_p->ips_key_e_size = ixt_e->ixt_e_ctx_size),
+ GFP_ATOMIC)) == NULL) {
+ ret=-ENOMEM;
+ goto ixt_out;
+ }
+ /* zero-out key_e */
+ memset(sa_p->ips_key_e, 0, sa_p->ips_key_e_size);
+
+ /* I cast here to allow more decoupling in alg module */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_enc_key_create: about to call:"
+ "set_key(key_e=%p, ekp=%p, key_size=%d)\n",
+ (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
+ ret = ixt_e->ixt_e_set_key(ixt_e, (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
+ }
+ /* paranoid */
+ memset(ekp, 0, sa_p->ips_key_bits_e/8);
+ kfree(ekp);
+ixt_out:
+ return ret;
+}
+
+/***************************************************************
+ *
+ * INTERFACE for AUTH services: key creation, hash functions
+ *
+ ***************************************************************/
+
+/*
+ * auth key context creation function
+ * called from pfkey_v2_parser.c:pfkey_ips_init()
+ */
+int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p) {
+ int ret=-EINVAL;
+ struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
+ int keyminbits, keymaxbits;
+ unsigned char *akp;
+ unsigned int aks;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_auth_key_create: "
+ "entering with authalg=%d ixt_a=%p\n",
+ sa_p->ips_authalg, ixt_a);
+ if (!ixt_a) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_auth_key_create: "
+ "NULL ipsec_alg_auth object\n");
+ return -EPROTO;
+ }
+ keyminbits=ixt_a->ixt_keyminbits;
+ keymaxbits=ixt_a->ixt_keymaxbits;
+ if(sa_p->ips_key_bits_a<keyminbits || sa_p->ips_key_bits_a>keymaxbits) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_alg_auth_key_create: incorrect auth"
+ "key size: %d bits -- must be between %d,%d bits\n"/*octets (bytes)\n"*/,
+ sa_p->ips_key_bits_a, keyminbits, keymaxbits);
+ ret=-EINVAL;
+ goto ixt_out;
+ }
+ /* save auth key pointer */
+ sa_p->ips_auth_bits = ixt_a->ixt_a_keylen * 8; /* XXX XXX */
+ akp = sa_p->ips_key_a;
+ aks = sa_p->ips_key_a_size;
+
+ /* will hold: 2 ctx and a blocksize buffer: kb */
+ sa_p->ips_key_a_size = ixt_a->ixt_a_ctx_size;
+ if((sa_p->ips_key_a =
+ (caddr_t) kmalloc(sa_p->ips_key_a_size, GFP_ATOMIC)) == NULL) {
+ ret=-ENOMEM;
+ goto ixt_out;
+ }
+ ixt_a->ixt_a_hmac_set_key(ixt_a, sa_p->ips_key_a, akp, sa_p->ips_key_bits_a/8); /* XXX XXX */
+ ret=0;
+ memset(akp, 0, aks);
+ kfree(akp);
+
+ixt_out:
+ return ret;
+}
+int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) {
+ struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
+ if (!ixt_a) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_sa_esp_hash: "
+ "NULL ipsec_alg_auth object\n");
+ return -EPROTO;
+ }
+ KLIPS_PRINT(debug_tunnel|debug_rcv,
+ "klips_debug:ipsec_sa_esp_hash: "
+ "hashing %p (%d bytes) to %p (%d bytes)\n",
+ espp, len,
+ hash, hashlen);
+ ixt_a->ixt_a_hmac_hash(ixt_a,
+ sa_p->ips_key_a,
+ espp, len,
+ hash, hashlen);
+ return 0;
+}
+
+/***************************************************************
+ *
+ * INTERFACE for module loading,testing, and unloading
+ *
+ ***************************************************************/
+
+/* validation for registering (enc) module */
+static int check_enc(struct ipsec_alg_enc *ixt) {
+ int ret=-EINVAL;
+ if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_EALG_MAX)
+ barf_out("invalid alg_id=%d >= %d\n", ixt->ixt_alg_id, SADB_EALG_MAX);
+ if (ixt->ixt_blocksize==0) /* || ixt->ixt_blocksize%2) need for ESP_NULL */
+ barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);
+ if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_e_keylen==0)
+ goto zero_key_ok;
+ if (ixt->ixt_keyminbits==0)
+ barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);
+ if (ixt->ixt_keymaxbits==0)
+ barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);
+ if (ixt->ixt_e_keylen==0)
+ barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_e_keylen);
+zero_key_ok:
+ if (ixt->ixt_e_ctx_size==0 && ixt->ixt_e_new_key == NULL)
+ barf_out(KERN_ERR "invalid key_e_size=%d and ixt_e_new_key=NULL\n", ixt->ixt_e_ctx_size);
+ if (ixt->ixt_e_cbc_encrypt==NULL)
+ barf_out(KERN_ERR "e_cbc_encrypt() must be not NULL\n");
+ ret=0;
+out:
+ return ret;
+}
+
+/* validation for registering (auth) module */
+static int check_auth(struct ipsec_alg_auth *ixt) {
+ int ret=-EINVAL;
+ if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_AALG_MAX)
+ barf_out("invalid alg_id=%d > %d (SADB_AALG_MAX)\n", ixt->ixt_alg_id, SADB_AALG_MAX);
+ if (ixt->ixt_blocksize==0 || ixt->ixt_blocksize%2)
+ barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);
+ if (ixt->ixt_blocksize>AH_BLKLEN_MAX)
+ barf_out(KERN_ERR "sorry blocksize=%d > %d. "
+ "Please increase AH_BLKLEN_MAX and recompile\n",
+ ixt->ixt_blocksize,
+ AH_BLKLEN_MAX);
+ if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_a_keylen==0)
+ goto zero_key_ok;
+ if (ixt->ixt_keyminbits==0)
+ barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);
+ if (ixt->ixt_keymaxbits==0)
+ barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);
+ if (ixt->ixt_keymaxbits!=ixt->ixt_keyminbits)
+ barf_out(KERN_ERR "keymaxbits must equal keyminbits (not sure).\n");
+ if (ixt->ixt_a_keylen==0)
+ barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_a_keylen);
+zero_key_ok:
+ if (ixt->ixt_a_ctx_size==0)
+ barf_out(KERN_ERR "invalid a_ctx_size=%d\n", ixt->ixt_a_ctx_size);
+ if (ixt->ixt_a_hmac_set_key==NULL)
+ barf_out(KERN_ERR "a_hmac_set_key() must be not NULL\n");
+ if (ixt->ixt_a_hmac_hash==NULL)
+ barf_out(KERN_ERR "a_hmac_hash() must be not NULL\n");
+ ret=0;
+out:
+ return ret;
+}
+
+/*
+ * Generic (enc, auth) registration entry point
+ */
+int register_ipsec_alg(struct ipsec_alg *ixt) {
+ int ret=-EINVAL;
+ /* Validation */
+ if (ixt==NULL)
+ barf_out("NULL ipsec_alg object passed\n");
+ if ((ixt->ixt_version&0xffffff00) != (IPSEC_ALG_VERSION&0xffffff00))
+ barf_out("incorrect version: %d.%d.%d-%d, "
+ "must be %d.%d.%d[-%d]\n",
+ IPSEC_ALG_VERSION_QUAD(ixt->ixt_version),
+ IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION));
+ switch(ixt->ixt_alg_type) {
+ case IPSEC_ALG_TYPE_AUTH:
+ if ((ret=check_auth((struct ipsec_alg_auth *)ixt)<0))
+ goto out;
+ break;
+ case IPSEC_ALG_TYPE_ENCRYPT:
+ if ((ret=check_enc((struct ipsec_alg_enc *)ixt)<0))
+ goto out;
+ /*
+ * Adapted two lines below:
+ * ivlen == 0 is possible (NULL enc has blocksize==1)
+ *
+ * fixed NULL support by David De Reu <DeReu@tComLabs.com>
+ */
+ if (ixt->ixt_ivlen == 0 && ixt->ixt_blocksize > 1)
+ ixt->ixt_ivlen = ixt->ixt_blocksize*8;
+ break;
+ default:
+ barf_out("alg_type=%d not supported\n", ixt->ixt_alg_type);
+ }
+ INIT_LIST_HEAD(&ixt->ixt_list);
+ ret = ipsec_alg_insert(ixt);
+ if (ret<0)
+ barf_out(KERN_WARNING "ipsec_alg for alg_id=%d failed."
+ "Not loaded (ret=%d).\n",
+ ixt->ixt_alg_id, ret);
+
+ ret = pfkey_list_insert_supported((struct supported *)&ixt->ixt_support, &(pfkey_supported_list[SADB_SATYPE_ESP]));
+ if (ret==0) {
+ ixt->ixt_state |= IPSEC_ALG_ST_SUPP;
+ /* send register event to userspace */
+ pfkey_register_reply(SADB_SATYPE_ESP, NULL);
+ } else
+ printk(KERN_ERR "pfkey_list_insert_supported returned %d. "
+ "Loading anyway.\n", ret);
+ ret=0;
+out:
+ return ret;
+}
+
+/*
+ * unregister ipsec_alg object from own tables, if
+ * success => calls pfkey_list_remove_supported()
+ */
+int unregister_ipsec_alg(struct ipsec_alg *ixt) {
+ int ret= -EINVAL;
+ switch(ixt->ixt_alg_type) {
+ case IPSEC_ALG_TYPE_AUTH:
+ case IPSEC_ALG_TYPE_ENCRYPT:
+ break;
+ default:
+ /* this is not a typo :) */
+ barf_out("frog found in list (\"%s\"): ixt_p=NULL\n",
+ ixt->ixt_name);
+ }
+
+ ret=ipsec_alg_delete(ixt);
+ if (ixt->ixt_state&IPSEC_ALG_ST_SUPP) {
+ ixt->ixt_state &= ~IPSEC_ALG_ST_SUPP;
+ pfkey_list_remove_supported((struct supported *)&ixt->ixt_support, &(pfkey_supported_list[SADB_SATYPE_ESP]));
+ /* send register event to userspace */
+ pfkey_register_reply(SADB_SATYPE_ESP, NULL);
+ }
+
+out:
+ return ret;
+}
+/*
+ * Must be called from user context
+ * used at module load type for testing algo implementation
+ */
+static int ipsec_alg_test_encrypt(int enc_alg, int test) {
+ int ret;
+ caddr_t buf = NULL;
+ int iv_size, keysize, key_e_size;
+ struct ipsec_alg_enc *ixt_e;
+ void *tmp_key_e = NULL;
+ #define BUFSZ 1024
+ #define MARGIN 0
+ #define test_enc (buf+MARGIN)
+ #define test_dec (test_enc+BUFSZ+MARGIN)
+ #define test_tmp (test_dec+BUFSZ+MARGIN)
+ #define test_key_e (test_tmp+BUFSZ+MARGIN)
+ #define test_iv (test_key_e+key_e_size+MARGIN)
+ #define test_key (test_iv+iv_size+MARGIN)
+ #define test_size (BUFSZ*3+key_e_size+iv_size+keysize+MARGIN*7)
+ ixt_e=(struct ipsec_alg_enc *)ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, enc_alg);
+ if (ixt_e==NULL) {
+ KLIPS_PRINT(1,
+ "klips_debug: ipsec_alg_test_encrypt: "
+ "encalg=%d object not found\n",
+ enc_alg);
+ ret=-EINVAL;
+ goto out;
+ }
+ iv_size=ixt_e->ixt_ivlen / 8;
+ key_e_size=ixt_e->ixt_e_ctx_size;
+ keysize=ixt_e->ixt_e_keylen;
+ KLIPS_PRINT(1,
+ "klips_debug: ipsec_alg_test_encrypt: "
+ "enc_alg=%d blocksize=%d key_e_size=%d keysize=%d\n",
+ enc_alg, iv_size, key_e_size, keysize);
+ if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
+ ret= -ENOMEM;
+ goto out;
+ }
+ get_random_bytes(test_key, keysize);
+ get_random_bytes(test_iv, iv_size);
+ if (ixt_e->ixt_e_new_key) {
+ tmp_key_e = ixt_e->ixt_e_new_key(ixt_e, test_key, keysize);
+ ret = tmp_key_e ? 0 : -EINVAL;
+ } else {
+ tmp_key_e = test_key_e;
+ ret = ixt_e->ixt_e_set_key(ixt_e, test_key_e, test_key, keysize);
+ }
+ if (ret < 0)
+ goto out;
+ get_random_bytes(test_enc, BUFSZ);
+ memcpy(test_tmp, test_enc, BUFSZ);
+ ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, tmp_key_e, test_enc, BUFSZ, test_iv, 1);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "cbc_encrypt=1 ret=%d\n",
+ ret);
+ ret=memcmp(test_enc, test_tmp, BUFSZ);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "memcmp(enc, tmp) ret=%d: %s\n", ret,
+ ret!=0? "OK. (encr->DIFFers)" : "FAIL! (encr->SAME)" );
+ memcpy(test_dec, test_enc, BUFSZ);
+ ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, tmp_key_e, test_dec, BUFSZ, test_iv, 0);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "cbc_encrypt=0 ret=%d\n", ret);
+ ret=memcmp(test_dec, test_tmp, BUFSZ);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "memcmp(dec,tmp) ret=%d: %s\n", ret,
+ ret==0? "OK. (encr->decr->SAME)" : "FAIL! (encr->decr->DIFFers)" );
+ {
+ /* Shamelessly taken from drivers/md sources O:) */
+ unsigned long now;
+ int i, count, max=0;
+ int encrypt, speed;
+ for (encrypt=0; encrypt <2;encrypt ++) {
+ for (i = 0; i < 5; i++) {
+ now = jiffies;
+ count = 0;
+ while (jiffies == now) {
+ mb();
+ ixt_e->ixt_e_cbc_encrypt(ixt_e,
+ tmp_key_e, test_tmp,
+ BUFSZ, test_iv, encrypt);
+ mb();
+ count++;
+ mb();
+ }
+ if (count > max)
+ max = count;
+ }
+ speed = max * (HZ * BUFSZ / 1024);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_encrypt: "
+ "%s %s speed=%d KB/s\n",
+ ixt_e->ixt_name,
+ encrypt? "encrypt": "decrypt", speed);
+ }
+ }
+out:
+ if (tmp_key_e && ixt_e->ixt_e_destroy_key) ixt_e->ixt_e_destroy_key(ixt_e, tmp_key_e);
+ if (buf) kfree(buf);
+ if (ixt_e) ipsec_alg_put((struct ipsec_alg *)ixt_e);
+ return ret;
+ #undef test_enc
+ #undef test_dec
+ #undef test_tmp
+ #undef test_key_e
+ #undef test_iv
+ #undef test_key
+ #undef test_size
+}
+/*
+ * Must be called from user context
+ * used at module load type for testing algo implementation
+ */
+static int ipsec_alg_test_auth(int auth_alg, int test) {
+ int ret;
+ caddr_t buf = NULL;
+ int blocksize, keysize, key_a_size;
+ struct ipsec_alg_auth *ixt_a;
+ #define BUFSZ 1024
+ #define MARGIN 0
+ #define test_auth (buf+MARGIN)
+ #define test_key_a (test_auth+BUFSZ+MARGIN)
+ #define test_key (test_key_a+key_a_size+MARGIN)
+ #define test_hash (test_key+keysize+MARGIN)
+ #define test_size (BUFSZ+key_a_size+keysize+AHHMAC_HASHLEN+MARGIN*4)
+ ixt_a=(struct ipsec_alg_auth *)ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, auth_alg);
+ if (ixt_a==NULL) {
+ KLIPS_PRINT(1,
+ "klips_debug: ipsec_alg_test_auth: "
+ "encalg=%d object not found\n",
+ auth_alg);
+ ret=-EINVAL;
+ goto out;
+ }
+ blocksize=ixt_a->ixt_blocksize;
+ key_a_size=ixt_a->ixt_a_ctx_size;
+ keysize=ixt_a->ixt_a_keylen;
+ KLIPS_PRINT(1,
+ "klips_debug: ipsec_alg_test_auth: "
+ "auth_alg=%d blocksize=%d key_a_size=%d keysize=%d\n",
+ auth_alg, blocksize, key_a_size, keysize);
+ if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
+ ret= -ENOMEM;
+ goto out;
+ }
+ get_random_bytes(test_key, keysize);
+ ret = ixt_a->ixt_a_hmac_set_key(ixt_a, test_key_a, test_key, keysize);
+ if (ret < 0 )
+ goto out;
+ get_random_bytes(test_auth, BUFSZ);
+ ret=ixt_a->ixt_a_hmac_hash(ixt_a, test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_auth: "
+ "ret=%d\n", ret);
+ {
+ /* Shamelessly taken from drivers/md sources O:) */
+ unsigned long now;
+ int i, count, max=0;
+ int speed;
+ for (i = 0; i < 5; i++) {
+ now = jiffies;
+ count = 0;
+ while (jiffies == now) {
+ mb();
+ ixt_a->ixt_a_hmac_hash(ixt_a, test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
+ mb();
+ count++;
+ mb();
+ }
+ if (count > max)
+ max = count;
+ }
+ speed = max * (HZ * BUFSZ / 1024);
+ printk(KERN_INFO
+ "klips_info: ipsec_alg_test_auth: "
+ "%s hash speed=%d KB/s\n",
+ ixt_a->ixt_name,
+ speed);
+ }
+out:
+ if (buf) kfree(buf);
+ if (ixt_a) ipsec_alg_put((struct ipsec_alg *)ixt_a);
+ return ret;
+ #undef test_auth
+ #undef test_key_a
+ #undef test_key
+ #undef test_hash
+ #undef test_size
+}
+int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int test) {
+ switch(alg_type) {
+ case IPSEC_ALG_TYPE_ENCRYPT:
+ return ipsec_alg_test_encrypt(alg_id, test);
+ break;
+ case IPSEC_ALG_TYPE_AUTH:
+ return ipsec_alg_test_auth(alg_id, test);
+ break;
+ }
+ printk(KERN_ERR "klips_info: ipsec_alg_test() called incorrectly: "
+ "alg_type=%d alg_id=%d\n",
+ alg_type, alg_id);
+ return -EINVAL;
+}
+int ipsec_alg_init(void) {
+ KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
+ "KLIPS alg v=%d.%d.%d-%d (EALG_MAX=%d, AALG_MAX=%d)\n",
+ IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION),
+ SADB_EALG_MAX, SADB_AALG_MAX);
+ /* Initialize tables */
+ write_lock_bh(&ipsec_alg_lock);
+ ipsec_alg_hash_init();
+ write_unlock_bh(&ipsec_alg_lock);
+ /* Initialize static algos */
+ KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
+ "calling ipsec_alg_static_init()\n");
+ ipsec_alg_static_init();
+ return 0;
+}
+
+/**********************************************
+ *
+ * INTERFACE for ipsec_sa init and wipe
+ *
+ **********************************************/
+
+/*
+ * Called from pluto -> pfkey_v2_parser.c:pfkey_ipsec_sa_init()
+ */
+int ipsec_alg_sa_init(struct ipsec_sa *sa_p) {
+ struct ipsec_alg_enc *ixt_e;
+ struct ipsec_alg_auth *ixt_a;
+
+ /* Only ESP for now ... */
+ if (sa_p->ips_said.proto != IPPROTO_ESP)
+ return -EPROTONOSUPPORT;
+ KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_init() :"
+ "entering for encalg=%d, authalg=%d\n",
+ sa_p->ips_encalg, sa_p->ips_authalg);
+ if ((ixt_e=(struct ipsec_alg_enc *)
+ ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, sa_p->ips_encalg))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug: ipsec_alg_sa_init() :"
+ "found ipsec_alg (ixt_e=%p) for encalg=%d\n",
+ ixt_e, sa_p->ips_encalg);
+ sa_p->ips_alg_enc=ixt_e;
+ }
+ if ((ixt_a=(struct ipsec_alg_auth *)
+ ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, sa_p->ips_authalg))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug: ipsec_alg_sa_init() :"
+ "found ipsec_alg (ixt_a=%p) for auth=%d\n",
+ ixt_a, sa_p->ips_authalg);
+ sa_p->ips_alg_auth=ixt_a;
+ }
+ return 0;
+}
+
+/*
+ * Called from pluto -> ipsec_sa.c:ipsec_sa_delchain()
+ */
+int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p) {
+ struct ipsec_alg *ixt;
+ if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_enc)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_wipe() :"
+ "unlinking for encalg=%d\n",
+ ixt->ixt_alg_id);
+ ipsec_alg_put(ixt);
+ }
+ if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_auth)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_wipe() :"
+ "unlinking for authalg=%d\n",
+ ixt->ixt_alg_id);
+ ipsec_alg_put(ixt);
+ }
+ return 0;
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_xform_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ int len = 0;
+ off_t begin = 0;
+ int i;
+ struct list_head *head;
+ struct ipsec_alg *ixt;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_tncfg_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ for(i = 0, head = ipsec_alg_hash_table; i< IPSEC_ALG_HASHSZ; i++, head++)
+ {
+ struct list_head *p;
+ for (p=head->next; p!=head; p=p->next)
+ {
+ ixt = list_entry(p, struct ipsec_alg, ixt_list);
+ len += ipsec_snprintf(buffer+len, length-len,
+ "VERSION=%d TYPE=%d ID=%d NAME=%s REFCNT=%d ",
+ ixt->ixt_version, ixt->ixt_alg_type, ixt->ixt_alg_id,
+ ixt->ixt_name, ixt->ixt_refcnt);
+
+ len += ipsec_snprintf(buffer+len, length-len,
+ "STATE=%08x BLOCKSIZE=%d IVLEN=%d KEYMINBITS=%d KEYMAXBITS=%d ",
+ ixt->ixt_state, ixt->ixt_blocksize,
+ ixt->ixt_ivlen, ixt->ixt_keyminbits, ixt->ixt_keymaxbits);
+
+ len += ipsec_snprintf(buffer+len, length-len,
+ "IVLEN=%d KEYMINBITS=%d KEYMAXBITS=%d ",
+ ixt->ixt_ivlen, ixt->ixt_keyminbits, ixt->ixt_keymaxbits);
+
+ switch(ixt->ixt_alg_type)
+ {
+ case IPSEC_ALG_TYPE_AUTH:
+ {
+ struct ipsec_alg_auth *auth = (struct ipsec_alg_auth *)ixt;
+
+ len += ipsec_snprintf(buffer+len, length-len,
+ "KEYLEN=%d CTXSIZE=%d AUTHLEN=%d ",
+ auth->ixt_a_keylen, auth->ixt_a_ctx_size,
+ auth->ixt_a_authlen);
+ break;
+ }
+ case IPSEC_ALG_TYPE_ENCRYPT:
+ {
+ struct ipsec_alg_enc *enc = (struct ipsec_alg_enc *)ixt;
+ len += ipsec_snprintf(buffer+len, length-len,
+ "KEYLEN=%d CTXSIZE=%d ",
+ enc->ixt_e_keylen, enc->ixt_e_ctx_size);
+
+ break;
+ }
+ }
+
+ len += ipsec_snprintf(buffer+len, length-len, "\n");
+ }
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length;
+ return len;
+}
+
+/*
+ * As the author of this module, I ONLY ALLOW using it from
+ * GPL (or same LICENSE TERMS as kernel source) modules.
+ *
+ * In respect to hardware crypto engines this means:
+ * * Closed-source device drivers ARE NOT ALLOWED to use
+ * this interface.
+ * * Closed-source VHDL/Verilog firmware running on
+ * the crypto hardware device IS ALLOWED to use this interface
+ * via a GPL (or same LICENSE TERMS as kernel source) device driver.
+ * --Juan Jose Ciarlante 20/03/2002 (thanks RGB for the correct wording)
+ */
+
+/*
+ * These symbols can only be used from GPL modules
+ * for now, I'm disabling this because it creates false
+ * symbol problems for old modutils.
+ */
+
+/* #ifndef EXPORT_SYMBOL_GPL */
+#undef EXPORT_SYMBOL_GPL
+#define EXPORT_SYMBOL_GPL EXPORT_SYMBOL
+/* #endif */
+EXPORT_SYMBOL_GPL(register_ipsec_alg);
+EXPORT_SYMBOL_GPL(unregister_ipsec_alg);
+EXPORT_SYMBOL_GPL(ipsec_alg_test);
+#endif /* CONFIG_IPSEC_ALG */
diff --git a/linux/net/ipsec/ipsec_init.c b/linux/net/ipsec/ipsec_init.c
new file mode 100644
index 000000000..56512acb6
--- /dev/null
+++ b/linux/net/ipsec/ipsec_init.c
@@ -0,0 +1,755 @@
+/*
+ * @(#) Initialization code.
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Richard Guy Briggs <rgb@freeswan.org>
+ * 2001 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * /proc system code was split out into ipsec_proc.c after rev. 1.70.
+ *
+ */
+
+char ipsec_init_c_version[] = "RCSID $Id: ipsec_init.c,v 1.3 2004/06/13 19:57:49 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/in.h> /* struct sockaddr_in */
+#include <linux/skbuff.h>
+#include <linux/random.h> /* get_random_bytes() */
+#include <freeswan.h>
+
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* 23_SPINLOCK */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* 23_SPINLOCK */
+#endif /* SPINLOCK */
+
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif /* NET_21 */
+
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#ifdef CONFIG_PROC_FS
+# include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+#ifdef NETLINK_SOCK
+# include <linux/netlink.h>
+#else
+# include <net/netlink.h>
+#endif
+
+#include "freeswan/radij.h"
+
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_stats.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+
+#include "freeswan/ipsec_rcv.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#ifdef CONFIG_IPSEC_IPCOMP
+# include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#if !defined(CONFIG_IPSEC_ESP) && !defined(CONFIG_IPSEC_AH)
+#error "kernel configuration must include ESP or AH"
+#endif
+
+/*
+ * seems to be present in 2.4.10 (Linus), but also in some RH and other
+ * distro kernels of a lower number.
+ */
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_eroute = 0;
+int debug_spi = 0;
+int debug_netlink = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+struct prng ipsec_prng;
+
+extern int ipsec_device_event(struct notifier_block *dnot, unsigned long event, void *ptr);
+/*
+ * the following structure is required so that we receive
+ * event notifications when network devices are enabled and
+ * disabled (ifconfig up and down).
+ */
+static struct notifier_block ipsec_dev_notifier={
+ ipsec_device_event,
+ NULL,
+ 0
+};
+
+#ifdef CONFIG_SYSCTL
+extern int ipsec_sysctl_register(void);
+extern void ipsec_sysctl_unregister(void);
+#endif
+
+static inline int
+freeswan_inet_add_protocol(struct inet_protocol *prot, unsigned protocol)
+{
+#ifdef NETDEV_25
+ return inet_add_protocol(prot, protocol);
+#else
+ inet_add_protocol(prot);
+ return 0;
+#endif
+}
+
+static inline int
+freeswan_inet_del_protocol(struct inet_protocol *prot, unsigned protocol)
+{
+#ifdef NETDEV_25
+ return inet_del_protocol(prot, protocol);
+#else
+ inet_del_protocol(prot);
+ return 0;
+#endif
+}
+
+/* void */
+int
+ipsec_init(void)
+{
+ int error = 0;
+ unsigned char seed[256];
+#ifdef CONFIG_IPSEC_ENC_3DES
+ extern int des_check_key;
+
+ /* turn off checking of keys */
+ des_check_key=0;
+#endif /* CONFIG_IPSEC_ENC_3DES */
+
+ KLIPS_PRINT(1, "klips_info:ipsec_init: "
+ "KLIPS startup, FreeS/WAN IPSec version: %s\n",
+ ipsec_version_code());
+
+ error |= ipsec_proc_init();
+
+#ifdef SPINLOCK
+ ipsec_sadb.sadb_lock = SPIN_LOCK_UNLOCKED;
+#else /* SPINLOCK */
+ ipsec_sadb.sadb_lock = 0;
+#endif /* SPINLOCK */
+
+#ifndef SPINLOCK
+ tdb_lock.lock = 0;
+ eroute_lock.lock = 0;
+#endif /* !SPINLOCK */
+
+ error |= ipsec_sadb_init();
+ error |= ipsec_radijinit();
+
+ error |= pfkey_init();
+
+ error |= register_netdevice_notifier(&ipsec_dev_notifier);
+
+#ifdef CONFIG_IPSEC_ESP
+ freeswan_inet_add_protocol(&esp_protocol, IPPROTO_ESP);
+#endif /* CONFIG_IPSEC_ESP */
+
+#ifdef CONFIG_IPSEC_AH
+ freeswan_inet_add_protocol(&ah_protocol, IPPROTO_AH);
+#endif /* CONFIG_IPSEC_AH */
+
+/* we never actually link IPCOMP to the stack */
+#ifdef IPCOMP_USED_ALONE
+#ifdef CONFIG_IPSEC_IPCOMP
+ freeswan_inet_add_protocol(&comp_protocol, IPPROTO_COMP);
+#endif /* CONFIG_IPSEC_IPCOMP */
+#endif
+
+ error |= ipsec_tunnel_init_devices();
+
+
+#ifdef CONFIG_SYSCTL
+ error |= ipsec_sysctl_register();
+#endif
+
+#ifdef CONFIG_IPSEC_ALG
+ ipsec_alg_init();
+#endif
+
+ get_random_bytes((void *)seed, sizeof(seed));
+ prng_init(&ipsec_prng, seed, sizeof(seed));
+
+ return error;
+}
+
+
+/* void */
+int
+ipsec_cleanup(void)
+{
+ int error = 0;
+
+#ifdef CONFIG_SYSCTL
+ ipsec_sysctl_unregister();
+#endif
+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:ipsec_cleanup: "
+ "calling ipsec_tunnel_cleanup_devices.\n");
+ error |= ipsec_tunnel_cleanup_devices();
+
+ KLIPS_PRINT(debug_netlink, "called ipsec_tunnel_cleanup_devices");
+
+/* we never actually link IPCOMP to the stack */
+#ifdef IPCOMP_USED_ALONE
+#ifdef CONFIG_IPSEC_IPCOMP
+ if (freeswan_inet_del_protocol(&comp_protocol, IPPROTO_COMP) < 0)
+ printk(KERN_INFO "klips_debug:ipsec_cleanup: "
+ "comp close: can't remove protocol\n");
+#endif /* CONFIG_IPSEC_IPCOMP */
+#endif /* IPCOMP_USED_ALONE */
+
+#ifdef CONFIG_IPSEC_AH
+ if (freeswan_inet_del_protocol(&ah_protocol, IPPROTO_AH) < 0)
+ printk(KERN_INFO "klips_debug:ipsec_cleanup: "
+ "ah close: can't remove protocol\n");
+#endif /* CONFIG_IPSEC_AH */
+
+#ifdef CONFIG_IPSEC_ESP
+ if (freeswan_inet_del_protocol(&esp_protocol, IPPROTO_ESP) < 0)
+ printk(KERN_INFO "klips_debug:ipsec_cleanup: "
+ "esp close: can't remove protocol\n");
+#endif /* CONFIG_IPSEC_ESP */
+
+ error |= unregister_netdevice_notifier(&ipsec_dev_notifier);
+
+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:ipsec_cleanup: "
+ "calling ipsec_sadb_cleanup.\n");
+ error |= ipsec_sadb_cleanup(0);
+ error |= ipsec_sadb_free();
+
+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:ipsec_cleanup: "
+ "calling ipsec_radijcleanup.\n");
+ error |= ipsec_radijcleanup();
+
+ KLIPS_PRINT(debug_pfkey, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:ipsec_cleanup: "
+ "calling pfkey_cleanup.\n");
+ error |= pfkey_cleanup();
+
+ ipsec_proc_cleanup();
+
+ prng_final(&ipsec_prng);
+
+ return error;
+}
+
+#ifdef MODULE
+int
+init_module(void)
+{
+ int error = 0;
+
+ error |= ipsec_init();
+
+ return error;
+}
+
+int
+cleanup_module(void)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
+ "klips_debug:cleanup_module: "
+ "calling ipsec_cleanup.\n");
+
+ error |= ipsec_cleanup();
+
+ KLIPS_PRINT(1, "klips_info:cleanup_module: "
+ "ipsec module unloaded.\n");
+
+ return error;
+}
+#endif /* MODULE */
+
+/*
+ * $Log: ipsec_init.c,v $
+ * Revision 1.3 2004/06/13 19:57:49 as
+ * removed inclusion of ipsec_netlink.h
+ *
+ * Revision 1.2 2004/03/22 21:53:19 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:19 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.89 2003/07/31 22:47:16 mcr
+ * preliminary (untested by FS-team) 2.5 patches.
+ *
+ * Revision 1.88 2003/06/22 20:05:36 mcr
+ * clarified why IPCOMP was not being registered, and put a new
+ * #ifdef in rather than #if 0.
+ *
+ * Revision 1.87 2002/09/20 15:40:51 rgb
+ * Added a lock to the global ipsec_sadb struct for future use.
+ * Split ipsec_sadb_cleanup from new funciton ipsec_sadb_free to avoid problem
+ * of freeing newly created structures when clearing the reftable upon startup
+ * to start from a known state.
+ *
+ * Revision 1.86 2002/08/15 18:39:15 rgb
+ * Move ipsec_prng outside debug code.
+ *
+ * Revision 1.85 2002/05/14 02:35:29 rgb
+ * Change reference to tdb to ipsa.
+ *
+ * Revision 1.84 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.83 2002/04/24 07:36:28 mcr
+ * Moved from ./klips/net/ipsec/ipsec_init.c,v
+ *
+ * Revision 1.82 2002/04/20 00:12:25 rgb
+ * Added esp IV CBC attack fix, disabled.
+ *
+ * Revision 1.81 2002/04/09 16:13:32 mcr
+ * switch license to straight GPL.
+ *
+ * Revision 1.80 2002/03/24 07:34:08 rgb
+ * Sanity check for at least one of AH or ESP configured.
+ *
+ * Revision 1.79 2002/02/05 22:55:15 mcr
+ * added MODULE_LICENSE declaration.
+ * This macro does not appear in all kernel versions (see comment).
+ *
+ * Revision 1.78 2002/01/29 17:17:55 mcr
+ * moved include of ipsec_param.h to after include of linux/kernel.h
+ * otherwise, it seems that some option that is set in ipsec_param.h
+ * screws up something subtle in the include path to kernel.h, and
+ * it complains on the snprintf() prototype.
+ *
+ * Revision 1.77 2002/01/29 04:00:51 mcr
+ * more excise of kversions.h header.
+ *
+ * Revision 1.76 2002/01/29 02:13:17 mcr
+ * introduction of ipsec_kversion.h means that include of
+ * ipsec_param.h must preceed any decisions about what files to
+ * include to deal with differences in kernel source.
+ *
+ * Revision 1.75 2001/11/26 09:23:48 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.74 2001/11/22 05:44:11 henry
+ * new version stuff
+ *
+ * Revision 1.71.2.2 2001/10/22 20:51:00 mcr
+ * explicitely set des_check_key.
+ *
+ * Revision 1.71.2.1 2001/09/25 02:19:39 mcr
+ * /proc manipulation code moved to new ipsec_proc.c
+ *
+ * Revision 1.73 2001/11/06 19:47:17 rgb
+ * Changed lifetime_packets to uint32 from uint64.
+ *
+ * Revision 1.72 2001/10/18 04:45:19 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.71 2001/09/20 15:32:45 rgb
+ * Minor pfkey lifetime fixes.
+ *
+ * Revision 1.70 2001/07/06 19:51:21 rgb
+ * Added inbound policy checking code for IPIP SAs.
+ *
+ * Revision 1.69 2001/06/14 19:33:26 rgb
+ * Silence startup message for console, but allow it to be logged.
+ * Update copyright date.
+ *
+ * Revision 1.68 2001/05/29 05:14:36 rgb
+ * Added PMTU to /proc/net/ipsec_tncfg output. See 'man 5 ipsec_tncfg'.
+ *
+ * Revision 1.67 2001/05/04 16:34:52 rgb
+ * Rremove erroneous checking of return codes for proc_net_* in 2.4.
+ *
+ * Revision 1.66 2001/05/03 19:40:34 rgb
+ * Check error return codes in startup and shutdown.
+ *
+ * Revision 1.65 2001/02/28 05:03:27 rgb
+ * Clean up and rationalise startup messages.
+ *
+ * Revision 1.64 2001/02/27 22:24:53 rgb
+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
+ * Check for satoa() return codes.
+ *
+ * Revision 1.63 2000/11/29 20:14:06 rgb
+ * Add src= to the output of /proc/net/ipsec_spi and delete dst from IPIP.
+ *
+ * Revision 1.62 2000/11/06 04:31:24 rgb
+ * Ditched spin_lock_irqsave in favour of spin_lock_bh.
+ * Fixed longlong for pre-2.4 kernels (Svenning).
+ * Add Svenning's adaptive content compression.
+ * Disabled registration of ipcomp handler.
+ *
+ * Revision 1.61 2000/10/11 13:37:54 rgb
+ * #ifdef out debug print that causes proc/net/ipsec_version to oops.
+ *
+ * Revision 1.60 2000/09/20 03:59:01 rgb
+ * Change static info functions to DEBUG_NO_STATIC to reveal function names
+ * in oopsen.
+ *
+ * Revision 1.59 2000/09/16 01:06:26 rgb
+ * Added cast of var to silence compiler warning about long fed to int
+ * format.
+ *
+ * Revision 1.58 2000/09/15 11:37:01 rgb
+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+ * IPCOMP zlib deflate code.
+ *
+ * Revision 1.57 2000/09/12 03:21:50 rgb
+ * Moved radij_c_version printing to ipsec_version_get_info().
+ * Reformatted ipsec_version_get_info().
+ * Added sysctl_{,un}register() calls.
+ *
+ * Revision 1.56 2000/09/08 19:16:50 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ * Removed all references to CONFIG_IPSEC_PFKEYv2.
+ *
+ * Revision 1.55 2000/08/30 05:19:03 rgb
+ * Cleaned up no longer used spi_next, netlink register/unregister, other
+ * minor cleanup.
+ * Removed cruft replaced by TDB_XFORM_NAME.
+ * Removed all the rest of the references to tdb_spi, tdb_proto, tdb_dst.
+ * Moved debug version strings to printk when /proc/net/ipsec_version is
+ * called.
+ *
+ * Revision 1.54 2000/08/20 18:31:05 rgb
+ * Changed cosmetic alignment in spi_info.
+ * Changed addtime and usetime to use actual value which is relative
+ * anyways, as intended. (Momchil)
+ *
+ * Revision 1.53 2000/08/18 17:37:03 rgb
+ * Added an (int) cast to shut up the compiler...
+ *
+ * Revision 1.52 2000/08/01 14:51:50 rgb
+ * Removed _all_ remaining traces of DES.
+ *
+ * Revision 1.51 2000/07/25 20:41:22 rgb
+ * Removed duplicate parameter in spi_getinfo.
+ *
+ * Revision 1.50 2000/07/17 03:21:45 rgb
+ * Removed /proc/net/ipsec_spinew.
+ *
+ * Revision 1.49 2000/06/28 05:46:51 rgb
+ * Renamed ivlen to iv_bits for consistency.
+ * Changed output of add and use times to be relative to now.
+ *
+ * Revision 1.48 2000/05/11 18:26:10 rgb
+ * Commented out calls to netlink_attach/detach to avoid activating netlink
+ * in the kenrel config.
+ *
+ * Revision 1.47 2000/05/10 22:35:26 rgb
+ * Comment out most of the startup version information.
+ *
+ * Revision 1.46 2000/03/22 16:15:36 rgb
+ * Fixed renaming of dev_get (MB).
+ *
+ * Revision 1.45 2000/03/16 06:40:48 rgb
+ * Hardcode PF_KEYv2 support.
+ *
+ * Revision 1.44 2000/01/22 23:19:20 rgb
+ * Simplified code to use existing macro TDB_XFORM_NAME().
+ *
+ * Revision 1.43 2000/01/21 06:14:04 rgb
+ * Print individual stats only if non-zero.
+ * Removed 'bits' from each keylength for brevity.
+ * Shortened lifetimes legend for brevity.
+ * Changed wording from 'last_used' to the clearer 'idle'.
+ *
+ * Revision 1.42 1999/12/31 14:57:19 rgb
+ * MB fix for new dummy-less proc_get_info in 2.3.35.
+ *
+ * Revision 1.41 1999/11/23 23:04:03 rgb
+ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
+ * Sort out pfkey and freeswan headers, putting them in a library path.
+ *
+ * Revision 1.40 1999/11/18 18:47:01 rgb
+ * Added dynamic proc registration for 2.3.25+.
+ * Changed all device registrations for static linking to
+ * dynamic to reduce the number and size of patches.
+ * Changed all protocol registrations for static linking to
+ * dynamic to reduce the number and size of patches.
+ *
+ * Revision 1.39 1999/11/18 04:12:07 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ * Added Marc Boucher's 2.3.25 proc patches.
+ * Converted all PROC_FS entries to dynamic to reduce kernel patching.
+ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
+ *
+ * Revision 1.38 1999/11/17 15:53:38 rgb
+ * Changed all occurrences of #include "../../../lib/freeswan.h"
+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
+ * klips/net/ipsec/Makefile.
+ *
+ * Revision 1.37 1999/10/16 04:23:06 rgb
+ * Add stats for replaywin_errs, replaywin_max_sequence_difference,
+ * authentication errors, encryption size errors, encryption padding
+ * errors, and time since last packet.
+ *
+ * Revision 1.36 1999/10/16 00:30:47 rgb
+ * Added SA lifetime counting.
+ *
+ * Revision 1.35 1999/10/15 22:14:00 rgb
+ * Clean out cruft.
+ *
+ * Revision 1.34 1999/10/03 18:46:28 rgb
+ * Spinlock fixes for 2.0.xx and 2.3.xx.
+ *
+ * Revision 1.33 1999/10/01 17:08:10 rgb
+ * Disable spinlock init.
+ *
+ * Revision 1.32 1999/10/01 16:22:24 rgb
+ * Switch from assignment init. to functional init. of spinlocks.
+ *
+ * Revision 1.31 1999/10/01 15:44:52 rgb
+ * Move spinlock header include to 2.1> scope.
+ *
+ * Revision 1.30 1999/10/01 00:00:16 rgb
+ * Added eroute structure locking.
+ * Added tdb structure locking.
+ * Minor formatting changes.
+ * Add call to initialize tdb hash table.
+ *
+ * Revision 1.29 1999/09/23 20:22:40 rgb
+ * Enable, tidy and fix network notifier code.
+ *
+ * Revision 1.28 1999/09/18 11:39:56 rgb
+ * Start to add (disabled) netdevice notifier code.
+ *
+ * Revision 1.27 1999/08/28 08:24:47 rgb
+ * Add compiler directives to compile cleanly without debugging.
+ *
+ * Revision 1.26 1999/08/06 16:03:22 rgb
+ * Correct error messages on failure to unload /proc entries.
+ *
+ * Revision 1.25 1999/08/03 17:07:25 rgb
+ * Report device MTU, not private MTU.
+ *
+ * Revision 1.24 1999/05/25 22:24:37 rgb
+ * /PROC/NET/ipsec* init problem fix.
+ *
+ * Revision 1.23 1999/05/25 02:16:38 rgb
+ * Make modular proc_fs entries dynamic and fix for 2.2.x.
+ *
+ * Revision 1.22 1999/05/09 03:25:35 rgb
+ * Fix bug introduced by 2.2 quick-and-dirty patch.
+ *
+ * Revision 1.21 1999/05/05 22:02:30 rgb
+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
+ *
+ * Revision 1.20 1999/04/29 15:15:50 rgb
+ * Fix undetected iv_len reporting bug.
+ * Add sanity checking for null pointer to private data space.
+ * Add return values to init and cleanup functions.
+ *
+ * Revision 1.19 1999/04/27 19:24:44 rgb
+ * Added /proc/net/ipsec_klipsdebug support for reading the current debug
+ * settings.
+ * Instrument module load/init/unload.
+ *
+ * Revision 1.18 1999/04/15 15:37:24 rgb
+ * Forward check changes from POST1_00 branch.
+ *
+ * Revision 1.15.2.3 1999/04/13 20:29:19 rgb
+ * /proc/net/ipsec_* cleanup.
+ *
+ * Revision 1.15.2.2 1999/04/02 04:28:23 rgb
+ * /proc/net/ipsec_* formatting enhancements.
+ *
+ * Revision 1.15.2.1 1999/03/30 17:08:33 rgb
+ * Add pfkey initialisation.
+ *
+ * Revision 1.17 1999/04/11 00:28:57 henry
+ * GPL boilerplate
+ *
+ * Revision 1.16 1999/04/06 04:54:25 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.15 1999/02/24 20:15:07 rgb
+ * Update output format.
+ *
+ * Revision 1.14 1999/02/17 16:49:39 rgb
+ * Convert DEBUG_IPSEC to KLIPS_PRINT
+ * Ditch NET_IPIP dependancy.
+ *
+ * Revision 1.13 1999/01/26 02:06:37 rgb
+ * Remove ah/esp switching on include files.
+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
+ * Removed dead code.
+ * Remove references to INET_GET_PROTOCOL.
+ *
+ * Revision 1.12 1999/01/22 06:19:18 rgb
+ * Cruft clean-out.
+ * 64-bit clean-up.
+ * Added algorithm switch code.
+ *
+ * Revision 1.11 1998/12/01 05:54:53 rgb
+ * Cleanup and order debug version output.
+ *
+ * Revision 1.10 1998/11/30 13:22:54 rgb
+ * Rationalised all the klips kernel file headers. They are much shorter
+ * now and won't conflict under RH5.2.
+ *
+ * Revision 1.9 1998/11/10 05:35:13 rgb
+ * Print direction in/out flag from /proc/net/ipsec_spi.
+ *
+ * Revision 1.8 1998/10/27 13:48:10 rgb
+ * Cleaned up /proc/net/ipsec_* filesystem for easy parsing by scripts.
+ * Fixed less(1) truncated output bug.
+ * Code clean-up.
+ *
+ * Revision 1.7 1998/10/22 06:43:16 rgb
+ * Convert to use satoa for printk.
+ *
+ * Revision 1.6 1998/10/19 14:24:35 rgb
+ * Added inclusion of freeswan.h.
+ *
+ * Revision 1.5 1998/10/09 04:43:35 rgb
+ * Added 'klips_debug' prefix to all klips printk debug statements.
+ *
+ * Revision 1.4 1998/07/27 21:50:22 rgb
+ * Not necessary to traverse mask tree for /proc/net/ipsec_eroute.
+ *
+ * Revision 1.3 1998/06/25 19:51:20 rgb
+ * Clean up #endif comments.
+ * Shift debugging comment control for procfs to debug_tunnel.
+ * Make proc_dir_entries visible to rest of kernel for static link.
+ * Replace hardwired fileperms with macros.
+ * Use macros for procfs inode numbers.
+ * Rearrange initialisations between ipsec_init and module_init as appropriate
+ * for static loading.
+ *
+ * Revision 1.2 1998/06/23 02:55:43 rgb
+ * Slightly quieted init-time messages.
+ * Re-introduced inet_add_protocol after it mysteriously disappeared...
+ * Check for and warn of absence of IPIP protocol on install of module.
+ * Move tdbcleanup to ipsec_xform.c.
+ *
+ * Revision 1.10 1998/06/18 21:29:04 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid kernel
+ * build scripts happier in presence of symbolic links
+ *
+ * Revision 1.9 1998/06/14 23:49:40 rgb
+ * Clarify version reporting on module loading.
+ *
+ * Revision 1.8 1998/06/11 05:54:23 rgb
+ * Added /proc/net/ipsec_version to report freeswan and transform versions.
+ * Added /proc/net/ipsec_spinew to generate new and unique spi's..
+ * Fixed /proc/net/ipsec_tncfg bug.
+ *
+ * Revision 1.7 1998/05/25 20:23:13 rgb
+ * proc_register changed to dynamic registration to avoid arbitrary inode
+ * numbers.
+ *
+ * Implement memory recovery from tdb and eroute tables.
+ *
+ * Revision 1.6 1998/05/21 13:08:58 rgb
+ * Rewrote procinfo subroutines to avoid *bad things* when more that 3k of
+ * information is available for printout.
+ *
+ * Revision 1.5 1998/05/18 21:29:48 rgb
+ * Cleaned up /proc/net/ipsec_* output, including a title line, algorithm
+ * names instead of numbers, standard format for numerical output base,
+ * whitespace for legibility, and the names themselves for consistency.
+ *
+ * Added /proc/net/ipsec_spigrp and /proc/net/ipsec_tncfg.
+ *
+ * Revision 1.4 1998/04/30 15:42:24 rgb
+ * Silencing attach for normal operations with #ifdef IPSEC_DEBUG.
+ *
+ * Revision 1.3 1998/04/21 21:28:58 rgb
+ * Rearrange debug switches to change on the fly debug output from user
+ * space. Only kernel changes checked in at this time. radij.c was also
+ * changed to temporarily remove buggy debugging code in rj_delete causing
+ * an OOPS and hence, netlink device open errors.
+ *
+ * Revision 1.2 1998/04/12 22:03:22 rgb
+ * Updated ESP-3DES-HMAC-MD5-96,
+ * ESP-DES-HMAC-MD5-96,
+ * AH-HMAC-MD5-96,
+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
+ *
+ * Fixed eroute references in /proc/net/ipsec*.
+ *
+ * Started to patch module unloading memory leaks in ipsec_netlink and
+ * radij tree unloading.
+ *
+ * Revision 1.1 1998/04/09 03:06:05 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * No changes.
+ *
+ * Revision 0.3 1996/11/20 14:39:04 ji
+ * Fixed problem with node names of /proc/net entries.
+ * Other minor cleanups.
+ * Rationalized debugging code.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/net/ipsec/ipsec_life.c b/linux/net/ipsec/ipsec_life.c
new file mode 100644
index 000000000..384866c06
--- /dev/null
+++ b/linux/net/ipsec/ipsec_life.c
@@ -0,0 +1,210 @@
+/*
+ * @(#) lifetime structure utilities
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_life.c,v 1.3 2004/04/28 08:06:22 as Exp $
+ *
+ */
+
+/*
+ * This provides series of utility functions for dealing with lifetime
+ * structures.
+ *
+ * ipsec_check_lifetime - returns -1 hard lifetime exceeded
+ * 0 soft lifetime exceeded
+ * 1 everything is okay
+ * based upon whether or not the count exceeds hard/soft
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#ifdef CONFIG_IPSEC_IPCOMP
+#include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+
+
+enum ipsec_life_alive
+ipsec_lifetime_check(struct ipsec_lifetime64 *il64,
+ const char *lifename,
+ const char *saname,
+ enum ipsec_life_type ilt,
+ enum ipsec_direction idir,
+ struct ipsec_sa *ips)
+{
+ __u64 count;
+ const char *dir;
+
+ if(saname == NULL) {
+ saname = "unknown-SA";
+ }
+
+ if(idir == ipsec_incoming) {
+ dir = "incoming";
+ } else {
+ dir = "outgoing";
+ }
+
+
+ if(ilt == ipsec_life_timebased) {
+ count = jiffies/HZ - il64->ipl_count;
+ } else {
+ count = il64->ipl_count;
+ }
+
+ if(il64->ipl_hard &&
+ (count > il64->ipl_hard)) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_lifetime_check: "
+ "hard %s lifetime of SA:<%s%s%s> %s has been reached, SA expired, "
+ "%s packet dropped.\n",
+ lifename,
+ IPS_XFORM_NAME(ips),
+ saname,
+ dir);
+
+ pfkey_expire(ips, 1);
+ return ipsec_life_harddied;
+ }
+
+ if(il64->ipl_soft &&
+ (count > il64->ipl_soft)) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_lifetime_check: "
+ "soft %s lifetime of SA:<%s%s%s> %s has been reached, SA expiring, "
+ "soft expire message sent up, %s packet still processed.\n",
+ lifename,
+ IPS_XFORM_NAME(ips),
+ saname,
+ dir);
+
+ if(ips->ips_state != SADB_SASTATE_DYING) {
+ pfkey_expire(ips, 0);
+ }
+ ips->ips_state = SADB_SASTATE_DYING;
+
+ return ipsec_life_softdied;
+ }
+ return ipsec_life_okay;
+}
+
+
+/*
+ * This function takes a buffer (with length), a lifetime name and type,
+ * and formats a string to represent the current values of the lifetime.
+ *
+ * It returns the number of bytes that the format took (or would take,
+ * if the buffer were large enough: snprintf semantics).
+ * This is used in /proc routines and in debug output.
+ */
+int
+ipsec_lifetime_format(char *buffer,
+ int buflen,
+ char *lifename,
+ enum ipsec_life_type timebaselife,
+ struct ipsec_lifetime64 *lifetime)
+{
+ int len = 0;
+ __u64 count;
+
+ if(timebaselife == ipsec_life_timebased) {
+ count = jiffies/HZ - lifetime->ipl_count;
+ } else {
+ count = lifetime->ipl_count;
+ }
+
+ if(lifetime->ipl_count > 1 ||
+ lifetime->ipl_soft ||
+ lifetime->ipl_hard) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+ len = ipsec_snprintf(buffer, buflen,
+ "%s(%Lu,%Lu,%Lu)",
+ lifename,
+ count,
+ lifetime->ipl_soft,
+ lifetime->ipl_hard);
+#else /* XXX high 32 bits are not displayed */
+ len = ipsec_snprintf(buffer, buflen,
+ "%s(%lu,%lu,%lu)",
+ lifename,
+ (unsigned long)count,
+ (unsigned long)lifetime->ipl_soft,
+ (unsigned long)lifetime->ipl_hard);
+#endif
+ }
+
+ return len;
+}
+
+void
+ipsec_lifetime_update_hard(struct ipsec_lifetime64 *lifetime,
+ __u64 newvalue)
+{
+ if(newvalue &&
+ (!lifetime->ipl_hard ||
+ (newvalue < lifetime->ipl_hard))) {
+ lifetime->ipl_hard = newvalue;
+
+ if(!lifetime->ipl_soft &&
+ (lifetime->ipl_hard < lifetime->ipl_soft)) {
+ lifetime->ipl_soft = lifetime->ipl_hard;
+ }
+ }
+}
+
+void
+ipsec_lifetime_update_soft(struct ipsec_lifetime64 *lifetime,
+ __u64 newvalue)
+{
+ if(newvalue &&
+ (!lifetime->ipl_soft ||
+ (newvalue < lifetime->ipl_soft))) {
+ lifetime->ipl_soft = newvalue;
+
+ if(lifetime->ipl_hard &&
+ (lifetime->ipl_hard < lifetime->ipl_soft)) {
+ lifetime->ipl_soft = lifetime->ipl_hard;
+ }
+ }
+}
diff --git a/linux/net/ipsec/ipsec_mast.c b/linux/net/ipsec/ipsec_mast.c
new file mode 100644
index 000000000..f5216b541
--- /dev/null
+++ b/linux/net/ipsec/ipsec_mast.c
@@ -0,0 +1,1064 @@
+/*
+ * IPSEC MAST code.
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 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 ipsec_mast_c_version[] = "RCSID $Id: ipsec_mast.c,v 1.2 2004/06/13 19:57:49 as Exp $";
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/tcp.h> /* struct tcphdr */
+#include <linux/udp.h> /* struct udphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#include <asm/uaccess.h>
+#include <linux/in6.h>
+#include <net/dst.h>
+#undef dev_kfree_skb
+#define dev_kfree_skb(a,b) kfree_skb(a)
+#define PHYSDEV_TYPE
+#include <asm/checksum.h>
+#include <net/icmp.h> /* icmp_send() */
+#include <net/ip.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <linux/if_arp.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_mast.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+
+int ipsec_maxdevice_count = -1;
+
+DEBUG_NO_STATIC int
+ipsec_mast_open(struct device *dev)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ /*
+ * Can't open until attached.
+ */
+
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_open: "
+ "dev = %s, prv->dev = %s\n",
+ dev->name, prv->dev?prv->dev->name:"NONE");
+
+ if (prv->dev == NULL)
+ return -ENODEV;
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_close(struct device *dev)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static inline int ipsec_mast_xmit2(struct sk_buff *skb)
+{
+ return ip_send(skb);
+}
+
+enum ipsec_xmit_value
+ipsec_mast_send(struct ipsec_xmit_state*ixs)
+{
+ /* new route/dst cache code from James Morris */
+ ixs->skb->dev = ixs->physdev;
+ /*skb_orphan(ixs->skb);*/
+ if((ixs->error = ip_route_output(&ixs->route,
+ ixs->skb->nh.iph->daddr,
+ ixs->pass ? 0 : ixs->skb->nh.iph->saddr,
+ RT_TOS(ixs->skb->nh.iph->tos),
+ ixs->physdev->iflink /* rgb: should this be 0? */))) {
+ ixs->stats->tx_errors++;
+ KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "ip_route_output failed with error code %d, rt->u.dst.dev=%s, dropped\n",
+ ixs->error,
+ ixs->route->u.dst.dev->name);
+ return IPSEC_XMIT_ROUTEERR;
+ }
+ if(ixs->dev == ixs->route->u.dst.dev) {
+ ip_rt_put(ixs->route);
+ /* This is recursion, drop it. */
+ ixs->stats->tx_errors++;
+ KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n",
+ ixs->dev->name);
+ return IPSEC_XMIT_RECURSDETECT;
+ }
+ dst_release(ixs->skb->dst);
+ ixs->skb->dst = &ixs->route->u.dst;
+ ixs->stats->tx_bytes += ixs->skb->len;
+ if(ixs->skb->len < ixs->skb->nh.raw - ixs->skb->data) {
+ ixs->stats->tx_errors++;
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_send: "
+ "tried to __skb_pull nh-data=%ld, %d available. This should never happen, please report.\n",
+ (unsigned long)(ixs->skb->nh.raw - ixs->skb->data),
+ ixs->skb->len);
+ return IPSEC_XMIT_PUSHPULLERR;
+ }
+ __skb_pull(ixs->skb, ixs->skb->nh.raw - ixs->skb->data);
+#ifdef SKB_RESET_NFCT
+ nf_conntrack_put(ixs->skb->nfct);
+ ixs->skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ ixs->skb->nf_debug = 0;
+#endif /* CONFIG_NETFILTER_DEBUG */
+#endif /* SKB_RESET_NFCT */
+ KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "...done, calling ip_send() on device:%s\n",
+ ixs->skb->dev ? ixs->skb->dev->name : "NULL");
+ KLIPS_IP_PRINT(debug_mast & DB_MAST_XMIT, ixs->skb->nh.iph);
+ {
+ int err;
+
+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, ixs->skb, NULL, ixs->route->u.dst.dev,
+ ipsec_mast_xmit2);
+ if(err != NET_XMIT_SUCCESS && err != NET_XMIT_CN) {
+ if(net_ratelimit())
+ printk(KERN_ERR
+ "klips_error:ipsec_xmit_send: "
+ "ip_send() failed, err=%d\n",
+ -err);
+ ixs->stats->tx_errors++;
+ ixs->stats->tx_aborted_errors++;
+ ixs->skb = NULL;
+ return IPSEC_XMIT_IPSENDFAILURE;
+ }
+ }
+ ixs->stats->tx_packets++;
+
+ ixs->skb = NULL;
+
+ return IPSEC_XMIT_OK;
+}
+
+void
+ipsec_mast_cleanup(struct ipsec_xmit_state*ixs)
+{
+#if defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE)
+ netif_wake_queue(ixs->dev);
+#else /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
+ ixs->dev->tbusy = 0;
+#endif /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
+ if(ixs->saved_header) {
+ kfree(ixs->saved_header);
+ }
+ if(ixs->skb) {
+ dev_kfree_skb(ixs->skb, FREE_WRITE);
+ }
+ if(ixs->oskb) {
+ dev_kfree_skb(ixs->oskb, FREE_WRITE);
+ }
+ if (ixs->ips.ips_ident_s.data) {
+ kfree(ixs->ips.ips_ident_s.data);
+ }
+ if (ixs->ips.ips_ident_d.data) {
+ kfree(ixs->ips.ips_ident_d.data);
+ }
+}
+
+#if 0
+/*
+ * This function assumes it is being called from dev_queue_xmit()
+ * and that skb is filled properly by that function.
+ */
+int
+ipsec_mast_start_xmit(struct sk_buff *skb, struct device *dev, IPsecSAref_t SAref)
+{
+ struct ipsec_xmit_state ixs_mem;
+ struct ipsec_xmit_state *ixs = &ixs_mem;
+ enum ipsec_xmit_value stat = IPSEC_XMIT_OK;
+
+ /* dev could be a mast device, but should be optional, I think... */
+ /* SAref is also optional, but one of the two must be present. */
+ /* I wonder if it could accept no device or saref and guess? */
+
+/* ipsec_xmit_sanity_check_dev(ixs); */
+
+ ipsec_xmit_sanity_check_skb(ixs);
+
+ ipsec_xmit_adjust_hard_header(ixs);
+
+ stat = ipsec_xmit_encap_bundle(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ /* SA processing failed */
+ }
+
+ ipsec_xmit_hard_header_restore();
+}
+#endif
+
+DEBUG_NO_STATIC struct net_device_stats *
+ipsec_mast_get_stats(struct device *dev)
+{
+ return &(((struct ipsecpriv *)(dev->priv))->mystats);
+}
+
+/*
+ * Revectored calls.
+ * For each of these calls, a field exists in our private structure.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_mast_hard_header(struct sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+ struct ipsecpriv *prv = dev->priv;
+ struct device *tmp;
+ int ret;
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(skb == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "no skb...\n");
+ return -ENODATA;
+ }
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "no device...\n");
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "skb->dev=%s dev=%s.\n",
+ skb->dev ? skb->dev->name : "NULL",
+ dev->name);
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "no private space associated with dev=%s\n",
+ dev->name ? dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "no physical device associated with dev=%s\n",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ /* check if we have to send a IPv6 packet. It might be a Router
+ Solicitation, where the building of the packet happens in
+ reverse order:
+ 1. ll hdr,
+ 2. IPv6 hdr,
+ 3. ICMPv6 hdr
+ -> skb->nh.raw is still uninitialized when this function is
+ called!! If this is no IPv6 packet, we can print debugging
+ messages, otherwise we skip all debugging messages and just
+ build the ll header */
+ if(type != ETH_P_IPV6) {
+ /* execute this only, if we don't have to build the
+ header for a IPv6 packet */
+ if(!prv->hard_header) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "physical device has been detached, packet dropped 0p%p->0p%p len=%d type=%d dev=%s->NULL ",
+ saddr,
+ daddr,
+ len,
+ type,
+ dev->name);
+ KLIPS_PRINTMORE(debug_mast & DB_MAST_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+#define da ((struct device *)(prv->dev))->dev_addr
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_hard_header: "
+ "Revectored 0p%p->0p%p len=%d type=%d dev=%s->%s dev_addr=%02x:%02x:%02x:%02x:%02x:%02x ",
+ saddr,
+ daddr,
+ len,
+ type,
+ dev->name,
+ prv->dev->name,
+ da[0], da[1], da[2], da[3], da[4], da[5]);
+ KLIPS_PRINTMORE(debug_mast & DB_MAST_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+ } else {
+ KLIPS_PRINT(debug_mast,
+ "klips_debug:ipsec_mast_hard_header: "
+ "is IPv6 packet, skip debugging messages, only revector and build linklocal header.\n");
+ }
+ tmp = skb->dev;
+ skb->dev = prv->dev;
+ ret = prv->hard_header(skb, prv->dev, type, (void *)daddr, (void *)saddr, len);
+ skb->dev = tmp;
+ return ret;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_rebuild_header(struct sk_buff *skb)
+{
+ struct ipsecpriv *prv = skb->dev->priv;
+ struct device *tmp;
+ int ret;
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(skb->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_rebuild_header: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_rebuild_header: "
+ "no private space associated with dev=%s",
+ skb->dev->name ? skb->dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_rebuild_header: "
+ "no physical device associated with dev=%s",
+ skb->dev->name ? skb->dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ if(!prv->rebuild_header) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_rebuild_header: "
+ "physical device has been detached, packet dropped skb->dev=%s->NULL ",
+ skb->dev->name);
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast: "
+ "Revectored rebuild_header dev=%s->%s ",
+ skb->dev->name, prv->dev->name);
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+ tmp = skb->dev;
+ skb->dev = prv->dev;
+
+ ret = prv->rebuild_header(skb);
+ skb->dev = tmp;
+ return ret;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_set_mac_address(struct device *dev, void *addr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ if(!prv->set_mac_address) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_set_mac_address: "
+ "Revectored dev=%s->%s addr=0p%p\n",
+ dev->name, prv->dev->name, addr);
+ return prv->set_mac_address(prv->dev, addr);
+
+}
+
+DEBUG_NO_STATIC void
+ipsec_mast_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_cache_update: "
+ "no device...");
+ return;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_cache_update: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_cache_update: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return;
+ }
+
+ if(!prv->header_cache_update) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_cache_update: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ return;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast: "
+ "Revectored cache_update\n");
+ prv->header_cache_update(hh, prv->dev, haddr);
+ return;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_neigh_setup(struct neighbour *n)
+{
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_neigh_setup:\n");
+
+ if (n->nud_state == NUD_NONE) {
+ n->ops = &arp_broken_ops;
+ n->output = n->ops->output;
+ }
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
+{
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_neigh_setup_dev: "
+ "setting up %s\n",
+ dev ? dev->name : "NULL");
+
+ if (p->tbl->family == AF_INET) {
+ p->neigh_setup = ipsec_mast_neigh_setup;
+ p->ucast_probes = 0;
+ p->mcast_probes = 0;
+ }
+ return 0;
+}
+
+/*
+ * We call the attach routine to attach another device.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_mast_attach(struct device *dev, struct device *physdev)
+{
+ int i;
+ struct ipsecpriv *prv = dev->priv;
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_attach: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_attach: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODATA;
+ }
+
+ prv->dev = physdev;
+ prv->hard_start_xmit = physdev->hard_start_xmit;
+ prv->get_stats = physdev->get_stats;
+
+ if (physdev->hard_header) {
+ prv->hard_header = physdev->hard_header;
+ dev->hard_header = ipsec_mast_hard_header;
+ } else
+ dev->hard_header = NULL;
+
+ if (physdev->rebuild_header) {
+ prv->rebuild_header = physdev->rebuild_header;
+ dev->rebuild_header = ipsec_mast_rebuild_header;
+ } else
+ dev->rebuild_header = NULL;
+
+ if (physdev->set_mac_address) {
+ prv->set_mac_address = physdev->set_mac_address;
+ dev->set_mac_address = ipsec_mast_set_mac_address;
+ } else
+ dev->set_mac_address = NULL;
+
+ if (physdev->header_cache_update) {
+ prv->header_cache_update = physdev->header_cache_update;
+ dev->header_cache_update = ipsec_mast_cache_update;
+ } else
+ dev->header_cache_update = NULL;
+
+ dev->hard_header_len = physdev->hard_header_len;
+
+/* prv->neigh_setup = physdev->neigh_setup; */
+ dev->neigh_setup = ipsec_mast_neigh_setup_dev;
+ dev->mtu = 16260; /* 0xfff0; */ /* dev->mtu; */
+ prv->mtu = physdev->mtu;
+
+#ifdef PHYSDEV_TYPE
+ dev->type = physdev->type; /* ARPHRD_MAST; */
+#endif /* PHYSDEV_TYPE */
+
+ dev->addr_len = physdev->addr_len;
+ for (i=0; i<dev->addr_len; i++) {
+ dev->dev_addr[i] = physdev->dev_addr[i];
+ }
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_mast & DB_MAST_INIT) {
+ printk(KERN_INFO "klips_debug:ipsec_mast_attach: "
+ "physical device %s being attached has HW address: %2x",
+ physdev->name, physdev->dev_addr[0]);
+ for (i=1; i < physdev->addr_len; i++) {
+ printk(":%02x", physdev->dev_addr[i]);
+ }
+ printk("\n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ return 0;
+}
+
+/*
+ * We call the detach routine to detach the ipsec mast from another device.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_mast_detach(struct device *dev)
+{
+ int i;
+ struct ipsecpriv *prv = dev->priv;
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_detach: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
+ "klips_debug:ipsec_mast_detach: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODATA;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_detach: "
+ "physical device %s being detached from virtual device %s\n",
+ prv->dev ? prv->dev->name : "NULL",
+ dev->name);
+
+ prv->dev = NULL;
+ prv->hard_start_xmit = NULL;
+ prv->get_stats = NULL;
+
+ prv->hard_header = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->hard_header = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->rebuild_header = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->rebuild_header = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->set_mac_address = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->set_mac_address = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->header_cache_update = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->header_cache_update = NULL;
+#endif /* DETACH_AND_DOWN */
+
+#ifdef DETACH_AND_DOWN
+ dev->neigh_setup = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ dev->hard_header_len = 0;
+#ifdef DETACH_AND_DOWN
+ dev->mtu = 0;
+#endif /* DETACH_AND_DOWN */
+ prv->mtu = 0;
+ for (i=0; i<MAX_ADDR_LEN; i++) {
+ dev->dev_addr[i] = 0;
+ }
+ dev->addr_len = 0;
+#ifdef PHYSDEV_TYPE
+ dev->type = ARPHRD_VOID; /* ARPHRD_MAST; */
+#endif /* PHYSDEV_TYPE */
+
+ return 0;
+}
+
+/*
+ * We call the clear routine to detach all ipsec masts from other devices.
+ */
+DEBUG_NO_STATIC int
+ipsec_mast_clear(void)
+{
+ int i;
+ struct device *ipsecdev = NULL, *prvdev;
+ struct ipsecpriv *prv;
+ char name[9];
+ int ret;
+
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_clear: .\n");
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ sprintf(name, IPSEC_DEV_FORMAT, i);
+ if((ipsecdev = ipsec_dev_get(name)) != NULL) {
+ if((prv = (struct ipsecpriv *)(ipsecdev->priv))) {
+ prvdev = (struct device *)(prv->dev);
+ if(prvdev) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_clear: "
+ "physical device for device %s is %s\n",
+ name, prvdev->name);
+ if((ret = ipsec_mast_detach(ipsecdev))) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_clear: "
+ "error %d detatching device %s from device %s.\n",
+ ret, name, prvdev->name);
+ return ret;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_mast_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ipsecmastconf *cf = (struct ipsecmastconf *)&ifr->ifr_data;
+ struct ipsecpriv *prv = dev->priv;
+ struct device *them; /* physical device */
+#ifdef CONFIG_IP_ALIAS
+ char *colon;
+ char realphysname[IFNAMSIZ];
+#endif /* CONFIG_IP_ALIAS */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "device not supplied.\n");
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "tncfg service call #%d for dev=%s\n",
+ cmd,
+ dev->name ? dev->name : "NULL");
+ switch (cmd) {
+ /* attach a virtual ipsec? device to a physical device */
+ case IPSEC_SET_DEV:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "calling ipsec_mast_attatch...\n");
+#ifdef CONFIG_IP_ALIAS
+ /* If this is an IP alias interface, get its real physical name */
+ strncpy(realphysname, cf->cf_name, IFNAMSIZ);
+ realphysname[IFNAMSIZ-1] = 0;
+ colon = strchr(realphysname, ':');
+ if (colon) *colon = 0;
+ them = ipsec_dev_get(realphysname);
+#else /* CONFIG_IP_ALIAS */
+ them = ipsec_dev_get(cf->cf_name);
+#endif /* CONFIG_IP_ALIAS */
+
+ if (them == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "physical device %s requested is null\n",
+ cf->cf_name);
+ return -ENXIO;
+ }
+
+#if 0
+ if (them->flags & IFF_UP) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "physical device %s requested is not up.\n",
+ cf->cf_name);
+ return -ENXIO;
+ }
+#endif
+
+ if (prv && prv->dev) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "virtual device is already connected to %s.\n",
+ prv->dev->name ? prv->dev->name : "NULL");
+ return -EBUSY;
+ }
+ return ipsec_mast_attach(dev, them);
+
+ case IPSEC_DEL_DEV:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "calling ipsec_mast_detatch.\n");
+ if (! prv->dev) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "physical device not connected.\n");
+ return -ENODEV;
+ }
+ return ipsec_mast_detach(dev);
+
+ case IPSEC_CLR_DEV:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "calling ipsec_mast_clear.\n");
+ return ipsec_mast_clear();
+
+ default:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_ioctl: "
+ "unknown command %d.\n",
+ cmd);
+ return -EOPNOTSUPP;
+ }
+}
+
+int
+ipsec_mast_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
+{
+ struct device *dev = ptr;
+ struct device *ipsec_dev;
+ struct ipsecpriv *priv;
+ char name[9];
+ int i;
+
+ if (dev == NULL) {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "dev=NULL for event type %ld.\n",
+ event);
+ return(NOTIFY_DONE);
+ }
+
+ /* check for loopback devices */
+ if (dev && (dev->flags & IFF_LOOPBACK)) {
+ return(NOTIFY_DONE);
+ }
+
+ switch (event) {
+ case NETDEV_DOWN:
+ /* look very carefully at the scope of these compiler
+ directives before changing anything... -- RGB */
+
+ case NETDEV_UNREGISTER:
+ switch (event) {
+ case NETDEV_DOWN:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_DOWN dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ if(strncmp(dev->name, "ipsec", strlen("ipsec")) == 0) {
+ printk(KERN_CRIT "IPSEC EVENT: KLIPS device %s shut down.\n",
+ dev->name);
+ }
+ break;
+ case NETDEV_UNREGISTER:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_UNREGISTER dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ break;
+ }
+
+ /* find the attached physical device and detach it. */
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ sprintf(name, IPSEC_DEV_FORMAT, i);
+ ipsec_dev = ipsec_dev_get(name);
+ if(ipsec_dev) {
+ priv = (struct ipsecpriv *)(ipsec_dev->priv);
+ if(priv) {
+ ;
+ if(((struct device *)(priv->dev)) == dev) {
+ /* dev_close(ipsec_dev); */
+ /* return */ ipsec_mast_detach(ipsec_dev);
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "device '%s' has been detached.\n",
+ ipsec_dev->name);
+ break;
+ }
+ } else {
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "device '%s' has no private data space!\n",
+ ipsec_dev->name);
+ }
+ }
+ }
+ break;
+ case NETDEV_UP:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_UP dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_REBOOT:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_REBOOT dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGE:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_CHANGE dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ break;
+ case NETDEV_REGISTER:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_REGISTER dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGEMTU:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_CHANGEMTU dev=%s to mtu=%d\n",
+ dev->name,
+ dev->mtu);
+ break;
+ case NETDEV_CHANGEADDR:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_CHANGEADDR dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_GOING_DOWN:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_GOING_DOWN dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGENAME:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "NETDEV_CHANGENAME dev=%s\n",
+ dev->name);
+ break;
+ default:
+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
+ "klips_debug:ipsec_mast_device_event: "
+ "event type %ld unrecognised for dev=%s\n",
+ event,
+ dev->name);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+/*
+ * Called when an ipsec mast device is initialized.
+ * The ipsec mast device structure is passed to us.
+ */
+
+int
+ipsec_mast_init(struct device *dev)
+{
+ int i;
+
+ KLIPS_PRINT(debug_mast,
+ "klips_debug:ipsec_mast_init: "
+ "allocating %lu bytes initialising device: %s\n",
+ (unsigned long) sizeof(struct ipsecpriv),
+ dev->name ? dev->name : "NULL");
+
+ /* Add our mast functions to the device */
+ dev->open = ipsec_mast_open;
+ dev->stop = ipsec_mast_close;
+ dev->hard_start_xmit = ipsec_mast_start_xmit;
+ dev->get_stats = ipsec_mast_get_stats;
+
+ dev->priv = kmalloc(sizeof(struct ipsecpriv), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset((caddr_t)(dev->priv), 0, sizeof(struct ipsecpriv));
+
+ for(i = 0; i < sizeof(zeroes); i++) {
+ ((__u8*)(zeroes))[i] = 0;
+ }
+
+ dev->set_multicast_list = NULL;
+ dev->do_ioctl = ipsec_mast_ioctl;
+ dev->hard_header = NULL;
+ dev->rebuild_header = NULL;
+ dev->set_mac_address = NULL;
+ dev->header_cache_update= NULL;
+ dev->neigh_setup = ipsec_mast_neigh_setup_dev;
+ dev->hard_header_len = 0;
+ dev->mtu = 0;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_VOID; /* ARPHRD_MAST; */ /* ARPHRD_ETHER; */
+ dev->tx_queue_len = 10; /* Small queue */
+ memset((caddr_t)(dev->broadcast),0xFF, ETH_ALEN); /* what if this is not attached to ethernet? */
+
+ /* New-style flags. */
+ dev->flags = IFF_NOARP /* 0 */ /* Petr Novak */;
+ dev_init_buffers(dev);
+
+ /* We're done. Have I forgotten anything? */
+ return 0;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Module specific interface (but it links with the rest of IPSEC) */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int
+ipsec_mast_probe(struct device *dev)
+{
+ ipsec_mast_init(dev);
+ return 0;
+}
+
+int
+ipsec_mast_init_devices(void)
+{
+ return 0;
+}
+
+/* void */
+int
+ipsec_mast_cleanup_devices(void)
+{
+ int error = 0;
+ int i;
+ char name[10];
+ struct device *dev_mast;
+
+ for(i = 0; i < ipsec_mastdevice_count; i++) {
+ sprintf(name, MAST_DEV_FORMAT, i);
+ if((dev_mast = ipsec_dev_get(name)) == NULL) {
+ break;
+ }
+ unregister_netdev(dev_mast);
+ kfree(dev_mast->priv);
+ dev_mast->priv=NULL;
+ }
+ return error;
+}
diff --git a/linux/net/ipsec/ipsec_md5c.c b/linux/net/ipsec/ipsec_md5c.c
new file mode 100644
index 000000000..41a1551c1
--- /dev/null
+++ b/linux/net/ipsec/ipsec_md5c.c
@@ -0,0 +1,448 @@
+/*
+ * RCSID $Id: ipsec_md5c.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+/*
+ * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
+ * changes to accomodate it in the kernel by ji.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/string.h>
+
+#include "freeswan/ipsec_md5h.h"
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/*
+ * Additions by JI
+ *
+ * HAVEMEMCOPY is defined if mem* routines are available
+ *
+ * HAVEHTON is defined if htons() and htonl() can be used
+ * for big/little endian conversions
+ *
+ */
+
+#define HAVEMEMCOPY
+#ifdef __LITTLE_ENDIAN
+#define LITTLENDIAN
+#endif
+#ifdef __BIG_ENDIAN
+#define BIGENDIAN
+#endif
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+
+#ifdef LITTLEENDIAN
+#define Encode MD5_memcpy
+#define Decode MD5_memcpy
+#else
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+#endif
+
+#ifdef HAVEMEMCOPY
+/* no need to include <memory.h> here; <linux/string.h> defines these */
+#define MD5_memcpy memcpy
+#define MD5_memset memset
+#else
+#ifdef HAVEBCOPY
+#define MD5_memcpy(_a,_b,_c) bcopy((_b),(_a),(_c))
+#define MD5_memset(_a,_b,_c) bzero((_a),(_c))
+#else
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+#endif
+#endif
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/*
+ * MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init(void *vcontext)
+{
+ MD5_CTX *context = vcontext;
+
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (vcontext, input, inputLen)
+ void *vcontext;
+ unsigned char *input; /* input block */
+ __u32 inputLen; /* length of input block */
+{
+ MD5_CTX *context = vcontext;
+ __u32 i;
+ unsigned int index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, vcontext)
+unsigned char digest[16]; /* message digest */
+void *vcontext; /* context */
+{
+ MD5_CTX *context = vcontext;
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ if (digest != NULL) /* Bill Simpson's padding */
+ {
+ /* store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+ }
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+#ifndef LITTLEENDIAN
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#endif
+
+#ifndef HAVEMEMCOPY
+#ifndef HAVEBCOPY
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
+#endif
+
+/*
+ * $Log: ipsec_md5c.c,v $
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.7 2002/09/10 01:45:14 mcr
+ * changed type of MD5_CTX and SHA1_CTX to void * so that
+ * the function prototypes would match, and could be placed
+ * into a pointer to a function.
+ *
+ * Revision 1.6 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.5 2002/04/24 07:36:28 mcr
+ * Moved from ./klips/net/ipsec/ipsec_md5c.c,v
+ *
+ * Revision 1.4 1999/12/13 13:59:12 rgb
+ * Quick fix to argument size to Update bugs.
+ *
+ * Revision 1.3 1999/05/21 18:09:28 henry
+ * unnecessary <memory.h> include causes trouble in 2.2
+ *
+ * Revision 1.2 1999/04/06 04:54:26 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.1 1998/06/18 21:27:48 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/23 20:54:02 rgb
+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
+ * verified.
+ *
+ * Revision 1.1 1998/04/09 03:06:08 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.3 1996/11/20 14:48:53 ji
+ * Release update only.
+ *
+ * Revision 0.2 1996/11/02 00:18:33 ji
+ * First limited release.
+ *
+ *
+ */
diff --git a/linux/net/ipsec/ipsec_proc.c b/linux/net/ipsec/ipsec_proc.c
new file mode 100644
index 000000000..5d2bba554
--- /dev/null
+++ b/linux/net/ipsec/ipsec_proc.c
@@ -0,0 +1,1003 @@
+/*
+ * @(#) /proc file system interface code.
+ *
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * 2001 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * Split out from ipsec_init.c version 1.70.
+ */
+
+char ipsec_proc_c_version[] = "RCSID $Id: ipsec_proc.c,v 1.8 2004/04/28 08:06:22 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/in.h> /* struct sockaddr_in */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef SPINLOCK
+#ifdef SPINLOCK_23
+#include <linux/spinlock.h> /* *lock* */
+#else /* SPINLOCK_23 */
+#include <asm/spinlock.h> /* *lock* */
+#endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+#include <asm/uaccess.h>
+#include <linux/in6.h>
+#endif /* NET_21 */
+#include <asm/checksum.h>
+#include <net/ip.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+#ifdef NETLINK_SOCK
+#include <linux/netlink.h>
+#else
+#include <net/netlink.h>
+#endif
+
+#include "freeswan/radij.h"
+
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_stats.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_xmit.h"
+
+#include "freeswan/ipsec_rcv.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#ifdef CONFIG_IPSEC_IPCOMP
+#include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#include "freeswan/ipsec_proto.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef CONFIG_PROC_FS
+
+#ifdef IPSEC_PROC_SUBDIRS
+static struct proc_dir_entry *proc_net_ipsec_dir = NULL;
+static struct proc_dir_entry *proc_eroute_dir = NULL;
+static struct proc_dir_entry *proc_spi_dir = NULL;
+static struct proc_dir_entry *proc_spigrp_dir = NULL;
+static struct proc_dir_entry *proc_birth_dir = NULL;
+static struct proc_dir_entry *proc_stats_dir = NULL;
+#endif
+
+struct ipsec_birth_reply ipsec_ipv4_birth_packet;
+struct ipsec_birth_reply ipsec_ipv6_birth_packet;
+
+extern int ipsec_xform_get_info(char *buffer, char **start,
+ off_t offset, int length IPSEC_PROC_LAST_ARG);
+
+
+/* ipsec_snprintf: like snprintf except
+ * - size is signed and a negative value is treated as if it were 0
+ * - the returned result is never negative --
+ * an error generates a "?" or null output (depending on space).
+ * (Our callers are too lazy to check for an error return.)
+ *
+ * @param buf String buffer
+ * @param size Size of the string
+ * @param fmt printf string
+ * @param ... Variables to be displayed in fmt
+ * @return int Return code
+ */
+int ipsec_snprintf(char *buf, ssize_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+ size_t possize = size < 0? 0 : size;
+ va_start(args, fmt);
+ i = vsnprintf(buf,possize,fmt,args);
+ va_end(args);
+ if (i < 0) {
+ /* create empty output in place of error */
+ i = 0;
+ if (size > 0) {
+ *buf = '\0';
+ }
+ }
+ return i;
+}
+
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_eroute_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ struct wsbuf w = {buffer, length, offset, 0, 0};
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_radij & DB_RJ_DUMPTREES)
+ rj_dumptrees(); /* XXXXXXXXX */
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_eroute_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ spin_lock_bh(&eroute_lock);
+
+ rj_walktree(rnh, ipsec_rj_walker_procprint, &w);
+/* rj_walktree(mask_rjhead, ipsec_rj_walker_procprint, &w); */
+
+ spin_unlock_bh(&eroute_lock);
+
+ *start = buffer + (offset - w.begin); /* Start of wanted data */
+ return w.len - (offset - w.begin);
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_spi_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ /* Limit of useful snprintf output */
+ const int max_content = length > 0? length-1 : 0;
+
+ int len = 0;
+ off_t begin = 0;
+ int i;
+ struct ipsec_sa *sa_p;
+ char sa[SATOA_BUF];
+ char buf_s[SUBNETTOA_BUF];
+ char buf_d[SUBNETTOA_BUF];
+ size_t sa_len;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_spi_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ spin_lock_bh(&tdb_lock);
+
+
+
+ for (i = 0; i < SADB_HASHMOD; i++) {
+ for (sa_p = ipsec_sadb_hash[i];
+ sa_p;
+ sa_p = sa_p->ips_hnext) {
+ atomic_inc(&sa_p->ips_refcount);
+ sa_len = satoa(sa_p->ips_said, 0, sa, SATOA_BUF);
+ len += ipsec_snprintf(buffer+len, length-len, "%s ",
+ sa_len ? sa : " (error)");
+
+ len += ipsec_snprintf(buffer+len, length-len, "%s%s%s",
+ IPS_XFORM_NAME(sa_p));
+
+ len += ipsec_snprintf(buffer+len, length-len, ": dir=%s",
+ (sa_p->ips_flags & EMT_INBOUND) ?
+ "in " : "out");
+
+ if(sa_p->ips_addr_s) {
+ addrtoa(((struct sockaddr_in*)(sa_p->ips_addr_s))->sin_addr,
+ 0, buf_s, sizeof(buf_s));
+ len += ipsec_snprintf(buffer+len, length-len, " src=%s",
+ buf_s);
+ }
+
+ if((sa_p->ips_said.proto == IPPROTO_IPIP)
+ && (sa_p->ips_flags & SADB_X_SAFLAGS_INFLOW)) {
+ subnettoa(sa_p->ips_flow_s.u.v4.sin_addr,
+ sa_p->ips_mask_s.u.v4.sin_addr,
+ 0,
+ buf_s,
+ sizeof(buf_s));
+
+ subnettoa(sa_p->ips_flow_d.u.v4.sin_addr,
+ sa_p->ips_mask_d.u.v4.sin_addr,
+ 0,
+ buf_d,
+ sizeof(buf_d));
+
+ len += ipsec_snprintf(buffer+len, length-len, " policy=%s->%s",
+ buf_s, buf_d);
+ }
+
+ if(sa_p->ips_iv_bits) {
+ int j;
+ len += ipsec_snprintf(buffer+len, length-len, " iv_bits=%dbits iv=0x",
+ sa_p->ips_iv_bits);
+
+ for(j = 0; j < sa_p->ips_iv_bits / 8; j++) {
+ len += ipsec_snprintf(buffer+len, length-len, "%02x",
+ (__u32)((__u8*)(sa_p->ips_iv))[j]);
+ }
+ }
+
+ if(sa_p->ips_encalg || sa_p->ips_authalg) {
+ if(sa_p->ips_replaywin) {
+ len += ipsec_snprintf(buffer+len, length-len, " ooowin=%d",
+ sa_p->ips_replaywin);
+ }
+ if(sa_p->ips_errs.ips_replaywin_errs) {
+ len += ipsec_snprintf(buffer+len, length-len, " ooo_errs=%d",
+ sa_p->ips_errs.ips_replaywin_errs);
+ }
+ if(sa_p->ips_replaywin_lastseq) {
+ len += ipsec_snprintf(buffer+len, length-len, " seq=%d",
+ sa_p->ips_replaywin_lastseq);
+ }
+ if(sa_p->ips_replaywin_bitmap) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ len += ipsec_snprintf(buffer+len, length-len, " bit=0x%Lx",
+ sa_p->ips_replaywin_bitmap);
+#else
+ len += ipsec_snprintf(buffer+len, length-len, " bit=0x%x%08x",
+ (__u32)(sa_p->ips_replaywin_bitmap >> 32),
+ (__u32)sa_p->ips_replaywin_bitmap);
+#endif
+ }
+ if(sa_p->ips_replaywin_maxdiff) {
+ len += ipsec_snprintf(buffer+len, length-len, " max_seq_diff=%d",
+ sa_p->ips_replaywin_maxdiff);
+ }
+ }
+ if(sa_p->ips_flags & ~EMT_INBOUND) {
+ len += ipsec_snprintf(buffer+len, length-len, " flags=0x%x",
+ sa_p->ips_flags & ~EMT_INBOUND);
+ len += ipsec_snprintf(buffer+len, length-len, "<");
+ /* flag printing goes here */
+ len += ipsec_snprintf(buffer+len, length-len, ">");
+ }
+ if(sa_p->ips_auth_bits) {
+ len += ipsec_snprintf(buffer+len, length-len, " alen=%d",
+ sa_p->ips_auth_bits);
+ }
+ if(sa_p->ips_key_bits_a) {
+ len += ipsec_snprintf(buffer+len, length-len, " aklen=%d",
+ sa_p->ips_key_bits_a);
+ }
+ if(sa_p->ips_errs.ips_auth_errs) {
+ len += ipsec_snprintf(buffer+len, length-len, " auth_errs=%d",
+ sa_p->ips_errs.ips_auth_errs);
+ }
+ if(sa_p->ips_key_bits_e) {
+ len += ipsec_snprintf(buffer+len, length-len, " eklen=%d",
+ sa_p->ips_key_bits_e);
+ }
+ if(sa_p->ips_errs.ips_encsize_errs) {
+ len += ipsec_snprintf(buffer+len, length-len, " encr_size_errs=%d",
+ sa_p->ips_errs.ips_encsize_errs);
+ }
+ if(sa_p->ips_errs.ips_encpad_errs) {
+ len += ipsec_snprintf(buffer+len, length-len, " encr_pad_errs=%d",
+ sa_p->ips_errs.ips_encpad_errs);
+ }
+
+ len += ipsec_snprintf(buffer+len, length-len, " life(c,s,h)=");
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "alloc",
+ ipsec_life_countbased,
+ &sa_p->ips_life.ipl_allocations);
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "bytes",
+ ipsec_life_countbased,
+ &sa_p->ips_life.ipl_bytes);
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "addtime",
+ ipsec_life_timebased,
+ &sa_p->ips_life.ipl_addtime);
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "usetime",
+ ipsec_life_timebased,
+ &sa_p->ips_life.ipl_usetime);
+
+ len += ipsec_lifetime_format(buffer + len,
+ length - len,
+ "packets",
+ ipsec_life_countbased,
+ &sa_p->ips_life.ipl_packets);
+
+ if(sa_p->ips_life.ipl_usetime.ipl_last) { /* XXX-MCR should be last? */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ len += ipsec_snprintf(buffer+len, length-len, " idle=%Ld",
+ jiffies / HZ - sa_p->ips_life.ipl_usetime.ipl_last);
+#else
+ len += ipsec_snprintf(buffer+len, length-len, " idle=%lu",
+ jiffies / HZ - (unsigned long)sa_p->ips_life.ipl_usetime.ipl_last);
+#endif
+ }
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ if(sa_p->ips_said.proto == IPPROTO_COMP &&
+ (sa_p->ips_comp_ratio_dbytes ||
+ sa_p->ips_comp_ratio_cbytes)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ len += ipsec_snprintf(buffer+len, length-len, " ratio=%Ld:%Ld",
+ sa_p->ips_comp_ratio_dbytes,
+ sa_p->ips_comp_ratio_cbytes);
+#else
+ len += ipsec_snprintf(buffer+len, length-len, " ratio=%lu:%lu",
+ (unsigned long)sa_p->ips_comp_ratio_dbytes,
+ (unsigned long)sa_p->ips_comp_ratio_cbytes);
+#endif
+ }
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if(sa_p->ips_natt_type != 0) {
+ char *natttype_name;
+
+ switch(sa_p->ips_natt_type)
+ {
+ case ESPINUDP_WITH_NON_IKE:
+ natttype_name="nonike";
+ break;
+ case ESPINUDP_WITH_NON_ESP:
+ natttype_name="nonesp";
+ break;
+ default:
+ natttype_name="unknown";
+ break;
+ }
+
+ len += ipsec_snprintf(buffer+len, length-len, " natencap=%s",
+ natttype_name);
+
+ len += ipsec_snprintf(buffer+len, length-len, " natsport=%d",
+ sa_p->ips_natt_sport);
+
+ len += ipsec_snprintf(buffer+len, length-len, " natdport=%d",
+ sa_p->ips_natt_dport);
+ }
+#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
+
+ len += ipsec_snprintf(buffer+len, length-len, " refcount=%d",
+ atomic_read(&sa_p->ips_refcount));
+
+ len += ipsec_snprintf(buffer+len, length-len, " ref=%d",
+ sa_p->ips_ref);
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_xform) {
+ len += ipsec_snprintf(buffer+len, length-len, " reftable=%lu refentry=%lu",
+ (unsigned long)IPsecSAref2table(sa_p->ips_ref),
+ (unsigned long)IPsecSAref2entry(sa_p->ips_ref));
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ len += ipsec_snprintf(buffer+len, length-len, "\n");
+
+ atomic_dec(&sa_p->ips_refcount);
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loops */
+ len = max_content; /* truncate crap */
+ goto done_spi_i;
+ } else {
+ const off_t pos = begin + len;
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+ }
+ }
+
+done_spi_i:
+ spin_unlock_bh(&tdb_lock);
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_spigrp_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ /* limit of useful snprintf output */
+ const int max_content = length > 0? length-1 : 0;
+
+ int len = 0;
+ off_t begin = 0;
+ int i;
+ struct ipsec_sa *sa_p, *sa_p2;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_spigrp_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ spin_lock_bh(&tdb_lock);
+
+ for (i = 0; i < SADB_HASHMOD; i++) {
+ for (sa_p = ipsec_sadb_hash[i];
+ sa_p != NULL;
+ sa_p = sa_p->ips_hnext)
+ {
+ atomic_inc(&sa_p->ips_refcount);
+ if(sa_p->ips_inext == NULL) {
+ sa_p2 = sa_p;
+ while(sa_p2 != NULL) {
+ atomic_inc(&sa_p2->ips_refcount);
+ sa_len = satoa(sa_p2->ips_said,
+ 0, sa, SATOA_BUF);
+
+ len += ipsec_snprintf(buffer+len, length-len, "%s ",
+ sa_len ? sa : " (error)");
+ atomic_dec(&sa_p2->ips_refcount);
+ sa_p2 = sa_p2->ips_onext;
+ }
+ len += ipsec_snprintf(buffer+len, length-len, "\n");
+ }
+
+ atomic_dec(&sa_p->ips_refcount);
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loops */
+ len = max_content; /* truncate crap */
+ goto done_spigrp_i;
+ } else {
+ const off_t pos = begin + len;
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+ }
+ }
+
+ done_spigrp_i:
+ spin_unlock_bh(&tdb_lock);
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_tncfg_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ /* limit of useful snprintf output */
+ const int max_content = length > 0? length-1 : 0;
+
+ int len = 0;
+ off_t begin = 0;
+ int i;
+ char name[9];
+ struct device *dev, *privdev;
+ struct ipsecpriv *priv;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_tncfg_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ ipsec_snprintf(name, (ssize_t) sizeof(name), IPSEC_DEV_FORMAT, i);
+ dev = __ipsec_dev_get(name);
+ if(dev) {
+ priv = (struct ipsecpriv *)(dev->priv);
+ len += ipsec_snprintf(buffer+len, length-len, "%s",
+ dev->name);
+ if(priv) {
+ privdev = (struct device *)(priv->dev);
+ len += ipsec_snprintf(buffer+len, length-len, " -> %s",
+ privdev ? privdev->name : "NULL");
+ len += ipsec_snprintf(buffer+len, length-len, " mtu=%d(%d) -> %d",
+ dev->mtu,
+ priv->mtu,
+ privdev ? privdev->mtu : 0);
+ } else {
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_tncfg_get_info: device '%s' has no private data space!\n",
+ dev->name);
+ }
+ len += ipsec_snprintf(buffer+len, length-len, "\n");
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loop */
+ len = max_content; /* truncate crap */
+ break;
+ } else {
+ const off_t pos = begin + len;
+ if (pos <= offset) {
+ len = 0;
+ begin = pos;
+ }
+ }
+ }
+ }
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length;
+ return len;
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_version_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ int len = 0;
+ off_t begin = 0;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ len += ipsec_snprintf(buffer+len, length-len, "strongSwan version: %s\n",
+ ipsec_version_code());
+#if 0
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "ipsec_init version: %s\n",
+ ipsec_init_c_version);
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "ipsec_tunnel version: %s\n",
+ ipsec_tunnel_c_version);
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "ipsec_netlink version: %s\n",
+ ipsec_netlink_c_version);
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_version_get_info: "
+ "radij_c_version: %s\n",
+ radij_c_version);
+#endif
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length;
+ return len;
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_birth_info(char *page,
+ char **start,
+ off_t offset,
+ int count,
+ int *eof,
+ void *data)
+{
+ struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data;
+ int len;
+
+ if(offset >= ibr->packet_template_len) {
+ if(eof) {
+ *eof=1;
+ }
+ return 0;
+ }
+
+ len = ibr->packet_template_len;
+ len -= offset;
+ if (len > count)
+ len = count;
+
+ memcpy(page + offset, ibr->packet_template+offset, len);
+
+ return len;
+}
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_birth_set(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data;
+ int len;
+
+ MOD_INC_USE_COUNT;
+ if(count > IPSEC_BIRTH_TEMPLATE_MAXLEN) {
+ len = IPSEC_BIRTH_TEMPLATE_MAXLEN;
+ } else {
+ len = count;
+ }
+
+ if(copy_from_user(ibr->packet_template, buffer, len)) {
+ MOD_DEC_USE_COUNT;
+ return -EFAULT;
+ }
+ ibr->packet_template_len = len;
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_klipsdebug_get_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length IPSEC_PROC_LAST_ARG)
+{
+ int len = 0;
+ off_t begin = 0;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
+ "klips_debug:ipsec_klipsdebug_get_info: "
+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
+ buffer,
+ *start,
+ (int)offset,
+ length);
+
+ len += ipsec_snprintf(buffer+len, length-len, "debug_tunnel=%08x.\n", debug_tunnel);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_xform=%08x.\n", debug_xform);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_eroute=%08x.\n", debug_eroute);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_spi=%08x.\n", debug_spi);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_radij=%08x.\n", debug_radij);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_esp=%08x.\n", debug_esp);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_ah=%08x.\n", debug_ah);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_rcv=%08x.\n", debug_rcv);
+ len += ipsec_snprintf(buffer+len, length-len, "debug_pfkey=%08x.\n", debug_pfkey);
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length;
+ return len;
+}
+#endif /* CONFIG_IPSEC_DEBUG */
+
+IPSEC_PROCFS_DEBUG_NO_STATIC
+int
+ipsec_stats_get_int_info(char *buffer,
+ char **start,
+ off_t offset,
+ int length,
+ int *eof,
+ void *data)
+{
+ /* Limit of useful snprintf output */
+ const int max_content = length > 0? length-1 : 0;
+
+ int len = 0;
+ int *thing;
+
+ thing = (int *)data;
+
+ len = ipsec_snprintf(buffer+len, length-len, "%08x\n", *thing);
+
+ if (len >= max_content)
+ len = max_content; /* truncate crap */
+
+ *start = buffer + offset; /* Start of wanted data */
+ return len > offset? len - offset : 0;
+}
+
+#ifndef PROC_FS_2325
+struct proc_dir_entry ipsec_eroute =
+{
+ 0,
+ 12, "ipsec_eroute",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_eroute_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+struct proc_dir_entry ipsec_spi =
+{
+ 0,
+ 9, "ipsec_spi",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_spi_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+struct proc_dir_entry ipsec_spigrp =
+{
+ 0,
+ 12, "ipsec_spigrp",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_spigrp_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+struct proc_dir_entry ipsec_tncfg =
+{
+ 0,
+ 11, "ipsec_tncfg",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_tncfg_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+struct proc_dir_entry ipsec_version =
+{
+ 0,
+ 13, "ipsec_version",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_version_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+#ifdef CONFIG_IPSEC_DEBUG
+struct proc_dir_entry ipsec_klipsdebug =
+{
+ 0,
+ 16, "ipsec_klipsdebug",
+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations,
+ ipsec_klipsdebug_get_info,
+ NULL, NULL, NULL, NULL, NULL
+};
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* !PROC_FS_2325 */
+#endif /* CONFIG_PROC_FS */
+
+#if defined(PROC_FS_2325)
+struct ipsec_proc_list {
+ char *name;
+ struct proc_dir_entry **parent;
+ struct proc_dir_entry **dir;
+ read_proc_t *readthing;
+ write_proc_t *writething;
+ void *data;
+};
+static struct ipsec_proc_list proc_items[]={
+#ifdef CONFIG_IPSEC_DEBUG
+ {"klipsdebug", &proc_net_ipsec_dir, NULL, ipsec_klipsdebug_get_info, NULL, NULL},
+#endif
+ {"eroute", &proc_net_ipsec_dir, &proc_eroute_dir, NULL, NULL, NULL},
+ {"all", &proc_eroute_dir, NULL, ipsec_eroute_get_info, NULL, NULL},
+ {"spi", &proc_net_ipsec_dir, &proc_spi_dir, NULL, NULL, NULL},
+ {"all", &proc_spi_dir, NULL, ipsec_spi_get_info, NULL, NULL},
+ {"spigrp", &proc_net_ipsec_dir, &proc_spigrp_dir, NULL, NULL, NULL},
+ {"all", &proc_spigrp_dir, NULL, ipsec_spigrp_get_info, NULL, NULL},
+ {"birth", &proc_net_ipsec_dir, &proc_birth_dir, NULL, NULL, NULL},
+ {"ipv4", &proc_birth_dir, NULL, ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv4_birth_packet},
+ {"ipv6", &proc_birth_dir, NULL, ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv6_birth_packet},
+ {"xforms", &proc_net_ipsec_dir, NULL, ipsec_xform_get_info, NULL, NULL},
+ {"tncfg", &proc_net_ipsec_dir, NULL, ipsec_tncfg_get_info, NULL, NULL},
+ {"stats", &proc_net_ipsec_dir, &proc_stats_dir, NULL, NULL, NULL},
+ {"trap_count", &proc_stats_dir, NULL, ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_count},
+ {"trap_sendcount", &proc_stats_dir, NULL, ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_sendcount},
+ {"version", &proc_net_ipsec_dir, NULL, ipsec_version_get_info, NULL, NULL},
+ {NULL, NULL, NULL, NULL, NULL, NULL}
+};
+#endif
+
+int
+ipsec_proc_init()
+{
+ int error = 0;
+#ifdef IPSEC_PROC_SUBDIRS
+ struct proc_dir_entry *item;
+#endif
+
+ /*
+ * just complain because pluto won't run without /proc!
+ */
+#ifndef CONFIG_PROC_FS
+#error You must have PROC_FS built in to use KLIPS
+#endif
+
+ /* for 2.0 kernels */
+#if !defined(PROC_FS_2325) && !defined(PROC_FS_21)
+ error |= proc_register_dynamic(&proc_net, &ipsec_eroute);
+ error |= proc_register_dynamic(&proc_net, &ipsec_spi);
+ error |= proc_register_dynamic(&proc_net, &ipsec_spigrp);
+ error |= proc_register_dynamic(&proc_net, &ipsec_tncfg);
+ error |= proc_register_dynamic(&proc_net, &ipsec_version);
+#ifdef CONFIG_IPSEC_DEBUG
+ error |= proc_register_dynamic(&proc_net, &ipsec_klipsdebug);
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif
+
+ /* for 2.2 kernels */
+#if !defined(PROC_FS_2325) && defined(PROC_FS_21)
+ error |= proc_register(proc_net, &ipsec_eroute);
+ error |= proc_register(proc_net, &ipsec_spi);
+ error |= proc_register(proc_net, &ipsec_spigrp);
+ error |= proc_register(proc_net, &ipsec_tncfg);
+ error |= proc_register(proc_net, &ipsec_version);
+#ifdef CONFIG_IPSEC_DEBUG
+ error |= proc_register(proc_net, &ipsec_klipsdebug);
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif
+
+ /* for 2.4 kernels */
+#if defined(PROC_FS_2325)
+ /* create /proc/net/ipsec */
+
+ /* zero these out before we initialize /proc/net/ipsec/birth/stuff */
+ memset(&ipsec_ipv4_birth_packet, 0, sizeof(struct ipsec_birth_reply));
+ memset(&ipsec_ipv6_birth_packet, 0, sizeof(struct ipsec_birth_reply));
+
+ proc_net_ipsec_dir = proc_mkdir("ipsec", proc_net);
+ if(proc_net_ipsec_dir == NULL) {
+ /* no point in continuing */
+ return 1;
+ }
+
+ {
+ struct ipsec_proc_list *it;
+
+ it=proc_items;
+ while(it->name!=NULL) {
+ if(it->dir) {
+ /* make a dir instead */
+ item = proc_mkdir(it->name, *it->parent);
+ *it->dir = item;
+ } else {
+ item = create_proc_entry(it->name, 0400, *it->parent);
+ }
+ if(item) {
+ item->read_proc = it->readthing;
+ item->write_proc = it->writething;
+ item->data = it->data;
+#ifdef MODULE
+ item->owner = THIS_MODULE;
+#endif
+ } else {
+ error |= 1;
+ }
+ it++;
+ }
+ }
+
+ /* now create some symlinks to provide compatibility */
+ proc_symlink("ipsec_eroute", proc_net, "ipsec/eroute/all");
+ proc_symlink("ipsec_spi", proc_net, "ipsec/spi/all");
+ proc_symlink("ipsec_spigrp", proc_net, "ipsec/spigrp/all");
+ proc_symlink("ipsec_tncfg", proc_net, "ipsec/tncfg");
+ proc_symlink("ipsec_version",proc_net, "ipsec/version");
+ proc_symlink("ipsec_klipsdebug",proc_net,"ipsec/klipsdebug");
+
+#endif /* !PROC_FS_2325 */
+
+ return error;
+}
+
+void
+ipsec_proc_cleanup()
+{
+
+ /* for 2.0 and 2.2 kernels */
+#if !defined(PROC_FS_2325)
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (proc_net_unregister(ipsec_klipsdebug.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_klipsdebug\n");
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ if (proc_net_unregister(ipsec_version.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_version\n");
+ if (proc_net_unregister(ipsec_eroute.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_eroute\n");
+ if (proc_net_unregister(ipsec_spi.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_spi\n");
+ if (proc_net_unregister(ipsec_spigrp.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_spigrp\n");
+ if (proc_net_unregister(ipsec_tncfg.low_ino) != 0)
+ printk("klips_debug:ipsec_cleanup: "
+ "cannot unregister /proc/net/ipsec_tncfg\n");
+#endif
+
+ /* for 2.4 kernels */
+#if defined(PROC_FS_2325)
+ {
+ struct ipsec_proc_list *it;
+
+ /* find end of list */
+ it=proc_items;
+ while(it->name!=NULL) {
+ it++;
+ }
+ it--;
+
+ do {
+ remove_proc_entry(it->name, *it->parent);
+ it--;
+ } while(it > proc_items);
+ }
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+ remove_proc_entry("ipsec_klipsdebug", proc_net);
+#endif /* CONFIG_IPSEC_DEBUG */
+ remove_proc_entry("ipsec_eroute", proc_net);
+ remove_proc_entry("ipsec_spi", proc_net);
+ remove_proc_entry("ipsec_spigrp", proc_net);
+ remove_proc_entry("ipsec_tncfg", proc_net);
+ remove_proc_entry("ipsec_version", proc_net);
+ remove_proc_entry("ipsec", proc_net);
+#endif /* 2.4 kernel */
+}
+
+
diff --git a/linux/net/ipsec/ipsec_radij.c b/linux/net/ipsec/ipsec_radij.c
new file mode 100644
index 000000000..b20eb7a6f
--- /dev/null
+++ b/linux/net/ipsec/ipsec_radij.c
@@ -0,0 +1,550 @@
+/*
+ * Interface between the IPSEC code and the radix (radij) tree code
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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: ipsec_radij.c,v 1.5 2005/04/10 21:38:32 as Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* 23_SPINLOCK */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* 23_SPINLOCK */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_tunnel.h" /* struct ipsecpriv */
+#include "freeswan/ipsec_xform.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_radij = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+struct radij_node_head *rnh = NULL;
+#ifdef SPINLOCK
+spinlock_t eroute_lock = SPIN_LOCK_UNLOCKED;
+#else /* SPINLOCK */
+spinlock_t eroute_lock;
+#endif /* SPINLOCK */
+
+int
+ipsec_radijinit(void)
+{
+ maj_keylen = sizeof (struct sockaddr_encap);
+
+ rj_init();
+
+ if (rj_inithead((void **)&rnh, /*16*/offsetof(struct sockaddr_encap, sen_type) * sizeof(__u8)) == 0) /* 16 is bit offset of sen_type */
+ return -1;
+ return 0;
+}
+
+int
+ipsec_radijcleanup(void)
+{
+ int error;
+
+ spin_lock_bh(&eroute_lock);
+
+ error = radijcleanup();
+
+ spin_unlock_bh(&eroute_lock);
+
+ return error;
+}
+
+int
+ipsec_cleareroutes(void)
+{
+ int error;
+
+ spin_lock_bh(&eroute_lock);
+
+ error = radijcleartree();
+
+ spin_unlock_bh(&eroute_lock);
+
+ return error;
+}
+
+int
+ipsec_breakroute(struct sockaddr_encap *eaddr,
+ struct sockaddr_encap *emask,
+ struct sk_buff **first,
+ struct sk_buff **last)
+{
+ struct eroute *ro;
+ struct radij_node *rn;
+ int error;
+#ifdef CONFIG_IPSEC_DEBUG
+
+ if (debug_eroute) {
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+
+ subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_breakroute: "
+ "attempting to delete eroute for %s:%d->%s:%d %d\n",
+ buf1, ntohs(eaddr->sen_sport),
+ buf2, ntohs(eaddr->sen_dport), eaddr->sen_proto);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ spin_lock_bh(&eroute_lock);
+
+ if ((error = rj_delete(eaddr, emask, rnh, &rn)) != 0) {
+ spin_unlock_bh(&eroute_lock);
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_breakroute: "
+ "node not found, eroute delete failed.\n");
+ return error;
+ }
+
+ spin_unlock_bh(&eroute_lock);
+
+ ro = (struct eroute *)rn;
+
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_breakroute: "
+ "deleted eroute=0p%p, ident=0p%p->0p%p, first=0p%p, last=0p%p\n",
+ ro,
+ ro->er_ident_s.data,
+ ro->er_ident_d.data,
+ ro->er_first,
+ ro->er_last);
+
+ if (ro->er_ident_s.data != NULL) {
+ kfree(ro->er_ident_s.data);
+ }
+ if (ro->er_ident_d.data != NULL) {
+ kfree(ro->er_ident_d.data);
+ }
+ if (ro->er_first != NULL) {
+#if 0
+ struct net_device_stats *stats = (struct net_device_stats *) &(((struct ipsecpriv *)(ro->er_first->dev->priv))->mystats);
+ stats->tx_dropped--;
+#endif
+ *first = ro->er_first;
+ }
+ if (ro->er_last != NULL) {
+#if 0
+ struct net_device_stats *stats = (struct net_device_stats *) &(((struct ipsecpriv *)(ro->er_last->dev->priv))->mystats);
+ stats->tx_dropped--;
+#endif
+ *last = ro->er_last;
+ }
+
+ if (rn->rj_flags & (RJF_ACTIVE | RJF_ROOT))
+ panic ("ipsec_breakroute RMT_DELEROUTE root or active node\n");
+ memset((caddr_t)rn, 0, sizeof (struct eroute));
+ kfree(rn);
+
+ return 0;
+}
+
+int
+ipsec_makeroute(struct sockaddr_encap *eaddr,
+ struct sockaddr_encap *emask,
+ struct sa_id said,
+ uint32_t pid,
+ struct sk_buff *skb,
+ struct ident *ident_s,
+ struct ident *ident_d)
+{
+ struct eroute *retrt;
+ int error;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+#ifdef CONFIG_IPSEC_DEBUG
+
+ if (debug_eroute) {
+ {
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+
+ subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
+ sa_len = satoa(said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "attempting to allocate %lu bytes to insert eroute for %s:%d->%s:%d %d, SA: %s, PID:%d, skb=0p%p, ident:%s->%s\n",
+ (unsigned long) sizeof(struct eroute),
+ buf1, ntohs(eaddr->sen_sport),
+ buf2, ntohs(eaddr->sen_dport),
+ eaddr->sen_proto,
+ sa_len ? sa : " (error)",
+ pid,
+ skb,
+ (ident_s ? (ident_s->data ? ident_s->data : "NULL") : "NULL"),
+ (ident_d ? (ident_d->data ? ident_d->data : "NULL") : "NULL"));
+ }
+ {
+ char buf1[sizeof(struct sockaddr_encap)*2 + 1];
+ char buf2[sizeof(struct sockaddr_encap)*2 + 1];
+ int i;
+ unsigned char *b1 = buf1,
+ *b2 = buf2,
+ *ea = (unsigned char *)eaddr,
+ *em = (unsigned char *)emask;
+
+ for (i=0; i<sizeof(struct sockaddr_encap); i++) {
+ sprintf(b1, "%02x", ea[i]);
+ sprintf(b2, "%02x", em[i]);
+ b1+=2;
+ b2+=2;
+ }
+ KLIPS_PRINT(debug_eroute, "klips_debug:ipsec_makeroute: %s / %s \n", buf1, buf2);
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ retrt = (struct eroute *)kmalloc(sizeof (struct eroute), GFP_ATOMIC);
+ if (retrt == NULL) {
+ printk("klips_error:ipsec_makeroute: "
+ "not able to allocate kernel memory");
+ return -ENOMEM;
+ }
+ memset((caddr_t)retrt, 0, sizeof (struct eroute));
+
+ retrt->er_eaddr = *eaddr;
+ retrt->er_emask = *emask;
+ retrt->er_said = said;
+ retrt->er_pid = pid;
+ retrt->er_count = 0;
+ retrt->er_lasttime = jiffies/HZ;
+ {
+ struct sockaddr_encap **rkeyp = (struct sockaddr_encap**)&((retrt->er_rjt).rd_nodes->rj_key);
+ *rkeyp = &(retrt->er_eaddr);
+ }
+
+ if (ident_s && ident_s->type != SADB_IDENTTYPE_RESERVED) {
+ int data_len = ident_s->len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ retrt->er_ident_s.type = ident_s->type;
+ retrt->er_ident_s.id = ident_s->id;
+ retrt->er_ident_s.len = ident_s->len;
+ if(data_len) {
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "attempting to allocate %u bytes for ident_s.\n",
+ data_len);
+ if(!(retrt->er_ident_s.data = kmalloc(data_len, GFP_KERNEL))) {
+ kfree(retrt);
+ printk("klips_error:ipsec_makeroute: not able to allocate kernel memory (%d)\n", data_len);
+ return ENOMEM;
+ }
+ memcpy(retrt->er_ident_s.data, ident_s->data, data_len);
+ } else {
+ retrt->er_ident_s.data = NULL;
+ }
+ }
+
+ if (ident_d && ident_d->type != SADB_IDENTTYPE_RESERVED) {
+ int data_len = ident_d->len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ retrt->er_ident_d.type = ident_d->type;
+ retrt->er_ident_d.id = ident_d->id;
+ retrt->er_ident_d.len = ident_d->len;
+ if(data_len) {
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "attempting to allocate %u bytes for ident_d.\n",
+ data_len);
+ if(!(retrt->er_ident_d.data = kmalloc(data_len, GFP_KERNEL))) {
+ if (retrt->er_ident_s.data)
+ kfree(retrt->er_ident_s.data);
+ kfree(retrt);
+ printk("klips_error:ipsec_makeroute: not able to allocate kernel memory (%d)\n", data_len);
+ return ENOMEM;
+ }
+ memcpy(retrt->er_ident_d.data, ident_d->data, data_len);
+ } else {
+ retrt->er_ident_d.data = NULL;
+ }
+ }
+ retrt->er_first = skb;
+ retrt->er_last = NULL;
+
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "calling rj_addroute now\n");
+
+ spin_lock_bh(&eroute_lock);
+
+ error = rj_addroute(&(retrt->er_eaddr), &(retrt->er_emask),
+ rnh, retrt->er_rjt.rd_nodes);
+
+ spin_unlock_bh(&eroute_lock);
+
+ if(error) {
+ sa_len = satoa(said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "rj_addroute not able to insert eroute for SA:%s (error:%d)\n",
+ sa_len ? sa : " (error)", error);
+ if (retrt->er_ident_s.data)
+ kfree(retrt->er_ident_s.data);
+ if (retrt->er_ident_d.data)
+ kfree(retrt->er_ident_d.data);
+
+ kfree(retrt);
+
+ return error;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_eroute) {
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+/*
+ subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
+*/
+ subnettoa(rd_key((&(retrt->er_rjt)))->sen_ip_src, rd_mask((&(retrt->er_rjt)))->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(rd_key((&(retrt->er_rjt)))->sen_ip_dst, rd_mask((&(retrt->er_rjt)))->sen_ip_dst, 0, buf2, sizeof(buf2));
+ sa_len = satoa(retrt->er_said, 0, sa, SATOA_BUF);
+
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "pid=%05d "
+ "count=%10d "
+ "lasttime=%6d "
+ "%-18s -> %-18s => %s\n",
+ retrt->er_pid,
+ retrt->er_count,
+ (int)(jiffies/HZ - retrt->er_lasttime),
+ buf1,
+ buf2,
+ sa_len ? sa : " (error)");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_makeroute: "
+ "succeeded.\n");
+ return 0;
+}
+
+struct eroute *
+ipsec_findroute(struct sockaddr_encap *eaddr)
+{
+ struct radij_node *rn;
+#ifdef CONFIG_IPSEC_DEBUG
+ char buf1[ADDRTOA_BUF], buf2[ADDRTOA_BUF];
+
+ if (debug_radij & DB_RJ_FINDROUTE) {
+ addrtoa(eaddr->sen_ip_src, 0, buf1, sizeof(buf1));
+ addrtoa(eaddr->sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_eroute,
+ "klips_debug:ipsec_findroute: "
+ "%s:%d->%s:%d %d\n",
+ buf1, ntohs(eaddr->sen_sport),
+ buf2, ntohs(eaddr->sen_dport),
+ eaddr->sen_proto);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ rn = rj_match((caddr_t)eaddr, rnh);
+ if(rn) {
+ KLIPS_PRINT(debug_eroute && sysctl_ipsec_debug_verbose,
+ "klips_debug:ipsec_findroute: "
+ "found, points to proto=%d, spi=%x, dst=%x.\n",
+ ((struct eroute*)rn)->er_said.proto,
+ ntohl(((struct eroute*)rn)->er_said.spi),
+ ntohl(((struct eroute*)rn)->er_said.dst.s_addr));
+ }
+ return (struct eroute *)rn;
+}
+
+#ifdef CONFIG_PROC_FS
+/** ipsec_rj_walker_procprint: print one line of eroute table output.
+ *
+ * Theoretical BUG: if w->length is less than the length
+ * of some line we should produce, that line will never
+ * be finished. In effect, the "file" will stop part way
+ * through that line.
+ */
+int
+ipsec_rj_walker_procprint(struct radij_node *rn, void *w0)
+{
+ struct eroute *ro = (struct eroute *)rn;
+ struct rjtentry *rd = (struct rjtentry *)rn;
+ struct wsbuf *w = (struct wsbuf *)w0;
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+ char buf3[16];
+ char sa[SATOA_BUF];
+ size_t sa_len, buf_len;
+ struct sockaddr_encap *key, *mask;
+
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:ipsec_rj_walker_procprint: "
+ "rn=0p%p, w0=0p%p\n",
+ rn,
+ w0);
+ if (rn->rj_b >= 0) {
+ return 0;
+ }
+
+ key = rd_key(rd);
+ mask = rd_mask(rd);
+
+ if (key == NULL || mask == NULL) {
+ return 0;
+ }
+
+ buf_len = subnettoa(key->sen_ip_src, mask->sen_ip_src, 0, buf1, sizeof(buf1));
+ if(key->sen_sport != 0) {
+ sprintf(buf1+buf_len-1, ":%d", ntohs(key->sen_sport));
+ }
+
+ buf_len = subnettoa(key->sen_ip_dst, mask->sen_ip_dst, 0, buf2, sizeof(buf2));
+ if(key->sen_dport != 0) {
+ sprintf(buf2+buf_len-1, ":%d", ntohs(key->sen_dport));
+ }
+
+ buf3[0]='\0';
+ if(key->sen_proto != 0) {
+ sprintf(buf3, ":%d", key->sen_proto);
+ }
+
+ sa_len = satoa(ro->er_said, 0, sa, SATOA_BUF);
+
+ w->len += ipsec_snprintf(w->buffer + w->len,
+ w->length - w->len,
+ "%-10d "
+ "%-18s -> %-18s => %s%s\n",
+ ro->er_count,
+ buf1,
+ buf2,
+ sa_len ? sa : " (error)",
+ buf3);
+
+ {
+ /* snprintf can only fill the last character with NUL
+ * so the maximum useful character is w->length-1.
+ * However, if w->length == 0, we cannot go back.
+ * (w->length surely cannot be negative.)
+ */
+ int max_content = w->length > 0? w->length-1 : 0;
+
+ if (w->len >= max_content) {
+ /* we've done all that can fit -- stop treewalking */
+ w->len = max_content; /* truncate crap */
+ return -ENOBUFS;
+ } else {
+ const off_t pos = w->begin + w->len; /* file position of end of what we've generated */
+
+ if (pos <= w->offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ w->len = 0;
+ w->begin = pos;
+ }
+ return 0;
+ }
+ }
+}
+#endif /* CONFIG_PROC_FS */
+
+int
+ipsec_rj_walker_delete(struct radij_node *rn, void *w0)
+{
+ struct eroute *ro;
+ struct rjtentry *rd = (struct rjtentry *)rn;
+ struct radij_node *rn2;
+ int error;
+ struct sockaddr_encap *key, *mask;
+
+ key = rd_key(rd);
+ mask = rd_mask(rd);
+
+ if(!key || !mask) {
+ return -ENODATA;
+ }
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_radij) {
+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
+
+ subnettoa(key->sen_ip_src, mask->sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(key->sen_ip_dst, mask->sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:ipsec_rj_walker_delete: "
+ "deleting: %s -> %s\n",
+ buf1,
+ buf2);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ if((error = rj_delete(key, mask, rnh, &rn2))) {
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:ipsec_rj_walker_delete: "
+ "rj_delete failed with error=%d.\n", error);
+ return error;
+ }
+
+ if(rn2 != rn) {
+ printk("klips_debug:ipsec_rj_walker_delete: "
+ "tried to delete a different node?!? This should never happen!\n");
+ }
+
+ ro = (struct eroute *)rn;
+
+ if (ro->er_ident_s.data)
+ kfree(ro->er_ident_s.data);
+ if (ro->er_ident_d.data)
+ kfree(ro->er_ident_d.data);
+
+ memset((caddr_t)rn, 0, sizeof (struct eroute));
+ kfree(rn);
+
+ return 0;
+}
+
diff --git a/linux/net/ipsec/ipsec_rcv.c b/linux/net/ipsec/ipsec_rcv.c
new file mode 100644
index 000000000..4df839fe2
--- /dev/null
+++ b/linux/net/ipsec/ipsec_rcv.c
@@ -0,0 +1,2204 @@
+/*
+ * receive code
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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.
+ */
+
+char ipsec_rcv_c_version[] = "RCSID $Id: ipsec_rcv.c,v 1.5 2005/04/10 21:38:32 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define proto_priv cb
+#endif /* NET21 */
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h"
+
+#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
+#include "freeswan/ipsec_ah.h"
+#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
+
+#ifdef CONFIG_IPSEC_ESP
+#include "freeswan/ipsec_esp.h"
+#endif /* !CONFIG_IPSEC_ESP */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+#include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_COMP */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_ah = 0;
+int debug_esp = 0;
+int debug_rcv = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+int sysctl_ipsec_inbound_policy_check = 1;
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+#include <linux/udp.h>
+#endif
+
+#ifdef CONFIG_IPSEC_DEBUG
+static void
+rcv_dmp(char *s, caddr_t bb, int len)
+{
+ int i;
+ unsigned char *b = bb;
+
+ if (debug_rcv && sysctl_ipsec_debug_verbose) {
+ printk(KERN_INFO "klips_debug:ipsec_tunnel_:dmp: "
+ "at %s, len=%d:",
+ s,
+ len);
+ for (i=0; i < len; i++) {
+ if(!(i%16)){
+ printk("\nklips_debug: ");
+ }
+ printk(" %02x", *b++);
+ }
+ printk("\n");
+ }
+}
+#else /* CONFIG_IPSEC_DEBUG */
+#define rcv_dmp(_x, _y, _z)
+#endif /* CONFIG_IPSEC_DEBUG */
+
+
+#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
+__u32 zeroes[AH_AMAX];
+#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
+
+/*
+ * Check-replay-window routine, adapted from the original
+ * by J. Hughes, from draft-ietf-ipsec-esp-des-md5-03.txt
+ *
+ * This is a routine that implements a 64 packet window. This is intend-
+ * ed on being an implementation sample.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_checkreplaywindow(struct ipsec_sa*ipsp, __u32 seq)
+{
+ __u32 diff;
+
+ if (ipsp->ips_replaywin == 0) /* replay shut off */
+ return 1;
+ if (seq == 0)
+ return 0; /* first == 0 or wrapped */
+
+ /* new larger sequence number */
+ if (seq > ipsp->ips_replaywin_lastseq) {
+ return 1; /* larger is good */
+ }
+ diff = ipsp->ips_replaywin_lastseq - seq;
+
+ /* too old or wrapped */ /* if wrapped, kill off SA? */
+ if (diff >= ipsp->ips_replaywin) {
+ return 0;
+ }
+ /* this packet already seen */
+ if (ipsp->ips_replaywin_bitmap & (1 << diff))
+ return 0;
+ return 1; /* out of order but good */
+}
+
+DEBUG_NO_STATIC int
+ipsec_updatereplaywindow(struct ipsec_sa*ipsp, __u32 seq)
+{
+ __u32 diff;
+
+ if (ipsp->ips_replaywin == 0) /* replay shut off */
+ return 1;
+ if (seq == 0)
+ return 0; /* first == 0 or wrapped */
+
+ /* new larger sequence number */
+ if (seq > ipsp->ips_replaywin_lastseq) {
+ diff = seq - ipsp->ips_replaywin_lastseq;
+
+ /* In win, set bit for this pkt */
+ if (diff < ipsp->ips_replaywin)
+ ipsp->ips_replaywin_bitmap =
+ (ipsp->ips_replaywin_bitmap << diff) | 1;
+ else
+ /* This packet has way larger seq num */
+ ipsp->ips_replaywin_bitmap = 1;
+
+ if(seq - ipsp->ips_replaywin_lastseq - 1 > ipsp->ips_replaywin_maxdiff) {
+ ipsp->ips_replaywin_maxdiff = seq - ipsp->ips_replaywin_lastseq - 1;
+ }
+ ipsp->ips_replaywin_lastseq = seq;
+ return 1; /* larger is good */
+ }
+ diff = ipsp->ips_replaywin_lastseq - seq;
+
+ /* too old or wrapped */ /* if wrapped, kill off SA? */
+ if (diff >= ipsp->ips_replaywin) {
+/*
+ if(seq < 0.25*max && ipsp->ips_replaywin_lastseq > 0.75*max) {
+ ipsec_sa_delchain(ipsp);
+ }
+*/
+ return 0;
+ }
+ /* this packet already seen */
+ if (ipsp->ips_replaywin_bitmap & (1 << diff))
+ return 0;
+ ipsp->ips_replaywin_bitmap |= (1 << diff); /* mark as seen */
+ return 1; /* out of order but good */
+}
+
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+struct auth_alg ipsec_rcv_md5[]={
+ {MD5Init, MD5Update, MD5Final, AHMD596_ALEN}
+};
+
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+struct auth_alg ipsec_rcv_sha1[]={
+ {SHA1Init, SHA1Update, SHA1Final, AHSHA196_ALEN}
+};
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+
+enum ipsec_rcv_value {
+ IPSEC_RCV_LASTPROTO=1,
+ IPSEC_RCV_OK=0,
+ IPSEC_RCV_BADPROTO=-1,
+ IPSEC_RCV_BADLEN=-2,
+ IPSEC_RCV_ESP_BADALG=-3,
+ IPSEC_RCV_3DES_BADBLOCKING=-4,
+ IPSEC_RCV_ESP_DECAPFAIL=-5,
+ IPSEC_RCV_DECAPFAIL=-6,
+ IPSEC_RCV_SAIDNOTFOUND=-7,
+ IPSEC_RCV_IPCOMPALONE=-8,
+ IPSEC_RCV_IPCOMPFAILED=-10,
+ IPSEC_RCV_SAIDNOTLIVE=-11,
+ IPSEC_RCV_FAILEDINBOUND=-12,
+ IPSEC_RCV_LIFETIMEFAILED=-13,
+ IPSEC_RCV_BADAUTH=-14,
+ IPSEC_RCV_REPLAYFAILED=-15,
+ IPSEC_RCV_AUTHFAILED=-16,
+ IPSEC_RCV_REPLAYROLLED=-17,
+ IPSEC_RCV_BAD_DECRYPT=-18
+};
+
+struct ipsec_rcv_state {
+ struct sk_buff *skb;
+ struct net_device_stats *stats;
+ struct iphdr *ipp;
+ struct ipsec_sa *ipsp;
+ int len;
+ int ilen;
+ int authlen;
+ int hard_header_len;
+ int iphlen;
+ struct auth_alg *authfuncs;
+ struct sa_id said;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ __u8 next_header;
+ __u8 hash[AH_AMAX];
+ char ipsaddr_txt[ADDRTOA_BUF];
+ char ipdaddr_txt[ADDRTOA_BUF];
+ __u8 *octx;
+ __u8 *ictx;
+ int ictx_len;
+ int octx_len;
+ union {
+ struct {
+ struct esphdr *espp;
+ } espstuff;
+ struct {
+ struct ahhdr *ahp;
+ } ahstuff;
+ struct {
+ struct ipcomphdr *compp;
+ } ipcompstuff;
+ } protostuff;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ __u16 natt_len;
+ __u16 natt_sport;
+ __u16 natt_dport;
+ __u8 natt_type;
+#endif
+};
+
+struct xform_functions {
+ enum ipsec_rcv_value (*checks)(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb);
+ enum ipsec_rcv_value (*decrypt)(struct ipsec_rcv_state *irs);
+
+ enum ipsec_rcv_value (*setup_auth)(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb,
+ __u32 *replay,
+ unsigned char **authenticator);
+ enum ipsec_rcv_value (*calc_auth)(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb);
+};
+
+#ifdef CONFIG_IPSEC_ESP
+enum ipsec_rcv_value
+ipsec_rcv_esp_checks(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ __u8 proto;
+ int len; /* packet length */
+
+ len = skb->len;
+ proto = irs->ipp->protocol;
+
+ /* XXX this will need to be 8 for IPv6 */
+ if ((proto == IPPROTO_ESP) && ((len - irs->iphlen) % 4)) {
+ printk("klips_error:ipsec_rcv: "
+ "got packet with content length = %d from %s -- should be on 4 octet boundary, packet dropped\n",
+ len - irs->iphlen,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ if(skb->len < (irs->hard_header_len + sizeof(struct iphdr) + sizeof(struct esphdr))) {
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "runt esp packet of skb->len=%d received from %s, dropped.\n",
+ skb->len,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ irs->protostuff.espstuff.espp = (struct esphdr *)(skb->data + irs->iphlen);
+ irs->said.spi = irs->protostuff.espstuff.espp->esp_spi;
+
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_esp_decrypt_setup(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb,
+ __u32 *replay,
+ unsigned char **authenticator)
+{
+ struct esphdr *espp = irs->protostuff.espstuff.espp;
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "packet from %s received with seq=%d (iv)=0x%08x%08x iplen=%d esplen=%d sa=%s\n",
+ irs->ipsaddr_txt,
+ (__u32)ntohl(espp->esp_rpl),
+ (__u32)ntohl(*((__u32 *)(espp->esp_iv) )),
+ (__u32)ntohl(*((__u32 *)(espp->esp_iv) + 1)),
+ irs->len,
+ irs->ilen,
+ irs->sa_len ? irs->sa : " (error)");
+
+ *replay = ntohl(espp->esp_rpl);
+ *authenticator = &(skb->data[irs->len - irs->authlen]);
+
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_esp_authcalc(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ struct auth_alg *aa;
+ struct esphdr *espp = irs->protostuff.espstuff.espp;
+ union {
+ MD5_CTX md5;
+ SHA1_CTX sha1;
+ } tctx;
+
+#ifdef CONFIG_IPSEC_ALG
+ if (irs->ipsp->ips_alg_auth) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ipsec_alg hashing proto=%d... ",
+ irs->said.proto);
+ if(irs->said.proto == IPPROTO_ESP) {
+ ipsec_alg_sa_esp_hash(irs->ipsp,
+ (caddr_t)espp, irs->ilen,
+ irs->hash, AHHMAC_HASHLEN);
+ return IPSEC_RCV_OK;
+ }
+ return IPSEC_RCV_BADPROTO;
+ }
+#endif
+ aa = irs->authfuncs;
+
+ /* copy the initialized keying material */
+ memcpy(&tctx, irs->ictx, irs->ictx_len);
+
+ (*aa->update)((void *)&tctx, (caddr_t)espp, irs->ilen);
+
+ (*aa->final)(irs->hash, (void *)&tctx);
+
+ memcpy(&tctx, irs->octx, irs->octx_len);
+
+ (*aa->update)((void *)&tctx, irs->hash, aa->hashlen);
+ (*aa->final)(irs->hash, (void *)&tctx);
+
+ return IPSEC_RCV_OK;
+}
+
+
+enum ipsec_rcv_value
+ipsec_rcv_esp_decrypt(struct ipsec_rcv_state *irs)
+{
+ struct ipsec_sa *ipsp = irs->ipsp;
+ struct esphdr *espp = irs->protostuff.espstuff.espp;
+ int esphlen = 0;
+ __u8 *idat; /* pointer to content to be decrypted/authenticated */
+#ifdef CONFIG_IPSEC_ENC_3DES
+ __u32 iv[2];
+#endif /* !CONFIG_IPSEC_ENC_3DES */
+ int pad = 0, padlen;
+ int badpad = 0;
+ int i;
+ struct sk_buff *skb;
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_enc *ixt_e=NULL;
+#endif /* CONFIG_IPSEC_ALG */
+
+ skb=irs->skb;
+
+ idat = skb->data + irs->iphlen;
+
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_e=ipsp->ips_alg_enc)) {
+ esphlen = ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "encalg=%d esphlen=%d\n",
+ ipsp->ips_encalg, esphlen);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ iv[0] = *((__u32 *)(espp->esp_iv) );
+ iv[1] = *((__u32 *)(espp->esp_iv) + 1);
+ esphlen = sizeof(struct esphdr);
+ break;
+#endif /* !CONFIG_IPSEC_ENC_3DES */
+ default:
+ ipsp->ips_errs.ips_alg_errs += 1;
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_ESP_BADALG;
+ }
+
+ idat += esphlen;
+ irs->ilen -= esphlen;
+
+#ifdef CONFIG_IPSEC_ALG
+ if (ixt_e)
+ {
+ if (ipsec_alg_esp_encrypt(ipsp,
+ idat, irs->ilen, espp->esp_iv,
+ IPSEC_ALG_DECRYPT) <= 0)
+ {
+ printk("klips_error:ipsec_rcv: "
+ "got packet with esplen = %d "
+ "from %s -- should be on "
+ "ENC(%d) octet boundary, "
+ "packet dropped\n",
+ irs->ilen,
+ irs->ipsaddr_txt,
+ ipsp->ips_encalg);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BAD_DECRYPT;
+ }
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ if ((irs->ilen) % 8) {
+ ipsp->ips_errs.ips_encsize_errs += 1;
+ printk("klips_error:ipsec_rcv: "
+ "got packet with esplen = %d from %s -- should be on 8 octet boundary, packet dropped\n",
+ irs->ilen,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_3DES_BADBLOCKING;
+ }
+ des_ede3_cbc_encrypt((des_cblock *)idat,
+ (des_cblock *)idat,
+ irs->ilen,
+ ((struct des_eks *)(ipsp->ips_key_e))[0].ks,
+ ((struct des_eks *)(ipsp->ips_key_e))[1].ks,
+ ((struct des_eks *)(ipsp->ips_key_e))[2].ks,
+ (des_cblock *)iv, 0);
+ break;
+#endif /* !CONFIG_IPSEC_ENC_3DES */
+ }
+
+ rcv_dmp("postdecrypt", skb->data, skb->len);
+
+ irs->next_header = idat[irs->ilen - 1];
+ padlen = idat[irs->ilen - 2];
+ pad = padlen + 2 + irs->authlen;
+
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug:ipsec_rcv: "
+ "padlen=%d, contents: 0x<offset>: 0x<value> 0x<value> ...\n",
+ padlen);
+
+ for (i = 1; i <= padlen; i++) {
+ if((i % 16) == 1) {
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug: %02x:",
+ i - 1);
+ }
+ KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
+ " %02x",
+ idat[irs->ilen - 2 - padlen + i - 1]);
+ if(i != idat[irs->ilen - 2 - padlen + i - 1]) {
+ badpad = 1;
+ }
+ if((i % 16) == 0) {
+ KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
+ "\n");
+ }
+ }
+ if((i % 16) != 1) {
+ KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
+ "\n");
+ }
+ if(badpad) {
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug:ipsec_rcv: "
+ "warning, decrypted packet from %s has bad padding\n",
+ irs->ipsaddr_txt);
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug:ipsec_rcv: "
+ "...may be bad decryption -- not dropped\n");
+ ipsp->ips_errs.ips_encpad_errs += 1;
+ }
+
+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
+ "klips_debug:ipsec_rcv: "
+ "packet decrypted from %s: next_header = %d, padding = %d\n",
+ irs->ipsaddr_txt,
+ irs->next_header,
+ pad - 2 - irs->authlen);
+
+ irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - (esphlen + pad));
+
+ /*
+ * move the IP header forward by the size of the ESP header, which
+ * will remove the the ESP header from the packet.
+ */
+ memmove((void *)(skb->data + esphlen),
+ (void *)(skb->data), irs->iphlen);
+
+ rcv_dmp("esp postmove", skb->data, skb->len);
+
+ /* skb_pull below, will move up by esphlen */
+
+ /* XXX not clear how this can happen, as the message indicates */
+ if(skb->len < esphlen) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_rcv: "
+ "tried to skb_pull esphlen=%d, %d available. This should never happen, please report.\n",
+ esphlen, (int)(skb->len));
+ return IPSEC_RCV_ESP_DECAPFAIL;
+ }
+ skb_pull(skb, esphlen);
+
+ irs->ipp = (struct iphdr *)skb->data;
+
+ rcv_dmp("esp postpull", skb->data, skb->len);
+
+ /* now, trip off the padding from the end */
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "trimming to %d.\n",
+ irs->len - esphlen - pad);
+ if(pad + esphlen <= irs->len) {
+ skb_trim(skb, irs->len - esphlen - pad);
+ } else {
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "bogus packet, size is zero or negative, dropping.\n");
+ return IPSEC_RCV_DECAPFAIL;
+ }
+
+ return IPSEC_RCV_OK;
+}
+
+
+struct xform_functions esp_rcv_funcs[]={
+ { checks: ipsec_rcv_esp_checks,
+ setup_auth: ipsec_rcv_esp_decrypt_setup,
+ calc_auth: ipsec_rcv_esp_authcalc,
+ decrypt: ipsec_rcv_esp_decrypt,
+ },
+};
+#endif /* !CONFIG_IPSEC_ESP */
+
+#ifdef CONFIG_IPSEC_AH
+enum ipsec_rcv_value
+ipsec_rcv_ah_checks(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ int ahminlen;
+
+ ahminlen = irs->hard_header_len + sizeof(struct iphdr);
+
+ /* take care not to deref this pointer until we check the minlen though */
+ irs->protostuff.ahstuff.ahp = (struct ahhdr *) (skb->data + irs->iphlen);
+
+ if((skb->len < ahminlen+sizeof(struct ahhdr)) ||
+ (skb->len < ahminlen+(irs->protostuff.ahstuff.ahp->ah_hl << 2))) {
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "runt ah packet of skb->len=%d received from %s, dropped.\n",
+ skb->len,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ irs->said.spi = irs->protostuff.ahstuff.ahp->ah_spi;
+
+ /* XXX we only support the one 12-byte authenticator for now */
+ if(irs->protostuff.ahstuff.ahp->ah_hl != ((AHHMAC_HASHLEN+AHHMAC_RPLLEN) >> 2)) {
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "bad authenticator length %ld, expected %lu from %s.\n",
+ (long)(irs->protostuff.ahstuff.ahp->ah_hl << 2),
+ (unsigned long) sizeof(struct ahhdr),
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ return IPSEC_RCV_OK;
+}
+
+
+enum ipsec_rcv_value
+ipsec_rcv_ah_setup_auth(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb,
+ __u32 *replay,
+ unsigned char **authenticator)
+{
+ struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
+
+ *replay = ntohl(ahp->ah_rpl);
+ *authenticator = ahp->ah_data;
+
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_ah_authcalc(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ struct auth_alg *aa;
+ struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
+ union {
+ MD5_CTX md5;
+ SHA1_CTX sha1;
+ } tctx;
+ struct iphdr ipo;
+ int ahhlen;
+
+ aa = irs->authfuncs;
+
+ /* copy the initialized keying material */
+ memcpy(&tctx, irs->ictx, irs->ictx_len);
+
+ ipo = *irs->ipp;
+ ipo.tos = 0; /* mutable RFC 2402 3.3.3.1.1.1 */
+ ipo.frag_off = 0;
+ ipo.ttl = 0;
+ ipo.check = 0;
+
+
+ /* do the sanitized header */
+ (*aa->update)((void*)&tctx, (caddr_t)&ipo, sizeof(struct iphdr));
+
+ /* XXX we didn't do the options here! */
+
+ /* now do the AH header itself */
+ ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2);
+ (*aa->update)((void*)&tctx, (caddr_t)ahp, ahhlen - AHHMAC_HASHLEN);
+
+ /* now, do some zeroes */
+ (*aa->update)((void*)&tctx, (caddr_t)zeroes, AHHMAC_HASHLEN);
+
+ /* finally, do the packet contents themselves */
+ (*aa->update)((void*)&tctx,
+ (caddr_t)skb->data + irs->iphlen + ahhlen,
+ skb->len - irs->iphlen - ahhlen);
+
+ (*aa->final)(irs->hash, (void *)&tctx);
+
+ memcpy(&tctx, irs->octx, irs->octx_len);
+
+ (*aa->update)((void *)&tctx, irs->hash, aa->hashlen);
+ (*aa->final)(irs->hash, (void *)&tctx);
+
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_ah_decap(struct ipsec_rcv_state *irs)
+{
+ struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
+ struct sk_buff *skb;
+ int ahhlen;
+
+ skb=irs->skb;
+
+ ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2);
+
+ irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - ahhlen);
+ irs->next_header = ahp->ah_nh;
+
+ /*
+ * move the IP header forward by the size of the AH header, which
+ * will remove the the AH header from the packet.
+ */
+ memmove((void *)(skb->data + ahhlen),
+ (void *)(skb->data), irs->iphlen);
+
+ rcv_dmp("ah postmove", skb->data, skb->len);
+
+ /* skb_pull below, will move up by ahhlen */
+
+ /* XXX not clear how this can happen, as the message indicates */
+ if(skb->len < ahhlen) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_rcv: "
+ "tried to skb_pull ahhlen=%d, %d available. This should never happen, please report.\n",
+ ahhlen,
+ (int)(skb->len));
+ return IPSEC_RCV_DECAPFAIL;
+ }
+ skb_pull(skb, ahhlen);
+
+ irs->ipp = (struct iphdr *)skb->data;
+
+ rcv_dmp("ah postpull", skb->data, skb->len);
+
+ return IPSEC_RCV_OK;
+}
+
+
+struct xform_functions ah_rcv_funcs[]={
+ { checks: ipsec_rcv_ah_checks,
+ setup_auth: ipsec_rcv_ah_setup_auth,
+ calc_auth: ipsec_rcv_ah_authcalc,
+ decrypt: ipsec_rcv_ah_decap,
+ },
+};
+
+#endif /* CONFIG_IPSEC_AH */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+enum ipsec_rcv_value
+ipsec_rcv_ipcomp_checks(struct ipsec_rcv_state *irs,
+ struct sk_buff *skb)
+{
+ int ipcompminlen;
+
+ ipcompminlen = irs->hard_header_len + sizeof(struct iphdr);
+
+ if(skb->len < (ipcompminlen + sizeof(struct ipcomphdr))) {
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "runt comp packet of skb->len=%d received from %s, dropped.\n",
+ skb->len,
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+ irs->protostuff.ipcompstuff.compp = (struct ipcomphdr *)(skb->data + irs->iphlen);
+ irs->said.spi = htonl((__u32)ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi));
+ return IPSEC_RCV_OK;
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_ipcomp_decomp(struct ipsec_rcv_state *irs)
+{
+ unsigned int flags = 0;
+ struct ipsec_sa *ipsp = irs->ipsp;
+ struct sk_buff *skb;
+
+ skb=irs->skb;
+
+ rcv_dmp("ipcomp", skb->data, skb->len);
+
+ if(ipsp == NULL) {
+ return IPSEC_RCV_SAIDNOTFOUND;
+ }
+
+#if 0
+ /* we want to check that this wasn't the first SA on the list, because
+ * we don't support bare IPCOMP, for unexplained reasons. MCR
+ */
+ if (ipsp->ips_onext != NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "Incoming packet with outer IPCOMP header SA:%s: not yet supported by KLIPS, dropped\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+
+ return IPSEC_RCV_IPCOMPALONE;
+ }
+#endif
+
+ if(sysctl_ipsec_inbound_policy_check &&
+ ((((ntohl(ipsp->ips_said.spi) & 0x0000ffff) != ntohl(irs->said.spi)) &&
+ (ipsp->ips_encalg != ntohl(irs->said.spi)) /* this is a workaround for peer non-compliance with rfc2393 */
+ ))) {
+ char sa2[SATOA_BUF];
+ size_t sa_len2 = 0;
+
+ sa_len2 = satoa(ipsp->ips_said, 0, sa2, SATOA_BUF);
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "Incoming packet with SA(IPCA):%s does not match policy SA(IPCA):%s cpi=%04x cpi->spi=%08x spi=%08x, spi->cpi=%04x for SA grouping, dropped.\n",
+ irs->sa_len ? irs->sa : " (error)",
+ ipsp != NULL ? (sa_len2 ? sa2 : " (error)") : "NULL",
+ ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi),
+ (__u32)ntohl(irs->said.spi),
+ ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0,
+ ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_SAIDNOTFOUND;
+ }
+
+ ipsp->ips_comp_ratio_cbytes += ntohs(irs->ipp->tot_len);
+ irs->next_header = irs->protostuff.ipcompstuff.compp->ipcomp_nh;
+
+ skb = skb_decompress(skb, ipsp, &flags);
+ if (!skb || flags) {
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "skb_decompress() returned error flags=%x, dropped.\n",
+ flags);
+ if (irs->stats) {
+ if (flags)
+ irs->stats->rx_errors++;
+ else
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_IPCOMPFAILED;
+ }
+
+ /* make sure we update the pointer */
+ irs->skb = skb;
+
+#ifdef NET_21
+ irs->ipp = skb->nh.iph;
+#else /* NET_21 */
+ irs->ipp = skb->ip_hdr;
+#endif /* NET_21 */
+
+ ipsp->ips_comp_ratio_dbytes += ntohs(irs->ipp->tot_len);
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "packet decompressed SA(IPCA):%s cpi->spi=%08x spi=%08x, spi->cpi=%04x, nh=%d.\n",
+ irs->sa_len ? irs->sa : " (error)",
+ (__u32)ntohl(irs->said.spi),
+ ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0,
+ ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0,
+ irs->next_header);
+ KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, irs->ipp);
+
+ return IPSEC_RCV_OK;
+}
+
+
+struct xform_functions ipcomp_rcv_funcs[]={
+ {checks: ipsec_rcv_ipcomp_checks,
+ decrypt: ipsec_rcv_ipcomp_decomp,
+ },
+};
+
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+enum ipsec_rcv_value
+ipsec_rcv_decap_once(struct ipsec_rcv_state *irs)
+{
+ int iphlen;
+ unsigned char *dat;
+ __u8 proto;
+ struct in_addr ipsaddr;
+ struct in_addr ipdaddr;
+ int replay = 0; /* replay value in AH or ESP packet */
+ struct ipsec_sa* ipsnext = NULL; /* next SA towards inside of packet */
+ struct xform_functions *proto_funcs;
+ struct ipsec_sa *newipsp;
+ struct iphdr *ipp;
+ struct sk_buff *skb;
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_auth *ixt_a=NULL;
+#endif /* CONFIG_IPSEC_ALG */
+
+ skb = irs->skb;
+ irs->len = skb->len;
+ dat = skb->data;
+ ipp = irs->ipp;
+ proto = ipp->protocol;
+ ipsaddr.s_addr = ipp->saddr;
+ addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
+ ipdaddr.s_addr = ipp->daddr;
+ addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
+
+ iphlen = ipp->ihl << 2;
+ irs->iphlen=iphlen;
+ ipp->check = 0; /* we know the sum is good */
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv_decap_once: "
+ "decap (%d) from %s -> %s\n",
+ proto, irs->ipsaddr_txt, irs->ipdaddr_txt);
+
+ switch(proto) {
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP:
+ proto_funcs = esp_rcv_funcs;
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ proto_funcs = ah_rcv_funcs;
+ break;
+#endif /* !CONFIG_IPSEC_AH */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ proto_funcs = ipcomp_rcv_funcs;
+ break;
+#endif /* !CONFIG_IPSEC_IPCOMP */
+ default:
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADPROTO;
+ }
+
+ /*
+ * Find tunnel control block and (indirectly) call the
+ * appropriate tranform routine. The resulting sk_buf
+ * is a valid IP packet ready to go through input processing.
+ */
+
+ irs->said.dst.s_addr = ipp->daddr;
+
+ if(proto_funcs->checks) {
+ enum ipsec_rcv_value retval = (*proto_funcs->checks)(irs, skb);
+
+ if(retval < 0) {
+ return retval;
+ }
+ }
+
+ irs->said.proto = proto;
+ irs->sa_len = satoa(irs->said, 0, irs->sa, SATOA_BUF);
+ if(irs->sa_len == 0) {
+ strcpy(irs->sa, "(error)");
+ }
+
+ newipsp = ipsec_sa_getbyid(&irs->said);
+ if (newipsp == NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_SAIDNOTFOUND;
+ }
+
+ /* MCR - XXX this is bizarre. ipsec_sa_getbyid returned it, having incremented the refcount,
+ * why in the world would we decrement it here?
+
+ ipsec_sa_put(irs->ipsp);*/ /* incomplete */
+
+ /* If it is in larval state, drop the packet, we cannot process yet. */
+ if(newipsp->ips_state == SADB_SASTATE_LARVAL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ipsec_sa in larval state, cannot be used yet, dropping packet.\n");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_SAIDNOTLIVE;
+ }
+
+ if(newipsp->ips_state == SADB_SASTATE_DEAD) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ipsec_sa in dead state, cannot be used any more, dropping packet.\n");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_SAIDNOTLIVE;
+ }
+
+ if(sysctl_ipsec_inbound_policy_check) {
+ if(irs->ipp->saddr != ((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
+ irs->sa_len ? irs->sa : " (error)",
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, src=%s of pkt agrees with expected SA source address policy.\n",
+ irs->sa_len ? irs->sa : " (error)",
+ irs->ipsaddr_txt);
+
+ /*
+ * at this point, we have looked up a new SA, and we want to make sure that if this
+ * isn't the first SA in the list, that the previous SA actually points at this one.
+ */
+ if(irs->ipsp) {
+ if(irs->ipsp->ips_inext != newipsp) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "unexpected SA:%s: does not agree with ips->inext policy, dropped\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s grouping from previous SA is OK.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ } else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s First SA in group.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ }
+
+ /*
+ * previously, at this point, we checked if the back pointer from the new SA that
+ * we just found matched the back pointer. But, we won't do this check anymore,
+ * because we want to be able to nest SAs
+ */
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "natt_type=%u tdbp->ips_natt_type=%u : %s\n",
+ irs->natt_type, newipsp->ips_natt_type,
+ (irs->natt_type==newipsp->ips_natt_type)?"ok":"bad");
+ if (irs->natt_type != newipsp->ips_natt_type) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s does not agree with expected NAT-T policy.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+#endif
+ }
+
+ /* okay, SA checks out, so free any previous SA, and record a new one */
+
+ if(irs->ipsp) {
+ ipsec_sa_put(irs->ipsp);
+ }
+ irs->ipsp=newipsp;
+
+ /* note that the outer code will free the irs->ipsp if there is an error */
+
+
+ /* now check the lifetimes */
+ if(ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_bytes, "bytes", irs->sa,
+ ipsec_life_countbased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "addtime",irs->sa,
+ ipsec_life_timebased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "usetime",irs->sa,
+ ipsec_life_timebased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_packets, "packets",irs->sa,
+ ipsec_life_countbased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied) {
+ ipsec_sa_delchain(irs->ipsp);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv_decap_once: "
+ "decap (%d) failed lifetime check\n",
+ proto);
+
+ return IPSEC_RCV_LIFETIMEFAILED;
+ }
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if ((irs->natt_type) &&
+ ( (irs->ipp->saddr != (((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr)) ||
+ (irs->natt_sport != newipsp->ips_natt_sport)
+ )) {
+ struct sockaddr sipaddr;
+ /** Advertise NAT-T addr change to pluto **/
+ sipaddr.sa_family = AF_INET;
+ ((struct sockaddr_in*)&sipaddr)->sin_addr.s_addr = irs->ipp->saddr;
+ ((struct sockaddr_in*)&sipaddr)->sin_port = htons(irs->natt_sport);
+ pfkey_nat_t_new_mapping(newipsp, &sipaddr, irs->natt_sport);
+ /**
+ * Then allow or block packet depending on
+ * sysctl_ipsec_inbound_policy_check.
+ *
+ * In all cases, pluto will update SA if new mapping is
+ * accepted.
+ */
+ if (sysctl_ipsec_inbound_policy_check) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, src=%s:%u of pkt does not agree with expected "
+ "SA source address policy (pluto has been informed).\n",
+ irs->sa_len ? irs->sa : " (error)",
+ irs->ipsaddr_txt, irs->natt_sport);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ ipsec_sa_put(newipsp);
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+ }
+#endif
+
+ irs->authfuncs=NULL;
+ /* authenticate, if required */
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_a=irs->ipsp->ips_alg_auth)) {
+ irs->authlen = AHHMAC_HASHLEN;
+ irs->authfuncs = NULL;
+ irs->ictx = NULL;
+ irs->octx = NULL;
+ irs->ictx_len = 0;
+ irs->octx_len = 0;
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "authalg=%d authlen=%d\n",
+ irs->ipsp->ips_authalg,
+ irs->authlen);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(irs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ irs->authlen = AHHMAC_HASHLEN;
+ irs->authfuncs = ipsec_rcv_md5;
+ irs->ictx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx;
+ irs->octx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx;
+ irs->ictx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx);
+ irs->octx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx);
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ irs->authlen = AHHMAC_HASHLEN;
+ irs->authfuncs = ipsec_rcv_sha1;
+ irs->ictx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx;
+ irs->octx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx;
+ irs->ictx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx);
+ irs->octx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx);
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ irs->authlen = 0;
+ irs->authfuncs = NULL;
+ irs->ictx = NULL;
+ irs->octx = NULL;
+ irs->ictx_len = 0;
+ irs->octx_len = 0;
+
+ break;
+ default:
+ irs->ipsp->ips_errs.ips_alg_errs += 1;
+ if(irs->stats) {
+ irs->stats->rx_errors++;
+ }
+ return IPSEC_RCV_BADAUTH;
+ }
+
+ irs->ilen = irs->len - iphlen - irs->authlen;
+ if(irs->ilen <= 0) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "runt %s packet with no data, dropping.\n",
+ (proto == IPPROTO_ESP ? "esp" : "ah"));
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_BADLEN;
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if(irs->authfuncs || ixt_a) {
+#else
+ if(irs->authfuncs) {
+#endif
+ unsigned char *authenticator = NULL;
+
+ if(proto_funcs->setup_auth) {
+ enum ipsec_rcv_value retval
+ = (*proto_funcs->setup_auth)(irs, skb,
+ &replay,
+ &authenticator);
+ if(retval < 0) {
+ return retval;
+ }
+ }
+
+ if(!authenticator) {
+ irs->ipsp->ips_errs.ips_auth_errs += 1;
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_BADAUTH;
+ }
+
+ if(!ipsec_checkreplaywindow(irs->ipsp, replay)) {
+ irs->ipsp->ips_errs.ips_replaywin_errs += 1;
+ KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
+ "klips_debug:ipsec_rcv: "
+ "duplicate frame from %s, packet dropped\n",
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_REPLAYFAILED;
+ }
+
+ /*
+ * verify authenticator
+ */
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "encalg = %d, authalg = %d.\n",
+ irs->ipsp->ips_encalg,
+ irs->ipsp->ips_authalg);
+
+ /* calculate authenticator */
+ if(proto_funcs->calc_auth == NULL) {
+ return IPSEC_RCV_BADAUTH;
+ }
+ (*proto_funcs->calc_auth)(irs, skb);
+
+ if (memcmp(irs->hash, authenticator, irs->authlen)) {
+ irs->ipsp->ips_errs.ips_auth_errs += 1;
+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
+ "klips_debug:ipsec_rcv: "
+ "auth failed on incoming packet from %s: hash=%08x%08x%08x auth=%08x%08x%08x, dropped\n",
+ irs->ipsaddr_txt,
+ ntohl(*(__u32*)&irs->hash[0]),
+ ntohl(*(__u32*)&irs->hash[4]),
+ ntohl(*(__u32*)&irs->hash[8]),
+ ntohl(*(__u32*)authenticator),
+ ntohl(*((__u32*)authenticator + 1)),
+ ntohl(*((__u32*)authenticator + 2)));
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_AUTHFAILED;
+ } else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "authentication successful.\n");
+ }
+
+ /* Crypto hygiene: clear memory used to calculate autheticator.
+ * The length varies with the algorithm.
+ */
+ memset(irs->hash, 0, irs->authlen);
+
+ /* If the sequence number == 0, expire SA, it had rolled */
+ if(irs->ipsp->ips_replaywin && !replay /* !irs->ipsp->ips_replaywin_lastseq */) {
+ ipsec_sa_delchain(irs->ipsp);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "replay window counter rolled, expiring SA.\n");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_REPLAYROLLED;
+ }
+
+ /* now update the replay counter */
+ if (!ipsec_updatereplaywindow(irs->ipsp, replay)) {
+ irs->ipsp->ips_errs.ips_replaywin_errs += 1;
+ KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
+ "klips_debug:ipsec_rcv: "
+ "duplicate frame from %s, packet dropped\n",
+ irs->ipsaddr_txt);
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_REPLAYROLLED;
+ }
+ }
+
+ if(proto_funcs->decrypt) {
+ enum ipsec_rcv_value retval =
+ (*proto_funcs->decrypt)(irs);
+
+ if(retval != IPSEC_RCV_OK) {
+ return retval;
+ }
+ }
+
+ /*
+ * Adjust pointers
+ */
+ skb = irs->skb;
+ irs->len = skb->len;
+ dat = skb->data;
+
+#ifdef NET_21
+/* skb->h.ipiph=(struct iphdr *)skb->data; */
+ skb->nh.raw = skb->data;
+ skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2);
+
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+#else /* NET_21 */
+ skb->h.iph=(struct iphdr *)skb->data;
+ skb->ip_hdr=(struct iphdr *)skb->data;
+ memset(skb->proto_priv, 0, sizeof(struct options));
+#endif /* NET_21 */
+
+ ipp = (struct iphdr *)dat;
+ ipsaddr.s_addr = ipp->saddr;
+ addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
+ ipdaddr.s_addr = ipp->daddr;
+ addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
+ /*
+ * Discard the original ESP/AH header
+ */
+ ipp->protocol = irs->next_header;
+
+ ipp->check = 0; /* NOTE: this will be included in checksum */
+ ipp->check = ip_fast_csum((unsigned char *)dat, iphlen >> 2);
+
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "after <%s%s%s>, SA:%s:\n",
+ IPS_XFORM_NAME(irs->ipsp),
+ irs->sa_len ? irs->sa : " (error)");
+ KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);
+
+ skb->protocol = htons(ETH_P_IP);
+ skb->ip_summed = 0;
+
+ ipsnext = irs->ipsp->ips_inext;
+ if(sysctl_ipsec_inbound_policy_check) {
+ if(ipsnext) {
+ if(
+ ipp->protocol != IPPROTO_AH
+ && ipp->protocol != IPPROTO_ESP
+#ifdef CONFIG_IPSEC_IPCOMP
+ && ipp->protocol != IPPROTO_COMP
+ && (ipsnext->ips_said.proto != IPPROTO_COMP
+ || ipsnext->ips_inext)
+#endif /* CONFIG_IPSEC_IPCOMP */
+ && ipp->protocol != IPPROTO_IPIP
+ ) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "packet with incomplete policy dropped, last successful SA:%s.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ if(irs->stats) {
+ irs->stats->rx_dropped++;
+ }
+ return IPSEC_RCV_FAILEDINBOUND;
+ }
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, Another IPSEC header to process.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ } else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "No ips_inext from this SA:%s.\n",
+ irs->sa_len ? irs->sa : " (error)");
+ }
+ }
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ /* update ipcomp ratio counters, even if no ipcomp packet is present */
+ if (ipsnext
+ && ipsnext->ips_said.proto == IPPROTO_COMP
+ && ipp->protocol != IPPROTO_COMP) {
+ ipsnext->ips_comp_ratio_cbytes += ntohs(ipp->tot_len);
+ ipsnext->ips_comp_ratio_dbytes += ntohs(ipp->tot_len);
+ }
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+ irs->ipsp->ips_life.ipl_bytes.ipl_count += irs->len;
+ irs->ipsp->ips_life.ipl_bytes.ipl_last = irs->len;
+
+ if(!irs->ipsp->ips_life.ipl_usetime.ipl_count) {
+ irs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
+ }
+ irs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
+ irs->ipsp->ips_life.ipl_packets.ipl_count += 1;
+
+#ifdef CONFIG_NETFILTER
+ if(proto == IPPROTO_ESP || proto == IPPROTO_AH) {
+ skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_MASK))))
+ | IPsecSAref2NFmark(IPsecSA2SAref(irs->ipsp));
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "%s SA sets skb->nfmark=0x%x.\n",
+ proto == IPPROTO_ESP ? "ESP" : "AH",
+ (unsigned)skb->nfmark);
+ }
+#endif /* CONFIG_NETFILTER */
+
+ return IPSEC_RCV_OK;
+}
+
+
+int
+#ifdef PROTO_HANDLER_SINGLE_PARM
+ipsec_rcv(struct sk_buff *skb)
+#else /* PROTO_HANDLER_SINGLE_PARM */
+#ifdef NET_21
+ipsec_rcv(struct sk_buff *skb, unsigned short xlen)
+#else /* NET_21 */
+ipsec_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+ __u32 daddr_unused, unsigned short xlen, __u32 saddr,
+ int redo, struct inet_protocol *protocol)
+#endif /* NET_21 */
+#endif /* PROTO_HANDLER_SINGLE_PARM */
+{
+#ifdef NET_21
+#ifdef CONFIG_IPSEC_DEBUG
+ struct device *dev = skb->dev;
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* NET_21 */
+ unsigned char protoc;
+ struct iphdr *ipp;
+#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
+#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
+
+ struct ipsec_sa *ipsp = NULL;
+ struct net_device_stats *stats = NULL; /* This device's statistics */
+ struct device *ipsecdev = NULL, *prvdev;
+ struct ipsecpriv *prv;
+ char name[9];
+ int i;
+ struct in_addr ipsaddr;
+ struct in_addr ipdaddr;
+
+ struct ipsec_sa* ipsnext = NULL; /* next SA towards inside of packet */
+ struct ipsec_rcv_state irs;
+
+ /* Don't unlink in the middle of a turnaround */
+ MOD_INC_USE_COUNT;
+
+ memset(&irs, 0, sizeof(struct ipsec_rcv_state));
+
+ if (skb == NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NULL skb passed in.\n");
+ goto rcvleave;
+ }
+
+ if (skb->data == NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NULL skb->data passed in, packet is bogus, dropping.\n");
+ goto rcvleave;
+ }
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (skb->sk && skb->nh.iph && skb->nh.iph->protocol==IPPROTO_UDP) {
+ /**
+ * Packet comes from udp_queue_rcv_skb so it is already defrag,
+ * checksum verified, ... (ie safe to use)
+ *
+ * If the packet is not for us, return -1 and udp_queue_rcv_skb
+ * will continue to handle it (do not kfree skb !!).
+ */
+ struct udp_opt *tp = &(skb->sk->tp_pinfo.af_udp);
+ struct iphdr *ip = (struct iphdr *)skb->nh.iph;
+ struct udphdr *udp = (struct udphdr *)((__u32 *)ip+ip->ihl);
+ __u8 *udpdata = (__u8 *)udp + sizeof(struct udphdr);
+ __u32 *udpdata32 = (__u32 *)udpdata;
+
+ irs.natt_sport = ntohs(udp->source);
+ irs.natt_dport = ntohs(udp->dest);
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "suspected ESPinUDP packet (NAT-Traversal) [%d].\n",
+ tp->esp_in_udp);
+ KLIPS_IP_PRINT(debug_rcv, ip);
+
+ if (udpdata < skb->tail) {
+ unsigned int len = skb->tail - udpdata;
+ if ((len==1) && (udpdata[0]==0xff)) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ /* not IPv6 compliant message */
+ "NAT-keepalive from %d.%d.%d.%d.\n", NIPQUAD(ip->saddr));
+ goto rcvleave;
+ }
+ else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_IKE) &&
+ (len > (2*sizeof(__u32) + sizeof(struct esphdr))) &&
+ (udpdata32[0]==0) && (udpdata32[1]==0) ) {
+ /* ESP Packet with Non-IKE header */
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ESPinUDP pkt with Non-IKE - spi=0x%x\n",
+ udpdata32[2]);
+ irs.natt_type = ESPINUDP_WITH_NON_IKE;
+ irs.natt_len = sizeof(struct udphdr)+(2*sizeof(__u32));
+ }
+ else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_ESP) &&
+ (len > sizeof(struct esphdr)) &&
+ (udpdata32[0]!=0) ) {
+ /* ESP Packet without Non-ESP header */
+ irs.natt_type = ESPINUDP_WITH_NON_ESP;
+ irs.natt_len = sizeof(struct udphdr);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "ESPinUDP pkt without Non-ESP - spi=0x%x\n",
+ udpdata32[0]);
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "IKE packet - not handled here\n");
+ MOD_DEC_USE_COUNT;
+ return -1;
+ }
+ }
+ else {
+ MOD_DEC_USE_COUNT;
+ return -1;
+ }
+ }
+#endif
+
+#ifdef IPH_is_SKB_PULLED
+ /* In Linux 2.4.4, the IP header has been skb_pull()ed before the
+ packet is passed to us. So we'll skb_push() to get back to it. */
+ if (skb->data == skb->h.raw) {
+ skb_push(skb, skb->h.raw - skb->nh.raw);
+ }
+#endif /* IPH_is_SKB_PULLED */
+
+ /* dev->hard_header_len is unreliable and should not be used */
+ irs.hard_header_len = skb->mac.raw ? (skb->data - skb->mac.raw) : 0;
+ if((irs.hard_header_len < 0) || (irs.hard_header_len > skb_headroom(skb)))
+ irs.hard_header_len = 0;
+
+#ifdef NET_21
+ /* if skb was cloned (most likely due to a packet sniffer such as
+ tcpdump being momentarily attached to the interface), make
+ a copy of our own to modify */
+ if(skb_cloned(skb)) {
+ /* include any mac header while copying.. */
+ if(skb_headroom(skb) < irs.hard_header_len) {
+ printk(KERN_WARNING "klips_error:ipsec_rcv: "
+ "tried to skb_push hhlen=%d, %d available. This should never happen, please report.\n",
+ irs.hard_header_len,
+ skb_headroom(skb));
+ goto rcvleave;
+ }
+ skb_push(skb, irs.hard_header_len);
+ if
+#ifdef SKB_COW_NEW
+ (skb_cow(skb, skb_headroom(skb)) != 0)
+#else /* SKB_COW_NEW */
+ ((skb = skb_cow(skb, skb_headroom(skb))) == NULL)
+#endif /* SKB_COW_NEW */
+ {
+ goto rcvleave;
+ }
+ if(skb->len < irs.hard_header_len) {
+ printk(KERN_WARNING "klips_error:ipsec_rcv: "
+ "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n",
+ irs.hard_header_len,
+ skb->len);
+ goto rcvleave;
+ }
+ skb_pull(skb, irs.hard_header_len);
+ }
+
+#endif /* NET_21 */
+
+#if IP_FRAGMENT_LINEARIZE
+ /* In Linux 2.4.4, we may have to reassemble fragments. They are
+ not assembled automatically to save TCP from having to copy
+ twice.
+ */
+ if (skb_is_nonlinear(skb)) {
+ if (skb_linearize(skb, GFP_ATOMIC) != 0) {
+ goto rcvleave;
+ }
+ }
+#endif /* IP_FRAGMENT_LINEARIZE */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (irs.natt_len) {
+ /**
+ * Now, we are sure packet is ESPinUDP. Remove natt_len bytes from
+ * packet and modify protocol to ESP.
+ */
+ if (((unsigned char *)skb->data > (unsigned char *)skb->nh.iph) &&
+ ((unsigned char *)skb->nh.iph > (unsigned char *)skb->head)) {
+ unsigned int _len = (unsigned char *)skb->data -
+ (unsigned char *)skb->nh.iph;
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: adjusting skb: skb_push(%u)\n",
+ _len);
+ skb_push(skb, _len);
+ }
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "removing %d bytes from ESPinUDP packet\n", irs.natt_len);
+ ipp = (struct iphdr *)skb->data;
+ irs.iphlen = ipp->ihl << 2;
+ ipp->tot_len = htons(ntohs(ipp->tot_len) - irs.natt_len);
+ if (skb->len < irs.iphlen + irs.natt_len) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_rcv: "
+ "ESPinUDP packet is too small (%d < %d+%d). "
+ "This should never happen, please report.\n",
+ (int)(skb->len), irs.iphlen, irs.natt_len);
+ goto rcvleave;
+ }
+ memmove(skb->data + irs.natt_len, skb->data, irs.iphlen);
+ skb_pull(skb, irs.natt_len);
+
+ /* update nh.iph */
+ ipp = skb->nh.iph = (struct iphdr *)skb->data;
+
+ /* modify protocol */
+ ipp->protocol = IPPROTO_ESP;
+
+ skb->sk = NULL;
+
+ KLIPS_IP_PRINT(debug_rcv, skb->nh.iph);
+ }
+#endif
+
+ ipp = skb->nh.iph;
+ ipsaddr.s_addr = ipp->saddr;
+ addrtoa(ipsaddr, 0, irs.ipsaddr_txt, sizeof(irs.ipsaddr_txt));
+ ipdaddr.s_addr = ipp->daddr;
+ addrtoa(ipdaddr, 0, irs.ipdaddr_txt, sizeof(irs.ipdaddr_txt));
+ irs.iphlen = ipp->ihl << 2;
+
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "<<< Info -- ");
+ KLIPS_PRINTMORE(debug_rcv && skb->dev, "skb->dev=%s ",
+ skb->dev->name ? skb->dev->name : "NULL");
+ KLIPS_PRINTMORE(debug_rcv && dev, "dev=%s ",
+ dev->name ? dev->name : "NULL");
+ KLIPS_PRINTMORE(debug_rcv, "\n");
+
+ KLIPS_PRINT(debug_rcv && !(skb->dev && dev && (skb->dev == dev)),
+ "klips_debug:ipsec_rcv: "
+ "Informational -- **if this happens, find out why** skb->dev:%s is not equal to dev:%s\n",
+ skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL",
+ dev ? (dev->name ? dev->name : "NULL") : "NULL");
+
+ protoc = ipp->protocol;
+#ifndef NET_21
+ if((!protocol) || (protocol->protocol != protoc)) {
+ KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
+ "klips_debug:ipsec_rcv: "
+ "protocol arg is NULL or unequal to the packet contents, this is odd, using value in packet.\n");
+ }
+#endif /* !NET_21 */
+
+ if( (protoc != IPPROTO_AH) &&
+#ifdef CONFIG_IPSEC_IPCOMP_disabled_until_we_register_IPCOMP_HANDLER
+ (protoc != IPPROTO_COMP) &&
+#endif /* CONFIG_IPSEC_IPCOMP */
+ (protoc != IPPROTO_ESP) ) {
+ KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
+ "klips_debug:ipsec_rcv: Why the hell is someone "
+ "passing me a non-ipsec protocol = %d packet? -- dropped.\n",
+ protoc);
+ goto rcvleave;
+ }
+
+ if(skb->dev) {
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ sprintf(name, IPSEC_DEV_FORMAT, i);
+ if(!strcmp(name, skb->dev->name)) {
+ prv = (struct ipsecpriv *)(skb->dev->priv);
+ if(prv) {
+ stats = (struct net_device_stats *) &(prv->mystats);
+ }
+ ipsecdev = skb->dev;
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "Info -- pkt already proc'ed a group of ipsec headers, processing next group of ipsec headers.\n");
+ break;
+ }
+ if((ipsecdev = __ipsec_dev_get(name)) == NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_error:ipsec_rcv: "
+ "device %s does not exist\n",
+ name);
+ }
+ prv = ipsecdev ? (struct ipsecpriv *)(ipsecdev->priv) : NULL;
+ prvdev = prv ? (struct device *)(prv->dev) : NULL;
+
+#if 0
+ KLIPS_PRINT(debug_rcv && prvdev,
+ "klips_debug:ipsec_rcv: "
+ "physical device for device %s is %s\n",
+ name,
+ prvdev->name);
+#endif
+ if(prvdev && skb->dev &&
+ !strcmp(prvdev->name, skb->dev->name)) {
+ stats = prv ? ((struct net_device_stats *) &(prv->mystats)) : NULL;
+ skb->dev = ipsecdev;
+ KLIPS_PRINT(debug_rcv && prvdev,
+ "klips_debug:ipsec_rcv: "
+ "assigning packet ownership to virtual device %s from physical device %s.\n",
+ name, prvdev->name);
+ if(stats) {
+ stats->rx_packets++;
+ }
+ break;
+ }
+ }
+ } else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "device supplied with skb is NULL\n");
+ }
+
+ if(stats == NULL) {
+ KLIPS_PRINT((debug_rcv),
+ "klips_error:ipsec_rcv: "
+ "packet received from physical I/F (%s) not connected to ipsec I/F. Cannot record stats. May not have SA for decoding. Is IPSEC traffic expected on this I/F? Check routing.\n",
+ skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL");
+ }
+
+ KLIPS_IP_PRINT(debug_rcv, ipp);
+
+ /* begin decapsulating loop here */
+
+ /*
+ The spinlock is to prevent any other process from
+ accessing or deleting the ipsec_sa hash table or any of the
+ ipsec_sa s while we are using and updating them.
+
+ This is not optimal, but was relatively straightforward
+ at the time. A better way to do it has been planned for
+ more than a year, to lock the hash table and put reference
+ counts on each ipsec_sa instead. This is not likely to happen
+ in KLIPS1 unless a volunteer contributes it, but will be
+ designed into KLIPS2.
+ */
+ spin_lock(&tdb_lock);
+
+ /* set up for decap loop */
+ irs.stats= stats;
+ irs.ipp = ipp;
+ irs.ipsp = NULL;
+ irs.ilen = 0;
+ irs.authlen=0;
+ irs.authfuncs=NULL;
+ irs.skb = skb;
+
+ do {
+ int decap_stat;
+
+ decap_stat = ipsec_rcv_decap_once(&irs);
+
+ if(decap_stat != IPSEC_RCV_OK) {
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: decap_once failed: %d\n",
+ decap_stat);
+
+ goto rcvleave;
+ }
+ /* end decapsulation loop here */
+ } while( (irs.ipp->protocol == IPPROTO_ESP )
+ || (irs.ipp->protocol == IPPROTO_AH )
+#ifdef CONFIG_IPSEC_IPCOMP
+ || (irs.ipp->protocol == IPPROTO_COMP)
+#endif /* CONFIG_IPSEC_IPCOMP */
+ );
+
+ /* set up for decap loop */
+ ipp =irs.ipp;
+ ipsp =irs.ipsp;
+ ipsnext = ipsp->ips_inext;
+ skb = irs.skb;
+
+ /* if there is an IPCOMP, but we don't have an IPPROTO_COMP,
+ * then we can just skip it
+ */
+#ifdef CONFIG_IPSEC_IPCOMP
+ if(ipsnext && ipsnext->ips_said.proto == IPPROTO_COMP) {
+ ipsp = ipsnext;
+ ipsnext = ipsp->ips_inext;
+ }
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if ((irs.natt_type) && (ipp->protocol != IPPROTO_IPIP)) {
+ /**
+ * NAT-Traversal and Transport Mode:
+ * we need to correct TCP/UDP checksum
+ *
+ * If we've got NAT-OA, we can fix checksum without recalculation.
+ */
+ __u32 natt_oa = ipsp->ips_natt_oa ?
+ ((struct sockaddr_in*)(ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
+ __u16 pkt_len = skb->tail - (unsigned char *)ipp;
+ __u16 data_len = pkt_len - (ipp->ihl << 2);
+
+ switch (ipp->protocol) {
+ case IPPROTO_TCP:
+ if (data_len >= sizeof(struct tcphdr)) {
+ struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ipp+ipp->ihl);
+ if (natt_oa) {
+ __u32 buff[2] = { ~natt_oa, ipp->saddr };
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: "
+ "fix TCP checksum using NAT-OA\n");
+ tcp->check = csum_fold(
+ csum_partial((unsigned char *)buff, sizeof(buff),
+ tcp->check^0xffff));
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: recalc TCP checksum\n");
+ if (pkt_len > (ntohs(ipp->tot_len)))
+ data_len -= (pkt_len - ntohs(ipp->tot_len));
+ tcp->check = 0;
+ tcp->check = csum_tcpudp_magic(ipp->saddr, ipp->daddr,
+ data_len, IPPROTO_TCP,
+ csum_partial((unsigned char *)tcp, data_len, 0));
+ }
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: can't fix TCP checksum\n");
+ }
+ break;
+ case IPPROTO_UDP:
+ if (data_len >= sizeof(struct udphdr)) {
+ struct udphdr *udp = (struct udphdr *)((__u32 *)ipp+ipp->ihl);
+ if (udp->check == 0) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: UDP checksum already 0\n");
+ }
+ else if (natt_oa) {
+ __u32 buff[2] = { ~natt_oa, ipp->saddr };
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: "
+ "fix UDP checksum using NAT-OA\n");
+ udp->check = csum_fold(
+ csum_partial((unsigned char *)buff, sizeof(buff),
+ udp->check^0xffff));
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: zero UDP checksum\n");
+ udp->check = 0;
+ }
+ }
+ else {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: can't fix UDP checksum\n");
+ }
+ break;
+ default:
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
+ break;
+ }
+ }
+#endif
+
+ /*
+ * XXX this needs to be locked from when it was first looked
+ * up in the decapsulation loop. Perhaps it is better to put
+ * the IPIP decap inside the loop.
+ */
+ if(ipsnext) {
+ ipsp = ipsnext;
+ irs.sa_len = satoa(irs.said, 0, irs.sa, SATOA_BUF);
+ if(ipp->protocol != IPPROTO_IPIP) {
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, Hey! How did this get through? Dropped.\n",
+ irs.sa_len ? irs.sa : " (error)");
+ if(stats) {
+ stats->rx_dropped++;
+ }
+ goto rcvleave;
+ }
+ if(sysctl_ipsec_inbound_policy_check) {
+ if((ipsnext = ipsp->ips_inext)) {
+ char sa2[SATOA_BUF];
+ size_t sa_len2;
+ sa_len2 = satoa(ipsnext->ips_said, 0, sa2, SATOA_BUF);
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "unexpected SA:%s after IPIP SA:%s\n",
+ sa_len2 ? sa2 : " (error)",
+ irs.sa_len ? irs.sa : " (error)");
+ if(stats) {
+ stats->rx_dropped++;
+ }
+ goto rcvleave;
+ }
+ if(ipp->saddr != ((struct sockaddr_in*)(ipsp->ips_addr_s))->sin_addr.s_addr) {
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
+ irs.sa_len ? irs.sa : " (error)",
+ irs.ipsaddr_txt);
+ if(stats) {
+ stats->rx_dropped++;
+ }
+ goto rcvleave;
+ }
+ }
+
+ /*
+ * XXX this needs to be locked from when it was first looked
+ * up in the decapsulation loop. Perhaps it is better to put
+ * the IPIP decap inside the loop.
+ */
+ ipsp->ips_life.ipl_bytes.ipl_count += skb->len;
+ ipsp->ips_life.ipl_bytes.ipl_last = skb->len;
+
+ if(!ipsp->ips_life.ipl_usetime.ipl_count) {
+ ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
+ }
+ ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
+ ipsp->ips_life.ipl_packets.ipl_count += 1;
+
+ if(skb->len < irs.iphlen) {
+ spin_unlock(&tdb_lock);
+ printk(KERN_WARNING "klips_debug:ipsec_rcv: "
+ "tried to skb_pull iphlen=%d, %d available. This should never happen, please report.\n",
+ irs.iphlen,
+ (int)(skb->len));
+
+ goto rcvleave;
+ }
+ skb_pull(skb, irs.iphlen);
+
+#ifdef NET_21
+ skb->nh.raw = skb->data;
+ ipp = (struct iphdr *)skb->nh.raw;
+ skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2);
+
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+#else /* NET_21 */
+ ipp = skb->ip_hdr = skb->h.iph = (struct iphdr *)skb->data;
+
+ memset(skb->proto_priv, 0, sizeof(struct options));
+#endif /* NET_21 */
+ ipsaddr.s_addr = ipp->saddr;
+ addrtoa(ipsaddr, 0, irs.ipsaddr_txt, sizeof(irs.ipsaddr_txt));
+ ipdaddr.s_addr = ipp->daddr;
+ addrtoa(ipdaddr, 0, irs.ipdaddr_txt, sizeof(irs.ipdaddr_txt));
+
+ skb->protocol = htons(ETH_P_IP);
+ skb->ip_summed = 0;
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "IPIP tunnel stripped.\n");
+ KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);
+
+ if(sysctl_ipsec_inbound_policy_check
+ /*
+ Note: "xor" (^) logically replaces "not equal"
+ (!=) and "bitwise or" (|) logically replaces
+ "boolean or" (||). This is done to speed up
+ execution by doing only bitwise operations and
+ no branch operations
+ */
+ && (((ipp->saddr & ipsp->ips_mask_s.u.v4.sin_addr.s_addr)
+ ^ ipsp->ips_flow_s.u.v4.sin_addr.s_addr)
+ | ((ipp->daddr & ipsp->ips_mask_d.u.v4.sin_addr.s_addr)
+ ^ ipsp->ips_flow_d.u.v4.sin_addr.s_addr)) )
+ {
+ char sflow_txt[SUBNETTOA_BUF], dflow_txt[SUBNETTOA_BUF];
+
+ subnettoa(ipsp->ips_flow_s.u.v4.sin_addr,
+ ipsp->ips_mask_s.u.v4.sin_addr,
+ 0, sflow_txt, sizeof(sflow_txt));
+ subnettoa(ipsp->ips_flow_d.u.v4.sin_addr,
+ ipsp->ips_mask_d.u.v4.sin_addr,
+ 0, dflow_txt, sizeof(dflow_txt));
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "SA:%s, inner tunnel policy [%s -> %s] does not agree with pkt contents [%s -> %s].\n",
+ irs.sa_len ? irs.sa : " (error)",
+ sflow_txt,
+ dflow_txt,
+ irs.ipsaddr_txt,
+ irs.ipdaddr_txt);
+ if(stats) {
+ stats->rx_dropped++;
+ }
+ goto rcvleave;
+ }
+#ifdef CONFIG_NETFILTER
+ skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_TABLE_MASK))))
+ | IPsecSAref2NFmark(IPsecSA2SAref(ipsp));
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "IPIP SA sets skb->nfmark=0x%x.\n",
+ (unsigned)skb->nfmark);
+#endif /* CONFIG_NETFILTER */
+ }
+
+ spin_unlock(&tdb_lock);
+
+#ifdef NET_21
+ if(stats) {
+ stats->rx_bytes += skb->len;
+ }
+ if(skb->dst) {
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ }
+ skb->pkt_type = PACKET_HOST;
+ if(irs.hard_header_len &&
+ (skb->mac.raw != (skb->data - irs.hard_header_len)) &&
+ (irs.hard_header_len <= skb_headroom(skb))) {
+ /* copy back original MAC header */
+ memmove(skb->data - irs.hard_header_len, skb->mac.raw, irs.hard_header_len);
+ skb->mac.raw = skb->data - irs.hard_header_len;
+ }
+#endif /* NET_21 */
+
+#ifdef CONFIG_IPSEC_IPCOMP
+ if(ipp->protocol == IPPROTO_COMP) {
+ unsigned int flags = 0;
+
+ if(sysctl_ipsec_inbound_policy_check) {
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "inbound policy checking enabled, IPCOMP follows IPIP, dropped.\n");
+ if (stats) {
+ stats->rx_errors++;
+ }
+ goto rcvleave;
+ }
+ /*
+ XXX need a ipsec_sa for updating ratio counters but it is not
+ following policy anyways so it is not a priority
+ */
+ skb = skb_decompress(skb, NULL, &flags);
+ if (!skb || flags) {
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "skb_decompress() returned error flags: %d, dropped.\n",
+ flags);
+ if (stats) {
+ stats->rx_errors++;
+ }
+ goto rcvleave;
+ }
+ }
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef SKB_RESET_NFCT
+ nf_conntrack_put(skb->nfct);
+ skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ skb->nf_debug = 0;
+#endif /* CONFIG_NETFILTER_DEBUG */
+#endif /* SKB_RESET_NFCT */
+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
+ "klips_debug:ipsec_rcv: "
+ "netif_rx() called.\n");
+ netif_rx(skb);
+
+ MOD_DEC_USE_COUNT;
+ return(0);
+
+ rcvleave:
+ if(skb) {
+ ipsec_kfree_skb(skb);
+ }
+
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+struct inet_protocol ah_protocol =
+{
+ ipsec_rcv, /* AH handler */
+ NULL, /* TUNNEL error control */
+#ifdef NETDEV_25
+ 1, /* no policy */
+#else
+ 0, /* next */
+ IPPROTO_AH, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "AH" /* name */
+#endif
+};
+
+struct inet_protocol esp_protocol =
+{
+ ipsec_rcv, /* ESP handler */
+ NULL, /* TUNNEL error control */
+#ifdef NETDEV_25
+ 1, /* no policy */
+#else
+ 0, /* next */
+ IPPROTO_ESP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "ESP" /* name */
+#endif
+};
+
+#if 0
+/* We probably don't want to install a pure IPCOMP protocol handler, but
+ only want to handle IPCOMP if it is encapsulated inside an ESP payload
+ (which is already handled) */
+#ifdef CONFIG_IPSEC_IPCOMP
+struct inet_protocol comp_protocol =
+{
+ ipsec_rcv, /* COMP handler */
+ NULL, /* COMP error control */
+#ifdef NETDEV_25
+ 1, /* no policy */
+#else
+ 0, /* next */
+ IPPROTO_COMP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "COMP" /* name */
+#endif
+};
+#endif /* CONFIG_IPSEC_IPCOMP */
+#endif
diff --git a/linux/net/ipsec/ipsec_sa.c b/linux/net/ipsec/ipsec_sa.c
new file mode 100644
index 000000000..4f73b92f2
--- /dev/null
+++ b/linux/net/ipsec/ipsec_sa.c
@@ -0,0 +1,1031 @@
+/*
+ * Common routines for IPsec SA maintenance routines.
+ *
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 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.
+ *
+ * RCSID $Id: ipsec_sa.c,v 1.3 2004/06/13 19:57:50 as Exp $
+ *
+ * This is the file formerly known as "ipsec_xform.h"
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/vmalloc.h> /* vmalloc() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef SPINLOCK
+#ifdef SPINLOCK_23
+#include <linux/spinlock.h> /* *lock* */
+#else /* SPINLOCK_23 */
+#include <asm/spinlock.h> /* *lock* */
+#endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+#include <asm/uaccess.h>
+#include <linux/in6.h>
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/radij.h"
+
+#include "freeswan/ipsec_stats.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_xform.h"
+
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_xform = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
+#ifdef SPINLOCK
+spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
+#else /* SPINLOCK */
+spinlock_t tdb_lock;
+#endif /* SPINLOCK */
+
+struct ipsec_sadb ipsec_sadb;
+
+#if IPSEC_SA_REF_CODE
+
+/* the sub table must be narrower (or equal) in bits than the variable type
+ in the main table to count the number of unused entries in it. */
+typedef struct {
+ int testSizeOf_refSubTable :
+ ((sizeof(IPsecRefTableUnusedCount) * 8) < IPSEC_SA_REF_SUBTABLE_IDX_WIDTH ? -1 : 1);
+} dummy;
+
+
+/* The field where the saref will be hosted in the skb must be wide enough to
+ accomodate the information it needs to store. */
+typedef struct {
+ int testSizeOf_refField :
+ (IPSEC_SA_REF_HOST_FIELD_WIDTH < IPSEC_SA_REF_TABLE_IDX_WIDTH ? -1 : 1 );
+} dummy2;
+
+
+void
+ipsec_SAtest(void)
+{
+ IPsecSAref_t SAref = 258;
+ struct ipsec_sa ips;
+ ips.ips_ref = 772;
+
+ printk("klips_debug:ipsec_SAtest: "
+ "IPSEC_SA_REF_SUBTABLE_IDX_WIDTH=%u\n"
+ "IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES=%u\n"
+ "IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES=%u\n"
+ "IPSEC_SA_REF_HOST_FIELD_WIDTH=%lu\n"
+ "IPSEC_SA_REF_TABLE_MASK=%x\n"
+ "IPSEC_SA_REF_ENTRY_MASK=%x\n"
+ "IPsecSAref2table(%d)=%u\n"
+ "IPsecSAref2entry(%d)=%u\n"
+ "IPsecSAref2NFmark(%d)=%u\n"
+ "IPsecSAref2SA(%d)=%p\n"
+ "IPsecSA2SAref(%p)=%d\n"
+ ,
+ IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
+ IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
+ (unsigned long) IPSEC_SA_REF_HOST_FIELD_WIDTH,
+ IPSEC_SA_REF_TABLE_MASK,
+ IPSEC_SA_REF_ENTRY_MASK,
+ SAref, IPsecSAref2table(SAref),
+ SAref, IPsecSAref2entry(SAref),
+ SAref, IPsecSAref2NFmark(SAref),
+ SAref, IPsecSAref2SA(SAref),
+ (&ips), IPsecSA2SAref((&ips))
+ );
+ return;
+}
+
+int
+ipsec_SAref_recycle(void)
+{
+ int table;
+ int entry;
+ int error = 0;
+
+ ipsec_sadb.refFreeListHead = -1;
+ ipsec_sadb.refFreeListTail = -1;
+
+ if(ipsec_sadb.refFreeListCont == IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "end of table reached, continuing at start..\n");
+ ipsec_sadb.refFreeListCont = 0;
+ }
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "recycling, continuing from SAref=%d (0p%p), table=%d, entry=%d.\n",
+ ipsec_sadb.refFreeListCont,
+ (ipsec_sadb.refTable[IPsecSAref2table(ipsec_sadb.refFreeListCont)] != NULL) ? IPsecSAref2SA(ipsec_sadb.refFreeListCont) : NULL,
+ IPsecSAref2table(ipsec_sadb.refFreeListCont),
+ IPsecSAref2entry(ipsec_sadb.refFreeListCont));
+
+ for(table = IPsecSAref2table(ipsec_sadb.refFreeListCont);
+ table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES;
+ table++) {
+ if(ipsec_sadb.refTable[table] == NULL) {
+ error = ipsec_SArefSubTable_alloc(table);
+ if(error) {
+ return error;
+ }
+ }
+ for(entry = IPsecSAref2entry(ipsec_sadb.refFreeListCont);
+ entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES;
+ entry++) {
+ if(ipsec_sadb.refTable[table]->entry[entry] == NULL) {
+ ipsec_sadb.refFreeList[++ipsec_sadb.refFreeListTail] = IPsecSArefBuild(table, entry);
+ if(ipsec_sadb.refFreeListTail == (IPSEC_SA_REF_FREELIST_NUM_ENTRIES - 1)) {
+ ipsec_sadb.refFreeListHead = 0;
+ ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "SArefFreeList refilled.\n");
+ return 0;
+ }
+ }
+ }
+ }
+
+ if(ipsec_sadb.refFreeListTail == -1) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "out of room in the SArefTable.\n");
+
+ return(-ENOSPC);
+ }
+
+ ipsec_sadb.refFreeListHead = 0;
+ ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_recycle: "
+ "SArefFreeList partly refilled to %d of %d.\n",
+ ipsec_sadb.refFreeListTail,
+ IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
+ return 0;
+}
+
+int
+ipsec_SArefSubTable_alloc(unsigned table)
+{
+ unsigned entry;
+ struct IPsecSArefSubTable* SArefsub;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SArefSubTable_alloc: "
+ "allocating %lu bytes for table %u of %u.\n",
+ (unsigned long) (IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *)),
+ table,
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
+
+ /* allocate another sub-table */
+ SArefsub = vmalloc(IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *));
+ if(SArefsub == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SArefSubTable_alloc: "
+ "error allocating memory for table %u of %u!\n",
+ table,
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
+ return -ENOMEM;
+ }
+
+ /* add this sub-table to the main table */
+ ipsec_sadb.refTable[table] = SArefsub;
+
+ /* initialise each element to NULL */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SArefSubTable_alloc: "
+ "initialising %u elements (2 ^ %u) of table %u.\n",
+ IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
+ IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
+ table);
+ for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
+ SArefsub->entry[entry] = NULL;
+ }
+
+ return 0;
+}
+#endif /* IPSEC_SA_REF_CODE */
+
+int
+ipsec_saref_freelist_init(void)
+{
+ int i;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_saref_freelist_init: "
+ "initialising %u elements of FreeList.\n",
+ IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
+
+ for(i = 0; i < IPSEC_SA_REF_FREELIST_NUM_ENTRIES; i++) {
+ ipsec_sadb.refFreeList[i] = IPSEC_SAREF_NULL;
+ }
+ ipsec_sadb.refFreeListHead = -1;
+ ipsec_sadb.refFreeListCont = 0;
+ ipsec_sadb.refFreeListTail = -1;
+
+ return 0;
+}
+
+int
+ipsec_sadb_init(void)
+{
+ int error = 0;
+ unsigned i;
+
+ for(i = 0; i < SADB_HASHMOD; i++) {
+ ipsec_sadb_hash[i] = NULL;
+ }
+ /* parts above are for the old style SADB hash table */
+
+
+#if IPSEC_SA_REF_CODE
+ /* initialise SA reference table */
+
+ /* initialise the main table */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_init: "
+ "initialising main table of size %u (2 ^ %u).\n",
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
+ IPSEC_SA_REF_MAINTABLE_IDX_WIDTH);
+ {
+ unsigned table;
+ for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
+ ipsec_sadb.refTable[table] = NULL;
+ }
+ }
+
+ /* allocate the first sub-table */
+ error = ipsec_SArefSubTable_alloc(0);
+ if(error) {
+ return error;
+ }
+
+ error = ipsec_saref_freelist_init();
+#endif /* IPSEC_SA_REF_CODE */
+ return error;
+}
+
+#if IPSEC_SA_REF_CODE
+IPsecSAref_t
+ipsec_SAref_alloc(int*error) /* pass in error var by pointer */
+{
+ IPsecSAref_t SAref;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "SAref requested... head=%d, cont=%d, tail=%d, listsize=%d.\n",
+ ipsec_sadb.refFreeListHead,
+ ipsec_sadb.refFreeListCont,
+ ipsec_sadb.refFreeListTail,
+ IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
+
+ if(ipsec_sadb.refFreeListHead == -1) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "FreeList empty, recycling...\n");
+ *error = ipsec_SAref_recycle();
+ if(*error) {
+ return IPSEC_SAREF_NULL;
+ }
+ }
+
+ SAref = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead];
+ if(SAref == IPSEC_SAREF_NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "unexpected error, refFreeListHead = %d points to invalid entry.\n",
+ ipsec_sadb.refFreeListHead);
+ *error = -ESPIPE;
+ return IPSEC_SAREF_NULL;
+ }
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "allocating SAref=%d, table=%u, entry=%u of %u.\n",
+ SAref,
+ IPsecSAref2table(SAref),
+ IPsecSAref2entry(SAref),
+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES);
+
+ ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead] = IPSEC_SAREF_NULL;
+ ipsec_sadb.refFreeListHead++;
+ if(ipsec_sadb.refFreeListHead > ipsec_sadb.refFreeListTail) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_SAref_alloc: "
+ "last FreeList entry allocated, resetting list head to empty.\n");
+ ipsec_sadb.refFreeListHead = -1;
+ }
+
+ return SAref;
+}
+#endif /* IPSEC_SA_REF_CODE */
+
+int
+ipsec_sa_print(struct ipsec_sa *ips)
+{
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ printk(KERN_INFO "klips_debug: SA:");
+ if(ips == NULL) {
+ printk("NULL\n");
+ return -ENOENT;
+ }
+ printk(" ref=%d", ips->ips_ref);
+ printk(" refcount=%d", atomic_read(&ips->ips_refcount));
+ if(ips->ips_hnext != NULL) {
+ printk(" hnext=0p%p", ips->ips_hnext);
+ }
+ if(ips->ips_inext != NULL) {
+ printk(" inext=0p%p", ips->ips_inext);
+ }
+ if(ips->ips_onext != NULL) {
+ printk(" onext=0p%p", ips->ips_onext);
+ }
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ printk(" said=%s", sa_len ? sa : " (error)");
+ if(ips->ips_seq) {
+ printk(" seq=%u", ips->ips_seq);
+ }
+ if(ips->ips_pid) {
+ printk(" pid=%u", ips->ips_pid);
+ }
+ if(ips->ips_authalg) {
+ printk(" authalg=%u", ips->ips_authalg);
+ }
+ if(ips->ips_encalg) {
+ printk(" encalg=%u", ips->ips_encalg);
+ }
+ printk(" XFORM=%s%s%s", IPS_XFORM_NAME(ips));
+ if(ips->ips_replaywin) {
+ printk(" ooowin=%u", ips->ips_replaywin);
+ }
+ if(ips->ips_flags) {
+ printk(" flags=%u", ips->ips_flags);
+ }
+ if(ips->ips_addr_s) {
+ char buf[SUBNETTOA_BUF];
+ addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
+ 0, buf, sizeof(buf));
+ printk(" src=%s", buf);
+ }
+ if(ips->ips_addr_d) {
+ char buf[SUBNETTOA_BUF];
+ addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
+ 0, buf, sizeof(buf));
+ printk(" dst=%s", buf);
+ }
+ if(ips->ips_addr_p) {
+ char buf[SUBNETTOA_BUF];
+ addrtoa(((struct sockaddr_in*)(ips->ips_addr_p))->sin_addr,
+ 0, buf, sizeof(buf));
+ printk(" proxy=%s", buf);
+ }
+ if(ips->ips_key_bits_a) {
+ printk(" key_bits_a=%u", ips->ips_key_bits_a);
+ }
+ if(ips->ips_key_bits_e) {
+ printk(" key_bits_e=%u", ips->ips_key_bits_e);
+ }
+
+ printk("\n");
+ return 0;
+}
+
+struct ipsec_sa*
+ipsec_sa_alloc(int*error) /* pass in error var by pointer */
+{
+ struct ipsec_sa* ips;
+
+ if((ips = kmalloc(sizeof(*ips), GFP_ATOMIC) ) == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_alloc: "
+ "memory allocation error\n");
+ *error = -ENOMEM;
+ return NULL;
+ }
+ memset((caddr_t)ips, 0, sizeof(*ips));
+#if IPSEC_SA_REF_CODE
+ ips->ips_ref = ipsec_SAref_alloc(error); /* pass in error return by pointer */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_alloc: "
+ "allocated %lu bytes for ipsec_sa struct=0p%p ref=%d.\n",
+ (unsigned long) sizeof(*ips),
+ ips,
+ ips->ips_ref);
+ if(ips->ips_ref == IPSEC_SAREF_NULL) {
+ kfree(ips);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_alloc: "
+ "SAref allocation error\n");
+ return NULL;
+ }
+
+ atomic_inc(&ips->ips_refcount);
+ IPsecSAref2SA(ips->ips_ref) = ips;
+#endif /* IPSEC_SA_REF_CODE */
+
+ *error = 0;
+ return(ips);
+}
+
+int
+ipsec_sa_free(struct ipsec_sa* ips)
+{
+ return ipsec_sa_wipe(ips);
+}
+
+struct ipsec_sa *
+ipsec_sa_getbyid(struct sa_id *said)
+{
+ int hashval;
+ struct ipsec_sa *ips;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ if(said == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_getbyid: "
+ "null pointer passed in!\n");
+ return NULL;
+ }
+
+ sa_len = satoa(*said, 0, sa, SATOA_BUF);
+
+ hashval = (said->spi+said->dst.s_addr+said->proto) % SADB_HASHMOD;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_getbyid: "
+ "linked entry in ipsec_sa table for hash=%d of SA:%s requested.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+
+ if((ips = ipsec_sadb_hash[hashval]) == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_getbyid: "
+ "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+ return NULL;
+ }
+
+ for (; ips; ips = ips->ips_hnext) {
+ if ((ips->ips_said.spi == said->spi) &&
+ (ips->ips_said.dst.s_addr == said->dst.s_addr) &&
+ (ips->ips_said.proto == said->proto)) {
+ atomic_inc(&ips->ips_refcount);
+ return ips;
+ }
+ }
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_getbyid: "
+ "no entry in linked list for hash=%d of SA:%s.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+ return NULL;
+}
+
+int
+ipsec_sa_put(struct ipsec_sa *ips)
+{
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ if(ips == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_put: "
+ "null pointer passed in!\n");
+ return -1;
+ }
+
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_put: "
+ "ipsec_sa SA:%s, ref:%d reference count decremented.\n",
+ sa_len ? sa : " (error)",
+ ips->ips_ref);
+
+ atomic_dec(&ips->ips_refcount);
+
+ return 0;
+}
+
+/*
+ The ipsec_sa table better *NOT* be locked before it is handed in, or SMP locks will happen
+*/
+int
+ipsec_sa_add(struct ipsec_sa *ips)
+{
+ int error = 0;
+ unsigned int hashval;
+
+ if(ips == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_add: "
+ "null pointer passed in!\n");
+ return -ENODATA;
+ }
+ hashval = ((ips->ips_said.spi + ips->ips_said.dst.s_addr + ips->ips_said.proto) % SADB_HASHMOD);
+
+ atomic_inc(&ips->ips_refcount);
+ spin_lock_bh(&tdb_lock);
+
+ ips->ips_hnext = ipsec_sadb_hash[hashval];
+ ipsec_sadb_hash[hashval] = ips;
+
+ spin_unlock_bh(&tdb_lock);
+
+ return error;
+}
+
+/*
+ The ipsec_sa table better be locked before it is handed in, or races might happen
+*/
+int
+ipsec_sa_del(struct ipsec_sa *ips)
+{
+ unsigned int hashval;
+ struct ipsec_sa *ipstp;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ if(ips == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_del: "
+ "null pointer passed in!\n");
+ return -ENODATA;
+ }
+
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ if(ips->ips_inext || ips->ips_onext) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_del: "
+ "SA:%s still linked!\n",
+ sa_len ? sa : " (error)");
+ return -EMLINK;
+ }
+
+ hashval = ((ips->ips_said.spi + ips->ips_said.dst.s_addr + ips->ips_said.proto) % SADB_HASHMOD);
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "deleting SA:%s, hashval=%d.\n",
+ sa_len ? sa : " (error)",
+ hashval);
+ if(ipsec_sadb_hash[hashval] == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+ return -ENOENT;
+ }
+
+ if (ips == ipsec_sadb_hash[hashval]) {
+ ipsec_sadb_hash[hashval] = ipsec_sadb_hash[hashval]->ips_hnext;
+ ips->ips_hnext = NULL;
+ atomic_dec(&ips->ips_refcount);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "successfully deleted first ipsec_sa in chain.\n");
+ return 0;
+ } else {
+ for (ipstp = ipsec_sadb_hash[hashval];
+ ipstp;
+ ipstp = ipstp->ips_hnext) {
+ if (ipstp->ips_hnext == ips) {
+ ipstp->ips_hnext = ips->ips_hnext;
+ ips->ips_hnext = NULL;
+ atomic_dec(&ips->ips_refcount);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "successfully deleted link in ipsec_sa chain.\n");
+ return 0;
+ }
+ }
+ }
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_del: "
+ "no entries in linked list for hash=%d of SA:%s.\n",
+ hashval,
+ sa_len ? sa : " (error)");
+ return -ENOENT;
+}
+
+/*
+ The ipsec_sa table better be locked before it is handed in, or races
+ might happen
+*/
+int
+ipsec_sa_delchain(struct ipsec_sa *ips)
+{
+ struct ipsec_sa *ipsdel;
+ int error = 0;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ if(ips == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_error:ipsec_sa_delchain: "
+ "null pointer passed in!\n");
+ return -ENODATA;
+ }
+
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_delchain: "
+ "passed SA:%s\n",
+ sa_len ? sa : " (error)");
+ while(ips->ips_onext != NULL) {
+ ips = ips->ips_onext;
+ }
+
+ while(ips) {
+ /* XXX send a pfkey message up to advise of deleted ipsec_sa */
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_delchain: "
+ "unlinking and delting SA:%s",
+ sa_len ? sa : " (error)");
+ ipsdel = ips;
+ ips = ips->ips_inext;
+ if(ips != NULL) {
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", inext=%s",
+ sa_len ? sa : " (error)");
+ atomic_dec(&ipsdel->ips_refcount);
+ ipsdel->ips_inext = NULL;
+ atomic_dec(&ips->ips_refcount);
+ ips->ips_onext = NULL;
+ }
+ KLIPS_PRINT(debug_xform,
+ ".\n");
+ if((error = ipsec_sa_del(ipsdel))) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_delchain: "
+ "ipsec_sa_del returned error %d.\n", -error);
+ return error;
+ }
+ if((error = ipsec_sa_wipe(ipsdel))) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_delchain: "
+ "ipsec_sa_wipe returned error %d.\n", -error);
+ return error;
+ }
+ }
+ return error;
+}
+
+int
+ipsec_sadb_cleanup(__u8 proto)
+{
+ unsigned i;
+ int error = 0;
+ struct ipsec_sa *ips, **ipsprev, *ipsdel;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "cleaning up proto=%d.\n",
+ proto);
+
+ spin_lock_bh(&tdb_lock);
+
+ for (i = 0; i < SADB_HASHMOD; i++) {
+ ipsprev = &(ipsec_sadb_hash[i]);
+ ips = ipsec_sadb_hash[i];
+ if(ips != NULL) {
+ atomic_inc(&ips->ips_refcount);
+ }
+ for(; ips != NULL;) {
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "checking SA:%s, hash=%d, ref=%d",
+ sa_len ? sa : " (error)",
+ i,
+ ips->ips_ref);
+ ipsdel = ips;
+ ips = ipsdel->ips_hnext;
+ if(ips != NULL) {
+ atomic_inc(&ips->ips_refcount);
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", hnext=%s",
+ sa_len ? sa : " (error)");
+ }
+ if(*ipsprev != NULL) {
+ sa_len = satoa((*ipsprev)->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", *ipsprev=%s",
+ sa_len ? sa : " (error)");
+ if((*ipsprev)->ips_hnext) {
+ sa_len = satoa((*ipsprev)->ips_hnext->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", *ipsprev->ips_hnext=%s",
+ sa_len ? sa : " (error)");
+ }
+ }
+ KLIPS_PRINT(debug_xform,
+ ".\n");
+ if(proto == 0 || (proto == ipsdel->ips_said.proto)) {
+ sa_len = satoa(ipsdel->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "deleting SA chain:%s.\n",
+ sa_len ? sa : " (error)");
+ if((error = ipsec_sa_delchain(ipsdel))) {
+ SENDERR(-error);
+ }
+ ipsprev = &(ipsec_sadb_hash[i]);
+ ips = ipsec_sadb_hash[i];
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "deleted SA chain:%s",
+ sa_len ? sa : " (error)");
+ if(ips != NULL) {
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", ipsec_sadb_hash[%d]=%s",
+ i,
+ sa_len ? sa : " (error)");
+ }
+ if(*ipsprev != NULL) {
+ sa_len = satoa((*ipsprev)->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", *ipsprev=%s",
+ sa_len ? sa : " (error)");
+ if((*ipsprev)->ips_hnext != NULL) {
+ sa_len = satoa((*ipsprev)->ips_hnext->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ ", *ipsprev->ips_hnext=%s",
+ sa_len ? sa : " (error)");
+ }
+ }
+ KLIPS_PRINT(debug_xform,
+ ".\n");
+ } else {
+ ipsprev = &ipsdel;
+ }
+ if(ipsdel != NULL) {
+ ipsec_sa_put(ipsdel);
+ }
+ }
+ }
+ errlab:
+
+ spin_unlock_bh(&tdb_lock);
+
+
+#if IPSEC_SA_REF_CODE
+ /* clean up SA reference table */
+
+ /* go through the ref table and clean out all the SAs */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "removing SAref entries and tables.");
+ {
+ unsigned table, entry;
+ for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "cleaning SAref table=%u.\n",
+ table);
+ if(ipsec_sadb.refTable[table] == NULL) {
+ printk("\n");
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_cleanup: "
+ "cleaned %u used refTables.\n",
+ table);
+ break;
+ }
+ for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
+ if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
+ ipsec_sa_delchain(ipsec_sadb.refTable[table]->entry[entry]);
+ ipsec_sadb.refTable[table]->entry[entry] = NULL;
+ }
+ }
+ }
+ }
+#endif /* IPSEC_SA_REF_CODE */
+
+ return(error);
+}
+
+int
+ipsec_sadb_free(void)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_free: "
+ "freeing SArefTable memory.\n");
+
+ /* clean up SA reference table */
+
+ /* go through the ref table and clean out all the SAs if any are
+ left and free table memory */
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_free: "
+ "removing SAref entries and tables.\n");
+ {
+ unsigned table, entry;
+ for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_free: "
+ "removing SAref table=%u.\n",
+ table);
+ if(ipsec_sadb.refTable[table] == NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sadb_free: "
+ "removed %u used refTables.\n",
+ table);
+ break;
+ }
+ for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
+ if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
+ ipsec_sa_delchain(ipsec_sadb.refTable[table]->entry[entry]);
+ ipsec_sadb.refTable[table]->entry[entry] = NULL;
+ }
+ }
+ vfree(ipsec_sadb.refTable[table]);
+ ipsec_sadb.refTable[table] = NULL;
+ }
+ }
+
+ return(error);
+}
+
+int
+ipsec_sa_wipe(struct ipsec_sa *ips)
+{
+ if(ips == NULL) {
+ return -ENODATA;
+ }
+
+ /* if(atomic_dec_and_test(ips)) {
+ }; */
+
+#if IPSEC_SA_REF_CODE
+ /* remove me from the SArefTable */
+ {
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ sa_len = satoa(ips->ips_said, 0, sa, SATOA_BUF);
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_wipe: "
+ "removing SA=%s(0p%p), SAref=%d, table=%d(0p%p), entry=%d from the refTable.\n",
+ sa_len ? sa : " (error)",
+ ips,
+ ips->ips_ref,
+ IPsecSAref2table(IPsecSA2SAref(ips)),
+ ipsec_sadb.refTable[IPsecSAref2table(IPsecSA2SAref(ips))],
+ IPsecSAref2entry(IPsecSA2SAref(ips)));
+ }
+ if(ips->ips_ref == IPSEC_SAREF_NULL) {
+ KLIPS_PRINT(debug_xform,
+ "klips_debug:ipsec_sa_wipe: "
+ "why does this SA not have a valid SAref?.\n");
+ }
+ ipsec_sadb.refTable[IPsecSAref2table(IPsecSA2SAref(ips))]->entry[IPsecSAref2entry(IPsecSA2SAref(ips))] = NULL;
+ ips->ips_ref = IPSEC_SAREF_NULL;
+ ipsec_sa_put(ips);
+#endif /* IPSEC_SA_REF_CODE */
+
+ /* paranoid clean up */
+ if(ips->ips_addr_s != NULL) {
+ memset((caddr_t)(ips->ips_addr_s), 0, ips->ips_addr_s_size);
+ kfree(ips->ips_addr_s);
+ }
+ ips->ips_addr_s = NULL;
+
+ if(ips->ips_addr_d != NULL) {
+ memset((caddr_t)(ips->ips_addr_d), 0, ips->ips_addr_d_size);
+ kfree(ips->ips_addr_d);
+ }
+ ips->ips_addr_d = NULL;
+
+ if(ips->ips_addr_p != NULL) {
+ memset((caddr_t)(ips->ips_addr_p), 0, ips->ips_addr_p_size);
+ kfree(ips->ips_addr_p);
+ }
+ ips->ips_addr_p = NULL;
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if(ips->ips_natt_oa) {
+ memset((caddr_t)(ips->ips_natt_oa), 0, ips->ips_natt_oa_size);
+ kfree(ips->ips_natt_oa);
+ }
+ ips->ips_natt_oa = NULL;
+#endif
+
+ if(ips->ips_key_a != NULL) {
+ memset((caddr_t)(ips->ips_key_a), 0, ips->ips_key_a_size);
+ kfree(ips->ips_key_a);
+ }
+ ips->ips_key_a = NULL;
+
+ if(ips->ips_key_e != NULL) {
+#ifdef CONFIG_IPSEC_ALG
+ if (ips->ips_alg_enc&&ips->ips_alg_enc->ixt_e_destroy_key) {
+ ips->ips_alg_enc->ixt_e_destroy_key(ips->ips_alg_enc,
+ ips->ips_key_e);
+ } else {
+#endif /* CONFIG_IPSEC_ALG */
+ memset((caddr_t)(ips->ips_key_e), 0, ips->ips_key_e_size);
+ kfree(ips->ips_key_e);
+#ifdef CONFIG_IPSEC_ALG
+ }
+#endif /* CONFIG_IPSEC_ALG */
+ }
+ ips->ips_key_e = NULL;
+
+ if(ips->ips_iv != NULL) {
+ memset((caddr_t)(ips->ips_iv), 0, ips->ips_iv_size);
+ kfree(ips->ips_iv);
+ }
+ ips->ips_iv = NULL;
+
+ if(ips->ips_ident_s.data != NULL) {
+ memset((caddr_t)(ips->ips_ident_s.data),
+ 0,
+ ips->ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
+ kfree(ips->ips_ident_s.data);
+ }
+ ips->ips_ident_s.data = NULL;
+
+ if(ips->ips_ident_d.data != NULL) {
+ memset((caddr_t)(ips->ips_ident_d.data),
+ 0,
+ ips->ips_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
+ kfree(ips->ips_ident_d.data);
+ }
+ ips->ips_ident_d.data = NULL;
+
+#ifdef CONFIG_IPSEC_ALG
+ if (ips->ips_alg_enc||ips->ips_alg_auth) {
+ ipsec_alg_sa_wipe(ips);
+ }
+#endif /* CONFIG_IPSEC_ALG */
+
+ memset((caddr_t)ips, 0, sizeof(*ips));
+ kfree(ips);
+ ips = NULL;
+
+ return 0;
+}
diff --git a/linux/net/ipsec/ipsec_sha1.c b/linux/net/ipsec/ipsec_sha1.c
new file mode 100644
index 000000000..389a55b06
--- /dev/null
+++ b/linux/net/ipsec/ipsec_sha1.c
@@ -0,0 +1,219 @@
+/*
+ * RCSID $Id: ipsec_sha1.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+/*
+ * The rest of the code is derived from sha1.c by Steve Reid, which is
+ * public domain.
+ * Minor cosmetic changes to accomodate it in the Linux kernel by ji.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/string.h>
+
+#include "freeswan/ipsec_sha1.h"
+
+#if defined(rol)
+#undef rol
+#endif
+
+#define SHA1HANDSOFF
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifdef __LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(__u32 state[5], __u8 buffer[64])
+{
+__u32 a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ __u32 l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(void *vcontext)
+{
+ SHA1_CTX* context = vcontext;
+
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(void *vcontext, unsigned char* data, __u32 len)
+{
+ SHA1_CTX* context = vcontext;
+ __u32 i, j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1]++;
+ context->count[1] += (len>>29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], void *vcontext)
+{
+ __u32 i, j;
+ unsigned char finalcount[8];
+ SHA1_CTX* context = vcontext;
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+
+/*
+ * $Log: ipsec_sha1.c,v $
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.8 2002/09/10 01:45:14 mcr
+ * changed type of MD5_CTX and SHA1_CTX to void * so that
+ * the function prototypes would match, and could be placed
+ * into a pointer to a function.
+ *
+ * Revision 1.7 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.6 2002/04/24 07:36:30 mcr
+ * Moved from ./klips/net/ipsec/ipsec_sha1.c,v
+ *
+ * Revision 1.5 1999/12/13 13:59:13 rgb
+ * Quick fix to argument size to Update bugs.
+ *
+ * Revision 1.4 1999/04/11 00:29:00 henry
+ * GPL boilerplate
+ *
+ * Revision 1.3 1999/04/06 04:54:27 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.2 1999/01/22 06:55:50 rgb
+ * 64-bit clean-up.
+ *
+ * Revision 1.1 1998/06/18 21:27:50 henry
+ * move sources from klips/src to klips/net/ipsec, to keep stupid
+ * kernel-build scripts happier in the presence of symlinks
+ *
+ * Revision 1.2 1998/04/23 20:54:04 rgb
+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
+ * verified.
+ *
+ * Revision 1.1 1998/04/09 03:06:11 henry
+ * sources moved up from linux/net/ipsec
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:05 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.4 1997/01/15 01:28:15 ji
+ * New transform
+ *
+ *
+ */
diff --git a/linux/net/ipsec/ipsec_tunnel.c b/linux/net/ipsec/ipsec_tunnel.c
new file mode 100644
index 000000000..de86843bb
--- /dev/null
+++ b/linux/net/ipsec/ipsec_tunnel.c
@@ -0,0 +1,1671 @@
+/*
+ * IPSEC Tunneling code. Heavily based on drivers/net/new_tunnel.c
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 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 ipsec_tunnel_c_version[] = "RCSID $Id: ipsec_tunnel.c,v 1.4 2005/06/16 21:21:02 as Exp $";
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/tcp.h> /* struct tcphdr */
+#include <linux/udp.h> /* struct udphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define ip_chk_addr inet_addr_type
+# define IS_MYADDR RTN_LOCAL
+# include <net/dst.h>
+# undef dev_kfree_skb
+# define dev_kfree_skb(a,b) kfree_skb(a)
+# define PHYSDEV_TYPE
+#endif /* NET_21 */
+#include <asm/checksum.h>
+#include <net/icmp.h> /* icmp_send() */
+#include <net/ip.h>
+#ifdef NETDEV_23
+# include <linux/netfilter_ipv4.h>
+#endif /* NETDEV_23 */
+
+#include <linux/if_arp.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_xmit.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+#include <linux/udp.h>
+#endif
+
+static __u32 zeroes[64];
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_tunnel = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_open(struct device *dev)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ /*
+ * Can't open until attached.
+ */
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_open: "
+ "dev = %s, prv->dev = %s\n",
+ dev->name, prv->dev?prv->dev->name:"NONE");
+
+ if (prv->dev == NULL)
+ return -ENODEV;
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_close(struct device *dev)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+#ifdef NETDEV_23
+static inline int ipsec_tunnel_xmit2(struct sk_buff *skb)
+{
+#ifdef NETDEV_25 /* 2.6 kernels */
+ return dst_output(skb);
+#else
+ return ip_send(skb);
+#endif
+}
+#endif /* NETDEV_23 */
+
+enum ipsec_xmit_value
+ipsec_tunnel_strip_hard_header(struct ipsec_xmit_state *ixs)
+{
+ /* ixs->physdev->hard_header_len is unreliable and should not be used */
+ ixs->hard_header_len = (unsigned char *)(ixs->iph) - ixs->skb->data;
+
+ if(ixs->hard_header_len < 0) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_strip_hard_header: "
+ "Negative hard_header_len (%d)?!\n", ixs->hard_header_len);
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_BADHHLEN;
+ }
+
+ /* while ixs->physdev->hard_header_len is unreliable and
+ * should not be trusted, it accurate and required for ATM, GRE and
+ * some other interfaces to work. Thanks to Willy Tarreau
+ * <willy@w.ods.org>.
+ */
+ if(ixs->hard_header_len == 0) { /* no hard header present */
+ ixs->hard_header_stripped = 1;
+ ixs->hard_header_len = ixs->physdev->hard_header_len;
+ }
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_tunnel & DB_TN_XMIT) {
+ int i;
+ char c;
+
+ printk(KERN_INFO "klips_debug:ipsec_xmit_strip_hard_header: "
+ ">>> skb->len=%ld hard_header_len:%d",
+ (unsigned long int)ixs->skb->len, ixs->hard_header_len);
+ c = ' ';
+ for (i=0; i < ixs->hard_header_len; i++) {
+ printk("%c%02x", c, ixs->skb->data[i]);
+ c = ':';
+ }
+ printk(" \n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_strip_hard_header: "
+ "Original head,tailroom: %d,%d\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_tunnel_SAlookup(struct ipsec_xmit_state *ixs)
+{
+ /*
+ * First things first -- look us up in the erouting tables.
+ */
+ ixs->matcher.sen_len = sizeof (struct sockaddr_encap);
+ ixs->matcher.sen_family = AF_ENCAP;
+ ixs->matcher.sen_type = SENT_IP4;
+ ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
+ ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
+ ixs->matcher.sen_proto = ixs->iph->protocol;
+ ipsec_extract_ports(ixs->iph, &ixs->matcher);
+
+ /*
+ * The spinlock is to prevent any other process from accessing or deleting
+ * the eroute while we are using and updating it.
+ */
+ spin_lock(&eroute_lock);
+
+ ixs->eroute = ipsec_findroute(&ixs->matcher);
+
+ if(ixs->iph->protocol == IPPROTO_UDP) {
+ if(ixs->skb->sk) {
+ ixs->sport=ntohs(ixs->skb->sk->sport);
+ ixs->dport=ntohs(ixs->skb->sk->dport);
+ } else if((ntohs(ixs->iph->frag_off) & IP_OFFSET) == 0 &&
+ ((ixs->skb->len - ixs->hard_header_len) >=
+ ((ixs->iph->ihl << 2) + sizeof(struct udphdr)))) {
+ ixs->sport=ntohs(((struct udphdr*)((caddr_t)ixs->iph+(ixs->iph->ihl<<2)))->source);
+ ixs->dport=ntohs(((struct udphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl<<2)))->dest);
+ } else {
+ ixs->sport=0; ixs->dport=0;
+ }
+ }
+
+ /* default to a %drop eroute */
+ ixs->outgoing_said.proto = IPPROTO_INT;
+ ixs->outgoing_said.spi = htonl(SPI_DROP);
+ ixs->outgoing_said.dst.s_addr = INADDR_ANY;
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "checking for local udp/500 IKE packet "
+ "saddr=%x, er=0p%p, daddr=%x, er_dst=%x, proto=%d sport=%d dport=%d\n",
+ ntohl((unsigned int)ixs->iph->saddr),
+ ixs->eroute,
+ ntohl((unsigned int)ixs->iph->daddr),
+ ixs->eroute ? ntohl((unsigned int)ixs->eroute->er_said.dst.s_addr) : 0,
+ ixs->iph->protocol,
+ ixs->sport,
+ ixs->dport);
+
+ /*
+ * Quick cheat for now...are we udp/500 or udp/4500? If so, let it through
+ * without interference since it is most likely an IKE packet.
+ */
+
+ if (ip_chk_addr((unsigned long)ixs->iph->saddr) == IS_MYADDR
+ && (!ixs->eroute
+ || ixs->iph->daddr == ixs->eroute->er_said.dst.s_addr
+ || INADDR_ANY == ixs->eroute->er_said.dst.s_addr)
+ && ((ixs->sport == 500) || (ixs->sport == 4500))) {
+ /* Whatever the eroute, this is an IKE message
+ * from us (i.e. not being forwarded).
+ * Furthermore, if there is a tunnel eroute,
+ * the destination is the peer for this eroute.
+ * So %pass the packet: modify the default %drop.
+ */
+ ixs->outgoing_said.spi = htonl(SPI_PASS);
+ if(!(ixs->skb->sk) && ((ntohs(ixs->iph->frag_off) & IP_MF) != 0)) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "local UDP/500 (probably IKE) passthrough: base fragment, rest of fragments will probably get filtered.\n");
+ }
+ } else if (ixs->eroute) {
+ ixs->eroute->er_count++;
+ ixs->eroute->er_lasttime = jiffies/HZ;
+ if(ixs->eroute->er_said.proto==IPPROTO_INT
+ && ixs->eroute->er_said.spi==htonl(SPI_HOLD)) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "shunt SA of HOLD: skb stored in HOLD.\n");
+ if(ixs->eroute->er_last != NULL) {
+ kfree_skb(ixs->eroute->er_last);
+ }
+ ixs->eroute->er_last = ixs->skb;
+ ixs->skb = NULL;
+ ixs->stats->tx_dropped++;
+ spin_unlock(&eroute_lock);
+ return IPSEC_XMIT_STOLEN;
+ }
+ ixs->outgoing_said = ixs->eroute->er_said;
+ ixs->eroute_pid = ixs->eroute->er_pid;
+ /* Copy of the ident for the TRAP/TRAPSUBNET eroutes */
+ if(ixs->outgoing_said.proto==IPPROTO_INT
+ && (ixs->outgoing_said.spi==htonl(SPI_TRAP)
+ || (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)))) {
+ int len;
+
+ ixs->ips.ips_ident_s.type = ixs->eroute->er_ident_s.type;
+ ixs->ips.ips_ident_s.id = ixs->eroute->er_ident_s.id;
+ ixs->ips.ips_ident_s.len = ixs->eroute->er_ident_s.len;
+ if (ixs->ips.ips_ident_s.len) {
+ len = ixs->ips.ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "allocating %d bytes for ident_s shunt SA of HOLD: skb stored in HOLD.\n",
+ len);
+ if ((ixs->ips.ips_ident_s.data = kmalloc(len, GFP_ATOMIC)) == NULL) {
+ printk(KERN_WARNING "klips_debug:ipsec_xmit_SAlookup: "
+ "Failed, tried to allocate %d bytes for source ident.\n",
+ len);
+ ixs->stats->tx_dropped++;
+ spin_unlock(&eroute_lock);
+ return IPSEC_XMIT_ERRMEMALLOC;
+ }
+ memcpy(ixs->ips.ips_ident_s.data, ixs->eroute->er_ident_s.data, len);
+ }
+ ixs->ips.ips_ident_d.type = ixs->eroute->er_ident_d.type;
+ ixs->ips.ips_ident_d.id = ixs->eroute->er_ident_d.id;
+ ixs->ips.ips_ident_d.len = ixs->eroute->er_ident_d.len;
+ if (ixs->ips.ips_ident_d.len) {
+ len = ixs->ips.ips_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_SAlookup: "
+ "allocating %d bytes for ident_d shunt SA of HOLD: skb stored in HOLD.\n",
+ len);
+ if ((ixs->ips.ips_ident_d.data = kmalloc(len, GFP_ATOMIC)) == NULL) {
+ printk(KERN_WARNING "klips_debug:ipsec_xmit_SAlookup: "
+ "Failed, tried to allocate %d bytes for dest ident.\n",
+ len);
+ ixs->stats->tx_dropped++;
+ spin_unlock(&eroute_lock);
+ return IPSEC_XMIT_ERRMEMALLOC;
+ }
+ memcpy(ixs->ips.ips_ident_d.data, ixs->eroute->er_ident_d.data, len);
+ }
+ }
+ }
+
+ spin_unlock(&eroute_lock);
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_tunnel_restore_hard_header(struct ipsec_xmit_state*ixs)
+{
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_restore_hard_header: "
+ "After recursive xforms -- head,tailroom: %d,%d\n",
+ skb_headroom(ixs->skb),
+ skb_tailroom(ixs->skb));
+
+ if(ixs->saved_header) {
+ if(skb_headroom(ixs->skb) < ixs->hard_header_len) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_restore_hard_header: "
+ "tried to skb_push hhlen=%d, %d available. This should never happen, please report.\n",
+ ixs->hard_header_len,
+ skb_headroom(ixs->skb));
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_PUSHPULLERR;
+
+ }
+ skb_push(ixs->skb, ixs->hard_header_len);
+ {
+ int i;
+ for (i = 0; i < ixs->hard_header_len; i++) {
+ ixs->skb->data[i] = ixs->saved_header[i];
+ }
+ }
+ }
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (ixs->natt_type && ixs->natt_head) {
+ struct iphdr *ipp = ixs->skb->nh.iph;
+ struct udphdr *udp;
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "encapsulating packet into UDP (NAT-Traversal) (%d %d)\n",
+ ixs->natt_type, ixs->natt_head);
+ ixs->iphlen = ipp->ihl << 2;
+ ipp->tot_len =
+ htons(ntohs(ipp->tot_len) + ixs->natt_head);
+ if(skb_tailroom(ixs->skb) < ixs->natt_head) {
+ printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
+ "tried to skb_put %d, %d available. "
+ "This should never happen, please report.\n",
+ ixs->natt_head,
+ skb_tailroom(ixs->skb));
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESPUDP;
+ }
+ skb_put(ixs->skb, ixs->natt_head);
+ udp = (struct udphdr *)((char *)ipp + ixs->iphlen);
+ /* move ESP hdr after UDP hdr */
+ memmove((void *)((char *)udp + ixs->natt_head),
+ (void *)(udp),
+ ntohs(ipp->tot_len) - ixs->iphlen - ixs->natt_head);
+ /* clear UDP & Non-IKE Markers (if any) */
+ memset(udp, 0, ixs->natt_head);
+ /* fill UDP with usefull informations ;-) */
+ udp->source = htons(ixs->natt_sport);
+ udp->dest = htons(ixs->natt_dport);
+ udp->len = htons(ntohs(ipp->tot_len) - ixs->iphlen);
+ /* set protocol */
+ ipp->protocol = IPPROTO_UDP;
+ /* fix IP checksum */
+ ipp->check = 0;
+ ipp->check = ip_fast_csum((unsigned char *)ipp, ipp->ihl);
+ }
+#endif
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_restore_hard_header: "
+ "With hard_header, final head,tailroom: %d,%d\n",
+ skb_headroom(ixs->skb),
+ skb_tailroom(ixs->skb));
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_tunnel_send(struct ipsec_xmit_state*ixs)
+{
+#ifdef NETDEV_25
+ struct flowi fl;
+#endif
+
+#ifdef NET_21 /* 2.2 and 2.4 kernels */
+ /* new route/dst cache code from James Morris */
+ ixs->skb->dev = ixs->physdev;
+#ifdef NETDEV_25
+ fl.oif = ixs->physdev->iflink;
+ fl.nl_u.ip4_u.daddr = ixs->skb->nh.iph->daddr;
+ fl.nl_u.ip4_u.saddr = ixs->pass ? 0 : ixs->skb->nh.iph->saddr;
+ fl.nl_u.ip4_u.tos = RT_TOS(ixs->skb->nh.iph->tos);
+ fl.proto = ixs->skb->nh.iph->protocol;
+ if ((ixs->error = ip_route_output_key(&ixs->route, &fl))) {
+#else
+ /*skb_orphan(ixs->skb);*/
+ if((ixs->error = ip_route_output(&ixs->route,
+ ixs->skb->nh.iph->daddr,
+ ixs->pass ? 0 : ixs->skb->nh.iph->saddr,
+ RT_TOS(ixs->skb->nh.iph->tos),
+ /* mcr->rgb: should this be 0 instead? */
+ ixs->physdev->iflink))) {
+#endif
+ ixs->stats->tx_errors++;
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "ip_route_output failed with error code %d, rt->u.dst.dev=%s, dropped\n",
+ ixs->error,
+ ixs->route->u.dst.dev->name);
+ return IPSEC_XMIT_ROUTEERR;
+ }
+ if(ixs->dev == ixs->route->u.dst.dev) {
+ ip_rt_put(ixs->route);
+ /* This is recursion, drop it. */
+ ixs->stats->tx_errors++;
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n",
+ ixs->dev->name);
+ return IPSEC_XMIT_RECURSDETECT;
+ }
+ dst_release(ixs->skb->dst);
+ ixs->skb->dst = &ixs->route->u.dst;
+ ixs->stats->tx_bytes += ixs->skb->len;
+ if(ixs->skb->len < ixs->skb->nh.raw - ixs->skb->data) {
+ ixs->stats->tx_errors++;
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_send: "
+ "tried to __skb_pull nh-data=%ld, %d available. This should never happen, please report.\n",
+ (unsigned long)(ixs->skb->nh.raw - ixs->skb->data),
+ ixs->skb->len);
+ return IPSEC_XMIT_PUSHPULLERR;
+ }
+ __skb_pull(ixs->skb, ixs->skb->nh.raw - ixs->skb->data);
+#ifdef SKB_RESET_NFCT
+ if(!ixs->pass) {
+ nf_conntrack_put(ixs->skb->nfct);
+ ixs->skb->nfct = NULL;
+ }
+#ifdef CONFIG_NETFILTER_DEBUG
+ ixs->skb->nf_debug = 0;
+#endif /* CONFIG_NETFILTER_DEBUG */
+#endif /* SKB_RESET_NFCT */
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "...done, calling ip_send() on device:%s\n",
+ ixs->skb->dev ? ixs->skb->dev->name : "NULL");
+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->skb->nh.iph);
+#ifdef NETDEV_23 /* 2.4 kernels */
+ {
+ int err;
+
+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, ixs->skb, NULL, ixs->route->u.dst.dev,
+ ipsec_tunnel_xmit2);
+ if(err != NET_XMIT_SUCCESS && err != NET_XMIT_CN) {
+ if(net_ratelimit())
+ printk(KERN_ERR
+ "klips_error:ipsec_xmit_send: "
+ "ip_send() failed, err=%d\n",
+ -err);
+ ixs->stats->tx_errors++;
+ ixs->stats->tx_aborted_errors++;
+ ixs->skb = NULL;
+ return IPSEC_XMIT_IPSENDFAILURE;
+ }
+ }
+#else /* NETDEV_23 */ /* 2.2 kernels */
+ ip_send(ixs->skb);
+#endif /* NETDEV_23 */
+#else /* NET_21 */ /* 2.0 kernels */
+ ixs->skb->arp = 1;
+ /* ISDN/ASYNC PPP from Matjaz Godec. */
+ /* skb->protocol = htons(ETH_P_IP); */
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_send: "
+ "...done, calling dev_queue_xmit() or ip_fragment().\n");
+ IP_SEND(ixs->skb, ixs->physdev);
+#endif /* NET_21 */
+ ixs->stats->tx_packets++;
+
+ ixs->skb = NULL;
+
+ return IPSEC_XMIT_OK;
+}
+
+void
+ipsec_tunnel_cleanup(struct ipsec_xmit_state*ixs)
+{
+#if defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE)
+ netif_wake_queue(ixs->dev);
+#else /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
+ ixs->dev->tbusy = 0;
+#endif /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
+ if(ixs->saved_header) {
+ kfree(ixs->saved_header);
+ }
+ if(ixs->skb) {
+ dev_kfree_skb(ixs->skb, FREE_WRITE);
+ }
+ if(ixs->oskb) {
+ dev_kfree_skb(ixs->oskb, FREE_WRITE);
+ }
+ if (ixs->ips.ips_ident_s.data) {
+ kfree(ixs->ips.ips_ident_s.data);
+ }
+ if (ixs->ips.ips_ident_d.data) {
+ kfree(ixs->ips.ips_ident_d.data);
+ }
+}
+
+/*
+ * This function assumes it is being called from dev_queue_xmit()
+ * and that skb is filled properly by that function.
+ */
+int
+ipsec_tunnel_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct ipsec_xmit_state ixs_mem;
+ struct ipsec_xmit_state *ixs = &ixs_mem;
+ enum ipsec_xmit_value stat;
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ ixs->natt_type = 0, ixs->natt_head = 0;
+ ixs->natt_sport = 0, ixs->natt_dport = 0;
+#endif
+
+ memset((caddr_t)ixs, 0, sizeof(*ixs));
+ ixs->oskb = NULL;
+ ixs->saved_header = NULL; /* saved copy of the hard header */
+ ixs->route = NULL;
+ memset((caddr_t)&(ixs->ips), 0, sizeof(ixs->ips));
+ ixs->dev = dev;
+ ixs->skb = skb;
+
+ stat = ipsec_xmit_sanity_check_dev(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ goto cleanup;
+ }
+
+ stat = ipsec_xmit_sanity_check_skb(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ goto cleanup;
+ }
+
+ stat = ipsec_tunnel_strip_hard_header(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ goto cleanup;
+ }
+
+ stat = ipsec_tunnel_SAlookup(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_tunnel_start_xmit: SAlookup failed: %d\n",
+ stat);
+ goto cleanup;
+ }
+
+ ixs->innersrc = ixs->iph->saddr;
+ /* start encapsulation loop here XXX */
+ do {
+ stat = ipsec_xmit_encap_bundle(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ if(stat == IPSEC_XMIT_PASS) {
+ goto bypass;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_tunnel_start_xmit: encap_bundle failed: %d\n",
+ stat);
+ goto cleanup;
+ }
+
+ ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
+ ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
+ ixs->matcher.sen_proto = ixs->iph->protocol;
+ ipsec_extract_ports(ixs->iph, &ixs->matcher);
+
+ spin_lock(&eroute_lock);
+ ixs->eroute = ipsec_findroute(&ixs->matcher);
+ if(ixs->eroute) {
+ ixs->outgoing_said = ixs->eroute->er_said;
+ ixs->eroute_pid = ixs->eroute->er_pid;
+ ixs->eroute->er_count++;
+ ixs->eroute->er_lasttime = jiffies/HZ;
+ }
+ spin_unlock(&eroute_lock);
+
+ KLIPS_PRINT((debug_tunnel & DB_TN_XMIT) &&
+ /* ((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc)) */
+ (ixs->orgedst != ixs->outgoing_said.dst.s_addr) &&
+ ixs->outgoing_said.dst.s_addr &&
+ ixs->eroute,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "We are recursing here.\n");
+
+ } while(/*((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc))*/
+ (ixs->orgedst != ixs->outgoing_said.dst.s_addr) &&
+ ixs->outgoing_said.dst.s_addr &&
+ ixs->eroute);
+
+ stat = ipsec_tunnel_restore_hard_header(ixs);
+ if(stat != IPSEC_XMIT_OK) {
+ goto cleanup;
+ }
+
+ bypass:
+ stat = ipsec_tunnel_send(ixs);
+
+ cleanup:
+ ipsec_tunnel_cleanup(ixs);
+
+ return 0;
+}
+
+DEBUG_NO_STATIC struct net_device_stats *
+ipsec_tunnel_get_stats(struct device *dev)
+{
+ return &(((struct ipsecpriv *)(dev->priv))->mystats);
+}
+
+/*
+ * Revectored calls.
+ * For each of these calls, a field exists in our private structure.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_hard_header(struct sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+ struct ipsecpriv *prv = dev->priv;
+ struct device *tmp;
+ int ret;
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(skb == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "no skb...\n");
+ return -ENODATA;
+ }
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "no device...\n");
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "skb->dev=%s dev=%s.\n",
+ skb->dev ? skb->dev->name : "NULL",
+ dev->name);
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "no private space associated with dev=%s\n",
+ dev->name ? dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "no physical device associated with dev=%s\n",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ /* check if we have to send a IPv6 packet. It might be a Router
+ Solicitation, where the building of the packet happens in
+ reverse order:
+ 1. ll hdr,
+ 2. IPv6 hdr,
+ 3. ICMPv6 hdr
+ -> skb->nh.raw is still uninitialized when this function is
+ called!! If this is no IPv6 packet, we can print debugging
+ messages, otherwise we skip all debugging messages and just
+ build the ll header */
+ if(type != ETH_P_IPV6) {
+ /* execute this only, if we don't have to build the
+ header for a IPv6 packet */
+ if(!prv->hard_header) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "physical device has been detached, packet dropped 0p%p->0p%p len=%d type=%d dev=%s->NULL ",
+ saddr,
+ daddr,
+ len,
+ type,
+ dev->name);
+#ifdef NET_21
+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+#else /* NET_21 */
+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->ip_hdr->saddr),
+ (__u32)ntohl(skb->ip_hdr->daddr) );
+#endif /* NET_21 */
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+#define da ((struct device *)(prv->dev))->dev_addr
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "Revectored 0p%p->0p%p len=%d type=%d dev=%s->%s dev_addr=%02x:%02x:%02x:%02x:%02x:%02x ",
+ saddr,
+ daddr,
+ len,
+ type,
+ dev->name,
+ prv->dev->name,
+ da[0], da[1], da[2], da[3], da[4], da[5]);
+#ifdef NET_21
+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+#else /* NET_21 */
+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->ip_hdr->saddr),
+ (__u32)ntohl(skb->ip_hdr->daddr) );
+#endif /* NET_21 */
+ } else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_hard_header: "
+ "is IPv6 packet, skip debugging messages, only revector and build linklocal header.\n");
+ }
+ tmp = skb->dev;
+ skb->dev = prv->dev;
+ ret = prv->hard_header(skb, prv->dev, type, (void *)daddr, (void *)saddr, len);
+ skb->dev = tmp;
+ return ret;
+}
+
+DEBUG_NO_STATIC int
+#ifdef NET_21
+ipsec_tunnel_rebuild_header(struct sk_buff *skb)
+#else /* NET_21 */
+ipsec_tunnel_rebuild_header(void *buff, struct device *dev,
+ unsigned long raddr, struct sk_buff *skb)
+#endif /* NET_21 */
+{
+ struct ipsecpriv *prv = skb->dev->priv;
+ struct device *tmp;
+ int ret;
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(skb->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_rebuild_header: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_rebuild_header: "
+ "no private space associated with dev=%s",
+ skb->dev->name ? skb->dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_rebuild_header: "
+ "no physical device associated with dev=%s",
+ skb->dev->name ? skb->dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ if(!prv->rebuild_header) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_rebuild_header: "
+ "physical device has been detached, packet dropped skb->dev=%s->NULL ",
+ skb->dev->name);
+#ifdef NET_21
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+#else /* NET_21 */
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->ip_hdr->saddr),
+ (__u32)ntohl(skb->ip_hdr->daddr) );
+#endif /* NET_21 */
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel: "
+ "Revectored rebuild_header dev=%s->%s ",
+ skb->dev->name, prv->dev->name);
+#ifdef NET_21
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->nh.iph->saddr),
+ (__u32)ntohl(skb->nh.iph->daddr) );
+#else /* NET_21 */
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "ip=%08x->%08x\n",
+ (__u32)ntohl(skb->ip_hdr->saddr),
+ (__u32)ntohl(skb->ip_hdr->daddr) );
+#endif /* NET_21 */
+ tmp = skb->dev;
+ skb->dev = prv->dev;
+
+#ifdef NET_21
+ ret = prv->rebuild_header(skb);
+#else /* NET_21 */
+ ret = prv->rebuild_header(buff, prv->dev, raddr, skb);
+#endif /* NET_21 */
+ skb->dev = tmp;
+ return ret;
+}
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_set_mac_address(struct device *dev, void *addr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODEV;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return -ENODEV;
+ }
+
+ if(!prv->set_mac_address) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_set_mac_address: "
+ "Revectored dev=%s->%s addr=0p%p\n",
+ dev->name, prv->dev->name, addr);
+ return prv->set_mac_address(prv->dev, addr);
+
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC void
+ipsec_tunnel_cache_bind(struct hh_cache **hhp, struct device *dev,
+ unsigned short htype, __u32 daddr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "no device...");
+ return;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return;
+ }
+
+ if(!prv->header_cache_bind) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ stats->tx_dropped++;
+ return;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_bind: "
+ "Revectored \n");
+ prv->header_cache_bind(hhp, prv->dev, htype, daddr);
+ return;
+}
+#endif /* !NET_21 */
+
+
+DEBUG_NO_STATIC void
+ipsec_tunnel_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
+{
+ struct ipsecpriv *prv = dev->priv;
+
+ struct net_device_stats *stats; /* This device's statistics */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_update: "
+ "no device...");
+ return;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_update: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return;
+ }
+
+ stats = (struct net_device_stats *) &(prv->mystats);
+
+ if(prv->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_update: "
+ "no physical device associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ stats->tx_dropped++;
+ return;
+ }
+
+ if(!prv->header_cache_update) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_cache_update: "
+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
+ dev->name);
+ return;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel: "
+ "Revectored cache_update\n");
+ prv->header_cache_update(hh, prv->dev, haddr);
+ return;
+}
+
+#ifdef NET_21
+DEBUG_NO_STATIC int
+ipsec_tunnel_neigh_setup(struct neighbour *n)
+{
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_neigh_setup:\n");
+
+ if (n->nud_state == NUD_NONE) {
+ n->ops = &arp_broken_ops;
+ n->output = n->ops->output;
+ }
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
+{
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_neigh_setup_dev: "
+ "setting up %s\n",
+ dev ? dev->name : "NULL");
+
+ if (p->tbl->family == AF_INET) {
+ p->neigh_setup = ipsec_tunnel_neigh_setup;
+ p->ucast_probes = 0;
+ p->mcast_probes = 0;
+ }
+ return 0;
+}
+#endif /* NET_21 */
+
+/*
+ * We call the attach routine to attach another device.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_attach(struct device *dev, struct device *physdev)
+{
+ int i;
+ struct ipsecpriv *prv = dev->priv;
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_attach: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_attach: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODATA;
+ }
+
+ prv->dev = physdev;
+ prv->hard_start_xmit = physdev->hard_start_xmit;
+ prv->get_stats = physdev->get_stats;
+
+ if (physdev->hard_header) {
+ prv->hard_header = physdev->hard_header;
+ dev->hard_header = ipsec_tunnel_hard_header;
+ } else
+ dev->hard_header = NULL;
+
+ if (physdev->rebuild_header) {
+ prv->rebuild_header = physdev->rebuild_header;
+ dev->rebuild_header = ipsec_tunnel_rebuild_header;
+ } else
+ dev->rebuild_header = NULL;
+
+ if (physdev->set_mac_address) {
+ prv->set_mac_address = physdev->set_mac_address;
+ dev->set_mac_address = ipsec_tunnel_set_mac_address;
+ } else
+ dev->set_mac_address = NULL;
+
+#ifndef NET_21
+ if (physdev->header_cache_bind) {
+ prv->header_cache_bind = physdev->header_cache_bind;
+ dev->header_cache_bind = ipsec_tunnel_cache_bind;
+ } else
+ dev->header_cache_bind = NULL;
+#endif /* !NET_21 */
+
+ if (physdev->header_cache_update) {
+ prv->header_cache_update = physdev->header_cache_update;
+ dev->header_cache_update = ipsec_tunnel_cache_update;
+ } else
+ dev->header_cache_update = NULL;
+
+ dev->hard_header_len = physdev->hard_header_len;
+
+#ifdef NET_21
+/* prv->neigh_setup = physdev->neigh_setup; */
+ dev->neigh_setup = ipsec_tunnel_neigh_setup_dev;
+#endif /* NET_21 */
+ dev->mtu = 16260; /* 0xfff0; */ /* dev->mtu; */
+ prv->mtu = physdev->mtu;
+
+#ifdef PHYSDEV_TYPE
+ dev->type = physdev->type; /* ARPHRD_TUNNEL; */
+#endif /* PHYSDEV_TYPE */
+
+ dev->addr_len = physdev->addr_len;
+ for (i=0; i<dev->addr_len; i++) {
+ dev->dev_addr[i] = physdev->dev_addr[i];
+ }
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_tunnel & DB_TN_INIT) {
+ printk(KERN_INFO "klips_debug:ipsec_tunnel_attach: "
+ "physical device %s being attached has HW address: %2x",
+ physdev->name, physdev->dev_addr[0]);
+ for (i=1; i < physdev->addr_len; i++) {
+ printk(":%02x", physdev->dev_addr[i]);
+ }
+ printk("\n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ return 0;
+}
+
+/*
+ * We call the detach routine to detach the ipsec tunnel from another device.
+ */
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_detach(struct device *dev)
+{
+ int i;
+ struct ipsecpriv *prv = dev->priv;
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_detach: "
+ "no device...");
+ return -ENODEV;
+ }
+
+ if(prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
+ "klips_debug:ipsec_tunnel_detach: "
+ "no private space associated with dev=%s",
+ dev->name ? dev->name : "NULL");
+ return -ENODATA;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_detach: "
+ "physical device %s being detached from virtual device %s\n",
+ prv->dev ? prv->dev->name : "NULL",
+ dev->name);
+
+ ipsec_dev_put(prv->dev);
+ prv->dev = NULL;
+ prv->hard_start_xmit = NULL;
+ prv->get_stats = NULL;
+
+ prv->hard_header = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->hard_header = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->rebuild_header = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->rebuild_header = NULL;
+#endif /* DETACH_AND_DOWN */
+
+ prv->set_mac_address = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->set_mac_address = NULL;
+#endif /* DETACH_AND_DOWN */
+
+#ifndef NET_21
+ prv->header_cache_bind = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->header_cache_bind = NULL;
+#endif /* DETACH_AND_DOWN */
+#endif /* !NET_21 */
+
+ prv->header_cache_update = NULL;
+#ifdef DETACH_AND_DOWN
+ dev->header_cache_update = NULL;
+#endif /* DETACH_AND_DOWN */
+
+#ifdef NET_21
+/* prv->neigh_setup = NULL; */
+#ifdef DETACH_AND_DOWN
+ dev->neigh_setup = NULL;
+#endif /* DETACH_AND_DOWN */
+#endif /* NET_21 */
+ dev->hard_header_len = 0;
+#ifdef DETACH_AND_DOWN
+ dev->mtu = 0;
+#endif /* DETACH_AND_DOWN */
+ prv->mtu = 0;
+ for (i=0; i<MAX_ADDR_LEN; i++) {
+ dev->dev_addr[i] = 0;
+ }
+ dev->addr_len = 0;
+#ifdef PHYSDEV_TYPE
+ dev->type = ARPHRD_VOID; /* ARPHRD_TUNNEL; */
+#endif /* PHYSDEV_TYPE */
+
+ return 0;
+}
+
+/*
+ * We call the clear routine to detach all ipsec tunnels from other devices.
+ */
+DEBUG_NO_STATIC int
+ipsec_tunnel_clear(void)
+{
+ int i;
+ struct device *ipsecdev = NULL, *prvdev;
+ struct ipsecpriv *prv;
+ char name[9];
+ int ret;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_clear: .\n");
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ ipsecdev = ipsecdevices[i];
+ if(ipsecdev != NULL) {
+ if((prv = (struct ipsecpriv *)(ipsecdev->priv))) {
+ prvdev = (struct device *)(prv->dev);
+ if(prvdev) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_clear: "
+ "physical device for device %s is %s\n",
+ name, prvdev->name);
+ if((ret = ipsec_tunnel_detach(ipsecdev))) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_clear: "
+ "error %d detatching device %s from device %s.\n",
+ ret, name, prvdev->name);
+ return ret;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+ipsec_tunnel_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ipsectunnelconf *cf = (struct ipsectunnelconf *)&ifr->ifr_data;
+ struct ipsecpriv *prv = dev->priv;
+ struct device *them; /* physical device */
+#ifdef CONFIG_IP_ALIAS
+ char *colon;
+ char realphysname[IFNAMSIZ];
+#endif /* CONFIG_IP_ALIAS */
+
+ if(dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "device not supplied.\n");
+ return -ENODEV;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "tncfg service call #%d for dev=%s\n",
+ cmd,
+ dev->name ? dev->name : "NULL");
+ switch (cmd) {
+ /* attach a virtual ipsec? device to a physical device */
+ case IPSEC_SET_DEV:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "calling ipsec_tunnel_attatch...\n");
+#ifdef CONFIG_IP_ALIAS
+ /* If this is an IP alias interface, get its real physical name */
+ strncpy(realphysname, cf->cf_name, IFNAMSIZ);
+ realphysname[IFNAMSIZ-1] = 0;
+ colon = strchr(realphysname, ':');
+ if (colon) *colon = 0;
+ them = ipsec_dev_get(realphysname);
+#else /* CONFIG_IP_ALIAS */
+ them = ipsec_dev_get(cf->cf_name);
+#endif /* CONFIG_IP_ALIAS */
+
+ if (them == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "physical device %s requested is null\n",
+ cf->cf_name);
+ return -ENXIO;
+ }
+
+#if 0
+ if (them->flags & IFF_UP) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "physical device %s requested is not up.\n",
+ cf->cf_name);
+ ipsec_dev_put(them);
+ return -ENXIO;
+ }
+#endif
+
+ if (prv && prv->dev) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "virtual device is already connected to %s.\n",
+ prv->dev->name ? prv->dev->name : "NULL");
+ ipsec_dev_put(them);
+ return -EBUSY;
+ }
+ return ipsec_tunnel_attach(dev, them);
+
+ case IPSEC_DEL_DEV:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "calling ipsec_tunnel_detatch.\n");
+ if (! prv->dev) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "physical device not connected.\n");
+ return -ENODEV;
+ }
+ return ipsec_tunnel_detach(dev);
+
+ case IPSEC_CLR_DEV:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "calling ipsec_tunnel_clear.\n");
+ return ipsec_tunnel_clear();
+
+ default:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_ioctl: "
+ "unknown command %d.\n",
+ cmd);
+ return -EOPNOTSUPP;
+ }
+}
+
+int
+ipsec_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
+{
+ struct device *dev = ptr;
+ struct device *ipsec_dev;
+ struct ipsecpriv *priv;
+ int i;
+
+ if (dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "dev=NULL for event type %ld.\n",
+ event);
+ return(NOTIFY_DONE);
+ }
+
+ /* check for loopback devices */
+ if (dev && (dev->flags & IFF_LOOPBACK)) {
+ return(NOTIFY_DONE);
+ }
+
+ switch (event) {
+ case NETDEV_DOWN:
+ /* look very carefully at the scope of these compiler
+ directives before changing anything... -- RGB */
+#ifdef NET_21
+ case NETDEV_UNREGISTER:
+ switch (event) {
+ case NETDEV_DOWN:
+#endif /* NET_21 */
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_DOWN dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ if(strncmp(dev->name, "ipsec", strlen("ipsec")) == 0) {
+ printk(KERN_CRIT "IPSEC EVENT: KLIPS device %s shut down.\n",
+ dev->name);
+ }
+#ifdef NET_21
+ break;
+ case NETDEV_UNREGISTER:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_UNREGISTER dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ break;
+ }
+#endif /* NET_21 */
+
+ /* find the attached physical device and detach it. */
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ ipsec_dev = ipsecdevices[i];
+
+ if(ipsec_dev) {
+ priv = (struct ipsecpriv *)(ipsec_dev->priv);
+ if(priv) {
+ ;
+ if(((struct device *)(priv->dev)) == dev) {
+ /* dev_close(ipsec_dev); */
+ /* return */ ipsec_tunnel_detach(ipsec_dev);
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "device '%s' has been detached.\n",
+ ipsec_dev->name);
+ break;
+ }
+ } else {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "device '%s' has no private data space!\n",
+ ipsec_dev->name);
+ }
+ }
+ }
+ break;
+ case NETDEV_UP:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_UP dev=%s\n",
+ dev->name);
+ break;
+#ifdef NET_21
+ case NETDEV_REBOOT:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_REBOOT dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGE:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_CHANGE dev=%s flags=%x\n",
+ dev->name,
+ dev->flags);
+ break;
+ case NETDEV_REGISTER:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_REGISTER dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGEMTU:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_CHANGEMTU dev=%s to mtu=%d\n",
+ dev->name,
+ dev->mtu);
+ break;
+ case NETDEV_CHANGEADDR:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_CHANGEADDR dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_GOING_DOWN:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_GOING_DOWN dev=%s\n",
+ dev->name);
+ break;
+ case NETDEV_CHANGENAME:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "NETDEV_CHANGENAME dev=%s\n",
+ dev->name);
+ break;
+#endif /* NET_21 */
+ default:
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_device_event: "
+ "event type %ld unrecognised for dev=%s\n",
+ event,
+ dev->name);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+/*
+ * Called when an ipsec tunnel device is initialized.
+ * The ipsec tunnel device structure is passed to us.
+ */
+
+int
+ipsec_tunnel_init(struct device *dev)
+{
+ int i;
+
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_init: "
+ "allocating %lu bytes initialising device: %s\n",
+ (unsigned long) sizeof(struct ipsecpriv),
+ dev->name ? dev->name : "NULL");
+
+ /* Add our tunnel functions to the device */
+ dev->open = ipsec_tunnel_open;
+ dev->stop = ipsec_tunnel_close;
+ dev->hard_start_xmit = ipsec_tunnel_start_xmit;
+ dev->get_stats = ipsec_tunnel_get_stats;
+
+ dev->priv = kmalloc(sizeof(struct ipsecpriv), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset((caddr_t)(dev->priv), 0, sizeof(struct ipsecpriv));
+
+ for(i = 0; i < sizeof(zeroes); i++) {
+ ((__u8*)(zeroes))[i] = 0;
+ }
+
+#ifndef NET_21
+ /* Initialize the tunnel device structure */
+ for (i = 0; i < DEV_NUMBUFFS; i++)
+ skb_queue_head_init(&dev->buffs[i]);
+#endif /* !NET_21 */
+
+ dev->set_multicast_list = NULL;
+ dev->do_ioctl = ipsec_tunnel_ioctl;
+ dev->hard_header = NULL;
+ dev->rebuild_header = NULL;
+ dev->set_mac_address = NULL;
+#ifndef NET_21
+ dev->header_cache_bind = NULL;
+#endif /* !NET_21 */
+ dev->header_cache_update= NULL;
+
+#ifdef NET_21
+/* prv->neigh_setup = NULL; */
+ dev->neigh_setup = ipsec_tunnel_neigh_setup_dev;
+#endif /* NET_21 */
+ dev->hard_header_len = 0;
+ dev->mtu = 0;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_VOID; /* ARPHRD_TUNNEL; */ /* ARPHRD_ETHER; */
+ dev->tx_queue_len = 10; /* Small queue */
+ memset((caddr_t)(dev->broadcast),0xFF, ETH_ALEN); /* what if this is not attached to ethernet? */
+
+ /* New-style flags. */
+ dev->flags = IFF_NOARP /* 0 */ /* Petr Novak */;
+#ifdef NET_21
+ dev_init_buffers(dev);
+#else /* NET_21 */
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = 4;
+#endif /* NET_21 */
+
+ /* We're done. Have I forgotten anything? */
+ return 0;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Module specific interface (but it links with the rest of IPSEC) */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int
+ipsec_tunnel_probe(struct device *dev)
+{
+ ipsec_tunnel_init(dev);
+ return 0;
+}
+
+struct device *ipsecdevices[IPSEC_NUM_IF];
+
+int
+ipsec_tunnel_init_devices(void)
+{
+ int i;
+ char name[IFNAMSIZ];
+ struct device *dev_ipsec;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "creating and registering IPSEC_NUM_IF=%u devices, allocating %lu per device, IFNAMSIZ=%u.\n",
+ IPSEC_NUM_IF,
+ (unsigned long) (sizeof(struct device) + IFNAMSIZ),
+ IFNAMSIZ);
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ sprintf(name, IPSEC_DEV_FORMAT, i);
+ dev_ipsec = (struct device*)kmalloc(sizeof(struct device), GFP_KERNEL);
+ if (dev_ipsec == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "failed to allocate memory for device %s, quitting device init.\n",
+ name);
+ return -ENOMEM;
+ }
+ memset((caddr_t)dev_ipsec, 0, sizeof(struct device));
+#ifdef NETDEV_23
+ strncpy(dev_ipsec->name, name, sizeof(dev_ipsec->name));
+#else /* NETDEV_23 */
+ dev_ipsec->name = (char*)kmalloc(IFNAMSIZ, GFP_KERNEL);
+ if (dev_ipsec->name == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "failed to allocate memory for device %s name, quitting device init.\n",
+ name);
+ return -ENOMEM;
+ }
+ memset((caddr_t)dev_ipsec->name, 0, IFNAMSIZ);
+ strncpy(dev_ipsec->name, name, IFNAMSIZ);
+#endif /* NETDEV_23 */
+ dev_ipsec->next = NULL;
+ dev_ipsec->init = &ipsec_tunnel_probe;
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "registering device %s\n",
+ dev_ipsec->name);
+
+ /* reference and hold the device reference */
+ dev_hold(dev_ipsec);
+ ipsecdevices[i]=dev_ipsec;
+
+ if (register_netdev(dev_ipsec) != 0) {
+ KLIPS_PRINT(1 || debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "registering device %s failed, quitting device init.\n",
+ dev_ipsec->name);
+ return -EIO;
+ } else {
+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
+ "klips_debug:ipsec_tunnel_init_devices: "
+ "registering device %s succeeded, continuing...\n",
+ dev_ipsec->name);
+ }
+ }
+ return 0;
+}
+
+/* void */
+int
+ipsec_tunnel_cleanup_devices(void)
+{
+ int error = 0;
+ int i;
+ char name[32];
+ struct device *dev_ipsec;
+
+ for(i = 0; i < IPSEC_NUM_IF; i++) {
+ dev_ipsec = ipsecdevices[i];
+ if(dev_ipsec == NULL) {
+ continue;
+ }
+
+ /* release reference */
+ ipsecdevices[i]=NULL;
+ ipsec_dev_put(dev_ipsec);
+
+ KLIPS_PRINT(debug_tunnel, "Unregistering %s (refcnt=%d)\n",
+ name,
+ atomic_read(&dev_ipsec->refcnt));
+ unregister_netdev(dev_ipsec);
+ KLIPS_PRINT(debug_tunnel, "Unregisted %s\n", name);
+#ifndef NETDEV_23
+ kfree(dev_ipsec->name);
+ dev_ipsec->name=NULL;
+#endif /* !NETDEV_23 */
+ kfree(dev_ipsec->priv);
+ dev_ipsec->priv=NULL;
+ }
+ return error;
+}
diff --git a/linux/net/ipsec/ipsec_xform.c b/linux/net/ipsec/ipsec_xform.c
new file mode 100644
index 000000000..677f83aaf
--- /dev/null
+++ b/linux/net/ipsec/ipsec_xform.c
@@ -0,0 +1,73 @@
+/*
+ * Common routines for IPSEC transformations.
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 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: ipsec_xform.c,v 1.2 2004/06/13 19:57:50 as Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#include <linux/random.h> /* get_random_bytes() */
+#include <freeswan.h>
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_xform = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#ifdef SPINLOCK
+spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
+#else /* SPINLOCK */
+spinlock_t tdb_lock;
+#endif /* SPINLOCK */
diff --git a/linux/net/ipsec/ipsec_xmit.c b/linux/net/ipsec/ipsec_xmit.c
new file mode 100644
index 000000000..bb390bcf9
--- /dev/null
+++ b/linux/net/ipsec/ipsec_xmit.c
@@ -0,0 +1,1782 @@
+/*
+ * IPSEC Transmit code.
+ * Copyright (C) 1996, 1997 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 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 ipsec_xmit_c_version[] = "RCSID $Id: ipsec_xmit.c,v 1.3 2004/06/13 19:37:23 as Exp $";
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/tcp.h> /* struct tcphdr */
+#include <linux/udp.h> /* struct udphdr */
+#include <linux/skbuff.h>
+#include <freeswan.h>
+#ifdef NET_21
+# define MSS_HACK_ /* experimental */
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# include <net/dst.h>
+# define proto_priv cb
+#endif /* NET_21 */
+#include <asm/checksum.h>
+#include <net/icmp.h> /* icmp_send() */
+#include <net/ip.h>
+#ifdef NETDEV_23
+# include <linux/netfilter_ipv4.h>
+#endif /* NETDEV_23 */
+
+#include <linux/if_arp.h>
+#ifdef MSS_HACK
+# include <net/tcp.h> /* TCP options */
+#endif /* MSS_HACK */
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_life.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_eroute.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xmit.h"
+#include "freeswan/ipsec_sa.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_ipe4.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+
+#ifdef CONFIG_IPSEC_IPCOMP
+#include "freeswan/ipcomp.h"
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+
+/*
+ * Stupid kernel API differences in APIs. Not only do some
+ * kernels not have ip_select_ident, but some have differing APIs,
+ * and SuSE has one with one parameter, but no way of checking to
+ * see what is really what.
+ */
+
+#ifdef SUSE_LINUX_2_4_19_IS_STUPID
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph)
+#else
+
+/* simplest case, nothing */
+#if !defined(IP_SELECT_IDENT)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) do { iph->id = htons(ip_id_count++); } while(0)
+#endif
+
+/* kernels > 2.3.37-ish */
+#if defined(IP_SELECT_IDENT) && !defined(IP_SELECT_IDENT_NEW)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst)
+#endif
+
+/* kernels > 2.4.2 */
+#if defined(IP_SELECT_IDENT) && defined(IP_SELECT_IDENT_NEW)
+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst, NULL)
+#endif
+
+#endif /* SUSE_LINUX_2_4_19_IS_STUPID */
+
+
+static __u32 zeroes[64];
+
+#ifdef CONFIG_IPSEC_DEBUG
+int sysctl_ipsec_debug_verbose = 0;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+int ipsec_xmit_trap_count = 0;
+int ipsec_xmit_trap_sendcount = 0;
+
+int sysctl_ipsec_icmp = 0;
+int sysctl_ipsec_tos = 0;
+
+/*
+ * If the IP packet (iph) is a carrying TCP/UDP, then set the encaps
+ * source and destination ports to those from the TCP/UDP header.
+ */
+void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er)
+{
+ struct udphdr *udp;
+
+ switch (iph->protocol) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ /*
+ * The ports are at the same offsets in a TCP and UDP
+ * header so hack it ...
+ */
+ udp = (struct udphdr*)(((char*)iph)+(iph->ihl<<2));
+ er->sen_sport = udp->source;
+ er->sen_dport = udp->dest;
+ break;
+ default:
+ er->sen_sport = 0;
+ er->sen_dport = 0;
+ break;
+ }
+}
+
+/*
+ * A TRAP eroute is installed and we want to replace it with a HOLD
+ * eroute.
+ */
+static int create_hold_eroute(struct sk_buff * skb, struct iphdr * iph,
+ uint32_t eroute_pid)
+{
+ struct eroute hold_eroute;
+ struct sa_id hold_said;
+ struct sk_buff *first, *last;
+ int error;
+
+ first = last = NULL;
+ memset((caddr_t)&hold_eroute, 0, sizeof(hold_eroute));
+ memset((caddr_t)&hold_said, 0, sizeof(hold_said));
+
+ hold_said.proto = IPPROTO_INT;
+ hold_said.spi = htonl(SPI_HOLD);
+ hold_said.dst.s_addr = INADDR_ANY;
+
+ hold_eroute.er_eaddr.sen_len = sizeof(struct sockaddr_encap);
+ hold_eroute.er_emask.sen_len = sizeof(struct sockaddr_encap);
+ hold_eroute.er_eaddr.sen_family = AF_ENCAP;
+ hold_eroute.er_emask.sen_family = AF_ENCAP;
+ hold_eroute.er_eaddr.sen_type = SENT_IP4;
+ hold_eroute.er_emask.sen_type = 255;
+
+ hold_eroute.er_eaddr.sen_ip_src.s_addr = iph->saddr;
+ hold_eroute.er_eaddr.sen_ip_dst.s_addr = iph->daddr;
+ hold_eroute.er_emask.sen_ip_src.s_addr = INADDR_BROADCAST;
+ hold_eroute.er_emask.sen_ip_dst.s_addr = INADDR_BROADCAST;
+ hold_eroute.er_emask.sen_sport = ~0;
+ hold_eroute.er_emask.sen_dport = ~0;
+ hold_eroute.er_pid = eroute_pid;
+ hold_eroute.er_count = 0;
+ hold_eroute.er_lasttime = jiffies/HZ;
+
+ hold_eroute.er_eaddr.sen_proto = iph->protocol;
+ ipsec_extract_ports(iph, &hold_eroute.er_eaddr);
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_pfkey) {
+ char buf1[64], buf2[64];
+ subnettoa(hold_eroute.er_eaddr.sen_ip_src,
+ hold_eroute.er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(hold_eroute.er_eaddr.sen_ip_dst,
+ hold_eroute.er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "calling breakeroute and makeroute for %s:%d->%s:%d %d HOLD eroute.\n",
+ buf1, ntohs(hold_eroute.er_eaddr.sen_sport),
+ buf2, ntohs(hold_eroute.er_eaddr.sen_dport),
+ hold_eroute.er_eaddr.sen_proto);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ if (ipsec_breakroute(&(hold_eroute.er_eaddr), &(hold_eroute.er_emask),
+ &first, &last)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "HOLD breakeroute found nothing.\n");
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "HOLD breakroute deleted %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u %u\n",
+ NIPQUAD(hold_eroute.er_eaddr.sen_ip_src),
+ ntohs(hold_eroute.er_eaddr.sen_sport),
+ NIPQUAD(hold_eroute.er_eaddr.sen_ip_dst),
+ ntohs(hold_eroute.er_eaddr.sen_dport),
+ hold_eroute.er_eaddr.sen_proto);
+ }
+ if (first != NULL)
+ kfree_skb(first);
+ if (last != NULL)
+ kfree_skb(last);
+
+ error = ipsec_makeroute(&(hold_eroute.er_eaddr),
+ &(hold_eroute.er_emask),
+ hold_said, eroute_pid, skb, NULL, NULL);
+ if (error) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "HOLD makeroute returned %d, failed.\n", error);
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "HOLD makeroute call successful.\n");
+ }
+ return (error == 0);
+}
+
+#ifdef CONFIG_IPSEC_DEBUG_
+DEBUG_NO_STATIC void
+dmp(char *s, caddr_t bb, int len)
+{
+ int i;
+ unsigned char *b = bb;
+
+ if (debug_tunnel) {
+ printk(KERN_INFO "klips_debug:ipsec_tunnel_:dmp: "
+ "at %s, len=%d:",
+ s,
+ len);
+ for (i=0; i < len; i++) {
+ if(!(i%16)){
+ printk("\nklips_debug: ");
+ }
+ printk(" %02x", *b++);
+ }
+ printk("\n");
+ }
+}
+#else /* CONFIG_IPSEC_DEBUG */
+#define dmp(_x, _y, _z)
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#ifndef SKB_COPY_EXPAND
+/*
+ * This is mostly skbuff.c:skb_copy().
+ */
+struct sk_buff *
+skb_copy_expand(struct sk_buff *skb, int headroom, int tailroom, int priority)
+{
+ struct sk_buff *n;
+ unsigned long offset;
+
+ /*
+ * Do sanity checking
+ */
+ if((headroom < 0) || (tailroom < 0) || ((headroom+tailroom) < 0)) {
+ printk(KERN_WARNING
+ "klips_error:skb_copy_expand: "
+ "Illegal negative head,tailroom %d,%d\n",
+ headroom,
+ tailroom);
+ return NULL;
+ }
+ /*
+ * Allocate the copy buffer
+ */
+
+#ifndef NET_21
+ IS_SKB(skb);
+#endif /* !NET_21 */
+
+
+ n=alloc_skb(skb->end - skb->head + headroom + tailroom, priority);
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:skb_copy_expand: "
+ "allocating %d bytes, head=0p%p data=0p%p tail=0p%p end=0p%p end-head=%d tail-data=%d\n",
+ skb->end - skb->head + headroom + tailroom,
+ skb->head,
+ skb->data,
+ skb->tail,
+ skb->end,
+ skb->end - skb->head,
+ skb->tail - skb->data);
+
+ if(n==NULL)
+ return NULL;
+
+ /*
+ * Shift between the two data areas in bytes
+ */
+
+ /* Set the data pointer */
+ skb_reserve(n,skb->data-skb->head+headroom);
+ /* Set the tail pointer and length */
+ if(skb_tailroom(n) < skb->len) {
+ printk(KERN_WARNING "klips_error:skb_copy_expand: "
+ "tried to skb_put %ld, %d available. This should never happen, please report.\n",
+ (unsigned long int)skb->len,
+ skb_tailroom(n));
+ ipsec_kfree_skb(n);
+ return NULL;
+ }
+ skb_put(n,skb->len);
+
+ offset=n->head + headroom - skb->head;
+
+ /* Copy the bytes */
+ memcpy(n->head + headroom, skb->head,skb->end-skb->head);
+#ifdef NET_21
+ n->csum=skb->csum;
+ n->priority=skb->priority;
+ n->dst=dst_clone(skb->dst);
+ if(skb->nh.raw)
+ n->nh.raw=skb->nh.raw+offset;
+#ifndef NETDEV_23
+ n->is_clone=0;
+#endif /* NETDEV_23 */
+ atomic_set(&n->users, 1);
+ n->destructor = NULL;
+ n->security=skb->security;
+#else /* NET_21 */
+ n->link3=NULL;
+ n->when=skb->when;
+ if(skb->ip_hdr)
+ n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
+ n->saddr=skb->saddr;
+ n->daddr=skb->daddr;
+ n->raddr=skb->raddr;
+ n->seq=skb->seq;
+ n->end_seq=skb->end_seq;
+ n->ack_seq=skb->ack_seq;
+ n->acked=skb->acked;
+ n->free=1;
+ n->arp=skb->arp;
+ n->tries=0;
+ n->lock=0;
+ n->users=0;
+#endif /* NET_21 */
+ n->protocol=skb->protocol;
+ n->list=NULL;
+ n->sk=NULL;
+ n->dev=skb->dev;
+ if(skb->h.raw)
+ n->h.raw=skb->h.raw+offset;
+ if(skb->mac.raw)
+ n->mac.raw=skb->mac.raw+offset;
+ memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
+#ifndef NETDEV_23
+ n->used=skb->used;
+#endif /* !NETDEV_23 */
+ n->pkt_type=skb->pkt_type;
+ n->stamp=skb->stamp;
+
+#ifndef NET_21
+ IS_SKB(n);
+#endif /* !NET_21 */
+ return n;
+}
+#endif /* !SKB_COPY_EXPAND */
+
+#ifdef CONFIG_IPSEC_DEBUG
+void
+ipsec_print_ip(struct iphdr *ip)
+{
+ char buf[ADDRTOA_BUF];
+
+ printk(KERN_INFO "klips_debug: IP:");
+ printk(" ihl:%d", ip->ihl << 2);
+ printk(" ver:%d", ip->version);
+ printk(" tos:%d", ip->tos);
+ printk(" tlen:%d", ntohs(ip->tot_len));
+ printk(" id:%d", ntohs(ip->id));
+ printk(" %s%s%sfrag_off:%d",
+ ip->frag_off & __constant_htons(IP_CE) ? "CE " : "",
+ ip->frag_off & __constant_htons(IP_DF) ? "DF " : "",
+ ip->frag_off & __constant_htons(IP_MF) ? "MF " : "",
+ (ntohs(ip->frag_off) & IP_OFFSET) << 3);
+ printk(" ttl:%d", ip->ttl);
+ printk(" proto:%d", ip->protocol);
+ if(ip->protocol == IPPROTO_UDP)
+ printk(" (UDP)");
+ if(ip->protocol == IPPROTO_TCP)
+ printk(" (TCP)");
+ if(ip->protocol == IPPROTO_ICMP)
+ printk(" (ICMP)");
+ printk(" chk:%d", ntohs(ip->check));
+ addrtoa(*((struct in_addr*)(&ip->saddr)), 0, buf, sizeof(buf));
+ printk(" saddr:%s", buf);
+ if(ip->protocol == IPPROTO_UDP)
+ printk(":%d",
+ ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
+ if(ip->protocol == IPPROTO_TCP)
+ printk(":%d",
+ ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
+ addrtoa(*((struct in_addr*)(&ip->daddr)), 0, buf, sizeof(buf));
+ printk(" daddr:%s", buf);
+ if(ip->protocol == IPPROTO_UDP)
+ printk(":%d",
+ ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
+ if(ip->protocol == IPPROTO_TCP)
+ printk(":%d",
+ ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
+ if(ip->protocol == IPPROTO_ICMP)
+ printk(" type:code=%d:%d",
+ ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->type,
+ ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->code);
+ printk("\n");
+
+ if(sysctl_ipsec_debug_verbose) {
+ __u8 *c;
+ int i;
+
+ c = ((__u8*)ip) + ip->ihl*4;
+ for(i = 0; i < ntohs(ip->tot_len) - ip->ihl*4; i++ /*, c++*/) {
+ if(!(i % 16)) {
+ printk(KERN_INFO
+ "klips_debug: @%03x:",
+ i);
+ }
+ printk(" %02x", /***/c[i]);
+ if(!((i + 1) % 16)) {
+ printk("\n");
+ }
+ }
+ if(i % 16) {
+ printk("\n");
+ }
+ }
+}
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#ifdef MSS_HACK
+/*
+ * Issues:
+ * 1) Fragments arriving in the tunnel should probably be rejected.
+ * 2) How does this affect syncookies, mss_cache, dst cache ?
+ * 3) Path MTU discovery handling needs to be reviewed. For example,
+ * if we receive an ICMP 'packet too big' message from an intermediate
+ * router specifying it's next hop MTU, our stack may process this and
+ * adjust the MSS without taking our AH/ESP overheads into account.
+ */
+
+
+/*
+ * Recaclulate checksum using differences between changed datum,
+ * borrowed from netfilter.
+ */
+DEBUG_NO_STATIC u_int16_t
+ipsec_fast_csum(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
+{
+ u_int32_t diffs[] = { oldvalinv, newval };
+ return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
+ oldcheck^0xFFFF));
+}
+
+/*
+ * Determine effective MSS.
+ *
+ * Note that we assume that there is always an MSS option for our own
+ * SYN segments, which is mentioned in tcp_syn_build_options(), kernel 2.2.x.
+ * This could change, and we should probably parse TCP options instead.
+ *
+ */
+DEBUG_NO_STATIC u_int8_t
+ipsec_adjust_mss(struct sk_buff *skb, struct tcphdr *tcph, u_int16_t mtu)
+{
+ u_int16_t oldmss, newmss;
+ u_int32_t *mssp;
+ struct sock *sk = skb->sk;
+
+ newmss = tcp_sync_mss(sk, mtu);
+ printk(KERN_INFO "klips: setting mss to %u\n", newmss);
+ mssp = (u_int32_t *)tcph + sizeof(struct tcphdr) / sizeof(u_int32_t);
+ oldmss = ntohl(*mssp) & 0x0000FFFF;
+ *mssp = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | newmss);
+ tcph->check = ipsec_fast_csum(htons(~oldmss),
+ htons(newmss), tcph->check);
+ return 1;
+}
+#endif /* MSS_HACK */
+
+/*
+ * Sanity checks
+ */
+enum ipsec_xmit_value
+ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs)
+{
+
+ if (ixs->dev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_dev: "
+ "No device associated with skb!\n" );
+ return IPSEC_XMIT_NODEV;
+ }
+
+ ixs->prv = ixs->dev->priv;
+ if (ixs->prv == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_dev: "
+ "Device has no private structure!\n" );
+ return IPSEC_XMIT_NOPRIVDEV;
+ }
+
+ ixs->physdev = ixs->prv->dev;
+ if (ixs->physdev == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_dev: "
+ "Device is not attached to physical device!\n" );
+ return IPSEC_XMIT_NOPHYSDEV;
+ }
+
+ ixs->physmtu = ixs->physdev->mtu;
+
+ ixs->stats = (struct net_device_stats *) &(ixs->prv->mystats);
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs)
+{
+ /*
+ * Return if there is nothing to do. (Does this ever happen?) XXX
+ */
+ if (ixs->skb == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_skb: "
+ "Nothing to do!\n" );
+ return IPSEC_XMIT_NOSKB;
+ }
+#ifdef NET_21
+ /* if skb was cloned (most likely due to a packet sniffer such as
+ tcpdump being momentarily attached to the interface), make
+ a copy of our own to modify */
+ if(skb_cloned(ixs->skb)) {
+ if
+#ifdef SKB_COW_NEW
+ (skb_cow(ixs->skb, skb_headroom(ixs->skb)) != 0)
+#else /* SKB_COW_NEW */
+ ((ixs->skb = skb_cow(ixs->skb, skb_headroom(ixs->skb))) == NULL)
+#endif /* SKB_COW_NEW */
+ {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_error:ipsec_xmit_sanity_check_skb: "
+ "skb_cow failed to allocate buffer, dropping.\n" );
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_ERRSKBALLOC;
+ }
+ }
+#endif /* NET_21 */
+
+#ifdef NET_21
+ ixs->iph = ixs->skb->nh.iph;
+#else /* NET_21 */
+ ixs->iph = ixs->skb->ip_hdr;
+#endif /* NET_21 */
+
+ /* sanity check for IP version as we can't handle IPv6 right now */
+ if (ixs->iph->version != 4) {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_xmit_sanity_check_skb: "
+ "found IP Version %d but cannot process other IP versions than v4.\n",
+ ixs->iph->version); /* XXX */
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_NOIPV6;
+ }
+
+#if IPSEC_DISALLOW_IPOPTIONS
+ if ((ixs->iph->ihl << 2) != sizeof (struct iphdr)) {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_xmit_sanity_check_skb: "
+ "cannot process IP header options yet. May be mal-formed packet.\n"); /* XXX */
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_NOIPOPTIONS;
+ }
+#endif /* IPSEC_DISALLOW_IPOPTIONS */
+
+#ifndef NET_21
+ if (ixs->iph->ttl <= 0) {
+ /* Tell the sender its packet died... */
+ ICMP_SEND(ixs->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, ixs->physdev);
+
+ KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_xmit_sanity_check_skb: "
+ "TTL=0, too many hops!\n");
+ ixs->stats->tx_dropped++;
+ return IPSEC_XMIT_TTLEXPIRED;
+ }
+#endif /* !NET_21 */
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_xmit_encap_once(struct ipsec_xmit_state *ixs)
+{
+#ifdef CONFIG_IPSEC_ESP
+ struct esphdr *espp;
+#ifdef CONFIG_IPSEC_ENC_3DES
+ __u32 iv[ESP_IV_MAXSZ_INT];
+#endif /* !CONFIG_IPSEC_ENC_3DES */
+ unsigned char *idat, *pad;
+ int authlen = 0, padlen = 0, i;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_AH
+ struct iphdr ipo;
+ struct ahhdr *ahp;
+#endif /* CONFIG_IPSEC_AH */
+#if defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1)
+ union {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ MD5_CTX md5;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ SHA1_CTX sha1;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ } tctx;
+ __u8 hash[AH_AMAX];
+#endif /* defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1) */
+ int headroom = 0, tailroom = 0, ilen = 0, len = 0;
+ unsigned char *dat;
+ int blocksize = 8; /* XXX: should be inside ixs --jjo */
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_enc *ixt_e = NULL;
+ struct ipsec_alg_auth *ixt_a = NULL;
+#endif /* CONFIG_IPSEC_ALG */
+
+ ixs->iphlen = ixs->iph->ihl << 2;
+ ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
+ ixs->sa_len = satoa(ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOA_BUF);
+ KLIPS_PRINT(debug_tunnel & DB_TN_OXFS,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "calling output for <%s%s%s>, SA:%s\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+
+ switch(ixs->ipsp->ips_said.proto) {
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ headroom += sizeof(struct ahhdr);
+ break;
+#endif /* CONFIG_IPSEC_AH */
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP:
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_e=ixs->ipsp->ips_alg_enc)) {
+ blocksize = ixt_e->ixt_blocksize;
+ headroom += ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ headroom += sizeof(struct esphdr);
+ break;
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_a=ixs->ipsp->ips_alg_auth)) {
+ tailroom += AHHMAC_HASHLEN;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ authlen = AHHMAC_HASHLEN;
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ authlen = AHHMAC_HASHLEN;
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ break;
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+#ifdef CONFIG_IPSEC_ALG
+ tailroom += blocksize != 1 ?
+ ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
+ ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
+#else
+ tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
+#endif /* CONFIG_IPSEC_ALG */
+ tailroom += authlen;
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_IPIP
+ case IPPROTO_IPIP:
+ headroom += sizeof(struct iphdr);
+ ixs->iphlen = sizeof(struct iphdr);
+ break;
+#endif /* !CONFIG_IPSEC_IPIP */
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_BADPROTO;
+ }
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "pushing %d bytes, putting %d, proto %d.\n",
+ headroom, tailroom, ixs->ipsp->ips_said.proto);
+ if(skb_headroom(ixs->skb) < headroom) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_encap_once: "
+ "tried to skb_push headroom=%d, %d available. This should never happen, please report.\n",
+ headroom, skb_headroom(ixs->skb));
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_PUSHPULLERR;
+ }
+ dat = skb_push(ixs->skb, headroom);
+ ilen = ixs->skb->len - tailroom;
+ if(skb_tailroom(ixs->skb) < tailroom) {
+ printk(KERN_WARNING
+ "klips_error:ipsec_xmit_encap_once: "
+ "tried to skb_put %d, %d available. This should never happen, please report.\n",
+ tailroom, skb_tailroom(ixs->skb));
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_PUSHPULLERR;
+ }
+ skb_put(ixs->skb, tailroom);
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "head,tailroom: %d,%d before xform.\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
+ len = ixs->skb->len;
+ if(len > 0xfff0) {
+ printk(KERN_WARNING "klips_error:ipsec_xmit_encap_once: "
+ "tot_len (%d) > 65520. This should never happen, please report.\n",
+ len);
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_BADLEN;
+ }
+ memmove((void *)dat, (void *)(dat + headroom), ixs->iphlen);
+ ixs->iph = (struct iphdr *)dat;
+ ixs->iph->tot_len = htons(ixs->skb->len);
+
+ switch(ixs->ipsp->ips_said.proto) {
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP:
+ espp = (struct esphdr *)(dat + ixs->iphlen);
+ espp->esp_spi = ixs->ipsp->ips_said.spi;
+ espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
+
+#ifdef CONFIG_IPSEC_ALG
+ if (!ixt_e)
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#if defined(CONFIG_IPSEC_ENC_3DES)
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ iv[0] = *((__u32*)&(espp->esp_iv) ) =
+ ((__u32*)(ixs->ipsp->ips_iv))[0];
+ iv[1] = *((__u32*)&(espp->esp_iv) + 1) =
+ ((__u32*)(ixs->ipsp->ips_iv))[1];
+ break;
+#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+
+ idat = dat + ixs->iphlen + headroom;
+ ilen = len - (ixs->iphlen + headroom + authlen);
+
+ /* Self-describing padding */
+ pad = &dat[len - tailroom];
+ padlen = tailroom - 2 - authlen;
+ for (i = 0; i < padlen; i++) {
+ pad[i] = i + 1;
+ }
+ dat[len - authlen - 2] = padlen;
+
+ dat[len - authlen - 1] = ixs->iph->protocol;
+ ixs->iph->protocol = IPPROTO_ESP;
+
+#ifdef CONFIG_IPSEC_ALG
+ /* Do all operations here:
+ * copy IV->ESP, encrypt, update ips IV
+ */
+ if (ixt_e) {
+ int ret;
+ memcpy(espp->esp_iv,
+ ixs->ipsp->ips_iv,
+ ixt_e->ixt_ivlen/8);
+ ret=ipsec_alg_esp_encrypt(ixs->ipsp,
+ idat, ilen, espp->esp_iv,
+ IPSEC_ALG_ENCRYPT);
+ memcpy(ixs->ipsp->ips_iv,
+ idat + ilen - ixt_e->ixt_ivlen/8,
+ ixt_e->ixt_ivlen/8);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ des_ede3_cbc_encrypt((des_cblock *)idat,
+ (des_cblock *)idat,
+ ilen,
+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[0].ks,
+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[1].ks,
+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[2].ks,
+ (des_cblock *)iv, 1);
+ break;
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if (!ixt_e)
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#if defined(CONFIG_IPSEC_ENC_3DES)
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ /* XXX update IV with the last 8 octets of the encryption */
+#if KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK
+ ((__u32*)(ixs->ipsp->ips_iv))[0] =
+ ((__u32 *)(idat))[(ilen >> 2) - 2];
+ ((__u32*)(ixs->ipsp->ips_iv))[1] =
+ ((__u32 *)(idat))[(ilen >> 2) - 1];
+#else /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
+ prng_bytes(&ipsec_prng, (char *)ixs->ipsp->ips_iv, EMT_ESPDES_IV_SZ);
+#endif /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
+ break;
+#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_ESP_BADALG;
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if (ixt_a) {
+ ipsec_alg_sa_esp_hash(ixs->ipsp,
+ (caddr_t)espp, len - ixs->iphlen - authlen,
+ &(dat[len - authlen]), authlen);
+
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ dmp("espp", (char*)espp, len - ixs->iphlen - authlen);
+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+ dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, (caddr_t)espp, len - ixs->iphlen - authlen);
+ dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Final(hash, &tctx.md5);
+ dmp("ictx hash", (char*)&hash, sizeof(hash));
+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
+ dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, hash, AHMD596_ALEN);
+ dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Final(hash, &tctx.md5);
+ dmp("octx hash", (char*)&hash, sizeof(hash));
+ memcpy(&(dat[len - authlen]), hash, authlen);
+
+ /* paranoid */
+ memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
+ memset((caddr_t)hash, 0, sizeof(*hash));
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+ SHA1Update(&tctx.sha1, (caddr_t)espp, len - ixs->iphlen - authlen);
+ SHA1Final(hash, &tctx.sha1);
+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
+ SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
+ SHA1Final(hash, &tctx.sha1);
+ memcpy(&(dat[len - authlen]), hash, authlen);
+
+ /* paranoid */
+ memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
+ memset((caddr_t)hash, 0, sizeof(*hash));
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ break;
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_AH_BADALG;
+ }
+#ifdef NET_21
+ ixs->skb->h.raw = (unsigned char*)espp;
+#endif /* NET_21 */
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ ahp = (struct ahhdr *)(dat + ixs->iphlen);
+ ahp->ah_spi = ixs->ipsp->ips_said.spi;
+ ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
+ ahp->ah_rv = 0;
+ ahp->ah_nh = ixs->iph->protocol;
+ ahp->ah_hl = (headroom >> 2) - sizeof(__u64)/sizeof(__u32);
+ ixs->iph->protocol = IPPROTO_AH;
+ dmp("ahp", (char*)ahp, sizeof(*ahp));
+
+ ipo = *ixs->iph;
+ ipo.tos = 0;
+ ipo.frag_off = 0;
+ ipo.ttl = 0;
+ ipo.check = 0;
+ dmp("ipo", (char*)&ipo, sizeof(ipo));
+
+ switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+ dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
+ dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
+ dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
+ dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
+ dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Final(hash, &tctx.md5);
+ dmp("ictx hash", (char*)&hash, sizeof(hash));
+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
+ dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Update(&tctx.md5, hash, AHMD596_ALEN);
+ dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
+ MD5Final(hash, &tctx.md5);
+ dmp("octx hash", (char*)&hash, sizeof(hash));
+
+ memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
+
+ /* paranoid */
+ memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
+ memset((caddr_t)hash, 0, sizeof(*hash));
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+ SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
+ SHA1Update(&tctx.sha1, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
+ SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
+ SHA1Update(&tctx.sha1, dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
+ SHA1Final(hash, &tctx.sha1);
+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
+ SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
+ SHA1Final(hash, &tctx.sha1);
+
+ memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
+
+ /* paranoid */
+ memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
+ memset((caddr_t)hash, 0, sizeof(*hash));
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_AH_BADALG;
+ }
+#ifdef NET_21
+ ixs->skb->h.raw = (unsigned char*)ahp;
+#endif /* NET_21 */
+ break;
+#endif /* CONFIG_IPSEC_AH */
+#ifdef CONFIG_IPSEC_IPIP
+ case IPPROTO_IPIP:
+ ixs->iph->version = 4;
+ switch(sysctl_ipsec_tos) {
+ case 0:
+#ifdef NET_21
+ ixs->iph->tos = ixs->skb->nh.iph->tos;
+#else /* NET_21 */
+ ixs->iph->tos = ixs->skb->ip_hdr->tos;
+#endif /* NET_21 */
+ break;
+ case 1:
+ ixs->iph->tos = 0;
+ break;
+ default:
+ break;
+ }
+#ifdef NET_21
+#ifdef NETDEV_23
+ ixs->iph->ttl = sysctl_ip_default_ttl;
+#else /* NETDEV_23 */
+ ixs->iph->ttl = ip_statistics.IpDefaultTTL;
+#endif /* NETDEV_23 */
+#else /* NET_21 */
+ ixs->iph->ttl = 64; /* ip_statistics.IpDefaultTTL; */
+#endif /* NET_21 */
+ ixs->iph->frag_off = 0;
+ ixs->iph->saddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr;
+ ixs->iph->daddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
+ ixs->iph->protocol = IPPROTO_IPIP;
+ ixs->iph->ihl = sizeof(struct iphdr) >> 2;
+
+ KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb);
+
+ ixs->newdst = (__u32)ixs->iph->daddr;
+ ixs->newsrc = (__u32)ixs->iph->saddr;
+
+#ifdef NET_21
+ ixs->skb->h.ipiph = ixs->skb->nh.iph;
+#endif /* NET_21 */
+ break;
+#endif /* !CONFIG_IPSEC_IPIP */
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ {
+ unsigned int flags = 0;
+#ifdef CONFIG_IPSEC_DEBUG
+ unsigned int old_tot_len = ntohs(ixs->iph->tot_len);
+#endif /* CONFIG_IPSEC_DEBUG */
+ ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len);
+
+ ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);
+
+#ifdef NET_21
+ ixs->iph = ixs->skb->nh.iph;
+#else /* NET_21 */
+ ixs->iph = ixs->skb->ip_hdr;
+#endif /* NET_21 */
+
+ ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_tunnel & DB_TN_CROUT)
+ {
+ if (old_tot_len > ntohs(ixs->iph->tot_len))
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",
+ old_tot_len, ntohs(ixs->iph->tot_len),
+ ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi),
+ ntohl(ixs->ipsp->ips_said.spi),
+ (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff));
+ else
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "packet did not compress (flags = %d).\n",
+ flags);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ }
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ default:
+ ixs->stats->tx_errors++;
+ return IPSEC_XMIT_BADPROTO;
+ }
+
+#ifdef NET_21
+ ixs->skb->nh.raw = ixs->skb->data;
+#else /* NET_21 */
+ ixs->skb->ip_hdr = ixs->skb->h.iph = (struct iphdr *) ixs->skb->data;
+#endif /* NET_21 */
+ ixs->iph->check = 0;
+ ixs->iph->check = ip_fast_csum((unsigned char *)ixs->iph, ixs->iph->ihl);
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_once: "
+ "after <%s%s%s>, SA:%s:\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
+
+ ixs->ipsp->ips_life.ipl_bytes.ipl_count += len;
+ ixs->ipsp->ips_life.ipl_bytes.ipl_last = len;
+
+ if(!ixs->ipsp->ips_life.ipl_usetime.ipl_count) {
+ ixs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
+ }
+ ixs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
+ ixs->ipsp->ips_life.ipl_packets.ipl_count++;
+
+ ixs->ipsp = ixs->ipsp->ips_onext;
+
+ return IPSEC_XMIT_OK;
+}
+
+enum ipsec_xmit_value
+ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs)
+{
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_enc *ixt_e = NULL;
+ struct ipsec_alg_auth *ixt_a = NULL;
+ int blocksize = 8;
+#endif /* CONFIG_IPSEC_ALG */
+ enum ipsec_xmit_value bundle_stat = IPSEC_XMIT_OK;
+
+ ixs->newdst = ixs->orgdst = ixs->iph->daddr;
+ ixs->newsrc = ixs->orgsrc = ixs->iph->saddr;
+ ixs->orgedst = ixs->outgoing_said.dst.s_addr;
+ ixs->iphlen = ixs->iph->ihl << 2;
+ ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
+ ixs->max_headroom = ixs->max_tailroom = 0;
+
+ if (ixs->outgoing_said.proto == IPPROTO_INT) {
+ switch (ntohl(ixs->outgoing_said.spi)) {
+ case SPI_DROP:
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "shunt SA of DROP or no eroute: dropping.\n");
+ ixs->stats->tx_dropped++;
+ break;
+
+ case SPI_REJECT:
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "shunt SA of REJECT: notifying and dropping.\n");
+ ICMP_SEND(ixs->skb,
+ ICMP_DEST_UNREACH,
+ ICMP_PKT_FILTERED,
+ 0,
+ ixs->physdev);
+ ixs->stats->tx_dropped++;
+ break;
+
+ case SPI_PASS:
+#ifdef NET_21
+ ixs->pass = 1;
+#endif /* NET_21 */
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "PASS: calling dev_queue_xmit\n");
+ return IPSEC_XMIT_PASS;
+ goto cleanup;
+
+#if 1 /* now moved up to finderoute so we don't need to lock it longer */
+ case SPI_HOLD:
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "shunt SA of HOLD: this does not make sense here, dropping.\n");
+ ixs->stats->tx_dropped++;
+ break;
+#endif
+ case SPI_TRAP:
+ case SPI_TRAPSUBNET:
+ {
+ struct sockaddr_in src, dst;
+#ifdef CONFIG_IPSEC_DEBUG
+ char bufsrc[ADDRTOA_BUF], bufdst[ADDRTOA_BUF];
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ /* Signal all listening KMds with a PF_KEY ACQUIRE */
+ ixs->ips.ips_said.proto = ixs->iph->protocol;
+ src.sin_family = AF_INET;
+ dst.sin_family = AF_INET;
+ src.sin_addr.s_addr = ixs->iph->saddr;
+ dst.sin_addr.s_addr = ixs->iph->daddr;
+ src.sin_port =
+ (ixs->iph->protocol == IPPROTO_UDP
+ ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->source
+ : (ixs->iph->protocol == IPPROTO_TCP
+ ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->source
+ : 0));
+ dst.sin_port =
+ (ixs->iph->protocol == IPPROTO_UDP
+ ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->dest
+ : (ixs->iph->protocol == IPPROTO_TCP
+ ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->dest
+ : 0));
+ {
+ int i;
+ for(i = 0;
+ i < sizeof(struct sockaddr_in)
+ - offsetof(struct sockaddr_in, sin_zero);
+ i++) {
+ src.sin_zero[i] = 0;
+ dst.sin_zero[i] = 0;
+ }
+ }
+
+ ixs->ips.ips_addr_s = (struct sockaddr*)(&src);
+ ixs->ips.ips_addr_d = (struct sockaddr*)(&dst);
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "SADB_ACQUIRE sent with src=%s:%d, dst=%s:%d, proto=%d.\n",
+ addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_addr, 0, bufsrc, sizeof(bufsrc)) <= ADDRTOA_BUF ? bufsrc : "BAD_ADDR",
+ ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_port),
+ addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_addr, 0, bufdst, sizeof(bufdst)) <= ADDRTOA_BUF ? bufdst : "BAD_ADDR",
+ ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_port),
+ ixs->ips.ips_said.proto);
+
+ /* increment count of total traps needed */
+ ipsec_xmit_trap_count++;
+
+ if (pfkey_acquire(&ixs->ips) == 0) {
+
+ /* note that we succeeded */
+ ipsec_xmit_trap_sendcount++;
+
+ if (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)) {
+ /*
+ * The spinlock is to prevent any other
+ * process from accessing or deleting
+ * the eroute while we are using and
+ * updating it.
+ */
+ spin_lock(&eroute_lock);
+ ixs->eroute = ipsec_findroute(&ixs->matcher);
+ if(ixs->eroute) {
+ ixs->eroute->er_said.spi = htonl(SPI_HOLD);
+ ixs->eroute->er_first = ixs->skb;
+ ixs->skb = NULL;
+ }
+ spin_unlock(&eroute_lock);
+ } else if (create_hold_eroute(ixs->skb, ixs->iph, ixs->eroute_pid)) {
+ ixs->skb = NULL;
+ }
+ }
+ ixs->stats->tx_dropped++;
+ }
+ default:
+ /* XXX what do we do with an unknown shunt spi? */
+ break;
+ } /* switch (ntohl(ixs->outgoing_said.spi)) */
+ return IPSEC_XMIT_STOLEN;
+ } /* if (ixs->outgoing_said.proto == IPPROTO_INT) */
+
+ /*
+ The spinlock is to prevent any other process from
+ accessing or deleting the ipsec_sa hash table or any of the
+ ipsec_sa s while we are using and updating them.
+
+ This is not optimal, but was relatively straightforward
+ at the time. A better way to do it has been planned for
+ more than a year, to lock the hash table and put reference
+ counts on each ipsec_sa instead. This is not likely to happen
+ in KLIPS1 unless a volunteer contributes it, but will be
+ designed into KLIPS2.
+ */
+ spin_lock(&tdb_lock);
+
+ ixs->ipsp = ipsec_sa_getbyid(&ixs->outgoing_said);
+ ixs->sa_len = satoa(ixs->outgoing_said, 0, ixs->sa_txt, SATOA_BUF);
+
+ if (ixs->ipsp == NULL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "no ipsec_sa for SA%s: outgoing packet with no SA, dropped.\n",
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ ixs->stats->tx_dropped++;
+ bundle_stat = IPSEC_XMIT_SAIDNOTFOUND;
+ goto cleanup;
+ }
+
+ ipsec_sa_put(ixs->ipsp); /* incomplete */
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "found ipsec_sa -- SA:<%s%s%s> %s\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+
+ /*
+ * How much headroom do we need to be able to apply
+ * all the grouped transforms?
+ */
+ ixs->ipsq = ixs->ipsp; /* save the head of the ipsec_sa chain */
+ while (ixs->ipsp) {
+ ixs->sa_len = satoa(ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOA_BUF);
+ if(ixs->sa_len == 0) {
+ strcpy(ixs->sa_txt, "(error)");
+ }
+
+ /* If it is in larval state, drop the packet, we cannot process yet. */
+ if(ixs->ipsp->ips_state == SADB_SASTATE_LARVAL) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "ipsec_sa in larval state for SA:<%s%s%s> %s, cannot be used yet, dropping packet.\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
+ goto cleanup;
+ }
+
+ if(ixs->ipsp->ips_state == SADB_SASTATE_DEAD) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "ipsec_sa in dead state for SA:<%s%s%s> %s, can no longer be used, dropping packet.\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
+ goto cleanup;
+ }
+
+ /* If the replay window counter == -1, expire SA, it will roll */
+ if(ixs->ipsp->ips_replaywin && ixs->ipsp->ips_replaywin_lastseq == -1) {
+ pfkey_expire(ixs->ipsp, 1);
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "replay window counter rolled for SA:<%s%s%s> %s, packet dropped, expiring SA.\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ ipsec_sa_delchain(ixs->ipsp);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_REPLAYROLLED;
+ goto cleanup;
+ }
+
+ /*
+ * if this is the first time we are using this SA, mark start time,
+ * and offset hard/soft counters by "now" for later checking.
+ */
+#if 0
+ if(ixs->ipsp->ips_life.ipl_usetime.count == 0) {
+ ixs->ipsp->ips_life.ipl_usetime.count = jiffies;
+ ixs->ipsp->ips_life.ipl_usetime.hard += jiffies;
+ ixs->ipsp->ips_life.ipl_usetime.soft += jiffies;
+ }
+#endif
+
+
+ if(ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_bytes, "bytes", ixs->sa_txt,
+ ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_addtime, "addtime",ixs->sa_txt,
+ ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_usetime, "usetime",ixs->sa_txt,
+ ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
+ ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_packets, "packets",ixs->sa_txt,
+ ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied) {
+
+ ipsec_sa_delchain(ixs->ipsp);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_LIFETIMEFAILED;
+ goto cleanup;
+ }
+
+
+ ixs->headroom = ixs->tailroom = 0;
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "calling room for <%s%s%s>, SA:%s\n",
+ IPS_XFORM_NAME(ixs->ipsp),
+ ixs->sa_len ? ixs->sa_txt : " (error)");
+ switch(ixs->ipsp->ips_said.proto) {
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ ixs->headroom += sizeof(struct ahhdr);
+ break;
+#endif /* CONFIG_IPSEC_AH */
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP:
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_e=ixs->ipsp->ips_alg_enc)) {
+ blocksize = ixt_e->ixt_blocksize;
+ ixs->headroom += ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ ixs->headroom += sizeof(struct esphdr);
+ break;
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ default:
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_ESP_BADALG;
+ goto cleanup;
+ }
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_a=ixs->ipsp->ips_alg_auth)) {
+ ixs->tailroom += AHHMAC_HASHLEN;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ ixs->tailroom += AHHMAC_HASHLEN;
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA:
+ ixs->tailroom += AHHMAC_HASHLEN;
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ break;
+ default:
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_AH_BADALG;
+ goto cleanup;
+ }
+#ifdef CONFIG_IPSEC_ALG
+ ixs->tailroom += blocksize != 1 ?
+ ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
+ ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
+#else
+ ixs->tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
+#endif /* CONFIG_IPSEC_ALG */
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if ((ixs->ipsp->ips_natt_type) && (!ixs->natt_type)) {
+ ixs->natt_type = ixs->ipsp->ips_natt_type;
+ ixs->natt_sport = ixs->ipsp->ips_natt_sport;
+ ixs->natt_dport = ixs->ipsp->ips_natt_dport;
+ switch (ixs->natt_type) {
+ case ESPINUDP_WITH_NON_IKE:
+ ixs->natt_head = sizeof(struct udphdr)+(2*sizeof(__u32));
+ break;
+ case ESPINUDP_WITH_NON_ESP:
+ ixs->natt_head = sizeof(struct udphdr);
+ break;
+ default:
+ ixs->natt_head = 0;
+ break;
+ }
+ ixs->tailroom += ixs->natt_head;
+ }
+#endif
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_IPIP
+ case IPPROTO_IPIP:
+ ixs->headroom += sizeof(struct iphdr);
+ break;
+#endif /* !CONFIG_IPSEC_IPIP */
+ case IPPROTO_COMP:
+#ifdef CONFIG_IPSEC_IPCOMP
+ /*
+ We can't predict how much the packet will
+ shrink without doing the actual compression.
+ We could do it here, if we were the first
+ encapsulation in the chain. That might save
+ us a skb_copy_expand, since we might fit
+ into the existing skb then. However, this
+ would be a bit unclean (and this hack has
+ bit us once), so we better not do it. After
+ all, the skb_copy_expand is cheap in
+ comparison to the actual compression.
+ At least we know the packet will not grow.
+ */
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ default:
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_BADPROTO;
+ goto cleanup;
+ }
+ ixs->ipsp = ixs->ipsp->ips_onext;
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "Required head,tailroom: %d,%d\n",
+ ixs->headroom, ixs->tailroom);
+ ixs->max_headroom += ixs->headroom;
+ ixs->max_tailroom += ixs->tailroom;
+ ixs->pyldsz += (ixs->headroom + ixs->tailroom);
+ }
+ ixs->ipsp = ixs->ipsq; /* restore the head of the ipsec_sa chain */
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "existing head,tailroom: %d,%d before applying xforms with head,tailroom: %d,%d .\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb),
+ ixs->max_headroom, ixs->max_tailroom);
+
+ ixs->tot_headroom += ixs->max_headroom;
+ ixs->tot_tailroom += ixs->max_tailroom;
+
+ ixs->mtudiff = ixs->prv->mtu + ixs->tot_headroom + ixs->tot_tailroom - ixs->physmtu;
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "mtu:%d physmtu:%d tothr:%d tottr:%d mtudiff:%d ippkttotlen:%d\n",
+ ixs->prv->mtu, ixs->physmtu,
+ ixs->tot_headroom, ixs->tot_tailroom, ixs->mtudiff, ntohs(ixs->iph->tot_len));
+ if(ixs->mtudiff > 0) {
+ int newmtu = ixs->physmtu - (ixs->tot_headroom + ((ixs->tot_tailroom + 2) & ~7) + 5);
+
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_info:ipsec_xmit_encap_bundle: "
+ "dev %s mtu of %d decreased by %d to %d\n",
+ ixs->dev->name,
+ ixs->prv->mtu,
+ ixs->prv->mtu - newmtu,
+ newmtu);
+ ixs->prv->mtu = newmtu;
+#ifdef NET_21
+#if 0
+ ixs->skb->dst->pmtu = ixs->prv->mtu; /* RGB */
+#endif /* 0 */
+#else /* NET_21 */
+#if 0
+ ixs->dev->mtu = ixs->prv->mtu; /* RGB */
+#endif /* 0 */
+#endif /* NET_21 */
+ }
+
+ /*
+ If the sender is doing PMTU discovery, and the
+ packet doesn't fit within ixs->prv->mtu, notify him
+ (unless it was an ICMP packet, or it was not the
+ zero-offset packet) and send it anyways.
+
+ Note: buggy firewall configuration may prevent the
+ ICMP packet from getting back.
+ */
+ if(sysctl_ipsec_icmp
+ && ixs->prv->mtu < ntohs(ixs->iph->tot_len)
+ && (ixs->iph->frag_off & __constant_htons(IP_DF)) ) {
+ int notify = ixs->iph->protocol != IPPROTO_ICMP
+ && (ixs->iph->frag_off & __constant_htons(IP_OFFSET)) == 0;
+
+#ifdef IPSEC_obey_DF
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "fragmentation needed and DF set; %sdropping packet\n",
+ notify ? "sending ICMP and " : "");
+ if (notify)
+ ICMP_SEND(ixs->skb,
+ ICMP_DEST_UNREACH,
+ ICMP_FRAG_NEEDED,
+ ixs->prv->mtu,
+ ixs->physdev);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_CANNOTFRAG;
+ goto cleanup;
+#else /* IPSEC_obey_DF */
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "fragmentation needed and DF set; %spassing packet\n",
+ notify ? "sending ICMP and " : "");
+ if (notify)
+ ICMP_SEND(ixs->skb,
+ ICMP_DEST_UNREACH,
+ ICMP_FRAG_NEEDED,
+ ixs->prv->mtu,
+ ixs->physdev);
+#endif /* IPSEC_obey_DF */
+ }
+
+#ifdef MSS_HACK
+ /*
+ * If this is a transport mode TCP packet with
+ * SYN set, determine an effective MSS based on
+ * AH/ESP overheads determined above.
+ */
+ if (ixs->iph->protocol == IPPROTO_TCP
+ && ixs->outgoing_said.proto != IPPROTO_IPIP) {
+ struct tcphdr *tcph = ixs->skb->h.th;
+ if (tcph->syn && !tcph->ack) {
+ if(!ipsec_adjust_mss(ixs->skb, tcph, ixs->prv->mtu)) {
+ printk(KERN_WARNING
+ "klips_warning:ipsec_xmit_encap_bundle: "
+ "ipsec_adjust_mss() failed\n");
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_MSSERR;
+ goto cleanup;
+ }
+ }
+ }
+#endif /* MSS_HACK */
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if ((ixs->natt_type) && (ixs->outgoing_said.proto != IPPROTO_IPIP)) {
+ /**
+ * NAT-Traversal and Transport Mode:
+ * we need to correct TCP/UDP checksum
+ *
+ * If we've got NAT-OA, we can fix checksum without recalculation.
+ * If we don't we can zero udp checksum.
+ */
+ __u32 natt_oa = ixs->ipsp->ips_natt_oa ?
+ ((struct sockaddr_in*)(ixs->ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
+ __u16 pkt_len = ixs->skb->tail - (unsigned char *)ixs->iph;
+ __u16 data_len = pkt_len - (ixs->iph->ihl << 2);
+ switch (ixs->iph->protocol) {
+ case IPPROTO_TCP:
+ if (data_len >= sizeof(struct tcphdr)) {
+ struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ixs->iph+ixs->iph->ihl);
+ if (natt_oa) {
+ __u32 buff[2] = { ~ixs->iph->daddr, natt_oa };
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: "
+ "fix TCP checksum using NAT-OA\n");
+ tcp->check = csum_fold(
+ csum_partial((unsigned char *)buff, sizeof(buff),
+ tcp->check^0xffff));
+ }
+ else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: do not recalc TCP checksum\n");
+ }
+ }
+ else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: can't fix TCP checksum\n");
+ }
+ break;
+ case IPPROTO_UDP:
+ if (data_len >= sizeof(struct udphdr)) {
+ struct udphdr *udp = (struct udphdr *)((__u32 *)ixs->iph+ixs->iph->ihl);
+ if (udp->check == 0) {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: UDP checksum already 0\n");
+ }
+ else if (natt_oa) {
+ __u32 buff[2] = { ~ixs->iph->daddr, natt_oa };
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: "
+ "fix UDP checksum using NAT-OA\n");
+ udp->check = csum_fold(
+ csum_partial((unsigned char *)buff, sizeof(buff),
+ udp->check^0xffff));
+ }
+ else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: zero UDP checksum\n");
+ udp->check = 0;
+ }
+ }
+ else {
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: can't fix UDP checksum\n");
+ }
+ break;
+ default:
+ KLIPS_PRINT(debug_tunnel,
+ "klips_debug:ipsec_tunnel_start_xmit: "
+ "NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
+ break;
+ }
+ }
+#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
+
+ if(!ixs->hard_header_stripped) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "allocating %d bytes for hardheader.\n",
+ ixs->hard_header_len);
+ if((ixs->saved_header = kmalloc(ixs->hard_header_len, GFP_ATOMIC)) == NULL) {
+ printk(KERN_WARNING "klips_debug:ipsec_xmit_encap_bundle: "
+ "Failed, tried to allocate %d bytes for temp hard_header.\n",
+ ixs->hard_header_len);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_ERRMEMALLOC;
+ goto cleanup;
+ }
+ {
+ int i;
+ for (i = 0; i < ixs->hard_header_len; i++) {
+ ixs->saved_header[i] = ixs->skb->data[i];
+ }
+ }
+ if(ixs->skb->len < ixs->hard_header_len) {
+ printk(KERN_WARNING "klips_error:ipsec_xmit_encap_bundle: "
+ "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n",
+ ixs->hard_header_len, (int)(ixs->skb->len));
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_ESP_PUSHPULLERR;
+ goto cleanup;
+ }
+ skb_pull(ixs->skb, ixs->hard_header_len);
+ ixs->hard_header_stripped = 1;
+
+/* ixs->iph = (struct iphdr *) (ixs->skb->data); */
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "head,tailroom: %d,%d after hard_header stripped.\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_CROUT, ixs->iph);
+ } else {
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "hard header already stripped.\n");
+ }
+
+ ixs->ll_headroom = (ixs->hard_header_len + 15) & ~15;
+
+ if ((skb_headroom(ixs->skb) >= ixs->max_headroom + 2 * ixs->ll_headroom) &&
+ (skb_tailroom(ixs->skb) >= ixs->max_tailroom)
+#ifndef NET_21
+ && ixs->skb->free
+#endif /* !NET_21 */
+ ) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "data fits in existing skb\n");
+ } else {
+ struct sk_buff* tskb;
+
+ if(!ixs->oskb) {
+ ixs->oskb = ixs->skb;
+ }
+
+ tskb = skb_copy_expand(ixs->skb,
+ /* The need for 2 * link layer length here remains unexplained...RGB */
+ ixs->max_headroom + 2 * ixs->ll_headroom,
+ ixs->max_tailroom,
+ GFP_ATOMIC);
+#ifdef NET_21
+ if(tskb && ixs->skb->sk) {
+ skb_set_owner_w(tskb, ixs->skb->sk);
+ }
+#endif /* NET_21 */
+ if(ixs->skb != ixs->oskb) {
+ ipsec_kfree_skb(ixs->skb);
+ }
+ ixs->skb = tskb;
+ if (!ixs->skb) {
+ printk(KERN_WARNING
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "Failed, tried to allocate %d head and %d tailroom\n",
+ ixs->max_headroom, ixs->max_tailroom);
+ ixs->stats->tx_errors++;
+ bundle_stat = IPSEC_XMIT_ERRSKBALLOC;
+ goto cleanup;
+ }
+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+ "klips_debug:ipsec_xmit_encap_bundle: "
+ "head,tailroom: %d,%d after allocation\n",
+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
+ }
+
+ /*
+ * Apply grouped transforms to packet
+ */
+ while (ixs->ipsp) {
+ enum ipsec_xmit_value encap_stat = IPSEC_XMIT_OK;
+
+ encap_stat = ipsec_xmit_encap_once(ixs);
+ if(encap_stat != IPSEC_XMIT_OK) {
+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+ "klips_debug:ipsec_xmit_encap_bundle: encap_once failed: %d\n",
+ encap_stat);
+
+ bundle_stat = IPSEC_XMIT_ENCAPFAIL;
+ goto cleanup;
+ }
+ }
+ /* end encapsulation loop here XXX */
+ cleanup:
+ spin_unlock(&tdb_lock);
+ return bundle_stat;
+}
diff --git a/linux/net/ipsec/pfkey_v2.c b/linux/net/ipsec/pfkey_v2.c
new file mode 100644
index 000000000..a78aaf26e
--- /dev/null
+++ b/linux/net/ipsec/pfkey_v2.c
@@ -0,0 +1,2125 @@
+/*
+ * @(#) RFC2367 PF_KEYv2 Key management API domain socket I/F
+ * 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: pfkey_v2.c,v 1.4 2004/09/29 22:27:41 as Exp $
+ */
+
+/*
+ * Template from /usr/src/linux-2.0.36/net/unix/af_unix.c.
+ * Hints from /usr/src/linux-2.0.36/net/ipv4/udp.c.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#include "freeswan/ipsec_param.h"
+
+#include <linux/major.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/un.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h> /* struct socket */
+#include <linux/in.h>
+#include <linux/fs.h>
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <asm/segment.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/sock.h> /* struct sock */
+/* #include <net/tcp.h> */
+#include <net/af_unix.h>
+#ifdef CONFIG_PROC_FS
+# include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+#include <linux/types.h>
+
+#include <freeswan.h>
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif /* NET_21 */
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+
+#ifdef CONFIG_IPSEC_DEBUG
+int debug_pfkey = 0;
+extern int sysctl_ipsec_debug_verbose;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+#ifndef SOCKOPS_WRAPPED
+#define SOCKOPS_WRAPPED(name) name
+#endif /* SOCKOPS_WRAPPED */
+
+extern struct proto_ops pfkey_ops;
+struct sock *pfkey_sock_list = NULL;
+struct supported_list *pfkey_supported_list[SADB_SATYPE_MAX+1];
+
+struct socket_list *pfkey_open_sockets = NULL;
+struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1];
+
+int pfkey_msg_interp(struct sock *, struct sadb_msg *, struct sadb_msg **);
+
+int
+pfkey_list_remove_socket(struct socket *socketp, struct socket_list **sockets)
+{
+ struct socket_list *socket_listp,*prev;
+
+ if(!socketp) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_socket: "
+ "NULL socketp handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ if(!sockets) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_socket: "
+ "NULL sockets list handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ socket_listp = *sockets;
+ prev = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_socket: "
+ "removing sock=0p%p\n",
+ socketp);
+
+ while(socket_listp != NULL) {
+ if(socket_listp->socketp == socketp) {
+ if(prev != NULL) {
+ prev->next = socket_listp->next;
+ } else {
+ *sockets = socket_listp->next;
+ }
+
+ kfree((void*)socket_listp);
+
+ break;
+ }
+ prev = socket_listp;
+ socket_listp = socket_listp->next;
+ }
+
+ return 0;
+}
+
+int
+pfkey_list_insert_socket(struct socket *socketp, struct socket_list **sockets)
+{
+ struct socket_list *socket_listp;
+
+ if(!socketp) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_socket: "
+ "NULL socketp handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ if(!sockets) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_socket: "
+ "NULL sockets list handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_socket: "
+ "allocating %lu bytes for socketp=0p%p\n",
+ (unsigned long) sizeof(struct socket_list),
+ socketp);
+
+ if((socket_listp = (struct socket_list *)kmalloc(sizeof(struct socket_list), GFP_KERNEL)) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_socket: "
+ "memory allocation error.\n");
+ return -ENOMEM;
+ }
+
+ socket_listp->socketp = socketp;
+ socket_listp->next = *sockets;
+ *sockets = socket_listp;
+
+ return 0;
+}
+
+int
+pfkey_list_remove_supported(struct supported *supported, struct supported_list **supported_list)
+{
+ struct supported_list *supported_listp = *supported_list, *prev = NULL;
+
+ if(!supported) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_supported: "
+ "NULL supported handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ if(!supported_list) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_supported: "
+ "NULL supported_list handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_remove_supported: "
+ "removing supported=0p%p\n",
+ supported);
+
+ while(supported_listp != NULL) {
+ if(supported_listp->supportedp == supported) {
+ if(prev != NULL) {
+ prev->next = supported_listp->next;
+ } else {
+ *supported_list = supported_listp->next;
+ }
+
+ kfree((void*)supported_listp);
+
+ break;
+ }
+ prev = supported_listp;
+ supported_listp = supported_listp->next;
+ }
+
+ return 0;
+}
+
+int
+pfkey_list_insert_supported(struct supported *supported, struct supported_list **supported_list)
+{
+ struct supported_list *supported_listp;
+
+ if(!supported) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "NULL supported handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ if(!supported_list) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "NULL supported_list handed in, failed.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "allocating %lu bytes for incoming, supported=0p%p, supported_list=0p%p\n",
+ (unsigned long) sizeof(struct supported_list),
+ supported,
+ supported_list);
+
+ supported_listp = (struct supported_list *)kmalloc(sizeof(struct supported_list), GFP_KERNEL);
+ if(supported_listp == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "memory allocation error.\n");
+ return -ENOMEM;
+ }
+
+ supported_listp->supportedp = supported;
+ supported_listp->next = *supported_list;
+ *supported_list = supported_listp;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_list_insert_supported: "
+ "outgoing, supported=0p%p, supported_list=0p%p\n",
+ supported,
+ supported_list);
+
+ return 0;
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC void
+pfkey_state_change(struct sock *sk)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_state_change: .\n");
+ if(!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ }
+}
+#endif /* !NET_21 */
+
+#ifndef NET_21
+DEBUG_NO_STATIC void
+pfkey_data_ready(struct sock *sk, int len)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_data_ready: "
+ "sk=0p%p len=%d\n",
+ sk,
+ len);
+ if(!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ sock_wake_async(sk->socket, 1);
+ }
+}
+
+DEBUG_NO_STATIC void
+pfkey_write_space(struct sock *sk)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_write_space: .\n");
+ if(!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ sock_wake_async(sk->socket, 2);
+ }
+}
+#endif /* !NET_21 */
+
+DEBUG_NO_STATIC void
+pfkey_insert_socket(struct sock *sk)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_insert_socket: "
+ "sk=0p%p\n",
+ sk);
+ cli();
+ sk->next=pfkey_sock_list;
+ pfkey_sock_list=sk;
+ sti();
+}
+
+DEBUG_NO_STATIC void
+pfkey_remove_socket(struct sock *sk)
+{
+ struct sock **s;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_remove_socket: .\n");
+ cli();
+ s=&pfkey_sock_list;
+
+ while(*s!=NULL) {
+ if(*s==sk) {
+ *s=sk->next;
+ sk->next=NULL;
+ sti();
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_remove_socket: "
+ "succeeded.\n");
+ return;
+ }
+ s=&((*s)->next);
+ }
+ sti();
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_remove_socket: "
+ "not found.\n");
+ return;
+}
+
+DEBUG_NO_STATIC void
+pfkey_destroy_socket(struct sock *sk)
+{
+ struct sk_buff *skb;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: .\n");
+ pfkey_remove_socket(sk);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: "
+ "pfkey_remove_socket called.\n");
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: "
+ "sk(0p%p)->(&0p%p)receive_queue.{next=0p%p,prev=0p%p}.\n",
+ sk,
+ &(sk->receive_queue),
+ sk->receive_queue.next,
+ sk->receive_queue.prev);
+ while(sk && ((skb=skb_dequeue(&(sk->receive_queue)))!=NULL)) {
+#ifdef NET_21
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_pfkey && sysctl_ipsec_debug_verbose) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: "
+ "skb=0p%p dequeued.\n", skb);
+ printk(KERN_INFO "klips_debug:pfkey_destroy_socket: "
+ "pfkey_skb contents:");
+ printk(" next:0p%p", skb->next);
+ printk(" prev:0p%p", skb->prev);
+ printk(" list:0p%p", skb->list);
+ printk(" sk:0p%p", skb->sk);
+ printk(" stamp:%ld.%ld", skb->stamp.tv_sec, skb->stamp.tv_usec);
+ printk(" dev:0p%p", skb->dev);
+ if(skb->dev) {
+ if(skb->dev->name) {
+ printk(" dev->name:%s", skb->dev->name);
+ } else {
+ printk(" dev->name:NULL?");
+ }
+ } else {
+ printk(" dev:NULL");
+ }
+ printk(" h:0p%p", skb->h.raw);
+ printk(" nh:0p%p", skb->nh.raw);
+ printk(" mac:0p%p", skb->mac.raw);
+ printk(" dst:0p%p", skb->dst);
+ if(sysctl_ipsec_debug_verbose) {
+ int i;
+
+ printk(" cb");
+ for(i=0; i<48; i++) {
+ printk(":%2x", skb->cb[i]);
+ }
+ }
+ printk(" len:%d", skb->len);
+ printk(" csum:%d", skb->csum);
+#ifndef NETDEV_23
+ printk(" used:%d", skb->used);
+ printk(" is_clone:%d", skb->is_clone);
+#endif /* NETDEV_23 */
+ printk(" cloned:%d", skb->cloned);
+ printk(" pkt_type:%d", skb->pkt_type);
+ printk(" ip_summed:%d", skb->ip_summed);
+ printk(" priority:%d", skb->priority);
+ printk(" protocol:%d", skb->protocol);
+ printk(" security:%d", skb->security);
+ printk(" truesize:%d", skb->truesize);
+ printk(" head:0p%p", skb->head);
+ printk(" data:0p%p", skb->data);
+ printk(" tail:0p%p", skb->tail);
+ printk(" end:0p%p", skb->end);
+ if(sysctl_ipsec_debug_verbose) {
+ unsigned char* i;
+ printk(" data");
+ for(i = skb->head; i < skb->end; i++) {
+ printk(":%2x", (unsigned char)(*(i)));
+ }
+ }
+ printk(" destructor:0p%p", skb->destructor);
+ printk("\n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* NET_21 */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: "
+ "skb=0p%p freed.\n",
+ skb);
+ ipsec_kfree_skb(skb);
+ }
+
+ sk->dead = 1;
+ sk_free(sk);
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_destroy_socket: destroyed.\n");
+}
+
+int
+pfkey_upmsg(struct socket *sock, struct sadb_msg *pfkey_msg)
+{
+ int error = 0;
+ struct sk_buff * skb = NULL;
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "NULL socket passed in.\n");
+ return -EINVAL;
+ }
+
+ if(pfkey_msg == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "NULL pfkey_msg passed in.\n");
+ return -EINVAL;
+ }
+
+#ifdef NET_21
+ sk = sock->sk;
+#else /* NET_21 */
+ sk = sock->data;
+#endif /* NET_21 */
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "NULL sock passed in.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "allocating %d bytes...\n",
+ (int)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN));
+ if(!(skb = alloc_skb(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN, GFP_ATOMIC) )) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "no buffers left to send up a message.\n");
+ return -ENOBUFS;
+ }
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "...allocated at 0p%p.\n",
+ skb);
+
+ skb->dev = NULL;
+
+ if(skb_tailroom(skb) < pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {
+ printk(KERN_WARNING "klips_error:pfkey_upmsg: "
+ "tried to skb_put %ld, %d available. This should never happen, please report.\n",
+ (unsigned long int)pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN,
+ skb_tailroom(skb));
+ ipsec_kfree_skb(skb);
+ return -ENOBUFS;
+ }
+ skb->h.raw = skb_put(skb, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+ memcpy(skb->h.raw, pfkey_msg, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+
+#ifndef NET_21
+ skb->free = 1;
+#endif /* !NET_21 */
+
+ if((error = sock_queue_rcv_skb(sk, skb)) < 0) {
+ skb->sk=NULL;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_upmsg: "
+ "error=%d calling sock_queue_rcv_skb with skb=0p%p.\n",
+ error,
+ skb);
+ ipsec_kfree_skb(skb);
+ return error;
+ }
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_create(struct socket *sock, int protocol)
+{
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "socket NULL.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "sock=0p%p type:%d state:%d flags:%ld protocol:%d\n",
+ sock,
+ sock->type,
+ (unsigned int)(sock->state),
+ sock->flags, protocol);
+
+ if(sock->type != SOCK_RAW) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "only SOCK_RAW supported.\n");
+ return -ESOCKTNOSUPPORT;
+ }
+
+ if(protocol != PF_KEY_V2) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "protocol not PF_KEY_V2.\n");
+ return -EPROTONOSUPPORT;
+ }
+
+ if((current->uid != 0)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "must be root to open pfkey sockets.\n");
+ return -EACCES;
+ }
+
+#ifdef NET_21
+ sock->state = SS_UNCONNECTED;
+#endif /* NET_21 */
+ MOD_INC_USE_COUNT;
+#ifdef NET_21
+ if((sk=(struct sock *)sk_alloc(PF_KEY, GFP_KERNEL, 1)) == NULL)
+#else /* NET_21 */
+ if((sk=(struct sock *)sk_alloc(GFP_KERNEL)) == NULL)
+#endif /* NET_21 */
+ {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "Out of memory trying to allocate.\n");
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+
+#ifndef NET_21
+ memset(sk, 0, sizeof(*sk));
+#endif /* !NET_21 */
+
+#ifdef NET_21
+ sock_init_data(sock, sk);
+
+ sk->destruct = NULL;
+ sk->reuse = 1;
+ sock->ops = &pfkey_ops;
+
+ sk->zapped=0;
+ sk->family = PF_KEY;
+/* sk->num = protocol; */
+ sk->protocol = protocol;
+ key_pid(sk) = current->pid;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "sock->fasync_list=0p%p sk->sleep=0p%p.\n",
+ sock->fasync_list,
+ sk->sleep);
+#else /* NET_21 */
+ sk->type=sock->type;
+ init_timer(&sk->timer);
+ skb_queue_head_init(&sk->write_queue);
+ skb_queue_head_init(&sk->receive_queue);
+ skb_queue_head_init(&sk->back_log);
+ sk->rcvbuf=SK_RMEM_MAX;
+ sk->sndbuf=SK_WMEM_MAX;
+ sk->allocation=GFP_KERNEL;
+ sk->state=TCP_CLOSE;
+ sk->priority=SOPRI_NORMAL;
+ sk->state_change=pfkey_state_change;
+ sk->data_ready=pfkey_data_ready;
+ sk->write_space=pfkey_write_space;
+ sk->error_report=pfkey_state_change;
+ sk->mtu=4096;
+ sk->socket=sock;
+ sock->data=(void *)sk;
+ sk->sleep=sock->wait;
+#endif /* NET_21 */
+
+ pfkey_insert_socket(sk);
+ pfkey_list_insert_socket(sock, &pfkey_open_sockets);
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_create: "
+ "Socket sock=0p%p sk=0p%p initialised.\n", sock, sk);
+ return 0;
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC int
+pfkey_dup(struct socket *newsock, struct socket *oldsock)
+{
+ struct sock *sk;
+
+ if(newsock==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dup: "
+ "No new socket attached.\n");
+ return -EINVAL;
+ }
+
+ if(oldsock==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dup: "
+ "No old socket attached.\n");
+ return -EINVAL;
+ }
+
+#ifdef NET_21
+ sk=oldsock->sk;
+#else /* NET_21 */
+ sk=oldsock->data;
+#endif /* NET_21 */
+
+ /* May not have data attached */
+ if(sk==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dup: "
+ "No sock attached to old socket.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dup: .\n");
+
+ return pfkey_create(newsock, sk->protocol);
+}
+#endif /* !NET_21 */
+
+DEBUG_NO_STATIC int
+#ifdef NETDEV_23
+pfkey_release(struct socket *sock)
+#else /* NETDEV_23 */
+pfkey_release(struct socket *sock, struct socket *peersock)
+#endif /* NETDEV_23 */
+{
+ struct sock *sk;
+ int i;
+
+ if(sock==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_release: "
+ "No socket attached.\n");
+ return 0; /* -EINVAL; */
+ }
+
+#ifdef NET_21
+ sk=sock->sk;
+#else /* NET_21 */
+ sk=sock->data;
+#endif /* NET_21 */
+
+ /* May not have data attached */
+ if(sk==NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_release: "
+ "No sk attached to sock=0p%p.\n", sock);
+ return 0; /* -EINVAL; */
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_release: "
+ "sock=0p%p sk=0p%p\n", sock, sk);
+
+#ifdef NET_21
+ if(!sk->dead)
+#endif /* NET_21 */
+ if(sk->state_change) {
+ sk->state_change(sk);
+ }
+
+#ifdef NET_21
+ sock->sk = NULL;
+#else /* NET_21 */
+ sock->data = NULL;
+#endif /* NET_21 */
+
+ /* Try to flush out this socket. Throw out buffers at least */
+ pfkey_destroy_socket(sk);
+ pfkey_list_remove_socket(sock, &pfkey_open_sockets);
+ for(i = SADB_SATYPE_UNSPEC; i <= SADB_SATYPE_MAX; i++) {
+ pfkey_list_remove_socket(sock, &(pfkey_registered_sockets[i]));
+ }
+
+ MOD_DEC_USE_COUNT;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_release: "
+ "succeeded.\n");
+
+ return 0;
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC int
+pfkey_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_bind: "
+ "operation not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_connect: "
+ "operation not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_socketpair(struct socket *a, struct socket *b)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_socketpair: "
+ "operation not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_aaccept: "
+ "operation not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len,
+ int peer)
+{
+ struct sockaddr *ska = (struct sockaddr*)uaddr;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getname: .\n");
+ ska->sa_family = PF_KEY;
+ *uaddr_len = sizeof(*ska);
+ return 0;
+}
+
+DEBUG_NO_STATIC int
+pfkey_select(struct socket *sock, int sel_type, select_table *wait)
+{
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_select: "
+ ".sock=0p%p sk=0p%p sel_type=%d\n",
+ sock,
+ sock->data,
+ sel_type);
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_select: "
+ "Null socket passed in.\n");
+ return -EINVAL;
+ }
+ return datagram_select(sock->data, sel_type, wait);
+}
+
+DEBUG_NO_STATIC int
+pfkey_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ioctl: "
+ "not supported.\n");
+ return -EINVAL;
+}
+
+DEBUG_NO_STATIC int
+pfkey_listen(struct socket *sock, int backlog)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_listen: "
+ "not supported.\n");
+ return -EINVAL;
+}
+#endif /* !NET_21 */
+
+DEBUG_NO_STATIC int
+pfkey_shutdown(struct socket *sock, int mode)
+{
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_shutdown: "
+ "NULL socket passed in.\n");
+ return -EINVAL;
+ }
+
+#ifdef NET_21
+ sk=sock->sk;
+#else /* NET_21 */
+ sk=sock->data;
+#endif /* NET_21 */
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_shutdown: "
+ "No sock attached to socket.\n");
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_shutdown: "
+ "mode=%x.\n", mode);
+ mode++;
+
+ if(mode&SEND_SHUTDOWN) {
+ sk->shutdown|=SEND_SHUTDOWN;
+ sk->state_change(sk);
+ }
+
+ if(mode&RCV_SHUTDOWN) {
+ sk->shutdown|=RCV_SHUTDOWN;
+ sk->state_change(sk);
+ }
+ return 0;
+}
+
+#ifndef NET_21
+DEBUG_NO_STATIC int
+pfkey_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+{
+#ifndef NET_21
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: "
+ "Null socket passed in.\n");
+ return -EINVAL;
+ }
+
+ sk=sock->data;
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: "
+ "Null sock passed in.\n");
+ return -EINVAL;
+ }
+#endif /* !NET_21 */
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: .\n");
+ if(level!=SOL_SOCKET) {
+ return -EOPNOTSUPP;
+ }
+#ifdef NET_21
+ return sock_setsockopt(sock, level, optname, optval, optlen);
+#else /* NET_21 */
+ return sock_setsockopt(sk, level, optname, optval, optlen);
+#endif /* NET_21 */
+}
+
+DEBUG_NO_STATIC int
+pfkey_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+{
+#ifndef NET_21
+ struct sock *sk;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: "
+ "Null socket passed in.\n");
+ return -EINVAL;
+ }
+
+ sk=sock->data;
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_setsockopt: "
+ "Null sock passed in.\n");
+ return -EINVAL;
+ }
+#endif /* !NET_21 */
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getsockopt: .\n");
+ if(level!=SOL_SOCKET) {
+ return -EOPNOTSUPP;
+ }
+#ifdef NET_21
+ return sock_getsockopt(sock, level, optname, optval, optlen);
+#else /* NET_21 */
+ return sock_getsockopt(sk, level, optname, optval, optlen);
+#endif /* NET_21 */
+}
+
+DEBUG_NO_STATIC int
+pfkey_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_fcntl: "
+ "not supported.\n");
+ return -EINVAL;
+}
+#endif /* !NET_21 */
+
+/*
+ * Send PF_KEY data down.
+ */
+
+DEBUG_NO_STATIC int
+#ifdef NET_21
+pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+#else /* NET_21 */
+pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
+#endif /* NET_21 */
+{
+ struct sock *sk;
+ int error = 0;
+ struct sadb_msg *pfkey_msg = NULL, *pfkey_reply = NULL;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "Null socket passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+#ifdef NET_21
+ sk = sock->sk;
+#else /* NET_21 */
+ sk = sock->data;
+#endif /* NET_21 */
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "Null sock passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(msg == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "Null msghdr passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: .\n");
+ if(sk->err) {
+ error = sock_error(sk);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "sk->err is non-zero, returns %d.\n",
+ error);
+ SENDERR(-error);
+ }
+
+ if((current->uid != 0)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "must be root to send messages to pfkey sockets.\n");
+ SENDERR(EACCES);
+ }
+
+#ifdef NET_21
+ if(msg->msg_control)
+#else /* NET_21 */
+ if(flags || msg->msg_control)
+#endif /* NET_21 */
+ {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "can't set flags or set msg_control.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(sk->shutdown & SEND_SHUTDOWN) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "shutdown.\n");
+ send_sig(SIGPIPE, current, 0);
+ SENDERR(EPIPE);
+ }
+
+ if(len < sizeof(struct sadb_msg)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "bogus msg len of %d, too small.\n", len);
+ SENDERR(EMSGSIZE);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "allocating %d bytes for downward message.\n",
+ len);
+ if((pfkey_msg = (struct sadb_msg*)kmalloc(len, GFP_KERNEL)) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "memory allocation error.\n");
+ SENDERR(ENOBUFS);
+ }
+
+ memcpy_fromiovec((void *)pfkey_msg, msg->msg_iov, len);
+
+ if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
+ KLIPS_PRINT(1 || debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "not PF_KEY_V2 msg, found %d, should be %d.\n",
+ pfkey_msg->sadb_msg_version,
+ PF_KEY_V2);
+ kfree((void*)pfkey_msg);
+ return -EINVAL;
+ }
+
+ if(len != pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "bogus msg len of %d, not %d byte aligned.\n",
+ len, (int)IPSEC_PFKEYv2_ALIGN);
+ SENDERR(EMSGSIZE);
+ }
+
+#if 0
+ /* This check is questionable, since a downward message could be
+ the result of an ACQUIRE either from kernel (PID==0) or
+ userspace (some other PID). */
+ /* check PID */
+ if(pfkey_msg->sadb_msg_pid != current->pid) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "pid (%d) does not equal sending process pid (%d).\n",
+ pfkey_msg->sadb_msg_pid, current->pid);
+ SENDERR(EINVAL);
+ }
+#endif
+
+ if(pfkey_msg->sadb_msg_reserved) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "reserved field must be zero, set to %d.\n",
+ pfkey_msg->sadb_msg_reserved);
+ SENDERR(EINVAL);
+ }
+
+ if((pfkey_msg->sadb_msg_type > SADB_MAX) || (!pfkey_msg->sadb_msg_type)){
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "msg type too large or small:%d.\n",
+ pfkey_msg->sadb_msg_type);
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "msg sent for parsing.\n");
+
+ if((error = pfkey_msg_interp(sk, pfkey_msg, &pfkey_reply))) {
+ struct socket_list *pfkey_socketsp;
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
+ "pfkey_msg_parse returns %d.\n",
+ error);
+
+ if((pfkey_reply = (struct sadb_msg*)kmalloc(sizeof(struct sadb_msg), GFP_KERNEL)) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "memory allocation error.\n");
+ SENDERR(ENOBUFS);
+ }
+ memcpy((void*)pfkey_reply, (void*)pfkey_msg, sizeof(struct sadb_msg));
+ pfkey_reply->sadb_msg_errno = -error;
+ pfkey_reply->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ int error_upmsg = 0;
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
+ "sending up error=%d message=0p%p to socket=0p%p.\n",
+ error,
+ pfkey_reply,
+ pfkey_socketsp->socketp);
+ if((error_upmsg = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
+ "sending up error message to socket=0p%p failed with error=%d.\n",
+ pfkey_socketsp->socketp,
+ error_upmsg);
+ /* pfkey_msg_free(&pfkey_reply); */
+ /* SENDERR(-error); */
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
+ "sending up error message to socket=0p%p succeeded.\n",
+ pfkey_socketsp->socketp);
+ }
+
+ pfkey_msg_free(&pfkey_reply);
+
+ SENDERR(-error);
+ }
+
+ errlab:
+ if (pfkey_msg) {
+ kfree((void*)pfkey_msg);
+ }
+
+ if(error) {
+ return error;
+ } else {
+ return len;
+ }
+}
+
+/*
+ * Receive PF_KEY data up.
+ */
+
+DEBUG_NO_STATIC int
+#ifdef NET_21
+pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
+#else /* NET_21 */
+pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
+#endif /* NET_21 */
+{
+ struct sock *sk;
+#ifdef NET_21
+ int noblock = flags & MSG_DONTWAIT;
+#endif /* NET_21 */
+ struct sk_buff *skb;
+ int error;
+
+ if(sock == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_recvmsg: "
+ "Null socket passed in.\n");
+ return -EINVAL;
+ }
+
+#ifdef NET_21
+ sk = sock->sk;
+#else /* NET_21 */
+ sk = sock->data;
+#endif /* NET_21 */
+
+ if(sk == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_recvmsg: "
+ "Null sock passed in for sock=0p%p.\n", sock);
+ return -EINVAL;
+ }
+
+ if(msg == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_recvmsg: "
+ "Null msghdr passed in for sock=0p%p, sk=0p%p.\n",
+ sock, sk);
+ return -EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_recvmsg: sock=0p%p sk=0p%p msg=0p%p size=%d.\n",
+ sock, sk, msg, size);
+ if(flags & ~MSG_PEEK) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "flags (%d) other than MSG_PEEK not supported.\n",
+ flags);
+ return -EOPNOTSUPP;
+ }
+
+#ifdef NET_21
+ msg->msg_namelen = 0; /* sizeof(*ska); */
+#else /* NET_21 */
+ if(addr_len) {
+ *addr_len = 0; /* sizeof(*ska); */
+ }
+#endif /* NET_21 */
+
+ if(sk->err) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sendmsg: "
+ "sk->err=%d.\n", sk->err);
+ return sock_error(sk);
+ }
+
+ if((skb = skb_recv_datagram(sk, flags, noblock, &error) ) == NULL) {
+ return error;
+ }
+
+ if(size > skb->len) {
+ size = skb->len;
+ }
+#ifdef NET_21
+ else if(size <skb->len) {
+ msg->msg_flags |= MSG_TRUNC;
+ }
+#endif /* NET_21 */
+
+ skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size);
+ sk->stamp=skb->stamp;
+
+ skb_free_datagram(sk, skb);
+ return size;
+}
+
+#ifdef NET_21
+struct net_proto_family pfkey_family_ops = {
+ PF_KEY,
+ pfkey_create
+};
+
+struct proto_ops SOCKOPS_WRAPPED(pfkey_ops) = {
+#ifdef NETDEV_23
+ family: PF_KEY,
+ release: pfkey_release,
+ bind: sock_no_bind,
+ connect: sock_no_connect,
+ socketpair: sock_no_socketpair,
+ accept: sock_no_accept,
+ getname: sock_no_getname,
+ poll: datagram_poll,
+ ioctl: sock_no_ioctl,
+ listen: sock_no_listen,
+ shutdown: pfkey_shutdown,
+ setsockopt: sock_no_setsockopt,
+ getsockopt: sock_no_getsockopt,
+ sendmsg: pfkey_sendmsg,
+ recvmsg: pfkey_recvmsg,
+ mmap: sock_no_mmap,
+#else /* NETDEV_23 */
+ PF_KEY,
+ sock_no_dup,
+ pfkey_release,
+ sock_no_bind,
+ sock_no_connect,
+ sock_no_socketpair,
+ sock_no_accept,
+ sock_no_getname,
+ datagram_poll,
+ sock_no_ioctl,
+ sock_no_listen,
+ pfkey_shutdown,
+ sock_no_setsockopt,
+ sock_no_getsockopt,
+ sock_no_fcntl,
+ pfkey_sendmsg,
+ pfkey_recvmsg
+#endif /* NETDEV_23 */
+};
+
+#ifdef NETDEV_23
+#include <linux/smp_lock.h>
+SOCKOPS_WRAP(pfkey, PF_KEY);
+#endif /* NETDEV_23 */
+
+#else /* NET_21 */
+struct proto_ops pfkey_proto_ops = {
+ PF_KEY,
+ pfkey_create,
+ pfkey_dup,
+ pfkey_release,
+ pfkey_bind,
+ pfkey_connect,
+ pfkey_socketpair,
+ pfkey_accept,
+ pfkey_getname,
+ pfkey_select,
+ pfkey_ioctl,
+ pfkey_listen,
+ pfkey_shutdown,
+ pfkey_setsockopt,
+ pfkey_getsockopt,
+ pfkey_fcntl,
+ pfkey_sendmsg,
+ pfkey_recvmsg
+};
+#endif /* NET_21 */
+
+#ifdef CONFIG_PROC_FS
+#ifndef PROC_FS_2325
+DEBUG_NO_STATIC
+#endif /* PROC_FS_2325 */
+int
+pfkey_get_info(char *buffer, char **start, off_t offset, int length
+#ifndef PROC_NO_DUMMY
+, int dummy
+#endif /* !PROC_NO_DUMMY */
+)
+{
+ const int max_content = length > 0? length-1 : 0;
+
+ off_t begin=0;
+ int len=0;
+ struct sock *sk=pfkey_sock_list;
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(!sysctl_ipsec_debug_verbose) {
+#endif /* CONFIG_IPSEC_DEBUG */
+ len+= snprintf(buffer,length,
+ " sock pid socket next prev e n p sndbf Flags Type St\n");
+#ifdef CONFIG_IPSEC_DEBUG
+ } else {
+ len+= snprintf(buffer,length,
+ " sock pid d sleep socket next prev e r z n p sndbf stamp Flags Type St\n");
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ while(sk!=NULL) {
+#ifdef CONFIG_IPSEC_DEBUG
+ if(!sysctl_ipsec_debug_verbose) {
+#endif /* CONFIG_IPSEC_DEBUG */
+ len += ipsec_snprintf(buffer+len, length-len,
+ "%8p %5d %8p %8p %8p %d %d %d %5d %08lX %8X %2X\n",
+ sk,
+ key_pid(sk),
+ sk->socket,
+ sk->next,
+ sk->prev,
+ sk->err,
+ sk->num,
+ sk->protocol,
+ sk->sndbuf,
+ sk->socket->flags,
+ sk->socket->type,
+ sk->socket->state);
+#ifdef CONFIG_IPSEC_DEBUG
+ } else {
+ len += ipsec_snprintf(buffer+len, length-len,
+ "%8p %5d %d %8p %8p %8p %8p %d %d %d %d %d %5d %d.%06d %08lX %8X %2X\n",
+ sk,
+ key_pid(sk),
+ sk->dead,
+ sk->sleep,
+ sk->socket,
+ sk->next,
+ sk->prev,
+ sk->err,
+ sk->reuse,
+ sk->zapped,
+ sk->num,
+ sk->protocol,
+ sk->sndbuf,
+ (unsigned int)sk->stamp.tv_sec,
+ (unsigned int)sk->stamp.tv_usec,
+ sk->socket->flags,
+ sk->socket->type,
+ sk->socket->state);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loop */
+ len = max_content; /* truncate crap */
+ break;
+ } else {
+ const off_t pos = begin + len; /* file position of end of what we've generated */
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+ sk=sk->next;
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+#ifndef PROC_FS_2325
+DEBUG_NO_STATIC
+#endif /* PROC_FS_2325 */
+int
+pfkey_supported_get_info(char *buffer, char **start, off_t offset, int length
+#ifndef PROC_NO_DUMMY
+, int dummy
+#endif /* !PROC_NO_DUMMY */
+)
+{
+ const int max_content = length > 0? length-1 : 0;
+
+ off_t begin=0;
+ int len=0;
+ int satype;
+ struct supported_list *pfkey_supported_p;
+
+ len += ipsec_snprintf(buffer, length,
+ "satype exttype alg_id ivlen minbits maxbits\n");
+
+ for(satype = SADB_SATYPE_UNSPEC; satype <= SADB_SATYPE_MAX; satype++) {
+ pfkey_supported_p = pfkey_supported_list[satype];
+ while(pfkey_supported_p) {
+ len += ipsec_snprintf(buffer+len, length-len,
+ " %2d %2d %2d %3d %3d %3d\n",
+ satype,
+ pfkey_supported_p->supportedp->supported_alg_exttype,
+ pfkey_supported_p->supportedp->supported_alg_id,
+ pfkey_supported_p->supportedp->supported_alg_ivlen,
+ pfkey_supported_p->supportedp->supported_alg_minbits,
+ pfkey_supported_p->supportedp->supported_alg_maxbits);
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loop */
+ len = max_content; /* truncate crap */
+ break;
+ } else {
+ const off_t pos = begin + len; /* file position of end of what we've generated */
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+
+ pfkey_supported_p = pfkey_supported_p->next;
+ }
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+#ifndef PROC_FS_2325
+DEBUG_NO_STATIC
+#endif /* PROC_FS_2325 */
+int
+pfkey_registered_get_info(char *buffer, char **start, off_t offset, int length
+#ifndef PROC_NO_DUMMY
+, int dummy
+#endif /* !PROC_NO_DUMMY */
+)
+{
+ const int max_content = length > 0? length-1 : 0;
+
+ off_t begin=0;
+ int len=0;
+ int satype;
+ struct socket_list *pfkey_sockets;
+
+ len += ipsec_snprintf(buffer, length,
+ "satype socket pid sk\n");
+
+ for(satype = SADB_SATYPE_UNSPEC; satype <= SADB_SATYPE_MAX; satype++) {
+ pfkey_sockets = pfkey_registered_sockets[satype];
+ while(pfkey_sockets) {
+#ifdef NET_21
+ len += ipsec_snprintf(buffer+len, length-len,
+ " %2d %8p %5d %8p\n",
+ satype,
+ pfkey_sockets->socketp,
+ key_pid(pfkey_sockets->socketp->sk),
+ pfkey_sockets->socketp->sk);
+#else /* NET_21 */
+ len += ipsec_snprintf(buffer+len, length-len,
+ " %2d %8p N/A %8p\n",
+ satype,
+ pfkey_sockets->socketp,
+#if 0
+ key_pid((pfkey_sockets->socketp)->data),
+#endif
+ (pfkey_sockets->socketp)->data);
+#endif /* NET_21 */
+
+ if (len >= max_content) {
+ /* we've done all that can fit -- stop loop (could stop two) */
+ len = max_content; /* truncate crap */
+ break;
+ } else {
+ const off_t pos = begin + len; /* file position of end of what we've generated */
+
+ if (pos <= offset) {
+ /* all is before first interesting character:
+ * discard, but note where we are.
+ */
+ len = 0;
+ begin = pos;
+ }
+ }
+
+ pfkey_sockets = pfkey_sockets->next;
+ }
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ return len - (offset - begin);
+}
+
+#ifndef PROC_FS_2325
+struct proc_dir_entry proc_net_pfkey =
+{
+ 0,
+ 6, "pf_key",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ pfkey_get_info
+};
+struct proc_dir_entry proc_net_pfkey_supported =
+{
+ 0,
+ 16, "pf_key_supported",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ pfkey_supported_get_info
+};
+struct proc_dir_entry proc_net_pfkey_registered =
+{
+ 0,
+ 17, "pf_key_registered",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ pfkey_registered_get_info
+};
+#endif /* !PROC_FS_2325 */
+#endif /* CONFIG_PROC_FS */
+
+DEBUG_NO_STATIC int
+supported_add_all(int satype, struct supported supported[], int size)
+{
+ int i;
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:init_pfkey: "
+ "sizeof(supported_init_<satype=%d>)[%d]/sizeof(struct supported)[%d]=%d.\n",
+ satype,
+ size,
+ (int)sizeof(struct supported),
+ (int)(size/sizeof(struct supported)));
+
+ for(i = 0; i < size / sizeof(struct supported); i++) {
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:init_pfkey: "
+ "i=%d inserting satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
+ i,
+ satype,
+ supported[i].supported_alg_exttype,
+ supported[i].supported_alg_id,
+ supported[i].supported_alg_ivlen,
+ supported[i].supported_alg_minbits,
+ supported[i].supported_alg_maxbits);
+
+ error |= pfkey_list_insert_supported(&(supported[i]),
+ &(pfkey_supported_list[satype]));
+ }
+ return error;
+}
+
+DEBUG_NO_STATIC int
+supported_remove_all(int satype)
+{
+ int error = 0;
+ struct supported*supportedp;
+
+ while(pfkey_supported_list[satype]) {
+ supportedp = pfkey_supported_list[satype]->supportedp;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:init_pfkey: "
+ "removing satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
+ satype,
+ supportedp->supported_alg_exttype,
+ supportedp->supported_alg_id,
+ supportedp->supported_alg_ivlen,
+ supportedp->supported_alg_minbits,
+ supportedp->supported_alg_maxbits);
+
+ error |= pfkey_list_remove_supported(supportedp,
+ &(pfkey_supported_list[satype]));
+ }
+ return error;
+}
+
+int
+pfkey_init(void)
+{
+ int error = 0;
+ int i;
+
+ static struct supported supported_init_ah[] = {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5_HMAC, 0, 128, 128},
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1_HMAC, 0, 160, 160}
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ };
+ static struct supported supported_init_esp[] = {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5_HMAC, 0, 128, 128},
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1_HMAC, 0, 160, 160},
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+#ifdef CONFIG_IPSEC_ENC_3DES
+ {SADB_EXT_SUPPORTED_ENCRYPT, SADB_EALG_3DES_CBC, 64, 168, 168},
+#endif /* CONFIG_IPSEC_ENC_3DES */
+ };
+ static struct supported supported_init_ipip[] = {
+ {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv4_in_IPv4, 0, 32, 32}
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv6_in_IPv4, 0, 128, 32}
+ , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv4_in_IPv6, 0, 32, 128}
+ , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv6_in_IPv6, 0, 128, 128}
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+ };
+#ifdef CONFIG_IPSEC_IPCOMP
+ static struct supported supported_init_ipcomp[] = {
+ {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_CALG_DEFLATE, 0, 1, 1}
+ };
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#if 0
+ printk(KERN_INFO
+ "klips_info:pfkey_init: "
+ "FreeS/WAN: initialising PF_KEYv2 domain sockets.\n");
+#endif
+
+ for(i = SADB_SATYPE_UNSPEC; i <= SADB_SATYPE_MAX; i++) {
+ pfkey_registered_sockets[i] = NULL;
+ pfkey_supported_list[i] = NULL;
+ }
+
+ error |= supported_add_all(SADB_SATYPE_AH, supported_init_ah, sizeof(supported_init_ah));
+ error |= supported_add_all(SADB_SATYPE_ESP, supported_init_esp, sizeof(supported_init_esp));
+#ifdef CONFIG_IPSEC_IPCOMP
+ error |= supported_add_all(SADB_X_SATYPE_COMP, supported_init_ipcomp, sizeof(supported_init_ipcomp));
+#endif /* CONFIG_IPSEC_IPCOMP */
+ error |= supported_add_all(SADB_X_SATYPE_IPIP, supported_init_ipip, sizeof(supported_init_ipip));
+
+#ifdef NET_21
+ error |= sock_register(&pfkey_family_ops);
+#else /* NET_21 */
+ error |= sock_register(pfkey_proto_ops.family, &pfkey_proto_ops);
+#endif /* NET_21 */
+
+#ifdef CONFIG_PROC_FS
+# ifndef PROC_FS_2325
+# ifdef PROC_FS_21
+ error |= proc_register(proc_net, &proc_net_pfkey);
+ error |= proc_register(proc_net, &proc_net_pfkey_supported);
+ error |= proc_register(proc_net, &proc_net_pfkey_registered);
+# else /* PROC_FS_21 */
+ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey);
+ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_supported);
+ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_registered);
+# endif /* PROC_FS_21 */
+# else /* !PROC_FS_2325 */
+ proc_net_create ("pf_key", 0, pfkey_get_info);
+ proc_net_create ("pf_key_supported", 0, pfkey_supported_get_info);
+ proc_net_create ("pf_key_registered", 0, pfkey_registered_get_info);
+# endif /* !PROC_FS_2325 */
+#endif /* CONFIG_PROC_FS */
+
+ return error;
+}
+
+int
+pfkey_cleanup(void)
+{
+ int error = 0;
+
+ printk(KERN_INFO "klips_info:pfkey_cleanup: "
+ "shutting down PF_KEY domain sockets.\n");
+#ifdef NET_21
+ error |= sock_unregister(PF_KEY);
+#else /* NET_21 */
+ error |= sock_unregister(pfkey_proto_ops.family);
+#endif /* NET_21 */
+
+ error |= supported_remove_all(SADB_SATYPE_AH);
+ error |= supported_remove_all(SADB_SATYPE_ESP);
+#ifdef CONFIG_IPSEC_IPCOMP
+ error |= supported_remove_all(SADB_X_SATYPE_COMP);
+#endif /* CONFIG_IPSEC_IPCOMP */
+ error |= supported_remove_all(SADB_X_SATYPE_IPIP);
+
+#ifdef CONFIG_PROC_FS
+# ifndef PROC_FS_2325
+ if (proc_net_unregister(proc_net_pfkey.low_ino) != 0)
+ printk("klips_debug:pfkey_cleanup: "
+ "cannot unregister /proc/net/pf_key\n");
+ if (proc_net_unregister(proc_net_pfkey_supported.low_ino) != 0)
+ printk("klips_debug:pfkey_cleanup: "
+ "cannot unregister /proc/net/pf_key_supported\n");
+ if (proc_net_unregister(proc_net_pfkey_registered.low_ino) != 0)
+ printk("klips_debug:pfkey_cleanup: "
+ "cannot unregister /proc/net/pf_key_registered\n");
+# else /* !PROC_FS_2325 */
+ proc_net_remove ("pf_key");
+ proc_net_remove ("pf_key_supported");
+ proc_net_remove ("pf_key_registered");
+# endif /* !PROC_FS_2325 */
+#endif /* CONFIG_PROC_FS */
+
+ /* other module unloading cleanup happens here */
+ return error;
+}
+
+#ifdef MODULE
+#if 0
+int
+init_module(void)
+{
+ pfkey_init();
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ pfkey_cleanup();
+}
+#endif /* 0 */
+#else /* MODULE */
+void
+pfkey_proto_init(struct net_proto *pro)
+{
+ pfkey_init();
+}
+#endif /* MODULE */
+
+/*
+ * $Log: pfkey_v2.c,v $
+ * Revision 1.4 2004/09/29 22:27:41 as
+ * changed SADB identifiers
+ *
+ * Revision 1.3 2004/04/28 08:06:22 as
+ * added dhr's freeswan-2.06 changes
+ *
+ * Revision 1.2 2004/03/22 21:53:19 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.4.1 2004/03/16 09:48:20 as
+ * alg-0.8.1rc12 patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.78 2003/04/03 17:38:09 rgb
+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
+ *
+ * Revision 1.77 2002/10/17 16:49:36 mcr
+ * sock->ops should reference the unwrapped options so that
+ * we get hacked in locking on SMP systems.
+ *
+ * Revision 1.76 2002/10/12 23:11:53 dhr
+ *
+ * [KenB + DHR] more 64-bit cleanup
+ *
+ * Revision 1.75 2002/09/20 05:01:57 rgb
+ * Added memory allocation debugging.
+ *
+ * Revision 1.74 2002/09/19 02:42:50 mcr
+ * do not define the pfkey_ops function for now.
+ *
+ * Revision 1.73 2002/09/17 17:29:23 mcr
+ * #if 0 out some dead code - pfkey_ops is never used as written.
+ *
+ * Revision 1.72 2002/07/24 18:44:54 rgb
+ * Type fiddling to tame ia64 compiler.
+ *
+ * Revision 1.71 2002/05/23 07:14:11 rgb
+ * Cleaned up %p variants to 0p%p for test suite cleanup.
+ *
+ * Revision 1.70 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.69 2002/04/24 07:36:33 mcr
+ * Moved from ./klips/net/ipsec/pfkey_v2.c,v
+ *
+ * Revision 1.68 2002/03/08 01:15:17 mcr
+ * put some internal structure only debug messages behind
+ * && sysctl_ipsec_debug_verbose.
+ *
+ * Revision 1.67 2002/01/29 17:17:57 mcr
+ * moved include of ipsec_param.h to after include of linux/kernel.h
+ * otherwise, it seems that some option that is set in ipsec_param.h
+ * screws up something subtle in the include path to kernel.h, and
+ * it complains on the snprintf() prototype.
+ *
+ * Revision 1.66 2002/01/29 04:00:54 mcr
+ * more excise of kversions.h header.
+ *
+ * Revision 1.65 2002/01/29 02:13:18 mcr
+ * introduction of ipsec_kversion.h means that include of
+ * ipsec_param.h must preceed any decisions about what files to
+ * include to deal with differences in kernel source.
+ *
+ * Revision 1.64 2001/11/26 09:23:51 rgb
+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
+ *
+ * Revision 1.61.2.1 2001/09/25 02:28:44 mcr
+ * cleaned up includes.
+ *
+ * Revision 1.63 2001/11/12 19:38:00 rgb
+ * Continue trying other sockets even if one fails and return only original
+ * error.
+ *
+ * Revision 1.62 2001/10/18 04:45:22 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.61 2001/09/20 15:32:59 rgb
+ * Min/max cleanup.
+ *
+ * Revision 1.60 2001/06/14 19:35:12 rgb
+ * Update copyright date.
+ *
+ * Revision 1.59 2001/06/13 15:35:48 rgb
+ * Fixed #endif comments.
+ *
+ * Revision 1.58 2001/05/04 16:37:24 rgb
+ * Remove erroneous checking of return codes for proc_net_* in 2.4.
+ *
+ * Revision 1.57 2001/05/03 19:43:36 rgb
+ * Initialise error return variable.
+ * Check error return codes in startup and shutdown.
+ * Standardise on SENDERR() macro.
+ *
+ * Revision 1.56 2001/04/21 23:05:07 rgb
+ * Define out skb->used for 2.4 kernels.
+ *
+ * Revision 1.55 2001/02/28 05:03:28 rgb
+ * Clean up and rationalise startup messages.
+ *
+ * Revision 1.54 2001/02/27 22:24:55 rgb
+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
+ * Check for satoa() return codes.
+ *
+ * Revision 1.53 2001/02/27 06:48:18 rgb
+ * Fixed pfkey socket unregister log message to reflect type and function.
+ *
+ * Revision 1.52 2001/02/26 22:34:38 rgb
+ * Fix error return code that was getting overwritten by the error return
+ * code of an upmsg.
+ *
+ * Revision 1.51 2001/01/30 23:42:47 rgb
+ * Allow pfkey msgs from pid other than user context required for ACQUIRE
+ * and subsequent ADD or UDATE.
+ *
+ * Revision 1.50 2001/01/23 20:22:59 rgb
+ * 2.4 fix to remove removed is_clone member.
+ *
+ * Revision 1.49 2000/11/06 04:33:47 rgb
+ * Changed non-exported functions to DEBUG_NO_STATIC.
+ *
+ * Revision 1.48 2000/09/29 19:47:41 rgb
+ * Update copyright.
+ *
+ * Revision 1.47 2000/09/22 04:23:04 rgb
+ * Added more debugging to pfkey_upmsg() call from pfkey_sendmsg() error.
+ *
+ * Revision 1.46 2000/09/21 04:20:44 rgb
+ * Fixed array size off-by-one error. (Thanks Svenning!)
+ *
+ * Revision 1.45 2000/09/20 04:01:26 rgb
+ * Changed static functions to DEBUG_NO_STATIC for revealing function names
+ * in oopsen.
+ *
+ * Revision 1.44 2000/09/19 00:33:17 rgb
+ * 2.0 fixes.
+ *
+ * Revision 1.43 2000/09/16 01:28:13 rgb
+ * Fixed use of 0 in p format warning.
+ *
+ * Revision 1.42 2000/09/16 01:09:41 rgb
+ * Fixed debug format warning for pointers that was expecting ints.
+ *
+ * Revision 1.41 2000/09/13 15:54:00 rgb
+ * Rewrote pfkey_get_info(), added pfkey_{supported,registered}_get_info().
+ * Moved supported algos add and remove to functions.
+ *
+ * Revision 1.40 2000/09/12 18:49:28 rgb
+ * Added IPIP tunnel and IPCOMP register support.
+ *
+ * Revision 1.39 2000/09/12 03:23:49 rgb
+ * Converted #if0 debugs to sysctl.
+ * Removed debug_pfkey initialisations that prevented no_debug loading or
+ * linking.
+ *
+ * Revision 1.38 2000/09/09 06:38:02 rgb
+ * Return positive errno in pfkey_reply error message.
+ *
+ * Revision 1.37 2000/09/08 19:19:09 rgb
+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
+ * Clean-up of long-unused crud...
+ * Create pfkey error message on on failure.
+ * Give pfkey_list_{insert,remove}_{socket,supported}() some error
+ * checking.
+ *
+ * Revision 1.36 2000/09/01 18:49:38 rgb
+ * Reap experimental NET_21_ bits.
+ * Turned registered sockets list into an array of one list per satype.
+ * Remove references to deprecated sklist_{insert,remove}_socket.
+ * Removed leaking socket debugging code.
+ * Removed duplicate pfkey_insert_socket in pfkey_create.
+ * Removed all references to pfkey msg->msg_name, since it is not used for
+ * pfkey.
+ * Added a supported algorithms array lists, one per satype and registered
+ * existing algorithms.
+ * Fixed pfkey_list_{insert,remove}_{socket,support}() to allow change to
+ * list.
+ * Only send pfkey_expire() messages to sockets registered for that satype.
+ *
+ * Revision 1.35 2000/08/24 17:03:00 rgb
+ * Corrected message size error return code for PF_KEYv2.
+ * Removed downward error prohibition.
+ *
+ * Revision 1.34 2000/08/21 16:32:26 rgb
+ * Re-formatted for cosmetic consistency and readability.
+ *
+ * Revision 1.33 2000/08/20 21:38:24 rgb
+ * Added a pfkey_reply parameter to pfkey_msg_interp(). (Momchil)
+ * Extended the upward message initiation of pfkey_sendmsg(). (Momchil)
+ *
+ * Revision 1.32 2000/07/28 14:58:31 rgb
+ * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5.
+ *
+ * Revision 1.31 2000/05/16 03:04:00 rgb
+ * Updates for 2.3.99pre8 from MB.
+ *
+ * Revision 1.30 2000/05/10 19:22:21 rgb
+ * Use sklist private functions for 2.3.xx compatibility.
+ *
+ * Revision 1.29 2000/03/22 16:17:03 rgb
+ * Fixed SOCKOPS_WRAPPED macro for SMP (MB).
+ *
+ * Revision 1.28 2000/02/21 19:30:45 rgb
+ * Removed references to pkt_bridged for 2.3.47 compatibility.
+ *
+ * Revision 1.27 2000/02/14 21:07:00 rgb
+ * Fixed /proc/net/pf-key legend spacing.
+ *
+ * Revision 1.26 2000/01/22 03:46:59 rgb
+ * Fixed pfkey error return mechanism so that we are able to free the
+ * local copy of the pfkey_msg, plugging a memory leak and silencing
+ * the bad object free complaints.
+ *
+ * Revision 1.25 2000/01/21 06:19:44 rgb
+ * Moved pfkey_list_remove_socket() calls to before MOD_USE_DEC_COUNT.
+ * Added debugging to pfkey_upmsg.
+ *
+ * Revision 1.24 2000/01/10 16:38:23 rgb
+ * MB fixups for 2.3.x.
+ *
+ * Revision 1.23 1999/12/09 23:22:16 rgb
+ * Added more instrumentation for debugging 2.0 socket
+ * selection/reading.
+ * Removed erroneous 2.0 wait==NULL check bug in select.
+ *
+ * Revision 1.22 1999/12/08 20:32:16 rgb
+ * Tidied up 2.0.xx support, after major pfkey work, eliminating
+ * msg->msg_name twiddling in the process, since it is not defined
+ * for PF_KEYv2.
+ *
+ * Revision 1.21 1999/12/01 22:17:19 rgb
+ * Set skb->dev to zero on new skb in case it is a reused skb.
+ * Added check for skb_put overflow and freeing to avoid upmsg on error.
+ * Added check for wrong pfkey version and freeing to avoid upmsg on
+ * error.
+ * Shut off content dumping in pfkey_destroy.
+ * Added debugging message for size of buffer allocated for upmsg.
+ *
+ * Revision 1.20 1999/11/27 12:11:00 rgb
+ * Minor clean-up, enabling quiet operation of pfkey if desired.
+ *
+ * Revision 1.19 1999/11/25 19:04:21 rgb
+ * Update proc_fs code for pfkey to use dynamic registration.
+ *
+ * Revision 1.18 1999/11/25 09:07:17 rgb
+ * Implemented SENDERR macro for propagating error codes.
+ * Fixed error return code bug.
+ *
+ * Revision 1.17 1999/11/23 23:07:20 rgb
+ * Change name of pfkey_msg_parser to pfkey_msg_interp since it no longer
+ * parses. (PJO)
+ * Sort out pfkey and freeswan headers, putting them in a library path.
+ *
+ * Revision 1.16 1999/11/20 22:00:22 rgb
+ * Moved socketlist type declarations and prototypes for shared use.
+ * Renamed reformatted and generically extended for use by other socket
+ * lists pfkey_{del,add}_open_socket to pfkey_list_{remove,insert}_socket.
+ *
+ * Revision 1.15 1999/11/18 04:15:09 rgb
+ * Make pfkey_data_ready temporarily available for 2.2.x testing.
+ * Clean up pfkey_destroy_socket() debugging statements.
+ * Add Peter Onion's code to send messages up to all listening sockets.
+ * Changed all occurrences of #include "../../../lib/freeswan.h"
+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
+ * klips/net/ipsec/Makefile.
+ * Replaced all kernel version macros to shorter, readable form.
+ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
+ *
+ * Revision 1.14 1999/11/17 16:01:00 rgb
+ * Make pfkey_data_ready temporarily available for 2.2.x testing.
+ * Clean up pfkey_destroy_socket() debugging statements.
+ * Add Peter Onion's code to send messages up to all listening sockets.
+ * Changed #include "../../../lib/freeswan.h" to #include <freeswan.h>
+ * which works due to -Ilibfreeswan in the klips/net/ipsec/Makefile.
+ *
+ * Revision 1.13 1999/10/27 19:59:51 rgb
+ * Removed af_unix comments that are no longer relevant.
+ * Added debug prink statements.
+ * Added to the /proc output in pfkey_get_info.
+ * Made most functions non-static to enable oops tracing.
+ * Re-enable skb dequeueing and freeing.
+ * Fix skb_alloc() and skb_put() size bug in pfkey_upmsg().
+ *
+ * Revision 1.12 1999/10/26 17:05:42 rgb
+ * Complete re-ordering based on proto_ops structure order.
+ * Separated out proto_ops structures for 2.0.x and 2.2.x for clarity.
+ * Simplification to use built-in socket ops where possible for 2.2.x.
+ * Add shorter macros for compiler directives to visually clean-up.
+ * Add lots of sk skb dequeueing debugging statements.
+ * Added to the /proc output in pfkey_get_info.
+ *
+ * Revision 1.11 1999/09/30 02:55:10 rgb
+ * Bogus skb detection.
+ * Fix incorrect /proc/net/ipsec-eroute printk message.
+ *
+ * Revision 1.10 1999/09/21 15:22:13 rgb
+ * Temporary fix while I figure out the right way to destroy sockets.
+ *
+ * Revision 1.9 1999/07/08 19:19:44 rgb
+ * Fix pointer format warning.
+ * Fix missing member error under 2.0.xx kernels.
+ *
+ * Revision 1.8 1999/06/13 07:24:04 rgb
+ * Add more debugging.
+ *
+ * Revision 1.7 1999/06/10 05:24:17 rgb
+ * Clarified compiler directives.
+ * Renamed variables to reduce confusion.
+ * Used sklist_*_socket() kernel functions to simplify 2.2.x socket support.
+ * Added lots of sanity checking.
+ *
+ * Revision 1.6 1999/06/03 18:59:50 rgb
+ * More updates to 2.2.x socket support. Almost works, oops at end of call.
+ *
+ * Revision 1.5 1999/05/25 22:44:05 rgb
+ * Start fixing 2.2 sockets.
+ *
+ * Revision 1.4 1999/04/29 15:21:34 rgb
+ * Move log to the end of the file.
+ * Eliminate min/max redefinition in #include <net/tcp.h>.
+ * Correct path for pfkey #includes
+ * Standardise an error return method.
+ * Add debugging instrumentation.
+ * Move message type checking to pfkey_msg_parse().
+ * Add check for errno incorrectly set.
+ * Add check for valid PID.
+ * Add check for reserved illegally set.
+ * Add check for message out of bounds.
+ *
+ * Revision 1.3 1999/04/15 17:58:07 rgb
+ * Add RCSID labels.
+ *
+ * Revision 1.2 1999/04/15 15:37:26 rgb
+ * Forward check changes from POST1_00 branch.
+ *
+ * Revision 1.1.2.2 1999/04/13 20:37:12 rgb
+ * Header Title correction.
+ *
+ * Revision 1.1.2.1 1999/03/26 20:58:55 rgb
+ * Add pfkeyv2 support to KLIPS.
+ *
+ *
+ * RFC 2367
+ * PF_KEY_v2 Key Management API
+ */
diff --git a/linux/net/ipsec/pfkey_v2_ext_process.c b/linux/net/ipsec/pfkey_v2_ext_process.c
new file mode 100644
index 000000000..9269bd59e
--- /dev/null
+++ b/linux/net/ipsec/pfkey_v2_ext_process.c
@@ -0,0 +1,851 @@
+/*
+ * @(#) RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pfkey_v2_ext_process.c,v 1.3 2004/06/13 19:57:50 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_netlink.c.
+ */
+
+char pfkey_v2_ext_process_c_version[] = "$Id: pfkey_v2_ext_process.c,v 1.3 2004/06/13 19:57:50 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+
+#include <freeswan.h>
+
+#include <crypto/des.h>
+
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define ip_chk_addr inet_addr_type
+# define IS_MYADDR RTN_LOCAL
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+#ifdef NETLINK_SOCK
+# include <linux/netlink.h>
+#else
+# include <net/netlink.h>
+#endif
+
+#include <linux/random.h> /* get_random_bytes() */
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h"
+#include "freeswan/ipcomp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+int
+pfkey_sa_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
+ int error = 0;
+ struct ipsec_sa* ipsp;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sa_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sa_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_ext->sadb_ext_type) {
+ case SADB_EXT_SA:
+ ipsp = extr->ips;
+ break;
+ case SADB_X_EXT_SA2:
+ if(extr->ips2 == NULL) {
+ extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
+ }
+ if(extr->ips2 == NULL) {
+ SENDERR(-error);
+ }
+ ipsp = extr->ips2;
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sa_process: "
+ "invalid exttype=%d.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL);
+ }
+
+ ipsp->ips_said.spi = pfkey_sa->sadb_sa_spi;
+ ipsp->ips_replaywin = pfkey_sa->sadb_sa_replay;
+ ipsp->ips_state = pfkey_sa->sadb_sa_state;
+ ipsp->ips_flags = pfkey_sa->sadb_sa_flags;
+ ipsp->ips_replaywin_lastseq = ipsp->ips_replaywin_bitmap = 0;
+ ipsp->ips_ref_rel = pfkey_sa->sadb_x_sa_ref;
+
+ switch(ipsp->ips_said.proto) {
+ case IPPROTO_AH:
+ ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
+ ipsp->ips_encalg = SADB_EALG_NONE;
+ break;
+ case IPPROTO_ESP:
+ ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
+ ipsp->ips_encalg = pfkey_sa->sadb_sa_encrypt;
+#ifdef CONFIG_IPSEC_ALG
+ ipsec_alg_sa_init(ipsp);
+#endif /* CONFIG_IPSEC_ALG */
+ break;
+ case IPPROTO_IPIP:
+ ipsp->ips_authalg = AH_NONE;
+ ipsp->ips_encalg = ESP_NONE;
+ break;
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ ipsp->ips_authalg = AH_NONE;
+ ipsp->ips_encalg = pfkey_sa->sadb_sa_encrypt;
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ case IPPROTO_INT:
+ ipsp->ips_authalg = AH_NONE;
+ ipsp->ips_encalg = ESP_NONE;
+ break;
+ case 0:
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sa_process: "
+ "unknown proto=%d.\n",
+ ipsp->ips_said.proto);
+ SENDERR(EINVAL);
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_lifetime_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_lifetime_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_lifetime_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_lifetime->sadb_lifetime_exttype) {
+ case SADB_EXT_LIFETIME_CURRENT:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_lifetime_process: "
+ "lifetime_current not supported yet.\n");
+ SENDERR(EINVAL);
+ break;
+ case SADB_EXT_LIFETIME_HARD:
+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_allocations,
+ pfkey_lifetime->sadb_lifetime_allocations);
+
+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_bytes,
+ pfkey_lifetime->sadb_lifetime_bytes);
+
+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_addtime,
+ pfkey_lifetime->sadb_lifetime_addtime);
+
+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_usetime,
+ pfkey_lifetime->sadb_lifetime_usetime);
+
+ break;
+
+ case SADB_EXT_LIFETIME_SOFT:
+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_allocations,
+ pfkey_lifetime->sadb_lifetime_allocations);
+
+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_bytes,
+ pfkey_lifetime->sadb_lifetime_bytes);
+
+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_addtime,
+ pfkey_lifetime->sadb_lifetime_addtime);
+
+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_usetime,
+ pfkey_lifetime->sadb_lifetime_usetime);
+
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_lifetime_process: "
+ "invalid exttype=%d.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL);
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_address_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ int saddr_len = 0;
+ char ipaddr_txt[ADDRTOA_BUF];
+ unsigned char **sap;
+ unsigned short * portp = 0;
+ struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
+ struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
+ struct ipsec_sa* ipsp;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process:\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(s->sa_family) {
+ case AF_INET:
+ saddr_len = sizeof(struct sockaddr_in);
+ addrtoa(((struct sockaddr_in*)s)->sin_addr, 0, ipaddr_txt, sizeof(ipaddr_txt));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found address family=%d, AF_INET, %s.\n",
+ s->sa_family,
+ ipaddr_txt);
+ break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ saddr_len = sizeof(struct sockaddr_in6);
+ break;
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "s->sa_family=%d not supported.\n",
+ s->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+
+ switch(pfkey_address->sadb_address_exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found src address.\n");
+ sap = (unsigned char **)&(extr->ips->ips_addr_s);
+ extr->ips->ips_addr_s_size = saddr_len;
+ break;
+ case SADB_EXT_ADDRESS_DST:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found dst address.\n");
+ sap = (unsigned char **)&(extr->ips->ips_addr_d);
+ extr->ips->ips_addr_d_size = saddr_len;
+ break;
+ case SADB_EXT_ADDRESS_PROXY:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found proxy address.\n");
+ sap = (unsigned char **)&(extr->ips->ips_addr_p);
+ extr->ips->ips_addr_p_size = saddr_len;
+ break;
+ case SADB_X_EXT_ADDRESS_DST2:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found 2nd dst address.\n");
+ if(extr->ips2 == NULL) {
+ extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
+ }
+ if(extr->ips2 == NULL) {
+ SENDERR(-error);
+ }
+ sap = (unsigned char **)&(extr->ips2->ips_addr_d);
+ extr->ips2->ips_addr_d_size = saddr_len;
+ break;
+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found src flow address.\n");
+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
+ SENDERR(ENOMEM);
+ }
+ sap = (unsigned char **)&(extr->eroute->er_eaddr.sen_ip_src);
+ portp = &(extr->eroute->er_eaddr.sen_sport);
+ break;
+ case SADB_X_EXT_ADDRESS_DST_FLOW:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found dst flow address.\n");
+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
+ SENDERR(ENOMEM);
+ }
+ sap = (unsigned char **)&(extr->eroute->er_eaddr.sen_ip_dst);
+ portp = &(extr->eroute->er_eaddr.sen_dport);
+ break;
+ case SADB_X_EXT_ADDRESS_SRC_MASK:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found src mask address.\n");
+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
+ SENDERR(ENOMEM);
+ }
+ sap = (unsigned char **)&(extr->eroute->er_emask.sen_ip_src);
+ portp = &(extr->eroute->er_emask.sen_sport);
+ break;
+ case SADB_X_EXT_ADDRESS_DST_MASK:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found dst mask address.\n");
+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
+ SENDERR(ENOMEM);
+ }
+ sap = (unsigned char **)&(extr->eroute->er_emask.sen_ip_dst);
+ portp = &(extr->eroute->er_emask.sen_dport);
+ break;
+#ifdef NAT_TRAVERSAL
+ case SADB_X_EXT_NAT_T_OA:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "found NAT-OA address.\n");
+ sap = (unsigned char **)&(extr->ips->ips_natt_oa);
+ extr->ips->ips_natt_oa_size = saddr_len;
+ break;
+#endif
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "unrecognised ext_type=%d.\n",
+ pfkey_address->sadb_address_exttype);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_address->sadb_address_exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_X_EXT_ADDRESS_DST2:
+#ifdef NAT_TRAVERSAL
+ case SADB_X_EXT_NAT_T_OA:
+#endif
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "allocating %d bytes for saddr.\n",
+ saddr_len);
+ if(!(*sap = kmalloc(saddr_len, GFP_KERNEL))) {
+ SENDERR(ENOMEM);
+ }
+ memcpy(*sap, s, saddr_len);
+ break;
+ default:
+ if(s->sa_family != AF_INET) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "s->sa_family=%d not supported.\n",
+ s->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+ (unsigned long)(*sap) = ((struct sockaddr_in*)s)->sin_addr.s_addr;
+ if (portp != 0)
+ *portp = ((struct sockaddr_in*)s)->sin_port;
+#ifdef CONFIG_IPSEC_DEBUG
+ if(extr->eroute) {
+ char buf1[64], buf2[64];
+ if (debug_pfkey) {
+ subnettoa(extr->eroute->er_eaddr.sen_ip_src,
+ extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
+ extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_parse: "
+ "extr->eroute set to %s:%d->%s:%d\n",
+ buf1,
+ ntohs(extr->eroute->er_eaddr.sen_sport),
+ buf2,
+ ntohs(extr->eroute->er_eaddr.sen_dport));
+ }
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ }
+
+ ipsp = extr->ips;
+ switch(pfkey_address->sadb_address_exttype) {
+ case SADB_X_EXT_ADDRESS_DST2:
+ ipsp = extr->ips2;
+ case SADB_EXT_ADDRESS_DST:
+ if(s->sa_family == AF_INET) {
+ ipsp->ips_said.dst.s_addr = ((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr.s_addr;
+ addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr,
+ 0,
+ ipaddr_txt,
+ sizeof(ipaddr_txt));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "ips_said.dst set to %s.\n",
+ ipaddr_txt);
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: "
+ "uh, ips_said.dst doesn't do address family=%d yet, said will be invalid.\n",
+ s->sa_family);
+ }
+ default:
+ break;
+ }
+
+ /* XXX check if port!=0 */
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_address_process: successful.\n");
+ errlab:
+ return error;
+}
+
+int
+pfkey_key_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_key->sadb_key_exttype) {
+ case SADB_EXT_KEY_AUTH:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "allocating %d bytes for authkey.\n",
+ DIVUP(pfkey_key->sadb_key_bits, 8));
+ if(!(extr->ips->ips_key_a = kmalloc(DIVUP(pfkey_key->sadb_key_bits, 8), GFP_KERNEL))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "memory allocation error.\n");
+ SENDERR(ENOMEM);
+ }
+ extr->ips->ips_key_bits_a = pfkey_key->sadb_key_bits;
+ extr->ips->ips_key_a_size = DIVUP(pfkey_key->sadb_key_bits, 8);
+ memcpy(extr->ips->ips_key_a,
+ (char*)pfkey_key + sizeof(struct sadb_key),
+ extr->ips->ips_key_a_size);
+ break;
+ case SADB_EXT_KEY_ENCRYPT: /* Key(s) */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "allocating %d bytes for enckey.\n",
+ DIVUP(pfkey_key->sadb_key_bits, 8));
+ if(!(extr->ips->ips_key_e = kmalloc(DIVUP(pfkey_key->sadb_key_bits, 8), GFP_KERNEL))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "memory allocation error.\n");
+ SENDERR(ENOMEM);
+ }
+ extr->ips->ips_key_bits_e = pfkey_key->sadb_key_bits;
+ extr->ips->ips_key_e_size = DIVUP(pfkey_key->sadb_key_bits, 8);
+ memcpy(extr->ips->ips_key_e,
+ (char*)pfkey_key + sizeof(struct sadb_key),
+ extr->ips->ips_key_e_size);
+ break;
+ default:
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_key_process: "
+ "success.\n");
+errlab:
+ return error;
+}
+
+int
+pfkey_ident_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext;
+ int data_len;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ident_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ident_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_ident->sadb_ident_exttype) {
+ case SADB_EXT_IDENTITY_SRC:
+ data_len = pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ extr->ips->ips_ident_s.type = pfkey_ident->sadb_ident_type;
+ extr->ips->ips_ident_s.id = pfkey_ident->sadb_ident_id;
+ extr->ips->ips_ident_s.len = pfkey_ident->sadb_ident_len;
+ if(data_len) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ident_process: "
+ "allocating %d bytes for ident_s.\n",
+ data_len);
+ if(!(extr->ips->ips_ident_s.data
+ = kmalloc(data_len, GFP_KERNEL))) {
+ SENDERR(ENOMEM);
+ }
+ memcpy(extr->ips->ips_ident_s.data,
+ (char*)pfkey_ident + sizeof(struct sadb_ident),
+ data_len);
+ } else {
+ extr->ips->ips_ident_s.data = NULL;
+ }
+ break;
+ case SADB_EXT_IDENTITY_DST: /* Identity(ies) */
+ data_len = pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ extr->ips->ips_ident_d.type = pfkey_ident->sadb_ident_type;
+ extr->ips->ips_ident_d.id = pfkey_ident->sadb_ident_id;
+ extr->ips->ips_ident_d.len = pfkey_ident->sadb_ident_len;
+ if(data_len) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ident_process: "
+ "allocating %d bytes for ident_d.\n",
+ data_len);
+ if(!(extr->ips->ips_ident_d.data
+ = kmalloc(data_len, GFP_KERNEL))) {
+ SENDERR(ENOMEM);
+ }
+ memcpy(extr->ips->ips_ident_d.data,
+ (char*)pfkey_ident + sizeof(struct sadb_ident),
+ data_len);
+ } else {
+ extr->ips->ips_ident_d.data = NULL;
+ }
+ break;
+ default:
+ SENDERR(EINVAL);
+ }
+errlab:
+ return error;
+}
+
+int
+pfkey_sens_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_sens_process: "
+ "Sorry, I can't process exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+ errlab:
+ return error;
+}
+
+int
+pfkey_prop_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_prop_process: "
+ "Sorry, I can't process exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ errlab:
+ return error;
+}
+
+int
+pfkey_supported_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_supported_process: "
+ "Sorry, I can't process exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+errlab:
+ return error;
+}
+
+int
+pfkey_spirange_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_spirange_process: .\n");
+/* errlab: */
+ return error;
+}
+
+int
+pfkey_x_kmprivate_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_kmprivate_process: "
+ "Sorry, I can't process exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+errlab:
+ return error;
+}
+
+int
+pfkey_x_satype_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_satype_process: .\n");
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_satype_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ if(extr->ips2 == NULL) {
+ extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
+ }
+ if(extr->ips2 == NULL) {
+ SENDERR(-error);
+ }
+ if(!(extr->ips2->ips_said.proto = satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_satype_process: "
+ "proto lookup from satype=%d failed.\n",
+ pfkey_x_satype->sadb_x_satype_satype);
+ SENDERR(EINVAL);
+ }
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_satype_process: "
+ "protocol==%d decoded from satype==%d(%s).\n",
+ extr->ips2->ips_said.proto,
+ pfkey_x_satype->sadb_x_satype_satype,
+ satype2name(pfkey_x_satype->sadb_x_satype_satype));
+
+errlab:
+ return error;
+}
+
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+int
+pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)pfkey_ext;
+
+ if(!pfkey_x_nat_t_type) {
+ printk("klips_debug:pfkey_x_nat_t_type_process: "
+ "null pointer passed in\n");
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_nat_t_type_process: %d.\n",
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_nat_t_type_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_x_nat_t_type->sadb_x_nat_t_type_type) {
+ case ESPINUDP_WITH_NON_IKE: /* with Non-IKE */
+ case ESPINUDP_WITH_NON_ESP: /* with Non-ESP */
+ extr->ips->ips_natt_type = pfkey_x_nat_t_type->sadb_x_nat_t_type_type;
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_nat_t_type_process: "
+ "unknown type %d.\n",
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
+ SENDERR(EINVAL);
+ break;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)pfkey_ext;
+
+ if(!pfkey_x_nat_t_port) {
+ printk("klips_debug:pfkey_x_nat_t_port_process: "
+ "null pointer passed in\n");
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_nat_t_port_process: %d/%d.\n",
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype,
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_port);
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_nat_t_type_process: "
+ "extr or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype) {
+ case SADB_X_EXT_NAT_T_SPORT:
+ extr->ips->ips_natt_sport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
+ break;
+ case SADB_X_EXT_NAT_T_DPORT:
+ extr->ips->ips_natt_dport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_nat_t_port_process: "
+ "unknown exttype %d.\n",
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype);
+ SENDERR(EINVAL);
+ break;
+ }
+
+errlab:
+ return error;
+}
+#endif
+
+int
+pfkey_x_debug_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext;
+
+ if(!pfkey_x_debug) {
+ printk("klips_debug:pfkey_x_debug_process: "
+ "null pointer passed in\n");
+ SENDERR(EINVAL);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_debug_process: .\n");
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if(pfkey_x_debug->sadb_x_debug_netlink >>
+ (sizeof(pfkey_x_debug->sadb_x_debug_netlink) * 8 - 1)) {
+ pfkey_x_debug->sadb_x_debug_netlink &=
+ ~(1 << (sizeof(pfkey_x_debug->sadb_x_debug_netlink) * 8 -1));
+ debug_tunnel |= pfkey_x_debug->sadb_x_debug_tunnel;
+ debug_netlink |= pfkey_x_debug->sadb_x_debug_netlink;
+ debug_xform |= pfkey_x_debug->sadb_x_debug_xform;
+ debug_eroute |= pfkey_x_debug->sadb_x_debug_eroute;
+ debug_spi |= pfkey_x_debug->sadb_x_debug_spi;
+ debug_radij |= pfkey_x_debug->sadb_x_debug_radij;
+ debug_esp |= pfkey_x_debug->sadb_x_debug_esp;
+ debug_ah |= pfkey_x_debug->sadb_x_debug_ah;
+ debug_rcv |= pfkey_x_debug->sadb_x_debug_rcv;
+ debug_pfkey |= pfkey_x_debug->sadb_x_debug_pfkey;
+#ifdef CONFIG_IPSEC_IPCOMP
+ sysctl_ipsec_debug_ipcomp |= pfkey_x_debug->sadb_x_debug_ipcomp;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ sysctl_ipsec_debug_verbose |= pfkey_x_debug->sadb_x_debug_verbose;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_debug_process: "
+ "set\n");
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_debug_process: "
+ "unset\n");
+ debug_tunnel &= pfkey_x_debug->sadb_x_debug_tunnel;
+ debug_netlink &= pfkey_x_debug->sadb_x_debug_netlink;
+ debug_xform &= pfkey_x_debug->sadb_x_debug_xform;
+ debug_eroute &= pfkey_x_debug->sadb_x_debug_eroute;
+ debug_spi &= pfkey_x_debug->sadb_x_debug_spi;
+ debug_radij &= pfkey_x_debug->sadb_x_debug_radij;
+ debug_esp &= pfkey_x_debug->sadb_x_debug_esp;
+ debug_ah &= pfkey_x_debug->sadb_x_debug_ah;
+ debug_rcv &= pfkey_x_debug->sadb_x_debug_rcv;
+ debug_pfkey &= pfkey_x_debug->sadb_x_debug_pfkey;
+#ifdef CONFIG_IPSEC_IPCOMP
+ sysctl_ipsec_debug_ipcomp &= pfkey_x_debug->sadb_x_debug_ipcomp;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ sysctl_ipsec_debug_verbose &= pfkey_x_debug->sadb_x_debug_verbose;
+ }
+#else /* CONFIG_IPSEC_DEBUG */
+ printk("klips_debug:pfkey_x_debug_process: "
+ "debugging not enabled\n");
+ SENDERR(EINVAL);
+#endif /* CONFIG_IPSEC_DEBUG */
+
+errlab:
+ return error;
+}
diff --git a/linux/net/ipsec/pfkey_v2_parser.c b/linux/net/ipsec/pfkey_v2_parser.c
new file mode 100644
index 000000000..d170ddea5
--- /dev/null
+++ b/linux/net/ipsec/pfkey_v2_parser.c
@@ -0,0 +1,3420 @@
+/*
+ * @(#) RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pfkey_v2_parser.c,v 1.4 2004/09/29 22:27:41 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_netlink.c.
+ */
+
+char pfkey_v2_parser_c_version[] = "$Id: pfkey_v2_parser.c,v 1.4 2004/09/29 22:27:41 as Exp $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+
+#include <freeswan.h>
+
+#include <crypto/des.h>
+
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+# include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+# include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define ip_chk_addr inet_addr_type
+# define IS_MYADDR RTN_LOCAL
+#endif
+#include <asm/checksum.h>
+#include <net/ip.h>
+#ifdef NETLINK_SOCK
+# include <linux/netlink.h>
+#else
+# include <net/netlink.h>
+#endif
+
+#include <linux/random.h> /* get_random_bytes() */
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_sa.h"
+
+#include "freeswan/ipsec_radij.h"
+#include "freeswan/ipsec_xform.h"
+#include "freeswan/ipsec_ah.h"
+#include "freeswan/ipsec_esp.h"
+#include "freeswan/ipsec_tunnel.h"
+#include "freeswan/ipsec_rcv.h"
+#include "freeswan/ipcomp.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/ipsec_proto.h"
+#include "freeswan/ipsec_alg.h"
+
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+struct sklist_t {
+ struct socket *sk;
+ struct sklist_t* next;
+} pfkey_sklist_head, *pfkey_sklist, *pfkey_sklist_prev;
+
+__u32 pfkey_msg_seq = 0;
+
+int
+pfkey_alloc_eroute(struct eroute** eroute)
+{
+ int error = 0;
+ if(*eroute) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_alloc_eroute: "
+ "eroute struct already allocated\n");
+ SENDERR(EEXIST);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_alloc_eroute: "
+ "allocating %lu bytes for an eroute.\n",
+ (unsigned long) sizeof(**eroute));
+ if((*eroute = kmalloc(sizeof(**eroute), GFP_ATOMIC) ) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_alloc_eroute: "
+ "memory allocation error\n");
+ SENDERR(ENOMEM);
+ }
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_alloc_eroute: "
+ "allocated eroute struct=0p%p.\n", eroute);
+ memset((caddr_t)*eroute, 0, sizeof(**eroute));
+ (*eroute)->er_eaddr.sen_len =
+ (*eroute)->er_emask.sen_len = sizeof(struct sockaddr_encap);
+ (*eroute)->er_eaddr.sen_family =
+ (*eroute)->er_emask.sen_family = AF_ENCAP;
+ (*eroute)->er_eaddr.sen_type = SENT_IP4;
+ (*eroute)->er_emask.sen_type = 255;
+ (*eroute)->er_pid = 0;
+ (*eroute)->er_count = 0;
+ (*eroute)->er_lasttime = jiffies/HZ;
+
+ errlab:
+ return(error);
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_protocol_process(struct sadb_ext *pfkey_ext,
+ struct pfkey_extracted_data *extr)
+{
+ int error = 0;
+ struct sadb_protocol * p = (struct sadb_protocol *)pfkey_ext;
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_protocol_process: %p\n", extr);
+
+ if (extr == 0) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_protocol_process:"
+ "extr is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+ if (extr->eroute == 0) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_protocol_process:"
+ "extr->eroute is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+ extr->eroute->er_eaddr.sen_proto = p->sadb_protocol_proto;
+ extr->eroute->er_emask.sen_proto = p->sadb_protocol_proto ? ~0:0;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_protocol_process: protocol = %d.\n",
+ p->sadb_protocol_proto);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_ipsec_sa_init(struct ipsec_sa *ipsp, struct sadb_ext **extensions)
+{
+ int error = 0;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ char ipaddr_txt[ADDRTOA_BUF];
+ char ipaddr2_txt[ADDRTOA_BUF];
+#if defined (CONFIG_IPSEC_AUTH_HMAC_MD5) || defined (CONFIG_IPSEC_AUTH_HMAC_SHA1)
+ int i;
+ unsigned char kb[AHMD596_BLKLEN];
+#endif
+#ifdef CONFIG_IPSEC_ALG
+ struct ipsec_alg_enc *ixt_e = NULL;
+ struct ipsec_alg_auth *ixt_a = NULL;
+#endif /* CONFIG_IPSEC_ALG */
+
+ if(ipsp == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "ipsp is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(ipsp->ips_said, 0, sa, SATOA_BUF);
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "(pfkey defined) called for SA:%s\n",
+ sa_len ? sa : " (error)");
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "calling init routine of %s%s%s\n",
+ IPS_XFORM_NAME(ipsp));
+
+ switch(ipsp->ips_said.proto) {
+
+#ifdef CONFIG_IPSEC_IPIP
+ case IPPROTO_IPIP: {
+ addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_s))->sin_addr,
+ 0,
+ ipaddr_txt, sizeof(ipaddr_txt));
+ addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr,
+ 0,
+ ipaddr2_txt, sizeof(ipaddr_txt));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "(pfkey defined) IPIP ipsec_sa set for %s->%s.\n",
+ ipaddr_txt,
+ ipaddr2_txt);
+ }
+ break;
+#endif /* !CONFIG_IPSEC_IPIP */
+#ifdef CONFIG_IPSEC_AH
+ case IPPROTO_AH:
+ switch(ipsp->ips_authalg) {
+# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5: {
+ unsigned char *akp;
+ unsigned int aks;
+ MD5_CTX *ictx;
+ MD5_CTX *octx;
+
+ if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_a, AHMD596_KLEN * 8);
+ SENDERR(EINVAL);
+ }
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "hmac md5-96 key is 0x%08x %08x %08x %08x\n",
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+
+ ipsp->ips_auth_bits = AHMD596_ALEN * 8;
+
+ /* save the pointer to the key material */
+ akp = ipsp->ips_key_a;
+ aks = ipsp->ips_key_a_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for md5_ctx.\n",
+ (unsigned long) sizeof(struct md5_ctx));
+ if((ipsp->ips_key_a = (caddr_t)
+ kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_a = akp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_a_size = sizeof(struct md5_ctx);
+
+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
+ kb[i] = akp[i] ^ HMAC_IPAD;
+ }
+ for (; i < AHMD596_BLKLEN; i++) {
+ kb[i] = HMAC_IPAD;
+ }
+
+ ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx);
+ MD5Init(ictx);
+ MD5Update(ictx, kb, AHMD596_BLKLEN);
+
+ for (i = 0; i < AHMD596_BLKLEN; i++) {
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
+ }
+
+ octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx);
+ MD5Init(octx);
+ MD5Update(octx, kb, AHMD596_BLKLEN);
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
+ ((__u32*)ictx)[0],
+ ((__u32*)ictx)[1],
+ ((__u32*)ictx)[2],
+ ((__u32*)ictx)[3],
+ ((__u32*)octx)[0],
+ ((__u32*)octx)[1],
+ ((__u32*)octx)[2],
+ ((__u32*)octx)[3] );
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+
+ /* zero key buffer -- paranoid */
+ memset(akp, 0, aks);
+ kfree(akp);
+ }
+ break;
+# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA: {
+ unsigned char *akp;
+ unsigned int aks;
+ SHA1_CTX *ictx;
+ SHA1_CTX *octx;
+
+ if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_a, AHSHA196_KLEN * 8);
+ SENDERR(EINVAL);
+ }
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+
+ ipsp->ips_auth_bits = AHSHA196_ALEN * 8;
+
+ /* save the pointer to the key material */
+ akp = ipsp->ips_key_a;
+ aks = ipsp->ips_key_a_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for sha1_ctx.\n",
+ (unsigned long) sizeof(struct sha1_ctx));
+ if((ipsp->ips_key_a = (caddr_t)
+ kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_a = akp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_a_size = sizeof(struct sha1_ctx);
+
+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
+ kb[i] = akp[i] ^ HMAC_IPAD;
+ }
+ for (; i < AHMD596_BLKLEN; i++) {
+ kb[i] = HMAC_IPAD;
+ }
+
+ ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx);
+ SHA1Init(ictx);
+ SHA1Update(ictx, kb, AHSHA196_BLKLEN);
+
+ for (i = 0; i < AHSHA196_BLKLEN; i++) {
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
+ }
+
+ octx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->octx);
+ SHA1Init(octx);
+ SHA1Update(octx, kb, AHSHA196_BLKLEN);
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
+ ((__u32*)ictx)[0],
+ ((__u32*)ictx)[1],
+ ((__u32*)ictx)[2],
+ ((__u32*)ictx)[3],
+ ((__u32*)octx)[0],
+ ((__u32*)octx)[1],
+ ((__u32*)octx)[2],
+ ((__u32*)octx)[3] );
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ /* zero key buffer -- paranoid */
+ memset(akp, 0, aks);
+ kfree(akp);
+ }
+ break;
+# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "authalg=%d support not available in the kernel",
+ ipsp->ips_authalg);
+ SENDERR(EINVAL);
+ }
+ break;
+#endif /* CONFIG_IPSEC_AH */
+#ifdef CONFIG_IPSEC_ESP
+ case IPPROTO_ESP: {
+#if defined (CONFIG_IPSEC_AUTH_HMAC_MD5) || defined (CONFIG_IPSEC_AUTH_HMAC_SHA1)
+ unsigned char *akp;
+ unsigned int aks;
+#endif
+#if defined (CONFIG_IPSEC_ENC_3DES)
+ unsigned char *ekp;
+ unsigned int eks;
+#endif
+
+ ipsp->ips_iv_size = 0;
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_e=ipsp->ips_alg_enc)) {
+ ipsp->ips_iv_size = ixt_e->ixt_ivlen/8;
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ipsp->ips_encalg) {
+# ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+# endif /* CONFIG_IPSEC_ENC_3DES */
+# if defined(CONFIG_IPSEC_ENC_3DES)
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %u bytes for iv.\n",
+ EMT_ESPDES_IV_SZ);
+ if((ipsp->ips_iv = (caddr_t)
+ kmalloc((ipsp->ips_iv_size = EMT_ESPDES_IV_SZ), GFP_ATOMIC)) == NULL) {
+ SENDERR(ENOMEM);
+ }
+ prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv, EMT_ESPDES_IV_SZ);
+ ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
+ ipsp->ips_iv_size = EMT_ESPDES_IV_SZ;
+ break;
+# endif /* defined(CONFIG_IPSEC_ENC_3DES) */
+ case ESP_NONE:
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "encalg=%d support not available in the kernel",
+ ipsp->ips_encalg);
+ SENDERR(EINVAL);
+ }
+
+ /* Create IV */
+ if (ipsp->ips_iv_size) {
+ if((ipsp->ips_iv = (caddr_t)
+ kmalloc(ipsp->ips_iv_size, GFP_ATOMIC)) == NULL) {
+ SENDERR(ENOMEM);
+ }
+ prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv, ipsp->ips_iv_size);
+ ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if (ixt_e) {
+ if ((error=ipsec_alg_enc_key_create(ipsp)) < 0)
+ SENDERR(-error);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+ switch(ipsp->ips_encalg) {
+# ifdef CONFIG_IPSEC_ENC_3DES
+ case ESP_3DES:
+ if(ipsp->ips_key_bits_e != (EMT_ESP3DES_KEY_SZ * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect encryption key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_e, EMT_ESP3DES_KEY_SZ * 8);
+ SENDERR(EINVAL);
+ }
+
+ /* save encryption key pointer */
+ ekp = ipsp->ips_key_e;
+ eks = ipsp->ips_key_e_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for 3des.\n",
+ (unsigned long) (3 * sizeof(struct des_eks)));
+ if((ipsp->ips_key_e = (caddr_t)
+ kmalloc(3 * sizeof(struct des_eks), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_e = ekp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_e_size = 3 * sizeof(struct des_eks);
+
+ for(i = 0; i < 3; i++) {
+#if KLIPS_DIVULGE_CYPHER_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "3des key %d/3 is 0x%08x%08x\n",
+ i + 1,
+ ntohl(*((__u32 *)ekp + i * 2)),
+ ntohl(*((__u32 *)ekp + i * 2 + 1)));
+# endif
+#if KLIPS_FIXES_DES_PARITY
+ /* force parity */
+ des_set_odd_parity((des_cblock *)(ekp + EMT_ESPDES_KEY_SZ * i));
+#endif
+ error = des_set_key((des_cblock *)(ekp + EMT_ESPDES_KEY_SZ * i),
+ ((struct des_eks *)(ipsp->ips_key_e))[i].ks);
+ if (error == -1)
+ printk("klips_debug:pfkey_ipsec_sa_init: "
+ "parity error in des key %d/3\n",
+ i + 1);
+ else if (error == -2)
+ printk("klips_debug:pfkey_ipsec_sa_init: "
+ "illegal weak des key %d/3\n", i + 1);
+ if (error) {
+ memset(ekp, 0, eks);
+ kfree(ekp);
+ SENDERR(EINVAL);
+ }
+ }
+
+ /* paranoid */
+ memset(ekp, 0, eks);
+ kfree(ekp);
+ break;
+# endif /* CONFIG_IPSEC_ENC_3DES */
+ case ESP_NONE:
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "encalg=%d support not available in the kernel",
+ ipsp->ips_encalg);
+ SENDERR(EINVAL);
+ }
+
+#ifdef CONFIG_IPSEC_ALG
+ if ((ixt_a=ipsp->ips_alg_auth)) {
+ if ((error=ipsec_alg_auth_key_create(ipsp)) < 0)
+ SENDERR(-error);
+ } else
+#endif /* CONFIG_IPSEC_ALG */
+
+ switch(ipsp->ips_authalg) {
+# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5: {
+ MD5_CTX *ictx;
+ MD5_CTX *octx;
+
+ if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_a,
+ AHMD596_KLEN * 8);
+ SENDERR(EINVAL);
+ }
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "hmac md5-96 key is 0x%08x %08x %08x %08x\n",
+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+0)),
+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+1)),
+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+2)),
+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+3)));
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ ipsp->ips_auth_bits = AHMD596_ALEN * 8;
+
+ /* save the pointer to the key material */
+ akp = ipsp->ips_key_a;
+ aks = ipsp->ips_key_a_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for md5_ctx.\n",
+ (unsigned long) sizeof(struct md5_ctx));
+ if((ipsp->ips_key_a = (caddr_t)
+ kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_a = akp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_a_size = sizeof(struct md5_ctx);
+
+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
+ kb[i] = akp[i] ^ HMAC_IPAD;
+ }
+ for (; i < AHMD596_BLKLEN; i++) {
+ kb[i] = HMAC_IPAD;
+ }
+
+ ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx);
+ MD5Init(ictx);
+ MD5Update(ictx, kb, AHMD596_BLKLEN);
+
+ for (i = 0; i < AHMD596_BLKLEN; i++) {
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
+ }
+
+ octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx);
+ MD5Init(octx);
+ MD5Update(octx, kb, AHMD596_BLKLEN);
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
+ ((__u32*)ictx)[0],
+ ((__u32*)ictx)[1],
+ ((__u32*)ictx)[2],
+ ((__u32*)ictx)[3],
+ ((__u32*)octx)[0],
+ ((__u32*)octx)[1],
+ ((__u32*)octx)[2],
+ ((__u32*)octx)[3] );
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ /* paranoid */
+ memset(akp, 0, aks);
+ kfree(akp);
+ break;
+ }
+# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
+ case AH_SHA: {
+ SHA1_CTX *ictx;
+ SHA1_CTX *octx;
+
+ if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
+ ipsp->ips_key_bits_a,
+ AHSHA196_KLEN * 8);
+ SENDERR(EINVAL);
+ }
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
+ ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ ipsp->ips_auth_bits = AHSHA196_ALEN * 8;
+
+ /* save the pointer to the key material */
+ akp = ipsp->ips_key_a;
+ aks = ipsp->ips_key_a_size;
+
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "allocating %lu bytes for sha1_ctx.\n",
+ (unsigned long) sizeof(struct sha1_ctx));
+ if((ipsp->ips_key_a = (caddr_t)
+ kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) {
+ ipsp->ips_key_a = akp;
+ SENDERR(ENOMEM);
+ }
+ ipsp->ips_key_a_size = sizeof(struct sha1_ctx);
+
+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
+ kb[i] = akp[i] ^ HMAC_IPAD;
+ }
+ for (; i < AHMD596_BLKLEN; i++) {
+ kb[i] = HMAC_IPAD;
+ }
+
+ ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx);
+ SHA1Init(ictx);
+ SHA1Update(ictx, kb, AHSHA196_BLKLEN);
+
+ for (i = 0; i < AHSHA196_BLKLEN; i++) {
+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
+ }
+
+ octx = &((struct sha1_ctx*)(ipsp->ips_key_a))->octx;
+ SHA1Init(octx);
+ SHA1Update(octx, kb, AHSHA196_BLKLEN);
+
+# if KLIPS_DIVULGE_HMAC_KEY
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
+ ((__u32*)ictx)[0],
+ ((__u32*)ictx)[1],
+ ((__u32*)ictx)[2],
+ ((__u32*)ictx)[3],
+ ((__u32*)octx)[0],
+ ((__u32*)octx)[1],
+ ((__u32*)octx)[2],
+ ((__u32*)octx)[3] );
+# endif /* KLIPS_DIVULGE_HMAC_KEY */
+ memset(akp, 0, aks);
+ kfree(akp);
+ break;
+ }
+# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+ case AH_NONE:
+ break;
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "authalg=%d support not available in the kernel.\n",
+ ipsp->ips_authalg);
+ SENDERR(EINVAL);
+ }
+ }
+ break;
+#endif /* !CONFIG_IPSEC_ESP */
+#ifdef CONFIG_IPSEC_IPCOMP
+ case IPPROTO_COMP:
+ ipsp->ips_comp_adapt_tries = 0;
+ ipsp->ips_comp_adapt_skip = 0;
+ ipsp->ips_comp_ratio_cbytes = 0;
+ ipsp->ips_comp_ratio_dbytes = 0;
+ break;
+#endif /* CONFIG_IPSEC_IPCOMP */
+ default:
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_ipsec_sa_init: "
+ "proto=%d unknown.\n",
+ ipsp->ips_said.proto);
+ SENDERR(EINVAL);
+ }
+
+ errlab:
+ return(error);
+}
+
+
+int
+pfkey_safe_build(int error, struct sadb_ext *extensions[SADB_MAX+1])
+{
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build: "
+ "error=%d\n",
+ error);
+ if (!error) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:"
+ "success.\n");
+ return 1;
+ } else {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:"
+ "caught error %d\n",
+ error);
+ pfkey_extensions_free(extensions);
+ return 0;
+ }
+}
+
+
+DEBUG_NO_STATIC int
+pfkey_getspi_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ ipsec_spi_t minspi = htonl(256), maxspi = htonl(-1L);
+ int found_avail = 0;
+ struct ipsec_sa *ipsq;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(extr == NULL || extr->ips == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "error, extr or extr->ipsec_sa pointer NULL\n");
+ SENDERR(EINVAL);
+ }
+
+ if(extensions[SADB_EXT_SPIRANGE]) {
+ minspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_min;
+ maxspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_max;
+ }
+
+ if(maxspi == minspi) {
+ extr->ips->ips_said.spi = maxspi;
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ipsq != NULL) {
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+ ipsec_sa_put(ipsq);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "EMT_GETSPI found an old ipsec_sa for SA: %s, delete it first.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(EEXIST);
+ } else {
+ found_avail = 1;
+ }
+ } else {
+ int i = 0;
+ __u32 rand_val;
+ __u32 spi_diff;
+ while( ( i < (spi_diff = (ntohl(maxspi) - ntohl(minspi)))) && !found_avail ) {
+ prng_bytes(&ipsec_prng, (char *) &(rand_val),
+ ( (spi_diff < (2^8)) ? 1 :
+ ( (spi_diff < (2^16)) ? 2 :
+ ( (spi_diff < (2^24)) ? 3 :
+ 4 ) ) ) );
+ extr->ips->ips_said.spi = htonl(ntohl(minspi) +
+ (rand_val %
+ (spi_diff + 1)));
+ i++;
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ipsq == NULL) {
+ found_avail = 1;
+ } else {
+ ipsec_sa_put(ipsq);
+ }
+ }
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ if (!found_avail) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "found an old ipsec_sa for SA: %s, delete it first.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(EEXIST);
+ }
+
+ if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) {
+ extr->ips->ips_flags |= EMT_INBOUND;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "existing ipsec_sa not found (this is good) for SA: %s, %s-bound, allocating.\n",
+ sa_len ? sa : " (error)",
+ extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
+
+ /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
+ extr->ips->ips_rcvif = NULL;
+ extr->ips->ips_life.ipl_addtime.ipl_count = jiffies/HZ;
+
+ extr->ips->ips_state = SADB_SASTATE_LARVAL;
+
+ if(!extr->ips->ips_life.ipl_allocations.ipl_count) {
+ extr->ips->ips_life.ipl_allocations.ipl_count += 1;
+ }
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_GETSPI,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ 0,
+ SADB_SASTATE_LARVAL,
+ 0,
+ 0,
+ 0,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply) )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "failed to build the getspi reply message extensions\n");
+ goto errlab;
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "failed to build the getspi reply message\n");
+ SENDERR(-error);
+ }
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "sending up getspi reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "sending up getspi reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ if((error = ipsec_sa_add(extr->ips))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
+ "failed to add the larval SA=%s with error=%d.\n",
+ sa_len ? sa : " (error)",
+ error);
+ SENDERR(-error);
+ }
+ extr->ips = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_getspi_parse: "
+ "successful for SA: %s\n",
+ sa_len ? sa : " (error)");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_update_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct ipsec_sa* ipsq;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ struct ipsec_sa *nat_t_ips_saved = NULL;
+#endif
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != SADB_SASTATE_MATURE) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "error, sa_state=%d must be MATURE=%d\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
+ SADB_SASTATE_MATURE);
+ SENDERR(EINVAL);
+ }
+
+ if(extr == NULL || extr->ips == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "error, extr or extr->ips pointer NULL\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ spin_lock_bh(&tdb_lock);
+
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if (ipsq == NULL) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "reserved ipsec_sa for SA: %s not found. Call SADB_GETSPI first or call SADB_ADD instead.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(ENOENT);
+ }
+
+ if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) {
+ extr->ips->ips_flags |= EMT_INBOUND;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "existing ipsec_sa found (this is good) for SA: %s, %s-bound, updating.\n",
+ sa_len ? sa : " (error)",
+ extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (extr->ips->ips_natt_sport || extr->ips->ips_natt_dport) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: only updating NAT-T ports "
+ "(%u:%u -> %u:%u)\n",
+ ipsq->ips_natt_sport, ipsq->ips_natt_dport,
+ extr->ips->ips_natt_sport, extr->ips->ips_natt_dport);
+
+ if (extr->ips->ips_natt_sport) {
+ ipsq->ips_natt_sport = extr->ips->ips_natt_sport;
+ if (ipsq->ips_addr_s->sa_family == AF_INET) {
+ ((struct sockaddr_in *)(ipsq->ips_addr_s))->sin_port = htons(extr->ips->ips_natt_sport);
+ }
+ }
+
+ if (extr->ips->ips_natt_dport) {
+ ipsq->ips_natt_dport = extr->ips->ips_natt_dport;
+ if (ipsq->ips_addr_d->sa_family == AF_INET) {
+ ((struct sockaddr_in *)(ipsq->ips_addr_d))->sin_port = htons(extr->ips->ips_natt_dport);
+ }
+ }
+
+ nat_t_ips_saved = extr->ips;
+ extr->ips = ipsq;
+ }
+ else {
+#endif
+
+ /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
+ extr->ips->ips_rcvif = NULL;
+ if ((error = pfkey_ipsec_sa_init(extr->ips, extensions))) {
+ ipsec_sa_put(ipsq);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "not successful for SA: %s, deleting.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(-error);
+ }
+
+ extr->ips->ips_life.ipl_addtime.ipl_count = ipsq->ips_life.ipl_addtime.ipl_count;
+ ipsec_sa_put(ipsq);
+ if((error = ipsec_sa_delchain(ipsq))) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "error=%d, trouble deleting intermediate ipsec_sa for SA=%s.\n",
+ error,
+ sa_len ? sa : " (error)");
+ SENDERR(-error);
+ }
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ }
+#endif
+
+ spin_unlock_bh(&tdb_lock);
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_UPDATE,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ /* The 3 lifetime extentions should only be sent if non-zero. */
+ && (extensions[SADB_EXT_LIFETIME_HARD]
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD],
+ SADB_EXT_LIFETIME_HARD,
+ extr->ips->ips_life.ipl_allocations.ipl_hard,
+ extr->ips->ips_life.ipl_bytes.ipl_hard,
+ extr->ips->ips_life.ipl_addtime.ipl_hard,
+ extr->ips->ips_life.ipl_usetime.ipl_hard,
+ extr->ips->ips_life.ipl_packets.ipl_hard),
+ extensions_reply) : 1)
+ && (extensions[SADB_EXT_LIFETIME_SOFT]
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT],
+ SADB_EXT_LIFETIME_SOFT,
+ extr->ips->ips_life.ipl_allocations.ipl_count,
+ extr->ips->ips_life.ipl_bytes.ipl_count,
+ extr->ips->ips_life.ipl_addtime.ipl_count,
+ extr->ips->ips_life.ipl_usetime.ipl_count,
+ extr->ips->ips_life.ipl_packets.ipl_count),
+ extensions_reply) : 1)
+ && (extr->ips->ips_life.ipl_allocations.ipl_count
+ || extr->ips->ips_life.ipl_bytes.ipl_count
+ || extr->ips->ips_life.ipl_addtime.ipl_count
+ || extr->ips->ips_life.ipl_usetime.ipl_count
+ || extr->ips->ips_life.ipl_packets.ipl_count
+
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_CURRENT],
+ SADB_EXT_LIFETIME_CURRENT,
+ extr->ips->ips_life.ipl_allocations.ipl_count,
+ extr->ips->ips_life.ipl_bytes.ipl_count,
+ extr->ips->ips_life.ipl_addtime.ipl_count,
+ extr->ips->ips_life.ipl_usetime.ipl_count,
+ extr->ips->ips_life.ipl_packets.ipl_count),
+ extensions_reply) : 1)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ && (extr->ips->ips_ident_s.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC],
+ SADB_EXT_IDENTITY_SRC,
+ extr->ips->ips_ident_s.type,
+ extr->ips->ips_ident_s.id,
+ extr->ips->ips_ident_s.len,
+ extr->ips->ips_ident_s.data),
+ extensions_reply) : 1)
+ && (extr->ips->ips_ident_d.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST],
+ SADB_EXT_IDENTITY_DST,
+ extr->ips->ips_ident_d.type,
+ extr->ips->ips_ident_d.id,
+ extr->ips->ips_ident_d.len,
+ extr->ips->ips_ident_d.data),
+ extensions_reply) : 1)
+#if 0
+ /* FIXME: This won't work yet because I have not finished
+ it. */
+ && (extr->ips->ips_sens_
+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY],
+ extr->ips->ips_sens_dpd,
+ extr->ips->ips_sens_sens_level,
+ extr->ips->ips_sens_sens_len,
+ extr->ips->ips_sens_sens_bitmap,
+ extr->ips->ips_sens_integ_level,
+ extr->ips->ips_sens_integ_len,
+ extr->ips->ips_sens_integ_bitmap),
+ extensions_reply) : 1)
+#endif
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "failed to build the update reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "failed to build the update reply message\n");
+ SENDERR(-error);
+ }
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "sending up update reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "sending up update reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ if (nat_t_ips_saved) {
+ /**
+ * As we _really_ update existing SA, we keep tdbq and need to delete
+ * parsed ips (nat_t_ips_saved, was extr->ips).
+ *
+ * goto errlab with extr->ips = nat_t_ips_saved will free it.
+ */
+
+ extr->ips = nat_t_ips_saved;
+
+ error = 0;
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse (NAT-T ports): "
+ "successful for SA: %s\n",
+ sa_len ? sa : " (error)");
+
+ goto errlab;
+ }
+#endif
+
+ if((error = ipsec_sa_add(extr->ips))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
+ "failed to update the mature SA=%s with error=%d.\n",
+ sa_len ? sa : " (error)",
+ error);
+ SENDERR(-error);
+ }
+ extr->ips = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_update_parse: "
+ "successful for SA: %s\n",
+ sa_len ? sa : " (error)");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_add_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct ipsec_sa* ipsq;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != SADB_SASTATE_MATURE) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "error, sa_state=%d must be MATURE=%d\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
+ SADB_SASTATE_MATURE);
+ SENDERR(EINVAL);
+ }
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "extr or extr->ips pointer NULL\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ipsq != NULL) {
+ ipsec_sa_put(ipsq);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "found an old ipsec_sa for SA%s, delete it first.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(EEXIST);
+ }
+
+ if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) {
+ extr->ips->ips_flags |= EMT_INBOUND;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "existing ipsec_sa not found (this is good) for SA%s, %s-bound, allocating.\n",
+ sa_len ? sa : " (error)",
+ extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
+
+ /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
+ extr->ips->ips_rcvif = NULL;
+
+ if ((error = pfkey_ipsec_sa_init(extr->ips, extensions))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "not successful for SA: %s, deleting.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(-error);
+ }
+
+ extr->ips->ips_life.ipl_addtime.ipl_count = jiffies / HZ;
+ if(!extr->ips->ips_life.ipl_allocations.ipl_count) {
+ extr->ips->ips_life.ipl_allocations.ipl_count += 1;
+ }
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_ADD,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ /* The 3 lifetime extentions should only be sent if non-zero. */
+ && (extensions[SADB_EXT_LIFETIME_HARD]
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD],
+ SADB_EXT_LIFETIME_HARD,
+ extr->ips->ips_life.ipl_allocations.ipl_hard,
+ extr->ips->ips_life.ipl_bytes.ipl_hard,
+ extr->ips->ips_life.ipl_addtime.ipl_hard,
+ extr->ips->ips_life.ipl_usetime.ipl_hard,
+ extr->ips->ips_life.ipl_packets.ipl_hard),
+ extensions_reply) : 1)
+ && (extensions[SADB_EXT_LIFETIME_SOFT]
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT],
+ SADB_EXT_LIFETIME_SOFT,
+ extr->ips->ips_life.ipl_allocations.ipl_soft,
+ extr->ips->ips_life.ipl_bytes.ipl_soft,
+ extr->ips->ips_life.ipl_addtime.ipl_soft,
+ extr->ips->ips_life.ipl_usetime.ipl_soft,
+ extr->ips->ips_life.ipl_packets.ipl_soft),
+ extensions_reply) : 1)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ && (extr->ips->ips_ident_s.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC],
+ SADB_EXT_IDENTITY_SRC,
+ extr->ips->ips_ident_s.type,
+ extr->ips->ips_ident_s.id,
+ extr->ips->ips_ident_s.len,
+ extr->ips->ips_ident_s.data),
+ extensions_reply) : 1)
+ && (extr->ips->ips_ident_d.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST],
+ SADB_EXT_IDENTITY_DST,
+ extr->ips->ips_ident_d.type,
+ extr->ips->ips_ident_d.id,
+ extr->ips->ips_ident_d.len,
+ extr->ips->ips_ident_d.data),
+ extensions_reply) : 1)
+#if 0
+ /* FIXME: This won't work yet because I have not finished
+ it. */
+ && (extr->ips->ips_sens_
+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY],
+ extr->ips->ips_sens_dpd,
+ extr->ips->ips_sens_sens_level,
+ extr->ips->ips_sens_sens_len,
+ extr->ips->ips_sens_sens_bitmap,
+ extr->ips->ips_sens_integ_level,
+ extr->ips->ips_sens_integ_len,
+ extr->ips->ips_sens_integ_bitmap),
+ extensions_reply) : 1)
+#endif
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "failed to build the add reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "failed to build the add reply message\n");
+ SENDERR(-error);
+ }
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "sending up add reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "sending up add reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ if((error = ipsec_sa_add(extr->ips))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
+ "failed to add the mature SA=%s with error=%d.\n",
+ sa_len ? sa : " (error)",
+ error);
+ SENDERR(-error);
+ }
+ extr->ips = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_add_parse: "
+ "successful for SA: %s\n",
+ sa_len ? sa : " (error)");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_delete_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ struct ipsec_sa *ipsp;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ int error = 0;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_delete_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_delete_parse: "
+ "extr or extr->ips pointer NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ spin_lock_bh(&tdb_lock);
+
+ ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if (ipsp == NULL) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_delete_parse: "
+ "ipsec_sa not found for SA:%s, could not delete.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(ESRCH);
+ }
+
+ ipsec_sa_put(ipsp);
+ if((error = ipsec_sa_delchain(ipsp))) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_delete_parse: "
+ "error=%d returned trying to delete ipsec_sa for SA:%s.\n",
+ error,
+ sa_len ? sa : " (error)");
+ SENDERR(-error);
+ }
+ spin_unlock_bh(&tdb_lock);
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_DELETE,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
+ "failed to build the delete reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
+ "failed to build the delete reply message\n");
+ SENDERR(-error);
+ }
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
+ "sending up delete reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
+ "sending up delete reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_get_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct ipsec_sa *ipsp;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_get_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_get_parse: "
+ "extr or extr->ips pointer NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ spin_lock_bh(&tdb_lock);
+
+ ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if (ipsp == NULL) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "ipsec_sa not found for SA=%s, could not get.\n",
+ sa_len ? sa : " (error)");
+ SENDERR(ESRCH);
+ }
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_GET,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ /* The 3 lifetime extentions should only be sent if non-zero. */
+ && (ipsp->ips_life.ipl_allocations.ipl_count
+ || ipsp->ips_life.ipl_bytes.ipl_count
+ || ipsp->ips_life.ipl_addtime.ipl_count
+ || ipsp->ips_life.ipl_usetime.ipl_count
+ || ipsp->ips_life.ipl_packets.ipl_count
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_CURRENT],
+ SADB_EXT_LIFETIME_CURRENT,
+ ipsp->ips_life.ipl_allocations.ipl_count,
+ ipsp->ips_life.ipl_bytes.ipl_count,
+ ipsp->ips_life.ipl_addtime.ipl_count,
+ ipsp->ips_life.ipl_usetime.ipl_count,
+ ipsp->ips_life.ipl_packets.ipl_count),
+ extensions_reply) : 1)
+ && (ipsp->ips_life.ipl_allocations.ipl_hard
+ || ipsp->ips_life.ipl_bytes.ipl_hard
+ || ipsp->ips_life.ipl_addtime.ipl_hard
+ || ipsp->ips_life.ipl_usetime.ipl_hard
+ || ipsp->ips_life.ipl_packets.ipl_hard
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD],
+ SADB_EXT_LIFETIME_HARD,
+ ipsp->ips_life.ipl_allocations.ipl_hard,
+ ipsp->ips_life.ipl_bytes.ipl_hard,
+ ipsp->ips_life.ipl_addtime.ipl_hard,
+ ipsp->ips_life.ipl_usetime.ipl_hard,
+ ipsp->ips_life.ipl_packets.ipl_hard),
+ extensions_reply) : 1)
+ && (ipsp->ips_life.ipl_allocations.ipl_soft
+ || ipsp->ips_life.ipl_bytes.ipl_soft
+ || ipsp->ips_life.ipl_addtime.ipl_soft
+ || ipsp->ips_life.ipl_usetime.ipl_soft
+ || ipsp->ips_life.ipl_packets.ipl_soft
+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT],
+ SADB_EXT_LIFETIME_SOFT,
+ ipsp->ips_life.ipl_allocations.ipl_soft,
+ ipsp->ips_life.ipl_bytes.ipl_soft,
+ ipsp->ips_life.ipl_addtime.ipl_soft,
+ ipsp->ips_life.ipl_usetime.ipl_soft,
+ ipsp->ips_life.ipl_packets.ipl_soft),
+ extensions_reply) : 1)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ && (extr->ips->ips_addr_p
+ ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_PROXY],
+ SADB_EXT_ADDRESS_PROXY,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_p),
+ extensions_reply) : 1)
+#if 0
+ /* FIXME: This won't work yet because the keys are not
+ stored directly in the ipsec_sa. They are stored as
+ contexts. */
+ && (extr->ips->ips_key_a_size
+ ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[SADB_EXT_KEY_AUTH],
+ SADB_EXT_KEY_AUTH,
+ extr->ips->ips_key_a_size * 8,
+ extr->ips->ips_key_a),
+ extensions_reply) : 1)
+ /* FIXME: This won't work yet because the keys are not
+ stored directly in the ipsec_sa. They are stored as
+ key schedules. */
+ && (extr->ips->ips_key_e_size
+ ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[SADB_EXT_KEY_ENCRYPT],
+ SADB_EXT_KEY_ENCRYPT,
+ extr->ips->ips_key_e_size * 8,
+ extr->ips->ips_key_e),
+ extensions_reply) : 1)
+#endif
+ && (extr->ips->ips_ident_s.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC],
+ SADB_EXT_IDENTITY_SRC,
+ extr->ips->ips_ident_s.type,
+ extr->ips->ips_ident_s.id,
+ extr->ips->ips_ident_s.len,
+ extr->ips->ips_ident_s.data),
+ extensions_reply) : 1)
+ && (extr->ips->ips_ident_d.data
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST],
+ SADB_EXT_IDENTITY_DST,
+ extr->ips->ips_ident_d.type,
+ extr->ips->ips_ident_d.id,
+ extr->ips->ips_ident_d.len,
+ extr->ips->ips_ident_d.data),
+ extensions_reply) : 1)
+#if 0
+ /* FIXME: This won't work yet because I have not finished
+ it. */
+ && (extr->ips->ips_sens_
+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY],
+ extr->ips->ips_sens_dpd,
+ extr->ips->ips_sens_sens_level,
+ extr->ips->ips_sens_sens_len,
+ extr->ips->ips_sens_sens_bitmap,
+ extr->ips->ips_sens_integ_level,
+ extr->ips->ips_sens_integ_len,
+ extr->ips->ips_sens_integ_bitmap),
+ extensions_reply) : 1)
+#endif
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "failed to build the get reply message extensions\n");
+ ipsec_sa_put(ipsp);
+ spin_unlock_bh(&tdb_lock);
+ SENDERR(-error);
+ }
+
+ ipsec_sa_put(ipsp);
+ spin_unlock_bh(&tdb_lock);
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "failed to build the get reply message\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_upmsg(sk->socket, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "failed to send the get reply message\n");
+ SENDERR(-error);
+ }
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
+ "succeeded in sending get reply message.\n");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_acquire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_acquire_parse: .\n");
+
+ /* XXX I don't know if we want an upper bound, since userspace may
+ want to register itself for an satype > SADB_SATYPE_MAX. */
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_acquire_parse: "
+ "SATYPE=%d invalid.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+
+ if(!(pfkey_registered_sockets[satype])) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
+ "no sockets registered for SAtype=%d(%s).\n",
+ satype,
+ satype2name(satype));
+ SENDERR(EPROTONOSUPPORT);
+ }
+
+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
+ "sending up acquire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
+ "sending up acquire reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_register_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_parse: .\n");
+
+ /* XXX I don't know if we want an upper bound, since userspace may
+ want to register itself for an satype > SADB_SATYPE_MAX. */
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_parse: "
+ "SATYPE=%d invalid.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_list_insert_socket(sk->socket,
+ &(pfkey_registered_sockets[satype]))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_parse: "
+ "SATYPE=%02d(%s) successfully registered by KMd (pid=%d).\n",
+ satype,
+ satype2name(satype),
+ key_pid(sk));
+ };
+
+ /* send up register msg with supported SATYPE algos */
+
+ error=pfkey_register_reply(satype, (struct sadb_msg*)extensions[SADB_EXT_RESERVED]);
+ errlab:
+ return error;
+}
+int
+pfkey_register_reply(int satype, struct sadb_msg *sadb_msg)
+{
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ struct supported_list *pfkey_supported_listp;
+ unsigned int alg_num_a = 0, alg_num_e = 0;
+ struct sadb_alg *alg_a = NULL, *alg_e = NULL, *alg_ap = NULL, *alg_ep = NULL;
+ int error = 0;
+
+ pfkey_extensions_init(extensions_reply);
+
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "SAtype=%d unspecified or unknown.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+ if(!(pfkey_registered_sockets[satype])) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "no sockets registered for SAtype=%d(%s).\n",
+ satype,
+ satype2name(satype));
+ SENDERR(EPROTONOSUPPORT);
+ }
+ /* send up register msg with supported SATYPE algos */
+ pfkey_supported_listp = pfkey_supported_list[satype];
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "pfkey_supported_list[%d]=0p%p\n",
+ satype,
+ pfkey_supported_list[satype]);
+ while(pfkey_supported_listp) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "checking supported=0p%p\n",
+ pfkey_supported_listp);
+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_AUTH) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "adding auth alg.\n");
+ alg_num_a++;
+ }
+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_ENCRYPT) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "adding encrypt alg.\n");
+ alg_num_e++;
+ }
+ pfkey_supported_listp = pfkey_supported_listp->next;
+ }
+
+ if(alg_num_a) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "allocating %lu bytes for auth algs.\n",
+ (unsigned long) (alg_num_a * sizeof(struct sadb_alg)));
+ if((alg_a = kmalloc(alg_num_a * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "auth alg memory allocation error\n");
+ SENDERR(ENOMEM);
+ }
+ alg_ap = alg_a;
+ }
+
+ if(alg_num_e) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "allocating %lu bytes for enc algs.\n",
+ (unsigned long) (alg_num_e * sizeof(struct sadb_alg)));
+ if((alg_e = kmalloc(alg_num_e * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "enc alg memory allocation error\n");
+ SENDERR(ENOMEM);
+ }
+ alg_ep = alg_e;
+ }
+
+ pfkey_supported_listp = pfkey_supported_list[satype];
+ while(pfkey_supported_listp) {
+ if(alg_num_a) {
+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_AUTH) {
+ alg_ap->sadb_alg_id = pfkey_supported_listp->supportedp->supported_alg_id;
+ alg_ap->sadb_alg_ivlen = pfkey_supported_listp->supportedp->supported_alg_ivlen;
+ alg_ap->sadb_alg_minbits = pfkey_supported_listp->supportedp->supported_alg_minbits;
+ alg_ap->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits;
+ alg_ap->sadb_alg_reserved = 0;
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_register_reply: "
+ "adding auth=0p%p\n",
+ alg_ap);
+ alg_ap++;
+ }
+ }
+ if(alg_num_e) {
+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_ENCRYPT) {
+ alg_ep->sadb_alg_id = pfkey_supported_listp->supportedp->supported_alg_id;
+ alg_ep->sadb_alg_ivlen = pfkey_supported_listp->supportedp->supported_alg_ivlen;
+ alg_ep->sadb_alg_minbits = pfkey_supported_listp->supportedp->supported_alg_minbits;
+ alg_ep->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits;
+ alg_ep->sadb_alg_reserved = 0;
+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
+ "klips_debug:pfkey_register_reply: "
+ "adding encrypt=0p%p\n",
+ alg_ep);
+ alg_ep++;
+ }
+ }
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_register_reply: "
+ "found satype=%d(%s) exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_supported_listp->supportedp->supported_alg_exttype,
+ pfkey_supported_listp->supportedp->supported_alg_id,
+ pfkey_supported_listp->supportedp->supported_alg_ivlen,
+ pfkey_supported_listp->supportedp->supported_alg_minbits,
+ pfkey_supported_listp->supportedp->supported_alg_maxbits);
+ pfkey_supported_listp = pfkey_supported_listp->next;
+ }
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_REGISTER,
+ satype,
+ 0,
+ sadb_msg? sadb_msg->sadb_msg_seq : ++pfkey_msg_seq,
+ sadb_msg? sadb_msg->sadb_msg_pid: current->pid),
+ extensions_reply) &&
+ (alg_num_a ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[SADB_EXT_SUPPORTED_AUTH],
+ SADB_EXT_SUPPORTED_AUTH,
+ alg_num_a,
+ alg_a),
+ extensions_reply) : 1) &&
+ (alg_num_e ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[SADB_EXT_SUPPORTED_ENCRYPT],
+ SADB_EXT_SUPPORTED_ENCRYPT,
+ alg_num_e,
+ alg_e),
+ extensions_reply) : 1))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "failed to build the register message extensions_reply\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "failed to build the register message\n");
+ SENDERR(-error);
+ }
+ /* this should go to all registered sockets for that satype only */
+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+ "sending up register message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if(alg_a) {
+ kfree(alg_a);
+ }
+ if(alg_e) {
+ kfree(alg_e);
+ }
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_expire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct socket_list *pfkey_socketsp;
+#ifdef CONFIG_IPSEC_DEBUG
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+#endif /* CONFIG_IPSEC_DEBUG */
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_expire_parse: .\n");
+
+ if(pfkey_open_sockets) {
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: "
+ "sending up expire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: "
+ "sending up expire reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_flush_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+ uint8_t proto = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_flush_parse: "
+ "flushing type %d SAs\n",
+ satype);
+
+ if(satype && !(proto = satype2proto(satype))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_flush_parse: "
+ "satype %d lookup failed.\n",
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
+ SENDERR(EINVAL);
+ }
+
+ if ((error = ipsec_sadb_cleanup(proto))) {
+ SENDERR(-error);
+ }
+
+ if(pfkey_open_sockets) {
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: "
+ "sending up flush reply message for satype=%d(%s) (proto=%d) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ proto,
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: "
+ "sending up flush reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_dump_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_dump_parse: .\n");
+
+ SENDERR(ENOSYS);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_promisc_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_promisc_parse: .\n");
+
+ SENDERR(ENOSYS);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_pchange_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_pchange_parse: .\n");
+
+ SENDERR(ENOSYS);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_grpsa_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ struct ipsec_sa *ips1p, *ips2p, *ipsp;
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+ char sa1[SATOA_BUF], sa2[SATOA_BUF];
+ size_t sa_len1, sa_len2 = 0;
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ if(extr == NULL || extr->ips == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "extr or extr->ips is NULL, fatal.\n");
+ SENDERR(EINVAL);
+ }
+
+ sa_len1 = satoa(extr->ips->ips_said, 0, sa1, SATOA_BUF);
+ if(extr->ips2 != NULL) {
+ sa_len2 = satoa(extr->ips2->ips_said, 0, sa2, SATOA_BUF);
+ }
+
+ spin_lock_bh(&tdb_lock);
+
+ ips1p = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ips1p == NULL) {
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "reserved ipsec_sa for SA1: %s not found. Call SADB_ADD/UPDATE first.\n",
+ sa_len1 ? sa1 : " (error)");
+ SENDERR(ENOENT);
+ }
+ if(extr->ips2) { /* GRPSA */
+ ips2p = ipsec_sa_getbyid(&(extr->ips2->ips_said));
+ if(ips2p == NULL) {
+ ipsec_sa_put(ips1p);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "reserved ipsec_sa for SA2: %s not found. Call SADB_ADD/UPDATE first.\n",
+ sa_len2 ? sa2 : " (error)");
+ SENDERR(ENOENT);
+ }
+
+ /* Is either one already linked? */
+ if(ips1p->ips_onext) {
+ ipsec_sa_put(ips1p);
+ ipsec_sa_put(ips2p);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "ipsec_sa for SA: %s is already linked.\n",
+ sa_len1 ? sa1 : " (error)");
+ SENDERR(EEXIST);
+ }
+ if(ips2p->ips_inext) {
+ ipsec_sa_put(ips1p);
+ ipsec_sa_put(ips2p);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "ipsec_sa for SA: %s is already linked.\n",
+ sa_len2 ? sa2 : " (error)");
+ SENDERR(EEXIST);
+ }
+
+ /* Is extr->ips already linked to extr->ips2? */
+ ipsp = ips2p;
+ while(ipsp) {
+ if(ipsp == ips1p) {
+ ipsec_sa_put(ips1p);
+ ipsec_sa_put(ips2p);
+ spin_unlock_bh(&tdb_lock);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "ipsec_sa for SA: %s is already linked to %s.\n",
+ sa_len1 ? sa1 : " (error)",
+ sa_len2 ? sa2 : " (error)");
+ SENDERR(EEXIST);
+ }
+ ipsp = ipsp->ips_onext;
+ }
+
+ /* link 'em */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "linking ipsec_sa SA: %s with %s.\n",
+ sa_len1 ? sa1 : " (error)",
+ sa_len2 ? sa2 : " (error)");
+ ips1p->ips_onext = ips2p;
+ ips2p->ips_inext = ips1p;
+ } else { /* UNGRPSA */
+ ipsec_sa_put(ips1p);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_grpsa_parse: "
+ "unlinking ipsec_sa SA: %s.\n",
+ sa_len1 ? sa1 : " (error)");
+ while(ips1p->ips_onext) {
+ ips1p = ips1p->ips_onext;
+ }
+ while(ips1p->ips_inext) {
+ ipsp = ips1p;
+ ips1p = ips1p->ips_inext;
+ ipsec_sa_put(ips1p);
+ ipsp->ips_inext = NULL;
+ ipsec_sa_put(ipsp);
+ ips1p->ips_onext = NULL;
+ }
+ }
+
+ spin_unlock_bh(&tdb_lock);
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_X_GRPSA,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply)
+ && (extr->ips2
+ ? (pfkey_safe_build(error = pfkey_x_satype_build(&extensions_reply[SADB_X_EXT_SATYPE2],
+ ((struct sadb_x_satype*)extensions[SADB_X_EXT_SATYPE2])->sadb_x_satype_satype
+ /* proto2satype(extr->ips2->ips_said.proto) */),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_X_EXT_SA2],
+ SADB_X_EXT_SA2,
+ extr->ips2->ips_said.spi,
+ extr->ips2->ips_replaywin,
+ extr->ips2->ips_state,
+ extr->ips2->ips_authalg,
+ extr->ips2->ips_encalg,
+ extr->ips2->ips_flags,
+ extr->ips2->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST2],
+ SADB_X_EXT_ADDRESS_DST2,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips2->ips_addr_d),
+ extensions_reply) ) : 1 )
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "failed to build the x_grpsa reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "failed to build the x_grpsa reply message\n");
+ SENDERR(-error);
+ }
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
+ "succeeded in sending x_grpsa reply message.\n");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_addflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+#ifdef CONFIG_IPSEC_DEBUG
+ char buf1[64], buf2[64];
+#endif /* CONFIG_IPSEC_DEBUG */
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+ ip_address srcflow, dstflow, srcmask, dstmask;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ memset((caddr_t)&srcflow, 0, sizeof(srcflow));
+ memset((caddr_t)&dstflow, 0, sizeof(dstflow));
+ memset((caddr_t)&srcmask, 0, sizeof(srcmask));
+ memset((caddr_t)&dstmask, 0, sizeof(dstmask));
+
+ if(!extr || !(extr->ips) || !(extr->eroute)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "missing extr, ipsec_sa or eroute data.\n");
+ SENDERR(EINVAL);
+ }
+
+ srcflow.u.v4.sin_family = AF_INET;
+ dstflow.u.v4.sin_family = AF_INET;
+ srcmask.u.v4.sin_family = AF_INET;
+ dstmask.u.v4.sin_family = AF_INET;
+ srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src;
+ dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst;
+ srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src;
+ dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst;
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_pfkey) {
+ subnettoa(extr->eroute->er_eaddr.sen_ip_src,
+ extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
+ extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "calling breakeroute and/or makeroute for %s->%s\n",
+ buf1, buf2);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ if(extr->ips->ips_flags & SADB_X_SAFLAGS_INFLOW) {
+/* if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) */
+ struct ipsec_sa *ipsp, *ipsq;
+ char sa[SATOA_BUF];
+ size_t sa_len;
+
+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
+ if(ipsq == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "ipsec_sa not found, cannot set incoming policy.\n");
+ SENDERR(ENOENT);
+ }
+
+ ipsp = ipsq;
+ while(ipsp && ipsp->ips_said.proto != IPPROTO_IPIP) {
+ ipsp = ipsp->ips_inext;
+ }
+
+ if(ipsp == NULL) {
+ ipsec_sa_put(ipsq);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "SA chain does not have an IPIP SA, cannot set incoming policy.\n");
+ SENDERR(ENOENT);
+ }
+
+ sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF);
+
+ ipsp->ips_flags |= SADB_X_SAFLAGS_INFLOW;
+ ipsp->ips_flow_s = srcflow;
+ ipsp->ips_flow_d = dstflow;
+ ipsp->ips_mask_s = srcmask;
+ ipsp->ips_mask_d = dstmask;
+
+ ipsec_sa_put(ipsq);
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "inbound eroute, setting incoming policy information in IPIP ipsec_sa for SA: %s.\n",
+ sa_len ? sa : " (error)");
+ } else {
+ struct sk_buff *first = NULL, *last = NULL;
+
+ if(extr->ips->ips_flags & SADB_X_SAFLAGS_REPLACEFLOW) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "REPLACEFLOW flag set, calling breakeroute.\n");
+ if ((error = ipsec_breakroute(&(extr->eroute->er_eaddr),
+ &(extr->eroute->er_emask),
+ &first, &last))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "breakeroute returned %d. first=0p%p, last=0p%p\n",
+ error,
+ first,
+ last);
+ if(first != NULL) {
+ ipsec_kfree_skb(first);
+ }
+ if(last != NULL) {
+ ipsec_kfree_skb(last);
+ }
+ SENDERR(-error);
+ }
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "calling makeroute.\n");
+
+ if ((error = ipsec_makeroute(&(extr->eroute->er_eaddr),
+ &(extr->eroute->er_emask),
+ extr->ips->ips_said,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid,
+ NULL,
+ &(extr->ips->ips_ident_s),
+ &(extr->ips->ips_ident_d)))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "makeroute returned %d.\n", error);
+ SENDERR(-error);
+ }
+ if(first != NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "first=0p%p HOLD packet re-injected.\n",
+ first);
+ DEV_QUEUE_XMIT(first, first->dev, SOPRI_NORMAL);
+ }
+ if(last != NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "last=0p%p HOLD packet re-injected.\n",
+ last);
+ DEV_QUEUE_XMIT(last, last->dev, SOPRI_NORMAL);
+ }
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "makeroute call successful.\n");
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_X_ADDFLOW,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && (extensions[SADB_EXT_ADDRESS_SRC]
+ ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_s),
+ extensions_reply) : 1)
+ && (extensions[SADB_EXT_ADDRESS_DST]
+ ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ extr->ips->ips_addr_d),
+ extensions_reply) : 1)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_FLOW],
+ SADB_X_EXT_ADDRESS_SRC_FLOW,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&srcflow),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_FLOW],
+ SADB_X_EXT_ADDRESS_DST_FLOW,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&dstflow),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_MASK],
+ SADB_X_EXT_ADDRESS_SRC_MASK,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&srcmask),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_MASK],
+ SADB_X_EXT_ADDRESS_DST_MASK,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&dstmask),
+ extensions_reply)
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
+ "failed to build the x_addflow reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
+ "failed to build the x_addflow reply message\n");
+ SENDERR(-error);
+ }
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
+ "sending up x_addflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
+ "sending up x_addflow reply message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ extr->ips->ips_said.proto,
+ pfkey_socketsp->socketp);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_addflow_parse: "
+ "extr->ips cleaned up and freed.\n");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_delflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+#ifdef CONFIG_IPSEC_DEBUG
+ char buf1[64], buf2[64];
+#endif /* CONFIG_IPSEC_DEBUG */
+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_reply = NULL;
+ struct socket_list *pfkey_socketsp;
+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+ ip_address srcflow, dstflow, srcmask, dstmask;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: .\n");
+
+ pfkey_extensions_init(extensions_reply);
+
+ memset((caddr_t)&srcflow, 0, sizeof(srcflow));
+ memset((caddr_t)&dstflow, 0, sizeof(dstflow));
+ memset((caddr_t)&srcmask, 0, sizeof(srcmask));
+ memset((caddr_t)&dstmask, 0, sizeof(dstmask));
+
+ if(!extr || !(extr->ips)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "extr, or extr->ips is NULL, fatal\n");
+ SENDERR(EINVAL);
+ }
+
+ if(extr->ips->ips_flags & SADB_X_SAFLAGS_CLEARFLOW) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "CLEARFLOW flag set, calling cleareroutes.\n");
+ if ((error = ipsec_cleareroutes()))
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "cleareroutes returned %d.\n", error);
+ SENDERR(-error);
+ } else {
+ struct sk_buff *first = NULL, *last = NULL;
+
+ if(!(extr->eroute)) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "extr->eroute is NULL, fatal.\n");
+ SENDERR(EINVAL);
+ }
+
+ srcflow.u.v4.sin_family = AF_INET;
+ dstflow.u.v4.sin_family = AF_INET;
+ srcmask.u.v4.sin_family = AF_INET;
+ dstmask.u.v4.sin_family = AF_INET;
+ srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src;
+ dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst;
+ srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src;
+ dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst;
+
+#ifdef CONFIG_IPSEC_DEBUG
+ if (debug_pfkey) {
+ subnettoa(extr->eroute->er_eaddr.sen_ip_src,
+ extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
+ subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
+ extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "calling breakeroute for %s->%s\n",
+ buf1, buf2);
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ error = ipsec_breakroute(&(extr->eroute->er_eaddr),
+ &(extr->eroute->er_emask),
+ &first, &last);
+ if(error) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "breakeroute returned %d. first=0p%p, last=0p%p\n",
+ error,
+ first,
+ last);
+ }
+ if(first != NULL) {
+ ipsec_kfree_skb(first);
+ }
+ if(last != NULL) {
+ ipsec_kfree_skb(last);
+ }
+ if(error) {
+ SENDERR(-error);
+ }
+ }
+
+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
+ SADB_X_DELFLOW,
+ satype,
+ 0,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_FLOW],
+ SADB_X_EXT_ADDRESS_SRC_FLOW,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&srcflow),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_FLOW],
+ SADB_X_EXT_ADDRESS_DST_FLOW,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&dstflow),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_MASK],
+ SADB_X_EXT_ADDRESS_SRC_MASK,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&srcmask),
+ extensions_reply)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_MASK],
+ SADB_X_EXT_ADDRESS_DST_MASK,
+ 0, /*extr->ips->ips_said.proto,*/
+ 0,
+ (struct sockaddr*)&dstmask),
+ extensions_reply)
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
+ "failed to build the x_delflow reply message extensions\n");
+ SENDERR(-error);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
+ "failed to build the x_delflow reply message\n");
+ SENDERR(-error);
+ }
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
+ "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
+ "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_delflow_parse: "
+ "extr->ips cleaned up and freed.\n");
+
+ errlab:
+ if (pfkey_reply) {
+ pfkey_msg_free(&pfkey_reply);
+ }
+ pfkey_extensions_free(extensions_reply);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_msg_debug_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ int error = 0;
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_x_msg_debug_parse: .\n");
+
+/* errlab:*/
+ return error;
+}
+
+/* pfkey_expire expects the ipsec_sa table to be locked before being called. */
+int
+pfkey_expire(struct ipsec_sa *ipsp, int hard)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_msg = NULL;
+ struct socket_list *pfkey_socketsp;
+ int error = 0;
+ uint8_t satype;
+
+ pfkey_extensions_init(extensions);
+
+ if(!(satype = proto2satype(ipsp->ips_said.proto))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_expire: "
+ "satype lookup for protocol %d lookup failed.\n",
+ ipsp->ips_said.proto);
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_open_sockets) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "no sockets listening.\n");
+ SENDERR(EPROTONOSUPPORT);
+ }
+
+ if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0],
+ SADB_EXPIRE,
+ satype,
+ 0,
+ ++pfkey_msg_seq,
+ 0),
+ extensions)
+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions[SADB_EXT_SA],
+ SADB_EXT_SA,
+ ipsp->ips_said.spi,
+ ipsp->ips_replaywin,
+ ipsp->ips_state,
+ ipsp->ips_authalg,
+ ipsp->ips_encalg,
+ ipsp->ips_flags,
+ ipsp->ips_ref),
+ extensions)
+ && pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_CURRENT],
+ SADB_EXT_LIFETIME_CURRENT,
+ ipsp->ips_life.ipl_allocations.ipl_count,
+ ipsp->ips_life.ipl_bytes.ipl_count,
+ ipsp->ips_life.ipl_addtime.ipl_count,
+ ipsp->ips_life.ipl_usetime.ipl_count,
+ ipsp->ips_life.ipl_packets.ipl_count),
+ extensions)
+ && (hard ?
+ pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_HARD],
+ SADB_EXT_LIFETIME_HARD,
+ ipsp->ips_life.ipl_allocations.ipl_hard,
+ ipsp->ips_life.ipl_bytes.ipl_hard,
+ ipsp->ips_life.ipl_addtime.ipl_hard,
+ ipsp->ips_life.ipl_usetime.ipl_hard,
+ ipsp->ips_life.ipl_packets.ipl_hard),
+ extensions)
+ : pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_SOFT],
+ SADB_EXT_LIFETIME_SOFT,
+ ipsp->ips_life.ipl_allocations.ipl_soft,
+ ipsp->ips_life.ipl_bytes.ipl_soft,
+ ipsp->ips_life.ipl_addtime.ipl_soft,
+ ipsp->ips_life.ipl_usetime.ipl_soft,
+ ipsp->ips_life.ipl_packets.ipl_soft),
+ extensions))
+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0, /* ipsp->ips_said.proto, */
+ 0,
+ ipsp->ips_addr_s),
+ extensions)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ 0, /* ipsp->ips_said.proto, */
+ 0,
+ ipsp->ips_addr_d),
+ extensions))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "failed to build the expire message extensions\n");
+ spin_unlock(&tdb_lock);
+ goto errlab;
+ }
+
+ if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "failed to build the expire message\n");
+ SENDERR(-error);
+ }
+
+ for(pfkey_socketsp = pfkey_open_sockets;
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "sending up expire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
+ "sending up expire message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ ipsp->ips_said.proto,
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if (pfkey_msg) {
+ pfkey_msg_free(&pfkey_msg);
+ }
+ pfkey_extensions_free(extensions);
+ return error;
+}
+
+int
+pfkey_acquire(struct ipsec_sa *ipsp)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_msg = NULL;
+ struct socket_list *pfkey_socketsp;
+ int error = 0;
+ struct sadb_comb comb[] = {
+ /* auth; encrypt; flags; */
+ /* auth_minbits; auth_maxbits; encrypt_minbits; encrypt_maxbits; */
+ /* reserved; soft_allocations; hard_allocations; soft_bytes; hard_bytes; */
+ /* soft_addtime; hard_addtime; soft_usetime; hard_usetime; */
+ /* soft_packets; hard_packets; */
+ { SADB_AALG_MD5_HMAC, SADB_EALG_3DES_CBC, SADB_SAFLAGS_PFS,
+ 128, 128, 168, 168,
+ 0, 0, 0, 0, 0,
+ 57600, 86400, 57600, 86400,
+ 0, 0 },
+ { SADB_AALG_SHA1_HMAC, SADB_EALG_3DES_CBC, SADB_SAFLAGS_PFS,
+ 160, 160, 168, 168,
+ 0, 0, 0, 0, 0,
+ 57600, 86400, 57600, 86400,
+ 0, 0 }
+ };
+
+ /* XXX This should not be hard-coded. It should be taken from the spdb */
+ uint8_t satype = SADB_SATYPE_ESP;
+
+ pfkey_extensions_init(extensions);
+
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: "
+ "SAtype=%d unspecified or unknown.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+
+ if(!(pfkey_registered_sockets[satype])) {
+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
+ "no sockets registered for SAtype=%d(%s).\n",
+ satype,
+ satype2name(satype));
+ SENDERR(EPROTONOSUPPORT);
+ }
+
+ if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0],
+ SADB_ACQUIRE,
+ satype,
+ 0,
+ ++pfkey_msg_seq,
+ 0),
+ extensions)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ ipsp->ips_said.proto,
+ 0,
+ ipsp->ips_addr_s),
+ extensions)
+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ ipsp->ips_said.proto,
+ 0,
+ ipsp->ips_addr_d),
+ extensions)
+#if 0
+ && (ipsp->ips_addr_p
+ ? pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_PROXY],
+ SADB_EXT_ADDRESS_PROXY,
+ ipsp->ips_said.proto,
+ 0,
+ ipsp->ips_addr_p),
+ extensions) : 1)
+#endif
+ && (ipsp->ips_ident_s.type != SADB_IDENTTYPE_RESERVED
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_SRC],
+ SADB_EXT_IDENTITY_SRC,
+ ipsp->ips_ident_s.type,
+ ipsp->ips_ident_s.id,
+ ipsp->ips_ident_s.len,
+ ipsp->ips_ident_s.data),
+ extensions) : 1)
+
+ && (ipsp->ips_ident_d.type != SADB_IDENTTYPE_RESERVED
+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_DST],
+ SADB_EXT_IDENTITY_DST,
+ ipsp->ips_ident_d.type,
+ ipsp->ips_ident_d.id,
+ ipsp->ips_ident_d.len,
+ ipsp->ips_ident_d.data),
+ extensions) : 1)
+#if 0
+ /* FIXME: This won't work yet because I have not finished
+ it. */
+ && (ipsp->ips_sens_
+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions[SADB_EXT_SENSITIVITY],
+ ipsp->ips_sens_dpd,
+ ipsp->ips_sens_sens_level,
+ ipsp->ips_sens_sens_len,
+ ipsp->ips_sens_sens_bitmap,
+ ipsp->ips_sens_integ_level,
+ ipsp->ips_sens_integ_len,
+ ipsp->ips_sens_integ_bitmap),
+ extensions) : 1)
+#endif
+ && pfkey_safe_build(error = pfkey_prop_build(&extensions[SADB_EXT_PROPOSAL],
+ 64, /* replay */
+ sizeof(comb)/sizeof(struct sadb_comb),
+ &(comb[0])),
+ extensions)
+ )) {
+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
+ "failed to build the acquire message extensions\n");
+ SENDERR(-error);
+ }
+
+ if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
+ "failed to build the acquire message\n");
+ SENDERR(-error);
+ }
+
+#if KLIPS_PFKEY_ACQUIRE_LOSSAGE > 0
+ if(sysctl_ipsec_regress_pfkey_lossage) {
+ return(0);
+ }
+#endif
+
+ /* this should go to all registered sockets for that satype only */
+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
+ "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: "
+ "sending up acquire message for satype=%d(%s) to socket=0p%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if (pfkey_msg) {
+ pfkey_msg_free(&pfkey_msg);
+ }
+ pfkey_extensions_free(extensions);
+ return error;
+}
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+int
+pfkey_nat_t_new_mapping(struct ipsec_sa *ipsp, struct sockaddr *ipaddr,
+ __u16 sport)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ struct sadb_msg *pfkey_msg = NULL;
+ struct socket_list *pfkey_socketsp;
+ int error = 0;
+ uint8_t satype = (ipsp->ips_said.proto==IPPROTO_ESP) ? SADB_SATYPE_ESP : 0;
+
+ /* Construct SADB_X_NAT_T_NEW_MAPPING message */
+
+ pfkey_extensions_init(extensions);
+
+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "SAtype=%d unspecified or unknown.\n",
+ satype);
+ SENDERR(EINVAL);
+ }
+
+ if(!(pfkey_registered_sockets[satype])) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "no sockets registered for SAtype=%d(%s).\n",
+ satype,
+ satype2name(satype));
+ SENDERR(EPROTONOSUPPORT);
+ }
+
+ if (!(pfkey_safe_build
+ (error = pfkey_msg_hdr_build(&extensions[0], SADB_X_NAT_T_NEW_MAPPING,
+ satype, 0, ++pfkey_msg_seq, 0), extensions)
+ /* SA */
+ && pfkey_safe_build
+ (error = pfkey_sa_build(&extensions[SADB_EXT_SA],
+ SADB_EXT_SA, ipsp->ips_said.spi, 0, 0, 0, 0, 0), extensions)
+ /* ADDRESS_SRC = old addr */
+ && pfkey_safe_build
+ (error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC, ipsp->ips_said.proto, 0, ipsp->ips_addr_s),
+ extensions)
+ /* NAT_T_SPORT = old port */
+ && pfkey_safe_build
+ (error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_SPORT],
+ SADB_X_EXT_NAT_T_SPORT, ipsp->ips_natt_sport), extensions)
+ /* ADDRESS_DST = new addr */
+ && pfkey_safe_build
+ (error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST, ipsp->ips_said.proto, 0, ipaddr), extensions)
+ /* NAT_T_DPORT = new port */
+ && pfkey_safe_build
+ (error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_DPORT],
+ SADB_X_EXT_NAT_T_DPORT, sport), extensions)
+ )) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "failed to build the nat_t_new_mapping message extensions\n");
+ SENDERR(-error);
+ }
+
+ if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "failed to build the nat_t_new_mapping message\n");
+ SENDERR(-error);
+ }
+
+ /* this should go to all registered sockets for that satype only */
+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
+ pfkey_socketsp;
+ pfkey_socketsp = pfkey_socketsp->next) {
+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p failed with error=%d.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp,
+ error);
+ SENDERR(-error);
+ }
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+ "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p succeeded.\n",
+ satype,
+ satype2name(satype),
+ pfkey_socketsp->socketp);
+ }
+
+ errlab:
+ if (pfkey_msg) {
+ pfkey_msg_free(&pfkey_msg);
+ }
+ pfkey_extensions_free(extensions);
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_nat_t_new_mapping_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+ /* SADB_X_NAT_T_NEW_MAPPING not used in kernel */
+ return -EINVAL;
+}
+#endif
+
+DEBUG_NO_STATIC int (*ext_processors[SADB_EXT_MAX+1])(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr) =
+{
+ NULL, /* pfkey_msg_process, */
+ pfkey_sa_process,
+ pfkey_lifetime_process,
+ pfkey_lifetime_process,
+ pfkey_lifetime_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_key_process,
+ pfkey_key_process,
+ pfkey_ident_process,
+ pfkey_ident_process,
+ pfkey_sens_process,
+ pfkey_prop_process,
+ pfkey_supported_process,
+ pfkey_supported_process,
+ pfkey_spirange_process,
+ pfkey_x_kmprivate_process,
+ pfkey_x_satype_process,
+ pfkey_sa_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_address_process,
+ pfkey_x_debug_process,
+ pfkey_x_protocol_process
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ ,
+ pfkey_x_nat_t_type_process,
+ pfkey_x_nat_t_port_process,
+ pfkey_x_nat_t_port_process,
+ pfkey_address_process
+#endif
+};
+
+
+DEBUG_NO_STATIC int (*msg_parsers[SADB_MAX +1])(struct sock *sk, struct sadb_ext *extensions[], struct pfkey_extracted_data* extr)
+ =
+{
+ NULL, /* RESERVED */
+ pfkey_getspi_parse,
+ pfkey_update_parse,
+ pfkey_add_parse,
+ pfkey_delete_parse,
+ pfkey_get_parse,
+ pfkey_acquire_parse,
+ pfkey_register_parse,
+ pfkey_expire_parse,
+ pfkey_flush_parse,
+ pfkey_dump_parse,
+ pfkey_x_promisc_parse,
+ pfkey_x_pchange_parse,
+ pfkey_x_grpsa_parse,
+ pfkey_x_addflow_parse,
+ pfkey_x_delflow_parse,
+ pfkey_x_msg_debug_parse
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+ , pfkey_x_nat_t_new_mapping_parse
+#endif
+};
+
+int
+pfkey_build_reply(struct sadb_msg *pfkey_msg, struct pfkey_extracted_data *extr,
+ struct sadb_msg **pfkey_reply)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ int error = 0;
+ int msg_type = pfkey_msg->sadb_msg_type;
+ int seq = pfkey_msg->sadb_msg_seq;
+
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
+ "building reply with type: %d\n",
+ msg_type);
+ pfkey_extensions_init(extensions);
+ if (!extr || !extr->ips) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
+ "bad ipsec_sa passed\n");
+ return EINVAL;
+ }
+ error = pfkey_safe_build(pfkey_msg_hdr_build(&extensions[0],
+ msg_type,
+ proto2satype(extr->ips->ips_said.proto),
+ 0,
+ seq,
+ pfkey_msg->sadb_msg_pid),
+ extensions) &&
+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
+ 1 << SADB_EXT_SA)
+ || pfkey_safe_build(pfkey_sa_ref_build(&extensions[SADB_EXT_SA],
+ SADB_EXT_SA,
+ extr->ips->ips_said.spi,
+ extr->ips->ips_replaywin,
+ extr->ips->ips_state,
+ extr->ips->ips_authalg,
+ extr->ips->ips_encalg,
+ extr->ips->ips_flags,
+ extr->ips->ips_ref),
+ extensions)) &&
+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
+ 1 << SADB_EXT_LIFETIME_CURRENT)
+ || pfkey_safe_build(pfkey_lifetime_build(&extensions
+ [SADB_EXT_LIFETIME_CURRENT],
+ SADB_EXT_LIFETIME_CURRENT,
+ extr->ips->ips_life.ipl_allocations.ipl_count,
+ extr->ips->ips_life.ipl_bytes.ipl_count,
+ extr->ips->ips_life.ipl_addtime.ipl_count,
+ extr->ips->ips_life.ipl_usetime.ipl_count,
+ extr->ips->ips_life.ipl_packets.ipl_count),
+ extensions)) &&
+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
+ 1 << SADB_EXT_ADDRESS_SRC)
+ || pfkey_safe_build(pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ extr->ips->ips_said.proto,
+ 0,
+ extr->ips->ips_addr_s),
+ extensions)) &&
+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
+ 1 << SADB_EXT_ADDRESS_DST)
+ || pfkey_safe_build(pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
+ SADB_EXT_ADDRESS_DST,
+ extr->ips->ips_said.proto,
+ 0,
+ extr->ips->ips_addr_d),
+ extensions));
+
+ if (error == 0) {
+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
+ "building extensions failed\n");
+ return EINVAL;
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_build_reply: "
+ "built extensions, proceed to build the message\n");
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_build_reply: "
+ "extensions[1]=0p%p\n",
+ extensions[1]);
+ error = pfkey_msg_build(pfkey_reply, extensions, EXT_BITS_OUT);
+ pfkey_extensions_free(extensions);
+
+ return error;
+}
+
+int
+pfkey_msg_interp(struct sock *sk, struct sadb_msg *pfkey_msg,
+ struct sadb_msg **pfkey_reply)
+{
+ int error = 0;
+ int i;
+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
+ struct pfkey_extracted_data extr = {NULL, NULL, NULL};
+
+ pfkey_extensions_init(extensions);
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "parsing message ver=%d, type=%d, errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n",
+ pfkey_msg->sadb_msg_version,
+ pfkey_msg->sadb_msg_type,
+ pfkey_msg->sadb_msg_errno,
+ pfkey_msg->sadb_msg_satype,
+ satype2name(pfkey_msg->sadb_msg_satype),
+ pfkey_msg->sadb_msg_len,
+ pfkey_msg->sadb_msg_reserved,
+ pfkey_msg->sadb_msg_seq,
+ pfkey_msg->sadb_msg_pid);
+
+ extr.ips = ipsec_sa_alloc(&error); /* pass in error var by pointer */
+ if(extr.ips == NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "memory allocation error.\n");
+ SENDERR(-error);
+ }
+
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "allocated extr->ips=0p%p.\n",
+ extr.ips);
+
+ if(pfkey_msg->sadb_msg_satype > SADB_SATYPE_MAX) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "satype %d > max %d\n",
+ pfkey_msg->sadb_msg_satype,
+ SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_msg->sadb_msg_type) {
+ case SADB_GETSPI:
+ case SADB_UPDATE:
+ case SADB_ADD:
+ case SADB_DELETE:
+ case SADB_X_GRPSA:
+ case SADB_X_ADDFLOW:
+ if(!(extr.ips->ips_said.proto = satype2proto(pfkey_msg->sadb_msg_satype))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "satype %d lookup failed.\n",
+ pfkey_msg->sadb_msg_satype);
+ SENDERR(EINVAL);
+ } else {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "satype %d lookups to proto=%d.\n",
+ pfkey_msg->sadb_msg_satype,
+ extr.ips->ips_said.proto);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* The NULL below causes the default extension parsers to be used */
+ /* Parse the extensions */
+ if((error = pfkey_msg_parse(pfkey_msg, NULL, extensions, EXT_BITS_IN)))
+ {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "message parsing failed with error %d.\n",
+ error);
+ SENDERR(-error);
+ }
+
+ /* Process the extensions */
+ for(i=1; i <= SADB_EXT_MAX;i++) {
+ if(extensions[i] != NULL) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "processing ext %d 0p%p with processor 0p%p.\n",
+ i, extensions[i], ext_processors[i]);
+ if((error = ext_processors[i](extensions[i], &extr))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "extension processing for type %d failed with error %d.\n",
+ i,
+ error);
+ SENDERR(-error);
+ }
+
+ }
+
+ }
+
+ /* Parse the message types */
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "parsing message type %d(%s) with msg_parser 0p%p.\n",
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
+ msg_parsers[pfkey_msg->sadb_msg_type]);
+ if((error = msg_parsers[pfkey_msg->sadb_msg_type](sk, extensions, &extr))) {
+ KLIPS_PRINT(debug_pfkey,
+ "klips_debug:pfkey_msg_interp: "
+ "message parsing failed with error %d.\n",
+ error);
+ SENDERR(-error);
+ }
+
+#if 0
+ error = pfkey_build_reply(pfkey_msg, &extr, pfkey_reply);
+ if (error) {
+ *pfkey_reply = NULL;
+ }
+#endif
+ errlab:
+ if(extr.ips != NULL) {
+ ipsec_sa_wipe(extr.ips);
+ }
+ if(extr.ips2 != NULL) {
+ ipsec_sa_wipe(extr.ips2);
+ }
+ if (extr.eroute != NULL) {
+ kfree(extr.eroute);
+ }
+ return(error);
+}
+
diff --git a/linux/net/ipsec/radij.c b/linux/net/ipsec/radij.c
new file mode 100644
index 000000000..7dbec8d37
--- /dev/null
+++ b/linux/net/ipsec/radij.c
@@ -0,0 +1,992 @@
+char radij_c_version[] = "RCSID $Id: radij.c,v 1.2 2004/06/13 19:57:50 as Exp $";
+
+/*
+ * This file is defived from ${SRC}/sys/net/radix.c of BSD 4.4lite
+ *
+ * Variable and procedure names have been modified so that they don't
+ * conflict with the original BSD code, as a small number of modifications
+ * have been introduced and we may want to reuse this code in BSD.
+ *
+ * The `j' in `radij' is pronounced as a voiceless guttural (like a Greek
+ * chi or a German ch sound (as `doch', not as in `milch'), or even a
+ * spanish j as in Juan. It is not as far back in the throat like
+ * the corresponding Hebrew sound, nor is it a soft breath like the English h.
+ * It has nothing to do with the Dutch ij sound.
+ *
+ * Here is the appropriate copyright notice:
+ */
+
+/*
+ * Copyright (c) 1988, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)radix.c 8.2 (Berkeley) 1/4/94
+ */
+
+/*
+ * Routines to build and maintain radix trees for routing lookups.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h> /* printk() */
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+#else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+#endif /* MALLOC_SLAB */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h> /* struct iphdr */
+#include <linux/skbuff.h>
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+#endif /* NET_21 */
+#include <asm/checksum.h>
+#include <net/ip.h>
+
+#include <freeswan.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_radij.h"
+
+int maj_keylen;
+struct radij_mask *rj_mkfreelist;
+struct radij_node_head *mask_rjhead;
+static int gotOddMasks;
+static char *maskedKey;
+static char *rj_zeroes, *rj_ones;
+
+#define rj_masktop (mask_rjhead->rnh_treetop)
+#ifdef Bcmp
+# undef Bcmp
+#endif /* Bcmp */
+#define Bcmp(a, b, l) (l == 0 ? 0 : memcmp((caddr_t)(b), (caddr_t)(a), (size_t)l))
+/*
+ * The data structure for the keys is a radix tree with one way
+ * branching removed. The index rj_b at an internal node n represents a bit
+ * position to be tested. The tree is arranged so that all descendants
+ * of a node n have keys whose bits all agree up to position rj_b - 1.
+ * (We say the index of n is rj_b.)
+ *
+ * There is at least one descendant which has a one bit at position rj_b,
+ * and at least one with a zero there.
+ *
+ * A route is determined by a pair of key and mask. We require that the
+ * bit-wise logical and of the key and mask to be the key.
+ * We define the index of a route to associated with the mask to be
+ * the first bit number in the mask where 0 occurs (with bit number 0
+ * representing the highest order bit).
+ *
+ * We say a mask is normal if every bit is 0, past the index of the mask.
+ * If a node n has a descendant (k, m) with index(m) == index(n) == rj_b,
+ * and m is a normal mask, then the route applies to every descendant of n.
+ * If the index(m) < rj_b, this implies the trailing last few bits of k
+ * before bit b are all 0, (and hence consequently true of every descendant
+ * of n), so the route applies to all descendants of the node as well.
+ *
+ * The present version of the code makes no use of normal routes,
+ * but similar logic shows that a non-normal mask m such that
+ * index(m) <= index(n) could potentially apply to many children of n.
+ * Thus, for each non-host route, we attach its mask to a list at an internal
+ * node as high in the tree as we can go.
+ */
+
+struct radij_node *
+rj_search(v_arg, head)
+ void *v_arg;
+ struct radij_node *head;
+{
+ register struct radij_node *x;
+ register caddr_t v;
+
+ for (x = head, v = v_arg; x->rj_b >= 0;) {
+ if (x->rj_bmask & v[x->rj_off])
+ x = x->rj_r;
+ else
+ x = x->rj_l;
+ }
+ return (x);
+};
+
+struct radij_node *
+rj_search_m(v_arg, head, m_arg)
+ struct radij_node *head;
+ void *v_arg, *m_arg;
+{
+ register struct radij_node *x;
+ register caddr_t v = v_arg, m = m_arg;
+
+ for (x = head; x->rj_b >= 0;) {
+ if ((x->rj_bmask & m[x->rj_off]) &&
+ (x->rj_bmask & v[x->rj_off]))
+ x = x->rj_r;
+ else
+ x = x->rj_l;
+ }
+ return x;
+};
+
+int
+rj_refines(m_arg, n_arg)
+ void *m_arg, *n_arg;
+{
+ register caddr_t m = m_arg, n = n_arg;
+ register caddr_t lim, lim2 = lim = n + *(u_char *)n;
+ int longer = (*(u_char *)n++) - (int)(*(u_char *)m++);
+ int masks_are_equal = 1;
+
+ if (longer > 0)
+ lim -= longer;
+ while (n < lim) {
+ if (*n & ~(*m))
+ return 0;
+ if (*n++ != *m++)
+ masks_are_equal = 0;
+
+ }
+ while (n < lim2)
+ if (*n++)
+ return 0;
+ if (masks_are_equal && (longer < 0))
+ for (lim2 = m - longer; m < lim2; )
+ if (*m++)
+ return 1;
+ return (!masks_are_equal);
+}
+
+
+struct radij_node *
+rj_match(v_arg, head)
+ void *v_arg;
+ struct radij_node_head *head;
+{
+ caddr_t v = v_arg;
+ register struct radij_node *t = head->rnh_treetop, *x;
+ register caddr_t cp = v, cp2, cp3;
+ caddr_t cplim, mstart;
+ struct radij_node *saved_t, *top = t;
+ int off = t->rj_off, vlen = *(u_char *)cp, matched_off;
+
+ /*
+ * Open code rj_search(v, top) to avoid overhead of extra
+ * subroutine call.
+ */
+ for (; t->rj_b >= 0; ) {
+ if (t->rj_bmask & cp[t->rj_off])
+ t = t->rj_r;
+ else
+ t = t->rj_l;
+ }
+ /*
+ * See if we match exactly as a host destination
+ */
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "* See if we match exactly as a host destination\n");
+
+ cp += off; cp2 = t->rj_key + off; cplim = v + vlen;
+ for (; cp < cplim; cp++, cp2++)
+ if (*cp != *cp2)
+ goto on1;
+ /*
+ * This extra grot is in case we are explicitly asked
+ * to look up the default. Ugh!
+ */
+ if ((t->rj_flags & RJF_ROOT) && t->rj_dupedkey)
+ t = t->rj_dupedkey;
+ return t;
+on1:
+ matched_off = cp - v;
+ saved_t = t;
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "** try to match a leaf, t=0p%p\n", t);
+ do {
+ if (t->rj_mask) {
+ /*
+ * Even if we don't match exactly as a hosts;
+ * we may match if the leaf we wound up at is
+ * a route to a net.
+ */
+ cp3 = matched_off + t->rj_mask;
+ cp2 = matched_off + t->rj_key;
+ for (; cp < cplim; cp++)
+ if ((*cp2++ ^ *cp) & *cp3++)
+ break;
+ if (cp == cplim)
+ return t;
+ cp = matched_off + v;
+ }
+ } while ((t = t->rj_dupedkey));
+ t = saved_t;
+ /* start searching up the tree */
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "*** start searching up the tree, t=0p%p\n",
+ t);
+ do {
+ register struct radij_mask *m;
+
+ t = t->rj_p;
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "**** t=0p%p\n",
+ t);
+ if ((m = t->rj_mklist)) {
+ /*
+ * After doing measurements here, it may
+ * turn out to be faster to open code
+ * rj_search_m here instead of always
+ * copying and masking.
+ */
+ /* off = min(t->rj_off, matched_off); */
+ off = t->rj_off;
+ if (matched_off < off)
+ off = matched_off;
+ mstart = maskedKey + off;
+ do {
+ cp2 = mstart;
+ cp3 = m->rm_mask + off;
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "***** cp2=0p%p cp3=0p%p\n",
+ cp2, cp3);
+ for (cp = v + off; cp < cplim;)
+ *cp2++ = *cp++ & *cp3++;
+ x = rj_search(maskedKey, t);
+ while (x && x->rj_mask != m->rm_mask)
+ x = x->rj_dupedkey;
+ if (x &&
+ (Bcmp(mstart, x->rj_key + off,
+ vlen - off) == 0))
+ return x;
+ } while ((m = m->rm_mklist));
+ }
+ } while (t != top);
+ KLIPS_PRINT(debug_radij,
+ "klips_debug:rj_match: "
+ "***** not found.\n");
+ return 0;
+};
+
+#ifdef RJ_DEBUG
+int rj_nodenum;
+struct radij_node *rj_clist;
+int rj_saveinfo;
+DEBUG_NO_STATIC void traverse(struct radij_node *);
+#ifdef RJ_DEBUG2
+int rj_debug = 1;
+#else
+int rj_debug = 0;
+#endif /* RJ_DEBUG2 */
+#endif /* RJ_DEBUG */
+
+struct radij_node *
+rj_newpair(v, b, nodes)
+ void *v;
+ int b;
+ struct radij_node nodes[2];
+{
+ register struct radij_node *tt = nodes, *t = tt + 1;
+ t->rj_b = b; t->rj_bmask = 0x80 >> (b & 7);
+ t->rj_l = tt; t->rj_off = b >> 3;
+ tt->rj_b = -1; tt->rj_key = (caddr_t)v; tt->rj_p = t;
+ tt->rj_flags = t->rj_flags = RJF_ACTIVE;
+#ifdef RJ_DEBUG
+ tt->rj_info = rj_nodenum++; t->rj_info = rj_nodenum++;
+ tt->rj_twin = t; tt->rj_ybro = rj_clist; rj_clist = tt;
+#endif /* RJ_DEBUG */
+ return t;
+}
+
+struct radij_node *
+rj_insert(v_arg, head, dupentry, nodes)
+ void *v_arg;
+ struct radij_node_head *head;
+ int *dupentry;
+ struct radij_node nodes[2];
+{
+ caddr_t v = v_arg;
+ struct radij_node *top = head->rnh_treetop;
+ int head_off = top->rj_off, vlen = (int)*((u_char *)v);
+ register struct radij_node *t = rj_search(v_arg, top);
+ register caddr_t cp = v + head_off;
+ register int b;
+ struct radij_node *tt;
+ /*
+ *find first bit at which v and t->rj_key differ
+ */
+ {
+ register caddr_t cp2 = t->rj_key + head_off;
+ register int cmp_res;
+ caddr_t cplim = v + vlen;
+
+ while (cp < cplim)
+ if (*cp2++ != *cp++)
+ goto on1;
+ *dupentry = 1;
+ return t;
+on1:
+ *dupentry = 0;
+ cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
+ for (b = (cp - v) << 3; cmp_res; b--)
+ cmp_res >>= 1;
+ }
+ {
+ register struct radij_node *p, *x = top;
+ cp = v;
+ do {
+ p = x;
+ if (cp[x->rj_off] & x->rj_bmask)
+ x = x->rj_r;
+ else x = x->rj_l;
+ } while (b > (unsigned) x->rj_b); /* x->rj_b < b && x->rj_b >= 0 */
+#ifdef RJ_DEBUG
+ if (rj_debug)
+ printk("klips_debug:rj_insert: Going In:\n"), traverse(p);
+#endif /* RJ_DEBUG */
+ t = rj_newpair(v_arg, b, nodes); tt = t->rj_l;
+ if ((cp[p->rj_off] & p->rj_bmask) == 0)
+ p->rj_l = t;
+ else
+ p->rj_r = t;
+ x->rj_p = t; t->rj_p = p; /* frees x, p as temp vars below */
+ if ((cp[t->rj_off] & t->rj_bmask) == 0) {
+ t->rj_r = x;
+ } else {
+ t->rj_r = tt; t->rj_l = x;
+ }
+#ifdef RJ_DEBUG
+ if (rj_debug)
+ printk("klips_debug:rj_insert: Coming out:\n"), traverse(p);
+#endif /* RJ_DEBUG */
+ }
+ return (tt);
+}
+
+struct radij_node *
+rj_addmask(n_arg, search, skip)
+ int search, skip;
+ void *n_arg;
+{
+ caddr_t netmask = (caddr_t)n_arg;
+ register struct radij_node *x;
+ register caddr_t cp, cplim;
+ register int b, mlen, j;
+ int maskduplicated;
+
+ mlen = *(u_char *)netmask;
+ if (search) {
+ x = rj_search(netmask, rj_masktop);
+ mlen = *(u_char *)netmask;
+ if (Bcmp(netmask, x->rj_key, mlen) == 0)
+ return (x);
+ }
+ R_Malloc(x, struct radij_node *, maj_keylen + 2 * sizeof (*x));
+ if (x == 0)
+ return (0);
+ Bzero(x, maj_keylen + 2 * sizeof (*x));
+ cp = (caddr_t)(x + 2);
+ Bcopy(netmask, cp, mlen);
+ netmask = cp;
+ x = rj_insert(netmask, mask_rjhead, &maskduplicated, x);
+ /*
+ * Calculate index of mask.
+ */
+ cplim = netmask + mlen;
+ for (cp = netmask + skip; cp < cplim; cp++)
+ if (*(u_char *)cp != 0xff)
+ break;
+ b = (cp - netmask) << 3;
+ if (cp != cplim) {
+ if (*cp != 0) {
+ gotOddMasks = 1;
+ for (j = 0x80; j; b++, j >>= 1)
+ if ((j & *cp) == 0)
+ break;
+ }
+ }
+ x->rj_b = -1 - b;
+ return (x);
+}
+
+#if 0
+struct radij_node *
+#endif
+int
+rj_addroute(v_arg, n_arg, head, treenodes)
+ void *v_arg, *n_arg;
+ struct radij_node_head *head;
+ struct radij_node treenodes[2];
+{
+ caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
+ register struct radij_node *t, *x=NULL, *tt;
+ struct radij_node *saved_tt, *top = head->rnh_treetop;
+ short b = 0, b_leaf;
+ int mlen, keyduplicated;
+ caddr_t cplim;
+ struct radij_mask *m, **mp;
+
+ /*
+ * In dealing with non-contiguous masks, there may be
+ * many different routes which have the same mask.
+ * We will find it useful to have a unique pointer to
+ * the mask to speed avoiding duplicate references at
+ * nodes and possibly save time in calculating indices.
+ */
+ if (netmask) {
+ x = rj_search(netmask, rj_masktop);
+ mlen = *(u_char *)netmask;
+ if (Bcmp(netmask, x->rj_key, mlen) != 0) {
+ x = rj_addmask(netmask, 0, top->rj_off);
+ if (x == 0)
+ return -ENOMEM; /* (0) rgb */
+ }
+ netmask = x->rj_key;
+ b = -1 - x->rj_b;
+ }
+ /*
+ * Deal with duplicated keys: attach node to previous instance
+ */
+ saved_tt = tt = rj_insert(v, head, &keyduplicated, treenodes);
+ if (keyduplicated) {
+ do {
+ if (tt->rj_mask == netmask)
+ return -EEXIST; /* -ENXIO; (0) rgb */
+ t = tt;
+ if (netmask == 0 ||
+ (tt->rj_mask && rj_refines(netmask, tt->rj_mask)))
+ break;
+ } while ((tt = tt->rj_dupedkey));
+ /*
+ * If the mask is not duplicated, we wouldn't
+ * find it among possible duplicate key entries
+ * anyway, so the above test doesn't hurt.
+ *
+ * We sort the masks for a duplicated key the same way as
+ * in a masklist -- most specific to least specific.
+ * This may require the unfortunate nuisance of relocating
+ * the head of the list.
+ */
+ if (tt && t == saved_tt) {
+ struct radij_node *xx = x;
+ /* link in at head of list */
+ (tt = treenodes)->rj_dupedkey = t;
+ tt->rj_flags = t->rj_flags;
+ tt->rj_p = x = t->rj_p;
+ if (x->rj_l == t) x->rj_l = tt; else x->rj_r = tt;
+ saved_tt = tt; x = xx;
+ } else {
+ (tt = treenodes)->rj_dupedkey = t->rj_dupedkey;
+ t->rj_dupedkey = tt;
+ }
+#ifdef RJ_DEBUG
+ t=tt+1; tt->rj_info = rj_nodenum++; t->rj_info = rj_nodenum++;
+ tt->rj_twin = t; tt->rj_ybro = rj_clist; rj_clist = tt;
+#endif /* RJ_DEBUG */
+ t = saved_tt;
+ tt->rj_key = (caddr_t) v;
+ tt->rj_b = -1;
+ tt->rj_flags = t->rj_flags & ~RJF_ROOT;
+ }
+ /*
+ * Put mask in tree.
+ */
+ if (netmask) {
+ tt->rj_mask = netmask;
+ tt->rj_b = x->rj_b;
+ }
+ t = saved_tt->rj_p;
+ b_leaf = -1 - t->rj_b;
+ if (t->rj_r == saved_tt) x = t->rj_l; else x = t->rj_r;
+ /* Promote general routes from below */
+ if (x->rj_b < 0) {
+ if (x->rj_mask && (x->rj_b >= b_leaf) && x->rj_mklist == 0) {
+ MKGet(m);
+ if (m) {
+ Bzero(m, sizeof *m);
+ m->rm_b = x->rj_b;
+ m->rm_mask = x->rj_mask;
+ x->rj_mklist = t->rj_mklist = m;
+ }
+ }
+ } else if (x->rj_mklist) {
+ /*
+ * Skip over masks whose index is > that of new node
+ */
+ for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist)
+ if (m->rm_b >= b_leaf)
+ break;
+ t->rj_mklist = m; *mp = 0;
+ }
+ /* Add new route to highest possible ancestor's list */
+ if ((netmask == 0) || (b > t->rj_b ))
+ return 0; /* tt rgb */ /* can't lift at all */
+ b_leaf = tt->rj_b;
+ do {
+ x = t;
+ t = t->rj_p;
+ } while (b <= t->rj_b && x != top);
+ /*
+ * Search through routes associated with node to
+ * insert new route according to index.
+ * For nodes of equal index, place more specific
+ * masks first.
+ */
+ cplim = netmask + mlen;
+ for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist) {
+ if (m->rm_b < b_leaf)
+ continue;
+ if (m->rm_b > b_leaf)
+ break;
+ if (m->rm_mask == netmask) {
+ m->rm_refs++;
+ tt->rj_mklist = m;
+ return 0; /* tt rgb */
+ }
+ if (rj_refines(netmask, m->rm_mask))
+ break;
+ }
+ MKGet(m);
+ if (m == 0) {
+ printk("klips_debug:rj_addroute: "
+ "Mask for route not entered\n");
+ return 0; /* (tt) rgb */
+ }
+ Bzero(m, sizeof *m);
+ m->rm_b = b_leaf;
+ m->rm_mask = netmask;
+ m->rm_mklist = *mp;
+ *mp = m;
+ tt->rj_mklist = m;
+ return 0; /* tt rgb */
+}
+
+int
+rj_delete(v_arg, netmask_arg, head, node)
+ void *v_arg, *netmask_arg;
+ struct radij_node_head *head;
+ struct radij_node **node;
+{
+ register struct radij_node *t, *p, *x, *tt;
+ struct radij_mask *m, *saved_m, **mp;
+ struct radij_node *dupedkey, *saved_tt, *top;
+ caddr_t v, netmask;
+ int b, head_off, vlen;
+
+ v = v_arg;
+ netmask = netmask_arg;
+ x = head->rnh_treetop;
+ tt = rj_search(v, x);
+ head_off = x->rj_off;
+ vlen = *(u_char *)v;
+ saved_tt = tt;
+ top = x;
+ if (tt == 0 ||
+ Bcmp(v + head_off, tt->rj_key + head_off, vlen - head_off))
+ return -EFAULT; /* (0) rgb */
+ /*
+ * Delete our route from mask lists.
+ */
+ if ((dupedkey = tt->rj_dupedkey)) {
+ if (netmask)
+ netmask = rj_search(netmask, rj_masktop)->rj_key;
+ while (tt->rj_mask != netmask)
+ if ((tt = tt->rj_dupedkey) == 0)
+ return -ENOENT; /* -ENXIO; (0) rgb */
+ }
+ if (tt->rj_mask == 0 || (saved_m = m = tt->rj_mklist) == 0)
+ goto on1;
+ if (m->rm_mask != tt->rj_mask) {
+ printk("klips_debug:rj_delete: "
+ "inconsistent annotation\n");
+ goto on1;
+ }
+ if (--m->rm_refs >= 0)
+ goto on1;
+ b = -1 - tt->rj_b;
+ t = saved_tt->rj_p;
+ if (b > t->rj_b)
+ goto on1; /* Wasn't lifted at all */
+ do {
+ x = t;
+ t = t->rj_p;
+ } while (b <= t->rj_b && x != top);
+ for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist)
+ if (m == saved_m) {
+ *mp = m->rm_mklist;
+ MKFree(m);
+ break;
+ }
+ if (m == 0)
+ printk("klips_debug:rj_delete: "
+ "couldn't find our annotation\n");
+on1:
+ /*
+ * Eliminate us from tree
+ */
+ if (tt->rj_flags & RJF_ROOT)
+ return -EFAULT; /* (0) rgb */
+#ifdef RJ_DEBUG
+ /* Get us out of the creation list */
+ for (t = rj_clist; t && t->rj_ybro != tt; t = t->rj_ybro) {}
+ if (t) t->rj_ybro = tt->rj_ybro;
+#endif /* RJ_DEBUG */
+ t = tt->rj_p;
+ if (dupedkey) {
+ if (tt == saved_tt) {
+ x = dupedkey; x->rj_p = t;
+ if (t->rj_l == tt) t->rj_l = x; else t->rj_r = x;
+ } else {
+ for (x = p = saved_tt; p && p->rj_dupedkey != tt;)
+ p = p->rj_dupedkey;
+ if (p) p->rj_dupedkey = tt->rj_dupedkey;
+ else printk("klips_debug:rj_delete: "
+ "couldn't find us\n");
+ }
+ t = tt + 1;
+ if (t->rj_flags & RJF_ACTIVE) {
+#ifndef RJ_DEBUG
+ *++x = *t; p = t->rj_p;
+#else
+ b = t->rj_info; *++x = *t; t->rj_info = b; p = t->rj_p;
+#endif /* RJ_DEBUG */
+ if (p->rj_l == t) p->rj_l = x; else p->rj_r = x;
+ x->rj_l->rj_p = x; x->rj_r->rj_p = x;
+ }
+ goto out;
+ }
+ if (t->rj_l == tt) x = t->rj_r; else x = t->rj_l;
+ p = t->rj_p;
+ if (p->rj_r == t) p->rj_r = x; else p->rj_l = x;
+ x->rj_p = p;
+ /*
+ * Demote routes attached to us.
+ */
+ if (t->rj_mklist) {
+ if (x->rj_b >= 0) {
+ for (mp = &x->rj_mklist; (m = *mp);)
+ mp = &m->rm_mklist;
+ *mp = t->rj_mklist;
+ } else {
+ for (m = t->rj_mklist; m;) {
+ struct radij_mask *mm = m->rm_mklist;
+ if (m == x->rj_mklist && (--(m->rm_refs) < 0)) {
+ x->rj_mklist = 0;
+ MKFree(m);
+ } else
+ printk("klips_debug:rj_delete: "
+ "Orphaned Mask 0p%p at 0p%p\n", m, x);
+ m = mm;
+ }
+ }
+ }
+ /*
+ * We may be holding an active internal node in the tree.
+ */
+ x = tt + 1;
+ if (t != x) {
+#ifndef RJ_DEBUG
+ *t = *x;
+#else
+ b = t->rj_info; *t = *x; t->rj_info = b;
+#endif /* RJ_DEBUG */
+ t->rj_l->rj_p = t; t->rj_r->rj_p = t;
+ p = x->rj_p;
+ if (p->rj_l == x) p->rj_l = t; else p->rj_r = t;
+ }
+out:
+ tt->rj_flags &= ~RJF_ACTIVE;
+ tt[1].rj_flags &= ~RJF_ACTIVE;
+ *node = tt;
+ return 0; /* (tt) rgb */
+}
+
+int
+rj_walktree(h, f, w)
+ struct radij_node_head *h;
+ register int (*f)(struct radij_node *,void *);
+ void *w;
+{
+ int error;
+ struct radij_node *base, *next;
+ register struct radij_node *rn;
+
+ if(!h || !f /* || !w */) {
+ return -ENODATA;
+ }
+
+ rn = h->rnh_treetop;
+ /*
+ * This gets complicated because we may delete the node
+ * while applying the function f to it, so we need to calculate
+ * the successor node in advance.
+ */
+ /* First time through node, go left */
+ while (rn->rj_b >= 0)
+ rn = rn->rj_l;
+ for (;;) {
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_radij) {
+ printk("klips_debug:rj_walktree: "
+ "for: rn=0p%p rj_b=%d rj_flags=%x",
+ rn,
+ rn->rj_b,
+ rn->rj_flags);
+ rn->rj_b >= 0 ?
+ printk(" node off=%x\n",
+ rn->rj_off) :
+ printk(" leaf key = %08x->%08x\n",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
+ ;
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ base = rn;
+ /* If at right child go back up, otherwise, go right */
+ while (rn->rj_p->rj_r == rn && (rn->rj_flags & RJF_ROOT) == 0)
+ rn = rn->rj_p;
+ /* Find the next *leaf* since next node might vanish, too */
+ for (rn = rn->rj_p->rj_r; rn->rj_b >= 0;)
+ rn = rn->rj_l;
+ next = rn;
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_radij) {
+ printk("klips_debug:rj_walktree: "
+ "processing leaves, rn=0p%p rj_b=%d rj_flags=%x",
+ rn,
+ rn->rj_b,
+ rn->rj_flags);
+ rn->rj_b >= 0 ?
+ printk(" node off=%x\n",
+ rn->rj_off) :
+ printk(" leaf key = %08x->%08x\n",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
+ ;
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ /* Process leaves */
+ while ((rn = base)) {
+ base = rn->rj_dupedkey;
+#ifdef CONFIG_IPSEC_DEBUG
+ if(debug_radij) {
+ printk("klips_debug:rj_walktree: "
+ "while: base=0p%p rn=0p%p rj_b=%d rj_flags=%x",
+ base,
+ rn,
+ rn->rj_b,
+ rn->rj_flags);
+ rn->rj_b >= 0 ?
+ printk(" node off=%x\n",
+ rn->rj_off) :
+ printk(" leaf key = %08x->%08x\n",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
+ ;
+ }
+#endif /* CONFIG_IPSEC_DEBUG */
+ if (!(rn->rj_flags & RJF_ROOT) && (error = (*f)(rn, w)))
+ return (-error);
+ }
+ rn = next;
+ if (rn->rj_flags & RJF_ROOT)
+ return (0);
+ }
+ /* NOTREACHED */
+}
+
+int
+rj_inithead(head, off)
+ void **head;
+ int off;
+{
+ register struct radij_node_head *rnh;
+ register struct radij_node *t, *tt, *ttt;
+ if (*head)
+ return (1);
+ R_Malloc(rnh, struct radij_node_head *, sizeof (*rnh));
+ if (rnh == NULL)
+ return (0);
+ Bzero(rnh, sizeof (*rnh));
+ *head = rnh;
+ t = rj_newpair(rj_zeroes, off, rnh->rnh_nodes);
+ ttt = rnh->rnh_nodes + 2;
+ t->rj_r = ttt;
+ t->rj_p = t;
+ tt = t->rj_l;
+ tt->rj_flags = t->rj_flags = RJF_ROOT | RJF_ACTIVE;
+ tt->rj_b = -1 - off;
+ *ttt = *tt;
+ ttt->rj_key = rj_ones;
+ rnh->rnh_addaddr = rj_addroute;
+ rnh->rnh_deladdr = rj_delete;
+ rnh->rnh_matchaddr = rj_match;
+ rnh->rnh_walktree = rj_walktree;
+ rnh->rnh_treetop = t;
+ return (1);
+}
+
+void
+rj_init()
+{
+ char *cp, *cplim;
+
+ if (maj_keylen == 0) {
+ printk("klips_debug:rj_init: "
+ "radij functions require maj_keylen be set\n");
+ return;
+ }
+ R_Malloc(rj_zeroes, char *, 3 * maj_keylen);
+ if (rj_zeroes == NULL)
+ panic("rj_init");
+ Bzero(rj_zeroes, 3 * maj_keylen);
+ rj_ones = cp = rj_zeroes + maj_keylen;
+ maskedKey = cplim = rj_ones + maj_keylen;
+ while (cp < cplim)
+ *cp++ = -1;
+ if (rj_inithead((void **)&mask_rjhead, 0) == 0)
+ panic("rj_init 2");
+}
+
+void
+rj_preorder(struct radij_node *rn, int l)
+{
+ int i;
+
+ if (rn == NULL){
+ printk("klips_debug:rj_preorder: "
+ "NULL pointer\n");
+ return;
+ }
+
+ if (rn->rj_b >= 0){
+ rj_preorder(rn->rj_l, l+1);
+ rj_preorder(rn->rj_r, l+1);
+ printk("klips_debug:");
+ for (i=0; i<l; i++)
+ printk("*");
+ printk(" off = %d\n",
+ rn->rj_off);
+ } else {
+ printk("klips_debug:");
+ for (i=0; i<l; i++)
+ printk("@");
+ printk(" flags = %x",
+ (u_int)rn->rj_flags);
+ if (rn->rj_flags & RJF_ACTIVE) {
+ printk(" @key=0p%p",
+ rn->rj_key);
+ printk(" key = %08x->%08x",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr));
+ printk(" @mask=0p%p",
+ rn->rj_mask);
+ if (rn->rj_mask)
+ printk(" mask = %08x->%08x",
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_mask)->sen_ip_src.s_addr),
+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_mask)->sen_ip_dst.s_addr));
+ if (rn->rj_dupedkey)
+ printk(" dupedkey = 0p%p",
+ rn->rj_dupedkey);
+ }
+ printk("\n");
+ }
+}
+
+#ifdef RJ_DEBUG
+DEBUG_NO_STATIC void traverse(struct radij_node *p)
+{
+ rj_preorder(p, 0);
+}
+#endif /* RJ_DEBUG */
+
+void
+rj_dumptrees(void)
+{
+ rj_preorder(rnh->rnh_treetop, 0);
+}
+
+void
+rj_free_mkfreelist(void)
+{
+ struct radij_mask *mknp, *mknp2;
+
+ mknp = rj_mkfreelist;
+ while(mknp)
+ {
+ mknp2 = mknp;
+ mknp = mknp->rm_mklist;
+ kfree(mknp2);
+ }
+}
+
+int
+radijcleartree(void)
+{
+ return rj_walktree(rnh, ipsec_rj_walker_delete, NULL);
+}
+
+int
+radijcleanup(void)
+{
+ int error = 0;
+
+ error = radijcleartree();
+
+ rj_free_mkfreelist();
+
+/* rj_walktree(mask_rjhead, ipsec_rj_walker_delete, NULL); */
+ if(mask_rjhead) {
+ kfree(mask_rjhead);
+ }
+
+ if(rj_zeroes) {
+ kfree(rj_zeroes);
+ }
+
+ if(rnh) {
+ kfree(rnh);
+ }
+
+ return error;
+}
+
diff --git a/linux/net/ipsec/sysctl_net_ipsec.c b/linux/net/ipsec/sysctl_net_ipsec.c
new file mode 100644
index 000000000..b494329f6
--- /dev/null
+++ b/linux/net/ipsec/sysctl_net_ipsec.c
@@ -0,0 +1,196 @@
+/*
+ * sysctl interface to net IPSEC subsystem.
+ * Copyright (C) 1998, 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: sysctl_net_ipsec.c,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+
+/* -*- linux-c -*-
+ *
+ * Initiated April 3, 1998, Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+#include "freeswan/ipsec_param.h"
+
+#ifdef CONFIG_SYSCTL
+
+#define NET_IPSEC 2112 /* Random number */
+#ifdef CONFIG_IPSEC_DEBUG
+extern int debug_ah;
+extern int debug_esp;
+extern int debug_tunnel;
+extern int debug_eroute;
+extern int debug_spi;
+extern int debug_radij;
+extern int debug_netlink;
+extern int debug_xform;
+extern int debug_rcv;
+extern int debug_pfkey;
+extern int sysctl_ipsec_debug_verbose;
+#ifdef CONFIG_IPSEC_IPCOMP
+extern int sysctl_ipsec_debug_ipcomp;
+#endif /* CONFIG_IPSEC_IPCOMP */
+#endif /* CONFIG_IPSEC_DEBUG */
+
+extern int sysctl_ipsec_icmp;
+extern int sysctl_ipsec_inbound_policy_check;
+extern int sysctl_ipsec_tos;
+int sysctl_ipsec_regress_pfkey_lossage;
+
+enum {
+#ifdef CONFIG_IPSEC_DEBUG
+ NET_IPSEC_DEBUG_AH=1,
+ NET_IPSEC_DEBUG_ESP=2,
+ NET_IPSEC_DEBUG_TUNNEL=3,
+ NET_IPSEC_DEBUG_EROUTE=4,
+ NET_IPSEC_DEBUG_SPI=5,
+ NET_IPSEC_DEBUG_RADIJ=6,
+ NET_IPSEC_DEBUG_NETLINK=7,
+ NET_IPSEC_DEBUG_XFORM=8,
+ NET_IPSEC_DEBUG_RCV=9,
+ NET_IPSEC_DEBUG_PFKEY=10,
+ NET_IPSEC_DEBUG_VERBOSE=11,
+ NET_IPSEC_DEBUG_IPCOMP=12,
+#endif /* CONFIG_IPSEC_DEBUG */
+ NET_IPSEC_ICMP=13,
+ NET_IPSEC_INBOUND_POLICY_CHECK=14,
+ NET_IPSEC_TOS=15,
+ NET_IPSEC_REGRESS_PFKEY_LOSSAGE=16,
+};
+
+static ctl_table ipsec_table[] = {
+#ifdef CONFIG_IPSEC_DEBUG
+ { NET_IPSEC_DEBUG_AH, "debug_ah", &debug_ah,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_ESP, "debug_esp", &debug_esp,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_TUNNEL, "debug_tunnel", &debug_tunnel,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_EROUTE, "debug_eroute", &debug_eroute,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_SPI, "debug_spi", &debug_spi,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_RADIJ, "debug_radij", &debug_radij,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_NETLINK, "debug_netlink", &debug_netlink,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_XFORM, "debug_xform", &debug_xform,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_RCV, "debug_rcv", &debug_rcv,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_PFKEY, "debug_pfkey", &debug_pfkey,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_DEBUG_VERBOSE, "debug_verbose",&sysctl_ipsec_debug_verbose,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_IPSEC_IPCOMP
+ { NET_IPSEC_DEBUG_IPCOMP, "debug_ipcomp", &sysctl_ipsec_debug_ipcomp,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+#endif /* CONFIG_IPSEC_IPCOMP */
+
+#ifdef CONFIG_IPSEC_REGRESS
+ { NET_IPSEC_REGRESS_PFKEY_LOSSAGE, "pfkey_lossage",
+ &sysctl_ipsec_regress_pfkey_lossage,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+#endif /* CONFIG_IPSEC_REGRESS */
+
+#endif /* CONFIG_IPSEC_DEBUG */
+ { NET_IPSEC_ICMP, "icmp", &sysctl_ipsec_icmp,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_INBOUND_POLICY_CHECK, "inbound_policy_check", &sysctl_ipsec_inbound_policy_check,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ { NET_IPSEC_TOS, "tos", &sysctl_ipsec_tos,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ {0}
+};
+
+static ctl_table ipsec_net_table[] = {
+ { NET_IPSEC, "ipsec", NULL, 0, 0555, ipsec_table },
+ { 0 }
+};
+
+static ctl_table ipsec_root_table[] = {
+ { CTL_NET, "net", NULL, 0, 0555, ipsec_net_table },
+ { 0 }
+};
+
+static struct ctl_table_header *ipsec_table_header;
+
+int ipsec_sysctl_register(void)
+{
+ ipsec_table_header = register_sysctl_table(ipsec_root_table, 0);
+ if (!ipsec_table_header) {
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void ipsec_sysctl_unregister(void)
+{
+ unregister_sysctl_table(ipsec_table_header);
+}
+
+#endif /* CONFIG_SYSCTL */
+
+/*
+ * $Log: sysctl_net_ipsec.c,v $
+ * Revision 1.1 2004/03/15 20:35:27 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.15 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.14 2002/04/24 07:36:35 mcr
+ * Moved from ./klips/net/ipsec/sysctl_net_ipsec.c,v
+ *
+ * Revision 1.13 2002/01/12 02:58:32 mcr
+ * first regression test causes acquire messages to be lost
+ * 100% of the time. This is to help testing of pluto.
+ *
+ * Revision 1.12 2001/06/14 19:35:13 rgb
+ * Update copyright date.
+ *
+ * Revision 1.11 2001/02/26 19:58:13 rgb
+ * Drop sysctl_ipsec_{no_eroute_pass,opportunistic}, replaced by magic SAs.
+ *
+ * Revision 1.10 2000/09/16 01:50:15 rgb
+ * Protect sysctl_ipsec_debug_ipcomp with compiler defines too so that the
+ * linker won't blame rj_delete() for missing symbols. ;-> Damn statics...
+ *
+ * Revision 1.9 2000/09/15 23:17:51 rgb
+ * Moved stuff around to compile with debug off.
+ *
+ * Revision 1.8 2000/09/15 11:37:02 rgb
+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+ * IPCOMP zlib deflate code.
+ *
+ * Revision 1.7 2000/09/15 07:37:15 rgb
+ * Munged silly log comment that was causing a warning.
+ *
+ * Revision 1.6 2000/09/15 04:58:23 rgb
+ * Added tos runtime switch.
+ * Removed 'sysctl_ipsec_' prefix from /proc/sys/net/ipsec/ filenames.
+ *
+ * Revision 1.5 2000/09/12 03:25:28 rgb
+ * Filled in and implemented sysctl.
+ *
+ * Revision 1.4 1999/04/11 00:29:03 henry
+ * GPL boilerplate
+ *
+ * Revision 1.3 1999/04/06 04:54:29 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ */
diff --git a/linux/net/ipsec/tagsfile.mak b/linux/net/ipsec/tagsfile.mak
new file mode 100644
index 000000000..b2a5126a2
--- /dev/null
+++ b/linux/net/ipsec/tagsfile.mak
@@ -0,0 +1,6 @@
+TAGS:
+ etags *.c ../../include/*.h ../../include/freeswan/*.h
+ ctags *.c ../../include/*.h ../../include/freeswan/*.h
+
+
+
diff --git a/linux/net/ipv4/af_inet.c.fs2_0.patch b/linux/net/ipv4/af_inet.c.fs2_0.patch
new file mode 100644
index 000000000..bc8a5083c
--- /dev/null
+++ b/linux/net/ipv4/af_inet.c.fs2_0.patch
@@ -0,0 +1,21 @@
+RCSID $Id: af_inet.c.fs2_0.patch,v 1.1 2004/03/15 20:35:27 as Exp $
+--- ./net/ipv4/af_inet.c.preipsec Wed Jun 3 18:17:50 1998
++++ ./net/ipv4/af_inet.c Fri Sep 17 10:14:12 1999
+@@ -1146,6 +1146,17 @@
+ ip_alias_init();
+ #endif
+
++#if defined(CONFIG_IPSEC)
++ {
++ extern /* void */ int ipsec_init(void);
++ /*
++ * Initialise AF_INET ESP and AH protocol support including
++ * e-routing and SA tables
++ */
++ ipsec_init();
++ }
++#endif /* CONFIG_IPSEC */
++
+ #ifdef CONFIG_INET_RARP
+ rarp_ioctl_hook = rarp_ioctl;
+ #endif
diff --git a/linux/net/ipv4/af_inet.c.fs2_2.patch b/linux/net/ipv4/af_inet.c.fs2_2.patch
new file mode 100644
index 000000000..00c85baf3
--- /dev/null
+++ b/linux/net/ipv4/af_inet.c.fs2_2.patch
@@ -0,0 +1,21 @@
+RCSID $Id: af_inet.c.fs2_2.patch,v 1.1 2004/03/15 20:35:27 as Exp $
+--- ./net/ipv4/af_inet.c.preipsec Mon Aug 9 15:05:13 1999
++++ ./net/ipv4/af_inet.c Fri Sep 17 10:13:07 1999
+@@ -1140,6 +1140,17 @@
+ ip_mr_init();
+ #endif
+
++#if defined(CONFIG_IPSEC)
++ {
++ extern /* void */ int ipsec_init(void);
++ /*
++ * Initialise AF_INET ESP and AH protocol support including
++ * e-routing and SA tables
++ */
++ ipsec_init();
++ }
++#endif /* CONFIG_IPSEC */
++
+ #ifdef CONFIG_INET_RARP
+ rarp_ioctl_hook = rarp_ioctl;
+ #endif
diff --git a/linux/net/ipv4/af_inet.c.fs2_4.patch b/linux/net/ipv4/af_inet.c.fs2_4.patch
new file mode 100644
index 000000000..70290e3c8
--- /dev/null
+++ b/linux/net/ipv4/af_inet.c.fs2_4.patch
@@ -0,0 +1,21 @@
+RCSID $Id: af_inet.c.fs2_4.patch,v 1.1 2004/03/15 20:35:27 as Exp $
+--- ./net/ipv4/af_inet.c.preipsec Wed Apr 26 15:13:17 2000
++++ ./net/ipv4/af_inet.c Fri Jun 30 15:01:27 2000
+@@ -1019,6 +1019,17 @@
+ ip_mr_init();
+ #endif
+
++#if defined(CONFIG_IPSEC)
++ {
++ extern /* void */ int ipsec_init(void);
++ /*
++ * Initialise AF_INET ESP and AH protocol support including
++ * e-routing and SA tables
++ */
++ ipsec_init();
++ }
++#endif /* CONFIG_IPSEC */
++
+ /*
+ * Create all the /proc entries.
+ */
diff --git a/linux/net/ipv4/udp.c.fs2_2.patch b/linux/net/ipv4/udp.c.fs2_2.patch
new file mode 100644
index 000000000..767ddaa23
--- /dev/null
+++ b/linux/net/ipv4/udp.c.fs2_2.patch
@@ -0,0 +1,108 @@
+--- ./net/ipv4/udp.c Sun Mar 25 18:37:41 2001
++++ ./net/ipv4/udp.c Mon Jun 10 19:53:18 2002
+@@ -965,6 +965,9 @@
+
+ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+ {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++ struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
++#endif
+ /*
+ * Charge it to the socket, dropping if the queue is full.
+ */
+@@ -982,6 +985,38 @@
+ }
+ #endif
+
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++ if (tp->esp_in_udp) {
++ /*
++ * Set skb->sk and xmit packet to ipsec_rcv.
++ *
++ * If ret != 0, ipsec_rcv refused the packet (not ESPinUDP),
++ * restore skb->sk and fall back to sock_queue_rcv_skb
++ */
++ struct inet_protocol *esp = NULL;
++
++#ifdef CONFIG_IPSEC_MODULE
++ for (esp = (struct inet_protocol *)inet_protos[IPPROTO_ESP & (MAX_INET_PROTOS - 1)];
++ (esp) && (esp->protocol != IPPROTO_ESP);
++ esp = esp->next);
++#else
++ extern struct inet_protocol esp_protocol;
++ esp = &esp_protocol;
++#endif
++
++ if (esp && esp->handler) {
++ struct sock *sav_sk = skb->sk;
++ skb->sk = sk;
++ if (esp->handler(skb, 0) == 0) {
++ skb->sk = sav_sk;
++ /* not sure we might count ESPinUDP as UDP... */
++ udp_statistics.UdpInDatagrams++;
++ return 0;
++ }
++ skb->sk = sav_sk;
++ }
++ }
++#endif
+ if (sock_queue_rcv_skb(sk,skb)<0) {
+ udp_statistics.UdpInErrors++;
+ ip_statistics.IpInDiscards++;
+@@ -1165,6 +1200,44 @@
+ return(0);
+ }
+
++#if 1
++static int udp_setsockopt(struct sock *sk, int level, int optname,
++ char *optval, int optlen)
++{
++ struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
++ int val;
++ int err = 0;
++
++ if (level != SOL_UDP)
++ return ip_setsockopt(sk, level, optname, optval, optlen);
++
++ if(optlen<sizeof(int))
++ return -EINVAL;
++
++ if (get_user(val, (int *)optval))
++ return -EFAULT;
++
++ lock_sock(sk);
++
++ switch(optname) {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++#ifndef UDP_ESPINUDP
++#define UDP_ESPINUDP 100
++#endif
++ case UDP_ESPINUDP:
++ tp->esp_in_udp = val;
++ break;
++#endif
++ default:
++ err = -ENOPROTOOPT;
++ break;
++ }
++
++ release_sock(sk);
++ return err;
++}
++#endif
++
+ struct proto udp_prot = {
+ (struct sock *)&udp_prot, /* sklist_next */
+ (struct sock *)&udp_prot, /* sklist_prev */
+@@ -1179,7 +1252,11 @@
+ NULL, /* init */
+ NULL, /* destroy */
+ NULL, /* shutdown */
++#if 1
++ udp_setsockopt, /* setsockopt */
++#else
+ ip_setsockopt, /* setsockopt */
++#endif
+ ip_getsockopt, /* getsockopt */
+ udp_sendmsg, /* sendmsg */
+ udp_recvmsg, /* recvmsg */
diff --git a/linux/net/ipv4/udp.c.fs2_4.patch b/linux/net/ipv4/udp.c.fs2_4.patch
new file mode 100644
index 000000000..87b208bac
--- /dev/null
+++ b/linux/net/ipv4/udp.c.fs2_4.patch
@@ -0,0 +1,107 @@
+--- ./net/ipv4/udp.c 2002/02/26 14:54:22 1.2
++++ ./net/ipv4/udp.c 2002/05/22 12:14:58
+@@ -777,6 +777,9 @@
+
+ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+ {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++ struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
++#endif
+ /*
+ * Charge it to the socket, dropping if the queue is full.
+ */
+@@ -794,6 +797,38 @@
+ }
+ #endif
+
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++ if (tp->esp_in_udp) {
++ /*
++ * Set skb->sk and xmit packet to ipsec_rcv.
++ *
++ * If ret != 0, ipsec_rcv refused the packet (not ESPinUDP),
++ * restore skb->sk and fall back to sock_queue_rcv_skb
++ */
++ struct inet_protocol *esp = NULL;
++
++#ifdef CONFIG_IPSEC_MODULE
++ for (esp = (struct inet_protocol *)inet_protos[IPPROTO_ESP & (MAX_INET_PROTOS - 1)];
++ (esp) && (esp->protocol != IPPROTO_ESP);
++ esp = esp->next);
++#else
++ extern struct inet_protocol esp_protocol;
++ esp = &esp_protocol;
++#endif
++
++ if (esp && esp->handler) {
++ struct sock *sav_sk = skb->sk;
++ skb->sk = sk;
++ if (esp->handler(skb) == 0) {
++ skb->sk = sav_sk;
++ /* not sure we might count ESPinUDP as UDP... */
++ UDP_INC_STATS_BH(UdpInDatagrams);
++ return 0;
++ }
++ skb->sk = sav_sk;
++ }
++ }
++#endif
+ if (sock_queue_rcv_skb(sk,skb)<0) {
+ UDP_INC_STATS_BH(UdpInErrors);
+ IP_INC_STATS_BH(IpInDiscards);
+@@ -1010,13 +1045,55 @@
+ return len;
+ }
+
++#if 1
++static int udp_setsockopt(struct sock *sk, int level, int optname,
++ char *optval, int optlen)
++{
++ struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
++ int val;
++ int err = 0;
++
++ if (level != SOL_UDP)
++ return ip_setsockopt(sk, level, optname, optval, optlen);
++
++ if(optlen<sizeof(int))
++ return -EINVAL;
++
++ if (get_user(val, (int *)optval))
++ return -EFAULT;
++
++ lock_sock(sk);
++
++ switch(optname) {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++#ifndef UDP_ESPINUDP
++#define UDP_ESPINUDP 100
++#endif
++ case UDP_ESPINUDP:
++ tp->esp_in_udp = val;
++ break;
++#endif
++ default:
++ err = -ENOPROTOOPT;
++ break;
++ }
++
++ release_sock(sk);
++ return err;
++}
++#endif
++
+ struct proto udp_prot = {
+ name: "UDP",
+ close: udp_close,
+ connect: udp_connect,
+ disconnect: udp_disconnect,
+ ioctl: udp_ioctl,
++#if 1
++ setsockopt: udp_setsockopt,
++#else
+ setsockopt: ip_setsockopt,
++#endif
+ getsockopt: ip_getsockopt,
+ sendmsg: udp_sendmsg,
+ recvmsg: udp_recvmsg,
diff --git a/packaging/ipkg/conffiles b/packaging/ipkg/conffiles
new file mode 100644
index 000000000..ff0851c29
--- /dev/null
+++ b/packaging/ipkg/conffiles
@@ -0,0 +1 @@
+/etc/ipsec.conf
diff --git a/packaging/ipkg/control-freeswan-module.dist b/packaging/ipkg/control-freeswan-module.dist
new file mode 100644
index 000000000..aec4091f1
--- /dev/null
+++ b/packaging/ipkg/control-freeswan-module.dist
@@ -0,0 +1,8 @@
+Package: freeswan-module
+Priority: optional
+Section: Communications
+Version: VERSION
+Architecture: ARCH
+Maintainer: FreeS/WAN <users@lists.freeswan.org>
+Depends: freeswan
+Description: FreeS/WAN ipsec.o binary module
diff --git a/packaging/ipkg/control-freeswan.dist b/packaging/ipkg/control-freeswan.dist
new file mode 100644
index 000000000..376647e6f
--- /dev/null
+++ b/packaging/ipkg/control-freeswan.dist
@@ -0,0 +1,8 @@
+Package: freeswan
+Priority: optional
+Section: Communications
+Version: VERSION
+Architecture: ARCH
+Maintainer: FreeS/WAN <users@lists.freeswan.org>
+Depends: gawk libgmp
+Description: FreeS/WAN daemons and userland tools
diff --git a/packaging/ipkg/debian-binary b/packaging/ipkg/debian-binary
new file mode 100644
index 000000000..cd5ac039d
--- /dev/null
+++ b/packaging/ipkg/debian-binary
@@ -0,0 +1 @@
+2.0
diff --git a/packaging/ipkg/generate-ipkg b/packaging/ipkg/generate-ipkg
new file mode 100755
index 000000000..5a288f34e
--- /dev/null
+++ b/packaging/ipkg/generate-ipkg
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# This script expects the following variables to be in the environment:
+# DESTDIR
+# FREESWANSRCDIR
+# ARCH
+# IPSECVERSION
+
+#set -e
+
+cd $DESTDIR
+rm -f *.tar.gz
+
+mkdir -p $FREESWANSRCDIR/packaging/ipkg/ipkg
+cp $FREESWANSRCDIR/packaging/ipkg/debian-binary .
+cp $FREESWANSRCDIR/packaging/ipkg/conffiles .
+
+cat $FREESWANSRCDIR/packaging/ipkg/control-freeswan.dist | sed s/VERSION/$IPSECVERSION/ |sed s/ARCH/$ARCH/ > $FREESWANSRCDIR/packaging/ipkg/control-freeswan
+
+cp $FREESWANSRCDIR/packaging/ipkg/control-freeswan control
+
+tar -czf ./control.tar.gz ./conffiles ./control --owner=root --group=root
+
+tar -czf ./data.tar.gz ./* --owner=root --group=root --exclude=control.tar.gz --exclude=conffiles --exclude=control --exclude=debian-binary
+
+tar -czf $FREESWANSRCDIR/packaging/ipkg/ipkg/freeswan-utils-$IPSECVERSION.arm.ipk ./debian-binary ./control.tar.gz ./data.tar.gz --owner=root --group=root
+mkdir -p $FREESWANSRCDIR/packaging/ipkg/kernel-module
+cd $FREESWANSRCDIR/packaging/ipkg/kernel-module
+
+rm -f *.tar.gz
+cp $FREESWANSRCDIR/packaging/ipkg/debian-binary .
+
+cat $FREESWANSRCDIR/packaging/ipkg/control-freeswan-module.dist | sed s/VERSION/$IPSECVERSION/ |sed s/ARCH/$ARCH/ > $FREESWANSRCDIR/packaging/ipkg/control-freeswan-module
+
+cp $FREESWANSRCDIR/packaging/ipkg/control-freeswan-module control
+
+tar czf ./control.tar.gz ./control --owner=root --group=root
+
+tar czf ./data.tar.gz * --owner=root --group=root --exclude=control.tar.gz --exclude=control --exclude=debian-binary
+
+tar czf $FREESWANSRCDIR/packaging/ipkg/ipkg/freeswan-module-$IPSECVERSION.arm.ipk ./debian-binary ./control.tar.gz ./data.tar.gz --owner=root --group=root
+rm -rf $FREESWANSRCDIR/packaging/ipkg/ipkg/binaries/*
+rm -rf $FREESWANSRCDIR/packaging/ipkg/ipkg/kernel-module/*
diff --git a/packaging/linus/config-all.h b/packaging/linus/config-all.h
new file mode 100644
index 000000000..b34203372
--- /dev/null
+++ b/packaging/linus/config-all.h
@@ -0,0 +1,62 @@
+#ifndef _CONFIG_ALL_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-all.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_ALL_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+
+#endif /* _CONFIG_ALL_H */
diff --git a/packaging/makefiles/module.make b/packaging/makefiles/module.make
new file mode 100644
index 000000000..af6047362
--- /dev/null
+++ b/packaging/makefiles/module.make
@@ -0,0 +1,5 @@
+include ${FREESWANSRCDIR}/Makefile.inc
+
+KLIPS_TOP=${FREESWANSRCDIR}/linux
+VPATH+=${KLIPSSRC}
+include ${KLIPSSRC}/Makefile
diff --git a/packaging/redhat/.cvsignore b/packaging/redhat/.cvsignore
new file mode 100644
index 000000000..630b0ff36
--- /dev/null
+++ b/packaging/redhat/.cvsignore
@@ -0,0 +1,12 @@
+BUILD.athlon
+BUILD.athlon-smp
+BUILD.i386
+BUILD.i386-smp
+BUILD.i586
+BUILD.i586-smp
+BUILD.i586-up
+BUILD.i686
+BUILD.i686-smp
+rpms
+rpm.spec
+tmp.rpmbuild
diff --git a/packaging/redhat/Makefile b/packaging/redhat/Makefile
new file mode 100644
index 000000000..45f775734
--- /dev/null
+++ b/packaging/redhat/Makefile
@@ -0,0 +1,100 @@
+# FreeS/WAN RedHat RPM makefile
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=$(shell cd ../.. && pwd)
+include ${FREESWANSRCDIR}/Makefile.inc
+include ${FREESWANSRCDIR}/Makefile.ver
+
+
+# temporary directory to be used when building RPMs, and where to put the
+# resulting RPM tree
+RPMKERNDIR := $(shell echo `pwd`/tmp.rpmkernel)
+RPMTMPDIR=$(shell echo `pwd`/tmp.rpmbuild)
+RPMDEST := $(shell echo `pwd`/rpms)
+
+# definitions from main Makefile that may be relevant
+
+KERNELKLIPS=$(KERNELSRC)/net/ipsec
+KERNELCRYPTODES=$(KERNELSRC)/crypto/ciphers/des
+KERNELLIBFREESWAN=$(KERNELSRC)/lib/libfreeswan
+KERNELLIBZLIB=$(KERNELSRC)/lib/zlib
+KERNELINCLUDE=$(KERNELSRC)/include
+
+MAKEUTILS=${FREESWANSRCDIR}/packaging/utils
+ERRCHECK=${MAKEUTILS}/errcheck
+KVUTIL=${MAKEUTILS}/kernelversion
+KVSHORTUTIL=${MAKEUTILS}/kernelversion-short
+
+
+clean:
+ rm -rf $(shell echo `pwd`/BUILD.*)
+ rm -rf ${RPMTMPDIR}
+ rm -rf ${RPMDEST}
+ rm -f $(shell echo `pwd`/rpm.spec)
+
+rpm: rpm_userland rpm_modules rpm.spec final_rpm
+
+# RPM-build userland install in temporary directory
+rpm_userland: clean
+ mkdir -p $(RPMTMPDIR)
+ (cd ${FREESWANSRCDIR} && $(MAKE) programs install DESTDIR=$(RPMTMPDIR) && cd `pwd`)
+ for extras in README CHANGES ; do \
+ cp -f $(FREESWANSRCDIR)/$$extras $(RPMTMPDIR)$(FINALEXAMPLECONFDIR)/ ; \
+ done
+
+rpm_modules:
+ @if [ ! -d ${RH_KERNELSRC}/configs ]; then echo "Please fix RH_KERNELSRC in Makefile.inc (${RH_KERNELSRC})"; exit 1; fi
+ @KV=`${KVUTIL} $(RH_KERNELSRC)/Makefile | sed -e 's/custom//'` ; \
+ MD=${RPMTMPDIR}/lib/modules/$$KV/kernel/net/ipsec; mkdir -p $$MD; \
+ echo Installing into $$MD for $$KV; \
+ rm -rf BUILD.*; \
+ cat kernel-list.txt | while read kerneltype arch subarch; \
+ do \
+ mkdir -p BUILD.$$kerneltype; \
+ if [ -z "$$subarch" ]; then subarch=$$arch; fi; \
+ BUILDDIR=`pwd`/BUILD.$$kerneltype; \
+ HERE=`pwd` ;\
+ echo Building $$KV-$$kerneltype in $$BUILDDIR; \
+ ${MAKE} -C ${FREESWANSRCDIR} MODBUILDDIR=$$BUILDDIR KERNELSRC=${RH_KERNELSRC} ARCH=$$arch SUBARCH=$$subarch MODULE_DEF_INCLUDE=$$HERE/config-$$kerneltype.h module;\
+ cp $$BUILDDIR/ipsec.o $$MD/ipsec.o-$$kerneltype; \
+ goo="`nm -ao $$BUILDDIR/ipsec.o | ${FREESWANSRCDIR}/programs/calcgoo/calcgoo`"; \
+ (cd $$MD && ln -f ipsec.o-$$kerneltype $$goo); \
+ done
+
+# build spec file for building RPMs
+rpm.spec: rpm.in $(RH_KERNELSRC)/Makefile
+ KVORIG=`${KVUTIL} $(RH_KERNELSRC)/Makefile | sed -e 's/custom//'` ; \
+ KV=`echo $$KVORIG | sed -e 's/-/_/g' ` ; \
+ IPSECVERSIONFIXED=`echo ${IPSECVERSION} | sed -e 's/-/_/g'`; \
+ echo KVORIG: $$KVORIG KV: $$KV IV: $$IPSECVERSIONFIXED; \
+ sed -e "/@KERNELVERSION@/s;;$$KV;" \
+ -e "/@KERNELVERSIONORIG@/s;;$$KVORIG;" \
+ -e "/@IPSECVERSION@/s;;$$IPSECVERSIONFIXED;" \
+ -e '/@PUBDIR@/s;;$(PUBDIR);' \
+ -e '/@FINALBINDIR@/s;;$(FINALBINDIR);' \
+ -e '/@FINALLIBDIR@/s;;$(FINALLIBDIR);' \
+ -e '/@FINALCONFDDIR@/s;;$(FINALCONFDDIR);' \
+ -e '/@FINALCONFDIR@/s;;$(FINALCONFDIR);' \
+ -e '/@FINALEXAMPLECONFDIR@/s;;$(FINALEXAMPLECONFDIR);' \
+ -e '/@MANTREE@/s;;$(MANTREE);' rpm.in > rpm.spec
+
+# build RPMs
+final_rpm: rpm.spec
+ mkdir -p $(RPMDEST)
+ cd $(RPMDEST) ; mkdir -p SRPMS BUILD RPMS SPECS SOURCES
+ cd $(RPMDEST)/RPMS ; mkdir -p $(ARCH) noarch
+ $(RPMBUILD) -bb --define "buildroot $(RPMTMPDIR)" \
+ --define "_topdir $(RPMDEST)" rpm.spec
+ # that has, incidentally, gotten rid of $(RPMTMPDIR)
diff --git a/packaging/redhat/config-athlon-smp.h b/packaging/redhat/config-athlon-smp.h
new file mode 100644
index 000000000..2aa764477
--- /dev/null
+++ b/packaging/redhat/config-athlon-smp.h
@@ -0,0 +1,79 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-athlon-smp.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_ATHLON_SMP_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#define __module__smp
+#undef __module__up
+#define __module__athlon
+#define __module__athlon_smp
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_ATHLON_SMP_H_ */
+
diff --git a/packaging/redhat/config-athlon.h b/packaging/redhat/config-athlon.h
new file mode 100644
index 000000000..f9d51fc01
--- /dev/null
+++ b/packaging/redhat/config-athlon.h
@@ -0,0 +1,79 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-athlon.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_ATHLON_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#undef __module__smp
+#define __module__up
+#define __module__athlon
+#define __module__athlon_up
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_ATHLON_H_ */
+
diff --git a/packaging/redhat/config-i386-smp.h b/packaging/redhat/config-i386-smp.h
new file mode 100644
index 000000000..2971ef9e0
--- /dev/null
+++ b/packaging/redhat/config-i386-smp.h
@@ -0,0 +1,79 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-i386-smp.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_I386_SMP_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#undef __module__up
+#define __module__smp
+#define __module__i386
+#define __module__i386_smp
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_I386_SMP_H_ */
+
diff --git a/packaging/redhat/config-i386.h b/packaging/redhat/config-i386.h
new file mode 100644
index 000000000..dd6cde171
--- /dev/null
+++ b/packaging/redhat/config-i386.h
@@ -0,0 +1,79 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-i386.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_I386_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#undef __module__smp
+#define __module__up
+#define __module__i386
+#define __module__i386_up
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_I386_H_ */
+
diff --git a/packaging/redhat/config-i586-smp.h b/packaging/redhat/config-i586-smp.h
new file mode 100644
index 000000000..c56c55219
--- /dev/null
+++ b/packaging/redhat/config-i586-smp.h
@@ -0,0 +1,79 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-i586-smp.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_I586_SMP_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#undef __module__up
+#define __module__smp
+#define __module__i586
+#define __module__i586_smp
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_I586_H_ */
+
diff --git a/packaging/redhat/config-i586-up.h b/packaging/redhat/config-i586-up.h
new file mode 100644
index 000000000..54b64caf3
--- /dev/null
+++ b/packaging/redhat/config-i586-up.h
@@ -0,0 +1,79 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-i586-up.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_I586_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#undef __module__smp
+#define __module__up
+#define __module__i586
+#define __module__i586_up
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_I586_H_ */
+
diff --git a/packaging/redhat/config-i586.h b/packaging/redhat/config-i586.h
new file mode 100644
index 000000000..6877c9f92
--- /dev/null
+++ b/packaging/redhat/config-i586.h
@@ -0,0 +1,79 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-i586.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_I586_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#undef __module__smp
+#define __module__up
+#define __module__i586
+#define __module__i586_up
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_I586_H_ */
+
diff --git a/packaging/redhat/config-i686-bigmem.h b/packaging/redhat/config-i686-bigmem.h
new file mode 100644
index 000000000..4d870cbaf
--- /dev/null
+++ b/packaging/redhat/config-i686-bigmem.h
@@ -0,0 +1,78 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-i686-bigmem.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_I686_BIGMEM_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#undef __module__up
+#define __module__bigmem
+#define __module__i686_bigmem
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_I686_BIGMEM_H_ */
+
diff --git a/packaging/redhat/config-i686-smp.h b/packaging/redhat/config-i686-smp.h
new file mode 100644
index 000000000..9abd7a7d1
--- /dev/null
+++ b/packaging/redhat/config-i686-smp.h
@@ -0,0 +1,79 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-i686-smp.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_I686_SMP_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#undef __module__up
+#define __module__smp
+#define __module__i686
+#define __module__i686_smp
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_I686_SMP_H_ */
+
diff --git a/packaging/redhat/config-i686.h b/packaging/redhat/config-i686.h
new file mode 100644
index 000000000..4e4d7b292
--- /dev/null
+++ b/packaging/redhat/config-i686.h
@@ -0,0 +1,79 @@
+#ifndef _CONFIG_RH_I586_H_
+/*
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This kernel module 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/lgpl.txt>.
+ *
+ * This kernel module 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: config-i686.h,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+#define _CONFIG_RH_I686_H_ /* seen it, no need to see it again */
+
+#define CONFIG_IPSEC 1
+
+#ifndef CONFIG_IPSEC_AH
+#define CONFIG_IPSEC_AH 1
+#endif
+
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG 1
+#endif
+
+#ifndef CONFIG_IPSEC_ESP
+#define CONFIG_IPSEC_ESP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPCOMP
+#define CONFIG_IPSEC_IPCOMP 1
+#endif
+
+#ifndef CONFIG_IPSEC_IPIP
+#define CONFIG_IPSEC_IPIP 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_MD5
+#define CONFIG_IPSEC_AUTH_HMAC_MD5 1
+#endif
+
+#ifndef CONFIG_IPSEC_AUTH_HMAC_SHA1
+#define CONFIG_IPSEC_AUTH_HMAC_SHA1 1
+#endif
+
+#ifndef CONFIG_IPSEC_DYNDEV
+#define CONFIG_IPSEC_DYNDEV 1
+#endif
+
+#ifndef CONFIG_IPSEC_ENC_3DES
+#define CONFIG_IPSEC_ENC_3DES 1
+#endif
+
+#ifndef CONFIG_IPSEC_REGRESS
+#define CONFIG_IPSEC_REGRESS 0
+#endif
+
+/* keep rhconfig.h from doing anything */
+#define __rh_config_h__
+
+/* pick which arch we are supposed to be */
+#undef __module__smp
+#define __module__up
+#define __module__i686
+#define __module__i686_up
+
+#if defined(__module__smp) || defined(__module__BOOTsmp) || defined(__module__enterprise) || defined(__module__bigmem)
+#define _ver_str(x) smp_ ## x
+#else
+#define _ver_str(x) x
+#endif
+
+#define RED_HAT_LINUX_KERNEL 1
+
+#endif /* _CONFIG_RH_I686_H_ */
+
diff --git a/packaging/redhat/freeswan.spec b/packaging/redhat/freeswan.spec
new file mode 100644
index 000000000..83b59fc8c
--- /dev/null
+++ b/packaging/redhat/freeswan.spec
@@ -0,0 +1,176 @@
+Summary: FreeS/WAN IPSEC implementation
+Name: freeswan
+Version: 2.04
+%define defkv %(rpm -q --qf='%{Version}-%{Release}\\n' kernel-source|tail -1)
+# The default kernel version to build for is the latest of
+# the installed kernel-source RPMs.
+# This can be overridden by "--define 'kversion x.x.x-y.y.y'"
+%{!?kversion: %{expand: %%define kversion %defkv}}
+%define krelver %(echo %{kversion} | tr -s '-' '_')
+# FreeS/WAN -pre/-rc nomenclature has to co-exist with hyphen paranoia
+%define srcpkgver %(echo %{version} | tr -s '_' '-')
+%define our_release 1fs
+%define debug_package %{nil}
+Release: %{our_release}
+License: GPL
+Url: http://www.freeswan.org/
+Source: freeswan-%{srcpkgver}.tar.gz
+Group: System Environment/Daemons
+BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root
+%define __spec_install_post /usr/lib/rpm/brp-compress || :
+BuildRequires: kernel-source = %{kversion}
+
+%package userland
+Summary: FreeS/WAN IPSEC usermod tools
+Group: System Environment/Daemons
+Provides: ipsec-userland
+Obsoletes: freeswan
+Requires: ipsec-kernel
+Release: %{our_release}
+
+%package doc
+Summary: FreeS/WAN IPSEC full documentation
+Group: System Environment/Daemons
+Release: %{our_release}
+
+%package module
+Summary: FreeS/Wan kernel module
+Group: System Environment/Kernel
+Release: %{krelver}_%{our_release}
+Provides: ipsec-kernel
+Requires: kernel = %{kversion}
+# do not make the dependancy circular for now.
+#Requires: ipsec-userland
+
+%description userland
+FreeS/WAN is a free implementation of IPSEC & IKE for Linux. IPSEC is
+the Internet Protocol Security and uses strong cryptography to provide
+both authentication and encryption services. These services allow you
+to build secure tunnels through untrusted networks. Everything passing
+through the untrusted net is encrypted by the ipsec gateway machine and
+decrypted by the gateway at the other end of the tunnel. The resulting
+tunnel is a virtual private network or VPN.
+
+This package contains the daemons and userland tools for setting up
+FreeS/WAN on a freeswan enabled kernel.
+
+%description module
+This package contains only the ipsec module for the RedHat series of kernels.
+
+%description doc
+This package contains extensive documentation of the FreeeS/WAN IPSEC
+system.
+
+%description
+A dummy package that installs userland and kernel pieces.
+
+%prep
+%setup -q -n freeswan-%{srcpkgver}
+
+%build
+%{__make} \
+ USERCOMPILE="-g %{optflags}" \
+ INC_USRLOCAL=%{_prefix} \
+ MANTREE=%{_mandir} \
+ INC_RCDEFAULT=%{_initrddir} \
+ programs
+FS=$(pwd)
+mkdir -p BUILD.%{_target_cpu}
+mkdir -p BUILD.%{_target_cpu}-smp
+
+cd packaging/redhat
+for smp in -smp ""
+do
+%{__make} -C $FS MODBUILDDIR=$FS/BUILD.%{_target_cpu}$smp \
+ FREESWANSRCDIR=$FS \
+ KERNELSRC=/usr/src/linux-%{kversion} \
+ ARCH=%{_arch} \
+ SUBARCH=%{_arch} \
+ MODULE_DEF_INCLUDE=$FS/packaging/redhat/config-%{_target_cpu}$smp.h \
+ module
+done
+
+%install
+%{__make} \
+ DESTDIR=%{buildroot} \
+ INC_USRLOCAL=%{_prefix} \
+ MANTREE=%{buildroot}%{_mandir} \
+ INC_RCDEFAULT=%{_initrddir} \
+ install
+install -d -m700 %{buildroot}%{_localstatedir}/run/pluto
+install -d %{buildroot}%{_sbindir}
+
+mkdir -p %{buildroot}/lib/modules/%{kversion}/kernel/net/ipsec
+cp BUILD.%{_target_cpu}/ipsec.o \
+ %{buildroot}/lib/modules/%{kversion}/kernel/net/ipsec
+
+mkdir -p %{buildroot}/lib/modules/%{kversion}smp/kernel/net/ipsec
+cp BUILD.%{_target_cpu}-smp/ipsec.o \
+ %{buildroot}/lib/modules/%{kversion}smp/kernel/net/ipsec
+
+%clean
+rm -rf ${RPM_BUILD_ROOT}
+
+%files doc
+%defattr(-,root,root)
+%doc doc
+%doc %{_defaultdocdir}/freeswan/ipsec.conf-sample
+
+%files userland
+%defattr(-,root,root)
+%doc BUGS CHANGES COPYING
+%doc CREDITS INSTALL README
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipsec.conf
+%attr(0700,root,root) %dir %{_sysconfdir}/ipsec.d
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipsec.d/policies/*
+%config(noreplace) %{_initrddir}/ipsec
+%{_libdir}/ipsec
+%{_sbindir}/ipsec
+%{_libexecdir}/ipsec
+%doc %{_mandir}/*/*
+%{_localstatedir}/run/pluto
+
+%files module
+%defattr (-,root,root)
+/lib/modules/%{kversion}/kernel/net/ipsec
+/lib/modules/%{kversion}smp/kernel/net/ipsec
+
+%pre userland
+%preun userland
+if [ $1 = 0 ]; then
+ /sbin/service ipsec stop || :
+ /sbin/chkconfig --del ipsec
+fi
+
+%postun userland
+if [ $1 -ge 1 ] ; then
+ /sbin/service ipsec stop 2>&1 > /dev/null && /sbin/service ipsec start 2>&1 > /dev/null || :
+fi
+
+%postun module
+%post module
+
+%post userland
+chkconfig --add ipsec
+
+%changelog
+* Fri Aug 22 2003 Sam Sgro <sam@freeswan.org>
+- Juggling release/source package names to allow for
+ -pre/-rc releases to build.
+
+* Thu Aug 14 2003 Sam Sgro <sam@freeswan.org>
+- Reverting back to pre-x.509 version, cosmetic changes.
+
+* Tue May 20 2003 Charlie Brady <charlieb@e-smith.com> 2.0.0-x509_1.3.2_2es
+- Add "Obsoletes: freeswan" to userland RPM.
+
+* Fri May 16 2003 Charlie Brady <charlieb@e-smith.com> 2.0.0-x509_1.3.2_1es
+- Add version 1.3.2 of the x509 patch.
+- Add missing /usr/libexec/ipsec dir and files.
+- Minor tidy up of spec file.
+
+* Thu May 15 2003 Charlie Brady <charlieb@e-smith.com> 2.0.0-1es
+- Based on work by Paul Lahaie of Steamballoon, Michael
+ Richardson of freeS/WAN team and Tuomo Soini <tis@foobar.fi>.
+- Build freeswan RPMs from a single source RPM, for RedHat, but
+ should work on any RPM based system.
diff --git a/packaging/redhat/kernel-list.txt b/packaging/redhat/kernel-list.txt
new file mode 100644
index 000000000..e24d827e1
--- /dev/null
+++ b/packaging/redhat/kernel-list.txt
@@ -0,0 +1,9 @@
+athlon-smp i386 i386
+athlon i386 i386
+i386-smp i386 i386
+i386 i386 i386
+i586-smp i386 i386
+i586 i386 i386
+i686-smp i386 i386
+i686-bigmem i386 i386
+i686 i386 i386
diff --git a/packaging/redhat/rpm.in b/packaging/redhat/rpm.in
new file mode 100644
index 000000000..4ede8ebc5
--- /dev/null
+++ b/packaging/redhat/rpm.in
@@ -0,0 +1,149 @@
+# fairly minimal RPM spec file, does only packaging
+# Based on work by Paul Lahaie of Steamballoon.
+# This file is touched up by sed (in the Makefile) before it is actually used.
+Summary: Kernel with FreeS/WAN
+Name: freeswan
+Version: @IPSECVERSION@_@KERNELVERSION@
+Release: 0
+Copyright: GPL
+Source: freeswan-%{version}.tar.gz
+Group: System Environment/Daemons
+BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root
+%define __spec_install_post /usr/lib/rpm/brp-compress || :
+%define KernelVer @KERNELVERSIONORIG@
+Requires: ipsec-userland ipsec-kernel
+
+%package userland
+Summary: Kernel with FreeS/WAN
+Group: System Environment/Daemons
+Provides: ipsec-userland
+Requires: ipsec-kernel
+
+%package module
+Summary: FreeS/Wan kernel module
+Group: System Environment/Kernel
+Provides: ipsec-kernel
+# do not make the dependancy circular for now.
+#Requires: ipsec-userland
+
+%description userland
+This package contains the daemons and userland tools for setting up
+FreeS/WAN on a freeswan enabled kernel.
+
+%description module
+This package contains only the ipsec module for the RedHat series of kernels.
+
+%description
+A dummy package that installs userland and kernel pieces.
+
+%prep
+
+%build
+
+%install
+
+%clean
+rm -rf ${RPM_BUILD_ROOT}
+
+%files userland
+%defattr(-,root,root)
+@PUBDIR@/ipsec
+@FINALBINDIR@/*
+@FINALLIBDIR@/*
+/etc/rc.d/init.d/ipsec
+
+%attr(0644,root,root) %config @FINALCONFDIR@/ipsec.conf
+%attr(0644,root,root) %config @FINALCONFDDIR@/policies/clear
+%attr(0644,root,root) %config @FINALCONFDDIR@/policies/private
+%attr(0644,root,root) %config @FINALCONFDDIR@/policies/block
+%attr(0644,root,root) %config @FINALCONFDDIR@/policies/private-or-clear
+%attr(0644,root,root) %config @FINALCONFDDIR@/policies/clear-or-private
+
+%doc @MANTREE@/man3/*
+%doc @MANTREE@/man5/*
+%doc @MANTREE@/man8/*
+%doc @FINALEXAMPLECONFDIR@/*
+
+%files module
+%defattr (-,root,root)
+/lib/modules/%{KernelVer}/kernel/net/ipsec
+
+%pre userland
+if [ -f /etc/ipsec.conf ]
+then
+ cp -f --backup=t /etc/ipsec.conf /etc/ipsec.conf.prerpm > /dev/null 2> /dev/null
+fi
+
+%preun userland
+sh /etc/rc.d/init.d/ipsec stop || exit 0
+
+%postun module
+# This is a kludge to handle the fact that ipsec.o is not deleted
+# on plain jane RPM uninstall.
+for i in /lib/modules/*@KERNELVERSIONORIG@*
+ do
+ mv -f --backup=t "$i"/kernel/net/ipsec/ipsec.o "$i"/kernel/net/ipsec/ipsec.o.rpmbak > /dev/null 2> /dev/null
+ done || exit 0
+
+%post module
+# Same RPM uninstall kludge.
+for i in /lib/modules/*@KERNELVERSIONORIG@*
+ do
+ mv -f --backup=t "$i"/kernel/net/ipsec/ipsec.o "$i"/kernel/net/ipsec/ipsec.o.rpmbak > /dev/null 2> /dev/null
+ done
+echo "do not forget to install the userland utilities"
+exit 0
+
+%post userland
+chkconfig --add ipsec
+echo "invoke \"service ipsec start\" or reboot to begin"
+
+%changelog
+#
+# $Log: rpm.in,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.6 2003/01/30 23:31:34 sam
+#
+# dhr contributed changes. still may need modification, but I'm committing
+# before I leave.
+#
+# Revision 1.5 2003/01/14 22:03:44 sam
+# include policy files in RPM.
+#
+# Revision 1.4 2003/01/04 07:38:11 build
+# *** empty log message ***
+#
+# Revision 1.3 2002/12/12 05:45:41 sam
+# new template file from 1.99 pulled up in part
+#
+# Revision 1.2.2.1 2002/12/07 23:47:22 sam
+# merging in a few 1.99 rpm.in changes.
+#
+# Revision 1.2 2002/10/30 06:54:15 sam
+# Updates to take into account lib vs libexec - so we don't miss files.
+#
+# Revision 1.1 2002/10/06 08:35:54 sam
+# RPM template
+#
+# Revision 1.9 2002/06/16 21:53:49 mcr
+# added missing clauses to userland section.
+#
+# Revision 1.8 2002/06/16 20:18:41 mcr
+# 2.00 series RPM will have a "freeswan-userland" rather than
+# a "freeswan-X" RPM. Among other things, it makes regexp easier
+# to locate the different pieces.
+#
+# Revision 1.7 2002/06/11 23:10:53 mcr
+# added dependancies from userland->kernel.
+# cross-dependancies considered but cause too much user pain.
+#
+# Revision 1.6 2002/06/09 15:46:41 mcr
+# move installed modules for make rpm to kernel versioned directory.
+#
+# Revision 1.5 2002/04/11 02:50:30 mcr
+# added %post to make ipsec start, and %post to shut it down.
+# added %changelog as well.
+#
+#
diff --git a/packaging/utils/backup b/packaging/utils/backup
new file mode 100755
index 000000000..0c860c280
--- /dev/null
+++ b/packaging/utils/backup
@@ -0,0 +1,80 @@
+#! /bin/sh
+# make backup of FreeSwan repository
+# -l local build only, do not transmit
+
+#scphost=freeswan@xs1.xs4all.nl
+scphost=henry@adams.freeswan.org
+scpdir=backup
+pfile=~freeswan/etc/relpass
+ppfile=~freeswan/etc/bpp
+
+PATH=/bin:/usr/bin
+export PATH
+umask 077
+
+tmpdir=~freeswan/tmp
+tarname=freeswan.tar
+
+. ~freeswan/setup
+
+cd $tmpdir
+rm -f $tarname $tarname.gz
+touch $tarname
+
+cd ~freeswan
+tar -cf $tmpdir/$tarname `ls -a |
+ egrep -v '^(\.|\.\.|archive|\.nobak|\.ssh|\.ssh2|tmp)$'`
+
+cd $tmpdir
+gzip -9 $tarname
+ls -l $tarname.gz
+
+if test " $1" = " -l"
+then
+ exit 0
+fi
+
+echo updating >notice
+
+date
+expect -nN -c "
+ set scphost $scphost
+ set scpdir $scpdir
+ set pfile $pfile
+ set ppfile $ppfile
+ set tarname $tarname
+ "'
+ # canned procedure for scp copying
+ proc scp {from to} {
+ global p scphost scpdir
+ spawn scp2 -p -q $from $scphost:$scpdir/$to
+ set timeout -1
+ expect {
+ "word:" {
+ set fname $pfile
+ # fall out
+ }
+ {":} {
+ set fname $ppfile
+ # fall out
+ }
+ eof {
+ puts "eofed!"
+ return
+ }}
+ sleep 3
+ set f [open $fname r]
+ set p [read $f]
+ close $f
+ send "$p\r"
+ expect "\n"
+ expect eof
+ wait
+ }
+
+ scp notice $tarname.gz
+ scp $tarname.gz $tarname.gz
+ # done'
+date
+
+rm -f $tarname.gz
diff --git a/packaging/utils/branch b/packaging/utils/branch
new file mode 100755
index 000000000..2c13d4b6a
--- /dev/null
+++ b/packaging/utils/branch
@@ -0,0 +1,70 @@
+#! /bin/sh
+# branch release
+
+PATH=/bin:/usr/bin ; export PATH
+umask 022
+
+. $HOME/freeswan-regress-env.sh
+
+case "$1" in
+*.*) ;;
+*) echo "Usage: $0 release [file...]" >&2 ; exit 2 ;;
+esac
+
+rel="$1"
+shift
+tr="`echo $rel | tr '.' '_'`"
+pre=PRE$tr
+base=BASE$pre
+
+echo "generating key for branch"
+SNAPPGP=$SNAPSHOTSIGDIR/$base
+# Note: PGPPATH is limited to 50 characters.
+PGPPATH=$SNAPPGP export PGPPATH
+mkdir -p $PGPPATH
+touch $PGPPATH/pgpdoc1.txt
+touch $PGPPATH/pgpdoc2.txt
+
+if [ ! -f $PGPPATH/secring.pgp ]
+then
+ echo "Please set userid to '<build+snap$tr@freeswan.org>'$PGPPATH"
+ pgp -kg
+
+ echo -n "Please insert release key floppy for signature"
+ read ans
+ mount /mnt/build
+ PGPPATH=/mnt/build/freeswan export PGPPATH
+
+ echo "Now signing key - please answer yes."
+ pgp $SNAPPGP/pubring.pgp
+
+ echo Please put key in $SNAPPGP/signedkey.asc
+ pgp -kxa build+snap$tr@freeswan.org
+
+ umount /mnt/build
+
+fi
+
+if [ ! -f snapshotsigs.pgp ]
+then
+ PGPPATH=$SNAPPGP export PGPPATH
+ echo "Now importing key"
+ pgp $SNAPPGP/signedkey.asc
+
+ cp $SNAPPGP/signedkey.asc snapshotsigs.pgp
+ cvs add snapshotsigs.pgp
+ cvs commit -m"Signing key for $rel" snapshotsigs.pgp
+fi
+
+echo -n "PGP finished, now budding, press enter"
+read ans
+
+echo "budding..."
+rm -f Makefile.ver
+cvs tag $opt -c $base $*
+echo
+echo "branching..."
+cvs tag $opt -b -r $base $pre $*
+
+
+
diff --git a/packaging/utils/canrel b/packaging/utils/canrel
new file mode 100755
index 000000000..567ce96a8
--- /dev/null
+++ b/packaging/utils/canrel
@@ -0,0 +1,55 @@
+#! /bin/sh
+# canrel [-F] release
+# -F means override previous run
+# current versions in the repository are used
+# must be run in a release-branch CVS working directory with current top/*
+
+PATH=/bin:/usr/bin ; export PATH
+umask 022
+
+. ~build/freeswan-regress-env.sh
+
+opt=
+case "$1" in
+-F) opt=-F ; shift ;;
+esac
+
+case "$#:$1" in
+1:*.*) ;;
+*) echo "Usage: $0 release" >&2 ; exit 2 ;;
+esac
+
+rel="$1"
+pretag="PRE`echo $rel | tr '.' '_'`"
+rtag="R`echo $rel | tr '.' '_'`"
+
+sed '1s/xxx/'"$rel"'/' README >README.$$
+if cmp -s README README.$$
+then
+ : already current, for some reason
+ rm -f README.$$
+else
+ mv README.$$ README
+ cvs -Q commit -m "update for release $rel" README
+fi
+sed '/=.*/s//='"$rel"'/' Makefile.ver >mversion.$$
+if cmp -s Makefile.ver mversion.$$
+then
+ : already current, for some reason
+ rm -f mversion.$$
+else
+ mv mversion.$$ Makefile.ver
+ cvs -Q commit -m "update for release $rel" Makefile.ver
+fi
+sed '1s/xxx/'"$rel"'/' CHANGES >CHANGES.$$
+if cmp -s CHANGES CHANGES.$$
+then
+ : already current, for some reason
+ rm -f CHANGES.$$
+else
+ mv CHANGES.$$ CHANGES
+ cvs -Q commit -m "update for release $rel" CHANGES
+fi
+cd ..
+
+cvs rtag $opt -r $pretag $rtag all
diff --git a/packaging/utils/disttools.pl b/packaging/utils/disttools.pl
new file mode 100644
index 000000000..4ea8db61d
--- /dev/null
+++ b/packaging/utils/disttools.pl
@@ -0,0 +1,357 @@
+#!/usr/bin/perl
+
+#
+# $Id: disttools.pl,v 1.1 2004/03/15 20:35:27 as Exp $
+#
+# $Log: disttools.pl,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.13 2003/06/17 22:30:06 build
+# adjusted userid to pick
+# use key that is offline.
+#
+# Revision 1.12 2002/09/30 16:02:17 mcr
+# added handling for date stamp.
+#
+# Revision 1.11 2002/08/30 01:30:25 mcr
+# changed code to write maintain local copy of FTP site,
+# and rsync things up when needed.
+#
+# Revision 1.10 2002/07/29 05:13:33 mcr
+# append .gz to patch files before they are signed.
+#
+# Revision 1.9 2002/07/29 04:02:21 mcr
+# removed errant ) from tar copy line.
+#
+# Revision 1.8 2002/07/29 03:57:59 mcr
+# produce kernel patches as part of the snapshots, candidates
+# and releases.
+#
+# Revision 1.7 2002/06/07 18:23:49 mcr
+# adjusted sendfiles to use tar to copy rather than scp.
+# mkcand now prints usage if you don't give it enough arguments.
+# It also now updates the "CANDIDATE" symlink.
+# mksnap properly quotes the wildcards in the -name for find.
+#
+# Revision 1.6 2002/06/03 03:10:58 mcr
+# "upload" now takes argument to indicate name to
+# install/upload for the symlink.
+#
+# Revision 1.5 2002/06/03 02:19:40 mcr
+# fixed bug in datelettername() - y/sed was not applied to $let,
+# but to $_.
+#
+# Revision 1.4 2002/06/03 02:14:16 mcr
+# die statements are now numbered for easier backtracking.
+# candidate checks are now done if $candidate arg=1: edit README
+# and CHANGES file for mkcand.
+#
+# Revision 1.3 2002/05/30 23:24:22 mcr
+# working "mksnap" and disttools.pl.
+#
+# Revision 1.2 2002/05/30 22:20:56 mcr
+# initial debugging done.
+#
+# Revision 1.1 2002/05/30 21:24:00 mcr
+# perl-ified mksnap.
+#
+#
+
+@supportedkernels=("2.0", "2.2", "2.4");
+
+sub nicesystem {
+ if($debug) {
+ print STDERR "System: ",join(' ',@_)."\n";
+ }
+ system(@_);
+ if($? == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+sub kpatchname {
+ local($pkgname, $ver)=@_;
+ local($name);
+
+ $name = $pkgname.".k".$ver.".patch";
+ return $name;
+}
+
+
+sub datelettername {
+ @MoY = ('jan','feb','mar','apr','may','jun',
+ 'jul','aug','sep','oct','nov','dec');
+
+ $letters="abcdefghjklmnpqrstuvwxyz";
+
+ ($sec, $min, $hour, $mday, $mon, $year) = gmtime(time);
+
+ $let=substr($letters, $hour-1, 1);
+ if($min >= 30) {
+ $let =~ y/a-z/A-Z/;
+ }
+
+ if($year < 1900) {
+ $year += 1900;
+ }
+
+ $ver=sprintf("%04d%s%02d%s", $year, $MoY[$mon], $mday, $let);
+ $ver;
+}
+
+sub snapname {
+ local($prefix)=@_;
+ $snapname=$prefix.&datelettername;
+ $snapname;
+}
+
+sub suckvars {
+ $envvar=$ENV{'HOME'}."/freeswan-regress-env.sh";
+
+ if(-f $envvar) {
+
+ open(SHVARS, $envvar) || die "001: Can not open $envvar: $!\n";
+ while(<SHVARS>) {
+ chop;
+ next if (/^\#/);
+
+ if(/(\S+)\=(\S+)/) {
+ $var=$1;
+ $value=$2;
+
+ $ENV{$var}=$value;
+ }
+ }
+ close(SHVARS);
+ }
+}
+
+sub defvar {
+ local($var,$value)=@_;
+
+ if(!defined($ENV{$var})) {
+ $ENV{$var}=$value;
+ }
+}
+
+sub defvars {
+ &defvar('BTMP', '/btmp');
+ if($ENV{'DEBUGFREESWANDIST'}) {
+ $debug=$ENV{'DEBUGFREESWANDIST'};
+ }
+}
+
+sub setuppgp {
+ local($lastrel)=@_;
+
+ $lastrel =~ y/\./\_/;
+
+ $ENV{'PGPPATH'}=$ENV{'SNAPSHOTSIGDIR'}."/BASEPRE$lastrel";
+ $ENV{'PGPNAME'}="build+snap".$lastrel."\@freeswan.org";
+}
+
+sub dopgpsig {
+ local($pkgname)=@_;
+
+ local($tarfile);
+ $tarfile=$pkgname.".tar";
+
+ $userid=$ENV{'PGPNAME'};
+ &nicesystem("pgp -sba $tarfile.gz -u $userid -o $tarfile.gz.sig") || die "002: PGP failed: $?\n";
+ &nicesystem("chmod a+r $tarfile.gz.sig");
+
+ foreach $ver (@supportedkernels) {
+ $file=&kpatchname($pkgname,$ver).".gz";
+ &nicesystem("pgp -sba $file -u $userid -o $file.sig") || die "002: PGP failed: $?\n";
+ &nicesystem("chmod a+r $file.sig");
+ }
+}
+
+
+# this function now does two things:
+# 1) makes the tar file of old
+# 2) makes the kernel patch file of new.
+#
+
+sub makedisttarfile {
+ local($tmpdir, $pkgname, $vername, $dirname, $date, $relopt, $candidate)=@_;
+ local($file);
+
+ &nicesystem("mkdir -p $tmpdir") || die "003: Can not mkdir $tmpdir\n";
+ chdir($tmpdir) || die "004: makedisttarfile: Can not chdir to $tmpdir\n";
+
+ # nuke anything that was there before
+ &nicesystem("rm -rf $dirname");
+
+ if(defined($date) && $date ne '') {
+ $minusD="-D \"${date}\"";
+ }
+
+ print "cvs -Q export $minusD ${relopt} -d ${dirname} freeswan\n";
+
+ &nicesystem("cvs -Q export $minusD ${relopt} -d ${dirname} freeswan") || die "005: CVS failed!\n";
+
+ chdir($dirname) || die "006: Can not chdir to $dirname\n";
+
+ open(VERSIONFILE, ">Makefile.ver") || die "007: failed to open Makefile.ver\n";
+ print VERSIONFILE "IPSECVERSION=".$vername."\n";
+ close(VERSIONFILE);
+
+ if($candidate) {
+ open(README, "README") || die "008: Can not edit README: $!\n";
+ $nreadme="README.$$";
+ open(NREADME, ">$nreadme") || die "009: Can not write README: $!\n";
+ $lines=1;
+ while(<README>) {
+ if($lines == 1) {
+ s/xxx/$vername/;
+ }
+# if(/^---$/) {
+# print STDERR "README not ready, run prepcand first\n";
+# die;
+# }
+ $lines++;
+ print NREADME;
+ }
+ close(NREADME);
+ close(README);
+ unlink("README") || die "010: Can not remove README: $!\n";
+ rename("$nreadme", "README") || die "011: Can not rename $nreadme to README: $!\n";
+
+ # now edit CHANGES file
+ open(CHANGES, "CHANGES") || die "012: Can not edit README: $!\n";
+ $nchanges="CHANGES.$$";
+ open(NCHANGES,">$nchanges") || die "013: Can not write README: $!\n";
+ $lines=1;
+ while(<CHANGES>) {
+ if($lines == 1) {
+ if(/since last release/) {
+ die "CHANGES not ready, run prepcand first";
+ }
+ s/xxx/$vername/;
+ }
+ $lines++;
+ print NCHANGES;
+ }
+ close(NCHANGES);
+ close(CHANGES);
+ unlink("CHANGES") || die "014: Can not remove CHANGES: $!\n";
+ rename("$nchanges", "CHANGES") || die "015: Can not rename $nreadme to README: $!\n";
+ }
+
+ &nicesystem("make -f dtrmakefile -s snapready") || die "016: failed to make snapshot ready for distribution: $?\n";
+
+ chdir("..") || die "017: failed to go to parent dir: $!\n";
+
+ unlink("$pkgname.tar");
+ unlink("$pkgname.tar.gz");
+ unlink("$pkgname.tar.gz.md5");
+
+ &nicesystem("tar -cf $pkgname.tar $dirname") || die "018: Failed to tar file: $?\n";
+
+ # make the kernelpatch for each of 2.0, 2.2, and 2.4.
+ foreach $ver (@supportedkernels) {
+ $file=&kpatchname($pkgname,$ver);
+ &nicesystem("make -C $dirname kernelpatch$ver >$file");
+ &nicesystem("gzip -9 $file");
+ }
+
+ &nicesystem("rm -rf $dirname") || warn "failed to cleanup $dirname\n";
+
+ &nicesystem("gzip -9 $pkgname.tar") || die "019: gzip died: $?\n";
+
+ &nicesystem("ls -l $pkgname.tar.gz");
+
+ &nicesystem("md5sum $pkgname.tar.gz >$pkgname.tar.gz.md5");
+ &nicesystem("chmod a+r $pkgname.tar.gz");
+}
+
+sub sendfiles {
+ local(@thefiles)=@_;
+
+ local($file, $localroot);
+
+if($ENV{'DEV_DIR'}) { $localroot=$ENV{'DEV_DIR'}; } else { $localroot=$ENV{'LOCAL_ARCHIVE'}; }
+
+ foreach $file (@thefiles) {
+ $dir=$file;
+ if(!($dir =~ s,(.*)/([^/]*),\1,)) {
+ $dir=".";
+ } else {
+ $file=$2;
+ }
+
+ &nicesystem("tar -C $dir -c -f - $file | tar -C ${localroot} -x -f -");
+ }
+}
+
+
+sub remotecmd {
+ local($cmd)=@_;
+
+ $distuser=$ENV{'DISTUSER'};
+ $disthost=$ENV{'DISTHOST'};
+ $distdir =$ENV{'DISTDIR'};
+ $ssh =$ENV{'ssh'};
+
+ &nicesystem("$ssh -l $distuser $disthost '$cmd'");
+}
+
+
+sub upload {
+ local($pkgname, $symlinkname)=@_;
+
+ local($localroot);
+
+if($ENV{'DEV_DIR'}) { $localroot=$ENV{'DEV_DIR'}; } else { $localroot=$ENV{'LOCAL_ARCHIVE'}; }
+
+ &sendfiles("$pkgname.tar.gz",
+ "$pkgname.tar.gz.sig",
+ "$pkgname.tar.gz.md5");
+
+ foreach $ver (@supportedkernels) {
+ $file=&kpatchname($pkgname,$ver).".gz";
+ &sendfiles($file, "$file.sig");
+ }
+
+ if(defined($symlinkname)) {
+ &sendfiles($symlinkname.".tar.gz.md5");
+ &nicesystem("cd $localroot && ln -f -s $pkgname.tar.gz $symlinkname.tar.gz && ln -f -s $pkgname.tar.gz.sig $symlinkname.tar.gz.sig");
+
+ foreach $ver (@supportedkernels) {
+ $file=&kpatchname($pkgname,$ver);
+ $newname=&kpatchname($symlinkname,$ver);
+ &nicesystem("cd $localroot && ln -f -s $file.gz $newname.gz && ln -f -s $file.gz.sig $newname.gz.sig");
+ }
+
+ }
+}
+
+sub upsync {
+
+ local($localroot, $distuser, $disthost, $distdir, $spoolhost, $spooluser);
+ local($masterhost, $masteruser, $masterdir);
+
+ $localroot=$ENV{'LOCAL_ARCHIVE'};
+ $distuser=$ENV{'DISTUSER'};
+ $disthost=$ENV{'DISTHOST'};
+ $distdir =$ENV{'DISTDIR'};
+ $ssh =$ENV{'ssh'};
+ $masterhost = $ENV{'MASTERHOST'};
+ $masteruser = $ENV{'MASTERUSER'};
+ $masterdir = $ENV{'MASTERDIR'};
+
+ # sync stuff to distribution site.
+ &nicesystem("rsync -e $ssh -r --delete -a -v -c $localroot/ $masteruser\@$masterhost:$masterdir/");
+
+ # sync stuff to xs4all site.
+ &nicesystem(print "rsync -e $ssh -r --delete -a -v -c $localroot/ $distuser\@$disthost:$distdir/");
+ &nicesystem("rsync -e $ssh -r --delete -a -v -c $localroot/ $distuser\@$disthost:$distdir/");
+
+}
+
+1;
+
diff --git a/packaging/utils/errcheck b/packaging/utils/errcheck
new file mode 100755
index 000000000..1a1ab5037
--- /dev/null
+++ b/packaging/utils/errcheck
@@ -0,0 +1,40 @@
+#! /bin/sh
+# internal utility for testing kernel make output for errors
+# Copyright (C) 1998, 1999 Henry Spencer.
+#
+# 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: errcheck,v 1.1 2004/03/15 20:35:27 as Exp $
+
+# the errors.[och] stuff is for math emulation
+# the HiSax nonsense is due to a Red Hat 5.2 botch
+# RH7.2 "make dep" builds stuff in drivers/macintosh (!!) using <asm/init.h>
+# Red Hat's 2.2.19 whines about function read_rx_long_length_errors in e100.c
+# 2.4.18: 53c700.h:40:2: #error "Config.in must define either CONFIG_53C700_IO_MAPPED or CONFIG_53C700_MEM_MAPPED to use this scsi core."
+oops="`sed -e 's/-Werror/-Weror/g' \
+ -e '/errors*\.[och]/s/errors*\./eror./g' \
+ -e '/scsi_error/s//scsi_eror/' \
+ -e '/KBUILD_BASENAME=errors/s/errors/eror/g' \
+ -e '/#error .HiSax: No cards configured/s/error/eror/' \
+ -e '/#error .<asm.init.h> should never be used/s/error/eror/' \
+ -e '/53c700.h:[0-9:]* #error "Config.in must define either CONFIG_53C700_IO_MAPPED or CONFIG_53C700_MEM_MAPPED to use this scsi core."/s/error/eror/' \
+ -e '/^e100.c: In function/s/length_errors/length_erors/' $* |
+ egrep -i 'error|\*\*\*' | egrep -v ': warning:'`"
+if test " $oops" != " "
+then
+ echo
+ echo "***ERRORS DETECTED in $* (examine file for details):"
+ echo "$oops"
+ echo
+ exit 1
+else
+ exit 0
+fi
diff --git a/packaging/utils/kernel.patch.gen.sh b/packaging/utils/kernel.patch.gen.sh
new file mode 100644
index 000000000..0bc726dd1
--- /dev/null
+++ b/packaging/utils/kernel.patch.gen.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+# RCSID $Id: kernel.patch.gen.sh,v 1.1 2004/03/15 20:35:27 as Exp $
+
+patchdir=`pwd`
+kernelsrc=/usr/src/linux
+[ "$1~" = "~" ] || kernelsrc=$1
+cd $kernelsrc
+# clean out destination file for all patch
+#echo "">$patchdir/all
+
+# find files to patch and loop
+for i in `find . -name '*.preipsec'`
+do
+
+# strip off '.preipsec' suffix
+j=${i%.preipsec}
+
+# strip off './' prefix
+k=${j#\.\/}
+
+# single unified diff
+#diff -u $i $j >>$patchdir/all
+
+# convert '/' in filename to '.' to avoid subdirectories
+sed -e 's/\//\./g' << EOI > /tmp/t
+$k
+EOI
+l=`cat /tmp/t`
+rm -f /tmp/t
+
+# *with* path from source root
+#echo do diff -u $i $j '>' $patchdir/$l
+echo found $i
+echo "RCSID \$Id: kernel.patch.gen.sh,v 1.1 2004/03/15 20:35:27 as Exp $" >$patchdir/$l
+diff -u $i $j >>$patchdir/$l
+
+done
+
+#
+# $Log: kernel.patch.gen.sh,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.6 2002/04/25 17:04:16 mcr
+# resurrected kernel.patch.gen.sh
+#
+# Revision 1.4 1999/04/06 04:54:30 rgb
+# Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+# patch shell fixes.
+#
+#
diff --git a/packaging/utils/kerneldiff b/packaging/utils/kerneldiff
new file mode 100755
index 000000000..5cd4f73e2
--- /dev/null
+++ b/packaging/utils/kerneldiff
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# wander through a FreeSWAN linux directory, comparing each file to
+# a corresponding file in the argument $KERNELSRC directory, creating
+# a diff that can be used to update the FreeSWAN source tree.
+#
+# This script is useful if you have used "make kernelpatch" to patch
+# a kernel, and then had to edit the source code in the kernel tree.
+#
+# $Id: kerneldiff,v 1.1 2004/03/15 20:35:27 as Exp $
+#
+
+KERNELSRC=$1
+shift
+
+(cd linux && find . -type f -print) | grep -v CVS | egrep -v './Makefile' | while read file
+do
+ base=`basename $file`
+ case $base in
+ .cvsignore) ;;
+ .*.o.flags) ;;
+ *.o) ;;
+ *~) ;;
+ *.$patchname.patch) ;;
+ *.patch) ;;
+ *.orig) ;;
+ *.rej) ;;
+ version.c);;
+ *) diff -u linux/$file $KERNELSRC/$file ;;
+ esac
+done
+
+exit 0
+
+
diff --git a/packaging/utils/kernelpatch b/packaging/utils/kernelpatch
new file mode 100755
index 000000000..d2b8e86f1
--- /dev/null
+++ b/packaging/utils/kernelpatch
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+# wander through a FreeSWAN linux directory, creating a patch file (to stdout)
+# that will apply the code to a kernel source directory.
+#
+# $Id: kernelpatch,v 1.1 2004/03/15 20:35:27 as Exp $
+#
+
+KERN=$1
+shift
+
+case $KERN in
+ 2.0) patchname=fs2_0;;
+ 2.2) patchname=fs2_2;;
+ 2.4) patchname=fs2_4;;
+ 2.5) patchname=fs2_5;;
+ *) echo "Invalid kernel patch target: $KERN"; exit 1;;
+esac
+
+# make sure that sort gets the right locale.
+LANG=C export LANG
+LC_ALL=C export LC_ALL
+
+
+find linux -type f -print | grep -v CVS | egrep -v 'linux/Makefile' | sort | while read file
+do
+ base=`basename $file`
+ case $base in
+ TAGS) ;;
+ tags) ;;
+ .cvsignore) ;;
+ .*.o.flags) ;;
+ .\#*);;
+ *.o) ;;
+ *~) ;;
+ tagsfile.mak) ;;
+ *.$patchname.patch) cat $file;;
+ *.patch) ;;
+ *) diff -u /dev/null $file;;
+ esac
+done
+
+#
+# finally, we have to produce a diff for linux/net/linux/Makefile.ver,
+# a file which is generated at runtime, so there is nothing in CVS.
+#
+echo '--- /dev/null Fri May 10 13:59:54 2002'
+echo '+++ linux/net/ipsec/Makefile.ver Sun Jul 28 22:10:40 2002'
+echo '@@ -0,0 +1 @@'
+echo -n '+'
+grep IPSECVERSION Makefile.ver
+
+exit 0
+
+
diff --git a/packaging/utils/kernelversion b/packaging/utils/kernelversion
new file mode 100755
index 000000000..a021398af
--- /dev/null
+++ b/packaging/utils/kernelversion
@@ -0,0 +1,10 @@
+#! /bin/sh
+# determine kernel version code, mostly for use in RPM building
+
+awk 'BEGIN { FS = " *= *" }
+ NF != 2 { next }
+ $1 == "VERSION" { maj = $2 }
+ $1 == "PATCHLEVEL" { mid = $2 }
+ $1 == "SUBLEVEL" { min = $2 }
+ $1 == "EXTRAVERSION" { ext = $2 }
+ END { print maj "." mid "." min ext }' $*
diff --git a/packaging/utils/kernelversion-short b/packaging/utils/kernelversion-short
new file mode 100755
index 000000000..677f7b4da
--- /dev/null
+++ b/packaging/utils/kernelversion-short
@@ -0,0 +1,8 @@
+#! /bin/sh
+# determine kernel version code, mostly for use in RPM building
+
+awk 'BEGIN { FS = " *= *" }
+ NF != 2 { next }
+ $1 == "VERSION" { maj = $2 }
+ $1 == "PATCHLEVEL" { mid = $2 }
+ END { print maj "." mid }' $*
diff --git a/packaging/utils/manlink b/packaging/utils/manlink
new file mode 100755
index 000000000..84e6031b2
--- /dev/null
+++ b/packaging/utils/manlink
@@ -0,0 +1,74 @@
+#! /bin/sh
+#
+# $Id: manlink,v 1.1 2004/03/15 20:35:27 as Exp $
+#
+# make list of alternate names for manpages
+
+PATH=/bin:/usr/bin ; export PATH
+usage="$0 manpage ..."
+
+for m
+do
+ bm=`basename $m`
+ if test ! -f $m
+ then
+ echo "$0: cannot find \`$m'" >&2
+ exit 1
+ fi
+ suf=$(expr $bm : '.*\([.][^.][^.]*\)$')
+
+ # a .\"+ line rules
+ them=$(awk '/^\.\\"\+[ ]/ { for (i = 2; i <= NF; i++) print $i }' $m)
+
+ # otherwise, try to intuit the list of names from the NAME section
+ if test " $them" = " "
+ then
+ them=$( awk '/^\.SH[ \t]+NAME/,/^\.SH[ \t]+[^N]/' $m |
+ egrep -v '^\.' | tr ' ,' ' ' |
+ sed -n '/ *\\*- *.*/s///p' | tr -s ' ' '\012' |
+ egrep -v '^ipsec$' )
+ fi
+
+ # do it
+ for f in $them
+ do
+ case $f in
+ ipsec*) ff="$f" ;; # ipsec.8, ipsec.conf.5, etc.
+ *) ff="ipsec_$f" ;;
+ esac
+ case $ff in
+ *.[1-8]) ;;
+ *) ff="$ff$suf" ;;
+ esac
+ #echo "Q: $bm FF: $ff" >&2
+ if [ " $ff" != " $bm" ] && [ " $ff" != " ipsec_$bm" ]
+ then
+ echo $bm $ff
+ fi
+ done
+done
+
+#
+# $Log: manlink,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.8 2002/09/17 20:17:16 sam
+#
+# The "make doc" fix broke "make install" silently; some man page symlinks
+# were being linked incorrectly. This resulted in files which passed the make
+# install test but linked to nothing.
+#
+# Revision 1.7 2002/08/07 06:23:35 sam
+#
+# freeswan/packaging/utils/manlink
+#
+# Revision 1.6 2002/05/06 21:20:24 mcr
+# manlink -n idea is a fail. It depended upon being able to
+# read the man page at the installed location, which isn't going
+# to work consistently. manlink now just generates a list of links
+# that should be made, leaving the Makefile script to decide what
+# to do with them. Further, it now processes the files found in the
+# repository, rather than the ones installed.
+#
+#
diff --git a/packaging/utils/maysnap b/packaging/utils/maysnap
new file mode 100755
index 000000000..9685c1d20
--- /dev/null
+++ b/packaging/utils/maysnap
@@ -0,0 +1,41 @@
+#! /bin/sh
+# consider making snapshot of FreeSwan code
+
+who=mcr
+USER=build export USER
+
+. ~build/freeswan-regress-env.sh
+
+umask 022
+
+cd ~build/WANTSNAP
+
+if test ! -f dosnap
+then
+ exit 0
+fi
+
+set -x
+
+if test -f doingsnap
+then
+ echo "snapshot already in progress" | mail -s "snapshot averted" $who
+ exit 0
+fi
+
+echo $$ >doingsnap
+sort -u dosnap >/tmp/snap$$
+echo === >>/tmp/snap$$
+if ~build/bin/mksnap -S >>/tmp/snap$$ 2>&1
+then
+ #if ~build/bin/mksnap -r 1.97 -p pre1.98 >>/tmp/snap$$ 2>&1
+ #then
+ rm -f dosnap
+ #fi
+fi
+
+mail -s "snapshot report $reqd" $who </tmp/snap$$
+rm -f /tmp/snap$$ doingsnap
+
+find /btmp/build/snapshots -type f -ctime +5 -print | xargs -r rm
+
diff --git a/packaging/utils/maytest b/packaging/utils/maytest
new file mode 100755
index 000000000..6bc08da11
--- /dev/null
+++ b/packaging/utils/maytest
@@ -0,0 +1,42 @@
+#! /bin/sh
+# consider making snapshot of FreeSwan code
+
+who=mcr
+USER=build export USER
+
+. ~build/freeswan-regress-env.sh
+
+umask 022
+
+cd ~build/WANTSNAP
+
+if test ! -f dotest
+then
+ exit 0
+fi
+
+if test -f doingtest
+then
+ exit 0
+fi
+
+trap "rm -f ~build/WANTSNAP/doingtest ~build/WANTSNAP/dotest; exit 0" 0 1 2 15
+
+set -x
+
+echo $$ >doingtest
+sort -u doingtest >/tmp/nightly$$
+echo === >>/tmp/test$$
+if ~build/bin/nightly.sh >>/tmp/snap$$ 2>&1
+then
+ rm -f doingtest
+ rm -f dotest
+fi
+
+mail -s "nightly test report $reqd" $who </tmp/nightly$$
+rm -f /tmp/nightly$$ dotest
+
+# kill any wayward linux processes
+killuml linux
+
+
diff --git a/packaging/utils/mkcand b/packaging/utils/mkcand
new file mode 100755
index 000000000..91e69f62b
--- /dev/null
+++ b/packaging/utils/mkcand
@@ -0,0 +1,126 @@
+#!/usr/bin/perl
+# mkcand m.nn
+# package candidate, leaving it in tmp directory
+
+require($ENV{'HOME'}."/bin/disttools.pl");
+
+&defvars;
+&suckvars;
+
+umask(022);
+
+$localdir=$ENV{'HOME'}."/archive";
+$ENV{'DEV_DIR'}=$localdir."/development";
+$tmpdir=$ENV{'BTMP'}."/".$ENV{'USER'}."/snapshots";
+
+$transmit=1;
+$snapprefix="";
+$tarinfix="";
+$date="now";
+$lastrel=$ENV{'LASTREL'};
+
+sub usage {
+ print STDERR "mkcand:\n";
+ print STDERR "\t-l do not transmit\n";
+ print STDERR "\t-p name set candidate name\n";
+ print STDERR "\t-r rel set release branch\n";
+}
+
+while(@ARGV) {
+ $_=shift;
+
+ if(/^-l/) {
+ $transmit=0;
+
+ } elsif(/^-S/) {
+ $symlink=1;
+
+ } elsif(/^-p/) {
+ $rel=shift;
+ $snapprefix="pre$rel-";
+
+ } elsif(/^-r/) {
+ $arg=shift;
+ ($lastrel=$arg) =~ y/\./\_/;
+ $relopt="-r PRE${lastrel}"
+
+# } elsif(/^-d/) {
+# $arg=shift;
+# $transmit=0;
+# $date=$arg;
+
+ } else {
+ &usage;
+ exit;
+ }
+}
+
+
+
+if(!defined($relopt) ||
+ !defined($rel)) {
+ &usage;
+ exit;
+}
+
+if($rel < 2.00) {
+ undef(@supportedkernels);
+}
+
+
+$candname=&snapname($snapprefix);
+$dirname="freeswan-cand".$candname;
+# $pkgname="candidate-".$candname;
+$pkgname=$dirname;
+$tarname=$pkgname.".tar";
+$vername="cand-".$candname;
+
+&nicesystem("mkdir -p $tmpdir");
+print "BUILDING candidate $candname in $dirname\n";
+if($transmit) {
+ print "WILL TRANSMIT TO $ENV{'DISTHOST'}\n"
+} else {
+ print "WILL NOT TRANSMIT\n";
+}
+
+&setuppgp($lastrel);
+
+&makedisttarfile($tmpdir, $pkgname, $vername, $dirname, $date, $relopt, 1);
+
+unlink("CANDIDATE.tar.gz");
+&nicesystem("ln $tarname.gz CANDIDATE.tar.gz") || die "failed to symlink to CANDIDATE.tar.gz: $?\n";
+&nicesystem("md5sum CANDIDATE.tar.gz >CANDIDATE.tar.gz.md5") || die "failed to md5sum of CANDIDATE.tar.gz: $?\n";
+
+&dopgpsig($pkgname);
+
+&nicesystem("pgp -kxa $ENV{'PGPNAME'} $pkgname.tar.gz.pgpkey && chmod +r $pkgname.tar.gz.pgpkey.asc");
+
+if($transmit) {
+ system("date");
+
+ local($snapprefix);
+
+ &upload($pkgname);
+
+ if($symlink) {
+ &sendfiles("CANDIDATE.tar.gz.md5");
+
+ &remotecmd("cd ".$ENV{'DISTDIR'}." && ln -f -s $pkgname.tar.gz CANDIDATE.tar.gz && ln -f -s $tarname.gz.sig CANDIDATE.tar.gz.sig");
+
+ foreach $ver (@supportedkernels) {
+ &remotecmd("cd ".$ENV{'DISTDIR'}." && ln -f -s $pkgname$ver.patch.gz CAND.KERN$ver.gz && ln -f -s $tarname.gz.sig CAND.KERN$ver.gz.sig");
+ }
+ }
+
+ print "Cleaning up old candidates\n";
+
+ local($file, $localroot);
+
+ $localroot=$ENV{'DEV_DIR'};
+ &nicesystem("cd $localroot && find . -mtime +3 | grep 'freeswan-cand$snapprefix' | xargs rm");
+
+ &upsync;
+
+ system("date");
+}
+
diff --git a/packaging/utils/mkrel b/packaging/utils/mkrel
new file mode 100755
index 000000000..3182d9d06
--- /dev/null
+++ b/packaging/utils/mkrel
@@ -0,0 +1,95 @@
+#!/usr/bin/perl
+# mkcand m.nn
+# package candidate, leaving it in tmp directory
+
+require($ENV{'HOME'}."/bin/disttools.pl");
+
+&defvars;
+&suckvars;
+
+umask(022);
+
+$localdir=$ENV{'HOME'}."/archive";
+
+$tmpdir=$ENV{'BTMP'}."/".$ENV{'USER'}."/snapshots";
+
+$transmit=1;
+$snapprefix="";
+$tarinfix="";
+$date="";
+$lastrel=$ENV{'LASTREL'};
+
+sub usage {
+ print STDERR "mkrel:\n";
+ print STDERR "\t-l do not transmit\n";
+ print STDERR "\t-p name set release name\n";
+ print STDERR "\t-r rel set release branch\n";
+}
+
+while(@ARGV) {
+ $_=shift;
+
+ if(/^-l/) {
+ $transmit=0;
+
+ } elsif(/^-S/) {
+ $symlink=1;
+
+ } elsif(/^-p/) {
+ $rel=shift;
+ $snapprefix="pre$rel-";
+
+ } elsif(/^-r/) {
+ $arg=shift;
+ ($lastrel=$arg) =~ y/\./\_/;
+ $relopt="-r PRE${lastrel}"
+
+ } else {
+ &usage;
+ exit;
+ }
+}
+
+if(!defined($relopt) ||
+ !defined($rel)) {
+ &usage;
+ exit;
+}
+
+$dirname="freeswan-".$rel;
+$pkgname="freeswan-".$rel;
+$tarname=$pkgname.".tar";
+$vername=$rel;
+
+&nicesystem("mkdir -p $tmpdir");
+print "BUILDING release $rel in $dirname\n";
+if($transmit) {
+ print "WILL TRANSMIT TO $ENV{'DISTHOST'}\n"
+} else {
+ print "WILL NOT TRANSMIT\n";
+}
+
+$ENV{'PGPPATH'}="/mnt/build/freeswan";
+$ENV{'PGPNAME'}="build\@freeswan.org";
+
+&makedisttarfile($tmpdir, $pkgname, $vername, $dirname, $date, $relopt, 1);
+
+print "Please insert release key floppy for signature";
+$ans=<STDIN>;
+system("mount /mnt/build");
+&dopgpsig($pkgname);
+system("umount /mnt/build");
+
+if($transmit) {
+ print "Now transmitting to XS4all\n";
+ print "Starting on: ";
+ system("date");
+
+ &upload($pkgname);
+
+ &upsync;
+
+ print "Finished on: ";
+ system("date");
+}
+
diff --git a/packaging/utils/mksnap b/packaging/utils/mksnap
new file mode 100755
index 000000000..4f336fc7a
--- /dev/null
+++ b/packaging/utils/mksnap
@@ -0,0 +1,114 @@
+#!/usr/bin/perl
+# make snapshot of FreeSwan code
+# -l local build only, do not transmit
+# -p nn pre-nn version (where nn is a release like 1.00)
+# -d ddd build as of date ddd (implies -l)
+
+require($ENV{'HOME'}."/bin/disttools.pl");
+
+&defvars;
+&suckvars;
+
+umask(022);
+
+$localdir=$ENV{'HOME'}."/archive";
+$ENV{'DEV_DIR'}=$localdir."/development";
+
+if(!defined($ENV{'USER'})) {
+ $ENV{'USER'}="build";
+}
+
+$tmpdir=$ENV{'BTMP'}."/".$ENV{'USER'}."/snapshots";
+
+$transmit=1;
+$symlink=0;
+$snapprefix="";
+$tarinfix="";
+$relopt="";
+$date="now";
+$lastrel=$ENV{'LASTREL'};
+$lastrel =~ y/\./\_/;
+
+while(@ARGV) {
+ $_=shift;
+
+ if(/^-l/) {
+ $transmit=0;
+
+ } elsif(/^-D/) {
+ $debug++;
+
+ } elsif(/^-S/) {
+ $symlink=1;
+
+ } elsif(/^-p/) {
+ $arg=shift;
+ $snapprefix="$arg-";
+
+ } elsif(/^-r/) {
+ $arg=shift;
+ ($lastrel=$arg) =~ y/\./\_/;
+ $relopt="-r PRE${lastrel}"
+
+# } elsif(/^-d/) {
+# $arg=shift;
+# $transmit=0;
+# $date=$arg;
+
+ } else {
+ print STDERR "mksnap:\n";
+ print STDERR "\t-l do not transmit\n";
+ print STDERR "\t-p stuff set snapshot prefix\n";
+ print STDERR "\t-r rel set release branch\n";
+ print STDERR "\t-d date set snapshot date\n";
+ exit;
+ }
+}
+
+$snapname=&snapname($snapprefix);
+
+#if($date ne "now") {
+# $snapname="`echo $date | tr -d ' :'`" ;;
+#}
+
+$dirname="freeswan-snap".$snapname;
+$pkgname="snapshot-".$snapname;
+$tarname=$pkgname.".tar";
+
+&nicesystem("mkdir -p $tmpdir");
+print "BUILDING snapshot $dirname\n";
+if($transmit) {
+ print "WILL TRANSMIT TO $ENV{'DISTHOST'}\n"
+} else {
+ print "WILL NOT TRANSMIT\n";
+}
+
+&setuppgp($lastrel);
+
+&makedisttarfile($tmpdir, $pkgname, "$lastrel_$snapname", $dirname, $date, $relopt, 0);
+
+unlink("snapshot.tar.gz");
+&nicesystem("ln -s $tarname.gz snapshot.tar.gz") || die "failed to symlink to snapshot.tar.gz: $?\n";
+&nicesystem("md5sum snapshot.tar.gz >snapshot.tar.gz.md5") || die "failed to md5sum of snapshot.tar.gz: $?\n";
+
+&dopgpsig($pkgname);
+
+if($transmit) {
+ system("date");
+
+ &upload($pkgname, "snapshot");
+
+ print "Cleaning up old snapshots\n";
+
+ local($file, $localroot);
+
+ $localroot=$ENV{'DEV_DIR'};
+
+ &nicesystem("cd $localroot && find . -name \"snapshot-*\" -print | grep -v $pkgname | xargs -r rm --");
+
+ &upsync;
+
+ system("date");
+}
+
+
diff --git a/packaging/utils/mvcand b/packaging/utils/mvcand
new file mode 100755
index 000000000..6e29bc490
--- /dev/null
+++ b/packaging/utils/mvcand
@@ -0,0 +1,62 @@
+#! /bin/sh
+# mvcand
+# move packaged candidate to distribution site (password supplied manually)
+
+PATH=/bin:/usr/bin
+export PATH
+umask 022
+
+. $HOME/freeswan-regress-env.sh
+
+localplace=~build/archive
+site=freeswan@xs4.xs4all.nl
+place=FTP
+linkname=CANDIDATE.tar
+ssh=/usr/bin/ssh
+scp=/usr/bin/scp
+
+localonly=
+remove=yes
+for dummy
+do
+ case "$1" in
+ -l) localonly=yes ;;
+ -k) remove= ;;
+ --) shift ; break ;;
+ -*) echo "$0: unknown option \'$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+case "$#" in
+0) ;;
+*) echo "Usage: $0" >&2 ; exit ;;
+esac
+
+cd ~build/tmp
+tarname=`ls | sed -n '/^freeswan-.*\.gz$/s/\.gz$//p' | tail -1`
+echo "moving $tarname.gz"
+
+(
+ cd $localplace
+ rm -f freeswan-cand* $linkname.*
+ ln -s $tarname.gz $linkname.gz
+)
+cp -p $tarname.gz $tarname.gz.md5 $tarname.gz.sig CANDIDATE.tar.gz.md5 $localplace
+
+if test "$localonly"
+then
+ exit 0 # leaving the original around
+fi
+
+$ssh $site "cd $place ; rm -f freeswan-cand* $linkname.* ;
+ ln -s $tarname.gz $linkname.gz ;
+ ln -s $tarname.gz.sig $linkname.gz.sig"
+
+$scp -p $tarname.gz.md5 $tarname.gz.sig $tarname.gz CANDIDATE.tar.gz.md5 $site:$place
+
+if test "$remove"
+then
+ rm -f $tarname.*
+fi
diff --git a/packaging/utils/mvrel b/packaging/utils/mvrel
new file mode 100755
index 000000000..66b1180a8
--- /dev/null
+++ b/packaging/utils/mvrel
@@ -0,0 +1,65 @@
+#! /bin/sh
+# mvrel major minor
+# move packaged release to distribution site (password supplied manually)
+
+PATH=/bin:/usr/bin
+export PATH
+umask 022
+
+. $HOME/freeswan-regress-env.sh
+
+localplace=~build/archive
+site=freeswan@xs4.xs4all.nl
+place=FTP
+linkname=LATEST.tar
+ssh=/usr/bin/ssh
+scp=/usr/bin/scp
+
+localonly=
+remove=yes
+for dummy
+do
+ case "$1" in
+ -l) localonly=yes ;;
+ -c) site=adams.freeswan.org ; place=/home/team ; scp=scp2 ; ssh=ssh2 ;;
+ -k) remove= ;;
+ --) shift ; break ;;
+ -*) echo "$0: unknown option \'$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+case "$#:$1" in
+1:*.*) ;;
+*) echo "Usage: $0 [-l] [-c] release" >&2 ; exit ;;
+esac
+
+tarname=freeswan-$1.tar
+
+cd ~build/tmp
+if test ! -r $tarname.gz
+then
+ echo "$0: no $tarname.gz!" >&2
+ exit 1
+fi
+
+rm -f $localplace/$tarname.*
+cp -p $tarname.gz $tarname.gz.sig $localplace
+
+if test "$localonly"
+then
+ exit 0 # leaving the original around
+fi
+
+$ssh $site "cd $place ; rm -f $tarname.gz.sig $tarname.gz LATEST.* ;
+ rm -f CANDIDATE.* freeswan-cand* ;
+ mv freeswan-[0-9]* old ;
+ ln -s $tarname.gz LATEST.tar.gz ;
+ ln -s $tarname.gz.sig LATEST.tar.gz.sig"
+$scp -p $tarname.gz.sig $tarname.gz $site:$place
+
+if test "$remove"
+then
+ rm -f $tarname.*
+fi
diff --git a/packaging/utils/patcher b/packaging/utils/patcher
new file mode 100755
index 000000000..ba31bdd26
--- /dev/null
+++ b/packaging/utils/patcher
@@ -0,0 +1,188 @@
+#! /bin/sh
+# smart patch applier
+# Copyright (C) 1999, 2001 Henry Spencer.
+#
+# 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.
+#
+# patcher [-v] [-c] targetdir target [ key patchfile ] ...
+# In targetdir, patch target from patchfile unless it already contains
+# key and it appears to have been patched with the same patch. (If the
+# patch has changed, undo the old one and then put the new one in.) Save
+# original as target.preipsec, and patched copy as target.wipsec, with
+# patch md5sum stored as target.ipsecmd5. If the patch doesn't work,
+# put the original back and save the patch attempt as target.mangled.
+# If there are no key+patchfile pairs, undo any old patch and leave it
+# at that.
+# -v means verbose
+# -c means do "patching" by appending rather than by using patch(1)
+#
+# RCSID $Id: patcher,v 1.1 2004/03/15 20:35:27 as Exp $
+
+PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin
+export PATH
+umask 022
+
+verbose=
+modifier=patch
+for dummy
+do
+ case "$1" in
+ -v) verbose=yes ;;
+ -c) modifier=cat ;;
+ --) shift ; break ;;
+ -*) echo "$0: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+if test $# -lt 2
+then
+ echo "Usage: $0 [-v] [-c] targetdir target [ key patchfile ] ..." >&2
+ exit 2
+fi
+
+need() {
+ if test ! -f $1
+ then
+ echo "$0: cannot find file \`$1'" >&2
+ exit 1
+ fi
+}
+
+note() {
+ if test "$verbose"
+ then
+ echo "* $1"
+ fi
+}
+
+dir="$1"
+target="$2"
+shift ; shift
+it=$dir/$target
+need $it
+
+
+
+patches=
+if test ! -s $it.ipsecmd5
+then
+ # no records of patching...
+ while test $# -ge 2
+ do
+ key="$1"
+ patchfile="$2"
+ shift ; shift
+ need $patchfile
+
+ if egrep -q "$key" $it
+ then
+ # patched but no record of how
+ note "$it no longer needs patch $patchfile"
+ else
+ patches="$patches $patchfile"
+ fi
+ done
+elif test ! -f $it.preipsec -o ! -f $it.wipsec
+then
+ echo "$0: $it.preipsec or .wipsec is missing!" >&2
+ exit 1
+else
+ # determine whether patches have changed
+ tmp=/tmp/patcher.$$
+ >$tmp
+ while test $# -ge 2
+ do
+ key="$1"
+ patchfile="$2"
+ shift ; shift
+ need $patchfile
+ md5sum $patchfile | awk '{print $1}' >>$tmp
+
+ if egrep -q "$key" $it.preipsec
+ then
+ note "$it no longer needs patch $patchfile"
+ else
+ patches="$patches $patchfile"
+ fi
+ done
+ if cmp -s $tmp $it.ipsecmd5
+ then
+ note "$it already fully patched"
+ rm -f $tmp
+ exit 0
+ fi
+ rm -f $tmp
+
+ # must undo old patch(es)
+ note "$it old patches must be undone, undoing them..."
+ if ! cmp -s $it $it.wipsec
+ then
+ note "$it has changed, cannot undo old patches!"
+ echo "$0: cannot unpatch $it, it has changed since patching" >&2
+ exit 1
+ fi
+ rm $it
+ mv $it.preipsec $it
+ rm $it.wipsec $it.ipsecmd5
+fi
+
+# if no necessary patches, we're done
+if test " $patches" = " "
+then
+ note "$it no longer needs patching"
+ exit 0
+fi
+
+# try to figure out patch options
+if test " $modifier" = " patch"
+then
+ if patch --help >/dev/null 2>/dev/null
+ then
+ # looks like a modern version
+ popts='-p1 -b'
+ else
+ # looks like an old one
+ popts='-p1'
+ fi
+fi
+
+# do it
+>$it.ipsecmd5
+for patchfile in $patches
+do
+ note "applying $patchfile to $it..."
+
+ # make local copy - this defeats hard and soft links
+ mv $it $it.preipsec || exit 0
+ rm -f $it
+ cp -p $it.preipsec $it
+
+ case "$modifier" in
+ patch) ( cd $dir ; patch $popts ) <$patchfile ;;
+ cat) cat $patchfile >>$it ;;
+ esac
+ status=$?
+ if test $status -ne 0
+ then
+ note "$it patch failed, restoring original"
+ echo "$0: patch on $it failed!" >&2
+ echo "$0: restoring original $it," >&2
+ echo "$0: leaving patch attempt in $it.mangled" >&2
+ mv $it $it.mangled
+ mv $it.preipsec $it
+ rm -f $it.ipsecmd5
+ exit 1
+ fi
+ rm -f $it.orig # some patch versions leave debris
+ md5sum $patchfile | awk '{print $1}' >>$it.ipsecmd5
+done
+cp -p $it $it.wipsec
diff --git a/packaging/utils/prepcand b/packaging/utils/prepcand
new file mode 100755
index 000000000..31c382501
--- /dev/null
+++ b/packaging/utils/prepcand
@@ -0,0 +1,33 @@
+#! /bin/sh
+# prepcand m.nn
+# prepare candidate for building, must be done in top working dir
+
+PATH=/bin:/usr/bin
+export PATH
+umask 022
+
+case "$#:$1" in
+1:*.*) ;;
+*) echo "Usage: $0 release" >&2 ; exit ;;
+esac
+
+rel="$1"
+tag="PRE`echo $rel | tr '.' '_'`"
+
+# update from snapshot form to candidate/release form, if necessary
+if egrep -q -e '^---$' README
+then
+ sed '1,/^---$/d' README | sed '1s/This is release xxx of Linux FreeS\/WAN/This is release '$rel' of Linux FreeS\/WAN/' > README.$$
+ mv README.$$ README
+ cvs -Q commit -m "update for candidates of release $rel" README
+fi
+
+if sed -n 1p CHANGES | egrep -q 'since last release'
+then
+ sed '1s/since last release/in '$rel'/' CHANGES >CHANGES.$$
+ mv CHANGES.$$ CHANGES
+ cvs -Q commit -m "update for candidates of release $rel" CHANGES
+fi
+
+echo "IPSECVERSION=$rel" >Makefile.ver
+cvs -Q commit -m "update for candidate of release $rel" Makefile
diff --git a/packaging/utils/recan b/packaging/utils/recan
new file mode 100755
index 000000000..eaaf9436a
--- /dev/null
+++ b/packaging/utils/recan
@@ -0,0 +1,17 @@
+#! /bin/sh
+# recan release
+# run in a working directory to recan contents of same where necessary
+
+PATH=/bin:/usr/bin ; export PATH
+umask 022
+
+. ~freeswan/setup
+
+case $# in
+0) echo "Usage: $0 release [file] ..." >&2 ; exit 2 ;;
+esac
+
+tag="R`echo $1 | tr '.' '_'`"
+shift
+
+cvs tag -F -D now $tag $*
diff --git a/packaging/utils/setup b/packaging/utils/setup
new file mode 100755
index 000000000..5d250bb37
--- /dev/null
+++ b/packaging/utils/setup
@@ -0,0 +1,9 @@
+# shell file setting up environment for freeswan CVS access
+# This is here, rather than in .profiles, because Henry has local access
+# and doesn't want to duplicate this stuff.
+
+PATH=$PATH:/sandel/bin export PATH
+CVSROOT=/freeswan/MASTER
+CVSUMASK=002
+
+export CVSROOT CVSUMASK
diff --git a/packaging/utils/sshenv b/packaging/utils/sshenv
new file mode 100755
index 000000000..8075b9d09
--- /dev/null
+++ b/packaging/utils/sshenv
@@ -0,0 +1,4 @@
+# ssh environment file for freeswan CVS access
+# user .ssh directories have links to this, so this info is in one place
+CVSROOT=/home/freeswan/cvs
+CVSUMASK=002
diff --git a/packaging/utils/tattle b/packaging/utils/tattle
new file mode 100755
index 000000000..37d015b0f
--- /dev/null
+++ b/packaging/utils/tattle
@@ -0,0 +1,33 @@
+#! /bin/sh
+# tattle [-f] subject address ...
+# report a freeswan CVS change made by someone other than "owner" of files
+
+PATH=/bin:/usr/bin ; export PATH
+
+noself=yes # don't mail to person making change
+case "$1" in
+-f) noself= ; shift ;;
+esac
+
+msg="freeswan commit: $1"
+shift
+
+them=
+if test "$noself"
+then
+ iam="`id -un`"
+ for who
+ do
+ if test " $who" != " $iam"
+ then
+ them="$them $who"
+ fi
+ done
+else
+ them="$*"
+fi
+
+if test " $them" != " "
+then
+ mail -s "$msg" $them
+fi
diff --git a/packaging/utils/wantsnap b/packaging/utils/wantsnap
new file mode 100755
index 000000000..74b4287da
--- /dev/null
+++ b/packaging/utils/wantsnap
@@ -0,0 +1,3 @@
+#! /bin/sh
+umask 002
+id -un >>~build/WANTSNAP/dosnap
diff --git a/packaging/utils/wanttest b/packaging/utils/wanttest
new file mode 100755
index 000000000..9cbdde8d0
--- /dev/null
+++ b/packaging/utils/wanttest
@@ -0,0 +1,10 @@
+#! /bin/sh
+
+if [ -f ~build/WANTSNAP/doingtest ]
+then
+ echo Test already in progress.
+ exit 1
+fi
+
+umask 002
+id -un >>~build/WANTSNAP/dotest
diff --git a/programs/Makefile b/programs/Makefile
new file mode 100644
index 000000000..03c9d582a
--- /dev/null
+++ b/programs/Makefile
@@ -0,0 +1,46 @@
+# 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.8 2006/04/17 11:04:45 as Exp $
+
+FREESWANSRCDIR=..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+SUBDIRS=spi eroute spigrp tncfg klipsdebug pf_key proc pluto
+SUBDIRS+=_confread _copyright _include _keycensor _plutoload _plutorun
+SUBDIRS+=_realsetup _secretcensor _startklips _updown _updown_espmark
+SUBDIRS+=auto barf ipsec look manual ranbits secrets starter
+SUBDIRS+=rsasigkey send-pr setup showdefaults showhostkey calcgoo mailkey
+SUBDIRS+=ikeping examples openac scepclient
+
+ifeq ($(USE_LWRES),true)
+SUBDIRS+=lwdnsq
+endif
+
+ifeq ($(USE_IPSECPOLICY),true)
+SUBDIRS+=showpolicy
+endif
+
+def:
+ @echo "Please read doc/intro.html or INSTALL before running make"
+ @false
+
+# programs
+
+cleanall distclean mostlyclean realclean install programs checkprograms check clean spotless install_file_list:
+ @for d in $(SUBDIRS) ; \
+ do \
+ (cd $$d && $(MAKE) FREESWANSRCDIR=$(FREESWANSRCDIR)/.. $@ ) || exit 1;\
+ done; \
+
diff --git a/programs/Makefile.program b/programs/Makefile.program
new file mode 100644
index 000000000..6868c258a
--- /dev/null
+++ b/programs/Makefile.program
@@ -0,0 +1,150 @@
+
+include ${FREESWANSRCDIR}/Makefile.ver
+
+CFLAGS+=$(USERCOMPILE) -I${KLIPSINC}
+
+CFLAGS+= -Wall
+#CFLAGS+= -Wconversion
+#CFLAGS+= -Wmissing-prototypes
+CFLAGS+= -Wpointer-arith
+CFLAGS+= -Wcast-qual
+#CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wstrict-prototypes
+#CFLAGS+= -pedantic
+#CFLAGS+= -W
+#CFLAGS+= -Wwrite-strings
+CFLAGS+= -Wbad-function-cast
+
+# die if there are any warnings
+ifndef WERROR
+WERROR:= -Werror
+endif
+
+#CFLAGS+= ${WERROR}
+
+ifneq ($(LD_LIBRARY_PATH),)
+LDFLAGS=-L$(LD_LIBRARY_PATH)
+endif
+
+MANDIR8=$(MANTREE)/man8
+MANDIR5=$(MANTREE)/man5
+
+ifndef PROGRAMDIR
+PROGRAMDIR=${LIBEXECDIR}
+endif
+
+ifndef MANPROGPREFIX
+MANPROGPREFIX=ipsec_
+endif
+
+ifndef CONFDSUBDIR
+CONFDSUBDIR=.
+endif
+
+all: $(PROGRAM)
+
+programs: all
+
+ifneq ($(PROGRAM),check)
+check: $(PROGRAM)
+endif
+
+
+ifneq ($(NOINSTALL),true)
+
+install:: $(PROGRAM) $(CONFFILES) $(EXTRA8MAN) $(EXTRA5MAN) $(EXTRA5PROC) $(LIBFILES) $(CONFDFILES)
+ @mkdir -p $(PROGRAMDIR) $(MANDIR8) $(MANDIR5) $(LIBDIR) $(CONFDIR) $(CONFDDIR) $(CONFDDIR)/$(CONFDSUBDIR) $(EXAMPLECONFDIR)
+ @if [ -n "$(PROGRAM)" ]; then $(INSTALL) $(INSTBINFLAGS) $(PROGRAM) $(PROGRAMDIR); fi
+ @$(foreach f, $(addsuffix .8, $(PROGRAM)), \
+ $(INSTALL) $(INSTMANFLAGS) $f $(MANDIR8)/$(MANPROGPREFIX)$f || exit 1; \
+ )
+ @$(foreach f, $(EXTRA8MAN), \
+ $(INSTALL) $(INSTMANFLAGS) $f $(MANDIR8)/ipsec_$f || exit 1; \
+ )
+ @$(foreach f, $(EXTRA5MAN), \
+ $(INSTALL) $(INSTMANFLAGS) $f $(MANDIR5)/$f || exit 1 ;\
+ )
+ @$(foreach f, $(EXTRA5PROC), \
+ $(INSTALL) $(INSTMANFLAGS) $f $(MANDIR5)/ipsec_$f || exit 1 ;\
+ )
+ @$(foreach f, $(LIBFILES), \
+ $(INSTALL) $(INSTCONFFLAGS) $f $(LIBDIR)/$f || exit 1 ;\
+ )
+ @$(foreach f, $(CONFFILES), \
+ if [ ! -f $(CONFDIR)/$f ]; then $(INSTALL) $(INSTCONFFLAGS) $f $(CONFDIR)/$f || exit 1; fi;\
+ $(INSTALL) $(INSTCONFFLAGS) $f $(EXAMPLECONFDIR)/$f-sample || exit 1; \
+ )
+ @$(foreach f, $(CONFDFILES), \
+ if [ ! -f $(CONFDDIR)/$(CONFDSUBDIR)/$f ]; then $(INSTALL) $(INSTCONFFLAGS) $f $(CONFDDIR)/$(CONFDSUBDIR)/$f || exit 1; fi;\
+ )
+
+install_file_list::
+ @if [ -n "$(PROGRAM)" ]; then echo $(PROGRAMDIR)/$(PROGRAM); fi
+ @$(foreach f, $(addsuffix .8, $(PROGRAM)), \
+ echo $(MANDIR8)/${MANPROGPREFIX}$f; \
+ )
+ @$(foreach f, $(EXTRA8MAN), \
+ echo $(MANDIR8)/ipsec_$f; \
+ )
+ @$(foreach f, $(EXTRA5MAN), \
+ echo $(MANDIR5)/$f;\
+ )
+ @$(foreach f, $(EXTRA5PROC), \
+ echo $(MANDIR5)/ipsec_$f; \
+ )
+ @$(foreach f, $(LIBFILES), \
+ echo $(LIBDIR)/$f;\
+ )
+ @$(foreach f, $(CONFFILES), \
+ echo $(CONFDIR)/$f;\
+ echo $(EXAMPLECONFDIR)/$f-sample;\
+ )
+ @$(foreach f, $(CONFDFILES), \
+ echo $(CONFDDIR)/${CONFDSUBDIR}/$f;\
+ )
+
+endif
+
+# cancel the rule that compiles directly
+%: %.c
+
+%: %.o $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $@.o ${OBJS} $(LDFLAGS) $(LIBS)
+
+%: %.in ${FREESWANSRCDIR}/Makefile.inc ${FREESWANSRCDIR}/Makefile.ver
+ cat $< | sed -e "s/xxx/$(IPSECVERSION)/" \
+ -e "s:@IPSEC_DIR@:$(FINALBINDIR):" \
+ -e "s:@IPSEC_EXECDIR@:$(FINALLIBEXECDIR):" \
+ -e "s:@IPSEC_SBINDIR@:$(FINALSBINDIR):" \
+ -e "s:@IPSEC_LIBDIR@:$(FINALLIBDIR):" \
+ -e "s:@FINALCONFDIR@:$(FINALCONFDIR):" \
+ -e "s:@EXAMPLECONFDIR@:$(EXAMPLECONFDIR):" \
+ -e "s:@FINALDOCDIR@:$(FINALDOCDIR):" \
+ -e "s:@FINALEXAMPLECONFDIR@:$(FINALEXAMPLECONFDIR):" \
+ -e "s:@MODULE_GOO_LIST@:$(MODULE_GOO_LIST):" \
+ -e "s:@IPSEC_CONFS@:$(FINALCONFDIR):" \
+ -e "s:@IPSEC_CONFDDIR@:$(FINALCONFDDIR):" \
+ -e "s:@USE_IPROUTE2@:$(USE_IPROUTE2):" \
+ -e "s:@IPSEC_FIREWALLTYPE@:$(IPSEC_FIREWALLTYPE):" \
+ | cat >$@
+ if [ -x $< ]; then chmod +x $@; fi
+ if [ "${PROGRAM}.in" = $< ]; then chmod +x $@; fi
+
+cleanall: clean
+
+distclean: clean
+
+mostlyclean: clean
+
+realclean: clean
+
+clean::
+ifneq ($(strip $(PROGRAM)),)
+ @if [ -r $(PROGRAM).in ]; then rm -f $(PROGRAM); fi
+ @if [ -r $(PROGRAM).c ]; then rm -f $(PROGRAM); fi
+ @if [ -n "$(OBJS)" ]; then rm -f $(PROGRAM); fi
+endif
+ @rm -f *.o
+
+checkprograms:
+
diff --git a/programs/_confread/.cvsignore b/programs/_confread/.cvsignore
new file mode 100644
index 000000000..405492384
--- /dev/null
+++ b/programs/_confread/.cvsignore
@@ -0,0 +1,7 @@
+_confread
+ipsec.conf
+block
+clear
+private
+clear-or-private
+private-or-clear
diff --git a/programs/_confread/Makefile b/programs/_confread/Makefile
new file mode 100644
index 000000000..1bdc9a3f0
--- /dev/null
+++ b/programs/_confread/Makefile
@@ -0,0 +1,27 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.2 2004/03/31 19:23:00 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_confread
+PROGRAMDIR=${LIBDIR}
+EXTRA5MAN=ipsec.conf.5
+CONFFILES=ipsec.conf
+
+CONFDSUBDIR=policies
+CONFDFILES=clear clear-or-private private-or-clear private block
+
+include ../Makefile.program
diff --git a/programs/_confread/README.conf.V2 b/programs/_confread/README.conf.V2
new file mode 100644
index 000000000..244e245c5
--- /dev/null
+++ b/programs/_confread/README.conf.V2
@@ -0,0 +1,103 @@
+Subject: [Design] changes to ipsec.conf
+# RCSID $Id: README.conf.V2,v 1.1 2004/03/15 20:35:27 as Exp $
+
+We are changing ipsec.conf for the 2.0 series of FreeS/WAN.
+
+OE is enabled by default. This is accomplished by automatically
+defining a conn "OEself" UNLESS the sysadmin defines one with the same
+name:
+
+conn OEself
+ # authby=rsasig # default
+ left=%defaultroute
+ leftrsasigkey=%dnsondemand # default
+ right=%opportunistic
+ rightrsasigkey=%dnsondemand # default
+ keyingtries=3
+ ikelifetime=1h
+ keylife=1h # default
+ rekey=no
+ # disablearrivalcheck=no # default
+ auto=route
+
+This will only work if %defaultroute works.
+The leftid will be the resulting IP address (won't work if
+you haven't filled in the reverse DNS entry).
+Unlike other conns, nothing in this implicit conn is changed by conn %default.
+
+We'd like a better name. A conn name starting with % cannot be
+defined by the sysadmin, so that is out. Names that haven't grabbed
+us: OEhost, OElocalhost, OEthishost, OEforself, OE4self.
+
+There is no requirement to have /etc/ipsec.conf. If you do, the first
+significant line (non-blank, non-comment) must be (not indented):
+version 2.0
+This signifies that the file was intended for FreeS/WAN version 2.0.
+
+
+The following table shows most changes. "-" means that the option
+doesn't exist. "Recent Boilerplate" shows the effect of the "conn
+%default" in the automatically installed /etc/ipsec.conf (not
+installed if you already had one).
+
+Option Old Default Recent Boilerplate New Default
+====== =========== ================== ===========
+
+config setup:
+interfaces "" %defaultroute %defaultroute
+plutoload "" %search - [same as %search]
+plutostart "" %search - [same as %search]
+uniqueids no yes yes
+rp_filter - - 0
+plutowait yes yes no
+dump no no - [use dumpdir]
+plutobackgroundload ignored ignored -
+no_eroute_pass no no - [use packetdefault]
+
+conn %default:
+keyingtries 3 0 %forever [0 means this]
+disablearrivalcheck yes no no
+authby secret rsasig rsasig
+leftrsasigkey "" %dnsondemand %dnsondemand
+rightrsasigkey "" %dnsondemand %dnsondemand
+lifetime ==keylife ==keylife - [use keylife]
+rekeystart ==rekeymargin ==rekeymargin - [use rekeymargin]
+rekeytries ==keyingtries ==keyingtries - [use keyingtries]
+
+====== =========== ================== ===========
+Option Old Default Recent Boilerplate New Default
+
+
+The auto= mechanism has been extended to support manual conns. If you
+specify auto=manual in a conn, an "ipsec manual" will be performed on
+it at startup (ipsec setup start).
+
+
+There is a new config setup option "rp_filter". It controls
+ /proc/sys/net/ipv4/conf/PHYS/rp_filter
+for each PHYSical IP interface used by FreeS/WAN. Settings are:
+ %unchanged do not touch (but warn if wrong)
+ 0 set to 0; default; means: no filtering
+ 1 set to 1; means: loose filter
+ 2 set to 1; means: strict filter
+0 is often necessary for FreeS/WAN to function. Some folks
+want other settings. Shutting down FreeS/WAN does not restore
+the original value.
+
+Currently ikelife defaults to 1 hour and keylife defaults to 8 hours.
+There have been some rumblings that these are the wrong defaults, but
+it isn't clear what would be best. Perhaps both should be closer.
+Any thoughts of what these should be? Any Road Warrior or OE conn
+should probably have carefully thought-out values explicitly
+specified. The settings don't matter much for VPN connections.
+
+keyingtries=%forever is the new improved notation for keyingtries=0.
+Eventually the 0 notation will be eliminated.
+
+Some options can now be set to %none to signify no setting. Otherwise
+there would be no way for the user to override a default setting:
+ leftrsasigkey, rightrsasigkey [added in 1.98]
+ interfaces
+
+Hugh Redelmeier
+hugh@mimosa.com voice: +1 416 482-8253
diff --git a/programs/_confread/_confread.8 b/programs/_confread/_confread.8
new file mode 100644
index 000000000..20d92a002
--- /dev/null
+++ b/programs/_confread/_confread.8
@@ -0,0 +1,28 @@
+.TH _CONFREAD 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _confread.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _confread \- internal routing to parse config file
+.SH DESCRIPTION
+.I _confread
+is an internal script used for parsing /etc/ipsec.conf into a canonical format.
+.SH "SEE ALSO"
+ipsec(8), ipsec_conf(8)
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Program written by Henry Spencer.
+.\"
+.\" $Log: _confread.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.3 2002/09/16 01:28:43 dhr
+.\"
+.\" typo
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\"
+.\"
diff --git a/programs/_confread/_confread.in b/programs/_confread/_confread.in
new file mode 100755
index 000000000..4561af9fe
--- /dev/null
+++ b/programs/_confread/_confread.in
@@ -0,0 +1,520 @@
+#!/bin/sh
+# configuration-file reader utility
+# Copyright (C) 1999-2002 Henry Spencer.
+#
+# 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: _confread.in,v 1.15 2006/04/20 04:42:12 as Exp $
+#
+# Extract configuration info from /etc/ipsec.conf, repackage as assignments
+# to shell variables or tab-delimited fields. Success or failure is reported
+# inline, as extra data, due to the vagaries of shell backquote handling.
+# In the absence of --varprefix, output is tab-separated fields, like:
+# = sectionname
+# : parameter value
+# ! status (empty for success, else complaint)
+# In the presence of (say) "--varprefix IPSEC", output is like:
+# IPSEC_confreadsection="sectionname"
+# IPSECparameter="value"
+# IPSEC_confreadstatus="status" (same empty/complaint convention)
+#
+# The "--search parametername" option inverts the search: instead of
+# yielding the parameters of the specified name(s), it yields the names
+# of sections with parameter <parametername> having (one of) the
+# specified value(s). In this case, --varprefix output is a list of
+# names in the <prefix>_confreadnames variable. Search values with
+# white space in them are currently not handled properly.
+#
+# Typical usage:
+# eval `ipsec _confread --varprefix IPSEC --type config setup`
+# if test " $IPSEC_confreadstatus" != " "
+# then
+# echo "$0: $IPSEC_confreadstatus -- aborting" 2>&1
+# exit 1
+# fi
+
+# absent default config file treated as empty
+config=${IPSEC_CONFS-@FINALCONFDIR@}/ipsec.conf
+if test ! -f "$config" ; then config=/dev/null ; fi
+
+include=yes
+type=conn
+fieldfmt=yes
+prefix=
+search=
+export=0
+version=
+optional=0
+me="ipsec _confread"
+
+for dummy
+do
+ case "$1" in
+ --config) config="$2" ; shift ;;
+ --noinclude) include= ;;
+ --type) type="$2" ; shift ;;
+ --varprefix) fieldfmt=
+ prefix="$2"
+ shift ;;
+ --export) export=1 ;;
+ --search) search="$2" ; shift ;;
+ --version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+ --optional) optional=1 ;;
+ --) shift ; break ;;
+ -*) echo "$0: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+if test "$include"
+then
+ ipsec _include --inband $config
+else
+ cat $config
+fi |
+awk 'BEGIN {
+ type = "'"$type"'"
+ names = "'"$*"'"
+ prefix = "'"$prefix"'"
+ export = "'"$export"'"
+ optional = 0 + '"$optional"'
+ myid = "'"$IPSECmyid"'"
+ search = "'"$search"'"
+ searching = 0
+ if (search != "") {
+ searching = 1
+ searchpat = search "[ \t]*=[ \t]*"
+ }
+ fieldfmt = 0
+ if ("'"$fieldfmt"'" == "yes")
+ fieldfmt = 1
+ including = 0
+ if ("'"$include"'" == "yes")
+ including = 1
+ filename = "'"$config"'"
+ lineno = 0
+ originalfilename = filename
+ if (fieldfmt)
+ bq = eq = "\""
+ else
+ bq = eq = "\\\""
+ failed = 0
+ insection = 0
+ wrongtype = 0
+ indefault = 0
+ outputting = 0
+ sawnondefault = 0
+ OFS = "\t"
+ o_status = "!"
+ o_parm = ":"
+ o_section = "="
+ o_names = "%"
+ o_end = "."
+ n = split(names, na, " ")
+ if (n == 0)
+ fail("no section names supplied")
+ for (i = 1; i <= n; i++) {
+ if (na[i] in wanted)
+ fail("section " bq na[i] eq " requested more than once")
+ wanted[na[i]] = 1
+ pending[na[i]] = 1
+ if (!searching && na[i] !~ /^[a-zA-Z][a-zA-Z0-9._-]*$/)
+ fail("invalid section name " bq na[i] eq)
+ }
+
+ good = "also alsoflip type auto authby _plutodevel"
+ left = " left leftsubnet leftnexthop leftfirewall lefthostaccess leftupdown"
+ akey = " keyexchange auth pfs keylife rekey rekeymargin rekeyfuzz"
+ akey = akey " dpdaction dpddelay dpdtimeout"
+ akey = akey " pfsgroup compress"
+ akey = akey " keyingtries ikelifetime disablearrivalcheck failureshunt ike"
+ mkey = " spibase spi esp espenckey espauthkey espreplay_window"
+ left = left " leftespenckey leftespauthkey leftahkey"
+ left = left " leftespspi leftahspi leftid leftrsasigkey leftrsasigkey2"
+ left = left " leftsendcert leftcert leftca leftsubnetwithin leftprotoport"
+ left = left " leftgroups leftsourceip"
+ mkey = mkey " ah ahkey ahreplay_window"
+ right = left
+ gsub(/left/, "right", right)
+ n = split(good left right akey mkey, g)
+ for (i = 1; i <= n; i++)
+ goodnames["conn:" g[i]] = 1
+
+ good = "also interfaces forwardcontrol myid"
+ good = good " syslog klipsdebug plutodebug plutoopts plutostderrlog"
+ good = good " plutorestartoncrash"
+ good = good " dumpdir manualstart pluto"
+ good = good " plutowait prepluto postpluto"
+ good = good " fragicmp hidetos rp_filter uniqueids"
+ good = good " overridemtu pkcs11module pkcs11keepstate pkcs11proxy"
+ good = good " nocrsend strictcrlpolicy crlcheckinterval cachecrls"
+ good = good " nat_traversal keep_alive force_keepalive"
+ good = good " disable_port_floating virtual_private"
+
+ n = split(good, g)
+ for (i = 1; i <= n; i++)
+ goodnames["config:" g[i]] = 1
+
+ good = "auto cacert ldaphost ldapbase crluri crluri2 ocspuri"
+ good = good " strictcrlpolicy"
+
+ n = split(good, g)
+ for (i = 1; i <= n; i++)
+ goodnames["ca:" g[i]] = 1
+
+ goodtypes["conn"] = 1
+ goodtypes["config"] = 1
+ goodtypes["ca"] = 1
+
+ badchars = ""
+ for (i = 1; i < 32; i++)
+ badchars = badchars sprintf("%c", i)
+ for (i = 127; i < 128+32; i++)
+ badchars = badchars sprintf("%c", i)
+ badchar = "[" badchars "]"
+
+ # if searching, seen is set of sectionnames which match
+ # if not searching, seen is set of parameter names found
+ seen[""] = ""
+ defaults[""] = ""
+ usesdefault[""] = ""
+ orientation = 1
+}
+
+
+
+function output(code, v1, v2) {
+ if (code == o_parm) {
+ if (v2 == "") # suppress empty parameters
+ return
+ if (privatename(v1)) # and private ones
+ return
+ if (v2 ~ badchar)
+ fail("parameter value " bq v2 eq " contains unprintable character")
+ }
+
+ if (fieldfmt) {
+ print code, v1, v2
+ return
+ }
+
+ if (code == o_status) {
+ v2 = v1
+ v1 = "_confreadstatus"
+ } else if (code == o_section) {
+ v2 = v1
+ v1 = "_confreadsection"
+ } else if (code == o_names) {
+ v2 = v1
+ v1 = "_confreadnames"
+ } else if (code != o_parm)
+ return # currently no variable version of o_end
+
+ print prefix v1 "=\"" v2 "\""
+ if (export)
+ print "export " prefix v1
+}
+function searchfound(sectionname, n, i, reflist) {
+ # a hit in x is a hit in everybody who refers to x too
+ n = split(refsto[sectionname], reflist, ";")
+ for (i = 1; i <= n; i++)
+ if (reflist[i] in seen)
+ fail("duplicated parameter " bq search eq)
+ else
+ seen[reflist[i]] = 1
+ seen[sectionname] = 1
+}
+function fail(msg) {
+ output(o_status, ("(" filename ", line " lineno ") " msg))
+ failed = 1
+ while ((getline junk) > 0)
+ continue
+ exit
+}
+function badname(n) {
+ if ((type ":" n) in goodnames)
+ return 0
+ if (privatename(n))
+ return 0
+ return 1
+}
+function privatename(n) {
+ if (n ~ /^[xX][-_]/)
+ return 1
+ return 0
+}
+function orient(n) {
+ if (orientation == -1) {
+ if (n ~ /left/)
+ gsub(/left/, "right", n)
+ else if (n ~ /right/)
+ gsub(/right/, "left", n)
+ }
+ return n
+}
+# in searching, referencing is transitive: xyz->from->to
+function chainref(from, to, i, reflist, listnum) {
+ if (from in refsto) {
+ listnum = split(refsto[from], reflist, ";")
+ for (i = 1; i <= listnum; i++)
+ chainref(reflist[i], to)
+ }
+ if (to in refsto)
+ refsto[to] = refsto[to] ";" from
+ else
+ refsto[to] = from
+}
+
+# start of rules
+
+{
+ lineno++
+ # lineno is now the number of this line
+
+ # we must remember indentation because comment stripping loses it
+ exdented = $0 !~ /^[ \t]/
+ sub(/^[ \t]+/, "") # get rid of leading white space
+ sub(/[ \t]+$/, "") # get rid of trailing white space
+}
+including && $0 ~ /^#[<>:]/ {
+ # _include control line
+ if ($1 ~ /^#[<>]$/) {
+ filename = $2
+ lineno = $3 - 1
+ } else if ($0 ~ /^#:/) {
+ msg = substr($0, 3)
+ gsub(/"/, "\\\"", msg)
+ fail(msg)
+ }
+ next
+}
+exdented {
+ # any non-leading-white-space line is a section end
+ ### but not the end of relevant stuff, might be also= sections later
+ ###if (insection && !indefault && !searching && outputting)
+ ### output(o_end)
+ insection = 0
+ wrongtype = 0
+ indefault = 0
+ outputting = 0
+}
+/[ \t]#/ {
+ # strip trailing comments including the leading whitespace
+ # tricky because we must respect quotes
+ q = 0
+ for (i = 1; i <= NF; i++) {
+ if ($i ~ /^#/ && q % 2 == 0) {
+ NF = i - 1;
+ break
+ }
+ # using $i in gsub loses whitespace?!?
+ junk = $i
+ q += gsub(/"/, "&", junk)
+ }
+}
+$0 == "" || $0 ~ /^#/ {
+ # empty lines and comments are ignored
+ next
+}
+exdented && NF != 2 {
+ # bad section header
+ fail("section header " bq $0 eq " has wrong number of fields (" NF ")")
+}
+exdented && $1 == "version" {
+ version = $2 + 0
+ if (version < 2.0 || 2.0 < version)
+ fail("we only support version 2.0 ipsec.conf files, not " bq version eq)
+ next
+}
+version == "" {
+ fail("we only support version 2 ipsec.conf files")
+}
+exdented && !($1 in goodtypes) {
+ # unknown section type
+ fail("section type " bq $1 eq " not recognized")
+}
+exdented && $1 != type {
+ # section header, but not of the type we want
+ insection = 1
+ wrongtype = 1
+ next
+}
+extented {
+ # type fits
+ wrongtype = 0
+}
+exdented && $1 == "config" && $2 != "setup" {
+ fail("unknown config section " bq $2 eq)
+}
+exdented && $2 != "%default" {
+ # non-default section header of our type
+ sawnondefault = 1
+}
+exdented && searching && $2 != "%default" {
+ # section header, during search
+ insection = 1
+ sectionname = $2
+ usesdefault[sectionname] = 1 # tentatively
+ next
+}
+exdented && !searching && $2 in wanted {
+ # one of our wanted section headers
+ if (!($2 in pending))
+ fail("duplicate " type " section " bq $2 eq)
+ delete pending[$2]
+ tag = bq type " " $2 eq
+ outputting = 1
+ insection = 1
+ orientation = wanted[$2]
+ output(o_section, $2)
+ next
+}
+exdented && $2 == "%default" {
+ # relevant default section header
+ if (sawnondefault)
+ fail(bq $1 " %default" eq " sections must precede non-default ones")
+ tag = bq type " " $2 eq
+ indefault = 1
+ next
+}
+exdented {
+ # section header, but not one we want
+ insection = 1
+ next
+}
+!insection && !indefault {
+ # starts with white space but not in a section... oops
+ fail("parameter is not within a section")
+}
+!wrongtype && searching && $0 ~ searchpat {
+ # search found the right parameter name
+ match($0, searchpat)
+ rest = substr($0, RLENGTH+1)
+ if (rest ~ /^".*"$/)
+ rest = substr(rest, 2, length(rest)-2)
+ if (!indefault) {
+ if (!usesdefault[sectionname])
+ fail("duplicated parameter " bq search eq)
+ usesdefault[sectionname] = 0
+ } else if (search in defaults)
+ fail("duplicated parameter " bq search eq)
+ if (rest in wanted) { # a hit
+ if (indefault)
+ defaults[search] = rest
+ else
+ searchfound(sectionname)
+ } else {
+ # rather a kludge, but must check this somewhere
+ if (search == "auto" && rest !~ /^(add|route|start|ignore|manual)$/)
+ fail("illegal auto value " bq rest eq)
+ }
+ next
+}
+!searching && !outputting && !indefault {
+ # uninteresting line
+ next
+}
+$0 ~ /"/ && $0 !~ /^[^=]+=[ \t]*"[^"]*"$/ {
+ if (!searching)
+ fail("mismatched quotes in parameter value")
+ else
+ gsub(/"/, "", $0)
+}
+$0 !~ /^[a-zA-Z_][a-zA-Z0-9_-]*[ \t]*=/ {
+ if (searching)
+ next # just ignore it
+ fail("syntax error or illegal parameter name")
+}
+{
+ sub(/[ \t]*=[ \t]*/, "=") # get rid of white space around =
+}
+$0 ~ /^(also|alsoflip)=/ {
+ v = orientation
+ if ($0 ~ /^alsoflip/)
+ v = -v;
+ if (indefault)
+ fail("%default section may not contain " bq "also" eq " or " bq "alsoflip" eq " parameter")
+ sub(/^(also|alsoflip)=/, "")
+ if ($0 !~ /^[a-zA-Z][a-zA-Z0-9._-]*$/)
+ fail("invalid section name " bq $0 eq)
+ if (!searching) {
+ if ($0 in wanted)
+ fail("section " bq $0 eq " requested more than once")
+ wanted[$0] = v
+ pending[$0] = 1
+ } else
+ chainref(sectionname, $0)
+ next
+}
+!outputting && !indefault {
+ # uninteresting line even for a search
+ next
+}
+{
+ equal = match($0, /[=]/)
+ name = substr($0, 1, equal-1)
+ if (badname(name))
+ fail("unknown parameter name " bq name eq)
+ value = substr($0, equal+1)
+ if (value ~ /^"/)
+ value = substr(value, 2, length(value)-2)
+ else if (value ~ /[ \t]/)
+ fail("white space within non-quoted parameter " bq name eq)
+}
+indefault {
+ if (name in defaults)
+ fail("duplicated default parameter " bq name eq)
+ defaults[name] = value
+ next
+}
+{
+ name = orient(name)
+ if (name in seen)
+ fail("duplicated parameter " bq name eq)
+ seen[name] = 1
+ output(o_parm, name, value)
+}
+END {
+ if (failed)
+ exit 1
+
+ filename = originalfilename
+ unseen = ""
+ for (i in pending)
+ unseen = unseen " " i
+ if (!optional && !searching && unseen != "")
+ fail("did not find " type " section(s) " bq substr(unseen, 2) eq)
+ if (!searching) {
+ for (name in defaults)
+ if (!(name in seen))
+ output(o_parm, name, defaults[name])
+ } else {
+ if (defaults[search] in wanted)
+ for (name in usesdefault)
+ if (usesdefault[name])
+ seen[name] = 1
+ delete seen[""]
+ if (fieldfmt)
+ for (name in seen)
+ output(o_section, name)
+ else {
+ outlist = ""
+ for (name in seen)
+ if (outlist == "")
+ outlist = name
+ else
+ outlist = outlist " " name
+ output(o_names, outlist)
+ }
+ }
+ output(o_status, "")
+}'
diff --git a/programs/_confread/block.in b/programs/_confread/block.in
new file mode 100644
index 000000000..e3a4b2dd5
--- /dev/null
+++ b/programs/_confread/block.in
@@ -0,0 +1,8 @@
+# This file defines the set of CIDRs (network/mask-length) to which
+# communication should never be allowed.
+#
+# See @FINALDOCDIR@/policygroups.html for details.
+#
+# $Id: block.in,v 1.1 2004/03/15 20:35:27 as Exp $
+#
+
diff --git a/programs/_confread/clear-or-private.in b/programs/_confread/clear-or-private.in
new file mode 100644
index 000000000..800093d94
--- /dev/null
+++ b/programs/_confread/clear-or-private.in
@@ -0,0 +1,8 @@
+# This file defines the set of CIDRs (network/mask-length) to which
+# we will communicate in the clear, or, if the other side initiates IPSEC,
+# using encryption. This behaviour is also called "Opportunistic Responder".
+#
+# See @FINALDOCDIR@/policygroups.html for details.
+#
+# $Id: clear-or-private.in,v 1.1 2004/03/15 20:35:27 as Exp $
+#
diff --git a/programs/_confread/clear.in b/programs/_confread/clear.in
new file mode 100644
index 000000000..46e63388e
--- /dev/null
+++ b/programs/_confread/clear.in
@@ -0,0 +1,7 @@
+# This file defines the set of CIDRs (network/mask-length) to which
+# communication should always be in the clear.
+#
+# See @FINALDOCDIR@/policygroups.html for details.
+#
+# $Id: clear.in,v 1.1 2004/03/15 20:35:27 as Exp $
+#
diff --git a/programs/_confread/ipsec.conf.5 b/programs/_confread/ipsec.conf.5
new file mode 100644
index 000000000..af6fae6bd
--- /dev/null
+++ b/programs/_confread/ipsec.conf.5
@@ -0,0 +1,1286 @@
+.TH IPSEC.CONF 5 "20 Jan 2006"
+.\" RCSID $Id: ipsec.conf.5,v 1.2 2006/01/22 15:33:46 as Exp $
+.SH NAME
+ipsec.conf \- IPsec configuration and connections
+.SH DESCRIPTION
+The optional
+.I ipsec.conf
+file
+specifies most configuration and control information for the
+strongSwan IPsec subsystem.
+(The major exception is secrets for authentication;
+see
+.IR ipsec.secrets (5).)
+Its contents are not security-sensitive
+.I unless
+manual keying is being done for more than just testing,
+in which case the encryption/authentication keys in the
+descriptions for the manually-keyed connections are very sensitive
+(and those connection descriptions
+are probably best kept in a separate file,
+via the include facility described below).
+.PP
+The file is a text file, consisting of one or more
+.IR sections .
+White space followed by
+.B #
+followed by anything to the end of the line
+is a comment and is ignored,
+as are empty lines which are not within a section.
+.PP
+A line which contains
+.B include
+and a file name, separated by white space,
+is replaced by the contents of that file,
+preceded and followed by empty lines.
+If the file name is not a full pathname,
+it is considered to be relative to the directory containing the
+including file.
+Such inclusions can be nested.
+Only a single filename may be supplied, and it may not contain white space,
+but it may include shell wildcards (see
+.IR sh (1));
+for example:
+.PP
+.B include
+.B "ipsec.*.conf"
+.PP
+The intention of the include facility is mostly to permit keeping
+information on connections, or sets of connections,
+separate from the main configuration file.
+This permits such connection descriptions to be changed,
+copied to the other security gateways involved, etc.,
+without having to constantly extract them from the configuration
+file and then insert them back into it.
+Note also the
+.B also
+parameter (described below) which permits splitting a single logical
+section (e.g. a connection description) into several actual sections.
+.PP
+The first significant line of the file must specify the version
+of this specification that it conforms to:
+.PP
+\fBversion 2\fP
+.PP
+A section
+begins with a line of the form:
+.PP
+.I type
+.I name
+.PP
+where
+.I type
+indicates what type of section follows, and
+.I name
+is an arbitrary name which distinguishes the section from others
+of the same type.
+(Names must start with a letter and may contain only
+letters, digits, periods, underscores, and hyphens.)
+All subsequent non-empty lines
+which begin with white space are part of the section;
+comments within a section must begin with white space too.
+There may be only one section of a given type with a given name.
+.PP
+Lines within the section are generally of the form
+.PP
+\ \ \ \ \ \fIparameter\fB=\fIvalue\fR
+.PP
+(note the mandatory preceding white space).
+There can be white space on either side of the
+.BR = .
+Parameter names follow the same syntax as section names,
+and are specific to a section type.
+Unless otherwise explicitly specified,
+no parameter name may appear more than once in a section.
+.PP
+An empty
+.I value
+stands for the system default value (if any) of the parameter,
+i.e. it is roughly equivalent to omitting the parameter line entirely.
+A
+.I value
+may contain white space only if the entire
+.I value
+is enclosed in double quotes (\fB"\fR);
+a
+.I value
+cannot itself contain a double quote,
+nor may it be continued across more than one line.
+.PP
+Numeric values are specified to be either an ``integer''
+(a sequence of digits) or a ``decimal number''
+(sequence of digits optionally followed by `.' and another sequence of digits).
+.PP
+There is currently one parameter which is available in any type of
+section:
+.TP
+.B also
+the value is a section name;
+the parameters of that section are appended to this section,
+as if they had been written as part of it.
+The specified section must exist, must follow the current one,
+and must have the same section type.
+(Nesting is permitted,
+and there may be more than one
+.B also
+in a single section,
+although it is forbidden to append the same section more than once.)
+This allows, for example, keeping the encryption keys
+for a connection in a separate file
+from the rest of the description, by using both an
+.B also
+parameter and an
+.B include
+line.
+.PP
+Parameter names beginning with
+.B x-
+(or
+.BR X- ,
+or
+.BR x_ ,
+or
+.BR X_ )
+are reserved for user extensions and will never be assigned meanings
+by IPsec.
+Parameters with such names must still observe the syntax rules
+(limits on characters used in the name;
+no white space in a non-quoted value;
+no newlines or double quotes within the value).
+All other as-yet-unused parameter names are reserved for future IPsec
+improvements.
+.PP
+A section with name
+.B %default
+specifies defaults for sections of the same type.
+For each parameter in it,
+any section of that type which does not have a parameter of the same name
+gets a copy of the one from the
+.B %default
+section.
+There may be multiple
+.B %default
+sections of a given type,
+but only one default may be supplied for any specific parameter name,
+and all
+.B %default
+sections of a given type must precede all non-\c
+.B %default
+sections of that type.
+.B %default
+sections may not contain the
+.B also
+parameter.
+.PP
+Currently there are three types of sections:
+a
+.B config
+section specifies general configuration information for IPsec, a
+.B conn
+section specifies an IPsec connection, while a
+.B ca
+section specifies special properties a certification authority.
+.SH "CONN SECTIONS"
+A
+.B conn
+section contains a
+.IR "connection specification" ,
+defining a network connection to be made using IPsec.
+The name given is arbitrary, and is used to identify the connection to
+.IR ipsec_auto (8)
+and
+.IR ipsec_manual (8).
+Here's a simple example:
+.PP
+.ne 10
+.nf
+.ft B
+.ta 1c
+conn snt
+ left=10.11.11.1
+ leftsubnet=10.0.1.0/24
+ leftnexthop=172.16.55.66
+ right=192.168.22.1
+ rightsubnet=10.0.2.0/24
+ rightnexthop=172.16.88.99
+ keyingtries=%forever
+.ft
+.fi
+.PP
+A note on terminology...
+In automatic keying, there are two kinds of communications going on:
+transmission of user IP packets, and gateway-to-gateway negotiations for
+keying, rekeying, and general control.
+The data path (a set of ``IPsec SAs'') used for user packets is herein
+referred to as the ``connection'';
+the path used for negotiations (built with ``ISAKMP SAs'') is referred to as
+the ``keying channel''.
+.PP
+To avoid trivial editing of the configuration file to suit it to each system
+involved in a connection,
+connection specifications are written in terms of
+.I left
+and
+.I right
+participants,
+rather than in terms of local and remote.
+Which participant is considered
+.I left
+or
+.I right
+is arbitrary;
+IPsec figures out which one it is being run on based on internal information.
+This permits using identical connection specifications on both ends.
+There are cases where there is no symmetry; a good convention is to
+use
+.I left
+for the local side and
+.I right
+for the remote side (the first letters are a good mnemonic).
+.PP
+Many of the parameters relate to one participant or the other;
+only the ones for
+.I left
+are listed here, but every parameter whose name begins with
+.B left
+has a
+.B right
+counterpart,
+whose description is the same but with
+.B left
+and
+.B right
+reversed.
+.PP
+Parameters are optional unless marked ``(required)'';
+a parameter required for manual keying need not be included for
+a connection which will use only automatic keying, and vice versa.
+.SS "CONN PARAMETERS: GENERAL"
+The following parameters are relevant to both automatic and manual keying.
+Unless otherwise noted,
+for a connection to work,
+in general it is necessary for the two ends to agree exactly
+on the values of these parameters.
+.TP 14
+.B type
+the type of the connection; currently the accepted values
+are
+.B tunnel
+(the default)
+signifying a host-to-host, host-to-subnet, or subnet-to-subnet tunnel;
+.BR transport ,
+signifying host-to-host transport mode;
+.BR passthrough ,
+signifying that no IPsec processing should be done at all;
+.BR drop ,
+signifying that packets should be discarded; and
+.BR reject ,
+signifying that packets should be discarded and a diagnostic ICMP returned.
+.TP
+.B left
+(required)
+the IP address of the left participant's public-network interface,
+in any form accepted by
+.IR ipsec_ttoaddr (3)
+or one of several magic values.
+If it is
+.BR %defaultroute ,
+and
+the
+.B config
+.B setup
+section's,
+.B interfaces
+specification contains
+.BR %defaultroute,
+.B left
+will be filled in automatically with the local address
+of the default-route interface (as determined at IPsec startup time);
+this also overrides any value supplied for
+.BR leftnexthop .
+(Either
+.B left
+or
+.B right
+may be
+.BR %defaultroute ,
+but not both.)
+The value
+.B %any
+signifies an address to be filled in (by automatic keying) during
+negotiation.
+The value
+.B %opportunistic
+signifies that both
+.B left
+and
+.B leftnexthop
+are to be filled in (by automatic keying) from DNS data for
+.BR left 's
+client.
+The values
+.B %group
+and
+.B %opportunisticgroup
+makes this a policy group conn: one that will be instantiated
+into a regular or opportunistic conn for each CIDR block listed in the
+policy group file with the same name as the conn.
+.TP
+.B leftsubnet
+private subnet behind the left participant, expressed as
+\fInetwork\fB/\fInetmask\fR
+(actually, any form acceptable to
+.IR ipsec_ttosubnet (3));
+if omitted, essentially assumed to be \fIleft\fB/32\fR,
+signifying that the left end of the connection goes to the left participant only
+.TP
+.B leftnexthop
+next-hop gateway IP address for the left participant's connection
+to the public network;
+defaults to
+.B %direct
+(meaning
+.IR right ).
+If the value is to be overridden by the
+.B left=%defaultroute
+method (see above),
+an explicit value must
+.I not
+be given.
+If that method is not being used,
+but
+.B leftnexthop
+is
+.BR %defaultroute ,
+and
+.B interfaces=%defaultroute
+is used in the
+.B config
+.B setup
+section,
+the next-hop gateway address of the default-route interface
+will be used.
+The magic value
+.B %direct
+signifies a value to be filled in (by automatic keying)
+with the peer's address.
+Relevant only locally, other end need not agree on it.
+.TP
+.B leftupdown
+what ``updown'' script to run to adjust routing and/or firewalling
+when the status of the connection
+changes (default
+.BR "ipsec _updown" ).
+May include positional parameters separated by white space
+(although this requires enclosing the whole string in quotes);
+including shell metacharacters is unwise.
+See
+.IR ipsec_pluto (8)
+for details.
+Relevant only locally, other end need not agree on it.
+.TP
+.B leftfirewall
+whether the left participant is doing forwarding-firewalling
+(including masquerading) for traffic from \fIleftsubnet\fR,
+which should be turned off (for traffic to the other subnet)
+once the connection is established;
+acceptable values are
+.B yes
+and (the default)
+.BR no .
+May not be used in the same connection description with
+.BR leftupdown .
+Implemented as a parameter to the default
+.I updown
+script.
+See notes below.
+Relevant only locally, other end need not agree on it.
+.PP
+If one or both security gateways are doing forwarding firewalling
+(possibly including masquerading),
+and this is specified using the firewall parameters,
+tunnels established with IPsec are exempted from it
+so that packets can flow unchanged through the tunnels.
+(This means that all subnets connected in this manner must have
+distinct, non-overlapping subnet address blocks.)
+This is done by the default
+.I updown
+script (see
+.IR ipsec_pluto (8)).
+.PP
+The implementation of this makes certain assumptions about firewall setup,
+notably the use of the old
+.I ipfwadm
+interface to the firewall.
+In situations calling for more control,
+it may be preferable for the user to supply his own
+.I updown
+script,
+which makes the appropriate adjustments for his system.
+.SS "CONN PARAMETERS: AUTOMATIC KEYING"
+The following parameters are relevant only to automatic keying,
+and are ignored in manual keying.
+Unless otherwise noted,
+for a connection to work,
+in general it is necessary for the two ends to agree exactly
+on the values of these parameters.
+.TP 14
+.B auto
+what operation, if any, should be done automatically at IPsec startup;
+currently-accepted values are
+.B add
+(signifying an
+.B ipsec auto
+.BR \-\-add ),
+.B route
+(signifying that plus an
+.B ipsec auto
+.BR \-\-route ),
+.B start
+(signifying that plus an
+.B ipsec auto
+.BR \-\-up ),
+.B manual
+(signifying an
+.B ipsec
+.B manual
+.BR \-\-up ),
+and
+.B ignore
+(also the default) (signifying no automatic startup operation).
+See the
+.B config
+.B setup
+discussion below.
+Relevant only locally, other end need not agree on it
+(but in general, for an intended-to-be-permanent connection,
+both ends should use
+.B auto=start
+to ensure that any reboot causes immediate renegotiation).
+.TP
+.B auth
+whether authentication should be done as part of
+ESP encryption, or separately using the AH protocol;
+acceptable values are
+.B esp
+(the default) and
+.BR ah .
+.TP
+.B authby
+how the two security gateways should authenticate each other;
+acceptable values are
+.B secret
+for shared secrets,
+.B rsasig
+for RSA digital signatures (the default),
+.B secret|rsasig
+for either, and
+.B never
+if negotiation is never to be attempted or accepted (useful for shunt-only conns).
+Digital signatures are superior in every way to shared secrets.
+.TP
+.B compress
+whether IPComp compression of content is proposed on the connection
+(link-level compression does not work on encrypted data,
+so to be effective, compression must be done \fIbefore\fR encryption);
+acceptable values are
+.B yes
+and
+.B no
+(the default).
+The two ends need not agree.
+A value of
+.B yes
+causes IPsec to propose both compressed and uncompressed,
+and prefer compressed.
+A value of
+.B no
+prevents IPsec from proposing compression;
+a proposal to compress will still be accepted.
+.TP
+.B disablearrivalcheck
+whether KLIPS's normal tunnel-exit check
+(that a packet emerging from a tunnel has plausible addresses in its header)
+should be disabled;
+acceptable values are
+.B yes
+and
+.B no
+(the default).
+Tunnel-exit checks improve security and do not break any normal configuration.
+Relevant only locally, other end need not agree on it.
+.TP
+.B dpdaction
+controls the use of the Dead Peer Detection protocol (DPD, RFC 3706) where
+R_U_THERE IKE notification messages are periodically sent in order to check the
+liveliness of the IPsec peer. The default is..
+.B none
+which disables the active sending of R_U_THERE notifications.
+Nevertheless pluto will always send the DPD Vendor ID during connection set up
+in order to signal the readiness to act passively as a responder if the peer
+wants to use DPD. The values
+.B clear
+and
+.B hold
+both activate DPD. If no activity is detected, all connections with a dead peer
+are stopped and unrouted (
+.B clear
+) or put in the hold state (
+.B hold
+).
+.TP
+.B dpddelay
+defines the period time interval with which R_U_THERE messages are sent to the peer.
+.TP
+.B dpdtimeout
+defines the timeout interval, after which all connections to a peer are deleted
+in case of inactivity.
+.TP
+.B failureshunt
+what to do with packets when negotiation fails.
+The default is
+.BR none :
+no shunt;
+.BR passthrough ,
+.BR drop ,
+and
+.B reject
+have the obvious meanings.
+.TP
+.B ikelifetime
+how long the keying channel of a connection (buzzphrase: ``ISAKMP SA'')
+should last before being renegotiated;
+acceptable values as for
+.B keyexchange
+method of key exchange;
+the default and currently the only accepted value is
+.B ike
+.TP
+.B keylife
+(default set by
+.IR ipsec_pluto (8),
+currently
+.BR 3h ,
+maximum
+.BR 24h ).
+The two-ends-disagree case is similar to that of
+.BR keylife .
+.TP
+.B keyingtries
+how many attempts (a whole number or \fB%forever\fP) should be made to
+negotiate a connection, or a replacement for one, before giving up
+(default
+.BR %forever ).
+The value \fB%forever\fP
+means ``never give up'' (obsolete: this can be written \fB0\fP).
+Relevant only locally, other end need not agree on it.
+.TP
+.B keylife
+how long a particular instance of a connection
+(a set of encryption/authentication keys for user packets) should last,
+from successful negotiation to expiry;
+acceptable values are an integer optionally followed by
+.BR s
+(a time in seconds)
+or a decimal number followed by
+.BR m ,
+.BR h ,
+or
+.B d
+(a time
+in minutes, hours, or days respectively)
+(default
+.BR 1h ,
+maximum
+.BR 24h ).
+Normally, the connection is renegotiated (via the keying channel)
+before it expires.
+The two ends need not exactly agree on
+.BR keylife ,
+although if they do not,
+there will be some clutter of superseded connections on the end
+which thinks the lifetime is longer.
+.TP
+.B leftca
+the distinguished name of a certificate authority which is required to
+lie in the trust path going from the left participant's certificate up
+to the root certification authority.
+.TP
+.B leftcert
+the path to the left participant's X.509 certificate. The file can be coded either in
+PEM or DER format. OpenPGP certificates are supported as well.
+Both absolute paths or paths relative to
+.B /etc/ipsec.d/certs
+are accepted. By default
+.B leftcert
+sets
+.B leftid
+to the distinguished name of the certificate's subject and
+.B leftca
+to the distinguished name of the certificate's issuer.
+The left participant's ID can be overriden by specifying a
+.B leftid
+value which must be certified by the certificate, though.
+.TP
+.B leftgroups
+a comma separated list of group names. If the
+.B leftgroups
+parameter is present then the peer must be a member of at least one
+of the groups defined by the parameter. Group membership must be certified
+by a valid attribute certificate stored in \fI/etc/ipsec.d/acerts\fP thas has been
+issued to the peer by a trusted Authorization Authority stored in
+\fI/etc/ipsec.d/aacerts\fP.
+.TP
+.B leftid
+how
+the left participant
+should be identified for authentication;
+defaults to
+.BR left .
+Can be an IP address (in any
+.IR ipsec_ttoaddr (3)
+syntax)
+or a fully-qualified domain name preceded by
+.B @
+(which is used as a literal string and not resolved).
+The magic value
+.B %myid
+stands for the current setting of \fImyid\fP.
+This is set in \fBconfig setup\fP or by \fIipsec_whack\fP(8)), or, if not set,
+it is the IP address in \fB%defaultroute\fP (if that is supported by a TXT record in its reverse domain), or otherwise
+it is the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined.
+.TP
+.B leftrsasigkey
+the left participant's
+public key for RSA signature authentication,
+in RFC 2537 format using
+.IR ipsec_ttodata (3)
+encoding.
+The magic value
+.B %none
+means the same as not specifying a value (useful to override a default).
+The value
+.B %cert
+(the default)
+means that the key is extracted from a certificate.
+The value
+.B %dnsondemand
+means the key is to be fetched from DNS at the time it is needed.
+The value
+.B %dnsonload
+means the key is to be fetched from DNS at the time
+the connection description is read from
+.IR ipsec.conf ;
+currently this will be treated as
+.B %none
+if
+.B right=%any
+or
+.BR right=%opportunistic .
+The value
+.B %dns
+is currently treated as
+.B %dnsonload
+but will change to
+.B %dnsondemand
+in the future.
+The identity used for the left participant
+must be a specific host, not
+.B %any
+or another magic value.
+.B Caution:
+if two connection descriptions
+specify different public keys for the same
+.BR leftid ,
+confusion and madness will ensue.
+.TP
+.B leftrsasigkey2
+if present, a second public key.
+Either key can authenticate the signature, allowing for key rollover.
+.TP
+.B leftsourceip
+.TP
+.B leftsubnetwithin
+.TP
+.B pfs
+whether Perfect Forward Secrecy of keys is desired on the connection's
+keying channel
+(with PFS, penetration of the key-exchange protocol
+does not compromise keys negotiated earlier);
+acceptable values are
+.B yes
+(the default)
+and
+.BR no .
+.TP
+.B rekey
+whether a connection should be renegotiated when it is about to expire;
+acceptable values are
+.B yes
+(the default)
+and
+.BR no .
+The two ends need not agree,
+but while a value of
+.B no
+prevents Pluto from requesting renegotiation,
+it does not prevent responding to renegotiation requested from the other end,
+so
+.B no
+will be largely ineffective unless both ends agree on it.
+.TP
+.B rekeyfuzz
+maximum percentage by which
+.B rekeymargin
+should be randomly increased to randomize rekeying intervals
+(important for hosts with many connections);
+acceptable values are an integer,
+which may exceed 100,
+followed by a `%'
+(default set by
+.IR ipsec_pluto (8),
+currently
+.BR 100% ).
+The value of
+.BR rekeymargin ,
+after this random increase,
+must not exceed
+.BR keylife .
+The value
+.B 0%
+will suppress time randomization.
+Relevant only locally, other end need not agree on it.
+.TP
+.B rekeymargin
+how long before connection expiry or keying-channel expiry
+should attempts to
+negotiate a replacement
+begin; acceptable values as for
+.B keylife
+(default
+.BR 9m ).
+Relevant only locally, other end need not agree on it.
+.SS "CONN PARAMETERS: MANUAL KEYING"
+The following parameters are relevant only to manual keying,
+and are ignored in automatic keying.
+Unless otherwise noted,
+for a connection to work,
+in general it is necessary for the two ends to agree exactly
+on the values of these parameters.
+A manually-keyed
+connection must specify at least one of AH or ESP.
+.TP 14
+.B spi
+(this or
+.B spibase
+required for manual keying)
+the SPI number to be used for the connection (see
+.IR ipsec_manual (8));
+must be of the form \fB0x\fIhex\fB\fR,
+where
+.I hex
+is one or more hexadecimal digits
+(note, it will generally be necessary to make
+.I spi
+at least
+.B 0x100
+to be acceptable to KLIPS,
+and use of SPIs in the range
+.BR 0x100 - 0xfff
+is recommended)
+.TP 14
+.B spibase
+(this or
+.B spi
+required for manual keying)
+the base number for the SPIs to be used for the connection (see
+.IR ipsec_manual (8));
+must be of the form \fB0x\fIhex\fB0\fR,
+where
+.I hex
+is one or more hexadecimal digits
+(note, it will generally be necessary to make
+.I spibase
+at least
+.B 0x100
+for the resulting SPIs
+to be acceptable to KLIPS,
+and use of numbers in the range
+.BR 0x100 - 0xff0
+is recommended)
+.TP
+.B esp
+ESP encryption/authentication algorithm to be used
+for the connection, e.g.
+.B 3des-md5-96
+(must be suitable as a value of
+.IR ipsec_spi (8)'s
+.B \-\-esp
+option);
+default is not to use ESP
+.TP
+.B espenckey
+ESP encryption key
+(must be suitable as a value of
+.IR ipsec_spi (8)'s
+.B \-\-enckey
+option)
+(may be specified separately for each direction using
+.B leftespenckey
+(leftward SA)
+and
+.B rightespenckey
+parameters)
+.TP
+.B espauthkey
+ESP authentication key
+(must be suitable as a value of
+.IR ipsec_spi (8)'s
+.B \-\-authkey
+option)
+(may be specified separately for each direction using
+.B leftespauthkey
+(leftward SA)
+and
+.B rightespauthkey
+parameters)
+.TP
+.B espreplay_window
+ESP replay-window setting,
+an integer from
+.B 0
+(the
+.IR ipsec_manual
+default, which turns off replay protection) to
+.BR 64 ;
+relevant only if ESP authentication is being used
+.TP
+.B leftespspi
+SPI to be used for the leftward ESP SA, overriding
+automatic assignment using
+.B spi
+or
+.BR spibase ;
+typically a hexadecimal number beginning with
+.B 0x
+.TP
+.B ah
+AH authentication algorithm to be used
+for the connection, e.g.
+.B hmac-md5-96
+(must be suitable as a value of
+.IR ipsec_spi (8)'s
+.B \-\-ah
+option);
+default is not to use AH
+.TP
+.B ahkey
+(required if
+.B ah
+is present) AH authentication key
+(must be suitable as a value of
+.IR ipsec_spi (8)'s
+.B \-\-authkey
+option)
+(may be specified separately for each direction using
+.B leftahkey
+(leftward SA)
+and
+.B rightahkey
+parameters)
+.TP
+.B ahreplay_window
+AH replay-window setting,
+an integer from
+.B 0
+(the
+.I ipsec_manual
+default, which turns off replay protection) to
+.B 64
+.TP
+.B leftahspi
+SPI to be used for the leftward AH SA, overriding
+automatic assignment using
+.B spi
+or
+.BR spibase ;
+typically a hexadecimal number beginning with
+.B 0x
+.SH "CA SECTIONS"
+This are optional sections that can be used to assign special
+parameters to a Certification Authority (CA).
+.TP 10
+.B auto
+currently can have either the value
+.B ignore
+or
+.B add
+.
+.TP
+.B cacert
+defines a path to the CA certificate either relative to
+\fI/etc/ipsec.d/cacerts\fP or as an absolute path.
+.TP
+.B crluri
+defines a CRL distribution point (ldap, http, or file URI)
+.TP
+.B crluri2
+defines an alternative CRL distribution point (ldap, http, or file URI)
+.TP
+.B ldaphost
+defines an ldap host.
+.TP
+.B ocspuri
+defines an OCSP URI.
+.SH "CONFIG SECTIONS"
+At present, the only
+.B config
+section known to the IPsec software is the one named
+.BR setup ,
+which contains information used when the software is being started
+(see
+.IR ipsec_setup (8)).
+Here's an example:
+.PP
+.ne 8
+.nf
+.ft B
+.ta 1c
+config setup
+ interfaces="ipsec0=eth1 ipsec1=ppp0"
+ klipsdebug=none
+ plutodebug=all
+ manualstart=
+.ft
+.fi
+.PP
+Parameters are optional unless marked ``(required)''.
+The currently-accepted
+.I parameter
+names in a
+.B config
+.B setup
+section are:
+.TP 14
+.B myid
+the identity to be used for
+.BR %myid .
+.B %myid
+is used in the implicit policy group conns and can be used as
+an identity in explicit conns.
+If unspecified,
+.B %myid
+is set to the IP address in \fB%defaultroute\fP (if that is supported by a TXT record in its reverse domain), or otherwise
+the system's hostname (if that is supported by a TXT record in its forward domain), or otherwise it is undefined.
+An explicit value generally starts with ``\fB@\fP''.
+.TP
+.B interfaces
+virtual and physical interfaces for IPsec to use:
+a single
+\fIvirtual\fB=\fIphysical\fR pair, a (quoted!) list of pairs separated
+by white space, or
+.BR %none .
+One of the pairs may be written as
+.BR %defaultroute ,
+which means: find the interface \fId\fR that the default route points to,
+and then act as if the value was ``\fBipsec0=\fId\fR''.
+.B %defaultroute
+is the default;
+.B %none
+must be used to denote no interfaces.
+If
+.B %defaultroute
+is used (implicitly or explicitly)
+information about the default route and its interface is noted for
+use by
+.IR ipsec_manual (8)
+and
+.IR ipsec_auto (8).)
+.TP
+.B forwardcontrol
+whether
+.I setup
+should turn IP forwarding on
+(if it's not already on) as IPsec is started,
+and turn it off again (if it was off) as IPsec is stopped;
+acceptable values are
+.B yes
+and (the default)
+.BR no .
+For this to have full effect, forwarding must be
+disabled before the hardware interfaces are brought
+up (e.g.,
+.B "net.ipv4.ip_forward\ =\ 0"
+in Red Hat 6.x
+.IR /etc/sysctl.conf ),
+because IPsec doesn't get control early enough to do that.
+.TP
+.B rp_filter
+whether and how
+.I setup
+should adjust the reverse path filtering mechanism for the
+physical devices to be used.
+Values are \fB%unchanged\fP (to leave it alone)
+or \fB0\fP, \fB1\fP, \fB2\fP (values to set it to).
+\fI/proc/sys/net/ipv4/conf/PHYS/rp_filter\fP
+is badly documented; it must be \fB0\fP in many cases
+for ipsec to function.
+The default value for the parameter is \fB0\fP.
+.TP
+.B syslog
+the
+.IR syslog (2)
+``facility'' name and priority to use for
+startup/shutdown log messages,
+default
+.BR daemon.error .
+.TP
+.B klipsdebug
+how much KLIPS debugging output should be logged.
+An empty value,
+or the magic value
+.BR none ,
+means no debugging output (the default).
+The magic value
+.B all
+means full output.
+Otherwise only the specified types of output
+(a quoted list, names separated by white space) are enabled;
+for details on available debugging types, see
+.IR ipsec_klipsdebug (8).
+.TP
+.B plutodebug
+how much Pluto debugging output should be logged.
+An empty value,
+or the magic value
+.BR none ,
+means no debugging output (the default).
+The magic value
+.B all
+means full output.
+Otherwise only the specified types of output
+(a quoted list, names without the
+.B \-\-debug\-
+prefix,
+separated by white space) are enabled;
+for details on available debugging types, see
+.IR ipsec_pluto (8).
+.TP
+.B plutoopts
+additional options to pass to pluto upon startup. See
+.IR ipsec_pluto (8).
+.TP
+.B plutostderrlog
+do not use syslog, but rather log to stderr, and direct stderr to the
+argument file.
+.TP
+.B dumpdir
+in what directory should things started by
+.I setup
+(notably the Pluto daemon) be allowed to
+dump core?
+The empty value (the default) means they are not
+allowed to.
+.TP
+.B manualstart
+which manually-keyed connections to set up at startup
+(empty, a name, or a quoted list of names separated by white space);
+see
+.IR ipsec_manual (8).
+Default is none.
+.TP
+.B pluto
+whether to start Pluto or not;
+Values are
+.B yes
+(the default)
+or
+.B no
+(useful only in special circumstances).
+.TP
+.B plutowait
+should Pluto wait for each
+negotiation attempt that is part of startup to
+finish before proceeding with the next?
+Values are
+.B yes
+or
+.BR no
+(the default).
+.TP
+.B prepluto
+shell command to run before starting Pluto
+(e.g., to decrypt an encrypted copy of the
+.I ipsec.secrets
+file).
+It's run in a very simple way;
+complexities like I/O redirection are best hidden within a script.
+Any output is redirected for logging,
+so running interactive commands is difficult unless they use
+.I /dev/tty
+or equivalent for their interaction.
+Default is none.
+.TP
+.B postpluto
+shell command to run after starting Pluto
+(e.g., to remove a decrypted copy of the
+.I ipsec.secrets
+file).
+It's run in a very simple way;
+complexities like I/O redirection are best hidden within a script.
+Any output is redirected for logging,
+so running interactive commands is difficult unless they use
+.I /dev/tty
+or equivalent for their interaction.
+Default is none.
+.TP
+.B fragicmp
+whether a tunnel's need to fragment a packet should be reported
+back with an ICMP message,
+in an attempt to make the sender lower his PMTU estimate;
+acceptable values are
+.B yes
+(the default)
+and
+.BR no .
+.TP
+.B hidetos
+whether a tunnel packet's TOS field should be set to
+.B 0
+rather than copied from the user packet inside;
+acceptable values are
+.B yes
+(the default)
+and
+.BR no .
+.TP
+.B uniqueids
+whether a particular participant ID should be kept unique,
+with any new (automatically keyed)
+connection using an ID from a different IP address
+deemed to replace all old ones using that ID;
+acceptable values are
+.B yes
+(the default)
+and
+.BR no .
+Participant IDs normally \fIare\fR unique,
+so a new (automatically-keyed) connection using the same ID is
+almost invariably intended to replace an old one.
+.TP
+.B overridemtu
+value that the MTU of the ipsec\fIn\fR interface(s) should be set to,
+overriding IPsec's (large) default.
+This parameter is needed only in special situations.
+.TP
+.B nat_traversal
+.TP
+.B crlcheckinterval
+.TP
+.B strictcrlpolicy
+.TP
+.B pkcs11module
+.TP
+.B pkcs11keepstate
+
+.SH CHOOSING A CONNECTION
+.PP
+When choosing a connection to apply to an outbound packet caught with a
+.BR %trap,
+the system prefers the one with the most specific eroute that
+includes the packet's source and destination IP addresses.
+Source subnets are examined before destination subnets.
+For initiating, only routed connections are considered. For responding,
+unrouted but added connections are considered.
+.PP
+When choosing a connection to use to respond to a negotiation which
+doesn't match an ordinary conn, an opportunistic connection
+may be instantiated. Eventually, its instance will be /32 -> /32, but
+for earlier stages of the negotiation, there will not be enough
+information about the client subnets to complete the instantiation.
+.SH FILES
+.nf
+/etc/ipsec.conf
+/etc/ipsec.d/cacerts
+/etc/ipsec.d/certs
+/etc/ipsec.d/crls
+/etc/ipsec.d/aacerts
+/etc/ipsec.d/acerts
+
+.SH SEE ALSO
+ipsec(8), ipsec_ttoaddr(8), ipsec_auto(8), ipsec_manual(8), ipsec_rsasigkey(8)
+.SH HISTORY
+Written for the FreeS/WAN project
+<http://www.freeswan.org>
+by Henry Spencer. Extended for the strongSwan project
+<http://www.strongswan.org>
+by Andreas Steffen.
+.SH BUGS
+.PP
+When
+.B type
+or
+.B failureshunt
+is set to
+.B drop
+or
+.BR reject,
+strongSwan blocks outbound packets using eroutes, but assumes inbound
+blocking is handled by the firewall. strongSwan offers firewall hooks
+via an ``updown'' script. However, the default
+.B ipsec _updown
+provides no help in controlling a modern firewall.
+.PP
+Including attributes of the keying channel
+(authentication methods,
+.BR ikelifetime ,
+etc.)
+as an attribute of a connection,
+rather than of a participant pair, is dubious and incurs limitations.
+.PP
+.IR Ipsec_manual
+is not nearly as generous about the syntax of subnets,
+addresses, etc. as the usual strongSwan user interfaces.
+Four-component dotted-decimal must be used for all addresses.
+It
+.I is
+smart enough to translate bit-count netmasks to dotted-decimal form.
+.PP
+It would be good to have a line-continuation syntax,
+especially for the very long lines involved in
+RSA signature keys.
+.PP
+The ability to specify different identities,
+.BR authby ,
+and public keys for different automatic-keyed connections
+between the same participants is misleading;
+this doesn't work dependably because the identity of the participants
+is not known early enough.
+This is especially awkward for the ``Road Warrior'' case,
+where the remote IP address is specified as
+.BR 0.0.0.0 ,
+and that is considered to be the ``participant'' for such connections.
+.PP
+In principle it might be necessary to control MTU on an
+interface-by-interface basis,
+rather than with the single global override that
+.B overridemtu
+provides.
+.PP
+A number of features which \fIcould\fR be implemented in
+both manual and automatic keying
+actually are not yet implemented for manual keying.
+This is unlikely to be fixed any time soon.
+.PP
+If conns are to be added before DNS is available,
+\fBleft=\fP\fIFQDN\fP,
+\fBleftnextop=\fP\fIFQDN\fP,
+and
+.B leftrsasigkey=%dnsonload
+will fail.
+.IR ipsec_pluto (8)
+does not actually use the public key for our side of a conn but it
+isn't generally known at a add-time which side is ours (Road Warrior
+and Opportunistic conns are currently exceptions).
+.PP
+The \fBmyid\fP option does not affect explicit \fB ipsec auto \-\-add\fP or \fBipsec auto \-\-replace\fP commands for implicit conns.
diff --git a/programs/_confread/ipsec.conf.in b/programs/_confread/ipsec.conf.in
new file mode 100644
index 000000000..296986459
--- /dev/null
+++ b/programs/_confread/ipsec.conf.in
@@ -0,0 +1,44 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+# RCSID $Id: ipsec.conf.in,v 1.7 2006/01/31 13:09:10 as Exp $
+
+# Manual: ipsec.conf.5
+# Help: http://www.strongswan.org/docs/readme.htm
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+# basic configuration
+
+config setup
+ # Debug-logging controls: "none" for (almost) none, "all" for lots.
+ # plutodebug=all
+ # crlcheckinterval=600
+ # strictcrlpolicy=yes
+ # cachecrls=yes
+ # nat_traversal=yes
+
+# Uncomment to activate Opportunistic Encryption (OE)
+# include /etc/ipsec.d/examples/oe.conf
+
+# Add connections here.
+
+# Sample VPN connections
+
+#conn sample-self-signed
+# left=%defaultroute
+# leftsubnet=10.1.0.0/16
+# leftcert=selfCert.der
+# leftsendcert=never
+# right=192.168.0.2
+# rightsubnet=10.2.0.0/16
+# rightcert=peerCert.der
+# auto=start
+
+#conn sample-with-ca-cert
+# left=%defaultroute
+# leftsubnet=10.1.0.0/16
+# leftcert=myCert.pem
+# right=192.168.0.2
+# rightsubnet=10.2.0.0/16
+# rightid="C=CH, O=Linux strongSwan CN=peer name"
+# auto=start
diff --git a/programs/_confread/private-or-clear.in b/programs/_confread/private-or-clear.in
new file mode 100644
index 000000000..c66b1d29f
--- /dev/null
+++ b/programs/_confread/private-or-clear.in
@@ -0,0 +1,14 @@
+# This file defines the set of CIDRs (network/mask-length) to which
+# communication should be private, if possible, but in the clear otherwise.
+#
+# If the target has a TXT (later IPSECKEY) record that specifies
+# authentication material, we will require private (i.e. encrypted)
+# communications. If no such record is found, communications will be
+# in the clear.
+#
+# See @FINALDOCDIR@/policygroups.html for details.
+#
+# $Id: private-or-clear.in,v 1.1 2004/03/15 20:35:27 as Exp $
+#
+
+0.0.0.0/0
diff --git a/programs/_confread/private.in b/programs/_confread/private.in
new file mode 100644
index 000000000..9d4bd6c67
--- /dev/null
+++ b/programs/_confread/private.in
@@ -0,0 +1,6 @@
+# This file defines the set of CIDRs (network/mask-length) to which
+# communication should always be private (i.e. encrypted).
+# See @FINALDOCDIR@/policygroups.html for details.
+#
+# $Id: private.in,v 1.1 2004/03/15 20:35:27 as Exp $
+#
diff --git a/programs/_confread/randomize b/programs/_confread/randomize
new file mode 100755
index 000000000..26d80a8f3
--- /dev/null
+++ b/programs/_confread/randomize
@@ -0,0 +1,28 @@
+#! /bin/sh
+# internal utility for putting random keys into sample configuration file
+# Copyright (C) 1998, 1999 Henry Spencer.
+#
+# 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: randomize,v 1.1 2004/03/15 20:35:27 as Exp $
+
+awk '/`[0-9]+`/ {
+ match($0, /`[0-9]+`/)
+ n = substr($0, RSTART+1, RLENGTH-2)
+ cmd = "./ranbits --quick " n
+ cmd | getline key
+ cmd | getline eof
+ close(cmd)
+ sub(/`[0-9]+`/, key, $0)
+ print
+ next
+}
+{ print }' $*
diff --git a/programs/_copyright/.cvsignore b/programs/_copyright/.cvsignore
new file mode 100644
index 000000000..23ebcb381
--- /dev/null
+++ b/programs/_copyright/.cvsignore
@@ -0,0 +1 @@
+_copyright
diff --git a/programs/_copyright/Makefile b/programs/_copyright/Makefile
new file mode 100644
index 000000000..52c594b68
--- /dev/null
+++ b/programs/_copyright/Makefile
@@ -0,0 +1,44 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_copyright
+PROGRAMDIR=${LIBDIR}
+LIBS=${FREESWANLIB}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.3 2002/08/02 16:01:07 mcr
+# moved user visible programs to $PREFIX/libexec, while moving
+# private files to $PREFIX/lib.
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/_copyright/_copyright.8 b/programs/_copyright/_copyright.8
new file mode 100644
index 000000000..87e4adc98
--- /dev/null
+++ b/programs/_copyright/_copyright.8
@@ -0,0 +1,32 @@
+.TH _COPYRIGHT 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _copyright.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _copyright \- prints FreeSWAN copyright
+.SH DESCRIPTION
+.I _copyright
+outputs the FreeSWAN copyright, and version numbers for "ipsec --copyright"
+.SH "SEE ALSO"
+ipsec(8)
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Michael Richardson. Program written by Henry Spencer.
+.\"
+.\" $Log: _copyright.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 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.
+.\"
+.\"
+.\"
diff --git a/programs/_copyright/_copyright.c b/programs/_copyright/_copyright.c
new file mode 100644
index 000000000..0fb360f40
--- /dev/null
+++ b/programs/_copyright/_copyright.c
@@ -0,0 +1,69 @@
+/*
+ * copyright reporter
+ * (just avoids having the info in more than one place in the source)
+ * Copyright (C) 2001 Henry Spencer.
+ *
+ * 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: _copyright.c,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <freeswan.h>
+
+char usage[] = "Usage: ipsec _copyright";
+struct option opts[] = {
+ {"help", 0, NULL, 'h',},
+ {"version", 0, NULL, 'v',},
+ {0, 0, NULL, 0, },
+};
+
+char me[] = "ipsec _copyright"; /* for messages */
+
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ extern int optind;
+ int errflg = 0;
+ const char *version = ipsec_version_code();
+ const char **notice = ipsec_copyright_notice();
+ const char **co;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ case 'h': /* help */
+ printf("%s\n", usage);
+ exit(0);
+ break;
+ case 'v': /* version */
+ printf("%s %s\n", me, version);
+ exit(0);
+ break;
+ case '?':
+ default:
+ errflg = 1;
+ break;
+ }
+ if (errflg || optind != argc) {
+ fprintf(stderr, "%s\n", usage);
+ exit(2);
+ }
+
+ for (co = notice; *co != NULL; co++)
+ printf("%s\n", *co);
+ exit(0);
+}
diff --git a/programs/_include/.cvsignore b/programs/_include/.cvsignore
new file mode 100644
index 000000000..ab6204115
--- /dev/null
+++ b/programs/_include/.cvsignore
@@ -0,0 +1 @@
+_include
diff --git a/programs/_include/Makefile b/programs/_include/Makefile
new file mode 100644
index 000000000..6b5f11682
--- /dev/null
+++ b/programs/_include/Makefile
@@ -0,0 +1,43 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_include
+PROGRAMDIR=${LIBDIR}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.3 2002/08/02 16:01:11 mcr
+# moved user visible programs to $PREFIX/libexec, while moving
+# private files to $PREFIX/lib.
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/_include/_include.8 b/programs/_include/_include.8
new file mode 100644
index 000000000..56ffa0723
--- /dev/null
+++ b/programs/_include/_include.8
@@ -0,0 +1,35 @@
+.TH _INCLUDE 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _include.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _include \- internal script to process config files
+.SH DESCRIPTION
+.I _include
+is used by
+.I _confread
+to process
+.B include
+directives in /etc/ipsec.conf.
+.SH "SEE ALSO"
+ipsec(8), ipsec__confread(8)
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Program written by Henry Spencer.
+.\"
+.\" $Log: _include.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 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.
+.\"
+.\"
+.\"
diff --git a/programs/_include/_include.in b/programs/_include/_include.in
new file mode 100755
index 000000000..10a8a49e4
--- /dev/null
+++ b/programs/_include/_include.in
@@ -0,0 +1,102 @@
+#! /bin/sh
+# implements nested file inclusion for control files, including wildcarding
+# Copyright (C) 1998, 1999 Henry Spencer.
+#
+# 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: _include.in,v 1.2 2004/03/15 21:03:06 as Exp $
+#
+# Output includes marker lines for file changes:
+# "#< filename lineno" signals entry into that file
+# "#> filename lineno" signals return to that file
+# The lineno is the line number of the *next* line.
+#
+# Errors are reported with a "#:message" line rather than on stderr.
+#
+# Lines which look like marker and report lines are never passed through.
+
+IPSEC_NAME="strongSwan"
+
+usage="Usage: $0 file ..."
+me="ipsec _include"
+
+for dummy
+do
+ case "$1" in
+ --inband) ;; # back compatibility
+ --help) echo "$usage" ; exit 0 ;;
+ --version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+ --) shift ; break ;;
+ -*) echo "$0: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+case $# in
+0) echo "$usage" >&2 ; exit 2 ;;
+esac
+
+for f
+do
+ if test ! -r "$f"
+ then
+ if test ! "$f" = "/etc/ipsec.conf"
+ then
+ echo "#:cannot open configuration file \'$f\'"
+ if test "$f" = "/etc/ipsec.secrets"
+ then
+ echo "#:Your secrets file will be created when you start $IPSEC_NAME for the first time."
+ fi
+ exit 1
+ else
+ exit 1
+ fi
+ fi
+done
+
+awk 'BEGIN {
+ wasfile = ""
+}
+FNR == 1 {
+ print ""
+ print "#<", FILENAME, 1
+ lineno = 0
+ wasfile = FILENAME
+}
+{
+ lineno++
+ # lineno is now the number of this line
+}
+/^#[<>:]/ {
+ next
+}
+/^include[ \t]+/ {
+ orig = $0
+ sub(/[ \t]+#.*$/, "")
+ if (NF != 2) {
+ msg = "(" FILENAME ", line " lineno ")"
+ msg = msg " include syntax error in \"" orig "\""
+ print "#:" msg
+ exit 1
+ }
+ newfile = $2
+ if (newfile !~ /^\// && FILENAME ~ /\//) {
+ prefix = FILENAME
+ sub("[^/]+$", "", prefix)
+ newfile = prefix newfile
+ }
+ system("ipsec _include " newfile)
+ print ""
+ print "#>", FILENAME, lineno + 1
+ next
+}
+{ print }' $*
diff --git a/programs/_keycensor/.cvsignore b/programs/_keycensor/.cvsignore
new file mode 100644
index 000000000..97d0bb2bf
--- /dev/null
+++ b/programs/_keycensor/.cvsignore
@@ -0,0 +1 @@
+_keycensor
diff --git a/programs/_keycensor/Makefile b/programs/_keycensor/Makefile
new file mode 100644
index 000000000..bc495328f
--- /dev/null
+++ b/programs/_keycensor/Makefile
@@ -0,0 +1,43 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_keycensor
+PROGRAMDIR=${LIBDIR}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.3 2002/08/02 16:01:15 mcr
+# moved user visible programs to $PREFIX/libexec, while moving
+# private files to $PREFIX/lib.
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/_keycensor/_keycensor.8 b/programs/_keycensor/_keycensor.8
new file mode 100644
index 000000000..89a97a9f9
--- /dev/null
+++ b/programs/_keycensor/_keycensor.8
@@ -0,0 +1,33 @@
+.TH _KEYCENSOR 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _keycensor.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _keycensor \- internal routine to remove sensitive information
+.SH DESCRIPTION
+.I _keycensor
+is used by
+.B ipsec barf
+to process the /etc/ipsec.secrets file, removing private key info.
+.SH "SEE ALSO"
+ipsec(8), ipsec_barf(8)
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Original program by Henry Spencer.
+.\"
+.\" $Log: _keycensor.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 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.
+.\"
+.\"
+.\"
diff --git a/programs/_keycensor/_keycensor.in b/programs/_keycensor/_keycensor.in
new file mode 100755
index 000000000..7d6f257e5
--- /dev/null
+++ b/programs/_keycensor/_keycensor.in
@@ -0,0 +1,52 @@
+#! /bin/sh
+# implements key censoring for barf
+# Copyright (C) 1999, 2002 Henry Spencer.
+#
+# 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: _keycensor.in,v 1.1 2004/03/15 20:35:27 as Exp $
+
+usage="Usage: $0 [file ...]"
+me="ipsec _keycensor"
+
+for dummy
+do
+ case "$1" in
+ --help) echo "$usage" ; exit 0 ;;
+ --version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+ --) shift ; break ;;
+ -*) echo "$0: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+awk ' /(sig|enc|auth)key[ \t]*=[ \t]*[^%]/ {
+ i = match($0, /key[ \t]*=[ \t]*/)
+ i += RLENGTH
+ cold = substr($0, 1, i-1)
+ hot = substr($0, i)
+ sub(/[ \t]+(#.*)?$/, "", hot)
+ q = "'"'"'" # single quote
+ if (hot ~ q)
+ cooled = "[cannot be condensed]"
+ else if (hot ~ /^0s/)
+ cooled = "[keyid " substr(hot, 3, 9) "]"
+ else {
+ run = "echo " q hot q " | md5sum"
+ run | getline
+ close(run)
+ cooled = "[sums to " substr($1, 1, 4) "...]"
+ }
+ print cold cooled
+ next
+ }
+ { print }' $*
diff --git a/programs/_plutoload/.cvsignore b/programs/_plutoload/.cvsignore
new file mode 100644
index 000000000..cbcf7e699
--- /dev/null
+++ b/programs/_plutoload/.cvsignore
@@ -0,0 +1 @@
+_plutoload
diff --git a/programs/_plutoload/Makefile b/programs/_plutoload/Makefile
new file mode 100644
index 000000000..af9ffee18
--- /dev/null
+++ b/programs/_plutoload/Makefile
@@ -0,0 +1,43 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_plutoload
+PROGRAMDIR=${LIBDIR}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.3 2002/08/02 16:01:19 mcr
+# moved user visible programs to $PREFIX/libexec, while moving
+# private files to $PREFIX/lib.
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/_plutoload/_plutoload.8 b/programs/_plutoload/_plutoload.8
new file mode 100644
index 000000000..ba421b6c3
--- /dev/null
+++ b/programs/_plutoload/_plutoload.8
@@ -0,0 +1,33 @@
+.TH _PLUTOLOAD 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _plutoload.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _plutoload \- internal script to start pluto
+.SH DESCRIPTION
+.I _plutoload
+is called by
+.B _plutorun
+to actually start the pluto executable.
+.SH "SEE ALSO"
+ipsec(8), ipsec_setup(8), ipsec__realsetup(8), ipsec__plutorun(8)
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Original program by Henry Spencer.
+.\"
+.\" $Log: _plutoload.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 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.
+.\"
+.\"
+.\"
diff --git a/programs/_plutoload/_plutoload.in b/programs/_plutoload/_plutoload.in
new file mode 100755
index 000000000..73841197d
--- /dev/null
+++ b/programs/_plutoload/_plutoload.in
@@ -0,0 +1,164 @@
+#!/bin/sh
+# Pluto database-loading script
+# Copyright (C) 1998, 1999, 2001 Henry Spencer.
+#
+# 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: _plutoload.in,v 1.2 2004/03/31 16:15:10 as Exp $
+#
+# exit status is 13 for protocol violation, that of Pluto otherwise
+
+me='ipsec _plutoload' # for messages
+
+for dummy
+do
+ case "$1" in
+ --load) plutoload="$2" ; shift ;;
+ --start) plutostart="$2" ; shift ;;
+ --wait) plutowait="$2" ; shift ;;
+ --post) postpluto="$2" ; shift ;;
+ --) shift ; break ;;
+ -*) echo "$me: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+# load ca information
+eval `ipsec _confread --varprefix PLUTO --type ca --search auto add start`
+if test " $PLUTO_confreadstatus" != " "
+then
+ echo "auto=add/start search: $PLUTO_confreadstatus"
+ echo "unable to determine what ca information to add -- adding none"
+ caload=
+else
+ caload="$PLUTO_confreadnames"
+fi
+
+# searches, if needed
+# the way the searches were done ensures plutoload >= plutoroute >= plutostart
+
+# search for things to "ipsec auto --add": auto in "add" "route" "start"
+eval `ipsec _confread --varprefix PLUTO --search auto add route start`
+if test " $PLUTO_confreadstatus" != " "
+then
+ echo "auto=add/route/start search: $PLUTO_confreadstatus"
+ echo "unable to determine what conns to add -- adding none"
+ plutoload=
+else
+ plutoload="$PLUTO_confreadnames"
+fi
+
+# search for things to "ipsec auto --route": auto in "route" "start"
+eval `ipsec _confread --varprefix PLUTO --search auto route start`
+if test " $PLUTO_confreadstatus" != " "
+then
+ echo "auto=route/start search: $PLUTO_confreadstatus"
+ echo "unable to determine what conns to route -- routing none"
+ plutoroute=
+else
+ plutoroute="$PLUTO_confreadnames"
+fi
+
+# search for things to "ipsec auto --up": auto in "start"
+eval `ipsec _confread --varprefix PLUTO --search auto start`
+if test " $PLUTO_confreadstatus" != " "
+then
+ echo "auto=start search: $PLUTO_confreadstatus"
+ echo "unable to determine what conns to start -- starting none"
+ plutostart=
+else
+ plutostart="$PLUTO_confreadnames"
+fi
+
+# await Pluto's readiness (not likely to be an issue, but...)
+eofed=y
+while read saying
+do
+ case "$saying" in
+ 'Pluto initialized') eofed= ; break ;; # NOTE BREAK OUT
+ *) echo "pluto unexpectedly said \`$saying'" ;;
+ esac
+done
+if test "$eofed"
+then
+ echo "pluto died unexpectedly!?!"
+ exit 13
+fi
+
+# ca database load
+for tu in $caload
+do
+ ipsec auto --type ca --add $tu ||
+ echo "...could not add ca \"$tu\""
+done
+
+# conn database load
+for tu in $plutoload
+do
+ ipsec auto --add $tu ||
+ echo "...could not add conn \"$tu\""
+done
+
+# enable listening
+ipsec auto --ready
+
+# execute any post-startup cleanup
+if test " $postpluto" != " "
+then
+ $postpluto
+ st=$?
+ if test " $st" -ne 0
+ then
+ echo "...postpluto command exited with status $st"
+ fi
+fi
+
+# quickly establish routing
+for tu in $plutoroute
+do
+ ipsec auto --route $tu ||
+ echo "...could not route conn \"$tu\""
+done
+
+# tunnel initiation, which may take a while
+async=
+if test " $plutowait" = " no"
+then
+ async="--asynchronous"
+fi
+for tu in $plutostart
+do
+ ipsec auto --up $async $tu ||
+ echo "...could not start conn \"$tu\""
+done
+
+# report any further utterances, and watch for exit status
+eofed=y
+while read saying
+do
+ case "$saying" in
+ exit) eofed= ; break ;; # NOTE BREAK OUT
+ *) echo "pluto unexpectedly says \`$saying'" ;;
+ esac
+done
+if test "$eofed"
+then
+ echo "pluto died without exit status!?!"
+ exit 13
+fi
+if read status
+then
+ exit $status
+else
+ echo "pluto yielded no exit status!?!"
+ exit 13
+fi
diff --git a/programs/_plutorun/.cvsignore b/programs/_plutorun/.cvsignore
new file mode 100644
index 000000000..13e0ae1a1
--- /dev/null
+++ b/programs/_plutorun/.cvsignore
@@ -0,0 +1 @@
+_plutorun
diff --git a/programs/_plutorun/Makefile b/programs/_plutorun/Makefile
new file mode 100644
index 000000000..b0928797c
--- /dev/null
+++ b/programs/_plutorun/Makefile
@@ -0,0 +1,43 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_plutorun
+PROGRAMDIR=${LIBDIR}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.3 2002/08/02 16:01:26 mcr
+# moved user visible programs to $PREFIX/libexec, while moving
+# private files to $PREFIX/lib.
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/_plutorun/_plutorun.8 b/programs/_plutorun/_plutorun.8
new file mode 100644
index 000000000..9de6927dc
--- /dev/null
+++ b/programs/_plutorun/_plutorun.8
@@ -0,0 +1,37 @@
+.TH _PLUTORUN 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _plutorun.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _plutorun \- internal script to start pluto
+.SH DESCRIPTION
+.I _plutorun
+is called by
+.B _realsetup
+to configure and bring up
+.B ipsec_pluto(8).
+It calls
+.B _plutoload
+to invoke pluto, and watches to makes sure that pluto is restarted if it fails.
+.SH "SEE ALSO"
+ipsec(8), ipsec_setup(8), ipsec__realsetup(8), ipsec__plutoload(8), ipsec_pluto(8).
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Original program written by Henry Spencer.
+.\"
+.\" $Log: _plutorun.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 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.
+.\"
+.\"
+.\"
diff --git a/programs/_plutorun/_plutorun.in b/programs/_plutorun/_plutorun.in
new file mode 100755
index 000000000..b02afeefb
--- /dev/null
+++ b/programs/_plutorun/_plutorun.in
@@ -0,0 +1,281 @@
+#!/bin/sh
+# Pluto control daemon
+# Copyright (C) 1998, 1999, 2001 Henry Spencer.
+#
+# 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: _plutorun.in,v 1.9 2005/10/16 13:28:15 as Exp $
+
+me='ipsec _plutorun' # for messages
+
+info=/var/run/ipsec.info
+
+popts=
+stderrlog=
+plutorestartoncrash=true
+
+wherelog=daemon.error
+pidfile=/var/run/pluto.pid
+verb="Starting"
+for dummy
+do
+ case "$1" in
+ --re) verb="Restarting" ;;
+ --plutorestartoncrash) plutorestartoncrash="$2"; shift ;;
+ --debug) plutodebug="$2" ; shift ;;
+ --uniqueids) uniqueids="$2" ; shift ;;
+ --nat_traversal) nat_traversal="$2" ; shift ;;
+ --keep_alive) keep_alive="$2" ; shift ;;
+ --force_keepalive) force_keepalive="$2" ; shift ;;
+ --disable_port_floating) disable_port_floating="$2" ; shift ;;
+ --virtual_private) virtual_private="$2" ; shift ;;
+ --nocrsend) nocrsend="$2" ; shift ;;
+ --strictcrlpolicy) strictcrlpolicy="$2" ; shift ;;
+ --crlcheckinterval) crlcheckinterval="$2"; shift ;;
+ --cachecrls) cachecrls="$2" ; shift ;;
+ --pkcs11module) pkcs11module="$2"; shift ;;
+ --pkcs11keepstate) pkcs11keepstate="$2"; shift ;;
+ --pkcs11proxy) pkcs11proxy="$2"; shift ;;
+ --dump) dumpdir="$2" ; shift ;;
+ --opts) popts="$2" ; shift ;;
+ --stderrlog) stderrlog="$2" ; shift ;;
+ --wait) plutowait="$2" ; shift ;;
+ --pre) prepluto="$2" ; shift ;;
+ --post) postpluto="$2" ; shift ;;
+ --log) wherelog="$2" ; shift ;;
+ --pid) pidfile="$2" ; shift ;;
+ --) shift ; break ;;
+ -*) echo "$me: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+# initially we are in the foreground, with parent looking after logging
+
+# precautions
+if test -f $pidfile
+then
+ echo "pluto appears to be running already (\`$pidfile' exists), will not start another"
+ exit 1
+fi
+if test ! -e /dev/urandom
+then
+ echo "cannot start Pluto, system lacks \`/dev/urandom'!?!"
+ exit 1
+fi
+
+# sort out options
+for d in $plutodebug
+do
+ popts="$popts --debug-$d"
+done
+case "$uniqueids" in
+yes) popts="$popts --uniqueids" ;;
+no|'') ;;
+*) echo "unknown uniqueids value (not yes/no) \`$IPSECuniqueids'" ;;
+esac
+case "$nocrsend" in
+yes) popts="$popts --nocrsend" ;;
+no|'') ;;
+*) echo "unknown nocrsend value (not yes/no) \`$IPSECnocrsend'" ;;
+esac
+case "$strictcrlpolicy" in
+yes) popts="$popts --strictcrlpolicy" ;;
+no|'') ;;
+*) echo "unknown strictcrlpolicy value (not yes/no) \`$IPSECstrictcrlpolicy'" ;;
+esac
+case "$cachecrls" in
+yes) popts="$popts --cachecrls" ;;
+no|'') ;;
+*) echo "unknown cachecrls value (not yes/no) \`$IPSECcachecrls'" ;;
+esac
+case "$nat_traversal" in
+yes) popts="$popts --nat_traversal" ;;
+no|'') ;;
+*) echo "unknown nat_traversal value (not yes/no) \`$IPSECnat_traversal'" ;;
+esac
+[ -n "$keep_alive" ] && popts="$popts --keep_alive $keep_alive"
+case "$force_keepalive" in
+yes) popts="$popts --force_keepalive" ;;
+no|'') ;;
+*) echo "unknown force_keepalive value (not yes/no) \`$IPSECforce_keepalive'" ;;
+esac
+case "$disable_port_floating" in
+yes) popts="$popts --disable_port_floating" ;;
+no|'') ;;
+*) echo "unknown disable_port_floating (not yes/no) \`$disable_port_floating'" ;;
+esac
+case "$pkcs11keepstate" in
+yes) popts="$popts --pkcs11keepstate" ;;
+no|'') ;;
+*) echo "unknown pkcs11keepstate value (not yes/no) \`$IPSECpkcs11keepstate'" ;;
+esac
+case "$pkcs11proxy" in
+yes) popts="$popts --pkcs11proxy" ;;
+no|'') ;;
+*) echo "unknown pkcs11proxy value (not yes/no) \`$IPSECpkcs11proxy'" ;;
+esac
+
+[ -n "$virtual_private" ] && popts="$popts --virtual_private $virtual_private"
+
+# add crl check interval
+if test ${crlcheckinterval:-0} -gt 0
+then
+ popts="$popts --crlcheckinterval $crlcheckinterval"
+fi
+
+if test -n "$pkcs11module"
+then
+ popts="$popts --pkcs11module $pkcs11module"
+fi
+
+if test -n "$stderrlog"
+then
+ popts="$popts --stderrlog 2>>$stderrlog"
+
+ if test -f $stderrlog
+ then
+ if test ! -w $stderrlog
+ then
+ echo Cannot write to \"$stderrlog\".
+ exit 1
+ fi
+ else
+ if test ! -w "`dirname $stderrlog`"
+ then
+ echo Cannot write to directory to create \"$stderrlog\".
+ exit 1
+ fi
+ fi
+
+ echo "Plutorun started on "`date` >$stderrlog
+fi
+
+# set up dump directory
+if test " $dumpdir" = " "
+then
+ ulimit -c 0 # preclude core dumps
+elif test ! -d "$dumpdir"
+then
+ echo "dumpdir \`$dumpdir' does not exist, ignored"
+ ulimit -c 0 # preclude core dumps
+elif cd $dumpdir # put them where desired
+then
+ ulimit -c unlimited # permit them
+else
+ echo "cannot cd to dumpdir \`$dumpdir', ignored"
+ ulimit -c 0 # preclude them
+fi
+
+# execute any preliminaries
+if test " $prepluto" != " "
+then
+ $prepluto
+ st=$?
+ if test " $st" -ne 0
+ then
+ echo "...prepluto command exited with status $st"
+ fi
+fi
+
+IPSEC_SECRETS=${IPSEC_CONFS}/ipsec.secrets
+if test ! -f "${IPSEC_SECRETS}"
+then
+ ( logger -p authpriv.info -t ipsec__plutorun No file ${IPSEC_SECRETS}, generating key.
+ ipsec scepclient --out pkcs1 --out cert-self --quiet
+ echo -e "# /etc/ipsec.secrets - strongSwan IPsec secrets file\n" > ${IPSEC_SECRETS}
+ chmod 600 ${IPSEC_SECRETS}
+ echo ": RSA myKey.der" >> ${IPSEC_SECRETS}
+
+ # tell pluto to go re-read the file
+ ipsec auto --rereadsecrets
+ ) &
+fi
+
+#
+# make sure that the isakmp port is open!
+#
+if test -f /etc/sysconfig/ipchains
+then
+ if egrep -q 500:500 /etc/sysconfig/ipchains
+ then
+ :
+ else
+ ipchains -I input 1 -p udp -s 0.0.0.0/0.0.0.0 -d 0.0.0.0/0.0.0.0 500:500 -j ACCEPT
+ # if it redhat, then save the rules again.
+ if [ -f /etc/redhat-release ]
+ then
+ sh /etc/rc.d/init.d/ipchains save
+ fi
+ fi
+fi
+
+# spin off into the background, with our own logging
+echo "$verb Pluto subsystem..." | logger -p authpriv.error -t ipsec__plutorun
+execdir=${IPSEC_EXECDIR-@IPSEC_EXECDIR@}
+libdir=${IPSEC_LIBDIR-@IPSEC_LIBDIR@}
+until (
+ if test -s $info
+ then
+ . $info
+ export defaultroutephys defaultroutevirt defaultrouteaddr defaultroutenexthop
+ fi
+ # eval allows $popts to contain redirection and other magic
+ eval $execdir/pluto --nofork --secretsfile "$IPSEC_SECRETS" --policygroupsdir "${IPSEC_CONFS}/ipsec.d/policies" $popts
+ status=$?
+ echo "exit"
+ echo $status
+ ) | $libdir/_plutoload --wait "$plutowait" --post "$postpluto"
+do
+ status=$?
+ case "$status" in
+ 13) echo "internal failure in pluto scripts, impossible to carry on"
+ exit 1
+ ;;
+ 10) echo "pluto apparently already running (?!?), giving up"
+ exit 1
+ ;;
+ 137) echo "pluto killed by SIGKILL, terminating without restart or unlock"
+ exit 0
+ ;;
+ 143) echo "pluto killed by SIGTERM, terminating without restart"
+ # pluto now does its own unlock for this
+ exit 0
+ ;;
+ *) st=$status
+ if $plutorestartoncrash
+ then
+ :
+ else
+ exit 0
+ fi
+
+ if test $st -gt 128
+ then
+ st="$st (signal `expr $st - 128`)"
+ fi
+ echo "!pluto failure!: exited with error status $st"
+ echo "restarting IPsec after pause..."
+ (
+ sleep 10
+ ipsec setup _autorestart
+ ) </dev/null >/dev/null 2>&1 &
+ exit 1
+ ###sleep 10
+ ###rm -rf $pidfile
+ #### and go around the loop again
+ ;;
+ esac
+done </dev/null 2>&1 |
+ logger -s -p $wherelog -t ipsec__plutorun >/dev/null 2>/dev/null &
+
+exit 0
diff --git a/programs/_realsetup/.cvsignore b/programs/_realsetup/.cvsignore
new file mode 100644
index 000000000..54941b8a3
--- /dev/null
+++ b/programs/_realsetup/.cvsignore
@@ -0,0 +1 @@
+_realsetup
diff --git a/programs/_realsetup/Makefile b/programs/_realsetup/Makefile
new file mode 100644
index 000000000..c339007e0
--- /dev/null
+++ b/programs/_realsetup/Makefile
@@ -0,0 +1,43 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_realsetup
+PROGRAMDIR=${LIBDIR}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.3 2002/08/02 16:01:34 mcr
+# moved user visible programs to $PREFIX/libexec, while moving
+# private files to $PREFIX/lib.
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/_realsetup/_realsetup.8 b/programs/_realsetup/_realsetup.8
new file mode 100644
index 000000000..51b647115
--- /dev/null
+++ b/programs/_realsetup/_realsetup.8
@@ -0,0 +1,36 @@
+.TH _REALSETUP 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _realsetup.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _realsetup \- internal routine to start FreeS/WAN.
+.SH DESCRIPTION
+.I _realsetup
+is called by the system init scripts to start the FreeS/WAN
+system. It starts
+.B KLIPS
+(the kernel component) and
+.B pluto
+(the userspace keying component).
+.SH "SEE ALSO"
+ipsec(8), ipsec__klipsstart(8), ipsec__plutorun(8).
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Original program by Henry Spencer.
+.\"
+.\" $Log: _realsetup.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 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.
+.\"
+.\"
+.\"
diff --git a/programs/_realsetup/_realsetup.in b/programs/_realsetup/_realsetup.in
new file mode 100755
index 000000000..91b6e98d3
--- /dev/null
+++ b/programs/_realsetup/_realsetup.in
@@ -0,0 +1,456 @@
+#!/bin/sh
+# IPsec startup and shutdown command
+# Copyright (C) 1998, 1999, 2001 Henry Spencer.
+#
+# 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: _realsetup.in,v 1.10 2005/09/25 21:30:52 as Exp $
+
+IPSEC_NAME=strongSwan
+
+me='ipsec setup' # for messages
+
+# Misc. paths (some of this should perhaps be overrideable from ipsec.conf).
+plutopid=/var/run/pluto.pid
+subsyslock=/var/lock/subsys/ipsec
+lock=/var/run/ipsec_setup.pid
+info=/var/run/ipsec.info
+sysflags=/proc/sys/net/ipsec
+modules=/proc/modules
+ipforward=/proc/sys/net/ipv4/ip_forward
+ipsecversion=/proc/net/ipsec_version
+kamepfkey=/proc/net/pfkey
+
+# make sure output of (e.g.) ifconfig is in English
+unset LANG LANGUAGE LC_ALL LC_MESSAGES
+
+# check we were called properly
+if test " $IPSEC_confreadsection" != " setup"
+then
+ echo "$me: $0 must be called by ipsec_setup" >&2
+ exit 1
+fi
+# defaults for "config setup" items
+
+IPSECinterfaces=${IPSECinterfaces:-%defaultroute}
+ if test " $IPSECinterfaces" = " %none" ; then IPSECinterfaces= ; fi
+# IPSECforwardcontrol "no"
+# IPSECsyslog "daemon.error"
+# IPSECklipsdebug "none"
+# IPSECplutodebug "none"
+# IPSECdumpdir "" (no dump)
+# IPSECmanualstart ""
+# IPSECpluto "yes"
+IPSECplutowait=${IPSECplutowait:-no}
+# IPSECprepluto ""
+# IPSECpostpluto ""
+# IPSECfragicmp "yes"
+# IPSEChidetos "yes"
+IPSECrp_filter=${IPSECrp_filter:-0}
+IPSECuniqueids=${IPSECuniqueids:-yes}
+IPSECcrlcheckinterval=${IPSECcrlcheckinterval:-0}
+# IPSECpkcs11module ""
+# IPSECoverridemtu ""
+
+# Shall we trace?
+execute="true"
+display="false"
+for i in $IPSEC_setupflags
+do
+ case "$i" in
+ "--showonly") execute="false" ; display=true ;;
+ "--show") display=true ;;
+ esac
+done
+
+if $display
+then
+ echo " " PATH="$PATH"
+fi
+
+perform() {
+ if $display
+ then
+ echo " " "$*"
+ fi
+
+ if $execute
+ then
+ eval "$*"
+ fi
+}
+
+# function to set up manually-keyed connections
+manualconns() {
+ if test " $IPSECmanualstart" != " "
+ then
+ for tu in $IPSECmanualstart
+ do
+ perform ipsec manual --up $tu
+ done
+ fi
+
+ # search for things to "ipsec manual --up": auto == "manual"
+ eval `ipsec _confread --varprefix MANUALSTART --search auto manual`
+ if test " $MANUALSTART_confreadstatus" != " "
+ then
+ echo "auto=manual search: $MANUALSTART_confreadstatus"
+ echo "unable to determine what conns to manual --up; none done"
+ elif test " $MANUALSTART_confreadnames" != " "
+ then
+ for tu in $MANUALSTART_confreadnames
+ do
+ perform ipsec manual --up $tu
+ done
+ fi
+}
+
+# for no-stdout logging:
+LOGONLY="logger -p $IPSECsyslog -t ipsec_setup"
+
+# What an ugly string.
+# Must be a string, not a function, because it is nested
+# within another sequence (for plutorun).
+# Luckily there are NO substitutions in it.
+KILLKLIPS='ifl=` ifconfig | sed -n -e "/^ipsec/s/ .*//p" ` ;
+ test "X$ifl" != "X" &&
+ for i in $ifl ;
+ do
+ ifconfig $i down ;
+ ipsec tncfg --detach --virtual $i ;
+ done ;
+ test -r /proc/net/ipsec_klipsdebug && ipsec klipsdebug --none ;
+ ipsec eroute --clear ;
+ ipsec spi --clear ;
+ for alg in aes serpent twofish blowfish sha2 ;
+ do
+ lsmod 2>&1 | grep "^ipsec_$alg" > /dev/null && rmmod ipsec_$alg ;
+ done ;
+ lsmod 2>&1 | grep "^ipsec" > /dev/null && rmmod ipsec'
+
+if test -f $kamepfkey
+then
+ KILLKLIPS='
+ if ip xfrm state > /dev/null 2>&1 ;
+ then
+ ip xfrm state flush ;
+ ip xfrm policy flush ;
+ elif type setkey > /dev/null 2>&1 ;
+ then
+ setkey -F ;
+ setkey -FP ;
+ fi'
+fi
+
+
+
+# do it
+case "$1" in
+ start|--start|_autostart)
+ # First, does it seem to be going already?
+ perform test ! -f $lock "||" "{" \
+ echo "\"$IPSEC_NAME IPsec apparently already running, start aborted\"" ";" \
+ exit 1 ";" \
+ "}"
+
+ # announcement
+ # (Warning, changes to this log message may affect barf.)
+ version="`ipsec --version | awk 'NR == 1 { print $(3) }' | sed -e 's/^U\(.*\)\/K(.*/\1/'`"
+ case "$1" in
+ start|--start) perform echo "\"Starting $IPSEC_NAME IPsec $version...\"" ;;
+ _autostart) perform echo "\"Restarting $IPSEC_NAME IPsec $version...\"" ;;
+ esac
+
+ # preliminaries
+ perform rm -f $lock
+
+ for f in /dev/random /dev/urandom
+ do
+ perform test -r $f "||" "{" \
+ echo "\"...unable to start $IPSEC_NAME IPsec, no $f!\"" ";" \
+ exit 1 ";" \
+ "}"
+ done
+
+ # the meaning of $$ at a different runtime is questionable!
+ perform echo '$$' ">" $lock
+ perform test -s $lock "||" "{" \
+ echo "\"...unable to create $lock, aborting start!\"" ";" \
+ rm -f $lock ";" \
+ exit 1 ";" \
+ "}"
+
+ perform ">" $info
+
+ # here we go
+ perform ipsec _startklips \
+ --info $info \
+ --debug "\"$IPSECklipsdebug\"" \
+ --omtu "\"$IPSECoverridemtu\"" \
+ --fragicmp "\"$IPSECfragicmp\"" \
+ --hidetos "\"$IPSEChidetos\"" \
+ --rpfilter "\"$IPSECrp_filter\"" \
+ --log "\"$IPSECsyslog\"" \
+ $IPSECinterfaces "||" \
+ "{" rm -f $lock ";" exit 1 ";" "}"
+
+ perform test -f $ipsecversion "||" \
+ test -f $kamepfkey "||" "{" \
+ echo "\"OOPS, should have aborted! Broken shell!\"" ";" \
+ exit 1 ";" \
+ "}"
+
+ # misc pre-Pluto setup
+
+ perform test -d `dirname $subsyslock` "&&" touch $subsyslock
+
+ if test " $IPSECforwardcontrol" = " yes"
+ then
+ perform grep '"^0"' $ipforward ">" /dev/null "&&" "{" \
+ echo "\"enabling IP forwarding:\"" "|" $LOGONLY ";" \
+ echo "\"ipforwardingwas=$fw\"" ">>" $info ";" \
+ echo 1 ">" $ipforward ";" \
+ "}"
+ fi
+ manualconns
+
+ plutorestartoncrash=""
+ case "$IPSECplutorestartoncrash" in
+ true|[yY]|yes|restart) plutorestartoncrash="--plutorestartoncrash true";;
+ false|[nN]|no|die) plutorestartoncrash="--plutorestartoncrash false" ;;
+ esac
+
+ # Pluto
+ case "$1" in
+ start|--start) re= ;;
+ _autostart) re=--re ;;
+ esac
+ if test " $IPSECpluto" != " no"
+ then
+ perform ipsec _plutorun $re \
+ --debug "\"$IPSECplutodebug\"" \
+ --uniqueids "\"$IPSECuniqueids\"" \
+ --nocrsend "\"$IPSECnocrsend\"" \
+ --strictcrlpolicy "\"$IPSECstrictcrlpolicy\"" \
+ --cachecrls "\"$IPSECcachecrls\"" \
+ --nat_traversal "\"$IPSECnat_traversal\"" \
+ --keep_alive "\"$IPSECkeep_alive\"" \
+ --force_keepalive "\"$IPSECforce_keepalive\"" \
+ --disable_port_floating "\"$IPSECdisable_port_floating\"" \
+ --virtual_private "\"$IPSECvirtual_private\"" \
+ --crlcheckinterval "\"$IPSECcrlcheckinterval\"" \
+ --pkcs11module "\"$IPSECpkcs11module\"" \
+ --pkcs11keepstate "\"$IPSECpkcs11keepstate\"" \
+ --pkcs11proxy "\"$IPSECpkcs11proxy\"" \
+ --dump "\"$IPSECdumpdir\"" \
+ --opts "\"$IPSECplutoopts\"" \
+ --stderrlog "\"$IPSECplutostderrlog\"" \
+ --wait "\"$IPSECplutowait\"" \
+ --pre "\"$IPSECprepluto\"" \
+ --post "\"$IPSECpostpluto\"" \
+ --log "\"$IPSECsyslog\"" $plutorestartoncrash \
+ --pid "\"$plutopid\"" "||" "{" \
+ $KILLKLIPS ";" \
+ rm -f $lock ";" \
+ exit 1 ";" \
+ "}"
+ fi
+
+ # done!
+ perform echo "\"...$IPSEC_NAME IPsec started\"" "|" $LOGONLY
+ ;;
+
+ stop|--stop|_autostop) # _autostop is same as stop
+ # Shut things down.
+ perform echo "\"Stopping $IPSEC_NAME IPsec...\""
+ perform \
+ if test -r $lock ";" \
+ then \
+ status=0 ";" \
+ . $info ";" \
+ else \
+ echo "\"stop ordered, but IPsec does not appear to be running!\"" ";" \
+ echo "\"doing cleanup anyway...\"" ";" \
+ status=1 ";" \
+ fi
+ if test " $IPSECforwardcontrol" = " yes"
+ then
+ perform test "\"X\$ipforwardingwas\"" = "\"X0\"" "&&" "{" \
+ echo "\"disabling IP forwarding:\"" "|" $LOGONLY ";" \
+ echo 0 ">" $ipforward ";" \
+ "}"
+ fi
+
+ perform test -f $plutopid "&&" "{" \
+ if ps -p '`' cat $plutopid '`' ">" /dev/null ";" \
+ then \
+ ipsec whack --shutdown "|" grep -v "^002" ";" \
+ sleep 1 ";" \
+ if test -s $plutopid ";" \
+ then \
+ echo "\"Attempt to shut Pluto down failed! Trying kill:\"" ";" \
+ kill '`' cat $plutopid '`' ";" \
+ sleep 5 ";" \
+ fi ";" \
+ else \
+ echo "\"Removing orphaned $plutopid:\"" ";" \
+ fi ";" \
+ rm -f $plutopid ";" \
+ "}"
+
+ perform $KILLKLIPS
+
+ perform test -d `dirname $subsyslock` "&&" rm -f $subsyslock
+
+ perform rm -f $info $lock
+ perform echo "...$IPSEC_NAME IPsec stopped" "|" $LOGONLY
+ perform exit \$status
+ ;;
+
+ status|--status)
+ if test " $IPSEC_setupflags" != " "
+ then
+ echo "$me $1 does not support $IPSEC_setupflags"
+ exit 1
+ fi
+
+ if test -f $info
+ then
+ hasinfo=yes
+ fi
+
+ if test -f $lock
+ then
+ haslock=yes
+ fi
+
+ if test -f $subsyslock
+ then
+ hassublock=yes
+ fi
+
+ if test -s $plutopid
+ then
+ if ps -p `cat $plutopid` >/dev/null
+ then
+ plutokind=normal
+ elif ps -C pluto >/dev/null
+ then
+ plutokind=illicit
+ fi
+ elif ps -C pluto >/dev/null
+ then
+ plutokind=orphaned
+ else
+ plutokind=no
+ fi
+
+ if test -r /proc/net/ipsec_eroute
+ then
+ if test " `wc -l </proc/net/ipsec_eroute`" -gt 0
+ then
+ eroutes=yes
+ fi
+ fi
+
+ if test -r $ipsecversion
+ then
+ klips=yes
+ elif test -r $modules
+ then
+ klips=maybe
+ else
+ klips=none
+ fi
+
+ if test "$haslock"
+ then
+ echo "IPsec running"
+ # might not be a subsystem lock dir, ignore that issue
+ if test "$plutokind" = "normal" -a "$klips" = "yes" -a "$hasinfo"
+ then
+ echo "pluto pid `cat $plutopid`"
+ exit 0
+ fi
+ echo "but..."
+ if test "$plutokind" != "normal"
+ then
+ echo "$plutokind Pluto running!"
+ fi
+ if test ! "$hasinfo"
+ then
+ echo "$info file missing!"
+ fi
+ case $klips in
+ maybe) echo "KLIPS module is not loaded!" ;;
+ none) echo "no KLIPS in kernel!" ;;
+ esac
+ if test "$eroutes"
+ then
+ echo "some eroutes exist"
+ fi
+ exit 1
+ else
+ echo "IPsec stopped"
+ if test ! "$hassublock" -a ! "$hasinfo" -a "$plutokind" = "no" \
+ -a ! "$eroutes"
+ then
+ exit 0
+ fi
+ echo "but..."
+ if test "$hassublock"
+ then
+ echo "has subsystem lock ($subsyslock)!"
+ fi
+ if test "$hasinfo"
+ then
+ echo "has $info file!"
+ fi
+ if test "$plutokind" != "normal"
+ then
+ echo "$plutokind Pluto is running!"
+ fi
+ if test "$eroutes"
+ then
+ echo "some eroutes exist!"
+ fi
+ exit 1
+ fi
+ ;;
+
+ --version)
+ if test " $IPSEC_setupflags" != " "
+ then
+ echo "$me $1 does not support $IPSEC_setupflags"
+ exit 1
+ fi
+
+ echo "$me $IPSEC_VERSION"
+ exit 0
+ ;;
+
+ --help)
+ if test " $IPSEC_setupflags" != " "
+ then
+ echo "$me $1 does not support $IPSEC_setupflags"
+ exit 1
+ fi
+
+ echo "Usage: $me {--start|--stop|--restart|--status}"
+ exit 0
+ ;;
+
+ *)
+ echo "Usage: $me {--start|--stop|--restart|--status}" >&2
+ exit 2
+esac
+
+exit 0
diff --git a/programs/_secretcensor/.cvsignore b/programs/_secretcensor/.cvsignore
new file mode 100644
index 000000000..202d856fe
--- /dev/null
+++ b/programs/_secretcensor/.cvsignore
@@ -0,0 +1 @@
+_secretcensor
diff --git a/programs/_secretcensor/Makefile b/programs/_secretcensor/Makefile
new file mode 100644
index 000000000..3df15286e
--- /dev/null
+++ b/programs/_secretcensor/Makefile
@@ -0,0 +1,43 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_secretcensor
+PROGRAMDIR=${LIBDIR}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.3 2002/08/02 16:01:38 mcr
+# moved user visible programs to $PREFIX/libexec, while moving
+# private files to $PREFIX/lib.
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/_secretcensor/_secretcensor.8 b/programs/_secretcensor/_secretcensor.8
new file mode 100644
index 000000000..d502bbd37
--- /dev/null
+++ b/programs/_secretcensor/_secretcensor.8
@@ -0,0 +1,34 @@
+.TH _SECRETCENSOR 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _secretcensor.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _secretcensor \- internal routing to sanitize files
+.SH DESCRIPTION
+.I _secretcensor
+is called by
+.B ipsec barf
+to process the /etc/ipsec.secrets file to remove the private key components
+from the file prior to revealing the contents.
+.SH "SEE ALSO"
+ipsec(8), ipsec_barf(8).
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Original program by Henry Spencer.
+.\"
+.\" $Log: _secretcensor.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 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.
+.\"
+.\"
+.\"
diff --git a/programs/_secretcensor/_secretcensor.in b/programs/_secretcensor/_secretcensor.in
new file mode 100755
index 000000000..150c13cbc
--- /dev/null
+++ b/programs/_secretcensor/_secretcensor.in
@@ -0,0 +1,75 @@
+#! /bin/sh
+# implements secret censoring for barf
+# Copyright (C) 1999 Henry Spencer.
+#
+# 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: _secretcensor.in,v 1.1 2004/03/15 20:35:27 as Exp $
+
+usage="Usage: $0 [file ...]"
+me="ipsec _secretcensor"
+
+for dummy
+do
+ case "$1" in
+ --help) echo "$usage" ; exit 0 ;;
+ --version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+ --) shift ; break ;;
+ -*) echo "$0: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+awk ' function cool(hot, q, cooled, run) {
+ # warning: may destroy input line!
+ q = "'"'"'" # single quote
+ if (hot ~ q)
+ return "[cannot be summed]"
+ if (hot ~ /^0s/)
+ return "[keyid " substr(hot, 3, 9) "]"
+ run = "echo " q hot q " | md5sum"
+ run | getline
+ close(run)
+ return "[sums to " substr($1, 1, 4) "...]"
+ }
+ /"/ {
+ i = match($0, /"[^"]+"/)
+ cold1 = substr($0, 1, i)
+ cold2 = substr($0, i+RLENGTH-1)
+ hot = substr($0, i+1, RLENGTH-2)
+ print cold1 cool(hot) cold2
+ next
+ }
+ /#pubkey=/ {
+ i = match($0, /^.*#pubkey=/)
+ i += RLENGTH-1
+ cold = substr($0, 1, i)
+ hot = substr($0, i+1)
+ print cold cool(hot)
+ next
+ }
+ /#IN KEY / {
+ i = match($0, /^.*[ \t][^ \t]/)
+ i += RLENGTH-2
+ cold = substr($0, 1, i)
+ hot = substr($0, i+1)
+ print cold cool("0s" hot)
+ next
+ }
+ /^[ \t]+(Modulus|P[a-z]+Exponent|Prime[12]|Exponent[12]|Coefficient):/ {
+ i = match($0, /^[^:]*:[ \t]*/)
+ i += RLENGTH-1
+ cold = substr($0, 1, i)
+ print cold "[...]"
+ next
+ }
+ { print }' $*
diff --git a/programs/_startklips/.cvsignore b/programs/_startklips/.cvsignore
new file mode 100644
index 000000000..a206fe65f
--- /dev/null
+++ b/programs/_startklips/.cvsignore
@@ -0,0 +1 @@
+_startklips
diff --git a/programs/_startklips/Makefile b/programs/_startklips/Makefile
new file mode 100644
index 000000000..9df701b0e
--- /dev/null
+++ b/programs/_startklips/Makefile
@@ -0,0 +1,43 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_startklips
+PROGRAMDIR=${LIBDIR}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.3 2002/08/02 16:01:42 mcr
+# moved user visible programs to $PREFIX/libexec, while moving
+# private files to $PREFIX/lib.
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/_startklips/_startklips.8 b/programs/_startklips/_startklips.8
new file mode 100644
index 000000000..066699085
--- /dev/null
+++ b/programs/_startklips/_startklips.8
@@ -0,0 +1,33 @@
+.TH _STARTKLIPS 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: _startklips.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec _startklips \- internal script to bring up kernel components
+.SH DESCRIPTION
+.I _startklips
+brings up the FreeS/WAN kernel component. This involves loading any
+required modules, attaching and configuring the ipsecX pseudo-devices and
+attaching the pseudo-devices to the physical devices.
+.SH "SEE ALSO"
+ipsec(8), ipsec_tncfg(8).
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Original program by Henry Spencer.
+.\"
+.\" $Log: _startklips.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 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.
+.\"
+.\"
+.\"
diff --git a/programs/_startklips/_startklips.in b/programs/_startklips/_startklips.in
new file mode 100755
index 000000000..7f85a94de
--- /dev/null
+++ b/programs/_startklips/_startklips.in
@@ -0,0 +1,367 @@
+#!/bin/sh
+# KLIPS startup script
+# Copyright (C) 1998, 1999, 2001, 2002 Henry Spencer.
+#
+# 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: _startklips.in,v 1.6 2005/05/06 22:11:33 as Exp $
+
+me='ipsec _startklips' # for messages
+
+# KLIPS-related paths
+sysflags=/proc/sys/net/ipsec
+modules=/proc/modules
+# full rp_filter path is $rpfilter1/interface/$rpfilter2
+rpfilter1=/proc/sys/net/ipv4/conf
+rpfilter2=rp_filter
+# %unchanged or setting (0, 1, or 2)
+rpfiltercontrol=0
+ipsecversion=/proc/net/ipsec_version
+moduleplace=/lib/modules/`uname -r`/kernel/net/ipsec
+bareversion=`uname -r | sed -e 's/^\(2\.[0-9]\.[1-9][0-9]*-[1-9][0-9]*\(\.[0-9][0-9]*\)*\(\.x\)*\).*$/\1/'`
+moduleinstplace=/lib/modules/$bareversion/kernel/net/ipsec
+modulename=ipsec.o
+klips=true
+netkey=/proc/net/pfkey
+
+info=/dev/null
+log=daemon.error
+for dummy
+do
+ case "$1" in
+ --log) log="$2" ; shift ;;
+ --info) info="$2" ; shift ;;
+ --debug) debug="$2" ; shift ;;
+ --omtu) omtu="$2" ; shift ;;
+ --fragicmp) fragicmp="$2" ; shift ;;
+ --hidetos) hidetos="$2" ; shift ;;
+ --rpfilter) rpfiltercontrol="$2" ; shift ;;
+ --) shift ; break ;;
+ -*) echo "$me: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+
+
+# some shell functions, to clarify the actual code
+
+# set up a system flag based on a variable
+# sysflag value shortname default flagname
+sysflag() {
+ case "$1" in
+ '') v="$3" ;;
+ *) v="$1" ;;
+ esac
+ if test ! -f $sysflags/$4
+ then
+ if test " $v" != " $3"
+ then
+ echo "cannot do $2=$v, $sysflags/$4 does not exist"
+ exit 1
+ else
+ return # can't set, but it's the default anyway
+ fi
+ fi
+ case "$v" in
+ yes|no) ;;
+ *) echo "unknown (not yes/no) $2 value \`$1'"
+ exit 1
+ ;;
+ esac
+ case "$v" in
+ yes) echo 1 >$sysflags/$4 ;;
+ no) echo 0 >$sysflags/$4 ;;
+ esac
+}
+
+# set up a Klips interface
+klipsinterface() {
+ # pull apart the interface spec
+ virt=`expr $1 : '\([^=]*\)=.*'`
+ phys=`expr $1 : '[^=]*=\(.*\)'`
+ case "$virt" in
+ ipsec[0-9]) ;;
+ *) echo "invalid interface \`$virt' in \`$1'" ; exit 1 ;;
+ esac
+
+ # figure out ifconfig for interface
+ addr=
+ eval `ifconfig $phys |
+ awk '$1 == "inet" && $2 ~ /^addr:/ && $NF ~ /^Mask:/ {
+ gsub(/:/, " ", $0)
+ print "addr=" $3
+ other = $5
+ if ($4 == "Bcast")
+ print "type=broadcast"
+ else if ($4 == "P-t-P")
+ print "type=pointopoint"
+ else if (NF == 5) {
+ print "type="
+ other = ""
+ } else
+ print "type=unknown"
+ print "otheraddr=" other
+ print "mask=" $NF
+ }'`
+ if test " $addr" = " "
+ then
+ echo "unable to determine address of \`$phys'"
+ exit 1
+ fi
+ if test " $type" = " unknown"
+ then
+ echo "\`$phys' is of an unknown type"
+ exit 1
+ fi
+ if test " $omtu" != " "
+ then
+ mtu="mtu $omtu"
+ else
+ mtu=
+ fi
+ echo "KLIPS $virt on $phys $addr/$mask $type $otheraddr $mtu" | logonly
+
+ if $klips
+ then
+ # attach the interface and bring it up
+ ipsec tncfg --attach --virtual $virt --physical $phys
+ ifconfig $virt inet $addr $type $otheraddr netmask $mask $mtu
+ fi
+
+ # if %defaultroute, note the facts
+ if test " $2" != " "
+ then
+ (
+ echo "defaultroutephys=$phys"
+ echo "defaultroutevirt=$virt"
+ echo "defaultrouteaddr=$addr"
+ if test " $2" != " 0.0.0.0"
+ then
+ echo "defaultroutenexthop=$2"
+ fi
+ ) >>$info
+ else
+ echo '#dr: no default route' >>$info
+ fi
+
+ # check for rp_filter trouble
+ checkif $phys # thought to be a problem only on phys
+}
+
+# check an interface for problems
+checkif() {
+ $klips || return 0
+ rpf=$rpfilter1/$1/$rpfilter2
+ if test -f $rpf
+ then
+ r="`cat $rpf`"
+ if test " $r" != " 0"
+ then
+ case "$r-$rpfiltercontrol" in
+ 0-%unchanged|0-0|1-1|2-2)
+ # happy state
+ ;;
+ *-%unchanged)
+ echo "WARNING: $1 has route filtering turned on; KLIPS may not work ($rpf is $r)"
+ ;;
+ [012]-[012])
+ echo "WARNING: changing route filtering on $1 (changing $rpf from $r to $rpfiltercontrol)"
+ echo "$rpfiltercontrol" >$rpf
+ ;;
+ [012]-*)
+ echo "ERROR: unknown rpfilter setting: $rpfiltercontrol"
+ ;;
+ *)
+ echo "ERROR: unknown $rpf value $r"
+ ;;
+ esac
+ fi
+ fi
+}
+
+# interfaces=%defaultroute: put ipsec0 on top of default route's interface
+defaultinterface() {
+ phys=`netstat -nr |
+ awk '$1 == "0.0.0.0" && $3 == "0.0.0.0" { print $NF }'`
+ if test " $phys" = " "
+ then
+ echo "no default route, %defaultroute cannot cope!!!"
+ exit 1
+ fi
+ if test `echo " $phys" | wc -l` -gt 1
+ then
+ echo "multiple default routes, %defaultroute cannot cope!!!"
+ exit 1
+ fi
+ next=`netstat -nr |
+ awk '$1 == "0.0.0.0" && $3 == "0.0.0.0" { print $2 }'`
+ klipsinterface "ipsec0=$phys" $next
+}
+
+# log only to syslog, not to stdout/stderr
+logonly() {
+ logger -p $log -t ipsec_setup
+}
+
+# sort out which module is appropriate, changing it if necessary
+setmodule() {
+ wantgoo="`ipsec calcgoo /proc/ksyms`"
+ module=$moduleplace/$modulename
+ if test -f $module
+ then
+ goo="`nm -ao $module | ipsec calcgoo`"
+ if test " $wantgoo" = " $goo"
+ then
+ return # looks right
+ fi
+ fi
+ if test -f $moduleinstplace/$wantgoo
+ then
+ echo "insmod failed, but found matching template module $wantgoo."
+ echo "Copying $moduleinstplace/$wantgoo to $module."
+ rm -f $module
+ mkdir -p $moduleplace
+ cp -p $moduleinstplace/$wantgoo $module
+ # "depmod -a" gets done by caller
+ fi
+}
+
+
+
+# main line
+
+# load module if possible
+if test ! -f $ipsecversion && test ! -f $netkey
+then
+ # statically compiled KLIPS not found; try to load the module
+ insmod ipsec
+fi
+
+if test ! -f $ipsecversion && test ! -f $netkey
+then
+ modprobe -v af_key
+fi
+
+if test -f $netkey
+then
+ klips=false
+ if test -f $modules
+ then
+ modprobe -qv ah4
+ modprobe -qv esp4
+ modprobe -qv ipcomp
+ modprobe -qv xfrm4_tunnel
+ modprobe -qv xfrm_user
+ fi
+fi
+
+if test ! -f $ipsecversion && $klips
+then
+ if test -r $modules # kernel does have modules
+ then
+ setmodule
+ unset MODPATH MODULECONF # no user overrides!
+ depmod -a >/dev/null 2>&1
+ modprobe -v ipsec
+ fi
+ if test ! -f $ipsecversion
+ then
+ echo "kernel appears to lack KLIPS"
+ exit 1
+ fi
+fi
+
+# load all compiled algo modules
+if $klips
+then
+ for alg in aes serpent twofish blowfish sha2
+ do
+ if test -f $moduleinstplace/alg/ipsec_$alg.o
+ then
+ modprobe ipsec_$alg
+ fi
+ done
+fi
+
+# figure out debugging flags
+case "$debug" in
+'') debug=none ;;
+esac
+if test -r /proc/net/ipsec_klipsdebug
+then
+ echo "KLIPS debug \`$debug'" | logonly
+ case "$debug" in
+ none) ipsec klipsdebug --none ;;
+ all) ipsec klipsdebug --all ;;
+ *) ipsec klipsdebug --none
+ for d in $debug
+ do
+ ipsec klipsdebug --set $d
+ done
+ ;;
+ esac
+elif $klips
+then
+ if test " $debug" != " none"
+ then
+ echo "klipsdebug=\`$debug' ignored, KLIPS lacks debug facilities"
+ fi
+fi
+
+# figure out misc. kernel config
+if test -d $sysflags
+then
+ sysflag "$fragicmp" "fragicmp" yes icmp
+ echo 1 >$sysflags/inbound_policy_check # no debate
+ sysflag no "no_eroute_pass" no no_eroute_pass # obsolete parm
+ sysflag no "opportunistic" no opportunistic # obsolete parm
+ sysflag "$hidetos" "hidetos" yes tos
+elif $klips
+then
+ echo "WARNING: cannot adjust KLIPS flags, no $sysflags directory!"
+ # carry on
+fi
+
+if $klips; then
+ # clear tables out in case dregs have been left over
+ ipsec eroute --clear
+ ipsec spi --clear
+elif test $netkey
+then
+ if ip xfrm state > /dev/null 2>&1
+ then
+ ip xfrm state flush
+ ip xfrm policy flush
+ elif type setkey > /dev/null 2>&1
+ then
+ setkey -F
+ setkey -FP
+ else
+ echo "WARNING: cannot flush state/policy database -- \`$1'" |
+ logger -s -p $log -t ipsec_setup
+ fi
+fi
+
+# figure out interfaces
+for i
+do
+ case "$i" in
+ ipsec*=?*) klipsinterface "$i" ;;
+ %defaultroute) defaultinterface ;;
+ *) echo "interface \`$i' not understood"
+ exit 1
+ ;;
+ esac
+done
+
+exit 0
diff --git a/programs/_updown/.cvsignore b/programs/_updown/.cvsignore
new file mode 100644
index 000000000..81e2e4f86
--- /dev/null
+++ b/programs/_updown/.cvsignore
@@ -0,0 +1,2 @@
+_updown
+_updown.in
diff --git a/programs/_updown/Makefile b/programs/_updown/Makefile
new file mode 100644
index 000000000..e0aaab488
--- /dev/null
+++ b/programs/_updown/Makefile
@@ -0,0 +1,22 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.3 2006/04/17 06:48:49 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_updown
+PROGRAMDIR=${LIBDIR}
+
+include ../Makefile.program
diff --git a/programs/_updown/_updown.8 b/programs/_updown/_updown.8
new file mode 100644
index 000000000..5107d3694
--- /dev/null
+++ b/programs/_updown/_updown.8
@@ -0,0 +1,19 @@
+.TH _UPDOWN 8 "27 Apr 2006"
+.\"
+.\" RCSID $Id: _updown.8,v 1.2 2006/04/17 06:48:49 as Exp $
+.\"
+.SH NAME
+ipsec _updown \- route and firewall manipulation script
+.SH SYNOPSIS
+.I _updown
+is invoked by pluto when it has brought up a new connection. This script
+is used to insert the appropriate routing entries for IPsec operation.
+It can also be used to insert and delete dynamic iptables firewall rules.
+The interface to the script is documented in the pluto man page.
+.SH "SEE ALSO"
+ipsec(8), ipsec_pluto(8).
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Original program written by Henry Spencer. Extended
+for the Linux strongSwan project <http://www.strongswan.org/> by Andreas
+Steffen.
diff --git a/programs/_updown/_updown.in b/programs/_updown/_updown.in
new file mode 100755
index 000000000..8db74f737
--- /dev/null
+++ b/programs/_updown/_updown.in
@@ -0,0 +1,503 @@
+#! /bin/sh
+# iproute2 version, default updown script
+#
+# Copyright (C) 2003-2004 Nigel Meteringham
+# Copyright (C) 2003-2004 Tuomo Soini
+# Copyright (C) 2002-2004 Michael Richardson
+# Copyright (C) 2005-2006 Andreas Steffen <andreas.steffen@strongswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: _updown.in,v 1.2 2006/04/17 15:06:29 as Exp $
+
+# CAUTION: Installing a new version of strongSwan will install a new
+# copy of this script, wiping out any custom changes you make. If
+# you need changes, make a copy of this under another name, and customize
+# that, and use the (left/right)updown parameters in ipsec.conf to make
+# strongSwan use yours instead of this default one.
+
+# things that this script gets (from ipsec_pluto(8) man page)
+#
+# PLUTO_VERSION
+# indicates what version of this interface is being
+# used. This document describes version 1.1. This
+# is upwardly compatible with version 1.0.
+#
+# PLUTO_VERB
+# specifies the name of the operation to be performed
+# (prepare-host, prepare-client, up-host, up-client,
+# down-host, or down-client). If the address family
+# for security gateway to security gateway communica­
+# tions is IPv6, then a suffix of -v6 is added to the
+# verb.
+#
+# PLUTO_CONNECTION
+# is the name of the connection for which we are
+# routing.
+#
+# PLUTO_NEXT_HOP
+# is the next hop to which packets bound for the peer
+# must be sent.
+#
+# PLUTO_INTERFACE
+# is the name of the ipsec interface to be used.
+#
+# PLUTO_REQID
+# is the requid of the ESP policy
+#
+# PLUTO_ME
+# is the IP address of our host.
+#
+# PLUTO_MY_ID
+# is the ID of our host.
+#
+# PLUTO_MY_CLIENT
+# is the IP address / count of our client subnet. If
+# the client is just the host, this will be the
+# host's own IP address / max (where max is 32 for
+# IPv4 and 128 for IPv6).
+#
+# PLUTO_MY_CLIENT_NET
+# is the IP address of our client net. If the client
+# is just the host, this will be the host's own IP
+# address.
+#
+# PLUTO_MY_CLIENT_MASK
+# is the mask for our client net. If the client is
+# just the host, this will be 255.255.255.255.
+#
+# PLUTO_MY_SOURCEIP
+# if non-empty, then the source address for the route will be
+# set to this IP address.
+#
+# PLUTO_MY_PROTOCOL
+# is the IP protocol that will be transported.
+#
+# PLUTO_MY_PORT
+# is the UDP/TCP port to which the IPsec SA is
+# restricted on our side.
+#
+# PLUTO_PEER
+# is the IP address of our peer.
+#
+# PLUTO_PEER_ID
+# is the ID of our peer.
+#
+# PLUTO_PEER_CA
+# is the CA which issued the cert of our peer.
+#
+# PLUTO_PEER_CLIENT
+# is the IP address / count of the peer's client sub­
+# net. If the client is just the peer, this will be
+# the peer's own IP address / max (where max is 32
+# for IPv4 and 128 for IPv6).
+#
+# PLUTO_PEER_CLIENT_NET
+# is the IP address of the peer's client net. If the
+# client is just the peer, this will be the peer's
+# own IP address.
+#
+# PLUTO_PEER_CLIENT_MASK
+# is the mask for the peer's client net. If the
+# client is just the peer, this will be
+# 255.255.255.255.
+#
+# PLUTO_PEER_PROTOCOL
+# is the IP protocol that will be transported.
+#
+# PLUTO_PEER_PORT
+# is the UDP/TCP port to which the IPsec SA is
+# restricted on the peer side.
+#
+
+# uncomment to log VPN connections
+VPN_LOGGING=1
+#
+# tag put in front of each log entry:
+TAG=vpn
+#
+# syslog facility and priority used:
+FAC_PRIO=local0.notice
+#
+# to create a special vpn logging file, put the following line into
+# the syslog configuration file /etc/syslog.conf:
+#
+# local0.notice -/var/log/vpn
+#
+
+# check interface version
+case "$PLUTO_VERSION" in
+1.[0|1]) # Older Pluto?!? Play it safe, script may be using new features.
+ echo "$0: obsolete interface version \`$PLUTO_VERSION'," >&2
+ echo "$0: called by obsolete Pluto?" >&2
+ exit 2
+ ;;
+1.*) ;;
+*) echo "$0: unknown interface version \`$PLUTO_VERSION'" >&2
+ exit 2
+ ;;
+esac
+
+# check parameter(s)
+case "$1:$*" in
+':') # no parameters
+ ;;
+iptables:iptables) # due to (left/right)firewall; for default script only
+ ;;
+custom:*) # custom parameters (see above CAUTION comment)
+ ;;
+*) echo "$0: unknown parameters \`$*'" >&2
+ exit 2
+ ;;
+esac
+
+# utility functions for route manipulation
+# Meddling with this stuff should not be necessary and requires great care.
+uproute() {
+ doroute add
+ ip route flush cache
+}
+downroute() {
+ doroute delete
+ ip route flush cache
+}
+
+addsource() {
+ st=0
+ if ! ip -o route get ${PLUTO_MY_SOURCEIP%/*} | grep -q ^local
+ then
+ it="ip addr add ${PLUTO_MY_SOURCEIP%/*}/32 dev $PLUTO_INTERFACE"
+ oops="`eval $it 2>&1`"
+ st=$?
+ if test " $oops" = " " -a " $st" != " 0"
+ then
+ oops="silent error, exit status $st"
+ fi
+ if test " $oops" != " " -o " $st" != " 0"
+ then
+ echo "$0: addsource \`$it' failed ($oops)" >&2
+ fi
+ fi
+ return $st
+}
+
+doroute() {
+ st=0
+ parms="$PLUTO_PEER_CLIENT"
+
+ parms2=
+ if [ -n "$PLUTO_NEXT_HOP" ]
+ then
+ parms2="via $PLUTO_NEXT_HOP"
+ fi
+ parms2="$parms2 dev $PLUTO_INTERFACE"
+
+ if [ -z "$PLUTO_MY_SOURCEIP" ]
+ then
+ if [ -f /etc/sysconfig/defaultsource ]
+ then
+ . /etc/sysconfig/defaultsource
+ fi
+
+ if [ -f /etc/conf.d/defaultsource ]
+ then
+ . /etc/conf.d/defaultsource
+ fi
+
+ if [ -n "$DEFAULTSOURCE" ]
+ then
+ PLUTO_MY_SOURCEIP=$DEFAULTSOURCE
+ fi
+ fi
+
+ parms3=
+ if test "$1" = "add" -a -n "$PLUTO_MY_SOURCEIP"
+ then
+ addsource
+ parms3="$parms3 src ${PLUTO_MY_SOURCEIP%/*}"
+ fi
+
+ case "$PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK" in
+ "0.0.0.0/0.0.0.0")
+ # opportunistic encryption work around
+ # need to provide route that eclipses default, without
+ # replacing it.
+ it="ip route $1 0.0.0.0/1 $parms2 $parms3 &&
+ ip route $1 128.0.0.0/1 $parms2 $parms3"
+ ;;
+ *) it="ip route $1 $parms $parms2 $parms3"
+ ;;
+ esac
+ oops="`eval $it 2>&1`"
+ st=$?
+ if test " $oops" = " " -a " $st" != " 0"
+ then
+ oops="silent error, exit status $st"
+ fi
+ if test " $oops" != " " -o " $st" != " 0"
+ then
+ echo "$0: doroute \`$it' failed ($oops)" >&2
+ fi
+ return $st
+}
+
+# in the presence of KLIPS and ipsecN interfaces do not use IPSEC_POLICY
+if [ `echo "$PLUTO_INTERFACE" | grep "ipsec"` ]
+then
+ IPSEC_POLICY_IN=""
+ IPSEC_POLICY_OUT=""
+else
+ IPSEC_POLICY="-m policy --pol ipsec --proto esp --reqid $PLUTO_REQID"
+ IPSEC_POLICY_IN="$IPSEC_POLICY --dir in"
+ IPSEC_POLICY_OUT="$IPSEC_POLICY --dir out"
+fi
+
+# are there port numbers?
+if [ "$PLUTO_MY_PORT" != 0 ]
+then
+ S_MY_PORT="--sport $PLUTO_MY_PORT"
+ D_MY_PORT="--dport $PLUTO_MY_PORT"
+fi
+if [ "$PLUTO_PEER_PORT" != 0 ]
+then
+ S_PEER_PORT="--sport $PLUTO_PEER_PORT"
+ D_PEER_PORT="--dport $PLUTO_PEER_PORT"
+fi
+
+# the big choice
+case "$PLUTO_VERB:$1" in
+prepare-host:*|prepare-client:*)
+ # delete possibly-existing route (preliminary to adding a route)
+ case "$PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK" in
+ "0.0.0.0/0.0.0.0")
+ # need to provide route that eclipses default, without
+ # replacing it.
+ parms1="0.0.0.0/1"
+ parms2="128.0.0.0/1"
+ it="ip route delete $parms1 2>&1 ; ip route delete $parms2 2>&1"
+ oops="`ip route delete $parms1 2>&1 ; ip route delete $parms2 2>&1`"
+ ;;
+ *)
+ parms="$PLUTO_PEER_CLIENT"
+ it="ip route delete $parms 2>&1"
+ oops="`ip route delete $parms 2>&1`"
+ ;;
+ esac
+ status="$?"
+ if test " $oops" = " " -a " $status" != " 0"
+ then
+ oops="silent error, exit status $status"
+ fi
+ case "$oops" in
+ *'RTNETLINK answers: No such process'*)
+ # This is what route (currently -- not documented!) gives
+ # for "could not find such a route".
+ oops=
+ status=0
+ ;;
+ esac
+ if test " $oops" != " " -o " $status" != " 0"
+ then
+ echo "$0: \`$it' failed ($oops)" >&2
+ fi
+ exit $status
+ ;;
+route-host:*|route-client:*)
+ # connection to me or my client subnet being routed
+ uproute
+ ;;
+unroute-host:*|unroute-client:*)
+ # connection to me or my client subnet being unrouted
+ downroute
+ ;;
+up-host:)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-host:)
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+up-client:)
+ # connection to my client subnet coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-client:)
+ # connection to my client subnet going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+up-host:iptables)
+ # connection to me, with (left/right)firewall=yes, coming up
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ iptables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_ME $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT
+ iptables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_ME $S_MY_PORT $IPSEC_POLICY_OUT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ #
+ # log IPsec host connection setup
+ if [ $VPN_LOGGING ]
+ then
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME"
+ else
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME"
+ fi
+ fi
+ ;;
+down-host:iptables)
+ # connection to me, with (left/right)firewall=yes, going down
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ iptables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_ME $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT
+ iptables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_ME $S_MY_PORT $IPSEC_POLICY_OUT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ #
+ # log IPsec host connection teardown
+ if [ $VPN_LOGGING ]
+ then
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME"
+ else
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME"
+ fi
+ fi
+ ;;
+up-client:iptables)
+ # connection to client subnet, with (left/right)firewall=yes, coming up
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ if [ "$PLUTO_PEER_CLIENT" != "$PLUTO_MY_SOURCEIP/32" ]
+ then
+ iptables -I FORWARD 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \
+ $IPSEC_POLICY_OUT -j ACCEPT
+ iptables -I FORWARD 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $IPSEC_POLICY_IN -j ACCEPT
+ fi
+ #
+ # a virtual IP requires an INPUT and OUTPUT rule on the host
+ # or sometimes host access via the internal IP is needed
+ if [ -n "$PLUTO_MY_SOURCEIP" -o -n "$PLUTO_HOST_ACCESS" ]
+ then
+ iptables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $IPSEC_POLICY_IN -j ACCEPT
+ iptables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \
+ $IPSEC_POLICY_OUT -j ACCEPT
+ fi
+ #
+ # log IPsec client connection setup
+ if [ $VPN_LOGGING ]
+ then
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ else
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ fi
+ fi
+ ;;
+down-client:iptables)
+ # connection to client subnet, with (left/right)firewall=yes, going down
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ if [ "$PLUTO_PEER_CLIENT" != "$PLUTO_MY_SOURCEIP/32" ]
+ then
+ iptables -D FORWARD -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \
+ $IPSEC_POLICY_OUT -j ACCEPT
+ iptables -D FORWARD -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $IPSEC_POLICY_IN -j ACCEPT
+ fi
+ #
+ # a virtual IP requires an INPUT and OUTPUT rule on the host
+ # or sometimes host access via the internal IP is needed
+ if [ -n "$PLUTO_MY_SOURCEIP" -o -n "$PLUTO_HOST_ACCESS" ]
+ then
+ iptables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $IPSEC_POLICY_IN -j ACCEPT
+ iptables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT \
+ $IPSEC_POLICY_OUT -j ACCEPT
+ fi
+ #
+ # log IPsec client connection teardown
+ if [ $VPN_LOGGING ]
+ then
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ else
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ fi
+ fi
+ ;;
+#
+# IPv6
+#
+prepare-host-v6:*|prepare-client-v6:*)
+ ;;
+route-host-v6:*|route-client-v6:*)
+ # connection to me or my client subnet being routed
+ #uproute_v6
+ ;;
+unroute-host-v6:*|unroute-client-v6:*)
+ # connection to me or my client subnet being unrouted
+ #downroute_v6
+ ;;
+up-host-v6:*)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-host-v6:*)
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+up-client-v6:)
+ # connection to my client subnet coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-client-v6:)
+ # connection to my client subnet going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+*) echo "$0: unknown verb \`$PLUTO_VERB' or parameter \`$1'" >&2
+ exit 1
+ ;;
+esac
diff --git a/programs/_updown_espmark/Makefile b/programs/_updown_espmark/Makefile
new file mode 100644
index 000000000..bd9cd38cb
--- /dev/null
+++ b/programs/_updown_espmark/Makefile
@@ -0,0 +1,22 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2005/04/07 21:34:19 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=_updown_espmark
+PROGRAMDIR=${LIBDIR}
+
+include ../Makefile.program
diff --git a/programs/_updown_espmark/_updown_espmark.8 b/programs/_updown_espmark/_updown_espmark.8
new file mode 100644
index 000000000..91eaa5cb7
--- /dev/null
+++ b/programs/_updown_espmark/_updown_espmark.8
@@ -0,0 +1,18 @@
+.TH _UPDOWN_ESPMARK 8 "7 Apr 2005"
+.\"
+.\" RCSID $Id: _updown_espmark.8,v 1.1 2005/04/07 21:34:19 as Exp $
+.\"
+.SH NAME
+ipsec _updown_espmark \- manages routes and firewall rules
+.SH SYNOPSIS
+.I _updown_espmark
+is invoked by pluto when it has brought up a new connection. This script
+is used to insert the appropriate routing and iptables firewall entries for
+IPsec operation. The incoming ESP traffic must be marked by a static rule
+in the mangle table. The default value for the mark is 50.
+The interface to the script is documented in the pluto man page.
+.SH "SEE ALSO"
+ipsec(8), ipsec_pluto(8).
+.SH HISTORY
+Man page written for the Linux strongSwan project <http://www.strongswan.org/>
+by Andreas Steffen. Original program written by Henry Spencer.
diff --git a/programs/_updown_espmark/_updown_espmark.in b/programs/_updown_espmark/_updown_espmark.in
new file mode 100644
index 000000000..3627d470d
--- /dev/null
+++ b/programs/_updown_espmark/_updown_espmark.in
@@ -0,0 +1,452 @@
+#! /bin/sh
+# iproute2 version, default updown script
+#
+# Copyright (C) 2003-2004 Nigel Meteringham
+# Copyright (C) 2003-2004 Tuomo Soini
+# Copyright (C) 2002-2004 Michael Richardson
+# Copyright (C) 2005 Andreas Steffen <andreas.steffen@strongsec.com>
+#
+# 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: _updown_espmark.in,v 1.4 2005/09/14 14:33:05 as Exp $
+
+
+
+# CAUTION: Installing a new version of strongSwan will install a new
+# copy of this script, wiping out any custom changes you make. If
+# you need changes, make a copy of this under another name, and customize
+# that, and use the (left/right)updown parameters in ipsec.conf to make
+# FreeS/WAN use yours instead of this default one.
+
+# things that this script gets (from ipsec_pluto(8) man page)
+#
+#
+# PLUTO_VERSION
+# indicates what version of this interface is being
+# used. This document describes version 1.1. This
+# is upwardly compatible with version 1.0.
+#
+# PLUTO_VERB
+# specifies the name of the operation to be performed
+# (prepare-host, prepare-client, up-host, up-client,
+# down-host, or down-client). If the address family
+# for security gateway to security gateway communica­
+# tions is IPv6, then a suffix of -v6 is added to the
+# verb.
+#
+# PLUTO_CONNECTION
+# is the name of the connection for which we are
+# routing.
+#
+# PLUTO_NEXT_HOP
+# is the next hop to which packets bound for the peer
+# must be sent.
+#
+# PLUTO_INTERFACE
+# is the name of the ipsec interface to be used.
+#
+# PLUTO_ME
+# is the IP address of our host.
+#
+# PLUTO_MY_ID
+# is the ID of our host.
+#
+# PLUTO_MY_CLIENT
+# is the IP address / count of our client subnet. If
+# the client is just the host, this will be the
+# host's own IP address / max (where max is 32 for
+# IPv4 and 128 for IPv6).
+#
+# PLUTO_MY_CLIENT_NET
+# is the IP address of our client net. If the client
+# is just the host, this will be the host's own IP
+# address.
+#
+# PLUTO_MY_CLIENT_MASK
+# is the mask for our client net. If the client is
+# just the host, this will be 255.255.255.255.
+#
+# PLUTO_MY_SOURCEIP
+# if non-empty, then the source address for the route will be
+# set to this IP address.
+#
+# PLUTO_MY_PROTOCOL
+# is the IP protocol that will be transported.
+#
+# PLUTO_MY_PORT
+# is the UDP/TCP port to which the IPsec SA is
+# restricted on our side.
+#
+# PLUTO_PEER
+# is the IP address of our peer.
+#
+# PLUTO_PEER_ID
+# is the ID of our peer.
+#
+# PLUTO_PEER_CA
+# is the CA which issued the cert of our peer.
+#
+# PLUTO_PEER_CLIENT
+# is the IP address / count of the peer's client sub­
+# net. If the client is just the peer, this will be
+# the peer's own IP address / max (where max is 32
+# for IPv4 and 128 for IPv6).
+#
+# PLUTO_PEER_CLIENT_NET
+# is the IP address of the peer's client net. If the
+# client is just the peer, this will be the peer's
+# own IP address.
+#
+# PLUTO_PEER_CLIENT_MASK
+# is the mask for the peer's client net. If the
+# client is just the peer, this will be
+# 255.255.255.255.
+#
+# PLUTO_PEER_PROTOCOL
+# is the IP protocol that will be transported.
+#
+# PLUTO_PEER_PORT
+# is the UDP/TCP port to which the IPsec SA is
+# restricted on the peer side.
+#
+
+# logging of VPN connections
+#
+# tag put in front of each log entry:
+TAG=vpn
+#
+# syslog facility and priority used:
+FAC_PRIO=local0.notice
+#
+# to create a special vpn logging file, put the following line into
+# the syslog configuration file /etc/syslog.conf:
+#
+# local0.notice -/var/log/vpn
+#
+
+# check interface version
+case "$PLUTO_VERSION" in
+1.[0]) # Older Pluto?!? Play it safe, script may be using new features.
+ echo "$0: obsolete interface version \`$PLUTO_VERSION'," >&2
+ echo "$0: called by obsolete Pluto?" >&2
+ exit 2
+ ;;
+1.*) ;;
+*) echo "$0: unknown interface version \`$PLUTO_VERSION'" >&2
+ exit 2
+ ;;
+esac
+
+# check parameter(s)
+case "$1:$*" in
+':') # no parameters
+ ;;
+ipfwadm:ipfwadm) # due to (left/right)firewall; for default script only
+ ;;
+custom:*) # custom parameters (see above CAUTION comment)
+ ;;
+*) echo "$0: unknown parameters \`$*'" >&2
+ exit 2
+ ;;
+esac
+
+# utility functions for route manipulation
+# Meddling with this stuff should not be necessary and requires great care.
+uproute() {
+ doroute add
+ ip route flush cache
+}
+downroute() {
+ doroute delete
+ ip route flush cache
+}
+
+addsource() {
+ st=0
+ if ! ip -o route get ${PLUTO_MY_SOURCEIP%/*} | grep -q ^local
+ then
+ it="ip addr add ${PLUTO_MY_SOURCEIP%/*}/32 dev $PLUTO_INTERFACE"
+ oops="`eval $it 2>&1`"
+ st=$?
+ if test " $oops" = " " -a " $st" != " 0"
+ then
+ oops="silent error, exit status $st"
+ fi
+ if test " $oops" != " " -o " $st" != " 0"
+ then
+ echo "$0: addsource \`$it' failed ($oops)" >&2
+ fi
+ fi
+ return $st
+}
+
+doroute() {
+ st=0
+ parms="$PLUTO_PEER_CLIENT"
+
+ parms2=
+ if [ -n "$PLUTO_NEXT_HOP" ]
+ then
+ parms2="via $PLUTO_NEXT_HOP"
+ fi
+ parms2="$parms2 dev $PLUTO_INTERFACE"
+
+ if [ -z "$PLUTO_MY_SOURCEIP" ]
+ then
+ if [ -f /etc/sysconfig/defaultsource ]
+ then
+ . /etc/sysconfig/defaultsource
+ fi
+
+ if [ -f /etc/conf.d/defaultsource ]
+ then
+ . /etc/conf.d/defaultsource
+ fi
+
+ if [ -n "$DEFAULTSOURCE" ]
+ then
+ PLUTO_MY_SOURCEIP=$DEFAULTSOURCE
+ fi
+ fi
+
+ parms3=
+ if test "$1" = "add" -a -n "$PLUTO_MY_SOURCEIP"
+ then
+ addsource
+ parms3="$parms3 src ${PLUTO_MY_SOURCEIP%/*}"
+ fi
+
+ case "$PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK" in
+ "0.0.0.0/0.0.0.0")
+ # opportunistic encryption work around
+ # need to provide route that eclipses default, without
+ # replacing it.
+ it="ip route $1 0.0.0.0/1 $parms2 $parms3 &&
+ ip route $1 128.0.0.0/1 $parms2 $parms3"
+ ;;
+ *) it="ip route $1 $parms $parms2 $parms3"
+ ;;
+ esac
+ oops="`eval $it 2>&1`"
+ st=$?
+ if test " $oops" = " " -a " $st" != " 0"
+ then
+ oops="silent error, exit status $st"
+ fi
+ if test " $oops" != " " -o " $st" != " 0"
+ then
+ echo "$0: doroute \`$it' failed ($oops)" >&2
+ fi
+ return $st
+}
+
+# define ESP mark
+ESP_MARK=50
+
+# add the following static rule to the INPUT chain in the mangle table
+# iptables -t mangle -A INPUT -p 50 -j MARK --set-mark 50
+
+# NAT traversal via UDP encapsulation is supported with the rule
+# iptables -t mangle -A INPUT -p udp --dport 4500 -j MARK --set-mark 50
+
+# in the presence of KLIPS and ipsecN interfaces do not use ESP mark rules
+if [ `echo "$PLUTO_INTERFACE" | grep "ipsec"` ]
+then
+ CHECK_MARK=""
+else
+ CHECK_MARK="-m mark --mark $ESP_MARK"
+fi
+
+# are there port numbers?
+if [ "$PLUTO_MY_PORT" != 0 ]
+then
+ S_MY_PORT="--sport $PLUTO_MY_PORT"
+ D_MY_PORT="--dport $PLUTO_MY_PORT"
+fi
+if [ "$PLUTO_PEER_PORT" != 0 ]
+then
+ S_PEER_PORT="--sport $PLUTO_PEER_PORT"
+ D_PEER_PORT="--dport $PLUTO_PEER_PORT"
+fi
+
+# the big choice
+case "$PLUTO_VERB:$1" in
+prepare-host:*|prepare-client:*)
+ # delete possibly-existing route (preliminary to adding a route)
+ case "$PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK" in
+ "0.0.0.0/0.0.0.0")
+ # need to provide route that eclipses default, without
+ # replacing it.
+ parms1="0.0.0.0/1"
+ parms2="128.0.0.0/1"
+ it="ip route delete $parms1 2>&1 ; ip route delete $parms2 2>&1"
+ oops="`ip route delete $parms1 2>&1 ; ip route delete $parms2 2>&1`"
+ ;;
+ *)
+ parms="$PLUTO_PEER_CLIENT"
+ it="ip route delete $parms 2>&1"
+ oops="`ip route delete $parms 2>&1`"
+ ;;
+ esac
+ status="$?"
+ if test " $oops" = " " -a " $status" != " 0"
+ then
+ oops="silent error, exit status $status"
+ fi
+ case "$oops" in
+ *'RTNETLINK answers: No such process'*)
+ # This is what route (currently -- not documented!) gives
+ # for "could not find such a route".
+ oops=
+ status=0
+ ;;
+ esac
+ if test " $oops" != " " -o " $status" != " 0"
+ then
+ echo "$0: \`$it' failed ($oops)" >&2
+ fi
+ exit $status
+ ;;
+route-host:*|route-client:*)
+ # connection to me or my client subnet being routed
+ uproute
+ ;;
+unroute-host:*|unroute-client:*)
+ # connection to me or my client subnet being unrouted
+ downroute
+ ;;
+up-host:*)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ iptables -I INPUT 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_ME $D_MY_PORT $CHECK_MARK -j ACCEPT
+ iptables -I OUTPUT 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_ME $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ #
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME"
+ else
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME"
+ fi
+ ;;
+down-host:*)
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ iptables -D INPUT -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_ME $D_MY_PORT $CHECK_MARK -j ACCEPT
+ iptables -D OUTPUT -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_ME $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ #
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME"
+ else
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME"
+ fi
+ ;;
+up-client:)
+ # connection to my client subnet coming up
+ # If you are doing a custom version, firewall commands go here.
+ iptables -I FORWARD 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ iptables -I FORWARD 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $CHECK_MARK -j ACCEPT
+ #
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ else
+ logger -t $TAG -p $FAC_PRIO \
+ "+ `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ fi
+ ;;
+down-client:)
+ # connection to my client subnet going down
+ # If you are doing a custom version, firewall commands go here.
+ iptables -D FORWARD -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL \
+ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $S_MY_PORT \
+ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $D_PEER_PORT -j ACCEPT
+ iptables -D FORWARD -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL \
+ -s $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK $S_PEER_PORT \
+ -d $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK $D_MY_PORT \
+ $CHECK_MARK -j ACCEPT
+ #
+ if [ "$PLUTO_PEER_CLIENT" == "$PLUTO_PEER/32" ]
+ then
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ else
+ logger -t $TAG -p $FAC_PRIO -- \
+ "- `echo -e $PLUTO_PEER_ID` $PLUTO_PEER_CLIENT == $PLUTO_PEER -- $PLUTO_ME == $PLUTO_MY_CLIENT"
+ fi
+ ;;
+up-client:ipfwadm)
+ # connection to client subnet, with (left/right)firewall=yes, coming up
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ ipfwadm -F -i accept -b -S $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK \
+ -D $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK
+ ;;
+down-client:ipfwadm)
+ # connection to client subnet, with (left/right)firewall=yes, going down
+ # This is used only by the default updown script, not by your custom
+ # ones, so do not mess with it; see CAUTION comment up at top.
+ ipfwadm -F -d accept -b -S $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK \
+ -D $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK
+ ;;
+#
+# IPv6
+#
+prepare-host-v6:*|prepare-client-v6:*)
+ ;;
+route-host-v6:*|route-client-v6:*)
+ # connection to me or my client subnet being routed
+ #uproute_v6
+ ;;
+unroute-host-v6:*|unroute-client-v6:*)
+ # connection to me or my client subnet being unrouted
+ #downroute_v6
+ ;;
+up-host-v6:*)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-host-v6:*)
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+up-client-v6:)
+ # connection to my client subnet coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+down-client-v6:)
+ # connection to my client subnet going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+*) echo "$0: unknown verb \`$PLUTO_VERB' or parameter \`$1'" >&2
+ exit 1
+ ;;
+esac
diff --git a/programs/auto/.cvsignore b/programs/auto/.cvsignore
new file mode 100644
index 000000000..865faf10c
--- /dev/null
+++ b/programs/auto/.cvsignore
@@ -0,0 +1 @@
+auto
diff --git a/programs/auto/Makefile b/programs/auto/Makefile
new file mode 100644
index 000000000..035dbf708
--- /dev/null
+++ b/programs/auto/Makefile
@@ -0,0 +1,21 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.2 2006/02/10 11:28:38 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=auto
+
+include ../Makefile.program
diff --git a/programs/auto/auto.8 b/programs/auto/auto.8
new file mode 100644
index 000000000..21b5fd11b
--- /dev/null
+++ b/programs/auto/auto.8
@@ -0,0 +1,481 @@
+.TH IPSEC_AUTO 8 "17 December 2004"
+.\" RCSID $Id: auto.8,v 1.6 2004/12/17 22:34:38 as Exp $
+.SH NAME
+ipsec auto \- control automatically-keyed IPsec connections
+.SH SYNOPSIS
+.B ipsec
+.B auto
+[
+.B \-\-show
+] [
+.B \-\-showonly
+] [
+.B \-\-asynchronous
+]
+.br
+\ \ \ [
+.B \-\-config
+configfile
+] [
+.B \-\-verbose
+] [
+.B \-\-type conn
+]
+.br
+\ \ \ operation
+connection
+.sp
+.B ipsec
+.B auto
+[
+.B \-\-show
+] [
+.B \-\-showonly
+]
+.br
+\ \ \ [
+.B \-\-config
+configfile
+] [
+.B \-\-verbose
+]
+.B \-\-type ca
+.br
+\ \ \ operation
+ca
+.sp
+.B ipsec
+.B auto
+[
+.B \-\-show
+] [
+.B \-\-showonly
+] operation
+.SH DESCRIPTION
+.I Auto
+manipulates automatically-keyed strongSwan IPsec connections,
+setting them up and shutting them down
+based on the information in the IPsec configuration file.
+In the normal usage,
+.I connection
+is the name of a connection specification in the configuration file;
+.I ca
+is the name of a Certification Authority (CA) specification in the configuration file;
+.I operation
+is
+.BR \-\-add ,
+.BR \-\-delete ,
+.BR \-\-replace ,
+.BR \-\-up ,
+.BR \-\-down ,
+.BR \-\-route ,
+or
+.BR \-\-unroute .
+The
+.BR \-\-status
+and
+.BR \-\-statusall
+.I operations
+may take a
+.I connection
+name.
+The
+.BR \-\-ready ,
+.BR \-\-rereadsecrets ,
+.BR \-\-rereadgroups ,
+.BR \-\-rereadcacerts ,
+.BR \-\-rereadaacerts ,
+.BR \-\-rereadocspcerts ,
+.BR \-\-rereadacerts ,
+.BR \-\-rereadcrls ,
+.BR \-\-rereadall ,
+.BR \-\-listalgs ,
+.BR \-\-listpubkeys ,
+.BR \-\-listcerts ,
+.BR \-\-listcacerts ,
+.BR \-\-listaacerts ,
+.BR \-\-listocspcerts ,
+.BR \-\-listacerts ,
+.BR \-\-listgroups ,
+.BR \-\-listcainfos ,
+.BR \-\-listcrls ,
+.BR \-\-listocsp ,
+.BR \-\-listcards ,
+.BR \-\-listall ,
+and
+.BR \-\-purgeocsp
+.I operations
+do not take a connection name.
+.I Auto
+generates suitable
+commands and feeds them to a shell for execution.
+.PP
+The
+.B \-\-add
+operation adds a connection or ca specification to the internal database
+within
+.IR pluto ;
+it will fail if
+.I pluto
+already has a specification by that name.
+The
+.B \-\-delete
+operation deletes a connection or ca specification from
+.IR pluto 's
+internal database (also tearing down any connections based on it);
+it will fail if the specification does not exist.
+The
+.B \-\-replace
+operation is equivalent to
+.B \-\-delete
+(if there is already a specification by the given name)
+followed by
+.BR \-\-add ,
+and is a convenience for updating
+.IR pluto 's
+internal specification to match an external one.
+(Note that a
+.B \-\-rereadsecrets
+may also be needed.)
+The
+.B \-\-rereadgroups
+operation causes any changes to the policy group files to take effect
+(this is currently a synonym for
+.BR \-\-ready ,
+but that may change).
+None of the other operations alters the internal database.
+.PP
+The
+.B \-\-up
+operation asks
+.I pluto
+to establish a connection based on an entry in its internal database.
+The
+.B \-\-down
+operation tells
+.I pluto
+to tear down such a connection.
+.PP
+Normally,
+.I pluto
+establishes a route to the destination specified for a connection as
+part of the
+.B \-\-up
+operation.
+However, the route and only the route can be established with the
+.B \-\-route
+operation.
+Until and unless an actual connection is established,
+this discards any packets sent there,
+which may be preferable to having them sent elsewhere based on a more
+general route (e.g., a default route).
+.PP
+Normally,
+.IR pluto 's
+route to a destination remains in place when a
+.B \-\-down
+operation is used to take the connection down
+(or if connection setup, or later automatic rekeying, fails).
+This permits establishing a new connection (perhaps using a
+different specification; the route is altered as necessary)
+without having a ``window'' in which packets might go elsewhere
+based on a more general route.
+Such a route can be removed using the
+.B \-\-unroute
+operation
+(and is implicitly removed by
+.BR \-\-delete ).
+.PP
+The
+.B \-\-ready
+operation tells
+.I pluto
+to listen for connection-setup requests from other hosts.
+Doing an
+.B \-\-up
+operation before doing
+.B \-\-ready
+on both ends is futile and will not work,
+although this is now automated as part of IPsec startup and
+should not normally be an issue.
+.PP
+The
+.B \-\-status
+operation asks
+.I pluto
+for current connection status either for all connections
+(no connection argument) or a for specified
+.I connection
+name. For more detailed information use
+.B \-\-statusall
+\. The output format is ad-hoc and likely to change.
+.PP
+The
+.B \-\-rereadsecrets
+operation tells
+.I pluto
+to re-read the
+.I /etc/ipsec.secrets
+secret-keys file,
+which it normally reads only at startup time.
+(This is currently a synonym for
+.BR \-\-ready ,
+but that may change.)
+.PP
+The
+.B \-\-rereadcacerts
+operation reads all certificate files contained in the
+.IR /etc/ipsec.d/cacerts
+directory and adds them to
+.IR pluto 's
+list of Certification Authority (CA) certificates.
+.PP
+The
+.B \-\-rereadaacerts
+operation reads all certificate files contained in the
+.IR /etc/ipsec.d/aacerts
+directory and adds them to
+.IR pluto 's
+list of Authorization Authority (AA) certificates.
+.PP
+The
+.B \-\-rereadocspcerts
+operation reads all certificate files contained in the
+.IR /etc/ipsec.d/ocspcerts
+directory and adds them to
+.IR pluto 's
+list of OCSP signer certificates.
+.PP
+The
+.B \-\-rereadacerts
+operation reads all certificate files contained in the
+.IR /etc/ipsec.d/acerts
+directory and adds them to
+.IR pluto 's
+list of attribute certificates.
+.PP
+The
+.B \-\-rereadcrls
+operation reads all certificate revocation list (CRL) files
+contained in the
+.IR /etc/ipsec.d/crls
+directory and adds them to
+.IR pluto 's
+list of CRLs.
+.PP
+The
+.B \-\-rereadall
+operation is equivalent to the execution of
+.BR \-\-rereadsecrets ,
+.BR \-\-rereadcacerts ,
+.BR \-\-rereadaacerts ,
+.BR \-\-rereadocspcerts ,
+.BR \-\-rereadacerts ,
+and
+.BR \-\-rereadcrls .
+.PP
+The
+.B \-\-listalgs
+operation lists all registed IKE encryption and hash algorithms,
+that are available to
+.IR pluto ,
+as well as the Diffie-Hellman (DH) groups.
+.PP
+The
+.B \-\-listpubkeys
+operation lists all RSA public keys either received from peers
+via the IKE protocol embedded in authenticated certificate payloads
+or loaded locally using the
+.BR rightcert \ /
+.BR leftcert
+or
+.BR rightrsasigkey \ /
+.BR leftrsasigkey
+parameters in
+.IR ipsec.conf (5).
+.PP
+The
+.B \-\-listcerts
+operation lists all X.509 and OpenPGP certificates loaded locally using the
+.BR rightcert
+and
+.BR leftcert
+parameters in
+.IR ipsec.conf (5).
+.PP
+The
+.B \-\-listcacerts
+operation lists all X.509 CA certificates either loaded locally from the
+.IR /etc/ipsec.d/cacerts
+directory or received in PKCS#7-wrapped certificate payloads via
+the IKE protocol.
+.PP
+The
+.B \-\-listaacerts
+operation lists all X.509 AA certificates loaded locally from the
+.IR /etc/ipsec.d/aacerts
+directory.
+.PP
+The
+.B \-\-listocspcerts
+operation lists all OCSP signer certificates either loaded locally from the
+.IR /etc/ipsec.d/ocspcerts
+directory or received via the Online Certificate Status Protocol
+from an OCSP server.
+.PP
+The
+.B \-\-listacerts
+operation lists all X.509 attribute certificates loaded locally from the
+.IR /etc/ipsec.d/acerts
+directory.
+.PP
+The
+.B \-\-listgropus
+operation lists all groups that are either used in connection definitions in
+.IR ipsec.conf (5)
+or are embedded in loaded X.509 attributes certificates.
+.PP
+The
+.B \-\-listcainfos
+operation lists the certification authority information specified in the ca
+sections of
+.IR ipsec.conf (5).
+.PP
+The
+.B \-\-listcrls
+operation lists all Certificate Revocation Lists (CRLs) either loaded
+locally from the
+.IR /etc/ipsec.d/crls
+directory or fetched dynamically from an HTTP or LDAP server.
+.PP
+The
+.B \-\-listocsp
+operation lists the certicates status information fetched from
+OCSP servers.
+.PP
+The
+.B \-\-purgeocsp
+operation deletes any cached certificate status information and pending
+OCSP fetch requests.
+.PP
+The
+.B \-\-listcards
+operation lists information about attached smartcards or crypto tokens.
+.PP
+The
+.B \-\-listall
+operation is equivalent to the execution of
+.BR \-\-listalgs ,
+.BR \-\-listpubkeys ,
+.BR \-\-listcerts ,
+.BR \-\-listcacerts ,
+.BR \-\-listaacerts ,
+.BR \-\-listocspcerts ,
+.BR \-\-listacerts ,
+.BR \-\-listgroups ,
+.BR \-\-listcainfos ,
+.BR \-\-listcrls ,
+.BR \-\-listocsp ,
+and
+.BR \-\-listcards .
+.PP
+The
+.B \-\-show
+option turns on the
+.B \-x
+option of the shell used to execute the commands,
+so each command is shown as it is executed.
+.PP
+The
+.B \-\-showonly
+option causes
+.I auto
+to show the commands it would run, on standard output,
+and not run them.
+.PP
+The
+.B \-\-asynchronous
+option, applicable only to the
+.B up
+operation,
+tells
+.I pluto
+to attempt to establish the connection,
+but does not delay to report results.
+This is especially useful to start multiple connections in parallel
+when network links are slow.
+.PP
+The
+.B \-\-verbose
+option instructs
+.I auto
+to pass through all output from
+.IR ipsec_whack (8),
+including log output that is normally filtered out as uninteresting.
+.PP
+The
+.B \-\-config
+option specifies a non-standard location for the IPsec
+configuration file (default
+.IR /etc/ipsec.conf ).
+.PP
+See
+.IR ipsec.conf (5)
+for details of the configuration file.
+Apart from the basic parameters which specify the endpoints and routing
+of a connection (\fBleft\fR
+and
+.BR right ,
+plus possibly
+.BR leftsubnet ,
+.BR leftnexthop ,
+.BR leftfirewall ,
+their
+.B right
+equivalents,
+and perhaps
+.BR type ),
+an
+.I auto
+connection almost certainly needs a
+.B keyingtries
+parameter (since the
+.B keyingtries
+default is poorly chosen).
+.SH FILES
+.ta \w'/var/run/ipsec.info'u+4n
+/etc/ipsec.conf default IPSEC configuration file
+.br
+/var/run/ipsec.info \fB%defaultroute\fR information
+.SH SEE ALSO
+ipsec.conf(5), ipsec(8), ipsec_pluto(8), ipsec_whack(8), ipsec_manual(8)
+.SH HISTORY
+Written for the FreeS/WAN project
+<http://www.freeswan.org>
+by Henry Spencer.
+Extended for the strongSwan project
+<http://www.strongswan.org>
+by Andreas Steffen.
+.SH BUGS
+Although an
+.B \-\-up
+operation does connection setup on both ends,
+.B \-\-down
+tears only one end of the connection down
+(although the orphaned end will eventually time out).
+.PP
+There is no support for
+.B passthrough
+connections.
+.PP
+A connection description which uses
+.B %defaultroute
+for one of its
+.B nexthop
+parameters but not the other may be falsely
+rejected as erroneous in some circumstances.
+.PP
+The exit status of
+.B \-\-showonly
+does not always reflect errors discovered during processing of the request.
+(This is fine for human inspection, but not so good for use in scripts.)
diff --git a/programs/auto/auto.in b/programs/auto/auto.in
new file mode 100755
index 000000000..05568f9b5
--- /dev/null
+++ b/programs/auto/auto.in
@@ -0,0 +1,660 @@
+#! /bin/sh
+# user interface to automatic keying and Pluto in general
+# Copyright (C) 1998, 1999, 2000 Henry Spencer.
+#
+# 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: auto.in,v 1.17 2006/04/20 04:42:12 as Exp $
+
+me='ipsec auto'
+usage="Usage:
+ $me [--showonly] [--asynchronous] --up connectionname
+ $me [--showonly] [-- type conn|ca] --{add|delete|replace|down} name
+ $me [--showonly] --{route|unroute} connectionname
+ $me [--showonly] --ready
+ $me [--showonly] --{status|statusall} [connectionname]
+ $me [--showonly] --{rereadsecrets|rereadgroups}
+ $me [--showonly] --{rereadcacerts|rereadaacerts|rereadocspcerts}
+ $me [--showonly] --{rereadacerts|rereadcrls|rereadall}
+ $me [--showonly] [--utc] --{listalgs|listpubkeys|listcerts}
+ $me [--showonly] [--utc] --{listcacerts|listaacerts|listocspcerts}
+ $me [--showonly] [--utc] --{listacerts|listgroups|listcainfos}
+ $me [--showonly] [--utc] --{listcrls|listocsp|listcards|listall}
+ $me [--showonly] --purgeocsp
+
+ other options: [--config ipsecconfigfile] [--verbose] [--show]"
+
+showonly=
+config=
+info=/var/run/ipsec.info
+shopts=
+noinclude=
+async=
+logfilter='$1 != "002"'
+op=
+argc=
+utc=
+type="conn"
+name="--name"
+
+for dummy
+do
+ case "$1" in
+ --help) echo "$usage" ; exit 0 ;;
+ --version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+ --show) shopts=-x ;;
+ --showonly) showonly=yes ;;
+ --utc) utc="$1" ;;
+ --config) config="--config $2" ; shift ;;
+ --noinclude) noinclude=--noinclude ;;
+ --asynchronous) async="--asynchronous" ;;
+ --verbose) logfilter='1' ;;
+ --type) type="$2" ; shift ;;
+ --up|--down|--add|--delete|--replace|--route|--unroute)
+ if test " $op" != " "
+ then
+ echo "$usage" >&2
+ exit 2
+ fi
+ op="$1"
+ argc=1
+ if test "$type" = "ca"
+ then
+ name="--caname"
+ case "$op" in
+ --add|--delete|--replace) ;;
+ --*) echo "$op option not supported for --type ca";
+ exit 3 ;;
+ esac
+ fi
+ ;;
+ --status|--statusall)
+ if test " $op" != " "
+ then
+ echo "$usage" >&2
+ exit 2
+ fi
+ op="$1"
+ argc=1
+ if test $# -eq 1
+ then
+ argc=0; name=
+ fi
+ ;;
+ --ready|--rereadsecrets|--rereadgroups|\
+ --rereadcacerts|--rereadaacerts|--rereadocspcerts|\
+ --rereadacerts|--rereadcrls|--rereadall|\
+ --listalgs|--listpubkeys|--listcerts|\
+ --listcacerts|--listaacerts|--listocspcerts|\
+ --listacerts|--listgroups|--listcainfos|\
+ --listcrls|--listocsp|--listcards|--listall|\
+ --purgeocsp)
+ if test " $op" != " "
+ then
+ echo "$usage" >&2
+ exit 2
+ fi
+ op="$1"
+ argc=0
+ ;;
+ --) shift ; break ;;
+ -*) echo "$me: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+names=
+case "$op" in
+--*) if test " $argc" -ne $#
+ then
+ echo "$usage" >&2
+ exit 2
+ fi
+ names="$*"
+ ;;
+*) echo "$usage" >&2 ; exit 2 ;;
+esac
+
+
+runit() {
+ if test "$showonly"
+ then
+ cat
+ else
+ (
+ echo '('
+ cat
+ echo ')'
+ echo 'echo = $?'
+ ) | sh $shopts |
+ awk "/^= / { exit \$2 } $logfilter { print }"
+ fi
+}
+
+case "$op" in
+--ready) echo "ipsec whack --listen" | runit ; exit ;;
+--rereadsecrets) echo "ipsec whack --rereadsecrets" | runit ; exit ;;
+--rereadgroups) echo "ipsec whack --listen" | runit ; exit ;;
+--rereadcacerts) echo "ipsec whack --rereadcacerts" | runit ; exit ;;
+--rereadaacerts) echo "ipsec whack --rereadaacerts" | runit ; exit ;;
+--rereadocspcerts) echo "ipsec whack --rereadocspcerts" | runit ; exit ;;
+--rereadacerts) echo "ipsec whack --rereadacerts" | runit ; exit ;;
+--rereadcrls) echo "ipsec whack --rereadcrls" | runit ; exit ;;
+--rereadall) echo "ipsec whack --rereadall" | runit ; exit ;;
+--listalgs) echo "ipsec whack --listalgs" | runit ; exit ;;
+--listpubkeys) echo "ipsec whack $utc --listpubkeys" | runit ; exit ;;
+--listcerts) echo "ipsec whack $utc --listcerts" | runit ; exit ;;
+--listcacerts) echo "ipsec whack $utc --listcacerts" | runit ; exit ;;
+--listaacerts) echo "ipsec whack $utc --listaacerts" | runit ; exit ;;
+--listocspcerts) echo "ipsec whack $utc --listocspcerts" | runit ; exit ;;
+--listacerts) echo "ipsec whack $utc --listacerts" | runit ; exit ;;
+--listgroups) echo "ipsec whack $utc --listgroups" | runit ; exit ;;
+--listcainfos) echo "ipsec whack $utc --listcainfos" | runit ; exit ;;
+--listcrls) echo "ipsec whack $utc --listcrls" | runit ; exit ;;
+--listocsp) echo "ipsec whack $utc --listocsp" | runit ; exit ;;
+--listcards) echo "ipsec whack $utc --listcards" | runit ; exit ;;
+--listall) echo "ipsec whack $utc --listall" | runit ; exit ;;
+--purgeocsp) echo "ipsec whack $utc --purgeocsp" | runit ; exit ;;
+--up) echo "ipsec whack $async --name $names --initiate" | runit ; exit ;;
+--down) echo "ipsec whack --name $names --terminate" | runit ; exit ;;
+--delete) echo "ipsec whack $name $names --delete" | runit ; exit ;;
+--route) echo "ipsec whack --name $names --route" | runit ; exit ;;
+--unroute) echo "ipsec whack --name $names --unroute" | runit ; exit ;;
+--status) echo "ipsec whack $name $names --status" | runit ; exit ;;
+--statusall) echo "ipsec whack $name $names --statusall" | runit ; exit ;;
+esac
+
+if test -s $info
+then
+ . $info
+fi
+
+ipsec _confread $config $noinclude --type $type $names |
+awk -v section="$type" ' BEGIN {
+ FS = "\t"
+ op = "'"$op"'"
+ err = "cat >&2"
+ draddr = "'"$defaultrouteaddr"'"
+ drnexthop = "'"$defaultroutenexthop"'"
+ failed = 0
+ s[""] = ""
+ init()
+ print "PATH=\"'"$PATH"'\""
+ print "export PATH"
+ flip["left"] = "right"
+ flip["right"] = "left"
+ }
+ function init(n) {
+ for (n in s)
+ delete s[n]
+ name = ""
+ seensome = 0
+ }
+ $1 == ":" {
+ s[$2] = $3
+ seensome = 1
+ next
+ }
+ $1 == "!" {
+ if ($2 != "")
+ fail($2)
+ next
+ }
+ $1 == "=" {
+ if (name == "")
+ name = $2
+ next
+ }
+ $1 == "." {
+ if (section == "ca")
+ output_ca()
+ else
+ output()
+ init()
+ next
+ }
+ {
+ fail("internal error, unknown type code " v($1))
+ }
+ function fail(m) {
+ print "ipsec_auto: fatal error in " v(name) ": " m |err
+ failed = 1
+ exit
+ }
+ function yesno(k) {
+ if ((k in s) && s[k] != "yes" && s[k] != "no")
+ fail("parameter " v(k) " must be \"yes\" or \"no\"")
+ }
+ function setdefault(k, val) {
+ if (!(k in s))
+ s[k] = val
+ }
+ function was(new, old) {
+ if (!(new in s) && (old in s))
+ s[new] = s[old]
+ }
+ function need(k) {
+ if (!(k in s))
+ fail("connection has no " v(k) " parameter specified")
+ if (s[k] == "")
+ fail("parameter " v(k) " value must be non-empty")
+ }
+ function integer(k) {
+ if (!(k in s))
+ return
+ if (s[k] !~ /^[0-9]+$/)
+ fail("parameter " v(k) " value must be integer")
+ }
+ function duration(k, n, t) {
+ if (!(k in s))
+ return
+ t = s[k]
+ n = substr(t, 1, length(t)-1)
+ if (t ~ /^[0-9]+$/)
+ s[k] = t
+ else if (t ~ /^[0-9]+s$/)
+ s[k] = n
+ else if (t ~ /^[0-9]+(\.[0-9]+)?m$/)
+ s[k] = int(n*60)
+ else if (t ~ /^[0-9]+(\.[0-9]+)?h$/)
+ s[k] = int(n*3600)
+ else if (t ~ /^[0-9]+(\.[0-9]+)?d$/)
+ s[k] = int(n*3600*24)
+ else
+ fail("parameter " v(k) " not valid time, must be nnn[smhd]")
+ }
+ function nexthopset(dir, val, k) {
+ k = dir "nexthop"
+ if (k in s)
+ fail("non-default value of " k " is being overridden")
+ if (val != "")
+ s[k] = val
+ else if (k in s)
+ delete s[k]
+ }
+ function id(dir, k) {
+ k = dir "id"
+ if (!(k in s))
+ k = dir
+ return s[k]
+ }
+ function whackkey(dir, which, flag, rk, n) {
+ if (id(dir) == "%opportunistic")
+ return
+ rk = s[dir which]
+ if (rk == "%dnsondemand")
+ {
+ kod="--dnskeyondemand"
+ return
+ }
+ if (rk == "" || rk == "%none" || rk == "%cert" || rk == "0x00")
+ return
+ n = "\"\\\"" name "\\\" " dir which"\""
+ if (rk == "%dns" || rk == "%dnsonload")
+ {
+ if (id(flip[dir]) == "%opportunistic" || s[flip[dir]] == "%any")
+ return
+ print "ipsec whack --label", n, flag,
+ "--keyid", q(id(dir)), "\\"
+ }
+ else
+ {
+ print "ipsec whack --label", n, flag,
+ "--keyid", q(id(dir)),
+ "--pubkeyrsa", q(rk), "\\"
+ }
+ print "\t|| exit $?"
+ }
+ function q(str) { # quoting for shell
+ return "\"" str "\""
+ }
+ function qs(k) { # utility abbreviation for q(s[k])
+ return q(s[k])
+ }
+ function v(str) { # quoting for human viewing
+ return "\"" str "\""
+ }
+ function output() {
+ if (!seensome)
+ fail("internal error, output called inappropriately")
+
+ setdefault("type", "tunnel")
+ type_flags = ""
+ t = s["type"]
+ if (t == "tunnel") {
+ # do NOT default subnets to side/32, despite what
+ # the docs say...
+ type_flags = "--tunnel"
+ } else if (t == "transport") {
+ if ("leftsubnet" in s)
+ fail("type=transport incompatible with leftsubnet")
+ if ("rightsubnet" in s)
+ fail("type=transport incompatible with rightsubnet")
+ type_flags = ""
+ } else if (t == "passthrough") {
+ type_flags = "--pass"
+ } else if (t == "drop") {
+ type_flags = "--drop"
+ } else if (t == "reject") {
+ type_flags = "--reject"
+ } else
+ fail("unknown type " v(t))
+
+ setdefault("failureshunt", "none")
+ t = s["failureshunt"]
+ if (t == "passthrough")
+ type_flags = type_flags " --failpass";
+ else if (t == "drop")
+ type_flags = type_flags " --faildrop";
+ else if (t == "reject")
+ type_flags = type_flags " --failreject";
+ else if (t != "none")
+ fail("unknown failureshunt value " v(t))
+
+ need("left")
+ need("right")
+ if (s["left"] == "%defaultroute") {
+ if (s["right"] == "%defaultroute")
+ fail("left and right cannot both be %defaultroute")
+ if (draddr == "")
+ fail("%defaultroute requested but not known")
+ s["left"] = draddr
+ nexthopset("left", drnexthop)
+ } else if (s["right"] == "%defaultroute") {
+ if (draddr == "")
+ fail("%defaultroute requested but not known")
+ s["right"] = draddr
+ nexthopset("right", drnexthop)
+ }
+
+ setdefault("keyexchange", "ike")
+ if (s["keyexchange"] != "ike")
+ fail("only know how to do keyexchange=ike")
+ setdefault("auth", "esp")
+ if (("auth" in s) && s["auth"] != "esp" && s["auth"] != "ah")
+ fail("only know how to do auth=esp or auth=ah")
+ yesno("pfs")
+
+ setdefault("pfs", "yes")
+ duration("dpddelay")
+ duration("dpdtimeout")
+ if ("dpdaction" in s)
+ {
+ setdefault("dpddelay",30)
+ setdefault("dpdtimeout",120)
+ }
+ yesno("compress")
+ setdefault("compress", "no")
+ setdefault("keylife", "1h")
+ duration("keylife")
+ yesno("rekey")
+ setdefault("rekey", "yes")
+ setdefault("rekeymargin", "9m")
+ duration("rekeymargin")
+ setdefault("keyingtries", "%forever")
+ if (s["keyingtries"] == "%forever")
+ s["keyingtries"] = 0
+ integer("keyingtries")
+ if ("rekeyfuzz" in s) {
+ if (s["rekeyfuzz"] !~ /%$/)
+ fail("rekeyfuzz must be nnn%")
+ r = s["rekeyfuzz"]
+ s["rekeyfuzz"] = substr(r, 1, length(r)-1)
+ integer("rekeyfuzz")
+ }
+ duration("ikelifetime")
+ setdefault("disablearrivalcheck", "no")
+
+ setdefault("leftsendcert", "always")
+ setdefault("rightsendcert", "always")
+
+ setdefault("leftnexthop", "%direct")
+ setdefault("rightnexthop", "%direct")
+ if (s["leftnexthop"] == s["left"])
+ fail("left and leftnexthop must not be the same")
+ if (s["rightnexthop"] == s["right"])
+ fail("right and rightnexthop must not be the same")
+ if (s["leftnexthop"] == "%defaultroute") {
+ if (drnexthop == "")
+ fail("%defaultroute requested but not known")
+ s["leftnexthop"] = drnexthop
+ }
+ if (s["rightnexthop"] == "%defaultroute") {
+ if (drnexthop == "")
+ fail("%defaultroute requested but not known")
+ s["rightnexthop"] = drnexthop
+ }
+
+ if ("leftfirewall" in s && "leftupdown" in s)
+ fail("cannot have both leftfirewall and leftupdown")
+ if ("rightfirewall" in s && "rightupdown" in s)
+ fail("cannot have both rightfirewall and rightupdown")
+ setdefault("leftupdown", "ipsec _updown")
+ setdefault("rightupdown", "ipsec _updown")
+ setdefault("lefthostaccess", "no")
+ setdefault("righthostaccess", "no")
+ yesno("lefthostaccess")
+ yesno("righthostaccess")
+ lha = ""
+ if (s["lefthostaccess"] == "yes")
+ lha = "--hostaccess"
+ rha = ""
+ if (s["righthostaccess"] == "yes")
+ rha = "--hostaccess"
+ setdefault("leftfirewall", "no")
+ setdefault("rightfirewall", "no")
+ yesno("leftfirewall")
+ yesno("rightfirewall")
+ if (s["leftfirewall"] == "yes")
+ s["leftupdown"] = s["leftupdown"] " iptables"
+ if (s["rightfirewall"] == "yes")
+ s["rightupdown"] = s["rightupdown"] " iptables"
+
+ setdefault("authby", "rsasig")
+ t = s["authby"]
+ if (t == "rsasig" || t == "secret|rsasig" || t == "rsasig|secret") {
+ authtype = "--rsasig"
+ type_flags = "--encrypt " type_flags
+ if (!("leftcert" in s)) {
+ setdefault("leftrsasigkey", "%cert")
+ if (id("left") == "%any" &&
+ !(s["leftrsasigkey"] == "%cert" ||
+ s["leftrsasigkey"] == "0x00") )
+ fail("ID " v(id("left")) " cannot have RSA key")
+ }
+ if (!("rightcert" in s)) {
+ setdefault("rightrsasigkey", "%cert")
+ if (id("right") == "%any" &&
+ !(s["rightrsasigkey"] == "%cert" ||
+ s["rightrsasigkey"] == "0x00") )
+ fail("ID " v(id("right")) " cannot have RSA key")
+ }
+ if (t != "rsasig")
+ authtype = authtype " --psk"
+ } else if (t == "secret") {
+ authtype = "--psk"
+ type_flags = "--encrypt " type_flags
+ } else if (t == "never") {
+ authtype = ""
+ } else {
+ fail("unknown authby value " v(t))
+ }
+
+ settings = type_flags
+ setdefault("ike", "3des-sha,3des-md5")
+ if (s["ike"] != "")
+ settings = settings " --ike " qs("ike")
+ setdefault("esp", "3des")
+ if (s["esp"] != "")
+ settings = settings " --esp " qs("esp")
+ if (s["auth"] == "ah")
+ settings = settings " --authenticate"
+ if (s["pfs"] == "yes") {
+ settings = settings " --pfs"
+ if (s["pfsgroup"] != "")
+ settings = settings " --pfsgroup " qs("pfsgroup")
+ }
+
+ if (s["dpdaction"])
+ settings = settings " --dpdaction " qs("dpdaction")
+ if (s["dpddelay"])
+ settings = settings " --dpddelay " qs("dpddelay")
+ if (s["dpdtimeout"])
+ settings = settings " --dpdtimeout " qs("dpdtimeout")
+
+ if (s["compress"] == "yes")
+ settings = settings " --compress"
+ if (op == "--replace")
+ settings = settings " --delete"
+ if ("ikelifetime" in s)
+ settings = settings " --ikelifetime " qs("ikelifetime")
+ if (s["disablearrivalcheck"] == "yes")
+ settings = settings " --disablearrivalcheck"
+ settings = settings " " authtype
+
+ lc = ""
+ rc = ""
+ if ("leftsubnet" in s)
+ lc = "--client " qs("leftsubnet")
+ if ("rightsubnet" in s)
+ rc = "--client " qs("rightsubnet")
+ if ("leftsubnetwithin" in s)
+ lc = lc " --clientwithin " qs("leftsubnetwithin")
+ if ("rightsubnetwithin" in s)
+ rc = rc " --clientwithin " qs("rightsubnetwithin")
+ lp = ""
+ rp = ""
+ if ("leftprotoport" in s)
+ lp = "--clientprotoport " qs("leftprotoport")
+ if ("rightprotoport" in s)
+ rp = "--clientprotoport " qs("rightprotoport")
+ lud = "--updown " qs("leftupdown")
+ rud = "--updown " qs("rightupdown")
+
+ lid = ""
+ if ("leftid" in s)
+ lid = "--id " qs("leftid")
+ rid = ""
+ if ("rightid" in s)
+ rid = "--id " qs("rightid")
+ lsip = ""
+ if ("leftsourceip" in s)
+ lsip = "--srcip " qs("leftsourceip")
+ rsip = ""
+ if ("rightsourceip" in s)
+ rsip = "--srcip " qs("rightsourceip")
+ lscert = ""
+ if ("leftsendcert" in s)
+ lscert = "--sendcert " qs("leftsendcert")
+ rscert = ""
+ if ("rightsendcert" in s)
+ rscert = "--sendcert " qs("rightsendcert")
+ lcert = ""
+ if ("leftcert" in s)
+ lcert = "--cert " qs("leftcert")
+ rcert = ""
+ if ("rightcert" in s)
+ rcert = "--cert " qs("rightcert")
+ lca = ""
+ if ("leftca" in s)
+ lca = "--ca " qs("leftca")
+ rca = ""
+ if ("rightca" in s)
+ rca = "--ca " qs("rightca")
+ lgr = ""
+ if ("leftgroups" in s)
+ lgr = "--groups " qs("leftgroups")
+ rgr = ""
+ if ("rightgroups" in s)
+ rgr = "--groups " qs("rightgroups")
+ fuzz = ""
+ if ("rekeyfuzz" in s)
+ fuzz = "--rekeyfuzz " qs("rekeyfuzz")
+ rk = ""
+ if (s["rekey"] == "no")
+ rk = "--dontrekey"
+ pd = ""
+ if ("_plutodevel" in s)
+ pd = "--plutodevel " s["_plutodevel"] # not qs()
+
+ lkod = ""
+ rkod = ""
+ if (authtype != "--psk") {
+ kod = ""
+ whackkey("left", "rsasigkey", "")
+ whackkey("left", "rsasigkey2", "--addkey")
+ lkod = kod
+ kod = ""
+ whackkey("right", "rsasigkey", "")
+ whackkey("right", "rsasigkey2", "--addkey")
+ rkod = kod
+ }
+ print "ipsec whack --name", name, settings, "\\"
+ print "\t--host", qs("left"), lc, lp, "--nexthop",
+ qs("leftnexthop"), lud, lha, lid, lkod, lscert, lcert, lca, lsip, lgr, "\\"
+ print "\t--to", "--host", qs("right"), rc, rp, "--nexthop",
+ qs("rightnexthop"), rud, rha, rid, rkod, rscert, rcert, rca, rsip, rgr, "\\"
+ print "\t--ipseclifetime", qs("keylife"),
+ "--rekeymargin", qs("rekeymargin"), "\\"
+ print "\t--keyingtries", qs("keyingtries"), fuzz, rk, pd, "\\"
+ print "\t|| exit $?"
+ }
+ function output_ca() {
+ if (!seensome)
+ fail("internal error, output called inappropriately")
+ settings = ""
+ if (op == "--replace")
+ settings = "--delete"
+ cacert = ""
+ if ("cacert" in s)
+ cacert = "--cacert " qs("cacert")
+ ldaphost = ""
+ if ("ldaphost" in s)
+ ldaphost = "--ldaphost " qs("ldaphost")
+ ldapbase = ""
+ if ("ldapbase" in s)
+ ldapbase = "--ldapbase " qs("ldapbase")
+ crluri = ""
+ if ("crluri" in s)
+ crluri = "--crluri " qs("crluri")
+ crluri2 = ""
+ if ("crluri2" in s)
+ crluri2 = "--crluri2 " qs("crluri2")
+ ocspuri = ""
+ if ("ocspuri" in s)
+ ocspuri = "--ocspuri " qs("ocspuri")
+ yesno("strictcrlpolicy")
+ setdefault("strictcrlpolicy", "no")
+ if (s["strictcrlpolicy"] == "yes")
+ settings = settings " --strictcrlpolicy"
+ yesno("cachecrls")
+ setdefault("cachecrls", "no")
+ if (s["cachecrls"] == "yes")
+ settings = settings " --cachecrls"
+
+ print "ipsec whack --caname", name, settings, cacert, ldaphost, ldapbase,
+ crluri, crluri2, ocspuri, "\\"
+ print "\t|| exit $?"
+ }
+ END {
+ if (failed) {
+ print "# fatal error discovered, force failure using \"false\" command"
+ print "false"
+ exit 1 # just on general principles
+ }
+ if (seensome) {
+ if (section == "ca")
+ output_ca()
+ else
+ output()
+ }
+ }' | runit
diff --git a/programs/barf/.cvsignore b/programs/barf/.cvsignore
new file mode 100644
index 000000000..bca77a6ee
--- /dev/null
+++ b/programs/barf/.cvsignore
@@ -0,0 +1 @@
+barf
diff --git a/programs/barf/Makefile b/programs/barf/Makefile
new file mode 100644
index 000000000..6a20d4ee2
--- /dev/null
+++ b/programs/barf/Makefile
@@ -0,0 +1,38 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=barf
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/barf/barf.8 b/programs/barf/barf.8
new file mode 100644
index 000000000..e692a4e5f
--- /dev/null
+++ b/programs/barf/barf.8
@@ -0,0 +1,84 @@
+.TH IPSEC_BARF 8 "17 March 2002"
+.\" RCSID $Id: barf.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.SH NAME
+ipsec barf \- spew out collected IPsec debugging information
+.SH SYNOPSIS
+.B ipsec
+.B barf
+[
+.B \-\-short
+]
+.sp
+.SH DESCRIPTION
+.I Barf
+outputs (on standard output) a collection of debugging information
+(contents of files, selections from logs, etc.)
+related to the IPsec encryption/authentication system.
+It is primarily a convenience for remote debugging,
+a single command which packages up (and labels) all information
+that might be relevant to diagnosing a problem in IPsec.
+.PP
+.PP
+The
+.B \-\-short
+option limits the length of
+the log portion of
+.IR barf 's
+output, which can otherwise be extremely voluminous
+if debug logging is turned on.
+.PP
+.I Barf
+censors its output,
+replacing keys
+and secrets with brief checksums to avoid revealing sensitive information.
+.PP
+Beware that the output of both commands is aimed at humans,
+not programs,
+and the output format is subject to change without warning.
+.PP
+.I Barf
+has to figure out which files in
+.I /var/log
+contain the IPsec log messages.
+It looks for KLIPS and general log messages first in
+.IR messages
+and
+.IR syslog ,
+and for Pluto messages first in
+.IR secure ,
+.IR auth.log ,
+and
+.IR debug .
+In both cases,
+if it does not find what it is looking for in one of those ``likely'' places,
+it will resort to a brute-force search of most (non-compressed) files in
+.IR /var/log .
+.SH FILES
+.nf
+/proc/net/*
+/var/log/*
+/etc/ipsec.conf
+/etc/ipsec.secrets
+.fi
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org>
+by Henry Spencer.
+.SH BUGS
+.I Barf
+uses heuristics to try to pick relevant material out of the logs,
+and relevant messages
+which are not labelled with any of the tags that
+.I barf
+looks for will be lost.
+We think we've eliminated the last such case, but one never knows...
+.PP
+Finding
+.I updown
+scripts (so they can be included in output) is, in general, difficult.
+.I Barf
+uses a very simple heuristic that is easily fooled.
+.PP
+The brute-force search for the right log files can get expensive on
+systems with a lot of clutter in
+.IR /var/log .
diff --git a/programs/barf/barf.in b/programs/barf/barf.in
new file mode 100755
index 000000000..99cc3546c
--- /dev/null
+++ b/programs/barf/barf.in
@@ -0,0 +1,296 @@
+#! /bin/sh
+# dump assorted information of use in debugging
+# Copyright (C) 1998, 1999 Henry Spencer.
+#
+# 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: barf.in,v 1.4 2004/09/23 21:08:23 as Exp $
+
+IPSEC_NAME="strongSwan"
+
+KERNSRC=${KERNSRC-/usr/src/linux}
+LOGS=${LOGS-/var/log}
+CONFS=${IPSEC_CONFS-/etc}
+CONFDDIR=${IPSEC_CONFDDIR-/etc/ipsec.d}
+me="ipsec barf"
+
+# kludge to produce no barf output mentioning policygroups if none are present.
+# This will not catch ".file" policygroups.
+PREPOLICIES=${CONFDDIR}/policies
+if [ `ls $PREPOLICIES 2> /dev/null | wc -l` -ne 0 ]
+then
+ POLICIES=$PREPOLICIES
+fi
+
+# message patterns that start relevant parts of logs
+fstart="Starting $IPSEC_NAME"
+pstart='Starting Pluto subsystem'
+
+case "$1" in
+--help) echo "Usage: ipsec barf" ; exit 0 ;;
+--version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+esac
+
+# make sure output is in English
+unset LANG LANGUAGE LC_ALL LC_MESSAGES
+
+# log-location guesser, results in $findlog_file and $findlog_startline
+# Fine point: startline is the *last* line containing "string", or
+# failing that, the *first* line containing "fallbackstring".
+findlog() { # findlog string fallbackstring possiblefile ...
+ s="$1"
+ shift
+ t="$1"
+ shift
+ # try the suggested files first
+ for f in $*
+ do
+ if test -r $LOGS/$f -a -f $LOGS/$f && egrep -q "$s" $LOGS/$f
+ then
+ # aha, this one has it
+ findlog_file=$LOGS/$f
+ findlog_startline=`egrep -n "$s" $LOGS/$f |
+ sed -n '$s/:.*//p'`
+ return 0
+ fi
+ done
+ for f in $*
+ do
+ if test -r $LOGS/$f -a -f $LOGS/$f && egrep -q "$t" $LOGS/$f
+ then
+ # aha, this one has it
+ findlog_file=$LOGS/$f
+ findlog_startline=`egrep -n "$t" $LOGS/$f |
+ sed -n '1s/:.*//p'`
+ return 0
+ fi
+ done
+ # nope, resort to a search, newest first, of uncompressed logs
+ for f in `ls -t $LOGS | egrep -v '^mail' | egrep -v '\.(gz|Z)$'`
+ do
+ if test -r $LOGS/$f -a ! -d $LOGS/$f && egrep -q "$s" $LOGS/$f
+ then
+ # found it
+ findlog_file=$LOGS/$f
+ findlog_startline=`egrep -n "$s" $LOGS/$f |
+ sed -n '$s/:.*//p'`
+ return 0
+ fi
+ done
+ for f in `ls -t $LOGS | egrep -v '^mail' | egrep -v '\.(gz|Z)$'`
+ do
+ if test -r $LOGS/$f -a -f $LOGS/$f && egrep -q "$t" $LOGS/$f
+ then
+ # found it
+ findlog_file=$LOGS/$f
+ findlog_startline=`egrep -n "$t" $LOGS/$f |
+ sed -n '1s/:.*//p'`
+ return 0
+ fi
+ done
+# echo "$0: unable to find $LOGS/$1 or local equivalent" >&2
+ findlog_file=/dev/null
+ findlog_startline=1 # arbitrary
+}
+
+# try to guess where logs are
+findlog "$fstart" "klips" messages syslog
+if test " $findlog_file" = " /dev/null"
+then
+echo "Unable to find KLIPS messages, typically found in /var/log/messages or equivalent. You may need to run $IPSEC_NAME for the first time; alternatively, your log files have been emptied (ie, logwatch) or we do not understand your logging configuration."
+fi
+klog=$findlog_file
+kline=$findlog_startline
+
+findlog "$pstart" "Pluto" secure auth.log debug
+if test " $findlog_file" = " /dev/null"
+then
+echo "Unable to find Pluto messages, typically found in /var/log/secure or equivalent. You may need to run $IPSEC_NAME for the first time; alternatively, your log files have been emptied (ie, logwatch) or we do not understand your logging configuration."
+fi
+plog=$findlog_file
+pline=$findlog_startline
+
+# /lib/modules examiner
+modulegoo() {
+ set +x
+ for d in `ls /lib/modules`
+ do
+ if test -d /lib/modules/$d
+ then
+ f=/lib/modules/$d/$1
+ if test -f $f
+ then
+ nm -g $f | egrep "$2"
+ else
+ echo
+ fi | sed "s;^;$d: ;"
+ fi
+ done
+ set -x
+}
+
+# advanced shell deviousness to get dividers into output
+_________________________() {
+ $2 # something to do nothing and not echo anything
+}
+
+exec 2>&1 # stderr on stdout, so errors go into main output
+
+hostname ; date
+set -x
+_________________________ version
+ipsec --version
+_________________________ proc/version
+cat /proc/version
+_________________________ proc/net/ipsec_eroute
+sort -sg +3 /proc/net/ipsec_eroute || cat /proc/net/ipsec_eroute
+_________________________ netstat-rn
+netstat -nr
+_________________________ proc/net/ipsec_spi
+cat /proc/net/ipsec_spi
+_________________________ proc/net/ipsec_spigrp
+cat /proc/net/ipsec_spigrp
+_________________________ proc/net/ipsec_tncfg
+cat /proc/net/ipsec_tncfg
+_________________________ proc/net/pf_key
+cat /proc/net/pf_key
+_________________________ proc/net/pf_key-star
+( cd /proc/net && egrep '^' pf_key_* )
+_________________________ proc/sys/net/ipsec-star
+( cd /proc/sys/net/ipsec && egrep '^' * )
+_________________________ ipsec/statusall
+ipsec auto --statusall
+_________________________ ifconfig-a
+ifconfig -a
+_________________________ mii-tool
+if [ -x /sbin/mii-tool ]
+then
+ /sbin/mii-tool -v
+elif [ -x /usr/sbin/mii-tool ]
+then
+ /usr/sbin/mii-tool -v
+else
+ mii-tool -v
+fi
+_________________________ ipsec/directory
+ipsec --directory
+_________________________ hostname/fqdn
+hostname --fqdn
+_________________________ hostname/ipaddress
+hostname --ip-address
+_________________________ uptime
+uptime
+_________________________ ps
+# -i ppid picks up the header
+ps alxwf | egrep -i 'ppid|pluto|ipsec|klips'
+_________________________ ipsec/showdefaults
+ipsec showdefaults
+_________________________ ipsec/conf
+ipsec _include $CONFS/ipsec.conf | ipsec _keycensor
+_________________________ ipsec/secrets
+ipsec _include $CONFS/ipsec.secrets | ipsec _secretcensor
+_________________________ ipsec/listall
+ipsec auto --listall
+if [ $POLICIES ]
+then
+ for policy in $POLICIES/*; do base=`basename $policy`;
+ _________________________ ipsec/policies/$base
+ cat $policy
+ done
+fi
+_________________________ ipsec/ls-libdir
+ls -l ${IPSEC_LIBDIR-/usr/local/lib/ipsec}
+_________________________ ipsec/ls-execdir
+ls -l ${IPSEC_EXECDIR-/usr/local/libexec/ipsec}
+_________________________ ipsec/updowns
+for f in `ls ${IPSEC_EXECDIR-/usr/local/libexec/ipsec} | egrep updown`
+do
+ cat ${IPSEC_EXECDIR-/usr/local/libexec/ipsec}/$f
+done
+_________________________ proc/net/dev
+cat /proc/net/dev
+_________________________ proc/net/route
+cat /proc/net/route
+_________________________ proc/sys/net/ipv4/ip_forward
+cat /proc/sys/net/ipv4/ip_forward
+_________________________ proc/sys/net/ipv4/conf/star-rp_filter
+( cd /proc/sys/net/ipv4/conf && egrep '^' */rp_filter )
+_________________________ uname-a
+uname -a
+_________________________ redhat-release
+if test -r /etc/redhat-release
+then
+ cat /etc/redhat-release
+fi
+_________________________ proc/net/ipsec_version
+cat /proc/net/ipsec_version
+_________________________ iptables/list
+iptables -L -v -n
+_________________________ ipchains/list
+ipchains -L -v -n
+_________________________ ipfwadm/forward
+ipfwadm -F -l -n -e
+_________________________ ipfwadm/input
+ipfwadm -I -l -n -e
+_________________________ ipfwadm/output
+ipfwadm -O -l -n -e
+_________________________ iptables/nat
+iptables -t nat -L -v -n
+_________________________ ipchains/masq
+ipchains -M -L -v -n
+_________________________ ipfwadm/masq
+ipfwadm -M -l -n -e
+_________________________ iptables/mangle
+iptables -t mangle -L -v -n
+_________________________ proc/modules
+cat /proc/modules
+_________________________ proc/meminfo
+cat /proc/meminfo
+_________________________ dev/ipsec-ls
+ls -l /dev/ipsec*
+_________________________ proc/net/ipsec-ls
+ls -l /proc/net/ipsec_*
+_________________________ usr/src/linux/.config
+if test -f $KERNSRC/.config
+then
+ egrep 'IP|NETLINK' $KERNSRC/.config
+fi
+_________________________ etc/syslog.conf
+cat /etc/syslog.conf
+_________________________ etc/resolv.conf
+cat /etc/resolv.conf
+_________________________ lib/modules-ls
+ls -ltr /lib/modules
+_________________________ proc/ksyms-netif_rx
+egrep netif_rx /proc/ksyms
+_________________________ lib/modules-netif_rx
+modulegoo kernel/net/ipv4/ipip.o netif_rx
+_________________________ kern.debug
+if test -f $LOGS/kern.debug
+then
+ tail -100 $LOGS/kern.debug
+fi
+_________________________ klog
+sed -n $kline,'$'p $klog |
+ egrep -i 'ipsec|klips|pluto' |
+ case "$1" in
+ --short) tail -500 ;;
+ *) cat ;;
+ esac
+_________________________ plog
+sed -n $pline,'$'p $plog |
+ egrep -i 'pluto' |
+ case "$1" in
+ --short) tail -500 ;;
+ *) cat ;;
+ esac
+_________________________ date
+date
diff --git a/programs/calcgoo/.cvsignore b/programs/calcgoo/.cvsignore
new file mode 100644
index 000000000..b4aa748b7
--- /dev/null
+++ b/programs/calcgoo/.cvsignore
@@ -0,0 +1 @@
+calcgoo
diff --git a/programs/calcgoo/Makefile b/programs/calcgoo/Makefile
new file mode 100644
index 000000000..8e3cae9ea
--- /dev/null
+++ b/programs/calcgoo/Makefile
@@ -0,0 +1,41 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=calcgoo
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.1 2002/06/10 04:27:25 mcr
+# calcgoo program processes kernel symbol list and generates a
+# composite value by xor'ing the programmed symbol.
+#
+# Revision 1.1 2002/06/10 00:19:44 mcr
+# rename "ipsec check" to "ipsec verify"
+#
+# Revision 1.1 2002/06/08 17:01:25 mcr
+# added new program "ipsec check" to do rudamentary testing
+# on a newly installed system to see if it is OE ready.
+#
+#
+#
+
diff --git a/programs/calcgoo/calcgoo.8 b/programs/calcgoo/calcgoo.8
new file mode 100644
index 000000000..ceb576e41
--- /dev/null
+++ b/programs/calcgoo/calcgoo.8
@@ -0,0 +1,31 @@
+.TH IPSEC_CALCGOO 8 "8 June 2002"
+.\" RCSID $Id: calcgoo.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.SH NAME
+ipsec calcgoo \- calculate hex value for matching modules and kernels
+.SH SYNOPSIS
+.B ipsec
+.B calcgoo
+.SH DESCRIPTION
+.I calcgoo
+accepts the output of
+.B nm -ao
+or
+.B /proc/ksyms
+and extracts a release dependant list of symbols from it. The symbols
+are processed to extract the values assigned during the MODVERSIONS
+process. This process makes sure that Linux modules are only loaded
+on matching kernels.
+.P
+This routine is used to find an appropriate module to match the currently
+running kernel by _startklips.
+.SH FILES
+.nf
+/proc/ksyms
+.fi
+.SH "SEE ALSO"
+ipsec__startklips(8), genksyms(8)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org>
+by Michael Richardson.
+.SH BUGS
diff --git a/programs/calcgoo/calcgoo.in b/programs/calcgoo/calcgoo.in
new file mode 100644
index 000000000..0d383d173
--- /dev/null
+++ b/programs/calcgoo/calcgoo.in
@@ -0,0 +1,43 @@
+#!/usr/bin/perl
+
+$MODULE_GOO_LIST="@MODULE_GOO_LIST@";
+
+@goo = split(/\s+/,$MODULE_GOO_LIST);
+
+$sep="(";
+$goore=" ";
+
+#print "GOO: ",join('|',@goo),"\n";
+
+foreach $sym (@goo) {
+ $goore=${goore}.${sep}.${sym};
+ $sep="|";
+}
+$goore=${goore}.")_R(smp_){0,1}([0-9A-F]{8})";
+
+#print "GOORE: $goore\n";
+
+while(<>) {
+ chomp;
+ if(/$goore/io) {
+ $sym=$1;
+ $goosym=$3;
+ $bingoo=hex($goosym);
+ if($2 eq "smp_") {
+ $bingoo++;
+ }
+ #print STDERR "Processing $goosym (from $_)\n";
+ $bingoo{$sym}=$bingoo;
+ }
+}
+$wholegoo=0;
+foreach $sym (keys %bingoo) {
+ $wholegoo=$wholegoo ^ $bingoo{$sym};
+}
+print sprintf("%08x", $wholegoo)."\n";
+
+# Local variables::
+# mode: perl
+# End variables::
+
+
diff --git a/Source/Doxyfile b/programs/charon/Doxyfile
index 5ee25a839..5ee25a839 100644
--- a/Source/Doxyfile
+++ b/programs/charon/Doxyfile
diff --git a/Source/Makefile b/programs/charon/Makefile
index b69438b84..b69438b84 100644
--- a/Source/Makefile
+++ b/programs/charon/Makefile
diff --git a/Source/charon.kdevelop b/programs/charon/charon.kdevelop
index 270e815c4..270e815c4 100644
--- a/Source/charon.kdevelop
+++ b/programs/charon/charon.kdevelop
diff --git a/Source/charon/Makefile.charon b/programs/charon/charon/Makefile.charon
index 336495db9..336495db9 100644
--- a/Source/charon/Makefile.charon
+++ b/programs/charon/charon/Makefile.charon
diff --git a/Source/charon/config/Makefile.config b/programs/charon/charon/config/Makefile.config
index d4638b318..d4638b318 100644
--- a/Source/charon/config/Makefile.config
+++ b/programs/charon/charon/config/Makefile.config
diff --git a/Source/charon/config/configuration.c b/programs/charon/charon/config/configuration.c
index eac1bd43a..eac1bd43a 100755
--- a/Source/charon/config/configuration.c
+++ b/programs/charon/charon/config/configuration.c
diff --git a/Source/charon/config/configuration.h b/programs/charon/charon/config/configuration.h
index 6b741f9fb..6b741f9fb 100755
--- a/Source/charon/config/configuration.h
+++ b/programs/charon/charon/config/configuration.h
diff --git a/Source/charon/config/connections/Makefile.connections b/programs/charon/charon/config/connections/Makefile.connections
index 8fbc983f6..8fbc983f6 100644
--- a/Source/charon/config/connections/Makefile.connections
+++ b/programs/charon/charon/config/connections/Makefile.connections
diff --git a/Source/charon/config/connections/connection.c b/programs/charon/charon/config/connections/connection.c
index 74e6762b4..74e6762b4 100644
--- a/Source/charon/config/connections/connection.c
+++ b/programs/charon/charon/config/connections/connection.c
diff --git a/Source/charon/config/connections/connection.h b/programs/charon/charon/config/connections/connection.h
index 2cb3c20b8..2cb3c20b8 100644
--- a/Source/charon/config/connections/connection.h
+++ b/programs/charon/charon/config/connections/connection.h
diff --git a/Source/charon/config/connections/connection_store.h b/programs/charon/charon/config/connections/connection_store.h
index 41fd58e42..41fd58e42 100755
--- a/Source/charon/config/connections/connection_store.h
+++ b/programs/charon/charon/config/connections/connection_store.h
diff --git a/Source/charon/config/connections/local_connection_store.c b/programs/charon/charon/config/connections/local_connection_store.c
index 3f07f0d21..3f07f0d21 100644
--- a/Source/charon/config/connections/local_connection_store.c
+++ b/programs/charon/charon/config/connections/local_connection_store.c
diff --git a/Source/charon/config/connections/local_connection_store.h b/programs/charon/charon/config/connections/local_connection_store.h
index 14a0a24ae..14a0a24ae 100644
--- a/Source/charon/config/connections/local_connection_store.h
+++ b/programs/charon/charon/config/connections/local_connection_store.h
diff --git a/Source/charon/config/credentials/Makefile.credentials b/programs/charon/charon/config/credentials/Makefile.credentials
index 720d56656..720d56656 100644
--- a/Source/charon/config/credentials/Makefile.credentials
+++ b/programs/charon/charon/config/credentials/Makefile.credentials
diff --git a/Source/charon/config/credentials/credential_store.h b/programs/charon/charon/config/credentials/credential_store.h
index 2339469c0..2339469c0 100755
--- a/Source/charon/config/credentials/credential_store.h
+++ b/programs/charon/charon/config/credentials/credential_store.h
diff --git a/Source/charon/config/credentials/local_credential_store.c b/programs/charon/charon/config/credentials/local_credential_store.c
index dc6cb6c50..dc6cb6c50 100644
--- a/Source/charon/config/credentials/local_credential_store.c
+++ b/programs/charon/charon/config/credentials/local_credential_store.c
diff --git a/Source/charon/config/credentials/local_credential_store.h b/programs/charon/charon/config/credentials/local_credential_store.h
index ab9ef88d7..ab9ef88d7 100644
--- a/Source/charon/config/credentials/local_credential_store.h
+++ b/programs/charon/charon/config/credentials/local_credential_store.h
diff --git a/Source/charon/config/policies/Makefile.policies b/programs/charon/charon/config/policies/Makefile.policies
index e7ed8ab13..e7ed8ab13 100644
--- a/Source/charon/config/policies/Makefile.policies
+++ b/programs/charon/charon/config/policies/Makefile.policies
diff --git a/Source/charon/config/policies/local_policy_store.c b/programs/charon/charon/config/policies/local_policy_store.c
index ae02357ea..ae02357ea 100644
--- a/Source/charon/config/policies/local_policy_store.c
+++ b/programs/charon/charon/config/policies/local_policy_store.c
diff --git a/Source/charon/config/policies/local_policy_store.h b/programs/charon/charon/config/policies/local_policy_store.h
index 7ab9e0efd..7ab9e0efd 100644
--- a/Source/charon/config/policies/local_policy_store.h
+++ b/programs/charon/charon/config/policies/local_policy_store.h
diff --git a/Source/charon/config/policies/policy.c b/programs/charon/charon/config/policies/policy.c
index cff87fc6b..cff87fc6b 100644
--- a/Source/charon/config/policies/policy.c
+++ b/programs/charon/charon/config/policies/policy.c
diff --git a/Source/charon/config/policies/policy.h b/programs/charon/charon/config/policies/policy.h
index 78cda1e8b..78cda1e8b 100644
--- a/Source/charon/config/policies/policy.h
+++ b/programs/charon/charon/config/policies/policy.h
diff --git a/Source/charon/config/policies/policy_store.h b/programs/charon/charon/config/policies/policy_store.h
index 651dea634..651dea634 100755
--- a/Source/charon/config/policies/policy_store.h
+++ b/programs/charon/charon/config/policies/policy_store.h
diff --git a/Source/charon/config/proposal.c b/programs/charon/charon/config/proposal.c
index cb71a756a..cb71a756a 100644
--- a/Source/charon/config/proposal.c
+++ b/programs/charon/charon/config/proposal.c
diff --git a/Source/charon/config/proposal.h b/programs/charon/charon/config/proposal.h
index 48e3ad8d5..48e3ad8d5 100644
--- a/Source/charon/config/proposal.h
+++ b/programs/charon/charon/config/proposal.h
diff --git a/Source/charon/config/traffic_selector.c b/programs/charon/charon/config/traffic_selector.c
index 81272659a..81272659a 100644
--- a/Source/charon/config/traffic_selector.c
+++ b/programs/charon/charon/config/traffic_selector.c
diff --git a/Source/charon/config/traffic_selector.h b/programs/charon/charon/config/traffic_selector.h
index 5ac5bdeb1..5ac5bdeb1 100644
--- a/Source/charon/config/traffic_selector.h
+++ b/programs/charon/charon/config/traffic_selector.h
diff --git a/Source/charon/daemon.c b/programs/charon/charon/daemon.c
index 4b0ea54e8..4b0ea54e8 100644
--- a/Source/charon/daemon.c
+++ b/programs/charon/charon/daemon.c
diff --git a/Source/charon/daemon.h b/programs/charon/charon/daemon.h
index 5aee21fdb..5aee21fdb 100644
--- a/Source/charon/daemon.h
+++ b/programs/charon/charon/daemon.h
diff --git a/Source/charon/encoding/Makefile.encoding b/programs/charon/charon/encoding/Makefile.encoding
index ccdb42f79..ccdb42f79 100644
--- a/Source/charon/encoding/Makefile.encoding
+++ b/programs/charon/charon/encoding/Makefile.encoding
diff --git a/Source/charon/encoding/generator.c b/programs/charon/charon/encoding/generator.c
index ba12190dd..ba12190dd 100644
--- a/Source/charon/encoding/generator.c
+++ b/programs/charon/charon/encoding/generator.c
diff --git a/Source/charon/encoding/generator.h b/programs/charon/charon/encoding/generator.h
index 717d32b73..717d32b73 100644
--- a/Source/charon/encoding/generator.h
+++ b/programs/charon/charon/encoding/generator.h
diff --git a/Source/charon/encoding/message.c b/programs/charon/charon/encoding/message.c
index a57315272..a57315272 100644
--- a/Source/charon/encoding/message.c
+++ b/programs/charon/charon/encoding/message.c
diff --git a/Source/charon/encoding/message.h b/programs/charon/charon/encoding/message.h
index e3a72f439..e3a72f439 100644
--- a/Source/charon/encoding/message.h
+++ b/programs/charon/charon/encoding/message.h
diff --git a/Source/charon/encoding/parser.c b/programs/charon/charon/encoding/parser.c
index a589e9bde..a589e9bde 100644
--- a/Source/charon/encoding/parser.c
+++ b/programs/charon/charon/encoding/parser.c
diff --git a/Source/charon/encoding/parser.h b/programs/charon/charon/encoding/parser.h
index 216fac9b7..216fac9b7 100644
--- a/Source/charon/encoding/parser.h
+++ b/programs/charon/charon/encoding/parser.h
diff --git a/Source/charon/encoding/payloads/Makefile.payloads b/programs/charon/charon/encoding/payloads/Makefile.payloads
index 61d920907..61d920907 100644
--- a/Source/charon/encoding/payloads/Makefile.payloads
+++ b/programs/charon/charon/encoding/payloads/Makefile.payloads
diff --git a/Source/charon/encoding/payloads/auth_payload.c b/programs/charon/charon/encoding/payloads/auth_payload.c
index cc7c4bfb1..cc7c4bfb1 100644
--- a/Source/charon/encoding/payloads/auth_payload.c
+++ b/programs/charon/charon/encoding/payloads/auth_payload.c
diff --git a/Source/charon/encoding/payloads/auth_payload.h b/programs/charon/charon/encoding/payloads/auth_payload.h
index e099cdfef..e099cdfef 100644
--- a/Source/charon/encoding/payloads/auth_payload.h
+++ b/programs/charon/charon/encoding/payloads/auth_payload.h
diff --git a/Source/charon/encoding/payloads/cert_payload.c b/programs/charon/charon/encoding/payloads/cert_payload.c
index 146d42eda..146d42eda 100644
--- a/Source/charon/encoding/payloads/cert_payload.c
+++ b/programs/charon/charon/encoding/payloads/cert_payload.c
diff --git a/Source/charon/encoding/payloads/cert_payload.h b/programs/charon/charon/encoding/payloads/cert_payload.h
index 9148cfd31..9148cfd31 100644
--- a/Source/charon/encoding/payloads/cert_payload.h
+++ b/programs/charon/charon/encoding/payloads/cert_payload.h
diff --git a/Source/charon/encoding/payloads/certreq_payload.c b/programs/charon/charon/encoding/payloads/certreq_payload.c
index cdab82be4..cdab82be4 100644
--- a/Source/charon/encoding/payloads/certreq_payload.c
+++ b/programs/charon/charon/encoding/payloads/certreq_payload.c
diff --git a/Source/charon/encoding/payloads/certreq_payload.h b/programs/charon/charon/encoding/payloads/certreq_payload.h
index 3e88e7ffe..3e88e7ffe 100644
--- a/Source/charon/encoding/payloads/certreq_payload.h
+++ b/programs/charon/charon/encoding/payloads/certreq_payload.h
diff --git a/Source/charon/encoding/payloads/configuration_attribute.c b/programs/charon/charon/encoding/payloads/configuration_attribute.c
index 489d7f372..489d7f372 100644
--- a/Source/charon/encoding/payloads/configuration_attribute.c
+++ b/programs/charon/charon/encoding/payloads/configuration_attribute.c
diff --git a/Source/charon/encoding/payloads/configuration_attribute.h b/programs/charon/charon/encoding/payloads/configuration_attribute.h
index 5b6b4f473..5b6b4f473 100644
--- a/Source/charon/encoding/payloads/configuration_attribute.h
+++ b/programs/charon/charon/encoding/payloads/configuration_attribute.h
diff --git a/Source/charon/encoding/payloads/cp_payload.c b/programs/charon/charon/encoding/payloads/cp_payload.c
index 583488382..583488382 100644
--- a/Source/charon/encoding/payloads/cp_payload.c
+++ b/programs/charon/charon/encoding/payloads/cp_payload.c
diff --git a/Source/charon/encoding/payloads/cp_payload.h b/programs/charon/charon/encoding/payloads/cp_payload.h
index eb8076446..eb8076446 100644
--- a/Source/charon/encoding/payloads/cp_payload.h
+++ b/programs/charon/charon/encoding/payloads/cp_payload.h
diff --git a/Source/charon/encoding/payloads/delete_payload.c b/programs/charon/charon/encoding/payloads/delete_payload.c
index 28e78800f..28e78800f 100644
--- a/Source/charon/encoding/payloads/delete_payload.c
+++ b/programs/charon/charon/encoding/payloads/delete_payload.c
diff --git a/Source/charon/encoding/payloads/delete_payload.h b/programs/charon/charon/encoding/payloads/delete_payload.h
index 71a6317d4..71a6317d4 100644
--- a/Source/charon/encoding/payloads/delete_payload.h
+++ b/programs/charon/charon/encoding/payloads/delete_payload.h
diff --git a/Source/charon/encoding/payloads/eap_payload.c b/programs/charon/charon/encoding/payloads/eap_payload.c
index 2a0e17679..2a0e17679 100644
--- a/Source/charon/encoding/payloads/eap_payload.c
+++ b/programs/charon/charon/encoding/payloads/eap_payload.c
diff --git a/Source/charon/encoding/payloads/eap_payload.h b/programs/charon/charon/encoding/payloads/eap_payload.h
index 5e5a0c6d8..5e5a0c6d8 100644
--- a/Source/charon/encoding/payloads/eap_payload.h
+++ b/programs/charon/charon/encoding/payloads/eap_payload.h
diff --git a/Source/charon/encoding/payloads/encodings.c b/programs/charon/charon/encoding/payloads/encodings.c
index da39467a9..da39467a9 100644
--- a/Source/charon/encoding/payloads/encodings.c
+++ b/programs/charon/charon/encoding/payloads/encodings.c
diff --git a/Source/charon/encoding/payloads/encodings.h b/programs/charon/charon/encoding/payloads/encodings.h
index e30e1c215..e30e1c215 100644
--- a/Source/charon/encoding/payloads/encodings.h
+++ b/programs/charon/charon/encoding/payloads/encodings.h
diff --git a/Source/charon/encoding/payloads/encryption_payload.c b/programs/charon/charon/encoding/payloads/encryption_payload.c
index e0ca74ff4..e0ca74ff4 100644
--- a/Source/charon/encoding/payloads/encryption_payload.c
+++ b/programs/charon/charon/encoding/payloads/encryption_payload.c
diff --git a/Source/charon/encoding/payloads/encryption_payload.h b/programs/charon/charon/encoding/payloads/encryption_payload.h
index 77be246c5..77be246c5 100644
--- a/Source/charon/encoding/payloads/encryption_payload.h
+++ b/programs/charon/charon/encoding/payloads/encryption_payload.h
diff --git a/Source/charon/encoding/payloads/id_payload.c b/programs/charon/charon/encoding/payloads/id_payload.c
index 6a8d7738d..6a8d7738d 100644
--- a/Source/charon/encoding/payloads/id_payload.c
+++ b/programs/charon/charon/encoding/payloads/id_payload.c
diff --git a/Source/charon/encoding/payloads/id_payload.h b/programs/charon/charon/encoding/payloads/id_payload.h
index c35b44d59..c35b44d59 100644
--- a/Source/charon/encoding/payloads/id_payload.h
+++ b/programs/charon/charon/encoding/payloads/id_payload.h
diff --git a/Source/charon/encoding/payloads/ike_header.c b/programs/charon/charon/encoding/payloads/ike_header.c
index ad46d3d29..ad46d3d29 100644
--- a/Source/charon/encoding/payloads/ike_header.c
+++ b/programs/charon/charon/encoding/payloads/ike_header.c
diff --git a/Source/charon/encoding/payloads/ike_header.h b/programs/charon/charon/encoding/payloads/ike_header.h
index ec55f0e18..ec55f0e18 100644
--- a/Source/charon/encoding/payloads/ike_header.h
+++ b/programs/charon/charon/encoding/payloads/ike_header.h
diff --git a/Source/charon/encoding/payloads/ke_payload.c b/programs/charon/charon/encoding/payloads/ke_payload.c
index 0c92e033d..0c92e033d 100644
--- a/Source/charon/encoding/payloads/ke_payload.c
+++ b/programs/charon/charon/encoding/payloads/ke_payload.c
diff --git a/Source/charon/encoding/payloads/ke_payload.h b/programs/charon/charon/encoding/payloads/ke_payload.h
index 982d29754..982d29754 100644
--- a/Source/charon/encoding/payloads/ke_payload.h
+++ b/programs/charon/charon/encoding/payloads/ke_payload.h
diff --git a/Source/charon/encoding/payloads/nonce_payload.c b/programs/charon/charon/encoding/payloads/nonce_payload.c
index a7528fbfb..a7528fbfb 100644
--- a/Source/charon/encoding/payloads/nonce_payload.c
+++ b/programs/charon/charon/encoding/payloads/nonce_payload.c
diff --git a/Source/charon/encoding/payloads/nonce_payload.h b/programs/charon/charon/encoding/payloads/nonce_payload.h
index 366dfec15..366dfec15 100644
--- a/Source/charon/encoding/payloads/nonce_payload.h
+++ b/programs/charon/charon/encoding/payloads/nonce_payload.h
diff --git a/Source/charon/encoding/payloads/notify_payload.c b/programs/charon/charon/encoding/payloads/notify_payload.c
index 43d0c5322..43d0c5322 100644
--- a/Source/charon/encoding/payloads/notify_payload.c
+++ b/programs/charon/charon/encoding/payloads/notify_payload.c
diff --git a/Source/charon/encoding/payloads/notify_payload.h b/programs/charon/charon/encoding/payloads/notify_payload.h
index 093f99144..093f99144 100644
--- a/Source/charon/encoding/payloads/notify_payload.h
+++ b/programs/charon/charon/encoding/payloads/notify_payload.h
diff --git a/Source/charon/encoding/payloads/payload.c b/programs/charon/charon/encoding/payloads/payload.c
index b89e80a53..b89e80a53 100644
--- a/Source/charon/encoding/payloads/payload.c
+++ b/programs/charon/charon/encoding/payloads/payload.c
diff --git a/Source/charon/encoding/payloads/payload.h b/programs/charon/charon/encoding/payloads/payload.h
index fc3457832..fc3457832 100644
--- a/Source/charon/encoding/payloads/payload.h
+++ b/programs/charon/charon/encoding/payloads/payload.h
diff --git a/Source/charon/encoding/payloads/proposal_substructure.c b/programs/charon/charon/encoding/payloads/proposal_substructure.c
index cb3c695b2..cb3c695b2 100644
--- a/Source/charon/encoding/payloads/proposal_substructure.c
+++ b/programs/charon/charon/encoding/payloads/proposal_substructure.c
diff --git a/Source/charon/encoding/payloads/proposal_substructure.h b/programs/charon/charon/encoding/payloads/proposal_substructure.h
index 506d25800..506d25800 100644
--- a/Source/charon/encoding/payloads/proposal_substructure.h
+++ b/programs/charon/charon/encoding/payloads/proposal_substructure.h
diff --git a/Source/charon/encoding/payloads/sa_payload.c b/programs/charon/charon/encoding/payloads/sa_payload.c
index 81b4e6709..81b4e6709 100644
--- a/Source/charon/encoding/payloads/sa_payload.c
+++ b/programs/charon/charon/encoding/payloads/sa_payload.c
diff --git a/Source/charon/encoding/payloads/sa_payload.h b/programs/charon/charon/encoding/payloads/sa_payload.h
index 45095c030..45095c030 100644
--- a/Source/charon/encoding/payloads/sa_payload.h
+++ b/programs/charon/charon/encoding/payloads/sa_payload.h
diff --git a/Source/charon/encoding/payloads/traffic_selector_substructure.c b/programs/charon/charon/encoding/payloads/traffic_selector_substructure.c
index c1a461e8a..c1a461e8a 100644
--- a/Source/charon/encoding/payloads/traffic_selector_substructure.c
+++ b/programs/charon/charon/encoding/payloads/traffic_selector_substructure.c
diff --git a/Source/charon/encoding/payloads/traffic_selector_substructure.h b/programs/charon/charon/encoding/payloads/traffic_selector_substructure.h
index 755917055..755917055 100644
--- a/Source/charon/encoding/payloads/traffic_selector_substructure.h
+++ b/programs/charon/charon/encoding/payloads/traffic_selector_substructure.h
diff --git a/Source/charon/encoding/payloads/transform_attribute.c b/programs/charon/charon/encoding/payloads/transform_attribute.c
index 71cdd59e2..71cdd59e2 100644
--- a/Source/charon/encoding/payloads/transform_attribute.c
+++ b/programs/charon/charon/encoding/payloads/transform_attribute.c
diff --git a/Source/charon/encoding/payloads/transform_attribute.h b/programs/charon/charon/encoding/payloads/transform_attribute.h
index 547699915..547699915 100644
--- a/Source/charon/encoding/payloads/transform_attribute.h
+++ b/programs/charon/charon/encoding/payloads/transform_attribute.h
diff --git a/Source/charon/encoding/payloads/transform_substructure.c b/programs/charon/charon/encoding/payloads/transform_substructure.c
index 350ad63e4..350ad63e4 100644
--- a/Source/charon/encoding/payloads/transform_substructure.c
+++ b/programs/charon/charon/encoding/payloads/transform_substructure.c
diff --git a/Source/charon/encoding/payloads/transform_substructure.h b/programs/charon/charon/encoding/payloads/transform_substructure.h
index f6af3ee59..f6af3ee59 100644
--- a/Source/charon/encoding/payloads/transform_substructure.h
+++ b/programs/charon/charon/encoding/payloads/transform_substructure.h
diff --git a/Source/charon/encoding/payloads/ts_payload.c b/programs/charon/charon/encoding/payloads/ts_payload.c
index 58772e666..58772e666 100644
--- a/Source/charon/encoding/payloads/ts_payload.c
+++ b/programs/charon/charon/encoding/payloads/ts_payload.c
diff --git a/Source/charon/encoding/payloads/ts_payload.h b/programs/charon/charon/encoding/payloads/ts_payload.h
index 775ff6134..775ff6134 100644
--- a/Source/charon/encoding/payloads/ts_payload.h
+++ b/programs/charon/charon/encoding/payloads/ts_payload.h
diff --git a/Source/charon/encoding/payloads/unknown_payload.c b/programs/charon/charon/encoding/payloads/unknown_payload.c
index 25bb37d59..25bb37d59 100644
--- a/Source/charon/encoding/payloads/unknown_payload.c
+++ b/programs/charon/charon/encoding/payloads/unknown_payload.c
diff --git a/Source/charon/encoding/payloads/unknown_payload.h b/programs/charon/charon/encoding/payloads/unknown_payload.h
index 9c4926ea7..9c4926ea7 100644
--- a/Source/charon/encoding/payloads/unknown_payload.h
+++ b/programs/charon/charon/encoding/payloads/unknown_payload.h
diff --git a/Source/charon/encoding/payloads/vendor_id_payload.c b/programs/charon/charon/encoding/payloads/vendor_id_payload.c
index 436b82d79..436b82d79 100644
--- a/Source/charon/encoding/payloads/vendor_id_payload.c
+++ b/programs/charon/charon/encoding/payloads/vendor_id_payload.c
diff --git a/Source/charon/encoding/payloads/vendor_id_payload.h b/programs/charon/charon/encoding/payloads/vendor_id_payload.h
index c9ead4337..c9ead4337 100644
--- a/Source/charon/encoding/payloads/vendor_id_payload.h
+++ b/programs/charon/charon/encoding/payloads/vendor_id_payload.h
diff --git a/Source/charon/network/Makefile.network b/programs/charon/charon/network/Makefile.network
index fd99bd085..fd99bd085 100644
--- a/Source/charon/network/Makefile.network
+++ b/programs/charon/charon/network/Makefile.network
diff --git a/Source/charon/network/packet.c b/programs/charon/charon/network/packet.c
index 6cded72a3..6cded72a3 100644
--- a/Source/charon/network/packet.c
+++ b/programs/charon/charon/network/packet.c
diff --git a/Source/charon/network/packet.h b/programs/charon/charon/network/packet.h
index a2620d391..a2620d391 100644
--- a/Source/charon/network/packet.h
+++ b/programs/charon/charon/network/packet.h
diff --git a/Source/charon/network/socket.c b/programs/charon/charon/network/socket.c
index 32ff84538..32ff84538 100644
--- a/Source/charon/network/socket.c
+++ b/programs/charon/charon/network/socket.c
diff --git a/Source/charon/network/socket.h b/programs/charon/charon/network/socket.h
index 498e7700a..498e7700a 100644
--- a/Source/charon/network/socket.h
+++ b/programs/charon/charon/network/socket.h
diff --git a/Source/charon/queues/Makefile.queues b/programs/charon/charon/queues/Makefile.queues
index eeb012d2b..eeb012d2b 100644
--- a/Source/charon/queues/Makefile.queues
+++ b/programs/charon/charon/queues/Makefile.queues
diff --git a/Source/charon/queues/event_queue.c b/programs/charon/charon/queues/event_queue.c
index ece9d1513..ece9d1513 100644
--- a/Source/charon/queues/event_queue.c
+++ b/programs/charon/charon/queues/event_queue.c
diff --git a/Source/charon/queues/event_queue.h b/programs/charon/charon/queues/event_queue.h
index a60424100..a60424100 100644
--- a/Source/charon/queues/event_queue.h
+++ b/programs/charon/charon/queues/event_queue.h
diff --git a/Source/charon/queues/job_queue.c b/programs/charon/charon/queues/job_queue.c
index 3640395ab..3640395ab 100644
--- a/Source/charon/queues/job_queue.c
+++ b/programs/charon/charon/queues/job_queue.c
diff --git a/Source/charon/queues/job_queue.h b/programs/charon/charon/queues/job_queue.h
index 9fcf08001..9fcf08001 100644
--- a/Source/charon/queues/job_queue.h
+++ b/programs/charon/charon/queues/job_queue.h
diff --git a/Source/charon/queues/jobs/Makefile.jobs b/programs/charon/charon/queues/jobs/Makefile.jobs
index db89987bc..db89987bc 100644
--- a/Source/charon/queues/jobs/Makefile.jobs
+++ b/programs/charon/charon/queues/jobs/Makefile.jobs
diff --git a/Source/charon/queues/jobs/delete_established_ike_sa_job.c b/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.c
index 7251e2ca4..7251e2ca4 100644
--- a/Source/charon/queues/jobs/delete_established_ike_sa_job.c
+++ b/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.c
diff --git a/Source/charon/queues/jobs/delete_established_ike_sa_job.h b/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.h
index 762dceae6..762dceae6 100644
--- a/Source/charon/queues/jobs/delete_established_ike_sa_job.h
+++ b/programs/charon/charon/queues/jobs/delete_established_ike_sa_job.h
diff --git a/Source/charon/queues/jobs/delete_half_open_ike_sa_job.c b/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.c
index 610285e20..610285e20 100644
--- a/Source/charon/queues/jobs/delete_half_open_ike_sa_job.c
+++ b/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.c
diff --git a/Source/charon/queues/jobs/delete_half_open_ike_sa_job.h b/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.h
index ea42be8f2..ea42be8f2 100644
--- a/Source/charon/queues/jobs/delete_half_open_ike_sa_job.h
+++ b/programs/charon/charon/queues/jobs/delete_half_open_ike_sa_job.h
diff --git a/Source/charon/queues/jobs/incoming_packet_job.c b/programs/charon/charon/queues/jobs/incoming_packet_job.c
index fc71f63ea..fc71f63ea 100644
--- a/Source/charon/queues/jobs/incoming_packet_job.c
+++ b/programs/charon/charon/queues/jobs/incoming_packet_job.c
diff --git a/Source/charon/queues/jobs/incoming_packet_job.h b/programs/charon/charon/queues/jobs/incoming_packet_job.h
index e3fb5797e..e3fb5797e 100644
--- a/Source/charon/queues/jobs/incoming_packet_job.h
+++ b/programs/charon/charon/queues/jobs/incoming_packet_job.h
diff --git a/Source/charon/queues/jobs/initiate_ike_sa_job.c b/programs/charon/charon/queues/jobs/initiate_ike_sa_job.c
index ac9ace36c..ac9ace36c 100644
--- a/Source/charon/queues/jobs/initiate_ike_sa_job.c
+++ b/programs/charon/charon/queues/jobs/initiate_ike_sa_job.c
diff --git a/Source/charon/queues/jobs/initiate_ike_sa_job.h b/programs/charon/charon/queues/jobs/initiate_ike_sa_job.h
index cee31f07b..cee31f07b 100644
--- a/Source/charon/queues/jobs/initiate_ike_sa_job.h
+++ b/programs/charon/charon/queues/jobs/initiate_ike_sa_job.h
diff --git a/Source/charon/queues/jobs/job.c b/programs/charon/charon/queues/jobs/job.c
index df739f9e5..df739f9e5 100644
--- a/Source/charon/queues/jobs/job.c
+++ b/programs/charon/charon/queues/jobs/job.c
diff --git a/Source/charon/queues/jobs/job.h b/programs/charon/charon/queues/jobs/job.h
index eea4da09e..eea4da09e 100644
--- a/Source/charon/queues/jobs/job.h
+++ b/programs/charon/charon/queues/jobs/job.h
diff --git a/Source/charon/queues/jobs/retransmit_request_job.c b/programs/charon/charon/queues/jobs/retransmit_request_job.c
index e171df5bd..e171df5bd 100644
--- a/Source/charon/queues/jobs/retransmit_request_job.c
+++ b/programs/charon/charon/queues/jobs/retransmit_request_job.c
diff --git a/Source/charon/queues/jobs/retransmit_request_job.h b/programs/charon/charon/queues/jobs/retransmit_request_job.h
index 2349d3f5e..2349d3f5e 100644
--- a/Source/charon/queues/jobs/retransmit_request_job.h
+++ b/programs/charon/charon/queues/jobs/retransmit_request_job.h
diff --git a/Source/charon/queues/send_queue.c b/programs/charon/charon/queues/send_queue.c
index 0852e5303..0852e5303 100644
--- a/Source/charon/queues/send_queue.c
+++ b/programs/charon/charon/queues/send_queue.c
diff --git a/Source/charon/queues/send_queue.h b/programs/charon/charon/queues/send_queue.h
index 6dc5867eb..6dc5867eb 100644
--- a/Source/charon/queues/send_queue.h
+++ b/programs/charon/charon/queues/send_queue.h
diff --git a/Source/charon/sa/Makefile.sa b/programs/charon/charon/sa/Makefile.sa
index 825c19959..825c19959 100644
--- a/Source/charon/sa/Makefile.sa
+++ b/programs/charon/charon/sa/Makefile.sa
diff --git a/Source/charon/sa/authenticator.c b/programs/charon/charon/sa/authenticator.c
index 3aeb8795f..3aeb8795f 100644
--- a/Source/charon/sa/authenticator.c
+++ b/programs/charon/charon/sa/authenticator.c
diff --git a/Source/charon/sa/authenticator.h b/programs/charon/charon/sa/authenticator.h
index b6bc317ac..b6bc317ac 100644
--- a/Source/charon/sa/authenticator.h
+++ b/programs/charon/charon/sa/authenticator.h
diff --git a/Source/charon/sa/child_sa.c b/programs/charon/charon/sa/child_sa.c
index a678ea9b8..a678ea9b8 100644
--- a/Source/charon/sa/child_sa.c
+++ b/programs/charon/charon/sa/child_sa.c
diff --git a/Source/charon/sa/child_sa.h b/programs/charon/charon/sa/child_sa.h
index 6ccbff13f..6ccbff13f 100644
--- a/Source/charon/sa/child_sa.h
+++ b/programs/charon/charon/sa/child_sa.h
diff --git a/Source/charon/sa/ike_sa.c b/programs/charon/charon/sa/ike_sa.c
index 6322eb8e9..6322eb8e9 100644
--- a/Source/charon/sa/ike_sa.c
+++ b/programs/charon/charon/sa/ike_sa.c
diff --git a/Source/charon/sa/ike_sa.h b/programs/charon/charon/sa/ike_sa.h
index c526c6347..c526c6347 100644
--- a/Source/charon/sa/ike_sa.h
+++ b/programs/charon/charon/sa/ike_sa.h
diff --git a/Source/charon/sa/ike_sa_id.c b/programs/charon/charon/sa/ike_sa_id.c
index bf3a05d11..bf3a05d11 100644
--- a/Source/charon/sa/ike_sa_id.c
+++ b/programs/charon/charon/sa/ike_sa_id.c
diff --git a/Source/charon/sa/ike_sa_id.h b/programs/charon/charon/sa/ike_sa_id.h
index 0f16f7637..0f16f7637 100644
--- a/Source/charon/sa/ike_sa_id.h
+++ b/programs/charon/charon/sa/ike_sa_id.h
diff --git a/Source/charon/sa/ike_sa_manager.c b/programs/charon/charon/sa/ike_sa_manager.c
index 01f3f5ad2..01f3f5ad2 100644
--- a/Source/charon/sa/ike_sa_manager.c
+++ b/programs/charon/charon/sa/ike_sa_manager.c
diff --git a/Source/charon/sa/ike_sa_manager.h b/programs/charon/charon/sa/ike_sa_manager.h
index e2235b4b6..e2235b4b6 100644
--- a/Source/charon/sa/ike_sa_manager.h
+++ b/programs/charon/charon/sa/ike_sa_manager.h
diff --git a/Source/charon/sa/states/Makefile.states b/programs/charon/charon/sa/states/Makefile.states
index a258ebef0..a258ebef0 100644
--- a/Source/charon/sa/states/Makefile.states
+++ b/programs/charon/charon/sa/states/Makefile.states
diff --git a/Source/charon/sa/states/ike_auth_requested.c b/programs/charon/charon/sa/states/ike_auth_requested.c
index 3d49f440f..3d49f440f 100644
--- a/Source/charon/sa/states/ike_auth_requested.c
+++ b/programs/charon/charon/sa/states/ike_auth_requested.c
diff --git a/Source/charon/sa/states/ike_auth_requested.h b/programs/charon/charon/sa/states/ike_auth_requested.h
index a8eef014c..a8eef014c 100644
--- a/Source/charon/sa/states/ike_auth_requested.h
+++ b/programs/charon/charon/sa/states/ike_auth_requested.h
diff --git a/Source/charon/sa/states/ike_sa_established.c b/programs/charon/charon/sa/states/ike_sa_established.c
index e91409f6a..e91409f6a 100644
--- a/Source/charon/sa/states/ike_sa_established.c
+++ b/programs/charon/charon/sa/states/ike_sa_established.c
diff --git a/Source/charon/sa/states/ike_sa_established.h b/programs/charon/charon/sa/states/ike_sa_established.h
index 8477ad5bc..8477ad5bc 100644
--- a/Source/charon/sa/states/ike_sa_established.h
+++ b/programs/charon/charon/sa/states/ike_sa_established.h
diff --git a/Source/charon/sa/states/ike_sa_init_requested.c b/programs/charon/charon/sa/states/ike_sa_init_requested.c
index 311cdf0a0..311cdf0a0 100644
--- a/Source/charon/sa/states/ike_sa_init_requested.c
+++ b/programs/charon/charon/sa/states/ike_sa_init_requested.c
diff --git a/Source/charon/sa/states/ike_sa_init_requested.h b/programs/charon/charon/sa/states/ike_sa_init_requested.h
index 0a43afad1..0a43afad1 100644
--- a/Source/charon/sa/states/ike_sa_init_requested.h
+++ b/programs/charon/charon/sa/states/ike_sa_init_requested.h
diff --git a/Source/charon/sa/states/ike_sa_init_responded.c b/programs/charon/charon/sa/states/ike_sa_init_responded.c
index e40b0cf22..e40b0cf22 100644
--- a/Source/charon/sa/states/ike_sa_init_responded.c
+++ b/programs/charon/charon/sa/states/ike_sa_init_responded.c
diff --git a/Source/charon/sa/states/ike_sa_init_responded.h b/programs/charon/charon/sa/states/ike_sa_init_responded.h
index 43aecf26f..43aecf26f 100644
--- a/Source/charon/sa/states/ike_sa_init_responded.h
+++ b/programs/charon/charon/sa/states/ike_sa_init_responded.h
diff --git a/Source/charon/sa/states/initiator_init.c b/programs/charon/charon/sa/states/initiator_init.c
index 35d15235d..35d15235d 100644
--- a/Source/charon/sa/states/initiator_init.c
+++ b/programs/charon/charon/sa/states/initiator_init.c
diff --git a/Source/charon/sa/states/initiator_init.h b/programs/charon/charon/sa/states/initiator_init.h
index 6b4940a73..6b4940a73 100644
--- a/Source/charon/sa/states/initiator_init.h
+++ b/programs/charon/charon/sa/states/initiator_init.h
diff --git a/Source/charon/sa/states/responder_init.c b/programs/charon/charon/sa/states/responder_init.c
index 10acf645c..10acf645c 100644
--- a/Source/charon/sa/states/responder_init.c
+++ b/programs/charon/charon/sa/states/responder_init.c
diff --git a/Source/charon/sa/states/responder_init.h b/programs/charon/charon/sa/states/responder_init.h
index c8ba73ea3..c8ba73ea3 100644
--- a/Source/charon/sa/states/responder_init.h
+++ b/programs/charon/charon/sa/states/responder_init.h
diff --git a/Source/charon/sa/states/state.c b/programs/charon/charon/sa/states/state.c
index 595f5abbb..595f5abbb 100644
--- a/Source/charon/sa/states/state.c
+++ b/programs/charon/charon/sa/states/state.c
diff --git a/Source/charon/sa/states/state.h b/programs/charon/charon/sa/states/state.h
index c93068d35..c93068d35 100644
--- a/Source/charon/sa/states/state.h
+++ b/programs/charon/charon/sa/states/state.h
diff --git a/Source/charon/threads/Makefile.threads b/programs/charon/charon/threads/Makefile.threads
index 949c1ad24..949c1ad24 100644
--- a/Source/charon/threads/Makefile.threads
+++ b/programs/charon/charon/threads/Makefile.threads
diff --git a/Source/charon/threads/kernel_interface.c b/programs/charon/charon/threads/kernel_interface.c
index 679cf69ee..679cf69ee 100644
--- a/Source/charon/threads/kernel_interface.c
+++ b/programs/charon/charon/threads/kernel_interface.c
diff --git a/Source/charon/threads/kernel_interface.h b/programs/charon/charon/threads/kernel_interface.h
index ceafa6468..ceafa6468 100644
--- a/Source/charon/threads/kernel_interface.h
+++ b/programs/charon/charon/threads/kernel_interface.h
diff --git a/Source/charon/threads/receiver.c b/programs/charon/charon/threads/receiver.c
index 0cf8b7bde..0cf8b7bde 100644
--- a/Source/charon/threads/receiver.c
+++ b/programs/charon/charon/threads/receiver.c
diff --git a/Source/charon/threads/receiver.h b/programs/charon/charon/threads/receiver.h
index 932774f5f..932774f5f 100644
--- a/Source/charon/threads/receiver.h
+++ b/programs/charon/charon/threads/receiver.h
diff --git a/Source/charon/threads/scheduler.c b/programs/charon/charon/threads/scheduler.c
index 47c5d6fb9..47c5d6fb9 100644
--- a/Source/charon/threads/scheduler.c
+++ b/programs/charon/charon/threads/scheduler.c
diff --git a/Source/charon/threads/scheduler.h b/programs/charon/charon/threads/scheduler.h
index 0165a718b..0165a718b 100644
--- a/Source/charon/threads/scheduler.h
+++ b/programs/charon/charon/threads/scheduler.h
diff --git a/Source/charon/threads/sender.c b/programs/charon/charon/threads/sender.c
index 42d11beb9..42d11beb9 100644
--- a/Source/charon/threads/sender.c
+++ b/programs/charon/charon/threads/sender.c
diff --git a/Source/charon/threads/sender.h b/programs/charon/charon/threads/sender.h
index ea8124147..ea8124147 100644
--- a/Source/charon/threads/sender.h
+++ b/programs/charon/charon/threads/sender.h
diff --git a/Source/charon/threads/stroke_interface.c b/programs/charon/charon/threads/stroke_interface.c
index ef5d5f1f6..ef5d5f1f6 100755
--- a/Source/charon/threads/stroke_interface.c
+++ b/programs/charon/charon/threads/stroke_interface.c
diff --git a/Source/charon/threads/stroke_interface.h b/programs/charon/charon/threads/stroke_interface.h
index f8efc9c67..f8efc9c67 100644
--- a/Source/charon/threads/stroke_interface.h
+++ b/programs/charon/charon/threads/stroke_interface.h
diff --git a/Source/charon/threads/thread_pool.c b/programs/charon/charon/threads/thread_pool.c
index 4482e795f..4482e795f 100644
--- a/Source/charon/threads/thread_pool.c
+++ b/programs/charon/charon/threads/thread_pool.c
diff --git a/Source/charon/threads/thread_pool.h b/programs/charon/charon/threads/thread_pool.h
index b33be08e3..b33be08e3 100644
--- a/Source/charon/threads/thread_pool.h
+++ b/programs/charon/charon/threads/thread_pool.h
diff --git a/Source/doc/Architecture.txt b/programs/charon/doc/Architecture.txt
index 14b99274c..14b99274c 100644
--- a/Source/doc/Architecture.txt
+++ b/programs/charon/doc/Architecture.txt
diff --git a/Source/doc/Known-bugs.txt b/programs/charon/doc/Known-bugs.txt
index 3f594ad79..3f594ad79 100644
--- a/Source/doc/Known-bugs.txt
+++ b/programs/charon/doc/Known-bugs.txt
diff --git a/Source/doc/Todo-list.txt b/programs/charon/doc/Todo-list.txt
index 11b30fb7d..11b30fb7d 100644
--- a/Source/doc/Todo-list.txt
+++ b/programs/charon/doc/Todo-list.txt
diff --git a/Source/lib/Makefile.lib b/programs/charon/lib/Makefile.lib
index 80a44ff69..80a44ff69 100644
--- a/Source/lib/Makefile.lib
+++ b/programs/charon/lib/Makefile.lib
diff --git a/Source/lib/asn1/Makefile.asn1 b/programs/charon/lib/asn1/Makefile.asn1
index 3a5450d50..3a5450d50 100644
--- a/Source/lib/asn1/Makefile.asn1
+++ b/programs/charon/lib/asn1/Makefile.asn1
diff --git a/Source/lib/asn1/asn1.c b/programs/charon/lib/asn1/asn1.c
index c847461b6..c847461b6 100644
--- a/Source/lib/asn1/asn1.c
+++ b/programs/charon/lib/asn1/asn1.c
diff --git a/Source/lib/asn1/asn1.h b/programs/charon/lib/asn1/asn1.h
index 556bb2b05..556bb2b05 100644
--- a/Source/lib/asn1/asn1.h
+++ b/programs/charon/lib/asn1/asn1.h
diff --git a/Source/lib/asn1/oid.c b/programs/charon/lib/asn1/oid.c
index 4b0632de2..4b0632de2 100644
--- a/Source/lib/asn1/oid.c
+++ b/programs/charon/lib/asn1/oid.c
diff --git a/Source/lib/asn1/oid.h b/programs/charon/lib/asn1/oid.h
index a9265d43f..a9265d43f 100644
--- a/Source/lib/asn1/oid.h
+++ b/programs/charon/lib/asn1/oid.h
diff --git a/Source/lib/asn1/oid.pl b/programs/charon/lib/asn1/oid.pl
index a3725e57d..a3725e57d 100644
--- a/Source/lib/asn1/oid.pl
+++ b/programs/charon/lib/asn1/oid.pl
diff --git a/Source/lib/asn1/oid.txt b/programs/charon/lib/asn1/oid.txt
index eed46d59d..eed46d59d 100644
--- a/Source/lib/asn1/oid.txt
+++ b/programs/charon/lib/asn1/oid.txt
diff --git a/Source/lib/asn1/pem.c b/programs/charon/lib/asn1/pem.c
index b02268dd9..b02268dd9 100755
--- a/Source/lib/asn1/pem.c
+++ b/programs/charon/lib/asn1/pem.c
diff --git a/Source/lib/asn1/pem.h b/programs/charon/lib/asn1/pem.h
index a4332fd34..a4332fd34 100755
--- a/Source/lib/asn1/pem.h
+++ b/programs/charon/lib/asn1/pem.h
diff --git a/Source/lib/asn1/ttodata.c b/programs/charon/lib/asn1/ttodata.c
index 5e8149955..5e8149955 100644
--- a/Source/lib/asn1/ttodata.c
+++ b/programs/charon/lib/asn1/ttodata.c
diff --git a/Source/lib/asn1/ttodata.h b/programs/charon/lib/asn1/ttodata.h
index d57244ef5..d57244ef5 100644
--- a/Source/lib/asn1/ttodata.h
+++ b/programs/charon/lib/asn1/ttodata.h
diff --git a/Source/lib/crypto/Makefile.transforms b/programs/charon/lib/crypto/Makefile.transforms
index af0b147da..af0b147da 100644
--- a/Source/lib/crypto/Makefile.transforms
+++ b/programs/charon/lib/crypto/Makefile.transforms
diff --git a/Source/lib/crypto/crypters/Makefile.crypters b/programs/charon/lib/crypto/crypters/Makefile.crypters
index 612477de8..612477de8 100644
--- a/Source/lib/crypto/crypters/Makefile.crypters
+++ b/programs/charon/lib/crypto/crypters/Makefile.crypters
diff --git a/Source/lib/crypto/crypters/aes_cbc_crypter.c b/programs/charon/lib/crypto/crypters/aes_cbc_crypter.c
index 9b7b07c62..9b7b07c62 100644
--- a/Source/lib/crypto/crypters/aes_cbc_crypter.c
+++ b/programs/charon/lib/crypto/crypters/aes_cbc_crypter.c
diff --git a/Source/lib/crypto/crypters/aes_cbc_crypter.h b/programs/charon/lib/crypto/crypters/aes_cbc_crypter.h
index d7a3c0f5b..d7a3c0f5b 100644
--- a/Source/lib/crypto/crypters/aes_cbc_crypter.h
+++ b/programs/charon/lib/crypto/crypters/aes_cbc_crypter.h
diff --git a/Source/lib/crypto/crypters/crypter.c b/programs/charon/lib/crypto/crypters/crypter.c
index 827d10228..827d10228 100644
--- a/Source/lib/crypto/crypters/crypter.c
+++ b/programs/charon/lib/crypto/crypters/crypter.c
diff --git a/Source/lib/crypto/crypters/crypter.h b/programs/charon/lib/crypto/crypters/crypter.h
index 9c219f5cc..9c219f5cc 100644
--- a/Source/lib/crypto/crypters/crypter.h
+++ b/programs/charon/lib/crypto/crypters/crypter.h
diff --git a/Source/lib/crypto/diffie_hellman.c b/programs/charon/lib/crypto/diffie_hellman.c
index e458fb80f..e458fb80f 100644
--- a/Source/lib/crypto/diffie_hellman.c
+++ b/programs/charon/lib/crypto/diffie_hellman.c
diff --git a/Source/lib/crypto/diffie_hellman.h b/programs/charon/lib/crypto/diffie_hellman.h
index 48a165557..48a165557 100644
--- a/Source/lib/crypto/diffie_hellman.h
+++ b/programs/charon/lib/crypto/diffie_hellman.h
diff --git a/Source/lib/crypto/hashers/Makefile.hashers b/programs/charon/lib/crypto/hashers/Makefile.hashers
index e05d41af3..e05d41af3 100644
--- a/Source/lib/crypto/hashers/Makefile.hashers
+++ b/programs/charon/lib/crypto/hashers/Makefile.hashers
diff --git a/Source/lib/crypto/hashers/hasher.c b/programs/charon/lib/crypto/hashers/hasher.c
index c15f41804..c15f41804 100644
--- a/Source/lib/crypto/hashers/hasher.c
+++ b/programs/charon/lib/crypto/hashers/hasher.c
diff --git a/Source/lib/crypto/hashers/hasher.h b/programs/charon/lib/crypto/hashers/hasher.h
index 24683c01b..24683c01b 100644
--- a/Source/lib/crypto/hashers/hasher.h
+++ b/programs/charon/lib/crypto/hashers/hasher.h
diff --git a/Source/lib/crypto/hashers/md5_hasher.c b/programs/charon/lib/crypto/hashers/md5_hasher.c
index bd3ab0c62..bd3ab0c62 100644
--- a/Source/lib/crypto/hashers/md5_hasher.c
+++ b/programs/charon/lib/crypto/hashers/md5_hasher.c
diff --git a/Source/lib/crypto/hashers/md5_hasher.h b/programs/charon/lib/crypto/hashers/md5_hasher.h
index 1e6d95d19..1e6d95d19 100644
--- a/Source/lib/crypto/hashers/md5_hasher.h
+++ b/programs/charon/lib/crypto/hashers/md5_hasher.h
diff --git a/Source/lib/crypto/hashers/sha1_hasher.c b/programs/charon/lib/crypto/hashers/sha1_hasher.c
index 2b82ef4ba..2b82ef4ba 100644
--- a/Source/lib/crypto/hashers/sha1_hasher.c
+++ b/programs/charon/lib/crypto/hashers/sha1_hasher.c
diff --git a/Source/lib/crypto/hashers/sha1_hasher.h b/programs/charon/lib/crypto/hashers/sha1_hasher.h
index 5124ea1a8..5124ea1a8 100644
--- a/Source/lib/crypto/hashers/sha1_hasher.h
+++ b/programs/charon/lib/crypto/hashers/sha1_hasher.h
diff --git a/Source/lib/crypto/hmac.c b/programs/charon/lib/crypto/hmac.c
index bb8880770..bb8880770 100644
--- a/Source/lib/crypto/hmac.c
+++ b/programs/charon/lib/crypto/hmac.c
diff --git a/Source/lib/crypto/hmac.h b/programs/charon/lib/crypto/hmac.h
index 8945fc1fc..8945fc1fc 100644
--- a/Source/lib/crypto/hmac.h
+++ b/programs/charon/lib/crypto/hmac.h
diff --git a/Source/lib/crypto/prf_plus.c b/programs/charon/lib/crypto/prf_plus.c
index d408d0517..d408d0517 100644
--- a/Source/lib/crypto/prf_plus.c
+++ b/programs/charon/lib/crypto/prf_plus.c
diff --git a/Source/lib/crypto/prf_plus.h b/programs/charon/lib/crypto/prf_plus.h
index bdcd01966..bdcd01966 100644
--- a/Source/lib/crypto/prf_plus.h
+++ b/programs/charon/lib/crypto/prf_plus.h
diff --git a/Source/lib/crypto/prfs/Makefile.prfs b/programs/charon/lib/crypto/prfs/Makefile.prfs
index a98894346..a98894346 100644
--- a/Source/lib/crypto/prfs/Makefile.prfs
+++ b/programs/charon/lib/crypto/prfs/Makefile.prfs
diff --git a/Source/lib/crypto/prfs/hmac_prf.c b/programs/charon/lib/crypto/prfs/hmac_prf.c
index 2a7d34a3a..2a7d34a3a 100644
--- a/Source/lib/crypto/prfs/hmac_prf.c
+++ b/programs/charon/lib/crypto/prfs/hmac_prf.c
diff --git a/Source/lib/crypto/prfs/hmac_prf.h b/programs/charon/lib/crypto/prfs/hmac_prf.h
index 3a68960f7..3a68960f7 100644
--- a/Source/lib/crypto/prfs/hmac_prf.h
+++ b/programs/charon/lib/crypto/prfs/hmac_prf.h
diff --git a/Source/lib/crypto/prfs/prf.c b/programs/charon/lib/crypto/prfs/prf.c
index bb7015e64..bb7015e64 100644
--- a/Source/lib/crypto/prfs/prf.c
+++ b/programs/charon/lib/crypto/prfs/prf.c
diff --git a/Source/lib/crypto/prfs/prf.h b/programs/charon/lib/crypto/prfs/prf.h
index b1c1e6a66..b1c1e6a66 100644
--- a/Source/lib/crypto/prfs/prf.h
+++ b/programs/charon/lib/crypto/prfs/prf.h
diff --git a/Source/lib/crypto/rsa/Makefile.rsa b/programs/charon/lib/crypto/rsa/Makefile.rsa
index 1a0204c83..1a0204c83 100644
--- a/Source/lib/crypto/rsa/Makefile.rsa
+++ b/programs/charon/lib/crypto/rsa/Makefile.rsa
diff --git a/Source/lib/crypto/rsa/rsa_private_key.c b/programs/charon/lib/crypto/rsa/rsa_private_key.c
index 358653f0e..358653f0e 100644
--- a/Source/lib/crypto/rsa/rsa_private_key.c
+++ b/programs/charon/lib/crypto/rsa/rsa_private_key.c
diff --git a/Source/lib/crypto/rsa/rsa_private_key.h b/programs/charon/lib/crypto/rsa/rsa_private_key.h
index b3b8ae87f..b3b8ae87f 100644
--- a/Source/lib/crypto/rsa/rsa_private_key.h
+++ b/programs/charon/lib/crypto/rsa/rsa_private_key.h
diff --git a/Source/lib/crypto/rsa/rsa_public_key.c b/programs/charon/lib/crypto/rsa/rsa_public_key.c
index 6601b6cda..6601b6cda 100644
--- a/Source/lib/crypto/rsa/rsa_public_key.c
+++ b/programs/charon/lib/crypto/rsa/rsa_public_key.c
diff --git a/Source/lib/crypto/rsa/rsa_public_key.h b/programs/charon/lib/crypto/rsa/rsa_public_key.h
index ef79153d6..ef79153d6 100644
--- a/Source/lib/crypto/rsa/rsa_public_key.h
+++ b/programs/charon/lib/crypto/rsa/rsa_public_key.h
diff --git a/Source/lib/crypto/signers/Makefile.signers b/programs/charon/lib/crypto/signers/Makefile.signers
index 8f161a09d..8f161a09d 100644
--- a/Source/lib/crypto/signers/Makefile.signers
+++ b/programs/charon/lib/crypto/signers/Makefile.signers
diff --git a/Source/lib/crypto/signers/hmac_signer.c b/programs/charon/lib/crypto/signers/hmac_signer.c
index cb7d08244..cb7d08244 100644
--- a/Source/lib/crypto/signers/hmac_signer.c
+++ b/programs/charon/lib/crypto/signers/hmac_signer.c
diff --git a/Source/lib/crypto/signers/hmac_signer.h b/programs/charon/lib/crypto/signers/hmac_signer.h
index 62427167e..62427167e 100644
--- a/Source/lib/crypto/signers/hmac_signer.h
+++ b/programs/charon/lib/crypto/signers/hmac_signer.h
diff --git a/Source/lib/crypto/signers/signer.c b/programs/charon/lib/crypto/signers/signer.c
index 3e6378957..3e6378957 100644
--- a/Source/lib/crypto/signers/signer.c
+++ b/programs/charon/lib/crypto/signers/signer.c
diff --git a/Source/lib/crypto/signers/signer.h b/programs/charon/lib/crypto/signers/signer.h
index 9625af813..9625af813 100644
--- a/Source/lib/crypto/signers/signer.h
+++ b/programs/charon/lib/crypto/signers/signer.h
diff --git a/Source/lib/crypto/x509.c b/programs/charon/lib/crypto/x509.c
index 86a595618..86a595618 100755
--- a/Source/lib/crypto/x509.c
+++ b/programs/charon/lib/crypto/x509.c
diff --git a/Source/lib/crypto/x509.h b/programs/charon/lib/crypto/x509.h
index 077238eab..077238eab 100755
--- a/Source/lib/crypto/x509.h
+++ b/programs/charon/lib/crypto/x509.h
diff --git a/Source/lib/definitions.c b/programs/charon/lib/definitions.c
index 59c97a29b..59c97a29b 100644
--- a/Source/lib/definitions.c
+++ b/programs/charon/lib/definitions.c
diff --git a/Source/lib/definitions.h b/programs/charon/lib/definitions.h
index c9ef066c1..c9ef066c1 100644
--- a/Source/lib/definitions.h
+++ b/programs/charon/lib/definitions.h
diff --git a/Source/lib/library.c b/programs/charon/lib/library.c
index fa9c732bf..fa9c732bf 100644
--- a/Source/lib/library.c
+++ b/programs/charon/lib/library.c
diff --git a/Source/lib/library.h b/programs/charon/lib/library.h
index da96befe1..da96befe1 100644
--- a/Source/lib/library.h
+++ b/programs/charon/lib/library.h
diff --git a/Source/lib/types.c b/programs/charon/lib/types.c
index 09ebf7310..09ebf7310 100644
--- a/Source/lib/types.c
+++ b/programs/charon/lib/types.c
diff --git a/Source/lib/types.h b/programs/charon/lib/types.h
index 0e0782b31..0e0782b31 100644
--- a/Source/lib/types.h
+++ b/programs/charon/lib/types.h
diff --git a/Source/lib/utils/Makefile.utils b/programs/charon/lib/utils/Makefile.utils
index 1c82283d7..1c82283d7 100644
--- a/Source/lib/utils/Makefile.utils
+++ b/programs/charon/lib/utils/Makefile.utils
diff --git a/Source/lib/utils/host.c b/programs/charon/lib/utils/host.c
index 020ed27f3..020ed27f3 100644
--- a/Source/lib/utils/host.c
+++ b/programs/charon/lib/utils/host.c
diff --git a/Source/lib/utils/host.h b/programs/charon/lib/utils/host.h
index d81efffa6..d81efffa6 100644
--- a/Source/lib/utils/host.h
+++ b/programs/charon/lib/utils/host.h
diff --git a/Source/lib/utils/identification.c b/programs/charon/lib/utils/identification.c
index 33f3d92cd..33f3d92cd 100644
--- a/Source/lib/utils/identification.c
+++ b/programs/charon/lib/utils/identification.c
diff --git a/Source/lib/utils/identification.h b/programs/charon/lib/utils/identification.h
index 309b6858c..309b6858c 100644
--- a/Source/lib/utils/identification.h
+++ b/programs/charon/lib/utils/identification.h
diff --git a/Source/lib/utils/iterator.h b/programs/charon/lib/utils/iterator.h
index de81db8e9..de81db8e9 100644
--- a/Source/lib/utils/iterator.h
+++ b/programs/charon/lib/utils/iterator.h
diff --git a/Source/lib/utils/leak_detective.c b/programs/charon/lib/utils/leak_detective.c
index 780ba4c05..780ba4c05 100644
--- a/Source/lib/utils/leak_detective.c
+++ b/programs/charon/lib/utils/leak_detective.c
diff --git a/Source/lib/utils/leak_detective.h b/programs/charon/lib/utils/leak_detective.h
index 13c0d01ab..13c0d01ab 100644
--- a/Source/lib/utils/leak_detective.h
+++ b/programs/charon/lib/utils/leak_detective.h
diff --git a/Source/lib/utils/linked_list.c b/programs/charon/lib/utils/linked_list.c
index 64443434b..64443434b 100644
--- a/Source/lib/utils/linked_list.c
+++ b/programs/charon/lib/utils/linked_list.c
diff --git a/Source/lib/utils/linked_list.h b/programs/charon/lib/utils/linked_list.h
index 8647f064d..8647f064d 100644
--- a/Source/lib/utils/linked_list.h
+++ b/programs/charon/lib/utils/linked_list.h
diff --git a/Source/lib/utils/logger.c b/programs/charon/lib/utils/logger.c
index fdaeddff0..fdaeddff0 100644
--- a/Source/lib/utils/logger.c
+++ b/programs/charon/lib/utils/logger.c
diff --git a/Source/lib/utils/logger.h b/programs/charon/lib/utils/logger.h
index dec73078e..dec73078e 100644
--- a/Source/lib/utils/logger.h
+++ b/programs/charon/lib/utils/logger.h
diff --git a/Source/lib/utils/logger_manager.c b/programs/charon/lib/utils/logger_manager.c
index ecbe1a6c1..ecbe1a6c1 100644
--- a/Source/lib/utils/logger_manager.c
+++ b/programs/charon/lib/utils/logger_manager.c
diff --git a/Source/lib/utils/logger_manager.h b/programs/charon/lib/utils/logger_manager.h
index a3ff5a37e..a3ff5a37e 100644
--- a/Source/lib/utils/logger_manager.h
+++ b/programs/charon/lib/utils/logger_manager.h
diff --git a/Source/lib/utils/randomizer.c b/programs/charon/lib/utils/randomizer.c
index 09e81894e..09e81894e 100644
--- a/Source/lib/utils/randomizer.c
+++ b/programs/charon/lib/utils/randomizer.c
diff --git a/Source/lib/utils/randomizer.h b/programs/charon/lib/utils/randomizer.h
index 55519550e..55519550e 100644
--- a/Source/lib/utils/randomizer.h
+++ b/programs/charon/lib/utils/randomizer.h
diff --git a/Source/lib/utils/tester.c b/programs/charon/lib/utils/tester.c
index a7599dd82..a7599dd82 100644
--- a/Source/lib/utils/tester.c
+++ b/programs/charon/lib/utils/tester.c
diff --git a/Source/lib/utils/tester.h b/programs/charon/lib/utils/tester.h
index 3decb2039..3decb2039 100644
--- a/Source/lib/utils/tester.h
+++ b/programs/charon/lib/utils/tester.h
diff --git a/Source/patches/strongswan-2.7.0.patch b/programs/charon/patches/strongswan-2.7.0.patch
index b21e1013b..b21e1013b 100644
--- a/Source/patches/strongswan-2.7.0.patch
+++ b/programs/charon/patches/strongswan-2.7.0.patch
diff --git a/Source/scripts/alice-key.der b/programs/charon/scripts/alice-key.der
index 5a8aef6cb..5a8aef6cb 100644
--- a/Source/scripts/alice-key.der
+++ b/programs/charon/scripts/alice-key.der
Binary files differ
diff --git a/Source/scripts/alice.der b/programs/charon/scripts/alice.der
index 8154defd9..8154defd9 100644
--- a/Source/scripts/alice.der
+++ b/programs/charon/scripts/alice.der
Binary files differ
diff --git a/Source/scripts/bob-key.der b/programs/charon/scripts/bob-key.der
index f944dec9f..f944dec9f 100644
--- a/Source/scripts/bob-key.der
+++ b/programs/charon/scripts/bob-key.der
Binary files differ
diff --git a/Source/scripts/bob.der b/programs/charon/scripts/bob.der
index 401611888..401611888 100644
--- a/Source/scripts/bob.der
+++ b/programs/charon/scripts/bob.der
Binary files differ
diff --git a/Source/scripts/complex1.der b/programs/charon/scripts/complex1.der
index ba460cbee..ba460cbee 100644
--- a/Source/scripts/complex1.der
+++ b/programs/charon/scripts/complex1.der
Binary files differ
diff --git a/Source/scripts/complex2.der b/programs/charon/scripts/complex2.der
index 160b21f47..160b21f47 100644
--- a/Source/scripts/complex2.der
+++ b/programs/charon/scripts/complex2.der
Binary files differ
diff --git a/Source/scripts/daemon-loop.sh b/programs/charon/scripts/daemon-loop.sh
index 9a361e012..9a361e012 100755
--- a/Source/scripts/daemon-loop.sh
+++ b/programs/charon/scripts/daemon-loop.sh
diff --git a/Source/scripts/deleteline b/programs/charon/scripts/deleteline
index 9f529dccc..9f529dccc 100755
--- a/Source/scripts/deleteline
+++ b/programs/charon/scripts/deleteline
diff --git a/Source/scripts/replace b/programs/charon/scripts/replace
index adfc8e09a..adfc8e09a 100755
--- a/Source/scripts/replace
+++ b/programs/charon/scripts/replace
diff --git a/Source/scripts/to-alice.sh b/programs/charon/scripts/to-alice.sh
index 01ba27f5b..01ba27f5b 100755
--- a/Source/scripts/to-alice.sh
+++ b/programs/charon/scripts/to-alice.sh
diff --git a/Source/scripts/to-bob.sh b/programs/charon/scripts/to-bob.sh
index df30bd893..df30bd893 100755
--- a/Source/scripts/to-bob.sh
+++ b/programs/charon/scripts/to-bob.sh
diff --git a/Source/stroke/Makefile.stroke b/programs/charon/stroke/Makefile.stroke
index c87445095..c87445095 100644
--- a/Source/stroke/Makefile.stroke
+++ b/programs/charon/stroke/Makefile.stroke
diff --git a/Source/stroke/stroke.c b/programs/charon/stroke/stroke.c
index 9ecda0413..9ecda0413 100644
--- a/Source/stroke/stroke.c
+++ b/programs/charon/stroke/stroke.c
diff --git a/Source/stroke/stroke.h b/programs/charon/stroke/stroke.h
index cb40cf843..cb40cf843 100644
--- a/Source/stroke/stroke.h
+++ b/programs/charon/stroke/stroke.h
diff --git a/Source/testing/Makefile.testcases b/programs/charon/testing/Makefile.testcases
index 5a261a799..5a261a799 100644
--- a/Source/testing/Makefile.testcases
+++ b/programs/charon/testing/Makefile.testcases
diff --git a/Source/testing/aes_cbc_crypter_test.c b/programs/charon/testing/aes_cbc_crypter_test.c
index 30dae3926..30dae3926 100644
--- a/Source/testing/aes_cbc_crypter_test.c
+++ b/programs/charon/testing/aes_cbc_crypter_test.c
diff --git a/Source/testing/aes_cbc_crypter_test.h b/programs/charon/testing/aes_cbc_crypter_test.h
index c3897a4d6..c3897a4d6 100644
--- a/Source/testing/aes_cbc_crypter_test.h
+++ b/programs/charon/testing/aes_cbc_crypter_test.h
diff --git a/Source/testing/certificate_test.c b/programs/charon/testing/certificate_test.c
index be8a8f7cf..be8a8f7cf 100644
--- a/Source/testing/certificate_test.c
+++ b/programs/charon/testing/certificate_test.c
diff --git a/Source/testing/certificate_test.h b/programs/charon/testing/certificate_test.h
index 8dcbd0f93..8dcbd0f93 100644
--- a/Source/testing/certificate_test.h
+++ b/programs/charon/testing/certificate_test.h
diff --git a/Source/testing/child_sa_test.c b/programs/charon/testing/child_sa_test.c
index 0cf354c26..0cf354c26 100644
--- a/Source/testing/child_sa_test.c
+++ b/programs/charon/testing/child_sa_test.c
diff --git a/Source/testing/child_sa_test.h b/programs/charon/testing/child_sa_test.h
index ef92499fe..ef92499fe 100644
--- a/Source/testing/child_sa_test.h
+++ b/programs/charon/testing/child_sa_test.h
diff --git a/Source/testing/connection_test.c b/programs/charon/testing/connection_test.c
index 6b12afc1d..6b12afc1d 100644
--- a/Source/testing/connection_test.c
+++ b/programs/charon/testing/connection_test.c
diff --git a/Source/testing/connection_test.h b/programs/charon/testing/connection_test.h
index 4d2a1d89e..4d2a1d89e 100644
--- a/Source/testing/connection_test.h
+++ b/programs/charon/testing/connection_test.h
diff --git a/Source/testing/diffie_hellman_test.c b/programs/charon/testing/diffie_hellman_test.c
index 0a44a022a..0a44a022a 100644
--- a/Source/testing/diffie_hellman_test.c
+++ b/programs/charon/testing/diffie_hellman_test.c
diff --git a/Source/testing/diffie_hellman_test.h b/programs/charon/testing/diffie_hellman_test.h
index e6e3ff608..e6e3ff608 100644
--- a/Source/testing/diffie_hellman_test.h
+++ b/programs/charon/testing/diffie_hellman_test.h
diff --git a/Source/testing/encryption_payload_test.c b/programs/charon/testing/encryption_payload_test.c
index 9e4108b9e..9e4108b9e 100644
--- a/Source/testing/encryption_payload_test.c
+++ b/programs/charon/testing/encryption_payload_test.c
diff --git a/Source/testing/encryption_payload_test.h b/programs/charon/testing/encryption_payload_test.h
index 5e6353bfd..5e6353bfd 100644
--- a/Source/testing/encryption_payload_test.h
+++ b/programs/charon/testing/encryption_payload_test.h
diff --git a/Source/testing/event_queue_test.c b/programs/charon/testing/event_queue_test.c
index 58a214051..58a214051 100644
--- a/Source/testing/event_queue_test.c
+++ b/programs/charon/testing/event_queue_test.c
diff --git a/Source/testing/event_queue_test.h b/programs/charon/testing/event_queue_test.h
index 5f8c47fad..5f8c47fad 100644
--- a/Source/testing/event_queue_test.h
+++ b/programs/charon/testing/event_queue_test.h
diff --git a/Source/testing/generator_test.c b/programs/charon/testing/generator_test.c
index 004c700e6..004c700e6 100644
--- a/Source/testing/generator_test.c
+++ b/programs/charon/testing/generator_test.c
diff --git a/Source/testing/generator_test.h b/programs/charon/testing/generator_test.h
index 204255fb7..204255fb7 100644
--- a/Source/testing/generator_test.h
+++ b/programs/charon/testing/generator_test.h
diff --git a/Source/testing/hasher_test.c b/programs/charon/testing/hasher_test.c
index 9130a2092..9130a2092 100644
--- a/Source/testing/hasher_test.c
+++ b/programs/charon/testing/hasher_test.c
diff --git a/Source/testing/hasher_test.h b/programs/charon/testing/hasher_test.h
index cc6fe52c8..cc6fe52c8 100644
--- a/Source/testing/hasher_test.h
+++ b/programs/charon/testing/hasher_test.h
diff --git a/Source/testing/hmac_signer_test.c b/programs/charon/testing/hmac_signer_test.c
index a1ac8ea43..a1ac8ea43 100644
--- a/Source/testing/hmac_signer_test.c
+++ b/programs/charon/testing/hmac_signer_test.c
diff --git a/Source/testing/hmac_signer_test.h b/programs/charon/testing/hmac_signer_test.h
index 4a2459a8e..4a2459a8e 100644
--- a/Source/testing/hmac_signer_test.h
+++ b/programs/charon/testing/hmac_signer_test.h
diff --git a/Source/testing/hmac_test.c b/programs/charon/testing/hmac_test.c
index c1341257c..c1341257c 100644
--- a/Source/testing/hmac_test.c
+++ b/programs/charon/testing/hmac_test.c
diff --git a/Source/testing/hmac_test.h b/programs/charon/testing/hmac_test.h
index 1eef93cd3..1eef93cd3 100644
--- a/Source/testing/hmac_test.h
+++ b/programs/charon/testing/hmac_test.h
diff --git a/Source/testing/identification_test.c b/programs/charon/testing/identification_test.c
index b148b53e0..b148b53e0 100644
--- a/Source/testing/identification_test.c
+++ b/programs/charon/testing/identification_test.c
diff --git a/Source/testing/identification_test.h b/programs/charon/testing/identification_test.h
index b1078c52f..b1078c52f 100644
--- a/Source/testing/identification_test.h
+++ b/programs/charon/testing/identification_test.h
diff --git a/Source/testing/ike_sa_id_test.c b/programs/charon/testing/ike_sa_id_test.c
index ba44363fb..ba44363fb 100644
--- a/Source/testing/ike_sa_id_test.c
+++ b/programs/charon/testing/ike_sa_id_test.c
diff --git a/Source/testing/ike_sa_id_test.h b/programs/charon/testing/ike_sa_id_test.h
index 75429e4fb..75429e4fb 100644
--- a/Source/testing/ike_sa_id_test.h
+++ b/programs/charon/testing/ike_sa_id_test.h
diff --git a/Source/testing/ike_sa_manager_test.c b/programs/charon/testing/ike_sa_manager_test.c
index 5247be7f0..5247be7f0 100644
--- a/Source/testing/ike_sa_manager_test.c
+++ b/programs/charon/testing/ike_sa_manager_test.c
diff --git a/Source/testing/ike_sa_manager_test.h b/programs/charon/testing/ike_sa_manager_test.h
index c3e9f99f1..c3e9f99f1 100644
--- a/Source/testing/ike_sa_manager_test.h
+++ b/programs/charon/testing/ike_sa_manager_test.h
diff --git a/Source/testing/ike_sa_test.c b/programs/charon/testing/ike_sa_test.c
index 798b5edc9..798b5edc9 100644
--- a/Source/testing/ike_sa_test.c
+++ b/programs/charon/testing/ike_sa_test.c
diff --git a/Source/testing/ike_sa_test.h b/programs/charon/testing/ike_sa_test.h
index e93bc34fd..e93bc34fd 100644
--- a/Source/testing/ike_sa_test.h
+++ b/programs/charon/testing/ike_sa_test.h
diff --git a/Source/testing/job_queue_test.c b/programs/charon/testing/job_queue_test.c
index 336a9a188..336a9a188 100644
--- a/Source/testing/job_queue_test.c
+++ b/programs/charon/testing/job_queue_test.c
diff --git a/Source/testing/job_queue_test.h b/programs/charon/testing/job_queue_test.h
index f2d3edc4c..f2d3edc4c 100644
--- a/Source/testing/job_queue_test.h
+++ b/programs/charon/testing/job_queue_test.h
diff --git a/Source/testing/kernel_interface_test.c b/programs/charon/testing/kernel_interface_test.c
index 86553e15e..86553e15e 100644
--- a/Source/testing/kernel_interface_test.c
+++ b/programs/charon/testing/kernel_interface_test.c
diff --git a/Source/testing/kernel_interface_test.h b/programs/charon/testing/kernel_interface_test.h
index fc8dab4b6..fc8dab4b6 100644
--- a/Source/testing/kernel_interface_test.h
+++ b/programs/charon/testing/kernel_interface_test.h
diff --git a/Source/testing/leak_detective_test.c b/programs/charon/testing/leak_detective_test.c
index 8d71d9f0f..8d71d9f0f 100644
--- a/Source/testing/leak_detective_test.c
+++ b/programs/charon/testing/leak_detective_test.c
diff --git a/Source/testing/leak_detective_test.h b/programs/charon/testing/leak_detective_test.h
index e64266bd5..e64266bd5 100644
--- a/Source/testing/leak_detective_test.h
+++ b/programs/charon/testing/leak_detective_test.h
diff --git a/Source/testing/linked_list_test.c b/programs/charon/testing/linked_list_test.c
index 3d5666f64..3d5666f64 100644
--- a/Source/testing/linked_list_test.c
+++ b/programs/charon/testing/linked_list_test.c
diff --git a/Source/testing/linked_list_test.h b/programs/charon/testing/linked_list_test.h
index a9773f8f0..a9773f8f0 100644
--- a/Source/testing/linked_list_test.h
+++ b/programs/charon/testing/linked_list_test.h
diff --git a/Source/testing/packet_test.c b/programs/charon/testing/packet_test.c
index fdb195ec1..fdb195ec1 100644
--- a/Source/testing/packet_test.c
+++ b/programs/charon/testing/packet_test.c
diff --git a/Source/testing/packet_test.h b/programs/charon/testing/packet_test.h
index 8bc297e1b..8bc297e1b 100644
--- a/Source/testing/packet_test.h
+++ b/programs/charon/testing/packet_test.h
diff --git a/Source/testing/parser_test.c b/programs/charon/testing/parser_test.c
index 263c6eb70..263c6eb70 100644
--- a/Source/testing/parser_test.c
+++ b/programs/charon/testing/parser_test.c
diff --git a/Source/testing/parser_test.h b/programs/charon/testing/parser_test.h
index 4956df13e..4956df13e 100644
--- a/Source/testing/parser_test.h
+++ b/programs/charon/testing/parser_test.h
diff --git a/Source/testing/policy_test.c b/programs/charon/testing/policy_test.c
index 9003eeff0..9003eeff0 100644
--- a/Source/testing/policy_test.c
+++ b/programs/charon/testing/policy_test.c
diff --git a/Source/testing/policy_test.h b/programs/charon/testing/policy_test.h
index 6c8072a9c..6c8072a9c 100644
--- a/Source/testing/policy_test.h
+++ b/programs/charon/testing/policy_test.h
diff --git a/Source/testing/prf_plus_test.c b/programs/charon/testing/prf_plus_test.c
index 818c5c17e..818c5c17e 100644
--- a/Source/testing/prf_plus_test.c
+++ b/programs/charon/testing/prf_plus_test.c
diff --git a/Source/testing/prf_plus_test.h b/programs/charon/testing/prf_plus_test.h
index 2ad8ce0c1..2ad8ce0c1 100644
--- a/Source/testing/prf_plus_test.h
+++ b/programs/charon/testing/prf_plus_test.h
diff --git a/Source/testing/proposal_test.c b/programs/charon/testing/proposal_test.c
index 1b16390d3..1b16390d3 100644
--- a/Source/testing/proposal_test.c
+++ b/programs/charon/testing/proposal_test.c
diff --git a/Source/testing/proposal_test.h b/programs/charon/testing/proposal_test.h
index 059af11cc..059af11cc 100644
--- a/Source/testing/proposal_test.h
+++ b/programs/charon/testing/proposal_test.h
diff --git a/Source/testing/rsa_test.c b/programs/charon/testing/rsa_test.c
index 696901531..696901531 100644
--- a/Source/testing/rsa_test.c
+++ b/programs/charon/testing/rsa_test.c
diff --git a/Source/testing/rsa_test.h b/programs/charon/testing/rsa_test.h
index baeccf402..baeccf402 100644
--- a/Source/testing/rsa_test.h
+++ b/programs/charon/testing/rsa_test.h
diff --git a/Source/testing/scheduler_test.c b/programs/charon/testing/scheduler_test.c
index de7346d83..de7346d83 100644
--- a/Source/testing/scheduler_test.c
+++ b/programs/charon/testing/scheduler_test.c
diff --git a/Source/testing/scheduler_test.h b/programs/charon/testing/scheduler_test.h
index 746848e49..746848e49 100644
--- a/Source/testing/scheduler_test.h
+++ b/programs/charon/testing/scheduler_test.h
diff --git a/Source/testing/send_queue_test.c b/programs/charon/testing/send_queue_test.c
index a56f8e5a2..a56f8e5a2 100644
--- a/Source/testing/send_queue_test.c
+++ b/programs/charon/testing/send_queue_test.c
diff --git a/Source/testing/send_queue_test.h b/programs/charon/testing/send_queue_test.h
index 138657e10..138657e10 100644
--- a/Source/testing/send_queue_test.h
+++ b/programs/charon/testing/send_queue_test.h
diff --git a/Source/testing/sender_test.c b/programs/charon/testing/sender_test.c
index 391d71fbc..391d71fbc 100644
--- a/Source/testing/sender_test.c
+++ b/programs/charon/testing/sender_test.c
diff --git a/Source/testing/sender_test.h b/programs/charon/testing/sender_test.h
index 1fdfed69d..1fdfed69d 100644
--- a/Source/testing/sender_test.h
+++ b/programs/charon/testing/sender_test.h
diff --git a/Source/testing/socket_test.c b/programs/charon/testing/socket_test.c
index 9ae1b0fbc..9ae1b0fbc 100644
--- a/Source/testing/socket_test.c
+++ b/programs/charon/testing/socket_test.c
diff --git a/Source/testing/socket_test.h b/programs/charon/testing/socket_test.h
index a59995297..a59995297 100644
--- a/Source/testing/socket_test.h
+++ b/programs/charon/testing/socket_test.h
diff --git a/Source/testing/testcases.c b/programs/charon/testing/testcases.c
index e4d92becf..e4d92becf 100644
--- a/Source/testing/testcases.c
+++ b/programs/charon/testing/testcases.c
diff --git a/Source/testing/thread_pool_test.c b/programs/charon/testing/thread_pool_test.c
index ee7a5101f..ee7a5101f 100644
--- a/Source/testing/thread_pool_test.c
+++ b/programs/charon/testing/thread_pool_test.c
diff --git a/Source/testing/thread_pool_test.h b/programs/charon/testing/thread_pool_test.h
index bdae797b7..bdae797b7 100644
--- a/Source/testing/thread_pool_test.h
+++ b/programs/charon/testing/thread_pool_test.h
diff --git a/programs/eroute/.cvsignore b/programs/eroute/.cvsignore
new file mode 100644
index 000000000..133c4b456
--- /dev/null
+++ b/programs/eroute/.cvsignore
@@ -0,0 +1 @@
+eroute
diff --git a/programs/eroute/Makefile b/programs/eroute/Makefile
new file mode 100644
index 000000000..6d8f68033
--- /dev/null
+++ b/programs/eroute/Makefile
@@ -0,0 +1,52 @@
+# Makefile for the KLIPS interface utilities
+# Copyright (C) 1998, 1999 Henry Spencer.
+# Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM:=eroute
+EXTRA5PROC=eroute.5
+
+LIBS:=${FREESWANLIB}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.4 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 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.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/eroute/eroute.5 b/programs/eroute/eroute.5
new file mode 100644
index 000000000..52b3f4d25
--- /dev/null
+++ b/programs/eroute/eroute.5
@@ -0,0 +1,272 @@
+.TH IPSEC_EROUTE 5 "20 Sep 2001"
+.\"
+.\" RCSID $Id: eroute.5,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec_eroute \- list of existing eroutes
+.SH SYNOPSIS
+.B ipsec
+.B eroute
+.PP
+.B cat
+.B /proc/net/ipsec_eroute
+.SH DESCRIPTION
+.I /proc/net/ipsec_eroute
+lists the IPSEC extended routing tables,
+which control what (if any) processing is applied
+to non-encrypted packets arriving for IPSEC processing and forwarding.
+At this point it is a read-only file.
+.PP
+A table entry consists of:
+.IP + 3
+packet count,
+.IP +
+source address with mask and source port (0 if all ports or not applicable)
+.IP +
+a '->' separator for visual and automated parsing between src and dst
+.IP +
+destination address with mask and destination port (0 if all ports or
+not applicable)
+.IP +
+a '=>' separator for visual and automated parsing between selection
+criteria and SAID to use
+.IP +
+SAID (Security Association IDentifier), comprised of:
+.IP + 6
+protocol
+(\fIproto\fR),
+.IP +
+address family
+(\fIaf\fR),
+where '.' stands for IPv4 and ':' for IPv6
+.IP +
+Security Parameters Index
+(\fISPI\fR),
+.IP +
+effective destination
+(\fIedst\fR),
+where the packet should be forwarded after processing
+(normally the other security gateway)
+together indicate which Security Association should be used to process
+the packet,
+.IP + 3
+a ':' separating the SAID from the transport protocol (0 if all protocols)
+.IP +
+source identity text string with no whitespace, in parens,
+.IP +
+destination identity text string with no whitespace, in parens
+.PP
+Addresses are written as IPv4 dotted quads or IPv6 coloned hex,
+protocol is one of "ah", "esp", "comp" or "tun"
+and
+SPIs are prefixed hexadecimal numbers where the prefix '.' is for IPv4 and the prefix ':' is for IPv6
+.
+.PP
+SAIDs are written as "protoafSPI@edst". There are also 5
+"magic" SAIDs which have special meaning:
+.IP + 3
+.B %drop
+means that matches are to be dropped
+.IP +
+.B %reject
+means that matches are to be dropped and an ICMP returned, if
+possible to inform
+.IP +
+.B %trap
+means that matches are to trigger an ACQUIRE message to the Key
+Management daemon(s) and a hold eroute will be put in place to
+prevent subsequent packets also triggering ACQUIRE messages.
+.IP +
+.B %hold
+means that matches are to stored until the eroute is replaced or
+until that eroute gets reaped
+.IP +
+.B %pass
+means that matches are to allowed to pass without IPSEC processing
+.br
+.ne 5
+.SH EXAMPLES
+.LP
+.B "1867 172.31.252.0/24:0 -> 0.0.0.0/0:0 => tun0x130@192.168.43.1:0 "
+.br
+.B " () ()"
+.LP
+means that 1,867 packets have been sent to an
+.BR eroute
+that has been set up to protect traffic between the subnet
+.BR 172.31.252.0
+with a subnet mask of
+.BR 24
+bits and the default address/mask represented by an address of
+.BR 0.0.0.0
+with a subnet mask of
+.BR 0
+bits using the local machine as a security gateway on this end of the
+tunnel and the machine
+.BR 192.168.43.1
+on the other end of the tunnel with a Security Association IDentifier of
+.BR tun0x130@192.168.43.1
+which means that it is a tunnel mode connection (4, IPPROTO_IPIP) with a
+Security Parameters Index of
+.BR 130
+in hexadecimal with no identies defined for either end.
+.LP
+.B "746 192.168.2.110/32:0 -> 192.168.2.120/32:25 => esp0x130@192.168.2.120:6 "
+.br
+.B " () ()"
+.LP
+means that 746 packets have been sent to an
+.BR eroute
+that has been set up to protect traffic sent from any port on the host
+.BR 192.168.2.110
+to the SMTP (TCP, port 25) port on the host
+.BR 192.168.2.120
+with a Security Association IDentifier of
+.BR tun0x130@192.168.2.120
+which means that it is a transport mode connection with a
+Security Parameters Index of
+.BR 130
+in hexadecimal with no identies defined for either end.
+.LP
+.B 125 3049:1::/64 -> 0:0/0 => tun:130@3058:4::5 () ()
+.LP
+means that 125 packets have been sent to an
+.BR eroute
+that has been set up to protect traffic between the subnet
+.BR 3049:1::
+with a subnet mask of
+.BR 64
+bits and the default address/mask represented by an address of
+.BR 0:0
+with a subnet mask of
+.BR 0
+bits using the local machine as a security gateway on this end of the
+tunnel and the machine
+.BR 3058:4::5
+on the other end of the tunnel with a Security Association IDentifier of
+.BR tun:130@3058:4::5
+which means that it is a tunnel mode connection with a
+Security Parameters Index of
+.BR 130
+in hexadecimal with no identies defined for either end.
+.LP
+.B 42 192.168.6.0/24:0 -> 192.168.7.0/24:0 => %passthrough
+.LP
+means that 42 packets have been sent to an
+.BR eroute
+that has been set up to pass the traffic from the subnet
+.BR 192.168.6.0
+with a subnet mask of
+.BR 24
+bits and to subnet
+.BR 192.168.7.0
+with a subnet mask of
+.BR 24
+bits without any IPSEC processing with no identies defined for either end.
+.LP
+.B 2112 192.168.8.55/32:0 -> 192.168.9.47/24:0 => %hold (east) ()
+.LP
+means that 2112 packets have been sent to an
+.BR eroute
+that has been set up to hold the traffic from the host
+.BR 192.168.8.55
+and to host
+.BR 192.168.9.47
+until a key exchange from a Key Management daemon
+succeeds and puts in an SA or fails and puts in a pass
+or drop eroute depending on the default configuration with the local client
+defined as "east" and no identy defined for the remote end.
+.LP
+.B "2001 192.168.2.110/32:0 -> 192.168.2.120/32:0 => "
+.br
+.B " esp0xe6de@192.168.2.120:0 () ()"
+.LP
+means that 2001 packets have been sent to an
+.BR eroute
+that has been set up to protect traffic between the host
+.BR 192.168.2.110
+and the host
+.BR 192.168.2.120
+using
+.BR 192.168.2.110
+as a security gateway on this end of the
+connection and the machine
+.BR 192.168.2.120
+on the other end of the connection with a Security Association IDentifier of
+.BR esp0xe6de@192.168.2.120
+which means that it is a transport mode connection with a Security
+Parameters Index of
+.BR e6de
+in hexadecimal using Encapsuation Security Payload protocol (50,
+IPPROTO_ESP) with no identies defined for either end.
+.LP
+.B "1984 3049:1::110/128 -> 3049:1::120/128 => "
+.br
+.B " ah:f5ed@3049:1::120 () ()"
+.LP
+means that 1984 packets have been sent to an
+.BR eroute
+that has been set up to authenticate traffic between the host
+.BR 3049:1::110
+and the host
+.BR 3049:1::120
+using
+.BR 3049:1::110
+as a security gateway on this end of the
+connection and the machine
+.BR 3049:1::120
+on the other end of the connection with a Security Association IDentifier of
+.BR ah:f5ed@3049:1::120
+which means that it is a transport mode connection with a Security
+Parameters Index of
+.BR f5ed
+in hexadecimal using Authentication Header protocol (51,
+IPPROTO_AH) with no identies defined for either end.
+.SH FILES
+/proc/net/ipsec_eroute, /usr/local/bin/ipsec
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_tncfg(5), ipsec_spi(5),
+ipsec_spigrp(5), ipsec_klipsdebug(5), ipsec_eroute(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.
+.\"
+.\" $Log: eroute.5,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.9 2002/04/24 07:35:38 mcr
+.\" Moved from ./klips/utils/eroute.5,v
+.\"
+.\" Revision 1.8 2001/09/20 15:33:13 rgb
+.\" PF_KEYv2 ident extension output documentation.
+.\"
+.\" Revision 1.7 2001/05/29 05:15:31 rgb
+.\" Added packet count field at beginning of line.
+.\"
+.\" Revision 1.6 2001/02/26 19:58:32 rgb
+.\" Put SAID elements in order they appear in SAID.
+.\" Implement magic SAs %drop, %reject, %trap, %hold, %pass as part
+.\" of the new SPD and to support opportunistic.
+.\"
+.\" Revision 1.5 2000/09/17 18:56:48 rgb
+.\" Added IPCOMP support.
+.\"
+.\" Revision 1.4 2000/09/13 15:54:31 rgb
+.\" Added Gerhard's ipv6 updates.
+.\"
+.\" 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:11 henry
+.\" format touchup
+.\"
+.\" Revision 1.1 2000/06/28 05:43:00 rgb
+.\" Added manpages for all 5 klips utils.
+.\"
+.\"
+.\"
diff --git a/programs/eroute/eroute.8 b/programs/eroute/eroute.8
new file mode 100644
index 000000000..d9449632b
--- /dev/null
+++ b/programs/eroute/eroute.8
@@ -0,0 +1,354 @@
+.TH IPSEC_EROUTE 8 "21 Jun 2000"
+.\"
+.\" RCSID $Id: eroute.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.\"
+.SH NAME
+ipsec eroute \- manipulate IPSEC extended routing tables
+.SH SYNOPSIS
+.B ipsec
+.B eroute
+.PP
+.B ipsec
+.B eroute
+.B \-\-add
+.B \-\-eraf (inet | inet6)
+.B \-\-src
+src/srcmaskbits|srcmask
+.B \-\-dst
+dst/dstmaskbits|dstmask
+[
+.B \-\-transport\-proto
+transport-protocol
+]
+[
+.B \-\-src\-port
+source-port
+]
+[
+.B \-\-dst\-port
+dest-port
+]
+<SAID>
+.PP
+.B ipsec
+.B eroute
+.B \-\-replace
+.B \-\-eraf (inet | inet6)
+.B \-\-src
+src/srcmaskbits|srcmask
+.B \-\-dst
+dst/dstmaskbits|dstmask
+[
+.B \-\-transport\-proto
+transport-protocol
+]
+[
+.B \-\-src\-port
+source-port
+]
+[
+.B \-\-dst\-port
+dest-port
+]
+<SAID>
+.PP
+.B ipsec
+.B eroute
+.B \-\-del
+.B \-\-eraf (inet | inet6)
+.B \-\-src
+src/srcmaskbits|srcmask
+.B \-\-dst
+dst/dstmaskbits|dstmask
+[
+.B \-\-transport\-proto
+transport-protocol
+]
+[
+.B \-\-src\-port
+source-port
+]
+[
+.B \-\-dst\-port
+dest-port
+]
+.PP
+.B ipsec
+.B eroute
+.B \-\-clear
+.PP
+.B ipsec
+.B eroute
+.B \-\-help
+.PP
+.B ipsec
+.B eroute
+.B \-\-version
+.PP
+Where <SAID> is
+.B \-\-af
+(inet | inet6)
+.B \-\-edst
+edst
+.B \-\-spi
+spi
+.B \-\-proto
+proto
+OR
+.B \-\-said
+said
+OR
+.B \-\-said
+.B (%passthrough | %passthrough4 | %passthrough6 | %drop | %reject | %trap | %hold | %pass )
+.SH DESCRIPTION
+.I Eroute
+manages the IPSEC extended routing tables,
+which control what (if any) processing is applied
+to non-encrypted packets arriving for IPSEC processing and forwarding.
+The form with no additional arguments lists the contents of
+/proc/net/ipsec_eroute.
+The
+.B \-\-add
+form adds a table entry, the
+.B \-\-replace
+form replaces a table entry, while the
+.B \-\-del
+form deletes one. The
+.B \-\-clear
+form deletes the entire table.
+.PP
+A table entry consists of:
+.IP + 3
+source and destination addresses,
+with masks, source and destination ports and protocol
+for selection of packets. The source and destination ports are only
+legal if the transport protocol is
+.BR TCP
+or
+.BR UDP.
+A port can be specified as either decimal, hexadecimal (leading 0x),
+octal (leading 0) or a name listed in the first column of /etc/services.
+A transport protocol can be specified as either decimal, hexadecimal
+(leading 0x), octal (leading 0) or a name listed in the first column
+of /etc/protocols. If a transport protocol or port is not specified
+then it defaults to 0 which means all protocols or all ports
+respectively.
+.IP +
+Security Association IDentifier, comprised of:
+.IP + 6
+protocol
+(\fIproto\fR), indicating (together with the
+effective destination and the security parameters index)
+which Security Association should be used to process the packet
+.IP +
+address family
+(\fIaf\fR),
+.IP +
+Security Parameters Index
+(\fIspi\fR), indicating (together with the
+effective destination and protocol)
+which Security Association should be used to process the packet
+(must be larger than or equal to 0x100)
+.IP +
+effective destination
+(\fIedst\fR),
+where the packet should be forwarded after processing
+(normally the other security gateway)
+.IP + 3
+OR
+.IP + 6
+SAID
+(\fIsaid\fR), indicating
+which Security Association should be used to process the packet
+.PP
+Addresses are written as IPv4 dotted quads or IPv6 coloned hex,
+protocol is one of "ah", "esp", "comp" or "tun" and SPIs are
+prefixed hexadecimal numbers where '.' represents IPv4 and ':'
+stands for IPv6.
+.PP
+SAIDs are written as "protoafSPI@address". There are also 5
+"magic" SAIDs which have special meaning:
+.IP + 3
+.B %drop
+means that matches are to be dropped
+.IP +
+.B %reject
+means that matches are to be dropped and an ICMP returned, if
+possible to inform
+.IP +
+.B %trap
+means that matches are to trigger an ACQUIRE message to the Key
+Management daemon(s) and a hold eroute will be put in place to
+prevent subsequent packets also triggering ACQUIRE messages.
+.IP +
+.B %hold
+means that matches are to stored until the eroute is replaced or
+until that eroute gets reaped
+.IP +
+.B %pass
+means that matches are to allowed to pass without IPSEC processing
+.PP
+The format of /proc/net/ipsec_eroute is listed in ipsec_eroute(5).
+.br
+.ne 5
+.SH EXAMPLES
+.LP
+.B "ipsec eroute \-\-add \-\-eraf inet \-\-src 192.168.0.1/32 \e"
+.br
+.B " \-\-dst 192.168.2.0/24 \-\-af inet \-\-edst 192.168.0.2 \e"
+.br
+.B " \-\-spi 0x135 \-\-proto tun"
+.LP
+sets up an
+.BR eroute
+on a Security Gateway to protect traffic between the host
+.BR 192.168.0.1
+and the subnet
+.BR 192.168.2.0
+with
+.BR 24
+bits of subnet mask via Security Gateway
+.BR 192.168.0.2
+using the Security Association with address
+.BR 192.168.0.2 ,
+Security Parameters Index
+.BR 0x135
+and protocol
+.BR tun
+(50, IPPROTO_ESP).
+.LP
+.B "ipsec eroute \-\-add \-\-eraf inet6 \-\-src 3049:1::1/128 \e"
+.br
+.B " \-\-dst 3049:2::/64 \-\-af inet6 \-\-edst 3049:1::2 \e"
+.br
+.B " \-\-spi 0x145 \-\-proto tun"
+.LP
+sets up an
+.BR eroute
+on a Security Gateway to protect traffic between the host
+.BR 3049:1::1
+and the subnet
+.BR 3049:2::
+with
+.BR 64
+bits of subnet mask via Security Gateway
+.BR 3049:1::2
+using the Security Association with address
+.BR 3049:1::2 ,
+Security Parameters Index
+.BR 0x145
+and protocol
+.BR tun
+(50, IPPROTO_ESP).
+.LP
+.B "ipsec eroute \-\-replace \-\-eraf inet \-\-src company.com/24 \e"
+.br
+.B " \-\-dst ftp.ngo.org/32 \-\-said tun.135@gw.ngo.org"
+.LP
+replaces an
+.BR eroute
+on a Security Gateway to protect traffic between the subnet
+.BR company.com
+with
+.BR 24
+bits of subnet mask and the host
+.BR ftp.ngo.org
+via Security Gateway
+.BR gw.ngo.org
+using the Security Association with Security Association ID
+.BR tun0x135@gw.ngo.org
+.LP
+.B "ipsec eroute \-\-del \-\-eraf inet \-\-src company.com/24 \e"
+.br
+.B " \-\-dst www.ietf.org/32 \-\-said %passthrough4"
+.LP
+deletes an
+.BR eroute
+on a Security Gateway that allowed traffic between the subnet
+.BR company.com
+with
+.BR 24
+bits of subnet mask and the host
+.BR www.ietf.org
+to pass in the clear, unprocessed.
+.LP
+.B "ipsec eroute \-\-add \-\-eraf inet \-\-src company.com/24 \e"
+.br
+.B " \-\-dst mail.ngo.org/32 \-\-transport-proto 6 \e"
+.br
+.B " \-\-dst\-port 110 \-\-said tun.135@mail.ngo.org"
+.LP
+sets up an
+.BR eroute
+on on a Security Gateway to protect only TCP traffic on port 110
+(pop3) between the subnet
+.BR company.com
+with
+.BR 24
+bits of subnet mask and the host
+.BR ftp.ngo.org
+via Security Gateway
+.BR mail.ngo.org
+using the Security Association with Security Association ID
+.BR tun0x135@mail.ngo.org.
+Note that any other traffic bound for
+.BR mail.ngo.org
+that is routed via the ipsec device will be dropped. If you wish to
+allow other traffic to pass through then you must add a %pass rule.
+For example the following rule when combined with the above will
+ensure that POP3 messages read from
+.BR mail.ngo.org
+will be encrypted but all other traffic to/from
+.BR mail.ngo.org
+will be in clear text.
+.LP
+.B "ipsec eroute \-\-add \-\-eraf inet \-\-src company.com/24 \e"
+.br
+.B " \-\-dst mail.ngo.org/32 \-\-said %pass"
+.br
+.LP
+.SH FILES
+/proc/net/ipsec_eroute, /usr/local/bin/ipsec
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_tncfg(8), ipsec_spi(8),
+ipsec_spigrp(8), ipsec_klipsdebug(8), ipsec_eroute(5)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Richard Guy Briggs.
+.\"
+.\" $Log: eroute.8,v $
+.\" Revision 1.1 2004/03/15 20:35:27 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.25 2002/04/24 07:35:38 mcr
+.\" Moved from ./klips/utils/eroute.8,v
+.\"
+.\" Revision 1.24 2001/02/26 19:58:49 rgb
+.\" Added a comment on the restriction of spi > 0x100.
+.\" Implement magic SAs %drop, %reject, %trap, %hold, %pass as part
+.\" of the new SPD and to support opportunistic.
+.\"
+.\" Revision 1.23 2000/09/17 18:56:48 rgb
+.\" Added IPCOMP support.
+.\"
+.\" Revision 1.22 2000/09/13 15:54:31 rgb
+.\" Added Gerhard's ipv6 updates.
+.\"
+.\" Revision 1.21 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.20 2000/06/21 16:54:57 rgb
+.\" Added 'no additional args' text for listing contents of
+.\" /proc/net/ipsec_* files.
+.\"
+.\" Revision 1.19 1999/07/19 18:47:24 henry
+.\" fix slightly-misformed comments
+.\"
+.\" Revision 1.18 1999/04/06 04:54:37 rgb
+.\" Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+.\" patch shell fixes.
+.\"
+.\"
diff --git a/programs/eroute/eroute.c b/programs/eroute/eroute.c
new file mode 100644
index 000000000..d1b2bff0a
--- /dev/null
+++ b/programs/eroute/eroute.c
@@ -0,0 +1,1044 @@
+/*
+ * manipulate eroutes
+ * Copyright (C) 1996 John Ioannidis.
+ * Copyright (C) 1997, 1998, 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.
+ */
+
+char eroute_c_version[] = "RCSID $Id: eroute.c,v 1.3 2005/02/24 20:03:46 as Exp $";
+
+
+#include <sys/types.h>
+#include <linux/types.h> /* new */
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h> /* system(), strtoul() */
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netdb.h>
+
+
+#include <unistd.h>
+#include <freeswan.h>
+#if 0
+#include <linux/autoconf.h> /* CONFIG_IPSEC_PFKEYv2 */
+#endif
+/* permanently turn it on since netlink support has been disabled */
+
+#include <signal.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+
+#include <stdio.h>
+#include <getopt.h>
+
+char *program_name;
+char me[] = "ipsec eroute";
+extern char *optarg;
+extern int optind, opterr, optopt;
+char *eroute_af_opt, *said_af_opt, *edst_opt, *spi_opt, *proto_opt, *said_opt, *dst_opt, *src_opt;
+char *transport_proto_opt, *src_port_opt, *dst_port_opt;
+int action_type = 0;
+
+int pfkey_sock;
+fd_set pfkey_socks;
+uint32_t pfkey_seq = 0;
+
+#define EMT_IFADDR 1 /* set enc if addr */
+#define EMT_SETSPI 2 /* Set SPI properties */
+#define EMT_DELSPI 3 /* Delete an SPI */
+#define EMT_GRPSPIS 4 /* Group SPIs (output order) */
+#define EMT_SETEROUTE 5 /* set an extended route */
+#define EMT_DELEROUTE 6 /* del an extended route */
+#define EMT_TESTROUTE 7 /* try to find route, print to console */
+#define EMT_SETDEBUG 8 /* set debug level if active */
+#define EMT_UNGRPSPIS 9 /* UnGroup SPIs (output order) */
+#define EMT_CLREROUTE 10 /* clear the extended route table */
+#define EMT_CLRSPIS 11 /* clear the spi table */
+#define EMT_REPLACEROUTE 12 /* set an extended route */
+#define EMT_GETDEBUG 13 /* get debug level if active */
+#define EMT_INEROUTE 14 /* set incoming policy for IPIP on a chain */
+
+static void
+add_port(int af, ip_address * addr, short port)
+{
+ switch (af)
+ {
+ case AF_INET:
+ addr->u.v4.sin_port = port;
+ break;
+ case AF_INET6:
+ addr->u.v6.sin6_port = port;
+ break;
+ }
+}
+
+static void
+usage(char* arg)
+{
+ fprintf(stdout, "usage: %s --{add,addin,replace} --eraf <inet | inet6> --src <src>/<srcmaskbits>|<srcmask> --dst <dst>/<dstmaskbits>|<dstmask> [ --transport-proto <protocol> ] [ --src-port <source-port> ] [ --dst-port <dest-port> ] <SA>\n", arg);
+ fprintf(stdout, " where <SA> is '--af <inet | inet6> --edst <edst> --spi <spi> --proto <proto>'\n");
+ fprintf(stdout, " OR '--said <said>'\n");
+ fprintf(stdout, " OR '--said <%%passthrough | %%passthrough4 | %%passthrough6 | %%drop | %%reject | %%trap | %%hold | %%pass>'.\n");
+ fprintf(stdout, " %s --del --eraf <inet | inet6>--src <src>/<srcmaskbits>|<srcmask> --dst <dst>/<dstmaskbits>|<dstmask> [ --transport-proto <protocol> ] [ --src-port <source-port> ] [ --dst-port <dest-port> ]\n", arg);
+ fprintf(stdout, " %s --clear\n", arg);
+ fprintf(stdout, " %s --help\n", arg);
+ fprintf(stdout, " %s --version\n", arg);
+ fprintf(stdout, " %s\n", arg);
+ fprintf(stdout, " [ --debug ] is optional to any %s command.\n", arg);
+ fprintf(stdout, " [ --label <label> ] is optional to any %s command.\n", arg);
+ exit(1);
+}
+
+static struct option const longopts[] =
+{
+ {"dst", 1, 0, 'D'},
+ {"src", 1, 0, 'S'},
+ {"eraf", 1, 0, 'f'},
+ {"add", 0, 0, 'a'},
+ {"addin", 0, 0, 'A'},
+ {"replace", 0, 0, 'r'},
+ {"clear", 0, 0, 'c'},
+ {"del", 0, 0, 'd'},
+ {"af", 1, 0, 'i'},
+ {"edst", 1, 0, 'e'},
+ {"proto", 1, 0, 'p'},
+ {"transport-proto", 1, 0, 'P'},
+ {"src-port", 1, 0, 'Q'},
+ {"dst-port", 1, 0, 'R'},
+ {"help", 0, 0, 'h'},
+ {"spi", 1, 0, 's'},
+ {"said", 1, 0, 'I'},
+ {"version", 0, 0, 'v'},
+ {"label", 1, 0, 'l'},
+ {"optionsfrom", 1, 0, '+'},
+ {"debug", 0, 0, 'g'},
+ {0, 0, 0, 0}
+};
+
+int
+main(int argc, char **argv)
+{
+ /* int fd; */
+ char *endptr;
+ /* int ret; */
+ int c, previous = -1;
+ const char* error_s;
+ int debug = 0;
+
+ int error = 0;
+
+ char ipaddr_txt[ADDRTOT_BUF];
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+ struct sadb_msg *pfkey_msg;
+ ip_address pfkey_address_s_ska;
+ /*struct sockaddr_in pfkey_address_d_ska;*/
+ ip_address pfkey_address_sflow_ska;
+ ip_address pfkey_address_dflow_ska;
+ ip_address pfkey_address_smask_ska;
+ ip_address pfkey_address_dmask_ska;
+
+ int transport_proto = 0;
+ int src_port = 0;
+ int dst_port = 0;
+ ip_said said;
+ ip_subnet s_subnet, d_subnet;
+ int eroute_af = 0;
+ int said_af = 0;
+
+ int argcount = argc;
+
+ const char permitted_options[] =
+ "%s: Only one of '--add', '--addin', '--replace', '--clear', or '--del' options permitted.\n";
+
+ program_name = argv[0];
+ eroute_af_opt = said_af_opt = edst_opt = spi_opt = proto_opt = said_opt = dst_opt = src_opt = NULL;
+
+ while((c = getopt_long(argc, argv, ""/*"acdD:e:i:hprs:S:f:vl:+:g"*/, longopts, 0)) != EOF)
+ {
+ switch(c)
+ {
+ case 'g':
+ debug = 1;
+ pfkey_lib_debug = PF_KEY_DEBUG_PARSE_MAX;
+ argcount--;
+ break;
+ case 'a':
+ if (action_type)
+ {
+ fprintf(stderr, permitted_options, program_name);
+ exit(1);
+ }
+ action_type = EMT_SETEROUTE;
+ break;
+ case 'A':
+ if (action_type)
+ {
+ fprintf(stderr, permitted_options, program_name);
+ exit(1);
+ }
+ action_type = EMT_INEROUTE;
+ break;
+ case 'r':
+ if (action_type)
+ {
+ fprintf(stderr, permitted_options, program_name);
+ exit(1);
+ }
+ action_type = EMT_REPLACEROUTE;
+ break;
+ case 'c':
+ if (action_type)
+ {
+ fprintf(stderr, permitted_options, program_name);
+ exit(1);
+ }
+ action_type = EMT_CLREROUTE;
+ break;
+ case 'd':
+ if (action_type)
+ {
+ fprintf(stderr, permitted_options, program_name);
+ exit(1);
+ }
+ action_type = EMT_DELEROUTE;
+ 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, said_af, &said.dst);
+ if (error_s != NULL)
+ {
+ fprintf(stderr, "%s: Error, %s converting --edst argument:%s\n"
+ , program_name, error_s, optarg);
+ exit (1);
+ }
+ edst_opt = optarg;
+ break;
+ case 'h':
+ case '?':
+ usage(program_name);
+ exit(1);
+ 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);
+ }
+ said.spi = htonl(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 (ntohl(said.spi) < 0x100)
+ {
+ fprintf(stderr, "%s: Illegal reserved spi: %s => 0x%x Must be larger than 0x100.\n"
+ , program_name, optarg, ntohl(said.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 0
+ if (said.proto)
+ {
+ fprintf(stderr, "%s: Warning, PROTO parameter redefined:%s\n"
+ , program_name, optarg);
+ exit (1);
+ }
+#endif
+ if (!strcmp(optarg, "ah"))
+ said.proto = SA_AH;
+ if (!strcmp(optarg, "esp"))
+ said.proto = SA_ESP;
+ if (!strcmp(optarg, "tun"))
+ said.proto = SA_IPIP;
+ if (!strcmp(optarg, "comp"))
+ said.proto = SA_COMP;
+ if (said.proto == 0)
+ {
+ fprintf(stderr, "%s: Invalid PROTO parameter: %s\n"
+ , program_name, optarg);
+ exit (1);
+ }
+ proto_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);
+ }
+ if (said_af_opt)
+ {
+ fprintf(stderr, "%s: Error, address family parameter redefined in SA:%s, already defined as:%s\n"
+ , program_name, optarg, said_af_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);
+ }
+ else if (ntohl(said.spi) < 0x100)
+ {
+ fprintf(stderr, "%s: Illegal reserved spi: %s => 0x%x Must be larger than or equal to 0x100.\n"
+ , program_name, optarg, said.spi);
+ exit(1);
+ }
+ said_af = addrtypeof(&said.dst);
+ said_opt = optarg;
+ break;
+ case 'v':
+ fprintf(stdout, "%s %s\n", me, ipsec_version_code());
+ fprintf(stdout, "See `ipsec --copyright' for copyright information.\n");
+ exit(1);
+ 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 = ttosubnet(optarg, 0, eroute_af, &d_subnet);
+ if (error_s != NULL)
+ {
+ fprintf(stderr, "%s: Error, %s converting --dst argument: %s\n"
+ , program_name, error_s, optarg);
+ exit (1);
+ }
+ dst_opt = optarg;
+ 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 = ttosubnet(optarg, 0, eroute_af, &s_subnet);
+ if (error_s != NULL)
+ {
+ fprintf(stderr, "%s: Error, %s converting --src argument: %s\n"
+ , program_name, error_s, optarg);
+ exit (1);
+ }
+ src_opt = optarg;
+ break;
+ case 'P':
+ if (transport_proto_opt)
+ {
+ fprintf(stderr, "%s: Error, --transport-proto parameter redefined:%s, already defined as:%s\n"
+ , program_name, optarg, transport_proto_opt);
+ exit(1);
+ }
+ transport_proto_opt = optarg;
+ break;
+ case 'Q':
+ if (src_port_opt)
+ {
+ fprintf(stderr, "%s: Error, --src-port parameter redefined:%s, already defined as:%s\n"
+ , program_name, optarg, src_port_opt);
+ exit(1);
+ }
+ src_port_opt = optarg;
+ break;
+ case 'R':
+ if (dst_port_opt)
+ {
+ fprintf(stderr, "%s: Error, --dst-port parameter redefined:%s, already defined as:%s\n"
+ , program_name, optarg, dst_port_opt);
+ exit(1);
+ }
+ dst_port_opt = optarg;
+ 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 'i': /* specifies the address family of the SAID, stored in said_af */
+ if (said_af_opt)
+ {
+ fprintf(stderr, "%s: Error, address family of SAID redefined:%s, already defined as:%s\n"
+ , program_name, optarg, said_af_opt);
+ exit (1);
+ }
+ if (!strcmp(optarg, "inet"))
+ said_af = AF_INET;
+ if (!strcmp(optarg, "inet6"))
+ said_af = AF_INET6;
+ if (said_af == 0)
+ {
+ fprintf(stderr, "%s: Invalid address family parameter for SAID: %s\n"
+ , program_name, optarg);
+ exit (1);
+ }
+ said_af_opt = optarg;
+ break;
+ case 'f': /* specifies the address family of the eroute, stored in eroute_af */
+ if (eroute_af_opt)
+ {
+ fprintf(stderr, "%s: Error, address family of eroute redefined:%s, already defined as:%s\n"
+ , program_name, optarg, eroute_af_opt);
+ exit (1);
+ }
+ if (!strcmp(optarg, "inet"))
+ eroute_af = AF_INET;
+ if (!strcmp(optarg, "inet6"))
+ eroute_af = AF_INET6;
+ if (eroute_af == 0)
+ {
+ fprintf(stderr, "%s: Invalid address family parameter for eroute: %s\n"
+ , program_name, optarg);
+ exit (1);
+ }
+ eroute_af_opt = optarg;
+ break;
+ case '+': /* optionsfrom */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* no return on error */
+ break;
+ default:
+ break;
+ }
+ previous = c;
+ }
+
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: argc=%d\n", program_name, argc);
+ }
+
+ if (argcount == 1)
+ {
+ system("cat /proc/net/ipsec_eroute");
+ exit(0);
+ }
+
+ /* Sanity checks */
+
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: action_type=%d\n", program_name, action_type);
+ }
+
+ if (transport_proto_opt != 0)
+ {
+ struct protoent * proto = getprotobyname(transport_proto_opt);
+
+ if (proto != 0)
+ {
+ transport_proto = proto->p_proto;
+ }
+ else
+ {
+ transport_proto = strtoul(transport_proto_opt, &endptr, 0);
+
+ if ((*endptr != '\0')
+ || (transport_proto == 0 && endptr == transport_proto_opt))
+ {
+ fprintf(stderr, "%s: Invalid character in --transport-proto parameter: %s\n"
+ , program_name, transport_proto_opt);
+ exit (1);
+ }
+ if (transport_proto > 255)
+ {
+ fprintf(stderr, "%s: --transport-proto parameter: %s must be in the range 0 to 255 inclusive\n"
+ , program_name, transport_proto_opt);
+ exit (1);
+ }
+ }
+ }
+
+ if (src_port_opt != 0 || dst_port_opt != 0)
+ {
+ switch (transport_proto)
+ {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ break;
+ default:
+ fprintf(stderr, "%s: --transport-proto with either UDP or TCP must be specified if --src-port or --dst-port is used\n"
+ , program_name);
+ exit(1);
+ }
+ }
+
+ if (src_port_opt)
+ {
+ struct servent * ent = getservbyname(src_port_opt, 0);
+
+ if (ent != 0)
+ {
+ src_port = ent->s_port;
+ }
+ else
+ {
+ src_port = strtoul(src_port_opt, &endptr, 0);
+
+ if ((*endptr != '\0')
+ || (src_port == 0 && endptr == src_port_opt))
+ {
+ fprintf(stderr, "%s: Invalid character in --src-port parameter: %s\n"
+ , program_name, src_port_opt);
+ exit (1);
+ }
+ if (src_port > 65535)
+ {
+ fprintf(stderr, "%s: --src-port parameter: %s must be in the range 0 to 65535 inclusive\n"
+ , program_name, src_port_opt);
+ }
+ src_port = htons(src_port);
+ }
+ }
+
+ if (dst_port_opt)
+ {
+ struct servent * ent = getservbyname(dst_port_opt, 0);
+
+ if (ent != 0)
+ {
+ dst_port = ent->s_port;
+ }
+ else
+ {
+ dst_port = strtoul(dst_port_opt, &endptr, 0);
+
+ if ((*endptr != '\0')
+ || (dst_port == 0 && endptr == dst_port_opt))
+ {
+ fprintf(stderr, "%s: Invalid character in --dst-port parameter: %s\n"
+ , program_name, dst_port_opt);
+ exit (1);
+ }
+ if (dst_port > 65535)
+ {
+ fprintf(stderr, "%s: --dst-port parameter: %s must be in the range 0 to 65535 inclusive\n"
+ , program_name, dst_port_opt);
+ }
+ dst_port = htons(dst_port);
+ }
+ }
+
+ switch(action_type)
+ {
+ case EMT_SETEROUTE:
+ case EMT_REPLACEROUTE:
+ case EMT_INEROUTE:
+ if (!(said_af_opt && edst_opt && spi_opt && proto_opt) && !(said_opt))
+ {
+ fprintf(stderr, "%s: add and addin options must have SA specified.\n"
+ , program_name);
+ exit(1);
+ }
+ case EMT_DELEROUTE:
+ if (!src_opt)
+ {
+ fprintf(stderr, "%s: Error -- %s option '--src' is required.\n"
+ , program_name, (action_type == EMT_SETEROUTE) ? "add" : "del");
+ exit(1);
+ }
+ if (!dst_opt)
+ {
+ fprintf(stderr, "%s: Error -- %s option '--dst' is required.\n"
+ , program_name, (action_type == EMT_SETEROUTE) ? "add" : "del");
+ exit(1);
+ }
+ case EMT_CLREROUTE:
+ break;
+ default:
+ fprintf(stderr, "%s: exactly one of '--add', '--addin', '--replace', '--del' or '--clear' options must be specified.\n"
+ "Try %s --help' for usage information.\n"
+ , program_name, program_name);
+ exit(1);
+ }
+
+ 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, "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:
+ case ENOMEM:
+ case ENFILE:
+ fprintf(stderr, "No kernel memory to allocate socket.\n");
+ break;
+ case EMFILE:
+ fprintf(stderr, "Process file table overflow.\n");
+ break;
+ case ESOCKTNOSUPPORT:
+ fprintf(stderr, "Socket type not supported.\n");
+ break;
+ case EPROTONOSUPPORT:
+ fprintf(stderr, "Protocol version not supported.\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);
+ }
+
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: PFKEYv2 socket successfully openned=%d.\n"
+ , program_name, pfkey_sock);
+ }
+
+ /* Build an SADB_X_ADDFLOW or SADB_X_DELFLOW message to send down. */
+ /* It needs <base, SA, address(SD), flow(SD), mask(SD)> minimum. */
+ pfkey_extensions_init(extensions);
+
+ error = pfkey_msg_hdr_build(&extensions[0]
+ , (action_type == EMT_SETEROUTE || action_type == EMT_REPLACEROUTE
+ || action_type == EMT_INEROUTE)? SADB_X_ADDFLOW : SADB_X_DELFLOW
+ , proto2satype(said.proto)
+ , 0
+ , ++pfkey_seq
+ , getpid()
+ );
+
+ if (error)
+ {
+ fprintf(stderr, "%s: Trouble building message header, error=%d.\n"
+ , program_name, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: pfkey_msg_hdr_build successfull.\n"
+ , program_name);
+ }
+
+ switch (action_type)
+ {
+ case EMT_SETEROUTE:
+ case EMT_REPLACEROUTE:
+ case EMT_INEROUTE:
+ case EMT_CLREROUTE:
+ error = pfkey_sa_build(&extensions[SADB_EXT_SA]
+ , SADB_EXT_SA
+ , said.spi /* in network order */
+ , 0
+ , 0
+ , 0
+ , 0
+ , (action_type == EMT_CLREROUTE) ? SADB_X_SAFLAGS_CLEARFLOW : 0
+ );
+
+ if (error)
+ {
+ fprintf(stderr, "%s: Trouble building sa extension, error=%d.\n"
+ , program_name, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: pfkey_sa_build successful.\n"
+ , program_name);
+ }
+ default:
+ break;
+ }
+
+ switch (action_type)
+ {
+ case EMT_SETEROUTE:
+ case EMT_REPLACEROUTE:
+ case EMT_INEROUTE:
+ anyaddr(said_af, &pfkey_address_s_ska);
+ error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC]
+ , SADB_EXT_ADDRESS_SRC
+ , 0
+ , 0
+ , sockaddrof(&pfkey_address_s_ska)
+ );
+ if (error)
+ {
+ addrtot(&pfkey_address_s_ska, 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)
+ {
+ fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for src.\n"
+ , program_name);
+ }
+
+ error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST]
+ , SADB_EXT_ADDRESS_DST
+ , 0
+ , 0
+ , sockaddrof(&said.dst)
+ );
+
+ if (error)
+ {
+ addrtot(&said.dst, 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)
+ {
+ fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for dst.\n"
+ , program_name);
+ }
+ default:
+ break;
+ }
+
+ switch (action_type)
+ {
+ case EMT_SETEROUTE:
+ case EMT_REPLACEROUTE:
+ case EMT_INEROUTE:
+ case EMT_DELEROUTE:
+ networkof(&s_subnet, &pfkey_address_sflow_ska); /* src flow */
+ add_port(eroute_af, &pfkey_address_sflow_ska, src_port);
+
+ error = pfkey_address_build(&extensions[SADB_X_EXT_ADDRESS_SRC_FLOW]
+ , SADB_X_EXT_ADDRESS_SRC_FLOW
+ , 0
+ , 0
+ , sockaddrof(&pfkey_address_sflow_ska)
+ );
+
+ if (error)
+ {
+ addrtot(&pfkey_address_sflow_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
+ fprintf(stderr, "%s: Trouble building address_sflow extension (%s), error=%d.\n",
+ program_name, ipaddr_txt, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for src flow.\n"
+ , program_name);
+ }
+
+ networkof(&d_subnet, &pfkey_address_dflow_ska); /* dst flow */
+ add_port(eroute_af, &pfkey_address_dflow_ska, dst_port);
+
+ error = pfkey_address_build(&extensions[SADB_X_EXT_ADDRESS_DST_FLOW]
+ , SADB_X_EXT_ADDRESS_DST_FLOW
+ , 0
+ , 0
+ , sockaddrof(&pfkey_address_dflow_ska)
+ );
+
+ if (error)
+ {
+ addrtot(&pfkey_address_dflow_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
+ fprintf(stderr, "%s: Trouble building address_dflow extension (%s), error=%d.\n"
+ , program_name, ipaddr_txt, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for dst flow.\n"
+ , program_name);
+ }
+
+ maskof(&s_subnet, &pfkey_address_smask_ska); /* src mask */
+ add_port(eroute_af, &pfkey_address_smask_ska, src_port ? ~0:0);
+
+ error = pfkey_address_build(&extensions[SADB_X_EXT_ADDRESS_SRC_MASK]
+ , SADB_X_EXT_ADDRESS_SRC_MASK
+ , 0
+ , 0
+ , sockaddrof(&pfkey_address_smask_ska)
+ );
+
+ if (error)
+ {
+ addrtot(&pfkey_address_smask_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
+ fprintf(stderr, "%s: Trouble building address_smask extension (%s), error=%d.\n"
+ , program_name, ipaddr_txt, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for src mask.\n"
+ , program_name);
+ }
+
+ maskof(&d_subnet, &pfkey_address_dmask_ska); /* dst mask */
+ add_port(eroute_af, &pfkey_address_dmask_ska, dst_port ? ~0:0);
+
+ error = pfkey_address_build(&extensions[SADB_X_EXT_ADDRESS_DST_MASK]
+ , SADB_X_EXT_ADDRESS_DST_MASK
+ , 0
+ , 0
+ , sockaddrof(&pfkey_address_dmask_ska)
+ );
+
+ if (error)
+ {
+ addrtot(&pfkey_address_dmask_ska, 0, ipaddr_txt, sizeof(ipaddr_txt));
+ fprintf(stderr, "%s: Trouble building address_dmask extension (%s), error=%d.\n"
+ , program_name, ipaddr_txt, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: pfkey_address_build successful for dst mask.\n"
+ , program_name);
+ }
+ }
+
+ if (transport_proto != 0)
+ {
+ error = pfkey_x_protocol_build(&extensions[SADB_X_EXT_PROTOCOL]
+ , transport_proto);
+
+ if (error)
+ {
+ fprintf(stderr, "%s: Trouble building transport protocol extension, error=%d.\n"
+ , program_name, error);
+ exit(1);
+ }
+ }
+
+ error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN);
+
+ if (error)
+ {
+ 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: DEBUG: pfkey_msg_build successful.\n"
+ , program_name);
+ }
+
+ error = write(pfkey_sock
+ , pfkey_msg
+ , pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN
+ )
+ != (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+
+ if (error)
+ {
+ fprintf(stderr, "%s: pfkey write failed, returning %d with errno=%d.\n"
+ , program_name, error, errno);
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+
+ switch (errno)
+ {
+ case EINVAL:
+ fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n");
+ break;
+ case ENXIO:
+ if (action_type == EMT_SETEROUTE || action_type == EMT_REPLACEROUTE)
+ {
+ fprintf(stderr, "Invalid mask.\n");
+ break;
+ }
+ if (action_type == EMT_DELEROUTE)
+ {
+ fprintf(stderr, "Mask not found.\n");
+ break;
+ }
+ case EFAULT:
+ if (action_type == EMT_SETEROUTE || action_type == EMT_REPLACEROUTE)
+ {
+ fprintf(stderr, "Invalid address.\n");
+ break;
+ }
+ if (action_type == EMT_DELEROUTE)
+ {
+ fprintf(stderr, "Address not found.\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, "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 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, "eroute already in use. Delete old one first.\n");
+ break;
+ case ENOENT:
+ if (action_type == EMT_INEROUTE)
+ {
+ fprintf(stderr, "non-existant IPIP SA.\n");
+ break;
+ }
+ fprintf(stderr, "eroute doesn't exist. Can't 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. Please report as much detail as possible to development team.\n"
+ , errno);
+ }
+/* fprintf(stderr, "%s: socket write returned errno %d\n",
+ program_name, errno);*/
+ exit(1);
+ }
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: pfkey write successful.\n"
+ , program_name);
+ }
+
+ if (pfkey_msg)
+ {
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+ }
+
+ (void) close(pfkey_sock); /* close the socket */
+
+ if (debug)
+ {
+ fprintf(stdout, "%s: DEBUG: write ok\n", program_name);
+ }
+
+ exit(0);
+}
diff --git a/programs/examples/Makefile b/programs/examples/Makefile
new file mode 100644
index 000000000..114008a73
--- /dev/null
+++ b/programs/examples/Makefile
@@ -0,0 +1,22 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/08/28 11:25:09 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+CONFDSUBDIR=examples
+CONFDFILES=oe.conf
+
+include ../Makefile.program
diff --git a/programs/examples/oe.conf.in b/programs/examples/oe.conf.in
new file mode 100644
index 000000000..4eff4d0dd
--- /dev/null
+++ b/programs/examples/oe.conf.in
@@ -0,0 +1,68 @@
+# defines default policy groups for Opportunistic Encryption (OE)
+#
+# RCSID $Id: oe.conf.in,v 1.1 2004/08/28 11:25:09 as Exp $
+
+conn packetdefault
+ type=tunnel
+ leftsubnet=0.0.0.0/0
+ right=%opportunistic
+ failureshunt=passthrough
+ keyingtries=3
+ ikelifetime=1h
+ keylife=1h
+ rekey=no
+ also=oe_defaults
+ auto=route
+
+conn clear
+ type=passthrough
+ authby=never
+ right=%group
+ also=oe_defaults
+ auto=route
+
+conn clear-or-private
+ type=passthrough
+ right=%opportunisticgroup
+ failureshunt=passthrough
+ keyingtries=3
+ ikelifetime=1h
+ keylife=1h
+ rekey=no
+ also=oe_defaults
+ auto=route
+
+conn private-or-clear
+ type=tunnel
+ right=%opportunisticgroup
+ failureshunt=passthrough
+ keyingtries=3
+ ikelifetime=1h
+ keylife=1h
+ rekey=no
+ also=oe_defaults
+ auto=route
+
+conn private
+ type=tunnel
+ right=%opportunisticgroup
+ failureshunt=drop
+ keyingtries=3
+ ikelifetime=1h
+ keylife=1h
+ rekey=no
+ also=oe_defaults
+ auto=route
+
+conn block
+ type=reject
+ authby=never
+ right=%group
+ also=oe_defaults
+ auto=route
+
+conn oe_defaults
+ left=%defaultroute
+ leftid=%myid
+ leftrsasigkey=%dnsondemand
+ rightrsasigkey=%dnsondemand
diff --git a/programs/ikeping/.cvsignore b/programs/ikeping/.cvsignore
new file mode 100644
index 000000000..755295a5f
--- /dev/null
+++ b/programs/ikeping/.cvsignore
@@ -0,0 +1 @@
+ikeping
diff --git a/programs/ikeping/Makefile b/programs/ikeping/Makefile
new file mode 100644
index 000000000..6c7b31d59
--- /dev/null
+++ b/programs/ikeping/Makefile
@@ -0,0 +1,57 @@
+# Makefile for the KLIPS interface utilities
+# Copyright (C) 1998, 1999 Henry Spencer.
+# Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=ikeping
+LIBS=${FREESWANLIB}
+
+ifeq ($(USE_IKEPING),false)
+NOINSTALL=true
+install:
+ # do nothing
+
+install_file_list:
+ # do nothing
+
+endif
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:27 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.4 2003/06/29 21:34:49 mcr
+# added "NOINSTALL" to omit install: target from common
+# Makefile so that it can be overridden
+#
+# Revision 1.3 2003/06/25 03:57:45 mcr
+# build, but do not install "ikeping" even when we do not
+# want it as part of the system.
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
diff --git a/programs/ikeping/ikeping.8 b/programs/ikeping/ikeping.8
new file mode 100644
index 000000000..a9b80b46d
--- /dev/null
+++ b/programs/ikeping/ikeping.8
@@ -0,0 +1,71 @@
+.TH IPSEC_IKEPING 8 "23 Feb 2002"
+.\" RCSID $Id: ikeping.8,v 1.1 2004/03/15 20:35:27 as Exp $
+.SH NAME
+ipsec ikeping \- send/receive ISAKMP/IKE echo requests/replies
+.SH SYNOPSIS
+.B ipsec
+.B ikeping
+[
+.B \-\-listen
+] [
+.B \-\-verbose
+] [
+.B \-\-wait
+time ] [
+.B \-\-exchangenum
+num ] [
+.B \-\-ikeport
+localport ] [
+.B \-\-ikeaddress
+address ] [
+.B \-\-inet
+] [
+.B \-\-inet6
+] destaddr[/dstport] ...
+.SH DESCRIPTION
+.I Ikeping
+sends and receives ISAKMP/IKE echo request and echo reply packets. These
+packets are intended for diagnostics purposes, in a manner similar to
+.IR ping (8)
+does for ICMP echo request/reply packets.
+.PP
+At the time of this writing, the ISAKMP echo request/reply exchange is still
+an internet-draft, and is therefore completely non-standard.
+.PP
+.I Ikeping
+will bind to the local address given by
+.B \-\-ikeaddress
+and the port number given by
+.B \-\-ikeport
+defaulting to the wildcard address and the ISAKMP port 500. An ISAKMP
+exchange of type 244 (a private use number) is sent to each of the
+address/ports listed on the command line. The exchange number may be
+overridden by the
+.B \-\-exchangenum
+option.
+.PP
+.I Ikeping
+then listens for replies, printing them as they are received. Replies
+are of exchange type 245 or the specified exchange number plus 1.
+.I Ikeping
+will keep listening until it either receives as many echo responses as it sent,
+or until the timeout period (10 seconds) has been reached. Receipt of a
+packet will reset the timer. The
+.B \-\-wait
+option can be used to specify a different timeout period.
+.PP
+If the
+.B \-\-listen
+option is given, then
+.I ikeping
+will not send any packets. Instead, it will listen for them and reply to
+each request received.
+.SH FILES
+no external files
+.SH SEE ALSO
+ping(8), ipsec_pluto(8)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org>
+by Michael Richardson.
+.SH BUGS
diff --git a/programs/ikeping/ikeping.c b/programs/ikeping/ikeping.c
new file mode 100644
index 000000000..7efb26ad7
--- /dev/null
+++ b/programs/ikeping/ikeping.c
@@ -0,0 +1,483 @@
+/* send out an IKE "ping" packet.
+ * Copyright (C) 2002 Michael Richardson
+ * Copyright (C) 2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ikeping.c,v 1.1 2004/03/15 20:35:27 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <assert.h>
+#include <poll.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/packet.h"
+
+#ifndef ISAKMP_XCHG_ECHOREQUEST
+#define ISAKMP_XCHG_ECHOREQUEST 30 /* Echo Request */
+#define ISAKMP_XCHG_ECHOREPLY 31 /* Echo Reply */
+#endif
+
+#ifndef ISAKMP_XCGH_ECHOREQUEST_PRIV
+#define ISAKMP_XCHG_ECHOREQUEST_PRIV 244 /* Private Echo Request */
+#define ISAKMP_XCHG_ECHOREPLY_PRIV 245 /* Private Echo Reply */
+#endif
+
+
+/* what exchange number to use for outgoing requests */
+static int exchange_number;
+
+static void
+help(void)
+{
+ fprintf(stderr,
+ "Usage:\n\n"
+ "ikeping"
+ " [--listen] causes IKEping to open a socket and reply to requests.\n"
+ " [--verbose] causes IKEping to hexdump all packets sent/received.\n"
+ " [--ikeport <port-number>] port to listen on/send from\n"
+ " [--ikeaddress <address>] address to listen on/send from\n"
+ " [--inet] just send/listen on IPv4 socket\n"
+ " [--inet6] just send/listen on IPv6 socket\n"
+ " [--version] just dump version number and exit\n"
+ " [--exchangenum num] use num instead of 244 for the exchange type.\n"
+ " [--wait seconds] time to wait for replies, defaults to 10 seconds.\n"
+ " host/port ...\n\n"
+ "FreeS/WAN %s\n",
+ ipsec_version_code());
+}
+
+static void
+hton_ping(struct isakmp_hdr *ih)
+{
+ u_int32_t *ihp;
+
+ ihp=(u_int32_t *)ih;
+
+ /* put it in network byte order. */
+ /* cookies are byte viewed anyway */
+ ihp[4]=htonl(ihp[4]);
+ ih->isa_msgid = htonl(ih->isa_msgid);
+ ih->isa_length = htonl(ih->isa_length);
+}
+
+static void
+ntoh_ping(struct isakmp_hdr *ih)
+{
+ u_int32_t *ihp;
+
+ ihp=(u_int32_t *)ih;
+
+ /* put it in network byte order. */
+ /* cookies are byte viewed anyway */
+ ihp[4]=ntohl(ihp[4]);
+ ih->isa_msgid = ntohl(ih->isa_msgid);
+ ih->isa_length = ntohl(ih->isa_length);
+}
+
+
+/*
+ * send an IKE ping
+ *
+ */
+static void
+send_ping(int afamily,
+ int s,
+ ip_address *raddr,
+ int rport)
+{
+ struct isakmp_hdr ih;
+ int i, raddrlen;
+
+ raddrlen=0;
+
+ for(i=0; i<COOKIE_SIZE; i++) {
+ ih.isa_icookie[i]=rand()&0xff;
+ }
+
+ for(i=0; i<COOKIE_SIZE; i++) {
+ ih.isa_rcookie[i]=rand()&0xff;
+ }
+
+ ih.isa_np = NOTHING_WRONG;
+ ih.isa_version = (1 << ISA_MAJ_SHIFT) | 0;
+ ih.isa_xchg = (exchange_number ?
+ exchange_number : ISAKMP_XCHG_ECHOREQUEST_PRIV);
+ ih.isa_flags =0;
+ ih.isa_msgid =rand();
+ ih.isa_length=0;
+
+ switch(afamily) {
+ case AF_INET:
+ raddr->u.v4.sin_port = htons(rport);
+ raddrlen=sizeof(raddr->u.v4);
+ break;
+
+ case AF_INET6:
+ raddr->u.v6.sin6_port = htons(rport);
+ raddrlen=sizeof(raddr->u.v6);
+ break;
+ }
+
+ hton_ping(&ih);
+
+ if(sendto(s, &ih, sizeof(ih), 0, (struct sockaddr *)raddr, raddrlen) < 0) {
+ perror("sendto");
+ exit(5);
+ }
+}
+
+/*
+ * send an IKE ping
+ *
+ */
+static void
+reply_packet(int afamily,
+ int s,
+ ip_address *dst_addr,
+ int dst_len,
+ struct isakmp_hdr *op)
+{
+ int i, tmp;
+
+ tmp=afamily; /* shut up compiler */
+
+ for(i=0; i<COOKIE_SIZE; i++) {
+ tmp=op->isa_icookie[i];
+ op->isa_icookie[i]=op->isa_rcookie[i];
+ op->isa_rcookie[i]=tmp;
+ }
+
+ op->isa_np = NOTHING_WRONG;
+ op->isa_version = (1 << ISA_MAJ_SHIFT) | 0;
+ op->isa_xchg = ISAKMP_XCHG_ECHOREPLY;
+ op->isa_flags =0;
+ op->isa_msgid =rand();
+ op->isa_length=0;
+
+ hton_ping(op);
+
+ if(sendto(s, op, sizeof(*op), 0, (struct sockaddr *)dst_addr, dst_len) < 0) {
+ perror("sendto");
+ exit(5);
+ }
+}
+
+/*
+ * receive and decode packet.
+ *
+ */
+static void
+receive_ping(int afamily, int s, int reply)
+{
+ ip_address sender;
+ struct isakmp_hdr ih;
+ char buf[64];
+ int n, rport, sendlen;
+ const char *xchg_name;
+ int xchg;
+
+ rport = 500;
+ xchg = 0;
+ sendlen=sizeof(sender);
+ n = recvfrom(s, &ih, sizeof(ih), 0, (struct sockaddr *)&sender, &sendlen);
+
+ addrtot(&sender, 0, buf, sizeof(buf));
+ switch(afamily) {
+ case AF_INET:
+ rport = sender.u.v4.sin_port;
+ break;
+
+ case AF_INET6:
+ rport = sender.u.v6.sin6_port;
+ break;
+ }
+
+ if((unsigned int)n < sizeof(ih)) {
+ fprintf(stderr, "read short packet (%d) from %s/%d\n",
+ n, buf, rport);
+ return;
+ }
+
+ /* translate from network byte order */
+ ntoh_ping(&ih);
+
+
+ if(ih.isa_xchg == ISAKMP_XCHG_ECHOREQUEST ||
+ ih.isa_xchg == ISAKMP_XCHG_ECHOREQUEST_PRIV ||
+ (exchange_number!=0 && ih.isa_xchg == exchange_number)) {
+ xchg_name="echo-request";
+ xchg=ISAKMP_XCHG_ECHOREQUEST;
+ } else if(ih.isa_xchg == ISAKMP_XCHG_ECHOREPLY ||
+ ih.isa_xchg == ISAKMP_XCHG_ECHOREPLY_PRIV ||
+ (exchange_number!=0 && ih.isa_xchg == exchange_number+1)) {
+ xchg_name="echo-reply";
+ } else {
+ xchg_name="";
+ }
+
+ printf("received %d(%s) packet from %s/%d of len: %d\n",
+ ih.isa_xchg, xchg_name, buf, ntohs(rport), n);
+ printf("\trcookie=%08x_%08x icookie=%08x_%08x msgid=%08x\n",
+ *(u_int32_t *)(ih.isa_icookie),
+ *(u_int32_t *)(ih.isa_icookie+4),
+ *(u_int32_t *)(ih.isa_rcookie),
+ *(u_int32_t *)(ih.isa_rcookie+4),
+ ih.isa_msgid);
+ printf("\tnp=%03d version=%d.%d xchg=%s(%d)\n",
+ ih.isa_np,
+ ih.isa_version >> ISA_MAJ_SHIFT,
+ ih.isa_version & ISA_MIN_MASK,
+ xchg_name,
+ ih.isa_xchg);
+
+ if(reply && xchg==ISAKMP_XCHG_ECHOREQUEST) {
+ reply_packet(afamily, s, &sender, sendlen, &ih);
+ }
+}
+
+static const struct option long_opts[] = {
+ /* name, has_arg, flag, val */
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "listen", no_argument, NULL, 's' },
+ { "ikeport", required_argument, NULL, 'p' },
+ { "ikeaddress", required_argument, NULL, 'b' },
+ { "inet", no_argument, NULL, '4' },
+ { "inet6", no_argument, NULL, '6' },
+ { "exchangenum", required_argument, NULL, 'n' },
+ { "wait", required_argument, NULL, 'w' },
+ { 0,0,0,0 }
+};
+
+int
+main(int argc, char **argv)
+{
+ char *foo;
+ const char *errstr;
+ int s;
+ int listen_only;
+ int lport,dport;
+ int afamily;
+ int pfamily;
+ int c;
+ int numSenders, numReceived, noDNS;
+ int waitTime;
+ int verbose, timedOut;
+ ip_address laddr, raddr;
+
+ afamily=AF_INET;
+ pfamily=PF_INET;
+ lport=500;
+ dport=500;
+ waitTime=10;
+ verbose=0;
+ listen_only=0;
+ noDNS=0;
+ bzero(&laddr, sizeof(laddr));
+
+ while((c = getopt_long(argc, argv, "hVnvsp:b:46E:w:", long_opts, 0))!=EOF) {
+ switch (c) {
+ case 'h': /* --help */
+ help();
+ return 0; /* GNU coding standards say to stop here */
+
+ case 'V': /* --version */
+ fprintf(stderr, "FreeS/WAN %s\n", ipsec_version_code());
+ return 0; /* GNU coding standards say to stop here */
+
+ case 'v': /* --label <string> */
+ verbose++;
+ continue;
+
+ case 'n':
+ noDNS=1;
+ break;
+
+ case 'E':
+ exchange_number=strtol(optarg, &foo, 0);
+ if(optarg==foo || exchange_number < 1 || exchange_number>255) {
+ fprintf(stderr, "Invalid exchange number '%s' (should be 1<=x<255)\n",
+ optarg);
+ exit(1);
+ }
+ continue;
+
+
+ case 's':
+ listen_only++;
+ continue;
+
+ case 'p':
+ lport=strtol(optarg, &foo, 0);
+ if(optarg==foo || lport <0 || lport>65535) {
+ fprintf(stderr, "Invalid port number '%s' (should be 0<=x<65536)\n",
+ optarg);
+ exit(1);
+ }
+ continue;
+
+ case 'w':
+ waitTime=strtol(optarg, &foo, 0);
+ if(optarg==foo || waitTime < 0) {
+ fprintf(stderr, "Invalid waittime number '%s' (should be 0<=x)\n",
+ optarg);
+ exit(1);
+ }
+ continue;
+
+ case 'b':
+ errstr = ttoaddr(optarg, strlen(optarg), afamily, &laddr);
+ if(errstr!=NULL) {
+ fprintf(stderr, "Invalid local address '%s': %s\n",
+ optarg, errstr);
+ exit(1);
+ }
+ continue;
+
+ case '4':
+ afamily=AF_INET;
+ pfamily=PF_INET;
+ continue;
+
+ case '6':
+ afamily=AF_INET6;
+ pfamily=PF_INET6;
+ continue;
+
+ default:
+ assert(FALSE); /* unknown return value */
+ }
+ }
+
+ s=socket(pfamily, SOCK_DGRAM, IPPROTO_UDP);
+ if(s < 0) {
+ perror("socket");
+ exit(3);
+ }
+
+ switch(afamily) {
+ case AF_INET:
+ laddr.u.v4.sin_port = htons(lport);
+ if(bind(s, (struct sockaddr *)&laddr.u.v4, sizeof(laddr.u.v4)) < 0) {
+ perror("v4 bind");
+ exit(5);
+ }
+ break;
+
+ case AF_INET6:
+ laddr.u.v6.sin6_port = htons(lport);
+ if(bind(s, (struct sockaddr *)&laddr.u.v6, sizeof(laddr.u.v6)) < 0) {
+ perror("v6 bind");
+ exit(5);
+ }
+ break;
+ }
+
+ numSenders = 0;
+
+ if(!listen_only) {
+ while(optind < argc) {
+ char *port;
+ char *host;
+ char namebuf[128];
+
+ host = argv[optind];
+
+ port = strchr(host, '/');
+ dport=500;
+ if(port) {
+ *port='\0';
+ port++;
+ dport= strtol(port, &foo, 0);
+ if(port==foo || dport < 0 || dport > 65535) {
+ fprintf(stderr, "Invalid port number '%s' "
+ "(should be 0<=x<65536)\n",
+ port);
+ exit(1);
+ }
+ }
+
+ errstr = ttoaddr(host, strlen(host),
+ afamily, &raddr);
+ if(errstr!=NULL) {
+ fprintf(stderr, "Invalid remote address '%s': %s\n",
+ host, errstr);
+ exit(1);
+ }
+
+ addrtot(&raddr, 0, namebuf, sizeof(namebuf));
+
+ printf("Sending packet to %s/%d\n", namebuf, dport);
+
+ send_ping(afamily, s, &raddr, dport);
+ numSenders++;
+ optind++;
+ }
+ }
+
+ timedOut = 0;
+ numReceived=0;
+
+ /* really should catch ^C and print stats on exit */
+ while(numSenders > 0 || listen_only) {
+ struct pollfd ready;
+ int n;
+
+ ready.fd = s;
+ ready.events = POLLIN;
+
+ n = poll(&ready, 1, waitTime);
+ if(n < 0) {
+ perror("poll");
+ exit(1);
+ }
+
+ if(n == 0 && !listen_only) {
+ break;
+ }
+
+ if(n == 1) {
+ numReceived++;
+ receive_ping(afamily, s, listen_only);
+ }
+ }
+
+ if(numReceived > 0) {
+ printf("%d packets sent, %d packets received. %d packet loss\n",
+ numSenders, numReceived, numSenders*100/numReceived);
+ }
+ exit(0);
+}
+
+/*
+ * Local variables:
+ * c-file-style: "linux"
+ * c-basic-offset: 4
+ * End:
+ *
+ */
diff --git a/programs/ipsec/.cvsignore b/programs/ipsec/.cvsignore
new file mode 100644
index 000000000..70025a7f8
--- /dev/null
+++ b/programs/ipsec/.cvsignore
@@ -0,0 +1 @@
+ipsec
diff --git a/programs/ipsec/Makefile b/programs/ipsec/Makefile
new file mode 100644
index 000000000..fdff3728a
--- /dev/null
+++ b/programs/ipsec/Makefile
@@ -0,0 +1,28 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.2 2006/02/10 11:27:31 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=ipsec
+PROGRAMDIR=${SBINDIR}
+MANPROGPREFIX:=./
+LIBFILES:=$(wildcard distro.txt)
+
+include ../Makefile.program
+
+install:: ipsec
+ @$(INSTALL) $(INSTBINFLAGS) ipsec $(RCDIR)/ipsec
+
diff --git a/programs/ipsec/distro.txt b/programs/ipsec/distro.txt
new file mode 100644
index 000000000..80f4192a4
--- /dev/null
+++ b/programs/ipsec/distro.txt
@@ -0,0 +1 @@
+distributed by Andreas Steffen <andreas.steffen@strongswan.org>
diff --git a/programs/ipsec/ipsec.8 b/programs/ipsec/ipsec.8
new file mode 100644
index 000000000..823289372
--- /dev/null
+++ b/programs/ipsec/ipsec.8
@@ -0,0 +1,336 @@
+.TH IPSEC 8 "9 February 2006"
+.\" RCSID $Id: ipsec.8,v 1.3 2006/02/09 19:47:38 as Exp $
+.SH NAME
+ipsec \- invoke IPsec utilities
+.SH SYNOPSIS
+.B ipsec
+command [ argument ...]
+.sp
+.B ipsec start|update|reload|restart|stop
+.sp
+.B ipsec up|down|route|unroute
+\fIconnectionname\fP
+.sp
+.B ipsec status|statusall
+[
+\fIconnectionname\fP
+]
+.sp
+.B ipsec listalgs|listpubkeys|listcerts
+[
+.B \-\-utc
+]
+.br
+.B ipsec listcacerts|listaacerts|listocspcerts
+[
+.B \-\-utc
+]
+.br
+.B ipsec listacerts|listgroups|listcainfos
+[
+.B \-\-utc
+]
+.br
+.B ipsec listcrls|listocsp|listcards|listall
+[
+.B \-\-utc
+]
+.sp
+.B ipsec rereadsecrets|rereadgroups
+.br
+.B ipsec rereadcacerts|rereadaacerts|rereadocspcerts
+.br
+.B ipsec rereadacerts|rereadcrls|rereadall
+.sp
+.B ipsec purgeocsp
+.sp
+.B ipsec
+[
+.B \-\-help
+] [
+.B \-\-version
+] [
+.B \-\-versioncode
+] [
+.B \-\-copyright
+]
+.br
+.B ipsec
+[
+.B \-\-directory
+] [
+.B \-\-confdir
+]
+.SH DESCRIPTION
+.I Ipsec
+invokes any of several utilities involved in controlling the IPsec
+encryption/authentication system,
+running the specified
+.I command
+with the specified
+.IR argument s
+as if it had been invoked directly.
+This largely eliminates possible name collisions with other software,
+and also permits some centralized services.
+.PP
+The commands
+.BR start ,
+.BR update ,
+.BR reload ,
+.BR restart ,
+and
+.BR stop
+are built-in and are used to control the
+.BR "ipsec starter"
+utility, an extremely fast replacement for the traditional
+.BR ipsec
+.BR setup
+script.
+.PP
+The commands
+.BR up,
+.BR down,
+.BR route,
+.BR unroute,
+.BR status,
+.BR statusall,
+.BR listalgs,
+.BR listpubkeys,
+.BR listcerts,
+.BR listcacerts,
+.BR listaacerts,
+.BR listocspcerts,
+.BR listacerts,
+.BR listgroups,
+.BR listcainfos,
+.BR listcrls,
+.BR listocsp,
+.BR listcards,
+.BR listall,
+.BR rereadsecrets,
+.BR rereadgroups,
+.BR rereadcacerts,
+.BR rereadaacerts,
+.BR rereadocspcerts,
+.BR rereadacerts,
+.BR rereadcrls,
+and
+.BR rereadall
+are also built-in and completely replace the corresponding
+.BR "ipsec auto"
+\-\-\fIoperation\fP"
+commands. Communication with the pluto daemon happens via the
+.BR "ipsec whack"
+socket interface.
+.PP
+In particular,
+.I ipsec
+supplies the invoked
+.I command
+with a suitable PATH environment variable,
+and also provides IPSEC_DIR,
+IPSEC_CONFS, and IPSEC_VERSION environment variables,
+containing respectively
+the full pathname of the directory where the IPsec utilities are stored,
+the full pathname of the directory where the configuration files live,
+and the IPsec version number.
+.PP
+.B "ipsec start"
+calls
+.BR "ipsec starter"
+which in turn starts \fIpluto\fR.
+.PP
+.B "ipsec update"
+sends a \fIHUP\fR signal to
+.BR "ipsec starter"
+which in turn determines any changes in \fIipsec.conf\fR
+and updates the configuration on the running \fIpluto\fR daemon, correspondingly.
+.PP
+.B "ipsec reload"
+sends a \fIUSR1\fR signal to
+.BR "ipsec starter"
+which in turn reloads the whole configuration on the running \fIpluto\fR daemon
+based on the actual \fIipsec.conf\fR.
+.PP
+.B "ipsec restart"
+executes
+.B "ipsec stop"
+followed by
+.BR "ipsec start".
+.PP
+.B "ipsec stop"
+stops \fIipsec\fR by sending a \fITERM\fR signal to
+.BR "ipsec starter".
+.PP
+.B "ipsec up"
+\fIname\fP tells the \fIpluto\fP daemon to start up connection \fIname\fP.
+.PP
+.B "ipsec down"
+\fIname\fP tells the \fIpluto\fP daemon to take down connection \fIname\fP.
+.PP
+.B "ipsec route"
+\fIname\fP tells the \fIpluto\fP daemon to install a route for connection
+\fIname\fP.
+.PP
+.B "ipsec unroute"
+\fIname\fP tells the \fIpluto\fP daemon to take down the route for connection
+\fIname\fP.
+.PP
+.B "ipsec status"
+[ \fIname\fP ] gives concise status information either on connection
+\fIname\fP or if the \fIname\fP argument is lacking, on all connections.
+.PP
+.B "ipsec statusall"
+[ \fIname\fP ] gives detailed status information either on connection
+\fIname\fP or if the \fIname\fP argument is lacking, on all connections.
+.PP
+.B "ipsec listalgs"
+returns a list all supported IKE encryption and hash algorithms, the available
+Diffie-Hellman groups, as well as all supported ESP encryption and authentication
+algorithms.
+.PP
+.B "ipsec listpubkeys"
+returns a list of RSA public keys that were either loaded in raw key format
+or extracted from X.509 and|or OpenPGP certificates.
+.PP
+.B "ipsec listcerts"
+returns a list of X.509 and|or OpenPGP certificates that were loaded locally
+by the \fIpluto\fP daemon.
+.PP
+.B "ipsec listcacerts"
+returns a list of X.509 Certification Authority (CA) certificates that were
+loaded locally by the \fIpluto\fP daemon from the \fI/etc/ipsec.d/cacerts/\fP
+directory or received in PKCS#7-wrapped certificate payloads via the IKE
+protocol.
+.PP
+.B "ipsec listaacerts"
+returns a list of X.509 Authorization Authority (AA) certificates that were
+loaded locally by the \fIpluto\fP daemon from the \fI/etc/ipsec.d/aacerts/\fP
+directory.
+.PP
+.B "ipsec listocspcerts"
+returns a list of X.509 OCSP Signer certificates that were either loaded
+locally by the \fIpluto\fP daemon from the \fI/etc/ipsec.d/ocspcerts/\fP
+directory or were sent by an OCSP server.
+.PP
+.B "ipsec listacerts"
+returns a list of X.509 Attribute certificates that were loaded locally by
+the \fIpluto\fP daemon from the \fI/etc/ipsec.d/acerts/\fP directory.
+.PP
+.B "ipsec listgroups"
+returns a list of groups that are used to define user authorization profiles.
+.PP
+.B "ipsec listcainfos"
+returns certification authority information (CRL distribution points, OCSP URIs,
+LDAP servers) that were defined by
+.BR ca
+sections in \fIipsec.conf\fP.
+.PP
+.B "ipsec listcrls"
+returns a list of Certificate Revocation Lists (CRLs).
+.PP
+.B "ipsec listocsp"
+returns revocation information fetched from OCSP servers.
+.PP
+.B "ipsec listcards"
+returns a list of certificates residing on smartcards.
+.PP
+.B "ipsec listall"
+returns all information generated by the list commands above. Each list command
+can be called with the
+\-\-url
+option which displays all dates in UTC instead of local time.
+.PP
+.B "ipsec rereadsecrets"
+flushes and rereads all secrets defined in \fIipsec.conf\fP.
+.PP
+.B "ipsec rereadcacerts"
+reads all certificate files contained in the \fI/etc/ipsec.d/cacerts\fP
+directory and adds them to \fIpluto\fP's list of Certification Authority (CA) certificates.
+.PP
+.B "ipsec rereadaacerts"
+reads all certificate files contained in the \fI/etc/ipsec.d/aacerts\fP
+directory and adds them to \fIpluto\fP's list of Authorization Authority (AA) certificates.
+.PP
+.B "ipsec rereadocspcerts"
+reads all certificate files contained in the \fI/etc/ipsec.d/ocspcerts/\fP
+directory and adds them to \fIpluto\fP's list of OCSP signer certificates.
+.PP
+.B "ipsec rereadacerts"
+operation reads all certificate files contained in the \fI/etc/ipsec.d/acerts/\fP
+directory and adds them to \fIpluto\fP's list of attribute certificates.
+.PP
+.B "ipsec rereadcrls"
+reads all Certificate Revocation Lists (CRLs) contained in the
+\fI/etc/ipsec.d/crls/\fP directory and adds them to \fIpluto\fP's list of CRLs.
+.PP
+.B "ipsec rereadall"
+is equivalent to the execution of \fBrereadsecrets\fP,
+\fBrereadcacerts\fP, \fBrereadaacerts\fP, \fBrereadocspcerts\fP,
+\fBrereadacerts\fP, and \fBrereadcrls\fP.
+.PP
+.B "ipsec \-\-help"
+lists the available commands.
+Most have their own manual pages, e.g.
+.IR ipsec_auto (8)
+for
+.IR auto .
+.PP
+.B "ipsec \-\-version"
+outputs version information about Linux strongSwan.
+A version code of the form ``U\fIxxx\fR/K\fIyyy\fR''
+indicates that the user-level utilities are version \fIxxx\fR
+but the kernel portion appears to be version \fIyyy\fR
+(this form is used only if the two disagree).
+.PP
+.B "ipsec \-\-versioncode"
+outputs \fIjust\fR the version code,
+with none of
+.BR \-\-version 's
+supporting information,
+for use by scripts.
+.PP
+.B "ipsec \-\-copyright"
+supplies boring copyright details.
+.PP
+.B "ipsec \-\-directory"
+reports where
+.I ipsec
+thinks the IPsec utilities are stored.
+.PP
+.B "ipsec \-\-confdir"
+reports where
+.I ipsec
+thinks the IPsec configuration files are stored.
+.SH FILES
+/usr/local/lib/ipsec usual utilities directory
+.SH ENVIRONMENT
+.PP
+The following environment variables control where strongSwan finds its
+components.
+The
+.B ipsec
+command sets them if they are not already set.
+.nf
+.na
+IPSEC_EXECDIR directory containing published commands
+IPSEC_LIBDIR directory containing internal executables
+IPSEC_SBINDIR directory containing \fBipsec\fP command
+IPSEC_CONFS directory containing configuration files
+.ad
+.fi
+.SH SEE ALSO
+.hy 0
+.na
+ipsec.conf(5), ipsec.secrets(5),
+ipsec_barf(8),
+.ad
+.hy
+.PP
+.SH HISTORY
+Written for Linux FreeS/WAN
+<http://www.freeswan.org>
+by Henry Spencer.
+Updated and extended for Linux strongSwan
+<http://www.strongswan.org>
+by Andreas Steffen.
diff --git a/programs/ipsec/ipsec.in b/programs/ipsec/ipsec.in
new file mode 100755
index 000000000..0616561d8
--- /dev/null
+++ b/programs/ipsec/ipsec.in
@@ -0,0 +1,244 @@
+#! /bin/sh
+# prefix command to run stuff from our programs directory
+# Copyright (C) 1998-2002 Henry Spencer.
+#
+# 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: ipsec.in,v 1.13 2006/03/09 20:09:33 as Exp $
+
+IPSEC_NAME=strongSwan
+
+# where the private directory and the config files are
+IPSEC_EXECDIR="${IPSEC_EXECDIR-@IPSEC_EXECDIR@}"
+IPSEC_LIBDIR="${IPSEC_LIBDIR-@IPSEC_LIBDIR@}"
+IPSEC_SBINDIR="${IPSEC_SBINDIR-@IPSEC_SBINDIR@}"
+IPSEC_CONFS="${IPSEC_CONFS-@IPSEC_CONFS@}"
+
+IPSEC_DIR="$IPSEC_LIBDIR"
+export IPSEC_DIR IPSEC_CONFS IPSEC_LIBDIR IPSEC_EXECDIR
+
+IPSEC_STARTER_PID="/var/run/starter.pid"
+
+# standardize PATH, and export it for everything else's benefit
+PATH="${IPSEC_SBINDIR}":/sbin:/usr/sbin:/usr/local/bin:/bin:/usr/bin
+export PATH
+
+# things not to be listed in --help command list
+DONTMENTION='^(ipsec|_.*|.*\.old|.*~)$'
+
+# version numbering (details filled in by build)
+# Possibly should call a C program to invoke the version_code() function
+# instead, but for performance's sake, we inline it here (and only here).
+version="xxx"
+
+# export the version information
+IPSEC_VERSION="$version"
+export IPSEC_VERSION
+
+# function for the funky user/kernel version stuff
+fixversion() {
+ if test -f /proc/net/ipsec_version
+ then
+ stack=" (KLIPS)"
+ kv="`awk '{print $NF}' /proc/net/ipsec_version`"
+ else
+ if test -f /proc/net/pfkey
+ then
+ stack=" (native)"
+ kv="`uname -r`"
+ else
+ kv="(no kernel code presently loaded)"
+ fi
+ fi
+ if test " $kv" != " $version"
+ then
+ version="U$version/K$kv"
+ fi
+ version="$version$stack"
+}
+
+case "$1" in
+'')
+ echo "Usage: ipsec command argument ..."
+ echo "Use --help for list of commands, or see ipsec(8) manual page"
+ echo "or the $IPSEC_NAME documentation for names of the common ones."
+ echo "Most have their own manual pages, e.g. ipsec_auto(8)."
+ echo "See <http://www.strongswan.org> for more general info."
+ exit 0
+ ;;
+--help)
+ echo "Usage: ipsec command argument ..."
+ echo "where command is one of:"
+ echo " start|restart arguments..."
+ echo " update|reload|stop"
+ echo " up|down|route|unroute <connectionname>"
+ echo " status|statusall [<connectionname>]"
+ echo " ready"
+ echo " listalgs|listpubkeys|listcerts [--utc]"
+ echo " listcacerts|listaacerts|listocspcerts [--utc]"
+ echo " listacerts|listgroups|listcainfos [--utc]"
+ echo " listcrls|listocsp|listcards|listall [--utc]"
+ echo " rereadsecrets|rereadgroups"
+ echo " rereadcacerts|rereadaacerts|rereadocspcerts"
+ echo " rereadacerts|rereadcrls|rereadall"
+ echo " purgeocsp"
+ echo " scencrypt|scdecrypt <value> [--inbase <base>] [--outbase <base>] [--keyid <id>]"
+ echo " barf"
+ echo " openac"
+ echo " pluto"
+ echo " scepclient"
+ echo " secrets"
+ echo " starter"
+ echo " version"
+ echo " whack"
+ echo
+ echo "Some of these functions have their own manual pages, e.g. ipsec_scepclient(8)."
+ exit 0
+ ;;
+--versioncode)
+ fixversion
+ echo "$version"
+ exit 0
+ ;;
+--copyright)
+ set _copyright
+ # and fall through, invoking "ipsec _copyright"
+ ;;
+--directory)
+ echo "$IPSEC_DIR"
+ exit 0
+ ;;
+--confdir)
+ echo "$IPSEC_CONFS"
+ exit 0
+ ;;
+down)
+ shift
+ $IPSEC_EXECDIR/whack --name "$1" --terminate
+ exit 0
+ ;;
+listalgs|listpubkeys|listcerts|listcacerts|\
+listaacerts|listocspcerts|listacerts|listgroups|\
+listcainfos|listcrls|listocsp|listcards|\
+listall|purgeocsp|rereadsecrets|rereadgroups|\
+rereadcacerts|rereadaacerts|rereadocspcerts|\
+rereadacerts|rereadcrls|rereadall)
+ op="$1"
+ shift
+ $IPSEC_EXECDIR/whack "$@" "--$op"
+ exit 0
+ ;;
+ready)
+ shift
+ $IPSEC_EXECDIR/whack --listen
+ exit 0
+ ;;
+reload)
+ if test -e $IPSEC_STARTER_PID
+ then
+ echo "Reloading strongSwan IPsec configuration..." >&2
+ kill -s USR1 `cat $IPSEC_STARTER_PID`
+ else
+ echo "ipsec starter is not running" >&2
+ fi
+ exit 0
+ ;;
+restart)
+ $IPSEC_SBINDIR/ipsec stop
+ sleep 2
+ shift
+ $IPSEC_SBINDIR/ipsec start "$@"
+ exit 0
+ ;;
+route|unroute)
+ op="$1"
+ shift
+ $IPSEC_EXECDIR/whack --name "$1" "--$op"
+ exit 0
+ ;;
+scencrypt|scdecrypt)
+ op="$1"
+ shift
+ $IPSEC_EXECDIR/whack "--$op" "$@"
+ exit 0
+ ;;
+start)
+ shift
+ exec $IPSEC_EXECDIR/starter "$@"
+ ;;
+status|statusall)
+ op="$1"
+ shift
+ if test $# -eq 0
+ then
+ $IPSEC_EXECDIR/whack "--$op"
+ else
+ $IPSEC_EXECDIR/whack --name "$1" "--$op"
+ fi
+ exit 0
+ ;;
+stop)
+ if test -e $IPSEC_STARTER_PID
+ then
+ echo "Stopping strongSwan IPsec..." >&2
+ kill `cat $IPSEC_STARTER_PID`
+ else
+ echo "ipsec starter is not running" >&2
+ fi
+ exit 0
+ ;;
+up)
+ shift
+ $IPSEC_EXECDIR/whack --name "$1" --initiate
+ exit 0
+ ;;
+update)
+ if test -e $IPSEC_STARTER_PID
+ then
+ echo "Updating strongSwan IPsec configuration..." >&2
+ kill -s HUP `cat $IPSEC_STARTER_PID`
+ else
+ echo "ipsec starter is not running" >&2
+ fi
+ exit 0
+ ;;
+version|--version)
+ fixversion
+ echo "Linux $IPSEC_NAME $version"
+ echo "See \`ipsec --copyright' for copyright information."
+ if [ -f $IPSEC_LIBDIR/distro.txt ]
+ then
+ cat $IPSEC_LIBDIR/distro.txt
+ fi
+ exit 0
+ ;;
+--*)
+ echo "$0: unknown option \`$1' (perhaps command name was omitted?)" >&2
+ exit 1
+ ;;
+esac
+
+cmd="$1"
+shift
+
+path="$IPSEC_EXECDIR/$cmd"
+
+if test ! -x "$path"
+then
+ path="$IPSEC_LIBDIR/$cmd"
+ if test ! -x "$path"
+ then
+ echo "$0: unknown IPsec command \`$cmd' (\`ipsec --help' for list)" >&2
+ exit 1
+ fi
+fi
+
+exec $path "$@"
diff --git a/programs/klipsdebug/.cvsignore b/programs/klipsdebug/.cvsignore
new file mode 100644
index 000000000..03c1d474c
--- /dev/null
+++ b/programs/klipsdebug/.cvsignore
@@ -0,0 +1 @@
+klipsdebug
diff --git a/programs/klipsdebug/Makefile b/programs/klipsdebug/Makefile
new file mode 100644
index 000000000..6c98e7592
--- /dev/null
+++ b/programs/klipsdebug/Makefile
@@ -0,0 +1,80 @@
+# Makefile for the KLIPS interface utilities
+# Copyright (C) 1998, 1999 Henry Spencer.
+# Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:28 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM:=klipsdebug
+EXTRA5PROC=${PROGRAM}.5
+
+LIBS:=${FREESWANLIB}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:28 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 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.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.
+#
+#
+#
+
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:28 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 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.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/klipsdebug/klipsdebug.5 b/programs/klipsdebug/klipsdebug.5
new file mode 100644
index 000000000..8e5f985f0
--- /dev/null
+++ b/programs/klipsdebug/klipsdebug.5
@@ -0,0 +1,138 @@
+.TH IPSEC_KLIPSDEBUG 5 "26 Jun 2000"
+.\"
+.\" RCSID $Id: klipsdebug.5,v 1.1 2004/03/15 20:35:28 as Exp $
+.\"
+.SH NAME
+ipsec_klipsdebug \- list KLIPS (kernel IPSEC support) debug features and level
+.SH SYNOPSIS
+.B ipsec
+.B klipsdebug
+.PP
+.B cat
+.B /proc/net/ipsec_klipsdebug
+.SH DESCRIPTION
+.I /proc/net/ipsec_klipsdebug
+lists flags that control various parts of the debugging output of Klips
+(the kernel portion of FreeS/WAN IPSEC).
+At this point it is a read-only file.
+.PP
+A table entry consists of:
+.IP + 3
+a KLIPS debug variable
+.IP +
+a '=' separator for visual and automated parsing between the variable
+name and its current value
+.IP +
+hexadecimal bitmap of variable's flags.
+.PP
+The variable names roughly describe the scope of the debugging variable.
+Currently, no flags are documented or individually accessible yet except
+tunnel-xmit.
+.ne 5
+.PP
+The variable names are:
+.TP 8
+.B tunnel
+tunnelling code
+.TP
+.B netlink
+userspace communication code (obsolete)
+.TP
+.B xform
+transform selection and manipulation code
+.TP
+.B eroute
+eroute table manipulation code
+.TP
+.B spi
+SA table manipulation code
+.TP
+.B radij
+radij tree manipulation code
+.TP
+.B esp
+encryptions transforms code
+.TP
+.B ah
+authentication transforms code
+.TP
+.B rcv
+receive code
+.TP
+.B ipcomp
+ip compression transforms code
+.TP
+.B verbose
+give even more information, beware this will probably trample the 4k kernel printk buffer giving inaccurate output
+.PP
+All KLIPS debug output appears as
+.B kernel.info
+messages to
+.IR syslogd (8).
+Most systems are set up
+to log these messages to
+.IR /var/log/messages .
+.PP
+.SH EXAMPLES
+.LP
+.B debug_tunnel=00000010.
+.br
+.B debug_netlink=00000000.
+.br
+.B debug_xform=00000000.
+.br
+.B debug_eroute=00000000.
+.br
+.B debug_spi=00000000.
+.br
+.B debug_radij=00000000.
+.br
+.B debug_esp=00000000.
+.br
+.B debug_ah=00000000.
+.br
+.B debug_rcv=00000000.
+.br
+.B debug_pfkey=ffffffff.
+.LP
+means that one
+.B tunnel
+flag has been set (tunnel-xmit),
+full
+.B pfkey
+sockets debugging has been set and everything else is not set.
+.LP
+.SH FILES
+/proc/net/ipsec_klipsdebug, /usr/local/bin/ipsec
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_tncfg(8), ipsec_eroute(8),
+ipsec_spi(8), ipsec_spigrp(8), ipsec_klipsdebug(5), ipsec_version(5),
+ipsec_pf_key(5)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Richard Guy Briggs.
+.\"
+.\" $Log: klipsdebug.5,v $
+.\" Revision 1.1 2004/03/15 20:35:28 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.5 2002/04/24 07:35:38 mcr
+.\" Moved from ./klips/utils/klipsdebug.5,v
+.\"
+.\" Revision 1.4 2000/10/10 20:10:19 rgb
+.\" Added support for debug_ipcomp and debug_verbose to klipsdebug.
+.\"
+.\" 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/klipsdebug/klipsdebug.8 b/programs/klipsdebug/klipsdebug.8
new file mode 100644
index 000000000..60d018eec
--- /dev/null
+++ b/programs/klipsdebug/klipsdebug.8
@@ -0,0 +1,164 @@
+.TH IPSEC_KLIPSDEBUG 8 "21 Jun 2000"
+.\"
+.\" RCSID $Id: klipsdebug.8,v 1.1 2004/03/15 20:35:28 as Exp $
+.\"
+.SH NAME
+ipsec klipsdebug \- set KLIPS (kernel IPSEC support) debug features and level
+.SH SYNOPSIS
+.B ipsec
+.B klipsdebug
+.PP
+.B ipsec
+.B klipsdebug
+.B \-\-set
+flagname
+.PP
+.B ipsec
+.B klipsdebug
+.B \-\-clear
+flagname
+.PP
+.B ipsec
+.B klipsdebug
+.B \-\-all
+.PP
+.B ipsec
+.B klipsdebug
+.B \-\-none
+.PP
+.B ipsec
+.B klipsdebug
+.B \-\-help
+.PP
+.B ipsec
+.B klipsdebug
+.B \-\-version
+.SH DESCRIPTION
+.I Klipsdebug
+sets and clears flags that control
+various parts of the debugging output of Klips
+(the kernel portion of FreeS/WAN IPSEC).
+The form with no additional arguments lists the present contents of
+/proc/net/ipsec_klipsdebug.
+The
+.B \-\-set
+form turns the specified flag on,
+while the
+.B \-\-clear
+form turns the specified flag off.
+The
+.B \-\-all
+form
+turns all flags on except verbose, while the
+.B \-\-none
+form turns all flags off.
+.PP
+The current flag names are:
+.TP 8
+.B tunnel
+tunnelling code
+.TP
+.B tunnel-xmit
+tunnelling transmit only code
+.TP
+.B pfkey
+userspace communication code
+.TP
+.B xform
+transform selection and manipulation code
+.TP
+.B eroute
+eroute table manipulation code
+.TP
+.B spi
+SA table manipulation code
+.TP
+.B radij
+radij tree manipulation code
+.TP
+.B esp
+encryptions transforms code
+.TP
+.B ah
+authentication transforms code
+.B rcv
+receive code
+.TP
+.B ipcomp
+ip compression transforms code
+.TP
+.B verbose
+give even more information, BEWARE:
+a)this will print authentication and encryption keys in the logs
+b)this will probably trample the 4k kernel printk buffer giving inaccurate output
+.PP
+All Klips debug output appears as
+.B kernel.info
+messages to
+.IR syslogd (8).
+Most systems are set up
+to log these messages to
+.IR /var/log/messages .
+Beware that
+.B klipsdebug
+.B \-\-all
+produces a lot of output and the log file will grow quickly.
+.PP
+The file format for /proc/net/ipsec_klipsdebug is discussed in
+ipsec_klipsdebug(5).
+.SH EXAMPLES
+.TP
+.B klipsdebug \-\-all
+turns on all KLIPS debugging except verbose.
+.TP
+.B klipsdebug \-\-clear tunnel
+turns off only the
+.B tunnel
+debugging messages.
+.LP
+.SH FILES
+/proc/net/ipsec_klipsdebug, /usr/local/bin/ipsec
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_tncfg(8), ipsec_eroute(8),
+ipsec_spi(8), ipsec_spigrp(8), ipsec_klipsdebug(5)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Richard Guy Briggs.
+.SH BUGS
+It really ought to be possible to set or unset selective combinations
+of flags.
+.\"
+.\" $Log: klipsdebug.8,v $
+.\" Revision 1.1 2004/03/15 20:35:28 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.18 2002/04/24 07:35:39 mcr
+.\" Moved from ./klips/utils/klipsdebug.8,v
+.\"
+.\" Revision 1.17 2000/10/10 20:10:19 rgb
+.\" Added support for debug_ipcomp and debug_verbose to klipsdebug.
+.\"
+.\" Revision 1.16 2000/08/18 17:33:11 rgb
+.\" Updated obsolete netlink reference and added pfkey and tunnel-xmit.
+.\"
+.\" Revision 1.15 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.14 2000/06/28 05:53:09 rgb
+.\" Mention that netlink is obsolete.
+.\"
+.\" Revision 1.13 2000/06/21 16:54:58 rgb
+.\" Added 'no additional args' text for listing contents of
+.\" /proc/net/ipsec_* files.
+.\"
+.\" Revision 1.12 1999/07/19 18:47:24 henry
+.\" fix slightly-misformed comments
+.\"
+.\" Revision 1.11 1999/04/06 04:54:37 rgb
+.\" Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+.\" patch shell fixes.
+.\"
+.\"
diff --git a/programs/klipsdebug/klipsdebug.c b/programs/klipsdebug/klipsdebug.c
new file mode 100644
index 000000000..c205038a1
--- /dev/null
+++ b/programs/klipsdebug/klipsdebug.c
@@ -0,0 +1,436 @@
+/*
+ * control KLIPS debugging options
+ * Copyright (C) 1996 John Ioannidis.
+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * 2001 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+char klipsdebug_c_version[] = "RCSID $Id: klipsdebug.c,v 1.2 2004/06/07 15:16:34 as Exp $";
+
+
+#include <sys/types.h>
+#include <linux/types.h> /* new */
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h> /* system(), strtoul() */
+#include <sys/stat.h> /* open() */
+#include <fcntl.h> /* open() */
+
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+
+#include <unistd.h>
+#include <freeswan.h>
+#if 0
+#include <linux/autoconf.h> /* CONFIG_IPSEC_PFKEYv2 */
+#endif
+
+/* permanently turn it on since netlink support has been disabled */
+#include <signal.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#ifndef CONFIG_IPSEC_DEBUG
+#define CONFIG_IPSEC_DEBUG
+#endif /* CONFIG_IPSEC_DEBUG */
+#include "freeswan/ipsec_tunnel.h"
+
+#include <stdio.h>
+#include <getopt.h>
+
+__u32 bigbuf[1024];
+char *program_name;
+
+int pfkey_sock;
+fd_set pfkey_socks;
+uint32_t pfkey_seq = 0;
+
+char copyright[] =
+"Copyright (C) 1999 Henry Spencer, Richard Guy Briggs, D. Hugh Redelmeier,\n\
+ Sandy Harris, Angelos D. Keromytis, John Ioannidis.\n\
+\n\
+ This program is free software; you can redistribute it and/or modify it\n\
+ under the terms of the GNU General Public License as published by the\n\
+ Free Software Foundation; either version 2 of the License, or (at your\n\
+ option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.\n\
+\n\
+ This program is distributed in the hope that it will be useful, but\n\
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n\
+ (file COPYING in the distribution) for more details.\n";
+
+static void
+usage(char * arg)
+{
+ fprintf(stdout, "usage: %s {--set|--clear} {tunnel|tunnel-xmit|netlink|xform|eroute|spi|radij|esp|ah|rcv|pfkey|ipcomp|verbose}\n", arg);
+ fprintf(stdout, " %s {--all|--none}\n", arg);
+ fprintf(stdout, " %s --help\n", arg);
+ fprintf(stdout, " %s --version\n", arg);
+ fprintf(stdout, " %s\n", arg);
+ fprintf(stdout, " [ --debug ] is optional to any %s command\n", arg);
+ fprintf(stdout, " [ --label <label> ] is optional to any %s command.\n", arg);
+ exit(1);
+}
+
+static struct option const longopts[] =
+{
+ {"set", 1, 0, 's'},
+ {"clear", 1, 0, 'c'},
+ {"all", 0, 0, 'a'},
+ {"none", 0, 0, 'n'},
+ {"help", 0, 0, 'h'},
+ {"version", 0, 0, 'v'},
+ {"label", 1, 0, 'l'},
+ {"optionsfrom", 1, 0, '+'},
+ {"debug", 0, 0, 'd'},
+ {0, 0, 0, 0}
+};
+
+int
+main(int argc, char **argv)
+{
+/* int fd; */
+ unsigned char action = 0;
+ int c, previous = -1;
+
+ int debug = 0;
+ int error = 0;
+ int argcount = argc;
+ int em_db_tn, em_db_nl, em_db_xf, em_db_er, em_db_sp;
+ int em_db_rj, em_db_es, em_db_ah, em_db_rx, em_db_ky;
+ int em_db_gz, em_db_vb;
+
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+ struct sadb_msg *pfkey_msg;
+
+ em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=0;
+ em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=0;
+ em_db_gz=em_db_vb=0;
+
+
+ program_name = argv[0];
+
+ while((c = getopt_long(argc, argv, ""/*"s:c:anhvl:+:d"*/, longopts, 0)) != EOF) {
+ switch(c) {
+ case 'd':
+ debug = 1;
+ pfkey_lib_debug = PF_KEY_DEBUG_PARSE_MAX;
+ argcount--;
+ break;
+ case 's':
+ if(action) {
+ fprintf(stderr, "%s: Only one of '--set', '--clear', '--all' or '--none' options permitted.\n",
+ program_name);
+ exit(1);
+ }
+ action = 's';
+ em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=0;
+ em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=0;
+ em_db_gz=em_db_vb=0;
+ if(strcmp(optarg, "tunnel") == 0) {
+ em_db_tn = -1L;
+ } else if(strcmp(optarg, "tunnel-xmit") == 0) {
+ em_db_tn = DB_TN_XMIT;
+ } else if(strcmp(optarg, "netlink") == 0) {
+ em_db_nl = -1L;
+ } else if(strcmp(optarg, "xform") == 0) {
+ em_db_xf = -1L;
+ } else if(strcmp(optarg, "eroute") == 0) {
+ em_db_er = -1L;
+ } else if(strcmp(optarg, "spi") == 0) {
+ em_db_sp = -1L;
+ } else if(strcmp(optarg, "radij") == 0) {
+ em_db_rj = -1L;
+ } else if(strcmp(optarg, "esp") == 0) {
+ em_db_es = -1L;
+ } else if(strcmp(optarg, "ah") == 0) {
+ em_db_ah = -1L;
+ } else if(strcmp(optarg, "rcv") == 0) {
+ em_db_rx = -1L;
+ } else if(strcmp(optarg, "pfkey") == 0) {
+ em_db_ky = -1L;
+ } else if(strcmp(optarg, "comp") == 0) {
+ em_db_gz = -1L;
+ } else if(strcmp(optarg, "verbose") == 0) {
+ em_db_vb = -1L;
+ } else {
+ usage(program_name);
+ }
+ em_db_nl |= 1 << (sizeof(em_db_nl) * 8 -1);
+ break;
+ case 'c':
+ if(action) {
+ fprintf(stderr, "%s: Only one of '--set', '--clear', '--all' or '--none' options permitted.\n",
+ program_name);
+ exit(1);
+ }
+ em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=-1;
+ em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=-1;
+ em_db_gz=em_db_vb=-1;
+
+ action = 'c';
+ if(strcmp(optarg, "tunnel") == 0) {
+ em_db_tn = 0;
+ } else if(strcmp(optarg, "tunnel-xmit") == 0) {
+ em_db_tn = ~DB_TN_XMIT;
+ } else if(strcmp(optarg, "netlink") == 0) {
+ em_db_nl = 0;
+ } else if(strcmp(optarg, "xform") == 0) {
+ em_db_xf = 0;
+ } else if(strcmp(optarg, "eroute") == 0) {
+ em_db_er = 0;
+ } else if(strcmp(optarg, "spi") == 0) {
+ em_db_sp = 0;
+ } else if(strcmp(optarg, "radij") == 0) {
+ em_db_rj = 0;
+ } else if(strcmp(optarg, "esp") == 0) {
+ em_db_es = 0;
+ } else if(strcmp(optarg, "ah") == 0) {
+ em_db_ah = 0;
+ } else if(strcmp(optarg, "rcv") == 0) {
+ em_db_rx = 0;
+ } else if(strcmp(optarg, "pfkey") == 0) {
+ em_db_ky = 0;
+ } else if(strcmp(optarg, "comp") == 0) {
+ em_db_gz = 0;
+ } else if(strcmp(optarg, "verbose") == 0) {
+ em_db_vb = 0;
+ } else {
+ usage(program_name);
+ }
+ em_db_nl &= ~(1 << (sizeof(em_db_nl) * 8 -1));
+ break;
+ case 'a':
+ if(action) {
+ fprintf(stderr, "%s: Only one of '--set', '--clear', '--all' or '--none' options permitted.\n",
+ program_name);
+ exit(1);
+ }
+ action = 'a';
+ em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=-1;
+ em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=-1;
+ em_db_gz=-1;
+ em_db_vb= 0;
+ break;
+ case 'n':
+ if(action) {
+ fprintf(stderr, "%s: Only one of '--set', '--clear', '--all' or '--none' options permitted.\n",
+ program_name);
+ exit(1);
+ }
+ action = 'n';
+ em_db_tn=em_db_nl=em_db_xf=em_db_er=em_db_sp=0;
+ em_db_rj=em_db_es=em_db_ah=em_db_rx=em_db_ky=0;
+ em_db_gz=em_db_vb=0;
+ break;
+ case 'h':
+ case '?':
+ usage(program_name);
+ exit(1);
+ case 'v':
+ fprintf(stdout, "klipsdebug (Linux FreeS/WAN %s) %s\n",
+ ipsec_version_code(), klipsdebug_c_version);
+ fputs(copyright, stdout);
+ exit(0);
+ 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 '+': /* optionsfrom */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* no return on error */
+ break;
+ default:
+ break;
+ }
+ previous = c;
+ }
+
+ if(argcount == 1) {
+ system("cat /proc/net/ipsec_klipsdebug");
+ exit(0);
+ }
+
+ if(!action) {
+ usage(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);
+ }
+
+ pfkey_extensions_init(extensions);
+
+ if((error = pfkey_msg_hdr_build(&extensions[0],
+ SADB_X_DEBUG,
+ 0,
+ 0,
+ ++pfkey_seq,
+ getpid()))) {
+ fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
+ program_name, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+
+ if((error = pfkey_x_debug_build(&extensions[SADB_X_EXT_DEBUG],
+ em_db_tn,
+ em_db_nl,
+ em_db_xf,
+ em_db_er,
+ em_db_sp,
+ em_db_rj,
+ em_db_es,
+ em_db_ah,
+ em_db_rx,
+ em_db_ky,
+ em_db_gz,
+ em_db_vb))) {
+ fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
+ program_name, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+
+ if((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN))) {
+ fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n",
+ program_name, error);
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+ exit(1);
+ }
+
+ if((error = write(pfkey_sock,
+ pfkey_msg,
+ pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) !=
+ (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
+ fprintf(stderr,
+ "%s: pfkey write failed, tried to write %u octets, returning %d with errno=%d.\n",
+ program_name,
+ (unsigned)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN),
+ error,
+ 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:
+ 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. Please report as much detail as possible to development team.\n", errno);
+ }
+ exit(1);
+ }
+
+ if(pfkey_msg) {
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+ }
+
+ (void) close(pfkey_sock); /* close the socket */
+ exit(0);
+}
diff --git a/programs/look/.cvsignore b/programs/look/.cvsignore
new file mode 100644
index 000000000..6f094f8d7
--- /dev/null
+++ b/programs/look/.cvsignore
@@ -0,0 +1 @@
+look
diff --git a/programs/look/Makefile b/programs/look/Makefile
new file mode 100644
index 000000000..e66ca60c1
--- /dev/null
+++ b/programs/look/Makefile
@@ -0,0 +1,38 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:28 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=look
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:28 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/look/look.8 b/programs/look/look.8
new file mode 100644
index 000000000..fc2d53eca
--- /dev/null
+++ b/programs/look/look.8
@@ -0,0 +1,45 @@
+.TH look 8 "25 Apr 2002"
+.\"
+.\" RCSID $Id: look.8,v 1.1 2004/03/15 20:35:28 as Exp $
+.\"
+.SH NAME
+ipsec look \- get a quick summary of FreeS/WAN status
+.SH SYNOPSIS
+.I look
+is used to get a quick overview of what the status of FreeSWAN is.
+It is equivalent to:
+\ \ \ ipsec eroute
+
+\ \ \ ipsec spigrp
+
+\ \ \ ipsec tncfg
+
+\ \ \ ipsec spi
+
+\ \ \ netstat -rn
+
+.LP
+However a bit of processing is done to combine the outputs.
+.SH "SEE ALSO"
+ipsec(8), ipsec_tncfg(8), ipsec_spi(8), ipsec_spigrp(8), ipsec_eroute(5),
+netstat(8).
+.SH HISTORY
+Man page written for the Linux FreeS/WAN project <http://www.freeswan.org/>
+by Michael Richardson. Original program written by Henry Spencer.
+.\"
+.\" $Log: look.8,v $
+.\" Revision 1.1 2004/03/15 20:35:28 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.2 2002/04/29 22:39:31 mcr
+.\" added basic man page for all internal commands.
+.\"
+.\" Revision 1.1 2002/04/26 01:21:43 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.
+.\"
+.\"
+.\"
diff --git a/programs/look/look.in b/programs/look/look.in
new file mode 100755
index 000000000..a5331c03b
--- /dev/null
+++ b/programs/look/look.in
@@ -0,0 +1,87 @@
+#! /bin/sh
+# quick look at current connections and related information
+# Copyright (C) 1998, 1999 Henry Spencer.
+#
+# 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: look.in,v 1.1 2004/03/15 20:35:28 as Exp $
+
+info=/var/run/ipsec.info
+me="ipsec look"
+
+case "$1" in
+--help) echo "Usage: ipsec look" ; exit 0 ;;
+--version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+esac
+
+# clear out variables that have strange effects on sort etc.
+unset LANG LANGUAGE LC_ALL LC_MESSAGES
+
+# Pick up IPsec configuration etc.
+eval `ipsec _confread --varprefix IPSEC --optional --type config setup`
+if test " $IPSEC_confreadstatus" != " "
+then
+ echo "$IPSEC_confreadstatus -- aborting" |
+ logger -s -p daemon.error -t ipsec_look
+ exit 1
+fi
+if test -s $info
+then
+ . $info
+fi
+
+# label it just to be sure
+echo "`hostname` `date`"
+
+# combine spigrp and eroute
+cat /proc/net/ipsec_spigrp /proc/net/ipsec_eroute |
+ awk '
+ function pad(subnet) {
+ sub("/", ".", subnet)
+ split(subnet, d, ".")
+ return sprintf("%03s%03s%03s%03s%03s", d[1], d[2],
+ d[3], d[4], d[5])
+ }
+ $2 == "->" {
+ printf "%s:%-18s -> %-18s => %s\n",
+ (pad($1) pad($3)),
+ $1, $3, (($5 in tun) ? tun[$5] : $5)
+ next
+ }
+ $3 == "->" {
+ printf "%s:%-18s -> %-18s => %s (%s)\n",
+ (pad($2) pad($4)),
+ $2, $4, (($6 in tun) ? tun[$6] : $6), $1
+ next
+ }
+ { tun[$1] = $0 }
+ ' | sort | sed 's/^[^:]*://'
+
+# tncfg (mostly as a divider line)
+egrep -v 'NULL[ \t]+mtu=0\(0\)[ \t]+->[ \t]+0' /proc/net/ipsec_tncfg |
+ paste -d % | sed 's/%/ /g' | sed 's/ -> /->/g'
+
+# SAs
+sort /proc/net/ipsec_spi
+
+# relevant routing information, including header line (which is good
+# enough as a separator, no need for another bar)
+pat="^Dest"
+if test " $defaultroutephys" != " "
+then
+ pat="$pat|$defaultroutephys\$|$defaultroutevirt\$"
+else
+ for i in `echo "$IPSECinterfaces" | tr '=' ' '`
+ do
+ pat="$pat|$i\$"
+ done
+fi
+netstat -nr | egrep "$pat" | sed '/^Dest/s/^/ /' | sort | sed '/^ Dest/s/ //'
diff --git a/programs/lwdnsq/.cvsignore b/programs/lwdnsq/.cvsignore
new file mode 100644
index 000000000..b1ff942bf
--- /dev/null
+++ b/programs/lwdnsq/.cvsignore
@@ -0,0 +1,4 @@
+dnskey
+dnskey.cat8
+lwdnsq
+lwdnsq.xml
diff --git a/programs/lwdnsq/CONTRACT.txt b/programs/lwdnsq/CONTRACT.txt
new file mode 100644
index 000000000..77335e8cf
--- /dev/null
+++ b/programs/lwdnsq/CONTRACT.txt
@@ -0,0 +1,106 @@
+The only delays are after START, and after CNAME.
+
+add the time to each line.
+
+put DNSSEC status on each line.
+
+The format of the replies is:
+
+ <ID> <TIME> <TTL> <TYPE> <TYPE-SPECIFIC> \n
+ ^- whitespace.
+
+ID is a unique number that identifies the transaction. It is determined
+by the caller. lwdnsq treats this ID as a string, and does nothing
+with it other than repeat it on each line.
+There is no predetermined bound on the length, but the total line
+length of input to lwdnsq must not exceed LWDNSQ_CMDBUF_LEN (1024).
+LWDNSQ_CMDBUF_LEN is defined in <freeswan.h>
+
+The output of lwdnsq is currently limited to LWDNSQ_RESULT_LEN_MAX (4096) byte
+lines. LWDNSQ_RESULT_LEN_MAX is defined in <freeswan.h>
+
+Time is a decimal encoded integer, currently 32-bit time (time_t) since Unix
+epoch. On systems with a 64-bit time_t, it would be 64-bit in range.
+
+The TTL field gives the number of seconds that the result is valid for.
+(starting at the time given). If there is no useful TTL value for the
+record, it will be either "0".
+
+Type is a case-insensitive, one of:
+structure
+ START (optional comments) acknowledges start of transaction
+ DONE (optional comments) signals the end of data for a transaction
+
+errors
+ RETRY same as for FATAL, but this implies that the data
+ was not found, but could be found later.
+
+ FATAL Following this, is text detailing the fault,
+ in a human readable form.
+ "FATAL" results likely mean that the lwdnsq should
+ be restarted.
+
+ WARNING Log this result, but do not cancel transaction.
+
+ Errors are still followed by "DONE".
+
+
+
+data answers
+ DNSSEC followed by "OKAY" or "not present"
+ NAME followed by canonical name for requested RR,
+ i.e. the result of any CNAMEs/DNAMEs that were chased
+ by the recursive resolving server.
+ CNAME followed by the name which has been followed.
+ CNAMEFROM the thing that was mapped
+ TXT followed by RR-specific Presentation Format
+ SIG "
+ A "
+ AAAA "
+ PTR "
+ KEY "
+ AD-TXT followed by RR-specific Presentation Format - DNSSEC
+ TXT followed by RR-specific Presentation Format - DNSSEC
+ AD-KEY followed by RR-specific Presentation Format - DNSSEC
+ KEY followed by RR-specific Presentation Format - DNSSEC
+
+If there is no data of the type requested, even after lwdnsq
+has attempted to follow CNAMEs, then there will be no resource
+records returned. This is the formal indication of the lack of
+the records, however, in addition, an error will be returned, of the type:
+ RETRY the record "foobar" does not have a RR resource record.
+
+The -ldns library from bind9 will deal with the presentation format,
+producing a structure breakout from it. The functions are:
+
+dns_rdata_fromtext(3)
+ Presentation Format -> Wire Format
+dns_rdata_tostruct(3)
+ Wire Format -> C-structure
+
+dns_rdata_totext(3)
+ Wire Format -> Presentation Format
+
+(Above from .../src/bind-9.3.0s20020722/lib/dns/include/dns/rdata.h)
+
+The lwdnsq program uses dns_rdata_totext(3) to format the resource record
+(received from lwres in wire format) into its presentation format.
+
+The documentation is in the bind-9.3 source tree, in the header files.
+(They are likely all installed into the include directories).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/programs/lwdnsq/Makefile b/programs/lwdnsq/Makefile
new file mode 100644
index 000000000..2fca5e249
--- /dev/null
+++ b/programs/lwdnsq/Makefile
@@ -0,0 +1,96 @@
+# Makefile for the KLIPS interface utilities
+# Copyright (C) 1998, 1999 Henry Spencer.
+# Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:28 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM:=lwdnsq
+
+OBJS:=cmds.o lookup.o
+
+LWRESINCL=${LWRESDIR}/include
+
+LIBS:=${FREESWANLIB} ${LWRESLIB} ${BIND9STATICLIBDIR}/libdns.a ${BIND9STATICLIBDIR}/libisc.a
+CFLAGS+=-I${LWRESINCL}
+#USERCOMPILE=-g
+
+
+include ../Makefile.program
+
+lwdnsq.8: lwdnsq.xml
+ xmlto man lwdnsq.xml
+
+lwdnsq.xml: lwdnsq.xml.in
+
+TAGS:
+ etags *.[ch] ../../lib/liblwres/*.[ch] ../../lib/liblwres/include/lwres/*.h
+
+# manually maintained dependancies
+lwdnsq.o: lwdnsq.c lwdnsq.h
+cmds.o: cmds.c lwdnsq.h
+lookup.o: lookup.c lwdnsq.h
+
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:28 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.9 2003/09/03 01:13:24 mcr
+# first attempt at async capable lwdnsq.
+#
+# Revision 1.8 2003/02/27 09:29:02 mcr
+# moved targets to after include file so that XML-conversion
+# does not occur by default.
+#
+# Revision 1.7 2003/02/01 01:36:53 mcr
+# updates to lwdnsq man page to reflect CONTRACT
+#
+# Revision 1.6 2003/01/14 03:01:14 dhr
+#
+# improve diagnostics; tidy
+#
+# Revision 1.5 2003/01/10 23:20:40 dhr
+#
+# remove reference to /sandel
+#
+# Revision 1.4 2002/12/19 05:45:47 mcr
+# use BIND9STATICLIBDIR to find -lisc/-ldns.
+#
+# Revision 1.3 2002/12/12 06:03:41 mcr
+# added --regress option to force times to be regular
+#
+# Revision 1.2 2002/12/04 03:21:06 mcr
+# DNS zone files (with signed versions) for DNSSEC enabled testing root.
+#
+# Revision 1.1 2002/10/30 02:25:31 mcr
+# renamed version of files from dnskey/
+#
+# Revision 1.4 2002/10/18 04:08:02 mcr
+# added -ldns and -lisc to libraries, but it isn't clear
+# where we will find these only-slightly standard libraries yet.
+#
+# Revision 1.3 2002/10/09 20:13:10 mcr
+# get appropriate LWRES include directory.
+#
+# Revision 1.2 2002/09/30 18:55:54 mcr
+# skeleton for dnskey helper program.
+#
+# Revision 1.1 2002/09/30 16:50:23 mcr
+# documentation for "dnskey" helper
+#
+#
+#
diff --git a/programs/lwdnsq/cmds.c b/programs/lwdnsq/cmds.c
new file mode 100644
index 000000000..1b15202ff
--- /dev/null
+++ b/programs/lwdnsq/cmds.c
@@ -0,0 +1,351 @@
+/*
+ * DNS KEY lookup helper - command implementation
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <freeswan.h>
+
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <lwres/netdb.h>
+#include <time.h>
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/types.h>
+#include <isc/result.h>
+#include <isc/mem.h>
+#include <isc/buffer.h>
+#include <isc/region.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <lwres/netdb.h>
+#include <lwres/async.h>
+
+
+#include "lwdnsq.h"
+
+static void cmd_not_implemented(dnskey_glob *gs, const char *what)
+{
+ fprintf(gs->cmdproto_out, "0 FATAL unimplemented command \"%s\"\n", what);
+}
+
+void output_transaction_line(dnskey_glob *gs,
+ char *id,
+ int ttl,
+ char *cmd,
+ char *data)
+{
+ time_t t;
+
+ t=time(NULL);
+
+ /* regularlize time for regression testing */
+ if(gs->regress) {
+ t=3145915;
+ }
+
+ if(data) {
+ fprintf(gs->cmdproto_out,
+ "%s %ld %d %s %s\n",
+ id, t, ttl, cmd, data);
+ } else {
+ fprintf(gs->cmdproto_out,
+ "%s %ld %d %s\n",
+ id, t, ttl, cmd);
+ }
+
+}
+
+void output_transaction_line_limited(dnskey_glob *gs,
+ char *id,
+ int ttl,
+ char *cmd,
+ int max,
+ char *data)
+{
+ time_t t;
+
+ t=time(NULL);
+
+ /* regularlize time for regression testing */
+ if(gs->regress) {
+ t=3145915;
+ }
+
+ fprintf(gs->cmdproto_out,
+ "%s %ld %d %s %.*s\n",
+ id, t, ttl, cmd, max, data);
+}
+
+
+#if 0
+again:
+
+ lwres_getrrsetbyname_xmit(ctx, &las);
+ timeout.tv_sec = lwres_async_timeout(ctx);
+ sock = lwres_async_fd(ctx);
+
+ FD_ZERO(&readfds);
+ FD_SET(sock, &readfds);
+ ret2 = select(sock + 1, &readfds, NULL, NULL, &timeout);
+
+ /*
+ * What happened with select?
+ */
+ if (ret2 < 0) {
+ success = LWRES_R_IOERROR;
+ goto out3;
+ }
+ if (ret2 == 0) {
+ success = LWRES_R_TIMEOUT;
+ goto out3;
+ }
+
+ out:
+ if (ctx != NULL)
+ lwres_context_destroy(&ctx);
+
+ out2:
+
+#endif
+
+
+void lookup_key(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ char *id;
+ char *fqdn;
+ char simplebuf[80];
+
+ /* process arguments */
+ /* KEY 31459 east.uml.freeswan.org */
+ if(argc!=3) {
+ snprintf(simplebuf, sizeof(simplebuf), "wrong number of arguments %d", argc);
+ output_transaction_line(gs, "0", 0, "FATAL", simplebuf);
+ return;
+ }
+
+ id=argv[1];
+ fqdn=argv[2];
+
+ lookup_thing(gs, dns_rdatatype_key, "KEY", id, fqdn);
+}
+
+void lookup_key4(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "key4");
+}
+
+void lookup_key6(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "key6");
+}
+
+
+void lookup_txt(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ char *id;
+ char *fqdn;
+ char simplebuf[80];
+
+ /* process arguments */
+ /* KEY 31459 east.uml.freeswan.org */
+ if(argc != 3) {
+ snprintf(simplebuf, sizeof(simplebuf), "wrong number of arguments to TXT: %d", argc);
+ output_transaction_line(gs, "0", 0, "FATAL", simplebuf);
+ return;
+ }
+
+ id=argv[1];
+ fqdn=argv[2];
+
+ lookup_thing(gs, dns_rdatatype_txt, "TXT", id, fqdn);
+}
+
+void lookup_txt4(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ char *id;
+ char *ipv4;
+ struct in_addr in4;
+ char simplebuf[80];
+
+ /* process arguments */
+ /* KEY 31459 east.uml.freeswan.org */
+ if(argc != 3) {
+ snprintf(simplebuf, sizeof(simplebuf), "wrong number of arguments to TXT: %d", argc);
+ output_transaction_line(gs, "0", 0, "FATAL", simplebuf);
+ return;
+ }
+
+ id=argv[1];
+ ipv4=argv[2];
+
+ if(inet_pton(AF_INET, ipv4, &in4) <= 0) {
+ snprintf(simplebuf, sizeof(simplebuf), "invalid IPv4 address: %s", ipv4);
+ output_transaction_line(gs, "0", 0, "FATAL", simplebuf);
+ return;
+ }
+
+ snprintf(simplebuf, 80, "%d.%d.%d.%d.in-addr.arpa",
+ in4.s_addr & 0xff,
+ (in4.s_addr & 0xff00) >> 8,
+ (in4.s_addr & 0xff0000) >> 16,
+ (in4.s_addr & 0xff000000) >> 24);
+
+ lookup_thing(gs, dns_rdatatype_txt, "TXT4", id, simplebuf);
+}
+
+void lookup_txt6(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "txt6");
+}
+
+void lookup_ipseckey(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "ipseckey");
+}
+
+void lookup_ipseckey4(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "ipseckey4");
+}
+
+void lookup_ipseckey6(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "ipseckey6");
+}
+
+void lookup_oe4(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "oe4");
+}
+
+void lookup_oe6(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "oe6");
+}
+
+void lookup_a(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "a");
+}
+
+void lookup_aaaa(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ cmd_not_implemented(gs, "aaaa");
+}
+
+
+
+
+
+
+/*
+ * $Log: cmds.c,v $
+ * Revision 1.1 2004/03/15 20:35:28 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.11 2003/09/03 01:13:24 mcr
+ * first attempt at async capable lwdnsq.
+ *
+ * Revision 1.10 2003/05/22 16:33:51 mcr
+ * added trailing . to CNAME return and cleaned up "CNAMEFROM" output.
+ *
+ * Revision 1.9 2003/05/14 15:47:39 mcr
+ * processing of IP address into pieces was not done with
+ * the right order of operations.
+ *
+ * Revision 1.8 2003/02/27 09:27:17 mcr
+ * adjusted lwdnsq so that it adheres to contract - TXT records
+ * are returned in a single piece. Requires custom decoding.
+ * implemented "txt4" lookup type.
+ *
+ * Revision 1.7 2003/01/14 07:53:29 dhr
+ *
+ * - attempt to diagnose lack of lwdnsq
+ * - increase too-small buffer size
+ *
+ * Revision 1.6 2003/01/14 03:01:14 dhr
+ *
+ * improve diagnostics; tidy
+ *
+ * Revision 1.5 2002/12/12 06:03:41 mcr
+ * added --regress option to force times to be regular
+ *
+ * Revision 1.4 2002/11/25 18:37:28 mcr
+ * added AD- marking of each record that was DNSSEC verified.
+ *
+ * Revision 1.3 2002/11/16 02:53:53 mcr
+ * lwdnsq - with new contract added.
+ *
+ * Revision 1.2 2002/11/12 04:33:44 mcr
+ * print DNSSEC status as we process CNAMEs.
+ *
+ * Revision 1.1 2002/10/30 02:25:31 mcr
+ * renamed version of files from dnskey/
+ *
+ * Revision 1.4 2002/10/18 23:11:02 mcr
+ * if we get ENOENT, then see if we can get a CNAME. If so, then
+ * follow it.
+ * Be careful when following them to avoid recursion.
+ *
+ * Revision 1.3 2002/10/18 04:08:47 mcr
+ * use -ldns routines to decode lwres results and format them nicely.
+ *
+ * Revision 1.2 2002/10/09 20:13:34 mcr
+ * first set of real code - lookup KEY records in forward.
+ *
+ * Revision 1.1 2002/09/30 18:55:54 mcr
+ * skeleton for dnskey helper program.
+ *
+ * Revision 1.1 2002/09/30 16:50:23 mcr
+ * documentation for "dnskey" helper
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * c-basic-offset: 2
+ * End:
+ *
+ */
diff --git a/programs/lwdnsq/lookup.c b/programs/lwdnsq/lookup.c
new file mode 100644
index 000000000..700c4adbe
--- /dev/null
+++ b/programs/lwdnsq/lookup.c
@@ -0,0 +1,632 @@
+/*
+ * DNS KEY lookup helper
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+char lookup_c_version[] = "@(#) RCSID $Id: lookup.c,v 1.1 2004/03/15 20:35:28 as Exp $";
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <freeswan.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include <isc/mem.h>
+#include <isc/buffer.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <dns/name.h>
+#include <lwres/netdb.h>
+#include <lwres/async.h>
+#include "lwdnsq.h"
+
+static int lwresd_has_spoken = 0;
+
+char *xstrdup(const char *s)
+{
+ char *n;
+
+ n = strdup(s);
+ if(n == NULL) {
+ abort();
+ }
+ return n;
+}
+
+void free_dl(dnskey_glob *gs, dnskey_lookup *dl)
+{
+ dnskey_lookup **walk;
+
+ walk = &gs->dns_outstanding;
+ while(*walk!=NULL && *walk != dl)
+ {
+ walk = &((*walk)->next);
+ }
+ if(*walk != NULL)
+ {
+ /* if we exit with it non-null, then we
+ * found a matching location, remove
+ * it.
+ */
+ *walk = dl->next;
+ dl->next = NULL;
+ }
+ gs->dns_inflight--;
+
+ if(dl->tracking_id) {
+ free(dl->tracking_id);
+ dl->tracking_id = NULL;
+ }
+ if(dl->wantedtype_name) {
+ free(dl->wantedtype_name);
+ dl->wantedtype_name = NULL;
+ }
+ if(dl->fqdn) {
+ free(dl->fqdn);
+ dl->fqdn = NULL;
+ }
+#if 0
+ if(dl->last_cname_used) {
+ dns_name_free(&dl->last_cname, gs->iscmem);
+ }
+#endif
+
+ free(dl);
+}
+
+void lookup_thing(dnskey_glob *gs,
+ dns_rdatatype_t wantedtype,
+ char *wantedtype_name,
+ char *id,
+ char *fqdn)
+{
+ isc_mem_t *iscmem;
+ isc_buffer_t *iscbuf;
+ int success;
+ dnskey_lookup *dl;
+
+ iscmem=NULL;
+ iscbuf=NULL;
+ dl = malloc(sizeof(*dl));
+ memset(dl, 0, sizeof(*dl));
+
+ dl->tracking_id = strdup(id);
+ dl->step = dkl_start;
+
+ output_transaction_line(gs, id, 0, "START", NULL);
+
+ success = lwres_getrrsetbyname_init(fqdn, dns_rdataclass_in,
+ wantedtype, 0 /*flags*/,
+ gs->lwctx, &dl->las);
+
+ if(success != ERRSET_SUCCESS) {
+ /* screwed: */
+ output_transaction_line(gs, id, 0, "FATAL", "isc buffer error");
+ return;
+ }
+
+ lwres_getrrsetbyname_xmit(gs->lwctx, &dl->las);
+
+ dl->step = dkl_first;
+ dl->wantedtype = wantedtype;
+ dl->wantedtype_name = xstrdup(wantedtype_name);
+ dl->fqdn = xstrdup(fqdn);
+ dl->tracking_id = xstrdup(id);
+
+ /* link it in */
+ dl->next = gs->dns_outstanding;
+ gs->dns_outstanding = dl;
+
+ gs->dns_inflight++;
+
+ return;
+}
+
+
+int setup_follow_possible_cname(dnskey_glob *gs,
+ dnskey_lookup *dl)
+{
+ int ret;
+
+ dl->cname_count++;
+
+ /*
+ * If we are on an odd cycle (starting with 1),
+ * then convert to dns_name_t so that we can compare later.
+ *
+ * This detects loops in the CNAME processing, while still
+ * allowing an arbitrary number of CNAMEs to be followed.
+ */
+ if(dl->cname_count & 1)
+ {
+ isc_buffer_t fqdn_src;
+ isc_buffer_t *fqdn_dst;
+
+ if(dl->cname_count == 1)
+ {
+ memset(&dl->last_cname, 0, sizeof(dl->last_cname));
+ dns_name_init(&dl->last_cname, NULL);
+ }
+ else
+ {
+ dns_name_reset(&dl->last_cname);
+ }
+
+ fqdn_dst=NULL;
+
+ isc_buffer_init(&fqdn_src, dl->fqdn, strlen(dl->fqdn));
+ isc_buffer_add(&fqdn_src, strlen(dl->fqdn));
+
+ isc_buffer_allocate(gs->iscmem, &fqdn_dst, strlen(dl->fqdn)+1);
+
+#if 0
+ if(dl->last_cname_used) {
+ dns_name_free(&dl->last_cname, gs->iscmem);
+ }
+#endif
+ dl->last_cname_used = 1;
+ if(dns_name_fromtext(&dl->last_cname,
+ &fqdn_src,
+ NULL,
+ 1,
+ fqdn_dst) != ISC_R_SUCCESS) {
+ return 0;
+ }
+
+ /* something else here ? */
+ }
+
+ ret = lwres_getrrsetbyname_init(dl->fqdn, dns_rdataclass_in,
+ dns_rdatatype_cname, 0 /*flags*/,
+ gs->lwctx,
+ &dl->las);
+
+ if(ret != ERRSET_SUCCESS) {
+ return 0;
+ }
+
+ lwres_getrrsetbyname_xmit(gs->lwctx, &dl->las);
+
+ return 1;
+}
+
+
+/*
+ * we asked for, and got a CNAME of some kind.
+ */
+void process_step_cname(dnskey_glob *gs,
+ dnskey_lookup *dl,
+ struct rrsetinfo *ans,
+ int success)
+{
+ struct rdatainfo *ri;
+ isc_region_t region;
+ dns_rdata_t rd;
+ dns_rdata_cname_t cn;
+ char simplebuf[80];
+ isc_buffer_t *cname_text;
+ char cname_buf[DNS_NAME_MAXTEXT];
+ /* char cname_buf2[DNS_NAME_MAXTEXT]; */
+
+ switch(success) {
+ case ERRSET_NONAME:
+ case ERRSET_NODATA:
+ /* no, no CNAME found, thing isn't there */
+ snprintf(simplebuf, sizeof(simplebuf),
+ "RR of type %s for %s was not found (tried CNAMEs)",
+ dl->wantedtype_name,
+ dl->fqdn);
+ output_transaction_line(gs, dl->tracking_id, 0, "RETRY",
+ simplebuf);
+ dl->step = dkl_done;
+ return;
+
+ case 0:
+ /* aha! found a CNAME */
+ break;
+
+ default:
+ fatal:
+ /* some other error */
+ snprintf(simplebuf, sizeof(simplebuf), "err=%d", success);
+ output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf);
+ dl->step = dkl_done;
+ return;
+ }
+
+ /*
+ * now process out the CNAMEs, and look them up, one by one...
+ * there should be only one... We just use the first one that works.
+ */
+
+ if(ans->rri_flags & RRSET_VALIDATED) {
+ output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "OKAY");
+ } else {
+ output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "not present");
+ }
+
+ if(ans->rri_nrdatas != 1) {
+ /* we got a number of CNAMEs different from 1! */
+ success=0;
+ snprintf(simplebuf, sizeof(simplebuf), "illegal number of CNAMES: %d", ans->rri_nrdatas);
+ output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf);
+ dl->step = dkl_done;
+ return;
+ }
+
+ /* process first CNAME record */
+ ri= &ans->rri_rdatas[0];
+
+ memset(&region, 0, sizeof(region));
+ memset(&rd, 0, sizeof(rd));
+
+ region.base = ri->rdi_data;
+ region.length = ri->rdi_length;
+
+ dns_rdata_fromregion(&rd, dns_rdataclass_in,
+ dns_rdatatype_cname, &region);
+
+ /* we set mctx to NULL, which means that the tenure for
+ * the stuff pointed to by cn will persist only as long
+ * as rd persists.
+ */
+ if(dns_rdata_tostruct(&rd, &cn, NULL) != ISC_R_SUCCESS) {
+ /* failed, try next return error */
+ success=0;
+ goto fatal;
+ }
+
+ cname_text=NULL;
+ if(isc_buffer_allocate(gs->iscmem, &cname_text, DNS_NAME_MAXTEXT)) {
+ success=0;
+ goto fatal;
+ }
+
+ if(dns_name_totext(&cn.cname, ISC_TRUE, cname_text) !=
+ ISC_R_SUCCESS) {
+ success=0;
+ goto fatal;
+ }
+
+ cname_buf[0]='\0';
+ strncat(cname_buf,
+ isc_buffer_base(cname_text),
+ isc_buffer_usedlength(cname_text));
+
+ /* free up buffer */
+ isc_buffer_free(&cname_text);
+
+ {
+ /* add a trailing . */
+ char *end;
+ end = &cname_buf[strlen(cname_buf)];
+ if(*end != '.') {
+ strncat(cname_buf, ".", sizeof(cname_buf));
+ }
+ }
+
+ /* format out a text version */
+ output_transaction_line(gs, dl->tracking_id, 0, "CNAME", cname_buf);
+ output_transaction_line(gs, dl->tracking_id, 0, "CNAMEFROM", dl->fqdn);
+
+ /* check for loops in the CNAMEs! */
+ if(dns_name_equal(&dl->last_cname, &cn.cname) == ISC_TRUE) {
+ /* damn, we found a loop! */
+ dl->step = dkl_done;
+ return;
+ }
+
+ /* send new request. */
+ /* okay, so look this new thing up */
+ success = lwres_getrrsetbyname_init(cname_buf, dns_rdataclass_in,
+ dl->wantedtype, 0 /*flags*/,
+ gs->lwctx, &dl->las);
+
+ if(success != ERRSET_SUCCESS) {
+ return;
+ }
+
+ lwres_getrrsetbyname_xmit(gs->lwctx, &dl->las);
+
+ dl->step = dkl_second;
+}
+
+void process_step_first(dnskey_glob *gs,
+ dnskey_lookup *dl,
+ struct rrsetinfo *ans,
+ int success,
+ int attempt) /* attempt = 0 first time, 1 after cname */
+{
+ char simplebuf[132], typebuf[16];
+ char txtbuf[1024];
+ int i;
+
+ switch(success) {
+ case ERRSET_NODATA:
+ if(attempt == 0) {
+ lwresd_has_spoken = 1;
+ setup_follow_possible_cname(gs, dl);
+ dl->step = dkl_cname;
+ return;
+ }
+ /* FALLTHROUGH */
+ case ERRSET_NONAME:
+ lwresd_has_spoken = 1;
+ snprintf(simplebuf, sizeof(simplebuf),
+ "RR of type %s for %s was not found",
+ dl->wantedtype_name,
+ dl->fqdn);
+ output_transaction_line(gs, dl->tracking_id, 0, "RETRY",
+ simplebuf);
+ dl->step = dkl_done;
+ goto done;
+
+ case ERRSET_NOMEMORY:
+ snprintf(simplebuf, sizeof(simplebuf),
+ "ran out of memory while looking up RR of type %s for %s",
+ dl->wantedtype_name, dl->fqdn);
+ output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf);
+ dl->step = dkl_done;
+ goto done;
+
+ case ERRSET_FAIL:
+ snprintf(simplebuf, sizeof(simplebuf),
+ "unspecified failure while looking up RR of type %s for %s%s",
+ dl->wantedtype_name, dl->fqdn,
+ lwresd_has_spoken ? "" : " (is lwresd running?)");
+ output_transaction_line(gs, dl->tracking_id, 0, "FATAL", simplebuf);
+ dl->step = dkl_done;
+ goto done;
+
+ case ERRSET_INVAL:
+ snprintf(simplebuf, sizeof(simplebuf),
+ "invalid input while looking up RR of type %s for %s",
+ dl->wantedtype_name, dl->fqdn);
+ output_transaction_line(gs, dl->tracking_id, 0, "RETRY", simplebuf);
+ dl->step = dkl_done;
+ goto done;
+
+ default:
+ snprintf(simplebuf, sizeof(simplebuf), " unknown error %d", success);
+ output_transaction_line(gs, dl->tracking_id, 0, "RETRY", simplebuf);
+ dl->step = dkl_done;
+ done:
+ return;
+
+ case 0:
+ /* everything okay */
+ lwresd_has_spoken = 1;
+ dl->step = dkl_done;
+ break;
+ }
+
+ /* output the rest of the data */
+
+ if(ans->rri_flags & RRSET_VALIDATED) {
+ output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "OKAY");
+ snprintf(typebuf, sizeof(typebuf), "AD-%s", dl->wantedtype_name);
+ if(dl->wantedtype_name) free(dl->wantedtype_name);
+ dl->wantedtype_name=xstrdup(typebuf);
+ } else {
+ output_transaction_line(gs, dl->tracking_id, 0, "DNSSEC", "not present");
+ }
+
+ output_transaction_line(gs, dl->tracking_id, 0, "NAME", ans->rri_name);
+
+ for(i=0; i<ans->rri_nrdatas; i++) {
+ struct rdatainfo *ri = &ans->rri_rdatas[i];
+ isc_region_t region;
+ dns_rdata_t rd;
+
+ isc_buffer_clear(gs->iscbuf);
+ memset(&region, 0, sizeof(region));
+ memset(&rd, 0, sizeof(rd));
+
+ region.base = ri->rdi_data;
+ region.length = ri->rdi_length;
+
+ if(dl->wantedtype == dns_rdatatype_txt) {
+ /* special treatment for TXT records */
+ unsigned int len, rdatalen, totlen;
+ unsigned char *txtp, *rdata;
+
+ txtp = txtbuf;
+ totlen = 0;
+ rdatalen = ri->rdi_length;
+ rdata = ri->rdi_data;
+
+ while(rdatalen > 0) {
+ len= (unsigned)rdata[0];
+ memcpy(txtp, rdata+1, len);
+ totlen += len;
+ txtp += len;
+ rdata += len+1;
+ rdatalen -= len+1;
+ }
+ *txtp = '\0';
+
+ output_transaction_line_limited(gs, dl->tracking_id, 0,
+ dl->wantedtype_name,
+ totlen, txtbuf);
+
+ } else {
+ dns_rdata_fromregion(&rd, dns_rdataclass_in,
+ dl->wantedtype, &region);
+
+ if(dns_rdata_totext(&rd, NULL, gs->iscbuf) != ISC_R_SUCCESS) {
+
+ }
+
+ output_transaction_line_limited(gs, dl->tracking_id, 0,
+ dl->wantedtype_name,
+ (int)isc_buffer_usedlength(gs->iscbuf),
+ (char *)isc_buffer_base(gs->iscbuf));
+ }
+ }
+
+ for(i=0; i<ans->rri_nsigs; i++) {
+ struct rdatainfo *ri = &ans->rri_sigs[i];
+ isc_region_t region;
+ dns_rdata_t rd;
+
+ isc_buffer_clear(gs->iscbuf);
+ memset(&region, 0, sizeof(region));
+ memset(&rd, 0, sizeof(rd));
+
+ region.base = ri->rdi_data;
+ region.length = ri->rdi_length;
+
+ dns_rdata_fromregion(&rd, dns_rdataclass_in,
+ dns_rdatatype_sig, &region);
+ if(dns_rdata_totext(&rd, NULL, gs->iscbuf) != ISC_R_SUCCESS) {
+ output_transaction_line(gs, dl->tracking_id, 0, "FATAL", "isc totext error");
+ return;
+ }
+
+ output_transaction_line_limited(gs, dl->tracking_id, 0, "SIG",
+ (int)isc_buffer_usedlength(gs->iscbuf),
+ (char *)isc_buffer_base(gs->iscbuf));
+ }
+}
+
+
+
+void lookup_step(dnskey_glob *gs,
+ dnskey_lookup *dl,
+ struct rrsetinfo *ans,
+ int success)
+{
+ /* char simplebuf[80]; */
+ int nextstate;
+
+ nextstate = dkl_done;
+
+ if(dl == NULL)
+ {
+ return;
+ }
+
+ switch(dl->step)
+ {
+ case dkl_start:
+ /* first request done, why are still in this state? */
+ break;
+
+ case dkl_first:
+ /* okay, got the reply from the first step! */
+ process_step_first(gs, dl, ans, success, 0);
+ nextstate = dl->step;
+ break;
+
+ case dkl_cname:
+ /*
+ * we asked for a cname, and we have some result to deal
+ * with here.
+ */
+ process_step_cname(gs, dl, ans, success);
+ nextstate = dl->step;
+ break;
+
+ case dkl_second:
+ /*
+ * we had asked for something, for a cname, and we followed
+ * it, and we'll see what we got back.
+ */
+ process_step_first(gs, dl, ans, success, 1);
+ nextstate = dl->step;
+ break;
+
+ case dkl_done:
+ /* this should not happen, really, just book keeping, so,
+ * just free up the structure, and return.
+ */
+ nextstate = dl->step;
+ return;
+ }
+
+
+ /* we have been through, made a state transition, if we are
+ * done, then do that.
+ */
+ if(nextstate == dkl_done)
+ {
+ output_transaction_line(gs, dl->tracking_id, 0, "DONE", NULL);
+ free_dl(gs, dl);
+ dl=NULL;
+ }
+ return;
+}
+
+void process_dns_reply(dnskey_glob *gs)
+{
+ dnskey_lookup *dl;
+ struct lwres_async_state *plas;
+ struct rrsetinfo *res;
+ int success;
+
+ plas = NULL;
+
+ success = lwres_getrrsetbyname_read(&plas, gs->lwctx, &res);
+
+ /* cast answer back to dnskey_lookup structure */
+ dl = (dnskey_lookup *)plas;
+
+ if(success == LWRES_R_RETRY) {
+ /* XXX we got something from some other weird place!
+ * transmit again, in the hope of getting the right answer
+ */
+ dl->retry_count--;
+ if(dl->retry_count > 0) {
+ lwres_getrrsetbyname_xmit(gs->lwctx, plas);
+ } else {
+ output_transaction_line(gs, dl->tracking_id, 0, "FATAL", "too many retries");
+ free_dl(gs, dl);
+ }
+ return;
+ }
+
+ /* perform next step for this one */
+ lookup_step(gs, dl, res, success);
+}
+
+/*
+ * $Log: lookup.c,v $
+ * Revision 1.1 2004/03/15 20:35:28 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.3 2003/09/18 02:17:39 mcr
+ * if we have tried a CNAME lookup, then take a NODATA
+ * reply as a no-name.
+ *
+ * Revision 1.2 2003/09/10 17:55:14 mcr
+ * the CNAME message had the s removed, which changes test
+ * results gratuitously.
+ *
+ * Revision 1.1 2003/09/03 01:13:24 mcr
+ * first attempt at async capable lwdnsq.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * c-basic-offset: 2
+ * End:
+ *
+ */
diff --git a/programs/lwdnsq/lwdnsq.8 b/programs/lwdnsq/lwdnsq.8
new file mode 100644
index 000000000..bb07985f2
--- /dev/null
+++ b/programs/lwdnsq/lwdnsq.8
@@ -0,0 +1,250 @@
+.\"Generated by db2man.xsl. Don't modify this, modify the source.
+.de Sh \" Subsection
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Ip \" List item
+.br
+.ie \\n(.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+.TH "IPSEC LWDNSQ" 8 "" "" ""
+.SH NAME
+lwdnsq \- lookup items in DNS to help pluto (and others)
+.SH "SYNOPSIS"
+
+.nf
+\fBipsec lwdnsq\fR lwdnsq\fR [\fB\-\-prompt\fR] [\fB\-\-serial\fR]
+.fi
+
+.nf
+\fBipsec lwdnsq\fR lwdnsq\fR [\fB\-\-help\fR]
+.fi
+
+.SH "DESCRIPTION"
+
+.PP
+The \fBipsec lwdnsq\fR is a helper program that does DNS lookups for other programs. It implements an asynchronous interface on stdin/stdout, with an ASCII driven command language.
+
+.PP
+If stdin is a tty or if the \fB\-\-prompt\fR option is given, then it issues a prompt to the user. Otherwise, it is silent, except for results.
+
+.PP
+The program will accept multiple queries concurrently, with each result being marked with the ID provided on the output. The IDs are strings.
+
+.PP
+If the \fB\-\-serial\fR option is given, then the program will not attempt to execute concurrent queries, but will serialize all input and output.
+
+.SH "QUERY LANGUAGE"
+
+.PP
+There are eleven command that the program understands. This is to lookup different types of records in both the forward and reverse maps. Every query includes a queryid, which is returned in the output, on every single line to identify the transaction.
+
+.SS "KEY queryid FQDN"
+
+.PP
+This request looks up the KEY resource record for the given \fBFQDN.\fR.
+
+.SS "KEY4 queryid A.B.C.D"
+
+.PP
+This request looks up the KEY resource record found in the reverse map for the IP version 4 address \fBA.B.C.D\fR, i.e. it looks up D.C.B.A.in\-addr.arpa.
+
+.SS "KEY6 queryid A:B::C:D"
+
+.PP
+This request looks up the KEY resource record found in the reverse map for the IPv6 address \fBA:B::C:D\fR, i.e. it looks the 32\-nibble long entry in ip6.arpa (and ip6.int).
+
+.SS "TXT4 queryid A.B.C.D"
+
+.PP
+This request looks up the TXT resource record found in the reverse map for the IP version 4 address \fBA.B.C.D\fR, i.e. it looks up D.C.B.A.in\-addr.arpa.
+
+.SS "TXT6 queryid A:B::C:D"
+
+.PP
+This request looks up the TXT resource record found in the reverse map for the IPv6 address \fBA:B::C:D\fR, i.e. it looks the 32\-nibble long entry in ip6.arpa (and ip6.int).
+
+.SS "KEY queryid FQDN"
+
+.PP
+This request looks up the IPSECKEY resource record for the given \fBFQDN.\fR. See note about IPSECKEY processing, below.
+
+.SS "IPSECKEY4 queryid A.B.C.D"
+
+.PP
+This request looks up the IPSECKEY resource record found in the reverse map for the IP version 4 address \fBA.B.C.D\fR, i.e. it looks up D.C.B.A.in\-addr.arpa. See special note about IPSECKEY processing, below.
+
+.SS "IPSECKEY6 queryid A:B::C:D"
+
+.PP
+This request looks up the IPSECKEY resource record found in the reverse map for the IPv6 address \fBA:B::C:D\fR, i.e. it looks the 32\-nibble long entry in ip6.arpa (and ip6.int). See special note about IPSECKEY processing, below.
+
+.SS "OE4 queryid A.B.C.D"
+
+.PP
+This request looks an appropriate record for Opportunistic Encryption for the given IP address. This attempts to look for the delegation record. This may be one of IPSECKEY, KEY, or TXT record. Unless configured otherwise, (see OE4 Directives, below), then a query type of ANY will be used to retrieve all relevant records, and all will be returned.
+
+.SS "OE6 queryid A:B::C:D"
+
+.PP
+This request looks an appropriate record for Opportunistic Encryption for the given IPv6 address. This attempts to look for the delegation record. This may be one of IPSECKEY, KEY, or TXT record. Unless configured otherwise, (see OE Directives, below), then a query type of ALL will be used to retrieve all relevant records, and all will be returned. i.e. it looks the 32\-nibble long entry in ip6.arpa (and ip6.int).
+
+.SS "A queryid FQDN"
+
+.PP
+This request looks up the A (IPv4) resource record for the given \fBFQDN.\fR.
+
+.SS "AAAA queryid FQDN"
+
+.PP
+This request looks up the AAAA (IPv6) resource record for the given \fBFQDN.\fR.
+
+.SH "REPLIES TO QUERIES"
+
+.PP
+All replies from the queries are in the following format:
+
+.nf
+
+<ID> <TIME> <TTL> <TYPE> <TYPE\-SPECIFIC> \\n
+
+.fi
+
+
+.TP
+\fIID\fR
+this is the \fBqueryid\fR value that was provided in the query. It is repeated on every line to permit the replies to be properly associated with the query. When the response is not ascribable to particular query (such as for a mis\-formed query), then the query ID "0" will be used.
+
+.TP
+\fITIME\fR
+this is the current time in seconds since epoch.
+
+.TP
+\fITTL\fR
+for answers which have a time to live, this is the current value. The answer is valid for this number of seconds. If there is no useful value here, then the number 0 is used.
+
+.TP
+\fITYPE\fR
+This is the type of the record that is being returned. The types are described in the next section. The TYPE specific data that follows is specific to the type.
+
+
+.PP
+The replies are limited to 4096 bytes, a value defined as \fBLWDNSQ_RESULT_LEN_MAX\fR. This is defined in \fIfreeswan.h\fR.
+
+.PP
+All of the replies which include resource records use the standard presentation format (with no line feeds or carriage returns) in their answer.
+
+.SS "START"
+
+.PP
+This reply indicates that a query has been received and has been started. It serves as an anchor point for timing, as well as an acknowledgement.
+
+.SS "DONE"
+
+.PP
+This reply indicates that a query is entirely over, and no further information from this query will be sent.
+
+.SS "RETRY"
+
+.PP
+This reply indicates that a query is entirely over, but that no data was found. The records may exist, but appropriate servers could not be reached.
+
+.SS "FATAL"
+
+.PP
+This reply indicates that a query is entirely over, and that no data of the type requested could be found. There were no timeouts, and all servers were available and confirmed non\-existances. There may be NXT records returned prior to this.
+
+.SS "CNAME"
+
+.PP
+This is an interim reply, and indicates that a CNAME was found (and followed) while performing the query. The value of the CNAME is present in the type specific section.
+
+.SS "CNAMEFROM"
+
+.PP
+This is an interim reply, and indicates that a CNAME was found. The original name that was queries for was not the canonical name, and this reply indicates the name that was actually followed.
+
+.SS "NAME"
+
+.PP
+This is an interim reply. The original name that was queries for was not the canonical name. This reply indicates the canonical name.
+
+.SS "DNSSEC"
+
+.PP
+This is an interim reply. It is followed either by "OKAY" or "not present. It indicates if DNSSEC was available on the reply.
+
+.SS "TXT and AD-TXT"
+
+.PP
+This is an interim reply. If there are TXT resource records in the reply, then each one is presented using this type. If preceeded by AD\-, then this record was signed with DNSSEC.
+
+.SS "A and AD-A"
+
+.PP
+This is an interim reply. If there are A resource records in the reply, then each one is presented using this type. If preceeded by AD\-, then this record was signed with DNSSEC.
+
+.SS "AAAA and AD-AAAA"
+
+.PP
+This is an interim reply. If there are AAAA resource records in the reply, then each one is presented using this type. If preceeded by AD\-, then this record was signed with DNSSEC.
+
+.SS "PTR and AD-PTR"
+
+.PP
+This is an interim reply. If there are PTR resource records in the reply, then each one is presented using this type. If preceeded by AD\-, then this record was signed with DNSSEC.
+
+.SS "KEY and AD-KEY"
+
+.PP
+This is an interim reply. If there are KEY resource records in the reply, then each one is presented using this type. If preceeded by AD\-, then this record was signed with DNSSEC.
+
+.SS "IPSECKEY and AD-IPSECKEY"
+
+.PP
+This is an interim reply. If there are IPSEC resource records in the reply, then each one is presented using this type. If preceeded by AD\-, then this record was signed with DNSSEC.
+
+.SH "SPECIAL IPSECKEY PROCESSING"
+
+.PP
+At the time of this writing, the IPSECKEY resource record is not entirely specified. In particular no resource record number has been assigned. This program assumes that it is resource record number 45. If the file /etc/ipsec.d/lwdnsq.conf exists, and contains a line like
+
+.nf
+
+ipseckey_rr=\fBnumber\fR
+
+.fi
+ then this number will be used instead. The file is read only once at startup.
+
+.SH "OE DIRECTIVES"
+
+.PP
+If the file /etc/ipsec.d/lwdnsq.conf exists, and contains a line like
+
+.nf
+
+queryany=false
+
+.fi
+ then instead of doing an ALL query when looking for OE delegation records, lwdnsq will do a series of queries. It will first look for IPSECKEY, and then TXT record. If it finds neither, it will then look for KEY records of all kinds, although they do not contain delegation information.
+
+.SH "SPECIAL IPSECKEY PROCESSING"
+
+.nf
+
+/etc/ipsec.d/lwdnsq.conf
+
+.fi
+
+.SH AUTHOR
+Michael Richardson <mcr@sandelman.ottawa.on.ca>.
diff --git a/programs/lwdnsq/lwdnsq.c b/programs/lwdnsq/lwdnsq.c
new file mode 100644
index 000000000..2684a7d45
--- /dev/null
+++ b/programs/lwdnsq/lwdnsq.c
@@ -0,0 +1,506 @@
+/*
+ * DNS KEY lookup helper
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+char tncfg_c_version[] = "RCSID $Id: lwdnsq.c,v 1.1 2004/03/15 20:35:28 as Exp $";
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <freeswan.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/types.h>
+#include <isc/result.h>
+#include <isc/mem.h>
+#include <isc/buffer.h>
+#include <isc/region.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <lwres/netdb.h>
+#include <lwres/async.h>
+
+#include "lwdnsq.h"
+
+static void
+usage(char *name)
+{
+ fprintf(stdout,"%s --attach --virtual <virtual-device> --physical <physical-device>\n",
+ name);
+ exit(1);
+}
+
+static struct option const longopts[] =
+{
+ {"prompt", 0, 0, 'i'},
+ {"serial", 0, 0, 's'},
+ {"debug", 0, 0, 'g'},
+ {"regress",0, 0, 'X'},
+ {"ignoreeof",0, 0, 'Z'},
+ {0, 0, 0, 0}
+};
+
+/* globals */
+jmp_buf getMeOut;
+
+void sig_handler(int sig)
+{
+ fprintf(stderr, "Caught signal %d, cleaning up and exiting\n", sig);
+ longjmp(getMeOut, 1);
+}
+
+void cmdprompt(dnskey_glob *gs)
+{
+ if(gs->prompt) {
+ printf("lwdnsq> ");
+ }
+ fflush(gs->cmdproto_out);
+}
+
+void quitprog(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ gs->done=1;
+}
+
+void setdebug(dnskey_glob *gs,
+ int argc,
+ char **argv)
+{
+ if(argc > 1) {
+ gs->debug=strtoul(argv[1],NULL,0);
+ }
+ printf("0 DEBUG is %d\n",gs->debug);
+}
+
+
+int cmdparse(dnskey_glob *gs,
+ char *cmdline)
+{
+ char *argv[256];
+ int argc;
+ char *arg;
+ static const struct cmd_entry {
+ const char *cmdname;
+ void (*cmdfunc)(dnskey_glob *, int, char **);
+ } cmds[]={
+ {"key", lookup_key},
+ {"key4", lookup_key4},
+ {"key6", lookup_key6},
+ {"txt", lookup_txt},
+ {"txt4", lookup_txt4},
+ {"txt6", lookup_txt6},
+ {"ipseckey", lookup_ipseckey},
+ {"ipseckey4", lookup_ipseckey4},
+ {"ipseckey6", lookup_ipseckey6},
+ {"oe4", lookup_oe4},
+ {"oe6", lookup_oe6},
+ {"vpn4", lookup_key4},
+ {"vpn6", lookup_key6},
+ {"quit", quitprog},
+ {"a", lookup_a},
+ {"aaaa", lookup_aaaa},
+ {"debug", setdebug},
+ {NULL, NULL}};
+ const struct cmd_entry *ce = cmds;
+
+ argc=0;
+
+ /* skip initial spaces */
+ while(cmdline && isspace(*cmdline)) {
+ cmdline++;
+ }
+
+ while(cmdline && *cmdline!='\0' &&
+ (arg=strsep(&cmdline, " \t\n"))!=NULL) {
+ if (argc < sizeof(argv)/sizeof(*argv - 1)) {
+ /* ignore arguments that would overflow.
+ * XXX should generate a diagnostic.
+ */
+ argv[argc++]=arg;
+ }
+ while(cmdline && isspace(*cmdline)) {
+ cmdline++;
+ }
+ }
+ argv[argc]=NULL;
+
+ if(argc==0 || argv[0][0]=='\0') {
+ /* ignore empty line */
+ } else if(strcasecmp("help", argv[0]) == 0) {
+ fprintf(gs->cmdproto_out, "0 HELP\n");
+ for (; ce->cmdname != NULL; ce++)
+ fprintf(gs->cmdproto_out, "0 HELP %s\n", ce->cmdname);
+ } else {
+ for (;; ce++) {
+ if (ce->cmdname == NULL) {
+ fprintf(gs->cmdproto_out, "0 FATAL unknown command \"%s\"\n", argv[0]);
+ break;
+ }
+ if(strcasecmp(ce->cmdname, argv[0])==0) {
+ (*ce->cmdfunc)(gs, argc, argv);
+ break;
+ }
+ }
+ }
+
+ if (!gs->done)
+ cmdprompt(gs);
+ return 0;
+}
+
+int cmdread(dnskey_glob *gs,
+ char *buf,
+ int len)
+{
+ unsigned char *nl;
+ int cmdlen;
+
+ cmdlen=0;
+
+ /*
+ * have to handle partial reads and multiple commands
+ * per read, since this may in fact be a file or a pipe.
+ */
+ if((gs->cmdloc + len + 1) > sizeof(gs->cmdbuf)) {
+ fprintf(stderr, "command '%.*s...' is too long, discarding!\n",
+ 40, buf);
+ fflush(stdout);
+
+ gs->cmdloc=0;
+ return 0;
+ }
+ memcpy(gs->cmdbuf+gs->cmdloc, buf, len);
+ gs->cmdloc+=len;
+ gs->cmdbuf[gs->cmdloc]='\0';
+
+ while((nl = strchr(gs->cmdbuf, '\n')) != NULL) {
+ /* found a newline, so turn it into a \0, and process the
+ * command, and then we will pull the rest of the buffer
+ * up.
+ */
+ *nl='\0';
+ cmdlen= nl - gs->cmdbuf +1;
+
+ cmdparse(gs, gs->cmdbuf);
+
+ gs->cmdloc -= cmdlen;
+ memmove(gs->cmdbuf, gs->cmdbuf+cmdlen, gs->cmdloc);
+ }
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *program_name;
+ dnskey_glob gs;
+ int c;
+ static int ignoreeof=0; /* static to avoid longjmp clobber */
+ int ineof;
+
+ memset(&gs, 0, sizeof(dnskey_glob));
+
+#if 0
+ printf("PID: %d\n", getpid());
+ sleep(60);
+#endif
+
+ program_name = argv[0];
+ gs.concurrent = 1;
+
+ if(lwres_async_init(&gs.lwctx) != ERRSET_SUCCESS) {
+ fprintf(stderr, "Can not initialize async context\n");
+ exit(3);
+ }
+
+ if(isc_mem_create(0,0,&gs.iscmem) != ISC_R_SUCCESS) {
+ fprintf(stderr, "Can not initialize isc memory allocator\n");
+ exit(4);
+ }
+
+ if(isc_buffer_allocate(gs.iscmem, &gs.iscbuf, LWDNSQ_RESULT_LEN_MAX)) {
+ fprintf(stderr, "Can not allocate a result buffer\n");
+ exit(5);
+ }
+
+ while((c = getopt_long_only(argc, argv, "dgsiXZ", longopts, 0)) != EOF) {
+ switch(c) {
+ case 'd':
+ gs.debug+=2;
+ break;
+
+ case 'g':
+ gs.debug++;
+ break;
+ case 's':
+ gs.concurrent=0;
+ break;
+ case 'i':
+ gs.prompt=1;
+ break;
+ case 'X':
+ gs.regress++;
+ break;
+
+ case 'Z':
+ ignoreeof=1;
+ break;
+
+ default:
+ usage(program_name);
+ break;
+ }
+ }
+
+ if(gs.debug && ignoreeof) {
+ fprintf(stderr, "Ignoring end of file\n");
+ }
+
+ if(isatty(0)) {
+ gs.prompt=1;
+ }
+
+ /* do various bits of setup */
+ if(setjmp(getMeOut)!=0) {
+ signal(SIGINT, SIG_DFL);
+ signal(SIGPIPE, SIG_IGN);
+
+ /* cleanup_crap(); */
+
+ exit(1);
+ }
+
+ if(signal(SIGINT, sig_handler) < 0)
+ perror("Setting handler for SIGINT");
+
+ if(signal(SIGPIPE, sig_handler) < 0)
+ perror("Setting handler for SIGINT");
+
+ cmdprompt(&gs);
+
+ ineof = 0;
+ gs.done = 0;
+ gs.cmdproto_out = stdout;
+ gs.l_fds[0].events = POLLIN|POLLHUP;
+ gs.l_fds[0].fd=0;
+
+ gs.l_fds[1].events = POLLIN|POLLHUP|POLLERR;
+ gs.l_fds[1].fd = lwres_async_fd(gs.lwctx);
+
+ gs.l_nfds= 2;
+
+ while(!gs.done)
+ {
+ int timeout;
+ char buf[128];
+ int n;
+ int rlen;
+
+ timeout=-1;
+
+ gs.l_fds[0].revents = 0;
+
+ gs.l_fds[1].events = POLLIN|POLLHUP|POLLERR;
+ gs.l_fds[1].revents = 0;
+ gs.l_fds[1].fd = lwres_async_fd(gs.lwctx);
+
+ if(gs.debug > 1) {
+ fprintf(stderr, "=== invoking poll(,%d,) with %s\n",
+ gs.l_nfds,
+ timeout>0 ? "waittime" : "no wait");
+ for(n = 0; n < gs.l_nfds; n++) {
+ fprintf(stderr, "=== waiting on fd#%d\n",
+ gs.l_fds[n].fd);
+ }
+ fprintf(stderr, "=== inflight: %d\n", gs.dns_inflight);
+ }
+
+ n = poll(gs.l_fds, gs.l_nfds, timeout);
+
+ if(n == 0) {
+ /* timeout! */
+ }
+
+ if(n < 0) {
+ perror("poll");
+ }
+
+ if(gs.debug > 1) {
+ fprintf(stderr, "=== poll returned with %d\n", n);
+ }
+
+ while(n>0) {
+ if((gs.l_fds[0].revents & POLLERR) == POLLERR ||
+ (gs.l_fds[1].revents & POLLERR) == POLLERR)
+ {
+ break;
+ }
+
+ /* see if there are DNS events coming back */
+ if((gs.l_fds[1].revents & POLLIN) == POLLIN) {
+ if(gs.debug > 1) {
+ fprintf(stderr,
+ "=== new responses from lwdnsd\n");
+ }
+
+ process_dns_reply(&gs);
+ fflush(stdout);
+ n--;
+ }
+
+ if(!ignoreeof &&
+ (gs.l_fds[0].revents & POLLHUP) == POLLHUP)
+ {
+ break;
+ }
+
+ if((gs.l_fds[0].revents & POLLIN) == POLLIN) {
+
+ rlen=read(0, buf, sizeof(buf));
+
+ if(gs.debug > 1) {
+ if(rlen > 0) {
+ buf[rlen]='\0';
+ }
+ fprintf(stderr,
+ "=== new commands on fd 0: %d: %s\n",
+ rlen, buf);
+ }
+
+ if(rlen > 0) {
+ cmdread(&gs, buf, rlen);
+ } else if(rlen == 0) {
+ ineof = 1;
+ if(!ignoreeof) {
+ /* EOF, die */
+ gs.done=1;
+ }
+ }
+ n--;
+ }
+
+ }
+
+ if((gs.l_fds[0].revents & POLLHUP) == POLLHUP)
+ {
+ ineof = 1;
+ if(!ignoreeof)
+ {
+ gs.done=1;
+ }
+ }
+
+ if(ignoreeof) {
+ /* if we have exhausted the input,
+ * and there are none in flight,
+ * then exit, finally.
+ */
+ if(ineof) {
+ if(gs.dns_inflight == 0) {
+ gs.done=1;
+ }
+ }
+ }
+
+ if(gs.debug) {
+ fprintf(stderr, "=== ineof: %d inflight: %d\n",
+ ineof, gs.dns_inflight);
+ }
+
+ }
+
+ signal(SIGINT, SIG_DFL);
+ signal(SIGPIPE, SIG_IGN);
+
+ exit(0);
+}
+
+/*
+ * $Log: lwdnsq.c,v $
+ * Revision 1.1 2004/03/15 20:35:28 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.12 2003/09/16 05:01:14 mcr
+ * prefix all debugging with === so that it can be easily removed.
+ *
+ * Revision 1.11 2003/09/10 04:43:52 mcr
+ * final fixes to lwdnsq to exit only when all requests are done,
+ * and we have been told to wait, *OR* if there is an EOF in stdin.
+ *
+ * Revision 1.10 2003/09/03 01:13:24 mcr
+ * first attempt at async capable lwdnsq.
+ *
+ * Revision 1.9 2003/04/02 07:37:57 dhr
+ *
+ * lwdnsq: fix non-deterministic bug in handling batched input
+ *
+ * Revision 1.8 2003/02/08 04:03:06 mcr
+ * renamed --single to --serial.
+ *
+ * Revision 1.7 2003/01/14 03:01:14 dhr
+ *
+ * improve diagnostics; tidy
+ *
+ * Revision 1.6 2002/12/19 07:29:47 dhr
+ *
+ * - avoid (improbable) buffer overflow
+ * - suppress prompt after "quit" command
+ * - add space to prompt to match aesthetics and man page
+ * - elminate a magic number
+ *
+ * Revision 1.5 2002/12/19 07:08:42 dhr
+ *
+ * continue renaming dnskey => lwdnsq
+ *
+ * Revision 1.4 2002/12/12 06:03:41 mcr
+ * added --regress option to force times to be regular
+ *
+ * Revision 1.3 2002/11/25 18:37:48 mcr
+ * make sure that we exit cleanly upon EOF.
+ *
+ * Revision 1.2 2002/11/16 02:53:53 mcr
+ * lwdnsq - with new contract added.
+ *
+ * Revision 1.1 2002/10/30 02:25:31 mcr
+ * renamed version of files from dnskey/
+ *
+ * Revision 1.3 2002/10/09 20:14:16 mcr
+ * make sure to flush stdout at the right time - do it regardless
+ * of whether or not we are printing prompts.
+ *
+ * Revision 1.2 2002/09/30 18:55:54 mcr
+ * skeleton for dnskey helper program.
+ *
+ * Revision 1.1 2002/09/30 16:50:23 mcr
+ * documentation for "dnskey" helper
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * c-basic-offset: 2
+ * End:
+ *
+ */
diff --git a/programs/lwdnsq/lwdnsq.h b/programs/lwdnsq/lwdnsq.h
new file mode 100644
index 000000000..109b39507
--- /dev/null
+++ b/programs/lwdnsq/lwdnsq.h
@@ -0,0 +1,121 @@
+/*
+ * DNS KEY lookup global definitions
+ * Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef POLLIN
+#include <poll.h>
+#endif
+
+#include "freeswan.h"
+
+/*
+ * a base-64 encoded 2192 bit key takes:
+ * 2192/8 * 4/3 = 365 bytes.
+ *
+ * a base-64 encoded 16384 bit key takes:
+ * 16384/8*4/3 = 2730 bytes.
+ *
+ * so, we pick 4096 bytes as the maximum.
+ *
+ * Note that TXT records may have an introducer (X-IPsec) and an ID which
+ * is either an IP address or @FQDN that preceeds the base64 encoded key.
+ *
+ */
+
+enum dkl_state {
+ dkl_start, /* no work yet none - initial state */
+ dkl_first, /* sent first DNS request. */
+ dkl_cname, /* sent request for CNAME record */
+ dkl_second, /* sent request for thing CNAME pointed to */
+ dkl_done /* done */
+};
+
+typedef struct dnskey_lookup dnskey_lookup;
+
+struct dnskey_lookup {
+ struct lwres_async_state las;
+ dnskey_lookup *next;
+ char *tracking_id;
+ enum dkl_state step;
+ /* lwres_context_t *ctx; */
+ char *wantedtype_name;
+ dns_rdatatype_t wantedtype;
+ char *fqdn;
+ int cname_count;
+ int last_cname_used;
+ dns_name_t last_cname;
+ int retry_count;
+};
+
+typedef struct dnskey_glob {
+ int debug;
+ int prompt;
+ int concurrent;
+ int done;
+ int regress; /* if 1, then we are doing regression testing */
+ struct pollfd l_fds[5]; /* array of input sources */
+ int l_nfds; /* number of relevant entries */
+ int cmdloc;
+ unsigned char cmdbuf[LWDNSQ_CMDBUF_LEN];
+ FILE *cmdproto_out;
+ dnskey_lookup *dns_outstanding;
+ int dns_inflight;
+ lwres_context_t *lwctx;
+ isc_mem_t *iscmem;
+ isc_buffer_t *iscbuf;
+} dnskey_glob;
+
+/* in cmds.c */
+extern void lookup_key(dnskey_glob *gs,int, char **);
+extern void lookup_key4(dnskey_glob *gs,int, char **);
+extern void lookup_key6(dnskey_glob *gs,int, char **);
+extern void lookup_txt(dnskey_glob *gs,int, char **);
+extern void lookup_txt4(dnskey_glob *gs,int, char **);
+extern void lookup_txt6(dnskey_glob *gs,int, char **);
+extern void lookup_ipseckey(dnskey_glob *gs,int, char **);
+extern void lookup_ipseckey4(dnskey_glob *gs,int, char **);
+extern void lookup_ipseckey6(dnskey_glob *gs,int, char **);
+extern void lookup_oe4(dnskey_glob *gs,int, char **);
+extern void lookup_oe6(dnskey_glob *gs,int, char **);
+extern void lookup_a(dnskey_glob *gs,int, char **);
+extern void lookup_aaaa(dnskey_glob *gs,int, char **);
+extern void output_transaction_line(dnskey_glob *gs,
+ char *id,
+ int ttl,
+ char *cmd,
+ char *data);
+extern void output_transaction_line_limited(dnskey_glob *gs,
+ char *id,
+ int ttl,
+ char *cmd,
+ int max,
+ char *data);
+
+
+/* lookup code */
+extern void process_dns_reply(dnskey_glob *gs);
+extern void lookup_thing(dnskey_glob *gs,
+ dns_rdatatype_t wantedtype,
+ char *wantedtype_name,
+ char *id,
+ char *fqdn);
+
+/*
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * c-basic-offset: 2
+ * End:
+ *
+ */
diff --git a/programs/lwdnsq/lwdnsq.xml.in b/programs/lwdnsq/lwdnsq.xml.in
new file mode 100644
index 000000000..4c4039120
--- /dev/null
+++ b/programs/lwdnsq/lwdnsq.xml.in
@@ -0,0 +1,446 @@
+<?xml version='1.0'?> <!-- -*- docbook -*- -->
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<article>
+ <articleinfo>
+ <title>lwdnsq</title>
+
+ <author>
+ <firstname>Michael</firstname>
+ <surname>Richardson</surname>
+ <affiliation>
+ <address><email>mcr@sandelman.ottawa.on.ca</email></address>
+ </affiliation>
+ </author>
+
+ <copyright>
+ <year>2003</year>
+ <holder>Michael Richardson</holder>
+ </copyright>
+ </articleinfo>
+
+ <section>
+ <title>Reference</title>
+
+<refentry id="ipsec_lwdnsq">
+
+<refmeta>
+<refentrytitle>ipsec lwdnsq</refentrytitle>
+<manvolnum>8</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname>lwdnsq</refname>
+<refpurpose>lookup items in DNS to help pluto (and others)</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+
+<cmdsynopsis>
+ <command>ipsec lwdnsq</command>
+ <arg choice="opt"><option>--prompt</option></arg>
+ <arg choice="opt"><option>--serial</option></arg>
+</cmdsynopsis>
+
+<cmdsynopsis>
+ <command>ipsec lwdnsq</command>
+ <arg choice="opt"><option>--help</option></arg>
+</cmdsynopsis>
+
+</refsynopsisdiv>
+
+<refsect1><title>Description</title>
+<para>
+The
+<command>ipsec lwdnsq</command>
+is a helper program that does DNS lookups for other programs. It implements
+an asynchronous interface on stdin/stdout, with an ASCII driven command
+language.
+</para>
+
+<para>
+If stdin is a tty or if the
+<option>--prompt</option>
+option is given, then it issues a prompt to the user. Otherwise, it is
+silent, except for results.
+</para>
+
+<para>
+The program will accept multiple queries concurrently, with each result
+being marked with the ID provided on the output. The IDs are strings.
+</para>
+
+<para>
+If the
+<option>--serial</option>
+option is given, then the program will not attempt to execute concurrent
+queries, but will serialize all input and output.
+</para>
+
+</refsect1>
+
+<refsect1><title>QUERY LANGUAGE</title>
+
+<para>
+There are eleven command that the program understands. This is to lookup
+different types of records in both the forward and reverse maps. Every query
+includes a queryid, which is returned in the output, on every single line to
+identify the transaction.
+</para>
+
+<refsect2><title>KEY <option>queryid</option> <option>FQDN</option></title>
+<para>
+This request looks up the KEY resource record for the given <option>FQDN.</option>.
+</para>
+</refsect2>
+
+<refsect2>
+<title>KEY4 <option>queryid</option> <option>A.B.C.D</option></title>
+<para>
+This request looks up the KEY resource record found in the reverse map for
+the IP version 4 address <option>A.B.C.D</option>, i.e. it looks
+up D.C.B.A.in-addr.arpa.
+</para>
+</refsect2>
+
+<refsect2>
+<title>KEY6 <option>queryid</option> <option>A:B::C:D</option></title>
+<para>
+This request looks up the KEY resource record found in the reverse map
+for the IPv6 address <option>A:B::C:D</option>, i.e.
+it looks the 32-nibble long entry in ip6.arpa (and ip6.int).
+</para>
+</refsect2>
+
+<refsect2>
+<title>TXT4 <option>queryid</option> <option>A.B.C.D</option></title>
+<para>
+This request looks up the TXT resource record found in the reverse map for
+the IP version 4 address <option>A.B.C.D</option>, i.e. it looks
+up D.C.B.A.in-addr.arpa.
+</para>
+</refsect2>
+
+<refsect2>
+<title>TXT6 <option>queryid</option> <option>A:B::C:D</option></title>
+<para>
+This request looks up the TXT resource record found in the reverse map
+for the IPv6 address <option>A:B::C:D</option>, i.e.
+it looks the 32-nibble long entry in ip6.arpa (and ip6.int).
+</para>
+</refsect2>
+
+<refsect2>
+<title>KEY <option>queryid</option> <option>FQDN</option></title>
+<para>
+This request looks up the IPSECKEY resource record for the given
+<option>FQDN.</option>. See note about IPSECKEY processing, below.
+</para>
+</refsect2>
+
+<refsect2>
+<title>IPSECKEY4 <option>queryid</option> <option>A.B.C.D</option></title>
+<para>
+This request looks up the IPSECKEY resource record found in the reverse map for
+the IP version 4 address <option>A.B.C.D</option>, i.e. it looks
+up D.C.B.A.in-addr.arpa. See special note about IPSECKEY processing, below.
+</para>
+</refsect2>
+
+<refsect2>
+<title>IPSECKEY6 <option>queryid</option> <option>A:B::C:D</option></title>
+<para>
+This request looks up the IPSECKEY resource record found in the reverse map
+for the IPv6 address <option>A:B::C:D</option>, i.e.
+it looks the 32-nibble long entry in ip6.arpa (and ip6.int). See
+special note about IPSECKEY processing, below.
+</para>
+</refsect2>
+
+<refsect2>
+<title>OE4 <option>queryid</option> <option>A.B.C.D</option></title>
+<para>
+This request looks an appropriate record for Opportunistic
+Encryption for the given IP address. This attempts to look for the
+delegation record. This may be one of IPSECKEY, KEY, or TXT
+record. Unless configured otherwise, (see OE4 Directives, below), then
+a query type of ANY will be used to retrieve all relevant records, and
+all will be returned.
+</para>
+</refsect2>
+
+<refsect2>
+<title>OE6 <option>queryid</option> <option>A:B::C:D</option></title>
+<para>
+This request looks an appropriate record for Opportunistic
+Encryption for the given IPv6 address. This attempts to look for the
+delegation record. This may be one of IPSECKEY, KEY, or TXT
+record. Unless configured otherwise, (see OE Directives, below), then
+a query type of ALL will be used to retrieve all relevant records, and
+all will be returned.
+i.e. it looks the 32-nibble long entry in ip6.arpa (and ip6.int).
+</para>
+</refsect2>
+
+<refsect2>
+<title>A <option>queryid</option> <option>FQDN</option></title>
+<para>
+This request looks up the A (IPv4) resource record for the given
+<option>FQDN.</option>.
+</para>
+</refsect2>
+
+<refsect2>
+<title>AAAA <option>queryid</option> <option>FQDN</option></title>
+<para>
+This request looks up the AAAA (IPv6) resource record for the given
+<option>FQDN.</option>.
+</para>
+</refsect2>
+
+</refsect1>
+
+<refsect1><title>Replies to queries</title>
+
+<para>
+All replies from the queries are in the following format:
+<programlisting>
+&lt;ID&gt; &lt;TIME&gt; &lt;TTL&gt; &lt;TYPE&gt; &lt;TYPE-SPECIFIC&gt; \n
+</programlisting>
+
+<variablelist>
+
+<varlistentry><term><parameter>ID</parameter></term>
+<listitem>
+<para>
+this is the <option>queryid</option> value that was provided in
+the query. It is repeated on every line to permit the replies to be
+properly associated with the query. When the response is not ascribable to
+particular query (such as for a mis-formed query), then the query ID "0" will
+be used.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><parameter>TIME</parameter></term>
+<listitem>
+<para>
+this is the current time in seconds since epoch.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><parameter>TTL</parameter></term>
+<listitem>
+<para>
+for answers which have a time to live, this is the current value. The
+answer is valid for this number of seconds. If there is no useful
+value here, then the number 0 is used.
+</para>
+</listitem>
+</varlistentry>
+
+
+<varlistentry><term><parameter>TYPE</parameter></term>
+<listitem>
+<para>
+This is the type of the record that is being returned. The types are
+described in the next section. The TYPE specific data that follows is
+specific to the type.
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</para>
+
+<para>
+The replies are limited to 4096 bytes, a value defined as
+<constant>LWDNSQ_RESULT_LEN_MAX</constant>. This is defined in
+<filename>freeswan.h</filename>.
+</para>
+
+<para>All of the replies which include resource records use the
+standard presentation format (with no line feeds or carriage returns)
+in their answer.</para>
+
+<refsect2>
+<title>START</title>
+<para>
+This reply indicates that a query has been received and has been
+started. It serves as an anchor point for timing, as well as an acknowledgement.
+</para>
+</refsect2>
+
+<refsect2>
+<title>DONE</title>
+<para>
+This reply indicates that a query is entirely over, and no further
+information from this query will be sent.
+</para>
+</refsect2>
+
+<refsect2>
+<title>RETRY</title>
+<para>
+This reply indicates that a query is entirely over, but that no
+data was found. The records may exist, but appropriate servers could
+not be reached.
+</para>
+</refsect2>
+
+<refsect2>
+<title>FATAL</title>
+<para>
+This reply indicates that a query is entirely over, and that no
+data of the type requested could be found. There were no timeouts, and
+all servers were available and confirmed non-existances. There may be
+NXT records returned prior to this.
+</para>
+</refsect2>
+
+<refsect2>
+<title>CNAME</title>
+<para>
+This is an interim reply, and indicates that a CNAME was found (and
+followed) while performing the query. The value of the CNAME is
+present in the type specific section.
+</para>
+</refsect2>
+
+<refsect2>
+<title>CNAMEFROM</title>
+<para>
+This is an interim reply, and indicates that a CNAME was found. The
+original name that was queries for was not the canonical name, and
+this reply indicates the name that was actually followed.
+</para>
+</refsect2>
+
+<refsect2>
+<title>NAME</title>
+<para>
+This is an interim reply. The original name that was queries for was
+not the canonical name. This reply indicates the canonical name.
+</para>
+</refsect2>
+
+<refsect2>
+<title>DNSSEC</title>
+<para>
+This is an interim reply. It is followed either by "OKAY" or "not
+present.
+It indicates if DNSSEC was available on the reply.
+</para>
+</refsect2>
+
+<refsect2>
+<title>TXT and AD-TXT</title>
+<para>
+This is an interim reply. If there are TXT resource records in the
+reply, then each one is presented using this type. If preceeded by
+AD-, then this record was signed with DNSSEC.
+</para>
+</refsect2>
+
+<refsect2>
+<title>A and AD-A</title>
+<para>
+This is an interim reply. If there are A resource records in the
+reply, then each one is presented using this type. If preceeded by
+AD-, then this record was signed with DNSSEC.
+</para>
+</refsect2>
+
+<refsect2>
+<title>AAAA and AD-AAAA</title>
+<para>
+This is an interim reply. If there are AAAA resource records in the
+reply, then each one is presented using this type. If preceeded by
+AD-, then this record was signed with DNSSEC.
+</para>
+</refsect2>
+
+<refsect2>
+<title>PTR and AD-PTR</title>
+<para>
+This is an interim reply. If there are PTR resource records in the
+reply, then each one is presented using this type. If preceeded by
+AD-, then this record was signed with DNSSEC.
+</para>
+</refsect2>
+
+<refsect2>
+<title>KEY and AD-KEY</title>
+<para>
+This is an interim reply. If there are KEY resource records in the
+reply, then each one is presented using this type. If preceeded by
+AD-, then this record was signed with DNSSEC.
+</para>
+</refsect2>
+
+
+<refsect2>
+<title>IPSECKEY and AD-IPSECKEY</title>
+<para>
+This is an interim reply. If there are IPSEC resource records in the
+reply, then each one is presented using this type. If preceeded by
+AD-, then this record was signed with DNSSEC.
+</para>
+</refsect2>
+
+
+</refsect1>
+
+<refsect1><title>Special IPSECKEY processing</title>
+
+<para>
+At the time of this writing, the IPSECKEY resource record is not
+entirely specified. In particular no resource record number has been
+assigned. This program assumes that it is resource record number
+45. If the file
+@IPSEC_CONFDDIR@/lwdnsq.conf
+exists, and contains a line like
+<programlisting>
+ipseckey_rr=<option>number</option>
+</programlisting>
+then this number will be used instead. The file is read only once at
+startup.
+</para>
+</refsect1>
+
+<refsect1><title>OE Directives</title>
+
+<para>
+If the file
+@IPSEC_CONFDDIR@/lwdnsq.conf
+exists, and contains a line like
+<programlisting>
+queryany=false
+</programlisting>
+then instead of doing an ALL query when looking for OE delegation
+records, lwdnsq will do a series of queries. It will first look for
+IPSECKEY, and then TXT record. If it finds neither, it will then look
+for KEY records of all kinds, although they do not contain delegation
+information.
+</para>
+</refsect1>
+
+<refsect1><title>Special IPSECKEY processing</title>
+
+<programlisting>
+/etc/ipsec.d/lwdnsq.conf
+</programlisting>
+
+</refsect1>
+
+</refentry>
+</section>
+</article>
+
+
+
+
+
+
diff --git a/programs/lwdnsq/states.fig b/programs/lwdnsq/states.fig
new file mode 100644
index 000000000..6a28249ee
--- /dev/null
+++ b/programs/lwdnsq/states.fig
@@ -0,0 +1,66 @@
+#FIG 3.2
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+6 1305 1530 3330 2205
+2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5
+ 3330 2205 3330 1530 1305 1530 1305 2205 3330 2205
+4 1 0 50 0 0 20 0.0000 4 255 1575 2385 1935 initial request\001
+-6
+6 1350 5850 3375 6525
+2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5
+ 3375 6525 3375 5850 1350 5850 1350 6525 3375 6525
+4 1 0 50 0 0 20 0.0000 4 135 825 2430 6255 success\001
+-6
+6 4275 2700 6525 3375
+2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5
+ 6525 3375 6525 2700 4275 2700 4275 3375 6525 3375
+4 1 0 50 0 0 20 0.0000 4 195 2115 5400 3150 ASK for CNAME\001
+-6
+6 225 3825 2250 4500
+2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5
+ 2250 4500 2250 3825 225 3825 225 4500 2250 4500
+4 1 0 50 0 0 20 0.0000 4 195 750 1305 4230 failure\001
+-6
+6 5625 4545 7875 5220
+2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5
+ 7875 5220 7875 4545 5625 4545 5625 5220 7875 5220
+4 1 0 50 0 0 20 0.0000 4 255 1740 6750 4995 ASK for target\001
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 2 0 1.00 60.00 120.00
+ 3330 1935 4275 2745
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 2 0 1.00 60.00 120.00
+ 2250 2205 1305 3825
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 2 0 1.00 60.00 120.00
+ 4275 3330 2250 4050
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 2 0 1.00 60.00 120.00
+ 2880 2250 2880 5850
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 2 0 1.00 60.00 120.00
+ 5895 5220 3375 6120
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 2 0 1.00 60.00 120.00
+ 5625 4950 2250 4275
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 2 0 1.00 60.00 120.00
+ 6030 3375 6570 4545
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 2 0 1.00 60.00 120.00
+ 7695 4545 6525 3150
+4 0 0 50 0 0 14 0.0000 4 195 1830 3825 2295 ERRSET_NODATA\001
+4 2 0 50 0 0 14 0.0000 4 195 1875 1575 3150 ERRSET_NONAME\001
+4 0 0 50 0 0 14 0.0000 4 150 300 2970 5175 OK\001
+4 0 0 50 0 0 14 0.0000 4 150 300 4500 5895 OK\001
+4 0 0 50 0 0 14 0.0000 4 195 1875 3420 3825 ERRSET_NONAME\001
+4 0 0 50 0 0 14 0.0000 4 195 1875 3420 4500 ERRSET_NONAME\001
+4 0 0 50 0 0 14 0.0000 4 150 300 6390 3960 OK\001
+4 0 0 50 0 0 14 0.0000 4 195 1830 7110 3825 ERRSET_NODATA\001
diff --git a/programs/lwdnsq/states.png b/programs/lwdnsq/states.png
new file mode 100644
index 000000000..ceb5b3c45
--- /dev/null
+++ b/programs/lwdnsq/states.png
Binary files differ
diff --git a/programs/mailkey/.cvsignore b/programs/mailkey/.cvsignore
new file mode 100644
index 000000000..5af485234
--- /dev/null
+++ b/programs/mailkey/.cvsignore
@@ -0,0 +1 @@
+mailkey
diff --git a/programs/mailkey/Makefile b/programs/mailkey/Makefile
new file mode 100644
index 000000000..4b0385823
--- /dev/null
+++ b/programs/mailkey/Makefile
@@ -0,0 +1,41 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:28 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=mailkey
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:28 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.1 2003/02/22 03:26:55 sam
+# remaining pieces of mailkey
+#
+# Revision 1.2 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.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/mailkey/mailkey.8 b/programs/mailkey/mailkey.8
new file mode 100644
index 000000000..be6b4ff93
--- /dev/null
+++ b/programs/mailkey/mailkey.8
@@ -0,0 +1,47 @@
+.TH IPSEC_MAILKEY 8 "21 Feb 2002"
+.\" RCSID $Id: mailkey.8,v 1.1 2004/03/15 20:35:28 as Exp $
+.SH NAME
+ipsec mailkey \- mail DNS records for Opportunistic Encryption
+.SH SYNOPSIS
+.B ipsec
+.B mailkey
+\-\-me
+my@address.tld
+[
+.B \-\-reverse
+1.2.3.4
+] [
+.B \-\-forward
+hostname.domain.tld
+]
+.SH DESCRIPTION
+.I mailkey
+is a meta-program. It generates a script which will attempt to mail the TXT
+records required to enable Opportunistic Encryption (OE).
+.PP
+An e-mail address for the domain's DNS administrator is derived from SOA records.
+The mail body and destination address are freely editable in the script.
+.PP
+If no administrator can be located, the output file will not be executable.
+.PP
+.TP
+\fB\-\-me\fP\ \fImy@address.tld\fP
+set the Reply-To: address of the mail to be sent.
+.TP
+\fB\-\-forward\fP\ \fIhostname.domain.tld\fP
+the domain name to be used for initator-only OE.
+.TP
+\fB\-\-reverse\fP\ \fI1.2.3.4\fP
+the IP address to be used for full Opportunistic Encryption.
+.PP
+Only one of --forward or --reverse may be specified.
+.SH FILES
+.nf
+/etc/ipsec.secrets
+.fi
+.SH SEE ALSO
+ipsec_showhostkey(8), host(8)
+.SH HISTORY
+Written for the Linux FreeS/WAN project <http://www.freeswan.org> by Sam Sgro.
+.SH BUGS
+May produce indeterminate results when processing non-routable IPs.
diff --git a/programs/mailkey/mailkey.in b/programs/mailkey/mailkey.in
new file mode 100755
index 000000000..fecdcf62c
--- /dev/null
+++ b/programs/mailkey/mailkey.in
@@ -0,0 +1,241 @@
+#! /bin/sh
+# mail OE DNS RR info to relevent administrator
+#
+# Copyright (C) 2003 Sam Sgro <sam@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: mailkey.in,v 1.1 2004/03/15 20:35:28 as Exp $
+
+me="ipsec mailkey"
+
+PATH=/sbin:/usr/bin:/usr/local/sbin:@IPSEC_SBINDIR@:$PATH export PATH
+
+reverse=0
+forward=0
+mymail=""
+usage="Usage:
+ $me --me my@address.tld --forward hostname.domain.tld
+ $me --me my@address.tld --reverse 1.2.3.4"
+
+for dummy
+do
+ case "$1" in
+ --help) echo "$usage" ; exit 0 ;;
+ --forward) forward=1 ; reverse=0 ; hostname="$2" ; shift ;;
+ --reverse) reverse=1 ; forward=0 ; reverseip="$2" ; shift ;;
+ --me) mymail="$2" ; shift ;;
+ --) shift ; break ;;
+ -*) echo "$0: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+# only do one of iOE || (pOE/rOE/fOE/insert acronym here) at a time
+# but you have to choose one. Plus, if ya ain't specified your mail address...
+if [ "$forward" -eq "$reverse" ] || [ ! "$mymail" ]
+then
+{
+echo "$usage"; exit 0;
+}
+fi
+
+# Test to see if there is a key to process in the first place.
+test1st=`ipsec showhostkey --txt 1.2.3.4 2>&1`
+test2nd=`echo $test1st | grep TXT`
+if [ ! "$test2nd" ]
+then
+{
+echo "Our attempt to retrieve your RSA key using 'ipsec showhostkey' failed
+with the following error:
+
+"$test1st"
+
+Common concerns: This account must be able to read /etc/ipsec.secrets.
+If you haven't generated your key yet, please run 'ipsec newhostkey'."
+exit 0
+}
+fi
+
+
+# This is where we will save the script.
+save_mail_file=~/"OE_mail_""$reverseip$hostname"
+
+# RSA/SOA processing functions.
+# takes two arguments - the IP address/hostname to be used, and an attempt to guess the
+# beginning of the DNS record for the administrator
+txtprocess(){
+ipsec showhostkey --txt $1 | sed "s/^.* IN TXT/$2. IN TXT/" | grep TXT
+}
+
+# Find the hostmaster part of the SOA.
+# This only works with the "net" portion of in-addr.arpa. commands - 20.168.192.in-addr.arpa. -
+# or the domain portion of FQDNs. The data is prepped using host_data in the individual sections
+# for $forward and $reverse.
+# Note: I've experienced it returning SOAs for non-routeable IP addresses! This needs to be
+# addressed.
+hostprocess(){
+host -t soa $1 | grep SOA | while read a b c d e
+do
+echo $d | sed -e "s/\(^[a-zA-Z0-9-]*\)\.\([a-zA-Z0-9-\.]*\).$/\1@\2/"
+done
+}
+
+# generate the pieces that go into the template, which are dependent on the type of OE.
+if [ "$reverse" -eq 1 ]; then
+{
+# convert the reverse ip to something appropriate for a DNS record.
+arpaip=`echo $reverseip | sed -e "s/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\4.\3.\2.\1.in-addr.arpa/"`
+# prepare data for hostprocess()
+host_data=`echo $arpaip | sed -e "s/^[0-9]*\.\(.*\)/\1/"`
+
+firstsub=" I'm contacting you in your role as the administrator of the domain
+\"$arpaip\" as listed in its SOA record.
+
+ My network security software, which employs IPSec, requires the
+below keying information to be published as a RR in the DNS domain
+which you are responsible for.
+
+"
+
+txt=`txtprocess $reverseip $arpaip`
+secondsub=" To this end, I need you to publish the following TXT record:
+
+--DNS_RESOURCE_RECORDS--
+
+"$txt"
+
+--DNS_RESOURCE_RECORDS--"
+
+thirdsub="to enable full Opportunistic Encryption using the IP address:
+
+"$reverseip
+
+fourthsub="and TXT records are"
+
+proposed_email=`hostprocess $host_data`
+}
+elif [ "$forward" -eq 1 ]; then
+{
+# prepare data for hostprocess()
+# leave only the domain name
+domain_data=`echo $hostname | sed -e "s/.*\.\([a-zA-Z0-9-]*\.[a-zA-Z0-9-]*$\)/\1/"`
+# leave only the host name
+host_data=`echo $hostname | sed -e "s/\(.*\)\.[a-zA-Z0-9-]*\.[a-zA-Z0-9-]*$/\1/"`
+
+firstsub=" I'm contacting you in your role as the administrator of the domain
+\"$hostname\" as listed in its SOA record.
+
+ My network security software, which employs IPSec, requires the
+below keying information to be published as a RR in the DNS domain
+which you are responsible for.
+
+"
+
+txt=`txtprocess @$hostname $host_data`
+secondsub=" To this end, please publish the following TXT record for the hostname
+$hostname:
+
+
+--DNS_RESOURCE_RECORDS--
+
+$txt
+
+--DNS_RESOURCE_RECORDS--"
+thirdsub="to allow me to use the hostname:
+
+"$hostname"
+
+for initiator-only Opportunistic Encryption."
+fourthsub="record is"
+
+proposed_email=`hostprocess $domain_data`
+}
+fi
+
+# Create the template used for the body of the e-mail.
+
+mailbody=$firstsub$secondsub"
+
+
+ Please be careful to preserve the spaces and/or quotation marks as written.
+These are important for the RSA key to survive DNS processing.
+
+ Thanks for your help in securing the 'net!
+
+ $mymail
+ (Generated by '$me' for $mymail)
+
+
+
+Opportunistic Encryption (OE) is the result of ongoing effort by the FreeS/WAN
+project (www.freeswan.org). It allows for the creation of dynamic IPSec
+connections between hosts without pre-arrangement, authenticated via RSA keys
+stored in DNS records.
+
+Technical information on OE can be found in this RFC draft:
+
+http://www.freeswan.org/freeswan_snaps/CURRENT-SNAP/doc/draft-richardson-ipsec-opportunistic.txt
+
+If you have any questions about these TXT records, or about OE in general,
+please direct them to the FreeS/WAN support lists:
+
+users@lists.freeswan.org
+"
+
+# If we managed to find a hostmaster, make the appropriate modifications to the mail's body and
+# our instructions to the user.
+if [ "$proposed_email" ]; then
+{
+
+# This is now converting the mail test into an executable script.
+# Most users will have reached this stage; they can edit the contact_email
+# if they know better than us.
+# -s - Subject line. By extending it, we can "hack" the mail program to
+# include a customized Reply-To header.
+
+mailbody="#!/bin/sh
+#
+# Edit this variable to send this message to an alternate destination
+contact_email=$proposed_email
+
+mail \$contact_email -s 'DNS records for Opportunistic Encryption ($hostname$reverseip)
+Reply-To: $mymail' <<EOF
+
+"$mailbody"
+
+EOF
+"
+
+screenoutput="Executable mail file saved to: "$save_mail_file
+}
+else
+{
+# Slightly different instructions if we have nothing to tell the user.
+
+screenoutput="$me: error: Unable to locate SOA record for this domain. Not generating executable file.
+Sample mail file saved to: "$save_mail_file
+}
+fi
+
+# Create the output that has been prepared.
+echo "$mailbody" > $save_mail_file
+
+# Only make it executable if we've guessed a destination e-mail address.
+if [ "$proposed_email" ]; then
+{
+chmod u+x $save_mail_file
+}
+fi
+
+# Tell the user what'sgoing on.
+echo "$screenoutput"
diff --git a/programs/manual/.cvsignore b/programs/manual/.cvsignore
new file mode 100644
index 000000000..2905494b6
--- /dev/null
+++ b/programs/manual/.cvsignore
@@ -0,0 +1 @@
+manual
diff --git a/programs/manual/Makefile b/programs/manual/Makefile
new file mode 100644
index 000000000..68cfb9110
--- /dev/null
+++ b/programs/manual/Makefile
@@ -0,0 +1,38 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:28 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=manual
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:28 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 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.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/manual/manual.8 b/programs/manual/manual.8
new file mode 100644
index 000000000..a439544da
--- /dev/null
+++ b/programs/manual/manual.8
@@ -0,0 +1,267 @@
+.TH IPSEC_MANUAL 8 "17 July 2001"
+.\" RCSID $Id: manual.8,v 1.1 2004/03/15 20:35:28 as Exp $
+.SH NAME
+ipsec manual \- take manually-keyed IPsec connections up and down
+.SH SYNOPSIS
+.B ipsec
+.B manual
+[
+.B \-\-show
+] [
+.B \-\-showonly
+] [
+.B \-\-other
+]
+.br
+\ \ \ [
+.B \-\-iam
+.RB address "@" interface
+] [
+.B \-\-config
+configfile
+]
+.br
+\ \ \ operation connection
+.sp 0.5
+.B ipsec
+.B manual
+[
+.I options
+]
+.B \-\-union
+operation part ...
+.SH DESCRIPTION
+.I Manual
+manipulates manually-keyed FreeS/WAN IPsec connections,
+setting them up and shutting them down,
+based on the information in the IPsec configuration file.
+In the normal usage,
+.I connection
+is the name of a connection specification in the configuration file;
+.I operation
+is
+.BR \-\-up ,
+.BR \-\-down ,
+.BR \-\-route ,
+or
+.BR \-\-unroute .
+.I Manual
+generates setup (\c
+.BR \-\-route
+or
+.BR \-\-up )
+or
+teardown (\c
+.BR \-\-down
+or
+.BR \-\-unroute )
+commands for the connection and feeds them to a shell for execution.
+.PP
+The
+.B \-\-up
+operation brings the specified connection up, including establishing a
+suitable route for it if necessary.
+.PP
+The
+.B \-\-route
+operation just establishes the route for a connection.
+Unless and until an
+.B \-\-up
+operation is done, packets routed by that route will simply be discarded.
+.PP
+The
+.B \-\-down
+operation tears the specified connection down,
+.I except
+that it leaves the route in place.
+Unless and until an
+.B \-\-unroute
+operation is done, packets routed by that route will simply be discarded.
+This permits establishing another connection to the same destination
+without any ``window'' in which packets can pass without encryption.
+.PP
+The
+.B \-\-unroute
+operation (and only the
+.B \-\-unroute
+operation) deletes any route established for a connection.
+.PP
+In the
+.B \-\-union
+usage, each
+.I part
+is the name of a partial connection specification in the configuration file,
+and the union of all the partial specifications is the
+connection specification used.
+The effect is as if the contents of the partial specifications were
+concatenated together;
+restrictions on duplicate parameters, etc., do apply to the result.
+(The same effect can now be had, more gracefully, using the
+.B also
+parameter in connection descriptions;
+see
+.IR ipsec.conf (5)
+for details.)
+.PP
+The
+.B \-\-show
+option turns on the
+.B \-x
+option of the shell used to execute the commands,
+so each command is shown as it is executed.
+.PP
+The
+.B \-\-showonly
+option causes
+.I manual
+to show the commands it would run, on standard output,
+and not run them.
+.PP
+The
+.B \-\-other
+option causes
+.I manual
+to pretend it is the other end of the connection.
+This is probably not useful except in combination with
+.BR \-\-showonly .
+.PP
+The
+.B \-\-iam
+option causes
+.I manual
+to believe it is running on the host with the specified IP
+.IR address ,
+and that it should use the specified
+.I interface
+(normally it determines all this automatically,
+based on what IPsec interfaces are up and how they are configured).
+.PP
+The
+.B \-\-config
+option specifies a non-standard location for the FreeS/WAN IPsec
+configuration file (default
+.IR /etc/ipsec.conf ).
+.PP
+See
+.IR ipsec.conf (5)
+for details of the configuration file.
+Apart from the basic parameters which specify the endpoints and routing
+of a connection (\fBleft\fR
+and
+.BR right ,
+plus possibly
+.BR leftsubnet ,
+.BR leftnexthop ,
+.BR leftfirewall ,
+their
+.B right
+equivalents,
+and perhaps
+.BR type ),
+a non-\fBpassthrough\fR
+.I manual
+connection needs an
+.B spi
+or
+.B spibase
+parameter and some parameters specifying encryption, authentication, or
+both, most simply
+.BR esp ,
+.BR espenckey ,
+and
+.BR espauthkey .
+Moderately-secure keys can be obtained from
+.IR ipsec_ranbits (8).
+For production use of manually-keyed connections,
+it is strongly recommended that the keys be kept in a separate file
+(with permissions
+.BR rw\-\-\-\-\-\-\- )
+using the
+.B include
+and
+.B also
+facilities of the configuration file (see
+.IR ipsec.conf (5)).
+.PP
+If an
+.B spi
+parameter is given,
+.I manual
+uses that value as the SPI number for all the SAs
+(which are in separate number spaces anyway).
+If an
+.B spibase
+parameter is given instead,
+.I manual
+assigns SPI values by altering the bottom digit
+of that value;
+SAs going from left to right get even digits starting at 0,
+SAs going from right to left get odd digits starting at 1.
+Either way, it is suggested that manually-keyed connections use
+three-digit SPIs with the first digit non-zero,
+i.e. in the range
+.B 0x100
+through
+.BR 0xfff ;
+FreeS/WAN reserves those for manual keying and will not
+attempt to use them for automatic keying (unless requested to,
+presumably by a non-FreeS/WAN other end).
+.SH FILES
+.ta \w'/var/run/ipsec.nexthop'u+4n
+/etc/ipsec.conf default IPsec configuration file
+.br
+/var/run/ipsec.info \fB%defaultroute\fR information
+.SH SEE ALSO
+ipsec(8), ipsec.conf(5), ipsec_spi(8), ipsec_eroute(8), ipsec_spigrp(8),
+route(8)
+.SH HISTORY
+Written for the FreeS/WAN project
+<http://www.freeswan.org/>
+by Henry Spencer.
+.SH BUGS
+It's not nearly as generous about the syntax of subnets,
+addresses, etc. as the usual FreeS/WAN user interfaces.
+Four-component dotted-decimal must be used for all addresses.
+It
+.I is
+smart enough to translate bit-count netmasks to dotted-decimal form.
+.PP
+If the connection specification for a connection is changed between an
+.B \-\-up
+and the ensuing
+.BR \-\-down ,
+chaos may ensue.
+.PP
+The
+.B \-\-up
+operation is not smart enough to notice whether the connection is already up.
+.PP
+.I Manual
+is not smart enough to reject insecure combinations of algorithms,
+e.g. encryption with no authentication at all.
+.PP
+Any non-IPsec route to the other end which is replaced by the
+.B \-\-up
+or
+.B \-\-route
+operation will not be re-established by
+.BR \-\-unroute .
+Whether this is a feature or a bug depends on your viewpoint.
+.PP
+The optional parameters which
+override the automatic
+.BR spibase -based
+SPI assignment are a messy area of the code and bugs are likely.
+.PP
+``Road warrior'' handling,
+and other special forms of setup which
+require negotiation between the two security gateways,
+inherently cannot be done with
+.IR manual .
+.PP
+.I Manual
+generally lags behind
+.I auto
+in support of various features,
+even when implementation \fIwould\fR be possible.
+For example, currently it does not do IPComp content compression.
diff --git a/programs/manual/manual.in b/programs/manual/manual.in
new file mode 100755
index 000000000..bda4bafa0
--- /dev/null
+++ b/programs/manual/manual.in
@@ -0,0 +1,637 @@
+#! /bin/sh
+# user interface to manual keying
+# Copyright (C) 1998, 1999 Henry Spencer.
+#
+# 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: manual.in,v 1.1 2004/03/15 20:35:28 as Exp $
+
+me='ipsec manual'
+usage="Usage:
+ $me [--showonly] --{up|down|route|unroute} name
+ $me [--showonly] --{up|down|route|unroute} --union partname ...
+
+ other options: [--config ipsecconfigfile] [--other] [--show]
+ [--iam ipaddress@interface]"
+
+# make sure outputs of (e.g.) ifconfig are in English
+unset LANG LANGUAGE LC_ALL LC_MESSAGES
+
+showonly=
+config=
+info=/var/run/ipsec.info
+shopts=
+other=0
+union=0
+noinclude=
+interfs=
+op=
+
+for dummy
+do
+ case "$1" in
+ --help) echo "$usage" ; exit 0 ;;
+ --version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+ --show) shopts=-x ;;
+ --showonly) showonly=yes ;;
+ --other) other=1 ;;
+ --union) union=1 ;;
+ --config) config="--config $2" ; shift ;;
+ --noinclude) noinclude=--noinclude ;;
+ --iam) interfs="$2" ; shift ;;
+ --up|--down|--route|--unroute)
+ if test " $op" != " "
+ then
+ echo "$usage" >&2
+ exit 2
+ fi
+ op="$1"
+ ;;
+ --) shift ; break ;;
+ -*) echo "$me: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+case "$op$#:$union" in
+[01]:*) echo "$usage" >&2 ; exit 2 ;;
+2:0) echo "$me: warning: obsolete command syntax used" >&2
+ op="--$2"
+ names="$1"
+ ;;
+[0-9]*:1) ;;
+--*) if test $# -eq 0
+ then
+ echo "$usage" >&2
+ exit 2
+ fi
+ names="$*"
+ ;;
+*) echo "$usage" >&2 ; exit 2 ;;
+esac
+if test " $op" = " "
+then
+ # --union obsolete-syntax case, op is last argument
+ echo "$me: warning: obsolete command syntax used" >&2
+ names=
+ prev=
+ for arg
+ do
+ names="$names $prev"
+ prev="$arg"
+ done
+ op="--$prev"
+fi
+case "$op" in
+--up|--down|--route|--unroute) ;;
+*) echo "$usage" >&2 ; exit 2 ;;
+esac
+
+case "$interfs" in
+'') interfs="`ifconfig |
+ awk ' /^ipsec/ { interf = $1 ; next }
+ /^[^ \t]/ { interf = "" ; next }
+ /^[ \t]*inet addr/ {
+ sub(/:/, " ", $0)
+ if (interf != "")
+ print $3 "@" interf
+ }' | tr '\n' ' '`"
+ ;;
+esac
+
+if test -s $info
+then
+ . $info
+fi
+
+ipsec _confread $config $noinclude $names |
+awk ' BEGIN {
+ FS = "\t"
+ myname = "'"$me"'"
+ err = "cat >&2"
+ op = "'"$op"'"
+ other = '"$other"'
+ names = "'"$names"'"
+ interfs = "'"$interfs"'"
+ ni = split(interfs, terfs, " ")
+ if (ni == 0)
+ fail("no IPsec-enabled interfaces found")
+ for (i = 1; i <= ni; i++) {
+ nc = split(terfs[i], cpts, "@")
+ if (nc != 2)
+ fail("internal error on " terfs[i])
+ interface[cpts[1]] = cpts[2]
+ }
+ draddr = "'"$defaultrouteaddr"'"
+ drnexthop = "'"$defaultroutenexthop"'"
+ s[""] = ""
+ nlspi = 0
+ nrspi = 0
+ failed = 0
+ maskbits[0] = "0.0.0.0"
+ maskbits[1] = "128.0.0.0"
+ maskbits[2] = "192.0.0.0"
+ maskbits[3] = "224.0.0.0"
+ maskbits[4] = "240.0.0.0"
+ maskbits[5] = "248.0.0.0"
+ maskbits[6] = "252.0.0.0"
+ maskbits[7] = "254.0.0.0"
+ maskbits[8] = "255.0.0.0"
+ maskbits[9] = "255.128.0.0"
+ maskbits[10] = "255.192.0.0"
+ maskbits[11] = "255.224.0.0"
+ maskbits[12] = "255.240.0.0"
+ maskbits[13] = "255.248.0.0"
+ maskbits[14] = "255.252.0.0"
+ maskbits[15] = "255.254.0.0"
+ maskbits[16] = "255.255.0.0"
+ maskbits[17] = "255.255.128.0"
+ maskbits[18] = "255.255.192.0"
+ maskbits[19] = "255.255.224.0"
+ maskbits[20] = "255.255.240.0"
+ maskbits[21] = "255.255.248.0"
+ maskbits[22] = "255.255.252.0"
+ maskbits[23] = "255.255.254.0"
+ maskbits[24] = "255.255.255.0"
+ maskbits[25] = "255.255.255.128"
+ maskbits[26] = "255.255.255.192"
+ maskbits[27] = "255.255.255.224"
+ maskbits[28] = "255.255.255.240"
+ maskbits[29] = "255.255.255.248"
+ maskbits[30] = "255.255.255.252"
+ maskbits[31] = "255.255.255.254"
+ maskbits[32] = "255.255.255.255"
+ }
+ $1 == "=" {
+ next
+ }
+ $1 == "!" {
+ if ($2 != "")
+ fail($2)
+ next
+ }
+ $1 != ":" {
+ fail("internal error, unknown type code \"" $1 "\"")
+ }
+ { s[$2] = $3 }
+ function q(s) {
+ return "\"" s "\""
+ }
+ function fail(m) {
+ print myname ": fatal error in " q(names) ": " m |err
+ failed = 1
+ exit
+ }
+ function swap(k, t, l, r) {
+ l = "left" k
+ r = "right" k
+ if ((l in s) && (r in s)) {
+ t = s[l]
+ s[l] = s[r]
+ s[r] = t
+ } else if (l in s) { # but not r
+ s[r] = s[l]
+ delete s[l]
+ } else if (r in s) { # but not l
+ s[l] = s[r]
+ delete s[r]
+ }
+ }
+ function yesno(k) {
+ if ((k in s) && s[k] != "yes" && s[k] != "no")
+ fail("parameter \"" k "\" must be \"yes\" or \"no\"")
+ }
+ function default(k, v) {
+ if (!(k in s))
+ s[k] = v
+ }
+ function need(k) {
+ if (!(k in s))
+ fail("connection has no \"" k "\" parameter specified")
+ if (s[k] == "")
+ fail("parameter \"" k "\" value must be non-empty")
+ }
+ function integer(k) {
+ if (!(k in s))
+ return
+ if (s[k] !~ /^[0-9]+$/)
+ fail("parameter \"" k "\" value must be integer")
+ }
+ function nexthopset(dir, val, k) {
+ k = dir "nexthop"
+ if (k in s)
+ fail("non-default value of " k " is being overridden")
+ if (val != "")
+ s[k] = val
+ else if (k in s)
+ delete s[k]
+ }
+ function leftward( t) {
+ nlspi++
+ if ("spi" in s)
+ return s["spi"]
+ t = spibase spil
+ spil += 2
+ return t
+ }
+ function rightward( t) {
+ nrspi++
+ if ("spi" in s)
+ return s["spi"]
+ t = spibase spir
+ spir += 2
+ return t
+ }
+ function netfix(dir, n, t) {
+ n = s[dir "subnet"]
+ if (n == "%default")
+ n = "0.0.0.0/0"
+ if (n !~ /\//)
+ fail(dir "subnet=" n " has no mask specified")
+ t = split(n, netfixarray, "/")
+ if (t != 2)
+ fail("bad syntax in " dir "subnet=" n)
+ s[dir "net"] = netfixarray[1]
+ s[dir "mask"] = mask(netfixarray[2])
+ }
+ function mask(m) {
+ if (m ~ /\./)
+ return m
+ if (!(m in maskbits))
+ fail("unknown mask syntax \"" m "\"")
+ return maskbits[m]
+ }
+ function bidir(name, l, r) {
+ l = "left" name
+ r = "right" name
+ if (!(l in s) && (name in s))
+ s[l] = s[name]
+ if (!(r in s) && (name in s))
+ s[r] = s[name]
+ if ((l in s) != (r in s))
+ fail("must give both or neither \"" l "\" and \"" \
+ r "\"")
+ }
+ function espspi(src, dest, spi, dir) {
+ if (!("esp" in s))
+ return
+ dir = (dest == me) ? "left" : "right"
+ print "ipsec spi --label", q(names), "--af inet",
+ "--said", ("esp" spi "@" dest), "\\"
+ print "\t--esp", s["esp"], "--src", src, "\\"
+ if ((dir "espauthkey") in s)
+ print "\t--authkey", s[dir "espauthkey"], "\\"
+ if ("espreplay_window" in s)
+ print "\t--replay_window", s["espreplay_window"], "\\"
+ if ((dir "espenckey") in s)
+ print "\t--enckey", s[dir "espenckey"], "&&"
+ else
+ print "\t&&"
+ }
+ function ahspi(src, dest, spi, dir) {
+ if (!("ah" in s))
+ return
+ dir = (dest == me) ? "left" : "right"
+ if (!((dir "ahkey") in s))
+ fail("AH specified but no ahkey= given")
+ print "ipsec spi --label", q(names), "--af inet",
+ "--said", ("ah" spi "@" dest), "\\"
+ print "\t--ah", s["ah"], "--src", src, "\\"
+ if ("ahreplay_window" in s)
+ print "\t--replay_window", s["ahreplay_window"], "\\"
+ print "\t--authkey", s[dir "ahkey"], "&&"
+ }
+ # issue a suitable invocation of updown command
+ function updown(verb, suffix, cmd) {
+ if ("leftupdown" in s) {
+ cmd = s["leftupdown"]
+ if (s["leftfirewall"] == "yes")
+ fail("cannot specify both updown and firewall")
+ } else {
+ cmd = "ipsec _updown"
+ if (s["leftfirewall"] == "yes")
+ cmd = cmd " ipfwadm"
+ }
+ print "PLUTO_VERB=" verb verbsuf " " cmd " " suffix
+ }
+ END {
+ #########
+ if (failed)
+ exit 1
+ default("type", "tunnel")
+ type = s["type"]
+ shunt = 0
+ if (type == "transport") {
+ if ("leftsubnet" in s)
+ fail("type=transport incompatible with leftsubnet")
+ if ("rightsubnet" in s)
+ fail("type=transport incompatible with rightsubnet")
+ } else if (type == "passthrough") {
+ shunt = 1;
+ p = "%pass"
+ } else if (type == "drop" || type == "reject") {
+ shunt = 1;
+ p = "%" type
+ } else if (type != "tunnel")
+ fail("only know how to do types tunnel/transport/passthrough")
+ if (shunt) {
+ if (("ah" in s) || ("esp" in s))
+ fail(type " connection may not specify AH or ESP")
+ } else {
+ if (!("ah" in s) && !("esp" in s))
+ fail("neither AH nor ESP specified for connection")
+ }
+
+ need("left")
+ need("right")
+ if (s["left"] == "%defaultroute") {
+ if (s["right"] == "%defaultroute")
+ fail("left and right cannot both be %defaultroute")
+ if (draddr == "")
+ fail("%defaultroute requested but not known")
+ s["left"] = draddr
+ nexthopset("left", drnexthop)
+ } else if (s["right"] == "%defaultroute") {
+ if (draddr == "")
+ fail("%defaultroute requested but not known")
+ s["right"] = draddr
+ nexthopset("right", drnexthop)
+ }
+
+ leftsub = ("leftsubnet" in s) ? 1 : 0
+ default("leftsubnet", s["left"] "/32")
+ rightsub = ("rightsubnet" in s) ? 1 : 0
+ default("rightsubnet", s["right"] "/32")
+ default("leftfirewall", "no")
+ default("rightfirewall", "no")
+ yesno("leftfirewall")
+ yesno("rightfirewall")
+ integer("espreplay_window")
+ if (("espreplay_window" in s) && s["espreplay_window"] == 0)
+ delete s["espreplay_window"]
+ integer("ahreplay_window")
+ if (("ahreplay_window" in s) && s["ahreplay_window"] == 0)
+ delete s["ahreplay_window"]
+ netfix("left")
+ netfix("right")
+
+ default("leftnexthop", s["right"])
+ default("rightnexthop", s["left"])
+ if (s["leftnexthop"] == s["left"])
+ fail("left and leftnexthop must not be the same")
+ if (s["rightnexthop"] == s["right"])
+ fail("right and rightnexthop must not be the same")
+
+ bidir("espenckey")
+ bidir("espauthkey")
+ bidir("ahkey")
+ if ("spi" in s && "spibase" in s)
+ fail("cannot specify both spi and spibase")
+ if (!shunt) {
+ if ("spibase" in s) {
+ b = s["spibase"]
+ if (b !~ /^0x[0-9a-fA-F]+0$/)
+ fail("bad syntax in spibase -- must be 0x...0")
+ spibase = substr(b, 1, length(b)-1)
+ } else {
+ need("spi")
+ if (s["spi"] !~ /^0x[0-9a-fA-F]+$/)
+ fail("bad syntax in spi -- must be 0x...")
+ }
+ }
+ spir = 0
+ spil = 1
+
+ # who am I?
+ me = ""
+ for (addr in interface) {
+ if (addr == s["left"] || addr == s["right"]) {
+ if (me != "")
+ fail("ambiguous: could be on \"" iface \
+ "\" or \"" interface[addr] "\"")
+ me = addr
+ iface = interface[addr]
+ }
+ }
+ if (me == "")
+ fail("cannot find interface for " s["left"] " or " s["right"])
+ if (other) {
+ if (s["left"] == me)
+ me = s["right"]
+ else if (s["right"] == me)
+ me = s["left"]
+ }
+ havesubnet = leftsubnet
+ if (s["right"] == me) {
+ swap("") # swaps "left" and "right"
+ swap("subnet")
+ swap("nexthop")
+ swap("net")
+ swap("mask")
+ swap("firewall")
+ swap("espspi")
+ swap("ahspi")
+ swap("espenckey")
+ swap("espauthkey")
+ swap("ahkey")
+ swap("updown")
+ t = spil
+ spil = spir
+ spir = t
+ havesubnet = rightsubnet
+ }
+ him = s["right"]
+
+ if (s["leftnexthop"] == "%defaultroute") {
+ if (drnexthop == "")
+ fail("%defaultroute requested but not known")
+ s["leftnexthop"] = drnexthop
+ }
+
+ tspi = rightward()
+ if (type == "tunnel") {
+ espi = rightward()
+ intspi = leftward()
+ } else
+ espi = tspi
+ if (s["rightespspi"] != "")
+ espi = s["rightespspi"]
+ respi = leftward()
+ if (s["leftespspi"] != "")
+ respi = s["leftespspi"]
+ if ("ah" in s) {
+ if ("esp" in s) {
+ aspi = rightward()
+ raspi = leftward()
+ } else {
+ aspi = espi
+ raspi = respi
+ }
+ if (s["rightahspi"] != "")
+ aspi = s["rightahspi"]
+ if (s["leftahspi"] != "")
+ raspi = s["leftahspi"]
+ }
+ routeid = "-net " s["rightnet"] " netmask " s["rightmask"]
+ if (s["rightmask"] == "255.255.255.255")
+ routeid = "-host " s["rightnet"]
+
+ print "PATH=\"'"$PATH"'\""
+ print "export PATH"
+ print "PLUTO_VERSION=1.1"
+ verbsuf = (havesubnet) ? "-client" : "-host"
+ print "PLUTO_CONNECTION=" q(names)
+ print "PLUTO_NEXT_HOP=" s["leftnexthop"]
+ print "PLUTO_INTERFACE=" iface
+ print "PLUTO_ME=" me
+ print "PLUTO_MY_CLIENT=" s["leftsubnet"]
+ print "PLUTO_MY_CLIENT_NET=" s["leftnet"]
+ print "PLUTO_MY_CLIENT_MASK=" s["leftmask"]
+ print "PLUTO_PEER=" him
+ print "PLUTO_PEER_CLIENT=" s["rightsubnet"]
+ print "PLUTO_PEER_CLIENT_NET=" s["rightnet"]
+ print "PLUTO_PEER_CLIENT_MASK=" s["rightmask"]
+ print "export PLUTO_VERSION PLUTO_CONNECTION PLUTO_NEXT_HOP"
+ print "export PLUTO_INTERFACE PLUTO_ME PLUTO_MY_CLIENT"
+ print "export PLUTO_MY_CLIENT_NET PLUTO_MY_CLIENT_MASK PLUTO_PEER"
+ print "export PLUTO_PEER_CLIENT PLUTO_PEER_CLIENT_NET"
+ print "export PLUTO_PEER_CLIENT_MASK"
+
+ if (op == "--up") {
+ print "{"
+ # first, the outbound SAs
+ if (type == "tunnel") {
+ print "ipsec spi --label", q(names), "--af inet",
+ "--said", ("tun" tspi "@" him), "\\"
+ print "\t--ip4", "--src", me, "--dst", him, "&&"
+ }
+ espspi(me, him, espi)
+ ahspi(me, him, aspi)
+ if (nrspi > 1) {
+ # group them
+ printf "ipsec spigrp --label %s --said ", q(names)
+ if (type == "tunnel")
+ printf "tun%s@%s ", tspi, him
+ if (("esp" in s))
+ printf "esp%s@%s ", espi, him
+ if ("ah" in s)
+ printf "ah%s@%s ", aspi, him
+ printf " &&\n"
+ }
+ # inbound SAs
+ if (type == "tunnel") {
+ print "ipsec spi --label", q(names), "--af inet",
+ "--said", ("tun" intspi "@" me), "\\"
+ print "\t--ip4", "--src", him, "--dst", me, "&&"
+ }
+ espspi(him, me, respi)
+ ahspi(him, me, raspi)
+ if (nlspi > 1) {
+ # group them
+ printf "ipsec spigrp --label %s --said ", q(names)
+ if (type == "tunnel")
+ printf "tun%s@%s ", intspi, me
+ if (("esp" in s))
+ printf "esp%s@%s ", respi, me
+ if ("ah" in s)
+ printf "ah%s@%s ", raspi, me
+ printf " &&\n"
+ }
+ # with the SAs in place, eroute to them
+ print "ipsec eroute --label", q(names),
+ "--eraf inet --replace", "\\"
+ if (!shunt) {
+ if (type == "tunnel")
+ p = "tun"
+ else if (("esp" in s))
+ p = "esp"
+ else
+ p = "ah"
+ p = p tspi "@" him
+ }
+ print "\t--src", s["leftsubnet"], "--dst", s["rightsubnet"],
+ "--said", p, "&&"
+ # with the eroute in place, NOW we can route to it
+ #print "{ route del", routeid, "2>/dev/null ; true ; } &&"
+ updown("prepare", "&&")
+ #print "route add", routeid, "dev", iface, "gw",
+ # s["leftnexthop"], "&&"
+ updown("route", "&&")
+ # and with all processing in place, we can penetrate firewall
+ #if (s["leftfirewall"] == "yes") {
+ # print "ipfwadm -F -i accept -b -S", s["leftsubnet"],
+ # "-D", s["rightsubnet"], "&&"
+ #}
+ updown("up", "&&")
+ print "true"
+ print "} || {"
+ } else if (op == "--route") {
+ #print "{ route del", routeid, "2>/dev/null ; true ; } &&"
+ updown("prepare", "&&")
+ #print "route add", routeid, "dev", iface, "gw",
+ # s["leftnexthop"]
+ updown("route")
+ exit 0
+ } else if (op == "--unroute") {
+ #print "route del", routeid, "dev", iface, "gw",
+ # s["leftnexthop"]
+ updown("unroute")
+ exit 0
+ } else # down
+ print "{"
+
+ # now do "down", unconditionally, since the desired output for "up"
+ # is { up && up && up && true } || { down ; down ; down }
+ # tear things down in fairly strict reverse order
+ #if (s["leftfirewall"] == "yes")
+ # print "ipfwadm -F -d accept -b -S", s["leftsubnet"],
+ # "-D", s["rightsubnet"]
+ updown("down")
+ #print "route del", routeid, "dev", iface, "gw", s["leftnexthop"]
+ print "# do not delete route"
+ print "ipsec eroute --label", q(names), "--eraf inet --del", "\\"
+ print "\t--src", s["leftsubnet"], "--dst", s["rightsubnet"]
+ #if ("ah" in s) {
+ # print "ipsec spi --label", q(names), "--af inet", "--del",
+ # "--said", ("ah" raspi "@" me)
+ #}
+ #if ("esp" in s) {
+ # print "ipsec spi --label", q(names), "--af inet", "--del",
+ # "--said", ("esp" respi "@" me)
+ #}
+ if (!shunt) {
+ if (type == "tunnel")
+ p = "tun"
+ else if (("esp" in s))
+ p = "esp"
+ else
+ p = "ah"
+ print "ipsec spi --label", q(names), "--af inet", "--del",
+ "--said", (p tspi "@" him),
+ " # outbound"
+ print "ipsec spi --label", q(names), "--af inet", "--del",
+ "--said", (p intspi "@" me),
+ " # inbound"
+ }
+
+ if (op == "--up")
+ print "} 2>/dev/null"
+ else
+ print "}"
+ #########
+ }' |
+if test $showonly
+then
+ cat
+else
+ sh $shopts
+fi
diff --git a/programs/openac/Makefile b/programs/openac/Makefile
new file mode 100644
index 000000000..7aeacee0a
--- /dev/null
+++ b/programs/openac/Makefile
@@ -0,0 +1,154 @@
+# Makefile for the openac attribute certificate generation tool
+# Copyright (C) 2004 Andreas Steffen
+# Zuercher Hochschule Winterthur
+#
+# 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.16 2006/02/17 19:33:27 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+CONFDIR=$(DESTDIR)/etc/openac
+PLUTODIR=../pluto
+
+PROGRAM=openac
+EXTRA8PROC=${PROGRAM}.8
+
+LIBS=${FREESWANLIB} $(LIBDESLITE) -lgmp
+CFLAGS+= -DDEBUG -DNO_PLUTO
+
+# This compile option activates the leak detective
+ifeq ($(USE_LEAK_DETECTIVE),true)
+ CFLAGS+= -DLEAK_DETECTIVE
+endif
+
+X509_OBJS= ac.o asn1.o ca.o certs.o constants.o crl.o defs.o mp_defs.o fetch.o \
+ id.o keys.o lex.o md2.o md5.o ocsp.o oid.o pem.o pgp.o pkcs1.o \
+ rnd.o sha1.o smartcard.o x509.o
+
+OBJS= build.o loglite.o ${X509_OBJS}
+
+include ../Makefile.program
+
+build.o : build.c build.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+loglite.o : loglite.c $(PLUTODIR)/log.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+# X.509 library
+
+ac.o : $(PLUTODIR)/ac.c $(PLUTODIR)/ac.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+asn1.o : $(PLUTODIR)/asn1.c $(PLUTODIR)/asn1.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+certs.o : $(PLUTODIR)/certs.c $(PLUTODIR)/certs.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+mp_defs.o : $(PLUTODIR)/mp_defs.c $(PLUTODIR)/mp_defs.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+fetch.o : $(PLUTODIR)/fetch.c $(PLUTODIR)/fetch.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+id.o : $(PLUTODIR)/id.c $(PLUTODIR)/id.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+keys.o : $(PLUTODIR)/keys.c $(PLUTODIR)/keys.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+md2.o : $(PLUTODIR)/md2.c $(PLUTODIR)/md2.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+md5.o : $(PLUTODIR)/md5.c $(PLUTODIR)/md5.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+oid.o : $(PLUTODIR)/oid.c $(PLUTODIR)/oid.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+rnd.o : $(PLUTODIR)/rnd.c $(PLUTODIR)/rnd.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+sha1.o : $(PLUTODIR)/sha1.c $(PLUTODIR)/sha1.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+smartcard.o : $(PLUTODIR)/smartcard.c $(PLUTODIR)/smartcard.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+x509.o : $(PLUTODIR)/x509.c $(PLUTODIR)/x509.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+# Stolen from pluto/Makefile
+
+gatherdeps:
+ @ls | grep '\.c$$' | sed -e 's/\(.*\)\.c$$/\1.o: \1.c/'
+ @echo
+ @ls | grep '\.c$$' | xargs grep '^#[ ]*include[ ]*"' | \
+ sed -e 's/\.c:#[ ]*include[ ]*"/.o: /' -e 's/".*//'
+
+# Dependencies generated by "make gatherdeps":
+
+build.o: build.c
+loglite.o: loglite.c
+openac.o: openac.c
+
+build.o: ../pluto/constants.h
+build.o: ../pluto/defs.h
+build.o: ../pluto/oid.h
+build.o: ../pluto/asn1.h
+build.o: ../pluto/x509.h
+build.o: ../pluto/log.h
+build.o: build.h
+loglite.o: ../pluto/constants.h
+loglite.o: ../pluto/defs.h
+loglite.o: ../pluto/log.h
+loglite.o: ../pluto/whack.h
+openac.o: ../pluto/constants.h
+openac.o: ../pluto/defs.h
+openac.o: ../pluto/mp_defs.h
+openac.o: ../pluto/log.h
+openac.o: ../pluto/asn1.h
+openac.o: ../pluto/certs.h
+openac.o: ../pluto/x509.h
+openac.o: ../pluto/crl.h
+openac.o: ../pluto/keys.h
+openac.o: ../pluto/ac.h
+openac.o: build.h
diff --git a/programs/openac/build.c b/programs/openac/build.c
new file mode 100644
index 000000000..bd3df6fee
--- /dev/null
+++ b/programs/openac/build.c
@@ -0,0 +1,242 @@
+/* Build a X.509 attribute certificate
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2004 Andreas Steffen
+ * Zuercher Hochschule Winterthur, Switzerland
+ *
+ * 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: build.c,v 1.14 2005/09/06 11:47:57 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/oid.h"
+#include "../pluto/asn1.h"
+#include "../pluto/x509.h"
+#include "../pluto/log.h"
+
+#include "build.h"
+
+static u_char ASN1_group_oid_str[] = {
+ 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a ,0x04
+};
+
+static const chunk_t ASN1_group_oid = strchunk(ASN1_group_oid_str);
+
+static u_char ASN1_authorityKeyIdentifier_oid_str[] = {
+ 0x06, 0x03,
+ 0x55, 0x1d, 0x23
+};
+
+static const chunk_t ASN1_authorityKeyIdentifier_oid
+ = strchunk(ASN1_authorityKeyIdentifier_oid_str);
+
+static u_char ASN1_noRevAvail_ext_str[] = {
+ 0x30, 0x09,
+ 0x06, 0x03,
+ 0x55, 0x1d, 0x38,
+ 0x04, 0x02,
+ 0x05, 0x00
+};
+
+static const chunk_t ASN1_noRevAvail_ext = strchunk(ASN1_noRevAvail_ext_str);
+
+/*
+ * build directoryName
+ */
+static chunk_t
+build_directoryName(asn1_t tag, chunk_t name)
+{
+ return asn1_wrap(tag, "m"
+ , asn1_simple_object(ASN1_CONTEXT_C_4, name));
+}
+
+/*
+ * build holder
+ */
+static chunk_t
+build_holder(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "mm"
+ , asn1_wrap(ASN1_CONTEXT_C_0, "mm"
+ , build_directoryName(ASN1_SEQUENCE, user->issuer)
+ , asn1_simple_object(ASN1_INTEGER, user->serialNumber)
+ )
+ , build_directoryName(ASN1_CONTEXT_C_1, user->subject));
+}
+
+/*
+ * build v2Form
+ */
+static chunk_t
+build_v2_form(void)
+{
+ return asn1_wrap(ASN1_CONTEXT_C_0, "m"
+ , build_directoryName(ASN1_SEQUENCE, signer->subject));
+}
+
+/*
+ * build attrCertValidityPeriod
+ */
+static chunk_t
+build_attr_cert_validity(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "mm"
+ , timetoasn1(&notBefore, ASN1_GENERALIZEDTIME)
+ , timetoasn1(&notAfter, ASN1_GENERALIZEDTIME));
+}
+
+/*
+ * build attributes
+ */
+static chunk_t
+build_ietfAttributes(ietfAttrList_t *list)
+{
+ chunk_t ietfAttributes;
+ ietfAttrList_t *item = list;
+ size_t size = 0;
+ u_char *pos;
+
+ /* precalculate the total size of all values */
+ while (item != NULL)
+ {
+ size_t len = item->attr->value.len;
+
+ size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
+ item = item->next;
+ }
+ pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size);
+
+ while (list != NULL)
+ {
+ ietfAttr_t *attr = list->attr;
+ asn1_t type = ASN1_NULL;
+
+ switch (attr->kind)
+ {
+ case IETF_ATTRIBUTE_OCTETS:
+ type = ASN1_OCTET_STRING;
+ break;
+ case IETF_ATTRIBUTE_STRING:
+ type = ASN1_UTF8STRING;
+ break;
+ case IETF_ATTRIBUTE_OID:
+ type = ASN1_OID;
+ break;
+ }
+ mv_chunk(&pos, asn1_simple_object(type, attr->value));
+
+ list = list->next;
+ }
+
+ return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes);
+}
+
+/*
+ * build attribute type
+ */
+static chunk_t
+build_attribute_type(const chunk_t type, chunk_t content)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , type
+ , asn1_wrap(ASN1_SET, "m", content));
+}
+
+/*
+ * build attributes
+ */
+static chunk_t
+build_attributes(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "m"
+ , build_attribute_type(ASN1_group_oid
+ , build_ietfAttributes(groups)));
+}
+
+/*
+ * build authorityKeyIdentifier
+ */
+static chunk_t
+build_authorityKeyID(x509cert_t *signer)
+{
+ chunk_t keyIdentifier = (signer->subjectKeyID.ptr == NULL)
+ ? empty_chunk
+ : asn1_simple_object(ASN1_CONTEXT_S_0
+ , signer->subjectKeyID);
+
+ chunk_t authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1
+ , signer->issuer);
+
+ chunk_t authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2
+ , signer->serialNumber);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_authorityKeyIdentifier_oid
+ , asn1_wrap(ASN1_OCTET_STRING, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "mmm"
+ , keyIdentifier
+ , authorityCertIssuer
+ , authorityCertSerialNumber
+ )
+ )
+ );
+}
+
+/*
+ * build extensions
+ */
+static chunk_t
+build_extensions(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "mc"
+ , build_authorityKeyID(signer)
+ , ASN1_noRevAvail_ext);
+}
+
+/*
+ * build attributeCertificateInfo
+ */
+static chunk_t
+build_attr_cert_info(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm"
+ , ASN1_INTEGER_1
+ , build_holder()
+ , build_v2_form()
+ , ASN1_sha1WithRSA_id
+ , asn1_simple_object(ASN1_INTEGER, serial)
+ , build_attr_cert_validity()
+ , build_attributes()
+ , build_extensions());
+}
+
+/*
+ * build an X.509 attribute certificate
+ */
+chunk_t
+build_attr_cert(void)
+{
+ chunk_t attributeCertificateInfo = build_attr_cert_info();
+ chunk_t signatureValue = pkcs1_build_signature(attributeCertificateInfo
+ , OID_SHA1, signerkey, TRUE);
+
+ return asn1_wrap(ASN1_SEQUENCE, "mcm"
+ , attributeCertificateInfo
+ , ASN1_sha1WithRSA_id
+ , signatureValue);
+}
diff --git a/programs/openac/build.h b/programs/openac/build.h
new file mode 100644
index 000000000..deeddda04
--- /dev/null
+++ b/programs/openac/build.h
@@ -0,0 +1,47 @@
+/* Build a X.509 attribute certificate
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2004 Andreas Steffen
+ * Zuercher Hochschule Winterthur, Switzerland
+ *
+ * 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: build.h,v 1.4 2004/11/03 14:28:52 as Exp $
+ */
+
+#ifndef _BUILD_H
+#define _BUILD_H
+
+#include <time.h>
+
+#include "../pluto/x509.h"
+#include "../pluto/keys.h"
+#include "../pluto/ac.h"
+
+/*
+ * global variables accessible by both main() and build.c
+ */
+extern x509cert_t *user;
+extern x509cert_t *signer;
+
+extern ietfAttrList_t *groups;
+extern struct RSA_private_key *signerkey;
+
+extern time_t notBefore;
+extern time_t notAfter;
+
+extern chunk_t serial;
+
+/*
+ * exported functions
+ */
+extern chunk_t build_attr_cert(void);
+
+#endif /* _BUILD_H */
diff --git a/programs/openac/loglite.c b/programs/openac/loglite.c
new file mode 100644
index 000000000..b1763cc9f
--- /dev/null
+++ b/programs/openac/loglite.c
@@ -0,0 +1,295 @@
+/* error logging functions
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: loglite.c,v 1.2 2005/07/11 18:38:16 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+#include "../pluto/whack.h"
+
+bool
+ log_to_stderr = FALSE, /* should log go to stderr? */
+ log_to_syslog = TRUE; /* should log go to syslog? */
+
+void
+init_log(const char *program)
+{
+ if (log_to_stderr)
+ setbuf(stderr, NULL);
+ if (log_to_syslog)
+ openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
+}
+
+void
+close_log(void)
+{
+ if (log_to_syslog)
+ closelog();
+}
+
+void
+plog(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m);
+}
+
+void
+loglog(int mess_no, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m);
+}
+
+void
+log_errno_routine(int e, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
+ if (log_to_syslog)
+ syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e));
+}
+
+void
+exit_log(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "FATAL ERROR: %s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_ERR, "FATAL ERROR: %s", m);
+ exit(1);
+}
+
+void
+exit_log_errno_routine(int e, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
+ if (log_to_syslog)
+ syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
+ exit(1);
+}
+
+void
+whack_log(int mess_no, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ fprintf(stderr, "%s\n", m);
+}
+
+/* Build up a diagnostic in a static buffer.
+ * Although this would be a generally useful function, it is very
+ * hard to come up with a discipline that prevents different uses
+ * from interfering. It is intended that by limiting it to building
+ * diagnostics, we will avoid this problem.
+ * Juggling is performed to allow an argument to be a previous
+ * result: the new string may safely depend on the old one. This
+ * restriction is not checked in any way: violators will produce
+ * confusing results (without crashing!).
+ */
+char diag_space[sizeof(diag_space)];
+
+err_t
+builddiag(const char *fmt, ...)
+{
+ static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */
+ char t[sizeof(diag_space)]; /* build result here first */
+ va_list args;
+
+ va_start(args, fmt);
+ t[0] = '\0'; /* in case nothing terminates string */
+ vsnprintf(t, sizeof(t), fmt, args);
+ va_end(args);
+ strcpy(diag_space, t);
+ return diag_space;
+}
+
+/* Debugging message support */
+
+#ifdef DEBUG
+
+void
+switch_fail(int n, const char *file_str, unsigned long line_no)
+{
+ char buf[30];
+
+ snprintf(buf, sizeof(buf), "case %d unexpected", n);
+ passert_fail(buf, file_str, line_no);
+}
+
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ /* we will get a possibly unplanned prefix. Hope it works */
+ loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+ abort(); /* exiting correctly doesn't always work */
+}
+
+lset_t
+ base_debugging = DBG_NONE, /* default to reporting nothing */
+ cur_debugging = DBG_NONE;
+
+void
+pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ /* we will get a possibly unplanned prefix. Hope it works */
+ loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+}
+
+/* log a debugging message (prefixed by "| ") */
+
+void
+DBG_log(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "| %s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_DEBUG, "| %s", m);
+}
+
+/* dump raw bytes in hex to stderr (for lack of any better destination) */
+
+void
+DBG_dump(const char *label, const void *p, size_t len)
+{
+# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */
+# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1)
+ char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH];
+ char *bp;
+ const unsigned char *cp = p;
+
+ bp = buf;
+
+ if (label != NULL && label[0] != '\0')
+ {
+ /* Handle the label. Care must be taken to avoid buffer overrun. */
+ size_t llen = strlen(label);
+
+ if (llen + 1 > sizeof(buf))
+ {
+ DBG_log("%s", label);
+ }
+ else
+ {
+ strcpy(buf, label);
+ if (buf[llen-1] == '\n')
+ {
+ buf[llen-1] = '\0'; /* get rid of newline */
+ DBG_log("%s", buf);
+ }
+ else if (llen < DUMP_LABEL_WIDTH)
+ {
+ bp = buf + llen;
+ }
+ else
+ {
+ DBG_log("%s", buf);
+ }
+ }
+ }
+
+ do {
+ int i, j;
+
+ for (i = 0; len!=0 && i!=4; i++)
+ {
+ *bp++ = ' ';
+ for (j = 0; len!=0 && j!=4; len--, j++)
+ {
+ static const char hexdig[] = "0123456789abcdef";
+
+ *bp++ = ' ';
+ *bp++ = hexdig[(*cp >> 4) & 0xF];
+ *bp++ = hexdig[*cp & 0xF];
+ cp++;
+ }
+ }
+ *bp = '\0';
+ DBG_log("%s", buf);
+ bp = buf;
+ } while (len != 0);
+# undef DUMP_LABEL_WIDTH
+# undef DUMP_WIDTH
+}
+
+#endif /* DEBUG */
diff --git a/programs/openac/openac.8 b/programs/openac/openac.8
new file mode 100644
index 000000000..8e609a1b1
--- /dev/null
+++ b/programs/openac/openac.8
@@ -0,0 +1,180 @@
+.TH IPSEC_OPENAC 8 "29 September 2005"
+.SH NAME
+ipsec openac \- Generation of X.509 attribute certificates
+.SH SYNOPSIS
+.B ipsec
+.B openac
+[
+.B \-\-help
+] [
+.B \-\-version
+] [
+.B \-\-optionsfrom
+\fIfilename\fP
+] [
+.B \-\-quiet
+]
+.br
+\ \ \ [
+.B \-\-debug\(hyall
+] [
+.B \-\-debug\(hyparsing
+] [
+.B \-\-debug\(hyraw
+] [
+.B \-\-debug\(hyprivate
+]
+.br
+\ \ \ [
+.B \-\-days
+\fIdays\fP
+] [
+.B \-\-hours
+\fIhours\fP
+]
+.br
+\ \ \ [
+.B \-\-startdate
+\fIYYYYMMDDHHMMSSZ\fP
+] [
+.B \-\-stopdate
+\fIYYYYMMDDHHMMSSZ\fP
+]
+.br
+.B \ \ \ \-\-cert
+\fIcertfile\fP
+.B \-\-key
+\fIkeyfile\fP
+[
+.B \-\-password
+\fIpassword\fP
+]
+.br
+.B \ \ \ \-\-usercert
+\fIcertfile\fP
+.B \-\-groups
+\fIattr1,attr2,...\fP
+.B \-\-out
+\fIfilename\fP
+.SH DESCRIPTION
+.BR openac
+is intended to be used by an Authorization Authority (AA) to generate and sign
+X.509 attribute certificates. Currently only the inclusion of one ore several group
+attributes is supported. An attribute certificate is linked to a holder by
+including the issuer and serial number of the holder's X.509 certificate.
+.SH OPTIONS
+.TP
+\fB\-\-help\fP
+display the usage message.
+.TP
+\fB\-\-version\fP
+display the version of \fBopenac\fP.
+.TP
+\fB\-\-optionsfrom\fP\ \fIfilename\fP
+adds the contents of the file to the argument list.
+If \fIfilename\fP is a relative path then the file is searched in the directory
+\fI/etc/openac\fP.
+.TP
+\fB\-\-quiet\fP
+By default \fBopenac\fP logs all control output both to syslog and stderr.
+With the \fB\-\-quiet\fP option no output is written to stderr.
+.TP
+\fB\-\-days\fP\ \fIdays\fP
+Validity of the X.509 attribute certificate in days. If neiter the \fB\-\-days\fP\ nor
+the \fB\-\-hours\fP\ option is specified then a default validity interval of 1 day is assumed.
+The \fB\-\-days\fP\ option can be combined with the \fB\-\-hours\fP\ option.
+.TP
+\fB\-\-hours\fP\ \fIhours\fP
+Validity of the X.509 attribute certificate in hours. If neiter the \fB\-\-hours\fP\ nor
+the \fB\-\-days\fP\ option is specified then a default validity interval of 24 hours is assumed.
+The \fB\-\-hours\fP\ option can be combined with the \fB\-\-days\fP\ option.
+.TP
+\fB\-\-startdate\fP\ \fIYYYYMMDDHHMMSSZ\fP
+defines the \fBnotBefore\fP date when the X.509 attribute certificate becomes valid.
+The date \fIYYYYMMDDHHMMSS\fP must be specified in UTC (\fIZ\fPulu time).
+If the \fB\-\-startdate\fP option is not specified then the current date is taken as a default.
+
+.TP
+\fB\-\-stopdate\fP\ \fIYYYYMMDDHHMMSSZ\fP
+defines the \fBnotAfter\fP date when the X.509 attribute certificate will expire.
+The date \fIYYYYMMDDHHMMSS\fP must be specified in UTC (\fIZ\fPulu time).
+If the \fB\-\-stopdate\fP option is not specified then the default \fBnotAfter\fP value is computed
+by adding the validity interval specified by the \fB\-\-days\fP\ and/or \fB\-\-days\fP\ options
+to the \fBnotBefore\fP date.
+.TP
+\fB\-\-cert\fP\ \fIcertfile\fP
+specifies the file containing the X.509 certificate of the Authorization Authority.
+The certificate is stored either in PEM or DER format.
+.TP
+\fB\-\-key\fP\ \fIkeyfile\fP
+specifies the encrypted file containing the private RSA key of the Authoritzation
+Authority. The private key is stored in PKCS#1 format.
+.TP
+\fB\-\-password\fP\ \fIpassword\fP
+specifies the password with which the private RSA keyfile defined by the
+\fB\-\-key\fP option has been protected. If the option is missing then the
+password is prompted for on the command line.
+.TP
+\fB\-\-usercert\fP\ \fIcertfile\fP
+specifies file containing the X.509 certificate of the user to which the generated attribute
+certificate will apply. The certificate file is stored either in PEM or DER format.
+.TP
+\fB\-\-groups\fP\ \fIattr1,attr2\fP
+specifies a comma-separated list of group attributes that will go into the
+X.509 attribute certificate.
+.TP
+\fB\-\-out\fP\ \fIfilename\fP
+specifies the file where the generated X.509 attribute certificate will be stored to.
+.SS Debugging
+.LP
+\fBopenac\fP produces a prodigious amount of debugging information. To do so,
+it must be compiled with \-DDEBUG. There are several classes of debugging output,
+and \fBopenac\fP may be directed to produce a selection of them. All lines of
+debugging output are prefixed with ``|\ '' to distinguish them from error messages.
+.LP
+When \fBopenac\fP is invoked, it may be given arguments to specify
+which classes to output. The current options are:
+.TP
+\fB\-\-debug-raw\fP
+show the raw bytes of the parsed user and authorization authority certificates
+as well as of the generated X.509 attribute certificate.
+.TP
+\fB\-\-debug-parsing\fP
+show the parsed structure of user and authorization authority certificats
+as well as of the generated X.509 attribute certificate.
+.TP
+\fB\-\-debug-all\fP
+all of the above.
+.TP
+\fB\-\-debug-private\fP
+enables debugging output of the authorization authority's private key.
+.SH EXIT STATUS
+.LP
+The execution of \fBopenac\fP terminates with one of the following two exit codes:
+.TP
+0
+means that the attribute certificate was successfully generated and stored.
+.TP
+1
+means that something went wrong.
+.SH FILES
+\fI/etc/openac/serial\fP\ \ \ serial number of latest attribute certificate
+.SH SEE ALSO
+.LP
+The X.509 attribute certificates generated with \fBopenac\fP can be used to
+enforce group policies defined by \fIipsec.conf\fP(5). Use \fIipsec_auto\fP(8)
+to load and list X.509 attribute certificates.
+.LP
+For more information on X.509 attribute certificates, refer to the following
+IETF RFC:
+.IP
+RFC 3281 An Internet Attribute Certificate Profile for Authorization
+.SH HISTORY
+The \fBopenac\fP program was originally written by Ariane Seiler and Ueli Galizzi.
+The software was recoded by Andreas Steffen using strongSwan's X.509 library and
+the ASN.1 code synthesis functions written by Christoph Gysin and Christoph Zwahlen.
+All authors were with the Zurich University of Applied Sciences in Winterthur,
+Switzerland.
+.LP
+.SH BUGS
+Bugs should be reported to the <users@lists.strongswan.org> mailing list.
diff --git a/programs/openac/openac.c b/programs/openac/openac.c
new file mode 100755
index 000000000..524a302d7
--- /dev/null
+++ b/programs/openac/openac.c
@@ -0,0 +1,438 @@
+/* Generation of X.509 attribute certificates
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2004 Andreas Steffen
+ * Zuercher Hochschule Winterthur, Switzerland
+ *
+ * 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: openac.c,v 1.18 2006/01/04 21:12:33 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <time.h>
+#include <gmp.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/mp_defs.h"
+#include "../pluto/log.h"
+#include "../pluto/asn1.h"
+#include "../pluto/certs.h"
+#include "../pluto/x509.h"
+#include "../pluto/crl.h"
+#include "../pluto/keys.h"
+#include "../pluto/ac.h"
+
+#include "build.h"
+
+#define OPENAC_PATH "/etc/openac"
+#define OPENAC_SERIAL "/etc/openac/serial"
+
+const char openac_version[] = "openac 0.3";
+
+/* by default the CRL policy is lenient */
+bool strict_crl_policy = FALSE;
+
+/* by default pluto does not check crls dynamically */
+long crl_check_interval = 0;
+
+/* by default pluto logs out after every smartcard use */
+bool pkcs11_keep_state = FALSE;
+
+static void
+usage(const char *mess)
+{
+ if (mess != NULL && *mess != '\0')
+ fprintf(stderr, "%s\n", mess);
+ fprintf(stderr
+ , "Usage: openac"
+ " [--help]"
+ " [--version]"
+ " [--optionsfrom <filename>]"
+ " [--quiet]"
+#ifdef DEBUG
+ " \\\n\t"
+ " [--debug-all]"
+ " [--debug-parsing]"
+ " [--debug-raw]"
+ " [--debug-private]"
+#endif
+ " \\\n\t"
+ " [--days <days>]"
+ " [--hours <hours>]"
+ " \\\n\t"
+ " [--startdate <YYYYMMDDHHMMSSZ>]"
+ " [--enddate <YYYYMMDDHHMMSSZ>]"
+ " \\\n\t"
+ " --cert <certfile>"
+ " --key <keyfile>"
+ " [--password <password>]"
+ " \\\n\t"
+ " --usercert <certfile>"
+ " --groups <attr1,attr2,..>"
+ " --out <filename>"
+ "\n"
+ );
+ exit(mess == NULL? 0 : 1);
+}
+
+/*
+ * read the last serial number from file
+ */
+static chunk_t
+read_serial(void)
+{
+ MP_INT number;
+
+ char buf[BUF_LEN];
+ char bytes[BUF_LEN];
+
+ FILE *fd = fopen(OPENAC_SERIAL, "r");
+
+ /* serial number defaults to 0 */
+ size_t len = 1;
+ bytes[0] = 0x00;
+
+ if (fd)
+ {
+ if (fscanf(fd, "%s", buf))
+ {
+ err_t ugh = ttodata(buf, 0, 16, bytes, BUF_LEN, &len);
+
+ if (ugh != NULL)
+ plog(" error reading serial number from %s: %s"
+ , OPENAC_SERIAL, ugh);
+ }
+ fclose(fd);
+ }
+ else
+ plog(" file '%s' does not exist yet - serial number set to 01"
+ , OPENAC_SERIAL);
+
+ /* conversion of read serial number to a multiprecision integer
+ * and incrementing it by one
+ * and representing it as a two's complement octet string
+ */
+ n_to_mpz(&number, bytes, len);
+ mpz_add_ui(&number, &number, 0x01);
+ serial = mpz_to_n(&number, 1 + mpz_sizeinbase(&number, 2)/BITS_PER_BYTE);
+ mpz_clear(&number);
+
+ return serial;
+}
+
+/*
+ * write back the last serial number to file
+ */
+static void
+write_serial(chunk_t serial)
+{
+ char buf[BUF_LEN];
+
+ FILE *fd = fopen(OPENAC_SERIAL, "w");
+
+ if (fd)
+ {
+ datatot(serial.ptr, serial.len, 16, buf, BUF_LEN);
+ plog(" serial number is %s", buf);
+ fprintf(fd, "%s\n", buf);
+ fclose(fd);
+ }
+ else
+ plog(" could not open file '%s' for writing", OPENAC_SERIAL);
+}
+
+/*
+ * global variables accessible by both main() and build.c
+ */
+x509cert_t *user = NULL;
+x509cert_t *signer = NULL;
+
+ietfAttrList_t *groups = NULL;
+struct RSA_private_key *signerkey = NULL;
+
+time_t notBefore = 0;
+time_t notAfter = 0;
+
+chunk_t serial;
+
+
+int
+main(int argc, char **argv)
+{
+ char *keyfile = NULL;
+ char *certfile = NULL;
+ char *usercertfile = NULL;
+ char *outfile = NULL;
+
+ cert_t signercert = empty_cert;
+ cert_t usercert = empty_cert;
+
+ chunk_t attr_cert = empty_chunk;
+ x509acert_t *ac = NULL;
+
+ const time_t default_validity = 24*3600; /* 24 hours */
+ time_t validity = 0;
+
+ prompt_pass_t pass;
+
+ pass.secret[0] = '\0';
+ pass.prompt = TRUE;
+ pass.fd = STDIN_FILENO;
+
+ log_to_stderr = TRUE;
+
+ /* handle arguments */
+ for (;;)
+ {
+# define DBG_OFFSET 256
+ static const struct option long_opts[] = {
+ /* name, has_arg, flag, val */
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "optionsfrom", required_argument, NULL, '+' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "cert", required_argument, NULL, 'c' },
+ { "key", required_argument, NULL, 'k' },
+ { "password", required_argument, NULL, 'p' },
+ { "usercert", required_argument, NULL, 'u' },
+ { "groups", required_argument, NULL, 'g' },
+ { "days", required_argument, NULL, 'D' },
+ { "hours", required_argument, NULL, 'H' },
+ { "startdate", required_argument, NULL, 'S' },
+ { "enddate", required_argument, NULL, 'E' },
+ { "out", required_argument, NULL, 'o' },
+#ifdef DEBUG
+ { "debug-all", no_argument, NULL, 'A' },
+ { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
+ { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
+ { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },
+#endif
+ { 0,0,0,0 }
+ };
+
+ int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:", long_opts, NULL);
+
+ /* Note: "breaking" from case terminates loop */
+ switch (c)
+ {
+ case EOF: /* end of flags */
+ break;
+
+ case 0: /* long option already handled */
+ continue;
+
+ case ':': /* diagnostic already printed by getopt_long */
+ case '?': /* diagnostic already printed by getopt_long */
+ usage(NULL);
+ break; /* not actually reached */
+
+ case 'h': /* --help */
+ usage(NULL);
+ break; /* not actually reached */
+
+ case 'v': /* --version */
+ printf("%s\n", openac_version);
+ exit(0);
+ break; /* not actually reached */
+
+ case '+': /* --optionsfrom <filename> */
+ {
+ char path[BUF_LEN];
+
+ if (*optarg == '/') /* absolute pathname */
+ strncpy(path, optarg, BUF_LEN);
+ else /* relative pathname */
+ snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg);
+ optionsfrom(path, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ }
+ continue;
+
+ case 'q': /* --quiet */
+ log_to_stderr = TRUE;
+ continue;
+
+ case 'c': /* --cert */
+ certfile = optarg;
+ continue;
+
+ case 'k': /* --key */
+ keyfile = optarg;
+ continue;
+
+ case 'p': /* --key */
+ pass.prompt = FALSE;
+ strncpy(pass.secret, optarg, sizeof(pass.secret));
+ continue;
+
+ case 'u': /* --usercert */
+ usercertfile = optarg;
+ continue;
+
+ case 'g': /* --groups */
+ decode_groups(optarg, &groups);
+ continue;
+
+ case 'D': /* --days */
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing number of days");
+ {
+ char *endptr;
+ long days = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || days <= 0)
+ usage("<days> must be a positive number");
+ validity += 24*3600*days;
+ }
+ continue;
+
+ case 'H': /* --hours */
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing number of hours");
+ {
+ char *endptr;
+ long hours = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || hours <= 0)
+ usage("<hours> must be a positive number");
+ validity += 3600*hours;
+ }
+ continue;
+
+ case 'S': /* --startdate */
+ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
+ usage("date format must be YYYYMMDDHHMMSSZ");
+ {
+ chunk_t date = { optarg, 15 };
+ notBefore = asn1totime(&date, ASN1_GENERALIZEDTIME);
+ }
+ continue;
+
+ case 'E': /* --enddate */
+ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
+ usage("date format must be YYYYMMDDHHMMSSZ");
+ {
+ chunk_t date = { optarg, 15 };
+ notAfter = asn1totime(&date, ASN1_GENERALIZEDTIME);
+ }
+ continue;
+
+ case 'o': /* --outt */
+ outfile = optarg;
+ continue ;
+
+#ifdef DEBUG
+ case 'A': /* --debug-all */
+ base_debugging = DBG_ALL;
+ continue;
+#endif
+ default:
+#ifdef DEBUG
+ if (c >= DBG_OFFSET)
+ {
+ base_debugging |= c - DBG_OFFSET;
+ continue;
+ }
+#undef DBG_OFFSET
+#endif
+ bad_case(c);
+ }
+ break;
+ }
+
+ init_log("openac");
+ cur_debugging = base_debugging;
+
+ if (optind != argc)
+ usage("unexpected argument");
+
+ /* load the signer's RSA private key */
+ if (keyfile != NULL)
+ {
+ err_t ugh = NULL;
+
+ signerkey = alloc_thing(RSA_private_key_t, "RSA private key");
+ ugh = load_rsa_private_key(keyfile, &pass, signerkey);
+
+ if (ugh != NULL)
+ {
+ free_RSA_private_content(signerkey);
+ pfree(signerkey);
+ plog("%s", ugh);
+ exit(1);
+ }
+ }
+
+ /* load the signer's X.509 certificate */
+ if (certfile != NULL)
+ {
+ if (!load_cert(certfile, "signer cert", &signercert))
+ exit(1);
+ signer = signercert.u.x509;
+ }
+
+ /* load the users's X.509 certificate */
+ if (usercertfile != NULL)
+ {
+ if (!load_cert(usercertfile, "user cert", &usercert))
+ exit(1);
+ user = usercert.u.x509;
+ }
+
+ /* compute validity interval */
+ validity = (validity)? validity : default_validity;
+ notBefore = (notBefore) ? notBefore : time(NULL);
+ notAfter = (notAfter) ? notAfter : notBefore + validity;
+
+ /* build and parse attribute certificate */
+ if (user != NULL && signer != NULL && signerkey != NULL)
+ {
+ /* read the serial number and increment it by one */
+ serial = read_serial();
+
+ attr_cert = build_attr_cert();
+ ac = alloc_thing(x509acert_t, "x509acert");
+ *ac = empty_ac;
+ parse_ac(attr_cert, ac);
+
+ /* write the attribute certificate to file */
+ if (write_chunk(outfile, "attribute cert", attr_cert, 0022, TRUE))
+ write_serial(serial);
+ }
+
+ /* delete all dynamic objects */
+ if (signerkey != NULL)
+ {
+ free_RSA_private_content(signerkey);
+ pfree(signerkey);
+ }
+ free_x509cert(signercert.u.x509);
+ free_x509cert(usercert.u.x509);
+ free_ietfAttrList(groups);
+ free_acert(ac);
+ pfree(serial.ptr);
+
+#ifdef LEAK_DETECTIVE
+ report_leaks();
+#endif /* LEAK_DETECTIVE */
+ close_log();
+ exit(0);
+}
diff --git a/programs/pf_key/.cvsignore b/programs/pf_key/.cvsignore
new file mode 100644
index 000000000..323068235
--- /dev/null
+++ b/programs/pf_key/.cvsignore
@@ -0,0 +1 @@
+pf_key
diff --git a/programs/pf_key/Makefile b/programs/pf_key/Makefile
new file mode 100644
index 000000000..6af45c8d1
--- /dev/null
+++ b/programs/pf_key/Makefile
@@ -0,0 +1,49 @@
+# Makefile for the KLIPS interface utilities
+# Copyright (C) 1998, 1999 Henry Spencer.
+# Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:28 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM:=pf_key
+EXTRA5MAN=${PROGRAM}.5
+
+LIBS:=${FREESWANLIB}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:28 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.3 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.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/pf_key/pf_key.5 b/programs/pf_key/pf_key.5
new file mode 100644
index 000000000..f5eab9a96
--- /dev/null
+++ b/programs/pf_key/pf_key.5
@@ -0,0 +1,122 @@
+.TH IPSEC_PF_KEY 5 "29 Jun 2000"
+.\"
+.\" RCSID $Id: pf_key.5,v 1.1 2004/03/15 20:35:28 as Exp $
+.\"
+.SH NAME
+ipsec_pf_key \- lists PF_KEY sockets registered with KLIPS
+.SH SYNOPSIS
+.B cat
+.B /proc/net/pf_key
+.SH DESCRIPTION
+.I /proc/net/pf_key
+is a read-only file which lists the presently open PF_KEY sockets on the
+local system and their parameters.
+.PP
+Each line lists one PF_KEY socket.
+A table entry consists of:
+.IP + 3
+sock pointer (sock)
+.IP +
+PID of the socket owner (pid)
+.IP +
+flag to indicate if the socket is dead (d)
+.IP +
+socket wait queue (sleep)
+.IP +
+socket pointer (socket)
+.IP +
+next socket in chain (next)
+.IP +
+previous socket in chain (prev)
+.IP +
+last socket error (e)
+.IP +
+pointer to destruct routine (destruct)
+.IP +
+is this a reused socket (r)
+.IP +
+has this socket been zapped (z)
+.IP +
+socket family to which this socket belongs (fa)
+.IP +
+local port number (n)
+.IP +
+protocol version number (p)
+.IP +
+Receive queue bytes committed (r)
+.IP +
+Transmit queue bytes committed (w)
+.IP +
+option memory allocations (o)
+.IP +
+size of send buffer in bytes (sndbf)
+.IP +
+timestamp in seconds (stamp)
+.IP +
+socket flags (Flags)
+.IP +
+socket type (Type)
+.IP +
+connection state (St)
+.BR
+.SH EXAMPLES
+.TP
+.\".B "sock pid d sleep socket next prev e destruct r z fa n p r w o sndbf stamp Flags Type St"
+.TP
+.B c3b8c140 3553 0 c0599818 c05997fc 0 0 0 0 1 0 15 0 2 0 0 0 65535 0.103232 00000000 00000003 01
+.LP
+shows that there is one pf_key socket set up that starts at
+.BR c3b8c140 ,
+whose owning process has PID
+.BR 3553 ,
+the socket is not dead, its wait queue is at
+.BR c0599818 ,
+whose owning socket is at
+.BR c05997fc ,
+with no other sockets in the chain, no errors, no destructor, it is a
+reused socket which has not been zapped, from protocol family
+.BR 15
+(PF_KEY), local port number
+.BR 0 ,
+protocol socket version
+.BR 2 ,
+no memory allocated to transmit, receive or option queues, a send buffer
+of almost
+.BR 64kB ,
+a timestamp of
+.BR 0.103232 ,
+no flags set, type
+.BR 3 ,
+in state
+.BR 1 .
+.SH "FILES"
+/proc/net/pf_key
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_eroute(5), ipsec_spi(5),
+ipsec_spigrp(5), ipsec_klipsdebug(5), ipsec_tncfg(8), ipsec_version(5)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Richard Guy Briggs.
+.\"
+.\" $Log: pf_key.5,v $
+.\" Revision 1.1 2004/03/15 20:35:28 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.4 2002/04/24 07:35:39 mcr
+.\" Moved from ./klips/utils/pf_key.5,v
+.\"
+.\" Revision 1.3 2001/01/23 23:51:49 rgb
+.\" Fix outdated references to /proc/net/ipsec_pf_key.
+.\"
+.\" Revision 1.2 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.1 2000/06/30 06:19:27 rgb
+.\" manpages for the last two /proc/net/ipsec* files that don't have a
+.\" corresponding utility.
+.\"
+.\"
+.\"
diff --git a/programs/pf_key/pf_key.8 b/programs/pf_key/pf_key.8
new file mode 100644
index 000000000..dd42bf541
--- /dev/null
+++ b/programs/pf_key/pf_key.8
@@ -0,0 +1,73 @@
+.TH IPSEC_PF_KEY 8 "17 Oct 2001"
+.\"
+.\" RCSID $Id: pf_key.8,v 1.2 2005/07/07 19:07:43 as Exp $
+.\"
+.SH NAME
+pf_key \- shows pfkey messages emitted by the kernel
+.SH SYNOPSIS
+.B pf_key
+.B \-\-ah
+.B \-\-esp
+.B \-\-ipip
+.B \-\-ipcomp
+.B \-\-daemon
+.I file
+.BR hmac-md5-96 | hmac-sha1-96
+.SH DESCRIPTION
+.B pf_key
+is a program to open a PF_KEY socket and print all messages that are received
+from it. With no options, it will register itself to receive key requests for
+AH, ESP, IPIP and IPCOMP security associations. If given more specific
+options, then it will listen only to those protocols which are listed.
+.PP
+If the messages are recognized, the messages will be decoded.
+.PP
+If the option
+.B \-\-daemon
+is provided, then after doing the registrations, the program will fork
+into the background. The provided file will be opened and the process ID of
+the background process will be written to it. This option is present to
+present race conditions in regression testing.
+.SH EXAMPLES
+.TP
+.\".B "pfkey v.2 msg. type 3 seq=20 len=2 errno=22 satype=3"
+.SH "FILES"
+/proc/net/pf_key
+.SH "SEE ALSO"
+pf_key(5), ipsec(8), ipsec_manual(8), ipsec_eroute(5), ipsec_spi(5),
+ipsec_spigrp(5), ipsec_klipsdebug(5), ipsec_tncfg(8), ipsec_version(5)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Michael Richardson <mcr@freeswan.org>
+.\"
+.\" $Log: pf_key.8,v $
+.\" Revision 1.2 2005/07/07 19:07:43 as
+.\" fixed man page type
+.\"
+.\" Revision 1.1 2004/03/15 20:35:28 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.4 2002/07/16 02:53:42 mcr
+.\" added --daemon <pidfile> to "ipsec pf_key" command.
+.\" this is used in *-trap-* tests to avoid race conditions between
+.\" registration of PF_KEY listeners and arrival of first test packet.
+.\"
+.\" Revision 1.3 2002/04/24 07:35:39 mcr
+.\" Moved from ./klips/utils/pf_key.8,v
+.\"
+.\" Revision 1.2 2001/11/23 07:23:14 mcr
+.\" pulled up klips2 Makefile and pf_key code.
+.\"
+.\" Revision 1.1.2.1 2001/10/23 18:49:12 mcr
+.\" renamed man page to section 8.
+.\" added --ah, --esp, --ipcomp and --ipip to control which
+.\" protocols are printed.
+.\" incomplete messages which include at least an sadb header are printed.
+.\"
+.\" Revision 1.1.2.1 2001/10/17 23:25:37 mcr
+.\" added "pk_key" program to dump raw kernel pf messages.
+.\" (program is still skeletal)
+.\"
+.\"
+.\"
diff --git a/programs/pf_key/pf_key.c b/programs/pf_key/pf_key.c
new file mode 100644
index 000000000..af7365d65
--- /dev/null
+++ b/programs/pf_key/pf_key.c
@@ -0,0 +1,353 @@
+/*
+ * @(#) pfkey socket manipulator/observer
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pf_key.c,v 1.2 2004/04/20 21:23:25 as Exp $
+ *
+ */
+
+/*
+ * This program opens a pfkey socket and prints all messages that it sees.
+ *
+ * This can be used to diagnose problems.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+
+#include <sys/socket.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+char *progname;
+uint32_t pfkey_seq = 0;
+int pfkey_sock;
+
+static void
+Usage(char *progname)
+{
+ fprintf(stderr, "%s: Usage: %s [--help]\n"
+ "\tby default listens for AH, ESP, IPIP and IPCOMP\n"
+ "\t--daemon <file> fork before printing, stuffing the PID in the file\n"
+ "\t--ah listen for AH messages\n"
+ "\t--esp listen for ESP messages\n"
+ "\t--ipip listen for IPIP messages\n"
+ "\t--ipcomp listen for IPCOMP messages\n",
+ progname, progname);
+ exit(1);
+}
+
+void
+pfkey_register(uint8_t satype) {
+ /* for registering SA types that can be negotiated */
+ int error = 0;
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+ struct sadb_msg *pfkey_msg;
+
+ pfkey_extensions_init(extensions);
+ if((error = pfkey_msg_hdr_build(&extensions[0],
+ SADB_REGISTER,
+ satype,
+ 0,
+ ++pfkey_seq,
+ getpid()))) {
+ fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
+ progname, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+ if((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN))) {
+ fprintf(stderr, "%s: Trouble building pfkey message, error=%d.\n",
+ progname, error);
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+ exit(1);
+ }
+ if(write(pfkey_sock, pfkey_msg,
+ pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) !=
+ (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
+ /* cleanup code here */
+ fprintf(stderr, "%s: Trouble writing to channel PF_KEY.\n", progname);
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+ exit(1);
+ }
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+}
+
+int dienow;
+
+void controlC(int foo)
+{
+ fflush(stdout);
+ printf("%s: Exiting on signal 15\n", progname);
+ fflush(stderr);
+ exit(0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ ssize_t readlen;
+ unsigned char pfkey_buf[256];
+ struct sadb_msg *msg;
+ int fork_after_register;
+ char *pidfilename;
+
+ static int ah_register;
+ static int esp_register;
+ static int ipip_register;
+ static int ipcomp_register;
+
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, 'h'},
+ {"daemon", required_argument, 0, 'f'},
+ {"ah", no_argument, &ah_register, 1},
+ {"esp", no_argument, &esp_register, 1},
+ {"ipip", no_argument, &ipip_register, 1},
+ {"ipcomp", no_argument, &ipcomp_register, 1},
+ };
+
+ ah_register = 0;
+ esp_register = 0;
+ ipip_register = 0;
+ ipcomp_register=0;
+ dienow = 0;
+ fork_after_register=0;
+ pidfilename=NULL;
+
+ progname = argv[0];
+ if(strrchr(progname, '/')) {
+ progname=strrchr(progname, '/')+1;
+ }
+
+ while((opt = getopt_long(argc, argv, "hf:",
+ long_options, NULL)) != EOF) {
+ switch(opt) {
+ case 'f':
+ pidfilename=optarg;
+ fork_after_register=1;
+ break;
+ case 'h':
+ Usage(progname);
+ break;
+ case '0':
+ /* it was a long option with a flag */
+ break;
+ }
+ }
+
+ if((pfkey_sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2) ) < 0) {
+ fprintf(stderr, "%s: failed to open PF_KEY family socket: %s\n",
+ progname, strerror(errno));
+ exit(1);
+ }
+
+ if(ah_register == 0 &&
+ esp_register== 0 &&
+ ipip_register==0 &&
+ ipcomp_register==0) {
+ ah_register=1;
+ esp_register=1;
+ ipip_register=1;
+ ipcomp_register=1;
+ }
+
+ if(ah_register) {
+ pfkey_register(SADB_SATYPE_AH);
+ }
+ if(esp_register) {
+ pfkey_register(SADB_SATYPE_ESP);
+ }
+ if(ipip_register) {
+ pfkey_register(SADB_X_SATYPE_IPIP);
+ }
+ if(ipcomp_register) {
+ pfkey_register(SADB_X_SATYPE_COMP);
+ }
+
+ if(fork_after_register) {
+ /*
+ * to aid in regression testing, we offer to register
+ * everything first, and then we fork. As part of this
+ * we write the PID of the new process to a file
+ * provided.
+ */
+ int pid;
+ FILE *pidfile;
+
+ fflush(stdout);
+ fflush(stderr);
+
+ pid=fork();
+ if(pid!=0) {
+ /* in parent! */
+ exit(0);
+ }
+
+ if((pidfile=fopen(pidfilename, "w"))==NULL) {
+ perror(pidfilename);
+ } else {
+ fprintf(pidfile, "%d", getpid());
+ fclose(pidfile);
+ }
+ }
+
+ signal(SIGINT, controlC);
+ signal(SIGTERM, controlC);
+
+ while((readlen = read(pfkey_sock, pfkey_buf, sizeof(pfkey_buf))) > 0) {
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+ msg = (struct sadb_msg *)pfkey_buf;
+
+ /* first, see if we got enough for an sadb_msg */
+ if((size_t)readlen < sizeof(struct sadb_msg)) {
+ printf("%s: runt packet of size: %d (<%lu)\n",
+ progname, (int)readlen, (unsigned long)sizeof(struct sadb_msg));
+ continue;
+ }
+
+ /* okay, we got enough for a message, print it out */
+ printf("\npfkey v%d msg. type=%d(%s) seq=%d len=%d pid=%d errno=%d satype=%d(%s)\n",
+ msg->sadb_msg_version,
+ msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(msg->sadb_msg_type),
+ msg->sadb_msg_seq,
+ msg->sadb_msg_len,
+ msg->sadb_msg_pid,
+ msg->sadb_msg_errno,
+ msg->sadb_msg_satype,
+ satype2name(msg->sadb_msg_satype));
+
+ if((size_t)readlen != msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)
+ {
+ printf("%s: packet size read from socket=%d doesn't equal sadb_msg_len %d * %u; message not decoded\n",
+ progname,
+ (int)readlen,
+ msg->sadb_msg_len,
+ (int) IPSEC_PFKEYv2_ALIGN);
+ continue;
+ }
+
+ pfkey_lib_debug = PF_KEY_DEBUG_PARSE_STRUCT;
+ if (pfkey_msg_parse(msg, NULL, extensions, EXT_BITS_OUT)) {
+ printf("%s: unparseable PF_KEY message.\n",
+ progname);
+ } else {
+ printf("%s: parseable PF_KEY message.\n",
+ progname);
+ }
+ }
+ printf("%s: exited normally\n", progname);
+ exit(0);
+}
+
+/*
+ * $Log: pf_key.c,v $
+ * Revision 1.2 2004/04/20 21:23:25 as
+ * int cast fix for 64 bit platforms
+ *
+ * Revision 1.1 2004/03/15 20:35:28 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.15 2003/09/10 00:01:30 mcr
+ * fixes for gcc 3.3 from Matthias Bethke <Matthias.Bethke@gmx.net>
+ *
+ * Revision 1.14 2002/10/09 03:12:05 dhr
+ *
+ * [kenb+dhr] 64-bit fixes
+ *
+ * Revision 1.13 2002/09/20 05:02:15 rgb
+ * Cleaned up pfkey_lib_debug usage.
+ *
+ * Revision 1.12 2002/09/13 23:02:23 rgb
+ * Type fiddling to tame ia64 compiler.
+ * Added text labels to elucidate numeric values presented.
+ *
+ * Revision 1.11 2002/08/26 03:05:25 mcr
+ * duh, pf_key much catch SIGTERM as well as SIGINT...
+ *
+ * Revision 1.10 2002/08/13 19:01:27 mcr
+ * patches from kenb to permit compilation of FreeSWAN on ia64.
+ * des library patched to use proper DES_LONG type for ia64.
+ *
+ * Revision 1.9 2002/07/16 02:53:42 mcr
+ * added --daemon <pidfile> to "ipsec pf_key" command.
+ * this is used in *-trap-* tests to avoid race conditions between
+ * registration of PF_KEY listeners and arrival of first test packet.
+ *
+ * Revision 1.8 2002/06/17 04:32:55 mcr
+ * exit nicely from pf_key when SIGINT (^C) is sent.
+ * This is needed so that the stdout will flush properly.
+ *
+ * Revision 1.7 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.6 2002/04/24 07:35:39 mcr
+ * Moved from ./klips/utils/pf_key.c,v
+ *
+ * Revision 1.5 2002/03/08 21:44:04 rgb
+ * Update for all GNU-compliant --version strings.
+ *
+ * Revision 1.4 2001/11/27 05:19:06 mcr
+ * added extra newline between packets.
+ * set pfkey_lib_debug to enum rather than just to "1".
+ *
+ * Revision 1.3 2001/11/27 03:35:29 rgb
+ * Added stdlib *again*.
+ *
+ * Revision 1.2 2001/11/23 07:23:14 mcr
+ * pulled up klips2 Makefile and pf_key code.
+ *
+ * Revision 1.1.2.5 2001/10/23 18:49:12 mcr
+ * renamed man page to section 8.
+ * added --ah, --esp, --ipcomp and --ipip to control which
+ * protocols are printed.
+ * incomplete messages which include at least an sadb header are printed.
+ *
+ * Revision 1.1.2.4 2001/10/22 21:50:51 rgb
+ * Added pfkey register for AH, ESP, IPIP and COMP.
+ *
+ * Revision 1.1.2.3 2001/10/21 21:51:06 rgb
+ * Bug fixes to get working.
+ *
+ * Revision 1.1.2.2 2001/10/20 22:45:31 rgb
+ * Added check for exact length and a call to message parser to get some
+ * idea of the contents of each extension.
+ *
+ * Revision 1.1.2.1 2001/10/17 23:25:37 mcr
+ * added "pk_key" program to dump raw kernel pf messages.
+ * (program is still skeletal)
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/programs/pluto/.cvsignore b/programs/pluto/.cvsignore
new file mode 100644
index 000000000..fb96dae41
--- /dev/null
+++ b/programs/pluto/.cvsignore
@@ -0,0 +1,3 @@
+_pluto_adns
+pluto
+whack
diff --git a/programs/pluto/Makefile b/programs/pluto/Makefile
new file mode 100644
index 000000000..515b3fac0
--- /dev/null
+++ b/programs/pluto/Makefile
@@ -0,0 +1,1090 @@
+# Pluto Makefile
+# Copyright (C) 1997 Angelos D. Keromytis.
+# Copyright (C) 1998-2001 D. Hugh Redelmeier
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.44 2006/01/25 17:22:19 as Exp $
+
+# relative path to top directory of FreeS/WAN source
+# Note: referenced in ${FREESWANSRCDIR}/Makefile.inc
+FREESWANSRCDIR=../..
+
+include ${FREESWANSRCDIR}/Makefile.inc
+
+FMANDIR=$(MANTREE)/man5
+PMANDIR=$(MANTREE)/man8
+
+# -O on Linux makes gcc coredump when compiling sha1.c
+# -Wundef is nice but RHL5.2 compiler doesn't support it
+CFLAGS = -g -Wall -W -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast \
+ -Wcast-qual -Wmissing-declarations -Wwrite-strings \
+ -Wstrict-prototypes # -Wundef
+
+# where to find klips headers and FreeS/WAN headers
+HDRDIRS = -I$(KLIPSINC) -I${FREESWANSRCDIR}/programs/pluto/linux26
+
+# where to find sha2.h
+LIBCRYPTO=$(FREESWANSRCDIR)/lib/libcrypto
+HDRDIRS += -I$(LIBCRYPTO)
+
+# On non-LINUX systems, these one of these may be needed (see endian.h)
+# BYTE_ORDER = -DBIG_ENDIAN=4321 -DLITTLE_ENDIAN=1234 -DBYTE_ORDER=BIG_ENDIAN
+# BYTE_ORDER = -DBIG_ENDIAN=4321 -DLITTLE_ENDIAN=1234 -DBYTE_ORDER=LITTLE_ENDIAN
+
+# -DKLIPS enables interface to Kernel LINUX IPsec code
+# -DDEBUG enables debugging code, allowing for debugging output
+# (note that output must also be selected at runtime, so it is
+# reasonable to always define this)
+# -DVENDORID enables Pluto to send out a VendorID payload.
+# this can be used by remote nodes to work around faults (bugs),
+# but is most useful to humans who are debugging things.
+# -DGCC_LINT uses gcc-specific declarations to improve compile-time
+# diagnostics.
+# -DLEAK_DETECTIVE enables crude code to find memory allocation leaks.
+# -DOLD_RESOLVER. At some point, the resolver interface changed.
+# This macro enables Pluto support for the old interface.
+# It is automatically defined, based on the value of the <resolver.h>
+# macro __RES. We don't know the correct threshold, so you may
+# find that you must manually define this. If so, please inform
+# us so that we can refine the threshold.
+# -DLIBCURL includes libcurl functions for the support of http-based protocols.
+# -DLDAP_VER includes openldap functions for the support of ldap-based queries.
+# LDAPv2 and LDAPv3 are supported.
+# -DTHREADS enables an asynchronous thread managing CRL fetching.
+# This option is activated either by -DLIBCURL or -DLDAP_VER.
+# -DSMARTCARD enables PKCS11-based smartcard support
+# -DPKCS11_DEFAULT_LIB defines a default PKCS11 library module which will be
+# loaded during runtime and is overridden by the pkcs11module parameter in
+# ipsec.conf. This option is activated by -DSMARTCARD.
+# -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+# allows IPsec transport mode in NAT-ed environments. Because of the
+# inherent security risks of such scenarios this options is deactivated
+# by default.
+
+# The following are best left undefined -- each can be overridden at runtime
+# if need be.
+# -DPORT=n sets the default UDP port for IKE messages (otherwise 500)
+# -DSHARED_SECRETS_FILE=string overrides /etc/ipsec.secrets as the
+# default name of the file containing secrets used to authenticate other
+# IKE daemons. In the Makefile, two levels of quoting are needed:
+# -DSHARED_SECRETS_FILE='"/etc/ipsec.secrets"'
+# -DDEFAULT_CTLBASE=string overrides /var/run/pluto as default directory
+# and basename for pluto's lockfile (.pid) and control socket (.ctl).
+# Double quoting may be needed.
+
+ifeq ($(USE_LWRES),true)
+ LWRESDEF=-DUSE_LWRES
+ USE_ADNS=false
+ BINNAMEADNSIFNEEDE=
+else
+ USE_ADNS=true
+ BINNAMEADNSIFNEEDED=$(BINNAMEADNS)
+endif
+
+ifeq ($(USE_IPSECPOLICY),true)
+ IPSECPOLICY_FILES=rcv_info.c
+ IPSECPOLICY_DEFINES=-DIPSECPOLICY
+ IPSECPOLICY_LIBS=$(POLICYLIB)
+ IPSECPOLICY_OBJS=rcv_info.o
+endif
+
+ifeq ($(USE_KEYRR),true)
+ KEYRR_DEFINES=-DUSE_KEYRR
+endif
+
+ifeq ($(USE_KERNEL26),true)
+ KERNEL26_DEFS=-DKERNEL26_SUPPORT -DKERNEL26_HAS_KAME_DUPLICATES
+ KERNEL26_SRCS=kernel_netlink.c kernel_netlink.h
+ KERNEL26_OBJS=kernel_netlink.o
+endif
+
+ifeq ($(USE_NAT_TRAVERSAL),true)
+NAT_DEFS=-DNAT_TRAVERSAL -DVIRTUAL_IP
+endif
+
+ifeq ($(USE_NAT_TRAVERSAL_TRANSPORT_MODE),true)
+NAT_DEFS+=-DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+endif
+
+DEFINES = $(EXTRA_DEFINES) \
+ $(IPSECPOLICY_DEFINES) \
+ $(KEYRR_DEFINES) \
+ $(BYTE_ORDER) \
+ $(LWRESDEF) \
+ $(KERNEL26_DEFS) \
+ -DPLUTO \
+ -DKLIPS \
+ -DDEBUG \
+ -DGCC_LINT \
+ $(NAT_DEFS)
+
+# libefence is a free memory allocation debugger
+# Solaris 2 needs -lsocket -lnsl
+LIBSPLUTO = $(OBJSGCRYPT) $(LIBDESLITE) $(FREESWANLIB) $(IPSECPOLICY_LIBS)
+LIBSPLUTO+= -lgmp -lresolv # -lefence
+
+
+ifeq ($(USE_VENDORID),true)
+ DEFINES+= -DVENDORID
+endif
+
+ifeq ($(USE_XAUTH_VID),true)
+ DEFINES+= -DXAUTH_VID
+endif
+
+# This compile option activates dynamic URL fetching using libcurl
+ifeq ($(USE_LIBCURL),true)
+ DEFINES+= -DLIBCURL
+ LIBSPLUTO+= -lcurl
+ THREADS=1 # Asynchronous cURL queries require threads
+endif
+
+# This compile option activates dynamic LDAP CRL fetching
+ifeq ($(USE_LDAP),true)
+ DEFINES+= -DLDAP_VER=$(LDAP_VERSION)
+ LIBSPLUTO+= -lldap -llber
+ THREADS=1 # Asynchronous LDAP queries require threads
+endif
+
+# This compile option activates the use of threads
+ifdef THREADS
+ DEFINES+= -DTHREADS
+ LIBSPLUTO+= -lpthread
+endif
+
+# This compile option activates smartcard support
+ifeq ($(USE_SMARTCARD),true)
+ DEFINES+= -DSMARTCARD
+ ifdef PKCS11_DEFAULT_LIB
+ DEFINES+= -DPKCS11_DEFAULT_LIB=$(PKCS11_DEFAULT_LIB)
+ endif
+ LIBSPLUTO+= -ldl
+endif
+
+# This compile option activates the leak detective
+ifeq ($(USE_LEAK_DETECTIVE),true)
+ DEFINES+= -DLEAK_DETECTIVE
+endif
+
+CPPFLAGS = $(HDRDIRS) $(DEFINES) \
+ -DSHARED_SECRETS_FILE=\"${FINALCONFDIR}/ipsec.secrets\" \
+ -DPOLICYGROUPSDIR=\"${FINALCONFDDIR}/policies\" \
+ -DPERPEERLOGDIR=\"${FINALLOGDIR}/pluto/peer\"
+
+ALLFLAGS = $(CPPFLAGS) $(CFLAGS) $(USERCOMPILE)
+
+ifneq ($(LD_LIBRARY_PATH),)
+ LDFLAGS=-L$(LD_LIBRARY_PATH)
+endif
+
+LIBSADNS = $(FREESWANLIB)
+LIBSADNS += -lresolv # -lefence
+
+# Solaris needs -lsocket -lnsl
+LIBSWHACK = ${FREESWANLIB}
+
+BINNAMEPLUTO = pluto
+BINNAMEWHACK = whack
+BINNAMEADNS = _pluto_adns
+
+RM = /bin/rm
+RMFLAGS = -f
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+# files for a (source) distribution
+
+DISTMISC = CHANGES PLUTO-CONVENTIONS TODO ipsec.secrets Makefile routing.txt \
+ pluto.8 ipsec.secrets.5 .cvsignore
+
+DISTGCRYPT = \
+ gcryptfix.c gcryptfix.h \
+ dsa.c dsa.h \
+ elgamal.c elgamal.h \
+ primegen.c \
+ smallprime.c
+
+DISTSRC = \
+ ac.c ac.h \
+ asn1.c asn1.h \
+ ca.c ca.h \
+ certs.c certs.h \
+ connections.c connections.h \
+ crl.c crl.h \
+ foodgroups.c foodgroups.h \
+ constants.c constants.h \
+ cookie.c cookie.h \
+ crypto.h crypto.c \
+ defs.h defs.c \
+ mp_defs.h mp_defs.c \
+ demux.c demux.h \
+ dnskey.c dnskey.h \
+ fetch.c fetch.h \
+ id.c id.h \
+ ipsec_doi.c ipsec_doi.h \
+ kernel.c kernel.h \
+ kernel_netlink.c kernel_netlink.h \
+ kernel_pfkey.c kernel_pfkey.h \
+ kernel_noklips.c kernel_noklips.h \
+ kernel_alg.c kernel_alg.h \
+ ike_alg.c ike_alg.h \
+ alg_info.c alg_info.h \
+ rcv_whack.c rcv_whack.h \
+ $(IPSECPOLICY_FILES) \
+ log.c log.h \
+ plutomain.c \
+ md2.c md2.h \
+ md5.c md5.h \
+ modecfg.c modecfg.h \
+ ocsp.c ocsp.h \
+ oid.txt oid.pl oid.c oid.h \
+ packet.c packet.h \
+ pem.c pem.h \
+ pgp.c pgp.h \
+ pkcs1.c pkcs1.h \
+ pkcs7.c pkcs7.h \
+ lex.c lex.h \
+ keys.c keys.h \
+ rnd.c rnd.h \
+ server.c server.h \
+ sha1.c sha1.h \
+ smartcard.c smartcard.h \
+ spdb.c spdb.h \
+ state.c state.h \
+ timer.c timer.h \
+ x509.c x509.h \
+ $(DISTGCRYPT) \
+ vendor.c nat_traversal.c virtual.c \
+ adns.c adns.h \
+ whack.c whack.h
+
+DIST = $(DISTMISC) $(DISTSRC)
+
+
+# start of support for DSS/DSA. Not currently used.
+# OBJSGCRYPT = gcryptfix.o dsa.o elgamal.o primegen.o smallprime.o
+OBJSGCRYPT =
+
+OBJSPLUTO = asn1.o connections.o constants.o cookie.o crypto.o defs.o fetch.o foodgroups.o \
+ log.o state.o plutomain.o server.o timer.o oid.o pem.o pgp.o pkcs1.o pkcs7.o x509.o \
+ ca.o certs.o id.o ipsec_doi.o kernel.o $(KERNEL26_OBJS) kernel_pfkey.o mp_defs.o \
+ kernel_noklips.o rcv_whack.o ${IPSECPOLICY_OBJS} demux.o packet.o lex.o keys.o \
+ dnskey.o smartcard.o ac.o rnd.o spdb.o sha1.o md5.o md2.o modecfg.o ocsp.o crl.o \
+ vendor.o nat_traversal.o virtual.o
+
+OBJSADNS = adns.o
+
+OBJSWHACK = whack.o
+
+all: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK)
+programs: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK)
+
+oid.c: oid.txt oid.pl
+ perl oid.pl
+
+oid.h: oid.txt oid.pl
+ perl oid.pl
+
+install: all
+ mkdir -p ${LIBEXECDIR} ${LIBDIR}
+ mkdir -p -m 755 $(CONFDIR)/ipsec.d
+ mkdir -p -m 755 $(CONFDIR)/ipsec.d/cacerts
+ mkdir -p -m 755 $(CONFDIR)/ipsec.d/ocspcerts
+ mkdir -p -m 755 $(CONFDIR)/ipsec.d/certs
+ mkdir -p -m 755 $(CONFDIR)/ipsec.d/acerts
+ mkdir -p -m 755 $(CONFDIR)/ipsec.d/aacerts
+ mkdir -p -m 755 $(CONFDIR)/ipsec.d/crls
+ mkdir -p -m 755 $(CONFDIR)/ipsec.d/reqs
+ mkdir -p -m 700 $(CONFDIR)/ipsec.d/private
+ $(INSTALL) $(INSTBINFLAGS) $(BINNAMEPLUTO) $(BINNAMEWHACK) $(LIBEXECDIR)
+ if $(USE_ADNS) ; then $(INSTALL) $(INSTBINFLAGS) $(BINNAMEADNS) $(LIBDIR) ; fi
+ $(INSTALL) $(INSTMANFLAGS) pluto.8 $(PMANDIR)/ipsec_pluto.8
+ sh ${FREESWANSRCDIR}/packaging/utils/manlink pluto.8 | \
+ while read from to ; \
+ do \
+ ln -s -f ipsec_$$from $(PMANDIR)/$$to; \
+ done
+ $(INSTALL) $(INSTMANFLAGS) ipsec.secrets.5 $(FMANDIR)
+ sh ${FREESWANSRCDIR}/packaging/utils/manlink ipsec.secrets.5 | \
+ while read from to ; \
+ do \
+ ln -s -f $$from $(FMANDIR)/$$to; \
+ done
+
+install_file_list:
+ @echo $(LIBEXECDIR)/$(BINNAMEPLUTO)
+ @if $(USE_ADNS) ; then echo $(LIBDIR)/$(BINNAMEADNS) ; fi
+ @echo $(LIBEXECDIR)/$(BINNAMEWHACK)
+ @echo $(PMANDIR)/ipsec_pluto.8
+ @sh ${FREESWANSRCDIR}/packaging/utils/manlink pluto.8 | \
+ while read from to; \
+ do\
+ echo $(PMANDIR)/$$to; \
+ done
+ @echo $(FMANDIR)/ipsec.secrets.5
+ @sh ${FREESWANSRCDIR}/packaging/utils/manlink ipsec.secrets.5 | \
+ while read from to; \
+ do \
+ echo $(FMANDIR)/$$to; \
+ done
+
+alg_info_test: alg_info_test.o alg_info.o kernel_alg.o ike_alg.o constants.o defs.o log.o db_ops.o crypto.o $(LIBDESLITE) $(FREESWANLIB)
+ $(CC) -o $@ $^ $(LIBSPLUTO)
+
+# alg/libalg.o contains an already resolved object built with
+# additional crypto algos inside.
+OBJSPLUTO:= kernel_alg.o ike_alg.o alg_info.o db_ops.o $(OBJSPLUTO) alg/libalg.o
+# if new alg source is created in alg directory,
+# trigger libalg.o rebuild
+alg/libalg.o: alg alg/Config.ike_alg
+ make -C alg libalg.o
+ touch alg/libalg.o
+
+# helper for creating alg/Make.common
+showdefs:
+ @echo DEFINES=$(DEFINES)
+ @echo CFLAGS=$(CFLAGS)
+ @echo CPPFLAGS=$(CPPFLAGS)
+ @echo COPTS=$(COPTS)
+
+$(BINNAMEPLUTO): $(OBJSPLUTO) $(ALG_LIBS)
+ $(CC) -o $(BINNAMEPLUTO) $(LDFLAGS) $(OBJSPLUTO) $(LIBSPLUTO)
+
+$(BINNAMEADNS): $(OBJSADNS)
+ $(CC) -o $(BINNAMEADNS) $(OBJSADNS) $(LIBSADNS)
+
+$(BINNAMEWHACK): $(OBJSWHACK)
+ $(CC) -o $(BINNAMEWHACK) $(OBJSWHACK) $(LIBSWHACK)
+
+distlist:
+ @echo $(DIST)
+
+# Exuberant Ctags doesn't work if LC_ALL is set to something other than C
+
+CTAGSFLAGS = -N --format=1 # fishy options required for Exuberant Ctags
+
+tags: $(DISTSRC)
+ LC_ALL=C ctags $(CTAGSFLAGS) $(DISTSRC) $(LIBFREESWANDIR)/*.[ch]
+
+TAGS: $(DISTSRC)
+ LC_ALL=C etags $(ETAGSFLAGS) $(DISTSRC) $(LIBFREESWANDIR)/*.[ch]
+
+cleanall: clean
+
+distclean: clean
+
+mostlyclean: clean
+
+realclean: clean
+
+clean:
+ $(RM) $(RMFLAGS) *.core core *~ a.out ktrace.out \
+ $(OBJSPLUTO) $(BINNAMEPLUTO) \
+ $(OBJSWHACK) $(BINNAMEWHACK) \
+ $(OBJSADNS) $(BINNAMEADNS)
+ make -C alg clean
+
+check:
+ echo no checks in lib right now.
+
+checkprograms:
+
+.c.o:
+ $(CC) $(COPTS) $(ALLFLAGS) -c $<
+
+# Gather dependencies caused by explicit #includes within .c files
+#
+# Each .c is assumed to compile into a .o with the corresponding name.
+# Only dependencies on based on "" includes are considered, not <>.
+# Dependencies caused by includes within headers are not noticed.
+# Unlike dependencies generated by the compiler, these include dependencies
+# suppressed by conditional compilation (good, we think).
+# This code can be tricked by embeding #include in comments or
+# vice-versa, but we're among friends.
+
+gatherdeps:
+ @ls $(DISTSRC) | grep '\.c' | sed -e 's/\(.*\)\.c$$/\1.o: \1.c/'
+ @echo
+ @ls $(DISTSRC) | grep '\.c' | xargs grep '^#[ ]*include[ ]*"' | \
+ sed -e 's/\.c:#[ ]*include[ ]*"/.o: /' -e 's/".*//'
+
+# Dependencies generated by "make gatherdeps":
+
+ac.o: ac.c
+adns.o: adns.c
+alg_info.o: alg_info.c
+asn1.o: asn1.c
+ca.o: ca.c
+certs.o: certs.c
+connections.o: connections.c
+constants.o: constants.c
+cookie.o: cookie.c
+crl.o: crl.c
+crypto.o: crypto.c
+defs.o: defs.c
+demux.o: demux.c
+dnskey.o: dnskey.c
+dsa.o: dsa.c
+elgamal.o: elgamal.c
+fetch.o: fetch.c
+foodgroups.o: foodgroups.c
+gcryptfix.o: gcryptfix.c
+id.o: id.c
+ike_alg.o: ike_alg.c
+ipsec_doi.o: ipsec_doi.c
+kernel.o: kernel.c
+kernel_alg.o: kernel_alg.c
+kernel_netlink.o: kernel_netlink.c
+kernel_noklips.o: kernel_noklips.c
+kernel_pfkey.o: kernel_pfkey.c
+keys.o: keys.c
+lex.o: lex.c
+log.o: log.c
+md2.o: md2.c
+md5.o: md5.c
+modecfg.o: modecfg.c
+mp_defs.o: mp_defs.c
+nat_traversal.o: nat_traversal.c
+ocsp.o: ocsp.c
+oid.o: oid.c
+packet.o: packet.c
+pem.o: pem.c
+pgp.o: pgp.c
+pkcs1.o: pkcs1.c
+pkcs7.o: pkcs7.c
+plutomain.o: plutomain.c
+primegen.o: primegen.c
+rcv_whack.o: rcv_whack.c
+rnd.o: rnd.c
+server.o: server.c
+sha1.o: sha1.c
+smallprime.o: smallprime.c
+smartcard.o: smartcard.c
+spdb.o: spdb.c
+state.o: state.c
+timer.o: timer.c
+vendor.o: vendor.c
+virtual.o: virtual.c
+whack.o: whack.c
+x509.o: x509.c
+
+ac.o: constants.h
+ac.o: defs.h
+ac.o: asn1.h
+ac.o: oid.h
+ac.o: ac.h
+ac.o: x509.h
+ac.o: crl.h
+ac.o: ca.h
+ac.o: certs.h
+ac.o: log.h
+ac.o: whack.h
+ac.o: fetch.h
+adns.o: constants.h
+adns.o: adns.h
+alg_info.o: alg_info.h
+alg_info.o: constants.h
+alg_info.o: defs.h
+alg_info.o: log.h
+alg_info.o: whack.h
+alg_info.o: sha1.h
+alg_info.o: md5.h
+alg_info.o: crypto.h
+alg_info.o: kernel_alg.h
+alg_info.o: ike_alg.h
+asn1.o: constants.h
+asn1.o: defs.h
+asn1.o: mp_defs.h
+asn1.o: asn1.h
+asn1.o: oid.h
+asn1.o: log.h
+ca.o: constants.h
+ca.o: defs.h
+ca.o: log.h
+ca.o: x509.h
+ca.o: ca.h
+ca.o: certs.h
+ca.o: whack.h
+ca.o: fetch.h
+certs.o: constants.h
+certs.o: defs.h
+certs.o: log.h
+certs.o: asn1.h
+certs.o: id.h
+certs.o: x509.h
+certs.o: pgp.h
+certs.o: pem.h
+certs.o: certs.h
+certs.o: pkcs1.h
+connections.o: kameipsec.h
+connections.o: constants.h
+connections.o: defs.h
+connections.o: id.h
+connections.o: x509.h
+connections.o: ca.h
+connections.o: crl.h
+connections.o: pgp.h
+connections.o: certs.h
+connections.o: ac.h
+connections.o: smartcard.h
+connections.o: fetch.h
+connections.o: connections.h
+connections.o: foodgroups.h
+connections.o: demux.h
+connections.o: state.h
+connections.o: timer.h
+connections.o: ipsec_doi.h
+connections.o: server.h
+connections.o: kernel.h
+connections.o: log.h
+connections.o: keys.h
+connections.o: adns.h
+connections.o: dnskey.h
+connections.o: whack.h
+connections.o: alg_info.h
+connections.o: ike_alg.h
+connections.o: kernel_alg.h
+connections.o: nat_traversal.h
+connections.o: virtual.h
+constants.o: constants.h
+constants.o: defs.h
+constants.o: log.h
+constants.o: packet.h
+cookie.o: constants.h
+cookie.o: defs.h
+cookie.o: sha1.h
+cookie.o: rnd.h
+cookie.o: cookie.h
+crl.o: constants.h
+crl.o: defs.h
+crl.o: log.h
+crl.o: asn1.h
+crl.o: oid.h
+crl.o: x509.h
+crl.o: crl.h
+crl.o: ca.h
+crl.o: certs.h
+crl.o: keys.h
+crl.o: whack.h
+crl.o: fetch.h
+crl.o: sha1.h
+crypto.o: constants.h
+crypto.o: defs.h
+crypto.o: state.h
+crypto.o: log.h
+crypto.o: md5.h
+crypto.o: sha1.h
+crypto.o: crypto.h
+crypto.o: alg_info.h
+crypto.o: ike_alg.h
+defs.o: constants.h
+defs.o: defs.h
+defs.o: log.h
+defs.o: whack.h
+demux.o: constants.h
+demux.o: defs.h
+demux.o: cookie.h
+demux.o: connections.h
+demux.o: state.h
+demux.o: packet.h
+demux.o: md5.h
+demux.o: sha1.h
+demux.o: crypto.h
+demux.o: ike_alg.h
+demux.o: log.h
+demux.o: demux.h
+demux.o: ipsec_doi.h
+demux.o: timer.h
+demux.o: whack.h
+demux.o: server.h
+demux.o: nat_traversal.h
+demux.o: vendor.h
+demux.o: modecfg.h
+dnskey.o: constants.h
+dnskey.o: adns.h
+dnskey.o: defs.h
+dnskey.o: log.h
+dnskey.o: id.h
+dnskey.o: connections.h
+dnskey.o: keys.h
+dnskey.o: dnskey.h
+dnskey.o: packet.h
+dnskey.o: timer.h
+dsa.o: constants.h
+dsa.o: defs.h
+dsa.o: log.h
+dsa.o: rnd.h
+dsa.o: gcryptfix.h
+dsa.o: dsa.h
+elgamal.o: constants.h
+elgamal.o: defs.h
+elgamal.o: log.h
+elgamal.o: rnd.h
+elgamal.o: gcryptfix.h
+elgamal.o: elgamal.h
+fetch.o: constants.h
+fetch.o: defs.h
+fetch.o: log.h
+fetch.o: id.h
+fetch.o: asn1.h
+fetch.o: pem.h
+fetch.o: x509.h
+fetch.o: ca.h
+fetch.o: whack.h
+fetch.o: ocsp.h
+fetch.o: crl.h
+fetch.o: fetch.h
+foodgroups.o: constants.h
+foodgroups.o: defs.h
+foodgroups.o: connections.h
+foodgroups.o: foodgroups.h
+foodgroups.o: kernel.h
+foodgroups.o: lex.h
+foodgroups.o: log.h
+foodgroups.o: whack.h
+gcryptfix.o: constants.h
+gcryptfix.o: defs.h
+gcryptfix.o: log.h
+gcryptfix.o: rnd.h
+gcryptfix.o: gcryptfix.h
+id.o: constants.h
+id.o: defs.h
+id.o: id.h
+id.o: log.h
+id.o: connections.h
+id.o: packet.h
+id.o: whack.h
+ike_alg.o: constants.h
+ike_alg.o: defs.h
+ike_alg.o: sha1.h
+ike_alg.o: md5.h
+ike_alg.o: crypto.h
+ike_alg.o: state.h
+ike_alg.o: packet.h
+ike_alg.o: log.h
+ike_alg.o: whack.h
+ike_alg.o: spdb.h
+ike_alg.o: alg_info.h
+ike_alg.o: ike_alg.h
+ike_alg.o: db_ops.h
+ike_alg.o: connections.h
+ike_alg.o: kernel.h
+ipsec_doi.o: constants.h
+ipsec_doi.o: defs.h
+ipsec_doi.o: mp_defs.h
+ipsec_doi.o: state.h
+ipsec_doi.o: id.h
+ipsec_doi.o: x509.h
+ipsec_doi.o: crl.h
+ipsec_doi.o: ca.h
+ipsec_doi.o: certs.h
+ipsec_doi.o: smartcard.h
+ipsec_doi.o: connections.h
+ipsec_doi.o: keys.h
+ipsec_doi.o: packet.h
+ipsec_doi.o: demux.h
+ipsec_doi.o: adns.h
+ipsec_doi.o: dnskey.h
+ipsec_doi.o: kernel.h
+ipsec_doi.o: log.h
+ipsec_doi.o: cookie.h
+ipsec_doi.o: server.h
+ipsec_doi.o: spdb.h
+ipsec_doi.o: timer.h
+ipsec_doi.o: rnd.h
+ipsec_doi.o: ipsec_doi.h
+ipsec_doi.o: whack.h
+ipsec_doi.o: fetch.h
+ipsec_doi.o: pkcs7.h
+ipsec_doi.o: asn1.h
+ipsec_doi.o: sha1.h
+ipsec_doi.o: md5.h
+ipsec_doi.o: crypto.h
+ipsec_doi.o: vendor.h
+ipsec_doi.o: alg_info.h
+ipsec_doi.o: ike_alg.h
+ipsec_doi.o: kernel_alg.h
+ipsec_doi.o: nat_traversal.h
+ipsec_doi.o: virtual.h
+kernel.o: kameipsec.h
+kernel.o: constants.h
+kernel.o: defs.h
+kernel.o: rnd.h
+kernel.o: id.h
+kernel.o: connections.h
+kernel.o: state.h
+kernel.o: timer.h
+kernel.o: kernel.h
+kernel.o: kernel_netlink.h
+kernel.o: kernel_pfkey.h
+kernel.o: kernel_noklips.h
+kernel.o: log.h
+kernel.o: ca.h
+kernel.o: server.h
+kernel.o: whack.h
+kernel.o: keys.h
+kernel.o: packet.h
+kernel.o: nat_traversal.h
+kernel.o: alg_info.h
+kernel.o: kernel_alg.h
+kernel_alg.o: constants.h
+kernel_alg.o: defs.h
+kernel_alg.o: connections.h
+kernel_alg.o: state.h
+kernel_alg.o: packet.h
+kernel_alg.o: spdb.h
+kernel_alg.o: kernel.h
+kernel_alg.o: kernel_alg.h
+kernel_alg.o: alg_info.h
+kernel_alg.o: log.h
+kernel_alg.o: whack.h
+kernel_alg.o: db_ops.h
+kernel_netlink.o: kameipsec.h
+kernel_netlink.o: linux26/rtnetlink.h
+kernel_netlink.o: linux26/xfrm.h
+kernel_netlink.o: constants.h
+kernel_netlink.o: defs.h
+kernel_netlink.o: kernel.h
+kernel_netlink.o: kernel_netlink.h
+kernel_netlink.o: kernel_pfkey.h
+kernel_netlink.o: log.h
+kernel_netlink.o: whack.h
+kernel_netlink.o: kernel_alg.h
+kernel_noklips.o: constants.h
+kernel_noklips.o: defs.h
+kernel_noklips.o: kernel.h
+kernel_noklips.o: kernel_noklips.h
+kernel_noklips.o: log.h
+kernel_noklips.o: whack.h
+kernel_pfkey.o: constants.h
+kernel_pfkey.o: defs.h
+kernel_pfkey.o: kernel.h
+kernel_pfkey.o: kernel_pfkey.h
+kernel_pfkey.o: log.h
+kernel_pfkey.o: whack.h
+kernel_pfkey.o: demux.h
+kernel_pfkey.o: nat_traversal.h
+kernel_pfkey.o: alg_info.h
+kernel_pfkey.o: kernel_alg.h
+keys.o: constants.h
+keys.o: defs.h
+keys.o: mp_defs.h
+keys.o: id.h
+keys.o: x509.h
+keys.o: pgp.h
+keys.o: certs.h
+keys.o: smartcard.h
+keys.o: connections.h
+keys.o: state.h
+keys.o: lex.h
+keys.o: keys.h
+keys.o: adns.h
+keys.o: dnskey.h
+keys.o: log.h
+keys.o: whack.h
+keys.o: timer.h
+keys.o: fetch.h
+keys.o: nat_traversal.h
+lex.o: constants.h
+lex.o: defs.h
+lex.o: log.h
+lex.o: whack.h
+lex.o: lex.h
+log.o: constants.h
+log.o: defs.h
+log.o: log.h
+log.o: server.h
+log.o: state.h
+log.o: connections.h
+log.o: kernel.h
+log.o: whack.h
+log.o: timer.h
+md2.o: md2.h
+md5.o: md5.h
+modecfg.o: constants.h
+modecfg.o: defs.h
+modecfg.o: state.h
+modecfg.o: demux.h
+modecfg.o: timer.h
+modecfg.o: ipsec_doi.h
+modecfg.o: log.h
+modecfg.o: md5.h
+modecfg.o: sha1.h
+modecfg.o: crypto.h
+modecfg.o: modecfg.h
+modecfg.o: whack.h
+mp_defs.o: constants.h
+mp_defs.o: defs.h
+mp_defs.o: mp_defs.h
+mp_defs.o: log.h
+nat_traversal.o: constants.h
+nat_traversal.o: defs.h
+nat_traversal.o: log.h
+nat_traversal.o: server.h
+nat_traversal.o: state.h
+nat_traversal.o: connections.h
+nat_traversal.o: packet.h
+nat_traversal.o: demux.h
+nat_traversal.o: kernel.h
+nat_traversal.o: whack.h
+nat_traversal.o: timer.h
+nat_traversal.o: cookie.h
+nat_traversal.o: sha1.h
+nat_traversal.o: md5.h
+nat_traversal.o: crypto.h
+nat_traversal.o: vendor.h
+nat_traversal.o: ike_alg.h
+nat_traversal.o: nat_traversal.h
+ocsp.o: constants.h
+ocsp.o: defs.h
+ocsp.o: log.h
+ocsp.o: x509.h
+ocsp.o: crl.h
+ocsp.o: ca.h
+ocsp.o: rnd.h
+ocsp.o: asn1.h
+ocsp.o: certs.h
+ocsp.o: smartcard.h
+ocsp.o: oid.h
+ocsp.o: whack.h
+ocsp.o: pkcs1.h
+ocsp.o: keys.h
+ocsp.o: fetch.h
+ocsp.o: ocsp.h
+oid.o: oid.h
+packet.o: constants.h
+packet.o: defs.h
+packet.o: log.h
+packet.o: packet.h
+packet.o: whack.h
+pem.o: constants.h
+pem.o: defs.h
+pem.o: log.h
+pem.o: md5.h
+pem.o: whack.h
+pem.o: pem.h
+pgp.o: constants.h
+pgp.o: defs.h
+pgp.o: mp_defs.h
+pgp.o: log.h
+pgp.o: id.h
+pgp.o: pgp.h
+pgp.o: certs.h
+pgp.o: md5.h
+pgp.o: whack.h
+pgp.o: pkcs1.h
+pgp.o: keys.h
+pkcs1.o: constants.h
+pkcs1.o: defs.h
+pkcs1.o: mp_defs.h
+pkcs1.o: asn1.h
+pkcs1.o: oid.h
+pkcs1.o: log.h
+pkcs1.o: pkcs1.h
+pkcs1.o: md2.h
+pkcs1.o: md5.h
+pkcs1.o: sha1.h
+pkcs1.o: rnd.h
+pkcs7.o: constants.h
+pkcs7.o: defs.h
+pkcs7.o: asn1.h
+pkcs7.o: oid.h
+pkcs7.o: log.h
+pkcs7.o: x509.h
+pkcs7.o: certs.h
+pkcs7.o: pkcs7.h
+pkcs7.o: rnd.h
+plutomain.o: constants.h
+plutomain.o: defs.h
+plutomain.o: id.h
+plutomain.o: ca.h
+plutomain.o: certs.h
+plutomain.o: ac.h
+plutomain.o: connections.h
+plutomain.o: foodgroups.h
+plutomain.o: packet.h
+plutomain.o: demux.h
+plutomain.o: server.h
+plutomain.o: kernel.h
+plutomain.o: log.h
+plutomain.o: keys.h
+plutomain.o: adns.h
+plutomain.o: dnskey.h
+plutomain.o: rnd.h
+plutomain.o: state.h
+plutomain.o: ipsec_doi.h
+plutomain.o: ocsp.h
+plutomain.o: crl.h
+plutomain.o: fetch.h
+plutomain.o: sha1.h
+plutomain.o: md5.h
+plutomain.o: crypto.h
+plutomain.o: virtual.h
+plutomain.o: nat_traversal.h
+primegen.o: constants.h
+primegen.o: defs.h
+primegen.o: log.h
+primegen.o: rnd.h
+primegen.o: gcryptfix.h
+rcv_whack.o: constants.h
+rcv_whack.o: defs.h
+rcv_whack.o: id.h
+rcv_whack.o: ca.h
+rcv_whack.o: certs.h
+rcv_whack.o: ac.h
+rcv_whack.o: smartcard.h
+rcv_whack.o: connections.h
+rcv_whack.o: foodgroups.h
+rcv_whack.o: whack.h
+rcv_whack.o: packet.h
+rcv_whack.o: demux.h
+rcv_whack.o: state.h
+rcv_whack.o: ipsec_doi.h
+rcv_whack.o: kernel.h
+rcv_whack.o: rcv_whack.h
+rcv_whack.o: log.h
+rcv_whack.o: keys.h
+rcv_whack.o: adns.h
+rcv_whack.o: dnskey.h
+rcv_whack.o: server.h
+rcv_whack.o: fetch.h
+rcv_whack.o: ocsp.h
+rcv_whack.o: crl.h
+rcv_whack.o: kernel_alg.h
+rcv_whack.o: ike_alg.h
+rnd.o: sha1.h
+rnd.o: constants.h
+rnd.o: defs.h
+rnd.o: rnd.h
+rnd.o: log.h
+rnd.o: timer.h
+server.o: constants.h
+server.o: defs.h
+server.o: state.h
+server.o: connections.h
+server.o: kernel.h
+server.o: log.h
+server.o: server.h
+server.o: timer.h
+server.o: packet.h
+server.o: demux.h
+server.o: rcv_whack.h
+server.o: rcv_info.h
+server.o: keys.h
+server.o: adns.h
+server.o: dnskey.h
+server.o: whack.h
+server.o: kameipsec.h
+server.o: nat_traversal.h
+sha1.o: sha1.h
+smallprime.o: constants.h
+smallprime.o: defs.h
+smallprime.o: gcryptfix.h
+smartcard.o: constants.h
+smartcard.o: rsaref/unix.h
+smartcard.o: rsaref/pkcs11.h
+smartcard.o: defs.h
+smartcard.o: mp_defs.h
+smartcard.o: log.h
+smartcard.o: x509.h
+smartcard.o: ca.h
+smartcard.o: certs.h
+smartcard.o: keys.h
+smartcard.o: smartcard.h
+smartcard.o: whack.h
+smartcard.o: fetch.h
+spdb.o: constants.h
+spdb.o: defs.h
+spdb.o: id.h
+spdb.o: connections.h
+spdb.o: state.h
+spdb.o: packet.h
+spdb.o: keys.h
+spdb.o: kernel.h
+spdb.o: log.h
+spdb.o: spdb.h
+spdb.o: whack.h
+spdb.o: sha1.h
+spdb.o: md5.h
+spdb.o: crypto.h
+spdb.o: alg_info.h
+spdb.o: kernel_alg.h
+spdb.o: ike_alg.h
+spdb.o: db_ops.h
+spdb.o: nat_traversal.h
+state.o: constants.h
+state.o: defs.h
+state.o: connections.h
+state.o: state.h
+state.o: kernel.h
+state.o: log.h
+state.o: packet.h
+state.o: keys.h
+state.o: rnd.h
+state.o: timer.h
+state.o: whack.h
+state.o: demux.h
+state.o: ipsec_doi.h
+state.o: sha1.h
+state.o: md5.h
+state.o: crypto.h
+timer.o: constants.h
+timer.o: defs.h
+timer.o: connections.h
+timer.o: state.h
+timer.o: demux.h
+timer.o: ipsec_doi.h
+timer.o: kernel.h
+timer.o: server.h
+timer.o: log.h
+timer.o: rnd.h
+timer.o: timer.h
+timer.o: whack.h
+timer.o: nat_traversal.h
+vendor.o: constants.h
+vendor.o: defs.h
+vendor.o: log.h
+vendor.o: md5.h
+vendor.o: connections.h
+vendor.o: packet.h
+vendor.o: demux.h
+vendor.o: whack.h
+vendor.o: vendor.h
+vendor.o: kernel.h
+vendor.o: nat_traversal.h
+virtual.o: constants.h
+virtual.o: defs.h
+virtual.o: log.h
+virtual.o: connections.h
+virtual.o: whack.h
+virtual.o: virtual.h
+whack.o: constants.h
+whack.o: defs.h
+whack.o: whack.h
+x509.o: constants.h
+x509.o: defs.h
+x509.o: mp_defs.h
+x509.o: log.h
+x509.o: id.h
+x509.o: asn1.h
+x509.o: oid.h
+x509.o: pkcs1.h
+x509.o: x509.h
+x509.o: crl.h
+x509.o: ca.h
+x509.o: certs.h
+x509.o: keys.h
+x509.o: whack.h
+x509.o: fetch.h
+x509.o: ocsp.h
+x509.o: sha1.h
diff --git a/programs/pluto/PLUTO-CONVENTIONS b/programs/pluto/PLUTO-CONVENTIONS
new file mode 100644
index 000000000..5288dd2bb
--- /dev/null
+++ b/programs/pluto/PLUTO-CONVENTIONS
@@ -0,0 +1,127 @@
+Notes on Pluto Conventions
+==========================
+
+RCSID $Id: PLUTO-CONVENTIONS,v 1.1 2004/03/15 20:35:28 as Exp $
+
+Pluto has its own stylistic conventions. They are fairly easily
+inferred by reading the code.
+
+- sample formatting:
+
+void
+fun(char *s)
+{
+ if (s == NULL)
+ {
+ return "";
+ }
+ else
+ {
+ switch (*s)
+ {
+ default:
+ s++;
+ /* fall through */
+ case '\0':
+ return s;
+ }
+ }
+}
+
+- a function definition has its function identifier at the margin
+
+- indentation is in steps of 4 columns (tabstops are every 8 columns)
+
+- try to keep lines shorter than 80 columns
+
+- space should be canonical:
+ + no line should have trailing whitespace
+ + leading whitespace should use tabs where possible
+ + indentation should be precise
+ + there should be no empty lines at the end of a file.
+
+- braces go on their own line, indented the same as the start of what they are part of
+
+- switch labels are indented the same as the enclosing braces
+
+- if a case falls through, say so explicitly
+
+- spaces follow control flow reserved words (but not function names)
+
+- the operand of return need not be parenthesized
+
+- be careful with types. For example, use size_t and ssize_t.
+ Use const wherever possible.
+
+- we pretend that C has a strong boolean type.
+ We actually define bool with constants TRUE and FALSE.
+ Other types cannot be used as the complete expression in a test.
+ Hence:
+ if (s == NULL)
+ One exception: lset_t values can be treated as booleans
+ (technically they are, in the original sense of the word)
+
+
+- memsetting a pointer to binary zero is not guaranteed to make it NULL
+
+- side-effects of expressions are to be avoided.
+ BAD: if (i++ == 9)
+ OK: i++;
+
+- variables are to have as small a scope as is possible.
+ Move definitions into inner blocks whenever possible.
+ Often initializing definitions become possible and are clearer.
+
+- within a block that has declarations, separate the declarations from
+ the other statements with a blank line.
+
+- "magic numbers" are suspect. Most integers in code stand for something.
+ They should be given a name, and that name used consistently.
+
+- don't use malloc/free -- use the wrappers (see defs.h)
+
+- it is good to put comments on #else and #endif to show what
+ they match with. I use ! to indicate the sense of the test:
+ #ifdef CRUD
+ #else /* !CRUD */
+ #endif /* !CRUD */
+
+ #ifndef CRUD
+ #else /* CRUD */
+ #endif /* CRUD */
+
+- all functions and variables that are exported from a .c file should
+ be declared in that file's header file. Because the .c includes the
+ header, the declaration and the definition will be checked by the
+ compiler. There is almost no excuse for the "extern" keyword
+ in a .c file.
+
+- when lines are too long and expressions are to be broken, try to
+ break just before a binary operator. The outermost binary operator
+ is preferred. This is perhaps the most unconventional convention.
+ It allows the structure of code to be evident from a scan of the
+ left margin. Example:
+ if (next_step == vos_his_client
+ && sameaddr(&c->spd.that.host_addr, &his_client))
+ next_step = vos_done;
+ and
+ p = oppo_instantiate(p, &c->spd.that.host_addr, &c->spd.that.id
+ , NULL, &our_client, &his_client);
+ Note the different indentation of the continuations. The continuation
+ of a control flow statement is not indented but other continuations are.
+
+- Never put two statements on one line.
+ REALLY BAD: if (cat);
+ Exception: some macro definitions.
+
+- C preprocessor macros are implemented by a kind of textual substitution.
+ Be sure to put parentheses around references to macro arguments and
+ around the whole macro body. If the body is meant to be a statement,
+ put braces around it instead.
+
+ #define RETURN_STF_FAILURE(f) \
+ { int r = (f); if (r != NOTHING_WRONG) return STF_FAIL + r; }
+
+- adding #include statements adds dependencies. The Makefile should be
+ changed to reflect them. Target "makedepend" will try to list dependencies
+ in a way suitable for pasting into Makefile
diff --git a/programs/pluto/TODO b/programs/pluto/TODO
new file mode 100644
index 000000000..7db4a9ebc
--- /dev/null
+++ b/programs/pluto/TODO
@@ -0,0 +1,129 @@
+Pluto TODO list
+===============
+RCSID $Id: TODO,v 1.1 2004/03/15 20:35:28 as Exp $
+
+- should all log entries that are for errors say ERROR?
+
+- Add a "plug-in" facility so that others can add features without
+ changing the mainline code. This is how X509/LDAP/biometric stuff
+ might be added.
+
+- (internal change only) routines for outputting payloads should plug
+ "np" into the previous payload so that a payload generating routine
+ need not know what the next payload will be. This may be more bother
+ than it is worth.
+
+- notifications, in and out
+ + delete
+ + first contact
+ + last contact? (not part of drafts, but would be nice)
+
+- Make DNS usage for asynchronous (non-blocking)
+ + looking up KEY and TXT records during negotiation
+ + perhaps not for whack command arguments and ipsec.secrets since the
+ library code uses gethostbyname
+
+- check that ipsec auto and whack to agree on what is worth reporting
+
+- Should Pluto (rather than ipsec manual) install %passthrough conns?
+ That way Pluto would know of them.
+
+- For responding to Road Warriors, how can we decide if the RW has
+ gone away? The rekeying event is perhaps too imprecise. Even if
+ rekeying event is good enough, how do we know if the route should be
+ torn down? Perhaps limiting a Phase 1 ID to one IP address would
+ help (limiting a client subnet to one peer already helps). Perhaps
+ (in some rate-limited way) we can take an ICMP host unreachable
+ as a hint to do some authenticated and reliable probe.
+
+- it is annoying that Pluto and auto have different models for public keys.
+ + auto specifies one per connection
+ + Pluto allows one to be specified per id
+ Two connections with the same id are going to use the same key:
+ the one of the last conn to be added!
+
+ I think auto ought to be fixed. It is hard for Pluto to warn when
+ there is a conflict since the deletion of a connection doesn't
+ prompt auto to tell pluto to delete the public key.
+
+- different connections with the same host IP addresses are randomly
+ interchangeable until the ID payload is received. At least for the
+ Responder case (and eventually for the opportunistic Initiator).
+ Worse, all Road Warriors must be considered to have the
+ indistinguishable IP addresses. This affects ISAKMP SA negotiation.
+ Currently, there is little flexibility in this negotiation, so the
+ problem is limited to the specification of acceptable authentication
+ method(s). Correct, but more work than seems worthwhile, would be
+ to select the conn based on what is proposed.
+
+ Warning about such confusion at connection definition time isn't great
+ because there is no confusion when explicitly initiated (a particular
+ conn is specified). Warning for a Road Warrior conn is possible
+ since it cannot be initiated (and has been implemented).
+
+- characterize and ameliorate DOS attacks. Lots of rate limiting.
+
+- look at John Denker's wish list: http://www.quintillion.com/moat/wish.list
+
+- use of random numbers needs to be audited.
+
+- unknown (not just unimplemented) transforms cause a negotiation to
+ fail. Only the transform should be rejected.
+
+- we need better policy control. Our present flags need to be
+ modulated (forbid, allow, offer, require)
+
+- HS will specify how --copyright and --version should behave
+
+- HS will initiate project-wide terminology replacing ISAKMP SA, IPSEC
+ SA, Protection Suite, Phase 1, Main Mode, Phase 2, Quick Mode, ...
+ Simplicity and clarity will be a goal.
+
+- interface discovery ought to match what is specified in ipsec.conf.
+ This probably means grokking /proc/net/ipsec_tncfg. Documented in
+ ipsec_tncfg(5). This won't do for Hugh's debugging setup.
+
+
+Protocol Issues
+===============
+
+Notification and delete payloads seem to be "escape hatches" for the
+protocols. As such, anything implemented using them seems to be
+kludged without being well designed or well situated or well
+constrained in the protocols. Often the precise meaning (if any) or
+usage is under specified. An implementation is allowed to ignore
+them, so they cannot really matter (but they too often do). Their
+specification ought to be scrutinized by a protocol guru.
+
+Any extra payload in last main mode message is not protected (not
+authenticated by hash).
+
+Should notification payloads be interpreted before or after the normal
+payloads (i.e. understood in the context of, executed in the context of).
+
+What is the precise result of an INITIAL_CONNECTION? What is a
+"system" (eg. does Phase 1 Identity count)? What is "earlier" or
+"before" (simultaneous negotiation is possible, with time being only a
+partial order)? Could it be used for FINAL_CONTACT (needed too)?
+
+Blasting out a pile of UDP messages, especially to a particular
+destination, is likely to provoke message loss. The exchanges are
+just that, so they individually are self-throttling. But what about
+multiple exchanges simultaneously? What about notifications (example:
+when shutting down, a flurry of delete notifications are likely).
+Should the RFCs be designed to protect against this problem?
+
+draft-jenkins-ipsec-rekeying-03.txt rekeying is way too complicated.
+Our solution looks sound and simple (we have the Responder install the
+incoming IPSEC SA before sending its first reply). In "2.2.1.4
+Responder Pre-Set-up Security Hole", the draft claims that setting up
+the IPSEC SA early leaves the Responder open to replay attacks. I
+think that this is wrong: the Message Id, since it must not be reused,
+serves to prove that this isn't a replay.
+
+The details for notification messages suggested by
+draft-ietf-ipsec-notifymsg-02.txt are over-complicated, just to make
+them machine-comprehensible. I think this is over-engineering,
+justified only if another level of negotiation is contemplated (ugh!).
+Plain text is probably sufficient for informing humans (I admit that
+there is a problem with I18N).
diff --git a/programs/pluto/ac.c b/programs/pluto/ac.c
new file mode 100644
index 000000000..bcf5f80d1
--- /dev/null
+++ b/programs/pluto/ac.c
@@ -0,0 +1,1018 @@
+/* Support of X.509 attribute certificates
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2003 Martin Berner, Lukas Suter
+ *
+ * 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: ac.c,v 1.12 2005/12/06 22:49:32 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "asn1.h"
+#include "oid.h"
+#include "ac.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certs.h"
+#include "log.h"
+#include "whack.h"
+#include "fetch.h"
+
+/* chained list of X.509 attribute certificates */
+
+static x509acert_t *x509acerts = NULL;
+
+/* chained list of ietfAttributes */
+
+static ietfAttrList_t *ietfAttributes = NULL;
+
+/* ASN.1 definition of ietfAttrSyntax */
+
+static const asn1Object_t ietfAttrSyntaxObjects[] =
+{
+ { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_BODY }, /* 1 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
+ { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
+ { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 4 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
+ { 2, "oid", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 6 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
+ { 2, "string", ASN1_UTF8STRING, ASN1_OPT |
+ ASN1_BODY }, /* 8 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */
+};
+
+#define IETF_ATTR_OCTETS 4
+#define IETF_ATTR_OID 6
+#define IETF_ATTR_STRING 8
+#define IETF_ATTR_ROOF 11
+
+/* ASN.1 definition of roleSyntax */
+
+static const asn1Object_t roleSyntaxObjects[] =
+{
+ { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_OBJ }, /* 1 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
+ { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ } /* 3 */
+};
+
+#define ROLE_ROOF 4
+
+/* ASN.1 definition of an X509 attribute certificate */
+
+static const asn1Object_t acObjects[] =
+{
+ { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "version", ASN1_INTEGER, ASN1_DEF |
+ ASN1_BODY }, /* 2 */
+ { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
+ { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
+ { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */
+ { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 7 */
+ { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
+ { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT |
+ ASN1_OBJ }, /* 10 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
+ { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */
+ { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13*/
+ { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 14 */
+ { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15*/
+ { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
+ { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */
+ { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_OBJ }, /* 19 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
+ { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */
+ { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
+ { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */
+ { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */
+ { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 25 */
+ { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
+ { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */
+ { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */
+ { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */
+ { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 31 */
+ { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */
+ { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */
+ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */
+ { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */
+ { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */
+ { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */
+ { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */
+ { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */
+ { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */
+ { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */
+ { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */
+ { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */
+ { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */
+ { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */
+ { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */
+ { 4, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 50 */
+ { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 54 */
+};
+
+#define AC_OBJ_CERTIFICATE 0
+#define AC_OBJ_CERTIFICATE_INFO 1
+#define AC_OBJ_VERSION 2
+#define AC_OBJ_HOLDER_ISSUER 5
+#define AC_OBJ_HOLDER_SERIAL 6
+#define AC_OBJ_ENTITY_NAME 10
+#define AC_OBJ_ISSUER_NAME 19
+#define AC_OBJ_ISSUER 23
+#define AC_OBJ_SIG_ALG 35
+#define AC_OBJ_SERIAL_NUMBER 36
+#define AC_OBJ_NOT_BEFORE 38
+#define AC_OBJ_NOT_AFTER 39
+#define AC_OBJ_ATTRIBUTE_TYPE 42
+#define AC_OBJ_ATTRIBUTE_VALUE 44
+#define AC_OBJ_EXTN_ID 49
+#define AC_OBJ_CRITICAL 50
+#define AC_OBJ_EXTN_VALUE 51
+#define AC_OBJ_ALGORITHM 53
+#define AC_OBJ_SIGNATURE 54
+#define AC_OBJ_ROOF 55
+
+const x509acert_t empty_ac = {
+ NULL , /* *next */
+ 0 , /* installed */
+ { NULL, 0 }, /* certificate */
+ { NULL, 0 }, /* certificateInfo */
+ 1 , /* version */
+ /* holder */
+ /* baseCertificateID */
+ { NULL, 0 }, /* holderIssuer */
+ { NULL, 0 }, /* holderSerial */
+ /* entityName */
+ { NULL, 0 }, /* generalNames */
+ /* v2Form */
+ { NULL, 0 }, /* issuerName */
+ /* signature */
+ OID_UNKNOWN, /* sigAlg */
+ { NULL, 0 }, /* serialNumber */
+ /* attrCertValidityPeriod */
+ 0 , /* notBefore */
+ 0 , /* notAfter */
+ /* attributes */
+ NULL , /* charging */
+ NULL , /* groups */
+ /* extensions */
+ { NULL, 0 }, /* authKeyID */
+ { NULL, 0 }, /* authKeySerialNumber */
+ FALSE , /* noRevAvail */
+ /* signatureAlgorithm */
+ OID_UNKNOWN, /* algorithm */
+ { NULL, 0 }, /* signature */
+};
+
+
+/* compare two ietfAttributes, returns zero if a equals b
+ * negative/positive if a is earlier/later in the alphabet than b
+ */
+static int
+cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b)
+{
+ int cmp_len, len, cmp_value;
+
+ /* cannot compare OID with STRING or OCTETS attributes */
+ if (a->kind == IETF_ATTRIBUTE_OID && b->kind != IETF_ATTRIBUTE_OID)
+ return 1;
+
+ cmp_len = a->value.len - b->value.len;
+ len = (cmp_len < 0)? a->value.len : b->value.len;
+ cmp_value = memcmp(a->value.ptr, b->value.ptr, len);
+
+ return (cmp_value == 0)? cmp_len : cmp_value;
+}
+
+/*
+ * add an ietfAttribute to the chained list
+ */
+static ietfAttr_t*
+add_ietfAttr(ietfAttr_t *attr)
+{
+ ietfAttrList_t **listp = &ietfAttributes;
+ ietfAttrList_t *list = *listp;
+ int cmp = -1;
+
+ while (list != NULL)
+ {
+ cmp = cmp_ietfAttr(attr, list->attr);
+ if (cmp <= 0)
+ break;
+ listp = &list->next;
+ list = *listp;
+ }
+
+ if (cmp == 0)
+ {
+ /* attribute already exists, increase count */
+ pfree(attr);
+ list->attr->count++;
+ return list->attr;
+ }
+ else
+ {
+ ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
+
+ /* new attribute, unshare value */
+ attr->value.ptr = clone_bytes(attr->value.ptr, attr->value.len
+ , "attr value");
+ attr->count = 1;
+ time(&attr->installed);
+
+ el->attr = attr;
+ el->next = list;
+ *listp = el;
+
+ return attr;
+ }
+}
+
+/*
+ * decodes a comma separated list of group attributes
+ */
+void
+decode_groups(char *groups, ietfAttrList_t **listp)
+{
+ if (groups == NULL)
+ return;
+
+ while (strlen(groups) > 0)
+ {
+ char *end;
+ char *next = strchr(groups, ',');
+
+ if (next == NULL)
+ end = next = groups + strlen(groups);
+ else
+ end = next++;
+
+ /* eat preceeding whitespace */
+ while (groups < end && *groups == ' ')
+ groups++;
+
+ /* eat trailing whitespace */
+ while (end > groups && *(end-1) == ' ')
+ end--;
+
+ if (groups < end)
+ {
+ ietfAttr_t *attr = alloc_thing(ietfAttr_t, "ietfAttr");
+ ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
+
+ attr->kind = IETF_ATTRIBUTE_STRING;
+ attr->value.ptr = groups;
+ attr->value.len = end - groups;
+ attr->count = 0;
+
+ el->attr = add_ietfAttr(attr);
+ el->next = *listp;
+ *listp = el;
+ }
+
+ groups = next;
+ }
+}
+
+static bool
+same_attribute(const ietfAttr_t *a, const ietfAttr_t *b)
+{
+ return (a->kind == b->kind && a->value.len == b->value.len
+ && memcmp(a->value.ptr, b->value.ptr, b->value.len) == 0);
+}
+
+bool
+group_membership(const ietfAttrList_t *peer_list
+ , const char *conn
+ , const ietfAttrList_t *conn_list)
+{
+ if (conn_list == NULL)
+ return TRUE;
+
+ while (peer_list != NULL)
+ {
+ const ietfAttr_t *peer_attr = peer_list->attr;
+ const ietfAttrList_t *list = conn_list;
+
+ while (list != NULL)
+ {
+ ietfAttr_t *conn_attr = list->attr;
+
+ if (same_attribute(conn_attr, peer_attr))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("%s: peer matches group '%.*s'"
+ , conn
+ , (int)peer_attr->value.len, peer_attr->value.ptr)
+ )
+ return TRUE;
+ }
+ list = list->next;
+ }
+ peer_list = peer_list->next;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("%s: peer doesn't match any group", conn)
+ )
+ return FALSE;
+}
+
+
+void
+unshare_ietfAttrList(ietfAttrList_t **listp)
+{
+ ietfAttrList_t *list = *listp;
+
+ while (list != NULL)
+ {
+ ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
+
+ el->attr = list->attr;
+ el->attr->count++;
+ el->next = NULL;
+ *listp = el;
+ listp = &el->next;
+ list = list->next;
+ }
+}
+
+/*
+ * parses ietfAttrSyntax
+ */
+static ietfAttrList_t*
+parse_ietfAttrSyntax(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ ietfAttrList_t *list = NULL;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < IETF_ATTR_ROOF)
+ {
+ if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx))
+ return NULL;
+
+ switch (objectID)
+ {
+ case IETF_ATTR_OCTETS:
+ case IETF_ATTR_OID:
+ case IETF_ATTR_STRING:
+ {
+ ietfAttr_t *attr = alloc_thing(ietfAttr_t, "ietfAttr");
+ ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList");
+
+ attr->kind = (objectID - IETF_ATTR_OCTETS) / 2;
+ attr->value = object;
+ attr->count = 0;
+
+ el->attr = add_ietfAttr(attr);
+ el->next = list;
+ list = el;
+ }
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ return list;
+}
+/*
+ * parses roleSyntax
+ */
+static void
+parse_roleSyntax(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < ROLE_ROOF)
+ {
+ if (!extract_object(roleSyntaxObjects, &objectID, &object, &level, &ctx))
+ return;
+
+ switch (objectID) {
+ default:
+ break;
+ }
+ objectID++;
+ }
+}
+
+/*
+ * Parses an X.509 attribute certificate
+ */
+bool
+parse_ac(chunk_t blob, x509acert_t *ac)
+{
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ u_int level;
+ u_int type = OID_UNKNOWN;
+ u_int extn_oid = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
+
+ while (objectID < AC_OBJ_ROOF) {
+
+ if (!extract_object(acObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ /* those objects which will parsed further need the next higher level */
+ level++;
+
+ switch (objectID)
+ {
+ case AC_OBJ_CERTIFICATE:
+ ac->certificate = object;
+ break;
+ case AC_OBJ_CERTIFICATE_INFO:
+ ac->certificateInfo = object;
+ break;
+ case AC_OBJ_VERSION:
+ ac->version = (object.len) ? (1 + (u_int)*object.ptr) : 1;
+ DBG(DBG_PARSING,
+ DBG_log(" v%d", ac->version);
+ )
+ if (ac->version != 2)
+ {
+ plog("v%d attribute certificates are not supported"
+ , ac->version);
+ return FALSE;
+ }
+ break;
+ case AC_OBJ_HOLDER_ISSUER:
+ ac->holderIssuer = get_directoryName(object, level, FALSE);
+ break;
+ case AC_OBJ_HOLDER_SERIAL:
+ ac->holderSerial = object;
+ break;
+ case AC_OBJ_ENTITY_NAME:
+ ac->entityName = get_directoryName(object, level, TRUE);
+ break;
+ case AC_OBJ_ISSUER_NAME:
+ ac->issuerName = get_directoryName(object, level, FALSE);
+ break;
+ case AC_OBJ_SIG_ALG:
+ ac->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case AC_OBJ_SERIAL_NUMBER:
+ ac->serialNumber = object;
+ break;
+ case AC_OBJ_NOT_BEFORE:
+ ac->notBefore = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case AC_OBJ_NOT_AFTER:
+ ac->notAfter = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case AC_OBJ_ATTRIBUTE_TYPE:
+ type = known_oid(object);
+ break;
+ case AC_OBJ_ATTRIBUTE_VALUE:
+ {
+ switch (type) {
+ case OID_AUTHENTICATION_INFO:
+ DBG(DBG_PARSING,
+ DBG_log(" need to parse authenticationInfo")
+ )
+ break;
+ case OID_ACCESS_IDENTITY:
+ DBG(DBG_PARSING,
+ DBG_log(" need to parse accessIdentity")
+ )
+ break;
+ case OID_CHARGING_IDENTITY:
+ ac->charging = parse_ietfAttrSyntax(object, level);
+ break;
+ case OID_GROUP:
+ ac->groups = parse_ietfAttrSyntax(object, level);
+ break;
+ case OID_ROLE:
+ parse_roleSyntax(object, level);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case AC_OBJ_EXTN_ID:
+ extn_oid = known_oid(object);
+ break;
+ case AC_OBJ_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ break;
+ case AC_OBJ_EXTN_VALUE:
+ {
+ switch (extn_oid) {
+ case OID_CRL_DISTRIBUTION_POINTS:
+ DBG(DBG_PARSING,
+ DBG_log(" need to parse crlDistributionPoints")
+ )
+ break;
+ case OID_AUTHORITY_KEY_ID:
+ parse_authorityKeyIdentifier(object, level
+ , &ac->authKeyID, &ac->authKeySerialNumber);
+ break;
+ case OID_TARGET_INFORMATION:
+ DBG(DBG_PARSING,
+ DBG_log(" need to parse targetInformation")
+ )
+ break;
+ case OID_NO_REV_AVAIL:
+ ac->noRevAvail = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case AC_OBJ_ALGORITHM:
+ ac->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case AC_OBJ_SIGNATURE:
+ ac->signature = object;
+ break;
+
+ default:
+ break;
+ }
+ objectID++;
+ }
+ time(&ac->installed);
+ return TRUE;
+}
+
+/*
+ * compare two X.509 attribute certificates by comparing their signatures
+ */
+static bool
+same_x509acert(x509acert_t *a, x509acert_t *b)
+{
+ return a->signature.len == b->signature.len &&
+ memcmp(a->signature.ptr, b->signature.ptr, b->signature.len) == 0;
+}
+
+/*
+ * release an ietfAttribute, free it if count reaches zero
+ */
+static void
+release_ietfAttr(ietfAttr_t* attr)
+{
+ if (--attr->count == 0)
+ {
+ ietfAttrList_t **plist = &ietfAttributes;
+ ietfAttrList_t *list = *plist;
+
+ while (list->attr != attr)
+ {
+ plist = &list->next;
+ list = *plist;
+ }
+ *plist = list->next;
+
+ pfree(attr->value.ptr);
+ pfree(attr);
+ pfree(list);
+ }
+}
+
+/*
+ * free an ietfAttrList
+ */
+void
+free_ietfAttrList(ietfAttrList_t* list)
+{
+ while (list != NULL)
+ {
+ ietfAttrList_t *el = list;
+
+ release_ietfAttr(el->attr);
+ list = list->next;
+ pfree(el);
+ }
+}
+
+/*
+ * free a X.509 attribute certificate
+ */
+void
+free_acert(x509acert_t *ac)
+{
+ if (ac != NULL)
+ {
+ free_ietfAttrList(ac->charging);
+ free_ietfAttrList(ac->groups);
+ pfreeany(ac->certificate.ptr);
+ pfree(ac);
+ }
+}
+
+/*
+ * free first X.509 attribute certificate in the chained list
+ */
+static void
+free_first_acert(void)
+{
+ x509acert_t *first = x509acerts;
+ x509acerts = first->next;
+ free_acert(first);
+}
+
+/*
+ * Free all attribute certificates in the chained list
+ */
+void
+free_acerts(void)
+{
+ while (x509acerts != NULL)
+ free_first_acert();
+}
+
+/*
+ * get a X.509 attribute certificate for a given holder
+ */
+x509acert_t*
+get_x509acert(chunk_t issuer, chunk_t serial)
+{
+ x509acert_t *ac = x509acerts;
+ x509acert_t *prev_ac = NULL;
+
+ while (ac != NULL)
+ {
+ if (same_dn(issuer, ac->holderIssuer)
+ && same_serial(serial, ac->holderSerial))
+ {
+ if (ac!= x509acerts)
+ {
+ /* bring the certificate up front */
+ prev_ac->next = ac->next;
+ ac->next = x509acerts;
+ x509acerts = ac;
+ }
+ return ac;
+ }
+ prev_ac = ac;
+ ac = ac->next;
+ }
+ return NULL;
+}
+
+/*
+ * add a X.509 attribute certificate to the chained list
+ */
+static void
+add_acert(x509acert_t *ac)
+{
+ x509acert_t *old_ac = get_x509acert(ac->holderIssuer, ac->holderSerial);
+
+ if (old_ac != NULL)
+ {
+ if (ac->notBefore >old_ac->notBefore)
+ {
+ /* delete the old attribute cert */
+ free_first_acert();
+ DBG(DBG_CONTROL,
+ DBG_log("attribute cert is newer - existing cert deleted")
+ )
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("attribute cert is not newer - existing cert kept");
+ )
+ free_acert(ac);
+ return;
+ }
+ }
+ plog("attribute cert added");
+
+ /* insert new attribute cert at the root of the chain */
+ ac->next = x509acerts;
+ x509acerts = ac;
+}
+
+/* verify the validity of an attribute certificate by
+ * checking the notBefore and notAfter dates
+ */
+static err_t
+check_ac_validity(const x509acert_t *ac)
+{
+ time_t current_time;
+
+ time(&current_time);
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" not before : %s", timetoa(&ac->notBefore, TRUE));
+ DBG_log(" current time: %s", timetoa(&current_time, TRUE));
+ DBG_log(" not after : %s", timetoa(&ac->notAfter, TRUE));
+ )
+
+ if (current_time < ac->notBefore)
+ return "attribute certificate is not valid yet";
+ if (current_time > ac->notAfter)
+ return "attribute certificate has expired";
+ else
+ return NULL;
+}
+
+/*
+ * verifies a X.509 attribute certificate
+ */
+bool
+verify_x509acert(x509acert_t *ac, bool strict)
+{
+ u_char buf[BUF_LEN];
+ x509cert_t *aacert;
+ err_t ugh = NULL;
+ time_t valid_until = ac->notAfter;
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, ac->entityName);
+ DBG_log("holder: '%s'",buf);
+ dntoa(buf, BUF_LEN, ac->issuerName);
+ DBG_log("issuer: '%s'",buf);
+ )
+
+ ugh = check_ac_validity(ac);
+
+ if (ugh != NULL)
+ {
+ plog("%s", ugh);
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("attribute certificate is valid")
+ )
+
+ lock_authcert_list("verify_x509acert");
+ aacert = get_authcert(ac->issuerName, ac->authKeySerialNumber
+ , ac->authKeyID, AUTH_AA);
+ unlock_authcert_list("verify_x509acert");
+
+ if (aacert == NULL)
+ {
+ plog("issuer aacert not found");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("issuer aacert found")
+ )
+
+ if (!check_signature(ac->certificateInfo, ac->signature
+ , ac->algorithm, ac->algorithm, aacert))
+ {
+ plog("attribute certificate signature is invalid");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("attribute certificate signature is valid");
+ )
+
+ return verify_x509cert(aacert, strict, &valid_until);
+}
+
+/*
+ * Loads X.509 attribute certificates
+ */
+void
+load_acerts(void)
+{
+ u_char buf[BUF_LEN];
+
+ /* change directory to specified path */
+ u_char *save_dir = getcwd(buf, BUF_LEN);
+
+ if (!chdir(A_CERT_PATH))
+ {
+ struct dirent **filelist;
+ int n;
+
+ plog("Changing to directory '%s'",A_CERT_PATH);
+ n = scandir(A_CERT_PATH, &filelist, file_select, alphasort);
+
+ if (n > 0)
+ {
+ while (n--)
+ {
+ chunk_t blob = empty_chunk;
+ bool pgp = FALSE;
+
+ if (load_coded_file(filelist[n]->d_name, NULL, "acert", &blob, &pgp))
+ {
+ x509acert_t *ac = alloc_thing(x509acert_t, "x509acert");
+
+ *ac = empty_ac;
+
+ if (parse_ac(blob, ac)
+ && verify_x509acert(ac, FALSE))
+ add_acert(ac);
+ else
+ free_acert(ac);
+ }
+ free(filelist[n]);
+ }
+ free(filelist);
+ }
+ }
+ /* restore directory path */
+ chdir(save_dir);
+}
+
+/*
+ * lists group attributes separated by commas on a single line
+ */
+void
+format_groups(const ietfAttrList_t *list, char *buf, int len)
+{
+ bool first_group = TRUE;
+
+ while (list != NULL && len > 0)
+ {
+ ietfAttr_t *attr = list->attr;
+
+ if (attr->kind == IETF_ATTRIBUTE_OCTETS
+ || attr->kind == IETF_ATTRIBUTE_STRING)
+ {
+ int written = snprintf(buf, len, "%s%.*s"
+ , (first_group)? "" : ", "
+ , (int)attr->value.len, attr->value.ptr);
+
+ first_group = FALSE;
+
+ /* return value of snprintf() up to glibc 2.0.6 */
+ if (written < 0)
+ break;
+
+ buf += written;
+ len -= written;
+ }
+ list = list->next;
+ }
+}
+
+/*
+ * list all X.509 attribute certificates in the chained list
+ */
+void
+list_acerts(bool utc)
+{
+ x509acert_t *ac = x509acerts;
+ time_t now;
+
+ /* determine the current time */
+ time(&now);
+
+ if (ac != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (ac != NULL)
+ {
+ u_char buf[BUF_LEN];
+
+ whack_log(RC_COMMENT, "%s",timetoa(&ac->installed, utc));
+ if (ac->entityName.ptr != NULL)
+ {
+ dntoa(buf, BUF_LEN, ac->entityName);
+ whack_log(RC_COMMENT, " holder: '%s'", buf);
+ }
+ if (ac->holderIssuer.ptr != NULL)
+ {
+ dntoa(buf, BUF_LEN, ac->holderIssuer);
+ whack_log(RC_COMMENT, " hissuer: '%s'", buf);
+ }
+ if (ac->holderSerial.ptr != NULL)
+ {
+ datatot(ac->holderSerial.ptr, ac->holderSerial.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " hserial: %s", buf);
+ }
+ if (ac->groups != NULL)
+ {
+ format_groups(ac->groups, buf, BUF_LEN);
+ whack_log(RC_COMMENT, " groups: %s", buf);
+ }
+ dntoa(buf, BUF_LEN, ac->issuerName);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ datatot(ac->serialNumber.ptr, ac->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " serial: %s", buf);
+ whack_log(RC_COMMENT, " validity: not before %s %s",
+ timetoa(&ac->notBefore, utc),
+ (ac->notBefore < now)?"ok":"fatal (not valid yet)");
+ whack_log(RC_COMMENT, " not after %s %s",
+ timetoa(&ac->notAfter, utc),
+ check_expiry(ac->notAfter, ACERT_WARNING_INTERVAL, TRUE));
+ if (ac->authKeyID.ptr != NULL)
+ {
+ datatot(ac->authKeyID.ptr, ac->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (ac->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(ac->authKeySerialNumber.ptr, ac->authKeySerialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+
+ ac = ac->next;
+ }
+}
+
+/*
+ * list all group attributes in alphabetical order
+ */
+void
+list_groups(bool utc)
+{
+ ietfAttrList_t *list = ietfAttributes;
+
+ if (list != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of Group Attributes:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (list != NULL)
+ {
+ ietfAttr_t *attr = list->attr;
+
+ whack_log(RC_COMMENT, "%s, count: %d", timetoa(&attr->installed, utc),
+ attr->count);
+
+ switch (attr->kind)
+ {
+ case IETF_ATTRIBUTE_OCTETS:
+ case IETF_ATTRIBUTE_STRING:
+ whack_log(RC_COMMENT, " %.*s", (int)attr->value.len, attr->value.ptr);
+ break;
+ case IETF_ATTRIBUTE_OID:
+ whack_log(RC_COMMENT, " OID");
+ break;
+ default:
+ break;
+ }
+
+ list = list->next;
+ }
+}
diff --git a/programs/pluto/ac.h b/programs/pluto/ac.h
new file mode 100644
index 000000000..3913d745d
--- /dev/null
+++ b/programs/pluto/ac.h
@@ -0,0 +1,103 @@
+/* Support of X.509 attribute certificates
+ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
+ * Copyright (C) 2003 Martin Berner, Lukas Suter
+
+ *
+ * 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: ac.h,v 1.8 2005/02/17 20:56:04 as Exp $
+ */
+
+#ifndef _AC_H
+#define _AC_H
+
+/* definition of ietfAttribute kinds */
+
+typedef enum {
+ IETF_ATTRIBUTE_OCTETS = 0,
+ IETF_ATTRIBUTE_OID = 1,
+ IETF_ATTRIBUTE_STRING = 2
+} ietfAttribute_t;
+
+/* access structure for an ietfAttribute */
+
+typedef struct ietfAttr ietfAttr_t;
+
+struct ietfAttr {
+ time_t installed;
+ int count;
+ ietfAttribute_t kind;
+ chunk_t value;
+};
+
+typedef struct ietfAttrList ietfAttrList_t;
+
+struct ietfAttrList {
+ ietfAttrList_t *next;
+ ietfAttr_t *attr;
+};
+
+
+/* access structure for an X.509 attribute certificate */
+
+typedef struct x509acert x509acert_t;
+
+struct x509acert {
+ x509acert_t *next;
+ time_t installed;
+ chunk_t certificate;
+ chunk_t certificateInfo;
+ u_int version;
+ /* holder */
+ /* baseCertificateID */
+ chunk_t holderIssuer;
+ chunk_t holderSerial;
+ chunk_t entityName;
+ /* v2Form */
+ chunk_t issuerName;
+ /* signature */
+ int sigAlg;
+ chunk_t serialNumber;
+ /* attrCertValidityPeriod */
+ time_t notBefore;
+ time_t notAfter;
+ /* attributes */
+ ietfAttrList_t *charging;
+ ietfAttrList_t *groups;
+ /* extensions */
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ bool noRevAvail;
+ /* signatureAlgorithm */
+ int algorithm;
+ chunk_t signature;
+};
+
+/* used for initialization */
+extern const x509acert_t empty_ac;
+
+extern void unshare_ietfAttrList(ietfAttrList_t **listp);
+extern void free_ietfAttrList(ietfAttrList_t *list);
+extern void decode_groups(char *groups, ietfAttrList_t **listp);
+extern bool group_membership(const ietfAttrList_t *my_list
+ , const char *conn, const ietfAttrList_t *conn_list);
+extern bool parse_ac(chunk_t blob, x509acert_t *ac);
+extern bool verify_x509acert(x509acert_t *ac, bool strict);
+extern x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial);
+extern void load_acerts(void);
+extern void free_acert(x509acert_t *ac);
+extern void free_acerts(void);
+extern void list_acerts(bool utc);
+extern void list_groups(bool utc);
+extern void format_groups(const ietfAttrList_t *list, char *buf, int len);
+
+
+#endif /* _AH_H */
diff --git a/programs/pluto/adns.c b/programs/pluto/adns.c
new file mode 100644
index 000000000..c5977d23c
--- /dev/null
+++ b/programs/pluto/adns.c
@@ -0,0 +1,615 @@
+/* Pluto Asynchronous DNS Helper Program -- for internal use only!
+ * Copyright (C) 2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: adns.c,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#ifndef USE_LWRES /* whole file! */
+
+/* This program executes as multiple processes. The Master process
+ * receives queries (struct adns_query messages) from Pluto and distributes
+ * them amongst Worker processes. These Worker processes are created
+ * by the Master whenever a query arrives and no existing Worker is free.
+ * At most MAX_WORKERS will be created; after that, the Master will queue
+ * queries until a Worker becomes free. When a Worker has an answer from
+ * the resolver, it sends the answer as a struct adns_answer message to the
+ * Master. The Master then forwards the answer to Pluto, noting that
+ * the Worker is free to accept another query.
+ *
+ * The protocol is simple: Pluto sends a sequence of queries and receives
+ * a sequence of answers. select(2) is used by Pluto and by the Master
+ * process to decide when to read, but writes are done without checking
+ * for readiness. Communications is via pipes. Since only one process
+ * can write to each pipe, messages will not be interleaved. Fixed length
+ * records are used for simplicity.
+ *
+ * Pluto needs a way to indicate to the Master when to shut down
+ * and the Master needs to indicate this to each worker. EOF on the pipe
+ * signifies this.
+ *
+ * The interfaces between these components are considered private to
+ * Pluto. This allows us to get away with less checking. This is a
+ * reason to use pipes instead of TCP/IP.
+ *
+ * Although the code uses plain old UNIX processes, it could be modified
+ * to use threads. That might reduce resource requirements. It would
+ * preclude running on systems without thread-safe resolvers.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h> /* ??? for h_errno */
+
+#include <freeswan.h>
+
+/* GCC magic! */
+#ifdef GCC_LINT
+# define UNUSED __attribute__ ((unused))
+#else
+# define UNUSED /* ignore */
+#endif
+
+#include "constants.h"
+#include "adns.h" /* needs <resolv.h> */
+
+/* shared by all processes */
+
+static const char *name; /* program name, for messages */
+
+static bool debug = FALSE;
+
+/* Read a variable-length record from a pipe (and no more!).
+ * First bytes must be a size_t containing the length.
+ * HES_CONTINUE if record read
+ * HES_OK if EOF
+ * HES_IO_ERROR_IN if errno tells the tale.
+ * Others are errors.
+ */
+static enum helper_exit_status
+read_pipe(int fd, unsigned char *stuff, size_t minlen, size_t maxlen)
+{
+ size_t n = 0;
+ size_t goal = minlen;
+
+ do {
+ ssize_t m = read(fd, stuff + n, goal - n);
+
+ if (m == -1)
+ {
+ if (errno != EINTR)
+ {
+ syslog(LOG_ERR, "Input error on pipe: %s", strerror(errno));
+ return HES_IO_ERROR_IN;
+ }
+ }
+ else if (m == 0)
+ {
+ return HES_OK; /* treat empty message as EOF */
+ }
+ else
+ {
+ n += m;
+ if (n >= sizeof(size_t))
+ {
+ goal = *(size_t *)(void *)stuff;
+ if (goal < minlen || maxlen < goal)
+ {
+ if (debug)
+ fprintf(stderr, "%lu : [%lu, %lu]\n"
+ , (unsigned long)goal
+ , (unsigned long)minlen, (unsigned long)maxlen);
+ return HES_BAD_LEN;
+ }
+ }
+ }
+ } while (n < goal);
+
+ return HES_CONTINUE;
+}
+
+/* Write a variable-length record to a pipe.
+ * First bytes must be a size_t containing the length.
+ * HES_CONTINUE if record written
+ * Others are errors.
+ */
+static enum helper_exit_status
+write_pipe(int fd, const unsigned char *stuff)
+{
+ size_t len = *(const size_t *)(const void *)stuff;
+ size_t n = 0;
+
+ do {
+ ssize_t m = write(fd, stuff + n, len - n);
+
+ if (m == -1)
+ {
+ /* error, but ignore and retry if EINTR */
+ if (errno != EINTR)
+ {
+ syslog(LOG_ERR, "Output error from master: %s", strerror(errno));
+ return HES_IO_ERROR_OUT;
+ }
+ }
+ else
+ {
+ n += m;
+ }
+ } while (n != len);
+ return HES_CONTINUE;
+}
+
+/**************** worker process ****************/
+
+/* The interface in RHL6.x and BIND distribution 8.2.2 are different,
+ * so we build some of our own :-(
+ */
+
+/* Support deprecated interface to allow for older releases of the resolver.
+ * Fake new interface!
+ * See resolver(3) bind distribution (should be in RHL6.1, but isn't).
+ * __RES was 19960801 in RHL6.2, an old resolver.
+ */
+
+#if (__RES) <= 19960801
+# define OLD_RESOLVER 1
+#endif
+
+#ifdef OLD_RESOLVER
+
+# define res_ninit(statp) res_init()
+# define res_nquery(statp, dname, class, type, answer, anslen) \
+ res_query(dname, class, type, answer, anslen)
+# define res_nclose(statp) res_close()
+
+static struct __res_state *statp = &_res;
+
+#else /* !OLD_RESOLVER */
+
+static struct __res_state my_res_state /* = { 0 } */;
+static res_state statp = &my_res_state;
+
+#endif /* !OLD_RESOLVER */
+
+static int
+worker(int qfd, int afd)
+{
+ {
+ int r = res_ninit(statp);
+
+ if (r != 0)
+ {
+ syslog(LOG_ERR, "cannot initialize resolver");
+ return HES_RES_INIT;
+ }
+#ifndef OLD_RESOLVER
+ statp->options |= RES_ROTATE;
+#endif
+ statp->options |= RES_DEBUG;
+ }
+
+ for (;;)
+ {
+ struct adns_query q;
+ struct adns_answer a;
+
+ enum helper_exit_status r = read_pipe(qfd, (unsigned char *)&q
+ , sizeof(q), sizeof(q));
+
+ if (r != HES_CONTINUE)
+ return r; /* some kind of exit */
+
+ if (q.qmagic != ADNS_Q_MAGIC)
+ {
+ syslog(LOG_ERR, "error in input from master: bad magic");
+ return HES_BAD_MAGIC;
+ }
+
+ a.amagic = ADNS_A_MAGIC;
+ a.serial = q.serial;
+
+ a.result = res_nquery(statp, q.name_buf, C_IN, q.type, a.ans, sizeof(a.ans));
+ a.h_errno_val = h_errno;
+
+ a.len = offsetof(struct adns_answer, ans) + (a.result < 0? 0 : a.result);
+
+#ifdef DEBUG
+ if (((q.debugging & IMPAIR_DELAY_ADNS_KEY_ANSWER) && q.type == T_KEY)
+ || ((q.debugging & IMPAIR_DELAY_ADNS_TXT_ANSWER) && q.type == T_TXT))
+ sleep(30); /* delay the answer */
+#endif
+
+ /* write answer, possibly a bit at a time */
+ r = write_pipe(afd, (const unsigned char *)&a);
+
+ if (r != HES_CONTINUE)
+ return r; /* some kind of exit */
+ }
+}
+
+/**************** master process ****************/
+
+bool eof_from_pluto = FALSE;
+#define PLUTO_QFD 0 /* queries come on stdin */
+#define PLUTO_AFD 1 /* answers go out on stdout */
+
+#ifndef MAX_WORKERS
+# define MAX_WORKERS 10 /* number of in-flight queries */
+#endif
+
+struct worker_info {
+ int qfd; /* query pipe's file descriptor */
+ int afd; /* answer pipe's file descriptor */
+ pid_t pid;
+ bool busy;
+ void *continuation; /* of outstanding request */
+};
+
+static struct worker_info wi[MAX_WORKERS];
+static struct worker_info *wi_roof = wi;
+
+/* request FIFO */
+
+struct query_list {
+ struct query_list *next;
+ struct adns_query aq;
+};
+
+static struct query_list *oldest_query = NULL;
+static struct query_list *newest_query; /* undefined when oldest == NULL */
+static struct query_list *free_queries = NULL;
+
+static bool
+spawn_worker(void)
+{
+ int qfds[2];
+ int afds[2];
+ pid_t p;
+
+ if (pipe(qfds) != 0 || pipe(afds) != 0)
+ {
+ syslog(LOG_ERR, "pipe(2) failed: %s", strerror(errno));
+ exit(HES_PIPE);
+ }
+
+ wi_roof->qfd = qfds[1]; /* write end of query pipe */
+ wi_roof->afd = afds[0]; /* read end of answer pipe */
+
+ p = fork();
+ if (p == -1)
+ {
+ /* fork failed: ignore if at least one worker exists */
+ if (wi_roof == wi)
+ {
+ syslog(LOG_ERR, "fork(2) error creating first worker: %s", strerror(errno));
+ exit(HES_FORK);
+ }
+ close(qfds[0]);
+ close(qfds[1]);
+ close(afds[0]);
+ close(afds[1]);
+ return FALSE;
+ }
+ else if (p == 0)
+ {
+ /* child */
+ struct worker_info *w;
+
+ close(PLUTO_QFD);
+ close(PLUTO_AFD);
+ /* close all master pipes, including ours */
+ for (w = wi; w <= wi_roof; w++)
+ {
+ close(w->qfd);
+ close(w->afd);
+ }
+ exit(worker(qfds[0], afds[1]));
+ }
+ else
+ {
+ /* parent */
+ struct worker_info *w = wi_roof++;
+
+ w->pid = p;
+ w->busy = FALSE;
+ close(qfds[0]);
+ close(afds[1]);
+ return TRUE;
+ }
+}
+
+static void
+send_eof(struct worker_info *w)
+{
+ pid_t p;
+ int status;
+
+ close(w->qfd);
+ w->qfd = NULL_FD;
+
+ close(w->afd);
+ w->afd = NULL_FD;
+
+ /* reap child */
+ p = waitpid(w->pid, &status, 0);
+ /* ignore result -- what could we do with it? */
+}
+
+static void
+forward_query(struct worker_info *w)
+{
+ struct query_list *q = oldest_query;
+
+ if (q == NULL)
+ {
+ if (eof_from_pluto)
+ send_eof(w);
+ }
+ else
+ {
+ enum helper_exit_status r
+ = write_pipe(w->qfd, (const unsigned char *) &q->aq);
+
+ if (r != HES_CONTINUE)
+ exit(r);
+
+ w->busy = TRUE;
+
+ oldest_query = q->next;
+ q->next = free_queries;
+ free_queries = q;
+ }
+}
+
+static void
+query(void)
+{
+ struct query_list *q = free_queries;
+ enum helper_exit_status r;
+
+ /* find an unused queue entry */
+ if (q == NULL)
+ {
+ q = malloc(sizeof(*q));
+ if (q == NULL)
+ {
+ syslog(LOG_ERR, "malloc(3) failed");
+ exit(HES_MALLOC);
+ }
+ }
+ else
+ {
+ free_queries = q->next;
+ }
+
+ r = read_pipe(PLUTO_QFD, (unsigned char *)&q->aq
+ , sizeof(q->aq), sizeof(q->aq));
+
+ if (r == HES_OK)
+ {
+ /* EOF: we're done, except for unanswered queries */
+ struct worker_info *w;
+
+ eof_from_pluto = TRUE;
+ q->next = free_queries;
+ free_queries = q;
+
+ /* Send bye-bye to unbusy processes.
+ * Note that if there are queued queries, there won't be
+ * any non-busy workers.
+ */
+ for (w = wi; w != wi_roof; w++)
+ if (!w->busy)
+ send_eof(w);
+ }
+ else if (r != HES_CONTINUE)
+ {
+ exit(r);
+ }
+ else if (q->aq.qmagic != ADNS_Q_MAGIC)
+ {
+ syslog(LOG_ERR, "error in query from Pluto: bad magic");
+ exit(HES_BAD_MAGIC);
+ }
+ else
+ {
+ struct worker_info *w;
+
+ /* got a query */
+
+ /* add it to FIFO */
+ q->next = NULL;
+ if (oldest_query == NULL)
+ oldest_query = q;
+ else
+ newest_query->next = q;
+ newest_query = q;
+
+ /* See if any worker available */
+ for (w = wi; ; w++)
+ {
+ if (w == wi_roof)
+ {
+ /* no free worker */
+ if (w == wi + MAX_WORKERS)
+ break; /* no more to be created */
+ /* make a new one */
+ if (!spawn_worker())
+ break; /* cannot create one at this time */
+ }
+ if (!w->busy)
+ {
+ /* assign first to free worker */
+ forward_query(w);
+ break;
+ }
+ }
+ }
+ return;
+}
+
+static void
+answer(struct worker_info *w)
+{
+ struct adns_answer a;
+ enum helper_exit_status r = read_pipe(w->afd, (unsigned char *)&a
+ , offsetof(struct adns_answer, ans), sizeof(a));
+
+ if (r == HES_OK)
+ {
+ /* unexpected EOF */
+ syslog(LOG_ERR, "unexpected EOF from worker");
+ exit(HES_IO_ERROR_IN);
+ }
+ else if (r != HES_CONTINUE)
+ {
+ exit(r);
+ }
+ else if (a.amagic != ADNS_A_MAGIC)
+ {
+ syslog(LOG_ERR, "Input from worker error: bad magic");
+ exit(HES_BAD_MAGIC);
+ }
+ else if (a.continuation != w->continuation)
+ {
+ /* answer doesn't match query */
+ syslog(LOG_ERR, "Input from worker error: continuation mismatch");
+ exit(HES_SYNC);
+ }
+ else
+ {
+ /* pass the answer on to Pluto */
+ enum helper_exit_status r
+ = write_pipe(PLUTO_AFD, (const unsigned char *) &a);
+
+ if (r != HES_CONTINUE)
+ exit(r);
+ w->busy = FALSE;
+ forward_query(w);
+ }
+}
+
+/* assumption: input limited; accept blocking on output */
+static int
+master(void)
+{
+ for (;;)
+ {
+ fd_set readfds;
+ int maxfd = PLUTO_QFD; /* approximate lower bound */
+ int ndes = 0;
+ struct worker_info *w;
+
+ FD_ZERO(&readfds);
+ if (!eof_from_pluto)
+ {
+ FD_SET(PLUTO_QFD, &readfds);
+ ndes++;
+ }
+ for (w = wi; w != wi_roof; w++)
+ {
+ if (w->busy)
+ {
+ FD_SET(w->afd, &readfds);
+ ndes++;
+ if (maxfd < w->afd)
+ maxfd = w->afd;
+ }
+ }
+
+ if (ndes == 0)
+ return HES_OK; /* done! */
+
+ do {
+ ndes = select(maxfd + 1, &readfds, NULL, NULL, NULL);
+ } while (ndes == -1 && errno == EINTR);
+ if (ndes == -1)
+ {
+ syslog(LOG_ERR, "select(2) error: %s", strerror(errno));
+ exit(HES_IO_ERROR_SELECT);
+ }
+ else if (ndes > 0)
+ {
+ if (FD_ISSET(PLUTO_QFD, &readfds))
+ {
+ query();
+ ndes--;
+ }
+ for (w = wi; ndes > 0 && w != wi_roof; w++)
+ {
+ if (w->busy && FD_ISSET(w->afd, &readfds))
+ {
+ answer(w);
+ ndes--;
+ }
+ }
+ }
+ }
+}
+
+/* Not to be invoked by strangers -- user hostile.
+ * Mandatory args: query-fd answer-fd
+ * Optional arg: -d, signifying "debug".
+ */
+
+static void
+adns_usage(const char *fmt, const char *arg)
+{
+ const char **sp = ipsec_copyright_notice();
+
+ fprintf(stderr, "INTERNAL TO PLUTO: DO NOT EXECUTE\n");
+
+ fprintf(stderr, fmt, arg);
+ fprintf(stderr, "\n%s\n", ipsec_version_string());
+
+ for (; *sp != NULL; sp++)
+ fprintf(stderr, "%s\n", *sp);
+
+ syslog(LOG_ERR, fmt, arg);
+ exit(HES_INVOCATION);
+}
+
+int
+main(int argc UNUSED, char **argv)
+{
+ int i = 1;
+
+ name = argv[0];
+
+ while (i < argc)
+ {
+ if (streq(argv[i], "-d"))
+ {
+ i++;
+ debug = TRUE;
+ }
+ else
+ {
+ adns_usage("unexpected argument \"%s\"", argv[i]);
+ /*NOTREACHED*/
+ }
+ }
+
+ return master();
+}
+
+#endif /* !USE_LWRES */
diff --git a/programs/pluto/adns.h b/programs/pluto/adns.h
new file mode 100644
index 000000000..00fc4ad07
--- /dev/null
+++ b/programs/pluto/adns.h
@@ -0,0 +1,75 @@
+/* Pluto Asynchronous DNS Helper Program's Header
+ * Copyright (C) 2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: adns.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#ifndef USE_LWRES /* whole file! */
+
+/* The interface in RHL6.x and BIND distribution 8.2.2 are different,
+ * so we build some of our own :-(
+ */
+
+# ifndef NS_MAXDNAME
+# define NS_MAXDNAME MAXDNAME /* I hope this is long enough for IPv6 */
+# endif
+
+# ifndef NS_PACKETSZ
+# define NS_PACKETSZ PACKETSZ
+# endif
+
+/* protocol version */
+
+#define ADNS_Q_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 4)
+#define ADNS_A_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 128 + 4)
+
+/* note: both struct adns_query and struct adns_answer must start with
+ * size_t len;
+ */
+
+struct adns_query {
+ size_t len;
+ unsigned int qmagic;
+ unsigned long serial;
+ lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
+ u_char name_buf[NS_MAXDNAME + 2];
+ int type; /* T_KEY or T_TXT */
+};
+
+struct adns_answer {
+ size_t len;
+ unsigned int amagic;
+ unsigned long serial;
+ struct adns_continuation *continuation;
+ int result;
+ int h_errno_val;
+ u_char ans[NS_PACKETSZ * 10]; /* very probably bigger than necessary */
+};
+
+enum helper_exit_status {
+ HES_CONTINUE = -1, /* not an exit */
+ HES_OK = 0, /* all's well that ends well (perhaps EOF) */
+ HES_INVOCATION, /* improper invocation */
+ HES_IO_ERROR_SELECT, /* IO error in select() */
+ HES_MALLOC, /* malloc failed */
+ HES_IO_ERROR_IN, /* error reading pipe */
+ HES_IO_ERROR_OUT, /* error reading pipe */
+ HES_PIPE, /* pipe(2) failed */
+ HES_SYNC, /* answer from worker doesn't match query */
+ HES_FORK, /* fork(2) failed */
+ HES_RES_INIT, /* resolver initialization failed */
+ HES_BAD_LEN, /* implausible .len field */
+ HES_BAD_MAGIC, /* .magic field wrong */
+};
+
+#endif /* !USE_LWRES */
diff --git a/programs/pluto/alg/Config.ike_alg b/programs/pluto/alg/Config.ike_alg
new file mode 100644
index 000000000..0fcda4cad
--- /dev/null
+++ b/programs/pluto/alg/Config.ike_alg
@@ -0,0 +1,9 @@
+##
+## IKE algorithms config. for static linking into pluto
+## By now 3DES,MD5 and SHA1 are already present in pluto.
+##
+CONFIG_IKE_ALG_AES=y
+CONFIG_IKE_ALG_BLOWFISH=y
+CONFIG_IKE_ALG_SERPENT=y
+CONFIG_IKE_ALG_TWOFISH=y
+CONFIG_IKE_ALG_SHA2=y
diff --git a/programs/pluto/alg/Makefile b/programs/pluto/alg/Makefile
new file mode 100644
index 000000000..9732cc80e
--- /dev/null
+++ b/programs/pluto/alg/Makefile
@@ -0,0 +1,93 @@
+# pluto/alg Makefile
+# Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+#
+# 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.
+#
+# $Id: Makefile,v 1.3 2004/06/23 04:45:20 as Exp $
+
+Make.common: ../Makefile
+ make -s -C .. showdefs > $@
+
+-include Make.common
+include Config.ike_alg
+
+LIBCRYPTO:=../../../lib/libcrypto
+ALLFLAGS=$(CPPFLAGS) $(CFLAGS) -I .. -I- -I ../../../linux/include -I $(LIBCRYPTO)
+LIBALG := libalg.o
+
+all : $(LIBALG)
+
+include $(wildcard Makefile.ike_alg_*)
+#include $(wildcard Makefile.ike_alg_[ab]*)
+
+ALG_DIRS:=$(ALG_DIRS-y)
+ALG_LIBS:=$(ALG_LIBS-y)
+ALG_SRCS:=$(ALG_SRCS-y)
+ALG_OBJS:=$(ALG_OBJS-y)
+$(LIBALG): ike_alginit.o $(ALG_OBJS) $(ALG_LIBS)
+ $(LD) -r -o $@ $^
+
+# Search for IKE_ALG_INIT_NAME: in ike_alg_*.c to
+# build ike_alginit.c:ike_alginit()
+
+ike_alginit.c: $(ALG_SRCS) Makefile Config.ike_alg
+ @awk ' \
+ BEGIN { print "extern int ike_alg_init(void); \
+ int ike_alg_init(void) {" } \
+ /IKE_ALG_INIT_NAME:/ \
+ { print "{ extern int " $$2" (void); " $$2 "();}" } \
+ END { print "return 0;}" } \
+ ' $(ALG_SRCS) /dev/null > $@
+
+clean :
+ @for i in $(ALG_DIRS);do make -C $$i clean;done
+ rm -f *.[oa] ike_alginit.c Make.common
+
+gatherdeps:
+ @ls $(ALG_SRCS) | grep '\.c' | sed -e 's/\(.*\)\.c$$/\1.o: \1.c/'
+ @echo
+ @ls $(ALG_SRCS) | grep '\.c' | xargs grep '^#[ ]*include[ ]*"' | \
+ sed -n -e '/#include.*"lib/d' \
+ -e 's/\.c:#[ ]*include[ ]*"/.o: ..\//' -e 's/".*//p'
+
+# Dependencies generated by "make gatherdeps":
+
+ike_alg_aes.o: ike_alg_aes.c
+ike_alg_blowfish.o: ike_alg_blowfish.c
+ike_alg_serpent.o: ike_alg_serpent.c
+ike_alg_sha2.o: ike_alg_sha2.c
+ike_alg_twofish.o: ike_alg_twofish.c
+
+ike_alg_aes.o: ../constants.h
+ike_alg_aes.o: ../defs.h
+ike_alg_aes.o: ../log.h
+ike_alg_aes.o: ../alg_info.h
+ike_alg_aes.o: ../ike_alg.h
+ike_alg_blowfish.o: ../constants.h
+ike_alg_blowfish.o: ../defs.h
+ike_alg_blowfish.o: ../log.h
+ike_alg_blowfish.o: ../alg_info.h
+ike_alg_blowfish.o: ../ike_alg.h
+ike_alg_serpent.o: ../constants.h
+ike_alg_serpent.o: ../defs.h
+ike_alg_serpent.o: ../log.h
+ike_alg_serpent.o: ../alg_info.h
+ike_alg_serpent.o: ../ike_alg.h
+ike_alg_sha2.o: ../constants.h
+ike_alg_sha2.o: ../defs.h
+ike_alg_sha2.o: ../log.h
+ike_alg_sha2.o: ../alg_info.h
+ike_alg_sha2.o: ../ike_alg.h
+ike_alg_twofish.o: ../constants.h
+ike_alg_twofish.o: ../defs.h
+ike_alg_twofish.o: ../log.h
+ike_alg_twofish.o: ../alg_info.h
+ike_alg_twofish.o: ../ike_alg.h
diff --git a/programs/pluto/alg/Makefile.ike_alg_aes b/programs/pluto/alg/Makefile.ike_alg_aes
new file mode 100644
index 000000000..12009ba5c
--- /dev/null
+++ b/programs/pluto/alg/Makefile.ike_alg_aes
@@ -0,0 +1,14 @@
+ALG:=aes
+CONFIG_YES:=$(CONFIG_IKE_ALG_AES)
+DIR_AES:=$(LIBCRYPTO)/libaes
+
+ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_AES)
+ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_AES)/libaes.a
+ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
+ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
+
+$(DIR_AES)/libaes.a:
+ make -C $(DIR_AES) CFLAGS="$(CFLAGS)" libaes.a
+
+ike_alg_$(ALG).o: ike_alg_$(ALG).c
+ $(CC) -I $(LIBCRYPTO) -I$(DIR_AES) $(COPTS) $(ALLFLAGS) -c $<
diff --git a/programs/pluto/alg/Makefile.ike_alg_blowfish b/programs/pluto/alg/Makefile.ike_alg_blowfish
new file mode 100644
index 000000000..c3af6199b
--- /dev/null
+++ b/programs/pluto/alg/Makefile.ike_alg_blowfish
@@ -0,0 +1,13 @@
+ALG:=blowfish
+CONFIG_YES:=$(CONFIG_IKE_ALG_BLOWFISH)
+DIR_BLOWFISH:=$(LIBCRYPTO)/libblowfish
+ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_BLOWFISH)
+ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_BLOWFISH)/libblowfish.a
+ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
+ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
+
+$(DIR_BLOWFISH)/libblowfish.a:
+ make -C $(DIR_BLOWFISH) CFLAGS="$(CFLAGS)" libblowfish.a
+
+ike_alg_$(ALG).o: ike_alg_$(ALG).c
+ $(CC) -I $(LIBCRYPTO) -I$(DIR_BLOWFISH) $(COPTS) $(ALLFLAGS) -c $<
diff --git a/programs/pluto/alg/Makefile.ike_alg_serpent b/programs/pluto/alg/Makefile.ike_alg_serpent
new file mode 100644
index 000000000..3395ac0ea
--- /dev/null
+++ b/programs/pluto/alg/Makefile.ike_alg_serpent
@@ -0,0 +1,13 @@
+ALG:=serpent
+CONFIG_YES:=$(CONFIG_IKE_ALG_SERPENT)
+DIR_SERPENT:=$(LIBCRYPTO)/libserpent
+ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_SERPENT)
+ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_SERPENT)/libserpent.a
+ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
+ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
+
+$(DIR_SERPENT)/libserpent.a:
+ make -C $(DIR_SERPENT) CFLAGS="$(CFLAGS)" libserpent.a
+
+ike_alg_$(ALG).o: ike_alg_$(ALG).c
+ $(CC) -I $(LIBCRYPTO) -I$(DIR_SERPENT) $(COPTS) $(ALLFLAGS) -c $<
diff --git a/programs/pluto/alg/Makefile.ike_alg_sha2 b/programs/pluto/alg/Makefile.ike_alg_sha2
new file mode 100644
index 000000000..67e68a667
--- /dev/null
+++ b/programs/pluto/alg/Makefile.ike_alg_sha2
@@ -0,0 +1,13 @@
+ALG:=sha2
+CONFIG_YES:=$(CONFIG_IKE_ALG_SHA2)
+DIR_SHA2:=$(LIBCRYPTO)/libsha2
+ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_SHA2)
+ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_SHA2)/libsha2.a
+ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
+ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
+
+$(DIR_SHA2)/libsha2.a:
+ make -C $(DIR_SHA2) libsha2.a
+
+ike_alg_$(ALG).o: ike_alg_$(ALG).c
+ $(CC) -I $(LIBCRYPTO) -I$(DIR_SHA2) $(COPTS) $(ALLFLAGS) -c $<
diff --git a/programs/pluto/alg/Makefile.ike_alg_twofish b/programs/pluto/alg/Makefile.ike_alg_twofish
new file mode 100644
index 000000000..dcd30dd3e
--- /dev/null
+++ b/programs/pluto/alg/Makefile.ike_alg_twofish
@@ -0,0 +1,13 @@
+ALG:=twofish
+CONFIG_YES:=$(CONFIG_IKE_ALG_TWOFISH)
+DIR_TWOFISH:=$(LIBCRYPTO)/libtwofish
+ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_TWOFISH)
+ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_TWOFISH)/libtwofish.a
+ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
+ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
+
+$(DIR_TWOFISH)/libtwofish.a:
+ make -C $(DIR_TWOFISH) CFLAGS="$(CFLAGS)" libtwofish.a
+
+ike_alg_$(ALG).o: ike_alg_$(ALG).c
+ $(CC) -I $(LIBCRYPTO) -I$(DIR_TWOFISH) $(COPTS) $(ALLFLAGS) -c $<
diff --git a/programs/pluto/alg/ike_alg_aes.c b/programs/pluto/alg/ike_alg_aes.c
new file mode 100644
index 000000000..44de09b4c
--- /dev/null
+++ b/programs/pluto/alg/ike_alg_aes.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libaes/aes_cbc.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+#define AES_CBC_BLOCK_SIZE (128/BITS_PER_BYTE)
+#define AES_KEY_MIN_LEN 128
+#define AES_KEY_DEF_LEN 128
+#define AES_KEY_MAX_LEN 256
+
+static void
+do_aes(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ aes_context aes_ctx;
+ char iv_bak[AES_CBC_BLOCK_SIZE];
+ char *new_iv = NULL; /* logic will avoid copy to NULL */
+
+ aes_set_key(&aes_ctx, key, key_size, 0);
+
+ /*
+ * my AES cbc does not touch passed IV (optimization for
+ * ESP handling), so I must "emulate" des-like IV
+ * crunching
+ */
+ if (!enc)
+ memcpy(new_iv=iv_bak, (char*) buf + buf_len - AES_CBC_BLOCK_SIZE
+ , AES_CBC_BLOCK_SIZE);
+
+ AES_cbc_encrypt(&aes_ctx, buf, buf, buf_len, iv, enc);
+
+ if (enc)
+ new_iv = (char*) buf + buf_len-AES_CBC_BLOCK_SIZE;
+
+ memcpy(iv, new_iv, AES_CBC_BLOCK_SIZE);
+}
+
+struct encrypt_desc algo_aes =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_AES_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(aes_context),
+ enc_blocksize: AES_CBC_BLOCK_SIZE,
+ keyminlen: AES_KEY_MIN_LEN,
+ keydeflen: AES_KEY_DEF_LEN,
+ keymaxlen: AES_KEY_MAX_LEN,
+ do_crypt: do_aes,
+};
+
+int ike_alg_aes_init(void);
+
+int
+ike_alg_aes_init(void)
+{
+ int ret = ike_alg_register_enc(&algo_aes);
+ return ret;
+}
+/*
+IKE_ALG_INIT_NAME: ike_alg_aes_init
+*/
diff --git a/programs/pluto/alg/ike_alg_blowfish.c b/programs/pluto/alg/ike_alg_blowfish.c
new file mode 100644
index 000000000..2bbef051b
--- /dev/null
+++ b/programs/pluto/alg/ike_alg_blowfish.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libblowfish/blowfish.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+#define BLOWFISH_CBC_BLOCK_SIZE 8 /* block size */
+#define BLOWFISH_KEY_MIN_LEN 128
+#define BLOWFISH_KEY_MAX_LEN 448
+
+
+static void
+do_blowfish(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ BF_KEY bf_ctx;
+
+ BF_set_key(&bf_ctx, key_size , key);
+ BF_cbc_encrypt(buf, buf, buf_len, &bf_ctx, iv, enc);
+}
+
+struct encrypt_desc algo_blowfish =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_BLOWFISH_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(BF_KEY),
+ enc_blocksize: BLOWFISH_CBC_BLOCK_SIZE,
+ keyminlen: BLOWFISH_KEY_MIN_LEN,
+ keydeflen: BLOWFISH_KEY_MIN_LEN,
+ keymaxlen: BLOWFISH_KEY_MAX_LEN,
+ do_crypt: do_blowfish,
+};
+
+int ike_alg_blowfish_init(void);
+
+int
+ike_alg_blowfish_init(void)
+{
+ int ret = ike_alg_register_enc(&algo_blowfish);
+
+ return ret;
+}
+/*
+IKE_ALG_INIT_NAME: ike_alg_blowfish_init
+*/
diff --git a/programs/pluto/alg/ike_alg_serpent.c b/programs/pluto/alg/ike_alg_serpent.c
new file mode 100644
index 000000000..fb01caa41
--- /dev/null
+++ b/programs/pluto/alg/ike_alg_serpent.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libserpent/serpent_cbc.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+#define SERPENT_CBC_BLOCK_SIZE (128/BITS_PER_BYTE)
+#define SERPENT_KEY_MIN_LEN 128
+#define SERPENT_KEY_DEF_LEN 128
+#define SERPENT_KEY_MAX_LEN 256
+
+static void
+do_serpent(u_int8_t *buf, size_t buf_size, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ serpent_context serpent_ctx;
+ char iv_bak[SERPENT_CBC_BLOCK_SIZE];
+ char *new_iv = NULL; /* logic will avoid copy to NULL */
+
+
+ serpent_set_key(&serpent_ctx, key, key_size);
+ /*
+ * my SERPENT cbc does not touch passed IV (optimization for
+ * ESP handling), so I must "emulate" des-like IV
+ * crunching
+ */
+ if (!enc)
+ memcpy(new_iv=iv_bak,
+ (char*) buf + buf_size-SERPENT_CBC_BLOCK_SIZE,
+ SERPENT_CBC_BLOCK_SIZE);
+
+ serpent_cbc_encrypt(&serpent_ctx, buf, buf, buf_size, iv, enc);
+
+ if (enc)
+ new_iv = (char*) buf + buf_size-SERPENT_CBC_BLOCK_SIZE;
+
+ memcpy(iv, new_iv, SERPENT_CBC_BLOCK_SIZE);
+}
+
+struct encrypt_desc encrypt_desc_serpent =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_SERPENT_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(struct serpent_context),
+ enc_blocksize: SERPENT_CBC_BLOCK_SIZE,
+ keyminlen: SERPENT_KEY_MIN_LEN,
+ keydeflen: SERPENT_KEY_DEF_LEN,
+ keymaxlen: SERPENT_KEY_MAX_LEN,
+ do_crypt: do_serpent,
+};
+
+int ike_alg_serpent_init(void);
+
+int
+ike_alg_serpent_init(void)
+{
+ int ret = ike_alg_register_enc(&encrypt_desc_serpent);
+
+ return ret;
+}
+/*
+IKE_ALG_INIT_NAME: ike_alg_serpent_init
+*/
diff --git a/programs/pluto/alg/ike_alg_sha2.c b/programs/pluto/alg/ike_alg_sha2.c
new file mode 100644
index 000000000..ad24f7cf0
--- /dev/null
+++ b/programs/pluto/alg/ike_alg_sha2.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libsha2/sha2.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+#define SHA2_256_DIGEST_SIZE (256/BITS_PER_BYTE)
+#define SHA2_512_DIGEST_SIZE (512/BITS_PER_BYTE)
+
+static void sha256_hash_final(u_char *hash, sha256_context *ctx)
+{
+ sha256_final(ctx);
+ memcpy(hash, &ctx->sha_out[0], SHA2_256_DIGEST_SIZE);
+}
+static void sha512_hash_final(u_char *hash, sha512_context *ctx)
+{
+ sha512_final(ctx);
+ memcpy(hash, &ctx->sha_out[0], SHA2_512_DIGEST_SIZE);
+}
+struct hash_desc hash_desc_sha2_256 = {
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_SHA2_256,
+ algo_next: NULL,
+ hash_ctx_size: sizeof(sha256_context),
+ hash_init: (void (*)(void *))sha256_init,
+ hash_update: (void (*)(void *, const u_char *, size_t ))sha256_write,
+ hash_final:(void (*)(u_char *, void *))sha256_hash_final,
+ hash_digest_size: SHA2_256_DIGEST_SIZE,
+};
+struct hash_desc hash_desc_sha2_512 = {
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_SHA2_512,
+ algo_next: NULL,
+ hash_ctx_size: sizeof(sha512_context),
+ hash_init: (void (*)(void *))sha512_init,
+ hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
+ hash_final:(void (*)(u_char *, void *))sha512_hash_final,
+ hash_digest_size: SHA2_512_DIGEST_SIZE,
+};
+int ike_alg_sha2_init(void);
+int
+ike_alg_sha2_init(void)
+{
+ int ret;
+ ret = ike_alg_register_hash(&hash_desc_sha2_256);
+ if (ret)
+ goto out;
+ ret = ike_alg_register_hash(&hash_desc_sha2_512);
+out:
+ return ret;
+}
+/*
+IKE_ALG_INIT_NAME: ike_alg_sha2_init
+*/
diff --git a/programs/pluto/alg/ike_alg_twofish.c b/programs/pluto/alg/ike_alg_twofish.c
new file mode 100644
index 000000000..1788bc394
--- /dev/null
+++ b/programs/pluto/alg/ike_alg_twofish.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "libtwofish/twofish_cbc.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+
+#define TWOFISH_CBC_BLOCK_SIZE (128/BITS_PER_BYTE)
+#define TWOFISH_KEY_MIN_LEN 128
+#define TWOFISH_KEY_DEF_LEN 128
+#define TWOFISH_KEY_MAX_LEN 256
+
+static void
+do_twofish(u_int8_t *buf, size_t buf_size, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ twofish_context twofish_ctx;
+ char iv_bak[TWOFISH_CBC_BLOCK_SIZE];
+ char *new_iv = NULL; /* logic will avoid copy to NULL */
+
+ twofish_set_key(&twofish_ctx, key, key_size);
+ /*
+ * my TWOFISH cbc does not touch passed IV (optimization for
+ * ESP handling), so I must "emulate" des-like IV
+ * crunching
+ */
+ if (!enc)
+ memcpy(new_iv=iv_bak,
+ (char*) buf + buf_size-TWOFISH_CBC_BLOCK_SIZE,
+ TWOFISH_CBC_BLOCK_SIZE);
+
+ twofish_cbc_encrypt(&twofish_ctx, buf, buf, buf_size, iv, enc);
+
+ if (enc)
+ new_iv = (char*) buf + buf_size-TWOFISH_CBC_BLOCK_SIZE;
+
+ memcpy(iv, new_iv, TWOFISH_CBC_BLOCK_SIZE);
+}
+
+struct encrypt_desc encrypt_desc_twofish =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_TWOFISH_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(twofish_context),
+ enc_blocksize: TWOFISH_CBC_BLOCK_SIZE,
+ keydeflen: TWOFISH_KEY_MIN_LEN,
+ keyminlen: TWOFISH_KEY_DEF_LEN,
+ keymaxlen: TWOFISH_KEY_MAX_LEN,
+ do_crypt: do_twofish,
+};
+
+struct encrypt_desc encrypt_desc_twofish_ssh =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_TWOFISH_CBC_SSH,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(twofish_context),
+ enc_blocksize: TWOFISH_CBC_BLOCK_SIZE,
+ keydeflen: TWOFISH_KEY_MIN_LEN,
+ keyminlen: TWOFISH_KEY_DEF_LEN,
+ keymaxlen: TWOFISH_KEY_MAX_LEN,
+ do_crypt: do_twofish,
+};
+
+int ike_alg_twofish_init(void);
+
+int
+ike_alg_twofish_init(void)
+{
+ int ret = ike_alg_register_enc(&encrypt_desc_twofish);
+
+ if (ike_alg_register_enc(&encrypt_desc_twofish_ssh) < 0)
+ plog("ike_alg_twofish_init(): Experimental OAKLEY_TWOFISH_CBC_SSH activation failed");
+
+ return ret;
+}
+/*
+IKE_ALG_INIT_NAME: ike_alg_twofish_init
+*/
diff --git a/programs/pluto/alg_info.c b/programs/pluto/alg_info.c
new file mode 100644
index 000000000..4ac7f2ca9
--- /dev/null
+++ b/programs/pluto/alg_info.c
@@ -0,0 +1,1197 @@
+/*
+ * Algorithm info parsing and creation functions
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: alg_info.c,v 1.5 2004/09/29 22:42:49 as Exp $
+ *
+ * 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.
+ */
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+#include <pfkeyv2.h>
+
+#include "alg_info.h"
+#include "constants.h"
+#ifndef NO_PLUTO
+#include "defs.h"
+#include "log.h"
+#include "whack.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+#include "kernel_alg.h"
+#include "ike_alg.h"
+#else
+/*
+ * macros/functions for compilation without pluto (eg: spi for manual conns)
+ */
+#include <assert.h>
+#define passert(x) assert(x)
+extern int debug; /* eg: spi.c */
+#define DBG(cond, action) { if (debug) { action ; } }
+#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
+#define RC_LOG_SERIOUS
+#define loglog(x, args...) fprintf(stderr, ##args);
+#define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
+void * alloc_bytes(size_t size, const char *name) {
+ void *p=malloc(size);
+ if (p == NULL)
+ fprintf(stderr, "unable to malloc %lu bytes for %s",
+ (unsigned long) size, name);
+ memset(p, '\0', size);
+ return p;
+}
+#define pfreeany(ptr) free(ptr)
+#endif /* NO_PLUTO */
+
+/*
+ * sadb/ESP aa attrib converters
+ */
+int
+alg_info_esp_aa2sadb(int auth)
+{
+ int sadb_aalg = 0;
+
+ switch(auth) {
+ case AUTH_ALGORITHM_HMAC_MD5:
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ sadb_aalg = auth + 1;
+ break;
+ case AUTH_ALGORITHM_HMAC_SHA2_256:
+ case AUTH_ALGORITHM_HMAC_SHA2_384:
+ case AUTH_ALGORITHM_HMAC_SHA2_512:
+ case AUTH_ALGORITHM_HMAC_RIPEMD:
+ sadb_aalg = auth;
+ break;
+ default:
+ /* loose ... */
+ sadb_aalg = auth;
+ }
+ return sadb_aalg;
+}
+
+int /* __attribute__ ((unused)) */
+alg_info_esp_sadb2aa(int sadb_aalg)
+{
+ int auth = 0;
+
+ switch(sadb_aalg) {
+ case SADB_AALG_MD5_HMAC:
+ case SADB_AALG_SHA1_HMAC:
+ auth = sadb_aalg - 1;
+ break;
+ /* since they are the same ... :) */
+ case AUTH_ALGORITHM_HMAC_SHA2_256:
+ case AUTH_ALGORITHM_HMAC_SHA2_384:
+ case AUTH_ALGORITHM_HMAC_SHA2_512:
+ case AUTH_ALGORITHM_HMAC_RIPEMD:
+ auth = sadb_aalg;
+ break;
+ default:
+ /* loose ... */
+ auth = sadb_aalg;
+ }
+ return auth;
+}
+
+/*
+ * Search enum_name array with in prefixed uppercase
+ */
+static int
+enum_search_prefix (enum_names *ed, const char *prefix, const char *str, int strlen)
+{
+ char buf[64];
+ char *ptr;
+ int ret;
+ int len = sizeof(buf) - 1; /* reserve space for final \0 */
+
+ for (ptr = buf; *prefix; *ptr++ = *prefix++, len--);
+ while (strlen-- && len-- && *str) *ptr++ = toupper(*str++);
+ *ptr = 0;
+
+ DBG(DBG_CRYPT,
+ DBG_log("enum_search_prefix () calling enum_search(%p, \"%s\")"
+ , ed, buf)
+ )
+ ret = enum_search(ed, buf);
+ return ret;
+}
+
+/*
+ * Search enum_name array with in prefixed and postfixed uppercase
+ */
+static int
+enum_search_ppfix (enum_names *ed, const char *prefix, const char *postfix, const char *str, int strlen)
+{
+ char buf[64];
+ char *ptr;
+ int ret;
+ int len = sizeof(buf) - 1; /* reserve space for final \0 */
+
+ for (ptr = buf; *prefix; *ptr++ = *prefix++, len--);
+ while (strlen-- && len-- && *str) *ptr++ = toupper(*str++);
+ while (len-- && *postfix) *ptr++ = *postfix++;
+ *ptr = 0;
+
+ DBG(DBG_CRYPT,
+ DBG_log("enum_search_ppfixi () calling enum_search(%p, \"%s\")"
+ , ed, buf)
+ )
+ ret = enum_search(ed, buf);
+ return ret;
+}
+
+/*
+ * Search esp_transformid_names for a match, eg:
+ * "3des" <=> "ESP_3DES"
+ */
+#define ESP_MAGIC_ID 0x00ffff01
+
+static int
+ealg_getbyname_esp(const char *const str, int len)
+{
+ if (!str || !*str)
+ return -1;
+
+ /* leave special case for eg: "id248" string */
+ if (strcmp("id", str) == 0)
+ return ESP_MAGIC_ID;
+
+ return enum_search_prefix(&esp_transformid_names, "ESP_", str, len);
+}
+
+/*
+ * Search auth_alg_names for a match, eg:
+ * "md5" <=> "AUTH_ALGORITHM_HMAC_MD5"
+ */
+static int
+aalg_getbyname_esp(const char *const str, int len)
+{
+ int ret;
+ unsigned num;
+
+ if (!str || !*str)
+ return -1;
+
+ ret = enum_search_prefix(&auth_alg_names,"AUTH_ALGORITHM_HMAC_", str ,len);
+ if (ret >= 0)
+ return ret;
+
+ ret = enum_search_prefix(&auth_alg_names,"AUTH_ALGORITHM_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ sscanf(str, "id%d%n", &ret, &num);
+ return (ret >= 0 && num != strlen(str))? -1 : ret;
+}
+
+static int
+modp_getbyname_esp(const char *const str, int len)
+{
+ int ret;
+
+ if (!str || !*str)
+ return -1;
+
+ ret = enum_search_prefix(&oakley_group_names,"OAKLEY_GROUP_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ ret = enum_search_ppfix(&oakley_group_names, "OAKLEY_GROUP_", " (extension)", str, len);
+ return ret;
+}
+
+void
+alg_info_free(struct alg_info *alg_info)
+{
+ pfreeany(alg_info);
+}
+
+/*
+ * Raw add routine: only checks for no duplicates
+ */
+static void
+__alg_info_esp_add (struct alg_info_esp *alg_info, int ealg_id, unsigned ek_bits, int aalg_id, unsigned ak_bits)
+{
+ struct esp_info *esp_info=alg_info->esp;
+ unsigned cnt = alg_info->alg_info_cnt, i;
+
+ /* check for overflows */
+ passert(cnt < elemsof(alg_info->esp));
+
+ /* dont add duplicates */
+ for (i = 0; i < cnt; i++)
+ {
+ if (esp_info[i].esp_ealg_id == ealg_id
+ && (!ek_bits || esp_info[i].esp_ealg_keylen == ek_bits)
+ && esp_info[i].esp_aalg_id == aalg_id
+ && (!ak_bits || esp_info[i].esp_aalg_keylen == ak_bits))
+ return;
+ }
+
+ esp_info[cnt].esp_ealg_id = ealg_id;
+ esp_info[cnt].esp_ealg_keylen = ek_bits;
+ esp_info[cnt].esp_aalg_id = aalg_id;
+ esp_info[cnt].esp_aalg_keylen = ak_bits;
+
+ /* sadb values */
+ esp_info[cnt].encryptalg = ealg_id;
+ esp_info[cnt].authalg = alg_info_esp_aa2sadb(aalg_id);
+ alg_info->alg_info_cnt++;
+
+ DBG(DBG_CRYPT,
+ DBG_log("__alg_info_esp_add() ealg=%d aalg=%d cnt=%d"
+ , ealg_id, aalg_id, alg_info->alg_info_cnt)
+ )
+}
+
+/*
+ * Add ESP alg info _with_ logic (policy):
+ */
+static void
+alg_info_esp_add (struct alg_info *alg_info, int ealg_id, int ek_bits, int aalg_id, int ak_bits)
+{
+ /* Policy: default to 3DES */
+ if (ealg_id == 0)
+ ealg_id = ESP_3DES;
+
+ if (ealg_id > 0)
+ {
+#ifndef NO_PLUTO
+ if (aalg_id > 0)
+#else
+ /* Allow no auth for manual conns (from spi.c) */
+ if (aalg_id >= 0)
+#endif
+ __alg_info_esp_add((struct alg_info_esp *)alg_info,
+ ealg_id, ek_bits,
+ aalg_id, ak_bits);
+ else
+ {
+ /* Policy: default to MD5 and SHA1 */
+ __alg_info_esp_add((struct alg_info_esp *)alg_info,
+ ealg_id, ek_bits,
+ AUTH_ALGORITHM_HMAC_MD5, ak_bits);
+ __alg_info_esp_add((struct alg_info_esp *)alg_info,
+ ealg_id, ek_bits,
+ AUTH_ALGORITHM_HMAC_SHA1, ak_bits);
+ }
+ }
+}
+
+#ifndef NO_PLUTO
+/**************************************
+ *
+ * IKE alg
+ *
+ *************************************/
+/*
+ * Search oakley_enc_names for a match, eg:
+ * "3des_cbc" <=> "OAKLEY_3DES_CBC"
+ */
+static int
+ealg_getbyname_ike(const char *const str, int len)
+{
+ int ret;
+
+ if (!str || !*str)
+ return -1;
+
+ ret = enum_search_prefix(&oakley_enc_names,"OAKLEY_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ ret = enum_search_ppfix(&oakley_enc_names, "OAKLEY_", "_CBC", str, len);
+ return ret;
+}
+
+/*
+ * Search oakley_hash_names for a match, eg:
+ * "md5" <=> "OAKLEY_MD5"
+ */
+static int
+aalg_getbyname_ike(const char *const str, int len)
+{
+ int ret;
+ unsigned num;
+
+ if (!str || !*str)
+ return -1;
+
+ ret = enum_search_prefix(&oakley_hash_names,"OAKLEY_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ sscanf(str, "id%d%n", &ret, &num);
+ return (ret >=0 && num != strlen(str))? -1 : ret;
+}
+
+/*
+ * Search oakley_group_names for a match, eg:
+ * "modp1024" <=> "OAKLEY_GROUP_MODP1024"
+ */
+static int
+modp_getbyname_ike(const char *const str, int len)
+{
+ int ret;
+
+ if (!str || !*str)
+ return -1;
+
+ ret = enum_search_prefix(&oakley_group_names,"OAKLEY_GROUP_", str, len);
+ if (ret >= 0)
+ return ret;
+
+ ret = enum_search_ppfix(&oakley_group_names, "OAKLEY_GROUP_", " (extension)", str, len);
+ return ret;
+}
+
+static void
+__alg_info_ike_add (struct alg_info_ike *alg_info, int ealg_id, unsigned ek_bits, int aalg_id, unsigned ak_bits, int modp_id)
+{
+ struct ike_info *ike_info = alg_info->ike;
+ unsigned cnt = alg_info->alg_info_cnt;
+ unsigned i;
+
+ /* check for overflows */
+ passert(cnt < elemsof(alg_info->ike));
+
+ /* dont add duplicates */
+ for (i = 0;i < cnt; i++)
+ {
+ if (ike_info[i].ike_ealg == ealg_id
+ && (!ek_bits || ike_info[i].ike_eklen == ek_bits)
+ && ike_info[i].ike_halg == aalg_id
+ && (!ak_bits || ike_info[i].ike_hklen == ak_bits)
+ && ike_info[i].ike_modp==modp_id)
+ return;
+ }
+
+ ike_info[cnt].ike_ealg = ealg_id;
+ ike_info[cnt].ike_eklen = ek_bits;
+ ike_info[cnt].ike_halg = aalg_id;
+ ike_info[cnt].ike_hklen = ak_bits;
+ ike_info[cnt].ike_modp = modp_id;
+ alg_info->alg_info_cnt++;
+
+ DBG(DBG_CRYPT,
+ DBG_log("__alg_info_ike_add() ealg=%d aalg=%d modp_id=%d, cnt=%d"
+ , ealg_id, aalg_id, modp_id
+ , alg_info->alg_info_cnt)
+ )
+}
+
+/*
+ * Proposals will be built by looping over default_ike_groups array and
+ * merging alg_info (ike_info) contents
+ */
+
+static int default_ike_groups[] = {
+ OAKLEY_GROUP_MODP1536,
+ OAKLEY_GROUP_MODP1024
+};
+
+/*
+ * Add IKE alg info _with_ logic (policy):
+ */
+static void
+alg_info_ike_add (struct alg_info *alg_info, int ealg_id, int ek_bits, int aalg_id, int ak_bits, int modp_id)
+{
+ int i = 0;
+ int n_groups = elemsof(default_ike_groups);
+
+ /* if specified modp_id avoid loop over default_ike_groups */
+ if (modp_id)
+ {
+ n_groups=0;
+ goto in_loop;
+ }
+
+ for (; n_groups--; i++)
+ {
+ modp_id = default_ike_groups[i];
+in_loop:
+ /* Policy: default to 3DES */
+ if (ealg_id == 0)
+ ealg_id = OAKLEY_3DES_CBC;
+
+ if (ealg_id > 0)
+ {
+ if (aalg_id > 0)
+ __alg_info_ike_add((struct alg_info_ike *)alg_info,
+ ealg_id, ek_bits,
+ aalg_id, ak_bits,
+ modp_id);
+ else
+ {
+ /* Policy: default to MD5 and SHA */
+ __alg_info_ike_add((struct alg_info_ike *)alg_info,
+ ealg_id, ek_bits,
+ OAKLEY_MD5, ak_bits,
+ modp_id);
+ __alg_info_ike_add((struct alg_info_ike *)alg_info,
+ ealg_id, ek_bits,
+ OAKLEY_SHA, ak_bits,
+ modp_id);
+ }
+ }
+ }
+}
+#endif /* NO_PLUTO */
+
+/*
+ * Creates a new alg_info by parsing passed string
+ */
+enum parser_state_esp {
+ ST_INI,
+ ST_EA, /* encrypt algo */
+ ST_EA_END,
+ ST_EK, /* enc. key length */
+ ST_EK_END,
+ ST_AA, /* auth algo */
+ ST_AA_END,
+ ST_AK, /* auth. key length */
+ ST_AK_END,
+ ST_MODP, /* modp spec */
+ ST_FLAG_STRICT,
+ ST_END,
+ ST_EOF,
+ ST_ERR
+};
+
+static const char *parser_state_esp_names[] = {
+ "ST_INI",
+ "ST_EA",
+ "ST_EA_END",
+ "ST_EK",
+ "ST_EK_END",
+ "ST_AA",
+ "ST_AA_END",
+ "ST_AK",
+ "ST_AK_END",
+ "ST_MOPD",
+ "ST_FLAG_STRICT",
+ "ST_END",
+ "ST_EOF",
+ "ST_ERR"
+};
+
+static const char*
+parser_state_name_esp(enum parser_state_esp state)
+{
+ return parser_state_esp_names[state];
+}
+
+/* XXX:jjo to implement different parser for ESP and IKE */
+struct parser_context {
+ unsigned state, old_state;
+ unsigned protoid;
+ char ealg_buf[16];
+ char aalg_buf[16];
+ char modp_buf[16];
+ int (*ealg_getbyname)(const char *const str, int len);
+ int (*aalg_getbyname)(const char *const str, int len);
+ int (*modp_getbyname)(const char *const str, int len);
+ char *ealg_str;
+ char *aalg_str;
+ char *modp_str;
+ int eklen;
+ int aklen;
+ int ch;
+ const char *err;
+};
+
+static inline void
+parser_set_state(struct parser_context *p_ctx, enum parser_state_esp state)
+{
+ if (state != p_ctx->state)
+ {
+ p_ctx->old_state = p_ctx->state;
+ p_ctx->state = state;
+ }
+}
+
+static int
+parser_machine(struct parser_context *p_ctx)
+{
+ int ch = p_ctx->ch;
+
+ /* special 'absolute' cases */
+ p_ctx->err = "No error.";
+
+ /* chars that end algo strings */
+ switch (ch){
+ case 0: /* end-of-string */
+ case '!': /* flag as strict algo list */
+ case ',': /* algo string separator */
+ switch (p_ctx->state) {
+ case ST_EA:
+ case ST_EK:
+ case ST_AA:
+ case ST_AK:
+ case ST_MODP:
+ case ST_FLAG_STRICT:
+ {
+ enum parser_state_esp next_state = 0;
+
+ switch (ch) {
+ case 0:
+ next_state = ST_EOF;
+ break;
+ case ',':
+ next_state = ST_END;
+ break;
+ case '!':
+ next_state = ST_FLAG_STRICT;
+ break;
+ }
+ /* ch? parser_set_state(p_ctx, ST_END) : parser_set_state(p_ctx, ST_EOF) ; */
+ parser_set_state(p_ctx, next_state);
+ goto out;
+ }
+ default:
+ p_ctx->err = "String ended with invalid char";
+ goto err;
+ }
+ }
+re_eval:
+ switch (p_ctx->state) {
+ case ST_INI:
+ if (isspace(ch))
+ break;
+ if (isalnum(ch))
+ {
+ *(p_ctx->ealg_str++) = ch;
+ parser_set_state(p_ctx, ST_EA);
+ break;
+ }
+ p_ctx->err = "No alphanum. char initially found";
+ goto err;
+ case ST_EA:
+ if (isalpha(ch) || ch == '_')
+ {
+ *(p_ctx->ealg_str++) = ch;
+ break;
+ }
+ if (isdigit(ch))
+ {
+ /* bravely switch to enc keylen */
+ *(p_ctx->ealg_str) = 0;
+ parser_set_state(p_ctx, ST_EK);
+ goto re_eval;
+ }
+ if (ch == '-')
+ {
+ *(p_ctx->ealg_str) = 0;
+ parser_set_state(p_ctx, ST_EA_END);
+ break;
+ }
+ p_ctx->err = "No valid char found after enc alg string";
+ goto err;
+ case ST_EA_END:
+ if (isdigit(ch))
+ {
+ /* bravely switch to enc keylen */
+ parser_set_state(p_ctx, ST_EK);
+ goto re_eval;
+ }
+ if (isalpha(ch))
+ {
+ parser_set_state(p_ctx, ST_AA);
+ goto re_eval;
+ }
+ p_ctx->err = "No alphanum char found after enc alg separator";
+ goto err;
+ case ST_EK:
+ if (ch == '-')
+ {
+ parser_set_state(p_ctx, ST_EK_END);
+ break;
+ }
+ if (isdigit(ch))
+ {
+ p_ctx->eklen = p_ctx->eklen*10 + ch - '0';
+ break;
+ }
+ p_ctx->err = "Non digit or valid separator found while reading enc keylen";
+ goto err;
+ case ST_EK_END:
+ if (isalpha(ch))
+ {
+ parser_set_state(p_ctx, ST_AA);
+ goto re_eval;
+ }
+ p_ctx->err = "Non alpha char found after enc keylen end separator";
+ goto err;
+ case ST_AA:
+ if (ch == '-')
+ {
+ *(p_ctx->aalg_str++) = 0;
+ parser_set_state(p_ctx, ST_AA_END);
+ break;
+ }
+ if (isalnum(ch) || ch == '_')
+ {
+ *(p_ctx->aalg_str++) = ch;
+ break;
+ }
+ p_ctx->err = "Non alphanum or valid separator found in auth string";
+ goto err;
+ case ST_AA_END:
+ if (isdigit(ch))
+ {
+ parser_set_state(p_ctx, ST_AK);
+ goto re_eval;
+ }
+ /* Only allow modpXXXX string if we have a modp_getbyname method */
+ if ((p_ctx->modp_getbyname) && isalpha(ch))
+ {
+ parser_set_state(p_ctx, ST_MODP);
+ goto re_eval;
+ }
+ p_ctx->err = "Non initial digit found for auth keylen";
+ goto err;
+ case ST_AK:
+ if (ch=='-')
+ {
+ parser_set_state(p_ctx, ST_AK_END);
+ break;
+ }
+ if (isdigit(ch))
+ {
+ p_ctx->aklen = p_ctx->aklen*10 + ch - '0';
+ break;
+ }
+ p_ctx->err = "Non digit found for auth keylen";
+ goto err;
+ case ST_AK_END:
+ /* Only allow modpXXXX string if we have a modp_getbyname method */
+ if ((p_ctx->modp_getbyname) && isalpha(ch))
+ {
+ parser_set_state(p_ctx, ST_MODP);
+ goto re_eval;
+ }
+ p_ctx->err = "Non alpha char found after auth keylen";
+ goto err;
+ case ST_MODP:
+ if (isalnum(ch))
+ {
+ *(p_ctx->modp_str++) = ch;
+ break;
+ }
+ p_ctx->err = "Non alphanum char found after in modp string";
+ goto err;
+ case ST_FLAG_STRICT:
+ if (ch == 0)
+ parser_set_state(p_ctx, ST_END);
+ p_ctx->err = "Flags character(s) must be at end of whole string";
+ goto err;
+
+ /* XXX */
+ case ST_END:
+ case ST_EOF:
+ case ST_ERR:
+ break;
+ /* XXX */
+ }
+out:
+ return p_ctx->state;
+err:
+ parser_set_state(p_ctx, ST_ERR);
+ return ST_ERR;
+}
+
+/*
+ * Must be called for each "new" char, with new
+ * character in ctx.ch
+ */
+static void
+parser_init(struct parser_context *p_ctx, unsigned protoid)
+{
+ memset(p_ctx, 0, sizeof (*p_ctx));
+ p_ctx->protoid = protoid; /* XXX: jjo */
+ p_ctx->protoid = PROTO_IPSEC_ESP;
+ p_ctx->ealg_str = p_ctx->ealg_buf;
+ p_ctx->aalg_str = p_ctx->aalg_buf;
+ p_ctx->modp_str = p_ctx->modp_buf;
+ p_ctx->state = ST_INI;
+
+ switch (protoid) {
+#ifndef NO_PLUTO
+ case PROTO_ISAKMP:
+ p_ctx->ealg_getbyname = ealg_getbyname_ike;
+ p_ctx->aalg_getbyname = aalg_getbyname_ike;
+ p_ctx->modp_getbyname = modp_getbyname_ike;
+ break;
+#endif
+ case PROTO_IPSEC_ESP:
+ p_ctx->ealg_getbyname = ealg_getbyname_esp;
+ p_ctx->aalg_getbyname = aalg_getbyname_esp;
+ break;
+ }
+}
+
+static int
+parser_alg_info_add(struct parser_context *p_ctx, struct alg_info *alg_info)
+{
+ int ealg_id = 0;
+ int aalg_id = 0;
+ int modp_id = 0;
+#ifndef NO_PLUTO
+ const struct oakley_group_desc *gd;
+#endif
+
+ if (*p_ctx->ealg_buf)
+ {
+ ealg_id = p_ctx->ealg_getbyname(p_ctx->ealg_buf, strlen(p_ctx->ealg_buf));
+ if (ealg_id == ESP_MAGIC_ID)
+ {
+ ealg_id = p_ctx->eklen;
+ p_ctx->eklen = 0;
+ }
+ if (ealg_id < 0)
+ {
+ p_ctx->err = "enc_alg not found";
+ return -1;
+ }
+ DBG(DBG_CRYPT,
+ DBG_log("parser_alg_info_add() ealg_getbyname(\"%s\")=%d"
+ , p_ctx->ealg_buf
+ , ealg_id)
+ )
+ }
+ if (*p_ctx->aalg_buf)
+ {
+ aalg_id = p_ctx->aalg_getbyname(p_ctx->aalg_buf, strlen(p_ctx->aalg_buf));
+ if (aalg_id < 0)
+ {
+ p_ctx->err = "hash_alg not found";
+ return -1;
+ }
+ DBG(DBG_CRYPT,
+ DBG_log("parser_alg_info_add() aalg_getbyname(\"%s\")=%d"
+ , p_ctx->aalg_buf
+ , aalg_id)
+ )
+ }
+ if (p_ctx->modp_getbyname && *p_ctx->modp_buf)
+ {
+ modp_id = p_ctx->modp_getbyname(p_ctx->modp_buf, strlen(p_ctx->modp_buf));
+ if (modp_id < 0)
+ {
+ p_ctx->err = "modp group not found";
+ return -1;
+ }
+ DBG(DBG_CRYPT,
+ DBG_log("parser_alg_info_add() modp_getbyname(\"%s\")=%d"
+ , p_ctx->modp_buf
+ , modp_id)
+ )
+ }
+ switch (alg_info->alg_info_protoid) {
+ case PROTO_IPSEC_ESP:
+ alg_info_esp_add(alg_info,
+ ealg_id, p_ctx->eklen,
+ aalg_id, p_ctx->aklen);
+ break;
+#ifndef NO_PLUTO
+ case PROTO_ISAKMP:
+ if (modp_id && !(gd = lookup_group(modp_id)))
+ {
+ p_ctx->err = "found modp group id, but not supported";
+ return -1;
+ }
+ alg_info_ike_add(alg_info,
+ ealg_id, p_ctx->eklen,
+ aalg_id, p_ctx->aklen,
+ modp_id);
+ break;
+#endif
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static int
+alg_info_parse_str (struct alg_info *alg_info, const char *alg_str, const char **err_p)
+{
+ struct parser_context ctx;
+ int ret;
+ const char *ptr;
+ static char err_buf[256];
+
+ *err_buf = 0;
+ parser_init(&ctx, alg_info->alg_info_protoid);
+ if (err_p)
+ *err_p = NULL;
+
+ /* use default if nul esp string */
+ if (!*alg_str)
+ {
+ switch (alg_info->alg_info_protoid) {
+#ifndef NO_PLUTO
+ case PROTO_ISAKMP:
+ alg_info_ike_add(alg_info, 0, 0, 0, 0, 0);
+ return 0;
+#endif
+ case PROTO_IPSEC_ESP:
+ alg_info_esp_add(alg_info, 0, 0, 0, 0);
+ return 0;
+ default:
+ /* IMPOSSIBLE */
+ passert(alg_info->alg_info_protoid);
+ }
+ }
+
+ for (ret = 0, ptr = alg_str; ret < ST_EOF;)
+ {
+ ctx.ch = *ptr++;
+ ret = parser_machine(&ctx);
+
+ switch (ret) {
+ case ST_FLAG_STRICT:
+ alg_info->alg_info_flags |= ALG_INFO_F_STRICT;
+ break;
+ case ST_END:
+ case ST_EOF:
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_parse_str() ealg_buf=%s aalg_buf=%s"
+ "eklen=%d aklen=%d",
+ ctx.ealg_buf, ctx.aalg_buf,
+ ctx.eklen, ctx.aklen)
+ )
+ if (parser_alg_info_add(&ctx, alg_info) < 0)
+ {
+ snprintf(err_buf, sizeof(err_buf),
+ "%s, enc_alg=\"%s\", auth_alg=\"%s\", modp=\"%s\"",
+ ctx.err,
+ ctx.ealg_buf,
+ ctx.aalg_buf,
+ ctx.modp_buf);
+ goto err;
+ }
+ /* zero out for next run (ST_END) */
+ parser_init(&ctx, alg_info->alg_info_protoid);
+ break;
+ case ST_ERR:
+ snprintf(err_buf, sizeof(err_buf),
+ "%s, just after \"%.*s\" (old_state=%s)",
+ ctx.err,
+ (int)(ptr-alg_str-1), alg_str ,
+ parser_state_name_esp(ctx.old_state));
+ goto err;
+ default:
+ if (!ctx.ch)
+ break;
+ }
+ }
+ return 0;
+err:
+ if (err_p)
+ *err_p=err_buf;
+ return -1;
+}
+
+struct alg_info_esp *
+alg_info_esp_create_from_str (const char *alg_str, const char **err_p)
+{
+ struct alg_info_esp *alg_info_esp;
+ char esp_buf[256];
+ static char err_buf[256];
+ char *pfs_name;
+ int ret = 0;
+ /*
+ * alg_info storage should be sized dynamically
+ * but this may require 2passes to know
+ * transform count in advance.
+ */
+ alg_info_esp = alloc_thing (struct alg_info_esp, "alg_info_esp");
+ if (!alg_info_esp)
+ goto out;
+
+ pfs_name=index (alg_str, ';');
+ if (pfs_name)
+ {
+ memcpy(esp_buf, alg_str, pfs_name-alg_str);
+ esp_buf[pfs_name-alg_str] = 0;
+ alg_str = esp_buf;
+ pfs_name++;
+
+ /* if pfs strings AND first char is not '0' */
+ if (*pfs_name && pfs_name[0] != '0')
+ {
+ ret = modp_getbyname_esp(pfs_name, strlen(pfs_name));
+ if (ret < 0)
+ {
+ /* Bomb if pfsgroup not found */
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_esp_create_from_str(): pfsgroup \"%s\" not found"
+ , pfs_name)
+ )
+ if (*err_p)
+ {
+ snprintf(err_buf, sizeof(err_buf),
+ "pfsgroup \"%s\" not found",
+ pfs_name);
+
+ *err_p = err_buf;
+ }
+ goto out;
+ }
+ alg_info_esp->esp_pfsgroup = ret;
+ }
+ }
+ else
+ alg_info_esp->esp_pfsgroup = 0;
+
+ alg_info_esp->alg_info_protoid = PROTO_IPSEC_ESP;
+ ret = alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str, err_p) ;
+out:
+ if (ret < 0)
+ {
+ pfreeany(alg_info_esp);
+ alg_info_esp = NULL;
+ }
+ return alg_info_esp;
+}
+
+#ifndef NO_PLUTO
+struct alg_info_ike *
+alg_info_ike_create_from_str (const char *alg_str, const char **err_p)
+{
+ struct alg_info_ike *alg_info_ike;
+ /*
+ * alg_info storage should be sized dynamically
+ * but this may require 2passes to know
+ * transform count in advance.
+ */
+ alg_info_ike = alloc_thing (struct alg_info_ike, "alg_info_ike");
+ alg_info_ike->alg_info_protoid = PROTO_ISAKMP;
+
+ if (alg_info_parse_str((struct alg_info *)alg_info_ike,
+ alg_str, err_p) < 0)
+ {
+ pfreeany(alg_info_ike);
+ return NULL;
+ }
+ return alg_info_ike;
+}
+#endif
+
+/*
+ * alg_info struct can be shared by
+ * several connections instances,
+ * handle free() with ref_cnts
+ */
+void
+alg_info_addref(struct alg_info *alg_info)
+{
+ if (alg_info != NULL)
+ {
+ alg_info->ref_cnt++;
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_addref() alg_info->ref_cnt=%d"
+ , alg_info->ref_cnt)
+ )
+ }
+}
+
+void
+alg_info_delref(struct alg_info **alg_info_p)
+{
+ struct alg_info *alg_info = *alg_info_p;
+
+ if (alg_info != NULL)
+ {
+ passert(alg_info->ref_cnt != 0);
+ alg_info->ref_cnt--;
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_delref() alg_info->ref_cnt=%d"
+ , alg_info->ref_cnt)
+ )
+ if (alg_info->ref_cnt == 0)
+ {
+ DBG(DBG_CRYPT,
+ DBG_log("alg_info_delref() freeing alg_info")
+ )
+ alg_info_free(alg_info);
+ }
+ *alg_info_p = NULL;
+ }
+}
+
+/* snprint already parsed transform list (alg_info) */
+int
+alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info)
+{
+ char *ptr = buf;
+ int np = 0;
+ struct esp_info *esp_info;
+#ifndef NO_PLUTO
+ struct ike_info *ike_info;
+#endif
+ int cnt;
+
+ switch (alg_info->alg_info_protoid) {
+ case PROTO_IPSEC_ESP:
+ {
+ struct alg_info_esp *alg_info_esp = (struct alg_info_esp *)alg_info;
+
+ ALG_INFO_ESP_FOREACH(alg_info_esp, esp_info, cnt)
+ {
+ np = snprintf(ptr, buflen, "%d_%03d-%d, "
+ , esp_info->esp_ealg_id
+ , (int)esp_info->esp_ealg_keylen
+ , esp_info->esp_aalg_id);
+ ptr += np;
+ buflen -= np;
+ if (buflen < 0)
+ goto out;
+ }
+ if (alg_info_esp->esp_pfsgroup)
+ {
+ np = snprintf(ptr, buflen, "; pfsgroup=%d; "
+ , alg_info_esp->esp_pfsgroup);
+ ptr += np;
+ buflen -= np;
+ if (buflen < 0)
+ goto out;
+ }
+ break;
+ }
+#ifndef NO_PLUTO
+ case PROTO_ISAKMP:
+ ALG_INFO_IKE_FOREACH((struct alg_info_ike *)alg_info, ike_info, cnt)
+ {
+ np = snprintf(ptr, buflen, "%d_%03d-%d-%d, "
+ , ike_info->ike_ealg
+ , (int)ike_info->ike_eklen
+ , ike_info->ike_halg
+ , ike_info->ike_modp);
+ ptr += np;
+ buflen -= np;
+ if (buflen < 0)
+ goto out;
+ }
+ break;
+#endif
+ default:
+ np = snprintf(buf, buflen, "INVALID protoid=%d\n"
+ , alg_info->alg_info_protoid);
+ ptr += np;
+ buflen -= np;
+ goto out;
+ }
+
+ np = snprintf(ptr, buflen, "%s"
+ , alg_info->alg_info_flags & ALG_INFO_F_STRICT?
+ "strict":"");
+ ptr += np;
+ buflen -= np;
+out:
+ if (buflen < 0)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "buffer space exhausted in alg_info_snprint_ike(), buflen=%d"
+ , buflen);
+ }
+
+ return ptr - buf;
+}
+
+#ifndef NO_PLUTO
+int
+alg_info_snprint_esp(char *buf, int buflen, struct alg_info_esp *alg_info)
+{
+ char *ptr = buf;
+
+ int cnt = alg_info->alg_info_cnt;
+ struct esp_info *esp_info = alg_info->esp;
+
+ while (cnt--)
+ {
+ if (kernel_alg_esp_enc_ok(esp_info->esp_ealg_id, 0, NULL)
+ && kernel_alg_esp_auth_ok(esp_info->esp_aalg_id, NULL))
+ {
+ u_int eklen = (esp_info->esp_ealg_keylen)
+ ? esp_info->esp_ealg_keylen
+ : kernel_alg_esp_enc_keylen(esp_info->esp_ealg_id)
+ * BITS_PER_BYTE;
+
+ u_int aklen = esp_info->esp_aalg_keylen
+ ? esp_info->esp_aalg_keylen
+ : kernel_alg_esp_auth_keylen(esp_info->esp_aalg_id)
+ * BITS_PER_BYTE;
+
+ int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d, ",
+ esp_info->esp_ealg_id, eklen,
+ esp_info->esp_aalg_id, aklen);
+ ptr += ret;
+ buflen -= ret;
+ if (buflen < 0)
+ break;
+ }
+ esp_info++;
+ }
+ return ptr - buf;
+}
+
+int
+alg_info_snprint_ike(char *buf, int buflen, struct alg_info_ike *alg_info)
+{
+ char *ptr = buf;
+
+ int cnt = alg_info->alg_info_cnt;
+ struct ike_info *ike_info = alg_info->ike;
+
+ while (cnt--)
+ {
+ struct encrypt_desc *enc_desc = ike_alg_get_encrypter(ike_info->ike_ealg);
+ struct hash_desc *hash_desc = ike_alg_get_hasher(ike_info->ike_halg);
+
+ if (enc_desc != NULL && hash_desc != NULL
+ && lookup_group(ike_info->ike_modp))
+ {
+
+ u_int eklen = (ike_info->ike_eklen)
+ ? ike_info->ike_eklen
+ : enc_desc->keydeflen;
+
+ u_int aklen = (ike_info->ike_hklen)
+ ? ike_info->ike_hklen
+ : hash_desc->hash_digest_size * BITS_PER_BYTE;
+
+ int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d-%d, ",
+ ike_info->ike_ealg, eklen,
+ ike_info->ike_halg, aklen,
+ ike_info->ike_modp);
+ ptr += ret;
+ buflen -= ret;
+ if (buflen < 0)
+ break;
+ }
+ ike_info++;
+ }
+ return ptr - buf;
+}
+#endif /* NO_PLUTO */
diff --git a/programs/pluto/alg_info.h b/programs/pluto/alg_info.h
new file mode 100644
index 000000000..cd2011dcc
--- /dev/null
+++ b/programs/pluto/alg_info.h
@@ -0,0 +1,85 @@
+/* Algorithm info parsing and creation functions
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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: alg_info.h,v 1.4 2004/09/29 22:39:44 as Exp $
+ */
+
+#ifndef ALG_INFO_H
+#define ALG_INFO_H
+
+struct esp_info {
+ u_int8_t transid; /* ESP transform */
+ u_int16_t auth; /* AUTH */
+ size_t enckeylen; /* keylength for ESP transform */
+ size_t authkeylen; /* keylength for AUTH */
+ u_int8_t encryptalg; /* normally encryptalg=transid */
+ u_int8_t authalg; /* normally authalg=auth+1 */
+};
+
+struct ike_info {
+ u_int16_t ike_ealg; /* high 16 bit nums for reserved */
+ u_int8_t ike_halg;
+ size_t ike_eklen;
+ size_t ike_hklen;
+ u_int16_t ike_modp;
+};
+
+#define ALG_INFO_COMMON \
+ int alg_info_cnt; \
+ int ref_cnt; \
+ unsigned alg_info_flags; \
+ unsigned alg_info_protoid
+
+struct alg_info {
+ ALG_INFO_COMMON;
+};
+
+struct alg_info_esp {
+ ALG_INFO_COMMON;
+ struct esp_info esp[64];
+ int esp_pfsgroup;
+};
+
+struct alg_info_ike {
+ ALG_INFO_COMMON;
+ struct ike_info ike[64];
+};
+#define esp_ealg_id transid
+#define esp_aalg_id auth
+#define esp_ealg_keylen enckeylen /* bits */
+#define esp_aalg_keylen authkeylen /* bits */
+
+/* alg_info_flags bits */
+#define ALG_INFO_F_STRICT 0x01
+
+extern int alg_info_esp_aa2sadb(int auth);
+extern int alg_info_esp_sadb2aa(int sadb_aalg);
+extern void alg_info_free(struct alg_info *alg_info);
+extern void alg_info_addref(struct alg_info *alg_info);
+extern void alg_info_delref(struct alg_info **alg_info);
+extern struct alg_info_esp* alg_info_esp_create_from_str(const char *alg_str
+ , const char **err_p);
+extern struct alg_info_ike* alg_info_ike_create_from_str(const char *alg_str
+ , const char **err_p);
+extern int alg_info_parse(const char *str);
+extern int alg_info_snprint(char *buf, int buflen
+ , struct alg_info *alg_info);
+extern int alg_info_snprint_esp(char *buf, int buflen
+ , struct alg_info_esp *alg_info);
+extern int alg_info_snprint_ike(char *buf, int buflen
+ , struct alg_info_ike *alg_info);
+#define ALG_INFO_ESP_FOREACH(ai, ai_esp, i) \
+ for (i=(ai)->alg_info_cnt,ai_esp=(ai)->esp; i--; ai_esp++)
+#define ALG_INFO_IKE_FOREACH(ai, ai_ike, i) \
+ for (i=(ai)->alg_info_cnt,ai_ike=(ai)->ike; i--; ai_ike++)
+#endif /* ALG_INFO_H */
diff --git a/programs/pluto/asn1.c b/programs/pluto/asn1.c
new file mode 100644
index 000000000..0663bc490
--- /dev/null
+++ b/programs/pluto/asn1.c
@@ -0,0 +1,770 @@
+/* Simple ASN.1 parser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: asn1.c,v 1.16 2006/01/04 21:00:43 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "asn1.h"
+#include "oid.h"
+#include "log.h"
+
+/* some common prefabricated ASN.1 constants */
+
+static u_char ASN1_INTEGER_0_str[] = { 0x02, 0x00 };
+static u_char ASN1_INTEGER_1_str[] = { 0x02, 0x01, 0x01 };
+static u_char ASN1_INTEGER_2_str[] = { 0x02, 0x01, 0x02 };
+
+const chunk_t ASN1_INTEGER_0 = strchunk(ASN1_INTEGER_0_str);
+const chunk_t ASN1_INTEGER_1 = strchunk(ASN1_INTEGER_1_str);
+const chunk_t ASN1_INTEGER_2 = strchunk(ASN1_INTEGER_2_str);
+
+/* some popular algorithmIdentifiers */
+
+static u_char ASN1_md5_id_str[] = {
+ 0x30, 0x0C,
+ 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,
+ 0x05, 0x00
+};
+
+static u_char ASN1_sha1_id_str[] = {
+ 0x30, 0x09,
+ 0x06, 0x05, 0x2B, 0x0E,0x03, 0x02, 0x1A,
+ 0x05, 0x00
+};
+
+static u_char ASN1_md5WithRSA_id_str[] = {
+ 0x30, 0x0D,
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04,
+ 0x05, 0x00
+};
+
+static u_char ASN1_sha1WithRSA_id_str[] = {
+ 0x30, 0x0D,
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05,
+ 0x05, 0x00
+};
+
+static u_char ASN1_rsaEncryption_id_str[] = {
+ 0x30, 0x0D,
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
+ 0x05, 0x00
+};
+
+const chunk_t ASN1_md5_id = strchunk(ASN1_md5_id_str);
+const chunk_t ASN1_sha1_id = strchunk(ASN1_sha1_id_str);
+const chunk_t ASN1_rsaEncryption_id = strchunk(ASN1_rsaEncryption_id_str);
+const chunk_t ASN1_md5WithRSA_id = strchunk(ASN1_md5WithRSA_id_str);
+const chunk_t ASN1_sha1WithRSA_id = strchunk(ASN1_sha1WithRSA_id_str);
+
+/* ASN.1 definiton of an algorithmIdentifier */
+
+static const asn1Object_t algorithmIdentifierObjects[] = {
+ { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
+ { 1, "parameters", ASN1_EOC, ASN1_RAW } /* 2 */
+};
+
+#define ALGORITHM_ID_ALG 1
+#define ALGORITHM_ID_PARAMETERS 2
+#define ALGORITHM_ID_ROOF 3
+
+/*
+ * return the ASN.1 encoded algorithm identifier
+ */
+chunk_t
+asn1_algorithmIdentifier(int oid)
+{
+ switch (oid)
+ {
+ case OID_RSA_ENCRYPTION:
+ return ASN1_rsaEncryption_id;
+ case OID_MD5_WITH_RSA:
+ return ASN1_md5WithRSA_id;
+ case OID_SHA1_WITH_RSA:
+ return ASN1_sha1WithRSA_id;
+ case OID_MD5:
+ return ASN1_md5_id;
+ case OID_SHA1:
+ return ASN1_sha1_id;
+ default:
+ return empty_chunk;
+ }
+}
+
+/* If the oid is listed in the oid_names table then the corresponding
+ * position in the oid_names table is returned otherwise -1 is returned
+ */
+int
+known_oid(chunk_t object)
+{
+ int oid = 0;
+
+ while (object.len)
+ {
+ if (oid_names[oid].octet == *object.ptr)
+ {
+ if (--object.len == 0 || oid_names[oid].down == 0)
+ {
+ return oid; /* found terminal symbol */
+ }
+ else
+ {
+ object.ptr++; oid++; /* advance to next hex octet */
+ }
+ }
+ else
+ {
+ if (oid_names[oid].next)
+ oid = oid_names[oid].next;
+ else
+ return OID_UNKNOWN;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Decodes the length in bytes of an ASN.1 object
+ */
+u_int
+asn1_length(chunk_t *blob)
+{
+ u_char n;
+ size_t len;
+
+ /* advance from tag field on to length field */
+ blob->ptr++;
+ blob->len--;
+
+ /* read first octet of length field */
+ n = *blob->ptr++;
+ blob->len--;
+
+ if ((n & 0x80) == 0) /* single length octet */
+ return n;
+
+ /* composite length, determine number of length octets */
+ n &= 0x7f;
+
+ if (n > blob->len)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("number of length octets is larger than ASN.1 object")
+ )
+ return ASN1_INVALID_LENGTH;
+ }
+
+ if (n > sizeof(len))
+ {
+ DBG(DBG_PARSING,
+ DBG_log("number of length octets is larger than limit of %d octets"
+ , (int)sizeof(len))
+ )
+ return ASN1_INVALID_LENGTH;
+ }
+
+ len = 0;
+
+ while (n-- > 0)
+ {
+ len = 256*len + *blob->ptr++;
+ blob->len--;
+ }
+ return len;
+}
+
+/*
+ * codes ASN.1 lengths up to a size of 16'777'215 bytes
+ */
+void
+code_asn1_length(size_t length, chunk_t *code)
+{
+ if (length < 128)
+ {
+ code->ptr[0] = length;
+ code->len = 1;
+ }
+ else if (length < 256)
+ {
+ code->ptr[0] = 0x81;
+ code->ptr[1] = (u_char) length;
+ code->len = 2;
+ }
+ else if (length < 65536)
+ {
+ code->ptr[0] = 0x82;
+ code->ptr[1] = length >> 8;
+ code->ptr[2] = length & 0x00ff;
+ code->len = 3;
+ }
+ else
+ {
+ code->ptr[0] = 0x83;
+ code->ptr[1] = length >> 16;
+ code->ptr[2] = (length >> 8) & 0x00ff;
+ code->ptr[3] = length & 0x0000ff;
+ code->len = 4;
+ }
+}
+
+/*
+ * build an empty asn.1 object with tag and length fields already filled in
+ */
+u_char*
+build_asn1_object(chunk_t *object, asn1_t type, size_t datalen)
+{
+ u_char length_buf[4];
+ chunk_t length = { length_buf, 0 };
+ u_char *pos;
+
+ /* code the asn.1 length field */
+ code_asn1_length(datalen, &length);
+
+ /* allocate memory for the asn.1 TLV object */
+ object->len = 1 + length.len + datalen;
+ object->ptr = alloc_bytes(object->len, "asn1 object");
+
+ /* set position pointer at the start of the object */
+ pos = object->ptr;
+
+ /* copy the asn.1 tag field and advance the pointer */
+ *pos++ = type;
+
+ /* copy the asn.1 length field and advance the pointer */
+ chunkcpy(pos, length);
+
+ return pos;
+}
+
+/*
+ * build a simple ASN.1 object
+ */
+chunk_t
+asn1_simple_object(asn1_t tag, chunk_t content)
+{
+ chunk_t object;
+
+ u_char *pos = build_asn1_object(&object, tag, content.len);
+ chunkcpy(pos, content);
+
+ return object;
+}
+
+/* Build an ASN.1 object from a variable number of individual chunks.
+ * Depending on the mode, chunks either are moved ('m') or copied ('c').
+ */
+chunk_t
+asn1_wrap(asn1_t type, const char *mode, ...)
+{
+ chunk_t construct;
+ va_list chunks;
+ u_char *pos;
+ int i;
+ int count = strlen(mode);
+
+ /* sum up lengths of individual chunks */
+ va_start(chunks, mode);
+ construct.len = 0;
+ for (i = 0; i < count; i++)
+ {
+ chunk_t ch = va_arg(chunks, chunk_t);
+ construct.len += ch.len;
+ }
+ va_end(chunks);
+
+ /* allocate needed memory for construct */
+ pos = build_asn1_object(&construct, type, construct.len);
+
+ /* copy or move the chunks */
+ va_start(chunks, mode);
+ for (i = 0; i < count; i++)
+ {
+ chunk_t ch = va_arg(chunks, chunk_t);
+
+ switch (*mode++)
+ {
+ case 'm':
+ mv_chunk(&pos, ch);
+ break;
+ case 'c':
+ default:
+ chunkcpy(pos, ch);
+ }
+ }
+ va_end(chunks);
+
+ return construct;
+}
+
+/*
+ * convert a MP integer into a DER coded ASN.1 object
+ */
+chunk_t
+asn1_integer_from_mpz(const mpz_t value)
+{
+ size_t bits = mpz_sizeinbase(value, 2); /* size in bits */
+ size_t size = 1 + bits / BITS_PER_BYTE; /* size in bytes */
+ chunk_t n = mpz_to_n(value, size);
+
+ return asn1_wrap(ASN1_INTEGER, "m", n);
+}
+
+/*
+ * determines if a character string is of type ASN.1 printableString
+ */
+bool
+is_printablestring(chunk_t str)
+{
+ const char printablestring_charset[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
+ u_int i;
+
+ for (i = 0; i < str.len; i++)
+ {
+ if (strchr(printablestring_charset, str.ptr[i]) == NULL)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
+ */
+time_t
+asn1totime(const chunk_t *utctime, asn1_t type)
+{
+ struct tm t;
+ time_t tz_offset;
+ u_char *eot = NULL;
+
+ if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
+ {
+ tz_offset = 0; /* Zulu time with a zero time zone offset */
+ }
+ else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)
+ {
+ int tz_hour, tz_min;
+
+ sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
+ tz_offset = 3600*tz_hour + 60*tz_min; /* positive time zone offset */
+ }
+ else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)
+ {
+ int tz_hour, tz_min;
+
+ sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
+ tz_offset = -3600*tz_hour - 60*tz_min; /* negative time zone offset */
+ }
+ else
+ {
+ return 0; /* error in time format */
+ }
+
+ {
+ const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
+ "%4d%2d%2d%2d%2d";
+
+ sscanf(utctime->ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday,
+ &t.tm_hour, &t.tm_min);
+ }
+
+ /* is there a seconds field? */
+ if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
+ {
+ sscanf(eot-2, "%2d", &t.tm_sec);
+ }
+ else
+ {
+ t.tm_sec = 0;
+ }
+
+ /* representation of year */
+ if (t.tm_year >= 1900)
+ {
+ t.tm_year -= 1900;
+ }
+ else if (t.tm_year >= 100)
+ {
+ return 0;
+ }
+ else if (t.tm_year < 50)
+ {
+ t.tm_year += 100;
+ }
+
+ /* representation of month 0..11*/
+ t.tm_mon--;
+
+ /* set daylight saving time to off */
+ t.tm_isdst = 0;
+
+ /* compensate timezone */
+
+ return mktime(&t) - timezone - tz_offset;
+}
+
+/*
+ * convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
+ */
+chunk_t
+timetoasn1(const time_t *time, asn1_t type)
+{
+ int offset;
+ const char *format;
+ char buf[TIMETOA_BUF];
+ chunk_t formatted_time;
+ struct tm *t = gmtime(time);
+
+ if (type == ASN1_GENERALIZEDTIME)
+ {
+ format = "%04d%02d%02d%02d%02d%02dZ";
+ offset = 1900;
+ }
+ else /* ASN1_UTCTIME */
+ {
+ format = "%02d%02d%02d%02d%02d%02dZ";
+ offset = (t->tm_year < 100)? 0 : -100;
+ }
+ sprintf(buf, format, t->tm_year + offset, t->tm_mon + 1, t->tm_mday
+ , t->tm_hour, t->tm_min, t->tm_sec);
+ formatted_time.ptr = buf;
+ formatted_time.len = strlen(buf);
+ return asn1_simple_object(type, formatted_time);
+}
+
+
+/*
+ * Initializes the internal context of the ASN.1 parser
+ */
+void
+asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0,
+ bool implicit, u_int cond)
+{
+ ctx->blobs[0] = blob;
+ ctx->level0 = level0;
+ ctx->implicit = implicit;
+ ctx->cond = cond;
+ memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr));
+}
+
+/*
+ * print the value of an ASN.1 simple object
+ */
+static void
+debug_asn1_simple_object(chunk_t object, asn1_t type, u_int cond)
+{
+ int oid;
+
+ switch (type)
+ {
+ case ASN1_OID:
+ oid = known_oid(object);
+ if (oid != OID_UNKNOWN)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" '%s'",oid_names[oid].name);
+ )
+ return;
+ }
+ break;
+ case ASN1_UTF8STRING:
+ case ASN1_IA5STRING:
+ case ASN1_PRINTABLESTRING:
+ case ASN1_T61STRING:
+ case ASN1_VISIBLESTRING:
+ DBG(DBG_PARSING,
+ DBG_log(" '%.*s'", (int)object.len, object.ptr);
+ )
+ return;
+ case ASN1_UTCTIME:
+ case ASN1_GENERALIZEDTIME:
+ DBG(DBG_PARSING,
+ time_t time = asn1totime(&object, type);
+ DBG_log(" '%s'", timetoa(&time, TRUE));
+ )
+ return;
+ default:
+ break;
+ }
+ DBG(cond,
+ DBG_dump_chunk("", object);
+ )
+}
+
+/*
+ * Parses and extracts the next ASN.1 object
+ */
+bool
+extract_object(asn1Object_t const *objects,
+ u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx)
+{
+ asn1Object_t obj = objects[*objectID];
+ chunk_t *blob;
+ chunk_t *blob1;
+ u_char *start_ptr;
+
+ *object = empty_chunk;
+
+ if (obj.flags & ASN1_END) /* end of loop or option found */
+ {
+ if (ctx->loopAddr[obj.level] && ctx->blobs[obj.level+1].len > 0)
+ {
+ *objectID = ctx->loopAddr[obj.level]; /* another iteration */
+ obj = objects[*objectID];
+ }
+ else
+ {
+ ctx->loopAddr[obj.level] = 0; /* exit loop or option*/
+ return TRUE;
+ }
+ }
+
+ *level = ctx->level0 + obj.level;
+ blob = ctx->blobs + obj.level;
+ blob1 = blob + 1;
+ start_ptr = blob->ptr;
+
+ /* handle ASN.1 defaults values */
+
+ if ((obj.flags & ASN1_DEF)
+ && (blob->len == 0 || *start_ptr != obj.type) )
+ {
+ /* field is missing */
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s:", *level, obj.name);
+ )
+ if (obj.type & ASN1_CONSTRUCTED)
+ {
+ (*objectID)++ ; /* skip context-specific tag */
+ }
+ return TRUE;
+ }
+
+ /* handle ASN.1 options */
+
+ if ((obj.flags & ASN1_OPT)
+ && (blob->len == 0 || *start_ptr != obj.type))
+ {
+ /* advance to end of missing option field */
+ do
+ (*objectID)++;
+ while (!((objects[*objectID].flags & ASN1_END)
+ && (objects[*objectID].level == obj.level)));
+ return TRUE;
+ }
+
+ /* an ASN.1 object must possess at least a tag and length field */
+
+ if (blob->len < 2)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s: ASN.1 object smaller than 2 octets",
+ *level, obj.name);
+ )
+ return FALSE;
+ }
+
+ blob1->len = asn1_length(blob);
+
+ if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s: length of ASN.1 object invalid or too large",
+ *level, obj.name);
+ )
+ return FALSE;
+ }
+
+ blob1->ptr = blob->ptr;
+ blob->ptr += blob1->len;
+ blob->len -= blob1->len;
+
+ /* return raw ASN.1 object without prior type checking */
+
+ if (obj.flags & ASN1_RAW)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s:", *level, obj.name);
+ )
+ object->ptr = start_ptr;
+ object->len = (size_t)(blob->ptr - start_ptr);
+ return TRUE;
+ }
+
+ if (*start_ptr != obj.type && !(ctx->implicit && *objectID == 0))
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+ *level, obj.name, obj.type, *start_ptr);
+ DBG_dump("", start_ptr, (u_int)(blob->ptr - start_ptr));
+ )
+ return FALSE;
+ }
+
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s:", ctx->level0+obj.level, obj.name);
+ )
+
+ /* In case of "SEQUENCE OF" or "SET OF" start a loop */
+
+ if (obj.flags & ASN1_LOOP)
+ {
+ if (blob1->len > 0)
+ {
+ /* at least one item, start the loop */
+ ctx->loopAddr[obj.level] = *objectID + 1;
+ }
+ else
+ {
+ /* no items, advance directly to end of loop */
+ do
+ (*objectID)++;
+ while (!((objects[*objectID].flags & ASN1_END)
+ && (objects[*objectID].level == obj.level)));
+ return TRUE;
+ }
+ }
+
+ if (obj.flags & ASN1_OBJ)
+ {
+ object->ptr = start_ptr;
+ object->len = (size_t)(blob->ptr - start_ptr);
+ DBG(ctx->cond,
+ DBG_dump_chunk("", *object);
+ )
+ }
+ else if (obj.flags & ASN1_BODY)
+ {
+ *object = *blob1;
+ debug_asn1_simple_object(*object, obj.type, ctx->cond);
+ }
+ return TRUE;
+}
+
+/*
+ * parse an ASN.1 simple type
+ */
+bool
+parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level
+, const char* name)
+{
+ size_t len;
+
+ /* an ASN.1 object must possess at least a tag and length field */
+ if (object->len < 2)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s: ASN.1 object smaller than 2 octets",
+ level, name);
+ )
+ return FALSE;
+ }
+
+ if (*object->ptr != type)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+ level, name, type, *object->ptr);
+ )
+ return FALSE;
+ }
+
+ len = asn1_length(object);
+
+ if (len == ASN1_INVALID_LENGTH || object->len < len)
+ {
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s: length of ASN.1 object invalid or too large",
+ level, name);
+ )
+ return FALSE;
+ }
+
+ DBG(DBG_PARSING,
+ DBG_log("L%d - %s:", level, name);
+ )
+ debug_asn1_simple_object(*object, type, DBG_RAW);
+ return TRUE;
+}
+
+/*
+ * extracts an algorithmIdentifier
+ */
+int
+parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int alg = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < ALGORITHM_ID_ROOF)
+ {
+ if (!extract_object(algorithmIdentifierObjects, &objectID, &object, &level, &ctx))
+ return OID_UNKNOWN;
+
+ switch (objectID)
+ {
+ case ALGORITHM_ID_ALG:
+ alg = known_oid(object);
+ break;
+ case ALGORITHM_ID_PARAMETERS:
+ if (parameters != NULL)
+ *parameters = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ return alg;
+ }
+
+/*
+ * tests if a blob contains a valid ASN.1 set or sequence
+ */
+bool
+is_asn1(chunk_t blob)
+{
+ u_int len;
+ u_char tag = *blob.ptr;
+
+ if (tag != ASN1_SEQUENCE && tag != ASN1_SET)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file content is not binary ASN.1");
+ )
+ return FALSE;
+ }
+ len = asn1_length(&blob);
+ if (len != blob.len)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file size does not match ASN.1 coded length");
+ )
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/programs/pluto/asn1.h b/programs/pluto/asn1.h
new file mode 100644
index 000000000..2a3fb3e9e
--- /dev/null
+++ b/programs/pluto/asn1.h
@@ -0,0 +1,141 @@
+/* Simple ASN.1 parser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: asn1.h,v 1.14 2005/12/06 22:50:10 as Exp $
+ */
+
+#ifndef _ASN1_H
+#define _ASN1_H
+
+#include <stdarg.h>
+#include <gmp.h>
+
+#include "defs.h"
+
+/* Defines some primitive ASN1 types */
+
+typedef enum {
+ ASN1_EOC = 0x00,
+ ASN1_BOOLEAN = 0x01,
+ ASN1_INTEGER = 0x02,
+ ASN1_BIT_STRING = 0x03,
+ ASN1_OCTET_STRING = 0x04,
+ ASN1_NULL = 0x05,
+ ASN1_OID = 0x06,
+ ASN1_ENUMERATED = 0x0A,
+ ASN1_UTF8STRING = 0x0C,
+ ASN1_NUMERICSTRING = 0x12,
+ ASN1_PRINTABLESTRING = 0x13,
+ ASN1_T61STRING = 0x14,
+ ASN1_VIDEOTEXSTRING = 0x15,
+ ASN1_IA5STRING = 0x16,
+ ASN1_UTCTIME = 0x17,
+ ASN1_GENERALIZEDTIME = 0x18,
+ ASN1_GRAPHICSTRING = 0x19,
+ ASN1_VISIBLESTRING = 0x1A,
+ ASN1_GENERALSTRING = 0x1B,
+ ASN1_UNIVERSALSTRING = 0x1C,
+ ASN1_BMPSTRING = 0x1E,
+
+ ASN1_CONSTRUCTED = 0x20,
+
+ ASN1_SEQUENCE = 0x30,
+
+ ASN1_SET = 0x31,
+
+ ASN1_CONTEXT_S_0 = 0x80,
+ ASN1_CONTEXT_S_1 = 0x81,
+ ASN1_CONTEXT_S_2 = 0x82,
+ ASN1_CONTEXT_S_3 = 0x83,
+ ASN1_CONTEXT_S_4 = 0x84,
+ ASN1_CONTEXT_S_5 = 0x85,
+ ASN1_CONTEXT_S_6 = 0x86,
+ ASN1_CONTEXT_S_7 = 0x87,
+ ASN1_CONTEXT_S_8 = 0x88,
+
+ ASN1_CONTEXT_C_0 = 0xA0,
+ ASN1_CONTEXT_C_1 = 0xA1,
+ ASN1_CONTEXT_C_2 = 0xA2,
+ ASN1_CONTEXT_C_3 = 0xA3,
+ ASN1_CONTEXT_C_4 = 0xA4,
+ ASN1_CONTEXT_C_5 = 0xA5
+} asn1_t;
+
+/* Definition of ASN1 flags */
+
+#define ASN1_NONE 0x00
+#define ASN1_DEF 0x01
+#define ASN1_OPT 0x02
+#define ASN1_LOOP 0x04
+#define ASN1_END 0x08
+#define ASN1_OBJ 0x10
+#define ASN1_BODY 0x20
+#define ASN1_RAW 0x40
+
+#define ASN1_INVALID_LENGTH 0xffffffff
+
+/* definition of an ASN.1 object */
+
+typedef struct {
+ u_int level;
+ const u_char *name;
+ asn1_t type;
+ u_char flags;
+} asn1Object_t;
+
+#define ASN1_MAX_LEVEL 10
+
+typedef struct {
+ bool implicit;
+ u_int cond;
+ u_int level0;
+ u_int loopAddr[ASN1_MAX_LEVEL+1];
+ chunk_t blobs[ASN1_MAX_LEVEL+2];
+} asn1_ctx_t;
+
+/* some common prefabricated ASN.1 constants */
+
+extern const chunk_t ASN1_INTEGER_0;
+extern const chunk_t ASN1_INTEGER_1;
+extern const chunk_t ASN1_INTEGER_2;
+
+/* some popular algorithmIdentifiers */
+extern const chunk_t ASN1_md5_id;
+extern const chunk_t ASN1_sha1_id;
+extern const chunk_t ASN1_rsaEncryption_id;
+extern const chunk_t ASN1_md5WithRSA_id;
+extern const chunk_t ASN1_sha1WithRSA_id;
+
+extern chunk_t asn1_algorithmIdentifier(int oid);
+extern int known_oid(chunk_t object);
+extern u_int asn1_length(chunk_t *blob);
+extern void code_asn1_length(size_t length, chunk_t *code);
+extern u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen);
+extern chunk_t asn1_integer_from_mpz(const mpz_t value);
+extern chunk_t asn1_simple_object(asn1_t tag, chunk_t content);
+extern chunk_t asn1_wrap(asn1_t type, const char *mode, ...);
+extern bool is_printablestring(chunk_t str);
+extern time_t asn1totime(const chunk_t *utctime, asn1_t type);
+extern chunk_t timetoasn1(const time_t *time, asn1_t type);
+extern void asn1_init(asn1_ctx_t *ctx, chunk_t blob
+ , u_int level0, bool implicit, u_int cond);
+extern bool extract_object(asn1Object_t const *objects
+ , u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx);
+extern bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level
+ , const char* name);
+extern int parse_algorithmIdentifier(chunk_t blob, int level0
+ , chunk_t *parameters);
+extern bool is_asn1(chunk_t blob);
+
+#endif /* _ASN1_H */
+
diff --git a/programs/pluto/ca.c b/programs/pluto/ca.c
new file mode 100644
index 000000000..c1e0261d8
--- /dev/null
+++ b/programs/pluto/ca.c
@@ -0,0 +1,694 @@
+/* Certification Authority (CA) support for IKE authentication
+ * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: ca.c,v 1.10 2005/12/25 12:29:55 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "x509.h"
+#include "ca.h"
+#include "certs.h"
+#include "whack.h"
+#include "fetch.h"
+
+/* chained list of X.509 authority certificates (ca, aa, and ocsp) */
+
+static x509cert_t *x509authcerts = NULL;
+
+const ca_info_t empty_ca_info = {
+ NULL , /* next */
+ NULL , /* name */
+ UNDEFINED_TIME,
+ { NULL, 0 } , /* authName */
+ { NULL, 0 } , /* authKeyID */
+ { NULL, 0 } , /* authKey SerialNumber */
+ NULL , /* ldaphost */
+ NULL , /* ldapbase */
+ NULL , /* ocspori */
+ NULL , /* crluri */
+ FALSE /* strictcrlpolicy */
+};
+
+/* chained list of X.509 certification authority information records */
+
+static ca_info_t *ca_infos = NULL;
+
+/*
+ * Checks if CA a is trusted by CA b
+ */
+bool
+trusted_ca(chunk_t a, chunk_t b, int *pathlen)
+{
+ bool match = FALSE;
+
+ /* no CA b specified -> any CA a is accepted */
+ if (b.ptr == NULL)
+ {
+ *pathlen = (a.ptr == NULL)? 0 : MAX_CA_PATH_LEN;
+ return TRUE;
+ }
+
+ /* no CA a specified -> trust cannot be established */
+ if (a.ptr == NULL)
+ {
+ *pathlen = MAX_CA_PATH_LEN;
+ return FALSE;
+ }
+
+ *pathlen = 0;
+
+ /* CA a equals CA b -> we have a match */
+ if (same_dn(a, b))
+ return TRUE;
+
+ /* CA a might be a subordinate CA of b */
+ lock_authcert_list("trusted_ca");
+
+ while ((*pathlen)++ < MAX_CA_PATH_LEN)
+ {
+ x509cert_t *cacert = get_authcert(a, empty_chunk, empty_chunk, AUTH_CA);
+
+ /* cacert not found or self-signed root cacert-> exit */
+ if (cacert == NULL || same_dn(cacert->issuer, a))
+ break;
+
+ /* does the issuer of CA a match CA b? */
+ match = same_dn(cacert->issuer, b);
+
+ /* we have a match and exit the loop */
+ if (match)
+ break;
+
+ /* go one level up in the CA chain */
+ a = cacert->issuer;
+ }
+
+ unlock_authcert_list("trusted_ca");
+ return match;
+}
+
+/*
+ * does our CA match one of the requested CAs?
+ */
+bool
+match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, int *our_pathlen)
+{
+ /* if no ca is requested than any ca will match */
+ if (requested_ca == NULL)
+ {
+ *our_pathlen = 0;
+ return TRUE;
+ }
+
+ *our_pathlen = MAX_CA_PATH_LEN + 1;
+
+ while (requested_ca != NULL)
+ {
+ int pathlen;
+
+ if (trusted_ca(our_ca, requested_ca->name, &pathlen)
+ && pathlen < *our_pathlen)
+ *our_pathlen = pathlen;
+ requested_ca = requested_ca->next;
+ }
+
+ return *our_pathlen <= MAX_CA_PATH_LEN;
+}
+
+/*
+ * free the first authority certificate in the chain
+ */
+static void
+free_first_authcert(void)
+{
+ x509cert_t *first = x509authcerts;
+ x509authcerts = first->next;
+ free_x509cert(first);
+}
+
+/*
+ * free all CA certificates
+ */
+void
+free_authcerts(void)
+{
+ lock_authcert_list("free_authcerts");
+
+ while (x509authcerts != NULL)
+ free_first_authcert();
+
+ unlock_authcert_list("free_authcerts");
+}
+
+/*
+ * get a X.509 authority certificate with a given subject or keyid
+ */
+x509cert_t*
+get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid, u_char auth_flags)
+{
+ x509cert_t *cert = x509authcerts;
+ x509cert_t *prev_cert = NULL;
+
+ while (cert != NULL)
+ {
+ if (cert->authority_flags & auth_flags
+ && ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID)
+ : (same_dn(subject, cert->subject)
+ && same_serial(serial, cert->serialNumber))))
+ {
+ if (cert != x509authcerts)
+ {
+ /* bring the certificate up front */
+ prev_cert->next = cert->next;
+ cert->next = x509authcerts;
+ x509authcerts = cert;
+ }
+ return cert;
+ }
+ prev_cert = cert;
+ cert = cert->next;
+ }
+ return NULL;
+}
+
+/*
+ * add an authority certificate to the chained list
+ */
+bool
+add_authcert(x509cert_t *cert, u_char auth_flags)
+{
+ x509cert_t *old_cert;
+
+ /* set authority flags */
+ cert->authority_flags |= auth_flags;
+
+ lock_authcert_list("add_authcert");
+
+ old_cert = get_authcert(cert->subject, cert->serialNumber
+ , cert->subjectKeyID, auth_flags);
+
+ if (old_cert != NULL)
+ {
+ if (same_x509cert(cert, old_cert))
+ {
+ /* cert is already present, just add additional authority flags */
+ old_cert->authority_flags |= cert->authority_flags;
+ DBG(DBG_CONTROL | DBG_PARSING ,
+ DBG_log(" authcert is already present and identical")
+ )
+ unlock_authcert_list("add_authcert");
+
+ free_x509cert(cert);
+ return FALSE;
+ }
+ else
+ {
+ /* cert is already present but will be replaced by new cert */
+ free_first_authcert();
+ DBG(DBG_CONTROL | DBG_PARSING ,
+ DBG_log(" existing authcert deleted")
+ )
+ }
+ }
+
+ /* add new authcert to chained list */
+ cert->next = x509authcerts;
+ x509authcerts = cert;
+ share_x509cert(cert); /* set count to one */
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" authcert inserted")
+ )
+ unlock_authcert_list("add_authcert");
+ return TRUE;
+}
+
+/*
+ * Loads authority certificates
+ */
+void
+load_authcerts(const char *type, const char *path, u_char auth_flags)
+{
+ struct dirent **filelist;
+ u_char buf[BUF_LEN];
+ u_char *save_dir;
+ int n;
+
+ /* change directory to specified path */
+ save_dir = getcwd(buf, BUF_LEN);
+
+ if (chdir(path))
+ {
+ plog("Could not change to directory '%s'", path);
+ }
+ else
+ {
+ plog("Changing to directory '%s'", path);
+ n = scandir(path, &filelist, file_select, alphasort);
+
+ if (n < 0)
+ plog(" scandir() error");
+ else
+ {
+ while (n--)
+ {
+ cert_t cert;
+
+ if (load_cert(filelist[n]->d_name, type, &cert))
+ add_authcert(cert.u.x509, auth_flags);
+
+ free(filelist[n]);
+ }
+ free(filelist);
+ }
+ }
+ /* restore directory path */
+ chdir(save_dir);
+}
+
+/*
+ * list all X.509 authcerts with given auth flags in a chained list
+ */
+void
+list_authcerts(const char *caption, u_char auth_flags, bool utc)
+{
+ lock_authcert_list("list_authcerts");
+ list_x509cert_chain(caption, x509authcerts, auth_flags, utc);
+ unlock_authcert_list("list_authcerts");
+}
+
+/*
+ * get a cacert with a given subject or keyid from an alternative list
+ */
+static const x509cert_t*
+get_alt_cacert(chunk_t subject, chunk_t serial, chunk_t keyid
+ , const x509cert_t *cert)
+{
+ while (cert != NULL)
+ {
+ if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID)
+ : (same_dn(subject, cert->subject)
+ && same_serial(serial, cert->serialNumber)))
+ {
+ return cert;
+ }
+ cert = cert->next;
+ }
+ return NULL;
+}
+
+/* establish trust into a candidate authcert by going up the trust chain.
+ * validity and revocation status are not checked.
+ */
+bool
+trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain)
+{
+ int pathlen;
+
+ lock_authcert_list("trust_authcert_candidate");
+
+ for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
+ {
+ const x509cert_t *authcert = NULL;
+ u_char buf[BUF_LEN];
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("subject: '%s'",buf);
+ dntoa(buf, BUF_LEN, cert->issuer);
+ DBG_log("issuer: '%s'",buf);
+ if (cert->authKeyID.ptr != NULL)
+ {
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+
+ /* search in alternative chain first */
+ authcert = get_alt_cacert(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID, alt_chain);
+
+ if (authcert != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found in alternative chain")
+ )
+ }
+ else
+ {
+ /* search in trusted chain */
+ authcert = get_authcert(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID, AUTH_CA);
+
+ if (authcert != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found")
+ )
+ }
+ else
+ {
+ plog("issuer cacert not found");
+ unlock_authcert_list("trust_authcert_candidate");
+ return FALSE;
+ }
+ }
+
+ if (!check_signature(cert->tbsCertificate, cert->signature
+ , cert->algorithm, cert->algorithm, authcert))
+ {
+ plog("certificate signature is invalid");
+ unlock_authcert_list("trust_authcert_candidate");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate signature is valid")
+ )
+
+ /* check if cert is a self-signed root ca */
+ if (pathlen > 0 && same_dn(cert->issuer, cert->subject))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("reached self-signed root ca")
+ )
+ unlock_authcert_list("trust_authcert_candidate");
+ return TRUE;
+ }
+
+ /* go up one step in the trust chain */
+ cert = authcert;
+ }
+ plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
+ unlock_authcert_list("trust_authcert_candidate");
+ return FALSE;
+}
+
+/*
+ * get a CA info record with a given authName or authKeyID
+ */
+ca_info_t*
+get_ca_info(chunk_t authname, chunk_t serial, chunk_t keyid)
+{
+ ca_info_t *ca= ca_infos;
+
+ while (ca!= NULL)
+ {
+ if ((keyid.ptr != NULL) ? same_keyid(keyid, ca->authKeyID)
+ : (same_dn(authname, ca->authName)
+ && same_serial(serial, ca->authKeySerialNumber)))
+ {
+ return ca;
+ }
+ ca = ca->next;
+ }
+ return NULL;
+}
+
+
+/*
+ * free the dynamic memory used by a ca_info record
+ */
+static void
+free_ca_info(ca_info_t* ca_info)
+{
+ if (ca_info == NULL)
+ return;
+
+ pfreeany(ca_info->name);
+ pfreeany(ca_info->ldaphost);
+ pfreeany(ca_info->ldapbase);
+ pfreeany(ca_info->ocspuri);
+
+ freeanychunk(ca_info->authName);
+ freeanychunk(ca_info->authKeyID);
+ freeanychunk(ca_info->authKeySerialNumber);
+
+ free_generalNames(ca_info->crluri, TRUE);
+
+ pfree(ca_info);
+}
+
+/*
+ * free all CA certificates
+ */
+void
+free_ca_infos(void)
+{
+ while (ca_infos != NULL)
+ {
+ ca_info_t *ca = ca_infos;
+
+ ca_infos = ca_infos->next;
+ free_ca_info(ca);
+ }
+}
+
+/*
+ * find a CA information record by name and optionally delete it
+ */
+bool
+find_ca_info_by_name(const char *name, bool delete)
+{
+ ca_info_t **ca_p = &ca_infos;
+ ca_info_t *ca = *ca_p;
+
+ while (ca != NULL)
+ {
+ /* is there already an entry? */
+ if (streq(name, ca->name))
+ {
+ if (delete)
+ {
+ lock_ca_info_list("find_ca_info_by_name");
+ *ca_p = ca->next;
+ free_ca_info(ca);
+ plog("deleting ca description \"%s\"", name);
+ unlock_ca_info_list("find_ca_info_by_name");
+ }
+ return TRUE;
+ }
+ ca_p = &ca->next;
+ ca = *ca_p;
+ }
+ return FALSE;
+}
+
+
+ /*
+ * adds a CA description to a chained list
+ */
+void
+add_ca_info(const whack_message_t *msg)
+{
+ smartcard_t *sc = NULL;
+ cert_t cert;
+ bool valid_cert = FALSE;
+ bool cached_cert = FALSE;
+
+ if (find_ca_info_by_name(msg->name, FALSE))
+ {
+ loglog(RC_DUPNAME, "attempt to redefine ca record \"%s\"", msg->name);
+ return;
+ }
+
+ if (scx_on_smartcard(msg->cacert))
+ {
+ /* load CA cert from smartcard */
+ valid_cert = scx_load_cert(msg->cacert, &sc, &cert, &cached_cert);
+ }
+ else
+ {
+ /* load CA cert from file */
+ valid_cert = load_ca_cert(msg->cacert, &cert);
+ }
+
+ if (valid_cert)
+ {
+ char buf[BUF_LEN];
+ x509cert_t *cacert = cert.u.x509;
+ ca_info_t *ca = NULL;
+
+ /* does the authname already exist? */
+ ca = get_ca_info(cacert->subject, cacert->serialNumber
+ , cacert->subjectKeyID);
+
+ if (ca != NULL)
+ {
+ /* ca_info is already present */
+ loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found,"
+ "ignoring \"%s\"", ca->name, msg->name);
+ free_x509cert(cacert);
+ return;
+ }
+
+ plog("added ca description \"%s\"", msg->name);
+
+ /* create and initialize new ca_info record */
+ ca = alloc_thing(ca_info_t, "ca info");
+ *ca = empty_ca_info;
+
+ /* name */
+ ca->name = clone_str(msg->name, "ca name");
+
+ /* authName */
+ clonetochunk(ca->authName, cacert->subject.ptr
+ , cacert->subject.len, "authName");
+ dntoa(buf, BUF_LEN, ca->authName);
+ DBG(DBG_CONTROL,
+ DBG_log("authname: '%s'", buf)
+ )
+
+ /* authSerialNumber */
+ clonetochunk(ca->authKeySerialNumber, cacert->serialNumber.ptr
+ , cacert->serialNumber.len, "authKeySerialNumber");
+
+ /* authKeyID */
+ if (cacert->subjectKeyID.ptr != NULL)
+ {
+ clonetochunk(ca->authKeyID, cacert->subjectKeyID.ptr
+ , cacert->subjectKeyID.len, "authKeyID");
+ datatot(cacert->subjectKeyID.ptr, cacert->subjectKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG(DBG_CONTROL | DBG_PARSING ,
+ DBG_log("authkey: %s", buf)
+ )
+ }
+
+ /* ldaphost */
+ ca->ldaphost = clone_str(msg->ldaphost, "ldaphost");
+
+ /* ldapbase */
+ ca->ldapbase = clone_str(msg->ldapbase, "ldapbase");
+
+ /* ocspuri */
+ if (msg->ocspuri != NULL)
+ {
+ if (strncasecmp(msg->ocspuri, "http", 4) == 0)
+ ca->ocspuri = clone_str(msg->ocspuri, "ocspuri");
+ else
+ plog(" ignoring ocspuri with unkown protocol");
+ }
+
+ /* crluri2*/
+ if (msg->crluri2 != NULL)
+ {
+ generalName_t gn =
+ { NULL, GN_URI, {msg->crluri2, strlen(msg->crluri2)} };
+
+ add_distribution_points(&gn, &ca->crluri);
+ }
+
+ /* crluri */
+ if (msg->crluri != NULL)
+ {
+ generalName_t gn =
+ { NULL, GN_URI, {msg->crluri, strlen(msg->crluri)} };
+
+ add_distribution_points(&gn, &ca->crluri);
+ }
+
+ /* strictrlpolicy */
+ ca->strictcrlpolicy = msg->whack_strict;
+
+ /* insert ca_info record into the chained list */
+ lock_ca_info_list("add_ca_info");
+
+ ca->next = ca_infos;
+ ca_infos = ca;
+ ca->installed = time(NULL);
+
+ unlock_ca_info_list("add_ca_info");
+
+ /* add cacert to list of authcerts */
+ if (!cached_cert)
+ {
+ if (add_authcert(cacert, AUTH_CA) && sc != NULL)
+ {
+ if (sc->last_cert.type == CERT_X509_SIGNATURE)
+ sc->last_cert.u.x509->count--;
+ sc->last_cert = cert;
+ share_cert(sc->last_cert);
+ }
+ }
+ if (sc != NULL)
+ time(&sc->last_load);
+ }
+}
+
+/*
+ * list all ca_info records in the chained list
+ */
+void
+list_ca_infos(bool utc)
+{
+ ca_info_t *ca = ca_infos;
+
+ if (ca != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 CA Information Records:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (ca != NULL)
+ {
+ u_char buf[BUF_LEN];
+
+ /* strictpolicy per CA not supported yet
+ *
+ whack_log(RC_COMMENT, "%s, \"%s\", strictcrlpolicy: %s"
+ , timetoa(&ca->installed, utc), ca->name
+ , ca->strictcrlpolicy? "yes":"no");
+ */
+ whack_log(RC_COMMENT, "%s, \"%s\"", timetoa(&ca->installed, utc), ca->name);
+ dntoa(buf, BUF_LEN, ca->authName);
+ whack_log(RC_COMMENT, " authname: '%s'", buf);
+ if (ca->ldaphost != NULL)
+ whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost);
+ if (ca->ldapbase != NULL)
+ whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase);
+ if (ca->ocspuri != NULL)
+ whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri);
+
+ list_distribution_points(ca->crluri);
+
+ if (ca->authKeyID.ptr != NULL)
+ {
+ datatot(ca->authKeyID.ptr, ca->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (ca->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(ca->authKeySerialNumber.ptr, ca->authKeySerialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+ ca = ca->next;
+ }
+}
+
+
diff --git a/programs/pluto/ca.h b/programs/pluto/ca.h
new file mode 100644
index 000000000..8d4602dc6
--- /dev/null
+++ b/programs/pluto/ca.h
@@ -0,0 +1,70 @@
+/* Certification Authority (CA) support for IKE authentication
+ * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: ca.h,v 1.5 2005/12/25 12:28:40 as Exp $
+ */
+
+#ifndef _CA_H
+#define _CA_H
+
+#include "x509.h"
+#include "whack.h"
+
+#define MAX_CA_PATH_LEN 7
+
+/* authority flags */
+
+#define AUTH_NONE 0x00 /* no authorities */
+#define AUTH_CA 0x01 /* certification authority */
+#define AUTH_AA 0x02 /* authorization authority */
+#define AUTH_OCSP 0x04 /* ocsp signing authority */
+
+/* CA info structures */
+
+typedef struct ca_info ca_info_t;
+
+struct ca_info {
+ ca_info_t *next;
+ char *name;
+ time_t installed;
+ chunk_t authName;
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ char *ldaphost;
+ char *ldapbase;
+ char *ocspuri;
+ generalName_t *crluri;
+ bool strictcrlpolicy;
+};
+
+extern bool trusted_ca(chunk_t a, chunk_t b, int *pathlen);
+extern bool match_requested_ca(generalName_t *requested_ca
+ , chunk_t our_ca, int *our_pathlen);
+extern x509cert_t* get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid
+ , u_char auth_flags);
+extern void load_authcerts(const char *type, const char *path
+ , u_char auth_flags);
+extern bool add_authcert(x509cert_t *cert, u_char auth_flags);
+extern void free_authcerts(void);
+extern void list_authcerts(const char *caption, u_char auth_flags, bool utc);
+extern bool trust_authcert_candidate(const x509cert_t *cert
+ , const x509cert_t *alt_chain);
+extern ca_info_t* get_ca_info(chunk_t name, chunk_t serial, chunk_t keyid);
+extern bool find_ca_info_by_name(const char *name, bool delete);
+extern void add_ca_info(const whack_message_t *msg);
+extern void delete_ca_info(const char *name);
+extern void free_ca_infos(void);
+extern void list_ca_infos(bool utc);
+
+#endif /* _CA_H */
+
diff --git a/programs/pluto/certs.c b/programs/pluto/certs.c
new file mode 100644
index 000000000..92b40605f
--- /dev/null
+++ b/programs/pluto/certs.c
@@ -0,0 +1,287 @@
+/* Certificate support for IKE authentication
+ * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: certs.c,v 1.8 2005/11/06 22:55:41 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "asn1.h"
+#include "id.h"
+#include "x509.h"
+#include "pgp.h"
+#include "pem.h"
+#include "certs.h"
+#include "pkcs1.h"
+
+/*
+ * used for initializatin of certs
+ */
+const cert_t empty_cert = {CERT_NONE, {NULL}};
+
+/*
+ * extracts the certificate to be sent to the peer
+ */
+chunk_t
+get_mycert(cert_t cert)
+{
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ return cert.u.pgp->certificate;
+ case CERT_X509_SIGNATURE:
+ return cert.u.x509->certificate;
+ default:
+ return empty_chunk;
+ }
+}
+
+/* load a coded key or certificate file with autodetection
+ * of binary DER or base64 PEM ASN.1 formats and armored PGP format
+ */
+bool
+load_coded_file(const char *filename, prompt_pass_t *pass, const char *type
+, chunk_t *blob, bool *pgp)
+{
+ err_t ugh = NULL;
+
+ FILE *fd = fopen(filename, "r");
+
+ if (fd)
+ {
+ int bytes;
+ fseek(fd, 0, SEEK_END );
+ blob->len = ftell(fd);
+ rewind(fd);
+ blob->ptr = alloc_bytes(blob->len, type);
+ bytes = fread(blob->ptr, 1, blob->len, fd);
+ fclose(fd);
+ plog(" loaded %s file '%s' (%d bytes)", type, filename, bytes);
+
+ *pgp = FALSE;
+
+ /* try DER format */
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file coded in DER format");
+ )
+ return TRUE;
+ }
+
+ /* try PEM format */
+ ugh = pemtobin(blob, pass, filename, pgp);
+
+ if (ugh == NULL)
+ {
+ if (*pgp)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file coded in armored PGP format");
+ )
+ return TRUE;
+ }
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file coded in PEM format");
+ )
+ return TRUE;
+ }
+ ugh = "file coded in unknown format, discarded";
+ }
+
+ /* a conversion error has occured */
+ plog(" %s", ugh);
+ pfree(blob->ptr);
+ *blob = empty_chunk;
+ }
+ else
+ {
+ plog(" could not open %s file '%s'", type, filename);
+ }
+ return FALSE;
+}
+
+/*
+ * Loads a PKCS#1 or PGP private RSA key file
+ */
+err_t
+load_rsa_private_key(const char* filename, prompt_pass_t *pass
+, RSA_private_key_t *key)
+{
+ err_t ugh = NULL;
+ bool pgp = FALSE;
+ chunk_t blob = empty_chunk;
+
+ const char *path = concatenate_paths(PRIVATE_KEY_PATH, filename);
+
+ if (load_coded_file(path, pass, "private key", &blob, &pgp))
+ {
+ if (pgp)
+ {
+ if (!parse_pgp(blob, NULL, key))
+ ugh = "syntax error in PGP private key file";
+ }
+ else
+ {
+ if (!pkcs1_parse_private_key(blob, key))
+ ugh = "syntax error in PKCS#1 private key file";
+ }
+ pfree(blob.ptr);
+ }
+ else
+ ugh = "error loading RSA private key file";
+
+ return ugh;
+}
+/*
+ * Loads a X.509 or OpenPGP certificate
+ */
+bool
+load_cert(const char *filename, const char *label, cert_t *cert)
+{
+ bool pgp = FALSE;
+ chunk_t blob = empty_chunk;
+
+ /* initialize cert struct */
+ cert->type = CERT_NONE;
+ cert->u.x509 = NULL;
+
+ if (load_coded_file(filename, NULL, label, &blob, &pgp))
+ {
+ if (pgp)
+ {
+ pgpcert_t *pgpcert = alloc_thing(pgpcert_t, "pgpcert");
+ *pgpcert = empty_pgpcert;
+ if (parse_pgp(blob, pgpcert, NULL))
+ {
+ cert->type = CERT_PGP;
+ cert->u.pgp = pgpcert;
+ return TRUE;
+ }
+ else
+ {
+ plog(" error in OpenPGP certificate");
+ free_pgpcert(pgpcert);
+ return FALSE;
+ }
+ }
+ else
+ {
+ x509cert_t *x509cert = alloc_thing(x509cert_t, "x509cert");
+ *x509cert = empty_x509cert;
+ if (parse_x509cert(blob, 0, x509cert))
+ {
+ cert->type = CERT_X509_SIGNATURE;
+ cert->u.x509 = x509cert;
+ return TRUE;
+ }
+ else
+ {
+ plog(" error in X.509 certificate");
+ free_x509cert(x509cert);
+ return FALSE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Loads a host certificate
+ */
+bool
+load_host_cert(const char *filename, cert_t *cert)
+{
+ const char *path = concatenate_paths(HOST_CERT_PATH, filename);
+
+ return load_cert(path, "host cert", cert);
+}
+
+/*
+ * Loads a CA certificate
+ */
+bool
+load_ca_cert(const char *filename, cert_t *cert)
+{
+ const char *path = concatenate_paths(CA_CERT_PATH, filename);
+
+ return load_cert(path, "CA cert", cert);
+}
+
+/*
+ * establish equality of two certificates
+ */
+bool
+same_cert(const cert_t *a, const cert_t *b)
+{
+ return a->type == b->type && a->u.x509 == b->u.x509;
+}
+
+/* for each link pointing to the certif icate
+ " increase the count by one
+ */
+void
+share_cert(cert_t cert)
+{
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ share_pgpcert(cert.u.pgp);
+ break;
+ case CERT_X509_SIGNATURE:
+ share_x509cert(cert.u.x509);
+ break;
+ default:
+ break;
+ }
+}
+
+/* release of a certificate decreases the count by one
+ " the certificate is freed when the counter reaches zero
+ */
+void
+release_cert(cert_t cert)
+{
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ release_pgpcert(cert.u.pgp);
+ break;
+ case CERT_X509_SIGNATURE:
+ release_x509cert(cert.u.x509);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * list all X.509 and OpenPGP end certificates
+ */
+void
+list_certs(bool utc)
+{
+ list_x509_end_certs(utc);
+ list_pgp_end_certs(utc);
+}
+
diff --git a/programs/pluto/certs.h b/programs/pluto/certs.h
new file mode 100644
index 000000000..cca128965
--- /dev/null
+++ b/programs/pluto/certs.h
@@ -0,0 +1,80 @@
+/* Certificate support for IKE authentication
+ * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: certs.h,v 1.7 2005/11/06 22:55:41 as Exp $
+ */
+
+#ifndef _CERTS_H
+#define _CERTS_H
+
+#include "pkcs1.h"
+#include "x509.h"
+#include "pgp.h"
+
+/* path definitions for private keys, end certs,
+ * cacerts, attribute certs and crls
+ */
+#define PRIVATE_KEY_PATH "/etc/ipsec.d/private"
+#define HOST_CERT_PATH "/etc/ipsec.d/certs"
+#define CA_CERT_PATH "/etc/ipsec.d/cacerts"
+#define A_CERT_PATH "/etc/ipsec.d/acerts"
+#define AA_CERT_PATH "/etc/ipsec.d/aacerts"
+#define OCSP_CERT_PATH "/etc/ipsec.d/ocspcerts"
+#define CRL_PATH "/etc/ipsec.d/crls"
+#define REQ_PATH "/etc/ipsec.d/reqs"
+
+/* advance warning of imminent expiry of
+ * cacerts, public keys, and crls
+ */
+#define CA_CERT_WARNING_INTERVAL 30 /* days */
+#define OCSP_CERT_WARNING_INTERVAL 30 /* days */
+#define PUBKEY_WARNING_INTERVAL 7 /* days */
+#define CRL_WARNING_INTERVAL 7 /* days */
+#define ACERT_WARNING_INTERVAL 1 /* day */
+
+/* certificate access structure
+ * currently X.509 and OpenPGP certificates are supported
+ */
+typedef struct {
+ u_char type;
+ union {
+ x509cert_t *x509;
+ pgpcert_t *pgp;
+ } u;
+} cert_t;
+
+/* used for initialization */
+extern const cert_t empty_cert;
+
+/* do not send certificate requests
+ * flag set in plutomain.c and used in ipsec_doi.c
+ */
+extern bool no_cr_send;
+
+extern err_t load_rsa_private_key(const char* filename, prompt_pass_t *pass
+ , RSA_private_key_t *key);
+extern chunk_t get_mycert(cert_t cert);
+extern bool load_coded_file(const char *filename, prompt_pass_t *pass
+ , const char *type, chunk_t *blob, bool *pgp);
+extern bool load_cert(const char *filename, const char *label
+ , cert_t *cert);
+extern bool load_host_cert(const char *filename, cert_t *cert);
+extern bool load_ca_cert(const char *filename, cert_t *cert);
+extern bool same_cert(const cert_t *a, const cert_t *b);
+extern void share_cert(cert_t cert);
+extern void release_cert(cert_t cert);
+extern void list_certs(bool utc);
+
+#endif /* _CERTS_H */
+
+
diff --git a/programs/pluto/connections.c b/programs/pluto/connections.c
new file mode 100644
index 000000000..263bdbd1e
--- /dev/null
+++ b/programs/pluto/connections.c
@@ -0,0 +1,4431 @@
+/* information about connections between hosts and clients
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: connections.c,v 1.42 2006/04/22 21:59:20 as Exp $
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+#include "kameipsec.h"
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "x509.h"
+#include "ca.h"
+#include "crl.h"
+#include "pgp.h"
+#include "certs.h"
+#include "ac.h"
+#include "smartcard.h"
+#include "fetch.h"
+#include "connections.h"
+#include "foodgroups.h"
+#include "demux.h"
+#include "state.h"
+#include "timer.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "server.h"
+#include "kernel.h"
+#include "log.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "whack.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+#include "kernel_alg.h"
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
+#ifdef VIRTUAL_IP
+#include "virtual.h"
+#endif
+
+static void flush_pending_by_connection(struct connection *c); /* forward */
+
+static struct connection *connections = NULL;
+
+/* struct host_pair: a nexus of information about a pair of hosts.
+ * A host is an IP address, UDP port pair. This is a debatable choice:
+ * - should port be considered (no choice of port in standard)?
+ * - should ID be considered (hard because not always known)?
+ * - should IP address matter on our end (we don't know our end)?
+ * Only oriented connections are registered.
+ * Unoriented connections are kept on the unoriented_connections
+ * linked list (using hp_next). For them, host_pair is NULL.
+ */
+
+struct host_pair {
+ struct {
+ ip_address addr;
+ u_int16_t port; /* host order */
+ } me, him;
+ bool initial_connection_sent;
+ struct connection *connections; /* connections with this pair */
+ struct pending *pending; /* awaiting Keying Channel */
+ struct host_pair *next;
+};
+
+static struct host_pair *host_pairs = NULL;
+
+static struct connection *unoriented_connections = NULL;
+
+/* check to see that Ids of peers match */
+bool
+same_peer_ids(const struct connection *c, const struct connection *d
+, const struct id *his_id)
+{
+ return same_id(&c->spd.this.id, &d->spd.this.id)
+ && same_id(his_id == NULL? &c->spd.that.id : his_id, &d->spd.that.id);
+}
+
+static struct host_pair *
+find_host_pair(const ip_address *myaddr, u_int16_t myport
+, const ip_address *hisaddr, u_int16_t hisport)
+{
+ struct host_pair *p, *prev;
+
+ /* default hisaddr to an appropriate any */
+ if (hisaddr == NULL)
+ hisaddr = aftoinfo(addrtypeof(myaddr))->any;
+
+#ifdef NAT_TRAVERSAL
+ if (nat_traversal_enabled) {
+ /**
+ * port is not relevant in host_pair. with nat_traversal we
+ * always use pluto_port (500)
+ */
+ myport = pluto_port;
+ hisport = pluto_port;
+ }
+#endif
+
+ for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next)
+ {
+ if (sameaddr(&p->me.addr, myaddr) && p->me.port == myport
+ && sameaddr(&p->him.addr, hisaddr) && p->him.port == hisport)
+ {
+ if (prev != NULL)
+ {
+ prev->next = p->next; /* remove p from list */
+ p->next = host_pairs; /* and stick it on front */
+ host_pairs = p;
+ }
+ break;
+ }
+ }
+ return p;
+}
+
+/* find head of list of connections with this pair of hosts */
+static struct connection *
+find_host_pair_connections(const ip_address *myaddr, u_int16_t myport
+, const ip_address *hisaddr, u_int16_t hisport)
+{
+ struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport);
+
+#ifdef NAT_TRAVERSAL
+ if (nat_traversal_enabled && hp && hisaddr) {
+ struct connection *c;
+ for (c = hp->connections; c != NULL; c = c->hp_next) {
+ if ((c->spd.this.host_port==myport) && (c->spd.that.host_port==hisport))
+ return c;
+ }
+ return NULL;
+ }
+#endif
+
+ return hp == NULL? NULL : hp->connections;
+}
+
+static void
+connect_to_host_pair(struct connection *c)
+{
+ if (oriented(*c))
+ {
+ struct host_pair *hp = find_host_pair(&c->spd.this.host_addr, c->spd.this.host_port
+ , &c->spd.that.host_addr, c->spd.that.host_port);
+
+ if (hp == NULL)
+ {
+ /* no suitable host_pair -- build one */
+ hp = alloc_thing(struct host_pair, "host_pair");
+ hp->me.addr = c->spd.this.host_addr;
+ hp->him.addr = c->spd.that.host_addr;
+#ifdef NAT_TRAVERSAL
+ hp->me.port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port;
+ hp->him.port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port;
+#else
+ hp->me.port = c->spd.this.host_port;
+ hp->him.port = c->spd.that.host_port;
+#endif
+ hp->initial_connection_sent = FALSE;
+ hp->connections = NULL;
+ hp->pending = NULL;
+ hp->next = host_pairs;
+ host_pairs = hp;
+ }
+ c->host_pair = hp;
+ c->hp_next = hp->connections;
+ hp->connections = c;
+ }
+ else
+ {
+ /* since this connection isn't oriented, we place it
+ * in the unoriented_connections list instead.
+ */
+ c->host_pair = NULL;
+ c->hp_next = unoriented_connections;
+ unoriented_connections = c;
+ }
+}
+
+/* find a connection by name.
+ * If strict, don't accept a CK_INSTANCE.
+ * Move the winner (if any) to the front.
+ * If none is found, and strict, a diagnostic is logged to whack.
+ */
+struct connection *
+con_by_name(const char *nm, bool strict)
+{
+ struct connection *p, *prev;
+
+ for (prev = NULL, p = connections; ; prev = p, p = p->ac_next)
+ {
+ if (p == NULL)
+ {
+ if (strict)
+ whack_log(RC_UNKNOWN_NAME
+ , "no connection named \"%s\"", nm);
+ break;
+ }
+ if (streq(p->name, nm)
+ && (!strict || p->kind != CK_INSTANCE))
+ {
+ if (prev != NULL)
+ {
+ prev->ac_next = p->ac_next; /* remove p from list */
+ p->ac_next = connections; /* and stick it on front */
+ connections = p;
+ }
+ break;
+ }
+ }
+ return p;
+}
+
+void
+release_connection(struct connection *c, bool relations)
+{
+ if (c->kind == CK_INSTANCE)
+ {
+ /* This does everything we need.
+ * Note that we will be called recursively by delete_connection,
+ * but kind will be CK_GOING_AWAY.
+ */
+ delete_connection(c, relations);
+ }
+ else
+ {
+ flush_pending_by_connection(c);
+ delete_states_by_connection(c, relations);
+ unroute_connection(c);
+ }
+}
+
+/* Delete a connection */
+
+#define list_rm(etype, enext, e, ehead) { \
+ etype **ep; \
+ for (ep = &(ehead); *ep != (e); ep = &(*ep)->enext) \
+ passert(*ep != NULL); /* we must not come up empty-handed */ \
+ *ep = (e)->enext; \
+ }
+
+
+void
+delete_connection(struct connection *c, bool relations)
+{
+ struct connection *old_cur_connection
+ = cur_connection == c? NULL : cur_connection;
+#ifdef DEBUG
+ lset_t old_cur_debugging = cur_debugging;
+#endif
+
+ set_cur_connection(c);
+
+ /* Must be careful to avoid circularity:
+ * we mark c as going away so it won't get deleted recursively.
+ */
+ passert(c->kind != CK_GOING_AWAY);
+ if (c->kind == CK_INSTANCE)
+ {
+ plog("deleting connection \"%s\" instance with peer %s {isakmp=#%lu/ipsec=#%lu}"
+ , c->name
+ , ip_str(&c->spd.that.host_addr)
+ , c->newest_isakmp_sa, c->newest_ipsec_sa);
+ c->kind = CK_GOING_AWAY;
+ }
+ else
+ {
+ plog("deleting connection");
+ }
+ release_connection(c, relations); /* won't delete c */
+
+ if (c->kind == CK_GROUP)
+ delete_group(c);
+
+ /* free up any logging resources */
+ perpeer_logfree(c);
+
+ /* find and delete c from connections list */
+ list_rm(struct connection, ac_next, c, connections);
+ cur_connection = old_cur_connection;
+
+ /* find and delete c from the host pair list */
+ if (c->host_pair == NULL)
+ {
+ list_rm(struct connection, hp_next, c, unoriented_connections);
+ }
+ else
+ {
+ struct host_pair *hp = c->host_pair;
+
+ list_rm(struct connection, hp_next, c, hp->connections);
+ c->host_pair = NULL; /* redundant, but safe */
+
+ /* if there are no more connections with this host_pair
+ * and we haven't even made an initial contact, let's delete
+ * this guy in case we were created by an attempted DOS attack.
+ */
+ if (hp->connections == NULL
+ && !hp->initial_connection_sent)
+ {
+ passert(hp->pending == NULL); /* ??? must deal with this! */
+ list_rm(struct host_pair, next, hp, host_pairs);
+ pfree(hp);
+ }
+ }
+
+#ifdef VIRTUAL_IP
+ if (c->kind != CK_GOING_AWAY) pfreeany(c->spd.that.virt);
+#endif
+
+#ifdef DEBUG
+ cur_debugging = old_cur_debugging;
+#endif
+ pfreeany(c->name);
+ free_id_content(&c->spd.this.id);
+ pfreeany(c->spd.this.updown);
+ freeanychunk(c->spd.this.ca);
+ free_ietfAttrList(c->spd.this.groups);
+ free_id_content(&c->spd.that.id);
+ pfreeany(c->spd.that.updown);
+ freeanychunk(c->spd.that.ca);
+ free_ietfAttrList(c->spd.that.groups);
+ free_generalNames(c->requested_ca, TRUE);
+ gw_delref(&c->gw_info);
+
+ lock_certs_and_keys("delete_connection");
+ release_cert(c->spd.this.cert);
+ scx_release(c->spd.this.sc);
+ release_cert(c->spd.that.cert);
+ scx_release(c->spd.that.sc);
+ unlock_certs_and_keys("delete_connection");
+
+ alg_info_delref((struct alg_info **)&c->alg_info_esp);
+ alg_info_delref((struct alg_info **)&c->alg_info_ike);
+
+ pfree(c);
+}
+
+/* Delete connections with the specified name */
+void
+delete_connections_by_name(const char *name, bool strict)
+{
+ struct connection *c = con_by_name(name, strict);
+
+ for (; c != NULL; c = con_by_name(name, FALSE))
+ delete_connection(c, FALSE);
+}
+
+void
+delete_every_connection(void)
+{
+ while (connections != NULL)
+ delete_connection(connections, TRUE);
+}
+
+void
+release_dead_interfaces(void)
+{
+ struct host_pair *hp;
+
+ for (hp = host_pairs; hp != NULL; hp = hp->next)
+ {
+ struct connection **pp
+ , *p;
+
+ for (pp = &hp->connections; (p = *pp) != NULL; )
+ {
+ if (p->interface->change == IFN_DELETE)
+ {
+ /* this connection's interface is going away */
+ enum connection_kind k = p->kind;
+
+ release_connection(p, TRUE);
+
+ if (k <= CK_PERMANENT)
+ {
+ /* The connection should have survived release:
+ * move it to the unoriented_connections list.
+ */
+ passert(p == *pp);
+
+ p->interface = NULL;
+
+ *pp = p->hp_next; /* advance *pp */
+ p->host_pair = NULL;
+ p->hp_next = unoriented_connections;
+ unoriented_connections = p;
+ }
+ else
+ {
+ /* The connection should have vanished,
+ * but the previous connection remains.
+ */
+ passert(p != *pp);
+ }
+ }
+ else
+ {
+ pp = &p->hp_next; /* advance pp */
+ }
+ }
+ }
+}
+
+/* adjust orientations of connections to reflect newly added interfaces */
+void
+check_orientations(void)
+{
+ /* try to orient all the unoriented connections */
+ {
+ struct connection *c = unoriented_connections;
+
+ unoriented_connections = NULL;
+
+ while (c != NULL)
+ {
+ struct connection *nxt = c->hp_next;
+
+ (void)orient(c);
+ connect_to_host_pair(c);
+ c = nxt;
+ }
+ }
+
+ /* Check that no oriented connection has become double-oriented.
+ * In other words, the far side must not match one of our new interfaces.
+ */
+ {
+ struct iface *i;
+
+ for (i = interfaces; i != NULL; i = i->next)
+ {
+ if (i->change == IFN_ADD)
+ {
+ struct host_pair *hp;
+
+ for (hp = host_pairs; hp != NULL; hp = hp->next)
+ {
+ if (sameaddr(&hp->him.addr, &i->addr)
+ && (!no_klips || hp->him.port == pluto_port))
+ {
+ /* bad news: the whole chain of connections
+ * hanging off this host pair has both sides
+ * matching an interface.
+ * We'll get rid of them, using orient and
+ * connect_to_host_pair. But we'll be lazy
+ * and not ditch the host_pair itself (the
+ * cost of leaving it is slight and cannot
+ * be induced by a foe).
+ */
+ struct connection *c = hp->connections;
+
+ hp->connections = NULL;
+ while (c != NULL)
+ {
+ struct connection *nxt = c->hp_next;
+
+ c->interface = NULL;
+ (void)orient(c);
+ connect_to_host_pair(c);
+ c = nxt;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static err_t
+default_end(struct end *e, ip_address *dflt_nexthop)
+{
+ err_t ugh = NULL;
+ const struct af_info *afi = aftoinfo(addrtypeof(&e->host_addr));
+
+ if (afi == NULL)
+ return "unknown address family in default_end";
+
+ /* default ID to IP (but only if not NO_IP -- WildCard) */
+ if (e->id.kind == ID_NONE && !isanyaddr(&e->host_addr))
+ {
+ e->id.kind = afi->id_addr;
+ e->id.ip_addr = e->host_addr;
+ e->has_id_wildcards = FALSE;
+ }
+
+ /* default nexthop to other side */
+ if (isanyaddr(&e->host_nexthop))
+ e->host_nexthop = *dflt_nexthop;
+
+ /* default client to subnet containing only self
+ * XXX This may mean that the client's address family doesn't match
+ * tunnel_addr_family.
+ */
+ if (!e->has_client)
+ ugh = addrtosubnet(&e->host_addr, &e->client);
+
+ return ugh;
+}
+
+/* Format the topology of a connection end, leaving out defaults.
+ * Largest left end looks like: client === host : port [ host_id ] --- hop
+ * Note: if that==NULL, skip nexthop
+ * Returns strlen of formated result (length excludes NUL at end).
+ */
+size_t
+format_end(char *buf
+, size_t buf_len
+, const struct end *this
+, const struct end *that
+, bool is_left
+, lset_t policy)
+{
+ char client[SUBNETTOT_BUF];
+ const char *client_sep = "";
+ char protoport[sizeof(":255/65535")];
+ const char *host = NULL;
+ char host_space[ADDRTOT_BUF];
+ char host_port[sizeof(":65535")];
+ char host_id[BUF_LEN + 2];
+ char hop[ADDRTOT_BUF];
+ const char *hop_sep = "";
+ const char *open_brackets = "";
+ const char *close_brackets = "";
+
+ if (isanyaddr(&this->host_addr))
+ {
+ switch (policy & (POLICY_GROUP | POLICY_OPPO))
+ {
+ case POLICY_GROUP:
+ host = "%group";
+ break;
+ case POLICY_OPPO:
+ host = "%opportunistic";
+ break;
+ case POLICY_GROUP | POLICY_OPPO:
+ host = "%opportunisticgroup";
+ break;
+ default:
+ host = "%any";
+ break;
+ }
+ }
+
+ client[0] = '\0';
+
+#ifdef VIRTUAL_IP
+ if (is_virtual_end(this) && isanyaddr(&this->host_addr))
+ {
+ host = "%virtual";
+ }
+#endif
+
+ /* [client===] */
+ if (this->has_client)
+ {
+ ip_address client_net, client_mask;
+
+ networkof(&this->client, &client_net);
+ maskof(&this->client, &client_mask);
+ client_sep = "===";
+
+ /* {client_subnet_wildcard} */
+ if (this->has_client_wildcard)
+ {
+ open_brackets = "{";
+ close_brackets = "}";
+ }
+
+ if (isanyaddr(&client_net) && isanyaddr(&client_mask)
+ && (policy & (POLICY_GROUP | POLICY_OPPO)))
+ client_sep = ""; /* boring case */
+ else if (subnetisnone(&this->client))
+ strcpy(client, "?");
+ else
+ subnettot(&this->client, 0, client, sizeof(client));
+ }
+ else if (this->modecfg && isanyaddr(&this->host_srcip))
+ {
+ /* we are mode config client */
+ client_sep = "===";
+ strcpy(client, "%modecfg");
+ }
+
+ /* host */
+ if (host == NULL)
+ {
+ addrtot(&this->host_addr, 0, host_space, sizeof(host_space));
+ host = host_space;
+ }
+
+ host_port[0] = '\0';
+ if (this->host_port != IKE_UDP_PORT)
+ snprintf(host_port, sizeof(host_port), ":%u"
+ , this->host_port);
+
+ /* payload portocol and port */
+ protoport[0] = '\0';
+ if (this->has_port_wildcard)
+ snprintf(protoport, sizeof(protoport), ":%u/%%any", this->protocol);
+ else if (this->port || this->protocol)
+ snprintf(protoport, sizeof(protoport), ":%u/%u", this->protocol
+ , this->port);
+
+ /* id, if different from host */
+ host_id[0] = '\0';
+ if (this->id.kind == ID_MYID)
+ {
+ strcpy(host_id, "[%myid]");
+ }
+ else if (!(this->id.kind == ID_NONE
+ || (id_is_ipaddr(&this->id) && sameaddr(&this->id.ip_addr, &this->host_addr))))
+ {
+ int len = idtoa(&this->id, host_id+1, sizeof(host_id)-2);
+
+ host_id[0] = '[';
+ strcpy(&host_id[len < 0? (ptrdiff_t)sizeof(host_id)-2 : 1 + len], "]");
+ }
+
+ /* [---hop] */
+ hop[0] = '\0';
+ hop_sep = "";
+ if (that != NULL && !sameaddr(&this->host_nexthop, &that->host_addr))
+ {
+ addrtot(&this->host_nexthop, 0, hop, sizeof(hop));
+ hop_sep = "---";
+ }
+
+ if (is_left)
+ snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s"
+ , open_brackets, client, close_brackets
+ , client_sep, host, host_port, host_id
+ , protoport, hop_sep, hop);
+ else
+ snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s"
+ , hop, hop_sep, host, host_port, host_id
+ , protoport, client_sep
+ , open_brackets, client, close_brackets);
+ return strlen(buf);
+}
+
+/* format topology of a connection.
+ * Two symmetric ends separated by ...
+ */
+#define CONNECTION_BUF (2 * (END_BUF - 1) + 4)
+
+static size_t
+format_connection(char *buf, size_t buf_len
+ , const struct connection *c
+ , struct spd_route *sr)
+{
+ size_t w = format_end(buf, buf_len, &sr->this, &sr->that, TRUE, LEMPTY);
+
+ w += snprintf(buf + w, buf_len - w, "...");
+ return w + format_end(buf + w, buf_len - w, &sr->that, &sr->this, FALSE, c->policy);
+}
+
+static void
+unshare_connection_strings(struct connection *c)
+{
+ c->name = clone_str(c->name, "connection name");
+
+ unshare_id_content(&c->spd.this.id);
+ c->spd.this.updown = clone_str(c->spd.this.updown, "updown");
+ scx_share(c->spd.this.sc);
+ share_cert(c->spd.this.cert);
+ if (c->spd.this.ca.ptr != NULL)
+ clonetochunk(c->spd.this.ca, c->spd.this.ca.ptr, c->spd.this.ca.len, "ca string");
+
+ unshare_id_content(&c->spd.that.id);
+ c->spd.that.updown = clone_str(c->spd.that.updown, "updown");
+ scx_share(c->spd.that.sc);
+ share_cert(c->spd.that.cert);
+ if (c->spd.that.ca.ptr != NULL)
+ clonetochunk(c->spd.that.ca, c->spd.that.ca.ptr, c->spd.that.ca.len, "ca string");
+
+ /* increment references to algo's */
+ alg_info_addref((struct alg_info *)c->alg_info_esp);
+ alg_info_addref((struct alg_info *)c->alg_info_ike);
+}
+
+static void
+load_end_certificate(const char *filename, struct end *dst)
+{
+ time_t valid_until;
+ cert_t cert;
+ bool valid_cert = FALSE;
+ bool cached_cert = FALSE;
+
+ /* initialize end certificate */
+ dst->cert.type = CERT_NONE;
+ dst->cert.u.x509 = NULL;
+
+ /* initialize smartcard info record */
+ dst->sc = NULL;
+
+ if (filename != NULL)
+ {
+ if (scx_on_smartcard(filename))
+ {
+ /* load cert from smartcard */
+ valid_cert = scx_load_cert(filename, &dst->sc, &cert, &cached_cert);
+ }
+ else
+ {
+ /* load cert from file */
+ valid_cert = load_host_cert(filename, &cert);
+ }
+ }
+
+ if (valid_cert)
+ {
+ err_t ugh = NULL;
+
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ select_pgpcert_id(cert.u.pgp, &dst->id);
+
+ if (cached_cert)
+ dst->cert = cert;
+ else
+ {
+ valid_until = cert.u.pgp->until;
+ add_pgp_public_key(cert.u.pgp, cert.u.pgp->until, DAL_LOCAL);
+ dst->cert.type = cert.type;
+ dst->cert.u.pgp = add_pgpcert(cert.u.pgp);
+ }
+ break;
+ case CERT_X509_SIGNATURE:
+ select_x509cert_id(cert.u.x509, &dst->id);
+
+ if (cached_cert)
+ dst->cert = cert;
+ else
+ {
+ /* check validity of cert */
+ valid_until = cert.u.x509->notAfter;
+ ugh = check_validity(cert.u.x509, &valid_until);
+ if (ugh != NULL)
+ {
+ plog(" %s", ugh);
+ free_x509cert(cert.u.x509);
+ break;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is valid")
+ )
+ add_x509_public_key(cert.u.x509, valid_until, DAL_LOCAL);
+ dst->cert.type = cert.type;
+ dst->cert.u.x509 = add_x509cert(cert.u.x509);
+ }
+ /* if no CA is defined, use issuer as default */
+ if (dst->ca.ptr == NULL)
+ dst->ca = dst->cert.u.x509->issuer;
+ break;
+ default:
+ break;
+ }
+
+ /* cache the certificate that was last retrieved from the smartcard */
+ if (dst->sc != NULL)
+ {
+ if (!same_cert(&dst->sc->last_cert, &dst->cert))
+ {
+ lock_certs_and_keys("load_end_certificates");
+ release_cert(dst->sc->last_cert);
+ dst->sc->last_cert = dst->cert;
+ share_cert(dst->cert);
+ unlock_certs_and_keys("load_end_certificates");
+ }
+ time(&dst->sc->last_load);
+ }
+ }
+}
+
+static bool
+extract_end(struct end *dst, const whack_end_t *src, const char *which)
+{
+ bool same_ca = FALSE;
+
+ /* decode id, if any */
+ if (src->id == NULL)
+ {
+ dst->id.kind = ID_NONE;
+ }
+ else
+ {
+ err_t ugh = atoid(src->id, &dst->id, TRUE);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_BADID, "bad %s --id: %s (ignored)", which, ugh);
+ dst->id = empty_id; /* ignore bad one */
+ }
+ }
+
+ dst->ca = empty_chunk;
+
+ /* decode CA distinguished name, if any */
+ if (src->ca != NULL)
+ {
+ if streq(src->ca, "%same")
+ same_ca = TRUE;
+ else if (!streq(src->ca, "%any"))
+ {
+ err_t ugh;
+
+ dst->ca.ptr = temporary_cyclic_buffer();
+ ugh = atodn(src->ca, &dst->ca);
+ if (ugh != NULL)
+ {
+ plog("bad CA string '%s': %s (ignored)", src->ca, ugh);
+ dst->ca = empty_chunk;
+ }
+ }
+ }
+
+ /* load local end certificate and extract ID, if any */
+ load_end_certificate(src->cert, dst);
+
+ /* does id has wildcards? */
+ dst->has_id_wildcards = id_count_wildcards(&dst->id) > 0;
+
+ /* decode group attributes, if any */
+ decode_groups(src->groups, &dst->groups);
+
+ /* the rest is simple copying of corresponding fields */
+ dst->host_addr = src->host_addr;
+ dst->host_nexthop = src->host_nexthop;
+ dst->host_srcip = src->host_srcip;
+ dst->client = src->client;
+ dst->protocol = src->protocol;
+ dst->port = src->port;
+ dst->has_port_wildcard = src->has_port_wildcard;
+ dst->key_from_DNS_on_demand = src->key_from_DNS_on_demand;
+ dst->has_client = src->has_client;
+ dst->has_client_wildcard = src->has_client_wildcard;
+ dst->modecfg = src->modecfg;
+ dst->hostaccess = src->hostaccess;
+ dst->sendcert = src->sendcert;
+ dst->updown = src->updown;
+ dst->host_port = src->host_port;
+
+ /* if host sourceip is defined but no client is present
+ * behind the host then set client to sourceip/32
+ */
+ if (addrbytesptr(&dst->host_srcip, NULL)
+ && !isanyaddr(&dst->host_srcip)
+ && !dst->has_client)
+ {
+ err_t ugh = addrtosubnet(&dst->host_srcip, &dst->client);
+
+ if (ugh != NULL)
+ plog("could not assign host sourceip to client subnet");
+ else
+ dst->has_client = TRUE;
+ }
+ return same_ca;
+}
+
+static bool
+check_connection_end(const whack_end_t *this, const whack_end_t *that
+, const whack_message_t *wm)
+{
+ if (wm->addr_family != addrtypeof(&this->host_addr)
+ || wm->addr_family != addrtypeof(&this->host_nexthop)
+ || (this->has_client? wm->tunnel_addr_family : wm->addr_family)
+ != subnettypeof(&this->client)
+ || subnettypeof(&this->client) != subnettypeof(&that->client))
+ {
+ /* this should have been diagnosed by whack, so we need not be clear
+ * !!! overloaded use of RC_CLASH
+ */
+ loglog(RC_CLASH, "address family inconsistency in connection");
+ return FALSE;
+ }
+
+ if (isanyaddr(&that->host_addr))
+ {
+ /* other side is wildcard: we must check if other conditions met */
+ if (isanyaddr(&this->host_addr))
+ {
+ loglog(RC_ORIENT, "connection must specify host IP address for our side");
+ return FALSE;
+ }
+ }
+#ifdef VIRTUAL_IP
+ if (this->virt && (!isanyaddr(&this->host_addr) || this->has_client))
+ {
+ loglog(RC_CLASH,
+ "virtual IP must only be used with %%any and without client");
+ return FALSE;
+ }
+#endif
+ return TRUE; /* happy */
+}
+
+struct connection *
+find_connection_by_reqid(uint32_t reqid)
+{
+ struct connection *c;
+
+ reqid &= ~3;
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ if (c->spd.reqid == reqid)
+ return c;
+ }
+
+ return NULL;
+}
+
+static uint32_t
+gen_reqid(void)
+{
+ uint32_t start;
+ static uint32_t reqid = IPSEC_MANUAL_REQID_MAX & ~3;
+
+ start = reqid;
+ do {
+ reqid += 4;
+ if (reqid == 0)
+ reqid = (IPSEC_MANUAL_REQID_MAX & ~3) + 4;
+ if (!find_connection_by_reqid(reqid))
+ return reqid;
+ } while (reqid != start);
+
+ exit_log("unable to allocate reqid");
+}
+
+void
+add_connection(const whack_message_t *wm)
+{
+ if (con_by_name(wm->name, FALSE) != NULL)
+ {
+ loglog(RC_DUPNAME, "attempt to redefine connection \"%s\"", wm->name);
+ }
+ else if (wm->right.protocol != wm->left.protocol)
+ {
+ /* this should haven been diagnosed by whack
+ * !!! overloaded use of RC_CLASH
+ */
+ loglog(RC_CLASH, "the protocol must be the same for leftport and rightport");
+ }
+ else if (check_connection_end(&wm->right, &wm->left, wm)
+ && check_connection_end(&wm->left, &wm->right, wm))
+ {
+ bool same_rightca, same_leftca;
+ struct connection *c = alloc_thing(struct connection, "struct connection");
+
+ c->name = wm->name;
+
+ c->policy = wm->policy;
+
+ if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp)
+ loglog(RC_COMMENT
+ , "ignoring --compress in \"%s\" because KLIPS is not configured to do IPCOMP"
+ , c->name);
+
+ if (wm->esp)
+ {
+ const char *ugh;
+
+ DBG(DBG_CONTROL,
+ DBG_log("from whack: got --esp=%s", wm->esp ? wm->esp: "NULL")
+ )
+ c->alg_info_esp= alg_info_esp_create_from_str(wm->esp? wm->esp : "", &ugh);
+
+ DBG(DBG_CRYPT|DBG_CONTROL,
+ static char buf[256]="<NULL>";
+
+ if (c->alg_info_esp)
+ alg_info_snprint(buf, sizeof(buf)
+ ,(struct alg_info *)c->alg_info_esp);
+ DBG_log("esp string values: %s", buf);
+ )
+ if (c->alg_info_esp)
+ {
+ if (c->alg_info_esp->alg_info_cnt==0)
+ loglog(RC_LOG_SERIOUS
+ , "got 0 transforms for esp=\"%s\"", wm->esp);
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "esp string error: %s", ugh? ugh : "Unknown");
+ }
+ }
+
+ if (wm->ike)
+ {
+ const char *ugh;
+
+ DBG(DBG_CONTROL,
+ DBG_log("from whack: got --ike=%s", wm->ike ? wm->ike: "NULL")
+ )
+ c->alg_info_ike= alg_info_ike_create_from_str(wm->ike? wm->ike : "", &ugh);
+
+ DBG(DBG_CRYPT|DBG_CONTROL,
+ static char buf[256]="<NULL>";
+
+ if (c->alg_info_ike)
+ alg_info_snprint(buf, sizeof(buf)
+ , (struct alg_info *)c->alg_info_ike);
+ DBG_log("ike string values: %s", buf);
+ )
+ if (c->alg_info_ike)
+ {
+ if (c->alg_info_ike->alg_info_cnt==0)
+ loglog(RC_LOG_SERIOUS
+ , "got 0 transforms for ike=\"%s\"", wm->ike);
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ike string error: %s", ugh? ugh : "Unknown");
+ }
+ }
+
+ c->sa_ike_life_seconds = wm->sa_ike_life_seconds;
+ c->sa_ipsec_life_seconds = wm->sa_ipsec_life_seconds;
+ c->sa_rekey_margin = wm->sa_rekey_margin;
+ c->sa_rekey_fuzz = wm->sa_rekey_fuzz;
+ c->sa_keying_tries = wm->sa_keying_tries;
+
+ /* RFC 3706 DPD */
+ c->dpd_delay = wm->dpd_delay;
+ c->dpd_timeout = wm->dpd_timeout;
+ c->dpd_action = wm->dpd_action;
+
+ c->addr_family = wm->addr_family;
+ c->tunnel_addr_family = wm->tunnel_addr_family;
+
+ c->requested_ca = NULL;
+
+ same_leftca = extract_end(&c->spd.this, &wm->left, "left");
+ same_rightca = extract_end(&c->spd.that, &wm->right, "right");
+
+ if (same_rightca)
+ c->spd.that.ca = c->spd.this.ca;
+ else if (same_leftca)
+ c->spd.this.ca = c->spd.that.ca;
+
+ default_end(&c->spd.this, &c->spd.that.host_addr);
+ default_end(&c->spd.that, &c->spd.this.host_addr);
+
+ /* force any wildcard host IP address, any wildcard subnet
+ * or any wildcard ID to that end
+ */
+ if (isanyaddr(&c->spd.this.host_addr) || c->spd.this.has_client_wildcard
+ || c->spd.this.has_port_wildcard || c->spd.this.has_id_wildcards)
+ {
+ struct end t = c->spd.this;
+
+ c->spd.this = c->spd.that;
+ c->spd.that = t;
+ }
+
+ c->spd.next = NULL;
+ c->spd.reqid = gen_reqid();
+
+ /* set internal fields */
+ c->instance_serial = 0;
+ c->ac_next = connections;
+ connections = c;
+ c->interface = NULL;
+ c->spd.routing = RT_UNROUTED;
+ c->newest_isakmp_sa = SOS_NOBODY;
+ c->newest_ipsec_sa = SOS_NOBODY;
+ c->spd.eroute_owner = SOS_NOBODY;
+
+ if (c->policy & POLICY_GROUP)
+ {
+ c->kind = CK_GROUP;
+ add_group(c);
+ }
+ else if ((isanyaddr(&c->spd.that.host_addr) && !NEVER_NEGOTIATE(c->policy))
+ || c->spd.that.has_client_wildcard || c->spd.that.has_port_wildcard
+ || c->spd.that.has_id_wildcards)
+ {
+ /* Opportunistic or Road Warrior or wildcard client subnet
+ * or wildcard ID */
+ c->kind = CK_TEMPLATE;
+ }
+ else
+ {
+ c->kind = CK_PERMANENT;
+ }
+ set_policy_prio(c); /* must be after kind is set */
+
+#ifdef DEBUG
+ c->extra_debugging = wm->debugging;
+#endif
+
+ c->gw_info = NULL;
+
+#ifdef VIRTUAL_IP
+ passert(!(wm->left.virt && wm->right.virt));
+ if (wm->left.virt || wm->right.virt)
+ {
+ passert(isanyaddr(&c->spd.that.host_addr));
+ c->spd.that.virt = create_virtual(c,
+ wm->left.virt ? wm->left.virt : wm->right.virt);
+ if (c->spd.that.virt)
+ c->spd.that.has_client = TRUE;
+ }
+#endif
+
+ unshare_connection_strings(c);
+ (void)orient(c);
+ connect_to_host_pair(c);
+
+ /* log all about this connection */
+ plog("added connection description \"%s\"", c->name);
+ DBG(DBG_CONTROL,
+ char topo[CONNECTION_BUF];
+
+ (void) format_connection(topo, sizeof(topo), c, &c->spd);
+
+ DBG_log("%s", topo);
+
+ /* Make sure that address families can be correctly inferred
+ * from printed ends.
+ */
+ passert(c->addr_family == addrtypeof(&c->spd.this.host_addr)
+ && c->addr_family == addrtypeof(&c->spd.this.host_nexthop)
+ && (c->spd.this.has_client? c->tunnel_addr_family : c->addr_family)
+ == subnettypeof(&c->spd.this.client)
+
+ && c->addr_family == addrtypeof(&c->spd.that.host_addr)
+ && c->addr_family == addrtypeof(&c->spd.that.host_nexthop)
+ && (c->spd.that.has_client? c->tunnel_addr_family : c->addr_family)
+ == subnettypeof(&c->spd.that.client));
+
+ DBG_log("ike_life: %lus; ipsec_life: %lus; rekey_margin: %lus;"
+ " rekey_fuzz: %lu%%; keyingtries: %lu; policy: %s"
+ , (unsigned long) c->sa_ike_life_seconds
+ , (unsigned long) c->sa_ipsec_life_seconds
+ , (unsigned long) c->sa_rekey_margin
+ , (unsigned long) c->sa_rekey_fuzz
+ , (unsigned long) c->sa_keying_tries
+ , prettypolicy(c->policy));
+ );
+ }
+}
+
+/* Derive a template connection from a group connection and target.
+ * Similar to instantiate(). Happens at whack --listen.
+ * Returns name of new connection. May be NULL.
+ * Caller is responsible for pfreeing.
+ */
+char *
+add_group_instance(struct connection *group, const ip_subnet *target)
+{
+ char namebuf[100]
+ , targetbuf[SUBNETTOT_BUF];
+ struct connection *t;
+ char *name = NULL;
+
+ passert(group->kind == CK_GROUP);
+ passert(oriented(*group));
+
+ /* manufacture a unique name for this template */
+ subnettot(target, 0, targetbuf, sizeof(targetbuf));
+ snprintf(namebuf, sizeof(namebuf), "%s#%s", group->name, targetbuf);
+
+ if (con_by_name(namebuf, FALSE) != NULL)
+ {
+ loglog(RC_DUPNAME, "group name + target yields duplicate name \"%s\""
+ , namebuf);
+ }
+ else
+ {
+ t = clone_thing(*group, "group instance");
+ t->name = namebuf;
+ unshare_connection_strings(t);
+ name = clone_str(t->name, "group instance name");
+ t->spd.that.client = *target;
+ t->policy &= ~(POLICY_GROUP | POLICY_GROUTED);
+ t->kind = isanyaddr(&t->spd.that.host_addr) && !NEVER_NEGOTIATE(t->policy)
+ ? CK_TEMPLATE : CK_INSTANCE;
+
+ /* reset log file info */
+ t->log_file_name = NULL;
+ t->log_file = NULL;
+ t->log_file_err = FALSE;
+
+ t->spd.reqid = gen_reqid();
+
+#ifdef VIRTUAL_IP
+ if (t->spd.that.virt)
+ {
+ DBG_log("virtual_ip not supported in group instance");
+ t->spd.that.virt = NULL;
+ }
+#endif
+
+ /* add to connections list */
+ t->ac_next = connections;
+ connections = t;
+
+ /* same host_pair as parent: stick after parent on list */
+ group->hp_next = t;
+
+ /* route if group is routed */
+ if (group->policy & POLICY_GROUTED)
+ {
+ if (!trap_connection(t))
+ whack_log(RC_ROUTE, "could not route");
+ }
+ }
+ return name;
+}
+
+/* an old target has disappeared for a group: delete instance */
+void
+remove_group_instance(const struct connection *group USED_BY_DEBUG
+, const char *name)
+{
+ passert(group->kind == CK_GROUP);
+ passert(oriented(*group));
+
+ delete_connections_by_name(name, FALSE);
+}
+
+/* Common part of instantiating a Road Warrior or Opportunistic connection.
+ * his_id can be used to carry over an ID discovered in Phase 1.
+ * It must not disagree with the one in c, but if that is unspecified,
+ * the new connection will use his_id.
+ * If his_id is NULL, and c.that.id is uninstantiated (ID_NONE), the
+ * new connection will continue to have an uninstantiated that.id.
+ * Note: instantiation does not affect port numbers.
+ *
+ * Note that instantiate can only deal with a single SPD/eroute.
+ */
+static struct connection *
+instantiate(struct connection *c, const ip_address *him
+#ifdef NAT_TRAVERSAL
+, u_int16_t his_port
+#endif
+, const struct id *his_id)
+{
+ struct connection *d;
+ int wildcards;
+
+ passert(c->kind == CK_TEMPLATE);
+ passert(c->spd.next == NULL);
+
+ c->instance_serial++;
+ d = clone_thing(*c, "temporary connection");
+ if (his_id != NULL)
+ {
+ passert(match_id(his_id, &d->spd.that.id, &wildcards));
+ d->spd.that.id = *his_id;
+ d->spd.that.has_id_wildcards = FALSE;
+ }
+ unshare_connection_strings(d);
+ unshare_ietfAttrList(&d->spd.this.groups);
+ unshare_ietfAttrList(&d->spd.that.groups);
+ d->kind = CK_INSTANCE;
+
+ passert(oriented(*d));
+ d->spd.that.host_addr = *him;
+ setportof(htons(c->spd.that.port), &d->spd.that.host_addr);
+#ifdef NAT_TRAVERSAL
+ if (his_port) d->spd.that.host_port = his_port;
+#endif
+ default_end(&d->spd.that, &d->spd.this.host_addr);
+
+ /* We cannot guess what our next_hop should be, but if it was
+ * explicitly specified as 0.0.0.0, we set it to be him.
+ * (whack will not allow nexthop to be elided in RW case.)
+ */
+ default_end(&d->spd.this, &d->spd.that.host_addr);
+ d->spd.next = NULL;
+ d->spd.reqid = gen_reqid();
+
+ /* set internal fields */
+ d->ac_next = connections;
+ connections = d;
+ d->spd.routing = RT_UNROUTED;
+ d->newest_isakmp_sa = SOS_NOBODY;
+ d->newest_ipsec_sa = SOS_NOBODY;
+ d->spd.eroute_owner = SOS_NOBODY;
+
+ /* reset log file info */
+ d->log_file_name = NULL;
+ d->log_file = NULL;
+ d->log_file_err = FALSE;
+
+ connect_to_host_pair(d);
+
+ return d;
+}
+
+struct connection *
+rw_instantiate(struct connection *c
+, const ip_address *him
+#ifdef NAT_TRAVERSAL
+, u_int16_t his_port
+#endif
+#ifdef VIRTUAL_IP
+, const ip_subnet *his_net
+#endif
+, const struct id *his_id)
+{
+#ifdef NAT_TRAVERSAL
+ struct connection *d = instantiate(c, him, his_port, his_id);
+#else
+ struct connection *d = instantiate(c, him, his_id);
+#endif
+
+#ifdef VIRTUAL_IP
+ if (d && his_net && is_virtual_connection(c))
+ {
+ d->spd.that.client = *his_net;
+ d->spd.that.virt = NULL;
+ if (subnetishost(his_net) && addrinsubnet(him, his_net))
+ d->spd.that.has_client = FALSE;
+ }
+#endif
+
+ if (d->policy & POLICY_OPPO)
+ {
+ /* This must be before we know the client addresses.
+ * Fill in one that is impossible. This prevents anyone else from
+ * trying to use this connection to get to a particular client
+ */
+ d->spd.that.client = *aftoinfo(subnettypeof(&d->spd.that.client))->none;
+ }
+ DBG(DBG_CONTROL
+ , DBG_log("instantiated \"%s\" for %s" , d->name, ip_str(him)));
+ return d;
+}
+
+struct connection *
+oppo_instantiate(struct connection *c
+, const ip_address *him
+, const struct id *his_id
+, struct gw_info *gw
+, const ip_address *our_client USED_BY_DEBUG
+, const ip_address *peer_client)
+{
+#ifdef NAT_TRAVERSAL
+ struct connection *d = instantiate(c, him, 0, his_id);
+#else
+ struct connection *d = instantiate(c, him, his_id);
+#endif
+
+ passert(d->spd.next == NULL);
+
+ /* fill in our client side */
+ if (d->spd.this.has_client)
+ {
+ /* there was a client in the abstract connection
+ * so we demand that the required client is within that subnet.
+ */
+ passert(addrinsubnet(our_client, &d->spd.this.client));
+ happy(addrtosubnet(our_client, &d->spd.this.client));
+ /* opportunistic connections do not use port selectors */
+ setportof(0, &d->spd.this.client.addr);
+ }
+ else
+ {
+ /* there was no client in the abstract connection
+ * so we demand that the required client be the host
+ */
+ passert(sameaddr(our_client, &d->spd.this.host_addr));
+ }
+
+ /* fill in peer's client side.
+ * If the client is the peer, excise the client from the connection.
+ */
+ passert((d->policy & POLICY_OPPO)
+ && addrinsubnet(peer_client, &d->spd.that.client));
+ happy(addrtosubnet(peer_client, &d->spd.that.client));
+ /* opportunistic connections do not use port selectors */
+ setportof(0, &d->spd.that.client.addr);
+
+ if (sameaddr(peer_client, &d->spd.that.host_addr))
+ d->spd.that.has_client = FALSE;
+
+ passert(d->gw_info == NULL);
+ gw_addref(gw);
+ d->gw_info = gw;
+
+ /* Adjust routing if something is eclipsing c.
+ * It must be a %hold for us (hard to passert this).
+ * If there was another instance eclipsing, we'd be using it.
+ */
+ if (c->spd.routing == RT_ROUTED_ECLIPSED)
+ d->spd.routing = RT_ROUTED_PROSPECTIVE;
+
+ /* Remember if the template is routed:
+ * if so, this instance applies for initiation
+ * even if it is created for responding.
+ */
+ if (routed(c->spd.routing))
+ d->instance_initiation_ok = TRUE;
+
+ DBG(DBG_CONTROL,
+ char topo[CONNECTION_BUF];
+
+ (void) format_connection(topo, sizeof(topo), d, &d->spd);
+ DBG_log("instantiated \"%s\": %s", d->name, topo);
+ );
+ return d;
+}
+
+/* priority formatting */
+void
+fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF])
+{
+ if (pp == BOTTOM_PRIO)
+ snprintf(buf, POLICY_PRIO_BUF, "0");
+ else
+ snprintf(buf, POLICY_PRIO_BUF, "%lu,%lu"
+ , pp>>16, (pp & ~(~(policy_prio_t)0 << 16)) >> 8);
+}
+
+/* Format any information needed to identify an instance of a connection.
+ * Fills any needed information into buf which MUST be big enough.
+ * Road Warrior: peer's IP address
+ * Opportunistic: [" " myclient "==="] " ..." peer ["===" hisclient] '\0'
+ */
+static size_t
+fmt_client(const ip_subnet *client, const ip_address *gw, const char *prefix, char buf[ADDRTOT_BUF])
+{
+ if (subnetisaddr(client, gw))
+ {
+ buf[0] = '\0'; /* compact denotation for "self" */
+ }
+ else
+ {
+ char *ap;
+
+ strcpy(buf, prefix);
+ ap = buf + strlen(prefix);
+ if (subnetisnone(client))
+ strcpy(ap, "?"); /* unknown */
+ else
+ subnettot(client, 0, ap, SUBNETTOT_BUF);
+ }
+ return strlen(buf);
+}
+
+void
+fmt_conn_instance(const struct connection *c, char buf[CONN_INST_BUF])
+{
+ char *p = buf;
+
+ *p = '\0';
+
+ if (c->kind == CK_INSTANCE)
+ {
+ if (c->instance_serial != 0)
+ {
+ snprintf(p, CONN_INST_BUF, "[%lu]", c->instance_serial);
+ p += strlen(p);
+ }
+
+ if (c->policy & POLICY_OPPO)
+ {
+ size_t w = fmt_client(&c->spd.this.client, &c->spd.this.host_addr, " ", p);
+
+ p += w;
+
+ strcpy(p, w == 0? " ..." : "=== ...");
+ p += strlen(p);
+
+ addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF);
+ p += strlen(p);
+
+ (void) fmt_client(&c->spd.that.client, &c->spd.that.host_addr, "===", p);
+ }
+ else
+ {
+ *p++ = ' ';
+ addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF);
+#ifdef NAT_TRAVERSAL
+ if (c->spd.that.host_port != pluto_port)
+ {
+ p += strlen(p);
+ sprintf(p, ":%d", c->spd.that.host_port);
+ }
+#endif
+ }
+ }
+}
+
+/* Find an existing connection for a trapped outbound packet.
+ * This is attempted before we bother with gateway discovery.
+ * + this connection is routed or instance_of_routed_template
+ * (i.e. approved for on-demand)
+ * + this subnet contains our_client (or we are our_client)
+ * + that subnet contains peer_client (or peer is peer_client)
+ * + don't care about Phase 1 IDs (we don't know)
+ * Note: result may still need to be instantiated.
+ * The winner has the highest policy priority.
+ *
+ * If there are several with that priority, we give preference to
+ * the first one that is an instance.
+ *
+ * See also build_outgoing_opportunistic_connection.
+ */
+struct connection *
+find_connection_for_clients(struct spd_route **srp,
+ const ip_address *our_client,
+ const ip_address *peer_client,
+ int transport_proto)
+{
+ struct connection *c = connections, *best = NULL;
+ policy_prio_t best_prio = BOTTOM_PRIO;
+ struct spd_route *sr;
+ struct spd_route *best_sr = NULL;
+ int our_port = ntohs(portof(our_client));
+ int peer_port = ntohs(portof(peer_client));
+
+ passert(!isanyaddr(our_client) && !isanyaddr(peer_client));
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROL))
+ {
+ char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF];
+
+ addrtot(our_client, 0, ocb, sizeof(ocb));
+ addrtot(peer_client, 0, pcb, sizeof(pcb));
+ DBG_log("find_connection: "
+ "looking for policy for connection: %s:%d/%d -> %s:%d/%d"
+ , ocb, transport_proto, our_port, pcb, transport_proto, peer_port);
+ }
+#endif /* DEBUG */
+
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ if (c->kind == CK_GROUP)
+ continue;
+
+ for (sr = &c->spd; best!=c && sr; sr = sr->next)
+ {
+ if ((routed(sr->routing) || c->instance_initiation_ok)
+ && addrinsubnet(our_client, &sr->this.client)
+ && addrinsubnet(peer_client, &sr->that.client)
+ && addrinsubnet(peer_client, &sr->that.client)
+ && (!sr->this.protocol || transport_proto == sr->this.protocol)
+ && (!sr->this.port || our_port == sr->this.port)
+ && (!sr->that.port || peer_port == sr->that.port))
+ {
+ char cib[CONN_INST_BUF];
+ char cib2[CONN_INST_BUF];
+
+ policy_prio_t prio = 8 * (c->prio + (c->kind == CK_INSTANCE))
+ + 2 * (sr->this.port == our_port)
+ + 2 * (sr->that.port == peer_port)
+ + (sr->this.protocol == transport_proto);
+
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROL|DBG_CONTROLMORE))
+ {
+ char c_ocb[SUBNETTOT_BUF], c_pcb[SUBNETTOT_BUF];
+
+ subnettot(&c->spd.this.client, 0, c_ocb, sizeof(c_ocb));
+ subnettot(&c->spd.that.client, 0, c_pcb, sizeof(c_pcb));
+ DBG_log("find_connection: conn \"%s\"%s has compatible peers: %s->%s [pri: %ld]"
+ , c->name
+ , (fmt_conn_instance(c, cib), cib)
+ , c_ocb, c_pcb, prio);
+ }
+#endif /* DEBUG */
+
+ if (best == NULL)
+ {
+ best = c;
+ best_sr = sr;
+ best_prio = prio;
+ }
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("find_connection: "
+ "comparing best \"%s\"%s [pri:%ld]{%p} (child %s) to \"%s\"%s [pri:%ld]{%p} (child %s)"
+ , best->name
+ , (fmt_conn_instance(best, cib), cib)
+ , best_prio
+ , best
+ , (best->policy_next ? best->policy_next->name : "none")
+ , c->name
+ , (fmt_conn_instance(c, cib2), cib2)
+ , prio
+ , c
+ , (c->policy_next ? c->policy_next->name : "none")));
+
+ if (prio > best_prio)
+ {
+ best = c;
+ best_sr = sr;
+ best_prio = prio;
+ }
+ }
+ }
+ }
+
+ if (best!= NULL && NEVER_NEGOTIATE(best->policy))
+ best = NULL;
+
+ if (srp != NULL && best != NULL)
+ *srp = best_sr;
+
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROL))
+ {
+ if (best)
+ {
+ char cib[CONN_INST_BUF];
+ DBG_log("find_connection: concluding with \"%s\"%s [pri:%ld]{%p} kind=%s"
+ , best->name
+ , (fmt_conn_instance(best, cib), cib)
+ , best_prio
+ , best
+ , enum_name(&connection_kind_names, best->kind));
+ } else {
+ DBG_log("find_connection: concluding with empty");
+ }
+ }
+#endif /* DEBUG */
+
+ return best;
+}
+
+/* Find and instantiate a connection for an outgoing Opportunistic connection.
+ * We've already discovered its gateway.
+ * We look for a the connection such that:
+ * + this is one of our interfaces
+ * + this subnet contains our_client (or we are our_client)
+ * (we will specialize the client). We prefer the smallest such subnet.
+ * + that subnet contains peer_clent (we will specialize the client).
+ * We prefer the smallest such subnet.
+ * + is opportunistic
+ * + that peer is NO_IP
+ * + don't care about Phase 1 IDs (probably should be default)
+ * We could look for a connection that already had the desired peer
+ * (rather than NO_IP) specified, but it doesn't seem worth the
+ * bother.
+ *
+ * We look for the routed policy applying to the narrowest subnets.
+ * We only succeed if we find such a policy AND it is satisfactory.
+ *
+ * The body of the inner loop is a lot like that in
+ * find_connection_for_clients. In this case, we know the gateways
+ * that we need to instantiate an opportunistic connection.
+ */
+struct connection *
+build_outgoing_opportunistic_connection(struct gw_info *gw
+ ,const ip_address *our_client
+ ,const ip_address *peer_client)
+{
+ struct iface *p;
+ struct connection *best = NULL;
+ struct spd_route *sr, *bestsr;
+ char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF];
+
+ addrtot(our_client, 0, ocb, sizeof(ocb));
+ addrtot(peer_client, 0, pcb, sizeof(pcb));
+
+ passert(!isanyaddr(our_client) && !isanyaddr(peer_client));
+
+ /* We don't know his ID yet, so gw id must be an ipaddr */
+ passert(gw->key != NULL);
+ passert(id_is_ipaddr(&gw->gw_id));
+
+ /* for each of our addresses... */
+ for (p = interfaces; p != NULL; p = p->next)
+ {
+ /* go through those connections with our address and NO_IP as hosts
+ * We cannot know what port the peer would use, so we assume
+ * that it is pluto_port (makes debugging easier).
+ */
+ struct connection *c = find_host_pair_connections(&p->addr
+ , pluto_port, (ip_address *)NULL, pluto_port);
+
+ for (; c != NULL; c = c->hp_next)
+ {
+ DBG(DBG_OPPO,
+ DBG_log("checking %s", c->name));
+ if (c->kind == CK_GROUP)
+ {
+ continue;
+ }
+
+ for (sr = &c->spd; best!=c && sr; sr = sr->next)
+ {
+ if (routed(sr->routing)
+ && addrinsubnet(our_client, &sr->this.client)
+ && addrinsubnet(peer_client, &sr->that.client))
+ {
+ if (best == NULL)
+ {
+ best = c;
+ break;
+ }
+
+ DBG(DBG_OPPO,
+ DBG_log("comparing best %s to %s"
+ , best->name, c->name));
+
+ for (bestsr = &best->spd; best!=c && bestsr; bestsr=bestsr->next)
+ {
+ if (!subnetinsubnet(&bestsr->this.client, &sr->this.client)
+ || (samesubnet(&bestsr->this.client, &sr->this.client)
+ && !subnetinsubnet(&bestsr->that.client
+ , &sr->that.client)))
+ {
+ best = c;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (best == NULL
+ || NEVER_NEGOTIATE(best->policy)
+ || (best->policy & POLICY_OPPO) == LEMPTY
+ || best->kind != CK_TEMPLATE)
+ return NULL;
+ else
+ return oppo_instantiate(best, &gw->gw_id.ip_addr, NULL, gw
+ , our_client, peer_client);
+}
+
+bool
+orient(struct connection *c)
+{
+ struct spd_route *sr;
+
+ if (!oriented(*c))
+ {
+ struct iface *p;
+
+ for (sr = &c->spd; sr; sr = sr->next)
+ {
+ /* Note: this loop does not stop when it finds a match:
+ * it continues checking to catch any ambiguity.
+ */
+ for (p = interfaces; p != NULL; p = p->next)
+ {
+#ifdef NAT_TRAVERSAL
+ if (p->ike_float) continue;
+#endif
+ for (;;)
+ {
+ /* check if this interface matches this end */
+ if (sameaddr(&sr->this.host_addr, &p->addr)
+ && (!no_klips || sr->this.host_port == pluto_port))
+ {
+ if (oriented(*c))
+ {
+ if (c->interface == p)
+ loglog(RC_LOG_SERIOUS
+ , "both sides of \"%s\" are our interface %s!"
+ , c->name, p->rname);
+ else
+ loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)"
+ , c->name, c->interface->rname, p->rname);
+ c->interface = NULL; /* withdraw orientation */
+ return FALSE;
+ }
+ c->interface = p;
+ }
+
+ /* done with this interface if it doesn't match that end */
+ if (!(sameaddr(&sr->that.host_addr, &p->addr)
+ && (!no_klips || sr->that.host_port == pluto_port)))
+ break;
+
+ /* swap ends and try again.
+ * It is a little tricky to see that this loop will stop.
+ * Only continue if the far side matches.
+ * If both sides match, there is an error-out.
+ */
+ {
+ struct end t = sr->this;
+
+ sr->this = sr->that;
+ sr->that = t;
+ }
+ }
+ }
+ }
+ }
+ return oriented(*c);
+}
+
+void
+initiate_connection(const char *name, int whackfd)
+{
+ struct connection *c = con_by_name(name, TRUE);
+
+ if (c != NULL)
+ {
+ set_cur_connection(c);
+ if (!oriented(*c))
+ {
+ loglog(RC_ORIENT, "we have no ipsecN interface for either end of this connection");
+ }
+ else if (NEVER_NEGOTIATE(c->policy))
+ {
+ loglog(RC_INITSHUNT
+ , "cannot initiate an authby=never connection");
+ }
+ else if (c->kind != CK_PERMANENT)
+ {
+ if (isanyaddr(&c->spd.that.host_addr))
+ loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP address");
+ else
+ loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards");
+ }
+ else
+ {
+ /* We will only request an IPsec SA if policy isn't empty
+ * (ignoring Main Mode items).
+ * This is a fudge, but not yet important.
+ * If we are to proceed asynchronously, whackfd will be NULL_FD.
+ */
+ c->policy |= POLICY_UP;
+ /* do we have to prompt for a PIN code? */
+ if (c->spd.this.sc != NULL && !c->spd.this.sc->valid && whackfd != NULL_FD)
+ scx_get_pin(c->spd.this.sc, whackfd);
+
+ if (c->spd.this.sc != NULL && !c->spd.this.sc->valid)
+ {
+ loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN");
+ }
+ else
+ {
+ ipsecdoi_initiate(whackfd, c, c->policy, 1, SOS_NOBODY);
+ whackfd = NULL_FD; /* protect from close */
+ }
+ }
+ reset_cur_connection();
+ }
+ close_any(whackfd);
+}
+
+/* (Possibly) Opportunistic Initiation:
+ * Knowing clients (single IP addresses), try to build an tunnel.
+ * This may involve discovering a gateway and instantiating an
+ * Opportunistic connection. Called when a packet is caught by
+ * a %trap, or when whack --oppohere --oppothere is used.
+ * It may turn out that an existing or non-opporunistic connnection
+ * can handle the traffic.
+ *
+ * Most of the code will be restarted if an ADNS request is made
+ * to discover the gateway. The only difference between the first
+ * and second entry is whether gateways_from_dns is NULL or not.
+ * initiate_opportunistic: initial entrypoint
+ * continue_oppo: where we pickup when ADNS result arrives
+ * initiate_opportunistic_body: main body shared by above routines
+ * cannot_oppo: a helper function to log a diagnostic
+ * This structure repeats a lot of code when the ADNS result arrives.
+ * This seems like a waste, but anything learned the first time through
+ * may no longer be true!
+ *
+ * After the first IKE message is sent, the regular state machinery
+ * carries negotiation forward.
+ */
+
+enum find_oppo_step {
+ fos_start,
+ fos_myid_ip_txt,
+ fos_myid_hostname_txt,
+ fos_myid_ip_key,
+ fos_myid_hostname_key,
+ fos_our_client,
+ fos_our_txt,
+#ifdef USE_KEYRR
+ fos_our_key,
+#endif /* USE_KEYRR */
+ fos_his_client,
+ fos_done
+};
+
+#ifdef DEBUG
+static const char *const oppo_step_name[] = {
+ "fos_start",
+ "fos_myid_ip_txt",
+ "fos_myid_hostname_txt",
+ "fos_myid_ip_key",
+ "fos_myid_hostname_key",
+ "fos_our_client",
+ "fos_our_txt",
+#ifdef USE_KEYRR
+ "fos_our_key",
+#endif /* USE_KEYRR */
+ "fos_his_client",
+ "fos_done"
+};
+#endif /* DEBUG */
+
+struct find_oppo_bundle {
+ enum find_oppo_step step;
+ err_t want;
+ bool failure_ok; /* if true, continue_oppo should not die on DNS failure */
+ ip_address our_client; /* not pointer! */
+ ip_address peer_client;
+ int transport_proto;
+ bool held;
+ policy_prio_t policy_prio;
+ ipsec_spi_t failure_shunt; /* in host order! 0 for delete. */
+ int whackfd;
+};
+
+struct find_oppo_continuation {
+ struct adns_continuation ac; /* common prefix */
+ struct find_oppo_bundle b;
+};
+
+static void
+cannot_oppo(struct connection *c
+ , struct find_oppo_bundle *b
+ , err_t ugh)
+{
+ char pcb[ADDRTOT_BUF];
+ char ocb[ADDRTOT_BUF];
+
+ addrtot(&b->peer_client, 0, pcb, sizeof(pcb));
+ addrtot(&b->our_client, 0, ocb, sizeof(ocb));
+
+ DBG(DBG_DNS | DBG_OPPO, DBG_log("Can't Opportunistically initiate for %s to %s: %s"
+ , ocb, pcb, ugh));
+
+ whack_log(RC_OPPOFAILURE
+ , "Can't Opportunistically initiate for %s to %s: %s"
+ , ocb, pcb, ugh);
+
+ if (c != NULL && c->policy_next != NULL)
+ {
+ /* there is some policy that comes afterwards */
+ struct spd_route *shunt_spd;
+ struct connection *nc = c->policy_next;
+ struct state *st;
+
+ passert(c->kind == CK_TEMPLATE);
+ passert(c->policy_next->kind == CK_PERMANENT);
+
+ DBG(DBG_OPPO, DBG_log("OE failed for %s to %s, but %s overrides shunt"
+ , ocb, pcb, c->policy_next->name));
+
+ /*
+ * okay, here we need add to the "next" policy, which is ought
+ * to be an instance.
+ * We will add another entry to the spd_route list for the specific
+ * situation that we have.
+ */
+
+ shunt_spd = clone_thing(nc->spd, "shunt eroute policy");
+
+ shunt_spd->next = nc->spd.next;
+ nc->spd.next = shunt_spd;
+
+ happy(addrtosubnet(&b->peer_client, &shunt_spd->that.client));
+
+ if (sameaddr(&b->peer_client, &shunt_spd->that.host_addr))
+ shunt_spd->that.has_client = FALSE;
+
+ /*
+ * override the tunnel destination with the one from the secondaried
+ * policy
+ */
+ shunt_spd->that.host_addr = nc->spd.that.host_addr;
+
+ /* now, lookup the state, and poke it up.
+ */
+
+ st = state_with_serialno(nc->newest_ipsec_sa);
+
+ /* XXX what to do if the IPSEC SA has died? */
+ passert(st != NULL);
+
+ /* link the new connection instance to the state's list of
+ * connections
+ */
+
+ DBG(DBG_OPPO, DBG_log("installing state: %ld for %s to %s"
+ , nc->newest_ipsec_sa
+ , ocb, pcb));
+
+#ifdef DEBUG
+ if (DBGP(DBG_OPPO | DBG_CONTROLMORE))
+ {
+ char state_buf[LOG_WIDTH];
+ char state_buf2[LOG_WIDTH];
+ time_t n = now();
+
+ fmt_state(st, n, state_buf, sizeof(state_buf)
+ , state_buf2, sizeof(state_buf2));
+ DBG_log("cannot_oppo, failure SA1: %s", state_buf);
+ DBG_log("cannot_oppo, failure SA2: %s", state_buf2);
+ }
+#endif /* DEBUG */
+
+ if (!route_and_eroute(c, shunt_spd, st))
+ {
+ whack_log(RC_OPPOFAILURE
+ , "failed to instantiate shunt policy %s for %s to %s"
+ , c->name
+ , ocb, pcb);
+ }
+ return;
+ }
+
+#ifdef KLIPS
+ if (b->held)
+ {
+ /* Replace HOLD with b->failure_shunt.
+ * If no b->failure_shunt specified, use SPI_PASS -- THIS MAY CHANGE.
+ */
+ if (b->failure_shunt == 0)
+ {
+ DBG(DBG_OPPO, DBG_log("no explicit failure shunt for %s to %s; installing %%pass"
+ , ocb, pcb));
+ }
+
+ (void) replace_bare_shunt(&b->our_client, &b->peer_client
+ , b->policy_prio
+ , b->failure_shunt
+ , b->failure_shunt != 0
+ , b->transport_proto
+ , ugh);
+ }
+#endif
+}
+
+static void initiate_opportunistic_body(struct find_oppo_bundle *b
+ , struct adns_continuation *ac, err_t ac_ugh); /* forward */
+
+void
+initiate_opportunistic(const ip_address *our_client
+, const ip_address *peer_client
+, int transport_proto
+, bool held
+, int whackfd)
+{
+ struct find_oppo_bundle b;
+
+ b.want = (whackfd == NULL_FD ? "whack" : "acquire");
+ b.failure_ok = FALSE;
+ b.our_client = *our_client;
+ b.peer_client = *peer_client;
+ b.transport_proto = transport_proto;
+ b.held = held;
+ b.policy_prio = BOTTOM_PRIO;
+ b.failure_shunt = 0;
+ b.whackfd = whackfd;
+ b.step = fos_start;
+ initiate_opportunistic_body(&b, NULL, NULL);
+}
+
+static void
+continue_oppo(struct adns_continuation *acr, err_t ugh)
+{
+ struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */
+ struct connection *c;
+ bool was_held = cr->b.held;
+ int whackfd = cr->b.whackfd;
+
+ /* note: cr->id has no resources; cr->sgw_id is id_none:
+ * neither need freeing.
+ */
+ whack_log_fd = whackfd;
+
+#ifdef KLIPS
+ /* Discover and record whether %hold has gone away.
+ * This could have happened while we were awaiting DNS.
+ * We must check BEFORE any call to cannot_oppo.
+ */
+ if (was_held)
+ cr->b.held = has_bare_hold(&cr->b.our_client, &cr->b.peer_client
+ , cr->b.transport_proto);
+#endif
+
+#ifdef DEBUG
+ /* if we're going to ignore the error, at least note it in debugging log */
+ if (cr->b.failure_ok && ugh != NULL)
+ {
+ DBG(DBG_CONTROL | DBG_DNS,
+ {
+ char ocb[ADDRTOT_BUF];
+ char pcb[ADDRTOT_BUF];
+
+ addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb));
+ addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb));
+ DBG_log("continuing from failed DNS lookup for %s, %s to %s: %s"
+ , cr->b.want, ocb, pcb, ugh);
+ });
+ }
+#endif
+
+ if (!cr->b.failure_ok && ugh != NULL)
+ {
+ c = find_connection_for_clients(NULL, &cr->b.our_client, &cr->b.peer_client
+ , cr->b.transport_proto);
+ cannot_oppo(c, &cr->b
+ , builddiag("%s: %s", cr->b.want, ugh));
+ }
+ else if (was_held && !cr->b.held)
+ {
+ /* was_held indicates we were started due to a %trap firing
+ * (as opposed to a "whack --oppohere --oppothere").
+ * Since the %hold has gone, we can assume that somebody else
+ * has beaten us to the punch. We can go home. But lets log it.
+ */
+ char ocb[ADDRTOT_BUF];
+ char pcb[ADDRTOT_BUF];
+
+ addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb));
+ addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb));
+
+ loglog(RC_COMMENT
+ , "%%hold otherwise handled during DNS lookup for Opportunistic Initiation for %s to %s"
+ , ocb, pcb);
+ }
+ else
+ {
+ initiate_opportunistic_body(&cr->b, &cr->ac, ugh);
+ whackfd = NULL_FD; /* was handed off */
+ }
+
+ whack_log_fd = NULL_FD;
+ close_any(whackfd);
+}
+
+#ifdef USE_KEYRR
+static err_t
+check_key_recs(enum myid_state try_state
+, const struct connection *c
+, struct adns_continuation *ac)
+{
+ /* Check if KEY lookup yielded good results.
+ * Looking up based on our ID. Used if
+ * client is ourself, or if TXT had no public key.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ enum myid_state old_myid_state = myid_state;
+ const struct RSA_private_key *our_RSA_pri;
+ err_t ugh = NULL;
+
+ myid_state = try_state;
+
+ if (old_myid_state != myid_state
+ && old_myid_state == MYID_SPECIFIED)
+ {
+ ugh = "%myid was specified while we were guessing";
+ }
+ else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (!same_id(&ac->id, &c->spd.this.id))
+ {
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in RSA_check_signature
+ * for checking the other side.
+ */
+ pubkey_list_t *kr;
+
+ ugh = "no KEY RR found for us";
+ for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next)
+ {
+ ugh = "all our KEY RRs have the wrong public key";
+ if (kr->key->alg == PUBKEY_ALG_RSA
+ && same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ if (ugh != NULL)
+ myid_state = old_myid_state;
+ return ugh;
+}
+#endif /* USE_KEYRR */
+
+static err_t
+check_txt_recs(enum myid_state try_state
+, const struct connection *c
+, struct adns_continuation *ac)
+{
+ /* Check if TXT lookup yielded good results.
+ * Looking up based on our ID. Used if
+ * client is ourself, or if TXT had no public key.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ enum myid_state old_myid_state = myid_state;
+ const struct RSA_private_key *our_RSA_pri;
+ err_t ugh = NULL;
+
+ myid_state = try_state;
+
+ if (old_myid_state != myid_state
+ && old_myid_state == MYID_SPECIFIED)
+ {
+ ugh = "%myid was specified while we were guessing";
+ }
+ else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (!same_id(&ac->id, &c->spd.this.id))
+ {
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in RSA_check_signature
+ * for checking the other side.
+ */
+ struct gw_info *gwp;
+
+ ugh = "no TXT RR found for us";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ ugh = "all our TXT RRs have the wrong public key";
+ if (gwp->key->alg == PUBKEY_ALG_RSA
+ && same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ if (ugh != NULL)
+ myid_state = old_myid_state;
+ return ugh;
+}
+
+
+/* note: gateways_from_dns must be NULL iff this is the first call */
+static void
+initiate_opportunistic_body(struct find_oppo_bundle *b
+, struct adns_continuation *ac
+, err_t ac_ugh)
+{
+ struct connection *c;
+ struct spd_route *sr;
+
+ /* What connection shall we use?
+ * First try for one that explicitly handles the clients.
+ */
+ DBG(DBG_CONTROL,
+ {
+ char ours[ADDRTOT_BUF];
+ char his[ADDRTOT_BUF];
+ int ourport;
+ int hisport;
+
+ addrtot(&b->our_client, 0, ours, sizeof(ours));
+ addrtot(&b->peer_client, 0, his, sizeof(his));
+ ourport = ntohs(portof(&b->our_client));
+ hisport = ntohs(portof(&b->peer_client));
+ DBG_log("initiate on demand from %s:%d to %s:%d proto=%d state: %s because: %s"
+ , ours, ourport, his, hisport, b->transport_proto
+ , oppo_step_name[b->step], b->want);
+ });
+ if (isanyaddr(&b->our_client) || isanyaddr(&b->peer_client))
+ {
+ cannot_oppo(NULL, b, "impossible IP address");
+ }
+ else if ((c = find_connection_for_clients(&sr
+ , &b->our_client
+ , &b->peer_client
+ , b->transport_proto)) == NULL)
+ {
+ /* No connection explicitly handles the clients and there
+ * are no Opportunistic connections -- whine and give up.
+ * The failure policy cannot be gotten from a connection; we pick %pass.
+ */
+ cannot_oppo(NULL, b, "no routed Opportunistic template covers this pair");
+ }
+ else if (c->kind != CK_TEMPLATE)
+ {
+ /* We've found a connection that can serve.
+ * Do we have to initiate it?
+ * Not if there is currently an IPSEC SA.
+ * But if there is an IPSEC SA, then KLIPS would not
+ * have generated the acquire. So we assume that there isn't one.
+ * This may be redundant if a non-opportunistic
+ * negotiation is already being attempted.
+ */
+
+ /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */
+
+ if(c->kind == CK_INSTANCE)
+ {
+ char cib[CONN_INST_BUF];
+ /* there is already an instance being negotiated, no nothing */
+ DBG(DBG_CONTROL, DBG_log("found existing instance \"%s\"%s, rekeying it"
+ , c->name
+ , (fmt_conn_instance(c, cib), cib)));
+ /* XXX-mcr - return; */
+ }
+
+ /* otherwise, there is some kind of static conn that can handle
+ * this connection, so we initiate it */
+
+#ifdef KLIPS
+ if (b->held)
+ {
+ /* what should we do on failure? */
+ (void) assign_hold(c, sr, b->transport_proto, &b->our_client, &b->peer_client);
+ }
+#endif
+ ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY);
+ b->whackfd = NULL_FD; /* protect from close */
+ }
+ else
+ {
+ /* We are handling an opportunistic situation.
+ * This involves several DNS lookup steps that require suspension.
+ * Note: many facts might change while we're suspended.
+ * Here be dragons.
+ *
+ * The first chunk of code handles the result of the previous
+ * DNS query (if any). It also selects the kind of the next step.
+ * The second chunk initiates the next DNS query (if any).
+ */
+ enum find_oppo_step next_step;
+ err_t ugh = ac_ugh;
+ char mycredentialstr[BUF_LEN];
+ char cib[CONN_INST_BUF];
+
+ DBG(DBG_CONTROL, DBG_log("creating new instance from \"%s\"%s"
+ , c->name
+ , (fmt_conn_instance(c, cib), cib)));
+
+
+ idtoa(&sr->this.id, mycredentialstr, sizeof(mycredentialstr));
+
+ passert(c->policy & POLICY_OPPO); /* can't initiate Road Warrior connections */
+
+ /* handle any DNS answer; select next step */
+
+ switch (b->step)
+ {
+ case fos_start:
+ /* just starting out: select first query step */
+ next_step = fos_myid_ip_txt;
+ break;
+
+ case fos_myid_ip_txt: /* TXT for our default IP address as %myid */
+ ugh = check_txt_recs(MYID_IP, c, ac);
+ if (ugh != NULL)
+ {
+ /* cannot use our IP as OE identitiy for initiation */
+ DBG(DBG_OPPO, DBG_log("can not use our IP (%s:TXT) as identity: %s"
+ , myid_str[MYID_IP]
+ , ugh));
+ if (!logged_myid_ip_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "can not use our IP (%s:TXT) as identity: %s"
+ , myid_str[MYID_IP]
+ , ugh);
+ logged_myid_ip_txt_warning = TRUE;
+ }
+
+ next_step = fos_myid_hostname_txt;
+ ugh = NULL; /* failure can be recovered from */
+ }
+ else
+ {
+ /* we can use our IP as OE identity for initiation */
+ if (!logged_myid_ip_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "using our IP (%s:TXT) as identity!"
+ , myid_str[MYID_IP]);
+ logged_myid_ip_txt_warning = TRUE;
+ }
+
+ next_step = fos_our_client;
+ }
+ break;
+
+ case fos_myid_hostname_txt: /* TXT for our hostname as %myid */
+ ugh = check_txt_recs(MYID_HOSTNAME, c, ac);
+ if (ugh != NULL)
+ {
+ /* cannot use our hostname as OE identitiy for initiation */
+ DBG(DBG_OPPO, DBG_log("can not use our hostname (%s:TXT) as identity: %s"
+ , myid_str[MYID_HOSTNAME]
+ , ugh));
+ if (!logged_myid_fqdn_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "can not use our hostname (%s:TXT) as identity: %s"
+ , myid_str[MYID_HOSTNAME]
+ , ugh);
+ logged_myid_fqdn_txt_warning = TRUE;
+ }
+#ifdef USE_KEYRR
+ next_step = fos_myid_ip_key;
+ ugh = NULL; /* failure can be recovered from */
+#endif
+ }
+ else
+ {
+ /* we can use our hostname as OE identity for initiation */
+ if (!logged_myid_fqdn_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "using our hostname (%s:TXT) as identity!"
+ , myid_str[MYID_HOSTNAME]);
+ logged_myid_fqdn_txt_warning = TRUE;
+ }
+ next_step = fos_our_client;
+ }
+ break;
+
+#ifdef USE_KEYRR
+ case fos_myid_ip_key: /* KEY for our default IP address as %myid */
+ ugh = check_key_recs(MYID_IP, c, ac);
+ if (ugh != NULL)
+ {
+ /* cannot use our IP as OE identitiy for initiation */
+ DBG(DBG_OPPO, DBG_log("can not use our IP (%s:KEY) as identity: %s"
+ , myid_str[MYID_IP]
+ , ugh));
+ if (!logged_myid_ip_key_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "can not use our IP (%s:KEY) as identity: %s"
+ , myid_str[MYID_IP]
+ , ugh);
+ logged_myid_ip_key_warning = TRUE;
+ }
+
+ next_step = fos_myid_hostname_key;
+ ugh = NULL; /* failure can be recovered from */
+ }
+ else
+ {
+ /* we can use our IP as OE identity for initiation */
+ if (!logged_myid_ip_key_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "using our IP (%s:KEY) as identity!"
+ , myid_str[MYID_IP]);
+ logged_myid_ip_key_warning = TRUE;
+ }
+ next_step = fos_our_client;
+ }
+ break;
+
+ case fos_myid_hostname_key: /* KEY for our hostname as %myid */
+ ugh = check_key_recs(MYID_HOSTNAME, c, ac);
+ if (ugh != NULL)
+ {
+ /* cannot use our IP as OE identitiy for initiation */
+ DBG(DBG_OPPO, DBG_log("can not use our hostname (%s:KEY) as identity: %s"
+ , myid_str[MYID_HOSTNAME]
+ , ugh));
+ if (!logged_myid_fqdn_key_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "can not use our hostname (%s:KEY) as identity: %s"
+ , myid_str[MYID_HOSTNAME]
+ , ugh);
+ logged_myid_fqdn_key_warning = TRUE;
+ }
+
+ next_step = fos_myid_hostname_key;
+ ugh = NULL; /* failure can be recovered from */
+ }
+ else
+ {
+ /* we can use our IP as OE identity for initiation */
+ if (!logged_myid_fqdn_key_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "using our hostname (%s:KEY) as identity!"
+ , myid_str[MYID_HOSTNAME]);
+ logged_myid_fqdn_key_warning = TRUE;
+ }
+ next_step = fos_our_client;
+ }
+ break;
+#endif
+
+ case fos_our_client: /* TXT for our client */
+ {
+ /* Our client is not us: we must check the TXT records.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
+
+ next_step = fos_his_client; /* normal situation */
+
+ passert(sr != NULL);
+
+ if (our_RSA_pri == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (sameaddr(&sr->this.host_addr, &b->our_client))
+ {
+ /* this wasn't true when we started -- bail */
+ ugh = "our IP address changed underfoot";
+ }
+ else if (!same_id(&ac->sgw_id, &sr->this.id))
+ {
+ /* this wasn't true when we started -- bail */
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in quick_inI1_outR1_tail
+ * for checking the other side.
+ */
+ struct gw_info *gwp;
+
+ ugh = "no TXT RR for our client delegates us";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ passert(same_id(&gwp->gw_id, &sr->this.id));
+
+ ugh = "TXT RR for our client has wrong key";
+ /* If there is a key from the TXT record,
+ * we count it as a win if we match the key.
+ * If there was no key, we have a tentative win:
+ * we need to check our KEY record to be sure.
+ */
+ if (!gwp->gw_key_present)
+ {
+ /* Success, but the TXT had no key
+ * so we must check our our own KEY records.
+ */
+ next_step = fos_our_txt;
+ ugh = NULL; /* good! */
+ break;
+ }
+ if (same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case fos_our_txt: /* TXT for us */
+ {
+ /* Check if TXT lookup yielded good results.
+ * Looking up based on our ID. Used if
+ * client is ourself, or if TXT had no public key.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
+
+ next_step = fos_his_client; /* unless we decide to look for KEY RR */
+
+ if (our_RSA_pri == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (!same_id(&ac->id, &c->spd.this.id))
+ {
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in RSA_check_signature
+ * for checking the other side.
+ */
+ struct gw_info *gwp;
+
+ ugh = "no TXT RR for us";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ passert(same_id(&gwp->gw_id, &sr->this.id));
+
+ ugh = "TXT RR for us has wrong key";
+ if (gwp->gw_key_present
+ && same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("initiate on demand found TXT with right public key at: %s"
+ , mycredentialstr));
+ ugh = NULL;
+ break;
+ }
+ }
+#ifdef USE_KEYRR
+ if (ugh != NULL)
+ {
+ /* if no TXT with right key, try KEY */
+ DBG(DBG_CONTROL,
+ DBG_log("will try for KEY RR since initiate on demand found %s: %s"
+ , ugh, mycredentialstr));
+ next_step = fos_our_key;
+ ugh = NULL;
+ }
+#endif
+ }
+ }
+ break;
+
+#ifdef USE_KEYRR
+ case fos_our_key: /* KEY for us */
+ {
+ /* Check if KEY lookup yielded good results.
+ * Looking up based on our ID. Used if
+ * client is ourself, or if TXT had no public key.
+ * Note: if c is different this time, there is
+ * a chance that we did the wrong query.
+ * If so, treat as a kind of failure.
+ */
+ const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
+
+ next_step = fos_his_client; /* always */
+
+ if (our_RSA_pri == NULL)
+ {
+ ugh = "we don't know our own RSA key";
+ }
+ else if (!same_id(&ac->id, &c->spd.this.id))
+ {
+ ugh = "our ID changed underfoot";
+ }
+ else
+ {
+ /* Similar to code in RSA_check_signature
+ * for checking the other side.
+ */
+ pubkey_list_t *kr;
+
+ ugh = "no KEY RR found for us (and no good TXT RR)";
+ for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next)
+ {
+ ugh = "all our KEY RRs have the wrong public key (and no good TXT RR)";
+ if (kr->key->alg == PUBKEY_ALG_RSA
+ && same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
+ {
+ /* do this only once a day */
+ if (!logged_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "found KEY RR but not TXT RR for %s. See http://www.freeswan.org/err/txt-change.html."
+ , mycredentialstr);
+ logged_txt_warning = TRUE;
+ }
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ }
+ break;
+#endif /* USE_KEYRR */
+
+ case fos_his_client: /* TXT for his client */
+ {
+ /* We've finished last DNS queries: TXT for his client.
+ * Using the information, try to instantiate a connection
+ * and start negotiating.
+ * We now know the peer. The chosing of "c" ignored this,
+ * so we will disregard its current value.
+ * !!! We need to randomize the entry in gw that we choose.
+ */
+ next_step = fos_done; /* no more queries */
+
+ c = build_outgoing_opportunistic_connection(ac->gateways_from_dns
+ , &b->our_client
+ , &b->peer_client);
+
+ if (c == NULL)
+ {
+ /* We cannot seem to instantiate a suitable connection:
+ * complain clearly.
+ */
+ char ocb[ADDRTOT_BUF]
+ , pcb[ADDRTOT_BUF]
+ , pb[ADDRTOT_BUF];
+
+ addrtot(&b->our_client, 0, ocb, sizeof(ocb));
+ addrtot(&b->peer_client, 0, pcb, sizeof(pcb));
+ passert(id_is_ipaddr(&ac->gateways_from_dns->gw_id));
+ addrtot(&ac->gateways_from_dns->gw_id.ip_addr, 0, pb, sizeof(pb));
+ loglog(RC_OPPOFAILURE
+ , "no suitable connection for opportunism"
+ " between %s and %s with %s as peer"
+ , ocb, pcb, pb);
+
+#ifdef KLIPS
+ if (b->held)
+ {
+ /* Replace HOLD with PASS.
+ * The type of replacement *ought* to be
+ * specified by policy.
+ */
+ (void) replace_bare_shunt(&b->our_client, &b->peer_client
+ , BOTTOM_PRIO
+ , SPI_PASS /* fail into PASS */
+ , TRUE, b->transport_proto
+ , "no suitable connection");
+ }
+#endif
+ }
+ else
+ {
+ /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */
+ passert(c->kind == CK_INSTANCE);
+ passert(c->gw_info != NULL);
+ passert(HAS_IPSEC_POLICY(c->policy));
+ passert(LHAS(LELEM(RT_UNROUTED) | LELEM(RT_ROUTED_PROSPECTIVE), c->spd.routing));
+#ifdef KLIPS
+ if (b->held)
+ {
+ /* what should we do on failure? */
+ (void) assign_hold(c, &c->spd
+ , b->transport_proto
+ , &b->our_client, &b->peer_client);
+ }
+#endif
+ c->gw_info->key->last_tried_time = now();
+ ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY);
+ b->whackfd = NULL_FD; /* protect from close */
+ }
+ }
+ break;
+
+ default:
+ bad_case(b->step);
+ }
+
+ /* the second chunk: initiate the next DNS query (if any) */
+ DBG(DBG_CONTROL,
+ {
+ char ours[ADDRTOT_BUF];
+ char his[ADDRTOT_BUF];
+
+ addrtot(&b->our_client, 0, ours, sizeof(ours));
+ addrtot(&b->peer_client, 0, his, sizeof(his));
+ DBG_log("initiate on demand from %s to %s new state: %s with ugh: %s"
+ , ours, his, oppo_step_name[b->step], ugh ? ugh : "ok");
+ });
+
+ if (ugh != NULL)
+ {
+ b->policy_prio = c->prio;
+ b->failure_shunt = shunt_policy_spi(c, FALSE);
+ cannot_oppo(c, b, ugh);
+ }
+ else if (next_step == fos_done)
+ {
+ /* nothing to do */
+ }
+ else
+ {
+ /* set up the next query */
+ struct find_oppo_continuation *cr = alloc_thing(struct find_oppo_continuation
+ , "opportunistic continuation");
+ struct id id;
+
+ b->policy_prio = c->prio;
+ b->failure_shunt = shunt_policy_spi(c, FALSE);
+ cr->b = *b; /* copy; start hand off of whackfd */
+ cr->b.failure_ok = FALSE;
+ cr->b.step = next_step;
+
+ for (sr = &c->spd
+ ; sr!=NULL && !sameaddr(&sr->this.host_addr, &b->our_client)
+ ; sr = sr->next)
+ ;
+
+ if (sr == NULL)
+ sr = &c->spd;
+
+ /* If a %hold shunt has replaced the eroute for this template,
+ * record this fact.
+ */
+ if (b->held
+ && sr->routing == RT_ROUTED_PROSPECTIVE && eclipsable(sr))
+ {
+ sr->routing = RT_ROUTED_ECLIPSED;
+ eclipse_count++;
+ }
+
+ /* Switch to issue next query.
+ * A case may turn out to be unnecessary. If so, it falls
+ * through to the next case.
+ * Figuring out what %myid can stand for must be done before
+ * our client credentials are looked up: we must know what
+ * the client credentials may use to identify us.
+ * On the other hand, our own credentials should be looked
+ * up after our clients in case our credentials are not
+ * needed at all.
+ * XXX this is a wasted effort if we don't have credentials
+ * BUT they are not needed.
+ */
+ switch (next_step)
+ {
+ case fos_myid_ip_txt:
+ if (c->spd.this.id.kind == ID_MYID
+ && myid_state != MYID_SPECIFIED)
+ {
+ cr->b.failure_ok = TRUE;
+ cr->b.want = b->want = "TXT record for IP address as %myid";
+ ugh = start_adns_query(&myids[MYID_IP]
+ , &myids[MYID_IP]
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+ cr->b.step = fos_myid_hostname_txt;
+ /* fall through */
+
+ case fos_myid_hostname_txt:
+ if (c->spd.this.id.kind == ID_MYID
+ && myid_state != MYID_SPECIFIED)
+ {
+#ifdef USE_KEYRR
+ cr->b.failure_ok = TRUE;
+#else
+ cr->b.failure_ok = FALSE;
+#endif
+ cr->b.want = b->want = "TXT record for hostname as %myid";
+ ugh = start_adns_query(&myids[MYID_HOSTNAME]
+ , &myids[MYID_HOSTNAME]
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+
+#ifdef USE_KEYRR
+ cr->b.step = fos_myid_ip_key;
+ /* fall through */
+
+ case fos_myid_ip_key:
+ if (c->spd.this.id.kind == ID_MYID
+ && myid_state != MYID_SPECIFIED)
+ {
+ cr->b.failure_ok = TRUE;
+ cr->b.want = b->want = "KEY record for IP address as %myid (no good TXT)";
+ ugh = start_adns_query(&myids[MYID_IP]
+ , (const struct id *) NULL /* security gateway meaningless */
+ , T_KEY
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+ cr->b.step = fos_myid_hostname_key;
+ /* fall through */
+
+ case fos_myid_hostname_key:
+ if (c->spd.this.id.kind == ID_MYID
+ && myid_state != MYID_SPECIFIED)
+ {
+ cr->b.failure_ok = FALSE; /* last attempt! */
+ cr->b.want = b->want = "KEY record for hostname as %myid (no good TXT)";
+ ugh = start_adns_query(&myids[MYID_HOSTNAME]
+ , (const struct id *) NULL /* security gateway meaningless */
+ , T_KEY
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+#endif
+ cr->b.step = fos_our_client;
+ /* fall through */
+
+ case fos_our_client: /* TXT for our client */
+ if (!sameaddr(&c->spd.this.host_addr, &b->our_client))
+ {
+ /* Check that at least one TXT(reverse(b->our_client)) is workable.
+ * Note: {unshare|free}_id_content not needed for id: ephemeral.
+ */
+ cr->b.want = b->want = "our client's TXT record";
+ iptoid(&b->our_client, &id);
+ ugh = start_adns_query(&id
+ , &c->spd.this.id /* we are the security gateway */
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+ }
+ cr->b.step = fos_our_txt;
+ /* fall through */
+
+ case fos_our_txt: /* TXT for us */
+ cr->b.failure_ok = b->failure_ok = TRUE;
+ cr->b.want = b->want = "our TXT record";
+ ugh = start_adns_query(&sr->this.id
+ , &sr->this.id /* we are the security gateway XXX - maybe ignore? mcr */
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+
+#ifdef USE_KEYRR
+ case fos_our_key: /* KEY for us */
+ cr->b.want = b->want = "our KEY record";
+ cr->b.failure_ok = b->failure_ok = FALSE;
+ ugh = start_adns_query(&sr->this.id
+ , (const struct id *) NULL /* security gateway meaningless */
+ , T_KEY
+ , continue_oppo
+ , &cr->ac);
+ break;
+#endif /* USE_KEYRR */
+
+ case fos_his_client: /* TXT for his client */
+ /* note: {unshare|free}_id_content not needed for id: ephemeral */
+ cr->b.want = b->want = "target's TXT record";
+ cr->b.failure_ok = b->failure_ok = FALSE;
+ iptoid(&b->peer_client, &id);
+ ugh = start_adns_query(&id
+ , (const struct id *) NULL /* security gateway unconstrained */
+ , T_TXT
+ , continue_oppo
+ , &cr->ac);
+ break;
+
+ default:
+ bad_case(next_step);
+ }
+
+ if (ugh == NULL)
+ b->whackfd = NULL_FD; /* complete hand-off */
+ else
+ cannot_oppo(c, b, ugh);
+ }
+ }
+ close_any(b->whackfd);
+}
+
+void
+terminate_connection(const char *nm)
+{
+ /* Loop because more than one may match (master and instances)
+ * But at least one is required (enforced by con_by_name).
+ */
+ struct connection *c, *n;
+
+ for (c = con_by_name(nm, TRUE); c != NULL; c = n)
+ {
+ n = c->ac_next; /* grab this before c might disappear */
+ if (streq(c->name, nm)
+ && c->kind >= CK_PERMANENT
+ && !NEVER_NEGOTIATE(c->policy))
+ {
+ set_cur_connection(c);
+ plog("terminating SAs using this connection");
+ c->policy &= ~POLICY_UP;
+ flush_pending_by_connection(c);
+ delete_states_by_connection(c, FALSE);
+ reset_cur_connection();
+ }
+ }
+}
+
+/* check nexthop safety
+ * Our nexthop must not be within a routed client subnet, and vice versa.
+ * Note: we don't think this is true. We think that KLIPS will
+ * not process a packet output by an eroute.
+ */
+#ifdef NEVER
+//bool
+//check_nexthop(const struct connection *c)
+//{
+// struct connection *d;
+//
+// if (addrinsubnet(&c->spd.this.host_nexthop, &c->spd.that.client))
+// {
+// loglog(RC_LOG_SERIOUS, "cannot perform routing for connection \"%s\""
+// " because nexthop is within peer's client network",
+// c->name);
+// return FALSE;
+// }
+//
+// for (d = connections; d != NULL; d = d->next)
+// {
+// if (d->routing != RT_UNROUTED)
+// {
+// if (addrinsubnet(&c->spd.this.host_nexthop, &d->spd.that.client))
+// {
+// loglog(RC_LOG_SERIOUS, "cannot do routing for connection \"%s\"
+// " because nexthop is contained in"
+// " existing routing for connection \"%s\"",
+// c->name, d->name);
+// return FALSE;
+// }
+// if (addrinsubnet(&d->spd.this.host_nexthop, &c->spd.that.client))
+// {
+// loglog(RC_LOG_SERIOUS, "cannot do routing for connection \"%s\"
+// " because it contains nexthop of"
+// " existing routing for connection \"%s\"",
+// c->name, d->name);
+// return FALSE;
+// }
+// }
+// }
+// return TRUE;
+//}
+#endif /* NEVER */
+
+/* an ISAKMP SA has been established.
+ * Note the serial number, and release any connections with
+ * the same peer ID but different peer IP address.
+ */
+bool uniqueIDs = FALSE; /* --uniqueids? */
+
+void
+ISAKMP_SA_established(struct connection *c, so_serial_t serial)
+{
+ c->newest_isakmp_sa = serial;
+
+ /* the connection is now oriented so that we are able to determine
+ * whether we are a mode config server with a virtual IP to send.
+ */
+ if (!isanyaddr(&c->spd.that.host_srcip))
+ c->spd.that.modecfg = TRUE;
+
+ if (uniqueIDs)
+ {
+ /* for all connections: if the same Phase 1 IDs are used
+ * for a different IP address, unorient that connection.
+ */
+ struct connection *d;
+
+ for (d = connections; d != NULL; )
+ {
+ struct connection *next = d->ac_next; /* might move underneath us */
+
+#ifdef NAT_TRAVERSAL
+ if (d->kind >= CK_PERMANENT
+ && same_id(&c->spd.this.id, &d->spd.this.id)
+ && same_id(&c->spd.that.id, &d->spd.that.id)
+ && (!sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr) ||
+ (c->spd.that.host_port != d->spd.that.host_port)))
+#else
+ if (d->kind >= CK_PERMANENT
+ && same_id(&c->spd.this.id, &d->spd.this.id)
+ && same_id(&c->spd.that.id, &d->spd.that.id)
+ && !sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr))
+#endif
+ {
+ release_connection(d, FALSE);
+ }
+ d = next;
+ }
+ }
+}
+
+/* Find the connection to connection c's peer's client with the
+ * largest value of .routing. All other things being equal,
+ * preference is given to c. If none is routed, return NULL.
+ *
+ * If erop is non-null, set *erop to a connection sharing both
+ * our client subnet and peer's client subnet with the largest value
+ * of .routing. If none is erouted, set *erop to NULL.
+ *
+ * The return value is used to find other connections sharing a route.
+ * *erop is used to find other connections sharing an eroute.
+ */
+struct connection *
+route_owner(struct connection *c
+ , struct spd_route **srp
+ , struct connection **erop
+ , struct spd_route **esrp)
+{
+ struct connection *d
+ , *best_ro = c
+ , *best_ero = c;
+ struct spd_route *srd, *src;
+ struct spd_route *best_sr, *best_esr;
+ enum routing_t best_routing, best_erouting;
+
+ passert(oriented(*c));
+ best_sr = NULL;
+ best_esr = NULL;
+ best_routing = c->spd.routing;
+ best_erouting = best_routing;
+
+ for (d = connections; d != NULL; d = d->ac_next)
+ {
+ for (srd = &d->spd; srd; srd = srd->next)
+ {
+ if (srd->routing == RT_UNROUTED)
+ continue;
+
+ for (src = &c->spd; src; src=src->next)
+ {
+ if (!samesubnet(&src->that.client, &srd->that.client))
+ continue;
+ if (src->that.protocol != srd->that.protocol)
+ continue;
+ if (src->that.port != srd->that.port)
+ continue;
+ passert(oriented(*d));
+ if (srd->routing > best_routing)
+ {
+ best_ro = d;
+ best_sr = srd;
+ best_routing = srd->routing;
+ }
+
+ if (!samesubnet(&src->this.client, &srd->this.client))
+ continue;
+ if (src->this.protocol != srd->this.protocol)
+ continue;
+ if (src->this.port != srd->this.port)
+ continue;
+ if (srd->routing > best_erouting)
+ {
+ best_ero = d;
+ best_esr = srd;
+ best_erouting = srd->routing;
+ }
+ }
+ }
+ }
+
+ DBG(DBG_CONTROL,
+ {
+ char cib[CONN_INST_BUF];
+ err_t m = builddiag("route owner of \"%s\"%s %s:"
+ , c->name
+ , (fmt_conn_instance(c, cib), cib)
+ , enum_name(&routing_story, c->spd.routing));
+
+ if (!routed(best_ro->spd.routing))
+ m = builddiag("%s NULL", m);
+ else if (best_ro == c)
+ m = builddiag("%s self", m);
+ else
+ m = builddiag("%s \"%s\"%s %s", m
+ , best_ro->name
+ , (fmt_conn_instance(best_ro, cib), cib)
+ , enum_name(&routing_story, best_ro->spd.routing));
+
+ if (erop != NULL)
+ {
+ m = builddiag("%s; eroute owner:", m);
+ if (!erouted(best_ero->spd.routing))
+ m = builddiag("%s NULL", m);
+ else if (best_ero == c)
+ m = builddiag("%s self", m);
+ else
+ m = builddiag("%s \"%s\"%s %s", m
+ , best_ero->name
+ , (fmt_conn_instance(best_ero, cib), cib)
+ , enum_name(&routing_story, best_ero->spd.routing));
+ }
+
+ DBG_log("%s", m);
+ });
+
+ if (erop != NULL)
+ *erop = erouted(best_erouting)? best_ero : NULL;
+
+ if (srp != NULL )
+ {
+ *srp = best_sr;
+ if (esrp != NULL )
+ *esrp = best_esr;
+ }
+
+ return routed(best_routing)? best_ro : NULL;
+}
+
+/* Find a connection that owns the shunt eroute between subnets.
+ * There ought to be only one.
+ * This might get to be a bottleneck -- try hashing if it does.
+ */
+struct connection *
+shunt_owner(const ip_subnet *ours, const ip_subnet *his)
+{
+ struct connection *c;
+ struct spd_route *sr;
+
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ for (sr = &c->spd; sr; sr = sr->next)
+ {
+ if (shunt_erouted(sr->routing)
+ && samesubnet(ours, &sr->this.client)
+ && samesubnet(his, &sr->that.client))
+ return c;
+ }
+ }
+ return NULL;
+}
+
+/* Find some connection with this pair of hosts.
+ * We don't know enough to chose amongst those available.
+ * ??? no longer usefully different from find_host_pair_connections
+ */
+struct connection *
+find_host_connection(const ip_address *me, u_int16_t my_port
+, const ip_address *him, u_int16_t his_port, lset_t policy)
+{
+ struct connection *c = find_host_pair_connections(me, my_port, him, his_port);
+
+ if (policy != LEMPTY)
+ {
+ /* if we have requirements for the policy,
+ * choose the first matching connection.
+ */
+ while (c != NULL)
+ {
+ if ((c->policy & policy) == policy)
+ break;
+ c = c->hp_next;
+ }
+ }
+ return c;
+}
+
+/* given an up-until-now satisfactory connection, find the best connection
+ * now that we just got the Phase 1 Id Payload from the peer.
+ *
+ * Comments in the code describe the (tricky!) matching criteria.
+ * Although this routine could handle the initiator case,
+ * it isn't currently called in this case.
+ * If it were, it could "upgrade" an Opportunistic Connection
+ * to a Road Warrior Connection if a suitable Peer ID were found.
+ *
+ * In RFC 2409 "The Internet Key Exchange (IKE)",
+ * in 5.1 "IKE Phase 1 Authenticated With Signatures", describing Main
+ * Mode:
+ *
+ * Initiator Responder
+ * ----------- -----------
+ * HDR, SA -->
+ * <-- HDR, SA
+ * HDR, KE, Ni -->
+ * <-- HDR, KE, Nr
+ * HDR*, IDii, [ CERT, ] SIG_I -->
+ * <-- HDR*, IDir, [ CERT, ] SIG_R
+ *
+ * In 5.4 "Phase 1 Authenticated With a Pre-Shared Key":
+ *
+ * HDR, SA -->
+ * <-- HDR, SA
+ * HDR, KE, Ni -->
+ * <-- HDR, KE, Nr
+ * HDR*, IDii, HASH_I -->
+ * <-- HDR*, IDir, HASH_R
+ *
+ * refine_host_connection could be called in two case:
+ *
+ * - the Responder receives the IDii payload:
+ * + [PSK] after using PSK to decode this message
+ * + before sending its IDir payload
+ * + before using its ID in HASH_R computation
+ * + [DSig] before using its private key to sign SIG_R
+ * + before using the Initiator's ID in HASH_I calculation
+ * + [DSig] before using the Initiator's public key to check SIG_I
+ *
+ * - the Initiator receives the IDir payload:
+ * + [PSK] after using PSK to encode previous message and decode this message
+ * + after sending its IDii payload
+ * + after using its ID in HASH_I computation
+ * + [DSig] after using its private key to sign SIG_I
+ * + before using the Responder's ID to compute HASH_R
+ * + [DSig] before using Responder's public key to check SIG_R
+ *
+ * refine_host_connection can choose a different connection, as long as
+ * nothing already used is changed.
+ *
+ * In the Initiator case, the particular connection might have been
+ * specified by whatever provoked Pluto to initiate. For example:
+ * whack --initiate connection-name
+ * The advantages of switching connections when we're the Initiator seem
+ * less important than the disadvantages, so after FreeS/WAN 1.9, we
+ * don't do this.
+ */
+struct connection *
+refine_host_connection(const struct state *st, const struct id *peer_id
+, chunk_t peer_ca)
+{
+ struct connection *c = st->st_connection;
+ u_int16_t auth = st->st_oakley.auth;
+ struct connection *d;
+ struct connection *best_found = NULL;
+ lset_t auth_policy;
+ const chunk_t *psk = NULL;
+ bool wcpip; /* wildcard Peer IP? */
+
+ int wildcards, our_pathlen, peer_pathlen;
+ int best_wildcards = MAX_WILDCARDS;
+ int best_our_pathlen = MAX_CA_PATH_LEN;
+ int best_peer_pathlen = MAX_CA_PATH_LEN;
+
+ if (same_id(&c->spd.that.id, peer_id)
+ && trusted_ca(peer_ca, c->spd.that.ca, &peer_pathlen)
+ && peer_pathlen == 0
+ && match_requested_ca(c->requested_ca, c->spd.this.ca, &our_pathlen)
+ && our_pathlen == 0)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("current connection is a full match"
+ " -- no need to look further");
+ )
+ return c;
+ }
+
+ switch (auth)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ auth_policy = POLICY_PSK;
+ psk = get_preshared_secret(c);
+ /* It should be virtually impossible to fail to find PSK:
+ * we just used it to decode the current message!
+ */
+ if (psk == NULL)
+ return NULL; /* cannot determine PSK! */
+ break;
+
+ case OAKLEY_RSA_SIG:
+ auth_policy = POLICY_RSASIG;
+ break;
+
+ default:
+ bad_case(auth);
+ }
+
+ /* The current connection won't do: search for one that will.
+ * First search for one with the same pair of hosts.
+ * If that fails, search for a suitable Road Warrior or Opportunistic
+ * connection (i.e. wildcard peer IP).
+ * We need to match:
+ * - peer_id (slightly complicated by instantiation)
+ * - if PSK auth, the key must not change (we used it to decode message)
+ * - policy-as-used must be acceptable to new connection
+ */
+ d = c->host_pair->connections;
+ for (wcpip = FALSE; ; wcpip = TRUE)
+ {
+ for (; d != NULL; d = d->hp_next)
+ {
+ const char *match_name[] = {"no", "ok"};
+
+ bool matching_id = match_id(peer_id
+ , &d->spd.that.id, &wildcards);
+ bool matching_trust = trusted_ca(peer_ca
+ , d->spd.that.ca, &peer_pathlen);
+ bool matching_request = match_requested_ca(c->requested_ca
+ , d->spd.this.ca, &our_pathlen);
+ bool match = matching_id && matching_trust && matching_request;
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("%s: %s match (id: %s, trust: %s, request: %s)"
+ , d->name
+ , match ? "full":" no"
+ , match_name[matching_id]
+ , match_name[matching_trust]
+ , match_name[matching_request])
+ )
+
+ /* do we have a match? */
+ if (!match)
+ continue;
+
+ /* ignore group connections */
+ if (d->policy & POLICY_GROUP)
+ continue;
+
+#ifdef NAT_TRAVERSAL
+ if (c->spd.that.host_port != d->spd.that.host_port
+ && d->kind == CK_INSTANCE)
+ continue;
+#endif
+
+ /* authentication used must fit policy of this connection */
+ if ((d->policy & auth_policy) == LEMPTY)
+ continue; /* our auth isn't OK for this connection */
+
+ switch (auth)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ /* secret must match the one we already used */
+ {
+ const chunk_t *dpsk = get_preshared_secret(d);
+
+ if (dpsk == NULL)
+ continue; /* no secret */
+
+ if (psk != dpsk)
+ if (psk->len != dpsk->len
+ || memcmp(psk->ptr, dpsk->ptr, psk->len) != 0)
+ continue; /* different secret */
+ }
+ break;
+
+ case OAKLEY_RSA_SIG:
+ /*
+ * We must at least be able to find our private key
+ .*/
+ if (d->spd.this.sc == NULL /* no smartcard */
+ && get_RSA_private_key(d) == NULL) /* no private key */
+ continue;
+ break;
+
+ default:
+ bad_case(auth);
+ }
+
+ /* d has passed all the tests.
+ * We'll go with it if the Peer ID was an exact match.
+ */
+ if (match && wildcards == 0 && peer_pathlen == 0 && our_pathlen == 0)
+ return d;
+
+ /* We'll remember it as best_found in case an exact
+ * match doesn't come along.
+ */
+ if (best_found == NULL || wildcards < best_wildcards
+ || ((wildcards == best_wildcards && peer_pathlen < best_peer_pathlen)
+ || (peer_pathlen == best_peer_pathlen && our_pathlen < best_our_pathlen)))
+ {
+ best_found = d;
+ best_wildcards = wildcards;
+ best_peer_pathlen = peer_pathlen;
+ best_our_pathlen = our_pathlen;
+ }
+ }
+ if (wcpip)
+ return best_found; /* been around twice already */
+
+ /* Starting second time around.
+ * We're willing to settle for a connection that needs Peer IP
+ * instantiated: Road Warrior or Opportunistic.
+ * Look on list of connections for host pair with wildcard Peer IP
+ */
+ d = find_host_pair_connections(&c->spd.this.host_addr, c->spd.this.host_port
+ , (ip_address *)NULL, c->spd.that.host_port);
+ }
+}
+
+#ifdef VIRTUAL_IP
+/**
+ * With virtual addressing, we must not allow someone to use an already
+ * used (by another id) addr/net.
+ */
+static bool
+is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id)
+{
+ struct connection *d;
+
+ for (d = connections; d != NULL; d = d->ac_next)
+ {
+ switch (d->kind)
+ {
+ case CK_PERMANENT:
+ case CK_INSTANCE:
+ if ((subnetinsubnet(peer_net,&d->spd.that.client) ||
+ subnetinsubnet(&d->spd.that.client,peer_net))
+ && !same_id(&d->spd.that.id, peer_id))
+ {
+ char buf[BUF_LEN];
+ char client[SUBNETTOT_BUF];
+
+ subnettot(peer_net, 0, client, sizeof(client));
+ idtoa(&d->spd.that.id, buf, sizeof(buf));
+ plog("Virtual IP %s is already used by '%s'", client, buf);
+ idtoa(peer_id, buf, sizeof(buf));
+ plog("Your ID is '%s'", buf);
+ return TRUE; /* already used by another one */
+ }
+ break;
+ case CK_GOING_AWAY:
+ default:
+ break;
+ }
+ }
+ return FALSE; /* you can safely use it */
+}
+#endif
+
+/* find_client_connection: given a connection suitable for ISAKMP
+ * (i.e. the hosts match), find a one suitable for IPSEC
+ * (i.e. with matching clients).
+ *
+ * If we don't find an exact match (not even our current connection),
+ * we try for one that still needs instantiation. Try Road Warrior
+ * abstract connections and the Opportunistic abstract connections.
+ * This requires inverse instantiation: abstraction.
+ *
+ * After failing to find an exact match, we abstract the peer
+ * to be NO_IP (the wildcard value). This enables matches with
+ * Road Warrior and Opportunistic abstract connections.
+ *
+ * After failing that search, we also abstract the Phase 1 peer ID
+ * if possible. If the peer's ID was the peer's IP address, we make
+ * it NO_ID; instantiation will make it the peer's IP address again.
+ *
+ * If searching for a Road Warrior abstract connection fails,
+ * and conditions are suitable, we search for the best Opportunistic
+ * abstract connection.
+ *
+ * Note: in the end, both Phase 1 IDs must be preserved, after any
+ * instantiation. They are the IDs that have been authenticated.
+ */
+
+#define PATH_WEIGHT 1
+#define WILD_WEIGHT (MAX_CA_PATH_LEN+1)
+#define PRIO_WEIGHT (MAX_WILDCARDS+1)*WILD_WEIGHT
+
+/* fc_try: a helper function for find_client_connection */
+static struct connection *
+fc_try(const struct connection *c
+, struct host_pair *hp
+, const struct id *peer_id
+, const ip_subnet *our_net
+, const ip_subnet *peer_net
+, const u_int8_t our_protocol
+, const u_int16_t our_port
+, const u_int8_t peer_protocol
+, const u_int16_t peer_port
+, chunk_t peer_ca
+, const ietfAttrList_t *peer_list)
+{
+ struct connection *d;
+ struct connection *best = NULL;
+ policy_prio_t best_prio = BOTTOM_PRIO;
+ int wildcards, pathlen;
+
+ const bool peer_net_is_host = subnetisaddr(peer_net, &c->spd.that.host_addr);
+
+ for (d = hp->connections; d != NULL; d = d->hp_next)
+ {
+ struct spd_route *sr;
+
+ if (d->policy & POLICY_GROUP)
+ continue;
+
+ if (!(same_id(&c->spd.this.id, &d->spd.this.id)
+ && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
+ && trusted_ca(peer_ca, d->spd.that.ca, &pathlen)
+ && group_membership(peer_list, d->name, d->spd.that.groups)))
+ continue;
+
+ /* compare protocol and ports */
+ if (d->spd.this.protocol != our_protocol
+ || d->spd.this.port != our_port
+ || d->spd.that.protocol != peer_protocol
+ || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard))
+ continue;
+
+ /* non-Opportunistic case:
+ * our_client must match.
+ *
+ * So must peer_client, but the testing is complicated
+ * by the fact that the peer might be a wildcard
+ * and if so, the default value of that.client
+ * won't match the default peer_net. The appropriate test:
+ *
+ * If d has a peer client, it must match peer_net.
+ * If d has no peer client, peer_net must just have peer itself.
+ */
+
+ for (sr = &d->spd; best != d && sr != NULL; sr = sr->next)
+ {
+ policy_prio_t prio;
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
+ char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF];
+
+ subnettot(our_net, 0, s1, sizeof(s1));
+ subnettot(peer_net, 0, d1, sizeof(d1));
+ subnettot(&sr->this.client, 0, s3, sizeof(s3));
+ subnettot(&sr->that.client, 0, d3, sizeof(d3));
+ DBG_log(" fc_try trying "
+ "%s:%s:%d/%d -> %s:%d/%d vs %s:%s:%d/%d -> %s:%d/%d"
+ , c->name, s1, c->spd.this.protocol, c->spd.this.port
+ , d1, c->spd.that.protocol, c->spd.that.port
+ , d->name, s3, sr->this.protocol, sr->this.port
+ , d3, sr->that.protocol, sr->that.port);
+ }
+#endif /* DEBUG */
+
+ if (!samesubnet(&sr->this.client, our_net))
+ continue;
+
+ if (sr->that.has_client)
+ {
+ if (sr->that.has_client_wildcard)
+ {
+ if (!subnetinsubnet(peer_net, &sr->that.client))
+ continue;
+ }
+ else
+ {
+#ifdef VIRTUAL_IP
+ if ((!samesubnet(&sr->that.client, peer_net)) && (!is_virtual_connection(d)))
+#else
+ if (!samesubnet(&sr->that.client, peer_net))
+#endif
+ continue;
+#ifdef VIRTUAL_IP
+ if (is_virtual_connection(d)
+ && ( (!is_virtual_net_allowed(d, peer_net, &c->spd.that.host_addr))
+ || is_virtual_net_used(peer_net, peer_id?peer_id:&c->spd.that.id)))
+ continue;
+#endif
+ }
+ }
+ else
+ {
+ if (!peer_net_is_host)
+ continue;
+ }
+
+ /* We've run the gauntlet -- success:
+ * We've got an exact match of subnets.
+ * The connection is feasible, but we continue looking for the best.
+ * The highest priority wins, implementing eroute-like rule.
+ * - a routed connection is preferrred
+ * - given that, the smallest number of ID wildcards are preferred
+ * - given that, the shortest CA pathlength is preferred
+ */
+ prio = PRIO_WEIGHT * routed(sr->routing)
+ + WILD_WEIGHT * (MAX_WILDCARDS - wildcards)
+ + PATH_WEIGHT * (MAX_CA_PATH_LEN - pathlen)
+ + 1;
+ if (prio > best_prio)
+ {
+ best = d;
+ best_prio = prio;
+ }
+ }
+ }
+
+ if (best != NULL && NEVER_NEGOTIATE(best->policy))
+ best = NULL;
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" fc_try concluding with %s [%ld]"
+ , (best ? best->name : "none"), best_prio)
+ )
+ return best;
+}
+
+static struct connection *
+fc_try_oppo(const struct connection *c
+, struct host_pair *hp
+, const ip_subnet *our_net
+, const ip_subnet *peer_net
+, const u_int8_t our_protocol
+, const u_int16_t our_port
+, const u_int8_t peer_protocol
+, const u_int16_t peer_port
+, chunk_t peer_ca
+, const ietfAttrList_t *peer_list)
+{
+ struct connection *d;
+ struct connection *best = NULL;
+ policy_prio_t best_prio = BOTTOM_PRIO;
+ int wildcards, pathlen;
+
+ for (d = hp->connections; d != NULL; d = d->hp_next)
+ {
+ struct spd_route *sr;
+ policy_prio_t prio;
+
+ if (d->policy & POLICY_GROUP)
+ continue;
+
+ if (!(same_id(&c->spd.this.id, &d->spd.this.id)
+ && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
+ && trusted_ca(peer_ca, d->spd.that.ca, &pathlen)
+ && group_membership(peer_list, d->name, d->spd.that.groups)))
+ continue;
+
+ /* compare protocol and ports */
+ if (d->spd.this.protocol != our_protocol
+ || d->spd.this.port != our_port
+ || d->spd.that.protocol != peer_protocol
+ || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard))
+ continue;
+
+ /* Opportunistic case:
+ * our_net must be inside d->spd.this.client
+ * and peer_net must be inside d->spd.that.client
+ * Note: this host_pair chain also has shunt
+ * eroute conns (clear, drop), but they won't
+ * be marked as opportunistic.
+ */
+ for (sr = &d->spd; sr != NULL; sr = sr->next)
+ {
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
+ char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF];
+
+ subnettot(our_net, 0, s1, sizeof(s1));
+ subnettot(peer_net, 0, d1, sizeof(d1));
+ subnettot(&sr->this.client, 0, s3, sizeof(s3));
+ subnettot(&sr->that.client, 0, d3, sizeof(d3));
+ DBG_log(" fc_try_oppo trying %s:%s -> %s vs %s:%s -> %s"
+ , c->name, s1, d1, d->name, s3, d3);
+ }
+#endif /* DEBUG */
+
+ if (!subnetinsubnet(our_net, &sr->this.client)
+ || !subnetinsubnet(peer_net, &sr->that.client))
+ continue;
+
+ /* The connection is feasible, but we continue looking for the best.
+ * The highest priority wins, implementing eroute-like rule.
+ * - our smallest client subnet is preferred (longest mask)
+ * - given that, his smallest client subnet is preferred
+ * - given that, a routed connection is preferrred
+ * - given that, the smallest number of ID wildcards are preferred
+ * - given that, the shortest CA pathlength is preferred
+ */
+ prio = PRIO_WEIGHT * (d->prio + routed(sr->routing))
+ + WILD_WEIGHT * (MAX_WILDCARDS - wildcards)
+ + PATH_WEIGHT * (MAX_CA_PATH_LEN - pathlen);
+ if (prio > best_prio)
+ {
+ best = d;
+ best_prio = prio;
+ }
+ }
+ }
+
+ /* if the best wasn't opportunistic, we fail: it must be a shunt */
+ if (best != NULL
+ && (NEVER_NEGOTIATE(best->policy)
+ || (best->policy & POLICY_OPPO) == LEMPTY))
+ {
+ best = NULL;
+ }
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" fc_try_oppo concluding with %s [%ld]"
+ , (best ? best->name : "none"), best_prio)
+ )
+ return best;
+
+}
+
+/*
+ * get the peer's CA and group attributes
+ */
+chunk_t
+get_peer_ca_and_groups(struct connection *c, const ietfAttrList_t **peer_list)
+{
+ struct state *p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES);
+
+ *peer_list = NULL;
+
+ if (p1st != NULL
+ && p1st->st_peer_pubkey != NULL
+ && p1st->st_peer_pubkey->issuer.ptr != NULL)
+ {
+ x509acert_t *ac = get_x509acert(p1st->st_peer_pubkey->issuer
+ , p1st->st_peer_pubkey->serial);;
+
+ if (ac != NULL && verify_x509acert(ac, strict_crl_policy))
+ *peer_list = ac->groups;
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("no valid attribute cert found")
+ )
+ }
+ return p1st->st_peer_pubkey->issuer;
+ }
+ return empty_chunk;
+}
+
+struct connection *
+find_client_connection(struct connection *c
+, const ip_subnet *our_net, const ip_subnet *peer_net
+, const u_int8_t our_protocol, const u_int16_t our_port
+, const u_int8_t peer_protocol, const u_int16_t peer_port)
+{
+ struct connection *d;
+ struct spd_route *sr;
+
+ const ietfAttrList_t *peer_list = NULL;
+ chunk_t peer_ca = get_peer_ca_and_groups(c, &peer_list);
+
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF];
+
+ subnettot(our_net, 0, s1, sizeof(s1));
+ subnettot(peer_net, 0, d1, sizeof(d1));
+
+ DBG_log("find_client_connection starting with %s"
+ , (c ? c->name : "(none)"));
+ DBG_log(" looking for %s:%d/%d -> %s:%d/%d"
+ , s1, our_protocol, our_port
+ , d1, peer_protocol, peer_port);
+ }
+#endif /* DEBUG */
+
+ /* give priority to current connection
+ * but even greater priority to a routed concrete connection
+ */
+ {
+ struct connection *unrouted = NULL;
+ int srnum = -1;
+
+ for (sr = &c->spd; unrouted == NULL && sr != NULL; sr = sr->next)
+ {
+ srnum++;
+
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
+
+ subnettot(&sr->this.client, 0, s2, sizeof(s2));
+ subnettot(&sr->that.client, 0, d2, sizeof(d2));
+ DBG_log(" concrete checking against sr#%d %s -> %s"
+ , srnum, s2, d2);
+ }
+#endif /* DEBUG */
+
+ if (samesubnet(&sr->this.client, our_net)
+ && samesubnet(&sr->that.client, peer_net)
+ && sr->this.protocol == our_protocol
+ && sr->this.port == our_port
+ && sr->that.protocol == peer_protocol
+ && sr->that.port == peer_port
+ && group_membership(peer_list, c->name, sr->that.groups))
+ {
+ passert(oriented(*c));
+ if (routed(sr->routing))
+ return c;
+
+ unrouted = c;
+ }
+ }
+
+ /* exact match? */
+ d = fc_try(c, c->host_pair, NULL, our_net, peer_net
+ , our_protocol, our_port, peer_protocol, peer_port
+ , peer_ca, peer_list);
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" fc_try %s gives %s"
+ , c->name
+ , (d ? d->name : "none"))
+ )
+
+ if (d == NULL)
+ d = unrouted;
+ }
+
+ if (d == NULL)
+ {
+ /* look for an abstract connection to match */
+ struct spd_route *sr;
+ struct host_pair *hp = NULL;
+
+ for (sr = &c->spd; hp==NULL && sr != NULL; sr = sr->next)
+ {
+ hp = find_host_pair(&sr->this.host_addr
+ , sr->this.host_port
+ , NULL
+ , sr->that.host_port);
+#ifdef DEBUG
+ if (DBGP(DBG_CONTROLMORE))
+ {
+ char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
+
+ subnettot(&sr->this.client, 0, s2, sizeof(s2));
+ subnettot(&sr->that.client, 0, d2, sizeof(d2));
+
+ DBG_log(" checking hostpair %s -> %s is %s"
+ , s2, d2
+ , (hp ? "found" : "not found"));
+ }
+#endif /* DEBUG */
+ }
+
+ if (hp != NULL)
+ {
+ /* RW match with actual peer_id or abstract peer_id? */
+ d = fc_try(c, hp, NULL, our_net, peer_net
+ , our_protocol, our_port, peer_protocol, peer_port
+ , peer_ca, peer_list);
+
+ if (d == NULL
+ && subnetishost(our_net)
+ && subnetishost(peer_net))
+ {
+ /* Opportunistic match?
+ * Always use abstract peer_id.
+ * Note that later instantiation will result in the same peer_id.
+ */
+ d = fc_try_oppo(c, hp, our_net, peer_net
+ , our_protocol, our_port, peer_protocol, peer_port
+ , peer_ca, peer_list);
+ }
+ }
+ }
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" concluding with d = %s"
+ , (d ? d->name : "none"))
+ )
+ return d;
+}
+
+int
+connection_compare(const struct connection *ca
+, const struct connection *cb)
+{
+ int ret;
+
+ /* DBG_log("comparing %s to %s", ca->name, cb->name); */
+
+ ret = strcasecmp(ca->name, cb->name);
+ if (ret != 0)
+ return ret;
+
+ ret = ca->kind - cb->kind; /* note: enum connection_kind behaves like int */
+ if (ret != 0)
+ return ret;
+
+ /* same name, and same type */
+ switch (ca->kind)
+ {
+ case CK_INSTANCE:
+ return ca->instance_serial < cb->instance_serial ? -1
+ : ca->instance_serial > cb->instance_serial ? 1
+ : 0;
+
+ default:
+ return ca->prio < cb->prio ? -1
+ : ca->prio > cb->prio ? 1
+ : 0;
+ }
+}
+
+static int
+connection_compare_qsort(const void *a, const void *b)
+{
+ return connection_compare(*(const struct connection *const *)a
+ , *(const struct connection *const *)b);
+}
+
+void
+show_connections_status(bool all, const char *name)
+{
+ struct connection *c;
+ int count, i;
+ struct connection **array;
+
+ /* make an array of connections, and sort it */
+ count = 0;
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ if (name == NULL || streq(c->name, name))
+ count++;
+ }
+ array = alloc_bytes(sizeof(struct connection *)*count, "connection array");
+
+ count=0;
+ for (c = connections; c != NULL; c = c->ac_next)
+ {
+ if (name == NULL || streq(c->name, name))
+ array[count++]=c;
+ }
+
+ /* sort it! */
+ qsort(array, count, sizeof(struct connection *), connection_compare_qsort);
+
+ for (i=0; i<count; i++)
+ {
+ const char *ifn;
+ char instance[1 + 10 + 1];
+ char prio[POLICY_PRIO_BUF];
+
+ c = array[i];
+
+ ifn = oriented(*c)? c->interface->rname : "";
+
+ instance[0] = '\0';
+ if (c->kind == CK_INSTANCE && c->instance_serial != 0)
+ snprintf(instance, sizeof(instance), "[%lu]", c->instance_serial);
+
+ /* show topology */
+ {
+ char topo[CONNECTION_BUF];
+ struct spd_route *sr = &c->spd;
+ int num=0;
+
+ while (sr != NULL)
+ {
+ (void) format_connection(topo, sizeof(topo), c, sr);
+ whack_log(RC_COMMENT, "\"%s\"%s: %s; %s; eroute owner: #%lu"
+ , c->name, instance, topo
+ , enum_name(&routing_story, sr->routing)
+ , sr->eroute_owner);
+ sr = sr->next;
+ num++;
+ }
+ }
+
+ if (all)
+ {
+ /* show CAs if defined */
+ if (c->spd.this.ca.ptr != NULL || c->spd.that.ca.ptr != NULL)
+ {
+ char this_ca[BUF_LEN], that_ca[BUF_LEN];
+
+ dntoa_or_null(this_ca, BUF_LEN, c->spd.this.ca, "%any");
+ dntoa_or_null(that_ca, BUF_LEN, c->spd.that.ca, "%any");
+
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: CAs: '%s'...'%s'"
+ , c->name
+ , instance
+ , this_ca
+ , that_ca);
+ }
+
+ /* show group attributes if defined */
+ if (c->spd.that.groups != NULL)
+ {
+ char buf[BUF_LEN];
+
+ format_groups(c->spd.that.groups, buf, BUF_LEN);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: groups: %s"
+ , c->name
+ , instance
+ , buf);
+ }
+
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: ike_life: %lus; ipsec_life: %lus;"
+ " rekey_margin: %lus; rekey_fuzz: %lu%%; keyingtries: %lu"
+ , c->name
+ , instance
+ , (unsigned long) c->sa_ike_life_seconds
+ , (unsigned long) c->sa_ipsec_life_seconds
+ , (unsigned long) c->sa_rekey_margin
+ , (unsigned long) c->sa_rekey_fuzz
+ , (unsigned long) c->sa_keying_tries);
+
+ /* show DPD parameters if defined */
+
+ if (c->dpd_action != DPD_ACTION_NONE)
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: dpd_action: %s;"
+ " dpd_delay: %lus; dpd_timeout: %lus;"
+ , c->name
+ , instance
+ , enum_show(&dpd_action_names, c->dpd_action)
+ , (unsigned long) c->dpd_delay
+ , (unsigned long) c->dpd_timeout);
+
+ if (c->policy_next)
+ {
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: policy_next: %s"
+ , c->name, instance, c->policy_next->name);
+ }
+
+ /* Note: we display key_from_DNS_on_demand as if policy [lr]KOD */
+ fmt_policy_prio(c->prio, prio);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: policy: %s%s%s; prio: %s; interface: %s; "
+ , c->name
+ , instance
+ , prettypolicy(c->policy)
+ , c->spd.this.key_from_DNS_on_demand? "+lKOD" : ""
+ , c->spd.that.key_from_DNS_on_demand? "+rKOD" : ""
+ , prio
+ , ifn);
+ }
+
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: newest ISAKMP SA: #%ld; newest IPsec SA: #%ld; "
+ , c->name
+ , instance
+ , c->newest_isakmp_sa
+ , c->newest_ipsec_sa);
+
+ if (all)
+ {
+ ike_alg_show_connection(c, instance);
+ kernel_alg_show_connection(c, instance);
+ }
+ }
+ pfree(array);
+}
+
+/* struct pending, the structure representing Quick Mode
+ * negotiations delayed until a Keying Channel has been negotiated.
+ * Essentially, a pending call to quick_outI1.
+ */
+
+struct pending {
+ int whack_sock;
+ struct state *isakmp_sa;
+ struct connection *connection;
+ lset_t policy;
+ unsigned long try;
+ so_serial_t replacing;
+
+ struct pending *next;
+};
+
+/* queue a Quick Mode negotiation pending completion of a suitable Main Mode */
+void
+add_pending(int whack_sock
+, struct state *isakmp_sa
+, struct connection *c
+, lset_t policy
+, unsigned long try
+, so_serial_t replacing)
+{
+ bool already_queued = FALSE;
+ struct pending *p = c->host_pair->pending;
+
+ while (p != NULL)
+ {
+ if (streq(c->name, p->connection->name))
+ {
+ already_queued = TRUE;
+ break;
+ }
+ p = p->next;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("Queuing pending Quick Mode with %s \"%s\"%s"
+ , ip_str(&c->spd.that.host_addr)
+ , c->name
+ , already_queued? " already done" : "")
+ )
+ if (already_queued)
+ return;
+
+ p = alloc_thing(struct pending, "struct pending");
+ p->whack_sock = whack_sock;
+ p->isakmp_sa = isakmp_sa;
+ p->connection = c;
+ p->policy = policy;
+ p->try = try;
+ p->replacing = replacing;
+ p->next = c->host_pair->pending;
+ c->host_pair->pending = p;
+}
+
+/* Release all the whacks awaiting the completion of this state.
+ * This is accomplished by closing all the whack socket file descriptors.
+ * We go to a lot of trouble to tell each whack, but to not tell it twice.
+ */
+void
+release_pending_whacks(struct state *st, err_t story)
+{
+ struct pending *p;
+ struct stat stst;
+
+ if (st->st_whack_sock == NULL_FD || fstat(st->st_whack_sock, &stst) != 0)
+ zero(&stst); /* resulting st_dev/st_ino ought to be distinct */
+
+ release_whack(st);
+
+ for (p = st->st_connection->host_pair->pending; p != NULL; p = p->next)
+ {
+ if (p->isakmp_sa == st && p->whack_sock != NULL_FD)
+ {
+ struct stat pst;
+
+ if (fstat(p->whack_sock, &pst) == 0
+ && (stst.st_dev != pst.st_dev || stst.st_ino != pst.st_ino))
+ {
+ passert(whack_log_fd == NULL_FD);
+ whack_log_fd = p->whack_sock;
+ whack_log(RC_COMMENT
+ , "%s for ISAKMP SA, but releasing whack for pending IPSEC SA"
+ , story);
+ whack_log_fd = NULL_FD;
+ }
+ close(p->whack_sock);
+ p->whack_sock = NULL_FD;
+ }
+ }
+}
+
+static void
+delete_pending(struct pending **pp)
+{
+ struct pending *p = *pp;
+
+ *pp = p->next;
+ if (p->connection != NULL)
+ connection_discard(p->connection);
+ close_any(p->whack_sock);
+ pfree(p);
+}
+
+void
+unpend(struct state *st)
+{
+ struct pending **pp
+ , *p;
+
+ for (pp = &st->st_connection->host_pair->pending; (p = *pp) != NULL; )
+ {
+ if (p->isakmp_sa == st)
+ {
+ DBG(DBG_CONTROL, DBG_log("unqueuing pending Quick Mode with %s \"%s\""
+ , ip_str(&p->connection->spd.that.host_addr)
+ , p->connection->name));
+ (void) quick_outI1(p->whack_sock, st, p->connection, p->policy
+ , p->try, p->replacing);
+ p->whack_sock = NULL_FD; /* ownership transferred */
+ p->connection = NULL; /* ownership transferred */
+ delete_pending(pp);
+ }
+ else
+ {
+ pp = &p->next;
+ }
+ }
+}
+
+/* a Main Mode negotiation has been replaced; update any pending */
+void
+update_pending(struct state *os, struct state *ns)
+{
+ struct pending *p;
+
+ for (p = os->st_connection->host_pair->pending; p != NULL; p = p->next)
+ {
+ if (p->isakmp_sa == os)
+ p->isakmp_sa = ns;
+#ifdef NAT_TRAVERSAL
+ if (p->connection->spd.this.host_port != ns->st_connection->spd.this.host_port)
+ {
+ p->connection->spd.this.host_port = ns->st_connection->spd.this.host_port;
+ p->connection->spd.that.host_port = ns->st_connection->spd.that.host_port;
+ }
+#endif
+ }
+}
+
+/* a Main Mode negotiation has failed; discard any pending */
+void
+flush_pending_by_state(struct state *st)
+{
+ struct host_pair *hp = st->st_connection->host_pair;
+
+ if (hp != NULL)
+ {
+ struct pending **pp
+ , *p;
+
+ for (pp = &hp->pending; (p = *pp) != NULL; )
+ {
+ if (p->isakmp_sa == st)
+ delete_pending(pp);
+ else
+ pp = &p->next;
+ }
+ }
+}
+
+/* a connection has been deleted; discard any related pending */
+static void
+flush_pending_by_connection(struct connection *c)
+{
+ if (c->host_pair != NULL)
+ {
+ struct pending **pp
+ , *p;
+
+ for (pp = &c->host_pair->pending; (p = *pp) != NULL; )
+ {
+ if (p->connection == c)
+ {
+ p->connection = NULL; /* prevent delete_pending from releasing */
+ delete_pending(pp);
+ }
+ else
+ {
+ pp = &p->next;
+ }
+ }
+ }
+}
+
+void
+show_pending_phase2(const struct host_pair *hp, const struct state *st)
+{
+ const struct pending *p;
+
+ for (p = hp->pending; p != NULL; p = p->next)
+ {
+ if (p->isakmp_sa == st)
+ {
+ /* connection-name state-number [replacing state-number] */
+ char cip[CONN_INST_BUF];
+
+ fmt_conn_instance(p->connection, cip);
+ whack_log(RC_COMMENT, "#%lu: pending Phase 2 for \"%s\"%s replacing #%lu"
+ , p->isakmp_sa->st_serialno
+ , p->connection->name
+ , cip
+ , p->replacing);
+ }
+ }
+}
+
+/* Delete a connection if it is an instance and it is no longer in use.
+ * We must be careful to avoid circularity:
+ * we don't touch it if it is CK_GOING_AWAY.
+ */
+void
+connection_discard(struct connection *c)
+{
+ if (c->kind == CK_INSTANCE)
+ {
+ /* see if it is being used by a pending */
+ struct pending *p;
+
+ for (p = c->host_pair->pending; p != NULL; p = p->next)
+ if (p->connection == c)
+ return; /* in use, so we're done */
+
+ if (!states_use_connection(c))
+ delete_connection(c, FALSE);
+ }
+}
+
+
+/* A template connection's eroute can be eclipsed by
+ * either a %hold or an eroute for an instance iff
+ * the template is a /32 -> /32. This requires some special casing.
+ */
+
+long eclipse_count = 0;
+
+struct connection *
+eclipsed(struct connection *c, struct spd_route **esrp)
+{
+ struct connection *ue;
+ struct spd_route *sr1 = &c->spd;
+
+ ue = NULL;
+
+ while (sr1 != NULL && ue != NULL)
+ {
+ for (ue = connections; ue != NULL; ue = ue->ac_next)
+ {
+ struct spd_route *srue = &ue->spd;
+
+ while (srue != NULL
+ && srue->routing == RT_ROUTED_ECLIPSED
+ && !(samesubnet(&sr1->this.client, &srue->this.client)
+ && samesubnet(&sr1->that.client, &srue->that.client)))
+ {
+ srue = srue->next;
+ }
+ if (srue != NULL && srue->routing==RT_ROUTED_ECLIPSED)
+ {
+ *esrp = srue;
+ break;
+ }
+ }
+ }
+ return ue;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/programs/pluto/connections.h b/programs/pluto/connections.h
new file mode 100644
index 000000000..6dfddbe22
--- /dev/null
+++ b/programs/pluto/connections.h
@@ -0,0 +1,375 @@
+/* information about connections between hosts and clients
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: connections.h,v 1.18 2006/04/22 21:59:20 as Exp $
+ */
+
+#ifndef _CONNECTIONS_H
+#define _CONNECTIONS_H
+
+#include <sys/queue.h>
+
+#include "id.h"
+#include "certs.h"
+#include "ac.h"
+#include "smartcard.h"
+#include "whack.h"
+
+/* There are two kinds of connections:
+ * - ISAKMP connections, between hosts (for IKE communication)
+ * - IPsec connections, between clients (for secure IP communication)
+ *
+ * An ISAKMP connection looks like:
+ * host<--->host
+ *
+ * An IPsec connection looks like:
+ * client-subnet<-->host<->nexthop<--->nexthop<->host<-->client-subnet
+ *
+ * For the connection to be relevant to this instance of Pluto,
+ * exactly one of the hosts must be a public interface of our machine
+ * known to this instance.
+ *
+ * The client subnet might simply be the host -- this is a
+ * representation of "host mode".
+ *
+ * Each nexthop defaults to the neighbouring host's IP address.
+ * The nexthop is a property of the pair of hosts, not each
+ * individually. It is only needed for IPsec because of the
+ * way IPsec is mixed into the kernel routing logic. Furthermore,
+ * only this end's nexthop is actually used. Eventually, nexthop
+ * will be unnecessary.
+ *
+ * Other information represented:
+ * - each connection has a name: a chunk of uninterpreted text
+ * that is unique for each connection.
+ * - security requirements (currently just the "policy" flags from
+ * the whack command to initiate the connection, but eventually
+ * much more. Different for ISAKMP and IPsec connections.
+ * - rekeying parameters:
+ * + time an SA may live
+ * + time before SA death that a rekeying should be attempted
+ * (only by the initiator)
+ * + number of times to attempt rekeying
+ * - With the current KLIPS, we must route packets for a client
+ * subnet through the ipsec interface (ipsec0). Only one
+ * gateway can get traffic for a specific (client) subnet.
+ * Furthermore, if the routing isn't in place, packets will
+ * be sent in the clear.
+ * "routing" indicates whether the routing has been done for
+ * this connection. Note that several connections may claim
+ * the same routing, as long as they agree about where the
+ * packets are to be sent.
+ * - With the current KLIPS, only one outbound IPsec SA bundle can be
+ * used for a particular client. This is due to a limitation
+ * of using only routing for selection. So only one IPsec state (SA)
+ * may "own" the eroute. "eroute_owner" is the serial number of
+ * this state, SOS_NOBODY if there is none. "routing" indicates
+ * what kind of erouting has been done for this connection, if any.
+ *
+ * Details on routing is in constants.h
+ *
+ * Operations on Connections:
+ *
+ * - add a new connection (with all details) [whack command]
+ * - delete a connection (by name) [whack command]
+ * - initiate a connection (by name) [whack command]
+ * - find a connection (by IP addresses of hosts)
+ * [response to peer request; finding ISAKMP connection for IPsec connection]
+ *
+ * Some connections are templates, missing the address of the peer
+ * (represented by INADDR_ANY). These are always arranged so that the
+ * missing end is "that" (there can only be one missing end). These can
+ * be instantiated (turned into real connections) by Pluto in one of two
+ * different ways: Road Warrior Instantiation or Opportunistic
+ * Instantiation. A template connection is marked for Opportunistic
+ * Instantiation by specifying the peer client as 0.0.0.0/32 (or the IPV6
+ * equivalent). Otherwise, it is suitable for Road Warrior Instantiation.
+ *
+ * Instantiation creates a new temporary connection, with the missing
+ * details filled in. The resulting template lasts only as long as there
+ * is a state that uses it.
+ */
+
+/* connection policy priority: how important this policy is
+ * - used to implement eroute-like precedence (augmented by a small
+ * bonus for a routed connection).
+ * - a whole number
+ * - larger is more important
+ * - three subcomponents. In order of decreasing significance:
+ * + length of source subnet mask (8 bits)
+ * + length of destination subnet mask (8 bits)
+ * + bias (8 bit)
+ * - a bias of 1 is added to allow prio BOTTOM_PRIO to be less than all
+ * normal priorities
+ * - other bias values are created on the fly to give mild preference
+ * to certaion conditions (eg. routedness)
+ * - priority is inherited -- an instance of a policy has the same priority
+ * as the original policy, even though its subnets might be smaller.
+ * - display format: n,m
+ */
+typedef unsigned long policy_prio_t;
+#define BOTTOM_PRIO ((policy_prio_t)0) /* smaller than any real prio */
+#define set_policy_prio(c) { (c)->prio = \
+ ((policy_prio_t)(c)->spd.this.client.maskbits << 16) \
+ | ((policy_prio_t)(c)->spd.that.client.maskbits << 8) \
+ | (policy_prio_t)1; }
+#define POLICY_PRIO_BUF (3+1+3+1)
+extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]);
+
+#ifdef VIRTUAL_IP
+struct virtual_t;
+#endif
+
+struct end {
+ struct id id;
+ ip_address
+ host_addr,
+ host_nexthop,
+ host_srcip;
+ ip_subnet client;
+
+ bool key_from_DNS_on_demand;
+ bool has_client;
+ bool has_client_wildcard;
+ bool has_port_wildcard;
+ bool has_id_wildcards;
+ char *updown;
+ u_int16_t host_port; /* host order */
+ u_int16_t port; /* host order */
+ u_int8_t protocol;
+ cert_t cert; /* end certificate */
+ chunk_t ca; /* CA distinguished name */
+ struct ietfAttrList *groups;/* access control groups */
+ smartcard_t *sc; /* smartcard reader and key info */
+#ifdef VIRTUAL_IP
+ struct virtual_t *virt;
+#endif
+ bool modecfg; /* this end: request local address from server */
+ /* that end: give local addresses to clients */
+ bool hostaccess; /* allow access to host via iptables INPUT/OUTPUT */
+ /* rules if client behind host is a subnet */
+ certpolicy_t sendcert; /* whether or not to send the certificate */
+};
+
+struct spd_route {
+ struct spd_route *next;
+ struct end this;
+ struct end that;
+ so_serial_t eroute_owner;
+ enum routing_t routing; /* level of routing in place */
+ uint32_t reqid;
+};
+
+struct connection {
+ char *name;
+ lset_t policy;
+ time_t sa_ike_life_seconds;
+ time_t sa_ipsec_life_seconds;
+ time_t sa_rekey_margin;
+ unsigned long sa_rekey_fuzz;
+ unsigned long sa_keying_tries;
+
+ /* RFC 3706 DPD */
+ time_t dpd_delay;
+ time_t dpd_timeout;
+ dpd_action_t dpd_action;
+
+ char *log_file_name; /* name of log file */
+ FILE *log_file; /* possibly open FILE */
+ CIRCLEQ_ENTRY(connection) log_link; /* linked list of open conns */
+ bool log_file_err; /* only bitch once */
+
+ struct spd_route spd;
+
+ /* internal fields: */
+
+ unsigned long instance_serial;
+ policy_prio_t prio;
+ bool instance_initiation_ok; /* this is an instance of a policy that mandates initiate */
+ enum connection_kind kind;
+ const struct iface *interface; /* filled in iff oriented */
+
+ so_serial_t /* state object serial number */
+ newest_isakmp_sa,
+ newest_ipsec_sa;
+
+
+#ifdef DEBUG
+ lset_t extra_debugging;
+#endif
+
+ /* note: if the client is the gateway, the following must be equal */
+ sa_family_t addr_family; /* between gateways */
+ sa_family_t tunnel_addr_family; /* between clients */
+
+ struct connection *policy_next; /* if multiple policies,
+ next one to apply */
+
+ struct gw_info *gw_info;
+ struct alg_info_esp *alg_info_esp;
+ struct alg_info_ike *alg_info_ike;
+
+ struct host_pair *host_pair;
+ struct connection *hp_next; /* host pair list link */
+
+ struct connection *ac_next; /* all connections list link */
+
+ generalName_t *requested_ca; /* collected certificate requests */
+ bool got_certrequest;
+};
+
+#define oriented(c) ((c).interface != NULL)
+extern bool orient(struct connection *c);
+
+extern bool same_peer_ids(const struct connection *c
+ , const struct connection *d, const struct id *his_id);
+
+/* Format the topology of a connection end, leaving out defaults.
+ * Largest left end looks like: client === host : port [ host_id ] --- hop
+ * Note: if that==NULL, skip nexthop
+ */
+#define END_BUF (SUBNETTOT_BUF + ADDRTOT_BUF + IDTOA_BUF + ADDRTOT_BUF + 10)
+extern size_t format_end(char *buf, size_t buf_len
+ , const struct end *this, const struct end *that
+ , bool is_left, lset_t policy);
+
+extern void add_connection(const whack_message_t *wm);
+extern void initiate_connection(const char *name, int whackfd);
+extern void initiate_opportunistic(const ip_address *our_client
+ , const ip_address *peer_client, int transport_proto, bool held, int whackfd);
+extern void terminate_connection(const char *nm);
+extern void release_connection(struct connection *c, bool relations);
+extern void delete_connection(struct connection *c, bool relations);
+extern void delete_connections_by_name(const char *name, bool strict);
+extern void delete_every_connection(void);
+extern char *add_group_instance(struct connection *group, const ip_subnet *target);
+extern void remove_group_instance(const struct connection *group, const char *name);
+extern void release_dead_interfaces(void);
+extern void check_orientations(void);
+extern struct connection *route_owner(struct connection *c
+ , struct spd_route **srp
+ , struct connection **erop
+ , struct spd_route **esrp);
+extern struct connection *shunt_owner(const ip_subnet *ours
+ , const ip_subnet *his);
+
+extern bool uniqueIDs; /* --uniqueids? */
+extern void ISAKMP_SA_established(struct connection *c, so_serial_t serial);
+
+#define his_id_was_instantiated(c) ((c)->kind == CK_INSTANCE \
+ && (id_is_ipaddr(&(c)->spd.that.id)? \
+ sameaddr(&(c)->spd.that.id.ip_addr, &(c)->spd.that.host_addr) : TRUE))
+
+struct state; /* forward declaration of tag (defined in state.h) */
+extern struct connection
+ *con_by_name(const char *nm, bool strict),
+ *find_host_connection(const ip_address *me, u_int16_t my_port
+ , const ip_address *him, u_int16_t his_port, lset_t policy),
+ *refine_host_connection(const struct state *st, const struct id *id
+ , chunk_t peer_ca),
+ *find_client_connection(struct connection *c
+ , const ip_subnet *our_net
+ , const ip_subnet *peer_net
+ , const u_int8_t our_protocol
+ , const u_int16_t out_port
+ , const u_int8_t peer_protocol
+ , const u_int16_t peer_port),
+ *find_connection_by_reqid(uint32_t reqid);
+
+extern struct connection *
+find_connection_for_clients(struct spd_route **srp
+ , const ip_address *our_client
+ , const ip_address *peer_client
+ , int transport_proto);
+
+extern chunk_t get_peer_ca_and_groups(struct connection *c
+ , const ietfAttrList_t **peer_list);
+
+/* instantiating routines
+ * Note: connection_discard() is in state.h because all its work
+ * is looking through state objects.
+ */
+struct gw_info; /* forward declaration of tag (defined in dnskey.h) */
+struct alg_info; /* forward declaration of tag (defined in alg_info.h) */
+extern struct connection *rw_instantiate(struct connection *c
+ , const ip_address *him
+#ifdef NAT_TRAVERSAL
+ , u_int16_t his_port
+#endif
+#ifdef VIRTUAL_IP
+ , const ip_subnet *his_net
+#endif
+ , const struct id *his_id);
+
+extern struct connection *oppo_instantiate(struct connection *c
+ , const ip_address *him
+ , const struct id *his_id
+ , struct gw_info *gw
+ , const ip_address *our_client
+ , const ip_address *peer_client);
+
+extern struct connection
+ *build_outgoing_opportunistic_connection(struct gw_info *gw
+ , const ip_address *our_client
+ , const ip_address *peer_client);
+
+/* worst case: "[" serial "] " myclient "=== ..." peer "===" hisclient '\0' */
+#define CONN_INST_BUF \
+ (2 + 10 + 1 + SUBNETTOT_BUF + 7 + ADDRTOT_BUF + 3 + SUBNETTOT_BUF + 1)
+
+extern void fmt_conn_instance(const struct connection *c
+ , char buf[CONN_INST_BUF]);
+
+/* operations on "pending", the structure representing Quick Mode
+ * negotiations delayed until a Keying Channel has been negotiated.
+ */
+
+struct pending; /* forward declaration (opaque outside connections.c) */
+
+extern void add_pending(int whack_sock
+ , struct state *isakmp_sa
+ , struct connection *c
+ , lset_t policy
+ , unsigned long try
+ , so_serial_t replacing);
+
+extern void release_pending_whacks(struct state *st, err_t story);
+extern void unpend(struct state *st);
+extern void update_pending(struct state *os, struct state *ns);
+extern void flush_pending_by_state(struct state *st);
+extern void show_pending_phase2(const struct host_pair *hp, const struct state *st);
+
+extern void connection_discard(struct connection *c);
+
+/* A template connection's eroute can be eclipsed by
+ * either a %hold or an eroute for an instance iff
+ * the template is a /32 -> /32. This requires some special casing.
+ */
+#define eclipsable(sr) (subnetishost(&(sr)->this.client) && subnetishost(&(sr)->that.client))
+extern long eclipse_count;
+extern struct connection *eclipsed(struct connection *c, struct spd_route **);
+
+
+/* print connection status */
+
+extern void show_connections_status(bool all, const char *name);
+extern int connection_compare(const struct connection *ca
+ , const struct connection *cb);
+#ifdef NAT_TRAVERSAL
+void
+update_host_pair(const char *why, struct connection *c,
+ const ip_address *myaddr, u_int16_t myport ,
+ const ip_address *hisaddr, u_int16_t hisport);
+#endif /* NAT_TRAVERSAL */
+
+#endif /* _CONNECTIONS_H */
diff --git a/programs/pluto/constants.c b/programs/pluto/constants.c
new file mode 100644
index 000000000..27e4db1e0
--- /dev/null
+++ b/programs/pluto/constants.c
@@ -0,0 +1,1271 @@
+/* tables of names for values defined in constants.h
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: constants.c,v 1.21 2006/03/27 07:38:59 as Exp $
+ */
+
+/*
+ * Note that the array sizes are all specified; this is to enable range
+ * checking by code that only includes constants.h.
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <netinet/in.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "packet.h"
+
+/* string naming compile-time options that have interop implications */
+
+const char compile_time_interop_options[] = ""
+#ifdef THREADS
+ " THREADS"
+#endif
+#ifdef LIBCURL
+ " LIBCURL"
+#endif
+#ifdef LDAP_VER
+#if LDAP_VER == 2
+ " LDAP_V2"
+#else
+ " LDAP_V3"
+#endif
+#endif
+#ifdef SMARTCARD
+ " SMARTCARD"
+#endif
+#ifdef VENDORID
+ " VENDORID"
+#endif
+#ifdef XAUTH_VID
+ " XAUTH_VID"
+#endif
+#ifdef USE_KEYRR
+ " KEYRR"
+#endif
+ ;
+
+/* version */
+
+static const char *const version_name[] = {
+ "ISAKMP Version 1.0",
+};
+
+enum_names version_names =
+ { ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION,
+ ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION,
+ version_name, NULL };
+
+/* RFC 2459 CRL reason codes */
+
+static const char *const crl_reason_name[] = {
+ "unspecified",
+ "key compromise",
+ "ca compromise",
+ "affiliation changed",
+ "superseded",
+ "cessation of operation",
+ "certificate hold",
+ "reason #7",
+ "remove from crl"
+ };
+
+enum_names crl_reason_names =
+ { REASON_UNSPECIFIED, REASON_REMOVE_FROM_CRL, crl_reason_name, NULL};
+
+/* RFC 3706 Dead Peer Detection */
+
+static const char *const dpd_action_name[] = {
+ "none",
+ "clear",
+ "hold",
+ "restart"
+ };
+
+enum_names dpd_action_names =
+ { DPD_ACTION_NONE, DPD_ACTION_RESTART, dpd_action_name, NULL};
+
+/* Timer events */
+
+static const char *const timer_event_name[] = {
+ "EVENT_NULL",
+ "EVENT_REINIT_SECRET",
+ "EVENT_SHUNT_SCAN",
+ "EVENT_SO_DISCARD",
+ "EVENT_RETRANSMIT",
+ "EVENT_SA_REPLACE",
+ "EVENT_SA_REPLACE_IF_USED",
+ "EVENT_SA_EXPIRE",
+ "EVENT_NAT_T_KEEPALIVE",
+ "EVENT_DPD",
+ "EVENT_DPD_TIMEOUT",
+ "EVENT_LOG_DAILY"
+ };
+
+enum_names timer_event_names =
+ { EVENT_NULL, EVENT_LOG_DAILY, timer_event_name, NULL };
+
+/* Domain of Interpretation */
+
+static const char *const doi_name[] = {
+ "ISAKMP_DOI_ISAKMP",
+ "ISAKMP_DOI_IPSEC",
+};
+
+enum_names doi_names = { ISAKMP_DOI_ISAKMP, ISAKMP_DOI_IPSEC, doi_name, NULL };
+
+/* debugging settings: a set of selections for reporting
+ * These would be more naturally situated in log.h,
+ * but they are shared with whack.
+ * It turns out that "debug-" is clutter in all contexts this is used,
+ * so we leave it off.
+ */
+#ifdef DEBUG
+const char *const debug_bit_names[] = {
+ "raw",
+ "crypt",
+ "parsing",
+ "emitting",
+ "control",
+ "lifecycle",
+ "klips",
+ "dns",
+ "natt",
+ "oppo",
+ "controlmore",
+
+ "private",
+
+ "impair-delay-adns-key-answer",
+ "impair-delay-adns-txt-answer",
+ "impair-bust-mi2",
+ "impair-bust-mr2",
+
+ NULL
+ };
+#endif
+
+/* State of exchanges */
+
+static const char *const state_name[] = {
+ "STATE_MAIN_R0",
+ "STATE_MAIN_I1",
+ "STATE_MAIN_R1",
+ "STATE_MAIN_I2",
+ "STATE_MAIN_R2",
+ "STATE_MAIN_I3",
+ "STATE_MAIN_R3",
+ "STATE_MAIN_I4",
+
+ "STATE_QUICK_R0",
+ "STATE_QUICK_I1",
+ "STATE_QUICK_R1",
+ "STATE_QUICK_I2",
+ "STATE_QUICK_R2",
+
+ "STATE_INFO",
+ "STATE_INFO_PROTECTED",
+
+ "STATE_MODE_CFG_R0",
+ "STATE_MODE_CFG_R1",
+ "STATE_MODE_CFG_R2",
+ "STATE_MODE_CFG_I1",
+ "STATE_MODE_CFG_I2",
+
+ "STATE_IKE_ROOF"
+ };
+
+enum_names state_names =
+ { STATE_MAIN_R0, STATE_IKE_ROOF-1, state_name, NULL };
+
+/* story for state */
+
+const char *const state_story[] = {
+ "expecting MI1", /* STATE_MAIN_R0 */
+ "sent MI1, expecting MR1", /* STATE_MAIN_I1 */
+ "sent MR1, expecting MI2", /* STATE_MAIN_R1 */
+ "sent MI2, expecting MR2", /* STATE_MAIN_I2 */
+ "sent MR2, expecting MI3", /* STATE_MAIN_R2 */
+ "sent MI3, expecting MR3", /* STATE_MAIN_I3 */
+ "sent MR3, ISAKMP SA established", /* STATE_MAIN_R3 */
+ "ISAKMP SA established", /* STATE_MAIN_I4 */
+
+ "expecting QI1", /* STATE_QUICK_R0 */
+ "sent QI1, expecting QR1", /* STATE_QUICK_I1 */
+ "sent QR1, inbound IPsec SA installed, expecting QI2", /* STATE_QUICK_R1 */
+ "sent QI2, IPsec SA established", /* STATE_QUICK_I2 */
+ "IPsec SA established", /* STATE_QUICK_R2 */
+
+ "got Informational Message in clear", /* STATE_INFO */
+ "got encrypted Informational Message", /* STATE_INFO_PROTECTED */
+
+ "sent ModeCfg reply", /* STATE_MODE_CFG_R0 */
+ "sent ModeCfg reply", /* STATE_MODE_CFG_R1 */
+ "ModeCfg R2", /* STATE_MODE_CFG_R2 */
+ "sent ModeCfg request, expecting reply", /* STATE_MODE_CFG_I1 */
+ "received ModeCfg reply", /* STATE_MODE_CFG_I2 */
+ };
+
+/* kind of struct connection */
+
+static const char *const connection_kind_name[] = {
+ "CK_GROUP", /* policy group: instantiates to template */
+ "CK_TEMPLATE", /* abstract connection, with wildcard */
+ "CK_PERMANENT", /* normal connection */
+ "CK_INSTANCE", /* instance of template, created for a particular attempt */
+ "CK_GOING_AWAY" /* instance being deleted -- don't delete again */
+};
+
+enum_names connection_kind_names =
+ { CK_GROUP, CK_GOING_AWAY, connection_kind_name, NULL };
+
+/* routing status names */
+
+static const char *const routing_story_strings[] = {
+ "unrouted", /* RT_UNROUTED: unrouted */
+ "unrouted HOLD", /* RT_UNROUTED_HOLD: unrouted, but HOLD shunt installed */
+ "eroute eclipsed", /* RT_ROUTED_ECLIPSED: RT_ROUTED_PROSPECTIVE except bare HOLD or instance has eroute */
+ "prospective erouted", /* RT_ROUTED_PROSPECTIVE: routed, and prospective shunt installed */
+ "erouted HOLD", /* RT_ROUTED_HOLD: routed, and HOLD shunt installed */
+ "fail erouted", /* RT_ROUTED_FAILURE: routed, and failure-context shunt eroute installed */
+ "erouted", /* RT_ROUTED_TUNNEL: routed, and erouted to an IPSEC SA group */
+ "keyed, unrouted", /* RT_UNROUTED_KEYED: was routed+keyed, but it got turned into an outer policy */
+ };
+
+enum_names routing_story =
+ { RT_UNROUTED, RT_ROUTED_TUNNEL, routing_story_strings, NULL};
+
+/* Payload types (RFC 2408 "ISAKMP" section 3.1) */
+
+const char *const payload_name[] = {
+ "ISAKMP_NEXT_NONE",
+ "ISAKMP_NEXT_SA",
+ "ISAKMP_NEXT_P",
+ "ISAKMP_NEXT_T",
+ "ISAKMP_NEXT_KE",
+ "ISAKMP_NEXT_ID",
+ "ISAKMP_NEXT_CERT",
+ "ISAKMP_NEXT_CR",
+ "ISAKMP_NEXT_HASH",
+ "ISAKMP_NEXT_SIG",
+ "ISAKMP_NEXT_NONCE",
+ "ISAKMP_NEXT_N",
+ "ISAKMP_NEXT_D",
+ "ISAKMP_NEXT_VID",
+ "ISAKMP_NEXT_MODECFG",
+ "ISAKMP_NEXT_15",
+ "ISAKMP_NEXT_16",
+ "ISAKMP_NEXT_17",
+ "ISAKMP_NEXT_18",
+ "ISAKMP_NEXT_19",
+ "ISAKMP_NEXT_NAT-D",
+ "ISAKMP_NEXT_NAT-OA",
+ NULL
+ };
+
+const char *const payload_name_nat_d[] = { "ISAKMP_NEXT_NAT-D",
+ "ISAKMP_NEXT_NAT-OA", NULL };
+
+static enum_names payload_names_nat_d =
+ { ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_NATOA_DRAFTS, payload_name_nat_d, NULL };
+
+enum_names payload_names =
+ { ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_nat_d };
+
+/* Exchange types (note: two discontinuous ranges) */
+
+static const char *const exchange_name[] = {
+ "ISAKMP_XCHG_NONE",
+ "ISAKMP_XCHG_BASE",
+ "ISAKMP_XCHG_IDPROT",
+ "ISAKMP_XCHG_AO",
+ "ISAKMP_XCHG_AGGR",
+ "ISAKMP_XCHG_INFO",
+ "ISAKMP_XCHG_MODE_CFG",
+ };
+
+static const char *const exchange_name2[] = {
+ "ISAKMP_XCHG_QUICK",
+ "ISAKMP_XCHG_NGRP",
+ "ISAKMP_XCHG_ACK_INFO",
+ };
+
+static enum_names exchange_desc2 =
+ { ISAKMP_XCHG_QUICK, ISAKMP_XCHG_ACK_INFO, exchange_name2, NULL };
+
+enum_names exchange_names =
+ { ISAKMP_XCHG_NONE, ISAKMP_XCHG_MODE_CFG, exchange_name, &exchange_desc2 };
+
+/* Flag BITS */
+const char *const flag_bit_names[] = {
+ "ISAKMP_FLAG_ENCRYPTION",
+ "ISAKMP_FLAG_COMMIT",
+ NULL
+ };
+
+/* Situation BITS definition for IPsec DOI */
+
+const char *const sit_bit_names[] = {
+ "SIT_IDENTITY_ONLY",
+ "SIT_SECRECY",
+ "SIT_INTEGRITY",
+ NULL
+ };
+
+/* Protocol IDs (RFC 2407 "IPsec DOI" section 4.4.1) */
+
+static const char *const protocol_name[] = {
+ "PROTO_ISAKMP",
+ "PROTO_IPSEC_AH",
+ "PROTO_IPSEC_ESP",
+ "PROTO_IPCOMP",
+ };
+
+enum_names protocol_names =
+ { PROTO_ISAKMP, PROTO_IPCOMP, protocol_name, NULL };
+
+/* IPsec ISAKMP transform values */
+
+static const char *const isakmp_transform_name[] = {
+ "KEY_IKE",
+ };
+
+enum_names isakmp_transformid_names =
+ { KEY_IKE, KEY_IKE, isakmp_transform_name, NULL };
+
+/* IPsec AH transform values */
+
+static const char *const ah_transform_name[] = {
+ "AH_MD5",
+ "AH_SHA",
+ "AH_DES",
+ "AH_SHA2_256",
+ "AH_SHA2_384",
+ "AH_SHA2_512",
+ "AH_RIPEMD"
+ };
+
+enum_names ah_transformid_names =
+ { AH_MD5, AH_RIPEMD, ah_transform_name, NULL };
+
+/* IPsec ESP transform values */
+
+static const char *const esp_transform_name[] = {
+ "ESP_DES_IV64",
+ "ESP_DES",
+ "ESP_3DES",
+ "ESP_RC5",
+ "ESP_IDEA",
+ "ESP_CAST",
+ "ESP_BLOWFISH",
+ "ESP_3IDEA",
+ "ESP_DES_IV32",
+ "ESP_RC4",
+ "ESP_NULL",
+ "ESP_AES",
+ "ESP_AES-CTR",
+ "ESP_AES-CCM_8",
+ "ESP_AES-CCM_12",
+ "ESP_AES-CCM_16"
+ };
+
+/*
+ * ipsec drafts suggest "high" ESP ids values for testing,
+ * assign generic ESP_ID<num> if not officially defined
+ */
+static const char *const esp_transform_name_high[] = {
+ "ESP_SERPENT",
+ "ESP_TWOFISH"
+ };
+
+enum_names esp_transformid_names_high =
+ { ESP_SERPENT, ESP_TWOFISH, esp_transform_name_high, NULL };
+
+enum_names esp_transformid_names =
+ { ESP_DES_IV64, ESP_AES_CCM_16, esp_transform_name, &esp_transformid_names_high };
+
+/* IPCOMP transform values */
+
+static const char *const ipcomp_transform_name[] = {
+ "IPCOMP_OUI",
+ "IPCOMP_DEFLAT",
+ "IPCOMP_LZS",
+ "IPCOMP_LZJH",
+ };
+
+enum_names ipcomp_transformid_names =
+ { IPCOMP_OUI, IPCOMP_LZJH, ipcomp_transform_name, NULL };
+
+/* Identification type values */
+
+static const char *const ident_name[] = {
+ "ID_IPV4_ADDR",
+ "ID_FQDN",
+ "ID_USER_FQDN",
+ "ID_IPV4_ADDR_SUBNET",
+ "ID_IPV6_ADDR",
+ "ID_IPV6_ADDR_SUBNET",
+ "ID_IPV4_ADDR_RANGE",
+ "ID_IPV6_ADDR_RANGE",
+ "ID_DER_ASN1_DN",
+ "ID_DER_ASN1_GN",
+ "ID_KEY_ID",
+ };
+
+enum_names ident_names =
+ { ID_IPV4_ADDR, ID_KEY_ID, ident_name, NULL };
+
+/* Certificate type values */
+
+static const char *const cert_type_name[] = {
+ "CERT_NONE",
+ "CERT_PKCS7_WRAPPED_X509",
+ "CERT_PGP",
+ "CERT_DNS_SIGNED_KEY",
+ "CERT_X509_SIGNATURE",
+ "CERT_X509_KEY_EXCHANGE",
+ "CERT_KERBEROS_TOKENS",
+ "CERT_CRL",
+ "CERT_ARL",
+ "CERT_SPKI",
+ "CERT_X509_ATTRIBUTE",
+ };
+
+enum_names cert_type_names =
+ { CERT_NONE, CERT_X509_ATTRIBUTE, cert_type_name, NULL };
+
+/* Certificate policy names */
+
+static const char *const cert_policy_name[] = {
+ "ALWAYS_SEND",
+ "SEND_IF_ASKED",
+ "NEVER_SEND",
+ };
+
+enum_names cert_policy_names =
+ { CERT_ALWAYS_SEND, CERT_NEVER_SEND, cert_policy_name, NULL };
+
+/* Goal BITs for establishing an SA
+ * Note: we drop the POLICY_ prefix so that logs are more concise.
+ */
+
+const char *const sa_policy_bit_names[] = {
+ "PSK",
+ "RSASIG",
+ "ENCRYPT",
+ "AUTHENTICATE",
+ "COMPRESS",
+ "TUNNEL",
+ "PFS",
+ "DISABLEARRIVALCHECK",
+ "SHUNT0",
+ "SHUNT1",
+ "FAILSHUNT0",
+ "FAILSHUNT1",
+ "DONTREKEY",
+ "OPPORTUNISTIC",
+ "GROUP",
+ "GROUTED",
+ "UP",
+ NULL
+ };
+
+const char *const policy_shunt_names[4] = {
+ "TRAP",
+ "PASS",
+ "DROP",
+ "REJECT",
+ };
+
+const char *const policy_fail_names[4] = {
+ "NONE",
+ "PASS",
+ "DROP",
+ "REJECT",
+ };
+
+/* Oakley transform attributes
+ * oakley_attr_bit_names does double duty: it is used for enum names
+ * and bit names.
+ */
+
+const char *const oakley_attr_bit_names[] = {
+ "OAKLEY_ENCRYPTION_ALGORITHM",
+ "OAKLEY_HASH_ALGORITHM",
+ "OAKLEY_AUTHENTICATION_METHOD",
+ "OAKLEY_GROUP_DESCRIPTION",
+ "OAKLEY_GROUP_TYPE",
+ "OAKLEY_GROUP_PRIME",
+ "OAKLEY_GROUP_GENERATOR_ONE",
+ "OAKLEY_GROUP_GENERATOR_TWO",
+ "OAKLEY_GROUP_CURVE_A",
+ "OAKLEY_GROUP_CURVE_B",
+ "OAKLEY_LIFE_TYPE",
+ "OAKLEY_LIFE_DURATION",
+ "OAKLEY_PRF",
+ "OAKLEY_KEY_LENGTH",
+ "OAKLEY_FIELD_SIZE",
+ "OAKLEY_GROUP_ORDER",
+ "OAKLEY_BLOCK_SIZE",
+ NULL
+ };
+
+static const char *const oakley_var_attr_name[] = {
+ "OAKLEY_GROUP_PRIME (variable length)",
+ "OAKLEY_GROUP_GENERATOR_ONE (variable length)",
+ "OAKLEY_GROUP_GENERATOR_TWO (variable length)",
+ "OAKLEY_GROUP_CURVE_A (variable length)",
+ "OAKLEY_GROUP_CURVE_B (variable length)",
+ NULL,
+ "OAKLEY_LIFE_DURATION (variable length)",
+ NULL,
+ NULL,
+ NULL,
+ "OAKLEY_GROUP_ORDER (variable length)",
+ };
+
+static enum_names oakley_attr_desc_tv = {
+ OAKLEY_ENCRYPTION_ALGORITHM + ISAKMP_ATTR_AF_TV,
+ OAKLEY_GROUP_ORDER + ISAKMP_ATTR_AF_TV, oakley_attr_bit_names, NULL };
+
+enum_names oakley_attr_names = {
+ OAKLEY_GROUP_PRIME, OAKLEY_GROUP_ORDER,
+ oakley_var_attr_name, &oakley_attr_desc_tv };
+
+/* for each Oakley attribute, which enum_names describes its values? */
+enum_names *oakley_attr_val_descs[] = {
+ NULL, /* (none) */
+ &oakley_enc_names, /* OAKLEY_ENCRYPTION_ALGORITHM */
+ &oakley_hash_names, /* OAKLEY_HASH_ALGORITHM */
+ &oakley_auth_names, /* OAKLEY_AUTHENTICATION_METHOD */
+ &oakley_group_names, /* OAKLEY_GROUP_DESCRIPTION */
+ &oakley_group_type_names,/* OAKLEY_GROUP_TYPE */
+ NULL, /* OAKLEY_GROUP_PRIME */
+ NULL, /* OAKLEY_GROUP_GENERATOR_ONE */
+ NULL, /* OAKLEY_GROUP_GENERATOR_TWO */
+ NULL, /* OAKLEY_GROUP_CURVE_A */
+ NULL, /* OAKLEY_GROUP_CURVE_B */
+ &oakley_lifetime_names, /* OAKLEY_LIFE_TYPE */
+ NULL, /* OAKLEY_LIFE_DURATION */
+ &oakley_prf_names, /* OAKLEY_PRF */
+ NULL, /* OAKLEY_KEY_LENGTH */
+ NULL, /* OAKLEY_FIELD_SIZE */
+ NULL, /* OAKLEY_GROUP_ORDER */
+ };
+
+/* IPsec DOI attributes (RFC 2407 "IPsec DOI" section 4.5) */
+
+static const char *const ipsec_attr_name[] = {
+ "SA_LIFE_TYPE",
+ "SA_LIFE_DURATION",
+ "GROUP_DESCRIPTION",
+ "ENCAPSULATION_MODE",
+ "AUTH_ALGORITHM",
+ "KEY_LENGTH",
+ "KEY_ROUNDS",
+ "COMPRESS_DICT_SIZE",
+ "COMPRESS_PRIVATE_ALG",
+ };
+
+static const char *const ipsec_var_attr_name[] = {
+ "SA_LIFE_DURATION (variable length)",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "COMPRESS_PRIVATE_ALG (variable length)",
+ };
+
+static enum_names ipsec_attr_desc_tv = {
+ SA_LIFE_TYPE + ISAKMP_ATTR_AF_TV,
+ COMPRESS_PRIVATE_ALG + ISAKMP_ATTR_AF_TV,
+ ipsec_attr_name, NULL };
+
+enum_names ipsec_attr_names = {
+ SA_LIFE_DURATION, COMPRESS_PRIVATE_ALG,
+ ipsec_var_attr_name, &ipsec_attr_desc_tv };
+
+/* for each IPsec attribute, which enum_names describes its values? */
+enum_names *ipsec_attr_val_descs[] = {
+ NULL, /* (none) */
+ &sa_lifetime_names, /* SA_LIFE_TYPE */
+ NULL, /* SA_LIFE_DURATION */
+ &oakley_group_names, /* GROUP_DESCRIPTION */
+ &enc_mode_names, /* ENCAPSULATION_MODE */
+ &auth_alg_names, /* AUTH_ALGORITHM */
+ NULL, /* KEY_LENGTH */
+ NULL, /* KEY_ROUNDS */
+ NULL, /* COMPRESS_DICT_SIZE */
+ NULL, /* COMPRESS_PRIVATE_ALG */
+ };
+
+/* SA Lifetime Type attribute */
+
+static const char *const sa_lifetime_name[] = {
+ "SA_LIFE_TYPE_SECONDS",
+ "SA_LIFE_TYPE_KBYTES",
+ };
+
+enum_names sa_lifetime_names =
+ { SA_LIFE_TYPE_SECONDS, SA_LIFE_TYPE_KBYTES, sa_lifetime_name, NULL };
+
+/* Encapsulation Mode attribute */
+
+static const char *const enc_mode_name[] = {
+ "ENCAPSULATION_MODE_TUNNEL",
+ "ENCAPSULATION_MODE_TRANSPORT",
+ "ENCAPSULATION_MODE_UDP_TUNNEL",
+ "ENCAPSULATION_MODE_UDP_TRANSPORT",
+ };
+
+static const char *const enc_udp_mode_name[] = {
+ "ENCAPSULATION_MODE_UDP_TUNNEL",
+ "ENCAPSULATION_MODE_UDP_TRANSPORT",
+ };
+
+static enum_names enc_udp_mode_names =
+ { ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS, ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS, enc_udp_mode_name, NULL };
+
+enum_names enc_mode_names =
+ { ENCAPSULATION_MODE_TUNNEL, ENCAPSULATION_MODE_UDP_TRANSPORT_RFC, enc_mode_name, &enc_udp_mode_names };
+
+/* Auth Algorithm attribute */
+
+static const char *const auth_alg_name[] = {
+ "AUTH_ALGORITHM_HMAC_MD5",
+ "AUTH_ALGORITHM_HMAC_SHA1",
+ "AUTH_ALGORITHM_DES_MAC",
+ "AUTH_ALGORITHM_KPDK",
+ "AUTH_ALGORITHM_HMAC_SHA2_256",
+ "AUTH_ALGORITHM_HMAC_SHA2_384",
+ "AUTH_ALGORITHM_HMAC_SHA2_512",
+ "AUTH_ALGORITHM_HMAC_RIPEMD",
+ };
+
+static const char *const extended_auth_alg_name[] = {
+ "AUTH_ALGORITHM_NULL"
+ };
+
+enum_names extended_auth_alg_names =
+ { AUTH_ALGORITHM_NULL, AUTH_ALGORITHM_NULL, extended_auth_alg_name, NULL };
+
+enum_names auth_alg_names =
+ { AUTH_ALGORITHM_HMAC_MD5, AUTH_ALGORITHM_HMAC_RIPEMD, auth_alg_name
+ , &extended_auth_alg_names };
+
+const char *const modecfg_attr_name[] = {
+ "INTERNAL_IP4_ADDRESS",
+ "INTERNAL_IP4_NETMASK",
+ "INTERNAL_IP4_DNS",
+ "INTERNAL_IP4_NBNS",
+ "INTERNAL_ADDRESS_EXPIRY",
+ "INTERNAL_IP4_DHCP",
+ "APPLICATION_VERSION",
+ "INTERNAL_IP6_ADDRESS",
+ "INTERNAL_IP6_NETMASK",
+ "INTERNAL_IP6_DNS",
+ "INTERNAL_IP6_NBNS",
+ "INTERNAL_IP6_DHCP",
+ "INTERNAL_IP4_SUBNET",
+ "SUPPORTED_ATTRIBUTES",
+ "INTERNAL_IP6_SUBNET",
+ NULL
+ };
+
+enum_names modecfg_attr_names =
+ { INTERNAL_IP4_ADDRESS , INTERNAL_IP6_SUBNET, modecfg_attr_name , NULL };
+
+/* Oakley Lifetime Type attribute */
+
+static const char *const oakley_lifetime_name[] = {
+ "OAKLEY_LIFE_SECONDS",
+ "OAKLEY_LIFE_KILOBYTES",
+ };
+
+enum_names oakley_lifetime_names =
+ { OAKLEY_LIFE_SECONDS, OAKLEY_LIFE_KILOBYTES, oakley_lifetime_name, NULL };
+
+/* Oakley PRF attribute (none defined) */
+
+enum_names oakley_prf_names =
+ { 1, 0, NULL, NULL };
+
+/* Oakley Encryption Algorithm attribute */
+
+static const char *const oakley_enc_name[] = {
+ "OAKLEY_DES_CBC",
+ "OAKLEY_IDEA_CBC",
+ "OAKLEY_BLOWFISH_CBC",
+ "OAKLEY_RC5_R16_B64_CBC",
+ "OAKLEY_3DES_CBC",
+ "OAKLEY_CAST_CBC",
+ "OAKLEY_AES_CBC",
+ };
+
+#ifdef NO_EXTRA_IKE
+enum_names oakley_enc_names =
+ { OAKLEY_DES_CBC, OAKLEY_AES_CBC, oakley_enc_name, NULL };
+#else
+static const char *const oakley_enc_name_draft_aes_cbc_02[] = {
+ "OAKLEY_MARS_CBC" /* 65001 */,
+ "OAKLEY_RC6_CBC" /* 65002 */,
+ "OAKLEY_ID_65003" /* 65003 */,
+ "OAKLEY_SERPENT_CBC" /* 65004 */,
+ "OAKLEY_TWOFISH_CBC" /* 65005 */,
+};
+static const char *const oakley_enc_name_ssh[] = {
+ "OAKLEY_TWOFISH_CBC_SSH",
+};
+enum_names oakley_enc_names_ssh =
+ { OAKLEY_TWOFISH_CBC_SSH, OAKLEY_TWOFISH_CBC_SSH, oakley_enc_name_ssh
+ , NULL };
+
+enum_names oakley_enc_names_draft_aes_cbc_02 =
+ { OAKLEY_MARS_CBC, OAKLEY_TWOFISH_CBC, oakley_enc_name_draft_aes_cbc_02
+ , &oakley_enc_names_ssh };
+
+enum_names oakley_enc_names =
+ { OAKLEY_DES_CBC, OAKLEY_AES_CBC, oakley_enc_name
+ , &oakley_enc_names_draft_aes_cbc_02 };
+#endif
+
+/* Oakley Hash Algorithm attribute */
+
+static const char *const oakley_hash_name[] = {
+ "OAKLEY_MD5",
+ "OAKLEY_SHA",
+ "OAKLEY_TIGER",
+ "OAKLEY_SHA2_256",
+ "OAKLEY_SHA2_384",
+ "OAKLEY_SHA2_512",
+ };
+
+enum_names oakley_hash_names =
+ { OAKLEY_MD5, OAKLEY_SHA2_512, oakley_hash_name, NULL };
+
+/* Oakley Authentication Method attribute */
+
+static const char *const oakley_auth_name1[] = {
+ "OAKLEY_PRESHARED_KEY",
+ "OAKLEY_DSS_SIG",
+ "OAKLEY_RSA_SIG",
+ "OAKLEY_RSA_ENC",
+ "OAKLEY_RSA_ENC_REV",
+ "OAKLEY_ELGAMAL_ENC",
+ "OAKLEY_ELGAMAL_ENC_REV",
+ };
+
+static const char *const oakley_auth_name2[] = {
+ "HybridInitRSA",
+ "HybridRespRSA",
+ "HybridInitDSS",
+ "HybridRespDSS",
+ };
+
+static const char *const oakley_auth_name3[] = {
+ "XAUTHInitPreShared",
+ "XAUTHRespPreShared",
+ "XAUTHInitDSS",
+ "XAUTHRespDSS",
+ "XAUTHInitRSA",
+ "XAUTHRespRSA",
+ "XAUTHInitRSAEncryption",
+ "XAUTHRespRSAEncryption",
+ "XAUTHInitRSARevisedEncryption",
+ "XAUTHRespRSARevisedEncryption",
+ };
+
+static enum_names oakley_auth_names1 =
+ { OAKLEY_PRESHARED_KEY, OAKLEY_ELGAMAL_ENC_REV
+ , oakley_auth_name1, NULL };
+
+static enum_names oakley_auth_names2 =
+ { HybridInitRSA, HybridRespDSS
+ , oakley_auth_name2, &oakley_auth_names1 };
+
+enum_names oakley_auth_names =
+ { XAUTHInitPreShared, XAUTHRespRSARevisedEncryption
+ , oakley_auth_name3, &oakley_auth_names2 };
+
+/* Oakley Group Description attribute */
+
+static const char *const oakley_group_name[] = {
+ "OAKLEY_GROUP_MODP768",
+ "OAKLEY_GROUP_MODP1024",
+ "OAKLEY_GROUP_GP155",
+ "OAKLEY_GROUP_GP185",
+ "OAKLEY_GROUP_MODP1536",
+ };
+
+static const char *const oakley_group_name_rfc3526[] = {
+ "OAKLEY_GROUP_MODP2048",
+ "OAKLEY_GROUP_MODP3072",
+ "OAKLEY_GROUP_MODP4096",
+ "OAKLEY_GROUP_MODP6144",
+ "OAKLEY_GROUP_MODP8192"
+};
+enum_names oakley_group_names_rfc3526 =
+ { OAKLEY_GROUP_MODP2048, OAKLEY_GROUP_MODP8192,
+ oakley_group_name_rfc3526, NULL };
+
+enum_names oakley_group_names =
+ { OAKLEY_GROUP_MODP768, OAKLEY_GROUP_MODP1536,
+ oakley_group_name, &oakley_group_names_rfc3526 };
+
+/* Oakley Group Type attribute */
+
+static const char *const oakley_group_type_name[] = {
+ "OAKLEY_GROUP_TYPE_MODP",
+ "OAKLEY_GROUP_TYPE_ECP",
+ "OAKLEY_GROUP_TYPE_EC2N",
+ };
+
+enum_names oakley_group_type_names =
+ { OAKLEY_GROUP_TYPE_MODP, OAKLEY_GROUP_TYPE_EC2N, oakley_group_type_name, NULL };
+
+/* Notify messages -- error types */
+
+static const char *const notification_name[] = {
+ "INVALID_PAYLOAD_TYPE",
+ "DOI_NOT_SUPPORTED",
+ "SITUATION_NOT_SUPPORTED",
+ "INVALID_COOKIE",
+ "INVALID_MAJOR_VERSION",
+ "INVALID_MINOR_VERSION",
+ "INVALID_EXCHANGE_TYPE",
+ "INVALID_FLAGS",
+ "INVALID_MESSAGE_ID",
+ "INVALID_PROTOCOL_ID",
+ "INVALID_SPI",
+ "INVALID_TRANSFORM_ID",
+ "ATTRIBUTES_NOT_SUPPORTED",
+ "NO_PROPOSAL_CHOSEN",
+ "BAD_PROPOSAL_SYNTAX",
+ "PAYLOAD_MALFORMED",
+ "INVALID_KEY_INFORMATION",
+ "INVALID_ID_INFORMATION",
+ "INVALID_CERT_ENCODING",
+ "INVALID_CERTIFICATE",
+ "CERT_TYPE_UNSUPPORTED",
+ "INVALID_CERT_AUTHORITY",
+ "INVALID_HASH_INFORMATION",
+ "AUTHENTICATION_FAILED",
+ "INVALID_SIGNATURE",
+ "ADDRESS_NOTIFICATION",
+ "NOTIFY_SA_LIFETIME",
+ "CERTIFICATE_UNAVAILABLE",
+ "UNSUPPORTED_EXCHANGE_TYPE",
+ "UNEQUAL_PAYLOAD_LENGTHS",
+ };
+
+static const char *const notification_status_name[] = {
+ "CONNECTED",
+ };
+
+static const char *const ipsec_notification_name[] = {
+ "IPSEC_RESPONDER_LIFETIME",
+ "IPSEC_REPLAY_STATUS",
+ "IPSEC_INITIAL_CONTACT",
+ };
+
+static const char *const notification_dpd_name[] = {
+ "R_U_THERE",
+ "R_U_THERE_ACK",
+};
+
+enum_names notification_dpd_names =
+ { R_U_THERE, R_U_THERE_ACK,
+ notification_dpd_name, NULL };
+
+enum_names ipsec_notification_names =
+ { IPSEC_RESPONDER_LIFETIME, IPSEC_INITIAL_CONTACT,
+ ipsec_notification_name, &notification_dpd_names };
+
+enum_names notification_status_names =
+ { CONNECTED, CONNECTED,
+ notification_status_name, &ipsec_notification_names };
+
+enum_names notification_names =
+ { INVALID_PAYLOAD_TYPE, UNEQUAL_PAYLOAD_LENGTHS,
+ notification_name, &notification_status_names };
+
+/* MODECFG
+ * From draft-dukes-ike-mode-cfg
+ */
+const char *const attr_msg_type_name[] = {
+ "ISAKMP_CFG_RESERVED",
+ "ISAKMP_CFG_REQUEST",
+ "ISAKMP_CFG_REPLY",
+ "ISAKMP_CFG_SET",
+ "ISAKMP_CFG_ACK",
+ NULL
+ };
+
+enum_names attr_msg_type_names =
+ { 0 , ISAKMP_CFG_ACK, attr_msg_type_name , NULL };
+
+/* socket address family info */
+
+static const char *const af_inet_name[] = {
+ "AF_INET",
+ };
+
+static const char *const af_inet6_name[] = {
+ "AF_INET6",
+ };
+
+static enum_names af_names6 = { AF_INET6, AF_INET6, af_inet6_name, NULL };
+
+enum_names af_names = { AF_INET, AF_INET, af_inet_name, &af_names6 };
+
+static ip_address ipv4_any, ipv6_any;
+static ip_subnet ipv4_wildcard, ipv6_wildcard;
+static ip_subnet ipv4_all, ipv6_all;
+
+const struct af_info af_inet4_info = {
+ AF_INET,
+ "AF_INET",
+ sizeof(struct in_addr),
+ sizeof(struct sockaddr_in),
+ 32,
+ ID_IPV4_ADDR, ID_IPV4_ADDR_SUBNET, ID_IPV4_ADDR_RANGE,
+ &ipv4_any, &ipv4_wildcard, &ipv4_all,
+ };
+
+const struct af_info af_inet6_info = {
+ AF_INET6,
+ "AF_INET6",
+ sizeof(struct in6_addr),
+ sizeof(struct sockaddr_in6),
+ 128,
+ ID_IPV6_ADDR, ID_IPV6_ADDR_SUBNET, ID_IPV6_ADDR_RANGE,
+ &ipv6_any, &ipv6_wildcard, &ipv6_all,
+ };
+
+const struct af_info *
+aftoinfo(int af)
+{
+ switch (af)
+ {
+ case AF_INET:
+ return &af_inet4_info;
+ case AF_INET6:
+ return &af_inet6_info;
+ default:
+ return NULL;
+ }
+}
+
+bool
+subnetisnone(const ip_subnet *sn)
+{
+ ip_address base;
+
+ networkof(sn, &base);
+ return isanyaddr(&base) && subnetishost(sn);
+}
+
+/* BIND enumerated types */
+
+#include <arpa/nameser.h>
+
+static const char *const rr_type_name[] = {
+ "T_A", /* 1 host address */
+ "T_NS", /* 2 authoritative server */
+ "T_MD", /* 3 mail destination */
+ "T_MF", /* 4 mail forwarder */
+ "T_CNAME", /* 5 canonical name */
+ "T_SOA", /* 6 start of authority zone */
+ "T_MB", /* 7 mailbox domain name */
+ "T_MG", /* 8 mail group member */
+ "T_MR", /* 9 mail rename name */
+ "T_NULL", /* 10 null resource record */
+ "T_WKS", /* 11 well known service */
+ "T_PTR", /* 12 domain name pointer */
+ "T_HINFO", /* 13 host information */
+ "T_MINFO", /* 14 mailbox information */
+ "T_MX", /* 15 mail routing information */
+ "T_TXT", /* 16 text strings */
+ "T_RP", /* 17 responsible person */
+ "T_AFSDB", /* 18 AFS cell database */
+ "T_X25", /* 19 X_25 calling address */
+ "T_ISDN", /* 20 ISDN calling address */
+ "T_RT", /* 21 router */
+ "T_NSAP", /* 22 NSAP address */
+ "T_NSAP_PTR", /* 23 reverse NSAP lookup (deprecated) */
+ "T_SIG", /* 24 security signature */
+ "T_KEY", /* 25 security key */
+ "T_PX", /* 26 X.400 mail mapping */
+ "T_GPOS", /* 27 geographical position (withdrawn) */
+ "T_AAAA", /* 28 IP6 Address */
+ "T_LOC", /* 29 Location Information */
+ "T_NXT", /* 30 Next Valid Name in Zone */
+ "T_EID", /* 31 Endpoint identifier */
+ "T_NIMLOC", /* 32 Nimrod locator */
+ "T_SRV", /* 33 Server selection */
+ "T_ATMA", /* 34 ATM Address */
+ "T_NAPTR", /* 35 Naming Authority PoinTeR */
+ NULL
+ };
+
+enum_names rr_type_names = { T_A, T_NAPTR, rr_type_name, NULL };
+
+/* Query type values which do not appear in resource records */
+static const char *const rr_qtype_name[] = {
+ "T_IXFR", /* 251 incremental zone transfer */
+ "T_AXFR", /* 252 transfer zone of authority */
+ "T_MAILB", /* 253 transfer mailbox records */
+ "T_MAILA", /* 254 transfer mail agent records */
+ "T_ANY", /* 255 wildcard match */
+ NULL
+ };
+
+enum_names rr_qtype_names = { T_IXFR, T_ANY, rr_qtype_name, &rr_type_names };
+
+static const char *const rr_class_name[] = {
+ "C_IN", /* 1 the arpa internet */
+ NULL
+ };
+
+enum_names rr_class_names = { C_IN, C_IN, rr_class_name, NULL };
+
+/*
+ * NAT-Traversal defines for nat_traveral type from nat_traversal.h
+ *
+ */
+const char *const natt_type_bitnames[] = {
+ "draft-ietf-ipsec-nat-t-ike-00/01", /* 0 */
+ "draft-ietf-ipsec-nat-t-ike-02/03",
+ "RFC 3947",
+ "3", /* 3 */
+ "4", "5", "6", "7",
+ "8", "9", "10", "11",
+ "12", "13", "14", "15",
+ "16", "17", "18", "19",
+ "20", "21", "22", "23",
+ "24", "25", "26", "27",
+ "28", "29",
+ "nat is behind me",
+ "nat is behind peer"
+};
+
+/* look up enum names in an enum_names */
+
+const char *
+enum_name(enum_names *ed, unsigned long val)
+{
+ enum_names *p;
+
+ for (p = ed; p != NULL; p = p->en_next_range)
+ {
+ if (p->en_first <= val && val <= p->en_last)
+ return p->en_names[val - p->en_first];
+ }
+ return NULL;
+}
+
+/* find or construct a string to describe an enum value
+ * Result may be in STATIC buffer!
+ */
+const char *
+enum_show(enum_names *ed, unsigned long val)
+{
+ const char *p = enum_name(ed, val);
+
+ if (p == NULL)
+ {
+ static char buf[12]; /* only one! I hope that it is big enough */
+
+ snprintf(buf, sizeof(buf), "%lu??", val);
+ p = buf;
+ }
+ return p;
+}
+
+
+static char bitnamesbuf[200]; /* only one! I hope that it is big enough! */
+
+int
+enum_search(enum_names *ed, const char *str)
+{
+ enum_names *p;
+ const char *ptr;
+ unsigned en;
+
+ for (p = ed; p != NULL; p = p->en_next_range)
+ for (en = p->en_first; en <= p->en_last ;en++)
+ {
+ ptr = p->en_names[en - p->en_first];
+ if (ptr == 0) continue;
+ /* if (strncmp(ptr, str, strlen(ptr))==0) */
+ if (strcmp(ptr, str) == 0)
+ return en;
+ }
+ return -1;
+}
+
+/* construct a string to name the bits on in a set
+ * Result may be in STATIC buffer!
+ * Note: prettypolicy depends on internal details.
+ */
+const char *
+bitnamesof(const char *const table[], lset_t val)
+{
+ char *p = bitnamesbuf;
+ lset_t bit;
+ const char *const *tp;
+
+ if (val == 0)
+ return "none";
+
+ for (tp = table, bit = 01; val != 0; bit <<= 1)
+ {
+ if (val & bit)
+ {
+ const char *n = *tp;
+ size_t nl;
+
+ if (n == NULL || *n == '\0')
+ {
+ /* no name for this bit, so use hex */
+ static char flagbuf[sizeof("0x80000000")];
+
+ snprintf(flagbuf, sizeof(flagbuf), "0x%llx", bit);
+ n = flagbuf;
+ }
+
+ nl = strlen(n);
+
+ if (p != bitnamesbuf && p < bitnamesbuf+sizeof(bitnamesbuf) - 1)
+ *p++ = '+';
+
+ if (bitnamesbuf+sizeof(bitnamesbuf) - p > (ptrdiff_t)nl)
+ {
+ strcpy(p, n);
+ p += nl;
+ }
+ val -= bit;
+ }
+ if (*tp != NULL)
+ tp++; /* move on, but not past end */
+ }
+ *p = '\0';
+ return bitnamesbuf;
+}
+
+/* print a policy: like bitnamesof, but it also does the non-bitfields.
+ * Suppress the shunt and fail fields if 0.
+ */
+const char *
+prettypolicy(lset_t policy)
+{
+ const char *bn = bitnamesof(sa_policy_bit_names
+ , policy & ~(POLICY_SHUNT_MASK | POLICY_FAIL_MASK));
+ size_t len;
+ lset_t shunt = (policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT;
+ lset_t fail = (policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT;
+
+ if (bn != bitnamesbuf)
+ bitnamesbuf[0] = '\0';
+ len = strlen(bitnamesbuf);
+ if (shunt != 0)
+ {
+ snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+%s"
+ , policy_shunt_names[shunt]);
+ len += strlen(bitnamesbuf + len);
+ }
+ if (fail != 0)
+ {
+ snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+failure%s"
+ , policy_fail_names[fail]);
+ len += strlen(bitnamesbuf + len);
+ }
+ if (NEVER_NEGOTIATE(policy))
+ {
+ snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+NEVER_NEGOTIATE");
+ len += strlen(bitnamesbuf + len);
+ }
+ return bitnamesbuf;
+}
+
+/* test a set by seeing if all bits have names */
+
+bool
+testset(const char *const table[], lset_t val)
+{
+ lset_t bit;
+ const char *const *tp;
+
+ for (tp = table, bit = 01; val != 0; bit <<= 1, tp++)
+ {
+ const char *n = *tp;
+
+ if (n == NULL || ((val & bit) && *n == '\0'))
+ return FALSE;
+ val &= ~bit;
+ }
+ return TRUE;
+}
+
+
+const char sparse_end[] = "end of sparse names";
+
+/* look up enum names in a sparse_names */
+const char *sparse_name(sparse_names sd, unsigned long val)
+{
+ const struct sparse_name *p;
+
+ for (p = sd; p->name != sparse_end; p++)
+ if (p->val == val)
+ return p->name;
+ return NULL;
+}
+
+/* find or construct a string to describe an sparse value
+ * Result may be in STATIC buffer!
+ */
+const char *
+sparse_val_show(sparse_names sd, unsigned long val)
+{
+ const char *p = sparse_name(sd, val);
+
+ if (p == NULL)
+ {
+ static char buf[12]; /* only one! I hope that it is big enough */
+
+ snprintf(buf, sizeof(buf), "%lu??", val);
+ p = buf;
+ }
+ return p;
+}
+
+void init_constants(void)
+{
+ happy(anyaddr(AF_INET, &ipv4_any));
+ happy(anyaddr(AF_INET6, &ipv6_any));
+
+ happy(addrtosubnet(&ipv4_any, &ipv4_wildcard));
+ happy(addrtosubnet(&ipv6_any, &ipv6_wildcard));
+
+ happy(initsubnet(&ipv4_any, 0, '0', &ipv4_all));
+ happy(initsubnet(&ipv6_any, 0, '0', &ipv6_all));
+}
diff --git a/programs/pluto/constants.h b/programs/pluto/constants.h
new file mode 100644
index 000000000..b66d002ee
--- /dev/null
+++ b/programs/pluto/constants.h
@@ -0,0 +1,1184 @@
+/* manifest constants
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: constants.h,v 1.20 2006/02/28 19:13:33 as Exp $
+ */
+
+#ifndef _CONSTANTS_H
+#define _CONSTANTS_H
+
+extern const char compile_time_interop_options[];
+
+extern void init_constants(void);
+
+/*
+ * NOTE:For debugging purposes, constants.c has tables to map numbers back to names.
+ * Any changes here should be reflected there.
+ */
+
+#define elemsof(array) (sizeof(array) / sizeof(*(array))) /* number of elements in an array */
+
+/* Many routines return only success or failure, but wish to describe
+ * the failure in a message. We use the convention that they return
+ * a NULL on success and a pointer to constant string on failure.
+ * The fact that the string is a constant is limiting, but it
+ * avoids storage management issues: the recipient is allowed to assume
+ * that the string will live "long enough" (usually forever).
+ * <freeswan.h> defines err_t for this return type.
+ */
+
+typedef int bool;
+#define FALSE 0
+#define TRUE 1
+
+#define NULL_FD (-1) /* NULL file descriptor */
+#define dup_any(fd) ((fd) == NULL_FD? NULL_FD : dup(fd))
+#define close_any(fd) { if ((fd) != NULL_FD) { close(fd); (fd) = NULL_FD; } }
+
+#define BITS_PER_BYTE 8
+
+#define streq(a, b) (strcmp((a), (b)) == 0) /* clearer shorthand */
+#define strcaseeq(a, b) (strcasecmp((a), (b)) == 0) /* clearer shorthand */
+
+/* set type with room for at least 64 elements for ALG opts (was 32 in stock FS) */
+
+typedef unsigned long long lset_t;
+#define LEMPTY 0ULL
+#define LELEM(opt) (1ULL << (opt))
+#define LRANGE(lwb, upb) LRANGES(LELEM(lwb), LELEM(upb))
+#define LRANGES(first, last) (last - first + last)
+#define LHAS(set, elem) ((LELEM(elem) & (set)) != LEMPTY)
+#define LIN(subset, set) (((subset) & (set)) == (subset))
+#define LDISJOINT(a, b) (((a) & (b)) == LEMPTY)
+
+/* Control and lock pathnames */
+
+#ifndef DEFAULT_CTLBASE
+# define DEFAULT_CTLBASE "/var/run/pluto"
+#endif
+
+#define CTL_SUFFIX ".ctl" /* for UNIX domain socket pathname */
+#define LOCK_SUFFIX ".pid" /* for pluto's lock */
+#define INFO_SUFFIX ".info" /* for UNIX domain socket for apps */
+
+/* Routines to check and display values.
+ *
+ * An enum_names describes an enumeration.
+ * enum_name() returns the name of an enum value, or NULL if invalid.
+ * enum_show() is like enum_name, except it formats a numeric representation
+ * for any invalid value (in a static area!)
+ *
+ * bitnames() formats a display of a set of named bits (in a static area)
+ */
+
+struct enum_names {
+ unsigned long en_first; /* first value in range */
+ unsigned long en_last; /* last value in range (inclusive) */
+ const char *const *en_names;
+ const struct enum_names *en_next_range; /* descriptor of next range */
+};
+
+typedef const struct enum_names enum_names;
+
+extern const char *enum_name(enum_names *ed, unsigned long val);
+extern const char *enum_show(enum_names *ed, unsigned long val);
+extern int enum_search(enum_names *ed, const char *string);
+
+extern bool testset(const char *const table[], lset_t val);
+extern const char *bitnamesof(const char *const table[], lset_t val);
+
+/* sparse_names is much like enum_names, except values are
+ * not known to be contiguous or ordered.
+ * The array of names is ended with one with the name sparse_end
+ * (this avoids having to reserve a value to signify the end).
+ * Often appropriate for enums defined by others.
+ */
+struct sparse_name {
+ unsigned long val;
+ const char *const name;
+};
+typedef const struct sparse_name sparse_names[];
+
+extern const char *sparse_name(sparse_names sd, unsigned long val);
+extern const char *sparse_val_show(sparse_names sd, unsigned long val);
+extern const char sparse_end[];
+
+#define FULL_INET_ADDRESS_SIZE 6
+
+/* Group parameters from draft-ietf-ike-01.txt section 6 */
+
+#define MODP_GENERATOR "2"
+
+#define MODP768_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 " \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD " \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 " \
+ "E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF"
+
+#define MODP1024_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 " \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD " \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 " \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED " \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 " \
+ "FFFFFFFF FFFFFFFF"
+
+#define MODP1536_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 " \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD " \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 " \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED " \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D " \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F " \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D " \
+ "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF "
+
+/* draft-ietf-ipsec-ike-modp-groups-03.txt */
+#define MODP2048_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+ "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"
+
+#define MODP3072_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+ "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF"
+
+#define MODP4096_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" \
+ "FFFFFFFF FFFFFFFF"
+
+/* copy&pasted from rfc3526: */
+#define MODP6144_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08" \
+ "8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B" \
+ "302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9" \
+ "A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6" \
+ "49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8" \
+ "FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C" \
+ "180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718" \
+ "3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D" \
+ "04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D" \
+ "B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226" \
+ "1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC" \
+ "E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26" \
+ "99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB" \
+ "04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2" \
+ "233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127" \
+ "D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406" \
+ "AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918" \
+ "DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151" \
+ "2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03" \
+ "F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F" \
+ "BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B" \
+ "B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632" \
+ "387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E" \
+ "6DCC4024 FFFFFFFF FFFFFFFF"
+
+/* copy&pasted from rfc3526: */
+#define MODP8192_MODULUS \
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" \
+ "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" \
+ "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" \
+ "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" \
+ "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" \
+ "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" \
+ "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" \
+ "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" \
+ "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" \
+ "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" \
+ "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" \
+ "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" \
+ "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" \
+ "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" \
+ "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" \
+ "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" \
+ "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" \
+ "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" \
+ "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" \
+ "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" \
+ "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF"
+#define LOCALSECRETSIZE (256 / BITS_PER_BYTE)
+
+/* limits on nonce sizes. See RFC2409 "The internet key exchange (IKE)" 5 */
+#define MINIMUM_NONCE_SIZE 8 /* bytes */
+#define DEFAULT_NONCE_SIZE 16 /* bytes */
+#define MAXIMUM_NONCE_SIZE 256 /* bytes */
+
+#define COOKIE_SIZE 8
+#define MAX_ISAKMP_SPI_SIZE 16
+
+#define MD2_DIGEST_SIZE (128 / BITS_PER_BYTE) /* ought to be supplied by md2.h */
+#define MD5_DIGEST_SIZE (128 / BITS_PER_BYTE) /* ought to be supplied by md5.h */
+#define SHA1_DIGEST_SIZE (160 / BITS_PER_BYTE) /* ought to be supplied by sha1.h */
+
+#define DES_CBC_BLOCK_SIZE (64 / BITS_PER_BYTE)
+
+#define DSS_QBITS 160 /* bits in DSS's "q" (FIPS 186-1) */
+
+/* to statically allocate IV, we need max of
+ * MD5_DIGEST_SIZE, SHA1_DIGEST_SIZE, and DES_CBC_BLOCK_SIZE.
+ * To avoid combinatorial explosion, we leave out DES_CBC_BLOCK_SIZE.
+ */
+#define MAX_DIGEST_LEN_OLD (MD5_DIGEST_SIZE > SHA1_DIGEST_SIZE? MD5_DIGEST_SIZE : SHA1_DIGEST_SIZE)
+
+/* for max: SHA2_512 */
+#define MAX_DIGEST_LEN (512/BITS_PER_BYTE)
+
+/* RFC 2404 "HMAC-SHA-1-96" section 3 */
+#define HMAC_SHA1_KEY_LEN SHA1_DIGEST_SIZE
+
+/* RFC 2403 "HMAC-MD5-96" section 3 */
+#define HMAC_MD5_KEY_LEN MD5_DIGEST_SIZE
+
+#define IKE_UDP_PORT 500
+
+/* RFC 2560 OCSP - certificate status */
+
+typedef enum {
+ CERT_GOOD = 0,
+ CERT_REVOKED = 1,
+ CERT_UNKNOWN = 2,
+ CERT_UNDEFINED = 3
+} cert_status_t;
+
+/* RFC 2459 CRL reason codes */
+
+extern enum_names crl_reason_names;
+
+typedef enum {
+ REASON_UNSPECIFIED = 0,
+ REASON_KEY_COMPROMISE = 1,
+ REASON_CA_COMPROMISE = 2,
+ REASON_AFFILIATION_CHANGED = 3,
+ REASON_SUPERSEDED = 4,
+ REASON_CESSATION_OF_OPERATON = 5,
+ REASON_CERTIFICATE_HOLD = 6,
+ REASON_REMOVE_FROM_CRL = 8
+} crl_reason_t;
+
+/* RFC 3706 Dead Peer Detection */
+
+extern enum_names dpd_action_names;
+
+typedef enum {
+ DPD_ACTION_NONE = 0,
+ DPD_ACTION_CLEAR = 1,
+ DPD_ACTION_HOLD = 2,
+ DPD_ACTION_RESTART = 3,
+ DPD_ACTION_UNKNOWN = 4
+} dpd_action_t;
+
+/* Timer events */
+
+extern enum_names timer_event_names;
+
+enum event_type {
+ EVENT_NULL, /* non-event */
+ EVENT_REINIT_SECRET, /* Refresh cookie secret */
+#ifdef KLIPS
+ EVENT_SHUNT_SCAN, /* scan shunt eroutes known to kernel */
+#endif
+ EVENT_SO_DISCARD, /* discard unfinished state object */
+ EVENT_RETRANSMIT, /* Retransmit packet */
+ EVENT_SA_REPLACE, /* SA replacement event */
+ EVENT_SA_REPLACE_IF_USED, /* SA replacement event */
+ EVENT_SA_EXPIRE, /* SA expiration event */
+ EVENT_NAT_T_KEEPALIVE, /* NAT Traversal Keepalive */
+ EVENT_DPD, /* dead peer detection */
+ EVENT_DPD_TIMEOUT, /* dead peer detection timeout */
+ EVENT_LOG_DAILY /* reset certain log events/stats */
+};
+
+#define EVENT_REINIT_SECRET_DELAY 3600 /* 1 hour */
+#define EVENT_RETRANSMIT_DELAY_0 10 /* 10 seconds */
+
+/* Misc. stuff */
+
+#define MAXIMUM_RETRANSMISSIONS 2
+#define MAXIMUM_RETRANSMISSIONS_INITIAL 20
+
+#define MAX_INPUT_UDP_SIZE 65536
+#define MAX_OUTPUT_UDP_SIZE 65536
+
+/* Version numbers */
+
+#define ISAKMP_MAJOR_VERSION 0x1
+#define ISAKMP_MINOR_VERSION 0x0
+
+extern enum_names version_names;
+
+/* Domain of Interpretation */
+
+extern enum_names doi_names;
+
+#define ISAKMP_DOI_ISAKMP 0
+#define ISAKMP_DOI_IPSEC 1
+
+/* IPsec DOI things */
+
+#define IPSEC_DOI_SITUATION_LENGTH 4
+#define IPSEC_DOI_LDI_LENGTH 4
+#define IPSEC_DOI_SPI_SIZE 4
+
+/* SPI value 0 is invalid and values 1-255 are reserved to IANA.
+ * ESP: RFC 2402 2.4; AH: RFC 2406 2.1
+ * IPComp RFC 2393 substitutes a CPI in the place of an SPI.
+ * see also draft-shacham-ippcp-rfc2393bis-05.txt.
+ * We (FreeS/WAN) reserve 0x100 to 0xFFF for manual keying, so
+ * Pluto won't generate these values.
+ */
+#define IPSEC_DOI_SPI_MIN 0x100
+#define IPSEC_DOI_SPI_OUR_MIN 0x1000
+
+/* debugging settings: a set of selections for reporting
+ * These would be more naturally situated in log.h,
+ * but they are shared with whack.
+ * IMPAIR_* actually change behaviour, usually badly,
+ * to aid in testing. Naturally, these are not included in ALL.
+ *
+ * NOTE: changes here must be done in concert with changes to DBGOPT_*
+ * in whack.c. A change to WHACK_MAGIC in whack.h will be required too.
+ */
+#ifdef DEBUG
+extern const char *const debug_bit_names[];
+#endif
+
+#define DBG_RAW LELEM(0) /* raw packet I/O */
+#define DBG_CRYPT LELEM(1) /* encryption/decryption of messages */
+#define DBG_PARSING LELEM(2) /* show decoding of messages */
+#define DBG_EMITTING LELEM(3) /* show encoding of messages */
+#define DBG_CONTROL LELEM(4) /* control flow within Pluto */
+#define DBG_LIFECYCLE LELEM(5) /* SA lifecycle */
+#define DBG_KLIPS LELEM(6) /* messages to KLIPS */
+#define DBG_DNS LELEM(7) /* DNS activity */
+#define DBG_NATT LELEM(8) /* NAT-T */
+#define DBG_OPPO LELEM(9) /* opportunism */
+#define DBG_CONTROLMORE LELEM(10) /* more detailed debugging */
+
+#define DBG_PRIVATE LELEM(11) /* private information: DANGER! */
+
+#define IMPAIR0 12 /* first bit for IMPAIR_* */
+
+#define IMPAIR_DELAY_ADNS_KEY_ANSWER LELEM(IMPAIR0+0) /* sleep before answering */
+#define IMPAIR_DELAY_ADNS_TXT_ANSWER LELEM(IMPAIR0+1) /* sleep before answering */
+#define IMPAIR_BUST_MI2 LELEM(IMPAIR0+2) /* make MI2 really large */
+#define IMPAIR_BUST_MR2 LELEM(IMPAIR0+3) /* make MI2 really large */
+
+#define DBG_NONE 0 /* no options on, including impairments */
+#define DBG_ALL LRANGES(DBG_RAW, DBG_CONTROLMORE) /* all logging options on EXCEPT DBG_PRIVATE */
+
+/* State of exchanges
+ *
+ * The name of the state describes the last message sent, not the
+ * message currently being input or output (except during retry).
+ * In effect, the state represents the last completed action.
+ *
+ * Messages are named [MQ][IR]n where
+ * - M stands for Main Mode (Phase 1);
+ * Q stands for Quick Mode (Phase 2)
+ * - I stands for Initiator;
+ * R stands for Responder
+ * - n, a digit, stands for the number of the message
+ *
+ * It would be more convenient if each state accepted a message
+ * and produced one. This is the case for states at the start
+ * or end of an exchange. To fix this, we pretend that there are
+ * MR0 and QR0 messages before the MI1 and QR1 messages. Similarly,
+ * we pretend that there are MR4 and QR2 messages.
+ *
+ * STATE_MAIN_R0 and STATE_QUICK_R0 are intermediate states (not
+ * retained between messages) representing the state that accepts the
+ * first message of an exchange has been read but not processed.
+ *
+ * state_microcode state_microcode_table in demux.c describes
+ * other important details.
+ */
+
+extern enum_names state_names;
+extern const char *const state_story[];
+
+enum state_kind {
+ STATE_UNDEFINED, /* 0 -- most likely accident */
+
+ /* Opportunism states: see "Opportunistic Encryption" 2.2 */
+
+ OPPO_ACQUIRE, /* got an ACQUIRE message for this pair */
+ OPPO_GW_DISCOVERED, /* got TXT specifying gateway */
+
+ /* IKE states */
+
+ STATE_MAIN_R0,
+ STATE_MAIN_I1,
+ STATE_MAIN_R1,
+ STATE_MAIN_I2,
+ STATE_MAIN_R2,
+ STATE_MAIN_I3,
+ STATE_MAIN_R3,
+ STATE_MAIN_I4,
+
+ STATE_QUICK_R0,
+ STATE_QUICK_I1,
+ STATE_QUICK_R1,
+ STATE_QUICK_I2,
+ STATE_QUICK_R2,
+
+ STATE_INFO,
+ STATE_INFO_PROTECTED,
+
+ STATE_MODE_CFG_R0, /* these states are used on the responder */
+ STATE_MODE_CFG_R1,
+ STATE_MODE_CFG_R2,
+
+ STATE_MODE_CFG_I1, /* this is used on the initiator */
+ STATE_MODE_CFG_I2,
+
+ STATE_IKE_ROOF
+};
+
+#define STATE_IKE_FLOOR STATE_MAIN_R0
+
+#define PHASE1_INITIATOR_STATES (LELEM(STATE_MAIN_I1) | LELEM(STATE_MAIN_I2) \
+ | LELEM(STATE_MAIN_I3) | LELEM(STATE_MAIN_I4))
+#define ISAKMP_SA_ESTABLISHED_STATES (LELEM(STATE_MAIN_R3) | LELEM(STATE_MAIN_I4) \
+ | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_I2))
+
+#define IS_PHASE1(s) ((STATE_MAIN_R0 <= (s) && (s) <= STATE_MAIN_I4) \
+ || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_I2))
+#define IS_QUICK(s) (STATE_QUICK_R0 <= (s) && (s) <= STATE_QUICK_R2)
+#define IS_ISAKMP_ENCRYPTED(s) (STATE_MAIN_I2 <= (s))
+#define IS_ISAKMP_SA_ESTABLISHED(s) ((s) == STATE_MAIN_R3 \
+ || (s) == STATE_MAIN_I4 \
+ || (s) == STATE_MODE_CFG_R0 \
+ || (s) == STATE_MODE_CFG_R1 \
+ || (s) == STATE_MODE_CFG_I2)
+#define IS_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_I2 || (s) == STATE_QUICK_R2)
+#define IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_R1)
+
+/* kind of struct connection
+ * Ordered (mostly) by concreteness. Order is exploited.
+ */
+
+extern enum_names connection_kind_names;
+
+enum connection_kind {
+ CK_GROUP, /* policy group: instantiates to template */
+ CK_TEMPLATE, /* abstract connection, with wildcard */
+ CK_PERMANENT, /* normal connection */
+ CK_INSTANCE, /* instance of template, created for a particular attempt */
+ CK_GOING_AWAY /* instance being deleted -- don't delete again */
+};
+
+
+/* routing status.
+ * Note: routing ignores source address, but erouting does not!
+ * Note: a connection can only be routed if it is NEVER_NEGOTIATE
+ * or HAS_IPSEC_POLICY.
+ */
+
+extern enum_names routing_story;
+
+/* note that this is assumed to be ordered! */
+enum routing_t {
+ RT_UNROUTED, /* unrouted */
+ RT_UNROUTED_HOLD, /* unrouted, but HOLD shunt installed */
+ RT_ROUTED_ECLIPSED, /* RT_ROUTED_PROSPECTIVE except bare HOLD or instance has eroute */
+ RT_ROUTED_PROSPECTIVE, /* routed, and prospective shunt installed */
+ RT_ROUTED_HOLD, /* routed, and HOLD shunt installed */
+ RT_ROUTED_FAILURE, /* routed, and failure-context shunt installed */
+ RT_ROUTED_TUNNEL, /* routed, and erouted to an IPSEC SA group */
+ RT_UNROUTED_KEYED /* keyed, but not routed, on purpose */
+};
+
+#define routed(rs) ((rs) > RT_UNROUTED_HOLD)
+#define erouted(rs) ((rs) != RT_UNROUTED)
+#define shunt_erouted(rs) (erouted(rs) && (rs) != RT_ROUTED_TUNNEL)
+
+/* Payload types
+ * RFC2408 Internet Security Association and Key Management Protocol (ISAKMP)
+ * section 3.1
+ *
+ * RESERVED 14-127
+ * Private USE 128-255
+ */
+
+extern enum_names payload_names;
+extern const char *const payload_name[];
+
+#define ISAKMP_NEXT_NONE 0 /* No other payload following */
+#define ISAKMP_NEXT_SA 1 /* Security Association */
+#define ISAKMP_NEXT_P 2 /* Proposal */
+#define ISAKMP_NEXT_T 3 /* Transform */
+#define ISAKMP_NEXT_KE 4 /* Key Exchange */
+#define ISAKMP_NEXT_ID 5 /* Identification */
+#define ISAKMP_NEXT_CERT 6 /* Certificate */
+#define ISAKMP_NEXT_CR 7 /* Certificate Request */
+#define ISAKMP_NEXT_HASH 8 /* Hash */
+#define ISAKMP_NEXT_SIG 9 /* Signature */
+#define ISAKMP_NEXT_NONCE 10 /* Nonce */
+#define ISAKMP_NEXT_N 11 /* Notification */
+#define ISAKMP_NEXT_D 12 /* Delete */
+#define ISAKMP_NEXT_VID 13 /* Vendor ID */
+#define ISAKMP_NEXT_ATTR 14 /* Mode config Attribute */
+
+#define ISAKMP_NEXT_NATD_RFC 20 /* NAT-Traversal: NAT-D (rfc) */
+#define ISAKMP_NEXT_NATOA_RFC 21 /* NAT-Traversal: NAT-OA (rfc) */
+#define ISAKMP_NEXT_ROOF 22 /* roof on payload types */
+
+#define ISAKMP_NEXT_NATD_DRAFTS 130 /* NAT-Traversal: NAT-D (drafts) */
+#define ISAKMP_NEXT_NATOA_DRAFTS 131 /* NAT-Traversal: NAT-OA (drafts) */
+
+/* These values are to be used within the Type field of an Attribute (14)
+ * ISAKMP payload.
+ */
+#define ISAKMP_CFG_REQUEST 1
+#define ISAKMP_CFG_REPLY 2
+#define ISAKMP_CFG_SET 3
+#define ISAKMP_CFG_ACK 4
+
+extern enum_names attr_msg_type_names;
+
+/* Mode Config attribute values */
+#define INTERNAL_IP4_ADDRESS 1
+#define INTERNAL_IP4_NETMASK 2
+#define INTERNAL_IP4_DNS 3
+#define INTERNAL_IP4_NBNS 4
+#define INTERNAL_ADDRESS_EXPIRY 5
+#define INTERNAL_IP4_DHCP 6
+#define APPLICATION_VERSION 7
+#define INTERNAL_IP6_ADDRESS 8
+#define INTERNAL_IP6_NETMASK 9
+#define INTERNAL_IP6_DNS 10
+#define INTERNAL_IP6_NBNS 11
+#define INTERNAL_IP6_DHCP 12
+#define INTERNAL_IP4_SUBNET 13
+#define SUPPORTED_ATTRIBUTES 14
+#define INTERNAL_IP6_SUBNET 15
+
+extern enum_names modecfg_attr_names;
+
+/* Exchange types
+ * RFC2408 "Internet Security Association and Key Management Protocol (ISAKMP)"
+ * section 3.1
+ *
+ * ISAKMP Future Use 6 - 31
+ * DOI Specific Use 32 - 239
+ * Private Use 240 - 255
+ *
+ * Note: draft-ietf-ipsec-dhless-enc-mode-00.txt Appendix A
+ * defines "DHless RSA Encryption" as 6.
+ */
+
+extern enum_names exchange_names;
+
+#define ISAKMP_XCHG_NONE 0
+#define ISAKMP_XCHG_BASE 1
+#define ISAKMP_XCHG_IDPROT 2 /* ID Protection */
+#define ISAKMP_XCHG_AO 3 /* Authentication Only */
+#define ISAKMP_XCHG_AGGR 4 /* Aggressive */
+#define ISAKMP_XCHG_INFO 5 /* Informational */
+#define ISAKMP_XCHG_MODE_CFG 6 /* Mode Config */
+
+/* Extra exchange types, defined by Oakley
+ * RFC2409 "The Internet Key Exchange (IKE)", near end of Appendix A
+ */
+#define ISAKMP_XCHG_QUICK 32 /* Oakley Quick Mode */
+#define ISAKMP_XCHG_NGRP 33 /* Oakley New Group Mode */
+/* added in draft-ietf-ipsec-ike-01.txt, near end of Appendix A */
+#define ISAKMP_XCHG_ACK_INFO 34 /* Oakley Acknowledged Informational */
+
+/* Flag bits */
+
+extern const char *const flag_bit_names[];
+
+#define ISAKMP_FLAG_ENCRYPTION 0x1
+#define ISAKMP_FLAG_COMMIT 0x2
+
+/* Situation definition for IPsec DOI */
+
+extern const char *const sit_bit_names[];
+
+#define SIT_IDENTITY_ONLY 0x01
+#define SIT_SECRECY 0x02
+#define SIT_INTEGRITY 0x04
+
+/* Protocol IDs
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.1
+ */
+
+extern enum_names protocol_names;
+
+#define PROTO_ISAKMP 1
+#define PROTO_IPSEC_AH 2
+#define PROTO_IPSEC_ESP 3
+#define PROTO_IPCOMP 4
+
+/* warning: trans_show uses enum_show, so same static buffer is used */
+#define trans_show(p, t) \
+ ((p)==PROTO_IPSEC_AH ? enum_show(&ah_transformid_names, (t)) \
+ : (p)==PROTO_IPSEC_ESP ? enum_show(&esp_transformid_names, (t)) \
+ : (p)==PROTO_IPCOMP ? enum_show(&ipcomp_transformid_names, (t)) \
+ : "??")
+
+/* many transform values are moved to freeswan/ipsec_policy.h */
+
+extern enum_names isakmp_transformid_names;
+
+#define KEY_IKE 1
+
+extern enum_names ah_transformid_names;
+extern enum_names esp_transformid_names;
+extern enum_names ipcomp_transformid_names;
+
+/* the following are from RFC 2393/draft-shacham-ippcp-rfc2393bis-05.txt 3.3 */
+typedef u_int16_t cpi_t;
+#define IPCOMP_CPI_SIZE 2
+#define IPCOMP_FIRST_NEGOTIATED 256
+#define IPCOMP_LAST_NEGOTIATED 61439
+
+/* Identification type values
+ * RFC 2407 The Internet IP security Domain of Interpretation for ISAKMP 4.6.2.1
+ */
+
+extern enum_names ident_names;
+extern enum_names cert_type_names;
+extern enum_names cert_policy_names;
+
+typedef enum certpolicy {
+ CERT_ALWAYS_SEND = 0, /* the default */
+ CERT_SEND_IF_ASKED = 1,
+ CERT_NEVER_SEND = 2,
+
+ CERT_YES_SEND = 3, /* synonym for CERT_ALWAYS_SEND */
+ CERT_NO_SEND = 4 /* synonym for CERT_NEVER_SEND */
+} certpolicy_t;
+
+/* Policies for establishing an SA
+ *
+ * These are used to specify attributes (eg. encryption) and techniques
+ * (eg PFS) for an SA.
+ * Note: certain CD_ definitions in whack.c parallel these -- keep them
+ * in sync!
+ */
+
+extern const char *const sa_policy_bit_names[];
+extern const char *prettypolicy(lset_t policy);
+
+/* ISAKMP auth techniques (none means never negotiate) */
+#define POLICY_PSK LELEM(0)
+#define POLICY_RSASIG LELEM(1)
+
+#define POLICY_ISAKMP_SHIFT 0 /* log2(POLICY_PSK) */
+#define POLICY_ID_AUTH_MASK LRANGES(POLICY_PSK, POLICY_RSASIG)
+#define POLICY_ISAKMP_MASK POLICY_ID_AUTH_MASK /* all so far */
+
+/* Quick Mode (IPSEC) attributes */
+#define POLICY_ENCRYPT LELEM(2) /* must be first of IPSEC policies */
+#define POLICY_AUTHENTICATE LELEM(3) /* must be second */
+#define POLICY_COMPRESS LELEM(4) /* must be third */
+#define POLICY_TUNNEL LELEM(5)
+#define POLICY_PFS LELEM(6)
+#define POLICY_DISABLEARRIVALCHECK LELEM(7) /* supress tunnel egress address checking */
+
+#define POLICY_IPSEC_SHIFT 2 /* log2(POLICY_ENCRYPT) */
+#define POLICY_IPSEC_MASK LRANGES(POLICY_ENCRYPT, POLICY_DISABLEARRIVALCHECK)
+
+/* shunt attributes: what to do when routed without tunnel (2 bits) */
+#define POLICY_SHUNT_SHIFT 8 /* log2(POLICY_SHUNT_PASS) */
+#define POLICY_SHUNT_MASK (03ul << POLICY_SHUNT_SHIFT)
+
+#define POLICY_SHUNT_TRAP (0ul << POLICY_SHUNT_SHIFT) /* default: negotiate */
+#define POLICY_SHUNT_PASS (1ul << POLICY_SHUNT_SHIFT)
+#define POLICY_SHUNT_DROP (2ul << POLICY_SHUNT_SHIFT)
+#define POLICY_SHUNT_REJECT (3ul << POLICY_SHUNT_SHIFT)
+
+/* fail attributes: what to do with failed negotiation (2 bits) */
+
+#define POLICY_FAIL_SHIFT 10 /* log2(POLICY_FAIL_PASS) */
+#define POLICY_FAIL_MASK (03ul << POLICY_FAIL_SHIFT)
+
+#define POLICY_FAIL_NONE (0ul << POLICY_FAIL_SHIFT) /* default */
+#define POLICY_FAIL_PASS (1ul << POLICY_FAIL_SHIFT)
+#define POLICY_FAIL_DROP (2ul << POLICY_FAIL_SHIFT)
+#define POLICY_FAIL_REJECT (3ul << POLICY_FAIL_SHIFT)
+
+/* connection policy
+ * Other policies could vary per state object. These live in connection.
+ */
+#define POLICY_DONT_REKEY LELEM(12) /* don't rekey state either Phase */
+#define POLICY_OPPO LELEM(13) /* is this opportunistic? */
+#define POLICY_GROUP LELEM(14) /* is this a group template? */
+#define POLICY_GROUTED LELEM(15) /* do we want this group routed? */
+#define POLICY_UP LELEM(16) /* do we want this up? */
+
+
+/* Any IPsec policy? If not, a connection description
+ * is only for ISAKMP SA, not IPSEC SA. (A pun, I admit.)
+ * Note: a connection can only be routed if it is NEVER_NEGOTIATE
+ * or HAS_IPSEC_POLICY.
+ */
+#define HAS_IPSEC_POLICY(p) (((p) & POLICY_IPSEC_MASK) != 0)
+
+/* Don't allow negotiation? */
+#define NEVER_NEGOTIATE(p) (LDISJOINT((p), POLICY_PSK | POLICY_RSASIG))
+
+
+/* Oakley transform attributes
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ */
+
+extern enum_names oakley_attr_names;
+extern const char *const oakley_attr_bit_names[];
+
+#define OAKLEY_ENCRYPTION_ALGORITHM 1
+#define OAKLEY_HASH_ALGORITHM 2
+#define OAKLEY_AUTHENTICATION_METHOD 3
+#define OAKLEY_GROUP_DESCRIPTION 4
+#define OAKLEY_GROUP_TYPE 5
+#define OAKLEY_GROUP_PRIME 6 /* B/V */
+#define OAKLEY_GROUP_GENERATOR_ONE 7 /* B/V */
+#define OAKLEY_GROUP_GENERATOR_TWO 8 /* B/V */
+#define OAKLEY_GROUP_CURVE_A 9 /* B/V */
+#define OAKLEY_GROUP_CURVE_B 10 /* B/V */
+#define OAKLEY_LIFE_TYPE 11
+#define OAKLEY_LIFE_DURATION 12 /* B/V */
+#define OAKLEY_PRF 13
+#define OAKLEY_KEY_LENGTH 14
+#define OAKLEY_FIELD_SIZE 15
+#define OAKLEY_GROUP_ORDER 16 /* B/V */
+#define OAKLEY_BLOCK_SIZE 17
+
+/* for each Oakley attribute, which enum_names describes its values? */
+extern enum_names *oakley_attr_val_descs[];
+
+/* IPsec DOI attributes
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5
+ */
+
+extern enum_names ipsec_attr_names;
+
+#define SA_LIFE_TYPE 1
+#define SA_LIFE_DURATION 2 /* B/V */
+#define GROUP_DESCRIPTION 3
+#define ENCAPSULATION_MODE 4
+#define AUTH_ALGORITHM 5
+#define KEY_LENGTH 6
+#define KEY_ROUNDS 7
+#define COMPRESS_DICT_SIZE 8
+#define COMPRESS_PRIVATE_ALG 9 /* B/V */
+
+/* for each IPsec attribute, which enum_names describes its values? */
+extern enum_names *ipsec_attr_val_descs[];
+
+/* SA Lifetime Type attribute
+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5
+ * Default time specified in 4.5
+ *
+ * There are two defaults for IPSEC SA lifetime, SA_LIFE_DURATION_DEFAULT,
+ * and PLUTO_SA_LIFE_DURATION_DEFAULT.
+ * SA_LIFE_DURATION_DEFAULT is specified in RFC2407 "The Internet IP
+ * Security Domain of Interpretation for ISAKMP" 4.5. It applies when
+ * an ISAKMP negotiation does not explicitly specify a life duration.
+ * PLUTO_SA_LIFE_DURATION_DEFAULT is specified in pluto(8). It applies
+ * when a connection description does not specify --ipseclifetime.
+ * The value of SA_LIFE_DURATION_MAXIMUM is our local policy.
+ */
+
+extern enum_names sa_lifetime_names;
+
+#define SA_LIFE_TYPE_SECONDS 1
+#define SA_LIFE_TYPE_KBYTES 2
+
+#define SA_LIFE_DURATION_DEFAULT 28800 /* eight hours (RFC2407 4.5) */
+#define PLUTO_SA_LIFE_DURATION_DEFAULT 3600 /* one hour (pluto(8)) */
+#define SA_LIFE_DURATION_MAXIMUM 86400 /* one day */
+
+#define SA_REPLACEMENT_MARGIN_DEFAULT 540 /* (IPSEC & IKE) nine minutes */
+#define SA_REPLACEMENT_FUZZ_DEFAULT 100 /* (IPSEC & IKE) 100% of MARGIN */
+#define SA_REPLACEMENT_RETRIES_DEFAULT 3 /* (IPSEC & IKE) */
+
+#define SA_LIFE_DURATION_K_DEFAULT 0xFFFFFFFFlu
+
+/* Encapsulation Mode attribute */
+
+extern enum_names enc_mode_names;
+
+#define ENCAPSULATION_MODE_UNSPECIFIED 0 /* not legal -- used internally */
+#define ENCAPSULATION_MODE_TUNNEL 1
+#define ENCAPSULATION_MODE_TRANSPORT 2
+
+#define ENCAPSULATION_MODE_UDP_TUNNEL_RFC 3
+#define ENCAPSULATION_MODE_UDP_TRANSPORT_RFC 4
+
+#define ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS 61443
+#define ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS 61444
+
+/* Auth Algorithm attribute */
+
+extern enum_names auth_alg_names, extended_auth_alg_names;
+
+#define AUTH_ALGORITHM_NONE 0 /* our private designation */
+#define AUTH_ALGORITHM_HMAC_MD5 1
+#define AUTH_ALGORITHM_HMAC_SHA1 2
+#define AUTH_ALGORITHM_DES_MAC 3
+#define AUTH_ALGORITHM_KPDK 4
+#define AUTH_ALGORITHM_HMAC_SHA2_256 5
+#define AUTH_ALGORITHM_HMAC_SHA2_384 6
+#define AUTH_ALGORITHM_HMAC_SHA2_512 7
+#define AUTH_ALGORITHM_HMAC_RIPEMD 8
+#define AUTH_ALGORITHM_NULL 251
+
+/* Oakley Lifetime Type attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ * As far as I can see, there is not specification for
+ * OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT. This could lead to interop problems!
+ * For no particular reason, we chose three hours.
+ * The value of OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM is our local policy.
+ */
+extern enum_names oakley_lifetime_names;
+
+#define OAKLEY_LIFE_SECONDS 1
+#define OAKLEY_LIFE_KILOBYTES 2
+
+#define OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT 10800 /* three hours */
+#define OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM 86400 /* one day */
+
+/* Oakley PRF attribute (none defined)
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ */
+extern enum_names oakley_prf_names;
+
+/* HMAC (see rfc2104.txt) */
+
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5C
+#define HMAC_BUFSIZE 64
+
+/* Oakley Encryption Algorithm attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry
+ */
+
+extern enum_names oakley_enc_names;
+
+#define OAKLEY_DES_CBC 1
+#define OAKLEY_IDEA_CBC 2
+#define OAKLEY_BLOWFISH_CBC 3
+#define OAKLEY_RC5_R16_B64_CBC 4
+#define OAKLEY_3DES_CBC 5
+#define OAKLEY_CAST_CBC 6
+#define OAKLEY_AES_CBC 7
+
+#define OAKLEY_MARS_CBC 65001
+#define OAKLEY_RC6_CBC 65002
+#define OAKLEY_ID_65003 65003
+#define OAKLEY_SERPENT_CBC 65004
+#define OAKLEY_TWOFISH_CBC 65005
+
+#define OAKLEY_TWOFISH_CBC_SSH 65289
+
+#define OAKLEY_ENCRYPT_MAX 65535 /* pretty useless :) */
+
+/* Oakley Hash Algorithm attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry
+ */
+
+extern enum_names oakley_hash_names;
+
+#define OAKLEY_MD5 1
+#define OAKLEY_SHA 2
+#define OAKLEY_TIGER 3
+#define OAKLEY_SHA2_256 4
+#define OAKLEY_SHA2_384 5
+#define OAKLEY_SHA2_512 6
+
+#define OAKLEY_HASH_MAX 7
+
+/* Oakley Authentication Method attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ * Goofy Hybrid extensions from draft-ietf-ipsec-isakmp-hybrid-auth-05.txt
+ * Goofy XAUTH extensions from draft-ietf-ipsec-isakmp-xauth-06.txt
+ */
+
+extern enum_names oakley_auth_names;
+
+#define OAKLEY_PRESHARED_KEY 1
+#define OAKLEY_DSS_SIG 2
+#define OAKLEY_RSA_SIG 3
+#define OAKLEY_RSA_ENC 4
+#define OAKLEY_RSA_ENC_REV 5
+#define OAKLEY_ELGAMAL_ENC 6
+#define OAKLEY_ELGAMAL_ENC_REV 7
+
+#define OAKLEY_AUTH_ROOF 8 /* roof on auth values THAT WE SUPPORT */
+
+#define HybridInitRSA 64221
+#define HybridRespRSA 64222
+#define HybridInitDSS 64223
+#define HybridRespDSS 64224
+
+#define XAUTHInitPreShared 65001
+#define XAUTHRespPreShared 65002
+#define XAUTHInitDSS 65003
+#define XAUTHRespDSS 65004
+#define XAUTHInitRSA 65005
+#define XAUTHRespRSA 65006
+#define XAUTHInitRSAEncryption 65007
+#define XAUTHRespRSAEncryption 65008
+#define XAUTHInitRSARevisedEncryption 65009
+#define XAUTHRespRSARevisedEncryption 65010
+
+/* Oakley Group Description attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ */
+extern enum_names oakley_group_names;
+
+#define OAKLEY_GROUP_MODP768 1
+#define OAKLEY_GROUP_MODP1024 2
+#define OAKLEY_GROUP_GP155 3
+#define OAKLEY_GROUP_GP185 4
+#define OAKLEY_GROUP_MODP1536 5
+
+#define OAKLEY_GROUP_MODP2048 14
+#define OAKLEY_GROUP_MODP3072 15
+#define OAKLEY_GROUP_MODP4096 16
+#define OAKLEY_GROUP_MODP6144 17
+#define OAKLEY_GROUP_MODP8192 18
+/* you must also touch: constants.c, crypto.c */
+
+/* Oakley Group Type attribute
+ * draft-ietf-ipsec-ike-01.txt appendix A
+ */
+extern enum_names oakley_group_type_names;
+
+#define OAKLEY_GROUP_TYPE_MODP 1
+#define OAKLEY_GROUP_TYPE_ECP 2
+#define OAKLEY_GROUP_TYPE_EC2N 3
+
+
+/* Notify messages -- error types
+ * See RFC2408 ISAKMP 3.14.1
+ */
+
+extern enum_names notification_names;
+extern enum_names ipsec_notification_names;
+
+typedef enum {
+ NOTHING_WRONG = 0, /* unofficial! */
+
+ INVALID_PAYLOAD_TYPE = 1,
+ DOI_NOT_SUPPORTED = 2,
+ SITUATION_NOT_SUPPORTED = 3,
+ INVALID_COOKIE = 4,
+ INVALID_MAJOR_VERSION = 5,
+ INVALID_MINOR_VERSION = 6,
+ INVALID_EXCHANGE_TYPE = 7,
+ INVALID_FLAGS = 8,
+ INVALID_MESSAGE_ID = 9,
+ INVALID_PROTOCOL_ID = 10,
+ INVALID_SPI = 11,
+ INVALID_TRANSFORM_ID = 12,
+ ATTRIBUTES_NOT_SUPPORTED = 13,
+ NO_PROPOSAL_CHOSEN = 14,
+ BAD_PROPOSAL_SYNTAX = 15,
+ PAYLOAD_MALFORMED = 16,
+ INVALID_KEY_INFORMATION = 17,
+ INVALID_ID_INFORMATION = 18,
+ INVALID_CERT_ENCODING = 19,
+ INVALID_CERTIFICATE = 20,
+ CERT_TYPE_UNSUPPORTED = 21,
+ INVALID_CERT_AUTHORITY = 22,
+ INVALID_HASH_INFORMATION = 23,
+ AUTHENTICATION_FAILED = 24,
+ INVALID_SIGNATURE = 25,
+ ADDRESS_NOTIFICATION = 26,
+ NOTIFY_SA_LIFETIME = 27,
+ CERTIFICATE_UNAVAILABLE = 28,
+ UNSUPPORTED_EXCHANGE_TYPE = 29,
+ UNEQUAL_PAYLOAD_LENGTHS = 30,
+
+ /* ISAKMP status type */
+ CONNECTED = 16384,
+
+ /* IPSEC DOI additions; status types (RFC2407 IPSEC DOI 4.6.3)
+ * These must be sent under the protection of an ISAKMP SA.
+ */
+ IPSEC_RESPONDER_LIFETIME = 24576,
+ IPSEC_REPLAY_STATUS = 24577,
+ IPSEC_INITIAL_CONTACT = 24578,
+
+ /* RFC 3706 DPD */
+ R_U_THERE = 36136,
+ R_U_THERE_ACK = 36137
+
+ } notification_t;
+
+
+/* Public key algorithm number
+ * Same numbering as used in DNSsec
+ * See RFC 2535 DNSsec 3.2 The KEY Algorithm Number Specification.
+ * Also found in BIND 8.2.2 include/isc/dst.h as DST algorithm codes.
+ */
+
+enum pubkey_alg
+{
+ PUBKEY_ALG_RSA = 1,
+ PUBKEY_ALG_DSA = 3,
+};
+
+/* Limits on size of RSA moduli.
+ * The upper bound matches that of DNSsec (see RFC 2537).
+ * The lower bound must be more than 11 octets for certain
+ * the encoding to work, but it must be much larger for any
+ * real security. For now, we require 512 bits.
+ */
+
+#define RSA_MIN_OCTETS_RFC 12
+
+#define RSA_MIN_OCTETS (512 / BITS_PER_BYTE)
+#define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 512 bits"
+
+#define RSA_MAX_OCTETS (8192 / BITS_PER_BYTE)
+#define RSA_MAX_OCTETS_UGH "RSA modulus too large: more than 8192 bits"
+
+/* Note: RFC 2537 encoding adds a few bytes. If you use a small
+ * modulus like 3, the overhead is only 2 bytes
+ */
+#define RSA_MAX_ENCODING_BYTES (RSA_MAX_OCTETS + 2)
+
+/* socket address family info */
+
+struct af_info
+{
+ int af;
+ const char *name;
+ size_t ia_sz;
+ size_t sa_sz;
+ int mask_cnt;
+ u_int8_t id_addr, id_subnet, id_range;
+ const ip_address *any;
+ const ip_subnet *none; /* 0.0.0.0/32 or IPv6 equivalent */
+ const ip_subnet *all; /* 0.0.0.0/0 or IPv6 equivalent */
+};
+
+extern const struct af_info
+ af_inet4_info,
+ af_inet6_info;
+
+extern const struct af_info *aftoinfo(int af);
+
+extern enum_names af_names;
+
+#define subnetisaddr(sn, a) (subnetishost(sn) && addrinsubnet((a), (sn)))
+extern bool subnetisnone(const ip_subnet *sn);
+
+/* BIND enumerated types */
+
+extern enum_names
+ rr_qtype_names,
+ rr_type_names,
+ rr_class_names;
+
+/* How authenticated is info that might have come from DNS?
+ * In order of increasing confidence.
+ */
+enum dns_auth_level {
+ DAL_UNSIGNED, /* AD in response, but no signature: no authentication */
+ DAL_NOTSEC, /* no AD in response: authentication impossible */
+ DAL_SIGNED, /* AD and signature in response: authentic */
+ DAL_LOCAL /* locally provided (pretty good) */
+};
+
+/*
+ * define a macro for use in error messages
+ */
+
+#ifdef USE_KEYRR
+#define RRNAME "TXT or KEY"
+#else
+#define RRNAME "TXT"
+#endif
+
+/* natt traversal types */
+extern const char *const natt_type_bitnames[];
+
+#endif /* _CONSTANTS_H */
diff --git a/programs/pluto/cookie.c b/programs/pluto/cookie.c
new file mode 100644
index 000000000..458120e46
--- /dev/null
+++ b/programs/pluto/cookie.c
@@ -0,0 +1,67 @@
+/* cookie generation/verification routines.
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: cookie.c,v 1.2 2005/08/17 16:38:20 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "sha1.h"
+#include "rnd.h"
+#include "cookie.h"
+
+const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */
+
+/* Generate a cookie.
+ * First argument is true if we're to create an Initiator cookie.
+ * Length SHOULD be a multiple of sizeof(u_int32_t).
+ */
+void
+get_cookie(bool initiator, u_int8_t *cookie, int length, const ip_address *addr)
+{
+ u_char buffer[SHA1_DIGEST_SIZE];
+ SHA1_CTX ctx;
+
+ do {
+ if (initiator)
+ {
+ get_rnd_bytes(cookie, length);
+ }
+ else /* Responder cookie */
+ {
+ /* This looks as good as any way */
+ size_t addr_length;
+ static u_int32_t counter = 0;
+ unsigned char addr_buff[
+ sizeof(union {struct in_addr A; struct in6_addr B;})];
+
+ addr_length = addrbytesof(addr, addr_buff, sizeof(addr_buff));
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, addr_buff, addr_length);
+ SHA1Update(&ctx, secret_of_the_day, sizeof(secret_of_the_day));
+ counter++;
+ SHA1Update(&ctx, (const void *) &counter, sizeof(counter));
+ SHA1Final(buffer, &ctx);
+ memcpy(cookie, buffer, length);
+ }
+ } while (is_zero_cookie(cookie)); /* probably never loops */
+}
diff --git a/programs/pluto/cookie.h b/programs/pluto/cookie.h
new file mode 100644
index 000000000..f5b0e64d1
--- /dev/null
+++ b/programs/pluto/cookie.h
@@ -0,0 +1,24 @@
+/* cookie generation/verification routines.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: cookie.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#include <freeswan.h>
+
+extern const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */
+
+extern void get_cookie(bool initiator, u_int8_t *cookie, int length
+ , const ip_address *addr);
+
+#define is_zero_cookie(cookie) all_zero((cookie), COOKIE_SIZE)
diff --git a/programs/pluto/crl.c b/programs/pluto/crl.c
new file mode 100644
index 000000000..8d4b3bd7b
--- /dev/null
+++ b/programs/pluto/crl.c
@@ -0,0 +1,763 @@
+/* Support of X.509 certificate revocation lists (CRLs)
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: crl.c,v 1.12 2005/12/06 22:49:57 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "asn1.h"
+#include "oid.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certs.h"
+#include "keys.h"
+#include "whack.h"
+#include "fetch.h"
+#include "sha1.h"
+
+/* chained lists of X.509 crls */
+
+static x509crl_t *x509crls = NULL;
+
+/* ASN.1 definition of an X.509 certificate list */
+
+static const asn1Object_t crlObjects[] = {
+ { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "version", ASN1_INTEGER, ASN1_OPT |
+ ASN1_BODY }, /* 2 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
+ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
+ { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
+ { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
+ { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_LOOP }, /* 8 */
+ { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
+ { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
+ { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
+ { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_LOOP }, /* 12 */
+ { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
+ { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
+ { 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 15 */
+ { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
+ { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
+ { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
+ { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
+ { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 23 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
+ { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */
+ };
+
+#define CRL_OBJ_CERTIFICATE_LIST 0
+#define CRL_OBJ_TBS_CERT_LIST 1
+#define CRL_OBJ_VERSION 2
+#define CRL_OBJ_SIG_ALG 4
+#define CRL_OBJ_ISSUER 5
+#define CRL_OBJ_THIS_UPDATE 6
+#define CRL_OBJ_NEXT_UPDATE 7
+#define CRL_OBJ_USER_CERTIFICATE 10
+#define CRL_OBJ_REVOCATION_DATE 11
+#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
+#define CRL_OBJ_CRL_ENTRY_CRITICAL 15
+#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
+#define CRL_OBJ_EXTN_ID 22
+#define CRL_OBJ_CRITICAL 23
+#define CRL_OBJ_EXTN_VALUE 24
+#define CRL_OBJ_ALGORITHM 27
+#define CRL_OBJ_SIGNATURE 28
+#define CRL_OBJ_ROOF 29
+
+
+const x509crl_t empty_x509crl = {
+ NULL , /* *next */
+ UNDEFINED_TIME, /* installed */
+ NULL , /* distributionPoints */
+ { NULL, 0 } , /* certificateList */
+ { NULL, 0 } , /* tbsCertList */
+ 1 , /* version */
+ OID_UNKNOWN , /* sigAlg */
+ { NULL, 0 } , /* issuer */
+ UNDEFINED_TIME, /* thisUpdate */
+ UNDEFINED_TIME, /* nextUpdate */
+ NULL , /* revokedCertificates */
+ /* crlExtensions */
+ /* extension */
+ /* extnID */
+ /* critical */
+ /* extnValue */
+ { NULL, 0 } , /* authKeyID */
+ { NULL, 0 } , /* authKeySerialNumber */
+ OID_UNKNOWN , /* algorithm */
+ { NULL, 0 } /* signature */
+};
+
+/*
+ * get the X.509 CRL with a given issuer
+ */
+static x509crl_t*
+get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid)
+{
+ x509crl_t *crl = x509crls;
+ x509crl_t *prev_crl = NULL;
+
+ while (crl != NULL)
+ {
+ if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL)
+ ? same_keyid(keyid, crl->authKeyID)
+ : (same_dn(crl->issuer, issuer) && same_serial(serial, crl->authKeySerialNumber)))
+ {
+ if (crl != x509crls)
+ {
+ /* bring the CRL up front */
+ prev_crl->next = crl->next;
+ crl->next = x509crls;
+ x509crls = crl;
+ }
+ return crl;
+ }
+ prev_crl = crl;
+ crl = crl->next;
+ }
+ return NULL;
+}
+
+/*
+ * free the dynamic memory used to store revoked certificates
+ */
+static void
+free_revoked_certs(revokedCert_t* revokedCerts)
+{
+ while (revokedCerts != NULL)
+ {
+ revokedCert_t * revokedCert = revokedCerts;
+ revokedCerts = revokedCert->next;
+ pfree(revokedCert);
+ }
+}
+
+/*
+ * free the dynamic memory used to store CRLs
+ */
+void
+free_crl(x509crl_t *crl)
+{
+ free_revoked_certs(crl->revokedCertificates);
+ free_generalNames(crl->distributionPoints, TRUE);
+ pfree(crl->certificateList.ptr);
+ pfree(crl);
+}
+
+static void
+free_first_crl(void)
+{
+ x509crl_t *crl = x509crls;
+
+ x509crls = crl->next;
+ free_crl(crl);
+}
+
+void
+free_crls(void)
+{
+ lock_crl_list("free_crls");
+
+ while (x509crls != NULL)
+ free_first_crl();
+
+ unlock_crl_list("free_crls");
+}
+
+/*
+ * Insert X.509 CRL into chained list
+ */
+bool
+insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl)
+{
+ x509crl_t *crl = alloc_thing(x509crl_t, "x509crl");
+
+ *crl = empty_x509crl;
+
+ if (parse_x509crl(blob, 0, crl))
+ {
+ x509cert_t *issuer_cert;
+ x509crl_t *oldcrl;
+ bool valid_sig;
+ generalName_t *gn;
+
+ /* add distribution point */
+ gn = alloc_thing(generalName_t, "generalName");
+ gn->kind = GN_URI;
+ gn->name = crl_uri;
+ gn->next = crl->distributionPoints;
+ crl->distributionPoints = gn;
+
+ lock_authcert_list("insert_crl");
+ /* get the issuer cacert */
+ issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber,
+ crl->authKeyID, AUTH_CA);
+ if (issuer_cert == NULL)
+ {
+ plog("crl issuer cacert not found");
+ free_crl(crl);
+ unlock_authcert_list("insert_crl");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("crl issuer cacert found")
+ )
+
+ /* check the issuer's signature of the crl */
+ valid_sig = check_signature(crl->tbsCertList, crl->signature
+ , crl->algorithm, crl->algorithm, issuer_cert);
+ unlock_authcert_list("insert_crl");
+
+ if (!valid_sig)
+ {
+ free_crl(crl);
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("crl signature is valid")
+ )
+
+ lock_crl_list("insert_crl");
+ oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber
+ , crl->authKeyID);
+
+ if (oldcrl != NULL)
+ {
+ if (crl->thisUpdate > oldcrl->thisUpdate)
+ {
+ /* keep any known CRL distribution points */
+ add_distribution_points(oldcrl->distributionPoints
+ , &crl->distributionPoints);
+
+ /* now delete the old CRL */
+ free_first_crl();
+ DBG(DBG_CONTROL,
+ DBG_log("thisUpdate is newer - existing crl deleted")
+ )
+ }
+ else
+ {
+ unlock_crl_list("insert_crls");
+ DBG(DBG_CONTROL,
+ DBG_log("thisUpdate is not newer - existing crl not replaced");
+ )
+ free_crl(crl);
+ return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval;
+ }
+ }
+
+ /* insert new CRL */
+ crl->next = x509crls;
+ x509crls = crl;
+
+ unlock_crl_list("insert_crl");
+
+ /* If crl caching is enabled then the crl is saved locally.
+ * Only http or ldap URIs are cached but not local file URIs.
+ * The issuer's subjectKeyID is used as a unique filename
+ */
+ if (cache_crl && strncasecmp(crl_uri.ptr, "file", 4) != 0)
+ {
+ char path[BUF_LEN];
+ char buf[BUF_LEN];
+ char digest_buf[SHA1_DIGEST_SIZE];
+ chunk_t subjectKeyID = { digest_buf, SHA1_DIGEST_SIZE };
+
+ if (issuer_cert->subjectKeyID.ptr == NULL)
+ compute_subjectKeyID(issuer_cert, subjectKeyID);
+ else
+ subjectKeyID = issuer_cert->subjectKeyID;
+
+ datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN);
+ snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf);
+ write_chunk(path, "crl", crl->certificateList, 0022, TRUE);
+ }
+
+ /* is the fetched crl valid? */
+ return crl->nextUpdate - time(NULL) > 2*crl_check_interval;
+ }
+ else
+ {
+ plog(" error in X.509 crl");
+ free_crl(crl);
+ return FALSE;
+ }
+}
+
+/*
+ * Loads CRLs
+ */
+void
+load_crls(void)
+{
+ struct dirent **filelist;
+ u_char buf[BUF_LEN];
+ u_char *save_dir;
+ int n;
+
+ /* change directory to specified path */
+ save_dir = getcwd(buf, BUF_LEN);
+ if (chdir(CRL_PATH))
+ {
+ plog("Could not change to directory '%s'", CRL_PATH);
+ }
+ else
+ {
+ plog("Changing to directory '%s'", CRL_PATH);
+ n = scandir(CRL_PATH, &filelist, file_select, alphasort);
+
+ if (n < 0)
+ plog(" scandir() error");
+ else
+ {
+ while (n--)
+ {
+ bool pgp = FALSE;
+ chunk_t blob = empty_chunk;
+ char *filename = filelist[n]->d_name;
+
+ if (load_coded_file(filename, NULL, "crl", &blob, &pgp))
+ {
+ chunk_t crl_uri;
+
+ crl_uri.len = 7 + sizeof(CRL_PATH) + strlen(filename);
+ crl_uri.ptr = alloc_bytes(crl_uri.len + 1, "crl uri");
+
+ /* build CRL file URI */
+ snprintf(crl_uri.ptr, crl_uri.len + 1, "file://%s/%s"
+ , CRL_PATH, filename);
+
+ insert_crl(blob, crl_uri, FALSE);
+ }
+ free(filelist[n]);
+ }
+ free(filelist);
+ }
+ }
+ /* restore directory path */
+ chdir(save_dir);
+}
+
+/*
+ * Parses a CRL revocation reason code
+ */
+static crl_reason_t
+parse_crl_reasonCode(chunk_t object)
+{
+ crl_reason_t reason = REASON_UNSPECIFIED;
+
+ if (*object.ptr == ASN1_ENUMERATED
+ && asn1_length(&object) == 1)
+ {
+ reason = *object.ptr;
+ }
+
+ DBG(DBG_PARSING,
+ DBG_log(" '%s'", enum_name(&crl_reason_names, reason))
+ )
+ return reason;
+}
+
+/*
+ * Parses an X.509 CRL
+ */
+bool
+parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
+{
+ u_char buf[BUF_LEN];
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t extnID;
+ chunk_t userCertificate;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < CRL_OBJ_ROOF)
+ {
+ if (!extract_object(crlObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ /* those objects which will parsed further need the next higher level */
+ level++;
+
+ switch (objectID) {
+ case CRL_OBJ_CERTIFICATE_LIST:
+ crl->certificateList = object;
+ break;
+ case CRL_OBJ_TBS_CERT_LIST:
+ crl->tbsCertList = object;
+ break;
+ case CRL_OBJ_VERSION:
+ crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
+ DBG(DBG_PARSING,
+ DBG_log(" v%d", crl->version);
+ )
+ break;
+ case CRL_OBJ_SIG_ALG:
+ crl->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case CRL_OBJ_ISSUER:
+ crl->issuer = object;
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case CRL_OBJ_THIS_UPDATE:
+ crl->thisUpdate = parse_time(object, level);
+ break;
+ case CRL_OBJ_NEXT_UPDATE:
+ crl->nextUpdate = parse_time(object, level);
+ break;
+ case CRL_OBJ_USER_CERTIFICATE:
+ userCertificate = object;
+ break;
+ case CRL_OBJ_REVOCATION_DATE:
+ {
+ /* put all the serial numbers and the revocation date in a chained list
+ with revocedCertificates pointing to the first revoked certificate */
+
+ revokedCert_t *revokedCert = alloc_thing(revokedCert_t, "revokedCert");
+ revokedCert->userCertificate = userCertificate;
+ revokedCert->revocationDate = parse_time(object, level);
+ revokedCert->revocationReason = REASON_UNSPECIFIED;
+ revokedCert->next = crl->revokedCertificates;
+ crl->revokedCertificates = revokedCert;
+ }
+ break;
+ case CRL_OBJ_CRL_ENTRY_EXTN_ID:
+ case CRL_OBJ_EXTN_ID:
+ extnID = object;
+ break;
+ case CRL_OBJ_CRL_ENTRY_CRITICAL:
+ case CRL_OBJ_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ break;
+ case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
+ case CRL_OBJ_EXTN_VALUE:
+ {
+ u_int extn_oid = known_oid(extnID);
+
+ if (extn_oid == OID_CRL_REASON_CODE)
+ {
+ crl->revokedCertificates->revocationReason =
+ parse_crl_reasonCode(object);
+ }
+ else if (extn_oid == OID_AUTHORITY_KEY_ID)
+ {
+ parse_authorityKeyIdentifier(object, level
+ , &crl->authKeyID, &crl->authKeySerialNumber);
+ }
+ }
+ break;
+ case CRL_OBJ_ALGORITHM:
+ crl->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case CRL_OBJ_SIGNATURE:
+ crl->signature = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ time(&crl->installed);
+ return TRUE;
+}
+
+/* Checks if the current certificate is revoked. It goes through the
+ * list of revoked certificates of the corresponding crl. Either the
+ * status CERT_GOOD or CERT_REVOKED is returned
+ */
+static cert_status_t
+check_revocation(const x509crl_t *crl, chunk_t serial
+, time_t *revocationDate, crl_reason_t * revocationReason)
+{
+ revokedCert_t *revokedCert = crl->revokedCertificates;
+
+ *revocationDate = UNDEFINED_TIME;
+ *revocationReason = REASON_UNSPECIFIED;
+
+ DBG(DBG_CONTROL,
+ DBG_dump_chunk("serial number:", serial)
+ )
+
+ while(revokedCert != NULL)
+ {
+ /* compare serial numbers */
+ if (revokedCert->userCertificate.len == serial.len &&
+ memcmp(revokedCert->userCertificate.ptr, serial.ptr, serial.len) == 0)
+ {
+ *revocationDate = revokedCert->revocationDate;
+ *revocationReason = revokedCert->revocationReason;
+ return CERT_REVOKED;
+ }
+ revokedCert = revokedCert->next;
+ }
+ return CERT_GOOD;
+}
+
+/*
+ * check if any crls are about to expire
+ */
+void
+check_crls(void)
+{
+ x509crl_t *crl;
+
+ lock_crl_list("check_crls");
+ crl = x509crls;
+
+ while (crl != NULL)
+ {
+ time_t time_left = crl->nextUpdate - time(NULL);
+ u_char buf[BUF_LEN];
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, crl->issuer);
+ DBG_log("issuer: '%s'",buf);
+ if (crl->authKeyID.ptr != NULL)
+ {
+ datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ DBG_log("%ld seconds left", time_left)
+ )
+ if (time_left < 2*crl_check_interval)
+ {
+ fetch_req_t *req = build_crl_fetch_request(crl->issuer
+ , crl->authKeySerialNumber
+ , crl->authKeyID, crl->distributionPoints);
+ add_crl_fetch_request(req);
+ }
+ crl = crl->next;
+ }
+ unlock_crl_list("check_crls");
+}
+
+/*
+ * verify if a cert hasn't been revoked by a crl
+ */
+cert_status_t
+verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate
+, crl_reason_t *revocationReason)
+{
+ x509crl_t *crl;
+
+ ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID);
+
+ generalName_t *crluri = (ca == NULL)? NULL : ca->crluri;
+
+ *revocationDate = UNDEFINED_TIME;
+ *revocationReason = REASON_UNSPECIFIED;
+
+ lock_crl_list("verify_by_crl");
+ crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID);
+
+ if (crl == NULL)
+ {
+ unlock_crl_list("verify_by_crl");
+ plog("crl not found");
+
+ if (cert->crlDistributionPoints != NULL)
+ {
+ fetch_req_t *req = build_crl_fetch_request(cert->issuer
+ , cert->authKeySerialNumber
+ , cert->authKeyID, cert->crlDistributionPoints);
+ add_crl_fetch_request(req);
+ }
+
+ if (crluri != NULL)
+ {
+ fetch_req_t *req = build_crl_fetch_request(cert->issuer
+ , cert->authKeySerialNumber
+ , cert->authKeyID, crluri);
+ add_crl_fetch_request(req);
+ }
+
+ if (cert->crlDistributionPoints != 0 || crluri != NULL)
+ {
+ wake_fetch_thread("verify_by_crl");
+ return CERT_UNKNOWN;
+ }
+ else
+ return CERT_UNDEFINED;
+ }
+ else
+ {
+ x509cert_t *issuer_cert;
+ bool valid;
+
+ DBG(DBG_CONTROL,
+ DBG_log("crl found")
+ )
+
+ add_distribution_points(cert->crlDistributionPoints
+ , &crl->distributionPoints);
+
+ add_distribution_points(crluri
+ , &crl->distributionPoints);
+
+ lock_authcert_list("verify_by_crl");
+
+ issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
+ , crl->authKeyID, AUTH_CA);
+ valid = check_signature(crl->tbsCertList, crl->signature
+ , crl->algorithm, crl->algorithm, issuer_cert);
+
+ unlock_authcert_list("verify_by_crl");
+
+ if (valid)
+ {
+ cert_status_t status;
+
+ DBG(DBG_CONTROL,
+ DBG_log("crl signature is valid")
+ )
+ /* return the expiration date */
+ *until = crl->nextUpdate;
+
+ /* has the certificate been revoked? */
+ status = check_revocation(crl, cert->serialNumber, revocationDate
+ , revocationReason);
+
+ if (*until < time(NULL))
+ {
+ fetch_req_t *req;
+
+ plog("crl update is overdue since %s"
+ , timetoa(until, TRUE));
+
+ /* try to fetch a crl update */
+ req = build_crl_fetch_request(crl->issuer
+ , crl->authKeySerialNumber
+ , crl->authKeyID, crl->distributionPoints);
+ unlock_crl_list("verify_by_crl");
+
+ add_crl_fetch_request(req);
+ wake_fetch_thread("verify_by_crl");
+ }
+ else
+ {
+ unlock_crl_list("verify_by_crl");
+ DBG(DBG_CONTROL,
+ DBG_log("crl is valid")
+ )
+ }
+ return status;
+ }
+ else
+ {
+ unlock_crl_list("verify_by_crl");
+ plog("crl signature is invalid");
+ return CERT_UNKNOWN;
+ }
+ }
+}
+
+/*
+ * list all X.509 crls in the chained list
+ */
+void
+list_crls(bool utc, bool strict)
+{
+ x509crl_t *crl;
+
+ lock_crl_list("list_crls");
+ crl = x509crls;
+
+ if (crl != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 CRLs:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (crl != NULL)
+ {
+ u_char buf[BUF_LEN];
+ u_int revoked = 0;
+ revokedCert_t *revokedCert = crl->revokedCertificates;
+
+ /* count number of revoked certificates in CRL */
+ while (revokedCert != NULL)
+ {
+ revoked++;
+ revokedCert = revokedCert->next;
+ }
+
+ whack_log(RC_COMMENT, "%s, revoked certs: %d",
+ timetoa(&crl->installed, utc), revoked);
+ dntoa(buf, BUF_LEN, crl->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+
+ list_distribution_points(crl->distributionPoints);
+
+ whack_log(RC_COMMENT, " updates: this %s",
+ timetoa(&crl->thisUpdate, utc));
+ whack_log(RC_COMMENT, " next %s %s",
+ timetoa(&crl->nextUpdate, utc),
+ check_expiry(crl->nextUpdate, CRL_WARNING_INTERVAL, strict));
+ if (crl->authKeyID.ptr != NULL)
+ {
+ datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (crl->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+
+ crl = crl->next;
+ }
+ unlock_crl_list("list_crls");
+}
+
diff --git a/programs/pluto/crl.h b/programs/pluto/crl.h
new file mode 100644
index 000000000..9f985b6cd
--- /dev/null
+++ b/programs/pluto/crl.h
@@ -0,0 +1,87 @@
+/* Support of X.509 certificate revocation lists (CRLs)
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: crl.h,v 1.4 2005/07/18 19:36:22 as Exp $
+ */
+
+#include "constants.h"
+
+/* access structure for a revoked serial number */
+
+typedef struct revokedCert revokedCert_t;
+
+struct revokedCert{
+ revokedCert_t *next;
+ chunk_t userCertificate;
+ time_t revocationDate;
+ crl_reason_t revocationReason;
+};
+
+/* storage structure for an X.509 CRL */
+
+typedef struct x509crl x509crl_t;
+
+struct x509crl {
+ x509crl_t *next;
+ time_t installed;
+ generalName_t *distributionPoints;
+ chunk_t certificateList;
+ chunk_t tbsCertList;
+ u_int version;
+ /* signature */
+ int sigAlg;
+ chunk_t issuer;
+ time_t thisUpdate;
+ time_t nextUpdate;
+ revokedCert_t *revokedCertificates;
+ /* v2 extensions */
+ /* crlExtensions */
+ /* extension */
+ /* extnID */
+ /* critical */
+ /* extnValue */
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+
+ /* signatureAlgorithm */
+ int algorithm;
+ chunk_t signature;
+};
+
+/* apply a strict CRL policy
+ * flag set in plutomain.c and used in ipsec_doi.c and rcv_whack.c
+ */
+extern bool strict_crl_policy;
+
+/*
+ * cache the retrieved CRLs by storing them locally as a file
+ */
+extern bool cache_crls;
+
+/*
+ * check periodically for expired crls
+ */
+extern long crl_check_interval;
+
+/* used for initialization */
+extern const x509crl_t empty_x509crl;
+
+extern bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl);
+extern void load_crls(void);
+extern void check_crls(void);
+extern bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl);
+extern cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until
+ , time_t *revocationDate, crl_reason_t *revocationReason);
+extern void list_crls(bool utc, bool strict);
+extern void free_crls(void);
+extern void free_crl(x509crl_t *crl);
diff --git a/programs/pluto/crypto.c b/programs/pluto/crypto.c
new file mode 100644
index 000000000..24939bd04
--- /dev/null
+++ b/programs/pluto/crypto.c
@@ -0,0 +1,261 @@
+/* crypto interfaces
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: crypto.c,v 1.5 2005/12/06 22:51:34 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in <des.h> */
+#include <crypto/des.h>
+
+#include <errno.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "state.h"
+#include "log.h"
+#include "md5.h"
+#include "sha1.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+#include "alg_info.h"
+#include "ike_alg.h"
+
+
+/* moduli and generator. */
+
+static MP_INT
+ modp1024_modulus,
+ modp1536_modulus,
+ modp2048_modulus,
+ modp3072_modulus,
+ modp4096_modulus,
+ modp6144_modulus,
+ modp8192_modulus;
+
+MP_INT groupgenerator; /* MODP group generator (2) */
+
+static void do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc);
+
+static struct encrypt_desc crypto_encryptor_3des =
+{
+ algo_type: IKE_ALG_ENCRYPT,
+ algo_id: OAKLEY_3DES_CBC,
+ algo_next: NULL,
+ enc_ctxsize: sizeof(des_key_schedule) * 3,
+ enc_blocksize: DES_CBC_BLOCK_SIZE,
+ keydeflen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
+ keyminlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
+ keymaxlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
+ do_crypt: do_3des,
+};
+
+static struct hash_desc crypto_hasher_md5 =
+{
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_MD5,
+ algo_next: NULL,
+ hash_ctx_size: sizeof(MD5_CTX),
+ hash_digest_size: MD5_DIGEST_SIZE,
+ hash_init: (void (*)(void *)) MD5Init,
+ hash_update: (void (*)(void *, const u_int8_t *, size_t)) MD5Update,
+ hash_final: (void (*)(u_char *, void *)) MD5Final,
+};
+
+static struct hash_desc crypto_hasher_sha1 =
+{
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_SHA,
+ algo_next: NULL,
+ hash_ctx_size: sizeof(SHA1_CTX),
+ hash_digest_size: SHA1_DIGEST_SIZE,
+ hash_init: (void (*)(void *)) SHA1Init,
+ hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
+ hash_final: (void (*)(u_char *, void *)) SHA1Final,
+};
+
+void
+init_crypto(void)
+{
+ if (mpz_init_set_str(&groupgenerator, MODP_GENERATOR, 10) != 0
+ || mpz_init_set_str(&modp1024_modulus, MODP1024_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp1536_modulus, MODP1536_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp2048_modulus, MODP2048_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp3072_modulus, MODP3072_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp4096_modulus, MODP4096_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp6144_modulus, MODP6144_MODULUS, 16) != 0
+ || mpz_init_set_str(&modp8192_modulus, MODP8192_MODULUS, 16) != 0)
+ exit_log("mpz_init_set_str() failed in init_crypto()");
+
+ ike_alg_add((struct ike_alg *) &crypto_encryptor_3des);
+ ike_alg_add((struct ike_alg *) &crypto_hasher_sha1);
+ ike_alg_add((struct ike_alg *) &crypto_hasher_md5);
+ ike_alg_init();
+}
+
+/* Oakley group description
+ *
+ * See RFC2409 "The Internet key exchange (IKE)" 6.
+ */
+
+const struct oakley_group_desc unset_group = {0, NULL, 0}; /* magic signifier */
+
+const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE] = {
+# define BYTES(bits) (((bits) + BITS_PER_BYTE - 1) / BITS_PER_BYTE)
+ { OAKLEY_GROUP_MODP1024, &modp1024_modulus, BYTES(1024) },
+ { OAKLEY_GROUP_MODP1536, &modp1536_modulus, BYTES(1536) },
+ { OAKLEY_GROUP_MODP2048, &modp2048_modulus, BYTES(2048) },
+ { OAKLEY_GROUP_MODP3072, &modp3072_modulus, BYTES(3072) },
+ { OAKLEY_GROUP_MODP4096, &modp4096_modulus, BYTES(4096) },
+ { OAKLEY_GROUP_MODP6144, &modp6144_modulus, BYTES(6144) },
+ { OAKLEY_GROUP_MODP8192, &modp8192_modulus, BYTES(8192) },
+# undef BYTES
+};
+
+const struct oakley_group_desc *
+lookup_group(u_int16_t group)
+{
+ int i;
+
+ for (i = 0; i != elemsof(oakley_group); i++)
+ if (group == oakley_group[i].group)
+ return &oakley_group[i];
+ return NULL;
+}
+
+/* Encryption Routines
+ *
+ * Each uses and updates the state object's st_new_iv.
+ * This must already be initialized.
+ */
+
+/* encrypt or decrypt part of an IKE message using DES
+ * See RFC 2409 "IKE" Appendix B
+ */
+static void __attribute__ ((unused))
+do_des(bool enc, void *buf, size_t buf_len, struct state *st)
+{
+ des_key_schedule ks;
+
+ (void) des_set_key((des_cblock *)st->st_enc_key.ptr, ks);
+
+ passert(st->st_new_iv_len >= DES_CBC_BLOCK_SIZE);
+ st->st_new_iv_len = DES_CBC_BLOCK_SIZE; /* truncate */
+
+ des_ncbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len,
+ ks,
+ (des_cblock *)st->st_new_iv, enc);
+}
+
+/* encrypt or decrypt part of an IKE message using 3DES
+ * See RFC 2409 "IKE" Appendix B
+ */
+static void
+do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
+{
+ des_key_schedule ks[3];
+
+ passert (!key_size || (key_size==(DES_CBC_BLOCK_SIZE * 3)))
+ (void) des_set_key((des_cblock *)key + 0, ks[0]);
+ (void) des_set_key((des_cblock *)key + 1, ks[1]);
+ (void) des_set_key((des_cblock *)key + 2, ks[2]);
+
+ des_ede3_cbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len,
+ ks[0], ks[1], ks[2],
+ (des_cblock *)iv, enc);
+}
+
+/* hash and prf routines */
+void
+crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st)
+{
+ passert(st->st_new_iv_len >= e->enc_blocksize);
+ st->st_new_iv_len = e->enc_blocksize; /* truncate */
+
+ e->do_crypt(buf, size, st->st_enc_key.ptr, st->st_enc_key.len, st->st_new_iv, enc);
+ /*
+ e->set_key(&ctx, st->st_enc_key.ptr, st->st_enc_key.len);
+ e->cbc_crypt(&ctx, buf, size, st->st_new_iv, enc);
+ */
+}
+
+/* HMAC package
+ * rfc2104.txt specifies how HMAC works.
+ */
+
+void
+hmac_init(struct hmac_ctx *ctx,
+ const struct hash_desc *h,
+ const u_char *key, size_t key_len)
+{
+ int k;
+
+ ctx->h = h;
+ ctx->hmac_digest_size = h->hash_digest_size;
+
+ /* Prepare the two pads for the HMAC */
+
+ memset(ctx->buf1, '\0', HMAC_BUFSIZE);
+
+ if (key_len <= HMAC_BUFSIZE)
+ {
+ memcpy(ctx->buf1, key, key_len);
+ }
+ else
+ {
+ h->hash_init(&ctx->hash_ctx);
+ h->hash_update(&ctx->hash_ctx, key, key_len);
+ h->hash_final(ctx->buf1, &ctx->hash_ctx);
+ }
+
+ memcpy(ctx->buf2, ctx->buf1, HMAC_BUFSIZE);
+
+ for (k = 0; k < HMAC_BUFSIZE; k++)
+ {
+ ctx->buf1[k] ^= HMAC_IPAD;
+ ctx->buf2[k] ^= HMAC_OPAD;
+ }
+
+ hmac_reinit(ctx);
+}
+
+void
+hmac_reinit(struct hmac_ctx *ctx)
+{
+ ctx->h->hash_init(&ctx->hash_ctx);
+ ctx->h->hash_update(&ctx->hash_ctx, ctx->buf1, HMAC_BUFSIZE);
+}
+
+void
+hmac_update(struct hmac_ctx *ctx,
+ const u_char *data, size_t data_len)
+{
+ ctx->h->hash_update(&ctx->hash_ctx, data, data_len);
+}
+
+void
+hmac_final(u_char *output, struct hmac_ctx *ctx)
+{
+ const struct hash_desc *h = ctx->h;
+
+ h->hash_final(output, &ctx->hash_ctx);
+
+ h->hash_init(&ctx->hash_ctx);
+ h->hash_update(&ctx->hash_ctx, ctx->buf2, HMAC_BUFSIZE);
+ h->hash_update(&ctx->hash_ctx, output, h->hash_digest_size);
+ h->hash_final(output, &ctx->hash_ctx);
+}
diff --git a/programs/pluto/crypto.h b/programs/pluto/crypto.h
new file mode 100644
index 000000000..d29475af2
--- /dev/null
+++ b/programs/pluto/crypto.h
@@ -0,0 +1,107 @@
+/* crypto interfaces
+ * Copyright (C) 1998, 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: crypto.h,v 1.6 2005/04/07 20:13:30 as Exp $
+ */
+
+#include <gmp.h> /* GNU MP library */
+
+#include "libsha2/sha2.h"
+#include "ike_alg.h"
+
+extern void init_crypto(void);
+
+/* Oakley group descriptions */
+
+extern MP_INT groupgenerator; /* MODP group generator (2) */
+
+struct oakley_group_desc {
+ u_int16_t group;
+ MP_INT *modulus;
+ size_t bytes;
+};
+
+extern const struct oakley_group_desc unset_group; /* magic signifier */
+extern const struct oakley_group_desc *lookup_group(u_int16_t group);
+#define OAKLEY_GROUP_SIZE 7
+extern const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE];
+
+/* unification of cryptographic encoding/decoding algorithms
+ * The IV is taken from and returned to st->st_new_iv.
+ * This allows the old IV to be retained.
+ * Use update_iv to commit to the new IV (for example, once a packet has
+ * been validated).
+ */
+
+#define MAX_OAKLEY_KEY_LEN0 (3 * DES_CBC_BLOCK_SIZE)
+#define MAX_OAKLEY_KEY_LEN (256/BITS_PER_BYTE)
+
+struct state; /* forward declaration, dammit */
+
+void crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st);
+
+#define update_iv(st) memcpy((st)->st_iv, (st)->st_new_iv \
+ , (st)->st_iv_len = (st)->st_new_iv_len)
+
+#define set_ph1_iv(st, iv) \
+ passert((st)->st_ph1_iv_len <= sizeof((st)->st_ph1_iv)); \
+ memcpy((st)->st_ph1_iv, (iv), (st)->st_ph1_iv_len);
+
+/* unification of cryptographic hashing mechanisms */
+
+#ifndef NO_HASH_CTX
+union hash_ctx {
+ MD5_CTX ctx_md5;
+ SHA1_CTX ctx_sha1;
+ sha256_context ctx_sha256;
+ sha512_context ctx_sha512;
+ };
+
+/* HMAC package
+ * Note that hmac_ctx can be (and is) copied since there are
+ * no persistent pointers into it.
+ */
+
+struct hmac_ctx {
+ const struct hash_desc *h; /* underlying hash function */
+ size_t hmac_digest_size; /* copy of h->hash_digest_size */
+ union hash_ctx hash_ctx; /* ctx for hash function */
+ u_char buf1[HMAC_BUFSIZE], buf2[HMAC_BUFSIZE];
+ };
+
+extern void hmac_init(
+ struct hmac_ctx *ctx,
+ const struct hash_desc *h,
+ const u_char *key,
+ size_t key_len);
+
+#define hmac_init_chunk(ctx, h, ch) hmac_init((ctx), (h), (ch).ptr, (ch).len)
+
+extern void hmac_reinit(struct hmac_ctx *ctx); /* saves recreating pads */
+
+extern void hmac_update(
+ struct hmac_ctx *ctx,
+ const u_char *data,
+ size_t data_len);
+
+#define hmac_update_chunk(ctx, ch) hmac_update((ctx), (ch).ptr, (ch).len)
+
+extern void hmac_final(u_char *output, struct hmac_ctx *ctx);
+
+#define hmac_final_chunk(ch, name, ctx) { \
+ pfreeany((ch).ptr); \
+ (ch).len = (ctx)->hmac_digest_size; \
+ (ch).ptr = alloc_bytes((ch).len, name); \
+ hmac_final((ch).ptr, (ctx)); \
+ }
+#endif
diff --git a/programs/pluto/db_ops.c b/programs/pluto/db_ops.c
new file mode 100644
index 000000000..bbcd7918f
--- /dev/null
+++ b/programs/pluto/db_ops.c
@@ -0,0 +1,439 @@
+/* Dynamic db (proposal, transforms, attributes) handling.
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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: db_ops.c,v 1.4 2005/04/07 20:13:44 as Exp $
+ */
+
+/*
+ * The stratedy is to have (full contained) struct db_prop in db_context
+ * pointing to ONE dynamically sizable transform vector (trans0).
+ * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0)
+ * in a "serialized" way (attributes storage is used in linear sequence for
+ * subsecuent transforms).
+ *
+ * Resizing for both trans0 and attrs0 is supported:
+ * - For trans0: quite simple, just allocate and copy trans. vector content
+ * also update trans_cur (by offset)
+ * - For attrs0: after allocating and copying attrs, I must rewrite each
+ * trans->attrs present in trans0; to achieve this, calculate
+ * attrs pointer offset (new minus old) and iterate over
+ * each transform "adding" this difference.
+ * also update attrs_cur (by offset)
+ *
+ * db_context structure:
+ * +---------------------+
+ * | prop |
+ * | .protoid |
+ * | .trans | --+
+ * | .trans_cnt | |
+ * +---------------------+ <-+
+ * | trans0 | ----> { trans#1 | ... | trans#i | ... }
+ * +---------------------+ ^
+ * | trans_cur | ----------------------' current transf.
+ * +---------------------+
+ * | attrs0 | ----> { attr#1 | ... | attr#j | ... }
+ * +---------------------+ ^
+ * | attrs_cur | ---------------------' current attr.
+ * +---------------------+
+ * | max_trans,max_attrs | max_trans/attrs: number of elem. of each vector
+ * +---------------------+
+ *
+ * See testing examples at end for interface usage.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <malloc.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "state.h"
+#include "packet.h"
+#include "spdb.h"
+#include "db_ops.h"
+#include "log.h"
+#include "whack.h"
+
+#include <assert.h>
+
+#ifndef NO_PLUTO
+#else
+#define passert(x) assert(x)
+extern int debug; /* eg: spi.c */
+#define DBG(cond, action) { if (debug) { action ; } }
+#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
+#define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
+void * alloc_bytes(size_t size, const char *name) {
+ void *p=malloc(size);
+ if (p == NULL)
+ fprintf(stderr, "unable to malloc %lu bytes for %s",
+ (unsigned long) size, name);
+ memset(p, '\0', size);
+ return p;
+}
+#define pfreeany(ptr) free(ptr)
+
+#endif
+
+#ifdef NOT_YET
+/*
+ * Allocator cache:
+ * Because of the single-threaded nature of pluto/spdb.c,
+ * alloc()/free() is exercised many times with very small
+ * lifetime objects.
+ * Just caching last object (currently it will select the
+ * largest) will avoid this allocation mas^Wperturbations
+ *
+ */
+struct db_ops_alloc_cache {
+ void *ptr;
+ int size;
+};
+#endif
+
+#ifndef NO_DB_OPS_STATS
+/*
+ * stats: do account for allocations
+ * displayed in db_ops_show_status()
+ */
+struct db_ops_stats {
+ int st_curr_cnt; /* current number of allocations */
+ int st_total_cnt; /* total allocations so far */
+ size_t st_maxsz; /* max. size requested */
+};
+#define DB_OPS_ZERO { 0, 0, 0};
+#define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}"
+#define DB_OPS_STATS_STR(name) name "={%d,%d,%d} "
+#define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (int)(st).st_maxsz
+static struct db_ops_stats db_context_st = DB_OPS_ZERO;
+static struct db_ops_stats db_trans_st = DB_OPS_ZERO;
+static struct db_ops_stats db_attrs_st = DB_OPS_ZERO;
+static __inline__ void * alloc_bytes_st (size_t size, const char *str, struct db_ops_stats *st)
+{
+ void *ptr = alloc_bytes(size, str);
+ if (ptr) {
+ st->st_curr_cnt++;
+ st->st_total_cnt++;
+ if (size > st->st_maxsz) st->st_maxsz=size;
+ }
+ return ptr;
+}
+#define ALLOC_BYTES_ST(z,s,st) alloc_bytes_st(z, s, &st);
+#define PFREE_ST(p,st) do { st.st_curr_cnt--; pfree(p); } while (0);
+
+#else
+
+#define ALLOC_BYTES_ST(z,s,n) alloc_bytes(z, s);
+#define PFREE_ST(p,n) pfree(p);
+
+#endif /* NO_DB_OPS_STATS */
+/* Initialize db object
+ * max_trans and max_attrs can be 0, will be dynamically expanded
+ * as a result of "add" operations
+ */
+int
+db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs)
+{
+ int ret=-1;
+
+ ctx->trans0 = NULL;
+ ctx->attrs0 = NULL;
+
+ if (max_trans > 0) { /* quite silly if not */
+ ctx->trans0 = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans,
+ "db_context->trans", db_trans_st);
+ if (!ctx->trans0) goto out;
+ }
+
+ if (max_attrs > 0) { /* quite silly if not */
+ ctx->attrs0 = ALLOC_BYTES_ST (sizeof (struct db_attr) * max_attrs,
+ "db_context->attrs", db_attrs_st);
+ if (!ctx->attrs0) goto out;
+ }
+ ret = 0;
+out:
+ if (ret < 0 && ctx->trans0) {
+ PFREE_ST(ctx->trans0, db_trans_st);
+ ctx->trans0 = NULL;
+ }
+ ctx->max_trans = max_trans;
+ ctx->max_attrs = max_attrs;
+ ctx->trans_cur = ctx->trans0;
+ ctx->attrs_cur = ctx->attrs0;
+ ctx->prop.protoid = protoid;
+ ctx->prop.trans = ctx->trans0;
+ ctx->prop.trans_cnt = 0;
+ return ret;
+}
+
+/* Expand storage for transforms by number delta_trans */
+static int
+db_trans_expand(struct db_context *ctx, int delta_trans)
+{
+ int ret = -1;
+ struct db_trans *new_trans, *old_trans;
+ int max_trans = ctx->max_trans + delta_trans;
+ int offset;
+
+ old_trans = ctx->trans0;
+ new_trans = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans,
+ "db_context->trans (expand)", db_trans_st);
+ if (!new_trans)
+ goto out;
+ memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans));
+
+ /* update trans0 (obviously) */
+ ctx->trans0 = ctx->prop.trans = new_trans;
+ /* update trans_cur (by offset) */
+ offset = (char *)(new_trans) - (char *)(old_trans);
+
+ {
+ char *cctx = (char *)(ctx->trans_cur);
+
+ cctx += offset;
+ ctx->trans_cur = (struct db_trans *)cctx;
+ }
+ /* update elem count */
+ ctx->max_trans = max_trans;
+ PFREE_ST(old_trans, db_trans_st);
+ ret = 0;
+out:
+ return ret;
+}
+/*
+ * Expand storage for attributes by delta_attrs number AND
+ * rewrite trans->attr pointers
+ */
+static int
+db_attrs_expand(struct db_context *ctx, int delta_attrs)
+{
+ int ret = -1;
+ struct db_attr *new_attrs, *old_attrs;
+ struct db_trans *t;
+ int ti;
+ int max_attrs = ctx->max_attrs + delta_attrs;
+ int offset;
+
+ old_attrs = ctx->attrs0;
+ new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs,
+ "db_context->attrs (expand)", db_attrs_st);
+ if (!new_attrs)
+ goto out;
+
+ memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr));
+
+ /* update attrs0 and attrs_cur (obviously) */
+ offset = (char *)(new_attrs) - (char *)(old_attrs);
+
+ {
+ char *actx = (char *)(ctx->attrs0);
+
+ actx += offset;
+ ctx->attrs0 = (struct db_attr *)actx;
+
+ actx = (char *)ctx->attrs_cur;
+ actx += offset;
+ ctx->attrs_cur = (struct db_attr *)actx;
+ }
+
+ /* for each transform, rewrite attrs pointer by offsetting it */
+ for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) {
+ char *actx = (char *)(t->attrs);
+
+ actx += offset;
+ t->attrs = (struct db_attr *)actx;
+ }
+ /* update elem count */
+ ctx->max_attrs = max_attrs;
+ PFREE_ST(old_attrs, db_attrs_st);
+ ret = 0;
+out:
+ return ret;
+}
+/* Allocate a new db object */
+struct db_context *
+db_prop_new(u_int8_t protoid, int max_trans, int max_attrs)
+{
+ struct db_context *ctx;
+ ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), "db_context", db_context_st);
+ if (!ctx) goto out;
+
+ if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) {
+ PFREE_ST(ctx, db_context_st);
+ ctx=NULL;
+ }
+out:
+ return ctx;
+}
+/* Free a db object */
+void
+db_destroy(struct db_context *ctx)
+{
+ if (ctx->trans0) PFREE_ST(ctx->trans0, db_trans_st);
+ if (ctx->attrs0) PFREE_ST(ctx->attrs0, db_attrs_st);
+ PFREE_ST(ctx, db_context_st);
+}
+/* Start a new transform, expand trans0 is needed */
+int
+db_trans_add(struct db_context *ctx, u_int8_t transid)
+{
+ /* skip incrementing current trans pointer the 1st time*/
+ if (ctx->trans_cur && ctx->trans_cur->attr_cnt)
+ ctx->trans_cur++;
+ /*
+ * Strategy: if more space is needed, expand by
+ * <current_size>/2 + 1
+ *
+ * This happens to produce a "reasonable" sequence
+ * after few allocations, eg.:
+ * 0,1,2,4,8,13,20,31,47
+ */
+ if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) {
+ /* XXX:jjo if fails should shout and flag it */
+ if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0)
+ return -1;
+ }
+ ctx->trans_cur->transid = transid;
+ ctx->trans_cur->attrs=ctx->attrs_cur;
+ ctx->trans_cur->attr_cnt = 0;
+ ctx->prop.trans_cnt++;
+ return 0;
+}
+/* Add attr copy to current transform, expanding attrs0 if needed */
+int
+db_attr_add(struct db_context *ctx, const struct db_attr *a)
+{
+ /*
+ * Strategy: if more space is needed, expand by
+ * <current_size>/2 + 1
+ */
+ if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) {
+ /* XXX:jjo if fails should shout and flag it */
+ if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0)
+ return -1;
+ }
+ *ctx->attrs_cur++=*a;
+ ctx->trans_cur->attr_cnt++;
+ return 0;
+}
+/* Add attr copy (by value) to current transform,
+ * expanding attrs0 if needed, just calls db_attr_add().
+ */
+int
+db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val)
+{
+ struct db_attr attr;
+ attr.type = type;
+ attr.val = val;
+ return db_attr_add (ctx, &attr);
+}
+#ifndef NO_DB_OPS_STATS
+int
+db_ops_show_status(void)
+{
+ whack_log(RC_COMMENT, "stats " __FILE__ ": "
+ DB_OPS_STATS_DESC " :"
+ DB_OPS_STATS_STR("context")
+ DB_OPS_STATS_STR("trans")
+ DB_OPS_STATS_STR("attrs"),
+ DB_OPS_STATS_F(db_context_st),
+ DB_OPS_STATS_F(db_trans_st),
+ DB_OPS_STATS_F(db_attrs_st)
+ );
+ return 0;
+}
+#endif /* NO_DB_OPS_STATS */
+/*
+ * From below to end just testing stuff ....
+ */
+#ifdef TEST
+static void db_prop_print(struct db_prop *p)
+{
+ struct db_trans *t;
+ struct db_attr *a;
+ int ti, ai;
+ enum_names *n, *n_at, *n_av;
+ printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid));
+ for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) {
+ switch( t->transid) {
+ case PROTO_ISAKMP:
+ n=&isakmp_transformid_names;break;
+ case PROTO_IPSEC_ESP:
+ n=&esp_transformid_names;break;
+ default:
+ continue;
+ }
+ printf(" transid=\"%s\"\n",
+ enum_name(n, t->transid));
+ for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) {
+ int i;
+ switch( t->transid) {
+ case PROTO_ISAKMP:
+ n_at=&oakley_attr_names;
+ i=a->type|ISAKMP_ATTR_AF_TV;
+ n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
+ break;
+ case PROTO_IPSEC_ESP:
+ n_at=&ipsec_attr_names;
+ i=a->type|ISAKMP_ATTR_AF_TV;
+ n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
+ break;
+ default:
+ continue;
+ }
+ printf(" type=\"%s\" value=\"%s\"\n",
+ enum_name(n_at, i),
+ enum_name(n_av, a->val));
+ }
+ }
+
+}
+static void db_print(struct db_context *ctx)
+{
+ printf("trans_cur diff=%d, attrs_cur diff=%d\n",
+ ctx->trans_cur - ctx->trans0,
+ ctx->attrs_cur - ctx->attrs0);
+ db_prop_print(&ctx->prop);
+}
+
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no);
+void abort(void);
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+ abort(); /* exiting correctly doesn't always work */
+}
+int main(void) {
+ struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0);
+ db_trans_add(ctx, KEY_IKE);
+ db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC);
+ db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
+ db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
+ db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024);
+ db_trans_add(ctx, KEY_IKE);
+ db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC);
+ db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
+ db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
+ db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536);
+ db_trans_add(ctx, ESP_3DES);
+ db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1);
+ db_print(ctx);
+ db_destroy(ctx);
+ return 0;
+}
+#endif
diff --git a/programs/pluto/db_ops.h b/programs/pluto/db_ops.h
new file mode 100644
index 000000000..433e75280
--- /dev/null
+++ b/programs/pluto/db_ops.h
@@ -0,0 +1,56 @@
+/* Dynamic db (proposal, transforms, attributes) handling.
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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: db_ops.h,v 1.3 2004/09/17 12:37:37 as Exp $
+ */
+
+#ifndef _DB_OPS_H
+#define _DB_OPS_H
+
+/*
+ * Main db object, (quite proposal "oriented")
+ */
+#ifndef NO_DB_CONTEXT
+struct db_context {
+ struct db_prop prop; /* proposal buffer (not pointer) */
+ struct db_trans *trans0; /* transf. list, dynamically sized */
+ struct db_trans *trans_cur; /* current transform ptr */
+ struct db_attr *attrs0; /* attr. list, dynamically sized */
+ struct db_attr *attrs_cur; /* current attribute ptr */
+ int max_trans; /* size of trans list */
+ int max_attrs; /* size of attrs list */
+};
+/*
+ * Allocate a new db object
+ */
+struct db_context * db_prop_new(u_int8_t protoid, int max_trans, int max_attrs);
+/* Initialize object for proposal building */
+int db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs);
+/* Free all resourses for this db */
+void db_destroy(struct db_context *ctx);
+
+/* Start a new transform */
+int db_trans_add(struct db_context *ctx, u_int8_t transid);
+/* Add a new attribute by copying db_attr content */
+int db_attr_add(struct db_context *db_ctx, const struct db_attr *attr);
+/* Add a new attribute by value */
+int db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val);
+
+/* Get proposal from db object */
+static __inline__ struct db_prop *db_prop_get(struct db_context *ctx) {
+ return &ctx->prop;
+}
+/* Show stats (allocation, etc) */
+#endif /* NO_DB_CONTEXT */
+int db_ops_show_status(void);
+#endif /* _DB_OPS_H */
diff --git a/programs/pluto/defs.c b/programs/pluto/defs.c
new file mode 100644
index 000000000..16f6a3949
--- /dev/null
+++ b/programs/pluto/defs.c
@@ -0,0 +1,374 @@
+/* misc. universal things
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: defs.c,v 1.9 2006/01/04 21:00:43 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+
+const chunk_t empty_chunk = { NULL, 0 };
+
+bool
+all_zero(const unsigned char *m, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i != len; i++)
+ if (m[i] != '\0')
+ return FALSE;
+ return TRUE;
+}
+
+/* memory allocation
+ *
+ * LEAK_DETECTIVE puts a wrapper around each allocation and maintains
+ * a list of live ones. If a dead one is freed, an assertion MIGHT fail.
+ * If the live list is currupted, that will often be detected.
+ * In the end, report_leaks() is called, and the names of remaining
+ * live allocations are printed. At the moment, it is hoped, not that
+ * the list is empty, but that there will be no surprises.
+ *
+ * Accepted Leaks:
+ * - "struct iface" and "device name" (for "discovered" net interfaces)
+ * - "struct event in event_schedule()" (events not associated with states)
+ * - "Pluto lock name" (one only, needed until end -- why bother?)
+ */
+
+#ifdef LEAK_DETECTIVE
+
+/* this magic number is 3671129837 decimal (623837458 complemented) */
+#define LEAK_MAGIC 0xDAD0FEEDul
+
+union mhdr {
+ struct {
+ const char *name;
+ union mhdr *older, *newer;
+ unsigned long magic;
+ } i; /* info */
+ unsigned long junk; /* force maximal alignment */
+};
+
+static union mhdr *allocs = NULL;
+
+void *alloc_bytes(size_t size, const char *name)
+{
+ union mhdr *p = malloc(sizeof(union mhdr) + size);
+
+ if (p == NULL)
+ exit_log("unable to malloc %lu bytes for %s"
+ , (unsigned long) size, name);
+ p->i.name = name;
+ p->i.older = allocs;
+ if (allocs != NULL)
+ allocs->i.newer = p;
+ allocs = p;
+ p->i.newer = NULL;
+ p->i.magic = LEAK_MAGIC;
+
+ memset(p+1, '\0', size);
+ return p+1;
+}
+
+void *
+clone_bytes(const void *orig, size_t size, const char *name)
+{
+ void *p = alloc_bytes(size, name);
+
+ memcpy(p, orig, size);
+ return p;
+}
+
+void
+pfree(void *ptr)
+{
+ union mhdr *p;
+
+ passert(ptr != NULL);
+ p = ((union mhdr *)ptr) - 1;
+ passert(p->i.magic == LEAK_MAGIC);
+ if (p->i.older != NULL)
+ {
+ passert(p->i.older->i.newer == p);
+ p->i.older->i.newer = p->i.newer;
+ }
+ if (p->i.newer == NULL)
+ {
+ passert(p == allocs);
+ allocs = p->i.older;
+ }
+ else
+ {
+ passert(p->i.newer->i.older == p);
+ p->i.newer->i.older = p->i.older;
+ }
+ p->i.magic = ~LEAK_MAGIC;
+ free(p);
+}
+
+void
+report_leaks(void)
+{
+ union mhdr
+ *p = allocs,
+ *pprev = NULL;
+ unsigned long n = 0;
+
+ while (p != NULL)
+ {
+ passert(p->i.magic == LEAK_MAGIC);
+ passert(pprev == p->i.newer);
+ pprev = p;
+ p = p->i.older;
+ n++;
+ if (p == NULL || pprev->i.name != p->i.name)
+ {
+ if (n != 1)
+ plog("leak: %lu * %s", n, pprev->i.name);
+ else
+ plog("leak: %s", pprev->i.name);
+ n = 0;
+ }
+ }
+}
+
+#else /* !LEAK_DETECTIVE */
+
+void *alloc_bytes(size_t size, const char *name)
+{
+ void *p = malloc(size);
+
+ if (p == NULL)
+ exit_log("unable to malloc %lu bytes for %s"
+ , (unsigned long) size, name);
+ memset(p, '\0', size);
+ return p;
+}
+
+void *clone_bytes(const void *orig, size_t size, const char *name)
+{
+ void *p = malloc(size);
+
+ if (p == NULL)
+ exit_log("unable to malloc %lu bytes for %s"
+ , (unsigned long) size, name);
+ memcpy(p, orig, size);
+ return p;
+}
+#endif /* !LEAK_DETECTIVE */
+
+/* Note that there may be as many as six IDs that are temporary at
+ * one time before unsharing the two ends of a connection. So we need
+ * at least six temporary buffers for DER_ASN1_DN IDs.
+ * We rotate them. Be careful!
+ */
+#define MAX_BUF 10
+
+char*
+temporary_cyclic_buffer(void)
+{
+ static char buf[MAX_BUF][BUF_LEN]; /* MAX_BUF internal buffers */
+ static int counter = 0; /* cyclic counter */
+
+ if (++counter == MAX_BUF) counter = 0; /* next internal buffer */
+ return buf[counter]; /* assign temporary buffer */
+}
+
+/* concatenates two sub paths into a string with a maximum size of BUF_LEN
+ * use for temporary storage only
+ */
+const char*
+concatenate_paths(const char *a, const char *b)
+{
+ char *c;
+
+ if (*b == '/' || *b == '.')
+ return b;
+
+ c = temporary_cyclic_buffer();
+ snprintf(c, BUF_LEN, "%s/%s", a, b);
+ return c;
+}
+
+/* compare two chunks, returns zero if a equals b
+ * negative/positive if a is earlier/later in the alphabet than b
+ */
+bool
+cmp_chunk(chunk_t a, chunk_t b)
+{
+ int cmp_len, len, cmp_value;
+
+ cmp_len = a.len - b.len;
+ len = (cmp_len < 0)? a.len : b.len;
+ cmp_value = memcmp(a.ptr, b.ptr, len);
+
+ return (cmp_value == 0)? cmp_len : cmp_value;
+};
+
+/* moves a chunk to a memory position, chunk is freed afterwards
+ * position pointer is advanced after the insertion point
+ */
+void
+mv_chunk(u_char **pos, chunk_t content)
+{
+ if (content.len > 0)
+ {
+ chunkcpy(*pos, content);
+ freeanychunk(content);
+ }
+}
+
+/*
+ * write the binary contents of a chunk_t to a file
+ */
+bool
+write_chunk(const char *filename, const char *label, chunk_t ch
+, mode_t mask, bool force)
+{
+ mode_t oldmask;
+ FILE *fd;
+
+ if (!force)
+ {
+ fd = fopen(filename, "r");
+ if (fd)
+ {
+ fclose(fd);
+ plog(" %s file '%s' already exists", label, filename);
+ return FALSE;
+ }
+ }
+
+ /* set umask */
+ oldmask = umask(mask);
+
+ fd = fopen(filename, "w");
+
+ if (fd)
+ {
+ fwrite(ch.ptr, sizeof(u_char), ch.len, fd);
+ fclose(fd);
+ plog(" written %s file '%s' (%d bytes)", label, filename, (int)ch.len);
+ umask(oldmask);
+ return TRUE;
+ }
+ else
+ {
+ plog(" could not open %s file '%s' for writing", label, filename);
+ umask(oldmask);
+ return FALSE;
+ }
+}
+
+/* Names of the months */
+
+static const char* months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+
+/*
+ * Display a date either in local or UTC time
+ */
+char*
+timetoa(const time_t *time, bool utc)
+{
+ static char buf[TIMETOA_BUF];
+
+ if (*time == UNDEFINED_TIME)
+ sprintf(buf, "--- -- --:--:--%s----", (utc)?" UTC ":" ");
+ else
+ {
+ struct tm *t = (utc)? gmtime(time) : localtime(time);
+
+ sprintf(buf, "%s %02d %02d:%02d:%02d%s%04d",
+ months[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
+ (utc)?" UTC ":" ", t->tm_year + 1900
+ );
+ }
+ return buf;
+}
+
+/* checks if the expiration date has been reached and
+ * warns during the warning_interval of the imminent
+ * expiry. strict=TRUE declares a fatal error,
+ * strict=FALSE issues a warning upon expiry.
+ */
+const char*
+check_expiry(time_t expiration_date, int warning_interval, bool strict)
+{
+ time_t now;
+ int time_left;
+
+ if (expiration_date == UNDEFINED_TIME)
+ return "ok (expires never)";
+
+ /* determine the current time */
+ time(&now);
+
+ time_left = (expiration_date - now);
+ if (time_left < 0)
+ return strict? "fatal (expired)" : "warning (expired)";
+
+ if (time_left > 86400*warning_interval)
+ return "ok";
+ {
+ static char buf[35]; /* temporary storage */
+ const char* unit = "second";
+
+ if (time_left > 172800)
+ {
+ time_left /= 86400;
+ unit = "day";
+ }
+ else if (time_left > 7200)
+ {
+ time_left /= 3600;
+ unit = "hour";
+ }
+ else if (time_left > 120)
+ {
+ time_left /= 60;
+ unit = "minute";
+ }
+ snprintf(buf, 35, "warning (expires in %d %s%s)", time_left,
+ unit, (time_left == 1)?"":"s");
+ return buf;
+ }
+}
+
+
+/*
+ * Filter eliminating the directory entries '.' and '..'
+ */
+int
+file_select(const struct dirent *entry)
+{
+ return strcmp(entry->d_name, "." ) &&
+ strcmp(entry->d_name, "..");
+}
+
+
diff --git a/programs/pluto/defs.h b/programs/pluto/defs.h
new file mode 100644
index 000000000..7e92ea540
--- /dev/null
+++ b/programs/pluto/defs.h
@@ -0,0 +1,145 @@
+/* misc. universal things
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: defs.h,v 1.10 2006/01/04 21:00:43 as Exp $
+ */
+
+#ifndef _DEFS_H
+#define _DEFS_H
+
+#include <sys/types.h>
+
+#ifdef KLIPS
+# define USED_BY_KLIPS /* ignore */
+#else
+# define USED_BY_KLIPS UNUSED
+#endif
+
+#ifdef DEBUG
+# define USED_BY_DEBUG /* ignore */
+#else
+# define USED_BY_DEBUG UNUSED
+#endif
+
+/* Length of temporary buffers */
+
+#define BUF_LEN 512
+
+/* type of serial number of a state object
+ * Needed in connections.h and state.h; here to simplify dependencies.
+ */
+typedef unsigned long so_serial_t;
+#define SOS_NOBODY 0 /* null serial number */
+#define SOS_FIRST 1 /* first normal serial number */
+
+/* memory allocation */
+
+extern void *alloc_bytes(size_t size, const char *name);
+#define alloc_thing(thing, name) (alloc_bytes(sizeof(thing), (name)))
+
+extern void *clone_bytes(const void *orig, size_t size, const char *name);
+#define clone_thing(orig, name) clone_bytes((const void *)&(orig), sizeof(orig), (name))
+#define clone_str(str, name) \
+ ((str) == NULL? NULL : clone_bytes((str), strlen((str))+1, (name)))
+
+#ifdef LEAK_DETECTIVE
+ extern void pfree(void *ptr);
+ extern void report_leaks(void);
+#else
+# define pfree(ptr) free(ptr) /* ordinary stdc free */
+#endif
+#define pfreeany(p) { if ((p) != NULL) pfree(p); }
+#define replace(p, q) { pfreeany(p); (p) = (q); }
+
+
+/* chunk is a simple pointer-and-size abstraction */
+
+struct chunk {
+ u_char *ptr;
+ size_t len;
+ };
+typedef struct chunk chunk_t;
+
+#define setchunk(ch, addr, size) { (ch).ptr = (addr); (ch).len = (size); }
+#define strchunk(str) { str, sizeof(str) }
+/* NOTE: freeanychunk, unlike pfreeany, NULLs .ptr */
+#define freeanychunk(ch) { pfreeany((ch).ptr); (ch).ptr = NULL; }
+#define clonetochunk(ch, addr, size, name) \
+ { (ch).ptr = clone_bytes((addr), (ch).len = (size), name); }
+#define clonereplacechunk(ch, addr, size, name) \
+ { pfreeany((ch).ptr); clonetochunk(ch, addr, size, name); }
+#define chunkcpy(dst, chunk) \
+ { memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;}
+#define same_chunk(a, b) \
+ (a).len == (b).len && memcmp((a).ptr, (b).ptr, (b).len) == 0
+
+extern char* temporary_cyclic_buffer(void);
+extern const char* concatenate_paths(const char *a, const char *b);
+
+extern const chunk_t empty_chunk;
+
+/* compare two chunks */
+extern bool cmp_chunk(chunk_t a, chunk_t b);
+
+/* move a chunk to a memory position and free it after insertion */
+extern void mv_chunk(u_char **pos, chunk_t content);
+
+/* write the binary contents of a chunk_t to a file */
+extern bool write_chunk(const char *filename, const char *label, chunk_t ch
+ ,mode_t mask, bool force);
+
+/* display a date either in local or UTC time */
+extern char* timetoa(const time_t *time, bool utc);
+
+/* warns a predefined interval before expiry */
+extern const char* check_expiry(time_t expiration_date,
+ int warning_interval, bool strict);
+
+#define MAX_PROMPT_PASS_TRIALS 5
+#define PROMPT_PASS_LEN 64
+
+/* struct used to prompt for a secret passphrase
+ * from a console with file descriptor fd
+ */
+typedef struct {
+ char secret[PROMPT_PASS_LEN+1];
+ bool prompt;
+ int fd;
+} prompt_pass_t;
+
+/* no time defined in time_t */
+#define UNDEFINED_TIME 0
+
+/* size of timetoa string buffer */
+#define TIMETOA_BUF 30
+
+/* filter eliminating the directory entries '.' and '..' */
+typedef struct dirent dirent_t;
+extern int file_select(const dirent_t *entry);
+
+/* cleanly exit Pluto */
+
+extern void exit_pluto(int /*status*/) NEVER_RETURNS;
+
+
+/* zero all bytes */
+#define zero(x) memset((x), '\0', sizeof(*(x)))
+
+/* are all bytes 0? */
+extern bool all_zero(const unsigned char *m, size_t len);
+
+/* pad_up(n, m) is the amount to add to n to make it a multiple of m */
+#define pad_up(n, m) (((m) - 1) - (((n) + (m) - 1) % (m)))
+
+#endif /* _DEFS_H */
diff --git a/programs/pluto/demux.c b/programs/pluto/demux.c
new file mode 100644
index 000000000..2f8fb9a8f
--- /dev/null
+++ b/programs/pluto/demux.c
@@ -0,0 +1,2411 @@
+/* demultiplex incoming IKE messages
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: demux.c,v 1.13 2005/02/18 21:08:59 as Exp $
+ */
+
+/* Ordering Constraints on Payloads
+ *
+ * rfc2409: The Internet Key Exchange (IKE)
+ *
+ * 5 Exchanges:
+ * "The SA payload MUST precede all other payloads in a phase 1 exchange."
+ *
+ * "Except where otherwise noted, there are no requirements for ISAKMP
+ * payloads in any message to be in any particular order."
+ *
+ * 5.3 Phase 1 Authenticated With a Revised Mode of Public Key Encryption:
+ *
+ * "If the HASH payload is sent it MUST be the first payload of the
+ * second message exchange and MUST be followed by the encrypted
+ * nonce. If the HASH payload is not sent, the first payload of the
+ * second message exchange MUST be the encrypted nonce."
+ *
+ * "Save the requirements on the location of the optional HASH payload
+ * and the mandatory nonce payload there are no further payload
+ * requirements. All payloads-- in whatever order-- following the
+ * encrypted nonce MUST be encrypted with Ke_i or Ke_r depending on the
+ * direction."
+ *
+ * 5.5 Phase 2 - Quick Mode
+ *
+ * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP
+ * header and a SA payload MUST immediately follow the HASH."
+ * [NOTE: there may be more than one SA payload, so this is not
+ * totally reasonable. Probably all SAs should be so constrained.]
+ *
+ * "If ISAKMP is acting as a client negotiator on behalf of another
+ * party, the identities of the parties MUST be passed as IDci and
+ * then IDcr."
+ *
+ * "With the exception of the HASH, SA, and the optional ID payloads,
+ * there are no payload ordering restrictions on Quick Mode."
+ */
+
+/* Unfolding of Identity -- a central mystery
+ *
+ * This concerns Phase 1 identities, those of the IKE hosts.
+ * These are the only ones that are authenticated. Phase 2
+ * identities are for IPsec SAs.
+ *
+ * There are three case of interest:
+ *
+ * (1) We initiate, based on a whack command specifying a Connection.
+ * We know the identity of the peer from the Connection.
+ *
+ * (2) (to be implemented) we initiate based on a flow from our client
+ * to some IP address.
+ * We immediately know one of the peer's client IP addresses from
+ * the flow. We must use this to figure out the peer's IP address
+ * and Id. To be solved.
+ *
+ * (3) We respond to an IKE negotiation.
+ * We immediately know the peer's IP address.
+ * We get an ID Payload in Main I2.
+ *
+ * Unfortunately, this is too late for a number of things:
+ * - the ISAKMP SA proposals have already been made (Main I1)
+ * AND one accepted (Main R1)
+ * - the SA includes a specification of the type of ID
+ * authentication so this is negotiated without being told the ID.
+ * - with Preshared Key authentication, Main I2 is encrypted
+ * using the key, so it cannot be decoded to reveal the ID
+ * without knowing (or guessing) which key to use.
+ *
+ * There are three reasonable choices here for the responder:
+ * + assume that the initiator is making wise offers since it
+ * knows the IDs involved. We can balk later (but not gracefully)
+ * when we find the actual initiator ID
+ * + attempt to infer identity by IP address. Again, we can balk
+ * when the true identity is revealed. Actually, it is enough
+ * to infer properties of the identity (eg. SA properties and
+ * PSK, if needed).
+ * + make all properties universal so discrimination based on
+ * identity isn't required. For example, always accept the same
+ * kinds of encryption. Accept Public Key Id authentication
+ * since the Initiator presumably has our public key and thinks
+ * we must have / can find his. This approach is weakest
+ * for preshared key since the actual key must be known to
+ * decrypt the Initiator's ID Payload.
+ * These choices can be blended. For example, a class of Identities
+ * can be inferred, sufficient to select a preshared key but not
+ * sufficient to infer a unique identity.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h> /* only used for belt-and-suspenders select call */
+#include <sys/poll.h> /* only used for forensic poll call */
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/queue.h>
+
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+# include <asm/types.h> /* for __u8, __u32 */
+# include <linux/errqueue.h>
+# include <sys/uio.h> /* struct iovec */
+#endif
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "cookie.h"
+#include "connections.h"
+#include "state.h"
+#include "packet.h"
+#include "md5.h"
+#include "sha1.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+#include "ike_alg.h"
+#include "log.h"
+#include "demux.h" /* needs packet.h */
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "timer.h"
+#include "whack.h" /* requires connections.h */
+#include "server.h"
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+#include "vendor.h"
+#include "modecfg.h"
+
+/* This file does basic header checking and demux of
+ * incoming packets.
+ */
+
+/* forward declarations */
+static bool read_packet(struct msg_digest *md);
+static void process_packet(struct msg_digest **mdp);
+
+/* Reply messages are built in this buffer.
+ * Only one state transition function can be using it at a time
+ * so suspended STFs must save and restore it.
+ * It could be an auto variable of complete_state_transition except for the fact
+ * that when a suspended STF resumes, its reply message buffer
+ * must be at the same location -- there are pointers into it.
+ */
+u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE];
+
+/* state_microcode is a tuple of information parameterizing certain
+ * centralized processing of a packet. For example, it roughly
+ * specifies what payloads are expected in this message.
+ * The microcode is selected primarily based on the state.
+ * In Phase 1, the payload structure often depends on the
+ * authentication technique, so that too plays a part in selecting
+ * the state_microcode to use.
+ */
+
+struct state_microcode {
+ enum state_kind state, next_state;
+ lset_t flags;
+ lset_t req_payloads; /* required payloads (allows just one) */
+ lset_t opt_payloads; /* optional payloads (any mumber) */
+ /* if not ISAKMP_NEXT_NONE, process_packet will emit HDR with this as np */
+ u_int8_t first_out_payload;
+ enum event_type timeout_event;
+ state_transition_fn *processor;
+};
+
+/* State Microcode Flags, in several groups */
+
+/* Oakley Auth values: to which auth values does this entry apply?
+ * Most entries will use SMF_ALL_AUTH because they apply to all.
+ * Note: SMF_ALL_AUTH matches 0 for those circumstances when no auth
+ * has been set.
+ */
+#define SMF_ALL_AUTH LRANGE(0, OAKLEY_AUTH_ROOF-1)
+#define SMF_PSK_AUTH LELEM(OAKLEY_PRESHARED_KEY)
+#define SMF_DS_AUTH (LELEM(OAKLEY_DSS_SIG) | LELEM(OAKLEY_RSA_SIG))
+#define SMF_PKE_AUTH (LELEM(OAKLEY_RSA_ENC) | LELEM(OAKLEY_ELGAMAL_ENC))
+#define SMF_RPKE_AUTH (LELEM(OAKLEY_RSA_ENC_REV) | LELEM(OAKLEY_ELGAMAL_ENC_REV))
+
+/* misc flags */
+
+#define SMF_INITIATOR LELEM(OAKLEY_AUTH_ROOF + 0)
+#define SMF_FIRST_ENCRYPTED_INPUT LELEM(OAKLEY_AUTH_ROOF + 1)
+#define SMF_INPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 2)
+#define SMF_OUTPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 3)
+#define SMF_RETRANSMIT_ON_DUPLICATE LELEM(OAKLEY_AUTH_ROOF + 4)
+
+#define SMF_ENCRYPTED (SMF_INPUT_ENCRYPTED | SMF_OUTPUT_ENCRYPTED)
+
+/* this state generates a reply message */
+#define SMF_REPLY LELEM(OAKLEY_AUTH_ROOF + 5)
+
+/* this state completes P1, so any pending P2 negotiations should start */
+#define SMF_RELEASE_PENDING_P2 LELEM(OAKLEY_AUTH_ROOF + 6)
+
+/* end of flags */
+
+
+static state_transition_fn /* forward declaration */
+ unexpected,
+ informational;
+
+/* state_microcode_table is a table of all state_microcode tuples.
+ * It must be in order of state (the first element).
+ * After initialization, ike_microcode_index[s] points to the
+ * first entry in state_microcode_table for state s.
+ * Remember that each state name in Main or Quick Mode describes
+ * what has happened in the past, not what this message is.
+ */
+
+static const struct state_microcode
+ *ike_microcode_index[STATE_IKE_ROOF - STATE_IKE_FLOOR];
+
+static const struct state_microcode state_microcode_table[] = {
+#define PT(n) ISAKMP_NEXT_##n
+#define P(n) LELEM(PT(n))
+
+ /***** Phase 1 Main Mode *****/
+
+ /* No state for main_outI1: --> HDR, SA */
+
+ /* STATE_MAIN_R0: I1 --> R1
+ * HDR, SA --> HDR, SA
+ */
+ { STATE_MAIN_R0, STATE_MAIN_R1
+ , SMF_ALL_AUTH | SMF_REPLY
+ , P(SA), P(VID) | P(CR), PT(NONE)
+ , EVENT_RETRANSMIT, main_inI1_outR1},
+
+ /* STATE_MAIN_I1: R1 --> I2
+ * HDR, SA --> auth dependent
+ * SMF_PSK_AUTH, SMF_DS_AUTH: --> HDR, KE, Ni
+ * SMF_PKE_AUTH:
+ * --> HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ * SMF_RPKE_AUTH:
+ * --> HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
+ * Note: since we don't know auth at start, we cannot differentiate
+ * microcode entries based on it.
+ */
+ { STATE_MAIN_I1, STATE_MAIN_I2
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_REPLY
+ , P(SA), P(VID) | P(CR), PT(NONE) /* don't know yet */
+ , EVENT_RETRANSMIT, main_inR1_outI2 },
+
+ /* STATE_MAIN_R1: I2 --> R2
+ * SMF_PSK_AUTH, SMF_DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr
+ * SMF_PKE_AUTH: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ * --> HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ * SMF_RPKE_AUTH:
+ * HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
+ * --> HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r
+ */
+ { STATE_MAIN_R1, STATE_MAIN_R2
+ , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY
+#ifdef NAT_TRAVERSAL
+ , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(KE)
+#else
+ , P(KE) | P(NONCE), P(VID) | P(CR), PT(KE)
+#endif
+ , EVENT_RETRANSMIT, main_inI2_outR2 },
+
+ { STATE_MAIN_R1, STATE_UNDEFINED
+ , SMF_PKE_AUTH | SMF_REPLY
+ , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR) | P(HASH), PT(KE)
+ , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+
+ { STATE_MAIN_R1, STATE_UNDEFINED
+ , SMF_RPKE_AUTH | SMF_REPLY
+ , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR) | P(HASH) | P(CERT), PT(NONCE)
+ , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+
+ /* for states from here on, output message must be encrypted */
+
+ /* STATE_MAIN_I2: R2 --> I3
+ * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I
+ * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I
+ * SMF_PKE_AUTH: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ * --> HDR*, HASH_I
+ * SMF_RPKE_AUTH: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r
+ * --> HDR*, HASH_I
+ */
+ { STATE_MAIN_I2, STATE_MAIN_I3
+ , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY
+#ifdef NAT_TRAVERSAL
+ , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(ID)
+#else
+ , P(KE) | P(NONCE), P(VID) | P(CR), PT(ID)
+#endif
+ , EVENT_RETRANSMIT, main_inR2_outI3 },
+
+ { STATE_MAIN_I2, STATE_UNDEFINED
+ , SMF_PKE_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY
+ , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR), PT(HASH)
+ , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+
+ { STATE_MAIN_I2, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY
+ , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR), PT(HASH)
+ , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+
+ /* for states from here on, input message must be encrypted */
+
+ /* STATE_MAIN_R2: I3 --> R3
+ * SMF_PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R
+ * SMF_DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R
+ * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R
+ */
+ { STATE_MAIN_R2, STATE_MAIN_R3
+ , SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
+ | SMF_REPLY | SMF_RELEASE_PENDING_P2
+ , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE)
+ , EVENT_SA_REPLACE, main_inI3_outR3 },
+
+ { STATE_MAIN_R2, STATE_MAIN_R3
+ , SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
+ | SMF_REPLY | SMF_RELEASE_PENDING_P2
+ , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE)
+ , EVENT_SA_REPLACE, main_inI3_outR3 },
+
+ { STATE_MAIN_R2, STATE_UNDEFINED
+ , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
+ | SMF_REPLY | SMF_RELEASE_PENDING_P2
+ , P(HASH), P(VID) | P(CR), PT(NONE)
+ , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ },
+
+ /* STATE_MAIN_I3: R3 --> done
+ * SMF_PSK_AUTH: HDR*, IDr1, HASH_R --> done
+ * SMF_DS_AUTH: HDR*, IDr1, [ CERT, ] SIG_R --> done
+ * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_R --> done
+ * May initiate quick mode by calling quick_outI1
+ */
+ { STATE_MAIN_I3, STATE_MAIN_I4
+ , SMF_PSK_AUTH | SMF_INITIATOR
+ | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE)
+ , EVENT_SA_REPLACE, main_inR3 },
+
+ { STATE_MAIN_I3, STATE_MAIN_I4
+ , SMF_DS_AUTH | SMF_INITIATOR
+ | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE)
+ , EVENT_SA_REPLACE, main_inR3 },
+
+ { STATE_MAIN_I3, STATE_UNDEFINED
+ , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_INITIATOR
+ | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(HASH), P(VID) | P(CR), PT(NONE)
+ , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ },
+
+ /* STATE_MAIN_R3: can only get here due to packet loss */
+ { STATE_MAIN_R3, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE
+ , LEMPTY, LEMPTY
+ , PT(NONE), EVENT_NULL, unexpected },
+
+ /* STATE_MAIN_I4: can only get here due to packet loss */
+ { STATE_MAIN_I4, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY
+ , PT(NONE), EVENT_NULL, unexpected },
+
+
+ /***** Phase 2 Quick Mode *****/
+
+ /* No state for quick_outI1:
+ * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ]
+ */
+
+ /* STATE_QUICK_R0:
+ * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] -->
+ * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ]
+ * Installs inbound IPsec SAs.
+ * Because it may suspend for asynchronous DNS, first_out_payload
+ * is set to NONE to suppress early emission of HDR*.
+ * ??? it is legal to have multiple SAs, but we don't support it yet.
+ */
+ { STATE_QUICK_R0, STATE_QUICK_R1
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY
+#ifdef NAT_TRAVERSAL
+ , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(NONE)
+#else
+ , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID), PT(NONE)
+#endif
+ , EVENT_RETRANSMIT, quick_inI1_outR1 },
+
+ /* STATE_QUICK_I1:
+ * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] -->
+ * HDR*, HASH(3)
+ * Installs inbound and outbound IPsec SAs, routing, etc.
+ * ??? it is legal to have multiple SAs, but we don't support it yet.
+ */
+ { STATE_QUICK_I1, STATE_QUICK_I2
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_REPLY
+#ifdef NAT_TRAVERSAL
+ , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(HASH)
+#else
+ , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID), PT(HASH)
+#endif
+ , EVENT_SA_REPLACE, quick_inR1_outI2 },
+
+ /* STATE_QUICK_R1: HDR*, HASH(3) --> done
+ * Installs outbound IPsec SAs, routing, etc.
+ */
+ { STATE_QUICK_R1, STATE_QUICK_R2
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , P(HASH), LEMPTY, PT(NONE)
+ , EVENT_SA_REPLACE, quick_inI2 },
+
+ /* STATE_QUICK_I2: can only happen due to lost packet */
+ { STATE_QUICK_I2, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+ /* STATE_QUICK_R2: can only happen due to lost packet */
+ { STATE_QUICK_R2, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+
+ /***** informational messages *****/
+
+ /* STATE_INFO: */
+ { STATE_INFO, STATE_UNDEFINED
+ , SMF_ALL_AUTH
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, informational },
+
+ /* STATE_INFO_PROTECTED: */
+ { STATE_INFO_PROTECTED, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , P(HASH), LEMPTY, PT(NONE)
+ , EVENT_NULL, informational },
+
+ /* MODE_CFG_x:
+ * Case R0: Responder -> Initiator
+ * <- Req(addr=0)
+ * Reply(ad=x) ->
+ *
+ * Case R1: Set(addr=x) ->
+ * <- Ack(ok)
+ */
+
+ { STATE_MODE_CFG_R0, STATE_MODE_CFG_R1
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_SA_REPLACE, modecfg_inR0 },
+
+ { STATE_MODE_CFG_R1, STATE_MODE_CFG_R2
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_SA_REPLACE, modecfg_inR1 },
+
+ { STATE_MODE_CFG_R2, STATE_UNDEFINED
+ , SMF_ALL_AUTH | SMF_ENCRYPTED
+ , LEMPTY, LEMPTY, PT(NONE)
+ , EVENT_NULL, unexpected },
+
+ { STATE_MODE_CFG_I1, STATE_MODE_CFG_I2
+ , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+ , P(ATTR) | P(HASH), P(VID), PT(HASH)
+ , EVENT_SA_REPLACE, modecfg_inR1 },
+
+#undef P
+#undef PT
+};
+
+void
+init_demux(void)
+{
+ /* fill ike_microcode_index:
+ * make ike_microcode_index[s] point to first entry in
+ * state_microcode_table for state s (backward scan makes this easier).
+ * Check that table is in order -- catch coding errors.
+ * For what it's worth, this routine is idempotent.
+ */
+ const struct state_microcode *t;
+
+ for (t = &state_microcode_table[elemsof(state_microcode_table) - 1];;)
+ {
+ passert(STATE_IKE_FLOOR <= t->state && t->state < STATE_IKE_ROOF);
+ ike_microcode_index[t->state - STATE_IKE_FLOOR] = t;
+ if (t == state_microcode_table)
+ break;
+ t--;
+ passert(t[0].state <= t[1].state);
+ }
+}
+
+/* Process any message on the MSG_ERRQUEUE
+ *
+ * This information is generated because of the IP_RECVERR socket option.
+ * The API is sparsely documented, and may be LINUX-only, and only on
+ * fairly recent versions at that (hence the conditional compilation).
+ *
+ * - ip(7) describes IP_RECVERR
+ * - recvmsg(2) describes MSG_ERRQUEUE
+ * - readv(2) describes iovec
+ * - cmsg(3) describes how to process auxilliary messages
+ *
+ * ??? we should link this message with one we've sent
+ * so that the diagnostic can refer to that negotiation.
+ *
+ * ??? how long can the messge be?
+ *
+ * ??? poll(2) has a very incomplete description of the POLL* events.
+ * We assume that POLLIN, POLLOUT, and POLLERR are all we need to deal with
+ * and that POLLERR will be on iff there is a MSG_ERRQUEUE message.
+ *
+ * We have to code around a couple of surprises:
+ *
+ * - Select can say that a socket is ready to read from, and
+ * yet a read will hang. It turns out that a message available on the
+ * MSG_ERRQUEUE will cause select to say something is pending, but
+ * a normal read will hang. poll(2) can tell when a MSG_ERRQUEUE
+ * message is pending.
+ *
+ * This is dealt with by calling check_msg_errqueue after select
+ * has indicated that there is something to read, but before the
+ * read is performed. check_msg_errqueue will return TRUE if there
+ * is something left to read.
+ *
+ * - A write to a socket may fail because there is a pending MSG_ERRQUEUE
+ * message, without there being anything wrong with the write. This
+ * makes for confusing diagnostics.
+ *
+ * To avoid this, we call check_msg_errqueue before a write. True,
+ * there is a race condition (a MSG_ERRQUEUE message might arrive
+ * between the check and the write), but we should eliminate many
+ * of the problematic events. To narrow the window, the poll(2)
+ * will await until an event happens (in the case or a write,
+ * POLLOUT; this should be benign for POLLIN).
+ */
+
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+static bool
+check_msg_errqueue(const struct iface *ifp, short interest)
+{
+ struct pollfd pfd;
+
+ pfd.fd = ifp->fd;
+ pfd.events = interest | POLLPRI | POLLOUT;
+
+ while (pfd.revents = 0
+ , poll(&pfd, 1, -1) > 0 && (pfd.revents & POLLERR))
+ {
+ u_int8_t buffer[3000]; /* hope that this is big enough */
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in4;
+ struct sockaddr_in6 sa_in6;
+ } from;
+
+ int from_len = sizeof(from);
+
+ int packet_len;
+
+ struct msghdr emh;
+ struct iovec eiov;
+ union {
+ /* force alignment (not documented as necessary) */
+ struct cmsghdr ecms;
+
+ /* how much space is enough? */
+ unsigned char space[256];
+ } ecms_buf;
+
+ struct cmsghdr *cm;
+ char fromstr[sizeof(" for message to port 65536") + INET6_ADDRSTRLEN];
+ struct state *sender = NULL;
+
+ zero(&from.sa);
+ from_len = sizeof(from);
+
+ emh.msg_name = &from.sa; /* ??? filled in? */
+ emh.msg_namelen = sizeof(from);
+ emh.msg_iov = &eiov;
+ emh.msg_iovlen = 1;
+ emh.msg_control = &ecms_buf;
+ emh.msg_controllen = sizeof(ecms_buf);
+ emh.msg_flags = 0;
+
+ eiov.iov_base = buffer; /* see readv(2) */
+ eiov.iov_len = sizeof(buffer);
+
+ packet_len = recvmsg(ifp->fd, &emh, MSG_ERRQUEUE);
+
+ if (packet_len == -1)
+ {
+ log_errno((e, "recvmsg(,, MSG_ERRQUEUE) on %s failed in comm_handle"
+ , ifp->rname));
+ break;
+ }
+ else if (packet_len == sizeof(buffer))
+ {
+ plog("MSG_ERRQUEUE message longer than %lu bytes; truncated"
+ , (unsigned long) sizeof(buffer));
+ }
+ else
+ {
+ sender = find_sender((size_t) packet_len, buffer);
+ }
+
+ DBG_cond_dump(DBG_ALL, "rejected packet:\n", buffer, packet_len);
+ DBG_cond_dump(DBG_ALL, "control:\n", emh.msg_control, emh.msg_controllen);
+ /* ??? Andi Kleen <ak@suse.de> and misc documentation
+ * suggests that name will have the original destination
+ * of the packet. We seem to see msg_namelen == 0.
+ * Andi says that this is a kernel bug and has fixed it.
+ * Perhaps in 2.2.18/2.4.0.
+ */
+ passert(emh.msg_name == &from.sa);
+ DBG_cond_dump(DBG_ALL, "name:\n", emh.msg_name
+ , emh.msg_namelen);
+
+ fromstr[0] = '\0'; /* usual case :-( */
+ switch (from.sa.sa_family)
+ {
+ char as[INET6_ADDRSTRLEN];
+
+ case AF_INET:
+ if (emh.msg_namelen == sizeof(struct sockaddr_in))
+ snprintf(fromstr, sizeof(fromstr)
+ , " for message to %s port %u"
+ , inet_ntop(from.sa.sa_family
+ , &from.sa_in4.sin_addr, as, sizeof(as))
+ , ntohs(from.sa_in4.sin_port));
+ break;
+ case AF_INET6:
+ if (emh.msg_namelen == sizeof(struct sockaddr_in6))
+ snprintf(fromstr, sizeof(fromstr)
+ , " for message to %s port %u"
+ , inet_ntop(from.sa.sa_family
+ , &from.sa_in6.sin6_addr, as, sizeof(as))
+ , ntohs(from.sa_in6.sin6_port));
+ break;
+ }
+
+ for (cm = CMSG_FIRSTHDR(&emh)
+ ; cm != NULL
+ ; cm = CMSG_NXTHDR(&emh,cm))
+ {
+ if (cm->cmsg_level == SOL_IP
+ && cm->cmsg_type == IP_RECVERR)
+ {
+ /* ip(7) and recvmsg(2) specify:
+ * ee_origin is SO_EE_ORIGIN_ICMP for ICMP
+ * or SO_EE_ORIGIN_LOCAL for locally generated errors.
+ * ee_type and ee_code are from the ICMP header.
+ * ee_info is the discovered MTU for EMSGSIZE errors
+ * ee_data is not used.
+ *
+ * ??? recvmsg(2) says "SOCK_EE_OFFENDER" but
+ * means "SO_EE_OFFENDER". The OFFENDER is really
+ * the router that complained. As such, the port
+ * is meaningless.
+ */
+
+ /* ??? cmsg(3) claims that CMSG_DATA returns
+ * void *, but RFC 2292 and /usr/include/bits/socket.h
+ * say unsigned char *. The manual is being fixed.
+ */
+ struct sock_extended_err *ee = (void *)CMSG_DATA(cm);
+ const char *offstr = "unspecified";
+ char offstrspace[INET6_ADDRSTRLEN];
+ char orname[50];
+
+ if (cm->cmsg_len > CMSG_LEN(sizeof(struct sock_extended_err)))
+ {
+ const struct sockaddr *offender = SO_EE_OFFENDER(ee);
+
+ switch (offender->sa_family)
+ {
+ case AF_INET:
+ offstr = inet_ntop(offender->sa_family
+ , &((const struct sockaddr_in *)offender)->sin_addr
+ , offstrspace, sizeof(offstrspace));
+ break;
+ case AF_INET6:
+ offstr = inet_ntop(offender->sa_family
+ , &((const struct sockaddr_in6 *)offender)->sin6_addr
+ , offstrspace, sizeof(offstrspace));
+ break;
+ default:
+ offstr = "unknown";
+ break;
+ }
+ }
+
+ switch (ee->ee_origin)
+ {
+ case SO_EE_ORIGIN_NONE:
+ snprintf(orname, sizeof(orname), "none");
+ break;
+ case SO_EE_ORIGIN_LOCAL:
+ snprintf(orname, sizeof(orname), "local");
+ break;
+ case SO_EE_ORIGIN_ICMP:
+ snprintf(orname, sizeof(orname)
+ , "ICMP type %d code %d (not authenticated)"
+ , ee->ee_type, ee->ee_code
+ );
+ break;
+ case SO_EE_ORIGIN_ICMP6:
+ snprintf(orname, sizeof(orname)
+ , "ICMP6 type %d code %d (not authenticated)"
+ , ee->ee_type, ee->ee_code
+ );
+ break;
+ default:
+ snprintf(orname, sizeof(orname), "invalid origin %lu"
+ , (unsigned long) ee->ee_origin);
+ break;
+ }
+
+ {
+ struct state *old_state = cur_state;
+
+ cur_state = sender;
+
+ /* note dirty trick to suppress ~ at start of format
+ * if we know what state to blame.
+ */
+#ifdef NAT_TRAVERSAL
+ if ((packet_len == 1) && (buffer[0] = 0xff)
+#ifdef DEBUG
+ && ((cur_debugging & DBG_NATT) == 0)
+#endif
+ ) {
+ /* don't log NAT-T keepalive related errors unless NATT debug is
+ * enabled
+ */
+ }
+ else
+#endif
+ plog((sender != NULL) + "~"
+ "ERROR: asynchronous network error report on %s"
+ "%s"
+ ", complainant %s"
+ ": %s"
+ " [errno %lu, origin %s"
+ /* ", pad %d, info %ld" */
+ /* ", data %ld" */
+ "]"
+ , ifp->rname
+ , fromstr
+ , offstr
+ , strerror(ee->ee_errno)
+ , (unsigned long) ee->ee_errno
+ , orname
+ /* , ee->ee_pad, (unsigned long)ee->ee_info */
+ /* , (unsigned long)ee->ee_data */
+ );
+ cur_state = old_state;
+ }
+ }
+ else
+ {
+ /* .cmsg_len is a kernel_size_t(!), but the value
+ * certainly ought to fit in an unsigned long.
+ */
+ plog("unknown cmsg: level %d, type %d, len %lu"
+ , cm->cmsg_level, cm->cmsg_type
+ , (unsigned long) cm->cmsg_len);
+ }
+ }
+ }
+ return (pfd.revents & interest) != 0;
+}
+#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */
+
+bool
+#ifdef NAT_TRAVERSAL
+_send_packet(struct state *st, const char *where, bool verbose)
+#else
+send_packet(struct state *st, const char *where)
+#endif
+{
+ struct connection *c = st->st_connection;
+ int port_buf;
+ bool err;
+
+#ifdef NAT_TRAVERSAL
+ u_int8_t ike_pkt[MAX_OUTPUT_UDP_SIZE];
+ u_int8_t *ptr;
+ unsigned long len;
+
+ if ((c->interface->ike_float == TRUE) && (st->st_tpacket.len != 1)) {
+ if ((unsigned long) st->st_tpacket.len >
+ (MAX_OUTPUT_UDP_SIZE-sizeof(u_int32_t))) {
+ DBG_log("send_packet(): really too big");
+ return FALSE;
+ }
+ ptr = ike_pkt;
+ /** Add Non-ESP marker **/
+ memset(ike_pkt, 0, sizeof(u_int32_t));
+ memcpy(ike_pkt + sizeof(u_int32_t), st->st_tpacket.ptr,
+ (unsigned long)st->st_tpacket.len);
+ len = (unsigned long) st->st_tpacket.len + sizeof(u_int32_t);
+ }
+ else {
+ ptr = st->st_tpacket.ptr;
+ len = (unsigned long) st->st_tpacket.len;
+ }
+#endif
+
+ DBG(DBG_RAW,
+ {
+ DBG_log("sending %lu bytes for %s through %s to %s:%u:"
+ , (unsigned long) st->st_tpacket.len
+ , where
+ , c->interface->rname
+ , ip_str(&c->spd.that.host_addr)
+ , (unsigned)c->spd.that.host_port);
+ DBG_dump_chunk(NULL, st->st_tpacket);
+ });
+
+ /* XXX: Not very clean. We manipulate the port of the ip_address to
+ * have a port in the sockaddr*, but we retain the original port
+ * and restore it afterwards.
+ */
+
+ port_buf = portof(&c->spd.that.host_addr);
+ setportof(htons(c->spd.that.host_port), &c->spd.that.host_addr);
+
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+ (void) check_msg_errqueue(c->interface, POLLOUT);
+#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */
+
+#ifdef NAT_TRAVERSAL
+ err = sendto(c->interface->fd
+ , ptr, len, 0
+ , sockaddrof(&c->spd.that.host_addr)
+ , sockaddrlenof(&c->spd.that.host_addr)) != (ssize_t)len;
+#else
+ err = sendto(c->interface->fd
+ , st->st_tpacket.ptr, st->st_tpacket.len, 0
+ , sockaddrof(&c->spd.that.host_addr)
+ , sockaddrlenof(&c->spd.that.host_addr)) != (ssize_t)st->st_tpacket.len;
+#endif
+
+ /* restore port */
+ setportof(port_buf, &c->spd.that.host_addr);
+
+ if (err)
+ {
+#ifdef NAT_TRAVERSAL
+ /* do not log NAT-T Keep Alive packets */
+ if (!verbose)
+ return FALSE;
+#endif
+ log_errno((e, "sendto on %s to %s:%u failed in %s"
+ , c->interface->rname
+ , ip_str(&c->spd.that.host_addr)
+ , (unsigned)c->spd.that.host_port
+ , where));
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+static stf_status
+unexpected(struct msg_digest *md)
+{
+ loglog(RC_LOG_SERIOUS, "unexpected message received in state %s"
+ , enum_name(&state_names, md->st->st_state));
+ return STF_IGNORE;
+}
+
+static stf_status
+informational(struct msg_digest *md UNUSED)
+{
+ struct payload_digest *const n_pld = md->chain[ISAKMP_NEXT_N];
+
+ /* If the Notification Payload is not null... */
+ if (n_pld != NULL)
+ {
+ pb_stream *const n_pbs = &n_pld->pbs;
+ struct isakmp_notification *const n = &n_pld->payload.notification;
+ int disp_len;
+ char disp_buf[200];
+
+ /* Switch on Notification Type (enum) */
+ switch (n->isan_type)
+ {
+ case R_U_THERE:
+ return dpd_inI_outR(md->st, n, n_pbs);
+
+ case R_U_THERE_ACK:
+ return dpd_inR(md->st, n, n_pbs);
+ default:
+ if (pbs_left(n_pbs) >= sizeof(disp_buf)-1)
+ disp_len = sizeof(disp_buf)-1;
+ else
+ disp_len = pbs_left(n_pbs);
+ memcpy(disp_buf, n_pbs->cur, disp_len);
+ disp_buf[disp_len] = '\0';
+ break;
+ }
+ }
+ return STF_IGNORE;
+}
+
+/* message digest allocation and deallocation */
+
+static struct msg_digest *md_pool = NULL;
+
+/* free_md_pool is only used to avoid leak reports */
+void
+free_md_pool(void)
+{
+ for (;;)
+ {
+ struct msg_digest *md = md_pool;
+
+ if (md == NULL)
+ break;
+ md_pool = md->next;
+ pfree(md);
+ }
+}
+
+static struct msg_digest *
+alloc_md(void)
+{
+ struct msg_digest *md = md_pool;
+
+ /* convenient initializer:
+ * - all pointers NULL
+ * - .note = NOTHING_WRONG
+ * - .encrypted = FALSE
+ */
+ static const struct msg_digest blank_md;
+
+ if (md == NULL)
+ md = alloc_thing(struct msg_digest, "msg_digest");
+ else
+ md_pool = md->next;
+
+ *md = blank_md;
+ md->digest_roof = md->digest;
+
+ /* note: although there may be multiple msg_digests at once
+ * (due to suspended state transitions), there is a single
+ * global reply_buffer. It will need to be saved and restored.
+ */
+ init_pbs(&md->reply, reply_buffer, sizeof(reply_buffer), "reply packet");
+
+ return md;
+}
+
+void
+release_md(struct msg_digest *md)
+{
+ freeanychunk(md->raw_packet);
+ pfreeany(md->packet_pbs.start);
+ md->packet_pbs.start = NULL;
+ md->next = md_pool;
+ md_pool = md;
+}
+
+/* wrapper for read_packet and process_packet
+ *
+ * The main purpose of this wrapper is to factor out teardown code
+ * from the many return points in process_packet. This amounts to
+ * releasing the msg_digest and resetting global variables.
+ *
+ * When processing of a packet is suspended (STF_SUSPEND),
+ * process_packet sets md to NULL to prevent the msg_digest being freed.
+ * Someone else must ensure that msg_digest is freed eventually.
+ *
+ * read_packet is broken out to minimize the lifetime of the
+ * enormous input packet buffer, an auto.
+ */
+void
+comm_handle(const struct iface *ifp)
+{
+ static struct msg_digest *md;
+
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+ /* Even though select(2) says that there is a message,
+ * it might only be a MSG_ERRQUEUE message. At least
+ * sometimes that leads to a hanging recvfrom. To avoid
+ * what appears to be a kernel bug, check_msg_errqueue
+ * uses poll(2) and tells us if there is anything for us
+ * to read.
+ *
+ * This is early enough that teardown isn't required:
+ * just return on failure.
+ */
+ if (!check_msg_errqueue(ifp, POLLIN))
+ return; /* no normal message to read */
+#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */
+
+ md = alloc_md();
+ md->iface = ifp;
+
+ if (read_packet(md))
+ process_packet(&md);
+
+ if (md != NULL)
+ release_md(md);
+
+ cur_state = NULL;
+ reset_cur_connection();
+ cur_from = NULL;
+}
+
+/* read the message.
+ * Since we don't know its size, we read it into
+ * an overly large buffer and then copy it to a
+ * new, properly sized buffer.
+ */
+static bool
+read_packet(struct msg_digest *md)
+{
+ const struct iface *ifp = md->iface;
+ int packet_len;
+ u_int8_t *buffer;
+ u_int8_t *buffer_nat;
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in4;
+ struct sockaddr_in6 sa_in6;
+ } from;
+ int from_len = sizeof(from);
+ err_t from_ugh = NULL;
+ static const char undisclosed[] = "unknown source";
+
+ happy(anyaddr(addrtypeof(&ifp->addr), &md->sender));
+ zero(&from.sa);
+ ioctl(ifp->fd, FIONREAD, &packet_len);
+ buffer = alloc_bytes(packet_len, "buffer read packet");
+ packet_len = recvfrom(ifp->fd, buffer, packet_len, 0
+ , &from.sa, &from_len);
+
+ /* First: digest the from address.
+ * We presume that nothing here disturbs errno.
+ */
+ if (packet_len == -1
+ && from_len == sizeof(from)
+ && all_zero((const void *)&from.sa, sizeof(from)))
+ {
+ /* "from" is untouched -- not set by recvfrom */
+ from_ugh = undisclosed;
+ }
+ else if (from_len
+ < (int) (offsetof(struct sockaddr, sa_family) + sizeof(from.sa.sa_family)))
+ {
+ from_ugh = "truncated";
+ }
+ else
+ {
+ const struct af_info *afi = aftoinfo(from.sa.sa_family);
+
+ if (afi == NULL)
+ {
+ from_ugh = "unexpected Address Family";
+ }
+ else if (from_len != (int)afi->sa_sz)
+ {
+ from_ugh = "wrong length";
+ }
+ else
+ {
+ switch (from.sa.sa_family)
+ {
+ case AF_INET:
+ from_ugh = initaddr((void *) &from.sa_in4.sin_addr
+ , sizeof(from.sa_in4.sin_addr), AF_INET, &md->sender);
+ md->sender_port = ntohs(from.sa_in4.sin_port);
+ break;
+ case AF_INET6:
+ from_ugh = initaddr((void *) &from.sa_in6.sin6_addr
+ , sizeof(from.sa_in6.sin6_addr), AF_INET6, &md->sender);
+ md->sender_port = ntohs(from.sa_in6.sin6_port);
+ break;
+ }
+ }
+ }
+
+ /* now we report any actual I/O error */
+ if (packet_len == -1)
+ {
+ if (from_ugh == undisclosed
+ && errno == ECONNREFUSED)
+ {
+ /* Tone down scary message for vague event:
+ * We get "connection refused" in response to some
+ * datagram we sent, but we cannot tell which one.
+ */
+ plog("some IKE message we sent has been rejected with ECONNREFUSED (kernel supplied no details)");
+ }
+ else if (from_ugh != NULL)
+ {
+ log_errno((e, "recvfrom on %s failed; Pluto cannot decode source sockaddr in rejection: %s"
+ , ifp->rname, from_ugh));
+ }
+ else
+ {
+ log_errno((e, "recvfrom on %s from %s:%u failed"
+ , ifp->rname
+ , ip_str(&md->sender), (unsigned)md->sender_port));
+ }
+
+ return FALSE;
+ }
+ else if (from_ugh != NULL)
+ {
+ plog("recvfrom on %s returned misformed source sockaddr: %s"
+ , ifp->rname, from_ugh);
+ return FALSE;
+ }
+ cur_from = &md->sender;
+ cur_from_port = md->sender_port;
+
+#ifdef NAT_TRAVERSAL
+ if (ifp->ike_float == TRUE) {
+ u_int32_t non_esp;
+ if (packet_len < (int)sizeof(u_int32_t)) {
+ plog("recvfrom %s:%u too small packet (%d)"
+ , ip_str(cur_from), (unsigned) cur_from_port, packet_len);
+ return FALSE;
+ }
+ memcpy(&non_esp, buffer, sizeof(u_int32_t));
+ if (non_esp != 0) {
+ plog("recvfrom %s:%u has no Non-ESP marker"
+ , ip_str(cur_from), (unsigned) cur_from_port);
+ return FALSE;
+ }
+ packet_len -= sizeof(u_int32_t);
+ buffer_nat = alloc_bytes(packet_len, "buffer read packet");
+ memcpy(buffer_nat, buffer + sizeof(u_int32_t), packet_len);
+ pfree(buffer);
+ buffer = buffer_nat;
+ }
+#endif
+
+ /* Clone actual message contents
+ * and set up md->packet_pbs to describe it.
+ */
+ init_pbs(&md->packet_pbs, buffer, packet_len, "packet");
+
+ DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL,
+ {
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*received %d bytes from %s:%u on %s"
+ , (int) pbs_room(&md->packet_pbs)
+ , ip_str(cur_from), (unsigned) cur_from_port
+ , ifp->rname);
+ });
+
+ DBG(DBG_RAW,
+ DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs)));
+
+#ifdef NAT_TRAVERSAL
+ if ((pbs_room(&md->packet_pbs)==1) && (md->packet_pbs.start[0]==0xff)) {
+ /**
+ * NAT-T Keep-alive packets should be discared by kernel ESPinUDP
+ * layer. But boggus keep-alive packets (sent with a non-esp marker)
+ * can reach this point. Complain and discard them.
+ */
+ DBG(DBG_NATT,
+ DBG_log("NAT-T keep-alive (boggus ?) should not reach this point. "
+ "Ignored. Sender: %s:%u", ip_str(cur_from),
+ (unsigned) cur_from_port);
+ );
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+/* process an input packet, possibly generating a reply.
+ *
+ * If all goes well, this routine eventually calls a state-specific
+ * transition function.
+ */
+static void
+process_packet(struct msg_digest **mdp)
+{
+ struct msg_digest *md = *mdp;
+ const struct state_microcode *smc;
+ bool new_iv_set = FALSE;
+ bool restore_iv = FALSE;
+ u_char new_iv[MAX_DIGEST_LEN];
+ u_int new_iv_len = 0;
+
+ struct state *st = NULL;
+ enum state_kind from_state = STATE_UNDEFINED; /* state we started in */
+
+#define SEND_NOTIFICATION(t) { \
+ if (st) send_notification_from_state(st, from_state, t); \
+ else send_notification_from_md(md, t); }
+
+ if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs))
+ {
+ /* Identify specific failures:
+ * - bad ISAKMP major/minor version numbers
+ */
+ if (md->packet_pbs.roof - md->packet_pbs.cur >= (ptrdiff_t)isakmp_hdr_desc.size)
+ {
+ struct isakmp_hdr *hdr = (struct isakmp_hdr *)md->packet_pbs.cur;
+ if ((hdr->isa_version >> ISA_MAJ_SHIFT) != ISAKMP_MAJOR_VERSION)
+ {
+ SEND_NOTIFICATION(INVALID_MAJOR_VERSION);
+ return;
+ }
+ else if ((hdr->isa_version & ISA_MIN_MASK) != ISAKMP_MINOR_VERSION)
+ {
+ SEND_NOTIFICATION(INVALID_MINOR_VERSION);
+ return;
+ }
+ }
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+ if (md->packet_pbs.roof != md->message_pbs.roof)
+ {
+ plog("size (%u) differs from size specified in ISAKMP HDR (%u)"
+ , (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length);
+ return;
+ }
+
+ switch (md->hdr.isa_xchg)
+ {
+#ifdef NOTYET
+ case ISAKMP_XCHG_NONE:
+ case ISAKMP_XCHG_BASE:
+#endif
+
+ case ISAKMP_XCHG_IDPROT: /* part of a Main Mode exchange */
+ if (md->hdr.isa_msgid != MAINMODE_MSGID)
+ {
+ plog("Message ID was 0x%08lx but should be zero in Main Mode",
+ (unsigned long) md->hdr.isa_msgid);
+ SEND_NOTIFICATION(INVALID_MESSAGE_ID);
+ return;
+ }
+
+ if (is_zero_cookie(md->hdr.isa_icookie))
+ {
+ plog("Initiator Cookie must not be zero in Main Mode message");
+ SEND_NOTIFICATION(INVALID_COOKIE);
+ return;
+ }
+
+ if (is_zero_cookie(md->hdr.isa_rcookie))
+ {
+ /* initial message from initiator
+ * ??? what if this is a duplicate of another message?
+ */
+ if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION)
+ {
+ plog("initial Main Mode message is invalid:"
+ " its Encrypted Flag is on");
+ SEND_NOTIFICATION(INVALID_FLAGS);
+ return;
+ }
+
+ /* don't build a state until the message looks tasty */
+ from_state = STATE_MAIN_R0;
+ }
+ else
+ {
+ /* not an initial message */
+
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, md->hdr.isa_msgid);
+
+ if (st == NULL)
+ {
+ /* perhaps this is a first message from the responder
+ * and contains a responder cookie that we've not yet seen.
+ */
+ st = find_state(md->hdr.isa_icookie, zero_cookie
+ , &md->sender, md->hdr.isa_msgid);
+
+ if (st == NULL)
+ {
+ plog("Main Mode message is part of an unknown exchange");
+ /* XXX Could send notification back */
+ return;
+ }
+ }
+ set_cur_state(st);
+ from_state = st->st_state;
+ }
+ break;
+
+#ifdef NOTYET
+ case ISAKMP_XCHG_AO:
+ case ISAKMP_XCHG_AGGR:
+#endif
+
+ case ISAKMP_XCHG_INFO: /* an informational exchange */
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, MAINMODE_MSGID);
+
+ if (st != NULL)
+ set_cur_state(st);
+
+ if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION)
+ {
+ if (st == NULL)
+ {
+ plog("Informational Exchange is for an unknown (expired?) SA");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (!IS_ISAKMP_ENCRYPTED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "encrypted Informational Exchange message is invalid"
+ " because no key is known");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (md->hdr.isa_msgid == MAINMODE_MSGID)
+ {
+ loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because"
+ " it has a Message ID of 0");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (!reserve_msgid(st, md->hdr.isa_msgid))
+ {
+ loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because"
+ " it has a previously used Message ID (0x%08lx)"
+ , (unsigned long)md->hdr.isa_msgid);
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len);
+ st->st_ph1_iv_len = st->st_new_iv_len;
+
+ /* backup new_iv */
+ new_iv_len = st->st_new_iv_len;
+ passert(new_iv_len <= MAX_DIGEST_LEN)
+ memcpy(new_iv, st->st_new_iv, new_iv_len);
+ restore_iv = TRUE;
+ }
+ init_phase2_iv(st, &md->hdr.isa_msgid);
+ new_iv_set = TRUE;
+
+ from_state = STATE_INFO_PROTECTED;
+ }
+ else
+ {
+ if (st != NULL && IS_ISAKMP_ENCRYPTED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "Informational Exchange message"
+ " must be encrypted");
+ /* XXX Could send notification back */
+ return;
+ }
+ from_state = STATE_INFO;
+ }
+ break;
+
+ case ISAKMP_XCHG_QUICK: /* part of a Quick Mode exchange */
+ if (is_zero_cookie(md->hdr.isa_icookie))
+ {
+ plog("Quick Mode message is invalid because"
+ " it has an Initiator Cookie of 0");
+ SEND_NOTIFICATION(INVALID_COOKIE);
+ return;
+ }
+
+ if (is_zero_cookie(md->hdr.isa_rcookie))
+ {
+ plog("Quick Mode message is invalid because"
+ " it has a Responder Cookie of 0");
+ SEND_NOTIFICATION(INVALID_COOKIE);
+ return;
+ }
+
+ if (md->hdr.isa_msgid == MAINMODE_MSGID)
+ {
+ plog("Quick Mode message is invalid because"
+ " it has a Message ID of 0");
+ SEND_NOTIFICATION(INVALID_MESSAGE_ID);
+ return;
+ }
+
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, md->hdr.isa_msgid);
+
+ if (st == NULL)
+ {
+ /* No appropriate Quick Mode state.
+ * See if we have a Main Mode state.
+ * ??? what if this is a duplicate of another message?
+ */
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, MAINMODE_MSGID);
+
+ if (st == NULL)
+ {
+ plog("Quick Mode message is for a non-existent (expired?)"
+ " ISAKMP SA");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (st->st_state == STATE_MODE_CFG_R2) /* Have we just give an IP address to peer? */
+ {
+ st->st_state = STATE_MAIN_R3; /* ISAKMP is up... */
+ }
+
+ set_cur_state(st);
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "Quick Mode message is unacceptable because"
+ " it is for an incomplete ISAKMP SA");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */);
+ return;
+ }
+
+ /* only accept this new Quick Mode exchange if it has a unique message ID */
+ if (!reserve_msgid(st, md->hdr.isa_msgid))
+ {
+ loglog(RC_LOG_SERIOUS, "Quick Mode I1 message is unacceptable because"
+ " it uses a previously used Message ID 0x%08lx"
+ " (perhaps this is a duplicated packet)"
+ , (unsigned long) md->hdr.isa_msgid);
+ SEND_NOTIFICATION(INVALID_MESSAGE_ID);
+ return;
+ }
+
+ /* Quick Mode Initial IV */
+ init_phase2_iv(st, &md->hdr.isa_msgid);
+ new_iv_set = TRUE;
+
+ from_state = STATE_QUICK_R0;
+ }
+ else
+ {
+ set_cur_state(st);
+ from_state = st->st_state;
+ }
+
+ break;
+
+ case ISAKMP_XCHG_MODE_CFG:
+ if (is_zero_cookie(md->hdr.isa_icookie))
+ {
+ plog("Mode Config message is invalid because"
+ " it has an Initiator Cookie of 0");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (is_zero_cookie(md->hdr.isa_rcookie))
+ {
+ plog("Mode Config message is invalid because"
+ " it has a Responder Cookie of 0");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ if (md->hdr.isa_msgid == 0)
+ {
+ plog("Mode Config message is invalid because"
+ " it has a Message ID of 0");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, md->hdr.isa_msgid);
+
+ if (st == NULL)
+ {
+ /* No appropriate Mode Config state.
+ * See if we have a Main Mode state.
+ * ??? what if this is a duplicate of another message?
+ */
+ st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie
+ , &md->sender, 0);
+
+ if (st == NULL)
+ {
+ plog("Mode Config message is for a non-existent (expired?)"
+ " ISAKMP SA");
+ /* XXX Could send notification back */
+ return;
+ }
+
+ set_cur_state(st);
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "Mode Config message is unacceptable because"
+ " it is for an incomplete ISAKMP SA (state=%s)"
+ , enum_name(&state_names, st->st_state));
+ /* XXX Could send notification back */
+ return;
+ }
+ init_phase2_iv(st, &md->hdr.isa_msgid);
+ new_iv_set = TRUE;
+
+ /*
+ * okay, now we have to figure out if we are receiving a bogus
+ * new message in an oustanding XAUTH server conversation
+ * (i.e. a reply to our challenge)
+ * (this occurs with some broken other implementations).
+ *
+ * or if receiving for the first time, an XAUTH challenge.
+ *
+ * or if we are getting a MODECFG request.
+ *
+ * we distinguish these states because we can not both be an
+ * XAUTH server and client, and our policy tells us which
+ * one we are.
+ *
+ * to complicate further, it is normal to start a new msgid
+ * when going from one state to another, or when restarting
+ * the challenge.
+ *
+ */
+
+ if (st->st_connection->spd.that.modecfg
+ && IS_PHASE1(st->st_state))
+ {
+ from_state = STATE_MODE_CFG_R0;
+ }
+ else if (st->st_connection->spd.this.modecfg
+ && IS_PHASE1(st->st_state))
+ {
+ from_state = STATE_MODE_CFG_R1;
+ }
+ else
+ {
+ /* XXX check if we are being a mode config server here */
+ plog("received MODECFG message when in state %s, and we aren't mode config client"
+ , enum_name(&state_names, st->st_state));
+ return;
+ }
+ }
+ else
+ {
+ set_cur_state(st);
+ from_state = st->st_state;
+ }
+
+ break;
+
+#ifdef NOTYET
+ case ISAKMP_XCHG_NGRP:
+ case ISAKMP_XCHG_ACK_INFO:
+#endif
+
+ default:
+ plog("unsupported exchange type %s in message"
+ , enum_show(&exchange_names, md->hdr.isa_xchg));
+ SEND_NOTIFICATION(UNSUPPORTED_EXCHANGE_TYPE);
+ return;
+ }
+
+ /* We have found a from_state, and perhaps a state object.
+ * If we need to build a new state object,
+ * we wait until the packet has been sanity checked.
+ */
+
+ /* We don't support the Commit Flag. It is such a bad feature.
+ * It isn't protected -- neither encrypted nor authenticated.
+ * A man in the middle turns it on, leading to DoS.
+ * We just ignore it, with a warning.
+ * By placing the check here, we could easily add a policy bit
+ * to a connection to suppress the warning. This might be useful
+ * because the Commit Flag is expected from some peers.
+ */
+ if (md->hdr.isa_flags & ISAKMP_FLAG_COMMIT)
+ {
+ plog("IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag");
+ }
+
+ /* Set smc to describe this state's properties.
+ * Look up the appropriate microcode based on state and
+ * possibly Oakley Auth type.
+ */
+ passert(STATE_IKE_FLOOR <= from_state && from_state <= STATE_IKE_ROOF);
+ smc = ike_microcode_index[from_state - STATE_IKE_FLOOR];
+
+ if (st != NULL)
+ {
+ while (!LHAS(smc->flags, st->st_oakley.auth))
+ {
+ smc++;
+ passert(smc->state == from_state);
+ }
+ }
+
+ /* Ignore a packet if the state has a suspended state transition
+ * Probably a duplicated packet but the original packet is not yet
+ * recorded in st->st_rpacket, so duplicate checking won't catch.
+ * ??? Should the packet be recorded earlier to improve diagnosis?
+ */
+ if (st != NULL && st->st_suspended_md != NULL)
+ {
+ loglog(RC_LOG, "discarding packet received during DNS lookup in %s"
+ , enum_name(&state_names, st->st_state));
+ return;
+ }
+
+ /* Detect and handle duplicated packets.
+ * This won't work for the initial packet of an exchange
+ * because we won't have a state object to remember it.
+ * If we are in a non-receiving state (terminal), and the preceding
+ * state did transmit, then the duplicate may indicate that that
+ * transmission wasn't received -- retransmit it.
+ * Otherwise, just discard it.
+ * ??? Notification packets are like exchanges -- I hope that
+ * they are idempotent!
+ */
+ if (st != NULL
+ && st->st_rpacket.ptr != NULL
+ && st->st_rpacket.len == pbs_room(&md->packet_pbs)
+ && memcmp(st->st_rpacket.ptr, md->packet_pbs.start, st->st_rpacket.len) == 0)
+ {
+ if (smc->flags & SMF_RETRANSMIT_ON_DUPLICATE)
+ {
+ if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS)
+ {
+ st->st_retransmit++;
+ loglog(RC_RETRANSMISSION
+ , "retransmitting in response to duplicate packet; already %s"
+ , enum_name(&state_names, st->st_state));
+ send_packet(st, "retransmit in response to duplicate");
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "discarding duplicate packet -- exhausted retransmission; already %s"
+ , enum_name(&state_names, st->st_state));
+ }
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "discarding duplicate packet; already %s"
+ , enum_name(&state_names, st->st_state));
+ }
+ return;
+ }
+
+ if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION)
+ {
+ DBG(DBG_CRYPT, DBG_log("received encrypted packet from %s:%u"
+ , ip_str(&md->sender), (unsigned)md->sender_port));
+
+ if (st == NULL)
+ {
+ plog("discarding encrypted message for an unknown ISAKMP SA");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */);
+ return;
+ }
+ if (st->st_skeyid_e.ptr == (u_char *) NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "discarding encrypted message"
+ " because we haven't yet negotiated keying materiel");
+ SEND_NOTIFICATION(INVALID_FLAGS);
+ return;
+ }
+
+ /* Mark as encrypted */
+ md->encrypted = TRUE;
+
+ DBG(DBG_CRYPT, DBG_log("decrypting %u bytes using algorithm %s"
+ , (unsigned) pbs_left(&md->message_pbs)
+ , enum_show(&oakley_enc_names, st->st_oakley.encrypt)));
+
+ /* do the specified decryption
+ *
+ * IV is from st->st_iv or (if new_iv_set) st->st_new_iv.
+ * The new IV is placed in st->st_new_iv
+ *
+ * See RFC 2409 "IKE" Appendix B
+ *
+ * XXX The IV should only be updated really if the packet
+ * is successfully processed.
+ * We should keep this value, check for a success return
+ * value from the parsing routines and then replace.
+ *
+ * Each post phase 1 exchange generates IVs from
+ * the last phase 1 block, not the last block sent.
+ */
+ {
+ const struct encrypt_desc *e = st->st_oakley.encrypter;
+
+ if (pbs_left(&md->message_pbs) % e->enc_blocksize != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+ /* XXX Detect weak keys */
+
+ /* grab a copy of raw packet (for duplicate packet detection) */
+ clonetochunk(md->raw_packet, md->packet_pbs.start
+ , pbs_room(&md->packet_pbs), "raw packet");
+
+ /* Decrypt everything after header */
+ if (!new_iv_set)
+ {
+ /* use old IV */
+ passert(st->st_iv_len <= sizeof(st->st_new_iv));
+ st->st_new_iv_len = st->st_iv_len;
+ memcpy(st->st_new_iv, st->st_iv, st->st_new_iv_len);
+ }
+ crypto_cbc_encrypt(e, FALSE, md->message_pbs.cur,
+ pbs_left(&md->message_pbs) , st);
+ if (restore_iv)
+ {
+ memcpy(st->st_new_iv, new_iv, new_iv_len);
+ st->st_new_iv_len = new_iv_len;
+ }
+ }
+
+ DBG_cond_dump(DBG_CRYPT, "decrypted:\n", md->message_pbs.cur
+ , md->message_pbs.roof - md->message_pbs.cur);
+
+ DBG_cond_dump(DBG_CRYPT, "next IV:"
+ , st->st_new_iv, st->st_new_iv_len);
+ }
+ else
+ {
+ /* packet was not encryped -- should it have been? */
+
+ if (smc->flags & SMF_INPUT_ENCRYPTED)
+ {
+ loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted");
+ SEND_NOTIFICATION(INVALID_FLAGS);
+ return;
+ }
+ }
+
+ /* Digest the message.
+ * Padding must be removed to make hashing work.
+ * Padding comes from encryption (so this code must be after decryption).
+ * Padding rules are described before the definition of
+ * struct isakmp_hdr in packet.h.
+ */
+ {
+ struct payload_digest *pd = md->digest;
+ int np = md->hdr.isa_np;
+ lset_t needed = smc->req_payloads;
+ const char *excuse
+ = LIN(SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT, smc->flags)
+ ? "probable authentication failure (mismatch of preshared secrets?): "
+ : "";
+
+ while (np != ISAKMP_NEXT_NONE)
+ {
+ struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL;
+
+ if (pd == &md->digest[PAYLIMIT])
+ {
+ loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT);
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+#ifdef NAT_TRAVERSAL
+ switch (np)
+ {
+ case ISAKMP_NEXT_NATD_RFC:
+ case ISAKMP_NEXT_NATOA_RFC:
+ if ((!st) || (!(st->nat_traversal & NAT_T_WITH_RFC_VALUES))) {
+ /*
+ * don't accept NAT-D/NAT-OA reloc directly in message, unless
+ * we're using NAT-T RFC
+ */
+ sd = NULL;
+ }
+ break;
+ }
+#endif
+
+ if (sd == NULL)
+ {
+ /* payload type is out of range or requires special handling */
+ switch (np)
+ {
+ case ISAKMP_NEXT_ID:
+ sd = IS_PHASE1(from_state)
+ ? &isakmp_identification_desc : &isakmp_ipsec_identification_desc;
+ break;
+#ifdef NAT_TRAVERSAL
+ case ISAKMP_NEXT_NATD_DRAFTS:
+ np = ISAKMP_NEXT_NATD_RFC; /* NAT-D relocated */
+ sd = payload_descs[np];
+ break;
+ case ISAKMP_NEXT_NATOA_DRAFTS:
+ np = ISAKMP_NEXT_NATOA_RFC; /* NAT-OA relocated */
+ sd = payload_descs[np];
+ break;
+#endif
+ default:
+ loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains an unknown or"
+ " unexpected payload type (%s) at the outermost level"
+ , excuse, enum_show(&payload_names, np));
+ SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE);
+ return;
+ }
+ }
+
+ {
+ lset_t s = LELEM(np);
+
+ if (LDISJOINT(s
+ , needed | smc->opt_payloads| LELEM(ISAKMP_NEXT_N) | LELEM(ISAKMP_NEXT_D)))
+ {
+ loglog(RC_LOG_SERIOUS, "%smessage ignored because it "
+ "contains an unexpected payload type (%s)"
+ , excuse, enum_show(&payload_names, np));
+ SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE);
+ return;
+ }
+ needed &= ~s;
+ }
+
+ if (!in_struct(&pd->payload, sd, &md->message_pbs, &pd->pbs))
+ {
+ loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse);
+ if (md->hdr.isa_xchg != ISAKMP_XCHG_INFO)
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+ /* place this payload at the end of the chain for this type */
+ {
+ struct payload_digest **p;
+
+ for (p = &md->chain[np]; *p != NULL; p = &(*p)->next)
+ ;
+ *p = pd;
+ pd->next = NULL;
+ }
+
+ np = pd->payload.generic.isag_np;
+ pd++;
+
+ /* since we've digested one payload happily, it is probably
+ * the case that any decryption worked. So we will not suggest
+ * encryption failure as an excuse for subsequent payload
+ * problems.
+ */
+ excuse = "";
+ }
+
+ md->digest_roof = pd;
+
+ DBG(DBG_PARSING,
+ if (pbs_left(&md->message_pbs) != 0)
+ DBG_log("removing %d bytes of padding", (int) pbs_left(&md->message_pbs)));
+
+ md->message_pbs.roof = md->message_pbs.cur;
+
+ /* check that all mandatory payloads appeared */
+
+ if (needed != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "message for %s is missing payloads %s"
+ , enum_show(&state_names, from_state)
+ , bitnamesof(payload_name, needed));
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ }
+
+ /* more sanity checking: enforce most ordering constraints */
+
+ if (IS_PHASE1(from_state))
+ {
+ /* rfc2409: The Internet Key Exchange (IKE), 5 Exchanges:
+ * "The SA payload MUST precede all other payloads in a phase 1 exchange."
+ */
+ if (md->chain[ISAKMP_NEXT_SA] != NULL
+ && md->hdr.isa_np != ISAKMP_NEXT_SA)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Phase 1 message: does not start with an SA payload");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ }
+ else if (IS_QUICK(from_state))
+ {
+ /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode
+ *
+ * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP
+ * header and a SA payload MUST immediately follow the HASH."
+ * [NOTE: there may be more than one SA payload, so this is not
+ * totally reasonable. Probably all SAs should be so constrained.]
+ *
+ * "If ISAKMP is acting as a client negotiator on behalf of another
+ * party, the identities of the parties MUST be passed as IDci and
+ * then IDcr."
+ *
+ * "With the exception of the HASH, SA, and the optional ID payloads,
+ * there are no payload ordering restrictions on Quick Mode."
+ */
+
+ if (md->hdr.isa_np != ISAKMP_NEXT_HASH)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: does not start with a HASH payload");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+
+ {
+ struct payload_digest *p;
+ int i;
+
+ for (p = md->chain[ISAKMP_NEXT_SA], i = 1; p != NULL
+ ; p = p->next, i++)
+ {
+ if (p != &md->digest[i])
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: SA payload is in wrong position");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ }
+ }
+
+ /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode:
+ * "If ISAKMP is acting as a client negotiator on behalf of another
+ * party, the identities of the parties MUST be passed as IDci and
+ * then IDcr."
+ */
+ {
+ struct payload_digest *id = md->chain[ISAKMP_NEXT_ID];
+
+ if (id != NULL)
+ {
+ if (id->next == NULL || id->next->next != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:"
+ " if any ID payload is present,"
+ " there must be exactly two");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ if (id+1 != id->next)
+ {
+ loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:"
+ " the ID payloads are not adjacent");
+ SEND_NOTIFICATION(PAYLOAD_MALFORMED);
+ return;
+ }
+ }
+ }
+ }
+
+ /* Ignore payloads that we don't handle:
+ * Delete, Notification, VendorID
+ */
+ /* XXX Handle deletions */
+ /* XXX Handle Notifications */
+ /* XXX Handle VID payloads */
+ {
+ struct payload_digest *p;
+
+ for (p = md->chain[ISAKMP_NEXT_N]; p != NULL; p = p->next)
+ {
+ if (p->payload.notification.isan_type != R_U_THERE
+ && p->payload.notification.isan_type != R_U_THERE_ACK)
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring informational payload, type %s"
+ , enum_show(&notification_names, p->payload.notification.isan_type));
+ }
+ DBG_cond_dump(DBG_PARSING, "info:", p->pbs.cur, pbs_left(&p->pbs));
+ }
+
+ for (p = md->chain[ISAKMP_NEXT_D]; p != NULL; p = p->next)
+ {
+ accept_delete(st, md, p);
+ DBG_cond_dump(DBG_PARSING, "del:", p->pbs.cur, pbs_left(&p->pbs));
+ }
+
+ for (p = md->chain[ISAKMP_NEXT_VID]; p != NULL; p = p->next)
+ {
+ handle_vendorid(md, p->pbs.cur, pbs_left(&p->pbs));
+ }
+ }
+ md->from_state = from_state;
+ md->smc = smc;
+ md->st = st;
+
+ /* possibly fill in hdr */
+ if (smc->first_out_payload != ISAKMP_NEXT_NONE)
+ echo_hdr(md, (smc->flags & SMF_OUTPUT_ENCRYPTED) != 0
+ , smc->first_out_payload);
+
+ complete_state_transition(mdp, smc->processor(md));
+}
+
+/* complete job started by the state-specific state transition function */
+
+void
+complete_state_transition(struct msg_digest **mdp, stf_status result)
+{
+ struct msg_digest *md = *mdp;
+ const struct state_microcode *smc = md->smc;
+ enum state_kind from_state = md->from_state;
+ struct state *st;
+
+ cur_state = st = md->st; /* might have changed */
+
+ /* If state has DPD support, import it */
+ if (st && md->dpd)
+ st->st_dpd = TRUE;
+
+ switch (result)
+ {
+ case STF_IGNORE:
+ break;
+
+ case STF_SUSPEND:
+ /* the stf didn't complete its job: don't relase md */
+ *mdp = NULL;
+ break;
+
+ case STF_OK:
+ /* advance the state */
+ st->st_state = smc->next_state;
+
+ /* Delete previous retransmission event.
+ * New event will be scheduled below.
+ */
+ delete_event(st);
+
+ /* replace previous receive packet with latest */
+
+ pfreeany(st->st_rpacket.ptr);
+
+ if (md->encrypted)
+ {
+ /* if encrypted, duplication already done */
+ st->st_rpacket = md->raw_packet;
+ md->raw_packet.ptr = NULL;
+ }
+ else
+ {
+ clonetochunk(st->st_rpacket
+ , md->packet_pbs.start
+ , pbs_room(&md->packet_pbs), "raw packet");
+ }
+
+ /* free previous transmit packet */
+ freeanychunk(st->st_tpacket);
+
+ /* if requested, send the new reply packet */
+ if (smc->flags & SMF_REPLY)
+ {
+ close_output_pbs(&md->reply); /* good form, but actually a no-op */
+
+ clonetochunk(st->st_tpacket, md->reply.start
+ , pbs_offset(&md->reply), "reply packet");
+
+#ifdef NAT_TRAVERSAL
+ if (nat_traversal_enabled)
+ nat_traversal_change_port_lookup(md, md->st);
+#endif
+
+ /* actually send the packet
+ * Note: this is a great place to implement "impairments"
+ * for testing purposes. Suppress or duplicate the
+ * send_packet call depending on st->st_state.
+ */
+ send_packet(st, enum_name(&state_names, from_state));
+ }
+
+ /* Schedule for whatever timeout is specified */
+ {
+ time_t delay;
+ enum event_type kind = smc->timeout_event;
+ bool agreed_time = FALSE;
+ struct connection *c = st->st_connection;
+
+ switch (kind)
+ {
+ case EVENT_RETRANSMIT: /* Retransmit packet */
+ delay = EVENT_RETRANSMIT_DELAY_0;
+ break;
+
+ case EVENT_SA_REPLACE: /* SA replacement event */
+ if (IS_PHASE1(st->st_state))
+ {
+ /* Note: we will defer to the "negotiated" (dictated)
+ * lifetime if we are POLICY_DONT_REKEY.
+ * This allows the other side to dictate
+ * a time we would not otherwise accept
+ * but it prevents us from having to initiate
+ * rekeying. The negative consequences seem
+ * minor.
+ */
+ delay = c->sa_ike_life_seconds;
+ if ((c->policy & POLICY_DONT_REKEY)
+ || delay >= st->st_oakley.life_seconds)
+ {
+ agreed_time = TRUE;
+ delay = st->st_oakley.life_seconds;
+ }
+ }
+ else
+ {
+ /* Delay is min of up to four things:
+ * each can limit the lifetime.
+ */
+ delay = c->sa_ipsec_life_seconds;
+ if (st->st_ah.present
+ && delay >= st->st_ah.attrs.life_seconds)
+ {
+ agreed_time = TRUE;
+ delay = st->st_ah.attrs.life_seconds;
+ }
+ if (st->st_esp.present
+ && delay >= st->st_esp.attrs.life_seconds)
+ {
+ agreed_time = TRUE;
+ delay = st->st_esp.attrs.life_seconds;
+ }
+ if (st->st_ipcomp.present
+ && delay >= st->st_ipcomp.attrs.life_seconds)
+ {
+ agreed_time = TRUE;
+ delay = st->st_ipcomp.attrs.life_seconds;
+ }
+ }
+
+ /* By default, we plan to rekey.
+ *
+ * If there isn't enough time to rekey, plan to
+ * expire.
+ *
+ * If we are --dontrekey, a lot more rules apply.
+ * If we are the Initiator, use REPLACE_IF_USED.
+ * If we are the Responder, and the dictated time
+ * was unacceptable (too large), plan to REPLACE
+ * (the only way to ratchet down the time).
+ * If we are the Responder, and the dictated time
+ * is acceptable, plan to EXPIRE.
+ *
+ * Important policy lies buried here.
+ * For example, we favour the initiator over the
+ * responder by making the initiator start rekeying
+ * sooner. Also, fuzz is only added to the
+ * initiator's margin.
+ *
+ * Note: for ISAKMP SA, we let the negotiated
+ * time stand (implemented by earlier logic).
+ */
+ if (agreed_time
+ && (c->policy & POLICY_DONT_REKEY))
+ {
+ kind = (smc->flags & SMF_INITIATOR)
+ ? EVENT_SA_REPLACE_IF_USED
+ : EVENT_SA_EXPIRE;
+ }
+ if (kind != EVENT_SA_EXPIRE)
+ {
+ unsigned long marg = c->sa_rekey_margin;
+
+ if (smc->flags & SMF_INITIATOR)
+ marg += marg
+ * c->sa_rekey_fuzz / 100.E0
+ * (rand() / (RAND_MAX + 1.E0));
+ else
+ marg /= 2;
+
+ if ((unsigned long)delay > marg)
+ {
+ delay -= marg;
+ st->st_margin = marg;
+ }
+ else
+ {
+ kind = EVENT_SA_EXPIRE;
+ }
+ }
+ break;
+
+ case EVENT_NULL: /* non-event */
+ case EVENT_REINIT_SECRET: /* Refresh cookie secret */
+ default:
+ bad_case(kind);
+ }
+ event_schedule(kind, delay, st);
+ }
+
+ /* tell whack and log of progress */
+ {
+ const char *story = state_story[st->st_state - STATE_MAIN_R0];
+ enum rc_type w = RC_NEW_STATE + st->st_state;
+ char sadetails[128];
+
+ sadetails[0]='\0';
+
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ char *b = sadetails;
+ const char *ini = " {";
+ const char *fin = "";
+
+ /* -1 is to leave space for "fin" */
+
+ if (st->st_esp.present)
+ {
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sESP=>0x%08x <0x%08x"
+ , ini
+ , ntohl(st->st_esp.attrs.spi)
+ , ntohl(st->st_esp.our_spi));
+ ini = " ";
+ fin = "}";
+ }
+ /* advance b to end of string */
+ b = b + strlen(b);
+
+ if (st->st_ah.present)
+ {
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sAH=>0x%08x <0x%08x"
+ , ini
+ , ntohl(st->st_ah.attrs.spi)
+ , ntohl(st->st_ah.our_spi));
+ ini = " ";
+ fin = "}";
+ }
+ /* advance b to end of string */
+ b = b + strlen(b);
+
+ if (st->st_ipcomp.present)
+ {
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sIPCOMP=>0x%08x <0x%08x"
+ , ini
+ , ntohl(st->st_ipcomp.attrs.spi)
+ , ntohl(st->st_ipcomp.our_spi));
+ ini = " ";
+ fin = "}";
+ }
+ /* advance b to end of string */
+ b = b + strlen(b);
+
+#ifdef NAT_TRAVERSAL
+ if (st->nat_traversal)
+ {
+ char oa[ADDRTOT_BUF];
+ addrtot(&st->nat_oa, 0, oa, sizeof(oa));
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sNATOA=%s"
+ , ini, oa);
+ ini = " ";
+ fin = "}";
+ }
+#endif
+
+ /* advance b to end of string */
+ b = b + strlen(b);
+
+ if (st->st_dpd)
+ {
+ snprintf(b, sizeof(sadetails)-(b-sadetails)-1
+ , "%sDPD"
+ , ini);
+ ini = " ";
+ fin = "}";
+ }
+
+ strcat(b, fin);
+ }
+
+ if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ || IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ /* log our success */
+ plog("%s%s", story, sadetails);
+ w = RC_SUCCESS;
+ }
+
+ /* tell whack our progress */
+ whack_log(w
+ , "%s: %s%s"
+ , enum_name(&state_names, st->st_state)
+ , story, sadetails);
+ }
+
+ /* Should we start Mode Config as a client */
+ if (st->st_connection->spd.this.modecfg
+ && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ && !st->st_modecfg.started)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("modecfg client is starting")
+ )
+ modecfg_send_request(st);
+ break;
+ }
+
+ /* Should we set the peer's IP address regardless? */
+/* if (st->st_connection->spd.that.modecfg
+ && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ && !st->st_modecfg.vars_set
+ && !(st->st_connection->policy & POLICY_MODECFG_PULL))
+ {
+ st->st_state = STATE_MODE_CFG_R1;
+ set_cur_state(st);
+ plog("Sending MODE CONFIG set");
+ modecfg_start_set(st);
+ break;
+ }
+*/
+ /* wait for modecfg_set */
+ if (st->st_connection->spd.this.modecfg
+ && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ && !st->st_modecfg.vars_set)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("waiting for modecfg set from server")
+ )
+ break;
+ }
+
+ if (smc->flags & SMF_RELEASE_PENDING_P2)
+ {
+ /* Initiate any Quick Mode negotiations that
+ * were waiting to piggyback on this Keying Channel.
+ *
+ * ??? there is a potential race condition
+ * if we are the responder: the initial Phase 2
+ * message might outrun the final Phase 1 message.
+ * I think that retransmission will recover.
+ */
+ unpend(st);
+ }
+
+ if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+ || IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ release_whack(st);
+ break;
+
+ case STF_INTERNAL_ERROR:
+ whack_log(RC_INTERNALERR + md->note
+ , "%s: internal error"
+ , enum_name(&state_names, st->st_state));
+
+ DBG(DBG_CONTROL,
+ DBG_log("state transition function for %s had internal error"
+ , enum_name(&state_names, from_state)));
+ break;
+
+ default: /* a shortcut to STF_FAIL, setting md->note */
+ passert(result > STF_FAIL);
+ md->note = result - STF_FAIL;
+ result = STF_FAIL;
+ /* FALL THROUGH ... */
+ case STF_FAIL:
+ /* As it is, we act as if this message never happened:
+ * whatever retrying was in place, remains in place.
+ */
+ whack_log(RC_NOTIFICATION + md->note
+ , "%s: %s", enum_name(&state_names, st->st_state)
+ , enum_name(&notification_names, md->note));
+
+ SEND_NOTIFICATION(md->note);
+
+ DBG(DBG_CONTROL,
+ DBG_log("state transition function for %s failed: %s"
+ , enum_name(&state_names, from_state)
+ , enum_name(&notification_names, md->note)));
+ break;
+ }
+}
diff --git a/programs/pluto/demux.h b/programs/pluto/demux.h
new file mode 100644
index 000000000..7adac44f3
--- /dev/null
+++ b/programs/pluto/demux.h
@@ -0,0 +1,100 @@
+/* demultiplex incoming IKE messages
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: demux.h,v 1.4 2004/07/22 22:57:25 as Exp $
+ */
+
+#include "packet.h"
+
+struct state; /* forward declaration of tag */
+extern void init_demux(void);
+#ifdef NAT_TRAVERSAL
+#define send_packet(st,wh) _send_packet(st,wh,TRUE)
+extern bool _send_packet(struct state *st, const char *where, bool verbose);
+#else
+extern bool send_packet(struct state *st, const char *where);
+#endif
+extern void comm_handle(const struct iface *ifp);
+
+extern u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE];
+
+/* State transition function infrastructure
+ *
+ * com_handle parses a message, decides what state object it applies to,
+ * and calls the appropriate state transition function (STF).
+ * These declarations define the interface to these functions.
+ *
+ * Each STF must be able to be restarted up to any failure point:
+ * a later message will cause the state to be re-entered. This
+ * explains the use of the replace macro and the care in handling
+ * MP_INT members of struct state.
+ */
+
+struct payload_digest {
+ pb_stream pbs;
+ union payload payload;
+ struct payload_digest *next; /* of same kind */
+};
+
+/* message digest
+ * Note: raw_packet and packet_pbs are "owners" of space on heap.
+ */
+
+struct msg_digest {
+ struct msg_digest *next; /* for free list */
+ chunk_t raw_packet; /* if encrypted, received packet before decryption */
+ const struct iface *iface; /* interface on which message arrived */
+ ip_address sender; /* where message came from */
+ u_int16_t sender_port; /* host order */
+ pb_stream packet_pbs; /* whole packet */
+ pb_stream message_pbs; /* message to be processed */
+ struct isakmp_hdr hdr; /* message's header */
+ bool encrypted; /* was it encrypted? */
+ enum state_kind from_state; /* state we started in */
+ const struct state_microcode *smc; /* microcode for initial state */
+ struct state *st; /* current state object */
+ pb_stream reply; /* room for reply */
+ pb_stream rbody; /* room for reply body (after header) */
+ notification_t note; /* reason for failure */
+ bool dpd; /* peer supports RFC 3706 DPD */
+ bool openpgp; /* peer supports OpenPGP certificates */
+
+# define PAYLIMIT 20
+ struct payload_digest
+ digest[PAYLIMIT],
+ *digest_roof,
+ *chain[ISAKMP_NEXT_ROOF];
+#ifdef NAT_TRAVERSAL
+ unsigned short nat_traversal_vid;
+#endif
+};
+
+extern void release_md(struct msg_digest *md);
+
+/* status for state-transition-function
+ * Note: STF_FAIL + notification_t means fail with that notification
+ */
+
+typedef enum {
+ STF_IGNORE, /* don't respond */
+ STF_SUSPEND, /* unfinished -- don't release resources */
+ STF_OK, /* success */
+ STF_INTERNAL_ERROR, /* discard everything, we failed */
+ STF_FAIL /* discard everything, something failed. notification_t added. */
+} stf_status;
+
+typedef stf_status state_transition_fn(struct msg_digest *md);
+
+extern void complete_state_transition(struct msg_digest **mdp, stf_status result);
+
+extern void free_md_pool(void);
diff --git a/programs/pluto/dnskey.c b/programs/pluto/dnskey.c
new file mode 100644
index 000000000..9aca1938d
--- /dev/null
+++ b/programs/pluto/dnskey.c
@@ -0,0 +1,1962 @@
+/* Find public key in DNS
+ * Copyright (C) 2000-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: dnskey.c,v 1.5 2005/09/08 16:26:30 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h> /* ??? for h_errno */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "defs.h"
+#include "log.h"
+#include "id.h"
+#include "connections.h"
+#include "keys.h" /* needs connections.h */
+#include "dnskey.h"
+#include "packet.h"
+#include "timer.h"
+
+/* somebody has to decide */
+#define MAX_TXT_RDATA ((MAX_KEY_BYTES * 8 / 6) + 40) /* somewhat arbitrary overkill */
+
+/* ADNS stuff */
+
+int adns_qfd = NULL_FD, /* file descriptor for sending queries to adns (O_NONBLOCK) */
+ adns_afd = NULL_FD; /* file descriptor for receiving answers from adns */
+static pid_t adns_pid = 0;
+const char *pluto_adns_option = NULL; /* path from --pluto_adns */
+
+int adns_restart_count;
+#define ADNS_RESTART_MAX 20
+
+void
+init_adns(void)
+{
+ const char *adns_path = pluto_adns_option;
+#ifndef USE_LWRES
+ static const char adns_name[] = "_pluto_adns";
+ const char *helper_bin_dir = getenv("IPSEC_LIBDIR");
+#else /* USE_LWRES */
+ static const char adns_name[] = "lwdnsq";
+ const char *helper_bin_dir = getenv("IPSEC_EXECDIR");
+#endif /* USE_LWRES */
+ char adns_path_space[4096]; /* plenty long? */
+ int qfds[2];
+ int afds[2];
+
+ /* find a pathname to the ADNS program */
+ if (adns_path == NULL)
+ {
+ /* pathname was not specified as an option: build it.
+ * First, figure out the directory to be used.
+ */
+ ssize_t n;
+
+ if (helper_bin_dir != NULL)
+ {
+ n = strlen(helper_bin_dir);
+ if ((size_t)n <= sizeof(adns_path_space) - sizeof(adns_name))
+ {
+ strcpy(adns_path_space, helper_bin_dir);
+ if (n > 0 && adns_path_space[n -1] != '/')
+ adns_path_space[n++] = '/';
+ }
+ }
+ else
+ {
+ /* The program will be in the same directory as Pluto,
+ * so we use the sympolic link /proc/self/exe to
+ * tell us of the path prefix.
+ */
+ n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space));
+
+ if (n < 0)
+ exit_log_errno((e
+ , "readlink(\"/proc/self/exe\") failed in init_adns()"));
+
+ }
+
+ if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name))
+ exit_log("path to %s is too long", adns_name);
+
+ while (n > 0 && adns_path_space[n - 1] != '/')
+ n--;
+
+ strcpy(adns_path_space + n, adns_name);
+ adns_path = adns_path_space;
+ }
+ if (access(adns_path, X_OK) < 0)
+ exit_log_errno((e, "%s missing or not executable", adns_path));
+
+ if (pipe(qfds) != 0 || pipe(afds) != 0)
+ exit_log_errno((e, "pipe(2) failed in init_adns()"));
+
+ adns_pid = fork();
+ switch (adns_pid)
+ {
+ case -1:
+ exit_log_errno((e, "fork() failed in init_adns()"));
+
+ case 0:
+ /* child */
+ {
+ /* Make stdin and stdout our pipes.
+ * Take care to handle case where pipes already use these fds.
+ */
+ if (afds[1] == 0)
+ afds[1] = dup(afds[1]); /* avoid being overwritten */
+ if (qfds[0] != 0)
+ {
+ dup2(qfds[0], 0);
+ close(qfds[0]);
+ }
+ if (afds[1] != 1)
+ {
+ dup2(afds[1], 1);
+ close(qfds[1]);
+ }
+ if (afds[0] > 1)
+ close(afds[0]);
+ if (afds[1] > 1)
+ close(afds[1]);
+
+ DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL));
+
+ execlp(adns_path, adns_name, NULL);
+ exit_log_errno((e, "execlp of %s failed", adns_path));
+ }
+
+ default:
+ /* parent */
+ close(qfds[0]);
+ adns_qfd = qfds[1];
+ adns_afd = afds[0];
+ close(afds[1]);
+ fcntl(adns_qfd, F_SETFD, FD_CLOEXEC);
+ fcntl(adns_afd, F_SETFD, FD_CLOEXEC);
+ fcntl(adns_qfd, F_SETFL, O_NONBLOCK);
+ break;
+ }
+}
+
+void
+stop_adns(void)
+{
+ close_any(adns_qfd);
+ adns_qfd = NULL_FD;
+ close_any(adns_afd);
+ adns_afd = NULL_FD;
+
+ if (adns_pid != 0)
+ {
+ int status;
+ pid_t p = waitpid(adns_pid, &status, 0);
+
+ if (p == -1)
+ {
+ log_errno((e, "waitpid for ADNS process failed"));
+ }
+ else if (WIFEXITED(status))
+ {
+ if (WEXITSTATUS(status) != 0)
+ plog("ADNS process exited with status %d"
+ , (int) WEXITSTATUS(status));
+ }
+ else if (WIFSIGNALED(status))
+ {
+ plog("ADNS process terminated by signal %d", (int)WTERMSIG(status));
+ }
+ else
+ {
+ plog("wait for end of ADNS process returned odd status 0x%x\n"
+ , status);
+ }
+ }
+}
+
+
+
+/* tricky macro to pass any hot potato */
+#define TRY(x) { err_t ugh = x; if (ugh != NULL) return ugh; }
+
+
+/* Process TXT X-IPsec-Server record, accumulating relevant ones
+ * in cr->gateways_from_dns, a list sorted by "preference".
+ *
+ * Format of TXT record body: X-IPsec-Server ( nnn ) = iii kkk
+ * nnn is a 16-bit unsigned integer preference
+ * iii is @FQDN or dotted-decimal IPv4 address or colon-hex IPv6 address
+ * kkk is an optional RSA public signing key in base 64.
+ *
+ * NOTE: we've got to be very wary of anything we find -- bad guys
+ * might have prepared it.
+ */
+
+#define our_TXT_attr_string "X-IPsec-Server"
+static const char our_TXT_attr[] = our_TXT_attr_string;
+
+static err_t
+decode_iii(u_char **pp, struct id *gw_id)
+{
+ u_char *p = *pp + strspn(*pp, " \t");
+ u_char *e = p + strcspn(p, " \t");
+ u_char under = *e;
+
+ if (p == e)
+ return "TXT " our_TXT_attr_string " badly formed (no gateway specified)";
+
+ *e = '\0';
+ if (*p == '@')
+ {
+ /* gateway specification in this record is @FQDN */
+ err_t ugh = atoid(p, gw_id, FALSE);
+
+ if (ugh != NULL)
+ return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s"
+ , ugh);
+ }
+ else
+ {
+ /* gateway specification is numeric */
+ ip_address ip;
+ err_t ugh = tnatoaddr(p, e-p
+ , strchr(p, ':') == NULL? AF_INET : AF_INET6
+ , &ip);
+
+ if (ugh != NULL)
+ return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s"
+ , ugh);
+
+ if (isanyaddr(&ip))
+ return "gateway address must not be 0.0.0.0 or 0::0";
+
+ iptoid(&ip, gw_id);
+ }
+
+ *e = under;
+ *pp = e + strspn(e, " \t");
+
+ return NULL;
+}
+
+static err_t
+process_txt_rr_body(u_char *str
+, bool doit /* should we capture information? */
+, enum dns_auth_level dns_auth_level
+, struct adns_continuation *const cr)
+{
+ const struct id *client_id = &cr->id; /* subject of query */
+ u_char *p = str;
+ unsigned long pref = 0;
+ struct gw_info gi;
+
+ p += strspn(p, " \t"); /* ignore leading whitespace */
+
+ /* is this for us? */
+ if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0)
+ return NULL; /* neither interesting nor bad */
+
+ p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */
+ p += strspn(p, " \t"); /* ignore leading whitespace */
+
+ /* decode '(' nnn ')' */
+ if (*p != '(')
+ return "X-IPsec-Server missing '('";
+
+ {
+ char *e;
+
+ p++;
+ pref = strtoul(p, &e, 0);
+ if ((u_char *)e == p)
+ return "malformed X-IPsec-Server priority";
+
+ p = e + strspn(e, " \t");
+
+ if (*p != ')')
+ return "X-IPsec-Server priority missing ')'";
+
+ p++;
+ p += strspn(p, " \t");
+
+ if (pref > 0xFFFF)
+ return "X-IPsec-Server priority larger than 0xFFFF";
+ }
+
+ /* time for '=' */
+
+ if (*p != '=')
+ return "X-IPsec-Server priority missing '='";
+
+ p++;
+ p += strspn(p, " \t");
+
+ /* Decode iii (Security Gateway ID). */
+
+ zero(&gi); /* before first use */
+
+ TRY(decode_iii(&p, &gi.gw_id)); /* will need to unshare_id_content */
+
+ if (!cr->sgw_specified)
+ {
+ /* we don't know the peer's ID (because we are initiating
+ * and we don't know who to initiate with.
+ * So we're looking for gateway specs with an IP address
+ */
+ if (!id_is_ipaddr(&gi.gw_id))
+ {
+ DBG(DBG_DNS,
+ {
+ char cidb[BUF_LEN];
+ char gwidb[BUF_LEN];
+
+ idtoa(client_id, cidb, sizeof(cidb));
+ idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
+ DBG_log("TXT %s record for %s: security gateway %s;"
+ " ignored because gateway's IP is unspecified"
+ , our_TXT_attr, cidb, gwidb);
+ });
+ return NULL; /* we cannot use this record, but it isn't wrong */
+ }
+ }
+ else
+ {
+ /* We do know the peer's ID (because we are responding)
+ * So we're looking for gateway specs specifying this known ID.
+ */
+ const struct id *peer_id = &cr->sgw_id;
+
+ if (!same_id(peer_id, &gi.gw_id))
+ {
+ DBG(DBG_DNS,
+ {
+ char cidb[BUF_LEN];
+ char gwidb[BUF_LEN];
+ char pidb[BUF_LEN];
+
+ idtoa(client_id, cidb, sizeof(cidb));
+ idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
+ idtoa(peer_id, pidb, sizeof(pidb));
+ DBG_log("TXT %s record for %s: security gateway %s;"
+ " ignored -- looking to confirm %s as gateway"
+ , our_TXT_attr, cidb, gwidb, pidb);
+ });
+ return NULL; /* we cannot use this record, but it isn't wrong */
+ }
+ }
+
+ if (doit)
+ {
+ /* really accept gateway */
+ struct gw_info **gwip; /* gateway insertion point */
+
+ gi.client_id = *client_id; /* will need to unshare_id_content */
+
+ /* decode optional kkk: base 64 encoding of key */
+
+ gi.gw_key_present = *p != '\0';
+ if (gi.gw_key_present)
+ {
+ /* Decode base 64 encoding of key.
+ * Similar code is in process_lwdnsq_key.
+ */
+ u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
+ chunk_t kbc;
+ struct RSA_public_key r;
+
+ err_t ugh = ttodatav(p, 0, 64, kb, sizeof(kb), &kbc.len
+ , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
+
+ if (ugh != NULL)
+ return builddiag("malformed key data: %s", ugh);
+
+ if (kbc.len > sizeof(kb))
+ return builddiag("key data larger than %lu bytes"
+ , (unsigned long) sizeof(kb));
+
+ kbc.ptr = kb;
+ ugh = unpack_RSA_public_key(&r, &kbc);
+ if (ugh != NULL)
+ return builddiag("invalid key data: %s", ugh);
+
+ /* now find a key entry to put it in */
+ gi.key = public_key_from_rsa(&r);
+
+ free_RSA_public_content(&r);
+
+ unreference_key(&cr->last_info);
+ cr->last_info = reference_key(gi.key);
+ }
+
+ /* we're home free! Allocate everything and add to gateways list. */
+ gi.refcnt = 1;
+ gi.pref = pref;
+ gi.key->dns_auth_level = dns_auth_level;
+ gi.key->last_tried_time = gi.key->last_worked_time = NO_TIME;
+
+ /* find insertion point */
+ for (gwip = &cr->gateways_from_dns; *gwip != NULL && (*gwip)->pref < pref; gwip = &(*gwip)->next)
+ ;
+
+ DBG(DBG_DNS,
+ {
+ char cidb[BUF_LEN];
+ char gwidb[BUF_LEN];
+
+ idtoa(client_id, cidb, sizeof(cidb));
+ idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
+ if (gi.gw_key_present)
+ {
+ DBG_log("gateway for %s is %s with key %s"
+ , cidb, gwidb, gi.key->u.rsa.keyid);
+ }
+ else
+ {
+ DBG_log("gateway for %s is %s; no key specified"
+ , cidb, gwidb);
+ }
+ });
+
+ gi.next = *gwip;
+ *gwip = clone_thing(gi, "gateway info");
+ unshare_id_content(&(*gwip)->gw_id);
+ unshare_id_content(&(*gwip)->client_id);
+ }
+
+ return NULL;
+}
+
+static const char *
+rr_typename(int type)
+{
+ switch (type)
+ {
+ case T_TXT:
+ return "TXT";
+ case T_KEY:
+ return "KEY";
+ default:
+ return "???";
+ }
+}
+
+
+#ifdef USE_LWRES
+
+# ifdef USE_KEYRR
+static err_t
+process_lwdnsq_key(u_char *str
+, enum dns_auth_level dns_auth_level
+, struct adns_continuation *const cr)
+{
+ /* fields of KEY record. See RFC 2535 3.1 KEY RDATA format. */
+ unsigned long flags /* 16 bits */
+ , protocol /* 8 bits */
+ , algorithm; /* 8 bits */
+
+ char *rest = str
+ , *p
+ , *endofnumber;
+
+ /* flags */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq KEY: missing flags";
+
+ flags = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq KEY: malformed flags";
+
+ /* protocol */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq KEY: missing protocol";
+
+ protocol = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq KEY: malformed protocol";
+
+ /* algorithm */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq KEY: missing algorithm";
+
+ algorithm = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq KEY: malformed algorithm";
+
+ /* is this key interesting? */
+ if (protocol == 4 /* IPSEC (RFC 2535 3.1.3) */
+ && algorithm == 1 /* RSA/MD5 (RFC 2535 3.2) */
+ && (flags & 0x8000ul) == 0 /* use for authentication (3.1.2) */
+ && (flags & 0x2CF0ul) == 0) /* must be zero */
+ {
+ /* Decode base 64 encoding of key.
+ * Similar code is in process_txt_rr_body.
+ */
+ u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
+ chunk_t kbc;
+ err_t ugh = ttodatav(rest, 0, 64, kb, sizeof(kb), &kbc.len
+ , diag_space, sizeof(diag_space), TTODATAV_IGNORESPACE);
+
+ if (ugh != NULL)
+ return builddiag("malformed key data: %s", ugh);
+
+ if (kbc.len > sizeof(kb))
+ return builddiag("key data larger than %lu bytes"
+ , (unsigned long) sizeof(kb));
+
+ kbc.ptr = kb;
+ TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &kbc
+ , &cr->keys_from_dns));
+
+ /* keep a reference to last one */
+ unreference_key(&cr->last_info);
+ cr->last_info = reference_key(cr->keys_from_dns->key);
+ }
+ return NULL;
+}
+# endif /* USE_KEYRR */
+
+#else /* ! USE_LWRES */
+
+/* structure of Query Reply (RFC 1035 4.1.1):
+ *
+ * +---------------------+
+ * | Header |
+ * +---------------------+
+ * | Question | the question for the name server
+ * +---------------------+
+ * | Answer | RRs answering the question
+ * +---------------------+
+ * | Authority | RRs pointing toward an authority
+ * +---------------------+
+ * | Additional | RRs holding additional information
+ * +---------------------+
+ */
+
+/* Header section format (as modified by RFC 2535 6.1):
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ID |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QDCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ANCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | NSCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ARCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+struct qr_header {
+ u_int16_t id; /* 16-bit identifier to match query */
+
+ u_int16_t stuff; /* packed crud: */
+
+#define QRS_QR 0x8000 /* QR: on if this is a response */
+
+#define QRS_OPCODE_SHIFT 11 /* OPCODE field */
+#define QRS_OPCODE_MASK 0xF
+#define QRSO_QUERY 0 /* standard query */
+#define QRSO_IQUERY 1 /* inverse query */
+#define QRSO_STATUS 2 /* server status request query */
+
+#define QRS_AA 0x0400 /* AA: on if Authoritative Answer */
+#define QRS_TC 0x0200 /* TC: on if truncation happened */
+#define QRS_RD 0x0100 /* RD: on if recursion desired */
+#define QRS_RA 0x0080 /* RA: on if recursion available */
+#define QRS_Z 0x0040 /* Z: reserved; must be zero */
+#define QRS_AD 0x0020 /* AD: on if authentic data (RFC 2535) */
+#define QRS_CD 0x0010 /* AD: on if checking disabled (RFC 2535) */
+
+#define QRS_RCODE_SHIFT 0 /* RCODE field: response code */
+#define QRS_RCODE_MASK 0xF
+#define QRSR_OK 0
+
+
+ u_int16_t qdcount; /* number of entries in question section */
+ u_int16_t ancount; /* number of resource records in answer section */
+ u_int16_t nscount; /* number of name server resource records in authority section */
+ u_int16_t arcount; /* number of resource records in additional records section */
+};
+
+static field_desc qr_header_fields[] = {
+ { ft_nat, 16/BITS_PER_BYTE, "ID", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "stuff", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "QD Count", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "Answer Count", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "Authority Count", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "Additional Count", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc qr_header_desc = {
+ "Query Response Header",
+ qr_header_fields,
+ sizeof(struct qr_header)
+};
+
+/* Messages for codes in RCODE (see RFC 1035 4.1.1) */
+static const err_t rcode_text[QRS_RCODE_MASK + 1] = {
+ NULL, /* not an error */
+ "Format error - The name server was unable to interpret the query",
+ "Server failure - The name server was unable to process this query"
+ " due to a problem with the name server",
+ "Name Error - Meaningful only for responses from an authoritative name"
+ " server, this code signifies that the domain name referenced in"
+ " the query does not exist",
+ "Not Implemented - The name server does not support the requested"
+ " kind of query",
+ "Refused - The name server refuses to perform the specified operation"
+ " for policy reasons",
+ /* the rest are reserved for future use */
+ };
+
+/* throw away a possibly compressed domain name */
+
+static err_t
+eat_name(pb_stream *pbs)
+{
+ u_char name_buf[NS_MAXDNAME + 2];
+ u_char *ip = pbs->cur;
+ unsigned oi = 0;
+ unsigned jump_count = 0;
+
+ for (;;)
+ {
+ u_int8_t b;
+
+ if (ip >= pbs->roof)
+ return "ran out of message while skipping domain name";
+
+ b = *ip++;
+ if (jump_count == 0)
+ pbs->cur = ip;
+
+ if (b == 0)
+ break;
+
+ switch (b & 0xC0)
+ {
+ case 0x00:
+ /* we grab the next b characters */
+ if (oi + b > NS_MAXDNAME)
+ return "domain name too long";
+
+ if (pbs->roof - ip <= b)
+ return "domain name falls off end of message";
+
+ if (oi != 0)
+ name_buf[oi++] = '.';
+
+ memcpy(name_buf + oi, ip, b);
+ oi += b;
+ ip += b;
+ if (jump_count == 0)
+ pbs->cur = ip;
+ break;
+
+ case 0xC0:
+ {
+ unsigned ix;
+
+ if (ip >= pbs->roof)
+ return "ran out of message in middle of compressed domain name";
+
+ ix = ((b & ~0xC0u) << 8) | *ip++;
+ if (jump_count == 0)
+ pbs->cur = ip;
+
+ if (ix >= pbs_room(pbs))
+ return "impossible compressed domain name";
+
+ /* Avoid infinite loop.
+ * There can be no more jumps than there are bytes
+ * in the packet. Not a tight limit, but good enough.
+ */
+ jump_count++;
+ if (jump_count > pbs_room(pbs))
+ return "loop in compressed domain name";
+
+ ip = pbs->start + ix;
+ }
+ break;
+
+ default:
+ return "invalid code in label";
+ }
+ }
+
+ name_buf[oi++] = '\0';
+
+ DBG(DBG_DNS, DBG_log("skipping name %s", name_buf));
+
+ return NULL;
+}
+
+static err_t
+eat_name_helpfully(pb_stream *pbs, const char *context)
+{
+ err_t ugh = eat_name(pbs);
+
+ return ugh == NULL? ugh
+ : builddiag("malformed name within DNS record of %s: %s", context, ugh);
+}
+
+/* non-variable part of 4.1.2 Question Section entry:
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | |
+ * / QNAME /
+ * / /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QTYPE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QCLASS |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+
+struct qs_fixed {
+ u_int16_t qtype;
+ u_int16_t qclass;
+};
+
+static field_desc qs_fixed_fields[] = {
+ { ft_loose_enum, 16/BITS_PER_BYTE, "QTYPE", &rr_qtype_names },
+ { ft_loose_enum, 16/BITS_PER_BYTE, "QCLASS", &rr_class_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc qs_fixed_desc = {
+ "Question Section entry fixed part",
+ qs_fixed_fields,
+ sizeof(struct qs_fixed)
+};
+
+/* 4.1.3. Resource record format:
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | |
+ * / /
+ * / NAME /
+ * | |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | TYPE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | CLASS |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | TTL |
+ * | |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | RDLENGTH |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ * / RDATA /
+ * / /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+
+struct rr_fixed {
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl; /* actually signed */
+ u_int16_t rdlength;
+};
+
+
+static field_desc rr_fixed_fields[] = {
+ { ft_loose_enum, 16/BITS_PER_BYTE, "type", &rr_type_names },
+ { ft_loose_enum, 16/BITS_PER_BYTE, "class", &rr_class_names },
+ { ft_nat, 32/BITS_PER_BYTE, "TTL", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "RD length", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc rr_fixed_desc = {
+ "Resource Record fixed part",
+ rr_fixed_fields,
+ /* note: following is tricky: avoids padding problems */
+ offsetof(struct rr_fixed, rdlength) + sizeof(u_int16_t)
+};
+
+/* RFC 1035 3.3.14: TXT RRs have text in the RDATA field.
+ * It is in the form of a sequence of <character-string>s as described in 3.3.
+ * unpack_txt_rdata() deals with this peculiar representation.
+ */
+
+/* RFC 2535 3.1 KEY RDATA format:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | flags | protocol | algorithm |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | /
+ * / public key /
+ * / /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
+ */
+
+struct key_rdata {
+ u_int16_t flags;
+ u_int8_t protocol;
+ u_int8_t algorithm;
+};
+
+static field_desc key_rdata_fields[] = {
+ { ft_nat, 16/BITS_PER_BYTE, "flags", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "protocol", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc key_rdata_desc = {
+ "KEY RR RData fixed part",
+ key_rdata_fields,
+ sizeof(struct key_rdata)
+};
+
+/* RFC 2535 4.1 SIG RDATA format:
+ *
+ * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | type covered | algorithm | labels |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | original TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | signature expiration |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | signature inception |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | key tag | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ signer's name +
+ * | /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-/
+ * / /
+ * / signature /
+ * / /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+struct sig_rdata {
+ u_int16_t type_covered;
+ u_int8_t algorithm;
+ u_int8_t labels;
+ u_int32_t original_ttl;
+ u_int32_t sig_expiration;
+ u_int32_t sig_inception;
+ u_int16_t key_tag;
+};
+
+static field_desc sig_rdata_fields[] = {
+ { ft_nat, 16/BITS_PER_BYTE, "type_covered", NULL},
+ { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL},
+ { ft_nat, 8/BITS_PER_BYTE, "labels", NULL},
+ { ft_nat, 32/BITS_PER_BYTE, "original ttl", NULL},
+ { ft_nat, 32/BITS_PER_BYTE, "sig expiration", NULL},
+ { ft_nat, 32/BITS_PER_BYTE, "sig inception", NULL},
+ { ft_nat, 16/BITS_PER_BYTE, "key tag", NULL},
+ { ft_end, 0, NULL, NULL }
+};
+
+static struct_desc sig_rdata_desc = {
+ "SIG RR RData fixed part",
+ sig_rdata_fields,
+ sizeof(struct sig_rdata)
+};
+
+/* handle a KEY Resource Record. */
+
+#ifdef USE_KEYRR
+static err_t
+process_key_rr(u_char *ptr, size_t len
+, bool doit /* should we capture information? */
+, enum dns_auth_level dns_auth_level
+, struct adns_continuation *const cr)
+{
+ pb_stream pbs;
+ struct key_rdata kr;
+
+ if (len < sizeof(struct key_rdata))
+ return "KEY Resource Record's RD Length is too small";
+
+ init_pbs(&pbs, ptr, len, "KEY RR");
+
+ if (!in_struct(&kr, &key_rdata_desc, &pbs, NULL))
+ return "failed to get fixed part of KEY Resource Record RDATA";
+
+ if (kr.protocol == 4 /* IPSEC (RFC 2535 3.1.3) */
+ && kr.algorithm == 1 /* RSA/MD5 (RFC 2535 3.2) */
+ && (kr.flags & 0x8000) == 0 /* use for authentication (3.1.2) */
+ && (kr.flags & 0x2CF0) == 0) /* must be zero */
+ {
+ /* we have what seems to be a tasty key */
+
+ if (doit)
+ {
+ chunk_t k;
+
+ setchunk(k, pbs.cur, pbs_left(&pbs));
+ TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &k
+ , &cr->keys_from_dns));
+ }
+ }
+ return NULL;
+}
+#endif /* USE_KEYRR */
+
+
+/* unpack TXT rr RDATA into C string.
+ * A sequence of <character-string>s as described in RFC 1035 3.3.
+ * We concatenate them.
+ */
+static err_t
+unpack_txt_rdata(u_char *d, size_t dlen, const u_char *s, size_t slen)
+{
+ size_t i = 0
+ , o = 0;
+
+ while (i < slen)
+ {
+ size_t cl = s[i++];
+
+ if (i + cl > slen)
+ return "TXT rr RDATA representation malformed";
+
+ if (o + cl >= dlen)
+ return "TXT rr RDATA too large";
+
+ memcpy(d + o, s + i, cl);
+ i += cl;
+ o += cl;
+ }
+ d[o] = '\0';
+ if (strlen(d) != o)
+ return "TXT rr RDATA contains a NUL";
+
+ return NULL;
+}
+
+static err_t
+process_txt_rr(u_char *rdata, size_t rdlen
+, bool doit /* should we capture information? */
+, enum dns_auth_level dns_auth_level
+, struct adns_continuation *const cr)
+{
+ u_char str[RSA_MAX_ENCODING_BYTES * 8 / 6 + 20]; /* space for unpacked RDATA */
+
+ TRY(unpack_txt_rdata(str, sizeof(str), rdata, rdlen));
+ return process_txt_rr_body(str, doit, dns_auth_level, cr);
+}
+
+static err_t
+process_answer_section(pb_stream *pbs
+, bool doit /* should we capture information? */
+, enum dns_auth_level *dns_auth_level
+, u_int16_t ancount /* number of RRs in the answer section */
+, struct adns_continuation *const cr)
+{
+ const int type = cr->query.type; /* type of RR of interest */
+ unsigned c;
+
+ DBG(DBG_DNS, DBG_log("*Answer Section:"));
+
+ for (c = 0; c != ancount; c++)
+ {
+ struct rr_fixed rrf;
+ size_t tail;
+
+ /* ??? do we need to match the name? */
+
+ TRY(eat_name_helpfully(pbs, "Answer Section"));
+
+ if (!in_struct(&rrf, &rr_fixed_desc, pbs, NULL))
+ return "failed to get fixed part of Answer Section Resource Record";
+
+ if (rrf.rdlength > pbs_left(pbs))
+ return "RD Length extends beyond end of message";
+
+ /* ??? should we care about ttl? */
+
+ tail = rrf.rdlength;
+
+ if (rrf.type == type && rrf.class == C_IN)
+ {
+ err_t ugh = NULL;
+
+ switch (type)
+ {
+#ifdef USE_KEYRR
+ case T_KEY:
+ ugh = process_key_rr(pbs->cur, tail, doit, *dns_auth_level, cr);
+ break;
+#endif /* USE_KEYRR */
+ case T_TXT:
+ ugh = process_txt_rr(pbs->cur, tail, doit, *dns_auth_level, cr);
+ break;
+ case T_SIG:
+ /* Check if SIG RR authenticates what we are learning.
+ * The RRset covered by a SIG must have the same owner,
+ * class, and type.
+ * For us, the class is always C_IN, so that matches.
+ * We decode the SIG RR's fixed part to check
+ * that the type_covered field matches our query type
+ * (this may be redundant).
+ * We don't check the owner (apparently this is the
+ * name on the record) -- we assume that it matches
+ * or we would not have been given this SIG in the
+ * Answer Section.
+ *
+ * We only look on first pass, and only if we've something
+ * to learn. This cuts down on useless decoding.
+ */
+ if (!doit && *dns_auth_level == DAL_UNSIGNED)
+ {
+ struct sig_rdata sr;
+
+ if (!in_struct(&sr, &sig_rdata_desc, pbs, NULL))
+ ugh = "failed to get fixed part of SIG Resource Record RDATA";
+ else if (sr.type_covered == type)
+ *dns_auth_level = DAL_SIGNED;
+ }
+ break;
+ default:
+ ugh = builddiag("unexpected RR type %d", type);
+ break;
+ }
+ if (ugh != NULL)
+ return ugh;
+ }
+ in_raw(NULL, tail, pbs, "RR RDATA");
+ }
+
+ return doit
+ && cr->gateways_from_dns == NULL
+#ifdef USE_KEYRR
+ && cr->keys_from_dns == NULL
+#endif /* USE_KEYRR */
+ ? builddiag("no suitable %s record found in DNS", rr_typename(type))
+ : NULL;
+}
+
+/* process DNS answer -- TXT or KEY query */
+
+static err_t
+process_dns_answer(struct adns_continuation *const cr
+, u_char ans[], int anslen)
+{
+ const int type = cr->query.type; /* type of record being sought */
+ int r; /* all-purpose return value holder */
+ u_int16_t c; /* number of current RR in current answer section */
+ pb_stream pbs;
+ u_int8_t *ans_start; /* saved position of answer section */
+ struct qr_header qr_header;
+ enum dns_auth_level dns_auth_level;
+
+ init_pbs(&pbs, ans, anslen, "Query Response Message");
+
+ /* decode and check header */
+
+ if (!in_struct(&qr_header, &qr_header_desc, &pbs, NULL))
+ return "malformed header";
+
+ /* ID: nothing to do with us */
+
+ /* stuff -- lots of things */
+ if ((qr_header.stuff & QRS_QR) == 0)
+ return "not a response?!?";
+
+ if (((qr_header.stuff >> QRS_OPCODE_SHIFT) & QRS_OPCODE_MASK) != QRSO_QUERY)
+ return "unexpected opcode";
+
+ /* I don't think we care about AA */
+
+ if (qr_header.stuff & QRS_TC)
+ return "response truncated";
+
+ /* I don't think we care about RD, RA, or CD */
+
+ /* AD means "authentic data" */
+ dns_auth_level = qr_header.stuff & QRS_AD? DAL_UNSIGNED : DAL_NOTSEC;
+
+ if (qr_header.stuff & QRS_Z)
+ return "Z bit is not zero";
+
+ r = (qr_header.stuff >> QRS_RCODE_SHIFT) & QRS_RCODE_MASK;
+ if (r != 0)
+ return r < (int)elemsof(rcode_text)? rcode_text[r] : "unknown rcode";
+
+ if (qr_header.ancount == 0)
+ return builddiag("no %s RR found by DNS", rr_typename(type));
+
+ /* end of header checking */
+
+ /* Question Section processing */
+
+ /* 4.1.2. Question section format:
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | |
+ * / QNAME /
+ * / /
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QTYPE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QCLASS |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+
+ DBG(DBG_DNS, DBG_log("*Question Section:"));
+
+ for (c = 0; c != qr_header.qdcount; c++)
+ {
+ struct qs_fixed qsf;
+
+ TRY(eat_name_helpfully(&pbs, "Question Section"));
+
+ if (!in_struct(&qsf, &qs_fixed_desc, &pbs, NULL))
+ return "failed to get fixed part of Question Section";
+
+ if (qsf.qtype != type)
+ return "unexpected QTYPE in Question Section";
+
+ if (qsf.qclass != C_IN)
+ return "unexpected QCLASS in Question Section";
+ }
+
+ /* rest of sections are made up of Resource Records */
+
+ /* Answer Section processing -- error checking, noting T_SIG */
+
+ ans_start = pbs.cur; /* remember start of answer section */
+
+ TRY(process_answer_section(&pbs, FALSE, &dns_auth_level
+ , qr_header.ancount, cr));
+
+ /* Authority Section processing (just sanity checking) */
+
+ DBG(DBG_DNS, DBG_log("*Authority Section:"));
+
+ for (c = 0; c != qr_header.nscount; c++)
+ {
+ struct rr_fixed rrf;
+ size_t tail;
+
+ TRY(eat_name_helpfully(&pbs, "Authority Section"));
+
+ if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL))
+ return "failed to get fixed part of Authority Section Resource Record";
+
+ if (rrf.rdlength > pbs_left(&pbs))
+ return "RD Length extends beyond end of message";
+
+ /* ??? should we care about ttl? */
+
+ tail = rrf.rdlength;
+
+ in_raw(NULL, tail, &pbs, "RR RDATA");
+ }
+
+ /* Additional Section processing (just sanity checking) */
+
+ DBG(DBG_DNS, DBG_log("*Additional Section:"));
+
+ for (c = 0; c != qr_header.arcount; c++)
+ {
+ struct rr_fixed rrf;
+ size_t tail;
+
+ TRY(eat_name_helpfully(&pbs, "Additional Section"));
+
+ if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL))
+ return "failed to get fixed part of Additional Section Resource Record";
+
+ if (rrf.rdlength > pbs_left(&pbs))
+ return "RD Length extends beyond end of message";
+
+ /* ??? should we care about ttl? */
+
+ tail = rrf.rdlength;
+
+ in_raw(NULL, tail, &pbs, "RR RDATA");
+ }
+
+ /* done all sections */
+
+ /* ??? is padding legal, or can we complain if more left in record? */
+
+ /* process Answer Section again -- accept contents */
+
+ pbs.cur = ans_start; /* go back to start of answer section */
+
+ return process_answer_section(&pbs, TRUE, &dns_auth_level
+ , qr_header.ancount, cr);
+}
+
+#endif /* ! USE_LWRES */
+
+
+/****************************************************************/
+
+static err_t
+build_dns_name(u_char name_buf[NS_MAXDNAME + 2]
+, unsigned long serial USED_BY_DEBUG
+, const struct id *id
+, const char *typename USED_BY_DEBUG
+, const char *gwname USED_BY_DEBUG)
+{
+ /* note: all end in "." to suppress relative searches */
+ id = resolve_myid(id);
+ switch (id->kind)
+ {
+ case ID_IPV4_ADDR:
+ {
+ /* XXX: this is really ugly and only temporary until addrtot can
+ * generate the correct format
+ */
+ const unsigned char *b;
+ size_t bl USED_BY_DEBUG = addrbytesptr(&id->ip_addr, &b);
+
+ passert(bl == 4);
+ snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa."
+ , b[3], b[2], b[1], b[0]);
+ break;
+ }
+
+ case ID_IPV6_ADDR:
+ {
+ /* ??? is this correct? */
+ const unsigned char *b;
+ size_t bl;
+ u_char *op = name_buf;
+ static const char suffix[] = "IP6.INT.";
+
+ for (bl = addrbytesptr(&id->ip_addr, &b); bl-- != 0; )
+ {
+ if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1)
+ return "IPv6 reverse name too long";
+ op += sprintf(op, "%x.%x.", b[bl] & 0xF, b[bl] >> 4);
+ }
+ strcpy(op, suffix);
+ break;
+ }
+
+ case ID_FQDN:
+ /* strip trailing "." characters, then add one */
+ {
+ size_t il = id->name.len;
+
+ while (il > 0 && id->name.ptr[il - 1] == '.')
+ il--;
+ if (il > NS_MAXDNAME)
+ return "FQDN too long for domain name";
+
+ memcpy(name_buf, id->name.ptr, il);
+ strcpy(name_buf + il, ".");
+ }
+ break;
+
+ default:
+ return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR";
+ }
+
+ DBG(DBG_CONTROL | DBG_DNS, DBG_log("DNS query %lu for %s for %s (gw: %s)"
+ , serial, typename, name_buf, gwname));
+ return NULL;
+}
+
+void
+gw_addref(struct gw_info *gw)
+{
+ if (gw != NULL)
+ {
+ DBG(DBG_DNS, DBG_log("gw_addref: %p refcnt: %d++", gw, gw->refcnt))
+ gw->refcnt++;
+ }
+}
+
+void
+gw_delref(struct gw_info **gwp)
+{
+ struct gw_info *gw = *gwp;
+
+ if (gw != NULL)
+ {
+ DBG(DBG_DNS, DBG_log("gw_delref: %p refcnt: %d--", gw, gw->refcnt));
+
+ passert(gw->refcnt != 0);
+ gw->refcnt--;
+ if (gw->refcnt == 0)
+ {
+ free_id_content(&gw->client_id);
+ free_id_content(&gw->gw_id);
+ if (gw->gw_key_present)
+ unreference_key(&gw->key);
+ gw_delref(&gw->next);
+ pfree(gw); /* trickery could make this a tail-call */
+ }
+ *gwp = NULL;
+ }
+}
+
+static int adns_in_flight = 0; /* queries outstanding */
+
+/* Start an asynchronous DNS query.
+ *
+ * For KEY record, the result will be a list in cr->keys_from_dns.
+ * For TXT records, the result will be a list in cr->gateways_from_dns.
+ *
+ * If sgw_id is null, only consider TXT records that specify an
+ * IP address for the gatway: we need this in the initiation case.
+ *
+ * If sgw_id is non-null, only consider TXT records that specify
+ * this id as the security gatway; this is useful to the Responder
+ * for confirming claims of gateways.
+ *
+ * Continuation cr gives information for continuing when the result shows up.
+ *
+ * Two kinds of errors must be handled: synchronous (immediate)
+ * and asynchronous. Synchronous errors are indicated by the returned
+ * value of start_adns_query; in this case, the continuation will
+ * have been freed and the continuation routine will not be called.
+ * Asynchronous errors are indicated by the ugh parameter passed to the
+ * continuation routine.
+ *
+ * After the continuation routine has completed, handle_adns_answer
+ * will free the continuation. The continuation routine should have
+ * freed any axiliary resources.
+ *
+ * Note: in the synchronous error case, start_adns_query will have
+ * freed the continuation; this means that the caller will have to
+ * be very careful to release any auxiliary resources that were in
+ * the continuation record without using the continuation record.
+ *
+ * Either there will be an error result passed to the continuation routine,
+ * or the results will be in cr->keys_from_dns or cr->gateways_from_dns.
+ * The result variables must by left NULL by the continutation routine.
+ * The continuation routine is responsible for establishing and
+ * disestablishing any logging context (whack_log_fd, cur_*).
+ */
+
+static struct adns_continuation *continuations = NULL; /* newest of queue */
+static struct adns_continuation *next_query = NULL; /* oldest not sent */
+
+static struct adns_continuation *
+continuation_for_qtid(unsigned long qtid)
+{
+ struct adns_continuation *cr = NULL;
+
+ if (qtid != 0)
+ for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous)
+ ;
+ return cr;
+}
+
+static void
+release_adns_continuation(struct adns_continuation *cr)
+{
+ passert(cr != next_query);
+ gw_delref(&cr->gateways_from_dns);
+#ifdef USE_KEYRR
+ free_public_keys(&cr->keys_from_dns);
+#endif /* USE_KEYRR */
+ unshare_id_content(&cr->id);
+ unshare_id_content(&cr->sgw_id);
+
+ /* unlink from doubly-linked list */
+ if (cr->next == NULL)
+ {
+ passert(continuations == cr);
+ continuations = cr->previous;
+ }
+ else
+ {
+ passert(cr->next->previous == cr);
+ cr->next->previous = cr->previous;
+ }
+
+ if (cr->previous != NULL)
+ {
+ passert(cr->previous->next == cr);
+ cr->previous->next = cr->next;
+ }
+
+ pfree(cr);
+}
+
+err_t
+start_adns_query(const struct id *id /* domain to query */
+, const struct id *sgw_id /* if non-null, any accepted gw_info must match */
+, int type /* T_TXT or T_KEY, selecting rr type of interest */
+, cont_fn_t cont_fn
+, struct adns_continuation *cr)
+{
+ static unsigned long qtid = 1; /* query transaction id; NOTE: static */
+ const char *typename = rr_typename(type);
+ char gwidb[BUF_LEN];
+
+ if(adns_pid == 0
+ && adns_restart_count < ADNS_RESTART_MAX)
+ {
+ plog("ADNS helper was not running. Restarting attempt %d",adns_restart_count);
+ init_adns();
+ }
+
+
+ /* Splice this in at head of doubly-linked list of continuations.
+ * Note: this must be done before any release_adns_continuation().
+ */
+ cr->next = NULL;
+ cr->previous = continuations;
+ if (continuations != NULL)
+ {
+ passert(continuations->next == NULL);
+ continuations->next = cr;
+ }
+ continuations = cr;
+
+ cr->qtid = qtid++;
+ cr->type = type;
+ cr->cont_fn = cont_fn;
+ cr->id = *id;
+ unshare_id_content(&cr->id);
+ cr->sgw_specified = sgw_id != NULL;
+ cr->sgw_id = cr->sgw_specified? *sgw_id : empty_id;
+ unshare_id_content(&cr->sgw_id);
+ cr->gateways_from_dns = NULL;
+#ifdef USE_KEYRR
+ cr->keys_from_dns = NULL;
+#endif /* USE_KEYRR */
+
+#ifdef DEBUG
+ cr->debugging = cur_debugging;
+#else
+ cr->debugging = LEMPTY;
+#endif
+
+ idtoa(&cr->sgw_id, gwidb, sizeof(gwidb));
+
+ zero(&cr->query);
+
+ {
+ err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid
+ , id, typename, gwidb);
+
+ if (ugh != NULL)
+ {
+ release_adns_continuation(cr);
+ return ugh;
+ }
+ }
+
+ if (next_query == NULL)
+ next_query = cr;
+
+ unsent_ADNS_queries = TRUE;
+
+ return NULL;
+}
+
+/* send remaining ADNS queries (until pipe full or none left)
+ *
+ * This is a co-routine, so it uses static variables to
+ * preserve state across calls.
+ */
+bool unsent_ADNS_queries = FALSE;
+
+void
+send_unsent_ADNS_queries(void)
+{
+ static const unsigned char *buf_end = NULL; /* NOTE STATIC */
+ static const unsigned char *buf_cur = NULL; /* NOTE STATIC */
+
+ if (adns_qfd == NULL_FD)
+ return; /* nothing useful to do */
+
+ for (;;)
+ {
+ if (buf_cur != buf_end)
+ {
+ static int try = 0; /* NOTE STATIC */
+ size_t n = buf_end - buf_cur;
+ ssize_t r = write(adns_qfd, buf_cur, n);
+
+ if (r == -1)
+ {
+ switch (errno)
+ {
+ case EINTR:
+ continue; /* try again now */
+ case EAGAIN:
+ DBG(DBG_DNS, DBG_log("EAGAIN writing to ADNS"));
+ break; /* try again later */
+ default:
+ try++;
+ log_errno((e, "error %d writing DNS query", try));
+ break; /* try again later */
+ }
+ unsent_ADNS_queries = TRUE;
+ break; /* done! */
+ }
+ else
+ {
+ passert(r >= 0);
+ try = 0;
+ buf_cur += r;
+ }
+ }
+ else
+ {
+ if (next_query == NULL)
+ {
+ unsent_ADNS_queries = FALSE;
+ break; /* done! */
+ }
+
+#ifdef USE_LWRES
+ next_query->used = FALSE;
+ {
+ /* NOTE STATIC: */
+ static unsigned char qbuf[LWDNSQ_CMDBUF_LEN + 1]; /* room for NUL */
+
+ snprintf(qbuf, sizeof(qbuf), "%s %lu %s\n"
+ , rr_typename(next_query->type)
+ , next_query->qtid
+ , next_query->query.name_buf);
+ DBG(DBG_DNS, DBG_log("lwdnsq query: %.*s", (int)(strlen(qbuf) - 1), qbuf));
+ buf_cur = qbuf;
+ buf_end = qbuf + strlen(qbuf);
+ }
+#else /* !USE_LWRES */
+ next_query->query.debugging = next_query->debugging;
+ next_query->query.serial = next_query->qtid;
+ next_query->query.len = sizeof(next_query->query);
+ next_query->query.qmagic = ADNS_Q_MAGIC;
+ next_query->query.type = next_query->type;
+ buf_cur = (const void *)&next_query->query;
+ buf_end = buf_cur + sizeof(next_query->query);
+#endif /* !USE_LWRES */
+ next_query = next_query->next;
+ adns_in_flight++;
+ }
+ }
+}
+
+#ifdef USE_LWRES
+/* Process a line of lwdnsq answer.
+ * Returns with error message iff lwdnsq result is malformed.
+ * Most errors will be in DNS data and will be handled by cr->cont_fn.
+ */
+static err_t
+process_lwdnsq_answer(char *ts)
+{
+ err_t ugh = NULL;
+ char *rest;
+ char *p;
+ char *endofnumber;
+ struct adns_continuation *cr = NULL;
+ unsigned long qtid;
+ time_t anstime; /* time of answer */
+ char *atype; /* type of answer */
+ long ttl; /* ttl of answer; int, but long for conversion */
+ bool AuthenticatedData = FALSE;
+ static char scratch_null_str[] = ""; /* cannot be const, but isn't written */
+
+ /* query transaction id */
+ rest = ts;
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq: answer missing query transaction ID";
+
+ qtid = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq: malformed query transaction ID";
+
+ cr = continuation_for_qtid(qtid);
+ if (qtid != 0 && cr == NULL)
+ return "lwdnsq: unrecognized qtid"; /* can't happen! */
+
+ /* time */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq: missing time";
+
+ anstime = strtoul(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq: malformed time";
+
+ /* TTL */
+ p = strsep(&rest, " \t");
+ if (p == NULL)
+ return "lwdnsq: missing TTL";
+
+ ttl = strtol(p, &endofnumber, 10);
+ if (*endofnumber != '\0')
+ return "lwdnsq: malformed TTL";
+
+ /* type */
+ atype = strsep(&rest, " \t");
+ if (atype == NULL)
+ return "lwdnsq: missing type";
+
+ /* if rest is NULL, make it "", otherwise eat whitespace after type */
+ rest = rest == NULL? scratch_null_str : rest + strspn(rest, " \t");
+
+ if (strncasecmp(atype, "AD-", 3) == 0)
+ {
+ AuthenticatedData = TRUE;
+ atype += 3;
+ }
+
+ /* deal with each type */
+
+ if (cr == NULL)
+ {
+ /* we don't actually know which this applies to */
+ return builddiag("lwdnsq: 0 qtid invalid with %s", atype);
+ }
+ else if (strcaseeq(atype, "START"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "DONE"))
+ {
+ if (!cr->used)
+ {
+ /* "no results returned by lwdnsq" should not happen */
+ cr->cont_fn(cr
+ , cr->gateways_from_dns == NULL
+#ifdef USE_KEYRR
+ && cr->keys_from_dns == NULL
+#endif /* USE_KEYRR */
+ ? "no results returned by lwdnsq" : NULL);
+ cr->used = TRUE;
+ }
+ reset_globals();
+ release_adns_continuation(cr);
+ adns_in_flight--;
+ }
+ else if (strcaseeq(atype, "RETRY"))
+ {
+ if (!cr->used)
+ {
+ cr->cont_fn(cr, rest);
+ cr->used = TRUE;
+ }
+ }
+ else if (strcaseeq(atype, "FATAL"))
+ {
+ if (!cr->used)
+ {
+ cr->cont_fn(cr, rest);
+ cr->used = TRUE;
+ }
+ }
+ else if (strcaseeq(atype, "DNSSEC"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "NAME"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "TXT"))
+ {
+ char *end = rest + strlen(rest);
+ err_t txt_ugh;
+
+ if (*rest == '"' && end[-1] == '"')
+ {
+ /* strip those pesky quotes */
+ rest++;
+ *--end = '\0';
+ }
+
+ txt_ugh = process_txt_rr_body(rest
+ , TRUE
+ , AuthenticatedData? DAL_SIGNED : DAL_NOTSEC
+ , cr);
+
+ if (txt_ugh != NULL)
+ {
+ DBG(DBG_DNS,
+ DBG_log("error processing TXT resource record (%s) while processing: %s"
+ , txt_ugh, rest));
+ cr->cont_fn(cr, txt_ugh);
+ cr->used = TRUE;
+ }
+ }
+ else if (strcaseeq(atype, "SIG"))
+ {
+ /* record the SIG records for posterity */
+ if (cr->last_info != NULL)
+ {
+ pfreeany(cr->last_info->dns_sig);
+ cr->last_info->dns_sig = clone_str(rest, "sigrecord");
+ }
+ }
+ else if (strcaseeq(atype, "A"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "AAAA"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "CNAME"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "CNAMEFROM"))
+ {
+ /* ignore */
+ }
+ else if (strcaseeq(atype, "PTR"))
+ {
+ /* ignore */
+ }
+#ifdef USE_KEYRR
+ else if (strcaseeq(atype, "KEY"))
+ {
+ err_t key_ugh = process_lwdnsq_key(rest
+ , AuthenticatedData? DAL_SIGNED : DAL_NOTSEC
+ , cr);
+
+ if (key_ugh != NULL)
+ {
+ DBG(DBG_DNS,
+ DBG_log("error processing KEY resource record (%s) while processing: %s"
+ , key_ugh, rest));
+ cr->cont_fn(cr, key_ugh);
+ cr->used = TRUE;
+ }
+ }
+#endif /* USE_KEYRR */
+ else
+ {
+ ugh = "lwdnsq: unrecognized type";
+ }
+ return ugh;
+}
+#endif /* USE_LWRES */
+
+static void
+recover_adns_die(void)
+{
+ struct adns_continuation *cr = NULL;
+
+ adns_pid = 0;
+ if(adns_restart_count < ADNS_RESTART_MAX) {
+ adns_restart_count++;
+
+ /* next DNS query will restart it */
+
+ /* we have to walk the list of the outstanding requests,
+ * and redo them!
+ */
+
+ cr = continuations;
+
+ /* find the head of the list */
+ if(continuations != NULL) {
+ for (; cr->previous != NULL; cr = cr->previous);
+ }
+
+ next_query = cr;
+
+ if(next_query != NULL) {
+ unsent_ADNS_queries = TRUE;
+ }
+ }
+}
+
+void reset_adns_restart_count(void)
+{
+ adns_restart_count=0;
+}
+
+void
+handle_adns_answer(void)
+{
+ /* These are retained across calls to handle_adns_answer. */
+ static size_t buflen = 0; /* bytes in answer buffer */
+#ifndef USE_LWRES
+ static struct adns_answer buf;
+#else /* USE_LWRES */
+ static char buf[LWDNSQ_RESULT_LEN_MAX];
+ static char buf_copy[LWDNSQ_RESULT_LEN_MAX];
+#endif /* USE_LWRES */
+
+ ssize_t n;
+
+ passert(buflen < sizeof(buf));
+ n = read(adns_afd, (unsigned char *)&buf + buflen, sizeof(buf) - buflen);
+
+ if (n < 0)
+ {
+ if (errno != EINTR)
+ {
+ log_errno((e, "error reading answer from adns"));
+ /* ??? how can we recover? */
+ }
+ n = 0; /* now n reflects amount read */
+ }
+ else if (n == 0)
+ {
+ /* EOF */
+ if (adns_in_flight != 0)
+ {
+ plog("EOF from ADNS with %d queries outstanding (restarts %d)"
+ , adns_in_flight, adns_restart_count);
+ recover_adns_die();
+ }
+ if (buflen != 0)
+ {
+ plog("EOF from ADNS with %lu bytes of a partial answer outstanding"
+ "(restarts %d)"
+ , (unsigned long)buflen
+ , adns_restart_count);
+ recover_adns_die();
+ }
+ stop_adns();
+ return;
+ }
+ else
+ {
+ passert(adns_in_flight > 0);
+ }
+
+ buflen += n;
+#ifndef USE_LWRES
+ while (buflen >= offsetof(struct adns_answer, ans) && buflen >= buf.len)
+ {
+ /* we've got a tasty answer -- process it */
+ err_t ugh;
+ struct adns_continuation *cr = continuation_for_qtid(buf.serial); /* assume it works */
+ const char *typename = rr_typename(cr->query.type);
+ const char *name_buf = cr->query.name_buf;
+
+#ifdef USE_KEYRR
+ passert(cr->keys_from_dns == NULL);
+#endif /* USE_KEYRR */
+ passert(cr->gateways_from_dns == NULL);
+ adns_in_flight--;
+ if (buf.result == -1)
+ {
+ /* newer resolvers support statp->res_h_errno as well as h_errno.
+ * That might be better, but older resolvers don't.
+ * See resolver(3), if you have it.
+ * The undocumented(!) h_errno values are defined in
+ * /usr/include/netdb.h.
+ */
+ switch (buf.h_errno_val)
+ {
+ case NO_DATA:
+ ugh = builddiag("no %s record for %s", typename, name_buf);
+ break;
+ case HOST_NOT_FOUND:
+ ugh = builddiag("no host %s for %s record", name_buf, typename);
+ break;
+ default:
+ ugh = builddiag("failure querying DNS for %s of %s: %s"
+ , typename, name_buf, hstrerror(buf.h_errno_val));
+ break;
+ }
+ }
+ else if (buf.result > (int) sizeof(buf.ans))
+ {
+ ugh = builddiag("(INTERNAL ERROR) answer too long (%ld) for buffer"
+ , (long)buf.result);
+ }
+ else
+ {
+ ugh = process_dns_answer(cr, buf.ans, buf.result);
+ if (ugh != NULL)
+ ugh = builddiag("failure processing %s record of DNS answer for %s: %s"
+ , typename, name_buf, ugh);
+ }
+ DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL | DBG_DNS,
+ DBG_log(BLANK_FORMAT);
+ if (ugh == NULL)
+ DBG_log("asynch DNS answer %lu for %s of %s"
+ , cr->query.serial, typename, name_buf);
+ else
+ DBG_log("asynch DNS answer %lu %s", cr->query.serial, ugh);
+ );
+
+ passert(GLOBALS_ARE_RESET());
+ cr->cont_fn(cr, ugh);
+ reset_globals();
+ release_adns_continuation(cr);
+
+ /* shift out answer that we've consumed */
+ buflen -= buf.len;
+ memmove((unsigned char *)&buf, (unsigned char *)&buf + buf.len, buflen);
+ }
+#else /* USE_LWRES */
+ for (;;)
+ {
+ err_t ugh;
+ char *nlp = memchr(buf, '\n', buflen);
+
+ if (nlp == NULL)
+ break;
+
+ /* we've got a line */
+ *nlp++ = '\0';
+
+ DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL | DBG_DNS
+ , DBG_log("lwdns: %s", buf));
+
+ /* process lwdnsq_answer may modify buf, so make a copy. */
+ buf_copy[0]='\0';
+ strncat(buf_copy, buf, sizeof(buf_copy));
+
+ ugh = process_lwdnsq_answer(buf_copy);
+ if (ugh != NULL)
+ plog("failure processing lwdnsq output: %s; record: %s"
+ , ugh, buf);
+
+ passert(GLOBALS_ARE_RESET());
+ reset_globals();
+
+ /* shift out answer that we've consumed */
+ buflen -= nlp - buf;
+ memmove(buf, nlp, buflen);
+ }
+#endif /* USE_LWRES */
+}
diff --git a/programs/pluto/dnskey.h b/programs/pluto/dnskey.h
new file mode 100644
index 000000000..0b9f0ee33
--- /dev/null
+++ b/programs/pluto/dnskey.h
@@ -0,0 +1,84 @@
+/* Find public key in DNS
+ * Copyright (C) 2000-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: dnskey.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+extern int
+ adns_qfd, /* file descriptor for sending queries to adns */
+ adns_afd; /* file descriptor for receiving answers from adns */
+extern const char *pluto_adns_option; /* path from --pluto_adns */
+extern void init_adns(void);
+extern void stop_adns(void);
+extern void handle_adns_answer(void);
+
+extern bool unsent_ADNS_queries;
+extern void send_unsent_ADNS_queries(void);
+
+/* (common prefix of) stuff remembered between async query and answer.
+ * Filled in by start_adns_query.
+ * Freed by call to release_adns_continuation.
+ */
+
+struct adns_continuation; /* forward declaration (not far!) */
+
+typedef void (*cont_fn_t)(struct adns_continuation *cr, err_t ugh);
+
+struct adns_continuation {
+ unsigned long qtid; /* query transaction id number */
+ int type; /* T_TXT or T_KEY, selecting rr type of interest */
+ cont_fn_t cont_fn; /* function to carry on suspended work */
+ struct id id; /* subject of query */
+ bool sgw_specified;
+ struct id sgw_id; /* peer, if constrained */
+ lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
+ struct gw_info *gateways_from_dns; /* answer, if looking for our TXT rrs */
+#ifdef USE_KEYRR
+ struct pubkey_list *keys_from_dns; /* answer, if looking for KEY rrs */
+#endif
+ struct adns_continuation *previous, *next;
+ struct pubkey *last_info; /* the last structure we accumulated */
+#ifdef USE_LWRES
+ bool used; /* have we called the cont_fn yet? */
+ struct {
+ u_char name_buf[NS_MAXDNAME + 2];
+ } query;
+#else /* ! USE_LWRES */
+ struct adns_query query;
+#endif /* ! USE_LWRES */
+};
+
+extern err_t start_adns_query(const struct id *id /* domain to query */
+ , const struct id *sgw_id /* if non-null, any accepted gw_info must match */
+ , int type /* T_TXT or T_KEY, selecting rr type of interest */
+ , cont_fn_t cont_fn /* continuation function */
+ , struct adns_continuation *cr);
+
+
+/* Gateway info gleaned from reverse DNS of client */
+struct gw_info {
+ unsigned refcnt; /* reference counted! */
+ unsigned pref; /* preference: lower is better */
+#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */
+ struct id client_id; /* id of client of peer */
+ struct id gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */
+ bool gw_key_present;
+ struct pubkey *key;
+ struct gw_info *next;
+};
+
+extern void gw_addref(struct gw_info *gw)
+ , gw_delref(struct gw_info **gwp);
+
+extern void reset_adns_restart_count(void);
+
diff --git a/programs/pluto/dsa.c b/programs/pluto/dsa.c
new file mode 100644
index 000000000..c5982fbf4
--- /dev/null
+++ b/programs/pluto/dsa.c
@@ -0,0 +1,476 @@
+/* dsa.c - DSA signature scheme
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef PLUTO
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "rnd.h"
+#include "gcryptfix.h"
+#else /*! PLUTO */
+/* #include <config.h> */
+#endif /* !PLUTO */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef PLUTO
+/* #include <assert.h> */
+/* #include "util.h" */
+/* #include "mpi.h" */
+/* #include "cipher.h" */
+#endif
+
+#include "dsa.h"
+
+typedef struct {
+ MPI p; /* prime */
+ MPI q; /* group order */
+ MPI g; /* group generator */
+ MPI y; /* g^x mod p */
+} DSA_public_key;
+
+
+typedef struct {
+ MPI p; /* prime */
+ MPI q; /* group order */
+ MPI g; /* group generator */
+ MPI y; /* g^x mod p */
+ MPI x; /* secret exponent */
+} DSA_secret_key;
+
+
+static MPI gen_k( MPI q );
+static void test_keys( DSA_secret_key *sk, unsigned qbits );
+static int check_secret_key( DSA_secret_key *sk );
+static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
+static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
+static int verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
+
+static void
+progress( int c )
+{
+ fputc( c, stderr );
+}
+
+
+/****************
+ * Generate a random secret exponent k less than q
+ */
+static MPI
+gen_k( MPI q )
+{
+ MPI k = mpi_alloc_secure( mpi_get_nlimbs(q) );
+ unsigned int nbits = mpi_get_nbits(q);
+ unsigned int nbytes = (nbits+7)/8;
+ char *rndbuf = NULL;
+
+ if( DBG_CIPHER )
+ log_debug("choosing a random k ");
+ for(;;) {
+ if( DBG_CIPHER )
+ progress('.');
+
+ if( !rndbuf || nbits < 32 ) {
+ m_free(rndbuf);
+ rndbuf = get_random_bits( nbits, 1, 1 );
+ }
+ else { /* change only some of the higher bits */
+ /* we could imporove this by directly requesting more memory
+ * at the first call to get_random_bits() and use this the here
+ * maybe it is easier to do this directly in random.c */
+ char *pp = get_random_bits( 32, 1, 1 );
+ memcpy( rndbuf,pp, 4 );
+ m_free(pp);
+ }
+ mpi_set_buffer( k, rndbuf, nbytes, 0 );
+ if( mpi_test_bit( k, nbits-1 ) )
+ mpi_set_highbit( k, nbits-1 );
+ else {
+ mpi_set_highbit( k, nbits-1 );
+ mpi_clear_bit( k, nbits-1 );
+ }
+
+ if( !(mpi_cmp( k, q ) < 0) ) { /* check: k < q */
+ if( DBG_CIPHER )
+ progress('+');
+ continue; /* no */
+ }
+ if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
+ if( DBG_CIPHER )
+ progress('-');
+ continue; /* no */
+ }
+ break; /* okay */
+ }
+ m_free(rndbuf);
+ if( DBG_CIPHER )
+ progress('\n');
+
+ return k;
+}
+
+
+static void
+test_keys( DSA_secret_key *sk, unsigned qbits )
+{
+ DSA_public_key pk;
+ MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+ MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+ MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+
+ pk.p = sk->p;
+ pk.q = sk->q;
+ pk.g = sk->g;
+ pk.y = sk->y;
+ /*mpi_set_bytes( test, qbits, get_random_byte, 0 );*/
+ { char *p = get_random_bits( qbits, 0, 0 );
+ mpi_set_buffer( test, p, (qbits+7)/8, 0 );
+ m_free(p);
+ }
+
+ sign( out1_a, out1_b, test, sk );
+ if( !verify( out1_a, out1_b, test, &pk ) )
+ log_fatal("DSA:: sign, verify failed\n");
+
+ mpi_free( test );
+ mpi_free( out1_a );
+ mpi_free( out1_b );
+}
+
+
+
+/****************
+ * Generate a DSA key pair with a key of size NBITS
+ * Returns: 2 structures filled with all needed values
+ * and an array with the n-1 factors of (p-1)
+ */
+static void
+generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors )
+{
+ MPI p; /* the prime */
+ MPI q; /* the 160 bit prime factor */
+ MPI g; /* the generator */
+ MPI y; /* g^x mod p */
+ MPI x; /* the secret exponent */
+ MPI h, e; /* helper */
+ unsigned qbits;
+ byte *rndbuf;
+
+ assert( nbits >= 512 && nbits <= 1024 );
+
+ qbits = 160;
+ p = generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
+ /* get q out of factors */
+ q = mpi_copy((*ret_factors)[0]);
+ if( mpi_get_nbits(q) != qbits )
+ BUG();
+
+ /* find a generator g (h and e are helpers)*/
+ /* e = (p-1)/q */
+ e = mpi_alloc( mpi_get_nlimbs(p) );
+ mpi_sub_ui( e, p, 1 );
+ mpi_fdiv_q( e, e, q );
+ g = mpi_alloc( mpi_get_nlimbs(p) );
+ h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
+ do {
+ mpi_add_ui( h, h, 1 );
+ /* g = h^e mod p */
+ mpi_powm( g, h, e, p );
+ } while( !mpi_cmp_ui( g, 1 ) ); /* continue until g != 1 */
+
+ /* select a random number which has these properties:
+ * 0 < x < q-1
+ * This must be a very good random number because this
+ * is the secret part. */
+ if( DBG_CIPHER )
+ log_debug("choosing a random x ");
+ assert( qbits >= 160 );
+ x = mpi_alloc_secure( mpi_get_nlimbs(q) );
+ mpi_sub_ui( h, q, 1 ); /* put q-1 into h */
+ rndbuf = NULL;
+ do {
+ if( DBG_CIPHER )
+ progress('.');
+ if( !rndbuf )
+ rndbuf = get_random_bits( qbits, 2, 1 );
+ else { /* change only some of the higher bits (= 2 bytes)*/
+ char *r = get_random_bits( 16, 2, 1 );
+ memcpy(rndbuf, r, 16/8 );
+ m_free(r);
+ }
+ mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
+ mpi_clear_highbit( x, qbits+1 );
+ } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
+ m_free(rndbuf);
+ mpi_free( e );
+ mpi_free( h );
+
+ /* y = g^x mod p */
+ y = mpi_alloc( mpi_get_nlimbs(p) );
+ mpi_powm( y, g, x, p );
+
+ if( DBG_CIPHER ) {
+ progress('\n');
+ log_mpidump("dsa p= ", p );
+ log_mpidump("dsa q= ", q );
+ log_mpidump("dsa g= ", g );
+ log_mpidump("dsa y= ", y );
+ log_mpidump("dsa x= ", x );
+ }
+
+ /* copy the stuff to the key structures */
+ sk->p = p;
+ sk->q = q;
+ sk->g = g;
+ sk->y = y;
+ sk->x = x;
+
+ /* now we can test our keys (this should never fail!) */
+ test_keys( sk, qbits );
+}
+
+
+
+/****************
+ * Test whether the secret key is valid.
+ * Returns: if this is a valid key.
+ */
+static int
+check_secret_key( DSA_secret_key *sk )
+{
+ int rc;
+ MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
+
+ mpi_powm( y, sk->g, sk->x, sk->p );
+ rc = !mpi_cmp( y, sk->y );
+ mpi_free( y );
+ return rc;
+}
+
+
+
+/****************
+ * Make a DSA signature from HASH and put it into r and s.
+ */
+
+static void
+sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey )
+{
+ MPI k;
+ MPI kinv;
+ MPI tmp;
+
+ /* select a random k with 0 < k < q */
+ k = gen_k( skey->q );
+
+ /* r = (a^k mod p) mod q */
+ mpi_powm( r, skey->g, k, skey->p );
+ mpi_fdiv_r( r, r, skey->q );
+
+ /* kinv = k^(-1) mod q */
+ kinv = mpi_alloc( mpi_get_nlimbs(k) );
+ mpi_invm(kinv, k, skey->q );
+
+ /* s = (kinv * ( hash + x * r)) mod q */
+ tmp = mpi_alloc( mpi_get_nlimbs(skey->p) );
+ mpi_mul( tmp, skey->x, r );
+ mpi_add( tmp, tmp, hash );
+ mpi_mulm( s , kinv, tmp, skey->q );
+
+ mpi_free(k);
+ mpi_free(kinv);
+ mpi_free(tmp);
+}
+
+
+/****************
+ * Returns true if the signature composed from R and S is valid.
+ */
+static int
+verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey )
+{
+ int rc;
+ MPI w, u1, u2, v;
+ MPI base[3];
+ MPI exp[3];
+
+
+ if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
+ return 0; /* assertion 0 < r < q failed */
+ if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
+ return 0; /* assertion 0 < s < q failed */
+
+ w = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+ u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+ u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+ v = mpi_alloc( mpi_get_nlimbs(pkey->p) );
+
+ /* w = s^(-1) mod q */
+ mpi_invm( w, s, pkey->q );
+
+ /* u1 = (hash * w) mod q */
+ mpi_mulm( u1, hash, w, pkey->q );
+
+ /* u2 = r * w mod q */
+ mpi_mulm( u2, r, w, pkey->q );
+
+ /* v = g^u1 * y^u2 mod p mod q */
+ base[0] = pkey->g; exp[0] = u1;
+ base[1] = pkey->y; exp[1] = u2;
+ base[2] = NULL; exp[2] = NULL;
+ mpi_mulpowm( v, base, exp, pkey->p );
+ mpi_fdiv_r( v, v, pkey->q );
+
+ rc = !mpi_cmp( v, r );
+
+ mpi_free(w);
+ mpi_free(u1);
+ mpi_free(u2);
+ mpi_free(v);
+ return rc;
+}
+
+
+/*********************************************
+ ************** interface ******************
+ *********************************************/
+
+int
+dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+ DSA_secret_key sk;
+
+ if( algo != PUBKEY_ALGO_DSA )
+ return G10ERR_PUBKEY_ALGO;
+
+ generate( &sk, nbits, retfactors );
+ skey[0] = sk.p;
+ skey[1] = sk.q;
+ skey[2] = sk.g;
+ skey[3] = sk.y;
+ skey[4] = sk.x;
+ return 0;
+}
+
+
+int
+dsa_check_secret_key( int algo, MPI *skey )
+{
+ DSA_secret_key sk;
+
+ if( algo != PUBKEY_ALGO_DSA )
+ return G10ERR_PUBKEY_ALGO;
+ if( !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.q = skey[1];
+ sk.g = skey[2];
+ sk.y = skey[3];
+ sk.x = skey[4];
+ if( !check_secret_key( &sk ) )
+ return G10ERR_BAD_SECKEY;
+
+ return 0;
+}
+
+
+
+int
+dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+ DSA_secret_key sk;
+
+ if( algo != PUBKEY_ALGO_DSA )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.q = skey[1];
+ sk.g = skey[2];
+ sk.y = skey[3];
+ sk.x = skey[4];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+ resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+ sign( resarr[0], resarr[1], data, &sk );
+ return 0;
+}
+
+int
+dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED)
+{
+ DSA_public_key pk;
+
+ if( algo != PUBKEY_ALGO_DSA )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data[0] || !data[1] || !hash
+ || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] )
+ return G10ERR_BAD_MPI;
+
+ pk.p = pkey[0];
+ pk.q = pkey[1];
+ pk.g = pkey[2];
+ pk.y = pkey[3];
+ if( !verify( data[0], data[1], hash, &pk ) )
+ return G10ERR_BAD_SIGN;
+ return 0;
+}
+
+
+
+unsigned
+dsa_get_nbits( int algo, MPI *pkey )
+{
+ if( algo != PUBKEY_ALGO_DSA )
+ return 0;
+ return mpi_get_nbits( pkey[0] );
+}
+
+
+/****************
+ * Return some information about the algorithm. We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ * the ALGO is invalid.
+ * Usage: Bit 0 set : allows signing
+ * 1 set : allows encryption
+ */
+const char *
+dsa_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
+ int *use )
+{
+ *npkey = 4;
+ *nskey = 5;
+ *nenc = 0;
+ *nsig = 2;
+
+ switch( algo ) {
+ case PUBKEY_ALGO_DSA: *use = PUBKEY_USAGE_SIG; return "DSA";
+ default: *use = 0; return NULL;
+ }
+}
+
+
diff --git a/programs/pluto/dsa.h b/programs/pluto/dsa.h
new file mode 100644
index 000000000..1456d65b6
--- /dev/null
+++ b/programs/pluto/dsa.h
@@ -0,0 +1,32 @@
+/* dsa.h - DSA signature scheme
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_DSA_H
+#define G10_DSA_H
+
+int dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+int dsa_check_secret_key( int algo, MPI *skey );
+int dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey );
+int dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI), void *opaquev );
+unsigned dsa_get_nbits( int algo, MPI *pkey );
+const char *dsa_get_info( int algo, int *npkey, int *nskey,
+ int *nenc, int *nsig, int *use );
+
+#endif /*G10_DSA_H*/
diff --git a/programs/pluto/elgamal.c b/programs/pluto/elgamal.c
new file mode 100644
index 000000000..0c099bb90
--- /dev/null
+++ b/programs/pluto/elgamal.c
@@ -0,0 +1,613 @@
+/* elgamal.c - ElGamal Public Key encryption
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * For a description of the algorithm, see:
+ * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
+ * ISBN 0-471-11709-9. Pages 476 ff.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef PLUTO
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "rnd.h"
+#include "gcryptfix.h"
+#else /*! PLUTO */
+/* #include <config.h> */
+#endif /* !PLUTO */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef PLUTO
+/* #include "util.h" */
+/* #include "mpi.h" */
+/* #include "cipher.h" */
+#endif
+
+#include "elgamal.h"
+
+typedef struct {
+ MPI p; /* prime */
+ MPI g; /* group generator */
+ MPI y; /* g^x mod p */
+} ELG_public_key;
+
+
+typedef struct {
+ MPI p; /* prime */
+ MPI g; /* group generator */
+ MPI y; /* g^x mod p */
+ MPI x; /* secret exponent */
+} ELG_secret_key;
+
+
+static void test_keys( ELG_secret_key *sk, unsigned nbits );
+static MPI gen_k( MPI p );
+static void generate( ELG_secret_key *sk, unsigned nbits, MPI **factors );
+static int check_secret_key( ELG_secret_key *sk );
+static void encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey );
+static void decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey );
+static void sign(MPI a, MPI b, MPI input, ELG_secret_key *skey);
+static int verify(MPI a, MPI b, MPI input, ELG_public_key *pkey);
+
+
+static void
+progress( int c )
+{
+ fputc( c, stderr );
+}
+
+
+static void
+test_keys( ELG_secret_key *sk, unsigned nbits )
+{
+ ELG_public_key pk;
+ MPI test = mpi_alloc( 0 );
+ MPI out1_a = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ MPI out1_b = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+
+ pk.p = sk->p;
+ pk.g = sk->g;
+ pk.y = sk->y;
+
+ /*mpi_set_bytes( test, nbits, get_random_byte, 0 );*/
+ { char *p = get_random_bits( nbits, 0, 0 );
+ mpi_set_buffer( test, p, (nbits+7)/8, 0 );
+ m_free(p);
+ }
+
+ encrypt( out1_a, out1_b, test, &pk );
+ decrypt( out2, out1_a, out1_b, sk );
+ if( mpi_cmp( test, out2 ) )
+ log_fatal("ElGamal operation: encrypt, decrypt failed\n");
+
+ sign( out1_a, out1_b, test, sk );
+ if( !verify( out1_a, out1_b, test, &pk ) )
+ log_fatal("ElGamal operation: sign, verify failed\n");
+
+ mpi_free( test );
+ mpi_free( out1_a );
+ mpi_free( out1_b );
+ mpi_free( out2 );
+}
+
+
+/****************
+ * generate a random secret exponent k from prime p, so
+ * that k is relatively prime to p-1
+ */
+static MPI
+gen_k( MPI p )
+{
+ MPI k = mpi_alloc_secure( 0 );
+ MPI temp = mpi_alloc( mpi_get_nlimbs(p) );
+ MPI p_1 = mpi_copy(p);
+ unsigned int nbits = mpi_get_nbits(p);
+ unsigned int nbytes = (nbits+7)/8;
+ char *rndbuf = NULL;
+
+ if( DBG_CIPHER )
+ log_debug("choosing a random k ");
+ mpi_sub_ui( p_1, p, 1);
+ for(;;) {
+ if( DBG_CIPHER )
+ progress('.');
+ if( !rndbuf || nbits < 32 ) {
+ m_free(rndbuf);
+ rndbuf = get_random_bits( nbits, 1, 1 );
+ }
+ else { /* change only some of the higher bits */
+ /* we could imporove this by directly requesting more memory
+ * at the first call to get_random_bits() and use this the here
+ * maybe it is easier to do this directly in random.c */
+ char *pp = get_random_bits( 32, 1, 1 );
+ memcpy( rndbuf,pp, 4 );
+ m_free(pp);
+ }
+ mpi_set_buffer( k, rndbuf, nbytes, 0 );
+
+ for(;;) {
+ /* make sure that the number is of the exact lenght */
+ if( mpi_test_bit( k, nbits-1 ) )
+ mpi_set_highbit( k, nbits-1 );
+ else {
+ mpi_set_highbit( k, nbits-1 );
+ mpi_clear_bit( k, nbits-1 );
+ }
+ if( !(mpi_cmp( k, p_1 ) < 0) ) { /* check: k < (p-1) */
+ if( DBG_CIPHER )
+ progress('+');
+ break; /* no */
+ }
+ if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
+ if( DBG_CIPHER )
+ progress('-');
+ break; /* no */
+ }
+ if( mpi_gcd( temp, k, p_1 ) )
+ goto found; /* okay, k is relatively prime to (p-1) */
+ mpi_add_ui( k, k, 1 );
+ }
+ }
+ found:
+ m_free(rndbuf);
+ if( DBG_CIPHER )
+ progress('\n');
+ mpi_free(p_1);
+ mpi_free(temp);
+
+ return k;
+}
+
+/****************
+ * Generate a key pair with a key of size NBITS
+ * Returns: 2 structures filles with all needed values
+ * and an array with n-1 factors of (p-1)
+ */
+static void
+generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
+{
+ MPI p; /* the prime */
+ MPI p_min1;
+ MPI g;
+ MPI x; /* the secret exponent */
+ MPI y;
+ MPI temp;
+ unsigned qbits;
+ byte *rndbuf;
+
+ p_min1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ temp = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ if( nbits < 512 )
+ qbits = 120;
+ else if( nbits <= 1024 )
+ qbits = 160;
+ else if( nbits <= 2048 )
+ qbits = 200;
+ else
+ qbits = 240;
+ g = mpi_alloc(1);
+ p = generate_elg_prime( 0, nbits, qbits, g, ret_factors );
+ mpi_sub_ui(p_min1, p, 1);
+
+
+ /* select a random number which has these properties:
+ * 0 < x < p-1
+ * This must be a very good random number because this is the
+ * secret part. The prime is public and may be shared anyway,
+ * so a random generator level of 1 is used for the prime.
+ */
+ x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB );
+ if( DBG_CIPHER )
+ log_debug("choosing a random x ");
+ rndbuf = NULL;
+ do {
+ if( DBG_CIPHER )
+ progress('.');
+ if( rndbuf ) { /* change only some of the higher bits */
+ if( nbits < 16 ) {/* should never happen ... */
+ m_free(rndbuf);
+ rndbuf = get_random_bits( nbits, 2, 1 );
+ }
+ else {
+ char *r = get_random_bits( 16, 2, 1 );
+ memcpy(rndbuf, r, 16/8 );
+ m_free(r);
+ }
+ }
+ else
+ rndbuf = get_random_bits( nbits, 2, 1 );
+ mpi_set_buffer( x, rndbuf, (nbits+7)/8, 0 );
+ mpi_clear_highbit( x, nbits+1 );
+ } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
+ m_free(rndbuf);
+
+ y = mpi_alloc(nbits/BITS_PER_MPI_LIMB);
+ mpi_powm( y, g, x, p );
+
+ if( DBG_CIPHER ) {
+ progress('\n');
+ log_mpidump("elg p= ", p );
+ log_mpidump("elg g= ", g );
+ log_mpidump("elg y= ", y );
+ log_mpidump("elg x= ", x );
+ }
+
+ /* copy the stuff to the key structures */
+ sk->p = p;
+ sk->g = g;
+ sk->y = y;
+ sk->x = x;
+
+ /* now we can test our keys (this should never fail!) */
+ test_keys( sk, nbits - 64 );
+
+ mpi_free( p_min1 );
+ mpi_free( temp );
+}
+
+
+/****************
+ * Test whether the secret key is valid.
+ * Returns: if this is a valid key.
+ */
+static int
+check_secret_key( ELG_secret_key *sk )
+{
+ int rc;
+ MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
+
+ mpi_powm( y, sk->g, sk->x, sk->p );
+ rc = !mpi_cmp( y, sk->y );
+ mpi_free( y );
+ return rc;
+}
+
+
+static void
+encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey )
+{
+ MPI k;
+
+ /* Note: maybe we should change the interface, so that it
+ * is possible to check that input is < p and return an
+ * error code.
+ */
+
+ k = gen_k( pkey->p );
+ mpi_powm( a, pkey->g, k, pkey->p );
+ /* b = (y^k * input) mod p
+ * = ((y^k mod p) * (input mod p)) mod p
+ * and because input is < p
+ * = ((y^k mod p) * input) mod p
+ */
+ mpi_powm( b, pkey->y, k, pkey->p );
+ mpi_mulm( b, b, input, pkey->p );
+ #if 0
+ if( DBG_CIPHER ) {
+ log_mpidump("elg encrypted y= ", pkey->y);
+ log_mpidump("elg encrypted p= ", pkey->p);
+ log_mpidump("elg encrypted k= ", k);
+ log_mpidump("elg encrypted M= ", input);
+ log_mpidump("elg encrypted a= ", a);
+ log_mpidump("elg encrypted b= ", b);
+ }
+ #endif
+ mpi_free(k);
+}
+
+
+
+
+static void
+decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey )
+{
+ MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
+
+ /* output = b/(a^x) mod p */
+
+ mpi_powm( t1, a, skey->x, skey->p );
+ mpi_invm( t1, t1, skey->p );
+ mpi_mulm( output, b, t1, skey->p );
+ #if 0
+ if( DBG_CIPHER ) {
+ log_mpidump("elg decrypted x= ", skey->x);
+ log_mpidump("elg decrypted p= ", skey->p);
+ log_mpidump("elg decrypted a= ", a);
+ log_mpidump("elg decrypted b= ", b);
+ log_mpidump("elg decrypted M= ", output);
+ }
+ #endif
+ mpi_free(t1);
+}
+
+
+/****************
+ * Make an Elgamal signature out of INPUT
+ */
+
+static void
+sign(MPI a, MPI b, MPI input, ELG_secret_key *skey )
+{
+ MPI k;
+ MPI t = mpi_alloc( mpi_get_nlimbs(a) );
+ MPI inv = mpi_alloc( mpi_get_nlimbs(a) );
+ MPI p_1 = mpi_copy(skey->p);
+
+ /*
+ * b = (t * inv) mod (p-1)
+ * b = (t * inv(k,(p-1),(p-1)) mod (p-1)
+ * b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1)
+ *
+ */
+ mpi_sub_ui(p_1, p_1, 1);
+ k = gen_k( skey->p );
+ mpi_powm( a, skey->g, k, skey->p );
+ mpi_mul(t, skey->x, a );
+ mpi_subm(t, input, t, p_1 );
+ while( mpi_is_neg(t) )
+ mpi_add(t, t, p_1);
+ mpi_invm(inv, k, p_1 );
+ mpi_mulm(b, t, inv, p_1 );
+
+ #if 0
+ if( DBG_CIPHER ) {
+ log_mpidump("elg sign p= ", skey->p);
+ log_mpidump("elg sign g= ", skey->g);
+ log_mpidump("elg sign y= ", skey->y);
+ log_mpidump("elg sign x= ", skey->x);
+ log_mpidump("elg sign k= ", k);
+ log_mpidump("elg sign M= ", input);
+ log_mpidump("elg sign a= ", a);
+ log_mpidump("elg sign b= ", b);
+ }
+ #endif
+ mpi_free(k);
+ mpi_free(t);
+ mpi_free(inv);
+ mpi_free(p_1);
+}
+
+
+/****************
+ * Returns true if the signature composed of A and B is valid.
+ */
+static int
+verify(MPI a, MPI b, MPI input, ELG_public_key *pkey )
+{
+ int rc;
+ MPI t1;
+ MPI t2;
+ MPI base[4];
+ MPI exp[4];
+
+ if( !(mpi_cmp_ui( a, 0 ) > 0 && mpi_cmp( a, pkey->p ) < 0) )
+ return 0; /* assertion 0 < a < p failed */
+
+ t1 = mpi_alloc( mpi_get_nlimbs(a) );
+ t2 = mpi_alloc( mpi_get_nlimbs(a) );
+
+ #if 0
+ /* t1 = (y^a mod p) * (a^b mod p) mod p */
+ mpi_powm( t1, pkey->y, a, pkey->p );
+ mpi_powm( t2, a, b, pkey->p );
+ mpi_mulm( t1, t1, t2, pkey->p );
+
+ /* t2 = g ^ input mod p */
+ mpi_powm( t2, pkey->g, input, pkey->p );
+
+ rc = !mpi_cmp( t1, t2 );
+ #elif 0
+ /* t1 = (y^a mod p) * (a^b mod p) mod p */
+ base[0] = pkey->y; exp[0] = a;
+ base[1] = a; exp[1] = b;
+ base[2] = NULL; exp[2] = NULL;
+ mpi_mulpowm( t1, base, exp, pkey->p );
+
+ /* t2 = g ^ input mod p */
+ mpi_powm( t2, pkey->g, input, pkey->p );
+
+ rc = !mpi_cmp( t1, t2 );
+ #else
+ /* t1 = g ^ - input * y ^ a * a ^ b mod p */
+ mpi_invm(t2, pkey->g, pkey->p );
+ base[0] = t2 ; exp[0] = input;
+ base[1] = pkey->y; exp[1] = a;
+ base[2] = a; exp[2] = b;
+ base[3] = NULL; exp[3] = NULL;
+ mpi_mulpowm( t1, base, exp, pkey->p );
+ rc = !mpi_cmp_ui( t1, 1 );
+
+ #endif
+
+ mpi_free(t1);
+ mpi_free(t2);
+ return rc;
+}
+
+/*********************************************
+ ************** interface ******************
+ *********************************************/
+
+int
+elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+ ELG_secret_key sk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+
+ generate( &sk, nbits, retfactors );
+ skey[0] = sk.p;
+ skey[1] = sk.g;
+ skey[2] = sk.y;
+ skey[3] = sk.x;
+ return 0;
+}
+
+
+int
+elg_check_secret_key( int algo, MPI *skey )
+{
+ ELG_secret_key sk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !skey[0] || !skey[1] || !skey[2] || !skey[3] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.g = skey[1];
+ sk.y = skey[2];
+ sk.x = skey[3];
+ if( !check_secret_key( &sk ) )
+ return G10ERR_BAD_SECKEY;
+
+ return 0;
+}
+
+
+
+int
+elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
+{
+ ELG_public_key pk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data || !pkey[0] || !pkey[1] || !pkey[2] )
+ return G10ERR_BAD_MPI;
+
+ pk.p = pkey[0];
+ pk.g = pkey[1];
+ pk.y = pkey[2];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
+ resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
+ encrypt( resarr[0], resarr[1], data, &pk );
+ return 0;
+}
+
+int
+elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
+{
+ ELG_secret_key sk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data[0] || !data[1]
+ || !skey[0] || !skey[1] || !skey[2] || !skey[3] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.g = skey[1];
+ sk.y = skey[2];
+ sk.x = skey[3];
+ *result = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) );
+ decrypt( *result, data[0], data[1], &sk );
+ return 0;
+}
+
+int
+elg_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+ ELG_secret_key sk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] )
+ return G10ERR_BAD_MPI;
+
+ sk.p = skey[0];
+ sk.g = skey[1];
+ sk.y = skey[2];
+ sk.x = skey[3];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+ resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+ sign( resarr[0], resarr[1], data, &sk );
+ return 0;
+}
+
+int
+elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED)
+{
+ ELG_public_key pk;
+
+ if( !is_ELGAMAL(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data[0] || !data[1] || !hash
+ || !pkey[0] || !pkey[1] || !pkey[2] )
+ return G10ERR_BAD_MPI;
+
+ pk.p = pkey[0];
+ pk.g = pkey[1];
+ pk.y = pkey[2];
+ if( !verify( data[0], data[1], hash, &pk ) )
+ return G10ERR_BAD_SIGN;
+ return 0;
+}
+
+
+
+unsigned
+elg_get_nbits( int algo, MPI *pkey )
+{
+ if( !is_ELGAMAL(algo) )
+ return 0;
+ return mpi_get_nbits( pkey[0] );
+}
+
+
+/****************
+ * Return some information about the algorithm. We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ * the ALGO is invalid.
+ * Usage: Bit 0 set : allows signing
+ * 1 set : allows encryption
+ * NOTE: This function allows signing also for ELG-E, which is not
+ * okay but a bad hack to allow to work with old gpg keys. The real check
+ * is done in the gnupg ocde depending on the packet version.
+ */
+const char *
+elg_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
+ int *use )
+{
+ *npkey = 3;
+ *nskey = 4;
+ *nenc = 2;
+ *nsig = 2;
+
+ switch( algo ) {
+ case PUBKEY_ALGO_ELGAMAL:
+ *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC;
+ return "ELG";
+ case PUBKEY_ALGO_ELGAMAL_E:
+ *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC;
+ return "ELG-E";
+ default: *use = 0; return NULL;
+ }
+}
+
+
diff --git a/programs/pluto/elgamal.h b/programs/pluto/elgamal.h
new file mode 100644
index 000000000..f104c2a52
--- /dev/null
+++ b/programs/pluto/elgamal.h
@@ -0,0 +1,35 @@
+/* elgamal.h
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_ELGAMAL_H
+#define G10_ELGAMAL_H
+
+int elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+int elg_check_secret_key( int algo, MPI *skey );
+int elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey );
+int elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
+int elg_sign( int algo, MPI *resarr, MPI data, MPI *skey );
+int elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI), void *opaquev );
+unsigned elg_get_nbits( int algo, MPI *pkey );
+const char *elg_get_info( int algo, int *npkey, int *nskey,
+ int *nenc, int *nsig, int *use );
+
+
+#endif /*G10_ELGAMAL_H*/
diff --git a/programs/pluto/fetch.c b/programs/pluto/fetch.c
new file mode 100644
index 000000000..075b88fd2
--- /dev/null
+++ b/programs/pluto/fetch.c
@@ -0,0 +1,1081 @@
+/* Dynamic fetching of X.509 CRLs
+ * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com>
+ * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: fetch.c,v 1.11 2005/11/25 10:08:00 as Exp $
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+
+#ifdef THREADS
+#include <pthread.h>
+#endif
+
+#ifdef LIBCURL
+#include <curl/curl.h>
+#endif
+
+#include <freeswan.h>
+
+#ifdef LDAP_VER
+#include <ldap.h>
+#endif
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "id.h"
+#include "asn1.h"
+#include "pem.h"
+#include "x509.h"
+#include "ca.h"
+#include "whack.h"
+#include "ocsp.h"
+#include "crl.h"
+#include "fetch.h"
+
+fetch_req_t empty_fetch_req = {
+ NULL , /* next */
+ 0 , /* installed */
+ 0 , /* trials */
+ { NULL, 0}, /* issuer */
+ { NULL, 0}, /* authKeyID */
+ { NULL, 0}, /* authKeySerialNumber */
+ NULL /* distributionPoints */
+};
+
+/* chained list of crl fetch requests */
+static fetch_req_t *crl_fetch_reqs = NULL;
+
+/* chained list of ocsp fetch requests */
+static ocsp_location_t *ocsp_fetch_reqs = NULL;
+
+#ifdef THREADS
+static pthread_t thread;
+static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t ocsp_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t ca_info_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t crl_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t ocsp_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t fetch_wake_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t fetch_wake_cond = PTHREAD_COND_INITIALIZER;
+
+/*
+ * lock access to my certs and keys
+ */
+void
+lock_certs_and_keys(const char *who)
+{
+ pthread_mutex_lock(&certs_and_keys_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("certs and keys locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to my certs and keys
+ */
+void
+unlock_certs_and_keys(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("certs and keys unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&certs_and_keys_mutex);
+}
+
+/*
+ * lock access to the chained authcert list
+ */
+void
+lock_authcert_list(const char *who)
+{
+ pthread_mutex_lock(&authcert_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("authcert list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the chained authcert list
+ */
+void
+unlock_authcert_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("authcert list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&authcert_list_mutex);
+}
+
+/*
+ * lock access to the chained crl list
+ */
+void
+lock_crl_list(const char *who)
+{
+ pthread_mutex_lock(&crl_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("crl list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the chained crl list
+ */
+void
+unlock_crl_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("crl list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&crl_list_mutex);
+}
+
+/*
+ * lock access to the ocsp cache
+ */
+extern void
+lock_ocsp_cache(const char *who)
+{
+ pthread_mutex_lock(&ocsp_cache_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ocsp cache locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the ocsp cache
+ */
+extern void
+unlock_ocsp_cache(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ocsp cache unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&ocsp_cache_mutex);
+}
+
+/*
+ * lock access to the ca info list
+ */
+extern void
+lock_ca_info_list(const char *who)
+{
+ pthread_mutex_lock(&ca_info_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ca info list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the ca info list
+ */
+extern void
+unlock_ca_info_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ca info list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&ca_info_list_mutex);
+}
+
+/*
+ * lock access to the chained crl fetch request list
+ */
+static void
+lock_crl_fetch_list(const char *who)
+{
+ pthread_mutex_lock(&crl_fetch_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("crl fetch request list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the chained crl fetch request list
+ */
+static void
+unlock_crl_fetch_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("crl fetch request list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&crl_fetch_list_mutex);
+}
+
+/*
+ * lock access to the chained ocsp fetch request list
+ */
+static void
+lock_ocsp_fetch_list(const char *who)
+{
+ pthread_mutex_lock(&ocsp_fetch_list_mutex);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ocsp fetch request list locked by '%s'", who)
+ )
+}
+
+/*
+ * unlock access to the chained ocsp fetch request list
+ */
+static void
+unlock_ocsp_fetch_list(const char *who)
+{
+ DBG(DBG_CONTROLMORE,
+ DBG_log("ocsp fetch request list unlocked by '%s'", who)
+ )
+ pthread_mutex_unlock(&ocsp_fetch_list_mutex);
+}
+
+/*
+ * wakes up the sleeping fetch thread
+ */
+void
+wake_fetch_thread(const char *who)
+{
+ if (crl_check_interval > 0)
+ {
+ DBG(DBG_CONTROLMORE,
+ DBG_log("fetch thread wake call by '%s'", who)
+ )
+ pthread_mutex_lock(&fetch_wake_mutex);
+ pthread_cond_signal(&fetch_wake_cond);
+ pthread_mutex_unlock(&fetch_wake_mutex);
+ }
+}
+#else /* !THREADS */
+#define lock_crl_fetch_list(who) /* do nothing */
+#define unlock_crl_fetch_list(who) /* do nothing */
+#define lock_ocsp_fetch_list(who) /* do nothing */
+#define unlock_ocsp_fetch_list(who) /* do nothing */
+#endif /* !THREADS */
+
+/*
+ * free the dynamic memory used to store fetch requests
+ */
+static void
+free_fetch_request(fetch_req_t *req)
+{
+ pfree(req->issuer.ptr);
+ pfreeany(req->authKeySerialNumber.ptr);
+ pfreeany(req->authKeyID.ptr);
+ free_generalNames(req->distributionPoints, TRUE);
+ pfree(req);
+}
+
+/* writes data into a dynamically resizeable chunk_t
+ * needed for libcurl responses
+ */
+size_t
+write_buffer(void *ptr, size_t size, size_t nmemb, void *data)
+{
+ size_t realsize = size * nmemb;
+ chunk_t *mem = (chunk_t*)data;
+
+ mem->ptr = (u_char *)realloc(mem->ptr, mem->len + realsize);
+ if (mem->ptr) {
+ memcpy(&(mem->ptr[mem->len]), ptr, realsize);
+ mem->len += realsize;
+ }
+ return realsize;
+}
+
+#ifdef THREADS
+/*
+ * fetches a binary blob from a url with libcurl
+ */
+static err_t
+fetch_curl(char *url, chunk_t *blob)
+{
+#ifdef LIBCURL
+ char errorbuffer[CURL_ERROR_SIZE] = "";
+ chunk_t response = empty_chunk;
+ CURLcode res;
+
+ /* get it with libcurl */
+ CURL *curl = curl_easy_init();
+
+ if (curl != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("Trying cURL '%s'", url)
+ )
+
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
+ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorbuffer);
+ curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT);
+
+ res = curl_easy_perform(curl);
+
+ if (res == CURLE_OK)
+ {
+ blob->len = response.len;
+ blob->ptr = alloc_bytes(response.len, "curl blob");
+ memcpy(blob->ptr, response.ptr, response.len);
+ }
+ else
+ {
+ plog("fetching uri (%s) with libcurl failed: %s", url, errorbuffer);
+ }
+ curl_easy_cleanup(curl);
+ /* not using freeanychunk because of realloc (no leak detective) */
+ free(response.ptr);
+ }
+ return strlen(errorbuffer) > 0 ? "libcurl error" : NULL;
+#else /* !LIBCURL */
+ return "warning: not compiled with libcurl support";
+#endif /* !LIBCURL */
+}
+
+#ifdef LDAP_VER
+/*
+ * parses the result returned by an ldap query
+ */
+static err_t
+parse_ldap_result(LDAP * ldap, LDAPMessage *result, chunk_t *blob)
+{
+ err_t ugh = NULL;
+
+ LDAPMessage * entry = ldap_first_entry(ldap, result);
+
+ if (entry != NULL)
+ {
+ BerElement *ber = NULL;
+ char *attr;
+
+ attr = ldap_first_attribute(ldap, entry, &ber);
+
+ if (attr != NULL)
+ {
+ struct berval **values = ldap_get_values_len(ldap, entry, attr);
+
+ if (values != NULL)
+ {
+ if (values[0] != NULL)
+ {
+ blob->len = values[0]->bv_len;
+ blob->ptr = alloc_bytes(blob->len, "ldap blob");
+ memcpy(blob->ptr, values[0]->bv_val, blob->len);
+ if (values[1] != NULL)
+ {
+ plog("warning: more than one value was fetched from LDAP URL");
+ }
+ }
+ else
+ {
+ ugh = "no values in attribute";
+ }
+ ldap_value_free_len(values);
+ }
+ else
+ {
+ ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
+ }
+ ldap_memfree(attr);
+ }
+ else
+ {
+ ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
+ }
+ ber_free(ber, 0);
+ }
+ else
+ {
+ ugh = ldap_err2string(ldap_result2error(ldap, result, 0));
+ }
+ return ugh;
+}
+
+/*
+ * fetches a binary blob from an ldap url
+ */
+static err_t
+fetch_ldap_url(char *url, chunk_t *blob)
+{
+ LDAPURLDesc *lurl;
+ err_t ugh = NULL;
+ int rc;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Trying LDAP URL '%s'", url)
+ )
+
+ rc = ldap_url_parse(url, &lurl);
+
+ if (rc == LDAP_SUCCESS)
+ {
+ LDAP *ldap = ldap_init(lurl->lud_host, lurl->lud_port);
+
+ if (ldap != NULL)
+ {
+ int ldap_version = (LDAP_VER == 2)? LDAP_VERSION2 : LDAP_VERSION3;
+ struct timeval timeout;
+
+ timeout.tv_sec = FETCH_CMD_TIMEOUT;
+ timeout.tv_usec = 0;
+ ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
+ ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
+
+ rc = ldap_simple_bind_s(ldap, NULL, NULL);
+
+ if (rc == LDAP_SUCCESS)
+ {
+ LDAPMessage *result;
+
+ timeout.tv_sec = FETCH_CMD_TIMEOUT;
+ timeout.tv_usec = 0;
+
+ rc = ldap_search_st(ldap, lurl->lud_dn
+ , lurl->lud_scope
+ , lurl->lud_filter
+ , lurl->lud_attrs
+ , 0, &timeout, &result);
+
+ if (rc == LDAP_SUCCESS)
+ {
+ ugh = parse_ldap_result(ldap, result, blob);
+ ldap_msgfree(result);
+ }
+ else
+ {
+ ugh = ldap_err2string(rc);
+ }
+ }
+ else
+ {
+ ugh = ldap_err2string(rc);
+ }
+ ldap_unbind_s(ldap);
+ }
+ else
+ {
+ ugh = "ldap init";
+ }
+ ldap_free_urldesc(lurl);
+ }
+ else
+ {
+ ugh = ldap_err2string(rc);
+ }
+ return ugh;
+}
+#else /* !LDAP_VER */
+static err_t
+fetch_ldap_url(char *url, chunk_t *blob)
+{
+ return "LDAP URL fetching not activated in pluto source code";
+}
+#endif /* !LDAP_VER */
+
+/*
+ * fetch an ASN.1 blob coded in PEM or DER format from a URL
+ */
+static err_t
+fetch_asn1_blob(char *url, chunk_t *blob)
+{
+ err_t ugh = NULL;
+
+ if (strlen(url) >= 4 && strncasecmp(url, "ldap", 4) == 0)
+ {
+ ugh = fetch_ldap_url(url, blob);
+ }
+ else
+ {
+ ugh = fetch_curl(url, blob);
+ }
+ if (ugh != NULL)
+ return ugh;
+
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" fetched blob coded in DER format")
+ )
+ }
+ else
+ {
+ bool pgp = FALSE;
+
+ ugh = pemtobin(blob, NULL, "", &pgp);
+ if (ugh == NULL)
+ {
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" fetched blob coded in PEM format")
+ )
+ }
+ else
+ {
+ ugh = "blob coded in unknown format";
+ pfree(blob->ptr);
+ }
+ }
+ else
+ {
+ pfree(blob->ptr);
+ }
+ }
+ return ugh;
+}
+
+/*
+ * complete a distributionPoint URI with ca information
+ */
+static char*
+complete_uri(chunk_t distPoint, const char *ldaphost)
+{
+ char *uri;
+ char *ptr = distPoint.ptr;
+ size_t len = distPoint.len;
+
+ char *symbol = memchr(ptr, ':', len);
+
+ if (symbol != NULL)
+ {
+ size_t type_len = symbol - ptr;
+
+ if (type_len >= 4 && strncasecmp(ptr, "ldap", 4) == 0)
+ {
+ ptr = symbol + 1;
+ len -= (type_len + 1);
+
+ if (len > 2 && *ptr++ == '/' && *ptr++ == '/')
+ {
+ len -= 2;
+ symbol = memchr(ptr, '/', len);
+
+ if (symbol != NULL && symbol - ptr == 0 && ldaphost != NULL)
+ {
+ uri = alloc_bytes(distPoint.len+strlen(ldaphost)+1, "uri");
+
+ /* insert the ldaphost into the uri */
+ sprintf(uri, "%.*s%s%.*s"
+ , (int)(distPoint.len - len), distPoint.ptr
+ , ldaphost
+ , (int)len, symbol);
+ return uri;
+ }
+ }
+ }
+ }
+
+ /* default action: copy distributionPoint without change */
+ uri = alloc_bytes(distPoint.len+1, "uri");
+ sprintf(uri, "%.*s", (int)distPoint.len, distPoint.ptr);
+ return uri;
+}
+
+/*
+ * try to fetch the crls defined by the fetch requests
+ */
+static void
+fetch_crls(bool cache_crls)
+{
+ fetch_req_t *req;
+ fetch_req_t **reqp;
+
+ lock_crl_fetch_list("fetch_crls");
+ req = crl_fetch_reqs;
+ reqp = &crl_fetch_reqs;
+
+ while (req != NULL)
+ {
+ bool valid_crl = FALSE;
+ chunk_t blob = empty_chunk;
+ generalName_t *gn = req->distributionPoints;
+ const char *ldaphost;
+ ca_info_t *ca;
+
+ lock_ca_info_list("fetch_crls");
+
+ ca = get_ca_info(req->issuer, req->authKeySerialNumber, req->authKeyID);
+ ldaphost = (ca == NULL)? NULL : ca->ldaphost;
+
+ while (gn != NULL)
+ {
+ char *uri = complete_uri(gn->name, ldaphost);
+
+ err_t ugh = fetch_asn1_blob(uri, &blob);
+ pfree(uri);
+
+ if (ugh != NULL)
+ {
+ plog("fetch failed: %s", ugh);
+ }
+ else
+ {
+ chunk_t crl_uri;
+
+ clonetochunk(crl_uri, gn->name.ptr, gn->name.len, "crl uri");
+ if (insert_crl(blob, crl_uri, cache_crls))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("we have a valid crl")
+ )
+ valid_crl = TRUE;
+ break;
+ }
+ }
+ gn = gn->next;
+ }
+
+ unlock_ca_info_list("fetch_crls");
+
+ if (valid_crl)
+ {
+ /* delete fetch request */
+ fetch_req_t *req_free = req;
+
+ req = req->next;
+ *reqp = req;
+ free_fetch_request(req_free);
+ }
+ else
+ {
+ /* try again next time */
+ req->trials++;
+ reqp = &req->next;
+ req = req->next;
+ }
+ }
+ unlock_crl_fetch_list("fetch_crls");
+}
+
+static void
+fetch_ocsp_status(ocsp_location_t* location)
+{
+#ifdef LIBCURL
+ chunk_t request;
+ chunk_t response = empty_chunk;
+
+ CURL* curl;
+ CURLcode res;
+
+ request = build_ocsp_request(location);
+
+ DBG(DBG_CONTROL,
+ DBG_log("sending ocsp request to location '%.*s'"
+ , (int)location->uri.len, location->uri.ptr)
+ )
+ DBG(DBG_RAW,
+ DBG_dump_chunk("OCSP request", request)
+ )
+
+ /* send via http post using libcurl */
+ curl = curl_easy_init();
+
+ if (curl != NULL)
+ {
+ char errorbuffer[CURL_ERROR_SIZE];
+ struct curl_slist *headers = NULL;
+ char* uri = alloc_bytes(location->uri.len+1, "ocsp uri");
+
+ /* we need a null terminated string for curl */
+ memcpy(uri, location->uri.ptr, location->uri.len);
+ *(uri + location->uri.len) = '\0';
+
+ /* set content type header */
+ headers = curl_slist_append(headers, "Content-Type: application/ocsp-request");
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+ curl_easy_setopt(curl, CURLOPT_URL, uri);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer);
+ curl_easy_setopt(curl, CURLOPT_FILE, (void *)&response);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.ptr);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request.len);
+ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorbuffer);
+ curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT);
+
+ res = curl_easy_perform(curl);
+
+ if (res == CURLE_OK)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("received ocsp response")
+ )
+ DBG(DBG_RAW,
+ DBG_dump_chunk("OCSP response:\n", response)
+ )
+ parse_ocsp(location, response);
+ }
+ else
+ {
+ plog("failed to fetch ocsp status from '%s': %s", uri, errorbuffer);
+ }
+ curl_slist_free_all(headers);
+ curl_easy_cleanup(curl);
+ pfree(uri);
+ /* not using freeanychunk because of realloc (no leak detective) */
+ free(response.ptr);
+ }
+ freeanychunk(location->nonce);
+ freeanychunk(request);
+
+ /* increment the trial counter of the unresolved fetch requests */
+ {
+ ocsp_certinfo_t *certinfo = location->certinfo;
+
+ while (certinfo != NULL)
+ {
+ certinfo->trials++;
+ certinfo = certinfo->next;
+ }
+ }
+ return;
+#else /* !LIBCURL */
+ plog("ocsp error: pluto wasn't compiled with libcurl support");
+#endif /* !LIBCURL */
+}
+
+/*
+ * try to fetch the necessary ocsp information
+ */
+static void
+fetch_ocsp(void)
+{
+ ocsp_location_t *location;
+
+ lock_ocsp_fetch_list("fetch_ocsp");
+ location = ocsp_fetch_reqs;
+
+ /* fetch the ocps status for all locations */
+ while (location != NULL)
+ {
+ if (location->certinfo != NULL)
+ fetch_ocsp_status(location);
+ location = location->next;
+ }
+
+ unlock_ocsp_fetch_list("fetch_ocsp");
+}
+
+static void*
+fetch_thread(void *arg)
+{
+ struct timespec wait_interval;
+
+ DBG(DBG_CONTROL,
+ DBG_log("fetch thread started")
+ )
+
+ pthread_mutex_lock(&fetch_wake_mutex);
+
+ while(1)
+ {
+ int status;
+
+ wait_interval.tv_nsec = 0;
+ wait_interval.tv_sec = time(NULL) + crl_check_interval;
+
+ DBG(DBG_CONTROL,
+ DBG_log("next regular crl check in %ld seconds", crl_check_interval)
+ )
+ status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex
+ , &wait_interval);
+
+ if (status == ETIMEDOUT)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log(" ");
+ DBG_log("*time to check crls and the ocsp cache")
+ )
+ check_ocsp();
+ check_crls();
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("fetch thread was woken up")
+ )
+ }
+ fetch_ocsp();
+ fetch_crls(cache_crls);
+ }
+}
+#endif /* THREADS*/
+
+/*
+ * initializes curl and starts the fetching thread
+ */
+void
+init_fetch(void)
+{
+ int status;
+
+#ifdef LIBCURL
+ /* init curl */
+ status = curl_global_init(CURL_GLOBAL_NOTHING);
+ if (status != 0)
+ {
+ plog("libcurl could not be initialized, status = %d", status);
+ }
+#endif /* LIBCURL */
+
+ if (crl_check_interval > 0)
+ {
+#ifdef THREADS
+ status = pthread_create( &thread, NULL, fetch_thread, NULL);
+ if (status != 0)
+ {
+ plog("fetching thread could not be started, status = %d", status);
+ }
+#else /* !THREADS */
+ plog("warning: not compiled with pthread support");
+#endif /* !THREADS */
+ }
+}
+
+void
+free_crl_fetch(void)
+{
+ lock_crl_fetch_list("free_crl_fetch");
+
+ while (crl_fetch_reqs != NULL)
+ {
+ fetch_req_t *req = crl_fetch_reqs;
+ crl_fetch_reqs = req->next;
+ free_fetch_request(req);
+ }
+
+ unlock_crl_fetch_list("free_crl_fetch");
+
+#ifdef LIBCURL
+ if (crl_check_interval > 0)
+ {
+ /* cleanup curl */
+ curl_global_cleanup();
+ }
+#endif /* LIBCURL */
+}
+
+/*
+ * free the chained list of ocsp requests
+ */
+void
+free_ocsp_fetch(void)
+{
+ lock_ocsp_fetch_list("free_ocsp_fetch");
+ free_ocsp_locations(&ocsp_fetch_reqs);
+ unlock_ocsp_fetch_list("free_ocsp_fetch");
+}
+
+
+/*
+ * add additional distribution points
+ */
+void
+add_distribution_points(const generalName_t *newPoints ,generalName_t **distributionPoints)
+{
+ while (newPoints != NULL)
+ {
+ /* skip empty distribution point */
+ if (newPoints->name.len > 0)
+ {
+ bool add = TRUE;
+ generalName_t *gn = *distributionPoints;
+
+ while (gn != NULL)
+ {
+ if (gn->kind == newPoints->kind
+ && gn->name.len == newPoints->name.len
+ && memcmp(gn->name.ptr, newPoints->name.ptr, gn->name.len) == 0)
+ {
+ /* skip if the distribution point is already present */
+ add = FALSE;
+ break;
+ }
+ gn = gn->next;
+ }
+
+ if (add)
+ {
+ /* clone additional distribution point */
+ gn = clone_thing(*newPoints, "generalName");
+ clonetochunk(gn->name, newPoints->name.ptr, newPoints->name.len
+ , "crl uri");
+
+ /* insert additional CRL distribution point */
+ gn->next = *distributionPoints;
+ *distributionPoints = gn;
+ }
+ }
+ newPoints = newPoints->next;
+ }
+}
+
+fetch_req_t*
+build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber
+, chunk_t authKeyID, const generalName_t *gn)
+{
+ fetch_req_t *req = alloc_thing(fetch_req_t, "fetch request");
+ *req = empty_fetch_req;
+
+ /* note current time */
+ req->installed = time(NULL);
+
+ /* clone fields */
+ clonetochunk(req->issuer, issuer.ptr, issuer.len, "issuer");
+ if (authKeySerialNumber.ptr != NULL)
+ {
+ clonetochunk(req->authKeySerialNumber, authKeySerialNumber.ptr
+ , authKeySerialNumber.len, "authKeySerialNumber");
+ }
+ if (authKeyID.ptr != NULL)
+ {
+ clonetochunk(req->authKeyID, authKeyID.ptr, authKeyID.len, "authKeyID");
+ }
+
+ /* copy distribution points */
+ add_distribution_points(gn, &req->distributionPoints);
+
+ return req;
+}
+
+/*
+ * add a crl fetch request to the chained list
+ */
+void
+add_crl_fetch_request(fetch_req_t *req)
+{
+ fetch_req_t *r;
+
+ lock_crl_fetch_list("add_crl_fetch_request");
+ r = crl_fetch_reqs;
+
+ while (r != NULL)
+ {
+ if ((req->authKeyID.ptr != NULL)? same_keyid(req->authKeyID, r->authKeyID)
+ : (same_dn(req->issuer, r->issuer)
+ && same_serial(req->authKeySerialNumber, r->authKeySerialNumber)))
+ {
+ /* there is already a fetch request */
+ DBG(DBG_CONTROL,
+ DBG_log("crl fetch request already exists")
+ )
+
+ /* there might be new distribution points */
+ add_distribution_points(req->distributionPoints, &r->distributionPoints);
+
+ unlock_crl_fetch_list("add_crl_fetch_request");
+ free_fetch_request(req);
+ return;
+ }
+ r = r->next;
+ }
+
+ /* insert new fetch request at the head of the queue */
+ req->next = crl_fetch_reqs;
+ crl_fetch_reqs = req;
+
+ DBG(DBG_CONTROL,
+ DBG_log("crl fetch request added")
+ )
+ unlock_crl_fetch_list("add_crl_fetch_request");
+}
+
+/*
+ * add an ocsp fetch request to the chained list
+ */
+void
+add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber)
+{
+ ocsp_certinfo_t certinfo;
+
+ certinfo.serialNumber = serialNumber;
+
+ lock_ocsp_fetch_list("add_ocsp_fetch_request");
+ add_certinfo(location, &certinfo, &ocsp_fetch_reqs, TRUE);
+ unlock_ocsp_fetch_list("add_ocsp_fetch_request");
+}
+
+/*
+ * list all distribution points
+ */
+void
+list_distribution_points(const generalName_t *gn)
+{
+ bool first_gn = TRUE;
+
+ while (gn != NULL)
+ {
+ whack_log(RC_COMMENT, " %s '%.*s'", (first_gn)? "distPts: "
+ :" ", (int)gn->name.len, gn->name.ptr);
+ first_gn = FALSE;
+ gn = gn->next;
+ }
+}
+
+/*
+ * list all fetch requests in the chained list
+ */
+void
+list_crl_fetch_requests(bool utc)
+{
+ fetch_req_t *req;
+
+ lock_crl_fetch_list("list_crl_fetch_requests");
+ req = crl_fetch_reqs;
+
+ if (req != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of CRL fetch requests:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (req != NULL)
+ {
+ u_char buf[BUF_LEN];
+
+ whack_log(RC_COMMENT, "%s, trials: %d"
+ , timetoa(&req->installed, utc), req->trials);
+ dntoa(buf, BUF_LEN, req->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ if (req->authKeyID.ptr != NULL)
+ {
+ datatot(req->authKeyID.ptr, req->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (req->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(req->authKeySerialNumber.ptr, req->authKeySerialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+ list_distribution_points(req->distributionPoints);
+ req = req->next;
+ }
+ unlock_crl_fetch_list("list_crl_fetch_requests");
+}
+
+void
+list_ocsp_fetch_requests(bool utc)
+{
+ lock_ocsp_fetch_list("list_ocsp_fetch_requests");
+ list_ocsp_locations(ocsp_fetch_reqs, TRUE, utc, FALSE);
+ unlock_ocsp_fetch_list("list_ocsp_fetch_requests");
+
+}
diff --git a/programs/pluto/fetch.h b/programs/pluto/fetch.h
new file mode 100644
index 000000000..6303f37e4
--- /dev/null
+++ b/programs/pluto/fetch.h
@@ -0,0 +1,79 @@
+/* Dynamic fetching of X.509 CRLs
+ * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com>
+ * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: fetch.h,v 1.6 2005/11/25 10:08:00 as Exp $
+ */
+
+#include "x509.h"
+
+#define FETCH_CMD_TIMEOUT 10 /* seconds */
+
+struct ocsp_location; /* forward declaration of ocsp_location defined in ocsp.h */
+
+typedef enum {
+ FETCH_GET = 1,
+ FETCH_POST = 2
+} fetch_request_t;
+
+typedef struct fetch_req fetch_req_t;
+
+struct fetch_req {
+ fetch_req_t *next;
+ time_t installed;
+ int trials;
+ chunk_t issuer;
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ generalName_t *distributionPoints;
+};
+
+#ifdef THREADS
+extern void lock_crl_list(const char *who);
+extern void unlock_crl_list(const char *who);
+extern void lock_ocsp_cache(const char *who);
+extern void unlock_ocsp_cache(const char *who);
+extern void lock_ca_info_list(const char *who);
+extern void unlock_ca_info_list(const char *who);
+extern void lock_authcert_list(const char *who);
+extern void unlock_authcert_list(const char *who);
+extern void lock_certs_and_keys(const char *who);
+extern void unlock_certs_and_keys(const char *who);
+extern void wake_fetch_thread(const char *who);
+#else
+#define lock_crl_list(who) /* do nothing */
+#define unlock_crl_list(who) /* do nothing */
+#define lock_ocsp_cache(who) /* do nothing */
+#define unlock_ocsp_cache(who) /* do nothing */
+#define lock_ca_info_list(who) /* do nothing */
+#define unlock_ca_info_list(who) /* do nothing */
+#define lock_authcert_list(who) /* do nothing */
+#define unlock_authcert_list(who) /* do nothing */
+#define lock_certs_and_keys(who) /* do nothing */
+#define unlock_certs_and_keys(who) /* do nothing */
+#define wake_fetch_thread(who) /* do nothing */
+#endif
+extern void init_fetch(void);
+extern void free_crl_fetch(void);
+extern void free_ocsp_fetch(void);
+extern void add_distribution_points(const generalName_t *newPoints
+ , generalName_t **distributionPoints);
+extern fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber
+ , chunk_t authKeyID, const generalName_t *gn);
+extern void add_crl_fetch_request(fetch_req_t *req);
+extern void add_ocsp_fetch_request(struct ocsp_location *location, chunk_t serialNumber);
+extern void list_distribution_points(const generalName_t *gn);
+extern void list_crl_fetch_requests(bool utc);
+extern void list_ocsp_fetch_requests(bool utc);
+extern size_t write_buffer(void *ptr, size_t size, size_t nmemb, void *data);
+
diff --git a/programs/pluto/foodgroups.c b/programs/pluto/foodgroups.c
new file mode 100644
index 000000000..52e32f0fb
--- /dev/null
+++ b/programs/pluto/foodgroups.c
@@ -0,0 +1,462 @@
+/* Implement policy groups-style control files (aka "foodgroups")
+ * Copyright (C) 2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: foodgroups.c,v 1.2 2004/04/01 18:28:32 as Exp $
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "connections.h"
+#include "foodgroups.h"
+#include "kernel.h"
+#include "lex.h"
+#include "log.h"
+#include "whack.h"
+
+
+/* Food group config files are found in directory fg_path */
+
+#ifndef POLICYGROUPSDIR
+#define POLICYGROUPSDIR "/etc/ipsec.d/policies"
+#endif
+
+const char *policygroups_dir = POLICYGROUPSDIR;
+
+static char *fg_path = NULL;
+static size_t fg_path_space = 0;
+
+
+/* Groups is a list of connections that are policy groups.
+ * The list is updated as group connections are added and deleted.
+ */
+
+struct fg_groups {
+ struct fg_groups *next;
+ struct connection *connection;
+};
+
+static struct fg_groups *groups = NULL;
+
+
+/* Targets is a list of pairs: subnet and its policy group.
+ * This list is bulk-updated on whack --listen and
+ * incrementally updated when group connections are deleted.
+ *
+ * It is ordered by source subnet, and if those are equal, then target subnet.
+ * A subnet is compared by comparing the network, and if those are equal,
+ * comparing the mask.
+ */
+
+struct fg_targets {
+ struct fg_targets *next;
+ struct fg_groups *group;
+ ip_subnet subnet;
+ char *name; /* name of instance of group conn */
+};
+
+static struct fg_targets *targets = NULL;
+
+struct fg_targets *new_targets;
+
+/* ipcmp compares the two ip_address values a and b.
+ * It returns -1, 0, or +1 if a is, respectively,
+ * less than, equal to, or greater than b.
+ */
+static int
+ipcmp(ip_address *a, ip_address *b)
+{
+ if (addrtypeof(a) != addrtypeof(b))
+ {
+ return addrtypeof(a) < addrtypeof(b)? -1 : 1;
+ }
+ else if (sameaddr(a, b))
+ {
+ return 0;
+ }
+ else
+ {
+ const struct sockaddr *sa = sockaddrof(a)
+ , *sb = sockaddrof(b);
+
+ passert(addrtypeof(a) == AF_INET); /* not yet implemented IPv6 version :-( */
+ return (ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr)
+ < ntohl(((const struct sockaddr_in *)sb)->sin_addr.s_addr))
+ ? -1 : 1;
+ }
+}
+
+/* subnetcmp compares the two ip_subnet values a and b.
+ * It returns -1, 0, or +1 if a is, respectively,
+ * less than, equal to, or greater than b.
+ */
+static int
+subnetcmp(const ip_subnet *a, const ip_subnet *b)
+{
+ ip_address neta, maska, netb, maskb;
+ int r;
+
+ networkof(a, &neta);
+ maskof(a, &maska);
+ networkof(b, &netb);
+ maskof(b, &maskb);
+ r = ipcmp(&neta, &netb);
+ if (r == 0)
+ r = ipcmp(&maska, &maskb);
+ return r;
+}
+
+static void
+read_foodgroup(struct fg_groups *g)
+{
+ const char *fgn = g->connection->name;
+ const ip_subnet *lsn = &g->connection->spd.this.client;
+ size_t plen = strlen(policygroups_dir) + 1 + strlen(fgn) + 1;
+ struct file_lex_position flp_space;
+
+ if (plen > fg_path_space)
+ {
+ pfreeany(fg_path);
+ fg_path_space = plen + 10;
+ fg_path = alloc_bytes(fg_path_space, "policy group path");
+ }
+ snprintf(fg_path, fg_path_space, "%s/%s", policygroups_dir, fgn);
+ if (!lexopen(&flp_space, fg_path, TRUE))
+ {
+ DBG(DBG_CONTROL, DBG_log("no group file \"%s\"", fg_path));
+ }
+ else
+ {
+ plog("loading group \"%s\"", fg_path);
+ for (;;)
+ {
+ switch (flp->bdry)
+ {
+ case B_none:
+ {
+ /* !!! this test is not sufficient for distinguishing address families.
+ * We need a notation to specify that a FQDN is to be resolved to IPv6.
+ */
+ const struct af_info *afi = strchr(tok, ':') == NULL
+ ? &af_inet4_info: &af_inet6_info;
+ ip_subnet sn;
+ err_t ugh;
+
+ if (strchr(tok, '/') == NULL)
+ {
+ /* no /, so treat as /32 or V6 equivalent */
+ ip_address t;
+
+ ugh = ttoaddr(tok, 0, afi->af, &t);
+ if (ugh == NULL)
+ ugh = addrtosubnet(&t, &sn);
+ }
+ else
+ {
+ ugh = ttosubnet(tok, 0, afi->af, &sn);
+ }
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s \"%s\""
+ , flp->filename, flp->lino, ugh, tok);
+ }
+ else if (afi->af != AF_INET)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "\"%s\" line %d: unsupported Address Family \"%s\""
+ , flp->filename, flp->lino, tok);
+ }
+ else
+ {
+ /* Find where new entry ought to go in new_targets. */
+ struct fg_targets **pp;
+ int r;
+
+ for (pp = &new_targets; ; pp = &(*pp)->next)
+ {
+ if (*pp == NULL)
+ {
+ r = -1; /* end of list is infinite */
+ break;
+ }
+ r = subnetcmp(lsn, &(*pp)->group->connection->spd.this.client);
+ if (r == 0)
+ r = subnetcmp(&sn, &(*pp)->subnet);
+ if (r <= 0)
+ break;
+ }
+
+ if (r == 0)
+ {
+ char source[SUBNETTOT_BUF];
+
+ subnettot(lsn, 0, source, sizeof(source));
+ loglog(RC_LOG_SERIOUS
+ , "\"%s\" line %d: subnet \"%s\", source %s, already \"%s\""
+ , flp->filename
+ , flp->lino
+ , tok
+ , source
+ , (*pp)->group->connection->name);
+ }
+ else
+ {
+ struct fg_targets *f = alloc_thing(struct fg_targets, "fg_target");
+
+ f->next = *pp;
+ f->group = g;
+ f->subnet = sn;
+ f->name = NULL;
+ *pp = f;
+ }
+ }
+ }
+ (void)shift(); /* next */
+ continue;
+
+ case B_record:
+ flp->bdry = B_none; /* eat the Record Boundary */
+ (void)shift(); /* get real first token */
+ continue;
+
+ case B_file:
+ break; /* done */
+ }
+ break; /* if we reach here, out of loop */
+ }
+ lexclose();
+ }
+}
+
+static void
+free_targets(void)
+{
+ while (targets != NULL)
+ {
+ struct fg_targets *t = targets;
+
+ targets = t->next;
+ pfreeany(t->name);
+ pfree(t);
+ }
+}
+
+void
+load_groups(void)
+{
+ passert(new_targets == NULL);
+
+ /* for each group, add config file targets into new_targets */
+ {
+ struct fg_groups *g;
+
+ for (g = groups; g != NULL; g = g->next)
+ if (oriented(*g->connection))
+ read_foodgroup(g);
+ }
+
+ /* dump new_targets */
+ DBG(DBG_CONTROL,
+ {
+ struct fg_targets *t;
+
+ for (t = new_targets; t != NULL; t = t->next)
+ {
+ char asource[SUBNETTOT_BUF];
+ char atarget[SUBNETTOT_BUF];
+
+ subnettot(&t->group->connection->spd.this.client
+ , 0, asource, sizeof(asource));
+ subnettot(&t->subnet, 0, atarget, sizeof(atarget));
+ DBG_log("%s->%s %s"
+ , asource, atarget
+ , t->group->connection->name);
+ }
+ });
+
+ /* determine and deal with differences between targets and new_targets.
+ * structured like a merge.
+ */
+ {
+ struct fg_targets *op = targets
+ , *np = new_targets;
+
+ while (op != NULL && np != NULL)
+ {
+ int r = subnetcmp(&op->group->connection->spd.this.client
+ , &np->group->connection->spd.this.client);
+
+ if (r == 0)
+ r = subnetcmp(&op->subnet, &np->subnet);
+
+ if (r == 0 && op->group == np->group)
+ {
+ /* unchanged -- steal name & skip over */
+ np->name = op->name;
+ op->name = NULL;
+ op = op->next;
+ np = np->next;
+ }
+ else
+ {
+ /* note: following cases overlap! */
+ if (r <= 0)
+ {
+ remove_group_instance(op->group->connection, op->name);
+ op = op->next;
+ }
+ if (r >= 0)
+ {
+ np->name = add_group_instance(np->group->connection, &np->subnet);
+ np = np->next;
+ }
+ }
+ }
+ for (; op != NULL; op = op->next)
+ remove_group_instance(op->group->connection, op->name);
+ for (; np != NULL; np = np->next)
+ np->name = add_group_instance(np->group->connection, &np->subnet);
+
+ /* update: new_targets replaces targets */
+ free_targets();
+ targets = new_targets;
+ new_targets = NULL;
+ }
+}
+
+
+void
+add_group(struct connection *c)
+{
+ struct fg_groups *g = alloc_thing(struct fg_groups, "policy group");
+
+ g->next = groups;
+ groups = g;
+
+ g->connection = c;
+}
+
+static struct fg_groups *
+find_group(const struct connection *c)
+{
+ struct fg_groups *g;
+
+ for (g = groups; g != NULL && g->connection != c; g = g->next)
+ ;
+ return g;
+}
+
+void
+route_group(struct connection *c)
+{
+ /* it makes no sense to route a connection that is ISAKMP-only */
+ if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy))
+ {
+ loglog(RC_ROUTE, "cannot route an ISAKMP-only group connection");
+ }
+ else
+ {
+ struct fg_groups *g = find_group(c);
+ struct fg_targets *t;
+
+ passert(g != NULL);
+ g->connection->policy |= POLICY_GROUTED;
+ for (t = targets; t != NULL; t = t->next)
+ {
+ if (t->group == g)
+ {
+ struct connection *ci = con_by_name(t->name, FALSE);
+
+ if (ci != NULL)
+ {
+ set_cur_connection(ci);
+ if (!trap_connection(ci))
+ whack_log(RC_ROUTE, "could not route");
+ set_cur_connection(c);
+ }
+ }
+ }
+ }
+}
+
+void
+unroute_group(struct connection *c)
+{
+ struct fg_groups *g = find_group(c);
+ struct fg_targets *t;
+
+ passert(g != NULL);
+ g->connection->policy &= ~POLICY_GROUTED;
+ for (t = targets; t != NULL; t = t->next)
+ {
+ if (t->group == g)
+ {
+ struct connection *ci = con_by_name(t->name, FALSE);
+
+ if (ci != NULL)
+ {
+ set_cur_connection(ci);
+ unroute_connection(ci);
+ set_cur_connection(c);
+ }
+ }
+ }
+}
+
+void
+delete_group(const struct connection *c)
+{
+ struct fg_groups *g;
+
+ /* find and remove from groups */
+ {
+ struct fg_groups **pp;
+
+ for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next)
+ ;
+
+ *pp = g->next;
+ }
+
+ /* find and remove from targets */
+ {
+ struct fg_targets **pp;
+
+ for (pp = &targets; *pp != NULL; )
+ {
+ struct fg_targets *t = *pp;
+
+ if (t->group == g)
+ {
+ *pp = t->next;
+ remove_group_instance(t->group->connection, t->name);
+ pfree(t);
+ /* pp is ready for next iteration */
+ }
+ else
+ {
+ pp = &t->next;
+ }
+ }
+ }
+
+ pfree(g);
+}
diff --git a/programs/pluto/foodgroups.h b/programs/pluto/foodgroups.h
new file mode 100644
index 000000000..7cbbccc44
--- /dev/null
+++ b/programs/pluto/foodgroups.h
@@ -0,0 +1,24 @@
+/* Implement policygroups-style control files (aka "foodgroups")
+ * Copyright (C) 2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: foodgroups.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+struct connection; /* forward declaration */
+extern void add_group(struct connection *c);
+extern void route_group(struct connection *c);
+extern void unroute_group(struct connection *c);
+extern void delete_group(const struct connection *c);
+
+extern const char *policygroups_dir;
+extern void load_groups(void);
diff --git a/programs/pluto/gcryptfix.c b/programs/pluto/gcryptfix.c
new file mode 100644
index 000000000..1ebacdcf6
--- /dev/null
+++ b/programs/pluto/gcryptfix.c
@@ -0,0 +1,283 @@
+/* Routines to make gcrypt routines feel at home in Pluto.
+ * Copyright (C) 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: gcryptfix.c,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#include <stdlib.h>
+
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "rnd.h"
+#include "gcryptfix.h" /* includes <gmp.h> "defs.h" "rnd.h" */
+
+MPI
+mpi_alloc( unsigned nlimbs UNUSED )
+{
+ MPI n = alloc_bytes(sizeof *n, "mpi_alloc");
+
+ mpz_init(n);
+ return n;
+}
+
+MPI
+mpi_alloc_secure( unsigned nlimbs )
+{
+ return mpi_alloc(nlimbs);
+}
+
+MPI
+mpi_alloc_set_ui( unsigned long u)
+{
+ MPI n = alloc_bytes(sizeof *n, "mpi_copy");
+
+ mpz_init_set_ui(n, u);
+ return n;
+}
+
+MPI
+mpi_copy( MPI a )
+{
+ MPI n = alloc_bytes(sizeof *n, "mpi_copy");
+
+ mpz_init_set(n, a);
+ return n;
+}
+
+void
+mpi_free( MPI a )
+{
+ mpz_clear(a);
+ pfree(a);
+}
+
+int
+mpi_divisible_ui(MPI dividend, ulong divisor )
+{
+ ulong rem;
+ mpz_t remtoo;
+
+ mpz_init(remtoo);
+ rem = mpz_mod_ui(remtoo, dividend, divisor);
+ mpz_clear(remtoo);
+ return rem == 0;
+}
+
+unsigned
+mpi_trailing_zeros( MPI a )
+{
+ return mpz_scan1(a, 0);
+}
+
+unsigned
+mpi_get_nbits( MPI a )
+{
+ return mpz_sizeinbase(a, 2);
+}
+
+int
+mpi_test_bit( MPI a, unsigned n )
+{
+ /* inspired by gmp/mpz/clrbit.c */
+ mp_size_t li = n / mp_bits_per_limb;
+
+ if (li >= a->_mp_size)
+ return 0;
+ return (a->_mp_d[li] & ((mp_limb_t) 1 << (n % mp_bits_per_limb))) != 0;
+}
+
+void
+mpi_set_bit( MPI a, unsigned n )
+{
+ mpz_setbit(a, n);
+}
+
+void
+mpi_clear_bit( MPI a, unsigned n )
+{
+ mpz_clrbit(a, n);
+}
+
+void
+mpi_clear_highbit( MPI a, unsigned n )
+{
+ /* This seems whacky, but what do I know. */
+ mpz_fdiv_r_2exp(a, a, n);
+}
+
+void
+mpi_set_highbit( MPI a, unsigned n )
+{
+ /* This seems whacky, but what do I know. */
+ mpz_fdiv_r_2exp(a, a, n+1);
+ mpz_setbit(a, n);
+}
+
+void
+mpi_set_buffer( MPI a, const u_char *buffer, unsigned nbytes, int sign )
+{
+ /* this is a lot like n_to_mpz */
+ size_t i;
+
+ passert(sign == 0); /* we won't hit any negative numbers */
+ mpz_init_set_ui(a, 0);
+
+ for (i = 0; i != nbytes; i++)
+ {
+ mpz_mul_ui(a, a, 1 << BITS_PER_BYTE);
+ mpz_add_ui(a, a, buffer[i]);
+ }
+}
+
+u_char *
+get_random_bits(size_t nbits, int level UNUSED, int secure UNUSED)
+{
+ size_t nbytes = (nbits+7)/8;
+ u_char *b = alloc_bytes(nbytes, "random bytes");
+
+ get_rnd_bytes(b, nbytes);
+ return b;
+}
+/**************** from gnupg-1.0.0/mpi/mpi-mpow.c
+ * RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M
+ */
+#define barrett_mulm( w, u, v, m, y, k, r1, r2 ) mpi_mulm( (w), (u), (v), (m) )
+
+static int
+build_index( MPI *exparray, int k, int i, int t )
+{
+ int j, bitno;
+ int index = 0;
+
+ bitno = t-i;
+ for(j=k-1; j >= 0; j-- ) {
+ index <<= 1;
+ if( mpi_test_bit( exparray[j], bitno ) )
+ index |= 1;
+ }
+ /*log_debug("t=%d i=%d index=%d\n", t, i, index );*/
+ return index;
+}
+
+void
+mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m)
+{
+ int k; /* number of elements */
+ int t; /* bit size of largest exponent */
+ int i, j, idx;
+ MPI *G; /* table with precomputed values of size 2^k */
+ MPI tmp;
+ #ifdef USE_BARRETT
+ MPI barrett_y, barrett_r1, barrett_r2;
+ int barrett_k;
+ #endif
+
+ for(k=0; basearray[k]; k++ )
+ ;
+ passert(k);
+ for(t=0, i=0; (tmp=exparray[i]); i++ ) {
+ /*log_mpidump("exp: ", tmp );*/
+ j = mpi_get_nbits(tmp);
+ if( j > t )
+ t = j;
+ }
+ /*log_mpidump("mod: ", m );*/
+ passert(i==k);
+ passert(t);
+ passert( k < 10 );
+
+#ifdef PLUTO
+ m_alloc_ptrs_clear(G, 1<<k);
+#else
+ G = m_alloc_clear( (1<<k) * sizeof *G );
+#endif
+
+ #ifdef USE_BARRETT
+ barrett_y = init_barrett( m, &barrett_k, &barrett_r1, &barrett_r2 );
+ #endif
+ /* and calculate */
+ tmp = mpi_alloc( mpi_get_nlimbs(m)+1 );
+ mpi_set_ui( res, 1 );
+ for(i = 1; i <= t; i++ ) {
+ barrett_mulm(tmp, res, res, m, barrett_y, barrett_k,
+ barrett_r1, barrett_r2 );
+ idx = build_index( exparray, k, i, t );
+ passert( idx >= 0 && idx < (1<<k) );
+ if( !G[idx] ) {
+ if( !idx )
+ G[0] = mpi_alloc_set_ui( 1 );
+ else {
+ for(j=0; j < k; j++ ) {
+ if( (idx & (1<<j) ) ) {
+ if( !G[idx] )
+ G[idx] = mpi_copy( basearray[j] );
+ else
+ barrett_mulm( G[idx], G[idx], basearray[j],
+ m, barrett_y, barrett_k, barrett_r1, barrett_r2 );
+ }
+ }
+ if( !G[idx] )
+ G[idx] = mpi_alloc(0);
+ }
+ }
+ barrett_mulm(res, tmp, G[idx], m, barrett_y, barrett_k, barrett_r1, barrett_r2 );
+ }
+
+ /* cleanup */
+ mpi_free(tmp);
+ #ifdef USE_BARRETT
+ mpi_free(barrett_y);
+ mpi_free(barrett_r1);
+ mpi_free(barrett_r2);
+ #endif
+ for(i=0; i < (1<<k); i++ )
+ mpi_free(G[i]);
+ m_free(G);
+}
+
+void
+log_mpidump( const char *text UNUSED, MPI a )
+{
+ /* Print number in hex -- helpful to see if they match bytes.
+ * Humans are not going to do arithmetic with the large numbers!
+ * Much code adapted from mpz_to_n.
+ */
+ u_char buf[8048]; /* this ought to be big enough */
+ size_t len = (mpz_sizeinbase(a, 16) + 1) / 2; /* bytes */
+ MP_INT temp1, temp2;
+ int i;
+
+ passert(len <= sizeof(buf));
+
+ mpz_init(&temp1);
+ mpz_init(&temp2);
+
+ mpz_set(&temp1, a);
+
+ for (i = len-1; i >= 0; i--)
+ {
+ buf[i] = mpz_mdivmod_ui(&temp2, NULL, &temp1, 1 << BITS_PER_BYTE);
+ mpz_set(&temp1, &temp2);
+ }
+
+ passert(mpz_sgn(&temp1) == 0); /* we must have done all the bits */
+ mpz_clear(&temp1);
+ mpz_clear(&temp2);
+
+#ifdef DEBUG
+ DBG_dump(text, buf, len);
+#endif /* DEBUG */
+}
diff --git a/programs/pluto/gcryptfix.h b/programs/pluto/gcryptfix.h
new file mode 100644
index 000000000..637ecbc8d
--- /dev/null
+++ b/programs/pluto/gcryptfix.h
@@ -0,0 +1,111 @@
+/* Definitions to make gcrypt routines feel at home in Pluto.
+ * Copyright (C) 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: gcryptfix.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#define DBG_CIPHER 1 /* some day we'll do this right */
+
+/* Simulate MPI routines with gmp routines.
+ * gmp's MP_INT is a stuct; MPI's MPI is a pointer to an analogous struct.
+ * gmp's mpz_t is an array of one of these structs to enable magic pointer
+ * conversions to make the notation convenient (but confusing).
+ */
+typedef u_char byte;
+typedef MP_INT *MPI;
+
+#define BITS_PER_MPI_LIMB mp_bits_per_limb
+
+extern MPI mpi_alloc( unsigned nlimbs );
+extern MPI mpi_alloc_secure( unsigned nlimbs );
+#define mpi_alloc_like(n) mpi_alloc(mpi_get_nlimbs(n))
+extern MPI mpi_alloc_set_ui( unsigned long u);
+#define mpi_set_ui(w, u) mpz_set_ui(w, u)
+#define mpi_set(w, u) mpz_set(w, u)
+extern void mpi_free( MPI a );
+extern MPI mpi_copy( MPI a );
+extern unsigned mpi_get_nbits( MPI a );
+#define mpi_get_nlimbs(a) ((a)->_mp_alloc) /* dirty, but useless */
+extern void mpi_set_buffer( MPI a, const u_char *buffer, unsigned nbytes, int sign );
+extern unsigned mpi_trailing_zeros( MPI a );
+extern int mpi_test_bit( MPI a, unsigned n );
+extern void mpi_set_bit( MPI a, unsigned n );
+extern void mpi_clear_bit( MPI a, unsigned n );
+extern void mpi_clear_highbit( MPI a, unsigned n );
+extern void mpi_set_highbit( MPI a, unsigned n );
+#define mpi_cmp_ui(u, v) mpz_cmp_ui((u), (v))
+#define mpi_cmp(u, v) mpz_cmp((u), (v))
+#define mpi_is_neg(n) (mpz_sgn(n) < 0)
+#define mpi_add(w, u, v) mpz_add((w), (u), (v))
+#define mpi_add_ui(w, u, v) mpz_add_ui((w), (u), (v))
+#define mpi_sub_ui(w, u, v) mpz_sub_ui((w), (u), (v))
+#define mpi_subm( w, u, v, m) { mpz_sub( (w), (u), (v)) ; mpz_fdiv_r((w), (w), (m)); }
+#define mpi_mul( w, u, v) mpz_mul( (w), (u), (v))
+#define mpi_mul_ui( w, u, v) mpz_mul_ui( (w), (u), (v))
+#define mpi_mulm( w, u, v, m) { mpz_mul( (w), (u), (v)) ; mpz_fdiv_r((w), (w), (m)); }
+#define mpi_fdiv_q(quot, dividend, divisor) mpz_fdiv_q((quot), (dividend), (divisor))
+#define mpi_fdiv_r( rem, dividend, divisor ) mpz_fdiv_r( (rem), (dividend), (divisor) )
+#define mpi_fdiv_r_ui( rem, dividend, divisor ) mpz_fdiv_r_ui( (rem), (dividend), (divisor) )
+#define mpi_tdiv_q_2exp( w, u, count ) mpz_tdiv_q_2exp( (w), (u), (count) )
+extern int mpi_divisible_ui(MPI dividend, ulong divisor );
+#define mpi_powm( res, base, exp, mod) mpz_powm( res, base, exp, mod)
+extern void mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI mod);
+#define mpi_gcd( g, a, b ) ( mpz_gcd( (g), (a), (b) ), !mpi_cmp_ui( (g), 1))
+#define mpi_invm( x, a, n ) mpz_invert( (x), (a), (n) )
+
+#ifdef DEBUG
+# define log_debug(f...) DBG_log(f)
+#else
+# define log_debug(f...) do ; while (0) /* do nothing, carefully */
+#endif
+#define log_fatal(f...) exit_log(f) /* overreaction? */
+extern void log_mpidump( const char *text, MPI a );
+
+#define assert(p) passert(p)
+#define BUG() passert(FALSE)
+
+#define m_alloc_ptrs_clear(pp, n) { \
+ int c = (n); \
+ (pp) = alloc_bytes((n) * sizeof(*(pp)), "m_alloc_ptrs_clear"); \
+ while (c > 0) (pp)[--c] = NULL; \
+ }
+
+extern u_char *get_random_bits(size_t nbits, int level, int secure);
+#define m_alloc(sz) alloc_bytes((sz), "m_alloc") /* not initialized */
+#define m_free(n) pfree(n) /* always freeing something from get_random_bits */
+
+/* declarations from gnupg-1.0.0/include/cipher.h */
+/*-- primegen.c --*/
+MPI generate_secret_prime( unsigned nbits );
+MPI generate_public_prime( unsigned nbits );
+MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
+ MPI g, MPI **factors );
+
+#define PUBKEY_ALGO_ELGAMAL_E 16 /* encrypt only ElGamal (but not for v3)*/
+#define PUBKEY_ALGO_DSA 17
+#define PUBKEY_ALGO_ELGAMAL 20 /* sign and encrypt elgamal */
+
+#define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL || (a)==PUBKEY_ALGO_ELGAMAL_E)
+
+#define PUBKEY_USAGE_SIG 1 /* key is good for signatures */
+#define PUBKEY_USAGE_ENC 2 /* key is good for encryption */
+
+/* from gnupg-1.0.0/include/errors.h */
+
+#define G10ERR_PUBKEY_ALGO 4 /* Unknown pubkey algorithm */
+#define G10ERR_BAD_SECKEY 7 /* Bad secret key */
+#define G10ERR_BAD_SIGN 8 /* Bad signature */
+#define G10ERR_BAD_MPI 30
+
+/*-- smallprime.c --*/
+extern ushort small_prime_numbers[];
diff --git a/programs/pluto/id.c b/programs/pluto/id.c
new file mode 100644
index 000000000..4e306d3a7
--- /dev/null
+++ b/programs/pluto/id.c
@@ -0,0 +1,509 @@
+/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
+ * Copyright (C) 1999-2001 D. Hugh Redelmeier
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: id.c,v 1.4 2005/08/15 20:07:08 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says <unistd.h> defines this */
+# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */
+#endif
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "log.h"
+#include "connections.h"
+#include "packet.h"
+#include "whack.h"
+
+const struct id empty_id; /* ID_NONE */
+
+enum myid_state myid_state = MYID_UNKNOWN;
+struct id myids[MYID_SPECIFIED+1]; /* %myid */
+char *myid_str[MYID_SPECIFIED+1]; /* string form of IDs */
+
+/* initialize id module
+ * Fills in myid from environment variable IPSECmyid or defaultrouteaddr
+ */
+void
+init_id(void)
+{
+ passert(empty_id.kind == ID_NONE);
+ myid_state = MYID_UNKNOWN;
+ {
+ enum myid_state s;
+
+ for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++)
+ {
+ myids[s] = empty_id;
+ myid_str[s] = NULL;
+ }
+ }
+ set_myid(MYID_SPECIFIED, getenv("IPSECmyid"));
+ set_myid(MYID_IP, getenv("defaultrouteaddr"));
+ set_myFQDN();
+}
+
+static void
+calc_myid_str(enum myid_state s)
+{
+ /* preformat the ID name */
+ char buf[BUF_LEN];
+
+ idtoa(&myids[s], buf, BUF_LEN);
+ replace(myid_str[s], clone_str(buf, "myid string"));
+}
+
+
+void
+set_myid(enum myid_state s, char *idstr)
+{
+ if (idstr != NULL)
+ {
+ struct id id;
+ err_t ugh = atoid(idstr, &id, FALSE);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_BADID, "myid malformed: %s \"%s\"", ugh, idstr);
+ }
+ else
+ {
+ free_id_content(&myids[s]);
+ unshare_id_content(&id);
+ myids[s] = id;
+ if (s == MYID_SPECIFIED)
+ myid_state = MYID_SPECIFIED;
+
+ calc_myid_str(s);
+ }
+ }
+}
+
+void
+set_myFQDN(void)
+{
+ char FQDN[HOST_NAME_MAX + 1];
+ int r = gethostname(FQDN, sizeof(FQDN));
+
+ free_id_content(&myids[MYID_HOSTNAME]);
+ myids[MYID_HOSTNAME] = empty_id;
+ if (r != 0)
+ {
+ log_errno((e, "gethostname() failed in set_myFQDN"));
+ }
+ else
+ {
+ FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */
+
+ {
+ size_t len = strlen(FQDN);
+
+ if (len > 0 && FQDN[len-1] == '.')
+ {
+ /* nuke trailing . */
+ FQDN[len-1]='\0';
+ }
+ }
+
+ if (!strcaseeq(FQDN, "localhost.localdomain"))
+ {
+ clonetochunk(myids[MYID_HOSTNAME].name, FQDN, strlen(FQDN), "my FQDN");
+ myids[MYID_HOSTNAME].kind = ID_FQDN;
+ calc_myid_str(MYID_HOSTNAME);
+ }
+ }
+}
+
+void
+show_myid_status(void)
+{
+ char idstr[BUF_LEN];
+
+ (void)idtoa(&myids[myid_state], idstr, sizeof(idstr));
+ whack_log(RC_COMMENT, "%%myid = %s", idstr);
+}
+
+/* Convert textual form of id into a (temporary) struct id.
+ * Note that if the id is to be kept, unshare_id_content will be necessary.
+ */
+err_t
+atoid(char *src, struct id *id, bool myid_ok)
+{
+ err_t ugh = NULL;
+
+ *id = empty_id;
+
+ if (myid_ok && streq("%myid", src))
+ {
+ id->kind = ID_MYID;
+ }
+ else if (strchr(src, '=') != NULL)
+ {
+ /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN */
+ id->kind = ID_DER_ASN1_DN;
+ id->name.ptr = temporary_cyclic_buffer(); /* assign temporary buffer */
+ id->name.len = 0;
+ /* convert from LDAP style or openssl x509 -subject style to ASN.1 DN
+ * discard optional @ character in front of DN
+ */
+ ugh = atodn((*src == '@')?src+1:src, &id->name);
+ }
+ else if (strchr(src, '@') == NULL)
+ {
+ if (streq(src, "%any") || streq(src, "0.0.0.0"))
+ {
+ /* any ID will be accepted */
+ id->kind = ID_NONE;
+ }
+ else
+ {
+ /* !!! this test is not sufficient for distinguishing address families.
+ * We need a notation to specify that a FQDN is to be resolved to IPv6.
+ */
+ const struct af_info *afi = strchr(src, ':') == NULL
+ ? &af_inet4_info: &af_inet6_info;
+
+ id->kind = afi->id_addr;
+ ugh = ttoaddr(src, 0, afi->af, &id->ip_addr);
+ }
+ }
+ else
+ {
+ if (*src == '@')
+ {
+ if (*(src+1) == '#')
+ {
+ /* if there is a second specifier (#) on the line
+ * we interprete this as ID_KEY_ID
+ */
+ id->kind = ID_KEY_ID;
+ id->name.ptr = src;
+ /* discard @~, convert from hex to bin */
+ ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
+ }
+ else if (*(src+1) == '~')
+ {
+ /* if there is a second specifier (~) on the line
+ * we interprete this as a binary ID_DER_ASN1_DN
+ */
+ id->kind = ID_DER_ASN1_DN;
+ id->name.ptr = src;
+ /* discard @~, convert from hex to bin */
+ ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
+ }
+ else
+ {
+ id->kind = ID_FQDN;
+ id->name.ptr = src+1; /* discard @ */
+ id->name.len = strlen(src)-1;
+ }
+ }
+ else
+ {
+ /* We leave in @, as per DOI 4.6.2.4
+ * (but DNS wants . instead).
+ */
+ id->kind = ID_USER_FQDN;
+ id->name.ptr = src;
+ id->name.len = strlen(src);
+ }
+ }
+ return ugh;
+}
+
+
+/*
+ * Converts a binary key ID into hexadecimal format
+ */
+int
+keyidtoa(char *dst, size_t dstlen, chunk_t keyid)
+{
+ int n = datatot(keyid.ptr, keyid.len, 'x', dst, dstlen);
+ return (((size_t)n < dstlen)? n : dstlen) - 1;
+}
+
+void
+iptoid(const ip_address *ip, struct id *id)
+{
+ *id = empty_id;
+
+ switch (addrtypeof(ip))
+ {
+ case AF_INET:
+ id->kind = ID_IPV4_ADDR;
+ break;
+ case AF_INET6:
+ id->kind = ID_IPV6_ADDR;
+ break;
+ default:
+ bad_case(addrtypeof(ip));
+ }
+ id->ip_addr = *ip;
+}
+
+int
+idtoa(const struct id *id, char *dst, size_t dstlen)
+{
+ int n;
+
+ id = resolve_myid(id);
+ switch (id->kind)
+ {
+ case ID_NONE:
+ n = snprintf(dst, dstlen, "(none)");
+ break;
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ n = (int)addrtot(&id->ip_addr, 0, dst, dstlen) - 1;
+ break;
+ case ID_FQDN:
+ n = snprintf(dst, dstlen, "@%.*s", (int)id->name.len, id->name.ptr);
+ break;
+ case ID_USER_FQDN:
+ n = snprintf(dst, dstlen, "%.*s", (int)id->name.len, id->name.ptr);
+ break;
+ case ID_DER_ASN1_DN:
+ n = dntoa(dst, dstlen, id->name);
+ break;
+ case ID_KEY_ID:
+ n = keyidtoa(dst, dstlen, id->name);
+ break;
+ default:
+ n = snprintf(dst, dstlen, "unknown id kind %d", id->kind);
+ break;
+ }
+
+ /* "Sanitize" string so that log isn't endangered:
+ * replace unprintable characters with '?'.
+ */
+ if (n > 0)
+ {
+ for ( ; *dst != '\0'; dst++)
+ if (!isprint(*dst))
+ *dst = '?';
+ }
+
+ return n;
+}
+
+/* Replace the shell metacharacters ', \, ", `, and $ in a character string
+ * by escape sequences consisting of their octal values
+ */
+void
+escape_metachar(const char *src, char *dst, size_t dstlen)
+{
+ while (*src != '\0' && dstlen > 4)
+ {
+ switch (*src)
+ {
+ case '\'':
+ case '\\':
+ case '"':
+ case '`':
+ case '$':
+ sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src);
+ dst += 4;
+ dstlen -= 4;
+ break;
+ default:
+ *dst++ = *src;
+ dstlen--;
+ }
+ src++;
+ }
+ *dst = '\0';
+}
+
+
+/* Make private copy of string in struct id.
+ * This is needed if the result of atoid is to be kept.
+ */
+void
+unshare_id_content(struct id *id)
+{
+ switch (id->kind)
+ {
+ case ID_FQDN:
+ case ID_USER_FQDN:
+ case ID_DER_ASN1_DN:
+ case ID_KEY_ID:
+ id->name.ptr = clone_bytes(id->name.ptr, id->name.len, "keep id name");
+ break;
+ case ID_MYID:
+ case ID_NONE:
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ break;
+ default:
+ bad_case(id->kind);
+ }
+}
+
+void
+free_id_content(struct id *id)
+{
+ switch (id->kind)
+ {
+ case ID_FQDN:
+ case ID_USER_FQDN:
+ case ID_DER_ASN1_DN:
+ case ID_KEY_ID:
+ freeanychunk(id->name);
+ break;
+ case ID_MYID:
+ case ID_NONE:
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ break;
+ default:
+ bad_case(id->kind);
+ }
+}
+
+/* compare two struct id values */
+bool
+same_id(const struct id *a, const struct id *b)
+{
+ a = resolve_myid(a);
+ b = resolve_myid(b);
+ if (a->kind != b->kind)
+ return FALSE;
+ switch (a->kind)
+ {
+ case ID_NONE:
+ return TRUE; /* kind of vacuous */
+
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ return sameaddr(&a->ip_addr, &b->ip_addr);
+
+ case ID_FQDN:
+ case ID_USER_FQDN:
+ /* assumptions:
+ * - case should be ignored
+ * - trailing "." should be ignored (even if the only character?)
+ */
+ {
+ size_t al = a->name.len
+ , bl = b->name.len;
+
+ while (al > 0 && a->name.ptr[al - 1] == '.')
+ al--;
+ while (bl > 0 && b->name.ptr[bl - 1] == '.')
+ bl--;
+ return al == bl
+ && strncasecmp(a->name.ptr, b->name.ptr, al) == 0;
+ }
+
+ case ID_DER_ASN1_DN:
+ return same_dn(a->name, b->name);
+
+ case ID_KEY_ID:
+ return a->name.len == b->name.len
+ && memcmp(a->name.ptr, b->name.ptr, a->name.len) == 0;
+
+ default:
+ bad_case(a->kind);
+ }
+ return FALSE;
+}
+
+/* compare two struct id values, DNs can contain wildcards */
+bool
+match_id(const struct id *a, const struct id *b, int *wildcards)
+{
+ if (b->kind == ID_NONE)
+ {
+ *wildcards = MAX_WILDCARDS;
+ return TRUE;
+ }
+ if (a->kind != b->kind)
+ return FALSE;
+ if (a->kind == ID_DER_ASN1_DN)
+ return match_dn(a->name, b->name, wildcards);
+ else
+ {
+ *wildcards = 0;
+ return same_id(a, b);
+ }
+}
+
+/* count the numer of wildcards in an id */
+int
+id_count_wildcards(const struct id *id)
+{
+ switch (id->kind)
+ {
+ case ID_NONE:
+ return MAX_WILDCARDS;
+ case ID_DER_ASN1_DN:
+ return dn_count_wildcards(id->name);
+ default:
+ return 0;
+ }
+}
+
+/* build an ID payload
+ * Note: no memory is allocated for the body of the payload (tl->ptr).
+ * We assume it will end up being a pointer into a sufficiently
+ * stable datastructure. It only needs to last a short time.
+ */
+void
+build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end)
+{
+ const struct id *id = resolve_myid(&end->id);
+
+ zero(hd);
+ hd->isaiid_idtype = id->kind;
+ switch (id->kind)
+ {
+ case ID_NONE:
+ hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr;
+ tl->len = addrbytesptr(&end->host_addr
+ , (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
+ break;
+ case ID_FQDN:
+ case ID_USER_FQDN:
+ case ID_DER_ASN1_DN:
+ case ID_KEY_ID:
+ *tl = id->name;
+ break;
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ tl->len = addrbytesptr(&id->ip_addr
+ , (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
+ break;
+ default:
+ bad_case(id->kind);
+ }
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/programs/pluto/id.h b/programs/pluto/id.h
new file mode 100644
index 000000000..4fe9ef227
--- /dev/null
+++ b/programs/pluto/id.h
@@ -0,0 +1,67 @@
+/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
+ * Copyright (C) 1999-2001 D. Hugh Redelmeier
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: id.h,v 1.5 2005/08/15 20:07:08 as Exp $
+ */
+
+#ifndef _ID_H
+#define _ID_H
+
+#include "defs.h"
+
+struct id {
+ int kind; /* ID_* value */
+ ip_address ip_addr; /* ID_IPV4_ADDR, ID_IPV6_ADDR */
+ chunk_t name; /* ID_FQDN, ID_USER_FQDN (with @) */
+ /* ID_KEY_ID, ID_DER_ASN_DN */
+};
+
+extern void init_id(void);
+
+extern const struct id empty_id; /* ID_NONE */
+
+enum myid_state {
+ MYID_UNKNOWN, /* not yet figured out */
+ MYID_HOSTNAME, /* our current hostname */
+ MYID_IP, /* our default IP address */
+ MYID_SPECIFIED /* as specified by ipsec.conf */
+};
+
+extern enum myid_state myid_state;
+extern struct id myids[MYID_SPECIFIED+1]; /* %myid */
+extern char *myid_str[MYID_SPECIFIED+1]; /* strings */
+extern void set_myid(enum myid_state s, char *);
+extern void show_myid_status(void);
+#define resolve_myid(id) ((id)->kind == ID_MYID? &myids[myid_state] : (id))
+extern void set_myFQDN(void);
+
+extern err_t atoid(char *src, struct id *id, bool myid_ok);
+extern int keyidtoa(char *dst, size_t dstlen, chunk_t keyid);
+extern void iptoid(const ip_address *ip, struct id *id);
+extern int idtoa(const struct id *id, char *dst, size_t dstlen);
+#define IDTOA_BUF 512
+extern void escape_metachar(const char *src, char *dst, size_t dstlen);
+struct end; /* forward declaration of tag (defined in connections.h) */
+extern void unshare_id_content(struct id *id);
+extern void free_id_content(struct id *id);
+extern bool same_id(const struct id *a, const struct id *b);
+#define MAX_WILDCARDS 15
+extern bool match_id(const struct id *a, const struct id *b, int *wildcards);
+extern int id_count_wildcards(const struct id *id);
+#define id_is_ipaddr(id) ((id)->kind == ID_IPV4_ADDR || (id)->kind == ID_IPV6_ADDR)
+
+struct isakmp_ipsec_id; /* forward declaration of tag (defined in packet.h) */
+extern void
+ build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end);
+
+#endif /* _ID_H */
diff --git a/programs/pluto/ike_alg.c b/programs/pluto/ike_alg.c
new file mode 100644
index 000000000..47393079a
--- /dev/null
+++ b/programs/pluto/ike_alg.c
@@ -0,0 +1,459 @@
+/* IKE modular algorithm handling interface
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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: ike_alg.c,v 1.6 2004/09/17 21:29:50 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+
+#include "state.h"
+#include "packet.h"
+#include "log.h"
+#include "whack.h"
+#include "spdb.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+#include "db_ops.h"
+#include "connections.h"
+#include "kernel.h"
+
+#define return_on(var, val) do { var=val;goto return_out; } while(0);
+
+/*
+ * IKE algorithm list handling - registration and lookup
+ */
+
+/* Modular IKE algorithm storage structure */
+
+static struct ike_alg *ike_alg_base[IKE_ALG_MAX+1] = {NULL, NULL};
+
+/*
+ * return ike_algo object by {type, id}
+ */
+static struct ike_alg *
+ike_alg_find(u_int algo_type, u_int algo_id, u_int keysize __attribute__((unused)))
+{
+ struct ike_alg *e = ike_alg_base[algo_type];
+
+ while (e != NULL && algo_id > e->algo_id)
+ {
+ e = e->algo_next;
+ }
+ return (e != NULL && e->algo_id == algo_id) ? e : NULL;
+}
+
+/*
+ * "raw" ike_alg list adding function
+ */
+int
+ike_alg_add(struct ike_alg* a)
+{
+ if (a->algo_type > IKE_ALG_MAX)
+ {
+ plog("ike_alg: Not added, invalid algorithm type");
+ return -EINVAL;
+ }
+
+ if (ike_alg_find(a->algo_type, a->algo_id, 0) != NULL)
+ {
+ plog("ike_alg: Not added, algorithm already exists");
+ return -EEXIST;
+ }
+
+ {
+ struct ike_alg **ep = &ike_alg_base[a->algo_type];
+ struct ike_alg *e = *ep;
+
+ while (e != NULL && a->algo_id > e->algo_id)
+ {
+ ep = &e->algo_next;
+ e = *ep;
+ }
+ *ep = a;
+ a->algo_next = e;
+ return 0;
+ }
+}
+
+/*
+ * get IKE hash algorithm
+ */
+struct hash_desc *ike_alg_get_hasher(u_int alg)
+{
+ return (struct hash_desc *) ike_alg_find(IKE_ALG_HASH, alg, 0);
+}
+
+/*
+ * get IKE encryption algorithm
+ */
+struct encrypt_desc *ike_alg_get_encrypter(u_int alg)
+{
+ return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0);
+}
+
+/*
+ * check if IKE hash algorithm is present
+ */
+bool
+ike_alg_hash_present(u_int halg)
+{
+ return ike_alg_get_hasher(halg) != NULL;
+}
+
+/*
+ * check if IKE encryption algorithm is present
+ */
+bool
+ike_alg_enc_present(u_int ealg)
+{
+ return ike_alg_get_encrypter(ealg) != NULL;
+}
+
+/*
+ * Validate and register IKE hash algorithm object
+ */
+int
+ike_alg_register_hash(struct hash_desc *hash_desc)
+{
+ const char *alg_name = NULL;
+ int ret = 0;
+
+ if (hash_desc->algo_id > OAKLEY_HASH_MAX)
+ {
+ plog ("ike_alg: hash alg=%d > max=%d"
+ , hash_desc->algo_id, OAKLEY_HASH_MAX);
+ return_on(ret,-EINVAL);
+ }
+
+ if (hash_desc->hash_ctx_size > sizeof (union hash_ctx))
+ {
+ plog ("ike_alg: hash alg=%d has ctx_size=%d > hash_ctx=%d"
+ , hash_desc->algo_id
+ , (int)hash_desc->hash_ctx_size
+ , (int)sizeof (union hash_ctx));
+ return_on(ret,-EOVERFLOW);
+ }
+
+ if (!(hash_desc->hash_init && hash_desc->hash_update && hash_desc->hash_final))
+ {
+ plog ("ike_alg: hash alg=%d needs hash_init(), hash_update() and hash_final()"
+ , hash_desc->algo_id);
+ return_on(ret,-EINVAL);
+ }
+
+ alg_name = enum_name(&oakley_hash_names, hash_desc->algo_id);
+ if (!alg_name)
+ {
+ plog ("ike_alg: hash alg=%d not found in constants.c:oakley_hash_names"
+ , hash_desc->algo_id);
+ alg_name = "<NULL>";
+ }
+
+return_out:
+ if (ret == 0)
+ ret = ike_alg_add((struct ike_alg *)hash_desc);
+
+ plog("ike_alg: Activating %s hash: %s"
+ ,alg_name, ret == 0 ? "Ok" : "FAILED");
+
+ return ret;
+}
+
+/*
+ * Validate and register IKE encryption algorithm object
+ */
+int
+ike_alg_register_enc(struct encrypt_desc *enc_desc)
+{
+ int ret = ike_alg_add((struct ike_alg *)enc_desc);
+
+ const char *alg_name = enum_name(&oakley_enc_names, enc_desc->algo_id);
+
+ char alg_number[20];
+
+ /* algorithm is not listed in oakley_enc_names */
+ if (alg_name == NULL)
+ {
+ snprintf(alg_number, sizeof(alg_number), "OAKLEY_ID_%d"
+ , enc_desc->algo_id);
+ alg_name = alg_number;
+ }
+
+ plog("ike_alg: Activating %s encryption: %s"
+ , alg_name, ret == 0 ? "Ok" : "FAILED");
+
+ return ret;
+}
+
+/*
+ * Get pfsgroup for this connection
+ */
+const struct oakley_group_desc *
+ike_alg_pfsgroup(struct connection *c, lset_t policy)
+{
+ const struct oakley_group_desc * ret = NULL;
+
+ if ((policy & POLICY_PFS)
+ && c->alg_info_esp
+ && c->alg_info_esp->esp_pfsgroup)
+ ret = lookup_group(c->alg_info_esp->esp_pfsgroup);
+ return ret;
+}
+
+/*
+ * Create an OAKLEY proposal based on alg_info and policy
+ */
+struct db_context *
+ike_alg_db_new(struct alg_info_ike *ai , lset_t policy)
+{
+ struct db_context *db_ctx = NULL;
+ struct ike_info *ike_info;
+ u_int ealg, halg, modp, eklen = 0;
+ struct encrypt_desc *enc_desc;
+ int i;
+
+ if (!ai)
+ {
+ whack_log(RC_LOG_SERIOUS, "no IKE algorithms "
+ "for this connection "
+ "(check ike algorithm string)");
+ goto fail;
+ }
+ policy &= POLICY_ID_AUTH_MASK;
+ db_ctx = db_prop_new(PROTO_ISAKMP, 8, 8 * 5);
+
+ /* for each group */
+ ALG_INFO_IKE_FOREACH(ai, ike_info, i)
+ {
+ ealg = ike_info->ike_ealg;
+ halg = ike_info->ike_halg;
+ modp = ike_info->ike_modp;
+ eklen= ike_info->ike_eklen;
+
+ if (!ike_alg_enc_present(ealg))
+ {
+ DBG_log("ike_alg: ike enc ealg=%d not present"
+ , ealg);
+ continue;
+ }
+
+ if (!ike_alg_hash_present(halg))
+ {
+ DBG_log("ike_alg: ike hash halg=%d not present"
+ , halg);
+ continue;
+ }
+
+ enc_desc = ike_alg_get_encrypter(ealg);
+ passert(enc_desc != NULL);
+
+ if (eklen
+ && (eklen < enc_desc->keyminlen || eklen > enc_desc->keymaxlen))
+ {
+ DBG_log("ike_alg: ealg=%d (specified) keylen:%d, not valid min=%d, max=%d"
+ , ealg
+ , eklen
+ , enc_desc->keyminlen
+ , enc_desc->keymaxlen
+ );
+ continue;
+ }
+
+ if (policy & POLICY_RSASIG)
+ {
+ db_trans_add(db_ctx, KEY_IKE);
+ db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg);
+ db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg);
+ if (eklen)
+ db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen);
+ db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
+ db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp);
+ }
+
+ if (policy & POLICY_PSK)
+ {
+ db_trans_add(db_ctx, KEY_IKE);
+ db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg);
+ db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg);
+ if (ike_info->ike_eklen)
+ db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, ike_info->ike_eklen);
+ db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
+ db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp);
+ }
+ }
+fail:
+ return db_ctx;
+}
+
+/*
+ * Show registered IKE algorithms
+ */
+void
+ike_alg_list(void)
+{
+ u_int i;
+ struct ike_alg *a;
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered IKE Encryption Algorithms:");
+ whack_log(RC_COMMENT, " ");
+
+ for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next)
+ {
+ struct encrypt_desc *desc = (struct encrypt_desc*)a;
+
+ whack_log(RC_COMMENT, "#%-5d %s, blocksize: %d, keylen: %d-%d-%d"
+ , a->algo_id
+ , enum_name(&oakley_enc_names, a->algo_id)
+ , (int)desc->enc_blocksize*BITS_PER_BYTE
+ , desc->keyminlen
+ , desc->keydeflen
+ , desc->keymaxlen
+ );
+ }
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered IKE Hash Algorithms:");
+ whack_log(RC_COMMENT, " ");
+
+ for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next)
+ {
+ whack_log(RC_COMMENT, "#%-5d %s, hashsize: %d"
+ , a->algo_id
+ , enum_name(&oakley_hash_names, a->algo_id)
+ , (int)((struct hash_desc *)a)->hash_digest_size*BITS_PER_BYTE
+ );
+ }
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered IKE DH Groups:");
+ whack_log(RC_COMMENT, " ");
+
+ for (i = 0; i < elemsof(oakley_group); i++)
+ {
+ const struct oakley_group_desc *gdesc=oakley_group + i;
+
+ whack_log(RC_COMMENT, "#%-5d %s, groupsize: %d"
+ , gdesc->group
+ , enum_name(&oakley_group_names, gdesc->group)
+ , (int)gdesc->bytes*BITS_PER_BYTE
+ );
+ }
+}
+
+/* Show IKE algorithms for
+ * - this connection (result from ike= string)
+ * - newest SA
+ */
+void
+ike_alg_show_connection(struct connection *c, const char *instance)
+{
+ char buf[256];
+ struct state *st;
+
+ if (c->alg_info_ike)
+ {
+ alg_info_snprint(buf, sizeof(buf)-1, (struct alg_info *)c->alg_info_ike);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: IKE algorithms wanted: %s"
+ , c->name
+ , instance
+ , buf
+ );
+
+ alg_info_snprint_ike(buf, sizeof(buf)-1, c->alg_info_ike);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: IKE algorithms found: %s"
+ , c->name
+ , instance
+ , buf
+ );
+ }
+
+ st = state_with_serialno(c->newest_isakmp_sa);
+ if (st)
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: IKE algorithm newest: %s_%d-%s-%s"
+ , c->name
+ , instance
+ , enum_show(&oakley_enc_names, st->st_oakley.encrypt)
+ +7 /* strlen("OAKLEY_") */
+ /* , st->st_oakley.encrypter->keydeflen */
+ , st->st_oakley.enckeylen
+ , enum_show(&oakley_hash_names, st->st_oakley.hash)
+ +7 /* strlen("OAKLEY_") */
+ , enum_show(&oakley_group_names, st->st_oakley.group->group)
+ +13 /* strlen("OAKLEY_GROUP_") */
+ );
+}
+
+/*
+ * ML: make F_STRICT logic consider enc,hash/auth,modp algorithms
+ */
+bool
+ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group
+, struct alg_info_ike *alg_info_ike)
+{
+ /*
+ * simple test to discard low key_len, will accept it only
+ * if specified in "esp" string
+ */
+ bool ealg_insecure = (key_len < 128);
+
+ if (ealg_insecure
+ || (alg_info_ike && alg_info_ike->alg_info_flags & ALG_INFO_F_STRICT))
+ {
+ int i;
+ struct ike_info *ike_info;
+
+ if (alg_info_ike)
+ {
+ ALG_INFO_IKE_FOREACH(alg_info_ike, ike_info, i)
+ {
+ if (ike_info->ike_ealg == ealg
+ && (ike_info->ike_eklen == 0 || key_len == 0 || ike_info->ike_eklen == key_len)
+ && ike_info->ike_halg == aalg
+ && ike_info->ike_modp == group)
+ {
+ if (ealg_insecure)
+ loglog(RC_LOG_SERIOUS, "You should NOT use insecure IKE algorithms (%s)!"
+ , enum_name(&oakley_enc_names, ealg));
+ return TRUE;
+ }
+ }
+ }
+ plog("Oakley Transform [%s (%d), %s, %s] refused due to %s"
+ , enum_name(&oakley_enc_names, ealg), key_len
+ , enum_name(&oakley_hash_names, aalg)
+ , enum_name(&oakley_group_names, group)
+ , ealg_insecure ?
+ "insecure key_len and enc. alg. not listed in \"ike\" string" : "strict flag"
+ );
+ return FALSE;
+ }
+ return TRUE;
+}
+
diff --git a/programs/pluto/ike_alg.h b/programs/pluto/ike_alg.h
new file mode 100644
index 000000000..a41718c04
--- /dev/null
+++ b/programs/pluto/ike_alg.h
@@ -0,0 +1,73 @@
+/* IKE modular algorithm handling interface
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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: ike_alg.h,v 1.3 2004/09/16 23:22:22 as Exp $
+ */
+
+#ifndef _IKE_ALG_H
+#define _IKE_ALG_H
+
+#include "connections.h"
+
+struct ike_alg {
+ u_int16_t algo_type;
+ u_int16_t algo_id;
+ struct ike_alg *algo_next;
+};
+
+struct encrypt_desc {
+ u_int16_t algo_type;
+ u_int16_t algo_id;
+ struct ike_alg *algo_next;
+
+ size_t enc_ctxsize;
+ size_t enc_blocksize;
+ u_int keydeflen;
+ u_int keymaxlen;
+ u_int keyminlen;
+ void (*do_crypt)(u_int8_t *dat, size_t datasize, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc);
+};
+
+struct hash_desc {
+ u_int16_t algo_type;
+ u_int16_t algo_id;
+ struct ike_alg *algo_next;
+
+ size_t hash_ctx_size;
+ size_t hash_digest_size;
+ void (*hash_init)(void *ctx);
+ void (*hash_update)(void *ctx, const u_int8_t *in, size_t datasize);
+ void (*hash_final)(u_int8_t *out, void *ctx);
+};
+
+#define IKE_ALG_ENCRYPT 0
+#define IKE_ALG_HASH 1
+#define IKE_ALG_MAX IKE_ALG_HASH
+
+extern int ike_alg_add(struct ike_alg *a);
+extern struct hash_desc *ike_alg_get_hasher(u_int alg);
+extern struct encrypt_desc *ike_alg_get_encrypter(u_int alg);
+extern bool ike_alg_enc_present(u_int ealg);
+extern bool ike_alg_hash_present(u_int halg);
+extern int ike_alg_register_hash(struct hash_desc *a);
+extern int ike_alg_register_enc(struct encrypt_desc *e);
+extern const struct oakley_group_desc* ike_alg_pfsgroup(struct connection *c
+ , lset_t policy);
+extern struct db_context * ike_alg_db_new(struct alg_info_ike *ai, lset_t policy);
+extern void ike_alg_list(void);
+extern void ike_alg_show_connection(struct connection *c, const char *instance);
+extern bool ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group
+ , struct alg_info_ike *alg_info_ike);
+extern int ike_alg_init(void);
+
+#endif /* _IKE_ALG_H */
diff --git a/programs/pluto/ipsec.secrets.5 b/programs/pluto/ipsec.secrets.5
new file mode 100644
index 000000000..3cce4d3f8
--- /dev/null
+++ b/programs/pluto/ipsec.secrets.5
@@ -0,0 +1,175 @@
+.TH IPSEC.SECRETS 5 "28 March 1999"
+.SH NAME
+ipsec.secrets \- secrets for IKE/IPsec authentication
+.SH DESCRIPTION
+The file \fIipsec.secrets\fP holds a table of secrets.
+These secrets are used by \fIipsec_pluto\fP(8), the FreeS/WAN Internet Key
+Exchange daemon, to authenticate other hosts.
+Currently there are two kinds of secrets: preshared secrets and
+.\" the private part of DSS keys.
+RSA private keys.
+.LP
+It is vital that these secrets be protected. The file should be owned
+by the super-user,
+and its permissions should be set to block all access by others.
+.LP
+The file is a sequence of entries and include directives.
+Here is an example. Each entry or directive must start at the
+left margin, but if it continues beyond a single line, each continuation
+line must be indented.
+.LP
+.RS
+.nf
+# sample /etc/ipsec.secrets file for 10.1.0.1
+10.1.0.1 10.2.0.1: PSK "secret shared by two hosts"
+
+# an entry may be split across lines,
+# but indentation matters
+www.xs4all.nl @www.kremvax.ru
+\ \ \ \ 10.6.0.1 10.7.0.1 1.8.0.1: PSK "secret shared by 5"
+
+.\" # Private part of our DSS key, in base 64,
+.\" # as generated by BIND 8.2.1's dnskeygen.
+.\" # Since this is the default key for this host,
+.\" # there is no need to specify indices.
+.\" : DSS 0siMs0N/hfRoCBMXA6plPtuv58/+c=
+# an RSA private key.
+# note that the lines are too wide for a
+# man page, so ... has been substituted for
+# the truncated part
+@my.com: rsa {
+\ \ \ \ Modulus:\ 0syXpo/6waam+ZhSs8Lt6jnBzu3C4grtt...
+\ \ \ \ PublicExponent:\ 0sAw==
+\ \ \ \ PrivateExponent:\ 0shlGbVR1m8Z+7rhzSyenCaBN...
+\ \ \ \ Prime1:\ 0s8njV7WTxzVzRz7AP+0OraDxmEAt1BL5l...
+\ \ \ \ Prime2:\ 0s1LgR7/oUMo9BvfU8yRFNos1s211KX5K0...
+\ \ \ \ Exponent1:\ 0soaXj85ihM5M2inVf/NfHmtLutVz4r...
+\ \ \ \ Exponent2:\ 0sjdAL9VFizF+BKU4ohguJFzOd55OG6...
+\ \ \ \ Coefficient:\ 0sK1LWwgnNrNFGZsS/2GuMBg9nYVZ...
+\ \ \ \ }
+
+include ipsec.*.secrets # get secrets from other files
+.fi
+.RE
+.LP
+Each entry in the file is a list of indices, followed by a secret.
+The two parts are separated by a colon (\fB:\fP) that is
+followed by whitespace or a newline. For compatability
+with the previous form of this file, if the key part is just a
+double-quoted string the colon may be left out.
+.LP
+An index is an IP address, or a Fully Qualified Domain Name, user@FQDN,
+\fB%any\fP or \fB%any6\fP (other kinds may come). An IP address may be written
+in the familiar dotted quad form or as a domain name to be looked up
+when the file is loaded
+(or in any of the forms supported by the FreeS/WAN \fIipsec_ttoaddr\fP(3)
+routine). In many cases it is a bad idea to use domain names because
+the name server may not be running or may be insecure. To denote a
+Fully Qualified Domain Name (as opposed to an IP address denoted by
+its domain name), precede the name with an at sign (\fB@\fP).
+.LP
+Matching IDs with indices is fairly straightforward: they have to be
+equal. In the case of a ``Road Warrior'' connection, if an equal
+match is not found for the Peer's ID, and it is in the form of an IP
+address, an index of \fB%any\fP will match the peer's IP address if IPV4
+and \fB%any6\fP will match a the peer's IP address if IPV6.
+Currently, the obsolete notation \fB0.0.0.0\fP may be used in place of
+\fB%any\fP.
+.LP
+An additional complexity
+arises in the case of authentication by preshared secret: the
+responder will need to look up the secret before the Peer's ID payload has
+been decoded, so the ID used will be the IP address.
+.LP
+To authenticate a connection between two hosts, the entry that most
+specifically matches the host and peer IDs is used. An entry with no
+index will match any host and peer. More specifically, an entry with one index will
+match a host and peer if the index matches the host's ID (the peer isn't
+considered). Still more specifically, an entry with multiple indices will match a host and
+peer if the host ID and peer ID each match one of the indices. If the key
+is for an asymmetric authentication technique (i.e. a public key
+system such as RSA), an entry with multiple indices will match a host
+and peer even if only the host ID matches an index (it is presumed that the
+multiple indices are all identities of the host).
+It is acceptable for two entries to be the best match as
+long as they agree about the secret or private key.
+.LP
+Authentication by preshared secret requires that both systems find the
+identical secret (the secret is not actually transmitted by the IKE
+protocol). If both the host and peer appear in the index list, the
+same entry will be suitable for both systems so verbatim copying
+between systems can be used. This naturally extends to larger groups
+sharing the same secret. Thus multiple-index entries are best for PSK
+authentication.
+.LP
+Authentication by RSA Signatures requires that each host have its own private
+key. A host could reasonably use a different private keys
+for different interfaces and for different peers. But it would not
+be normal to share entries between systems. Thus thus no-index and
+one-index forms of entry often make sense for RSA Signature authentication.
+.LP
+The key part of an entry may start with a token indicating the kind of
+key. ``RSA'' signifies RSA private key and ``PSK'' signifies
+PreShared Key (case is ignored). For compatability with previous
+forms of this file, PSK is the default.
+.LP
+A preshared secret is most conveniently represented as a sequence of
+characters, delimited by the double-quote
+character (\fB"\fP). The sequence cannot contain a newline or
+double-quote. Strictly speaking, the secret is actually the sequence
+of bytes that is used in the file to represent the sequence of
+characters (excluding the delimiters).
+A preshared secret may also be represented, without quotes, in any form supported by
+\fIipsec_ttodata\fP(3).
+.LP
+An RSA private key is a composite of eight generally large numbers. The notation
+used is a brace-enclosed list of field name and value pairs (see the example above).
+A suitable key, in a suitable format, may be generated by \fIipsec_rsasigkey\fP(8).
+The structure is very similar to that used by BIND 8.2.2 or later, but note that
+the numbers must have a ``0s'' prefix if they are in base 64. The order of
+the fields is fixed.
+.LP
+The first token an entry must start in
+the first column of its line. Subsequent tokens must be
+separated by whitespace,
+except for a colon token, which only needs to be followed by whitespace.
+A newline is taken as whitespace, but every
+line of an entry after the first must be indented.
+.LP
+Whitespace at the end of a line is ignored (except in the 0t
+notation for a key). At the start of line or
+after whitespace, \fB#\fP and the following text up to the end of the
+line is treated as a comment. Within entries, all lines must be
+indented (except for lines with no tokens).
+Outside entries, no line may be indented (this is to make sure that
+the file layout reflects its structure).
+.LP
+An include directive causes the contents of the named file to be processed
+before continuing with the current file. The filename is subject to
+``globbing'' as in \fIsh\fP(1), so every file with a matching name
+is processed. Includes may be nested to a modest
+depth (10, currently). If the filename doesn't start with a \fB/\fP, the
+directory containing the current file is prepended to the name. The
+include directive is a line that starts with the word \fBinclude\fP,
+followed by whitespace, followed by the filename (which must not contain
+whitespace).
+.SH FILES
+/etc/ipsec.secrets
+.SH SEE ALSO
+The rest of the FreeS/WAN distribution, in particular
+\fIipsec.conf\fP(5),
+\fIipsec\fP(8),
+\fIipsec_newhostkey\fP(8),
+\fIipsec_rsasigkey\fP(8),
+\fIipsec_showhostkey\fP(8),
+\fIipsec_auto\fP(8) \fB\-\-rereadsecrets\fP,
+and \fIipsec_pluto\fP(8) \fB\-\-listen\fP,.
+.br
+BIND 8.2.2 or later, ftp://ftp.isc.org/isc/bind/src/
+.SH HISTORY
+Designed for the FreeS/WAN project
+<http://www.freeswan.org>
+by D. Hugh Redelmeier.
+.SH BUGS
+If an ID is \fB0.0.0.0\fP, it will match \fB%any\fP;
+if it is \fB0::0\fP, it will match \fB%any6\fP.
diff --git a/programs/pluto/ipsec_doi.c b/programs/pluto/ipsec_doi.c
new file mode 100644
index 000000000..fe5c846a7
--- /dev/null
+++ b/programs/pluto/ipsec_doi.c
@@ -0,0 +1,5649 @@
+/* IPsec DOI and Oakley resolution routines
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_doi.c,v 1.39 2006/04/22 21:59:20 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+#include <sys/time.h> /* for gettimeofday */
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "state.h"
+#include "id.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "keys.h"
+#include "packet.h"
+#include "demux.h" /* needs packet.h */
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "kernel.h"
+#include "log.h"
+#include "cookie.h"
+#include "server.h"
+#include "spdb.h"
+#include "timer.h"
+#include "rnd.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "whack.h"
+#include "fetch.h"
+#include "pkcs7.h"
+#include "asn1.h"
+
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+#include "vendor.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+#include "kernel_alg.h"
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+#ifdef VIRTUAL_IP
+#include "virtual.h"
+#endif
+
+/*
+ * are we sending Pluto's Vendor ID?
+ */
+#ifdef VENDORID
+#define SEND_PLUTO_VID 1
+#else /* !VENDORID */
+#define SEND_PLUTO_VID 0
+#endif /* !VENDORID */
+
+/*
+ * are we sending an XAUTH VID (Cisco Mode Config Interoperability)?
+ */
+#ifdef XAUTH_VID
+#define SEND_XAUTH_VID 1
+#else /* !XAUTH_VID */
+#define SEND_XAUTH_VID 0
+#endif /* !XAUTH_VID */
+
+/* MAGIC: perform f, a function that returns notification_t
+ * and return from the ENCLOSING stf_status returning function if it fails.
+ */
+#define RETURN_STF_FAILURE(f) \
+ { int r = (f); if (r != NOTHING_WRONG) return STF_FAIL + r; }
+
+/* create output HDR as replica of input HDR */
+void
+echo_hdr(struct msg_digest *md, bool enc, u_int8_t np)
+{
+ struct isakmp_hdr r_hdr = md->hdr; /* mostly same as incoming header */
+
+ r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */
+ if (enc)
+ r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION;
+ /* some day, we may have to set r_hdr.isa_version */
+ r_hdr.isa_np = np;
+ if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
+ impossible(); /* surely must have room and be well-formed */
+}
+
+/* Compute DH shared secret from our local secret and the peer's public value.
+ * We make the leap that the length should be that of the group
+ * (see quoted passage at start of ACCEPT_KE).
+ */
+static void
+compute_dh_shared(struct state *st, const chunk_t g
+, const struct oakley_group_desc *group)
+{
+ MP_INT mp_g, mp_shared;
+ struct timeval tv0, tv1;
+ unsigned long tv_diff;
+
+ gettimeofday(&tv0, NULL);
+ passert(st->st_sec_in_use);
+ n_to_mpz(&mp_g, g.ptr, g.len);
+ mpz_init(&mp_shared);
+ mpz_powm(&mp_shared, &mp_g, &st->st_sec, group->modulus);
+ mpz_clear(&mp_g);
+ freeanychunk(st->st_shared); /* happens in odd error cases */
+ st->st_shared = mpz_to_n(&mp_shared, group->bytes);
+ mpz_clear(&mp_shared);
+ gettimeofday(&tv1, NULL);
+ tv_diff=(tv1.tv_sec - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec);
+ DBG(DBG_CRYPT,
+ DBG_log("compute_dh_shared(): time elapsed (%s): %ld usec"
+ , enum_show(&oakley_group_names, st->st_oakley.group->group)
+ , tv_diff);
+ );
+ /* if took more than 200 msec ... */
+ if (tv_diff > 200000) {
+ loglog(RC_LOG_SERIOUS, "WARNING: compute_dh_shared(): for %s took "
+ "%ld usec"
+ , enum_show(&oakley_group_names, st->st_oakley.group->group)
+ , tv_diff);
+ }
+
+ DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", st->st_shared);
+}
+
+/* if we haven't already done so, compute a local DH secret (st->st_sec) and
+ * the corresponding public value (g). This is emitted as a KE payload.
+ */
+static bool
+build_and_ship_KE(struct state *st, chunk_t *g
+, const struct oakley_group_desc *group, pb_stream *outs, u_int8_t np)
+{
+ if (!st->st_sec_in_use)
+ {
+ u_char tmp[LOCALSECRETSIZE];
+ MP_INT mp_g;
+
+ get_rnd_bytes(tmp, LOCALSECRETSIZE);
+ st->st_sec_in_use = TRUE;
+ n_to_mpz(&st->st_sec, tmp, LOCALSECRETSIZE);
+
+ mpz_init(&mp_g);
+ mpz_powm(&mp_g, &groupgenerator, &st->st_sec, group->modulus);
+ freeanychunk(*g); /* happens in odd error cases */
+ *g = mpz_to_n(&mp_g, group->bytes);
+ mpz_clear(&mp_g);
+ DBG(DBG_CRYPT,
+ DBG_dump("Local DH secret:\n", tmp, LOCALSECRETSIZE);
+ DBG_dump_chunk("Public DH value sent:\n", *g));
+ }
+ return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value");
+}
+
+/* accept_ke
+ *
+ * Check and accept DH public value (Gi or Gr) from peer's message.
+ * According to RFC2409 "The Internet key exchange (IKE)" 5:
+ * The Diffie-Hellman public value passed in a KE payload, in either
+ * a phase 1 or phase 2 exchange, MUST be the length of the negotiated
+ * Diffie-Hellman group enforced, if necessary, by pre-pending the
+ * value with zeros.
+ */
+static notification_t
+accept_KE(chunk_t *dest, const char *val_name
+, const struct oakley_group_desc *gr
+, pb_stream *pbs)
+{
+ if (pbs_left(pbs) != gr->bytes)
+ {
+ loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required"
+ , (unsigned) pbs_left(pbs), (unsigned) gr->bytes);
+ /* XXX Could send notification back */
+ return INVALID_KEY_INFORMATION;
+ }
+ clonereplacechunk(*dest, pbs->cur, pbs_left(pbs), val_name);
+ DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest);
+ return NOTHING_WRONG;
+}
+
+/* accept_PFS_KE
+ *
+ * Check and accept optional Quick Mode KE payload for PFS.
+ * Extends ACCEPT_PFS to check whether KE is allowed or required.
+ */
+static notification_t
+accept_PFS_KE(struct msg_digest *md, chunk_t *dest
+, const char *val_name, const char *msg_name)
+{
+ struct state *st = md->st;
+ struct payload_digest *const ke_pd = md->chain[ISAKMP_NEXT_KE];
+
+ if (ke_pd == NULL)
+ {
+ if (st->st_pfs_group != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name);
+ return INVALID_KEY_INFORMATION;
+ }
+ }
+ else
+ {
+ if (st->st_pfs_group == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA"
+ , msg_name);
+ return INVALID_KEY_INFORMATION;
+ }
+ if (ke_pd->next != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s message contains several KE payloads; we accept at most one", msg_name);
+ return INVALID_KEY_INFORMATION; /* ??? */
+ }
+ return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs);
+ }
+ return NOTHING_WRONG;
+}
+
+static bool
+build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np
+, const char *name)
+{
+ freeanychunk(*n);
+ setchunk(*n, alloc_bytes(DEFAULT_NONCE_SIZE, name), DEFAULT_NONCE_SIZE);
+ get_rnd_bytes(n->ptr, DEFAULT_NONCE_SIZE);
+ return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name);
+}
+
+static bool
+collect_rw_ca_candidates(struct msg_digest *md, generalName_t **top)
+{
+ struct connection *d = find_host_connection(&md->iface->addr
+ , pluto_port, (ip_address*)NULL, md->sender_port, LEMPTY);
+
+ for (; d != NULL; d = d->hp_next)
+ {
+ /* must be a road warrior connection */
+ if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO)
+ && d->spd.that.ca.ptr != NULL)
+ {
+ generalName_t *gn;
+ bool new_entry = TRUE;
+
+ for (gn = *top; gn != NULL; gn = gn->next)
+ {
+ if (same_dn(gn->name, d->spd.that.ca))
+ {
+ new_entry = FALSE;
+ break;
+ }
+ }
+ if (new_entry)
+ {
+ gn = alloc_thing(generalName_t, "generalName");
+ gn->kind = GN_DIRECTORY_NAME;
+ gn->name = d->spd.that.ca;
+ gn->next = *top;
+ *top = gn;
+ }
+ }
+ }
+ return *top != NULL;
+}
+
+static bool
+build_and_ship_CR(u_int8_t type, chunk_t ca, pb_stream *outs, u_int8_t np)
+{
+ pb_stream cr_pbs;
+ struct isakmp_cr cr_hd;
+ cr_hd.isacr_np = np;
+ cr_hd.isacr_type = type;
+
+ /* build CR header */
+ if (!out_struct(&cr_hd, &isakmp_ipsec_cert_req_desc, outs, &cr_pbs))
+ return FALSE;
+
+ if (ca.ptr != NULL)
+ {
+ /* build CR body containing the distinguished name of the CA */
+ if (!out_chunk(ca, &cr_pbs, "CA"))
+ return FALSE;
+ }
+ close_output_pbs(&cr_pbs);
+ return TRUE;
+}
+
+/* Send a notification to the peer. We could decide
+ * whether to send the notification, based on the type and the
+ * destination, if we care to.
+ */
+static void
+send_notification(struct state *sndst, u_int16_t type, struct state *encst,
+ msgid_t msgid, u_char *icookie, u_char *rcookie,
+ u_char *spi, size_t spisize, u_char protoid)
+{
+ u_char buffer[1024];
+ pb_stream pbs, r_hdr_pbs;
+ u_char *r_hashval = NULL; /* where in reply to jam hash value */
+ u_char *r_hash_start = NULL; /* start of what is to be hashed */
+
+ passert((sndst) && (sndst->st_connection));
+
+ plog("sending %snotification %s to %s:%u"
+ , encst ? "encrypted " : ""
+ , enum_name(&notification_names, type)
+ , ip_str(&sndst->st_connection->spd.that.host_addr)
+ , (unsigned)sndst->st_connection->spd.that.host_port);
+
+ memset(buffer, 0, sizeof(buffer));
+ init_pbs(&pbs, buffer, sizeof(buffer), "ISAKMP notify");
+
+ /* HDR* */
+ {
+ struct isakmp_hdr hdr;
+
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = encst ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_N;
+ hdr.isa_xchg = ISAKMP_XCHG_INFO;
+ hdr.isa_msgid = msgid;
+ hdr.isa_flags = encst ? ISAKMP_FLAG_ENCRYPTION : 0;
+ if (icookie)
+ memcpy(hdr.isa_icookie, icookie, COOKIE_SIZE);
+ if (rcookie)
+ memcpy(hdr.isa_rcookie, rcookie, COOKIE_SIZE);
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &pbs, &r_hdr_pbs))
+ impossible();
+ }
+
+ /* HASH -- value to be filled later */
+ if (encst)
+ {
+ pb_stream hash_pbs;
+ if (!out_generic(ISAKMP_NEXT_N, &isakmp_hash_desc, &r_hdr_pbs,
+ &hash_pbs))
+ impossible();
+ r_hashval = hash_pbs.cur; /* remember where to plant value */
+ if (!out_zero(
+ encst->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH"))
+ impossible();
+ close_output_pbs(&hash_pbs);
+ r_hash_start = r_hdr_pbs.cur; /* hash from after HASH */
+ }
+
+ /* Notification Payload */
+ {
+ pb_stream not_pbs;
+ struct isakmp_notification isan;
+
+ isan.isan_doi = ISAKMP_DOI_IPSEC;
+ isan.isan_np = ISAKMP_NEXT_NONE;
+ isan.isan_type = type;
+ isan.isan_spisize = spisize;
+ isan.isan_protoid = protoid;
+
+ if (!out_struct(&isan, &isakmp_notification_desc, &r_hdr_pbs, &not_pbs)
+ || !out_raw(spi, spisize, &not_pbs, "spi"))
+ impossible();
+ close_output_pbs(&not_pbs);
+ }
+
+ /* calculate hash value and patch into Hash Payload */
+ if (encst)
+ {
+ struct hmac_ctx ctx;
+ hmac_init_chunk(&ctx, encst->st_oakley.hasher, encst->st_skeyid_a);
+ hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t));
+ hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start);
+ hmac_final(r_hashval, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("HASH computed:");
+ DBG_dump("", r_hashval, ctx.hmac_digest_size);
+ )
+ }
+
+ /* Encrypt message (preserve st_iv and st_new_iv) */
+ if (encst)
+ {
+ u_char old_iv[MAX_DIGEST_LEN];
+ u_char new_iv[MAX_DIGEST_LEN];
+
+ u_int old_iv_len = encst->st_iv_len;
+ u_int new_iv_len = encst->st_new_iv_len;
+
+ if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN)
+ impossible();
+
+ memcpy(old_iv, encst->st_iv, old_iv_len);
+ memcpy(new_iv, encst->st_new_iv, new_iv_len);
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(encst->st_state))
+ {
+ memcpy(encst->st_ph1_iv, encst->st_new_iv, encst->st_new_iv_len);
+ encst->st_ph1_iv_len = encst->st_new_iv_len;
+ }
+ init_phase2_iv(encst, &msgid);
+ if (!encrypt_message(&r_hdr_pbs, encst))
+ impossible();
+
+ /* restore preserved st_iv and st_new_iv */
+ memcpy(encst->st_iv, old_iv, old_iv_len);
+ memcpy(encst->st_new_iv, new_iv, new_iv_len);
+ encst->st_iv_len = old_iv_len;
+ encst->st_new_iv_len = new_iv_len;
+ }
+ else
+ {
+ close_output_pbs(&r_hdr_pbs);
+ }
+
+ /* Send packet (preserve st_tpacket) */
+ {
+ chunk_t saved_tpacket = sndst->st_tpacket;
+
+ setchunk(sndst->st_tpacket, pbs.start, pbs_offset(&pbs));
+ send_packet(sndst, "ISAKMP notify");
+ sndst->st_tpacket = saved_tpacket;
+ }
+}
+
+void
+send_notification_from_state(struct state *st, enum state_kind state,
+ u_int16_t type)
+{
+ struct state *p1st;
+
+ passert(st);
+
+ if (state == STATE_UNDEFINED)
+ state = st->st_state;
+
+ if (IS_QUICK(state)) {
+ p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES);
+ if ((p1st == NULL) || (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state))) {
+ loglog(RC_LOG_SERIOUS,
+ "no Phase1 state for Quick mode notification");
+ return;
+ }
+ send_notification(st, type, p1st, generate_msgid(p1st),
+ st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP);
+ }
+ else if (IS_ISAKMP_ENCRYPTED(state)) {
+ send_notification(st, type, st, generate_msgid(st),
+ st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP);
+ }
+ else {
+ /* no ISAKMP SA established - don't encrypt notification */
+ send_notification(st, type, NULL, 0,
+ st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP);
+ }
+}
+
+void
+send_notification_from_md(struct msg_digest *md, u_int16_t type)
+{
+ /**
+ * Create a dummy state to be able to use send_packet in
+ * send_notification
+ *
+ * we need to set:
+ * st_connection->that.host_addr
+ * st_connection->that.host_port
+ * st_connection->interface
+ */
+ struct state st;
+ struct connection cnx;
+
+ passert(md);
+
+ memset(&st, 0, sizeof(st));
+ memset(&cnx, 0, sizeof(cnx));
+ st.st_connection = &cnx;
+ cnx.spd.that.host_addr = md->sender;
+ cnx.spd.that.host_port = md->sender_port;
+ cnx.interface = md->iface;
+
+ send_notification(&st, type, NULL, 0,
+ md->hdr.isa_icookie, md->hdr.isa_rcookie, NULL, 0, PROTO_ISAKMP);
+}
+
+/* Send a Delete Notification to announce deletion of ISAKMP SA or
+ * inbound IPSEC SAs. Does nothing if no such SAs are being deleted.
+ * Delete Notifications cannot announce deletion of outbound IPSEC/ISAKMP SAs.
+ */
+void
+send_delete(struct state *st)
+{
+ pb_stream reply_pbs;
+ pb_stream r_hdr_pbs;
+ msgid_t msgid;
+ u_char buffer[8192];
+ struct state *p1st;
+ ip_said said[EM_MAXRELSPIS];
+ ip_said *ns = said;
+ u_char
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* start of what is to be hashed */
+ bool isakmp_sa = FALSE;
+
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES);
+ if (p1st == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete"));
+ return;
+ }
+
+ if (st->st_ah.present)
+ {
+ ns->spi = st->st_ah.our_spi;
+ ns->dst = st->st_connection->spd.this.host_addr;
+ ns->proto = PROTO_IPSEC_AH;
+ ns++;
+ }
+ if (st->st_esp.present)
+ {
+ ns->spi = st->st_esp.our_spi;
+ ns->dst = st->st_connection->spd.this.host_addr;
+ ns->proto = PROTO_IPSEC_ESP;
+ ns++;
+ }
+
+ passert(ns != said); /* there must be some SAs to delete */
+ }
+ else if (IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ p1st = st;
+ isakmp_sa = TRUE;
+ }
+ else
+ {
+ return; /* nothing to do */
+ }
+
+ msgid = generate_msgid(p1st);
+
+ zero(buffer);
+ init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg");
+
+ /* HDR* */
+ {
+ struct isakmp_hdr hdr;
+
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_HASH;
+ hdr.isa_xchg = ISAKMP_XCHG_INFO;
+ hdr.isa_msgid = msgid;
+ hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
+ memcpy(hdr.isa_icookie, p1st->st_icookie, COOKIE_SIZE);
+ memcpy(hdr.isa_rcookie, p1st->st_rcookie, COOKIE_SIZE);
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_pbs, &r_hdr_pbs))
+ impossible();
+ }
+
+ /* HASH -- value to be filled later */
+ {
+ pb_stream hash_pbs;
+
+ if (!out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs))
+ impossible();
+ r_hashval = hash_pbs.cur; /* remember where to plant value */
+ if (!out_zero(p1st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH(1)"))
+ impossible();
+ close_output_pbs(&hash_pbs);
+ r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */
+ }
+
+ /* Delete Payloads */
+ if (isakmp_sa)
+ {
+ pb_stream del_pbs;
+ struct isakmp_delete isad;
+ u_char isakmp_spi[2*COOKIE_SIZE];
+
+ isad.isad_doi = ISAKMP_DOI_IPSEC;
+ isad.isad_np = ISAKMP_NEXT_NONE;
+ isad.isad_spisize = (2 * COOKIE_SIZE);
+ isad.isad_protoid = PROTO_ISAKMP;
+ isad.isad_nospi = 1;
+
+ memcpy(isakmp_spi, st->st_icookie, COOKIE_SIZE);
+ memcpy(isakmp_spi+COOKIE_SIZE, st->st_rcookie, COOKIE_SIZE);
+
+ if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs)
+ || !out_raw(&isakmp_spi, (2*COOKIE_SIZE), &del_pbs, "delete payload"))
+ impossible();
+ close_output_pbs(&del_pbs);
+ }
+ else
+ {
+ while (ns != said)
+ {
+
+ pb_stream del_pbs;
+ struct isakmp_delete isad;
+
+ ns--;
+ isad.isad_doi = ISAKMP_DOI_IPSEC;
+ isad.isad_np = ns == said? ISAKMP_NEXT_NONE : ISAKMP_NEXT_D;
+ isad.isad_spisize = sizeof(ipsec_spi_t);
+ isad.isad_protoid = ns->proto;
+
+ isad.isad_nospi = 1;
+ if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs)
+ || !out_raw(&ns->spi, sizeof(ipsec_spi_t), &del_pbs, "delete payload"))
+ impossible();
+ close_output_pbs(&del_pbs);
+ }
+ }
+
+ /* calculate hash value and patch into Hash Payload */
+ {
+ struct hmac_ctx ctx;
+ hmac_init_chunk(&ctx, p1st->st_oakley.hasher, p1st->st_skeyid_a);
+ hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t));
+ hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start);
+ hmac_final(r_hashval, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("HASH(1) computed:");
+ DBG_dump("", r_hashval, ctx.hmac_digest_size);
+ )
+ }
+
+ /* Do a dance to avoid needing a new state object.
+ * We use the Phase 1 State. This is the one with right
+ * IV, for one thing.
+ * The tricky bits are:
+ * - we need to preserve (save/restore) st_iv (but not st_iv_new)
+ * - we need to preserve (save/restore) st_tpacket.
+ */
+ {
+ u_char old_iv[MAX_DIGEST_LEN];
+ chunk_t saved_tpacket = p1st->st_tpacket;
+
+ memcpy(old_iv, p1st->st_iv, p1st->st_iv_len);
+ init_phase2_iv(p1st, &msgid);
+
+ if (!encrypt_message(&r_hdr_pbs, p1st))
+ impossible();
+
+ setchunk(p1st->st_tpacket, reply_pbs.start, pbs_offset(&reply_pbs));
+ send_packet(p1st, "delete notify");
+ p1st->st_tpacket = saved_tpacket;
+
+ /* get back old IV for this state */
+ memcpy(p1st->st_iv, old_iv, p1st->st_iv_len);
+ }
+}
+
+void
+accept_delete(struct state *st, struct msg_digest *md, struct payload_digest *p)
+{
+ struct isakmp_delete *d = &(p->payload.delete);
+ size_t sizespi;
+ int i;
+
+ if (!md->encrypted)
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: not encrypted");
+ return;
+ }
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ /* can't happen (if msg is encrypt), but just to be sure */
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "ISAKMP SA not established");
+ return;
+ }
+
+ if (d->isad_nospi == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI");
+ return;
+ }
+
+ switch (d->isad_protoid)
+ {
+ case PROTO_ISAKMP:
+ sizespi = 2 * COOKIE_SIZE;
+ break;
+ case PROTO_IPSEC_AH:
+ case PROTO_IPSEC_ESP:
+ sizespi = sizeof(ipsec_spi_t);
+ break;
+ case PROTO_IPCOMP:
+ /* nothing interesting to delete */
+ return;
+ default:
+ loglog(RC_LOG_SERIOUS
+ , "ignoring Delete SA payload: unknown Protocol ID (%s)"
+ , enum_show(&protocol_names, d->isad_protoid));
+ return;
+ }
+
+ if (d->isad_spisize != sizespi)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ignoring Delete SA payload: bad SPI size (%d) for %s"
+ , d->isad_spisize, enum_show(&protocol_names, d->isad_protoid));
+ return;
+ }
+
+ if (pbs_left(&p->pbs) != d->isad_nospi * sizespi)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ignoring Delete SA payload: invalid payload size");
+ return;
+ }
+
+ for (i = 0; i < d->isad_nospi; i++)
+ {
+ u_char *spi = p->pbs.cur + (i * sizespi);
+
+ if (d->isad_protoid == PROTO_ISAKMP)
+ {
+ /**
+ * ISAKMP
+ */
+ struct state *dst = find_state(spi /*iCookie*/
+ , spi+COOKIE_SIZE /*rCookie*/
+ , &st->st_connection->spd.that.host_addr
+ , MAINMODE_MSGID);
+
+ if (dst == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "ISAKMP SA not found (maybe expired)");
+ }
+ else if (!same_peer_ids(st->st_connection, dst->st_connection, NULL))
+ {
+ /* we've not authenticated the relevant identities */
+ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: "
+ "ISAKMP SA used to convey Delete has different IDs from ISAKMP SA it deletes");
+ }
+ else
+ {
+ struct connection *oldc;
+
+ oldc = cur_connection;
+ set_cur_connection(dst->st_connection);
+#ifdef NAT_TRAVERSAL
+ if (nat_traversal_enabled)
+ nat_traversal_change_port_lookup(md, dst);
+#endif
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "deleting ISAKMP State #%lu", dst->st_serialno);
+ delete_state(dst);
+ set_cur_connection(oldc);
+ }
+ }
+ else
+ {
+ /**
+ * IPSEC (ESP/AH)
+ */
+ bool bogus;
+ struct state *dst = find_phase2_state_to_delete(st
+ , d->isad_protoid
+ , *(ipsec_spi_t *)spi /* network order */
+ , &bogus);
+
+ if (dst == NULL)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ignoring Delete SA payload: %s SA(0x%08lx) not found (%s)"
+ , enum_show(&protocol_names, d->isad_protoid)
+ , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi)
+ , bogus ? "our SPI - bogus implementation" : "maybe expired");
+ }
+ else
+ {
+ struct connection *rc = dst->st_connection;
+ struct connection *oldc;
+
+ oldc = cur_connection;
+ set_cur_connection(rc);
+
+#ifdef NAT_TRAVERSAL
+ if (nat_traversal_enabled)
+ nat_traversal_change_port_lookup(md, dst);
+#endif
+ if (rc->newest_ipsec_sa == dst->st_serialno
+ && (rc->policy & POLICY_UP))
+ {
+ /* Last IPSec SA for a permanent connection that we
+ * have initiated. Replace it in a few seconds.
+ *
+ * Useful if the other peer is rebooting.
+ */
+#define DELETE_SA_DELAY EVENT_RETRANSMIT_DELAY_0
+ if (dst->st_event != NULL
+ && dst->st_event->ev_type == EVENT_SA_REPLACE
+ && dst->st_event->ev_time <= DELETE_SA_DELAY + now())
+ {
+ /* Patch from Angus Lees to ignore retransmited
+ * Delete SA.
+ */
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "already replacing IPSEC State #%lu in %d seconds"
+ , dst->st_serialno, (int)(dst->st_event->ev_time - now()));
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
+ "replace IPSEC State #%lu in %d seconds"
+ , dst->st_serialno, DELETE_SA_DELAY);
+ dst->st_margin = DELETE_SA_DELAY;
+ delete_event(dst);
+ event_schedule(EVENT_SA_REPLACE, DELETE_SA_DELAY, dst);
+ }
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "received Delete SA(0x%08lx) payload: "
+ "deleting IPSEC State #%lu"
+ , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi)
+ , dst->st_serialno);
+ delete_state(dst);
+ }
+
+ /* reset connection */
+ set_cur_connection(oldc);
+ }
+ }
+ }
+}
+
+/* The whole message must be a multiple of 4 octets.
+ * I'm not sure where this is spelled out, but look at
+ * rfc2408 3.6 Transform Payload.
+ * Note: it talks about 4 BYTE boundaries!
+ */
+void
+close_message(pb_stream *pbs)
+{
+ size_t padding = pad_up(pbs_offset(pbs), 4);
+
+ if (padding != 0)
+ (void) out_zero(padding, pbs, "message padding");
+ close_output_pbs(pbs);
+}
+
+/* Initiate an Oakley Main Mode exchange.
+ * --> HDR;SA
+ * Note: this is not called from demux.c
+ */
+static stf_status
+main_outI1(int whack_sock, struct connection *c, struct state *predecessor
+ , lset_t policy, unsigned long try)
+{
+ struct state *st = new_state();
+ pb_stream reply; /* not actually a reply, but you know what I mean */
+ pb_stream rbody;
+
+ int vids_to_send = 0;
+
+ /* set up new state */
+ st->st_connection = c;
+ set_cur_state(st); /* we must reset before exit */
+ st->st_policy = policy & ~POLICY_IPSEC_MASK;
+ st->st_whack_sock = whack_sock;
+ st->st_try = try;
+ st->st_state = STATE_MAIN_I1;
+
+ /* determine how many Vendor ID payloads we will be sending */
+ if (SEND_PLUTO_VID)
+ vids_to_send++;
+ if (SEND_XAUTH_VID)
+ vids_to_send++;
+ if (c->spd.this.cert.type == CERT_PGP)
+ vids_to_send++;
+ /* always send DPD Vendor ID */
+ vids_to_send++;
+#ifdef NAT_TRAVERSAL
+ if (nat_traversal_enabled)
+ vids_to_send++;
+#endif
+
+ get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr);
+
+ insert_state(st); /* needs cookies, connection, and msgid (0) */
+
+ if (HAS_IPSEC_POLICY(policy))
+ add_pending(dup_any(whack_sock), st, c, policy, 1
+ , predecessor == NULL? SOS_NOBODY : predecessor->st_serialno);
+
+ if (predecessor == NULL)
+ plog("initiating Main Mode");
+ else
+ plog("initiating Main Mode to replace #%lu", predecessor->st_serialno);
+
+ /* set up reply */
+ init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet");
+
+ /* HDR out */
+ {
+ struct isakmp_hdr hdr;
+
+ zero(&hdr); /* default to 0 */
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_SA;
+ hdr.isa_xchg = ISAKMP_XCHG_IDPROT;
+ memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ /* R-cookie, flags and MessageID are left zero */
+
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* SA out */
+ {
+ u_char *sa_start = rbody.cur;
+ lset_t auth_policy = policy & POLICY_ID_AUTH_MASK;
+
+ if (!out_sa(&rbody, &oakley_sadb[auth_policy >> POLICY_ISAKMP_SHIFT]
+ , st, TRUE, vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* save initiator SA for later HASH */
+ passert(st->st_p1isa.ptr == NULL); /* no leak! (MUST be first time) */
+ clonetochunk(st->st_p1isa, sa_start, rbody.cur - sa_start
+ , "sa in main_outI1");
+ }
+
+ /* if enabled send Pluto Vendor ID */
+ if (SEND_PLUTO_VID)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody, VID_STRONGSWAN))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* if enabled send XAUTH Vendor ID */
+ if (SEND_XAUTH_VID)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody, VID_MISC_XAUTH))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* if we have an OpenPGP certificate we assume an
+ * OpenPGP peer and have to send the Vendor ID
+ */
+ if (c->spd.this.cert.type == CERT_PGP)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody, VID_OPENPGP))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* Announce our ability to do Dead Peer Detection to the peer */
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody, VID_MISC_DPD))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+#ifdef NAT_TRAVERSAL
+ if (nat_traversal_enabled)
+ {
+ /* Add supported NAT-Traversal VID */
+ if (!nat_traversal_add_vid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &rbody))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+#endif
+
+ close_message(&rbody);
+ close_output_pbs(&reply);
+
+ clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply)
+ , "reply packet for main_outI1");
+
+ /* Transmit */
+
+ send_packet(st, "main_outI1");
+
+ /* Set up a retransmission event, half a minute henceforth */
+ delete_event(st);
+ event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
+
+ if (predecessor != NULL)
+ {
+ update_pending(predecessor, st);
+ whack_log(RC_NEW_STATE + STATE_MAIN_I1
+ , "%s: initiate, replacing #%lu"
+ , enum_name(&state_names, st->st_state)
+ , predecessor->st_serialno);
+ }
+ else
+ {
+ whack_log(RC_NEW_STATE + STATE_MAIN_I1
+ , "%s: initiate", enum_name(&state_names, st->st_state));
+ }
+ reset_cur_state();
+ return STF_OK;
+}
+
+void
+ipsecdoi_initiate(int whack_sock
+, struct connection *c
+, lset_t policy
+, unsigned long try
+, so_serial_t replacing)
+{
+ /* If there's already an ISAKMP SA established, use that and
+ * go directly to Quick Mode. We are even willing to use one
+ * that is still being negotiated, but only if we are the Initiator
+ * (thus we can be sure that the IDs are not going to change;
+ * other issues around intent might matter).
+ * Note: there is no way to initiate with a Road Warrior.
+ */
+ struct state *st = find_phase1_state(c
+ , ISAKMP_SA_ESTABLISHED_STATES | PHASE1_INITIATOR_STATES);
+
+ if (st == NULL)
+ {
+ (void) main_outI1(whack_sock, c, NULL, policy, try);
+ }
+ else if (HAS_IPSEC_POLICY(policy))
+ {
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ /* leave our Phase 2 negotiation pending */
+ add_pending(whack_sock, st, c, policy, try, replacing);
+ }
+ else
+ {
+ /* ??? we assume that peer_nexthop_sin isn't important:
+ * we already have it from when we negotiated the ISAKMP SA!
+ * It isn't clear what to do with the error return.
+ */
+ (void) quick_outI1(whack_sock, st, c, policy, try, replacing);
+ }
+ }
+ else
+ {
+ close_any(whack_sock);
+ }
+}
+
+/* Replace SA with a fresh one that is similar
+ *
+ * Shares some logic with ipsecdoi_initiate, but not the same!
+ * - we must not reuse the ISAKMP SA if we are trying to replace it!
+ * - if trying to replace IPSEC SA, use ipsecdoi_initiate to build
+ * ISAKMP SA if needed.
+ * - duplicate whack fd, if live.
+ * Does not delete the old state -- someone else will do that.
+ */
+void
+ipsecdoi_replace(struct state *st, unsigned long try)
+{
+ int whack_sock = dup_any(st->st_whack_sock);
+ lset_t policy = st->st_policy;
+
+ if (IS_PHASE1(st->st_state))
+ {
+ passert(!HAS_IPSEC_POLICY(policy));
+ (void) main_outI1(whack_sock, st->st_connection, st, policy, try);
+ }
+ else
+ {
+ /* Add features of actual old state to policy. This ensures
+ * that rekeying doesn't downgrade security. I admit that
+ * this doesn't capture everything.
+ */
+ if (st->st_pfs_group != NULL)
+ policy |= POLICY_PFS;
+ if (st->st_ah.present)
+ {
+ policy |= POLICY_AUTHENTICATE;
+ if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ policy |= POLICY_TUNNEL;
+ }
+ if (st->st_esp.present && st->st_esp.attrs.transid != ESP_NULL)
+ {
+ policy |= POLICY_ENCRYPT;
+ if (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ policy |= POLICY_TUNNEL;
+ }
+ if (st->st_ipcomp.present)
+ {
+ policy |= POLICY_COMPRESS;
+ if (st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ policy |= POLICY_TUNNEL;
+ }
+ passert(HAS_IPSEC_POLICY(policy));
+ ipsecdoi_initiate(whack_sock, st->st_connection, policy, try
+ , st->st_serialno);
+ }
+}
+
+/* SKEYID for preshared keys.
+ * See draft-ietf-ipsec-ike-01.txt 4.1
+ */
+static bool
+skeyid_preshared(struct state *st)
+{
+ const chunk_t *pss = get_preshared_secret(st->st_connection);
+
+ if (pss == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "preshared secret disappeared!");
+ return FALSE;
+ }
+ else
+ {
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, *pss);
+ hmac_update_chunk(&ctx, st->st_ni);
+ hmac_update_chunk(&ctx, st->st_nr);
+ hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_preshared()", &ctx);
+ return TRUE;
+ }
+}
+
+static bool
+skeyid_digisig(struct state *st)
+{
+ struct hmac_ctx ctx;
+ chunk_t nir;
+
+ /* We need to hmac_init with the concatenation of Ni_b and Nr_b,
+ * so we have to build a temporary concatentation.
+ */
+ nir.len = st->st_ni.len + st->st_nr.len;
+ nir.ptr = alloc_bytes(nir.len, "Ni + Nr in skeyid_digisig");
+ memcpy(nir.ptr, st->st_ni.ptr, st->st_ni.len);
+ memcpy(nir.ptr+st->st_ni.len, st->st_nr.ptr, st->st_nr.len);
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, nir);
+ pfree(nir.ptr);
+
+ hmac_update_chunk(&ctx, st->st_shared);
+ hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_digisig()", &ctx);
+ return TRUE;
+}
+
+/* Generate the SKEYID_* and new IV
+ * See draft-ietf-ipsec-ike-01.txt 4.1
+ */
+static bool
+generate_skeyids_iv(struct state *st)
+{
+ /* Generate the SKEYID */
+ switch (st->st_oakley.auth)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ if (!skeyid_preshared(st))
+ return FALSE;
+ break;
+
+ case OAKLEY_RSA_SIG:
+ if (!skeyid_digisig(st))
+ return FALSE;
+ break;
+
+ case OAKLEY_DSS_SIG:
+ /* XXX */
+
+ case OAKLEY_RSA_ENC:
+ case OAKLEY_RSA_ENC_REV:
+ case OAKLEY_ELGAMAL_ENC:
+ case OAKLEY_ELGAMAL_ENC_REV:
+ /* XXX */
+
+ default:
+ bad_case(st->st_oakley.auth);
+ }
+
+ /* generate SKEYID_* from SKEYID */
+ {
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);
+
+ /* SKEYID_D */
+ hmac_update_chunk(&ctx, st->st_shared);
+ hmac_update(&ctx, st->st_icookie, COOKIE_SIZE);
+ hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE);
+ hmac_update(&ctx, "\0", 1);
+ hmac_final_chunk(st->st_skeyid_d, "st_skeyid_d in generate_skeyids_iv()", &ctx);
+
+ /* SKEYID_A */
+ hmac_reinit(&ctx);
+ hmac_update_chunk(&ctx, st->st_skeyid_d);
+ hmac_update_chunk(&ctx, st->st_shared);
+ hmac_update(&ctx, st->st_icookie, COOKIE_SIZE);
+ hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE);
+ hmac_update(&ctx, "\1", 1);
+ hmac_final_chunk(st->st_skeyid_a, "st_skeyid_a in generate_skeyids_iv()", &ctx);
+
+ /* SKEYID_E */
+ hmac_reinit(&ctx);
+ hmac_update_chunk(&ctx, st->st_skeyid_a);
+ hmac_update_chunk(&ctx, st->st_shared);
+ hmac_update(&ctx, st->st_icookie, COOKIE_SIZE);
+ hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE);
+ hmac_update(&ctx, "\2", 1);
+ hmac_final_chunk(st->st_skeyid_e, "st_skeyid_e in generate_skeyids_iv()", &ctx);
+ }
+
+ /* generate IV */
+ {
+ union hash_ctx hash_ctx;
+ const struct hash_desc *h = st->st_oakley.hasher;
+
+ st->st_new_iv_len = h->hash_digest_size;
+ passert(st->st_new_iv_len <= sizeof(st->st_new_iv));
+
+ DBG(DBG_CRYPT,
+ DBG_dump_chunk("DH_i:", st->st_gi);
+ DBG_dump_chunk("DH_r:", st->st_gr);
+ );
+ h->hash_init(&hash_ctx);
+ h->hash_update(&hash_ctx, st->st_gi.ptr, st->st_gi.len);
+ h->hash_update(&hash_ctx, st->st_gr.ptr, st->st_gr.len);
+ h->hash_final(st->st_new_iv, &hash_ctx);
+ }
+
+ /* Oakley Keying Material
+ * Derived from Skeyid_e: if it is not big enough, generate more
+ * using the PRF.
+ * See RFC 2409 "IKE" Appendix B
+ */
+ {
+ /* const size_t keysize = st->st_oakley.encrypter->keydeflen/BITS_PER_BYTE; */
+ const size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE;
+ u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN];
+ u_char *k = st->st_skeyid_e.ptr;
+
+ if (keysize > st->st_skeyid_e.len)
+ {
+ struct hmac_ctx ctx;
+ size_t i = 0;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_e);
+ hmac_update(&ctx, "\0", 1);
+ for (;;)
+ {
+ hmac_final(&keytemp[i], &ctx);
+ i += ctx.hmac_digest_size;
+ if (i >= keysize)
+ break;
+ hmac_reinit(&ctx);
+ hmac_update(&ctx, &keytemp[i - ctx.hmac_digest_size], ctx.hmac_digest_size);
+ }
+ k = keytemp;
+ }
+ clonereplacechunk(st->st_enc_key, k, keysize, "st_enc_key");
+ }
+
+ DBG(DBG_CRYPT,
+ DBG_dump_chunk("Skeyid: ", st->st_skeyid);
+ DBG_dump_chunk("Skeyid_d:", st->st_skeyid_d);
+ DBG_dump_chunk("Skeyid_a:", st->st_skeyid_a);
+ DBG_dump_chunk("Skeyid_e:", st->st_skeyid_e);
+ DBG_dump_chunk("enc key:", st->st_enc_key);
+ DBG_dump("IV:", st->st_new_iv, st->st_new_iv_len));
+ return TRUE;
+}
+
+/* Generate HASH_I or HASH_R for ISAKMP Phase I.
+ * This will *not* generate other hash payloads (eg. Phase II or Quick Mode,
+ * New Group Mode, or ISAKMP Informational Exchanges).
+ * If the hashi argument is TRUE, generate HASH_I; if FALSE generate HASH_R.
+ * If hashus argument is TRUE, we're generating a hash for our end.
+ * See RFC2409 IKE 5.
+ *
+ * Generating the SIG_I and SIG_R for DSS is an odd perversion of this:
+ * Most of the logic is the same, but SHA-1 is used in place of HMAC-whatever.
+ * The extensive common logic is embodied in main_mode_hash_body().
+ * See draft-ietf-ipsec-ike-01.txt 4.1 and 6.1.1.2
+ */
+
+typedef void (*hash_update_t)(union hash_ctx *, const u_char *, size_t) ;
+static void
+main_mode_hash_body(struct state *st
+, bool hashi /* Initiator? */
+, const pb_stream *idpl /* ID payload, as PBS */
+, union hash_ctx *ctx
+, void (*hash_update_void)(void *, const u_char *input, size_t))
+{
+#define HASH_UPDATE_T (union hash_ctx *, const u_char *input, unsigned int len)
+ hash_update_t hash_update=(hash_update_t) hash_update_void;
+#if 0 /* if desperate to debug hashing */
+# define hash_update(ctx, input, len) { \
+ DBG_dump("hash input", input, len); \
+ (hash_update)(ctx, input, len); \
+ }
+#endif
+
+# define hash_update_chunk(ctx, ch) hash_update((ctx), (ch).ptr, (ch).len)
+
+ if (hashi)
+ {
+ hash_update_chunk(ctx, st->st_gi);
+ hash_update_chunk(ctx, st->st_gr);
+ hash_update(ctx, st->st_icookie, COOKIE_SIZE);
+ hash_update(ctx, st->st_rcookie, COOKIE_SIZE);
+ }
+ else
+ {
+ hash_update_chunk(ctx, st->st_gr);
+ hash_update_chunk(ctx, st->st_gi);
+ hash_update(ctx, st->st_rcookie, COOKIE_SIZE);
+ hash_update(ctx, st->st_icookie, COOKIE_SIZE);
+ }
+
+ DBG(DBG_CRYPT, DBG_log("hashing %lu bytes of SA"
+ , (unsigned long) (st->st_p1isa.len - sizeof(struct isakmp_generic))));
+
+ /* SA_b */
+ hash_update(ctx, st->st_p1isa.ptr + sizeof(struct isakmp_generic)
+ , st->st_p1isa.len - sizeof(struct isakmp_generic));
+
+ /* Hash identification payload, without generic payload header.
+ * We used to reconstruct ID Payload for this purpose, but now
+ * we use the bytes as they appear on the wire to avoid
+ * "spelling problems".
+ */
+ hash_update(ctx
+ , idpl->start + sizeof(struct isakmp_generic)
+ , pbs_offset(idpl) - sizeof(struct isakmp_generic));
+
+# undef hash_update_chunk
+# undef hash_update
+}
+
+static size_t /* length of hash */
+main_mode_hash(struct state *st
+, u_char *hash_val /* resulting bytes */
+, bool hashi /* Initiator? */
+, const pb_stream *idpl) /* ID payload, as PBS; cur must be at end */
+{
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);
+ main_mode_hash_body(st, hashi, idpl, &ctx.hash_ctx, ctx.h->hash_update);
+ hmac_final(hash_val, &ctx);
+ return ctx.hmac_digest_size;
+}
+
+#if 0 /* only needed for DSS */
+static void
+main_mode_sha1(struct state *st
+, u_char *hash_val /* resulting bytes */
+, size_t *hash_len /* length of hash */
+, bool hashi /* Initiator? */
+, const pb_stream *idpl) /* ID payload, as PBS */
+{
+ union hash_ctx ctx;
+
+ SHA1Init(&ctx.ctx_sha1);
+ SHA1Update(&ctx.ctx_sha1, st->st_skeyid.ptr, st->st_skeyid.len);
+ *hash_len = SHA1_DIGEST_SIZE;
+ main_mode_hash_body(st, hashi, idpl, &ctx
+ , (void (*)(union hash_ctx *, const u_char *, unsigned int))&SHA1Update);
+ SHA1Final(hash_val, &ctx.ctx_sha1);
+}
+#endif
+
+/* Create an RSA signature of a hash.
+ * Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
+ * Use PKCS#1 version 1.5 encryption of hash (called
+ * RSAES-PKCS1-V1_5) in PKCS#2.
+ */
+static size_t
+RSA_sign_hash(struct connection *c
+, u_char sig_val[RSA_MAX_OCTETS]
+, const u_char *hash_val, size_t hash_len)
+{
+ size_t sz = 0;
+ smartcard_t *sc = c->spd.this.sc;
+
+ if (sc == NULL) /* no smartcard */
+ {
+ const struct RSA_private_key *k = get_RSA_private_key(c);
+
+ if (k == NULL)
+ return 0; /* failure: no key to use */
+
+ sz = k->pub.k;
+ passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS);
+ sign_hash(k, hash_val, hash_len, sig_val, sz);
+ }
+ else if (sc->valid) /* if valid pin then sign hash on the smartcard */
+ {
+ lock_certs_and_keys("RSA_sign_hash");
+ if (!scx_establish_context(sc) || !scx_login(sc))
+ {
+ scx_release_context(sc);
+ unlock_certs_and_keys("RSA_sign_hash");
+ return 0;
+ }
+
+ sz = scx_get_keylength(sc);
+ if (sz == 0)
+ {
+ plog("failed to get keylength from smartcard");
+ scx_release_context(sc);
+ unlock_certs_and_keys("RSA_sign_hash");
+ return 0;
+ }
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
+ , (int)sc->slot, sc->id)
+ )
+ sz = scx_sign_hash(sc, hash_val, hash_len, sig_val, sz) ? sz : 0;
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ unlock_certs_and_keys("RSA_sign_hash");
+ }
+ return sz;
+}
+
+/* Check a Main Mode RSA Signature against computed hash using RSA public key k.
+ *
+ * As a side effect, on success, the public key is copied into the
+ * state object to record the authenticator.
+ *
+ * Can fail because wrong public key is used or because hash disagrees.
+ * We distinguish because diagnostics should also.
+ *
+ * The result is NULL if the Signature checked out.
+ * Otherwise, the first character of the result indicates
+ * how far along failure occurred. A greater character signifies
+ * greater progress.
+ *
+ * Classes:
+ * 0 reserved for caller
+ * 1 SIG length doesn't match key length -- wrong key
+ * 2-8 malformed ECB after decryption -- probably wrong key
+ * 9 decrypted hash != computed hash -- probably correct key
+ *
+ * Although the math should be the same for generating and checking signatures,
+ * it is not: the knowledge of the private key allows more efficient (i.e.
+ * different) computation for encryption.
+ */
+static err_t
+try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN], size_t hash_len
+, const pb_stream *sig_pbs, pubkey_t *kr
+, struct state *st)
+{
+ const u_char *sig_val = sig_pbs->cur;
+ size_t sig_len = pbs_left(sig_pbs);
+ u_char s[RSA_MAX_OCTETS]; /* for decrypted sig_val */
+ u_char *hash_in_s = &s[sig_len - hash_len];
+ const struct RSA_public_key *k = &kr->u.rsa;
+
+ /* decrypt the signature -- reversing RSA_sign_hash */
+ if (sig_len != k->k)
+ {
+ /* XXX notification: INVALID_KEY_INFORMATION */
+ return "1" "SIG length does not match public key length";
+ }
+
+ /* actual exponentiation; see PKCS#1 v2.0 5.1 */
+ {
+ chunk_t temp_s;
+ mpz_t c;
+
+ n_to_mpz(c, sig_val, sig_len);
+ mpz_powm(c, c, &k->e, &k->n);
+
+ temp_s = mpz_to_n(c, sig_len); /* back to octets */
+ memcpy(s, temp_s.ptr, sig_len);
+ pfree(temp_s.ptr);
+ mpz_clear(c);
+ }
+
+ /* sanity check on signature: see if it matches
+ * PKCS#1 v1.5 8.1 encryption-block formatting
+ */
+ {
+ err_t ugh = NULL;
+
+ if (s[0] != 0x00)
+ ugh = "2" "no leading 00";
+ else if (hash_in_s[-1] != 0x00)
+ ugh = "3" "00 separator not present";
+ else if (s[1] == 0x01)
+ {
+ const u_char *p;
+
+ for (p = &s[2]; p != hash_in_s - 1; p++)
+ {
+ if (*p != 0xFF)
+ {
+ ugh = "4" "invalid Padding String";
+ break;
+ }
+ }
+ }
+ else if (s[1] == 0x02)
+ {
+ const u_char *p;
+
+ for (p = &s[2]; p != hash_in_s - 1; p++)
+ {
+ if (*p == 0x00)
+ {
+ ugh = "5" "invalid Padding String";
+ break;
+ }
+ }
+ }
+ else
+ ugh = "6" "Block Type not 01 or 02";
+
+ if (ugh != NULL)
+ {
+ /* note: it might be a good idea to make sure that
+ * an observer cannot tell what kind of failure happened.
+ * I don't know what this means in practice.
+ */
+ /* We probably selected the wrong public key for peer:
+ * SIG Payload decrypted into malformed ECB
+ */
+ /* XXX notification: INVALID_KEY_INFORMATION */
+ return ugh;
+ }
+ }
+
+ /* We have the decoded hash: see if it matches. */
+ if (memcmp(hash_val, hash_in_s, hash_len) != 0)
+ {
+ /* good: header, hash, signature, and other payloads well-formed
+ * good: we could find an RSA Sig key for the peer.
+ * bad: hash doesn't match
+ * Guess: sides disagree about key to be used.
+ */
+ DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len);
+ DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len);
+ /* XXX notification: INVALID_HASH_INFORMATION */
+ return "9" "authentication failure: received SIG does not match computed HASH, but message is well-formed";
+ }
+
+ /* Success: copy successful key into state.
+ * There might be an old one if we previously aborted this
+ * state transition.
+ */
+ unreference_key(&st->st_peer_pubkey);
+ st->st_peer_pubkey = reference_key(kr);
+
+ return NULL; /* happy happy */
+}
+
+/* Check signature against all RSA public keys we can find.
+ * If we need keys from DNS KEY records, and they haven't been fetched,
+ * return STF_SUSPEND to ask for asynch DNS lookup.
+ *
+ * Note: parameter keys_from_dns contains results of DNS lookup for key
+ * or is NULL indicating lookup not yet tried.
+ *
+ * take_a_crack is a helper function. Mostly forensic.
+ * If only we had coroutines.
+ */
+struct tac_state {
+ /* RSA_check_signature's args that take_a_crack needs */
+ struct state *st;
+ const u_char *hash_val;
+ size_t hash_len;
+ const pb_stream *sig_pbs;
+
+ /* state carried between calls */
+ err_t best_ugh; /* most successful failure */
+ int tried_cnt; /* number of keys tried */
+ char tried[50]; /* keyids of tried public keys */
+ char *tn; /* roof of tried[] */
+};
+
+static bool
+take_a_crack(struct tac_state *s
+, pubkey_t *kr
+, const char *story USED_BY_DEBUG)
+{
+ err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs
+ , kr, s->st);
+ const struct RSA_public_key *k = &kr->u.rsa;
+
+ s->tried_cnt++;
+ if (ugh == NULL)
+ {
+ DBG(DBG_CRYPT | DBG_CONTROL
+ , DBG_log("an RSA Sig check passed with *%s [%s]"
+ , k->keyid, story));
+ return TRUE;
+ }
+ else
+ {
+ DBG(DBG_CRYPT
+ , DBG_log("an RSA Sig check failure %s with *%s [%s]"
+ , ugh + 1, k->keyid, story));
+ if (s->best_ugh == NULL || s->best_ugh[0] < ugh[0])
+ s->best_ugh = ugh;
+ if (ugh[0] > '0'
+ && s->tn - s->tried + KEYID_BUF + 2 < (ptrdiff_t)sizeof(s->tried))
+ {
+ strcpy(s->tn, " *");
+ strcpy(s->tn + 2, k->keyid);
+ s->tn += strlen(s->tn);
+ }
+ return FALSE;
+ }
+}
+
+static stf_status
+RSA_check_signature(const struct id* peer
+, struct state *st
+, const u_char hash_val[MAX_DIGEST_LEN]
+, size_t hash_len
+, const pb_stream *sig_pbs
+#ifdef USE_KEYRR
+, const pubkey_list_t *keys_from_dns
+#endif /* USE_KEYRR */
+, const struct gw_info *gateways_from_dns
+)
+{
+ const struct connection *c = st->st_connection;
+ struct tac_state s;
+ err_t dns_ugh = NULL;
+
+ s.st = st;
+ s.hash_val = hash_val;
+ s.hash_len = hash_len;
+ s.sig_pbs = sig_pbs;
+
+ s.best_ugh = NULL;
+ s.tried_cnt = 0;
+ s.tn = s.tried;
+
+ /* try all gateway records hung off c */
+ if (c->policy & POLICY_OPPO)
+ {
+ struct gw_info *gw;
+
+ for (gw = c->gw_info; gw != NULL; gw = gw->next)
+ {
+ /* only consider entries that have a key and are for our peer */
+ if (gw->gw_key_present
+ && same_id(&gw->gw_id, &c->spd.that.id)
+ && take_a_crack(&s, gw->key, "key saved from DNS TXT"))
+ return STF_OK;
+ }
+ }
+
+ /* try all appropriate Public keys */
+ {
+ pubkey_list_t *p, **pp;
+
+ pp = &pubkeys;
+
+ for (p = pubkeys; p != NULL; p = *pp)
+ {
+ pubkey_t *key = p->key;
+
+ if (key->alg == PUBKEY_ALG_RSA && same_id(peer, &key->id))
+ {
+ time_t now = time(NULL);
+
+ /* check if found public key has expired */
+ if (key->until_time != UNDEFINED_TIME && key->until_time < now)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "cached RSA public key has expired and has been deleted");
+ *pp = free_public_keyentry(p);
+ continue; /* continue with next public key */
+ }
+
+ if (take_a_crack(&s, key, "preloaded key"))
+ return STF_OK;
+ }
+ pp = &p->next;
+ }
+ }
+
+ /* if no key was found (evidenced by best_ugh == NULL)
+ * and that side of connection is key_from_DNS_on_demand
+ * then go search DNS for keys for peer.
+ */
+ if (s.best_ugh == NULL && c->spd.that.key_from_DNS_on_demand)
+ {
+ if (gateways_from_dns != NULL)
+ {
+ /* TXT keys */
+ const struct gw_info *gwp;
+
+ for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ if (gwp->gw_key_present
+ && take_a_crack(&s, gwp->key, "key from DNS TXT"))
+ return STF_OK;
+ }
+#ifdef USE_KEYRR
+ else if (keys_from_dns != NULL)
+ {
+ /* KEY keys */
+ const pubkey_list_t *kr;
+
+ for (kr = keys_from_dns; kr != NULL; kr = kr->next)
+ if (kr->key->alg == PUBKEY_ALG_RSA
+ && take_a_crack(&s, kr->key, "key from DNS KEY"))
+ return STF_OK;
+ }
+#endif /* USE_KEYRR */
+ else
+ {
+ /* nothing yet: ask for asynch DNS lookup */
+ return STF_SUSPEND;
+ }
+ }
+
+ /* no acceptable key was found: diagnose */
+ {
+ char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
+
+ (void) idtoa(&st->st_connection->spd.that.id, id_buf, sizeof(id_buf));
+
+ if (s.best_ugh == NULL)
+ {
+ if (dns_ugh == NULL)
+ loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
+ , id_buf);
+ else
+ loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
+ "; DNS search for KEY failed (%s)"
+ , id_buf, dns_ugh);
+
+ /* ??? is this the best code there is? */
+ return STF_FAIL + INVALID_KEY_INFORMATION;
+ }
+
+ if (s.best_ugh[0] == '9')
+ {
+ loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1);
+ /* XXX Could send notification back */
+ return STF_FAIL + INVALID_HASH_INFORMATION;
+ }
+ else
+ {
+ if (s.tried_cnt == 1)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "Signature check (on %s) failed (wrong key?); tried%s"
+ , id_buf, s.tried);
+ DBG(DBG_CONTROL,
+ DBG_log("public key for %s failed:"
+ " decrypted SIG payload into a malformed ECB (%s)"
+ , id_buf, s.best_ugh + 1));
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "Signature check (on %s) failed:"
+ " tried%s keys but none worked."
+ , id_buf, s.tried);
+ DBG(DBG_CONTROL,
+ DBG_log("all %d public keys for %s failed:"
+ " best decrypted SIG payload into a malformed ECB (%s)"
+ , s.tried_cnt, id_buf, s.best_ugh + 1));
+ }
+ return STF_FAIL + INVALID_KEY_INFORMATION;
+ }
+ }
+}
+
+static notification_t
+accept_nonce(struct msg_digest *md, chunk_t *dest, const char *name)
+{
+ pb_stream *nonce_pbs = &md->chain[ISAKMP_NEXT_NONCE]->pbs;
+ size_t len = pbs_left(nonce_pbs);
+
+ if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len)
+ {
+ loglog(RC_LOG_SERIOUS, "%s length not between %d and %d"
+ , name , MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE);
+ return PAYLOAD_MALFORMED; /* ??? */
+ }
+ clonereplacechunk(*dest, nonce_pbs->cur, len, "nonce");
+ return NOTHING_WRONG;
+}
+
+/* encrypt message, sans fixed part of header
+ * IV is fetched from st->st_new_iv and stored into st->st_iv.
+ * The theory is that there will be no "backing out", so we commit to IV.
+ * We also close the pbs.
+ */
+bool
+encrypt_message(pb_stream *pbs, struct state *st)
+{
+ const struct encrypt_desc *e = st->st_oakley.encrypter;
+ u_int8_t *enc_start = pbs->start + sizeof(struct isakmp_hdr);
+ size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr);
+
+ DBG_cond_dump(DBG_CRYPT | DBG_RAW, "encrypting:\n", enc_start, enc_len);
+
+ /* Pad up to multiple of encryption blocksize.
+ * See the description associated with the definition of
+ * struct isakmp_hdr in packet.h.
+ */
+ {
+ size_t padding = pad_up(enc_len, e->enc_blocksize);
+
+ if (padding != 0)
+ {
+ if (!out_zero(padding, pbs, "encryption padding"))
+ return FALSE;
+ enc_len += padding;
+ }
+ }
+
+ DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt)));
+
+ /* e->crypt(TRUE, enc_start, enc_len, st); */
+ crypto_cbc_encrypt(e, TRUE, enc_start, enc_len, st);
+
+ update_iv(st);
+ DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len);
+ close_message(pbs);
+ return TRUE;
+}
+
+/* Compute HASH(1), HASH(2) of Quick Mode.
+ * HASH(1) is part of Quick I1 message.
+ * HASH(2) is part of Quick R1 message.
+ * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2
+ * (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25)
+ */
+static size_t
+quick_mode_hash12(u_char *dest, const u_char *start, const u_char *roof
+, const struct state *st, const msgid_t *msgid, bool hash2)
+{
+ struct hmac_ctx ctx;
+
+#if 0 /* if desperate to debug hashing */
+# define hmac_update(ctx, ptr, len) { \
+ DBG_dump("hash input", (ptr), (len)); \
+ (hmac_update)((ctx), (ptr), (len)); \
+ }
+ DBG_dump("hash key", st->st_skeyid_a.ptr, st->st_skeyid_a.len);
+#endif
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
+ hmac_update(&ctx, (const void *) msgid, sizeof(msgid_t));
+ if (hash2)
+ hmac_update_chunk(&ctx, st->st_ni); /* include Ni_b in the hash */
+ hmac_update(&ctx, start, roof-start);
+ hmac_final(dest, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("HASH(%d) computed:", hash2 + 1);
+ DBG_dump("", dest, ctx.hmac_digest_size));
+ return ctx.hmac_digest_size;
+# undef hmac_update
+}
+
+/* Compute HASH(3) in Quick Mode (part of Quick I2 message).
+ * Used by: quick_inR1_outI2, quick_inI2
+ * See RFC2409 "The Internet Key Exchange (IKE)" 5.5.
+ * NOTE: this hash (unlike HASH(1) and HASH(2)) ONLY covers the
+ * Message ID and Nonces. This is a mistake.
+ */
+static size_t
+quick_mode_hash3(u_char *dest, struct state *st)
+{
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
+ hmac_update(&ctx, "\0", 1);
+ hmac_update(&ctx, (u_char *) &st->st_msgid, sizeof(st->st_msgid));
+ hmac_update_chunk(&ctx, st->st_ni);
+ hmac_update_chunk(&ctx, st->st_nr);
+ hmac_final(dest, &ctx);
+ DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, ctx.hmac_digest_size);
+ return ctx.hmac_digest_size;
+}
+
+/* Compute Phase 2 IV.
+ * Uses Phase 1 IV from st_iv; puts result in st_new_iv.
+ */
+void
+init_phase2_iv(struct state *st, const msgid_t *msgid)
+{
+ const struct hash_desc *h = st->st_oakley.hasher;
+ union hash_ctx ctx;
+
+ DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:"
+ , st->st_ph1_iv, st->st_ph1_iv_len);
+
+ st->st_new_iv_len = h->hash_digest_size;
+ passert(st->st_new_iv_len <= sizeof(st->st_new_iv));
+
+ h->hash_init(&ctx);
+ h->hash_update(&ctx, st->st_ph1_iv, st->st_ph1_iv_len);
+ passert(*msgid != 0);
+ h->hash_update(&ctx, (const u_char *)msgid, sizeof(*msgid));
+ h->hash_final(st->st_new_iv, &ctx);
+
+ DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:"
+ , st->st_new_iv, st->st_new_iv_len);
+}
+
+/* Initiate quick mode.
+ * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ]
+ * (see RFC 2409 "IKE" 5.5)
+ * Note: this is not called from demux.c
+ */
+
+static bool
+emit_subnet_id(ip_subnet *net
+, u_int8_t np, u_int8_t protoid, u_int16_t port, pb_stream *outs)
+{
+ struct isakmp_ipsec_id id;
+ pb_stream id_pbs;
+ ip_address ta;
+ const unsigned char *tbp;
+ size_t tal;
+
+ id.isaiid_np = np;
+ id.isaiid_idtype = subnetishost(net)
+ ? aftoinfo(subnettypeof(net))->id_addr
+ : aftoinfo(subnettypeof(net))->id_subnet;
+ id.isaiid_protoid = protoid;
+ id.isaiid_port = port;
+
+ if (!out_struct(&id, &isakmp_ipsec_identification_desc, outs, &id_pbs))
+ return FALSE;
+
+ networkof(net, &ta);
+ tal = addrbytesptr(&ta, &tbp);
+ if (!out_raw(tbp, tal, &id_pbs, "client network"))
+ return FALSE;
+
+ if (!subnetishost(net))
+ {
+ maskof(net, &ta);
+ tal = addrbytesptr(&ta, &tbp);
+ if (!out_raw(tbp, tal, &id_pbs, "client mask"))
+ return FALSE;
+ }
+
+ close_output_pbs(&id_pbs);
+ return TRUE;
+}
+
+stf_status
+quick_outI1(int whack_sock
+, struct state *isakmp_sa
+, struct connection *c
+, lset_t policy
+, unsigned long try
+, so_serial_t replacing)
+{
+ struct state *st = duplicate_state(isakmp_sa);
+ pb_stream reply; /* not really a reply */
+ pb_stream rbody;
+ u_char /* set by START_HASH_PAYLOAD: */
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* start of what is to be hashed */
+ bool has_client = c->spd.this.has_client || c->spd.that.has_client ||
+ c->spd.this.protocol || c->spd.that.protocol ||
+ c->spd.this.port || c->spd.that.port;
+
+ bool send_natoa = FALSE;
+ u_int8_t np = ISAKMP_NEXT_NONE;
+
+ st->st_whack_sock = whack_sock;
+ st->st_connection = c;
+ set_cur_state(st); /* we must reset before exit */
+ st->st_policy = policy;
+ st->st_try = try;
+
+ st->st_myuserprotoid = c->spd.this.protocol;
+ st->st_peeruserprotoid = c->spd.that.protocol;
+ st->st_myuserport = c->spd.this.port;
+ st->st_peeruserport = c->spd.that.port;
+
+ st->st_msgid = generate_msgid(isakmp_sa);
+ st->st_state = STATE_QUICK_I1;
+
+ insert_state(st); /* needs cookies, connection, and msgid */
+
+ if (replacing == SOS_NOBODY)
+ plog("initiating Quick Mode %s {using isakmp#%lu}"
+ , prettypolicy(policy)
+ , isakmp_sa->st_serialno);
+ else
+ plog("initiating Quick Mode %s to replace #%lu {using isakmp#%lu}"
+ , prettypolicy(policy)
+ , replacing
+ , isakmp_sa->st_serialno);
+
+#ifdef NAT_TRAVERSAL
+ if (isakmp_sa->nat_traversal & NAT_T_DETECTED)
+ {
+ /* Duplicate nat_traversal status in new state */
+ st->nat_traversal = isakmp_sa->nat_traversal;
+
+ if (isakmp_sa->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))
+ has_client = TRUE;
+
+ nat_traversal_change_port_lookup(NULL, st);
+ }
+ else
+ st->nat_traversal = 0;
+
+ /* are we going to send a NAT-OA payload? */
+ if ((st->nat_traversal & NAT_T_WITH_NATOA)
+ && !(st->st_policy & POLICY_TUNNEL)
+ && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)))
+ {
+ send_natoa = TRUE;
+ np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ?
+ ISAKMP_NEXT_NATOA_RFC : ISAKMP_NEXT_NATOA_DRAFTS;
+ }
+#endif
+
+ /* set up reply */
+ init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet");
+
+ /* HDR* out */
+ {
+ struct isakmp_hdr hdr;
+
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_HASH;
+ hdr.isa_xchg = ISAKMP_XCHG_QUICK;
+ hdr.isa_msgid = st->st_msgid;
+ hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
+ memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* HASH(1) -- create and note space to be filled later */
+ START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA);
+
+ /* SA out */
+
+ /*
+ * See if pfs_group has been specified for this conn,
+ * if not, fallback to old use-same-as-P1 behaviour
+ */
+#ifndef NO_IKE_ALG
+ if (st->st_connection)
+ st->st_pfs_group = ike_alg_pfsgroup(st->st_connection, policy);
+ if (!st->st_pfs_group)
+#endif
+ /* If PFS specified, use the same group as during Phase 1:
+ * since no negotiation is possible, we pick one that is
+ * very likely supported.
+ */
+ st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL;
+
+ /* Emit SA payload based on a subset of the policy bits.
+ * POLICY_COMPRESS is considered iff we can do IPcomp.
+ */
+ {
+ lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE;
+
+ if (can_do_IPcomp)
+ pm |= POLICY_COMPRESS;
+
+ if (!out_sa(&rbody
+ , &ipsec_sadb[(st->st_policy & pm) >> POLICY_IPSEC_SHIFT]
+ , st, FALSE, ISAKMP_NEXT_NONCE))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* Ni out */
+ if (!build_and_ship_nonce(&st->st_ni, &rbody
+ , policy & POLICY_PFS? ISAKMP_NEXT_KE : has_client? ISAKMP_NEXT_ID : np
+ , "Ni"))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* [ KE ] out (for PFS) */
+
+ if (st->st_pfs_group != NULL)
+ {
+ if (!build_and_ship_KE(st, &st->st_gi, st->st_pfs_group
+ , &rbody, has_client? ISAKMP_NEXT_ID : np))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* [ IDci, IDcr ] out */
+ if (has_client)
+ {
+ /* IDci (we are initiator), then IDcr (peer is responder) */
+ if (!emit_subnet_id(&c->spd.this.client
+ , ISAKMP_NEXT_ID, st->st_myuserprotoid, st->st_myuserport, &rbody)
+ || !emit_subnet_id(&c->spd.that.client
+ , np, st->st_peeruserprotoid, st->st_peeruserport, &rbody))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+#ifdef NAT_TRAVERSAL
+ /* Send NAT-OA if our address is NATed */
+ if (send_natoa)
+ {
+ if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+ }
+#endif
+
+ /* finish computing HASH(1), inserting it in output */
+ (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur
+ , st, &st->st_msgid, FALSE);
+
+ /* encrypt message, except for fixed part of header */
+
+ init_phase2_iv(isakmp_sa, &st->st_msgid);
+ st->st_new_iv_len = isakmp_sa->st_new_iv_len;
+ memcpy(st->st_new_iv, isakmp_sa->st_new_iv, st->st_new_iv_len);
+
+ if (!encrypt_message(&rbody, st))
+ {
+ reset_cur_state();
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* save packet, now that we know its size */
+ clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply)
+ , "reply packet from quick_outI1");
+
+ /* send the packet */
+
+ send_packet(st, "quick_outI1");
+
+ delete_event(st);
+ event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
+
+ if (replacing == SOS_NOBODY)
+ whack_log(RC_NEW_STATE + STATE_QUICK_I1
+ , "%s: initiate"
+ , enum_name(&state_names, st->st_state));
+ else
+ whack_log(RC_NEW_STATE + STATE_QUICK_I1
+ , "%s: initiate to replace #%lu"
+ , enum_name(&state_names, st->st_state)
+ , replacing);
+ reset_cur_state();
+ return STF_OK;
+}
+
+
+/*
+ * Decode the CERT payload of Phase 1.
+ */
+static void
+decode_cert(struct msg_digest *md)
+{
+ struct payload_digest *p;
+
+ for (p = md->chain[ISAKMP_NEXT_CERT]; p != NULL; p = p->next)
+ {
+ struct isakmp_cert *const cert = &p->payload.cert;
+ chunk_t blob;
+ time_t valid_until;
+ blob.ptr = p->pbs.cur;
+ blob.len = pbs_left(&p->pbs);
+ if (cert->isacert_type == CERT_X509_SIGNATURE)
+ {
+ x509cert_t cert = empty_x509cert;
+ if (parse_x509cert(blob, 0, &cert))
+ {
+ if (verify_x509cert(&cert, strict_crl_policy, &valid_until))
+ {
+ DBG(DBG_PARSING,
+ DBG_log("Public key validated")
+ )
+ add_x509_public_key(&cert, valid_until, DAL_SIGNED);
+ }
+ else
+ {
+ plog("X.509 certificate rejected");
+ }
+ free_generalNames(cert.subjectAltName, FALSE);
+ free_generalNames(cert.crlDistributionPoints, FALSE);
+ }
+ else
+ plog("Syntax error in X.509 certificate");
+ }
+ else if (cert->isacert_type == CERT_PKCS7_WRAPPED_X509)
+ {
+ x509cert_t *cert = NULL;
+
+ if (pkcs7_parse_signedData(blob, NULL, &cert, NULL, NULL))
+ store_x509certs(&cert, strict_crl_policy);
+ else
+ plog("Syntax error in PKCS#7 wrapped X.509 certificates");
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "ignoring %s certificate payload",
+ enum_show(&cert_type_names, cert->isacert_type));
+ DBG_cond_dump_chunk(DBG_PARSING, "CERT:\n", blob);
+ }
+ }
+}
+
+/*
+ * Decode the CR payload of Phase 1.
+ */
+static void
+decode_cr(struct msg_digest *md, struct connection *c)
+{
+ struct payload_digest *p;
+
+ for (p = md->chain[ISAKMP_NEXT_CR]; p != NULL; p = p->next)
+ {
+ struct isakmp_cr *const cr = &p->payload.cr;
+ chunk_t ca_name;
+
+ ca_name.len = pbs_left(&p->pbs);
+ ca_name.ptr = (ca_name.len > 0)? p->pbs.cur : NULL;
+
+ DBG_cond_dump_chunk(DBG_PARSING, "CR", ca_name);
+
+ if (cr->isacr_type == CERT_X509_SIGNATURE)
+ {
+ char buf[BUF_LEN];
+
+ if (ca_name.len > 0)
+ {
+ generalName_t *gn;
+
+ if (!is_asn1(ca_name))
+ continue;
+
+ gn = alloc_thing(generalName_t, "generalName");
+ clonetochunk(ca_name, ca_name.ptr,ca_name.len, "ca name");
+ gn->kind = GN_DIRECTORY_NAME;
+ gn->name = ca_name;
+ gn->next = c->requested_ca;
+ c->requested_ca = gn;
+ }
+ c->got_certrequest = TRUE;
+
+ DBG(DBG_PARSING | DBG_CONTROL,
+ dntoa_or_null(buf, BUF_LEN, ca_name, "%any");
+ DBG_log("requested CA: '%s'", buf);
+ )
+ }
+ else
+ loglog(RC_LOG_SERIOUS, "ignoring %s certificate request payload",
+ enum_show(&cert_type_names, cr->isacr_type));
+ }
+}
+
+/* Decode the ID payload of Phase 1 (main_inI3_outR3 and main_inR3)
+ * Note: we may change connections as a result.
+ * We must be called before SIG or HASH are decoded since we
+ * may change the peer's RSA key or ID.
+ */
+static bool
+decode_peer_id(struct msg_digest *md, struct id *peer)
+{
+ struct state *const st = md->st;
+ struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID];
+ const pb_stream *const id_pbs = &id_pld->pbs;
+ struct isakmp_id *const id = &id_pld->payload.id;
+
+ /* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused.
+ * It talks about the protocol ID and Port fields of the ID
+ * Payload, but they don't exist as such in Phase 1.
+ * We use more appropriate names.
+ * isaid_doi_specific_a is in place of Protocol ID.
+ * isaid_doi_specific_b is in place of Port.
+ * Besides, there is no good reason for allowing these to be
+ * other than 0 in Phase 1.
+ */
+#ifdef NAT_TRAVERSAL
+ if ((st->nat_traversal & NAT_T_WITH_PORT_FLOATING)
+ && id->isaid_doi_specific_a == IPPROTO_UDP
+ && (id->isaid_doi_specific_b == 0 || id->isaid_doi_specific_b == NAT_T_IKE_FLOAT_PORT))
+ {
+ DBG_log("protocol/port in Phase 1 ID Payload is %d/%d. "
+ "accepted with port_floating NAT-T",
+ id->isaid_doi_specific_a, id->isaid_doi_specific_b);
+ }
+ else
+#endif
+ if (!(id->isaid_doi_specific_a == 0 && id->isaid_doi_specific_b == 0)
+ && !(id->isaid_doi_specific_a == IPPROTO_UDP && id->isaid_doi_specific_b == IKE_UDP_PORT))
+ {
+ loglog(RC_LOG_SERIOUS, "protocol/port in Phase 1 ID Payload must be 0/0 or %d/%d"
+ " but are %d/%d"
+ , IPPROTO_UDP, IKE_UDP_PORT
+ , id->isaid_doi_specific_a, id->isaid_doi_specific_b);
+ return FALSE;
+ }
+
+ peer->kind = id->isaid_idtype;
+
+ switch (peer->kind)
+ {
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ /* failure mode for initaddr is probably inappropriate address length */
+ {
+ err_t ugh = initaddr(id_pbs->cur, pbs_left(id_pbs)
+ , peer->kind == ID_IPV4_ADDR? AF_INET : AF_INET6
+ , &peer->ip_addr);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "improper %s identification payload: %s"
+ , enum_show(&ident_names, peer->kind), ugh);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ }
+ break;
+
+ case ID_USER_FQDN:
+ if (memchr(id_pbs->cur, '@', pbs_left(id_pbs)) == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "peer's ID_USER_FQDN contains no @");
+ return FALSE;
+ }
+ /* FALLTHROUGH */
+ case ID_FQDN:
+ if (memchr(id_pbs->cur, '\0', pbs_left(id_pbs)) != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "Phase 1 ID Payload of type %s contains a NUL"
+ , enum_show(&ident_names, peer->kind));
+ return FALSE;
+ }
+
+ /* ??? ought to do some more sanity check, but what? */
+
+ setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs));
+ break;
+
+ case ID_KEY_ID:
+ setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs));
+ DBG(DBG_PARSING,
+ DBG_dump_chunk("KEY ID:", peer->name));
+ break;
+
+ case ID_DER_ASN1_DN:
+ setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs));
+ DBG(DBG_PARSING,
+ DBG_dump_chunk("DER ASN1 DN:", peer->name));
+ break;
+
+ default:
+ /* XXX Could send notification back */
+ loglog(RC_LOG_SERIOUS, "Unacceptable identity type (%s) in Phase 1 ID Payload"
+ , enum_show(&ident_names, peer->kind));
+ return FALSE;
+ }
+
+ {
+ char buf[BUF_LEN];
+
+ idtoa(peer, buf, sizeof(buf));
+ plog("Peer ID is %s: '%s'",
+ enum_show(&ident_names, id->isaid_idtype), buf);
+ }
+
+ /* check for certificates */
+ decode_cert(md);
+ return TRUE;
+}
+
+/* Now that we've decoded the ID payload, let's see if we
+ * need to switch connections.
+ * We must not switch horses if we initiated:
+ * - if the initiation was explicit, we'd be ignoring user's intent
+ * - if opportunistic, we'll lose our HOLD info
+ */
+static bool
+switch_connection(struct msg_digest *md, struct id *peer, bool initiator)
+{
+ struct state *const st = md->st;
+ struct connection *c = st->st_connection;
+
+ chunk_t peer_ca = (st->st_peer_pubkey != NULL)
+ ? st->st_peer_pubkey->issuer : empty_chunk;
+
+ DBG(DBG_CONTROL,
+ char buf[BUF_LEN];
+
+ dntoa_or_null(buf, BUF_LEN, peer_ca, "%none");
+ DBG_log("peer CA: '%s'", buf);
+ )
+
+ if (initiator)
+ {
+ int pathlen;
+
+ if (!same_id(&c->spd.that.id, peer))
+ {
+ char expect[BUF_LEN]
+ , found[BUF_LEN];
+
+ idtoa(&c->spd.that.id, expect, sizeof(expect));
+ idtoa(peer, found, sizeof(found));
+ loglog(RC_LOG_SERIOUS
+ , "we require peer to have ID '%s', but peer declares '%s'"
+ , expect, found);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ char buf[BUF_LEN];
+
+ dntoa_or_null(buf, BUF_LEN, c->spd.this.ca, "%none");
+ DBG_log("required CA: '%s'", buf);
+ )
+
+ if (!trusted_ca(peer_ca, c->spd.that.ca, &pathlen))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "we don't accept the peer's CA");
+ return FALSE;
+ }
+ }
+ else
+ {
+ struct connection *r;
+
+ /* check for certificate requests */
+ decode_cr(md, c);
+
+ r = refine_host_connection(st, peer, peer_ca);
+
+ /* delete the collected certificate requests */
+ free_generalNames(c->requested_ca, TRUE);
+ c->requested_ca = NULL;
+
+ if (r == NULL)
+ {
+ char buf[BUF_LEN];
+
+ idtoa(peer, buf, sizeof(buf));
+ loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%s'", buf);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ char buf[BUF_LEN];
+
+ dntoa_or_null(buf, BUF_LEN, r->spd.this.ca, "%none");
+ DBG_log("offered CA: '%s'", buf);
+ )
+
+ if (r != c)
+ {
+ /* apparently, r is an improvement on c -- replace */
+
+ DBG(DBG_CONTROL
+ , DBG_log("switched from \"%s\" to \"%s\"", c->name, r->name));
+ if (r->kind == CK_TEMPLATE)
+ {
+ /* instantiate it, filling in peer's ID */
+ r = rw_instantiate(r, &c->spd.that.host_addr,
+#ifdef NAT_TRAVERSAL
+ c->spd.that.host_port,
+#endif
+#ifdef VIRTUAL_IP
+ NULL,
+#endif
+ peer);
+ }
+
+ /* copy certificate request info */
+ r->got_certrequest = c->got_certrequest;
+
+ st->st_connection = r; /* kill reference to c */
+ set_cur_connection(r);
+ connection_discard(c);
+ }
+ else if (c->spd.that.has_id_wildcards)
+ {
+ free_id_content(&c->spd.that.id);
+ c->spd.that.id = *peer;
+ c->spd.that.has_id_wildcards = FALSE;
+ unshare_id_content(&c->spd.that.id);
+ }
+ }
+ return TRUE;
+}
+
+/* Decode the variable part of an ID packet (during Quick Mode).
+ * This is designed for packets that identify clients, not peers.
+ * Rejects 0.0.0.0/32 or IPv6 equivalent because
+ * (1) it is wrong and (2) we use this value for inband signalling.
+ */
+static bool
+decode_net_id(struct isakmp_ipsec_id *id
+, pb_stream *id_pbs
+, ip_subnet *net
+, const char *which)
+{
+ const struct af_info *afi = NULL;
+
+ /* Note: the following may be a pointer into static memory
+ * that may be recycled, but only if the type is not known.
+ * That case is disposed of very early -- in the first switch.
+ */
+ const char *idtypename = enum_show(&ident_names, id->isaiid_idtype);
+
+ switch (id->isaiid_idtype)
+ {
+ case ID_IPV4_ADDR:
+ case ID_IPV4_ADDR_SUBNET:
+ case ID_IPV4_ADDR_RANGE:
+ afi = &af_inet4_info;
+ break;
+ case ID_IPV6_ADDR:
+ case ID_IPV6_ADDR_SUBNET:
+ case ID_IPV6_ADDR_RANGE:
+ afi = &af_inet6_info;
+ break;
+ case ID_FQDN:
+ return TRUE;
+ default:
+ /* XXX support more */
+ loglog(RC_LOG_SERIOUS, "unsupported ID type %s"
+ , idtypename);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+
+ switch (id->isaiid_idtype)
+ {
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ {
+ ip_address temp_address;
+ err_t ugh;
+
+ ugh = initaddr(id_pbs->cur, pbs_left(id_pbs), afi->af, &temp_address);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s has wrong length in Quick I1 (%s)"
+ , which, idtypename, ugh);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ if (isanyaddr(&temp_address))
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s is invalid (%s) in Quick I1"
+ , which, idtypename, ip_str(&temp_address));
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ happy(addrtosubnet(&temp_address, net));
+ DBG(DBG_PARSING | DBG_CONTROL
+ , DBG_log("%s is %s", which, ip_str(&temp_address)));
+ break;
+ }
+
+ case ID_IPV4_ADDR_SUBNET:
+ case ID_IPV6_ADDR_SUBNET:
+ {
+ ip_address temp_address, temp_mask;
+ err_t ugh;
+
+ if (pbs_left(id_pbs) != 2 * afi->ia_sz)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1"
+ , which, idtypename);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ ugh = initaddr(id_pbs->cur
+ , afi->ia_sz, afi->af, &temp_address);
+ if (ugh == NULL)
+ ugh = initaddr(id_pbs->cur + afi->ia_sz
+ , afi->ia_sz, afi->af, &temp_mask);
+ if (ugh == NULL)
+ ugh = initsubnet(&temp_address, masktocount(&temp_mask)
+ , '0', net);
+ if (ugh == NULL && subnetisnone(net))
+ ugh = "contains only anyaddr";
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s bad subnet in Quick I1 (%s)"
+ , which, idtypename, ugh);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ DBG(DBG_PARSING | DBG_CONTROL,
+ {
+ char temp_buff[SUBNETTOT_BUF];
+
+ subnettot(net, 0, temp_buff, sizeof(temp_buff));
+ DBG_log("%s is subnet %s", which, temp_buff);
+ });
+ break;
+ }
+
+ case ID_IPV4_ADDR_RANGE:
+ case ID_IPV6_ADDR_RANGE:
+ {
+ ip_address temp_address_from, temp_address_to;
+ err_t ugh;
+
+ if (pbs_left(id_pbs) != 2 * afi->ia_sz)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1"
+ , which, idtypename);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+ ugh = initaddr(id_pbs->cur, afi->ia_sz, afi->af, &temp_address_from);
+ if (ugh == NULL)
+ ugh = initaddr(id_pbs->cur + afi->ia_sz
+ , afi->ia_sz, afi->af, &temp_address_to);
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID payload %s malformed (%s) in Quick I1"
+ , which, idtypename, ugh);
+ /* XXX Could send notification back */
+ return FALSE;
+ }
+
+ ugh = rangetosubnet(&temp_address_from, &temp_address_to, net);
+ if (ugh == NULL && subnetisnone(net))
+ ugh = "contains only anyaddr";
+ if (ugh != NULL)
+ {
+ char temp_buff1[ADDRTOT_BUF], temp_buff2[ADDRTOT_BUF];
+
+ addrtot(&temp_address_from, 0, temp_buff1, sizeof(temp_buff1));
+ addrtot(&temp_address_to, 0, temp_buff2, sizeof(temp_buff2));
+ loglog(RC_LOG_SERIOUS, "%s ID payload in Quick I1, %s"
+ " %s - %s unacceptable: %s"
+ , which, idtypename, temp_buff1, temp_buff2, ugh);
+ return FALSE;
+ }
+ DBG(DBG_PARSING | DBG_CONTROL,
+ {
+ char temp_buff[SUBNETTOT_BUF];
+
+ subnettot(net, 0, temp_buff, sizeof(temp_buff));
+ DBG_log("%s is subnet %s (received as range)"
+ , which, temp_buff);
+ });
+ break;
+ }
+ }
+
+ /* set the port selector */
+ setportof(htons(id->isaiid_port), &net->addr);
+
+ DBG(DBG_PARSING | DBG_CONTROL,
+ DBG_log("%s protocol/port is %d/%d", which, id->isaiid_protoid, id->isaiid_port)
+ )
+
+ return TRUE;
+}
+
+/* like decode, but checks that what is received matches what was sent */
+static bool
+
+check_net_id(struct isakmp_ipsec_id *id
+, pb_stream *id_pbs
+, u_int8_t *protoid
+, u_int16_t *port
+, ip_subnet *net
+, const char *which)
+{
+ ip_subnet net_temp;
+
+ if (!decode_net_id(id, id_pbs, &net_temp, which))
+ return FALSE;
+
+ if (!samesubnet(net, &net_temp)
+ || *protoid != id->isaiid_protoid || *port != id->isaiid_port)
+ {
+ loglog(RC_LOG_SERIOUS, "%s ID returned doesn't match my proposal", which);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * look for the existence of a non-expiring preloaded public key
+ */
+static bool
+has_preloaded_public_key(struct state *st)
+{
+ struct connection *c = st->st_connection;
+
+ /* do not consider rw connections since
+ * the peer's identity must be known
+ */
+ if (c->kind == CK_PERMANENT)
+ {
+ pubkey_list_t *p;
+
+ /* look for a matching RSA public key */
+ for (p = pubkeys; p != NULL; p = p->next)
+ {
+ pubkey_t *key = p->key;
+
+ if (key->alg == PUBKEY_ALG_RSA &&
+ same_id(&c->spd.that.id, &key->id) &&
+ key->until_time == UNDEFINED_TIME)
+ {
+ /* found a preloaded public key */
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Produce the new key material of Quick Mode.
+ * RFC 2409 "IKE" section 5.5
+ * specifies how this is to be done.
+ */
+static void
+compute_proto_keymat(struct state *st
+, u_int8_t protoid
+, struct ipsec_proto_info *pi)
+{
+ size_t needed_len; /* bytes of keying material needed */
+
+ /* Add up the requirements for keying material
+ * (It probably doesn't matter if we produce too much!)
+ */
+ switch (protoid)
+ {
+ case PROTO_IPSEC_ESP:
+ switch (pi->attrs.transid)
+ {
+ case ESP_NULL:
+ needed_len = 0;
+ break;
+ case ESP_DES:
+ needed_len = DES_CBC_BLOCK_SIZE;
+ break;
+ case ESP_3DES:
+ needed_len = DES_CBC_BLOCK_SIZE * 3;
+ break;
+ default:
+#ifndef NO_KERNEL_ALG
+ if((needed_len=kernel_alg_esp_enc_keylen(pi->attrs.transid))>0) {
+ /* XXX: check key_len "coupling with kernel.c's */
+ if (pi->attrs.key_len) {
+ needed_len=pi->attrs.key_len/8;
+ DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
+ "key_len=%d from peer",
+ (int)needed_len));
+ }
+ break;
+ }
+#endif
+ bad_case(pi->attrs.transid);
+ }
+
+#ifndef NO_KERNEL_ALG
+ DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
+ "needed_len (after ESP enc)=%d",
+ (int)needed_len));
+ if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL)) {
+ needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth);
+ } else
+#endif
+ switch (pi->attrs.auth)
+ {
+ case AUTH_ALGORITHM_NONE:
+ break;
+ case AUTH_ALGORITHM_HMAC_MD5:
+ needed_len += HMAC_MD5_KEY_LEN;
+ break;
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ needed_len += HMAC_SHA1_KEY_LEN;
+ break;
+ case AUTH_ALGORITHM_DES_MAC:
+ default:
+ bad_case(pi->attrs.auth);
+ }
+ DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
+ "needed_len (after ESP auth)=%d",
+ (int)needed_len));
+ break;
+
+ case PROTO_IPSEC_AH:
+ switch (pi->attrs.transid)
+ {
+ case AH_MD5:
+ needed_len = HMAC_MD5_KEY_LEN;
+ break;
+ case AH_SHA:
+ needed_len = HMAC_SHA1_KEY_LEN;
+ break;
+ default:
+ bad_case(pi->attrs.transid);
+ }
+ break;
+
+ default:
+ bad_case(protoid);
+ }
+
+ pi->keymat_len = needed_len;
+
+ /* Allocate space for the keying material.
+ * Although only needed_len bytes are desired, we
+ * must round up to a multiple of ctx.hmac_digest_size
+ * so that our buffer isn't overrun.
+ */
+ {
+ struct hmac_ctx ctx_me, ctx_peer;
+ size_t needed_space; /* space needed for keying material (rounded up) */
+ size_t i;
+
+ hmac_init_chunk(&ctx_me, st->st_oakley.hasher, st->st_skeyid_d);
+ ctx_peer = ctx_me; /* duplicate initial conditions */
+
+ needed_space = needed_len + pad_up(needed_len, ctx_me.hmac_digest_size);
+ replace(pi->our_keymat, alloc_bytes(needed_space, "keymat in compute_keymat()"));
+ replace(pi->peer_keymat, alloc_bytes(needed_space, "peer_keymat in quick_inI1_outR1()"));
+
+ for (i = 0;; )
+ {
+ if (st->st_shared.ptr != NULL)
+ {
+ /* PFS: include the g^xy */
+ hmac_update_chunk(&ctx_me, st->st_shared);
+ hmac_update_chunk(&ctx_peer, st->st_shared);
+ }
+ hmac_update(&ctx_me, &protoid, sizeof(protoid));
+ hmac_update(&ctx_peer, &protoid, sizeof(protoid));
+
+ hmac_update(&ctx_me, (u_char *)&pi->our_spi, sizeof(pi->our_spi));
+ hmac_update(&ctx_peer, (u_char *)&pi->attrs.spi, sizeof(pi->attrs.spi));
+
+ hmac_update_chunk(&ctx_me, st->st_ni);
+ hmac_update_chunk(&ctx_peer, st->st_ni);
+
+ hmac_update_chunk(&ctx_me, st->st_nr);
+ hmac_update_chunk(&ctx_peer, st->st_nr);
+
+ hmac_final(pi->our_keymat + i, &ctx_me);
+ hmac_final(pi->peer_keymat + i, &ctx_peer);
+
+ i += ctx_me.hmac_digest_size;
+ if (i >= needed_space)
+ break;
+
+ /* more keying material needed: prepare to go around again */
+
+ hmac_reinit(&ctx_me);
+ hmac_reinit(&ctx_peer);
+
+ hmac_update(&ctx_me, pi->our_keymat + i - ctx_me.hmac_digest_size
+ , ctx_me.hmac_digest_size);
+ hmac_update(&ctx_peer, pi->peer_keymat + i - ctx_peer.hmac_digest_size
+ , ctx_peer.hmac_digest_size);
+ }
+ }
+
+ DBG(DBG_CRYPT,
+ DBG_dump("KEYMAT computed:\n", pi->our_keymat, pi->keymat_len);
+ DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, pi->keymat_len));
+}
+
+static void
+compute_keymats(struct state *st)
+{
+ if (st->st_ah.present)
+ compute_proto_keymat(st, PROTO_IPSEC_AH, &st->st_ah);
+ if (st->st_esp.present)
+ compute_proto_keymat(st, PROTO_IPSEC_ESP, &st->st_esp);
+}
+
+/* State Transition Functions.
+ *
+ * The definition of state_microcode_table in demux.c is a good
+ * overview of these routines.
+ *
+ * - Called from process_packet; result handled by complete_state_transition
+ * - struct state_microcode member "processor" points to these
+ * - these routine definitionss are in state order
+ * - these routines must be restartable from any point of error return:
+ * beware of memory allocated before any error.
+ * - output HDR is usually emitted by process_packet (if state_microcode
+ * member first_out_payload isn't ISAKMP_NEXT_NONE).
+ *
+ * The transition functions' functions include:
+ * - process and judge payloads
+ * - update st_iv (result of decryption is in st_new_iv)
+ * - build reply packet
+ */
+
+/* Handle a Main Mode Oakley first packet (responder side).
+ * HDR;SA --> HDR;SA
+ */
+stf_status
+main_inI1_outR1(struct msg_digest *md)
+{
+ struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
+ struct state *st;
+ struct connection *c = find_host_connection(&md->iface->addr, pluto_port
+ , &md->sender, md->sender_port, LEMPTY);
+ struct isakmp_proposal proposal;
+ pb_stream proposal_pbs;
+ pb_stream r_sa_pbs;
+ u_int32_t ipsecdoisit;
+ lset_t policy = LEMPTY;
+ int vids_to_send = 0;
+
+ RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sa_pd->payload.sa
+ , &sa_pd->pbs, &ipsecdoisit, &proposal_pbs, &proposal));
+
+#ifdef NAT_TRAVERSAL
+ if (c == NULL && md->iface->ike_float)
+ {
+ c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT
+ , &md->sender, md->sender_port, LEMPTY);
+ }
+#endif
+
+ if (c == NULL)
+ {
+ /* See if a wildcarded connection can be found.
+ * We cannot pick the right connection, so we're making a guess.
+ * All Road Warrior connections are fair game:
+ * we pick the first we come across (if any).
+ * If we don't find any, we pick the first opportunistic
+ * with the smallest subnet that includes the peer.
+ * There is, of course, no necessary relationship between
+ * an Initiator's address and that of its client,
+ * but Food Groups kind of assumes one.
+ */
+ {
+ struct connection *d;
+
+ backup_pbs(&proposal_pbs);
+ RETURN_STF_FAILURE(parse_isakmp_policy(&proposal_pbs
+ , proposal.isap_notrans, &policy));
+ restore_pbs(&proposal_pbs);
+
+ d = find_host_connection(&md->iface->addr
+ , pluto_port, (ip_address*)NULL, md->sender_port, policy);
+
+ for (; d != NULL; d = d->hp_next)
+ {
+ if (d->kind == CK_GROUP)
+ {
+ /* ignore */
+ }
+ else
+ {
+ if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO))
+ {
+ /* must be Road Warrior: we have a winner */
+ c = d;
+ break;
+ }
+
+ /* Opportunistic or Shunt: pick tightest match */
+ if (addrinsubnet(&md->sender, &d->spd.that.client)
+ && (c == NULL || !subnetinsubnet(&c->spd.that.client, &d->spd.that.client)))
+ c = d;
+ }
+ }
+ }
+
+ if (c == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u"
+ " but no connection has been authorized%s%s"
+ , ip_str(&md->iface->addr), ntohs(portof(&md->iface->addr))
+ , (policy != LEMPTY) ? " with policy=" : ""
+ , (policy != LEMPTY) ? bitnamesof(sa_policy_bit_names, policy) : "");
+ /* XXX notification is in order! */
+ return STF_IGNORE;
+ }
+ else if (c->kind != CK_TEMPLATE)
+ {
+ loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u"
+ " but \"%s\" forbids connection"
+ , ip_str(&md->iface->addr), pluto_port, c->name);
+ /* XXX notification is in order! */
+ return STF_IGNORE;
+ }
+ else
+ {
+ /* Create a temporary connection that is a copy of this one.
+ * His ID isn't declared yet.
+ */
+ c = rw_instantiate(c, &md->sender,
+#ifdef NAT_TRAVERSAL
+ md->sender_port,
+#endif
+#ifdef VIRTUAL_IP
+ NULL,
+#endif
+ NULL);
+ }
+ }
+
+ /* Set up state */
+ md->st = st = new_state();
+ st->st_connection = c;
+ set_cur_state(st); /* (caller will reset cur_state) */
+ st->st_try = 0; /* not our job to try again from start */
+ st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */
+
+ memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE);
+ get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender);
+
+ insert_state(st); /* needs cookies, connection, and msgid (0) */
+
+ st->st_doi = ISAKMP_DOI_IPSEC;
+ st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */
+
+ if ((c->kind == CK_INSTANCE) && (c->spd.that.host_port != pluto_port))
+ {
+ plog("responding to Main Mode from unknown peer %s:%u"
+ , ip_str(&c->spd.that.host_addr), c->spd.that.host_port);
+ }
+ else if (c->kind == CK_INSTANCE)
+ {
+ plog("responding to Main Mode from unknown peer %s"
+ , ip_str(&c->spd.that.host_addr));
+ }
+ else
+ {
+ plog("responding to Main Mode");
+ }
+
+ /* parse_isakmp_sa also spits out a winning SA into our reply,
+ * so we have to build our md->reply and emit HDR before calling it.
+ */
+
+ /* determine how many Vendor ID payloads we will be sending */
+ if (SEND_PLUTO_VID)
+ vids_to_send++;
+ if (SEND_XAUTH_VID)
+ vids_to_send++;
+ if (md->openpgp)
+ vids_to_send++;
+ /* always send DPD Vendor ID */
+ vids_to_send++;
+#ifdef NAT_TRAVERSAL
+ if (md->nat_traversal_vid && nat_traversal_enabled)
+ vids_to_send++;
+#endif
+
+ /* HDR out.
+ * We can't leave this to comm_handle() because we must
+ * fill in the cookie.
+ */
+ {
+ struct isakmp_hdr r_hdr = md->hdr;
+
+ r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */
+ memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ r_hdr.isa_np = ISAKMP_NEXT_SA;
+ if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* start of SA out */
+ {
+ struct isakmp_sa r_sa = sa_pd->payload.sa;
+
+ r_sa.isasa_np = vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE;
+
+ if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs))
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* SA body in and out */
+ RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit, &proposal_pbs
+ ,&proposal, &r_sa_pbs, st));
+
+ /* if enabled send Pluto Vendor ID */
+ if (SEND_PLUTO_VID)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, VID_STRONGSWAN))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* if enabled send XAUTH Vendor ID */
+ if (SEND_XAUTH_VID)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, VID_MISC_XAUTH))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /*
+ * if the peer sent an OpenPGP Vendor ID we offer the same capability
+ */
+ if (md->openpgp)
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, VID_OPENPGP))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* Announce our ability to do Dead Peer Detection to the peer */
+ {
+ if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, VID_MISC_DPD))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+#ifdef NAT_TRAVERSAL
+ DBG(DBG_CONTROLMORE,
+ DBG_log("sender checking NAT-t: %d and %d"
+ , nat_traversal_enabled, md->nat_traversal_vid)
+ )
+ if (md->nat_traversal_vid && nat_traversal_enabled)
+ {
+ /* reply if NAT-Traversal draft is supported */
+ st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid);
+
+ if (st->nat_traversal
+ && !out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+ , &md->rbody, md->nat_traversal_vid))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+#endif
+
+ close_message(&md->rbody);
+
+ /* save initiator SA for HASH */
+ clonereplacechunk(st->st_p1isa, sa_pd->pbs.start, pbs_room(&sa_pd->pbs), "sa in main_inI1_outR1()");
+
+ return STF_OK;
+}
+
+/* STATE_MAIN_I1: HDR, SA --> auth dependent
+ * PSK_AUTH, DS_AUTH: --> HDR, KE, Ni
+ *
+ * The following are not yet implemented:
+ * PKE_AUTH: --> HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ * RPKE_AUTH: --> HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i,
+ * <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
+ *
+ * We must verify that the proposal received matches one we sent.
+ */
+stf_status
+main_inR1_outI2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+
+ u_int8_t np = ISAKMP_NEXT_NONE;
+
+ /* verify echoed SA */
+ {
+ u_int32_t ipsecdoisit;
+ pb_stream proposal_pbs;
+ struct isakmp_proposal proposal;
+ struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
+
+ RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sapd->payload.sa
+ ,&sapd->pbs, &ipsecdoisit, &proposal_pbs, &proposal));
+ if (proposal.isap_notrans != 1)
+ {
+ loglog(RC_LOG_SERIOUS, "a single Transform is required in a selecting Oakley Proposal; found %u"
+ , (unsigned)proposal.isap_notrans);
+ RETURN_STF_FAILURE(BAD_PROPOSAL_SYNTAX);
+ }
+ RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit
+ , &proposal_pbs, &proposal, NULL, st));
+ }
+
+#ifdef NAT_TRAVERSAL
+ DBG(DBG_CONTROLMORE,
+ DBG_log("sender checking NAT-t: %d and %d"
+ , nat_traversal_enabled, md->nat_traversal_vid)
+ )
+ if (nat_traversal_enabled && md->nat_traversal_vid)
+ {
+ st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid);
+ plog("enabling possible NAT-traversal with method %s"
+ , bitnamesof(natt_type_bitnames, st->nat_traversal));
+ }
+ if (st->nat_traversal & NAT_T_WITH_NATD)
+ {
+ np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ?
+ ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS;
+ }
+ #endif
+
+ /**************** build output packet HDR;KE;Ni ****************/
+
+ /* HDR out.
+ * We can't leave this to comm_handle() because the isa_np
+ * depends on the type of Auth (eventually).
+ */
+ echo_hdr(md, FALSE, ISAKMP_NEXT_KE);
+
+ /* KE out */
+ if (!build_and_ship_KE(st, &st->st_gi, st->st_oakley.group
+ , &md->rbody, ISAKMP_NEXT_NONCE))
+ return STF_INTERNAL_ERROR;
+
+#ifdef DEBUG
+ /* Ni out */
+ if (!build_and_ship_nonce(&st->st_ni, &md->rbody
+ , (cur_debugging & IMPAIR_BUST_MI2)? ISAKMP_NEXT_VID : np, "Ni"))
+ return STF_INTERNAL_ERROR;
+
+ if (cur_debugging & IMPAIR_BUST_MI2)
+ {
+ /* generate a pointless large VID payload to push message over MTU */
+ pb_stream vid_pbs;
+
+ if (!out_generic(np, &isakmp_vendor_id_desc, &md->rbody, &vid_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&vid_pbs);
+ }
+#else
+ /* Ni out */
+ if (!build_and_ship_nonce(&st->st_ni, &md->rbody, np, "Ni"))
+ return STF_INTERNAL_ERROR;
+#endif
+
+#ifdef NAT_TRAVERSAL
+ if (st->nat_traversal & NAT_T_WITH_NATD)
+ {
+ if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md))
+ return STF_INTERNAL_ERROR;
+ }
+#endif
+
+ /* finish message */
+ close_message(&md->rbody);
+
+ /* Reinsert the state, using the responder cookie we just received */
+ unhash_state(st);
+ memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE);
+ insert_state(st); /* needs cookies, connection, and msgid (0) */
+
+ return STF_OK;
+}
+
+/* STATE_MAIN_R1:
+ * PSK_AUTH, DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr
+ *
+ * The following are not yet implemented:
+ * PKE_AUTH: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
+ * --> HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ * RPKE_AUTH:
+ * HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
+ * --> HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r
+ */
+stf_status
+main_inI2_outR2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
+
+ /* send CR if auth is RSA and no preloaded RSA public key exists*/
+ bool send_cr = !no_cr_send && (st->st_oakley.auth == OAKLEY_RSA_SIG) &&
+ !has_preloaded_public_key(st);
+
+ u_int8_t np = ISAKMP_NEXT_NONE;
+
+ /* KE in */
+ RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs));
+
+ /* Ni in */
+ RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni"));
+
+#ifdef NAT_TRAVERSAL
+ DBG(DBG_CONTROLMORE,
+ DBG_log("inI2: checking NAT-t: %d and %d"
+ , nat_traversal_enabled, st->nat_traversal)
+ )
+ if (st->nat_traversal & NAT_T_WITH_NATD)
+ {
+ nat_traversal_natd_lookup(md);
+
+ np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ?
+ ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS;
+ }
+ if (st->nat_traversal)
+ {
+ nat_traversal_show_result(st->nat_traversal, md->sender_port);
+ }
+ if (st->nat_traversal & NAT_T_WITH_KA)
+ {
+ nat_traversal_new_ka_event();
+ }
+#endif
+
+ /* decode certificate requests */
+ st->st_connection->got_certrequest = FALSE;
+ decode_cr(md, st->st_connection);
+
+ /**************** build output packet HDR;KE;Nr ****************/
+
+ /* HDR out done */
+
+ /* KE out */
+ if (!build_and_ship_KE(st, &st->st_gr, st->st_oakley.group
+ , &md->rbody, ISAKMP_NEXT_NONCE))
+ return STF_INTERNAL_ERROR;
+
+#ifdef DEBUG
+ /* Nr out */
+ if (!build_and_ship_nonce(&st->st_nr, &md->rbody
+ , (cur_debugging & IMPAIR_BUST_MR2)? ISAKMP_NEXT_VID
+ : (send_cr? ISAKMP_NEXT_CR : np), "Nr"))
+ return STF_INTERNAL_ERROR;
+
+ if (cur_debugging & IMPAIR_BUST_MR2)
+ {
+ /* generate a pointless large VID payload to push message over MTU */
+ pb_stream vid_pbs;
+
+ if (!out_generic((send_cr)? ISAKMP_NEXT_CR : np,
+ &isakmp_vendor_id_desc, &md->rbody, &vid_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&vid_pbs);
+ }
+#else
+ /* Nr out */
+ if (!build_and_ship_nonce(&st->st_nr, &md->rbody,
+ (send_cr)? ISAKMP_NEXT_CR : np, "Nr"))
+ return STF_INTERNAL_ERROR;
+#endif
+
+ /* CR out */
+ if (send_cr)
+ {
+ if (st->st_connection->kind == CK_PERMANENT)
+ {
+ if (!build_and_ship_CR(CERT_X509_SIGNATURE
+ , st->st_connection->spd.that.ca
+ , &md->rbody, np))
+ return STF_INTERNAL_ERROR;
+ }
+ else
+ {
+ generalName_t *ca = NULL;
+
+ if (collect_rw_ca_candidates(md, &ca))
+ {
+ generalName_t *gn;
+
+ for (gn = ca; gn != NULL; gn = gn->next)
+ {
+ if (!build_and_ship_CR(CERT_X509_SIGNATURE, gn->name
+ , &md->rbody
+ , gn->next == NULL ? np : ISAKMP_NEXT_CR))
+ return STF_INTERNAL_ERROR;
+ }
+ free_generalNames(ca, FALSE);
+ }
+ else
+ {
+ if (!build_and_ship_CR(CERT_X509_SIGNATURE, empty_chunk
+ , &md->rbody, np))
+ return STF_INTERNAL_ERROR;
+ }
+ }
+ }
+
+#ifdef NAT_TRAVERSAL
+ if (st->nat_traversal & NAT_T_WITH_NATD)
+ {
+ if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md))
+ return STF_INTERNAL_ERROR;
+ }
+#endif
+
+ /* finish message */
+ close_message(&md->rbody);
+
+ /* next message will be encrypted, but not this one.
+ * We could defer this calculation.
+ */
+ compute_dh_shared(st, st->st_gi, st->st_oakley.group);
+ if (!generate_skeyids_iv(st))
+ return STF_FAIL + AUTHENTICATION_FAILED;
+ update_iv(st);
+
+ return STF_OK;
+}
+
+/* STATE_MAIN_I2:
+ * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I
+ * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I
+ *
+ * The following are not yet implemented.
+ * SMF_PKE_AUTH: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
+ * --> HDR*, HASH_I
+ * SMF_RPKE_AUTH: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r
+ * --> HDR*, HASH_I
+ */
+stf_status
+main_inR2_outI3(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
+ int auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
+ ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
+ pb_stream id_pbs; /* ID Payload; also used for hash calculation */
+
+ certpolicy_t cert_policy = st->st_connection->spd.this.sendcert;
+ cert_t mycert = st->st_connection->spd.this.cert;
+ bool requested, send_cert, send_cr;
+
+ /* KE in */
+ RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs));
+
+ /* Nr in */
+ RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr"));
+
+ /* decode certificate requests */
+ st->st_connection->got_certrequest = FALSE;
+ decode_cr(md, st->st_connection);
+
+ /* free collected certificate requests since as initiator
+ * we don't heed them anyway
+ */
+ free_generalNames(st->st_connection->requested_ca, TRUE);
+ st->st_connection->requested_ca = NULL;
+
+ /* send certificate if auth is RSA, we have one and we want
+ * or are requested to send it
+ */
+ requested = cert_policy == CERT_SEND_IF_ASKED
+ && st->st_connection->got_certrequest;
+ send_cert = st->st_oakley.auth == OAKLEY_RSA_SIG
+ && mycert.type != CERT_NONE
+ && (cert_policy == CERT_ALWAYS_SEND || requested);
+
+ /* send certificate request if we don't have a preloaded RSA public key */
+ send_cr = !no_cr_send && send_cert && !has_preloaded_public_key(st);
+
+ /* done parsing; initialize crypto */
+
+ compute_dh_shared(st, st->st_gr, st->st_oakley.group);
+ if (!generate_skeyids_iv(st))
+ return STF_FAIL + AUTHENTICATION_FAILED;
+
+#ifdef NAT_TRAVERSAL
+ if (st->nat_traversal & NAT_T_WITH_NATD) {
+ nat_traversal_natd_lookup(md);
+ }
+ if (st->nat_traversal) {
+ nat_traversal_show_result(st->nat_traversal, md->sender_port);
+ }
+ if (st->nat_traversal & NAT_T_WITH_KA) {
+ nat_traversal_new_ka_event();
+ }
+#endif
+
+ /*************** build output packet HDR*;IDii;HASH/SIG_I ***************/
+ /* ??? NOTE: this is almost the same as main_inI3_outR3's code */
+
+ /* HDR* out done */
+
+ /* IDii out */
+ {
+ struct isakmp_ipsec_id id_hd;
+ chunk_t id_b;
+
+ build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
+ id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload;
+ if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &id_pbs)
+ || !out_chunk(id_b, &id_pbs, "my identity"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&id_pbs);
+ }
+
+ /* CERT out */
+ if ( st->st_oakley.auth == OAKLEY_RSA_SIG)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("our certificate policy is %s"
+ , enum_name(&cert_policy_names, cert_policy))
+ )
+ if (mycert.type != CERT_NONE)
+ {
+ const char *request_text = "";
+
+ if (cert_policy == CERT_SEND_IF_ASKED)
+ request_text = (send_cert)? "upon request":"without request";
+ plog("we have a cert %s sending it %s"
+ , send_cert? "and are":"but are not", request_text);
+ }
+ else
+ {
+ plog("we don't have a cert");
+ }
+ }
+ if (send_cert)
+ {
+ pb_stream cert_pbs;
+
+ struct isakmp_cert cert_hd;
+ cert_hd.isacert_np = (send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_SIG;
+ cert_hd.isacert_type = mycert.type;
+
+ if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_chunk(get_mycert(mycert), &cert_pbs, "CERT"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&cert_pbs);
+ }
+
+ /* CR out */
+ if (send_cr)
+ {
+ if (!build_and_ship_CR(mycert.type, st->st_connection->spd.that.ca
+ , &md->rbody, ISAKMP_NEXT_SIG))
+ return STF_INTERNAL_ERROR;
+ }
+
+ /* HASH_I or SIG_I out */
+ {
+ u_char hash_val[MAX_DIGEST_LEN];
+ size_t hash_len = main_mode_hash(st, hash_val, TRUE, &id_pbs);
+
+ if (auth_payload == ISAKMP_NEXT_HASH)
+ {
+ /* HASH_I out */
+ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody
+ , hash_val, hash_len, "HASH_I"))
+ return STF_INTERNAL_ERROR;
+ }
+ else
+ {
+ /* SIG_I out */
+ u_char sig_val[RSA_MAX_OCTETS];
+ size_t sig_len = RSA_sign_hash(st->st_connection
+ , sig_val, hash_val, hash_len);
+
+ if (sig_len == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
+ return STF_FAIL + AUTHENTICATION_FAILED;
+ }
+
+ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc
+ , &md->rbody, sig_val, sig_len, "SIG_I"))
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* encrypt message, except for fixed part of header */
+
+ /* st_new_iv was computed by generate_skeyids_iv */
+ if (!encrypt_message(&md->rbody, st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ return STF_OK;
+}
+
+/* Shared logic for asynchronous lookup of DNS KEY records.
+ * Used for STATE_MAIN_R2 and STATE_MAIN_I3.
+ */
+
+enum key_oppo_step {
+ kos_null,
+ kos_his_txt
+#ifdef USE_KEYRR
+ , kos_his_key
+#endif
+};
+
+struct key_continuation {
+ struct adns_continuation ac; /* common prefix */
+ struct msg_digest *md;
+ enum key_oppo_step step;
+ bool failure_ok;
+ err_t last_ugh;
+};
+
+typedef stf_status (key_tail_fn)(struct msg_digest *md
+ , struct key_continuation *kc);
+static void
+report_key_dns_failure(struct id *id, err_t ugh)
+{
+ char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
+
+ (void) idtoa(id, id_buf, sizeof(id_buf));
+ loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
+ "; DNS search for KEY failed (%s)", id_buf, ugh);
+}
+
+
+/* Processs the Main Mode ID Payload and the Authenticator
+ * (Hash or Signature Payload).
+ * If a DNS query is still needed to get the other host's public key,
+ * the query is initiated and STF_SUSPEND is returned.
+ * Note: parameter kc is a continuation containing the results from
+ * the previous DNS query, or NULL indicating no query has been issued.
+ */
+static stf_status
+main_id_and_auth(struct msg_digest *md
+ , bool initiator /* are we the Initiator? */
+ , cont_fn_t cont_fn /* continuation function */
+ , const struct key_continuation *kc /* current state, can be NULL */
+)
+{
+ struct state *st = md->st;
+ u_char hash_val[MAX_DIGEST_LEN];
+ size_t hash_len;
+ struct id peer;
+ stf_status r = STF_OK;
+
+ /* ID Payload in */
+ if (!decode_peer_id(md, &peer))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ /* Hash the ID Payload.
+ * main_mode_hash requires idpl->cur to be at end of payload
+ * so we temporarily set if so.
+ */
+ {
+ pb_stream *idpl = &md->chain[ISAKMP_NEXT_ID]->pbs;
+ u_int8_t *old_cur = idpl->cur;
+
+ idpl->cur = idpl->roof;
+ hash_len = main_mode_hash(st, hash_val, !initiator, idpl);
+ idpl->cur = old_cur;
+ }
+
+ switch (st->st_oakley.auth)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ {
+ pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs;
+
+ if (pbs_left(hash_pbs) != hash_len
+ || memcmp(hash_pbs->cur, hash_val, hash_len) != 0)
+ {
+ DBG_cond_dump(DBG_CRYPT, "received HASH:"
+ , hash_pbs->cur, pbs_left(hash_pbs));
+ loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value");
+ /* XXX Could send notification back */
+ r = STF_FAIL + INVALID_HASH_INFORMATION;
+ }
+ }
+ break;
+
+ case OAKLEY_RSA_SIG:
+ r = RSA_check_signature(&peer, st, hash_val, hash_len
+ , &md->chain[ISAKMP_NEXT_SIG]->pbs
+#ifdef USE_KEYRR
+ , kc == NULL? NULL : kc->ac.keys_from_dns
+#endif /* USE_KEYRR */
+ , kc == NULL? NULL : kc->ac.gateways_from_dns
+ );
+
+ if (r == STF_SUSPEND)
+ {
+ /* initiate/resume asynchronous DNS lookup for key */
+ struct key_continuation *nkc
+ = alloc_thing(struct key_continuation, "key continuation");
+ enum key_oppo_step step_done = kc == NULL? kos_null : kc->step;
+ err_t ugh;
+
+ /* Record that state is used by a suspended md */
+ passert(st->st_suspended_md == NULL);
+ st->st_suspended_md = md;
+
+ nkc->failure_ok = FALSE;
+ nkc->md = md;
+
+ switch (step_done)
+ {
+ case kos_null:
+ /* first try: look for the TXT records */
+ nkc->step = kos_his_txt;
+#ifdef USE_KEYRR
+ nkc->failure_ok = TRUE;
+#endif
+ ugh = start_adns_query(&peer
+ , &peer /* SG itself */
+ , T_TXT
+ , cont_fn
+ , &nkc->ac);
+ break;
+
+#ifdef USE_KEYRR
+ case kos_his_txt:
+ /* second try: look for the KEY records */
+ nkc->step = kos_his_key;
+ ugh = start_adns_query(&peer
+ , NULL /* no sgw for KEY */
+ , T_KEY
+ , cont_fn
+ , &nkc->ac);
+ break;
+#endif /* USE_KEYRR */
+
+ default:
+ bad_case(step_done);
+ }
+
+ if (ugh != NULL)
+ {
+ report_key_dns_failure(&peer, ugh);
+ st->st_suspended_md = NULL;
+ r = STF_FAIL + INVALID_KEY_INFORMATION;
+ }
+ }
+ break;
+
+ default:
+ bad_case(st->st_oakley.auth);
+ }
+ if (r != STF_OK)
+ return r;
+
+ DBG(DBG_CRYPT, DBG_log("authentication succeeded"));
+
+ /*
+ * With the peer ID known, let's see if we need to switch connections.
+ */
+ if (!switch_connection(md, &peer, initiator))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ return r;
+}
+
+/* This continuation is called as part of either
+ * the main_inI3_outR3 state or main_inR3 state.
+ *
+ * The "tail" function is the corresponding tail
+ * function main_inI3_outR3_tail | main_inR3_tail,
+ * either directly when the state is started, or via
+ * adns continuation.
+ *
+ * Basically, we go around in a circle:
+ * main_in?3* -> key_continue
+ * ^ \
+ * / V
+ * adns main_in?3*_tail
+ * ^ |
+ * \ V
+ * main_id_and_auth
+ *
+ * until such time as main_id_and_auth is able
+ * to find authentication, or we run out of things
+ * to try.
+ */
+static void
+key_continue(struct adns_continuation *cr
+, err_t ugh
+, key_tail_fn *tail)
+{
+ struct key_continuation *kc = (void *)cr;
+ struct state *st = kc->md->st;
+
+ passert(cur_state == NULL);
+
+ /* if st == NULL, our state has been deleted -- just clean up */
+ if (st != NULL)
+ {
+ stf_status r;
+
+ passert(st->st_suspended_md == kc->md);
+ st->st_suspended_md = NULL; /* no longer connected or suspended */
+ cur_state = st;
+
+ if (!kc->failure_ok && ugh != NULL)
+ {
+ report_key_dns_failure(&st->st_connection->spd.that.id, ugh);
+ r = STF_FAIL + INVALID_KEY_INFORMATION;
+ }
+ else
+ {
+
+#ifdef USE_KEYRR
+ passert(kc->step == kos_his_txt || kc->step == kos_his_key);
+#else
+ passert(kc->step == kos_his_txt);
+#endif
+ kc->last_ugh = ugh; /* record previous error in case we need it */
+ r = (*tail)(kc->md, kc);
+ }
+ complete_state_transition(&kc->md, r);
+ }
+ if (kc->md != NULL)
+ release_md(kc->md);
+ cur_state = NULL;
+}
+
+/* STATE_MAIN_R2:
+ * PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R
+ * DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R
+ * PKE_AUTH, RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R
+ *
+ * Broken into parts to allow asynchronous DNS lookup.
+ *
+ * - main_inI3_outR3 to start
+ * - main_inI3_outR3_tail to finish or suspend for DNS lookup
+ * - main_inI3_outR3_continue to start main_inI3_outR3_tail again
+ */
+static key_tail_fn main_inI3_outR3_tail; /* forward */
+
+stf_status
+main_inI3_outR3(struct msg_digest *md)
+{
+ return main_inI3_outR3_tail(md, NULL);
+}
+
+static void
+main_inI3_outR3_continue(struct adns_continuation *cr, err_t ugh)
+{
+ key_continue(cr, ugh, main_inI3_outR3_tail);
+}
+
+static stf_status
+main_inI3_outR3_tail(struct msg_digest *md
+, struct key_continuation *kc)
+{
+ struct state *const st = md->st;
+ u_int8_t auth_payload;
+ pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */
+ certpolicy_t cert_policy;
+ cert_t mycert;
+ bool send_cert;
+ bool requested;
+
+ /* ID and HASH_I or SIG_I in
+ * Note: this may switch the connection being used!
+ */
+ {
+ stf_status r = main_id_and_auth(md, FALSE
+ , main_inI3_outR3_continue
+ , kc);
+
+ if (r != STF_OK)
+ return r;
+ }
+
+ /* send certificate if auth is RSA, we have one and we want
+ * or are requested to send it
+ */
+ cert_policy = st->st_connection->spd.this.sendcert;
+ mycert = st->st_connection->spd.this.cert;
+ requested = cert_policy == CERT_SEND_IF_ASKED
+ && st->st_connection->got_certrequest;
+ send_cert = st->st_oakley.auth == OAKLEY_RSA_SIG
+ && mycert.type != CERT_NONE
+ && (cert_policy == CERT_ALWAYS_SEND || requested);
+
+ /*************** build output packet HDR*;IDir;HASH/SIG_R ***************/
+ /* proccess_packet() would automatically generate the HDR*
+ * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE.
+ * We don't do this because we wish there to be no partially
+ * built output packet if we need to suspend for asynch DNS.
+ */
+ /* ??? NOTE: this is almost the same as main_inR2_outI3's code */
+
+ /* HDR* out
+ * If auth were PKE_AUTH or RPKE_AUTH, ISAKMP_NEXT_HASH would
+ * be first payload.
+ */
+ echo_hdr(md, TRUE, ISAKMP_NEXT_ID);
+
+ auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
+ ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
+
+ /* IDir out */
+ {
+ /* id_hd should be struct isakmp_id, but struct isakmp_ipsec_id
+ * allows build_id_payload() to work for both phases.
+ */
+ struct isakmp_ipsec_id id_hd;
+ chunk_t id_b;
+
+ build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
+ id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload;
+ if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs)
+ || !out_chunk(id_b, &r_id_pbs, "my identity"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&r_id_pbs);
+ }
+
+ /* CERT out */
+ if (st->st_oakley.auth == OAKLEY_RSA_SIG)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("our certificate policy is %s"
+ , enum_name(&cert_policy_names, cert_policy))
+ )
+ if (mycert.type != CERT_NONE)
+ {
+ const char *request_text = "";
+
+ if (cert_policy == CERT_SEND_IF_ASKED)
+ request_text = (send_cert)? "upon request":"without request";
+ plog("we have a cert %s sending it %s"
+ , send_cert? "and are":"but are not", request_text);
+ }
+ else
+ {
+ plog("we don't have a cert");
+ }
+ }
+ if (send_cert)
+ {
+ pb_stream cert_pbs;
+
+ struct isakmp_cert cert_hd;
+ cert_hd.isacert_np = ISAKMP_NEXT_SIG;
+ cert_hd.isacert_type = mycert.type;
+
+ if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_chunk(get_mycert(mycert), &cert_pbs, "CERT"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&cert_pbs);
+ }
+
+ /* HASH_R or SIG_R out */
+ {
+ u_char hash_val[MAX_DIGEST_LEN];
+ size_t hash_len = main_mode_hash(st, hash_val, FALSE, &r_id_pbs);
+
+ if (auth_payload == ISAKMP_NEXT_HASH)
+ {
+ /* HASH_R out */
+ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody
+ , hash_val, hash_len, "HASH_R"))
+ return STF_INTERNAL_ERROR;
+ }
+ else
+ {
+ /* SIG_R out */
+ u_char sig_val[RSA_MAX_OCTETS];
+ size_t sig_len = RSA_sign_hash(st->st_connection
+ , sig_val, hash_val, hash_len);
+
+ if (sig_len == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
+ return STF_FAIL + AUTHENTICATION_FAILED;
+ }
+
+ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc
+ , &md->rbody, sig_val, sig_len, "SIG_R"))
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ /* encrypt message, sans fixed part of header */
+
+ if (!encrypt_message(&md->rbody, st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ /* Last block of Phase 1 (R3), kept for Phase 2 IV generation */
+ DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:"
+ , st->st_new_iv, st->st_new_iv_len);
+
+ ISAKMP_SA_established(st->st_connection, st->st_serialno);
+
+ /* Save Phase 1 IV */
+ st->st_ph1_iv_len = st->st_new_iv_len;
+ set_ph1_iv(st, st->st_new_iv);
+
+ return STF_OK;
+}
+
+/* STATE_MAIN_I3:
+ * Handle HDR*;IDir;HASH/SIG_R from responder.
+ *
+ * Broken into parts to allow asynchronous DNS for KEY records.
+ *
+ * - main_inR3 to start
+ * - main_inR3_tail to finish or suspend for DNS lookup
+ * - main_inR3_continue to start main_inR3_tail again
+ */
+
+static key_tail_fn main_inR3_tail; /* forward */
+
+stf_status
+main_inR3(struct msg_digest *md)
+{
+ return main_inR3_tail(md, NULL);
+}
+
+static void
+main_inR3_continue(struct adns_continuation *cr, err_t ugh)
+{
+ key_continue(cr, ugh, main_inR3_tail);
+}
+
+static stf_status
+main_inR3_tail(struct msg_digest *md
+, struct key_continuation *kc)
+{
+ struct state *const st = md->st;
+
+ /* ID and HASH_R or SIG_R in
+ * Note: this may switch the connection being used!
+ */
+ {
+ stf_status r = main_id_and_auth(md, TRUE, main_inR3_continue, kc);
+
+ if (r != STF_OK)
+ return r;
+ }
+
+ /**************** done input ****************/
+
+ ISAKMP_SA_established(st->st_connection, st->st_serialno);
+
+ /* Save Phase 1 IV */
+ st->st_ph1_iv_len = st->st_new_iv_len;
+ set_ph1_iv(st, st->st_new_iv);
+
+
+ update_iv(st); /* finalize our Phase 1 IV */
+
+ return STF_OK;
+}
+
+/* Handle first message of Phase 2 -- Quick Mode.
+ * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] -->
+ * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ]
+ * (see RFC 2409 "IKE" 5.5)
+ * Installs inbound IPsec SAs.
+ * Although this seems early, we know enough to do so, and
+ * this way we know that it is soon enough to catch all
+ * packets that other side could send using this IPsec SA.
+ *
+ * Broken into parts to allow asynchronous DNS for TXT records:
+ *
+ * - quick_inI1_outR1 starts the ball rolling.
+ * It checks and parses enough to learn the Phase 2 IDs
+ *
+ * - quick_inI1_outR1_tail does the rest of the job
+ * unless DNS must be consulted. In that case,
+ * it starts a DNS query, salts away what is needed
+ * to continue, and suspends. Calls
+ * + quick_inI1_outR1_start_query
+ * + quick_inI1_outR1_process_answer
+ *
+ * - quick_inI1_outR1_continue will restart quick_inI1_outR1_tail
+ * when DNS comes back with an answer.
+ *
+ * A big chunk of quick_inI1_outR1_tail is executed twice.
+ * This is necessary because the set of connections
+ * might change while we are awaiting DNS.
+ * When first called, gateways_from_dns == NULL. If DNS is
+ * consulted asynchronously, gateways_from_dns != NULL the second time.
+ * Remember that our state object might disappear too!
+ *
+ *
+ * If the connection is opportunistic, we must verify delegation.
+ *
+ * 1. Check that we are authorized to be SG for
+ * our client. We look for the TXT record that
+ * delegates us. We also check that the public
+ * key (if present) matches the private key we used.
+ * Eventually, we should probably require DNSsec
+ * authentication for our side.
+ *
+ * 2. If our client TXT record did not include a
+ * public key, check the KEY record indicated
+ * by the identity in the TXT record.
+ *
+ * 3. If the peer's client is the peer itself, we
+ * consider it authenticated. Otherwise, we check
+ * the TXT record for the client to see that
+ * the identity of the SG matches the peer and
+ * that some public key (if present in the TXT)
+ * matches. We need not check the public key if
+ * it isn't in the TXT record.
+ *
+ * Since p isn't yet instantiated, we need to look
+ * in c for description of peer.
+ *
+ * We cannot afford to block waiting for a DNS query.
+ * The code here is structured as two halves:
+ * - process the result of just completed
+ * DNS query (if any)
+ * - if another query is needed, initiate the next
+ * DNS query and suspend
+ */
+
+enum verify_oppo_step {
+ vos_fail,
+ vos_start,
+ vos_our_client,
+ vos_our_txt,
+#ifdef USE_KEYRR
+ vos_our_key,
+#endif /* USE_KEYRR */
+ vos_his_client,
+ vos_done
+};
+
+static const char *const verify_step_name[] = {
+ "vos_fail",
+ "vos_start",
+ "vos_our_client",
+ "vos_our_txt",
+#ifdef USE_KEYRR
+ "vos_our_key",
+#endif /* USE_KEYRR */
+ "vos_his_client",
+ "vos_done"
+};
+
+/* hold anything we can handle of a Phase 2 ID */
+struct p2id {
+ ip_subnet net;
+ u_int8_t proto;
+ u_int16_t port;
+};
+
+struct verify_oppo_bundle {
+ enum verify_oppo_step step;
+ bool failure_ok; /* if true, quick_inI1_outR1_continue will try
+ * other things on DNS failure */
+ struct msg_digest *md;
+ struct p2id my, his;
+ unsigned int new_iv_len; /* p1st's might change */
+ u_char new_iv[MAX_DIGEST_LEN];
+ /* int whackfd; */ /* not needed because we are Responder */
+};
+
+struct verify_oppo_continuation {
+ struct adns_continuation ac; /* common prefix */
+ struct verify_oppo_bundle b;
+};
+
+static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b
+ , struct adns_continuation *ac);
+
+stf_status
+quick_inI1_outR1(struct msg_digest *md)
+{
+ const struct state *const p1st = md->st;
+ struct connection *c = p1st->st_connection;
+ struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
+ struct verify_oppo_bundle b;
+
+ /* HASH(1) in */
+ CHECK_QUICK_HASH(md
+ , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof
+ , p1st, &md->hdr.isa_msgid, FALSE)
+ , "HASH(1)", "Quick I1");
+
+ /* [ IDci, IDcr ] in
+ * We do this now (probably out of physical order) because
+ * we wish to select the correct connection before we consult
+ * it for policy.
+ */
+
+ if (id_pd != NULL)
+ {
+ /* ??? we are assuming IPSEC_DOI */
+
+ /* IDci (initiator is peer) */
+
+ if (!decode_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs
+ , &b.his.net, "peer client"))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ /* Hack for MS 818043 NAT-T Update */
+
+ if (id_pd->payload.ipsec_id.isaiid_idtype == ID_FQDN)
+ happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net));
+
+ /* End Hack for MS 818043 NAT-T Update */
+
+ b.his.proto = id_pd->payload.ipsec_id.isaiid_protoid;
+ b.his.port = id_pd->payload.ipsec_id.isaiid_port;
+ b.his.net.addr.u.v4.sin_port = htons(b.his.port);
+
+ /* IDcr (we are responder) */
+
+ if (!decode_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs
+ , &b.my.net, "our client"))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ b.my.proto = id_pd->next->payload.ipsec_id.isaiid_protoid;
+ b.my.port = id_pd->next->payload.ipsec_id.isaiid_port;
+ b.my.net.addr.u.v4.sin_port = htons(b.my.port);
+ }
+ else
+ {
+ /* implicit IDci and IDcr: peer and self */
+ if (!sameaddrtype(&c->spd.this.host_addr, &c->spd.that.host_addr))
+ return STF_FAIL;
+
+ happy(addrtosubnet(&c->spd.this.host_addr, &b.my.net));
+ happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net));
+ b.his.proto = b.my.proto = 0;
+ b.his.port = b.my.port = 0;
+ }
+ b.step = vos_start;
+ b.md = md;
+ b.new_iv_len = p1st->st_new_iv_len;
+ memcpy(b.new_iv, p1st->st_new_iv, p1st->st_new_iv_len);
+ return quick_inI1_outR1_tail(&b, NULL);
+}
+
+static void
+report_verify_failure(struct verify_oppo_bundle *b, err_t ugh)
+{
+ struct state *st = b->md->st;
+ char fgwb[ADDRTOT_BUF]
+ , cb[ADDRTOT_BUF];
+ ip_address client;
+ err_t which;
+
+ switch (b->step)
+ {
+ case vos_our_client:
+ case vos_our_txt:
+#ifdef USE_KEYRR
+ case vos_our_key:
+#endif /* USE_KEYRR */
+ which = "our";
+ networkof(&b->my.net, &client);
+ break;
+
+ case vos_his_client:
+ which = "his";
+ networkof(&b->his.net, &client);
+ break;
+
+ case vos_start:
+ case vos_done:
+ case vos_fail:
+ default:
+ bad_case(b->step);
+ }
+
+ addrtot(&st->st_connection->spd.that.host_addr, 0, fgwb, sizeof(fgwb));
+ addrtot(&client, 0, cb, sizeof(cb));
+ loglog(RC_OPPOFAILURE
+ , "gateway %s wants connection with %s as %s client, but DNS fails to confirm delegation: %s"
+ , fgwb, cb, which, ugh);
+}
+
+static void
+quick_inI1_outR1_continue(struct adns_continuation *cr, err_t ugh)
+{
+ stf_status r;
+ struct verify_oppo_continuation *vc = (void *)cr;
+ struct verify_oppo_bundle *b = &vc->b;
+ struct state *st = b->md->st;
+
+ passert(cur_state == NULL);
+ /* if st == NULL, our state has been deleted -- just clean up */
+ if (st != NULL)
+ {
+ passert(st->st_suspended_md == b->md);
+ st->st_suspended_md = NULL; /* no longer connected or suspended */
+ cur_state = st;
+ if (!b->failure_ok && ugh != NULL)
+ {
+ report_verify_failure(b, ugh);
+ r = STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ else
+ {
+ r = quick_inI1_outR1_tail(b, cr);
+ }
+ complete_state_transition(&b->md, r);
+ }
+ if (b->md != NULL)
+ release_md(b->md);
+ cur_state = NULL;
+}
+
+static stf_status
+quick_inI1_outR1_start_query(struct verify_oppo_bundle *b
+, enum verify_oppo_step next_step)
+{
+ struct msg_digest *md = b->md;
+ struct state *p1st = md->st;
+ struct connection *c = p1st->st_connection;
+ struct verify_oppo_continuation *vc
+ = alloc_thing(struct verify_oppo_continuation, "verify continuation");
+ struct id id /* subject of query */
+ , *our_id /* needed for myid playing */
+ , our_id_space; /* ephemeral: no need for unshare_id_content */
+ ip_address client;
+ err_t ugh;
+
+ /* Record that state is used by a suspended md */
+ b->step = next_step; /* not just vc->b.step */
+ vc->b = *b;
+ passert(p1st->st_suspended_md == NULL);
+ p1st->st_suspended_md = b->md;
+
+ DBG(DBG_CONTROL,
+ {
+ char ours[SUBNETTOT_BUF];
+ char his[SUBNETTOT_BUF];
+
+ subnettot(&c->spd.this.client, 0, ours, sizeof(ours));
+ subnettot(&c->spd.that.client, 0, his, sizeof(his));
+
+ DBG_log("responding with DNS query - from %s to %s new state: %s"
+ , ours, his, verify_step_name[b->step]);
+ });
+
+ /* Resolve %myid in a cheesy way.
+ * We have to do the resolution because start_adns_query
+ * et al have insufficient information to do so.
+ * If %myid is already known, we'll use that value
+ * (XXX this may be a mistake: it could be stale).
+ * If %myid is unknown, we should check to see if
+ * there are credentials for the IP address or the FQDN.
+ * Instead, we'll just assume the IP address since we are
+ * acting as the responder and only the IP address would
+ * have gotten it to us.
+ * We don't even try to do this for the other side:
+ * %myid makes no sense for the other side (but it is syntactically
+ * legal).
+ */
+ our_id = resolve_myid(&c->spd.this.id);
+ if (our_id->kind == ID_NONE)
+ {
+ iptoid(&c->spd.this.host_addr, &our_id_space);
+ our_id = &our_id_space;
+ }
+
+ switch (next_step)
+ {
+ case vos_our_client:
+ networkof(&b->my.net, &client);
+ iptoid(&client, &id);
+ vc->b.failure_ok = b->failure_ok = FALSE;
+ ugh = start_adns_query(&id
+ , our_id
+ , T_TXT
+ , quick_inI1_outR1_continue
+ , &vc->ac);
+ break;
+
+ case vos_our_txt:
+ vc->b.failure_ok = b->failure_ok = TRUE;
+ ugh = start_adns_query(our_id
+ , our_id /* self as SG */
+ , T_TXT
+ , quick_inI1_outR1_continue
+ , &vc->ac);
+ break;
+
+#ifdef USE_KEYRR
+ case vos_our_key:
+ vc->b.failure_ok = b->failure_ok = FALSE;
+ ugh = start_adns_query(our_id
+ , NULL
+ , T_KEY
+ , quick_inI1_outR1_continue
+ , &vc->ac);
+ break;
+#endif
+
+ case vos_his_client:
+ networkof(&b->his.net, &client);
+ iptoid(&client, &id);
+ vc->b.failure_ok = b->failure_ok = FALSE;
+ ugh = start_adns_query(&id
+ , &c->spd.that.id
+ , T_TXT
+ , quick_inI1_outR1_continue
+ , &vc->ac);
+ break;
+
+ default:
+ bad_case(next_step);
+ }
+
+ if (ugh != NULL)
+ {
+ /* note: we'd like to use vc->b but vc has been freed
+ * so we have to use b. This is why we plunked next_state
+ * into b, not just vc->b.
+ */
+ report_verify_failure(b, ugh);
+ p1st->st_suspended_md = NULL;
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ else
+ {
+ return STF_SUSPEND;
+ }
+}
+
+static enum verify_oppo_step
+quick_inI1_outR1_process_answer(struct verify_oppo_bundle *b
+, struct adns_continuation *ac
+, struct state *p1st)
+{
+ struct connection *c = p1st->st_connection;
+ enum verify_oppo_step next_step;
+ err_t ugh = NULL;
+
+ DBG(DBG_CONTROL,
+ {
+ char ours[SUBNETTOT_BUF];
+ char his[SUBNETTOT_BUF];
+
+ subnettot(&c->spd.this.client, 0, ours, sizeof(ours));
+ subnettot(&c->spd.that.client, 0, his, sizeof(his));
+ DBG_log("responding on demand from %s to %s state: %s"
+ , ours, his, verify_step_name[b->step]);
+ });
+
+ /* process just completed DNS query (if any) */
+ switch (b->step)
+ {
+ case vos_start:
+ /* no query to digest */
+ next_step = vos_our_client;
+ break;
+
+ case vos_our_client:
+ next_step = vos_his_client;
+ {
+ const struct RSA_private_key *pri = get_RSA_private_key(c);
+ struct gw_info *gwp;
+
+ if (pri == NULL)
+ {
+ ugh = "we don't know our own key";
+ break;
+ }
+ ugh = "our client does not delegate us as its Security Gateway";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ ugh = "our client delegates us as its Security Gateway but with the wrong public key";
+ /* If there is no key in the TXT record,
+ * we count it as a win, but we will have
+ * to separately fetch and check the KEY record.
+ * If there is a key from the TXT record,
+ * we count it as a win if we match the key.
+ */
+ if (!gwp->gw_key_present)
+ {
+ next_step = vos_our_txt;
+ ugh = NULL; /* good! */
+ break;
+ }
+ else if (same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ break;
+
+ case vos_our_txt:
+ next_step = vos_his_client;
+ {
+ const struct RSA_private_key *pri = get_RSA_private_key(c);
+
+ if (pri == NULL)
+ {
+ ugh = "we don't know our own key";
+ break;
+ }
+ {
+ struct gw_info *gwp;
+
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+#ifdef USE_KEYRR
+ /* not an error yet, because we have to check KEY RR as well */
+ ugh = NULL;
+#else
+ ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
+#endif
+ if (gwp->gw_key_present
+ && same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+#ifdef USE_KEYRR
+ next_step = vos_our_key;
+#endif
+ }
+ }
+ }
+ break;
+
+#ifdef USE_KEYRR
+ case vos_our_key:
+ next_step = vos_his_client;
+ {
+ const struct RSA_private_key *pri = get_RSA_private_key(c);
+
+ if (pri == NULL)
+ {
+ ugh = "we don't know our own key";
+ break;
+ }
+ {
+ pubkey_list_t *kp;
+
+ ugh = "our client delegation depends on our missing " RRNAME " record";
+ for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next)
+ {
+ ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
+ if (same_RSA_public_key(&pri->pub, &kp->key->u.rsa))
+ {
+ /* do this only once a day */
+ if (!logged_txt_warning)
+ {
+ loglog(RC_LOG_SERIOUS, "found KEY RR but not TXT RR. See http://www.freeswan.org/err/txt-change.html.");
+ logged_txt_warning = TRUE;
+ }
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ }
+ break;
+#endif /* USE_KEYRR */
+
+ case vos_his_client:
+ next_step = vos_done;
+ {
+ struct gw_info *gwp;
+
+ /* check that the public key that authenticated
+ * the ISAKMP SA (p1st) will do for this gateway.
+ */
+
+ ugh = "peer's client does not delegate to peer";
+ for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ ugh = "peer and its client disagree about public key";
+ /* If there is a key from the TXT record,
+ * we count it as a win if we match the key.
+ * If there was no key, we claim a match since
+ * it implies fetching a KEY from the same
+ * place we must have gotten it.
+ */
+ if (!gwp->gw_key_present
+ || same_RSA_public_key(&p1st->st_peer_pubkey->u.rsa
+ , &gwp->key->u.rsa))
+ {
+ ugh = NULL; /* good! */
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ bad_case(b->step);
+ }
+
+ if (ugh != NULL)
+ {
+ report_verify_failure(b, ugh);
+ next_step = vos_fail;
+ }
+ return next_step;
+}
+
+static stf_status
+quick_inI1_outR1_tail(struct verify_oppo_bundle *b
+, struct adns_continuation *ac)
+{
+ struct msg_digest *md = b->md;
+ struct state *const p1st = md->st;
+ struct connection *c = p1st->st_connection;
+ struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
+ ip_subnet *our_net = &b->my.net
+ , *his_net = &b->his.net;
+
+ u_char /* set by START_HASH_PAYLOAD: */
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* from where to start hashing */
+
+ /* Now that we have identities of client subnets, we must look for
+ * a suitable connection (our current one only matches for hosts).
+ */
+ {
+ struct connection *p = find_client_connection(c
+ , our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port);
+
+ if (p == NULL)
+ {
+ /* This message occurs in very puzzling circumstances
+ * so we must add as much information and beauty as we can.
+ */
+ struct end
+ me = c->spd.this,
+ he = c->spd.that;
+ char buf[2*SUBNETTOT_BUF + 2*ADDRTOT_BUF + 2*BUF_LEN + 2*ADDRTOT_BUF + 12]; /* + 12 for separating */
+ size_t l;
+
+ me.client = *our_net;
+ me.has_client = !subnetisaddr(our_net, &me.host_addr);
+ me.protocol = b->my.proto;
+ me.port = b->my.port;
+
+ he.client = *his_net;
+ he.has_client = !subnetisaddr(his_net, &he.host_addr);
+ he.protocol = b->his.proto;
+ he.port = b->his.port;
+
+ l = format_end(buf, sizeof(buf), &me, NULL, TRUE, LEMPTY);
+ l += snprintf(buf + l, sizeof(buf) - l, "...");
+ (void)format_end(buf + l, sizeof(buf) - l, &he, NULL, FALSE, LEMPTY);
+ plog("cannot respond to IPsec SA request"
+ " because no connection is known for %s"
+ , buf);
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ else if (p != c)
+ {
+ /* We've got a better connection: it can support the
+ * specified clients. But it may need instantiation.
+ */
+ if (p->kind == CK_TEMPLATE)
+ {
+ /* Yup, it needs instantiation. How much?
+ * Is it a Road Warrior connection (simple)
+ * or is it an Opportunistic connection (needing gw validation)?
+ */
+ if (p->policy & POLICY_OPPO)
+ {
+ /* Opportunistic case: delegation must be verified.
+ * Here be dragons.
+ */
+ enum verify_oppo_step next_step;
+ ip_address our_client, his_client;
+
+ passert(subnetishost(our_net) && subnetishost(his_net));
+ networkof(our_net, &our_client);
+ networkof(his_net, &his_client);
+
+ next_step = quick_inI1_outR1_process_answer(b, ac, p1st);
+ if (next_step == vos_fail)
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ /* short circuit: if peer's client is self,
+ * accept that we've verified delegation in Phase 1
+ */
+ if (next_step == vos_his_client
+ && sameaddr(&c->spd.that.host_addr, &his_client))
+ next_step = vos_done;
+
+ /* the second chunk: initiate the next DNS query (if any) */
+ DBG(DBG_CONTROL,
+ {
+ char ours[SUBNETTOT_BUF];
+ char his[SUBNETTOT_BUF];
+
+ subnettot(&c->spd.this.client, 0, ours, sizeof(ours));
+ subnettot(&c->spd.that.client, 0, his, sizeof(his));
+
+ DBG_log("responding on demand from %s to %s new state: %s"
+ , ours, his, verify_step_name[next_step]);
+ });
+
+ /* start next DNS query and suspend (if necessary) */
+ if (next_step != vos_done)
+ return quick_inI1_outR1_start_query(b, next_step);
+
+ /* Instantiate inbound Opportunistic connection,
+ * carrying over authenticated peer ID
+ * and filling in a few more details.
+ * We used to include gateways_from_dns, but that
+ * seems pointless at this stage of negotiation.
+ * We should record DNS sec use, if any -- belongs in
+ * state during perhaps.
+ */
+ p = oppo_instantiate(p, &c->spd.that.host_addr, &c->spd.that.id
+ , NULL, &our_client, &his_client);
+ }
+ else
+ {
+ /* Plain Road Warrior:
+ * instantiate, carrying over authenticated peer ID
+ */
+ p = rw_instantiate(p, &c->spd.that.host_addr,
+#ifdef NAT_TRAVERSAL
+ md->sender_port,
+#endif
+#ifdef VIRTUAL_IP
+ his_net,
+#endif
+ &c->spd.that.id);
+ }
+ }
+#ifdef DEBUG
+ /* temporarily bump up cur_debugging to get "using..." message
+ * printed if we'd want it with new connection.
+ */
+ {
+ lset_t old_cur_debugging = cur_debugging;
+
+ cur_debugging |= p->extra_debugging;
+ DBG(DBG_CONTROL, DBG_log("using connection \"%s\"", p->name));
+ cur_debugging = old_cur_debugging;
+ }
+#endif
+ c = p;
+ }
+ /* fill in the client's true ip address/subnet */
+ if (p->spd.that.has_client_wildcard)
+ {
+ p->spd.that.client = *his_net;
+ p->spd.that.has_client_wildcard = FALSE;
+ }
+
+#ifdef VIRTUAL_IP
+ else if (is_virtual_connection(c))
+ {
+ c->spd.that.client = *his_net;
+ c->spd.that.virt = NULL;
+ if (subnetishost(his_net) && addrinsubnet(&c->spd.that.host_addr, his_net))
+ c->spd.that.has_client = FALSE;
+ }
+#endif
+
+ /* fill in the client's true port */
+ if (p->spd.that.has_port_wildcard)
+ {
+ int port = htons(b->his.port);
+
+ setportof(port, &p->spd.that.host_addr);
+ setportof(port, &p->spd.that.client.addr);
+
+ p->spd.that.port = b->his.port;
+ p->spd.that.has_port_wildcard = FALSE;
+ }
+ }
+
+ /* now that we are sure of our connection, create our new state */
+ {
+ struct state *const st = duplicate_state(p1st);
+
+ /* first: fill in missing bits of our new state object
+ * note: we don't copy over st_peer_pubkey, the public key
+ * that authenticated the ISAKMP SA. We only need it in this
+ * routine, so we can "reach back" to p1st to get it.
+ */
+
+ if (st->st_connection != c)
+ {
+ struct connection *t = st->st_connection;
+
+ st->st_connection = c;
+ set_cur_connection(c);
+ connection_discard(t);
+ }
+
+ st->st_try = 0; /* not our job to try again from start */
+
+ st->st_msgid = md->hdr.isa_msgid;
+
+ st->st_new_iv_len = b->new_iv_len;
+ memcpy(st->st_new_iv, b->new_iv, b->new_iv_len);
+
+ set_cur_state(st); /* (caller will reset) */
+ md->st = st; /* feed back new state */
+
+ st->st_peeruserprotoid = b->his.proto;
+ st->st_peeruserport = b->his.port;
+ st->st_myuserprotoid = b->my.proto;
+ st->st_myuserport = b->my.port;
+
+ insert_state(st); /* needs cookies, connection, and msgid */
+
+ /* copy the connection's
+ * IPSEC policy into our state. The ISAKMP policy is water under
+ * the bridge, I think. It will reflect the ISAKMP SA that we
+ * are using.
+ */
+ st->st_policy = (p1st->st_policy & POLICY_ISAKMP_MASK)
+ | (c->policy & ~POLICY_ISAKMP_MASK);
+
+#ifdef NAT_TRAVERSAL
+ if (p1st->nat_traversal & NAT_T_DETECTED)
+ {
+ st->nat_traversal = p1st->nat_traversal;
+ nat_traversal_change_port_lookup(md, md->st);
+ }
+ else
+ {
+ st->nat_traversal = 0;
+ }
+ if ((st->nat_traversal & NAT_T_DETECTED) &&
+ (st->nat_traversal & NAT_T_WITH_NATOA))
+ {
+ nat_traversal_natoa_lookup(md);
+ }
+#endif
+
+ /* Start the output packet.
+ *
+ * proccess_packet() would automatically generate the HDR*
+ * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE.
+ * We don't do this because we wish there to be no partially
+ * built output packet if we need to suspend for asynch DNS.
+ *
+ * We build the reply packet as we parse the message since
+ * the parse_ipsec_sa_body emits the reply SA
+ */
+
+ /* HDR* out */
+ echo_hdr(md, TRUE, ISAKMP_NEXT_HASH);
+
+ /* HASH(2) out -- first pass */
+ START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA);
+
+ /* process SA (in and out) */
+ {
+ struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
+ pb_stream r_sa_pbs;
+ struct isakmp_sa sa = sapd->payload.sa;
+
+ /* sa header is unchanged -- except for np */
+ sa.isasa_np = ISAKMP_NEXT_NONCE;
+ if (!out_struct(&sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs))
+ return STF_INTERNAL_ERROR;
+
+ /* parse and accept body */
+ st->st_pfs_group = &unset_group;
+ RETURN_STF_FAILURE(parse_ipsec_sa_body(&sapd->pbs
+ , &sapd->payload.sa, &r_sa_pbs, FALSE, st));
+ }
+
+ passert(st->st_pfs_group != &unset_group);
+
+ if ((st->st_policy & POLICY_PFS) && st->st_pfs_group == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "we require PFS but Quick I1 SA specifies no GROUP_DESCRIPTION");
+ return STF_FAIL + NO_PROPOSAL_CHOSEN; /* ??? */
+ }
+
+ /* Ni in */
+ RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni"));
+
+ /* [ KE ] in (for PFS) */
+ RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi, "Gi", "Quick Mode I1"));
+
+ plog("responding to Quick Mode");
+
+ /**** finish reply packet: Nr [, KE ] [, IDci, IDcr ] ****/
+
+ /* Nr out */
+ if (!build_and_ship_nonce(&st->st_nr, &md->rbody
+ , st->st_pfs_group != NULL? ISAKMP_NEXT_KE : id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE
+ , "Nr"))
+ return STF_INTERNAL_ERROR;
+
+ /* [ KE ] out (for PFS) */
+
+ if (st->st_pfs_group != NULL)
+ {
+ if (!build_and_ship_KE(st, &st->st_gr, st->st_pfs_group
+ , &md->rbody, id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE))
+ return STF_INTERNAL_ERROR;
+
+ /* MPZ-Operations might be done after sending the packet... */
+ compute_dh_shared(st, st->st_gi, st->st_pfs_group);
+ }
+
+ /* [ IDci, IDcr ] out */
+ if (id_pd != NULL)
+ {
+ struct isakmp_ipsec_id *p = (void *)md->rbody.cur; /* UGH! */
+
+ if (!out_raw(id_pd->pbs.start, pbs_room(&id_pd->pbs), &md->rbody, "IDci"))
+ return STF_INTERNAL_ERROR;
+ p->isaiid_np = ISAKMP_NEXT_ID;
+
+ p = (void *)md->rbody.cur; /* UGH! */
+
+ if (!out_raw(id_pd->next->pbs.start, pbs_room(&id_pd->next->pbs), &md->rbody, "IDcr"))
+ return STF_INTERNAL_ERROR;
+ p->isaiid_np = ISAKMP_NEXT_NONE;
+ }
+
+#ifdef NAT_TRAVERSAL
+ if ((st->nat_traversal & NAT_T_WITH_NATOA)
+ && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))
+ && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT))
+ {
+ /** Send NAT-OA if our address is NATed and if we use Transport Mode */
+ if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &md->rbody, md->st))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+ if ((st->nat_traversal & NAT_T_DETECTED)
+ && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT)
+ && (c->spd.that.has_client))
+ {
+ /** Remove client **/
+ addrtosubnet(&c->spd.that.host_addr, &c->spd.that.client);
+ c->spd.that.has_client = FALSE;
+ }
+#endif
+
+ /* Compute reply HASH(2) and insert in output */
+ (void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur
+ , st, &st->st_msgid, TRUE);
+
+ /* Derive new keying material */
+ compute_keymats(st);
+
+ /* Tell the kernel to establish the new inbound SA
+ * (unless the commit bit is set -- which we don't support).
+ * We do this before any state updating so that
+ * failure won't look like success.
+ */
+ if (!install_inbound_ipsec_sa(st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ /* encrypt message, except for fixed part of header */
+
+ if (!encrypt_message(&md->rbody, st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ return STF_OK;
+ }
+}
+
+/*
+ * Initialize RFC 3706 Dead Peer Detection
+ */
+static void
+dpd_init(struct state *st)
+{
+ struct state *p1st = find_state(st->st_icookie, st->st_rcookie
+ , &st->st_connection->spd.that.host_addr, 0);
+
+ if (p1st == NULL)
+ loglog(RC_LOG_SERIOUS, "could not find phase 1 state for DPD");
+ else if (p1st->st_dpd)
+ {
+ plog("Dead Peer Detection (RFC 3706) enabled");
+ /* randomize the first DPD event */
+
+ event_schedule(EVENT_DPD
+ , (0.5 + rand()/(RAND_MAX + 1.E0)) * st->st_connection->dpd_delay
+ , st);
+ }
+}
+
+/* Handle (the single) message from Responder in Quick Mode.
+ * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] -->
+ * HDR*, HASH(3)
+ * (see RFC 2409 "IKE" 5.5)
+ * Installs inbound and outbound IPsec SAs, routing, etc.
+ */
+stf_status
+quick_inR1_outI2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ const struct connection *c = st->st_connection;
+
+ /* HASH(2) in */
+ CHECK_QUICK_HASH(md
+ , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof
+ , st, &st->st_msgid, TRUE)
+ , "HASH(2)", "Quick R1");
+
+ /* SA in */
+ {
+ struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
+
+ RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs
+ , &sa_pd->payload.sa, NULL, TRUE, st));
+ }
+
+ /* Nr in */
+ RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr"));
+
+ /* [ KE ] in (for PFS) */
+ RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1"));
+
+ if (st->st_pfs_group != NULL)
+ compute_dh_shared(st, st->st_gr, st->st_pfs_group);
+
+ /* [ IDci, IDcr ] in; these must match what we sent */
+
+ {
+ struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID];
+
+ if (id_pd != NULL)
+ {
+ /* ??? we are assuming IPSEC_DOI */
+
+ /* IDci (we are initiator) */
+
+ if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs
+ , &st->st_myuserprotoid, &st->st_myuserport
+ , &st->st_connection->spd.this.client
+ , "our client"))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+
+ /* IDcr (responder is peer) */
+
+ if (!check_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs
+ , &st->st_peeruserprotoid, &st->st_peeruserport
+ , &st->st_connection->spd.that.client
+ , "peer client"))
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ else
+ {
+ /* no IDci, IDcr: we must check that the defaults match our proposal */
+ if (!subnetisaddr(&c->spd.this.client, &c->spd.this.host_addr)
+ || !subnetisaddr(&c->spd.that.client, &c->spd.that.host_addr))
+ {
+ loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message"
+ " but default does not match proposal");
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ }
+ }
+
+ /* check the peer's group attributes */
+
+ {
+ const ietfAttrList_t *peer_list = NULL;
+
+ get_peer_ca_and_groups(st->st_connection, &peer_list);
+
+ if (!group_membership(peer_list, st->st_connection->name
+ , st->st_connection->spd.that.groups))
+ {
+ char buf[BUF_LEN];
+
+ format_groups(st->st_connection->spd.that.groups, buf, BUF_LEN);
+ loglog(RC_LOG_SERIOUS, "peer is not member of one of the groups: %s"
+ , buf);
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+ }
+
+#ifdef NAT_TRAVERSAL
+ if ((st->nat_traversal & NAT_T_DETECTED)
+ && (st->nat_traversal & NAT_T_WITH_NATOA))
+ {
+ nat_traversal_natoa_lookup(md);
+ }
+#endif
+
+ /* ??? We used to copy the accepted proposal into the state, but it was
+ * never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs).
+ */
+
+ /**************** build reply packet HDR*, HASH(3) ****************/
+
+ /* HDR* out done */
+
+ /* HASH(3) out -- since this is the only content, no passes needed */
+ {
+ u_char /* set by START_HASH_PAYLOAD: */
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* start of what is to be hashed */
+
+ START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE);
+ (void)quick_mode_hash3(r_hashval, st);
+ }
+
+ /* Derive new keying material */
+ compute_keymats(st);
+
+ /* Tell the kernel to establish the inbound, outbound, and routing part
+ * of the new SA (unless the commit bit is set -- which we don't support).
+ * We do this before any state updating so that
+ * failure won't look like success.
+ */
+ if (!install_ipsec_sa(st, TRUE))
+ return STF_INTERNAL_ERROR;
+
+ /* encrypt message, except for fixed part of header */
+
+ if (!encrypt_message(&md->rbody, st))
+ return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
+
+ {
+ DBG(DBG_CONTROLMORE, DBG_log("inR1_outI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)"
+ , st->st_connection->name
+ , st->st_connection->instance_serial
+ , st->st_serialno
+ , st->st_connection->newest_ipsec_sa
+ , st->st_connection->spd.eroute_owner));
+ }
+
+ st->st_connection->newest_ipsec_sa = st->st_serialno;
+
+ /* note (presumed) success */
+ if (c->gw_info != NULL)
+ c->gw_info->key->last_worked_time = now();
+
+ /* If we want DPD on this connection then initialize it */
+ if (st->st_connection->dpd_action != DPD_ACTION_NONE)
+ dpd_init(st);
+
+ return STF_OK;
+}
+
+/* Handle last message of Quick Mode.
+ * HDR*, HASH(3) -> done
+ * (see RFC 2409 "IKE" 5.5)
+ * Installs outbound IPsec SAs, routing, etc.
+ */
+stf_status
+quick_inI2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+
+ /* HASH(3) in */
+ CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st)
+ , "HASH(3)", "Quick I2");
+
+ /* Tell the kernel to establish the outbound and routing part of the new SA
+ * (the previous state established inbound)
+ * (unless the commit bit is set -- which we don't support).
+ * We do this before any state updating so that
+ * failure won't look like success.
+ */
+ if (!install_ipsec_sa(st, FALSE))
+ return STF_INTERNAL_ERROR;
+
+ {
+ DBG(DBG_CONTROLMORE, DBG_log("inI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)"
+ , st->st_connection->name
+ , st->st_connection->instance_serial
+ , st->st_serialno
+ , st->st_connection->newest_ipsec_sa
+ , st->st_connection->spd.eroute_owner));
+ }
+
+ st->st_connection->newest_ipsec_sa = st->st_serialno;
+
+ update_iv(st); /* not actually used, but tidy */
+
+ /* note (presumed) success */
+ {
+ struct gw_info *gw = st->st_connection->gw_info;
+
+ if (gw != NULL)
+ gw->key->last_worked_time = now();
+ }
+
+ /* If we want DPD on this connection then initialize it */
+ if (st->st_connection->dpd_action != DPD_ACTION_NONE)
+ dpd_init(st);
+
+ return STF_OK;
+}
+
+static stf_status
+send_isakmp_notification(struct state *st, u_int16_t type
+ , const void *data, size_t len)
+{
+ msgid_t msgid;
+ pb_stream reply;
+ pb_stream rbody;
+ u_char
+ *r_hashval, /* where in reply to jam hash value */
+ *r_hash_start; /* start of what is to be hashed */
+
+ msgid = generate_msgid(st);
+
+ init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "ISAKMP notify");
+
+ /* HDR* */
+ {
+ struct isakmp_hdr hdr;
+
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_HASH;
+ hdr.isa_xchg = ISAKMP_XCHG_INFO;
+ hdr.isa_msgid = msgid;
+ hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
+ memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
+ impossible();
+ }
+ /* HASH -- create and note space to be filled later */
+ START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_N);
+
+ /* NOTIFY */
+ {
+ pb_stream notify_pbs;
+ struct isakmp_notification isan;
+
+ isan.isan_np = ISAKMP_NEXT_NONE;
+ isan.isan_doi = ISAKMP_DOI_IPSEC;
+ isan.isan_protoid = PROTO_ISAKMP;
+ isan.isan_spisize = COOKIE_SIZE * 2;
+ isan.isan_type = type;
+ if (!out_struct(&isan, &isakmp_notification_desc, &rbody, &notify_pbs))
+ return STF_INTERNAL_ERROR;
+ if (!out_raw(st->st_icookie, COOKIE_SIZE, &notify_pbs, "notify icookie"))
+ return STF_INTERNAL_ERROR;
+ if (!out_raw(st->st_rcookie, COOKIE_SIZE, &notify_pbs, "notify rcookie"))
+ return STF_INTERNAL_ERROR;
+ if (data != NULL && len > 0)
+ if (!out_raw(data, len, &notify_pbs, "notify data"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&notify_pbs);
+ }
+
+ {
+ /* finish computing HASH */
+ struct hmac_ctx ctx;
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
+ hmac_update(&ctx, (const u_char *) &msgid, sizeof(msgid_t));
+ hmac_update(&ctx, r_hash_start, rbody.cur-r_hash_start);
+ hmac_final(r_hashval, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("HASH computed:");
+ DBG_dump("", r_hashval, ctx.hmac_digest_size));
+ }
+
+ /* Encrypt message (preserve st_iv and st_new_iv) */
+ {
+ u_char old_iv[MAX_DIGEST_LEN];
+ u_char new_iv[MAX_DIGEST_LEN];
+
+ u_int old_iv_len = st->st_iv_len;
+ u_int new_iv_len = st->st_new_iv_len;
+
+ if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN)
+ return STF_INTERNAL_ERROR;
+
+ memcpy(old_iv, st->st_iv, old_iv_len);
+ memcpy(new_iv, st->st_new_iv, new_iv_len);
+
+ init_phase2_iv(st, &msgid);
+ if (!encrypt_message(&rbody, st))
+ return STF_INTERNAL_ERROR;
+
+ /* restore preserved st_iv and st_new_iv */
+ memcpy(st->st_iv, old_iv, old_iv_len);
+ memcpy(st->st_new_iv, new_iv, new_iv_len);
+ st->st_iv_len = old_iv_len;
+ st->st_new_iv_len = new_iv_len;
+ }
+
+ /* Send packet (preserve st_tpacket) */
+ {
+ chunk_t saved_tpacket = st->st_tpacket;
+
+ setchunk(st->st_tpacket, reply.start, pbs_offset(&reply));
+ send_packet(st, "ISAKMP notify");
+ st->st_tpacket = saved_tpacket;
+ }
+
+ return STF_IGNORE;
+}
+
+/*
+ * DPD Out Initiator
+ */
+void
+dpd_outI(struct state *p2st)
+{
+ struct state *st;
+ u_int32_t seqno;
+ time_t tm;
+ time_t idle_time;
+ time_t delay = p2st->st_connection->dpd_delay;
+ time_t timeout = p2st->st_connection->dpd_timeout;
+
+ /* find the newest related Phase 1 state */
+ st = find_phase1_state(p2st->st_connection, ISAKMP_SA_ESTABLISHED_STATES);
+
+ if (st == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: Could not find newest phase 1 state");
+ return;
+ }
+
+ /* If no DPD, then get out of here */
+ if (!st->st_dpd)
+ return;
+
+ /* schedule the next periodic DPD event */
+ event_schedule(EVENT_DPD, delay, p2st);
+
+ /* Current time */
+ tm = now();
+
+ /* Make sure we really need to invoke DPD */
+ if (!was_eroute_idle(p2st, delay, &idle_time))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("recent eroute activity %u seconds ago, "
+ "no need to send DPD notification"
+ , (int)idle_time)
+ )
+ st->st_last_dpd = tm;
+ delete_dpd_event(st);
+ return;
+ }
+
+ /* If an R_U_THERE has been sent or received recently, or if a
+ * companion Phase 2 SA has shown eroute activity,
+ * then we don't need to invoke DPD.
+ */
+ if (tm < st->st_last_dpd + delay)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("recent DPD activity %u seconds ago, "
+ "no need to send DPD notification"
+ , (int)(tm - st->st_last_dpd))
+ )
+ return;
+ }
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ return;
+
+ if (!st->st_dpd_seqno)
+ {
+ /* Get a non-zero random value that has room to grow */
+ get_rnd_bytes((u_char *)&st->st_dpd_seqno, sizeof(st->st_dpd_seqno));
+ st->st_dpd_seqno &= 0x7fff;
+ st->st_dpd_seqno++;
+ }
+ seqno = htonl(st->st_dpd_seqno);
+
+ if (send_isakmp_notification(st, R_U_THERE, &seqno, sizeof(seqno)) != STF_IGNORE)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: Could not send R_U_THERE");
+ return;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("sent DPD notification R_U_THERE with seqno = %u", st->st_dpd_seqno)
+ )
+ st->st_dpd_expectseqno = st->st_dpd_seqno++;
+ st->st_last_dpd = tm;
+ /* Only schedule a new timeout if there isn't one currently,
+ * or if it would be sooner than the current timeout. */
+ if (st->st_dpd_event == NULL
+ || st->st_dpd_event->ev_time > tm + timeout)
+ {
+ delete_dpd_event(st);
+ event_schedule(EVENT_DPD_TIMEOUT, timeout, st);
+ }
+}
+
+/*
+ * DPD in Initiator, out Responder
+ */
+stf_status
+dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *pbs)
+{
+ time_t tm = now();
+ u_int32_t seqno;
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: Received R_U_THERE for unestablished ISKAMP SA");
+ return STF_IGNORE;
+ }
+ if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid SPI length (%d)", n->isan_spisize);
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0)
+ {
+#ifdef APPLY_CRISCO
+ /* Ignore it, cisco sends odd icookies */
+#else
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid icookie (broken Cisco?)");
+ return STF_FAIL + INVALID_COOKIE;
+#endif
+ }
+ pbs->cur += COOKIE_SIZE;
+
+ if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid rcookie (broken Cisco?)");
+ return STF_FAIL + INVALID_COOKIE;
+ }
+ pbs->cur += COOKIE_SIZE;
+
+ if (pbs_left(pbs) != sizeof(seqno))
+ {
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid data length (%d)"
+ , (int) pbs_left(pbs));
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ seqno = ntohl(*(u_int32_t *)pbs->cur);
+ DBG(DBG_CONTROL,
+ DBG_log("received DPD notification R_U_THERE with seqno = %u", seqno)
+ )
+
+ if (st->st_dpd_peerseqno && seqno <= st->st_dpd_peerseqno) {
+ loglog(RC_LOG_SERIOUS, "DPD: Received old or duplicate R_U_THERE");
+ return STF_IGNORE;
+ }
+
+ st->st_dpd_peerseqno = seqno;
+ delete_dpd_event(st);
+
+ if (send_isakmp_notification(st, R_U_THERE_ACK, pbs->cur, pbs_left(pbs)) != STF_IGNORE)
+ {
+ loglog(RC_LOG_SERIOUS, "DPD Info: could not send R_U_THERE_ACK");
+ return STF_IGNORE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("sent DPD notification R_U_THERE_ACK with seqno = %u", seqno)
+ )
+
+ st->st_last_dpd = tm;
+ return STF_IGNORE;
+}
+
+/*
+ * DPD out Responder
+ */
+stf_status
+dpd_inR(struct state *st, struct isakmp_notification *const n, pb_stream *pbs)
+{
+ u_int32_t seqno;
+
+ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "DPD: Received R_U_THERE_ACK for unestablished ISKAMP SA");
+ return STF_FAIL;
+ }
+
+ if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "DPD: R_U_THERE_ACK has invalid SPI length (%d)"
+ , n->isan_spisize);
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0)
+ {
+#ifdef APPLY_CRISCO
+ /* Ignore it, cisco sends odd icookies */
+#else
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid icookie");
+ return STF_FAIL + INVALID_COOKIE;
+#endif
+ }
+ pbs->cur += COOKIE_SIZE;
+
+ if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0)
+ {
+#ifdef APPLY_CRISCO
+ /* Ignore it, cisco sends odd icookies */
+#else
+ loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid rcookie");
+ return STF_FAIL + INVALID_COOKIE;
+#endif
+ }
+ pbs->cur += COOKIE_SIZE;
+
+ if (pbs_left(pbs) != sizeof(seqno))
+ {
+ loglog(RC_LOG_SERIOUS
+ , " DPD: R_U_THERE_ACK has invalid data length (%d)"
+ , (int) pbs_left(pbs));
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ seqno = ntohl(*(u_int32_t *)pbs->cur);
+ DBG(DBG_CONTROL,
+ DBG_log("received DPD notification R_U_THERE_ACK with seqno = %u"
+ , seqno)
+ )
+
+ if (!st->st_dpd_expectseqno && seqno != st->st_dpd_expectseqno)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "DPD: R_U_THERE_ACK has unexpected sequence number");
+ return STF_FAIL + PAYLOAD_MALFORMED;
+ }
+
+ st->st_dpd_expectseqno = 0;
+ delete_dpd_event(st);
+ return STF_IGNORE;
+}
+
+/*
+ * DPD Timeout Function
+ *
+ * This function is called when a timeout DPD_EVENT occurs. We set clear/trap
+ * both the SA and the eroutes, depending on what the connection definition
+ * tells us (either 'hold' or 'clear')
+ */
+void
+dpd_timeout(struct state *st)
+{
+ struct state *newest_phase1_st;
+ struct connection *c = st->st_connection;
+ int action = st->st_connection->dpd_action;
+
+ passert(action == DPD_ACTION_HOLD
+ || action == DPD_ACTION_CLEAR
+ || DPD_ACTION_RESTART);
+
+ /* is there a newer phase1_state? */
+ newest_phase1_st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES);
+ if (newest_phase1_st != NULL && newest_phase1_st != st)
+ {
+ plog("DPD: Phase1 state #%ld has been superseded by #%ld"
+ " - timeout ignored"
+ , st->st_serialno, newest_phase1_st->st_serialno);
+ return;
+ }
+
+ loglog(RC_LOG_SERIOUS, "DPD: No response from peer - declaring peer dead");
+
+ /* delete the state, which is probably in phase 2 */
+ set_cur_connection(c);
+ plog("DPD: Terminating all SAs using this connection");
+ delete_states_by_connection(c, TRUE);
+ reset_cur_connection();
+
+ switch (action)
+ {
+ case DPD_ACTION_HOLD:
+ /* dpdaction=hold - Wipe the SA's but %trap the eroute so we don't
+ * leak traffic. Also, being in %trap means new packets will
+ * force an initiation of the conn again.
+ */
+ loglog(RC_LOG_SERIOUS, "DPD: Putting connection into %%trap");
+ break;
+ case DPD_ACTION_CLEAR:
+ /* dpdaction=clear - Wipe the SA & eroute - everything */
+ loglog(RC_LOG_SERIOUS, "DPD: Clearing connection");
+ unroute_connection(c);
+ break;
+ case DPD_ACTION_RESTART:
+ /* dpdaction=restart - Restart connection,
+ * except if roadwarrior connection
+ */
+ loglog(RC_LOG_SERIOUS, "DPD: Restarting connection");
+ unroute_connection(c);
+ initiate_connection(c->name, NULL_FD);
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "DPD: unknown action");
+ }
+}
+
diff --git a/programs/pluto/ipsec_doi.h b/programs/pluto/ipsec_doi.h
new file mode 100644
index 000000000..80b12c31d
--- /dev/null
+++ b/programs/pluto/ipsec_doi.h
@@ -0,0 +1,104 @@
+/* IPsec DOI and Oakley resolution routines
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ipsec_doi.h,v 1.3 2005/01/06 22:10:44 as Exp $
+ */
+
+extern void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np);
+
+extern void ipsecdoi_initiate(int whack_sock, struct connection *c
+ , lset_t policy, unsigned long try, so_serial_t replacing);
+
+extern void ipsecdoi_replace(struct state *st, unsigned long try);
+
+extern void init_phase2_iv(struct state *st, const msgid_t *msgid);
+
+extern stf_status quick_outI1(int whack_sock
+ , struct state *isakmp_sa
+ , struct connection *c
+ , lset_t policy
+ , unsigned long try
+ , so_serial_t replacing);
+
+extern state_transition_fn
+ main_inI1_outR1,
+ main_inR1_outI2,
+ main_inI2_outR2,
+ main_inR2_outI3,
+ main_inI3_outR3,
+ main_inR3,
+ quick_inI1_outR1,
+ quick_inR1_outI2,
+ quick_inI2;
+
+extern void send_delete(struct state *st);
+extern void accept_delete(struct state *st, struct msg_digest *md
+ , struct payload_digest *p);
+extern void close_message(pb_stream *pbs);
+extern bool encrypt_message(pb_stream *pbs, struct state *st);
+
+
+extern void send_notification_from_state(struct state *st,
+ enum state_kind state, u_int16_t type);
+extern void send_notification_from_md(struct msg_digest *md, u_int16_t type);
+
+extern const char *init_pluto_vendorid(void);
+
+extern void dpd_outI(struct state *st);
+extern stf_status dpd_inI_outR(struct state *st
+ , struct isakmp_notification *const n, pb_stream *n_pbs);
+extern stf_status dpd_inR(struct state *st
+ , struct isakmp_notification *const n, pb_stream *n_pbs);
+extern void dpd_timeout(struct state *st);
+
+/* START_HASH_PAYLOAD
+ *
+ * Emit a to-be-filled-in hash payload, noting the field start (r_hashval)
+ * and the start of the part of the message to be hashed (r_hash_start).
+ * This macro is magic.
+ * - it can cause the caller to return
+ * - it references variables local to the caller (r_hashval, r_hash_start, st)
+ */
+#define START_HASH_PAYLOAD(rbody, np) { \
+ pb_stream hash_pbs; \
+ if (!out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \
+ return STF_INTERNAL_ERROR; \
+ r_hashval = hash_pbs.cur; /* remember where to plant value */ \
+ if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) \
+ return STF_INTERNAL_ERROR; \
+ close_output_pbs(&hash_pbs); \
+ r_hash_start = (rbody).cur; /* hash from after HASH payload */ \
+}
+
+/* CHECK_QUICK_HASH
+ *
+ * This macro is magic -- it cannot be expressed as a function.
+ * - it causes the caller to return!
+ * - it declares local variables and expects the "do_hash" argument
+ * expression to reference them (hash_val, hash_pbs)
+ */
+#define CHECK_QUICK_HASH(md, do_hash, hash_name, msg_name) { \
+ pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; \
+ u_char hash_val[MAX_DIGEST_LEN]; \
+ size_t hash_len = do_hash; \
+ if (pbs_left(hash_pbs) != hash_len \
+ || memcmp(hash_pbs->cur, hash_val, hash_len) != 0) \
+ { \
+ DBG_cond_dump(DBG_CRYPT, "received " hash_name ":", hash_pbs->cur, pbs_left(hash_pbs)); \
+ loglog(RC_LOG_SERIOUS, "received " hash_name " does not match computed value in " msg_name); \
+ /* XXX Could send notification back */ \
+ return STF_FAIL + INVALID_HASH_INFORMATION; \
+ } \
+ }
+
+
diff --git a/programs/pluto/kameipsec.h b/programs/pluto/kameipsec.h
new file mode 100644
index 000000000..5f08c7d38
--- /dev/null
+++ b/programs/pluto/kameipsec.h
@@ -0,0 +1,47 @@
+#ifndef __IPSEC_H
+#define __IPSEC_H 1
+
+/* The definitions, required to talk to KAME racoon IKE. */
+
+#define IPSEC_PORT_ANY 0
+#define IPSEC_ULPROTO_ANY 255
+#define IPSEC_PROTO_ANY 255
+
+enum {
+ IPSEC_MODE_ANY = 0, /* We do not support this for SA */
+ IPSEC_MODE_TRANSPORT = 1,
+ IPSEC_MODE_TUNNEL = 2
+};
+
+enum {
+ IPSEC_DIR_ANY = 0,
+ IPSEC_DIR_INBOUND = 1,
+ IPSEC_DIR_OUTBOUND = 2,
+ IPSEC_DIR_FWD = 3, /* It is our own */
+ IPSEC_DIR_MAX = 4,
+ IPSEC_DIR_INVALID = 5
+};
+
+enum {
+ IPSEC_POLICY_DISCARD = 0,
+ IPSEC_POLICY_NONE = 1,
+ IPSEC_POLICY_IPSEC = 2,
+ IPSEC_POLICY_ENTRUST = 3,
+ IPSEC_POLICY_BYPASS = 4
+};
+
+enum {
+ IPSEC_LEVEL_DEFAULT = 0,
+ IPSEC_LEVEL_USE = 1,
+ IPSEC_LEVEL_REQUIRE = 2,
+ IPSEC_LEVEL_UNIQUE = 3
+};
+
+#define IPSEC_MANUAL_REQID_MAX 0x3fff
+
+#define IPSEC_REPLAYWSIZE 32
+
+#define IP_IPSEC_POLICY 16
+#define IPV6_IPSEC_POLICY 34
+
+#endif /* __IPSEC_H */
diff --git a/programs/pluto/kernel.c b/programs/pluto/kernel.c
new file mode 100644
index 000000000..5d7c5f78a
--- /dev/null
+++ b/programs/pluto/kernel.c
@@ -0,0 +1,2997 @@
+/* routines that interface with the kernel's IPsec mechanism
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: kernel.c,v 1.25 2006/04/17 14:58:09 as Exp $
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#ifdef KLIPS
+#include <signal.h>
+#include <sys/time.h> /* for select(2) */
+#include <sys/types.h> /* for select(2) */
+#include <pfkeyv2.h>
+#include <pfkey.h>
+#include "kameipsec.h"
+#endif /* KLIPS */
+
+#include "constants.h"
+#include "defs.h"
+#include "rnd.h"
+#include "id.h"
+#include "connections.h"
+#include "state.h"
+#include "timer.h"
+#include "kernel.h"
+#include "kernel_netlink.h"
+#include "kernel_pfkey.h"
+#include "kernel_noklips.h"
+#include "log.h"
+#include "ca.h"
+#include "server.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#include "keys.h"
+
+#ifdef NAT_TRAVERSAL
+#include "packet.h" /* for pb_stream in nat_traversal.h */
+#include "nat_traversal.h"
+#endif
+
+#include "alg_info.h"
+#include "kernel_alg.h"
+
+
+bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */
+
+/* How far can IPsec messages arrive out of order before the anti-replay
+ * logic loses track and swats them? 64 is the best KLIPS can do.
+ * And 32 is the best XFRM can do...
+ */
+#define REPLAY_WINDOW 64
+#define REPLAY_WINDOW_XFRM 32
+
+/* test if the routes required for two different connections agree
+ * It is assumed that the destination subnets agree; we are only
+ * testing that the interfaces and nexthops match.
+ */
+#define routes_agree(c, d) ((c)->interface == (d)->interface \
+ && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop))
+
+#ifndef KLIPS
+
+bool no_klips = TRUE; /* don't actually use KLIPS */
+
+#else /* !KLIPS */
+
+/* bare (connectionless) shunt (eroute) table
+ *
+ * Bare shunts are those that don't "belong" to a connection.
+ * This happens because some %trapped traffic hasn't yet or cannot be
+ * assigned to a connection. The usual reason is that we cannot discover
+ * the peer SG. Another is that even when the peer has been discovered,
+ * it may be that no connection matches all the particulars.
+ * We record them so that, with scanning, we can discover
+ * which %holds are news and which others should expire.
+ */
+
+#define SHUNT_SCAN_INTERVAL (60 * 2) /* time between scans of eroutes */
+
+/* SHUNT_PATIENCE only has resolution down to a multiple of the sample rate,
+ * SHUNT_SCAN_INTERVAL.
+ * By making SHUNT_PATIENCE an odd multiple of half of SHUNT_SCAN_INTERVAL,
+ * we minimize the effects of jitter.
+ */
+#define SHUNT_PATIENCE (SHUNT_SCAN_INTERVAL * 15 / 2) /* inactivity timeout */
+
+struct bare_shunt {
+ policy_prio_t policy_prio;
+ ip_subnet ours;
+ ip_subnet his;
+ ip_said said;
+ int transport_proto;
+ unsigned long count;
+ time_t last_activity;
+ char *why;
+ struct bare_shunt *next;
+};
+
+static struct bare_shunt *bare_shunts = NULL;
+
+#ifdef DEBUG
+static void
+DBG_bare_shunt(const char *op, const struct bare_shunt *bs)
+{
+ DBG(DBG_KLIPS,
+ {
+ int ourport = ntohs(portof(&(bs)->ours.addr));
+ int hisport = ntohs(portof(&(bs)->his.addr));
+ char ourst[SUBNETTOT_BUF];
+ char hist[SUBNETTOT_BUF];
+ char sat[SATOT_BUF];
+ char prio[POLICY_PRIO_BUF];
+
+ subnettot(&(bs)->ours, 0, ourst, sizeof(ourst));
+ subnettot(&(bs)->his, 0, hist, sizeof(hist));
+ satot(&(bs)->said, 0, sat, sizeof(sat));
+ fmt_policy_prio(bs->policy_prio, prio);
+ DBG_log("%s bare shunt %p %s:%d -> %s:%d => %s:%d %s %s"
+ , op, (const void *)(bs), ourst, ourport, hist, hisport
+ , sat, (bs)->transport_proto, prio, (bs)->why);
+ });
+}
+#else /* !DEBUG */
+#define DBG_bare_shunt(op, bs) {}
+#endif /* !DEBUG */
+
+/* The orphaned_holds table records %holds for which we
+ * scan_proc_shunts found no representation of in any connection.
+ * The corresponding ACQUIRE message might have been lost.
+ */
+struct eroute_info *orphaned_holds = NULL;
+
+/* forward declaration */
+static bool shunt_eroute(struct connection *c
+ , struct spd_route *sr
+ , enum routing_t rt_kind
+ , unsigned int op, const char *opname);
+static void set_text_said(char *text_said
+ , const ip_address *dst
+ , ipsec_spi_t spi
+ , int proto);
+
+bool no_klips = FALSE; /* don't actually use KLIPS */
+
+static const struct pfkey_proto_info null_proto_info[2] = {
+ {
+ proto: IPPROTO_ESP,
+ encapsulation: ENCAPSULATION_MODE_TRANSPORT,
+ reqid: 0
+ },
+ {
+ proto: 0,
+ encapsulation: 0,
+ reqid: 0
+ }
+};
+
+void
+record_and_initiate_opportunistic(const ip_subnet *ours
+ , const ip_subnet *his
+ , int transport_proto
+ , const char *why)
+{
+ passert(samesubnettype(ours, his));
+
+ /* Add to bare shunt list.
+ * We need to do this because the shunt was installed by KLIPS
+ * which can't do this itself.
+ */
+ {
+ struct bare_shunt *bs = alloc_thing(struct bare_shunt, "bare shunt");
+
+ bs->why = clone_str(why, "story for bare shunt");
+ bs->ours = *ours;
+ bs->his = *his;
+ bs->transport_proto = transport_proto;
+ bs->policy_prio = BOTTOM_PRIO;
+
+ bs->said.proto = SA_INT;
+ bs->said.spi = htonl(SPI_HOLD);
+ bs->said.dst = *aftoinfo(subnettypeof(ours))->any;
+
+ bs->count = 0;
+ bs->last_activity = now();
+
+ bs->next = bare_shunts;
+ bare_shunts = bs;
+ DBG_bare_shunt("add", bs);
+ }
+
+ /* actually initiate opportunism */
+ {
+ ip_address src, dst;
+
+ networkof(ours, &src);
+ networkof(his, &dst);
+ initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD);
+ }
+
+ /* if present, remove from orphaned_holds list.
+ * NOTE: we do this last in case ours or his is a pointer into a member.
+ */
+ {
+ struct eroute_info **pp, *p;
+
+ for (pp = &orphaned_holds; (p = *pp) != NULL; pp = &p->next)
+ {
+ if (samesubnet(ours, &p->ours)
+ && samesubnet(his, &p->his)
+ && transport_proto == p->transport_proto
+ && portof(&ours->addr) == portof(&p->ours.addr)
+ && portof(&his->addr) == portof(&p->his.addr))
+ {
+ *pp = p->next;
+ pfree(p);
+ break;
+ }
+ }
+ }
+}
+
+#endif /* KLIPS */
+
+static unsigned get_proto_reqid(unsigned base, int proto)
+{
+ switch (proto)
+ {
+ default:
+ case IPPROTO_COMP:
+ base++;
+ /* fall through */
+ case IPPROTO_ESP:
+ base++;
+ /* fall through */
+ case IPPROTO_AH:
+ break;
+ }
+
+ return base;
+}
+
+/* Generate Unique SPI numbers.
+ *
+ * The specs say that the number must not be less than IPSEC_DOI_SPI_MIN.
+ * Pluto generates numbers not less than IPSEC_DOI_SPI_OUR_MIN,
+ * reserving numbers in between for manual keying (but we cannot so
+ * restrict numbers generated by our peer).
+ * XXX This should be replaced by a call to the kernel when
+ * XXX we get an API.
+ * The returned SPI is in network byte order.
+ * We use a random number as the initial SPI so that there is
+ * a good chance that different Pluto instances will choose
+ * different SPIs. This is good for two reasons.
+ * - the keying material for the initiator and responder only
+ * differs if the SPIs differ.
+ * - if Pluto is restarted, it would otherwise recycle the SPI
+ * numbers and confuse everything. When the kernel generates
+ * SPIs, this will no longer matter.
+ * We then allocate numbers sequentially. Thus we don't have to
+ * check if the number was previously used (assuming that no
+ * SPI lives longer than 4G of its successors).
+ */
+ipsec_spi_t
+get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, bool tunnel)
+{
+ static ipsec_spi_t spi = 0; /* host order, so not returned directly! */
+ char text_said[SATOT_BUF];
+
+ set_text_said(text_said, &sr->this.host_addr, 0, proto);
+
+ if (kernel_ops->get_spi)
+ return kernel_ops->get_spi(&sr->that.host_addr
+ , &sr->this.host_addr, proto, tunnel
+ , get_proto_reqid(sr->reqid, proto)
+ , IPSEC_DOI_SPI_OUR_MIN, 0xffffffff
+ , text_said);
+
+ spi++;
+ while (spi < IPSEC_DOI_SPI_OUR_MIN || spi == ntohl(avoid))
+ get_rnd_bytes((u_char *)&spi, sizeof(spi));
+
+ DBG(DBG_CONTROL,
+ {
+ ipsec_spi_t spi_net = htonl(spi);
+
+ DBG_dump("generate SPI:", (u_char *)&spi_net, sizeof(spi_net));
+ });
+
+ return htonl(spi);
+}
+
+/* Generate Unique CPI numbers.
+ * The result is returned as an SPI (4 bytes) in network order!
+ * The real bits are in the nework-low-order 2 bytes.
+ * Modelled on get_ipsec_spi, but range is more limited:
+ * 256-61439.
+ * If we can't find one easily, return 0 (a bad SPI,
+ * no matter what order) indicating failure.
+ */
+ipsec_spi_t
+get_my_cpi(struct spd_route *sr, bool tunnel)
+{
+ static cpi_t
+ first_busy_cpi = 0,
+ latest_cpi;
+ char text_said[SATOT_BUF];
+
+ set_text_said(text_said, &sr->this.host_addr, 0, IPPROTO_COMP);
+
+ if (kernel_ops->get_spi)
+ return kernel_ops->get_spi(&sr->that.host_addr
+ , &sr->this.host_addr, IPPROTO_COMP, tunnel
+ , get_proto_reqid(sr->reqid, IPPROTO_COMP)
+ , IPCOMP_FIRST_NEGOTIATED, IPCOMP_LAST_NEGOTIATED
+ , text_said);
+
+ while (!(IPCOMP_FIRST_NEGOTIATED <= first_busy_cpi && first_busy_cpi < IPCOMP_LAST_NEGOTIATED))
+ {
+ get_rnd_bytes((u_char *)&first_busy_cpi, sizeof(first_busy_cpi));
+ latest_cpi = first_busy_cpi;
+ }
+
+ latest_cpi++;
+
+ if (latest_cpi == first_busy_cpi)
+ find_my_cpi_gap(&latest_cpi, &first_busy_cpi);
+
+ if (latest_cpi > IPCOMP_LAST_NEGOTIATED)
+ latest_cpi = IPCOMP_FIRST_NEGOTIATED;
+
+ return htonl((ipsec_spi_t)latest_cpi);
+}
+
+/* invoke the updown script to do the routing and firewall commands required
+ *
+ * The user-specified updown script is run. Parameters are fed to it in
+ * the form of environment variables. All such environment variables
+ * have names starting with "PLUTO_".
+ *
+ * The operation to be performed is specified by PLUTO_VERB. This
+ * verb has a suffix "-host" if the client on this end is just the
+ * host; otherwise the suffix is "-client". If the address family
+ * of the host is IPv6, an extra suffix of "-v6" is added.
+ *
+ * "prepare-host" and "prepare-client" are used to delete a route
+ * that may exist (due to forces outside of Pluto). It is used to
+ * prepare for pluto creating a route.
+ *
+ * "route-host" and "route-client" are used to install a route.
+ * Since routing is based only on destination, the PLUTO_MY_CLIENT_*
+ * values are probably of no use (using them may signify a bug).
+ *
+ * "unroute-host" and "unroute-client" are used to delete a route.
+ * Since routing is based only on destination, the PLUTO_MY_CLIENT_*
+ * values are probably of no use (using them may signify a bug).
+ *
+ * "up-host" and "up-client" are run when an eroute is added (not replaced).
+ * They are useful for adjusting a firewall: usually for adding a rule
+ * to let processed packets flow between clients. Note that only
+ * one eroute may exist for a pair of client subnets but inbound
+ * IPsec SAs may persist without an eroute.
+ *
+ * "down-host" and "down-client" are run when an eroute is deleted.
+ * They are useful for adjusting a firewall.
+ */
+
+#ifndef DEFAULT_UPDOWN
+# define DEFAULT_UPDOWN "ipsec _updown"
+#endif
+
+static bool
+do_command(struct connection *c, struct spd_route *sr, const char *verb)
+{
+ char cmd[1536]; /* arbitrary limit on shell command length */
+ const char *verb_suffix;
+
+ /* figure out which verb suffix applies */
+ {
+ const char *hs, *cs;
+
+ switch (addrtypeof(&sr->this.host_addr))
+ {
+ case AF_INET:
+ hs = "-host";
+ cs = "-client";
+ break;
+ case AF_INET6:
+ hs = "-host-v6";
+ cs = "-client-v6";
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "unknown address family");
+ return FALSE;
+ }
+ verb_suffix = subnetisaddr(&sr->this.client, &sr->this.host_addr)
+ ? hs : cs;
+ }
+
+ /* form the command string */
+ {
+ char
+ nexthop_str[sizeof("PLUTO_NEXT_HOP='' ") +ADDRTOT_BUF] = "",
+ srcip_str[sizeof("PLUTO_MY_SOURCEIP='' ")+ADDRTOT_BUF] = "",
+ me_str[ADDRTOT_BUF],
+ myid_str[BUF_LEN],
+ myclient_str[SUBNETTOT_BUF],
+ myclientnet_str[ADDRTOT_BUF],
+ myclientmask_str[ADDRTOT_BUF],
+ peer_str[ADDRTOT_BUF],
+ peerid_str[BUF_LEN],
+ peerclient_str[SUBNETTOT_BUF],
+ peerclientnet_str[ADDRTOT_BUF],
+ peerclientmask_str[ADDRTOT_BUF],
+ peerca_str[BUF_LEN],
+ secure_myid_str[BUF_LEN] = "",
+ secure_peerid_str[BUF_LEN] = "",
+ secure_peerca_str[BUF_LEN] = "";
+ ip_address ta;
+ pubkey_list_t *p;
+
+ if (addrbytesptr(&sr->this.host_nexthop, NULL)
+ && !isanyaddr(&sr->this.host_nexthop))
+ {
+ char *n;
+
+ strcpy(nexthop_str, "PLUTO_NEXT_HOP='");
+ n = nexthop_str + strlen(nexthop_str);
+
+ addrtot(&sr->this.host_nexthop, 0
+ ,n , sizeof(nexthop_str)-strlen(nexthop_str));
+ strncat(nexthop_str, "' ", sizeof(nexthop_str));
+ }
+
+ if (addrbytesptr(&sr->this.host_srcip, NULL)
+ && !isanyaddr(&sr->this.host_srcip))
+ {
+ char *n;
+
+ strcpy(srcip_str, "PLUTO_MY_SOURCEIP='");
+ n = srcip_str + strlen(srcip_str);
+
+ addrtot(&sr->this.host_srcip, 0
+ ,n , sizeof(srcip_str)-strlen(srcip_str));
+ strncat(srcip_str, "' ", sizeof(srcip_str));
+ }
+
+ addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str));
+ idtoa(&sr->this.id, myid_str, sizeof(myid_str));
+ escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str));
+ subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str));
+ networkof(&sr->this.client, &ta);
+ addrtot(&ta, 0, myclientnet_str, sizeof(myclientnet_str));
+ maskof(&sr->this.client, &ta);
+ addrtot(&ta, 0, myclientmask_str, sizeof(myclientmask_str));
+
+ addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str));
+ idtoa(&sr->that.id, peerid_str, sizeof(peerid_str));
+ escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str));
+ subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str));
+ networkof(&sr->that.client, &ta);
+ addrtot(&ta, 0, peerclientnet_str, sizeof(peerclientnet_str));
+ maskof(&sr->that.client, &ta);
+ addrtot(&ta, 0, peerclientmask_str, sizeof(peerclientmask_str));
+
+ for (p = pubkeys; p != NULL; p = p->next)
+ {
+ pubkey_t *key = p->key;
+ int pathlen;
+
+ if (key->alg == PUBKEY_ALG_RSA && same_id(&sr->that.id, &key->id)
+ && trusted_ca(key->issuer, sr->that.ca, &pathlen))
+ {
+ dntoa_or_null(peerca_str, BUF_LEN, key->issuer, "");
+ escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str));
+ break;
+ }
+ }
+
+ if (-1 == snprintf(cmd, sizeof(cmd)
+ , "2>&1 " /* capture stderr along with stdout */
+ "PLUTO_VERSION='1.1' " /* change VERSION when interface spec changes */
+ "PLUTO_VERB='%s%s' "
+ "PLUTO_CONNECTION='%s' "
+ "%s" /* optional PLUTO_NEXT_HOP */
+ "PLUTO_INTERFACE='%s' "
+ "%s" /* optional PLUTO_HOST_ACCESS */
+ "PLUTO_REQID='%u' "
+ "PLUTO_ME='%s' "
+ "PLUTO_MY_ID='%s' "
+ "PLUTO_MY_CLIENT='%s' "
+ "PLUTO_MY_CLIENT_NET='%s' "
+ "PLUTO_MY_CLIENT_MASK='%s' "
+ "PLUTO_MY_PORT='%u' "
+ "PLUTO_MY_PROTOCOL='%u' "
+ "PLUTO_PEER='%s' "
+ "PLUTO_PEER_ID='%s' "
+ "PLUTO_PEER_CLIENT='%s' "
+ "PLUTO_PEER_CLIENT_NET='%s' "
+ "PLUTO_PEER_CLIENT_MASK='%s' "
+ "PLUTO_PEER_PORT='%u' "
+ "PLUTO_PEER_PROTOCOL='%u' "
+ "PLUTO_PEER_CA='%s' "
+ "%s" /* optional PLUTO_MY_SRCIP */
+ "%s" /* actual script */
+ , verb, verb_suffix
+ , c->name
+ , nexthop_str
+ , c->interface->vname
+ , sr->this.hostaccess? "PLUTO_HOST_ACCESS='1' " : ""
+ , sr->reqid + 1 /* ESP requid */
+ , me_str
+ , secure_myid_str
+ , myclient_str
+ , myclientnet_str
+ , myclientmask_str
+ , sr->this.port
+ , sr->this.protocol
+ , peer_str
+ , secure_peerid_str
+ , peerclient_str
+ , peerclientnet_str
+ , peerclientmask_str
+ , sr->that.port
+ , sr->that.protocol
+ , secure_peerca_str
+ , srcip_str
+ , sr->this.updown == NULL? DEFAULT_UPDOWN : sr->this.updown))
+ {
+ loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix);
+ return FALSE;
+ }
+ }
+
+ DBG(DBG_CONTROL, DBG_log("executing %s%s: %s"
+ , verb, verb_suffix, cmd));
+
+#ifdef KLIPS
+ if (!no_klips)
+ {
+ /* invoke the script, catching stderr and stdout
+ * It may be of concern that some file descriptors will
+ * be inherited. For the ones under our control, we
+ * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this.
+ * Any used by library routines (perhaps the resolver or syslog)
+ * will remain.
+ */
+ FILE *f = popen(cmd, "r");
+
+ if (f == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix);
+ return FALSE;
+ }
+
+ /* log any output */
+ for (;;)
+ {
+ /* if response doesn't fit in this buffer, it will be folded */
+ char resp[256];
+
+ if (fgets(resp, sizeof(resp), f) == NULL)
+ {
+ if (ferror(f))
+ {
+ log_errno((e, "fgets failed on output of %s%s command"
+ , verb, verb_suffix));
+ return FALSE;
+ }
+ else
+ {
+ passert(feof(f));
+ break;
+ }
+ }
+ else
+ {
+ char *e = resp + strlen(resp);
+
+ if (e > resp && e[-1] == '\n')
+ e[-1] = '\0'; /* trim trailing '\n' */
+ plog("%s%s output: %s", verb, verb_suffix, resp);
+ }
+ }
+
+ /* report on and react to return code */
+ {
+ int r = pclose(f);
+
+ if (r == -1)
+ {
+ log_errno((e, "pclose failed for %s%s command"
+ , verb, verb_suffix));
+ return FALSE;
+ }
+ else if (WIFEXITED(r))
+ {
+ if (WEXITSTATUS(r) != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d"
+ , verb, verb_suffix, WEXITSTATUS(r));
+ return FALSE;
+ }
+ }
+ else if (WIFSIGNALED(r))
+ {
+ loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d"
+ , verb, verb_suffix, WTERMSIG(r));
+ return FALSE;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d"
+ , verb, verb_suffix, r);
+ return FALSE;
+ }
+ }
+ }
+#endif /* KLIPS */
+ return TRUE;
+}
+
+/* Check that we can route (and eroute). Diagnose if we cannot. */
+
+enum routability {
+ route_impossible = 0,
+ route_easy = 1,
+ route_nearconflict = 2,
+ route_farconflict = 3
+};
+
+static enum routability
+could_route(struct connection *c)
+{
+ struct spd_route *esr, *rosr;
+ struct connection *ero /* who, if anyone, owns our eroute? */
+ , *ro = route_owner(c, &rosr, &ero, &esr); /* who owns our route? */
+
+ /* it makes no sense to route a connection that is ISAKMP-only */
+ if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy))
+ {
+ loglog(RC_ROUTE, "cannot route an ISAKMP-only connection");
+ return route_impossible;
+ }
+
+ /* if this is a Road Warrior template, we cannot route.
+ * Opportunistic template is OK.
+ */
+ if (c->kind == CK_TEMPLATE && !(c->policy & POLICY_OPPO))
+ {
+ loglog(RC_ROUTE, "cannot route Road Warrior template");
+ return route_impossible;
+ }
+
+ /* if we don't know nexthop, we cannot route */
+ if (isanyaddr(&c->spd.this.host_nexthop))
+ {
+ loglog(RC_ROUTE, "cannot route connection without knowing our nexthop");
+ return route_impossible;
+ }
+
+ /* if routing would affect IKE messages, reject */
+ if (!no_klips
+#ifdef NAT_TRAVERSAL
+ && c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT
+#endif
+ && c->spd.this.host_port != IKE_UDP_PORT
+ && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client))
+ {
+ loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client");
+ return route_impossible;
+ }
+
+ /* If there is already a route for peer's client subnet
+ * and it disagrees about interface or nexthop, we cannot steal it.
+ * Note: if this connection is already routed (perhaps for another
+ * state object), the route will agree.
+ * This is as it should be -- it will arise during rekeying.
+ */
+ if (ro != NULL && !routes_agree(ro, c))
+ {
+ loglog(RC_LOG_SERIOUS, "cannot route -- route already in use for \"%s\""
+ , ro->name);
+ return route_impossible; /* another connection already
+ using the eroute */
+ }
+
+#ifdef KLIPS
+ /* if there is an eroute for another connection, there is a problem */
+ if (ero != NULL && ero != c)
+ {
+ struct connection *ero2, *ero_top;
+ struct connection *inside, *outside;
+
+ /*
+ * note, wavesec (PERMANENT) goes *outside* and
+ * OE goes *inside* (TEMPLATE)
+ */
+ inside = NULL;
+ outside= NULL;
+ if (ero->kind == CK_PERMANENT
+ && c->kind == CK_TEMPLATE)
+ {
+ outside = ero;
+ inside = c;
+ }
+ else if (c->kind == CK_PERMANENT
+ && ero->kind == CK_TEMPLATE)
+ {
+ outside = c;
+ inside = ero;
+ }
+
+ /* okay, check again, with correct order */
+ if (outside && outside->kind == CK_PERMANENT
+ && inside && inside->kind == CK_TEMPLATE)
+ {
+ char inst[CONN_INST_BUF];
+
+ /* this is a co-terminal attempt of the "near" kind. */
+ /* when chaining, we chain from inside to outside */
+
+ /* XXX permit multiple deep connections? */
+ passert(inside->policy_next == NULL);
+
+ inside->policy_next = outside;
+
+ /* since we are going to steal the eroute from the secondary
+ * policy, we need to make sure that it no longer thinks that
+ * it owns the eroute.
+ */
+ outside->spd.eroute_owner = SOS_NOBODY;
+ outside->spd.routing = RT_UNROUTED_KEYED;
+
+ /* set the priority of the new eroute owner to be higher
+ * than that of the current eroute owner
+ */
+ inside->prio = outside->prio + 1;
+
+ fmt_conn_instance(inside, inst);
+
+ loglog(RC_LOG_SERIOUS
+ , "conflict on eroute (%s), switching eroute to %s and linking %s"
+ , inst, inside->name, outside->name);
+
+ return route_nearconflict;
+ }
+
+ /* look along the chain of policies for one with the same name */
+ ero_top = ero;
+
+ for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next)
+ {
+ if (ero2->kind == CK_TEMPLATE
+ && streq(ero2->name, c->name))
+ break;
+ }
+
+ /* If we fell of the end of the list, then we found no TEMPLATE
+ * so there must be a conflict that we can't resolve.
+ * As the names are not equal, then we aren't replacing/rekeying.
+ */
+ if (ero2 == NULL)
+ {
+ char inst[CONN_INST_BUF];
+
+ fmt_conn_instance(ero, inst);
+
+ loglog(RC_LOG_SERIOUS
+ , "cannot install eroute -- it is in use for \"%s\"%s #%lu"
+ , ero->name, inst, esr->eroute_owner);
+ return FALSE; /* another connection already using the eroute */
+ }
+ }
+#endif /* KLIPS */
+ return route_easy;
+}
+
+bool
+trap_connection(struct connection *c)
+{
+ switch (could_route(c))
+ {
+ case route_impossible:
+ return FALSE;
+
+ case route_nearconflict:
+ case route_easy:
+ /* RT_ROUTED_TUNNEL is treated specially: we don't override
+ * because we don't want to lose track of the IPSEC_SAs etc.
+ */
+ if (c->spd.routing < RT_ROUTED_TUNNEL)
+ {
+ return route_and_eroute(c, &c->spd, NULL);
+ }
+ return TRUE;
+
+ case route_farconflict:
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+/* delete any eroute for a connection and unroute it if route isn't shared */
+void
+unroute_connection(struct connection *c)
+{
+ struct spd_route *sr;
+ enum routing_t cr;
+
+ for (sr = &c->spd; sr; sr = sr->next)
+ {
+ cr = sr->routing;
+
+ if (erouted(cr))
+ {
+ /* cannot handle a live one */
+ passert(sr->routing != RT_ROUTED_TUNNEL);
+#ifdef KLIPS
+ shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete");
+#endif
+ }
+
+ sr->routing = RT_UNROUTED; /* do now so route_owner won't find us */
+
+ /* only unroute if no other connection shares it */
+ if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL)
+ (void) do_command(c, sr, "unroute");
+ }
+}
+
+
+#ifdef KLIPS
+
+static void
+set_text_said(char *text_said, const ip_address *dst, ipsec_spi_t spi, int proto)
+{
+ ip_said said;
+
+ initsaid(dst, spi, proto, &said);
+ satot(&said, 0, text_said, SATOT_BUF);
+}
+
+/* find an entry in the bare_shunt table.
+ * Trick: return a pointer to the pointer to the entry;
+ * this allows the entry to be deleted.
+ */
+static struct bare_shunt **
+bare_shunt_ptr(const ip_subnet *ours, const ip_subnet *his, int transport_proto)
+{
+ struct bare_shunt *p, **pp;
+
+ for (pp = &bare_shunts; (p = *pp) != NULL; pp = &p->next)
+ {
+ if (samesubnet(ours, &p->ours)
+ && samesubnet(his, &p->his)
+ && transport_proto == p->transport_proto
+ && portof(&ours->addr) == portof(&p->ours.addr)
+ && portof(&his->addr) == portof(&p->his.addr))
+ return pp;
+ }
+ return NULL;
+}
+
+/* free a bare_shunt entry, given a pointer to the pointer */
+static void
+free_bare_shunt(struct bare_shunt **pp)
+{
+ if (pp == NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("delete bare shunt: null pointer")
+ )
+ }
+ else
+ {
+ struct bare_shunt *p = *pp;
+
+ *pp = p->next;
+ DBG_bare_shunt("delete", p);
+ pfree(p->why);
+ pfree(p);
+ }
+}
+
+void
+show_shunt_status(void)
+{
+ struct bare_shunt *bs;
+
+ for (bs = bare_shunts; bs != NULL; bs = bs->next)
+ {
+ /* Print interesting fields. Ignore count and last_active. */
+
+ int ourport = ntohs(portof(&bs->ours.addr));
+ int hisport = ntohs(portof(&bs->his.addr));
+ char ourst[SUBNETTOT_BUF];
+ char hist[SUBNETTOT_BUF];
+ char sat[SATOT_BUF];
+ char prio[POLICY_PRIO_BUF];
+
+ subnettot(&(bs)->ours, 0, ourst, sizeof(ourst));
+ subnettot(&(bs)->his, 0, hist, sizeof(hist));
+ satot(&(bs)->said, 0, sat, sizeof(sat));
+ fmt_policy_prio(bs->policy_prio, prio);
+
+ whack_log(RC_COMMENT, "%s:%d -> %s:%d => %s:%d %s %s"
+ , ourst, ourport, hist, hisport, sat, bs->transport_proto
+ , prio, bs->why);
+ }
+}
+
+/* Setup an IPsec route entry.
+ * op is one of the ERO_* operators.
+ */
+
+static bool
+raw_eroute(const ip_address *this_host
+ , const ip_subnet *this_client
+ , const ip_address *that_host
+ , const ip_subnet *that_client
+ , ipsec_spi_t spi
+ , unsigned int proto
+ , unsigned int satype
+ , unsigned int transport_proto
+ , const struct pfkey_proto_info *proto_info
+ , time_t use_lifetime
+ , unsigned int op
+ , const char *opname USED_BY_DEBUG)
+{
+ char text_said[SATOT_BUF];
+
+ set_text_said(text_said, that_host, spi, proto);
+
+ DBG(DBG_CONTROL | DBG_KLIPS,
+ {
+ int sport = ntohs(portof(&this_client->addr));
+ int dport = ntohs(portof(&that_client->addr));
+ char mybuf[SUBNETTOT_BUF];
+ char peerbuf[SUBNETTOT_BUF];
+
+ subnettot(this_client, 0, mybuf, sizeof(mybuf));
+ subnettot(that_client, 0, peerbuf, sizeof(peerbuf));
+ DBG_log("%s eroute %s:%d -> %s:%d => %s:%d"
+ , opname, mybuf, sport, peerbuf, dport
+ , text_said, transport_proto);
+ });
+
+ return kernel_ops->raw_eroute(this_host, this_client
+ , that_host, that_client, spi, satype, transport_proto, proto_info
+ , use_lifetime, op, text_said);
+}
+
+/* test to see if %hold remains */
+bool
+has_bare_hold(const ip_address *src, const ip_address *dst, int transport_proto)
+{
+ ip_subnet this_client, that_client;
+ struct bare_shunt **bspp;
+
+ passert(addrtypeof(src) == addrtypeof(dst));
+ happy(addrtosubnet(src, &this_client));
+ happy(addrtosubnet(dst, &that_client));
+ bspp = bare_shunt_ptr(&this_client, &that_client, transport_proto);
+ return bspp != NULL
+ && (*bspp)->said.proto == SA_INT && (*bspp)->said.spi == htonl(SPI_HOLD);
+}
+
+
+/* Replace (or delete) a shunt that is in the bare_shunts table.
+ * Issues the PF_KEY commands and updates the bare_shunts table.
+ */
+bool
+replace_bare_shunt(const ip_address *src, const ip_address *dst
+ , policy_prio_t policy_prio
+ , ipsec_spi_t shunt_spi /* in host order! */
+ , bool repl /* if TRUE, replace; if FALSE, delete */
+ , unsigned int transport_proto
+ , const char *why)
+{
+ ip_subnet this_client, that_client;
+ ip_subnet this_broad_client, that_broad_client;
+ const ip_address *null_host = aftoinfo(addrtypeof(src))->any;
+
+ passert(addrtypeof(src) == addrtypeof(dst));
+ happy(addrtosubnet(src, &this_client));
+ happy(addrtosubnet(dst, &that_client));
+ this_broad_client = this_client;
+ that_broad_client = that_client;
+ setportof(0, &this_broad_client.addr);
+ setportof(0, &that_broad_client.addr);
+
+ if (repl)
+ {
+ struct bare_shunt **bs_pp = bare_shunt_ptr(&this_broad_client
+ , &that_broad_client, 0);
+
+ /* is there already a broad host-to-host bare shunt? */
+ if (bs_pp == NULL)
+ {
+ if (raw_eroute(null_host, &this_broad_client, null_host, &that_broad_client
+ , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT
+ , 0, null_proto_info
+ , SHUNT_PATIENCE, ERO_ADD, why))
+ {
+ struct bare_shunt *bs = alloc_thing(struct bare_shunt, "bare shunt");
+
+ bs->ours = this_broad_client;
+ bs->his = that_broad_client;
+ bs->transport_proto = 0;
+ bs->said.proto = SA_INT;
+ bs->why = clone_str(why, "bare shunt story");
+ bs->policy_prio = policy_prio;
+ bs->said.spi = htonl(shunt_spi);
+ bs->said.dst = *null_host;
+ bs->count = 0;
+ bs->last_activity = now();
+ bs->next = bare_shunts;
+ bare_shunts = bs;
+ DBG_bare_shunt("add", bs);
+ }
+ }
+ shunt_spi = SPI_HOLD;
+ }
+
+ if (raw_eroute(null_host, &this_client, null_host, &that_client
+ , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT
+ , transport_proto, null_proto_info
+ , SHUNT_PATIENCE, ERO_DELETE, why))
+ {
+ struct bare_shunt **bs_pp = bare_shunt_ptr(&this_client, &that_client
+ , transport_proto);
+
+ /* delete bare eroute */
+ free_bare_shunt(bs_pp);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static bool
+eroute_connection(struct spd_route *sr
+, ipsec_spi_t spi, unsigned int proto, unsigned int satype
+, const struct pfkey_proto_info *proto_info
+, unsigned int op, const char *opname)
+{
+ const ip_address *peer = &sr->that.host_addr;
+ char buf2[256];
+
+ snprintf(buf2, sizeof(buf2)
+ , "eroute_connection %s", opname);
+
+ if (proto == SA_INT)
+ peer = aftoinfo(addrtypeof(peer))->any;
+
+ return raw_eroute(&sr->this.host_addr, &sr->this.client
+ , peer
+ , &sr->that.client
+ , spi, proto, satype
+ , sr->this.protocol, proto_info, 0, op, buf2);
+}
+
+/* assign a bare hold to a connection */
+
+bool
+assign_hold(struct connection *c USED_BY_DEBUG
+ , struct spd_route *sr
+ , int transport_proto
+ , const ip_address *src, const ip_address *dst)
+{
+ /* either the automatically installed %hold eroute is broad enough
+ * or we try to add a broader one and delete the automatic one.
+ * Beware: this %hold might be already handled, but still squeak
+ * through because of a race.
+ */
+ enum routing_t ro = sr->routing /* routing, old */
+ , rn = ro; /* routing, new */
+
+ passert(LHAS(LELEM(CK_PERMANENT) | LELEM(CK_INSTANCE), c->kind));
+ /* figure out what routing should become */
+ switch (ro)
+ {
+ case RT_UNROUTED:
+ rn = RT_UNROUTED_HOLD;
+ break;
+ case RT_ROUTED_PROSPECTIVE:
+ rn = RT_ROUTED_HOLD;
+ break;
+ default:
+ /* no change: this %hold is old news and should just be deleted */
+ break;
+ }
+
+ /* we need a broad %hold, not the narrow one.
+ * First we ensure that there is a broad %hold.
+ * There may already be one (race condition): no need to create one.
+ * There may already be a %trap: replace it.
+ * There may not be any broad eroute: add %hold.
+ * Once the broad %hold is in place, delete the narrow one.
+ */
+ if (rn != ro)
+ {
+ if (erouted(ro)
+ ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT
+ , null_proto_info
+ , ERO_REPLACE, "replace %trap with broad %hold")
+ : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT
+ , null_proto_info
+ , ERO_ADD, "add broad %hold"))
+ {
+ return FALSE;
+ }
+ }
+ if (!replace_bare_shunt(src, dst, BOTTOM_PRIO, SPI_HOLD, FALSE
+ , transport_proto, "delete narrow %hold"))
+ {
+ return FALSE;
+ }
+ sr->routing = rn;
+ return TRUE;
+}
+
+/* install or remove eroute for SA Group */
+static bool
+sag_eroute(struct state *st, struct spd_route *sr
+ , unsigned op, const char *opname)
+{
+ u_int inner_proto = 0;
+ u_int inner_satype = 0;
+ ipsec_spi_t inner_spi = 0;
+ struct pfkey_proto_info proto_info[4];
+ int i;
+ bool tunnel;
+
+ /* figure out the SPI and protocol (in two forms)
+ * for the innermost transformation.
+ */
+
+ i = sizeof(proto_info) / sizeof(proto_info[0]) - 1;
+ proto_info[i].proto = 0;
+ tunnel = FALSE;
+
+ if (st->st_ah.present)
+ {
+ inner_spi = st->st_ah.attrs.spi;
+ inner_proto = SA_AH;
+ inner_satype = SADB_SATYPE_AH;
+
+ i--;
+ proto_info[i].proto = IPPROTO_AH;
+ proto_info[i].encapsulation = st->st_ah.attrs.encapsulation;
+ tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;
+ proto_info[i].reqid = sr->reqid;
+ }
+
+ if (st->st_esp.present)
+ {
+ inner_spi = st->st_esp.attrs.spi;
+ inner_proto = SA_ESP;
+ inner_satype = SADB_SATYPE_ESP;
+
+ i--;
+ proto_info[i].proto = IPPROTO_ESP;
+ proto_info[i].encapsulation = st->st_esp.attrs.encapsulation;
+ tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;
+ proto_info[i].reqid = sr->reqid + 1;
+ }
+
+ if (st->st_ipcomp.present)
+ {
+ inner_spi = st->st_ipcomp.attrs.spi;
+ inner_proto = SA_COMP;
+ inner_satype = SADB_X_SATYPE_COMP;
+
+ i--;
+ proto_info[i].proto = IPPROTO_COMP;
+ proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation;
+ tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;
+ proto_info[i].reqid = sr->reqid + 2;
+ }
+
+ if (i == sizeof(proto_info) / sizeof(proto_info[0]) - 1)
+ {
+ impossible(); /* no transform at all! */
+ }
+
+ if (tunnel)
+ {
+ int j;
+
+ inner_spi = st->st_tunnel_out_spi;
+ inner_proto = SA_IPIP;
+ inner_satype = SADB_X_SATYPE_IPIP;
+
+ proto_info[i].encapsulation = ENCAPSULATION_MODE_TUNNEL;
+ for (j = i + 1; proto_info[j].proto; j++)
+ {
+ proto_info[j].encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+ }
+
+ return eroute_connection(sr
+ , inner_spi, inner_proto, inner_satype, proto_info + i
+ , op, opname);
+}
+
+/* compute a (host-order!) SPI to implement the policy in connection c */
+ipsec_spi_t
+shunt_policy_spi(struct connection *c, bool prospective)
+{
+ /* note: these are in host order :-( */
+ static const ipsec_spi_t shunt_spi[] =
+ {
+ SPI_TRAP, /* --initiateontraffic */
+ SPI_PASS, /* --pass */
+ SPI_DROP, /* --drop */
+ SPI_REJECT, /* --reject */
+ };
+
+ static const ipsec_spi_t fail_spi[] =
+ {
+ 0, /* --none*/
+ SPI_PASS, /* --failpass */
+ SPI_DROP, /* --faildrop */
+ SPI_REJECT, /* --failreject */
+ };
+
+ return prospective
+ ? shunt_spi[(c->policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT]
+ : fail_spi[(c->policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT];
+}
+
+/* Add/replace/delete a shunt eroute.
+ * Such an eroute determines the fate of packets without the use
+ * of any SAs. These are defaults, in effect.
+ * If a negotiation has not been attempted, use %trap.
+ * If negotiation has failed, the choice between %trap/%pass/%drop/%reject
+ * is specified in the policy of connection c.
+ */
+static bool
+shunt_eroute(struct connection *c
+, struct spd_route *sr
+, enum routing_t rt_kind
+, unsigned int op, const char *opname)
+{
+ /* We are constructing a special SAID for the eroute.
+ * The destination doesn't seem to matter, but the family does.
+ * The protocol is SA_INT -- mark this as shunt.
+ * The satype has no meaning, but is required for PF_KEY header!
+ * The SPI signifies the kind of shunt.
+ */
+ ipsec_spi_t spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE);
+ bool ok;
+
+ if (spi == 0)
+ {
+ /* we're supposed to end up with no eroute: rejig op and opname */
+ switch (op)
+ {
+ case ERO_REPLACE:
+ /* replace with nothing == delete */
+ op = ERO_DELETE;
+ opname = "delete";
+ break;
+ case ERO_ADD:
+ /* add nothing == do nothing */
+ return TRUE;
+ case ERO_DELETE:
+ /* delete remains delete */
+ break;
+ default:
+ bad_case(op);
+ }
+ }
+ if (sr->routing == RT_ROUTED_ECLIPSED && c->kind == CK_TEMPLATE)
+ {
+ /* We think that we have an eroute, but we don't.
+ * Adjust the request and account for eclipses.
+ */
+ passert(eclipsable(sr));
+ switch (op)
+ {
+ case ERO_REPLACE:
+ /* really an add */
+ op = ERO_ADD;
+ opname = "replace eclipsed";
+ eclipse_count--;
+ break;
+ case ERO_DELETE:
+ /* delete unnecessary: we don't actually have an eroute */
+ eclipse_count--;
+ return TRUE;
+ case ERO_ADD:
+ default:
+ bad_case(op);
+ }
+ }
+ else if (eclipse_count > 0 && op == ERO_DELETE && eclipsable(sr))
+ {
+ /* maybe we are uneclipsing something */
+ struct spd_route *esr;
+ struct connection *ue = eclipsed(c, &esr);
+
+ if (ue != NULL)
+ {
+ esr->routing = RT_ROUTED_PROSPECTIVE;
+ return shunt_eroute(ue, esr
+ , RT_ROUTED_PROSPECTIVE, ERO_REPLACE, "restoring eclipsed");
+ }
+ }
+
+ ok = TRUE;
+ if (kernel_ops->inbound_eroute)
+ {
+ ok = raw_eroute(&c->spd.that.host_addr, &c->spd.that.client
+ , &c->spd.this.host_addr, &c->spd.this.client
+ , htonl(spi), SA_INT, SADB_X_SATYPE_INT
+ , 0, null_proto_info, 0
+ , op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), opname);
+ }
+ return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT
+ , null_proto_info, op, opname) && ok;
+}
+
+
+/*
+ * This is only called when s is a likely SAID with trailing protocol i.e.
+ * it has the form :-
+ *
+ * %<keyword>:p
+ * <ip-proto><spi>@a.b.c.d:p
+ *
+ * The task here is to remove the ":p" part so that the rest can be read
+ * by another routine.
+ */
+static const char *
+read_proto(const char * s, size_t * len, int * transport_proto)
+{
+ const char * p;
+ const char * ugh;
+ unsigned long proto;
+ size_t l;
+
+ l = *len;
+ p = memchr(s, ':', l);
+ if (p == 0) {
+ *transport_proto = 0;
+ return 0;
+ }
+ ugh = ttoul(p+1, l-((p-s)+1), 10, &proto);
+ if (ugh != 0)
+ return ugh;
+ if (proto > 65535)
+ return "protocol number is too large, legal range is 0-65535";
+ *len = p-s;
+ *transport_proto = proto;
+ return 0;
+}
+
+
+/* scan /proc/net/ipsec_eroute every once in a while, looking for:
+ *
+ * - %hold shunts of which Pluto isn't aware. This situation could
+ * be caused by lost ACQUIRE messages. When found, they will
+ * added to orphan_holds. This in turn will lead to Opportunistic
+ * initiation.
+ *
+ * - other kinds of shunts that haven't been used recently. These will be
+ * deleted. They represent OE failures.
+ *
+ * - recording recent uses of tunnel eroutes so that rekeying decisions
+ * can be made for OE connections.
+ *
+ * Here are some sample lines:
+ * 10 10.3.2.1.0/24 -> 0.0.0.0/0 => %trap
+ * 259 10.3.2.1.115/32 -> 10.19.75.161/32 => tun0x1002@10.19.75.145
+ * 71 10.44.73.97/32 -> 0.0.0.0/0 => %trap
+ * 4119 10.44.73.97/32 -> 10.114.121.41/32 => %pass
+ * Newer versions of KLIPS start each line with a 32-bit packet count.
+ * If available, the count is used to detect whether a %pass shunt is in use.
+ *
+ * NOTE: execution time is quadratic in the number of eroutes since the
+ * searching for each is sequential. If this becomes a problem, faster
+ * searches could be implemented (hash or radix tree, for example).
+ */
+void
+scan_proc_shunts(void)
+{
+ static const char procname[] = "/proc/net/ipsec_eroute";
+ FILE *f;
+ time_t nw = now();
+ int lino;
+ struct eroute_info *expired = NULL;
+
+ event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL);
+
+ DBG(DBG_CONTROL,
+ DBG_log("scanning for shunt eroutes")
+ )
+
+ /* free any leftover entries: they will be refreshed if still current */
+ while (orphaned_holds != NULL)
+ {
+ struct eroute_info *p = orphaned_holds;
+
+ orphaned_holds = p->next;
+ pfree(orphaned_holds);
+ }
+
+ /* decode the /proc file. Don't do anything strenuous to it
+ * (certainly no PF_KEY stuff) to minimize the chance that it
+ * might change underfoot.
+ */
+
+ f = fopen(procname, "r");
+ if (f == NULL)
+ return;
+
+ /* for each line... */
+ for (lino = 1; ; lino++)
+ {
+ unsigned char buf[1024]; /* should be big enough */
+ chunk_t field[10]; /* 10 is loose upper bound */
+ chunk_t *ff = NULL; /* fixed fields (excluding optional count) */
+ int fi;
+ struct eroute_info eri;
+ char *cp;
+ err_t context = ""
+ , ugh = NULL;
+
+ cp = fgets(buf, sizeof(buf), f);
+ if (cp == NULL)
+ break;
+
+ /* break out each field
+ * Note: if there are too many fields, just stop;
+ * it will be diagnosed a little later.
+ */
+ for (fi = 0; fi < (int)elemsof(field); fi++)
+ {
+ static const char sep[] = " \t\n"; /* field-separating whitespace */
+ size_t w;
+
+ cp += strspn(cp, sep); /* find start of field */
+ w = strcspn(cp, sep); /* find width of field */
+ setchunk(field[fi], cp, w);
+ cp += w;
+ if (w == 0)
+ break;
+ }
+
+ /* This odd do-hickey is to share error reporting code.
+ * A break will get to that common code. The setting
+ * of "ugh" and "context" parameterize it.
+ */
+ do {
+ /* Old entries have no packet count; new ones do.
+ * check if things are as they should be.
+ */
+ if (fi == 5)
+ ff = &field[0]; /* old form, with no count */
+ else if (fi == 6)
+ ff = &field[1]; /* new form, with count */
+ else
+ {
+ ugh = "has wrong number of fields";
+ break;
+ }
+
+ if (ff[1].len != 2
+ || strncmp(ff[1].ptr, "->", 2) != 0
+ || ff[3].len != 2
+ || strncmp(ff[3].ptr, "=>", 2) != 0)
+ {
+ ugh = "is missing -> or =>";
+ break;
+ }
+
+ /* actually digest fields of interest */
+
+ /* packet count */
+
+ eri.count = 0;
+ if (ff != field)
+ {
+ context = "count field is malformed: ";
+ ugh = ttoul(field[0].ptr, field[0].len, 10, &eri.count);
+ if (ugh != NULL)
+ break;
+ }
+
+ /* our client */
+
+ context = "source subnet field malformed: ";
+ ugh = ttosubnet(ff[0].ptr, ff[0].len, AF_INET, &eri.ours);
+ if (ugh != NULL)
+ break;
+
+ /* his client */
+
+ context = "destination subnet field malformed: ";
+ ugh = ttosubnet(ff[2].ptr, ff[2].len, AF_INET, &eri.his);
+ if (ugh != NULL)
+ break;
+
+ /* SAID */
+
+ context = "SA ID field malformed: ";
+ ugh = read_proto(ff[4].ptr, &ff[4].len, &eri.transport_proto);
+ if (ugh != NULL)
+ break;
+ ugh = ttosa(ff[4].ptr, ff[4].len, &eri.said);
+ } while (FALSE);
+
+ if (ugh != NULL)
+ {
+ plog("INTERNAL ERROR: %s line %d %s%s"
+ , procname, lino, context, ugh);
+ continue; /* ignore rest of line */
+ }
+
+ /* Now we have decoded eroute, let's consider it.
+ * For shunt eroutes:
+ *
+ * %hold: if not known, add to orphaned_holds list for initiation
+ * because ACQUIRE might have been lost.
+ *
+ * %pass, %drop, %reject: determine if idle; if so, blast it away.
+ * Can occur bare (if DNS provided insufficient information)
+ * or with a connection (failure context).
+ * Could even be installed by ipsec manual.
+ *
+ * %trap: always welcome.
+ *
+ * For other eroutes: find state and record count change
+ */
+ if (eri.said.proto == SA_INT)
+ {
+ /* shunt eroute */
+ switch (ntohl(eri.said.spi))
+ {
+ case SPI_HOLD:
+ if (bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto) == NULL
+ && shunt_owner(&eri.ours, &eri.his) == NULL)
+ {
+ int ourport = ntohs(portof(&eri.ours.addr));
+ int hisport = ntohs(portof(&eri.his.addr));
+ char ourst[SUBNETTOT_BUF];
+ char hist[SUBNETTOT_BUF];
+ char sat[SATOT_BUF];
+
+ subnettot(&eri.ours, 0, ourst, sizeof(ourst));
+ subnettot(&eri.his, 0, hist, sizeof(hist));
+ satot(&eri.said, 0, sat, sizeof(sat));
+
+ DBG(DBG_CONTROL,
+ DBG_log("add orphaned shunt %s:%d -> %s:%d => %s:%d"
+ , ourst, ourport, hist, hisport, sat, eri.transport_proto)
+ )
+ eri.next = orphaned_holds;
+ orphaned_holds = clone_thing(eri, "orphaned %hold");
+ }
+ break;
+
+ case SPI_PASS:
+ case SPI_DROP:
+ case SPI_REJECT:
+ /* nothing sensible to do if we don't have counts */
+ if (ff != field)
+ {
+ struct bare_shunt **bs_pp
+ = bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto);
+
+ if (bs_pp != NULL)
+ {
+ struct bare_shunt *bs = *bs_pp;
+
+ if (eri.count != bs->count)
+ {
+ bs->count = eri.count;
+ bs->last_activity = nw;
+ }
+ else if (nw - bs->last_activity > SHUNT_PATIENCE)
+ {
+ eri.next = expired;
+ expired = clone_thing(eri, "expired %pass");
+ }
+ }
+ }
+ break;
+
+ case SPI_TRAP:
+ break;
+
+ default:
+ bad_case(ntohl(eri.said.spi));
+ }
+ }
+ else
+ {
+ /* regular (non-shunt) eroute */
+ state_eroute_usage(&eri.ours, &eri.his, eri.count, nw);
+ }
+ } /* for each line */
+ fclose(f);
+
+ /* Now that we've finished processing the /proc file,
+ * it is safe to delete the expired %pass shunts.
+ */
+ while (expired != NULL)
+ {
+ struct eroute_info *p = expired;
+ ip_address src, dst;
+
+ networkof(&p->ours, &src);
+ networkof(&p->his, &dst);
+ (void) replace_bare_shunt(&src, &dst
+ , BOTTOM_PRIO /* not used because we are deleting. This value is a filler */
+ , SPI_PASS /* not used because we are deleting. This value is a filler */
+ , FALSE, p->transport_proto, "delete expired bare shunts");
+ expired = p->next;
+ pfree(p);
+ }
+}
+
+static bool
+del_spi(ipsec_spi_t spi, int proto
+, const ip_address *src, const ip_address *dest)
+{
+ char text_said[SATOT_BUF];
+ struct kernel_sa sa;
+
+ set_text_said(text_said, dest, spi, proto);
+
+ DBG(DBG_KLIPS, DBG_log("delete %s", text_said));
+
+ memset(&sa, 0, sizeof(sa));
+ sa.spi = spi;
+ sa.proto = proto;
+ sa.src = src;
+ sa.dst = dest;
+ sa.text_said = text_said;
+
+ return kernel_ops->del_sa(&sa);
+}
+
+/* Setup a pair of SAs. Code taken from setsa.c and spigrp.c, in
+ * ipsec-0.5.
+ */
+
+static bool
+setup_half_ipsec_sa(struct state *st, bool inbound)
+{
+ /* Build an inbound or outbound SA */
+
+ struct connection *c = st->st_connection;
+ ip_subnet src, dst;
+ ip_subnet src_client, dst_client;
+ ipsec_spi_t inner_spi = 0;
+ u_int proto = 0;
+ u_int satype = SADB_SATYPE_UNSPEC;
+ bool replace;
+
+ /* SPIs, saved for spigrouping or undoing, if necessary */
+ struct kernel_sa
+ said[EM_MAXRELSPIS],
+ *said_next = said;
+
+ char text_said[SATOT_BUF];
+ int encapsulation;
+
+ replace = inbound && (kernel_ops->get_spi != NULL);
+
+ src.maskbits = 0;
+ dst.maskbits = 0;
+
+ if (inbound)
+ {
+ src.addr = c->spd.that.host_addr;
+ dst.addr = c->spd.this.host_addr;
+ src_client = c->spd.that.client;
+ dst_client = c->spd.this.client;
+ }
+ else
+ {
+ src.addr = c->spd.this.host_addr,
+ dst.addr = c->spd.that.host_addr;
+ src_client = c->spd.this.client;
+ dst_client = c->spd.that.client;
+ }
+
+ encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ encapsulation = ENCAPSULATION_MODE_TUNNEL;
+ }
+
+ memset(said, 0, sizeof(said));
+
+ /* If we are tunnelling, set up IP in IP pseudo SA */
+
+ if (kernel_ops->inbound_eroute)
+ {
+ inner_spi = 256;
+ proto = SA_IPIP;
+ satype = SADB_SATYPE_UNSPEC;
+ }
+ else if (encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ /* XXX hack alert -- we SHOULD NOT HAVE TO HAVE A DIFFERENT SPI
+ * XXX FOR IP-in-IP ENCAPSULATION!
+ */
+
+ ipsec_spi_t ipip_spi;
+
+ /* Allocate an SPI for the tunnel.
+ * Since our peer will never see this,
+ * and it comes from its own number space,
+ * it is purely a local implementation wart.
+ */
+ {
+ static ipsec_spi_t last_tunnel_spi = IPSEC_DOI_SPI_OUR_MIN;
+
+ ipip_spi = htonl(++last_tunnel_spi);
+ if (inbound)
+ st->st_tunnel_in_spi = ipip_spi;
+ else
+ st->st_tunnel_out_spi = ipip_spi;
+ }
+
+ set_text_said(text_said
+ , &c->spd.that.host_addr, ipip_spi, SA_IPIP);
+
+ said_next->src = &src.addr;
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
+ said_next->spi = ipip_spi;
+ said_next->satype = SADB_X_SATYPE_IPIP;
+ said_next->text_said = text_said;
+
+ if (!kernel_ops->add_sa(said_next, replace))
+ goto fail;
+
+ said_next++;
+
+ inner_spi = ipip_spi;
+ proto = SA_IPIP;
+ satype = SADB_X_SATYPE_IPIP;
+ }
+
+ /* set up IPCOMP SA, if any */
+
+ if (st->st_ipcomp.present)
+ {
+ ipsec_spi_t ipcomp_spi = inbound? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi;
+ unsigned compalg;
+
+ switch (st->st_ipcomp.attrs.transid)
+ {
+ case IPCOMP_DEFLATE:
+ compalg = SADB_X_CALG_DEFLATE;
+ break;
+
+ default:
+ loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented"
+ , enum_name(&ipcomp_transformid_names, st->st_ipcomp.attrs.transid));
+ goto fail;
+ }
+
+ set_text_said(text_said, &dst.addr, ipcomp_spi, SA_COMP);
+
+ said_next->src = &src.addr;
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
+ said_next->spi = ipcomp_spi;
+ said_next->satype = SADB_X_SATYPE_COMP;
+ said_next->compalg = compalg;
+ said_next->encapsulation = encapsulation;
+ said_next->reqid = c->spd.reqid + 2;
+ said_next->text_said = text_said;
+
+ if (!kernel_ops->add_sa(said_next, replace))
+ goto fail;
+
+ said_next++;
+
+ encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+
+ /* set up ESP SA, if any */
+
+ if (st->st_esp.present)
+ {
+ ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi;
+ u_char *esp_dst_keymat = inbound? st->st_esp.our_keymat : st->st_esp.peer_keymat;
+ const struct esp_info *ei;
+ u_int16_t key_len;
+
+ static const struct esp_info esp_info[] = {
+ { ESP_NULL, AUTH_ALGORITHM_HMAC_MD5,
+ 0, HMAC_MD5_KEY_LEN,
+ SADB_EALG_NULL, SADB_AALG_MD5_HMAC },
+ { ESP_NULL, AUTH_ALGORITHM_HMAC_SHA1,
+ 0, HMAC_SHA1_KEY_LEN,
+ SADB_EALG_NULL, SADB_AALG_SHA1_HMAC },
+
+ { ESP_DES, AUTH_ALGORITHM_NONE,
+ DES_CBC_BLOCK_SIZE, 0,
+ SADB_EALG_DES_CBC, SADB_AALG_NONE },
+ { ESP_DES, AUTH_ALGORITHM_HMAC_MD5,
+ DES_CBC_BLOCK_SIZE, HMAC_MD5_KEY_LEN,
+ SADB_EALG_DES_CBC, SADB_AALG_MD5_HMAC },
+ { ESP_DES, AUTH_ALGORITHM_HMAC_SHA1,
+ DES_CBC_BLOCK_SIZE,
+ HMAC_SHA1_KEY_LEN, SADB_EALG_DES_CBC, SADB_AALG_SHA1_HMAC },
+
+ { ESP_3DES, AUTH_ALGORITHM_NONE,
+ DES_CBC_BLOCK_SIZE * 3, 0,
+ SADB_EALG_3DES_CBC, SADB_AALG_NONE },
+ { ESP_3DES, AUTH_ALGORITHM_HMAC_MD5,
+ DES_CBC_BLOCK_SIZE * 3, HMAC_MD5_KEY_LEN,
+ SADB_EALG_3DES_CBC, SADB_AALG_MD5_HMAC },
+ { ESP_3DES, AUTH_ALGORITHM_HMAC_SHA1,
+ DES_CBC_BLOCK_SIZE * 3, HMAC_SHA1_KEY_LEN,
+ SADB_EALG_3DES_CBC, SADB_AALG_SHA1_HMAC },
+ };
+
+#ifdef NAT_TRAVERSAL
+ u_int8_t natt_type = 0;
+ u_int16_t natt_sport = 0, natt_dport = 0;
+ ip_address natt_oa;
+
+ if (st->nat_traversal & NAT_T_DETECTED) {
+ natt_type = (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) ?
+ ESPINUDP_WITH_NON_ESP : ESPINUDP_WITH_NON_IKE;
+ natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port;
+ natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port;
+ natt_oa = st->nat_oa;
+ }
+#endif
+
+ for (ei = esp_info; ; ei++)
+ {
+ if (ei == &esp_info[elemsof(esp_info)])
+ {
+ /* Check for additional kernel alg */
+#ifndef NO_KERNEL_ALG
+ if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid,
+ st->st_esp.attrs.auth))!=NULL) {
+ break;
+ }
+#endif
+
+ /* note: enum_show may use a static buffer, so two
+ * calls in one printf would be a mistake.
+ * enum_name does the same job, without a static buffer,
+ * assuming the name will be found.
+ */
+ loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s not implemented yet"
+ , enum_name(&esp_transformid_names, st->st_esp.attrs.transid)
+ , enum_name(&auth_alg_names, st->st_esp.attrs.auth));
+ goto fail;
+ }
+
+ if (st->st_esp.attrs.transid == ei->transid
+ && st->st_esp.attrs.auth == ei->auth)
+ break;
+ }
+
+ key_len = st->st_esp.attrs.key_len/8;
+ if (key_len) {
+ /* XXX: must change to check valid _range_ key_len */
+ if (key_len > ei->enckeylen) {
+ loglog(RC_LOG_SERIOUS, "ESP transform %s passed key_len=%d > %d",
+ enum_name(&esp_transformid_names, st->st_esp.attrs.transid),
+ (int)key_len, (int)ei->enckeylen);
+ goto fail;
+ }
+ } else {
+ key_len = ei->enckeylen;
+ }
+ /* Grrrrr.... f*cking 7 bits jurassic algos */
+
+ /* 168 bits in kernel, need 192 bits for keymat_len */
+ if (ei->transid == ESP_3DES && key_len == 21)
+ key_len = 24;
+
+ /* 56 bits in kernel, need 64 bits for keymat_len */
+ if (ei->transid == ESP_DES && key_len == 7)
+ key_len = 8;
+
+ /* divide up keying material */
+ /* passert(st->st_esp.keymat_len == ei->enckeylen + ei->authkeylen); */
+ DBG(DBG_KLIPS|DBG_CONTROL|DBG_PARSING,
+ if(st->st_esp.keymat_len != key_len + ei->authkeylen)
+ DBG_log("keymat_len=%d key_len=%d authkeylen=%d",
+ st->st_esp.keymat_len, (int)key_len, (int)ei->authkeylen);
+ );
+ passert(st->st_esp.keymat_len == key_len + ei->authkeylen);
+
+ set_text_said(text_said, &dst.addr, esp_spi, SA_ESP);
+
+ said_next->src = &src.addr;
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
+ said_next->spi = esp_spi;
+ said_next->satype = SADB_SATYPE_ESP;
+ said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM;
+ said_next->authalg = ei->authalg;
+ said_next->authkeylen = ei->authkeylen;
+ /* said_next->authkey = esp_dst_keymat + ei->enckeylen; */
+ said_next->authkey = esp_dst_keymat + key_len;
+ said_next->encalg = ei->encryptalg;
+ /* said_next->enckeylen = ei->enckeylen; */
+ said_next->enckeylen = key_len;
+ said_next->enckey = esp_dst_keymat;
+ said_next->encapsulation = encapsulation;
+ said_next->reqid = c->spd.reqid + 1;
+#ifdef NAT_TRAVERSAL
+ said_next->natt_sport = natt_sport;
+ said_next->natt_dport = natt_dport;
+ said_next->transid = st->st_esp.attrs.transid;
+ said_next->natt_type = natt_type;
+ said_next->natt_oa = &natt_oa;
+#endif
+ said_next->text_said = text_said;
+
+ if (!kernel_ops->add_sa(said_next, replace))
+ goto fail;
+
+ said_next++;
+
+ encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+
+ /* set up AH SA, if any */
+
+ if (st->st_ah.present)
+ {
+ ipsec_spi_t ah_spi = inbound? st->st_ah.our_spi : st->st_ah.attrs.spi;
+ u_char *ah_dst_keymat = inbound? st->st_ah.our_keymat : st->st_ah.peer_keymat;
+
+ unsigned char authalg;
+
+ switch (st->st_ah.attrs.auth)
+ {
+ case AUTH_ALGORITHM_HMAC_MD5:
+ authalg = SADB_AALG_MD5_HMAC;
+ break;
+
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ authalg = SADB_AALG_SHA1_HMAC;
+ break;
+
+ default:
+ loglog(RC_LOG_SERIOUS, "%s not implemented yet"
+ , enum_show(&auth_alg_names, st->st_ah.attrs.auth));
+ goto fail;
+ }
+
+ set_text_said(text_said, &dst.addr, ah_spi, SA_AH);
+
+ said_next->src = &src.addr;
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
+ said_next->spi = ah_spi;
+ said_next->satype = SADB_SATYPE_AH;
+ said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM;
+ said_next->authalg = authalg;
+ said_next->authkeylen = st->st_ah.keymat_len;
+ said_next->authkey = ah_dst_keymat;
+ said_next->encapsulation = encapsulation;
+ said_next->reqid = c->spd.reqid;
+ said_next->text_said = text_said;
+
+ if (!kernel_ops->add_sa(said_next, replace))
+ goto fail;
+
+ said_next++;
+
+ encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+
+ if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ encapsulation = ENCAPSULATION_MODE_TUNNEL;
+ }
+
+ if (kernel_ops->inbound_eroute ? c->spd.eroute_owner == SOS_NOBODY
+ : encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ /* If inbound, and policy does not specifie DISABLEARRIVALCHECK,
+ * tell KLIPS to enforce the IP addresses appropriate for this tunnel.
+ * Note reversed ends.
+ * Not much to be done on failure.
+ */
+ if (inbound && (c->policy & POLICY_DISABLEARRIVALCHECK) == 0)
+ {
+ struct pfkey_proto_info proto_info[4];
+ int i = 0;
+
+ if (st->st_ipcomp.present)
+ {
+ proto_info[i].proto = IPPROTO_COMP;
+ proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation;
+ proto_info[i].reqid = c->spd.reqid + 2;
+ i++;
+ }
+
+ if (st->st_esp.present)
+ {
+ proto_info[i].proto = IPPROTO_ESP;
+ proto_info[i].encapsulation = st->st_esp.attrs.encapsulation;
+ proto_info[i].reqid = c->spd.reqid + 1;
+ i++;
+ }
+
+ if (st->st_ah.present)
+ {
+ proto_info[i].proto = IPPROTO_AH;
+ proto_info[i].encapsulation = st->st_ah.attrs.encapsulation;
+ proto_info[i].reqid = c->spd.reqid;
+ i++;
+ }
+
+ proto_info[i].proto = 0;
+
+ if (kernel_ops->inbound_eroute
+ && encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ proto_info[0].encapsulation = ENCAPSULATION_MODE_TUNNEL;
+ for (i = 1; proto_info[i].proto; i++)
+ {
+ proto_info[i].encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+ }
+
+ /* MCR - should be passed a spd_eroute structure here */
+ (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client
+ , &c->spd.this.host_addr, &c->spd.this.client
+ , inner_spi, proto, satype, c->spd.this.protocol
+ , proto_info, 0
+ , ERO_ADD_INBOUND, "add inbound");
+ }
+ }
+
+ /* If there are multiple SPIs, group them. */
+
+ if (kernel_ops->grp_sa && said_next > &said[1])
+ {
+ struct kernel_sa *s;
+
+ /* group SAs, two at a time, inner to outer (backwards in said[])
+ * The grouping is by pairs. So if said[] contains ah esp ipip,
+ * the grouping would be ipip:esp, esp:ah.
+ */
+ for (s = said; s < said_next-1; s++)
+ {
+ char
+ text_said0[SATOT_BUF],
+ text_said1[SATOT_BUF];
+
+ /* group s[1] and s[0], in that order */
+
+ set_text_said(text_said0, s[0].dst, s[0].spi, s[0].proto);
+ set_text_said(text_said1, s[1].dst, s[1].spi, s[1].proto);
+
+ DBG(DBG_KLIPS, DBG_log("grouping %s and %s", text_said1, text_said0));
+
+ s[0].text_said = text_said0;
+ s[1].text_said = text_said1;
+
+ if (!kernel_ops->grp_sa(s + 1, s))
+ goto fail;
+ }
+ /* could update said, but it will not be used */
+ }
+
+ return TRUE;
+
+fail:
+ {
+ /* undo the done SPIs */
+ while (said_next-- != said)
+ (void) del_spi(said_next->spi, said_next->proto
+ , &src.addr, said_next->dst);
+ return FALSE;
+ }
+}
+
+/* teardown_ipsec_sa is a canibalized version of setup_ipsec_sa */
+
+static bool
+teardown_half_ipsec_sa(struct state *st, bool inbound)
+{
+ /* We need to delete AH, ESP, and IP in IP SPIs.
+ * But if there is more than one, they have been grouped
+ * so deleting any one will do. So we just delete the
+ * first one found. It may or may not be the only one.
+ */
+ struct connection *c = st->st_connection;
+ struct {
+ unsigned proto;
+ struct ipsec_proto_info *info;
+ } protos[4];
+ int i;
+ bool result;
+
+ i = 0;
+ if (kernel_ops->inbound_eroute && inbound
+ && c->spd.eroute_owner == SOS_NOBODY)
+ {
+ (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client
+ , &c->spd.this.host_addr, &c->spd.this.client
+ , 256, IPSEC_PROTO_ANY, SADB_SATYPE_UNSPEC, c->spd.this.protocol
+ , null_proto_info, 0
+ , ERO_DEL_INBOUND, "delete inbound");
+ }
+
+ if (!kernel_ops->grp_sa)
+ {
+ if (st->st_ah.present)
+ {
+ protos[i].info = &st->st_ah;
+ protos[i].proto = SA_AH;
+ i++;
+ }
+
+ if (st->st_esp.present)
+ {
+ protos[i].info = &st->st_esp;
+ protos[i].proto = SA_ESP;
+ i++;
+ }
+
+ if (st->st_ipcomp.present)
+ {
+ protos[i].info = &st->st_ipcomp;
+ protos[i].proto = SA_COMP;
+ i++;
+ }
+ }
+ else if (st->st_ah.present)
+ {
+ protos[i].info = &st->st_ah;
+ protos[i].proto = SA_AH;
+ i++;
+ }
+ else if (st->st_esp.present)
+ {
+ protos[i].info = &st->st_esp;
+ protos[i].proto = SA_ESP;
+ i++;
+ }
+ else
+ {
+ impossible(); /* neither AH nor ESP in outbound SA bundle! */
+ }
+ protos[i].proto = 0;
+
+ result = TRUE;
+ for (i = 0; protos[i].proto; i++)
+ {
+ unsigned proto = protos[i].proto;
+ ipsec_spi_t spi;
+ const ip_address *src, *dst;
+
+ if (inbound)
+ {
+ spi = protos[i].info->our_spi;
+ src = &c->spd.that.host_addr;
+ dst = &c->spd.this.host_addr;
+ }
+ else
+ {
+ spi = protos[i].info->attrs.spi;
+ src = &c->spd.this.host_addr;
+ dst = &c->spd.that.host_addr;
+ }
+
+ result &= del_spi(spi, proto, src, dst);
+ }
+ return result;
+}
+
+/*
+ * get information about a given sa
+ */
+bool
+get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time)
+{
+ char text_said[SATOT_BUF];
+ struct kernel_sa sa;
+ struct connection *c = st->st_connection;
+
+ *use_time = UNDEFINED_TIME;
+
+ if (kernel_ops->get_sa == NULL || !st->st_esp.present)
+ return FALSE;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.proto = SA_ESP;
+
+ if (inbound)
+ {
+ sa.src = &c->spd.that.host_addr;
+ sa.dst = &c->spd.this.host_addr;
+ sa.spi = st->st_esp.our_spi;
+ }
+ else
+ {
+ sa.src = &c->spd.this.host_addr;
+ sa.dst = &c->spd.that.host_addr;
+ sa.spi = st->st_esp.attrs.spi;
+ }
+ set_text_said(text_said, sa.dst, sa.spi, sa.proto);
+
+ sa.text_said = text_said;
+
+ DBG(DBG_KLIPS,
+ DBG_log("get %s", text_said)
+ )
+ if (!kernel_ops->get_sa(&sa, bytes))
+ return FALSE;
+ DBG(DBG_KLIPS,
+ DBG_log(" current: %d bytes", *bytes)
+ )
+
+ if (st->st_serialno == c->spd.eroute_owner)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("get %sbound policy with reqid %u"
+ , inbound? "in":"out", (u_int)c->spd.reqid + 1)
+ )
+ sa.transport_proto = c->spd.this.protocol;
+ sa.encapsulation = st->st_esp.attrs.encapsulation;
+
+ if (inbound)
+ {
+ sa.src_client = &c->spd.that.client;
+ sa.dst_client = &c->spd.this.client;
+ }
+ else
+ {
+ sa.src_client = &c->spd.this.client;
+ sa.dst_client = &c->spd.that.client;
+ }
+ if (!kernel_ops->get_policy(&sa, inbound, use_time))
+ return FALSE;
+ DBG(DBG_KLIPS,
+ DBG_log(" use_time: %s", timetoa(use_time, FALSE))
+ )
+ }
+ return TRUE;
+}
+
+const struct kernel_ops *kernel_ops;
+
+#endif /* KLIPS */
+
+void
+init_kernel(void)
+{
+#ifdef KLIPS
+
+ if (no_klips)
+ {
+ kernel_ops = &noklips_kernel_ops;
+ return;
+ }
+
+ init_pfkey();
+
+ kernel_ops = &klips_kernel_ops;
+
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+ {
+ bool linux_ipsec = 0;
+ struct stat buf;
+
+ linux_ipsec = (stat("/proc/net/pfkey", &buf) == 0);
+ if (linux_ipsec)
+ {
+ plog("Using Linux 2.6 IPsec interface code");
+ kernel_ops = &linux_kernel_ops;
+ }
+ else
+ {
+ plog("Using KLIPS IPsec interface code");
+ }
+ }
+#endif
+
+ if (kernel_ops->init)
+ {
+ kernel_ops->init();
+ }
+
+ /* register SA types that we can negotiate */
+ can_do_IPcomp = FALSE; /* until we get a response from KLIPS */
+ kernel_ops->pfkey_register();
+
+ if (!kernel_ops->policy_lifetime)
+ {
+ event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL);
+ }
+#endif
+}
+
+/* Note: install_inbound_ipsec_sa is only used by the Responder.
+ * The Responder will subsequently use install_ipsec_sa for the outbound.
+ * The Initiator uses install_ipsec_sa to install both at once.
+ */
+bool
+install_inbound_ipsec_sa(struct state *st)
+{
+ struct connection *const c = st->st_connection;
+
+ /* If our peer has a fixed-address client, check if we already
+ * have a route for that client that conflicts. We will take this
+ * as proof that that route and the connections using it are
+ * obsolete and should be eliminated. Interestingly, this is
+ * the only case in which we can tell that a connection is obsolete.
+ */
+ passert(c->kind == CK_PERMANENT || c->kind == CK_INSTANCE);
+ if (c->spd.that.has_client)
+ {
+ for (;;)
+ {
+ struct spd_route *esr;
+ struct connection *o = route_owner(c, &esr, NULL, NULL);
+
+ if (o == NULL)
+ break; /* nobody has a route */
+
+ /* note: we ignore the client addresses at this end */
+ if (sameaddr(&o->spd.that.host_addr, &c->spd.that.host_addr)
+ && o->interface == c->interface)
+ break; /* existing route is compatible */
+
+ if (o->kind == CK_TEMPLATE && streq(o->name, c->name))
+ break; /* ??? is this good enough?? */
+
+ loglog(RC_LOG_SERIOUS, "route to peer's client conflicts with \"%s\" %s; releasing old connection to free the route"
+ , o->name, ip_str(&o->spd.that.host_addr));
+ release_connection(o, FALSE);
+ }
+ }
+
+ DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa() checking if we can route"));
+ /* check that we will be able to route and eroute */
+ switch (could_route(c))
+ {
+ case route_easy:
+ case route_nearconflict:
+ break;
+
+ default:
+ return FALSE;
+ }
+
+#ifdef KLIPS
+ /* (attempt to) actually set up the SAs */
+ return setup_half_ipsec_sa(st, TRUE);
+#else /* !KLIPS */
+ DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa()"));
+ return TRUE;
+#endif /* !KLIPS */
+}
+
+/* Install a route and then a prospective shunt eroute or an SA group eroute.
+ * Assumption: could_route gave a go-ahead.
+ * Any SA Group must have already been created.
+ * On failure, steps will be unwound.
+ */
+bool
+route_and_eroute(struct connection *c USED_BY_KLIPS
+ , struct spd_route *sr USED_BY_KLIPS
+ , struct state *st USED_BY_KLIPS)
+{
+#ifdef KLIPS
+ struct spd_route *esr;
+ struct spd_route *rosr;
+ struct connection *ero /* who, if anyone, owns our eroute? */
+ , *ro = route_owner(c, &rosr, &ero, &esr);
+ bool eroute_installed = FALSE
+ , firewall_notified = FALSE
+ , route_installed = FALSE;
+
+ struct connection *ero_top;
+ struct bare_shunt **bspp;
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("route_and_eroute with c: %s (next: %s) ero:%s esr:{%p} ro:%s rosr:{%p} and state: %lu"
+ , c->name
+ , (c->policy_next ? c->policy_next->name : "none")
+ , ero ? ero->name : "null"
+ , esr
+ , ro ? ro->name : "null"
+ , rosr
+ , st ? st->st_serialno : 0));
+
+ /* look along the chain of policies for one with the same name */
+ ero_top = ero;
+
+#if 0
+ /* XXX - mcr this made sense before, and likely will make sense
+ * again, so I'l leaving this to remind me what is up */
+ if (ero!= NULL && ero->routing == RT_UNROUTED_KEYED)
+ ero = NULL;
+
+ for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next)
+ if ((ero2->kind == CK_TEMPLATE || ero2->kind==CK_SECONDARY)
+ && streq(ero2->name, c->name))
+ break;
+#endif
+
+ bspp = (ero == NULL)
+ ? bare_shunt_ptr(&sr->this.client, &sr->that.client, sr->this.protocol)
+ : NULL;
+
+ /* install the eroute */
+
+ passert(bspp == NULL || ero == NULL); /* only one non-NULL */
+
+ if (bspp != NULL || ero != NULL)
+ {
+ /* We're replacing an eroute */
+
+ /* if no state provided, then install a shunt for later */
+ if (st == NULL)
+ eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE
+ , ERO_REPLACE, "replace");
+ else
+ eroute_installed = sag_eroute(st, sr, ERO_REPLACE, "replace");
+
+#if 0
+ /* XXX - MCR. I previously felt that this was a bogus check */
+ if (ero != NULL && ero != c && esr != sr)
+ {
+ /* By elimination, we must be eclipsing ero. Check. */
+ passert(ero->kind == CK_TEMPLATE && streq(ero->name, c->name));
+ passert(LHAS(LELEM(RT_ROUTED_PROSPECTIVE) | LELEM(RT_ROUTED_ECLIPSED)
+ , esr->routing));
+ passert(samesubnet(&esr->this.client, &sr->this.client)
+ && samesubnet(&esr->that.client, &sr->that.client));
+ }
+#endif
+ /* remember to free bspp iff we make it out of here alive */
+ }
+ else
+ {
+ /* we're adding an eroute */
+
+ /* if no state provided, then install a shunt for later */
+ if (st == NULL)
+ eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE
+ , ERO_ADD, "add");
+ else
+ eroute_installed = sag_eroute(st, sr, ERO_ADD, "add");
+ }
+
+ /* notify the firewall of a new tunnel */
+
+ if (eroute_installed)
+ {
+ /* do we have to notify the firewall? Yes, if we are installing
+ * a tunnel eroute and the firewall wasn't notified
+ * for a previous tunnel with the same clients. Any Previous
+ * tunnel would have to be for our connection, so the actual
+ * test is simple.
+ */
+ firewall_notified = st == NULL /* not a tunnel eroute */
+ || sr->eroute_owner != SOS_NOBODY /* already notified */
+ || do_command(c, sr, "up"); /* go ahead and notify */
+ }
+
+ /* install the route */
+
+ DBG(DBG_CONTROL,
+ DBG_log("route_and_eroute: firewall_notified: %s"
+ , firewall_notified ? "true" : "false"));
+ if (!firewall_notified)
+ {
+ /* we're in trouble -- don't do routing */
+ }
+ else if (ro == NULL)
+ {
+ /* a new route: no deletion required, but preparation is */
+ (void) do_command(c, sr, "prepare"); /* just in case; ignore failure */
+ route_installed = do_command(c, sr, "route");
+ }
+ else if (routed(sr->routing)
+ || routes_agree(ro, c))
+ {
+ route_installed = TRUE; /* nothing to be done */
+ }
+ else
+ {
+ /* Some other connection must own the route
+ * and the route must disagree. But since could_route
+ * must have allowed our stealing it, we'll do so.
+ *
+ * A feature of LINUX allows us to install the new route
+ * before deleting the old if the nexthops differ.
+ * This reduces the "window of vulnerability" when packets
+ * might flow in the clear.
+ */
+ if (sameaddr(&sr->this.host_nexthop, &esr->this.host_nexthop))
+ {
+ (void) do_command(ro, sr, "unroute");
+ route_installed = do_command(c, sr, "route");
+ }
+ else
+ {
+ route_installed = do_command(c, sr, "route");
+ (void) do_command(ro, sr, "unroute");
+ }
+
+ /* record unrouting */
+ if (route_installed)
+ {
+ do {
+ passert(!erouted(rosr->routing));
+ rosr->routing = RT_UNROUTED;
+
+ /* no need to keep old value */
+ ro = route_owner(c, &rosr, NULL, NULL);
+ } while (ro != NULL);
+ }
+ }
+
+ /* all done -- clean up */
+ if (route_installed)
+ {
+ /* Success! */
+
+ if (bspp != NULL)
+ {
+ free_bare_shunt(bspp);
+ }
+ else if (ero != NULL && ero != c)
+ {
+ /* check if ero is an ancestor of c. */
+ struct connection *ero2;
+
+ for (ero2 = c; ero2 != NULL && ero2 != c; ero2 = ero2->policy_next)
+ ;
+
+ if (ero2 == NULL)
+ {
+ /* By elimination, we must be eclipsing ero. Checked above. */
+ if (ero->spd.routing != RT_ROUTED_ECLIPSED)
+ {
+ ero->spd.routing = RT_ROUTED_ECLIPSED;
+ eclipse_count++;
+ }
+ }
+ }
+
+ if (st == NULL)
+ {
+ passert(sr->eroute_owner == SOS_NOBODY);
+ sr->routing = RT_ROUTED_PROSPECTIVE;
+ }
+ else
+ {
+ char cib[CONN_INST_BUF];
+ sr->routing = RT_ROUTED_TUNNEL;
+
+ DBG(DBG_CONTROL,
+ DBG_log("route_and_eroute: instance \"%s\"%s, setting eroute_owner {spd=%p,sr=%p} to #%ld (was #%ld) (newest_ipsec_sa=#%ld)"
+ , st->st_connection->name
+ , (fmt_conn_instance(st->st_connection, cib), cib)
+ , &st->st_connection->spd, sr
+ , st->st_serialno
+ , sr->eroute_owner
+ , st->st_connection->newest_ipsec_sa));
+ sr->eroute_owner = st->st_serialno;
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ /* Failure! Unwind our work. */
+ if (firewall_notified && sr->eroute_owner == SOS_NOBODY)
+ (void) do_command(c, sr, "down");
+
+ if (eroute_installed)
+ {
+ /* Restore original eroute, if we can.
+ * Since there is nothing much to be done if the restoration
+ * fails, ignore success or failure.
+ */
+ if (bspp != NULL)
+ {
+ /* Restore old bare_shunt.
+ * I don't think that this case is very likely.
+ * Normally a bare shunt would have been assigned
+ * to a connection before we've gotten this far.
+ */
+ struct bare_shunt *bs = *bspp;
+
+ (void) raw_eroute(&bs->said.dst /* should be useless */
+ , &bs->ours
+ , &bs->said.dst /* should be useless */
+ , &bs->his
+ , bs->said.spi /* network order */
+ , SA_INT
+ , SADB_X_SATYPE_INT
+ , 0
+ , null_proto_info
+ , SHUNT_PATIENCE
+ , ERO_REPLACE, "restore");
+ }
+ else if (ero != NULL)
+ {
+ /* restore ero's former glory */
+ if (esr->eroute_owner == SOS_NOBODY)
+ {
+ /* note: normal or eclipse case */
+ (void) shunt_eroute(ero, esr
+ , esr->routing, ERO_REPLACE, "restore");
+ }
+ else
+ {
+ /* Try to find state that owned eroute.
+ * Don't do anything if it cannot be found.
+ * This case isn't likely since we don't run
+ * the updown script when replacing a SA group
+ * with its successor (for the same conn).
+ */
+ struct state *ost = state_with_serialno(esr->eroute_owner);
+
+ if (ost != NULL)
+ (void) sag_eroute(ost, esr, ERO_REPLACE, "restore");
+ }
+ }
+ else
+ {
+ /* there was no previous eroute: delete whatever we installed */
+ if (st == NULL)
+ (void) shunt_eroute(c, sr
+ , sr->routing, ERO_DELETE, "delete");
+ else
+ (void) sag_eroute(st, sr
+ , ERO_DELETE, "delete");
+ }
+ }
+
+ return FALSE;
+ }
+#else /* !KLIPS */
+ return TRUE;
+#endif /* !KLIPS */
+}
+
+bool
+install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS)
+{
+#ifdef KLIPS
+ struct spd_route *sr;
+
+ DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() for #%ld: %s"
+ , st->st_serialno
+ , inbound_also?
+ "inbound and outbound" : "outbound only"));
+
+ switch (could_route(st->st_connection))
+ {
+ case route_easy:
+ case route_nearconflict:
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ /* (attempt to) actually set up the SA group */
+ if ((inbound_also && !setup_half_ipsec_sa(st, TRUE))
+ || !setup_half_ipsec_sa(st, FALSE))
+ return FALSE;
+
+ for (sr = &st->st_connection->spd; sr != NULL; sr = sr->next)
+ {
+ DBG(DBG_CONTROL, DBG_log("sr for #%ld: %s"
+ , st->st_serialno
+ , enum_name(&routing_story, sr->routing)));
+
+ /*
+ * if the eroute owner is not us, then make it us.
+ * See test co-terminal-02, pluto-rekey-01, pluto-unit-02/oppo-twice
+ */
+ pexpect(sr->eroute_owner == SOS_NOBODY
+ || sr->routing >= RT_ROUTED_TUNNEL);
+
+ if (sr->eroute_owner != st->st_serialno
+ && sr->routing != RT_UNROUTED_KEYED)
+ {
+ if (!route_and_eroute(st->st_connection, sr, st))
+ {
+ delete_ipsec_sa(st, FALSE);
+ /* XXX go and unroute any SRs that were successfully
+ * routed already.
+ */
+ return FALSE;
+ }
+ }
+ }
+#else /* !KLIPS */
+ DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() %s"
+ , inbound_also? "inbound and oubound" : "outbound only"));
+
+ switch (could_route(st->st_connection))
+ {
+ case route_easy:
+ case route_nearconflict:
+ break;
+
+ default:
+ return FALSE;
+ }
+
+
+#endif /* !KLIPS */
+
+ return TRUE;
+}
+
+/* delete an IPSEC SA.
+ * we may not succeed, but we bull ahead anyway because
+ * we cannot do anything better by recognizing failure
+ */
+void
+delete_ipsec_sa(struct state *st USED_BY_KLIPS, bool inbound_only USED_BY_KLIPS)
+{
+#ifdef KLIPS
+ if (!inbound_only)
+ {
+ /* If the state is the eroute owner, we must adjust
+ * the routing for the connection.
+ */
+ struct connection *c = st->st_connection;
+ struct spd_route *sr;
+
+ passert(st->st_connection);
+
+ for (sr = &c->spd; sr; sr = sr->next)
+ {
+ if (sr->eroute_owner == st->st_serialno
+ && sr->routing == RT_ROUTED_TUNNEL)
+ {
+ sr->eroute_owner = SOS_NOBODY;
+
+ /* Routing should become RT_ROUTED_FAILURE,
+ * but if POLICY_FAIL_NONE, then we just go
+ * right back to RT_ROUTED_PROSPECTIVE as if no
+ * failure happened.
+ */
+ sr->routing = (c->policy & POLICY_FAIL_MASK) == POLICY_FAIL_NONE
+ ? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE;
+
+ (void) do_command(c, sr, "down");
+ if ((c->policy & POLICY_DONT_REKEY)
+ && c->kind == CK_INSTANCE)
+ {
+ /* in this special case, even if the connection
+ * is still alive (due to an ISAKMP SA),
+ * we get rid of routing.
+ * Even though there is still an eroute, the c->routing
+ * setting will convince unroute_connection to delete it.
+ * unroute_connection would be upset if c->routing == RT_ROUTED_TUNNEL
+ */
+ unroute_connection(c);
+ }
+ else
+ {
+ (void) shunt_eroute(c, sr, sr->routing, ERO_REPLACE, "replace with shunt");
+ }
+ }
+ }
+ (void) teardown_half_ipsec_sa(st, FALSE);
+ }
+ (void) teardown_half_ipsec_sa(st, TRUE);
+#else /* !KLIPS */
+ DBG(DBG_CONTROL, DBG_log("if I knew how, I'd eroute() and teardown_ipsec_sa()"));
+#endif /* !KLIPS */
+}
+#ifdef NAT_TRAVERSAL
+#ifdef KLIPS
+static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound)
+{
+ struct connection *c = st->st_connection;
+ char text_said[SATOT_BUF];
+ struct kernel_sa sa;
+ ip_address
+ src = inbound? c->spd.that.host_addr : c->spd.this.host_addr,
+ dst = inbound? c->spd.this.host_addr : c->spd.that.host_addr;
+
+
+ ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi;
+
+ u_int16_t
+ natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port,
+ natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port;
+
+ set_text_said(text_said, &dst, esp_spi, SA_ESP);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.spi = esp_spi;
+ sa.src = &src;
+ sa.dst = &dst;
+ sa.text_said = text_said;
+ sa.authalg = alg_info_esp_aa2sadb(st->st_esp.attrs.auth);
+ sa.natt_sport = natt_sport;
+ sa.natt_dport = natt_dport;
+ sa.transid = st->st_esp.attrs.transid;
+
+ return kernel_ops->add_sa(&sa, TRUE);
+
+}
+#endif
+
+bool update_ipsec_sa (struct state *st USED_BY_KLIPS)
+{
+#ifdef KLIPS
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) {
+ if ((st->st_esp.present) && (
+ (!update_nat_t_ipsec_esp_sa (st, TRUE)) ||
+ (!update_nat_t_ipsec_esp_sa (st, FALSE)))) {
+ return FALSE;
+ }
+ }
+ else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) {
+ if ((st->st_esp.present) && (!update_nat_t_ipsec_esp_sa (st, FALSE))) {
+ return FALSE;
+ }
+ }
+ else {
+ DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__,
+ st->st_state);
+ return FALSE;
+ }
+ return TRUE;
+#else /* !KLIPS */
+ DBG(DBG_CONTROL, DBG_log("if I knew how, I'd update_ipsec_sa()"));
+ return TRUE;
+#endif /* !KLIPS */
+}
+#endif
+
+/* Check if there was traffic on given SA during the last idle_max
+ * seconds. If TRUE, the SA was idle and DPD exchange should be performed.
+ * If FALSE, DPD is not necessary. We also return TRUE for errors, as they
+ * could mean that the SA is broken and needs to be replace anyway.
+ */
+bool
+was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time)
+{
+ static const char procname[] = "/proc/net/ipsec_spi";
+ FILE *f;
+ char buf[1024];
+ u_int bytes;
+ int ret = TRUE;
+
+ passert(st != NULL);
+
+ f = fopen(procname, "r");
+ if (f == NULL)
+ {
+ /* Can't open the file, perhaps were are on 26sec? */
+ time_t use_time;
+
+ if (get_sa_info(st, TRUE, &bytes, &use_time)
+ && use_time != UNDEFINED_TIME)
+ {
+ *idle_time = time(NULL) - use_time;
+ ret = *idle_time >= idle_max;
+ }
+ }
+ else
+ {
+ while (f != NULL)
+ {
+ char *line;
+ char text_said[SATOT_BUF];
+ u_int8_t proto = 0;
+ ip_address dst;
+ ip_said said;
+ ipsec_spi_t spi = 0;
+ static const char idle[] = "idle=";
+
+ dst = st->st_connection->spd.this.host_addr; /* inbound SA */
+ if (st->st_ah.present)
+ {
+ proto = SA_AH;
+ spi = st->st_ah.our_spi;
+ }
+ if (st->st_esp.present)
+ {
+ proto = SA_ESP;
+ spi = st->st_esp.our_spi;
+ }
+
+ if (proto == 0 && spi == 0)
+ {
+ ret = TRUE;
+ break;
+ }
+
+ initsaid(&dst, spi, proto, &said);
+ satot(&said, 'x', text_said, SATOT_BUF);
+
+ line = fgets(buf, sizeof(buf), f);
+ if (line == NULL)
+ {
+ /* Reached end of list */
+ ret = TRUE;
+ break;
+ }
+
+ if (strncmp(line, text_said, strlen(text_said)) == 0)
+ {
+ /* we found a match, now try to find idle= */
+ char *p = strstr(line, idle);
+
+ if (p == NULL)
+ {
+ /* SAs which haven't been used yet don't have it */
+ ret = TRUE; /* it didn't have traffic */
+ break;
+ }
+ p += sizeof(idle)-1;
+ if (*p == '\0')
+ {
+ ret = TRUE; /* be paranoid */
+ break;
+ }
+ if (sscanf(p, "%d", (int *) idle_time) <= 0)
+ {
+ ret = TRUE;
+ break;
+ }
+ if (*idle_time >= idle_max)
+ {
+ ret = TRUE;
+ break;
+ }
+ else
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+ }
+ fclose(f);
+ }
+ return ret;
+}
diff --git a/programs/pluto/kernel.h b/programs/pluto/kernel.h
new file mode 100644
index 000000000..c01ff31f9
--- /dev/null
+++ b/programs/pluto/kernel.h
@@ -0,0 +1,200 @@
+/* declarations of routines that interface with the kernel's IPsec mechanism
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: kernel.h,v 1.10 2006/03/08 22:12:37 as Exp $
+ */
+
+#include "connections.h"
+
+extern bool no_klips; /* don't actually use KLIPS */
+extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */
+
+#ifdef KLIPS
+/* Declare eroute things early enough for uses.
+ *
+ * Flags are encoded above the low-order byte of verbs.
+ * "real" eroutes are only outbound. Inbound eroutes don't exist,
+ * but an addflow with an INBOUND flag allows IPIP tunnels to be
+ * limited to appropriate source and destination addresses.
+ */
+
+#define ERO_MASK 0xFF
+#define ERO_FLAG_SHIFT 8
+
+#define ERO_DELETE SADB_X_DELFLOW
+#define ERO_ADD SADB_X_ADDFLOW
+#define ERO_REPLACE (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT))
+#define ERO_ADD_INBOUND (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
+#define ERO_DEL_INBOUND (SADB_X_DELFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
+
+struct pfkey_proto_info {
+ int proto;
+ int encapsulation;
+ unsigned reqid;
+};
+struct sadb_msg;
+
+struct kernel_sa {
+ const ip_address *src;
+ const ip_address *dst;
+
+ const ip_subnet *src_client;
+ const ip_subnet *dst_client;
+
+ ipsec_spi_t spi;
+ unsigned proto;
+ unsigned satype;
+ unsigned transport_proto;
+ unsigned replay_window;
+ unsigned reqid;
+
+ unsigned authalg;
+ unsigned authkeylen;
+ char *authkey;
+
+ unsigned encalg;
+ unsigned enckeylen;
+ char *enckey;
+
+ unsigned compalg;
+
+ int encapsulation;
+#ifdef NAT_TRAVERSAL
+ u_int16_t natt_sport, natt_dport;
+ u_int8_t transid, natt_type;
+ ip_address *natt_oa;
+#endif
+ const char *text_said;
+};
+
+struct kernel_ops {
+ enum {
+ KERNEL_TYPE_NONE,
+ KERNEL_TYPE_KLIPS,
+ KERNEL_TYPE_LINUX,
+ } type;
+ bool inbound_eroute;
+ bool policy_lifetime;
+ int *async_fdp;
+
+ void (*init)(void);
+ void (*pfkey_register)(void);
+ void (*pfkey_register_response)(const struct sadb_msg *msg);
+ void (*process_queue)(void);
+ void (*process_msg)(void);
+ bool (*raw_eroute)(const ip_address *this_host,
+ const ip_subnet *this_client,
+ const ip_address *that_host,
+ const ip_subnet *that_client,
+ ipsec_spi_t spi,
+ unsigned int satype,
+ unsigned int transport_proto,
+ const struct pfkey_proto_info *proto_info,
+ time_t use_lifetime,
+ unsigned int op,
+ const char *text_said);
+ bool (*get_policy)(const struct kernel_sa *sa, bool inbound,
+ time_t *use_time);
+ bool (*add_sa)(const struct kernel_sa *sa, bool replace);
+ bool (*grp_sa)(const struct kernel_sa *sa_outer,
+ const struct kernel_sa *sa_inner);
+ bool (*del_sa)(const struct kernel_sa *sa);
+ bool (*get_sa)(const struct kernel_sa *sa, u_int *bytes);
+ ipsec_spi_t (*get_spi)(const ip_address *src,
+ const ip_address *dst,
+ int proto,
+ bool tunnel_mode,
+ unsigned reqid,
+ ipsec_spi_t min,
+ ipsec_spi_t max,
+ const char *text_said);
+};
+
+
+extern const struct kernel_ops *kernel_ops;
+
+/* information from /proc/net/ipsec_eroute */
+
+struct eroute_info {
+ unsigned long count;
+ ip_subnet ours;
+ ip_subnet his;
+ ip_address dst;
+ ip_said said;
+ int transport_proto;
+ struct eroute_info *next;
+};
+
+extern struct eroute_info *orphaned_holds;
+
+extern void show_shunt_status(void);
+#endif
+
+/* A netlink header defines EM_MAXRELSPIS, the max number of SAs in a group.
+ * Is there a PF_KEY equivalent?
+ */
+#ifndef EM_MAXRELSPIS
+# define EM_MAXRELSPIS 4 /* AH ESP IPCOMP IPIP */
+#endif
+
+extern void record_and_initiate_opportunistic(const ip_subnet *
+ , const ip_subnet *
+ , int transport_proto
+ , const char *why);
+
+extern void init_kernel(void);
+
+extern void scan_proc_shunts(void);
+
+extern bool trap_connection(struct connection *c);
+extern void unroute_connection(struct connection *c);
+
+extern bool has_bare_hold(const ip_address *src, const ip_address *dst
+ , int transport_proto);
+
+extern bool replace_bare_shunt(const ip_address *src, const ip_address *dst
+ , policy_prio_t policy_prio
+ , ipsec_spi_t shunt_spi /* in host order! */
+ , bool repl
+ , unsigned int transport_proto
+ , const char *why);
+
+extern bool assign_hold(struct connection *c
+ , struct spd_route *sr
+ , int transport_proto
+ , const ip_address *src, const ip_address *dst);
+
+extern ipsec_spi_t shunt_policy_spi(struct connection *c, bool prospective);
+
+
+struct state; /* forward declaration of tag */
+extern ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid
+ , int proto
+ , struct spd_route *sr
+ , bool tunnel_mode);
+extern ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel_mode);
+
+extern bool install_inbound_ipsec_sa(struct state *st);
+extern bool install_ipsec_sa(struct state *st, bool inbound_also);
+extern void delete_ipsec_sa(struct state *st, bool inbound_only);
+extern bool route_and_eroute(struct connection *c
+ , struct spd_route *sr
+ , struct state *st);
+extern bool was_eroute_idle(struct state *st, time_t idle_max
+ , time_t *idle_time);
+extern bool get_sa_info(struct state *st, bool inbound, u_int *bytes
+ , time_t *use_time);
+
+#ifdef NAT_TRAVERSAL
+extern bool update_ipsec_sa(struct state *st);
+#endif
diff --git a/programs/pluto/kernel_alg.c b/programs/pluto/kernel_alg.c
new file mode 100644
index 000000000..920a879d7
--- /dev/null
+++ b/programs/pluto/kernel_alg.c
@@ -0,0 +1,775 @@
+/* Kernel runtime algorithm handling interface
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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: kernel_alg.c,v 1.9 2005/08/17 16:31:24 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "connections.h"
+#include "state.h"
+#include "packet.h"
+#include "spdb.h"
+#include "kernel.h"
+#include "kernel_alg.h"
+#include "alg_info.h"
+
+#ifndef NO_PLUTO
+#include "log.h"
+#include "whack.h"
+#include "db_ops.h"
+#else
+/*
+ * macros/functions for compilation without pluto (eg: spi for manual conns)
+ */
+extern int debug;
+#include <assert.h>
+#define passert(x) assert(x)
+#define DBG(cond, action) { if (debug) { action ; } }
+#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
+#define plog(x, args...) fprintf(stderr, x "\n" , ##args);
+#endif /* NO_PLUTO */
+/* ALG storage */
+static struct sadb_alg esp_aalg[SADB_AALG_MAX+1];
+static struct sadb_alg esp_ealg[SADB_EALG_MAX+1];
+static int esp_ealg_num = 0;
+static int esp_aalg_num = 0;
+
+#define ESP_EALG_PRESENT(algo) (((algo)<=SADB_EALG_MAX)&&(esp_ealg[(algo)].sadb_alg_id==(algo)))
+#define ESP_EALG_FOR_EACH_UPDOWN(algo) \
+ for (algo=SADB_EALG_MAX; algo >0 ; algo--) \
+ if (ESP_EALG_PRESENT(algo))
+#define ESP_AALG_PRESENT(algo) ((algo<=SADB_AALG_MAX)&&(esp_aalg[(algo)].sadb_alg_id==(algo)))
+#define ESP_AALG_FOR_EACH_UPDOWN(algo) \
+ for (algo=SADB_AALG_MAX; algo >0 ; algo--) \
+ if (ESP_AALG_PRESENT(algo))
+
+static struct sadb_alg*
+sadb_alg_ptr (int satype, int exttype, int alg_id, int rw)
+{
+ struct sadb_alg *alg_p = NULL;
+
+ switch (exttype)
+ {
+ case SADB_EXT_SUPPORTED_AUTH:
+ if (alg_id > SADB_AALG_MAX)
+ return NULL;
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ if (alg_id > SADB_EALG_MAX)
+ return NULL;
+ break;
+ default:
+ return NULL;
+ }
+
+ switch (satype)
+ {
+ case SADB_SATYPE_ESP:
+ alg_p = (exttype == SADB_EXT_SUPPORTED_ENCRYPT)?
+ &esp_ealg[alg_id] : &esp_aalg[alg_id];
+ /* get for write: increment elem count */
+ if (rw)
+ {
+ (exttype == SADB_EXT_SUPPORTED_ENCRYPT)?
+ esp_ealg_num++ : esp_aalg_num++;
+ }
+ break;
+ case SADB_SATYPE_AH:
+ default:
+ return NULL;
+ }
+
+ return alg_p;
+}
+
+const struct sadb_alg *
+kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id)
+{
+ return sadb_alg_ptr(satype, exttype, alg_id, 0);
+}
+
+/*
+ * Forget previous registration
+ */
+static void
+kernel_alg_init(void)
+{
+ DBG(DBG_KLIPS,
+ DBG_log("alg_init(): memset(%p, 0, %d) memset(%p, 0, %d)",
+ &esp_aalg, (int)sizeof (esp_aalg),
+ &esp_ealg, (int)sizeof (esp_ealg))
+ )
+ memset (&esp_aalg, 0, sizeof (esp_aalg));
+ memset (&esp_ealg, 0, sizeof (esp_ealg));
+ esp_ealg_num=esp_aalg_num = 0;
+}
+
+static int
+kernel_alg_add(int satype, int exttype, const struct sadb_alg *sadb_alg)
+{
+ struct sadb_alg *alg_p = NULL;
+ int alg_id = sadb_alg->sadb_alg_id;
+
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_add(): satype=%d, exttype=%d, alg_id=%d",
+ satype, exttype, sadb_alg->sadb_alg_id)
+ )
+ if (!(alg_p = sadb_alg_ptr(satype, exttype, alg_id, 1)))
+ return -1;
+
+ /* This logic "mimics" KLIPS: first algo implementation will be used */
+ if (alg_p->sadb_alg_id)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_add(): discarding already setup "
+ "satype=%d, exttype=%d, alg_id=%d",
+ satype, exttype, sadb_alg->sadb_alg_id)
+ )
+ return 0;
+ }
+ *alg_p = *sadb_alg;
+ return 1;
+}
+
+bool
+kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len,
+ struct alg_info_esp *alg_info __attribute__((unused)))
+{
+ struct sadb_alg *alg_p = NULL;
+
+ /*
+ * test #1: encrypt algo must be present
+ */
+ int ret = ESP_EALG_PRESENT(alg_id);
+ if (!ret) goto out;
+
+ alg_p = &esp_ealg[alg_id];
+
+ /*
+ * test #2: if key_len specified, it must be in range
+ */
+ if (key_len
+ && (key_len < alg_p->sadb_alg_minbits || key_len > alg_p->sadb_alg_maxbits))
+ {
+ plog("kernel_alg_db_add() key_len not in range: alg_id=%d, "
+ "key_len=%d, alg_minbits=%d, alg_maxbits=%d"
+ , alg_id, key_len
+ , alg_p->sadb_alg_minbits
+ , alg_p->sadb_alg_maxbits);
+ ret = FALSE;
+ }
+
+out:
+ if (ret)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_esp_enc_ok(%d,%d): "
+ "alg_id=%d, "
+ "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
+ "res=%d, ret=%d"
+ , alg_id, key_len
+ , alg_p->sadb_alg_id
+ , alg_p->sadb_alg_ivlen
+ , alg_p->sadb_alg_minbits
+ , alg_p->sadb_alg_maxbits
+ , alg_p->sadb_alg_reserved
+ , ret);
+ )
+ }
+ else
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO", alg_id, key_len);
+ )
+ }
+ return ret;
+}
+
+/*
+ * ML: make F_STRICT logic consider enc,auth algorithms
+ */
+#ifndef NO_PLUTO
+bool
+kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info)
+{
+ int ealg_insecure;
+
+ /*
+ * key_len passed comes from esp_attrs read from peer
+ * For many older algoritms (eg 3DES) this key_len is fixed
+ * and get passed as 0.
+ * ... then get default key_len
+ */
+ if (key_len == 0)
+ key_len = kernel_alg_esp_enc_keylen(ealg) * BITS_PER_BYTE;
+
+ /*
+ * simple test to toss low key_len, will accept it only
+ * if specified in "esp" string
+ */
+ ealg_insecure = (key_len < 128) ;
+
+ if (ealg_insecure
+ || (alg_info && alg_info->alg_info_flags & ALG_INFO_F_STRICT))
+ {
+ int i;
+ struct esp_info *esp_info;
+
+ if (alg_info)
+ {
+ ALG_INFO_ESP_FOREACH(alg_info, esp_info, i)
+ {
+ if (esp_info->esp_ealg_id == ealg
+ && (esp_info->esp_ealg_keylen == 0 || key_len == 0
+ || esp_info->esp_ealg_keylen == key_len)
+ && esp_info->esp_aalg_id == aalg)
+ {
+ if (ealg_insecure)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "You should NOT use insecure ESP algorithms [%s (%d)]!"
+ , enum_name(&esp_transformid_names, ealg), key_len);
+ }
+ return TRUE;
+ }
+ }
+ }
+ plog("IPSec Transform [%s (%d), %s] refused due to %s",
+ enum_name(&esp_transformid_names, ealg), key_len,
+ enum_name(&auth_alg_names, aalg),
+ ealg_insecure ? "insecure key_len and enc. alg. not listed in \"esp\" string" : "strict flag");
+ return FALSE;
+ }
+ return TRUE;
+}
+#endif /* NO_PLUTO */
+
+/*
+ * Load kernel_alg arrays from /proc
+ * used in manual mode from klips/utils/spi.c
+ */
+int
+kernel_alg_proc_read(void)
+{
+ int satype;
+ int supp_exttype;
+ int alg_id, ivlen, minbits, maxbits;
+ struct sadb_alg sadb_alg;
+ int ret;
+ char buf[128];
+
+ FILE *fp=fopen("/proc/net/pf_key_supported", "r");
+
+ if (!fp)
+ return -1;
+
+ kernel_alg_init();
+
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ if (buf[0] != ' ') /* skip titles */
+ continue;
+
+ sscanf(buf, "%d %d %d %d %d %d"
+ ,&satype, &supp_exttype
+ , &alg_id, &ivlen
+ , &minbits, &maxbits);
+
+ switch (satype)
+ {
+ case SADB_SATYPE_ESP:
+ switch(supp_exttype)
+ {
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ sadb_alg.sadb_alg_id = alg_id;
+ sadb_alg.sadb_alg_ivlen = ivlen;
+ sadb_alg.sadb_alg_minbits = minbits;
+ sadb_alg.sadb_alg_maxbits = maxbits;
+ ret = kernel_alg_add(satype, supp_exttype, &sadb_alg);
+ DBG(DBG_CRYPT,
+ DBG_log("kernel_alg_proc_read() alg_id=%d, "
+ "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
+ "ret=%d"
+ , sadb_alg.sadb_alg_id
+ , sadb_alg.sadb_alg_ivlen
+ , sadb_alg.sadb_alg_minbits
+ , sadb_alg.sadb_alg_maxbits
+ , ret)
+ )
+ }
+ default:
+ continue;
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
+/*
+ * Load kernel_alg arrays pluto's SADB_REGISTER
+ * user by pluto/kernel.c
+ */
+
+void
+kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen)
+{
+ /* Trick: one 'type-mangle-able' pointer to ease offset/assign */
+ union {
+ const struct sadb_msg *msg;
+ const struct sadb_supported *supported;
+ const struct sadb_ext *ext;
+ const struct sadb_alg *alg;
+ const char *ch;
+ } sadb;
+
+ int satype;
+ int msglen;
+ int i = 0;
+
+ /* Initialize alg arrays */
+ kernel_alg_init();
+ satype = msg_buf->sadb_msg_satype;
+ sadb.msg = msg_buf;
+ msglen = sadb.msg->sadb_msg_len*IPSEC_PFKEYv2_ALIGN;
+ msglen -= sizeof(struct sadb_msg);
+ buflen -= sizeof(struct sadb_msg);
+ passert(buflen > 0);
+
+ sadb.msg++;
+
+ while(msglen)
+ {
+ int supp_exttype = sadb.supported->sadb_supported_exttype;
+ int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN;
+
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
+ "sadb_msg_len=%d sadb_supported_len=%d"
+ , satype==SADB_SATYPE_ESP? "ESP" : "AH"
+ , msg_buf->sadb_msg_len, supp_len)
+ )
+ sadb.supported++;
+ msglen -= supp_len;
+ buflen -= supp_len;
+ passert(buflen >= 0);
+
+ for (supp_len -= sizeof(struct sadb_supported);
+ supp_len;
+ supp_len -= sizeof(struct sadb_alg), sadb.alg++,i++)
+ {
+ int ret = kernel_alg_add(satype, supp_exttype, sadb.alg);
+
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
+ "alg[%d], exttype=%d, satype=%d, alg_id=%d, "
+ "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
+ "res=%d, ret=%d"
+ , satype==SADB_SATYPE_ESP? "ESP" : "AH"
+ , i
+ , supp_exttype
+ , satype
+ , sadb.alg->sadb_alg_id
+ , sadb.alg->sadb_alg_ivlen
+ , sadb.alg->sadb_alg_minbits
+ , sadb.alg->sadb_alg_maxbits
+ , sadb.alg->sadb_alg_reserved
+ , ret)
+ )
+ }
+ }
+}
+
+u_int
+kernel_alg_esp_enc_keylen(u_int alg_id)
+{
+ u_int keylen = 0;
+
+ if (!ESP_EALG_PRESENT(alg_id))
+ goto none;
+
+ keylen = esp_ealg[alg_id].sadb_alg_maxbits/BITS_PER_BYTE;
+
+ switch (alg_id)
+ {
+ /*
+ * this is veryUgly[TM]
+ * Peer should have sent KEY_LENGTH attribute for ESP_AES
+ * but if not do force it to 128 instead of using sadb_alg_maxbits
+ * from kernel.
+ */
+ case ESP_AES:
+ keylen = 128/BITS_PER_BYTE;
+ break;
+ }
+
+none:
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_esp_enc_keylen():"
+ "alg_id=%d, keylen=%d",
+ alg_id, keylen)
+ )
+ return keylen;
+}
+
+struct sadb_alg *
+kernel_alg_esp_sadb_alg(u_int alg_id)
+{
+ struct sadb_alg *sadb_alg = (ESP_EALG_PRESENT(alg_id))
+ ? &esp_ealg[alg_id] : NULL;
+
+ DBG(DBG_KLIPS,
+ DBG_log("kernel_alg_esp_sadb_alg(): alg_id=%d, sadb_alg=%p"
+ , alg_id, sadb_alg)
+ )
+ return sadb_alg;
+}
+
+#ifndef NO_PLUTO
+void kernel_alg_list(void)
+{
+ u_int sadb_id;
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered ESP Encryption Algorithms:");
+ whack_log(RC_COMMENT, " ");
+
+ for (sadb_id = 1; sadb_id <= SADB_EALG_MAX; sadb_id++)
+ {
+ if (ESP_EALG_PRESENT(sadb_id))
+ {
+ struct sadb_alg *alg_p = &esp_ealg[sadb_id];
+
+ whack_log(RC_COMMENT, "#%-5d %s, blocksize: %d, keylen: %d-%d"
+ , sadb_id
+ , enum_name(&esp_transformid_names, sadb_id)
+ , alg_p->sadb_alg_ivlen
+ , alg_p->sadb_alg_minbits
+ , alg_p->sadb_alg_maxbits
+ );
+ }
+ }
+
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of registered ESP Authentication Algorithms:");
+ whack_log(RC_COMMENT, " ");
+
+ for (sadb_id = 1; sadb_id <= SADB_AALG_MAX; sadb_id++)
+ {
+ if (ESP_AALG_PRESENT(sadb_id))
+ {
+ u_int aaid = alg_info_esp_sadb2aa(sadb_id);
+ struct sadb_alg *alg_p = &esp_aalg[sadb_id];
+
+ whack_log(RC_COMMENT, "#%-5d %s, keylen: %d-%d"
+ , aaid
+ , enum_name(&auth_alg_names, aaid)
+ , alg_p->sadb_alg_minbits
+ , alg_p->sadb_alg_maxbits
+ );
+ }
+ }
+}
+
+void
+kernel_alg_show_connection(struct connection *c, const char *instance)
+{
+ char buf[256];
+ struct state *st;
+
+ if (c->alg_info_esp)
+ {
+ alg_info_snprint(buf, sizeof(buf), (struct alg_info *)c->alg_info_esp);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: ESP algorithms wanted: %s"
+ , c->name
+ , instance
+ , buf);
+ }
+ if (c->alg_info_esp)
+ {
+ alg_info_snprint_esp(buf, sizeof(buf), c->alg_info_esp);
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: ESP algorithms loaded: %s"
+ , c->name
+ , instance
+ , buf);
+ }
+ st = state_with_serialno(c->newest_ipsec_sa);
+ if (st && st->st_esp.present)
+ whack_log(RC_COMMENT
+ , "\"%s\"%s: ESP algorithm newest: %s_%d-%s; pfsgroup=%s"
+ , c->name
+ , instance
+ , enum_show(&esp_transformid_names, st->st_esp.attrs.transid)
+ +4 /* strlen("ESP_") */
+ , st->st_esp.attrs.key_len
+ , enum_show(&auth_alg_names, st->st_esp.attrs.auth)+
+ +15 /* strlen("AUTH_ALGORITHM_") */
+ , c->policy & POLICY_PFS ?
+ c->alg_info_esp->esp_pfsgroup ?
+ enum_show(&oakley_group_names,
+ c->alg_info_esp->esp_pfsgroup)
+ +13 /*strlen("OAKLEY_GROUP_")*/
+ : "<Phase1>"
+ : "<N/A>"
+ );
+}
+#endif /* NO_PLUTO */
+
+bool
+kernel_alg_esp_auth_ok(u_int auth,
+ struct alg_info_esp *alg_info __attribute__((unused)))
+{
+ return ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth));
+}
+
+u_int
+kernel_alg_esp_auth_keylen(u_int auth)
+{
+ u_int sadb_aalg = alg_info_esp_aa2sadb(auth);
+
+ u_int a_keylen = (sadb_aalg)
+ ? esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE
+ : 0;
+
+ DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING,
+ DBG_log("kernel_alg_esp_auth_keylen(auth=%d, sadb_aalg=%d): "
+ "a_keylen=%d", auth, sadb_aalg, a_keylen)
+ )
+ return a_keylen;
+}
+
+struct esp_info *
+kernel_alg_esp_info(int transid, int auth)
+{
+ int sadb_aalg, sadb_ealg;
+ static struct esp_info ei_buf;
+
+ sadb_ealg = transid;
+ sadb_aalg = alg_info_esp_aa2sadb(auth);
+
+ if (!ESP_EALG_PRESENT(sadb_ealg))
+ goto none;
+ if (!ESP_AALG_PRESENT(sadb_aalg))
+ goto none;
+
+ memset(&ei_buf, 0, sizeof (ei_buf));
+ ei_buf.transid = transid;
+ ei_buf.auth = auth;
+
+ /* don't return "default" keylen because this value is used from
+ * setup_half_ipsec_sa() to "validate" keylen
+ * In effect, enckeylen will be used as "max" value
+ */
+ ei_buf.enckeylen = esp_ealg[sadb_ealg].sadb_alg_maxbits/BITS_PER_BYTE;
+ ei_buf.authkeylen = esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE;
+ ei_buf.encryptalg = sadb_ealg;
+ ei_buf.authalg = sadb_aalg;
+
+ DBG(DBG_PARSING,
+ DBG_log("kernel_alg_esp_info():"
+ "transid=%d, auth=%d, ei=%p, "
+ "enckeylen=%d, authkeylen=%d, encryptalg=%d, authalg=%d",
+ transid, auth, &ei_buf,
+ (int)ei_buf.enckeylen, (int)ei_buf.authkeylen,
+ ei_buf.encryptalg, ei_buf.authalg)
+ )
+ return &ei_buf;
+
+none:
+ DBG(DBG_PARSING,
+ DBG_log("kernel_alg_esp_info():"
+ "transid=%d, auth=%d, ei=NULL",
+ transid, auth)
+ )
+ return NULL;
+}
+
+#ifndef NO_PLUTO
+static void
+kernel_alg_policy_algorithms(struct esp_info *esp_info)
+{
+ u_int ealg_id = esp_info->esp_ealg_id;
+
+ switch(ealg_id)
+ {
+ case 0:
+ case ESP_DES:
+ case ESP_3DES:
+ case ESP_NULL:
+ case ESP_CAST:
+ break;
+ default:
+ if (!esp_info->esp_ealg_keylen)
+ {
+ /* algos that need KEY_LENGTH
+ *
+ * Note: this is a very dirty hack ;-)
+ * Idea: Add a key_length_needed attribute to
+ * esp_ealg ??
+ */
+ esp_info->esp_ealg_keylen = esp_ealg[ealg_id].sadb_alg_maxbits;
+ }
+ }
+}
+
+static bool
+kernel_alg_db_add(struct db_context *db_ctx, struct esp_info *esp_info, lset_t policy)
+{
+ u_int ealg_id, aalg_id;
+
+ ealg_id = esp_info->esp_ealg_id;
+
+ if (!ESP_EALG_PRESENT(ealg_id))
+ {
+ DBG_log("kernel_alg_db_add() kernel enc ealg_id=%d not present", ealg_id);
+ return FALSE;
+ }
+
+ if (!(policy & POLICY_AUTHENTICATE)) /* skip ESP auth attrs for AH */
+ {
+ aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id);
+
+ if (!ESP_AALG_PRESENT(aalg_id))
+ {
+ DBG_log("kernel_alg_db_add() kernel auth "
+ "aalg_id=%d not present", aalg_id);
+ return FALSE;
+ }
+ }
+
+ /* do algo policy */
+ kernel_alg_policy_algorithms(esp_info);
+
+ /* open new transformation */
+ db_trans_add(db_ctx, ealg_id);
+
+ /* add ESP auth attr */
+ if (!(policy & POLICY_AUTHENTICATE))
+ db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id);
+
+ /* add keylegth if specified in esp= string */
+ if (esp_info->esp_ealg_keylen)
+ db_attr_add_values(db_ctx, KEY_LENGTH, esp_info->esp_ealg_keylen);
+
+ return TRUE;
+}
+
+/*
+ * Create proposal with runtime kernel algos, merging
+ * with passed proposal if not NULL
+ *
+ * for now this function does free() previous returned
+ * malloced pointer (this quirk allows easier spdb.c change)
+ */
+struct db_context *
+kernel_alg_db_new(struct alg_info_esp *alg_info, lset_t policy )
+{
+ const struct esp_info *esp_info;
+ struct esp_info tmp_esp_info;
+ struct db_context *ctx_new=NULL;
+ struct db_trans *t;
+ struct db_prop *prop;
+ u_int trans_cnt;
+ int tn = 0;
+
+ if (!(policy & POLICY_ENCRYPT)) /* not possible, I think */
+ return NULL;
+
+ trans_cnt = esp_ealg_num * esp_aalg_num;
+ DBG(DBG_EMITTING,
+ DBG_log("kernel_alg_db_prop_new() initial trans_cnt=%d"
+ , trans_cnt)
+ )
+
+ /* pass aprox. number of transforms and attributes */
+ ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2);
+
+ /*
+ * Loop: for each element (struct esp_info) of alg_info,
+ * if kernel support is present then build the transform (and attrs)
+ * if NULL alg_info, propose everything ...
+ */
+
+ if (alg_info)
+ {
+ int i;
+
+ ALG_INFO_ESP_FOREACH(alg_info, esp_info, i)
+ {
+ tmp_esp_info = *esp_info;
+ kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
+ }
+ }
+ else
+ {
+ u_int ealg_id;
+
+ ESP_EALG_FOR_EACH_UPDOWN(ealg_id)
+ {
+ u_int aalg_id;
+
+ tmp_esp_info.esp_ealg_id = ealg_id;
+ tmp_esp_info.esp_ealg_keylen = 0;
+
+ for (aalg_id = 1; aalg_id <= SADB_AALG_MAX; aalg_id++)
+ {
+ if (ESP_AALG_PRESENT(aalg_id))
+ {
+ tmp_esp_info.esp_aalg_id = alg_info_esp_sadb2aa(aalg_id);
+ tmp_esp_info.esp_aalg_keylen = 0;
+ kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
+ }
+ }
+ }
+ }
+
+ prop = db_prop_get(ctx_new);
+
+ DBG(DBG_CONTROL|DBG_EMITTING,
+ DBG_log("kernel_alg_db_prop_new() "
+ "will return p_new->protoid=%d, p_new->trans_cnt=%d"
+ , prop->protoid, prop->trans_cnt)
+ )
+
+ for (t = prop->trans, tn = 0; tn < prop->trans_cnt; tn++)
+ {
+ DBG(DBG_CONTROL|DBG_EMITTING,
+ DBG_log("kernel_alg_db_prop_new() "
+ " trans[%d]: transid=%d, attr_cnt=%d, "
+ "attrs[0].type=%d, attrs[0].val=%d"
+ , tn
+ , t[tn].transid, t[tn].attr_cnt
+ , t[tn].attrs[0].type, t[tn].attrs[0].val)
+ )
+ }
+ return ctx_new;
+}
+#endif /* NO_PLUTO */
diff --git a/programs/pluto/kernel_alg.h b/programs/pluto/kernel_alg.h
new file mode 100644
index 000000000..483e97da1
--- /dev/null
+++ b/programs/pluto/kernel_alg.h
@@ -0,0 +1,46 @@
+/* Kernel runtime algorithm handling interface definitions
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * 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: kernel_alg.h,v 1.5 2005/08/17 16:31:24 as Exp $
+ */
+
+#ifndef _KERNEL_ALG_H
+#define _KERNEL_ALG_H
+
+#include "alg_info.h"
+#include "spdb.h"
+
+/* status info */
+extern void kernel_alg_show_status(void);
+void kernel_alg_show_connection(struct connection *c, const char *instance);
+
+/* Registration messages from pluto */
+extern void kernel_alg_register_pfkey(const struct sadb_msg *msg, int buflen);
+
+/* ESP interface */
+extern struct sadb_alg *kernel_alg_esp_sadb_alg(u_int alg_id);
+extern u_int kernel_alg_esp_ivlen(u_int alg_id);
+extern bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, struct alg_info_esp *nfo);
+extern bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info);
+extern u_int kernel_alg_esp_enc_keylen(u_int alg_id);
+extern bool kernel_alg_esp_auth_ok(u_int auth, struct alg_info_esp *nfo);
+extern u_int kernel_alg_esp_auth_keylen(u_int auth);
+extern int kernel_alg_proc_read(void);
+extern void kernel_alg_list(void);
+
+/* get sadb_alg for passed args */
+extern const struct sadb_alg * kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id);
+
+extern struct db_context * kernel_alg_db_new(struct alg_info_esp *ai, lset_t policy);
+struct esp_info * kernel_alg_esp_info(int esp_id, int auth_id);
+#endif /* _KERNEL_ALG_H */
diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
new file mode 100644
index 000000000..fd43c4653
--- /dev/null
+++ b/programs/pluto/kernel_netlink.c
@@ -0,0 +1,1221 @@
+/* netlink interface to the kernel's IPsec mechanism
+ * Copyright (C) 2003 Herbert Xu.
+ *
+ * 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: kernel_netlink.c,v 1.24 2006/03/10 14:49:43 as Exp $
+ */
+
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <unistd.h>
+
+#include "kameipsec.h"
+#include "linux26/rtnetlink.h"
+#include "linux26/xfrm.h"
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "kernel.h"
+#include "kernel_netlink.h"
+#include "kernel_pfkey.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#include "kernel_alg.h"
+
+/* Minimum priority number in SPD used by pluto. */
+#define MIN_SPD_PRIORITY 1024
+
+static int netlinkfd = NULL_FD;
+static int netlink_bcast_fd = NULL_FD;
+
+#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */
+
+static sparse_names xfrm_type_names = {
+ NE(NLMSG_NOOP),
+ NE(NLMSG_ERROR),
+ NE(NLMSG_DONE),
+ NE(NLMSG_OVERRUN),
+
+ NE(XFRM_MSG_NEWSA),
+ NE(XFRM_MSG_DELSA),
+ NE(XFRM_MSG_GETSA),
+
+ NE(XFRM_MSG_NEWPOLICY),
+ NE(XFRM_MSG_DELPOLICY),
+ NE(XFRM_MSG_GETPOLICY),
+
+ NE(XFRM_MSG_ALLOCSPI),
+ NE(XFRM_MSG_ACQUIRE),
+ NE(XFRM_MSG_EXPIRE),
+
+ NE(XFRM_MSG_UPDPOLICY),
+ NE(XFRM_MSG_UPDSA),
+
+ NE(XFRM_MSG_POLEXPIRE),
+
+ NE(XFRM_MSG_MAX),
+
+ { 0, sparse_end }
+};
+
+#undef NE
+
+/* Authentication algorithms */
+static sparse_names aalg_list = {
+ { SADB_X_AALG_NULL, "digest_null" },
+ { SADB_AALG_MD5_HMAC, "md5" },
+ { SADB_AALG_SHA1_HMAC, "sha1" },
+ { SADB_AALG_SHA2_256_HMAC, "sha256" },
+ { SADB_AALG_SHA2_384_HMAC, "sha384" },
+ { SADB_AALG_SHA2_512_HMAC, "sha512" },
+ { SADB_AALG_RIPEMD_160_HMAC, "ripemd160" },
+ { SADB_X_AALG_NULL, "null" },
+ { 0, sparse_end }
+};
+
+/* Encryption algorithms */
+static sparse_names ealg_list = {
+ { SADB_EALG_NULL, "cipher_null" },
+ { SADB_EALG_DES_CBC, "des" },
+ { SADB_EALG_3DES_CBC, "des3_ede" },
+ { SADB_EALG_IDEA_CBC, "idea" },
+ { SADB_EALG_CAST_CBC, "cast128" },
+ { SADB_EALG_BLOWFISH_CBC, "blowfish" },
+ { SADB_EALG_AES_CBC, "aes" },
+ { SADB_X_EALG_SERPENT_CBC, "serpent" },
+ { SADB_X_EALG_TWOFISH_CBC, "twofish" },
+ { 0, sparse_end }
+};
+
+/* Compression algorithms */
+static sparse_names calg_list = {
+ { SADB_X_CALG_DEFLATE, "deflate" },
+ { SADB_X_CALG_LZS, "lzs" },
+ { SADB_X_CALG_LZJH, "lzjh" },
+ { 0, sparse_end }
+};
+
+/** ip2xfrm - Take an IP address and convert to an xfrm.
+ *
+ * @param addr ip_address
+ * @param xaddr xfrm_address_t - IPv[46] Address from addr is copied here.
+ */
+static void
+ip2xfrm(const ip_address *addr, xfrm_address_t *xaddr)
+{
+ if (addr->u.v4.sin_family == AF_INET)
+ {
+ xaddr->a4 = addr->u.v4.sin_addr.s_addr;
+ }
+ else
+ {
+ memcpy(xaddr->a6, &addr->u.v6.sin6_addr, sizeof(xaddr->a6));
+ }
+}
+
+/** init_netlink - Initialize the netlink inferface. Opens the sockets and
+ * then binds to the broadcast socket.
+ */
+static void
+init_netlink(void)
+{
+ struct sockaddr_nl addr;
+
+ netlinkfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
+
+ if (netlinkfd < 0)
+ exit_log_errno((e, "socket() in init_netlink()"));
+
+ if (fcntl(netlinkfd, F_SETFD, FD_CLOEXEC) != 0)
+ exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_netlink()"));
+
+ netlink_bcast_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM);
+
+ if (netlink_bcast_fd < 0)
+ exit_log_errno((e, "socket() for bcast in init_netlink()"));
+
+ if (fcntl(netlink_bcast_fd, F_SETFD, FD_CLOEXEC) != 0)
+ exit_log_errno((e, "fcntl(FD_CLOEXEC) for bcast in init_netlink()"));
+
+ if (fcntl(netlink_bcast_fd, F_SETFL, O_NONBLOCK) != 0)
+ exit_log_errno((e, "fcntl(O_NONBLOCK) for bcast in init_netlink()"));
+
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = getpid();
+ addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;
+ if (bind(netlink_bcast_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
+ exit_log_errno((e, "Failed to bind bcast socket in init_netlink()"));
+}
+
+/** send_netlink_msg
+ *
+ * @param hdr - Data to be sent.
+ * @param rbuf - Return Buffer - contains data returned from the send.
+ * @param rbuf_len - Length of rbuf
+ * @param description - String - user friendly description of what is
+ * being attempted. Used for diagnostics
+ * @param text_said - String
+ * @return bool True if the message was succesfully sent.
+ */
+static bool
+send_netlink_msg(struct nlmsghdr *hdr, struct nlmsghdr *rbuf, size_t rbuf_len
+, const char *description, const char *text_said)
+{
+ struct {
+ struct nlmsghdr n;
+ struct nlmsgerr e;
+ char data[1024];
+ } rsp;
+
+ size_t len;
+ ssize_t r;
+ struct sockaddr_nl addr;
+ static uint32_t seq;
+
+ if (no_klips)
+ {
+ return TRUE;
+ }
+
+ hdr->nlmsg_seq = ++seq;
+ len = hdr->nlmsg_len;
+ do {
+ r = write(netlinkfd, hdr, len);
+ } while (r < 0 && errno == EINTR);
+ if (r < 0)
+ {
+ log_errno((e
+ , "netlink write() of %s message"
+ " for %s %s failed"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said));
+ return FALSE;
+ }
+ else if ((size_t)r != len)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: netlink write() of %s message"
+ " for %s %s truncated: %ld instead of %lu"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said
+ , (long)r, (unsigned long)len);
+ return FALSE;
+ }
+
+ for (;;) {
+ socklen_t alen;
+
+ alen = sizeof(addr);
+ r = recvfrom(netlinkfd, &rsp, sizeof(rsp), 0
+ , (struct sockaddr *)&addr, &alen);
+ if (r < 0)
+ {
+ if (errno == EINTR)
+ {
+ continue;
+ }
+ log_errno((e
+ , "netlink recvfrom() of response to our %s message"
+ " for %s %s failed"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said));
+ return FALSE;
+ }
+ else if ((size_t) r < sizeof(rsp.n))
+ {
+ plog("netlink read truncated message: %ld bytes; ignore message"
+ , (long) r);
+ continue;
+ }
+ else if (addr.nl_pid != 0)
+ {
+ /* not for us: ignore */
+ DBG(DBG_KLIPS,
+ DBG_log("netlink: ignoring %s message from process %u"
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)
+ , addr.nl_pid));
+ continue;
+ }
+ else if (rsp.n.nlmsg_seq != seq)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("netlink: ignoring out of sequence (%u/%u) message %s"
+ , rsp.n.nlmsg_seq, seq
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)));
+ continue;
+ }
+ break;
+ }
+
+ if (rsp.n.nlmsg_len > (size_t) r)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "netlink recvfrom() of response to our %s message"
+ " for %s %s was truncated: %ld instead of %lu"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said
+ , (long) len, (unsigned long) rsp.n.nlmsg_len);
+ return FALSE;
+ }
+ else if (rsp.n.nlmsg_type != NLMSG_ERROR
+ && (rbuf && rsp.n.nlmsg_type != rbuf->nlmsg_type))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "netlink recvfrom() of response to our %s message"
+ " for %s %s was of wrong type (%s)"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type));
+ return FALSE;
+ }
+ else if (rbuf)
+ {
+ if ((size_t) r > rbuf_len)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "netlink recvfrom() of response to our %s message"
+ " for %s %s was too long: %ld > %lu"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , description, text_said
+ , (long)r, (unsigned long)rbuf_len);
+ return FALSE;
+ }
+ memcpy(rbuf, &rsp, r);
+ return TRUE;
+ }
+ else if (rsp.n.nlmsg_type == NLMSG_ERROR && rsp.e.error)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: netlink response for %s %s included errno %d: %s"
+ , description, text_said
+ , -rsp.e.error
+ , strerror(-rsp.e.error));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/** netlink_policy -
+ *
+ * @param hdr - Data to check
+ * @param enoent_ok - Boolean - OK or not OK.
+ * @param text_said - String
+ * @return boolean
+ */
+static bool
+netlink_policy(struct nlmsghdr *hdr, bool enoent_ok, const char *text_said)
+{
+ struct {
+ struct nlmsghdr n;
+ struct nlmsgerr e;
+ } rsp;
+ int error;
+
+ rsp.n.nlmsg_type = NLMSG_ERROR;
+ if (!send_netlink_msg(hdr, &rsp.n, sizeof(rsp), "policy", text_said))
+ {
+ return FALSE;
+ }
+
+ error = -rsp.e.error;
+ if (!error)
+ {
+ return TRUE;
+ }
+
+ if (error == ENOENT && enoent_ok)
+ {
+ return TRUE;
+ }
+
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: netlink %s response for flow %s included errno %d: %s"
+ , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
+ , text_said
+ , error
+ , strerror(error));
+ return FALSE;
+}
+
+/** netlink_raw_eroute
+ *
+ * @param this_host ip_address
+ * @param this_client ip_subnet
+ * @param that_host ip_address
+ * @param that_client ip_subnet
+ * @param spi
+ * @param proto int (Currently unused) Contains protocol (u=tcp, 17=udp, etc...)
+ * @param transport_proto int (Currently unused) 0=tunnel, 1=transport
+ * @param satype int
+ * @param proto_info
+ * @param lifetime (Currently unused)
+ * @param ip int
+ * @return boolean True if successful
+ */
+static bool
+netlink_raw_eroute(const ip_address *this_host
+ , const ip_subnet *this_client
+ , const ip_address *that_host
+ , const ip_subnet *that_client
+ , ipsec_spi_t spi
+ , unsigned int satype
+ , unsigned int transport_proto
+ , const struct pfkey_proto_info *proto_info
+ , time_t use_lifetime UNUSED
+ , unsigned int op
+ , const char *text_said)
+{
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct xfrm_userpolicy_info p;
+ struct xfrm_userpolicy_id id;
+ } u;
+ char data[1024];
+ } req;
+ int shift;
+ int dir;
+ int family;
+ int policy;
+ bool ok;
+ bool enoent_ok;
+
+ policy = IPSEC_POLICY_IPSEC;
+
+ if (satype == SADB_X_SATYPE_INT)
+ {
+ /* shunt route */
+ switch (ntohl(spi))
+ {
+ case SPI_PASS:
+ policy = IPSEC_POLICY_NONE;
+ break;
+ case SPI_DROP:
+ case SPI_REJECT:
+ default:
+ policy = IPSEC_POLICY_DISCARD;
+ break;
+ case SPI_TRAP:
+ case SPI_TRAPSUBNET:
+ case SPI_HOLD:
+ if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
+ {
+ return TRUE;
+ }
+ break;
+ }
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+ family = that_client->addr.u.v4.sin_family;
+ shift = (family == AF_INET) ? 5 : 7;
+
+ req.u.p.sel.sport = portof(&this_client->addr);
+ req.u.p.sel.dport = portof(&that_client->addr);
+ req.u.p.sel.sport_mask = (req.u.p.sel.sport) ? ~0:0;
+ req.u.p.sel.dport_mask = (req.u.p.sel.dport) ? ~0:0;
+ ip2xfrm(&this_client->addr, &req.u.p.sel.saddr);
+ ip2xfrm(&that_client->addr, &req.u.p.sel.daddr);
+ req.u.p.sel.prefixlen_s = this_client->maskbits;
+ req.u.p.sel.prefixlen_d = that_client->maskbits;
+ req.u.p.sel.proto = transport_proto;
+ req.u.p.sel.family = family;
+
+ dir = XFRM_POLICY_OUT;
+ if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
+ {
+ dir = XFRM_POLICY_IN;
+ }
+
+ if ((op & ERO_MASK) == ERO_DELETE)
+ {
+ req.u.id.dir = dir;
+ req.n.nlmsg_type = XFRM_MSG_DELPOLICY;
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.id)));
+ }
+ else
+ {
+ int src, dst;
+
+ req.u.p.dir = dir;
+
+ src = req.u.p.sel.prefixlen_s;
+ dst = req.u.p.sel.prefixlen_d;
+ if (dir != XFRM_POLICY_OUT) {
+ src = req.u.p.sel.prefixlen_d;
+ dst = req.u.p.sel.prefixlen_s;
+ }
+ req.u.p.priority = MIN_SPD_PRIORITY
+ + (((2 << shift) - src) << shift)
+ + (2 << shift) - dst;
+
+ req.u.p.action = XFRM_POLICY_ALLOW;
+ if (policy == IPSEC_POLICY_DISCARD)
+ {
+ req.u.p.action = XFRM_POLICY_BLOCK;
+ }
+ req.u.p.lft.soft_use_expires_seconds = use_lifetime;
+ req.u.p.lft.soft_byte_limit = XFRM_INF;
+ req.u.p.lft.soft_packet_limit = XFRM_INF;
+ req.u.p.lft.hard_byte_limit = XFRM_INF;
+ req.u.p.lft.hard_packet_limit = XFRM_INF;
+
+ req.n.nlmsg_type = XFRM_MSG_NEWPOLICY;
+ if (op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT))
+ {
+ req.n.nlmsg_type = XFRM_MSG_UPDPOLICY;
+ }
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.p)));
+ }
+
+ if (policy == IPSEC_POLICY_IPSEC && (op & ERO_MASK) != ERO_DELETE)
+ {
+ struct rtattr *attr;
+ struct xfrm_user_tmpl tmpl[4];
+ int i;
+
+ memset(tmpl, 0, sizeof(tmpl));
+ for (i = 0; proto_info[i].proto; i++)
+ {
+ tmpl[i].reqid = proto_info[i].reqid;
+ tmpl[i].id.proto = proto_info[i].proto;
+ tmpl[i].optional =
+ proto_info[i].proto == IPPROTO_COMP && dir != XFRM_POLICY_OUT;
+ tmpl[i].aalgos = tmpl[i].ealgos = tmpl[i].calgos = ~0;
+ tmpl[i].mode =
+ proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL;
+
+ if (!tmpl[i].mode)
+ {
+ continue;
+ }
+
+ ip2xfrm(this_host, &tmpl[i].saddr);
+ ip2xfrm(that_host, &tmpl[i].id.daddr);
+ }
+
+ attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len);
+ attr->rta_type = XFRMA_TMPL;
+ attr->rta_len = i * sizeof(tmpl[0]);
+ memcpy(RTA_DATA(attr), tmpl, attr->rta_len);
+ attr->rta_len = RTA_LENGTH(attr->rta_len);
+ req.n.nlmsg_len += attr->rta_len;
+ }
+
+ enoent_ok = FALSE;
+ if (op == ERO_DEL_INBOUND)
+ {
+ enoent_ok = TRUE;
+ }
+ else if (op == ERO_DELETE && ntohl(spi) == SPI_HOLD)
+ {
+ enoent_ok = TRUE;
+ }
+
+ ok = netlink_policy(&req.n, enoent_ok, text_said);
+ switch (dir)
+ {
+ case XFRM_POLICY_IN:
+ if (req.n.nlmsg_type == XFRM_MSG_DELPOLICY)
+ {
+ req.u.id.dir = XFRM_POLICY_FWD;
+ }
+ else if (!ok)
+ {
+ break;
+ }
+ else if (proto_info[0].encapsulation != ENCAPSULATION_MODE_TUNNEL
+ && satype != SADB_X_SATYPE_INT)
+ {
+ break;
+ }
+ else
+ {
+ req.u.p.dir = XFRM_POLICY_FWD;
+ }
+ ok &= netlink_policy(&req.n, enoent_ok, text_said);
+ break;
+ }
+
+ return ok;
+}
+
+/** netlink_add_sa - Add an SA into the kernel SPDB via netlink
+ *
+ * @param sa Kernel SA to add/modify
+ * @param replace boolean - true if this replaces an existing SA
+ * @return bool True if successfull
+ */
+static bool
+netlink_add_sa(const struct kernel_sa *sa, bool replace)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_usersa_info p;
+ char data[1024];
+ } req;
+ struct rtattr *attr;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
+
+ ip2xfrm(sa->src, &req.p.saddr);
+ ip2xfrm(sa->dst, &req.p.id.daddr);
+
+ req.p.id.spi = sa->spi;
+ req.p.id.proto = satype2proto(sa->satype);
+ req.p.family = sa->src->u.v4.sin_family;
+ req.p.mode = (sa->encapsulation == ENCAPSULATION_MODE_TUNNEL);
+ req.p.replay_window = sa->replay_window;
+ req.p.reqid = sa->reqid;
+ req.p.lft.soft_byte_limit = XFRM_INF;
+ req.p.lft.soft_packet_limit = XFRM_INF;
+ req.p.lft.hard_byte_limit = XFRM_INF;
+ req.p.lft.hard_packet_limit = XFRM_INF;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.p)));
+
+ attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len);
+
+ if (sa->authalg)
+ {
+ struct xfrm_algo algo;
+ const char *name;
+
+ name = sparse_name(aalg_list, sa->authalg);
+ if (!name) {
+ loglog(RC_LOG_SERIOUS, "unknown authentication algorithm: %u"
+ , sa->authalg);
+ return FALSE;
+ }
+
+ strcpy(algo.alg_name, name);
+ algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE;
+
+ attr->rta_type = XFRMA_ALG_AUTH;
+ attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen);
+
+ memcpy(RTA_DATA(attr), &algo, sizeof(algo));
+ memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->authkey
+ , sa->authkeylen);
+
+ req.n.nlmsg_len += attr->rta_len;
+ attr = (struct rtattr *)((char *)attr + attr->rta_len);
+ }
+
+ if (sa->encalg)
+ {
+ struct xfrm_algo algo;
+ const char *name;
+
+ name = sparse_name(ealg_list, sa->encalg);
+ if (!name) {
+ loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u"
+ , sa->encalg);
+ return FALSE;
+ }
+
+ strcpy(algo.alg_name, name);
+ algo.alg_key_len = sa->enckeylen * BITS_PER_BYTE;
+
+ attr->rta_type = XFRMA_ALG_CRYPT;
+ attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->enckeylen);
+
+ memcpy(RTA_DATA(attr), &algo, sizeof(algo));
+ memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->enckey
+ , sa->enckeylen);
+
+ req.n.nlmsg_len += attr->rta_len;
+ attr = (struct rtattr *)((char *)attr + attr->rta_len);
+ }
+
+ if (sa->compalg)
+ {
+ struct xfrm_algo algo;
+ const char *name;
+
+ name = sparse_name(calg_list, sa->compalg);
+ if (!name) {
+ loglog(RC_LOG_SERIOUS, "unknown compression algorithm: %u"
+ , sa->compalg);
+ return FALSE;
+ }
+
+ strcpy(algo.alg_name, name);
+ algo.alg_key_len = 0;
+
+ attr->rta_type = XFRMA_ALG_COMP;
+ attr->rta_len = RTA_LENGTH(sizeof(algo));
+
+ memcpy(RTA_DATA(attr), &algo, sizeof(algo));
+
+ req.n.nlmsg_len += attr->rta_len;
+ attr = (struct rtattr *)((char *)attr + attr->rta_len);
+ }
+
+#ifdef NAT_TRAVERSAL
+ if (sa->natt_type)
+ {
+ struct xfrm_encap_tmpl natt;
+
+ natt.encap_type = sa->natt_type;
+ natt.encap_sport = ntohs(sa->natt_sport);
+ natt.encap_dport = ntohs(sa->natt_dport);
+ memset (&natt.encap_oa, 0, sizeof (natt.encap_oa));
+
+ attr->rta_type = XFRMA_ENCAP;
+ attr->rta_len = RTA_LENGTH(sizeof(natt));
+
+ memcpy(RTA_DATA(attr), &natt, sizeof(natt));
+
+ req.n.nlmsg_len += attr->rta_len;
+ attr = (struct rtattr *)((char *)attr + attr->rta_len);
+ }
+#endif
+
+ return send_netlink_msg(&req.n, NULL, 0, "Add SA", sa->text_said);
+}
+
+/** netlink_del_sa - Delete an SA from the Kernel
+ *
+ * @param sa Kernel SA to be deleted
+ * @return bool True if successfull
+ */
+static bool
+netlink_del_sa(const struct kernel_sa *sa)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_usersa_id id;
+ char data[1024];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_type = XFRM_MSG_DELSA;
+
+ ip2xfrm(sa->dst, &req.id.daddr);
+
+ req.id.spi = sa->spi;
+ req.id.family = sa->src->u.v4.sin_family;
+ req.id.proto = sa->proto;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)));
+
+ return send_netlink_msg(&req.n, NULL, 0, "Del SA", sa->text_said);
+}
+
+static bool
+netlink_error(const char *req_type, const struct nlmsghdr *n
+, const struct nlmsgerr *e, int rsp_size)
+{
+ if (n->nlmsg_type == NLMSG_ERROR)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("%s returned with errno %d: %s"
+ , req_type
+ , -e->error
+ , strerror(-e->error))
+ )
+ return TRUE;
+ }
+ if (n->nlmsg_len < NLMSG_LENGTH(rsp_size))
+ {
+ plog("%s returned message with length %lu < %lu bytes"
+ , req_type
+ , (unsigned long) n->nlmsg_len
+ , (unsigned long) rsp_size);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static bool
+netlink_get_policy(const struct kernel_sa *sa, bool inbound, time_t *use_time)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_userpolicy_id id;
+ } req;
+
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct nlmsgerr e;
+ struct xfrm_userpolicy_info info;
+ } u;
+ char data[1024];
+ } rsp;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_GETPOLICY;
+
+ req.id.sel.sport = portof(&sa->src_client->addr);
+ req.id.sel.dport = portof(&sa->dst_client->addr);
+ req.id.sel.sport_mask = (req.id.sel.sport) ? ~0:0;
+ req.id.sel.dport_mask = (req.id.sel.dport) ? ~0:0;
+ ip2xfrm(&sa->src_client->addr, &req.id.sel.saddr);
+ ip2xfrm(&sa->dst_client->addr, &req.id.sel.daddr);
+ req.id.sel.prefixlen_s = sa->src_client->maskbits;
+ req.id.sel.prefixlen_d = sa->dst_client->maskbits;
+ req.id.sel.proto = sa->transport_proto;
+ req.id.sel.family = sa->dst_client->addr.u.v4.sin_family;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)));
+ rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY;
+
+ req.id.dir = (inbound)? XFRM_POLICY_IN:XFRM_POLICY_OUT;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?"))
+ return FALSE;
+
+ if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info)))
+ return FALSE;
+
+ *use_time = (time_t)rsp.u.info.curlft.use_time;
+
+ if (inbound && sa->encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ {
+ time_t use_time_fwd;
+
+ req.id.dir = XFRM_POLICY_FWD;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?"))
+ return FALSE;
+
+ if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info)))
+ return FALSE;
+
+ use_time_fwd = (time_t)rsp.u.info.curlft.use_time;
+ *use_time = (*use_time > use_time_fwd)? *use_time : use_time_fwd;
+ }
+ return TRUE;
+}
+
+
+/** netlink_get_sa - Get information about an SA from the Kernel
+ *
+ * @param sa Kernel SA to be queried
+ * @return bool True if successfull
+ */
+static bool
+netlink_get_sa(const struct kernel_sa *sa, u_int *bytes)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_usersa_id id;
+ } req;
+
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct nlmsgerr e;
+ struct xfrm_usersa_info info;
+ } u;
+ char data[1024];
+ } rsp;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_GETSA;
+
+ ip2xfrm(sa->dst, &req.id.daddr);
+
+ req.id.spi = sa->spi;
+ req.id.family = sa->src->u.v4.sin_family;
+ req.id.proto = sa->proto;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)));
+ rsp.n.nlmsg_type = XFRM_MSG_NEWSA;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SA", sa->text_said))
+ return FALSE;
+
+ if (netlink_error("XFRM_MSG_GETSA", &rsp.n, &rsp.u.e, sizeof(rsp.u.info)))
+ return FALSE;
+
+ *bytes = (u_int) rsp.u.info.curlft.bytes;
+
+ return TRUE;
+}
+
+static void
+linux_pfkey_register_response(const struct sadb_msg *msg)
+{
+ switch (msg->sadb_msg_satype)
+ {
+ case SADB_SATYPE_ESP:
+#ifndef NO_KERNEL_ALG
+ kernel_alg_register_pfkey(msg, msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+#endif
+ break;
+ case SADB_X_SATYPE_IPCOMP:
+ can_do_IPcomp = TRUE;
+ break;
+ default:
+ break;
+ }
+}
+
+/** linux_pfkey_register - Register via PFKEY our capabilities
+ *
+ */
+static void
+linux_pfkey_register(void)
+{
+ pfkey_register_proto(SADB_SATYPE_AH, "AH");
+ pfkey_register_proto(SADB_SATYPE_ESP, "ESP");
+ pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP");
+ pfkey_close();
+}
+
+/** Create ip_address out of xfrm_address_t.
+ *
+ * @param family
+ * @param src xfrm formatted IP address
+ * @param dst ip_address formatted destination
+ * @return err_t NULL if okay, otherwise an error
+ */
+static err_t
+xfrm_to_ip_address(unsigned family, const xfrm_address_t *src, ip_address *dst)
+{
+ switch (family)
+ {
+ case AF_INET: /* IPv4 */
+ case AF_UNSPEC: /* Unspecified, we assume IPv4 */
+ initaddr((const void *) &src->a4, sizeof(src->a4), AF_INET, dst);
+ return NULL;
+ case AF_INET6: /* IPv6 */
+ initaddr((const void *) &src->a6, sizeof(src->a6), AF_INET6, dst);
+ return NULL;
+ default:
+ return "unknown address family";
+ }
+}
+
+/* Create a pair of ip_address's out of xfrm_sel.
+ *
+ * @param sel xfrm selector
+ * @param src ip_address formatted source
+ * @param dst ip_address formatted destination
+ * @return err_t NULL if okay, otherwise an error
+ */
+static err_t
+xfrm_sel_to_ip_pair(const struct xfrm_selector *sel
+ , ip_address *src
+ , ip_address *dst)
+{
+ int family;
+ err_t ugh;
+
+ family = sel->family;
+
+ if ((ugh = xfrm_to_ip_address(family, &sel->saddr, src))
+ || (ugh = xfrm_to_ip_address(family, &sel->daddr, dst)))
+ return ugh;
+
+ /* family has been verified in xfrm_to_ip_address. */
+ if (family == AF_INET)
+ {
+ src->u.v4.sin_port = sel->sport;
+ dst->u.v4.sin_port = sel->dport;
+ }
+ else
+ {
+ src->u.v6.sin6_port = sel->sport;
+ dst->u.v6.sin6_port = sel->dport;
+ }
+
+ return NULL;
+}
+
+static void
+netlink_acquire(struct nlmsghdr *n)
+{
+ struct xfrm_user_acquire *acquire;
+ ip_address src, dst;
+ ip_subnet ours, his;
+ unsigned transport_proto;
+ err_t ugh = NULL;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*acquire)))
+ {
+ plog("netlink_acquire got message with length %lu < %lu bytes; ignore message"
+ , (unsigned long) n->nlmsg_len
+ , (unsigned long) sizeof(*acquire));
+ return;
+ }
+
+ acquire = NLMSG_DATA(n);
+ transport_proto = acquire->sel.proto;
+
+ /* XXX also the type of src/dst should be checked to make sure
+ * that they aren't v4 to v6 or something goofy
+ */
+
+ if (!(ugh = xfrm_sel_to_ip_pair(&acquire->sel, &src, &dst))
+ && !(ugh = addrtosubnet(&src, &ours))
+ && !(ugh = addrtosubnet(&dst, &his)))
+ record_and_initiate_opportunistic(&ours, &his, transport_proto
+ , "%acquire-netlink");
+
+ if (ugh != NULL)
+ plog("XFRM_MSG_ACQUIRE message from kernel malformed: %s", ugh);
+}
+
+static void
+netlink_shunt_expire(struct xfrm_userpolicy_info *pol)
+{
+ ip_address src, dst;
+ unsigned transport_proto;
+ err_t ugh = NULL;
+
+ transport_proto = pol->sel.proto;
+
+ if (!(ugh = xfrm_sel_to_ip_pair(&pol->sel, &src, &dst)))
+ {
+ plog("XFRM_MSG_POLEXPIRE message from kernel malformed: %s", ugh);
+ return;
+ }
+
+ replace_bare_shunt(&src, &dst, BOTTOM_PRIO, SPI_PASS, FALSE, transport_proto
+ , "delete expired bare shunt");
+}
+
+static void
+netlink_policy_expire(struct nlmsghdr *n)
+{
+ struct xfrm_user_polexpire *upe;
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_userpolicy_id id;
+ } req;
+
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct nlmsgerr e;
+ struct xfrm_userpolicy_info pol;
+ } u;
+ char data[1024];
+ } rsp;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*upe)))
+ {
+ plog("netlink_policy_expire got message with length %lu < %lu bytes; ignore message"
+ , (unsigned long) n->nlmsg_len
+ , (unsigned long) sizeof(*upe));
+ return;
+ }
+
+ upe = NLMSG_DATA(n);
+ req.id.dir = upe->pol.dir;
+ req.id.index = upe->pol.index;
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_GETPOLICY;
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id)));
+
+ rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?"))
+ return;
+
+ if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.pol)))
+ return;
+
+ if (req.id.index != rsp.u.pol.index)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_policy_expire: policy was replaced: "
+ "dir=%d, oldindex=%d, newindex=%d"
+ , req.id.dir, req.id.index, rsp.u.pol.index));
+ return;
+ }
+
+ if (upe->pol.curlft.add_time != rsp.u.pol.curlft.add_time)
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_policy_expire: policy was replaced "
+ " and you have won the lottery: "
+ "dir=%d, index=%d"
+ , req.id.dir, req.id.index));
+ return;
+ }
+
+ switch (upe->pol.dir)
+ {
+ case XFRM_POLICY_OUT:
+ netlink_shunt_expire(&rsp.u.pol);
+ break;
+ }
+}
+
+static bool
+netlink_get(void)
+{
+ struct {
+ struct nlmsghdr n;
+ char data[1024];
+ } rsp;
+ ssize_t r;
+ struct sockaddr_nl addr;
+ socklen_t alen;
+
+ alen = sizeof(addr);
+ r = recvfrom(netlink_bcast_fd, &rsp, sizeof(rsp), 0
+ , (struct sockaddr *)&addr, &alen);
+ if (r < 0)
+ {
+ if (errno == EAGAIN)
+ return FALSE;
+ if (errno != EINTR)
+ log_errno((e, "recvfrom() failed in netlink_get"));
+ return TRUE;
+ }
+ else if ((size_t) r < sizeof(rsp.n))
+ {
+ plog("netlink_get read truncated message: %ld bytes; ignore message"
+ , (long) r);
+ return TRUE;
+ }
+ else if (addr.nl_pid != 0)
+ {
+ /* not for us: ignore */
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_get: ignoring %s message from process %u"
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)
+ , addr.nl_pid));
+ return TRUE;
+ }
+ else if ((size_t) r != rsp.n.nlmsg_len)
+ {
+ plog("netlink_get read message with length %ld that doesn't equal nlmsg_len %lu bytes; ignore message"
+ , (long) r
+ , (unsigned long) rsp.n.nlmsg_len);
+ return TRUE;
+ }
+
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_get: %s message"
+ , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)));
+
+ switch (rsp.n.nlmsg_type)
+ {
+ case XFRM_MSG_ACQUIRE:
+ netlink_acquire(&rsp.n);
+ break;
+ case XFRM_MSG_POLEXPIRE:
+ netlink_policy_expire(&rsp.n);
+ break;
+ default:
+ /* ignored */
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+netlink_process_msg(void)
+{
+ while (netlink_get())
+ ;
+}
+
+static ipsec_spi_t
+netlink_get_spi(const ip_address *src
+, const ip_address *dst
+, int proto
+, bool tunnel_mode
+, unsigned reqid
+, ipsec_spi_t min
+, ipsec_spi_t max
+, const char *text_said)
+{
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_userspi_info spi;
+ } req;
+
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct nlmsgerr e;
+ struct xfrm_usersa_info sa;
+ } u;
+ char data[1024];
+ } rsp;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
+
+ ip2xfrm(src, &req.spi.info.saddr);
+ ip2xfrm(dst, &req.spi.info.id.daddr);
+ req.spi.info.mode = tunnel_mode;
+ req.spi.info.reqid = reqid;
+ req.spi.info.id.proto = proto;
+ req.spi.info.family = src->u.v4.sin_family;
+ req.spi.min = min;
+ req.spi.max = max;
+
+ req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.spi)));
+ rsp.n.nlmsg_type = XFRM_MSG_NEWSA;
+
+ if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SPI", text_said))
+ return 0;
+
+ if (netlink_error("XFRM_MSG_ALLOCSPI", &rsp.n, &rsp.u.e, sizeof(rsp.u.sa)))
+ return 0;
+
+ DBG(DBG_KLIPS,
+ DBG_log("netlink_get_spi: allocated 0x%x for %s"
+ , ntohl(rsp.u.sa.id.spi), text_said));
+ return rsp.u.sa.id.spi;
+}
+
+const struct kernel_ops linux_kernel_ops = {
+ type: KERNEL_TYPE_LINUX,
+ inbound_eroute: 1,
+ policy_lifetime: 1,
+ async_fdp: &netlink_bcast_fd,
+
+ init: init_netlink,
+ pfkey_register: linux_pfkey_register,
+ pfkey_register_response: linux_pfkey_register_response,
+ process_msg: netlink_process_msg,
+ raw_eroute: netlink_raw_eroute,
+ get_policy: netlink_get_policy,
+ add_sa: netlink_add_sa,
+ del_sa: netlink_del_sa,
+ get_sa: netlink_get_sa,
+ process_queue: NULL,
+ grp_sa: NULL,
+ get_spi: netlink_get_spi,
+};
+#endif /* linux && KLIPS */
diff --git a/programs/pluto/kernel_netlink.h b/programs/pluto/kernel_netlink.h
new file mode 100644
index 000000000..1b5f42e48
--- /dev/null
+++ b/programs/pluto/kernel_netlink.h
@@ -0,0 +1,20 @@
+/* declarations of routines that interface with the kernel's pfkey mechanism
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Herbert Xu
+ *
+ * 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: kernel_netlink.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#if defined(KLIPS) && defined(linux)
+extern const struct kernel_ops linux_kernel_ops;
+#endif
diff --git a/programs/pluto/kernel_noklips.c b/programs/pluto/kernel_noklips.c
new file mode 100644
index 000000000..570bb0470
--- /dev/null
+++ b/programs/pluto/kernel_noklips.c
@@ -0,0 +1,126 @@
+/* interface to fake kernel interface, used for testing pluto in-vitro.
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ * Copyright (C) 2003 Herbert Xu.
+ *
+ * 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: kernel_noklips.c,v 1.5 2006/02/04 00:01:22 as Exp $
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "kernel.h"
+#include "kernel_noklips.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+
+void
+init_noklips(void)
+{
+ return;
+}
+
+/* asynchronous messages from our queue */
+static void
+noklips_dequeue(void)
+{
+}
+
+/* asynchronous messages directly from PF_KEY socket */
+static void
+noklips_event(void)
+{
+}
+
+static void
+noklips_register_response(const struct sadb_msg *msg UNUSED)
+{
+}
+
+static void
+noklips_register(void)
+{
+}
+
+static bool
+noklips_raw_eroute(const ip_address *this_host UNUSED
+ , const ip_subnet *this_client UNUSED
+ , const ip_address *that_host UNUSED
+ , const ip_subnet *that_client UNUSED
+ , ipsec_spi_t spi UNUSED
+ , unsigned int satype UNUSED
+ , unsigned int transport_proto UNUSED
+ , const struct pfkey_proto_info *proto_info UNUSED
+ , time_t use_lifetime UNUSED
+ , unsigned int op UNUSED
+ , const char *text_said UNUSED)
+{
+ return TRUE;
+}
+
+static bool
+noklips_add_sa(const struct kernel_sa *sa UNUSED
+ , bool replace UNUSED)
+{
+ return TRUE;
+}
+
+static bool
+noklips_grp_sa(const struct kernel_sa *sa0 UNUSED
+ , const struct kernel_sa *sa1 UNUSED)
+{
+ return TRUE;
+}
+
+static bool
+noklips_del_sa(const struct kernel_sa *sa UNUSED)
+{
+ return TRUE;
+}
+
+
+const struct kernel_ops noklips_kernel_ops = {
+ type: KERNEL_TYPE_NONE,
+ async_fdp: NULL,
+
+ init: init_noklips,
+ pfkey_register: noklips_register,
+ pfkey_register_response: noklips_register_response,
+ process_queue: noklips_dequeue,
+ process_msg: noklips_event,
+ raw_eroute: noklips_raw_eroute,
+ add_sa: noklips_add_sa,
+ grp_sa: noklips_grp_sa,
+ del_sa: noklips_del_sa,
+ get_sa: NULL,
+ get_spi: NULL,
+ inbound_eroute: FALSE,
+ policy_lifetime: FALSE
+};
diff --git a/programs/pluto/kernel_noklips.h b/programs/pluto/kernel_noklips.h
new file mode 100644
index 000000000..fe4e77ec4
--- /dev/null
+++ b/programs/pluto/kernel_noklips.h
@@ -0,0 +1,19 @@
+/* declarations of routines that interface with the kernel's pfkey mechanism
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Herbert Xu
+ *
+ * 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: kernel_noklips.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+extern void init_noklips(void);
+extern const struct kernel_ops noklips_kernel_ops;
diff --git a/programs/pluto/kernel_pfkey.c b/programs/pluto/kernel_pfkey.c
new file mode 100644
index 000000000..76bfbaf9a
--- /dev/null
+++ b/programs/pluto/kernel_pfkey.c
@@ -0,0 +1,938 @@
+/* pfkey interface to the kernel's IPsec mechanism
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Herbert Xu.
+ *
+ * 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: kernel_pfkey.c,v 1.8 2006/02/04 00:01:22 as Exp $
+ */
+
+#ifdef KLIPS
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "kernel.h"
+#include "kernel_pfkey.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#ifdef NAT_TRAVERSAL
+#include "demux.h"
+#include "nat_traversal.h"
+#endif
+
+#include "alg_info.h"
+#include "kernel_alg.h"
+
+
+static int pfkeyfd = NULL_FD;
+
+typedef u_int32_t pfkey_seq_t;
+static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */
+
+static pid_t pid;
+
+#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */
+
+static sparse_names pfkey_type_names = {
+ NE(SADB_RESERVED),
+ NE(SADB_GETSPI),
+ NE(SADB_UPDATE),
+ NE(SADB_ADD),
+ NE(SADB_DELETE),
+ NE(SADB_GET),
+ NE(SADB_ACQUIRE),
+ NE(SADB_REGISTER),
+ NE(SADB_EXPIRE),
+ NE(SADB_FLUSH),
+ NE(SADB_DUMP),
+ NE(SADB_X_PROMISC),
+ NE(SADB_X_PCHANGE),
+ NE(SADB_X_GRPSA),
+ NE(SADB_X_ADDFLOW),
+ NE(SADB_X_DELFLOW),
+ NE(SADB_X_DEBUG),
+#ifdef NAT_TRAVERSAL
+ NE(SADB_X_NAT_T_NEW_MAPPING),
+#endif
+ NE(SADB_MAX),
+ { 0, sparse_end }
+};
+
+#ifdef NEVER /* not needed yet */
+static sparse_names pfkey_ext_names = {
+ NE(SADB_EXT_RESERVED),
+ NE(SADB_EXT_SA),
+ NE(SADB_EXT_LIFETIME_CURRENT),
+ NE(SADB_EXT_LIFETIME_HARD),
+ NE(SADB_EXT_LIFETIME_SOFT),
+ NE(SADB_EXT_ADDRESS_SRC),
+ NE(SADB_EXT_ADDRESS_DST),
+ NE(SADB_EXT_ADDRESS_PROXY),
+ NE(SADB_EXT_KEY_AUTH),
+ NE(SADB_EXT_KEY_ENCRYPT),
+ NE(SADB_EXT_IDENTITY_SRC),
+ NE(SADB_EXT_IDENTITY_DST),
+ NE(SADB_EXT_SENSITIVITY),
+ NE(SADB_EXT_PROPOSAL),
+ NE(SADB_EXT_SUPPORTED_AUTH),
+ NE(SADB_EXT_SUPPORTED_ENCRYPT),
+ NE(SADB_EXT_SPIRANGE),
+ NE(SADB_X_EXT_KMPRIVATE),
+ NE(SADB_X_EXT_SATYPE2),
+ NE(SADB_X_EXT_SA2),
+ NE(SADB_X_EXT_ADDRESS_DST2),
+ NE(SADB_X_EXT_ADDRESS_SRC_FLOW),
+ NE(SADB_X_EXT_ADDRESS_DST_FLOW),
+ NE(SADB_X_EXT_ADDRESS_SRC_MASK),
+ NE(SADB_X_EXT_ADDRESS_DST_MASK),
+ NE(SADB_X_EXT_DEBUG),
+ { 0, sparse_end }
+};
+#endif /* NEVER */
+
+#undef NE
+
+void
+init_pfkey(void)
+{
+ pid = getpid();
+
+ /* open PF_KEY socket */
+
+ pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
+
+ if (pfkeyfd == -1)
+ exit_log_errno((e, "socket() in init_pfkeyfd()"));
+
+#ifdef NEVER /* apparently unsupported! */
+ if (fcntl(pfkeyfd, F_SETFL, O_NONBLOCK) != 0)
+ exit_log_errno((e, "fcntl(O_NONBLOCK) in init_pfkeyfd()"));
+#endif
+ if (fcntl(pfkeyfd, F_SETFD, FD_CLOEXEC) != 0)
+ exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_pfkeyfd()"));
+
+ DBG(DBG_KLIPS,
+ DBG_log("process %u listening for PF_KEY_V2 on file descriptor %d", (unsigned)pid, pfkeyfd));
+}
+
+/* Kinds of PF_KEY message from the kernel:
+ * - response to a request from us
+ * + ACK/NAK
+ * + Register: indicates transforms supported by kernel
+ * + SPI requested by getspi
+ * - Acquire, requesting us to deal with trapped clear packet
+ * - expiration of of one of our SAs
+ * - messages to other processes
+ *
+ * To minimize the effect on the event-driven structure of Pluto,
+ * responses are dealt with synchronously. We hope that the Kernel
+ * produces them synchronously. We must "read ahead" in the PF_KEY
+ * stream, saving Acquire and Expiry messages that are encountered.
+ * We ignore messages to other processes.
+ */
+
+typedef union {
+ unsigned char bytes[PFKEYv2_MAX_MSGSIZE];
+ struct sadb_msg msg;
+ } pfkey_buf;
+
+/* queue of unprocessed PF_KEY messages input from kernel
+ * Note that the pfkey_buf may be partly allocated, reflecting
+ * the variable length nature of the messages. So the link field
+ * must come first.
+ */
+typedef struct pfkey_item {
+ struct pfkey_item *next;
+ pfkey_buf buf;
+ } pfkey_item;
+
+static pfkey_item *pfkey_iq_head = NULL; /* oldest */
+static pfkey_item *pfkey_iq_tail; /* youngest */
+
+static bool
+pfkey_input_ready(void)
+{
+ fd_set readfds;
+ int ndes;
+ struct timeval tm;
+
+ tm.tv_sec = 0; /* don't wait at all */
+ tm.tv_usec = 0;
+
+ FD_ZERO(&readfds); /* we only care about pfkeyfd */
+ FD_SET(pfkeyfd, &readfds);
+
+ do {
+ ndes = select(pfkeyfd + 1, &readfds, NULL, NULL, &tm);
+ } while (ndes == -1 && errno == EINTR);
+
+ if (ndes < 0)
+ {
+ log_errno((e, "select() failed in pfkey_get()"));
+ return FALSE;
+ }
+
+ if (ndes == 0)
+ return FALSE; /* nothing to read */
+
+ passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds));
+ return TRUE;
+}
+
+/* get a PF_KEY message from kernel.
+ * Returns TRUE is message found, FALSE if no message pending,
+ * and aborts or keeps trying when an error is encountered.
+ * The only validation of the message is that the message length
+ * received matches that in the message header, and that the message
+ * is for this process.
+ */
+static bool
+pfkey_get(pfkey_buf *buf)
+{
+ for (;;)
+ {
+ /* len must be less than PFKEYv2_MAX_MSGSIZE,
+ * so it should fit in an int. We use this fact when printing it.
+ */
+ ssize_t len;
+
+ if (!pfkey_input_ready())
+ return FALSE;
+
+ len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes));
+
+ if (len < 0)
+ {
+ if (errno == EAGAIN)
+ return FALSE;
+
+ log_errno((e, "read() failed in pfkey_get()"));
+ return FALSE;
+ }
+ else if ((size_t) len < sizeof(buf->msg))
+ {
+ plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring message"
+ , (int) len);
+ }
+ else if ((size_t) len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN)
+ {
+ plog("pfkey_get read PF_KEY message with length %d that doesn't equal sadb_msg_len %u * %u; ignoring message"
+ , (int) len
+ , (unsigned) buf->msg.sadb_msg_len
+ , (unsigned) IPSEC_PFKEYv2_ALIGN);
+ }
+ else if (!(buf->msg.sadb_msg_pid == (unsigned)pid
+ || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)
+ || (buf->msg.sadb_msg_type == SADB_REGISTER)
+#ifdef NAT_TRAVERSAL
+ || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING)
+#endif
+ ))
+ {
+ /* not for us: ignore */
+ DBG(DBG_KLIPS,
+ DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process %u"
+ , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
+ , buf->msg.sadb_msg_seq
+ , buf->msg.sadb_msg_pid));
+ }
+ else
+ {
+ DBG(DBG_KLIPS,
+ DBG_log("pfkey_get: %s message %u"
+ , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
+ , buf->msg.sadb_msg_seq));
+ return TRUE;
+ }
+ }
+}
+
+/* get a response to a specific message */
+static bool
+pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq)
+{
+ while (pfkey_get(buf))
+ {
+ if (buf->msg.sadb_msg_pid == (unsigned)pid
+ && buf->msg.sadb_msg_seq == seq)
+ {
+ return TRUE;
+ }
+ else
+ {
+ /* Not for us: queue it. */
+ size_t bl = buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN;
+ pfkey_item *it = alloc_bytes(offsetof(pfkey_item, buf) + bl, "pfkey_item");
+
+ memcpy(&it->buf, buf, bl);
+
+ it->next = NULL;
+ if (pfkey_iq_head == NULL)
+ {
+ pfkey_iq_head = it;
+ }
+ else
+ {
+ pfkey_iq_tail->next = it;
+ }
+ pfkey_iq_tail = it;
+ }
+ }
+ return FALSE;
+}
+
+/* Process a SADB_REGISTER message from the kernel.
+ * This will be a response to one of ours, but it may be asynchronous
+ * (if kernel modules are loaded and unloaded).
+ * Some sanity checking has already been performed.
+ */
+static void
+klips_pfkey_register_response(const struct sadb_msg *msg)
+{
+ /* Find out what the kernel can support.
+ * In fact, the only question at the moment
+ * is whether it can support IPcomp.
+ * So we ignore the rest.
+ * ??? we really should pay attention to what transforms are supported.
+ */
+ switch (msg->sadb_msg_satype)
+ {
+ case SADB_SATYPE_AH:
+ break;
+ case SADB_SATYPE_ESP:
+#ifndef NO_KERNEL_ALG
+ kernel_alg_register_pfkey(msg, sizeof (pfkey_buf));
+#endif
+ break;
+ case SADB_X_SATYPE_COMP:
+ /* ??? There ought to be an extension to list the
+ * supported algorithms, but RFC 2367 doesn't
+ * list one for IPcomp. KLIPS uses SADB_X_CALG_DEFLATE.
+ * Since we only implement deflate, we'll assume this.
+ */
+ can_do_IPcomp = TRUE;
+ break;
+ case SADB_X_SATYPE_IPIP:
+ break;
+ default:
+ break;
+ }
+}
+
+/* Processs a SADB_ACQUIRE message from KLIPS.
+ * Try to build an opportunistic connection!
+ * See RFC 2367 "PF_KEY Key Management API, Version 2" 3.1.6
+ * <base, address(SD), (address(P)), (identity(SD),) (sensitivity,) proposal>
+ * - extensions for source and data IP addresses
+ * - optional extensions for identity [not useful for us?]
+ * - optional extension for sensitivity [not useful for us?]
+ * - expension for proposal [not useful for us?]
+ *
+ * ??? We must use the sequence number in creating an SA.
+ * We actually need to create up to 4 SAs each way. Which one?
+ * I guess it depends on the protocol present in the sadb_msg_satype.
+ * For now, we'll ignore this requirement.
+ *
+ * ??? We need some mechanism to make sure that multiple ACQUIRE messages
+ * don't cause a whole bunch of redundant negotiations.
+ */
+static void
+process_pfkey_acquire(pfkey_buf *buf, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC];
+ struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST];
+ int src_proto = srcx->sadb_address_proto;
+ int dst_proto = dstx->sadb_address_proto;
+ ip_address *src = (ip_address*)&srcx[1];
+ ip_address *dst = (ip_address*)&dstx[1];
+ ip_subnet ours, his;
+ err_t ugh = NULL;
+
+ /* assumption: we're only catching our own outgoing packets
+ * so source is our end and destination is the other end.
+ * Verifying this is not actually convenient.
+ *
+ * This stylized control structure yields a complaint or
+ * desired results. For compactness, a pointer value is
+ * treated as a boolean. Logically, the structure is:
+ * keep going as long as things are OK.
+ */
+ if (buf->msg.sadb_msg_pid == 0 /* we only wish to hear from kernel */
+ && !(ugh = src_proto == dst_proto? NULL : "src and dst protocols differ")
+ && !(ugh = addrtypeof(src) == addrtypeof(dst)? NULL : "conflicting address types")
+ && !(ugh = addrtosubnet(src, &ours))
+ && !(ugh = addrtosubnet(dst, &his)))
+ record_and_initiate_opportunistic(&ours, &his, src_proto, "%acquire");
+
+ if (ugh != NULL)
+ plog("SADB_ACQUIRE message from KLIPS malformed: %s", ugh);
+
+}
+
+/* Handle PF_KEY messages from the kernel that are not dealt with
+ * synchronously. In other words, all but responses to PF_KEY messages
+ * that we sent.
+ */
+static void
+pfkey_async(pfkey_buf *buf)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+
+ if (pfkey_msg_parse(&buf->msg, NULL, extensions, EXT_BITS_OUT))
+ {
+ plog("pfkey_async:"
+ " unparseable PF_KEY message:"
+ " %s len=%d, errno=%d, seq=%d, pid=%d; message ignored"
+ , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
+ , buf->msg.sadb_msg_len
+ , buf->msg.sadb_msg_errno
+ , buf->msg.sadb_msg_seq
+ , buf->msg.sadb_msg_pid);
+ }
+ else
+ {
+ DBG(DBG_CONTROL | DBG_KLIPS, DBG_log("pfkey_async:"
+ " %s len=%u, errno=%u, satype=%u, seq=%u, pid=%u"
+ , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
+ , buf->msg.sadb_msg_len
+ , buf->msg.sadb_msg_errno
+ , buf->msg.sadb_msg_satype
+ , buf->msg.sadb_msg_seq
+ , buf->msg.sadb_msg_pid));
+
+ switch (buf->msg.sadb_msg_type)
+ {
+ case SADB_REGISTER:
+ kernel_ops->pfkey_register_response(&buf->msg);
+ break;
+ case SADB_ACQUIRE:
+ /* to simulate loss of ACQUIRE, delete this call */
+ process_pfkey_acquire(buf, extensions);
+ break;
+#ifdef NAT_TRAVERSAL
+ case SADB_X_NAT_T_NEW_MAPPING:
+ process_pfkey_nat_t_new_mapping(&(buf->msg), extensions);
+ break;
+#endif
+ default:
+ /* ignored */
+ break;
+ }
+ }
+}
+
+/* asynchronous messages from our queue */
+static void
+pfkey_dequeue(void)
+{
+ while (pfkey_iq_head != NULL)
+ {
+ pfkey_item *it = pfkey_iq_head;
+
+ pfkey_async(&it->buf);
+ pfkey_iq_head = it->next;
+ pfree(it);
+ }
+
+ /* Handle any orphaned holds, but only if no pfkey input is pending.
+ * For each, we initiate Opportunistic.
+ * note: we don't need to advance the pointer because
+ * record_and_initiate_opportunistic will remove the current
+ * record each time we call it.
+ */
+ while (orphaned_holds != NULL && !pfkey_input_ready())
+ record_and_initiate_opportunistic(&orphaned_holds->ours
+ , &orphaned_holds->his
+ , orphaned_holds->transport_proto
+ , "%hold found-pfkey");
+
+}
+
+/* asynchronous messages directly from PF_KEY socket */
+static void
+pfkey_event(void)
+{
+ pfkey_buf buf;
+
+ if (pfkey_get(&buf))
+ pfkey_async(&buf);
+}
+
+static bool
+pfkey_build(int error
+, const char *description
+, const char *text_said
+, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ if (error == 0)
+ {
+ return TRUE;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d"
+ , description, text_said, error);
+ pfkey_extensions_free(extensions);
+ return FALSE;
+ }
+}
+
+/* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */
+static bool
+pfkey_msg_start(u_int8_t msg_type
+, u_int8_t satype
+, const char *description
+, const char *text_said
+, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ pfkey_extensions_init(extensions);
+ return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type
+ , satype, 0, ++pfkey_seq, pid)
+ , description, text_said, extensions);
+}
+
+/* pfkey_build + pfkey_address_build */
+static bool
+pfkeyext_address(u_int16_t exttype
+, const ip_address *address
+, const char *description
+, const char *text_said
+, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ /* the following variable is only needed to silence
+ * a warning caused by the fact that the argument
+ * to sockaddrof is NOT pointer to const!
+ */
+ ip_address t = *address;
+
+ return pfkey_build(pfkey_address_build(extensions + exttype
+ , exttype, 0, 0, sockaddrof(&t))
+ , description, text_said, extensions);
+}
+
+/* pfkey_build + pfkey_x_protocol_build */
+static bool
+pfkeyext_protocol(int transport_proto
+, const char *description
+, const char *text_said
+, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ return (transport_proto == 0)? TRUE
+ : pfkey_build(
+ pfkey_x_protocol_build(extensions + SADB_X_EXT_PROTOCOL, transport_proto)
+ , description, text_said, extensions);
+}
+
+
+/* Finish (building, sending, accepting response for) PF_KEY message.
+ * If response isn't NULL, the response from the kernel will be
+ * placed there (and its errno field will not be examined).
+ * Returns TRUE iff all appears well.
+ */
+static bool
+finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
+, const char *description
+, const char *text_said
+, pfkey_buf *response)
+{
+ struct sadb_msg *pfkey_msg;
+ bool success = TRUE;
+ int error;
+
+ error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN);
+
+ if (error != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d"
+ , description, text_said, error);
+ success = FALSE;
+ }
+ else
+ {
+ size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN;
+
+ DBG(DBG_KLIPS,
+ DBG_log("finish_pfkey_msg: %s message %u for %s %s"
+ , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
+ , pfkey_msg->sadb_msg_seq
+ , description, text_said);
+ DBG_dump(NULL, (void *) pfkey_msg, len));
+
+ if (!no_klips)
+ {
+ ssize_t r = write(pfkeyfd, pfkey_msg, len);
+
+ if (r != (ssize_t)len)
+ {
+ if (r < 0)
+ {
+ log_errno((e
+ , "pfkey write() of %s message %u"
+ " for %s %s failed"
+ , sparse_val_show(pfkey_type_names
+ , pfkey_msg->sadb_msg_type)
+ , pfkey_msg->sadb_msg_seq
+ , description, text_said));
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: pfkey write() of %s message %u"
+ " for %s %s truncated: %ld instead of %ld"
+ , sparse_val_show(pfkey_type_names
+ , pfkey_msg->sadb_msg_type)
+ , pfkey_msg->sadb_msg_seq
+ , description, text_said
+ , (long)r, (long)len);
+ }
+ success = FALSE;
+
+ /* if we were compiled with debugging, but we haven't already
+ * dumped the KLIPS command, do so.
+ */
+#ifdef DEBUG
+ if ((cur_debugging & DBG_KLIPS) == 0)
+ DBG_dump(NULL, (void *) pfkey_msg, len);
+#endif
+ }
+ else
+ {
+ /* Check response from KLIPS.
+ * It ought to be an echo, perhaps with additional info.
+ * If the caller wants it, response will point to space.
+ */
+ pfkey_buf b;
+ pfkey_buf *bp = response != NULL? response : &b;
+
+ if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: no response to our PF_KEY %s message for %s %s"
+ , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
+ , description, text_said);
+ success = FALSE;
+ }
+ else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "FreeS/WAN ERROR: response to our PF_KEY %s message for %s %s was of wrong type (%s)"
+ , sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type)
+ , description, text_said
+ , sparse_val_show(pfkey_type_names, bp->msg.sadb_msg_type));
+ success = FALSE;
+ }
+ else if (response == NULL && bp->msg.sadb_msg_errno != 0)
+ {
+ /* KLIPS is signalling a problem */
+ loglog(RC_LOG_SERIOUS
+ , "ERROR: PF_KEY %s response for %s %s included errno %u: %s"
+ , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
+ , description, text_said
+ , (unsigned) bp->msg.sadb_msg_errno
+ , strerror(bp->msg.sadb_msg_errno));
+ success = FALSE;
+ }
+ }
+ }
+ }
+
+ /* all paths must exit this way to free resources */
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+ return success;
+}
+
+/* register SA types that can be negotiated */
+void
+pfkey_register_proto(unsigned satype, const char *satypename)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+ pfkey_buf pfb;
+
+ if (!(pfkey_msg_start(SADB_REGISTER
+ , satype
+ , satypename, NULL, extensions)
+ && finish_pfkey_msg(extensions, satypename, "", &pfb)))
+ {
+ /* ??? should this be loglog */
+ plog("no KLIPS support for %s", satypename);
+ }
+ else
+ {
+ kernel_ops->pfkey_register_response(&pfb.msg);
+ DBG(DBG_KLIPS,
+ DBG_log("%s registered with kernel.", satypename));
+ }
+}
+
+static void
+klips_pfkey_register(void)
+{
+ pfkey_register_proto(SADB_SATYPE_AH, "AH");
+ pfkey_register_proto(SADB_SATYPE_ESP, "ESP");
+ can_do_IPcomp = FALSE; /* until we get a response from KLIPS */
+ pfkey_register_proto(SADB_X_SATYPE_COMP, "IPCOMP");
+ pfkey_register_proto(SADB_X_SATYPE_IPIP, "IPIP");
+}
+
+static bool
+pfkey_raw_eroute(const ip_address *this_host
+ , const ip_subnet *this_client
+ , const ip_address *that_host
+ , const ip_subnet *that_client
+ , ipsec_spi_t spi
+ , unsigned int satype
+ , unsigned int transport_proto
+ , const struct pfkey_proto_info *proto_info UNUSED
+ , time_t use_lifetime UNUSED
+ , unsigned int op
+ , const char *text_said)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+ ip_address
+ sflow_ska,
+ dflow_ska,
+ smask_ska,
+ dmask_ska;
+ int sport = ntohs(portof(&this_client->addr));
+ int dport = ntohs(portof(&that_client->addr));
+
+ networkof(this_client, &sflow_ska);
+ maskof(this_client, &smask_ska);
+ setportof(sport ? ~0:0, &smask_ska);
+
+ networkof(that_client, &dflow_ska);
+ maskof(that_client, &dmask_ska);
+ setportof(dport ? ~0:0, &dmask_ska);
+
+ if (!pfkey_msg_start(op & ERO_MASK, satype
+ , "pfkey_msg_hdr flow", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (op != ERO_DELETE)
+ {
+ if (!(pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
+ , SADB_EXT_SA
+ , spi /* in network order */
+ , 0, 0, 0, 0, op >> ERO_FLAG_SHIFT)
+ , "pfkey_sa add flow", text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_SRC, this_host
+ , "pfkey_addr_s add flow", text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_DST, that_host
+ , "pfkey_addr_d add flow", text_said
+ , extensions)))
+ {
+ return FALSE;
+ }
+ }
+
+ if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_FLOW, &sflow_ska
+ , "pfkey_addr_sflow", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_FLOW, &dflow_ska
+ , "pfkey_addr_dflow", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_MASK, &smask_ska
+ , "pfkey_addr_smask", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_MASK, &dmask_ska
+ , "pfkey_addr_dmask", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ if (!pfkeyext_protocol(transport_proto
+ , "pfkey_x_protocol", text_said, extensions))
+ {
+ return FALSE;
+ }
+
+ return finish_pfkey_msg(extensions, "flow", text_said, NULL);
+}
+
+static bool
+pfkey_add_sa(const struct kernel_sa *sa, bool replace)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+
+ return pfkey_msg_start(replace ? SADB_UPDATE : SADB_ADD, sa->satype
+ , "pfkey_msg_hdr Add SA", sa->text_said, extensions)
+
+ && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
+ , SADB_EXT_SA
+ , sa->spi /* in network order */
+ , sa->replay_window, SADB_SASTATE_MATURE
+ , sa->authalg, sa->encalg ? sa->encalg: sa->compalg, 0)
+ , "pfkey_sa Add SA", sa->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src
+ , "pfkey_addr_s Add SA", sa->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst
+ , "pfkey_addr_d Add SA", sa->text_said, extensions)
+
+ && (sa->authkeylen == 0
+ || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH]
+ , SADB_EXT_KEY_AUTH, sa->authkeylen * BITS_PER_BYTE
+ , sa->authkey)
+ , "pfkey_key_a Add SA", sa->text_said, extensions))
+
+ && (sa->enckeylen == 0
+ || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT]
+ , SADB_EXT_KEY_ENCRYPT, sa->enckeylen * BITS_PER_BYTE
+ , sa->enckey)
+ , "pfkey_key_e Add SA", sa->text_said, extensions))
+
+#ifdef NAT_TRAVERSAL
+ && (sa->natt_type == 0
+ || pfkey_build(pfkey_x_nat_t_type_build(
+ &extensions[SADB_X_EXT_NAT_T_TYPE], sa->natt_type),
+ "pfkey_nat_t_type Add ESP SA", sa->text_said, extensions))
+ && (sa->natt_sport == 0
+ || pfkey_build(pfkey_x_nat_t_port_build(
+ &extensions[SADB_X_EXT_NAT_T_SPORT], SADB_X_EXT_NAT_T_SPORT,
+ sa->natt_sport), "pfkey_nat_t_sport Add ESP SA", sa->text_said,
+ extensions))
+ && (sa->natt_dport == 0
+ || pfkey_build(pfkey_x_nat_t_port_build(
+ &extensions[SADB_X_EXT_NAT_T_DPORT], SADB_X_EXT_NAT_T_DPORT,
+ sa->natt_dport), "pfkey_nat_t_dport Add ESP SA", sa->text_said,
+ extensions))
+ && (sa->natt_type == 0 || isanyaddr(sa->natt_oa)
+ || pfkeyext_address(SADB_X_EXT_NAT_T_OA, sa->natt_oa
+ , "pfkey_nat_t_oa Add ESP SA", sa->text_said, extensions))
+#endif
+
+ && finish_pfkey_msg(extensions, "Add SA", sa->text_said, NULL);
+
+}
+
+static bool
+pfkey_grp_sa(const struct kernel_sa *sa0, const struct kernel_sa *sa1)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+
+ return pfkey_msg_start(SADB_X_GRPSA, sa1->satype
+ , "pfkey_msg_hdr group", sa1->text_said, extensions)
+
+ && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
+ , SADB_EXT_SA
+ , sa1->spi /* in network order */
+ , 0, 0, 0, 0, 0)
+ , "pfkey_sa group", sa1->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa1->dst
+ , "pfkey_addr_d group", sa1->text_said, extensions)
+
+ && pfkey_build(pfkey_x_satype_build(&extensions[SADB_X_EXT_SATYPE2]
+ , sa0->satype)
+ , "pfkey_satype group", sa0->text_said, extensions)
+
+ && pfkey_build(pfkey_sa_build(&extensions[SADB_X_EXT_SA2]
+ , SADB_X_EXT_SA2
+ , sa0->spi /* in network order */
+ , 0, 0, 0, 0, 0)
+ , "pfkey_sa2 group", sa0->text_said, extensions)
+
+ && pfkeyext_address(SADB_X_EXT_ADDRESS_DST2, sa0->dst
+ , "pfkey_addr_d2 group", sa0->text_said, extensions)
+
+ && finish_pfkey_msg(extensions, "group", sa1->text_said, NULL);
+}
+
+static bool
+pfkey_del_sa(const struct kernel_sa *sa)
+{
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+
+ return pfkey_msg_start(SADB_DELETE, proto2satype(sa->proto)
+ , "pfkey_msg_hdr delete SA", sa->text_said, extensions)
+
+ && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
+ , SADB_EXT_SA
+ , sa->spi /* in host order */
+ , 0, SADB_SASTATE_MATURE, 0, 0, 0)
+ , "pfkey_sa delete SA", sa->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src
+ , "pfkey_addr_s delete SA", sa->text_said, extensions)
+
+ && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst
+ , "pfkey_addr_d delete SA", sa->text_said, extensions)
+
+ && finish_pfkey_msg(extensions, "Delete SA", sa->text_said, NULL);
+}
+
+void
+pfkey_close(void)
+{
+ while (pfkey_iq_head != NULL)
+ {
+ pfkey_item *it = pfkey_iq_head;
+
+ pfkey_iq_head = it->next;
+ pfree(it);
+ }
+
+ close(pfkeyfd);
+ pfkeyfd = NULL_FD;
+}
+
+const struct kernel_ops klips_kernel_ops = {
+ type: KERNEL_TYPE_KLIPS,
+ async_fdp: &pfkeyfd,
+
+ pfkey_register: klips_pfkey_register,
+ pfkey_register_response: klips_pfkey_register_response,
+ process_queue: pfkey_dequeue,
+ process_msg: pfkey_event,
+ raw_eroute: pfkey_raw_eroute,
+ add_sa: pfkey_add_sa,
+ grp_sa: pfkey_grp_sa,
+ del_sa: pfkey_del_sa,
+ get_sa: NULL,
+ get_spi: NULL,
+ inbound_eroute: FALSE,
+ policy_lifetime: FALSE,
+ init: NULL
+};
+#endif /* KLIPS */
diff --git a/programs/pluto/kernel_pfkey.h b/programs/pluto/kernel_pfkey.h
new file mode 100644
index 000000000..9dbcdd341
--- /dev/null
+++ b/programs/pluto/kernel_pfkey.h
@@ -0,0 +1,23 @@
+/* declarations of routines that interface with the kernel's pfkey mechanism
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ * Copyright (C) 2003 Herbert Xu
+ *
+ * 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: kernel_pfkey.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#ifdef KLIPS
+extern void init_pfkey(void);
+extern void pfkey_register_proto(unsigned satype, const char *satypename);
+extern void pfkey_close(void);
+extern const struct kernel_ops klips_kernel_ops;
+#endif
diff --git a/programs/pluto/keys.c b/programs/pluto/keys.c
new file mode 100644
index 000000000..21092383a
--- /dev/null
+++ b/programs/pluto/keys.c
@@ -0,0 +1,1404 @@
+/* mechanisms for preshared keys (public, private, and preshared secrets)
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: keys.c,v 1.24 2006/01/27 08:59:40 as Exp $
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+
+#include <glob.h>
+#ifndef GLOB_ABORTED
+# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */
+#endif
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "id.h"
+#include "x509.h"
+#include "pgp.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "state.h"
+#include "lex.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#include "timer.h"
+#include "fetch.h"
+
+#ifdef NAT_TRAVERSAL
+#define PB_STREAM_UNDEFINED
+#include "nat_traversal.h"
+#endif
+
+const char *shared_secrets_file = SHARED_SECRETS_FILE;
+
+typedef struct id_list id_list_t;
+
+struct id_list {
+ struct id id;
+ id_list_t *next;
+};
+
+typedef struct secret secret_t;
+
+struct secret {
+ id_list_t *ids;
+ enum PrivateKeyKind kind;
+ union {
+ chunk_t preshared_secret;
+ RSA_private_key_t RSA_private_key;
+ smartcard_t *smartcard;
+ } u;
+ secret_t *next;
+};
+
+static pubkey_t*
+allocate_RSA_public_key(const cert_t cert)
+{
+ pubkey_t *pk = alloc_thing(pubkey_t, "pubkey");
+ chunk_t e, n;
+
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ e = cert.u.pgp->publicExponent;
+ n = cert.u.pgp->modulus;
+ break;
+ case CERT_X509_SIGNATURE:
+ e = cert.u.x509->publicExponent;
+ n = cert.u.x509->modulus;
+ break;
+ default:
+ plog("RSA public key allocation error");
+ }
+ init_RSA_public_key(&pk->u.rsa, e, n);
+
+#ifdef DEBUG
+ DBG(DBG_PRIVATE, RSA_show_public_key(&pk->u.rsa));
+#endif
+
+ pk->alg = PUBKEY_ALG_RSA;
+ pk->id = empty_id;
+ pk->issuer = empty_chunk;
+ pk->serial = empty_chunk;
+
+ return pk;
+}
+
+/*
+ * free a public key struct
+ */
+static void
+free_public_key(pubkey_t *pk)
+{
+ free_id_content(&pk->id);
+ freeanychunk(pk->issuer);
+ freeanychunk(pk->serial);
+
+ /* algorithm-specific freeing */
+ switch (pk->alg)
+ {
+ case PUBKEY_ALG_RSA:
+ free_RSA_public_content(&pk->u.rsa);
+ break;
+ default:
+ bad_case(pk->alg);
+ }
+ pfree(pk);
+}
+
+secret_t *secrets = NULL;
+
+/* find the struct secret associated with the combination of
+ * me and the peer. We match the Id (if none, the IP address).
+ * Failure is indicated by a NULL.
+ */
+static const secret_t *
+get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym)
+{
+ enum { /* bits */
+ match_default = 01,
+ match_him = 02,
+ match_me = 04
+ };
+
+ unsigned int best_match = 0;
+ secret_t *best = NULL;
+ secret_t *s;
+ const struct id *my_id = &c->spd.this.id
+ , *his_id = &c->spd.that.id;
+ struct id rw_id;
+
+ /* is there a certificate assigned to this connection? */
+ if (kind == PPK_RSA && c->spd.this.cert.type != CERT_NONE)
+ {
+ pubkey_t *my_public_key = allocate_RSA_public_key(c->spd.this.cert);
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == kind &&
+ same_RSA_public_key(&s->u.RSA_private_key.pub, &my_public_key->u.rsa))
+ {
+ best = s;
+ break; /* we have found the private key - no sense in searching further */
+ }
+ }
+ free_public_key(my_public_key);
+ return best;
+ }
+
+ if (his_id_was_instantiated(c))
+ {
+ /* roadwarrior: replace him with 0.0.0.0 */
+ rw_id.kind = c->spd.that.id.kind;
+ rw_id.name = empty_chunk;
+ happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
+ his_id = &rw_id;
+ }
+#ifdef NAT_TRAVERSAL
+ else if (nat_traversal_enabled
+ && (c->policy & POLICY_PSK)
+ && kind == PPK_PSK
+ && ((c->kind == CK_TEMPLATE && c->spd.that.id.kind == ID_NONE) ||
+ (c->kind == CK_INSTANCE && id_is_ipaddr(&c->spd.that.id))))
+ {
+ /* roadwarrior: replace him with 0.0.0.0 */
+ rw_id.kind = ID_IPV4_ADDR;
+ happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
+ his_id = &rw_id;
+ }
+#endif
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == kind)
+ {
+ unsigned int match = 0;
+
+ if (s->ids == NULL)
+ {
+ /* a default (signified by lack of ids):
+ * accept if no more specific match found
+ */
+ match = match_default;
+ }
+ else
+ {
+ /* check if both ends match ids */
+ id_list_t *i;
+
+ for (i = s->ids; i != NULL; i = i->next)
+ {
+ if (same_id(my_id, &i->id))
+ match |= match_me;
+
+ if (same_id(his_id, &i->id))
+ match |= match_him;
+ }
+
+ /* If our end matched the only id in the list,
+ * default to matching any peer.
+ * A more specific match will trump this.
+ */
+ if (match == match_me
+ && s->ids->next == NULL)
+ match |= match_default;
+ }
+
+ switch (match)
+ {
+ case match_me:
+ /* if this is an asymmetric (eg. public key) system,
+ * allow this-side-only match to count, even if
+ * there are other ids in the list.
+ */
+ if (!asym)
+ break;
+ /* FALLTHROUGH */
+ case match_default: /* default all */
+ case match_me | match_default: /* default peer */
+ case match_me | match_him: /* explicit */
+ if (match == best_match)
+ {
+ /* two good matches are equally good:
+ * do they agree?
+ */
+ bool same = FALSE;
+
+ switch (kind)
+ {
+ case PPK_PSK:
+ same = s->u.preshared_secret.len == best->u.preshared_secret.len
+ && memcmp(s->u.preshared_secret.ptr, best->u.preshared_secret.ptr, s->u.preshared_secret.len) == 0;
+ break;
+ case PPK_RSA:
+ /* Dirty trick: since we have code to compare
+ * RSA public keys, but not private keys, we
+ * make the assumption that equal public keys
+ * mean equal private keys. This ought to work.
+ */
+ same = same_RSA_public_key(&s->u.RSA_private_key.pub
+ , &best->u.RSA_private_key.pub);
+ break;
+ default:
+ bad_case(kind);
+ }
+ if (!same)
+ {
+ loglog(RC_LOG_SERIOUS, "multiple ipsec.secrets entries with distinct secrets match endpoints:"
+ " first secret used");
+ best = s; /* list is backwards: take latest in list */
+ }
+ }
+ else if (match > best_match)
+ {
+ /* this is the best match so far */
+ best_match = match;
+ best = s;
+ }
+ }
+ }
+ }
+ return best;
+}
+
+/* find the appropriate preshared key (see get_secret).
+ * Failure is indicated by a NULL pointer.
+ * Note: the result is not to be freed by the caller.
+ */
+const chunk_t *
+get_preshared_secret(const struct connection *c)
+{
+ const secret_t *s = get_secret(c, PPK_PSK, FALSE);
+
+#ifdef DEBUG
+ DBG(DBG_PRIVATE,
+ if (s == NULL)
+ DBG_log("no Preshared Key Found");
+ else
+ DBG_dump_chunk("Preshared Key", s->u.preshared_secret);
+ );
+#endif
+ return s == NULL? NULL : &s->u.preshared_secret;
+}
+
+/* check the existence of an RSA private key matching an RSA public
+ * key contained in an X.509 or OpenPGP certificate
+ */
+bool
+has_private_key(cert_t cert)
+{
+ secret_t *s;
+ bool has_key = FALSE;
+ pubkey_t *pubkey = allocate_RSA_public_key(cert);
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == PPK_RSA &&
+ same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa))
+ {
+ has_key = TRUE;
+ break;
+ }
+ }
+ free_public_key(pubkey);
+ return has_key;
+}
+
+/*
+ * get the matching RSA private key belonging to a given X.509 certificate
+ */
+const RSA_private_key_t*
+get_x509_private_key(const x509cert_t *cert)
+{
+ secret_t *s;
+ const RSA_private_key_t *pri = NULL;
+ const cert_t c = {CERT_X509_SIGNATURE, {cert}};
+
+ pubkey_t *pubkey = allocate_RSA_public_key(c);
+
+ for (s = secrets; s != NULL; s = s->next)
+ {
+ if (s->kind == PPK_RSA &&
+ same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa))
+ {
+ pri = &s->u.RSA_private_key;
+ break;
+ }
+ }
+ free_public_key(pubkey);
+ return pri;
+}
+
+/* find the appropriate RSA private key (see get_secret).
+ * Failure is indicated by a NULL pointer.
+ */
+const RSA_private_key_t *
+get_RSA_private_key(const struct connection *c)
+{
+ const secret_t *s = get_secret(c, PPK_RSA, TRUE);
+
+ return s == NULL? NULL : &s->u.RSA_private_key;
+}
+
+/* digest a secrets file
+ *
+ * The file is a sequence of records. A record is a maximal sequence of
+ * tokens such that the first, and only the first, is in the first column
+ * of a line.
+ *
+ * Tokens are generally separated by whitespace and are key words, ids,
+ * strings, or data suitable for ttodata(3). As a nod to convention,
+ * a trailing ":" on what would otherwise be a token is taken as a
+ * separate token. If preceded by whitespace, a "#" is taken as starting
+ * a comment: it and the rest of the line are ignored.
+ *
+ * One kind of record is an include directive. It starts with "include".
+ * The filename is the only other token in the record.
+ * If the filename does not start with /, it is taken to
+ * be relative to the directory containing the current file.
+ *
+ * The other kind of record describes a key. It starts with a
+ * sequence of ids and ends with key information. Each id
+ * is an IP address, a Fully Qualified Domain Name (which will immediately
+ * be resolved), or @FQDN which will be left as a name.
+ *
+ * The key part can be in several forms.
+ *
+ * The old form of the key is still supported: a simple
+ * quoted strings (with no escapes) is taken as a preshred key.
+ *
+ * The new form starts the key part with a ":".
+ *
+ * For Preshared Key, use the "PSK" keyword, and follow it by a string
+ * or a data token suitable for ttodata(3).
+ *
+ * For RSA Private Key, use the "RSA" keyword, followed by a
+ * brace-enclosed list of key field keywords and data values.
+ * The data values are large integers to be decoded by ttodata(3).
+ * The fields are a subset of those used by BIND 8.2 and have the
+ * same names.
+ */
+
+/* parse PSK from file */
+static err_t
+process_psk_secret(chunk_t *psk)
+{
+ err_t ugh = NULL;
+
+ if (*tok == '"' || *tok == '\'')
+ {
+ clonetochunk(*psk, tok+1, flp->cur - tok - 2, "PSK");
+ (void) shift();
+ }
+ else
+ {
+ char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */
+ size_t sz;
+
+ ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz
+ , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
+ if (ugh != NULL)
+ {
+ /* ttodata didn't like PSK data */
+ ugh = builddiag("PSK data malformed (%s): %s", ugh, tok);
+ }
+ else
+ {
+ clonetochunk(*psk, buf, sz, "PSK");
+ (void) shift();
+ }
+ }
+ return ugh;
+}
+
+/* Parse fields of RSA private key.
+ * A braced list of keyword and value pairs.
+ * At the moment, each field is required, in order.
+ * The fields come from BIND 8.2's representation
+ */
+static err_t
+process_rsa_secret(RSA_private_key_t *rsak)
+{
+ char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */
+ const struct fld *p;
+
+ /* save bytes of Modulus and PublicExponent for keyid calculation */
+ unsigned char ebytes[sizeof(buf)];
+ unsigned char *eb_next = ebytes;
+ chunk_t pub_bytes[2];
+ chunk_t *pb_next = &pub_bytes[0];
+
+ for (p = RSA_private_field; p < &RSA_private_field[RSA_PRIVATE_FIELD_ELEMENTS]; p++)
+ {
+ size_t sz;
+ err_t ugh;
+
+ if (!shift())
+ {
+ return "premature end of RSA key";
+ }
+ else if (!tokeqword(p->name))
+ {
+ return builddiag("%s keyword not found where expected in RSA key"
+ , p->name);
+ }
+ else if (!(shift()
+ && (!tokeq(":") || shift()))) /* ignore optional ":" */
+ {
+ return "premature end of RSA key";
+ }
+ else if (NULL != (ugh = ttodatav(tok, flp->cur - tok
+ , 0, buf, sizeof(buf), &sz, diag_space, sizeof(diag_space)
+ , TTODATAV_SPACECOUNTS)))
+ {
+ /* in RSA key, ttodata didn't like */
+ return builddiag("RSA data malformed (%s): %s", ugh, tok);
+ }
+ else
+ {
+ MP_INT *n = (MP_INT *) ((char *)rsak + p->offset);
+
+ n_to_mpz(n, buf, sz);
+ if (pb_next < &pub_bytes[elemsof(pub_bytes)])
+ {
+ if (eb_next - ebytes + sz > sizeof(ebytes))
+ return "public key takes too many bytes";
+
+ setchunk(*pb_next, eb_next, sz);
+ memcpy(eb_next, buf, sz);
+ eb_next += sz;
+ pb_next++;
+ }
+#if 0 /* debugging info that compromises security */
+ {
+ size_t sz = mpz_sizeinbase(n, 16);
+ char buf[RSA_MAX_OCTETS * 2 + 2]; /* ought to be big enough */
+
+ passert(sz <= sizeof(buf));
+ mpz_get_str(buf, 16, n);
+
+ loglog(RC_LOG_SERIOUS, "%s: %s", p->name, buf);
+ }
+#endif
+ }
+ }
+
+ /* We require an (indented) '}' and the end of the record.
+ * We break down the test so that the diagnostic will be
+ * more helpful. Some people don't seem to wish to indent
+ * the brace!
+ */
+ if (!shift() || !tokeq("}"))
+ {
+ return "malformed end of RSA private key -- indented '}' required";
+ }
+ else if (shift())
+ {
+ return "malformed end of RSA private key -- unexpected token after '}'";
+ }
+ else
+ {
+ unsigned bits = mpz_sizeinbase(&rsak->pub.n, 2);
+
+ rsak->pub.k = (bits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
+ rsak->pub.keyid[0] = '\0'; /* in case of splitkeytoid failure */
+ splitkeytoid(pub_bytes[1].ptr, pub_bytes[1].len
+ , pub_bytes[0].ptr, pub_bytes[0].len
+ , rsak->pub.keyid, sizeof(rsak->pub.keyid));
+ return RSA_private_key_sanity(rsak);
+ }
+}
+
+/* process rsa key file protected with optional passphrase which can either be
+ * read from ipsec.secrets or prompted for by using whack
+ */
+static err_t
+process_rsa_keyfile(RSA_private_key_t *rsak, int whackfd)
+{
+ char filename[BUF_LEN];
+ prompt_pass_t pass;
+
+ memset(filename,'\0', BUF_LEN);
+ memset(pass.secret,'\0', sizeof(pass.secret));
+ pass.prompt = FALSE;
+ pass.fd = whackfd;
+
+ /* we expect the filename of a PKCS#1 private key file */
+
+ if (*tok == '"' || *tok == '\'') /* quoted filename */
+ memcpy(filename, tok+1, flp->cur - tok - 2);
+ else
+ memcpy(filename, tok, flp->cur - tok);
+
+ if (shift())
+ {
+ /* we expect an appended passphrase or passphrase prompt*/
+ if (tokeqword("%prompt"))
+ {
+ if (pass.fd == NULL_FD)
+ return "RSA private key file -- enter passphrase using 'ipsec secrets'";
+ pass.prompt = TRUE;
+ }
+ else
+ {
+ char *passphrase = tok;
+ size_t len = flp->cur - passphrase;
+
+ if (*tok == '"' || *tok == '\'') /* quoted passphrase */
+ {
+ passphrase++;
+ len -= 2;
+ }
+ if (len > PROMPT_PASS_LEN)
+ return "RSA private key file -- passphrase exceeds 64 characters";
+
+ memcpy(pass.secret, passphrase, len);
+ }
+ if (shift())
+ return "RSA private key file -- unexpected token after passphrase";
+ }
+ return load_rsa_private_key(filename, &pass, rsak);
+}
+
+/*
+ * process pin read from ipsec.secrets or prompted for it using whack
+ */
+static err_t
+process_pin(secret_t *s, int whackfd)
+{
+ smartcard_t *sc;
+ const char *pin_status = "no pin";
+
+ s->kind = PPK_PIN;
+
+ /* looking for the smartcard keyword */
+ if (!shift() || strncmp(tok, SCX_TOKEN, strlen(SCX_TOKEN)) != 0)
+ return "PIN keyword must be followed by %smartcard<reader>:<id>";
+
+ sc = scx_add(scx_parse_number_slot_id(tok + strlen(SCX_TOKEN)));
+ s->u.smartcard = sc;
+ scx_share(sc);
+ if (sc->pin.ptr != NULL)
+ {
+ scx_release_context(sc);
+ scx_free_pin(&sc->pin);
+ }
+ sc->valid = FALSE;
+
+ if (!shift())
+ return "PIN statement must be terminated either by <pin code>, %pinpad or %prompt";
+
+ if (tokeqword("%prompt"))
+ {
+ shift();
+ /* if whackfd exists, whack will be used to prompt for a pin */
+ if (whackfd != NULL_FD)
+ pin_status = scx_get_pin(sc, whackfd) ? "valid pin" : "invalid pin";
+ else
+ pin_status = "pin entry via prompt";
+ }
+ else if (tokeqword("%pinpad"))
+ {
+ shift();
+ /* pin will be entered via pin pad during verification */
+ clonetochunk(sc->pin, "", 0, "empty pin");
+ sc->pinpad = TRUE;
+ sc->valid = TRUE;
+ pin_status = "pin entry via pad";
+ if (pkcs11_keep_state)
+ scx_verify_pin(sc);
+ }
+ else
+ {
+ /* we read the pin directly from ipsec.secrets */
+ err_t ugh = process_psk_secret(&sc->pin);
+ if (ugh != NULL)
+ return ugh;
+ /* verify the pin */
+ pin_status = scx_verify_pin(sc) ? "valid PIN" : "invalid PIN";
+ }
+#ifdef SMARTCARD
+ {
+ char buf[BUF_LEN];
+
+ if (sc->any_slot)
+ snprintf(buf, BUF_LEN, "any slot");
+ else
+ snprintf(buf, BUF_LEN, "slot: %lu", sc->slot);
+
+ plog(" %s for #%d (%s, id: %s)"
+ , pin_status, sc->number, scx_print_slot(sc, ""), sc->id);
+ }
+#else
+ plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!");
+#endif
+ return NULL;
+}
+
+static void
+process_secret(secret_t *s, int whackfd)
+{
+ err_t ugh = NULL;
+
+ s->kind = PPK_PSK; /* default */
+ if (*tok == '"' || *tok == '\'')
+ {
+ /* old PSK format: just a string */
+ ugh = process_psk_secret(&s->u.preshared_secret);
+ }
+ else if (tokeqword("psk"))
+ {
+ /* preshared key: quoted string or ttodata format */
+ ugh = !shift()? "unexpected end of record in PSK"
+ : process_psk_secret(&s->u.preshared_secret);
+ }
+ else if (tokeqword("rsa"))
+ {
+ /* RSA key: the fun begins.
+ * A braced list of keyword and value pairs.
+ */
+ s->kind = PPK_RSA;
+ if (!shift())
+ {
+ ugh = "bad RSA key syntax";
+ }
+ else if (tokeq("{"))
+ {
+ ugh = process_rsa_secret(&s->u.RSA_private_key);
+ }
+ else
+ {
+ ugh = process_rsa_keyfile(&s->u.RSA_private_key, whackfd);
+ }
+ }
+ else if (tokeqword("pin"))
+ {
+ ugh = process_pin(s, whackfd);
+ }
+ else
+ {
+ ugh = builddiag("unrecognized key format: %s", tok);
+ }
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s"
+ , flp->filename, flp->lino, ugh);
+ pfree(s);
+ }
+ else if (flushline("expected record boundary in key"))
+ {
+ /* gauntlet has been run: install new secret */
+ lock_certs_and_keys("process_secret");
+ s->next = secrets;
+ secrets = s;
+ unlock_certs_and_keys("process_secrets");
+ }
+}
+
+static void process_secrets_file(const char *file_pat, int whackfd); /* forward declaration */
+
+static void
+process_secret_records(int whackfd)
+{
+ /* read records from ipsec.secrets and load them into our table */
+ for (;;)
+ {
+ (void)flushline(NULL); /* silently ditch leftovers, if any */
+ if (flp->bdry == B_file)
+ break;
+
+ flp->bdry = B_none; /* eat the Record Boundary */
+ (void)shift(); /* get real first token */
+
+ if (tokeqword("include"))
+ {
+ /* an include directive */
+ char fn[MAX_TOK_LEN]; /* space for filename (I hope) */
+ char *p = fn;
+ char *end_prefix = strrchr(flp->filename, '/');
+
+ if (!shift())
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of include directive"
+ , flp->filename, flp->lino);
+ continue; /* abandon this record */
+ }
+
+ /* if path is relative and including file's pathname has
+ * a non-empty dirname, prefix this path with that dirname.
+ */
+ if (tok[0] != '/' && end_prefix != NULL)
+ {
+ size_t pl = end_prefix - flp->filename + 1;
+
+ /* "clamp" length to prevent problems now;
+ * will be rediscovered and reported later.
+ */
+ if (pl > sizeof(fn))
+ pl = sizeof(fn);
+ memcpy(fn, flp->filename, pl);
+ p += pl;
+ }
+ if (flp->cur - tok >= &fn[sizeof(fn)] - p)
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: include pathname too long"
+ , flp->filename, flp->lino);
+ continue; /* abandon this record */
+ }
+ strcpy(p, tok);
+ (void) shift(); /* move to Record Boundary, we hope */
+ if (flushline("ignoring malformed INCLUDE -- expected Record Boundary after filename"))
+ {
+ process_secrets_file(fn, whackfd);
+ tok = NULL; /* correct, but probably redundant */
+ }
+ }
+ else
+ {
+ /* expecting a list of indices and then the key info */
+ secret_t *s = alloc_thing(secret_t, "secret");
+
+ s->ids = NULL;
+ s->kind = PPK_PSK; /* default */
+ setchunk(s->u.preshared_secret, NULL, 0);
+ s->next = NULL;
+
+ for (;;)
+ {
+ if (tok[0] == '"' || tok[0] == '\'')
+ {
+ /* found key part */
+ process_secret(s, whackfd);
+ break;
+ }
+ else if (tokeq(":"))
+ {
+ /* found key part */
+ shift(); /* discard explicit separator */
+ process_secret(s, whackfd);
+ break;
+ }
+ else
+ {
+ /* an id
+ * See RFC2407 IPsec Domain of Interpretation 4.6.2
+ */
+ struct id id;
+ err_t ugh;
+
+ if (tokeq("%any"))
+ {
+ id = empty_id;
+ id.kind = ID_IPV4_ADDR;
+ ugh = anyaddr(AF_INET, &id.ip_addr);
+ }
+ else if (tokeq("%any6"))
+ {
+ id = empty_id;
+ id.kind = ID_IPV6_ADDR;
+ ugh = anyaddr(AF_INET6, &id.ip_addr);
+ }
+ else
+ {
+ ugh = atoid(tok, &id, FALSE);
+ }
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ERROR \"%s\" line %d: index \"%s\" %s"
+ , flp->filename, flp->lino, tok, ugh);
+ }
+ else
+ {
+ id_list_t *i = alloc_thing(id_list_t
+ , "id_list");
+
+ i->id = id;
+ unshare_id_content(&i->id);
+ i->next = s->ids;
+ s->ids = i;
+ /* DBG_log("id type %d: %s %.*s", i->kind, ip_str(&i->ip_addr), (int)i->name.len, i->name.ptr); */
+ }
+ if (!shift())
+ {
+ /* unexpected Record Boundary or EOF */
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of id list"
+ , flp->filename, flp->lino);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+static int
+globugh(const char *epath, int eerrno)
+{
+ log_errno_routine(eerrno, "problem with secrets file \"%s\"", epath);
+ return 1; /* stop glob */
+}
+
+static void
+process_secrets_file(const char *file_pat, int whackfd)
+{
+ struct file_lex_position pos;
+ char **fnp;
+ glob_t globbuf;
+
+ pos.depth = flp == NULL? 0 : flp->depth + 1;
+
+ if (pos.depth > 10)
+ {
+ loglog(RC_LOG_SERIOUS, "preshared secrets file \"%s\" nested too deeply", file_pat);
+ return;
+ }
+
+ /* do globbing */
+ {
+ int r = glob(file_pat, GLOB_ERR, globugh, &globbuf);
+
+ if (r != 0)
+ {
+ switch (r)
+ {
+ case GLOB_NOSPACE:
+ loglog(RC_LOG_SERIOUS, "out of space processing secrets filename \"%s\"", file_pat);
+ break;
+ case GLOB_ABORTED:
+ break; /* already logged */
+ case GLOB_NOMATCH:
+ loglog(RC_LOG_SERIOUS, "no secrets filename matched \"%s\"", file_pat);
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "unknown glob error %d", r);
+ break;
+ }
+ globfree(&globbuf);
+ return;
+ }
+ }
+
+ /* for each file... */
+ for (fnp = globbuf.gl_pathv; *fnp != NULL; fnp++)
+ {
+ if (lexopen(&pos, *fnp, FALSE))
+ {
+ plog("loading secrets from \"%s\"", *fnp);
+ (void) flushline("file starts with indentation (continuation notation)");
+ process_secret_records(whackfd);
+ lexclose();
+ }
+ }
+
+ globfree(&globbuf);
+}
+
+void
+free_preshared_secrets(void)
+{
+ lock_certs_and_keys("free_preshared_secrets");
+
+ if (secrets != NULL)
+ {
+ secret_t *s, *ns;
+
+ plog("forgetting secrets");
+
+ for (s = secrets; s != NULL; s = ns)
+ {
+ id_list_t *i, *ni;
+
+ ns = s->next; /* grab before freeing s */
+ for (i = s->ids; i != NULL; i = ni)
+ {
+ ni = i->next; /* grab before freeing i */
+ free_id_content(&i->id);
+ pfree(i);
+ }
+ switch (s->kind)
+ {
+ case PPK_PSK:
+ pfree(s->u.preshared_secret.ptr);
+ break;
+ case PPK_RSA:
+ free_RSA_private_content(&s->u.RSA_private_key);
+ break;
+ case PPK_PIN:
+ scx_release(s->u.smartcard);
+ break;
+ default:
+ bad_case(s->kind);
+ }
+ pfree(s);
+ }
+ secrets = NULL;
+ }
+
+ unlock_certs_and_keys("free_preshard_secrets");
+}
+
+void
+load_preshared_secrets(int whackfd)
+{
+ free_preshared_secrets();
+ (void) process_secrets_file(shared_secrets_file, whackfd);
+}
+
+/* public key machinery
+ * Note: caller must set dns_auth_level.
+ */
+
+pubkey_t *
+public_key_from_rsa(const RSA_public_key_t *k)
+{
+ pubkey_t *p = alloc_thing(pubkey_t, "pubkey");
+
+ p->id = empty_id; /* don't know, doesn't matter */
+ p->issuer = empty_chunk;
+ p->serial = empty_chunk;
+ p->alg = PUBKEY_ALG_RSA;
+
+ memcpy(p->u.rsa.keyid, k->keyid, sizeof(p->u.rsa.keyid));
+ p->u.rsa.k = k->k;
+ mpz_init_set(&p->u.rsa.e, &k->e);
+ mpz_init_set(&p->u.rsa.n, &k->n);
+
+ /* note that we return a 1 reference count upon creation:
+ * invariant: recount > 0.
+ */
+ p->refcnt = 1;
+ time(&p->installed_time);
+ return p;
+}
+
+/* Free a public key record.
+ * As a convenience, this returns a pointer to next.
+ */
+pubkey_list_t *
+free_public_keyentry(pubkey_list_t *p)
+{
+ pubkey_list_t *nxt = p->next;
+
+ if (p->key != NULL)
+ unreference_key(&p->key);
+ pfree(p);
+ return nxt;
+}
+
+void
+free_public_keys(pubkey_list_t **keys)
+{
+ while (*keys != NULL)
+ *keys = free_public_keyentry(*keys);
+}
+
+/* root of chained public key list */
+
+pubkey_list_t *pubkeys = NULL; /* keys from ipsec.conf */
+
+void
+free_remembered_public_keys(void)
+{
+ free_public_keys(&pubkeys);
+}
+
+/* transfer public keys from *keys list to front of pubkeys list */
+void
+transfer_to_public_keys(struct gw_info *gateways_from_dns
+#ifdef USE_KEYRR
+, pubkey_list_t **keys
+#endif /* USE_KEYRR */
+)
+{
+ {
+ struct gw_info *gwp;
+
+ for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next)
+ {
+ pubkey_list_t *pl = alloc_thing(pubkey_list_t, "from TXT");
+
+ pl->key = gwp->key; /* note: this is a transfer */
+ gwp->key = NULL; /* really, it is! */
+ pl->next = pubkeys;
+ pubkeys = pl;
+ }
+ }
+
+#ifdef USE_KEYRR
+ {
+ pubkey_list_t **pp = keys;
+
+ while (*pp != NULL)
+ pp = &(*pp)->next;
+ *pp = pubkeys;
+ pubkeys = *keys;
+ *keys = NULL;
+ }
+#endif /* USE_KEYRR */
+}
+
+/* decode of RSA pubkey chunk
+ * - format specified in RFC 2537 RSA/MD5 Keys and SIGs in the DNS
+ * - exponent length in bytes (1 or 3 octets)
+ * + 1 byte if in [1, 255]
+ * + otherwise 0x00 followed by 2 bytes of length
+ * - exponent
+ * - modulus
+ */
+err_t
+unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey)
+{
+ chunk_t exp;
+ chunk_t mod;
+
+ if (pubkey->len < 3)
+ return "RSA public key blob way to short"; /* not even room for length! */
+
+ if (pubkey->ptr[0] != 0x00)
+ {
+ setchunk(exp, pubkey->ptr + 1, pubkey->ptr[0]);
+ }
+ else
+ {
+ setchunk(exp, pubkey->ptr + 3
+ , (pubkey->ptr[1] << BITS_PER_BYTE) + pubkey->ptr[2]);
+ }
+
+ if (pubkey->len - (exp.ptr - pubkey->ptr) < exp.len + RSA_MIN_OCTETS_RFC)
+ return "RSA public key blob too short";
+
+ mod.ptr = exp.ptr + exp.len;
+ mod.len = &pubkey->ptr[pubkey->len] - mod.ptr;
+
+ if (mod.len < RSA_MIN_OCTETS)
+ return RSA_MIN_OCTETS_UGH;
+
+ if (mod.len > RSA_MAX_OCTETS)
+ return RSA_MAX_OCTETS_UGH;
+
+ init_RSA_public_key(rsa, exp, mod);
+
+#ifdef DEBUG
+ DBG(DBG_PRIVATE, RSA_show_public_key(rsa));
+#endif
+
+
+ rsa->k = mpz_sizeinbase(&rsa->n, 2); /* size in bits, for a start */
+ rsa->k = (rsa->k + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* now octets */
+
+ if (rsa->k != mod.len)
+ {
+ mpz_clear(&rsa->e);
+ mpz_clear(&rsa->n);
+ return "RSA modulus shorter than specified";
+ }
+
+ return NULL;
+}
+
+static void
+install_public_key(pubkey_t *pk, pubkey_list_t **head)
+{
+ pubkey_list_t *p = alloc_thing(pubkey_list_t, "pubkey entry");
+
+ unshare_id_content(&pk->id);
+
+ /* copy issuer dn */
+ if (pk->issuer.ptr != NULL)
+ pk->issuer.ptr = clone_bytes(pk->issuer.ptr, pk->issuer.len, "issuer dn");
+
+ /* copy serial number */
+ if (pk->serial.ptr != NULL)
+ pk->serial.ptr = clone_bytes(pk->serial.ptr, pk->serial.len, "serialNumber");
+
+ /* store the time the public key was installed */
+ time(&pk->installed_time);
+
+ /* install new key at front */
+ p->key = reference_key(pk);
+ p->next = *head;
+ *head = p;
+}
+
+
+void
+delete_public_keys(const struct id *id, enum pubkey_alg alg
+, chunk_t issuer, chunk_t serial)
+{
+ pubkey_list_t **pp, *p;
+ pubkey_t *pk;
+
+ for (pp = &pubkeys; (p = *pp) != NULL; )
+ {
+ pk = p->key;
+
+ if (same_id(id, &pk->id) && pk->alg == alg
+ && (issuer.ptr == NULL || pk->issuer.ptr == NULL
+ || same_dn(issuer, pk->issuer))
+ && same_serial(serial, pk->serial))
+ *pp = free_public_keyentry(p);
+ else
+ pp = &p->next;
+ }
+}
+
+pubkey_t *
+reference_key(pubkey_t *pk)
+{
+ pk->refcnt++;
+ return pk;
+}
+
+void
+unreference_key(pubkey_t **pkp)
+{
+ pubkey_t *pk = *pkp;
+ char b[BUF_LEN];
+
+ if (pk == NULL)
+ return;
+
+ /* print stuff */
+ DBG(DBG_CONTROLMORE,
+ idtoa(&pk->id, b, sizeof(b));
+ DBG_log("unreference key: %p %s cnt %d--", pk, b, pk->refcnt)
+ )
+
+ /* cancel out the pointer */
+ *pkp = NULL;
+
+ passert(pk->refcnt != 0);
+ pk->refcnt--;
+ if (pk->refcnt == 0)
+ free_public_key(pk);
+}
+
+err_t
+add_public_key(const struct id *id
+, enum dns_auth_level dns_auth_level
+, enum pubkey_alg alg
+, const chunk_t *key
+, pubkey_list_t **head)
+{
+ pubkey_t *pk = alloc_thing(pubkey_t, "pubkey");
+
+ /* first: algorithm-specific decoding of key chunk */
+ switch (alg)
+ {
+ case PUBKEY_ALG_RSA:
+ {
+ err_t ugh = unpack_RSA_public_key(&pk->u.rsa, key);
+
+ if (ugh != NULL)
+ {
+ pfree(pk);
+ return ugh;
+ }
+ }
+ break;
+ default:
+ bad_case(alg);
+ }
+
+ pk->id = *id;
+ pk->dns_auth_level = dns_auth_level;
+ pk->alg = alg;
+ pk->until_time = UNDEFINED_TIME;
+ pk->issuer = empty_chunk;
+ pk->serial = empty_chunk;
+
+ install_public_key(pk, head);
+ return NULL;
+}
+
+/* extract id and public key from x.509 certificate and
+ * insert it into a pubkeyrec
+ */
+void
+add_x509_public_key(x509cert_t *cert , time_t until
+ , enum dns_auth_level dns_auth_level)
+{
+ generalName_t *gn;
+ pubkey_t *pk;
+ cert_t c = { CERT_X509_SIGNATURE, {cert} };
+
+ /* we support RSA only */
+ if (cert->subjectPublicKeyAlgorithm != PUBKEY_ALG_RSA)
+ return;
+
+ /* ID type: ID_DER_ASN1_DN (X.509 subject field) */
+ pk = allocate_RSA_public_key(c);
+ pk->id.kind = ID_DER_ASN1_DN;
+ pk->id.name = cert->subject;
+ pk->dns_auth_level = dns_auth_level;
+ pk->until_time = until;
+ pk->issuer = cert->issuer;
+ pk->serial = cert->serialNumber;
+ delete_public_keys(&pk->id, pk->alg, pk->issuer, pk->serial);
+ install_public_key(pk, &pubkeys);
+
+ gn = cert->subjectAltName;
+
+ while (gn != NULL) /* insert all subjectAltNames */
+ {
+ struct id id = empty_id;
+
+ gntoid(&id, gn);
+ if (id.kind != ID_NONE)
+ {
+ pk = allocate_RSA_public_key(c);
+ pk->id = id;
+ pk->dns_auth_level = dns_auth_level;
+ pk->until_time = until;
+ pk->issuer = cert->issuer;
+ pk->serial = cert->serialNumber;
+ delete_public_keys(&pk->id, pk->alg, pk->issuer, pk->serial);
+ install_public_key(pk, &pubkeys);
+ }
+ gn = gn->next;
+ }
+}
+
+/* extract id and public key from OpenPGP certificate and
+ * insert it into a pubkeyrec
+ */
+void
+add_pgp_public_key(pgpcert_t *cert , time_t until
+ , enum dns_auth_level dns_auth_level)
+{
+ pubkey_t *pk;
+ cert_t c;
+
+ c.type = CERT_PGP;
+ c.u.pgp = cert;
+
+ /* we support RSA only */
+ if (cert->pubkeyAlg != PUBKEY_ALG_RSA)
+ {
+ plog(" RSA public keys supported only");
+ return;
+ }
+
+ pk = allocate_RSA_public_key(c);
+ pk->id.kind = ID_KEY_ID;
+ pk->id.name.ptr = cert->fingerprint;
+ pk->id.name.len = PGP_FINGERPRINT_SIZE;
+ pk->dns_auth_level = dns_auth_level;
+ pk->until_time = until;
+ delete_public_keys(&pk->id, pk->alg, empty_chunk, empty_chunk);
+ install_public_key(pk, &pubkeys);
+}
+
+/* when a X.509 certificate gets revoked, all instances of
+ * the corresponding public key must be removed
+ */
+void
+remove_x509_public_key(const x509cert_t *cert)
+{
+ const cert_t c = {CERT_X509_SIGNATURE, {cert}};
+ pubkey_list_t *p, **pp;
+ pubkey_t *revoked_pk;
+
+ revoked_pk = allocate_RSA_public_key(c);
+ p = pubkeys;
+ pp = &pubkeys;
+
+ while(p != NULL)
+ {
+ if (same_RSA_public_key(&p->key->u.rsa, &revoked_pk->u.rsa))
+ {
+ /* remove p from list and free memory */
+ *pp = free_public_keyentry(p);
+ loglog(RC_LOG_SERIOUS,
+ "invalid RSA public key deleted");
+ }
+ else
+ {
+ pp = &p->next;
+ }
+ p =*pp;
+ }
+ free_public_key(revoked_pk);
+}
+
+/*
+ * list all public keys in the chained list
+ */
+void list_public_keys(bool utc)
+{
+ pubkey_list_t *p = pubkeys;
+
+ if (p != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of Public Keys:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (p != NULL)
+ {
+ pubkey_t *key = p->key;
+
+ if (key->alg == PUBKEY_ALG_RSA)
+ {
+ char buf[BUF_LEN];
+ char expires_buf[TIMETOA_BUF];
+
+ idtoa(&key->id, buf, BUF_LEN);
+ strcpy(expires_buf, timetoa(&key->until_time, utc));
+ whack_log(RC_COMMENT, "%s, %4d RSA Key %s, until %s %s",
+
+ timetoa(&key->installed_time, utc), 8*key->u.rsa.k, key->u.rsa.keyid,
+ expires_buf,
+ check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE));
+ whack_log(RC_COMMENT," %s '%s'",
+ enum_show(&ident_names, key->id.kind), buf);
+ if (key->issuer.len > 0)
+ {
+ dntoa(buf, BUF_LEN, key->issuer);
+ whack_log(RC_COMMENT," issuer: '%s'", buf);
+ }
+ if (key->serial.len > 0)
+ {
+ datatot(key->serial.ptr, key->serial.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT," serial: %s", buf);
+ }
+ }
+ p = p->next;
+ }
+}
diff --git a/programs/pluto/keys.h b/programs/pluto/keys.h
new file mode 100644
index 000000000..d47d8b0a2
--- /dev/null
+++ b/programs/pluto/keys.h
@@ -0,0 +1,110 @@
+/* mechanisms for preshared keys (public, private, and preshared secrets)
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: keys.h,v 1.7 2006/01/26 20:10:34 as Exp $
+ */
+
+#ifndef _KEYS_H
+#define _KEYS_H
+
+#include <gmp.h> /* GNU Multi-Precision library */
+
+#include "pkcs1.h"
+#include "certs.h"
+
+#ifndef SHARED_SECRETS_FILE
+# define SHARED_SECRETS_FILE "/etc/ipsec.secrets"
+#endif
+
+const char *shared_secrets_file;
+
+extern void load_preshared_secrets(int whackfd);
+extern void free_preshared_secrets(void);
+
+struct state; /* forward declaration */
+
+enum PrivateKeyKind {
+ PPK_PSK,
+ /* PPK_DSS, */ /* not implemented */
+ PPK_RSA,
+ PPK_PIN
+};
+
+extern const chunk_t *get_preshared_secret(const struct connection *c);
+extern err_t unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey);
+extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c);
+extern const RSA_private_key_t *get_x509_private_key(const x509cert_t *cert);
+
+/* public key machinery */
+
+typedef struct pubkey pubkey_t;
+
+struct pubkey {
+ struct id id;
+ unsigned refcnt; /* reference counted! */
+ enum dns_auth_level dns_auth_level;
+ char *dns_sig;
+ time_t installed_time
+ , last_tried_time
+ , last_worked_time
+ , until_time;
+ chunk_t issuer;
+ chunk_t serial;
+ enum pubkey_alg alg;
+ union {
+ RSA_public_key_t rsa;
+ } u;
+};
+
+typedef struct pubkey_list pubkey_list_t;
+
+struct pubkey_list {
+ pubkey_t *key;
+ pubkey_list_t *next;
+};
+
+extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */
+
+extern pubkey_t *public_key_from_rsa(const RSA_public_key_t *k);
+extern pubkey_list_t *free_public_keyentry(pubkey_list_t *p);
+extern void free_public_keys(pubkey_list_t **keys);
+extern void free_remembered_public_keys(void);
+extern void delete_public_keys(const struct id *id, enum pubkey_alg alg
+ , chunk_t issuer, chunk_t serial);
+
+extern pubkey_t *reference_key(pubkey_t *pk);
+extern void unreference_key(pubkey_t **pkp);
+
+
+extern err_t add_public_key(const struct id *id
+ , enum dns_auth_level dns_auth_level
+ , enum pubkey_alg alg
+ , const chunk_t *key
+ , pubkey_list_t **head);
+
+extern bool has_private_key(cert_t cert);
+extern void add_x509_public_key(x509cert_t *cert, time_t until
+ , enum dns_auth_level dns_auth_level);
+extern void add_pgp_public_key(pgpcert_t *cert, time_t until
+ , enum dns_auth_level dns_auth_level);
+extern void remove_x509_public_key(const x509cert_t *cert);
+extern void list_public_keys(bool utc);
+
+struct gw_info; /* forward declaration of tag (defined in dnskey.h) */
+extern void transfer_to_public_keys(struct gw_info *gateways_from_dns
+#ifdef USE_KEYRR
+ , pubkey_list_t **keys
+#endif /* USE_KEYRR */
+ );
+
+#endif /* _KEYS_H */
diff --git a/programs/pluto/lex.c b/programs/pluto/lex.c
new file mode 100644
index 000000000..5c811725a
--- /dev/null
+++ b/programs/pluto/lex.c
@@ -0,0 +1,213 @@
+/* lexer (lexical analyzer) for control files
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: lex.c,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+#include "lex.h"
+
+struct file_lex_position *flp = NULL;
+
+/* Open a file for lexical processing.
+ * new_flp and name must point into storage with will live
+ * at least until the file is closed.
+ */
+bool
+lexopen(struct file_lex_position *new_flp, const char *name, bool optional)
+{
+ FILE *f = fopen(name, "r");
+
+ if (f == NULL)
+ {
+ if (!optional || errno != ENOENT)
+ log_errno((e, "could not open \"%s\"", name));
+ return FALSE;
+ }
+ else
+ {
+ new_flp->previous = flp;
+ flp = new_flp;
+ flp->filename = name;
+ flp->fp = f;
+ flp->lino = 0;
+ flp->bdry = B_none;
+
+ flp->cur = flp->buffer; /* nothing loaded yet */
+ flp->under = *flp->cur = '\0';
+
+ (void) shift(); /* prime tok */
+ return TRUE;
+ }
+}
+
+void
+lexclose(void)
+{
+ fclose(flp->fp);
+ flp = flp->previous;
+}
+
+/* Token decoding: shift() loads the next token into tok.
+ * Iff a token starts at the left margin, it is considered
+ * to be the first in a record. We create a special condition,
+ * Record Boundary (analogous to EOF), just before such a token.
+ * We are unwilling to shift through a record boundary:
+ * it must be overridden first.
+ * Returns FALSE iff Record Boundary or EOF (i.e. no token);
+ * tok will then be NULL.
+ */
+
+char *tok;
+#define tokeq(s) (streq(tok, (s)))
+#define tokeqword(s) (strcasecmp(tok, (s)) == 0)
+
+bool
+shift(void)
+{
+ char *p = flp->cur;
+ char *sor = NULL; /* start of record for any new lines */
+
+ passert(flp->bdry == B_none);
+
+ *p = flp->under;
+ flp->under = '\0';
+
+ for (;;)
+ {
+ switch (*p)
+ {
+ case '\0': /* end of line */
+ case '#': /* comment to end of line: treat as end of line */
+ /* get the next line */
+ if (fgets(flp->buffer, sizeof(flp->buffer)-1, flp->fp) == NULL)
+ {
+ flp->bdry = B_file;
+ tok = flp->cur = NULL;
+ return FALSE;
+ }
+ else
+ {
+ /* strip trailing whitespace, including \n */
+
+ for (p = flp->buffer+strlen(flp->buffer)-1
+ ; p>flp->buffer && isspace(p[-1]); p--)
+ ;
+ *p = '\0';
+
+ flp->lino++;
+ sor = p = flp->buffer;
+ }
+ break; /* try again for a token */
+
+ case ' ': /* whitespace */
+ case '\t':
+ p++;
+ break; /* try again for a token */
+
+ case '"': /* quoted token */
+ case '\'':
+ if (p != sor)
+ {
+ /* we have a quoted token: note and advance to its end */
+ tok = p;
+ p = strchr(p+1, *p);
+ if (p == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unterminated string"
+ , flp->filename, flp->lino);
+ p = tok + strlen(tok);
+ }
+ else
+ {
+ p++; /* include delimiter in token */
+ }
+
+ /* remember token delimiter and replace with '\0' */
+ flp->under = *p;
+ *p = '\0';
+ flp->cur = p;
+ return TRUE;
+ }
+ /* FALL THROUGH */
+ default:
+ if (p != sor)
+ {
+ /* we seem to have a token: note and advance to its end */
+ tok = p;
+
+ if (p[0] == '0' && p[1] == 't')
+ {
+ /* 0t... token goes to end of line */
+ p += strlen(p);
+ }
+ else
+ {
+ /* "ordinary" token: up to whitespace or end of line */
+ do {
+ p++;
+ } while (*p != '\0' && !isspace(*p))
+ ;
+
+ /* fudge to separate ':' from a preceding adjacent token */
+ if (p-1 > tok && p[-1] == ':')
+ p--;
+ }
+
+ /* remember token delimiter and replace with '\0' */
+ flp->under = *p;
+ *p = '\0';
+ flp->cur = p;
+ return TRUE;
+ }
+
+ /* we have a start-of-record: return it, deferring "real" token */
+ flp->bdry = B_record;
+ tok = NULL;
+ flp->under = *p;
+ flp->cur = p;
+ return FALSE;
+ }
+ }
+}
+
+/* ensures we are at a Record (or File) boundary, optionally warning if not */
+
+bool
+flushline(const char *m)
+{
+ if (flp->bdry != B_none)
+ {
+ return TRUE;
+ }
+ else
+ {
+ if (m != NULL)
+ loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s", flp->filename, flp->lino, m);
+ do ; while (shift());
+ return FALSE;
+ }
+}
diff --git a/programs/pluto/lex.h b/programs/pluto/lex.h
new file mode 100644
index 000000000..fb6c15236
--- /dev/null
+++ b/programs/pluto/lex.h
@@ -0,0 +1,52 @@
+/* lexer (lexical analyzer) for control files
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: lex.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+#define MAX_TOK_LEN 2048 /* includes terminal '\0' */
+struct file_lex_position
+{
+ int depth; /* how deeply we are nested */
+ const char *filename;
+ FILE *fp;
+ enum { B_none, B_record, B_file } bdry; /* current boundary */
+ int lino; /* line number in file */
+ char buffer[MAX_TOK_LEN + 1]; /* note: one extra char for our use (jamming '"') */
+ char *cur; /* cursor */
+ char under; /* except in shift(): character orignally at *cur */
+ struct file_lex_position *previous;
+};
+
+extern struct file_lex_position *flp;
+
+extern bool lexopen(struct file_lex_position *new_flp, const char *name, bool optional);
+extern void lexclose(void);
+
+
+/* Token decoding: shift() loads the next token into tok.
+ * Iff a token starts at the left margin, it is considered
+ * to be the first in a record. We create a special condition,
+ * Record Boundary (analogous to EOF), just before such a token.
+ * We are unwilling to shift through a record boundary:
+ * it must be overridden first.
+ * Returns FALSE iff Record Boundary or EOF (i.e. no token);
+ * tok will then be NULL.
+ */
+
+extern char *tok;
+#define tokeq(s) (streq(tok, (s)))
+#define tokeqword(s) (strcasecmp(tok, (s)) == 0)
+
+extern bool shift(void);
+extern bool flushline(const char *m);
diff --git a/programs/pluto/linux26/netlink.h b/programs/pluto/linux26/netlink.h
new file mode 100644
index 000000000..6b0896da6
--- /dev/null
+++ b/programs/pluto/linux26/netlink.h
@@ -0,0 +1,90 @@
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+#include <stdint.h>
+#include <sys/socket.h> /* for sa_family_t */
+
+#define NETLINK_ROUTE 0 /* Routing/device hook */
+#define NETLINK_SKIP 1 /* Reserved for ENskip */
+#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
+#define NETLINK_FIREWALL 3 /* Firewalling hook */
+#define NETLINK_TCPDIAG 4 /* TCP socket monitoring */
+#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
+#define NETLINK_XFRM 6 /* ipsec */
+#define NETLINK_ARPD 8
+#define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */
+#define NETLINK_IP6_FW 13
+#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
+#define NETLINK_TAPBASE 16 /* 16 to 31 are ethertap */
+
+#define MAX_LINKS 32
+
+struct sockaddr_nl
+{
+ sa_family_t nl_family; /* AF_NETLINK */
+ unsigned short nl_pad; /* zero */
+ uint32_t nl_pid; /* process pid */
+ uint32_t nl_groups; /* multicast groups mask */
+};
+
+struct nlmsghdr
+{
+ uint32_t nlmsg_len; /* Length of message including header */
+ uint16_t nlmsg_type; /* Message content */
+ uint16_t nlmsg_flags; /* Additional flags */
+ uint32_t nlmsg_seq; /* Sequence number */
+ uint32_t nlmsg_pid; /* Sending process PID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST 1 /* It is request message. */
+#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */
+#define NLM_F_ECHO 8 /* Echo this request */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT 0x100 /* specify tree root */
+#define NLM_F_MATCH 0x200 /* return all matching */
+#define NLM_F_ATOMIC 0x400 /* atomic GET */
+#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE 0x100 /* Override existing */
+#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
+#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
+#define NLM_F_APPEND 0x800 /* Add to end of list */
+
+/*
+ 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
+ 4.4BSD CHANGE NLM_F_REPLACE
+
+ True CHANGE NLM_F_CREATE|NLM_F_REPLACE
+ Append NLM_F_CREATE
+ Check NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+ (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) > 0 && (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP 0x1 /* Nothing. */
+#define NLMSG_ERROR 0x2 /* Error */
+#define NLMSG_DONE 0x3 /* End of a dump */
+#define NLMSG_OVERRUN 0x4 /* Data lost */
+
+struct nlmsgerr
+{
+ int error;
+ struct nlmsghdr msg;
+};
+
+#define NET_MAJOR 36 /* Major 36 is reserved for networking */
+#endif /* __LINUX_NETLINK_H */
diff --git a/programs/pluto/linux26/rtnetlink.h b/programs/pluto/linux26/rtnetlink.h
new file mode 100644
index 000000000..341bc1f86
--- /dev/null
+++ b/programs/pluto/linux26/rtnetlink.h
@@ -0,0 +1,562 @@
+#ifndef __LINUX_RTNETLINK_H
+#define __LINUX_RTNETLINK_H
+
+#include "netlink.h"
+#include <stdint.h>
+
+#define RTNL_DEBUG 1
+
+
+/****
+ * Routing/neighbour discovery messages.
+ ****/
+
+/* Types of messages */
+
+#define RTM_BASE 0x10
+
+#define RTM_NEWLINK (RTM_BASE+0)
+#define RTM_DELLINK (RTM_BASE+1)
+#define RTM_GETLINK (RTM_BASE+2)
+#define RTM_SETLINK (RTM_BASE+3)
+
+#define RTM_NEWADDR (RTM_BASE+4)
+#define RTM_DELADDR (RTM_BASE+5)
+#define RTM_GETADDR (RTM_BASE+6)
+
+#define RTM_NEWROUTE (RTM_BASE+8)
+#define RTM_DELROUTE (RTM_BASE+9)
+#define RTM_GETROUTE (RTM_BASE+10)
+
+#define RTM_NEWNEIGH (RTM_BASE+12)
+#define RTM_DELNEIGH (RTM_BASE+13)
+#define RTM_GETNEIGH (RTM_BASE+14)
+
+#define RTM_NEWRULE (RTM_BASE+16)
+#define RTM_DELRULE (RTM_BASE+17)
+#define RTM_GETRULE (RTM_BASE+18)
+
+#define RTM_NEWQDISC (RTM_BASE+20)
+#define RTM_DELQDISC (RTM_BASE+21)
+#define RTM_GETQDISC (RTM_BASE+22)
+
+#define RTM_NEWTCLASS (RTM_BASE+24)
+#define RTM_DELTCLASS (RTM_BASE+25)
+#define RTM_GETTCLASS (RTM_BASE+26)
+
+#define RTM_NEWTFILTER (RTM_BASE+28)
+#define RTM_DELTFILTER (RTM_BASE+29)
+#define RTM_GETTFILTER (RTM_BASE+30)
+
+#define RTM_MAX (RTM_BASE+31)
+
+/*
+ Generic structure for encapsulation optional route information.
+ It is reminiscent of sockaddr, but with sa_family replaced
+ with attribute type.
+ */
+
+struct rtattr
+{
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+/* Macros to handle rtattributes */
+
+#define RTA_ALIGNTO 4
+#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
+#define RTA_OK(rta,len) ((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
+ (rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+ (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
+#define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
+#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
+
+
+
+
+/******************************************************************************
+ * Definitions used in routing table administation.
+ ****/
+
+struct rtmsg
+{
+ unsigned char rtm_family;
+ unsigned char rtm_dst_len;
+ unsigned char rtm_src_len;
+ unsigned char rtm_tos;
+
+ unsigned char rtm_table; /* Routing table id */
+ unsigned char rtm_protocol; /* Routing protocol; see below */
+ unsigned char rtm_scope; /* See below */
+ unsigned char rtm_type; /* See below */
+
+ unsigned rtm_flags;
+};
+
+/* rtm_type */
+
+enum
+{
+ RTN_UNSPEC,
+ RTN_UNICAST, /* Gateway or direct route */
+ RTN_LOCAL, /* Accept locally */
+ RTN_BROADCAST, /* Accept locally as broadcast,
+ send as broadcast */
+ RTN_ANYCAST, /* Accept locally as broadcast,
+ but send as unicast */
+ RTN_MULTICAST, /* Multicast route */
+ RTN_BLACKHOLE, /* Drop */
+ RTN_UNREACHABLE, /* Destination is unreachable */
+ RTN_PROHIBIT, /* Administratively prohibited */
+ RTN_THROW, /* Not in this table */
+ RTN_NAT, /* Translate this address */
+ RTN_XRESOLVE, /* Use external resolver */
+};
+
+#define RTN_MAX RTN_XRESOLVE
+
+
+/* rtm_protocol */
+
+#define RTPROT_UNSPEC 0
+#define RTPROT_REDIRECT 1 /* Route installed by ICMP redirects;
+ not used by current IPv4 */
+#define RTPROT_KERNEL 2 /* Route installed by kernel */
+#define RTPROT_BOOT 3 /* Route installed during boot */
+#define RTPROT_STATIC 4 /* Route installed by administrator */
+
+/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
+ they just passed from user and back as is.
+ It will be used by hypothetical multiple routing daemons.
+ Note that protocol values should be standardized in order to
+ avoid conflicts.
+ */
+
+#define RTPROT_GATED 8 /* Apparently, GateD */
+#define RTPROT_RA 9 /* RDISC/ND router advertisments */
+#define RTPROT_MRT 10 /* Merit MRT */
+#define RTPROT_ZEBRA 11 /* Zebra */
+#define RTPROT_BIRD 12 /* BIRD */
+#define RTPROT_DNROUTED 13 /* DECnet routing daemon */
+
+/* rtm_scope
+
+ Really it is not scope, but sort of distance to the destination.
+ NOWHERE are reserved for not existing destinations, HOST is our
+ local addresses, LINK are destinations, located on directly attached
+ link and UNIVERSE is everywhere in the Universe.
+
+ Intermediate values are also possible f.e. interior routes
+ could be assigned a value between UNIVERSE and LINK.
+*/
+
+enum rt_scope_t
+{
+ RT_SCOPE_UNIVERSE=0,
+/* User defined values */
+ RT_SCOPE_SITE=200,
+ RT_SCOPE_LINK=253,
+ RT_SCOPE_HOST=254,
+ RT_SCOPE_NOWHERE=255
+};
+
+/* rtm_flags */
+
+#define RTM_F_NOTIFY 0x100 /* Notify user of route change */
+#define RTM_F_CLONED 0x200 /* This route is cloned */
+#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */
+
+/* Reserved table identifiers */
+
+enum rt_class_t
+{
+ RT_TABLE_UNSPEC=0,
+/* User defined values */
+ RT_TABLE_DEFAULT=253,
+ RT_TABLE_MAIN=254,
+ RT_TABLE_LOCAL=255
+};
+#define RT_TABLE_MAX RT_TABLE_LOCAL
+
+
+
+/* Routing message attributes */
+
+enum rtattr_type_t
+{
+ RTA_UNSPEC,
+ RTA_DST,
+ RTA_SRC,
+ RTA_IIF,
+ RTA_OIF,
+ RTA_GATEWAY,
+ RTA_PRIORITY,
+ RTA_PREFSRC,
+ RTA_METRICS,
+ RTA_MULTIPATH,
+ RTA_PROTOINFO,
+ RTA_FLOW,
+ RTA_CACHEINFO,
+ RTA_SESSION,
+};
+
+#define RTA_MAX RTA_SESSION
+
+#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg))))
+#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg))
+
+/* RTM_MULTIPATH --- array of struct rtnexthop.
+ *
+ * "struct rtnexthop" describres all necessary nexthop information,
+ * i.e. parameters of path to a destination via this nextop.
+ *
+ * At the moment it is impossible to set different prefsrc, mtu, window
+ * and rtt for different paths from multipath.
+ */
+
+struct rtnexthop
+{
+ unsigned short rtnh_len;
+ unsigned char rtnh_flags;
+ unsigned char rtnh_hops;
+ int rtnh_ifindex;
+};
+
+/* rtnh_flags */
+
+#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
+#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
+#define RTNH_F_ONLINK 4 /* Gateway is forced on link */
+
+/* Macros to handle hexthops */
+
+#define RTNH_ALIGNTO 4
+#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) )
+#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \
+ ((int)(rtnh)->rtnh_len) <= (len))
+#define RTNH_NEXT(rtnh) ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len)))
+#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len))
+#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len))
+#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
+
+/* RTM_CACHEINFO */
+
+struct rta_cacheinfo
+{
+ uint32_t rta_clntref;
+ uint32_t rta_lastuse;
+ int32_t rta_expires;
+ uint32_t rta_error;
+ uint32_t rta_used;
+
+#define RTNETLINK_HAVE_PEERINFO 1
+ uint32_t rta_id;
+ uint32_t rta_ts;
+ uint32_t rta_tsage;
+};
+
+/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
+
+enum
+{
+ RTAX_UNSPEC,
+#define RTAX_UNSPEC RTAX_UNSPEC
+ RTAX_LOCK,
+#define RTAX_LOCK RTAX_LOCK
+ RTAX_MTU,
+#define RTAX_MTU RTAX_MTU
+ RTAX_WINDOW,
+#define RTAX_WINDOW RTAX_WINDOW
+ RTAX_RTT,
+#define RTAX_RTT RTAX_RTT
+ RTAX_RTTVAR,
+#define RTAX_RTTVAR RTAX_RTTVAR
+ RTAX_SSTHRESH,
+#define RTAX_SSTHRESH RTAX_SSTHRESH
+ RTAX_CWND,
+#define RTAX_CWND RTAX_CWND
+ RTAX_ADVMSS,
+#define RTAX_ADVMSS RTAX_ADVMSS
+ RTAX_REORDERING,
+#define RTAX_REORDERING RTAX_REORDERING
+};
+
+#define RTAX_MAX RTAX_REORDERING
+
+struct rta_session
+{
+ uint8_t proto;
+
+ union {
+ struct {
+ uint16_t sport;
+ uint16_t dport;
+ } ports;
+
+ struct {
+ uint8_t type;
+ uint8_t code;
+ uint16_t ident;
+ } icmpt;
+
+ uint32_t spi;
+ } u;
+};
+
+
+/*********************************************************
+ * Interface address.
+ ****/
+
+struct ifaddrmsg
+{
+ unsigned char ifa_family;
+ unsigned char ifa_prefixlen; /* The prefix length */
+ unsigned char ifa_flags; /* Flags */
+ unsigned char ifa_scope; /* See above */
+ int ifa_index; /* Link index */
+};
+
+enum
+{
+ IFA_UNSPEC,
+ IFA_ADDRESS,
+ IFA_LOCAL,
+ IFA_LABEL,
+ IFA_BROADCAST,
+ IFA_ANYCAST,
+ IFA_CACHEINFO
+};
+
+#define IFA_MAX IFA_CACHEINFO
+
+/* ifa_flags */
+
+#define IFA_F_SECONDARY 0x01
+#define IFA_F_TEMPORARY IFA_F_SECONDARY
+
+#define IFA_F_DEPRECATED 0x20
+#define IFA_F_TENTATIVE 0x40
+#define IFA_F_PERMANENT 0x80
+
+struct ifa_cacheinfo
+{
+ int32_t ifa_prefered;
+ int32_t ifa_valid;
+};
+
+
+#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
+/*
+ Important comment:
+ IFA_ADDRESS is prefix address, rather than local interface address.
+ It makes no difference for normally configured broadcast interfaces,
+ but for point-to-point IFA_ADDRESS is DESTINATION address,
+ local address is supplied in IFA_LOCAL attribute.
+ */
+
+/**************************************************************
+ * Neighbour discovery.
+ ****/
+
+struct ndmsg
+{
+ unsigned char ndm_family;
+ unsigned char ndm_pad1;
+ unsigned short ndm_pad2;
+ int ndm_ifindex; /* Link index */
+ uint16_t ndm_state;
+ uint8_t ndm_flags;
+ uint8_t ndm_type;
+};
+
+enum
+{
+ NDA_UNSPEC,
+ NDA_DST,
+ NDA_LLADDR,
+ NDA_CACHEINFO
+};
+
+#define NDA_MAX NDA_CACHEINFO
+
+#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
+
+/*
+ * Neighbor Cache Entry Flags
+ */
+
+#define NTF_PROXY 0x08 /* == ATF_PUBL */
+#define NTF_ROUTER 0x80
+
+/*
+ * Neighbor Cache Entry States.
+ */
+
+#define NUD_INCOMPLETE 0x01
+#define NUD_REACHABLE 0x02
+#define NUD_STALE 0x04
+#define NUD_DELAY 0x08
+#define NUD_PROBE 0x10
+#define NUD_FAILED 0x20
+
+/* Dummy states */
+#define NUD_NOARP 0x40
+#define NUD_PERMANENT 0x80
+#define NUD_NONE 0x00
+
+
+struct nda_cacheinfo
+{
+ uint32_t ndm_confirmed;
+ uint32_t ndm_used;
+ uint32_t ndm_updated;
+ uint32_t ndm_refcnt;
+};
+
+/****
+ * General form of address family dependent message.
+ ****/
+
+struct rtgenmsg
+{
+ unsigned char rtgen_family;
+};
+
+/*****************************************************************
+ * Link layer specific messages.
+ ****/
+
+/* struct ifinfomsg
+ * passes link level specific information, not dependent
+ * on network protocol.
+ */
+
+struct ifinfomsg
+{
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type; /* ARPHRD_* */
+ int ifi_index; /* Link index */
+ unsigned ifi_flags; /* IFF_* flags */
+ unsigned ifi_change; /* IFF_* change mask */
+};
+
+enum
+{
+ IFLA_UNSPEC,
+ IFLA_ADDRESS,
+ IFLA_BROADCAST,
+ IFLA_IFNAME,
+ IFLA_MTU,
+ IFLA_LINK,
+ IFLA_QDISC,
+ IFLA_STATS,
+ IFLA_COST,
+#define IFLA_COST IFLA_COST
+ IFLA_PRIORITY,
+#define IFLA_PRIORITY IFLA_PRIORITY
+ IFLA_MASTER,
+#define IFLA_MASTER IFLA_MASTER
+ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
+};
+
+
+#define IFLA_MAX IFLA_WIRELESS
+
+#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+
+/* ifi_flags.
+
+ IFF_* flags.
+
+ The only change is:
+ IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+ more not changeable by user. They describe link media
+ characteristics and set by device driver.
+
+ Comments:
+ - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+ - If neiher of these three flags are set;
+ the interface is NBMA.
+
+ - IFF_MULTICAST does not mean anything special:
+ multicasts can be used on all not-NBMA links.
+ IFF_MULTICAST means that this media uses special encapsulation
+ for multicast frames. Apparently, all IFF_POINTOPOINT and
+ IFF_BROADCAST devices are able to use multicasts too.
+ */
+
+/* IFLA_LINK.
+ For usual devices it is equal ifi_index.
+ If it is a "virtual interface" (f.e. tunnel), ifi_link
+ can point to real physical interface (f.e. for bandwidth calculations),
+ or maybe 0, what means, that real media is unknown (usual
+ for IPIP tunnels, when route to endpoint is allowed to change)
+ */
+
+/*****************************************************************
+ * Traffic control messages.
+ ****/
+
+struct tcmsg
+{
+ unsigned char tcm_family;
+ unsigned char tcm__pad1;
+ unsigned short tcm__pad2;
+ int tcm_ifindex;
+ uint32_t tcm_handle;
+ uint32_t tcm_parent;
+ uint32_t tcm_info;
+};
+
+enum
+{
+ TCA_UNSPEC,
+ TCA_KIND,
+ TCA_OPTIONS,
+ TCA_STATS,
+ TCA_XSTATS,
+ TCA_RATE,
+};
+
+#define TCA_MAX TCA_RATE
+
+#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
+#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
+
+
+/* SUMMARY: maximal rtattr understood by kernel */
+
+#define RTATTR_MAX RTA_MAX
+
+/* RTnetlink multicast groups */
+
+#define RTMGRP_LINK 1
+#define RTMGRP_NOTIFY 2
+#define RTMGRP_NEIGH 4
+#define RTMGRP_TC 8
+
+#define RTMGRP_IPV4_IFADDR 0x10
+#define RTMGRP_IPV4_MROUTE 0x20
+#define RTMGRP_IPV4_ROUTE 0x40
+
+#define RTMGRP_IPV6_IFADDR 0x100
+#define RTMGRP_IPV6_MROUTE 0x200
+#define RTMGRP_IPV6_ROUTE 0x400
+
+#define RTMGRP_DECnet_IFADDR 0x1000
+#define RTMGRP_DECnet_ROUTE 0x4000
+
+/* End of information exported to user level */
+
+#endif /* __LINUX_RTNETLINK_H */
diff --git a/programs/pluto/linux26/xfrm.h b/programs/pluto/linux26/xfrm.h
new file mode 100644
index 000000000..4269ae29b
--- /dev/null
+++ b/programs/pluto/linux26/xfrm.h
@@ -0,0 +1,233 @@
+#ifndef _LINUX_XFRM_H
+#define _LINUX_XFRM_H
+
+#include <stdint.h>
+
+/* All of the structures in this file may not change size as they are
+ * passed into the kernel from userspace via netlink sockets.
+ */
+
+/* Structure to encapsulate addresses. I do not want to use
+ * "standard" structure. My apologies.
+ */
+typedef union
+{
+ uint32_t a4;
+ uint32_t a6[4];
+} xfrm_address_t;
+
+/* Ident of a specific xfrm_state. It is used on input to lookup
+ * the state by (spi,daddr,ah/esp) or to store information about
+ * spi, protocol and tunnel address on output.
+ */
+struct xfrm_id
+{
+ xfrm_address_t daddr;
+ uint32_t spi;
+ uint8_t proto;
+};
+
+/* Selector, used as selector both on policy rules (SPD) and SAs. */
+
+struct xfrm_selector
+{
+ xfrm_address_t daddr;
+ xfrm_address_t saddr;
+ uint16_t dport;
+ uint16_t dport_mask;
+ uint16_t sport;
+ uint16_t sport_mask;
+ uint16_t family;
+ uint8_t prefixlen_d;
+ uint8_t prefixlen_s;
+ uint8_t proto;
+ int ifindex;
+ uid_t user;
+};
+
+#define XFRM_INF (~(uint64_t)0)
+
+struct xfrm_lifetime_cfg
+{
+ uint64_t soft_byte_limit;
+ uint64_t hard_byte_limit;
+ uint64_t soft_packet_limit;
+ uint64_t hard_packet_limit;
+ uint64_t soft_add_expires_seconds;
+ uint64_t hard_add_expires_seconds;
+ uint64_t soft_use_expires_seconds;
+ uint64_t hard_use_expires_seconds;
+};
+
+struct xfrm_lifetime_cur
+{
+ uint64_t bytes;
+ uint64_t packets;
+ uint64_t add_time;
+ uint64_t use_time;
+};
+
+struct xfrm_replay_state
+{
+ uint32_t oseq;
+ uint32_t seq;
+ uint32_t bitmap;
+};
+
+struct xfrm_algo {
+ char alg_name[64];
+ int alg_key_len; /* in bits */
+ char alg_key[0];
+};
+
+struct xfrm_stats {
+ uint32_t replay_window;
+ uint32_t replay;
+ uint32_t integrity_failed;
+};
+
+enum
+{
+ XFRM_POLICY_IN = 0,
+ XFRM_POLICY_OUT = 1,
+ XFRM_POLICY_FWD = 2,
+ XFRM_POLICY_MAX = 3
+};
+
+enum
+{
+ XFRM_SHARE_ANY, /* No limitations */
+ XFRM_SHARE_SESSION, /* For this session only */
+ XFRM_SHARE_USER, /* For this user only */
+ XFRM_SHARE_UNIQUE /* Use once */
+};
+
+/* Netlink configuration messages. */
+#define XFRM_MSG_BASE 0x10
+
+#define XFRM_MSG_NEWSA (XFRM_MSG_BASE + 0)
+#define XFRM_MSG_DELSA (XFRM_MSG_BASE + 1)
+#define XFRM_MSG_GETSA (XFRM_MSG_BASE + 2)
+
+#define XFRM_MSG_NEWPOLICY (XFRM_MSG_BASE + 3)
+#define XFRM_MSG_DELPOLICY (XFRM_MSG_BASE + 4)
+#define XFRM_MSG_GETPOLICY (XFRM_MSG_BASE + 5)
+
+#define XFRM_MSG_ALLOCSPI (XFRM_MSG_BASE + 6)
+#define XFRM_MSG_ACQUIRE (XFRM_MSG_BASE + 7)
+#define XFRM_MSG_EXPIRE (XFRM_MSG_BASE + 8)
+
+#define XFRM_MSG_UPDPOLICY (XFRM_MSG_BASE + 9)
+#define XFRM_MSG_UPDSA (XFRM_MSG_BASE + 10)
+
+#define XFRM_MSG_POLEXPIRE (XFRM_MSG_BASE + 11)
+
+#define XFRM_MSG_MAX (XFRM_MSG_POLEXPIRE+1)
+
+struct xfrm_user_tmpl {
+ struct xfrm_id id;
+ uint16_t family;
+ xfrm_address_t saddr;
+ uint32_t reqid;
+ uint8_t mode;
+ uint8_t share;
+ uint8_t optional;
+ uint32_t aalgos;
+ uint32_t ealgos;
+ uint32_t calgos;
+};
+
+struct xfrm_encap_tmpl {
+ uint16_t encap_type;
+ uint16_t encap_sport;
+ uint16_t encap_dport;
+ xfrm_address_t encap_oa;
+};
+
+/* Netlink message attributes. */
+enum xfrm_attr_type_t {
+ XFRMA_UNSPEC,
+ XFRMA_ALG_AUTH, /* struct xfrm_algo */
+ XFRMA_ALG_CRYPT, /* struct xfrm_algo */
+ XFRMA_ALG_COMP, /* struct xfrm_algo */
+ XFRMA_ENCAP, /* struct xfrm_algo + struct xfrm_encap_tmpl */
+ XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */
+
+#define XFRMA_MAX XFRMA_TMPL
+};
+
+struct xfrm_usersa_info {
+ struct xfrm_selector sel;
+ struct xfrm_id id;
+ xfrm_address_t saddr;
+ struct xfrm_lifetime_cfg lft;
+ struct xfrm_lifetime_cur curlft;
+ struct xfrm_stats stats;
+ uint32_t seq;
+ uint32_t reqid;
+ uint16_t family;
+ uint8_t mode; /* 0=transport,1=tunnel */
+ uint8_t replay_window;
+ uint8_t flags;
+#define XFRM_STATE_NOECN 1
+};
+
+struct xfrm_usersa_id {
+ xfrm_address_t daddr;
+ uint32_t spi;
+ uint16_t family;
+ uint8_t proto;
+};
+
+struct xfrm_userspi_info {
+ struct xfrm_usersa_info info;
+ uint32_t min;
+ uint32_t max;
+};
+
+struct xfrm_userpolicy_info {
+ struct xfrm_selector sel;
+ struct xfrm_lifetime_cfg lft;
+ struct xfrm_lifetime_cur curlft;
+ uint32_t priority;
+ uint32_t index;
+ uint8_t dir;
+ uint8_t action;
+#define XFRM_POLICY_ALLOW 0
+#define XFRM_POLICY_BLOCK 1
+ uint8_t flags;
+#define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */
+ uint8_t share;
+};
+
+struct xfrm_userpolicy_id {
+ struct xfrm_selector sel;
+ uint32_t index;
+ uint8_t dir;
+};
+
+struct xfrm_user_acquire {
+ struct xfrm_id id;
+ xfrm_address_t saddr;
+ struct xfrm_selector sel;
+ struct xfrm_userpolicy_info policy;
+ uint32_t aalgos;
+ uint32_t ealgos;
+ uint32_t calgos;
+ uint32_t seq;
+};
+
+struct xfrm_user_expire {
+ struct xfrm_usersa_info state;
+ uint8_t hard;
+};
+
+struct xfrm_user_polexpire {
+ struct xfrm_userpolicy_info pol;
+ uint8_t hard;
+};
+
+#define XFRMGRP_ACQUIRE 1
+#define XFRMGRP_EXPIRE 2
+
+#endif /* _LINUX_XFRM_H */
diff --git a/programs/pluto/log.c b/programs/pluto/log.c
new file mode 100644
index 000000000..137e92980
--- /dev/null
+++ b/programs/pluto/log.c
@@ -0,0 +1,843 @@
+/* error logging functions
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: log.c,v 1.7 2005/07/11 18:33:45 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
+#include <sys/queue.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "server.h"
+#include "state.h"
+#include "connections.h"
+#include "kernel.h"
+#include "whack.h" /* needs connections.h */
+#include "timer.h"
+
+/* close one per-peer log */
+static void perpeer_logclose(struct connection *c); /* forward */
+
+
+bool
+ log_to_stderr = TRUE, /* should log go to stderr? */
+ log_to_syslog = TRUE, /* should log go to syslog? */
+ log_to_perpeer= FALSE; /* should log go to per-IP file? */
+
+bool
+ logged_txt_warning = FALSE; /* should we complain about finding KEY? */
+
+/* should we complain when we find no local id */
+bool
+ logged_myid_fqdn_txt_warning = FALSE,
+ logged_myid_ip_txt_warning = FALSE,
+ logged_myid_fqdn_key_warning = FALSE,
+ logged_myid_ip_key_warning = FALSE;
+
+/* may include trailing / */
+const char *base_perpeer_logdir = PERPEERLOGDIR;
+static int perpeer_count = 0;
+
+/* from sys/queue.h */
+static CIRCLEQ_HEAD(,connection) perpeer_list;
+
+
+/* Context for logging.
+ *
+ * Global variables: must be carefully adjusted at transaction boundaries!
+ * If the context provides a whack file descriptor, messages
+ * should be copied to it -- see whack_log()
+ */
+int whack_log_fd = NULL_FD; /* only set during whack_handle() */
+struct state *cur_state = NULL; /* current state, for diagnostics */
+struct connection *cur_connection = NULL; /* current connection, for diagnostics */
+const ip_address *cur_from = NULL; /* source of current current message */
+u_int16_t cur_from_port; /* host order */
+
+void
+init_log(const char *program)
+{
+ if (log_to_stderr)
+ setbuf(stderr, NULL);
+ if (log_to_syslog)
+ openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
+
+ CIRCLEQ_INIT(&perpeer_list);
+}
+
+void
+close_peerlog(void)
+{
+ /* end of circular queue is given by pointer to "HEAD"
+ * BUT if the queue is not initialized, this won't be true
+ * so we must guard by test perpeer_list.cqh_first != NULL
+ */
+ if (perpeer_list.cqh_first != NULL)
+ while (perpeer_list.cqh_first != (void *)&perpeer_list)
+ perpeer_logclose(perpeer_list.cqh_first);
+}
+
+void
+close_log(void)
+{
+ if (log_to_syslog)
+ closelog();
+
+ close_peerlog();
+}
+
+/* Sanitize character string in situ: turns dangerous characters into \OOO.
+ * With a bit of work, we could use simpler reps for \\, \r, etc.,
+ * but this is only to protect against something that shouldn't be used.
+ * Truncate resulting string to what fits in buffer.
+ */
+static size_t
+sanitize(char *buf, size_t size)
+{
+# define UGLY_WIDTH 4 /* width for ugly character: \OOO */
+ size_t len;
+ size_t added = 0;
+ char *p;
+
+ passert(size >= UGLY_WIDTH); /* need room to swing cat */
+
+ /* find right side of string to be sanitized and count
+ * number of columns to be added. Stop on end of string
+ * or lack of room for more result.
+ */
+ for (p = buf; *p != '\0' && &p[added] < &buf[size - UGLY_WIDTH]; )
+ {
+ unsigned char c = *p++;
+
+ if (c == '\\' || !isprint(c))
+ added += UGLY_WIDTH - 1;
+ }
+
+ /* at this point, p points after last original character to be
+ * included. added is how many characters are added to sanitize.
+ * so p[added] will point after last sanitized character.
+ */
+
+ p[added] = '\0';
+ len = &p[added] - buf;
+
+ /* scan backwards, copying characters to their new home
+ * and inserting the expansions for ugly characters.
+ * It is finished when no more shifting is required.
+ * This is a predecrement loop.
+ */
+ while (added != 0)
+ {
+ char fmtd[UGLY_WIDTH + 1];
+ unsigned char c;
+
+ while ((c = *--p) != '\\' && isprint(c))
+ p[added] = c;
+ added -= UGLY_WIDTH - 1;
+ snprintf(fmtd, sizeof(fmtd), "\\%03o", c);
+ memcpy(p + added, fmtd, UGLY_WIDTH);
+ }
+ return len;
+# undef UGLY_WIDTH
+}
+
+/* format a string for the log, with suitable prefixes.
+ * A format starting with ~ indicates that this is a reprocessing
+ * of the message, so prefixing and quoting is suppressed.
+ */
+static void
+fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap)
+{
+ bool reproc = *fmt == '~';
+ size_t ps;
+ struct connection *c = cur_state != NULL ? cur_state->st_connection
+ : cur_connection;
+
+ buf[0] = '\0';
+ if (reproc)
+ fmt++; /* ~ at start of format suppresses this prefix */
+ else if (c != NULL)
+ {
+ /* start with name of connection */
+ char *const be = buf + buf_len;
+ char *bp = buf;
+
+ snprintf(bp, be - bp, "\"%s\"", c->name);
+ bp += strlen(bp);
+
+ /* if it fits, put in any connection instance information */
+ if (be - bp > CONN_INST_BUF)
+ {
+ fmt_conn_instance(c, bp);
+ bp += strlen(bp);
+ }
+
+ if (cur_state != NULL)
+ {
+ /* state number */
+ snprintf(bp, be - bp, " #%lu", cur_state->st_serialno);
+ bp += strlen(bp);
+ }
+ snprintf(bp, be - bp, ": ");
+ }
+ else if (cur_from != NULL)
+ {
+ /* peer's IP address */
+ /* Note: must not use ip_str() because our caller might! */
+ char ab[ADDRTOT_BUF];
+
+ (void) addrtot(cur_from, 0, ab, sizeof(ab));
+ snprintf(buf, buf_len, "packet from %s:%u: "
+ , ab, (unsigned)cur_from_port);
+ }
+
+ ps = strlen(buf);
+ vsnprintf(buf + ps, buf_len - ps, fmt, ap);
+ if (!reproc)
+ (void)sanitize(buf, buf_len);
+}
+
+static void
+perpeer_logclose(struct connection *c)
+{
+ /* only free/close things if we had used them! */
+ if (c->log_file != NULL)
+ {
+ passert(perpeer_count > 0);
+
+ CIRCLEQ_REMOVE(&perpeer_list, c, log_link);
+ perpeer_count--;
+ fclose(c->log_file);
+ c->log_file=NULL;
+ }
+}
+
+void
+perpeer_logfree(struct connection *c)
+{
+ perpeer_logclose(c);
+ if (c->log_file_name != NULL)
+ {
+ pfree(c->log_file_name);
+ c->log_file_name = NULL;
+ c->log_file_err = FALSE;
+ }
+}
+
+/* open the per-peer log */
+static void
+open_peerlog(struct connection *c)
+{
+ syslog(LOG_INFO, "opening log file for conn %s", c->name);
+
+ if (c->log_file_name == NULL)
+ {
+ char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF];
+ int peernamelen, lf_len;
+
+ addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername));
+ peernamelen = strlen(peername);
+
+ /* copy IP address, turning : and . into / */
+ {
+ char c, *p, *q;
+
+ p = peername;
+ q = dname;
+ do {
+ c = *p++;
+ if (c == '.' || c == ':')
+ c = '/';
+ *q++ = c;
+ } while (c != '\0');
+ }
+
+ lf_len = peernamelen * 2
+ + strlen(base_perpeer_logdir)
+ + sizeof("//.log")
+ + 1;
+ c->log_file_name = alloc_bytes(lf_len, "per-peer log file name");
+
+ fprintf(stderr, "base dir |%s| dname |%s| peername |%s|"
+ , base_perpeer_logdir, dname, peername);
+ snprintf(c->log_file_name, lf_len, "%s/%s/%s.log"
+ , base_perpeer_logdir, dname, peername);
+
+ syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name);
+ }
+
+ /* now open the file, creating directories if necessary */
+
+ { /* create the directory */
+ char *dname;
+ int bpl_len = strlen(base_perpeer_logdir);
+ char *slashloc;
+
+ dname = clone_str(c->log_file_name, "temp copy of file name");
+ dname = dirname(dname);
+
+ if (access(dname, W_OK) != 0)
+ {
+ if (errno != ENOENT)
+ {
+ if (c->log_file_err)
+ {
+ syslog(LOG_CRIT, "can not write to %s: %s"
+ , dname, strerror(errno));
+ c->log_file_err = TRUE;
+ pfree(dname);
+ return;
+ }
+ }
+
+ /* directory does not exist, walk path creating dirs */
+ /* start at base_perpeer_logdir */
+ slashloc = dname + bpl_len;
+ slashloc++; /* since, by construction there is a slash
+ right there */
+
+ while (*slashloc != '\0')
+ {
+ char saveslash;
+
+ /* look for next slash */
+ while (*slashloc != '\0' && *slashloc != '/') slashloc++;
+
+ saveslash = *slashloc;
+
+ *slashloc = '\0';
+
+ if (mkdir(dname, 0750) != 0 && errno != EEXIST)
+ {
+ syslog(LOG_CRIT, "can not create dir %s: %s"
+ , dname, strerror(errno));
+ c->log_file_err = TRUE;
+ pfree(dname);
+ return;
+ }
+ syslog(LOG_DEBUG, "created new directory %s", dname);
+ *slashloc = saveslash;
+ slashloc++;
+ }
+ }
+
+ pfree(dname);
+ }
+
+ c->log_file = fopen(c->log_file_name, "a");
+ if (c->log_file == NULL)
+ {
+ if (c->log_file_err)
+ {
+ syslog(LOG_CRIT, "logging system can not open %s: %s"
+ , c->log_file_name, strerror(errno));
+ c->log_file_err = TRUE;
+ }
+ return;
+ }
+
+ /* look for a connection to close! */
+ while (perpeer_count >= MAX_PEERLOG_COUNT)
+ {
+ /* can not be NULL because perpeer_count > 0 */
+ passert(perpeer_list.cqh_last != (void *)&perpeer_list);
+
+ perpeer_logclose(perpeer_list.cqh_last);
+ }
+
+ /* insert this into the list */
+ CIRCLEQ_INSERT_HEAD(&perpeer_list, c, log_link);
+ passert(c->log_file != NULL);
+ perpeer_count++;
+}
+
+/* log a line to cur_connection's log */
+static void
+peerlog(const char *prefix, const char *m)
+{
+ if (cur_connection == NULL)
+ {
+ /* we can not log it in this case. Oh well. */
+ return;
+ }
+
+ if (cur_connection->log_file == NULL)
+ {
+ open_peerlog(cur_connection);
+ }
+
+ /* despite our attempts above, we may not be able to open the file. */
+ if (cur_connection->log_file != NULL)
+ {
+ char datebuf[32];
+ time_t n;
+ struct tm *t;
+
+ time(&n);
+ t = localtime(&n);
+
+ strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t);
+ fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m);
+
+ /* now move it to the front of the list */
+ CIRCLEQ_REMOVE(&perpeer_list, cur_connection, log_link);
+ CIRCLEQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link);
+ }
+}
+
+void
+plog(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m);
+ if (log_to_perpeer)
+ peerlog("", m);
+
+ whack_log(RC_LOG, "~%s", m);
+}
+
+void
+loglog(int mess_no, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m);
+ if (log_to_perpeer)
+ peerlog("", m);
+
+ whack_log(mess_no, "~%s", m);
+}
+
+void
+log_errno_routine(int e, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
+ if (log_to_syslog)
+ syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e));
+ if (log_to_perpeer)
+ {
+ peerlog(strerror(e), m);
+ }
+
+ whack_log(RC_LOG_SERIOUS
+ , "~ERROR: %s. Errno %d: %s", m, e, strerror(e));
+}
+
+void
+exit_log(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "FATAL ERROR: %s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_ERR, "FATAL ERROR: %s", m);
+ if (log_to_perpeer)
+ peerlog("FATAL ERROR: ", m);
+
+ whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m);
+
+ exit_pluto(1);
+}
+
+void
+exit_log_errno_routine(int e, const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ fmt_log(m, sizeof(m), message, args);
+ va_end(args);
+
+ if (log_to_stderr)
+ fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
+ if (log_to_syslog)
+ syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
+ if (log_to_perpeer)
+ peerlog(strerror(e), m);
+
+ whack_log(RC_LOG_SERIOUS
+ , "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
+
+ exit_pluto(1);
+}
+
+/* emit message to whack.
+ * form is "ddd statename text" where
+ * - ddd is a decimal status code (RC_*) as described in whack.h
+ * - text is a human-readable annotation
+ */
+#ifdef DEBUG
+static volatile sig_atomic_t dying_breath = FALSE;
+#endif
+
+void
+whack_log(int mess_no, const char *message, ...)
+{
+ int wfd = whack_log_fd != NULL_FD ? whack_log_fd
+ : cur_state != NULL ? cur_state->st_whack_sock
+ : NULL_FD;
+
+ if (wfd != NULL_FD
+#ifdef DEBUG
+ || dying_breath
+#endif
+ )
+ {
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+ int prelen = snprintf(m, sizeof(m), "%03d ", mess_no);
+
+ passert(prelen >= 0);
+
+ va_start(args, message);
+ fmt_log(m+prelen, sizeof(m)-prelen, message, args);
+ va_end(args);
+
+#if DEBUG
+ if (dying_breath)
+ {
+ /* status output copied to log */
+ if (log_to_stderr)
+ fprintf(stderr, "%s\n", m + prelen);
+ if (log_to_syslog)
+ syslog(LOG_WARNING, "%s", m + prelen);
+ if (log_to_perpeer)
+ peerlog("", m);
+ }
+#endif
+
+ if (wfd != NULL_FD)
+ {
+ /* write to whack socket, but suppress possible SIGPIPE */
+ size_t len = strlen(m);
+#ifdef MSG_NOSIGNAL /* depends on version of glibc??? */
+ m[len] = '\n'; /* don't need NUL, do need NL */
+ (void) send(wfd, m, len + 1, MSG_NOSIGNAL);
+#else /* !MSG_NOSIGNAL */
+ int r;
+ struct sigaction act
+ , oldact;
+
+ m[len] = '\n'; /* don't need NUL, do need NL */
+ act.sa_handler = SIG_IGN;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0; /* no nothing */
+ r = sigaction(SIGPIPE, &act, &oldact);
+ passert(r == 0);
+
+ (void) write(wfd, m, len + 1);
+
+ r = sigaction(SIGPIPE, &oldact, NULL);
+ passert(r == 0);
+#endif /* !MSG_NOSIGNAL */
+ }
+ }
+}
+
+/* Build up a diagnostic in a static buffer.
+ * Although this would be a generally useful function, it is very
+ * hard to come up with a discipline that prevents different uses
+ * from interfering. It is intended that by limiting it to building
+ * diagnostics, we will avoid this problem.
+ * Juggling is performed to allow an argument to be a previous
+ * result: the new string may safely depend on the old one. This
+ * restriction is not checked in any way: violators will produce
+ * confusing results (without crashing!).
+ */
+char diag_space[sizeof(diag_space)];
+
+err_t
+builddiag(const char *fmt, ...)
+{
+ static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */
+ char t[sizeof(diag_space)]; /* build result here first */
+ va_list args;
+
+ va_start(args, fmt);
+ t[0] = '\0'; /* in case nothing terminates string */
+ vsnprintf(t, sizeof(t), fmt, args);
+ va_end(args);
+ strcpy(diag_space, t);
+ return diag_space;
+}
+
+/* Debugging message support */
+
+#ifdef DEBUG
+
+void
+switch_fail(int n, const char *file_str, unsigned long line_no)
+{
+ char buf[30];
+
+ snprintf(buf, sizeof(buf), "case %d unexpected", n);
+ passert_fail(buf, file_str, line_no);
+}
+
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ /* we will get a possibly unplanned prefix. Hope it works */
+ loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+ if (!dying_breath)
+ {
+ dying_breath = TRUE;
+ show_status(TRUE, NULL);
+ }
+ abort(); /* exiting correctly doesn't always work */
+}
+
+void
+pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+ /* we will get a possibly unplanned prefix. Hope it works */
+ loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+}
+
+lset_t
+ base_debugging = DBG_NONE, /* default to reporting nothing */
+ cur_debugging = DBG_NONE;
+
+void
+extra_debugging(const struct connection *c)
+{
+ if(c == NULL)
+ {
+ reset_debugging();
+ return;
+ }
+
+ if (c!= NULL && c->extra_debugging != 0)
+ {
+ plog("enabling for connection: %s"
+ , bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging));
+ cur_debugging |= c->extra_debugging;
+ }
+}
+
+/* log a debugging message (prefixed by "| ") */
+
+void
+DBG_log(const char *message, ...)
+{
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ (void)sanitize(m, sizeof(m));
+
+ if (log_to_stderr)
+ fprintf(stderr, "| %s\n", m);
+ if (log_to_syslog)
+ syslog(LOG_DEBUG, "| %s", m);
+ if (log_to_perpeer)
+ peerlog("| ", m);
+}
+
+/* dump raw bytes in hex to stderr (for lack of any better destination) */
+
+void
+DBG_dump(const char *label, const void *p, size_t len)
+{
+# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */
+# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1)
+ char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH];
+ char *bp;
+ const unsigned char *cp = p;
+
+ bp = buf;
+
+ if (label != NULL && label[0] != '\0')
+ {
+ /* Handle the label. Care must be taken to avoid buffer overrun. */
+ size_t llen = strlen(label);
+
+ if (llen + 1 > sizeof(buf))
+ {
+ DBG_log("%s", label);
+ }
+ else
+ {
+ strcpy(buf, label);
+ if (buf[llen-1] == '\n')
+ {
+ buf[llen-1] = '\0'; /* get rid of newline */
+ DBG_log("%s", buf);
+ }
+ else if (llen < DUMP_LABEL_WIDTH)
+ {
+ bp = buf + llen;
+ }
+ else
+ {
+ DBG_log("%s", buf);
+ }
+ }
+ }
+
+ do {
+ int i, j;
+
+ for (i = 0; len!=0 && i!=4; i++)
+ {
+ *bp++ = ' ';
+ for (j = 0; len!=0 && j!=4; len--, j++)
+ {
+ static const char hexdig[] = "0123456789abcdef";
+
+ *bp++ = ' ';
+ *bp++ = hexdig[(*cp >> 4) & 0xF];
+ *bp++ = hexdig[*cp & 0xF];
+ cp++;
+ }
+ }
+ *bp = '\0';
+ DBG_log("%s", buf);
+ bp = buf;
+ } while (len != 0);
+# undef DUMP_LABEL_WIDTH
+# undef DUMP_WIDTH
+}
+
+#endif /* DEBUG */
+
+void
+show_status(bool all, const char *name)
+{
+ if (all)
+ {
+ show_ifaces_status();
+ show_myid_status();
+ show_debug_status();
+ }
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
+ show_connections_status(all, name);
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
+ show_states_status(name);
+#ifdef KLIPS
+ whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
+ show_shunt_status();
+#endif
+}
+
+/* ip_str: a simple to use variant of addrtot.
+ * It stores its result in a static buffer.
+ * This means that newer calls overwrite the storage of older calls.
+ * Note: this is not used in any of the logging functions, so their
+ * callers may use it.
+ */
+const char *
+ip_str(const ip_address *src)
+{
+ static char buf[ADDRTOT_BUF];
+
+ addrtot(src, 0, buf, sizeof(buf));
+ return buf;
+}
+
+/*
+ * a routine that attempts to schedule itself daily.
+ *
+ */
+
+void
+daily_log_reset(void)
+{
+ /* now perform actions */
+ logged_txt_warning = FALSE;
+
+ logged_myid_fqdn_txt_warning = FALSE;
+ logged_myid_ip_txt_warning = FALSE;
+ logged_myid_fqdn_key_warning = FALSE;
+ logged_myid_ip_key_warning = FALSE;
+}
+
+void
+daily_log_event(void)
+{
+ struct tm *ltime;
+ time_t n, interval;
+
+ /* attempt to schedule oneself to midnight, local time
+ * do this by getting seconds in the day, and delaying
+ * by 86400 - hour*3600+minutes*60+seconds.
+ */
+ time(&n);
+ ltime = localtime(&n);
+ interval = (24 * 60 * 60)
+ - (ltime->tm_sec
+ + ltime->tm_min * 60
+ + ltime->tm_hour * 3600);
+
+ event_schedule(EVENT_LOG_DAILY, interval, NULL);
+
+ daily_log_reset();
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/programs/pluto/log.h b/programs/pluto/log.h
new file mode 100644
index 000000000..0bf8219aa
--- /dev/null
+++ b/programs/pluto/log.h
@@ -0,0 +1,236 @@
+/* logging definitions
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: log.h,v 1.4 2005/07/11 18:33:45 as Exp $
+ */
+
+#include <freeswan.h>
+
+#define LOG_WIDTH 1024 /* roof of number of chars in log line */
+
+#ifndef PERPERRLOGDIR
+#define PERPERRLOGDIR "/var/log/pluto/peer"
+#endif
+
+/* our versions of assert: log result */
+
+#ifdef DEBUG
+
+extern void passert_fail(const char *pred_str
+ , const char *file_str, unsigned long line_no) NEVER_RETURNS;
+
+extern void pexpect_log(const char *pred_str
+ , const char *file_str, unsigned long line_no);
+
+# define impossible() passert_fail("impossible", __FILE__, __LINE__)
+
+extern void switch_fail(int n
+ , const char *file_str, unsigned long line_no) NEVER_RETURNS;
+
+# define bad_case(n) switch_fail((int) n, __FILE__, __LINE__)
+
+# define passert(pred) { \
+ if (!(pred)) \
+ passert_fail(#pred, __FILE__, __LINE__); \
+ }
+
+# define pexpect(pred) { \
+ if (!(pred)) \
+ pexpect_log(#pred, __FILE__, __LINE__); \
+ }
+
+/* assert that an err_t is NULL; evaluate exactly once */
+# define happy(x) { \
+ err_t ugh = x; \
+ if (ugh != NULL) \
+ passert_fail(ugh, __FILE__, __LINE__); \
+ }
+
+#else /*!DEBUG*/
+
+# define impossible() abort()
+# define bad_case(n) abort()
+# define passert(pred) { } /* do nothing */
+# define happy(x) { (void) x; } /* evaluate non-judgementally */
+
+#endif /*!DEBUG*/
+
+
+extern bool
+ log_to_stderr, /* should log go to stderr? */
+ log_to_syslog, /* should log go to syslog? */
+ log_to_perpeer; /* should log go to per-IP file? */
+
+extern const char *base_perpeer_logdir;
+
+/* maximum number of files to keep open for per-peer log files */
+#define MAX_PEERLOG_COUNT 16
+
+/* Context for logging.
+ *
+ * Global variables: must be carefully adjusted at transaction boundaries!
+ * All are to be left in RESET condition and will be checked.
+ * There are several pairs of routines to set and reset them.
+ * If the context provides a whack file descriptor, messages
+ * should be copied to it -- see whack_log()
+ */
+extern int whack_log_fd; /* only set during whack_handle() */
+extern struct state *cur_state; /* current state, for diagnostics */
+extern struct connection *cur_connection; /* current connection, for diagnostics */
+extern const ip_address *cur_from; /* source of current current message */
+extern u_int16_t cur_from_port; /* host order */
+
+#ifdef DEBUG
+
+ extern lset_t cur_debugging; /* current debugging level */
+
+ extern void extra_debugging(const struct connection *c);
+
+# define reset_debugging() { cur_debugging = base_debugging; }
+
+# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \
+ && cur_state == NULL \
+ && cur_connection == NULL \
+ && cur_from == NULL \
+ && cur_debugging == base_debugging)
+
+#else /*!DEBUG*/
+
+# define extra_debugging(c) { }
+
+# define reset_debugging() { }
+
+# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \
+ && cur_state == NULL \
+ && cur_connection == NULL \
+ && cur_from == NULL)
+
+#endif /*!DEBUG*/
+
+#define reset_globals() { \
+ whack_log_fd = NULL_FD; \
+ cur_state = NULL; \
+ cur_from = NULL; \
+ reset_cur_connection(); \
+ }
+
+
+#define set_cur_connection(c) { \
+ cur_connection = (c); \
+ extra_debugging(c); \
+ }
+
+#define reset_cur_connection() { \
+ cur_connection = NULL; \
+ reset_debugging(); \
+ }
+
+
+#define set_cur_state(s) { \
+ cur_state = (s); \
+ extra_debugging((s)->st_connection); \
+ }
+
+#define reset_cur_state() { \
+ cur_state = NULL; \
+ reset_debugging(); \
+ }
+
+extern void init_log(const char *program);
+extern void close_log(void);
+extern void plog(const char *message, ...) PRINTF_LIKE(1);
+extern void exit_log(const char *message, ...) PRINTF_LIKE(1) NEVER_RETURNS;
+
+/* close of all per-peer logging */
+extern void close_peerlog(void);
+
+/* free all per-peer log resources */
+extern void perpeer_logfree(struct connection *c);
+
+
+
+/* the following routines do a dance to capture errno before it is changed
+ * A call must doubly parenthesize the argument list (no varargs macros).
+ * The first argument must be "e", the local variable that captures errno.
+ */
+#define log_errno(a) { int e = errno; log_errno_routine a; }
+extern void log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2);
+#define exit_log_errno(a) { int e = errno; exit_log_errno_routine a; }
+extern void exit_log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2) NEVER_RETURNS NEVER_RETURNS;
+
+extern void whack_log(int mess_no, const char *message, ...) PRINTF_LIKE(2);
+
+/* Log to both main log and whack log
+ * Much like log, actually, except for specifying mess_no.
+ */
+extern void loglog(int mess_no, const char *message, ...) PRINTF_LIKE(2);
+
+/* show status, usually on whack log */
+extern void show_status(bool all, const char *name);
+
+/* Build up a diagnostic in a static buffer.
+ * Although this would be a generally useful function, it is very
+ * hard to come up with a discipline that prevents different uses
+ * from interfering. It is intended that by limiting it to building
+ * diagnostics, we will avoid this problem.
+ * Juggling is performed to allow an argument to be a previous
+ * result: the new string may safely depend on the old one. This
+ * restriction is not checked in any way: violators will produce
+ * confusing results (without crashing!).
+ */
+extern char diag_space[LOG_WIDTH]; /* output buffer, but can be occupied at call */
+extern err_t builddiag(const char *fmt, ...) PRINTF_LIKE(1);
+
+#ifdef DEBUG
+
+extern lset_t base_debugging; /* bits selecting what to report */
+
+#define DBGP(cond) (cur_debugging & (cond))
+#define DBG(cond, action) { if (DBGP(cond)) { action ; } }
+
+extern void DBG_log(const char *message, ...) PRINTF_LIKE(1);
+extern void DBG_dump(const char *label, const void *p, size_t len);
+#define DBG_dump_chunk(label, ch) DBG_dump(label, (ch).ptr, (ch).len)
+
+#else /*!DEBUG*/
+
+#define DBG(cond, action) { } /* do nothing */
+
+#endif /*!DEBUG*/
+
+#define DBG_cond_dump(cond, label, p, len) DBG(cond, DBG_dump(label, p, len))
+#define DBG_cond_dump_chunk(cond, label, ch) DBG(cond, DBG_dump_chunk(label, ch))
+
+
+/* ip_str: a simple to use variant of addrtot.
+ * It stores its result in a static buffer.
+ * This means that newer calls overwrite the storage of older calls.
+ * Note: this is not used in any of the logging functions, so their
+ * callers may use it.
+ */
+extern const char *ip_str(const ip_address *src);
+
+/*
+ * call this routine to reset daily items.
+ */
+extern void daily_log_reset(void);
+extern void daily_log_event(void);
+
+/*
+ * some events are to be logged only occasionally.
+ */
+extern bool logged_txt_warning;
+extern bool logged_myid_ip_txt_warning;
+extern bool logged_myid_ip_key_warning;
+extern bool logged_myid_fqdn_txt_warning;
+extern bool logged_myid_fqdn_key_warning;
diff --git a/programs/pluto/md2.c b/programs/pluto/md2.c
new file mode 100644
index 000000000..d6465477d
--- /dev/null
+++ b/programs/pluto/md2.c
@@ -0,0 +1,237 @@
+/* MD2C.C - RSA Data Security, Inc., MD2 message-digest algorithm
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ rights reserved.
+
+ License to copy and use this software is granted for
+ non-commercial Internet Privacy-Enhanced Mail provided that it is
+ identified as the "RSA Data Security, Inc. MD2 Message Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include "md2.h"
+
+#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */
+
+static void MD2Transform PROTO_LIST
+ ((unsigned char [16], unsigned char [16], const unsigned char [16]));
+
+#ifdef HAVEMEMCOPY
+#include <memory.h>
+#define MD2_memcpy memcpy
+#define MD2_memset memset
+#else
+#ifdef HAVEBCOPY
+#define MD2_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c))
+#define MD2_memset(_a,_b,_c) memset((_a), '\0',(_c))
+#else
+static void MD2_memcpy PROTO_LIST ((POINTER, CONST_POINTER, unsigned int));
+static void MD2_memset PROTO_LIST ((POINTER, int, unsigned int));
+#endif
+#endif
+
+/* Permutation of 0..255 constructed from the digits of pi. It gives a
+ "random" nonlinear byte substitution operation.
+ */
+static unsigned char PI_SUBST[256] = {
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+static const unsigned char *PADDING[] = {
+ (const unsigned char *)"",
+ (const unsigned char *)"\001",
+ (const unsigned char *)"\002\002",
+ (const unsigned char *)"\003\003\003",
+ (const unsigned char *)"\004\004\004\004",
+ (const unsigned char *)"\005\005\005\005\005",
+ (const unsigned char *)"\006\006\006\006\006\006",
+ (const unsigned char *)"\007\007\007\007\007\007\007",
+ (const unsigned char *)"\010\010\010\010\010\010\010\010",
+ (const unsigned char *)"\011\011\011\011\011\011\011\011\011",
+ (const unsigned char *)"\012\012\012\012\012\012\012\012\012\012",
+ (const unsigned char *)"\013\013\013\013\013\013\013\013\013\013\013",
+ (const unsigned char *)"\014\014\014\014\014\014\014\014\014\014\014\014",
+ (const unsigned char *)
+ "\015\015\015\015\015\015\015\015\015\015\015\015\015",
+ (const unsigned char *)
+ "\016\016\016\016\016\016\016\016\016\016\016\016\016\016",
+ (const unsigned char *)
+ "\017\017\017\017\017\017\017\017\017\017\017\017\017\017\017",
+ (const unsigned char *)
+ "\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020"
+};
+
+/* MD2 initialization. Begins an MD2 operation, writing a new context.
+ */
+void MD2Init (context)
+MD2_CTX *context; /* context */
+{
+ context->count = 0;
+ MD2_memset ((POINTER)context->state, 0, sizeof (context->state));
+ MD2_memset
+ ((POINTER)context->checksum, 0, sizeof (context->checksum));
+}
+
+/* MD2 block update operation. Continues an MD2 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD2Update (context, input, inputLen)
+MD2_CTX *context; /* context */
+const unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Update number of bytes mod 16 */
+ index = context->count;
+ context->count = (index + inputLen) & 0xf;
+
+ partLen = 16 - index;
+
+ /* Transform as many times as possible.
+ */
+ if (inputLen >= partLen) {
+ MD2_memcpy
+ ((POINTER)&context->buffer[index], (CONST_POINTER)input, partLen);
+ MD2Transform (context->state, context->checksum, context->buffer);
+
+ for (i = partLen; i + 15 < inputLen; i += 16)
+ MD2Transform (context->state, context->checksum, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD2_memcpy
+ ((POINTER)&context->buffer[index], (CONST_POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD2 finalization. Ends an MD2 message-digest operation, writing the
+ message digest and zeroizing the context.
+ */
+void MD2Final (digest, context)
+
+unsigned char digest[16]; /* message digest */
+MD2_CTX *context; /* context */
+{
+ unsigned int index, padLen;
+
+ /* Pad out to multiple of 16.
+ */
+ index = context->count;
+ padLen = 16 - index;
+ MD2Update (context, PADDING[padLen], padLen);
+
+ /* Extend with checksum */
+ MD2Update (context, context->checksum, 16);
+
+ /* Store state in digest */
+ MD2_memcpy ((POINTER)digest, (POINTER)context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ MD2_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD2 basic transformation. Transforms state and updates checksum
+ based on block.
+ */
+static void MD2Transform (state, checksum, block)
+unsigned char state[16];
+unsigned char checksum[16];
+const unsigned char block[16];
+{
+ unsigned int i, j, t;
+ unsigned char x[48];
+
+ /* Form encryption block from state, block, state ^ block.
+ */
+ MD2_memcpy ((POINTER)x, (CONST_POINTER)state, 16);
+ MD2_memcpy ((POINTER)x+16, (CONST_POINTER)block, 16);
+ for (i = 0; i < 16; i++)
+ x[i+32] = state[i] ^ block[i];
+
+ /* Encrypt block (18 rounds).
+ */
+ t = 0;
+ for (i = 0; i < 18; i++) {
+ for (j = 0; j < 48; j++)
+ t = x[j] ^= PI_SUBST[t];
+ t = (t + i) & 0xff;
+ }
+
+ /* Save new state */
+ MD2_memcpy ((POINTER)state, (POINTER)x, 16);
+
+ /* Update checksum.
+ */
+ t = checksum[15];
+ for (i = 0; i < 16; i++)
+ t = checksum[i] ^= PI_SUBST[block[i] ^ t];
+
+ /* Zeroize sensitive information.
+ */
+ MD2_memset ((POINTER)x, 0, sizeof (x));
+}
+
+#ifndef HAVEMEMCOPY
+#ifndef HAVEBCOPY
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+static void MD2_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD2_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
+#endif
+
diff --git a/programs/pluto/md2.h b/programs/pluto/md2.h
new file mode 100644
index 000000000..b3b48dd92
--- /dev/null
+++ b/programs/pluto/md2.h
@@ -0,0 +1,72 @@
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+typedef const unsigned char *CONST_POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+#endif
+
+/* MD2.H - header file for MD2C.C
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ rights reserved.
+
+ License to copy and use this software is granted for
+ non-commercial Internet Privacy-Enhanced Mail provided that it is
+ identified as the "RSA Data Security, Inc. MD2 Message Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+/* MD2 context. */
+typedef struct {
+ unsigned char state[16]; /* state */
+ unsigned char checksum[16]; /* checksum */
+ unsigned int count; /* number of bytes, modulo 16 */
+ unsigned char buffer[16]; /* input buffer */
+} MD2_CTX;
+
+void MD2Init PROTO_LIST ((MD2_CTX *));
+void MD2Update PROTO_LIST
+ ((MD2_CTX *, const unsigned char *, unsigned int));
+void MD2Final PROTO_LIST ((unsigned char [16], MD2_CTX *));
+
+#define _MD2_H_
diff --git a/programs/pluto/md5.c b/programs/pluto/md5.c
new file mode 100644
index 000000000..5d75e38a4
--- /dev/null
+++ b/programs/pluto/md5.c
@@ -0,0 +1,385 @@
+/*
+ * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
+ * changes to accomodate it in the kernel by ji.
+ * Minor changes to make 64 bit clean by Peter Onion (i.e. using u_int*_t).
+ */
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/*
+ * Additions by JI
+ *
+ * HAVEMEMCOPY is defined if mem* routines are available
+ *
+ * HAVEHTON is defined if htons() and htonl() can be used
+ * for big/little endian conversions
+ *
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <sys/types.h> /* for u_int*_t */
+#include <endian.h> /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */
+
+#include "md5.h"
+
+#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+#define MD5Transform _MD5Transform
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define Encode MD5_memcpy
+#define Decode MD5_memcpy
+#else
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+#endif
+
+#ifdef HAVEMEMCOPY
+#include <memory.h>
+#define MD5_memcpy memcpy
+#define MD5_memset memset
+#else
+#ifdef HAVEBCOPY
+#define MD5_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c))
+#define MD5_memset(_a,_b,_c) memset((_a), '\0',(_c))
+#else
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+#endif
+#endif
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+const unsigned char *input; /* input block */
+UINT4 inputLen; /* length of input block */
+{
+ UINT4 i;
+ unsigned int index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += (inputLen << 3)) < (inputLen << 3))
+ context->count[1]++;
+ context->count[1] += (inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible. */
+ if (inputLen >= partLen) {
+ MD5_memcpy((POINTER)&context->buffer[index], (CONSTPOINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy((POINTER)&context->buffer[index], (CONSTPOINTER)&input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ if (digest != NULL) /* Bill Simpson's padding */
+ {
+ /* store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+ }
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+const unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+#if BYTE_ORDER != LITTLE_ENDIAN
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#endif
+
+#ifndef HAVEMEMCOPY
+#ifndef HAVEBCOPY
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
+#endif
+
diff --git a/programs/pluto/md5.h b/programs/pluto/md5.h
new file mode 100644
index 000000000..9b29bc46e
--- /dev/null
+++ b/programs/pluto/md5.h
@@ -0,0 +1,75 @@
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+typedef const unsigned char *CONSTPOINTER;
+
+/* UINT2 defines a two byte word */
+typedef u_int16_t UINT2;
+
+/* UINT4 defines a four byte word */
+typedef u_int32_t UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+#endif
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+ ((MD5_CTX *, const unsigned char *, UINT4));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+#define _MD5_H_
diff --git a/programs/pluto/modecfg.c b/programs/pluto/modecfg.c
new file mode 100644
index 000000000..1c22845a5
--- /dev/null
+++ b/programs/pluto/modecfg.c
@@ -0,0 +1,798 @@
+/* Mode config related functions
+ * Copyright (C) 2001-2002 Colubris Networks
+ * Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc.
+ * Copyright (C) 2003-2004 Xelerance Corporation
+ *
+ * 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: modecfg.c,v 1.6 2006/04/24 20:44:57 as Exp $
+ *
+ * This code originally written by Colubris Networks, Inc.
+ * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation
+ * Porting to 2.x by Sean Mathews
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "state.h"
+#include "demux.h"
+#include "timer.h"
+#include "ipsec_doi.h"
+#include "log.h"
+#include "md5.h"
+#include "sha1.h"
+#include "crypto.h"
+#include "modecfg.h"
+#include "whack.h"
+
+/*
+ * Addresses assigned (usually via MODE_CONFIG) to the Initiator
+ */
+struct internal_addr
+{
+ ip_address ipaddr;
+ ip_address dns[2];
+ ip_address wins[2];
+};
+
+/*
+ * Get inside IP address for a connection
+ */
+static void
+get_internal_addresses(struct connection *c, struct internal_addr *ia)
+{
+ zero(ia);
+
+ if (isanyaddr(&c->spd.that.host_srcip))
+ {
+ /* not defined in connection - fetch it from LDAP */
+ }
+ else
+ {
+ ia->ipaddr = c->spd.that.host_srcip;
+ }
+}
+
+/*
+ * Compute HASH of Mode Config.
+ */
+static size_t
+mode_cfg_hash(u_char *dest, const u_char *start, const u_char *roof
+ , const struct state *st)
+{
+ struct hmac_ctx ctx;
+
+ hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
+ hmac_update(&ctx, (const u_char *) &st->st_msgid, sizeof(st->st_msgid));
+ hmac_update(&ctx, start, roof-start);
+ hmac_final(dest, &ctx);
+
+ DBG(DBG_CRYPT,
+ DBG_log("MODE CFG: HASH computed:");
+ DBG_dump("", dest, ctx.hmac_digest_size)
+ )
+ return ctx.hmac_digest_size;
+}
+
+
+/* Mode Config Reply
+ * Generates a reply stream containing Mode Config information (eg: IP, DNS, WINS)
+ */
+stf_status modecfg_resp(struct state *st
+ , u_int resp
+ , pb_stream *rbody
+ , u_int16_t replytype
+ , bool hackthat
+ , u_int16_t ap_id)
+{
+ u_char *r_hash_start,*r_hashval;
+
+ /* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_ATTR); */
+
+ {
+ pb_stream hash_pbs;
+ int np = ISAKMP_NEXT_ATTR;
+
+ if (!out_generic(np, &isakmp_hash_desc, rbody, &hash_pbs))
+ return STF_INTERNAL_ERROR;
+ r_hashval = hash_pbs.cur; /* remember where to plant value */
+ if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH"))
+ return STF_INTERNAL_ERROR;
+ close_output_pbs(&hash_pbs);
+ r_hash_start = (rbody)->cur; /* hash from after HASH payload */
+ }
+
+ /* ATTR out */
+ {
+ struct isakmp_mode_attr attrh;
+ struct isakmp_attribute attr;
+ pb_stream strattr,attrval;
+ int attr_type;
+ struct internal_addr ia;
+ int dns_idx, wins_idx;
+ bool dont_advance;
+
+ attrh.isama_np = ISAKMP_NEXT_NONE;
+ attrh.isama_type = replytype;
+
+ attrh.isama_identifier = ap_id;
+ if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr))
+ return STF_INTERNAL_ERROR;
+
+ get_internal_addresses(st->st_connection, &ia);
+
+ if (!isanyaddr(&ia.dns[0])) /* We got DNS addresses, answer with those */
+ resp |= LELEM(INTERNAL_IP4_DNS);
+ else
+ resp &= ~LELEM(INTERNAL_IP4_DNS);
+
+ if (!isanyaddr(&ia.wins[0])) /* We got WINS addresses, answer with those */
+ resp |= LELEM(INTERNAL_IP4_NBNS);
+ else
+ resp &= ~LELEM(INTERNAL_IP4_NBNS);
+
+ if (hackthat)
+ {
+ if (memcmp(&st->st_connection->spd.that.client.addr
+ ,&ia.ipaddr
+ ,sizeof(ia.ipaddr)) != 0)
+ {
+ /* Make the Internal IP address and Netmask
+ * as that client address
+ */
+ st->st_connection->spd.that.client.addr = ia.ipaddr;
+ st->st_connection->spd.that.client.maskbits = 32;
+ st->st_connection->spd.that.has_client = TRUE;
+ }
+ }
+
+ attr_type = 0;
+ dns_idx = 0;
+ wins_idx = 0;
+
+ while (resp != 0)
+ {
+ dont_advance = FALSE;
+ if (resp & 1)
+ {
+ const u_char *byte_ptr;
+ u_int len;
+
+ /* ISAKMP attr out */
+ attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV;
+ out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval);
+
+ switch (attr_type)
+ {
+ case INTERNAL_IP4_ADDRESS:
+ {
+ char srcip[ADDRTOT_BUF];
+
+ addrtot(&ia.ipaddr, 0, srcip, sizeof(srcip));
+ plog("assigning virtual IP source address %s", srcip);
+ len = addrbytesptr(&ia.ipaddr, &byte_ptr);
+ out_raw(byte_ptr,len,&attrval,"IP4_addr");
+ }
+ break;
+ case INTERNAL_IP4_NETMASK:
+ {
+ u_int mask;
+#if 0
+ char mask[4],bits[8]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};
+ int t,m=st->st_connection->that.host_addr.maskbit;
+ for (t=0; t<4; t++)
+ {
+ if (m < 8)
+ mask[t] = bits[m];
+ else
+ mask[t] = 0xff;
+ m -= 8;
+ }
+#endif
+ if (st->st_connection->spd.this.client.maskbits == 0)
+ mask = 0;
+ else
+ mask = 0xffffffff * 1;
+ out_raw(&mask,4,&attrval,"IP4_mask");
+ }
+ break;
+ case INTERNAL_IP4_SUBNET:
+ {
+ char mask[4];
+ char bits[8] = {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};
+ int t;
+ int m = st->st_connection->spd.this.client.maskbits;
+
+ for (t = 0; t < 4; t++)
+ {
+ if (m < 8)
+ mask[t] = bits[m];
+ else
+ mask[t] = 0xff;
+ m -= 8;
+ if (m < 0)
+ m = 0;
+ }
+ len = addrbytesptr(&st->st_connection->spd.this.client.addr, &byte_ptr);
+ out_raw(byte_ptr,len,&attrval,"IP4_subnet");
+ out_raw(mask,sizeof(mask),&attrval,"IP4_submsk");
+ }
+ break;
+ case INTERNAL_IP4_DNS:
+ len = addrbytesptr(&ia.dns[dns_idx++], &byte_ptr);
+ out_raw(byte_ptr,len,&attrval,"IP4_dns");
+ if (dns_idx < 2 && !isanyaddr(&ia.dns[dns_idx]))
+ {
+ dont_advance = TRUE;
+ }
+ break;
+ case INTERNAL_IP4_NBNS:
+ len = addrbytesptr(&ia.wins[wins_idx++], &byte_ptr);
+ out_raw(byte_ptr,len,&attrval,"IP4_wins");
+ if (wins_idx < 2 && !isanyaddr(&ia.wins[wins_idx]))
+ {
+ dont_advance = TRUE;
+ }
+ break;
+ default:
+ plog("attempt to send unsupported mode cfg attribute %s."
+ , enum_show(&modecfg_attr_names, attr_type));
+ break;
+ }
+ close_output_pbs(&attrval);
+
+ }
+ if (!dont_advance)
+ {
+ attr_type++;
+ resp >>= 1;
+ }
+ }
+ close_message(&strattr);
+ }
+
+ mode_cfg_hash(r_hashval,r_hash_start,rbody->cur,st);
+ close_message(rbody);
+ encrypt_message(rbody, st);
+ return STF_OK;
+}
+
+/* Set MODE_CONFIG data to client.
+ * Pack IP Addresses, DNS, etc... and ship
+ */
+stf_status modecfg_send_set(struct state *st)
+{
+ pb_stream reply,rbody;
+ char buf[256];
+
+ /* set up reply */
+ init_pbs(&reply, buf, sizeof(buf), "ModecfgR1");
+
+ st->st_state = STATE_MODE_CFG_R1;
+ /* HDR out */
+ {
+ struct isakmp_hdr hdr;
+
+ zero(&hdr); /* default to 0 */
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_HASH;
+ hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG;
+ hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
+ memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ hdr.isa_msgid = st->st_msgid;
+
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+#define MODECFG_SET_ITEM ( LELEM(INTERNAL_IP4_ADDRESS) | LELEM(INTERNAL_IP4_SUBNET) | LELEM(INTERNAL_IP4_NBNS) | LELEM(INTERNAL_IP4_DNS) )
+
+ modecfg_resp(st, MODECFG_SET_ITEM
+ , &rbody
+ , ISAKMP_CFG_SET
+ , TRUE
+ , 0/* XXX ID */);
+#undef MODECFG_SET_ITEM
+
+ clonetochunk(st->st_tpacket, reply.start
+ , pbs_offset(&reply), "ModeCfg set");
+
+ /* Transmit */
+ send_packet(st, "ModeCfg set");
+
+ /* RETRANSMIT if Main, SA_REPLACE if Aggressive */
+ if (st->st_event->ev_type != EVENT_RETRANSMIT
+ && st->st_event->ev_type != EVENT_NULL)
+ {
+ delete_event(st);
+ event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
+ }
+
+ return STF_OK;
+}
+
+/* Set MODE_CONFIG data to client.
+ * Pack IP Addresses, DNS, etc... and ship
+ */
+stf_status
+modecfg_start_set(struct state *st)
+{
+ if (st->st_msgid == 0)
+ {
+ /* pick a new message id */
+ st->st_msgid = generate_msgid(st);
+ }
+ st->st_modecfg.vars_set = TRUE;
+
+ return modecfg_send_set(st);
+}
+
+/*
+ * Send modecfg IP address request (IP4 address)
+ */
+stf_status
+modecfg_send_request(struct state *st)
+{
+ pb_stream reply;
+ pb_stream rbody;
+ char buf[256];
+ u_char *r_hash_start,*r_hashval;
+
+ /* set up reply */
+ init_pbs(&reply, buf, sizeof(buf), "modecfg_buf");
+
+ plog("sending ModeCfg request");
+
+ /* this is the beginning of a new exchange */
+ st->st_msgid = generate_msgid(st);
+ st->st_state = STATE_MODE_CFG_I1;
+
+ /* HDR out */
+ {
+ struct isakmp_hdr hdr;
+
+ zero(&hdr); /* default to 0 */
+ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
+ hdr.isa_np = ISAKMP_NEXT_HASH;
+ hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG;
+ hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
+ memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ hdr.isa_msgid = st->st_msgid;
+
+ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
+ {
+ return STF_INTERNAL_ERROR;
+ }
+ }
+
+ START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_ATTR);
+
+ /* ATTR out */
+ {
+ struct isakmp_mode_attr attrh;
+ struct isakmp_attribute attr;
+ pb_stream strattr;
+
+ attrh.isama_np = ISAKMP_NEXT_NONE;
+ attrh.isama_type = ISAKMP_CFG_REQUEST;
+ attrh.isama_identifier = 0;
+ if (!out_struct(&attrh, &isakmp_attr_desc, &rbody, &strattr))
+ return STF_INTERNAL_ERROR;
+ /* ISAKMP attr out (ipv4) */
+ attr.isaat_af_type = INTERNAL_IP4_ADDRESS;
+ attr.isaat_lv = 0;
+ out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, NULL);
+
+ /* ISAKMP attr out (netmask) */
+ attr.isaat_af_type = INTERNAL_IP4_NETMASK;
+ attr.isaat_lv = 0;
+ out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, NULL);
+
+ close_message(&strattr);
+ }
+
+ mode_cfg_hash(r_hashval,r_hash_start,rbody.cur,st);
+
+ close_message(&rbody);
+ close_output_pbs(&reply);
+
+ init_phase2_iv(st, &st->st_msgid);
+ encrypt_message(&rbody, st);
+
+ clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply)
+ , "modecfg: req");
+
+ /* Transmit */
+ send_packet(st, "modecfg: req");
+
+ /* RETRANSMIT if Main, SA_REPLACE if Aggressive */
+ if (st->st_event->ev_type != EVENT_RETRANSMIT)
+ {
+ delete_event(st);
+ event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0 * 3, st);
+ }
+ st->st_modecfg.started = TRUE;
+
+ return STF_OK;
+}
+
+/*
+ * parse a modecfg attribute payload
+ */
+static stf_status
+modecfg_parse_attributes(pb_stream *attrs, u_int *set)
+{
+ struct isakmp_attribute attr;
+ pb_stream strattr;
+
+ while (pbs_left(attrs) > sizeof(struct isakmp_attribute))
+ {
+ if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr))
+ {
+ int len = (attr.isaat_af_type & 0x8000)? 4 : attr.isaat_lv;
+
+ if (len < 4)
+ {
+ plog("Attribute was too short: %d", len);
+ return STF_FAIL;
+ }
+
+ attrs->cur += len;
+ }
+
+ switch (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )
+ {
+ case INTERNAL_IP4_ADDRESS:
+ case INTERNAL_IP4_NETMASK:
+ case INTERNAL_IP4_DNS:
+ case INTERNAL_IP4_SUBNET:
+ case INTERNAL_IP4_NBNS:
+ *set |= LELEM(attr.isaat_af_type);
+ break;
+ default:
+ plog("unsupported mode cfg attribute %s received."
+ , enum_show(&modecfg_attr_names
+ , attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK ));
+ break;
+ }
+ }
+ return STF_OK;
+}
+
+/* STATE_MODE_CFG_R0:
+ * HDR*, HASH, ATTR(REQ=IP) --> HDR*, HASH, ATTR(REPLY=IP)
+ *
+ * This state occurs both in the responder and in the initiator.
+ *
+ * In the responding server, it occurs when the client *asks* for an IP
+ * address or other information.
+ *
+ * Otherwise, it occurs in the initiator when the server sends a challenge
+ * a set, or has a reply to our request.
+ */
+stf_status
+modecfg_inR0(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ struct payload_digest *p;
+ stf_status stat;
+
+ plog("received ModeCfg request");
+
+ st->st_msgid = md->hdr.isa_msgid;
+ CHECK_QUICK_HASH(md, mode_cfg_hash(hash_val
+ ,hash_pbs->roof
+ , md->message_pbs.roof, st)
+ , "MODECFG-HASH", "MODE R0");
+
+ /* process the MODECFG payloads therein */
+ for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
+ {
+ u_int set_modecfg_attrs = LEMPTY;
+
+ switch (p->payload.attribute.isama_type)
+ {
+ default:
+ plog("Expecting ISAKMP_CFG_REQUEST, got %s instead (ignored)."
+ , enum_name(&attr_msg_type_names
+ , p->payload.attribute.isama_type));
+
+ stat = modecfg_parse_attributes(&p->pbs, &set_modecfg_attrs);
+ if (stat != STF_OK)
+ return stat;
+ break;
+
+ case ISAKMP_CFG_REQUEST:
+ stat = modecfg_parse_attributes(&p->pbs, &set_modecfg_attrs);
+ if (stat != STF_OK)
+ return stat;
+
+ stat = modecfg_resp(st, set_modecfg_attrs
+ ,&md->rbody
+ ,ISAKMP_CFG_REPLY
+ ,TRUE
+ ,p->payload.attribute.isama_identifier);
+
+ if (stat != STF_OK)
+ {
+ /* notification payload - not exactly the right choice, but okay */
+ md->note = CERTIFICATE_UNAVAILABLE;
+ return stat;
+ }
+
+ /* they asked us, we responded, msgid is done */
+ st->st_msgid = 0;
+ }
+ }
+ return STF_OK;
+}
+
+/* STATE_MODE_CFG_R2:
+ * HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
+ *
+ * used in server push mode, on the client (initiator).
+ */
+static stf_status
+modecfg_inI2(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ pb_stream *attrs = &md->chain[ISAKMP_NEXT_ATTR]->pbs;
+ int resp = LEMPTY;
+ stf_status stat;
+ struct payload_digest *p;
+ u_int16_t isama_id = 0;
+
+ st->st_msgid = md->hdr.isa_msgid;
+ CHECK_QUICK_HASH(md
+ , mode_cfg_hash(hash_val
+ ,hash_pbs->roof
+ , md->message_pbs.roof
+ , st)
+ , "MODECFG-HASH", "MODE R1");
+
+ for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
+ {
+ struct isakmp_attribute attr;
+ pb_stream strattr;
+
+ isama_id = p->payload.attribute.isama_identifier;
+
+ if (p->payload.attribute.isama_type != ISAKMP_CFG_SET)
+ {
+ plog("Expecting MODE_CFG_SET, got %x instead."
+ ,md->chain[ISAKMP_NEXT_ATTR]->payload.attribute.isama_type);
+ return STF_IGNORE;
+ }
+
+ /* CHECK that SET has been received. */
+
+ while (pbs_left(attrs) > sizeof(struct isakmp_attribute))
+ {
+ if (!in_struct(&attr, &isakmp_modecfg_attribute_desc
+ , attrs, &strattr))
+ {
+ int len;
+
+ /* Skip unknown */
+ if (attr.isaat_af_type & 0x8000)
+ len = 4;
+ else
+ len = attr.isaat_lv;
+
+ if (len < 4)
+ {
+ plog("Attribute was too short: %d", len);
+ return STF_FAIL;
+ }
+
+ attrs->cur += len;
+ }
+
+ switch (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )
+ {
+ case INTERNAL_IP4_ADDRESS:
+ {
+ struct connection *c = st->st_connection;
+ ip_address a;
+ u_int32_t *ap = (u_int32_t *)(strattr.cur);
+ a.u.v4.sin_family = AF_INET;
+
+ memcpy(&a.u.v4.sin_addr.s_addr, ap
+ , sizeof(a.u.v4.sin_addr.s_addr));
+
+ if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
+ || isanyaddr(&c->spd.this.host_srcip))
+ {
+ char srcip[ADDRTOT_BUF];
+
+ c->spd.this.host_srcip = a;
+ addrtot(&a, 0, srcip, sizeof(srcip));
+ plog("setting virtual IP source address to %s", srcip);
+ }
+
+ /* setting client subnet as srcip/32 */
+ addrtosubnet(&a, &c->spd.this.client);
+ c->spd.this.has_client = TRUE;
+ }
+ resp |= LELEM(attr.isaat_af_type);
+ break;
+ case INTERNAL_IP4_NETMASK:
+ case INTERNAL_IP4_DNS:
+ case INTERNAL_IP4_SUBNET:
+ case INTERNAL_IP4_NBNS:
+ resp |= LELEM(attr.isaat_af_type);
+ break;
+ default:
+ plog("unsupported mode cfg attribute %s received."
+ , enum_show(&modecfg_attr_names, (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )));
+ break;
+ }
+ }
+ }
+
+ /* ack things */
+ stat = modecfg_resp(st, resp
+ ,&md->rbody
+ ,ISAKMP_CFG_ACK
+ ,FALSE
+ ,isama_id);
+
+ if (stat != STF_OK)
+ {
+ /* notification payload - not exactly the right choice, but okay */
+ md->note = CERTIFICATE_UNAVAILABLE;
+ return stat;
+ }
+
+ /*
+ * we are done with this exchange, clear things so
+ * that we can start phase 2 properly
+ */
+ st->st_msgid = 0;
+
+ if (resp)
+ {
+ st->st_modecfg.vars_set = TRUE;
+ }
+ return STF_OK;
+}
+
+/* STATE_MODE_CFG_R1:
+ * HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
+ */
+stf_status
+modecfg_inR1(struct msg_digest *md)
+{
+ struct state *const st = md->st;
+ pb_stream *attrs = &md->chain[ISAKMP_NEXT_ATTR]->pbs;
+ int set_modecfg_attrs = LEMPTY;
+ stf_status stat;
+ struct payload_digest *p;
+
+ plog("parsing ModeCfg reply");
+
+ st->st_msgid = md->hdr.isa_msgid;
+ CHECK_QUICK_HASH(md, mode_cfg_hash(hash_val,hash_pbs->roof, md->message_pbs.roof, st)
+ , "MODECFG-HASH", "MODE R1");
+
+
+ /* process the MODECFG payloads therein */
+ for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
+ {
+ struct isakmp_attribute attr;
+ pb_stream strattr;
+
+ attrs = &p->pbs;
+
+ switch (p->payload.attribute.isama_type)
+ {
+ default:
+ {
+ plog("Expecting MODE_CFG_ACK, got %x instead."
+ ,md->chain[ISAKMP_NEXT_ATTR]->payload.attribute.isama_type);
+ return STF_IGNORE;
+ }
+ break;
+
+ case ISAKMP_CFG_ACK:
+ /* CHECK that ACK has been received. */
+ stat = modecfg_parse_attributes(attrs, &set_modecfg_attrs);
+ if (stat != STF_OK)
+ return stat;
+ break;
+
+ case ISAKMP_CFG_REPLY:
+ while (pbs_left(attrs) > sizeof(struct isakmp_attribute))
+ {
+ if (!in_struct(&attr, &isakmp_modecfg_attribute_desc
+ , attrs, &strattr))
+ {
+ /* Skip unknown */
+ int len;
+ if (attr.isaat_af_type & 0x8000)
+ len = 4;
+ else
+ len = attr.isaat_lv;
+
+ if (len < 4)
+ {
+ plog("Attribute was too short: %d", len);
+ return STF_FAIL;
+ }
+
+ attrs->cur += len;
+ }
+
+ switch (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )
+ {
+ case INTERNAL_IP4_ADDRESS:
+ {
+ struct connection *c = st->st_connection;
+ ip_address a;
+ u_int32_t *ap = (u_int32_t *)(strattr.cur);
+ a.u.v4.sin_family = AF_INET;
+
+ memcpy(&a.u.v4.sin_addr.s_addr, ap
+ , sizeof(a.u.v4.sin_addr.s_addr));
+
+ if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
+ || isanyaddr(&c->spd.this.host_srcip))
+ {
+ char srcip[ADDRTOT_BUF];
+
+ c->spd.this.host_srcip = a;
+ addrtot(&a, 0, srcip, sizeof(srcip));
+ plog("setting virtual IP source address to %s", srcip);
+ }
+
+ /* setting client subnet as srcip/32 */
+ addrtosubnet(&a, &c->spd.this.client);
+ setportof(0, &c->spd.this.client.addr);
+ c->spd.this.has_client = TRUE;
+ }
+ /* fall through to set attribute flage */
+
+ case INTERNAL_IP4_NETMASK:
+ case INTERNAL_IP4_DNS:
+ case INTERNAL_IP4_SUBNET:
+ case INTERNAL_IP4_NBNS:
+ set_modecfg_attrs |= LELEM(attr.isaat_af_type);
+ break;
+ default:
+ plog("unsupported mode cfg attribute %s received."
+ , enum_show(&modecfg_attr_names
+ , (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )));
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /* we are done with this exchange, clear things so that we can start phase 2 properly */
+ st->st_msgid = 0;
+
+ if (set_modecfg_attrs)
+ {
+ st->st_modecfg.vars_set = TRUE;
+ }
+ return STF_OK;
+}
diff --git a/programs/pluto/modecfg.h b/programs/pluto/modecfg.h
new file mode 100644
index 000000000..f6856d263
--- /dev/null
+++ b/programs/pluto/modecfg.h
@@ -0,0 +1,33 @@
+/* Mode Config related functions
+ * Copyright (C) 2001-2002 Colubris Networks
+ * Copyright (C) 2003-2004 Xelerance Corporation
+ *
+ * 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: modecfg.h,v 1.1 2005/01/06 22:10:15 as Exp $
+ */
+
+struct state;
+
+stf_status modecfg_resp(struct state *st
+ , u_int resp
+ , pb_stream *s, u_int16_t cmd
+ , bool hackthat, u_int16_t id);
+
+stf_status modecfg_send_set(struct state *st);
+
+extern stf_status modecfg_start_set(struct state *st);
+
+/* Mode Config States */
+
+extern stf_status modecfg_inR0(struct msg_digest *md);
+extern stf_status modecfg_inR1(struct msg_digest *md);
+extern stf_status modecfg_send_request(struct state *st);
diff --git a/programs/pluto/mp_defs.c b/programs/pluto/mp_defs.c
new file mode 100644
index 000000000..7ad896751
--- /dev/null
+++ b/programs/pluto/mp_defs.c
@@ -0,0 +1,70 @@
+/* some multiprecision utilities
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: mp_defs.c,v 1.1 2006/01/05 12:37:11 as Exp $
+ */
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+
+/* Convert MP_INT to network form (binary octets, big-endian).
+ * We do the malloc; caller must eventually do free.
+ */
+chunk_t
+mpz_to_n(const MP_INT *mp, size_t bytes)
+{
+ chunk_t r;
+ MP_INT temp1, temp2;
+ int i;
+
+ r.len = bytes;
+ r.ptr = alloc_bytes(r.len, "host representation of large integer");
+
+ mpz_init(&temp1);
+ mpz_init(&temp2);
+
+ mpz_set(&temp1, mp);
+
+ for (i = r.len-1; i >= 0; i--)
+ {
+ r.ptr[i] = mpz_mdivmod_ui(&temp2, NULL, &temp1, 1 << BITS_PER_BYTE);
+ mpz_set(&temp1, &temp2);
+ }
+
+ passert(mpz_sgn(&temp1) == 0); /* we must have done all the bits */
+ mpz_clear(&temp1);
+ mpz_clear(&temp2);
+
+ return r;
+}
+
+/* Convert network form (binary bytes, big-endian) to MP_INT.
+ * The *mp must not be previously mpz_inited.
+ */
+void
+n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen)
+{
+ size_t i;
+
+ mpz_init_set_ui(mp, 0);
+
+ for (i = 0; i != nlen; i++)
+ {
+ mpz_mul_ui(mp, mp, 1 << BITS_PER_BYTE);
+ mpz_add_ui(mp, mp, nbytes[i]);
+ }
+}
diff --git a/programs/pluto/mp_defs.h b/programs/pluto/mp_defs.h
new file mode 100644
index 000000000..744a028d1
--- /dev/null
+++ b/programs/pluto/mp_defs.h
@@ -0,0 +1,36 @@
+/* some multiprecision utilities
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: mp_defs.h,v 1.2 2006/01/06 11:40:45 as Exp $
+ */
+
+#ifndef _MP_DEFS_H
+#define _MP_DEFS_H
+
+#include <gmp.h>
+
+#include "defs.h"
+
+extern void n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen);
+extern chunk_t mpz_to_n(const MP_INT *mp, size_t bytes);
+
+/* var := mod(base ** exp, mod), ensuring var is mpz_inited */
+#define mpz_init_powm(flag, var, base, exp, mod) { \
+ if (!(flag)) \
+ mpz_init(&(var)); \
+ (flag) = TRUE; \
+ mpz_powm(&(var), &(base), &(exp), (mod)); \
+ }
+
+#endif /* _MP_DEFS_H */
diff --git a/programs/pluto/nat_traversal.c b/programs/pluto/nat_traversal.c
new file mode 100644
index 000000000..2f5ba3cb4
--- /dev/null
+++ b/programs/pluto/nat_traversal.c
@@ -0,0 +1,869 @@
+/* FreeS/WAN NAT-Traversal
+ * Copyright (C) 2002-2005 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: nat_traversal.c,v 1.8 2005/01/06 22:36:58 as Exp $
+ */
+
+#ifdef NAT_TRAVERSAL
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "server.h"
+#include "state.h"
+#include "connections.h"
+#include "packet.h"
+#include "demux.h"
+#include "kernel.h"
+#include "whack.h"
+#include "timer.h"
+
+
+#include "cookie.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+#include "vendor.h"
+#include "ike_alg.h"
+#include "nat_traversal.h"
+
+/* #define FORCE_NAT_TRAVERSAL */
+#define NAT_D_DEBUG
+#define NAT_T_SUPPORT_LAST_DRAFTS
+
+#ifndef SOL_UDP
+#define SOL_UDP 17
+#endif
+
+#ifndef UDP_ESPINUDP
+#define UDP_ESPINUDP 100
+#endif
+
+#define DEFAULT_KEEP_ALIVE_PERIOD 20
+
+#ifdef _IKE_ALG_H
+/* Alg patch: hash_digest_len -> hash_digest_size */
+#define hash_digest_len hash_digest_size
+#endif
+
+bool nat_traversal_enabled = FALSE;
+bool nat_traversal_support_non_ike = FALSE;
+bool nat_traversal_support_port_floating = FALSE;
+
+static unsigned int _kap = 0;
+static unsigned int _ka_evt = 0;
+static bool _force_ka = 0;
+
+static const char *natt_version = "0.6c";
+
+void init_nat_traversal (bool activate, unsigned int keep_alive_period,
+ bool fka, bool spf)
+{
+ nat_traversal_enabled = activate;
+ nat_traversal_support_non_ike = activate;
+#ifdef NAT_T_SUPPORT_LAST_DRAFTS
+ nat_traversal_support_port_floating = activate ? spf : FALSE;
+#endif
+ _force_ka = fka;
+ _kap = keep_alive_period ? keep_alive_period : DEFAULT_KEEP_ALIVE_PERIOD;
+ plog(" including NAT-Traversal patch (Version %s)%s%s%s"
+ , natt_version, activate ? "" : " [disabled]"
+ , activate & fka ? " [Force KeepAlive]" : ""
+ , activate & !spf ? " [Port Floating disabled]" : "");
+}
+
+static void disable_nat_traversal (int type)
+{
+ if (type == ESPINUDP_WITH_NON_IKE)
+ nat_traversal_support_non_ike = FALSE;
+ else
+ nat_traversal_support_port_floating = FALSE;
+
+ if (!nat_traversal_support_non_ike &&
+ !nat_traversal_support_port_floating)
+ nat_traversal_enabled = FALSE;
+}
+
+static void _natd_hash(const struct hash_desc *hasher, char *hash,
+ u_int8_t *icookie, u_int8_t *rcookie,
+ const ip_address *ip, u_int16_t port)
+{
+ union hash_ctx ctx;
+
+ if (is_zero_cookie(icookie))
+ DBG_log("_natd_hash: Warning, icookie is zero !!");
+ if (is_zero_cookie(rcookie))
+ DBG_log("_natd_hash: Warning, rcookie is zero !!");
+
+ /**
+ * draft-ietf-ipsec-nat-t-ike-01.txt
+ *
+ * HASH = HASH(CKY-I | CKY-R | IP | Port)
+ *
+ * All values in network order
+ */
+ hasher->hash_init(&ctx);
+ hasher->hash_update(&ctx, icookie, COOKIE_SIZE);
+ hasher->hash_update(&ctx, rcookie, COOKIE_SIZE);
+ switch (addrtypeof(ip)) {
+ case AF_INET:
+ hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr
+ , sizeof(ip->u.v4.sin_addr.s_addr));
+ break;
+ case AF_INET6:
+ hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr
+ , sizeof(ip->u.v6.sin6_addr.s6_addr));
+ break;
+ }
+ hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t));
+ hasher->hash_final(hash, &ctx);
+#ifdef NAT_D_DEBUG
+ DBG(DBG_NATT,
+ DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len);
+ DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE);
+ DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE);
+ switch (addrtypeof(ip)) {
+ case AF_INET:
+ DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr
+ , sizeof(ip->u.v4.sin_addr.s_addr));
+ break;
+ }
+ DBG_log("_natd_hash: port=%d", port);
+ DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len);
+ );
+#endif
+}
+
+/* Add NAT-Traversal VIDs (supported ones)
+ * used when we are Initiator
+ */
+bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs)
+{
+ bool r = TRUE;
+
+ if (nat_traversal_support_port_floating)
+ {
+ u_int8_t last_np = nat_traversal_support_non_ike ?
+ ISAKMP_NEXT_VID : np;
+
+ if (r)
+ r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_RFC);
+ if (r)
+ r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_03);
+ if (r)
+ r = out_vendorid(last_np, outs, VID_NATT_IETF_02);
+ }
+ if (nat_traversal_support_non_ike)
+ {
+ if (r)
+ r = out_vendorid(np, outs, VID_NATT_IETF_00);
+ }
+ return r;
+}
+
+u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid)
+{
+ switch (nat_t_vid)
+ {
+ case VID_NATT_IETF_00:
+ return LELEM(NAT_TRAVERSAL_IETF_00_01);
+ case VID_NATT_IETF_02:
+ case VID_NATT_IETF_02_N:
+ case VID_NATT_IETF_03:
+ return LELEM(NAT_TRAVERSAL_IETF_02_03);
+ case VID_NATT_RFC:
+ return LELEM(NAT_TRAVERSAL_RFC);
+ }
+ return 0;
+}
+
+void nat_traversal_natd_lookup(struct msg_digest *md)
+{
+ char hash[MAX_DIGEST_LEN];
+ struct payload_digest *p;
+ struct state *st = md->st;
+ int i;
+
+ if (!st || !md->iface || !st->st_oakley.hasher)
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
+ , __FILE__, __LINE__);
+ return;
+ }
+
+ /** Count NAT-D **/
+ for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL; p = p->next, i++);
+
+ /*
+ * We need at least 2 NAT-D (1 for us, many for peer)
+ */
+ if (i < 2)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negociation", i);
+ st->nat_traversal = 0;
+ return;
+ }
+
+ /*
+ * First one with my IP & port
+ */
+ p = md->chain[ISAKMP_NEXT_NATD_RFC];
+ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
+ &(md->iface->addr), ntohs(st->st_connection->spd.this.host_port));
+
+ if (!(pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len &&
+ memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len) == 0))
+ {
+#ifdef NAT_D_DEBUG
+ DBG(DBG_NATT,
+ DBG_log("NAT_TRAVERSAL_NAT_BHND_ME");
+ DBG_dump("expected NAT-D:", hash
+ , st->st_oakley.hasher->hash_digest_len);
+ DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
+ )
+#endif
+ st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+ }
+
+ /*
+ * The others with sender IP & port
+ */
+ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
+ &(md->sender), ntohs(md->sender_port));
+ for (p = p->next, i=0 ; p != NULL; p = p->next)
+ {
+ if (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len &&
+ memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len) == 0)
+ {
+ i++;
+ }
+ }
+ if (!i)
+ {
+#ifdef NAT_D_DEBUG
+ DBG(DBG_NATT,
+ DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER");
+ DBG_dump("expected NAT-D:", hash
+ , st->st_oakley.hasher->hash_digest_len);
+ p = md->chain[ISAKMP_NEXT_NATD_RFC];
+ for (p = p->next, i=0 ; p != NULL; p = p->next)
+ {
+ DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
+ }
+ )
+#endif
+ st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+ }
+#ifdef FORCE_NAT_TRAVERSAL
+ st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+ st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+#endif
+}
+
+bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs,
+ struct msg_digest *md)
+{
+ char hash[MAX_DIGEST_LEN];
+ struct state *st = md->st;
+
+ if (!st || !st->st_oakley.hasher)
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
+ , __FILE__, __LINE__);
+ return FALSE;
+ }
+
+ DBG(DBG_EMITTING,
+ DBG_log("sending NATD payloads")
+ )
+
+ /*
+ * First one with sender IP & port
+ */
+ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
+ is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
+ &(md->sender),
+#ifdef FORCE_NAT_TRAVERSAL
+ 0
+#else
+ ntohs(md->sender_port)
+#endif
+ );
+ if (!out_generic_raw((st->nat_traversal & NAT_T_WITH_RFC_VALUES
+ ? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), &isakmp_nat_d, outs,
+ hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Second one with my IP & port
+ */
+ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
+ is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
+ &(md->iface->addr),
+#ifdef FORCE_NAT_TRAVERSAL
+ 0
+#else
+ ntohs(st->st_connection->spd.this.host_port)
+#endif
+ );
+ return (out_generic_raw(np, &isakmp_nat_d, outs,
+ hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"));
+}
+
+/*
+ * nat_traversal_natoa_lookup()
+ *
+ * Look for NAT-OA in message
+ */
+void nat_traversal_natoa_lookup(struct msg_digest *md)
+{
+ struct payload_digest *p;
+ struct state *st = md->st;
+ int i;
+ ip_address ip;
+
+ if (!st || !md->iface)
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
+ , __FILE__, __LINE__);
+ return;
+ }
+
+ /* Initialize NAT-OA */
+ anyaddr(AF_INET, &st->nat_oa);
+
+ /* Count NAT-OA **/
+ for (p = md->chain[ISAKMP_NEXT_NATOA_RFC], i=0; p != NULL; p = p->next, i++);
+
+ DBG(DBG_NATT,
+ DBG_log("NAT-Traversal: received %d NAT-OA.", i)
+ )
+
+ if (i == 0)
+ return;
+
+ if (!(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER)))
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
+ "ignored because peer is not NATed", i);
+ return;
+ }
+
+ if (i > 1)
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
+ "using first, ignoring others", i);
+ }
+
+ /* Take first */
+ p = md->chain[ISAKMP_NEXT_NATOA_RFC];
+
+ DBG(DBG_PARSING,
+ DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs));
+ );
+
+ switch (p->payload.nat_oa.isanoa_idtype)
+ {
+ case ID_IPV4_ADDR:
+ if (pbs_left(&p->pbs) == sizeof(struct in_addr))
+ {
+ initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET, &ip);
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv4 NAT-OA "
+ "with invalid IP size (%d)", (int)pbs_left(&p->pbs));
+ return;
+ }
+ break;
+ case ID_IPV6_ADDR:
+ if (pbs_left(&p->pbs) == sizeof(struct in6_addr))
+ {
+ initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET6, &ip);
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv6 NAT-OA "
+ "with invalid IP size (%d)", (int)pbs_left(&p->pbs));
+ return;
+ }
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+ "invalid ID Type (%d) in NAT-OA - ignored",
+ p->payload.nat_oa.isanoa_idtype);
+ return;
+ }
+
+ DBG(DBG_NATT,
+ {
+ char ip_t[ADDRTOT_BUF];
+ addrtot(&ip, 0, ip_t, sizeof(ip_t));
+
+ DBG_log("received NAT-OA: %s", ip_t);
+ }
+ )
+
+ if (isanyaddr(&ip))
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %%any NAT-OA...");
+ else
+ st->nat_oa = ip;
+}
+
+bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs,
+ struct state *st)
+{
+ struct isakmp_nat_oa natoa;
+ pb_stream pbs;
+ unsigned char ip_val[sizeof(struct in6_addr)];
+ size_t ip_len = 0;
+ ip_address *ip;
+
+ if ((!st) || (!st->st_connection))
+ {
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
+ , __FILE__, __LINE__);
+ return FALSE;
+ }
+ ip = &(st->st_connection->spd.this.host_addr);
+
+ memset(&natoa, 0, sizeof(natoa));
+ natoa.isanoa_np = np;
+
+ switch (addrtypeof(ip))
+ {
+ case AF_INET:
+ ip_len = sizeof(ip->u.v4.sin_addr.s_addr);
+ memcpy(ip_val, &ip->u.v4.sin_addr.s_addr, ip_len);
+ natoa.isanoa_idtype = ID_IPV4_ADDR;
+ break;
+ case AF_INET6:
+ ip_len = sizeof(ip->u.v6.sin6_addr.s6_addr);
+ memcpy(ip_val, &ip->u.v6.sin6_addr.s6_addr, ip_len);
+ natoa.isanoa_idtype = ID_IPV6_ADDR;
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+ "invalid addrtypeof()=%d", addrtypeof(ip));
+ return FALSE;
+ }
+
+ if (!out_struct(&natoa, &isakmp_nat_oa, outs, &pbs))
+ return FALSE;
+
+ if (!out_raw(ip_val, ip_len, &pbs, "NAT-OA"))
+ return FALSE;
+
+ DBG(DBG_NATT,
+ DBG_dump("NAT-OA (S):", ip_val, ip_len)
+ )
+
+ close_output_pbs(&pbs);
+ return TRUE;
+}
+
+void nat_traversal_show_result (u_int32_t nt, u_int16_t sport)
+{
+ const char *mth = NULL, *rslt = NULL;
+
+ switch (nt & NAT_TRAVERSAL_METHOD)
+ {
+ case LELEM(NAT_TRAVERSAL_IETF_00_01):
+ mth = natt_type_bitnames[0];
+ break;
+ case LELEM(NAT_TRAVERSAL_IETF_02_03):
+ mth = natt_type_bitnames[1];
+ break;
+ case LELEM(NAT_TRAVERSAL_RFC):
+ mth = natt_type_bitnames[2];
+ break;
+ }
+
+ switch (nt & NAT_T_DETECTED)
+ {
+ case 0:
+ rslt = "no NAT detected";
+ break;
+ case LELEM(NAT_TRAVERSAL_NAT_BHND_ME):
+ rslt = "i am NATed";
+ break;
+ case LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
+ rslt = "peer is NATed";
+ break;
+ case LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
+ rslt = "both are NATed";
+ break;
+ }
+
+ loglog(RC_LOG_SERIOUS,
+ "NAT-Traversal: Result using %s: %s",
+ mth ? mth : "unknown method",
+ rslt ? rslt : "unknown result"
+ );
+
+ if ((nt & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))
+ && (sport == IKE_UDP_PORT)
+ && ((nt & NAT_T_WITH_PORT_FLOATING)==0))
+ {
+ loglog(RC_LOG_SERIOUS,
+ "Warning: peer is NATed but source port is still udp/%d. "
+ "Ipsec-passthrough NAT device suspected -- NAT-T may not work.",
+ IKE_UDP_PORT
+ );
+ }
+}
+
+int nat_traversal_espinudp_socket (int sk, u_int32_t type)
+{
+ int r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type));
+
+ if (r < 0 && errno == ENOPROTOOPT)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "NAT-Traversal: ESPINUDP(%d) not supported by kernel -- "
+ "NAT-T disabled", type);
+ disable_nat_traversal(type);
+ }
+ return r;
+}
+
+void nat_traversal_new_ka_event (void)
+{
+ if (_ka_evt)
+ return; /* event already scheduled */
+
+ event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL);
+ _ka_evt = 1;
+}
+
+static void nat_traversal_send_ka (struct state *st)
+{
+ static unsigned char ka_payload = 0xff;
+ chunk_t sav;
+
+ DBG(DBG_NATT,
+ DBG_log("ka_event: send NAT-KA to %s:%d",
+ ip_str(&st->st_connection->spd.that.host_addr),
+ st->st_connection->spd.that.host_port);
+ )
+
+ /* save state chunk */
+ setchunk(sav, st->st_tpacket.ptr, st->st_tpacket.len);
+
+ /* send keep alive */
+ setchunk(st->st_tpacket, &ka_payload, 1);
+ _send_packet(st, "NAT-T Keep Alive", FALSE);
+
+ /* restore state chunk */
+ setchunk(st->st_tpacket, sav.ptr, sav.len);
+}
+
+/**
+ * Find ISAKMP States with NAT-T and send keep-alive
+ */
+static void nat_traversal_ka_event_state (struct state *st, void *data)
+{
+ unsigned int *_kap_st = (unsigned int *)data;
+ const struct connection *c = st->st_connection;
+
+ if (!c)
+ return;
+
+ if ((st->st_state == STATE_MAIN_R3 || st->st_state == STATE_MAIN_I4)
+ && (st->nat_traversal & NAT_T_DETECTED)
+ && ((st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka))
+ {
+ /*
+ * - ISAKMP established
+ * - NAT-Traversal detected
+ * - NAT-KeepAlive needed (we are NATed)
+ */
+ if (c->newest_isakmp_sa != st->st_serialno)
+ {
+ /*
+ * if newest is also valid, ignore this one, we will only use
+ * newest.
+ */
+ struct state *st_newest;
+
+ st_newest = state_with_serialno(c->newest_isakmp_sa);
+ if (st_newest
+ && (st_newest->st_state == STATE_MAIN_R3 || st_newest->st_state == STATE_MAIN_I4)
+ && (st_newest->nat_traversal & NAT_T_DETECTED)
+ && ((st_newest->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka))
+ {
+ return;
+ }
+ }
+ set_cur_state(st);
+ nat_traversal_send_ka(st);
+ reset_cur_state();
+ (*_kap_st)++;
+ }
+}
+
+void nat_traversal_ka_event (void)
+{
+ unsigned int _kap_st = 0;
+
+ _ka_evt = 0; /* ready to be reschedule */
+
+ for_each_state((void *)nat_traversal_ka_event_state, &_kap_st);
+
+ /* if there are still states who needs Keep-Alive, schedule new event */
+ if (_kap_st)
+ nat_traversal_new_ka_event();
+}
+
+struct _new_mapp_nfo {
+ ip_address addr;
+ u_int16_t sport, dport;
+};
+
+static void nat_traversal_find_new_mapp_state (struct state *st, void *data)
+{
+ struct connection *c = st->st_connection;
+ struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data;
+
+ if (c != NULL
+ && sameaddr(&c->spd.that.host_addr, &(nfo->addr))
+ && c->spd.that.host_port == nfo->sport)
+ {
+
+ /* change host port */
+ c->spd.that.host_port = nfo->dport;
+
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)
+ || IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+ if (!update_ipsec_sa(st))
+ {
+ /*
+ * If ipsec update failed, restore old port or we'll
+ * not be able to update anymore.
+ */
+ c->spd.that.host_port = nfo->sport;
+ }
+ }
+ }
+}
+
+static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport,
+ const ip_address *dst, u_int16_t dport)
+{
+ char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF];
+ struct _new_mapp_nfo nfo;
+
+ addrtot(src, 0, srca, ADDRTOT_BUF);
+ addrtot(dst, 0, dsta, ADDRTOT_BUF);
+
+ if (!sameaddr(src, dst))
+ {
+ loglog(RC_LOG_SERIOUS, "nat_traversal_new_mapping: "
+ "address change currently not supported [%s:%d,%s:%d]",
+ srca, sport, dsta, dport);
+ return -1;
+ }
+
+ if (sport == dport)
+ {
+ /* no change */
+ return 0;
+ }
+
+ DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport);
+
+ nfo.addr = *src;
+ nfo.sport = sport;
+ nfo.dport = dport;
+
+ for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo);
+
+ return 0;
+}
+
+void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st)
+{
+ struct connection *c = st ? st->st_connection : NULL;
+ struct iface *i = NULL;
+
+ if ((st == NULL) || (c == NULL))
+ return;
+
+ if (md)
+ {
+ /*
+ * If source port has changed, update (including other states and
+ * established kernel SA)
+ */
+ if (c->spd.that.host_port != md->sender_port)
+ {
+ nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port,
+ &c->spd.that.host_addr, md->sender_port);
+ }
+
+ /*
+ * If interface type has changed, update local port (500/4500)
+ */
+ if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !md->iface->ike_float)
+ || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && md->iface->ike_float))
+ {
+ c->spd.this.host_port = (md->iface->ike_float)
+ ? NAT_T_IKE_FLOAT_PORT : pluto_port;
+
+ DBG(DBG_NATT,
+ DBG_log("NAT-T: updating local port to %d", c->spd.this.host_port);
+ );
+ }
+ }
+
+ /*
+ * If we're initiator and NAT-T (with port floating) is detected, we
+ * need to change port (MAIN_I3 or QUICK_I1)
+ */
+ if ((st->st_state == STATE_MAIN_I3 || st->st_state == STATE_QUICK_I1)
+ && (st->nat_traversal & NAT_T_WITH_PORT_FLOATING)
+ && (st->nat_traversal & NAT_T_DETECTED)
+ && (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT))
+ {
+ DBG(DBG_NATT,
+ DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT);
+ )
+ c->spd.this.host_port = NAT_T_IKE_FLOAT_PORT;
+ c->spd.that.host_port = NAT_T_IKE_FLOAT_PORT;
+ /*
+ * Also update pending connections or they will be deleted if uniqueids
+ * option is set.
+ */
+ update_pending(st, st);
+ }
+
+ /*
+ * Find valid interface according to local port (500/4500)
+ */
+ if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !c->interface->ike_float)
+ || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && c->interface->ike_float))
+ {
+ for (i = interfaces; i != NULL; i = i->next)
+ {
+ if (sameaddr(&c->interface->addr, &i->addr)
+ && i->ike_float != c->interface->ike_float)
+ {
+ DBG(DBG_NATT,
+ DBG_log("NAT-T: using interface %s:%d", i->rname,
+ i->ike_float ? NAT_T_IKE_FLOAT_PORT : pluto_port);
+ )
+ c->interface = i;
+ break;
+ }
+ }
+ }
+}
+
+struct _new_klips_mapp_nfo {
+ struct sadb_sa *sa;
+ ip_address src, dst;
+ u_int16_t sport, dport;
+};
+
+static void nat_t_new_klips_mapp (struct state *st, void *data)
+{
+ struct connection *c = st->st_connection;
+ struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data;
+
+ if (c != NULL && st->st_esp.present
+ && sameaddr(&c->spd.that.host_addr, &(nfo->src))
+ && st->st_esp.our_spi == nfo->sa->sadb_sa_spi)
+ {
+ nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port,
+ &(nfo->dst), nfo->dport);
+ }
+}
+
+void process_pfkey_nat_t_new_mapping(
+ struct sadb_msg *msg __attribute__ ((unused)),
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ struct _new_klips_mapp_nfo nfo;
+ struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC];
+ struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST];
+ struct sockaddr *srca, *dsta;
+ err_t ugh = NULL;
+
+ nfo.sa = (void *) extensions[SADB_EXT_SA];
+
+ if (!nfo.sa || !srcx || !dstx)
+ {
+ plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: "
+ "got NULL params");
+ return;
+ }
+
+ srca = ((struct sockaddr *)(void *)&srcx[1]);
+ dsta = ((struct sockaddr *)(void *)&dstx[1]);
+
+ if (srca->sa_family != AF_INET || dsta->sa_family != AF_INET)
+ {
+ ugh = "only AF_INET supported";
+ }
+ else
+ {
+ char text_said[SATOT_BUF];
+ char _srca[ADDRTOT_BUF], _dsta[ADDRTOT_BUF];
+ ip_said said;
+
+ initaddr((const void *) &((const struct sockaddr_in *)srca)->sin_addr,
+ sizeof(((const struct sockaddr_in *)srca)->sin_addr),
+ srca->sa_family, &(nfo.src));
+ nfo.sport = ntohs(((const struct sockaddr_in *)srca)->sin_port);
+ initaddr((const void *) &((const struct sockaddr_in *)dsta)->sin_addr,
+ sizeof(((const struct sockaddr_in *)dsta)->sin_addr),
+ dsta->sa_family, &(nfo.dst));
+ nfo.dport = ntohs(((const struct sockaddr_in *)dsta)->sin_port);
+
+ DBG(DBG_NATT,
+ initsaid(&nfo.src, nfo.sa->sadb_sa_spi, SA_ESP, &said);
+ satot(&said, 0, text_said, SATOT_BUF);
+ addrtot(&nfo.src, 0, _srca, ADDRTOT_BUF);
+ addrtot(&nfo.dst, 0, _dsta, ADDRTOT_BUF);
+ DBG_log("new klips mapping %s %s:%d %s:%d",
+ text_said, _srca, nfo.sport, _dsta, nfo.dport);
+ )
+
+ for_each_state((void *)nat_t_new_klips_mapp, &nfo);
+ }
+
+ if (ugh != NULL)
+ plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: %s", ugh);
+}
+
+#endif
+
diff --git a/programs/pluto/nat_traversal.h b/programs/pluto/nat_traversal.h
new file mode 100644
index 000000000..71222c54c
--- /dev/null
+++ b/programs/pluto/nat_traversal.h
@@ -0,0 +1,154 @@
+/* FreeS/WAN NAT-Traversal
+ * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: nat_traversal.h,v 1.4 2004/07/27 21:11:30 as Exp $
+ */
+
+#ifndef _NAT_TRAVERSAL_H
+#define _NAT_TRAVERSAL_H
+
+#include "packet.h"
+
+#define NAT_TRAVERSAL_IETF_00_01 1
+#define NAT_TRAVERSAL_IETF_02_03 2
+#define NAT_TRAVERSAL_RFC 3
+
+#define NAT_TRAVERSAL_NAT_BHND_ME 30
+#define NAT_TRAVERSAL_NAT_BHND_PEER 31
+
+#define NAT_TRAVERSAL_METHOD (0xffffffff - LELEM(30) - LELEM(31))
+
+/**
+ * NAT-Traversal methods which need NAT-D
+ */
+#define NAT_T_WITH_NATD \
+ ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
+ LELEM(NAT_TRAVERSAL_RFC) )
+/**
+ * NAT-Traversal methods which need NAT-OA
+ */
+#define NAT_T_WITH_NATOA \
+ ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
+ LELEM(NAT_TRAVERSAL_RFC) )
+/**
+ * NAT-Traversal methods which use NAT-KeepAlive
+ */
+#define NAT_T_WITH_KA \
+ ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
+ LELEM(NAT_TRAVERSAL_RFC) )
+/**
+ * NAT-Traversal methods which use floating port
+ */
+#define NAT_T_WITH_PORT_FLOATING \
+ ( LELEM(NAT_TRAVERSAL_IETF_02_03) | LELEM(NAT_TRAVERSAL_RFC) )
+
+/**
+ * NAT-Traversal methods which use officials values (RFC)
+ */
+#define NAT_T_WITH_RFC_VALUES \
+ ( LELEM(NAT_TRAVERSAL_RFC) )
+
+/**
+ * NAT-Traversal detected
+ */
+#define NAT_T_DETECTED \
+ ( LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER) )
+
+/**
+ * NAT-T Port Floating
+ */
+#define NAT_T_IKE_FLOAT_PORT 4500
+
+void init_nat_traversal (bool activate, unsigned int keep_alive_period,
+ bool fka, bool spf);
+
+extern bool nat_traversal_enabled;
+extern bool nat_traversal_support_non_ike;
+extern bool nat_traversal_support_port_floating;
+
+/**
+ * NAT-D
+ */
+void nat_traversal_natd_lookup(struct msg_digest *md);
+#ifndef PB_STREAM_UNDEFINED
+bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs,
+ struct msg_digest *md);
+#endif
+
+/**
+ * NAT-OA
+ */
+void nat_traversal_natoa_lookup(struct msg_digest *md);
+#ifndef PB_STREAM_UNDEFINED
+bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs,
+ struct state *st);
+#endif
+
+/**
+ * NAT-keep_alive
+ */
+void nat_traversal_new_ka_event (void);
+void nat_traversal_ka_event (void);
+
+void nat_traversal_show_result (u_int32_t nt, u_int16_t sport);
+
+int nat_traversal_espinudp_socket (int sk, u_int32_t type);
+
+/**
+ * Vendor ID
+ */
+#ifndef PB_STREAM_UNDEFINED
+bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs);
+#endif
+u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid);
+
+void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st);
+
+/**
+ * New NAT mapping
+ */
+#ifdef __PFKEY_V2_H
+void process_pfkey_nat_t_new_mapping(
+ struct sadb_msg *,
+ struct sadb_ext *[SADB_EXT_MAX + 1]);
+#endif
+
+/**
+ * IKE port floating
+ */
+bool
+nat_traversal_port_float(struct state *st, struct msg_digest *md, bool in);
+
+/**
+ * Encapsulation mode macro (see demux.c)
+ */
+#define NAT_T_ENCAPSULATION_MODE(st,nat_t_policy) ( \
+ ((st)->nat_traversal & NAT_T_DETECTED) \
+ ? ( ((nat_t_policy) & POLICY_TUNNEL) \
+ ? ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \
+ ? (ENCAPSULATION_MODE_UDP_TUNNEL_RFC) \
+ : (ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS) \
+ ) \
+ : ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \
+ ? (ENCAPSULATION_MODE_UDP_TRANSPORT_RFC) \
+ : (ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS) \
+ ) \
+ ) \
+ : ( ((st)->st_policy & POLICY_TUNNEL) \
+ ? (ENCAPSULATION_MODE_TUNNEL) \
+ : (ENCAPSULATION_MODE_TRANSPORT) \
+ ) \
+ )
+
+#endif /* _NAT_TRAVERSAL_H */
+
diff --git a/programs/pluto/ocsp.c b/programs/pluto/ocsp.c
new file mode 100644
index 000000000..f31b96c7f
--- /dev/null
+++ b/programs/pluto/ocsp.c
@@ -0,0 +1,1568 @@
+/* Support of the Online Certificate Status Protocol (OCSP)
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * Zuercher Hochschule Winterthur
+ *
+ * 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.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "rnd.h"
+#include "asn1.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "oid.h"
+#include "whack.h"
+#include "pkcs1.h"
+#include "keys.h"
+#include "fetch.h"
+#include "ocsp.h"
+
+#define NONCE_LENGTH 16
+
+static const char *const cert_status_names[] = {
+ "good",
+ "revoked",
+ "unknown",
+ "undefined"
+};
+
+
+static const char *const response_status_names[] = {
+ "successful",
+ "malformed request",
+ "internal error",
+ "try later",
+ "signature required",
+ "unauthorized"
+};
+
+/* response container */
+typedef struct response response_t;
+
+struct response {
+ chunk_t tbs;
+ chunk_t responder_id_name;
+ chunk_t responder_id_key;
+ time_t produced_at;
+ chunk_t responses;
+ chunk_t nonce;
+ int algorithm;
+ chunk_t signature;
+};
+
+const response_t empty_response = {
+ { NULL, 0 } , /* tbs */
+ { NULL, 0 } , /* responder_id_name */
+ { NULL, 0 } , /* responder_id_key */
+ UNDEFINED_TIME, /* produced_at */
+ { NULL, 0 } , /* single_response */
+ { NULL, 0 } , /* nonce */
+ OID_UNKNOWN , /* signature_algorithm */
+ { NULL, 0 } /* signature */
+};
+
+/* single response container */
+typedef struct single_response single_response_t;
+
+struct single_response {
+ single_response_t *next;
+ int hash_algorithm;
+ chunk_t issuer_name_hash;
+ chunk_t issuer_key_hash;
+ chunk_t serialNumber;
+ cert_status_t status;
+ time_t revocationTime;
+ crl_reason_t revocationReason;
+ time_t thisUpdate;
+ time_t nextUpdate;
+};
+
+const single_response_t empty_single_response = {
+ NULL , /* *next */
+ OID_UNKNOWN , /* hash_algorithm */
+ { NULL, 0 } , /* issuer_name_hash */
+ { NULL, 0 } , /* issuer_key_hash */
+ { NULL, 0 } , /* serial_number */
+ CERT_UNDEFINED , /* status */
+ UNDEFINED_TIME , /* revocationTime */
+ REASON_UNSPECIFIED, /* revocationReason */
+ UNDEFINED_TIME , /* this_update */
+ UNDEFINED_TIME /* next_update */
+};
+
+
+/* list of single requests */
+typedef struct request_list request_list_t;
+struct request_list {
+ chunk_t request;
+ request_list_t *next;
+};
+
+/* some OCSP specific prefabricated ASN.1 constants */
+
+static u_char ASN1_nonce_oid_str[] = {
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02
+};
+
+static const chunk_t ASN1_nonce_oid = strchunk(ASN1_nonce_oid_str);
+
+static u_char ASN1_response_oid_str[] = {
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04
+};
+
+static const chunk_t ASN1_response_oid = strchunk(ASN1_response_oid_str);
+
+static u_char ASN1_response_content_str[] = {
+ 0x04, 0x0D,
+ 0x30, 0x0B,
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+};
+
+static const chunk_t ASN1_response_content = strchunk(ASN1_response_content_str);
+
+/* default OCSP uri */
+static chunk_t ocsp_default_uri;
+
+/* ocsp cache: pointer to first element */
+static ocsp_location_t *ocsp_cache = NULL;
+
+/* static temporary storage for ocsp requestor information */
+static x509cert_t *ocsp_requestor_cert = NULL;
+
+static smartcard_t *ocsp_requestor_sc = NULL;
+
+static const struct RSA_private_key *ocsp_requestor_pri = NULL;
+
+/* asn.1 definitions for parsing */
+
+static const asn1Object_t ocspResponseObjects[] = {
+ { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */
+ { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */
+ { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
+ { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */
+ { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */
+};
+
+#define OCSP_RESPONSE_STATUS 1
+#define OCSP_RESPONSE_TYPE 4
+#define OCSP_RESPONSE 5
+#define OCSP_RESPONSE_ROOF 7
+
+static const asn1Object_t basicResponseObjects[] = {
+ { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE |
+ ASN1_DEF }, /* 2 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
+ { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */
+ { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
+ { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */
+ { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */
+ { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
+ { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
+ { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_BODY |
+ ASN1_DEF }, /* 16 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */
+ { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */
+ { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */
+ { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */
+ { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */
+ { 3, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 24 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */
+};
+
+#define BASIC_RESPONSE_TBS_DATA 1
+#define BASIC_RESPONSE_VERSION 3
+#define BASIC_RESPONSE_ID_BY_NAME 5
+#define BASIC_RESPONSE_ID_BY_KEY 8
+#define BASIC_RESPONSE_PRODUCED_AT 10
+#define BASIC_RESPONSE_RESPONSES 11
+#define BASIC_RESPONSE_EXT_ID 15
+#define BASIC_RESPONSE_CRITICAL 16
+#define BASIC_RESPONSE_EXT_VALUE 17
+#define BASIC_RESPONSE_ALGORITHM 20
+#define BASIC_RESPONSE_SIGNATURE 21
+#define BASIC_RESPONSE_CERTIFICATE 24
+#define BASIC_RESPONSE_ROOF 27
+
+static const asn1Object_t responsesObjects[] = {
+ { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */
+ { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */
+};
+
+#define RESPONSES_SINGLE_RESPONSE 1
+#define RESPONSES_ROOF 3
+
+static const asn1Object_t singleResponseObjects[] = {
+ { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
+ { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
+ { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
+ { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */
+ { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
+ { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */
+ { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */
+ { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */
+ { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
+ { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
+ { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */
+ { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */
+ { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
+ { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */
+ { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */
+ { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
+ { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */
+ { 4, "critical", ASN1_BOOLEAN, ASN1_BODY |
+ ASN1_DEF }, /* 24 */
+ { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */
+};
+
+#define SINGLE_RESPONSE_ALGORITHM 2
+#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3
+#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4
+#define SINGLE_RESPONSE_SERIAL_NUMBER 5
+#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6
+#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8
+#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9
+#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11
+#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14
+#define SINGLE_RESPONSE_THIS_UPDATE 16
+#define SINGLE_RESPONSE_NEXT_UPDATE 18
+#define SINGLE_RESPONSE_EXT_ID 23
+#define SINGLE_RESPONSE_CRITICAL 24
+#define SINGLE_RESPONSE_EXT_VALUE 25
+#define SINGLE_RESPONSE_ROOF 28
+
+/* build an ocsp location from certificate information
+ * without unsharing its contents
+ */
+static bool
+build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
+{
+ static u_char digest[SHA1_DIGEST_SIZE]; /* temporary storage */
+
+ location->uri = cert->accessLocation;
+
+ if (location->uri.ptr == NULL)
+ {
+ ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID);
+ if (ca != NULL && ca->ocspuri != NULL)
+ setchunk(location->uri, ca->ocspuri, strlen(ca->ocspuri))
+ else
+ /* abort if no ocsp location uri is defined */
+ return FALSE;
+ }
+
+ setchunk(location->authNameID, digest, SHA1_DIGEST_SIZE);
+ compute_digest(cert->issuer, OID_SHA1, &location->authNameID);
+
+ location->next = NULL;
+ location->issuer = cert->issuer;
+ location->authKeyID = cert->authKeyID;
+ location->authKeySerialNumber = cert->authKeySerialNumber;
+
+ if (cert->authKeyID.ptr == NULL)
+ {
+ x509cert_t *authcert = get_authcert(cert->issuer
+ , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA);
+
+ if (authcert != NULL)
+ {
+ location->authKeyID = authcert->subjectKeyID;
+ location->authKeySerialNumber = authcert->serialNumber;
+ }
+ }
+
+ location->nonce = empty_chunk;
+ location->certinfo = NULL;
+
+ return TRUE;
+}
+
+/*
+ * compare two ocsp locations for equality
+ */
+static bool
+same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b)
+{
+ return ((a->authKeyID.ptr != NULL)
+ ? same_keyid(a->authKeyID, b->authKeyID)
+ : (same_dn(a->issuer, b->issuer)
+ && same_serial(a->authKeySerialNumber, b->authKeySerialNumber)))
+ && same_chunk(a->uri, b->uri);
+}
+
+/*
+ * find an existing ocsp location in a chained list
+ */
+ocsp_location_t*
+get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain)
+{
+
+ while (chain != NULL)
+ {
+ if (same_ocsp_location(loc, chain))
+ return chain;
+ chain = chain->next;
+ }
+ return NULL;
+}
+
+/* retrieves the status of a cert from the ocsp cache
+ * returns CERT_UNDEFINED if no status is found
+ */
+static cert_status_t
+get_ocsp_status(const ocsp_location_t *loc, chunk_t serialNumber
+ ,time_t *nextUpdate, time_t *revocationTime, crl_reason_t *revocationReason)
+{
+ ocsp_certinfo_t *certinfo, **certinfop;
+ int cmp = -1;
+
+ /* find location */
+ ocsp_location_t *location = get_ocsp_location(loc, ocsp_cache);
+
+ if (location == NULL)
+ return CERT_UNDEFINED;
+
+ /* traverse list of certinfos in increasing order */
+ certinfop = &location->certinfo;
+ certinfo = *certinfop;
+
+ while (certinfo != NULL)
+ {
+ cmp = cmp_chunk(serialNumber, certinfo->serialNumber);
+ if (cmp <= 0)
+ break;
+ certinfop = &certinfo->next;
+ certinfo = *certinfop;
+ }
+
+ if (cmp == 0)
+ {
+ *nextUpdate = certinfo->nextUpdate;
+ *revocationTime = certinfo->revocationTime;
+ *revocationReason = certinfo->revocationReason;
+ return certinfo->status;
+ }
+
+ return CERT_UNDEFINED;
+}
+
+/*
+ * verify the ocsp status of a certificate
+ */
+cert_status_t
+verify_by_ocsp(const x509cert_t *cert, time_t *until
+, time_t *revocationDate, crl_reason_t *revocationReason)
+{
+ cert_status_t status;
+ ocsp_location_t location;
+ time_t nextUpdate = 0;
+
+ *revocationDate = UNDEFINED_TIME;
+ *revocationReason = REASON_UNSPECIFIED;
+
+ /* is an ocsp location defined? */
+ if (!build_ocsp_location(cert, &location))
+ return CERT_UNDEFINED;
+
+ lock_ocsp_cache("verify_by_ocsp");
+ status = get_ocsp_status(&location, cert->serialNumber, &nextUpdate
+ , revocationDate, revocationReason);
+ unlock_ocsp_cache("verify_by_ocsp");
+
+ if (status == CERT_UNDEFINED || nextUpdate < time(NULL))
+ {
+ plog("ocsp status is stale or not in cache");
+ add_ocsp_fetch_request(&location, cert->serialNumber);
+
+ /* inititate fetching of ocsp status */
+ wake_fetch_thread("verify_by_ocsp");
+ }
+ *until = nextUpdate;
+ return status;
+}
+
+/*
+ * check if an ocsp status is about to expire
+ */
+void
+check_ocsp(void)
+{
+ ocsp_location_t *location;
+
+ lock_ocsp_cache("check_ocsp");
+ location = ocsp_cache;
+
+ while (location != NULL)
+ {
+ char buf[BUF_LEN];
+ bool first = TRUE;
+ ocsp_certinfo_t *certinfo = location->certinfo;
+
+ while (certinfo != NULL)
+ {
+ if (!certinfo->once)
+ {
+ time_t time_left = certinfo->nextUpdate - time(NULL);
+
+ DBG(DBG_CONTROL,
+ if (first)
+ {
+ dntoa(buf, BUF_LEN, location->issuer);
+ DBG_log("issuer: '%s'", buf);
+ if (location->authKeyID.ptr != NULL)
+ {
+ datatot(location->authKeyID.ptr, location->authKeyID.len
+ , ':', buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ first = FALSE;
+ }
+ datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len
+ , ':', buf, BUF_LEN);
+ DBG_log("serial: %s, %ld seconds left", buf, time_left)
+ )
+
+ if (time_left < 2*crl_check_interval)
+ add_ocsp_fetch_request(location, certinfo->serialNumber);
+ }
+ certinfo = certinfo->next;
+ }
+ location = location->next;
+ }
+ unlock_ocsp_cache("check_ocsp");
+}
+
+/*
+ * frees the allocated memory of a certinfo struct
+ */
+static void
+free_certinfo(ocsp_certinfo_t *certinfo)
+{
+ freeanychunk(certinfo->serialNumber);
+ pfree(certinfo);
+}
+
+/*
+ * frees all certinfos in a chained list
+ */
+static void
+free_certinfos(ocsp_certinfo_t *chain)
+{
+ ocsp_certinfo_t *certinfo;
+
+ while (chain != NULL)
+ {
+ certinfo = chain;
+ chain = chain->next;
+ free_certinfo(certinfo);
+ }
+}
+
+/*
+ * frees the memory allocated to an ocsp location including all certinfos
+ */
+static void
+free_ocsp_location(ocsp_location_t* location)
+{
+ freeanychunk(location->issuer);
+ freeanychunk(location->authNameID);
+ freeanychunk(location->authKeyID);
+ freeanychunk(location->authKeySerialNumber);
+ freeanychunk(location->uri);
+ free_certinfos(location->certinfo);
+ pfree(location);
+}
+
+/*
+ * free a chained list of ocsp locations
+ */
+void
+free_ocsp_locations(ocsp_location_t **chain)
+{
+ while (*chain != NULL)
+ {
+ ocsp_location_t *location = *chain;
+ *chain = location->next;
+ free_ocsp_location(location);
+ }
+}
+
+/*
+ * free the ocsp cache
+ */
+void
+free_ocsp_cache(void)
+{
+ lock_ocsp_cache("free_ocsp_cache");
+ free_ocsp_locations(&ocsp_cache);
+ unlock_ocsp_cache("free_ocsp_cache");
+}
+
+/*
+ * frees the ocsp cache and global variables
+ */
+void
+free_ocsp(void)
+{
+ pfreeany(ocsp_default_uri.ptr);
+ free_ocsp_cache();
+}
+
+/*
+ * list a chained list of ocsp_locations
+ */
+void
+list_ocsp_locations(ocsp_location_t *location, bool requests, bool utc
+, bool strict)
+{
+ bool first = TRUE;
+
+ while (location != NULL)
+ {
+ ocsp_certinfo_t *certinfo = location->certinfo;
+
+ if (certinfo != NULL)
+ {
+ u_char buf[BUF_LEN];
+
+ if (first)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of OCSP %s:", requests?
+ "fetch requests":"responses");
+ first = FALSE;
+ }
+ whack_log(RC_COMMENT, " ");
+ if (location->issuer.ptr != NULL)
+ {
+ dntoa(buf, BUF_LEN, location->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ }
+ whack_log(RC_COMMENT, " uri: '%.*s'", (int)location->uri.len
+ , location->uri.ptr);
+ if (location->authNameID.ptr != NULL)
+ {
+ datatot(location->authNameID.ptr, location->authNameID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authname: %s", buf);
+ }
+ if (location->authKeyID.ptr != NULL)
+ {
+ datatot(location->authKeyID.ptr, location->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (location->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(location->authKeySerialNumber.ptr
+ , location->authKeySerialNumber.len, ':', buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+ while (certinfo != NULL)
+ {
+ char thisUpdate[TIMETOA_BUF];
+
+ strcpy(thisUpdate, timetoa(&certinfo->thisUpdate, utc));
+
+ if (requests)
+ {
+ whack_log(RC_COMMENT, "%s, trials: %d", thisUpdate
+ , certinfo->trials);
+ }
+ else if (certinfo->once)
+ {
+ whack_log(RC_COMMENT, "%s, onetime use%s", thisUpdate
+ , (certinfo->nextUpdate < time(NULL))? " (expired)": "");
+ }
+ else
+ {
+ whack_log(RC_COMMENT, "%s, until %s %s", thisUpdate
+ , timetoa(&certinfo->nextUpdate, utc)
+ , check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict));
+ }
+ datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " serial: %s, %s", buf
+ , cert_status_names[certinfo->status]);
+ certinfo = certinfo->next;
+ }
+ }
+ location = location->next;
+ }
+}
+
+/*
+ * list the ocsp cache
+ */
+void
+list_ocsp_cache(bool utc, bool strict)
+{
+ lock_ocsp_cache("list_ocsp_cache");
+ list_ocsp_locations(ocsp_cache, FALSE, utc, strict);
+ unlock_ocsp_cache("list_ocsp_cache");
+}
+
+static bool
+get_ocsp_requestor_cert(ocsp_location_t *location)
+{
+ x509cert_t *cert = NULL;
+
+ /* initialize temporary static storage */
+ ocsp_requestor_cert = NULL;
+ ocsp_requestor_sc = NULL;
+ ocsp_requestor_pri = NULL;
+
+ for (;;)
+ {
+ char buf[BUF_LEN];
+
+ /* looking for a certificate from the same issuer */
+ cert = get_x509cert(location->issuer, location->authKeySerialNumber
+ ,location->authKeyID, cert);
+ if (cert == NULL)
+ break;
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("candidate: '%s'", buf);
+ )
+
+ if (cert->smartcard)
+ {
+ /* look for a matching private key on a smartcard */
+ smartcard_t *sc = scx_get(cert);
+
+ if (sc != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("matching smartcard found")
+ )
+ if (sc->valid)
+ {
+ ocsp_requestor_cert = cert;
+ ocsp_requestor_sc = sc;
+ return TRUE;
+ }
+ plog("unable to sign ocsp request without PIN");
+ }
+ }
+ else
+ {
+ /* look for a matching private key in the chained list */
+ const struct RSA_private_key *pri = get_x509_private_key(cert);
+
+ if (pri != NULL)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("matching private key found")
+ )
+ ocsp_requestor_cert = cert;
+ ocsp_requestor_pri = pri;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+static chunk_t
+generate_signature(chunk_t digest, smartcard_t *sc
+ , const RSA_private_key_t *pri)
+{
+ chunk_t sigdata;
+ u_char *pos;
+ size_t siglen = 0;
+
+ if (sc != NULL)
+ {
+ /* RSA signature is done on smartcard */
+
+ if (!scx_establish_context(sc) || !scx_login(sc))
+ {
+ scx_release_context(sc);
+ return empty_chunk;
+ }
+
+ siglen = scx_get_keylength(sc);
+
+ if (siglen == 0)
+ {
+ plog("failed to get keylength from smartcard");
+ scx_release_context(sc);
+ return empty_chunk;
+ }
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
+ , (int)sc->slot, sc->id)
+ )
+
+ pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
+ *pos++ = 0x00;
+ scx_sign_hash(sc, digest.ptr, digest.len, pos, siglen);
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ }
+ else
+ {
+ /* RSA signature is done in software */
+ siglen = pri->pub.k;
+ pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
+ *pos++ = 0x00;
+ sign_hash(pri, digest.ptr, digest.len, pos, siglen);
+ }
+ return sigdata;
+}
+
+/*
+ * build signature into ocsp request
+ * gets built only if a request cert with
+ * a corresponding private key is found
+ */
+static chunk_t
+build_signature(chunk_t tbsRequest)
+{
+ chunk_t sigdata, certs;
+ chunk_t digest_info;
+
+ u_char digest_buf[MAX_DIGEST_LEN];
+ chunk_t digest_raw = { digest_buf, MAX_DIGEST_LEN };
+
+ if (!compute_digest(tbsRequest, OID_SHA1, &digest_raw))
+ return empty_chunk;
+
+ /* according to PKCS#1 v2.1 digest must be packaged into
+ * an ASN.1 structure for encryption
+ */
+ digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_sha1_id
+ , asn1_simple_object(ASN1_OCTET_STRING, digest_raw));
+
+ /* generate the RSA signature */
+ sigdata = generate_signature(digest_info
+ , ocsp_requestor_sc
+ , ocsp_requestor_pri);
+ freeanychunk(digest_info);
+
+ /* has the RSA signature generation been successful? */
+ if (sigdata.ptr == NULL)
+ return empty_chunk;
+
+ /* include our certificate */
+ certs = asn1_wrap(ASN1_CONTEXT_C_0, "m"
+ , asn1_simple_object(ASN1_SEQUENCE
+ , ocsp_requestor_cert->certificate
+ )
+ );
+
+ /* build signature comprising algorithm, signature and cert */
+ return asn1_wrap(ASN1_CONTEXT_C_0, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "cmm"
+ , ASN1_sha1WithRSA_id
+ , sigdata
+ , certs
+ )
+ );
+}
+
+/* build request (into requestList)
+ * no singleRequestExtensions used
+ */
+static chunk_t
+build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo)
+{
+ chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm"
+ , ASN1_sha1_id
+ , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID)
+ , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID)
+ , asn1_simple_object(ASN1_INTEGER, certinfo->serialNumber));
+
+ return asn1_wrap(ASN1_SEQUENCE, "m", reqCert);
+}
+
+/*
+ * build requestList (into TBSRequest)
+ */
+static chunk_t
+build_request_list(ocsp_location_t *location)
+{
+ chunk_t requestList;
+ request_list_t *reqs = NULL;
+ ocsp_certinfo_t *certinfo = location->certinfo;
+ u_char *pos;
+
+ size_t datalen = 0;
+
+ /* build content */
+ while (certinfo != NULL)
+ {
+ /* build request for every certificate in list
+ * and store them in a chained list
+ */
+ request_list_t *req = alloc_thing(request_list_t, "ocsp request");
+
+ req->request = build_request(location, certinfo);
+ req->next = reqs;
+ reqs = req;
+
+ datalen += req->request.len;
+ certinfo = certinfo->next;
+ }
+
+ pos = build_asn1_object(&requestList, ASN1_SEQUENCE
+ , datalen);
+
+ /* copy all in chained list, free list afterwards */
+ while (reqs != NULL)
+ {
+ request_list_t *req = reqs;
+
+ mv_chunk(&pos, req->request);
+ reqs = reqs->next;
+ pfree(req);
+ }
+
+ return requestList;
+}
+
+/*
+ * build requestorName (into TBSRequest)
+ */
+static chunk_t
+build_requestor_name(void)
+{
+ return asn1_wrap(ASN1_CONTEXT_C_1, "m"
+ , asn1_simple_object(ASN1_CONTEXT_C_4
+ , ocsp_requestor_cert->subject));
+}
+
+/*
+ * build nonce extension (into requestExtensions)
+ */
+static chunk_t
+build_nonce_extension(ocsp_location_t *location)
+{
+ /* generate a random nonce */
+ location->nonce.ptr = alloc_bytes(NONCE_LENGTH, "ocsp nonce"),
+ location->nonce.len = NONCE_LENGTH;
+ get_rnd_bytes(location->nonce.ptr, NONCE_LENGTH);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_nonce_oid
+ , asn1_simple_object(ASN1_OCTET_STRING, location->nonce));
+}
+
+/*
+ * build requestExtensions (into TBSRequest)
+ */
+static chunk_t
+build_request_ext(ocsp_location_t *location)
+{
+ return asn1_wrap(ASN1_CONTEXT_C_2, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "mm"
+ , build_nonce_extension(location)
+ , asn1_wrap(ASN1_SEQUENCE, "cc"
+ , ASN1_response_oid
+ , ASN1_response_content
+ )
+ )
+ );
+}
+
+/*
+ * build TBSRequest (into OCSPRequest)
+ */
+static chunk_t
+build_tbs_request(ocsp_location_t *location, bool has_requestor_cert)
+{
+ /* version is skipped since the default is ok */
+ return asn1_wrap(ASN1_SEQUENCE, "mmm"
+ , (has_requestor_cert)
+ ? build_requestor_name()
+ : empty_chunk
+ , build_request_list(location)
+ , build_request_ext(location));
+}
+
+/* assembles an ocsp request to given location
+ * and sets nonce field in location to the sent nonce
+ */
+chunk_t
+build_ocsp_request(ocsp_location_t *location)
+{
+ bool has_requestor_cert;
+ chunk_t tbsRequest, signature;
+ char buf[BUF_LEN];
+
+ DBG(DBG_CONTROL,
+ DBG_log("assembling ocsp request");
+ dntoa(buf, BUF_LEN, location->issuer);
+ DBG_log("issuer: '%s'", buf);
+ if (location->authKeyID.ptr != NULL)
+ {
+ datatot(location->authKeyID.ptr, location->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+ lock_certs_and_keys("build_ocsp_request");
+
+ /* looks for requestor cert and matching private key */
+ has_requestor_cert = get_ocsp_requestor_cert(location);
+
+ /* build content */
+ tbsRequest = build_tbs_request(location, has_requestor_cert);
+
+ /* sign tbsReuqest */
+ signature = (has_requestor_cert)? build_signature(tbsRequest)
+ : empty_chunk;
+
+ unlock_certs_and_keys("build_ocsp_request");
+
+ return asn1_wrap(ASN1_SEQUENCE, "mm"
+ , tbsRequest
+ , signature);
+}
+
+/*
+ * check if the OCSP response has a valid signature
+ */
+static bool
+valid_ocsp_response(response_t *res)
+{
+ int pathlen;
+ x509cert_t *authcert;
+
+ lock_authcert_list("valid_ocsp_response");
+
+ authcert = get_authcert(res->responder_id_name, empty_chunk
+ , res->responder_id_key, AUTH_OCSP | AUTH_CA);
+
+ if (authcert == NULL)
+ {
+ plog("no matching ocsp signer cert found");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("ocsp signer cert found")
+ )
+
+ if (!check_signature(res->tbs, res->signature, res->algorithm
+ , res->algorithm, authcert))
+ {
+ plog("signature of ocsp response is invalid");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("signature of ocsp response is valid")
+ )
+
+
+ for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
+ {
+ u_char buf[BUF_LEN];
+ err_t ugh = NULL;
+ time_t until;
+
+ x509cert_t *cert = authcert;
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("subject: '%s'",buf);
+ dntoa(buf, BUF_LEN, cert->issuer);
+ DBG_log("issuer: '%s'",buf);
+ if (cert->authKeyID.ptr != NULL)
+ {
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+
+ ugh = check_validity(authcert, &until);
+
+ if (ugh != NULL)
+ {
+ plog("%s", ugh);
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is valid")
+ )
+
+ authcert = get_authcert(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID, AUTH_CA);
+
+ if (authcert == NULL)
+ {
+ plog("issuer cacert not found");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found")
+ )
+
+ if (!check_signature(cert->tbsCertificate, cert->signature
+ , cert->algorithm, cert->algorithm, authcert))
+ {
+ plog("certificate signature is invalid");
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate signature is valid")
+ )
+
+ /* check if cert is self-signed */
+ if (same_dn(cert->issuer, cert->subject))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("reached self-signed root ca")
+ )
+ unlock_authcert_list("valid_ocsp_response");
+ return TRUE;
+ }
+ }
+ plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
+ unlock_authcert_list("valid_ocsp_response");
+ return FALSE;
+}
+
+/*
+ * parse a basic OCSP response
+ */
+static bool
+parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
+{
+ u_int level, version;
+ u_int extn_oid = OID_UNKNOWN;
+ u_char buf[BUF_LEN];
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < BASIC_RESPONSE_ROOF)
+ {
+ if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case BASIC_RESPONSE_TBS_DATA:
+ res->tbs = object;
+ break;
+ case BASIC_RESPONSE_VERSION:
+ version = (object.len)? (1 + (u_int)*object.ptr) : 1;
+ if (version != OCSP_BASIC_RESPONSE_VERSION)
+ {
+ plog("wrong ocsp basic response version (version= %i)", version);
+ return FALSE;
+ }
+ break;
+ case BASIC_RESPONSE_ID_BY_NAME:
+ res->responder_id_name = object;
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case BASIC_RESPONSE_ID_BY_KEY:
+ res->responder_id_key = object;
+ break;
+ case BASIC_RESPONSE_PRODUCED_AT:
+ res->produced_at = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case BASIC_RESPONSE_RESPONSES:
+ res->responses = object;
+ break;
+ case BASIC_RESPONSE_EXT_ID:
+ extn_oid = known_oid(object);
+ break;
+ case BASIC_RESPONSE_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ break;
+ case BASIC_RESPONSE_EXT_VALUE:
+ if (extn_oid == OID_NONCE)
+ res->nonce = object;
+ break;
+ case BASIC_RESPONSE_ALGORITHM:
+ res->algorithm = parse_algorithmIdentifier(object, level+1, NULL);
+ break;
+ case BASIC_RESPONSE_SIGNATURE:
+ res->signature = object;
+ break;
+ case BASIC_RESPONSE_CERTIFICATE:
+ {
+ chunk_t blob;
+ x509cert_t *cert = alloc_thing(x509cert_t, "ocspcert");
+
+ clonetochunk(blob, object.ptr, object.len, "ocspcert blob");
+ *cert = empty_x509cert;
+
+ if (parse_x509cert(blob, level+1, cert)
+ && cert->isOcspSigner
+ && trust_authcert_candidate(cert, NULL))
+ {
+ add_authcert(cert, AUTH_OCSP);
+ }
+ else
+ {
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("embedded ocsp certificate rejected")
+ )
+ free_x509cert(cert);
+ }
+ }
+ break;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+
+/*
+ * parse an ocsp response and return the result as a response_t struct
+ */
+static response_status
+parse_ocsp_response(chunk_t blob, response_t * res)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ response_status rStatus = STATUS_INTERNALERROR;
+ u_int ocspResponseType = OID_UNKNOWN;
+
+ asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
+
+ while (objectID < OCSP_RESPONSE_ROOF)
+ {
+ if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx))
+ return STATUS_INTERNALERROR;
+
+ switch (objectID) {
+ case OCSP_RESPONSE_STATUS:
+ rStatus = (response_status) *object.ptr;
+
+ switch (rStatus)
+ {
+ case STATUS_SUCCESSFUL:
+ break;
+ case STATUS_MALFORMEDREQUEST:
+ case STATUS_INTERNALERROR:
+ case STATUS_TRYLATER:
+ case STATUS_SIGREQUIRED:
+ case STATUS_UNAUTHORIZED:
+ plog("ocsp response: server said '%s'"
+ , response_status_names[rStatus]);
+ return rStatus;
+ default:
+ return STATUS_INTERNALERROR;
+ }
+ break;
+ case OCSP_RESPONSE_TYPE:
+ ocspResponseType = known_oid(object);
+ break;
+ case OCSP_RESPONSE:
+ {
+ switch (ocspResponseType) {
+ case OID_BASIC:
+ if (!parse_basic_ocsp_response(object, level+1, res))
+ return STATUS_INTERNALERROR;
+ break;
+ default:
+ DBG(DBG_CONTROL,
+ DBG_log("ocsp response is not of type BASIC");
+ DBG_dump_chunk("ocsp response OID: ", object);
+ )
+ return STATUS_INTERNALERROR;
+ }
+ }
+ break;
+ }
+ objectID++;
+ }
+ return rStatus;
+}
+
+/*
+ * parse a basic OCSP response
+ */
+static bool
+parse_ocsp_single_response(chunk_t blob, int level0, single_response_t *sres)
+{
+ u_int level, extn_oid;
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < SINGLE_RESPONSE_ROOF)
+ {
+ if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case SINGLE_RESPONSE_ALGORITHM:
+ sres->hash_algorithm = parse_algorithmIdentifier(object, level+1, NULL);
+ break;
+ case SINGLE_RESPONSE_ISSUER_NAME_HASH:
+ sres->issuer_name_hash = object;
+ break;
+ case SINGLE_RESPONSE_ISSUER_KEY_HASH:
+ sres->issuer_key_hash = object;
+ break;
+ case SINGLE_RESPONSE_SERIAL_NUMBER:
+ sres->serialNumber = object;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_GOOD:
+ sres->status = CERT_GOOD;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_REVOKED:
+ sres->status = CERT_REVOKED;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME:
+ sres->revocationTime = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON:
+ sres->revocationReason = (object.len == 1)
+ ? *object.ptr : REASON_UNSPECIFIED;
+ break;
+ case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN:
+ sres->status = CERT_UNKNOWN;
+ break;
+ case SINGLE_RESPONSE_THIS_UPDATE:
+ sres->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case SINGLE_RESPONSE_NEXT_UPDATE:
+ sres->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
+ break;
+ case SINGLE_RESPONSE_EXT_ID:
+ extn_oid = known_oid(object);
+ break;
+ case SINGLE_RESPONSE_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ case SINGLE_RESPONSE_EXT_VALUE:
+ break;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/*
+ * add an ocsp location to a chained list
+ */
+ocsp_location_t*
+add_ocsp_location(const ocsp_location_t *loc, ocsp_location_t **chain)
+{
+ ocsp_location_t *location = alloc_thing(ocsp_location_t, "ocsp location");
+
+ /* unshare location fields */
+ clonetochunk(location->issuer
+ , loc->issuer.ptr, loc->issuer.len
+ , "ocsp issuer");
+
+ clonetochunk(location->authNameID
+ , loc->authNameID.ptr, loc->authNameID.len
+ , "ocsp authNameID");
+
+ if (loc->authKeyID.ptr == NULL)
+ location->authKeyID = empty_chunk;
+ else
+ clonetochunk(location->authKeyID
+ , loc->authKeyID.ptr, loc->authKeyID.len
+ , "ocsp authKeyID");
+
+ if (loc->authKeySerialNumber.ptr == NULL)
+ location->authKeySerialNumber = empty_chunk;
+ else
+ clonetochunk(location->authKeySerialNumber
+ , loc->authKeySerialNumber.ptr, loc->authKeySerialNumber.len
+ , "ocsp authKeySerialNumber");
+
+ clonetochunk(location->uri
+ , loc->uri.ptr, loc->uri.len
+ , "ocsp uri");
+
+ location->certinfo = NULL;
+
+ /* insert new ocsp location in front of chain */
+ location->next = *chain;
+ *chain = location;
+
+ DBG(DBG_CONTROL,
+ DBG_log("new ocsp location added")
+ )
+
+ return location;
+}
+
+/*
+ * add a certinfo struct to a chained list
+ */
+void
+add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, ocsp_location_t **chain
+ , bool request)
+{
+ ocsp_location_t *location;
+ ocsp_certinfo_t *certinfo, **certinfop;
+ char buf[BUF_LEN];
+ time_t now;
+ int cmp = -1;
+
+ location = get_ocsp_location(loc, *chain);
+ if (location == NULL)
+ location = add_ocsp_location(loc, chain);
+
+ /* traverse list of certinfos in increasing order */
+ certinfop = &location->certinfo;
+ certinfo = *certinfop;
+
+ while (certinfo != NULL)
+ {
+ cmp = cmp_chunk(info->serialNumber, certinfo->serialNumber);
+ if (cmp <= 0)
+ break;
+ certinfop = &certinfo->next;
+ certinfo = *certinfop;
+ }
+
+ if (cmp != 0)
+ {
+ /* add a new certinfo entry */
+ ocsp_certinfo_t *cnew = alloc_thing(ocsp_certinfo_t, "ocsp certinfo");
+ clonetochunk(cnew->serialNumber, info->serialNumber.ptr
+ , info->serialNumber.len, "serialNumber");
+ cnew->next = certinfo;
+ *certinfop = cnew;
+ certinfo = cnew;
+ }
+
+ DBG(DBG_CONTROL,
+ datatot(info->serialNumber.ptr, info->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("ocsp %s for serial %s %s"
+ , request?"fetch request":"certinfo"
+ , buf
+ , (cmp == 0)? (request?"already exists":"updated"):"added")
+ )
+
+ time(&now);
+
+ if (request)
+ {
+ certinfo->status = CERT_UNDEFINED;
+
+ if (cmp != 0)
+ certinfo->thisUpdate = now;
+
+ certinfo->nextUpdate = UNDEFINED_TIME;
+ }
+ else
+ {
+ certinfo->status = info->status;
+ certinfo->revocationTime = info->revocationTime;
+ certinfo->revocationReason = info->revocationReason;
+
+ certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)?
+ info->thisUpdate : now;
+
+ certinfo->once = (info->nextUpdate == UNDEFINED_TIME);
+
+ certinfo->nextUpdate = (certinfo->once)?
+ (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate;
+ }
+}
+
+/*
+ * process received ocsp single response and add it to ocsp cache
+ */
+static void
+process_single_response(ocsp_location_t *location, single_response_t *sres)
+{
+ ocsp_certinfo_t *certinfo, **certinfop;
+ int cmp = -1;
+
+ if (sres->hash_algorithm != OID_SHA1)
+ {
+ plog("only SHA-1 hash supported in OCSP single response");
+ return;
+ }
+ if (!(same_chunk(sres->issuer_name_hash, location->authNameID)
+ && same_chunk(sres->issuer_key_hash, location->authKeyID)))
+ {
+ plog("ocsp single response has wrong issuer");
+ return;
+ }
+
+ /* traverse list of certinfos in increasing order */
+ certinfop = &location->certinfo;
+ certinfo = *certinfop;
+
+ while (certinfo != NULL)
+ {
+ cmp = cmp_chunk(sres->serialNumber, certinfo->serialNumber);
+ if (cmp <= 0)
+ break;
+ certinfop = &certinfo->next;
+ certinfo = *certinfop;
+ }
+
+ if (cmp != 0)
+ {
+ plog("received unrequested cert status from ocsp server");
+ return;
+ }
+
+ /* unlink cert from ocsp fetch request list */
+ *certinfop = certinfo->next;
+
+ /* update certinfo using the single response information */
+ certinfo->thisUpdate = sres->thisUpdate;
+ certinfo->nextUpdate = sres->nextUpdate;
+ certinfo->status = sres->status;
+ certinfo->revocationTime = sres->revocationTime;
+ certinfo->revocationReason = sres->revocationReason;
+
+ /* add or update certinfo in ocsp cache */
+ lock_ocsp_cache("process_single_response");
+ add_certinfo(location, certinfo, &ocsp_cache, FALSE);
+ unlock_ocsp_cache("process_single_response");
+
+ /* free certinfo unlinked from ocsp fetch request list */
+ free_certinfo(certinfo);
+
+}
+
+/*
+ * parse and verify ocsp response and update the ocsp cache
+ */
+void
+parse_ocsp(ocsp_location_t *location, chunk_t blob)
+{
+ response_t res = empty_response;
+
+ /* parse the ocsp response without looking at the single responses yet */
+ response_status status = parse_ocsp_response(blob, &res);
+
+ if (status != STATUS_SUCCESSFUL)
+ {
+ plog("error in ocsp response");
+ return;
+ }
+ /* check if there was a nonce in the request */
+ if (location->nonce.ptr != NULL && res.nonce.ptr == NULL)
+ {
+ plog("ocsp response contains no nonce, replay attack possible");
+ }
+ /* check if the nonce is identical */
+ if (res.nonce.ptr != NULL && !same_chunk(res.nonce, location->nonce))
+ {
+ plog("invalid nonce in ocsp response");
+ return;
+ }
+ /* check if the response is signed by a trusted key */
+ if (!valid_ocsp_response(&res))
+ {
+ plog("invalid ocsp response");
+ return;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("valid ocsp response")
+ )
+
+ /* now parse the single responses one at a time */
+ {
+ u_int level;
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+
+ asn1_init(&ctx, res.responses, 0, FALSE, DBG_RAW);
+
+ while (objectID < RESPONSES_ROOF)
+ {
+ if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx))
+ return;
+
+ if (objectID == RESPONSES_SINGLE_RESPONSE)
+ {
+ single_response_t sres = empty_single_response;
+
+ if (parse_ocsp_single_response(object, level+1, &sres))
+ {
+ process_single_response(location, &sres);
+ }
+ }
+ objectID++;
+ }
+ }
+}
diff --git a/programs/pluto/ocsp.h b/programs/pluto/ocsp.h
new file mode 100644
index 000000000..49e1026ec
--- /dev/null
+++ b/programs/pluto/ocsp.h
@@ -0,0 +1,85 @@
+/* Support of the Online Certificate Status Protocol (OCSP) Support
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * Zuercher Hochschule Winterthur
+ *
+ * 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.
+ *
+ */
+
+#include "constants.h"
+
+/* constants */
+
+#define OCSP_BASIC_RESPONSE_VERSION 1
+#define OCSP_DEFAULT_VALID_TIME 120 /* validity of one-time response in seconds */
+#define OCSP_WARNING_INTERVAL 2 /* days */
+
+/* OCSP response status */
+
+typedef enum {
+ STATUS_SUCCESSFUL = 0,
+ STATUS_MALFORMEDREQUEST = 1,
+ STATUS_INTERNALERROR = 2,
+ STATUS_TRYLATER = 3,
+ STATUS_SIGREQUIRED = 5,
+ STATUS_UNAUTHORIZED= 6
+} response_status;
+
+/* OCSP access structures */
+
+typedef struct ocsp_certinfo ocsp_certinfo_t;
+
+struct ocsp_certinfo {
+ ocsp_certinfo_t *next;
+ int trials;
+ chunk_t serialNumber;
+ cert_status_t status;
+ bool once;
+ crl_reason_t revocationReason;
+ time_t revocationTime;
+ time_t thisUpdate;
+ time_t nextUpdate;
+};
+
+typedef struct ocsp_location ocsp_location_t;
+
+struct ocsp_location {
+ ocsp_location_t *next;
+ chunk_t issuer;
+ chunk_t authNameID;
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ chunk_t uri;
+ chunk_t nonce;
+ ocsp_certinfo_t *certinfo;
+};
+
+extern ocsp_location_t* get_ocsp_location(const ocsp_location_t *loc
+ , ocsp_location_t *chain);
+extern ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc
+ , ocsp_location_t **chain);
+extern void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info
+ , ocsp_location_t **chain, bool request);
+extern void check_ocsp(void);
+extern cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until
+ , time_t *revocationTime, crl_reason_t *revocationReason);
+extern bool ocsp_set_request_cert(char* path);
+extern void ocsp_set_default_uri(char* uri);
+extern void ocsp_cache_add_cert(const x509cert_t* cert);
+extern chunk_t build_ocsp_request(ocsp_location_t* location);
+extern void parse_ocsp(ocsp_location_t* location, chunk_t blob);
+extern void list_ocsp_locations(ocsp_location_t *location, bool requests
+ , bool utc, bool strict);
+extern void list_ocsp_cache(bool utc, bool strict);
+extern void free_ocsp_locations(ocsp_location_t **chain);
+extern void free_ocsp_cache(void);
+extern void free_ocsp(void);
+extern void ocsp_purge_cache(void);
diff --git a/programs/pluto/oid.c b/programs/pluto/oid.c
new file mode 100644
index 000000000..4b0632de2
--- /dev/null
+++ b/programs/pluto/oid.c
@@ -0,0 +1,197 @@
+/* List of some useful object identifiers (OIDs)
+ * Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * This file has been automatically generated by the script oid.pl
+ * Do not edit manually!
+ */
+
+#include <stdlib.h>
+
+#include "oid.h"
+
+const oid_t oid_names[] = {
+ {0x02, 7, 1, "ITU-T Administration" }, /* 0 */
+ { 0x82, 0, 1, "" }, /* 1 */
+ { 0x06, 0, 1, "Germany ITU-T member" }, /* 2 */
+ { 0x01, 0, 1, "Deutsche Telekom AG" }, /* 3 */
+ { 0x0A, 0, 1, "" }, /* 4 */
+ { 0x07, 0, 1, "" }, /* 5 */
+ { 0x14, 0, 0, "ND" }, /* 6 */
+ {0x09, 18, 1, "data" }, /* 7 */
+ { 0x92, 0, 1, "" }, /* 8 */
+ { 0x26, 0, 1, "" }, /* 9 */
+ { 0x89, 0, 1, "" }, /* 10 */
+ { 0x93, 0, 1, "" }, /* 11 */
+ { 0xF2, 0, 1, "" }, /* 12 */
+ { 0x2C, 0, 1, "" }, /* 13 */
+ { 0x64, 0, 1, "pilot" }, /* 14 */
+ { 0x01, 0, 1, "pilotAttributeType" }, /* 15 */
+ { 0x01, 17, 0, "UID" }, /* 16 */
+ { 0x19, 0, 0, "DC" }, /* 17 */
+ {0x55, 51, 1, "X.500" }, /* 18 */
+ { 0x04, 36, 1, "X.509" }, /* 19 */
+ { 0x03, 21, 0, "CN" }, /* 20 */
+ { 0x04, 22, 0, "S" }, /* 21 */
+ { 0x05, 23, 0, "SN" }, /* 22 */
+ { 0x06, 24, 0, "C" }, /* 23 */
+ { 0x07, 25, 0, "L" }, /* 24 */
+ { 0x08, 26, 0, "ST" }, /* 25 */
+ { 0x0A, 27, 0, "O" }, /* 26 */
+ { 0x0B, 28, 0, "OU" }, /* 27 */
+ { 0x0C, 29, 0, "T" }, /* 28 */
+ { 0x0D, 30, 0, "D" }, /* 29 */
+ { 0x24, 31, 0, "userCertificate" }, /* 30 */
+ { 0x29, 32, 0, "N" }, /* 31 */
+ { 0x2A, 33, 0, "G" }, /* 32 */
+ { 0x2B, 34, 0, "I" }, /* 33 */
+ { 0x2D, 35, 0, "ID" }, /* 34 */
+ { 0x48, 0, 0, "role" }, /* 35 */
+ { 0x1D, 0, 1, "id-ce" }, /* 36 */
+ { 0x09, 38, 0, "subjectDirectoryAttrs" }, /* 37 */
+ { 0x0E, 39, 0, "subjectKeyIdentifier" }, /* 38 */
+ { 0x0F, 40, 0, "keyUsage" }, /* 39 */
+ { 0x10, 41, 0, "privateKeyUsagePeriod" }, /* 40 */
+ { 0x11, 42, 0, "subjectAltName" }, /* 41 */
+ { 0x12, 43, 0, "issuerAltName" }, /* 42 */
+ { 0x13, 44, 0, "basicConstraints" }, /* 43 */
+ { 0x15, 45, 0, "reasonCode" }, /* 44 */
+ { 0x1F, 46, 0, "crlDistributionPoints" }, /* 45 */
+ { 0x20, 47, 0, "certificatePolicies" }, /* 46 */
+ { 0x23, 48, 0, "authorityKeyIdentifier" }, /* 47 */
+ { 0x25, 49, 0, "extendedKeyUsage" }, /* 48 */
+ { 0x37, 50, 0, "targetInformation" }, /* 49 */
+ { 0x38, 0, 0, "noRevAvail" }, /* 50 */
+ {0x2A, 88, 1, "" }, /* 51 */
+ { 0x86, 0, 1, "" }, /* 52 */
+ { 0x48, 0, 1, "" }, /* 53 */
+ { 0x86, 0, 1, "" }, /* 54 */
+ { 0xF7, 0, 1, "" }, /* 55 */
+ { 0x0D, 0, 1, "RSADSI" }, /* 56 */
+ { 0x01, 83, 1, "PKCS" }, /* 57 */
+ { 0x01, 66, 1, "PKCS-1" }, /* 58 */
+ { 0x01, 60, 0, "rsaEncryption" }, /* 59 */
+ { 0x02, 61, 0, "md2WithRSAEncryption" }, /* 60 */
+ { 0x04, 62, 0, "md5WithRSAEncryption" }, /* 61 */
+ { 0x05, 63, 0, "sha-1WithRSAEncryption" }, /* 62 */
+ { 0x0B, 64, 0, "sha256WithRSAEncryption"}, /* 63 */
+ { 0x0C, 65, 0, "sha384WithRSAEncryption"}, /* 64 */
+ { 0x0D, 0, 0, "sha512WithRSAEncryption"}, /* 65 */
+ { 0x07, 73, 1, "PKCS-7" }, /* 66 */
+ { 0x01, 68, 0, "data" }, /* 67 */
+ { 0x02, 69, 0, "signedData" }, /* 68 */
+ { 0x03, 70, 0, "envelopedData" }, /* 69 */
+ { 0x04, 71, 0, "signedAndEnvelopedData" }, /* 70 */
+ { 0x05, 72, 0, "digestedData" }, /* 71 */
+ { 0x06, 0, 0, "encryptedData" }, /* 72 */
+ { 0x09, 0, 1, "PKCS-9" }, /* 73 */
+ { 0x01, 75, 0, "E" }, /* 74 */
+ { 0x02, 76, 0, "unstructuredName" }, /* 75 */
+ { 0x03, 77, 0, "contentType" }, /* 76 */
+ { 0x04, 78, 0, "messageDigest" }, /* 77 */
+ { 0x05, 79, 0, "signingTime" }, /* 78 */
+ { 0x06, 80, 0, "counterSignature" }, /* 79 */
+ { 0x07, 81, 0, "challengePassword" }, /* 80 */
+ { 0x08, 82, 0, "unstructuredAddress" }, /* 81 */
+ { 0x0E, 0, 0, "extensionRequest" }, /* 82 */
+ { 0x02, 86, 1, "digestAlgorithm" }, /* 83 */
+ { 0x02, 85, 0, "md2" }, /* 84 */
+ { 0x05, 0, 0, "md5" }, /* 85 */
+ { 0x03, 0, 1, "encryptionAlgorithm" }, /* 86 */
+ { 0x07, 0, 0, "3des-ede-cbc" }, /* 87 */
+ {0x2B, 149, 1, "" }, /* 88 */
+ { 0x06, 136, 1, "dod" }, /* 89 */
+ { 0x01, 0, 1, "internet" }, /* 90 */
+ { 0x04, 105, 1, "private" }, /* 91 */
+ { 0x01, 0, 1, "enterprise" }, /* 92 */
+ { 0x82, 98, 1, "" }, /* 93 */
+ { 0x37, 0, 1, "Microsoft" }, /* 94 */
+ { 0x0A, 0, 1, "" }, /* 95 */
+ { 0x03, 0, 1, "" }, /* 96 */
+ { 0x03, 0, 0, "msSGC" }, /* 97 */
+ { 0x89, 0, 1, "" }, /* 98 */
+ { 0x31, 0, 1, "" }, /* 99 */
+ { 0x01, 0, 1, "" }, /* 100 */
+ { 0x01, 0, 1, "" }, /* 101 */
+ { 0x02, 0, 1, "" }, /* 102 */
+ { 0x02, 104, 0, "" }, /* 103 */
+ { 0x4B, 0, 0, "TCGID" }, /* 104 */
+ { 0x05, 0, 1, "security" }, /* 105 */
+ { 0x05, 0, 1, "mechanisms" }, /* 106 */
+ { 0x07, 0, 1, "id-pkix" }, /* 107 */
+ { 0x01, 110, 1, "id-pe" }, /* 108 */
+ { 0x01, 0, 0, "authorityInfoAccess" }, /* 109 */
+ { 0x03, 120, 1, "id-kp" }, /* 110 */
+ { 0x01, 112, 0, "serverAuth" }, /* 111 */
+ { 0x02, 113, 0, "clientAuth" }, /* 112 */
+ { 0x03, 114, 0, "codeSigning" }, /* 113 */
+ { 0x04, 115, 0, "emailProtection" }, /* 114 */
+ { 0x05, 116, 0, "ipsecEndSystem" }, /* 115 */
+ { 0x06, 117, 0, "ipsecTunnel" }, /* 116 */
+ { 0x07, 118, 0, "ipsecUser" }, /* 117 */
+ { 0x08, 119, 0, "timeStamping" }, /* 118 */
+ { 0x09, 0, 0, "ocspSigning" }, /* 119 */
+ { 0x08, 122, 1, "id-otherNames" }, /* 120 */
+ { 0x05, 0, 0, "xmppAddr" }, /* 121 */
+ { 0x0A, 127, 1, "id-aca" }, /* 122 */
+ { 0x01, 124, 0, "authenticationInfo" }, /* 123 */
+ { 0x02, 125, 0, "accessIdentity" }, /* 124 */
+ { 0x03, 126, 0, "chargingIdentity" }, /* 125 */
+ { 0x04, 0, 0, "group" }, /* 126 */
+ { 0x30, 0, 1, "id-ad" }, /* 127 */
+ { 0x01, 0, 1, "ocsp" }, /* 128 */
+ { 0x01, 130, 0, "basic" }, /* 129 */
+ { 0x02, 131, 0, "nonce" }, /* 130 */
+ { 0x03, 132, 0, "crl" }, /* 131 */
+ { 0x04, 133, 0, "response" }, /* 132 */
+ { 0x05, 134, 0, "noCheck" }, /* 133 */
+ { 0x06, 135, 0, "archiveCutoff" }, /* 134 */
+ { 0x07, 0, 0, "serviceLocator" }, /* 135 */
+ { 0x0E, 142, 1, "oiw" }, /* 136 */
+ { 0x03, 0, 1, "secsig" }, /* 137 */
+ { 0x02, 0, 1, "algorithms" }, /* 138 */
+ { 0x07, 140, 0, "des-cbc" }, /* 139 */
+ { 0x1A, 141, 0, "sha-1" }, /* 140 */
+ { 0x1D, 0, 0, "sha-1WithRSASignature" }, /* 141 */
+ { 0x24, 0, 1, "TeleTrusT" }, /* 142 */
+ { 0x03, 0, 1, "algorithm" }, /* 143 */
+ { 0x03, 0, 1, "signatureAlgorithm" }, /* 144 */
+ { 0x01, 0, 1, "rsaSignature" }, /* 145 */
+ { 0x02, 147, 0, "rsaSigWithripemd160" }, /* 146 */
+ { 0x03, 148, 0, "rsaSigWithripemd128" }, /* 147 */
+ { 0x04, 0, 0, "rsaSigWithripemd256" }, /* 148 */
+ {0x60, 0, 1, "" }, /* 149 */
+ { 0x86, 0, 1, "" }, /* 150 */
+ { 0x48, 0, 1, "" }, /* 151 */
+ { 0x01, 0, 1, "organization" }, /* 152 */
+ { 0x65, 160, 1, "gov" }, /* 153 */
+ { 0x03, 0, 1, "csor" }, /* 154 */
+ { 0x04, 0, 1, "nistalgorithm" }, /* 155 */
+ { 0x02, 0, 1, "hashalgs" }, /* 156 */
+ { 0x01, 158, 0, "id-SHA-256" }, /* 157 */
+ { 0x02, 159, 0, "id-SHA-384" }, /* 158 */
+ { 0x03, 0, 0, "id-SHA-512" }, /* 159 */
+ { 0x86, 0, 1, "" }, /* 160 */
+ { 0xf8, 0, 1, "" }, /* 161 */
+ { 0x42, 174, 1, "netscape" }, /* 162 */
+ { 0x01, 169, 1, "" }, /* 163 */
+ { 0x01, 165, 0, "nsCertType" }, /* 164 */
+ { 0x03, 166, 0, "nsRevocationUrl" }, /* 165 */
+ { 0x04, 167, 0, "nsCaRevocationUrl" }, /* 166 */
+ { 0x08, 168, 0, "nsCaPolicyUrl" }, /* 167 */
+ { 0x0d, 0, 0, "nsComment" }, /* 168 */
+ { 0x03, 172, 1, "directory" }, /* 169 */
+ { 0x01, 0, 1, "" }, /* 170 */
+ { 0x03, 0, 0, "employeeNumber" }, /* 171 */
+ { 0x04, 0, 1, "policy" }, /* 172 */
+ { 0x01, 0, 0, "nsSGC" }, /* 173 */
+ { 0x45, 0, 1, "verisign" }, /* 174 */
+ { 0x01, 0, 1, "pki" }, /* 175 */
+ { 0x09, 0, 1, "attributes" }, /* 176 */
+ { 0x02, 178, 0, "messageType" }, /* 177 */
+ { 0x03, 179, 0, "pkiStatus" }, /* 178 */
+ { 0x04, 180, 0, "failInfo" }, /* 179 */
+ { 0x05, 181, 0, "senderNonce" }, /* 180 */
+ { 0x06, 182, 0, "recipientNonce" }, /* 181 */
+ { 0x07, 183, 0, "transID" }, /* 182 */
+ { 0x08, 0, 0, "extensionReq" } /* 183 */
+};
diff --git a/programs/pluto/oid.h b/programs/pluto/oid.h
new file mode 100644
index 000000000..71f8101cd
--- /dev/null
+++ b/programs/pluto/oid.h
@@ -0,0 +1,75 @@
+/* Object identifiers (OIDs) used by FreeS/WAN
+ * Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * This file has been automatically generated by the script oid.pl
+ * Do not edit manually!
+ */
+
+typedef struct {
+ u_char octet;
+ u_int next;
+ u_int down;
+ const u_char *name;
+} oid_t;
+
+extern const oid_t oid_names[];
+
+#define OID_UNKNOWN -1
+#define OID_ROLE 35
+#define OID_SUBJECT_KEY_ID 38
+#define OID_SUBJECT_ALT_NAME 41
+#define OID_BASIC_CONSTRAINTS 43
+#define OID_CRL_REASON_CODE 44
+#define OID_CRL_DISTRIBUTION_POINTS 45
+#define OID_AUTHORITY_KEY_ID 47
+#define OID_EXTENDED_KEY_USAGE 48
+#define OID_TARGET_INFORMATION 49
+#define OID_NO_REV_AVAIL 50
+#define OID_RSA_ENCRYPTION 59
+#define OID_MD2_WITH_RSA 60
+#define OID_MD5_WITH_RSA 61
+#define OID_SHA1_WITH_RSA 62
+#define OID_SHA256_WITH_RSA 63
+#define OID_SHA384_WITH_RSA 64
+#define OID_SHA512_WITH_RSA 65
+#define OID_PKCS7_DATA 67
+#define OID_PKCS7_SIGNED_DATA 68
+#define OID_PKCS7_ENVELOPED_DATA 69
+#define OID_PKCS7_SIGNED_ENVELOPED_DATA 70
+#define OID_PKCS7_DIGESTED_DATA 71
+#define OID_PKCS7_ENCRYPTED_DATA 72
+#define OID_PKCS9_EMAIL 74
+#define OID_PKCS9_CONTENT_TYPE 76
+#define OID_PKCS9_MESSAGE_DIGEST 77
+#define OID_PKCS9_SIGNING_TIME 78
+#define OID_MD2 84
+#define OID_MD5 85
+#define OID_3DES_EDE_CBC 87
+#define OID_AUTHORITY_INFO_ACCESS 109
+#define OID_OCSP_SIGNING 119
+#define OID_XMPP_ADDR 121
+#define OID_AUTHENTICATION_INFO 123
+#define OID_ACCESS_IDENTITY 124
+#define OID_CHARGING_IDENTITY 125
+#define OID_GROUP 126
+#define OID_OCSP 128
+#define OID_BASIC 129
+#define OID_NONCE 130
+#define OID_CRL 131
+#define OID_RESPONSE 132
+#define OID_NO_CHECK 133
+#define OID_ARCHIVE_CUTOFF 134
+#define OID_SERVICE_LOCATOR 135
+#define OID_DES_CBC 139
+#define OID_SHA1 140
+#define OID_SHA1_WITH_RSA_OIW 141
+#define OID_NS_REVOCATION_URL 165
+#define OID_NS_CA_REVOCATION_URL 166
+#define OID_NS_CA_POLICY_URL 167
+#define OID_NS_COMMENT 168
+#define OID_PKI_MESSAGE_TYPE 177
+#define OID_PKI_STATUS 178
+#define OID_PKI_FAIL_INFO 179
+#define OID_PKI_SENDER_NONCE 180
+#define OID_PKI_RECIPIENT_NONCE 181
+#define OID_PKI_TRANS_ID 182
diff --git a/programs/pluto/oid.pl b/programs/pluto/oid.pl
new file mode 100644
index 000000000..52ac8eae0
--- /dev/null
+++ b/programs/pluto/oid.pl
@@ -0,0 +1,123 @@
+#!/usr/bin/perl
+# Generates oid.h and oid.c out of oid.txt
+# Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+#
+# 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.
+#
+
+$copyright="Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur";
+$automatic="This file has been automatically generated by the script oid.pl";
+$warning="Do not edit manually!";
+
+print "oid.pl generating oid.h and oid.c\n";
+
+# Generate oid.h
+
+open(OID_H, ">oid.h")
+ or die "could not open 'oid.h': $!";
+
+print OID_H "/* Object identifiers (OIDs) used by FreeS/WAN\n",
+ " * ", $copyright, "\n",
+ " * \n",
+ " * ", $automatic, "\n",
+ " * ", $warning, "\n",
+ " */\n\n",
+ "typedef struct {\n",
+ " u_char octet;\n",
+ " u_int next;\n",
+ " u_int down;\n",
+ " const u_char *name;\n",
+ "} oid_t;\n",
+ "\n",
+ "extern const oid_t oid_names[];\n",
+ "\n",
+ "#define OID_UNKNOWN -1\n";
+
+# parse oid.txt
+
+open(SRC, "<oid.txt")
+ or die "could not open 'oid.txt': $!";
+
+$counter = 0;
+$max_name = 0;
+$max_order = 0;
+
+while ($line = <SRC>)
+{
+ $line =~ m/( *?)(0x\w{2})\s+(".*?")[ \t]*?([\w_]*?)\Z/;
+
+ @order[$counter] = length($1);
+ @octet[$counter] = $2;
+ @name[$counter] = $3;
+
+ if (length($1) > $max_order)
+ {
+ $max_order = length($1);
+ }
+ if (length($3) > $max_name)
+ {
+ $max_name = length($3);
+ }
+ if (length($4) > 0)
+ {
+ printf OID_H "#define %s%s%d\n", $4, "\t" x ((39-length($4))/8), $counter;
+ }
+ $counter++;
+}
+
+close SRC;
+close OID_H;
+
+# Generate oid.c
+
+open(OID_C, ">oid.c")
+ or die "could not open 'oid.c': $!";
+
+print OID_C "/* List of some useful object identifiers (OIDs)\n",
+ " * ", $copyright, "\n",
+ " * \n",
+ " * ", $automatic, "\n",
+ " * ", $warning, "\n",
+ " */\n",
+ "\n",
+ "#include <stdlib.h>\n",
+ "\n",
+ "#include \"oid.h\"\n",
+ "\n",
+ "const oid_t oid_names[] = {\n";
+
+for ($c = 0; $c < $counter; $c++)
+{
+ $next = 0;
+
+ for ($d = $c+1; $d < $counter && @order[$d] >= @order[$c]; $d++)
+ {
+ if (@order[$d] == @order[$c])
+ {
+ @next[$c] = $d;
+ last;
+ }
+ }
+
+ printf OID_C " {%s%s,%s%3d, %d, %s%s}%s /* %3d */\n"
+ ,' ' x @order[$c]
+ , @octet[$c]
+ , ' ' x (1 + $max_order - @order[$c])
+ , @next[$c]
+ , @order[$c+1] > @order[$c]
+ , @name[$c]
+ , ' ' x ($max_name - length(@name[$c]))
+ , $c != $counter-1 ? "," : " "
+ , $c;
+}
+
+print OID_C "};\n" ;
+close OID_C;
diff --git a/programs/pluto/oid.txt b/programs/pluto/oid.txt
new file mode 100644
index 000000000..eed46d59d
--- /dev/null
+++ b/programs/pluto/oid.txt
@@ -0,0 +1,184 @@
+0x02 "ITU-T Administration"
+ 0x82 ""
+ 0x06 "Germany ITU-T member"
+ 0x01 "Deutsche Telekom AG"
+ 0x0A ""
+ 0x07 ""
+ 0x14 "ND"
+0x09 "data"
+ 0x92 ""
+ 0x26 ""
+ 0x89 ""
+ 0x93 ""
+ 0xF2 ""
+ 0x2C ""
+ 0x64 "pilot"
+ 0x01 "pilotAttributeType"
+ 0x01 "UID"
+ 0x19 "DC"
+0x55 "X.500"
+ 0x04 "X.509"
+ 0x03 "CN"
+ 0x04 "S"
+ 0x05 "SN"
+ 0x06 "C"
+ 0x07 "L"
+ 0x08 "ST"
+ 0x0A "O"
+ 0x0B "OU"
+ 0x0C "T"
+ 0x0D "D"
+ 0x24 "userCertificate"
+ 0x29 "N"
+ 0x2A "G"
+ 0x2B "I"
+ 0x2D "ID"
+ 0x48 "role" OID_ROLE
+ 0x1D "id-ce"
+ 0x09 "subjectDirectoryAttrs"
+ 0x0E "subjectKeyIdentifier" OID_SUBJECT_KEY_ID
+ 0x0F "keyUsage"
+ 0x10 "privateKeyUsagePeriod"
+ 0x11 "subjectAltName" OID_SUBJECT_ALT_NAME
+ 0x12 "issuerAltName"
+ 0x13 "basicConstraints" OID_BASIC_CONSTRAINTS
+ 0x15 "reasonCode" OID_CRL_REASON_CODE
+ 0x1F "crlDistributionPoints" OID_CRL_DISTRIBUTION_POINTS
+ 0x20 "certificatePolicies"
+ 0x23 "authorityKeyIdentifier" OID_AUTHORITY_KEY_ID
+ 0x25 "extendedKeyUsage" OID_EXTENDED_KEY_USAGE
+ 0x37 "targetInformation" OID_TARGET_INFORMATION
+ 0x38 "noRevAvail" OID_NO_REV_AVAIL
+0x2A ""
+ 0x86 ""
+ 0x48 ""
+ 0x86 ""
+ 0xF7 ""
+ 0x0D "RSADSI"
+ 0x01 "PKCS"
+ 0x01 "PKCS-1"
+ 0x01 "rsaEncryption" OID_RSA_ENCRYPTION
+ 0x02 "md2WithRSAEncryption" OID_MD2_WITH_RSA
+ 0x04 "md5WithRSAEncryption" OID_MD5_WITH_RSA
+ 0x05 "sha-1WithRSAEncryption" OID_SHA1_WITH_RSA
+ 0x0B "sha256WithRSAEncryption" OID_SHA256_WITH_RSA
+ 0x0C "sha384WithRSAEncryption" OID_SHA384_WITH_RSA
+ 0x0D "sha512WithRSAEncryption" OID_SHA512_WITH_RSA
+ 0x07 "PKCS-7"
+ 0x01 "data" OID_PKCS7_DATA
+ 0x02 "signedData" OID_PKCS7_SIGNED_DATA
+ 0x03 "envelopedData" OID_PKCS7_ENVELOPED_DATA
+ 0x04 "signedAndEnvelopedData" OID_PKCS7_SIGNED_ENVELOPED_DATA
+ 0x05 "digestedData" OID_PKCS7_DIGESTED_DATA
+ 0x06 "encryptedData" OID_PKCS7_ENCRYPTED_DATA
+ 0x09 "PKCS-9"
+ 0x01 "E" OID_PKCS9_EMAIL
+ 0x02 "unstructuredName"
+ 0x03 "contentType" OID_PKCS9_CONTENT_TYPE
+ 0x04 "messageDigest" OID_PKCS9_MESSAGE_DIGEST
+ 0x05 "signingTime" OID_PKCS9_SIGNING_TIME
+ 0x06 "counterSignature"
+ 0x07 "challengePassword"
+ 0x08 "unstructuredAddress"
+ 0x0E "extensionRequest"
+ 0x02 "digestAlgorithm"
+ 0x02 "md2" OID_MD2
+ 0x05 "md5" OID_MD5
+ 0x03 "encryptionAlgorithm"
+ 0x07 "3des-ede-cbc" OID_3DES_EDE_CBC
+0x2B ""
+ 0x06 "dod"
+ 0x01 "internet"
+ 0x04 "private"
+ 0x01 "enterprise"
+ 0x82 ""
+ 0x37 "Microsoft"
+ 0x0A ""
+ 0x03 ""
+ 0x03 "msSGC"
+ 0x89 ""
+ 0x31 ""
+ 0x01 ""
+ 0x01 ""
+ 0x02 ""
+ 0x02 ""
+ 0x4B "TCGID"
+ 0x05 "security"
+ 0x05 "mechanisms"
+ 0x07 "id-pkix"
+ 0x01 "id-pe"
+ 0x01 "authorityInfoAccess" OID_AUTHORITY_INFO_ACCESS
+ 0x03 "id-kp"
+ 0x01 "serverAuth"
+ 0x02 "clientAuth"
+ 0x03 "codeSigning"
+ 0x04 "emailProtection"
+ 0x05 "ipsecEndSystem"
+ 0x06 "ipsecTunnel"
+ 0x07 "ipsecUser"
+ 0x08 "timeStamping"
+ 0x09 "ocspSigning" OID_OCSP_SIGNING
+ 0x08 "id-otherNames"
+ 0x05 "xmppAddr" OID_XMPP_ADDR
+ 0x0A "id-aca"
+ 0x01 "authenticationInfo" OID_AUTHENTICATION_INFO
+ 0x02 "accessIdentity" OID_ACCESS_IDENTITY
+ 0x03 "chargingIdentity" OID_CHARGING_IDENTITY
+ 0x04 "group" OID_GROUP
+ 0x30 "id-ad"
+ 0x01 "ocsp" OID_OCSP
+ 0x01 "basic" OID_BASIC
+ 0x02 "nonce" OID_NONCE
+ 0x03 "crl" OID_CRL
+ 0x04 "response" OID_RESPONSE
+ 0x05 "noCheck" OID_NO_CHECK
+ 0x06 "archiveCutoff" OID_ARCHIVE_CUTOFF
+ 0x07 "serviceLocator" OID_SERVICE_LOCATOR
+ 0x0E "oiw"
+ 0x03 "secsig"
+ 0x02 "algorithms"
+ 0x07 "des-cbc" OID_DES_CBC
+ 0x1A "sha-1" OID_SHA1
+ 0x1D "sha-1WithRSASignature" OID_SHA1_WITH_RSA_OIW
+ 0x24 "TeleTrusT"
+ 0x03 "algorithm"
+ 0x03 "signatureAlgorithm"
+ 0x01 "rsaSignature"
+ 0x02 "rsaSigWithripemd160"
+ 0x03 "rsaSigWithripemd128"
+ 0x04 "rsaSigWithripemd256"
+0x60 ""
+ 0x86 ""
+ 0x48 ""
+ 0x01 "organization"
+ 0x65 "gov"
+ 0x03 "csor"
+ 0x04 "nistalgorithm"
+ 0x02 "hashalgs"
+ 0x01 "id-SHA-256"
+ 0x02 "id-SHA-384"
+ 0x03 "id-SHA-512"
+ 0x86 ""
+ 0xf8 ""
+ 0x42 "netscape"
+ 0x01 ""
+ 0x01 "nsCertType"
+ 0x03 "nsRevocationUrl" OID_NS_REVOCATION_URL
+ 0x04 "nsCaRevocationUrl" OID_NS_CA_REVOCATION_URL
+ 0x08 "nsCaPolicyUrl" OID_NS_CA_POLICY_URL
+ 0x0d "nsComment" OID_NS_COMMENT
+ 0x03 "directory"
+ 0x01 ""
+ 0x03 "employeeNumber"
+ 0x04 "policy"
+ 0x01 "nsSGC"
+ 0x45 "verisign"
+ 0x01 "pki"
+ 0x09 "attributes"
+ 0x02 "messageType" OID_PKI_MESSAGE_TYPE
+ 0x03 "pkiStatus" OID_PKI_STATUS
+ 0x04 "failInfo" OID_PKI_FAIL_INFO
+ 0x05 "senderNonce" OID_PKI_SENDER_NONCE
+ 0x06 "recipientNonce" OID_PKI_RECIPIENT_NONCE
+ 0x07 "transID" OID_PKI_TRANS_ID
+ 0x08 "extensionReq"
diff --git a/programs/pluto/packet.c b/programs/pluto/packet.c
new file mode 100644
index 000000000..9f04c8bb2
--- /dev/null
+++ b/programs/pluto/packet.c
@@ -0,0 +1,1244 @@
+/* parsing packets: formats and tools
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: packet.c,v 1.7 2005/01/06 22:39:04 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <netinet/in.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "packet.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+
+/* ISAKMP Header: for all messages
+ * layout from RFC 2408 "ISAKMP" section 3.1
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Initiator !
+ * ! Cookie !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Responder !
+ * ! Cookie !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Message ID !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+static field_desc isa_fields[] = {
+ { ft_raw, COOKIE_SIZE, "initiator cookie", NULL },
+ { ft_raw, COOKIE_SIZE, "responder cookie", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_enum, 8/BITS_PER_BYTE, "ISAKMP version", &version_names },
+ { ft_enum, 8/BITS_PER_BYTE, "exchange type", &exchange_names },
+ { ft_set, 8/BITS_PER_BYTE, "flags", flag_bit_names },
+ { ft_raw, 32/BITS_PER_BYTE, "message ID", NULL },
+ { ft_len, 32/BITS_PER_BYTE, "length", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_hdr_desc = { "ISAKMP Message", isa_fields, sizeof(struct isakmp_hdr) };
+
+/* Generic portion of all ISAKMP payloads.
+ * layout from RFC 2408 "ISAKMP" section 3.2
+ * This describes the first 32-bit chunk of all payloads.
+ * The previous next payload depends on the actual payload type.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+static field_desc isag_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_generic_desc = { "ISAKMP Generic Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+
+/* ISAKMP Data Attribute (generic representation within payloads)
+ * layout from RFC 2408 "ISAKMP" section 3.3
+ * This is not a payload type.
+ * In TLV format, this is followed by a value field.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * !A! Attribute Type ! AF=0 Attribute Length !
+ * !F! ! AF=1 Attribute Value !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * . AF=0 Attribute Value .
+ * . AF=1 Not Transmitted .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/* Oakley Attributes */
+static field_desc isaat_fields_oakley[] = {
+ { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &oakley_attr_names },
+ { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_oakley_attribute_desc = {
+ "ISAKMP Oakley attribute",
+ isaat_fields_oakley, sizeof(struct isakmp_attribute) };
+
+/* IPsec DOI Attributes */
+static field_desc isaat_fields_ipsec[] = {
+ { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &ipsec_attr_names },
+ { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_ipsec_attribute_desc = {
+ "ISAKMP IPsec DOI attribute",
+ isaat_fields_ipsec, sizeof(struct isakmp_attribute) };
+
+/* Mode Config Attributes */
+static field_desc isaat_fields_modecfg[] = {
+ { ft_af_loose_enum, 16/BITS_PER_BYTE, "ModeCfg attr type", &modecfg_attr_names },
+ { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_modecfg_attribute_desc = {
+ "ISAKMP ModeCfg attribute",
+ isaat_fields_modecfg, sizeof(struct isakmp_attribute) };
+
+/* ISAKMP Security Association Payload
+ * layout from RFC 2408 "ISAKMP" section 3.4
+ * A variable length Situation follows.
+ * Previous next payload: ISAKMP_NEXT_SA
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Situation ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isasa_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_sa_desc = { "ISAKMP Security Association Payload", isasa_fields, sizeof(struct isakmp_sa) };
+
+static field_desc ipsec_sit_field[] = {
+ { ft_set, 32/BITS_PER_BYTE, "IPsec DOI SIT", &sit_bit_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc ipsec_sit_desc = { "IPsec DOI SIT", ipsec_sit_field, sizeof(u_int32_t) };
+
+/* ISAKMP Proposal Payload
+ * layout from RFC 2408 "ISAKMP" section 3.5
+ * A variable length SPI follows.
+ * Previous next payload: ISAKMP_NEXT_P
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms!
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! SPI (variable) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isap_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "proposal number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "protocol ID", &protocol_names },
+ { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "number of transforms", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_proposal_desc = { "ISAKMP Proposal Payload", isap_fields, sizeof(struct isakmp_proposal) };
+
+/* ISAKMP Transform Payload
+ * layout from RFC 2408 "ISAKMP" section 3.6
+ * Variable length SA Attributes follow.
+ * Previous next payload: ISAKMP_NEXT_T
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Transform # ! Transform-Id ! RESERVED2 !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ SA Attributes ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/* PROTO_ISAKMP */
+static field_desc isat_fields_isakmp[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "transform ID", &isakmp_transformid_names },
+ { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_isakmp_transform_desc = {
+ "ISAKMP Transform Payload (ISAKMP)",
+ isat_fields_isakmp, sizeof(struct isakmp_transform) };
+
+/* PROTO_IPSEC_AH */
+static field_desc isat_fields_ah[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ah_transformid_names },
+ { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_ah_transform_desc = {
+ "ISAKMP Transform Payload (AH)",
+ isat_fields_ah, sizeof(struct isakmp_transform) };
+
+/* PROTO_IPSEC_ESP */
+static field_desc isat_fields_esp[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "transform ID", &esp_transformid_names },
+ { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_esp_transform_desc = {
+ "ISAKMP Transform Payload (ESP)",
+ isat_fields_esp, sizeof(struct isakmp_transform) };
+
+/* PROTO_IPCOMP */
+static field_desc isat_fields_ipcomp[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ipcomp_transformid_names },
+ { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_ipcomp_transform_desc = {
+ "ISAKMP Transform Payload (COMP)",
+ isat_fields_ipcomp, sizeof(struct isakmp_transform) };
+
+
+/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.7
+ * Variable Key Exchange Data follow the generic fields.
+ * Previous next payload: ISAKMP_NEXT_KE
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Key Exchange Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_keyex_desc = { "ISAKMP Key Exchange Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP Identification Payload
+ * layout from RFC 2408 "ISAKMP" section 3.8
+ * See "struct identity" declared later.
+ * Variable length Identification Data follow.
+ * Previous next payload: ISAKMP_NEXT_ID
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! DOI Specific ID Data !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Identification Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isaid_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, /* ??? depends on DOI? */
+ { ft_nat, 8/BITS_PER_BYTE, "DOI specific A", NULL }, /* ??? depends on DOI? */
+ { ft_nat, 16/BITS_PER_BYTE, "DOI specific B", NULL }, /* ??? depends on DOI? */
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_identification_desc = { "ISAKMP Identification Payload", isaid_fields, sizeof(struct isakmp_id) };
+
+/* IPSEC Identification Payload Content
+ * layout from RFC 2407 "IPsec DOI" section 4.6.2
+ * See struct isakmp_id declared earlier.
+ * Note: Hashing skips the ISAKMP generic payload header
+ * Variable length Identification Data follow.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! Protocol ID ! Port !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~ Identification Data ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isaiid_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
+ { ft_nat, 8/BITS_PER_BYTE, "Protocol ID", NULL }, /* ??? UDP/TCP or 0? */
+ { ft_nat, 16/BITS_PER_BYTE, "port", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_ipsec_identification_desc = { "ISAKMP Identification Payload (IPsec DOI)", isaiid_fields, sizeof(struct isakmp_ipsec_id) };
+
+/* ISAKMP Certificate Payload: oddball fixed field beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.9
+ * Variable length Certificate Data follow the generic fields.
+ * Previous next payload: ISAKMP_NEXT_CERT.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Cert Encoding ! !
+ * +-+-+-+-+-+-+-+-+ !
+ * ~ Certificate Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isacert_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "cert encoding", &cert_type_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+/* Note: the size field of isakmp_ipsec_certificate_desc cannot be
+ * sizeof(struct isakmp_cert) because that will rounded up for padding.
+ */
+ struct_desc isakmp_ipsec_certificate_desc = { "ISAKMP Certificate Payload", isacert_fields, ISAKMP_CERT_SIZE };
+
+/* ISAKMP Certificate Request Payload: oddball field beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.10
+ * Variable length Certificate Types and Certificate Authorities follow.
+ * Previous next payload: ISAKMP_NEXT_CR.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Cert. Type ! !
+ * +-+-+-+-+-+-+-+-+ !
+ * ~ Certificate Authority ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isacr_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "cert type", &cert_type_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+/* Note: the size field of isakmp_ipsec_cert_req_desc cannot be
+ * sizeof(struct isakmp_cr) because that will rounded up for padding.
+ */
+struct_desc isakmp_ipsec_cert_req_desc = { "ISAKMP Certificate RequestPayload", isacr_fields, ISAKMP_CR_SIZE };
+
+/* ISAKMP Hash Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.11
+ * Variable length Hash Data follow.
+ * Previous next payload: ISAKMP_NEXT_HASH.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Hash Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_hash_desc = { "ISAKMP Hash Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP Signature Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.12
+ * Variable length Signature Data follow.
+ * Previous next payload: ISAKMP_NEXT_SIG.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Signature Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_signature_desc = { "ISAKMP Signature Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.13
+ * Variable length Nonce Data follow.
+ * Previous next payload: ISAKMP_NEXT_NONCE.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Nonce Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_nonce_desc = { "ISAKMP Nonce Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP Notification Payload
+ * layout from RFC 2408 "ISAKMP" section 3.14
+ * This is followed by a variable length SPI
+ * and then possibly by variable length Notification Data.
+ * Previous next payload: ISAKMP_NEXT_N
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Protocol-ID ! SPI Size ! Notify Message Type !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Security Parameter Index (SPI) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Notification Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isan_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
+ { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC, ESP, ... */
+ { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
+ { ft_enum, 16/BITS_PER_BYTE, "Notify Message Type", &notification_names },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_notification_desc = { "ISAKMP Notification Payload", isan_fields, sizeof(struct isakmp_notification) };
+
+/* ISAKMP Delete Payload
+ * layout from RFC 2408 "ISAKMP" section 3.15
+ * This is followed by a variable length SPI.
+ * Previous next payload: ISAKMP_NEXT_D
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Protocol-Id ! SPI Size ! # of SPIs !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Security Parameter Index(es) (SPI) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isad_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
+ { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC */
+ { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "number of SPIs", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_delete_desc = { "ISAKMP Delete Payload", isad_fields, sizeof(struct isakmp_delete) };
+
+/* ISAKMP Vendor ID Payload
+ * layout from RFC 2408 "ISAKMP" section 3.15
+ * This is followed by a variable length VID.
+ * Previous next payload: ISAKMP_NEXT_VID
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Vendor ID (VID) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* MODECFG */
+/*
+ * From draft-dukes-ike-mode-cfg
+3.2. Attribute Payload
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Type ! RESERVED ! Identifier !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Attributes ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+static field_desc isaattr_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "Attr Msg Type", &attr_msg_type_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "Identifier", NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_attr_desc = { "ISAKMP Mode Attribute", isaattr_fields, sizeof(struct isakmp_mode_attr) };
+
+/* ISAKMP NAT-Traversal NAT-D
+ * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 3.2
+ *
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! HASH of the address and port !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP NAT-Traversal NAT-OA
+ * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 4.2
+ *
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! RESERVED ! RESERVED !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! IPv4 (4 octets) or IPv6 address (16 octets) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isanat_oa_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+ { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
+ { ft_mbz, 24/BITS_PER_BYTE, NULL, NULL },
+ { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) };
+
+/* descriptor for each payload type
+ *
+ * There is a slight problem in that some payloads differ, depending
+ * on the mode. Since this is table only used for top-level payloads,
+ * Proposal and Transform payloads need not be handled.
+ * That leaves only Identification payloads as a problem.
+ * We make all these entries NULL
+ */
+struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = {
+ NULL, /* 0 ISAKMP_NEXT_NONE (No other payload following) */
+ &isakmp_sa_desc, /* 1 ISAKMP_NEXT_SA (Security Association) */
+ NULL, /* 2 ISAKMP_NEXT_P (Proposal) */
+ NULL, /* 3 ISAKMP_NEXT_T (Transform) */
+ &isakmp_keyex_desc, /* 4 ISAKMP_NEXT_KE (Key Exchange) */
+ NULL, /* 5 ISAKMP_NEXT_ID (Identification) */
+ &isakmp_ipsec_certificate_desc, /* 6 ISAKMP_NEXT_CERT (Certificate) */
+ &isakmp_ipsec_cert_req_desc, /* 7 ISAKMP_NEXT_CR (Certificate Request) */
+ &isakmp_hash_desc, /* 8 ISAKMP_NEXT_HASH (Hash) */
+ &isakmp_signature_desc, /* 9 ISAKMP_NEXT_SIG (Signature) */
+ &isakmp_nonce_desc, /* 10 ISAKMP_NEXT_NONCE (Nonce) */
+ &isakmp_notification_desc, /* 11 ISAKMP_NEXT_N (Notification) */
+ &isakmp_delete_desc, /* 12 ISAKMP_NEXT_D (Delete) */
+ &isakmp_vendor_id_desc, /* 13 ISAKMP_NEXT_VID (Vendor ID) */
+ &isakmp_attr_desc, /* 14 ISAKMP_NEXT_ATTR (Mode Config) */
+ NULL, /* 15 */
+ NULL, /* 16 */
+ NULL, /* 17 */
+ NULL, /* 18 */
+ NULL, /* 19 */
+ &isakmp_nat_d, /* 20=130 ISAKMP_NEXT_NATD (NAT-D) */
+ &isakmp_nat_oa, /* 20=131 ISAKMP_NEXT_NATOA (NAT-OA) */
+};
+
+void
+init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name)
+{
+ pbs->container = NULL;
+ pbs->desc = NULL;
+ pbs->name = name;
+ pbs->start = pbs->cur = start;
+ pbs->roof = start + len;
+ pbs->lenfld = NULL;
+ pbs->lenfld_desc = NULL;
+}
+
+#ifdef DEBUG
+
+/* print a host struct
+ *
+ * This code assumes that the network and host structure
+ * members have the same alignment and size! This requires
+ * that all padding be explicit.
+ */
+void
+DBG_print_struct(const char *label, const void *struct_ptr
+, struct_desc *sd, bool len_meaningful)
+{
+ bool immediate = FALSE;
+ const u_int8_t *inp = struct_ptr;
+ field_desc *fp;
+
+ DBG_log("%s%s:", label, sd->name);
+
+ for (fp = sd->fields; fp->field_type != ft_end; fp++)
+ {
+ int i = fp->size;
+ u_int32_t n = 0;
+
+ switch (fp->field_type)
+ {
+ case ft_mbz: /* must be zero */
+ inp += i;
+ break;
+ case ft_nat: /* natural number (may be 0) */
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ case ft_enum: /* value from an enumeration */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ case ft_set: /* bits representing set */
+ switch (i)
+ {
+ case 8/BITS_PER_BYTE:
+ n = *(const u_int8_t *)inp;
+ break;
+ case 16/BITS_PER_BYTE:
+ n = *(const u_int16_t *)inp;
+ break;
+ case 32/BITS_PER_BYTE:
+ n = *(const u_int32_t *)inp;
+ break;
+ default:
+ bad_case(i);
+ }
+ switch (fp->field_type)
+ {
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ if (!immediate && !len_meaningful)
+ break;
+ /* FALL THROUGH */
+ case ft_nat: /* natural number (may be 0) */
+ DBG_log(" %s: %lu", fp->name, (unsigned long)n);
+ break;
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ /* FALL THROUGH */
+ case ft_enum: /* value from an enumeration */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ DBG_log(" %s: %s", fp->name, enum_show(fp->desc, n));
+ break;
+ case ft_set: /* bits representing set */
+ DBG_log(" %s: %s", fp->name, bitnamesof(fp->desc, n));
+ break;
+ default:
+ bad_case(fp->field_type);
+ }
+ inp += i;
+ break;
+
+ case ft_raw: /* bytes to be left in network-order */
+ {
+ char m[50]; /* arbitrary limit on name width in log */
+
+ snprintf(m, sizeof(m), " %s:", fp->name);
+ DBG_dump(m, inp, i);
+ inp += i;
+ }
+ break;
+ default:
+ bad_case(fp->field_type);
+ }
+ }
+}
+
+static void
+DBG_prefix_print_struct(const pb_stream *pbs
+, const char *label, const void *struct_ptr
+, struct_desc *sd, bool len_meaningful)
+{
+ /* print out a title, with a prefix of asterisks to show
+ * the nesting level.
+ */
+ char space[40]; /* arbitrary limit on label+flock-of-* */
+ size_t len = strlen(label);
+
+ if (sizeof(space) <= len)
+ {
+ DBG_print_struct(label, struct_ptr, sd, len_meaningful);
+ }
+ else
+ {
+ const pb_stream *p = pbs;
+ char *pre = &space[sizeof(space) - (len + 1)];
+
+ strcpy(pre, label);
+
+ /* put at least one * out */
+ for (;;)
+ {
+ if (pre <= space)
+ break;
+ *--pre = '*';
+ if (p == NULL)
+ break;
+ p = p->container;
+ }
+ DBG_print_struct(pre, struct_ptr, sd, len_meaningful);
+ }
+}
+
+#endif
+
+/* "parse" a network struct into a host struct.
+ *
+ * This code assumes that the network and host structure
+ * members have the same alignment and size! This requires
+ * that all padding be explicit.
+ *
+ * If obj_pbs is supplied, a new pb_stream is created for the
+ * variable part of the structure (this depends on their
+ * being one length field in the structure). The cursor of this
+ * new PBS is set to after the parsed part of the struct.
+ *
+ * This routine returns TRUE iff it succeeds.
+ */
+
+bool
+in_struct(void *struct_ptr, struct_desc *sd
+, pb_stream *ins, pb_stream *obj_pbs)
+{
+ err_t ugh = NULL;
+ u_int8_t *cur = ins->cur;
+
+ if (ins->roof - cur < (ptrdiff_t)sd->size)
+ {
+ ugh = builddiag("not enough room in input packet for %s", sd->name);
+ }
+ else
+ {
+ u_int8_t *roof = cur + sd->size; /* may be changed by a length field */
+ u_int8_t *outp = struct_ptr;
+ bool immediate = FALSE;
+ field_desc *fp;
+
+ for (fp = sd->fields; ugh == NULL; fp++)
+ {
+ size_t i = fp->size;
+
+ passert(ins->roof - cur >= (ptrdiff_t)i);
+ passert(cur - ins->cur <= (ptrdiff_t)(sd->size - i));
+ passert(outp - (cur - ins->cur) == struct_ptr);
+
+#if 0
+ DBG(DBG_PARSING, DBG_log("%d %s"
+ , (int) (cur - ins->cur), fp->name == NULL? "" : fp->name));
+#endif
+ switch (fp->field_type)
+ {
+ case ft_mbz: /* must be zero */
+ for (; i != 0; i--)
+ {
+ if (*cur++ != 0)
+ {
+ ugh = builddiag("byte %d of %s must be zero, but is not"
+ , (int) (cur - ins->cur), sd->name);
+ break;
+ }
+ *outp++ = '\0'; /* probably redundant */
+ }
+ break;
+
+ case ft_nat: /* natural number (may be 0) */
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ case ft_enum: /* value from an enumeration */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ case ft_set: /* bits representing set */
+ {
+ u_int32_t n = 0;
+
+ for (; i != 0; i--)
+ n = (n << BITS_PER_BYTE) | *cur++;
+
+ switch (fp->field_type)
+ {
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ {
+ u_int32_t len = fp->field_type == ft_len? n
+ : immediate? sd->size : n + sd->size;
+
+ if (len < sd->size)
+ {
+ ugh = builddiag("%s of %s is smaller than minimum"
+ , fp->name, sd->name);
+ }
+ else if (pbs_left(ins) < len)
+ {
+ ugh = builddiag("%s of %s is larger than can fit"
+ , fp->name, sd->name);
+ }
+ else
+ {
+ roof = ins->cur + len;
+ }
+ break;
+ }
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ break;
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ /* FALL THROUGH */
+ case ft_enum: /* value from an enumeration */
+ if (enum_name(fp->desc, n) == NULL)
+ {
+ ugh = builddiag("%s of %s has an unknown value: %lu"
+ , fp->name, sd->name, (unsigned long)n);
+ }
+ /* FALL THROUGH */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ break;
+ case ft_set: /* bits representing set */
+ if (!testset(fp->desc, n))
+ {
+ ugh = builddiag("bitset %s of %s has unknown member(s): %s"
+ , fp->name, sd->name, bitnamesof(fp->desc, n));
+ }
+ break;
+ default:
+ break;
+ }
+ i = fp->size;
+ switch (i)
+ {
+ case 8/BITS_PER_BYTE:
+ *(u_int8_t *)outp = n;
+ break;
+ case 16/BITS_PER_BYTE:
+ *(u_int16_t *)outp = n;
+ break;
+ case 32/BITS_PER_BYTE:
+ *(u_int32_t *)outp = n;
+ break;
+ default:
+ bad_case(i);
+ }
+ outp += i;
+ break;
+ }
+
+ case ft_raw: /* bytes to be left in network-order */
+ for (; i != 0; i--)
+ {
+ *outp++ = *cur++;
+ }
+ break;
+
+ case ft_end: /* end of field list */
+ passert(cur == ins->cur + sd->size);
+ if (obj_pbs != NULL)
+ {
+ init_pbs(obj_pbs, ins->cur, roof - ins->cur, sd->name);
+ obj_pbs->container = ins;
+ obj_pbs->desc = sd;
+ obj_pbs->cur = cur;
+ }
+ ins->cur = roof;
+ DBG(DBG_PARSING
+ , DBG_prefix_print_struct(ins, "parse ", struct_ptr, sd, TRUE));
+ return TRUE;
+
+ default:
+ bad_case(fp->field_type);
+ }
+ }
+ }
+
+ /* some failure got us here: report it */
+ loglog(RC_LOG_SERIOUS, ugh);
+ return FALSE;
+}
+
+bool
+in_raw(void *bytes, size_t len, pb_stream *ins, const char *name)
+{
+ if (pbs_left(ins) < len)
+ {
+ loglog(RC_LOG_SERIOUS, "not enough bytes left to get %s from %s", name, ins->name);
+ return FALSE;
+ }
+ else
+ {
+ if (bytes == NULL)
+ {
+ DBG(DBG_PARSING
+ , DBG_log("skipping %u raw bytes of %s (%s)"
+ , (unsigned) len, ins->name, name);
+ DBG_dump(name, ins->cur, len));
+ }
+ else
+ {
+ memcpy(bytes, ins->cur, len);
+ DBG(DBG_PARSING
+ , DBG_log("parsing %u raw bytes of %s into %s"
+ , (unsigned) len, ins->name, name);
+ DBG_dump(name, bytes, len));
+ }
+ ins->cur += len;
+ return TRUE;
+ }
+}
+
+/* "emit" a host struct into a network packet.
+ *
+ * This code assumes that the network and host structure
+ * members have the same alignment and size! This requires
+ * that all padding be explicit.
+ *
+ * If obj_pbs is non-NULL, its pbs describes a new output stream set up
+ * to contain the object. The cursor will be left at the variable part.
+ * This new stream must subsequently be finalized by close_output_pbs().
+ *
+ * The value of any field of type ft_len is computed, not taken
+ * from the input struct. The length is actually filled in when
+ * the object's output stream is finalized. If obj_pbs is NULL,
+ * finalization is done by out_struct before it returns.
+ *
+ * This routine returns TRUE iff it succeeds.
+ */
+
+bool
+out_struct(const void *struct_ptr, struct_desc *sd
+, pb_stream *outs, pb_stream *obj_pbs)
+{
+ err_t ugh = NULL;
+ const u_int8_t *inp = struct_ptr;
+ u_int8_t *cur = outs->cur;
+
+ DBG(DBG_EMITTING
+ , DBG_prefix_print_struct(outs, "emit ", struct_ptr, sd, obj_pbs==NULL));
+
+ if (outs->roof - cur < (ptrdiff_t)sd->size)
+ {
+ ugh = builddiag("not enough room left in output packet to place %s"
+ , sd->name);
+ }
+ else
+ {
+ bool immediate = FALSE;
+ pb_stream obj;
+ field_desc *fp;
+
+ obj.lenfld = NULL; /* until a length field is discovered */
+ obj.lenfld_desc = NULL;
+
+ for (fp = sd->fields; ugh == NULL; fp++)
+ {
+ size_t i = fp->size;
+
+ passert(outs->roof - cur >= (ptrdiff_t)i);
+ passert(cur - outs->cur <= (ptrdiff_t)(sd->size - i));
+ passert(inp - (cur - outs->cur) == struct_ptr);
+
+#if 0
+ DBG(DBG_EMITTING, DBG_log("%d %s"
+ , (int) (cur - outs->cur), fp->name == NULL? "" : fp->name);
+#endif
+ switch (fp->field_type)
+ {
+ case ft_mbz: /* must be zero */
+ inp += i;
+ for (; i != 0; i--)
+ *cur++ = '\0';
+ break;
+ case ft_nat: /* natural number (may be 0) */
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ case ft_enum: /* value from an enumeration */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ case ft_set: /* bits representing set */
+ {
+ u_int32_t n = 0;
+
+ switch (i)
+ {
+ case 8/BITS_PER_BYTE:
+ n = *(const u_int8_t *)inp;
+ break;
+ case 16/BITS_PER_BYTE:
+ n = *(const u_int16_t *)inp;
+ break;
+ case 32/BITS_PER_BYTE:
+ n = *(const u_int32_t *)inp;
+ break;
+ default:
+ bad_case(i);
+ }
+
+ switch (fp->field_type)
+ {
+ case ft_len: /* length of this struct and any following crud */
+ case ft_lv: /* length/value field of attribute */
+ if (immediate)
+ break; /* not a length */
+ /* We can't check the length because it will likely
+ * be filled in after variable part is supplied.
+ * We do record where this is so that it can be
+ * filled in by a subsequent close_output_pbs().
+ */
+ passert(obj.lenfld == NULL); /* only one ft_len allowed */
+ obj.lenfld = cur;
+ obj.lenfld_desc = fp;
+ break;
+ case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ break;
+ case ft_af_enum: /* Attribute Format + value from an enumeration */
+ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ immediate = TRUE;
+ /* FALL THROUGH */
+ case ft_enum: /* value from an enumeration */
+ if (enum_name(fp->desc, n) == NULL)
+ {
+ ugh = builddiag("%s of %s has an unknown value: %lu"
+ , fp->name, sd->name, (unsigned long)n);
+ }
+ /* FALL THROUGH */
+ case ft_loose_enum: /* value from an enumeration with only some names known */
+ break;
+ case ft_set: /* bits representing set */
+ if (!testset(fp->desc, n))
+ {
+ ugh = builddiag("bitset %s of %s has unknown member(s): %s"
+ , fp->name, sd->name, bitnamesof(fp->desc, n));
+ }
+ break;
+ default:
+ break;
+ }
+
+ while (i-- != 0)
+ {
+ cur[i] = (u_int8_t)n;
+ n >>= BITS_PER_BYTE;
+ }
+ inp += fp->size;
+ cur += fp->size;
+ break;
+ }
+ case ft_raw: /* bytes to be left in network-order */
+ for (; i != 0; i--)
+ *cur++ = *inp++;
+ break;
+ case ft_end: /* end of field list */
+ passert(cur == outs->cur + sd->size);
+
+ obj.container = outs;
+ obj.desc = sd;
+ obj.name = sd->name;
+ obj.start = outs->cur;
+ obj.cur = cur;
+ obj.roof = outs->roof; /* limit of possible */
+ /* obj.lenfld and obj.lenfld_desc already set */
+
+ if (obj_pbs == NULL)
+ {
+ close_output_pbs(&obj); /* fill in length field, if any */
+ }
+ else
+ {
+ /* We set outs->cur to outs->roof so that
+ * any attempt to output something into outs
+ * before obj is closed will trigger an error.
+ */
+ outs->cur = outs->roof;
+
+ *obj_pbs = obj;
+ }
+ return TRUE;
+
+ default:
+ bad_case(fp->field_type);
+ }
+ }
+ }
+
+ /* some failure got us here: report it */
+ loglog(RC_LOG_SERIOUS, ugh); /* ??? serious, but errno not relevant */
+ return FALSE;
+}
+
+bool
+out_generic(u_int8_t np, struct_desc *sd
+, pb_stream *outs, pb_stream *obj_pbs)
+{
+ struct isakmp_generic gen;
+
+ passert(sd->fields == isakmp_generic_desc.fields);
+ gen.isag_np = np;
+ return out_struct(&gen, sd, outs, obj_pbs);
+}
+
+bool
+out_generic_raw(u_int8_t np, struct_desc *sd
+, pb_stream *outs, const void *bytes, size_t len, const char *name)
+{
+ pb_stream pbs;
+
+ if (!out_generic(np, sd, outs, &pbs)
+ || !out_raw(bytes, len, &pbs, name))
+ return FALSE;
+ close_output_pbs(&pbs);
+ return TRUE;
+}
+
+bool
+out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name)
+{
+ if (pbs_left(outs) < len)
+ {
+ loglog(RC_LOG_SERIOUS, "not enough room left to place %lu bytes of %s in %s"
+ , (unsigned long) len, name, outs->name);
+ return FALSE;
+ }
+ else
+ {
+ DBG(DBG_EMITTING
+ , DBG_log("emitting %u raw bytes of %s into %s"
+ , (unsigned) len, name, outs->name);
+ DBG_dump(name, bytes, len));
+ memcpy(outs->cur, bytes, len);
+ outs->cur += len;
+ return TRUE;
+ }
+}
+
+bool
+out_zero(size_t len, pb_stream *outs, const char *name)
+{
+ if (pbs_left(outs) < len)
+ {
+ loglog(RC_LOG_SERIOUS, "not enough room left to place %s in %s", name, outs->name);
+ return FALSE;
+ }
+ else
+ {
+ DBG(DBG_EMITTING, DBG_log("emitting %u zero bytes of %s into %s"
+ , (unsigned) len, name, outs->name));
+ memset(outs->cur, 0x00, len);
+ outs->cur += len;
+ return TRUE;
+ }
+}
+
+/* Record current length.
+ * Note: currently, this may be repeated any number of times;
+ * the last one wins.
+ */
+void
+close_output_pbs(pb_stream *pbs)
+{
+ if (pbs->lenfld != NULL)
+ {
+ u_int32_t len = pbs_offset(pbs);
+ int i = pbs->lenfld_desc->size;
+
+ if (pbs->lenfld_desc->field_type == ft_lv)
+ len -= sizeof(struct isakmp_attribute);
+ DBG(DBG_EMITTING, DBG_log("emitting length of %s: %lu"
+ , pbs->name, (unsigned long) len));
+ while (i-- != 0)
+ {
+ pbs->lenfld[i] = (u_int8_t)len;
+ len >>= BITS_PER_BYTE;
+ }
+ }
+ if (pbs->container != NULL)
+ pbs->container->cur = pbs->cur; /* pass space utilization up */
+}
diff --git a/programs/pluto/packet.h b/programs/pluto/packet.h
new file mode 100644
index 000000000..676a5e6cd
--- /dev/null
+++ b/programs/pluto/packet.h
@@ -0,0 +1,655 @@
+/* parsing packets: formats and tools
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: packet.h,v 1.5 2005/01/06 22:10:15 as Exp $
+ */
+
+#ifndef _PACKET_H
+#define _PACKET_H
+
+/* a struct_desc describes a structure for the struct I/O routines.
+ * This requires arrays of field_desc values to describe struct fields.
+ */
+
+typedef const struct struct_desc {
+ const char *name;
+ const struct field_desc *fields;
+ size_t size;
+} struct_desc;
+
+/* Note: if an ft_af_enum field has the ISAKMP_ATTR_AF_TV bit set,
+ * the subsequent ft_lv field will be interpreted as an immediate value.
+ * This matches how attributes are encoded.
+ * See RFC 2408 "ISAKMP" 3.3
+ */
+
+enum field_type {
+ ft_mbz, /* must be zero */
+ ft_nat, /* natural number (may be 0) */
+ ft_len, /* length of this struct and any following crud */
+ ft_lv, /* length/value field of attribute */
+ ft_enum, /* value from an enumeration */
+ ft_loose_enum, /* value from an enumeration with only some names known */
+ ft_af_loose_enum, /* Attribute Format + enumeration, some names known */
+ ft_af_enum, /* Attribute Format + value from an enumeration */
+ ft_set, /* bits representing set */
+ ft_raw, /* bytes to be left in network-order */
+ ft_end, /* end of field list */
+};
+
+typedef const struct field_desc {
+ enum field_type field_type;
+ int size; /* size, in bytes, of field */
+ const char *name;
+ const void *desc; /* enum_names for enum or char *[] for bits */
+} field_desc;
+
+/* The formatting of input and output of packets is done
+ * through packet_byte_stream objects.
+ * These describe a stream of bytes in memory.
+ * Several routines are provided to manipulate these objects
+ * Actual packet transfer is done elsewhere.
+ */
+typedef struct packet_byte_stream {
+ struct packet_byte_stream *container; /* PBS of which we are part */
+ struct_desc *desc;
+ const char *name; /* what does this PBS represent? */
+ u_int8_t
+ *start,
+ *cur, /* current position in stream */
+ *roof; /* byte after last in PBS (actually just a limit on output) */
+ /* For an output PBS, the length field will be filled in later so
+ * we need to record its particulars. Note: it may not be aligned.
+ */
+ u_int8_t *lenfld;
+ field_desc *lenfld_desc;
+} pb_stream;
+
+/* For an input PBS, pbs_offset is amount of stream processed.
+ * For an output PBS, pbs_offset is current size of stream.
+ * For an input PBS, pbs_room is size of stream.
+ * For an output PBS, pbs_room is maximum size allowed.
+ */
+#define pbs_offset(pbs) ((size_t)((pbs)->cur - (pbs)->start))
+#define pbs_room(pbs) ((size_t)((pbs)->roof - (pbs)->start))
+#define pbs_left(pbs) ((size_t)((pbs)->roof - (pbs)->cur))
+
+extern void init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name);
+
+extern bool in_struct(void *struct_ptr, struct_desc *sd,
+ pb_stream *ins, pb_stream *obj_pbs);
+extern bool in_raw(void *bytes, size_t len, pb_stream *ins, const char *name);
+
+extern bool out_struct(const void *struct_ptr, struct_desc *sd,
+ pb_stream *outs, pb_stream *obj_pbs);
+extern bool out_generic(u_int8_t np, struct_desc *sd,
+ pb_stream *outs, pb_stream *obj_pbs);
+extern bool out_generic_raw(u_int8_t np, struct_desc *sd,
+ pb_stream *outs, const void *bytes, size_t len, const char *name);
+#define out_generic_chunk(np, sd, outs, ch, name) \
+ out_generic_raw(np, sd, outs, (ch).ptr, (ch).len, name)
+extern bool out_zero(size_t len, pb_stream *outs, const char *name);
+extern bool out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name);
+#define out_chunk(ch, outs, name) out_raw((ch).ptr, (ch).len, (outs), (name))
+extern void close_output_pbs(pb_stream *pbs);
+
+#ifdef DEBUG
+extern void DBG_print_struct(const char *label, const void *struct_ptr,
+ struct_desc *sd, bool len_meaningful);
+#endif
+
+/* ISAKMP Header: for all messages
+ * layout from RFC 2408 "ISAKMP" section 3.1
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Initiator !
+ * ! Cookie !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Responder !
+ * ! Cookie !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Message ID !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * Although the drafts are a little unclear, there are a few
+ * places that specify that messages should be padded with 0x00
+ * octets (bytes) to make the length a multiple of something.
+ *
+ * RFC 2408 "ISAKMP" 3.6 specifies that all messages will be
+ * padded to be a multiple of 4 octets in length.
+ * ??? This looks vestigial, and we ignore this requirement.
+ *
+ * RFC 2409 "IKE" Appedix B specifies:
+ * Each message should be padded up to the nearest block size
+ * using bytes containing 0x00.
+ * ??? This does not appear to be limited to encrypted messages,
+ * but it surely must be: the block size is meant to be the encryption
+ * block size, and that is meaningless for a non-encrypted message.
+ *
+ * RFC 2409 "IKE" 5.3 specifies:
+ * Encrypted payloads are padded up to the nearest block size.
+ * All padding bytes, except for the last one, contain 0x00. The
+ * last byte of the padding contains the number of the padding
+ * bytes used, excluding the last one. Note that this means there
+ * will always be padding.
+ * ??? This is nuts since payloads are not padded, messages are.
+ * It also contradicts Appendix B. So we ignore it.
+ *
+ * Summary: we pad encrypted output messages with 0x00 to bring them
+ * up to a multiple of the encryption block size. On input, we require
+ * that any encrypted portion of a message be a multiple of the encryption
+ * block size. After any decryption, we ignore padding (any bytes after
+ * the first payload that specifies a next payload of none; we don't
+ * require them to be zero).
+ */
+
+struct isakmp_hdr
+{
+ u_int8_t isa_icookie[COOKIE_SIZE];
+ u_int8_t isa_rcookie[COOKIE_SIZE];
+ u_int8_t isa_np; /* Next payload */
+ u_int8_t isa_version; /* high-order 4 bits: Major; low order 4: Minor */
+#define ISA_MAJ_SHIFT 4
+#define ISA_MIN_MASK (~((~0u) << ISA_MAJ_SHIFT))
+ u_int8_t isa_xchg; /* Exchange type */
+ u_int8_t isa_flags;
+ u_int32_t isa_msgid; /* Message ID (RAW) */
+ u_int32_t isa_length; /* Length of message */
+};
+
+extern struct_desc isakmp_hdr_desc;
+
+/* Generic portion of all ISAKMP payloads.
+ * layout from RFC 2408 "ISAKMP" section 3.2
+ * This describes the first 32-bit chunk of all payloads.
+ * The previous next payload depends on the actual payload type.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_generic
+{
+ u_int8_t isag_np;
+ u_int8_t isag_reserved;
+ u_int16_t isag_length;
+};
+
+extern struct_desc isakmp_generic_desc;
+
+/* ISAKMP Data Attribute (generic representation within payloads)
+ * layout from RFC 2408 "ISAKMP" section 3.3
+ * This is not a payload type.
+ * In TLV format, this is followed by a value field.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * !A! Attribute Type ! AF=0 Attribute Length !
+ * !F! ! AF=1 Attribute Value !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * . AF=0 Attribute Value .
+ * . AF=1 Not Transmitted .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_attribute
+{
+ /* The high order bit of isaat_af_type is the Attribute Format
+ * If it is off, the format is TLV: lv is the length of the following
+ * attribute value.
+ * If it is on, the format is TV: lv is the value of the attribute.
+ * ISAKMP_ATTR_AF_MASK is the mask in host form.
+ *
+ * The low order 15 bits of isaat_af_type is the Attribute Type.
+ * ISAKMP_ATTR_RTYPE_MASK is the mask in host form.
+ */
+ u_int16_t isaat_af_type; /* high order bit: AF; lower 15: rtype */
+ u_int16_t isaat_lv; /* Length or value */
+};
+
+#define ISAKMP_ATTR_AF_MASK 0x8000
+#define ISAKMP_ATTR_AF_TV ISAKMP_ATTR_AF_MASK /* value in lv */
+#define ISAKMP_ATTR_AF_TLV 0 /* length in lv; value follows */
+
+#define ISAKMP_ATTR_RTYPE_MASK 0x7FFF
+
+extern struct_desc
+ isakmp_oakley_attribute_desc,
+ isakmp_ipsec_attribute_desc;
+
+/* ISAKMP Security Association Payload
+ * layout from RFC 2408 "ISAKMP" section 3.4
+ * A variable length Situation follows.
+ * Previous next payload: ISAKMP_NEXT_SA
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Situation ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_sa
+{
+ u_int8_t isasa_np; /* Next payload */
+ u_int8_t isasa_reserved;
+ u_int16_t isasa_length; /* Payload length */
+ u_int32_t isasa_doi; /* DOI */
+};
+
+extern struct_desc isakmp_sa_desc;
+
+extern struct_desc ipsec_sit_desc;
+
+/* ISAKMP Proposal Payload
+ * layout from RFC 2408 "ISAKMP" section 3.5
+ * A variable length SPI follows.
+ * Previous next payload: ISAKMP_NEXT_P
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms!
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! SPI (variable) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_proposal
+{
+ u_int8_t isap_np;
+ u_int8_t isap_reserved;
+ u_int16_t isap_length;
+ u_int8_t isap_proposal;
+ u_int8_t isap_protoid;
+ u_int8_t isap_spisize;
+ u_int8_t isap_notrans; /* Number of transforms */
+};
+
+extern struct_desc isakmp_proposal_desc;
+
+/* ISAKMP Transform Payload
+ * layout from RFC 2408 "ISAKMP" section 3.6
+ * Variable length SA Attributes follow.
+ * Previous next payload: ISAKMP_NEXT_T
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Transform # ! Transform-Id ! RESERVED2 !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ SA Attributes ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_transform
+{
+ u_int8_t isat_np;
+ u_int8_t isat_reserved;
+ u_int16_t isat_length;
+ u_int8_t isat_transnum; /* Number of the transform */
+ u_int8_t isat_transid;
+ u_int16_t isat_reserved2;
+};
+
+extern struct_desc
+ isakmp_isakmp_transform_desc,
+ isakmp_ah_transform_desc,
+ isakmp_esp_transform_desc,
+ isakmp_ipcomp_transform_desc;
+
+/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.7
+ * Variable Key Exchange Data follow the generic fields.
+ * Previous next payload: ISAKMP_NEXT_KE
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Key Exchange Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_keyex_desc;
+
+/* ISAKMP Identification Payload
+ * layout from RFC 2408 "ISAKMP" section 3.8
+ * See "struct identity" declared later.
+ * Variable length Identification Data follow.
+ * Previous next payload: ISAKMP_NEXT_ID
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! DOI Specific ID Data !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Identification Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_id
+{
+ u_int8_t isaid_np;
+ u_int8_t isaid_reserved;
+ u_int16_t isaid_length;
+ u_int8_t isaid_idtype;
+ u_int8_t isaid_doi_specific_a;
+ u_int16_t isaid_doi_specific_b;
+};
+
+extern struct_desc isakmp_identification_desc;
+
+/* IPSEC Identification Payload Content
+ * layout from RFC 2407 "IPsec DOI" section 4.6.2
+ * See struct isakmp_id declared earlier.
+ * Note: Hashing skips the ISAKMP generic payload header
+ * Variable length Identification Data follow.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! ID Type ! Protocol ID ! Port !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~ Identification Data ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_ipsec_id
+{
+ u_int8_t isaiid_np;
+ u_int8_t isaiid_reserved;
+ u_int16_t isaiid_length;
+ u_int8_t isaiid_idtype;
+ u_int8_t isaiid_protoid;
+ u_int16_t isaiid_port;
+};
+
+extern struct_desc isakmp_ipsec_identification_desc;
+
+/* ISAKMP Certificate Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.9
+ * Variable length Certificate Data follow the generic fields.
+ * Previous next payload: ISAKMP_NEXT_CERT.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Cert Encoding ! !
+ * +-+-+-+-+-+-+-+-+ !
+ * ~ Certificate Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_cert
+{
+ u_int8_t isacert_np;
+ u_int8_t isacert_reserved;
+ u_int16_t isacert_length;
+ u_int8_t isacert_type;
+};
+
+/* NOTE: this packet type has a fixed portion that is not a
+ * multiple of 4 octets. This means that sizeof(struct isakmp_cert)
+ * yields the wrong value for the length.
+ */
+#define ISAKMP_CERT_SIZE 5
+
+extern struct_desc isakmp_ipsec_certificate_desc;
+
+/* ISAKMP Certificate Request Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.10
+ * Variable length Certificate Types and Certificate Authorities follow.
+ * Previous next payload: ISAKMP_NEXT_CR.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Cert. Type ! !
+ * +-+-+-+-+-+-+-+-+ !
+ * ~ Certificate Authority ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_cr
+{
+ u_int8_t isacr_np;
+ u_int8_t isacr_reserved;
+ u_int16_t isacr_length;
+ u_int8_t isacr_type;
+};
+
+/* NOTE: this packet type has a fixed portion that is not a
+ * multiple of 4 octets. This means that sizeof(struct isakmp_cr)
+ * yields the wrong value for the length.
+ */
+#define ISAKMP_CR_SIZE 5
+
+extern struct_desc isakmp_ipsec_cert_req_desc;
+
+/* ISAKMP Hash Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.11
+ * Variable length Hash Data follow.
+ * Previous next payload: ISAKMP_NEXT_HASH.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Hash Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_hash_desc;
+
+/* ISAKMP Signature Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.12
+ * Variable length Signature Data follow.
+ * Previous next payload: ISAKMP_NEXT_SIG.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Signature Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_signature_desc;
+
+/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones.
+ * layout from RFC 2408 "ISAKMP" section 3.13
+ * Variable length Nonce Data follow.
+ * Previous next payload: ISAKMP_NEXT_NONCE.
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Nonce Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_nonce_desc;
+
+/* ISAKMP Notification Payload
+ * layout from RFC 2408 "ISAKMP" section 3.14
+ * This is followed by a variable length SPI
+ * and then possibly by variable length Notification Data.
+ * Previous next payload: ISAKMP_NEXT_N
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Protocol-ID ! SPI Size ! Notify Message Type !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Security Parameter Index (SPI) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Notification Data ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_notification
+{
+ u_int8_t isan_np;
+ u_int8_t isan_reserved;
+ u_int16_t isan_length;
+ u_int32_t isan_doi;
+ u_int8_t isan_protoid;
+ u_int8_t isan_spisize;
+ u_int16_t isan_type;
+};
+
+extern struct_desc isakmp_notification_desc;
+
+/* ISAKMP Delete Payload
+ * layout from RFC 2408 "ISAKMP" section 3.15
+ * This is followed by a variable length SPI.
+ * Previous next payload: ISAKMP_NEXT_D
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Domain of Interpretation (DOI) !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Protocol-Id ! SPI Size ! # of SPIs !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Security Parameter Index(es) (SPI) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct isakmp_delete
+{
+ u_int8_t isad_np;
+ u_int8_t isad_reserved;
+ u_int16_t isad_length;
+ u_int32_t isad_doi;
+ u_int8_t isad_protoid;
+ u_int8_t isad_spisize;
+ u_int16_t isad_nospi;
+};
+
+extern struct_desc isakmp_delete_desc;
+
+/* From draft-dukes-ike-mode-cfg
+3.2. Attribute Payload
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Type ! RESERVED ! Identifier !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ! !
+ ~ Attributes ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+struct isakmp_mode_attr
+{
+ u_int8_t isama_np;
+ u_int8_t isama_reserved;
+ u_int16_t isama_length;
+ u_int8_t isama_type;
+ u_int8_t isama_reserved2;
+ u_int16_t isama_identifier;
+};
+
+extern struct_desc isakmp_attr_desc;
+extern struct_desc isakmp_modecfg_attribute_desc;
+
+/* ISAKMP Vendor ID Payload
+ * layout from RFC 2408 "ISAKMP" section 3.15
+ * This is followed by a variable length VID.
+ * Previous next payload: ISAKMP_NEXT_VID
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload ! RESERVED ! Payload Length !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! !
+ * ~ Vendor ID (VID) ~
+ * ! !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+extern struct_desc isakmp_vendor_id_desc;
+
+struct isakmp_nat_oa
+{
+ u_int8_t isanoa_np;
+ u_int8_t isanoa_reserved_1;
+ u_int16_t isanoa_length;
+ u_int8_t isanoa_idtype;
+ u_int8_t isanoa_reserved_2;
+ u_int16_t isanoa_reserved_3;
+};
+
+extern struct_desc isakmp_nat_d;
+extern struct_desc isakmp_nat_oa;
+
+/* union of all payloads */
+
+union payload {
+ struct isakmp_generic generic;
+ struct isakmp_sa sa;
+ struct isakmp_proposal proposal;
+ struct isakmp_transform transform;
+ struct isakmp_id id; /* Main Mode */
+ struct isakmp_cert cert;
+ struct isakmp_cr cr;
+ struct isakmp_ipsec_id ipsec_id; /* Quick Mode */
+ struct isakmp_notification notification;
+ struct isakmp_delete delete;
+ struct isakmp_nat_oa nat_oa;
+ struct isakmp_mode_attr attribute;
+};
+
+/* descriptor for each payload type
+ *
+ * There is a slight problem in that some payloads differ, depending
+ * on the mode. Since this is table only used for top-level payloads,
+ * Proposal and Transform payloads need not be handled.
+ * That leaves only Identification payloads as a problem.
+ * We make all these entries NULL
+ */
+extern struct_desc *const payload_descs[ISAKMP_NEXT_ROOF];
+
+#endif /* _PACKET_H */
diff --git a/programs/pluto/pem.c b/programs/pluto/pem.c
new file mode 100644
index 000000000..e8d381741
--- /dev/null
+++ b/programs/pluto/pem.c
@@ -0,0 +1,463 @@
+/* Loading of PEM encoded files with optional encryption
+ * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: pem.c,v 1.4 2005/08/17 16:31:24 as Exp $
+ */
+
+/* decrypt a PEM encoded data block using DES-EDE3-CBC
+ * see RFC 1423 PEM: Algorithms, Modes and Identifiers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in <des.h> */
+#include <crypto/des.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "md5.h"
+#include "whack.h"
+#include "pem.h"
+
+/*
+ * check the presence of a pattern in a character string
+ */
+static bool
+present(const char* pattern, chunk_t* ch)
+{
+ u_int pattern_len = strlen(pattern);
+
+ if (ch->len >= pattern_len && strncmp(ch->ptr, pattern, pattern_len) == 0)
+ {
+ ch->ptr += pattern_len;
+ ch->len -= pattern_len;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * compare string with chunk
+ */
+static bool
+match(const char *pattern, const chunk_t *ch)
+{
+ return ch->len == strlen(pattern) &&
+ strncmp(pattern, ch->ptr, ch->len) == 0;
+}
+
+/*
+ * find a boundary of the form -----tag name-----
+ */
+static bool
+find_boundary(const char* tag, chunk_t *line)
+{
+ chunk_t name = empty_chunk;
+
+ if (!present("-----", line))
+ return FALSE;
+ if (!present(tag, line))
+ return FALSE;
+ if (*line->ptr != ' ')
+ return FALSE;
+ line->ptr++; line->len--;
+
+ /* extract name */
+ name.ptr = line->ptr;
+ while (line->len > 0)
+ {
+ if (present("-----", line))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" -----%s %.*s-----",
+ tag, (int)name.len, name.ptr);
+ )
+ return TRUE;
+ }
+ line->ptr++; line->len--; name.len++;
+ }
+ return FALSE;
+}
+
+/*
+ * eat whitespace
+ */
+static void
+eat_whitespace(chunk_t *src)
+{
+ while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t'))
+ {
+ src->ptr++; src->len--;
+ }
+}
+
+/*
+ * extracts a token ending with a given termination symbol
+ */
+static bool
+extract_token(chunk_t *token, char termination, chunk_t *src)
+{
+ u_char *eot = memchr(src->ptr, termination, src->len);
+
+ /* initialize empty token */
+ *token = empty_chunk;
+
+ if (eot == NULL) /* termination symbol not found */
+ return FALSE;
+
+ /* extract token */
+ token->ptr = src->ptr;
+ token->len = (u_int)(eot - src->ptr);
+
+ /* advance src pointer after termination symbol */
+ src->ptr = eot + 1;
+ src->len -= (token->len + 1);
+
+ return TRUE;
+}
+
+/*
+ * extracts a name: value pair from the PEM header
+ */
+static bool
+extract_parameter(chunk_t *name, chunk_t *value, chunk_t *line)
+{
+ DBG(DBG_PARSING,
+ DBG_log(" %.*s", (int)line->len, line->ptr);
+ )
+
+ /* extract name */
+ if (!extract_token(name,':', line))
+ return FALSE;
+
+ eat_whitespace(line);
+
+ /* extract value */
+ *value = *line;
+ return TRUE;
+}
+
+/*
+ * fetches a new line terminated by \n or \r\n
+ */
+static bool
+fetchline(chunk_t *src, chunk_t *line)
+{
+ if (src->len == 0) /* end of src reached */
+ return FALSE;
+
+ if (extract_token(line, '\n', src))
+ {
+ if (line->len > 0 && *(line->ptr + line->len -1) == '\r')
+ line->len--; /* remove optional \r */
+ }
+ else /*last line ends without newline */
+ {
+ *line = *src;
+ src->ptr += src->len;
+ src->len = 0;
+ }
+ return TRUE;
+}
+
+/*
+ * decrypts a DES-EDE-CBC encrypted data block
+ */
+static bool
+pem_decrypt_3des(chunk_t *blob, chunk_t *iv, const char *passphrase)
+{
+ MD5_CTX context;
+ u_char digest[MD5_DIGEST_SIZE];
+ u_char des_iv[DES_CBC_BLOCK_SIZE];
+ u_char key[24];
+ des_cblock *deskey = (des_cblock *)key;
+ des_key_schedule ks[3];
+ u_char padding, *last_padding_pos, *first_padding_pos;
+
+ /* Convert passphrase to 3des key */
+ MD5Init(&context);
+ MD5Update(&context, passphrase, strlen(passphrase));
+ MD5Update(&context, iv->ptr, iv->len);
+ MD5Final(digest, &context);
+
+ memcpy(key, digest, MD5_DIGEST_SIZE);
+
+ MD5Init(&context);
+ MD5Update(&context, digest, MD5_DIGEST_SIZE);
+ MD5Update(&context, passphrase, strlen(passphrase));
+ MD5Update(&context, iv->ptr, iv->len);
+ MD5Final(digest, &context);
+
+ memcpy(key + MD5_DIGEST_SIZE, digest, 24 - MD5_DIGEST_SIZE);
+
+ (void) des_set_key(&deskey[0], ks[0]);
+ (void) des_set_key(&deskey[1], ks[1]);
+ (void) des_set_key(&deskey[2], ks[2]);
+
+ /* decrypt data block */
+ memcpy(des_iv, iv->ptr, DES_CBC_BLOCK_SIZE);
+ des_ede3_cbc_encrypt((des_cblock *)blob->ptr, (des_cblock *)blob->ptr,
+ blob->len, ks[0], ks[1], ks[2], (des_cblock *)des_iv, FALSE);
+
+ /* determine amount of padding */
+ last_padding_pos = blob->ptr + blob->len - 1;
+ padding = *last_padding_pos;
+ first_padding_pos = (padding > blob->len)?
+ blob->ptr : last_padding_pos - padding;
+
+ /* check the padding pattern */
+ while (--last_padding_pos > first_padding_pos)
+ {
+ if (*last_padding_pos != padding)
+ return FALSE;
+ }
+
+ /* remove padding */
+ blob->len -= padding;
+ return TRUE;
+}
+
+/*
+ * optionally prompts for a passphrase before decryption
+ * currently we support DES-EDE3-CBC, only
+ */
+static err_t
+pem_decrypt(chunk_t *blob, chunk_t *iv, prompt_pass_t *pass, const char* label)
+{
+ DBG(DBG_CRYPT,
+ DBG_log(" decrypting file using 'DES-EDE3-CBC'");
+ )
+ if (iv->len != DES_CBC_BLOCK_SIZE)
+ return "size of DES-EDE3-CBC IV is not 8 bytes";
+
+ if (pass == NULL)
+ return "no passphrase available";
+
+ /* do we prompt for the passphrase? */
+ if (pass->prompt && pass->fd != NULL_FD)
+ {
+ int i;
+ chunk_t blob_copy;
+ err_t ugh = "invalid passphrase, too many trials";
+
+ whack_log(RC_ENTERSECRET, "need passphrase for '%s'", label);
+
+ for (i = 0; i < MAX_PROMPT_PASS_TRIALS; i++)
+ {
+ int n;
+
+ if (i > 0)
+ whack_log(RC_ENTERSECRET, "invalid passphrase, please try again");
+
+ n = read(pass->fd, pass->secret, PROMPT_PASS_LEN);
+
+ if (n == -1)
+ {
+ err_t ugh = "read(whackfd) failed";
+
+ whack_log(RC_LOG_SERIOUS,ugh);
+ return ugh;
+ }
+
+ pass->secret[n-1] = '\0';
+
+ if (strlen(pass->secret) == 0)
+ {
+ err_t ugh = "no passphrase entered, aborted";
+
+ whack_log(RC_LOG_SERIOUS, ugh);
+ return ugh;
+ }
+
+ clonetochunk(blob_copy, blob->ptr, blob->len, "blob copy");
+
+ if (pem_decrypt_3des(blob, iv, pass->secret))
+ {
+ whack_log(RC_SUCCESS, "valid passphrase");
+ pfree(blob_copy.ptr);
+ return NULL;
+ }
+
+ /* blob is useless after wrong decryption, restore the original */
+ pfree(blob->ptr);
+ *blob = blob_copy;
+ }
+ whack_log(RC_LOG_SERIOUS, ugh);
+ return ugh;
+ }
+ else
+ {
+ if (pem_decrypt_3des(blob, iv, pass->secret))
+ return NULL;
+ else
+ return "invalid passphrase";
+ }
+}
+
+/* Converts a PEM encoded file into its binary form
+ *
+ * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
+ * RFC 934 Message Encapsulation, January 1985
+ */
+err_t
+pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label, bool *pgp)
+{
+ typedef enum {
+ PEM_PRE = 0,
+ PEM_MSG = 1,
+ PEM_HEADER = 2,
+ PEM_BODY = 3,
+ PEM_POST = 4,
+ PEM_ABORT = 5
+ } state_t;
+
+ bool encrypted = FALSE;
+
+ state_t state = PEM_PRE;
+
+ chunk_t src = *blob;
+ chunk_t dst = *blob;
+ chunk_t line = empty_chunk;
+ chunk_t iv = empty_chunk;
+
+ u_char iv_buf[MAX_DIGEST_LEN];
+
+ /* zero size of converted blob */
+ dst.len = 0;
+
+ /* zero size of IV */
+ iv.ptr = iv_buf;
+ iv.len = 0;
+
+ while (fetchline(&src, &line))
+ {
+ if (state == PEM_PRE)
+ {
+ if (find_boundary("BEGIN", &line))
+ {
+ *pgp = FALSE;
+ state = PEM_MSG;
+ }
+ continue;
+ }
+ else
+ {
+ if (find_boundary("END", &line))
+ {
+ state = PEM_POST;
+ break;
+ }
+ if (state == PEM_MSG)
+ {
+ state = (memchr(line.ptr, ':', line.len) == NULL)?
+ PEM_BODY : PEM_HEADER;
+ }
+ if (state == PEM_HEADER)
+ {
+ chunk_t name = empty_chunk;
+ chunk_t value = empty_chunk;
+
+ /* an empty line separates HEADER and BODY */
+ if (line.len == 0)
+ {
+ state = PEM_BODY;
+ continue;
+ }
+
+ /* we are looking for a name: value pair */
+ if (!extract_parameter(&name, &value, &line))
+ continue;
+
+ if (match("Proc-Type", &name) && *value.ptr == '4')
+ encrypted = TRUE;
+ else if (match("DEK-Info", &name))
+ {
+ const char *ugh = NULL;
+ size_t len = 0;
+ chunk_t dek;
+
+ if (!extract_token(&dek, ',', &value))
+ dek = value;
+
+ /* we support DES-EDE3-CBC encrypted files, only */
+ if (!match("DES-EDE3-CBC", &dek))
+ return "we support DES-EDE3-CBC encrypted files, only";
+
+ eat_whitespace(&value);
+ ugh = ttodata(value.ptr, value.len, 16,
+ iv.ptr, MAX_DIGEST_LEN, &len);
+ if (ugh)
+ return "error in IV";
+
+ iv.len = len;
+ }
+ }
+ else /* state is PEM_BODY */
+ {
+ const char *ugh = NULL;
+ size_t len = 0;
+ chunk_t data;
+
+ /* remove any trailing whitespace */
+ if (!extract_token(&data ,' ', &line))
+ data = line;
+
+ /* check for PGP armor checksum */
+ if (*data.ptr == '=')
+ {
+ *pgp = TRUE;
+ data.ptr++;
+ data.len--;
+ DBG(DBG_PARSING,
+ DBG_log(" Armor checksum: %.*s", (int)data.len, data.ptr);
+ )
+ continue;
+ }
+
+ ugh = ttodata(data.ptr, data.len, 64,
+ dst.ptr, blob->len - dst.len, &len);
+ if (ugh)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" %s", ugh);
+ )
+ state = PEM_ABORT;
+ break;
+ }
+ else
+ {
+ dst.ptr += len;
+ dst.len += len;
+ }
+ }
+ }
+ }
+ /* set length to size of binary blob */
+ blob->len = dst.len;
+
+ if (state != PEM_POST)
+ return "file coded in unknown format, discarded";
+
+ if (encrypted)
+ return pem_decrypt(blob, &iv, pass, label);
+ else
+ return NULL;
+}
diff --git a/programs/pluto/pem.h b/programs/pluto/pem.h
new file mode 100644
index 000000000..815b5d85b
--- /dev/null
+++ b/programs/pluto/pem.h
@@ -0,0 +1,18 @@
+/* Loading of PEM encoded files with optional encryption
+ * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: pem.h,v 1.1 2004/03/15 20:35:28 as Exp $
+ */
+
+extern err_t pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label
+ , bool *pgp);
diff --git a/programs/pluto/pgp.c b/programs/pluto/pgp.c
new file mode 100644
index 000000000..015319aaf
--- /dev/null
+++ b/programs/pluto/pgp.c
@@ -0,0 +1,647 @@
+/* Support of OpenPGP certificates
+ * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: pgp.c,v 1.7 2006/01/04 21:00:43 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+#include "id.h"
+#include "pgp.h"
+#include "certs.h"
+#include "md5.h"
+#include "whack.h"
+#include "pkcs1.h"
+#include "keys.h"
+
+/*
+ * chained list of OpenPGP end certificates
+ */
+static pgpcert_t *pgpcerts = NULL;
+
+/*
+ * OpenPGP packet tags defined in section 4.3 of RFC 2440
+ */
+#define PGP_PKT_RESERVED 0
+#define PGP_PKT_PUBKEY_ENC_SESSION_KEY 1
+#define PGP_PKT_SIGNATURE 2
+#define PGP_PKT_SYMKEY_ENC_SESSION_KEY 3
+#define PGP_PKT_ONE_PASS_SIGNATURE_PKT 4
+#define PGP_PKT_SECRET_KEY 5
+#define PGP_PKT_PUBLIC_KEY 6
+#define PGP_PKT_SECRET_SUBKEY 7
+#define PGP_PKT_COMPRESSED_DATA 8
+#define PGP_PKT_SYMKEY_ENC_DATA 9
+#define PGP_PKT_MARKER 10
+#define PGP_PKT_LITERAL_DATA 11
+#define PGP_PKT_TRUST 12
+#define PGP_PKT_USER_ID 13
+#define PGP_PKT_PUBLIC_SUBKEY 14
+#define PGP_PKT_ROOF 15
+
+static const char *const pgp_packet_type_name[] = {
+ "Reserved",
+ "Public-Key Encrypted Session Key Packet",
+ "Signature Packet",
+ "Symmetric-Key Encrypted Session Key Packet",
+ "One-Pass Signature Packet",
+ "Secret Key Packet",
+ "Public Key Packet",
+ "Secret Subkey Packet",
+ "Compressed Data Packet",
+ "Symmetrically Encrypted Data Packet",
+ "Marker Packet",
+ "Literal Data Packet",
+ "Trust Packet",
+ "User ID Packet",
+ "Public Subkey Packet"
+};
+
+/*
+ * OpenPGP public key algorithms defined in section 9.1 of RFC 2440
+ */
+#define PGP_PUBKEY_ALG_RSA 1
+#define PGP_PUBKEY_ALG_RSA_ENC_ONLY 2
+#define PGP_PUBKEY_ALG_RSA_SIGN_ONLY 3
+#define PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY 16
+#define PGP_PUBKEY_ALG_DSA 17
+#define PGP_PUBKEY_ALG_ECC 18
+#define PGP_PUBKEY_ALG_ECDSA 19
+#define PGP_PUBKEY_ALG_ELGAMAL 20
+
+/*
+ * OpenPGP symmetric key algorithms defined in section 9.2 of RFC 2440
+ */
+#define PGP_SYM_ALG_PLAIN 0
+#define PGP_SYM_ALG_IDEA 1
+#define PGP_SYM_ALG_3DES 2
+#define PGP_SYM_ALG_CAST5 3
+#define PGP_SYM_ALG_BLOWFISH 4
+#define PGP_SYM_ALG_SAFER 5
+#define PGP_SYM_ALG_DES 6
+#define PGP_SYM_ALG_AES 7
+#define PGP_SYM_ALG_AES_192 8
+#define PGP_SYM_ALG_AES_256 9
+#define PGP_SYM_ALG_TWOFISH 10
+#define PGP_SYM_ALG_ROOF 11
+
+static const char *const pgp_sym_alg_name[] = {
+ "Plaintext",
+ "IDEA",
+ "3DES",
+ "CAST5",
+ "Blowfish",
+ "SAFER",
+ "DES",
+ "AES",
+ "AES-192",
+ "AES-256",
+ "Twofish"
+};
+
+/*
+ * Size of PGP Key ID
+ */
+#define PGP_KEYID_SIZE 8
+
+const pgpcert_t empty_pgpcert = {
+ NULL , /* *next */
+ 0 , /* installed */
+ 0 , /* count */
+ { NULL, 0 }, /* certificate */
+ 0 , /* created */
+ 0 , /* until */
+ 0 , /* pubkeyAlgorithm */
+ { NULL, 0 }, /* modulus */
+ { NULL, 0 }, /* publicExponent */
+ "" /* fingerprint */
+};
+
+static size_t
+pgp_size(chunk_t *blob, int len)
+{
+ size_t size = 0;
+
+ blob->len -= len;
+ while (len-- > 0)
+ size = 256*size + *blob->ptr++;
+ return size;
+}
+
+/*
+ * extracts the length of a PGP packet
+ */
+static size_t
+pgp_old_packet_length(chunk_t *blob)
+{
+ /* bits 0 and 1 define the packet length type */
+ int len_type = 0x03 & *blob->ptr++;
+
+ blob->len--;
+
+ /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
+ return pgp_size(blob, (len_type == 0)? 1: len_type << 1);
+}
+
+/*
+ * extracts PGP packet version (V3 or V4)
+ */
+static u_char
+pgp_version(chunk_t *blob)
+{
+ u_char version = *blob->ptr++;
+ blob->len--;
+ DBG(DBG_PARSING,
+ DBG_log("L3 - version:");
+ DBG_log(" V%d", version)
+ )
+ return version;
+}
+
+/*
+ * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
+ */
+static bool
+parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
+{
+ u_char version = pgp_version(packet);
+
+ if (version < 3 || version > 4)
+ {
+ plog("PGP packet version V%d not supported", version);
+ return FALSE;
+ }
+
+ /* creation date - 4 bytes */
+ cert->created = (time_t)pgp_size(packet, 4);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - created:");
+ DBG_log(" %s", timetoa(&cert->created, TRUE))
+ )
+
+ if (version == 3)
+ {
+ /* validity in days - 2 bytes */
+ cert->until = (time_t)pgp_size(packet, 2);
+
+ /* validity of 0 days means that the key never expires */
+ if (cert->until > 0)
+ cert->until = cert->created + 24*3600*cert->until;
+
+ DBG(DBG_PARSING,
+ DBG_log("L3 - until:");
+ DBG_log(" %s", timetoa(&cert->until, TRUE));
+ )
+ }
+
+ /* public key algorithm - 1 byte */
+ DBG(DBG_PARSING,
+ DBG_log("L3 - public key algorithm:")
+ )
+
+ switch (pgp_size(packet, 1))
+ {
+ case PGP_PUBKEY_ALG_RSA:
+ case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
+ cert->pubkeyAlg = PUBKEY_ALG_RSA;
+ DBG(DBG_PARSING,
+ DBG_log(" RSA")
+ )
+ /* modulus n */
+ cert->modulus.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
+ cert->modulus.ptr = packet->ptr;
+ packet->ptr += cert->modulus.len;
+ packet->len -= cert->modulus.len;
+ DBG(DBG_PARSING,
+ DBG_log("L3 - modulus:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", cert->modulus);
+
+ /* public exponent e */
+ cert->publicExponent.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
+ cert->publicExponent.ptr = packet->ptr;
+ packet->ptr += cert->publicExponent.len;
+ packet->len -= cert->publicExponent.len;
+ DBG(DBG_PARSING,
+ DBG_log("L3 - public exponent:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", cert->publicExponent);
+
+ if (version == 3)
+ {
+ /* a V3 fingerprint is the MD5 hash of modulus and public exponent */
+ MD5_CTX context;
+ MD5Init(&context);
+ MD5Update(&context, cert->modulus.ptr, cert->modulus.len);
+ MD5Update(&context, cert->publicExponent.ptr, cert->publicExponent.len);
+ MD5Final(cert->fingerprint, &context);
+ }
+ else
+ {
+ plog(" computation of V4 key ID not implemented yet");
+ }
+ break;
+ case PGP_PUBKEY_ALG_DSA:
+ cert->pubkeyAlg = PUBKEY_ALG_DSA;
+ DBG(DBG_PARSING,
+ DBG_log(" DSA")
+ )
+ plog(" DSA public keys not supported");
+ return FALSE;
+ default:
+ cert->pubkeyAlg = 0;
+ DBG(DBG_PARSING,
+ DBG_log(" other")
+ )
+ plog(" exotic not RSA public keys not supported");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 2440
+ */
+static bool
+parse_pgp_secretkey_packet(chunk_t *packet, RSA_private_key_t *key)
+{
+ int i, s2k;
+ pgpcert_t cert = empty_pgpcert;
+
+ if (!parse_pgp_pubkey_packet(packet, &cert))
+ return FALSE;
+
+ init_RSA_public_key((RSA_public_key_t *)key, cert.publicExponent
+ , cert.modulus);
+
+ /* string-to-key usage */
+ s2k = pgp_size(packet, 1);
+
+ DBG(DBG_PARSING,
+ DBG_log("L3 - string-to-key: %d", s2k)
+ )
+
+ if (s2k == 255)
+ {
+ plog(" string-to-key specifiers not supported");
+ return FALSE;
+ }
+
+ if (s2k >= PGP_SYM_ALG_ROOF)
+ {
+ plog(" undefined symmetric key algorithm");
+ return FALSE;
+ }
+
+ /* a known symmetric key algorithm is specified*/
+ DBG(DBG_PARSING,
+ DBG_log(" %s", pgp_sym_alg_name[s2k])
+ )
+
+ /* private key is unencrypted */
+ if (s2k == PGP_SYM_ALG_PLAIN)
+ {
+ for (i = 2; i < RSA_PRIVATE_FIELD_ELEMENTS; i++)
+ {
+ mpz_t u; /* auxiliary variable */
+
+ /* compute offset to private key component i*/
+ MP_INT *n = (MP_INT*)((char *)key + RSA_private_field[i].offset);
+
+ switch (i)
+ {
+ case 2:
+ case 3:
+ case 4:
+ {
+ size_t len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
+
+ n_to_mpz(n, packet->ptr, len);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - %s:", RSA_private_field[i].name)
+ )
+ DBG_cond_dump(DBG_PRIVATE, "", packet->ptr, len);
+ packet->ptr += len;
+ packet->len -= len;
+ }
+ break;
+ case 5: /* dP = d mod (p-1) */
+ mpz_init(u);
+ mpz_sub_ui(u, &key->p, 1);
+ mpz_mod(n, &key->d, u);
+ mpz_clear(u);
+ break;
+ case 6: /* dQ = d mod (q-1) */
+ mpz_init(u);
+ mpz_sub_ui(u, &key->q, 1);
+ mpz_mod(n, &key->d, u);
+ mpz_clear(u);
+ break;
+ case 7: /* qInv = (q^-1) mod p */
+ mpz_invert(n, &key->q, &key->p);
+ if (mpz_cmp_ui(n, 0) < 0)
+ mpz_add(n, n, &key->p);
+ passert(mpz_cmp(n, &key->p) < 0);
+ break;
+ }
+ }
+ return TRUE;
+ }
+
+ plog(" %s encryption not supported", pgp_sym_alg_name[s2k]);
+ return FALSE;
+}
+
+/*
+ * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
+ */
+static bool
+parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
+{
+ time_t created;
+ chunk_t keyid;
+ u_char sig_type;
+ u_char version = pgp_version(packet);
+
+ /* we parse only V3 signature packets */
+ if (version != 3)
+ return TRUE;
+
+ /* size byte must have the value 5 */
+ if (pgp_size(packet, 1) != 5)
+ {
+ plog(" size must be 5");
+ return FALSE;
+ }
+
+ /* signature type - 1 byte */
+ sig_type = (u_char)pgp_size(packet, 1);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - signature type: 0x%2x", sig_type)
+ )
+
+ /* creation date - 4 bytes */
+ created = (time_t)pgp_size(packet, 4);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - created:");
+ DBG_log(" %s", timetoa(&cert->created, TRUE))
+ )
+
+ /* key ID of signer - 8 bytes */
+ keyid.ptr = packet->ptr;
+ keyid.len = PGP_KEYID_SIZE;
+ DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid);
+
+ return TRUE;
+}
+
+bool
+parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
+{
+ DBG(DBG_PARSING,
+ DBG_log("L0 - PGP file:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", blob);
+
+ if (cert != NULL)
+ {
+ /* parse a PGP certificate file */
+ cert->certificate = blob;
+ time(&cert->installed);
+ }
+ else if (key == NULL)
+ {
+ /* should not occur, nothing to parse */
+ return FALSE;
+ }
+
+ while (blob.len > 0)
+ {
+ chunk_t packet = empty_chunk;
+ u_char packet_tag = *blob.ptr;
+
+ DBG(DBG_PARSING,
+ DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag)
+ )
+
+ /* bit 7 must be set */
+ if (!(packet_tag & 0x80))
+ {
+ plog(" incorrect Packet Tag");
+ return FALSE;
+ }
+
+ /* bit 6 set defines new packet format */
+ if (packet_tag & 0x40)
+ {
+ plog(" new PGP packet format not supported");
+ return FALSE;
+ }
+ else
+ {
+ int packet_type = (packet_tag & 0x3C) >> 2;
+
+ packet.len = pgp_old_packet_length(&blob);
+ packet.ptr = blob.ptr;
+ blob.ptr += packet.len;
+ blob.len -= packet.len;
+ DBG(DBG_PARSING,
+ DBG_log(" %s (%d), old format, %d bytes",
+ (packet_type < PGP_PKT_ROOF) ?
+ pgp_packet_type_name[packet_type] :
+ "Undefined Packet Type", packet_type, (int)packet.len);
+ DBG_log("L2 - body:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", packet);
+
+ if (cert != NULL)
+ {
+ /* parse a PGP certificate */
+ switch (packet_type)
+ {
+ case PGP_PKT_PUBLIC_KEY:
+ if (!parse_pgp_pubkey_packet(&packet, cert))
+ return FALSE;
+ break;
+ case PGP_PKT_SIGNATURE:
+ if (!parse_pgp_signature_packet(&packet, cert))
+ return FALSE;
+ break;
+ case PGP_PKT_USER_ID:
+ DBG(DBG_PARSING,
+ DBG_log("L3 - user ID:");
+ DBG_log(" '%.*s'", (int)packet.len, packet.ptr)
+ )
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ /* parse a PGP private key file */
+ switch (packet_type)
+ {
+ case PGP_PKT_SECRET_KEY:
+ if (!parse_pgp_secretkey_packet(&packet, key))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * compare two OpenPGP certificates
+ */
+static bool
+same_pgpcert(pgpcert_t *a, pgpcert_t *b)
+{
+ return a->certificate.len == b->certificate.len &&
+ memcmp(a->certificate.ptr, b->certificate.ptr, b->certificate.len) == 0;
+}
+
+/*
+ * for each link pointing to the certificate increase the count by one
+ */
+void
+share_pgpcert(pgpcert_t *cert)
+{
+ if (cert != NULL)
+ cert->count++;
+}
+
+/*
+ * select the OpenPGP keyid as ID
+ */
+void
+select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
+{
+ end_id->kind = ID_KEY_ID;
+ end_id->name.len = PGP_FINGERPRINT_SIZE;
+ end_id->name.ptr = cert->fingerprint;
+ end_id->name.ptr = temporary_cyclic_buffer();
+ memcpy(end_id->name.ptr, cert->fingerprint, PGP_FINGERPRINT_SIZE);
+}
+
+/*
+ * add an OpenPGP user/host certificate to the chained list
+ */
+pgpcert_t*
+add_pgpcert(pgpcert_t *cert)
+{
+ pgpcert_t *c = pgpcerts;
+
+ while (c != NULL)
+ {
+ if (same_pgpcert(c, cert)) /* already in chain, free cert */
+ {
+ free_pgpcert(cert);
+ return c;
+ }
+ c = c->next;
+ }
+
+ /* insert new cert at the root of the chain */
+ cert->next = pgpcerts;
+ pgpcerts = cert;
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" pgp cert inserted")
+ )
+ return cert;
+}
+
+/* release of a certificate decreases the count by one
+ " the certificate is freed when the counter reaches zero
+ */
+void
+release_pgpcert(pgpcert_t *cert)
+{
+ if (cert != NULL && --cert->count == 0)
+ {
+ pgpcert_t **pp = &pgpcerts;
+ while (*pp != cert)
+ pp = &(*pp)->next;
+ *pp = cert->next;
+ free_pgpcert(cert);
+ }
+}
+
+/*
+ * free a PGP certificate
+ */
+void
+free_pgpcert(pgpcert_t *cert)
+{
+ if (cert != NULL)
+ {
+ if (cert->certificate.ptr != NULL)
+ pfree(cert->certificate.ptr);
+ pfree(cert);
+ }
+}
+
+/*
+ * list all PGP end certificates in a chained list
+ */
+void
+list_pgp_end_certs(bool utc)
+{
+ pgpcert_t *cert = pgpcerts;
+ time_t now;
+
+ /* determine the current time */
+ time(&now);
+
+ if (cert != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of PGP End certificates:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (cert != NULL)
+ {
+ unsigned keysize;
+ char buf[BUF_LEN];
+ cert_t c;
+
+ c.type = CERT_PGP;
+ c.u.pgp = cert;
+
+ whack_log(RC_COMMENT, "%s, count: %d", timetoa(&cert->installed, utc), cert->count);
+ datatot(cert->fingerprint, PGP_FINGERPRINT_SIZE, 'x', buf, BUF_LEN);
+ whack_log(RC_COMMENT, " fingerprint: %s", buf);
+ form_keyid(cert->publicExponent, cert->modulus, buf, &keysize);
+ whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s", 8*keysize, buf,
+ (has_private_key(c))? ", has private key" : "");
+ whack_log(RC_COMMENT, " created: %s", timetoa(&cert->created, utc));
+ whack_log(RC_COMMENT, " until: %s %s", timetoa(&cert->until, utc),
+ check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
+ cert = cert->next;
+ }
+}
+
diff --git a/programs/pluto/pgp.h b/programs/pluto/pgp.h
new file mode 100644
index 000000000..4f34debc9
--- /dev/null
+++ b/programs/pluto/pgp.h
@@ -0,0 +1,54 @@
+/* Support of OpenPGP certificates
+ * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: pgp.h,v 1.3 2005/08/07 07:50:09 as Exp $
+ */
+
+#ifndef _PGP_H
+#define _PGP_H
+
+#include "pkcs1.h"
+/*
+ * Length of PGP V3 fingerprint
+ */
+#define PGP_FINGERPRINT_SIZE MD5_DIGEST_SIZE
+
+typedef char fingerprint_t[PGP_FINGERPRINT_SIZE];
+
+/* access structure for an OpenPGP certificate */
+
+typedef struct pgpcert pgpcert_t;
+
+struct pgpcert {
+ pgpcert_t *next;
+ time_t installed;
+ int count;
+ chunk_t certificate;
+ time_t created;
+ time_t until;
+ enum pubkey_alg pubkeyAlg;
+ chunk_t modulus;
+ chunk_t publicExponent;
+ fingerprint_t fingerprint;
+};
+
+extern const pgpcert_t empty_pgpcert;
+extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key);
+extern void share_pgpcert(pgpcert_t *cert);
+extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
+extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
+extern void list_pgp_end_certs(bool utc);
+extern void release_pgpcert(pgpcert_t *cert);
+extern void free_pgpcert(pgpcert_t *cert);
+
+#endif /* _PGP_H */
diff --git a/programs/pluto/pkcs1.c b/programs/pluto/pkcs1.c
new file mode 100644
index 000000000..413938976
--- /dev/null
+++ b/programs/pluto/pkcs1.c
@@ -0,0 +1,635 @@
+/* Support of PKCS#1 private key data structures
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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: pkcs1.c,v 1.17 2006/01/04 21:00:43 as Exp $
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "asn1.h"
+#include "oid.h"
+#include "log.h"
+#include "pkcs1.h"
+#include "md2.h"
+#include "md5.h"
+#include "sha1.h"
+#include "rnd.h"
+
+const struct fld RSA_private_field[] =
+{
+ { "Modulus", offsetof(RSA_private_key_t, pub.n) },
+ { "PublicExponent", offsetof(RSA_private_key_t, pub.e) },
+
+ { "PrivateExponent", offsetof(RSA_private_key_t, d) },
+ { "Prime1", offsetof(RSA_private_key_t, p) },
+ { "Prime2", offsetof(RSA_private_key_t, q) },
+ { "Exponent1", offsetof(RSA_private_key_t, dP) },
+ { "Exponent2", offsetof(RSA_private_key_t, dQ) },
+ { "Coefficient", offsetof(RSA_private_key_t, qInv) },
+};
+
+/* ASN.1 definition of a PKCS#1 RSA private key */
+
+static const asn1Object_t privkeyObjects[] = {
+ { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */
+ { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */
+ { 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */
+ { 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */
+ { 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */
+ { 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */
+ { 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */
+ { 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */
+ { 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_LOOP }, /* 10 */
+ { 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
+ { 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */
+ { 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */
+ { 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */
+ { 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */
+};
+
+#define PKCS1_PRIV_KEY_VERSION 1
+#define PKCS1_PRIV_KEY_MODULUS 2
+#define PKCS1_PRIV_KEY_PUB_EXP 3
+#define PKCS1_PRIV_KEY_COEFF 9
+#define PKCS1_PRIV_KEY_ROOF 16
+
+
+/*
+ * forms the FreeS/WAN keyid from the public exponent e and modulus n
+ */
+void
+form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize)
+{
+ /* eliminate leading zero bytes in modulus from ASN.1 coding */
+ while (n.len > 1 && *n.ptr == 0x00)
+ {
+ n.ptr++; n.len--;
+ }
+
+ /* form the FreeS/WAN keyid */
+ keyid[0] = '\0'; /* in case of splitkeytoid failure */
+ splitkeytoid(e.ptr, e.len, n.ptr, n.len, keyid, KEYID_BUF);
+
+ /* return the RSA modulus size in octets */
+ *keysize = n.len;
+}
+
+/*
+ * initialize an RSA_public_key_t object
+ */
+void
+init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n)
+{
+ n_to_mpz(&rsa->e, e.ptr, e.len);
+ n_to_mpz(&rsa->n, n.ptr, n.len);
+
+ form_keyid(e, n, rsa->keyid, &rsa->k);
+}
+
+#ifdef DEBUG
+static void
+RSA_show_key_fields(RSA_private_key_t *k, int fieldcnt)
+{
+ const struct fld *p;
+
+ DBG_log(" keyid: *%s", k->pub.keyid);
+
+ for (p = RSA_private_field; p < &RSA_private_field[fieldcnt]; p++)
+ {
+ MP_INT *n = (MP_INT *) ((char *)k + p->offset);
+ size_t sz = mpz_sizeinbase(n, 16);
+ char buf[RSA_MAX_OCTETS * 2 + 2]; /* ought to be big enough */
+
+ passert(sz <= sizeof(buf));
+ mpz_get_str(buf, 16, n);
+
+ DBG_log(" %s: 0x%s", p->name, buf);
+ }
+}
+
+/* debugging info that compromises security! */
+void
+RSA_show_private_key(RSA_private_key_t *k)
+{
+ RSA_show_key_fields(k, elemsof(RSA_private_field));
+}
+
+void
+RSA_show_public_key(RSA_public_key_t *k)
+{
+ /* Kludge: pretend that it is a private key, but only display the
+ * first two fields (which are the public key).
+ */
+ passert(offsetof(RSA_private_key_t, pub) == 0);
+ RSA_show_key_fields((RSA_private_key_t *)k, 2);
+}
+#endif
+
+err_t
+RSA_private_key_sanity(RSA_private_key_t *k)
+{
+ /* note that the *last* error found is reported */
+ err_t ugh = NULL;
+ mpz_t t, u, q1;
+
+#ifdef DEBUG /* debugging info that compromises security */
+ DBG(DBG_PRIVATE, RSA_show_private_key(k));
+#endif
+
+ /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
+ * We actually require more (for security).
+ */
+ if (k->pub.k < RSA_MIN_OCTETS)
+ return RSA_MIN_OCTETS_UGH;
+
+ /* we picked a max modulus size to simplify buffer allocation */
+ if (k->pub.k > RSA_MAX_OCTETS)
+ return RSA_MAX_OCTETS_UGH;
+
+ mpz_init(t);
+ mpz_init(u);
+ mpz_init(q1);
+
+ /* check that n == p * q */
+ mpz_mul(u, &k->p, &k->q);
+ if (mpz_cmp(u, &k->pub.n) != 0)
+ ugh = "n != p * q";
+
+ /* check that e divides neither p-1 nor q-1 */
+ mpz_sub_ui(t, &k->p, 1);
+ mpz_mod(t, t, &k->pub.e);
+ if (mpz_cmp_ui(t, 0) == 0)
+ ugh = "e divides p-1";
+
+ mpz_sub_ui(t, &k->q, 1);
+ mpz_mod(t, t, &k->pub.e);
+ if (mpz_cmp_ui(t, 0) == 0)
+ ugh = "e divides q-1";
+
+ /* check that d is e^-1 (mod lcm(p-1, q-1)) */
+ /* see PKCS#1v2, aka RFC 2437, for the "lcm" */
+ mpz_sub_ui(q1, &k->q, 1);
+ mpz_sub_ui(u, &k->p, 1);
+ mpz_gcd(t, u, q1); /* t := gcd(p-1, q-1) */
+ mpz_mul(u, u, q1); /* u := (p-1) * (q-1) */
+ mpz_divexact(u, u, t); /* u := lcm(p-1, q-1) */
+
+ mpz_mul(t, &k->d, &k->pub.e);
+ mpz_mod(t, t, u);
+ if (mpz_cmp_ui(t, 1) != 0)
+ ugh = "(d * e) mod (lcm(p-1, q-1)) != 1";
+
+ /* check that dP is d mod (p-1) */
+ mpz_sub_ui(u, &k->p, 1);
+ mpz_mod(t, &k->d, u);
+ if (mpz_cmp(t, &k->dP) != 0)
+ ugh = "dP is not congruent to d mod (p-1)";
+
+ /* check that dQ is d mod (q-1) */
+ mpz_sub_ui(u, &k->q, 1);
+ mpz_mod(t, &k->d, u);
+ if (mpz_cmp(t, &k->dQ) != 0)
+ ugh = "dQ is not congruent to d mod (q-1)";
+
+ /* check that qInv is (q^-1) mod p */
+ mpz_mul(t, &k->qInv, &k->q);
+ mpz_mod(t, t, &k->p);
+ if (mpz_cmp_ui(t, 1) != 0)
+ ugh = "qInv is not conguent ot (q^-1) mod p";
+
+ mpz_clear(t);
+ mpz_clear(u);
+ mpz_clear(q1);
+ return ugh;
+}
+
+/*
+ * Check the equality of two RSA public keys
+ */
+bool
+same_RSA_public_key(const RSA_public_key_t *a, const RSA_public_key_t *b)
+{
+ return a == b
+ || (a->k == b->k && mpz_cmp(&a->n, &b->n) == 0 && mpz_cmp(&a->e, &b->e) == 0);
+}
+
+/*
+ * Parses a PKCS#1 private key
+ */
+bool
+pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key)
+{
+ err_t ugh = NULL;
+ asn1_ctx_t ctx;
+ chunk_t object, modulus, exp;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, 0, FALSE, DBG_PRIVATE);
+
+ while (objectID < PKCS1_PRIV_KEY_ROOF) {
+
+ if (!extract_object(privkeyObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ if (objectID == PKCS1_PRIV_KEY_VERSION)
+ {
+ if (object.len > 0 && *object.ptr != 0)
+ {
+ plog(" wrong PKCS#1 private key version");
+ return FALSE;
+ }
+ }
+ else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
+ objectID <= PKCS1_PRIV_KEY_COEFF)
+ {
+ MP_INT *u = (MP_INT *) ((char *)key
+ + RSA_private_field[objectID - PKCS1_PRIV_KEY_MODULUS].offset);
+
+ n_to_mpz(u, object.ptr, object.len);
+
+ if (objectID == PKCS1_PRIV_KEY_MODULUS)
+ modulus = object;
+ else if (objectID == PKCS1_PRIV_KEY_PUB_EXP)
+ exp = object;
+ }
+ objectID++;
+ }
+ form_keyid(exp, modulus, key->pub.keyid, &key->pub.k);
+ ugh = RSA_private_key_sanity(key);
+ return (ugh == NULL);
+}
+
+/*
+ * compute a digest over a binary blob
+ */
+bool
+compute_digest(chunk_t tbs, int alg, chunk_t *digest)
+{
+ switch (alg)
+ {
+ case OID_MD2:
+ case OID_MD2_WITH_RSA:
+ {
+ MD2_CTX context;
+ MD2Init(&context);
+ MD2Update(&context, tbs.ptr, tbs.len);
+ MD2Final(digest->ptr, &context);
+ digest->len = MD2_DIGEST_SIZE;
+ return TRUE;
+ }
+ case OID_MD5:
+ case OID_MD5_WITH_RSA:
+ {
+ MD5_CTX context;
+ MD5Init(&context);
+ MD5Update(&context, tbs.ptr, tbs.len);
+ MD5Final(digest->ptr, &context);
+ digest->len = MD5_DIGEST_SIZE;
+ return TRUE;
+ }
+ case OID_SHA1:
+ case OID_SHA1_WITH_RSA:
+ case OID_SHA1_WITH_RSA_OIW:
+ {
+ SHA1_CTX context;
+
+ SHA1Init(&context);
+ SHA1Update(&context, tbs.ptr, tbs.len);
+ SHA1Final(digest->ptr, &context);
+ digest->len = SHA1_DIGEST_SIZE;
+ return TRUE;
+ }
+ default:
+ digest->len = 0;
+ return FALSE;
+ }
+}
+
+/*
+ * compute an RSA signature with PKCS#1 padding
+ */
+void
+sign_hash(const RSA_private_key_t *k, const u_char *hash_val, size_t hash_len
+ , u_char *sig_val, size_t sig_len)
+{
+ chunk_t ch;
+ mpz_t t1, t2;
+ size_t padlen;
+ u_char *p = sig_val;
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("signing hash with RSA Key *%s", k->pub.keyid)
+ )
+ /* PKCS#1 v1.5 8.1 encryption-block formatting */
+ *p++ = 0x00;
+ *p++ = 0x01; /* BT (block type) 01 */
+ padlen = sig_len - 3 - hash_len;
+ memset(p, 0xFF, padlen);
+ p += padlen;
+ *p++ = 0x00;
+ memcpy(p, hash_val, hash_len);
+ passert(p + hash_len - sig_val == (ptrdiff_t)sig_len);
+
+ /* PKCS#1 v1.5 8.2 octet-string-to-integer conversion */
+ n_to_mpz(t1, sig_val, sig_len); /* (could skip leading 0x00) */
+
+ /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n
+ * Better described in PKCS#1 v2.0 5.1 RSADP.
+ * There are two methods, depending on the form of the private key.
+ * We use the one based on the Chinese Remainder Theorem.
+ */
+ mpz_init(t2);
+
+ mpz_powm(t2, t1, &k->dP, &k->p); /* m1 = c^dP mod p */
+
+ mpz_powm(t1, t1, &k->dQ, &k->q); /* m2 = c^dQ mod Q */
+
+ mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */
+ mpz_mod(t2, t2, &k->p);
+ mpz_mul(t2, t2, &k->qInv);
+ mpz_mod(t2, t2, &k->p);
+
+ mpz_mul(t2, t2, &k->q); /* m = m2 + h q */
+ mpz_add(t1, t1, t2);
+
+ /* PKCS#1 v1.5 8.4 integer-to-octet-string conversion */
+ ch = mpz_to_n(t1, sig_len);
+ memcpy(sig_val, ch.ptr, sig_len);
+ pfree(ch.ptr);
+
+ mpz_clear(t1);
+ mpz_clear(t2);
+}
+
+/*
+ * encrypt data with an RSA public key after padding
+ */
+chunk_t
+RSA_encrypt(const RSA_public_key_t *key, chunk_t in)
+{
+ u_char padded[RSA_MAX_OCTETS];
+ u_char *pos = padded;
+ int padding = key->k - in.len - 3;
+ int i;
+
+ if (padding < 8 || key->k > RSA_MAX_OCTETS)
+ return empty_chunk;
+
+ /* add padding according to PKCS#1 7.2.1 1.+2. */
+ *pos++ = 0x00;
+ *pos++ = 0x02;
+
+ /* pad with pseudo random bytes unequal to zero */
+ get_rnd_bytes(pos, padding);
+ for (i = 0; i < padding; i++)
+ {
+ while (!*pos)
+ get_rnd_bytes(pos, 1);
+ pos++;
+ }
+
+ /* append the padding terminator */
+ *pos++ = 0x00;
+
+ /* now add the data */
+ memcpy(pos, in.ptr, in.len);
+ DBG(DBG_RAW,
+ DBG_dump_chunk("data for rsa encryption:\n", in);
+ DBG_dump("padded data for rsa encryption:\n", padded, key->k)
+ )
+
+ /* convert chunk to integer (PKCS#1 7.2.1 3.a) */
+ {
+ chunk_t out;
+ mpz_t m, c;
+
+ mpz_init(c);
+ n_to_mpz(m, padded, key->k);
+
+ /* encrypt(PKCS#1 7.2.1 3.b) */
+ mpz_powm(c, m, &key->e, &key->n);
+
+ /* convert integer back to a chunk (PKCS#1 7.2.1 3.c) */
+ out = mpz_to_n(c, key->k);
+ mpz_clear(c);
+ mpz_clear(m);
+
+ DBG(DBG_RAW,
+ DBG_dump_chunk("rsa encrypted data:\n", out)
+ )
+ return out;
+ }
+}
+
+/*
+ * decrypt data with an RSA private key and remove padding
+ */
+bool
+RSA_decrypt(const RSA_private_key_t *key, chunk_t in, chunk_t *out)
+{
+ chunk_t padded;
+ u_char *pos;
+ mpz_t t1, t2;
+
+ n_to_mpz(t1, in.ptr,in.len);
+
+ /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n
+ * Better described in PKCS#1 v2.0 5.1 RSADP.
+ * There are two methods, depending on the form of the private key.
+ * We use the one based on the Chinese Remainder Theorem.
+ */
+ mpz_init(t2);
+
+ mpz_powm(t2, t1, &key->dP, &key->p); /* m1 = c^dP mod p */
+ mpz_powm(t1, t1, &key->dQ, &key->q); /* m2 = c^dQ mod Q */
+
+ mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */
+ mpz_mod(t2, t2, &key->p);
+ mpz_mul(t2, t2, &key->qInv);
+ mpz_mod(t2, t2, &key->p);
+
+ mpz_mul(t2, t2, &key->q); /* m = m2 + h q */
+ mpz_add(t1, t1, t2);
+
+ padded = mpz_to_n(t1, key->pub.k);
+ mpz_clear(t1);
+ mpz_clear(t2);
+
+ DBG(DBG_PRIVATE,
+ DBG_dump_chunk("rsa decrypted data with padding:\n", padded)
+ )
+ pos = padded.ptr;
+
+ /* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */
+
+ /* check for hex pattern 00 02 in decrypted message */
+ if ((*pos++ != 0x00) || (*(pos++) != 0x02))
+ {
+ plog("incorrect padding - probably wrong RSA key");
+ freeanychunk(padded);
+ return FALSE;
+ }
+ padded.len -= 2;
+
+ /* the plaintext data starts after first 0x00 byte */
+ while (padded.len-- > 0 && *pos++ != 0x00)
+
+ if (padded.len == 0)
+ {
+ plog("no plaintext data");
+ freeanychunk(padded);
+ return FALSE;
+ }
+
+ clonetochunk(*out, pos, padded.len, "decrypted data");
+ freeanychunk(padded);
+ return TRUE;
+}
+
+/*
+ * build signatureValue
+ */
+chunk_t
+pkcs1_build_signature(chunk_t tbs, int hash_alg, const RSA_private_key_t *key
+, bool bit_string)
+{
+
+ size_t siglen = key->pub.k;
+
+ u_char digest_buf[MAX_DIGEST_LEN];
+ chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
+ chunk_t digestInfo, alg_id, signatureValue;
+ u_char *pos;
+
+ switch (hash_alg)
+ {
+ case OID_MD5:
+ case OID_MD5_WITH_RSA:
+ alg_id = ASN1_md5_id;
+ break;
+ case OID_SHA1:
+ case OID_SHA1_WITH_RSA:
+ alg_id = ASN1_sha1_id;
+ break;
+ default:
+ return empty_chunk;
+ }
+ compute_digest(tbs, hash_alg, &digest);
+
+ /* according to PKCS#1 v2.1 digest must be packaged into
+ * an ASN.1 structure for encryption
+ */
+ digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , alg_id
+ , asn1_simple_object(ASN1_OCTET_STRING, digest));
+
+ /* generate the RSA signature */
+ if (bit_string)
+ {
+ pos = build_asn1_object(&signatureValue, ASN1_BIT_STRING, 1 + siglen);
+ *pos++ = 0x00;
+ }
+ else
+ {
+ pos = build_asn1_object(&signatureValue, ASN1_OCTET_STRING, siglen);
+ }
+ sign_hash(key, digestInfo.ptr, digestInfo.len, pos, siglen);
+ pfree(digestInfo.ptr);
+
+ return signatureValue;
+}
+
+/*
+ * build a DER-encoded PKCS#1 private key object
+ */
+chunk_t
+pkcs1_build_private_key(const RSA_private_key_t *key)
+{
+ chunk_t pkcs1 = asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm"
+ , ASN1_INTEGER_0
+ , asn1_integer_from_mpz(&key->pub.n)
+ , asn1_integer_from_mpz(&key->pub.e)
+ , asn1_integer_from_mpz(&key->d)
+ , asn1_integer_from_mpz(&key->p)
+ , asn1_integer_from_mpz(&key->q)
+ , asn1_integer_from_mpz(&key->dP)
+ , asn1_integer_from_mpz(&key->dQ)
+ , asn1_integer_from_mpz(&key->qInv));
+
+ DBG(DBG_PRIVATE,
+ DBG_dump_chunk("PKCS#1 encoded private key:", pkcs1)
+ )
+ return pkcs1;
+}
+
+/*
+ * build a DER-encoded PKCS#1 public key object
+ */
+chunk_t
+pkcs1_build_public_key(const RSA_public_key_t *rsa)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "mm"
+ , asn1_integer_from_mpz(&rsa->n)
+ , asn1_integer_from_mpz(&rsa->e));
+}
+
+/*
+ * build a DER-encoded publicKeyInfo object
+ */
+chunk_t
+pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa)
+{
+ chunk_t publicKey;
+ chunk_t rawKey = pkcs1_build_public_key(rsa);
+
+ u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING
+ , 1 + rawKey.len);
+ *pos++ = 0x00;
+ mv_chunk(&pos, rawKey);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_rsaEncryption_id
+ , publicKey);
+}
+void
+free_RSA_public_content(RSA_public_key_t *rsa)
+{
+ mpz_clear(&rsa->n);
+ mpz_clear(&rsa->e);
+}
+
+void
+free_RSA_private_content(RSA_private_key_t *rsak)
+{
+ free_RSA_public_content(&rsak->pub);
+ mpz_clear(&rsak->d);
+ mpz_clear(&rsak->p);
+ mpz_clear(&rsak->q);
+ mpz_clear(&rsak->dP);
+ mpz_clear(&rsak->dQ);
+ mpz_clear(&rsak->qInv);
+}
+
diff --git a/programs/pluto/pkcs1.h b/programs/pluto/pkcs1.h
new file mode 100644
index 000000000..c927db0f8
--- /dev/null
+++ b/programs/pluto/pkcs1.h
@@ -0,0 +1,88 @@
+/* Support of PKCS#1 private key data structures
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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: pkcs1.h,v 1.14 2005/12/06 22:52:12 as Exp $
+ */
+
+#ifndef _PKCS1_H
+#define _PKCS1_H
+
+#include <gmp.h> /* GNU Multi Precision library */
+
+#include "defs.h"
+
+typedef struct RSA_public_key RSA_public_key_t;
+
+struct RSA_public_key
+{
+ char keyid[KEYID_BUF]; /* see ipsec_keyblobtoid(3) */
+
+ /* length of modulus n in octets: [RSA_MIN_OCTETS, RSA_MAX_OCTETS] */
+ unsigned k;
+
+ /* public: */
+ MP_INT
+ n, /* modulus: p * q */
+ e; /* exponent: relatively prime to (p-1) * (q-1) [probably small] */
+};
+
+typedef struct RSA_private_key RSA_private_key_t;
+
+struct RSA_private_key {
+ struct RSA_public_key pub; /* must be at start for RSA_show_public_key */
+
+ MP_INT
+ d, /* private exponent: (e^-1) mod ((p-1) * (q-1)) */
+ /* help for Chinese Remainder Theorem speedup: */
+ p, /* first secret prime */
+ q, /* second secret prime */
+ dP, /* first factor's exponent: (e^-1) mod (p-1) == d mod (p-1) */
+ dQ, /* second factor's exponent: (e^-1) mod (q-1) == d mod (q-1) */
+ qInv; /* (q^-1) mod p */
+};
+
+struct fld {
+ const char *name;
+ size_t offset;
+};
+
+extern const struct fld RSA_private_field[];
+#define RSA_PRIVATE_FIELD_ELEMENTS 8
+
+extern void init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n);
+extern bool pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key);
+extern chunk_t pkcs1_build_private_key(const RSA_private_key_t *key);
+extern chunk_t pkcs1_build_public_key(const RSA_public_key_t *rsa);
+extern chunk_t pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa);
+extern chunk_t pkcs1_build_signature(chunk_t tbs, int hash_alg
+ , const RSA_private_key_t *key, bool bit_string);
+extern bool compute_digest(chunk_t tbs, int alg, chunk_t *digest);
+extern void sign_hash(const RSA_private_key_t *k, const u_char *hash_val
+ , size_t hash_len, u_char *sig_val, size_t sig_len);
+extern chunk_t RSA_encrypt(const RSA_public_key_t *key, chunk_t in);
+extern bool RSA_decrypt(const RSA_private_key_t *key, chunk_t in
+ , chunk_t *out);
+extern bool same_RSA_public_key(const RSA_public_key_t *a
+ , const RSA_public_key_t *b);
+extern void form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize);
+extern err_t RSA_private_key_sanity(RSA_private_key_t *k);
+#ifdef DEBUG
+extern void RSA_show_public_key(RSA_public_key_t *k);
+extern void RSA_show_private_key(RSA_private_key_t *k);
+#endif
+extern void free_RSA_public_content(RSA_public_key_t *rsa);
+extern void free_RSA_private_content(RSA_private_key_t *rsak);
+
+#endif /* _PKCS1_H */
diff --git a/programs/pluto/pkcs7.c b/programs/pluto/pkcs7.c
new file mode 100644
index 000000000..0691a80d6
--- /dev/null
+++ b/programs/pluto/pkcs7.c
@@ -0,0 +1,862 @@
+/* Support of PKCS#7 data structures
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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: pkcs7.c,v 1.13 2005/12/22 22:11:24 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <crypto/des.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "asn1.h"
+#include "oid.h"
+#include "log.h"
+#include "x509.h"
+#include "certs.h"
+#include "pkcs7.h"
+#include "rnd.h"
+
+const contentInfo_t empty_contentInfo = {
+ OID_UNKNOWN , /* type */
+ { NULL, 0 } /* content */
+};
+
+/* ASN.1 definition of the PKCS#7 ContentInfo type */
+
+static const asn1Object_t contentInfoObjects[] = {
+ { 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */
+ { 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_BODY }, /* 2 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */
+};
+
+#define PKCS7_INFO_TYPE 1
+#define PKCS7_INFO_CONTENT 2
+#define PKCS7_INFO_ROOF 4
+
+/* ASN.1 definition of the PKCS#7 signedData type */
+
+static const asn1Object_t signedDataObjects[] = {
+ { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */
+ { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */
+ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
+ { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */
+ { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_LOOP }, /* 6 */
+ { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */
+ { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */
+ { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT |
+ ASN1_LOOP }, /* 9 */
+ { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
+ { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */
+ { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */
+ { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */
+ { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */
+ { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */
+ { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */
+ { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */
+ { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_OBJ }, /* 19 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
+ { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */
+ { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */
+ { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */
+ { 1, "end loop", ASN1_EOC, ASN1_END } /* 25 */
+};
+
+#define PKCS7_DIGEST_ALG 3
+#define PKCS7_SIGNED_CONTENT_INFO 5
+#define PKCS7_SIGNED_CERT 7
+#define PKCS7_SIGNER_INFO 13
+#define PKCS7_SIGNED_ISSUER 16
+#define PKCS7_SIGNED_SERIAL_NUMBER 17
+#define PKCS7_DIGEST_ALGORITHM 18
+#define PKCS7_AUTH_ATTRIBUTES 19
+#define PKCS7_DIGEST_ENC_ALGORITHM 21
+#define PKCS7_ENCRYPTED_DIGEST 22
+#define PKCS7_SIGNED_ROOF 26
+
+/* ASN.1 definition of the PKCS#7 envelopedData type */
+
+static const asn1Object_t envelopedDataObjects[] = {
+ { 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */
+ { 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */
+ { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */
+ { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
+ { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */
+ { 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */
+ { 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */
+ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
+ { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
+ { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */
+ { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */
+ { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY } /* 14 */
+};
+
+#define PKCS7_ENVELOPED_VERSION 1
+#define PKCS7_RECIPIENT_INFO_VERSION 4
+#define PKCS7_ISSUER 6
+#define PKCS7_SERIAL_NUMBER 7
+#define PKCS7_ENCRYPTION_ALG 8
+#define PKCS7_ENCRYPTED_KEY 9
+#define PKCS7_CONTENT_TYPE 12
+#define PKCS7_CONTENT_ENC_ALGORITHM 13
+#define PKCS7_ENCRYPTED_CONTENT 14
+#define PKCS7_ENVELOPED_ROOF 15
+
+/* PKCS7 contentInfo OIDs */
+
+static u_char ASN1_pkcs7_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01
+};
+
+static u_char ASN1_pkcs7_signed_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02
+};
+
+static u_char ASN1_pkcs7_enveloped_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03
+};
+
+static u_char ASN1_pkcs7_signed_enveloped_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x04
+};
+
+static u_char ASN1_pkcs7_digested_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05
+};
+
+static char ASN1_pkcs7_encrypted_data_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06
+};
+
+static const chunk_t ASN1_pkcs7_data_oid =
+ strchunk(ASN1_pkcs7_data_oid_str);
+static const chunk_t ASN1_pkcs7_signed_data_oid =
+ strchunk(ASN1_pkcs7_signed_data_oid_str);
+static const chunk_t ASN1_pkcs7_enveloped_data_oid =
+ strchunk(ASN1_pkcs7_enveloped_data_oid_str);
+static const chunk_t ASN1_pkcs7_signed_enveloped_data_oid =
+ strchunk(ASN1_pkcs7_signed_enveloped_data_oid_str);
+static const chunk_t ASN1_pkcs7_digested_data_oid =
+ strchunk(ASN1_pkcs7_digested_data_oid_str);
+static const chunk_t ASN1_pkcs7_encrypted_data_oid =
+ strchunk(ASN1_pkcs7_encrypted_data_oid_str);
+
+/* 3DES and DES encryption OIDs */
+
+static u_char ASN1_3des_ede_cbc_oid_str[] = {
+ 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07
+};
+
+static u_char ASN1_des_cbc_oid_str[] = {
+ 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x07
+};
+
+static const chunk_t ASN1_3des_ede_cbc_oid =
+ strchunk(ASN1_3des_ede_cbc_oid_str);
+static const chunk_t ASN1_des_cbc_oid =
+ strchunk(ASN1_des_cbc_oid_str);
+
+/* PKCS#7 attribute type OIDs */
+
+static u_char ASN1_contentType_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03
+};
+
+static u_char ASN1_messageDigest_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04
+};
+
+static const chunk_t ASN1_contentType_oid =
+ strchunk(ASN1_contentType_oid_str);
+static const chunk_t ASN1_messageDigest_oid =
+ strchunk(ASN1_messageDigest_oid_str);
+
+/*
+ * Parse PKCS#7 ContentInfo object
+ */
+bool
+pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < PKCS7_INFO_ROOF)
+ {
+ if (!extract_object(contentInfoObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ if (objectID == PKCS7_INFO_TYPE)
+ {
+ cInfo->type = known_oid(object);
+ if (cInfo->type < OID_PKCS7_DATA
+ || cInfo->type > OID_PKCS7_ENCRYPTED_DATA)
+ {
+ plog("unknown pkcs7 content type");
+ return FALSE;
+ }
+ }
+ else if (objectID == PKCS7_INFO_CONTENT)
+ {
+ cInfo->content = object;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/*
+ * Parse a PKCS#7 signedData object
+ */
+bool
+pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
+, chunk_t *attributes, const x509cert_t *cacert)
+{
+ u_char buf[BUF_LEN];
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int digest_alg = OID_UNKNOWN;
+ int enc_alg = OID_UNKNOWN;
+ int signerInfos = 0;
+ int objectID = 0;
+
+ contentInfo_t cInfo = empty_contentInfo;
+ chunk_t encrypted_digest = empty_chunk;
+
+ if (!pkcs7_parse_contentInfo(blob, 0, &cInfo))
+ return FALSE;
+
+ if (cInfo.type != OID_PKCS7_SIGNED_DATA)
+ {
+ plog("pkcs7 content type is not signedData");
+ return FALSE;
+ }
+
+ asn1_init(&ctx, cInfo.content, 2, FALSE, DBG_RAW);
+
+ while (objectID < PKCS7_SIGNED_ROOF)
+ {
+ if (!extract_object(signedDataObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case PKCS7_DIGEST_ALG:
+ digest_alg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case PKCS7_SIGNED_CONTENT_INFO:
+ if (data != NULL)
+ {
+ pkcs7_parse_contentInfo(object, level, data);
+ }
+ break;
+ case PKCS7_SIGNED_CERT:
+ if (cert != NULL)
+ {
+ chunk_t cert_blob;
+
+ x509cert_t *newcert = alloc_thing(x509cert_t
+ , "pkcs7 wrapped x509cert");
+
+ clonetochunk(cert_blob, object.ptr, object.len
+ , "pkcs7 cert blob");
+ *newcert = empty_x509cert;
+
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("parsing pkcs7-wrapped certificate")
+ )
+ if (parse_x509cert(cert_blob, level+1, newcert))
+ {
+ newcert->next = *cert;
+ *cert = newcert;
+ }
+ else
+ {
+ free_x509cert(newcert);
+ }
+ }
+ break;
+ case PKCS7_SIGNER_INFO:
+ signerInfos++;
+ DBG(DBG_PARSING,
+ DBG_log(" signer #%d", signerInfos)
+ )
+ break;
+ case PKCS7_SIGNED_ISSUER:
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case PKCS7_AUTH_ATTRIBUTES:
+ if (attributes != NULL)
+ {
+ *attributes = object;
+ *attributes->ptr = ASN1_SET;
+ }
+ break;
+ case PKCS7_DIGEST_ALGORITHM:
+ digest_alg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case PKCS7_DIGEST_ENC_ALGORITHM:
+ enc_alg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case PKCS7_ENCRYPTED_DIGEST:
+ encrypted_digest = object;
+ }
+ objectID++;
+ }
+
+ /* check the signature only if a cacert is available */
+ if (cacert != NULL)
+ {
+ if (signerInfos == 0)
+ {
+ plog("no signerInfo object found");
+ return FALSE;
+ }
+ else if (signerInfos > 1)
+ {
+ plog("more than one signerInfo object found");
+ return FALSE;
+ }
+ if (attributes->ptr == NULL)
+ {
+ plog("no authenticatedAttributes object found");
+ return FALSE;
+ }
+ if (!check_signature(*attributes, encrypted_digest, digest_alg
+ , enc_alg, cacert))
+ {
+ plog("invalid signature");
+ return FALSE;
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("signature is valid")
+ )
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * Parse a PKCS#7 envelopedData object
+ */
+bool
+pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
+, chunk_t serialNumber, const RSA_private_key_t *key)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ chunk_t iv = empty_chunk;
+ chunk_t symmetric_key = empty_chunk;
+ chunk_t encrypted_content = empty_chunk;
+
+ u_char buf[BUF_LEN];
+ u_int level;
+ u_int total_keys = 3;
+ int enc_alg = OID_UNKNOWN;
+ int content_enc_alg = OID_UNKNOWN;
+ int objectID = 0;
+
+ contentInfo_t cInfo = empty_contentInfo;
+ *data = empty_chunk;
+
+ if (!pkcs7_parse_contentInfo(blob, 0, &cInfo))
+ goto failed;
+
+ if (cInfo.type != OID_PKCS7_ENVELOPED_DATA)
+ {
+ plog("pkcs7 content type is not envelopedData");
+ return FALSE;
+ }
+
+ asn1_init(&ctx, cInfo.content, 2, FALSE, DBG_RAW);
+
+ while (objectID < PKCS7_ENVELOPED_ROOF)
+ {
+ if (!extract_object(envelopedDataObjects, &objectID, &object, &level, &ctx))
+ goto failed;
+
+ switch (objectID)
+ {
+ case PKCS7_ENVELOPED_VERSION:
+ if (*object.ptr != 0)
+ {
+ plog("envelopedData version is not 0");
+ goto failed;
+ }
+ break;
+ case PKCS7_RECIPIENT_INFO_VERSION:
+ if (*object.ptr != 0)
+ {
+ plog("recipient info version is not 0");
+ goto failed;
+ }
+ break;
+ case PKCS7_ISSUER:
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'", buf)
+ )
+ break;
+ case PKCS7_SERIAL_NUMBER:
+ if (!same_chunk(serialNumber, object))
+ {
+ plog("serial numbers do not match");
+ goto failed;
+ }
+ break;
+ case PKCS7_ENCRYPTION_ALG:
+ enc_alg = parse_algorithmIdentifier(object, level, NULL);
+ if (enc_alg != OID_RSA_ENCRYPTION)
+ {
+ plog("only rsa encryption supported");
+ goto failed;
+ }
+ break;
+ case PKCS7_ENCRYPTED_KEY:
+ if (!RSA_decrypt(key, object, &symmetric_key))
+ {
+ plog("symmetric key could not be decrypted with rsa");
+ goto failed;
+ }
+ DBG(DBG_PRIVATE,
+ DBG_dump_chunk("symmetric key :", symmetric_key)
+ )
+ break;
+ case PKCS7_CONTENT_TYPE:
+ if (known_oid(object) != OID_PKCS7_DATA)
+ {
+ plog("encrypted content not of type pkcs7 data");
+ goto failed;
+ }
+ break;
+ case PKCS7_CONTENT_ENC_ALGORITHM:
+ content_enc_alg = parse_algorithmIdentifier(object, level, &iv);
+
+ switch (content_enc_alg)
+ {
+ case OID_DES_CBC:
+ total_keys = 1;
+ break;
+ case OID_3DES_EDE_CBC:
+ total_keys = 3;
+ break;
+ default:
+ plog("Only DES and 3DES supported for symmetric encryption");
+ goto failed;
+ }
+ if (symmetric_key.len != (total_keys * DES_CBC_BLOCK_SIZE))
+ {
+ plog("key length is not %d",(total_keys * DES_CBC_BLOCK_SIZE));
+ goto failed;
+ }
+ if (!parse_asn1_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV"))
+ {
+ plog("IV could not be parsed");
+ goto failed;
+ }
+ if (iv.len != DES_CBC_BLOCK_SIZE)
+ {
+ plog("IV has wrong length");
+ goto failed;
+ }
+ break;
+ case PKCS7_ENCRYPTED_CONTENT:
+ encrypted_content = object;
+ break;
+ }
+ objectID++;
+ }
+
+ /* decrypt the content */
+ {
+ u_int i;
+ des_cblock des_key[3], des_iv;
+ des_key_schedule key_s[3];
+
+ memcpy((char *)des_key, symmetric_key.ptr, symmetric_key.len);
+ memcpy((char *)des_iv, iv.ptr, iv.len);
+
+ for (i = 0; i < total_keys; i++)
+ {
+ if (des_set_key(&des_key[i], key_s[i]))
+ {
+ plog("des key schedule failed");
+ goto failed;
+ }
+ }
+
+ data->len = encrypted_content.len;
+ data->ptr = alloc_bytes(data->len, "decrypted data");
+
+ switch (content_enc_alg)
+ {
+ case OID_DES_CBC:
+ des_cbc_encrypt((des_cblock*)encrypted_content.ptr
+ , (des_cblock*)data->ptr, data->len
+ , key_s[0], &des_iv, DES_DECRYPT);
+ break;
+ case OID_3DES_EDE_CBC:
+ des_ede3_cbc_encrypt( (des_cblock*)encrypted_content.ptr
+ , (des_cblock*)data->ptr, data->len
+ , key_s[0], key_s[1], key_s[2]
+ , &des_iv, DES_DECRYPT);
+ }
+ DBG(DBG_PRIVATE,
+ DBG_dump_chunk("decrypted content with padding:\n", *data)
+ )
+ }
+
+ /* remove the padding */
+ {
+ u_char *pos = data->ptr + data->len - 1;
+ u_char pattern = *pos;
+ size_t padding = pattern;
+
+ if (padding > data->len)
+ {
+ plog("padding greater than data length");
+ goto failed;
+ }
+ data->len -= padding;
+
+ while (padding-- > 0)
+ {
+ if (*pos-- != pattern)
+ {
+ plog("wrong padding pattern");
+ goto failed;
+ }
+ }
+ }
+ freeanychunk(symmetric_key);
+ return TRUE;
+
+failed:
+ freeanychunk(symmetric_key);
+ pfreeany(data->ptr);
+ return FALSE;
+}
+
+/**
+ * @brief Builds a contentType attribute
+ *
+ * @return ASN.1 encoded contentType attribute
+ */
+chunk_t
+pkcs7_contentType_attribute(void)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_contentType_oid
+ , asn1_simple_object(ASN1_SET, ASN1_pkcs7_data_oid));
+}
+
+/**
+ * @brief Builds a messageDigest attribute
+ *
+ *
+ * @param[in] blob content to create digest of
+ * @param[in] digest_alg digest algorithm to be used
+ * @return ASN.1 encoded messageDigest attribute
+ *
+ */
+chunk_t
+pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
+{
+ u_char digest_buf[MAX_DIGEST_LEN];
+ chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
+
+ compute_digest(content, digest_alg, &digest);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_messageDigest_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(ASN1_OCTET_STRING, digest)
+ )
+ );
+}
+/*
+ * build a DER-encoded contentInfo object
+ */
+static chunk_t
+pkcs7_build_contentInfo(contentInfo_t *cInfo)
+{
+ chunk_t content_type;
+
+ /* select DER-encoded OID for pkcs7 contentInfo type */
+ switch(cInfo->type)
+ {
+ case OID_PKCS7_DATA:
+ content_type = ASN1_pkcs7_data_oid;
+ break;
+ case OID_PKCS7_SIGNED_DATA:
+ content_type = ASN1_pkcs7_signed_data_oid;
+ break;
+ case OID_PKCS7_ENVELOPED_DATA:
+ content_type = ASN1_pkcs7_enveloped_data_oid;
+ break;
+ case OID_PKCS7_SIGNED_ENVELOPED_DATA:
+ content_type = ASN1_pkcs7_signed_enveloped_data_oid;
+ break;
+ case OID_PKCS7_DIGESTED_DATA:
+ content_type = ASN1_pkcs7_digested_data_oid;
+ break;
+ case OID_PKCS7_ENCRYPTED_DATA:
+ content_type = ASN1_pkcs7_encrypted_data_oid;
+ break;
+ case OID_UNKNOWN:
+ default:
+ fprintf(stderr, "invalid pkcs7 contentInfo type");
+ return empty_chunk;
+ }
+
+ return (cInfo->content.ptr == NULL)
+ ? asn1_simple_object(ASN1_SEQUENCE, content_type)
+ : asn1_wrap(ASN1_SEQUENCE, "cm"
+ , content_type
+ , asn1_simple_object(ASN1_CONTEXT_C_0, cInfo->content)
+ );
+}
+
+/*
+ * build issuerAndSerialNumber object
+ */
+chunk_t
+pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , cert->issuer
+ , asn1_simple_object(ASN1_INTEGER, cert->serialNumber));
+}
+
+/*
+ * create a signed pkcs7 contentInfo object
+ */
+chunk_t
+pkcs7_build_signedData(chunk_t data, chunk_t attributes, const x509cert_t *cert
+, int digest_alg, const RSA_private_key_t *key)
+{
+ contentInfo_t pkcs7Data, signedData;
+ chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo;
+
+ chunk_t digestAlgorithm = asn1_algorithmIdentifier(digest_alg);
+
+ if (attributes.ptr != NULL)
+ {
+ encryptedDigest = pkcs1_build_signature(attributes, digest_alg
+ , key, FALSE);
+ clonetochunk(authenticatedAttributes, attributes.ptr, attributes.len
+ , "authenticatedAttributes");
+ *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
+ }
+ else
+ {
+ encryptedDigest = (data.ptr == NULL)? empty_chunk
+ : pkcs1_build_signature(data, digest_alg, key, FALSE);
+ authenticatedAttributes = empty_chunk;
+ }
+
+ signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmcmcm"
+ , ASN1_INTEGER_1
+ , pkcs7_build_issuerAndSerialNumber(cert)
+ , digestAlgorithm
+ , authenticatedAttributes
+ , ASN1_rsaEncryption_id
+ , encryptedDigest);
+
+ pkcs7Data.type = OID_PKCS7_DATA;
+ pkcs7Data.content = (data.ptr == NULL)? empty_chunk
+ : asn1_simple_object(ASN1_OCTET_STRING, data);
+
+ signedData.type = OID_PKCS7_SIGNED_DATA;
+ signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm"
+ , ASN1_INTEGER_1
+ , asn1_simple_object(ASN1_SET, digestAlgorithm)
+ , pkcs7_build_contentInfo(&pkcs7Data)
+ , asn1_simple_object(ASN1_CONTEXT_C_0, cert->certificate)
+ , asn1_wrap(ASN1_SET, "m", signerInfo));
+
+ cInfo = pkcs7_build_contentInfo(&signedData);
+ DBG(DBG_RAW,
+ DBG_dump_chunk("signedData:\n", cInfo)
+ )
+
+ freeanychunk(pkcs7Data.content);
+ freeanychunk(signedData.content);
+ return cInfo;
+}
+
+/*
+ * create a symmetrically encrypted pkcs7 contentInfo object
+ */
+chunk_t
+pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int cipher)
+{
+ bool des_check_key_save;
+ des_key_schedule ks[3];
+ des_cblock key[3], des_iv, des_iv_buf;
+
+ chunk_t iv = { (u_char *)des_iv_buf, DES_CBC_BLOCK_SIZE };
+ chunk_t out;
+ chunk_t cipher_oid;
+
+ u_int total_keys, i;
+ size_t padding = pad_up(data.len, DES_CBC_BLOCK_SIZE);
+
+ RSA_public_key_t public_key;
+
+ init_RSA_public_key(&public_key, cert->publicExponent
+ , cert->modulus);
+
+ if (padding == 0)
+ padding += DES_CBC_BLOCK_SIZE;
+
+ out.len = data.len + padding;
+ out.ptr = alloc_bytes(out.len, "DES-encrypted output");
+
+ DBG(DBG_CONTROL,
+ DBG_log("padding %d bytes of data to multiple DES block size of %d bytes"
+ , (int)data.len, (int)out.len)
+ )
+
+ /* copy data */
+ memcpy(out.ptr, data.ptr, data.len);
+ /* append padding */
+ memset(out.ptr + data.len, padding, padding);
+
+ DBG(DBG_RAW,
+ DBG_dump_chunk("Padded unencrypted data:\n", out)
+ )
+
+ /* select OID and keylength for specified cipher */
+ switch (cipher)
+ {
+ case OID_DES_CBC:
+ total_keys = 1;
+ cipher_oid = ASN1_des_cbc_oid;
+ break;
+ case OID_3DES_EDE_CBC:
+ default:
+ total_keys = 3;
+ cipher_oid = ASN1_3des_ede_cbc_oid;
+ }
+ DBG(DBG_CONTROLMORE,
+ DBG_log("pkcs7 encryption cipher: %s", oid_names[cipher].name)
+ )
+
+ /* generate a strong random key for DES/3DES */
+ des_check_key_save = des_check_key;
+ des_check_key = TRUE;
+ for (i = 0; i < total_keys;i++)
+ {
+ for (;;)
+ {
+ get_rnd_bytes((char*)key[i], DES_CBC_BLOCK_SIZE);
+ des_set_odd_parity(&key[i]);
+ if (!des_set_key(&key[i], ks[i]))
+ break;
+ plog("weak DES key discarded - we try again");
+ }
+ DBG(DBG_PRIVATE,
+ DBG_dump("DES key:", key[i], 8)
+ )
+ }
+ des_check_key = des_check_key_save;
+
+ /* generate an iv for DES/3DES CBC */
+ get_rnd_bytes(des_iv, DES_CBC_BLOCK_SIZE);
+ memcpy(iv.ptr, des_iv, DES_CBC_BLOCK_SIZE);
+ DBG(DBG_RAW,
+ DBG_dump_chunk("DES IV :", iv)
+ )
+
+ /* encryption using specified cipher */
+ switch (cipher)
+ {
+ case OID_DES_CBC:
+ des_cbc_encrypt((des_cblock*)out.ptr, (des_cblock*)out.ptr, out.len
+ , ks[0], &des_iv, DES_ENCRYPT);
+ break;
+ case OID_3DES_EDE_CBC:
+ default:
+ des_ede3_cbc_encrypt((des_cblock*)out.ptr, (des_cblock*)out.ptr, out.len
+ , ks[0], ks[1], ks[2], &des_iv, DES_ENCRYPT);
+ }
+ DBG(DBG_RAW,
+ DBG_dump_chunk("Encrypted data:\n", out));
+
+ /* build pkcs7 enveloped data object */
+ {
+ chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , cipher_oid
+ , asn1_simple_object(ASN1_OCTET_STRING, iv));
+
+ chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "cmm"
+ , ASN1_pkcs7_data_oid
+ , contentEncryptionAlgorithm
+ , asn1_wrap(ASN1_CONTEXT_S_0, "m", out));
+
+ chunk_t plainKey = { (u_char *)key, DES_CBC_BLOCK_SIZE * total_keys };
+
+ chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m"
+ , RSA_encrypt(&public_key, plainKey));
+
+ chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm"
+ , ASN1_INTEGER_0
+ , pkcs7_build_issuerAndSerialNumber(cert)
+ , ASN1_rsaEncryption_id
+ , encryptedKey);
+
+ chunk_t cInfo;
+ contentInfo_t envelopedData;
+
+ envelopedData.type = OID_PKCS7_ENVELOPED_DATA;
+ envelopedData.content = asn1_wrap(ASN1_SEQUENCE, "cmm"
+ , ASN1_INTEGER_0
+ , asn1_wrap(ASN1_SET, "m", recipientInfo)
+ , encryptedContentInfo);
+
+ cInfo = pkcs7_build_contentInfo(&envelopedData);
+ DBG(DBG_RAW,
+ DBG_dump_chunk("envelopedData:\n", cInfo)
+ )
+
+ free_RSA_public_content(&public_key);
+ freeanychunk(envelopedData.content);
+ return cInfo;
+ }
+}
diff --git a/programs/pluto/pkcs7.h b/programs/pluto/pkcs7.h
new file mode 100644
index 000000000..38c633f4e
--- /dev/null
+++ b/programs/pluto/pkcs7.h
@@ -0,0 +1,51 @@
+/* Support of PKCS#7 data structures
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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: pkcs7.h,v 1.10 2005/12/22 22:11:24 as Exp $
+ */
+
+#ifndef _PKCS7_H
+#define _PKCS7_H
+
+#include "defs.h"
+#include "pkcs1.h"
+#include "x509.h"
+
+/* Access structure for a PKCS#7 ContentInfo object */
+
+typedef struct contentInfo contentInfo_t;
+
+struct contentInfo {
+ int type;
+ chunk_t content;
+};
+
+extern const contentInfo_t empty_contentInfo;
+
+extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0
+ , contentInfo_t *cInfo);
+extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data
+ , x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert);
+extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
+ , chunk_t serialNumber, const RSA_private_key_t *key);
+extern chunk_t pkcs7_contentType_attribute(void);
+extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg);
+extern chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert);
+extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes
+ ,const x509cert_t *cert, int digest_alg, const RSA_private_key_t *key);
+extern chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert
+ , int cipher);
+
+#endif /* _PKCS7_H */
diff --git a/programs/pluto/pluto-style.el b/programs/pluto/pluto-style.el
new file mode 100644
index 000000000..0de474e44
--- /dev/null
+++ b/programs/pluto/pluto-style.el
@@ -0,0 +1,4 @@
+(c-add-style "pluto" '("bsd"
+ (c-basic-offset . 4)
+ (c-offsets-alias . ((substatement-open . 0)))))
+
diff --git a/programs/pluto/pluto.8 b/programs/pluto/pluto.8
new file mode 100644
index 000000000..b80d13772
--- /dev/null
+++ b/programs/pluto/pluto.8
@@ -0,0 +1,1649 @@
+.TH IPSEC_PLUTO 8 "28 March 1999"
+.SH NAME
+ipsec pluto \- IPsec IKE keying daemon
+.br
+ipsec whack \- control interface for IPSEC keying daemon
+.SH SYNOPSIS
+.na
+.nh
+.HP
+.ft B
+ipsec pluto
+[\-\-help]
+[\-\-version]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-nofork]
+[\-\-stderrlog]
+[\-\-noklips]
+[\-\-uniqueids]
+[\fB\-\-interface\fP \fIinterfacename\fP]
+[\-\-ikeport\ \c
+\fIportnumber\fP]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-secretsfile\ \c
+\fIsecrets\(hyfile\fP]
+[\-\-adns \fIpathname\fP]
+[\-\-lwdnsq \fIpathname\fP]
+[\-\-perpeerlog]
+[\-\-perpeerlogbase\ \c
+\fIdirname\fP]
+[\-\-debug\(hynone]
+[\-\-debug\(hyall]
+[\-\-debug\(hyraw]
+[\-\-debug\(hycrypt]
+[\-\-debug\(hyparsing]
+[\-\-debug\(hyemitting]
+[\-\-debug\(hycontrol]
+[\-\-debug\(hylifecycle]
+[\-\-debug\(hyklips]
+[\-\-debug\(hydns]
+[\-\-debug\(hyoppo]
+[\-\-debug\(hyprivate]
+.HP
+.ft B
+ipsec whack
+[\-\-help]
+[\-\-version]
+.HP
+.ft B
+ipsec whack
+\-\-name\ \c
+\fIconnection-name\fP
+.br
+[\-\-id\ \c
+\fIid\fP] \c
+[\-\-host\ \c
+\fIip\(hyaddress\fP]
+[\-\-ikeport\ \c
+\fIport\(hynumber\fP]
+[\-\-nexthop\ \c
+\fIip\(hyaddress\fP]
+[\-\-client\ \c
+\fIsubnet\fP]
+[\-\-dnskeyondemand]
+[\-\-updown\ \c
+\fIupdown\fP]
+.br
+\-\-to
+.br
+[\-\-id\ \c
+\fIid\fP]
+[\-\-host\ \c
+\fIip\(hyaddress\fP]
+[\-\-ikeport\ \c
+\fIport\(hynumber\fP]
+[\-\-nexthop\ \c
+\fIip\(hyaddress\fP]
+[\-\-client\ \c
+\fIsubnet\fP]
+[\-\-dnskeyondemand]
+[\-\-updown\ \c
+\fIupdown\fP]
+.br
+[\-\-psk]
+[\-\-rsasig]
+[\-\-encrypt]
+[\-\-authenticate]
+[\-\-compress]
+[\-\-tunnel]
+[\-\-pfs]
+[\-\-disablearrivalcheck]
+[\-\-ipv4]
+[\-\-ipv6]
+[\-\-tunnelipv4]
+[\-\-tunnelipv6]
+[\-\-ikelifetime\ \c
+\fIseconds\fP]
+[\-\-ipseclifetime\ \c
+\fIseconds\fP]
+[\-\-rekeymargin\ \c
+\fIseconds\fP]
+[\-\-rekeyfuzz\ \c
+\fIpercentage\fP]
+[\-\-keyingtries\ \c
+\fIcount\fP]
+[\-\-dontrekey]
+[\-\-delete]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-keyid\ \c
+\fIid\fP
+[\-\-addkey]
+[\-\-pubkeyrsa\ \c
+\fIkey\fP]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-myid\ \c
+\fIid\fP
+.HP
+.ft B
+ipsec whack
+\-\-listen|\-\-unlisten
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-route|\-\-unroute
+\-\-name\ \c
+\fIconnection-name\fP
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-initiate|\-\-terminate
+\-\-name\ \c
+\fIconnection-name\fP
+[\-\-asynchronous]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+[\-\-tunnelipv4]
+[\-\-tunnelipv6]
+\-\-oppohere \fIip\(hyaddress\fP
+\-\-oppothere \fIip\(hyaddress\fP
+.HP
+.ft B
+ipsec whack
+\-\-delete
+\-\-name\ \c
+\fIconnection-name\fP
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-deletestate\ \c
+\fIstate-number\fP
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+[\-\-name\ \c
+\fIconnection-name\fP]
+[\-\-debug\(hynone]
+[\-\-debug\(hyall]
+[\-\-debug\(hyraw]
+[\-\-debug\(hycrypt]
+[\-\-debug\(hyparsing]
+[\-\-debug\(hyemitting]
+[\-\-debug\(hycontrol]
+[\-\-debug\(hylifecycle]
+[\-\-debug\(hyklips]
+[\-\-debug\(hydns]
+[\-\-debug\(hyoppo]
+[\-\-debug\(hyprivate]
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-status
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.HP
+.ft B
+ipsec whack
+\-\-shutdown
+[\-\-ctlbase\ \c
+\fIpath\fP]
+[\-\-optionsfrom\ \c
+\fIfilename\fP]
+[\-\-label\ \c
+\fIstring\fP]
+.ft R
+.hy
+.ad
+.SH DESCRIPTION
+.BR pluto
+is an IKE (``IPsec Key Exchange'') daemon.
+.BR whack
+is an auxiliary program to allow requests to be made to a running
+.BR pluto .
+.LP
+.BR pluto
+is used to automatically build shared ``security associations'' on a
+system that has IPsec, the secure IP protocol.
+In other words,
+.BR pluto
+can eliminate much of the work of manual keying.
+The actual
+secure transmission of packets is the responsibility of other parts of
+the system (see
+.BR KLIPS ,
+the companion implementation of IPsec).
+\fIipsec_auto\fP(8) provides a more convenient interface to
+\fBpluto\fP and \fBwhack\fP.
+.SS IKE's Job
+.LP
+A \fISecurity Association\fP (\fISA\fP) is an agreement between two network nodes on
+how to process certain traffic between them. This processing involves
+encapsulation, authentication, encryption, or compression.
+.LP
+IKE can be deployed on a network node to negotiate Security
+Associations for that node. These IKE implementations can only
+negotiate with other IKE implementations, so IKE must be on each node
+that is to be an endpoint of an IKE-negotiated Security Association.
+No other nodes need to be running IKE.
+.LP
+An IKE instance (i.e. an IKE implementation on a particular network
+node) communicates with another IKE instance using UDP IP packets, so
+there must be a route between the nodes in each direction.
+.LP
+The negotiation of Security Associations requires a number of choices
+that involve tradeoffs between security, convenience, trust, and
+efficiency. These are policy issues and are normally specified to the
+IKE instance by the system administrator.
+.LP
+IKE deals with two kinds of Security Associations. The first part of
+a negotiation between IKE instances is to build an ISAKMP SA. An
+ISAKMP SA is used to protect communication between the two IKEs.
+IPsec SAs can then be built by the IKEs \- these are used to carry
+protected IP traffic between the systems.
+.LP
+The negotiation of the ISAKMP SA is known as Phase 1. In theory,
+Phase 1 can be accomplished by a couple of different exchange types,
+but we only implement one called Main Mode (we don't implement
+Aggressive Mode).
+.LP
+Any negotiation under the protection of an ISAKMP SA, including the
+negotiation of IPsec SAs, is part of Phase 2. The exchange type
+that we use to negotiate an IPsec SA is called Quick Mode.
+.LP
+IKE instances must be able to authenticate each other as part of their
+negotiation of an ISAKMP SA. This can be done by several mechanisms
+described in the draft standards.
+.LP
+IKE negotiation can be initiated by any instance with any other. If
+both can find an agreeable set of characteristics for a Security
+Association, and both recognize each others authenticity, they can set
+up a Security Association. The standards do not specify what causes
+an IKE instance to initiate a negotiation.
+.LP
+In summary, an IKE instance is prepared to automate the management of
+Security Associations in an IPsec environment, but a number of issues
+are considered policy and are left in the system administrator's hands.
+.SS Pluto
+.LP
+\fBpluto\fP is an implementation of IKE. It runs as a daemon on a network
+node. Currently, this network node must be a LINUX system running the
+\fBKLIPS\fP implementation of IPsec.
+.LP
+\fBpluto\fP only implements a subset of IKE. This is enough for it to
+interoperate with other instances of \fBpluto\fP, and many other IKE
+implementations. We are working on implementing more of IKE.
+.LP
+The policy for acceptable characteristics for Security Associations is
+mostly hardwired into the code of \fBpluto\fP (spdb.c). Eventually
+this will be moved into a security policy database with reasonable
+expressive power and more convenience.
+.LP
+\fBpluto\fP uses shared secrets or RSA signatures to authenticate
+peers with whom it is negotiating.
+.LP
+\fBpluto\fP initiates negotiation of a Security Association when it is
+manually prodded: the program \fBwhack\fP is run to trigger this.
+It will also initiate a negotiation when \fBKLIPS\fP traps an outbound packet
+for Opportunistic Encryption.
+.LP
+\fBpluto\fP implements ISAKMP SAs itself. After it has negotiated the
+characteristics of an IPsec SA, it directs \fBKLIPS\fP to implement it.
+It also invokes a script to adjust any firewall and issue \fIroute\fP(8)
+commands to direct IP packets through \fBKLIPS\fP.
+.LP
+When \fBpluto\fP shuts down, it closes all Security Associations.
+.SS Before Running Pluto
+.LP
+\fBpluto\fP runs as a daemon with userid root. Before running it, a few
+things must be set up.
+.LP
+\fBpluto\fP requires \fBKLIPS\fP, the FreeS/WAN implementation of IPsec.
+All of the components of \fBKLIPS\fP and \fBpluto\fP should be installed.
+.LP
+\fBpluto\fP supports multiple public networks (that is, networks
+that are considered insecure and thus need to have their traffic
+encrypted or authenticated). It discovers the
+public interfaces to use by looking at all interfaces that are
+configured (the \fB\-\-interface\fP option can be used to limit
+the interfaces considered).
+It does this only when \fBwhack\fP tells it to \-\-listen,
+so the interfaces must be configured by then. Each interface with a name of the form
+\fBipsec\fP[\fB0\fP-\fB9\fP] is taken as a \fBKLIPS\fP virtual public interface.
+Another network interface with the same IP address (there should be only
+one) is taken as the corresponding real public
+interface. \fIifconfig\fP(8) with the \fB\-a\fP flag will show
+the name and status of each network interface.
+.LP
+\fBpluto\fP requires a database of preshared secrets and RSA private keys.
+This is described in the
+.IR ipsec.secrets (5).
+\fBpluto\fP is told of RSA public keys via \fBwhack\fP commands.
+If the connection is Opportunistic, and no RSA public key is known,
+\fBpluto\fP will attempt to fetch RSA keys using the Domain Name System.
+.SS Setting up \fBKLIPS\fP for \fBpluto\fP
+.LP
+The most basic network topology that \fBpluto\fP supports has two security
+gateways negotiating on behalf of client subnets. The diagram of RGB's
+testbed is a good example (see \fIklips/doc/rgb_setup.txt\fP).
+.LP
+The file \fIINSTALL\fP in the base directory of this distribution
+explains how to start setting up the whole system, including \fBKLIPS\fP.
+.LP
+Make sure that the security gateways have routes to each other. This
+is usually covered by the default route, but may require issuing
+.IR route (8)
+commands. The route must go through a particular IP
+interface (we will assume it is \fIeth0\fP, but it need not be). The
+interface that connects the security gateway to its client must be a
+different one.
+.LP
+It is necessary to issue a
+.IR ipsec_tncfg (8)
+command on each gateway. The required command is:
+
+\ \ \ ipsec tncfg \-\-attach\ \-\-virtual\ ipsec0 \-\-physical\ eth0
+
+A command to set up the ipsec0 virtual interface will also need to be
+run. It will have the same parameters as the command used to set up
+the physical interface to which it has just been connected using
+.IR ipsec_tncfg (8).
+.SS ipsec.secrets file
+.LP
+A \fBpluto\fP daemon and another IKE daemon (for example, another instance
+of \fBpluto\fP) must convince each other that they are who they are supposed
+to be before any negotiation can succeed. This authentication is
+accomplished by using either secrets that have been shared beforehand
+(manually) or by using RSA signatures. There are other techniques,
+but they have not been implemented in \fBpluto\fP.
+.LP
+The file \fI/etc/ipsec.secrets\fP is used to keep preshared secret keys
+and RSA private keys for
+authentication with other IKE daemons. For debugging, there is an
+argument to the \fBpluto\fP command to use a different file.
+This file is described in
+.IR ipsec.secrets (5).
+.SS Running Pluto
+.LP
+To fire up the daemon, just type \fBpluto\fP (be sure to be running as
+the superuser).
+The default IKE port number is 500, the UDP port assigned by IANA for IKE Daemons.
+\fBpluto\fP must be run by the superuser to be able to use the UDP 500 port.
+.LP
+\fBpluto\fP attempts to create a lockfile with the name
+\fI/var/run/pluto.pid\fP. If the lockfile cannot be created,
+\fBpluto\fP exits \- this prevents multiple \fBpluto\fPs from
+competing Any ``leftover'' lockfile must be removed before
+\fBpluto\fP will run. \fBpluto\fP writes its pid into this file so
+that scripts can find it. This lock will not function properly if it
+is on an NFS volume (but sharing locks on multiple machines doesn't
+make sense anyway).
+.LP
+\fBpluto\fP then forks and the parent exits. This is the conventional
+``daemon fork''. It can make debugging awkward, so there is an option
+to suppress this fork.
+.LP
+All logging, including diagnostics, is sent to
+.IR syslog (3)
+with facility=authpriv;
+it decides where to put these messages (possibly in /var/log/secure).
+Since this too can make debugging awkward, there is an option to
+steer logging to stderr.
+.LP
+If the \fB\-\-perpeerlog\fP option is given, then pluto will open
+a log file per connection. By default, this is in /var/log/pluto/peer,
+in a subdirectory formed by turning all dot (.) [IPv4} or colon (:)
+[IPv6] into slashes (/).
+.LP
+The base directory can be changed with the \fB\-\-perpeerlogbase\fP.
+.LP
+Once \fBpluto\fP is started, it waits for requests from \fBwhack\fP.
+.SS Pluto's Internal State
+.LP
+To understand how to use \fBpluto\fP, it is helpful to understand a little
+about its internal state. Furthermore, the terminology is needed to decipher
+some of the diagnostic messages.
+.LP
+The \fI(potential) connection\fP database describes attributes of a
+connection. These include the IP addresses of the hosts and client
+subnets and the security characteristics desired. \fBpluto\fP
+requires this information (simply called a connection) before it can
+respond to a request to build an SA. Each connection is given a name
+when it is created, and all references are made using this name.
+.LP
+During the IKE exchange to build an SA, the information about the
+negotiation is represented in a \fIstate object\fP. Each state object
+reflects how far the negotiation has reached. Once the negotiation is
+complete and the SA established, the state object remains to represent
+the SA. When the SA is terminated, the state object is discarded.
+Each State object is given a serial number and this is used to refer
+to the state objects in logged messages.
+.LP
+Each state object corresponds to a connection and can be thought of
+as an instantiation of that connection.
+At any particular time, there may be any number of state objects
+corresponding to a particular connection.
+Often there is one representing an ISAKMP SA and another representing
+an IPsec SA.
+.LP
+\fBKLIPS\fP hooks into the routing code in a LINUX kernel.
+Traffic to be processed by an IPsec SA must be directed through
+\fBKLIPS\fP by routing commands. Furthermore, the processing to be
+done is specified by \fIipsec eroute(8)\fP commands.
+\fBpluto\fP takes the responsibility of managing both of these special
+kinds of routes.
+.LP
+Each connection may be routed, and must be while it has an IPsec SA.
+The connection specifies the characteristics of the route: the
+interface on this machine, the ``gateway'' (the nexthop),
+and the peer's client subnet. Two
+connections may not be simultaneously routed if they are for the same
+peer's client subnet but use different interfaces or gateways
+(\fBpluto\fP's logic does not reflect any advanced routing capabilities).
+.LP
+Each eroute is associated with the state object for an IPsec SA
+because it has the particular characteristics of the SA.
+Two eroutes conflict if they specify the identical local
+and remote clients (unlike for routes, the local clients are
+taken into account).
+.LP
+When \fBpluto\fP needs to install a route for a connection,
+it must make sure that no conflicting route is in use. If another
+connection has a conflicting route, that route will be taken down, as long
+as there is no IPsec SA instantiating that connection.
+If there is such an IPsec SA, the attempt to install a route will fail.
+.LP
+There is an exception. If \fBpluto\fP, as Responder, needs to install
+a route to a fixed client subnet for a connection, and there is
+already a conflicting route, then the SAs using the route are deleted
+to make room for the new SAs. The rationale is that the new
+connection is probably more current. The need for this usually is a
+product of Road Warrior connections (these are explained later; they
+cannot be used to initiate).
+.LP
+When \fBpluto\fP needs to install an eroute for an IPsec SA (for a
+state object), first the state object's connection must be routed (if
+this cannot be done, the eroute and SA will not be installed).
+If a conflicting eroute is already in place for another connection,
+the eroute and SA will not be installed (but note that the routing
+exception mentioned above may have already deleted potentially conflicting SAs).
+If another IPsec
+SA for the same connection already has an eroute, all its outgoing traffic
+is taken over by the new eroute. The incoming traffic will still be
+processed. This characteristic is exploited during rekeying.
+.LP
+All of these routing characteristics are expected change when
+\fBKLIPS\fP is modified to use the firewall hooks in the LINUX 2.4.x
+kernel.
+.SS Using Whack
+.LP
+\fBwhack\fP is used to command a running \fBpluto\fP.
+\fBwhack\fP uses a UNIX domain socket to speak to \fBpluto\fP
+(by default, \fI/var/pluto.ctl\fP).
+.LP
+\fBwhack\fP has an intricate argument syntax.
+This syntax allows many different functions to be specified.
+The help form shows the usage or version information.
+The connection form gives \fBpluto\fP a description of a potential connection.
+The public key form informs \fBpluto\fP of the RSA public key for a potential peer.
+The delete form deletes a connection description and all SAs corresponding
+to it.
+The listen form tells \fBpluto\fP to start or stop listening on the public interfaces
+for IKE requests from peers.
+The route form tells \fBpluto\fP to set up routing for a connection;
+the unroute form undoes this.
+The initiate form tells \fBpluto\fP to negotiate an SA corresponding to a connection.
+The terminate form tells \fBpluto\fP to remove all SAs corresponding to a connection,
+including those being negotiated.
+The status form displays the \fBpluto\fP's internal state.
+The debug form tells \fBpluto\fP to change the selection of debugging output
+``on the fly''. The shutdown form tells
+\fBpluto\fP to shut down, deleting all SAs.
+.LP
+Most options are specific to one of the forms, and will be described
+with that form. There are three options that apply to all forms.
+.TP
+\fB\-\-ctlbase\fP\ \fIpath\fP
+\fIpath\fP.ctl is used as the UNIX domain socket for talking
+to \fBpluto\fP.
+This option facilitates debugging.
+.TP
+\fB\-\-optionsfrom\fP\ \fIfilename\fP
+adds the contents of the file to the argument list.
+.TP
+\fB\-\-label\fP\ \fIstring\fP
+adds the string to all error messages generated by \fBwhack\fP.
+.LP
+The help form of \fBwhack\fP is self-explanatory.
+.TP
+\fB\-\-help\fP
+display the usage message.
+.TP
+\fB\-\-version\fP
+display the version of \fBwhack\fP.
+.LP
+The connection form describes a potential connection to \fBpluto\fP.
+\fBpluto\fP needs to know what connections can and should be negotiated.
+When \fBpluto\fP is the initiator, it needs to know what to propose.
+When \fBpluto\fP is the responder, it needs to know enough to decide whether
+is is willing to set up the proposed connection.
+.LP
+The description of a potential connection can specify a large number
+of details. Each connection has a unique name. This name will appear
+in a updown shell command, so it should not contain punctuation
+that would make the command ill-formed.
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The topology of
+a connection is symmetric, so to save space here is half a picture:
+
+\ \ \ client_subnet<\-\->host:ikeport<\-\->nexthop<\-\-\-
+
+A similar trick is used in the flags. The same flag names are used for
+both ends. Those before the \fB\-\-to\fP flag describe the left side
+and those afterwards describe the right side. When \fBpluto\fP attempts
+to use the connection, it decides whether it is the left side or the right
+side of the connection, based on the IP numbers of its interfaces.
+.TP
+\fB\-\-id\fP\ \fIid\fP
+the identity of the end. Currently, this can be an IP address (specified
+as dotted quad or as a Fully Qualified Domain Name, which will be resolved
+immediately) or as a Fully Qualified Domain Name itself (prefixed by ``@''
+to signify that it should not be resolved), or as user@FQDN, or as the
+magic value \fB%myid\fP.
+\fBPluto\fP only authenticates the identity, and does not use it for
+addressing, so, for example, an IP address need not be the one to which
+packets are to be sent. If the option is absent, the
+identity defaults to the IP address specified by \fB\-\-host\fP.
+\fB%myid\fP allows the identity to be separately specified (by the \fBpluto\fP or \fBwhack\fP option \fB\-\-myid\fP
+or by the \fBipsec.conf\fP(5) \fBconfig setup\fP parameter \fPmyid\fP).
+Otherwise, \fBpluto\fP tries to guess what \fB%myid\fP should stand for:
+the IP address of \fB%defaultroute\fP, if it is supported by a suitable TXT record in the reverse domain for that IP address,
+or the system's hostname, if it is supported by a suitable TXT record in its forward domain.
+.\" The identity is transmitted in the IKE protocol, and is what is authenticated.
+.TP
+\fB\-\-host\fP\ \fIip\(hyaddress\fP
+.TP
+\fB\-\-host\fP\ \fB%any\fP
+.TP
+\fB\-\-host\fP\ \fB%opportunistic\fP
+the IP address of the end (generally the public interface).
+If \fBpluto\fP is to act as a responder
+for IKE negotiations initiated from unknown IP addresses (the
+``Road Warrior'' case), the
+IP address should be specified as \fB%any\fP (currently,
+the obsolete notation \fB0.0.0.0\fP is also accepted for this).
+If \fBpluto\fP is to opportunistically initiate the connection,
+use \fB%opportunistic\fP
+.TP
+\fB\-\-ikeport\fP\ \fIport\(hynumber\fP
+the UDP port that IKE listens to on that host. The default is 500.
+(\fBpluto\fP on this machine uses the port specified by its own command
+line argument, so this only affects where \fBpluto\fP sends messages.)
+.TP
+\fB\-\-nexthop\fP\ \fIip\(hyaddress\fP
+where to route packets for the peer's client (presumably for the peer too,
+but it will not be used for this).
+When \fBpluto\fP installs an IPsec SA, it issues a route command.
+It uses the nexthop as the gateway.
+The default is the peer's IP address (this can be explicitly written as
+\fB%direct\fP; the obsolete notation \fB0.0.0.0\fP is accepted).
+This option is necessary if \fBpluto\fP's host's interface used for sending
+packets to the peer is neither point-to-point nor directly connected to the
+peer.
+.TP
+\fB\-\-client\fP\ \fIsubnet\fP
+the subnet for which the IPsec traffic will be destined. If not specified,
+the host will be the client.
+The subnet can be specified in any of the forms supported by \fIipsec_atosubnet\fP(3).
+The general form is \fIaddress\fP/\fImask\fP. The \fIaddress\fP can be either
+a domain name or four decimal numbers (specifying octets) separated by dots.
+The most convenient form of the \fImask\fP is a decimal integer, specifying
+the number of leading one bits in the mask. So, for example, 10.0.0.0/8
+would specify the class A network ``Net 10''.
+.TP
+\fB\-\-dnskeyondemand]\fP
+specifies that when an RSA public key is needed to authenticate this
+host, and it isn't already known, fetch it from DNS.
+.TP
+\fB\-\-updown\fP\ \fIupdown\fP
+specifies an external shell command to be run whenever \fBpluto\fP
+brings up or down a connection.
+The script is used to build a shell command, so it may contain positional
+parameters, but ought not to have punctuation that would cause the
+resulting command to be ill-formed.
+The default is \fIipsec _updown\fP.
+.TP
+\fB\-\-to\fP
+separates the specification of the left and right ends of the connection.
+.LP
+The potential connection description also specifies characteristics of
+rekeying and security.
+.TP
+\fB\-\-psk\fP
+Propose and allow preshared secret authentication for IKE peers. This authentication
+requires that each side use the same secret. May be combined with \fB\-\-rsasig\fP;
+at least one must be specified.
+.TP
+\fB\-\-rsasig\fP
+Propose and allow RSA signatures for authentication of IKE peers. This authentication
+requires that each side have have a private key of its own and know the
+public key of its peer. May be combined with \fB\-\-psk\fP;
+at least one must be specified.
+.TP
+\fB\-\-encrypt\fP
+All proposed or accepted IPsec SAs will include non-null ESP.
+The actual choices of transforms are wired into \fBpluto\fP.
+.TP
+\fB\-\-authenticate\fP
+All proposed IPsec SAs will include AH.
+All accepted IPsec SAs will include AH or ESP with authentication.
+The actual choices of transforms are wired into \fBpluto\fP.
+Note that this has nothing to do with IKE authentication.
+.TP
+\fB\-\-compress\fP
+All proposed IPsec SAs will include IPCOMP (compression).
+This will be ignored if KLIPS is not configured with IPCOMP support.
+.TP
+\fB\-\-tunnel\fP
+the IPsec SA should use tunneling. Implicit if the SA is for clients.
+Must only be used with \fB\-\-authenticate\fP or \fB\-\-encrypt\fP.
+.TP
+\fB\-\-ipv4\fP
+The host addresses will be interpreted as IPv4 addresses. This is the
+default. Note that for a connection, all host addresses must be of
+the same Address Family (IPv4 and IPv6 use different Address Families).
+.TP
+\fB\-\-ipv6\fP
+The host addresses (including nexthop) will be interpreted as IPv6 addresses.
+Note that for a connection, all host addresses must be of
+the same Address Family (IPv4 and IPv6 use different Address Families).
+.TP
+\fB\-\-tunnelipv4\fP
+The client addresses will be interpreted as IPv4 addresses. The default is
+to match what the host will be. This does not imply \fB\-\-tunnel\fP so the
+flag can be safely used when no tunnel is actually specified.
+Note that for a connection, all tunnel addresses must be of the same
+Address Family.
+.TP
+\fB\-\-tunnelipv6\fP
+The client addresses will be interpreted as IPv6 addresses. The default is
+to match what the host will be. This does not imply \fB\-\-tunnel\fP so the
+flag can be safely used when no tunnel is actually specified.
+Note that for a connection, all tunnel addresses must be of the same
+Address Family.
+.TP
+\fB\-\-pfs\fP
+There should be Perfect Forward Secrecy \- new keying material will
+be generated for each IPsec SA rather than being derived from the ISAKMP
+SA keying material.
+Since the group to be used cannot be negotiated (a dubious feature of the
+standard), \fBpluto\fP will propose the same group that was used during Phase 1.
+We don't implement a stronger form of PFS which would require that the
+ISAKMP SA be deleted after the IPSEC SA is negotiated.
+.TP
+\fB\-\-disablearrivalcheck\fP
+If the connection is a tunnel, allow packets arriving through the tunnel
+to have any source and destination addresses.
+.LP
+If none of the \fB\-\-encrypt\fP, \fB\-\-authenticate\fP, \fB\-\-compress\fP,
+or \fB\-\-pfs\fP flags is given, the initiating the connection will
+only build an ISAKMP SA. For such a connection, client subnets have
+no meaning and must not be specified.
+.LP
+More work is needed to allow for flexible policies. Currently
+policy is hardwired in the source file spdb.c. The ISAKMP SAs may use
+Oakley groups MODP1024 and MODP1536; 3DES encryption; SHA1-96
+and MD5-96 authentication. The IPsec SAs may use 3DES and
+MD5-96 or SHA1-96 for ESP, or just MD5-96 or SHA1-96 for AH.
+IPCOMP Compression is always Deflate.
+.TP
+\fB\-\-ikelifetime\fP\ \fIseconds\fP
+how long \fBpluto\fP will propose that an ISAKMP SA be allowed to live.
+The default is 10800 (three hours) and the maximum is 86400 (one day).
+This option will not affect what is accepted.
+\fBpluto\fP will reject proposals that exceed the maximum.
+.TP
+\fB\-\-ipseclifetime\fP\ \fIseconds\fP
+how long \fBpluto\fP will propose that an IPsec SA be allowed to live.
+The default is 3600 (one hour) and the maximum is 86400 (one day).
+This option will not affect what is accepted.
+\fBpluto\fP will reject proposals that exceed the maximum.
+.TP
+\fB\-\-rekeymargin\fP\ \fIseconds\fP
+how long before an SA's expiration should \fBpluto\fP try to negotiate
+a replacement SA. This will only happen if \fBpluto\fP was the initiator.
+The default is 540 (nine minutes).
+.TP
+\fB\-\-rekeyfuzz\fP\ \fIpercentage\fP
+maximum size of random component to add to rekeymargin, expressed as
+a percentage of rekeymargin. \fBpluto\fP will select a delay uniformly
+distributed within this range. By default, the percentage will be 100.
+If greater determinism is desired, specify 0. It may be appropriate
+for the percentage to be much larger than 100.
+.TP
+\fB\-\-keyingtries\fP\ \fIcount\fP
+how many times \fBpluto\fP should try to negotiate an SA,
+either for the first time or for rekeying.
+A value of 0 is interpreted as a very large number: never give up.
+The default is three.
+.TP
+\fB\-\-dontrekey\fP
+A misnomer.
+Only rekey a connection if we were the Initiator and there was recent
+traffic on the existing connection.
+This applies to Phase 1 and Phase 2.
+This is currently the only automatic way for a connection to terminate.
+It may be useful with Road Warrior or Opportunistic connections.
+.br
+Since SA lifetime negotiation is take-it-or-leave it, a Responder
+normally uses the shorter of the negotiated or the configured lifetime.
+This only works because if the lifetime is shorter than negotiated,
+the Responder will rekey in time so that everything works.
+This interacts badly with \fB\-\-dontrekey\fP. In this case,
+the Responder will end up rekeying to rectify a shortfall in an IPsec SA
+lifetime; for an ISAKMP SA, the Responder will accept the negotiated
+lifetime.
+.TP
+\fB\-\-delete\fP
+when used in the connection form, it causes any previous connection
+with this name to be deleted before this one is added. Unlike a
+normal delete, no diagnostic is produced if there was no previous
+connection to delete. Any routing in place for the connection is undone.
+.LP
+The delete form deletes a named connection description and any
+SAs established or negotiations initiated using this connection.
+Any routing in place for the connection is undone.
+.TP
+\fB\-\-delete\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The deletestate form deletes the state object with the specified serial number.
+This is useful for selectively deleting instances of connections.
+.TP
+\fB\-\-deletestate\fP\ \fIstate-number\fP
+.LP
+The route form of the \fBwhack\fP command tells \fBpluto\fP to set up
+routing for a connection.
+Although like a traditional route, it uses an ipsec device as a
+virtual interface.
+Once routing is set up, no packets will be
+sent ``in the clear'' to the peer's client specified in the connection.
+A TRAP shunt eroute will be installed; if outbound traffic is caught,
+Pluto will initiate the connection.
+An explicit \fBwhack\fP route is not always needed: if it hasn't been
+done when an IPsec SA is being installed, one will be automatically attempted.
+.LP
+When a routing is attempted for a connection, there must not already
+be a routing for a different connection with the same subnet but different
+interface or destination, or if
+there is, it must not be being used by an IPsec SA. Otherwise the
+attempt will fail.
+.TP
+\fB\-\-route\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The unroute form of the \fBwhack\fP command tells \fBpluto\fP to undo
+a routing. \fBpluto\fP will refuse if an IPsec SA is using the connection.
+If another connection is sharing the same routing, it will be left in place.
+Without a routing, packets will be sent without encryption or authentication.
+.TP
+\fB\-\-unroute\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The initiate form tells \fBpluto\fP to initiate a negotiation with another
+\fBpluto\fP (or other IKE daemon) according to the named connection.
+Initiation requires a route that \fB\-\-route\fP would provide;
+if none is in place at the time an IPsec SA is being installed,
+\fBpluto\fP attempts to set one up.
+.TP
+\fB\-\-initiate\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.TP
+\fB\-\-asynchronous
+.LP
+The initiate form of the \fBwhack\fP command will relay back from
+\fBpluto\fP status information via the UNIX domain socket (unless
+\-\-asynchronous is specified). The status information is meant to
+look a bit like that from \fBFTP\fP. Currently \fBwhack\fP simply
+copies this to stderr. When the request is finished (eg. the SAs are
+established or \fBpluto\fP gives up), \fBpluto\fP closes the channel,
+causing \fBwhack\fP to terminate.
+.LP
+The opportunistic initiate form is mainly used for debugging.
+.TP
+\fB\-\-tunnelipv4\fP
+.TP
+\fB\-\-tunnelipv6\fP
+.TP
+\fB\-\-oppohere\fP\ \fIip-address\fP
+.TP
+\fB\-\-oppothere\fP\ \fIip-address\fP
+.LP
+This will cause \fBpluto\fP to attempt to opportunistically initiate a
+connection from here to the there, even if a previous attempt
+had been made.
+The whack log will show the progress of this attempt.
+.LP
+The terminate form tells \fBpluto\fP to delete any SAs that use the specified
+connection and to stop any negotiations in process.
+It does not prevent new negotiations from starting (the delete form
+has this effect).
+.TP
+\fB\-\-terminate\fP
+.TP
+\fB\-\-name\fP\ \fIconnection-name\fP
+.LP
+The public key for informs \fBpluto\fP of the RSA public key for a potential peer.
+Private keys must be kept secret, so they are kept in
+.IR ipsec.secrets (5).
+.TP
+\fB\-\-keyid\ \fP\fIid\fP
+specififies the identity of the peer for which a public key should be used.
+Its form is identical to the identity in the connection.
+If no public key is specified, \fBpluto\fP attempts to find KEY records
+from DNS for the id (if a FQDN) or through reverse lookup (if an IP address).
+Note that there several interesting ways in which this is not secure.
+.TP
+\fB\-\-addkey\fP
+specifies that the new key is added to the collection; otherwise the
+new key replaces any old ones.
+.TP
+\fB\-\-pubkeyrsa\ \fP\fIkey\fP
+specifies the value of the RSA public key. It is a sequence of bytes
+as described in RFC 2537 ``RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)''.
+It is denoted in a way suitable for \fIipsec_ttodata\fP(3).
+For example, a base 64 numeral starts with 0s.
+.LP
+The listen form tells \fBpluto\fP to start listening for IKE requests
+on its public interfaces. To avoid race conditions, it is normal to
+load the appropriate connections into \fBpluto\fP before allowing it
+to listen. If \fBpluto\fP isn't listening, it is pointless to
+initiate negotiations, so it will refuse requests to do so. Whenever
+the listen form is used, \fBpluto\fP looks for public interfaces and
+will notice when new ones have been added and when old ones have been
+removed. This is also the trigger for \fBpluto\fP to read the
+\fIipsec.secrets\fP file. So listen may useful more than once.
+.TP
+\fB\-\-listen\fP
+start listening for IKE traffic on public interfaces.
+.TP
+\fB\-\-unlisten\fP
+stop listening for IKE traffic on public interfaces.
+.LP
+The status form will display information about the internal state of
+\fBpluto\fP: information about each potential connection, about
+each state object, and about each shunt that \fBpluto\fP is managing
+without an associated connection.
+.TP
+\fB\-\-status\fP
+.LP
+The shutdown form is the proper way to shut down \fBpluto\fP.
+It will tear down the SAs on this machine that \fBpluto\fP has negotiated.
+It does not inform its peers, so the SAs on their machines remain.
+.TP
+\fB\-\-shutdown\fP
+.SS Examples
+.LP
+It would be normal to start \fBpluto\fP in one of the system initialization
+scripts. It needs to be run by the superuser. Generally, no arguments are needed.
+To run in manually, the superuser can simply type
+
+\ \ \ ipsec pluto
+
+The command will immediately return, but a \fBpluto\fP process will be left
+running, waiting for requests from \fBwhack\fP or a peer.
+.LP
+Using \fBwhack\fP, several potential connections would be described:
+.HP
+.na
+\ \ \ ipsec whack \-\-name\ silly
+\-\-host\ 127.0.0.1 \-\-to \-\-host\ 127.0.0.2
+\-\-ikelifetime\ 900 \-\-ipseclifetime\ 800 \-\-keyingtries\ 3
+.ad
+.LP
+Since this silly connection description specifies neither encryption,
+authentication, nor tunneling, it could only be used to establish
+an ISAKMP SA.
+.HP
+.na
+\ \ \ ipsec whack \-\-name\ secret \-\-host\ 10.0.0.1 \-\-client\ 10.0.1.0/24
+\-\-to \-\-host\ 10.0.0.2 \-\-client\ 10.0.2.0/24
+\-\-encrypt
+.ad
+.LP
+This is something that must be done on both sides. If the other
+side is \fBpluto\fP, the same \fBwhack\fP command could be used on it
+(the command syntax is designed to not distinguish which end is ours).
+.LP
+Now that the connections are specified, \fBpluto\fP is ready to handle
+requests and replies via the public interfaces. We must tell it to discover
+those interfaces and start accepting messages from peers:
+
+\ \ \ ipsec whack \-\-listen
+.LP
+If we don't immediately wish to bring up a secure connection between
+the two clients, we might wish to prevent insecure traffic.
+The routing form asks \fBpluto\fP to cause the packets sent from
+our client to the peer's client to be routed through the ipsec0
+device; if there is no SA, they will be discarded:
+
+\ \ \ ipsec whack \-\-route secret
+.LP
+Finally, we are ready to get \fBpluto\fP to initiate negotiation
+for an IPsec SA (and implicitly, an ISAKMP SA):
+
+\ \ \ ipsec whack \-\-initiate\ \-\-name\ secret
+
+A small log of interesting events will appear on standard output
+(other logging is sent to syslog).
+.LP
+\fBwhack\fP can also be used to terminate \fBpluto\fP cleanly, tearing down
+all SAs that it has negotiated.
+
+\ \ \ ipsec whack \-\-shutdown
+
+Notification of any IPSEC SA deletion, but not ISAKMP SA deletion
+is sent to the peer. Unfortunately, such Notification is not reliable.
+Furthermore, \fBpluto\fP itself ignores Notifications.
+.SS The updown command
+.LP
+Whenever \fBpluto\fP brings a connection up or down, it invokes
+the updown command. This command is specified using the \fB\-\-updown\fP
+option. This allows for customized control over routing and firewall manipulation.
+.LP
+The updown is invoked for five different operations. Each of
+these operations can be for our client subnet or for our host itself.
+.TP
+\fBprepare-host\fP or \fBprepare-client\fP
+is run before bringing up a new connection if no other connection
+with the same clients is up. Generally, this is useful for deleting a
+route that might have been set up before \fBpluto\fP was run or
+perhaps by some agent not known to \fBpluto\fP.
+.TP
+\fBroute-host\fP or \fBroute-client\fP
+is run when bringing up a connection for a new peer client subnet
+(even if \fBprepare-host\fP or \fBprepare-client\fP was run). The
+command should install a suitable route. Routing decisions are based
+only on the destination (peer's client) subnet address, unlike eroutes
+which discriminate based on source too.
+.TP
+\fBunroute-host\fP or \fBunroute-client\fP
+is run when bringing down the last connection for a particular peer
+client subnet. It should undo what the \fBroute-host\fP or \fBroute-client\fP
+did.
+.TP
+\fBup-host\fP or \fBup-client\fP
+is run when bringing up a tunnel eroute with a pair of client subnets
+that does not already have a tunnel eroute.
+This command should install firewall rules as appropriate.
+It is generally a good idea to allow IKE messages (UDP port 500)
+travel between the hosts.
+.TP
+\fBdown-host\fP or \fBdown-client\fP
+is run when bringing down the eroute for a pair of client subnets.
+This command should delete firewall rules as appropriate. Note that
+there may remain some inbound IPsec SAs with these client subnets.
+.LP
+The script is passed a large number of environment variables to specify
+what needs to be done.
+.TP
+\fBPLUTO_VERSION\fP
+indicates what version of this interface is being used. This document
+describes version 1.1. This is upwardly compatible with version 1.0.
+.TP
+\fBPLUTO_VERB\fP
+specifies the name of the operation to be performed
+(\fBprepare-host\fP,r \fBprepare-client\fP,
+\fBup-host\fP, \fBup-client\fP,
+\fBdown-host\fP, or \fBdown-client\fP). If the address family for
+security gateway to security gateway communications is IPv6, then
+a suffix of -v6 is added to the verb.
+.TP
+\fBPLUTO_CONNECTION\fP
+is the name of the connection for which we are routing.
+.TP
+\fBPLUTO_NEXT_HOP\fP
+is the next hop to which packets bound for the peer must be sent.
+.TP
+\fBPLUTO_INTERFACE\fP
+is the name of the ipsec interface to be used.
+.TP
+\fBPLUTO_ME\fP
+is the IP address of our host.
+.TP
+\fBPLUTO_MY_CLIENT\fP
+is the IP address / count of our client subnet.
+If the client is just the host, this will be the host's own IP address / max
+(where max is 32 for IPv4 and 128 for IPv6).
+.TP
+\fBPLUTO_MY_CLIENT_NET\fP
+is the IP address of our client net.
+If the client is just the host, this will be the host's own IP address.
+.TP
+\fBPLUTO_MY_CLIENT_MASK\fP
+is the mask for our client net.
+If the client is just the host, this will be 255.255.255.255.
+.TP
+\fBPLUTO_PEER\fP
+is the IP address of our peer.
+.TP
+\fBPLUTO_PEER_CLIENT\fP
+is the IP address / count of the peer's client subnet.
+If the client is just the peer, this will be the peer's own IP address / max
+(where max is 32 for IPv4 and 128 for IPv6).
+.TP
+\fBPLUTO_PEER_CLIENT_NET\fP
+is the IP address of the peer's client net.
+If the client is just the peer, this will be the peer's own IP address.
+.TP
+\fBPLUTO_PEER_CLIENT_MASK\fP
+is the mask for the peer's client net.
+If the client is just the peer, this will be 255.255.255.255.
+.LP
+All output sent by the script to stderr or stdout is logged. The
+script should return an exit status of 0 if and only if it succeeds.
+.LP
+\fBPluto\fP waits for the script to finish and will not do any other
+processing while it is waiting.
+The script may assume that \fBpluto\fP will not change anything
+while the script runs.
+The script should avoid doing anything that takes much time and it
+should not issue any command that requires processing by \fBpluto\fP.
+Either of these activities could be performed by a background
+subprocess of the script.
+.SS Rekeying
+.LP
+When an SA that was initiated by \fBpluto\fP has only a bit of
+lifetime left,
+\fBpluto\fP will initiate the creation of a new SA. This applies to
+ISAKMP and IPsec SAs.
+The rekeying will be initiated when the SA's remaining lifetime is
+less than the rekeymargin plus a random percentage, between 0 and
+rekeyfuzz, of the rekeymargin.
+.LP
+Similarly, when an SA that was initiated by the peer has only a bit of
+lifetime left, \fBpluto\fP will try to initiate the creation of a
+replacement.
+To give preference to the initiator, this rekeying will only be initiated
+when the SA's remaining lifetime is half of rekeymargin.
+If rekeying is done by the responder, the roles will be reversed: the
+responder for the old SA will be the initiator for the replacement.
+The former initiator might also initiate rekeying, so there may
+be redundant SAs created.
+To avoid these complications, make sure that rekeymargin is generous.
+.LP
+One risk of having the former responder initiate is that perhaps
+none of its proposals is acceptable to the former initiator
+(they have not been used in a successful negotiation).
+To reduce the chances of this happening, and to prevent loss of security,
+the policy settings are taken from the old SA (this is the case even if
+the former initiator is initiating).
+These may be stricter than those of the connection.
+.LP
+\fBpluto\fP will not rekey an SA if that SA is not the most recent of its
+type (IPsec or ISAKMP) for its potential connection.
+This avoids creating redundant SAs.
+.LP
+The random component in the rekeying time (rekeyfuzz) is intended to
+make certain pathological patterns of rekeying unstable. If both
+sides decide to rekey at the same time, twice as many SAs as necessary
+are created. This could become a stable pattern without the
+randomness.
+.LP
+Another more important case occurs when a security gateway has SAs
+with many other security gateways. Each of these connections might
+need to be rekeyed at the same time. This would cause a high peek
+requirement for resources (network bandwidth, CPU time, entropy for
+random numbers). The rekeyfuzz can be used to stagger the rekeying
+times.
+.LP
+Once a new set of SAs has been negotiated, \fBpluto\fP will never send
+traffic on a superseded one. Traffic will be accepted on an old SA
+until it expires.
+.SS Selecting a Connection When Responding: Road Warrior Support
+.LP
+When \fBpluto\fP receives an initial Main Mode message, it needs to
+decide which connection this message is for. It picks based solely on
+the source and destination IP addresses of the message. There might
+be several connections with suitable IP addresses, in which case one
+of them is arbitrarily chosen. (The ISAKMP SA proposal contained in
+the message could be taken into account, but it is not.)
+.LP
+The ISAKMP SA is negotiated before the parties pass further
+identifying information, so all ISAKMP SA characteristics specified in
+the connection description should be the same for every connection
+with the same two host IP addresses. At the moment, the only
+characteristic that might differ is authentication method.
+.LP
+Up to this point,
+all configuring has presumed that the IP addresses
+are known to all parties ahead of time. This will not work
+when either end is mobile (or assigned a dynamic IP address for other
+reasons). We call this situation ``Road Warrior''. It is fairly tricky
+and has some important limitations, most of which are features of
+the IKE protocol.
+.LP
+Only the initiator may be mobile:
+the initiator may have an IP number unknown to the responder. When
+the responder doesn't recognize the IP address on the first Main Mode
+packet, it looks for a connection with itself as one end and \fB%any\fP
+as the other.
+If it cannot find one, it refuses to negotiate. If it
+does find one, it creates a temporary connection that is a duplicate
+except with the \fB%any\fP replaced by the source IP address from the
+packet; if there was no identity specified for the peer, the new IP
+address will be used.
+.LP
+When \fBpluto\fP is using one of these temporary connections and
+needs to find the preshared secret or RSA private key in \fIipsec.secrets\fP,
+and and the connection specified no identity for the peer, \fB%any\fP
+is used as its identity. After all, the real IP address was apparently
+unknown to the configuration, so it is unreasonable to require that
+it be used in this table.
+.LP
+Part way into the Phase 1 (Main Mode) negotiation using one of these
+temporary connection descriptions, \fBpluto\fP will be receive an
+Identity Payload. At this point, \fBpluto\fP checks for a more
+appropriate connection, one with an identity for the peer that matches
+the payload but which would use the same keys so-far used for
+authentication. If it finds one, it will switch to using this better
+connection (or a temporary derived from this, if it has \fB%any\fP
+for the peer's IP address). It may even turn out that no connection
+matches the newly discovered identity, including the current connection;
+if so, \fBpluto\fP terminates negotiation.
+.LP
+Unfortunately, if preshared secret authentication is being used, the
+Identity Payload is encrypted using this secret, so the secret must be
+selected by the responder without knowing this payload. This
+limits there to being at most one preshared secret for all Road Warrior
+systems connecting to a host. RSA Signature authentications does not
+require that the responder know how to select the initiator's public key
+until after the initiator's Identity Payload is decoded (using the
+responder's private key, so that must be preselected).
+.LP
+When \fBpluto\fP is responding to a Quick Mode negotiation via one of these
+temporary connection descriptions, it may well find that the subnets
+specified by the initiator don't match those in the temporary
+connection description. If so, it will look for a connection with
+matching subnets, its own host address, a peer address of \fB%any\fP
+and matching identities.
+If it finds one, a new temporary connection is derived from this one
+and used for the Quick Mode negotiation of IPsec SAs. If it does not
+find one, \fBpluto\fP terminates negotiation.
+.LP
+Be sure to specify an appropriate nexthop for the responder
+to send a message to the initiator: \fBpluto\fP has no way of guessing
+it (if forwarding isn't required, use an explicit \fB%direct\fP as the nexthop
+and the IP address of the initiator will be filled in; the obsolete
+notation \fB0.0.0.0\fP is still accepted).
+.LP
+\fBpluto\fP has no special provision for the initiator side. The current
+(possibly dynamic) IP address and nexthop must be used in defining
+connections. These must be
+properly configured each time the initiator's IP address changes.
+\fBpluto\fP has no mechanism to do this automatically.
+.LP
+Although we call this Road Warrior Support, it could also be used to
+support encrypted connections with anonymous initiators. The
+responder's organization could announce the preshared secret that would be used
+with unrecognized initiators and let anyone connect. Of course the initiator's
+identity would not be authenticated.
+.LP
+If any Road Warrior connections are supported, \fBpluto\fP cannot
+reject an exchange initiated by an unknown host until it has
+determined that the secret is not shared or the signature is invalid.
+This must await the
+third Main Mode message from the initiator. If no Road Warrior
+connection is supported, the first message from an unknown source
+would be rejected. This has implications for ease of debugging
+configurations and for denial of service attacks.
+.LP
+Although a Road Warrior connection must be initiated by the mobile
+side, the other side can and will rekey using the temporary connection
+it has created. If the Road Warrior wishes to be able to disconnect,
+it is probably wise to set \fB\-\-keyingtries\fP to 1 in the
+connection on the non-mobile side to prevent it trying to rekey the
+connection. Unfortunately, there is no mechanism to unroute the
+connection automatically.
+.SS Debugging
+.LP
+\fBpluto\fP accepts several optional arguments, useful mostly for debugging.
+Except for \fB\-\-interface\fP, each should appear at most once.
+.TP
+\fB\-\-interface\fP \fIinterfacename\fP
+specifies that the named real public network interface should be considered.
+The interface name specified should not be \fBipsec\fP\fIN\fP.
+If the option doesn't appear, all interfaces are considered.
+To specify several interfaces, use the option once for each.
+One use of this option is to specify which interface should be used
+when two or more share the same IP address.
+.TP
+\fB\-\-ikeport\fP \fIport-number\fP
+changes the UDP port that \fBpluto\fP will use
+(default, specified by IANA: 500)
+.TP
+\fB\-\-ctlbase\fP \fIpath\fP
+basename for control files.
+\fIpath\fP.ctl is the socket through which \fBwhack\fP communicates with
+\fBpluto\fP.
+\fIpath\fP.pid is the lockfile to prevent multiple \fBpluto\fP instances.
+The default is \fI/var/run/pluto\fP).
+.TP
+\fB\-\-secretsfile\fP \fIfile\fP
+specifies the file for authentication secrets
+(default: \fI/etc/ipsec.secrets\fP).
+This name is subject to ``globbing'' as in \fIsh\fP(1),
+so every file with a matching name is processed.
+Quoting is generally needed to prevent the shell from doing the globbing.
+.TP
+\fB\-\-adns\fP \fIpathname\fP
+.TP
+\fB\-\-lwdnsq\fP \fIpathname\fP
+specifies where to find \fBpluto\fP's helper program for asynchronous DNS lookup.
+\fBpluto\fP can be built to use one of two helper programs: \fB_pluto_adns\fP
+or \fBlwdnsq\fP. You must use the program for which it was built.
+By default, \fBpluto\fP will look for the program in
+\fB$IPSEC_DIR\fP (if that environment variable is defined) or, failing that,
+in the same directory as \fBpluto\fP.
+.TP
+\fB\-\-nofork\fP
+disable ``daemon fork'' (default is to fork). In addition, after the
+lock file and control socket are created, print the line ``Pluto
+initialized'' to standard out.
+.TP
+\fB\-\-noklips\fP
+don't actually implement negotiated IPsec SAs
+.TP
+\fB\-\-uniqueids\fP
+if this option has been selected, whenever a new ISAKMP SA is
+established, any connection with the same Peer ID but a different
+Peer IP address is unoriented (causing all its SAs to be deleted).
+This helps clean up dangling SAs when a connection is lost and
+then regained at another IP address.
+.TP
+\fB\-\-stderrlog\fP
+log goes to standard out {default is to use \fIsyslogd\fP(8))
+.LP
+For example
+.TP
+pluto \-\-secretsfile\ ipsec.secrets \-\-ctlbase\ pluto.base \-\-ikeport\ 8500 \-\-nofork \-\-noklips \-\-stderrlog
+.LP
+lets one test \fBpluto\fP without using the superuser account.
+.LP
+\fBpluto\fP is willing to produce a prodigious amount of debugging
+information. To do so, it must be compiled with \-DDEBUG. There are
+several classes of debugging output, and \fBpluto\fP may be directed to
+produce a selection of them. All lines of
+debugging output are prefixed with ``|\ '' to distinguish them from error
+messages.
+.LP
+When \fBpluto\fP is invoked, it may be given arguments to specify
+which classes to output. The current options are:
+.TP
+\fB\-\-debug-raw\fP
+show the raw bytes of messages
+.TP
+\fB\-\-debug-crypt\fP
+show the encryption and decryption of messages
+.TP
+\fB\-\-debug-parsing\fP
+show the structure of input messages
+.TP
+\fB\-\-debug-emitting\fP
+show the structure of output messages
+.TP
+\fB\-\-debug-control\fP
+show \fBpluto\fP's decision making
+.TP
+\fB\-\-debug-lifecycle\fP
+[this option is temporary] log more detail of lifecycle of SAs
+.TP
+\fB\-\-debug-klips\fP
+show \fBpluto\fP's interaction with \fBKLIPS\fP
+.TP
+\fB\-\-debug-dns\fP
+show \fBpluto\fP's interaction with \fBDNS\fP for KEY and TXT records
+.TP
+\fB\-\-debug-oppo\fP
+show why \fBpluto\fP didn't find a suitable DNS TXT record to authorize opportunistic initiation
+.TP
+\fB\-\-debug-all\fP
+all of the above
+.TP
+\fB\-\-debug-private\fP
+allow debugging output with private keys.
+.TP
+\fB\-\-debug-none\fP
+none of the above
+.LP
+The debug form of the
+\fBwhack\fP command will change the selection in a running
+\fBpluto\fP.
+If a connection name is specified, the flags are added whenever
+\fBpluto\fP has identified that it is dealing with that connection.
+Unfortunately, this is often part way into the operation being observed.
+.LP
+For example, to start a \fBpluto\fP with a display of the structure of input
+and output:
+.IP
+pluto \-\-debug-emitting \-\-debug-parsing
+.LP
+To later change this \fBpluto\fP to only display raw bytes:
+.IP
+whack \-\-debug-raw
+.LP
+For testing, SSH's IKE test page is quite useful:
+.IP
+\fIhttp://isakmp-test.ssh.fi/\fP
+.LP
+Hint: ISAKMP SAs are often kept alive by IKEs even after the IPsec SA
+is established. This allows future IPsec SA's to be negotiated
+directly. If one of the IKEs is restarted, the other may try to use
+the ISAKMP SA but the new IKE won't know about it. This can lead to
+much confusion. \fBpluto\fP is not yet smart enough to get out of such a
+mess.
+.SS Pluto's Behaviour When Things Go Wrong
+.LP
+When \fBpluto\fP doesn't understand or accept a message, it just
+ignores the message. It is not yet capable of communicating the
+problem to the other IKE daemon (in the future it might use
+Notifications to accomplish this in many cases). It does log a diagnostic.
+.LP
+When \fBpluto\fP gets no response from a message, it resends the same
+message (a message will be sent at most three times). This is
+appropriate: UDP is unreliable.
+.LP
+When pluto gets a message that it has already seen, there are many
+cases when it notices and discards it. This too is appropriate for UDP.
+.LP
+Combine these three rules, and you can explain many apparently
+mysterious behaviours. In a \fBpluto\fP log, retrying isn't usually the
+interesting event. The critical thing is either earlier (\fBpluto\fP
+got a message which it didn't like and so ignored, so it was still
+awaiting an acceptable message and got impatient) or on the other
+system (\fBpluto\fP didn't send a reply because it wasn't happy with
+the previous message).
+.SS Notes
+.LP
+If \fBpluto\fP is compiled without \-DKLIPS, it negotiates Security
+Associations but never ask the kernel to put them in place and never
+makes routing changes. This allows \fBpluto\fP to be tested on systems
+without \fBKLIPS\fP, but makes it rather useless.
+.LP
+Each IPsec SA is assigned an SPI, a 32-bit number used to refer to the SA.
+The IKE protocol lets the destination of the SA choose the SPI.
+The range 0 to 0xFF is reserved for IANA.
+\fBPluto\fP also avoids choosing an SPI in the range 0x100 to 0xFFF,
+leaving these SPIs free for manual keying.
+Remember that the peer, if not \fBpluto\fP, may well chose
+SPIs in this range.
+.SS Policies
+.LP
+This catalogue of policies may be of use when trying to configure
+\fBPluto\fP and another IKE implementation to interoperate.
+.LP
+In Phase 1, only Main Mode is supported. We are not sure that
+Aggressive Mode is secure. For one thing, it does not support
+identity protection. It may allow more severe Denial Of Service
+attacks.
+.LP
+No Informational Exchanges are supported. These are optional and
+since their delivery is not assured, they must not matter.
+It is the case that some IKE implementations won't interoperate
+without Informational Exchanges, but we feel they are broken.
+.LP
+No Informational Payloads are supported. These are optional, but
+useful. It is of concern that these payloads are not authenticated in
+Phase 1, nor in those Phase 2 messages authenticated with HASH(3).
+.IP \(bu \w'\(bu\ 'u
+Diffie Hellman Groups MODP 1024 and MODP 1536 (2 and 5)
+are supported.
+Group MODP768 (1) is not supported because it is too weak.
+.IP \(bu
+Host authetication can be done by RSA Signatures or Pre-Shared
+Secrets.
+.IP \(bu
+3DES CBC (Cypher Block Chaining mode) is the only encryption
+supported, both for ISAKMP SAs and IPSEC SAs.
+.IP \(bu
+MD5 and SHA1 hashing are supported for packet authentication in both
+kinds of SAs.
+.IP \(bu
+The ESP, AH, or AH plus ESP are supported. If, and only if, AH and
+ESP are combined, the ESP need not have its own authentication
+component. The selection is controlled by the \-\-encrypt and
+\-\-authenticate flags.
+.IP \(bu
+Each of these may be combined with IPCOMP Deflate compression,
+but only if the potential connection specifies compression and only
+if KLIPS is configured with IPCOMP support.
+.IP \(bu
+The IPSEC SAs may be tunnel or transport mode, where appropriate.
+The \-\-tunnel flag controls this when \fBpluto\fP is initiating.
+.IP \(bu
+When responding to an ISAKMP SA proposal, the maximum acceptable
+lifetime is eight hours. The default is one hour. There is no
+minimum. The \-\-ikelifetime flag controls this when \fBpluto\fP
+is initiating.
+.IP \(bu
+When responding to an IPSEC SA proposal, the maximum acceptable
+lifetime is one day. The default is eight hours. There is no
+minimum. The \-\-ipseclifetime flag controls this when \fBpluto\fP
+is initiating.
+.IP \(bu
+PFS is acceptable, and will be proposed if the \-\-pfs flag was
+specified. The DH group proposed will be the same as negotiated for
+Phase 1.
+.SH SIGNALS
+.LP
+\fBPluto\fP responds to \fBSIGHUP\fP by issuing a suggestion that ``\fBwhack\fP
+\-\-listen'' might have been intended.
+.LP
+\fBPluto\fP exits when it recieves \fBSIGTERM\fP.
+.SH EXIT STATUS
+.LP
+\fBpluto\fP normally forks a daemon process, so the exit status is
+normally a very preliminary result.
+.TP
+0
+means that all is OK so far.
+.TP
+1
+means that something was wrong.
+.TP
+10
+means that the lock file already exists.
+.LP
+If \fBwhack\fP detects a problem, it will return an exit status of 1.
+If it received progress messages from \fBpluto\fP, it returns as status
+the value of the numeric prefix from the last such message
+that was not a message sent to syslog or a comment
+(but the prefix for success is treated as 0).
+Otherwise, the exit status is 0.
+.SH FILES
+\fI/var/run/pluto.pid\fP
+.br
+\fI/var/run/pluto.ctl\fP
+.br
+\fI/etc/ipsec.secrets\fP
+.br
+\fI$IPSEC_LIBDIR/_pluto_adns\fP
+.br
+\fI$IPSEC_EXECDIR/lwdnsq\fP
+.br
+\fI/dev/urandom\fP
+.SH ENVIRONMENT
+\fIIPSEC_LIBDIR\fP
+.br
+\fIIPSEC_EXECDIR\fP
+.br
+\fIIPSECmyid\fP
+.SH SEE ALSO
+.LP
+The rest of the FreeS/WAN distribution, in particular \fIipsec\fP(8).
+.LP
+\fIipsec_auto\fP(8) is designed to make using \fBpluto\fP more pleasant.
+Use it!
+.LP
+.IR ipsec.secrets (5)
+describes the format of the secrets file.
+.LP
+\fIipsec_atoaddr\fP(3), part of the FreeS/WAN distribution, describes the
+forms that IP addresses may take.
+\fIipsec_atosubnet\fP(3), part of the FreeS/WAN distribution, describes the
+forms that subnet specifications.
+.LP
+For more information on IPsec, the mailing list, and the relevant
+documents, see:
+.IP
+.nh
+\fIhttp://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html\fP
+.hy
+.LP
+At the time of writing, the most relevant IETF RFCs are:
+.IP
+RFC2409 The Internet Key Exchange (IKE)
+.IP
+RFC2408 Internet Security Association and Key Management Protocol (ISAKMP)
+.IP
+RFC2407 The Internet IP Security Domain of Interpretation for ISAKMP
+.LP
+The FreeS/WAN web site <htp://www.freeswan.org>
+and the mailing lists described there.
+.SH HISTORY
+This code is released under the GPL terms.
+See the accompanying file COPYING-2.0 for more details.
+The GPL does NOT apply to those pieces of code written by others
+which are included in this distribution, except as noted by the
+individual authors.
+.LP
+This software was originally written
+for the FreeS/WAN project
+<http://www.freeswan.org>
+by Angelos D. Keromytis
+(angelos@dsl.cis.upenn.edu), in May/June 1997, in Athens, Greece.
+Thanks go to John Ioannidis for his help.
+.LP
+It is currently (2000)
+being developed and maintained by D. Hugh Redelmeier
+(hugh@mimosa.com), in Canada. The regulations of Greece and Canada
+allow us to make the code freely redistributable.
+.LP
+Kai Martius (admin@imib.med.tu-dresden.de) contributed the initial
+version of the code supporting PFS.
+.LP
+Richard Guy Briggs <rgb@conscoop.ottawa.on.ca> and Peter Onion
+<ponion@srd.bt.co.uk> added the PFKEY2 support.
+.LP
+We gratefully acknowledge that we use parts of Eric Young's \fIlibdes\fP
+package; see \fI../libdes/COPYRIGHT\fP.
+.SH BUGS
+.BR pluto
+is a work-in-progress. It currently has many limitations.
+For example, it ignores notification messages that it receives, and
+it generates only Delete Notifications and those only for IPSEC SAs.
+.LP
+\fBpluto\fP does not support the Commit Flag.
+The Commit Flag is a bad feature of the IKE protocol.
+It isn't protected -- neither encrypted nor authenticated.
+A man in the middle could turn it on, leading to DoS.
+We just ignore it, with a warning.
+This should let us interoperate with
+implementations that insist on it, with minor damage.
+.LP
+\fBpluto\fP does not check that the SA returned by the Responder
+is actually one that was proposed. It only checks that the SA is
+acceptable. The difference is not large, but can show up in attributes
+such as SA lifetime.
+.LP
+There is no good way for a connection to be automatically terminated.
+This is a problem for Road Warrior and Opportunistic connections.
+The \fB\-\-dontrekey\fP option does prevent the SAs from
+being rekeyed on expiry.
+Additonally, if a Road Warrior connection has a client subnet with a fixed IP
+address, a negotiation with that subnet will cause any other
+connection instantiations with that same subnet to be unoriented
+(deleted, in effect).
+See also the \-\-uniqueids option for an extension of this.
+.LP
+When \fBpluto\fP sends a message to a peer that has disappeared,
+\fBpluto\fP receives incomplete information from the kernel, so it
+logs the unsatisfactory message ``some IKE message we sent has been
+rejected with ECONNREFUSED (kernel supplied no details)''. John
+Denker suggests that this command is useful for tracking down the
+source of these problems:
+.br
+ tcpdump -i eth0 icmp[0] != 8 and icmp[0] != 0
+.br
+Substitute your public interface for eth0 if it is different.
+.LP
+The word ``authenticate'' is used for two different features. We must
+authenticate each IKE peer to the other. This is an important task of
+Phase 1. Each packet must be authenticated, both in IKE and in IPsec,
+and the method for IPsec is negotiated as an AH SA or part of an ESP SA.
+Unfortunately, the protocol has no mechanism for authenticating the Phase 2
+identities.
+.LP
+Bugs should be reported to the <users@lists.freeswan.org> mailing list.
+Caution: we cannot accept
+actual code from US residents, or even US citizens living outside the
+US, because that would bring FreeS/WAN under US export law. Some
+other countries cause similar problems. In general, we would prefer
+that you send detailed problem reports rather than code: we want
+FreeS/WAN to be unquestionably freely exportable, which means being
+very careful about where the code comes from, and for a small bug fix,
+that is often more time-consuming than just reinventing the fix
+ourselves.
diff --git a/programs/pluto/plutomain.c b/programs/pluto/plutomain.c
new file mode 100644
index 000000000..f9badbae3
--- /dev/null
+++ b/programs/pluto/plutomain.c
@@ -0,0 +1,696 @@
+/* Pluto main program
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: plutomain.c,v 1.16 2005/09/25 21:30:52 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "ca.h"
+#include "certs.h"
+#include "ac.h"
+#include "connections.h"
+#include "foodgroups.h"
+#include "packet.h"
+#include "demux.h" /* needs packet.h */
+#include "server.h"
+#include "kernel.h"
+#include "log.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "rnd.h"
+#include "state.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "ocsp.h"
+#include "crl.h"
+#include "fetch.h"
+
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+
+#ifdef VIRTUAL_IP
+#include "virtual.h"
+#endif
+
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
+static void
+usage(const char *mess)
+{
+ if (mess != NULL && *mess != '\0')
+ fprintf(stderr, "%s\n", mess);
+ fprintf(stderr
+ , "Usage: pluto"
+ " [--help]"
+ " [--version]"
+ " [--optionsfrom <filename>]"
+ " \\\n\t"
+ "[--nofork]"
+ " [--stderrlog]"
+ " [--noklips]"
+ " [--nocrsend]"
+ " \\\n\t"
+ "[--strictcrlpolicy]"
+ " [--crlcheckinterval]"
+ " [--cachecrls]"
+ " [--uniqueids]"
+ " \\\n\t"
+ "[--interface <ifname>]"
+ " [--ikeport <port-number>]"
+ " \\\n\t"
+ "[--ctlbase <path>]"
+ " \\\n\t"
+ "[--perpeerlogbase <path>] [--perpeerlog]"
+ " \\\n\t"
+ "[--secretsfile <secrets-file>]"
+ " [--policygroupsdir <policygroups-dir>]"
+ " \\\n\t"
+ "[--adns <pathname>]"
+ "[--pkcs11module <path>]"
+ "[--pkcs11keepstate"
+#ifdef DEBUG
+ " \\\n\t"
+ "[--debug-none]"
+ " [--debug-all]"
+ " \\\n\t"
+ "[--debug-raw]"
+ " [--debug-crypt]"
+ " [--debug-parsing]"
+ " [--debug-emitting]"
+ " \\\n\t"
+ "[--debug-control]"
+ " [--debug-lifecycle]"
+ " [--debug-klips]"
+ " [--debug-dns]"
+ " \\\n\t"
+ "[--debug-oppo]"
+ " [--debug-controlmore]"
+ " [--debug-private]"
+#endif
+#ifdef NAT_TRAVERSAL
+ " [ --debug-natt]"
+ " \\\n\t"
+ "[--nat_traversal] [--keep_alive <delay_sec>]"
+ " \\\n\t"
+ "[--force_keepalive] [--disable_port_floating]"
+#endif
+#ifdef VIRTUAL_IP
+ " \\\n\t"
+ "[--virtual_private <network_list>]"
+#endif
+ "\n"
+ "strongSwan %s\n"
+ , ipsec_version_code());
+ exit_pluto(mess == NULL? 0 : 1);
+}
+
+
+/* lock file support
+ * - provides convenient way for scripts to find Pluto's pid
+ * - prevents multiple Plutos competing for the same port
+ * - same basename as unix domain control socket
+ * NOTE: will not take account of sharing LOCK_DIR with other systems.
+ */
+
+static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX;
+static bool pluto_lock_created = FALSE;
+
+/* create lockfile, or die in the attempt */
+static int
+create_lock(void)
+{
+ int fd = open(pluto_lock, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC
+ , S_IRUSR | S_IRGRP | S_IROTH);
+
+ if (fd < 0)
+ {
+ if (errno == EEXIST)
+ {
+ fprintf(stderr, "pluto: lock file \"%s\" already exists\n"
+ , pluto_lock);
+ exit_pluto(10);
+ }
+ else
+ {
+ fprintf(stderr
+ , "pluto: unable to create lock file \"%s\" (%d %s)\n"
+ , pluto_lock, errno, strerror(errno));
+ exit_pluto(1);
+ }
+ }
+ pluto_lock_created = TRUE;
+ return fd;
+}
+
+static bool
+fill_lock(int lockfd, pid_t pid)
+{
+ char buf[30]; /* holds "<pid>\n" */
+ int len = snprintf(buf, sizeof(buf), "%u\n", (unsigned int) pid);
+ bool ok = len > 0 && write(lockfd, buf, len) == len;
+
+ close(lockfd);
+ return ok;
+}
+
+static void
+delete_lock(void)
+{
+ if (pluto_lock_created)
+ {
+ delete_ctl_socket();
+ unlink(pluto_lock); /* is noting failure useful? */
+ }
+}
+
+/* by default pluto sends certificate requests to its peers */
+bool no_cr_send = FALSE;
+
+/* by default the CRL policy is lenient */
+bool strict_crl_policy = FALSE;
+
+/* by default CRLs are cached locally as files */
+bool cache_crls = FALSE;
+
+/* by default pluto does not check crls dynamically */
+long crl_check_interval = 0;
+
+/* path to the PKCS#11 module */
+char *pkcs11_module_path = NULL;
+
+/* by default pluto logs out after every smartcard use */
+bool pkcs11_keep_state = FALSE;
+
+/* by default pluto does not allow pkcs11 proxy access via whack */
+bool pkcs11_proxy = FALSE;
+
+int
+main(int argc, char **argv)
+{
+ bool fork_desired = TRUE;
+ bool log_to_stderr_desired = FALSE;
+#ifdef NAT_TRAVERSAL
+ bool nat_traversal = FALSE;
+ bool nat_t_spf = TRUE; /* support port floating */
+ unsigned int keep_alive = 0;
+ bool force_keepalive = FALSE;
+#endif
+#ifdef VIRTUAL_IP
+ char *virtual_private = NULL;
+#endif
+ int lockfd;
+
+ /* handle arguments */
+ for (;;)
+ {
+# define DBG_OFFSET 256
+ static const struct option long_opts[] = {
+ /* name, has_arg, flag, val */
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "optionsfrom", required_argument, NULL, '+' },
+ { "nofork", no_argument, NULL, 'd' },
+ { "stderrlog", no_argument, NULL, 'e' },
+ { "noklips", no_argument, NULL, 'n' },
+ { "nocrsend", no_argument, NULL, 'c' },
+ { "strictcrlpolicy", no_argument, NULL, 'r' },
+ { "crlcheckinterval", required_argument, NULL, 'x'},
+ { "cachecrls", no_argument, NULL, 'C' },
+ { "uniqueids", no_argument, NULL, 'u' },
+ { "interface", required_argument, NULL, 'i' },
+ { "ikeport", required_argument, NULL, 'p' },
+ { "ctlbase", required_argument, NULL, 'b' },
+ { "secretsfile", required_argument, NULL, 's' },
+ { "foodgroupsdir", required_argument, NULL, 'f' },
+ { "perpeerlogbase", required_argument, NULL, 'P' },
+ { "perpeerlog", no_argument, NULL, 'l' },
+ { "policygroupsdir", required_argument, NULL, 'f' },
+#ifdef USE_LWRES
+ { "lwdnsq", required_argument, NULL, 'a' },
+#else /* !USE_LWRES */
+ { "adns", required_argument, NULL, 'a' },
+#endif /* !USE_LWRES */
+ { "pkcs11module", required_argument, NULL, 'm' },
+ { "pkcs11keepstate", no_argument, NULL, 'k' },
+ { "pkcs11proxy", no_argument, NULL, 'y' },
+#ifdef NAT_TRAVERSAL
+ { "nat_traversal", no_argument, NULL, '1' },
+ { "keep_alive", required_argument, NULL, '2' },
+ { "force_keepalive", no_argument, NULL, '3' },
+ { "disable_port_floating", no_argument, NULL, '4' },
+ { "debug-natt", no_argument, NULL, '5' },
+#endif
+#ifdef VIRTUAL_IP
+ { "virtual_private", required_argument, NULL, '6' },
+#endif
+#ifdef DEBUG
+ { "debug-none", no_argument, NULL, 'N' },
+ { "debug-all", no_argument, NULL, 'A' },
+
+ { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
+ { "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET },
+ { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
+ { "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET },
+ { "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET },
+ { "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET },
+ { "debug-klips", no_argument, NULL, DBG_KLIPS + DBG_OFFSET },
+ { "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET },
+ { "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET },
+ { "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET },
+ { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },
+
+ { "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET },
+ { "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET },
+ { "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET },
+ { "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET },
+#endif
+ { 0,0,0,0 }
+ };
+ /* Note: we don't like the way short options get parsed
+ * by getopt_long, so we simply pass an empty string as
+ * the list. It could be "hvdenp:l:s:" "NARXPECK".
+ */
+ int c = getopt_long(argc, argv, "", long_opts, NULL);
+
+ /* Note: "breaking" from case terminates loop */
+ switch (c)
+ {
+ case EOF: /* end of flags */
+ break;
+
+ case 0: /* long option already handled */
+ continue;
+
+ case ':': /* diagnostic already printed by getopt_long */
+ case '?': /* diagnostic already printed by getopt_long */
+ usage("");
+ break; /* not actually reached */
+
+ case 'h': /* --help */
+ usage(NULL);
+ break; /* not actually reached */
+
+ case 'v': /* --version */
+ {
+ const char **sp = ipsec_copyright_notice();
+
+ printf("%s%s\n", ipsec_version_string(),
+ compile_time_interop_options);
+ for (; *sp != NULL; sp++)
+ puts(*sp);
+ }
+ exit_pluto(0);
+ break; /* not actually reached */
+
+ case '+': /* --optionsfrom <filename> */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ continue;
+
+ case 'd': /* --nofork*/
+ fork_desired = FALSE;
+ continue;
+
+ case 'e': /* --stderrlog */
+ log_to_stderr_desired = TRUE;
+ continue;
+
+ case 'n': /* --noklips */
+ no_klips = TRUE;
+ continue;
+
+ case 'c': /* --nocrsend */
+ no_cr_send = TRUE;
+ continue;
+
+ case 'r': /* --strictcrlpolicy */
+ strict_crl_policy = TRUE;
+ continue;
+
+ case 'x': /* --crlcheckinterval <time>*/
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing interval time");
+
+ {
+ char *endptr;
+ long interval = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || interval <= 0)
+ usage("<interval-time> must be a positive number");
+ crl_check_interval = interval;
+ }
+ continue;
+
+ case 'C': /* --cachecrls */
+ cache_crls = TRUE;
+ continue;
+
+ case 'u': /* --uniqueids */
+ uniqueIDs = TRUE;
+ continue;
+
+ case 'i': /* --interface <ifname> */
+ if (!use_interface(optarg))
+ usage("too many --interface specifications");
+ continue;
+
+ case 'p': /* --port <portnumber> */
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing port number");
+
+ {
+ char *endptr;
+ long port = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || port <= 0 || port > 0x10000)
+ usage("<port-number> must be a number between 1 and 65535");
+ pluto_port = port;
+ }
+ continue;
+
+ case 'b': /* --ctlbase <path> */
+ if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path)
+ , "%s%s", optarg, CTL_SUFFIX) == -1)
+ usage("<path>" CTL_SUFFIX " too long for sun_path");
+ if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path)
+ , "%s%s", optarg, INFO_SUFFIX) == -1)
+ usage("<path>" INFO_SUFFIX " too long for sun_path");
+ if (snprintf(pluto_lock, sizeof(pluto_lock)
+ , "%s%s", optarg, LOCK_SUFFIX) == -1)
+ usage("<path>" LOCK_SUFFIX " must fit");
+ continue;
+
+ case 's': /* --secretsfile <secrets-file> */
+ shared_secrets_file = optarg;
+ continue;
+
+ case 'f': /* --policygroupsdir <policygroups-dir> */
+ policygroups_dir = optarg;
+ continue;
+
+ case 'a': /* --adns <pathname> */
+ pluto_adns_option = optarg;
+ continue;
+
+ case 'm': /* --pkcs11module <pathname> */
+ pkcs11_module_path = optarg;
+ continue;
+
+ case 'k': /* --pkcs11keepstate */
+ pkcs11_keep_state = TRUE;
+ continue;
+
+ case 'y': /* --pkcs11proxy */
+ pkcs11_proxy = TRUE;
+ continue;
+
+#ifdef DEBUG
+ case 'N': /* --debug-none */
+ base_debugging = DBG_NONE;
+ continue;
+
+ case 'A': /* --debug-all */
+ base_debugging = DBG_ALL;
+ continue;
+#endif
+
+ case 'P': /* --perpeerlogbase */
+ base_perpeer_logdir = optarg;
+ continue;
+
+ case 'l':
+ log_to_perpeer = TRUE;
+ continue;
+
+#ifdef NAT_TRAVERSAL
+ case '1': /* --nat_traversal */
+ nat_traversal = TRUE;
+ continue;
+ case '2': /* --keep_alive */
+ keep_alive = atoi(optarg);
+ continue;
+ case '3': /* --force_keepalive */
+ force_keepalive = TRUE;
+ continue;
+ case '4': /* --disable_port_floating */
+ nat_t_spf = FALSE;
+ continue;
+ case '5': /* --debug-nat_t */
+ base_debugging |= DBG_NATT;
+ continue;
+#endif
+#ifdef VIRTUAL_IP
+ case '6': /* --virtual_private */
+ virtual_private = optarg;
+ continue;
+#endif
+
+ default:
+#ifdef DEBUG
+ if (c >= DBG_OFFSET)
+ {
+ base_debugging |= c - DBG_OFFSET;
+ continue;
+ }
+# undef DBG_OFFSET
+#endif
+ bad_case(c);
+ }
+ break;
+ }
+ if (optind != argc)
+ usage("unexpected argument");
+ reset_debugging();
+ lockfd = create_lock();
+
+ /* select between logging methods */
+
+ if (log_to_stderr_desired)
+ log_to_syslog = FALSE;
+ else
+ log_to_stderr = FALSE;
+
+ /* set the logging function of pfkey debugging */
+#ifdef DEBUG
+ pfkey_debug_func = DBG_log;
+#else
+ pfkey_debug_func = NULL;
+#endif
+
+ /* create control socket.
+ * We must create it before the parent process returns so that
+ * there will be no race condition in using it. The easiest
+ * place to do this is before the daemon fork.
+ */
+ {
+ err_t ugh = init_ctl_socket();
+
+ if (ugh != NULL)
+ {
+ fprintf(stderr, "pluto: %s", ugh);
+ exit_pluto(1);
+ }
+ }
+
+#ifdef IPSECPOLICY
+ /* create info socket. */
+ {
+ err_t ugh = init_info_socket();
+
+ if (ugh != NULL)
+ {
+ fprintf(stderr, "pluto: %s", ugh);
+ exit_pluto(1);
+ }
+ }
+#endif
+
+ /* If not suppressed, do daemon fork */
+
+ if (fork_desired)
+ {
+ {
+ pid_t pid = fork();
+
+ if (pid < 0)
+ {
+ int e = errno;
+
+ fprintf(stderr, "pluto: fork failed (%d %s)\n",
+ errno, strerror(e));
+ exit_pluto(1);
+ }
+
+ if (pid != 0)
+ {
+ /* parent: die, after filling PID into lock file.
+ * must not use exit_pluto: lock would be removed!
+ */
+ exit(fill_lock(lockfd, pid)? 0 : 1);
+ }
+ }
+
+ if (setsid() < 0)
+ {
+ int e = errno;
+
+ fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n",
+ errno, strerror(e));
+ exit_pluto(1);
+ }
+ }
+ else
+ {
+ /* no daemon fork: we have to fill in lock file */
+ (void) fill_lock(lockfd, getpid());
+ fprintf(stdout, "Pluto initialized\n");
+ fflush(stdout);
+ }
+
+ /* Close everything but ctl_fd and (if needed) stderr.
+ * There is some danger that a library that we don't know
+ * about is using some fd that we don't know about.
+ * I guess we'll soon find out.
+ */
+ {
+ int i;
+
+ for (i = getdtablesize() - 1; i >= 0; i--) /* Bad hack */
+ if ((!log_to_stderr || i != 2)
+#ifdef IPSECPOLICY
+ && i != info_fd
+#endif
+ && i != ctl_fd)
+ close(i);
+
+ /* make sure that stdin, stdout, stderr are reserved */
+ if (open("/dev/null", O_RDONLY) != 0)
+ abort();
+ if (dup2(0, 1) != 1)
+ abort();
+ if (!log_to_stderr && dup2(0, 2) != 2)
+ abort();
+ }
+
+ init_constants();
+ init_log("pluto");
+
+ /* Note: some scripts may look for this exact message -- don't change
+ * ipsec barf was one, but it no longer does.
+ */
+ plog("Starting Pluto (strongSwan Version %s%s)"
+ , ipsec_version_code()
+ , compile_time_interop_options);
+
+#ifdef NAT_TRAVERSAL
+ init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf);
+#endif
+
+#ifdef VIRTUAL_IP
+ init_virtual_ip(virtual_private);
+#endif
+ scx_init(pkcs11_module_path); /* load and initialize PKCS #11 module */
+ init_rnd_pool();
+ init_secret();
+ init_states();
+ init_crypto();
+ init_demux();
+ init_kernel();
+ init_adns();
+ init_id();
+ init_fetch();
+
+ /* loading X.509 CA certificates */
+ load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA);
+ /* loading X.509 AA certificates */
+ load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA);
+ /* loading X.509 OCSP certificates */
+ load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP);
+ /* loading X.509 CRLs */
+ load_crls();
+ /* loading attribute certificates (experimental) */
+ load_acerts();
+
+ daily_log_event();
+ call_server();
+ return -1; /* Shouldn't ever reach this */
+}
+
+/* leave pluto, with status.
+ * Once child is launched, parent must not exit this way because
+ * the lock would be released.
+ *
+ * 0 OK
+ * 1 general discomfort
+ * 10 lock file exists
+ */
+void
+exit_pluto(int status)
+{
+ reset_globals(); /* needed because we may be called in odd state */
+ free_preshared_secrets();
+ free_remembered_public_keys();
+ delete_every_connection();
+ free_crl_fetch(); /* free chain of crl fetch requests */
+ free_ocsp_fetch(); /* free chain of ocsp fetch requests */
+ free_authcerts(); /* free chain of X.509 authority certificates */
+ free_crls(); /* free chain of X.509 CRLs */
+ free_acerts(); /* free chain of X.509 attribute certificates */
+ free_ca_infos(); /* free chain of X.509 CA information records */
+ free_ocsp(); /* free ocsp cache */
+ free_ifaces();
+ scx_finalize(); /* finalize and unload PKCS #11 module */
+ stop_adns();
+ free_md_pool();
+ delete_lock();
+#ifdef LEAK_DETECTIVE
+ report_leaks();
+#endif /* LEAK_DETECTIVE */
+ close_log();
+ exit(status);
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/programs/pluto/primegen.c b/programs/pluto/primegen.c
new file mode 100644
index 000000000..159490345
--- /dev/null
+++ b/programs/pluto/primegen.c
@@ -0,0 +1,593 @@
+/* primegen.c - prime number generator
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * ***********************************************************************
+ * The algorithm used to generate practically save primes is due to
+ * Lim and Lee as described in the CRYPTO '97 proceedings (ISBN3540633847)
+ * page 260.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef PLUTO
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "rnd.h"
+#include "gcryptfix.h"
+#else /*! PLUTO */
+/* #include <assert.h> */
+/* #include <config.h> */
+/* #include "util.h" */
+/* #include "mpi.h" */
+/* #include "cipher.h" */
+#endif /* !PLUTO */
+
+static int no_of_small_prime_numbers;
+static MPI gen_prime( unsigned nbits, int mode, int randomlevel );
+static int check_prime( MPI prime, MPI val_2 );
+static int is_prime( MPI n, unsigned steps, int *count );
+static void m_out_of_n( char *array, int m, int n );
+
+
+static void
+progress( int c )
+{
+ fputc( c, stderr );
+}
+
+
+/****************
+ * Generate a prime number (stored in secure memory)
+ */
+MPI
+generate_secret_prime( unsigned nbits )
+{
+ MPI prime;
+
+ prime = gen_prime( nbits, 1, 2 );
+ progress('\n');
+ return prime;
+}
+
+MPI
+generate_public_prime( unsigned nbits )
+{
+ MPI prime;
+
+ prime = gen_prime( nbits, 0, 2 );
+ progress('\n');
+ return prime;
+}
+
+
+/****************
+ * We do not need to use the strongest RNG because we gain no extra
+ * security from it - The prime number is public and we could also
+ * offer the factors for those who are willing to check that it is
+ * indeed a strong prime.
+ *
+ * mode 0: Standard
+ * 1: Make sure that at least one factor is of size qbits.
+ */
+MPI
+generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
+ MPI g, MPI **ret_factors )
+{
+ int n; /* number of factors */
+ int m; /* number of primes in pool */
+ unsigned fbits; /* length of prime factors */
+ MPI *factors; /* current factors */
+ MPI *pool; /* pool of primes */
+ MPI q; /* first prime factor (variable)*/
+ MPI prime; /* prime test value */
+ MPI q_factor; /* used for mode 1 */
+ byte *perms = NULL;
+ int i, j;
+ int count1, count2;
+ unsigned nprime;
+ unsigned req_qbits = qbits; /* the requested q bits size */
+ MPI val_2 = mpi_alloc_set_ui( 2 );
+
+ /* find number of needed prime factors */
+ for(n=1; (pbits - qbits - 1) / n >= qbits; n++ )
+ ;
+ n--;
+ if( !n || (mode==1 && n < 2) )
+ log_fatal("can't gen prime with pbits=%u qbits=%u\n", pbits, qbits );
+ if( mode == 1 ) {
+ n--;
+ fbits = (pbits - 2*req_qbits -1) / n;
+ qbits = pbits - req_qbits - n*fbits;
+ }
+ else {
+ fbits = (pbits - req_qbits -1) / n;
+ qbits = pbits - n*fbits;
+ }
+ if( DBG_CIPHER )
+ log_debug("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n",
+ pbits, req_qbits, qbits, fbits, n );
+ prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB );
+ q = gen_prime( qbits, 0, 1 );
+ q_factor = mode==1? gen_prime( req_qbits, 0, 1 ) : NULL;
+
+ /* allocate an array to hold the factors + 2 for later usage */
+#ifdef PLUTO
+ m_alloc_ptrs_clear(factors, n+2);
+#else
+ factors = m_alloc_clear( (n+2) * sizeof *factors );
+#endif
+
+ /* make a pool of 3n+5 primes (this is an arbitrary value) */
+ m = n*3+5;
+ if( mode == 1 )
+ m += 5; /* need some more for DSA */
+ if( m < 25 )
+ m = 25;
+#ifdef PLUTO
+ m_alloc_ptrs_clear(pool, m);
+#else
+ pool = m_alloc_clear( m * sizeof *pool );
+#endif
+
+ /* permutate over the pool of primes */
+ count1=count2=0;
+ do {
+ next_try:
+ if( !perms ) {
+ /* allocate new primes */
+ for(i=0; i < m; i++ ) {
+ mpi_free(pool[i]);
+ pool[i] = NULL;
+ }
+ /* init m_out_of_n() */
+#ifdef PLUTO
+ perms = alloc_bytes( m, "perms" );
+#else
+ perms = m_alloc_clear( m );
+#endif
+ for(i=0; i < n; i++ ) {
+ perms[i] = 1;
+ pool[i] = gen_prime( fbits, 0, 1 );
+ factors[i] = pool[i];
+ }
+ }
+ else {
+ m_out_of_n( perms, n, m );
+ for(i=j=0; i < m && j < n ; i++ )
+ if( perms[i] ) {
+ if( !pool[i] )
+ pool[i] = gen_prime( fbits, 0, 1 );
+ factors[j++] = pool[i];
+ }
+ if( i == n ) {
+ m_free(perms); perms = NULL;
+ progress('!');
+ goto next_try; /* allocate new primes */
+ }
+ }
+
+ mpi_set( prime, q );
+ mpi_mul_ui( prime, prime, 2 );
+ if( mode == 1 )
+ mpi_mul( prime, prime, q_factor );
+ for(i=0; i < n; i++ )
+ mpi_mul( prime, prime, factors[i] );
+ mpi_add_ui( prime, prime, 1 );
+ nprime = mpi_get_nbits(prime);
+ if( nprime < pbits ) {
+ if( ++count1 > 20 ) {
+ count1 = 0;
+ qbits++;
+ progress('>');
+ q = gen_prime( qbits, 0, 1 );
+ goto next_try;
+ }
+ }
+ else
+ count1 = 0;
+ if( nprime > pbits ) {
+ if( ++count2 > 20 ) {
+ count2 = 0;
+ qbits--;
+ progress('<');
+ q = gen_prime( qbits, 0, 1 );
+ goto next_try;
+ }
+ }
+ else
+ count2 = 0;
+ } while( !(nprime == pbits && check_prime( prime, val_2 )) );
+
+ if( DBG_CIPHER ) {
+ progress('\n');
+ log_mpidump( "prime : ", prime );
+ log_mpidump( "factor q: ", q );
+ if( mode == 1 )
+ log_mpidump( "factor q0: ", q_factor );
+ for(i=0; i < n; i++ )
+ log_mpidump( "factor pi: ", factors[i] );
+ log_debug("bit sizes: prime=%u, q=%u", mpi_get_nbits(prime), mpi_get_nbits(q) );
+ if( mode == 1 )
+ fprintf(stderr, ", q0=%u", mpi_get_nbits(q_factor) );
+ for(i=0; i < n; i++ )
+ fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) );
+ progress('\n');
+ }
+
+ if( ret_factors ) { /* caller wants the factors */
+#ifdef PLUTO
+ m_alloc_ptrs_clear(*ret_factors, n+2);
+#else
+ *ret_factors = m_alloc_clear( (n+2) * sizeof **ret_factors);
+#endif
+ if( mode == 1 ) {
+ i = 0;
+ (*ret_factors)[i++] = mpi_copy( q_factor );
+ for(; i <= n; i++ )
+ (*ret_factors)[i] = mpi_copy( factors[i] );
+ }
+ else {
+ for(; i < n; i++ )
+ (*ret_factors)[i] = mpi_copy( factors[i] );
+ }
+ }
+
+ if( g ) { /* create a generator (start with 3)*/
+ MPI tmp = mpi_alloc( mpi_get_nlimbs(prime) );
+ MPI b = mpi_alloc( mpi_get_nlimbs(prime) );
+ MPI pmin1 = mpi_alloc( mpi_get_nlimbs(prime) );
+
+ if( mode == 1 )
+ BUG(); /* not yet implemented */
+ factors[n] = q;
+ factors[n+1] = mpi_alloc_set_ui(2);
+ mpi_sub_ui( pmin1, prime, 1 );
+ mpi_set_ui(g,2);
+ do {
+ mpi_add_ui(g, g, 1);
+ if( DBG_CIPHER ) {
+#ifdef PLUTO
+ log_mpidump("checking g: ", g);
+#else
+ log_debug("checking g: ");
+ mpi_print( stderr, g, 1 );
+#endif
+ }
+ else
+ progress('^');
+ for(i=0; i < n+2; i++ ) {
+ /*fputc('~', stderr);*/
+ mpi_fdiv_q(tmp, pmin1, factors[i] );
+ /* (no mpi_pow(), but it is okay to use this with mod prime) */
+ mpi_powm(b, g, tmp, prime );
+ if( !mpi_cmp_ui(b, 1) )
+ break;
+ }
+ if( DBG_CIPHER )
+ progress('\n');
+ } while( i < n+2 );
+ mpi_free(factors[n+1]);
+ mpi_free(tmp);
+ mpi_free(b);
+ mpi_free(pmin1);
+ }
+ if( !DBG_CIPHER )
+ progress('\n');
+
+ m_free( factors ); /* (factors are shallow copies) */
+ for(i=0; i < m; i++ )
+ mpi_free( pool[i] );
+ m_free( pool );
+ m_free(perms);
+ mpi_free(val_2);
+ return prime;
+}
+
+
+
+static MPI
+gen_prime( unsigned nbits, int secret, int randomlevel )
+{
+ unsigned nlimbs;
+ MPI prime, ptest, pminus1, val_2, val_3, result;
+ int i;
+ unsigned x, step;
+ unsigned count1, count2;
+ int *mods;
+
+ if( 0 && DBG_CIPHER )
+ log_debug("generate a prime of %u bits ", nbits );
+
+ if( !no_of_small_prime_numbers ) {
+ for(i=0; small_prime_numbers[i]; i++ )
+ no_of_small_prime_numbers++;
+ }
+ mods = m_alloc( no_of_small_prime_numbers * sizeof *mods );
+ /* make nbits fit into MPI implementation */
+ nlimbs = (nbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB;
+ val_2 = mpi_alloc_set_ui( 2 );
+ val_3 = mpi_alloc_set_ui( 3);
+ prime = secret? mpi_alloc_secure( nlimbs ): mpi_alloc( nlimbs );
+ result = mpi_alloc_like( prime );
+ pminus1= mpi_alloc_like( prime );
+ ptest = mpi_alloc_like( prime );
+ count1 = count2 = 0;
+ for(;;) { /* try forvever */
+ int dotcount=0;
+
+ /* generate a random number */
+ { char *p = get_random_bits( nbits, randomlevel, secret );
+ mpi_set_buffer( prime, p, (nbits+7)/8, 0 );
+ m_free(p);
+ }
+
+ /* set high order bit to 1, set low order bit to 1 */
+ mpi_set_highbit( prime, nbits-1 );
+ mpi_set_bit( prime, 0 );
+
+ /* calculate all remainders */
+ for(i=0; (x = small_prime_numbers[i]); i++ )
+ mods[i] = mpi_fdiv_r_ui(NULL, prime, x);
+
+ /* now try some primes starting with prime */
+ for(step=0; step < 20000; step += 2 ) {
+ /* check against all the small primes we have in mods */
+ count1++;
+ for(i=0; (x = small_prime_numbers[i]); i++ ) {
+ while( mods[i] + step >= x )
+ mods[i] -= x;
+ if( !(mods[i] + step) )
+ break;
+ }
+ if( x )
+ continue; /* found a multiple of an already known prime */
+
+ mpi_add_ui( ptest, prime, step );
+
+ /* do a faster Fermat test */
+ count2++;
+ mpi_sub_ui( pminus1, ptest, 1);
+ mpi_powm( result, val_2, pminus1, ptest );
+ if( !mpi_cmp_ui( result, 1 ) ) { /* not composite */
+ /* perform stronger tests */
+ if( is_prime(ptest, 5, &count2 ) ) {
+ if( !mpi_test_bit( ptest, nbits-1 ) ) {
+ progress('\n');
+ log_debug("overflow in prime generation\n");
+ break; /* step loop, continue with a new prime */
+ }
+
+ mpi_free(val_2);
+ mpi_free(val_3);
+ mpi_free(result);
+ mpi_free(pminus1);
+ mpi_free(prime);
+ m_free(mods);
+ return ptest;
+ }
+ }
+ if( ++dotcount == 10 ) {
+ progress('.');
+ dotcount = 0;
+ }
+ }
+ progress(':'); /* restart with a new random value */
+ }
+}
+
+/****************
+ * Returns: true if this may be a prime
+ */
+static int
+check_prime( MPI prime, MPI val_2 )
+{
+ int i;
+ unsigned x;
+ int count=0;
+
+ /* check against small primes */
+ for(i=0; (x = small_prime_numbers[i]); i++ ) {
+ if( mpi_divisible_ui( prime, x ) )
+ return 0;
+ }
+
+ /* a quick fermat test */
+ {
+ MPI result = mpi_alloc_like( prime );
+ MPI pminus1 = mpi_alloc_like( prime );
+ mpi_sub_ui( pminus1, prime, 1);
+ mpi_powm( result, val_2, pminus1, prime );
+ mpi_free( pminus1 );
+ if( mpi_cmp_ui( result, 1 ) ) { /* if composite */
+ mpi_free( result );
+ progress('.');
+ return 0;
+ }
+ mpi_free( result );
+ }
+
+ /* perform stronger tests */
+ if( is_prime(prime, 5, &count ) )
+ return 1; /* is probably a prime */
+ progress('.');
+ return 0;
+}
+
+
+/****************
+ * Return true if n is probably a prime
+ */
+static int
+is_prime( MPI n, unsigned steps, int *count )
+{
+ MPI x = mpi_alloc( mpi_get_nlimbs( n ) );
+ MPI y = mpi_alloc( mpi_get_nlimbs( n ) );
+ MPI z = mpi_alloc( mpi_get_nlimbs( n ) );
+ MPI nminus1 = mpi_alloc( mpi_get_nlimbs( n ) );
+ MPI a2 = mpi_alloc_set_ui( 2 );
+ MPI q;
+ unsigned i, j, k;
+ int rc = 0;
+ unsigned nbits = mpi_get_nbits( n );
+
+ mpi_sub_ui( nminus1, n, 1 );
+
+ /* find q and k, so that n = 1 + 2^k * q */
+ q = mpi_copy( nminus1 );
+ k = mpi_trailing_zeros( q );
+ mpi_tdiv_q_2exp(q, q, k);
+
+ for(i=0 ; i < steps; i++ ) {
+ ++*count;
+ if( !i ) {
+ mpi_set_ui( x, 2 );
+ }
+ else {
+ /*mpi_set_bytes( x, nbits-1, get_random_byte, 0 );*/
+ { char *p = get_random_bits( nbits, 0, 0 );
+ mpi_set_buffer( x, p, (nbits+7)/8, 0 );
+ m_free(p);
+ }
+ /* make sure that the number is smaller than the prime
+ * and keep the randomness of the high bit */
+ if( mpi_test_bit( x, nbits-2 ) ) {
+ mpi_set_highbit( x, nbits-2 ); /* clear all higher bits */
+ }
+ else {
+ mpi_set_highbit( x, nbits-2 );
+ mpi_clear_bit( x, nbits-2 );
+ }
+ assert( mpi_cmp( x, nminus1 ) < 0 && mpi_cmp_ui( x, 1 ) > 0 );
+ }
+ mpi_powm( y, x, q, n);
+ if( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) {
+ for( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) {
+ mpi_powm(y, y, a2, n);
+ if( !mpi_cmp_ui( y, 1 ) )
+ goto leave; /* not a prime */
+ }
+ if( mpi_cmp( y, nminus1 ) )
+ goto leave; /* not a prime */
+ }
+ progress('+');
+ }
+ rc = 1; /* may be a prime */
+
+ leave:
+ mpi_free( x );
+ mpi_free( y );
+ mpi_free( z );
+ mpi_free( nminus1 );
+ mpi_free( q );
+
+ return rc;
+}
+
+
+static void
+m_out_of_n( char *array, int m, int n )
+{
+ int i=0, i1=0, j=0, jp=0, j1=0, k1=0, k2=0;
+
+ if( !m || m >= n )
+ return;
+
+ if( m == 1 ) { /* special case */
+ for(i=0; i < n; i++ )
+ if( array[i] ) {
+ array[i++] = 0;
+ if( i >= n )
+ i = 0;
+ array[i] = 1;
+ return;
+ }
+ BUG();
+ }
+
+ for(j=1; j < n; j++ ) {
+ if( array[n-1] == array[n-j-1] )
+ continue;
+ j1 = j;
+ break;
+ }
+
+ if( m & 1 ) { /* m is odd */
+ if( array[n-1] ) {
+ if( j1 & 1 ) {
+ k1 = n - j1;
+ k2 = k1+2;
+ if( k2 > n )
+ k2 = n;
+ goto leave;
+ }
+ goto scan;
+ }
+ k2 = n - j1 - 1;
+ if( k2 == 0 ) {
+ k1 = i;
+ k2 = n - j1;
+ }
+ else if( array[k2] && array[k2-1] )
+ k1 = n;
+ else
+ k1 = k2 + 1;
+ }
+ else { /* m is even */
+ if( !array[n-1] ) {
+ k1 = n - j1;
+ k2 = k1 + 1;
+ goto leave;
+ }
+
+ if( !(j1 & 1) ) {
+ k1 = n - j1;
+ k2 = k1+2;
+ if( k2 > n )
+ k2 = n;
+ goto leave;
+ }
+ scan:
+ jp = n - j1 - 1;
+ for(i=1; i <= jp; i++ ) {
+ i1 = jp + 2 - i;
+ if( array[i1-1] ) {
+ if( array[i1-2] ) {
+ k1 = i1 - 1;
+ k2 = n - j1;
+ }
+ else {
+ k1 = i1 - 1;
+ k2 = n + 1 - j1;
+ }
+ goto leave;
+ }
+ }
+ k1 = 1;
+ k2 = n + 1 - m;
+ }
+ leave:
+ array[k1-1] = !array[k1-1];
+ array[k2-1] = !array[k2-1];
+}
+
diff --git a/programs/pluto/rcv_info.c b/programs/pluto/rcv_info.c
new file mode 100644
index 000000000..1f6127830
--- /dev/null
+++ b/programs/pluto/rcv_info.c
@@ -0,0 +1,308 @@
+/* info/policy communicating routines
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: rcv_info.c,v 1.2 2004/04/01 18:44:38 as Exp $
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "connections.h"
+#include "foodgroups.h"
+#include "whack.h" /* needs connections.h */
+#include "packet.h"
+#include "demux.h" /* needs packet.h */
+#include "state.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "kernel.h"
+#include "rcv_whack.h"
+#include "log.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "server.h"
+
+#include "freeswan/ipsec_policy.h"
+#include "rcv_info.h"
+
+/* global */
+int info_fd = -1;
+
+static void
+info_lookuphostpair(struct ipsec_policy_cmd_query *ipcq)
+{
+ struct connection *c;
+ struct state *p1st, *p2st;
+
+
+ /* default result: no crypto */
+ ipcq->strength = IPSEC_PRIVACY_NONE;
+ ipcq->bandwidth = IPSEC_QOS_WIRESPEED;
+ ipcq->credential_count = 0;
+
+#ifdef DEBUG
+ {
+ char sstr[ADDRTOT_BUF], dstr[ADDRTOT_BUF];
+
+ addrtot(&ipcq->query_local, 0, sstr, sizeof(sstr));
+ addrtot(&ipcq->query_remote, 0, dstr, sizeof(dstr));
+ DBG_log("info request for %s -> %s", sstr, dstr);
+ }
+#endif
+
+ /* okay, look up what connection handles this ip pair */
+
+ c = find_connection_for_clients(NULL,
+ &ipcq->query_local,
+ &ipcq->query_remote);
+ if (c == NULL)
+ {
+ /* try reversing it */
+ c = find_connection_for_clients(NULL,
+ &ipcq->query_remote,
+ &ipcq->query_local);
+ if (c != NULL)
+ {
+ ip_address tmp;
+ tmp = ipcq->query_local;
+ ipcq->query_local = ipcq->query_remote;
+ ipcq->query_remote = tmp;
+ }
+ }
+
+ if (c == NULL)
+ {
+#ifdef DEBUG
+ DBG_log("no connection found");
+#endif
+ return; /* no crypto */
+ }
+
+ if (c->newest_ipsec_sa == SOS_NOBODY)
+ {
+ ip_subnet us, them;
+
+ DBG_log("connection %s found, no ipsec state, looking again", c->name);
+ addrtosubnet(&ipcq->query_local, &us);
+ addrtosubnet(&ipcq->query_remote, &them);
+ c = find_client_connection(c, &us, &them);
+
+ if (c == NULL)
+ return; /* no crypto */
+ }
+
+ DBG_log("connection %s[%ld] with state %u"
+ , c->name, c->instance_serial
+ , (unsigned int)c->newest_ipsec_sa);
+
+ if (c->newest_ipsec_sa == SOS_NOBODY)
+ return; /* no crypto */
+
+ /* we found a connection, try to lookup the state */
+ p2st = state_with_serialno(c->newest_ipsec_sa);
+
+ p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES);
+
+ if (p1st == NULL || p2st == NULL)
+ {
+ DBG_log("connection %s[%ld] has missing states %s %s"
+ , c->name, c->instance_serial
+ , (p1st ? "phase1" : "")
+ , (p2st ? "phase1" : ""));
+ return; /* no crypto */
+ }
+
+ /* if we have AH present, then record minimal info */
+ if (p2st->st_ah.present)
+ {
+ ipcq->strength = IPSEC_PRIVACY_INTEGRAL;
+ ipcq->auth_detail = p2st->st_esp.attrs.auth;
+ }
+
+ if (p2st->st_esp.present)
+ {
+ /*
+ * XXX-mcr Please do not shout at me about relative strengths
+ * here. I'm not a cryptographer. I just diddle bits.
+ */
+ switch (p2st->st_esp.attrs.transid)
+ {
+ case ESP_NULL:
+ /* actually, do not change it if we set it from AH */
+ break;
+
+ case ESP_DES:
+ case ESP_DES_IV64:
+ case ESP_DES_IV32:
+ case ESP_RC4:
+ ipcq->strength = IPSEC_PRIVACY_ROT13;
+ break;
+
+ case ESP_RC5:
+ case ESP_IDEA:
+ case ESP_CAST:
+ case ESP_BLOWFISH:
+ case ESP_3DES:
+ ipcq->strength = IPSEC_PRIVACY_PRIVATE;
+ ipcq->bandwidth = IPSEC_QOS_VOIP;
+ break;
+
+ case ESP_3IDEA:
+ ipcq->strength = IPSEC_PRIVACY_STRONG;
+ ipcq->bandwidth = IPSEC_QOS_INTERACTIVE;
+ break;
+
+ case ESP_AES:
+ ipcq->strength = IPSEC_PRIVACY_STRONG;
+ ipcq->bandwidth = IPSEC_QOS_FTP;
+ break;
+ }
+ ipcq->esp_detail = p2st->st_esp.attrs.transid;
+ }
+
+ if (p2st->st_ipcomp.present)
+ ipcq->comp_detail = p2st->st_esp.attrs.transid;
+
+ /* now! the credentails that were used */
+ /* for the moment we only have 1 credential, the DNS name,
+ * because the DNS servers do not return the chain of SIGs yet
+ */
+
+ if(!c->spd.this.key_from_DNS_on_demand)
+ {
+ /* the key didn't come from the DNS in some way,
+ * so it must have been loaded locally.
+ */
+ ipcq->credential_count = 1;
+ ipcq->credentials[0].ii_type = c->spd.this.id.kind;
+ ipcq->credentials[0].ii_format = CERT_RAW_RSA;
+ }
+
+#if 0
+ switch (c->spd.id.kind)
+ {
+ case ID_IPV4_ADDR:
+ }
+ if (c->gw_info == NULL)
+ {
+ plog("rcv_info: connection %s had NULL gw_info.", c->name);
+ return
+ }
+#endif
+
+ ipcq->credential_count = 1;
+
+ /* pull credentials out of gw_info */
+
+ switch (p1st->st_peer_pubkey->dns_auth_level)
+ {
+ case DAL_UNSIGNED:
+ case DAL_NOTSEC:
+ /* these seem to be the same for this purpose */
+ ipcq->credentials[0].ii_type = p1st->st_peer_pubkey->id.kind;
+ ipcq->credentials[0].ii_type = CERT_NONE;
+ idtoa(&p1st->st_peer_pubkey->id
+ , ipcq->credentials[0].ii_credential.ipsec_dns_signed.fqdn
+ , sizeof(ipcq->credentials[0].ii_credential.ipsec_dns_signed.fqdn));
+ break;
+
+ case DAL_SIGNED:
+ ipcq->credentials[0].ii_type = p1st->st_peer_pubkey->id.kind;
+ ipcq->credentials[0].ii_format = CERT_DNS_SIGNED_KEY;
+ idtoa(&p1st->st_peer_pubkey->id
+ , ipcq->credentials[0].ii_credential.ipsec_dns_signed.fqdn
+ , sizeof(ipcq->credentials[0].ii_credential.ipsec_dns_signed.fqdn));
+
+ if (p1st->st_peer_pubkey->dns_sig != NULL)
+ {
+ strncat(ipcq->credentials[0].ii_credential.ipsec_dns_signed.dns_sig
+ , p1st->st_peer_pubkey->dns_sig
+ , sizeof(ipcq->credentials[0].ii_credential.ipsec_dns_signed.dns_sig));
+ }
+ break;
+
+ case DAL_LOCAL:
+ ipcq->credentials[0].ii_type = p1st->st_peer_pubkey->id.kind;
+ ipcq->credentials[0].ii_format = CERT_RAW_RSA;
+ idtoa(&p1st->st_peer_pubkey->id
+ , ipcq->credentials[0].ii_credential.ipsec_raw_key.id_name
+ , sizeof(ipcq->credentials[0].ii_credential.ipsec_raw_key.id_name));
+ break;
+ }
+}
+
+/*
+ * Handle an info/policy request.
+ *
+ * For now, we close the socket after answering the request.
+ *
+ */
+void
+info_handle(int infoctlfd)
+{
+ struct sockaddr_un info_client_addr;
+ int info_addr_len = sizeof(info_client_addr);
+ /* Note: actual value in n should fit in int. To print, cast to int. */
+ int infofd;
+ err_t err;
+ struct ipsec_policy_cmd_query ipcq;
+
+ infofd = accept(infoctlfd, (struct sockaddr *)&info_client_addr
+ , &info_addr_len);
+
+ if (infofd < 0)
+ {
+ log_errno((e, "accept() failed in info_handle()"));
+ return;
+ }
+
+ err = ipsec_policy_readmsg(infofd, (unsigned char *)&ipcq, sizeof(ipcq));
+
+ if (err != NULL)
+ {
+ log_errno((e, "readmsg said: %s", err));
+ close(infofd);
+ return;
+ }
+
+ switch (ipcq.head.ipm_msg_type)
+ {
+ case IPSEC_CMD_QUERY_HOSTPAIR:
+ info_lookuphostpair(&ipcq);
+ write(infofd, &ipcq, ipcq.head.ipm_msg_len);
+ break;
+
+ default:
+ plog("got unimplemented msg type: %d", ipcq.head.ipm_msg_type);
+ break;
+ }
+
+ /* for now, close the socket */
+ close(infofd);
+}
diff --git a/programs/pluto/rcv_info.h b/programs/pluto/rcv_info.h
new file mode 100644
index 000000000..b5eaef219
--- /dev/null
+++ b/programs/pluto/rcv_info.h
@@ -0,0 +1,18 @@
+/* whack communicating routines
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: rcv_info.h,v 1.1 2004/03/15 20:35:29 as Exp $
+ */
+
+#include "freeswan/ipsec_policy.h"
+extern void info_handle(int infoctlfd);
diff --git a/programs/pluto/rcv_whack.c b/programs/pluto/rcv_whack.c
new file mode 100644
index 000000000..164a4f249
--- /dev/null
+++ b/programs/pluto/rcv_whack.c
@@ -0,0 +1,655 @@
+/* whack communicating routines
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: rcv_whack.c,v 1.17 2005/12/25 12:41:23 as Exp $
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+#include <fcntl.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "ca.h"
+#include "certs.h"
+#include "ac.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "foodgroups.h"
+#include "whack.h" /* needs connections.h */
+#include "packet.h"
+#include "demux.h" /* needs packet.h */
+#include "state.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "kernel.h"
+#include "rcv_whack.h"
+#include "log.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "server.h"
+#include "fetch.h"
+#include "ocsp.h"
+#include "crl.h"
+
+#include "kernel_alg.h"
+#include "ike_alg.h"
+/* helper variables and function to decode strings from whack message */
+
+static char *next_str
+ , *str_roof;
+
+static bool
+unpack_str(char **p)
+{
+ char *end = memchr(next_str, '\0', str_roof - next_str);
+
+ if (end == NULL)
+ {
+ return FALSE; /* fishy: no end found */
+ }
+ else
+ {
+ *p = next_str == end? NULL : next_str;
+ next_str = end + 1;
+ return TRUE;
+ }
+}
+
+/* bits loading keys from asynchronous DNS */
+
+enum key_add_attempt {
+ ka_TXT,
+#ifdef USE_KEYRR
+ ka_KEY,
+#endif
+ ka_roof /* largest value + 1 */
+};
+
+struct key_add_common {
+ int refCount;
+ char *diag[ka_roof];
+ int whack_fd;
+ bool success;
+};
+
+struct key_add_continuation {
+ struct adns_continuation ac; /* common prefix */
+ struct key_add_common *common; /* common data */
+ enum key_add_attempt lookingfor;
+};
+
+static void
+key_add_ugh(const struct id *keyid, err_t ugh)
+{
+ char name[BUF_LEN]; /* longer IDs will be truncated in message */
+
+ (void)idtoa(keyid, name, sizeof(name));
+ loglog(RC_NOKEY
+ , "failure to fetch key for %s from DNS: %s", name, ugh);
+}
+
+/* last one out: turn out the lights */
+static void
+key_add_merge(struct key_add_common *oc, const struct id *keyid)
+{
+ if (oc->refCount == 0)
+ {
+ enum key_add_attempt kaa;
+
+ /* if no success, print all diagnostics */
+ if (!oc->success)
+ for (kaa = ka_TXT; kaa != ka_roof; kaa++)
+ key_add_ugh(keyid, oc->diag[kaa]);
+
+ for (kaa = ka_TXT; kaa != ka_roof; kaa++)
+ pfreeany(oc->diag[kaa]);
+
+ close(oc->whack_fd);
+ pfree(oc);
+ }
+}
+
+static void
+key_add_continue(struct adns_continuation *ac, err_t ugh)
+{
+ struct key_add_continuation *kc = (void *) ac;
+ struct key_add_common *oc = kc->common;
+
+ passert(whack_log_fd == NULL_FD);
+ whack_log_fd = oc->whack_fd;
+
+ if (ugh != NULL)
+ {
+ oc->diag[kc->lookingfor] = clone_str(ugh, "key add error");
+ }
+ else
+ {
+ oc->success = TRUE;
+ transfer_to_public_keys(kc->ac.gateways_from_dns
+#ifdef USE_KEYRR
+ , &kc->ac.keys_from_dns
+#endif /* USE_KEYRR */
+ );
+ }
+
+ oc->refCount--;
+ key_add_merge(oc, &ac->id);
+ whack_log_fd = NULL_FD;
+}
+
+static void
+key_add_request(const whack_message_t *msg)
+{
+ struct id keyid;
+ err_t ugh = atoid(msg->keyid, &keyid, FALSE);
+
+ if (ugh != NULL)
+ {
+ loglog(RC_BADID, "bad --keyid \"%s\": %s", msg->keyid, ugh);
+ }
+ else
+ {
+ if (!msg->whack_addkey)
+ delete_public_keys(&keyid, msg->pubkey_alg
+ , empty_chunk, empty_chunk);
+
+ if (msg->keyval.len == 0)
+ {
+ struct key_add_common *oc
+ = alloc_thing(struct key_add_common
+ , "key add common things");
+ enum key_add_attempt kaa;
+
+ /* initialize state shared by queries */
+ oc->refCount = 0;
+ oc->whack_fd = dup_any(whack_log_fd);
+ oc->success = FALSE;
+
+ for (kaa = ka_TXT; kaa != ka_roof; kaa++)
+ {
+ struct key_add_continuation *kc
+ = alloc_thing(struct key_add_continuation
+ , "key add continuation");
+
+ oc->diag[kaa] = NULL;
+ oc->refCount++;
+ kc->common = oc;
+ kc->lookingfor = kaa;
+ switch (kaa)
+ {
+ case ka_TXT:
+ ugh = start_adns_query(&keyid
+ , &keyid /* same */
+ , T_TXT
+ , key_add_continue
+ , &kc->ac);
+ break;
+#ifdef USE_KEYRR
+ case ka_KEY:
+ ugh = start_adns_query(&keyid
+ , NULL
+ , T_KEY
+ , key_add_continue
+ , &kc->ac);
+ break;
+#endif /* USE_KEYRR */
+ default:
+ bad_case(kaa); /* suppress gcc warning */
+ }
+ if (ugh != NULL)
+ {
+ oc->diag[kaa] = clone_str(ugh, "early key add failure");
+ oc->refCount--;
+ }
+ }
+
+ /* Done launching queries.
+ * Handle total failure case.
+ */
+ key_add_merge(oc, &keyid);
+ }
+ else
+ {
+ ugh = add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg
+ , &msg->keyval, &pubkeys);
+ if (ugh != NULL)
+ loglog(RC_LOG_SERIOUS, "%s", ugh);
+ }
+ }
+}
+
+/* Handle a kernel request. Supposedly, there's a message in
+ * the kernelsock socket.
+ */
+void
+whack_handle(int whackctlfd)
+{
+ whack_message_t msg;
+ struct sockaddr_un whackaddr;
+ int whackaddrlen = sizeof(whackaddr);
+ int whackfd = accept(whackctlfd, (struct sockaddr *)&whackaddr, &whackaddrlen);
+ /* Note: actual value in n should fit in int. To print, cast to int. */
+ ssize_t n;
+
+ if (whackfd < 0)
+ {
+ log_errno((e, "accept() failed in whack_handle()"));
+ return;
+ }
+ if (fcntl(whackfd, F_SETFD, FD_CLOEXEC) < 0)
+ {
+ log_errno((e, "failed to set CLOEXEC in whack_handle()"));
+ close(whackfd);
+ return;
+ }
+
+ n = read(whackfd, &msg, sizeof(msg));
+
+ if (n == -1)
+ {
+ log_errno((e, "read() failed in whack_handle()"));
+ close(whackfd);
+ return;
+ }
+
+ whack_log_fd = whackfd;
+
+ /* sanity check message */
+ {
+ err_t ugh = NULL;
+
+ next_str = msg.string;
+ str_roof = (char *)&msg + n;
+
+ if ((size_t)n < offsetof(whack_message_t, whack_shutdown) + sizeof(msg.whack_shutdown))
+ {
+ ugh = builddiag("ignoring runt message from whack: got %d bytes", (int)n);
+ }
+ else if (msg.magic != WHACK_MAGIC)
+ {
+ if (msg.magic == WHACK_BASIC_MAGIC)
+ {
+ /* Only shutdown command. Simpler inter-version compatability. */
+ if (msg.whack_shutdown)
+ {
+ plog("shutting down");
+ exit_pluto(0); /* delete lock and leave, with 0 status */
+ }
+ ugh = ""; /* bail early, but without complaint */
+ }
+ else
+ {
+ ugh = builddiag("ignoring message from whack with bad magic %d; should be %d; probably wrong version"
+ , msg.magic, WHACK_MAGIC);
+ }
+ }
+ else if (next_str > str_roof)
+ {
+ ugh = builddiag("ignoring truncated message from whack: got %d bytes; expected %u"
+ , (int) n, (unsigned) sizeof(msg));
+ }
+ else if (!unpack_str(&msg.name) /* string 1 */
+ || !unpack_str(&msg.left.id) /* string 2 */
+ || !unpack_str(&msg.left.cert) /* string 3 */
+ || !unpack_str(&msg.left.ca) /* string 4 */
+ || !unpack_str(&msg.left.groups) /* string 5 */
+ || !unpack_str(&msg.left.updown) /* string 6 */
+#ifdef VIRTUAL_IP
+ || !unpack_str(&msg.left.virt)
+#endif
+ || !unpack_str(&msg.right.id) /* string 7 */
+ || !unpack_str(&msg.right.cert) /* string 8 */
+ || !unpack_str(&msg.right.ca) /* string 9 */
+ || !unpack_str(&msg.right.groups) /* string 10 */
+ || !unpack_str(&msg.right.updown) /* string 11 */
+#ifdef VIRTUAL_IP
+ || !unpack_str(&msg.right.virt)
+#endif
+ || !unpack_str(&msg.keyid) /* string 12 */
+ || !unpack_str(&msg.myid) /* string 13 */
+ || !unpack_str(&msg.cacert) /* string 14 */
+ || !unpack_str(&msg.ldaphost) /* string 15 */
+ || !unpack_str(&msg.ldapbase) /* string 16 */
+ || !unpack_str(&msg.crluri) /* string 17 */
+ || !unpack_str(&msg.crluri2) /* string 18 */
+ || !unpack_str(&msg.ocspuri) /* string 19 */
+ || !unpack_str(&msg.ike) /* string 20 */
+ || !unpack_str(&msg.esp) /* string 21 */
+ || !unpack_str(&msg.sc_data) /* string 22 */
+ || str_roof - next_str != (ptrdiff_t)msg.keyval.len) /* check chunk */
+ {
+ ugh = "message from whack contains bad string";
+ }
+ else
+ {
+ msg.keyval.ptr = next_str; /* grab chunk */
+ }
+
+ if (ugh != NULL)
+ {
+ if (*ugh != '\0')
+ loglog(RC_BADWHACKMESSAGE, "%s", ugh);
+ whack_log_fd = NULL_FD;
+ close(whackfd);
+ return;
+ }
+ }
+
+ if (msg.whack_options)
+ {
+#ifdef DEBUG
+ if (msg.name == NULL)
+ {
+ /* we do a two-step so that if either old or new would
+ * cause the message to print, it will be printed.
+ */
+ cur_debugging |= msg.debugging;
+ DBG(DBG_CONTROL
+ , DBG_log("base debugging = %s"
+ , bitnamesof(debug_bit_names, msg.debugging)));
+ cur_debugging = base_debugging = msg.debugging;
+ }
+ else if (!msg.whack_connection)
+ {
+ struct connection *c = con_by_name(msg.name, TRUE);
+
+ if (c != NULL)
+ {
+ c->extra_debugging = msg.debugging;
+ DBG(DBG_CONTROL
+ , DBG_log("\"%s\" extra_debugging = %s"
+ , c->name
+ , bitnamesof(debug_bit_names, c->extra_debugging)));
+ }
+ }
+#endif
+ }
+
+ if (msg.whack_myid)
+ set_myid(MYID_SPECIFIED, msg.myid);
+
+ /* Deleting combined with adding a connection works as replace.
+ * To make this more useful, in only this combination,
+ * delete will silently ignore the lack of the connection.
+ */
+ if (msg.whack_delete)
+ {
+ if (msg.whack_ca)
+ find_ca_info_by_name(msg.name, TRUE);
+ else
+ delete_connections_by_name(msg.name, !msg.whack_connection);
+ }
+
+ if (msg.whack_deletestate)
+ {
+ struct state *st = state_with_serialno(msg.whack_deletestateno);
+
+ if (st == NULL)
+ {
+ loglog(RC_UNKNOWN_NAME, "no state #%lu to delete"
+ , msg.whack_deletestateno);
+ }
+ else
+ {
+ delete_state(st);
+ }
+ }
+
+ if (msg.whack_crash)
+ delete_states_by_peer(&msg.whack_crash_peer);
+
+ if (msg.whack_connection)
+ add_connection(&msg);
+
+ if (msg.whack_ca && msg.cacert != NULL)
+ add_ca_info(&msg);
+
+ /* process "listen" before any operation that could require it */
+ if (msg.whack_listen)
+ {
+ close_peerlog(); /* close any open per-peer logs */
+ plog("listening for IKE messages");
+ listening = TRUE;
+ daily_log_reset();
+ reset_adns_restart_count();
+ set_myFQDN();
+ find_ifaces();
+ load_preshared_secrets(NULL_FD);
+ load_groups();
+ }
+ if (msg.whack_unlisten)
+ {
+ plog("no longer listening for IKE messages");
+ listening = FALSE;
+ }
+
+ if (msg.whack_reread & REREAD_SECRETS)
+ {
+ load_preshared_secrets(whackfd);
+ }
+
+ if (msg.whack_reread & REREAD_CACERTS)
+ {
+ load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA);
+ }
+
+ if (msg.whack_reread & REREAD_AACERTS)
+ {
+ load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA);
+ }
+
+ if (msg.whack_reread & REREAD_OCSPCERTS)
+ {
+ load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP);
+ }
+
+ if (msg.whack_reread & REREAD_ACERTS)
+ {
+ load_acerts();
+ }
+
+ if (msg.whack_reread & REREAD_CRLS)
+ {
+ load_crls();
+ }
+
+ if (msg.whack_purgeocsp)
+ {
+ free_ocsp_fetch();
+ free_ocsp_cache();
+ }
+
+ if (msg.whack_list & LIST_ALGS)
+ {
+ ike_alg_list();
+ kernel_alg_list();
+ }
+ if (msg.whack_list & LIST_PUBKEYS)
+ {
+ list_public_keys(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CERTS)
+ {
+ list_certs(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CACERTS)
+ {
+ list_authcerts("CA", AUTH_CA, msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_AACERTS)
+ {
+ list_authcerts("AA", AUTH_AA, msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_OCSPCERTS)
+ {
+ list_authcerts("OCSP", AUTH_OCSP, msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_ACERTS)
+ {
+ list_acerts(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_GROUPS)
+ {
+ list_groups(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CAINFOS)
+ {
+ list_ca_infos(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CRLS)
+ {
+ list_crls(msg.whack_utc, strict_crl_policy);
+ list_crl_fetch_requests(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_OCSP)
+ {
+ list_ocsp_cache(msg.whack_utc, strict_crl_policy);
+ list_ocsp_fetch_requests(msg.whack_utc);
+ }
+
+ if (msg.whack_list & LIST_CARDS)
+ {
+ scx_list(msg.whack_utc);
+ }
+
+ if (msg.whack_key)
+ {
+ /* add a public key */
+ key_add_request(&msg);
+ }
+
+ if (msg.whack_route)
+ {
+ if (!listening)
+ whack_log(RC_DEAF, "need --listen before --route");
+ else
+ {
+ struct connection *c = con_by_name(msg.name, TRUE);
+
+ if (c != NULL)
+ {
+ set_cur_connection(c);
+ if (!oriented(*c))
+ whack_log(RC_ORIENT
+ , "we have no ipsecN interface for either end of this connection");
+ else if (c->policy & POLICY_GROUP)
+ route_group(c);
+ else if (!trap_connection(c))
+ whack_log(RC_ROUTE, "could not route");
+ reset_cur_connection();
+ }
+ }
+ }
+
+ if (msg.whack_unroute)
+ {
+ struct connection *c = con_by_name(msg.name, TRUE);
+
+ if (c != NULL)
+ {
+ struct spd_route *sr;
+ int fail = 0;
+
+ set_cur_connection(c);
+
+ for (sr = &c->spd; sr != NULL; sr = sr->next)
+ {
+ if (sr->routing >= RT_ROUTED_TUNNEL)
+ fail++;
+ }
+ if (fail > 0)
+ whack_log(RC_RTBUSY, "cannot unroute: route busy");
+ else if (c->policy & POLICY_GROUP)
+ unroute_group(c);
+ else
+ unroute_connection(c);
+ reset_cur_connection();
+ }
+ }
+
+ if (msg.whack_initiate)
+ {
+ if (!listening)
+ whack_log(RC_DEAF, "need --listen before --initiate");
+ else
+ initiate_connection(msg.name
+ , msg.whack_async? NULL_FD : dup_any(whackfd));
+ }
+
+ if (msg.whack_oppo_initiate)
+ {
+ if (!listening)
+ whack_log(RC_DEAF, "need --listen before opportunistic initiation");
+ else
+ initiate_opportunistic(&msg.oppo_my_client, &msg.oppo_peer_client, 0
+ , FALSE
+ , msg.whack_async? NULL_FD : dup_any(whackfd));
+ }
+
+ if (msg.whack_terminate)
+ terminate_connection(msg.name);
+
+ if (msg.whack_status)
+ show_status(msg.whack_statusall, msg.name);
+
+ if (msg.whack_shutdown)
+ {
+ plog("shutting down");
+ exit_pluto(0); /* delete lock and leave, with 0 status */
+ }
+
+ if (msg.whack_sc_op != SC_OP_NONE)
+ {
+ if (pkcs11_proxy)
+ scx_op_via_whack(msg.sc_data, msg.inbase, msg.outbase
+ , msg.whack_sc_op, msg.keyid, whackfd);
+ else
+ plog("pkcs11 access to smartcard not allowed (set pkcs11proxy=yes)");
+ }
+
+ whack_log_fd = NULL_FD;
+ close(whackfd);
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * c-style: pluto
+ * End:
+ */
diff --git a/programs/pluto/rcv_whack.h b/programs/pluto/rcv_whack.h
new file mode 100644
index 000000000..f42761c51
--- /dev/null
+++ b/programs/pluto/rcv_whack.h
@@ -0,0 +1,17 @@
+/* whack communicating routines
+ * Copyright (C) 1998, 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: rcv_whack.h,v 1.1 2004/03/15 20:35:29 as Exp $
+ */
+
+extern void whack_handle(int kernelfd);
diff --git a/programs/pluto/rnd.c b/programs/pluto/rnd.c
new file mode 100644
index 000000000..da72cc8ff
--- /dev/null
+++ b/programs/pluto/rnd.c
@@ -0,0 +1,250 @@
+/* randomness machinery
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: rnd.c,v 1.3 2005/09/08 16:26:30 as Exp $
+ */
+
+/* A true random number generator (we hope)
+ *
+ * Under LINUX ("linux" predefined), use /dev/urandom.
+ * Under OpenBSD ("__OpenBSD__" predefined), use arc4random().
+ * Otherwise use our own random number generator based on clock skew.
+ * I (ADK) first heard of the idea from John Ioannidis, who heard it
+ * from Matt Blaze and/or Jack Lacy.
+ * ??? Why is mixing need for linux but not OpenBSD?
+ */
+
+/* Pluto's uses of randomness:
+ *
+ * - Setting up the "secret_of_the_day". This changes every hour! 20
+ * bytes a shot. It is used in building responder cookies.
+ *
+ * - generating initiator cookies (8 bytes, once per Phase 1 initiation).
+ *
+ * - 32 bytes per DH local secret. Once per Main Mode exchange and once
+ * per Quick Mode Exchange with PFS. (Size is our choice, with
+ * tradeoffs.)
+ *
+ * - 16 bytes per nonce we generate. Once per Main Mode exchange and
+ * once per Quick Mode exchange. (Again, we choose the size.)
+ *
+ * - 4 bytes per SPI number that we generate. We choose the SPIs for all
+ * inbound SPIs, one to three per IPSEC SA (one for AH (rare, probably)
+ * one for ESP (almost always), and one for tunnel (very common)).
+ * I don't actually know how the kernel would generate these numbers --
+ * currently Pluto generates them; this isn't the way things will be
+ * done in the future.
+ *
+ * - 4 bytes per Message ID we need to generate. One per Quick Mode
+ * exchange. Eventually, one per informational exchange.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+#include <freeswan.h>
+
+#include "sha1.h"
+#include "constants.h"
+#include "defs.h"
+#include "rnd.h"
+#include "log.h"
+#include "timer.h"
+
+#ifdef linux
+# define USE_DEV_RANDOM 1
+# define RANDOM_PATH "/dev/urandom"
+#else
+# ifdef __OpenBSD__
+# define USE_ARC4RANDOM
+# else
+# define USE_CLOCK_SLEW
+# endif
+#endif
+
+#ifdef USE_ARC4RANDOM
+
+#define get_rnd_byte() (arc4random() % 256)
+
+#else /**** start of large #else ****/
+
+#ifdef USE_DEV_RANDOM
+static int random_fd = NULL_FD;
+#endif
+
+#define RANDOM_POOL_SIZE SHA1_DIGEST_SIZE
+static u_char random_pool[RANDOM_POOL_SIZE];
+
+#ifdef USE_DEV_RANDOM
+
+/* Generate (what we hope is) a true random byte using /dev/urandom */
+static u_char
+generate_rnd_byte(void)
+{
+ u_char c;
+
+ if (read(random_fd, &c, sizeof(c)) == -1)
+ exit_log_errno((e, "read() failed in get_rnd_byte()"));
+
+ return c;
+}
+
+#else /* !USE_DEV_RANDOM */
+
+/* Generate (what we hope is) a true random byte using the clock skew trick.
+ * Note: this code is not maintained! In particular, LINUX signal(2)
+ * semantics changed with glibc2 (and not for the better). It isn't clear
+ * that this code will work. We keep the code because someday it might
+ * come in handy.
+ */
+# error "This code is not maintained. Please define USE_DEV_RANDOM."
+
+static volatile sig_atomic_t i, j, k;
+
+/* timer signal handler */
+static void
+rnd_handler(int ignore_me UNUSED)
+{
+ k <<= 1; /* Shift left by 1 */
+ j++;
+ k |= (i & 0x1); /* Get lsbit of counter */
+
+ if (j != 8)
+ signal(SIGVTALRM, rnd_handler);
+}
+
+static u_char
+generate_rnd_byte(void)
+{
+ struct itimerval tmval, ntmval;
+
+# ifdef NEVER /* ??? */
+# ifdef linux
+ int mask = siggetmask();
+
+ mask |= SIGVTALRM;
+ sigsetmask(mask);
+# endif
+# endif
+
+ i = 0;
+ j = 0;
+
+ ntmval.it_interval.tv_sec = 0;
+ ntmval.it_interval.tv_usec = 1;
+ ntmval.it_value.tv_sec = 0;
+ ntmval.it_value.tv_usec = 1;
+ signal(SIGVTALRM, rnd_handler);
+ setitimer(ITIMER_VIRTUAL, &ntmval, &tmval);
+
+ while (j != 8)
+ i++;
+
+ setitimer(ITIMER_VIRTUAL, &tmval, &ntmval);
+ signal(SIGVTALRM, SIG_IGN);
+
+# ifdef NEVER /* ??? */
+# ifdef linux
+ mask ^= SIGVTALRM;
+ sigsetmask(mask);
+# endif
+# endif
+
+ return k;
+}
+
+#endif /* !USE_DEV_RANDOM */
+
+static void
+mix_pool(void)
+{
+ SHA1_CTX ctx;
+
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, random_pool, RANDOM_POOL_SIZE);
+ SHA1Final(random_pool, &ctx);
+}
+
+/*
+ * Get a single random byte.
+ */
+static u_char
+get_rnd_byte(void)
+{
+ random_pool[RANDOM_POOL_SIZE - 1] = generate_rnd_byte();
+ random_pool[0] = generate_rnd_byte();
+ mix_pool();
+ return random_pool[0];
+}
+
+#endif /* !USE_ARC4RANDOM */ /**** end of large #else ****/
+
+void
+get_rnd_bytes(u_char *buffer, int length)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ buffer[i] = get_rnd_byte();
+}
+
+/*
+ * Initialize the random pool.
+ */
+void
+init_rnd_pool(void)
+{
+#ifndef USE_ARC4RANDOM
+# ifdef USE_DEV_RANDOM
+ DBG(DBG_KLIPS, DBG_log("opening %s", RANDOM_PATH));
+ random_fd = open(RANDOM_PATH, O_RDONLY);
+ if (random_fd == -1)
+ exit_log_errno((e, "open of %s failed in init_rnd_pool()", RANDOM_PATH));
+ fcntl(random_fd, F_SETFD, FD_CLOEXEC);
+# endif
+
+ get_rnd_bytes(random_pool, RANDOM_POOL_SIZE);
+ mix_pool();
+#endif /* !USE_ARC4RANDOM */
+
+ /* start of rand(3) on the right foot */
+ {
+ unsigned int seed;
+
+ get_rnd_bytes((void *)&seed, sizeof(seed));
+ srand(seed);
+ }
+}
+
+u_char secret_of_the_day[SHA1_DIGEST_SIZE];
+
+#ifndef NO_PLUTO
+
+void
+init_secret(void)
+{
+ /*
+ * Generate the secret value for responder cookies, and
+ * schedule an event for refresh.
+ */
+ get_rnd_bytes(secret_of_the_day, sizeof(secret_of_the_day));
+ event_schedule(EVENT_REINIT_SECRET, EVENT_REINIT_SECRET_DELAY, NULL);
+}
+
+#endif /* NO_PLUTO */
diff --git a/programs/pluto/rnd.h b/programs/pluto/rnd.h
new file mode 100644
index 000000000..0bd168039
--- /dev/null
+++ b/programs/pluto/rnd.h
@@ -0,0 +1,21 @@
+/* randomness machinery
+ * Copyright (C) 1998, 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: rnd.h,v 1.1 2004/03/15 20:35:29 as Exp $
+ */
+
+extern u_char secret_of_the_day[SHA1_DIGEST_SIZE];
+
+extern void get_rnd_bytes(u_char *buffer, int length);
+extern void init_rnd_pool(void);
+extern void init_secret(void);
diff --git a/programs/pluto/routing.txt b/programs/pluto/routing.txt
new file mode 100644
index 000000000..a69b8a542
--- /dev/null
+++ b/programs/pluto/routing.txt
@@ -0,0 +1,331 @@
+Routing and Erouting in Pluto
+=============================
+
+RCSID $Id: routing.txt,v 1.1 2004/03/15 20:35:29 as Exp $
+
+This is meant as internal documentation for Pluto. As such, it
+presumes some understanding of Pluto's code.
+
+It also describes KLIPS 1 erouting, including details not otherwise
+documented. KLIPS 1 documentation would be better included in KLIPS.
+
+Routing and erouting are complicated enough that the Pluto code needs
+a guide. This document is meant to be that guide.
+
+
+Mechanisms available to Pluto
+-----------------------------
+
+All outbound packets that are to be processed by KLIPS 1 must be
+routed to an ipsecN network interface. Pluto only uses normal routing
+(as opposed to "Advanced Routing"), so the selection of packets is
+made solely on the basis of the destination address. (Since the
+actual routing commands are in the updown script, they could be
+changed by the administrator, but Pluto needs to understand what is
+going on, and it currently assumes normal routing is used.)
+
+When an outbound packet hits an ipsecN interface, KLIPS figures out
+how to process it by finding an eroute that applies to the source and
+destination addresses. Eroutes are global: they are not specific to a
+particular ipsecN interface (routing needs to get the packets to any
+ipsecN interface; erouting takes it from there, ignoring issues of
+source IP address and nexthop (because nobody knows!)). If multiple
+eroutes apply to the packet, among the ones with the most specific
+source subnet, the one with the most specific destination subset is
+chosen (RGB thinks). If no eroute is discovered, KLIPS acts as if it
+was covered by a DROP eroute (this is the default behaviour; it can be
+changed). At most one eroute can exist for a particular pair of
+client subnets.
+
+There are fundamentally two kinds of eroutes: "shunt" eroutes and ones
+that specify that a packet is to be processed by a group of IPSEC SAs.
+Shunt eroutes specify what is to be done with the packet. Remember
+that these only apply to outbound packets.
+
+- TRAP: notify Pluto of the packet (presumably to attempt to negotiate
+ an appropriate group of IPSEC SAs). At the same time, KLIPS
+ installs a HOLD shunt (see below) for the specific source and
+ destination addresses from the packet and retains the packet
+ for later reprocessing (KLIPS does not yet implement retention).
+ Beware: if the TRAP's subnets both contained a single IP address
+ then installing the HOLD would actually delete the TRAP.
+
+- PASS: let the packet through in the clear
+
+- DROP: discard the packet
+
+- REJECT: discard the packet and notify the sender
+
+- HOLD: (automatically created by KLIPS when a TRAP fires) block
+ the packet, but retain it. If there is already a retained
+ packet, drop the old one and retain the new. When the HOLD
+ shunt is deleted or replaced, the retained packet is reinjected --
+ there might now be a tunnel. Note that KLIPS doesn't yet
+ implement the retention part, so HOLD is really like a DROP.
+
+One consequence of there being only one eroute for a pair of clients
+is that KLIPS will only use one SA group for output for this pair,
+even though there could be several SA groups that are authorised and
+live. Pluto chooses to make this the youngest such group.
+
+
+
+KLIPS lets through in the clear outbound UDP/500 packets that would
+otherwise be processed if they originate on this host and meet certain
+other conditions. The actual test is
+ source == me
+ && (no_eroute || dest == eroute.dest || isanyaddr(eroute.dest))
+ && port == UDP/500
+The idea is that IKE packets between us and a peer should not be
+sent through an IPSEC tunnel negotiated between us. Furthermore,
+our shunt eroutes should not apply to our IKE packets (shunt eroutes
+will generally have an eroute.dest of 0.0.0.0 or its IPv6 equivalent).
+
+Inbound behaviour is controlled in a quite different way. KLIPS
+processes only those inbound packets of ESP or AH protocol, with a
+destination address for this machine's ipsecN interfaces. The
+processing is as dictated by the SAs involved. Unfortunately, the
+decapsulated packet's source and destination address are not checked
+(part of "inbound policy checking").
+
+To prevent clear packets being accepted, firewall rules must be put in
+place. This has nothing to do with KLIPS, but is nonetheless in
+important part of security. It isn't clear what firewalling makes
+sense when Opportunism is allowed.
+
+
+For routing and firewalling, Pluto invokes the updown script. Pluto
+installs eroutes via extended PF_KEY messages.
+
+
+Current Pluto Behaviour
+-----------------------
+
+Data Structures:
+
+Routes and most eroutes are associated with connections (struct
+connection, a potential connection description). The enum routing_t
+field "routing" in struct connection records the state of routing and
+erouting for that connection. The values are:
+ RT_UNROUTED, /* unrouted */
+ RT_UNROUTED_HOLD, /* unrouted, but HOLD shunt installed */
+ RT_ROUTED_PROSPECTIVE, /* routed, and TRAP shunt installed */
+ RT_ROUTED_HOLD, /* routed, and HOLD shunt installed */
+ RT_ROUTED_FAILURE, /* routed, and failure-context shunt installed */
+ RT_ROUTED_TUNNEL /* routed, and erouted to an IPSEC SA group */
+Notice that the routing and erouting are not independent: erouting
+(except for HOLD) implies that the connection is routed.
+
+Several struct connections may have the same destination subnet. If
+they agree on what the route should be, they can share it -- any of
+them may have routing >= RT_ROUTED_PROSPECTIVE. If they disagree,
+they cannot simultaneously be routed.
+
+invariant: for all struct connections c, d:
+ (c.that.client == d.that.client
+ && c.routing >= RT_ROUTED_PROSPECTIVE
+ && d.routing >= RT_ROUTED_PROSPECTIVE)
+ => c.interface == d.interface && c.this.nexthop == d.this.nexthop
+
+There are two kinds of eroutes: shunt eroutes and ones for an IPSEC SA
+Group. Most eroutes are associated with and are represeented in a
+connection. The exception is that some HOLD and PASS shunts do not
+correspond to connections; those are represented in the bare_shunt
+table.
+
+An eroute for an IPSEC SA Group is associated with the state object
+for that Group. The existence of such an eroute is also represented
+by the "so_serial_t eroute_owner" field in the struct connection. The
+value is the serial number of the state object for the Group. The
+special value SOS_NOBODY means that there is no owner associated with
+this connection for the eroute and hence no normal eroute. At most
+one eroute owner may exist for a particular (source subnet,
+destination subnet) pair. A Pluto-managed eroute cannot be associated
+with an RT_UNROUTED connection.
+
+invariant: for all struct connection c:
+ c.routing == RT_EROUTED_TUNNEL || c.eroute_owner == SOS_NOBODY
+
+invariant: for all struct connections c, d:
+ c.this.client == d.this.client && c.that.client == d.that.client
+ && &c != &d
+ => c.routing == RT_UNROUTED || d.routing == RT_UNROUTED
+
+If no normal eroute is set for a particular (source subnet,
+destination subnet) pair for which a connection is routed, then a
+shunt eroute would have been installed. This specifies what should
+happen to packets snared by the route.
+
+When Pluto is notified by KLIPS of a packet that has been TRAPped,
+there is no connection with which to associate the HOLD. It is
+temporarily held in the "bare_shunt table". If Opportunism is
+attempted but DNS doesn't provide Security Gateway information, Pluto
+will replace the HOLD with a PASS shunt. Since this PASS isn't
+associated with a connection, it too will reside in the bare_shunt
+table. If the HOLD can be associated with a connection, it will be
+removed from the bare_shunt table and represented in the connection.
+
+There are two contexts for which shunt eroutes are installed by Pluto
+for a particular connection. The first context is with the prospect
+of dealing with packets before any negotiation has been attempted. I
+call this context "prospective". Currently is a TRAP shunt, used to
+catch packets for initiate opportunistic negotiation. In the future,
+it might also be used to implement preordained PASS, DROP, or REJECT
+rules.
+
+The second context is after a failed negotiation. I call this context
+"failure". At this point a different kind of shunt eroute is
+appropriate. Depending on policy, it could be PASS, DROP, or REJECT,
+but it is unlikely to be TRAP. The shunt eroute should have a
+lifetime (this isn't yet implemented). When the lifetime expires, the
+failure shunt eroute should be replaced by the prospective shunt
+eroute.
+
+The kind and duration of a failure shunt eroute should perhaps depend
+on the nature of the failure, at least as imperfectly detected by
+Pluto. We haven't looked at this. In particular, the mapping from
+observations to robust respose isn't obvious.
+
+The shunt eroute policies should be a function of the potential
+connection. The failure shunt eroute can be specified for a
+particular connection with the flags --pass and --drop in a connection
+definition. There are four combinations, and each has a distinct
+meaning. The failure shunt eroute is incompletely implemented and
+cannot be represented in /etc/ipsec.conf.
+
+There is as yet no control over the prospective shunt eroute: it is
+always TRAP as far as Pluto is concerned. This is probably
+reasonable: any other fate suggests that no negotiation will be done,
+and so a connection definition is inappropriate. These should be
+implemented as manual conns. There remains the issue of whether Pluto
+should be aware of them -- currently it is not.
+
+
+Routines:
+
+[in kernel.c]
+
+bool do_command(struct connection *c, const char *verb)
+ Run the updown script to perform such tasks as installing a route
+ and adjust the firewall.
+
+bool could_route(struct connection *c)
+ Check to see whether we could route and eroute the connection.
+ <- shunt_eroute_connection (to check if --route can be performed)
+ <- install_inbound_ipsec_sa (to see if it will be possible
+ to (later) install route and eroute the corresponding outbound SA)
+ <- install_ipsec_sa (to see if the outbound SA can be routed and erouted)
+
+bool trap_connection(struct connection *c)
+ Install a TRAP shunt eroute for this connection. This implements
+ "whack --route", the way an admin can specify that packets for a
+ connection should be caught without first bringing it up.
+
+void unroute_connection(struct connection *c)
+ Delete any eroute for a connection and unroute it if route isn't shared.
+ <- release_connection
+ <- whack_handle (for "whack --unroute)
+
+bool eroute_connection(struct connection *c
+, ipsec_spi_t spi, unsigned int proto, unsigned int satype
+, unsigned int op, const char *opname UNUSED)
+ Issue PF_KEY commands to KLIPS to add, replace, or delete an eroute.
+ The verb is specified by op and described (for logging) by opname.
+ <- assign_hold
+ <- sag_eroute
+ <- shunt_eroute
+
+bool assign_hold(struct connection *c
+, const ip_address *src, const ip_address *dst)
+ Take a HOLD from the bare_shunt table and assign it to a connection.
+ If the HOLD is broadened (i.e. the connection's source or destination
+ subnets contain more than one IP address), this will involve replacing
+ the HOLD with a different one.
+
+bool sag_eroute(struct state *st, unsigned op, const char *opname)
+ SA Group eroute manipulation. The SA Group concerned is
+ identified with a state object.
+ <- route_and_eroute several times
+
+bool shunt_eroute(struct connection *c, unsigned int op, const char *opname)
+ shunt eroute manipulation. Shunt eroutes are associated with
+ connections.
+ <- unroute_connection
+ <- route_and_eroute
+ <- delete_ipsec_sa
+
+bool route_and_eroute(struct connection *c, struct state *st)
+ Install a route and then a prospective shunt eroute or an SA group
+ eroute. The code assumes that could_route had previously
+ given the go-ahead. Any SA group to be erouted must already
+ exist.
+ <- shunt_eroute_connection
+ <- install_ipsec_sa
+
+void scan_proc_shunts(void)
+ Every SHUNT_SCAN_INTERVAL scan /proc/net/ipsec_eroute.
+ Delete any PASS eroute in the bare_shunt table that hasn't been used
+ within the last SHUNT_PATIENCE seconds.
+ For any HOLD for which Pluto hasn't received an ACQUIRE (possibly
+ lost due to congestion), act as if an ACQUIRE were received.
+
+[in connection.c]
+
+struct connection *route_owner(struct connection *c, struct connection **erop)
+ Find the connection to connection c's peer's client with the
+ largest value of .routing. All other things being equal,
+ preference is given to c. Return NULL if no connection is routed
+ at all. If erop is non-null, sets it to a connection sharing both
+ our client subnet and peer's client subnet with the largest value
+ of .routing.
+ The return value is used to find other connections sharing
+ a route. The value of *erop is used to find other connections
+ sharing an eroute.
+ <- could_route (to find any conflicting routes or eroutes)
+ <- unroute_connection (to find out if our route is still in use
+ after this connection is finished with it)
+ <- install_inbound_ipsec_sa (to find other IPSEC SAs for the
+ same peer clients; when we find them WE KILL THEM; a
+ kludge to deal with road warriors reconnecting)
+ <- route_and_eroute (to find all the connections from which the
+ route or eroute is being stolen)
+
+Uses:
+
+- setting up route & shunt eroute to TRAP packets for opportunism
+ (whack --route). Perhaps also manually designating DROP, REJECT, or
+ PASS for certain packets.
+
+ whack_handle() responds to --route; calls route_connection()
+
+
+- removing same (whack --unroute)
+
+ whack_handle() responds to --unroute; calls unroute_connection()
+
+- installing route & normal eroute for a newly negotiated group of
+ outbound IPSEC SAs
+
+ + perhaps an (additional) route is not needed: if the negotiation
+ was initiated by a TRAPped outgoing packet, then there must
+ already have been a route that got the packet to ipsecN. Mind
+ you, it could have been the wrong N!
+
+ install_ipsec_sa()
+
+- updating a normal eroute when a new group of IPSEC SAs replaces
+ an old one due to rekeying.
+
+ install_ipsec_sa()
+
+- replacing an old eroute when a negotiation fails. But this is
+ tricky. If this was a rekeying, we should just leave the old
+ normal eroute be -- it might still work. Otherwise, this was
+ an initial negotiation: we should replace the shunt eroute
+ with one appropriate for the failure context.
+
+- when a group of IPSEC SAs dies or is killed, and it had the eroute,
+ its normal eroute should be replaced by a shunt eroute. If there
+ was an attempt to replace the group, the replacement is in the
+ failure context; otherwise the replacement is in the prospective
+ context.
diff --git a/programs/pluto/rsaref/pkcs11.h b/programs/pluto/rsaref/pkcs11.h
new file mode 100644
index 000000000..9261e1e4c
--- /dev/null
+++ b/programs/pluto/rsaref/pkcs11.h
@@ -0,0 +1,299 @@
+/* pkcs11.h include file for PKCS #11. */
+/* $Revision: 1.2 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 6 platform-specific macros must be defined. These
+ * macros are described below, and typical definitions for them
+ * are also given. Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a Cryptoki library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 6 macros, the packing convention
+ * for Cryptoki structures should be set. The Cryptoki
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, this might be done by using the following
+ * preprocessor directive before including pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, this might be done by using
+ * the following preprocessor directive before including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(1)
+ *
+ * In a UNIX environment, you're on your own for this. You might
+ * not need to do (or be able to do!) anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object. It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, it might be defined by:
+ *
+ * #define CK_PTR far *
+ *
+ * In a typical UNIX environment, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
+ * an exportable Cryptoki library function definition out of a
+ * return type and a function name. It should be used in the
+ * following fashion to define the exposed Cryptoki functions in
+ * a Cryptoki library:
+ *
+ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * )
+ * {
+ * ...
+ * }
+ *
+ * If you're using Microsoft Developer Studio 5.0 to define a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllexport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to define a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable Cryptoki library function declaration out of a
+ * return type and a function name. It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * );
+ *
+ * If you're using Microsoft Developer Studio 5.0 to declare a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllimport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to declare a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a Cryptoki API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name. It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a Cryptoki API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // Cryptoki API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to access
+ * functions in a Win32 Cryptoki .dll, in might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __declspec(dllimport) (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to access functions in a Win16 Cryptoki .dll, it might
+ * be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __export _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV. It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to do Win32
+ * Cryptoki development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to do Win16 development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 6. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should best be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various Cryptoki types and #define'd values are in the
+ * file pkcs11t.h. */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y) x##y
+
+
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ extern CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points. That is, for
+ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points. A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's Cryptoki version
+ * and then a whole slew of function pointers to the routines in
+ * the library. This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ __PASTE(CK_,name) name;
+
+struct CK_FUNCTION_LIST {
+
+ CK_VERSION version; /* Cryptoki version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/programs/pluto/rsaref/pkcs11f.h b/programs/pluto/rsaref/pkcs11f.h
new file mode 100644
index 000000000..dec6315dd
--- /dev/null
+++ b/programs/pluto/rsaref/pkcs11f.h
@@ -0,0 +1,912 @@
+/* pkcs11f.h include file for PKCS #11. */
+/* $Revision: 1.2 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* This header file contains pretty much everything about all the */
+/* Cryptoki function prototypes. Because this information is */
+/* used for more than just declaring function prototypes, the */
+/* order of the functions appearing herein is important, and */
+/* should not be altered. */
+
+/* General-purpose */
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
+ * cast to CK_C_INITIALIZE_ARGS_PTR
+ * and dereferenced */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_INFO_PTR pInfo /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
+ * function list */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_BBOOL tokenPresent, /* only slots with tokens? */
+ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
+ CK_ULONG_PTR pulCount /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the ID of the slot */
+ CK_SLOT_INFO_PTR pInfo /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_TOKEN_INFO_PTR pInfo /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of token's slot */
+ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
+ CK_ULONG_PTR pulCount /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_MECHANISM_TYPE type, /* type of mechanism */
+ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
+ CK_ULONG ulPinLen, /* length in bytes of the PIN */
+ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
+ CK_ULONG ulPinLen /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
+ CK_ULONG ulOldLen, /* length of the old PIN */
+ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
+ CK_ULONG ulNewLen /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the slot's ID */
+ CK_FLAGS flags, /* from CK_SESSION_INFO */
+ CK_VOID_PTR pApplication, /* passed to callback */
+ CK_NOTIFY Notify, /* callback function */
+ CK_SESSION_HANDLE_PTR phSession /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_SESSION_INFO_PTR pInfo /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session. */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* gets state */
+ CK_ULONG_PTR pulOperationStateLen /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session. */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* holds state */
+ CK_ULONG ulOperationStateLen, /* holds state length */
+ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
+ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_USER_TYPE userType, /* the user type */
+ CK_UTF8CHAR_PTR pPin, /* the user's PIN */
+ CK_ULONG ulPinLen /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy. */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ULONG_PTR pulSize /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes. */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
+ CK_ULONG ulCount /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
+ CK_ULONG ulMaxObjectCount, /* max handles to get */
+ CK_ULONG_PTR pulObjectCount /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pData, /* the plaintext data */
+ CK_ULONG ulDataLen, /* bytes of plaintext */
+ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext data len */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session handle */
+ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
+ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedData, /* ciphertext */
+ CK_ULONG ulEncryptedDataLen, /* ciphertext length */
+ CK_BYTE_PTR pData, /* gets plaintext */
+ CK_ULONG_PTR pulDataLen /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* encrypted data */
+ CK_ULONG ulEncryptedPartLen, /* input length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pLastPart, /* gets plaintext */
+ CK_ULONG_PTR pulLastPartLen /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* data to be digested */
+ CK_ULONG ulDataLen, /* bytes of data to digest */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* data to be digested */
+ CK_ULONG ulPartLen /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested. */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hKey /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ *signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* the data to sign */
+ CK_ULONG ulPartLen /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation,
+ * returning the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ * cannot be recovered from the signature (e.g. DSA). */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation,
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* signed data */
+ CK_ULONG ulDataLen, /* length of signed data */
+ CK_BYTE_PTR pSignature, /* signature */
+ CK_ULONG ulSignatureLen /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* signed data */
+ CK_ULONG ulPartLen /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen, /* signature length */
+ CK_BYTE_PTR pData, /* gets signed data */
+ CK_ULONG_PTR pulDataLen /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key generation mech. */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
+ CK_ULONG ulCount, /* # of attrs in template */
+ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair,
+ * creating new key objects. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session
+ * handle */
+ CK_MECHANISM_PTR pMechanism, /* key-gen
+ * mech. */
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template
+ * for pub.
+ * key */
+ CK_ULONG ulPublicKeyAttributeCount, /* # pub.
+ * attrs. */
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template
+ * for priv.
+ * key */
+ CK_ULONG ulPrivateKeyAttributeCount, /* # priv.
+ * attrs. */
+ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub.
+ * key
+ * handle */
+ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets
+ * priv. key
+ * handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
+ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
+ CK_OBJECT_HANDLE hKey, /* key to be wrapped */
+ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
+ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object. */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
+ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
+ CK_BYTE_PTR pWrappedKey, /* the wrapped key */
+ CK_ULONG ulWrappedKeyLen, /* wrapped key len */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
+ CK_OBJECT_HANDLE hBaseKey, /* base key */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator. */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSeed, /* the seed material */
+ CK_ULONG ulSeedLen /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR RandomData, /* receives the random data */
+ CK_ULONG ulRandomLen /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel. */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Functions added in for Cryptoki Version 2.01 or later */
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur. */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FLAGS flags, /* blocking/nonblocking flag */
+ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
+ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
+);
+#endif
diff --git a/programs/pluto/rsaref/pkcs11t.h b/programs/pluto/rsaref/pkcs11t.h
new file mode 100644
index 000000000..3da20b215
--- /dev/null
+++ b/programs/pluto/rsaref/pkcs11t.h
@@ -0,0 +1,1685 @@
+/* pkcs11t.h include file for PKCS #11. */
+/* $Revision: 1.2 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* See top of pkcs11.h for information about the macros that
+ * must be defined and the structure-packing conventions that
+ * must be set before including this file. */
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#define CK_TRUE 1
+#define CK_FALSE 0
+
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE CK_FALSE
+#endif
+
+#ifndef TRUE
+#define TRUE CK_TRUE
+#endif
+#endif
+
+/* an unsigned 8-bit value */
+typedef unsigned char CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+/* CK_LONG is new for v2.0 */
+typedef long int CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE 0
+
+
+typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+typedef CK_CHAR CK_PTR CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
+typedef CK_ULONG CK_PTR CK_ULONG_PTR;
+typedef void CK_PTR CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session */
+/* handle or object handle */
+#define CK_INVALID_HANDLE 0
+
+
+typedef struct CK_VERSION {
+ CK_BYTE major; /* integer portion of version number */
+ CK_BYTE minor; /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+ /* manufacturerID and libraryDecription have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_VERSION cryptokiVersion; /* Cryptoki interface ver */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags; /* must be zero */
+
+ /* libraryDescription and libraryVersion are new for v2.0 */
+ CK_UTF8CHAR libraryDescription[32]; /* blank padded */
+ CK_VERSION libraryVersion; /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * Cryptoki provides to an application */
+/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER 0
+
+
+typedef CK_ULONG CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+ /* slotDescription and manufacturerID have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR slotDescription[64]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags;
+
+ /* hardwareVersion and firmwareVersion are new for v2.0 */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */
+#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices*/
+#define CKF_HW_SLOT 0x00000004 /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+ /* label, manufacturerID, and model have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR label[32]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_UTF8CHAR model[16]; /* blank padded */
+ CK_CHAR serialNumber[16]; /* blank padded */
+ CK_FLAGS flags; /* see below */
+
+ /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount,
+ * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been
+ * changed from CK_USHORT to CK_ULONG for v2.0 */
+ CK_ULONG ulMaxSessionCount; /* max open sessions */
+ CK_ULONG ulSessionCount; /* sess. now open */
+ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */
+ CK_ULONG ulRwSessionCount; /* R/W sess. now open */
+ CK_ULONG ulMaxPinLen; /* in bytes */
+ CK_ULONG ulMinPinLen; /* in bytes */
+ CK_ULONG ulTotalPublicMemory; /* in bytes */
+ CK_ULONG ulFreePublicMemory; /* in bytes */
+ CK_ULONG ulTotalPrivateMemory; /* in bytes */
+ CK_ULONG ulFreePrivateMemory; /* in bytes */
+
+ /* hardwareVersion, firmwareVersion, and time are new for
+ * v2.0 */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+ CK_CHAR utcTime[16]; /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RNG 0x00000001 /* has random #
+ * generator */
+#define CKF_WRITE_PROTECTED 0x00000002 /* token is
+ * write-
+ * protected */
+#define CKF_LOGIN_REQUIRED 0x00000004 /* user must
+ * login */
+#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's
+ * PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0. If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state */
+#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020
+
+/* CKF_CLOCK_ON_TOKEN is new for v2.0. If it is set, that means
+ * that the token has some sort of clock. The time on that
+ * clock is returned in the token info structure */
+#define CKF_CLOCK_ON_TOKEN 0x00000040
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0. If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the Cryptoki library itself */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
+
+/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0. If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign) */
+#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200
+
+/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the
+ * token has been initialized using C_InitializeToken or an
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause
+ * the token to be reinitialized. */
+#define CKF_TOKEN_INITIALIZED 0x00000400
+
+/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is
+ * true, the token supports secondary authentication for
+ * private key objects. This flag is deprecated in v2.11 and
+ onwards. */
+#define CKF_SECONDARY_AUTHENTICATION 0x00000800
+
+/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect user login PIN has been entered at least once
+ * since the last successful authentication. */
+#define CKF_USER_PIN_COUNT_LOW 0x00010000
+
+/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect user PIN will it to become locked. */
+#define CKF_USER_PIN_FINAL_TRY 0x00020000
+
+/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the
+ * user PIN has been locked. User login to the token is not
+ * possible. */
+#define CKF_USER_PIN_LOCKED 0x00040000
+
+/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the user PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000
+
+/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect SO login PIN has been entered at least once since
+ * the last successful authentication. */
+#define CKF_SO_PIN_COUNT_LOW 0x00100000
+
+/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect SO PIN will it to become locked. */
+#define CKF_SO_PIN_FINAL_TRY 0x00200000
+
+/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED 0x00400000
+
+/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the SO PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
+ * identifies a session */
+typedef CK_ULONG CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
+
+
+/* CK_USER_TYPE enumerates the types of Cryptoki users */
+/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO 0
+/* Normal user */
+#define CKU_USER 1
+/* Context specific (added in v2.20) */
+#define CKU_CONTEXT_SPECIFIC 2
+
+/* CK_STATE enumerates the session states */
+/* CK_STATE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_STATE;
+#define CKS_RO_PUBLIC_SESSION 0
+#define CKS_RO_USER_FUNCTIONS 1
+#define CKS_RW_PUBLIC_SESSION 2
+#define CKS_RW_USER_FUNCTIONS 3
+#define CKS_RW_SO_FUNCTIONS 4
+
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+ CK_SLOT_ID slotID;
+ CK_STATE state;
+ CK_FLAGS flags; /* see below */
+
+ /* ulDeviceError was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulDeviceError; /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RW_SESSION 0x00000002 /* session is r/w */
+#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object */
+typedef CK_ULONG CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that Cryptoki recognizes. It is defined
+ * as follows: */
+/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+/* CKO_HW_FEATURE is new for v2.10 */
+/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
+/* CKO_MECHANISM is new for v2.20 */
+#define CKO_DATA 0x00000000
+#define CKO_CERTIFICATE 0x00000001
+#define CKO_PUBLIC_KEY 0x00000002
+#define CKO_PRIVATE_KEY 0x00000003
+#define CKO_SECRET_KEY 0x00000004
+#define CKO_HW_FEATURE 0x00000005
+#define CKO_DOMAIN_PARAMETERS 0x00000006
+#define CKO_MECHANISM 0x00000007
+#define CKO_VENDOR_DEFINED 0x80000000
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
+ * value that identifies the hardware feature type of an object
+ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
+typedef CK_ULONG CK_HW_FEATURE_TYPE;
+
+/* The following hardware feature types are defined */
+/* CKH_USER_INTERFACE is new for v2.20 */
+#define CKH_MONOTONIC_COUNTER 0x00000001
+#define CKH_CLOCK 0x00000002
+#define CKH_USER_INTERFACE 0x00000003
+#define CKH_VENDOR_DEFINED 0x80000000
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA 0x00000000
+#define CKK_DSA 0x00000001
+#define CKK_DH 0x00000002
+
+/* CKK_ECDSA and CKK_KEA are new for v2.0 */
+/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
+#define CKK_ECDSA 0x00000003
+#define CKK_EC 0x00000003
+#define CKK_X9_42_DH 0x00000004
+#define CKK_KEA 0x00000005
+
+#define CKK_GENERIC_SECRET 0x00000010
+#define CKK_RC2 0x00000011
+#define CKK_RC4 0x00000012
+#define CKK_DES 0x00000013
+#define CKK_DES2 0x00000014
+#define CKK_DES3 0x00000015
+
+/* all these key types are new for v2.0 */
+#define CKK_CAST 0x00000016
+#define CKK_CAST3 0x00000017
+/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
+#define CKK_CAST5 0x00000018
+#define CKK_CAST128 0x00000018
+#define CKK_RC5 0x00000019
+#define CKK_IDEA 0x0000001A
+#define CKK_SKIPJACK 0x0000001B
+#define CKK_BATON 0x0000001C
+#define CKK_JUNIPER 0x0000001D
+#define CKK_CDMF 0x0000001E
+#define CKK_AES 0x0000001F
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKK_BLOWFISH 0x00000020
+#define CKK_TWOFISH 0x00000021
+
+#define CKK_VENDOR_DEFINED 0x80000000
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type */
+/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_CERTIFICATE_TYPE;
+
+/* The following certificate types are defined: */
+/* CKC_X_509_ATTR_CERT is new for v2.10 */
+/* CKC_WTLS is new for v2.20 */
+#define CKC_X_509 0x00000000
+#define CKC_X_509_ATTR_CERT 0x00000001
+#define CKC_WTLS 0x00000002
+#define CKC_VENDOR_DEFINED 0x80000000
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type */
+/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_ATTRIBUTE_TYPE;
+
+/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
+ consists of an array of values. */
+#define CKF_ARRAY_ATTRIBUTE 0x40000000
+
+/* The following attribute types are defined: */
+#define CKA_CLASS 0x00000000
+#define CKA_TOKEN 0x00000001
+#define CKA_PRIVATE 0x00000002
+#define CKA_LABEL 0x00000003
+#define CKA_APPLICATION 0x00000010
+#define CKA_VALUE 0x00000011
+
+/* CKA_OBJECT_ID is new for v2.10 */
+#define CKA_OBJECT_ID 0x00000012
+
+#define CKA_CERTIFICATE_TYPE 0x00000080
+#define CKA_ISSUER 0x00000081
+#define CKA_SERIAL_NUMBER 0x00000082
+
+/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new
+ * for v2.10 */
+#define CKA_AC_ISSUER 0x00000083
+#define CKA_OWNER 0x00000084
+#define CKA_ATTR_TYPES 0x00000085
+
+/* CKA_TRUSTED is new for v2.11 */
+#define CKA_TRUSTED 0x00000086
+
+/* CKA_CERTIFICATE_CATEGORY ...
+ * CKA_CHECK_VALUE are new for v2.20 */
+#define CKA_CERTIFICATE_CATEGORY 0x00000087
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088
+#define CKA_URL 0x00000089
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008A
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008B
+#define CKA_CHECK_VALUE 0x00000090
+
+#define CKA_KEY_TYPE 0x00000100
+#define CKA_SUBJECT 0x00000101
+#define CKA_ID 0x00000102
+#define CKA_SENSITIVE 0x00000103
+#define CKA_ENCRYPT 0x00000104
+#define CKA_DECRYPT 0x00000105
+#define CKA_WRAP 0x00000106
+#define CKA_UNWRAP 0x00000107
+#define CKA_SIGN 0x00000108
+#define CKA_SIGN_RECOVER 0x00000109
+#define CKA_VERIFY 0x0000010A
+#define CKA_VERIFY_RECOVER 0x0000010B
+#define CKA_DERIVE 0x0000010C
+#define CKA_START_DATE 0x00000110
+#define CKA_END_DATE 0x00000111
+#define CKA_MODULUS 0x00000120
+#define CKA_MODULUS_BITS 0x00000121
+#define CKA_PUBLIC_EXPONENT 0x00000122
+#define CKA_PRIVATE_EXPONENT 0x00000123
+#define CKA_PRIME_1 0x00000124
+#define CKA_PRIME_2 0x00000125
+#define CKA_EXPONENT_1 0x00000126
+#define CKA_EXPONENT_2 0x00000127
+#define CKA_COEFFICIENT 0x00000128
+#define CKA_PRIME 0x00000130
+#define CKA_SUBPRIME 0x00000131
+#define CKA_BASE 0x00000132
+
+/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */
+#define CKA_PRIME_BITS 0x00000133
+#define CKA_SUBPRIME_BITS 0x00000134
+#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS
+/* (To retain backwards-compatibility) */
+
+#define CKA_VALUE_BITS 0x00000160
+#define CKA_VALUE_LEN 0x00000161
+
+/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE,
+ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS,
+ * and CKA_EC_POINT are new for v2.0 */
+#define CKA_EXTRACTABLE 0x00000162
+#define CKA_LOCAL 0x00000163
+#define CKA_NEVER_EXTRACTABLE 0x00000164
+#define CKA_ALWAYS_SENSITIVE 0x00000165
+
+/* CKA_KEY_GEN_MECHANISM is new for v2.11 */
+#define CKA_KEY_GEN_MECHANISM 0x00000166
+
+#define CKA_MODIFIABLE 0x00000170
+
+/* CKA_ECDSA_PARAMS is deprecated in v2.11,
+ * CKA_EC_PARAMS is preferred. */
+#define CKA_ECDSA_PARAMS 0x00000180
+#define CKA_EC_PARAMS 0x00000180
+
+#define CKA_EC_POINT 0x00000181
+
+/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
+ * are new for v2.10. Deprecated in v2.11 and onwards. */
+#define CKA_SECONDARY_AUTH 0x00000200
+#define CKA_AUTH_PIN_FLAGS 0x00000201
+
+/* CKA_ALWAYS_AUTHENTICATE ...
+ * CKA_UNWRAP_TEMPLATE are new for v2.20 */
+#define CKA_ALWAYS_AUTHENTICATE 0x00000202
+
+#define CKA_WRAP_WITH_TRUSTED 0x00000210
+#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211)
+#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212)
+
+/* CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
+ * are new for v2.10 */
+#define CKA_HW_FEATURE_TYPE 0x00000300
+#define CKA_RESET_ON_INIT 0x00000301
+#define CKA_HAS_RESET 0x00000302
+
+/* The following attributes are new for v2.20 */
+#define CKA_PIXEL_X 0x00000400
+#define CKA_PIXEL_Y 0x00000401
+#define CKA_RESOLUTION 0x00000402
+#define CKA_CHAR_ROWS 0x00000403
+#define CKA_CHAR_COLUMNS 0x00000404
+#define CKA_COLOR 0x00000405
+#define CKA_BITS_PER_PIXEL 0x00000406
+#define CKA_CHAR_SETS 0x00000480
+#define CKA_ENCODING_METHODS 0x00000481
+#define CKA_MIME_TYPES 0x00000482
+#define CKA_MECHANISM_TYPE 0x00000500
+#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501
+#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502
+#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503
+#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600)
+
+#define CKA_VENDOR_DEFINED 0x80000000
+
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute */
+typedef struct CK_ATTRIBUTE {
+ CK_ATTRIBUTE_TYPE type;
+ CK_VOID_PTR pValue;
+
+ /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */
+ CK_ULONG ulValueLen; /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+ CK_CHAR year[4]; /* the year ("1900" - "9999") */
+ CK_CHAR month[2]; /* the month ("01" - "12") */
+ CK_CHAR day[2]; /* the day ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type */
+/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000
+#define CKM_RSA_PKCS 0x00000001
+#define CKM_RSA_9796 0x00000002
+#define CKM_RSA_X_509 0x00000003
+
+/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS
+ * are new for v2.0. They are mechanisms which hash and sign */
+#define CKM_MD2_RSA_PKCS 0x00000004
+#define CKM_MD5_RSA_PKCS 0x00000005
+#define CKM_SHA1_RSA_PKCS 0x00000006
+
+/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and
+ * CKM_RSA_PKCS_OAEP are new for v2.10 */
+#define CKM_RIPEMD128_RSA_PKCS 0x00000007
+#define CKM_RIPEMD160_RSA_PKCS 0x00000008
+#define CKM_RSA_PKCS_OAEP 0x00000009
+
+/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31,
+ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */
+#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A
+#define CKM_RSA_X9_31 0x0000000B
+#define CKM_SHA1_RSA_X9_31 0x0000000C
+#define CKM_RSA_PKCS_PSS 0x0000000D
+#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E
+
+#define CKM_DSA_KEY_PAIR_GEN 0x00000010
+#define CKM_DSA 0x00000011
+#define CKM_DSA_SHA1 0x00000012
+#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020
+#define CKM_DH_PKCS_DERIVE 0x00000021
+
+/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
+ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
+ * v2.11 */
+#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030
+#define CKM_X9_42_DH_DERIVE 0x00000031
+#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032
+#define CKM_X9_42_MQV_DERIVE 0x00000033
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_RSA_PKCS 0x00000040
+#define CKM_SHA384_RSA_PKCS 0x00000041
+#define CKM_SHA512_RSA_PKCS 0x00000042
+#define CKM_SHA256_RSA_PKCS_PSS 0x00000043
+#define CKM_SHA384_RSA_PKCS_PSS 0x00000044
+#define CKM_SHA512_RSA_PKCS_PSS 0x00000045
+
+#define CKM_RC2_KEY_GEN 0x00000100
+#define CKM_RC2_ECB 0x00000101
+#define CKM_RC2_CBC 0x00000102
+#define CKM_RC2_MAC 0x00000103
+
+/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */
+#define CKM_RC2_MAC_GENERAL 0x00000104
+#define CKM_RC2_CBC_PAD 0x00000105
+
+#define CKM_RC4_KEY_GEN 0x00000110
+#define CKM_RC4 0x00000111
+#define CKM_DES_KEY_GEN 0x00000120
+#define CKM_DES_ECB 0x00000121
+#define CKM_DES_CBC 0x00000122
+#define CKM_DES_MAC 0x00000123
+
+/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */
+#define CKM_DES_MAC_GENERAL 0x00000124
+#define CKM_DES_CBC_PAD 0x00000125
+
+#define CKM_DES2_KEY_GEN 0x00000130
+#define CKM_DES3_KEY_GEN 0x00000131
+#define CKM_DES3_ECB 0x00000132
+#define CKM_DES3_CBC 0x00000133
+#define CKM_DES3_MAC 0x00000134
+
+/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN,
+ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC,
+ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */
+#define CKM_DES3_MAC_GENERAL 0x00000135
+#define CKM_DES3_CBC_PAD 0x00000136
+#define CKM_CDMF_KEY_GEN 0x00000140
+#define CKM_CDMF_ECB 0x00000141
+#define CKM_CDMF_CBC 0x00000142
+#define CKM_CDMF_MAC 0x00000143
+#define CKM_CDMF_MAC_GENERAL 0x00000144
+#define CKM_CDMF_CBC_PAD 0x00000145
+
+/* the following four DES mechanisms are new for v2.20 */
+#define CKM_DES_OFB64 0x00000150
+#define CKM_DES_OFB8 0x00000151
+#define CKM_DES_CFB64 0x00000152
+#define CKM_DES_CFB8 0x00000153
+
+#define CKM_MD2 0x00000200
+
+/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD2_HMAC 0x00000201
+#define CKM_MD2_HMAC_GENERAL 0x00000202
+
+#define CKM_MD5 0x00000210
+
+/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD5_HMAC 0x00000211
+#define CKM_MD5_HMAC_GENERAL 0x00000212
+
+#define CKM_SHA_1 0x00000220
+
+/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */
+#define CKM_SHA_1_HMAC 0x00000221
+#define CKM_SHA_1_HMAC_GENERAL 0x00000222
+
+/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC,
+ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC,
+ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */
+#define CKM_RIPEMD128 0x00000230
+#define CKM_RIPEMD128_HMAC 0x00000231
+#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232
+#define CKM_RIPEMD160 0x00000240
+#define CKM_RIPEMD160_HMAC 0x00000241
+#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256 0x00000250
+#define CKM_SHA256_HMAC 0x00000251
+#define CKM_SHA256_HMAC_GENERAL 0x00000252
+#define CKM_SHA384 0x00000260
+#define CKM_SHA384_HMAC 0x00000261
+#define CKM_SHA384_HMAC_GENERAL 0x00000262
+#define CKM_SHA512 0x00000270
+#define CKM_SHA512_HMAC 0x00000271
+#define CKM_SHA512_HMAC_GENERAL 0x00000272
+
+/* All of the following mechanisms are new for v2.0 */
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST_KEY_GEN 0x00000300
+#define CKM_CAST_ECB 0x00000301
+#define CKM_CAST_CBC 0x00000302
+#define CKM_CAST_MAC 0x00000303
+#define CKM_CAST_MAC_GENERAL 0x00000304
+#define CKM_CAST_CBC_PAD 0x00000305
+#define CKM_CAST3_KEY_GEN 0x00000310
+#define CKM_CAST3_ECB 0x00000311
+#define CKM_CAST3_CBC 0x00000312
+#define CKM_CAST3_MAC 0x00000313
+#define CKM_CAST3_MAC_GENERAL 0x00000314
+#define CKM_CAST3_CBC_PAD 0x00000315
+#define CKM_CAST5_KEY_GEN 0x00000320
+#define CKM_CAST128_KEY_GEN 0x00000320
+#define CKM_CAST5_ECB 0x00000321
+#define CKM_CAST128_ECB 0x00000321
+#define CKM_CAST5_CBC 0x00000322
+#define CKM_CAST128_CBC 0x00000322
+#define CKM_CAST5_MAC 0x00000323
+#define CKM_CAST128_MAC 0x00000323
+#define CKM_CAST5_MAC_GENERAL 0x00000324
+#define CKM_CAST128_MAC_GENERAL 0x00000324
+#define CKM_CAST5_CBC_PAD 0x00000325
+#define CKM_CAST128_CBC_PAD 0x00000325
+#define CKM_RC5_KEY_GEN 0x00000330
+#define CKM_RC5_ECB 0x00000331
+#define CKM_RC5_CBC 0x00000332
+#define CKM_RC5_MAC 0x00000333
+#define CKM_RC5_MAC_GENERAL 0x00000334
+#define CKM_RC5_CBC_PAD 0x00000335
+#define CKM_IDEA_KEY_GEN 0x00000340
+#define CKM_IDEA_ECB 0x00000341
+#define CKM_IDEA_CBC 0x00000342
+#define CKM_IDEA_MAC 0x00000343
+#define CKM_IDEA_MAC_GENERAL 0x00000344
+#define CKM_IDEA_CBC_PAD 0x00000345
+#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350
+#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360
+#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362
+#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363
+#define CKM_XOR_BASE_AND_DATA 0x00000364
+#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365
+#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370
+#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371
+#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372
+
+/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN,
+ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and
+ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373
+#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374
+#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375
+#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376
+#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377
+
+/* CKM_TLS_PRF is new for v2.20 */
+#define CKM_TLS_PRF 0x00000378
+
+#define CKM_SSL3_MD5_MAC 0x00000380
+#define CKM_SSL3_SHA1_MAC 0x00000381
+#define CKM_MD5_KEY_DERIVATION 0x00000390
+#define CKM_MD2_KEY_DERIVATION 0x00000391
+#define CKM_SHA1_KEY_DERIVATION 0x00000392
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_KEY_DERIVATION 0x00000393
+#define CKM_SHA384_KEY_DERIVATION 0x00000394
+#define CKM_SHA512_KEY_DERIVATION 0x00000395
+
+#define CKM_PBE_MD2_DES_CBC 0x000003A0
+#define CKM_PBE_MD5_DES_CBC 0x000003A1
+#define CKM_PBE_MD5_CAST_CBC 0x000003A2
+#define CKM_PBE_MD5_CAST3_CBC 0x000003A3
+#define CKM_PBE_MD5_CAST5_CBC 0x000003A4
+#define CKM_PBE_MD5_CAST128_CBC 0x000003A4
+#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5
+#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5
+#define CKM_PBE_SHA1_RC4_128 0x000003A6
+#define CKM_PBE_SHA1_RC4_40 0x000003A7
+#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8
+#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9
+#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA
+#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB
+
+/* CKM_PKCS5_PBKD2 is new for v2.10 */
+#define CKM_PKCS5_PBKD2 0x000003B0
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0
+
+/* WTLS mechanisms are new for v2.20 */
+#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0
+#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1
+#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2
+#define CKM_WTLS_PRF 0x000003D3
+#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4
+#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5
+
+#define CKM_KEY_WRAP_LYNKS 0x00000400
+#define CKM_KEY_WRAP_SET_OAEP 0x00000401
+
+/* CKM_CMS_SIG is new for v2.20 */
+#define CKM_CMS_SIG 0x00000500
+
+/* Fortezza mechanisms */
+#define CKM_SKIPJACK_KEY_GEN 0x00001000
+#define CKM_SKIPJACK_ECB64 0x00001001
+#define CKM_SKIPJACK_CBC64 0x00001002
+#define CKM_SKIPJACK_OFB64 0x00001003
+#define CKM_SKIPJACK_CFB64 0x00001004
+#define CKM_SKIPJACK_CFB32 0x00001005
+#define CKM_SKIPJACK_CFB16 0x00001006
+#define CKM_SKIPJACK_CFB8 0x00001007
+#define CKM_SKIPJACK_WRAP 0x00001008
+#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009
+#define CKM_SKIPJACK_RELAYX 0x0000100a
+#define CKM_KEA_KEY_PAIR_GEN 0x00001010
+#define CKM_KEA_KEY_DERIVE 0x00001011
+#define CKM_FORTEZZA_TIMESTAMP 0x00001020
+#define CKM_BATON_KEY_GEN 0x00001030
+#define CKM_BATON_ECB128 0x00001031
+#define CKM_BATON_ECB96 0x00001032
+#define CKM_BATON_CBC128 0x00001033
+#define CKM_BATON_COUNTER 0x00001034
+#define CKM_BATON_SHUFFLE 0x00001035
+#define CKM_BATON_WRAP 0x00001036
+
+/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
+ * CKM_EC_KEY_PAIR_GEN is preferred */
+#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040
+#define CKM_EC_KEY_PAIR_GEN 0x00001040
+
+#define CKM_ECDSA 0x00001041
+#define CKM_ECDSA_SHA1 0x00001042
+
+/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
+ * are new for v2.11 */
+#define CKM_ECDH1_DERIVE 0x00001050
+#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051
+#define CKM_ECMQV_DERIVE 0x00001052
+
+#define CKM_JUNIPER_KEY_GEN 0x00001060
+#define CKM_JUNIPER_ECB128 0x00001061
+#define CKM_JUNIPER_CBC128 0x00001062
+#define CKM_JUNIPER_COUNTER 0x00001063
+#define CKM_JUNIPER_SHUFFLE 0x00001064
+#define CKM_JUNIPER_WRAP 0x00001065
+#define CKM_FASTHASH 0x00001070
+
+/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC,
+ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN,
+ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are
+ * new for v2.11 */
+#define CKM_AES_KEY_GEN 0x00001080
+#define CKM_AES_ECB 0x00001081
+#define CKM_AES_CBC 0x00001082
+#define CKM_AES_MAC 0x00001083
+#define CKM_AES_MAC_GENERAL 0x00001084
+#define CKM_AES_CBC_PAD 0x00001085
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKM_BLOWFISH_KEY_GEN 0x00001090
+#define CKM_BLOWFISH_CBC 0x00001091
+#define CKM_TWOFISH_KEY_GEN 0x00001092
+#define CKM_TWOFISH_CBC 0x00001093
+
+
+/* CKM_xxx_ENCRYPT_DATA mechanisms are new for v2.20 */
+#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100
+#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101
+#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102
+#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103
+#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104
+#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105
+
+#define CKM_DSA_PARAMETER_GEN 0x00002000
+#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001
+#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002
+
+#define CKM_VENDOR_DEFINED 0x80000000
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism */
+typedef struct CK_MECHANISM {
+ CK_MECHANISM_TYPE mechanism;
+ CK_VOID_PTR pParameter;
+
+ /* ulParameterLen was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulParameterLen; /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism */
+typedef struct CK_MECHANISM_INFO {
+ CK_ULONG ulMinKeySize;
+ CK_ULONG ulMaxKeySize;
+ CK_FLAGS flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ * Bit Flag Mask Meaning */
+#define CKF_HW 0x00000001 /* performed by HW */
+
+/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN,
+ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER,
+ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP,
+ * and CKF_DERIVE are new for v2.0. They specify whether or not
+ * a mechanism can be used for a particular task */
+#define CKF_ENCRYPT 0x00000100
+#define CKF_DECRYPT 0x00000200
+#define CKF_DIGEST 0x00000400
+#define CKF_SIGN 0x00000800
+#define CKF_SIGN_RECOVER 0x00001000
+#define CKF_VERIFY 0x00002000
+#define CKF_VERIFY_RECOVER 0x00004000
+#define CKF_GENERATE 0x00008000
+#define CKF_GENERATE_KEY_PAIR 0x00010000
+#define CKF_WRAP 0x00020000
+#define CKF_UNWRAP 0x00040000
+#define CKF_DERIVE 0x00080000
+
+/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE,
+ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They
+ * describe a token's EC capabilities not available in mechanism
+ * information. */
+#define CKF_EC_F_P 0x00100000
+#define CKF_EC_F_2M 0x00200000
+#define CKF_EC_ECPARAMETERS 0x00400000
+#define CKF_EC_NAMEDCURVE 0x00800000
+#define CKF_EC_UNCOMPRESS 0x01000000
+#define CKF_EC_COMPRESS 0x02000000
+
+#define CKF_EXTENSION 0x80000000 /* FALSE for this version */
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+
+/* CK_RV is a value that identifies the return value of a
+ * Cryptoki function */
+/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG CK_RV;
+
+#define CKR_OK 0x00000000
+#define CKR_CANCEL 0x00000001
+#define CKR_HOST_MEMORY 0x00000002
+#define CKR_SLOT_ID_INVALID 0x00000003
+
+/* CKR_FLAGS_INVALID was removed for v2.0 */
+
+/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */
+#define CKR_GENERAL_ERROR 0x00000005
+#define CKR_FUNCTION_FAILED 0x00000006
+
+/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS,
+ * and CKR_CANT_LOCK are new for v2.01 */
+#define CKR_ARGUMENTS_BAD 0x00000007
+#define CKR_NO_EVENT 0x00000008
+#define CKR_NEED_TO_CREATE_THREADS 0x00000009
+#define CKR_CANT_LOCK 0x0000000A
+
+#define CKR_ATTRIBUTE_READ_ONLY 0x00000010
+#define CKR_ATTRIBUTE_SENSITIVE 0x00000011
+#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012
+#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013
+#define CKR_DATA_INVALID 0x00000020
+#define CKR_DATA_LEN_RANGE 0x00000021
+#define CKR_DEVICE_ERROR 0x00000030
+#define CKR_DEVICE_MEMORY 0x00000031
+#define CKR_DEVICE_REMOVED 0x00000032
+#define CKR_ENCRYPTED_DATA_INVALID 0x00000040
+#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041
+#define CKR_FUNCTION_CANCELED 0x00000050
+#define CKR_FUNCTION_NOT_PARALLEL 0x00000051
+
+/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */
+#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054
+
+#define CKR_KEY_HANDLE_INVALID 0x00000060
+
+/* CKR_KEY_SENSITIVE was removed for v2.0 */
+
+#define CKR_KEY_SIZE_RANGE 0x00000062
+#define CKR_KEY_TYPE_INCONSISTENT 0x00000063
+
+/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED,
+ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED,
+ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for
+ * v2.0 */
+#define CKR_KEY_NOT_NEEDED 0x00000064
+#define CKR_KEY_CHANGED 0x00000065
+#define CKR_KEY_NEEDED 0x00000066
+#define CKR_KEY_INDIGESTIBLE 0x00000067
+#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068
+#define CKR_KEY_NOT_WRAPPABLE 0x00000069
+#define CKR_KEY_UNEXTRACTABLE 0x0000006A
+
+#define CKR_MECHANISM_INVALID 0x00000070
+#define CKR_MECHANISM_PARAM_INVALID 0x00000071
+
+/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
+ * were removed for v2.0 */
+#define CKR_OBJECT_HANDLE_INVALID 0x00000082
+#define CKR_OPERATION_ACTIVE 0x00000090
+#define CKR_OPERATION_NOT_INITIALIZED 0x00000091
+#define CKR_PIN_INCORRECT 0x000000A0
+#define CKR_PIN_INVALID 0x000000A1
+#define CKR_PIN_LEN_RANGE 0x000000A2
+
+/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */
+#define CKR_PIN_EXPIRED 0x000000A3
+#define CKR_PIN_LOCKED 0x000000A4
+
+#define CKR_SESSION_CLOSED 0x000000B0
+#define CKR_SESSION_COUNT 0x000000B1
+#define CKR_SESSION_HANDLE_INVALID 0x000000B3
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4
+#define CKR_SESSION_READ_ONLY 0x000000B5
+#define CKR_SESSION_EXISTS 0x000000B6
+
+/* CKR_SESSION_READ_ONLY_EXISTS and
+ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */
+#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7
+#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8
+
+#define CKR_SIGNATURE_INVALID 0x000000C0
+#define CKR_SIGNATURE_LEN_RANGE 0x000000C1
+#define CKR_TEMPLATE_INCOMPLETE 0x000000D0
+#define CKR_TEMPLATE_INCONSISTENT 0x000000D1
+#define CKR_TOKEN_NOT_PRESENT 0x000000E0
+#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1
+#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2
+#define CKR_USER_ALREADY_LOGGED_IN 0x00000100
+#define CKR_USER_NOT_LOGGED_IN 0x00000101
+#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102
+#define CKR_USER_TYPE_INVALID 0x00000103
+
+/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES
+ * are new to v2.01 */
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104
+#define CKR_USER_TOO_MANY_TYPES 0x00000105
+
+#define CKR_WRAPPED_KEY_INVALID 0x00000110
+#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112
+#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113
+#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115
+#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120
+
+/* These are new to v2.0 */
+#define CKR_RANDOM_NO_RNG 0x00000121
+
+/* These are new to v2.11 */
+#define CKR_DOMAIN_PARAMS_INVALID 0x00000130
+
+/* These are new to v2.0 */
+#define CKR_BUFFER_TOO_SMALL 0x00000150
+#define CKR_SAVED_STATE_INVALID 0x00000160
+#define CKR_INFORMATION_SENSITIVE 0x00000170
+#define CKR_STATE_UNSAVEABLE 0x00000180
+
+/* These are new to v2.01 */
+#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191
+#define CKR_MUTEX_BAD 0x000001A0
+#define CKR_MUTEX_NOT_LOCKED 0x000001A1
+
+/* This is new to v2.20 */
+#define CKR_FUNCTION_REJECTED 0x00000200
+
+#define CKR_VENDOR_DEFINED 0x80000000
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
+ * version and pointers of appropriate types to all the
+ * Cryptoki functions */
+/* CK_FUNCTION_LIST is new for v2.0 */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+ CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize */
+typedef struct CK_C_INITIALIZE_ARGS {
+ CK_CREATEMUTEX CreateMutex;
+ CK_DESTROYMUTEX DestroyMutex;
+ CK_LOCKMUTEX LockMutex;
+ CK_UNLOCKMUTEX UnlockMutex;
+ CK_FLAGS flags;
+ CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
+#define CKF_OS_LOCKING_OK 0x00000002
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK 1
+
+/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_MGF_TYPE is used to indicate the Message
+ * Generation Function (MGF) applied to a message block when
+ * formatting a message block for the PKCS #1 OAEP encryption
+ * scheme. */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+/* CKG_MGF1_SHA256, CKG_MGF1_SHA384, and CKG_MGF1_SHA512
+ * are new for v2.20 */
+#define CKG_MGF1_SHA1 0x00000001
+#define CKG_MGF1_SHA256 0x00000002
+#define CKG_MGF1_SHA384 0x00000003
+#define CKG_MGF1_SHA512 0x00000004
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source
+ * of the encoding parameter when formatting a message block
+ * for the PKCS #1 OAEP encryption scheme. */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED 0x00000001
+
+/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10.
+ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_OAEP mechanism. */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+ CK_VOID_PTR pSourceData;
+ CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11.
+ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s). */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_ULONG sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+/* CK_EC_KDF_TYPE is new for v2.11. */
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL 0x00000001
+#define CKD_SHA1_KDF 0x00000002
+
+/* CK_ECDH1_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+
+/* CK_ECDH2_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/* The following X9.42 DH key derivation functions are defined
+ (besides CKD_NULL already defined : */
+#define CKD_SHA1_KDF_ASN1 0x00000003
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004
+
+/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_X9_42_MQV_DERIVE_PARAMS;
+
+typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism */
+/* CK_KEA_DERIVE_PARAMS is new for v2.0 */
+typedef struct CK_KEA_DERIVE_PARAMS {
+ CK_BBOOL isSender;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pRandomB;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just
+ * holds the effective keysize */
+typedef CK_ULONG CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism */
+typedef struct CK_RC2_CBC_PARAMS {
+ /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+
+ CK_BYTE iv[8]; /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism */
+/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms */
+/* CK_RC5_PARAMS is new for v2.0 */
+typedef struct CK_RC5_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism */
+/* CK_RC5_CBC_PARAMS is new for v2.0 */
+typedef struct CK_RC5_CBC_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_BYTE_PTR pIv; /* pointer to IV */
+ CK_ULONG ulIvLen; /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism */
+/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms. Its value is the length of
+ * the MAC */
+/* CK_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+/* CK_DES/AES_ECB/CBC_ENCRYPT_DATA_PARAMS are new for v2.20 */
+typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[8];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pPassword;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPAndGLen;
+ CK_ULONG ulQLen;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pPrimeP;
+ CK_BYTE_PTR pBaseG;
+ CK_BYTE_PTR pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+ CK_SKIPJACK_PRIVATE_WRAP_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism */
+/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+ CK_ULONG ulOldWrappedXLen;
+ CK_BYTE_PTR pOldWrappedX;
+ CK_ULONG ulOldPasswordLen;
+ CK_BYTE_PTR pOldPassword;
+ CK_ULONG ulOldPublicDataLen;
+ CK_BYTE_PTR pOldPublicData;
+ CK_ULONG ulOldRandomLen;
+ CK_BYTE_PTR pOldRandomA;
+ CK_ULONG ulNewPasswordLen;
+ CK_BYTE_PTR pNewPassword;
+ CK_ULONG ulNewPublicDataLen;
+ CK_BYTE_PTR pNewPublicData;
+ CK_ULONG ulNewRandomLen;
+ CK_BYTE_PTR pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+ CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+ CK_BYTE_PTR pInitVector;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pSalt;
+ CK_ULONG ulSaltLen;
+ CK_ULONG ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism */
+/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+ CK_BYTE bBC; /* block contents byte */
+ CK_BYTE_PTR pX; /* extra data */
+ CK_ULONG ulXLen; /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
+ CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hClientMacSecret;
+ CK_OBJECT_HANDLE hServerMacSecret;
+ CK_OBJECT_HANDLE hClientKey;
+ CK_OBJECT_HANDLE hServerKey;
+ CK_BYTE_PTR pIVClient;
+ CK_BYTE_PTR pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_BBOOL bIsExport;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+/* CK_TLS_PRF_PARAMS is new for version 2.20 */
+typedef struct CK_TLS_PRF_PARAMS {
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_TLS_PRF_PARAMS;
+
+typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
+
+/* WTLS is new for version 2.20 */
+typedef struct CK_WTLS_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_WTLS_RANDOM_DATA;
+
+typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
+
+typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_BYTE_PTR pVersion;
+} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_WTLS_PRF_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_WTLS_PRF_PARAMS;
+
+typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hMacSecret;
+ CK_OBJECT_HANDLE hKey;
+ CK_BYTE_PTR pIV;
+} CK_WTLS_KEY_MAT_OUT;
+
+typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_ULONG ulSequenceNumber;
+ CK_BBOOL bIsExport;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_WTLS_KEY_MAT_PARAMS;
+
+typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
+
+/* CMS is new for version 2.20 */
+typedef struct CK_CMS_SIG_PARAMS {
+ CK_OBJECT_HANDLE certificateHandle;
+ CK_MECHANISM_PTR pSigningMechanism;
+ CK_MECHANISM_PTR pDigestMechanism;
+ CK_UTF8CHAR_PTR pContentType;
+ CK_BYTE_PTR pRequestedAttributes;
+ CK_ULONG ulRequestedAttributesLen;
+ CK_BYTE_PTR pRequiredAttributes;
+ CK_ULONG ulRequiredAttributesLen;
+} CK_CMS_SIG_PARAMS;
+
+typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+ CK_BYTE_PTR pData;
+ CK_ULONG ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+ CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key */
+/* CK_EXTRACT_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10.
+ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
+ * indicate the Pseudo-Random Function (PRF) used to generate
+ * key bits using PKCS #5 PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+/* The following PRFs are defined in PKCS #5 v2.0. */
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
+
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10.
+ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
+ * source of the salt value when deriving a key using PKCS #5
+ * PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED 0x00000001
+
+/* CK_PKCS5_PBKD2_PARAMS is new for v2.10.
+ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the
+ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+ CK_VOID_PTR pSaltSourceData;
+ CK_ULONG ulSaltSourceDataLen;
+ CK_ULONG iterations;
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ CK_VOID_PTR pPrfData;
+ CK_ULONG ulPrfDataLen;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG_PTR ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+#endif
diff --git a/programs/pluto/rsaref/unix.h b/programs/pluto/rsaref/unix.h
new file mode 100644
index 000000000..2e7eb6663
--- /dev/null
+++ b/programs/pluto/rsaref/unix.h
@@ -0,0 +1,24 @@
+
+
+#ifndef UNIX_H
+#define UNIX_H
+
+#define CK_PTR *
+
+#define CK_DEFINE_FUNCTION(returnType, name) \
+ returnType name
+
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType name
+
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType (* name)
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+ returnType (* name)
+
+#ifndef NULL_PTR
+#define NULL_PTR 0
+#endif
+
+#endif
diff --git a/programs/pluto/server.c b/programs/pluto/server.c
new file mode 100644
index 000000000..30251138e
--- /dev/null
+++ b/programs/pluto/server.c
@@ -0,0 +1,1064 @@
+/* get-next-event loop
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: server.c,v 1.9 2005/09/09 14:15:35 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#ifdef SOLARIS
+# include <sys/sockio.h> /* for Solaris 2.6: defines SIOCGIFCONF */
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <resolv.h>
+#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "state.h"
+#include "connections.h"
+#include "kernel.h"
+#include "log.h"
+#include "server.h"
+#include "timer.h"
+#include "packet.h"
+#include "demux.h" /* needs packet.h */
+#include "rcv_whack.h"
+#include "rcv_info.h"
+#include "keys.h"
+#include "adns.h" /* needs <resolv.h> */
+#include "dnskey.h" /* needs keys.h and adns.h */
+#include "whack.h" /* for RC_LOG_SERIOUS */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+#include "kameipsec.h"
+
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
+/*
+ * Server main loop and socket initialization routines.
+ */
+
+static const int on = TRUE; /* by-reference parameter; constant, we hope */
+
+/* control (whack) socket */
+int ctl_fd = NULL_FD; /* file descriptor of control (whack) socket */
+struct sockaddr_un ctl_addr = { AF_UNIX, DEFAULT_CTLBASE CTL_SUFFIX };
+
+/* info (showpolicy) socket */
+int policy_fd = NULL_FD;
+struct sockaddr_un info_addr= { AF_UNIX, DEFAULT_CTLBASE INFO_SUFFIX };
+
+/* Initialize the control socket.
+ * Note: this is called very early, so little infrastructure is available.
+ * It is important that the socket is created before the original
+ * Pluto process returns.
+ */
+err_t
+init_ctl_socket(void)
+{
+ err_t failed = NULL;
+
+ delete_ctl_socket(); /* preventative medicine */
+ ctl_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (ctl_fd == -1)
+ failed = "create";
+ else if (fcntl(ctl_fd, F_SETFD, FD_CLOEXEC) == -1)
+ failed = "fcntl FD+CLOEXEC";
+ else if (setsockopt(ctl_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) < 0)
+ failed = "setsockopt";
+ else
+ {
+ /* to keep control socket secure, use umask */
+ mode_t ou = umask(~S_IRWXU);
+
+ if (bind(ctl_fd, (struct sockaddr *)&ctl_addr
+ , offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
+ failed = "bind";
+ umask(ou);
+ }
+
+ /* 5 is a haphazardly chosen limit for the backlog.
+ * Rumour has it that this is the max on BSD systems.
+ */
+ if (failed == NULL && listen(ctl_fd, 5) < 0)
+ failed = "listen() on";
+
+ return failed == NULL? NULL : builddiag("could not %s control socket: %d %s"
+ , failed, errno, strerror(errno));
+}
+
+void
+delete_ctl_socket(void)
+{
+ /* Is noting failure useful? Not when used as preventative medicine. */
+ unlink(ctl_addr.sun_path);
+}
+
+#ifdef IPSECPOLICY
+/* Initialize the info socket.
+ */
+err_t
+init_info_socket(void)
+{
+ err_t failed = NULL;
+
+ delete_info_socket(); /* preventative medicine */
+ info_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (info_fd == -1)
+ failed = "create";
+ else if (fcntl(info_fd, F_SETFD, FD_CLOEXEC) == -1)
+ failed = "fcntl FD+CLOEXEC";
+ else if (setsockopt(info_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) < 0)
+ failed = "setsockopt";
+ else
+ {
+ /* this socket should be openable by all proceses */
+ mode_t ou = umask(0);
+
+ if (bind(info_fd, (struct sockaddr *)&info_addr
+ , offsetof(struct sockaddr_un, sun_path) + strlen(info_addr.sun_path)) < 0)
+ failed = "bind";
+ umask(ou);
+ }
+
+ /* 64 might be big enough, and the system may limit us anyway.
+ */
+ if (failed == NULL && listen(info_fd, 64) < 0)
+ failed = "listen() on";
+
+ return failed == NULL? NULL : builddiag("could not %s info socket: %d %s"
+ , failed, errno, strerror(errno));
+}
+
+void
+delete_info_socket(void)
+{
+ unlink(info_addr.sun_path);
+}
+#endif /* IPSECPOLICY */
+
+
+bool listening = FALSE; /* should we pay attention to IKE messages? */
+
+struct iface *interfaces = NULL; /* public interfaces */
+
+/* Initialize the interface sockets. */
+
+static void
+mark_ifaces_dead(void)
+{
+ struct iface *p;
+
+ for (p = interfaces; p != NULL; p = p->next)
+ p->change = IFN_DELETE;
+}
+
+static void
+free_dead_ifaces(void)
+{
+ struct iface *p;
+ bool some_dead = FALSE
+ , some_new = FALSE;
+
+ for (p = interfaces; p != NULL; p = p->next)
+ {
+ if (p->change == IFN_DELETE)
+ {
+ plog("shutting down interface %s/%s %s"
+ , p->vname, p->rname, ip_str(&p->addr));
+ some_dead = TRUE;
+ }
+ else if (p->change == IFN_ADD)
+ {
+ some_new = TRUE;
+ }
+ }
+
+ if (some_dead)
+ {
+ struct iface **pp;
+
+ release_dead_interfaces();
+ for (pp = &interfaces; (p = *pp) != NULL; )
+ {
+ if (p->change == IFN_DELETE)
+ {
+ *pp = p->next; /* advance *pp */
+ pfree(p->vname);
+ pfree(p->rname);
+ close(p->fd);
+ pfree(p);
+ }
+ else
+ {
+ pp = &p->next; /* advance pp */
+ }
+ }
+ }
+
+ /* this must be done after the release_dead_interfaces
+ * in case some to the newly unoriented connections can
+ * become oriented here.
+ */
+ if (some_dead || some_new)
+ check_orientations();
+}
+
+void
+free_ifaces(void)
+{
+ mark_ifaces_dead();
+ free_dead_ifaces();
+}
+
+struct raw_iface {
+ ip_address addr;
+ char name[IFNAMSIZ + 20]; /* what would be a safe size? */
+ struct raw_iface *next;
+};
+
+/* Called to handle --interface <ifname>
+ * Semantics: if specified, only these (real) interfaces are considered.
+ */
+static const char *pluto_ifn[10];
+static int pluto_ifn_roof = 0;
+
+bool
+use_interface(const char *rifn)
+{
+ if (pluto_ifn_roof >= (int)elemsof(pluto_ifn))
+ {
+ return FALSE;
+ }
+ else
+ {
+ pluto_ifn[pluto_ifn_roof++] = rifn;
+ return TRUE;
+ }
+}
+
+#ifndef IPSECDEVPREFIX
+# define IPSECDEVPREFIX "ipsec"
+#endif
+
+static struct raw_iface *
+find_raw_ifaces4(void)
+{
+ int j; /* index into buf */
+ struct ifconf ifconf;
+ struct ifreq buf[300]; /* for list of interfaces -- arbitrary limit */
+ struct raw_iface *rifaces = NULL;
+ int master_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Get a UDP socket */
+
+ /* get list of interfaces with assigned IPv4 addresses from system */
+
+ if (master_sock == -1)
+ exit_log_errno((e, "socket() failed in find_raw_ifaces4()"));
+
+ if (setsockopt(master_sock, SOL_SOCKET, SO_REUSEADDR
+ , (const void *)&on, sizeof(on)) < 0)
+ exit_log_errno((e, "setsockopt() in find_raw_ifaces4()"));
+
+ /* bind the socket */
+ {
+ ip_address any;
+
+ happy(anyaddr(AF_INET, &any));
+ setportof(htons(pluto_port), &any);
+ if (bind(master_sock, sockaddrof(&any), sockaddrlenof(&any)) < 0)
+ exit_log_errno((e, "bind() failed in find_raw_ifaces4()"));
+ }
+
+ /* Get local interfaces. See netdevice(7). */
+ ifconf.ifc_len = sizeof(buf);
+ ifconf.ifc_buf = (void *) buf;
+ zero(buf);
+
+ if (ioctl(master_sock, SIOCGIFCONF, &ifconf) == -1)
+ exit_log_errno((e, "ioctl(SIOCGIFCONF) in find_raw_ifaces4()"));
+
+ /* Add an entry to rifaces for each interesting interface. */
+ for (j = 0; (j+1) * sizeof(*buf) <= (size_t)ifconf.ifc_len; j++)
+ {
+ struct raw_iface ri;
+ const struct sockaddr_in *rs = (struct sockaddr_in *) &buf[j].ifr_addr;
+ struct ifreq auxinfo;
+
+ /* ignore all but AF_INET interfaces */
+ if (rs->sin_family != AF_INET)
+ continue; /* not interesting */
+
+ /* build a NUL-terminated copy of the rname field */
+ memcpy(ri.name, buf[j].ifr_name, IFNAMSIZ);
+ ri.name[IFNAMSIZ] = '\0';
+
+ /* ignore if our interface names were specified, and this isn't one */
+ if (pluto_ifn_roof != 0)
+ {
+ int i;
+
+ for (i = 0; i != pluto_ifn_roof; i++)
+ if (streq(ri.name, pluto_ifn[i]))
+ break;
+ if (i == pluto_ifn_roof)
+ continue; /* not found -- skip */
+ }
+
+ /* Find out stuff about this interface. See netdevice(7). */
+ zero(&auxinfo); /* paranoia */
+ memcpy(auxinfo.ifr_name, buf[j].ifr_name, IFNAMSIZ);
+ if (ioctl(master_sock, SIOCGIFFLAGS, &auxinfo) == -1)
+ exit_log_errno((e
+ , "ioctl(SIOCGIFFLAGS) for %s in find_raw_ifaces4()"
+ , ri.name));
+ if (!(auxinfo.ifr_flags & IFF_UP))
+ continue; /* ignore an interface that isn't UP */
+
+ /* ignore unconfigured interfaces */
+ if (rs->sin_addr.s_addr == 0)
+ continue;
+
+ happy(initaddr((const void *)&rs->sin_addr, sizeof(struct in_addr)
+ , AF_INET, &ri.addr));
+
+ DBG(DBG_CONTROL, DBG_log("found %s with address %s"
+ , ri.name, ip_str(&ri.addr)));
+ ri.next = rifaces;
+ rifaces = clone_thing(ri, "struct raw_iface");
+ }
+
+ close(master_sock);
+
+ return rifaces;
+}
+
+static struct raw_iface *
+find_raw_ifaces6(void)
+{
+
+ /* Get list of interfaces with IPv6 addresses from system from /proc/net/if_inet6).
+ *
+ * Documentation of format?
+ * RTFS: linux-2.2.16/net/ipv6/addrconf.c:iface_proc_info()
+ * linux-2.4.9-13/net/ipv6/addrconf.c:iface_proc_info()
+ *
+ * Sample from Gerhard's laptop:
+ * 00000000000000000000000000000001 01 80 10 80 lo
+ * 30490009000000000000000000010002 02 40 00 80 ipsec0
+ * 30490009000000000000000000010002 07 40 00 80 eth0
+ * fe80000000000000025004fffefd5484 02 0a 20 80 ipsec0
+ * fe80000000000000025004fffefd5484 07 0a 20 80 eth0
+ *
+ * Each line contains:
+ * - IPv6 address: 16 bytes, in hex, no punctuation
+ * - ifindex: 1 byte, in hex
+ * - prefix_len: 1 byte, in hex
+ * - scope (e.g. global, link local): 1 byte, in hex
+ * - flags: 1 byte, in hex
+ * - device name: string, followed by '\n'
+ */
+ struct raw_iface *rifaces = NULL;
+ static const char proc_name[] = "/proc/net/if_inet6";
+ FILE *proc_sock = fopen(proc_name, "r");
+
+ if (proc_sock == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("could not open %s", proc_name));
+ }
+ else
+ {
+ for (;;)
+ {
+ struct raw_iface ri;
+ unsigned short xb[8]; /* IPv6 address as 8 16-bit chunks */
+ char sb[8*5]; /* IPv6 address as string-with-colons */
+ unsigned int if_idx; /* proc field, not used */
+ unsigned int plen; /* proc field, not used */
+ unsigned int scope; /* proc field, used to exclude link-local */
+ unsigned int dad_status; /* proc field, not used */
+ /* ??? I hate and distrust scanf -- DHR */
+ int r = fscanf(proc_sock
+ , "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx"
+ " %02x %02x %02x %02x %20s\n"
+ , xb+0, xb+1, xb+2, xb+3, xb+4, xb+5, xb+6, xb+7
+ , &if_idx, &plen, &scope, &dad_status, ri.name);
+
+ /* ??? we should diagnose any problems */
+ if (r != 13)
+ break;
+
+ /* ignore addresses with link local scope.
+ * From linux-2.4.9-13/include/net/ipv6.h:
+ * IPV6_ADDR_LINKLOCAL 0x0020U
+ * IPV6_ADDR_SCOPE_MASK 0x00f0U
+ */
+ if ((scope & 0x00f0U) == 0x0020U)
+ continue;
+
+ snprintf(sb, sizeof(sb)
+ , "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
+ , xb[0], xb[1], xb[2], xb[3], xb[4], xb[5], xb[6], xb[7]);
+
+ happy(ttoaddr(sb, 0, AF_INET6, &ri.addr));
+
+ if (!isunspecaddr(&ri.addr))
+ {
+ DBG(DBG_CONTROL
+ , DBG_log("found %s with address %s"
+ , ri.name, sb));
+ ri.next = rifaces;
+ rifaces = clone_thing(ri, "struct raw_iface");
+ }
+ }
+ fclose(proc_sock);
+ }
+
+ return rifaces;
+}
+
+#if 1
+static int
+create_socket(struct raw_iface *ifp, const char *v_name, int port)
+{
+ int fd = socket(addrtypeof(&ifp->addr), SOCK_DGRAM, IPPROTO_UDP);
+ int fcntl_flags;
+
+ if (fd < 0)
+ {
+ log_errno((e, "socket() in process_raw_ifaces()"));
+ return -1;
+ }
+
+#if 1
+ /* Set socket Nonblocking */
+ if ((fcntl_flags=fcntl(fd, F_GETFL)) >= 0) {
+ if (!(fcntl_flags & O_NONBLOCK)) {
+ fcntl_flags |= O_NONBLOCK;
+ fcntl(fd, F_SETFL, fcntl_flags);
+ }
+ }
+#endif
+
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ {
+ log_errno((e, "fcntl(,, FD_CLOEXEC) in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR
+ , (const void *)&on, sizeof(on)) < 0)
+ {
+ log_errno((e, "setsockopt SO_REUSEADDR in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+
+ /* To improve error reporting. See ip(7). */
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+ if (setsockopt(fd, SOL_IP, IP_RECVERR
+ , (const void *)&on, sizeof(on)) < 0)
+ {
+ log_errno((e, "setsockopt IP_RECVERR in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+#endif
+
+ /* With IPv6, there is no fragmentation after
+ * it leaves our interface. PMTU discovery
+ * is mandatory but doesn't work well with IKE (why?).
+ * So we must set the IPV6_USE_MIN_MTU option.
+ * See draft-ietf-ipngwg-rfc2292bis-01.txt 11.1
+ */
+#ifdef IPV6_USE_MIN_MTU /* YUCK: not always defined */
+ if (addrtypeof(&ifp->addr) == AF_INET6
+ && setsockopt(fd, SOL_SOCKET, IPV6_USE_MIN_MTU
+ , (const void *)&on, sizeof(on)) < 0)
+ {
+ log_errno((e, "setsockopt IPV6_USE_MIN_MTU in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+#endif
+
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+ if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX)
+ {
+ struct sadb_x_policy policy;
+ int level, opt;
+
+ policy.sadb_x_policy_len = sizeof(policy) / IPSEC_PFKEYv2_ALIGN;
+ policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
+ policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
+ policy.sadb_x_policy_reserved = 0;
+ policy.sadb_x_policy_id = 0;
+ policy.sadb_x_policy_reserved2 = 0;
+
+ if (addrtypeof(&ifp->addr) == AF_INET6)
+ {
+ level = IPPROTO_IPV6;
+ opt = IPV6_IPSEC_POLICY;
+ }
+ else
+ {
+ level = IPPROTO_IP;
+ opt = IP_IPSEC_POLICY;
+ }
+
+ if (setsockopt(fd, level, opt
+ , &policy, sizeof(policy)) < 0)
+ {
+ log_errno((e, "setsockopt IPSEC_POLICY in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+
+ policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
+
+ if (setsockopt(fd, level, opt
+ , &policy, sizeof(policy)) < 0)
+ {
+ log_errno((e, "setsockopt IPSEC_POLICY in process_raw_ifaces()"));
+ close(fd);
+ return -1;
+ }
+ }
+#endif
+
+ setportof(htons(port), &ifp->addr);
+ if (bind(fd, sockaddrof(&ifp->addr), sockaddrlenof(&ifp->addr)) < 0)
+ {
+ log_errno((e, "bind() for %s/%s %s:%u in process_raw_ifaces()"
+ , ifp->name, v_name
+ , ip_str(&ifp->addr), (unsigned) port));
+ close(fd);
+ return -1;
+ }
+ setportof(htons(pluto_port), &ifp->addr);
+ return fd;
+}
+#endif
+
+static void
+process_raw_ifaces(struct raw_iface *rifaces)
+{
+ struct raw_iface *ifp;
+
+ /* Find all virtual/real interface pairs.
+ * For each real interface...
+ */
+ for (ifp = rifaces; ifp != NULL; ifp = ifp->next)
+ {
+ struct raw_iface *v = NULL; /* matching ipsecX interface */
+ struct raw_iface fake_v;
+ bool after = FALSE; /* has vfp passed ifp on the list? */
+ bool bad = FALSE;
+ struct raw_iface *vfp;
+
+ /* ignore if virtual (ipsec*) interface */
+ if (strncmp(ifp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1) == 0)
+ continue;
+
+ for (vfp = rifaces; vfp != NULL; vfp = vfp->next)
+ {
+ if (vfp == ifp)
+ {
+ after = TRUE;
+ }
+ else if (sameaddr(&ifp->addr, &vfp->addr))
+ {
+ /* Different entries with matching IP addresses.
+ * Many interesting cases.
+ */
+ if (strncmp(vfp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1) == 0)
+ {
+ if (v != NULL && !streq(v->name, vfp->name))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "ipsec interfaces %s and %s share same address %s"
+ , v->name, vfp->name, ip_str(&ifp->addr));
+ bad = TRUE;
+ }
+ else
+ {
+ v = vfp; /* current winner */
+ }
+ }
+ else
+ {
+ /* ugh: a second real interface with the same IP address
+ * "after" allows us to avoid double reporting.
+ */
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+ if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX)
+ {
+ if (after)
+ {
+ bad = TRUE;
+ break;
+ }
+ continue;
+ }
+#endif
+ if (after)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "IP interfaces %s and %s share address %s!"
+ , ifp->name, vfp->name, ip_str(&ifp->addr));
+ }
+ bad = TRUE;
+ }
+ }
+ }
+
+ if (bad)
+ continue;
+
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+ if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX)
+ {
+ v = ifp;
+ goto add_entry;
+ }
+#endif
+
+ /* what if we didn't find a virtual interface? */
+ if (v == NULL)
+ {
+ if (no_klips)
+ {
+ /* kludge for testing: invent a virtual device */
+ static const char fvp[] = "virtual";
+ fake_v = *ifp;
+ passert(sizeof(fake_v.name) > sizeof(fvp));
+ strcpy(fake_v.name, fvp);
+ addrtot(&ifp->addr, 0, fake_v.name + sizeof(fvp) - 1
+ , sizeof(fake_v.name) - (sizeof(fvp) - 1));
+ v = &fake_v;
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("IP interface %s %s has no matching ipsec* interface -- ignored"
+ , ifp->name, ip_str(&ifp->addr)));
+ continue;
+ }
+ }
+
+ /* We've got all we need; see if this is a new thing:
+ * search old interfaces list.
+ */
+#if defined(linux) && defined(KERNEL26_SUPPORT)
+add_entry:
+#endif
+ {
+ struct iface **p = &interfaces;
+
+ for (;;)
+ {
+ struct iface *q = *p;
+
+ /* search is over if at end of list */
+ if (q == NULL)
+ {
+ /* matches nothing -- create a new entry */
+ int fd = create_socket(ifp, v->name, pluto_port);
+
+ if (fd < 0)
+ break;
+
+#ifdef NAT_TRAVERSAL
+ if (nat_traversal_support_non_ike
+ && addrtypeof(&ifp->addr) == AF_INET)
+ {
+ nat_traversal_espinudp_socket(fd, ESPINUDP_WITH_NON_IKE);
+ }
+#endif
+
+ q = alloc_thing(struct iface, "struct iface");
+ q->rname = clone_str(ifp->name, "real device name");
+ q->vname = clone_str(v->name, "virtual device name");
+ q->addr = ifp->addr;
+ q->fd = fd;
+ q->next = interfaces;
+ q->change = IFN_ADD;
+ interfaces = q;
+ plog("adding interface %s/%s %s:%d"
+ , q->vname, q->rname, ip_str(&q->addr), pluto_port);
+#ifdef NAT_TRAVERSAL
+ if (nat_traversal_support_port_floating
+ && addrtypeof(&ifp->addr) == AF_INET)
+ {
+ fd = create_socket(ifp, v->name, NAT_T_IKE_FLOAT_PORT);
+ if (fd < 0)
+ break;
+ nat_traversal_espinudp_socket(fd,
+ ESPINUDP_WITH_NON_ESP);
+ q = alloc_thing(struct iface, "struct iface");
+ q->rname = clone_str(ifp->name, "real device name");
+ q->vname = clone_str(v->name, "virtual device name");
+ q->addr = ifp->addr;
+ setportof(htons(NAT_T_IKE_FLOAT_PORT), &q->addr);
+ q->fd = fd;
+ q->next = interfaces;
+ q->change = IFN_ADD;
+ q->ike_float = TRUE;
+ interfaces = q;
+ plog("adding interface %s/%s %s:%d",
+ q->vname, q->rname, ip_str(&q->addr), NAT_T_IKE_FLOAT_PORT);
+ }
+#endif
+ break;
+ }
+
+ /* search over if matching old entry found */
+ if (streq(q->rname, ifp->name)
+ && streq(q->vname, v->name)
+ && sameaddr(&q->addr, &ifp->addr))
+ {
+ /* matches -- rejuvinate old entry */
+ q->change = IFN_KEEP;
+#ifdef NAT_TRAVERSAL
+ /* look for other interfaces to keep (due to NAT-T) */
+ for (q = q->next ; q ; q = q->next) {
+ if (streq(q->rname, ifp->name)
+ && streq(q->vname, v->name)
+ && sameaddr(&q->addr, &ifp->addr)) {
+ q->change = IFN_KEEP;
+ }
+ }
+#endif
+ break;
+ }
+
+ /* try again */
+ p = &q->next;
+ } /* for (;;) */
+ }
+ }
+
+ /* delete the raw interfaces list */
+ while (rifaces != NULL)
+ {
+ struct raw_iface *t = rifaces;
+
+ rifaces = t->next;
+ pfree(t);
+ }
+}
+
+void
+find_ifaces(void)
+{
+ mark_ifaces_dead();
+ process_raw_ifaces(find_raw_ifaces4());
+ process_raw_ifaces(find_raw_ifaces6());
+
+ free_dead_ifaces(); /* ditch remaining old entries */
+
+ if (interfaces == NULL)
+ loglog(RC_LOG_SERIOUS, "no public interfaces found");
+}
+
+void
+show_ifaces_status(void)
+{
+ struct iface *p;
+
+ for (p = interfaces; p != NULL; p = p->next)
+ whack_log(RC_COMMENT, "interface %s/%s %s:%d"
+ , p->vname, p->rname, ip_str(&p->addr), ntohs(portof(&p->addr)));
+}
+
+void
+show_debug_status(void)
+{
+#ifdef DEBUG
+ whack_log(RC_COMMENT, "debug %s"
+ , bitnamesof(debug_bit_names, cur_debugging));
+#endif
+}
+
+static volatile sig_atomic_t sighupflag = FALSE;
+
+static void
+huphandler(int sig UNUSED)
+{
+ sighupflag = TRUE;
+}
+
+static volatile sig_atomic_t sigtermflag = FALSE;
+
+static void
+termhandler(int sig UNUSED)
+{
+ sigtermflag = TRUE;
+}
+
+/* call_server listens for incoming ISAKMP packets and Whack messages,
+ * and handles timer events.
+ */
+void
+call_server(void)
+{
+ struct iface *ifp;
+
+ /* catch SIGHUP and SIGTERM */
+ {
+ int r;
+ struct sigaction act;
+
+ act.sa_handler = &huphandler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0; /* no SA_ONESHOT, no SA_RESTART, no nothing */
+ r = sigaction(SIGHUP, &act, NULL);
+ passert(r == 0);
+
+ act.sa_handler = &termhandler;
+ r = sigaction(SIGTERM, &act, NULL);
+ passert(r == 0);
+ }
+
+ for (;;)
+ {
+ fd_set readfds;
+ fd_set writefds;
+ int ndes;
+
+ /* wait for next interesting thing */
+
+ for (;;)
+ {
+ long next_time = next_event(); /* time to any pending timer event */
+ int maxfd = ctl_fd;
+
+ if (sigtermflag)
+ exit_pluto(0);
+
+ if (sighupflag)
+ {
+ /* Ignorant folks think poking any daemon with SIGHUP
+ * is polite. We catch it and tell them otherwise.
+ * There is one use: unsticking a hung recvfrom.
+ * This sticking happens sometimes -- kernel bug?
+ */
+ sighupflag = FALSE;
+ plog("Pluto ignores SIGHUP -- perhaps you want \"whack --listen\"");
+ }
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_SET(ctl_fd, &readfds);
+#ifdef IPSECPOLICY
+ FD_SET(info_fd, &readfds);
+ if (maxfd < info_fd)
+ maxfd = info_fd;
+#endif
+
+ /* the only write file-descriptor of interest */
+ if (adns_qfd != NULL_FD && unsent_ADNS_queries)
+ {
+ if (maxfd < adns_qfd)
+ maxfd = adns_qfd;
+ FD_SET(adns_qfd, &writefds);
+ }
+
+ if (adns_afd != NULL_FD)
+ {
+ if (maxfd < adns_afd)
+ maxfd = adns_afd;
+ FD_SET(adns_afd, &readfds);
+ }
+
+#ifdef KLIPS
+ if (!no_klips)
+ {
+ int fd = *kernel_ops->async_fdp;
+
+ if (kernel_ops->process_queue)
+ kernel_ops->process_queue();
+ if (maxfd < fd)
+ maxfd = fd;
+ passert(!FD_ISSET(fd, &readfds));
+ FD_SET(fd, &readfds);
+ }
+#endif
+
+ if (listening)
+ {
+ for (ifp = interfaces; ifp != NULL; ifp = ifp->next)
+ {
+ if (maxfd < ifp->fd)
+ maxfd = ifp->fd;
+ passert(!FD_ISSET(ifp->fd, &readfds));
+ FD_SET(ifp->fd, &readfds);
+ }
+ }
+
+ if (next_time == -1)
+ {
+ /* select without timer */
+
+ ndes = select(maxfd + 1, &readfds, &writefds, NULL, NULL);
+ }
+ else if (next_time == 0)
+ {
+ /* timer without select: there is a timer event pending,
+ * and it should fire now so don't bother to do the select.
+ */
+ ndes = 0; /* signify timer expiration */
+ }
+ else
+ {
+ /* select with timer */
+
+ struct timeval tm;
+
+ tm.tv_sec = next_time;
+ tm.tv_usec = 0;
+ ndes = select(maxfd + 1, &readfds, &writefds, NULL, &tm);
+ }
+
+ if (ndes != -1)
+ break; /* success */
+
+ if (errno != EINTR)
+ exit_log_errno((e, "select() failed in call_server()"));
+
+ /* retry if terminated by signal */
+ }
+
+ /* figure out what is interesting */
+
+ if (ndes == 0)
+ {
+ /* timer event */
+
+ DBG(DBG_CONTROL,
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*time to handle event"));
+
+ handle_timer_event();
+ passert(GLOBALS_ARE_RESET());
+ }
+ else
+ {
+ /* at least one file descriptor is ready */
+
+ if (adns_qfd != NULL_FD && FD_ISSET(adns_qfd, &writefds))
+ {
+ passert(ndes > 0);
+ send_unsent_ADNS_queries();
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+
+ if (adns_afd != NULL_FD && FD_ISSET(adns_afd, &readfds))
+ {
+ passert(ndes > 0);
+ DBG(DBG_CONTROL,
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*received adns message"));
+ handle_adns_answer();
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+
+#ifdef KLIPS
+ if (!no_klips && FD_ISSET(*kernel_ops->async_fdp, &readfds))
+ {
+ passert(ndes > 0);
+ DBG(DBG_CONTROL,
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*received kernel message"));
+ kernel_ops->process_msg();
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+#endif
+
+ for (ifp = interfaces; ifp != NULL; ifp = ifp->next)
+ {
+ if (FD_ISSET(ifp->fd, &readfds))
+ {
+ /* comm_handle will print DBG_CONTROL intro,
+ * with more info than we have here.
+ */
+
+ passert(ndes > 0);
+ comm_handle(ifp);
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+ }
+
+ if (FD_ISSET(ctl_fd, &readfds))
+ {
+ passert(ndes > 0);
+ DBG(DBG_CONTROL,
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*received whack message"));
+ whack_handle(ctl_fd);
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+
+#ifdef IPSECPOLICY
+ if (FD_ISSET(info_fd, &readfds))
+ {
+ passert(ndes > 0);
+ DBG(DBG_CONTROL,
+ DBG_log(BLANK_FORMAT);
+ DBG_log("*received info message"));
+ info_handle(info_fd);
+ passert(GLOBALS_ARE_RESET());
+ ndes--;
+ }
+#endif
+
+ passert(ndes == 0);
+ }
+ }
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End Variables:
+ */
diff --git a/programs/pluto/server.h b/programs/pluto/server.h
new file mode 100644
index 000000000..aa14d5aaa
--- /dev/null
+++ b/programs/pluto/server.h
@@ -0,0 +1,60 @@
+/* get-next-event loop
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: server.h,v 1.2 2004/03/22 21:53:20 as Exp $
+ */
+
+extern int ctl_fd; /* file descriptor of control (whack) socket */
+extern struct sockaddr_un ctl_addr; /* address of control (whack) socket */
+
+extern int info_fd; /* file descriptor of control (info) socket */
+extern struct sockaddr_un info_addr; /* address of control (info) socket */
+
+extern err_t init_ctl_socket(void);
+extern void delete_ctl_socket(void);
+
+extern bool listening; /* should we pay attention to IKE messages? */
+
+
+/* interface: a terminal point for IKE traffic, IPsec transport mode
+ * and IPsec tunnels.
+ * Essentially:
+ * - an IP device (eg. eth1), and
+ * - its partner, an ipsec device (eg. ipsec0), and
+ * - their shared IP address (eg. 10.7.3.2)
+ * Note: the port for IKE is always implicitly UDP/pluto_port.
+ */
+struct iface {
+ char *vname; /* virtual (ipsec) device name */
+ char *rname; /* real device name */
+ ip_address addr; /* interface IP address */
+ int fd; /* file descriptor of socket for IKE UDP messages */
+ struct iface *next;
+#ifdef NAT_TRAVERSAL
+ bool ike_float;
+#endif
+ enum { IFN_ADD, IFN_KEEP, IFN_DELETE } change;
+};
+
+extern struct iface *interfaces; /* public interfaces */
+
+extern bool use_interface(const char *rifn);
+extern void find_ifaces(void);
+extern void show_ifaces_status(void);
+extern void free_ifaces(void);
+extern void show_debug_status(void);
+extern void call_server(void);
+
+/* in rcv_info.c */
+extern err_t init_info_socket(void);
+extern void delete_info_socket(void);
diff --git a/programs/pluto/sha1.c b/programs/pluto/sha1.c
new file mode 100644
index 000000000..bbf062876
--- /dev/null
+++ b/programs/pluto/sha1.c
@@ -0,0 +1,193 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#define SHA1HANDSOFF
+
+#include <string.h>
+#include <sys/types.h> /* for u_int*_t */
+#include <endian.h> /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */
+
+#include "sha1.h"
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#elif BYTE_ORDER == BIG_ENDIAN
+#define blk0(i) block->l[i]
+#else
+#error "Endianness not defined!"
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
+{
+u_int32_t a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ u_int32_t l[16];
+} CHAR64LONG16;
+#ifdef SHA1HANDSOFF
+CHAR64LONG16 block[1]; /* use array to appear as a pointer */
+ memcpy(block, buffer, 64);
+#else
+ /* The following had better never be used because it causes the
+ * pointer-to-const buffer to be cast into a pointer to non-const.
+ * And the result is written through. I threw a "const" in, hoping
+ * this will cause a diagnostic.
+ */
+CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+#ifdef SHA1HANDSOFF
+ memset(block, '\0', sizeof(block));
+#endif
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len)
+{
+u_int32_t i;
+u_int32_t j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1]++;
+ context->count[1] += (len>>29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+unsigned i;
+unsigned char finalcount[8];
+unsigned char c;
+
+#if 0 /* untested "improvement" by DHR */
+ /* Convert context->count to a sequence of bytes
+ * in finalcount. Second element first, but
+ * big-endian order within element.
+ * But we do it all backwards.
+ */
+ unsigned char *fcp = &finalcount[8];
+
+ for (i = 0; i < 2; i++)
+ {
+ u_int32_t t = context->count[i];
+ int j;
+
+ for (j = 0; j < 4; t >>= 8, j++)
+ *--fcp = (unsigned char) t
+ }
+#else
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+#endif
+ c = 0200;
+ SHA1Update(context, &c, 1);
+ while ((context->count[0] & 504) != 448) {
+ c = 0000;
+ SHA1Update(context, &c, 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ memset(context, '\0', sizeof(*context));
+ memset(&finalcount, '\0', sizeof(finalcount));
+}
diff --git a/programs/pluto/sha1.h b/programs/pluto/sha1.h
new file mode 100644
index 000000000..64b3d2f5d
--- /dev/null
+++ b/programs/pluto/sha1.h
@@ -0,0 +1,16 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+*/
+
+typedef struct {
+ u_int32_t state[5];
+ u_int32_t count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
diff --git a/programs/pluto/smallprime.c b/programs/pluto/smallprime.c
new file mode 100644
index 000000000..87497d096
--- /dev/null
+++ b/programs/pluto/smallprime.c
@@ -0,0 +1,122 @@
+/* smallprime.c - List of small primes
+ * Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef PLUTO
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "gcryptfix.h"
+#else
+/* #include <config.h> */
+/* #include <stdio.h> */
+/* #include <stdlib.h> */
+/* #include "util.h" */
+/* #include "types.h" */
+#endif
+
+/* Note: 2 is not included because it can be tested more easily
+ * by looking at bit 0. The last entry in this list is marked by a zero
+ */
+ushort
+small_prime_numbers[] = {
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
+ 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
+ 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
+ 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
+ 211, 223, 227, 229, 233, 239, 241, 251, 257, 263,
+ 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
+ 331, 337, 347, 349, 353, 359, 367, 373, 379, 383,
+ 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
+ 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
+ 509, 521, 523, 541, 547, 557, 563, 569, 571, 577,
+ 587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
+ 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
+ 709, 719, 727, 733, 739, 743, 751, 757, 761, 769,
+ 773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
+ 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
+ 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
+ 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
+ 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091,
+ 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
+ 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213,
+ 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277,
+ 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307,
+ 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
+ 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
+ 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493,
+ 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559,
+ 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609,
+ 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
+ 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
+ 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789,
+ 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871,
+ 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931,
+ 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997,
+ 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053,
+ 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111,
+ 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161,
+ 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243,
+ 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297,
+ 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
+ 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411,
+ 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473,
+ 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
+ 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633,
+ 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687,
+ 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729,
+ 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791,
+ 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851,
+ 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917,
+ 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999,
+ 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061,
+ 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137,
+ 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209,
+ 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271,
+ 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
+ 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391,
+ 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467,
+ 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533,
+ 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583,
+ 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643,
+ 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709,
+ 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779,
+ 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851,
+ 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917,
+ 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989,
+ 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049,
+ 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111,
+ 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
+ 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243,
+ 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297,
+ 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391,
+ 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457,
+ 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519,
+ 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597,
+ 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657,
+ 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729,
+ 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799,
+ 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889,
+ 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951,
+ 4957, 4967, 4969, 4973, 4987, 4993, 4999,
+ 0
+};
+
+
diff --git a/programs/pluto/smartcard.c b/programs/pluto/smartcard.c
new file mode 100644
index 000000000..f1994f1cf
--- /dev/null
+++ b/programs/pluto/smartcard.c
@@ -0,0 +1,1956 @@
+/* Support of smartcards and cryptotokens
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * Copyright (C) 2004 David Buechi, Michael Meier
+ * Zuercher Hochschule Winterthur, Switzerland
+ *
+ * Copyright (C) 2005 Michael Joosten
+ *
+ * Copyright (C) 2005 Andreas Steffen
+ * Hochschule für Technik Rapperswil, Switzerland
+ *
+ * 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: smartcard.c,v 1.41 2006/01/04 21:03:52 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <dlfcn.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+
+#ifdef SMARTCARD
+#include "rsaref/unix.h"
+#include "rsaref/pkcs11.h"
+#endif
+
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+#include "x509.h"
+#include "ca.h"
+#include "certs.h"
+#include "keys.h"
+#include "smartcard.h"
+#include "whack.h"
+#include "fetch.h"
+
+#define DEFAULT_BASE 16
+
+/* chained list of smartcard records */
+static smartcard_t *smartcards = NULL;
+
+/* number of generated sc objects */
+static int sc_number = 0;
+
+const smartcard_t empty_sc = {
+ NULL , /* next */
+ 0 , /* last_load */
+ { CERT_NONE, {NULL} }, /* last_cert */
+ 0 , /* count */
+ 0 , /* number */
+ 999999 , /* slot */
+ NULL , /* id */
+ NULL , /* label */
+ { NULL, 0 } , /* pin */
+ FALSE , /* pinpad */
+ FALSE , /* valid */
+ FALSE , /* session_opened */
+ FALSE , /* logged_in */
+ TRUE , /* any_slot */
+ 0L , /* session */
+};
+
+#ifdef SMARTCARD /* compile with smartcard support */
+
+#define SCX_MAGIC 0xd00bed00
+
+struct scx_pkcs11_module {
+ u_int _magic;
+ void *handle;
+};
+
+typedef struct scx_pkcs11_module scx_pkcs11_module_t;
+
+/* PKCS #11 cryptoki context */
+static bool scx_initialized = FALSE;
+static scx_pkcs11_module_t *pkcs11_module = NULL_PTR;
+static CK_FUNCTION_LIST_PTR pkcs11_functions = NULL_PTR;
+
+/* crytoki v2.11 - return values of PKCS #11 functions*/
+
+static const char *const pkcs11_return_name[] = {
+ "CKR_OK",
+ "CKR_CANCEL",
+ "CKR_HOST_MEMORY",
+ "CKR_SLOT_ID_INVALID",
+ "CKR_FLAGS_INVALID",
+ "CKR_GENERAL_ERROR",
+ "CKR_FUNCTION_FAILED",
+ "CKR_ARGUMENTS_BAD",
+ "CKR_NO_EVENT",
+ "CKR_NEED_TO_CREATE_THREADS",
+ "CKR_CANT_LOCK"
+ };
+
+static const char *const pkcs11_return_name_10[] = {
+ "CKR_ATTRIBUTE_READ_ONLY",
+ "CKR_ATTRIBUTE_SENSITIVE",
+ "CKR_ATTRIBUTE_TYPE_INVALID",
+ "CKR_ATTRIBUTE_VALUE_INVALID"
+ };
+
+static const char *const pkcs11_return_name_20[] = {
+ "CKR_DATA_INVALID",
+ "CKR_DATA_LEN_RANGE"
+ };
+
+static const char *const pkcs11_return_name_30[] = {
+ "CKR_DEVICE_ERROR",
+ "CKR_DEVICE_MEMORY",
+ "CKR_DEVICE_REMOVED"
+ };
+
+static const char *const pkcs11_return_name_40[] = {
+ "CKR_ENCRYPTED_DATA_INVALID",
+ "CKR_ENCRYPTED_DATA_LEN_RANGE"
+ };
+
+static const char *const pkcs11_return_name_50[] = {
+ "CKR_FUNCTION_CANCELED",
+ "CKR_FUNCTION_NOT_PARALLEL",
+ "CKR_0x52_UNDEFINED",
+ "CKR_0x53_UNDEFINED",
+ "CKR_FUNCTION_NOT_SUPPORTED"
+ };
+
+static const char *const pkcs11_return_name_60[] = {
+ "CKR_KEY_HANDLE_INVALID",
+ "CKR_KEY_SENSITIVE",
+ "CKR_KEY_SIZE_RANGE",
+ "CKR_KEY_TYPE_INCONSISTENT",
+ "CKR_KEY_NOT_NEEDED",
+ "CKR_KEY_CHANGED",
+ "CKR_KEY_NEEDED",
+ "CKR_KEY_INDIGESTIBLE",
+ "CKR_KEY_FUNCTION_NOT_PERMITTED",
+ "CKR_KEY_NOT_WRAPPABLE",
+ "CKR_KEY_UNEXTRACTABLE"
+ };
+
+static const char *const pkcs11_return_name_70[] = {
+ "CKR_MECHANISM_INVALID",
+ "CKR_MECHANISM_PARAM_INVALID"
+ };
+
+static const char *const pkcs11_return_name_80[] = {
+ "CKR_OBJECT_HANDLE_INVALID"
+ };
+
+static const char *const pkcs11_return_name_90[] = {
+ "CKR_OPERATION_ACTIVE",
+ "CKR_OPERATION_NOT_INITIALIZED"
+ };
+
+static const char *const pkcs11_return_name_A0[] = {
+ "CKR_PIN_INCORRECT",
+ "CKR_PIN_INVALID",
+ "CKR_PIN_LEN_RANGE",
+ "CKR_PIN_EXPIRED",
+ "CKR_PIN_LOCKED"
+ };
+
+static const char *const pkcs11_return_name_B0[] = {
+ "CKR_SESSION_CLOSED",
+ "CKR_SESSION_COUNT",
+ "CKR_0xB2_UNDEFINED",
+ "CKR_SESSION_HANDLE_INVALID",
+ "CKR_SESSION_PARALLEL_NOT_SUPPORTED",
+ "CKR_SESSION_READ_ONLY",
+ "CKR_SESSION_EXISTS",
+ "CKR_SESSION_READ_ONLY_EXISTS",
+ "CKR_SESSION_READ_WRITE_SO_EXISTS"
+ };
+
+static const char *const pkcs11_return_name_C0[] = {
+ "CKR_SIGNATURE_INVALID",
+ "CKR_SIGNATURE_LEN_RANGE"
+ };
+
+static const char *const pkcs11_return_name_D0[] = {
+ "CKR_TEMPLATE_INCOMPLETE",
+ "CKR_TEMPLATE_INCONSISTENT"
+ };
+
+static const char *const pkcs11_return_name_E0[] = {
+ "CKR_TOKEN_NOT_PRESENT",
+ "CKR_TOKEN_NOT_RECOGNIZED",
+ "CKR_TOKEN_WRITE_PROTECTED"
+ };
+
+static const char *const pkcs11_return_name_F0[] = {
+ "CKR_UNWRAPPING_KEY_HANDLE_INVALID",
+ "CKR_UNWRAPPING_KEY_SIZE_RANGE",
+ "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT"
+ };
+
+static const char *const pkcs11_return_name_100[] = {
+ "CKR_USER_ALREADY_LOGGED_IN",
+ "CKR_USER_NOT_LOGGED_IN",
+ "CKR_USER_PIN_NOT_INITIALIZED",
+ "CKR_USER_TYPE_INVALID",
+ "CKR_USER_ANOTHER_ALREADY_LOGGED_IN",
+ "CKR_USER_TOO_MANY_TYPES"
+ };
+
+static const char *const pkcs11_return_name_110[] = {
+ "CKR_WRAPPED_KEY_INVALID",
+ "CKR_0x111_UNDEFINED",
+ "CKR_WRAPPED_KEY_LEN_RANGE",
+ "CKR_WRAPPING_KEY_HANDLE_INVALID",
+ "CKR_WRAPPING_KEY_SIZE_RANGE",
+ "CKR_WRAPPING_KEY_TYPE_INCONSISTENT"
+ };
+
+static const char *const pkcs11_return_name_120[] = {
+ "CKR_RANDOM_SEED_NOT_SUPPORTED",
+ "CKR_RANDOM_NO_RNG"
+ };
+
+static const char *const pkcs11_return_name_130[] = {
+ "CKR_DOMAIN_PARAMS_INVALID"
+ };
+
+static const char *const pkcs11_return_name_150[] = {
+ "CKR_BUFFER_TOO_SMALL"
+ };
+
+static const char *const pkcs11_return_name_160[] = {
+ "CKR_SAVED_STATE_INVALID"
+ };
+
+static const char *const pkcs11_return_name_170[] = {
+ "CKR_INFORMATION_SENSITIVE"
+ };
+
+static const char *const pkcs11_return_name_180[] = {
+ "CKR_STATE_UNSAVEABLE"
+ };
+
+static const char *const pkcs11_return_name_190[] = {
+ "CKR_CRYPTOKI_NOT_INITIALIZED",
+ "CKR_CRYPTOKI_ALREADY_INITIALIZED"
+ };
+
+static const char *const pkcs11_return_name_1A0[] = {
+ "CKR_MUTEX_BAD",
+ "CKR_MUTEX_NOT_LOCKED"
+ };
+
+static const char *const pkcs11_return_name_200[] = {
+ "CKR_FUNCTION_REJECTED"
+ };
+
+static const char *const pkcs11_return_name_vendor[] = {
+ "CKR_VENDOR_DEFINED"
+ };
+
+static enum_names pkcs11_return_names_vendor =
+ { CKR_VENDOR_DEFINED, CKR_VENDOR_DEFINED
+ , pkcs11_return_name_vendor, NULL };
+
+static enum_names pkcs11_return_names_200 =
+ { CKR_FUNCTION_REJECTED, CKR_FUNCTION_REJECTED
+ , pkcs11_return_name_200, &pkcs11_return_names_vendor };
+
+static enum_names pkcs11_return_names_1A0 =
+ { CKR_MUTEX_BAD, CKR_MUTEX_NOT_LOCKED
+ , pkcs11_return_name_1A0, &pkcs11_return_names_200 };
+
+static enum_names pkcs11_return_names_190 =
+ { CKR_CRYPTOKI_NOT_INITIALIZED, CKR_CRYPTOKI_ALREADY_INITIALIZED
+ , pkcs11_return_name_190, &pkcs11_return_names_1A0 };
+
+static enum_names pkcs11_return_names_180 =
+ { CKR_STATE_UNSAVEABLE, CKR_STATE_UNSAVEABLE
+ , pkcs11_return_name_180, &pkcs11_return_names_190 };
+
+static enum_names pkcs11_return_names_170 =
+ { CKR_INFORMATION_SENSITIVE, CKR_INFORMATION_SENSITIVE
+ , pkcs11_return_name_170, &pkcs11_return_names_180 };
+
+static enum_names pkcs11_return_names_160 =
+ { CKR_SAVED_STATE_INVALID, CKR_SAVED_STATE_INVALID
+ , pkcs11_return_name_160, &pkcs11_return_names_170 };
+
+static enum_names pkcs11_return_names_150 =
+ { CKR_BUFFER_TOO_SMALL, CKR_BUFFER_TOO_SMALL
+ , pkcs11_return_name_150, &pkcs11_return_names_160 };
+
+static enum_names pkcs11_return_names_130 =
+ { CKR_DOMAIN_PARAMS_INVALID, CKR_DOMAIN_PARAMS_INVALID
+ , pkcs11_return_name_130, &pkcs11_return_names_150 };
+
+static enum_names pkcs11_return_names_120 =
+ { CKR_RANDOM_SEED_NOT_SUPPORTED, CKR_RANDOM_NO_RNG
+ , pkcs11_return_name_120, &pkcs11_return_names_130 };
+
+static enum_names pkcs11_return_names_110 =
+ { CKR_WRAPPED_KEY_INVALID, CKR_WRAPPING_KEY_TYPE_INCONSISTENT
+ , pkcs11_return_name_110, &pkcs11_return_names_120 };
+
+static enum_names pkcs11_return_names_100 =
+ { CKR_USER_ALREADY_LOGGED_IN, CKR_USER_TOO_MANY_TYPES
+ , pkcs11_return_name_100, &pkcs11_return_names_110 };
+
+static enum_names pkcs11_return_names_F0 =
+ { CKR_UNWRAPPING_KEY_HANDLE_INVALID, CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT
+ , pkcs11_return_name_F0, &pkcs11_return_names_100 };
+
+static enum_names pkcs11_return_names_E0 =
+ { CKR_TOKEN_NOT_PRESENT, CKR_TOKEN_WRITE_PROTECTED
+ , pkcs11_return_name_E0, &pkcs11_return_names_F0 };
+
+static enum_names pkcs11_return_names_D0 =
+ { CKR_TEMPLATE_INCOMPLETE, CKR_TEMPLATE_INCONSISTENT
+ , pkcs11_return_name_D0,&pkcs11_return_names_E0 };
+
+static enum_names pkcs11_return_names_C0 =
+ { CKR_SIGNATURE_INVALID, CKR_SIGNATURE_LEN_RANGE
+ , pkcs11_return_name_C0, &pkcs11_return_names_D0 };
+
+static enum_names pkcs11_return_names_B0 =
+ { CKR_SESSION_CLOSED, CKR_SESSION_READ_WRITE_SO_EXISTS
+ , pkcs11_return_name_B0, &pkcs11_return_names_C0 };
+
+static enum_names pkcs11_return_names_A0 =
+ { CKR_PIN_INCORRECT, CKR_PIN_LOCKED
+ , pkcs11_return_name_A0, &pkcs11_return_names_B0 };
+
+static enum_names pkcs11_return_names_90 =
+ { CKR_OPERATION_ACTIVE, CKR_OPERATION_NOT_INITIALIZED
+ , pkcs11_return_name_90, &pkcs11_return_names_A0 };
+
+static enum_names pkcs11_return_names_80 =
+ { CKR_OBJECT_HANDLE_INVALID, CKR_OBJECT_HANDLE_INVALID
+ , pkcs11_return_name_80, &pkcs11_return_names_90 };
+
+static enum_names pkcs11_return_names_70 =
+ { CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID
+ , pkcs11_return_name_70, &pkcs11_return_names_80 };
+
+static enum_names pkcs11_return_names_60 =
+ { CKR_KEY_HANDLE_INVALID, CKR_KEY_UNEXTRACTABLE
+ , pkcs11_return_name_60, &pkcs11_return_names_70 };
+
+static enum_names pkcs11_return_names_50 =
+ { CKR_FUNCTION_CANCELED, CKR_FUNCTION_NOT_SUPPORTED
+ , pkcs11_return_name_50, &pkcs11_return_names_60 };
+
+static enum_names pkcs11_return_names_40 =
+ { CKR_ENCRYPTED_DATA_INVALID, CKR_ENCRYPTED_DATA_LEN_RANGE
+ , pkcs11_return_name_40, &pkcs11_return_names_50 };
+
+static enum_names pkcs11_return_names_30 =
+ { CKR_DEVICE_ERROR, CKR_DEVICE_REMOVED
+ , pkcs11_return_name_30, &pkcs11_return_names_40 };
+
+static enum_names pkcs11_return_names_20 =
+ { CKR_DATA_INVALID, CKR_DATA_LEN_RANGE
+ , pkcs11_return_name_20, &pkcs11_return_names_30 };
+
+static enum_names pkcs11_return_names_10 =
+ { CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_VALUE_INVALID
+ , pkcs11_return_name_10, &pkcs11_return_names_20};
+
+static enum_names pkcs11_return_names =
+ { CKR_OK, CKR_CANT_LOCK
+ , pkcs11_return_name, &pkcs11_return_names_10};
+
+/*
+ * Unload a PKCS#11 module.
+ * The calling application is responsible for cleaning up
+ * and calling C_Finalize()
+ */
+static CK_RV
+scx_unload_pkcs11_module(scx_pkcs11_module_t *mod)
+{
+ if (!mod || mod->_magic != SCX_MAGIC)
+ return CKR_ARGUMENTS_BAD;
+
+ if (dlclose(mod->handle) < 0)
+ return CKR_FUNCTION_FAILED;
+
+ memset(mod, 0, sizeof(*mod));
+ pfree(mod);
+ return CKR_OK;
+}
+
+static scx_pkcs11_module_t*
+scx_load_pkcs11_module(const char *name, CK_FUNCTION_LIST_PTR_PTR funcs)
+{
+ CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR);
+ scx_pkcs11_module_t *mod;
+ void *handle;
+ int rv;
+
+ if (name == NULL || *name == '\0')
+ return NULL;
+
+ /* Try to load PKCS#11 library module*/
+ handle = dlopen(name, RTLD_NOW);
+ if (handle == NULL)
+ return NULL;
+
+ mod = alloc_thing(scx_pkcs11_module_t, "scx_pkcs11_module");
+ mod->_magic = SCX_MAGIC;
+ mod->handle = handle;
+
+ /* Get the list of function pointers */
+ c_get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))
+ dlsym(mod->handle, "C_GetFunctionList");
+ if (!c_get_function_list)
+ goto failed;
+
+ rv = c_get_function_list(funcs);
+ if (rv == CKR_OK)
+ return mod;
+
+failed: scx_unload_pkcs11_module(mod);
+ return NULL;
+}
+
+/*
+ * retrieve a certificate object
+ */
+static bool
+scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object
+, smartcard_t *sc, cert_t *cert)
+{
+ size_t hex_len, label_len;
+ u_char *hex_id = NULL;
+ chunk_t blob;
+ x509cert_t *x509cert;
+
+ CK_ATTRIBUTE attr[] = {
+ { CKA_ID, NULL_PTR, 0L },
+ { CKA_LABEL, NULL_PTR, 0L },
+ { CKA_VALUE, NULL_PTR, 0L }
+ };
+
+ /* initialize the return argument */
+ *cert = empty_cert;
+
+ /* get the length of the attributes first */
+ CK_RV rv = pkcs11_functions->C_GetAttributeValue(session, object, attr, 3);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the attribute sizes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ pfreeany(sc->label);
+
+ hex_id = alloc_bytes(attr[0].ulValueLen, "hex id");
+ hex_len = attr[0].ulValueLen;
+ sc->label = alloc_bytes(attr[1].ulValueLen + 1, "sc label");
+ label_len = attr[1].ulValueLen;
+ blob.ptr = alloc_bytes(attr[2].ulValueLen, "x509cert blob");
+ blob.len = attr[2].ulValueLen;
+
+ attr[0].pValue = hex_id;
+ attr[1].pValue = sc->label;
+ attr[2].pValue = blob.ptr;
+
+ /* now get the attributes */
+ rv = pkcs11_functions->C_GetAttributeValue(session, object, attr, 3);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the attributes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ pfree(hex_id);
+ pfreeany(sc->label);
+ pfree(blob.ptr);
+ return FALSE;
+ }
+
+ pfreeany(sc->id);
+
+ /* convert id from hex to ASCII */
+ sc->id = alloc_bytes(2*hex_len + 1, " sc id");
+ datatot(hex_id, hex_len, 16, sc->id, 2*hex_len + 1);
+ pfree(hex_id);
+
+ /* safeguard in case the label is not null terminated */
+ sc->label[label_len] = '\0';
+
+ /* parse the retrieved cert */
+ x509cert = alloc_thing(x509cert_t, "x509cert");
+ *x509cert = empty_x509cert;
+ x509cert->smartcard = TRUE;
+
+ if (!parse_x509cert(blob, 0, x509cert))
+ {
+ plog("failed to load cert from smartcard, error in X.509 certificate");
+ free_x509cert(x509cert);
+ return FALSE;
+ }
+ cert->type = CERT_X509_SIGNATURE;
+ cert->u.x509 = x509cert;
+ return TRUE;
+}
+
+/*
+ * search a given slot for PKCS#11 certificate objects
+ */
+static void
+scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
+{
+ CK_RV rv;
+ CK_OBJECT_CLASS class = CKO_CERTIFICATE;
+ CK_ATTRIBUTE attr[] = {{ CKA_CLASS, &class, sizeof(class) }};
+
+ rv = pkcs11_functions->C_FindObjectsInit(session, attr, 1);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjectsInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return;
+ }
+
+ for (;;)
+ {
+ CK_OBJECT_HANDLE object;
+ CK_ULONG obj_count = 0;
+ err_t ugh;
+ time_t valid_until;
+ smartcard_t *sc;
+ x509cert_t *cert;
+
+ rv = pkcs11_functions->C_FindObjects(session, &object, 1, &obj_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjects: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ break;
+ }
+
+ /* no objects left */
+ if (obj_count == 0)
+ break;
+
+ /* create and initialize a new smartcard object */
+ sc = alloc_thing(smartcard_t, "smartcard");
+ *sc = empty_sc;
+ sc->any_slot = FALSE;
+ sc->slot = slot;
+
+ if (!scx_find_cert_object(session, object, sc, &sc->last_cert))
+ {
+ scx_free(sc);
+ continue;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("found cert in %s with id: %s, label: '%s'"
+ , scx_print_slot(sc, ""), sc->id, sc->label)
+ )
+
+ /* check validity of certificate */
+ cert = sc->last_cert.u.x509;
+ valid_until = cert->notAfter;
+ ugh = check_validity(cert, &valid_until);
+ if (ugh != NULL)
+ {
+ plog(" %s", ugh);
+ free_x509cert(cert);
+ scx_free(sc);
+ continue;
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log(" certificate is valid")
+ )
+ }
+
+ sc = scx_add(sc);
+
+ /* put end entity and ca certificates into different chains */
+ if (cert->isCA)
+ add_authcert(cert, AUTH_CA);
+ else
+ {
+ add_x509_public_key(cert, valid_until, DAL_LOCAL);
+ sc->last_cert.u.x509 = add_x509cert(cert);
+ }
+
+ share_cert(sc->last_cert);
+ time(&sc->last_load);
+ }
+
+ rv = pkcs11_functions->C_FindObjectsFinal(session);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjectsFinal: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ }
+}
+
+/*
+ * search all slots for PKCS#11 certificate objects
+ */
+static void
+scx_find_all_cert_objects(void)
+{
+ CK_RV rv;
+ CK_SLOT_ID_PTR slots = NULL_PTR;
+ CK_ULONG slot_count = 0;
+ CK_ULONG i;
+
+ if (!scx_initialized)
+ {
+ plog("pkcs11 module not initialized");
+ return;
+ }
+
+ /* read size, always returns CKR_OK ! */
+ rv = pkcs11_functions->C_GetSlotList(FALSE, NULL_PTR, &slot_count);
+
+ /* allocate memory for the slots */
+ slots = (CK_SLOT_ID *)alloc_bytes(slot_count * sizeof(CK_SLOT_ID), "slots");
+
+ rv = pkcs11_functions->C_GetSlotList(FALSE, slots, &slot_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_GetSlotList: %s", enum_show(&pkcs11_return_names, rv));
+ pfreeany(slots);
+ return;
+ }
+
+ /* look in every slot for certificate objects */
+ for (i = 0; i < slot_count; i++)
+ {
+ CK_SLOT_ID slot = slots[i];
+ CK_SLOT_INFO info;
+ CK_SESSION_HANDLE session;
+
+ rv = pkcs11_functions->C_GetSlotInfo(slot, &info);
+
+ if (rv != CKR_OK)
+ {
+ plog("error in C_GetSlotInfo: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ continue;
+ }
+
+ if (!(info.flags & CKF_TOKEN_PRESENT))
+ {
+ plog("no token present in slot %lu", slot);
+ continue;
+ }
+
+ rv = pkcs11_functions->C_OpenSession(slot
+ , CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session);
+ if (rv != CKR_OK)
+ {
+ plog("failed to open a session on slot %lu: %s"
+ , slot, enum_show(&pkcs11_return_names, rv));
+ continue;
+ }
+ DBG(DBG_CONTROLMORE,
+ DBG_log("pkcs11 session #%ld for searching slot %lu", session, slot)
+ )
+ scx_find_cert_objects(slot, session);
+
+ rv = pkcs11_functions->C_CloseSession(session);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_CloseSession: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ }
+ }
+ pfreeany(slots);
+}
+#endif
+
+/*
+ * load and initialize PKCS#11 cryptoki module
+ */
+void
+scx_init(const char* module)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+
+ if (scx_initialized)
+ {
+ plog("weird - pkcs11 module seems already to be initialized");
+ return;
+ }
+
+ if (module == NULL)
+#ifdef PKCS11_DEFAULT_LIB
+ module = PKCS11_DEFAULT_LIB;
+#else
+ {
+ plog("no pkcs11 module defined");
+ return;
+ }
+#endif
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 module '%s' loading...", module)
+ )
+ pkcs11_module = scx_load_pkcs11_module(module, &pkcs11_functions);
+ if (pkcs11_module == NULL)
+ {
+ plog("failed to load pkcs11 module '%s'", module);
+ return;
+ }
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 module initializing...")
+ )
+ rv = pkcs11_functions->C_Initialize(NULL);
+ if (rv != CKR_OK)
+ {
+ plog("failed to initialize pkcs11 module: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return;
+ }
+
+ scx_initialized = TRUE;
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 module loaded and initialized")
+ )
+
+ scx_find_all_cert_objects();
+#endif
+}
+
+/*
+ * finalize and unload PKCS#11 cryptoki module
+ */
+void
+scx_finalize(void)
+{
+#ifdef SMARTCARD
+ while (smartcards != NULL)
+ {
+ scx_release(smartcards);
+ }
+
+ if (pkcs11_functions != NULL_PTR)
+ {
+ pkcs11_functions->C_Finalize(NULL_PTR);
+ pkcs11_functions = NULL_PTR;
+ }
+
+ if (pkcs11_module != NULL)
+ {
+ scx_unload_pkcs11_module(pkcs11_module);
+ pkcs11_module = NULL;
+ }
+
+ scx_initialized = FALSE;
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 module finalized and unloaded")
+ )
+#endif
+}
+
+/*
+ * does a filename contain the token %smartcard?
+ */
+bool
+scx_on_smartcard(const char *filename)
+{
+ return strncmp(filename, SCX_TOKEN, strlen(SCX_TOKEN)) == 0;
+}
+
+#ifdef SMARTCARD
+/*
+ * find a specific object on the smartcard
+ */
+static bool
+scx_pkcs11_find_object( CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE_PTR object,
+ CK_OBJECT_CLASS class,
+ const char* id)
+{
+ size_t len;
+ char buf[BUF_LEN];
+ CK_RV rv;
+ CK_ULONG obj_count = 0;
+ CK_ULONG attr_count = 1;
+
+ CK_ATTRIBUTE attr[] = {
+ { CKA_CLASS, &class, sizeof(class) },
+ { CKA_ID, &buf, 0L }
+ };
+
+ if (id != NULL)
+ {
+ ttodata(id, strlen(id), 16, buf, BUF_LEN, &len);
+ attr[1].ulValueLen = len;
+ attr_count = 2;
+ }
+
+ /* get info for certificate with id */
+ rv = pkcs11_functions->C_FindObjectsInit(session, attr, attr_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjectsInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_FindObjects(session, object, 1, &obj_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjects: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_FindObjectsFinal(session);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_FindObjectsFinal: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ return (obj_count != 0);
+}
+
+/*
+ * check if a given certificate object id is found in a slot
+ */
+static bool
+scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_SLOT_INFO info;
+
+ CK_RV rv = pkcs11_functions->C_GetSlotInfo(slot, &info);
+
+ if (rv != CKR_OK)
+ {
+ plog("error in C_GetSlotInfo: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ if (!(info.flags & CKF_TOKEN_PRESENT))
+ {
+ plog("no token present in slot %lu", slot);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_OpenSession(slot
+ , CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session);
+ if (rv != CKR_OK)
+ {
+ plog("failed to open a session on slot %lu: %s"
+ , slot, enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ DBG(DBG_CONTROLMORE,
+ DBG_log("pkcs11 session #%ld for searching slot %lu", session, slot)
+ )
+
+ /* check if there is a certificate on the card in the specified slot */
+ if (scx_pkcs11_find_object(session, &object, CKO_CERTIFICATE, sc->id))
+ {
+ sc->slot = slot;
+ sc->any_slot = FALSE;
+ sc->session = session;
+ sc->session_opened = TRUE;
+ return TRUE;
+ }
+
+ rv = pkcs11_functions->C_CloseSession(session);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_CloseSession: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ }
+ return FALSE;
+}
+#endif
+
+/*
+ * Connect to the smart card in the reader and select the correct slot
+ */
+bool
+scx_establish_context(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ bool id_found = FALSE;
+
+ if (!scx_initialized)
+ {
+ plog("pkcs11 module not initialized");
+ return FALSE;
+ }
+
+ if (sc->session_opened)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld already open", sc->session)
+ )
+ return TRUE;
+ }
+
+ if (!sc->any_slot)
+ id_found = scx_find_cert_id_in_slot(sc, sc->slot);
+
+ if (!id_found)
+ {
+ CK_RV rv;
+ CK_SLOT_ID slot;
+ CK_SLOT_ID_PTR slots = NULL_PTR;
+ CK_ULONG slot_count = 0;
+ CK_ULONG i;
+
+ /* read size, always returns CKR_OK ! */
+ rv = pkcs11_functions->C_GetSlotList(FALSE, NULL_PTR, &slot_count);
+
+ /* allocate memory for the slots */
+ slots = (CK_SLOT_ID *)alloc_bytes(slot_count * sizeof(CK_SLOT_ID), "slots");
+
+ rv = pkcs11_functions->C_GetSlotList(FALSE, slots, &slot_count);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_GetSlotList: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ pfreeany(slots);
+ return FALSE;
+ }
+
+ /* look in every slot for a certificate with a given object ID */
+ for (i = 0; i < slot_count; i++)
+ {
+ slot = slots[i];
+ id_found = scx_find_cert_id_in_slot(sc, slot);
+ if (id_found)
+ break;
+ }
+ pfreeany(slots)
+ }
+
+ if (id_found)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("found token with id %s in slot %lu", sc->id, sc->slot);
+ DBG_log("pkcs11 session #%ld opened", sc->session)
+ )
+ }
+ else
+ {
+ plog(" no certificate with id %s found on smartcard", sc->id);
+ }
+ return id_found;
+#else
+ plog("warning: SMARTCARD support is deactivated in pluto/Makefile!");
+ return FALSE;
+#endif
+}
+
+/*
+ * log in to a session
+ */
+bool
+scx_login(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+
+ if (sc->logged_in)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld login already done", sc->session)
+ )
+ return TRUE;
+ }
+
+ if (sc->pin.ptr == NULL)
+ {
+ plog("unable to log in without PIN!");
+ return FALSE;
+ }
+
+ if (!sc->session_opened)
+ {
+ plog("session not opened");
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Login(sc->session, CKU_USER
+ , (CK_UTF8CHAR *) sc->pin.ptr, sc->pin.len);
+ if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN)
+ {
+ plog("unable to login: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld login successful", sc->session)
+ )
+ sc->logged_in = TRUE;
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+#ifdef SMARTCARD
+/*
+ * logout from a session
+ */
+static void
+scx_logout(smartcard_t *sc)
+{
+ CK_RV rv;
+
+ rv = pkcs11_functions->C_Logout(sc->session);
+ if (rv != CKR_OK)
+ plog("error in C_Logout: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ else
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld logout", sc->session)
+ )
+ sc->logged_in = FALSE;
+}
+#endif
+
+
+/*
+ * Release context and disconnect from card
+ */
+void
+scx_release_context(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+
+ if (!scx_initialized)
+ return;
+
+ if (sc->session_opened)
+ {
+ if (sc->logged_in)
+ scx_logout(sc);
+
+ sc->session_opened = FALSE;
+
+ rv = pkcs11_functions->C_CloseSession(sc->session);
+ if (rv != CKR_OK)
+ plog("error in C_CloseSession: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ else
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("pkcs11 session #%ld closed", sc->session)
+ )
+ }
+#endif
+}
+
+/*
+ * Load host certificate from smartcard
+ */
+bool
+scx_load_cert(const char *filename, smartcard_t **scp, cert_t *cert
+, bool *cached)
+{
+#ifdef SMARTCARD /* compile with smartcard support */
+ CK_OBJECT_HANDLE object;
+
+ const char *number_slot_id = filename + strlen(SCX_TOKEN);
+
+ smartcard_t *sc = scx_add(scx_parse_number_slot_id(number_slot_id));
+
+ /* return the smartcard object */
+ *scp = sc;
+
+ /* is there a cached smartcard certificate? */
+ *cached = sc->last_cert.type != CERT_NONE
+ && (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL;
+
+ if (*cached)
+ {
+ *cert = sc->last_cert;
+ plog(" using cached cert from smartcard #%d (%s, id: %s, label: '%s')"
+ , sc->number
+ , scx_print_slot(sc, "")
+ , sc->id
+ , sc->label);
+ return TRUE;
+ }
+
+ if (!scx_establish_context(sc))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ /* find the certificate object */
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_CERTIFICATE, sc->id))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ /* retrieve the certificate object */
+ if (!scx_find_cert_object(sc->session, object, sc, cert))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+
+ plog(" loaded cert from smartcard #%d (%s, id: %s, label: '%s')"
+ , sc->number
+ , scx_print_slot(sc, "")
+ , sc->id
+ , sc->label);
+
+ return TRUE;
+#else
+ plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!");
+ return FALSE;
+#endif
+}
+
+/*
+ * parse slot number and key id
+ * the following syntax is allowed
+ * number slot id
+ * %smartcard 1 - -
+ * %smartcard#2 2 - -
+ * %smartcard0 - 0 -
+ * %smartcard:45 - - 45
+ * %smartcard0:45 - 0 45
+ */
+smartcard_t*
+scx_parse_number_slot_id(const char *number_slot_id)
+{
+ int len = strlen(number_slot_id);
+ smartcard_t *sc = alloc_thing(smartcard_t, "smartcard");
+
+ /* assign default values */
+ *sc = empty_sc;
+
+ if (len == 0) /* default: use certificate #1 */
+ {
+ sc->number = 1;
+ }
+ else if (*number_slot_id == '#') /* #number scheme */
+ {
+ err_t ugh;
+ unsigned long ul;
+
+ ugh = atoul(number_slot_id+1, len-1 , 10, &ul);
+ if (ugh == NULL)
+ sc->number = (int)ul;
+ else
+ plog("error parsing smartcard number: %s", ugh);
+ }
+ else /* slot:id scheme */
+ {
+ int slot_len = len;
+ char *p = strchr(number_slot_id, ':');
+
+ if (p != NULL)
+ {
+ int id_len = len - (p + 1 - number_slot_id);
+ slot_len -= (1 + id_len);
+
+ if (id_len > 0) /* we have an id */
+ sc->id = p + 1;
+ }
+ if (slot_len > 0) /* we have a slot */
+ {
+ err_t ugh = NULL;
+ unsigned long ul;
+
+ ugh = atoul(number_slot_id, slot_len, 10, &ul);
+ if (ugh == NULL)
+ {
+ sc->slot = ul;
+ sc->any_slot = FALSE;
+ }
+ else
+ plog("error parsing smartcard slot number: %s", ugh);
+ }
+ }
+ /* unshare the id string */
+ sc->id = clone_str(sc->id, "key id");
+ return sc;
+}
+
+/*
+ * Verify pin on card
+ */
+bool
+scx_verify_pin(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+
+ if (!sc->pinpad)
+ sc->valid = FALSE;
+
+ if (sc->pin.ptr == NULL)
+ {
+ plog("unable to verify without PIN");
+ return FALSE;
+ }
+
+ /* establish context */
+ if (!scx_establish_context(sc))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Login(sc->session, CKU_USER,
+ (CK_UTF8CHAR *) sc->pin.ptr, sc->pin.len);
+ if (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN)
+ {
+ sc->valid = TRUE;
+ sc->logged_in = TRUE;
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log((rv == CKR_OK)
+ ? "PIN code correct"
+ : "already logged in, no PIN entry required");
+ DBG_log("pkcs11 session #%ld login successful", sc->session)
+ )
+ }
+ else
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("PIN code incorrect")
+ )
+ }
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+#else
+ sc->valid = FALSE;
+#endif
+ return sc->valid;
+}
+
+/*
+ * Sign hash on smartcard
+ */
+bool
+scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen
+, u_char *out, size_t outlen)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+ CK_OBJECT_HANDLE object;
+ CK_ULONG siglen = (CK_ULONG)outlen;
+ CK_BBOOL sign_flag, decrypt_flag;
+ CK_ATTRIBUTE attr[] = {
+ { CKA_SIGN, &sign_flag, sizeof(sign_flag) },
+ { CKA_DECRYPT, &decrypt_flag, sizeof(decrypt_flag) }
+ };
+
+ if (!sc->logged_in)
+ return FALSE;
+
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id))
+ {
+ plog("unable to find private key with id '%s'", sc->id);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 2);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the private key attributes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("RSA key flags: sign = %s, decrypt = %s"
+ , (sign_flag)? "true":"false"
+ , (decrypt_flag)? "true":"false")
+ )
+
+ if (sign_flag)
+ {
+ CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 };
+
+ rv = pkcs11_functions->C_SignInit(sc->session, &mech, object);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_SignInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Sign(sc->session, (CK_BYTE_PTR)in, inlen
+ , out, &siglen);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_Sign: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ }
+ else if (decrypt_flag)
+ {
+ CK_MECHANISM mech = { CKM_RSA_X_509, NULL_PTR, 0 };
+ size_t padlen;
+ u_char *p = out ;
+
+ /* PKCS#1 v1.5 8.1 encryption-block formatting */
+ *p++ = 0x00;
+ *p++ = 0x01; /* BT (block type) 01 */
+ padlen = outlen - 3 - inlen;
+ memset(p, 0xFF, padlen);
+ p += padlen;
+ *p++ = 0x00;
+ memcpy(p, in, inlen);
+
+ rv = pkcs11_functions->C_DecryptInit(sc->session, &mech, object);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_DecryptInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Decrypt(sc->session, out, outlen
+ , out, &siglen);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_Decrypt: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+ }
+ else
+ {
+ plog("private key has neither sign nor decrypt flag set");
+ return FALSE;
+ }
+
+ if (siglen > (CK_ULONG)outlen)
+ {
+ plog("signature length (%lu) larger than allocated buffer (%d)"
+ , siglen, (int)outlen);
+ return FALSE;
+ }
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+/*
+ * encrypt data block with an RSA public key
+ */
+bool
+scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen
+, u_char *out, size_t *outlen)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+ CK_OBJECT_HANDLE object;
+ CK_ULONG len = (CK_ULONG)(*outlen);
+ CK_BBOOL encrypt_flag;
+ CK_ATTRIBUTE attr[] = {
+ { CKA_MODULUS, NULL_PTR, 0L },
+ { CKA_PUBLIC_EXPONENT, NULL_PTR, 0L },
+ { CKA_ENCRYPT, &encrypt_flag, sizeof(encrypt_flag) }
+ };
+ CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 };
+
+ if (!scx_establish_context(sc))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_PUBLIC_KEY, sc->id))
+ {
+ plog("unable to find public key with id '%s'", sc->id);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 3);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the public key attributes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ if (!encrypt_flag)
+ {
+ plog("public key cannot be used for encryption");
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ /* there must be enough space left for the PKCS#1 v1.5 padding */
+ if (inlen > attr[0].ulValueLen - 11)
+ {
+ plog("smartcard input data length (%d) exceeds maximum of %lu bytes"
+ , (int)inlen, attr[0].ulValueLen - 11);
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_EncryptInit(sc->session, &mech, object);
+
+ if (rv != CKR_OK)
+ {
+ if (rv == CKR_FUNCTION_NOT_SUPPORTED)
+ {
+ RSA_public_key_t rsa;
+ chunk_t plain_text = {in, inlen};
+ chunk_t cipher_text;
+
+ DBG(DBG_CONTROL,
+ DBG_log("doing RSA encryption in software")
+ )
+ attr[0].pValue = alloc_bytes(attr[0].ulValueLen, "modulus");
+ attr[1].pValue = alloc_bytes(attr[1].ulValueLen, "exponent");
+
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 2);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read modulus and public exponent: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ pfree(attr[0].pValue);
+ pfree(attr[1].pValue);
+ scx_release_context(sc);
+ return FALSE;
+ }
+ rsa.k = attr[0].ulValueLen;
+ n_to_mpz(&rsa.n, attr[0].pValue, attr[0].ulValueLen);
+ n_to_mpz(&rsa.e, attr[1].pValue, attr[1].ulValueLen);
+ pfree(attr[0].pValue);
+ pfree(attr[1].pValue);
+
+ cipher_text = RSA_encrypt(&rsa, plain_text);
+ free_RSA_public_content(&rsa);
+ if (cipher_text.ptr == NULL)
+ {
+ plog("smartcard input data length is too large");
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ memcpy(out, cipher_text.ptr, cipher_text.len);
+ *outlen = cipher_text.len;
+ freeanychunk(cipher_text);
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+ return TRUE;
+ }
+ else
+ {
+ plog("error in C_EncryptInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("doing RSA encryption on smartcard")
+ )
+ rv = pkcs11_functions->C_Encrypt(sc->session, in, inlen
+ , out, &len);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_Encrypt: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+
+ *outlen = (size_t)len;
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+/*
+ * decrypt a data block with an RSA private key
+ */
+bool
+scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen
+, u_char *out, size_t *outlen)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+ CK_OBJECT_HANDLE object;
+ CK_ULONG len = (CK_ULONG)(*outlen);
+ CK_BBOOL decrypt_flag;
+ CK_ATTRIBUTE attr[] = {
+ { CKA_DECRYPT, &decrypt_flag, sizeof(decrypt_flag) }
+ };
+ CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 };
+
+ if (!scx_establish_context(sc) || !scx_login(sc))
+ {
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id))
+ {
+ plog("unable to find private key with id '%s'", sc->id);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 1);
+ if (rv != CKR_OK)
+ {
+ plog("couldn't read the private key attributes: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ if (!decrypt_flag)
+ {
+ plog("private key cannot be used for decryption");
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("doing RSA decryption on smartcard")
+ )
+ rv = pkcs11_functions->C_DecryptInit(sc->session, &mech, object);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_DecryptInit: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+
+ rv = pkcs11_functions->C_Decrypt(sc->session, in, inlen
+ , out, &len);
+ if (rv != CKR_OK)
+ {
+ plog("error in C_Decrypt: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ scx_release_context(sc);
+ return FALSE;
+ }
+ if (!pkcs11_keep_state)
+ scx_release_context(sc);
+
+ *outlen = (size_t)len;
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+/* receive an encrypted data block via whack,
+ * decrypt it using a private RSA key and
+ * return the decrypted data block via whack
+ */
+bool
+scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op
+, const char* keyid, int whackfd)
+{
+ char inbuf[RSA_MAX_OCTETS];
+ char outbuf[2*RSA_MAX_OCTETS + 1];
+ size_t outlen = sizeof(inbuf);
+ size_t inlen;
+ smartcard_t *sc,*sc_new;
+
+ const char *number_slot_id = "";
+
+ err_t ugh = ttodata(msg, 0, inbase, inbuf, sizeof(inbuf), &inlen);
+
+ /* no prefix - use default base */
+ if (ugh != NULL && inbase == 0)
+ ugh = ttodata(msg, 0, DEFAULT_BASE, inbuf, sizeof(inbuf), &inlen);
+
+ if (ugh != NULL)
+ {
+ plog("format error in smartcard input data: %s", ugh);
+ return FALSE;
+ }
+
+ if (keyid != NULL)
+ {
+ number_slot_id = (strncmp(keyid, SCX_TOKEN, strlen(SCX_TOKEN)) == 0)
+ ? keyid + strlen(SCX_TOKEN) : keyid;
+ }
+
+ sc_new = scx_parse_number_slot_id(number_slot_id);
+ sc = scx_add(sc_new);
+ if (sc == sc_new)
+ scx_share(sc);
+
+ DBG((op == SC_OP_ENCRYPT)? DBG_PRIVATE:DBG_RAW,
+ DBG_dump("smartcard input data:\n", inbuf, inlen)
+ )
+
+ if (op == SC_OP_DECRYPT)
+ {
+ if (!sc->valid && whackfd != NULL_FD)
+ scx_get_pin(sc, whackfd);
+
+ if (!sc->valid)
+ {
+ loglog(RC_NOVALIDPIN, "cannot decrypt without valid PIN");
+ return FALSE;
+ }
+ }
+
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("using RSA key from smartcard (slot: %d, id: %s)"
+ , (int)sc->slot, sc->id)
+ )
+
+ switch (op)
+ {
+ case SC_OP_ENCRYPT:
+ if (!scx_encrypt(sc, inbuf, inlen, inbuf, &outlen))
+ return FALSE;
+ break;
+ case SC_OP_DECRYPT:
+ if (!scx_decrypt(sc, inbuf, inlen, inbuf, &outlen))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+
+ DBG((op == SC_OP_DECRYPT)? DBG_PRIVATE:DBG_RAW,
+ DBG_dump("smartcard output data:\n", inbuf, outlen)
+ )
+
+ if (outbase == 0) /* use default base */
+ outbase = DEFAULT_BASE;
+
+ if (outbase == 256) /* ascii plain text */
+ whack_log(RC_COMMENT, "%.*s", (int)outlen, inbuf);
+ else
+ {
+ outlen = datatot(inbuf, outlen, outbase, outbuf, sizeof(outbuf));
+ if (outlen == 0)
+ {
+ plog("error in output format conversion");
+ return FALSE;
+ }
+ whack_log(RC_COMMENT, "%s", outbuf);
+ }
+ return TRUE;
+}
+
+ /*
+ * get length of RSA key in bytes
+ */
+size_t
+scx_get_keylength(smartcard_t *sc)
+{
+#ifdef SMARTCARD
+ CK_RV rv;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE attr[] = {{ CKA_MODULUS, NULL_PTR, 0}};
+
+ if (!sc->logged_in)
+ return FALSE;
+
+ if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id))
+ {
+ plog("unable to find private key with id '%s'", sc->id);
+ return FALSE;
+ }
+
+ /* get the length of the private key */
+ rv = pkcs11_functions->C_GetAttributeValue(sc->session, object
+ , (CK_ATTRIBUTE_PTR)&attr, 1);
+ if (rv != CKR_OK)
+ {
+ plog("failed to get key length: %s"
+ , enum_show(&pkcs11_return_names, rv));
+ return FALSE;
+ }
+
+ return attr[0].ulValueLen; /*Return key length in bytes */
+#else
+ return 0;
+#endif
+}
+
+/*
+ * prompt for pin and verify it
+ */
+bool
+scx_get_pin(smartcard_t *sc, int whackfd)
+{
+#ifdef SMARTCARD
+ char pin[BUF_LEN];
+ int i, n;
+
+ whack_log(RC_ENTERSECRET, "need PIN for #%d (%s, id: %s, label: '%s')"
+ , sc->number, scx_print_slot(sc, ""), sc->id, sc->label);
+
+ for (i = 0; i < SCX_MAX_PIN_TRIALS; i++)
+ {
+ if (i > 0)
+ whack_log(RC_ENTERSECRET, "invalid PIN, please try again");
+
+ n = read(whackfd, pin, BUF_LEN);
+
+ if (n == -1)
+ {
+ whack_log(RC_LOG_SERIOUS, "read(whackfd) failed");
+ return FALSE;
+ }
+
+ if (strlen(pin) == 0)
+ {
+ whack_log(RC_LOG_SERIOUS, "no PIN entered, aborted");
+ return FALSE;
+ }
+
+ sc->pin.ptr = pin;
+ sc->pin.len = strlen(pin);
+
+ /* verify the pin */
+ if (scx_verify_pin(sc))
+ {
+ clonetochunk(sc->pin, pin, strlen(pin), "pin");
+ break;
+ }
+
+ /* wrong pin - we try another round */
+ sc->pin = empty_chunk;
+ }
+
+ if (sc->valid)
+ whack_log(RC_SUCCESS, "valid PIN");
+ else
+ whack_log(RC_LOG_SERIOUS, "invalid PIN, too many trials");
+#else
+ sc->valid = FALSE;
+ whack_log(RC_LOG_SERIOUS, "SMARTCARD support is deactivated in pluto/Makefile!");
+#endif
+ return sc->valid;
+}
+
+
+/*
+ * free the pin code
+ */
+void
+scx_free_pin(chunk_t *pin)
+{
+ if (pin->ptr != NULL)
+ {
+ /* clear pin field in memory */
+ memset(pin->ptr, '\0', pin->len);
+ pfree(pin->ptr);
+ *pin = empty_chunk;
+ }
+}
+
+/*
+ * frees a smartcard record
+ */
+void
+scx_free(smartcard_t *sc)
+{
+ if (sc != NULL)
+ {
+ scx_release_context(sc);
+ pfreeany(sc->id);
+ pfreeany(sc->label);
+ scx_free_pin(&sc->pin);
+ pfree(sc);
+ }
+}
+
+/* release of a smartcard record decreases the count by one
+ " the record is freed when the counter reaches zero
+ */
+void
+scx_release(smartcard_t *sc)
+{
+ if (sc != NULL && --sc->count == 0)
+ {
+ smartcard_t **pp = &smartcards;
+ while (*pp != sc)
+ pp = &(*pp)->next;
+ *pp = sc->next;
+ release_cert(sc->last_cert);
+ scx_free(sc);
+ }
+}
+
+/*
+ * compare two smartcard records by comparing their slots and ids
+ */
+static bool
+scx_same(smartcard_t *a, smartcard_t *b)
+{
+ if (a->number && b->number)
+ {
+ /* same number */
+ return a->number == b->number;
+ }
+ else
+ {
+ /* same id and/or same slot */
+ return (!a->id || (b->id && streq(a->id, b->id)))
+ && (a->any_slot || b->any_slot || a->slot == b->slot);
+ }
+}
+
+/* for each link pointing to the smartcard record
+ " increase the count by one
+ */
+void
+scx_share(smartcard_t *sc)
+{
+ if (sc != NULL)
+ sc->count++;
+}
+
+/*
+ * adds a smartcard record to the chained list
+ */
+smartcard_t*
+scx_add(smartcard_t *smartcard)
+{
+ smartcard_t *sc = smartcards;
+ smartcard_t **psc = &smartcards;
+
+ while (sc != NULL)
+ {
+ if (scx_same(smartcard, sc)) /* already in chain, free smartcard record */
+ {
+ scx_free(smartcard);
+ return sc;
+ }
+ psc = &sc->next;
+ sc = sc->next;
+ }
+
+ /* insert new smartcard record at the end of the chain */
+ *psc = smartcard;
+ smartcard->number = ++sc_number;
+ smartcard->count = 1;
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" smartcard #%d added", sc_number)
+ )
+ return smartcard;
+}
+
+/*
+ * get the smartcard that belongs to an X.509 certificate
+ */
+smartcard_t*
+scx_get(x509cert_t *cert)
+{
+ smartcard_t *sc = smartcards;
+
+ while (sc != NULL)
+ {
+ if (sc->last_cert.u.x509 == cert)
+ return sc;
+ sc = sc->next;
+ }
+ return NULL;
+}
+
+/*
+ * prints either the slot number or 'any slot'
+ */
+char *
+scx_print_slot(smartcard_t *sc, const char *whitespace)
+{
+ char *buf = temporary_cyclic_buffer();
+
+ if (sc->any_slot)
+ snprintf(buf, BUF_LEN, "any slot");
+ else
+ snprintf(buf, BUF_LEN, "slot: %s%lu", whitespace, sc->slot);
+ return buf;
+}
+
+/*
+ * list all smartcard info records in a chained list
+ */
+void
+scx_list(bool utc)
+{
+ smartcard_t *sc = smartcards;
+
+ if (sc != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of Smartcard Objects:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (sc != NULL)
+ {
+ whack_log(RC_COMMENT, "%s, #%d, count: %d"
+ , timetoa(&sc->last_load, utc)
+ , sc->number
+ , sc->count);
+ whack_log(RC_COMMENT, " %s, session %s, logged %s, has %s"
+ , scx_print_slot(sc, " ")
+ , sc->session_opened? "opened" : "closed"
+ , sc->logged_in? "in" : "out"
+ , sc->pinpad? "pin pad"
+ : ((sc->pin.ptr == NULL)? "no pin"
+ : sc->valid? "valid pin" : "invalid pin"));
+ if (sc->id != NULL)
+ whack_log(RC_COMMENT, " id: %s", sc->id);
+ if (sc->label != NULL)
+ whack_log(RC_COMMENT, " label: '%s'", sc->label);
+ if (sc->last_cert.type == CERT_X509_SIGNATURE)
+ {
+ char buf[BUF_LEN];
+
+ dntoa(buf, BUF_LEN, sc->last_cert.u.x509->subject);
+ whack_log(RC_COMMENT, " subject: '%s'", buf);
+ }
+ sc = sc->next;
+ }
+}
diff --git a/programs/pluto/smartcard.h b/programs/pluto/smartcard.h
new file mode 100644
index 000000000..c004ca7dd
--- /dev/null
+++ b/programs/pluto/smartcard.h
@@ -0,0 +1,100 @@
+/* Support of smartcards and cryptotokens
+ * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
+ * Copyright (C) 2004 David Buechi, Michael Meier
+ * Zuercher Hochschule Winterthur
+ *
+ * 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: smartcard.h,v 1.14 2005/11/06 22:55:41 as Exp $
+ */
+
+#ifndef _SMARTCARD_H
+#define _SMARTCARD_H
+
+#include "certs.h"
+
+#define SCX_TOKEN "%smartcard"
+#define SCX_CERT_CACHE_INTERVAL 60 /* seconds */
+#define SCX_MAX_PIN_TRIALS 3
+
+/* smartcard operations */
+
+typedef enum {
+ SC_OP_NONE = 0,
+ SC_OP_ENCRYPT = 1,
+ SC_OP_DECRYPT = 2,
+ SC_OP_SIGN = 3,
+} sc_op_t;
+
+/* smartcard record */
+
+typedef struct smartcard smartcard_t;
+
+struct smartcard {
+ smartcard_t *next;
+ time_t last_load;
+ cert_t last_cert;
+ int count;
+ int number;
+ unsigned long slot;
+ char *id;
+ char *label;
+ chunk_t pin;
+ bool pinpad;
+ bool valid;
+ bool session_opened;
+ bool logged_in;
+ bool any_slot;
+ long session;
+};
+
+extern const smartcard_t empty_sc;
+
+/* keep a PKCS#11 login during the lifetime of pluto
+ * flag set in plutomain.c and used in ipsec_doi.c and ocsp.c
+ */
+extern bool pkcs11_keep_state;
+
+/* allow other applications access to pluto's PKCS#11 interface
+ * via whack. Could be used e.g. for disk encryption
+ */
+extern bool pkcs11_proxy;
+
+extern smartcard_t* scx_parse_number_slot_id(const char *number_slot_id);
+extern void scx_init(const char *module);
+extern void scx_finalize(void);
+extern bool scx_establish_context(smartcard_t *sc);
+extern bool scx_login(smartcard_t *sc);
+extern bool scx_on_smartcard(const char *filename);
+extern bool scx_load_cert(const char *filename, smartcard_t **scp
+ , cert_t *cert, bool *cached);
+extern bool scx_verify_pin(smartcard_t *sc);
+extern void scx_share(smartcard_t *sc);
+extern bool scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen
+ , u_char *out, size_t outlen);
+extern bool scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen
+ , u_char *out, size_t *outlen);
+extern bool scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen
+ , u_char *out, size_t *outlen);
+extern bool scx_op_via_whack(const char* msg, int inbase, int outbase
+ , sc_op_t op, const char *keyid, int whackfd);
+extern bool scx_get_pin(smartcard_t *sc, int whackfd);
+extern size_t scx_get_keylength(smartcard_t *sc);
+extern smartcard_t* scx_add(smartcard_t *sc);
+extern smartcard_t* scx_get(x509cert_t *cert);
+extern void scx_release(smartcard_t *sc);
+extern void scx_release_context(smartcard_t *sc);
+extern void scx_free_pin(chunk_t *pin);
+extern void scx_free(smartcard_t *sc);
+extern void scx_list(bool utc);
+extern char *scx_print_slot(smartcard_t *sc, const char *whitespace);
+
+#endif /* _SMARTCARD_H */
diff --git a/programs/pluto/spdb.c b/programs/pluto/spdb.c
new file mode 100644
index 000000000..0544a1da2
--- /dev/null
+++ b/programs/pluto/spdb.c
@@ -0,0 +1,2402 @@
+/* Security Policy Data Base (such as it is)
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: spdb.c,v 1.9 2006/04/22 21:59:20 as Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "connections.h"
+#include "state.h"
+#include "packet.h"
+#include "keys.h"
+#include "kernel.h"
+#include "log.h"
+#include "spdb.h"
+#include "whack.h" /* for RC_LOG_SERIOUS */
+
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+
+#include "alg_info.h"
+#include "kernel_alg.h"
+#include "ike_alg.h"
+#include "db_ops.h"
+#define AD(x) x, elemsof(x) /* Array Description */
+#define AD_NULL NULL, 0
+
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
+/**************** Oakely (main mode) SA database ****************/
+
+/* arrays of attributes for transforms, preshared key */
+
+static struct db_attr otpsk1024des3md5[] = {
+ { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+ { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 },
+ { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY },
+ { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+ };
+
+static struct db_attr otpsk1536des3md5[] = {
+ { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+ { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 },
+ { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY },
+ { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 },
+ };
+
+static struct db_attr otpsk1024des3sha[] = {
+ { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+ { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+ { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY },
+ { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+ };
+
+static struct db_attr otpsk1536des3sha[] = {
+ { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+ { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+ { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY },
+ { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 },
+ };
+
+/* arrays of attributes for transforms, RSA signatures */
+
+static struct db_attr otrsasig1024des3md5[] = {
+ { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+ { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 },
+ { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG },
+ { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+ };
+
+static struct db_attr otrsasig1536des3md5[] = {
+ { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+ { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 },
+ { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG },
+ { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 },
+ };
+
+static struct db_attr otrsasig1024des3sha[] = {
+ { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+ { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+ { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG },
+ { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+ };
+
+static struct db_attr otrsasig1536des3sha[] = {
+ { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+ { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+ { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG },
+ { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 },
+ };
+
+/* We won't accept this, but by proposing it, we get to test
+ * our rejection. We better not propose it to an IKE daemon
+ * that will accept it!
+ */
+#ifdef TEST_INDECENT_PROPOSAL
+static struct db_attr otpsk1024des3tiger[] = {
+ { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+ { OAKLEY_HASH_ALGORITHM, OAKLEY_TIGER },
+ { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY },
+ { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+ };
+#endif /* TEST_INDECENT_PROPOSAL */
+
+/* tables of transforms, in preference order (select based on AUTH) */
+
+static struct db_trans oakley_trans_psk[] = {
+#ifdef TEST_INDECENT_PROPOSAL
+ { KEY_IKE, AD(otpsk1024des3tiger) },
+#endif
+ { KEY_IKE, AD(otpsk1536des3md5) },
+ { KEY_IKE, AD(otpsk1536des3sha) },
+ { KEY_IKE, AD(otpsk1024des3sha) },
+ { KEY_IKE, AD(otpsk1024des3md5) },
+ };
+
+static struct db_trans oakley_trans_rsasig[] = {
+ { KEY_IKE, AD(otrsasig1536des3md5) },
+ { KEY_IKE, AD(otrsasig1536des3sha) },
+ { KEY_IKE, AD(otrsasig1024des3sha) },
+ { KEY_IKE, AD(otrsasig1024des3md5) },
+ };
+
+/* In this table, either PSK or RSA sig is accepted.
+ * The order matters, but I don't know what would be best.
+ */
+static struct db_trans oakley_trans_pskrsasig[] = {
+#ifdef TEST_INDECENT_PROPOSAL
+ { KEY_IKE, AD(otpsk1024des3tiger) },
+#endif
+ { KEY_IKE, AD(otrsasig1536des3md5) },
+ { KEY_IKE, AD(otpsk1536des3md5) },
+ { KEY_IKE, AD(otrsasig1536des3sha) },
+ { KEY_IKE, AD(otpsk1536des3sha) },
+ { KEY_IKE, AD(otrsasig1024des3sha) },
+ { KEY_IKE, AD(otpsk1024des3sha) },
+ { KEY_IKE, AD(otrsasig1024des3md5) },
+ { KEY_IKE, AD(otpsk1024des3md5) },
+ };
+
+/* array of proposals to be conjoined (can only be one for Oakley) */
+
+static struct db_prop oakley_pc_psk[] =
+ { { PROTO_ISAKMP, AD(oakley_trans_psk) } };
+
+static struct db_prop oakley_pc_rsasig[] =
+ { { PROTO_ISAKMP, AD(oakley_trans_rsasig) } };
+
+static struct db_prop oakley_pc_pskrsasig[] =
+ { { PROTO_ISAKMP, AD(oakley_trans_pskrsasig) } };
+
+/* array of proposal conjuncts (can only be one) */
+
+static struct db_prop_conj oakley_props_psk[] = { { AD(oakley_pc_psk) } };
+
+static struct db_prop_conj oakley_props_rsasig[] = { { AD(oakley_pc_rsasig) } };
+
+static struct db_prop_conj oakley_props_pskrsasig[] = { { AD(oakley_pc_pskrsasig) } };
+
+/* the sadb entry, subscripted by POLICY_PSK and POLICY_RSASIG bits */
+struct db_sa oakley_sadb[] = {
+ { AD_NULL }, /* none */
+ { AD(oakley_props_psk) }, /* POLICY_PSK */
+ { AD(oakley_props_rsasig) }, /* POLICY_RSASIG */
+ { AD(oakley_props_pskrsasig) }, /* POLICY_PSK + POLICY_RSASIG */
+ };
+
+/**************** IPsec (quick mode) SA database ****************/
+
+/* arrays of attributes for transforms */
+
+static struct db_attr espmd5_attr[] = {
+ { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_MD5 },
+ };
+
+static struct db_attr espsha1_attr[] = {
+ { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 },
+ };
+
+static struct db_attr ah_HMAC_MD5_attr[] = {
+ { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_MD5 },
+ };
+
+static struct db_attr ah_HMAC_SHA1_attr[] = {
+ { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 },
+ };
+
+/* arrays of transforms, each in in preference order */
+
+static struct db_trans espa_trans[] = {
+ { ESP_3DES, AD(espmd5_attr) },
+ { ESP_3DES, AD(espsha1_attr) },
+ };
+
+static struct db_trans esp_trans[] = {
+ { ESP_3DES, AD_NULL },
+ };
+
+#ifdef SUPPORT_ESP_NULL
+static struct db_trans espnull_trans[] = {
+ { ESP_NULL, AD(espmd5_attr) },
+ { ESP_NULL, AD(espsha1_attr) },
+ };
+#endif /* SUPPORT_ESP_NULL */
+
+static struct db_trans ah_trans[] = {
+ { AH_MD5, AD(ah_HMAC_MD5_attr) },
+ { AH_SHA, AD(ah_HMAC_SHA1_attr) },
+ };
+
+static struct db_trans ipcomp_trans[] = {
+ { IPCOMP_DEFLATE, AD_NULL },
+ };
+
+/* arrays of proposals to be conjoined */
+
+static struct db_prop ah_pc[] = {
+ { PROTO_IPSEC_AH, AD(ah_trans) },
+ };
+
+#ifdef SUPPORT_ESP_NULL
+static struct db_prop espnull_pc[] = {
+ { PROTO_IPSEC_ESP, AD(espnull_trans) },
+ };
+#endif /* SUPPORT_ESP_NULL */
+
+static struct db_prop esp_pc[] = {
+ { PROTO_IPSEC_ESP, AD(espa_trans) },
+ };
+
+static struct db_prop ah_esp_pc[] = {
+ { PROTO_IPSEC_AH, AD(ah_trans) },
+ { PROTO_IPSEC_ESP, AD(esp_trans) },
+ };
+
+static struct db_prop compress_pc[] = {
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+
+static struct db_prop ah_compress_pc[] = {
+ { PROTO_IPSEC_AH, AD(ah_trans) },
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+
+#ifdef SUPPORT_ESP_NULL
+static struct db_prop espnull_compress_pc[] = {
+ { PROTO_IPSEC_ESP, AD(espnull_trans) },
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+#endif /* SUPPORT_ESP_NULL */
+
+static struct db_prop esp_compress_pc[] = {
+ { PROTO_IPSEC_ESP, AD(espa_trans) },
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+
+static struct db_prop ah_esp_compress_pc[] = {
+ { PROTO_IPSEC_AH, AD(ah_trans) },
+ { PROTO_IPSEC_ESP, AD(esp_trans) },
+ { PROTO_IPCOMP, AD(ipcomp_trans) },
+ };
+
+/* arrays of proposal alternatives (each element is a conjunction) */
+
+static struct db_prop_conj ah_props[] = {
+ { AD(ah_pc) },
+#ifdef SUPPORT_ESP_NULL
+ { AD(espnull_pc) }
+#endif
+ };
+
+static struct db_prop_conj esp_props[] =
+ { { AD(esp_pc) } };
+
+static struct db_prop_conj ah_esp_props[] =
+ { { AD(ah_esp_pc) } };
+
+static struct db_prop_conj compress_props[] = {
+ { AD(compress_pc) },
+ };
+
+static struct db_prop_conj ah_compress_props[] = {
+ { AD(ah_compress_pc) },
+#ifdef SUPPORT_ESP_NULL
+ { AD(espnull_compress_pc) }
+#endif
+ };
+
+static struct db_prop_conj esp_compress_props[] =
+ { { AD(esp_compress_pc) } };
+
+static struct db_prop_conj ah_esp_compress_props[] =
+ { { AD(ah_esp_compress_pc) } };
+
+/* The IPsec sadb is subscripted by a bitset (subset of policy)
+ * with members from { POLICY_ENCRYPT, POLICY_AUTHENTICATE, POLICY_COMPRESS }
+ * shifted right by POLICY_IPSEC_SHIFT.
+ */
+struct db_sa ipsec_sadb[1 << 3] = {
+ { AD_NULL }, /* none */
+ { AD(esp_props) }, /* POLICY_ENCRYPT */
+ { AD(ah_props) }, /* POLICY_AUTHENTICATE */
+ { AD(ah_esp_props) }, /* POLICY_ENCRYPT+POLICY_AUTHENTICATE */
+ { AD(compress_props) }, /* POLICY_COMPRESS */
+ { AD(esp_compress_props) }, /* POLICY_ENCRYPT+POLICY_COMPRESS */
+ { AD(ah_compress_props) }, /* POLICY_AUTHENTICATE+POLICY_COMPRESS */
+ { AD(ah_esp_compress_props) }, /* POLICY_ENCRYPT+POLICY_AUTHENTICATE+POLICY_COMPRESS */
+ };
+
+#undef AD
+#undef AD_NULL
+
+/* output an attribute (within an SA) */
+static bool
+out_attr(int type
+, unsigned long val
+, struct_desc *attr_desc
+, enum_names **attr_val_descs USED_BY_DEBUG
+, pb_stream *pbs)
+{
+ struct isakmp_attribute attr;
+
+ if (val >> 16 == 0)
+ {
+ /* short value: use TV form */
+ attr.isaat_af_type = type | ISAKMP_ATTR_AF_TV;
+ attr.isaat_lv = val;
+ if (!out_struct(&attr, attr_desc, pbs, NULL))
+ return FALSE;
+ }
+ else
+ {
+ /* This is a real fudge! Since we rarely use long attributes
+ * and since this is the only place where we can cause an
+ * ISAKMP message length to be other than a multiple of 4 octets,
+ * we force the length of the value to be a multiple of 4 octets.
+ * Furthermore, we only handle values up to 4 octets in length.
+ * Voila: a fixed format!
+ */
+ pb_stream val_pbs;
+ u_int32_t nval = htonl(val);
+
+ attr.isaat_af_type = type | ISAKMP_ATTR_AF_TLV;
+ if (!out_struct(&attr, attr_desc, pbs, &val_pbs)
+ || !out_raw(&nval, sizeof(nval), &val_pbs, "long attribute value"))
+ return FALSE;
+ close_output_pbs(&val_pbs);
+ }
+ DBG(DBG_EMITTING,
+ enum_names *d = attr_val_descs[type];
+
+ if (d != NULL)
+ DBG_log(" [%lu is %s]"
+ , val, enum_show(d, val)));
+ return TRUE;
+}
+#define return_on(var, val) do { var=val;goto return_out; } while(0);
+/* Output an SA, as described by a db_sa.
+ * This has the side-effect of allocating SPIs for us.
+ */
+bool
+out_sa(pb_stream *outs
+, struct db_sa *sadb
+, struct state *st
+, bool oakley_mode
+, u_int8_t np)
+{
+ pb_stream sa_pbs;
+ int pcn;
+ bool ret = FALSE;
+ bool ah_spi_generated = FALSE
+ , esp_spi_generated = FALSE
+ , ipcomp_cpi_generated = FALSE;
+#if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG
+ struct db_context *db_ctx = NULL;
+#endif
+
+ /* SA header out */
+ {
+ struct isakmp_sa sa;
+
+ sa.isasa_np = np;
+ st->st_doi = sa.isasa_doi = ISAKMP_DOI_IPSEC; /* all we know */
+ if (!out_struct(&sa, &isakmp_sa_desc, outs, &sa_pbs))
+ return_on(ret, FALSE);
+ }
+
+ /* within SA: situation out */
+ st->st_situation = SIT_IDENTITY_ONLY;
+ if (!out_struct(&st->st_situation, &ipsec_sit_desc, &sa_pbs, NULL))
+ return_on(ret, FALSE);
+
+ /* within SA: Proposal Payloads
+ *
+ * Multiple Proposals with the same number are simultaneous
+ * (conjuncts) and must deal with different protocols (AH or ESP).
+ * Proposals with different numbers are alternatives (disjuncts),
+ * in preference order.
+ * Proposal numbers must be monotonic.
+ * See RFC 2408 "ISAKMP" 4.2
+ */
+
+ for (pcn = 0; pcn != sadb->prop_conj_cnt; pcn++)
+ {
+ struct db_prop_conj *pc = &sadb->prop_conjs[pcn];
+ int pn;
+
+ for (pn = 0; pn != pc->prop_cnt; pn++)
+ {
+ struct db_prop *p = &pc->props[pn];
+ pb_stream proposal_pbs;
+ struct isakmp_proposal proposal;
+ struct_desc *trans_desc;
+ struct_desc *attr_desc;
+ enum_names **attr_val_descs;
+ int tn;
+ bool tunnel_mode;
+
+ tunnel_mode = (pn == pc->prop_cnt-1)
+ && (st->st_policy & POLICY_TUNNEL);
+
+ /* Proposal header */
+ proposal.isap_np = pcn == sadb->prop_conj_cnt-1 && pn == pc->prop_cnt-1
+ ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_P;
+ proposal.isap_proposal = pcn;
+ proposal.isap_protoid = p->protoid;
+ proposal.isap_spisize = oakley_mode ? 0
+ : p->protoid == PROTO_IPCOMP ? IPCOMP_CPI_SIZE
+ : IPSEC_DOI_SPI_SIZE;
+
+ /* In quick mode ONLY, create proposal for runtime kernel algos.
+ * Replace ESP proposals with runtime created one
+ */
+ if (!oakley_mode && p->protoid == PROTO_IPSEC_ESP)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ if (st->st_connection->alg_info_esp)
+ {
+ static char buf[256]="";
+
+ alg_info_snprint(buf, sizeof (buf),
+ (struct alg_info *)st->st_connection->alg_info_esp);
+ DBG_log(buf);
+ }
+ )
+ db_ctx = kernel_alg_db_new(st->st_connection->alg_info_esp, st->st_policy);
+ p = db_prop_get(db_ctx);
+
+ if (!p || p->trans_cnt == 0)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "empty IPSEC SA proposal to send "
+ "(no kernel algorithms for esp selection)");
+ return_on(ret, FALSE);
+ }
+ }
+
+ if (oakley_mode && p->protoid == PROTO_ISAKMP)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ if (st->st_connection->alg_info_ike)
+ {
+ static char buf[256]="";
+
+ alg_info_snprint(buf, sizeof (buf),
+ (struct alg_info *)st->st_connection->alg_info_ike);
+ DBG_log(buf);
+ }
+ )
+ db_ctx = ike_alg_db_new(st->st_connection->alg_info_ike, st->st_policy);
+ p = db_prop_get(db_ctx);
+
+ if (!p || p->trans_cnt == 0)
+ {
+ loglog(RC_LOG_SERIOUS,
+ "empty ISAKMP SA proposal to send "
+ "(no algorithms for ike selection?)");
+ return_on(ret, FALSE);
+ }
+ }
+
+ proposal.isap_notrans = p->trans_cnt;
+ if (!out_struct(&proposal, &isakmp_proposal_desc, &sa_pbs, &proposal_pbs))
+ return_on(ret, FALSE);
+
+ /* Per-protocols stuff:
+ * Set trans_desc.
+ * Set attr_desc.
+ * Set attr_val_descs.
+ * If not oakley_mode, emit SPI.
+ * We allocate SPIs on demand.
+ * All ESPs in an SA will share a single SPI.
+ * All AHs in an SAwill share a single SPI.
+ * AHs' SPI will be distinct from ESPs'.
+ * This latter is needed because KLIPS doesn't
+ * use the protocol when looking up a (dest, protocol, spi).
+ * ??? If multiple ESPs are composed, how should their SPIs
+ * be allocated?
+ */
+ {
+ ipsec_spi_t *spi_ptr = NULL;
+ int proto = 0;
+ bool *spi_generated = NULL;
+
+ switch (p->protoid)
+ {
+ case PROTO_ISAKMP:
+ passert(oakley_mode);
+ trans_desc = &isakmp_isakmp_transform_desc;
+ attr_desc = &isakmp_oakley_attribute_desc;
+ attr_val_descs = oakley_attr_val_descs;
+ /* no SPI needed */
+ break;
+ case PROTO_IPSEC_AH:
+ passert(!oakley_mode);
+ trans_desc = &isakmp_ah_transform_desc;
+ attr_desc = &isakmp_ipsec_attribute_desc;
+ attr_val_descs = ipsec_attr_val_descs;
+ spi_ptr = &st->st_ah.our_spi;
+ spi_generated = &ah_spi_generated;
+ proto = IPPROTO_AH;
+ break;
+ case PROTO_IPSEC_ESP:
+ passert(!oakley_mode);
+ trans_desc = &isakmp_esp_transform_desc;
+ attr_desc = &isakmp_ipsec_attribute_desc;
+ attr_val_descs = ipsec_attr_val_descs;
+ spi_ptr = &st->st_esp.our_spi;
+ spi_generated = &esp_spi_generated;
+ proto = IPPROTO_ESP;
+ break;
+ case PROTO_IPCOMP:
+ passert(!oakley_mode);
+ trans_desc = &isakmp_ipcomp_transform_desc;
+ attr_desc = &isakmp_ipsec_attribute_desc;
+ attr_val_descs = ipsec_attr_val_descs;
+
+ /* a CPI isn't quite the same as an SPI
+ * so we use specialized code to emit it.
+ */
+ if (!ipcomp_cpi_generated)
+ {
+ st->st_ipcomp.our_spi = get_my_cpi(
+ &st->st_connection->spd, tunnel_mode);
+ if (st->st_ipcomp.our_spi == 0)
+ return_on(ret, FALSE); /* problem generating CPI */
+
+ ipcomp_cpi_generated = TRUE;
+ }
+ /* CPI is stored in network low order end of an
+ * ipsec_spi_t. So we start a couple of bytes in.
+ */
+ if (!out_raw((u_char *)&st->st_ipcomp.our_spi
+ + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE
+ , IPCOMP_CPI_SIZE
+ , &proposal_pbs, "CPI"))
+ return_on(ret, FALSE);
+ break;
+ default:
+ bad_case(p->protoid);
+ }
+ if (spi_ptr != NULL)
+ {
+ if (!*spi_generated)
+ {
+ *spi_ptr = get_ipsec_spi(0
+ , proto
+ , &st->st_connection->spd
+ , tunnel_mode);
+ if (*spi_ptr == 0)
+ return FALSE;
+ *spi_generated = TRUE;
+ }
+ if (!out_raw((u_char *)spi_ptr, IPSEC_DOI_SPI_SIZE
+ , &proposal_pbs, "SPI"))
+ return_on(ret, FALSE);
+ }
+ }
+
+ /* within proposal: Transform Payloads */
+ for (tn = 0; tn != p->trans_cnt; tn++)
+ {
+ struct db_trans *t = &p->trans[tn];
+ pb_stream trans_pbs;
+ struct isakmp_transform trans;
+ int an;
+
+ trans.isat_np = (tn == p->trans_cnt - 1)
+ ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_T;
+ trans.isat_transnum = tn;
+ trans.isat_transid = t->transid;
+ if (!out_struct(&trans, trans_desc, &proposal_pbs, &trans_pbs))
+ return_on(ret, FALSE);
+
+ /* Within tranform: Attributes. */
+
+ /* For Phase 2 / Quick Mode, GROUP_DESCRIPTION is
+ * automatically generated because it must be the same
+ * in every transform. Except IPCOMP.
+ */
+ if (p->protoid != PROTO_IPCOMP
+ && st->st_pfs_group != NULL)
+ {
+ passert(!oakley_mode);
+ passert(st->st_pfs_group != &unset_group);
+ out_attr(GROUP_DESCRIPTION, st->st_pfs_group->group
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+
+ /* automatically generate duration
+ * and, for Phase 2 / Quick Mode, encapsulation.
+ */
+ if (oakley_mode)
+ {
+ out_attr(OAKLEY_LIFE_TYPE, OAKLEY_LIFE_SECONDS
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ out_attr(OAKLEY_LIFE_DURATION
+ , st->st_connection->sa_ike_life_seconds
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+ else
+ {
+ /* RFC 2407 (IPSEC DOI) 4.5 specifies that
+ * the default is "unspecified (host-dependent)".
+ * This makes little sense, so we always specify it.
+ *
+ * Unlike other IPSEC transforms, IPCOMP defaults
+ * to Transport Mode, so we can exploit the default
+ * (draft-shacham-ippcp-rfc2393bis-05.txt 4.1).
+ */
+ if (p->protoid != PROTO_IPCOMP
+ || st->st_policy & POLICY_TUNNEL)
+ {
+#ifdef NAT_TRAVERSAL
+#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+ if ((st->nat_traversal & NAT_T_DETECTED)
+ && !(st->st_policy & POLICY_TUNNEL))
+ {
+ /* Inform user that we will not respect policy and only
+ * propose Tunnel Mode
+ */
+ loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+ "Transport Mode not allowed due to security concerns -- "
+ "using Tunnel mode");
+ }
+#endif
+#endif
+ out_attr(ENCAPSULATION_MODE
+#ifdef NAT_TRAVERSAL
+#ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+ , NAT_T_ENCAPSULATION_MODE(st,st->st_policy)
+#else
+ /* If NAT-T is detected, use UDP_TUNNEL as long as Transport
+ * Mode has security concerns.
+ *
+ * User has been informed of that
+ */
+ , NAT_T_ENCAPSULATION_MODE(st,POLICY_TUNNEL)
+#endif
+#else /* ! NAT_TRAVERSAL */
+ , st->st_policy & POLICY_TUNNEL
+ ? ENCAPSULATION_MODE_TUNNEL : ENCAPSULATION_MODE_TRANSPORT
+#endif
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+ out_attr(SA_LIFE_TYPE, SA_LIFE_TYPE_SECONDS
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ out_attr(SA_LIFE_DURATION
+ , st->st_connection->sa_ipsec_life_seconds
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+
+ /* spit out attributes from table */
+ for (an = 0; an != t->attr_cnt; an++)
+ {
+ struct db_attr *a = &t->attrs[an];
+
+ out_attr(a->type, a->val
+ , attr_desc, attr_val_descs
+ , &trans_pbs);
+ }
+
+ close_output_pbs(&trans_pbs);
+ }
+ close_output_pbs(&proposal_pbs);
+ }
+ /* end of a conjunction of proposals */
+ }
+ close_output_pbs(&sa_pbs);
+ ret = TRUE;
+
+return_out:
+
+#if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG
+ if (db_ctx)
+ db_destroy(db_ctx);
+#endif
+ return ret;
+}
+
+/* Handle long form of duration attribute.
+ * The code is can only handle values that can fit in unsigned long.
+ * "Clamping" is probably an acceptable way to impose this limitation.
+ */
+static u_int32_t
+decode_long_duration(pb_stream *pbs)
+{
+ u_int32_t val = 0;
+
+ /* ignore leading zeros */
+ while (pbs_left(pbs) != 0 && *pbs->cur == '\0')
+ pbs->cur++;
+
+ if (pbs_left(pbs) > sizeof(val))
+ {
+ /* "clamp" too large value to max representable value */
+ val -= 1; /* portable way to get to maximum value */
+ DBG(DBG_PARSING, DBG_log(" too large duration clamped to: %lu"
+ , (unsigned long)val));
+ }
+ else
+ {
+ /* decode number */
+ while (pbs_left(pbs) != 0)
+ val = (val << BITS_PER_BYTE) | *pbs->cur++;
+ DBG(DBG_PARSING, DBG_log(" long duration: %lu", (unsigned long)val));
+ }
+ return val;
+}
+
+/* Preparse the body of an ISAKMP SA Payload and
+ * return body of ISAKMP Proposal Payload
+ *
+ * Only IPsec DOI is accepted (what is the ISAKMP DOI?).
+ * Error response is rudimentary.
+ */
+notification_t
+preparse_isakmp_sa_body(const struct isakmp_sa *sa
+ , pb_stream *sa_pbs
+ , u_int32_t *ipsecdoisit
+ , pb_stream *proposal_pbs
+ , struct isakmp_proposal *proposal)
+{
+ /* DOI */
+ if (sa->isasa_doi != ISAKMP_DOI_IPSEC)
+ {
+ loglog(RC_LOG_SERIOUS, "Unknown/unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi));
+ /* XXX Could send notification back */
+ return DOI_NOT_SUPPORTED;
+ }
+
+ /* Situation */
+ if (!in_struct(ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL))
+ return SITUATION_NOT_SUPPORTED;
+
+ if (*ipsecdoisit != SIT_IDENTITY_ONLY)
+ {
+ loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)"
+ , bitnamesof(sit_bit_names, *ipsecdoisit));
+ /* XXX Could send notification back */
+ return SITUATION_NOT_SUPPORTED;
+ }
+
+ /* The rules for ISAKMP SAs are scattered.
+ * RFC 2409 "IKE" section 5 says that there
+ * can only be one SA, and it can have only one proposal in it.
+ * There may well be multiple transforms.
+ */
+ if (!in_struct(proposal, &isakmp_proposal_desc, sa_pbs, proposal_pbs))
+ return PAYLOAD_MALFORMED;
+
+ if (proposal->isap_np != ISAKMP_NEXT_NONE)
+ {
+ loglog(RC_LOG_SERIOUS, "Proposal Payload must be alone in Oakley SA; found %s following Proposal"
+ , enum_show(&payload_names, proposal->isap_np));
+ return PAYLOAD_MALFORMED;
+ }
+
+ if (proposal->isap_protoid != PROTO_ISAKMP)
+ {
+ loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) found in Oakley Proposal"
+ , enum_show(&protocol_names, proposal->isap_protoid));
+ return INVALID_PROTOCOL_ID;
+ }
+
+ /* Just what should we accept for the SPI field?
+ * The RFC is sort of contradictory. We will ignore the SPI
+ * as long as it is of the proper size.
+ *
+ * From RFC2408 2.4 Identifying Security Associations:
+ * During phase 1 negotiations, the initiator and responder cookies
+ * determine the ISAKMP SA. Therefore, the SPI field in the Proposal
+ * payload is redundant and MAY be set to 0 or it MAY contain the
+ * transmitting entity's cookie.
+ *
+ * From RFC2408 3.5 Proposal Payload:
+ * o SPI Size (1 octet) - Length in octets of the SPI as defined by
+ * the Protocol-Id. In the case of ISAKMP, the Initiator and
+ * Responder cookie pair from the ISAKMP Header is the ISAKMP SPI,
+ * therefore, the SPI Size is irrelevant and MAY be from zero (0) to
+ * sixteen (16). If the SPI Size is non-zero, the content of the
+ * SPI field MUST be ignored. If the SPI Size is not a multiple of
+ * 4 octets it will have some impact on the SPI field and the
+ * alignment of all payloads in the message. The Domain of
+ * Interpretation (DOI) will dictate the SPI Size for other
+ * protocols.
+ */
+ if (proposal->isap_spisize == 0)
+ {
+ /* empty (0) SPI -- fine */
+ }
+ else if (proposal->isap_spisize <= MAX_ISAKMP_SPI_SIZE)
+ {
+ u_char junk_spi[MAX_ISAKMP_SPI_SIZE];
+
+ if (!in_raw(junk_spi, proposal->isap_spisize, proposal_pbs, "Oakley SPI"))
+ return PAYLOAD_MALFORMED;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS, "invalid SPI size (%u) in Oakley Proposal"
+ , (unsigned)proposal->isap_spisize);
+ return INVALID_SPI;
+ }
+ return NOTHING_WRONG;
+}
+
+static struct {
+ u_int8_t *start;
+ u_int8_t *cur;
+ u_int8_t *roof;
+} backup;
+
+/*
+ * backup the pointer into a pb_stream
+ */
+void
+backup_pbs(pb_stream *pbs)
+{
+ backup.start = pbs->start;
+ backup.cur = pbs->cur;
+ backup.roof = pbs->roof;
+}
+
+/*
+ * restore the pointer into a pb_stream
+ */
+void
+restore_pbs(pb_stream *pbs)
+{
+ pbs->start = backup.start;
+ pbs->cur = backup.cur;
+ pbs->roof = backup.roof;
+}
+
+/*
+ * Parse an ISAKMP Proposal Payload for RSA and PSK authentication policies
+ */
+notification_t
+parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, lset_t *policy)
+{
+ int last_transnum = -1;
+
+ *policy = LEMPTY;
+
+ while (notrans--)
+ {
+ pb_stream trans_pbs;
+ u_char *attr_start;
+ size_t attr_len;
+ struct isakmp_transform trans;
+
+ if (!in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+
+ if (trans.isat_transnum <= last_transnum)
+ {
+ /* picky, picky, picky */
+ loglog(RC_LOG_SERIOUS, "Transform Numbers are not monotonically increasing"
+ " in Oakley Proposal");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ last_transnum = trans.isat_transnum;
+
+ if (trans.isat_transid != KEY_IKE)
+ {
+ loglog(RC_LOG_SERIOUS, "expected KEY_IKE but found %s in Oakley Transform"
+ , enum_show(&isakmp_transformid_names, trans.isat_transid));
+ return INVALID_TRANSFORM_ID;
+ }
+
+ attr_start = trans_pbs.cur;
+ attr_len = pbs_left(&trans_pbs);
+
+ /* preprocess authentication attributes only */
+ while (pbs_left(&trans_pbs) != 0)
+ {
+ struct isakmp_attribute a;
+ pb_stream attr_pbs;
+
+ if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+
+ passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32);
+
+ switch (a.isaat_af_type)
+ {
+ case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV:
+ switch (a.isaat_lv)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ *policy |= POLICY_PSK;
+ break;
+ case OAKLEY_RSA_SIG:
+ *policy |= POLICY_RSASIG;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if ((*policy & POLICY_PSK) && (*policy & POLICY_RSASIG))
+ {
+ DBG(DBG_CONTROL|DBG_PARSING,
+ DBG_log("preparse_isakmp_policy: "
+ "peer supports both PSK and RSASIG authentication")
+ )
+ *policy = LEMPTY;
+ }
+ else
+ {
+ DBG(DBG_CONTROL|DBG_PARSING,
+ DBG_log("preparse_isakmp_policy: peer requests %s authentication"
+ , (*policy & POLICY_PSK) ? "PSK":"RSASIG")
+ )
+ }
+ return NOTHING_WRONG;
+}
+
+/* Parse the body of an ISAKMP SA Payload (i.e. Phase 1 / Main Mode).
+ * Various shortcuts are taken. In particular, the policy, such as
+ * it is, is hardwired.
+ *
+ * If r_sa is non-NULL, the body of an SA representing the selected
+ * proposal is emitted.
+ *
+ * This routine is used by main_inI1_outR1() and main_inR1_outI2().
+ */
+notification_t
+parse_isakmp_sa_body(u_int32_t ipsecdoisit
+ , pb_stream *proposal_pbs
+ , struct isakmp_proposal *proposal
+ , pb_stream *r_sa_pbs
+ , struct state *st)
+{
+ struct connection *c = st->st_connection;
+ unsigned no_trans_left;
+
+ /* for each transform payload... */
+ no_trans_left = proposal->isap_notrans;
+
+ for (;;)
+ {
+ pb_stream trans_pbs;
+ u_char *attr_start;
+ size_t attr_len;
+ struct isakmp_transform trans;
+ lset_t seen_attrs = 0;
+ lset_t seen_durations = 0;
+ u_int16_t life_type = 0;
+ struct oakley_trans_attrs ta;
+ err_t ugh = NULL; /* set to diagnostic when problem detected */
+
+ /* initialize only optional field in ta */
+ ta.life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; /* When this SA expires (seconds) */
+
+ if (no_trans_left == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs);
+ attr_start = trans_pbs.cur;
+ attr_len = pbs_left(&trans_pbs);
+
+ /* process all the attributes that make up the transform */
+
+ while (pbs_left(&trans_pbs) != 0)
+ {
+ struct isakmp_attribute a;
+ pb_stream attr_pbs;
+ u_int32_t val; /* room for larger values */
+
+ if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+
+ passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32);
+
+ if (LHAS(seen_attrs, a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK))
+ {
+ loglog(RC_LOG_SERIOUS, "repeated %s attribute in Oakley Transform %u"
+ , enum_show(&oakley_attr_names, a.isaat_af_type)
+ , trans.isat_transnum);
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK);
+
+ val = a.isaat_lv;
+
+ DBG(DBG_PARSING,
+ {
+ enum_names *vdesc = oakley_attr_val_descs
+ [a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK];
+
+ if (vdesc != NULL)
+ {
+ const char *nm = enum_name(vdesc, val);
+
+ if (nm != NULL)
+ DBG_log(" [%u is %s]", (unsigned)val, nm);
+ }
+ });
+
+ switch (a.isaat_af_type)
+ {
+ case OAKLEY_ENCRYPTION_ALGORITHM | ISAKMP_ATTR_AF_TV:
+ if (ike_alg_enc_present(val))
+ {
+ ta.encrypt = val;
+ ta.encrypter = ike_alg_get_encrypter(val);
+ ta.enckeylen = ta.encrypter->keydeflen;
+ }
+ else
+ {
+ ugh = builddiag("%s is not supported"
+ , enum_show(&oakley_enc_names, val));
+ }
+ break;
+
+ case OAKLEY_HASH_ALGORITHM | ISAKMP_ATTR_AF_TV:
+ if (ike_alg_hash_present(val))
+ {
+ ta.hash = val;
+ ta.hasher = ike_alg_get_hasher(val);
+ }
+ else
+ {
+ ugh = builddiag("%s is not supported"
+ , enum_show(&oakley_hash_names, val));
+ }
+ break;
+
+ case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV:
+ {
+ /* check that authentication method is acceptable */
+ lset_t iap = st->st_policy & POLICY_ID_AUTH_MASK;
+
+ switch (val)
+ {
+ case OAKLEY_PRESHARED_KEY:
+ if ((iap & POLICY_PSK) == LEMPTY)
+ {
+ ugh = "policy does not allow OAKLEY_PRESHARED_KEY authentication";
+ }
+ else
+ {
+ /* check that we can find a preshared secret */
+ struct connection *c = st->st_connection;
+
+ if (get_preshared_secret(c) == NULL)
+ {
+ char mid[BUF_LEN]
+ , hid[BUF_LEN];
+
+ idtoa(&c->spd.this.id, mid, sizeof(mid));
+ if (his_id_was_instantiated(c))
+ strcpy(hid, "%any");
+ else
+ idtoa(&c->spd.that.id, hid, sizeof(hid));
+ ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'"
+ , mid, hid);
+ }
+ ta.auth = val;
+ }
+ break;
+ case OAKLEY_RSA_SIG:
+ /* Accept if policy specifies RSASIG or is default */
+ if ((iap & POLICY_RSASIG) == LEMPTY)
+ {
+ ugh = "policy does not allow OAKLEY_RSA_SIG authentication";
+ }
+ else
+ {
+ /* We'd like to check that we can find a public
+ * key for him and a private key for us that is
+ * suitable, but we don't yet have his
+ * Id Payload, so it seems futile to try.
+ * We can assume that if he proposes it, he
+ * thinks we've got it. If we proposed it,
+ * perhaps we know what we're doing.
+ */
+ ta.auth = val;
+ }
+ break;
+
+ default:
+ ugh = builddiag("Pluto does not support %s authentication"
+ , enum_show(&oakley_auth_names, val));
+ break;
+ }
+ }
+ break;
+
+ case OAKLEY_GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV:
+ ta.group = lookup_group(val);
+ if (ta.group == NULL)
+ {
+ ugh = "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported";
+ }
+ break;
+
+ case OAKLEY_LIFE_TYPE | ISAKMP_ATTR_AF_TV:
+ switch (val)
+ {
+ case OAKLEY_LIFE_SECONDS:
+ case OAKLEY_LIFE_KILOBYTES:
+ if (LHAS(seen_durations, val))
+ {
+ loglog(RC_LOG_SERIOUS
+ , "attribute OAKLEY_LIFE_TYPE value %s repeated"
+ , enum_show(&oakley_lifetime_names, val));
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ seen_durations |= LELEM(val);
+ life_type = val;
+ break;
+ default:
+ ugh = builddiag("unknown value %s"
+ , enum_show(&oakley_lifetime_names, val));
+ break;
+ }
+ break;
+
+ case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TLV:
+ val = decode_long_duration(&attr_pbs);
+ /* fall through */
+ case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TV:
+ if (!LHAS(seen_attrs, OAKLEY_LIFE_TYPE))
+ {
+ ugh = "OAKLEY_LIFE_DURATION attribute not preceded by OAKLEY_LIFE_TYPE attribute";
+ break;
+ }
+ seen_attrs &= ~(LELEM(OAKLEY_LIFE_DURATION) | LELEM(OAKLEY_LIFE_TYPE));
+
+ switch (life_type)
+ {
+ case OAKLEY_LIFE_SECONDS:
+ if (val > OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM)
+ ugh = builddiag("peer requested %lu seconds"
+ " which exceeds our limit %d seconds"
+ , (long) val
+ , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM);
+ ta.life_seconds = val;
+ break;
+ case OAKLEY_LIFE_KILOBYTES:
+ ta.life_kilobytes = val;
+ break;
+ default:
+ bad_case(life_type);
+ }
+ break;
+
+ case OAKLEY_KEY_LENGTH | ISAKMP_ATTR_AF_TV:
+ if ((seen_attrs & LELEM(OAKLEY_ENCRYPTION_ALGORITHM)) == 0)
+ {
+ ugh = "OAKLEY_KEY_LENGTH attribute not preceded by "
+ "OAKLEY_ENCRYPTION_ALGORITHM attribute";
+ break;
+ }
+ if (ta.encrypter == NULL)
+ {
+ ugh = "NULL encrypter with seen OAKLEY_ENCRYPTION_ALGORITHM";
+ break;
+ }
+ /*
+ * check if this keylen is compatible with specified algorithm
+ */
+ if (val
+ && (val < ta.encrypter->keyminlen || val > ta.encrypter->keymaxlen))
+ {
+ ugh = "peer proposed key length not valid for "
+ "encryption algorithm specified";
+ }
+ ta.enckeylen = val;
+ break;
+#if 0 /* not yet supported */
+ case OAKLEY_GROUP_TYPE | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_PRF | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_FIELD_SIZE | ISAKMP_ATTR_AF_TV:
+
+ case OAKLEY_GROUP_PRIME | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_PRIME | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_GENERATOR_ONE | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_GENERATOR_ONE | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_GENERATOR_TWO | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_GENERATOR_TWO | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_CURVE_A | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_CURVE_A | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_CURVE_B | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_CURVE_B | ISAKMP_ATTR_AF_TLV:
+ case OAKLEY_GROUP_ORDER | ISAKMP_ATTR_AF_TV:
+ case OAKLEY_GROUP_ORDER | ISAKMP_ATTR_AF_TLV:
+#endif
+ default:
+ ugh = "unsupported OAKLEY attribute";
+ break;
+ }
+
+ if (ugh != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s. Attribute %s"
+ , ugh, enum_show(&oakley_attr_names, a.isaat_af_type));
+ break;
+ }
+ }
+
+ /*
+ * ML: at last check for allowed transforms in alg_info_ike
+ * (ALG_INFO_F_STRICT flag)
+ */
+ if (ugh == NULL)
+ {
+ if (!ike_alg_ok_final(ta.encrypt, ta.enckeylen, ta.hash,
+ ta.group ? ta.group->group : -1, c->alg_info_ike))
+ {
+ ugh = "OAKLEY proposal refused";
+ }
+ }
+
+ if (ugh == NULL)
+ {
+ /* a little more checking is in order */
+ {
+ lset_t missing
+ = ~seen_attrs
+ & (LELEM(OAKLEY_ENCRYPTION_ALGORITHM)
+ | LELEM(OAKLEY_HASH_ALGORITHM)
+ | LELEM(OAKLEY_AUTHENTICATION_METHOD)
+ | LELEM(OAKLEY_GROUP_DESCRIPTION));
+
+ if (missing)
+ {
+ loglog(RC_LOG_SERIOUS, "missing mandatory attribute(s) %s in Oakley Transform %u"
+ , bitnamesof(oakley_attr_bit_names, missing)
+ , trans.isat_transnum);
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ }
+ /* We must have liked this transform.
+ * Lets finish early and leave.
+ */
+
+ DBG(DBG_PARSING | DBG_CRYPT
+ , DBG_log("Oakley Transform %u accepted", trans.isat_transnum));
+
+ if (r_sa_pbs != NULL)
+ {
+ struct isakmp_proposal r_proposal = *proposal;
+ pb_stream r_proposal_pbs;
+ struct isakmp_transform r_trans = trans;
+ pb_stream r_trans_pbs;
+
+ /* Situation */
+ if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL))
+ impossible();
+
+ /* Proposal */
+#ifdef EMIT_ISAKMP_SPI
+ r_proposal.isap_spisize = COOKIE_SIZE;
+#else
+ r_proposal.isap_spisize = 0;
+#endif
+ r_proposal.isap_notrans = 1;
+ if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs))
+ impossible();
+
+ /* SPI */
+#ifdef EMIT_ISAKMP_SPI
+ if (!out_raw(my_cookie, COOKIE_SIZE, &r_proposal_pbs, "SPI"))
+ impossible();
+ r_proposal.isap_spisize = COOKIE_SIZE;
+#else
+ /* none (0) */
+#endif
+
+ /* Transform */
+ r_trans.isat_np = ISAKMP_NEXT_NONE;
+ if (!out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs))
+ impossible();
+
+ if (!out_raw(attr_start, attr_len, &r_trans_pbs, "attributes"))
+ impossible();
+ close_output_pbs(&r_trans_pbs);
+ close_output_pbs(&r_proposal_pbs);
+ close_output_pbs(r_sa_pbs);
+ }
+
+ /* copy over the results */
+ st->st_oakley = ta;
+ return NOTHING_WRONG;
+ }
+
+ /* on to next transform */
+ no_trans_left--;
+
+ if (trans.isat_np == ISAKMP_NEXT_NONE)
+ {
+ if (no_trans_left != 0)
+ {
+ loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ break;
+ }
+ if (trans.isat_np != ISAKMP_NEXT_T)
+ {
+ loglog(RC_LOG_SERIOUS, "unexpected %s payload in Oakley Proposal"
+ , enum_show(&payload_names, proposal->isap_np));
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ }
+ loglog(RC_LOG_SERIOUS, "no acceptable Oakley Transform");
+ return NO_PROPOSAL_CHOSEN;
+}
+
+/* Parse the body of an IPsec SA Payload (i.e. Phase 2 / Quick Mode).
+ *
+ * The main routine is parse_ipsec_sa_body; other functions defined
+ * between here and there are just helpers.
+ *
+ * Various shortcuts are taken. In particular, the policy, such as
+ * it is, is hardwired.
+ *
+ * If r_sa is non-NULL, the body of an SA representing the selected
+ * proposal is emitted into it.
+ *
+ * If "selection" is true, the SA is supposed to represent the
+ * single tranform that the peer has accepted.
+ * ??? We only check that it is acceptable, not that it is one that we offered!
+ *
+ * Only IPsec DOI is accepted (what is the ISAKMP DOI?).
+ * Error response is rudimentary.
+ *
+ * Since all ISAKMP groups in all SA Payloads must match, st->st_pfs_group
+ * holds this across multiple payloads.
+ * &unset_group signifies not yet "set"; NULL signifies NONE.
+ *
+ * This routine is used by quick_inI1_outR1() and quick_inR1_outI2().
+ */
+
+static const struct ipsec_trans_attrs null_ipsec_trans_attrs = {
+ 0, /* transid (NULL, for now) */
+ 0, /* spi */
+ SA_LIFE_DURATION_DEFAULT, /* life_seconds */
+ SA_LIFE_DURATION_K_DEFAULT, /* life_kilobytes */
+ ENCAPSULATION_MODE_UNSPECIFIED, /* encapsulation */
+ AUTH_ALGORITHM_NONE, /* auth */
+ 0, /* key_len */
+ 0, /* key_rounds */
+};
+
+static bool
+parse_ipsec_transform(struct isakmp_transform *trans
+, struct ipsec_trans_attrs *attrs
+, pb_stream *prop_pbs
+, pb_stream *trans_pbs
+, struct_desc *trans_desc
+, int previous_transnum /* or -1 if none */
+, bool selection
+, bool is_last
+, bool is_ipcomp
+, struct state *st) /* current state object */
+{
+ lset_t seen_attrs = 0;
+ lset_t seen_durations = 0;
+ u_int16_t life_type = 0;
+ const struct oakley_group_desc *pfs_group = NULL;
+
+ if (!in_struct(trans, trans_desc, prop_pbs, trans_pbs))
+ return FALSE;
+
+ if (trans->isat_transnum <= previous_transnum)
+ {
+ loglog(RC_LOG_SERIOUS, "Transform Numbers in Proposal are not monotonically increasing");
+ return FALSE;
+ }
+
+ switch (trans->isat_np)
+ {
+ case ISAKMP_NEXT_T:
+ if (is_last)
+ {
+ loglog(RC_LOG_SERIOUS, "Proposal Payload has more Transforms than specified");
+ return FALSE;
+ }
+ break;
+ case ISAKMP_NEXT_NONE:
+ if (!is_last)
+ {
+ loglog(RC_LOG_SERIOUS, "Proposal Payload has fewer Transforms than specified");
+ return FALSE;
+ }
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "expecting Transform Payload, but found %s in Proposal"
+ , enum_show(&payload_names, trans->isat_np));
+ return FALSE;
+ }
+
+ *attrs = null_ipsec_trans_attrs;
+ attrs->transid = trans->isat_transid;
+
+ while (pbs_left(trans_pbs) != 0)
+ {
+ struct isakmp_attribute a;
+ pb_stream attr_pbs;
+ enum_names *vdesc;
+ u_int32_t val; /* room for larger value */
+ bool ipcomp_inappropriate = is_ipcomp; /* will get reset if OK */
+
+ if (!in_struct(&a, &isakmp_ipsec_attribute_desc, trans_pbs, &attr_pbs))
+ return FALSE;
+
+ passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32);
+
+ if (LHAS(seen_attrs, a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK))
+ {
+ loglog(RC_LOG_SERIOUS, "repeated %s attribute in IPsec Transform %u"
+ , enum_show(&ipsec_attr_names, a.isaat_af_type)
+ , trans->isat_transnum);
+ return FALSE;
+ }
+
+ seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK);
+
+ val = a.isaat_lv;
+
+ vdesc = ipsec_attr_val_descs[a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK];
+ if (vdesc != NULL)
+ {
+ if (enum_name(vdesc, val) == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "invalid value %u for attribute %s in IPsec Transform"
+ , (unsigned)val, enum_show(&ipsec_attr_names, a.isaat_af_type));
+ return FALSE;
+ }
+ DBG(DBG_PARSING
+ , if ((a.isaat_af_type & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
+ DBG_log(" [%u is %s]"
+ , (unsigned)val, enum_show(vdesc, val)));
+ }
+
+ switch (a.isaat_af_type)
+ {
+ case SA_LIFE_TYPE | ISAKMP_ATTR_AF_TV:
+ ipcomp_inappropriate = FALSE;
+ if (LHAS(seen_durations, val))
+ {
+ loglog(RC_LOG_SERIOUS, "attribute SA_LIFE_TYPE value %s repeated in message"
+ , enum_show(&sa_lifetime_names, val));
+ return FALSE;
+ }
+ seen_durations |= LELEM(val);
+ life_type = val;
+ break;
+ case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV:
+ val = decode_long_duration(&attr_pbs);
+ /* fall through */
+ case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TV:
+ ipcomp_inappropriate = FALSE;
+ if (!LHAS(seen_attrs, SA_LIFE_DURATION))
+ {
+ loglog(RC_LOG_SERIOUS, "SA_LIFE_DURATION IPsec attribute not preceded by SA_LIFE_TYPE attribute");
+ return FALSE;
+ }
+ seen_attrs &= ~(LELEM(SA_LIFE_DURATION) | LELEM(SA_LIFE_TYPE));
+
+ switch (life_type)
+ {
+ case SA_LIFE_TYPE_SECONDS:
+ /* silently limit duration to our maximum */
+ attrs->life_seconds = val <= SA_LIFE_DURATION_MAXIMUM
+ ? val : SA_LIFE_DURATION_MAXIMUM;
+ break;
+ case SA_LIFE_TYPE_KBYTES:
+ attrs->life_kilobytes = val;
+ break;
+ default:
+ bad_case(life_type);
+ }
+ break;
+ case GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV:
+ if (is_ipcomp)
+ {
+ /* Accept reluctantly. Should not happen, according to
+ * draft-shacham-ippcp-rfc2393bis-05.txt 4.1.
+ */
+ ipcomp_inappropriate = FALSE;
+ loglog(RC_COMMENT
+ , "IPCA (IPcomp SA) contains GROUP_DESCRIPTION."
+ " Ignoring inapproprate attribute.");
+ }
+ pfs_group = lookup_group(val);
+ if (pfs_group == NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported for PFS");
+ return FALSE;
+ }
+ break;
+ case ENCAPSULATION_MODE | ISAKMP_ATTR_AF_TV:
+ ipcomp_inappropriate = FALSE;
+#ifdef NAT_TRAVERSAL
+ switch (val)
+ {
+ case ENCAPSULATION_MODE_TUNNEL:
+ case ENCAPSULATION_MODE_TRANSPORT:
+ if (st->nat_traversal & NAT_T_DETECTED)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used if NAT-Traversal is not detected"
+ , enum_name(&enc_mode_names, val));
+ /*
+ * Accept it anyway because SSH-Sentinel does not
+ * use UDP_TUNNEL or UDP_TRANSPORT for the diagnostic.
+ *
+ * remove when SSH-Sentinel is fixed
+ */
+#ifdef I_DONT_CARE_OF_SSH_SENTINEL
+ return FALSE;
+#endif
+ }
+ attrs->encapsulation = val;
+ break;
+ case ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS:
+#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+ loglog(RC_LOG_SERIOUS
+ , "NAT-Traversal: Transport mode disabled due to security concerns");
+ return FALSE;
+#endif
+ case ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS:
+ if (st->nat_traversal & NAT_T_WITH_RFC_VALUES)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used with old IETF drafts"
+ , enum_name(&enc_mode_names, val));
+ return FALSE;
+ }
+ else if (st->nat_traversal & NAT_T_DETECTED)
+ {
+ attrs->encapsulation = val
+ - ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS
+ + ENCAPSULATION_MODE_TUNNEL;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used if NAT-Traversal is detected"
+ , enum_name(&enc_mode_names, val));
+ return FALSE;
+ }
+ break;
+ case ENCAPSULATION_MODE_UDP_TRANSPORT_RFC:
+#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+ loglog(RC_LOG_SERIOUS
+ , "NAT-Traversal: Transport mode disabled due "
+ "to security concerns");
+ return FALSE;
+#endif
+ case ENCAPSULATION_MODE_UDP_TUNNEL_RFC:
+ if ((st->nat_traversal & NAT_T_DETECTED)
+ && (st->nat_traversal & NAT_T_WITH_RFC_VALUES))
+ {
+ attrs->encapsulation = val
+ - ENCAPSULATION_MODE_UDP_TUNNEL_RFC
+ + ENCAPSULATION_MODE_TUNNEL;
+ }
+ else if (st->nat_traversal & NAT_T_DETECTED)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used with NAT-T RFC"
+ , enum_name(&enc_mode_names, val));
+ return FALSE;
+ }
+ else
+ {
+ loglog(RC_LOG_SERIOUS
+ , "%s must only be used if NAT-Traversal is detected"
+ , enum_name(&enc_mode_names, val));
+ return FALSE;
+ }
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS
+ , "unknown ENCAPSULATION_MODE %d in IPSec SA", val);
+ return FALSE;
+ }
+#else
+ attrs->encapsulation = val;
+#endif
+ break;
+ case AUTH_ALGORITHM | ISAKMP_ATTR_AF_TV:
+ attrs->auth = val;
+ break;
+ case KEY_LENGTH | ISAKMP_ATTR_AF_TV:
+ attrs->key_len = val;
+ break;
+ case KEY_ROUNDS | ISAKMP_ATTR_AF_TV:
+ attrs->key_rounds = val;
+ break;
+#if 0 /* not yet implemented */
+ case COMPRESS_DICT_SIZE | ISAKMP_ATTR_AF_TV:
+ break;
+ case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TV:
+ break;
+
+ case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV:
+ break;
+ case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TLV:
+ break;
+#endif
+ default:
+ loglog(RC_LOG_SERIOUS, "unsupported IPsec attribute %s"
+ , enum_show(&ipsec_attr_names, a.isaat_af_type));
+ return FALSE;
+ }
+ if (ipcomp_inappropriate)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec attribute %s inappropriate for IPCOMP"
+ , enum_show(&ipsec_attr_names, a.isaat_af_type));
+ return FALSE;
+ }
+ }
+
+ /* Although an IPCOMP SA (IPCA) ought not to have a pfs_group,
+ * if it does, demand that it be consistent.
+ * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1.
+ */
+ if (!is_ipcomp || pfs_group != NULL)
+ {
+ if (st->st_pfs_group == &unset_group)
+ st->st_pfs_group = pfs_group;
+
+ if (st->st_pfs_group != pfs_group)
+ {
+ loglog(RC_LOG_SERIOUS, "GROUP_DESCRIPTION inconsistent with that of %s in IPsec SA"
+ , selection? "the Proposal" : "a previous Transform");
+ return FALSE;
+ }
+ }
+
+ if (LHAS(seen_attrs, SA_LIFE_DURATION))
+ {
+ loglog(RC_LOG_SERIOUS, "SA_LIFE_TYPE IPsec attribute not followed by SA_LIFE_DURATION attribute in message");
+ return FALSE;
+ }
+
+ if (!LHAS(seen_attrs, ENCAPSULATION_MODE))
+ {
+ if (is_ipcomp)
+ {
+ /* draft-shacham-ippcp-rfc2393bis-05.txt 4.1:
+ * "If the Encapsulation Mode is unspecified,
+ * the default value of Transport Mode is assumed."
+ * This contradicts/overrides the DOI (quuoted below).
+ */
+ attrs->encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+ }
+ else
+ {
+ /* ??? Technically, RFC 2407 (IPSEC DOI) 4.5 specifies that
+ * the default is "unspecified (host-dependent)".
+ * This makes little sense, so we demand that it be specified.
+ */
+ loglog(RC_LOG_SERIOUS, "IPsec Transform must specify ENCAPSULATION_MODE");
+ return FALSE;
+ }
+ }
+
+ /* ??? should check for key_len and/or key_rounds if required */
+
+ return TRUE;
+}
+
+static void
+echo_proposal(
+ struct isakmp_proposal r_proposal, /* proposal to emit */
+ struct isakmp_transform r_trans, /* winning transformation within it */
+ u_int8_t np, /* Next Payload for proposal */
+ pb_stream *r_sa_pbs, /* SA PBS into which to emit */
+ struct ipsec_proto_info *pi, /* info about this protocol instance */
+ struct_desc *trans_desc, /* descriptor for this transformation */
+ pb_stream *trans_pbs, /* PBS for incoming transform */
+ struct spd_route *sr, /* host details for the association */
+ bool tunnel_mode) /* true for inner most tunnel SA */
+{
+ pb_stream r_proposal_pbs;
+ pb_stream r_trans_pbs;
+
+ /* Proposal */
+ r_proposal.isap_np = np;
+ r_proposal.isap_notrans = 1;
+ if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs))
+ impossible();
+
+ /* allocate and emit our CPI/SPI */
+ if (r_proposal.isap_protoid == PROTO_IPCOMP)
+ {
+ /* CPI is stored in network low order end of an
+ * ipsec_spi_t. So we start a couple of bytes in.
+ * Note: we may fail to generate a satisfactory CPI,
+ * but we'll ignore that.
+ */
+ pi->our_spi = get_my_cpi(sr, tunnel_mode);
+ out_raw((u_char *) &pi->our_spi
+ + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE
+ , IPCOMP_CPI_SIZE
+ , &r_proposal_pbs, "CPI");
+ }
+ else
+ {
+ pi->our_spi = get_ipsec_spi(pi->attrs.spi
+ , r_proposal.isap_protoid == PROTO_IPSEC_AH ?
+ IPPROTO_AH : IPPROTO_ESP
+ , sr
+ , tunnel_mode);
+ /* XXX should check for errors */
+ out_raw((u_char *) &pi->our_spi, IPSEC_DOI_SPI_SIZE
+ , &r_proposal_pbs, "SPI");
+ }
+
+ /* Transform */
+ r_trans.isat_np = ISAKMP_NEXT_NONE;
+ if (!out_struct(&r_trans, trans_desc, &r_proposal_pbs, &r_trans_pbs))
+ impossible();
+
+ /* Transform Attributes: pure echo */
+ trans_pbs->cur = trans_pbs->start + sizeof(struct isakmp_transform);
+ if (!out_raw(trans_pbs->cur, pbs_left(trans_pbs)
+ , &r_trans_pbs, "attributes"))
+ impossible();
+
+ close_output_pbs(&r_trans_pbs);
+ close_output_pbs(&r_proposal_pbs);
+}
+
+notification_t
+parse_ipsec_sa_body(
+ pb_stream *sa_pbs, /* body of input SA Payload */
+ const struct isakmp_sa *sa, /* header of input SA Payload */
+ pb_stream *r_sa_pbs, /* if non-NULL, where to emit body of winning SA */
+ bool selection, /* if this SA is a selection, only one transform may appear */
+ struct state *st) /* current state object */
+{
+ const struct connection *c = st->st_connection;
+ u_int32_t ipsecdoisit;
+ pb_stream next_proposal_pbs;
+
+ struct isakmp_proposal next_proposal;
+ ipsec_spi_t next_spi;
+
+ bool next_full = TRUE;
+
+ /* DOI */
+ if (sa->isasa_doi != ISAKMP_DOI_IPSEC)
+ {
+ loglog(RC_LOG_SERIOUS, "Unknown or unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi));
+ /* XXX Could send notification back */
+ return DOI_NOT_SUPPORTED;
+ }
+
+ /* Situation */
+ if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL))
+ return SITUATION_NOT_SUPPORTED;
+
+ if (ipsecdoisit != SIT_IDENTITY_ONLY)
+ {
+ loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)"
+ , bitnamesof(sit_bit_names, ipsecdoisit));
+ /* XXX Could send notification back */
+ return SITUATION_NOT_SUPPORTED;
+ }
+
+ /* The rules for IPsec SAs are scattered.
+ * RFC 2408 "ISAKMP" section 4.2 gives some info.
+ * There may be multiple proposals. Those with identical proposal
+ * numbers must be considered as conjuncts. Those with different
+ * numbers are disjuncts.
+ * Each proposal may have several transforms, each considered
+ * an alternative.
+ * Each transform may have several attributes, all applying.
+ *
+ * To handle the way proposals are combined, we need to do a
+ * look-ahead.
+ */
+
+ if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+
+ /* for each conjunction of proposals... */
+ while (next_full)
+ {
+ int propno = next_proposal.isap_proposal;
+ pb_stream ah_prop_pbs, esp_prop_pbs, ipcomp_prop_pbs;
+ struct isakmp_proposal ah_proposal, esp_proposal, ipcomp_proposal;
+ ipsec_spi_t ah_spi = 0;
+ ipsec_spi_t esp_spi = 0;
+ ipsec_spi_t ipcomp_cpi = 0;
+ bool ah_seen = FALSE;
+ bool esp_seen = FALSE;
+ bool ipcomp_seen = FALSE;
+ bool tunnel_mode = FALSE;
+ int inner_proto = 0;
+ u_int16_t well_known_cpi = 0;
+
+ pb_stream ah_trans_pbs, esp_trans_pbs, ipcomp_trans_pbs;
+ struct isakmp_transform ah_trans, esp_trans, ipcomp_trans;
+ struct ipsec_trans_attrs ah_attrs, esp_attrs, ipcomp_attrs;
+
+ /* for each proposal in the conjunction */
+ do {
+
+ if (next_proposal.isap_protoid == PROTO_IPCOMP)
+ {
+ /* IPCOMP CPI */
+ if (next_proposal.isap_spisize == IPSEC_DOI_SPI_SIZE)
+ {
+ /* This code is to accommodate those peculiar
+ * implementations that send a CPI in the bottom of an
+ * SPI-sized field.
+ * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1
+ */
+ u_int8_t filler[IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE];
+
+ if (!in_raw(filler, sizeof(filler)
+ , &next_proposal_pbs, "CPI filler")
+ || !all_zero(filler, sizeof(filler)))
+ return INVALID_SPI;
+ }
+ else if (next_proposal.isap_spisize != IPCOMP_CPI_SIZE)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper CPI size (%u)"
+ , next_proposal.isap_spisize);
+ return INVALID_SPI;
+ }
+
+ /* We store CPI in the low order of a network order
+ * ipsec_spi_t. So we start a couple of bytes in.
+ */
+ zero(&next_spi);
+ if (!in_raw((u_char *)&next_spi
+ + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE
+ , IPCOMP_CPI_SIZE, &next_proposal_pbs, "CPI"))
+ return INVALID_SPI;
+
+ /* If sanity ruled, CPIs would have to be such that
+ * the SAID (the triple (CPI, IPCOM, destination IP))
+ * would be unique, just like for SPIs. But there is a
+ * perversion where CPIs can be well-known and consequently
+ * the triple is not unique. We hide this fact from
+ * ourselves by fudging the top 16 bits to make
+ * the property true internally!
+ */
+ switch (ntohl(next_spi))
+ {
+ case IPCOMP_DEFLATE:
+ well_known_cpi = ntohl(next_spi);
+ next_spi = uniquify_his_cpi(next_spi, st);
+ if (next_spi == 0)
+ {
+ loglog(RC_LOG_SERIOUS
+ , "IPsec Proposal contains well-known CPI that I cannot uniquify");
+ return INVALID_SPI;
+ }
+ break;
+ default:
+ if (ntohl(next_spi) < IPCOMP_FIRST_NEGOTIATED
+ || ntohl(next_spi) > IPCOMP_LAST_NEGOTIATED)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal contains CPI from non-negotiated range (0x%lx)"
+ , (unsigned long) ntohl(next_spi));
+ return INVALID_SPI;
+ }
+ break;
+ }
+ }
+ else
+ {
+ /* AH or ESP SPI */
+ if (next_proposal.isap_spisize != IPSEC_DOI_SPI_SIZE)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper SPI size (%u)"
+ , next_proposal.isap_spisize);
+ return INVALID_SPI;
+ }
+
+ if (!in_raw((u_char *)&next_spi, sizeof(next_spi), &next_proposal_pbs, "SPI"))
+ return INVALID_SPI;
+
+ /* SPI value 0 is invalid and values 1-255 are reserved to IANA.
+ * RFC 2402 (ESP) 2.4, RFC 2406 (AH) 2.1
+ * IPCOMP???
+ */
+ if (ntohl(next_spi) < IPSEC_DOI_SPI_MIN)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal contains invalid SPI (0x%lx)"
+ , (unsigned long) ntohl(next_spi));
+ return INVALID_SPI;
+ }
+ }
+
+ if (next_proposal.isap_notrans == 0)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec Proposal contains no Transforms");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ switch (next_proposal.isap_protoid)
+ {
+ case PROTO_IPSEC_AH:
+ if (ah_seen)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous AH Proposals");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ ah_seen = TRUE;
+ ah_prop_pbs = next_proposal_pbs;
+ ah_proposal = next_proposal;
+ ah_spi = next_spi;
+ break;
+
+ case PROTO_IPSEC_ESP:
+ if (esp_seen)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous ESP Proposals");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ esp_seen = TRUE;
+ esp_prop_pbs = next_proposal_pbs;
+ esp_proposal = next_proposal;
+ esp_spi = next_spi;
+ break;
+
+ case PROTO_IPCOMP:
+ if (ipcomp_seen)
+ {
+ loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous IPCOMP Proposals");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ ipcomp_seen = TRUE;
+ ipcomp_prop_pbs = next_proposal_pbs;
+ ipcomp_proposal = next_proposal;
+ ipcomp_cpi = next_spi;
+ break;
+
+ default:
+ loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) in IPsec Proposal"
+ , enum_show(&protocol_names, next_proposal.isap_protoid));
+ return INVALID_PROTOCOL_ID;
+ }
+
+ /* refill next_proposal */
+ if (next_proposal.isap_np == ISAKMP_NEXT_NONE)
+ {
+ next_full = FALSE;
+ break;
+ }
+ else if (next_proposal.isap_np != ISAKMP_NEXT_P)
+ {
+ loglog(RC_LOG_SERIOUS, "unexpected in Proposal: %s"
+ , enum_show(&payload_names, next_proposal.isap_np));
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs))
+ return BAD_PROPOSAL_SYNTAX;
+ } while (next_proposal.isap_proposal == propno);
+
+ /* Now that we have all conjuncts, we should try
+ * the Cartesian product of eachs tranforms!
+ * At the moment, we take short-cuts on account of
+ * our rudimentary hard-wired policy.
+ * For now, we find an acceptable AH (if any)
+ * and then an acceptable ESP. The only interaction
+ * is that the ESP acceptance can know whether there
+ * was an acceptable AH and hence not require an AUTH.
+ */
+
+ if (ah_seen)
+ {
+ int previous_transnum = -1;
+ int tn;
+
+ for (tn = 0; tn != ah_proposal.isap_notrans; tn++)
+ {
+ int ok_transid = 0;
+ bool ok_auth = FALSE;
+
+ if (!parse_ipsec_transform(&ah_trans
+ , &ah_attrs
+ , &ah_prop_pbs
+ , &ah_trans_pbs
+ , &isakmp_ah_transform_desc
+ , previous_transnum
+ , selection
+ , tn == ah_proposal.isap_notrans - 1
+ , FALSE
+ , st))
+ return BAD_PROPOSAL_SYNTAX;
+
+ previous_transnum = ah_trans.isat_transnum;
+
+ /* we must understand ah_attrs.transid
+ * COMBINED with ah_attrs.auth.
+ * See RFC 2407 "IPsec DOI" section 4.4.3
+ * The following combinations are legal,
+ * but we don't implement all of them:
+ * It seems as if each auth algorithm
+ * only applies to one ah transid.
+ * AH_MD5, AUTH_ALGORITHM_HMAC_MD5
+ * AH_MD5, AUTH_ALGORITHM_KPDK (unimplemented)
+ * AH_SHA, AUTH_ALGORITHM_HMAC_SHA1
+ * AH_DES, AUTH_ALGORITHM_DES_MAC (unimplemented)
+ */
+ switch (ah_attrs.auth)
+ {
+ case AUTH_ALGORITHM_NONE:
+ loglog(RC_LOG_SERIOUS, "AUTH_ALGORITHM attribute missing in AH Transform");
+ return BAD_PROPOSAL_SYNTAX;
+
+ case AUTH_ALGORITHM_HMAC_MD5:
+ ok_auth = TRUE;
+ /* fall through */
+ case AUTH_ALGORITHM_KPDK:
+ ok_transid = AH_MD5;
+ break;
+
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ ok_auth = TRUE;
+ ok_transid = AH_SHA;
+ break;
+
+ case AUTH_ALGORITHM_DES_MAC:
+ ok_transid = AH_DES;
+ break;
+ }
+ if (ah_attrs.transid != ok_transid)
+ {
+ loglog(RC_LOG_SERIOUS, "%s attribute inappropriate in %s Transform"
+ , enum_name(&auth_alg_names, ah_attrs.auth)
+ , enum_show(&ah_transformid_names, ah_attrs.transid));
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ if (!ok_auth)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("%s attribute unsupported"
+ " in %s Transform from %s"
+ , enum_name(&auth_alg_names, ah_attrs.auth)
+ , enum_show(&ah_transformid_names, ah_attrs.transid)
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ break; /* we seem to be happy */
+ }
+ if (tn == ah_proposal.isap_notrans)
+ continue; /* we didn't find a nice one */
+ ah_attrs.spi = ah_spi;
+ inner_proto = IPPROTO_AH;
+ if (ah_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ tunnel_mode = TRUE;
+ }
+
+ if (esp_seen)
+ {
+ int previous_transnum = -1;
+ int tn;
+
+ for (tn = 0; tn != esp_proposal.isap_notrans; tn++)
+ {
+ if (!parse_ipsec_transform(&esp_trans
+ , &esp_attrs
+ , &esp_prop_pbs
+ , &esp_trans_pbs
+ , &isakmp_esp_transform_desc
+ , previous_transnum
+ , selection
+ , tn == esp_proposal.isap_notrans - 1
+ , FALSE
+ , st))
+ return BAD_PROPOSAL_SYNTAX;
+
+ previous_transnum = esp_trans.isat_transnum;
+
+ /* set default key length for AES encryption */
+ if (!esp_attrs.key_len && esp_attrs.transid == ESP_AES)
+ {
+ esp_attrs.key_len = 128 / BITS_PER_BYTE;
+ }
+
+ if (!kernel_alg_esp_enc_ok(esp_attrs.transid, esp_attrs.key_len
+ ,c->alg_info_esp))
+ {
+ switch (esp_attrs.transid)
+ {
+ case ESP_3DES:
+ break;
+#ifdef SUPPORT_ESP_NULL /* should be about as secure as AH-only */
+ case ESP_NULL:
+ if (esp_attrs.auth == AUTH_ALGORITHM_NONE)
+ {
+ loglog(RC_LOG_SERIOUS, "ESP_NULL requires auth algorithm");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+ if (st->st_policy & POLICY_ENCRYPT)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("ESP_NULL Transform Proposal from %s"
+ " does not satisfy POLICY_ENCRYPT"
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ break;
+#endif
+ default:
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("unsupported ESP Transform %s from %s"
+ , enum_show(&esp_transformid_names, esp_attrs.transid)
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ }
+
+ if (!kernel_alg_esp_auth_ok(esp_attrs.auth, c->alg_info_esp))
+ {
+ switch (esp_attrs.auth)
+ {
+ case AUTH_ALGORITHM_NONE:
+ if (!ah_seen)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("ESP from %s must either have AUTH or be combined with AH"
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ break;
+ case AUTH_ALGORITHM_HMAC_MD5:
+ case AUTH_ALGORITHM_HMAC_SHA1:
+ break;
+ default:
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("unsupported ESP auth alg %s from %s"
+ , enum_show(&auth_alg_names, esp_attrs.auth)
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+ }
+
+ /* A last check for allowed transforms in alg_info_esp
+ * (ALG_INFO_F_STRICT flag)
+ */
+ if (!kernel_alg_esp_ok_final(esp_attrs.transid, esp_attrs.key_len
+ ,esp_attrs.auth, c->alg_info_esp))
+ {
+ continue;
+ }
+
+ if (ah_seen && ah_attrs.encapsulation != esp_attrs.encapsulation)
+ {
+ /* ??? This should be an error, but is it? */
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("AH and ESP transforms disagree about encapsulation; TUNNEL presumed"));
+ }
+
+ break; /* we seem to be happy */
+ }
+ if (tn == esp_proposal.isap_notrans)
+ continue; /* we didn't find a nice one */
+
+ esp_attrs.spi = esp_spi;
+ inner_proto = IPPROTO_ESP;
+ if (esp_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ tunnel_mode = TRUE;
+ }
+ else if (st->st_policy & POLICY_ENCRYPT)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("policy for \"%s\" requires encryption but ESP not in Proposal from %s"
+ , c->name, ip_str(&c->spd.that.host_addr)));
+ continue; /* we needed encryption, but didn't find ESP */
+ }
+ else if ((st->st_policy & POLICY_AUTHENTICATE) && !ah_seen)
+ {
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("policy for \"%s\" requires authentication"
+ " but none in Proposal from %s"
+ , c->name, ip_str(&c->spd.that.host_addr)));
+ continue; /* we need authentication, but we found neither ESP nor AH */
+ }
+
+ if (ipcomp_seen)
+ {
+ int previous_transnum = -1;
+ int tn;
+
+#ifdef NEVER /* we think IPcomp is working now */
+ /**** FUDGE TO PREVENT UNREQUESTED IPCOMP:
+ **** NEEDED BECAUSE OUR IPCOMP IS EXPERIMENTAL (UNSTABLE).
+ ****/
+ if (!(st->st_policy & POLICY_COMPRESS))
+ {
+ plog("compression proposed by %s, but policy for \"%s\" forbids it"
+ , ip_str(&c->spd.that.host_addr), c->name);
+ continue; /* unwanted compression proposal */
+ }
+#endif
+ if (!can_do_IPcomp)
+ {
+ plog("compression proposed by %s, but KLIPS is not configured with IPCOMP"
+ , ip_str(&c->spd.that.host_addr));
+ continue;
+ }
+
+ if (well_known_cpi != 0 && !ah_seen && !esp_seen)
+ {
+ plog("illegal proposal: bare IPCOMP used with well-known CPI");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ for (tn = 0; tn != ipcomp_proposal.isap_notrans; tn++)
+ {
+ if (!parse_ipsec_transform(&ipcomp_trans
+ , &ipcomp_attrs
+ , &ipcomp_prop_pbs
+ , &ipcomp_trans_pbs
+ , &isakmp_ipcomp_transform_desc
+ , previous_transnum
+ , selection
+ , tn == ipcomp_proposal.isap_notrans - 1
+ , TRUE
+ , st))
+ return BAD_PROPOSAL_SYNTAX;
+
+ previous_transnum = ipcomp_trans.isat_transnum;
+
+ if (well_known_cpi != 0 && ipcomp_attrs.transid != well_known_cpi)
+ {
+ plog("illegal proposal: IPCOMP well-known CPI disagrees with transform");
+ return BAD_PROPOSAL_SYNTAX;
+ }
+
+ switch (ipcomp_attrs.transid)
+ {
+ case IPCOMP_DEFLATE: /* all we can handle! */
+ break;
+
+ default:
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("unsupported IPCOMP Transform %s from %s"
+ , enum_show(&ipcomp_transformid_names, ipcomp_attrs.transid)
+ , ip_str(&c->spd.that.host_addr)));
+ continue; /* try another */
+ }
+
+ if (ah_seen && ah_attrs.encapsulation != ipcomp_attrs.encapsulation)
+ {
+ /* ??? This should be an error, but is it? */
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("AH and IPCOMP transforms disagree about encapsulation; TUNNEL presumed"));
+ } else if (esp_seen && esp_attrs.encapsulation != ipcomp_attrs.encapsulation)
+ {
+ /* ??? This should be an error, but is it? */
+ DBG(DBG_CONTROL | DBG_CRYPT
+ , DBG_log("ESP and IPCOMP transforms disagree about encapsulation; TUNNEL presumed"));
+ }
+
+ break; /* we seem to be happy */
+ }
+ if (tn == ipcomp_proposal.isap_notrans)
+ continue; /* we didn't find a nice one */
+ ipcomp_attrs.spi = ipcomp_cpi;
+ inner_proto = IPPROTO_COMP;
+ if (ipcomp_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)
+ tunnel_mode = TRUE;
+ }
+
+ /* Eureka: we liked what we saw -- accept it. */
+
+ if (r_sa_pbs != NULL)
+ {
+ /* emit what we've accepted */
+
+ /* Situation */
+ if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL))
+ impossible();
+
+ /* AH proposal */
+ if (ah_seen)
+ echo_proposal(ah_proposal
+ , ah_trans
+ , esp_seen || ipcomp_seen? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE
+ , r_sa_pbs
+ , &st->st_ah
+ , &isakmp_ah_transform_desc
+ , &ah_trans_pbs
+ , &st->st_connection->spd
+ , tunnel_mode && inner_proto == IPPROTO_AH);
+
+ /* ESP proposal */
+ if (esp_seen)
+ echo_proposal(esp_proposal
+ , esp_trans
+ , ipcomp_seen? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE
+ , r_sa_pbs
+ , &st->st_esp
+ , &isakmp_esp_transform_desc
+ , &esp_trans_pbs
+ , &st->st_connection->spd
+ , tunnel_mode && inner_proto == IPPROTO_ESP);
+
+ /* IPCOMP proposal */
+ if (ipcomp_seen)
+ echo_proposal(ipcomp_proposal
+ , ipcomp_trans
+ , ISAKMP_NEXT_NONE
+ , r_sa_pbs
+ , &st->st_ipcomp
+ , &isakmp_ipcomp_transform_desc
+ , &ipcomp_trans_pbs
+ , &st->st_connection->spd
+ , tunnel_mode && inner_proto == IPPROTO_COMP);
+
+ close_output_pbs(r_sa_pbs);
+ }
+
+ /* save decoded version of winning SA in state */
+
+ st->st_ah.present = ah_seen;
+ if (ah_seen)
+ st->st_ah.attrs = ah_attrs;
+
+ st->st_esp.present = esp_seen;
+ if (esp_seen)
+ st->st_esp.attrs = esp_attrs;
+
+ st->st_ipcomp.present = ipcomp_seen;
+ if (ipcomp_seen)
+ st->st_ipcomp.attrs = ipcomp_attrs;
+
+ return NOTHING_WRONG;
+ }
+
+ loglog(RC_LOG_SERIOUS, "no acceptable Proposal in IPsec SA");
+ return NO_PROPOSAL_CHOSEN;
+}
diff --git a/programs/pluto/spdb.h b/programs/pluto/spdb.h
new file mode 100644
index 000000000..5eebf86cf
--- /dev/null
+++ b/programs/pluto/spdb.h
@@ -0,0 +1,113 @@
+/* Security Policy Data Base (such as it is)
+ * Copyright (C) 1998, 1999 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: spdb.h,v 1.4 2006/04/22 21:59:20 as Exp $
+ */
+
+#ifndef _SPDB_H
+#define _SPDB_H
+
+#include "packet.h"
+
+/* database of SA properties */
+
+/* Attribute type and value pair.
+ * Note: only "basic" values are represented so far.
+ */
+struct db_attr {
+ u_int16_t type; /* ISAKMP_ATTR_AF_TV is implied; 0 for end */
+ u_int16_t val;
+};
+
+/* transform */
+struct db_trans {
+ u_int8_t transid; /* Transform-Id */
+ struct db_attr *attrs; /* array */
+ int attr_cnt; /* number of elements */
+};
+
+/* proposal */
+struct db_prop {
+ u_int8_t protoid; /* Protocol-Id */
+ struct db_trans *trans; /* array (disjunction) */
+ int trans_cnt; /* number of elements */
+ /* SPI size and value isn't part of DB */
+};
+
+/* conjunction of proposals */
+struct db_prop_conj {
+ struct db_prop *props; /* array */
+ int prop_cnt; /* number of elements */
+};
+
+/* security association */
+struct db_sa {
+ struct db_prop_conj *prop_conjs; /* array */
+ int prop_conj_cnt; /* number of elements */
+ /* Hardwired for now;
+ * DOI: ISAKMP_DOI_IPSEC
+ * Situation: SIT_IDENTITY_ONLY
+ */
+};
+
+/* The oakley sadb is subscripted by a bitset with members
+ * from POLICY_PSK and POLICY_RSASIG.
+ */
+extern struct db_sa oakley_sadb[1 << 2];
+
+/* The ipsec sadb is subscripted by a bitset with members
+ * from POLICY_ENCRYPT, POLICY_AUTHENTICATE, POLICY_COMPRESS
+ */
+extern struct db_sa ipsec_sadb[1 << 3];
+
+/* forward declaration */
+struct state;
+
+extern bool out_sa(
+ pb_stream *outs,
+ struct db_sa *sadb,
+ struct state *st,
+ bool oakley_mode,
+ u_int8_t np);
+
+extern notification_t preparse_isakmp_sa_body(
+ const struct isakmp_sa *sa, /* header of input SA Payload */
+ pb_stream *sa_pbs, /* body of input SA Payload */
+ u_int32_t *ipsecdoisit, /* IPsec DOI SIT bitset */
+ pb_stream *proposal_pbs, /* body of proposal Payload */
+ struct isakmp_proposal *proposal);
+
+extern notification_t parse_isakmp_policy(
+ pb_stream *proposal_pbs, /* body of proposal Payload */
+ u_int notrans, /* number of transforms */
+ lset_t *policy); /* RSA or PSK policy */
+
+extern notification_t parse_isakmp_sa_body(
+ u_int32_t ipsecdoisit, /* IPsec DOI SIT bitset */
+ pb_stream *proposal_pbs, /* body of proposal Payload */
+ struct isakmp_proposal *proposal,
+ pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */
+ struct state *st); /* current state object */
+
+extern notification_t parse_ipsec_sa_body(
+ pb_stream *sa_pbs, /* body of input SA Payload */
+ const struct isakmp_sa *sa, /* header of input SA Payload */
+ pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */
+ bool selection, /* if this SA is a selection, only one tranform can appear */
+ struct state *st); /* current state object */
+
+extern void backup_pbs(pb_stream *pbs);
+extern void restore_pbs(pb_stream *pbs);
+
+#endif /* _SPDB_H */
+
diff --git a/programs/pluto/state.c b/programs/pluto/state.c
new file mode 100644
index 000000000..5957654e3
--- /dev/null
+++ b/programs/pluto/state.c
@@ -0,0 +1,1007 @@
+/* routines for state objects
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: state.c,v 1.12 2006/04/03 15:49:36 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "connections.h"
+#include "state.h"
+#include "kernel.h"
+#include "log.h"
+#include "packet.h" /* so we can calculate sizeof(struct isakmp_hdr) */
+#include "keys.h" /* for free_public_key */
+#include "rnd.h"
+#include "timer.h"
+#include "whack.h"
+#include "demux.h" /* needs packet.h */
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h" /* requires sha1.h and md5.h */
+
+/*
+ * Global variables: had to go somewhere, might as well be this file.
+ */
+
+u_int16_t pluto_port = IKE_UDP_PORT; /* Pluto's port */
+
+/*
+ * This file has the functions that handle the
+ * state hash table and the Message ID list.
+ */
+
+/* Message-IDs
+ *
+ * A Message ID is contained in each IKE message header.
+ * For Phase 1 exchanges (Main and Aggressive), it will be zero.
+ * For other exchanges, which must be under the protection of an
+ * ISAKMP SA, the Message ID must be unique within that ISAKMP SA.
+ * Effectively, this labels the message as belonging to a particular
+ * exchange.
+ * BTW, we feel this uniqueness allows rekeying to be somewhat simpler
+ * than specified by draft-jenkins-ipsec-rekeying-06.txt.
+ *
+ * A MessageID is a 32 bit unsigned number. We represent the value
+ * internally in network order -- they are just blobs to us.
+ * They are unsigned numbers to make hashing and comparing easy.
+ *
+ * The following mechanism is used to allocate message IDs. This
+ * requires that we keep track of which numbers have already been used
+ * so that we don't allocate one in use.
+ */
+
+struct msgid_list
+{
+ msgid_t msgid; /* network order */
+ struct msgid_list *next;
+};
+
+bool
+reserve_msgid(struct state *isakmp_sa, msgid_t msgid)
+{
+ struct msgid_list *p;
+
+ passert(msgid != MAINMODE_MSGID);
+ passert(IS_ISAKMP_ENCRYPTED(isakmp_sa->st_state));
+
+ for (p = isakmp_sa->st_used_msgids; p != NULL; p = p->next)
+ if (p->msgid == msgid)
+ return FALSE;
+
+ p = alloc_thing(struct msgid_list, "msgid");
+ p->msgid = msgid;
+ p->next = isakmp_sa->st_used_msgids;
+ isakmp_sa->st_used_msgids = p;
+ return TRUE;
+}
+
+msgid_t
+generate_msgid(struct state *isakmp_sa)
+{
+ int timeout = 100; /* only try so hard for unique msgid */
+ msgid_t msgid;
+
+ passert(IS_ISAKMP_ENCRYPTED(isakmp_sa->st_state));
+
+ for (;;)
+ {
+ get_rnd_bytes((void *) &msgid, sizeof(msgid));
+ if (msgid != 0 && reserve_msgid(isakmp_sa, msgid))
+ break;
+
+ if (--timeout == 0)
+ {
+ plog("gave up looking for unique msgid; using 0x%08lx"
+ , (unsigned long) msgid);
+ break;
+ }
+ }
+ return msgid;
+}
+
+
+/* state table functions */
+
+#define STATE_TABLE_SIZE 32
+
+static struct state *statetable[STATE_TABLE_SIZE];
+
+static struct state **
+state_hash(const u_char *icookie, const u_char *rcookie, const ip_address *peer)
+{
+ u_int i = 0, j;
+ const unsigned char *byte_ptr;
+ size_t length = addrbytesptr(peer, &byte_ptr);
+
+ DBG(DBG_RAW | DBG_CONTROL,
+ DBG_dump("ICOOKIE:", icookie, COOKIE_SIZE);
+ DBG_dump("RCOOKIE:", rcookie, COOKIE_SIZE);
+ DBG_dump("peer:", byte_ptr, length));
+
+ /* XXX the following hash is pretty pathetic */
+
+ for (j = 0; j < COOKIE_SIZE; j++)
+ i = i * 407 + icookie[j] + rcookie[j];
+
+ for (j = 0; j < length; j++)
+ i = i * 613 + byte_ptr[j];
+
+ i = i % STATE_TABLE_SIZE;
+
+ DBG(DBG_CONTROL, DBG_log("state hash entry %d", i));
+
+ return &statetable[i];
+}
+
+/* Get a state object.
+ * Caller must schedule an event for this object so that it doesn't leak.
+ * Caller must insert_state().
+ */
+struct state *
+new_state(void)
+{
+ static const struct state blank_state; /* initialized all to zero & NULL */
+ static so_serial_t next_so = SOS_FIRST;
+ struct state *st;
+
+ st = clone_thing(blank_state, "struct state in new_state()");
+ st->st_serialno = next_so++;
+ passert(next_so > SOS_FIRST); /* overflow can't happen! */
+ st->st_whack_sock = NULL_FD;
+ DBG(DBG_CONTROL, DBG_log("creating state object #%lu at %p",
+ st->st_serialno, (void *) st));
+ return st;
+}
+
+/*
+ * Initialize the state table (and mask*).
+ */
+void
+init_states(void)
+{
+ int i;
+
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ statetable[i] = (struct state *) NULL;
+}
+
+/* Find the state object with this serial number.
+ * This allows state object references that don't turn into dangerous
+ * dangling pointers: reference a state by its serial number.
+ * Returns NULL if there is no such state.
+ * If this turns out to be a significant CPU hog, it could be
+ * improved to use a hash table rather than sequential seartch.
+ */
+struct state *
+state_with_serialno(so_serial_t sn)
+{
+ if (sn >= SOS_FIRST)
+ {
+ struct state *st;
+ int i;
+
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ if (st->st_serialno == sn)
+ return st;
+ }
+ return NULL;
+}
+
+/* Insert a state object in the hash table. The object is inserted
+ * at the begining of list.
+ * Needs cookies, connection, and msgid.
+ */
+void
+insert_state(struct state *st)
+{
+ struct state **p = state_hash(st->st_icookie, st->st_rcookie
+ , &st->st_connection->spd.that.host_addr);
+
+ passert(st->st_hashchain_prev == NULL && st->st_hashchain_next == NULL);
+
+ if (*p != NULL)
+ {
+ passert((*p)->st_hashchain_prev == NULL);
+ (*p)->st_hashchain_prev = st;
+ }
+ st->st_hashchain_next = *p;
+ *p = st;
+
+ /* Ensure that somebody is in charge of killing this state:
+ * if no event is scheduled for it, schedule one to discard the state.
+ * If nothing goes wrong, this event will be replaced by
+ * a more appropriate one.
+ */
+ if (st->st_event == NULL)
+ event_schedule(EVENT_SO_DISCARD, 0, st);
+}
+
+/* unlink a state object from the hash table, but don't free it
+ */
+void
+unhash_state(struct state *st)
+{
+ /* unlink from forward chain */
+ struct state **p = st->st_hashchain_prev == NULL
+ ? state_hash(st->st_icookie, st->st_rcookie
+ , &st->st_connection->spd.that.host_addr)
+ : &st->st_hashchain_prev->st_hashchain_next;
+
+ /* unlink from forward chain */
+ passert(*p == st);
+ *p = st->st_hashchain_next;
+
+ /* unlink from backward chain */
+ if (st->st_hashchain_next != NULL)
+ {
+ passert(st->st_hashchain_next->st_hashchain_prev == st);
+ st->st_hashchain_next->st_hashchain_prev = st->st_hashchain_prev;
+ }
+
+ st->st_hashchain_next = st->st_hashchain_prev = NULL;
+}
+
+/* Free the Whack socket file descriptor.
+ * This has the side effect of telling Whack that we're done.
+ */
+void
+release_whack(struct state *st)
+{
+ close_any(st->st_whack_sock);
+}
+
+/* delete a state object */
+void
+delete_state(struct state *st)
+{
+ struct connection *const c = st->st_connection;
+ struct state *old_cur_state = cur_state == st? NULL : cur_state;
+
+ set_cur_state(st);
+
+ /* If DPD is enabled on this state object, clear any pending events */
+ if(st->st_dpd_event != NULL)
+ delete_dpd_event(st);
+
+ /* if there is a suspended state transition, disconnect us */
+ if (st->st_suspended_md != NULL)
+ {
+ passert(st->st_suspended_md->st == st);
+ st->st_suspended_md->st = NULL;
+ }
+
+ /* tell the other side of any IPSEC SAs that are going down */
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)
+ || IS_ISAKMP_SA_ESTABLISHED(st->st_state))
+ send_delete(st);
+
+ delete_event(st); /* delete any pending timer event */
+
+ /* Ditch anything pending on ISAKMP SA being established.
+ * Note: this must be done before the unhash_state to prevent
+ * flush_pending_by_state inadvertently and prematurely
+ * deleting our connection.
+ */
+ flush_pending_by_state(st);
+
+ /* effectively, this deletes any ISAKMP SA that this state represents */
+ unhash_state(st);
+
+ /* tell kernel to delete any IPSEC SA
+ * ??? we ought to tell peer to delete IPSEC SAs
+ */
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ delete_ipsec_sa(st, FALSE);
+ else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state))
+ delete_ipsec_sa(st, TRUE);
+
+ if (c->newest_ipsec_sa == st->st_serialno)
+ c->newest_ipsec_sa = SOS_NOBODY;
+
+ if (c->newest_isakmp_sa == st->st_serialno)
+ c->newest_isakmp_sa = SOS_NOBODY;
+
+ st->st_connection = NULL; /* we might be about to free it */
+ cur_state = old_cur_state; /* without st_connection, st isn't complete */
+ connection_discard(c);
+
+ release_whack(st);
+
+ /* from here on we are just freeing RAM */
+
+ {
+ struct msgid_list *p = st->st_used_msgids;
+
+ while (p != NULL)
+ {
+ struct msgid_list *q = p;
+ p = p->next;
+ pfree(q);
+ }
+ }
+
+ unreference_key(&st->st_peer_pubkey);
+
+ if (st->st_sec_in_use)
+ mpz_clear(&(st->st_sec));
+
+ pfreeany(st->st_tpacket.ptr);
+ pfreeany(st->st_rpacket.ptr);
+ pfreeany(st->st_p1isa.ptr);
+ pfreeany(st->st_gi.ptr);
+ pfreeany(st->st_gr.ptr);
+ pfreeany(st->st_shared.ptr);
+ pfreeany(st->st_ni.ptr);
+ pfreeany(st->st_nr.ptr);
+ pfreeany(st->st_skeyid.ptr);
+ pfreeany(st->st_skeyid_d.ptr);
+ pfreeany(st->st_skeyid_a.ptr);
+ pfreeany(st->st_skeyid_e.ptr);
+ pfreeany(st->st_enc_key.ptr);
+ pfreeany(st->st_ah.our_keymat);
+ pfreeany(st->st_ah.peer_keymat);
+ pfreeany(st->st_esp.our_keymat);
+ pfreeany(st->st_esp.peer_keymat);
+
+ pfree(st);
+}
+
+/*
+ * Is a connection in use by some state?
+ */
+bool
+states_use_connection(struct connection *c)
+{
+ /* are there any states still using it? */
+ struct state *st = NULL;
+ int i;
+
+ for (i = 0; st == NULL && i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ if (st->st_connection == c)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * delete all states that were created for a given connection.
+ * if relations == TRUE, then also delete states that share
+ * the same phase 1 SA.
+ */
+void
+delete_states_by_connection(struct connection *c, bool relations)
+{
+ int pass;
+ /* this kludge avoids an n^2 algorithm */
+ enum connection_kind ck = c->kind;
+ struct spd_route *sr;
+
+ /* save this connection's isakmp SA, since it will get set to later SOS_NOBODY */
+ so_serial_t parent_sa = c->newest_isakmp_sa;
+
+ if (ck == CK_INSTANCE)
+ c->kind = CK_GOING_AWAY;
+
+ /* We take two passes so that we delete any ISAKMP SAs last.
+ * This allows Delete Notifications to be sent.
+ * ?? We could probably double the performance by caching any
+ * ISAKMP SA states found in the first pass, avoiding a second.
+ */
+ for (pass = 0; pass != 2; pass++)
+ {
+ int i;
+
+ /* For each hash chain... */
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ /* For each state in the hash chain... */
+ for (st = statetable[i]; st != NULL; )
+ {
+ struct state *this = st;
+
+ st = st->st_hashchain_next; /* before this is deleted */
+
+
+ if ((this->st_connection == c
+ || (relations && parent_sa != SOS_NOBODY
+ && this->st_clonedfrom == parent_sa))
+ && (pass == 1 || !IS_ISAKMP_SA_ESTABLISHED(this->st_state)))
+ {
+ struct state *old_cur_state
+ = cur_state == this? NULL : cur_state;
+#ifdef DEBUG
+ lset_t old_cur_debugging = cur_debugging;
+#endif
+
+ set_cur_state(this);
+ plog("deleting state (%s)"
+ , enum_show(&state_names, this->st_state));
+ delete_state(this);
+ cur_state = old_cur_state;
+#ifdef DEBUG
+ cur_debugging = old_cur_debugging;
+#endif
+ }
+ }
+ }
+ }
+
+ sr = &c->spd;
+ while (sr != NULL)
+ {
+ passert(sr->eroute_owner == SOS_NOBODY);
+ passert(sr->routing != RT_ROUTED_TUNNEL);
+ sr = sr->next;
+ }
+
+ if (ck == CK_INSTANCE)
+ {
+ c->kind = ck;
+ delete_connection(c, relations);
+ }
+}
+
+/* Walk through the state table, and delete each state whose phase 1 (IKE)
+ * peer is among those given.
+ */
+void
+delete_states_by_peer(ip_address *peer)
+{
+ char peerstr[ADDRTOT_BUF];
+ int i;
+
+ addrtot(peer, 0, peerstr, sizeof(peerstr));
+
+ /* For each hash chain... */
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ /* For each state in the hash chain... */
+ for (st = statetable[i]; st != NULL; )
+ {
+ struct state *this = st;
+ struct spd_route *sr;
+ struct connection *c = this->st_connection;
+
+ st = st->st_hashchain_next; /* before this is deleted */
+
+ /* ??? Is it not the case that the peer is the same for all spds? */
+ for (sr = &c->spd; sr != NULL; sr = sr->next)
+ {
+ if (sameaddr(&sr->that.host_addr, peer))
+ {
+ plog("peer %s for connection %s deleting - claimed to have crashed"
+ , peerstr
+ , c->name);
+ delete_states_by_connection(c, TRUE);
+ break; /* can only delete it once */
+ }
+ }
+ }
+ }
+}
+
+/* Duplicate a Phase 1 state object, to create a Phase 2 object.
+ * Caller must schedule an event for this object so that it doesn't leak.
+ * Caller must insert_state().
+ */
+struct state *
+duplicate_state(struct state *st)
+{
+ struct state *nst;
+
+ DBG(DBG_CONTROL, DBG_log("duplicating state object #%lu",
+ st->st_serialno));
+
+ /* record use of the Phase 1 state */
+ st->st_outbound_count++;
+ st->st_outbound_time = now();
+
+ nst = new_state();
+
+ memcpy(nst->st_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(nst->st_rcookie, st->st_rcookie, COOKIE_SIZE);
+
+ nst->st_connection = st->st_connection;
+ nst->st_doi = st->st_doi;
+ nst->st_situation = st->st_situation;
+ nst->st_clonedfrom = st->st_serialno;
+ nst->st_oakley = st->st_oakley;
+ nst->st_modecfg = st->st_modecfg;
+
+# define clone_chunk(ch, name) \
+ clonetochunk(nst->ch, st->ch.ptr, st->ch.len, name)
+
+ clone_chunk(st_skeyid_d, "st_skeyid_d in duplicate_state");
+ clone_chunk(st_skeyid_a, "st_skeyid_a in duplicate_state");
+ clone_chunk(st_skeyid_e, "st_skeyid_e in duplicate_state");
+ clone_chunk(st_enc_key, "st_enc_key in duplicate_state");
+
+# undef clone_chunk
+
+ return nst;
+}
+
+#if 1
+void for_each_state(void *(f)(struct state *, void *data), void *data)
+{
+ struct state *st, *ocs = cur_state;
+ int i;
+ for (i=0; i<STATE_TABLE_SIZE; i++) {
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) {
+ set_cur_state(st);
+ f(st, data);
+ }
+ }
+ cur_state = ocs;
+}
+#endif
+
+/*
+ * Find a state object.
+ */
+struct state *
+find_state(const u_char *icookie
+, const u_char *rcookie
+, const ip_address *peer
+, msgid_t /*network order*/ msgid)
+{
+ struct state *st = *state_hash(icookie, rcookie, peer);
+
+ while (st != (struct state *) NULL)
+ if (sameaddr(peer, &st->st_connection->spd.that.host_addr)
+ && memcmp(icookie, st->st_icookie, COOKIE_SIZE) == 0
+ && memcmp(rcookie, st->st_rcookie, COOKIE_SIZE) == 0
+ && msgid == st->st_msgid)
+ break;
+ else
+ st = st->st_hashchain_next;
+
+ DBG(DBG_CONTROL,
+ if (st == NULL)
+ DBG_log("state object not found");
+ else
+ DBG_log("state object #%lu found, in %s"
+ , st->st_serialno
+ , enum_show(&state_names, st->st_state)));
+
+ return st;
+}
+
+/* Find the state that sent a packet
+ * ??? this could be expensive -- it should be rate-limited to avoid DoS
+ */
+struct state *
+find_sender(size_t packet_len, u_char *packet)
+{
+ int i;
+ struct state *st;
+
+ if (packet_len >= sizeof(struct isakmp_hdr))
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ if (st->st_tpacket.ptr != NULL
+ && st->st_tpacket.len == packet_len
+ && memcmp(st->st_tpacket.ptr, packet, packet_len) == 0)
+ return st;
+
+ return NULL;
+}
+
+struct state *
+find_phase2_state_to_delete(const struct state *p1st
+, u_int8_t protoid
+, ipsec_spi_t spi
+, bool *bogus)
+{
+ struct state *st;
+ int i;
+
+ *bogus = FALSE;
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)
+ && p1st->st_connection->host_pair == st->st_connection->host_pair
+ && same_peer_ids(p1st->st_connection, st->st_connection, NULL))
+ {
+ struct ipsec_proto_info *pr = protoid == PROTO_IPSEC_AH
+ ? &st->st_ah : &st->st_esp;
+
+ if (pr->present)
+ {
+ if (pr->attrs.spi == spi)
+ return st;
+ if (pr->our_spi == spi)
+ *bogus = TRUE;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/* Find newest Phase 1 negotiation state object for suitable for connection c
+ */
+struct state *
+find_phase1_state(const struct connection *c, lset_t ok_states)
+{
+ struct state
+ *st,
+ *best = NULL;
+ int i;
+
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ if (LHAS(ok_states, st->st_state)
+ && c->host_pair == st->st_connection->host_pair
+ && same_peer_ids(c, st->st_connection, NULL)
+ && (best == NULL || best->st_serialno < st->st_serialno))
+ best = st;
+
+ return best;
+}
+
+void
+state_eroute_usage(ip_subnet *ours, ip_subnet *his
+, unsigned long count, time_t nw)
+{
+ struct state *st;
+ int i;
+
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ struct connection *c = st->st_connection;
+
+ /* XXX spd-enum */
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)
+ && c->spd.eroute_owner == st->st_serialno
+ && c->spd.routing == RT_ROUTED_TUNNEL
+ && samesubnet(&c->spd.this.client, ours)
+ && samesubnet(&c->spd.that.client, his))
+ {
+ if (st->st_outbound_count != count)
+ {
+ st->st_outbound_count = count;
+ st->st_outbound_time = nw;
+ }
+ return;
+ }
+ }
+ }
+ DBG(DBG_CONTROL,
+ {
+ char ourst[SUBNETTOT_BUF];
+ char hist[SUBNETTOT_BUF];
+
+ subnettot(ours, 0, ourst, sizeof(ourst));
+ subnettot(his, 0, hist, sizeof(hist));
+ DBG_log("unknown tunnel eroute %s -> %s found in scan"
+ , ourst, hist);
+ });
+}
+
+void fmt_state(struct state *st, time_t n
+, char *state_buf, size_t state_buf_len
+, char *state_buf2, size_t state_buf2_len)
+{
+ /* what the heck is interesting about a state? */
+ const struct connection *c = st->st_connection;
+
+ long delta = st->st_event->ev_time >= n
+ ? (long)(st->st_event->ev_time - n)
+ : -(long)(n - st->st_event->ev_time);
+
+ char inst[CONN_INST_BUF];
+ const char *np1 = c->newest_isakmp_sa == st->st_serialno
+ ? "; newest ISAKMP" : "";
+ const char *np2 = c->newest_ipsec_sa == st->st_serialno
+ ? "; newest IPSEC" : "";
+ /* XXX spd-enum */
+ const char *eo = c->spd.eroute_owner == st->st_serialno
+ ? "; eroute owner" : "";
+
+ passert(st->st_event != 0);
+
+ fmt_conn_instance(c, inst);
+
+ snprintf(state_buf, state_buf_len
+ , "#%lu: \"%s\"%s %s (%s); %s in %lds%s%s%s"
+ , st->st_serialno
+ , c->name, inst
+ , enum_name(&state_names, st->st_state)
+ , state_story[st->st_state - STATE_MAIN_R0]
+ , enum_name(&timer_event_names, st->st_event->ev_type)
+ , delta
+ , np1, np2, eo);
+
+ /* print out SPIs if SAs are established */
+ if (state_buf2_len != 0)
+ state_buf2[0] = '\0'; /* default to empty */
+ if (IS_IPSEC_SA_ESTABLISHED(st->st_state))
+ {
+
+ bool tunnel;
+ char buf[SATOT_BUF*6 + 2*20 + 1];
+ const char *p_end = buf + sizeof(buf);
+ char *p = buf;
+
+# define add_said(adst, aspi, aproto) { \
+ ip_said s; \
+ \
+ initsaid(adst, aspi, aproto, &s); \
+ if (p < p_end - 1) \
+ { \
+ *p++ = ' '; \
+ p += satot(&s, 0, p, p_end - p) - 1; \
+ } \
+ }
+
+# define add_sa_info(st, inbound) { \
+ u_int bytes; \
+ time_t use_time; \
+ \
+ if (get_sa_info(st, inbound, &bytes, &use_time)) \
+ { \
+ p += snprintf(p, p_end - p, " (%'u bytes", bytes); \
+ if (bytes > 0 && use_time != UNDEFINED_TIME) \
+ p += snprintf(p, p_end - p, ", %ds ago", (int)(now - use_time)); \
+ p += snprintf(p, p_end - p, ")"); \
+ } \
+ }
+
+ *p = '\0';
+ if (st->st_ah.present)
+ {
+ add_said(&c->spd.that.host_addr, st->st_ah.attrs.spi, SA_AH);
+ add_said(&c->spd.this.host_addr, st->st_ah.our_spi, SA_AH);
+ }
+ if (st->st_esp.present)
+ {
+ time_t now = time(NULL);
+
+ add_said(&c->spd.that.host_addr, st->st_esp.attrs.spi, SA_ESP);
+ add_sa_info(st, FALSE);
+ add_said(&c->spd.this.host_addr, st->st_esp.our_spi, SA_ESP);
+ add_sa_info(st, TRUE);
+ }
+ if (st->st_ipcomp.present)
+ {
+ add_said(&c->spd.that.host_addr, st->st_ipcomp.attrs.spi, SA_COMP);
+ add_said(&c->spd.this.host_addr, st->st_ipcomp.our_spi, SA_COMP);
+ }
+#ifdef KLIPS
+ tunnel = st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL
+ || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL;
+ p += snprintf(p, p_end - p, "; %s", tunnel? "tunnel":"transport");
+#endif
+
+ snprintf(state_buf2, state_buf2_len
+ , "#%lu: \"%s\"%s%s"
+ , st->st_serialno
+ , c->name, inst
+ , buf);
+
+# undef add_said
+# undef add_sa_info
+ }
+}
+
+/*
+ * sorting logic is:
+ *
+ * name
+ * type
+ * instance#
+ * isakmp_sa (XXX probably wrong)
+ *
+ */
+static int
+state_compare(const void *a, const void *b)
+{
+ const struct state *sap = *(const struct state *const *)a;
+ struct connection *ca = sap->st_connection;
+ const struct state *sbp = *(const struct state *const *)b;
+ struct connection *cb = sbp->st_connection;
+
+ /* DBG_log("comparing %s to %s", ca->name, cb->name); */
+
+ return connection_compare(ca, cb);
+}
+
+void
+show_states_status(const char *name)
+{
+ time_t n = now();
+ int i;
+ char state_buf[LOG_WIDTH];
+ char state_buf2[LOG_WIDTH];
+ int count;
+ struct state **array;
+
+ /* make count of states */
+ count = 0;
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ if (name == NULL || streq(name, st->st_connection->name))
+ count++;
+ }
+ }
+
+ /* build the array */
+ array = alloc_bytes(sizeof(struct state *)*count, "state array");
+ count = 0;
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ if (name == NULL || streq(name, st->st_connection->name))
+ array[count++]=st;
+ }
+ }
+
+ /* sort it! */
+ qsort(array, count, sizeof(struct state *), state_compare);
+
+ /* now print sorted results */
+ for (i = 0; i < count; i++)
+ {
+ struct state *st;
+
+ st = array[i];
+
+ fmt_state(st, n, state_buf, sizeof(state_buf)
+ , state_buf2, sizeof(state_buf2));
+ whack_log(RC_COMMENT, state_buf);
+ if (state_buf2[0] != '\0')
+ whack_log(RC_COMMENT, state_buf2);
+
+ /* show any associated pending Phase 2s */
+ if (IS_PHASE1(st->st_state))
+ show_pending_phase2(st->st_connection->host_pair, st);
+ }
+
+ /* free the array */
+ pfree(array);
+}
+
+/* Given that we've used up a range of unused CPI's,
+ * search for a new range of currently unused ones.
+ * Note: this is very expensive when not trivial!
+ * If we can't find one easily, choose 0 (a bad SPI,
+ * no matter what order) indicating failure.
+ */
+void
+find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi)
+{
+ int tries = 0;
+ cpi_t base = *latest_cpi;
+ cpi_t closest;
+ int i;
+
+startover:
+ closest = ~0; /* not close at all */
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *st;
+
+ for (st = statetable[i]; st != NULL; st = st->st_hashchain_next)
+ {
+ if (st->st_ipcomp.present)
+ {
+ cpi_t c = ntohl(st->st_ipcomp.our_spi) - base;
+
+ if (c < closest)
+ {
+ if (c == 0)
+ {
+ /* oops: next spot is occupied; start over */
+ if (++tries == 20)
+ {
+ /* FAILURE */
+ *latest_cpi = *first_busy_cpi = 0;
+ return;
+ }
+ base++;
+ if (base > IPCOMP_LAST_NEGOTIATED)
+ base = IPCOMP_FIRST_NEGOTIATED;
+ goto startover; /* really a tail call */
+ }
+ closest = c;
+ }
+ }
+ }
+ }
+ *latest_cpi = base; /* base is first in next free range */
+ *first_busy_cpi = closest + base; /* and this is the roof */
+}
+
+/* Muck with high-order 16 bits of this SPI in order to make
+ * the corresponding SAID unique.
+ * Its low-order 16 bits hold a well-known IPCOMP CPI.
+ * Oh, and remember that SPIs are stored in network order.
+ * Kludge!!! So I name it with the non-English word "uniquify".
+ * If we can't find one easily, return 0 (a bad SPI,
+ * no matter what order) indicating failure.
+ */
+ipsec_spi_t
+uniquify_his_cpi(ipsec_spi_t cpi, struct state *st)
+{
+ int tries = 0;
+ int i;
+
+startover:
+
+ /* network order makes first two bytes our target */
+ get_rnd_bytes((u_char *)&cpi, 2);
+
+ /* Make sure that the result is unique.
+ * Hard work. If there is no unique value, we'll loop forever!
+ */
+ for (i = 0; i < STATE_TABLE_SIZE; i++)
+ {
+ struct state *s;
+
+ for (s = statetable[i]; s != NULL; s = s->st_hashchain_next)
+ {
+ if (s->st_ipcomp.present
+ && sameaddr(&s->st_connection->spd.that.host_addr
+ , &st->st_connection->spd.that.host_addr)
+ && cpi == s->st_ipcomp.attrs.spi)
+ {
+ if (++tries == 20)
+ return 0; /* FAILURE */
+ goto startover;
+ }
+ }
+ }
+ return cpi;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * End:
+ */
diff --git a/programs/pluto/state.h b/programs/pluto/state.h
new file mode 100644
index 000000000..2f30d77f1
--- /dev/null
+++ b/programs/pluto/state.h
@@ -0,0 +1,269 @@
+/* state and event objects
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: state.h,v 1.11 2006/03/08 22:12:37 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <time.h>
+#include <gmp.h> /* GNU MP library */
+
+#include "connections.h"
+
+/* Message ID mechanism.
+ *
+ * A Message ID is contained in each IKE message header.
+ * For Phase 1 exchanges (Main and Aggressive), it will be zero.
+ * For other exchanges, which must be under the protection of an
+ * ISAKMP SA, the Message ID must be unique within that ISAKMP SA.
+ * Effectively, this labels the message as belonging to a particular
+ * exchange.
+ *
+ * RFC2408 "ISAKMP" 3.1 "ISAKMP Header Format" (near end) states that
+ * the Message ID must be unique. We interpret this to be "unique within
+ * one ISAKMP SA".
+ *
+ * BTW, we feel this uniqueness allows rekeying to be somewhat simpler
+ * than specified by draft-jenkins-ipsec-rekeying-06.txt.
+ */
+
+typedef u_int32_t msgid_t; /* Network order! */
+#define MAINMODE_MSGID ((msgid_t) 0)
+
+struct state; /* forward declaration of tag */
+extern bool reserve_msgid(struct state *isakmp_sa, msgid_t msgid);
+extern msgid_t generate_msgid(struct state *isakmp_sa);
+
+
+/* Oakley (Phase 1 / Main Mode) transform and attributes
+ * This is a flattened/decoded version of what is represented
+ * in the Transaction Payload.
+ * Names are chosen to match corresponding names in state.
+ */
+struct oakley_trans_attrs {
+ u_int16_t encrypt; /* Encryption algorithm */
+ u_int16_t enckeylen; /* encryption key len (bits) */
+ const struct encrypt_desc *encrypter; /* package of encryption routines */
+ u_int16_t hash; /* Hash algorithm */
+ const struct hash_desc *hasher; /* package of hashing routines */
+ u_int16_t auth; /* Authentication method */
+ const struct oakley_group_desc *group; /* Oakley group */
+ time_t life_seconds; /* When this SA expires (seconds) */
+ u_int32_t life_kilobytes; /* When this SA is exhausted (kilobytes) */
+#if 0 /* not yet */
+ u_int16_t prf; /* Pseudo Random Function */
+#endif
+};
+
+/* IPsec (Phase 2 / Quick Mode) transform and attributes
+ * This is a flattened/decoded version of what is represented
+ * by a Transaction Payload. There may be one for AH, one
+ * for ESP, and a funny one for IPCOMP.
+ */
+struct ipsec_trans_attrs {
+ u_int8_t transid; /* transform id */
+ ipsec_spi_t spi; /* his SPI */
+ time_t life_seconds; /* When this SA expires */
+ u_int32_t life_kilobytes; /* When this SA expires */
+ u_int16_t encapsulation;
+ u_int16_t auth;
+ u_int16_t key_len;
+ u_int16_t key_rounds;
+#if 0 /* not implemented yet */
+ u_int16_t cmprs_dict_sz;
+ u_int32_t cmprs_alg;
+#endif
+};
+
+/* IPsec per protocol state information */
+struct ipsec_proto_info {
+ bool present; /* was this transform specified? */
+ struct ipsec_trans_attrs attrs;
+ ipsec_spi_t our_spi;
+ u_int16_t keymat_len; /* same for both */
+ u_char *our_keymat;
+ u_char *peer_keymat;
+};
+
+/* state object: record the state of a (possibly nascent) SA
+ *
+ * Invariants (violated only during short transitions):
+ * - each state object will be in statetable exactly once.
+ * - each state object will always have a pending event.
+ * This prevents leaks.
+ */
+struct state
+{
+ so_serial_t st_serialno; /* serial number (for seniority) */
+ so_serial_t st_clonedfrom; /* serial number of parent */
+
+ struct connection *st_connection; /* connection for this SA */
+
+ int st_whack_sock; /* fd for our Whack TCP socket.
+ * Single copy: close when freeing struct.
+ */
+
+ struct msg_digest *st_suspended_md; /* suspended state-transition */
+
+ struct oakley_trans_attrs st_oakley;
+
+ struct ipsec_proto_info st_ah;
+ struct ipsec_proto_info st_esp;
+ struct ipsec_proto_info st_ipcomp;
+#ifdef KLIPS
+ ipsec_spi_t st_tunnel_in_spi; /* KLUDGE */
+ ipsec_spi_t st_tunnel_out_spi; /* KLUDGE */
+#endif
+
+ const struct oakley_group_desc *st_pfs_group; /* group for Phase 2 PFS */
+
+ u_int32_t st_doi; /* Domain of Interpretation */
+ u_int32_t st_situation;
+
+ lset_t st_policy; /* policy for IPsec SA */
+
+ msgid_t st_msgid; /* MSG-ID from header. Network Order! */
+
+ /* only for a state representing an ISAKMP SA */
+ struct msgid_list *st_used_msgids; /* used-up msgids */
+
+/* symmetric stuff */
+
+ /* initiator stuff */
+ chunk_t st_gi; /* Initiator public value */
+ u_int8_t st_icookie[COOKIE_SIZE];/* Initiator Cookie */
+ chunk_t st_ni; /* Ni nonce */
+
+ /* responder stuff */
+ chunk_t st_gr; /* Responder public value */
+ u_int8_t st_rcookie[COOKIE_SIZE];/* Responder Cookie */
+ chunk_t st_nr; /* Nr nonce */
+
+
+ /* my stuff */
+
+ chunk_t st_tpacket; /* Transmitted packet */
+
+ /* Phase 2 ID payload info about my user */
+ u_int8_t st_myuserprotoid; /* IDcx.protoid */
+ u_int16_t st_myuserport;
+
+ /* his stuff */
+
+ chunk_t st_rpacket; /* Received packet */
+
+ /* Phase 2 ID payload info about peer's user */
+ u_int8_t st_peeruserprotoid; /* IDcx.protoid */
+ u_int16_t st_peeruserport;
+
+/* end of symmetric stuff */
+
+ u_int8_t st_sec_in_use; /* bool: does st_sec hold a value */
+ MP_INT st_sec; /* Our local secret value */
+
+ chunk_t st_shared; /* Derived shared secret
+ * Note: during Quick Mode,
+ * presence indicates PFS
+ * selected.
+ */
+
+ /* In a Phase 1 state, preserve peer's public key after authentication */
+ struct pubkey *st_peer_pubkey;
+
+ enum state_kind st_state; /* State of exchange */
+ u_int8_t st_retransmit; /* Number of retransmits */
+ unsigned long st_try; /* number of times rekeying attempted */
+ /* 0 means the only time */
+ time_t st_margin; /* life after EVENT_SA_REPLACE */
+ unsigned long st_outbound_count; /* traffic through eroute */
+ time_t st_outbound_time; /* time of last change to st_outbound_count */
+ chunk_t st_p1isa; /* Phase 1 initiator SA (Payload) for HASH */
+ chunk_t st_skeyid; /* Key material */
+ chunk_t st_skeyid_d; /* KM for non-ISAKMP key derivation */
+ chunk_t st_skeyid_a; /* KM for ISAKMP authentication */
+ chunk_t st_skeyid_e; /* KM for ISAKMP encryption */
+ u_char st_iv[MAX_DIGEST_LEN]; /* IV for encryption */
+ u_char st_new_iv[MAX_DIGEST_LEN];
+ u_char st_ph1_iv[MAX_DIGEST_LEN]; /* IV at end if phase 1 */
+ unsigned int st_iv_len;
+ unsigned int st_new_iv_len;
+ unsigned int st_ph1_iv_len;
+
+ chunk_t st_enc_key; /* Oakley Encryption key */
+
+ struct event *st_event; /* backpointer for certain events */
+ struct state *st_hashchain_next; /* Next in list */
+ struct state *st_hashchain_prev; /* Previous in list */
+
+ struct {
+ bool vars_set;
+ bool started;
+ } st_modecfg;
+
+#ifdef NAT_TRAVERSAL
+ u_int32_t nat_traversal;
+ ip_address nat_oa;
+#endif
+
+ /* RFC 3706 Dead Peer Detection */
+ bool st_dpd; /* Peer supports DPD */
+ time_t st_last_dpd; /* Time of last DPD transmit */
+ u_int32_t st_dpd_seqno; /* Next R_U_THERE to send */
+ u_int32_t st_dpd_expectseqno; /* Next R_U_THERE_ACK to receive */
+ u_int32_t st_dpd_peerseqno; /* global variables */
+ struct event *st_dpd_event; /* backpointer for DPD events */
+
+ u_int32_t st_seen_vendorid; /* Bit field about recognized Vendor ID */
+};
+
+/* global variables */
+
+extern u_int16_t pluto_port; /* Pluto's port */
+
+extern bool states_use_connection(struct connection *c);
+
+/* state functions */
+
+extern struct state *new_state(void);
+extern void init_states(void);
+extern void insert_state(struct state *st);
+extern void unhash_state(struct state *st);
+extern void release_whack(struct state *st);
+extern void state_eroute_usage(ip_subnet *ours, ip_subnet *his
+ , unsigned long count, time_t nw);
+extern void delete_state(struct state *st);
+extern void delete_states_by_connection(struct connection *c, bool relations);
+
+extern struct state
+ *duplicate_state(struct state *st),
+ *find_state(const u_char *icookie
+ , const u_char *rcookie
+ , const ip_address *peer
+ , msgid_t msgid),
+ *state_with_serialno(so_serial_t sn),
+ *find_phase2_state_to_delete(const struct state *p1st, u_int8_t protoid
+ , ipsec_spi_t spi, bool *bogus),
+ *find_phase1_state(const struct connection *c, lset_t ok_states),
+ *find_sender(size_t packet_len, u_char *packet);
+
+extern void show_states_status(const char *name);
+extern void for_each_state(void *(f)(struct state *, void *data), void *data);
+extern void find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi);
+extern ipsec_spi_t uniquify_his_cpi(ipsec_spi_t cpi, struct state *st);
+extern void fmt_state(struct state *st, time_t n
+ , char *state_buf, size_t state_buf_len
+ , char *state_buf2, size_t state_buf_len2);
+extern void delete_states_by_peer(ip_address *peer);
diff --git a/programs/pluto/timer.c b/programs/pluto/timer.c
new file mode 100644
index 000000000..4d9ef8fab
--- /dev/null
+++ b/programs/pluto/timer.c
@@ -0,0 +1,537 @@
+/* timer event handling
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: timer.c,v 1.5 2004/09/17 21:36:57 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/queue.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "connections.h"
+#include "state.h"
+#include "demux.h"
+#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "kernel.h"
+#include "server.h"
+#include "log.h"
+#include "rnd.h"
+#include "timer.h"
+#include "whack.h"
+
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
+/* monotonic version of time(3) */
+time_t
+now(void)
+{
+ static time_t delta = 0
+ , last_time = 0;
+ time_t n = time((time_t)NULL);
+
+ passert(n != (time_t)-1);
+ if (last_time > n)
+ {
+ plog("time moved backwards %ld seconds", (long)(last_time - n));
+ delta += last_time - n;
+ }
+ last_time = n;
+ return n + delta;
+}
+
+/* This file has the event handling routines. Events are
+ * kept as a linked list of event structures. These structures
+ * have information like event type, expiration time and a pointer
+ * to event specific data (for example, to a state structure).
+ */
+
+static struct event *evlist = (struct event *) NULL;
+
+/*
+ * This routine places an event in the event list.
+ */
+void
+event_schedule(enum event_type type, time_t tm, struct state *st)
+{
+ struct event *ev = alloc_thing(struct event, "struct event in event_schedule()");
+
+ ev->ev_type = type;
+ ev->ev_time = tm + now();
+ ev->ev_state = st;
+
+ /* If the event is associated with a state, put a backpointer to the
+ * event in the state object, so we can find and delete the event
+ * if we need to (for example, if we receive a reply).
+ */
+ if (st != NULL)
+ {
+ if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT)
+ {
+ passert(st->st_dpd_event == NULL);
+ st->st_dpd_event = ev;
+ }
+ else
+ {
+ passert(st->st_event == NULL);
+ st->st_event = ev;
+ }
+ }
+
+ DBG(DBG_CONTROL,
+ if (st == NULL)
+ DBG_log("inserting event %s, timeout in %lu seconds"
+ , enum_show(&timer_event_names, type), (unsigned long)tm);
+ else
+ DBG_log("inserting event %s, timeout in %lu seconds for #%lu"
+ , enum_show(&timer_event_names, type), (unsigned long)tm
+ , ev->ev_state->st_serialno));
+
+ if (evlist == (struct event *) NULL
+ || evlist->ev_time >= ev->ev_time)
+ {
+ ev->ev_next = evlist;
+ evlist = ev;
+ }
+ else
+ {
+ struct event *evt;
+
+ for (evt = evlist; evt->ev_next != NULL; evt = evt->ev_next)
+ if (evt->ev_next->ev_time >= ev->ev_time)
+ break;
+
+#ifdef NEVER /* this seems to be overkill */
+ DBG(DBG_CONTROL,
+ if (evt->ev_state == NULL)
+ DBG_log("event added after event %s"
+ , enum_show(&timer_event_names, evt->ev_type));
+ else
+ DBG_log("event added after event %s for #%lu"
+ , enum_show(&timer_event_names, evt->ev_type)
+ , evt->ev_state->st_serialno));
+#endif /* NEVER */
+
+ ev->ev_next = evt->ev_next;
+ evt->ev_next = ev;
+ }
+}
+
+/*
+ * Handle the first event on the list.
+ */
+void
+handle_timer_event(void)
+{
+ time_t tm;
+ struct event *ev = evlist;
+ int type;
+ struct state *st;
+ struct connection *c = NULL;
+ ip_address peer;
+
+ if (ev == (struct event *) NULL) /* Just paranoid */
+ {
+ DBG(DBG_CONTROL, DBG_log("empty event list, yet we're called"));
+ return;
+ }
+
+ type = ev->ev_type;
+ st = ev->ev_state;
+
+ tm = now();
+
+ if (tm < ev->ev_time)
+ {
+ DBG(DBG_CONTROL, DBG_log("called while no event expired (%lu/%lu, %s)"
+ , (unsigned long)tm, (unsigned long)ev->ev_time
+ , enum_show(&timer_event_names, type)));
+
+ /* This will happen if the most close-to-expire event was
+ * a retransmission or cleanup, and we received a packet
+ * at the same time as the event expired. Due to the processing
+ * order in call_server(), the packet processing will happen first,
+ * and the event will be removed.
+ */
+ return;
+ }
+
+ evlist = evlist->ev_next; /* Ok, we'll handle this event */
+
+ DBG(DBG_CONTROL,
+ if (evlist != (struct event *) NULL)
+ DBG_log("event after this is %s in %ld seconds"
+ , enum_show(&timer_event_names, evlist->ev_type)
+ , (long) (evlist->ev_time - tm)));
+
+ /* for state-associated events, pick up the state pointer
+ * and remove the backpointer from the state object.
+ * We'll eventually either schedule a new event, or delete the state.
+ */
+ passert(GLOBALS_ARE_RESET());
+ if (st != NULL)
+ {
+ c = st->st_connection;
+ if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT)
+ {
+ passert(st->st_dpd_event == ev);
+ st->st_dpd_event = NULL;
+ }
+ else
+ {
+ passert(st->st_event == ev);
+ st->st_event = NULL;
+ }
+ peer = c->spd.that.host_addr;
+ set_cur_state(st);
+ }
+
+ switch (type)
+ {
+ case EVENT_REINIT_SECRET:
+ passert(st == NULL);
+ DBG(DBG_CONTROL, DBG_log("event EVENT_REINIT_SECRET handled"));
+ init_secret();
+ break;
+
+#ifdef KLIPS
+ case EVENT_SHUNT_SCAN:
+ passert(st == NULL);
+ scan_proc_shunts();
+ break;
+#endif
+
+ case EVENT_LOG_DAILY:
+ daily_log_event();
+ break;
+
+ case EVENT_RETRANSMIT:
+ /* Time to retransmit, or give up.
+ *
+ * Generally, we'll only try to send the message
+ * MAXIMUM_RETRANSMISSIONS times. Each time we double
+ * our patience.
+ *
+ * As a special case, if this is the first initiating message
+ * of a Main Mode exchange, and we have been directed to try
+ * forever, we'll extend the number of retransmissions to
+ * MAXIMUM_RETRANSMISSIONS_INITIAL times, with all these
+ * extended attempts having the same patience. The intention
+ * is to reduce the bother when nobody is home.
+ */
+ {
+ time_t delay = 0;
+
+ DBG(DBG_CONTROL, DBG_log(
+ "handling event EVENT_RETRANSMIT for %s \"%s\" #%lu"
+ , ip_str(&peer), c->name, st->st_serialno));
+
+ if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS)
+ delay = EVENT_RETRANSMIT_DELAY_0 << (st->st_retransmit + 1);
+ else if (st->st_state == STATE_MAIN_I1
+ && c->sa_keying_tries == 0
+ && st->st_retransmit < MAXIMUM_RETRANSMISSIONS_INITIAL)
+ delay = EVENT_RETRANSMIT_DELAY_0 << MAXIMUM_RETRANSMISSIONS;
+
+ if (delay != 0)
+ {
+ st->st_retransmit++;
+ whack_log(RC_RETRANSMISSION
+ , "%s: retransmission; will wait %lus for response"
+ , enum_name(&state_names, st->st_state)
+ , (unsigned long)delay);
+ send_packet(st, "EVENT_RETRANSMIT");
+ event_schedule(EVENT_RETRANSMIT, delay, st);
+ }
+ else
+ {
+ /* check if we've tried rekeying enough times.
+ * st->st_try == 0 means that this should be the only try.
+ * c->sa_keying_tries == 0 means that there is no limit.
+ */
+ unsigned long try = st->st_try;
+ unsigned long try_limit = c->sa_keying_tries;
+ const char *details = "";
+
+ switch (st->st_state)
+ {
+ case STATE_MAIN_I3:
+ details = ". Possible authentication failure:"
+ " no acceptable response to our"
+ " first encrypted message";
+ break;
+ case STATE_MAIN_I1:
+ details = ". No response (or no acceptable response) to our"
+ " first IKE message";
+ break;
+ case STATE_QUICK_I1:
+ if (c->newest_ipsec_sa == SOS_NOBODY)
+ details = ". No acceptable response to our"
+ " first Quick Mode message:"
+ " perhaps peer likes no proposal";
+ break;
+ default:
+ break;
+ }
+ loglog(RC_NORETRANSMISSION
+ , "max number of retransmissions (%d) reached %s%s"
+ , st->st_retransmit
+ , enum_show(&state_names, st->st_state), details);
+ if (try != 0 && try != try_limit)
+ {
+ /* A lot like EVENT_SA_REPLACE, but over again.
+ * Since we know that st cannot be in use,
+ * we can delete it right away.
+ */
+ char story[80]; /* arbitrary limit */
+
+ try++;
+ snprintf(story, sizeof(story), try_limit == 0
+ ? "starting keying attempt %ld of an unlimited number"
+ : "starting keying attempt %ld of at most %ld"
+ , try, try_limit);
+
+ if (st->st_whack_sock != NULL_FD)
+ {
+ /* Release whack because the observer will get bored. */
+ loglog(RC_COMMENT, "%s, but releasing whack"
+ , story);
+ release_pending_whacks(st, story);
+ }
+ else
+ {
+ /* no whack: just log to syslog */
+ plog("%s", story);
+ }
+ ipsecdoi_replace(st, try);
+ }
+ delete_state(st);
+ }
+ }
+ break;
+
+ case EVENT_SA_REPLACE:
+ case EVENT_SA_REPLACE_IF_USED:
+ {
+ so_serial_t newest = IS_PHASE1(st->st_state)
+ ? c->newest_isakmp_sa : c->newest_ipsec_sa;
+
+ if (newest != st->st_serialno
+ && newest != SOS_NOBODY)
+ {
+ /* not very interesting: no need to replace */
+ DBG(DBG_LIFECYCLE
+ , plog("not replacing stale %s SA: #%lu will do"
+ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"
+ , newest));
+ }
+ else if (type == EVENT_SA_REPLACE_IF_USED
+ && st->st_outbound_time <= tm - c->sa_rekey_margin)
+ {
+ /* we observed no recent use: no need to replace
+ *
+ * The sampling effects mean that st_outbound_time
+ * could be up to SHUNT_SCAN_INTERVAL more recent
+ * than actual traffic because the sampler looks at change
+ * over that interval.
+ * st_outbound_time could also not yet reflect traffic
+ * in the last SHUNT_SCAN_INTERVAL.
+ * We expect that SHUNT_SCAN_INTERVAL is smaller than
+ * c->sa_rekey_margin so that the effects of this will
+ * be unimportant.
+ * This is just an optimization: correctness is not
+ * at stake.
+ *
+ * Note: we are abusing the DBG mechanism to control
+ * normal log output.
+ */
+ DBG(DBG_LIFECYCLE
+ , plog("not replacing stale %s SA: inactive for %lus"
+ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"
+ , (unsigned long)(tm - st->st_outbound_time)));
+ }
+ else
+ {
+ DBG(DBG_LIFECYCLE
+ , plog("replacing stale %s SA"
+ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"));
+ ipsecdoi_replace(st, 1);
+ }
+ delete_dpd_event(st);
+ event_schedule(EVENT_SA_EXPIRE, st->st_margin, st);
+ }
+ break;
+
+ case EVENT_SA_EXPIRE:
+ {
+ const char *satype;
+ so_serial_t latest;
+
+ if (IS_PHASE1(st->st_state))
+ {
+ satype = "ISAKMP";
+ latest = c->newest_isakmp_sa;
+ }
+ else
+ {
+ satype = "IPsec";
+ latest = c->newest_ipsec_sa;
+ }
+
+ if (st->st_serialno != latest)
+ {
+ /* not very interesting: already superseded */
+ DBG(DBG_LIFECYCLE
+ , plog("%s SA expired (superseded by #%lu)"
+ , satype, latest));
+ }
+ else
+ {
+ plog("%s SA expired (%s)", satype
+ , (c->policy & POLICY_DONT_REKEY)
+ ? "--dontrekey"
+ : "LATEST!"
+ );
+ }
+ }
+ /* FALLTHROUGH */
+ case EVENT_SO_DISCARD:
+ /* Delete this state object. It must be in the hash table. */
+ delete_state(st);
+ break;
+
+ case EVENT_DPD:
+ dpd_outI(st);
+ break;
+ case EVENT_DPD_TIMEOUT:
+ dpd_timeout(st);
+ break;
+#ifdef NAT_TRAVERSAL
+ case EVENT_NAT_T_KEEPALIVE:
+ nat_traversal_ka_event();
+ break;
+#endif
+ default:
+ loglog(RC_LOG_SERIOUS, "INTERNAL ERROR: ignoring unknown expiring event %s"
+ , enum_show(&timer_event_names, type));
+ }
+
+ pfree(ev);
+ reset_cur_state();
+}
+
+/*
+ * Return the time until the next event in the queue
+ * expires (never negative), or -1 if no jobs in queue.
+ */
+long
+next_event(void)
+{
+ time_t tm;
+
+ if (evlist == (struct event *) NULL)
+ return -1;
+
+ tm = now();
+
+ DBG(DBG_CONTROL,
+ if (evlist->ev_state == NULL)
+ DBG_log("next event %s in %ld seconds"
+ , enum_show(&timer_event_names, evlist->ev_type)
+ , (long)evlist->ev_time - (long)tm);
+ else
+ DBG_log("next event %s in %ld seconds for #%lu"
+ , enum_show(&timer_event_names, evlist->ev_type)
+ , (long)evlist->ev_time - (long)tm
+ , evlist->ev_state->st_serialno));
+
+ if (evlist->ev_time - tm <= 0)
+ return 0;
+ else
+ return evlist->ev_time - tm;
+}
+
+/*
+ * Delete an event.
+ */
+void
+delete_event(struct state *st)
+{
+ if (st->st_event != (struct event *) NULL)
+ {
+ struct event **ev;
+
+ for (ev = &evlist; ; ev = &(*ev)->ev_next)
+ {
+ if (*ev == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found",
+ enum_show(&timer_event_names, st->st_event->ev_type)));
+ break;
+ }
+ if ((*ev) == st->st_event)
+ {
+ *ev = (*ev)->ev_next;
+
+ if (st->st_event->ev_type == EVENT_RETRANSMIT)
+ st->st_retransmit = 0;
+ pfree(st->st_event);
+ st->st_event = (struct event *) NULL;
+
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Delete a DPD event.
+ */
+void
+delete_dpd_event(struct state *st)
+{
+ if (st->st_dpd_event != (struct event *) NULL)
+ {
+ struct event **ev;
+
+ for (ev = &evlist; ; ev = &(*ev)->ev_next)
+ {
+ if (*ev == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found",
+ enum_show(&timer_event_names, st->st_dpd_event->ev_type)));
+ break;
+ }
+ if ((*ev) == st->st_dpd_event)
+ {
+ *ev = (*ev)->ev_next;
+ pfree(st->st_dpd_event);
+ st->st_dpd_event = (struct event *) NULL;
+ break;
+ }
+ }
+ }
+}
+
+
diff --git a/programs/pluto/timer.h b/programs/pluto/timer.h
new file mode 100644
index 000000000..92464192c
--- /dev/null
+++ b/programs/pluto/timer.h
@@ -0,0 +1,34 @@
+/* timing machinery
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: timer.h,v 1.2 2004/07/29 18:33:45 as Exp $
+ */
+
+extern time_t now(void); /* careful version of time(2) */
+
+struct state; /* forward declaration */
+
+struct event
+{
+ time_t ev_time;
+ int ev_type; /* Event type */
+ struct state *ev_state; /* Pointer to relevant state (if any) */
+ struct event *ev_next; /* Pointer to next event */
+};
+
+extern void event_schedule(enum event_type type, time_t tm, struct state *st);
+extern void handle_timer_event(void);
+extern long next_event(void);
+extern void delete_event(struct state *st);
+extern void delete_dpd_event(struct state *st);
+extern void daily_log_event(void);
diff --git a/programs/pluto/vendor.c b/programs/pluto/vendor.c
new file mode 100644
index 000000000..51931c239
--- /dev/null
+++ b/programs/pluto/vendor.c
@@ -0,0 +1,493 @@
+/* ISAKMP VendorID
+ * Copyright (C) 2002-2005 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: vendor.c,v 1.35 2006/04/12 16:44:28 as Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/queue.h>
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "md5.h"
+#include "connections.h"
+#include "packet.h"
+#include "demux.h"
+#include "whack.h"
+#include "vendor.h"
+#include "kernel.h"
+
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
+/**
+ * Unknown/Special VID:
+ *
+ * SafeNet SoftRemote 8.0.0:
+ * 47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310382e302e3020284275696c6420313029000000
+ * >> 382e302e3020284275696c6420313029 = '8.0.0 (Build 10)'
+ * da8e937880010000
+ *
+ * SafeNet SoftRemote 9.0.1
+ * 47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310392e302e3120284275696c6420313229000000
+ * >> 392e302e3120284275696c6420313229 = '9.0.1 (Build 12)'
+ * da8e937880010000
+ *
+ * Netscreen:
+ * d6b45f82f24bacb288af59a978830ab7
+ * cf49908791073fb46439790fdeb6aeed981101ab0000000500000300
+ *
+ * Cisco:
+ * 1f07f70eaa6514d3b0fa96542a500300 (VPN 3000 version 3.0.0)
+ * 1f07f70eaa6514d3b0fa96542a500301 (VPN 3000 version 3.0.1)
+ * 1f07f70eaa6514d3b0fa96542a500305 (VPN 3000 version 3.0.5)
+ * 1f07f70eaa6514d3b0fa96542a500407 (VPN 3000 version 4.0.7)
+ * (Can you see the pattern?)
+ * afcad71368a1f1c96b8696fc77570100 (Non-RFC Dead Peer Detection ?)
+ * c32364b3b4f447eb17c488ab2a480a57
+ * 6d761ddc26aceca1b0ed11fabbb860c4
+ * 5946c258f99a1a57b03eb9d1759e0f24 (From a Cisco VPN 3k)
+ * ebbc5b00141d0c895e11bd395902d690 (From a Cisco VPN 3k)
+ *
+ * Microsoft L2TP (???):
+ * 47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310382e312e3020284275696c6420313029000000
+ * >> 382e312e3020284275696c6420313029 = '8.1.0 (Build 10)'
+ * 3025dbd21062b9e53dc441c6aab5293600000000
+ * da8e937880010000
+ *
+ * 3COM-superstack
+ * da8e937880010000
+ * 404bf439522ca3f6
+ *
+
+ * If someone know what they mean, mail me.
+ */
+
+#define MAX_LOG_VID_LEN 32
+
+#define VID_KEEP 0x0000
+#define VID_MD5HASH 0x0001
+#define VID_STRING 0x0002
+#define VID_FSWAN_HASH 0x0004
+
+#define VID_SUBSTRING_DUMPHEXA 0x0100
+#define VID_SUBSTRING_DUMPASCII 0x0200
+#define VID_SUBSTRING_MATCH 0x0400
+#define VID_SUBSTRING (VID_SUBSTRING_DUMPHEXA | VID_SUBSTRING_DUMPASCII | VID_SUBSTRING_MATCH)
+
+struct vid_struct {
+ enum known_vendorid id;
+ unsigned short flags;
+ const char *data;
+ const char *descr;
+ const char *vid;
+ u_int vid_len;
+};
+
+#define DEC_MD5_VID_D(id,str,descr) \
+ { VID_##id, VID_MD5HASH, str, descr, NULL, 0 },
+#define DEC_MD5_VID(id,str) \
+ { VID_##id, VID_MD5HASH, str, NULL, NULL, 0 },
+#define DEC_FSWAN_VID(id,str,descr) \
+ { VID_##id, VID_FSWAN_HASH, str, descr, NULL, 0 },
+
+static struct vid_struct _vid_tab[] = {
+
+ /* Implementation names */
+
+ { VID_OPENPGP, VID_STRING, "OpenPGP10171", "OpenPGP", NULL, 0 },
+
+ DEC_MD5_VID(KAME_RACOON, "KAME/racoon")
+
+ { VID_MS_NT5, VID_MD5HASH | VID_SUBSTRING_DUMPHEXA,
+ "MS NT5 ISAKMPOAKLEY", NULL, NULL, 0 },
+
+ DEC_MD5_VID(SSH_SENTINEL, "SSH Sentinel")
+ DEC_MD5_VID(SSH_SENTINEL_1_1, "SSH Sentinel 1.1")
+ DEC_MD5_VID(SSH_SENTINEL_1_2, "SSH Sentinel 1.2")
+ DEC_MD5_VID(SSH_SENTINEL_1_3, "SSH Sentinel 1.3")
+ DEC_MD5_VID(SSH_SENTINEL_1_4, "SSH Sentinel 1.4")
+ DEC_MD5_VID(SSH_SENTINEL_1_4_1, "SSH Sentinel 1.4.1")
+
+ /* These ones come from SSH vendors.txt */
+ DEC_MD5_VID(SSH_IPSEC_1_1_0,
+ "Ssh Communications Security IPSEC Express version 1.1.0")
+ DEC_MD5_VID(SSH_IPSEC_1_1_1,
+ "Ssh Communications Security IPSEC Express version 1.1.1")
+ DEC_MD5_VID(SSH_IPSEC_1_1_2,
+ "Ssh Communications Security IPSEC Express version 1.1.2")
+ DEC_MD5_VID(SSH_IPSEC_1_2_1,
+ "Ssh Communications Security IPSEC Express version 1.2.1")
+ DEC_MD5_VID(SSH_IPSEC_1_2_2,
+ "Ssh Communications Security IPSEC Express version 1.2.2")
+ DEC_MD5_VID(SSH_IPSEC_2_0_0,
+ "SSH Communications Security IPSEC Express version 2.0.0")
+ DEC_MD5_VID(SSH_IPSEC_2_1_0,
+ "SSH Communications Security IPSEC Express version 2.1.0")
+ DEC_MD5_VID(SSH_IPSEC_2_1_1,
+ "SSH Communications Security IPSEC Express version 2.1.1")
+ DEC_MD5_VID(SSH_IPSEC_2_1_2,
+ "SSH Communications Security IPSEC Express version 2.1.2")
+ DEC_MD5_VID(SSH_IPSEC_3_0_0,
+ "SSH Communications Security IPSEC Express version 3.0.0")
+ DEC_MD5_VID(SSH_IPSEC_3_0_1,
+ "SSH Communications Security IPSEC Express version 3.0.1")
+ DEC_MD5_VID(SSH_IPSEC_4_0_0,
+ "SSH Communications Security IPSEC Express version 4.0.0")
+ DEC_MD5_VID(SSH_IPSEC_4_0_1,
+ "SSH Communications Security IPSEC Express version 4.0.1")
+ DEC_MD5_VID(SSH_IPSEC_4_1_0,
+ "SSH Communications Security IPSEC Express version 4.1.0")
+ DEC_MD5_VID(SSH_IPSEC_4_2_0,
+ "SSH Communications Security IPSEC Express version 4.2.0")
+
+ /* note: md5('CISCO-UNITY') = 12f5f28c457168a9702d9fe274cc02d4 */
+ { VID_CISCO_UNITY, VID_KEEP, NULL, "Cisco-Unity",
+ "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00",
+ 16 },
+
+ { VID_CISCO3K, VID_KEEP | VID_SUBSTRING_MATCH,
+ NULL, "Cisco VPN 3000 Series" , "\x1f\x07\xf7\x0e\xaa\x65\x14\xd3\xb0\xfa\x96\x54\x2a\x50", 14},
+
+ /*
+ * Timestep VID seen:
+ * - 54494d455354455020312053475720313532302033313520322e303145303133
+ * = 'TIMESTEP 1 SGW 1520 315 2.01E013'
+ */
+ { VID_TIMESTEP, VID_STRING | VID_SUBSTRING_DUMPASCII, "TIMESTEP",
+ NULL, NULL, 0 },
+
+ /*
+ * Netscreen:
+ * 4865617274426561745f4e6f74696679386b0100 (HeartBeat_Notify + 386b0100)
+ */
+ { VID_MISC_HEARTBEAT_NOTIFY, VID_STRING | VID_SUBSTRING_DUMPHEXA,
+ "HeartBeat_Notify", "HeartBeat Notify", NULL, 0 },
+
+ /*
+ * MacOS X
+ */
+ { VID_MACOSX, VID_STRING|VID_SUBSTRING_DUMPHEXA, "Mac OSX 10.x",
+ "\x4d\xf3\x79\x28\xe9\xfc\x4f\xd1\xb3\x26\x21\x70\xd5\x15\xc6\x62", NULL, 0},
+
+ /*
+ * Openswan
+ */
+ DEC_FSWAN_VID(OPENSWAN2, "Openswan 2.2.0", "Openswan 2.2.0")
+
+ /* NCP */
+ { VID_NCP_SERVER, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "NCP Server",
+ "\xc6\xf5\x7a\xc3\x98\xf4\x93\x20\x81\x45\xb7\x58", 12},
+ { VID_NCP_CLIENT, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "NCP Client",
+ "\xeb\x4c\x1b\x78\x8a\xfd\x4a\x9c\xb7\x73\x0a\x68", 12},
+ /*
+ * strongSwan
+ */
+ DEC_MD5_VID(STRONGSWAN, "strongSwan 2.7.0")
+ DEC_MD5_VID(STRONGSWAN_2_6_4, "strongSwan 2.6.4")
+ DEC_MD5_VID(STRONGSWAN_2_6_3, "strongSwan 2.6.3")
+ DEC_MD5_VID(STRONGSWAN_2_6_2, "strongSwan 2.6.2")
+ DEC_MD5_VID(STRONGSWAN_2_6_1, "strongSwan 2.6.1")
+ DEC_MD5_VID(STRONGSWAN_2_6_0, "strongSwan 2.6.0")
+ DEC_MD5_VID(STRONGSWAN_2_5_7, "strongSwan 2.5.7")
+ DEC_MD5_VID(STRONGSWAN_2_5_6, "strongSwan 2.5.6")
+ DEC_MD5_VID(STRONGSWAN_2_5_5, "strongSwan 2.5.5")
+ DEC_MD5_VID(STRONGSWAN_2_5_4, "strongSwan 2.5.4")
+ DEC_MD5_VID(STRONGSWAN_2_5_3, "strongSwan 2.5.3")
+ DEC_MD5_VID(STRONGSWAN_2_5_2, "strongSwan 2.5.2")
+ DEC_MD5_VID(STRONGSWAN_2_5_1, "strongSwan 2.5.1")
+ DEC_MD5_VID(STRONGSWAN_2_5_0, "strongSwan 2.5.0")
+ DEC_MD5_VID(STRONGSWAN_2_4_4, "strongSwan 2.4.4")
+ DEC_MD5_VID(STRONGSWAN_2_4_3, "strongSwan 2.4.3")
+ DEC_MD5_VID(STRONGSWAN_2_4_2, "strongSwan 2.4.2")
+ DEC_MD5_VID(STRONGSWAN_2_4_1, "strongSwan 2.4.1")
+ DEC_MD5_VID(STRONGSWAN_2_4_0, "strongSwan 2.4.0")
+ DEC_MD5_VID(STRONGSWAN_2_3_2, "strongSwan 2.3.2")
+ DEC_MD5_VID(STRONGSWAN_2_3_1, "strongSwan 2.3.1")
+ DEC_MD5_VID(STRONGSWAN_2_3_0, "strongSwan 2.3.0")
+ DEC_MD5_VID(STRONGSWAN_2_2_2, "strongSwan 2.2.2")
+ DEC_MD5_VID(STRONGSWAN_2_2_1, "strongSwan 2.2.1")
+ DEC_MD5_VID(STRONGSWAN_2_2_0, "strongSwan 2.2.0")
+
+ /* NAT-Traversal */
+
+ DEC_MD5_VID(NATT_STENBERG_01, "draft-stenberg-ipsec-nat-traversal-01")
+ DEC_MD5_VID(NATT_STENBERG_02, "draft-stenberg-ipsec-nat-traversal-02")
+ DEC_MD5_VID(NATT_HUTTUNEN, "ESPThruNAT")
+ DEC_MD5_VID(NATT_HUTTUNEN_ESPINUDP, "draft-huttunen-ipsec-esp-in-udp-00.txt")
+ DEC_MD5_VID(NATT_IETF_00, "draft-ietf-ipsec-nat-t-ike-00")
+ DEC_MD5_VID(NATT_IETF_02, "draft-ietf-ipsec-nat-t-ike-02")
+ /* hash in draft-ietf-ipsec-nat-t-ike-02 contains '\n'... Accept both */
+ DEC_MD5_VID_D(NATT_IETF_02_N, "draft-ietf-ipsec-nat-t-ike-02\n", "draft-ietf-ipsec-nat-t-ike-02_n")
+ DEC_MD5_VID(NATT_IETF_03, "draft-ietf-ipsec-nat-t-ike-03")
+ DEC_MD5_VID(NATT_RFC, "RFC 3947")
+
+ /* misc */
+
+ { VID_MISC_XAUTH, VID_KEEP, NULL, "XAUTH",
+ "\x09\x00\x26\x89\xdf\xd6\xb7\x12", 8 },
+
+ { VID_MISC_DPD, VID_KEEP, NULL, "Dead Peer Detection",
+ "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00", 16 },
+
+ DEC_MD5_VID(MISC_FRAGMENTATION, "FRAGMENTATION")
+
+ DEC_MD5_VID(INITIAL_CONTACT, "Vid-Initial-Contact")
+
+ /* -- */
+ { 0, 0, NULL, NULL, NULL, 0 }
+
+};
+
+static const char _hexdig[] = "0123456789abcdef";
+
+static int _vid_struct_init = 0;
+
+void
+init_vendorid(void)
+{
+ struct vid_struct *vid;
+ MD5_CTX ctx;
+ int i;
+
+ for (vid = _vid_tab; vid->id; vid++)
+ {
+ if (vid->flags & VID_STRING)
+ {
+ /** VendorID is a string **/
+ vid->vid = strdup(vid->data);
+ vid->vid_len = strlen(vid->data);
+ }
+ else if (vid->flags & VID_MD5HASH)
+ {
+ /** VendorID is a string to hash with MD5 **/
+ char *vidm = malloc(MD5_DIGEST_SIZE);
+
+ vid->vid = vidm;
+ if (vidm)
+ {
+ MD5Init(&ctx);
+ MD5Update(&ctx, (const u_char *)vid->data, strlen(vid->data));
+ MD5Final(vidm, &ctx);
+ vid->vid_len = MD5_DIGEST_SIZE;
+ }
+ }
+ else if (vid->flags & VID_FSWAN_HASH)
+ {
+ /** FreeS/WAN 2.00+ specific hash **/
+#define FSWAN_VID_SIZE 12
+ unsigned char hash[MD5_DIGEST_SIZE];
+ char *vidm = malloc(FSWAN_VID_SIZE);
+
+ vid->vid = vidm;
+ if (vidm)
+ {
+ MD5Init(&ctx);
+ MD5Update(&ctx, (const u_char *)vid->data, strlen(vid->data));
+ MD5Final(hash, &ctx);
+ vidm[0] = 'O';
+ vidm[1] = 'E';
+#if FSWAN_VID_SIZE - 2 <= MD5_DIGEST_SIZE
+ memcpy(vidm + 2, hash, FSWAN_VID_SIZE - 2);
+#else
+ memcpy(vidm + 2, hash, MD5_DIGEST_SIZE);
+ memset(vidm + 2 + MD5_DIGEST_SIZE, '\0',
+ FSWAN_VID_SIZE - 2 - MD5_DIGEST_SIZE);
+#endif
+ for (i = 2; i < FSWAN_VID_SIZE; i++)
+ {
+ vidm[i] &= 0x7f;
+ vidm[i] |= 0x40;
+ }
+ vid->vid_len = FSWAN_VID_SIZE;
+ }
+ }
+
+ if (vid->descr == NULL)
+ {
+ /** Find something to display **/
+ vid->descr = vid->data;
+ }
+ }
+ _vid_struct_init = 1;
+}
+
+static void
+handle_known_vendorid (struct msg_digest *md
+, const char *vidstr, size_t len, struct vid_struct *vid)
+{
+ char vid_dump[128];
+ bool vid_useful = FALSE;
+ size_t i, j;
+
+ switch (vid->id) {
+ /* Remote side supports OpenPGP certificates */
+ case VID_OPENPGP:
+ md->openpgp = TRUE;
+ vid_useful = TRUE;
+ break;
+#ifdef NAT_TRAVERSAL
+ /*
+ * Use most recent supported NAT-Traversal method and ignore the
+ * other ones (implementations will send all supported methods but
+ * only one will be used)
+ *
+ * Note: most recent == higher id in vendor.h
+ */
+ case VID_NATT_IETF_00:
+ if (!nat_traversal_support_non_ike)
+ break;
+ if ((nat_traversal_enabled) && (!md->nat_traversal_vid))
+ {
+ md->nat_traversal_vid = vid->id;
+ vid_useful = TRUE;
+ }
+ break;
+ case VID_NATT_IETF_02:
+ case VID_NATT_IETF_02_N:
+ case VID_NATT_IETF_03:
+ case VID_NATT_RFC:
+ if (nat_traversal_support_port_floating
+ && md->nat_traversal_vid < vid->id)
+ {
+ md->nat_traversal_vid = vid->id;
+ vid_useful = TRUE;
+ }
+ break;
+#endif
+ /* Remote side would like to do DPD with us on this connection */
+ case VID_MISC_DPD:
+ md->dpd = TRUE;
+ vid_useful = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ if (vid->flags & VID_SUBSTRING_DUMPHEXA)
+ {
+ /* Dump description + Hexa */
+ memset(vid_dump, 0, sizeof(vid_dump));
+ snprintf(vid_dump, sizeof(vid_dump), "%s ",
+ vid->descr ? vid->descr : "");
+ for (i = strlen(vid_dump), j = vid->vid_len;
+ j < len && i < sizeof(vid_dump) - 2;
+ i += 2, j++)
+ {
+ vid_dump[i] = _hexdig[(vidstr[j] >> 4) & 0xF];
+ vid_dump[i+1] = _hexdig[vidstr[j] & 0xF];
+ }
+ }
+ else if (vid->flags & VID_SUBSTRING_DUMPASCII)
+ {
+ /* Dump ASCII content */
+ memset(vid_dump, 0, sizeof(vid_dump));
+ for (i = 0; i < len && i < sizeof(vid_dump) - 1; i++)
+ {
+ vid_dump[i] = (isprint(vidstr[i])) ? vidstr[i] : '.';
+ }
+ }
+ else
+ {
+ /* Dump description (descr) */
+ snprintf(vid_dump, sizeof(vid_dump), "%s",
+ vid->descr ? vid->descr : "");
+ }
+
+ loglog(RC_LOG_SERIOUS, "%s Vendor ID payload [%s]",
+ vid_useful ? "received" : "ignoring", vid_dump);
+}
+
+void
+handle_vendorid (struct msg_digest *md, const char *vid, size_t len)
+{
+ struct vid_struct *pvid;
+
+ if (!_vid_struct_init)
+ init_vendorid();
+
+ /*
+ * Find known VendorID in _vid_tab
+ */
+ for (pvid = _vid_tab; pvid->id; pvid++)
+ {
+ if (pvid->vid && vid && pvid->vid_len && len)
+ {
+ if (pvid->vid_len == len)
+ {
+ if (memcmp(pvid->vid, vid, len) == 0)
+ {
+ handle_known_vendorid(md, vid, len, pvid);
+ return;
+ }
+ }
+ else if ((pvid->vid_len < len) && (pvid->flags & VID_SUBSTRING))
+ {
+ if (memcmp(pvid->vid, vid, pvid->vid_len) == 0)
+ {
+ handle_known_vendorid(md, vid, len, pvid);
+ return;
+ }
+ }
+ }
+ }
+
+ /*
+ * Unknown VendorID. Log the beginning.
+ */
+ {
+ char log_vid[2*MAX_LOG_VID_LEN+1];
+ size_t i;
+
+ memset(log_vid, 0, sizeof(log_vid));
+
+ for (i = 0; i < len && i < MAX_LOG_VID_LEN; i++)
+ {
+ log_vid[2*i] = _hexdig[(vid[i] >> 4) & 0xF];
+ log_vid[2*i+1] = _hexdig[vid[i] & 0xF];
+ }
+ loglog(RC_LOG_SERIOUS, "ignoring Vendor ID payload [%s%s]",
+ log_vid, (len>MAX_LOG_VID_LEN) ? "..." : "");
+ }
+}
+
+/**
+ * Add a vendor id payload to the msg
+ */
+bool
+out_vendorid (u_int8_t np, pb_stream *outs, enum known_vendorid vid)
+{
+ struct vid_struct *pvid;
+
+ if (!_vid_struct_init)
+ init_vendorid();
+
+ for (pvid = _vid_tab; pvid->id && pvid->id != vid; pvid++);
+
+ if (pvid->id != vid)
+ return STF_INTERNAL_ERROR; /* not found */
+ if (!pvid->vid)
+ return STF_INTERNAL_ERROR; /* not initialized */
+
+ DBG(DBG_EMITTING,
+ DBG_log("out_vendorid(): sending [%s]", pvid->descr)
+ )
+ return out_generic_raw(np, &isakmp_vendor_id_desc, outs,
+ pvid->vid, pvid->vid_len, "V_ID");
+}
+
diff --git a/programs/pluto/vendor.h b/programs/pluto/vendor.h
new file mode 100644
index 000000000..d6b414be2
--- /dev/null
+++ b/programs/pluto/vendor.h
@@ -0,0 +1,107 @@
+/* FreeS/WAN ISAKMP VendorID
+ * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: vendor.h,v 1.30 2006/04/12 16:44:28 as Exp $
+ */
+
+#ifndef _VENDOR_H_
+#define _VENDOR_H_
+
+enum known_vendorid {
+/* 1 - 100 : Implementation names */
+ VID_OPENPGP = 1,
+ VID_KAME_RACOON = 2,
+ VID_MS_NT5 = 3,
+ VID_SSH_SENTINEL = 4,
+ VID_SSH_SENTINEL_1_1 = 5,
+ VID_SSH_SENTINEL_1_2 = 6,
+ VID_SSH_SENTINEL_1_3 = 7,
+ VID_SSH_SENTINEL_1_4 = 8,
+ VID_SSH_SENTINEL_1_4_1 = 9,
+ VID_SSH_IPSEC_1_1_0 = 10,
+ VID_SSH_IPSEC_1_1_1 = 11,
+ VID_SSH_IPSEC_1_1_2 = 12,
+ VID_SSH_IPSEC_1_2_1 = 13,
+ VID_SSH_IPSEC_1_2_2 = 14,
+ VID_SSH_IPSEC_2_0_0 = 15,
+ VID_SSH_IPSEC_2_1_0 = 16,
+ VID_SSH_IPSEC_2_1_1 = 17,
+ VID_SSH_IPSEC_2_1_2 = 18,
+ VID_SSH_IPSEC_3_0_0 = 19,
+ VID_SSH_IPSEC_3_0_1 = 20,
+ VID_SSH_IPSEC_4_0_0 = 21,
+ VID_SSH_IPSEC_4_0_1 = 22,
+ VID_SSH_IPSEC_4_1_0 = 23,
+ VID_SSH_IPSEC_4_2_0 = 24,
+ VID_CISCO_UNITY = 25,
+ VID_CISCO3K = 26,
+ VID_TIMESTEP = 27,
+ VID_SAFENET = 28,
+ VID_MACOSX = 29,
+ VID_OPENSWAN2 = 30,
+ VID_NCP_SERVER = 31,
+ VID_NCP_CLIENT = 32,
+ VID_STRONGSWAN = 33,
+ VID_STRONGSWAN_2_2_0 = 34,
+ VID_STRONGSWAN_2_2_1 = 35,
+ VID_STRONGSWAN_2_2_2 = 36,
+ VID_STRONGSWAN_2_3_0 = 37,
+ VID_STRONGSWAN_2_3_1 = 38,
+ VID_STRONGSWAN_2_3_2 = 39,
+ VID_STRONGSWAN_2_4_0 = 40,
+ VID_STRONGSWAN_2_4_1 = 41,
+ VID_STRONGSWAN_2_4_2 = 42,
+ VID_STRONGSWAN_2_4_3 = 43,
+ VID_STRONGSWAN_2_4_4 = 44,
+ VID_STRONGSWAN_2_5_0 = 45,
+ VID_STRONGSWAN_2_5_1 = 46,
+ VID_STRONGSWAN_2_5_2 = 47,
+ VID_STRONGSWAN_2_5_3 = 48,
+ VID_STRONGSWAN_2_5_4 = 49,
+ VID_STRONGSWAN_2_5_5 = 50,
+ VID_STRONGSWAN_2_5_6 = 51,
+ VID_STRONGSWAN_2_5_7 = 52,
+ VID_STRONGSWAN_2_6_0 = 53,
+ VID_STRONGSWAN_2_6_1 = 54,
+ VID_STRONGSWAN_2_6_2 = 55,
+ VID_STRONGSWAN_2_6_3 = 56,
+ VID_STRONGSWAN_2_6_4 = 57,
+
+ /* 101 - 200 : NAT-Traversal */
+ VID_NATT_STENBERG_01 =101,
+ VID_NATT_STENBERG_02 =102,
+ VID_NATT_HUTTUNEN =103,
+ VID_NATT_HUTTUNEN_ESPINUDP =104,
+ VID_NATT_IETF_00 =105,
+ VID_NATT_IETF_02_N =106,
+ VID_NATT_IETF_02 =107,
+ VID_NATT_IETF_03 =108,
+ VID_NATT_RFC =109,
+
+ /* 201 - 300 : Misc */
+ VID_MISC_XAUTH =201,
+ VID_MISC_DPD =202,
+ VID_MISC_HEARTBEAT_NOTIFY =203,
+ VID_MISC_FRAGMENTATION =204,
+ VID_INITIAL_CONTACT =205
+};
+
+void init_vendorid(void);
+
+struct msg_digest;
+void handle_vendorid (struct msg_digest *md, const char *vid, size_t len);
+
+bool out_vendorid (u_int8_t np, pb_stream *outs, enum known_vendorid vid);
+
+#endif /* _VENDOR_H_ */
+
diff --git a/programs/pluto/virtual.c b/programs/pluto/virtual.c
new file mode 100644
index 000000000..58487c1e8
--- /dev/null
+++ b/programs/pluto/virtual.c
@@ -0,0 +1,338 @@
+/* FreeS/WAN Virtual IP Management
+ * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: virtual.c,v 1.4 2004/04/02 10:38:52 as Exp $
+ */
+
+#ifdef VIRTUAL_IP
+
+#include <freeswan.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "connections.h"
+#include "whack.h"
+#include "virtual.h"
+
+#define F_VIRTUAL_NO 1
+#define F_VIRTUAL_DHCP 2
+#define F_VIRTUAL_IKE_CONFIG 4
+#define F_VIRTUAL_PRIVATE 8
+#define F_VIRTUAL_ALL 16
+#define F_VIRTUAL_HOST 32
+
+struct virtual_t {
+ unsigned short flags;
+ unsigned short n_net;
+ ip_subnet net[0];
+};
+
+static ip_subnet *private_net_ok=NULL, *private_net_ko=NULL;
+static unsigned short private_net_ok_len=0, private_net_ko_len=0;
+
+/**
+ * read %v4:x.x.x.x/y or %v6:xxxxxxxxx/yy
+ * or %v4:!x.x.x.x/y if dstko not NULL
+ */
+static bool
+_read_subnet(const char *src, size_t len, ip_subnet *dst, ip_subnet *dstko,
+ bool *isok)
+{
+ bool ok;
+ int af;
+
+ if ((len > 4) && (strncmp(src, "%v4:", 4)==0))
+ {
+ af = AF_INET;
+ }
+ else if ((len > 4) && (strncmp(src, "%v6:", 4)==0))
+ {
+ af = AF_INET6;
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ ok = (src[4] != '!');
+ src += ok ? 4 : 5;
+ len -= ok ? 4 : 5;
+
+ if (!len)
+ return FALSE;
+ if (!ok && !dstko)
+ return FALSE;
+
+ passert ( ((ok)?(dst):(dstko))!=NULL );
+
+ if (ttosubnet(src, len, af, ((ok)?(dst):(dstko))))
+ {
+ return FALSE;
+ }
+ if (isok)
+ *isok = ok;
+ return TRUE;
+}
+
+void
+init_virtual_ip(const char *private_list)
+{
+ const char *next, *str=private_list;
+ unsigned short ign = 0, i_ok, i_ko;
+ ip_subnet sub;
+ bool ok;
+
+ /** Count **/
+ private_net_ok_len=0;
+ private_net_ko_len=0;
+
+ while (str)
+ {
+ next = strchr(str,',');
+ if (!next)
+ next = str + strlen(str);
+ if (_read_subnet(str, next-str, &sub, &sub, &ok))
+ if (ok)
+ private_net_ok_len++;
+ else
+ private_net_ko_len++;
+ else
+ ign++;
+ str = *next ? next+1 : NULL;
+ }
+
+ if (!ign)
+ {
+ /** Allocate **/
+ if (private_net_ok_len)
+ {
+ private_net_ok = (ip_subnet *)alloc_bytes(
+ (private_net_ok_len*sizeof(ip_subnet)),
+ "private_net_ok subnets");
+ }
+ if (private_net_ko_len)
+ {
+ private_net_ko = (ip_subnet *)alloc_bytes(
+ (private_net_ko_len*sizeof(ip_subnet)),
+ "private_net_ko subnets");
+ }
+ if ((private_net_ok_len && !private_net_ok)
+ || (private_net_ko_len && !private_net_ko))
+ {
+ loglog(RC_LOG_SERIOUS,
+ "can't alloc in init_virtual_ip");
+ pfreeany(private_net_ok);
+ private_net_ok = NULL;
+ pfreeany(private_net_ko);
+ private_net_ko = NULL;
+ }
+ else
+ {
+ /** Fill **/
+ str = private_list;
+ i_ok = 0;
+ i_ko = 0;
+
+ while (str)
+ {
+ next = strchr(str,',');
+ if (!next)
+ next = str + strlen(str);
+ if (_read_subnet(str, next-str,
+ &(private_net_ok[i_ok]), &(private_net_ko[i_ko]), &ok))
+ {
+ if (ok)
+ i_ok++;
+ else
+ i_ko++;
+ }
+ str = *next ? next+1 : NULL;
+ }
+ }
+ }
+ else
+ loglog(RC_LOG_SERIOUS,
+ "%d bad entries in virtual_private - none loaded", ign);
+}
+
+/**
+ * virtual string must be :
+ * {vhost,vnet}:[%method]*
+ *
+ * vhost = accept only a host (/32)
+ * vnet = accept any network
+ *
+ * %no = no virtual IP (accept public IP)
+ * %dhcp = accept DHCP SA (0.0.0.0/0) of affected IP [not implemented]
+ * %ike = accept affected IKE Config Mode IP [not implemented]
+ * %priv = accept system-wide private net list
+ * %v4:x = accept ipv4 in list 'x'
+ * %v6:x = accept ipv6 in list 'x'
+ * %all = accept all ips [only for testing]
+ *
+ * ex: vhost:%no,%dhcp,%priv,%v4:192.168.1.0/24
+ */
+struct virtual_t
+*create_virtual(const struct connection *c, const char *string)
+{
+ unsigned short flags=0, n_net=0, i;
+ const char *str = string, *next, *first_net=NULL;
+ ip_subnet sub;
+ struct virtual_t *v;
+
+ if (!string || string[0] == '\0')
+ return NULL;
+
+ if (strlen(string) >= 6 && strncmp(string,"vhost:",6) == 0)
+ {
+ flags |= F_VIRTUAL_HOST;
+ str += 6;
+ }
+ else if (strlen(string) >= 5 && strncmp(string,"vnet:",5) == 0)
+ str += 5;
+ else
+ goto fail;
+
+ /**
+ * Parse string : fill flags & count subnets
+ */
+ while ((str) && (*str))
+ {
+ next = strchr(str,',');
+ if (!next) next = str + strlen(str);
+ if (next-str == 3 && strncmp(str, "%no", 3) == 0)
+ flags |= F_VIRTUAL_NO;
+#if 0
+ else if (next-str == 4 && strncmp(str, "%ike", 4) == 0)
+ flags |= F_VIRTUAL_IKE_CONFIG;
+ else if (next-str == 5 && strncmp(str, "%dhcp", 5) == 0)
+ flags |= F_VIRTUAL_DHCP;
+#endif
+ else if (next-str == 5 && strncmp(str, "%priv", 5) == 0)
+ flags |= F_VIRTUAL_PRIVATE;
+ else if (next-str == 4 && strncmp(str, "%all", 4) == 0)
+ flags |= F_VIRTUAL_ALL;
+ else if (_read_subnet(str, next-str, &sub, NULL, NULL))
+ {
+ n_net++;
+ if (!first_net)
+ first_net = str;
+ }
+ else
+ goto fail;
+
+ str = *next ? next+1 : NULL;
+ }
+
+ v = (struct virtual_t *)alloc_bytes(
+ sizeof(struct virtual_t) + (n_net*sizeof(ip_subnet)),
+ "virtual description");
+ if (!v) goto fail;
+
+ v->flags = flags;
+ v->n_net = n_net;
+ if (n_net && first_net)
+ {
+ /**
+ * Save subnets in newly allocated struct
+ */
+ for (str = first_net, i = 0; str && *str; )
+ {
+ next = strchr(str,',');
+ if (!next) next = str + strlen(str);
+ if (_read_subnet(str, next-str, &(v->net[i]), NULL, NULL))
+ i++;
+ str = *next ? next+1 : NULL;
+ }
+ }
+
+ return v;
+
+fail:
+ plog("invalid virtual string [%s] - "
+ "virtual selection disabled for connection '%s'", string, c->name);
+ return NULL;
+}
+
+bool
+is_virtual_end(const struct end *that)
+{
+ return ((that->virt)?TRUE:FALSE);
+}
+
+bool
+is_virtual_connection(const struct connection *c)
+{
+ return ((c->spd.that.virt)?TRUE:FALSE);
+}
+
+static bool
+net_in_list(const ip_subnet *peer_net, const ip_subnet *list,
+ unsigned short len)
+{
+ unsigned short i;
+
+ if (!list || !len)
+ return FALSE;
+
+ for (i = 0; i < len; i++)
+ {
+ if (subnetinsubnet(peer_net, &(list[i])))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool
+is_virtual_net_allowed(const struct connection *c, const ip_subnet *peer_net,
+ const ip_address *his_addr)
+{
+ if (c->spd.that.virt == NULL)
+ return FALSE;
+
+ if ((c->spd.that.virt->flags & F_VIRTUAL_HOST)
+ && !subnetishost(peer_net))
+ return FALSE;
+
+ if ((c->spd.that.virt->flags & F_VIRTUAL_NO)
+ && subnetishost(peer_net) && addrinsubnet(his_addr, peer_net))
+ return TRUE;
+
+ if ((c->spd.that.virt->flags & F_VIRTUAL_PRIVATE)
+ && net_in_list(peer_net, private_net_ok, private_net_ok_len)
+ && !net_in_list(peer_net, private_net_ko, private_net_ko_len))
+ return TRUE;
+
+ if (c->spd.that.virt->n_net
+ && net_in_list(peer_net, c->spd.that.virt->net, c->spd.that.virt->n_net))
+ return TRUE;
+
+ if (c->spd.that.virt->flags & F_VIRTUAL_ALL)
+ {
+ /** %all must only be used for testing - log it **/
+ loglog(RC_LOG_SERIOUS, "Warning - "
+ "v%s:%%all must only be used for testing",
+ (c->spd.that.virt->flags & F_VIRTUAL_HOST) ? "host" : "net");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#endif
+
diff --git a/programs/pluto/virtual.h b/programs/pluto/virtual.h
new file mode 100644
index 000000000..2d5bf27ae
--- /dev/null
+++ b/programs/pluto/virtual.h
@@ -0,0 +1,31 @@
+/* FreeS/WAN Virtual IP Management
+ * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: virtual.h,v 1.2 2004/03/22 21:53:20 as Exp $
+ */
+
+#ifndef _VIRTUAL_IP_H
+#define _VIRTUAL_IP_H
+
+extern void init_virtual_ip(const char *private_list);
+
+extern struct virtual_t *create_virtual(const struct connection *c,
+ const char *string);
+
+extern bool is_virtual_end(const struct end *that);
+extern bool is_virtual_connection(const struct connection *c);
+extern bool is_virtual_net_allowed(const struct connection *c,
+ const ip_subnet *peer_net, const ip_address *his_addr);
+
+#endif /* _VIRTUAL_IP_H */
+
diff --git a/programs/pluto/whack.c b/programs/pluto/whack.c
new file mode 100644
index 000000000..a3b983771
--- /dev/null
+++ b/programs/pluto/whack.c
@@ -0,0 +1,1911 @@
+/* command interface to Pluto
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: whack.c,v 1.21 2006/04/20 04:42:12 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "whack.h"
+
+static void
+help(void)
+{
+ fprintf(stderr
+ , "Usage:\n\n"
+ "all forms:"
+ " [--optionsfrom <filename>]"
+ " [--ctlbase <path>]"
+ " [--label <string>]"
+ "\n\n"
+ "help: whack"
+ " [--help]"
+ " [--version]"
+ "\n\n"
+ "connection: whack"
+ " --name <connection_name>"
+ " \\\n "
+ " [--ipv4 | --ipv6]"
+ " [--tunnelipv4 | --tunnelipv6]"
+ " \\\n "
+ " (--host <ip-address> | --id <identity>)"
+ " \\\n "
+ " [--cert <path>]"
+ " [--ca <distinguished name>]"
+ " [--sendcert <policy>]"
+ " \\\n "
+ " [--groups <access control groups>]"
+ " \\\n "
+ " [--ikeport <port-number>]"
+ " [--nexthop <ip-address>]"
+ " [--srcip <ip-address>]"
+ " \\\n "
+ " [--client <subnet> | --clientwithin <address range>]"
+ " [--clientprotoport <protocol>/<port>]"
+ " \\\n "
+ " [--dnskeyondemand]"
+ " [--updown <updown>]"
+ " \\\n "
+ " --to"
+ " (--host <ip-address> | --id <identity>)"
+ " \\\n "
+ " [--cert <path>]"
+ " [--ca <distinguished name>]"
+ " [--sendcert <policy>]"
+ " \\\n "
+ " [--ikeport <port-number>]"
+ " [--nexthop <ip-address>]"
+ " [--srcip <ip-address>]"
+ " \\\n "
+ " [--client <subnet> | --clientwithin <address range>]"
+ " [--clientprotoport <protocol>/<port>]"
+ " \\\n "
+ " [--dnskeyondemand]"
+ " [--updown <updown>]"
+ " [--psk]"
+ " [--rsasig]"
+ " \\\n "
+ " [--encrypt]"
+ " [--authenticate]"
+ " [--compress]"
+ " [--tunnel]"
+ " [--pfs]"
+ " \\\n "
+ " [--ikelifetime <seconds>]"
+ " [--ipseclifetime <seconds>]"
+ " \\\n "
+ " [--reykeymargin <seconds>]"
+ " [--reykeyfuzz <percentage>]"
+ " \\\n "
+ " [--keyingtries <count>]"
+ " \\\n "
+ " [--esp <esp-algos>]"
+ " \\\n "
+ " [--dontrekey]"
+
+ " [--dpdaction (none|clear|hold|restart)]"
+ " \\\n "
+ " [--dpddelay <seconds> --dpdtimeout <seconds>]"
+ " \\\n "
+ " [--initiateontraffic|--pass|--drop|--reject]"
+ " \\\n "
+ " [--failnone|--failpass|--faildrop|--failreject]"
+ "\n\n"
+ "routing: whack"
+ " (--route | --unroute)"
+ " --name <connection_name>"
+ "\n\n"
+ "initiation:"
+ "\n "
+ " whack"
+ " (--initiate | --terminate)"
+ " --name <connection_name>"
+ " [--asynchronous]"
+ "\n\n"
+ "opportunistic initiation: whack"
+ " [--tunnelipv4 | --tunnelipv6]"
+ " \\\n "
+ " --oppohere <ip-address>"
+ " --oppothere <ip-address>"
+ "\n\n"
+ "delete: whack"
+ " --delete"
+ " (--name <connection_name> | --caname <ca name>)"
+ "\n\n"
+ "deletestate: whack"
+ " --deletestate <state_object_number>"
+ " --crash <ip-address>"
+ "\n\n"
+ "pubkey: whack"
+ " --keyid <id>"
+ " [--addkey]"
+ " [--pubkeyrsa <key>]"
+ "\n\n"
+ "myid: whack"
+ " --myid <id>"
+ "\n\n"
+ "ca: whack"
+ " --caname <name>"
+ " --cacert <path>"
+ " \\\n "
+ " [--ldaphost <hostname>]"
+ " [--ldapbase <base>]"
+ " \\\n "
+ " [--crluri <uri>]"
+ " [--crluri2 <uri>]"
+ " [--ocspuri <uri>]"
+ " [--strictcrlpolicy]"
+ "\n\n"
+#ifdef DEBUG
+ "debug: whack [--name <connection_name>]"
+ " \\\n "
+ " [--debug-none]"
+ " [--debug-all]"
+ " \\\n "
+ " [--debug-raw]"
+ " [--debug-crypt]"
+ " [--debug-parsing]"
+ " [--debug-emitting]"
+ " \\\n "
+ " [--debug-control]"
+ " [--debug-lifecycle]"
+ " [--debug-klips]"
+ " [--debug-dns]"
+ " \\\n "
+ " [--debug-natt]"
+ " [--debug-oppo]"
+ " [--debug-controlmore]"
+ " [--debug-private]"
+ "\n\n"
+#endif
+ "listen: whack"
+ " (--listen | --unlisten)"
+ "\n\n"
+ "list: whack [--utc]"
+ " [--listalgs]"
+ " [--listpubkeys]"
+ " [--listcerts]"
+ " [--listcacerts]"
+ " \\\n "
+ " [--listacerts]"
+ " [--listaacerts]"
+ " [--listocspcerts]"
+ " [--listgroups]"
+ " \\\n "
+ " [--listcainfos]"
+ " [--listcrls]"
+ " [--listocsp]"
+ " [--listcards]"
+ " [--listall]"
+ "\n\n"
+ "purge: whack"
+ " [--purgeocsp]"
+ "\n\n"
+ "reread: whack"
+ " [--rereadsecrets]"
+ " [--rereadcacerts]"
+ " [--rereadaacerts]"
+ " \\\n "
+ " [--rereadocspcerts]"
+ " [--rereadacerts]"
+ " [--rereadcrls]"
+ " [--rereadall]"
+ "\n\n"
+ "status: whack"
+ " [--name <connection_name>] --status|--statusall"
+ "\n\n"
+ "scdecrypt: whack"
+ " --scencrypt|scdecrypt <value>"
+ " [--inbase <base>]"
+ " [--outbase <base>]"
+ " [--keyid <id>]"
+ "\n\n"
+ "shutdown: whack"
+ " --shutdown"
+ "\n\n"
+ "strongSwan %s\n"
+ , ipsec_version_code());
+}
+
+static const char *label = NULL; /* --label operand, saved for diagnostics */
+
+static const char *name = NULL; /* --name operand, saved for diagnostics */
+
+/* print a string as a diagnostic, then exit whack unhappily */
+static void
+diag(const char *mess)
+{
+ if (mess != NULL)
+ {
+ fprintf(stderr, "whack error: ");
+ if (label != NULL)
+ fprintf(stderr, "%s ", label);
+ if (name != NULL)
+ fprintf(stderr, "\"%s\" ", name);
+ fprintf(stderr, "%s\n", mess);
+ }
+
+ exit(RC_WHACK_PROBLEM);
+}
+
+/* conditially calls diag; prints second arg, if non-NULL, as quoted string */
+static void
+diagq(err_t ugh, const char *this)
+{
+ if (ugh != NULL)
+ {
+ if (this == NULL)
+ {
+ diag(ugh);
+ }
+ else
+ {
+ char buf[120]; /* arbitrary limit */
+
+ snprintf(buf, sizeof(buf), "%s \"%s\"", ugh, this);
+ diag(buf);
+ }
+ }
+}
+
+/* complex combined operands return one of these enumerated values
+ * Note: these become flags in an lset_t. Since there are more than
+ * 32, we partition them into:
+ * - OPT_* options (most random options)
+ * - LST_* options (list various internal data)
+ * - DBGOPT_* option (DEBUG options)
+ * - END_* options (End description options)
+ * - CD_* options (Connection Description options)
+ * - CA_* options (CA description options)
+ */
+enum {
+# define OPT_FIRST OPT_CTLBASE
+ OPT_CTLBASE,
+ OPT_NAME,
+
+ OPT_CD,
+
+ OPT_KEYID,
+ OPT_ADDKEY,
+ OPT_PUBKEYRSA,
+
+ OPT_MYID,
+
+ OPT_ROUTE,
+ OPT_UNROUTE,
+
+ OPT_INITIATE,
+ OPT_TERMINATE,
+ OPT_DELETE,
+ OPT_DELETESTATE,
+ OPT_LISTEN,
+ OPT_UNLISTEN,
+
+ OPT_PURGEOCSP,
+
+ OPT_REREADSECRETS,
+ OPT_REREADCACERTS,
+ OPT_REREADAACERTS,
+ OPT_REREADOCSPCERTS,
+ OPT_REREADACERTS,
+ OPT_REREADCRLS,
+ OPT_REREADALL,
+
+ OPT_STATUS,
+ OPT_STATUSALL,
+ OPT_SHUTDOWN,
+
+ OPT_OPPO_HERE,
+ OPT_OPPO_THERE,
+
+ OPT_ASYNC,
+ OPT_DELETECRASH,
+
+# define OPT_LAST OPT_ASYNC /* last "normal" option */
+
+/* Smartcard options */
+
+# define SC_FIRST SC_ENCRYPT /* first smartcard option */
+
+ SC_ENCRYPT,
+ SC_DECRYPT,
+ SC_INBASE,
+ SC_OUTBASE,
+
+# define SC_LAST SC_OUTBASE /* last "smartcard" option */
+
+/* List options */
+
+# define LST_FIRST LST_UTC /* first list option */
+ LST_UTC,
+ LST_ALGS,
+ LST_PUBKEYS,
+ LST_CERTS,
+ LST_CACERTS,
+ LST_ACERTS,
+ LST_AACERTS,
+ LST_OCSPCERTS,
+ LST_GROUPS,
+ LST_CAINFOS,
+ LST_CRLS,
+ LST_OCSP,
+ LST_CARDS,
+ LST_ALL,
+
+# define LST_LAST LST_ALL /* last list option */
+
+/* Connection End Description options */
+
+# define END_FIRST END_HOST /* first end description */
+ END_HOST,
+ END_ID,
+ END_CERT,
+ END_CA,
+ END_SENDCERT,
+ END_GROUPS,
+ END_IKEPORT,
+ END_NEXTHOP,
+ END_CLIENT,
+ END_CLIENTWITHIN,
+ END_CLIENTPROTOPORT,
+ END_DNSKEYONDEMAND,
+ END_SRCIP,
+ END_HOSTACCESS,
+ END_UPDOWN,
+
+#define END_LAST END_UPDOWN /* last end description*/
+
+/* Connection Description options -- segregated */
+
+# define CD_FIRST CD_TO /* first connection description */
+ CD_TO,
+
+# define CD_POLICY_FIRST CD_PSK
+ CD_PSK, /* same order as POLICY_* */
+ CD_RSASIG, /* same order as POLICY_* */
+ CD_ENCRYPT, /* same order as POLICY_* */
+ CD_AUTHENTICATE, /* same order as POLICY_* */
+ CD_COMPRESS, /* same order as POLICY_* */
+ CD_TUNNEL, /* same order as POLICY_* */
+ CD_PFS, /* same order as POLICY_* */
+ CD_DISABLEARRIVALCHECK, /* same order as POLICY_* */
+ CD_SHUNT0, /* same order as POLICY_* */
+ CD_SHUNT1, /* same order as POLICY_* */
+ CD_FAIL0, /* same order as POLICY_* */
+ CD_FAIL1, /* same order as POLICY_* */
+ CD_DONT_REKEY, /* same order as POLICY_* */
+
+ CD_TUNNELIPV4,
+ CD_TUNNELIPV6,
+ CD_CONNIPV4,
+ CD_CONNIPV6,
+
+ CD_IKELIFETIME,
+ CD_IPSECLIFETIME,
+ CD_RKMARGIN,
+ CD_RKFUZZ,
+ CD_KTRIES,
+ CD_DPDACTION,
+ CD_DPDDELAY,
+ CD_DPDTIMEOUT,
+ CD_IKE,
+ CD_PFSGROUP,
+ CD_ESP,
+
+# define CD_LAST CD_ESP /* last connection description */
+
+/* Certificate Authority (CA) description options */
+
+# define CA_FIRST CA_NAME /* first ca description */
+
+ CA_NAME,
+ CA_CERT,
+ CA_LDAPHOST,
+ CA_LDAPBASE,
+ CA_CRLURI,
+ CA_CRLURI2,
+ CA_OCSPURI,
+ CA_STRICT
+
+# define CA_LAST CA_STRICT /* last ca description */
+
+#ifdef DEBUG /* must be last so others are less than 32 to fit in lset_t */
+# define DBGOPT_FIRST DBGOPT_NONE
+ ,
+ /* NOTE: these definitions must match DBG_* and IMPAIR_* in constants.h */
+ DBGOPT_NONE,
+ DBGOPT_ALL,
+
+ DBGOPT_RAW, /* same order as DBG_* */
+ DBGOPT_CRYPT, /* same order as DBG_* */
+ DBGOPT_PARSING, /* same order as DBG_* */
+ DBGOPT_EMITTING, /* same order as DBG_* */
+ DBGOPT_CONTROL, /* same order as DBG_* */
+ DBGOPT_LIFECYCLE, /* same order as DBG_* */
+ DBGOPT_KLIPS, /* same order as DBG_* */
+ DBGOPT_DNS, /* same order as DBG_* */
+ DBGOPT_NATT, /* same order as DBG_* */
+ DBGOPT_OPPO, /* same order as DBG_* */
+ DBGOPT_CONTROLMORE, /* same order as DBG_* */
+
+ DBGOPT_PRIVATE, /* same order as DBG_* */
+
+ DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER, /* same order as IMPAIR_* */
+ DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER, /* same order as IMPAIR_* */
+ DBGOPT_IMPAIR_BUST_MI2, /* same order as IMPAIR_* */
+ DBGOPT_IMPAIR_BUST_MR2 /* same order as IMPAIR_* */
+
+# define DBGOPT_LAST DBGOPT_IMPAIR_BUST_MR2
+#endif
+
+};
+
+/* Carve up space for result from getop_long.
+ * Stupidly, the only result is an int.
+ * Numeric arg is bit immediately left of basic value.
+ *
+ */
+#define OPTION_OFFSET 256 /* to get out of the way of letter options */
+#define NUMERIC_ARG (1 << 9) /* expect a numeric argument */
+#define AUX_SHIFT 10 /* amount to shift for aux information */
+
+static const struct option long_opts[] = {
+# define OO OPTION_OFFSET
+ /* name, has_arg, flag, val */
+
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "optionsfrom", required_argument, NULL, '+' },
+ { "label", required_argument, NULL, 'l' },
+
+ { "ctlbase", required_argument, NULL, OPT_CTLBASE + OO },
+ { "name", required_argument, NULL, OPT_NAME + OO },
+
+ { "keyid", required_argument, NULL, OPT_KEYID + OO },
+ { "addkey", no_argument, NULL, OPT_ADDKEY + OO },
+ { "pubkeyrsa", required_argument, NULL, OPT_PUBKEYRSA + OO },
+
+ { "myid", required_argument, NULL, OPT_MYID + OO },
+
+ { "route", no_argument, NULL, OPT_ROUTE + OO },
+ { "unroute", no_argument, NULL, OPT_UNROUTE + OO },
+
+ { "initiate", no_argument, NULL, OPT_INITIATE + OO },
+ { "terminate", no_argument, NULL, OPT_TERMINATE + OO },
+ { "delete", no_argument, NULL, OPT_DELETE + OO },
+ { "deletestate", required_argument, NULL, OPT_DELETESTATE + OO + NUMERIC_ARG },
+ { "crash", required_argument, NULL, OPT_DELETECRASH + OO },
+ { "listen", no_argument, NULL, OPT_LISTEN + OO },
+ { "unlisten", no_argument, NULL, OPT_UNLISTEN + OO },
+
+ { "purgeocsp", no_argument, NULL, OPT_PURGEOCSP + OO },
+
+ { "rereadsecrets", no_argument, NULL, OPT_REREADSECRETS + OO },
+ { "rereadcacerts", no_argument, NULL, OPT_REREADCACERTS + OO },
+ { "rereadaacerts", no_argument, NULL, OPT_REREADAACERTS + OO },
+ { "rereadocspcerts", no_argument, NULL, OPT_REREADOCSPCERTS + OO },
+ { "rereadacerts", no_argument, NULL, OPT_REREADACERTS + OO },
+ { "rereadcrls", no_argument, NULL, OPT_REREADCRLS + OO },
+ { "rereadall", no_argument, NULL, OPT_REREADALL + OO },
+ { "status", no_argument, NULL, OPT_STATUS + OO },
+ { "statusall", no_argument, NULL, OPT_STATUSALL + OO },
+ { "shutdown", no_argument, NULL, OPT_SHUTDOWN + OO },
+
+ { "oppohere", required_argument, NULL, OPT_OPPO_HERE + OO },
+ { "oppothere", required_argument, NULL, OPT_OPPO_THERE + OO },
+
+ { "asynchronous", no_argument, NULL, OPT_ASYNC + OO },
+
+ /* smartcard options */
+
+ { "scencrypt", required_argument, NULL, SC_ENCRYPT + OO },
+ { "scdecrypt", required_argument, NULL, SC_DECRYPT + OO },
+ { "inbase", required_argument, NULL, SC_INBASE + OO },
+ { "outbase", required_argument, NULL, SC_OUTBASE + OO },
+
+ /* list options */
+
+ { "utc", no_argument, NULL, LST_UTC + OO },
+ { "listalgs", no_argument, NULL, LST_ALGS + OO },
+ { "listpubkeys", no_argument, NULL, LST_PUBKEYS + OO },
+ { "listcerts", no_argument, NULL, LST_CERTS + OO },
+ { "listcacerts", no_argument, NULL, LST_CACERTS + OO },
+ { "listacerts", no_argument, NULL, LST_ACERTS + OO },
+ { "listaacerts", no_argument, NULL, LST_AACERTS + OO },
+ { "listocspcerts", no_argument, NULL, LST_OCSPCERTS + OO },
+ { "listgroups", no_argument, NULL, LST_GROUPS + OO },
+ { "listcainfos", no_argument, NULL, LST_CAINFOS + OO },
+ { "listcrls", no_argument, NULL, LST_CRLS + OO },
+ { "listocsp", no_argument, NULL, LST_OCSP + OO },
+ { "listcards", no_argument, NULL, LST_CARDS + OO },
+ { "listall", no_argument, NULL, LST_ALL + OO },
+
+ /* options for an end description */
+
+ { "host", required_argument, NULL, END_HOST + OO },
+ { "id", required_argument, NULL, END_ID + OO },
+ { "cert", required_argument, NULL, END_CERT + OO },
+ { "ca", required_argument, NULL, END_CA + OO },
+ { "sendcert", required_argument, NULL, END_SENDCERT + OO },
+ { "groups", required_argument, NULL, END_GROUPS + OO },
+ { "ikeport", required_argument, NULL, END_IKEPORT + OO + NUMERIC_ARG },
+ { "nexthop", required_argument, NULL, END_NEXTHOP + OO },
+ { "client", required_argument, NULL, END_CLIENT + OO },
+ { "clientwithin", required_argument, NULL, END_CLIENTWITHIN + OO },
+ { "clientprotoport", required_argument, NULL, END_CLIENTPROTOPORT + OO },
+ { "dnskeyondemand", no_argument, NULL, END_DNSKEYONDEMAND + OO },
+ { "srcip", required_argument, NULL, END_SRCIP + OO },
+ { "hostaccess", no_argument, NULL, END_HOSTACCESS + OO },
+ { "updown", required_argument, NULL, END_UPDOWN + OO },
+
+ /* options for a connection description */
+
+ { "to", no_argument, NULL, CD_TO + OO },
+
+ { "psk", no_argument, NULL, CD_PSK + OO },
+ { "rsasig", no_argument, NULL, CD_RSASIG + OO },
+
+ { "encrypt", no_argument, NULL, CD_ENCRYPT + OO },
+ { "authenticate", no_argument, NULL, CD_AUTHENTICATE + OO },
+ { "compress", no_argument, NULL, CD_COMPRESS + OO },
+ { "tunnel", no_argument, NULL, CD_TUNNEL + OO },
+ { "tunnelipv4", no_argument, NULL, CD_TUNNELIPV4 + OO },
+ { "tunnelipv6", no_argument, NULL, CD_TUNNELIPV6 + OO },
+ { "pfs", no_argument, NULL, CD_PFS + OO },
+ { "disablearrivalcheck", no_argument, NULL, CD_DISABLEARRIVALCHECK + OO },
+ { "initiateontraffic", no_argument, NULL
+ , CD_SHUNT0 + (POLICY_SHUNT_TRAP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
+ { "pass", no_argument, NULL
+ , CD_SHUNT0 + (POLICY_SHUNT_PASS >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
+ { "drop", no_argument, NULL
+ , CD_SHUNT0 + (POLICY_SHUNT_DROP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
+ { "reject", no_argument, NULL
+ , CD_SHUNT0 + (POLICY_SHUNT_REJECT >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
+ { "failnone", no_argument, NULL
+ , CD_FAIL0 + (POLICY_FAIL_NONE >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
+ { "failpass", no_argument, NULL
+ , CD_FAIL0 + (POLICY_FAIL_PASS >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
+ { "faildrop", no_argument, NULL
+ , CD_FAIL0 + (POLICY_FAIL_DROP >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
+ { "failreject", no_argument, NULL
+ , CD_FAIL0 + (POLICY_FAIL_REJECT >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
+ { "dontrekey", no_argument, NULL, CD_DONT_REKEY + OO },
+ { "ipv4", no_argument, NULL, CD_CONNIPV4 + OO },
+ { "ipv6", no_argument, NULL, CD_CONNIPV6 + OO },
+
+ { "ikelifetime", required_argument, NULL, CD_IKELIFETIME + OO + NUMERIC_ARG },
+ { "ipseclifetime", required_argument, NULL, CD_IPSECLIFETIME + OO + NUMERIC_ARG },
+ { "rekeymargin", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },
+ { "rekeywindow", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG }, /* OBSOLETE */
+ { "rekeyfuzz", required_argument, NULL, CD_RKFUZZ + OO + NUMERIC_ARG },
+ { "keyingtries", required_argument, NULL, CD_KTRIES + OO + NUMERIC_ARG },
+ { "dpdaction", required_argument, NULL, CD_DPDACTION + OO },
+ { "dpddelay", required_argument, NULL, CD_DPDDELAY + OO + NUMERIC_ARG },
+ { "dpdtimeout", required_argument, NULL, CD_DPDTIMEOUT + OO + NUMERIC_ARG },
+ { "ike", required_argument, NULL, CD_IKE + OO },
+ { "pfsgroup", required_argument, NULL, CD_PFSGROUP + OO },
+ { "esp", required_argument, NULL, CD_ESP + OO },
+
+ /* options for a ca description */
+
+ { "caname", required_argument, NULL, CA_NAME + OO },
+ { "cacert", required_argument, NULL, CA_CERT + OO },
+ { "ldaphost", required_argument, NULL, CA_LDAPHOST + OO },
+ { "ldapbase", required_argument, NULL, CA_LDAPBASE + OO },
+ { "crluri", required_argument, NULL, CA_CRLURI + OO },
+ { "crluri2", required_argument, NULL, CA_CRLURI2 + OO },
+ { "ocspuri", required_argument, NULL, CA_OCSPURI + OO },
+ { "strictcrlpolicy", no_argument, NULL, CA_STRICT + OO },
+
+#ifdef DEBUG
+ { "debug-none", no_argument, NULL, DBGOPT_NONE + OO },
+ { "debug-all]", no_argument, NULL, DBGOPT_ALL + OO },
+ { "debug-raw", no_argument, NULL, DBGOPT_RAW + OO },
+ { "debug-crypt", no_argument, NULL, DBGOPT_CRYPT + OO },
+ { "debug-parsing", no_argument, NULL, DBGOPT_PARSING + OO },
+ { "debug-emitting", no_argument, NULL, DBGOPT_EMITTING + OO },
+ { "debug-control", no_argument, NULL, DBGOPT_CONTROL + OO },
+ { "debug-lifecycle", no_argument, NULL, DBGOPT_LIFECYCLE + OO },
+ { "debug-klips", no_argument, NULL, DBGOPT_KLIPS + OO },
+ { "debug-dns", no_argument, NULL, DBGOPT_DNS + OO },
+ { "debug-natt", no_argument, NULL, DBGOPT_NATT + OO },
+ { "debug-oppo", no_argument, NULL, DBGOPT_OPPO + OO },
+ { "debug-controlmore", no_argument, NULL, DBGOPT_CONTROLMORE + OO },
+ { "debug-private", no_argument, NULL, DBGOPT_PRIVATE + OO },
+
+ { "impair-delay-adns-key-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER + OO },
+ { "impair-delay-adns-txt-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER + OO },
+ { "impair-bust-mi2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MI2 + OO },
+ { "impair-bust-mr2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MR2 + OO },
+#endif
+# undef OO
+ { 0,0,0,0 }
+};
+
+struct sockaddr_un ctl_addr = { AF_UNIX, DEFAULT_CTLBASE CTL_SUFFIX };
+
+/* helper variables and function to encode strings from whack message */
+
+static char
+ *next_str,
+ *str_roof;
+
+static bool
+pack_str(char **p)
+{
+ const char *s = *p == NULL? "" : *p; /* note: NULL becomes ""! */
+ size_t len = strlen(s) + 1;
+
+ if (str_roof - next_str < (ptrdiff_t)len)
+ {
+ return FALSE; /* fishy: no end found */
+ }
+ else
+ {
+ strcpy(next_str, s);
+ next_str += len;
+ *p = NULL; /* don't send pointers on the wire! */
+ return TRUE;
+ }
+}
+
+static void
+check_life_time(time_t life, time_t limit, const char *which
+, const whack_message_t *msg)
+{
+ time_t mint = msg->sa_rekey_margin * (100 + msg->sa_rekey_fuzz) / 100;
+
+ if (life > limit)
+ {
+ char buf[200]; /* arbitrary limit */
+
+ snprintf(buf, sizeof(buf)
+ , "%s [%lu seconds] must be less than %lu seconds"
+ , which, (unsigned long)life, (unsigned long)limit);
+ diag(buf);
+ }
+ if ((msg->policy & POLICY_DONT_REKEY) == LEMPTY && life <= mint)
+ {
+ char buf[200]; /* arbitrary limit */
+
+ snprintf(buf, sizeof(buf)
+ , "%s [%lu] must be greater than"
+ " rekeymargin*(100+rekeyfuzz)/100 [%lu*(100+%lu)/100 = %lu]"
+ , which
+ , (unsigned long)life
+ , (unsigned long)msg->sa_rekey_margin
+ , (unsigned long)msg->sa_rekey_fuzz
+ , (unsigned long)mint);
+ diag(buf);
+ }
+}
+
+static void
+clear_end(whack_end_t *e)
+{
+ zero(e);
+ e->id = NULL;
+ e->cert = NULL;
+ e->ca = NULL;
+ e->updown = NULL;
+ e->host_port = IKE_UDP_PORT;
+}
+
+static void
+update_ports(whack_message_t *m)
+{
+ int port;
+
+ if (m->left.port != 0) {
+ port = htons(m->left.port);
+ setportof(port, &m->left.host_addr);
+ setportof(port, &m->left.client.addr);
+ }
+ if (m->right.port != 0) {
+ port = htons(m->right.port);
+ setportof(port, &m->right.host_addr);
+ setportof(port, &m->right.client.addr);
+ }
+}
+
+static void
+check_end(whack_end_t *this, whack_end_t *that
+, bool default_nexthop, sa_family_t caf, sa_family_t taf)
+{
+ if (caf != addrtypeof(&this->host_addr))
+ diag("address family of host inconsistent");
+
+ if (default_nexthop)
+ {
+ if (isanyaddr(&that->host_addr))
+ diag("our nexthop must be specified when other host is a %any or %opportunistic");
+ this->host_nexthop = that->host_addr;
+ }
+
+ if (caf != addrtypeof(&this->host_nexthop))
+ diag("address family of nexthop inconsistent");
+
+ if (this->has_client)
+ {
+ if (taf != subnettypeof(&this->client))
+ diag("address family of client subnet inconsistent");
+ }
+ else
+ {
+ /* fill in anyaddr-anyaddr as (missing) client subnet */
+ ip_address cn;
+
+ diagq(anyaddr(caf, &cn), NULL);
+ diagq(rangetosubnet(&cn, &cn, &this->client), NULL);
+ }
+
+ /* fill in anyaddr if source IP is not defined */
+ if (!this->has_srcip)
+ diagq(anyaddr(caf, &this->host_srcip), optarg);
+
+ /* check protocol */
+ if (this->protocol != that->protocol)
+ diag("the protocol for leftprotoport and rightprotoport must be the same");
+}
+
+static void
+get_secret(int sock)
+{
+ const char *buf, *secret;
+ int len;
+
+ fflush(stdout);
+ usleep(20000); /* give fflush time for flushing */
+ buf = getpass("Enter: ");
+ secret = (buf == NULL)? "" : buf;
+
+ /* send the secret to pluto */
+ len = strlen(secret) + 1;
+ if (write(sock, secret, len) != len)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack: write() failed (%d %s)\n", e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+}
+
+/* This is a hack for initiating ISAKMP exchanges. */
+
+int
+main(int argc, char **argv)
+{
+ whack_message_t msg;
+ char esp_buf[256]; /* uses snprintf */
+ lset_t
+ opts_seen = LEMPTY,
+ sc_seen = LEMPTY,
+ lst_seen = LEMPTY,
+ cd_seen = LEMPTY,
+ ca_seen = LEMPTY,
+ end_seen = LEMPTY,
+ end_seen_before_to = LEMPTY;
+ const char
+ *af_used_by = NULL,
+ *tunnel_af_used_by = NULL;
+
+ /* check division of numbering space */
+#ifdef DEBUG
+ assert(OPTION_OFFSET + DBGOPT_LAST < NUMERIC_ARG);
+#else
+ assert(OPTION_OFFSET + CA_LAST < NUMERIC_ARG);
+#endif
+ assert(OPT_LAST - OPT_FIRST < (sizeof opts_seen * BITS_PER_BYTE));
+ assert(SC_LAST - SC_FIRST < (sizeof sc_seen * BITS_PER_BYTE));
+ assert(LST_LAST - LST_FIRST < (sizeof lst_seen * BITS_PER_BYTE));
+ assert(END_LAST - END_FIRST < (sizeof end_seen * BITS_PER_BYTE));
+ assert(CD_LAST - CD_FIRST < (sizeof cd_seen * BITS_PER_BYTE));
+ assert(CA_LAST - CA_FIRST < (sizeof ca_seen * BITS_PER_BYTE));
+#ifdef DEBUG /* must be last so others are less than (sizeof cd_seen * BITS_PER_BYTE) to fit in lset_t */
+ assert(DBGOPT_LAST - DBGOPT_FIRST < (sizeof cd_seen * BITS_PER_BYTE));
+#endif
+ /* check that POLICY bit assignment matches with CD_ */
+ assert(LELEM(CD_DONT_REKEY - CD_POLICY_FIRST) == POLICY_DONT_REKEY);
+
+ zero(&msg);
+
+ clear_end(&msg.right); /* left set from this after --to */
+
+ msg.name = NULL;
+ msg.keyid = NULL;
+ msg.keyval.ptr = NULL;
+ msg.esp = NULL;
+ msg.ike = NULL;
+ msg.pfsgroup = NULL;
+
+ msg.sa_ike_life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT;
+ msg.sa_ipsec_life_seconds = PLUTO_SA_LIFE_DURATION_DEFAULT;
+ msg.sa_rekey_margin = SA_REPLACEMENT_MARGIN_DEFAULT;
+ msg.sa_rekey_fuzz = SA_REPLACEMENT_FUZZ_DEFAULT;
+ msg.sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT;
+
+ msg.addr_family = AF_INET;
+ msg.tunnel_addr_family = AF_INET;
+
+ msg.cacert = NULL;
+ msg.ldaphost = NULL;
+ msg.ldapbase = NULL;
+ msg.crluri = NULL;
+ msg.crluri2 = NULL;
+ msg.ocspuri = NULL;
+
+ for (;;)
+ {
+ int long_index;
+ unsigned long opt_whole = 0; /* numeric argument for some flags */
+
+ /* Note: we don't like the way short options get parsed
+ * by getopt_long, so we simply pass an empty string as
+ * the list. It could be "hp:d:c:o:eatfs" "NARXPECK".
+ */
+ int c = getopt_long(argc, argv, "", long_opts, &long_index) - OPTION_OFFSET;
+ int aux = 0;
+
+ /* decode a numeric argument, if expected */
+ if (0 <= c)
+ {
+ if (c & NUMERIC_ARG)
+ {
+ char *endptr;
+
+ c -= NUMERIC_ARG;
+ opt_whole = strtoul(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg)
+ diagq("badly formed numeric argument", optarg);
+ }
+ if (c >= (1 << AUX_SHIFT))
+ {
+ aux = c >> AUX_SHIFT;
+ c -= aux << AUX_SHIFT;
+ }
+ }
+
+ /* per-class option processing */
+ if (0 <= c && c <= OPT_LAST)
+ {
+ /* OPT_* options get added to opts_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c);
+
+ if (opts_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ opts_seen |= f;
+ }
+ else if (SC_FIRST <= c && c <= SC_LAST)
+ {
+ /* SC_* options get added to sc_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - SC_FIRST);
+
+ if (sc_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ sc_seen |= f;
+ }
+ else if (LST_FIRST <= c && c <= LST_LAST)
+ {
+ /* LST_* options get added to lst_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - LST_FIRST);
+
+ if (lst_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ lst_seen |= f;
+ }
+#ifdef DEBUG
+ else if (DBGOPT_FIRST <= c && c <= DBGOPT_LAST)
+ {
+ msg.whack_options = TRUE;
+ }
+#endif
+ else if (END_FIRST <= c && c <= END_LAST)
+ {
+ /* END_* options are added to end_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - END_FIRST);
+
+ if (end_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ end_seen |= f;
+ opts_seen |= LELEM(OPT_CD);
+ }
+ else if (CD_FIRST <= c && c <= CD_LAST)
+ {
+ /* CD_* options are added to cd_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - CD_FIRST);
+
+ if (cd_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ cd_seen |= f;
+ opts_seen |= LELEM(OPT_CD);
+ }
+ else if (CA_FIRST <= c && c <= CA_LAST)
+ {
+ /* CA_* options are added to ca_seen.
+ * Reject repeated options (unless later code intervenes).
+ */
+ lset_t f = LELEM(c - CA_FIRST);
+
+ if (ca_seen & f)
+ diagq("duplicated flag", long_opts[long_index].name);
+ ca_seen |= f;
+ }
+
+ /* Note: "break"ing from switch terminates loop.
+ * most cases should end with "continue".
+ */
+ switch (c)
+ {
+ case EOF - OPTION_OFFSET: /* end of flags */
+ break;
+
+ case 0 - OPTION_OFFSET: /* long option already handled */
+ continue;
+
+ case ':' - OPTION_OFFSET: /* diagnostic already printed by getopt_long */
+ case '?' - OPTION_OFFSET: /* diagnostic already printed by getopt_long */
+ diag(NULL); /* print no additional diagnostic, but exit sadly */
+ break; /* not actually reached */
+
+ case 'h' - OPTION_OFFSET: /* --help */
+ help();
+ return 0; /* GNU coding standards say to stop here */
+
+ case 'v' - OPTION_OFFSET: /* --version */
+ {
+ const char **sp = ipsec_copyright_notice();
+
+ printf("%s\n", ipsec_version_string());
+ for (; *sp != NULL; sp++)
+ puts(*sp);
+ }
+ return 0; /* GNU coding standards say to stop here */
+
+ case 'l' - OPTION_OFFSET: /* --label <string> */
+ label = optarg; /* remember for diagnostics */
+ continue;
+
+ case '+' - OPTION_OFFSET: /* --optionsfrom <filename> */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ continue;
+
+ /* the rest of the options combine in complex ways */
+
+ case OPT_CTLBASE: /* --port <ctlbase> */
+ if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path)
+ , "%s%s", optarg, CTL_SUFFIX) == -1)
+ diag("<ctlbase>" CTL_SUFFIX " must be fit in a sun_addr");
+ continue;
+
+ case OPT_NAME: /* --name <connection-name> */
+ name = optarg;
+ msg.name = optarg;
+ continue;
+
+ case OPT_KEYID: /* --keyid <identity> */
+ msg.whack_key = !msg.whack_sc_op;
+ msg.keyid = optarg; /* decoded by Pluto */
+ continue;
+
+ case OPT_MYID: /* --myid <identity> */
+ msg.whack_myid = TRUE;
+ msg.myid = optarg; /* decoded by Pluto */
+ continue;
+
+ case OPT_ADDKEY: /* --addkey */
+ msg.whack_addkey = TRUE;
+ continue;
+
+ case OPT_PUBKEYRSA: /* --pubkeyrsa <key> */
+ {
+ static char keyspace[RSA_MAX_ENCODING_BYTES]; /* room for 8K bit key */
+ char diag_space[TTODATAV_BUF];
+ const char *ugh = ttodatav(optarg, 0, 0
+ , keyspace, sizeof(keyspace)
+ , &msg.keyval.len, diag_space, sizeof(diag_space)
+ , TTODATAV_SPACECOUNTS);
+
+ if (ugh != NULL)
+ {
+ char ugh_space[80]; /* perhaps enough space */
+
+ snprintf(ugh_space, sizeof(ugh_space)
+ , "RSA public-key data malformed (%s)", ugh);
+ diagq(ugh_space, optarg);
+ }
+ msg.pubkey_alg = PUBKEY_ALG_RSA;
+ msg.keyval.ptr = keyspace;
+ }
+ continue;
+
+ case OPT_ROUTE: /* --route */
+ msg.whack_route = TRUE;
+ continue;
+
+ case OPT_UNROUTE: /* --unroute */
+ msg.whack_unroute = TRUE;
+ continue;
+
+ case OPT_INITIATE: /* --initiate */
+ msg.whack_initiate = TRUE;
+ continue;
+
+ case OPT_TERMINATE: /* --terminate */
+ msg.whack_terminate = TRUE;
+ continue;
+
+ case OPT_DELETE: /* --delete */
+ msg.whack_delete = TRUE;
+ continue;
+
+ case OPT_DELETESTATE: /* --deletestate <state_object_number> */
+ msg.whack_deletestate = TRUE;
+ msg.whack_deletestateno = opt_whole;
+ continue;
+
+ case OPT_DELETECRASH: /* --crash <ip-address> */
+ msg.whack_crash = TRUE;
+ tunnel_af_used_by = long_opts[long_index].name;
+ diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.whack_crash_peer), optarg);
+ if (isanyaddr(&msg.whack_crash_peer))
+ diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg);
+ continue;
+
+ case OPT_LISTEN: /* --listen */
+ msg.whack_listen = TRUE;
+ continue;
+
+ case OPT_UNLISTEN: /* --unlisten */
+ msg.whack_unlisten = TRUE;
+ continue;
+
+ case OPT_PURGEOCSP: /* --purgeocsp */
+ msg.whack_purgeocsp = TRUE;
+ continue;
+
+ case OPT_REREADSECRETS: /* --rereadsecrets */
+ case OPT_REREADCACERTS: /* --rereadcacerts */
+ case OPT_REREADAACERTS: /* --rereadaacerts */
+ case OPT_REREADOCSPCERTS: /* --rereadocspcerts */
+ case OPT_REREADACERTS: /* --rereadacerts */
+ case OPT_REREADCRLS: /* --rereadcrls */
+ msg.whack_reread |= LELEM(c-OPT_REREADSECRETS);
+ continue;
+
+ case OPT_REREADALL: /* --rereadall */
+ msg.whack_reread = REREAD_ALL;
+ continue;
+
+ case OPT_STATUSALL: /* --statusall */
+ msg.whack_statusall = TRUE;
+
+ case OPT_STATUS: /* --status */
+ msg.whack_status = TRUE;
+ continue;
+
+ case OPT_SHUTDOWN: /* --shutdown */
+ msg.whack_shutdown = TRUE;
+ continue;
+
+ case OPT_OPPO_HERE: /* --oppohere <ip-address> */
+ tunnel_af_used_by = long_opts[long_index].name;
+ diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.oppo_my_client), optarg);
+ if (isanyaddr(&msg.oppo_my_client))
+ diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg);
+ continue;
+
+ case OPT_OPPO_THERE: /* --oppohere <ip-address> */
+ tunnel_af_used_by = long_opts[long_index].name;
+ diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.oppo_peer_client), optarg);
+ if (isanyaddr(&msg.oppo_peer_client))
+ diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg);
+ continue;
+
+ case OPT_ASYNC:
+ msg.whack_async = TRUE;
+ continue;
+
+ /* Smartcard options */
+
+ case SC_ENCRYPT: /* --scencrypt <plaintext data> */
+ case SC_DECRYPT: /* --scdecrypt <encrypted data> */
+ msg.whack_sc_op = 1 + c - SC_ENCRYPT;
+ msg.whack_key = FALSE;
+ msg.sc_data = optarg;
+ continue;
+
+ case SC_INBASE: /* --inform <format> */
+ case SC_OUTBASE: /* --outform <format> */
+ {
+ int base = 0;
+
+ if (streq(optarg, "16") || strcaseeq(optarg, "hex"))
+ base = 16;
+ else if (streq(optarg, "64") || strcaseeq(optarg, "base64"))
+ base = 64;
+ else if (streq(optarg, "256") || strcaseeq(optarg, "text")
+ || strcaseeq(optarg, "ascii"))
+ base = 256;
+ else
+ diagq("not a valid base", optarg);
+
+ if (c == SC_INBASE)
+ msg.inbase = base;
+ else
+ msg.outbase = base;
+ }
+ continue;
+
+ /* List options */
+
+ case LST_UTC: /* --utc */
+ msg.whack_utc = TRUE;
+ continue;
+
+ case LST_ALGS: /* --listalgs */
+ case LST_PUBKEYS: /* --listpubkeys */
+ case LST_CERTS: /* --listcerts */
+ case LST_CACERTS: /* --listcacerts */
+ case LST_ACERTS: /* --listacerts */
+ case LST_AACERTS: /* --listaacerts */
+ case LST_OCSPCERTS: /* --listocspcerts */
+ case LST_GROUPS: /* --listgroups */
+ case LST_CAINFOS: /* --listcainfos */
+ case LST_CRLS: /* --listcrls */
+ case LST_OCSP: /* --listocsp */
+ case LST_CARDS: /* --listcards */
+ msg.whack_list |= LELEM(c - LST_ALGS);
+ continue;
+
+ case LST_ALL: /* --listall */
+ msg.whack_list = LIST_ALL;
+ continue;
+
+ /* Connection Description options */
+
+ case END_HOST: /* --host <ip-address> */
+ {
+ lset_t new_policy = LEMPTY;
+
+ af_used_by = long_opts[long_index].name;
+ diagq(anyaddr(msg.addr_family, &msg.right.host_addr), optarg);
+ if (streq(optarg, "%any"))
+ {
+ }
+ else if (streq(optarg, "%opportunistic"))
+ {
+ /* always use tunnel mode; mark as opportunistic */
+ new_policy |= POLICY_TUNNEL | POLICY_OPPO;
+ }
+ else if (streq(optarg, "%group"))
+ {
+ /* always use tunnel mode; mark as group */
+ new_policy |= POLICY_TUNNEL | POLICY_GROUP;
+ }
+ else if (streq(optarg, "%opportunisticgroup"))
+ {
+ /* always use tunnel mode; mark as opportunistic */
+ new_policy |= POLICY_TUNNEL | POLICY_OPPO | POLICY_GROUP;
+ }
+ else
+ {
+ diagq(ttoaddr(optarg, 0, msg.addr_family
+ , &msg.right.host_addr), optarg);
+ }
+
+ msg.policy |= new_policy;
+
+ if (new_policy & (POLICY_OPPO | POLICY_GROUP))
+ {
+ if (!LHAS(end_seen, END_CLIENT - END_FIRST))
+ {
+ /* set host to 0.0.0 and --client to 0.0.0.0/0
+ * or IPV6 equivalent
+ */
+ ip_address any;
+
+ tunnel_af_used_by = optarg;
+ diagq(anyaddr(msg.tunnel_addr_family, &any), optarg);
+ diagq(initsubnet(&any, 0, '0', &msg.right.client), optarg);
+ }
+ msg.right.has_client = TRUE;
+ }
+ if (new_policy & POLICY_GROUP)
+ {
+ /* client subnet must not be specified by user:
+ * it will come from the group's file.
+ */
+ if (LHAS(end_seen, END_CLIENT - END_FIRST))
+ diag("--host %group clashes with --client");
+
+ end_seen |= LELEM(END_CLIENT - END_FIRST);
+ }
+ if (new_policy & POLICY_OPPO)
+ msg.right.key_from_DNS_on_demand = TRUE;
+ continue;
+ }
+ case END_ID: /* --id <identity> */
+ msg.right.id = optarg; /* decoded by Pluto */
+ continue;
+
+ case END_CERT: /* --cert <path> */
+ msg.right.cert = optarg; /* decoded by Pluto */
+ continue;
+
+ case END_CA: /* --ca <distinguished name> */
+ msg.right.ca = optarg; /* decoded by Pluto */
+ continue;
+
+ case END_SENDCERT:
+ if (streq(optarg, "yes") || streq(optarg, "always"))
+ {
+ msg.right.sendcert = CERT_ALWAYS_SEND;
+ }
+ else if (streq(optarg, "no") || streq(optarg, "never"))
+ {
+ msg.right.sendcert = CERT_NEVER_SEND;
+ }
+ else if (streq(optarg, "ifasked"))
+ {
+ msg.right.sendcert = CERT_SEND_IF_ASKED;
+ }
+ else
+ {
+ diagq("whack sendcert value is not legal", optarg);
+ }
+ continue;
+
+ case END_GROUPS:/* --groups <access control groups> */
+ msg.right.groups = optarg; /* decoded by Pluto */
+ continue;
+
+ case END_IKEPORT: /* --ikeport <port-number> */
+ if (opt_whole<=0 || opt_whole >= 0x10000)
+ diagq("<port-number> must be a number between 1 and 65535", optarg);
+ msg.right.host_port = opt_whole;
+ continue;
+
+ case END_NEXTHOP: /* --nexthop <ip-address> */
+ af_used_by = long_opts[long_index].name;
+ if (streq(optarg, "%direct"))
+ diagq(anyaddr(msg.addr_family
+ , &msg.right.host_nexthop), optarg);
+ else
+ diagq(ttoaddr(optarg, 0, msg.addr_family
+ , &msg.right.host_nexthop), optarg);
+ continue;
+
+ case END_SRCIP: /* --srcip <ip-address> */
+ af_used_by = long_opts[long_index].name;
+ if (streq(optarg, "%modeconfig") || streq(optarg, "%modecfg"))
+ {
+ msg.right.modecfg = TRUE;
+ }
+ else
+ {
+ diagq(ttoaddr(optarg, 0, msg.addr_family
+ , &msg.right.host_srcip), optarg);
+ msg.right.has_srcip = TRUE;
+ }
+ msg.policy |= POLICY_TUNNEL; /* srcip => tunnel */
+ continue;
+
+ case END_CLIENT: /* --client <subnet> */
+ if (end_seen & LELEM(END_CLIENTWITHIN - END_FIRST))
+ diag("--client conflicts with --clientwithin");
+ tunnel_af_used_by = long_opts[long_index].name;
+#ifdef VIRTUAL_IP
+ if ((strlen(optarg) >= 6 && strncmp(optarg,"vhost:",6) == 0)
+ || (strlen(optarg) >= 5 && strncmp(optarg,"vnet:",5) == 0))
+ {
+ msg.right.virt = optarg;
+ }
+ else
+ {
+ diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg);
+ msg.right.has_client = TRUE;
+ }
+#else
+ diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg);
+ msg.right.has_client = TRUE;
+#endif
+ msg.policy |= POLICY_TUNNEL; /* client => tunnel */
+ continue;
+
+ case END_CLIENTWITHIN: /* --clienwithin <address range> */
+ if (end_seen & LELEM(END_CLIENT - END_FIRST))
+ diag("--clientwithin conflicts with --client");
+ tunnel_af_used_by = long_opts[long_index].name;
+ diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg);
+ msg.right.has_client = TRUE;
+ msg.policy |= POLICY_TUNNEL; /* client => tunnel */
+ msg.right.has_client_wildcard = TRUE;
+ continue;
+
+ case END_CLIENTPROTOPORT: /* --clientprotoport <protocol>/<port> */
+ diagq(ttoprotoport(optarg, 0, &msg.right.protocol, &msg.right.port
+ , &msg.right.has_port_wildcard), optarg);
+ continue;
+
+ case END_DNSKEYONDEMAND: /* --dnskeyondemand */
+ msg.right.key_from_DNS_on_demand = TRUE;
+ continue;
+
+ case END_HOSTACCESS: /* --hostaccess */
+ msg.right.hostaccess = TRUE;
+ continue;
+
+ case END_UPDOWN: /* --updown <updown> */
+ msg.right.updown = optarg;
+ continue;
+
+ case CD_TO: /* --to */
+ /* process right end, move it to left, reset it */
+ if (!LHAS(end_seen, END_HOST - END_FIRST))
+ diag("connection missing --host before --to");
+ msg.left = msg.right;
+ clear_end(&msg.right);
+ end_seen_before_to = end_seen;
+ end_seen = LEMPTY;
+ continue;
+
+ case CD_PSK: /* --psk */
+ case CD_RSASIG: /* --rsasig */
+ case CD_ENCRYPT: /* --encrypt */
+ case CD_AUTHENTICATE: /* --authenticate */
+ case CD_COMPRESS: /* --compress */
+ case CD_TUNNEL: /* --tunnel */
+ case CD_PFS: /* --pfs */
+ case CD_DISABLEARRIVALCHECK: /* --disablearrivalcheck */
+ case CD_DONT_REKEY: /* --donotrekey */
+ msg.policy |= LELEM(c - CD_POLICY_FIRST);
+ continue;
+
+ /* --initiateontraffic
+ * --pass
+ * --drop
+ * --reject
+ */
+ case CD_SHUNT0:
+ msg.policy = (msg.policy & ~POLICY_SHUNT_MASK)
+ | ((lset_t)aux << POLICY_SHUNT_SHIFT);
+ continue;
+
+ /* --failnone
+ * --failpass
+ * --faildrop
+ * --failreject
+ */
+ case CD_FAIL0:
+ msg.policy = (msg.policy & ~POLICY_FAIL_MASK)
+ | ((lset_t)aux << POLICY_FAIL_SHIFT);
+ continue;
+
+ case CD_IKELIFETIME: /* --ikelifetime <seconds> */
+ msg.sa_ike_life_seconds = opt_whole;
+ continue;
+
+ case CD_IPSECLIFETIME: /* --ipseclifetime <seconds> */
+ msg.sa_ipsec_life_seconds = opt_whole;
+ continue;
+
+ case CD_RKMARGIN: /* --rekeymargin <seconds> */
+ msg.sa_rekey_margin = opt_whole;
+ continue;
+
+ case CD_RKFUZZ: /* --rekeyfuzz <percentage> */
+ msg.sa_rekey_fuzz = opt_whole;
+ continue;
+
+ case CD_KTRIES: /* --keyingtries <count> */
+ msg.sa_keying_tries = opt_whole;
+ continue;
+
+ case CD_DPDACTION:
+ if (streq(optarg, "none"))
+ msg.dpd_action = DPD_ACTION_NONE;
+ else if (streq(optarg, "clear"))
+ msg.dpd_action = DPD_ACTION_CLEAR;
+ else if (streq(optarg, "hold"))
+ msg.dpd_action = DPD_ACTION_HOLD;
+ else if (streq(optarg, "restart"))
+ msg.dpd_action = DPD_ACTION_RESTART;
+ else
+ msg.dpd_action = DPD_ACTION_UNKNOWN;
+ continue;
+
+ case CD_DPDDELAY:
+ msg.dpd_delay = opt_whole;
+ continue;
+
+ case CD_DPDTIMEOUT:
+ msg.dpd_timeout = opt_whole;
+ continue;
+
+ case CD_IKE: /* --ike <ike_alg1,ike_alg2,...> */
+ msg.ike = optarg;
+ continue;
+
+ case CD_PFSGROUP: /* --pfsgroup modpXXXX */
+ msg.pfsgroup = optarg;
+ continue;
+
+ case CD_ESP: /* --esp <esp_alg1,esp_alg2,...> */
+ msg.esp = optarg;
+ continue;
+
+ case CD_CONNIPV4:
+ if (LHAS(cd_seen, CD_CONNIPV6 - CD_FIRST))
+ diag("--ipv4 conflicts with --ipv6");
+
+ /* Since this is the default, the flag is redundant.
+ * So we don't need to set msg.addr_family
+ * and we don't need to check af_used_by
+ * and we don't have to consider defaulting tunnel_addr_family.
+ */
+ continue;
+
+ case CD_CONNIPV6:
+ if (LHAS(cd_seen, CD_CONNIPV4 - CD_FIRST))
+ diag("--ipv6 conflicts with --ipv4");
+
+ if (af_used_by != NULL)
+ diagq("--ipv6 must precede", af_used_by);
+
+ af_used_by = long_opts[long_index].name;
+ msg.addr_family = AF_INET6;
+
+ /* Consider defaulting tunnel_addr_family to AF_INET6.
+ * Do so only if it hasn't yet been specified or used.
+ */
+ if (LDISJOINT(cd_seen, LELEM(CD_TUNNELIPV4 - CD_FIRST) | LELEM(CD_TUNNELIPV6 - CD_FIRST))
+ && tunnel_af_used_by == NULL)
+ msg.tunnel_addr_family = AF_INET6;
+ continue;
+
+ case CD_TUNNELIPV4:
+ if (LHAS(cd_seen, CD_TUNNELIPV6 - CD_FIRST))
+ diag("--tunnelipv4 conflicts with --tunnelipv6");
+
+ if (tunnel_af_used_by != NULL)
+ diagq("--tunnelipv4 must precede", af_used_by);
+
+ msg.tunnel_addr_family = AF_INET;
+ continue;
+
+ case CD_TUNNELIPV6:
+ if (LHAS(cd_seen, CD_TUNNELIPV4 - CD_FIRST))
+ diag("--tunnelipv6 conflicts with --tunnelipv4");
+
+ if (tunnel_af_used_by != NULL)
+ diagq("--tunnelipv6 must precede", af_used_by);
+
+ msg.tunnel_addr_family = AF_INET6;
+ continue;
+
+ case CA_NAME: /* --caname <name> */
+ msg.name = optarg;
+ msg.whack_ca = TRUE;
+ continue;
+ case CA_CERT: /* --cacert <path> */
+ msg.cacert = optarg;
+ continue;
+ case CA_LDAPHOST: /* --ldaphost <hostname> */
+ msg.ldaphost = optarg;
+ continue;
+ case CA_LDAPBASE: /* --ldapbase <base> */
+ msg.ldapbase = optarg;
+ continue;
+ case CA_CRLURI: /* --crluri <uri> */
+ msg.crluri = optarg;
+ continue;
+ case CA_CRLURI2: /* --crluri2 <uri> */
+ msg.crluri2 = optarg;
+ continue;
+ case CA_OCSPURI: /* --ocspuri <uri> */
+ msg.ocspuri = optarg;
+ continue;
+ case CA_STRICT: /* --strictcrlpolicy */
+ msg.whack_strict = TRUE;
+ continue;
+
+#ifdef DEBUG
+ case DBGOPT_NONE: /* --debug-none */
+ msg.debugging = DBG_NONE;
+ continue;
+
+ case DBGOPT_ALL: /* --debug-all */
+ msg.debugging |= DBG_ALL; /* note: does not include PRIVATE */
+ continue;
+
+ case DBGOPT_RAW: /* --debug-raw */
+ case DBGOPT_CRYPT: /* --debug-crypt */
+ case DBGOPT_PARSING: /* --debug-parsing */
+ case DBGOPT_EMITTING: /* --debug-emitting */
+ case DBGOPT_CONTROL: /* --debug-control */
+ case DBGOPT_LIFECYCLE: /* --debug-lifecycle */
+ case DBGOPT_KLIPS: /* --debug-klips */
+ case DBGOPT_DNS: /* --debug-dns */
+ case DBGOPT_NATT: /* --debug-natt */
+ case DBGOPT_OPPO: /* --debug-oppo */
+ case DBGOPT_CONTROLMORE: /* --debug-controlmore */
+ case DBGOPT_PRIVATE: /* --debug-private */
+ case DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER: /* --impair-delay-adns-key-answer */
+ case DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER: /* --impair-delay-adns-txt-answer */
+ case DBGOPT_IMPAIR_BUST_MI2: /* --impair_bust_mi2 */
+ case DBGOPT_IMPAIR_BUST_MR2: /* --impair_bust_mr2 */
+ msg.debugging |= LELEM(c-DBGOPT_RAW);
+ continue;
+#endif
+ default:
+ assert(FALSE); /* unknown return value */
+ }
+ break;
+ }
+
+ if (optind != argc)
+ {
+ /* If you see this message unexpectedly, perhaps the
+ * case for the previous option ended with "break"
+ * instead of "continue"
+ */
+ diagq("unexpected argument", argv[optind]);
+ }
+
+ /* For each possible form of the command, figure out if an argument
+ * suggests whether that form was intended, and if so, whether all
+ * required information was supplied.
+ */
+
+ /* check opportunistic initiation simulation request */
+ switch (opts_seen & (LELEM(OPT_OPPO_HERE) | LELEM(OPT_OPPO_THERE)))
+ {
+ case LELEM(OPT_OPPO_HERE):
+ case LELEM(OPT_OPPO_THERE):
+ diag("--oppohere and --oppothere must be used together");
+ /*NOTREACHED*/
+ case LELEM(OPT_OPPO_HERE) | LELEM(OPT_OPPO_THERE):
+ msg.whack_oppo_initiate = TRUE;
+ if (LIN(cd_seen, LELEM(CD_TUNNELIPV4 - CD_FIRST) | LELEM(CD_TUNNELIPV6 - CD_FIRST)))
+ opts_seen &= ~LELEM(OPT_CD);
+ break;
+ }
+
+ /* check connection description */
+ if (LHAS(opts_seen, OPT_CD))
+ {
+ if (!LHAS(cd_seen, CD_TO-CD_FIRST))
+ diag("connection description option, but no --to");
+
+ if (!LHAS(end_seen, END_HOST-END_FIRST))
+ diag("connection missing --host after --to");
+
+ if (isanyaddr(&msg.left.host_addr)
+ && isanyaddr(&msg.right.host_addr))
+ diag("hosts cannot both be 0.0.0.0 or 0::0");
+
+ if (msg.policy & POLICY_OPPO)
+ {
+ if ((msg.policy & (POLICY_PSK | POLICY_RSASIG)) != POLICY_RSASIG)
+ diag("only RSASIG is supported for opportunism");
+ if ((msg.policy & POLICY_PFS) == 0)
+ diag("PFS required for opportunism");
+ if ((msg.policy & POLICY_ENCRYPT) == 0)
+ diag("encryption required for opportunism");
+ }
+
+ check_end(&msg.left, &msg.right, !LHAS(end_seen_before_to, END_NEXTHOP-END_FIRST)
+ , msg.addr_family, msg.tunnel_addr_family);
+
+ check_end(&msg.right, &msg.left, !LHAS(end_seen, END_NEXTHOP-END_FIRST)
+ , msg.addr_family, msg.tunnel_addr_family);
+
+ if (subnettypeof(&msg.left.client) != subnettypeof(&msg.right.client))
+ diag("endpoints clash: one is IPv4 and the other is IPv6");
+
+ if (NEVER_NEGOTIATE(msg.policy))
+ {
+ /* we think this is just a shunt (because he didn't specify
+ * a host authentication method). If he didn't specify a
+ * shunt type, he's probably gotten it wrong.
+ */
+ if ((msg.policy & POLICY_SHUNT_MASK) == POLICY_SHUNT_TRAP)
+ diag("non-shunt connection must have --psk or --rsasig or both");
+ }
+ else
+ {
+ /* not just a shunt: a real ipsec connection */
+ if ((msg.policy & POLICY_ID_AUTH_MASK) == LEMPTY)
+ diag("must specify --rsasig or --psk for a connection");
+
+ if (!HAS_IPSEC_POLICY(msg.policy)
+ && (msg.left.has_client || msg.right.has_client))
+ diag("must not specify clients for ISAKMP-only connection");
+ }
+
+ msg.whack_connection = TRUE;
+ }
+
+ /* decide whether --name is mandatory or forbidden */
+ if (!LDISJOINT(opts_seen
+ , LELEM(OPT_ROUTE) | LELEM(OPT_UNROUTE)
+ | LELEM(OPT_INITIATE) | LELEM(OPT_TERMINATE)
+ | LELEM(OPT_DELETE) | LELEM(OPT_CD)))
+ {
+ if (!LHAS(opts_seen, OPT_NAME) && !msg.whack_ca)
+ diag("missing --name <connection_name>");
+ }
+ else if (!msg.whack_options && !msg.whack_status)
+ {
+ if (LHAS(opts_seen, OPT_NAME))
+ diag("no reason for --name");
+ }
+
+ if (!LDISJOINT(opts_seen, LELEM(OPT_PUBKEYRSA) | LELEM(OPT_ADDKEY)))
+ {
+ if (!LHAS(opts_seen, OPT_KEYID))
+ diag("--addkey and --pubkeyrsa require --keyid");
+ }
+
+ if (!(msg.whack_connection || msg.whack_key || msg.whack_myid
+ || msg.whack_delete || msg.whack_deletestate
+ || msg.whack_initiate || msg.whack_oppo_initiate || msg.whack_terminate
+ || msg.whack_route || msg.whack_unroute || msg.whack_listen
+ || msg.whack_unlisten || msg.whack_list || msg.whack_purgeocsp || msg.whack_reread
+ || msg.whack_ca || msg.whack_status || msg.whack_options || msg.whack_shutdown
+ || msg.whack_sc_op))
+ {
+ diag("no action specified; try --help for hints");
+ }
+
+ update_ports(&msg);
+
+ /* tricky quick and dirty check for wild values */
+ if (msg.sa_rekey_margin != 0
+ && msg.sa_rekey_fuzz * msg.sa_rekey_margin * 4 / msg.sa_rekey_margin / 4
+ != msg.sa_rekey_fuzz)
+ diag("rekeymargin or rekeyfuzz values are so large that they cause oveflow");
+
+ check_life_time (msg.sa_ike_life_seconds, OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM
+ , "ikelifetime", &msg);
+
+ check_life_time(msg.sa_ipsec_life_seconds, SA_LIFE_DURATION_MAXIMUM
+ , "ipseclifetime", &msg);
+
+ if (msg.dpd_action == DPD_ACTION_UNKNOWN)
+ diag("dpdaction must be \"none\", \"clear\", \"hold\" or \"restart\"");
+
+ if (msg.dpd_action != DPD_ACTION_NONE)
+ {
+ if (msg.dpd_delay <= 0)
+ diag("dpddelay must be larger than zero");
+
+ if (msg.dpd_timeout <= 0)
+ diag("dpdtimeout must be larger than zero");
+
+ if (msg.dpd_timeout <= msg.dpd_delay)
+ diag("dpdtimeout must be larger than dpddelay");
+ }
+
+ /* pack strings for inclusion in message */
+ next_str = msg.string;
+ str_roof = &msg.string[sizeof(msg.string)];
+
+ /* build esp message as esp="<esp>;<pfsgroup>" */
+ if (msg.pfsgroup) {
+ snprintf(esp_buf, sizeof (esp_buf), "%s;%s",
+ msg.esp ? msg.esp : "",
+ msg.pfsgroup ? msg.pfsgroup : "");
+ msg.esp=esp_buf;
+ }
+ if (!pack_str(&msg.name) /* string 1 */
+ || !pack_str(&msg.left.id) /* string 2 */
+ || !pack_str(&msg.left.cert) /* string 3 */
+ || !pack_str(&msg.left.ca) /* string 4 */
+ || !pack_str(&msg.left.groups) /* string 5 */
+ || !pack_str(&msg.left.updown) /* string 6 */
+#ifdef VIRTUAL_IP
+ || !pack_str(&msg.left.virt)
+#endif
+ || !pack_str(&msg.right.id) /* string 7 */
+ || !pack_str(&msg.right.cert) /* string 8 */
+ || !pack_str(&msg.right.ca) /* string 9 */
+ || !pack_str(&msg.right.groups) /* string 10 */
+ || !pack_str(&msg.right.updown) /* string 11 */
+#ifdef VIRTUAL_IP
+ || !pack_str(&msg.right.virt)
+#endif
+ || !pack_str(&msg.keyid) /* string 12 */
+ || !pack_str(&msg.myid) /* string 13 */
+ || !pack_str(&msg.cacert) /* string 14 */
+ || !pack_str(&msg.ldaphost) /* string 15 */
+ || !pack_str(&msg.ldapbase) /* string 16 */
+ || !pack_str(&msg.crluri) /* string 17 */
+ || !pack_str(&msg.crluri2) /* string 18 */
+ || !pack_str(&msg.ocspuri) /* string 19 */
+ || !pack_str(&msg.ike) /* string 20 */
+ || !pack_str(&msg.esp) /* string 21 */
+ || !pack_str(&msg.sc_data) /* string 22 */
+ || str_roof - next_str < (ptrdiff_t)msg.keyval.len) /* chunk (sort of string 5) */
+ diag("too many bytes of strings to fit in message to pluto");
+
+ memcpy(next_str, msg.keyval.ptr, msg.keyval.len);
+ msg.keyval.ptr = NULL;
+ next_str += msg.keyval.len;
+
+ msg.magic = ((opts_seen & ~LELEM(OPT_SHUTDOWN))
+ | sc_seen | lst_seen | cd_seen | ca_seen) != LEMPTY
+ || msg.whack_options
+ ? WHACK_MAGIC : WHACK_BASIC_MAGIC;
+
+ /* send message to Pluto */
+ if (access(ctl_addr.sun_path, R_OK | W_OK) < 0)
+ {
+ int e = errno;
+
+ switch (e)
+ {
+ case EACCES:
+ fprintf(stderr, "whack: no right to communicate with pluto (access(\"%s\"))\n"
+ , ctl_addr.sun_path);
+ break;
+ case ENOENT:
+ fprintf(stderr, "whack: Pluto is not running (no \"%s\")\n"
+ , ctl_addr.sun_path);
+ break;
+ default:
+ fprintf(stderr, "whack: access(\"%s\") failed with %d %s\n"
+ , ctl_addr.sun_path, errno, strerror(e));
+ break;
+ }
+ exit(RC_WHACK_PROBLEM);
+ }
+ else
+ {
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ int exit_status = 0;
+ ssize_t len = next_str - (char *)&msg;
+
+ if (sock == -1)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack: socket() failed (%d %s)\n", e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+
+ if (connect(sock, (struct sockaddr *)&ctl_addr
+ , offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack:%s connect() for \"%s\" failed (%d %s)\n"
+ , e == ECONNREFUSED? " is Pluto running? " : ""
+ , ctl_addr.sun_path, e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+
+ if (write(sock, &msg, len) != len)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack: write() failed (%d %s)\n", e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+
+ /* for now, just copy reply back to stdout */
+
+ {
+ char buf[4097]; /* arbitrary limit on log line length */
+ char *be = buf;
+
+ for (;;)
+ {
+ char *ls = buf;
+ ssize_t rl = read(sock, be, (buf + sizeof(buf)-1) - be);
+
+ if (rl < 0)
+ {
+ int e = errno;
+
+ fprintf(stderr, "whack: read() failed (%d %s)\n", e, strerror(e));
+ exit(RC_WHACK_PROBLEM);
+ }
+ if (rl == 0)
+ {
+ if (be != buf)
+ fprintf(stderr, "whack: last line from pluto too long or unterminated\n");
+ break;
+ }
+
+ be += rl;
+ *be = '\0';
+
+ for (;;)
+ {
+ char *le = strchr(ls, '\n');
+
+ if (le == NULL)
+ {
+ /* move last, partial line to start of buffer */
+ memmove(buf, ls, be-ls);
+ be -= ls - buf;
+ break;
+ }
+
+ le++; /* include NL in line */
+ write(1, ls, le - ls);
+
+ /* figure out prefix number
+ * and how it should affect our exit status
+ */
+ {
+ unsigned long s = strtoul(ls, NULL, 10);
+
+ switch (s)
+ {
+ case RC_COMMENT:
+ case RC_LOG:
+ /* ignore */
+ break;
+ case RC_SUCCESS:
+ /* be happy */
+ exit_status = 0;
+ break;
+ case RC_ENTERSECRET:
+ get_secret(sock);
+ break;
+ /* case RC_LOG_SERIOUS: */
+ default:
+ /* pass through */
+ exit_status = s;
+ break;
+ }
+ }
+ ls = le;
+ }
+ }
+ }
+ return exit_status;
+ }
+}
diff --git a/programs/pluto/whack.h b/programs/pluto/whack.h
new file mode 100644
index 000000000..3086f1543
--- /dev/null
+++ b/programs/pluto/whack.h
@@ -0,0 +1,318 @@
+/* Structure of messages from whack to Pluto proper.
+ * Copyright (C) 1998-2001 D. Hugh Redelmeier.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: whack.h,v 1.16 2006/04/17 10:39:14 as Exp $
+ */
+
+#ifndef _WHACK_H
+#define _WHACK_H
+
+#include <freeswan.h>
+
+#include "smartcard.h"
+
+/* Since the message remains on one host, native representation is used.
+ * Think of this as horizontal microcode: all selected operations are
+ * to be done (in the order declared here).
+ *
+ * MAGIC is used to help detect version mismatches between whack and Pluto.
+ * Whenever the interface (i.e. this struct) changes in form or
+ * meaning, change this value (probably by changing the last number).
+ *
+ * If the command only requires basic actions (status or shutdown),
+ * it is likely that the relevant part of the message changes less frequently.
+ * Whack uses WHACK_BASIC_MAGIC in those cases.
+ *
+ * NOTE: no value of WHACK_BASIC_MAGIC may equal any value of WHACK_MAGIC.
+ * Otherwise certain version mismatches will not be detected.
+ */
+
+#define WHACK_BASIC_MAGIC (((((('w' << 8) + 'h') << 8) + 'k') << 8) + 24)
+#define WHACK_MAGIC (((((('w' << 8) + 'h') << 8) + 'k') << 8) + 26)
+
+typedef struct whack_end whack_end_t;
+
+/* struct whack_end is a lot like connection.h's struct end
+ * It differs because it is going to be shipped down a socket
+ * and because whack is a separate program from pluto.
+ */
+struct whack_end {
+ char *id; /* id string (if any) -- decoded by pluto */
+ char *cert; /* path string (if any) -- loaded by pluto */
+ char *ca; /* distinguished name string (if any) -- parsed by pluto */
+ char *groups; /* access control groups (if any) -- parsed by pluto */
+ ip_address
+ host_addr,
+ host_nexthop,
+ host_srcip;
+ ip_subnet client;
+
+ bool key_from_DNS_on_demand;
+ bool has_client;
+ bool has_client_wildcard;
+ bool has_port_wildcard;
+ bool has_srcip;
+ bool modecfg;
+ bool hostaccess;
+ certpolicy_t sendcert;
+ char *updown; /* string */
+ u_int16_t host_port; /* host order */
+ u_int16_t port; /* host order */
+ u_int8_t protocol;
+#ifdef VIRTUAL_IP
+ char *virt;
+#endif
+ };
+
+typedef struct whack_message whack_message_t;
+
+struct whack_message {
+ unsigned int magic;
+
+ /* for WHACK_STATUS: */
+ bool whack_status;
+ bool whack_statusall;
+
+
+ /* for WHACK_SHUTDOWN */
+ bool whack_shutdown;
+
+ /* END OF BASIC COMMANDS
+ * If you change anything earlier in this struct, update WHACK_BASIC_MAGIC.
+ */
+
+ /* name is used in connection, ca and initiate */
+ size_t name_len; /* string 1 */
+ char *name;
+
+ /* for WHACK_OPTIONS: */
+
+ bool whack_options;
+
+ lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
+
+ /* for WHACK_CONNECTION */
+
+ bool whack_connection;
+ bool whack_async;
+
+ lset_t policy;
+ time_t sa_ike_life_seconds;
+ time_t sa_ipsec_life_seconds;
+ time_t sa_rekey_margin;
+ unsigned long sa_rekey_fuzz;
+ unsigned long sa_keying_tries;
+
+ /* For DPD 3706 - Dead Peer Detection */
+ time_t dpd_delay;
+ time_t dpd_timeout;
+ dpd_action_t dpd_action;
+
+ /* note that each end contains string 2/5.id, string 3/6 cert,
+ * and string 4/7 updown
+ */
+ whack_end_t left;
+ whack_end_t right;
+
+ /* note: if the client is the gateway, the following must be equal */
+ sa_family_t addr_family; /* between gateways */
+ sa_family_t tunnel_addr_family; /* between clients */
+
+ char *ike; /* ike algo string (separated by commas) */
+ char *pfsgroup; /* pfsgroup will be "encapsulated" in esp string for pluto */
+ char *esp; /* esp algo string (separated by commas) */
+
+ /* for WHACK_KEY: */
+ bool whack_key;
+ bool whack_addkey;
+ char *keyid; /* string 8 */
+ enum pubkey_alg pubkey_alg;
+ chunk_t keyval; /* chunk */
+
+ /* for WHACK_MYID: */
+ bool whack_myid;
+ char *myid; /* string 7 */
+
+ /* for WHACK_ROUTE: */
+ bool whack_route;
+
+ /* for WHACK_UNROUTE: */
+ bool whack_unroute;
+
+ /* for WHACK_INITIATE: */
+ bool whack_initiate;
+
+ /* for WHACK_OPINITIATE */
+ bool whack_oppo_initiate;
+ ip_address oppo_my_client, oppo_peer_client;
+
+ /* for WHACK_TERMINATE: */
+ bool whack_terminate;
+
+ /* for WHACK_DELETE: */
+ bool whack_delete;
+
+ /* for WHACK_DELETESTATE: */
+ bool whack_deletestate;
+ so_serial_t whack_deletestateno;
+
+ /* for WHACK_LISTEN: */
+ bool whack_listen, whack_unlisten;
+
+ /* for WHACK_CRASH - note if a remote peer is known to have rebooted */
+ bool whack_crash;
+ ip_address whack_crash_peer;
+
+ /* for WHACK_LIST */
+ bool whack_utc;
+ lset_t whack_list;
+
+ /* for WHACK_PURGEOCSP */
+ bool whack_purgeocsp;
+
+ /* for WHACK_REREAD */
+ u_char whack_reread;
+
+ /* for WHACK_CA */
+ bool whack_ca;
+ bool whack_strict;
+
+ char *cacert;
+ char *ldaphost;
+ char *ldapbase;
+ char *crluri;
+ char *crluri2;
+ char *ocspuri;
+
+ /* for WHACK_SC_OP */
+ sc_op_t whack_sc_op;
+ int inbase, outbase;
+ char *sc_data;
+
+ /* space for strings (hope there is enough room):
+ * Note that pointers don't travel on wire.
+ * 1 connection name [name_len]
+ * 2 left's name [left.host.name.len]
+ * 3 left's cert
+ * 4 left's ca
+ * 5 left's groups
+ * 6 left's updown
+ * 7 right's name [left.host.name.len]
+ * 8 right's cert
+ * 9 right's ca
+ * 10 right's groups
+ * 11 right's updown
+ * 12 keyid
+ * 13 myid
+ * 14 cacert
+ * 15 ldaphost
+ * 16 ldapbase
+ * 17 crluri
+ * 18 crluri2
+ * 19 ocspuri
+ * 20 ike
+ " 21 esp
+ * 22 rsa_data
+ * plus keyval (limit: 8K bits + overhead), a chunk.
+ */
+ size_t str_size;
+ char string[2048];
+};
+
+/* Codes for status messages returned to whack.
+ * These are 3 digit decimal numerals. The structure
+ * is inspired by section 4.2 of RFC959 (FTP).
+ * Since these will end up as the exit status of whack, they
+ * must be less than 256.
+ * NOTE: ipsec_auto(8) knows about some of these numbers -- change carefully.
+ */
+enum rc_type {
+ RC_COMMENT, /* non-commital utterance (does not affect exit status) */
+ RC_WHACK_PROBLEM, /* whack-detected problem */
+ RC_LOG, /* message aimed at log (does not affect exit status) */
+ RC_LOG_SERIOUS, /* serious message aimed at log (does not affect exit status) */
+ RC_SUCCESS, /* success (exit status 0) */
+
+ /* failure, but not definitive */
+
+ RC_RETRANSMISSION = 10,
+
+ /* improper request */
+
+ RC_DUPNAME = 20, /* attempt to reuse a connection name */
+ RC_UNKNOWN_NAME, /* connection name unknown or state number */
+ RC_ORIENT, /* cannot orient connection: neither end is us */
+ RC_CLASH, /* clash between two Road Warrior connections OVERLOADED */
+ RC_DEAF, /* need --listen before --initiate */
+ RC_ROUTE, /* cannot route */
+ RC_RTBUSY, /* cannot unroute: route busy */
+ RC_BADID, /* malformed --id */
+ RC_NOKEY, /* no key found through DNS */
+ RC_NOPEERIP, /* cannot initiate when peer IP is unknown */
+ RC_INITSHUNT, /* cannot initiate a shunt-oly connection */
+ RC_WILDCARD, /* cannot initiate when ID has wildcards */
+ RC_NOVALIDPIN, /* cannot initiate without valid PIN */
+
+ /* permanent failure */
+
+ RC_BADWHACKMESSAGE = 30,
+ RC_NORETRANSMISSION,
+ RC_INTERNALERR,
+ RC_OPPOFAILURE, /* Opportunism failed */
+
+ /* entry of secrets */
+ RC_ENTERSECRET = 40,
+
+ /* progress: start of range for successful state transition.
+ * Actual value is RC_NEW_STATE plus the new state code.
+ */
+ RC_NEW_STATE = 100,
+
+ /* start of range for notification.
+ * Actual value is RC_NOTIFICATION plus code for notification
+ * that should be generated by this Pluto.
+ */
+ RC_NOTIFICATION = 200 /* as per IKE notification messages */
+};
+
+/* options of whack --list*** command */
+
+#define LIST_NONE 0x0000 /* don't list anything */
+#define LIST_ALGS 0x0001 /* list all registered IKE algorithms */
+#define LIST_PUBKEYS 0x0002 /* list all public keys */
+#define LIST_CERTS 0x0004 /* list all host/user certs */
+#define LIST_CACERTS 0x0008 /* list all ca certs */
+#define LIST_ACERTS 0x0010 /* list all attribute certs */
+#define LIST_AACERTS 0x0020 /* list all aa certs */
+#define LIST_OCSPCERTS 0x0040 /* list all ocsp certs */
+#define LIST_GROUPS 0x0080 /* list all access control groups */
+#define LIST_CAINFOS 0x0100 /* list all ca information records */
+#define LIST_CRLS 0x0200 /* list all crls */
+#define LIST_OCSP 0x0400 /* list all ocsp cache entries */
+#define LIST_CARDS 0x0800 /* list all smartcard records */
+
+#define LIST_ALL LRANGES(LIST_ALGS, LIST_CARDS) /* all list options */
+
+/* options of whack --reread*** command */
+
+#define REREAD_NONE 0x00 /* don't reread anything */
+#define REREAD_SECRETS 0x01 /* reread /etc/ipsec.secrets */
+#define REREAD_CACERTS 0x02 /* reread certs in /etc/ipsec.d/cacerts */
+#define REREAD_AACERTS 0x04 /* reread certs in /etc/ipsec.d/aacerts */
+#define REREAD_OCSPCERTS 0x08 /* reread certs in /etc/ipsec.d/ocspcerts */
+#define REREAD_ACERTS 0x10 /* reread certs in /etc/ipsec.d/acerts */
+#define REREAD_CRLS 0x20 /* reread crls in /etc/ipsec.d/crls */
+
+#define REREAD_ALL LRANGES(REREAD_SECRETS, REREAD_CRLS) /* all reread options */
+
+#endif /* _WHACK_H */
diff --git a/programs/pluto/x509.c b/programs/pluto/x509.c
new file mode 100644
index 000000000..c1b4cb6e3
--- /dev/null
+++ b/programs/pluto/x509.c
@@ -0,0 +1,2241 @@
+/* Support of X.509 certificates
+ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
+ * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
+ * Copyright (C) 2002 Mario Strasser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: x509.c,v 1.36 2006/04/10 16:08:33 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+#include "id.h"
+#include "asn1.h"
+#include "oid.h"
+#include "pkcs1.h"
+#include "x509.h"
+#include "crl.h"
+#include "ca.h"
+#include "certs.h"
+#include "keys.h"
+#include "whack.h"
+#include "fetch.h"
+#include "ocsp.h"
+#include "sha1.h"
+
+/* chained lists of X.509 end certificates */
+
+static x509cert_t *x509certs = NULL;
+
+/* ASN.1 definition of a basicConstraints extension */
+
+static const asn1Object_t basicConstraintsObjects[] = {
+ { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "CA", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 1 */
+ { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT |
+ ASN1_BODY }, /* 2 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */
+};
+
+#define BASIC_CONSTRAINTS_CA 1
+#define BASIC_CONSTRAINTS_ROOF 4
+
+/* ASN.1 definition of time */
+
+static const asn1Object_t timeObjects[] = {
+ { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT |
+ ASN1_BODY }, /* 0 */
+ { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */
+ { 0, "generalizeTime", ASN1_GENERALIZEDTIME, ASN1_OPT |
+ ASN1_BODY }, /* 2 */
+ { 0, "end opt", ASN1_EOC, ASN1_END } /* 3 */
+};
+
+#define TIME_UTC 0
+#define TIME_GENERALIZED 2
+#define TIME_ROOF 4
+
+/* ASN.1 definition of a keyIdentifier */
+
+static const asn1Object_t keyIdentifierObjects[] = {
+ { 0, "keyIdentifier", ASN1_OCTET_STRING, ASN1_BODY } /* 0 */
+};
+
+/* ASN.1 definition of a authorityKeyIdentifier extension */
+
+static const asn1Object_t authorityKeyIdentifierObjects[] = {
+ { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT |
+ ASN1_OBJ }, /* 1 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
+ { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT |
+ ASN1_OBJ }, /* 3 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */
+ { 1, "authorityCertSerialNumber", ASN1_CONTEXT_S_2, ASN1_OPT |
+ ASN1_BODY }, /* 5 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */
+};
+
+#define AUTH_KEY_ID_KEY_ID 1
+#define AUTH_KEY_ID_CERT_ISSUER 3
+#define AUTH_KEY_ID_CERT_SERIAL 5
+#define AUTH_KEY_ID_ROOF 7
+
+/* ASN.1 definition of a authorityInfoAccess extension */
+
+static const asn1Object_t authorityInfoAccessObjects[] = {
+ { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */
+ { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */
+ { 0, "end loop", ASN1_EOC, ASN1_END } /* 4 */
+};
+
+#define AUTH_INFO_ACCESS_METHOD 2
+#define AUTH_INFO_ACCESS_LOCATION 3
+#define AUTH_INFO_ACCESS_ROOF 5
+
+/* ASN.1 definition of a extendedKeyUsage extension */
+
+static const asn1Object_t extendedKeyUsageObjects[] = {
+ { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */
+};
+
+#define EXT_KEY_USAGE_PURPOSE_ID 1
+#define EXT_KEY_USAGE_ROOF 3
+
+/* ASN.1 definition of generalNames */
+
+static const asn1Object_t generalNamesObjects[] = {
+ { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */
+ { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */
+};
+
+#define GENERAL_NAMES_GN 1
+#define GENERAL_NAMES_ROOF 3
+
+/* ASN.1 definition of generalName */
+
+static const asn1Object_t generalNameObjects[] = {
+ { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_BODY }, /* 0 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */
+ { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT |
+ ASN1_BODY }, /* 2 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */
+ { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT |
+ ASN1_BODY }, /* 4 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
+ { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT |
+ ASN1_BODY }, /* 6 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
+ { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT |
+ ASN1_BODY }, /* 8 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT |
+ ASN1_BODY }, /* 10 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */
+ { 0, "uniformResourceIdentifier", ASN1_CONTEXT_S_6, ASN1_OPT |
+ ASN1_BODY }, /* 12 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */
+ { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT |
+ ASN1_BODY }, /* 14 */
+ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */
+ { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT |
+ ASN1_BODY }, /* 16 */
+ { 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */
+};
+
+#define GN_OBJ_OTHER_NAME 0
+#define GN_OBJ_RFC822_NAME 2
+#define GN_OBJ_DNS_NAME 4
+#define GN_OBJ_X400_ADDRESS 6
+#define GN_OBJ_DIRECTORY_NAME 8
+#define GN_OBJ_EDI_PARTY_NAME 10
+#define GN_OBJ_URI 12
+#define GN_OBJ_IP_ADDRESS 14
+#define GN_OBJ_REGISTERED_ID 16
+#define GN_OBJ_ROOF 18
+
+/* ASN.1 definition of otherName */
+
+static const asn1Object_t otherNameObjects[] = {
+ {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */
+ {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */
+};
+
+#define ON_OBJ_ID_TYPE 0
+#define ON_OBJ_VALUE 1
+#define ON_OBJ_ROOF 2
+
+/* ASN.1 definition of crlDistributionPoints */
+
+static const asn1Object_t crlDistributionPointsObjects[] = {
+ { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_LOOP }, /* 2 */
+ { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_OBJ }, /* 3 */
+ { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */
+ { 3, "nameRelativeToCRLIssuer", ASN1_CONTEXT_C_1, ASN1_OPT |
+ ASN1_BODY }, /* 5 */
+ { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
+ { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT |
+ ASN1_BODY }, /* 8 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
+ { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT |
+ ASN1_BODY }, /* 10 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */
+};
+
+#define CRL_DIST_POINTS_FULLNAME 3
+#define CRL_DIST_POINTS_ROOF 13
+
+/* ASN.1 definition of an X.509v3 certificate */
+
+static const asn1Object_t certObjects[] = {
+ { 0, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
+ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
+ { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
+ { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
+ { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
+ { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
+ { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
+ { 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
+ { 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */
+ { 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 13 */
+ { 4, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 14 */
+ { 5, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 15 */
+ { 5, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 16 */
+ { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 17 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 18 */
+ { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 19 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
+ { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 21 */
+ { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 22 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 23 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 24 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
+ ASN1_BODY }, /* 25 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 26 */
+ { 3, "end loop", ASN1_EOC, ASN1_END }, /* 27 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 28 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 29 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 30 */
+};
+
+#define X509_OBJ_CERTIFICATE 0
+#define X509_OBJ_TBS_CERTIFICATE 1
+#define X509_OBJ_VERSION 3
+#define X509_OBJ_SERIAL_NUMBER 4
+#define X509_OBJ_SIG_ALG 5
+#define X509_OBJ_ISSUER 6
+#define X509_OBJ_NOT_BEFORE 8
+#define X509_OBJ_NOT_AFTER 9
+#define X509_OBJ_SUBJECT 10
+#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12
+#define X509_OBJ_SUBJECT_PUBLIC_KEY 13
+#define X509_OBJ_RSA_PUBLIC_KEY 14
+#define X509_OBJ_MODULUS 15
+#define X509_OBJ_PUBLIC_EXPONENT 16
+#define X509_OBJ_EXTN_ID 24
+#define X509_OBJ_CRITICAL 25
+#define X509_OBJ_EXTN_VALUE 26
+#define X509_OBJ_ALGORITHM 29
+#define X509_OBJ_SIGNATURE 30
+#define X509_OBJ_ROOF 31
+
+
+const x509cert_t empty_x509cert = {
+ NULL , /* *next */
+ UNDEFINED_TIME, /* installed */
+ 0 , /* count */
+ FALSE , /* smartcard */
+ AUTH_NONE , /* authority_flags */
+ { NULL, 0 } , /* certificate */
+ { NULL, 0 } , /* tbsCertificate */
+ 1 , /* version */
+ { NULL, 0 } , /* serialNumber */
+ OID_UNKNOWN , /* sigAlg */
+ { NULL, 0 } , /* issuer */
+ /* validity */
+ 0 , /* notBefore */
+ 0 , /* notAfter */
+ { NULL, 0 } , /* subject */
+ /* subjectPublicKeyInfo */
+ OID_UNKNOWN , /* subjectPublicKeyAlgorithm */
+ { NULL, 0 } , /* subjectPublicKey */
+ { NULL, 0 } , /* modulus */
+ { NULL, 0 } , /* publicExponent */
+ /* issuerUniqueID */
+ /* subjectUniqueID */
+ /* extensions */
+ /* extension */
+ /* extnID */
+ /* critical */
+ /* extnValue */
+ FALSE , /* isCA */
+ FALSE , /* isOcspSigner */
+ { NULL, 0 } , /* subjectKeyID */
+ { NULL, 0 } , /* authKeyID */
+ { NULL, 0 } , /* authKeySerialNumber */
+ { NULL, 0 } , /* accessLocation */
+ NULL , /* subjectAltName */
+ NULL , /* crlDistributionPoints */
+ OID_UNKNOWN , /* algorithm */
+ { NULL, 0 } /* signature */
+};
+
+/* coding of X.501 distinguished name */
+
+typedef struct {
+ const u_char *name;
+ chunk_t oid;
+ u_char type;
+} x501rdn_t;
+
+/* X.501 acronyms for well known object identifiers (OIDs) */
+
+static u_char oid_ND[] = {0x02, 0x82, 0x06, 0x01,
+ 0x0A, 0x07, 0x14};
+static u_char oid_UID[] = {0x09, 0x92, 0x26, 0x89, 0x93,
+ 0xF2, 0x2C, 0x64, 0x01, 0x01};
+static u_char oid_DC[] = {0x09, 0x92, 0x26, 0x89, 0x93,
+ 0xF2, 0x2C, 0x64, 0x01, 0x19};
+static u_char oid_CN[] = {0x55, 0x04, 0x03};
+static u_char oid_S[] = {0x55, 0x04, 0x04};
+static u_char oid_SN[] = {0x55, 0x04, 0x05};
+static u_char oid_C[] = {0x55, 0x04, 0x06};
+static u_char oid_L[] = {0x55, 0x04, 0x07};
+static u_char oid_ST[] = {0x55, 0x04, 0x08};
+static u_char oid_O[] = {0x55, 0x04, 0x0A};
+static u_char oid_OU[] = {0x55, 0x04, 0x0B};
+static u_char oid_T[] = {0x55, 0x04, 0x0C};
+static u_char oid_D[] = {0x55, 0x04, 0x0D};
+static u_char oid_N[] = {0x55, 0x04, 0x29};
+static u_char oid_G[] = {0x55, 0x04, 0x2A};
+static u_char oid_I[] = {0x55, 0x04, 0x2B};
+static u_char oid_ID[] = {0x55, 0x04, 0x2D};
+static u_char oid_EN[] = {0x60, 0x86, 0x48, 0x01, 0x86,
+ 0xF8, 0x42, 0x03, 0x01, 0x03};
+static u_char oid_E[] = {0x2A, 0x86, 0x48, 0x86, 0xF7,
+ 0x0D, 0x01, 0x09, 0x01};
+static u_char oid_UN[] = {0x2A, 0x86, 0x48, 0x86, 0xF7,
+ 0x0D, 0x01, 0x09, 0x02};
+static u_char oid_TCGID[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x89,
+ 0x31, 0x01, 0x01, 0x02, 0x02, 0x4B};
+
+static const x501rdn_t x501rdns[] = {
+ {"ND" , {oid_ND, 7}, ASN1_PRINTABLESTRING},
+ {"UID" , {oid_UID, 10}, ASN1_PRINTABLESTRING},
+ {"DC" , {oid_DC, 10}, ASN1_PRINTABLESTRING},
+ {"CN" , {oid_CN, 3}, ASN1_PRINTABLESTRING},
+ {"S" , {oid_S, 3}, ASN1_PRINTABLESTRING},
+ {"SN" , {oid_SN, 3}, ASN1_PRINTABLESTRING},
+ {"serialNumber" , {oid_SN, 3}, ASN1_PRINTABLESTRING},
+ {"C" , {oid_C, 3}, ASN1_PRINTABLESTRING},
+ {"L" , {oid_L, 3}, ASN1_PRINTABLESTRING},
+ {"ST" , {oid_ST, 3}, ASN1_PRINTABLESTRING},
+ {"O" , {oid_O, 3}, ASN1_PRINTABLESTRING},
+ {"OU" , {oid_OU, 3}, ASN1_PRINTABLESTRING},
+ {"T" , {oid_T, 3}, ASN1_PRINTABLESTRING},
+ {"D" , {oid_D, 3}, ASN1_PRINTABLESTRING},
+ {"N" , {oid_N, 3}, ASN1_PRINTABLESTRING},
+ {"G" , {oid_G, 3}, ASN1_PRINTABLESTRING},
+ {"I" , {oid_I, 3}, ASN1_PRINTABLESTRING},
+ {"ID" , {oid_ID, 3}, ASN1_PRINTABLESTRING},
+ {"EN" , {oid_EN, 10}, ASN1_PRINTABLESTRING},
+ {"employeeNumber" , {oid_EN, 10}, ASN1_PRINTABLESTRING},
+ {"E" , {oid_E, 9}, ASN1_IA5STRING},
+ {"Email" , {oid_E, 9}, ASN1_IA5STRING},
+ {"emailAddress" , {oid_E, 9}, ASN1_IA5STRING},
+ {"UN" , {oid_UN, 9}, ASN1_IA5STRING},
+ {"unstructuredName", {oid_UN, 9}, ASN1_IA5STRING},
+ {"TCGID" , {oid_TCGID, 12}, ASN1_PRINTABLESTRING}
+};
+
+#define X501_RDN_ROOF 26
+
+static u_char ASN1_subjectAltName_oid_str[] = {
+ 0x06, 0x03, 0x55, 0x1D, 0x11
+};
+
+static const chunk_t ASN1_subjectAltName_oid = strchunk(ASN1_subjectAltName_oid_str);
+
+static void
+update_chunk(chunk_t *ch, int n)
+{
+ n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1;
+ ch->ptr += n; ch->len -= n;
+}
+
+
+/*
+ * Pointer is set to the first RDN in a DN
+ */
+static err_t
+init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next)
+{
+ *rdn = empty_chunk;
+ *attribute = empty_chunk;
+
+ /* a DN is a SEQUENCE OF RDNs */
+
+ if (*dn.ptr != ASN1_SEQUENCE)
+ {
+ return "DN is not a SEQUENCE";
+ }
+
+ rdn->len = asn1_length(&dn);
+
+ if (rdn->len == ASN1_INVALID_LENGTH)
+ return "Invalid RDN length";
+
+ rdn->ptr = dn.ptr;
+
+ /* are there any RDNs ? */
+ *next = rdn->len > 0;
+
+ return NULL;
+}
+
+/*
+ * Fetches the next RDN in a DN
+ */
+static err_t
+get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, chunk_t *value
+, asn1_t *type, bool *next)
+{
+ chunk_t body;
+
+ /* initialize return values */
+ *oid = empty_chunk;
+ *value = empty_chunk;
+
+ /* if all attributes have been parsed, get next rdn */
+ if (attribute->len <= 0)
+ {
+ /* an RDN is a SET OF attributeTypeAndValue */
+ if (*rdn->ptr != ASN1_SET)
+ return "RDN is not a SET";
+
+ attribute->len = asn1_length(rdn);
+
+ if (attribute->len == ASN1_INVALID_LENGTH)
+ return "Invalid attribute length";
+
+ attribute->ptr = rdn->ptr;
+
+ /* advance to start of next RDN */
+ rdn->ptr += attribute->len;
+ rdn->len -= attribute->len;
+ }
+
+ /* an attributeTypeAndValue is a SEQUENCE */
+ if (*attribute->ptr != ASN1_SEQUENCE)
+ return "attributeTypeAndValue is not a SEQUENCE";
+
+ /* extract the attribute body */
+ body.len = asn1_length(attribute);
+
+ if (body.len == ASN1_INVALID_LENGTH)
+ return "Invalid attribute body length";
+
+ body.ptr = attribute->ptr;
+
+ /* advance to start of next attribute */
+ attribute->ptr += body.len;
+ attribute->len -= body.len;
+
+ /* attribute type is an OID */
+ if (*body.ptr != ASN1_OID)
+ return "attributeType is not an OID";
+
+ /* extract OID */
+ oid->len = asn1_length(&body);
+
+ if (oid->len == ASN1_INVALID_LENGTH)
+ return "Invalid attribute OID length";
+
+ oid->ptr = body.ptr;
+
+ /* advance to the attribute value */
+ body.ptr += oid->len;
+ body.len -= oid->len;
+
+ /* extract string type */
+ *type = *body.ptr;
+
+ /* extract string value */
+ value->len = asn1_length(&body);
+
+ if (value->len == ASN1_INVALID_LENGTH)
+ return "Invalid attribute string length";
+
+ value->ptr = body.ptr;
+
+ /* are there any RDNs left? */
+ *next = rdn->len > 0 || attribute->len > 0;
+
+ return NULL;
+}
+
+/*
+ * Parses an ASN.1 distinguished name int its OID/value pairs
+ */
+static err_t
+dn_parse(chunk_t dn, chunk_t *str)
+{
+ chunk_t rdn, oid, attribute, value;
+ asn1_t type;
+ int oid_code;
+ bool next;
+ bool first = TRUE;
+
+ err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
+
+ if (ugh != NULL) /* a parsing error has occured */
+ return ugh;
+
+ while (next)
+ {
+ ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
+
+ if (ugh != NULL) /* a parsing error has occured */
+ return ugh;
+
+ if (first) /* first OID/value pair */
+ first = FALSE;
+ else /* separate OID/value pair by a comma */
+ update_chunk(str, snprintf(str->ptr,str->len,", "));
+
+ /* print OID */
+ oid_code = known_oid(oid);
+ if (oid_code == OID_UNKNOWN) /* OID not found in list */
+ hex_str(oid, str);
+ else
+ update_chunk(str, snprintf(str->ptr,str->len,"%s",
+ oid_names[oid_code].name));
+
+ /* print value */
+ update_chunk(str, snprintf(str->ptr,str->len,"=%.*s",
+ (int)value.len,value.ptr));
+ }
+ return NULL;
+}
+
+/*
+ * Count the number of wildcard RDNs in a distinguished name
+ */
+int
+dn_count_wildcards(chunk_t dn)
+{
+ chunk_t rdn, attribute, oid, value;
+ asn1_t type;
+ bool next;
+ int wildcards = 0;
+
+ err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
+
+ if (ugh != NULL) /* a parsing error has occured */
+ return -1;
+
+ while (next)
+ {
+ ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
+
+ if (ugh != NULL) /* a parsing error has occured */
+ return -1;
+ if (value.len == 1 && *value.ptr == '*')
+ wildcards++; /* we have found a wildcard RDN */
+ }
+ return wildcards;
+}
+
+/*
+ * Prints a binary string in hexadecimal form
+ */
+void
+hex_str(chunk_t bin, chunk_t *str)
+{
+ u_int i;
+ update_chunk(str, snprintf(str->ptr,str->len,"0x"));
+ for (i=0; i < bin.len; i++)
+ update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++));
+}
+
+
+/* Converts a binary DER-encoded ASN.1 distinguished name
+ * into LDAP-style human-readable ASCII format
+ */
+int
+dntoa(char *dst, size_t dstlen, chunk_t dn)
+{
+ err_t ugh = NULL;
+ chunk_t str;
+
+ str.ptr = dst;
+ str.len = dstlen;
+ ugh = dn_parse(dn, &str);
+
+ if (ugh != NULL) /* error, print DN as hex string */
+ {
+ DBG(DBG_PARSING,
+ DBG_log("error in DN parsing: %s", ugh)
+ )
+ str.ptr = dst;
+ str.len = dstlen;
+ hex_str(dn, &str);
+ }
+ return (int)(dstlen - str.len);
+}
+
+/*
+ * Same as dntoa but prints a special string for a null dn
+ */
+int
+dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, const char* null_dn)
+{
+ if (dn.ptr == NULL)
+ return snprintf(dst, dstlen, "%s", null_dn);
+ else
+ return dntoa(dst, dstlen, dn);
+}
+
+/* Converts an LDAP-style human-readable ASCII-encoded
+ * ASN.1 distinguished name into binary DER-encoded format
+ */
+err_t
+atodn(char *src, chunk_t *dn)
+{
+ /* finite state machine for atodn */
+
+ typedef enum {
+ SEARCH_OID = 0,
+ READ_OID = 1,
+ SEARCH_NAME = 2,
+ READ_NAME = 3,
+ UNKNOWN_OID = 4
+ } state_t;
+
+ u_char oid_len_buf[3];
+ u_char name_len_buf[3];
+ u_char rdn_seq_len_buf[3];
+ u_char rdn_set_len_buf[3];
+ u_char dn_seq_len_buf[3];
+
+ chunk_t asn1_oid_len = { oid_len_buf, 0 };
+ chunk_t asn1_name_len = { name_len_buf, 0 };
+ chunk_t asn1_rdn_seq_len = { rdn_seq_len_buf, 0 };
+ chunk_t asn1_rdn_set_len = { rdn_set_len_buf, 0 };
+ chunk_t asn1_dn_seq_len = { dn_seq_len_buf, 0 };
+ chunk_t oid = empty_chunk;
+ chunk_t name = empty_chunk;
+
+ int whitespace = 0;
+ int rdn_seq_len = 0;
+ int rdn_set_len = 0;
+ int dn_seq_len = 0;
+ int pos = 0;
+
+ err_t ugh = NULL;
+
+ u_char *dn_ptr = dn->ptr + 4;
+
+ state_t state = SEARCH_OID;
+
+ do
+ {
+ switch (state)
+ {
+ case SEARCH_OID:
+ if (*src != ' ' && *src != '/' && *src != ',')
+ {
+ oid.ptr = src;
+ oid.len = 1;
+ state = READ_OID;
+ }
+ break;
+ case READ_OID:
+ if (*src != ' ' && *src != '=')
+ oid.len++;
+ else
+ {
+ for (pos = 0; pos < X501_RDN_ROOF; pos++)
+ {
+ if (strlen(x501rdns[pos].name) == oid.len &&
+ strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0)
+ break; /* found a valid OID */
+ }
+ if (pos == X501_RDN_ROOF)
+ {
+ ugh = "unknown OID in distinguished name";
+ state = UNKNOWN_OID;
+ break;
+ }
+ code_asn1_length(x501rdns[pos].oid.len, &asn1_oid_len);
+
+ /* reset oid and change state */
+ oid = empty_chunk;
+ state = SEARCH_NAME;
+ }
+ break;
+ case SEARCH_NAME:
+ if (*src != ' ' && *src != '=')
+ {
+ name.ptr = src;
+ name.len = 1;
+ whitespace = 0;
+ state = READ_NAME;
+ }
+ break;
+ case READ_NAME:
+ if (*src != ',' && *src != '/' && *src != '\0')
+ {
+ name.len++;
+ if (*src == ' ')
+ whitespace++;
+ else
+ whitespace = 0;
+ }
+ else
+ {
+ name.len -= whitespace;
+ code_asn1_length(name.len, &asn1_name_len);
+
+ /* compute the length of the relative distinguished name sequence */
+ rdn_seq_len = 1 + asn1_oid_len.len + x501rdns[pos].oid.len +
+ 1 + asn1_name_len.len + name.len;
+ code_asn1_length(rdn_seq_len, &asn1_rdn_seq_len);
+
+ /* compute the length of the relative distinguished name set */
+ rdn_set_len = 1 + asn1_rdn_seq_len.len + rdn_seq_len;
+ code_asn1_length(rdn_set_len, &asn1_rdn_set_len);
+
+ /* encode the relative distinguished name */
+ *dn_ptr++ = ASN1_SET;
+ chunkcpy(dn_ptr, asn1_rdn_set_len);
+ *dn_ptr++ = ASN1_SEQUENCE;
+ chunkcpy(dn_ptr, asn1_rdn_seq_len);
+ *dn_ptr++ = ASN1_OID;
+ chunkcpy(dn_ptr, asn1_oid_len);
+ chunkcpy(dn_ptr, x501rdns[pos].oid);
+ /* encode the ASN.1 character string type of the name */
+ *dn_ptr++ = (x501rdns[pos].type == ASN1_PRINTABLESTRING
+ && !is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type;
+ chunkcpy(dn_ptr, asn1_name_len);
+ chunkcpy(dn_ptr, name);
+
+ /* accumulate the length of the distinguished name sequence */
+ dn_seq_len += 1 + asn1_rdn_set_len.len + rdn_set_len;
+
+ /* reset name and change state */
+ name = empty_chunk;
+ state = SEARCH_OID;
+ }
+ break;
+ case UNKNOWN_OID:
+ break;
+ }
+ } while (*src++ != '\0');
+
+ /* complete the distinguished name sequence*/
+ code_asn1_length(dn_seq_len, &asn1_dn_seq_len);
+ dn->ptr += 3 - asn1_dn_seq_len.len;
+ dn->len = 1 + asn1_dn_seq_len.len + dn_seq_len;
+ dn_ptr = dn->ptr;
+ *dn_ptr++ = ASN1_SEQUENCE;
+ chunkcpy(dn_ptr, asn1_dn_seq_len);
+ return ugh;
+}
+
+/* compare two distinguished names by
+ * comparing the individual RDNs
+ */
+bool
+same_dn(chunk_t a, chunk_t b)
+{
+ chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
+ chunk_t oid_a, oid_b, value_a, value_b;
+ asn1_t type_a, type_b;
+ bool next_a, next_b;
+
+ /* same lengths for the DNs */
+ if (a.len != b.len)
+ return FALSE;
+
+ /* try a binary comparison first */
+ if (memcmp(a.ptr, b.ptr, b.len) == 0)
+ return TRUE;
+
+ /* initialize DN parsing */
+ if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL
+ || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
+ return FALSE;
+
+ /* fetch next RDN pair */
+ while (next_a && next_b)
+ {
+ /* parse next RDNs and check for errors */
+ if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL
+ || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
+ {
+ return FALSE;
+ }
+
+ /* OIDs must agree */
+ if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
+ return FALSE;
+
+ /* same lengths for values */
+ if (value_a.len != value_b.len)
+ return FALSE;
+
+ /* printableStrings and email RDNs require uppercase comparison */
+ if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
+ (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
+ {
+ if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+ return FALSE;
+ }
+ else
+ {
+ if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+ return FALSE;
+ }
+ }
+ /* both DNs must have same number of RDNs */
+ if (next_a || next_b)
+ return FALSE;
+
+ /* the two DNs are equal! */
+ return TRUE;
+}
+
+
+/* compare two distinguished names by comparing the individual RDNs.
+ * A single'*' character designates a wildcard RDN in DN b.
+ */
+bool
+match_dn(chunk_t a, chunk_t b, int *wildcards)
+{
+ chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
+ chunk_t oid_a, oid_b, value_a, value_b;
+ asn1_t type_a, type_b;
+ bool next_a, next_b;
+
+ /* initialize wildcard counter */
+ *wildcards = 0;
+
+ /* initialize DN parsing */
+ if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL
+ || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
+ return FALSE;
+
+ /* fetch next RDN pair */
+ while (next_a && next_b)
+ {
+ /* parse next RDNs and check for errors */
+ if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL
+ || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
+ {
+ return FALSE;
+ }
+
+ /* OIDs must agree */
+ if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
+ return FALSE;
+
+ /* does rdn_b contain a wildcard? */
+ if (value_b.len == 1 && *value_b.ptr == '*')
+ {
+ (*wildcards)++;
+ continue;
+ }
+
+ /* same lengths for values */
+ if (value_a.len != value_b.len)
+ return FALSE;
+
+ /* printableStrings and email RDNs require uppercase comparison */
+ if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
+ (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
+ {
+ if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+ return FALSE;
+ }
+ else
+ {
+ if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
+ return FALSE;
+ }
+ }
+ /* both DNs must have same number of RDNs */
+ if (next_a || next_b)
+ return FALSE;
+
+ /* the two DNs match! */
+ return TRUE;
+}
+
+/*
+ * compare two X.509 certificates by comparing their signatures
+ */
+bool
+same_x509cert(const x509cert_t *a, const x509cert_t *b)
+{
+ return same_chunk(a->signature, b->signature);
+}
+
+/* for each link pointing to the certificate
+ " increase the count by one
+ */
+void
+share_x509cert(x509cert_t *cert)
+{
+ if (cert != NULL)
+ cert->count++;
+}
+
+/*
+ * add a X.509 user/host certificate to the chained list
+ */
+x509cert_t*
+add_x509cert(x509cert_t *cert)
+{
+ x509cert_t *c = x509certs;
+
+ while (c != NULL)
+ {
+ if (same_x509cert(c, cert)) /* already in chain, free cert */
+ {
+ free_x509cert(cert);
+ return c;
+ }
+ c = c->next;
+ }
+
+ /* insert new cert at the root of the chain */
+ lock_certs_and_keys("add_x509cert");
+ cert->next = x509certs;
+ x509certs = cert;
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" x509 cert inserted")
+ )
+ unlock_certs_and_keys("add_x509cert");
+ return cert;
+}
+
+/*
+ * choose either subject DN or a subjectAltName as connection end ID
+ */
+void
+select_x509cert_id(x509cert_t *cert, struct id *end_id)
+{
+ bool copy_subject_dn = TRUE; /* ID is subject DN */
+
+ if (end_id->kind != ID_NONE) /* check for matching subjectAltName */
+ {
+ generalName_t *gn = cert->subjectAltName;
+
+ while (gn != NULL)
+ {
+ struct id id = empty_id;
+
+ gntoid(&id, gn);
+ if (same_id(&id, end_id))
+ {
+ copy_subject_dn = FALSE; /* take subjectAltName instead */
+ break;
+ }
+ gn = gn->next;
+ }
+ }
+
+ if (copy_subject_dn)
+ {
+ if (end_id->kind != ID_NONE && end_id->kind != ID_DER_ASN1_DN)
+ {
+ char buf[BUF_LEN];
+
+ idtoa(end_id, buf, BUF_LEN);
+ plog(" no subjectAltName matches ID '%s', replaced by subject DN", buf);
+ }
+ end_id->kind = ID_DER_ASN1_DN;
+ end_id->name.len = cert->subject.len;
+ end_id->name.ptr = temporary_cyclic_buffer();
+ memcpy(end_id->name.ptr, cert->subject.ptr, cert->subject.len);
+ }
+}
+
+/*
+ * check for equality between two key identifiers
+ */
+bool
+same_keyid(chunk_t a, chunk_t b)
+{
+ if (a.ptr == NULL || b.ptr == NULL)
+ return FALSE;
+
+ return same_chunk(a, b);
+}
+
+/*
+ * check for equality between two serial numbers
+ */
+bool
+same_serial(chunk_t a, chunk_t b)
+{
+ /* do not compare serial numbers if one of them is not defined */
+ if (a.ptr == NULL || b.ptr == NULL)
+ return TRUE;
+
+ return same_chunk(a, b);
+}
+
+/*
+ * get a X.509 certificate with a given issuer found at a certain position
+ */
+x509cert_t*
+get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, x509cert_t *chain)
+{
+ x509cert_t *cert = (chain != NULL)? chain->next : x509certs;
+
+ while (cert != NULL)
+ {
+ if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->authKeyID)
+ : (same_dn(issuer, cert->issuer)
+ && same_serial(serial, cert->authKeySerialNumber)))
+ {
+ return cert;
+ }
+ cert = cert->next;
+ }
+ return NULL;
+}
+
+/*
+ * encode a linked list of subjectAltNames
+ */
+chunk_t
+build_subjectAltNames(generalName_t *subjectAltNames)
+{
+ u_char *pos;
+ chunk_t names;
+ size_t len = 0;
+ generalName_t *gn = subjectAltNames;
+
+ /* compute the total size of the ASN.1 attributes object */
+ while (gn != NULL)
+ {
+ len += gn->name.len;
+ gn = gn->next;
+ }
+
+ pos = build_asn1_object(&names, ASN1_SEQUENCE, len);
+
+ gn = subjectAltNames;
+ while (gn != NULL)
+ {
+ chunkcpy(pos, gn->name);
+ gn = gn->next;
+ }
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_subjectAltName_oid
+ , asn1_wrap(ASN1_OCTET_STRING, "m", names));
+}
+
+/*
+ * build a to-be-signed X.509 certificate body
+ */
+static chunk_t
+build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
+{
+ /* version is always X.509v3 */
+ chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2);
+
+ chunk_t extensions = empty_chunk;
+
+ if (cert->subjectAltName != NULL)
+ {
+ extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "m"
+ , build_subjectAltNames(cert->subjectAltName)));
+ }
+
+ return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm"
+ , version
+ , asn1_simple_object(ASN1_INTEGER, cert->serialNumber)
+ , asn1_algorithmIdentifier(cert->sigAlg)
+ , cert->issuer
+ , asn1_wrap(ASN1_SEQUENCE, "mm"
+ , timetoasn1(&cert->notBefore, ASN1_UTCTIME)
+ , timetoasn1(&cert->notAfter, ASN1_UTCTIME)
+ )
+ , cert->subject
+ , pkcs1_build_publicKeyInfo(rsa)
+ , extensions
+ );
+}
+
+/*
+ * build a DER-encoded X.509 certificate
+ */
+void
+build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key
+, const RSA_private_key_t *signer_key)
+{
+ chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key);
+
+ chunk_t signature = pkcs1_build_signature(tbs_cert, cert->sigAlg
+ , signer_key, TRUE);
+
+ cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm"
+ , tbs_cert
+ , asn1_algorithmIdentifier(cert->sigAlg)
+ , signature);
+}
+
+/*
+ * free the dynamic memory used to store generalNames
+ */
+void
+free_generalNames(generalName_t* gn, bool free_name)
+{
+ while (gn != NULL)
+ {
+ generalName_t *gn_top = gn;
+ if (free_name)
+ {
+ pfree(gn->name.ptr);
+ }
+ gn = gn->next;
+ pfree(gn_top);
+ }
+}
+
+/*
+ * free a X.509 certificate
+ */
+void
+free_x509cert(x509cert_t *cert)
+{
+ if (cert != NULL)
+ {
+ free_generalNames(cert->subjectAltName, FALSE);
+ free_generalNames(cert->crlDistributionPoints, FALSE);
+ pfreeany(cert->certificate.ptr);
+ pfree(cert);
+ cert = NULL;
+ }
+}
+
+/* release of a certificate decreases the count by one
+ " the certificate is freed when the counter reaches zero
+ */
+void
+release_x509cert(x509cert_t *cert)
+{
+ if (cert != NULL && --cert->count == 0)
+ {
+ x509cert_t **pp = &x509certs;
+ while (*pp != cert)
+ pp = &(*pp)->next;
+ *pp = cert->next;
+ free_x509cert(cert);
+ }
+}
+
+
+/*
+ * stores a chained list of end certs and CA certs
+ */
+void
+store_x509certs(x509cert_t **firstcert, bool strict)
+{
+ x509cert_t *cacerts = NULL;
+ x509cert_t **pp = firstcert;
+
+ /* first extract CA certs, discarding root CA certs */
+
+ while (*pp != NULL)
+ {
+ x509cert_t *cert = *pp;
+
+ if (cert->isCA)
+ {
+ *pp = cert->next;
+
+ /* we don't accept self-signed CA certs */
+ if (same_dn(cert->issuer, cert->subject))
+ {
+ plog("self-signed cacert rejected");
+ free_x509cert(cert);
+ }
+ else
+ {
+ /* insertion into temporary chain of candidate CA certs */
+ cert->next = cacerts;
+ cacerts = cert;
+ }
+ }
+ else
+ pp = &cert->next;
+ }
+
+ /* now verify the candidate CA certs */
+
+ while (cacerts != NULL)
+ {
+ x509cert_t *cert = cacerts;
+
+ cacerts = cacerts->next;
+
+ if (trust_authcert_candidate(cert, cacerts))
+ {
+ add_authcert(cert, AUTH_CA);
+ }
+ else
+ {
+ plog("intermediate cacert rejected");
+ free_x509cert(cert);
+ }
+ }
+
+ /* now verify the end certificates */
+
+ pp = firstcert;
+
+ while (*pp != NULL)
+ {
+ time_t valid_until;
+ x509cert_t *cert = *pp;
+
+ if (verify_x509cert(cert, strict, &valid_until))
+ {
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("public key validated")
+ )
+ add_x509_public_key(cert, valid_until, DAL_SIGNED);
+ }
+ else
+ {
+ plog("X.509 certificate rejected");
+ }
+ *pp = cert->next;
+ free_x509cert(cert);
+ }
+}
+
+/*
+ * decrypts an RSA signature using the issuer's certificate
+ */
+static bool
+decrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert,
+ chunk_t *digest)
+{
+ switch (alg)
+ {
+ chunk_t decrypted;
+
+ case OID_RSA_ENCRYPTION:
+ case OID_MD2_WITH_RSA:
+ case OID_MD5_WITH_RSA:
+ case OID_SHA1_WITH_RSA:
+ case OID_SHA1_WITH_RSA_OIW:
+ case OID_SHA256_WITH_RSA:
+ case OID_SHA384_WITH_RSA:
+ case OID_SHA512_WITH_RSA:
+ {
+ mpz_t s;
+ RSA_public_key_t rsa;
+
+ init_RSA_public_key(&rsa, issuer_cert->publicExponent
+ , issuer_cert->modulus);
+
+ /* decrypt the signature s = s^e mod n */
+ n_to_mpz(s, sig.ptr, sig.len);
+ mpz_powm(s, s, &rsa.e, &rsa.n);
+
+ /* convert back to bytes */
+ decrypted = mpz_to_n(s, rsa.k);
+ DBG(DBG_PARSING,
+ DBG_dump_chunk(" decrypted signature: ", decrypted)
+ )
+
+ /* copy the least significant bits of decrypted signature
+ * into the digest string
+ */
+ memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len,
+ digest->len);
+
+ /* free memory */
+ free_RSA_public_content(&rsa);
+ pfree(decrypted.ptr);
+ mpz_clear(s);
+ return TRUE;
+ }
+ default:
+ digest->len = 0;
+ return FALSE;
+ }
+}
+
+/*
+ * Check if a signature over binary blob is genuine
+ */
+bool
+check_signature(chunk_t tbs, chunk_t sig, int digest_alg, int enc_alg
+, const x509cert_t *issuer_cert)
+{
+ u_char digest_buf[MAX_DIGEST_LEN];
+ u_char decrypted_buf[MAX_DIGEST_LEN];
+ chunk_t digest = {digest_buf, MAX_DIGEST_LEN};
+ chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN};
+
+ DBG(DBG_PARSING,
+ if (digest_alg != OID_UNKNOWN)
+ DBG_log("signature digest algorithm: '%s'",oid_names[digest_alg].name);
+ else
+ DBG_log("unknown signature digest algorithm");
+ )
+
+ if (!compute_digest(tbs, digest_alg, &digest))
+ {
+ plog(" digest algorithm not supported");
+ return FALSE;
+ }
+
+ DBG(DBG_PARSING,
+ DBG_dump_chunk(" digest:", digest)
+ )
+
+ decrypted.len = digest.len; /* we want the same digest length */
+
+ DBG(DBG_PARSING,
+ if (enc_alg != OID_UNKNOWN)
+ DBG_log("signature encryption algorithm: '%s'",oid_names[enc_alg].name);
+ else
+ DBG_log("unknown signature encryption algorithm");
+ )
+
+ if (!decrypt_sig(sig, enc_alg, issuer_cert, &decrypted))
+ {
+ plog(" decryption algorithm not supported");
+ return FALSE;
+ }
+
+ /* check if digests are equal */
+ return !memcmp(decrypted.ptr, digest.ptr, digest.len);
+}
+
+/*
+ * extracts the basicConstraints extension
+ */
+static bool
+parse_basicConstraints(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+ bool isCA = FALSE;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < BASIC_CONSTRAINTS_ROOF) {
+
+ if (!extract_object(basicConstraintsObjects, &objectID,
+ &object,&level, &ctx))
+ break;
+
+ if (objectID == BASIC_CONSTRAINTS_CA)
+ {
+ isCA = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(isCA)?"TRUE":"FALSE");
+ )
+ }
+ objectID++;
+ }
+ return isCA;
+}
+
+/*
+ * Converts a X.500 generalName into an ID
+ */
+void
+gntoid(struct id *id, const generalName_t *gn)
+{
+ switch(gn->kind)
+ {
+ case GN_DNS_NAME: /* ID type: ID_FQDN */
+ id->kind = ID_FQDN;
+ id->name = gn->name;
+ break;
+ case GN_IP_ADDRESS: /* ID type: ID_IPV4_ADDR */
+ {
+ const struct af_info *afi = &af_inet4_info;
+ err_t ugh = NULL;
+
+ id->kind = afi->id_addr;
+ ugh = initaddr(gn->name.ptr, gn->name.len, afi->af, &id->ip_addr);
+ }
+ break;
+ case GN_RFC822_NAME: /* ID type: ID_USER_FQDN */
+ id->kind = ID_USER_FQDN;
+ id->name = gn->name;
+ break;
+ default:
+ id->kind = ID_NONE;
+ id->name = empty_chunk;
+ }
+}
+
+/* compute the subjectKeyIdentifier according to section 4.2.1.2 of RFC 3280
+ * as the 160 bit SHA-1 hash of the public key
+ */
+void
+compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID)
+{
+ SHA1_CTX context;
+
+ SHA1Init(&context);
+ SHA1Update(&context
+ , cert->subjectPublicKey.ptr
+ , cert->subjectPublicKey.len);
+ SHA1Final(subjectKeyID.ptr, &context);
+ subjectKeyID.len = SHA1_DIGEST_SIZE;
+}
+
+/*
+ * extracts an otherName
+ */
+static bool
+parse_otherName(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+ u_int level;
+ int oid = OID_UNKNOWN;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < ON_OBJ_ROOF)
+ {
+ if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case ON_OBJ_ID_TYPE:
+ oid = known_oid(object);
+ break;
+ case ON_OBJ_VALUE:
+ if (oid == OID_XMPP_ADDR)
+ {
+ if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING
+ , level + 1, "xmppAddr"))
+ {
+ return FALSE;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+
+/*
+ * extracts a generalName
+ */
+static generalName_t*
+parse_generalName(chunk_t blob, int level0)
+{
+ u_char buf[BUF_LEN];
+ asn1_ctx_t ctx;
+ chunk_t object;
+ int objectID = 0;
+ u_int level;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < GN_OBJ_ROOF)
+ {
+ bool valid_gn = FALSE;
+
+ if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx))
+ return NULL;
+
+ switch (objectID) {
+ case GN_OBJ_RFC822_NAME:
+ case GN_OBJ_DNS_NAME:
+ case GN_OBJ_URI:
+ DBG(DBG_PARSING,
+ DBG_log(" '%.*s'", (int)object.len, object.ptr);
+ )
+ valid_gn = TRUE;
+ break;
+ case GN_OBJ_DIRECTORY_NAME:
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'", buf)
+ )
+ valid_gn = TRUE;
+ break;
+ case GN_OBJ_IP_ADDRESS:
+ DBG(DBG_PARSING,
+ DBG_log(" '%d.%d.%d.%d'", *object.ptr, *(object.ptr+1),
+ *(object.ptr+2), *(object.ptr+3));
+ )
+ valid_gn = TRUE;
+ break;
+ case GN_OBJ_OTHER_NAME:
+ if (!parse_otherName(object, level + 1))
+ return NULL;
+ break;
+ case GN_OBJ_X400_ADDRESS:
+ case GN_OBJ_EDI_PARTY_NAME:
+ case GN_OBJ_REGISTERED_ID:
+ break;
+ default:
+ break;
+ }
+
+ if (valid_gn)
+ {
+ generalName_t *gn = alloc_thing(generalName_t, "generalName");
+ gn->kind = (objectID - GN_OBJ_OTHER_NAME) / 2;
+ gn->name = object;
+ gn->next = NULL;
+ return gn;
+ }
+ objectID++;
+ }
+ return NULL;
+}
+
+
+/*
+ * extracts one or several GNs and puts them into a chained list
+ */
+static generalName_t*
+parse_generalNames(chunk_t blob, int level0, bool implicit)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ generalName_t *top_gn = NULL;
+
+ asn1_init(&ctx, blob, level0, implicit, DBG_RAW);
+
+ while (objectID < GENERAL_NAMES_ROOF)
+ {
+ if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx))
+ return NULL;
+
+ if (objectID == GENERAL_NAMES_GN)
+ {
+ generalName_t *gn = parse_generalName(object, level+1);
+ if (gn != NULL)
+ {
+ gn->next = top_gn;
+ top_gn = gn;
+ }
+ }
+ objectID++;
+ }
+ return top_gn;
+}
+
+/*
+ * returns a directoryName
+ */
+chunk_t get_directoryName(chunk_t blob, int level, bool implicit)
+{
+ chunk_t name = empty_chunk;
+ generalName_t * gn = parse_generalNames(blob, level, implicit);
+
+ if (gn != NULL && gn->kind == GN_DIRECTORY_NAME)
+ name= gn->name;
+
+ free_generalNames(gn, FALSE);
+
+ return name;
+}
+
+/*
+ * extracts and converts a UTCTIME or GENERALIZEDTIME object
+ */
+time_t
+parse_time(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < TIME_ROOF)
+ {
+ if (!extract_object(timeObjects, &objectID, &object, &level, &ctx))
+ return UNDEFINED_TIME;
+
+ if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)
+ {
+ return asn1totime(&object, (objectID == TIME_UTC)
+ ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME);
+ }
+ objectID++;
+ }
+ return UNDEFINED_TIME;
+ }
+
+/*
+ * extracts a keyIdentifier
+ */
+static chunk_t
+parse_keyIdentifier(chunk_t blob, int level0, bool implicit)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, implicit, DBG_RAW);
+
+ extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx);
+ return object;
+}
+
+/*
+ * extracts an authoritykeyIdentifier
+ */
+void
+parse_authorityKeyIdentifier(chunk_t blob, int level0
+ , chunk_t *authKeyID, chunk_t *authKeySerialNumber)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < AUTH_KEY_ID_ROOF)
+ {
+ if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx))
+ return;
+
+ switch (objectID) {
+ case AUTH_KEY_ID_KEY_ID:
+ *authKeyID = parse_keyIdentifier(object, level+1, TRUE);
+ break;
+ case AUTH_KEY_ID_CERT_ISSUER:
+ {
+ generalName_t * gn = parse_generalNames(object, level+1, TRUE);
+
+ free_generalNames(gn, FALSE);
+ }
+ break;
+ case AUTH_KEY_ID_CERT_SERIAL:
+ *authKeySerialNumber = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+}
+
+/*
+ * extracts an authorityInfoAcess location
+ */
+static void
+parse_authorityInfoAccess(chunk_t blob, int level0, chunk_t *accessLocation)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ u_int accessMethod = OID_UNKNOWN;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < AUTH_INFO_ACCESS_ROOF)
+ {
+ if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx))
+ return;
+
+ switch (objectID) {
+ case AUTH_INFO_ACCESS_METHOD:
+ accessMethod = known_oid(object);
+ break;
+ case AUTH_INFO_ACCESS_LOCATION:
+ {
+ switch (accessMethod)
+ {
+ case OID_OCSP:
+ if (*object.ptr == ASN1_CONTEXT_S_6)
+ {
+ if (asn1_length(&object) == ASN1_INVALID_LENGTH)
+ return;
+
+ DBG(DBG_PARSING,
+ DBG_log(" '%.*s'",(int)object.len, object.ptr)
+ )
+
+ /* only HTTP(S) URIs accepted */
+ if (strncasecmp(object.ptr, "http", 4) == 0)
+ {
+ *accessLocation = object;
+ return;
+ }
+ }
+ plog("warning: ignoring OCSP InfoAccessLocation with unkown protocol");
+ break;
+ default:
+ /* unkown accessMethod, ignoring */
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+
+}
+
+/*
+ * extracts extendedKeyUsage OIDs
+ */
+static bool
+parse_extendedKeyUsage(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < EXT_KEY_USAGE_ROOF)
+ {
+ if (!extract_object(extendedKeyUsageObjects, &objectID
+ , &object, &level, &ctx))
+ return FALSE;
+
+ if (objectID == EXT_KEY_USAGE_PURPOSE_ID
+ && known_oid(object) == OID_OCSP_SIGNING)
+ return TRUE;
+ objectID++;
+ }
+ return FALSE;
+}
+
+/* extracts one or several crlDistributionPoints and puts them into
+ * a chained list
+ */
+static generalName_t*
+parse_crlDistributionPoints(chunk_t blob, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ generalName_t *top_gn = NULL; /* top of the chained list */
+ generalName_t **tail_gn = &top_gn; /* tail of the chained list */
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < CRL_DIST_POINTS_ROOF)
+ {
+ if (!extract_object(crlDistributionPointsObjects, &objectID,
+ &object, &level, &ctx))
+ return NULL;
+
+ if (objectID == CRL_DIST_POINTS_FULLNAME)
+ {
+ generalName_t *gn = parse_generalNames(object, level+1, TRUE);
+ /* append extracted generalNames to existing chained list */
+ *tail_gn = gn;
+ /* find new tail of the chained list */
+ while (gn != NULL)
+ {
+ tail_gn = &gn->next; gn = gn->next;
+ }
+ }
+ objectID++;
+ }
+ return top_gn;
+}
+
+
+/*
+ * Parses an X.509v3 certificate
+ */
+bool
+parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert)
+{
+ u_char buf[BUF_LEN];
+ asn1_ctx_t ctx;
+ bool critical;
+ chunk_t object;
+ u_int level;
+ u_int extn_oid = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
+
+ while (objectID < X509_OBJ_ROOF)
+ {
+ if (!extract_object(certObjects, &objectID, &object, &level, &ctx))
+ return FALSE;
+
+ /* those objects which will parsed further need the next higher level */
+ level++;
+
+ switch (objectID) {
+ case X509_OBJ_CERTIFICATE:
+ cert->certificate = object;
+ break;
+ case X509_OBJ_TBS_CERTIFICATE:
+ cert->tbsCertificate = object;
+ break;
+ case X509_OBJ_VERSION:
+ cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
+ DBG(DBG_PARSING,
+ DBG_log(" v%d", cert->version);
+ )
+ break;
+ case X509_OBJ_SERIAL_NUMBER:
+ cert->serialNumber = object;
+ break;
+ case X509_OBJ_SIG_ALG:
+ cert->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case X509_OBJ_ISSUER:
+ cert->issuer = object;
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case X509_OBJ_NOT_BEFORE:
+ cert->notBefore = parse_time(object, level);
+ break;
+ case X509_OBJ_NOT_AFTER:
+ cert->notAfter = parse_time(object, level);
+ break;
+ case X509_OBJ_SUBJECT:
+ cert->subject = object;
+ DBG(DBG_PARSING,
+ dntoa(buf, BUF_LEN, object);
+ DBG_log(" '%s'",buf)
+ )
+ break;
+ case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
+ if (parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION)
+ cert->subjectPublicKeyAlgorithm = PUBKEY_ALG_RSA;
+ else
+ {
+ plog(" unsupported public key algorithm");
+ return FALSE;
+ }
+ break;
+ case X509_OBJ_SUBJECT_PUBLIC_KEY:
+ if (ctx.blobs[4].len > 0 && *ctx.blobs[4].ptr == 0x00)
+ {
+ /* skip initial bit string octet defining 0 unused bits */
+ ctx.blobs[4].ptr++; ctx.blobs[4].len--;
+ }
+ else
+ {
+ plog(" invalid RSA public key format");
+ return FALSE;
+ }
+ break;
+ case X509_OBJ_RSA_PUBLIC_KEY:
+ cert->subjectPublicKey = object;
+ break;
+ case X509_OBJ_MODULUS:
+ if (object.len < RSA_MIN_OCTETS + 1)
+ {
+ plog(" " RSA_MIN_OCTETS_UGH);
+ return FALSE;
+ }
+ if (object.len > RSA_MAX_OCTETS + (size_t)(*object.ptr == 0x00))
+ {
+ plog(" " RSA_MAX_OCTETS_UGH);
+ return FALSE;
+ }
+ cert->modulus = object;
+ break;
+ case X509_OBJ_PUBLIC_EXPONENT:
+ cert->publicExponent = object;
+ break;
+ case X509_OBJ_EXTN_ID:
+ extn_oid = known_oid(object);
+ break;
+ case X509_OBJ_CRITICAL:
+ critical = object.len && *object.ptr;
+ DBG(DBG_PARSING,
+ DBG_log(" %s",(critical)?"TRUE":"FALSE");
+ )
+ break;
+ case X509_OBJ_EXTN_VALUE:
+ {
+ switch (extn_oid) {
+ case OID_SUBJECT_KEY_ID:
+ cert->subjectKeyID =
+ parse_keyIdentifier(object, level, FALSE);
+ break;
+ case OID_SUBJECT_ALT_NAME:
+ cert->subjectAltName =
+ parse_generalNames(object, level, FALSE);
+ break;
+ case OID_BASIC_CONSTRAINTS:
+ cert->isCA =
+ parse_basicConstraints(object, level);
+ break;
+ case OID_CRL_DISTRIBUTION_POINTS:
+ cert->crlDistributionPoints =
+ parse_crlDistributionPoints(object, level);
+ break;
+ case OID_AUTHORITY_KEY_ID:
+ parse_authorityKeyIdentifier(object, level
+ , &cert->authKeyID, &cert->authKeySerialNumber);
+ break;
+ case OID_AUTHORITY_INFO_ACCESS:
+ parse_authorityInfoAccess(object, level, &cert->accessLocation);
+ break;
+ case OID_EXTENDED_KEY_USAGE:
+ cert->isOcspSigner = parse_extendedKeyUsage(object, level);
+ break;
+ case OID_NS_REVOCATION_URL:
+ case OID_NS_CA_REVOCATION_URL:
+ case OID_NS_CA_POLICY_URL:
+ case OID_NS_COMMENT:
+ if (!parse_asn1_simple_object(&object, ASN1_IA5STRING
+ , level, oid_names[extn_oid].name))
+ {
+ return FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case X509_OBJ_ALGORITHM:
+ cert->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case X509_OBJ_SIGNATURE:
+ cert->signature = object;
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+ time(&cert->installed);
+ return TRUE;
+}
+
+/* verify the validity of a certificate by
+ * checking the notBefore and notAfter dates
+ */
+err_t
+check_validity(const x509cert_t *cert, time_t *until)
+{
+ time_t current_time;
+
+ time(&current_time);
+ DBG(DBG_CONTROL | DBG_PARSING ,
+ DBG_log(" not before : %s", timetoa(&cert->notBefore, TRUE));
+ DBG_log(" current time: %s", timetoa(&current_time, TRUE));
+ DBG_log(" not after : %s", timetoa(&cert->notAfter, TRUE));
+ )
+
+ if (cert->notAfter < *until) *until = cert->notAfter;
+
+ if (current_time < cert->notBefore)
+ return "certificate is not valid yet";
+ if (current_time > cert->notAfter)
+ return "certificate has expired";
+ else
+ return NULL;
+}
+
+/*
+ * verifies a X.509 certificate
+ */
+bool
+verify_x509cert(const x509cert_t *cert, bool strict, time_t *until)
+{
+ int pathlen;
+
+ *until = cert->notAfter;
+
+ for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
+ {
+ x509cert_t *issuer_cert;
+ u_char buf[BUF_LEN];
+ err_t ugh = NULL;
+
+ DBG(DBG_CONTROL,
+ dntoa(buf, BUF_LEN, cert->subject);
+ DBG_log("subject: '%s'",buf);
+ dntoa(buf, BUF_LEN, cert->issuer);
+ DBG_log("issuer: '%s'",buf);
+ if (cert->authKeyID.ptr != NULL)
+ {
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ DBG_log("authkey: %s", buf);
+ }
+ )
+
+ ugh = check_validity(cert, until);
+
+ if (ugh != NULL)
+ {
+ plog("%s", ugh);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is valid")
+ )
+
+ lock_authcert_list("verify_x509cert");
+ issuer_cert = get_authcert(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID, AUTH_CA);
+
+ if (issuer_cert == NULL)
+ {
+ plog("issuer cacert not found");
+ unlock_authcert_list("verify_x509cert");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("issuer cacert found")
+ )
+
+ if (!check_signature(cert->tbsCertificate, cert->signature
+ , cert->algorithm, cert->algorithm, issuer_cert))
+ {
+ plog("certificate signature is invalid");
+ unlock_authcert_list("verify_x509cert");
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate signature is valid")
+ )
+ unlock_authcert_list("verify_x509cert");
+
+ /* check if cert is a self-signed root ca */
+ if (pathlen > 0 && same_dn(cert->issuer, cert->subject))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("reached self-signed root ca")
+ )
+ return TRUE;
+ }
+ else
+ {
+ time_t nextUpdate = *until;
+ time_t revocationDate = UNDEFINED_TIME;
+ crl_reason_t revocationReason = REASON_UNSPECIFIED;
+
+ /* first check certificate revocation using ocsp */
+ cert_status_t status = verify_by_ocsp(cert, &nextUpdate
+ , &revocationDate, &revocationReason);
+
+ /* if ocsp service is not available then fall back to crl */
+ if ((status == CERT_UNDEFINED)
+ || (status == CERT_UNKNOWN && strict))
+ {
+ status = verify_by_crl(cert, &nextUpdate, &revocationDate
+ , &revocationReason);
+ }
+
+ switch (status)
+ {
+ case CERT_GOOD:
+ /* if status information is stale */
+ if (strict && nextUpdate < time(NULL))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is good but status is stale")
+ )
+ remove_x509_public_key(cert);
+ return FALSE;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("certificate is good")
+ )
+
+ /* with strict crl policy the public key must have the same
+ * lifetime as the validity of the ocsp status or crl lifetime
+ */
+ if (strict && nextUpdate < *until)
+ *until = nextUpdate;
+ break;
+ case CERT_REVOKED:
+ plog("certificate was revoked on %s, reason: %s"
+ , timetoa(&revocationDate, TRUE)
+ , enum_name(&crl_reason_names, revocationReason));
+ remove_x509_public_key(cert);
+ return FALSE;
+ case CERT_UNKNOWN:
+ case CERT_UNDEFINED:
+ default:
+ plog("certificate status unknown");
+ if (strict)
+ {
+ remove_x509_public_key(cert);
+ return FALSE;
+ }
+ break;
+ }
+ }
+
+ /* go up one step in the trust chain */
+ cert = issuer_cert;
+ }
+ plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
+ return FALSE;
+}
+
+/*
+ * list all X.509 certs in a chained list
+ */
+void
+list_x509cert_chain(const char *caption, x509cert_t* cert, u_char auth_flags
+ , bool utc)
+{
+ bool first = TRUE;
+ time_t now;
+
+ /* determine the current time */
+ time(&now);
+
+ while (cert != NULL)
+ {
+ if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags))
+ {
+ unsigned keysize;
+ char keyid[KEYID_BUF];
+ u_char buf[BUF_LEN];
+ cert_t c;
+
+ c.type = CERT_X509_SIGNATURE;
+ c.u.x509 = cert;
+
+ if (first)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption);
+ whack_log(RC_COMMENT, " ");
+ first = FALSE;
+ }
+
+ whack_log(RC_COMMENT, "%s, count: %d", timetoa(&cert->installed, utc),
+ cert->count);
+ dntoa(buf, BUF_LEN, cert->subject);
+ whack_log(RC_COMMENT, " subject: '%s'", buf);
+ dntoa(buf, BUF_LEN, cert->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " serial: %s", buf);
+ form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize);
+ whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s"
+ , 8*keysize, keyid
+ , cert->smartcard ? ", on smartcard" :
+ (has_private_key(c)? ", has private key" : ""));
+ whack_log(RC_COMMENT, " validity: not before %s %s",
+ timetoa(&cert->notBefore, utc),
+ (cert->notBefore < now)?"ok":"fatal (not valid yet)");
+ whack_log(RC_COMMENT, " not after %s %s",
+ timetoa(&cert->notAfter, utc),
+ check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE));
+ if (cert->subjectKeyID.ptr != NULL)
+ {
+ datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " subjkey: %s", buf);
+ }
+ if (cert->authKeyID.ptr != NULL)
+ {
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " authkey: %s", buf);
+ }
+ if (cert->authKeySerialNumber.ptr != NULL)
+ {
+ datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len
+ , ':', buf, BUF_LEN);
+ whack_log(RC_COMMENT, " aserial: %s", buf);
+ }
+ }
+ cert = cert->next;
+ }
+}
+
+/*
+ * list all X.509 end certificates in a chained list
+ */
+void
+list_x509_end_certs(bool utc)
+{
+ list_x509cert_chain("End", x509certs, AUTH_NONE, utc);
+}
diff --git a/programs/pluto/x509.h b/programs/pluto/x509.h
new file mode 100644
index 000000000..d15b3da53
--- /dev/null
+++ b/programs/pluto/x509.h
@@ -0,0 +1,138 @@
+/* Support of X.509 certificates
+ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
+ * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
+ * Copyright (C) 2002 Mario Strasser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * 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: x509.h,v 1.10 2005/12/06 22:52:44 as Exp $
+ */
+
+#ifndef _X509_H
+#define _X509_H
+
+#include "pkcs1.h"
+#include "id.h"
+
+/* Definition of generalNames kinds */
+
+typedef enum {
+ GN_OTHER_NAME = 0,
+ GN_RFC822_NAME = 1,
+ GN_DNS_NAME = 2,
+ GN_X400_ADDRESS = 3,
+ GN_DIRECTORY_NAME = 4,
+ GN_EDI_PARTY_NAME = 5,
+ GN_URI = 6,
+ GN_IP_ADDRESS = 7,
+ GN_REGISTERED_ID = 8
+} generalNames_t;
+
+/* access structure for a GeneralName */
+
+typedef struct generalName generalName_t;
+
+struct generalName {
+ generalName_t *next;
+ generalNames_t kind;
+ chunk_t name;
+};
+
+/* access structure for an X.509v3 certificate */
+
+typedef struct x509cert x509cert_t;
+
+struct x509cert {
+ x509cert_t *next;
+ time_t installed;
+ int count;
+ bool smartcard;
+ u_char authority_flags;
+ chunk_t certificate;
+ chunk_t tbsCertificate;
+ u_int version;
+ chunk_t serialNumber;
+ /* signature */
+ int sigAlg;
+ chunk_t issuer;
+ /* validity */
+ time_t notBefore;
+ time_t notAfter;
+ chunk_t subject;
+ /* subjectPublicKeyInfo */
+ enum pubkey_alg subjectPublicKeyAlgorithm;
+ chunk_t subjectPublicKey;
+ chunk_t modulus;
+ chunk_t publicExponent;
+ /* issuerUniqueID */
+ /* subjectUniqueID */
+ /* v3 extensions */
+ /* extension */
+ /* extension */
+ /* extnID */
+ /* critical */
+ /* extnValue */
+ bool isCA;
+ bool isOcspSigner; /* ocsp */
+ chunk_t subjectKeyID;
+ chunk_t authKeyID;
+ chunk_t authKeySerialNumber;
+ chunk_t accessLocation; /* ocsp */
+ generalName_t *subjectAltName;
+ generalName_t *crlDistributionPoints;
+ /* signatureAlgorithm */
+ int algorithm;
+ chunk_t signature;
+};
+
+/* used for initialization */
+extern const x509cert_t empty_x509cert;
+
+extern bool same_serial(chunk_t a, chunk_t b);
+extern bool same_keyid(chunk_t a, chunk_t b);
+extern bool same_dn(chunk_t a, chunk_t b);
+extern bool match_dn(chunk_t a, chunk_t b, int *wildcards);
+extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b);
+extern void hex_str(chunk_t bin, chunk_t *str);
+extern int dn_count_wildcards(chunk_t dn);
+extern int dntoa(char *dst, size_t dstlen, chunk_t dn);
+extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn
+ , const char* null_dn);
+extern err_t atodn(char *src, chunk_t *dn);
+extern void gntoid(struct id *id, const generalName_t *gn);
+extern void compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID);
+extern void select_x509cert_id(x509cert_t *cert, struct id *end_id);
+extern bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert);
+extern time_t parse_time(chunk_t blob, int level0);
+extern void parse_authorityKeyIdentifier(chunk_t blob, int level0
+ , chunk_t *authKeyID, chunk_t *authKeySerialNumber);
+extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit);
+extern err_t check_validity(const x509cert_t *cert, time_t *until);
+extern bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg
+ , int enc_alg, const x509cert_t *issuer_cert);
+extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until);
+extern x509cert_t* add_x509cert(x509cert_t *cert);
+extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid
+ , x509cert_t* chain);
+extern void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key
+ , const RSA_private_key_t *signer_key);
+extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames);
+extern void share_x509cert(x509cert_t *cert);
+extern void release_x509cert(x509cert_t *cert);
+extern void free_x509cert(x509cert_t *cert);
+extern void store_x509certs(x509cert_t **firstcert, bool strict);
+extern void list_x509cert_chain(const char *caption, x509cert_t* cert
+ , u_char auth_flags, bool utc);
+extern void list_x509_end_certs(bool utc);
+extern void free_generalNames(generalName_t* gn, bool free_name);
+
+#endif /* _X509_H */
diff --git a/programs/proc/Makefile b/programs/proc/Makefile
new file mode 100644
index 000000000..023356440
--- /dev/null
+++ b/programs/proc/Makefile
@@ -0,0 +1,51 @@
+# Makefile for the KLIPS interface utilities
+# Copyright (C) 1998, 1999 Henry Spencer.
+# Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:30 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+EXTRA5PROC:=version.5 trap_count.5 trap_sendcount.5
+
+LIBS:=${FREESWANLIB}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:30 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.5 2003/06/20 02:56:20 mcr
+# added documentation for /proc/net/ipsec/stats/trap_* and
+# amendments to test cases.
+#
+# 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/05/05 23:09:49 mcr
+# EXTRA35MAN should have the extensions on it.
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
diff --git a/programs/proc/trap_count.5 b/programs/proc/trap_count.5
new file mode 100644
index 000000000..e4cfd5871
--- /dev/null
+++ b/programs/proc/trap_count.5
@@ -0,0 +1,35 @@
+.TH IPSEC_TRAP_COUNT 5 "19 Jun 2003"
+.\"
+.\" RCSID $Id: trap_count.5,v 1.1 2004/03/15 20:35:30 as Exp $
+.\"
+.SH NAME
+trap_count \- KLIPS statistic on number of ACQUIREs
+.SH SYNOPSIS
+.B cat
+.B /proc/net/ipsec/stats/trap_count
+.SH DESCRIPTION
+.I /proc/net/ipsec/stats/trap_count
+is a read-only file. It contains a hexadecimal number which records the
+number of attempts to send PF_ACQUIRE messages. Only those recorded by
+trap_sendcount were actually successfully passed to userland. Note that the
+userland may still have lost them on its own.
+.LP
+.SH "FILES"
+/proc/net/ipsec/stats/trap_sendcount
+.SH "SEE ALSO"
+ipsec(8), ipsec_pf_key(5), trap_sendcount(5), pluto(8)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Michael C. Richardson <mcr@freeswan.org>
+.\"
+.\" $Log: trap_count.5,v $
+.\" Revision 1.1 2004/03/15 20:35:30 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.1 2003/06/20 02:56:20 mcr
+.\" added documentation for /proc/net/ipsec/stats/trap_* and
+.\" amendments to test cases.
+.\"
+.\"
+.\"
diff --git a/programs/proc/trap_sendcount.5 b/programs/proc/trap_sendcount.5
new file mode 100644
index 000000000..27090b52b
--- /dev/null
+++ b/programs/proc/trap_sendcount.5
@@ -0,0 +1,33 @@
+.TH IPSEC_TRAP_SENDCOUNT 5 "19 Jun 2003"
+.\"
+.\" RCSID $Id: trap_sendcount.5,v 1.1 2004/03/15 20:35:30 as Exp $
+.\"
+.SH NAME
+trap_sendcount \- KLIPS statistic on number of successful ACQUIREs
+.SH SYNOPSIS
+.B cat
+.B /proc/net/ipsec/stats/trap_sendcount
+.SH DESCRIPTION
+.I /proc/net/ipsec/stats/trap_sendcount
+is a read-only file. It contains a hexadecimal number which records the
+number of successful PF_ACQUIRE messages that were sent.
+.LP
+.SH "FILES"
+/proc/net/ipsec/stats/trap_sendcount
+.SH "SEE ALSO"
+ipsec(8), ipsec_pf_key(5), trap_count(5), pluto(8)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Michael C. Richardson <mcr@freeswan.org>
+.\"
+.\" $Log: trap_sendcount.5,v $
+.\" Revision 1.1 2004/03/15 20:35:30 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.1 2003/06/20 02:56:20 mcr
+.\" added documentation for /proc/net/ipsec/stats/trap_* and
+.\" amendments to test cases.
+.\"
+.\"
+.\"
diff --git a/programs/proc/version.5 b/programs/proc/version.5
new file mode 100644
index 000000000..c763d6d17
--- /dev/null
+++ b/programs/proc/version.5
@@ -0,0 +1,54 @@
+.TH IPSEC_VERSION 5 "29 Jun 2000"
+.\"
+.\" RCSID $Id: version.5,v 1.1 2004/03/15 20:35:30 as Exp $
+.\"
+.SH NAME
+ipsec_version \- lists KLIPS version information
+.SH SYNOPSIS
+.B cat
+.B /proc/net/ipsec_version
+.SH DESCRIPTION
+.I /proc/net/ipsec_version
+is a read-only file which lists the currently running KLIPS version
+information.
+.PP
+.SH EXAMPLES
+.TP
+.B FreeS/WAN version: 1.4
+.LP
+shows that the currently loaded
+.B KLIPS
+is from
+.B FreeS/WAN 1.4.
+.LP
+.SH "FILES"
+/proc/net/ipsec_version
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_eroute(5), ipsec_spi(5),
+ipsec_spigrp(5), ipsec_klipsdebug(5), ipsec_tncfg(8), ipsec_pf_key(5)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Richard Guy Briggs.
+.\"
+.\" $Log: version.5,v $
+.\" Revision 1.1 2004/03/15 20:35:30 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.4 2002/04/24 07:35:41 mcr
+.\" Moved from ./klips/utils/version.5,v
+.\"
+.\" 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/30 06:22:22 rgb
+.\" Fix SYNOPSIS since there is no 'ipsec version' command.
+.\"
+.\" Revision 1.1 2000/06/30 06:19:26 rgb
+.\" manpages for the last two /proc/net/ipsec* files that don't have a
+.\" corresponding utility.
+.\"
+.\"
+.\"
diff --git a/programs/ranbits/.cvsignore b/programs/ranbits/.cvsignore
new file mode 100644
index 000000000..910103faa
--- /dev/null
+++ b/programs/ranbits/.cvsignore
@@ -0,0 +1 @@
+ranbits
diff --git a/programs/ranbits/Makefile b/programs/ranbits/Makefile
new file mode 100644
index 000000000..558318e8e
--- /dev/null
+++ b/programs/ranbits/Makefile
@@ -0,0 +1,39 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:30 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=ranbits
+LIBS=${FREESWANLIB}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:30 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 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.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/ranbits/ranbits.8 b/programs/ranbits/ranbits.8
new file mode 100644
index 000000000..5a99a088f
--- /dev/null
+++ b/programs/ranbits/ranbits.8
@@ -0,0 +1,77 @@
+.TH IPSEC_RANBITS 8 "22 Aug 2000"
+.\" RCSID $Id: ranbits.8,v 1.1 2004/03/15 20:35:30 as Exp $
+.SH NAME
+ipsec ranbits \- generate random bits in ASCII form
+.SH SYNOPSIS
+.B ipsec
+.B ranbits
+[
+.B \-\-quick
+] [
+.B \-\-continuous
+] [
+.B \-\-bytes
+] nbits
+.SH DESCRIPTION
+.I Ranbits
+obtains
+.I nbits
+(rounded up to the nearest byte)
+high-quality random bits from
+.IR random (4),
+and emits them on standard output as an ASCII string.
+The default output format is
+.IR datatot (3)
+.B h
+format:
+lowercase hexadecimal with a
+.B 0x
+prefix and an underscore every 32 bits.
+.PP
+The
+.B \-\-quick
+option produces quick-and-dirty random bits:
+instead of using the high-quality random bits from
+.IR /dev/random ,
+which may take some time to supply the necessary bits if
+.I nbits
+is large,
+.I ranbits
+uses
+.IR /dev/urandom ,
+which yields prompt results but lower-quality randomness.
+.PP
+The
+.B \-\-continuous
+option uses
+.IR datatot (3)
+.B x
+output format, like
+.B h
+but without the underscores.
+.PP
+The
+.B \-\-bytes
+option causes
+.I nbits
+to be interpreted as a byte count rather than a bit count.
+.SH FILES
+/dev/random, /dev/urandom
+.SH SEE ALSO
+ipsec_datatot(3), random(4)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org>
+by Henry Spencer.
+.SH BUGS
+There is an internal limit on
+.IR nbits ,
+currently 20000.
+.PP
+Without
+.BR \-\-quick ,
+.IR ranbits 's
+run time is difficult to predict.
+A request for a large number of bits,
+at a time when the system's entropy pool is low on randomness,
+may take quite a while to satisfy.
diff --git a/programs/ranbits/ranbits.c b/programs/ranbits/ranbits.c
new file mode 100644
index 000000000..7b9a0f76e
--- /dev/null
+++ b/programs/ranbits/ranbits.c
@@ -0,0 +1,146 @@
+/*
+ * random bit generation for scripts, control files, etc.
+ * Copyright (C) 1998, 1999, 2000 Henry Spencer.
+ *
+ * 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: ranbits.c,v 1.1 2004/03/15 20:35:30 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <limits.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <freeswan.h>
+
+#ifndef DEVICE
+#define DEVICE "/dev/random"
+#endif
+#ifndef QDEVICE
+#define QDEVICE "/dev/urandom"
+#endif
+#ifndef MAXBITS
+#define MAXBITS 20000
+#endif
+
+char usage[] = "Usage: ranbits [--quick] [--continuous] [--bytes] nbits";
+struct option opts[] = {
+ {"quick", 0, NULL, 'q',},
+ {"continuous", 0, NULL, 'c',},
+ {"bytes", 0, NULL, 'b',},
+ {"help", 0, NULL, 'h',},
+ {"version", 0, NULL, 'v',},
+ {0, 0, NULL, 0,}
+};
+int quick = 0; /* quick and dirty? */
+char format = 'h'; /* datatot() format code */
+int isbytes = 0; /* byte count rather than bits? */
+
+char me[] = "ipsec ranbits"; /* for messages */
+
+char buf[MAXBITS/CHAR_BIT];
+char outbuf[3*sizeof(buf)];
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ extern int optind;
+ int errflg = 0;
+ int nbits;
+ size_t nbytes;
+ char *devname;
+ int dev;
+ size_t ndone;
+ size_t nneeded;
+ ssize_t got;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ case 'q': /* quick and dirty randomness */
+ quick = 1;
+ break;
+ case 'c': /* continuous hex, no underscores */
+ format = 'x';
+ break;
+ case 'b': /* byte count, not bit count */
+ isbytes = 1;
+ break;
+ case 'h': /* help */
+ printf("%s\n", usage);
+ exit(0);
+ break;
+ case 'v': /* version */
+ printf("%s %s\n", me, ipsec_version_code());
+ exit(0);
+ break;
+ case '?':
+ default:
+ errflg = 1;
+ break;
+ }
+ if (errflg || optind != argc-1) {
+ fprintf(stderr, "%s\n", usage);
+ exit(2);
+ }
+
+ nbits = atoi(argv[optind]);
+ if (isbytes)
+ nbits *= CHAR_BIT;
+ if (nbits <= 0) {
+ fprintf(stderr, "%s: invalid bit count (%d)\n", me, nbits);
+ exit(1);
+ }
+ if (nbits > MAXBITS) {
+ fprintf(stderr, "%s: overlarge bit count (max %d)\n", me,
+ MAXBITS);
+ exit(1);
+ }
+ nbytes = (size_t)(nbits + CHAR_BIT - 1) / CHAR_BIT;
+
+ devname = (quick) ? QDEVICE : DEVICE;
+ dev = open(devname, 0);
+ if (dev < 0) {
+ fprintf(stderr, "%s: could not open %s (%s)\n", me,
+ devname, strerror(errno));
+ exit(1);
+ }
+
+ ndone = 0;
+ while (ndone < nbytes) {
+ got = read(dev, buf + ndone, nbytes - ndone);
+ if (got < 0) {
+ fprintf(stderr, "%s: read error on %s (%s)\n", me,
+ devname, strerror(errno));
+ exit(1);
+ }
+ if (got == 0) {
+ fprintf(stderr, "%s: eof on %s!?!\n", me, devname);
+ exit(1);
+ }
+ ndone += got;
+ }
+
+ nneeded = datatot(buf, nbytes, format, outbuf, sizeof(outbuf));
+ if (nneeded > sizeof(outbuf)) {
+ fprintf(stderr, "%s: buffer overflow (need %ld bytes)?!?\n",
+ me, (long)nneeded);
+ exit(1);
+ }
+ printf("%s\n", outbuf);
+ exit(0);
+}
diff --git a/programs/rsasigkey/.cvsignore b/programs/rsasigkey/.cvsignore
new file mode 100644
index 000000000..f9e610b4d
--- /dev/null
+++ b/programs/rsasigkey/.cvsignore
@@ -0,0 +1 @@
+rsasigkey
diff --git a/programs/rsasigkey/Makefile b/programs/rsasigkey/Makefile
new file mode 100644
index 000000000..c2b82e5c8
--- /dev/null
+++ b/programs/rsasigkey/Makefile
@@ -0,0 +1,39 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:30 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=rsasigkey
+LIBS=${FREESWANLIB} -lgmp
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:30 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 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.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/rsasigkey/rsasigkey.8 b/programs/rsasigkey/rsasigkey.8
new file mode 100644
index 000000000..c64dd46bd
--- /dev/null
+++ b/programs/rsasigkey/rsasigkey.8
@@ -0,0 +1,259 @@
+.TH IPSEC_RSASIGKEY 8 "22 July 2001"
+.\" RCSID $Id: rsasigkey.8,v 1.1 2004/03/15 20:35:30 as Exp $
+.SH NAME
+ipsec rsasigkey \- generate RSA signature key
+.SH SYNOPSIS
+.B ipsec
+.B rsasigkey
+[
+.B \-\-verbose
+] [
+.B \-\-random
+filename
+]
+.B \e
+.br
+\ \ \ [
+.B \-\-rounds
+nr
+] [
+.B \-\-hostname
+host ] [
+.B \-\-noopt
+] nbits
+.br
+.B ipsec
+.B rsasigkey
+[
+.B \-\-verbose
+] [
+.B \-\-hostname
+host ]
+.B \e
+.br
+\ \ \
+[
+.B \-\-noopt
+]
+.B \-\-oldkey
+file
+.SH DESCRIPTION
+.I Rsasigkey
+generates an RSA public/private key pair,
+suitable for digital signatures,
+of (exactly)
+.I nbits
+bits (that is, two primes each of exactly
+.IR nbits /2
+bits,
+and related numbers)
+and emits it on standard output as ASCII (mostly hex) data.
+.I nbits
+must be a multiple of 16.
+.PP
+The public exponent is forced to the value
+.BR 3 ,
+which has important speed advantages for signature checking.
+Beware that the resulting keys have known weaknesses as encryption keys
+\fIand should not be used for that purpose\fR.
+.PP
+The
+.B \-\-verbose
+option makes
+.I rsasigkey
+give a running commentary on standard error.
+By default, it works in silence until it is ready to generate output.
+.PP
+The
+.B \-\-random
+option specifies a source for random bits.
+The default is
+.I /dev/random
+(see
+.IR random (4)).
+Normally,
+.I rsasigkey
+reads exactly
+.I nbits
+random bits from the source;
+in extremely-rare circumstances it may need more.
+.PP
+The
+.B \-\-rounds
+option specifies the number of rounds to be done by the
+.I mpz_probab_prime_p
+probabilistic primality checker.
+The default, 30, is fairly rigorous and should not normally
+have to be overridden.
+.PP
+The
+.B \-\-hostname
+option specifies what host name to use in
+the first line of the output (see below);
+the default is what
+.IR gethostname (2)
+returns.
+.PP
+The
+.B \-\-noopt
+option suppresses an optimization of the private key
+(to be precise, setting of the decryption exponent to
+.B lcm(p\-1,q\-1)
+rather than
+.BR (p\-1)*(q\-1) )
+which speeds up operations on it slightly
+but can cause it to flunk a validity check in old RSA implementations
+(notably, obsolete versions of
+.IR ipsec_pluto (8)).
+.PP
+The
+.B \-\-oldkey
+option specifies that rather than generate a new key,
+.I rsasigkey
+should read an old key from the
+.I file
+(the name
+.B \-
+means ``standard input'')
+and use that to generate its output.
+Input lines which do not look like
+.I rsasigkey
+output are silently ignored.
+This permits updating old keys to the current format.
+.PP
+The output format looks like this (with long numbers trimmed down
+for clarity):
+.PP
+.ne 15
+.nf
+ # RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ # for signatures only, UNSAFE FOR ENCRYPTION
+ #pubkey=0sAQOF8tZ2NZt...Y1P+buFuFn/
+ Modulus: 0xcc2a86fcf440...cf1011abb82d1
+ PublicExponent: 0x03
+ # everything after this point is secret
+ PrivateExponent: 0x881c59fdf8...ab05c8c77d23
+ Prime1: 0xf49fd1f779...46504c7bf3
+ Prime2: 0xd5a9108453...321d43cb2b
+ Exponent1: 0xa31536a4fb...536d98adda7f7
+ Exponent2: 0x8e70b5ad8d...9142168d7dcc7
+ Coefficient: 0xafb761d001...0c13e98d98
+.fi
+.PP
+The first (comment) line,
+indicating the nature and date of the key,
+and giving a host name,
+is used by
+.IR ipsec_showhostkey (8)
+when generating some forms of key output.
+.PP
+The commented-out
+.B pubkey=
+line contains the public key\(emthe public exponent and the modulus\(emcombined
+in approximately RFC 2537 format
+(the one deviation is that the combined value is given with a
+.B 0s
+prefix, rather than in unadorned base-64),
+suitable for use in the
+.I ipsec.conf
+file.
+.PP
+The
+.BR Modulus ,
+.BR PublicExponent ,
+and
+.B PrivateExponent
+lines give the basic signing and verification data.
+.PP
+The
+.B Prime1
+and
+.B Prime2
+lines give the primes themselves (aka
+.I p
+and
+.IR q ),
+largest first.
+The
+.B Exponent1
+and
+.B Exponent2
+lines give
+the private exponent mod
+.IR p\-1
+and
+.IR q\-1
+respectively.
+The
+.B Coefficient
+line gives the Chinese Remainder Theorem coefficient,
+which is the inverse of
+.IR q ,
+mod
+.IR p .
+These additional numbers (which must all be kept as secret as the
+private exponent) are precomputed aids to rapid signature generation.
+.PP
+No attempt is made to break long lines.
+.PP
+The US patent on the RSA algorithm expired 20 Sept 2000.
+.SH EXAMPLES
+.TP
+.B "ipsec rsasigkey \-\-verbose 2192 >mykey"
+generates a 2192-bit signature key and puts it in the file
+.IR mykey ,
+with running commentary on standard error.
+The file contents can be inserted verbatim into a suitable entry in the
+.I ipsec.secrets
+file (see
+.IR ipsec.secrets (5)),
+and the public key can then be extracted and edited into the
+.I ipsec.conf
+file (see
+.IR ipsec.conf (5)).
+.TP
+.B "ipsec rsasigkey \-\-verbose \-\-oldkey oldie >latest"
+takes the old signature key from file
+.I oldie
+and puts a version in the current format into the file
+.IR latest ,
+with running commentary on standard error.
+.SH FILES
+/dev/random
+.SH SEE ALSO
+random(4), ipsec_showhostkey(8)
+.br
+\fIApplied Cryptography\fR, 2nd. ed., by Bruce Schneier, Wiley 1996.
+.br
+RFCs 2537, 2313.
+.br
+\fIGNU MP, the GNU multiple precision arithmetic library, edition 2.0.2\fR,
+by Torbj Granlund.
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org>
+by Henry Spencer.
+.SH BUGS
+There is an internal limit on
+.IR nbits ,
+currently 20000.
+.PP
+.IR Rsasigkey 's
+run time is difficult to predict,
+since
+.I /dev/random
+output can be arbitrarily delayed if
+the system's entropy pool is low on randomness,
+and the time taken by the search for primes is also somewhat unpredictable.
+A reasonably typical time for a 1024-bit key on a quiet 200MHz Pentium MMX
+with plenty of randomness available is 20 seconds,
+almost all of it in the prime searches.
+Generating a 2192-bit key on the same system usually takes several minutes.
+A 4096-bit key took an hour and a half of CPU time.
+.PP
+The
+.B \-\-oldkey
+option does not check its input format as rigorously as it might.
+Corrupted
+.I rsasigkey
+output may confuse it.
diff --git a/programs/rsasigkey/rsasigkey.c b/programs/rsasigkey/rsasigkey.c
new file mode 100644
index 000000000..b55dbb889
--- /dev/null
+++ b/programs/rsasigkey/rsasigkey.c
@@ -0,0 +1,573 @@
+/*
+ * RSA signature key generation
+ * Copyright (C) 1999, 2000, 2001 Henry Spencer.
+ *
+ * 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: rsasigkey.c,v 1.2 2005/08/11 10:35:58 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+#include <limits.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <freeswan.h>
+#include "gmp.h"
+
+#ifndef DEVICE
+#define DEVICE "/dev/random"
+#endif
+#ifndef MAXBITS
+#define MAXBITS 20000
+#endif
+
+/* the code in getoldkey() knows about this */
+#define E 3 /* standard public exponent */
+
+char usage[] = "rsasigkey [--verbose] [--random device] nbits";
+char usage2[] = "rsasigkey [--verbose] --oldkey filename";
+struct option opts[] = {
+ {"verbose", 0, NULL, 'v',},
+ {"random", 1, NULL, 'r',},
+ {"rounds", 1, NULL, 'p',},
+ {"oldkey", 1, NULL, 'o',},
+ {"hostname", 1, NULL, 'H',},
+ {"noopt", 0, NULL, 'n',},
+ {"help", 0, NULL, 'h',},
+ {"version", 0, NULL, 'V',},
+ {0, 0, NULL, 0,}
+};
+int verbose = 0; /* narrate the action? */
+char *device = DEVICE; /* where to get randomness */
+int nrounds = 30; /* rounds of prime checking; 25 is good */
+mpz_t prime1; /* old key's prime1 */
+mpz_t prime2; /* old key's prime2 */
+char outputhostname[1024]; /* hostname for output */
+int do_lcm = 1; /* use lcm(p-1, q-1), not (p-1)*(q-1) */
+
+char me[] = "ipsec rsasigkey"; /* for messages */
+
+/* forwards */
+int getoldkey(char *filename);
+void rsasigkey(int nbits, int useoldkey);
+void initprime(mpz_t var, int nbits, int eval);
+void initrandom(mpz_t var, int nbits);
+void getrandom(size_t nbytes, char *buf);
+char *bundle(int e, mpz_t n, size_t *sizep);
+char *conv(char *bits, size_t nbytes, int format);
+char *hexout(mpz_t var);
+void report(char *msg);
+
+/*
+ - main - mostly argument parsing
+ */
+int main(int argc, char *argv[])
+{
+ int opt;
+ extern int optind;
+ extern char *optarg;
+ int errflg = 0;
+ int i;
+ int nbits;
+ char *oldkeyfile = NULL;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ case 'v': /* verbose description */
+ verbose = 1;
+ break;
+ case 'r': /* nonstandard /dev/random */
+ device = optarg;
+ break;
+ case 'p': /* number of prime-check rounds */
+ nrounds = atoi(optarg);
+ if (nrounds <= 0) {
+ fprintf(stderr, "%s: rounds must be > 0\n", me);
+ exit(2);
+ }
+ break;
+ case 'o': /* reformat old key */
+ oldkeyfile = optarg;
+ break;
+ case 'H': /* set hostname for output */
+ strcpy(outputhostname, optarg);
+ break;
+ case 'n': /* don't optimize the private key */
+ do_lcm = 0;
+ break;
+ case 'h': /* help */
+ printf("Usage:\t%s\n", usage);
+ printf("\tor\n");
+ printf("\t%s\n", usage2);
+ exit(0);
+ break;
+ case 'V': /* version */
+ printf("%s %s\n", me, ipsec_version_code());
+ exit(0);
+ break;
+ case '?':
+ default:
+ errflg = 1;
+ break;
+ }
+ if (errflg || optind != ((oldkeyfile != NULL) ? argc : argc-1)) {
+ printf("Usage:\t%s\n", usage);
+ printf("\tor\n");
+ printf("\t%s\n", usage2);
+ exit(2);
+ }
+
+ if (outputhostname[0] == '\0') {
+ i = gethostname(outputhostname, sizeof(outputhostname));
+ if (i < 0) {
+ fprintf(stderr, "%s: gethostname failed (%s)\n",
+ me,
+ strerror(errno));
+ exit(1);
+ }
+ }
+
+ if (oldkeyfile == NULL) {
+ assert(argv[optind] != NULL);
+ nbits = atoi(argv[optind]);
+ } else
+ nbits = getoldkey(oldkeyfile);
+
+ if (nbits <= 0) {
+ fprintf(stderr, "%s: invalid bit count (%d)\n", me, nbits);
+ exit(1);
+ } else if (nbits > MAXBITS) {
+ fprintf(stderr, "%s: overlarge bit count (max %d)\n", me,
+ MAXBITS);
+ exit(1);
+ } else if (nbits % (CHAR_BIT*2) != 0) { /* *2 for nbits/2-bit primes */
+ fprintf(stderr, "%s: bit count (%d) not multiple of %d\n", me,
+ nbits, (int)CHAR_BIT*2);
+ exit(1);
+ }
+
+ rsasigkey(nbits, (oldkeyfile == NULL) ? 0 : 1);
+ exit(0);
+}
+
+/*
+ - getoldkey - fetch an old key's primes
+ */
+int /* nbits */
+getoldkey(filename)
+char *filename;
+{
+ FILE *f;
+ char line[MAXBITS/2];
+ char *p;
+ char *value;
+ static char pube[] = "PublicExponent:";
+ static char pubevalue[] = "0x03";
+ static char pr1[] = "Prime1:";
+ static char pr2[] = "Prime2:";
+# define STREQ(a, b) (strcmp(a, b) == 0)
+ int sawpube = 0;
+ int sawpr1 = 0;
+ int sawpr2 = 0;
+ int nbits;
+
+ nbits = 0;
+
+ if (STREQ(filename, "-"))
+ f = stdin;
+ else
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ fprintf(stderr, "%s: unable to open file `%s' (%s)\n", me,
+ filename, strerror(errno));
+ exit(1);
+ }
+ if (verbose)
+ fprintf(stderr, "getting old key from %s...\n", filename);
+
+ while (fgets(line, sizeof(line), f) != NULL) {
+ p = line + strlen(line) - 1;
+ if (*p != '\n') {
+ fprintf(stderr, "%s: over-long line in file `%s'\n",
+ me, filename);
+ exit(1);
+ }
+ *p = '\0';
+
+ p = line + strspn(line, " \t"); /* p -> first word */
+ value = strpbrk(p, " \t"); /* value -> after it */
+ if (value != NULL) {
+ *value++ = '\0';
+ value += strspn(value, " \t");
+ /* value -> second word if any */
+ }
+
+ if (value == NULL || *value == '\0') {
+ /* wrong format */
+ } else if (STREQ(p, pube)) {
+ sawpube = 1;
+ if (!STREQ(value, pubevalue)) {
+ fprintf(stderr, "%s: wrong public exponent (`%s') in old key\n",
+ me, value);
+ exit(1);
+ }
+ } else if (STREQ(p, pr1)) {
+ if (sawpr1) {
+ fprintf(stderr, "%s: duplicate `%s' lines in `%s'\n",
+ me, pr1, filename);
+ exit(1);
+ }
+ sawpr1 = 1;
+ nbits = (strlen(value) - 2) * 4 * 2;
+ if (mpz_init_set_str(prime1, value, 0) < 0) {
+ fprintf(stderr, "%s: conversion error in reading old prime1\n",
+ me);
+ exit(1);
+ }
+ } else if (STREQ(p, pr2)) {
+ if (sawpr2) {
+ fprintf(stderr, "%s: duplicate `%s' lines in `%s'\n",
+ me, pr2, filename);
+ exit(1);
+ }
+ sawpr2 = 1;
+ if (mpz_init_set_str(prime2, value, 0) < 0) {
+ fprintf(stderr, "%s: conversion error in reading old prime2\n",
+ me);
+ exit(1);
+ }
+ }
+ }
+
+ if (f != stdin)
+ fclose(f);
+
+ if (!sawpube || !sawpr1 || !sawpr2) {
+ fprintf(stderr, "%s: old key missing or incomplete\n", me);
+ exit(1);
+ }
+
+ assert(sawpr1); /* and thus nbits is known */
+ return(nbits);
+}
+
+/*
+ - rsasigkey - generate an RSA signature key
+ * e is fixed at 3, without discussion. That would not be wise if these
+ * keys were to be used for encryption, but for signatures there are some
+ * real speed advantages.
+ */
+void
+rsasigkey(nbits, useoldkey)
+int nbits;
+int useoldkey; /* take primes from old key? */
+{
+ mpz_t p;
+ mpz_t q;
+ mpz_t n;
+ mpz_t e;
+ mpz_t d;
+ mpz_t q1; /* temporary */
+ mpz_t m; /* internal modulus, (p-1)*(q-1) */
+ mpz_t t; /* temporary */
+ mpz_t exp1;
+ mpz_t exp2;
+ mpz_t coeff;
+ char *bundp;
+ size_t bs;
+ int success;
+ time_t now = time((time_t *)NULL);
+
+ /* the easy stuff */
+ if (useoldkey) {
+ mpz_init_set(p, prime1);
+ mpz_init_set(q, prime2);
+ } else {
+ initprime(p, nbits/2, E);
+ initprime(q, nbits/2, E);
+ }
+ mpz_init(t);
+ if (mpz_cmp(p, q) < 0) {
+ report("swapping primes so p is the larger...");
+ mpz_set(t, p);
+ mpz_set(p, q);
+ mpz_set(q, t);
+ }
+ report("computing modulus...");
+ mpz_init(n);
+ mpz_mul(n, p, q); /* n = p*q */
+ mpz_init_set_ui(e, E);
+
+ /* internal modulus */
+ report("computing lcm(p-1, q-1)...");
+ mpz_init_set(m, p);
+ mpz_sub_ui(m, m, 1);
+ mpz_init_set(q1, q);
+ mpz_sub_ui(q1, q1, 1);
+ mpz_gcd(t, m, q1); /* t = gcd(p-1, q-1) */
+ mpz_mul(m, m, q1); /* m = (p-1)*(q-1) */
+ if (do_lcm)
+ mpz_divexact(m, m, t); /* m = lcm(p-1, q-1) */
+ mpz_gcd(t, m, e);
+ assert(mpz_cmp_ui(t, 1) == 0); /* m and e relatively prime */
+
+ /* decryption key */
+ report("computing d...");
+ mpz_init(d);
+ success = mpz_invert(d, e, m);
+ assert(success); /* e has an inverse mod m */
+ if (mpz_cmp_ui(d, 0) < 0)
+ mpz_add(d, d, m);
+ assert(mpz_cmp(d, m) < 0);
+
+ /* the speedup hacks */
+ report("computing exp1, exp1, coeff...");
+ mpz_init(exp1);
+ mpz_sub_ui(t, p, 1);
+ mpz_mod(exp1, d, t); /* exp1 = d mod p-1 */
+ mpz_init(exp2);
+ mpz_sub_ui(t, q, 1);
+ mpz_mod(exp2, d, t); /* exp2 = d mod q-1 */
+ mpz_init(coeff);
+ mpz_invert(coeff, q, p); /* coeff = q^-1 mod p */
+ if (mpz_cmp_ui(coeff, 0) < 0)
+ mpz_add(coeff, coeff, p);
+ assert(mpz_cmp(coeff, p) < 0);
+
+ /* and the output */
+ /* note, getoldkey() knows about some of this */
+ report("output...\n"); /* deliberate extra newline */
+ printf("\t# RSA %d bits %s %s", nbits, outputhostname, ctime(&now));
+ /* ctime provides \n */
+ printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n");
+ bundp = bundle(E, n, &bs);
+ printf("\t#pubkey=%s\n", conv(bundp, bs, 's')); /* RFC2537ish format */
+ printf("\tModulus: %s\n", hexout(n));
+ printf("\tPublicExponent: %s\n", hexout(e));
+ printf("\t# everything after this point is secret\n");
+ printf("\tPrivateExponent: %s\n", hexout(d));
+ printf("\tPrime1: %s\n", hexout(p));
+ printf("\tPrime2: %s\n", hexout(q));
+ printf("\tExponent1: %s\n", hexout(exp1));
+ printf("\tExponent2: %s\n", hexout(exp2));
+ printf("\tCoefficient: %s\n", hexout(coeff));
+}
+
+/*
+ - initprime - initialize an mpz_t to a random prime of specified size
+ * Efficiency tweak: we reject candidates that are 1 higher than a multiple
+ * of e, since they will make the internal modulus not relatively prime to e.
+ */
+void
+initprime(var, nbits, eval)
+mpz_t var;
+int nbits; /* known to be a multiple of CHAR_BIT */
+int eval; /* value of e; 0 means don't bother w. tweak */
+{
+ unsigned long tries;
+ size_t len;
+# define OKAY(p) (eval == 0 || mpz_fdiv_ui(p, eval) != 1)
+
+ initrandom(var, nbits);
+ assert(mpz_fdiv_ui(var, 2) == 1); /* odd number */
+
+ report("looking for a prime starting there (can take a while)...");
+ tries = 1;
+ while (!( OKAY(var) && mpz_probab_prime_p(var, nrounds) )) {
+ mpz_add_ui(var, var, 2);
+ tries++;
+ }
+
+ len = mpz_sizeinbase(var, 2);
+ assert(len == (size_t)nbits || len == (size_t)(nbits+1));
+ if (len == (size_t)(nbits+1)) {
+ report("carry out occurred (!), retrying...");
+ mpz_clear(var);
+ initprime(var, nbits, eval);
+ return;
+ }
+ if (verbose)
+ fprintf(stderr, "found it after %lu tries.\n", tries);
+}
+
+/*
+ - initrandom - initialize an mpz_t to a random number, specified bit count
+ * Converting via hex is a bit weird, but it's the best route GMP gives us.
+ * Note that highmost and lowmost bits are forced on -- highmost to give a
+ * number of exactly the specified length, lowmost so it is an odd number.
+ */
+void
+initrandom(var, nbits)
+mpz_t var;
+int nbits; /* known to be a multiple of CHAR_BIT */
+{
+ size_t nbytes = (size_t)(nbits / CHAR_BIT);
+ static char bitbuf[MAXBITS/CHAR_BIT];
+ static char hexbuf[2 + MAXBITS/4 + 1];
+ size_t hsize = sizeof(hexbuf);
+
+ assert(nbytes <= sizeof(bitbuf));
+ getrandom(nbytes, bitbuf);
+ bitbuf[0] |= 01 << (CHAR_BIT-1); /* force high bit on */
+ bitbuf[nbytes-1] |= 01; /* force low bit on */
+ if (datatot(bitbuf, nbytes, 'x', hexbuf, hsize) > hsize) {
+ fprintf(stderr, "%s: can't-happen buffer overflow\n", me);
+ exit(1);
+ }
+ if (mpz_init_set_str(var, hexbuf, 0) < 0) {
+ fprintf(stderr, "%s: can't-happen hex conversion error\n", me);
+ exit(1);
+ }
+}
+
+/*
+ - getrandom - get some random bytes from /dev/random (or wherever)
+ */
+void
+getrandom(nbytes, buf)
+size_t nbytes;
+char *buf; /* known to be big enough */
+{
+ size_t ndone;
+ int dev;
+ size_t got;
+
+ dev = open(device, 0);
+ if (dev < 0) {
+ fprintf(stderr, "%s: could not open %s (%s)\n", me,
+ device, strerror(errno));
+ exit(1);
+ }
+
+ ndone = 0;
+ if (verbose)
+ fprintf(stderr, "getting %d random bytes from %s...\n", (int) nbytes,
+ device);
+ while (ndone < nbytes) {
+ got = read(dev, buf + ndone, nbytes - ndone);
+ if (got < 0) {
+ fprintf(stderr, "%s: read error on %s (%s)\n", me,
+ device, strerror(errno));
+ exit(1);
+ }
+ if (got == 0) {
+ fprintf(stderr, "%s: eof on %s!?!\n", me, device);
+ exit(1);
+ }
+ ndone += got;
+ }
+
+ close(dev);
+}
+
+/*
+ - hexout - prepare hex output, guaranteeing even number of digits
+ * (The current FreeS/WAN conversion routines want an even digit count,
+ * but mpz_get_str doesn't promise one.)
+ */
+char * /* pointer to static buffer (ick) */
+hexout(var)
+mpz_t var;
+{
+ static char hexbuf[3 + MAXBITS/4 + 1];
+ char *hexp;
+
+ mpz_get_str(hexbuf+3, 16, var);
+ if (strlen(hexbuf+3)%2 == 0) /* even number of hex digits */
+ hexp = hexbuf+1;
+ else { /* odd, must pad */
+ hexp = hexbuf;
+ hexp[2] = '0';
+ }
+ hexp[0] = '0';
+ hexp[1] = 'x';
+
+ return hexp;
+}
+
+/*
+ - bundle - bundle e and n into an RFC2537-format lump
+ * Note, calls hexout.
+ */
+char * /* pointer to static buffer (ick) */
+bundle(e, n, sizep)
+int e;
+mpz_t n;
+size_t *sizep;
+{
+ char *hexp = hexout(n);
+ static char bundbuf[2 + MAXBITS/8];
+ const char *er;
+ size_t size;
+
+ assert(e <= 255);
+ bundbuf[0] = 1;
+ bundbuf[1] = e;
+ er = ttodata(hexp, 0, 0, bundbuf+2, sizeof(bundbuf)-2, &size);
+ if (er != NULL) {
+ fprintf(stderr, "%s: can't-happen bundle convert error `%s'\n",
+ me, er);
+ exit(1);
+ }
+ if (size > sizeof(bundbuf)-2) {
+ fprintf(stderr, "%s: can't-happen bundle overflow (need %d)\n",
+ me, (int) size);
+ exit(1);
+ }
+ if (sizep != NULL)
+ *sizep = size + 2;
+ return bundbuf;
+}
+
+/*
+ - conv - convert bits to output in specified format
+ */
+char * /* pointer to static buffer (ick) */
+conv(bits, nbytes, format)
+char *bits;
+size_t nbytes;
+int format; /* datatot() code */
+{
+ static char convbuf[MAXBITS/4 + 50]; /* enough for hex */
+ size_t n;
+
+ n = datatot(bits, nbytes, format, convbuf, sizeof(convbuf));
+ if (n == 0) {
+ fprintf(stderr, "%s: can't-happen convert error\n", me);
+ exit(1);
+ }
+ if (n > sizeof(convbuf)) {
+ fprintf(stderr, "%s: can't-happen convert overflow (need %d)\n",
+ me, (int) n);
+ exit(1);
+ }
+ return convbuf;
+}
+
+/*
+ - report - report progress, if indicated
+ */
+void
+report(msg)
+char *msg;
+{
+ if (!verbose)
+ return;
+ fprintf(stderr, "%s\n", msg);
+}
diff --git a/programs/scepclient/Makefile b/programs/scepclient/Makefile
new file mode 100644
index 000000000..dec36c888
--- /dev/null
+++ b/programs/scepclient/Makefile
@@ -0,0 +1,184 @@
+# Makefile for the scepclient
+# Copyright (C) 2005 Jan Hutter, Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# 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.
+#
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PLUTODIR=../pluto
+OPENACDIR=../openac
+
+PROGRAM=scepclient
+EXTRA8PROC=${PROGRAM}.8
+
+LIBS=${FREESWANLIB} $(LIBDESLITE) -lgmp
+CFLAGS+= -DDEBUG -DNO_PLUTO
+
+# This compile option activates the leak detective
+ifeq ($(USE_LEAK_DETECTIVE),true)
+ CFLAGS+= -DLEAK_DETECTIVE
+endif
+
+# This compile option activates dynamic URL fetching using libcurl
+ifeq ($(USE_LIBCURL),true)
+ CFLAGS+= -DLIBCURL
+ LIBS+= -lcurl
+endif
+
+X509_OBJS= asn1.o ca.o certs.o constants.o crl.o defs.o fetch.o id.o keys.o \
+ lex.o md2.o md5.o mp_defs.o ocsp.o oid.o pem.o pgp.o pkcs1.o pkcs7.o \
+ rnd.o sha1.o smartcard.o x509.o
+
+OBJS= rsakey.o pkcs10.o loglite.o scep.o ${X509_OBJS}
+
+include ../Makefile.program
+
+loglite.o : $(OPENACDIR)/loglite.c $(PLUTODIR)/log.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+rsakey.o : rsakey.c rsakey.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+pkcs10.o : pkcs10.c pkcs10.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+scep.o : scep.c scep.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+# X.509 library
+
+asn1.o : $(PLUTODIR)/asn1.c $(PLUTODIR)/asn1.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+certs.o : $(PLUTODIR)/certs.c $(PLUTODIR)/certs.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+fetch.o : $(PLUTODIR)/fetch.c $(PLUTODIR)/fetch.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+id.o : $(PLUTODIR)/id.c $(PLUTODIR)/id.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+keys.o : $(PLUTODIR)/keys.c $(PLUTODIR)/keys.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+md2.o : $(PLUTODIR)/md2.c $(PLUTODIR)/md2.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+md5.o : $(PLUTODIR)/md5.c $(PLUTODIR)/md5.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+mp_defs.o : $(PLUTODIR)/mp_defs.c $(PLUTODIR)/mp_defs.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+oid.o : $(PLUTODIR)/oid.c $(PLUTODIR)/oid.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+rnd.o : $(PLUTODIR)/rnd.c $(PLUTODIR)/rnd.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+sha1.o : $(PLUTODIR)/sha1.c $(PLUTODIR)/sha1.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+smartcard.o : $(PLUTODIR)/smartcard.c $(PLUTODIR)/smartcard.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+x509.o : $(PLUTODIR)/x509.c $(PLUTODIR)/x509.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+doxygen :
+ doxygen doxyconfig.DoxyFile
+
+# Stolen from pluto/Makefile
+
+gatherdeps:
+ @ls | grep '\.c$$' | sed -e 's/\(.*\)\.c$$/\1.o: \1.c/'
+ @echo
+ @ls | grep '\.c$$' | xargs grep '^#[ ]*include[ ]*"' | \
+ sed -e 's/\.c:#[ ]*include[ ]*"/.o: /' -e 's/".*//'
+
+# Dependencies generated by "make gatherdeps":
+
+pkcs10.o: pkcs10.c
+rsakey.o: rsakey.c
+scep.o: scep.c
+scepclient.o: scepclient.c
+
+pkcs10.o: ../pluto/constants.h
+pkcs10.o: ../pluto/defs.h
+pkcs10.o: ../pluto/oid.h
+pkcs10.o: ../pluto/asn1.h
+pkcs10.o: ../pluto/pkcs1.h
+pkcs10.o: ../pluto/log.h
+pkcs10.o: ../pluto/x509.h
+pkcs10.o: pkcs10.h
+rsakey.o: ../pluto/constants.h
+rsakey.o: ../pluto/defs.h
+rsakey.o: ../pluto/mp_defs.h
+rsakey.o: ../pluto/log.h
+rsakey.o: ../pluto/asn1.h
+rsakey.o: ../pluto/pkcs1.h
+rsakey.o: rsakey.h
+scep.o: ../pluto/constants.h
+scep.o: ../pluto/defs.h
+scep.o: ../pluto/rnd.h
+scep.o: ../pluto/oid.h
+scep.o: ../pluto/asn1.h
+scep.o: ../pluto/pkcs1.h
+scep.o: ../pluto/fetch.h
+scep.o: ../pluto/log.h
+scep.o: scep.h
+scepclient.o: ../pluto/constants.h
+scepclient.o: ../pluto/defs.h
+scepclient.o: ../pluto/log.h
+scepclient.o: ../pluto/oid.h
+scepclient.o: ../pluto/asn1.h
+scepclient.o: ../pluto/pkcs1.h
+scepclient.o: ../pluto/pkcs7.h
+scepclient.o: ../pluto/certs.h
+scepclient.o: ../pluto/fetch.h
+scepclient.o: ../pluto/rnd.h
+scepclient.o: rsakey.h
+scepclient.o: pkcs10.h
+scepclient.o: scep.h
diff --git a/programs/scepclient/pkcs10.c b/programs/scepclient/pkcs10.c
new file mode 100644
index 000000000..de3f06e18
--- /dev/null
+++ b/programs/scepclient/pkcs10.c
@@ -0,0 +1,220 @@
+/**
+ * @file pkcs10.c
+ * @brief Functions to build PKCS#10 requests
+ *
+ * Contains functions to build DER encoded pkcs#10 certificate requests
+ */
+
+/* Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/oid.h"
+#include "../pluto/asn1.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/log.h"
+#include "../pluto/x509.h"
+
+#include "pkcs10.h"
+
+/* some pre-coded OIDs */
+
+static u_char ASN1_challengePassword_oid_str[] = {
+ 0x06,0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x07
+};
+
+static const chunk_t ASN1_challengePassword_oid = strchunk(ASN1_challengePassword_oid_str);
+
+static u_char ASN1_extensionRequest_oid_str[] = {
+ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x0E
+};
+
+static const chunk_t ASN1_extensionRequest_oid = strchunk(ASN1_extensionRequest_oid_str);
+
+/**
+ * @brief Adds a subjectAltName in DER-coded form to a linked list
+ *
+ * @param[in,out] subjectAltNames head of the linked list of subjectAltNames
+ * @param[in] kind type of the subjectAltName (which is a generalName)
+ * @param[in] value value of the subjectAltName as an ASCII string
+ */
+void
+pkcs10_add_subjectAltName(generalName_t **subjectAltNames, generalNames_t kind
+, char *value)
+{
+ generalName_t *gn;
+ asn1_t asn1_type = ASN1_EOC;
+ chunk_t name = { value, strlen(value) };
+
+ switch (kind)
+ {
+ case GN_RFC822_NAME:
+ asn1_type = ASN1_CONTEXT_S_1;
+ break;
+ case GN_DNS_NAME:
+ asn1_type = ASN1_CONTEXT_S_2;
+ break;
+ case GN_IP_ADDRESS:
+ {
+ struct in_addr addr;
+
+ /* convert an ASCII dotted IPv4 address (e.g. 123.456.78.90)
+ * to a byte representation in network order
+ */
+ if (!inet_aton(value, &addr))
+ {
+ fprintf(stderr, "error in IPv4 subjectAltName\n");
+ return;
+ }
+ asn1_type = ASN1_CONTEXT_S_7;
+ name.ptr = (u_char *) &addr.s_addr;
+ name.len = sizeof(addr.s_addr);
+ break;
+ }
+ default:
+ break;
+ }
+
+ gn = alloc_thing(generalName_t, "subjectAltName");
+ gn->kind = kind;
+ gn->name = asn1_simple_object(asn1_type, name);
+ gn->next = *subjectAltNames;
+ *subjectAltNames = gn;
+}
+
+/**
+ * @brief Builds the requestInfoAttributes of the certificationRequestInfo-field
+ *
+ * challenge password ans subjectAltNames are only included,
+ * when avaiable in given #pkcs10_t structure
+ *
+ * @param[in] pkcs10 Pointer to a #pkcs10_t structure
+ * @return 1 if succeeded, 0 otherwise
+ */
+static chunk_t
+build_req_info_attributes(pkcs10_t* pkcs10)
+{
+
+ chunk_t subjectAltNames = empty_chunk;
+ chunk_t challengePassword = empty_chunk;
+
+ if (pkcs10->subjectAltNames != NULL)
+ {
+
+ subjectAltNames = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_extensionRequest_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_wrap(ASN1_SEQUENCE, "m"
+ , build_subjectAltNames(pkcs10->subjectAltNames)
+ )
+ )
+ );
+ }
+
+ if (pkcs10->challengePassword.len > 0)
+ {
+ asn1_t type = is_printablestring(pkcs10->challengePassword)
+ ? ASN1_PRINTABLESTRING : ASN1_T61STRING;
+
+ challengePassword = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_challengePassword_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(type, pkcs10->challengePassword)
+ )
+ );
+ }
+
+ return asn1_wrap(ASN1_CONTEXT_C_0, "mm"
+ , subjectAltNames
+ , challengePassword);
+}
+
+/**
+ * @brief Builds a DER-code pkcs#10 certificate request
+ *
+ * @param[in] pkcs10 pointer to a pkcs10_t struct
+ * @return DER-code pkcs10 request
+ */
+static chunk_t
+pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg)
+{
+ RSA_public_key_t *rsak = (RSA_public_key_t *) pkcs10->private_key;
+
+ chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm"
+ , ASN1_INTEGER_0
+ , pkcs10->subject
+ , pkcs1_build_publicKeyInfo(rsak)
+ , build_req_info_attributes(pkcs10));
+
+ chunk_t signature = pkcs1_build_signature(cert_req_info
+ , signature_alg, pkcs10->private_key, TRUE);
+
+ return asn1_wrap(ASN1_SEQUENCE, "mcm"
+ , cert_req_info
+ , asn1_algorithmIdentifier(signature_alg)
+ , signature);
+}
+
+/**
+ * @brief Creates a pkcs#10 certificate request object
+ *
+ * To create a certificate request, the RSA key and the
+ * names to be included as subject in the certificate request
+ * (e.g. commonName, organization) are needed. An optional challenge
+ * password or some subjectAltNames may be included.
+ *
+ * @param[in] key rsakey of type #rsakey_t
+ * @param[in] subject DER-coded subject distinguished name
+ * @param[in] challengePassword challenge password or empty_chunk
+ * @param[in] subjectAltNames linked list of subjectAltNames or NULL
+ * @return pointer to a #pkcs10_t object
+ */
+pkcs10_t*
+pkcs10_build(RSA_private_key_t *key, chunk_t subject, chunk_t challengePassword
+, generalName_t *subjectAltNames, int signature_alg)
+{
+ pkcs10_t *pkcs10 = alloc_thing(pkcs10_t, "pkcs10_t");
+
+ pkcs10->subject = subject;
+ pkcs10->private_key = key;
+ pkcs10->challengePassword = challengePassword;
+ pkcs10->subjectAltNames = subjectAltNames;
+
+ pkcs10->request = pkcs10_build_request(pkcs10, signature_alg);
+ return pkcs10;
+}
+
+/**
+ * @brief Frees the resources used by an #pkcs10_t object
+ *
+ * @param[in] pkcs10 #pkcs10_t to free
+ */
+void
+pkcs10_free(pkcs10_t *pkcs10)
+{
+ if (pkcs10 != NULL)
+ {
+ freeanychunk(pkcs10->request);
+ pfree(pkcs10);
+ }
+}
diff --git a/programs/scepclient/pkcs10.h b/programs/scepclient/pkcs10.h
new file mode 100644
index 000000000..c2a4c1b92
--- /dev/null
+++ b/programs/scepclient/pkcs10.h
@@ -0,0 +1,57 @@
+/**
+ * @file pkcs10.h
+ * @brief Functions to build PKCS#10 Request's
+ *
+ * Contains functions to build DER encoded pkcs#10 certificate requests
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+#ifndef _PKCS10_H
+#define _PKCS10_H
+
+#include "../pluto/defs.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/x509.h"
+
+typedef struct pkcs10_struct pkcs10_t;
+
+/**
+ * @brief type representating a pkcs#10 request.
+ *
+ * A pkcs#10 request contains a distinguished name, an optional
+ * challenge password, a public key and optional subjectAltNames.
+ *
+ * The RSA private key is needed to compute the signature of the given request
+ */
+struct pkcs10_struct {
+ RSA_private_key_t *private_key;
+ chunk_t request;
+ chunk_t subject;
+ chunk_t challengePassword;
+ generalName_t *subjectAltNames;
+};
+
+extern const pkcs10_t empty_pkcs10;
+
+extern void pkcs10_add_subjectAltName(generalName_t **subjectAltNames
+ , generalNames_t kind, char *value);
+extern pkcs10_t* pkcs10_build(RSA_private_key_t *key, chunk_t subject
+ , chunk_t challengePassword, generalName_t *subjectAltNames
+ , int signature_alg);
+extern void pkcs10_free(pkcs10_t *pkcs10);
+
+#endif /* _PKCS10_H */
diff --git a/programs/scepclient/rsakey.c b/programs/scepclient/rsakey.c
new file mode 100644
index 000000000..c4f26b286
--- /dev/null
+++ b/programs/scepclient/rsakey.c
@@ -0,0 +1,349 @@
+/**
+ * @file rsakey.c
+ * @brief Functions for RSA key generation
+ */
+
+/*
+ * Copyright (C) 1999, 2000, 2001 Henry Spencer.
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id: rsakey.c,v 1.5 2006/01/04 21:16:30 as Exp $
+ */
+
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <gmp.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/mp_defs.h"
+#include "../pluto/log.h"
+#include "../pluto/asn1.h"
+#include "../pluto/pkcs1.h"
+
+#include "rsakey.h"
+
+/* Number of times the probabilistic primality test is applied */
+#define PRIMECHECK_ROUNDS 30
+
+/* Public exponent used for signature key generation */
+#define PUBLIC_EXPONENT 0x10001
+
+#ifndef RANDOM_DEVICE
+#define RANDOM_DEVICE "/dev/random"
+#endif
+
+
+/**
+ * @brief Reads a specific number of bytes from a given device/file
+ *
+ * @param[in] nbytes number of bytes to read from random device
+ * @param[out] buf pointer to buffer where to write the data in.
+ * size of buffer has to be at least nbytes.
+ * @return TRUE, if succeeded, FALSE otherwise
+ */
+
+static bool
+get_true_random_bytes(size_t nbytes, char *buf)
+{
+ size_t ndone;
+ size_t got;
+ char *device = RANDOM_DEVICE;
+
+ int dev = open(RANDOM_DEVICE, 0);
+
+ if (dev < 0)
+ {
+ fprintf(stderr, "could not open random device %s", device);
+ return FALSE;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("getting %d bytes from %s...", (int) nbytes, device)
+ )
+
+ ndone = 0;
+ while (ndone < nbytes)
+ {
+ got = read(dev, buf + ndone, nbytes - ndone);
+ if (got < 0)
+ {
+ fprintf(stderr, "read error on %s", device);
+ return FALSE;
+ }
+ if (got == 0)
+ {
+ fprintf(stderr, "eof on %s", device);
+ return FALSE;
+ }
+ ndone += got;
+ }
+ close(dev);
+ return TRUE;
+}
+
+/**
+ * @brief initialize an mpz_t to a random number, specified bit count
+ *
+ * Converting the random value in a value of type mpz_t is done
+ * by creating a hexbuffer.
+ * Converting via hex is a bit weird, but it's the best route GMP gives us.
+ * Note that highmost and lowmost bits are forced on -- highmost to give a
+ * number of exactly the specified length, lowmost so it is an odd number.
+ *
+ * @param[out] var uninitialized mpz_t to store th random number in
+ * @param[in] nbits length of var in bits (known to be a multiple of BITS_PER_BYTE)
+ * @return TRUE on success, FALSE otherwise
+ */
+static bool
+init_random(mpz_t var, int nbits)
+{
+ size_t nbytes = (size_t)(nbits/BITS_PER_BYTE);
+ char random_buf[RSA_MAX_OCTETS/2];
+
+ assert(nbytes <= sizeof(random_buf));
+
+ if (!get_true_random_bytes(nbytes, random_buf))
+ return FALSE;
+
+ random_buf[0] |= 01 << (BITS_PER_BYTE-1); /* force high bit on */
+ random_buf[nbytes-1] |= 01; /* force low bit on */
+ n_to_mpz(var, random_buf, nbytes);
+ return TRUE;
+}
+
+/**
+ * @brief initialize an mpz_t to a random prime of specified size
+ *
+ * Efficiency tweak: we reject candidates that are 1 higher than a multiple
+ * of e, since they will make the internal modulus not relatively prime to e.
+ *
+ * @param[out] var mpz_t variable to initialize
+ * @param[in] nbits length of given prime in bits (known to be a multiple of BITS_PER_BYTE)
+ * @param[in] eval E-Value, 0 means don't bother w. tweak
+ * @return 1 on success, 0 otherwise
+ */
+static bool
+init_prime(mpz_t var, int nbits, int eval)
+{
+ unsigned long tries;
+ size_t len;
+
+ /* get a random value of nbits length */
+ if (!init_random(var, nbits))
+ return FALSE;
+
+ /* check if odd number */
+ assert(mpz_fdiv_ui(var, 2) == 1);
+ DBG(DBG_CONTROLMORE,
+ DBG_log("looking for a prime starting there (can take a while)...")
+ )
+
+ tries = 1;
+ while (mpz_fdiv_ui(var, eval) == 1
+ || !mpz_probab_prime_p(var, PRIMECHECK_ROUNDS))
+ {
+ /* not a prime, increase by 2 */
+ mpz_add_ui(var, var, 2);
+ tries++;
+ }
+
+ len = mpz_sizeinbase(var, 2);
+
+ /* check bit length of primee */
+ assert(len == (size_t)nbits || len == (size_t)(nbits+1));
+
+ if (len == (size_t)(nbits+1))
+ {
+ DBG(DBG_CONTROLMORE,
+ DBG_log("carry out occurred (!), retrying...")
+ )
+ mpz_clear(var);
+ /* recursive call */
+ return init_prime(var, nbits, eval);
+ }
+ DBG(DBG_CONTROLMORE,
+ DBG_log("found it after %lu tries.",tries)
+ )
+ return TRUE;
+}
+
+/**
+ * @brief Generate a RSA key usable for encryption
+ *
+ * Generate an RSA key usable for encryption. All the
+ * values of the RSA key are filled into mpz_t parameters.
+ * These mpz_t parameters must not be initialized and have
+ * to be cleared with mpz_clear after using.
+ *
+ * @param[in] nbits size of rsa key in bits
+ * @return RSA_public_key_t containing the generated RSA key
+ */
+err_t
+generate_rsa_private_key(int nbits, RSA_private_key_t *key)
+{
+ mpz_t p, q, n, e, d, exp1, exp2, coeff;
+ mpz_t m, q1, t; /* temporary variables*/
+
+ DBG(DBG_CONTROL,
+ DBG_log("generating %d bit RSA key:", nbits)
+ )
+
+ if (nbits <= 0)
+ return "negative rsa key length!";
+
+ /* Get values of primes p and q */
+ DBG(DBG_CONTROLMORE,
+ DBG_log("initialize prime p")
+ )
+ if (!init_prime(p, nbits/2, PUBLIC_EXPONENT))
+ return "could not generate prime p";
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("initialize prime q")
+ )
+ if (!init_prime(q, nbits/2, PUBLIC_EXPONENT))
+ return "could not generate prime q";
+
+ mpz_init(t);
+
+ /* Swapping primes so p is larger then q */
+ if (mpz_cmp(p, q) < 0)
+ {
+ DBG(DBG_CONTROLMORE,
+ DBG_log("swapping primes so p is the larger...")
+ );
+ mpz_set(t, p);
+ mpz_set(p, q);
+ mpz_set(q, t);
+ }
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("computing modulus...")
+ )
+ mpz_init(n);
+ /* n = p*q */
+ mpz_mul(n, p, q);
+
+ /* Assign e the value of defined PUBLIC_EXPONENT */
+ mpz_init_set_ui(e, PUBLIC_EXPONENT);
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log("computing lcm(p-1, q-1)...")
+ )
+ /* m = p */
+ mpz_init_set(m, p);
+ /* m = m-1 */
+ mpz_sub_ui(m, m, 1);
+ /* q1 = q */
+ mpz_init_set(q1, q);
+ /* q1 = q1-1 */
+ mpz_sub_ui(q1, q1, 1);
+ /* t = gcd(p-1, q-1) */
+ mpz_gcd(t, m, q1);
+ /* m = (p-1)*(q-1) */
+ mpz_mul(m, m, q1);
+ /* m = m / t */
+ mpz_divexact(m, m, t);
+ /* t = gcd(m, e) (greatest common divisor) */
+ mpz_gcd(t, m, e);
+ /* m and e relatively prime */
+ assert(mpz_cmp_ui(t, 1) == 0);
+
+ /* decryption key */
+ DBG(DBG_CONTROLMORE,
+ DBG_log("computing d...")
+ )
+ mpz_init(d);
+ /* e has an inverse mod m */
+ assert(mpz_invert(d, e, m));
+
+ /* make sure d is positive */
+ if (mpz_cmp_ui(d, 0) < 0)
+ mpz_add(d, d, m);
+
+ /* d has to be positive */
+ assert(mpz_cmp(d, m) < 0);
+
+ /* the speedup hacks */
+ DBG(DBG_CONTROLMORE,
+ DBG_log("computing exp1, exp1, coeff...")
+ )
+ mpz_init(exp1);
+ /* t = p-1 */
+ mpz_sub_ui(t, p, 1);
+ /* exp1 = d mod p-1 */
+ mpz_mod(exp1, d, t);
+
+ mpz_init(exp2);
+ /* t = q-1 */
+ mpz_sub_ui(t, q, 1);
+ /* exp2 = d mod q-1 */
+ mpz_mod(exp2, d, t);
+
+ mpz_init(coeff);
+ /* coeff = q^-1 mod p */
+ mpz_invert(coeff, q, p);
+
+ /* make sure coeff is positive */
+ if (mpz_cmp_ui(coeff, 0) < 0)
+ mpz_add(coeff, coeff, p);
+
+ /* coeff has to be positive */
+ assert(mpz_cmp(coeff, p) < 0);
+
+ /* Clear temporary variables */
+ mpz_clear(q1);
+ mpz_clear(m);
+ mpz_clear(t);
+
+ /* form FreeS/WAN keyid */
+ {
+ size_t e_len = (mpz_sizeinbase(e,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE;
+ size_t n_len = (mpz_sizeinbase(n,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE;
+ chunk_t e_ch = mpz_to_n(e, e_len);
+ chunk_t n_ch = mpz_to_n(n, n_len);
+ form_keyid(e_ch, n_ch, key->pub.keyid, &key->pub.k);
+ freeanychunk(e_ch);
+ freeanychunk(n_ch);
+ }
+ /* fill in the elements of the RSA private key */
+ key->p = *p;
+ key->q = *q;
+ key->pub.n = *n;
+ key->pub.e = *e;
+ key->d = *d;
+ key->dP = *exp1;
+ key->dQ = *exp2;
+ key->qInv = *coeff;
+
+ DBG(DBG_CONTROL,
+ DBG_log("RSA key *%s generated with %d bits", key->pub.keyid
+ , (int)mpz_sizeinbase(n,2))
+ )
+
+#ifdef DEBUG
+ DBG(DBG_PRIVATE,
+ RSA_show_private_key(key)
+ )
+#endif
+ return NULL;
+}
diff --git a/programs/scepclient/rsakey.h b/programs/scepclient/rsakey.h
new file mode 100644
index 000000000..3e3156d81
--- /dev/null
+++ b/programs/scepclient/rsakey.h
@@ -0,0 +1,31 @@
+/**
+ * @file rsakey.h
+ * @brief Functions for RSA key generation
+ */
+
+/*
+ * Copyright (C) 1999, 2000, 2001 Henry Spencer.
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id: rsakey.h,v 1.2 2005/08/11 21:52:56 as Exp $
+ */
+
+#ifndef RSAKEY_H_
+#define RSAKEY_H_
+
+#include "../pluto/pkcs1.h"
+
+extern err_t generate_rsa_private_key(int nbits, RSA_private_key_t *key);
+
+#endif // RSAKEY_H_
diff --git a/programs/scepclient/scep.c b/programs/scepclient/scep.c
new file mode 100644
index 000000000..577191787
--- /dev/null
+++ b/programs/scepclient/scep.c
@@ -0,0 +1,598 @@
+/**
+ * @file scep.c
+ * @brief SCEP specific functions
+ *
+ * Contains functions to build SCEP request's and to parse SCEP reply's.
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <freeswan.h>
+
+#ifdef LIBCURL
+#include <curl/curl.h>
+#endif
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/rnd.h"
+#include "../pluto/oid.h"
+#include "../pluto/asn1.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/fetch.h"
+#include "../pluto/log.h"
+
+#include "scep.h"
+
+static char ASN1_messageType_oid_str[] = {
+ 0x06, 0x0A, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x02
+};
+
+static char ASN1_senderNonce_oid_str[] = {
+ 0x06, 0x0A, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x05
+};
+
+static char ASN1_transId_oid_str[] = {
+ 0x06, 0x0A, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x07
+};
+
+static const chunk_t ASN1_messageType_oid =
+ strchunk(ASN1_messageType_oid_str);
+static const chunk_t ASN1_senderNonce_oid =
+ strchunk(ASN1_senderNonce_oid_str);
+static const chunk_t ASN1_transId_oid =
+ strchunk(ASN1_transId_oid_str);
+
+static const char *pkiStatus_values[] = { "0", "2", "3" };
+
+static const char *pkiStatus_names[] = {
+ "SUCCESS",
+ "FAILURE",
+ "PENDING",
+ "UNKNOWN"
+};
+
+static const char *msgType_values[] = { "3", "19", "20", "21", "22" };
+
+static const char *msgType_names[] = {
+ "CertRep",
+ "PKCSReq",
+ "GetCertInitial",
+ "GetCert",
+ "GetCRL",
+ "Unknown"
+};
+
+static const char *failInfo_reasons[] = {
+ "badAlg - unrecognized or unsupported algorithm identifier",
+ "badMessageCheck - integrity check failed",
+ "badRequest - transaction not permitted or supported",
+ "badTime - Message time field was not sufficiently close to the system time",
+ "badCertId - No certificate could be identified matching the provided criteria"
+};
+
+const scep_attributes_t empty_scep_attributes = {
+ SCEP_Unknown_MSG , /* msgType */
+ SCEP_UNKNOWN , /* pkiStatus */
+ SCEP_unknown_REASON, /* failInfo */
+ { NULL, 0 } , /* transID */
+ { NULL, 0 } , /* senderNonce */
+ { NULL, 0 } , /* recipientNonce */
+};
+
+/* ASN.1 definition of the X.501 atttribute type */
+
+static const asn1Object_t attributesObjects[] = {
+ { 0, "attributes", ASN1_SET, ASN1_LOOP }, /* 0 */
+ { 1, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "type", ASN1_OID, ASN1_BODY }, /* 2 */
+ { 2, "values", ASN1_SET, ASN1_LOOP }, /* 3 */
+ { 3, "value", ASN1_EOC, ASN1_RAW }, /* 4 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
+};
+
+#define ATTRIBUTE_OBJ_TYPE 2
+#define ATTRIBUTE_OBJ_VALUE 4
+#define ATTRIBUTE_OBJ_ROOF 7
+
+/*
+ * extract and store an attribute
+ */
+static bool
+extract_attribute(int oid, chunk_t object, u_int level
+, scep_attributes_t *attrs)
+{
+ asn1_t type = ASN1_EOC;
+ const char *name = "none";
+
+ switch (oid)
+ {
+ case OID_PKCS9_CONTENT_TYPE:
+ type = ASN1_OID;
+ name = "contentType";
+ break;
+ case OID_PKCS9_SIGNING_TIME:
+ type = ASN1_UTCTIME;
+ name = "signingTime";
+ break;
+ case OID_PKCS9_MESSAGE_DIGEST:
+ type = ASN1_OCTET_STRING;
+ name = "messageDigest";
+ break;
+ case OID_PKI_MESSAGE_TYPE:
+ type = ASN1_PRINTABLESTRING;
+ name = "messageType";
+ break;
+ case OID_PKI_STATUS:
+ type = ASN1_PRINTABLESTRING;
+ name = "pkiStatus";
+ break;
+ case OID_PKI_FAIL_INFO:
+ type = ASN1_PRINTABLESTRING;
+ name = "failInfo";
+ break;
+ case OID_PKI_SENDER_NONCE:
+ type = ASN1_OCTET_STRING;
+ name = "senderNonce";
+ break;
+ case OID_PKI_RECIPIENT_NONCE:
+ type = ASN1_OCTET_STRING;
+ name = "recipientNonce";
+ break;
+ case OID_PKI_TRANS_ID:
+ type = ASN1_PRINTABLESTRING;
+ name = "transID";
+ break;
+ default:
+ break;
+ }
+
+ if (type == ASN1_EOC)
+ return TRUE;
+
+ if (!parse_asn1_simple_object(&object, type, level+1, name))
+ return FALSE;
+
+ switch (oid)
+ {
+ case OID_PKCS9_CONTENT_TYPE:
+ break;
+ case OID_PKCS9_SIGNING_TIME:
+ break;
+ case OID_PKCS9_MESSAGE_DIGEST:
+ break;
+ case OID_PKI_MESSAGE_TYPE:
+ {
+ scep_msg_t m;
+
+ for (m = SCEP_CertRep_MSG; m < SCEP_Unknown_MSG; m++)
+ {
+ if (strncmp(msgType_values[m], object.ptr, object.len) == 0)
+ attrs->msgType = m;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("messageType: %s", msgType_names[attrs->msgType])
+ )
+ }
+ break;
+ case OID_PKI_STATUS:
+ {
+ pkiStatus_t s;
+
+ for (s = SCEP_SUCCESS; s < SCEP_UNKNOWN; s++)
+ {
+ if (strncmp(pkiStatus_values[s], object.ptr, object.len) == 0)
+ attrs->pkiStatus = s;
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("pkiStatus: %s", pkiStatus_names[attrs->pkiStatus])
+ )
+ }
+ break;
+ case OID_PKI_FAIL_INFO:
+ if (object.len == 1
+ && *object.ptr >= '0' && *object.ptr <= '4')
+ {
+ attrs->failInfo = (failInfo_t)(*object.ptr - '0');
+ }
+ if (attrs->failInfo != SCEP_unknown_REASON)
+ plog("failInfo: %s", failInfo_reasons[attrs->failInfo]);
+ break;
+ case OID_PKI_SENDER_NONCE:
+ attrs->senderNonce = object;
+ break;
+ case OID_PKI_RECIPIENT_NONCE:
+ attrs->recipientNonce = object;
+ break;
+ case OID_PKI_TRANS_ID:
+ attrs->transID = object;
+ }
+ return TRUE;
+}
+
+/*
+ * parse X.501 attributes
+ */
+bool
+parse_attributes(chunk_t blob, scep_attributes_t *attrs)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int oid = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
+
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log("parsing attributes")
+ )
+ while (objectID < ATTRIBUTE_OBJ_ROOF)
+ {
+ if (!extract_object(attributesObjects, &objectID
+ , &object, &level, &ctx))
+ return FALSE;
+
+ switch (objectID)
+ {
+ case ATTRIBUTE_OBJ_TYPE:
+ oid = known_oid(object);
+ break;
+ case ATTRIBUTE_OBJ_VALUE:
+ if (!extract_attribute(oid, object, level, attrs))
+ return FALSE;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/* generates a unique fingerprint of the pkcs10 request
+ * by computing an MD5 hash over it
+ */
+void
+scep_generate_pkcs10_fingerprint(chunk_t pkcs10, chunk_t *fingerprint)
+{
+ char buf[MD5_DIGEST_SIZE];
+ chunk_t digest = { buf, sizeof(buf) };
+
+ /* the fingerprint is the MD5 hash in hexadecimal format */
+ compute_digest(pkcs10, OID_MD5, &digest);
+ fingerprint->len = 2*digest.len;
+ fingerprint->ptr = alloc_bytes(fingerprint->len + 1, "fingerprint");
+ datatot(digest.ptr, digest.len, 16, fingerprint->ptr, fingerprint->len + 1);
+}
+
+/* generate a transaction id as the MD5 hash of an public key
+ * the transaction id is also used as a unique serial number
+ */
+void
+scep_generate_transaction_id(const RSA_public_key_t *rsak
+, chunk_t *transID, chunk_t *serialNumber)
+{
+ char buf[MD5_DIGEST_SIZE];
+
+ chunk_t digest = { buf, sizeof(buf) };
+ chunk_t public_key = pkcs1_build_publicKeyInfo(rsak);
+
+ bool msb_set;
+ u_char *pos;
+
+ compute_digest(public_key, OID_MD5, &digest);
+ pfree(public_key.ptr);
+
+ /* is the most significant bit of the digest set? */
+ msb_set = (*digest.ptr & 0x80) == 0x80;
+
+ /* allocate space for the serialNumber */
+ serialNumber->len = msb_set + digest.len;
+ serialNumber->ptr = alloc_bytes(serialNumber->len, "serialNumber");
+
+ /* the serial number as the two's complement of the digest */
+ pos = serialNumber->ptr;
+ if (msb_set)
+ {
+ *pos++ = 0x00;
+ }
+ memcpy(pos, digest.ptr, digest.len);
+
+ /* the transaction id is the serial number in hex format */
+ transID->len = 2*digest.len;
+ transID->ptr = alloc_bytes(transID->len + 1, "transID");
+ datatot(digest.ptr, digest.len, 16, transID->ptr, transID->len + 1);
+}
+
+/*
+ * builds a transId attribute
+ */
+chunk_t
+scep_transId_attribute(chunk_t transID)
+{
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_transId_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(ASN1_PRINTABLESTRING, transID)
+ )
+ );
+}
+
+/*
+ * builds a messageType attribute
+ */
+chunk_t
+scep_messageType_attribute(scep_msg_t m)
+{
+ chunk_t msgType = {
+ msgType_values[m],
+ strlen(msgType_values[m])
+ };
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_messageType_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(ASN1_PRINTABLESTRING, msgType)
+ )
+ );
+}
+
+/*
+ * builds a senderNonce attribute
+ */
+chunk_t
+scep_senderNonce_attribute(void)
+{
+ const size_t nonce_len = 16;
+ u_char nonce_buf[nonce_len];
+ chunk_t senderNonce = { nonce_buf, nonce_len };
+
+ get_rnd_bytes(nonce_buf, nonce_len);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm"
+ , ASN1_senderNonce_oid
+ , asn1_wrap(ASN1_SET, "m"
+ , asn1_simple_object(ASN1_OCTET_STRING, senderNonce)
+ )
+ );
+}
+
+/*
+ * builds a pkcs7 enveloped and signed scep request
+ */
+chunk_t
+scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg
+, const x509cert_t *enc_cert, int enc_alg
+, const x509cert_t *signer_cert, int digest_alg
+, const RSA_private_key_t *private_key)
+{
+ chunk_t envelopedData, attributes, request;
+
+ envelopedData = pkcs7_build_envelopedData(data, enc_cert, enc_alg);
+
+ attributes = asn1_wrap(ASN1_SET, "mmmmm"
+ , pkcs7_contentType_attribute()
+ , pkcs7_messageDigest_attribute(envelopedData
+ , digest_alg)
+ , scep_transId_attribute(transID)
+ , scep_messageType_attribute(msg)
+ , scep_senderNonce_attribute());
+
+ request = pkcs7_build_signedData(envelopedData, attributes
+ , signer_cert, digest_alg, private_key);
+ freeanychunk(envelopedData);
+ freeanychunk(attributes);
+ return request;
+}
+
+#ifdef LIBCURL
+/* converts a binary request to base64 with 64 characters per line
+ * newline and '+' characters are escaped by %0A and %2B, respectively
+ */
+static char*
+escape_http_request(chunk_t req)
+{
+ char *escaped_req = NULL;
+ char *p1, *p2;
+ int lines = 0;
+ int plus = 0;
+ int n = 0;
+
+ /* compute and allocate the size of the base64-encoded request */
+ int len = 1 + 4*((req.len + 2)/3);
+ char *encoded_req = alloc_bytes(len, "encoded request");
+
+ /* do the base64 conversion */
+ len = datatot(req.ptr, req.len, 64, encoded_req, len);
+
+ /* compute newline characters to be inserted every 64 characters */
+ lines = (len - 2) / 64;
+
+ /* count number of + characters to be escaped */
+ p1 = encoded_req;
+ while (*p1 != '\0')
+ {
+ if (*p1++ == '+')
+ plus++;
+ }
+
+ escaped_req = alloc_bytes(len + 3*(lines + plus), "escaped request");
+
+ /* escape special characters in the request */
+ p1 = encoded_req;
+ p2 = escaped_req;
+ while (*p1 != '\0')
+ {
+ if (n == 64)
+ {
+ memcpy(p2, "%0A", 3);
+ p2 += 3;
+ n = 0;
+ }
+ if (*p1 == '+')
+ {
+ memcpy(p2, "%2B", 3);
+ p2 += 3;
+ }
+ else
+ {
+ *p2++ = *p1;
+ }
+ p1++;
+ n++;
+ }
+ *p2 = '\0';
+ pfreeany(encoded_req);
+ return escaped_req;
+}
+#endif
+
+/*
+ * send a SCEP request via HTTP and wait for a response
+ */
+bool
+scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op
+, fetch_request_t req_type, chunk_t *response)
+{
+#ifdef LIBCURL
+ char errorbuffer[CURL_ERROR_SIZE] = "";
+ char *complete_url = NULL;
+ struct curl_slist *headers = NULL;
+ CURL *curl;
+ CURLcode res;
+
+ /* initialize response */
+ *response = empty_chunk;
+
+ /* initialize curl context */
+ curl = curl_easy_init();
+ if (curl == NULL)
+ {
+ plog("could not initialize curl context");
+ return FALSE;
+ }
+
+ if (op == SCEP_PKI_OPERATION)
+ {
+ const char operation[] = "PKIOperation";
+
+ if (req_type == FETCH_GET)
+ {
+ char *escaped_req = escape_http_request(pkcs7);
+
+ /* form complete url */
+ int len = strlen(url) + 20 + strlen(operation) + strlen(escaped_req) + 1;
+
+ complete_url = alloc_bytes(len, "complete url");
+ snprintf(complete_url, len, "%s?operation=%s&message=%s"
+ , url, operation, escaped_req);
+ pfreeany(escaped_req);
+
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, TRUE);
+ headers = curl_slist_append(headers, "Pragma:");
+ headers = curl_slist_append(headers, "Host:");
+ headers = curl_slist_append(headers, "Accept:");
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ }
+ else /* HTTP_POST */
+ {
+ /* form complete url */
+ int len = strlen(url) + 11 + strlen(operation) + 1;
+
+ complete_url = alloc_bytes(len, "complete url");
+ snprintf(complete_url, len, "%s?operation=%s", url, operation);
+
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, FALSE);
+ headers = curl_slist_append(headers, "Content-Type:");
+ headers = curl_slist_append(headers, "Expect:");
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, pkcs7.ptr);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, pkcs7.len);
+ }
+ }
+ else /* SCEP_GET_CA_CERT */
+ {
+ const char operation[] = "GetCACert";
+
+ /* form complete url */
+ int len = strlen(url) + 32 + strlen(operation) + 1;
+
+ complete_url = alloc_bytes(len, "complete url");
+ snprintf(complete_url, len, "%s?operation=%s&message=CAIdentifier"
+ , url, operation);
+
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, TRUE);
+ }
+
+ curl_easy_setopt(curl, CURLOPT_URL, complete_url);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)response);
+ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
+ curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT);
+
+ DBG(DBG_CONTROL,
+ DBG_log("sending scep request to '%s'", url)
+ )
+ res = curl_easy_perform(curl);
+
+ if (res == CURLE_OK)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("received scep response")
+ )
+ DBG(DBG_RAW,
+ DBG_dump_chunk("SCEP response:\n", *response)
+ )
+ }
+ else
+ {
+ plog("failed to fetch scep response from '%s': %s", url, errorbuffer);
+ }
+ curl_slist_free_all(headers);
+ curl_easy_cleanup(curl);
+ pfreeany(complete_url);
+
+ return (res == CURLE_OK);
+#else /* !LIBCURL */
+ plog("scep error: pluto wasn't compiled with libcurl support");
+ return FALSE;
+#endif /* !LIBCURL */
+}
+
+err_t
+scep_parse_response(chunk_t response, chunk_t transID, contentInfo_t *data
+, scep_attributes_t *attrs, x509cert_t *signer_cert)
+{
+ chunk_t attributes;
+
+ if (!pkcs7_parse_signedData(response, data, NULL, &attributes, signer_cert))
+ {
+ return "error parsing the scep response";
+ }
+ if (!parse_attributes(attributes, attrs))
+ {
+ return "error parsing the scep response attributes";
+ }
+ if (!same_chunk(transID, attrs->transID))
+ {
+ return "transaction ID of scep response does not match";
+ }
+ return NULL;
+}
diff --git a/programs/scepclient/scep.h b/programs/scepclient/scep.h
new file mode 100644
index 000000000..81e5d1a4b
--- /dev/null
+++ b/programs/scepclient/scep.h
@@ -0,0 +1,93 @@
+/**
+ * @file scep.h
+ * @brief SCEP specific functions
+ *
+ * Contains functions to build and parse SCEP requests and replies
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+#ifndef _SCEP_H
+#define _SCEP_H
+
+#include "../pluto/defs.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/pkcs7.h"
+
+/* supported SCEP operation types */
+typedef enum {
+ SCEP_PKI_OPERATION,
+ SCEP_GET_CA_CERT
+} scep_op_t;
+
+/* SCEP pkiStatus values */
+typedef enum {
+ SCEP_SUCCESS,
+ SCEP_FAILURE,
+ SCEP_PENDING,
+ SCEP_UNKNOWN
+} pkiStatus_t;
+
+/* SCEP messageType values */
+typedef enum {
+ SCEP_CertRep_MSG,
+ SCEP_PKCSReq_MSG,
+ SCEP_GetCertInitial_MSG,
+ SCEP_GetCert_MSG,
+ SCEP_GetCRL_MSG,
+ SCEP_Unknown_MSG
+} scep_msg_t;
+
+/* SCEP failure reasons */
+typedef enum {
+ SCEP_badAlg_REASON = 0,
+ SCEP_badMessageCheck_REASON = 1,
+ SCEP_badRequest_REASON = 2,
+ SCEP_badTime_REASON = 3,
+ SCEP_badCertId_REASON = 4,
+ SCEP_unknown_REASON = 5
+} failInfo_t;
+
+/* SCEP attributes */
+typedef struct {
+ scep_msg_t msgType;
+ pkiStatus_t pkiStatus;
+ failInfo_t failInfo;
+ chunk_t transID;
+ chunk_t senderNonce;
+ chunk_t recipientNonce;
+} scep_attributes_t;
+
+extern const scep_attributes_t empty_scep_attributes;
+
+extern bool parse_attributes(chunk_t blob, scep_attributes_t *attrs);
+extern void scep_generate_pkcs10_fingerprint(chunk_t pkcs10
+ , chunk_t *fingerprint);
+extern void scep_generate_transaction_id(const RSA_public_key_t *rsak
+ , chunk_t *transID, chunk_t *serialNumber);
+extern chunk_t scep_transId_attribute(chunk_t transaction_id);
+extern chunk_t scep_messageType_attribute(scep_msg_t m);
+extern chunk_t scep_senderNonce_attribute(void);
+extern chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg
+ , const x509cert_t *enc_cert, int enc_alg
+ , const x509cert_t *signer_cert, int digest_alg
+ , const RSA_private_key_t *private_key);
+extern bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op
+ , fetch_request_t request_type, chunk_t *response);
+extern err_t scep_parse_response(chunk_t response, chunk_t transID
+ , contentInfo_t *data, scep_attributes_t *attrs, x509cert_t *signer_cert);
+
+#endif /* _SCEP_H */
diff --git a/programs/scepclient/scepclient.8 b/programs/scepclient/scepclient.8
new file mode 100644
index 000000000..0d6364ef2
--- /dev/null
+++ b/programs/scepclient/scepclient.8
@@ -0,0 +1,288 @@
+.\"
+.TH "IPSEC_SCEPCLIENT" "8" "29 September 2005" "Jan Hutter, Martin Willi" ""
+.SH "NAME"
+ipsec scepclient \- Client for the SCEP protocol
+.SH "SYNOPSIS"
+.B ipsec scepclient [argument ...]
+.sp
+.B ipsec scepclient
+.B \-\-help
+.br
+.B ipsec scepclient
+.B \-\-version
+.SH "DESCRIPTION"
+.BR scepclient
+is a client implementation of Cisco System's Simple Certificate Enrollment Protocol (SCEP) written for Linux strongSwan <http://www.strongswan.org>.
+.BR scepclient
+is designed to be used for certificate enrollment on machines using the OpenSource IPsec solution
+.I strongSwan.
+.SH "FEATURES"
+.BR scepclient
+implements the following features of SCEP:
+.br
+.IP "\-" 4
+Automatic enrollment of client certificate using a preshared secret
+.IP "\-" 4
+Manual enrollment of client certificate. Offline fingerprint check required!
+.IP "\-" 4
+Acquisition of CA certificate(s)
+.SH "OPTIONS"
+.SS Basic Startup Options
+.B \-v, \-\-version
+.RS 4
+Display the version of ipsec scepclient.
+.PP
+.RE
+.B \-h, \-\-help
+.RS 4
+Display usage of ipsec scepclient.
+.RE
+
+.SS General Options
+.B \-u, \-\-url \fIurl\fP
+.RS 4
+Full HTTP URL of the SCEP server to be used for certificate enrollment and CA certificate acquisition.
+.RE
+.PP
+.B \-+, \-\-optionsfrom \fIfilename\fP
+.RS 4
+Reads additional options from \fIfilename\fP.
+.RE
+.PP
+.B \-f, \-\-force
+.RS 4
+Overwrite existing output file[s].
+.RE
+.PP
+.B \-q, \-\-quiet
+.RS 4
+Do not write log output to stderr.
+.RE
+
+.SS Options for CA Certificate Acquisition
+.B \-o, \-\-out cacert[=\fIfilename\fP]
+.RS 4
+Output file of acquired CA certificate. If more then one CA certificate is available, \fIfilename\fP is used as prefix for the resulting files.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/cacerts/caCert.der.
+.RE
+
+.SS Options For Certificate Enrollment
+.B \-i, \-\-in \fItype\fP[=\fIfilename\fP]
+.RS 4
+Input file for certificate enrollment. This option can be specified multiple times to specify input files for every \fItype\fP.
+Input files can bei either DER or PEM encoded.
+.PP
+Supported values for \fItype\fP:
+.IP "\fBpkcs1\fP" 12
+RSA private key in PKCS#1 file format. If no input of this type is specified, a RSA key gets generated.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/private/myKey.der.
+.IP "\fBcacert\-enc\fP" 12
+CA certificate to encrypt the SCEP request. Has to be specified for certificate enrollment.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/cacerts/caCert.der.
+.IP "\fBcacert\-sig\fP" 12
+CA certificate to check signature of SCEP reply. Has to be specified for certificate enrollment.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/cacerts/caCert.der.
+.RE
+.PP
+.B \-k, \-\-keylength \fIbits\fP
+.RS 4
+sets the key length for RSA key generation. The default length for a generated rsa key is set to 2048 bit.
+.RE
+.PP
+.B \-D, \-\-days \fIdays\fP
+.RS 4
+Validity of the self-signed X.509 certificate in days. The default is 1825 days (5 years).
+.RE
+.PP
+.B \-S, \-\-startdate \fIYYMMDDHHMMSS\fPZ
+.RS 4
+defines the \fBnotBefore\fP date when the X.509 certificate becomes valid.
+The date has the format \fIYYMMDDHHMMSS\fP and must be specified in UTC (Zulu time).
+If the \fB--startdate\fP option is not specified then the current date is taken as a default.
+.RE
+.PP
+.B \-E, \-\-enddate \fIYYMMDDHHMMSS\fPZ
+.RS 4
+defines the \fBnotAfter\fP date when the X.509 certificate will expire.
+The date has the format \fIYYMMDDHHMMSS\fP and must be specified in UTC (Zulu time).
+If the \fB--enddate\fP option is not specified then the default \fBnotAfter\fP value is computed by
+adding the validity interval specified by the \fB--days\fP option to the \fBnotBefore\fP date.
+.RE
+.PP
+.B \-d, \-\-dn \fIdn\fP
+.RS 4
+Distinguished name as comma separated list of relative distinguished names. Use quotation marks for a distinguished name containing spaces. If the \fB\-\-dn\fP parameter is missing then the default "C=CH, O=Linux strongSwan, CN=\fIhostname\fP"
+is used with \fIhostname\fP being the return value of the \fIgethostname\fP() function.
+.RE
+.PP
+.B \-s, \-\-subjectAltName \fItype\fP=\fIvalue\fP
+.RS 4
+Include subjectAltName in certificate request. This option can be specified multiple times to specify a subjectAltName
+for every \fItype\fP.
+.PP
+Supported values for \fItype\fP:
+.IP "\fBemail\fP" 12
+subjectAltName is a email address.
+.IP "\fBdns\fP" 12
+subjectAltName is a hostname.
+.IP "\fBip\fP" 12
+subjectAltName is a IP address.
+.RE
+.PP
+.B \-p, \-\-password \fIpw\fP
+.RS 4
+Password to be included as a \fIchallenge password\fP in SCEP request.
+If \fIpw\fP is \fB%prompt\fP', the password gets prompted for on the command line.
+.IP
+\- In automatic mode, this password corresponds to the preshared secret for the given enrollment.
+.IP
+\- In manual mode, this password can be used to later revoke the corresponding certificate.
+.RE
+.PP
+.B \-a, \-\-algorithm \fIalgo\fP
+.RS 4
+Change symmetric algorithm to use for encryption of certificate Request.
+The default is \fB3des\-cbc\fP.
+.PP
+Supported values for \fIalgo\fP:
+.IP "\fBdes\-cbc\fP" 12
+DES CBC encryption (key size = 56 bit).
+.IP "\fB3des\-cbc\fP" 12
+Triple DES CBC encryption (key size = 168 bit).
+.RE
+.PP
+.B \-o, \-\-out \fItype\fP[=\fIfilename\fP]
+.RS 4
+Output file for certificate enrollment. This option can be specified multiple times to specify output files for every \fItype\fP.
+.PP
+Supported values for \fItype\fP:
+.IP "\fBpkcs1\fP" 12
+RSA private key in PKCS#1 file format. If specified, the RSA key used for enrollment is stored in file \fIfilename\fP.
+If none of the \fItypes\fP listed below are specified, \fBscepclient\fP will stop after outputting this file.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/private/myKey.der.
+.IP "\fBpkcs10\fP" 12
+PKCS#10 certificate request. If specified, the PKCS#10 request used or certificate enrollment is stored in file \fIfilename\fP.
+If none of the \fItypes\fP listed below are specified, \fBscepclient\fP will stop after outputting this file.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/req/myReq.der.
+.IP "\fBpkcs7\fP" 12
+PKCS#7 SCEP request as it is sent using HTTP to the SCEP server. If specified, this SCEP request is stored in file \fIfilename\fP.
+If none of \fItypes\fP listed below is not specified, \fBscepclient\fP will stop after outputting this file.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/req/pkcs7.der.
+.IP "\fBcert-self\fP" 12
+Self-signed certificate. If specified the self-signed certificate is stored in file \fIfilename\fP.
+.br
+The default \fIfilename\fP is $CONFDIR/ipsec.d/certs/selfCert.der.
+.IP "\fBcert\fP" 12
+Enrolled certificate. This \fItype\fP must be specified for certificate enrollment.
+The enrolled certificate is stored in file \fIfilename\fP.
+.br
+The default \fIfilename\fP is set to $CONFDIR/ipsec.d/certs/myCert.der.
+.RE
+.PP
+.B \-m, \-\-method \fImethod\fP
+.RS 4
+Change HTTP request method for certificate enrollment. Default is \fBget\fP.
+.PP
+Supported values for \fImethod\fP:
+.IP "\fBpost\fP" 12
+Certificate enrollment using HTTP POST. Must be supported by the given SCEP server.
+.IP "\fBget\fP" 12
+Certificate enrollment using HTTP GET.
+.RE
+.PP
+.B \-t, \-\-interval \fIseconds\fP
+.RS 4
+Set interval time in seconds when polling in manual mode.
+The default interval is set to 5 seconds.
+.RE
+.PP
+.B \-x, \-\-maxpolltime \fIseconds\fP
+.RS 4
+Set max time in seconds to poll in manual mode.
+The default max time is set to unlimited.
+.RE
+
+.SS Debugging Output Options:
+.B \-A, \-\-debug\-all
+.RS 4
+Log everything except private data.
+.RE
+.PP
+.B \-P, \-\-debug\-parsing
+.RS 4
+Log parsing relevant stuff.
+.RE
+.PP
+.B \-R, \-\-debug\-raw
+.RS 4
+Log raw hex dumps.
+.RE
+.PP
+.B \-C, \-\-debug\-control
+.RS 4
+Log informations about control flow.
+.RE
+.PP
+.B \-M, \-\-debug\-controlmore
+.RS 4
+Log more detailed informations about control flow.
+.RE
+.PP
+.B \-X, \-\-debug\-private
+.RS 4
+Log sensitive data (e.g. private keys).
+.RE
+.SH "EXAMPLES"
+.B ipsec scepclient \-\-out caCert \-\-url http://scepserver/cgi\-bin/pkiclient.exe \-f
+.RS 4
+Acquire CA certificate from SCEP server and store it in the default file $CONFDIR/ipsec.d/cacerts/caCert.der.
+If more then one CA certificate is returned, store them in files named caCert.der\-1', caCert.der\-2', etc.
+.br
+Existing files are overwritten.
+.RE
+.PP
+.B ipsec scepclient \-\-out pkcs1=joeKey.der \-k 1024
+.RS 4
+Generate RSA private key with key length of 1024 bit and store it in file joeKey.der.
+.RE
+.PP
+.B ipsec scepclient \-\-in pkcs1=joeKey.der \-\-out pkcs10=joeReq.der \e
+.br
+.B \-\-dn \*(rqC=AT, CN=John Doe\*(rq \-s email=john@doe.com \-p mypassword
+.RS 4
+Generate a PKCS#10 request and store it in file joeReq.der. Use the RSA private key joeKey.der
+created earlier to sign the PKCS#10\-Request. In addition to the distinguished name include a
+email\-subjectAltName and a challenge password in the request.
+.RE
+.PP
+.B ipsec scepclient \-\-out pkcs1=joeKey.der \-\-out cert==joeCert.der \e
+.br
+.B \-\-dn \*(rqC=CH, CN=John Doe\*(rq \-k 512 \-p 5xH2pnT7wq \e
+.br
+.B \-\-url http://scep.hsr.ch/cgi\-bin/pkiclient.exe \e
+.br
+.B \-\-in cacert\-enc=caCert.der \-\-in cacert\-sig=caCert.der
+.RS 4
+Generate a new RSA key for the request and store it in joeKey.der. Then enroll a certificate and store as joeCert.der.
+The challenge password is '5xH2pnT7wq'. The encryption and signature check has to be made with the same CA certificate
+caCert.der.
+.RE
+
+
+.SH "BUGS"
+\fB\-\-optionsfrom\fP seems to have parsing problems reading option files containing strings in quotation marks.
+.SH "COPYRIGHT"
+Copyright (C) 2005 Jan Hutter, Martin Willi
+.br
+Hochschule fuer Technik Rapperswil
+.PP
+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>.
+.PP
+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.
diff --git a/programs/scepclient/scepclient.c b/programs/scepclient/scepclient.c
new file mode 100644
index 000000000..bde460844
--- /dev/null
+++ b/programs/scepclient/scepclient.c
@@ -0,0 +1,1036 @@
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+/**
+ * @file main.c
+ * @brief scepclient main program
+ */
+
+/**
+ * @mainpage SCEP for Linux strongSwan
+ *
+ * Documentation of SCEP for Linux StrongSwan
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <gmp.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+#include "../pluto/oid.h"
+#include "../pluto/asn1.h"
+#include "../pluto/pkcs1.h"
+#include "../pluto/pkcs7.h"
+#include "../pluto/certs.h"
+#include "../pluto/fetch.h"
+#include "../pluto/rnd.h"
+
+#include "rsakey.h"
+#include "pkcs10.h"
+#include "scep.h"
+
+/*
+ * definition of some defaults
+ */
+
+/* default name of DER-encoded PKCS#1 private key file */
+#define DEFAULT_FILENAME_PKCS1 "myKey.der"
+
+/* default name of DER-encoded PKCS#10 certificate request file */
+#define DEFAULT_FILENAME_PKCS10 "myReq.der"
+
+/* default name of DER-encoded PKCS#7 file */
+#define DEFAULT_FILENAME_PKCS7 "pkcs7.der"
+
+/* default name of DER-encoded self-signed X.509 certificate file */
+#define DEFAULT_FILENAME_CERT_SELF "selfCert.der"
+
+/* default name of DER-encoded X.509 certificate file */
+#define DEFAULT_FILENAME_CERT "myCert.der"
+
+/* default name of DER-encoded CA cert file used for key encipherment */
+#define DEFAULT_FILENAME_CACERT_ENC "caCert.der"
+
+/* default name of the der encoded CA cert file used for signature verification */
+#define DEFAULT_FILENAME_CACERT_SIG "caCert.der"
+
+/* default prefix of the der encoded CA certificates received from the SCEP server */
+#define DEFAULT_FILENAME_PREFIX_CACERT "caCert.der"
+
+/* default certificate validity */
+#define DEFAULT_CERT_VALIDITY 5 * 3600 * 24 * 365 /* seconds */
+
+/* default polling time interval in SCEP manual mode */
+#define DEFAULT_POLL_INTERVAL 20 /* seconds */
+
+/* default key length for self-generated RSA keys */
+#define DEFAULT_RSA_KEY_LENGTH 2048 /* bits */
+
+/* default distinguished name */
+#define DEFAULT_DN "C=CH, O=Linux strongSwan, CN="
+
+/* challenge password buffer size */
+#define MAX_PASSWORD_LENGTH 256
+
+/* Max length of filename for tempfile */
+#define MAX_TEMP_FILENAME_LENGTH 256
+
+
+/* current scepclient version */
+static const char *scepclient_version = "1.0";
+
+/* by default the CRL policy is lenient */
+bool strict_crl_policy = FALSE;
+
+/* by default pluto does not check crls dynamically */
+long crl_check_interval = 0;
+
+/* by default pluto logs out after every smartcard use */
+bool pkcs11_keep_state = FALSE;
+
+
+/*
+ * Global variables
+ */
+
+RSA_private_key_t *private_key = NULL;
+
+chunk_t pkcs1;
+chunk_t pkcs7;
+chunk_t subject;
+chunk_t challengePassword;
+chunk_t serialNumber;
+chunk_t transID;
+chunk_t fingerprint;
+chunk_t issuerAndSubject;
+chunk_t getCertInitial;
+chunk_t scep_response;
+cert_t cert;
+
+x509cert_t *x509_signer = NULL;
+x509cert_t *x509_ca_enc = NULL;
+x509cert_t *x509_ca_sig = NULL;
+generalName_t *subjectAltNames = NULL;
+pkcs10_t *pkcs10 = NULL;
+
+/**
+ * @brief exit scepclient
+ *
+ * The log is closed and leaks are reported
+ * if LEAK_DETECTIVE is activated
+ *
+ * @param status 0 = OK, 1 = general discomfort
+ */
+static void
+exit_scepclient(err_t message, ...)
+{
+ if (private_key != NULL)
+ {
+ free_RSA_private_content(private_key);
+ pfree(private_key);
+ }
+ freeanychunk(pkcs1);
+ freeanychunk(pkcs7);
+ freeanychunk(subject);
+ freeanychunk(serialNumber);
+ freeanychunk(transID);
+ freeanychunk(fingerprint);
+ freeanychunk(issuerAndSubject);
+ freeanychunk(getCertInitial);
+ if (scep_response.ptr != NULL)
+ free(scep_response.ptr);
+
+ free_generalNames(subjectAltNames, TRUE);
+ if (x509_signer != NULL)
+ x509_signer->subjectAltName = NULL;
+
+ free_x509cert(x509_signer);
+ free_x509cert(x509_ca_enc);
+ free_x509cert(x509_ca_sig);
+ pkcs10_free(pkcs10);
+
+#ifdef LEAK_DETECTIVE
+ report_leaks();
+#endif /* LEAK_DETECTIVE */
+ close_log();
+
+ /* print any error message to stderr */
+ if (message != NULL && *message != '\0')
+ {
+ va_list args;
+ char m[LOG_WIDTH]; /* longer messages will be truncated */
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ fprintf(stderr, "error: %s\n", m);
+ exit(-1);
+ }
+ exit(0);
+}
+
+/**
+ * @brief prints the program version and exits
+ *
+ */
+static void
+version(void)
+{
+ printf("scepclient %s\n", scepclient_version);
+ exit_scepclient(NULL);
+}
+
+/**
+ * @brief prints the usage of the program to the stderr output
+ *
+ * If message is set, program is exitet with 1 (error)
+ * @param message message in case of an error
+ */
+static void
+usage(const char *message)
+{
+ fprintf(stderr,
+ "Usage: scepclient\n"
+ " --help (-h) show usage and exit\n"
+ " --version (-v) show version and exit\n"
+ " --quiet (-q) do not write log output to stderr\n"
+ " --in (-i) <type>[=<filename>] use <filename> of <type> for input \n"
+ " <type> = pkcs1 | cacert-enc | cacert-sig\n"
+ " - if no pkcs1 input is defined, a \n"
+ " RSA key will be generated\n"
+ " - if no filename is given, default is used\n"
+ " --out (-o) <type>[=<filename>] write output of <type> to <filename>\n"
+ " multiple outputs are allowed\n"
+ " <type> = pkcs1 | pkcs10 | pkcs7 | cert-self | cert | cacert\n"
+ " - type cacert defines filename prefix of\n"
+ " received CA certificate(s)\n"
+ " - if no filename is given, default is used\n"
+ " --optionsfrom (-+) <filename> reads additional options from given file\n"
+ " --force (-f) force existing file(s)\n"
+ "\n"
+ "Options for key generation (pkcs1):\n"
+ " --keylength (-k) <bits> key length for RSA key generation\n"
+ "(default: 2048 bits)\n"
+ "\n"
+ "Options for validity:\n"
+ " --days (-D) <days> validity in days\n"
+ " --startdate (-S) <YYMMDDHHMMSS>Z not valid before date\n"
+ " --enddate (-E) <YYMMDDHHMMSS>Z not valid after date\n"
+ "\n"
+ "Options for request generation (pkcs10):\n"
+ " --dn (-d) <dn> comma separated list of distinguished names\n"
+ " --subjectAltName (-s) <t>=<v> include subjectAltName in certificate request\n"
+ " <t> = email | dns | ip \n"
+ " --password (-p) <pw> challenge password\n"
+ " - if pw is '%%prompt', password gets prompted for\n"
+ " --algorithm (-a) <algo> use specified algorithm for PKCS#7 encryption\n"
+ " <algo> = des-cbc | 3des-cbc (default: 3des-cbc)\n"
+ "\n"
+ "Options for enrollment (cert):\n"
+ " --url (-u) <url> url of the SCEP server\n"
+ " --method (-m) post | get http request type\n"
+ " --interval (-t) <seconds> manual mode poll interval in seconds (default 20s)\n"
+ " --maxpolltime (-x) <seconds> max poll time in seconds when in manual mode\n"
+ " (default: unlimited)\n"
+#ifdef DEBUG
+ "\n"
+ "Debugging output:\n"
+ " --debug-all (-A) show everything except private\n"
+ " --debug-parsing (-P) show parsing relevant stuff\n"
+ " --debug-raw (-R) show raw hex dumps\n"
+ " --debug-control (-C) show control flow output\n"
+ " --debug-controlmore (-M) show more control flow\n"
+ " --debug-private (-X) show sensitive data (private keys, etc.)\n"
+#endif
+ );
+ exit_scepclient(message);
+}
+
+/**
+ * @brief main of scepclient
+ *
+ * @param argc number of arguments
+ * @param argv pointer to the argument values
+ */
+int main(int argc, char **argv)
+{
+ /* external values */
+ extern char * optarg;
+ extern int optind;
+
+ /* type of input and output files */
+ typedef enum {
+ PKCS1 = 0x01,
+ PKCS10 = 0x02,
+ PKCS7 = 0x04,
+ CERT_SELF = 0x08,
+ CERT = 0x10,
+ CACERT_ENC = 0x20,
+ CACERT_SIG = 0x40
+ } scep_filetype_t;
+
+ /* filetype to read from, defaults to "generate a key" */
+ scep_filetype_t filetype_in = 0;
+
+ /* filetype to write to, no default here */
+ scep_filetype_t filetype_out = 0;
+
+ /* input files */
+ char *file_in_pkcs1 = DEFAULT_FILENAME_PKCS1;
+ char *file_in_cacert_enc = DEFAULT_FILENAME_CACERT_ENC;
+ char *file_in_cacert_sig = DEFAULT_FILENAME_CACERT_SIG;
+
+ /* output files */
+ char *file_out_pkcs1 = DEFAULT_FILENAME_PKCS1;
+ char *file_out_pkcs10 = DEFAULT_FILENAME_PKCS10;
+ char *file_out_pkcs7 = DEFAULT_FILENAME_PKCS7;
+ char *file_out_cert_self = DEFAULT_FILENAME_CERT_SELF;
+ char *file_out_cert = DEFAULT_FILENAME_CERT;
+ char *file_out_prefix_cacert = DEFAULT_FILENAME_PREFIX_CACERT;
+
+ /* by default user certificate is requested */
+ bool request_ca_certificate = FALSE;
+
+ /* by default existing files are not overwritten */
+ bool force = FALSE;
+
+ /* length of RSA key in bits */
+ u_int rsa_keylength = DEFAULT_RSA_KEY_LENGTH;
+
+ /* validity of self-signed certificate */
+ time_t validity = DEFAULT_CERT_VALIDITY;
+ time_t notBefore = 0;
+ time_t notAfter = 0;
+
+ /* distinguished name for requested certificate, ASCII format */
+ char *distinguishedName = NULL;
+
+ /* challenge password */
+ char challenge_password_buffer[MAX_PASSWORD_LENGTH];
+
+ /* symmetric encryption algorithm used by pkcs7, default is 3DES */
+ int pkcs7_symmetric_cipher = OID_3DES_EDE_CBC;
+
+ /* digest algorithm used by pkcs7, default is MD5 */
+ int pkcs7_digest_alg = OID_MD5;
+
+ /* signature algorithm used by pkcs10, default is MD5 with RSA encryption */
+ int pkcs10_signature_alg = OID_MD5;
+
+ /* URL of the SCEP-Server */
+ char *scep_url = NULL;
+
+ /* http request method, default is GET */
+ fetch_request_t request_type = FETCH_GET;
+
+ /* poll interval time in manual mode in seconds */
+ u_int poll_interval = DEFAULT_POLL_INTERVAL;
+
+ /* maximum poll time */
+ u_int max_poll_time = 0;
+
+ err_t ugh = NULL;
+
+ /* initialize global variables */
+ pkcs1 = empty_chunk;
+ pkcs7 = empty_chunk;
+ serialNumber = empty_chunk;
+ transID = empty_chunk;
+ fingerprint = empty_chunk;
+ issuerAndSubject = empty_chunk;
+ challengePassword = empty_chunk;
+ getCertInitial = empty_chunk;
+ scep_response = empty_chunk;
+ log_to_stderr = TRUE;
+
+ for (;;)
+ {
+ static const struct option long_opts[] = {
+ /* name, has_arg, flag, val */
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "optionsfrom", required_argument, NULL, '+' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "in", required_argument, NULL, 'i' },
+ { "out", required_argument, NULL, 'o' },
+ { "force", no_argument, NULL, 'f' },
+ { "keylength", required_argument, NULL, 'k' },
+ { "dn", required_argument, NULL, 'd' },
+ { "days", required_argument, NULL, 'D' },
+ { "startdate", required_argument, NULL, 'S' },
+ { "enddate", required_argument, NULL, 'E' },
+ { "subjectAltName", required_argument, NULL, 's' },
+ { "password", required_argument, NULL, 'p' },
+ { "algorithm", required_argument, NULL, 'a' },
+ { "url", required_argument, NULL, 'u' },
+ { "method", required_argument, NULL, 'm' },
+ { "interval", required_argument, NULL, 't' },
+ { "maxpolltime", required_argument, NULL, 'x' },
+#ifdef DEBUG
+ { "debug-all", no_argument, NULL, 'A' },
+ { "debug-parsing", no_argument, NULL, 'P'},
+ { "debug-raw", no_argument, NULL, 'R'},
+ { "debug-control", no_argument, NULL, 'C'},
+ { "debug-controlmore", no_argument, NULL, 'M'},
+ { "debug-private", no_argument, NULL, 'X'},
+#endif
+ { 0,0,0,0 }
+ };
+
+ /* parse next option */
+ int c = getopt_long(argc, argv, "hv+:qi:o:fk:d:s:p:a:u:m:t:x:APRCMS", long_opts, NULL);
+
+ switch (c)
+ {
+ case EOF: /* end of flags */
+ break;
+
+ case 'h': /* --help */
+ usage(NULL);
+
+ case 'v': /* --version */
+ version();
+
+ case 'q': /* --quiet */
+ log_to_stderr = FALSE;
+ continue;
+
+ case 'i': /* --in <type> [= <filename>] */
+ {
+ char *filename = strstr(optarg, "=");
+
+ if (filename)
+ {
+ /* replace '=' by '\0' */
+ *filename = '\0';
+ /* set pointer to start of filename */
+ filename++;
+ }
+ if (strcasecmp("pkcs1", optarg) == 0)
+ {
+ filetype_in |= PKCS1;
+ if (filename)
+ file_in_pkcs1 = filename;
+ }
+ else if (strcasecmp("cacert-enc", optarg) == 0)
+ {
+ filetype_in |= CACERT_ENC;
+ if (filename)
+ file_in_cacert_enc = filename;
+ }
+ else if (strcasecmp("cacert-sig", optarg) == 0)
+ {
+ filetype_in |= CACERT_SIG;
+ if (filename)
+ file_in_cacert_sig = filename;
+ }
+ else
+ {
+ usage("invalid --in file type");
+ }
+ continue;
+ }
+
+ case 'o': /* --out <type> [= <filename>] */
+ {
+ char *filename = strstr(optarg, "=");
+
+ if (filename)
+ {
+ /* replace '=' by '\0' */
+ *filename = '\0';
+ /* set pointer to start of filename */
+ filename++;
+ }
+ if (strcasecmp("pkcs1", optarg) == 0)
+ {
+ filetype_out |= PKCS1;
+ if (filename)
+ file_out_pkcs1 = filename;
+ }
+ else if (strcasecmp("pkcs10", optarg) == 0)
+ {
+ filetype_out |= PKCS10;
+ if (filename)
+ file_out_pkcs10 = filename;
+ }
+ else if (strcasecmp("pkcs7", optarg) == 0)
+ {
+ filetype_out |= PKCS7;
+ if (filename)
+ file_out_pkcs7 = filename;
+ }
+ else if (strcasecmp("cert-self", optarg) == 0)
+ {
+ filetype_out |= CERT_SELF;
+ if (filename)
+ file_out_cert_self = filename;
+ }
+ else if (strcasecmp("cert", optarg) == 0)
+ {
+ filetype_out |= CERT;
+ if (filename)
+ file_out_cert = filename;
+ }
+ else if (strcasecmp("cacert", optarg) == 0)
+ {
+ request_ca_certificate = TRUE;
+ if (filename)
+ file_out_prefix_cacert = filename;
+ }
+ else
+ {
+ usage("invalid --out file type");
+ }
+ continue;
+ }
+
+ case 'f': /* --force */
+ force = TRUE;
+ continue;
+
+ case '+': /* --optionsfrom <filename> */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ continue;
+
+ case 'k': /* --keylength <length> */
+ {
+ div_t q;
+
+ rsa_keylength = atoi(optarg);
+ if (rsa_keylength == 0)
+ usage("invalid keylength");
+
+ /* check if key length is a multiple of 8 bits */
+ q = div(rsa_keylength, 2*BITS_PER_BYTE);
+ if (q.rem != 0)
+ {
+ exit_scepclient("keylength is not a multiple of %d bits!"
+ , 2*BITS_PER_BYTE);
+ }
+ continue;
+ }
+
+ case 'D': /* --days */
+ if (optarg == NULL || !isdigit(optarg[0]))
+ usage("missing number of days");
+ {
+ char *endptr;
+ long days = strtol(optarg, &endptr, 0);
+
+ if (*endptr != '\0' || endptr == optarg
+ || days <= 0)
+ usage("<days> must be a positive number");
+ validity = 24*3600*days;
+ }
+ continue;
+
+ case 'S': /* --startdate */
+ if (optarg == NULL || strlen(optarg) != 13 || optarg[12] != 'Z')
+ usage("date format must be YYMMDDHHMMSSZ");
+ {
+ chunk_t date = { optarg, 13 };
+ notBefore = asn1totime(&date, ASN1_UTCTIME);
+ }
+ continue;
+
+ case 'E': /* --enddate */
+ if (optarg == NULL || strlen(optarg) != 13 || optarg[12] != 'Z')
+ usage("date format must be YYMMDDHHMMSSZ");
+ {
+ chunk_t date = { optarg, 13 };
+ notAfter = asn1totime(&date, ASN1_UTCTIME);
+ }
+ continue;
+
+ case 'd': /* --dn */
+ if (distinguishedName)
+ usage("only one distinguished name allowed");
+ distinguishedName = optarg;
+ continue;
+
+ case 's': /* --subjectAltName */
+ {
+ generalNames_t kind;
+ char *value = strstr(optarg, "=");
+
+ if (value)
+ {
+ /* replace '=' by '\0' */
+ *value = '\0';
+ /* set pointer to start of value */
+ value++;
+ }
+
+ if (!strcasecmp("email", optarg))
+ kind = GN_RFC822_NAME;
+ else if (!strcasecmp("dns", optarg))
+ kind = GN_DNS_NAME;
+ else if (!strcasecmp("ip", optarg))
+ kind = GN_IP_ADDRESS;
+ else
+ {
+ usage("invalid --subjectAltName type");
+ continue;
+ }
+ pkcs10_add_subjectAltName(&subjectAltNames, kind, value);
+ continue;
+ }
+
+ case 'p': /* --password */
+ if (challengePassword.len > 0)
+ usage("only one challenge password allowed");
+
+ if (strcasecmp("%prompt", optarg) == 0)
+ {
+ printf("Challenge password: ");
+ if (fgets(challenge_password_buffer, sizeof(challenge_password_buffer)-1, stdin))
+ {
+ challengePassword.ptr = challenge_password_buffer;
+ /* discard the terminating '\n' from the input */
+ challengePassword.len = strlen(challenge_password_buffer) - 1;
+ }
+ else
+ {
+ usage("challenge password could not be read");
+ }
+ }
+ else
+ {
+ challengePassword.ptr = optarg;
+ challengePassword.len = strlen(optarg);
+ }
+ continue;
+
+ case 'u': /* -- url */
+ if (scep_url)
+ usage("only one URL argument allowed");
+ scep_url = optarg;
+ continue;
+
+ case 'm': /* --method */
+ if (strcasecmp("post", optarg) == 0)
+ request_type = FETCH_POST;
+ else if (strcasecmp("get", optarg) == 0)
+ request_type = FETCH_GET;
+ else
+ usage("invalid http request method specified");
+ continue;
+
+ case 't': /* --interval */
+ poll_interval = atoi(optarg);
+ if (poll_interval <= 0)
+ usage("invalid interval specified");
+ continue;
+
+ case 'x': /* --maxpolltime */
+ max_poll_time = atoi(optarg);
+ if (max_poll_time < 0)
+ usage("invalid maxpolltime specified");
+ continue;
+
+ case 'a': /*--algorithm */
+ if (strcasecmp("des-cbc", optarg) == 0)
+ pkcs7_symmetric_cipher = OID_DES_CBC;
+ else if (strcasecmp("3des-cbc", optarg) == 0)
+ pkcs7_symmetric_cipher = OID_3DES_EDE_CBC;
+ else
+ usage("invalid encryption algorithm specified");
+ continue;
+#ifdef DEBUG
+ case 'A': /* --debug-all */
+ base_debugging |= DBG_ALL;
+ continue;
+ case 'P': /* debug parsing */
+ base_debugging |= DBG_PARSING;
+ continue;
+ case 'R': /* debug raw */
+ base_debugging |= DBG_RAW;
+ continue;
+ case 'C': /* debug control */
+ base_debugging |= DBG_CONTROL;
+ continue;
+ case 'M': /* debug control more */
+ base_debugging |= DBG_CONTROLMORE;
+ continue;
+ case 'X': /* debug private */
+ base_debugging |= DBG_PRIVATE;
+ continue;
+#endif
+ default:
+ usage("unknown option");
+ }
+ /* break from loop */
+ break;
+ }
+
+ init_log("scepclient");
+ cur_debugging = base_debugging;
+ init_rnd_pool();
+ init_fetch();
+
+ if ((filetype_out == 0) && (!request_ca_certificate))
+ usage ("--out filetype required");
+
+ if (request_ca_certificate && (filetype_out > 0 || filetype_in > 0))
+ usage("in CA certificate request, no other --in or --out option allowed");
+
+ /* check if url is given, if cert output defined */
+ if (((filetype_out & CERT) || request_ca_certificate) && !scep_url)
+ usage("URL of SCEP server required");
+
+ /* check for sanity of --in/--out */
+ if (!filetype_in && (filetype_in > filetype_out))
+ usage("cannot generate --out of given --in!");
+
+ /*
+ * input of PKCS#1 file
+ */
+ private_key = alloc_thing(RSA_private_key_t, "RSA_private_key_t");
+
+ if (filetype_in & PKCS1) /* load an RSA key pair from file */
+ {
+ prompt_pass_t pass = { "", FALSE, STDIN_FILENO };
+ const char *path = concatenate_paths(PRIVATE_KEY_PATH, file_in_pkcs1);
+
+ ugh = load_rsa_private_key(path, &pass, private_key);
+ }
+ else /* generate an RSA key pair */
+ {
+ ugh = generate_rsa_private_key(rsa_keylength, private_key);
+ }
+ if (ugh != NULL)
+ exit_scepclient(ugh);
+
+ /* check for minimum key length */
+ if ((private_key->pub.k) < RSA_MIN_OCTETS)
+ {
+ exit_scepclient("length of RSA key has to be at least %d bits"
+ ,RSA_MIN_OCTETS * BITS_PER_BYTE);
+ }
+
+ /*
+ * input of PKCS#10 file
+ */
+ if (filetype_in & PKCS10)
+ {
+ /* user wants to load a pkcs10 request
+ * operation is not yet supported
+ * would require a PKCS#10 parsing function
+
+ pkcs10 = pkcs10_read_from_file(file_in_pkcs10);
+
+ */
+ }
+ else
+ {
+ char buf[IDTOA_BUF];
+ chunk_t dn = empty_chunk;
+
+ dn.ptr = buf;
+
+ if (distinguishedName == NULL)
+ {
+ char buf[BUF_LEN];
+ int n = sprintf(buf, DEFAULT_DN);
+
+ /* set the common name to the hostname */
+ if (gethostname(buf + n, BUF_LEN - n) || strlen(buf) == n)
+ {
+ exit_scepclient("no hostname defined, use "
+ "--dn <distinguished name> option");
+ }
+ distinguishedName = buf;
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("dn: '%s'", distinguishedName);
+ )
+ ugh = atodn(distinguishedName, &dn);
+ if (ugh != NULL)
+ exit_scepclient(ugh);
+
+ clonetochunk(subject, dn.ptr, dn.len, "subject dn");
+
+ DBG(DBG_CONTROL,
+ DBG_log("building pkcs10 object:")
+ )
+ pkcs10 = pkcs10_build(private_key, subject, challengePassword
+ , subjectAltNames, pkcs10_signature_alg);
+ scep_generate_pkcs10_fingerprint(pkcs10->request, &fingerprint);
+ plog(" fingerprint: %.*s", (int)fingerprint.len, fingerprint.ptr);
+ }
+
+ /*
+ * output of PKCS#10 file
+ */
+ if (filetype_out & PKCS10)
+ {
+ const char *path = concatenate_paths(REQ_PATH, file_out_pkcs10);
+
+ if (!write_chunk(path, "pkcs10", pkcs10->request, 0022, force))
+ exit_scepclient("could not write pkcs10 file '%s'", path);
+
+ filetype_out &= ~PKCS10; /* delete PKCS10 flag */
+ }
+
+ if (!filetype_out)
+ exit_scepclient(NULL); /* no further output required */
+
+ /*
+ * output of PKCS#1 file
+ */
+ if (filetype_out & PKCS1)
+ {
+ const char *path = concatenate_paths(PRIVATE_KEY_PATH, file_out_pkcs1);
+
+ DBG(DBG_CONTROL,
+ DBG_log("building pkcs1 object:")
+ )
+ pkcs1 = pkcs1_build_private_key(private_key);
+
+ if (!write_chunk(path, "pkcs1", pkcs1, 0066, force))
+ exit_scepclient("could not write pkcs1 file '%s'", path);
+
+ filetype_out &= ~PKCS1; /* delete PKCS1 flag */
+ }
+
+ if (!filetype_out)
+ exit_scepclient(NULL); /* no further output required */
+
+ scep_generate_transaction_id((const RSA_public_key_t *)private_key
+ , &transID, &serialNumber);
+ plog(" transaction ID: %.*s", (int)transID.len, transID.ptr);
+
+ /* generate a self-signed X.509 certificate */
+ x509_signer = alloc_thing(x509cert_t, "signer cert");
+ *x509_signer = empty_x509cert;
+ x509_signer->serialNumber = serialNumber;
+ x509_signer->sigAlg = OID_SHA1_WITH_RSA;
+ x509_signer->issuer = subject;
+ x509_signer->notBefore = (notBefore)? notBefore
+ : time(NULL);
+ x509_signer->notAfter = (notAfter)? notAfter
+ : x509_signer->notBefore + validity;
+ x509_signer->subject = subject;
+ x509_signer->subjectAltName = subjectAltNames;
+
+ build_x509cert(x509_signer, (const RSA_public_key_t *)private_key
+ , private_key);
+
+ /*
+ * output of self-signed X.509 certificate file
+ */
+ if (filetype_out & CERT_SELF)
+ {
+ const char *path = concatenate_paths(HOST_CERT_PATH, file_out_cert_self);
+
+ if (!write_chunk(path, "self-signed cert", x509_signer->certificate, 0022, force))
+ exit_scepclient("could not write self-signed cert file '%s'", path);
+;
+ filetype_out &= ~CERT_SELF; /* delete CERT_SELF flag */
+ }
+
+ if (!filetype_out)
+ exit_scepclient(NULL); /* no further output required */
+
+ /*
+ * load ca encryption certificate
+ */
+ {
+ const char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_enc);
+ cert_t cert;
+
+ if (!load_cert(path, "encryption cacert", &cert))
+ exit_scepclient("could not load encryption cacert file '%s'", path);
+ x509_ca_enc = cert.u.x509;
+ }
+
+ /*
+ * input of PKCS#7 file
+ */
+ if (filetype_in & PKCS7)
+ {
+ /* user wants to load a pkcs7 encrypted request
+ * operation is not yet supported!
+ * would require additional parsing of transaction-id
+
+ pkcs7 = pkcs7_read_from_file(file_in_pkcs7);
+
+ */
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("building pkcs7 request")
+ )
+ pkcs7 = scep_build_request(pkcs10->request
+ , transID, SCEP_PKCSReq_MSG
+ , x509_ca_enc, pkcs7_symmetric_cipher
+ , x509_signer, pkcs7_digest_alg, private_key);
+ }
+
+ /*
+ * output pkcs7 encrypted and signed certificate request
+ */
+ if (filetype_out & PKCS7)
+ {
+ const char *path = concatenate_paths(REQ_PATH, file_out_pkcs7);
+
+ if (!write_chunk(path, "pkcs7 encrypted request", pkcs7, 0022, force))
+ exit_scepclient("could not write pkcs7 file '%s'", path);
+;
+ filetype_out &= ~PKCS7; /* delete PKCS7 flag */
+ }
+
+ if (!filetype_out)
+ exit_scepclient(NULL); /* no further output required */
+
+ /*
+ * output certificate fetch from SCEP server
+ */
+ if (filetype_out & CERT)
+ {
+ const char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_sig);
+ cert_t cert;
+ time_t poll_start;
+
+ x509cert_t *certs = NULL;
+ chunk_t envelopedData = empty_chunk;
+ chunk_t certData = empty_chunk;
+ contentInfo_t data = empty_contentInfo;
+ scep_attributes_t attrs = empty_scep_attributes;
+
+ if (!load_cert(path, "signature cacert", &cert))
+ exit_scepclient("could not load signature cacert file '%s'", path);
+ x509_ca_sig = cert.u.x509;
+
+ if (!scep_http_request(scep_url, pkcs7, SCEP_PKI_OPERATION
+ , request_type, &scep_response))
+ {
+ exit_scepclient("did not receive a valid scep response");
+ }
+ ugh = scep_parse_response(scep_response, transID, &data, &attrs
+ , x509_ca_sig);
+ if (ugh != NULL)
+ exit_scepclient(ugh);
+
+ /* in case of manual mode, we are going into a polling loop */
+ if (attrs.pkiStatus == SCEP_PENDING)
+ {
+ plog(" scep request pending, polling every %d seconds"
+ , poll_interval);
+ time(&poll_start);
+ issuerAndSubject = asn1_wrap(ASN1_SEQUENCE, "cc"
+ , x509_ca_sig->subject
+ , subject);
+ }
+ while (attrs.pkiStatus == SCEP_PENDING)
+ {
+ if (max_poll_time > 0
+ && (time(NULL) - poll_start >= max_poll_time))
+ {
+ exit_scepclient("maximum poll time reached: %d seconds"
+ , max_poll_time);
+ }
+ DBG(DBG_CONTROL,
+ DBG_log("going to sleep for %d seconds", poll_interval)
+ )
+ sleep(poll_interval);
+ free(scep_response.ptr);
+
+ DBG(DBG_CONTROL,
+ DBG_log("fingerprint: %.*s", (int)fingerprint.len, fingerprint.ptr);
+ DBG_log("transaction ID: %.*s", (int)transID.len, transID.ptr)
+ )
+
+ freeanychunk(getCertInitial);
+ getCertInitial = scep_build_request(issuerAndSubject
+ , transID, SCEP_GetCertInitial_MSG
+ , x509_ca_enc, pkcs7_symmetric_cipher
+ , x509_signer, pkcs7_digest_alg, private_key);
+
+ if (!scep_http_request(scep_url, getCertInitial, SCEP_PKI_OPERATION
+ , request_type, &scep_response))
+ {
+ exit_scepclient("did not receive a valid scep response");
+ }
+ ugh = scep_parse_response(scep_response, transID, &data, &attrs
+ , x509_ca_sig);
+ if (ugh != NULL)
+ exit_scepclient(ugh);
+ }
+
+ if (attrs.pkiStatus != SCEP_SUCCESS)
+ {
+ exit_scepclient("reply status is not 'SUCCESS'");
+ }
+
+ envelopedData = data.content;
+
+ if (data.type != OID_PKCS7_DATA
+ || !parse_asn1_simple_object(&envelopedData, ASN1_OCTET_STRING, 0, "data"))
+ {
+ exit_scepclient("contentInfo is not of type 'data'");
+ }
+ if (!pkcs7_parse_envelopedData(envelopedData, &certData
+ , serialNumber, private_key))
+ {
+ exit_scepclient("could not decrypt envelopedData");
+ }
+ if (!pkcs7_parse_signedData(certData, NULL, &certs, NULL, NULL))
+ {
+ exit_scepclient("error parsing the scep response");
+ }
+ freeanychunk(certData);
+
+ /* store the end entity certificate */
+ path = concatenate_paths(HOST_CERT_PATH, file_out_cert);
+ while (certs != NULL)
+ {
+ bool stored = FALSE;
+ x509cert_t *cert = certs;
+
+ if (!cert->isCA)
+ {
+ if (stored)
+ exit_scepclient("multiple certs received, only first stored");
+ if (!write_chunk(path, "requested cert", cert->certificate, 0022, force))
+ exit_scepclient("could not write cert file '%s'", path);
+ stored = TRUE;
+ }
+ certs = certs->next;
+ free_x509cert(cert);
+ }
+ filetype_out &= ~CERT; /* delete CERT flag */
+ }
+
+ exit_scepclient(NULL);
+ return -1; /* should never be reached */
+}
+
+
diff --git a/programs/secrets/Makefile b/programs/secrets/Makefile
new file mode 100644
index 000000000..a853d22f2
--- /dev/null
+++ b/programs/secrets/Makefile
@@ -0,0 +1,38 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:30 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=secrets
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:30 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 2002/06/02 22:02:14 mcr
+# changed TOPDIR->FREESWANSRCDIR in all Makefiles.
+# (note that linux/net/ipsec/Makefile uses TOPDIR because this is the
+# kernel sense.)
+#
+# Revision 1.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/secrets/secrets.8 b/programs/secrets/secrets.8
new file mode 100644
index 000000000..2333a0a3e
--- /dev/null
+++ b/programs/secrets/secrets.8
@@ -0,0 +1,20 @@
+.TH IPSEC_SECRETS 8 "31 Aug 2003"
+.\" RCSID $Id: secrets.8,v 1.1 2004/03/15 20:35:30 as Exp $
+.SH NAME
+ipsec secrets \- prompt for PIN codes and passphrases
+.SH SYNOPSIS
+.B ipsec
+.B secrets
+.SH DESCRIPTION
+.I Secrets
+is an alias for
+.B ipsec auto --rereadsecrets
+and prompts for PIN codes and passphrases protecting private RSA keys.
+.SH SEE ALSO
+ipsec.secrets(5)
+.SH HISTORY
+Written for the FreeS/WAN project
+<http://www.freeswan.org>
+by Andreas Steffen.
+.SH BUGS
+None
diff --git a/programs/secrets/secrets.in b/programs/secrets/secrets.in
new file mode 100644
index 000000000..b7e486098
--- /dev/null
+++ b/programs/secrets/secrets.in
@@ -0,0 +1,18 @@
+#! /bin/sh
+# program which prompts for PINs and passphrases
+# alias for ipsec auto --rereadsecrets
+# Copyright (C) 2003 Andreas Steffen
+#
+# 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: secrets.in,v 1.1 2004/03/15 20:35:31 as Exp $
+
+ipsec auto --rereadsecrets
diff --git a/programs/send-pr/.cvsignore b/programs/send-pr/.cvsignore
new file mode 100644
index 000000000..953bfcf5a
--- /dev/null
+++ b/programs/send-pr/.cvsignore
@@ -0,0 +1 @@
+send-pr
diff --git a/programs/send-pr/Makefile b/programs/send-pr/Makefile
new file mode 100644
index 000000000..db7d51929
--- /dev/null
+++ b/programs/send-pr/Makefile
@@ -0,0 +1,39 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:31 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=send-pr
+LIBFILES=ipsec_pr.template
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:31 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 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.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/send-pr/ipsec_pr.template b/programs/send-pr/ipsec_pr.template
new file mode 100644
index 000000000..3e809a677
--- /dev/null
+++ b/programs/send-pr/ipsec_pr.template
@@ -0,0 +1,54 @@
+SEND-PR: -*- send-pr -*-
+SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as
+SEND-PR: will all comments (text enclosed in `<' and `>').
+SEND-PR:
+SEND-PR: Please consult the send-pr man page `send-pr(1)' or the Texinfo
+SEND-PR: manual if you are not sure how to fill out a problem report.
+SEND-PR: Note that the Synopsis field is mandatory. The Subject (for
+SEND-PR: the mail) will be made the same as Synopsis unless explicitly
+SEND-PR: changed.
+SEND-PR:
+SEND-PR: Choose from the following categories:
+SEND-PR:
+SEND-PR: pluto - Problems with IKE daemon
+SEND-PR: klips - Problems with kernel code
+SEND-PR: startup- Problems with start/configuration code
+SEND-PR: doc - Problems with documentation
+SEND-PR: interop- Problems with interoperability
+SEND-PR: source - source code patches/contributions
+SEND-PR: admin - Problems with freeswan.org machines
+SEND-PR:
+To: gnats-bugs@freeswan.org
+Subject:
+From: <FROM>
+Reply-To: <REPLYTO>
+Cc:
+X-send-pr-version: 4.0-alpha
+X-GNATS-Notify:
+
+>Submitter-Id: <SUBMITTER>
+>Originator: <DEFAULT_ORIGINATOR>
+>Organization:
+ unknown
+>Synopsis: <One-line summary of the PR (one line)>
+>Confidential: <[ yes | no ] (one line)>
+>Severity: <[ critical | serious | non-critical ] (one line)>
+>Priority: <[ high | medium | low ] (one line)>
+>Category: <choose from a category listed above (one line)>
+>Class: <[ sw-bug | dos | interop | mtu | log | doc-bug | support | change-request | mistaken | duplicate ] (one line)>
+>Release: <DEFAULT_VERSION>
+>Environment:
+ <DEFAULT_ENVIRONMENT>
+
+>IPsec-barf-location: <DEFAULT_BARF>
+ <some URL with the output of ipsec barf.>
+
+>Description:
+ <Precise description of the problem (multiple lines)>
+>How-To-Repeat:
+ <code/input/activities to reproduce the problem (multiple lines)>
+>Fix:
+ <How to correct or work around the problem, if known (multiple lines)>
+
+>IPsec-look:
+
diff --git a/programs/send-pr/send-pr.8 b/programs/send-pr/send-pr.8
new file mode 100644
index 000000000..73a5bbf3c
--- /dev/null
+++ b/programs/send-pr/send-pr.8
@@ -0,0 +1,291 @@
+.\" -*- nroff -*-
+.\" ---------------------------------------------------------------------------
+.\" man page for send-pr (by Heinz G. Seidl, hgs@cygnus.com)
+.\" updated Feb 1993 for GNATS 3.00 by Jeffrey Osier, jeffrey@cygnus.com
+.\"
+.\" This file is part of the Problem Report Management System (GNATS)
+.\" Copyright 1992 Cygnus Support
+.\"
+.\" 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.
+.\"
+.\" 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.
+.\"
+.\" You should have received a copy of the GNU Library General Public
+.\" License along with this program; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
+.\"
+.\" ---------------------------------------------------------------------------
+.nh
+.TH SEND-PR 8 xVERSIONx "February 1993"
+.SH NAME
+ipsec send-pr \- send problem report (PR) to a central support site
+.SH SYNOPSIS
+.B ipsec send-pr
+[
+.I site
+]
+[
+.B \-f
+.I problem-report
+]
+[
+.B \-t
+.I mail-address
+]
+.br
+.in +0.8i
+[
+.B \-P
+]
+[
+.B \-L
+]
+[
+.B \-s
+.I severity
+]
+[
+.B \-c
+.I address
+]
+.br
+[
+.B \-\-request-id
+]
+[
+.B \-V
+]
+.SH DESCRIPTION
+.B ipsec send-pr
+is a tool used to submit
+.I problem reports
+.\" SITE ADMINISTRATORS - change this if you use a local default
+(PRs) to a central support site. In most cases the correct
+.I site
+will be the default. This argument indicates the support site which
+is responsible for the category of problem involved. Some sites may
+use a local address as a default.
+.I site
+values are defined by using the
+.BR aliases (5).
+.LP
+.B ipsec send-pr
+invokes an editor on a problem report template (after trying to fill
+in some fields with reasonable default values). When you exit the
+editor,
+.B ipsec send-pr
+sends the completed form to the
+.I Problem Report Management System
+(\fBGNATS\fR) at a central support site. At the support site, the PR
+is assigned a unique number and is stored in the \fBGNATS\fR database
+according to its category and submitter-id. \fBGNATS\fR automatically
+replies with an acknowledgement, citing the category and the PR
+number.
+.LP
+To ensure that a PR is handled promptly, it should contain your (unique)
+\fIsubmitter-id\fR and one of the available \fIcategories\fR to identify the
+problem area. (Use
+.B `ipsec send-pr -L'
+to see a list of categories.)
+.LP
+The
+.B ipsec send-pr
+template at your site should already be customized with your
+submitter-id (running `\|\fBinstall-sid\fP \fIsubmitter-id\fP\|' to
+accomplish this is part of the installation procedures for
+.BR ipsec send-pr ).
+If this hasn't been done, see your system administrator for your
+submitter-id, or request one from your support site by invoking
+.B `ipsec send-pr \-\-request\-id'.
+If your site does not distinguish between different user sites, or if
+you are not affiliated with the support site, use
+.B `net'
+for this field.
+.LP
+The more precise your problem description and the more complete your
+information, the faster your support team can solve your problems.
+.SH OPTIONS
+.TP
+.BI \-f " problem-report"
+specify a file (\fIproblem-report\fR) which already contains a
+complete problem report.
+.B ipsec send-pr
+sends the contents of the file without invoking the editor. If
+the value for
+.I problem-report
+is
+.BR `\|\-\|' ,
+then
+.B ipsec send-pr
+reads from standard input.
+.TP
+.BI \-s " severity"
+Give the problem report the severity
+.IR severity .
+.TP
+.BI \-t " mail-address"
+Change mail address at the support site for problem reports. The
+default
+.I mail-address
+is the address used for the default
+.IR site .
+Use the
+.I site
+argument rather than this option in nearly all cases.
+.TP
+.BI \-c " address"
+Put
+.I address
+in the
+.B Cc:
+header of the message.
+.TP
+.B \-P
+print the form specified by the environment variable
+.B PR_FORM
+on standard output. If
+.B PR_FORM
+is not set, print the standard blank PR template. No mail is sent.
+.TP
+.B -L
+print the list of available categories. No mail is sent.
+.TP
+.B \-\-request\-id
+sends mail to the default support site, or
+.I site
+if specified, with a request for your
+.IR submitter-id .
+If you are
+not affiliated with
+.IR site ,
+use a
+.I submitter-id
+of
+.BR net \|'.
+.TP
+.B \-V
+Display the
+.B ipsec send-pr
+version number.
+.LP
+Note: use
+.B ipsec send-pr
+to submit problem reports rather than mailing them directly. Using
+both the template and
+.B ipsec send-pr
+itself will help ensure all necessary information will reach the
+support site.
+.SH ENVIRONMENT
+The environment variable
+.B EDITOR
+specifies the editor to invoke on the template.
+.br
+default:
+.B vi
+.sp
+If the environment variable
+.B PR_FORM
+is set, then its value is used as the file name of the template for
+your problem-report editing session. You can use this to start with a
+partially completed form (for example, a form with the identification
+fields already completed).
+.SH "HOW TO FILL OUT A PROBLEM REPORT"
+Problem reports have to be in a particular form so that a program can
+easily manage them. Please remember the following guidelines:
+.IP \(bu 3m
+describe only
+.B one problem
+with each problem report.
+.IP \(bu 3m
+For follow-up mail, use the same subject line as the one in the automatic
+acknowledgent. It consists of category, PR number and the original synopsis
+line. This allows the support site to relate several mail messages to a
+particular PR and to record them automatically.
+.IP \(bu 3m
+Please try to be as accurate as possible in the subject and/or synopsis line.
+.IP \(bu 3m
+The subject and the synopsis line are not confidential. This is
+because open-bugs lists are compiled from them. Avoid confidential
+information there.
+.LP
+See the GNU
+.B Info
+file
+.B send-pr.info
+or the document \fIReporting Problems With send-pr\fR\ for detailed
+information on reporting problems
+.SH "HOW TO SUBMIT TEST CASES, CODE, ETC."
+Submit small code samples with the PR. Contact the support site for
+instructions on submitting larger test cases and problematic source
+code.
+.SH FILES
+.ta \w'/tmp/pbad$$ 'u
+/tmp/p$$ copy of PR used in editing session
+.br
+/tmp/pf$$ copy of empty PR form, for testing purposes
+.br
+/tmp/pbad$$ file for rejected PRs
+.br
+@IPSEC_DIR@/send-pr.conf script to customize send-pr.
+.SH EMACS USER INTERFACE
+An Emacs user interface for
+.B send-pr
+with completion of field values is part of the
+.B send-pr
+distribution (invoked with
+.BR "M-x send-pr" ).
+See the file
+.B send-pr.info
+or the ASCII file
+.B INSTALL
+in the top level directory of the distribution for configuration and
+installation information. The Emacs LISP template file is
+.B send-pr-el.in
+and is installed as
+.BR send-pr.el .
+.SH INSTALLATION AND CONFIGURATION
+See
+.B send-pr.info
+or
+.B INSTALL
+for installation instructions.
+.SH SEE ALSO
+.I Reporting Problems Using send-pr
+(also installed as the GNU Info file
+.BR send-pr.info ).
+.LP
+.BR gnats (l),
+.BR query-pr (1),
+.BR edit-pr (1),
+.BR gnats (8),
+.BR queue-pr (8),
+.BR at-pr (8),
+.BR mkcat (8),
+.BR mkdist (8).
+.SH AUTHORS
+Jeffrey Osier, Brendan Kehoe, Jason Merrill, Heinz G. Seidl (Cygnus
+Support)
+.SH COPYING
+Copyright (c) 1992, 1993 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
+
diff --git a/programs/send-pr/send-pr.in b/programs/send-pr/send-pr.in
new file mode 100755
index 000000000..6cd202470
--- /dev/null
+++ b/programs/send-pr/send-pr.in
@@ -0,0 +1,643 @@
+#!/bin/sh
+# Submit a problem report to a GNATS site.
+# Copyright (C) 2001 Milan Zamazal
+# Copyright (C) 1993, 2001 Free Software Foundation, Inc.
+# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a
+# version written by Heinz G. Seidl (hgs@cygnus.com).
+# Further edited by Milan Zamazal (pdm@zamazal.org).
+# mktemp support by Yngve Svendsen (yngve.svendsen@clustra.com).
+#
+# This file is part of GNU GNATS.
+#
+# GNU GNATS 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, or (at your option)
+# any later version.
+#
+# GNU GNATS 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU GNATS; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#
+# $Id: send-pr.in,v 1.1 2004/03/15 20:35:31 as Exp $
+#
+
+# The version of this send-pr.
+VERSION=4.0-alpha
+
+#SWAN_VERSION=
+
+# The submitter-id for your site.
+SUBMITTER=net
+
+# The place where our usual binaries live.
+BINDIR=@IPSEC_DIR@
+
+# The place where the builtin binaries are located.
+LIBDIR=@IPSEC_LIBDIR@
+LIBEXECDIR=@IPSEC_EXECDIR@
+
+# The default release for this host.
+DEFAULT_RELEASE="gnats-4.0-alpha"
+
+# The default organization.
+DEFAULT_ORGANIZATION="net"
+
+# How to read the passwd database.
+PASSWD="cat /etc/passwd"
+
+# Is the mktemp command available?
+MKTEMP="yes"
+
+ECHON=bsd
+
+# By default send-pr connects directly to the database. However, it
+# can be configured to use an existing template file by setting the
+# TEMPLATE variable below to point to a PR template generated from
+# "send-pr -P".
+TEMPLATE="$LIBDIR/ipsec_pr.template"
+
+# send-pr can use mail to submit PRs, instead of connecting to the
+# database directly. MAILPROG needs to point to a compatible mailer
+# (sendmail will work). If MAILPROG needs to have the address that
+# the mail is being sent to specified on the command line, it should
+# be specified here as well (for example, the command
+# MAILPROG="mail bugs@foo.bar.com"
+# should work). If sendmail is used, this should be set to
+# MAILPROG="/usr/lib/sendmail -oi -t"
+MAILPROG="/usr/sbin/sendmail -oi -t"
+
+# The address that PRs are sent to. Normally this can be left as "bugs";
+# however, if using mail to submit PRs, this should be set to the address
+# where PRs should be sent.
+MAILADDR="freeswan-bugs@freeswan.org"
+
+if [ $ECHON = bsd ] ; then
+ ECHON1="echo -n"
+ ECHON2=
+elif [ $ECHON = sysv ] ; then
+ ECHON1=echo
+ ECHON2='\c'
+else
+ ECHON1=echo
+ ECHON2=
+fi
+
+# Configuration file to be read. It must be a shell script that can redefine
+# the variables above to fit a local configuration.
+CONFIGFILE=@IPSEC_DIR@/send-pr.conf
+
+if [ -r $CONFIGFILE ]; then
+ . $CONFIGFILE
+fi
+
+#
+
+if [ -z "$TMPDIR" ]; then
+ TMPDIR=/tmp
+else
+ if [ "`echo $TMPDIR | grep '/$'`" != "" ]; then
+ TMPDIR="`echo $TMPDIR | sed -e 's,/$,,'`"
+ fi
+fi
+
+# TEMP: Temporary copy of the PR, to be edited by the user.
+# BAD: The PR will end up here if the user aborts.
+# REF: The 'reference' copy of the PR template, used to verify that the user
+# actually did edit the template.
+# FIXFIL: A sed script used to remove comments from the template before
+# processing.
+if [ $MKTEMP = yes ]; then
+ TEMP=`mktemp $TMPDIR/pXXXXXX` || exit 1
+ BAD=`mktemp $TMPDIR/pbadXXXXXX` || exit 1
+ REF=`mktemp $TMPDIR/pfXXXXXX` || exit 1
+ FIXFIL=`mktemp $TMPDIR/fixXXXXXX` || exit 1
+else
+ TEMP=$TMPDIR/p$$
+ BAD=$TMPDIR/pbad$$
+ REF=$TMPDIR/pf$$
+ FIXFIL=$TMPDIR/fix$$
+ bad_temp=0
+ : > $TEMP || bad_temp=1
+ : > $BAD || bad_temp=1
+ : > $REF || bad_temp=1
+ : > $FIXFIL || bad_temp=1
+ if [ $bad_temp = 1 ]; then
+ rm -f $TEMP $BAD $REF $FIXFIL
+ exit 1;
+ fi
+fi
+REMOVE_TEMP="rm -f $TEMP $BAD $REF"
+
+# find a user name
+if [ "$LOGNAME" = "" ]; then
+ if [ "$USER" != "" ]; then
+ LOGNAME="$USER"
+ else
+ LOGNAME="UNKNOWN"
+ fi
+fi
+
+FROM="$LOGNAME"
+REPLYTO="${REPLY_TO:-${REPLYTO:-$LOGNAME}}"
+if [ "x$MAILPROG" != "x" ]
+then
+ RESP_ALIAS="`query-pr --adm-field responsible --adm-key $LOGNAME --adm-subfield alias 2>/dev/null`"
+else
+ RESP_ALIAS=""
+fi
+
+# Find out the name of the originator of this PR.
+if [ -n "$NAME" ]; then
+ DEFAULT_ORIGINATOR="$NAME"
+elif [ -f $HOME/.fullname ]; then
+ DEFAULT_ORIGINATOR="`sed -e '1q' $HOME/.fullname`"
+else
+ # Must use temp file due to incompatibilities in quoting behavior
+ # and to protect shell metacharacters in the expansion of $LOGNAME
+ $PASSWD | grep "^$LOGNAME:" | awk -F: '{print $5}' | sed -e 's/,.*//' > $TEMP
+ if [ "x$RESP_ALIAS" != "x" ]
+ then
+ DEFAULT_ORIGINATOR="$RESP_ALIAS (`cat $TEMP`)"
+ else
+ DEFAULT_ORIGINATOR="$FROM (`cat $TEMP`)"
+ fi
+ rm -f $TEMP
+fi
+
+if [ -z "$ORGANIZATION" ]
+then
+ ORGANIZATION="$DEFAULT_ORGANIZATION";
+fi
+
+if [ -n "$ORGANIZATION" -a "x$ORGANIZATION" != "xunknown" ]; then
+ if [ -f "$ORGANIZATION" ]; then
+ ORGANIZATION="`cat $ORGANIZATION`"
+ fi
+ if [ -n "$ORGANIZATION" ]; then
+ ORGANIZATION="$ORGANIZATION"
+ elif [ -f $HOME/.organization ]; then
+ ORGANIZATION="`cat $HOME/.organization`"
+ fi
+fi
+
+if [ "x$ORGANIZATION" = "xunknown" ]; then
+ cat <<__EOF__
+It seems that send-pr is not installed with your organization set to a useful
+value. To fix this, you need to edit the configuration file
+$CONFIGFILE
+and fill in the organization with the correct value.
+
+__EOF__
+ ORGANIZATION="";
+fi 1>&2
+
+# If they don't have a preferred editor set, then use
+if [ -z "$VISUAL" ]; then
+ if [ -z "$EDITOR" ]; then
+ EDIT=vi
+ else
+ EDIT="$EDITOR"
+ fi
+else
+ EDIT="$VISUAL"
+fi
+
+# Find out some information.
+SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \
+ ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo "" | sed -e 's,|,\\|,'`
+
+# Our base command name.
+COMMAND=`echo $0 | sed -e 's,.*/,,'`
+USAGE="Usage: $COMMAND [OPTION]...
+
+ -b --batch run without printing most messages
+ --barf include a full barf inline rather than just look
+ -c --cc=LINE put LINE to the CC header
+ -d --database=DATABASE submit PR to DATABASE
+ -f --file=FILE read the PR template from FILE (\`-' for stdin)
+ -p --print just print the template and exit
+ --request-id send a request for a user id
+ -s --severity=SEVERITY PR severity
+
+ -h --help display this help and exit
+ -V --version output version information and exit
+"
+REMOVE=
+BATCH=
+CC=
+DEFAULT_SEVERITY=
+BARF=${BARF-false}
+
+if [ "$SYSTEM" != "" ]
+then
+ DEFAULT_ENVIRONMENT="System: $SYSTEM"
+fi
+
+if [ "$SWAN_VERSION" != "" ]
+then
+ DEFAULT_VERSION="$SWAN_VERSION";
+else
+ DEFAULT_VERSION=`ipsec --versioncode`
+fi
+DEFAULT_VERSION=`echo $DEFAULT_VERSION | sed -e 's,\/,\\\/,'`
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ -r) ;; # Ignore for backward compat.
+ -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+ shift ; IN_FILE="$1"
+ if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then
+ echo "$COMMAND: cannot read $IN_FILE"
+ exit 1
+ fi
+ ;;
+ -b | --batch) BATCH=true ;;
+ --barf) BARF=true ;;
+ -c | --cc) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+ shift ; CC="$1"
+ ;;
+ -d | --database) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+ shift; GNATSDB="$1"; export GNATSDB
+ ;;
+ -s | --severity) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+ shift ; DEFAULT_SEVERITY="$1"
+ ;;
+ -p | -P | --print) PRINT=true ;;
+ --request-id) REQUEST_ID=true ;;
+ -h | --help) echo "$USAGE"; exit 0 ;;
+ -V | --version) echo "$VERSION"; exit 0 ;;
+ -*) echo "$USAGE" ; exit 1 ;;
+ *) echo "$USAGE" ; exit 1 ;;
+ esac
+ shift
+done
+
+if [ "x$SUBMITTER" = "x" ]
+then
+ SUBMITTER="unknown"
+fi
+
+if [ "x$SUBMITTER" = "xunknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then
+ cat << '__EOF__'
+It seems that send-pr is not installed with your unique submitter-id.
+You need to run
+
+ install-sid YOUR-SID
+
+where YOUR-SID is the identification code you received with `send-pr'.
+`send-pr' will automatically insert this value into the template field
+`>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net'
+for this value. If you do not know your id, run `send-pr --request-id' to
+get one from your support site.
+__EOF__
+ exit 1
+fi
+
+# So the template generation code finds it.
+DEFAULT_SUBMITTERID=${SUBMITTER}
+
+# Catch some signals. ($xs kludge needed by Sun /bin/sh)
+xs=0
+trap 'rm -f $REF $TEMP $FIXFIL; exit $xs' 0
+trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP $FIXFIL; xs=1; exit' 1 3 13 15
+
+if [ "x$PRINT" = "xtrue" ]; then
+ FROM="<FROM>"
+ REPLYTO="<REPLYTO>"
+ DEFAULT_ORIGINATOR="<DEFAULT_ORIGINATOR>"
+ DEFAULT_SUBMITTERID="<SUBMITTER>"
+fi
+
+# If they told us to use a specific file, then do so.
+if [ -n "$IN_FILE" ]; then
+ if [ "$IN_FILE" = "-" ]; then
+ # The PR is coming from the standard input.
+ cat > $TEMP
+ else
+ # Use the file they named.
+ cat $IN_FILE > $TEMP
+ fi
+else
+ if [ -n "$TEMPLATE" -a -z "$PRINT_INTERN" ]; then
+ # If their TEMPLATE points to a bogus entry, then bail.
+ if [ ! -f "$TEMPLATE" -o ! -r "$TEMPLATE" -o ! -s "$TEMPLATE" ]; then
+ echo "$COMMAND: can't seem to read your template file (\`$TEMPLATE'), ignoring TEMPLATE"
+ sleep 1
+ PRINT_INTERN=bad_prform
+ fi
+ fi
+
+ if [ -n "$TEMPLATE" -a -z "$PRINT_INTERN" ]; then
+ sed "s/<FROM>/$FROM/;s/<REPLYTO>/$REPLYTO/;s/<DEFAULT_ORIGINATOR>/$DEFAULT_ORIGINATOR/;s/<SUBMITTER>/$DEFAULT_SUBMITTERID/;s|<DEFAULT_ENVIRONMENT>|$DEFAULT_ENVIRONMENT|;s/<DEFAULT_BARF>/$DEFAULT_BARF/;s/<DEFAULT_VERSION>/$DEFAULT_VERSION/;" < $TEMPLATE > $TEMP ||
+ ( echo "$COMMAND: could not copy $TEMPLATE" ; xs=1; exit )
+ else
+ # Which genius thought of iterating through this loop twice, when the
+ # cp command would suffice?
+ for file in $TEMP ; do
+ cat > $file << '__EOF__'
+SEND-PR: -*- send-pr -*-
+SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as
+SEND-PR: will all comments (text enclosed in `<' and `>').
+SEND-PR:
+SEND-PR: Please consult the send-pr man page `send-pr(1)' or the Texinfo
+SEND-PR: manual if you are not sure how to fill out a problem report.
+SEND-PR: Note that the Synopsis field is mandatory. The Subject (for
+SEND-PR: the mail) will be made the same as Synopsis unless explicitly
+SEND-PR: changed.
+SEND-PR:
+SEND-PR: Choose from the following categories:
+SEND-PR:
+__EOF__
+
+ # Format the categories so they fit onto lines.
+ CATEGORIES=`${BINDIR}/query-pr --valid-values Category`;
+ l=`echo "$CATEGORIES" | \
+ awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } }
+ END {print max + 1;}'`
+ c=`expr 61 / $l`
+ if [ $c -eq 0 ]; then c=1; fi
+ echo "$CATEGORIES" | \
+ awk 'BEGIN {printf "SEND-PR: "; i = 0 }
+ { printf ("%-'$l'.'$l's", $0);
+ if ((++i % '$c') == 0) { printf "\nSEND-PR: " } }
+ END { printf "\nSEND-PR:\n"; }' >> $file
+
+ cat >> $file << __EOF__
+To: $MAILADDR
+Subject:
+From: $FROM
+Reply-To: $REPLYTO
+Cc: $CC
+X-send-pr-version: $VERSION
+X-GNATS-Notify:
+
+
+__EOF__
+
+ #
+ # Iterate through the list of input fields. fieldname is the
+ # name of the field. fmtname is the formatted name of the field,
+ # with >, : and extra spaces to cause the field contents to be
+ # aligned.
+ #
+ ${BINDIR}/query-pr --list-input-fields | awk '{a[NR]=$1""; mnr = NR+1; len = length($1) + 2; if (mlen < len) mlen = len; } END { for (x = 1; x < mnr; x++) { b = ">"a[x]":"; printf ("%s %-"mlen"s&\n", a[x], b); } }' | while read fieldname fmtname
+ do
+ fmtname="`echo "$fmtname" | sed 's/[&]$//;'`"
+ upname="`echo $fieldname | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;s/-//g;'`"
+ # Grab the default value for this field.
+ eval 'default_val="$DEFAULT_'${upname}'"'
+ # What's stored in the field?
+ type=`${BINDIR}/query-pr --field-type $fieldname | sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+ case $type in
+ enum)
+ if [ "$default_val" != "" ]
+ then
+ desc=$default_val;
+ else
+ if [ "$fieldname" != "Category" ]
+ then
+ values=`${BINDIR}/query-pr --valid-values $fieldname | tr '\n' ' ' | sed 's/ *$//g;s/ / | /g;s/^/[ /;s/$/ ]/;'`
+ valslen=`echo "$values" | wc -c`
+ else
+ values="choose from a category listed above"
+ valslen=1;
+ fi
+ if [ "$valslen" -gt 160 ]
+ then
+ desc="<`${BINDIR}/query-pr --field-description $fieldname` (one line)>";
+ else
+ desc="<${values} (one line)>";
+ fi
+ dpat=`echo "$desc" | tr '\]\[*+^$|\()&/' '............'`
+ echo "/^>${fieldname}:/ s/${dpat}//" >> $FIXFIL
+ fi
+ echo "${fmtname}${desc}" >> $file
+ ;;
+ multitext)
+ if [ "$default_val" != "" ]
+ then
+ desc=" $default_val";
+ else
+ desc=" <`${BINDIR}/query-pr --field-description $fieldname` (multiple lines)>";
+ dpat=`echo "$desc" | tr '\]\[*+^$|\()&/' '............'`
+ echo "s/^${dpat}//" >> $FIXFIL
+ fi
+ echo "${fmtname}" >> $file;
+ echo "$desc" >> $file;
+ ;;
+ *)
+ if [ "$default_val" != "" ]
+ then
+ desc="${default_val}"
+ else
+ desc="<`${BINDIR}/query-pr --field-description $fieldname` (one line)>"
+ dpat=`echo "$desc" | tr '\]\[*+^$|\()&/' '............'`
+ echo "/^>${fieldname}:/ s/${dpat}//" >> $FIXFIL
+ fi
+ echo "${fmtname}${desc}" >> $file
+ ;;
+ esac
+ done
+ done
+ fi
+
+ if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then
+ cat $TEMP
+ xs=0; exit
+ fi
+
+ if $BARF
+ then
+ ipsec barf >>$TEMP
+ else
+ ipsec look >>$TEMP
+ fi
+
+ cp $TEMP $REF
+
+ chmod u+w $TEMP
+ if [ -z "$REQUEST_ID" ]; then
+ eval $EDIT $TEMP
+ else
+ ed -s $TEMP << '__EOF__'
+/^Subject/s/^Subject:.*/Subject: request for a customer id/
+/^>Category/s/^>Category:.*/>Category: send-pr/
+w
+q
+__EOF__
+ fi
+
+ if cmp -s $REF $TEMP ; then
+ echo "$COMMAND: problem report not filled out, therefore not sent"
+ xs=1; exit
+ fi
+fi
+
+# TEMP is the PR that we are editing. When we're done, REF will contain
+# the final PR to be sent.
+
+while [ -z "$REQUEST_ID" ]; do
+ CNT=0
+
+ #
+ # Remove comments.
+ #
+ echo '/^SEND-PR:/d' >> $FIXFIL
+ sed -f $FIXFIL $TEMP > $REF
+
+ # REF now has the actual PR that we want to send.
+
+ #
+ # Check that synopsis is not empty.
+ #
+ if grep "^>Synopsis:[ ]*$" $REF > /dev/null
+ then
+ echo "$COMMAND: Synopsis must not be empty."
+ CNT=`expr $CNT + 1`
+ fi
+
+ if [ "x$MAILPROG" = "x" ]
+ then
+ # Since we're not using mail, use pr-edit to check the PR. We can't
+ # do much checking otherwise, sorry.
+ $LIBEXECDIR/pr-edit --check-initial < $REF || CNT=`expr $CNT + 1`
+ fi
+
+ [ $CNT -gt 0 -a -z "$BATCH" ] &&
+ echo "Errors were found with the problem report."
+
+ while true; do
+ if [ -z "$BATCH" ]; then
+ $ECHON1 "a)bort, e)dit or s)end? $ECHON2"
+ read input
+ else
+ if [ $CNT -eq 0 ]; then
+ input=s
+ else
+ input=a
+ fi
+ fi
+ case "$input" in
+ a*)
+ if [ -z "$BATCH" ]; then
+ echo "$COMMAND: the problem report remains in $BAD and is not sent."
+ mv $TEMP $BAD
+ else
+ echo "$COMMAND: the problem report is not sent."
+ fi
+ xs=1; exit
+ ;;
+ e*)
+ eval $EDIT $TEMP
+ continue 2
+ ;;
+ s*)
+ break 2
+ ;;
+ esac
+ done
+done
+
+#
+# Make sure the mail has got a Subject. If not, use the same as
+# in Synopsis.
+#
+
+if grep '^Subject:[ ]*$' $REF > /dev/null
+then
+ SYNOPSIS=`grep '^>Synopsis:' $REF | sed -e 's/^>Synopsis:[ ]*//'`
+ ed -s $REF << __EOF__
+/^Subject:/s/:.*\$/: $SYNOPSIS/
+w
+q
+__EOF__
+fi
+
+while :
+do
+ if [ "x$MAILPROG" != "x" ]
+ then
+ # Use mail to send the PR.
+ if $MAILPROG < $REF
+ then
+ echo "$COMMAND: problem report mailed"
+ xs=0; exit
+ else
+ echo "$MAILPROG failed!"
+ fi
+ else
+ if $LIBEXECDIR/pr-edit --submit < $REF; then
+ echo "$COMMAND: problem report filed"
+ xs=0; exit
+ else
+ echo "$COMMAND: the problem report is not sent."
+ fi
+ fi
+ while true
+ do
+ if [ -z "$BATCH" ]; then
+ $ECHON1 "a)bort or s)end? (file=$REF) $ECHON2"
+ read input
+ case "$input" in
+ a*)
+ break 2 ;;
+ s*)
+ break ;;
+ esac
+ else
+ break 2;
+ fi
+ done
+done
+
+if [ -z "$BATCH" ]; then
+ echo "$COMMAND: the problem report remains in $BAD and is not sent."
+ mv $TEMP $BAD
+else
+ echo "$COMMAND: the problem report is not sent, is in $REF."
+fi
+
+xs=1; exit;
+
+#
+# $Log: send-pr.in,v $
+# Revision 1.1 2004/03/15 20:35:31 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.10 2003/07/14 12:26:17 mcr
+# use | as delimitor for $DEFAULT_ENVIRONMENT.
+# switch | to \\| when in $DEFAULT_ENVIRONMENT.
+# this is due to PR#236 where the "uname" output
+# says GNU/Linux, screwing up sed.
+#
+# Revision 1.9 2003/02/03 21:51:06 mcr
+# if MAILPROG fails, then offer to try again.
+#
+# Revision 1.8 2002/12/10 02:28:13 mcr
+# adjusted template to use gnats-bugs@freeswan.org
+# fix sed script to deal with version sanitizer.
+#
+# Revision 1.7 2002/12/10 02:17:34 mcr
+# need to init variables first
+#
+# Revision 1.6 2002/12/10 02:16:23 mcr
+# adjusted send-pr to look at LIBDIR, not LIBEXECDIR
+#
+# Revision 1.5 2002/09/30 16:04:05 mcr
+# fix for sed bug in "send-pr"
+#
+# Revision 1.4 2002/04/24 07:36:10 mcr
+# Moved from ./utils/send-pr.sh,v
+#
+# Revision 1.3 2001/11/27 15:02:55 mcr
+# added rcsids.
+# fixed submission address to be freeswan-bugs@freeswan.org
+# use new ipsec --versioncode to get version info.
+#
+#
diff --git a/programs/setup/.cvsignore b/programs/setup/.cvsignore
new file mode 100644
index 000000000..146f275e0
--- /dev/null
+++ b/programs/setup/.cvsignore
@@ -0,0 +1 @@
+setup
diff --git a/programs/setup/Makefile b/programs/setup/Makefile
new file mode 100644
index 000000000..f12d452b2
--- /dev/null
+++ b/programs/setup/Makefile
@@ -0,0 +1,22 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.3 2006/02/10 11:28:15 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=setup
+EXTRA8MAN=setup.8
+
+include ../Makefile.program
diff --git a/programs/setup/setup.8 b/programs/setup/setup.8
new file mode 100644
index 000000000..e2980ee74
--- /dev/null
+++ b/programs/setup/setup.8
@@ -0,0 +1,142 @@
+.TH IPSEC_SETUP 8 "23 July 2001"
+.\" RCSID $Id: setup.8,v 1.1 2004/03/15 20:35:31 as Exp $
+.SH NAME
+ipsec setup \- control IPsec subsystem
+.SH SYNOPSIS
+.B ipsec
+.B setup
+[
+.B \-\-show
+|
+.B \-\-showonly
+]
+command
+.SH DESCRIPTION
+.I Setup
+controls the FreeS/WAN IPsec subsystem,
+including both the Klips kernel code and the Pluto key-negotiation daemon.
+(It is a synonym for the ``rc'' script for the subsystem;
+the system runs the equivalent of
+.B "ipsec setup start"
+at boot time,
+and
+.B "ipsec setup stop"
+at shutdown time, more or less.)
+.PP
+The action taken depends on the specific
+.IR command ,
+and on the contents of the
+.B config
+.B setup
+section of the
+IPsec configuration file (\c
+.IR /etc/ipsec.conf ,
+see
+.IR ipsec.conf (5)).
+Current
+.IR command s
+are:
+.TP 10
+.B start
+start Klips and Pluto,
+including setting up Klips to do crypto operations on the
+interface(s) specified in the configuration file,
+and (if the configuration file so specifies)
+setting up manually-keyed connections and/or
+asking Pluto to negotiate automatically-keyed connections
+to other security gateways
+.TP
+.B stop
+shut down Klips and Pluto,
+including tearing down all existing crypto connections
+.TP
+.B restart
+equivalent to
+.B stop
+followed by
+.B start
+.TP
+.B status
+report the status of the subsystem;
+normally just reports
+.B "IPsec running"
+and
+.BR "pluto pid \fInnn\fP" ,
+or
+.BR "IPsec stopped" ,
+and exits with status 0,
+but will go into more detail (and exit with status 1)
+if something strange is found.
+(An ``illicit'' Pluto is one that does not match the process ID in
+Pluto's lock file;
+an ``orphaned'' Pluto is one with no lock file.)
+.PP
+The
+.B stop
+operation tries to clean up properly even if assorted accidents
+have occurred,
+e.g. Pluto having died without removing its lock file.
+If
+.B stop
+discovers that the subsystem is (supposedly) not running,
+it will complain,
+but will do its cleanup anyway before exiting with status 1.
+.PP
+Although a number of configuration-file parameters influence
+.IR setup 's
+operations, the key one is the
+.B interfaces
+parameter, which must be right or chaos will ensue.
+.PP
+The
+.B \-\-show
+and
+.B \-\-showonly
+options cause
+.I setup
+to display the shell commands that it would execute.
+.B \-\-showonly
+suppresses their execution.
+Only
+.BR start ,
+.BR stop ,
+and
+.B restart
+commands recognize these flags.
+.SH FILES
+.ta \w'/proc/sys/net/ipv4/ip_forward'u+2n
+/etc/rc.d/init.d/ipsec the script itself
+.br
+/etc/init.d/ipsec alternate location for the script
+.br
+/etc/ipsec.conf IPsec configuration file
+.br
+/proc/sys/net/ipv4/ip_forward forwarding control
+.br
+/var/run/ipsec.info saved information
+.br
+/var/run/pluto.pid Pluto lock file
+.br
+/var/run/ipsec_setup.pid IPsec lock file
+.SH SEE ALSO
+ipsec.conf(5), ipsec(8), ipsec_manual(8), ipsec_auto(8), route(8)
+.SH DIAGNOSTICS
+All output from the commands
+.B start
+and
+.B stop
+goes both to standard
+output and to
+.IR syslogd (8),
+via
+.IR logger (1).
+Selected additional information is logged only to
+.IR syslogd (8).
+.SH HISTORY
+Written for the FreeS/WAN project
+<http://www.freeswan.org>
+by Henry Spencer.
+.SH BUGS
+Old versions of
+.IR logger (1)
+inject spurious extra newlines onto standard output.
diff --git a/programs/setup/setup.in b/programs/setup/setup.in
new file mode 100755
index 000000000..1e43d0d67
--- /dev/null
+++ b/programs/setup/setup.in
@@ -0,0 +1,162 @@
+#!/bin/sh
+# IPsec startup and shutdown script
+# Copyright (C) 1998, 1999, 2001 Henry Spencer.
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: setup.in,v 1.1 2004/03/15 20:35:31 as Exp $
+#
+# ipsec init.d script for starting and stopping
+# the IPsec security subsystem (KLIPS and Pluto).
+#
+# This script becomes /etc/rc.d/init.d/ipsec (or possibly /etc/init.d/ipsec)
+# and is also accessible as "ipsec setup" (the preferred route for human
+# invocation).
+#
+# The startup and shutdown times are a difficult compromise (in particular,
+# it is almost impossible to reconcile them with the insanely early/late
+# times of NFS filesystem startup/shutdown). Startup is after startup of
+# syslog and pcmcia support; shutdown is just before shutdown of syslog.
+#
+# chkconfig: 2345 47 68
+# description: IPsec provides encrypted and authenticated communications; \
+# KLIPS is the kernel half of it, Pluto is the user-level management daemon.
+
+me='ipsec setup' # for messages
+
+
+# where the private directory and the config files are
+IPSEC_EXECDIR="${IPSEC_EXECDIR-@IPSEC_EXECDIR@}"
+IPSEC_LIBDIR="${IPSEC_LIBDIR-@IPSEC_LIBDIR@}"
+IPSEC_SBINDIR="${IPSEC_SBINDIR-@IPSEC_SBINDIR@}"
+IPSEC_CONFS="${IPSEC_CONFS-@IPSEC_CONFS@}"
+
+if test " $IPSEC_DIR" = " " # if we were not called by the ipsec command
+then
+ # we must establish a suitable PATH ourselves
+ PATH="${IPSEC_SBINDIR}":/sbin:/usr/sbin:/usr/local/bin:/bin:/usr/bin
+ export PATH
+
+ IPSEC_DIR="$IPSEC_LIBDIR"
+ export IPSEC_DIR IPSEC_CONFS IPSEC_LIBDIR IPSEC_EXECDIR
+fi
+
+# Check that the ipsec command is available.
+found=
+for dir in `echo $PATH | tr ':' ' '`
+do
+ if test -f $dir/ipsec -a -x $dir/ipsec
+ then
+ found=yes
+ break # NOTE BREAK OUT
+ fi
+done
+if ! test "$found"
+then
+ echo "cannot find ipsec command -- \`$1' aborted" |
+ logger -s -p daemon.error -t ipsec_setup
+ exit 1
+fi
+
+# accept a few flags
+
+export IPSEC_setupflags
+IPSEC_setupflags=""
+
+config=""
+
+for dummy
+do
+ case "$1" in
+ --showonly|--show) IPSEC_setupflags="$1" ;;
+ --config) config="--config $2" ; shift ;;
+ *) break ;;
+ esac
+ shift
+done
+
+
+# Pick up IPsec configuration (until we have done this, successfully, we
+# do not know where errors should go, hence the explicit "daemon.error"s.)
+# Note the "--export", which exports the variables created.
+eval `ipsec _confread $config --optional --varprefix IPSEC --export --type config setup`
+if test " $IPSEC_confreadstatus" != " "
+then
+ echo "$IPSEC_confreadstatus -- \`$1' aborted" |
+ logger -s -p daemon.error -t ipsec_setup
+ exit 1
+fi
+
+IPSEC_confreadsection=${IPSEC_confreadsection:-setup}
+export IPSEC_confreadsection
+
+IPSECsyslog=${IPSECsyslog-daemon.error}
+export IPSECsyslog
+
+# misc setup
+umask 022
+
+
+# do it
+case "$1" in
+ start|--start|stop|--stop|_autostop|_autostart)
+ if test " `id -u`" != " 0"
+ then
+ echo "permission denied (must be superuser)" |
+ logger -s -p $IPSECsyslog -t ipsec_setup 2>&1
+ exit 1
+ fi
+ tmp=/var/run/ipsec_setup.st
+ (
+ ipsec _realsetup $1
+ echo "$?" >$tmp
+ ) 2>&1 | logger -s -p $IPSECsyslog -t ipsec_setup 2>&1
+ st=$?
+ if test -f $tmp
+ then
+ st=`cat $tmp`
+ rm -f $tmp
+ fi
+ exit $st
+ ;;
+
+ restart|--restart|force-reload)
+ $0 $IPSEC_setupflags stop
+ $0 $IPSEC_setupflags start
+ ;;
+
+ _autorestart) # for internal use only
+ $0 $IPSEC_setupflags _autostop
+ $0 $IPSEC_setupflags _autostart
+ ;;
+
+ status|--status)
+ ipsec _realsetup $1
+ exit
+ ;;
+
+ --version)
+ echo "$me $IPSEC_VERSION"
+ exit 0
+ ;;
+
+ --help)
+ echo "Usage: $me {--start|--stop|--restart|--status}"
+ exit 0
+ ;;
+
+ *)
+ echo "Usage: $me {--start|--stop|--restart|--status}" >&2
+ exit 2
+esac
+
+exit 0
diff --git a/programs/showdefaults/.cvsignore b/programs/showdefaults/.cvsignore
new file mode 100644
index 000000000..609b55e81
--- /dev/null
+++ b/programs/showdefaults/.cvsignore
@@ -0,0 +1 @@
+showdefaults
diff --git a/programs/showdefaults/Makefile b/programs/showdefaults/Makefile
new file mode 100644
index 000000000..d2c8f9be8
--- /dev/null
+++ b/programs/showdefaults/Makefile
@@ -0,0 +1,38 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:31 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=showdefaults
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:31 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 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.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/showdefaults/showdefaults.8 b/programs/showdefaults/showdefaults.8
new file mode 100644
index 000000000..4a8db9c49
--- /dev/null
+++ b/programs/showdefaults/showdefaults.8
@@ -0,0 +1,34 @@
+.TH IPSEC_SHOWDEFAULTS 8 "23 Jan 2000"
+.\" RCSID $Id: showdefaults.8,v 1.1 2004/03/15 20:35:31 as Exp $
+.SH NAME
+ipsec showdefaults \- show %defaultroute defaults
+.SH SYNOPSIS
+.B ipsec
+.B showdefaults
+.SH DESCRIPTION
+.I Showdefaults
+outputs (on standard output) a terse description of the defaults
+used by the
+.B %defaultroute
+facilities in
+.IR ipsec_auto (8)
+and
+.IR ipsec_manual (8).
+.PP
+Beware that the exact output format is subject to change.
+.SH DIAGNOSTICS
+Normal exit status is 0.
+If no defaults are available,
+i.e. the
+.B interfaces
+parameter in
+.B "config setup"
+is not
+.BR %defaultroute ,
+produces a message on standard error and exits with status 1.
+.SH FILES
+/var/run/ipsec.info
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org>
+by Henry Spencer.
diff --git a/programs/showdefaults/showdefaults.in b/programs/showdefaults/showdefaults.in
new file mode 100755
index 000000000..67daf7fd8
--- /dev/null
+++ b/programs/showdefaults/showdefaults.in
@@ -0,0 +1,33 @@
+#! /bin/sh
+# show defaults for %defaultroute
+# Copyright (C) 2000 Henry Spencer.
+#
+# 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: showdefaults.in,v 1.1 2004/03/15 20:35:31 as Exp $
+
+info=/var/run/ipsec.info
+me="ipsec showdefaults"
+
+case "$1" in
+--help) echo "Usage: ipsec showdefaults" ; exit 0 ;;
+--version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+esac
+
+# Pick up the info.
+if test -s $info
+then
+ sed -n '/^defaultroute/s/default//p' $info
+ sed -n '/^#dr:/s/dr://p' $info
+else
+ echo "$me: cannot find defaults file \`$info'" >&2
+ exit 1
+fi
diff --git a/programs/showhostkey/.cvsignore b/programs/showhostkey/.cvsignore
new file mode 100644
index 000000000..8496cd633
--- /dev/null
+++ b/programs/showhostkey/.cvsignore
@@ -0,0 +1 @@
+showhostkey
diff --git a/programs/showhostkey/Makefile b/programs/showhostkey/Makefile
new file mode 100644
index 000000000..db819c906
--- /dev/null
+++ b/programs/showhostkey/Makefile
@@ -0,0 +1,38 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:31 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=showhostkey
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:31 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 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.1 2002/04/24 07:55:32 mcr
+# #include patches and Makefiles for post-reorg compilation.
+#
+#
+#
+
diff --git a/programs/showhostkey/showhostkey.8 b/programs/showhostkey/showhostkey.8
new file mode 100644
index 000000000..2c0043fca
--- /dev/null
+++ b/programs/showhostkey/showhostkey.8
@@ -0,0 +1,168 @@
+.TH IPSEC_SHOWHOSTKEY 8 "5 March 2002"
+.\" RCSID $Id: showhostkey.8,v 1.1 2004/03/15 20:35:31 as Exp $
+.SH NAME
+ipsec showhostkey \- show host's authentication key
+.SH SYNOPSIS
+.B ipsec
+.B showhostkey
+[
+.B \-\-key
+] [
+.B \-\-left
+] [
+.B \-\-right
+] [
+.B \-\-txt
+gateway
+] [
+.B \-\-dhclient
+] [
+.B \-\-file
+secretfile
+] [
+.B \-\-id
+identity
+]
+.SH DESCRIPTION
+.I Showhostkey
+outputs (on standard output) a public key suitable for this host,
+in the format specified,
+using the host key information stored in
+.IR /etc/ipsec.secrets .
+In general only the super-user can run this command,
+since only he can read
+.IR ipsec.secrets .
+.PP
+The
+.B \-\-txt
+option causes the output to be in opportunistic-encryption DNS TXT record
+format,
+with the specified
+.I gateway
+value.
+If information about how the key was generated is available,
+that is provided as a DNS-file comment.
+For example,
+.B "\-\-txt 10.11.12.13"
+might give (with the key data trimmed for clarity):
+.PP
+.nf
+ ; RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ IN TXT "X-IPsec-Server(10)=10.11.12.13 AQOF8tZ2...+buFuFn/"
+.fi
+.PP
+No name is supplied in the TXT record
+because there are too many possibilities,
+depending on how it will be used.
+If the text string is longer than 255 bytes,
+it is split up into multiple strings (matching the restrictions of
+the DNS TXT binary format).
+If any split is needed, the first split will be at the start of the key:
+this increases the chances that later hand editing will work.
+.PP
+The
+.B \-\-left
+and
+.B \-\-right
+options cause the output to be in
+.IR ipsec.conf (5)
+format, as a
+.B leftrsasigkey
+or
+.B rightrsasigkey
+parameter respectively.
+Again, generation information is included if available.
+For example,
+.B \-\-left
+might give (with the key data trimmed down for clarity):
+.PP
+.nf
+ # RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ leftrsasigkey=0sAQOF8tZ2...+buFuFn/
+.fi
+.PP
+The
+.B \-\-dhclient
+option cause the output to be suitable for inclusion in
+.IR dhclient.conf (5)
+as part of configuring WAVEsec.
+See <http://www.wavesec.org>.
+.PP
+If
+.B \-\-key
+is specified,
+the output format is the text form of a DNS KEY record;
+the host name is the one included in the key information
+(or, if that is not available,
+the output of
+.BR "hostname\ \-\-fqdn" ),
+with a
+.B \&.
+appended.
+Again, generation information is included if available.
+For example (with the key data trimmed down for clarity):
+.PP
+.nf
+ ; RSA 2048 bits xy.example.com Sat Apr 15 13:53:22 2000
+ xy.example.com. IN KEY 0x4200 4 1 AQOF8tZ2...+buFuFn/
+.fi
+.PP
+Normally, the default key for this host
+(the one with no host identities specified for it) is the one extracted.
+The
+.B \-\-id
+option overrides this,
+causing extraction of the key labeled with the specified
+.IR identity ,
+if any.
+The specified
+.I identity
+must
+.I exactly
+match the identity in the file;
+in particular, the comparison is case-sensitive.
+.PP
+The
+.B \-\-file
+option overrides the default for where the key information should be
+found, and takes it from the specified
+.IR secretfile .
+.SH DIAGNOSTICS
+A complaint about ``no pubkey line found'' indicates that the
+host has a key but it was generated with an old version of FreeS/WAN
+and does not contain the information that
+.I showhostkey
+needs.
+.SH FILES
+/etc/ipsec.secrets
+.SH SEE ALSO
+ipsec.secrets(5), ipsec.conf(5), ipsec_rsasigkey(8)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org>
+by Henry Spencer.
+.SH BUGS
+Arguably,
+rather than just reporting the no-IN-KEY-line-found problem,
+.I showhostkey
+should be smart enough to run the existing key through
+.I rsasigkey
+with the
+.B \-\-oldkey
+option, to generate a suitable output line.
+.PP
+The need to specify the gateway address (etc.) for
+.B \-\-txt
+is annoying, but there is no good way to determine it automatically.
+.PP
+There should be a way to specify the priority value for TXT records;
+currently it is hardwired to
+.BR 10 .
+.PP
+The
+.B \-\-id
+option assumes that the
+.I identity
+appears on the same line as the
+.B ":\ RSA\ {"
+that begins the key proper.
diff --git a/programs/showhostkey/showhostkey.in b/programs/showhostkey/showhostkey.in
new file mode 100755
index 000000000..7194363e8
--- /dev/null
+++ b/programs/showhostkey/showhostkey.in
@@ -0,0 +1,180 @@
+#! /bin/sh
+# show key for this host, in DNS (or other) format
+# Copyright (C) 2000, 2001 Henry Spencer.
+#
+# 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: showhostkey.in,v 1.1 2004/03/15 20:35:31 as Exp $
+
+me="ipsec showhostkey"
+usage="Usage: $me [--file secrets] [--left] [--right] [--txt gateway] [--id id]
+ [--dhclient]"
+
+file=/etc/ipsec.secrets
+fmt=""
+gw=
+id=
+for dummy
+do
+ case "$1" in
+ --key) fmt="dns" ;;
+ --file) file="$2" ; shift ;;
+ --left) fmt="left" ;;
+ --right) fmt="right" ;;
+ --dhclient) fmt="dhclient" ;;
+ --txt) fmt="txt" ; gw="$2" ; shift ;;
+ --wavesec) fmt="wavesec" ;;
+ --id) id="$2" ; shift ;;
+ --version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
+ --help) echo "$usage" ; exit 0 ;;
+ --) shift ; break ;;
+ -*) echo "$me: unknown option \`$1'" >&2 ; exit 2 ;;
+ *) break ;;
+ esac
+ shift
+done
+if test " $fmt" = " "
+then
+ echo "$me: must specify a format for the result" >&2
+ exit 2
+fi
+if test " $fmt" = " txt" -a " $gw" = " "
+then
+ echo "$me: --txt gateway value cannot be empty" >&2
+ exit 2
+fi
+
+if test ! -f $file
+then
+ echo "$me: file \`$file' does not exist" >&2
+ exit 1
+elif test ! -r $file
+then
+ echo "$me: permission denied (cannot read \`$file')" >&2
+ exit 1
+fi
+
+host="`hostname --fqdn`"
+
+awk ' BEGIN {
+ inkey = 0
+ seenkey = 0
+ nfound = 0
+ err = "cat >&2"
+ me = "'"$me"'"
+ host = "'"$host"'"
+ file = "'"$file"'"
+ fmt = "'"$fmt"'"
+ gw = "'"$gw"'"
+ id = "'"$id"'"
+ comment = ""
+ s = "[ \t]+"
+ os = "[ \t]*"
+ x = "[^ \t]+"
+ oc = "(#.*)?"
+ suffix = ":" os "[rR][sS][aA]" os "{" os oc "$"
+ if (id == "") {
+ pat = "^" suffix
+ printid = "default"
+ } else {
+ pat = "^(" x s ")*" id "(" s x ")*" os suffix
+ printid = quote(id)
+ }
+ paydirt = "^[ \t]+#pubkey=0s"
+ status = 0
+ }
+ $0 ~ pat {
+ inkey = 1
+ seenkey = 1
+ }
+ /^[ \t]+}$/ {
+ inkey = 0
+ }
+ inkey && $0 ~ /^[ \t]+# RSA [0-9]+ bits/ {
+ comment = $0
+ if (fmt == "dns" || fmt == "txt" || fmt == "dhclient")
+ sub(/^[ \t]+#/, "#", comment)
+ host = $5
+ }
+ inkey && $0 ~ /^[ \t]+#pubkey=0s/ {
+
+ }
+ inkey && fmt == "dns" && $0 ~ paydirt {
+ out = $0
+ sub(paydirt, (host ".\tIN\tKEY\t0x4200 4 1 "), out)
+ nfound++
+ }
+ inkey && fmt == "dhclient" && $0 ~ paydirt {
+ # NOT YET ADJUSTED TO KEY RR elimination
+ boilerplate = "option oe-key code 159 = string;\n" \
+ "option oe-gateway code 160 = ip-address;\n" \
+ "send oe-key = "
+ out = $0
+ sub(paydirt, "0x4200 4 1 ", out)
+ out = "option oe-key code 159 = string;\n" \
+ "option oe-gateway code 160 = ip-address;\n" \
+ "send oe-key = " quote(out) ";"
+ nfound++
+ }
+ inkey && fmt == "txt" && $0 ~ paydirt {
+ if (gw !~ /^@/ && gw !~ /^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$/ )
+ {
+ grump("gateway must be @FQDN or IPv4 address, not " quote(gw))
+ exit(status)
+ }
+ out = $0
+ gsub(/[ \t]+/, " ", out)
+ sub(paydirt, "", out)
+ out = " " out
+ str = "X-IPsec-Server(10)=" gw
+ if (length(str) < 255 && length(str) + length(out) > 255) {
+ str = " " quote(str)
+ } else {
+ out = str out
+ str = ""
+ }
+ while (length(out) > 255) {
+ str = str " " quote(substr(out, 1, 255))
+ out = substr(out, 256)
+ }
+ if (length(out) > 0)
+ str = str " " quote(out)
+ out = "\tIN\tTXT\t" substr(str, 2)
+ nfound++
+ }
+ inkey && (fmt == "left" || fmt == "right") && $0 ~ /^[ \t]+#pubkey=/ {
+ out = $0
+ sub(/^[ \t]+#pubkey=/, ("\t" fmt "rsasigkey="), out)
+ nfound++
+ }
+ function quote(s) {
+ return "\"" s "\""
+ }
+ function grump(s) {
+ print me ": " s |err
+ status = 1
+ }
+ END {
+ if (status != 0)
+ exit(status)
+ if (!seenkey)
+ grump("no " printid " key in " quote(file))
+ else if (nfound == 0) {
+ grump("no pubkey line found -- key information old?")
+ } else if (nfound > 1)
+ grump("multiple " printid " keys found!?!")
+ else {
+ if (comment != "")
+ print comment
+ print out
+ }
+ exit(status)
+ }' $file
diff --git a/programs/showpolicy/.cvsignore b/programs/showpolicy/.cvsignore
new file mode 100644
index 000000000..e4fad4e23
--- /dev/null
+++ b/programs/showpolicy/.cvsignore
@@ -0,0 +1 @@
+showpolicy
diff --git a/programs/showpolicy/Makefile b/programs/showpolicy/Makefile
new file mode 100644
index 000000000..b3ea5a0a8
--- /dev/null
+++ b/programs/showpolicy/Makefile
@@ -0,0 +1,38 @@
+# Makefile for the KLIPS interface utilities
+# Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:31 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=showpolicy
+EXTRA5PROC=${PROGRAM}.8
+
+LIBS=${POLICYLIB} ${FREESWANLIB}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# Revision 1.1 2004/03/15 20:35:31 as
+# added files from freeswan-2.04-x509-1.5.3
+#
+# Revision 1.2 2003/05/14 02:12:27 mcr
+# addition of CGI-focused interface to policy lookup interface
+#
+# Revision 1.1 2003/05/11 00:45:08 mcr
+# program to interogate ipsec policy of stdin.
+# run this from inetd.
+#
+#
diff --git a/programs/showpolicy/showpolicy.8 b/programs/showpolicy/showpolicy.8
new file mode 100644
index 000000000..4fbc2e40e
--- /dev/null
+++ b/programs/showpolicy/showpolicy.8
@@ -0,0 +1,41 @@
+.TH IPSEC_SHOWPOLICY 8 "7 May 2003"
+.\"
+.\" RCSID $Id: showpolicy.8,v 1.1 2004/03/15 20:35:31 as Exp $
+.\"
+.SH NAME
+ipsec showpolicy \- dump policy of socket found as stdin
+.SH SYNOPSIS
+.PP
+.B ipsec
+.B showpolicy
+.PP
+.SH DESCRIPTION
+.I showpolicy
+calls the
+.IR ipsec_policy_lookup (3)
+function on the file description which is its stdin.
+.PP
+It then dumps the resulting query in a human readable form.
+.PP
+This is a test program. One might run it from inetd, via:
+.TP
+discard stream tcp nowait nobody /usr/local/libexec/ipsec/showpolicy showpolicy
+.SH FILES
+/var/run/ipsecpolicy.ctl
+.SH "SEE ALSO"
+ipsec(8), ipsec_policy_query(3), ipsec_pluto(8)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Michael Richardson
+.SH BUGS
+.\"
+.\" $Log: showpolicy.8,v $
+.\" Revision 1.1 2004/03/15 20:35:31 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.1 2003/05/11 00:45:08 mcr
+.\" program to interogate ipsec policy of stdin.
+.\" run this from inetd.
+.\"
+.\"
diff --git a/programs/showpolicy/showpolicy.c b/programs/showpolicy/showpolicy.c
new file mode 100644
index 000000000..114cc3936
--- /dev/null
+++ b/programs/showpolicy/showpolicy.c
@@ -0,0 +1,251 @@
+/*
+ * A program to dump the IPsec status of the socket found on stdin.
+ * Run me from inetd, for instance.
+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+char showpolicy_version[] = "RCSID $Id: showpolicy.c,v 1.1 2004/03/15 20:35:31 as Exp $";
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <getopt.h>
+#include "freeswan.h"
+#include "freeswan/ipsec_policy.h"
+
+char *program_name;
+
+static void
+help(void)
+{
+ fprintf(stderr,
+ "Usage:\n\n"
+ "showpolicy"
+ " [--cgi] lookup the particulars from CGI variables.\n"
+ " [--socket] lookup the particulars from the socket on stdin.\n"
+ " [--textual] dump output in human friendly form\n"
+ " [--plaintext X] string to dump if no security\n"
+ " [--vpntext X] string to dump if VPN configured tunnel\n"
+ " [--privacytext X] string to dump if just plain DNS OE\n"
+ " [--dnssectext X] string to dump if just DNSSEC OE\n"
+ "\n\n"
+ "FreeS/WAN %s\n",
+ ipsec_version_code());
+}
+
+static const struct option long_opts[] = {
+ /* name, has_arg, flag, val */
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "socket", no_argument, NULL, 'i' },
+ { "cgi", no_argument, NULL, 'g' },
+ { "textual", no_argument, NULL, 't' },
+ { "plaintext", required_argument, NULL, 'c' },
+ { "vpntext", required_argument, NULL, 'v' },
+ { "privacytext", required_argument, NULL, 'p' },
+ { "dnssectext", required_argument, NULL, 's' },
+ { 0,0,0,0 }
+};
+
+void dump_policyreply(struct ipsec_policy_cmd_query *q)
+{
+ char src[ADDRTOT_BUF], dst[ADDRTOT_BUF];
+
+ /* now print it! */
+ addrtot(&q->query_local, 0, src, sizeof(src));
+ addrtot(&q->query_remote, 0, dst, sizeof(dst));
+
+ printf("Results of query on %s -> %s with seq %d\n",
+ src, dst, q->head.ipm_msg_seq);
+
+ printf("Received reply of %d bytes.\n", q->head.ipm_msg_len);
+
+ printf("Strength: %d\n", q->strength);
+ printf("Bandwidth: %d\n", q->bandwidth);
+ printf("authdetail: %d\n", q->auth_detail);
+ printf("esp_detail: %d\n", q->esp_detail);
+ printf("comp_detail: %d\n",q->comp_detail);
+
+ printf("credentials: %d\n", q->credential_count);
+ if(q->credential_count > 0) {
+ int c;
+
+ for(c=0; c<q->credential_count; c++) {
+ switch(q->credentials[c].ii_format) {
+ case CERT_DNS_SIGNED_KEY:
+ printf("\tDNSSEC identity: %s (SIG %s)\n",
+ q->credentials[c].ii_credential.ipsec_dns_signed.fqdn,
+ q->credentials[c].ii_credential.ipsec_dns_signed.dns_sig);
+ break;
+
+ case CERT_RAW_RSA:
+ printf("\tlocal identity: %s\n",
+ q->credentials[c].ii_credential.ipsec_raw_key.id_name);
+
+ case CERT_NONE:
+ printf("\tDNS identity: %s\n",
+ q->credentials[c].ii_credential.ipsec_dns_signed.fqdn);
+ break;
+
+ default:
+ printf("\tUnknown identity type %d", q->credentials[c].ii_format);
+ break;
+ }
+ }
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct ipsec_policy_cmd_query q;
+ err_t ret;
+ int c;
+
+ /* set the defaults */
+ char lookup_style = 'i';
+ char output_style = 's';
+
+ char *plaintext = "clear";
+ char *vpntext = "vpn";
+ char *privacytext = "private";
+ char *dnssectext = "secure";
+
+ while((c = getopt_long(argc, argv, "hVighc:v:p:s:", long_opts, 0))!=EOF) {
+ switch (c) {
+ default:
+ case 'h': /* --help */
+ help();
+ return 0; /* GNU coding standards say to stop here */
+
+ case 'V': /* --version */
+ fprintf(stderr, "FreeS/WAN %s\n", ipsec_version_code());
+ return 0; /* GNU coding standards say to stop here */
+
+ case 'i':
+ if(isatty(0)) {
+ printf("please run this connected to a socket\n");
+ exit(1);
+ }
+
+ lookup_style = 'i';
+ break;
+
+ case 'g':
+ lookup_style = 'g';
+ break;
+
+ case 't':
+ output_style = 't';
+ break;
+
+ case 'c':
+ plaintext = optarg;
+ break;
+
+ case 'v':
+ vpntext = optarg;
+ break;
+
+ case 'p':
+ privacytext = optarg;
+ break;
+
+ case 's':
+ dnssectext = optarg;
+ break;
+ }
+ }
+
+ if((ret = ipsec_policy_init()) != NULL) {
+ perror(ret);
+ exit(2);
+ }
+
+ switch(lookup_style) {
+ case 'i':
+ if((ret = ipsec_policy_lookup(0, &q)) != NULL) {
+ perror(ret);
+ exit(3);
+ }
+ break;
+
+ case 'g':
+ if((ret = ipsec_policy_cgilookup(&q)) != NULL) {
+ perror(ret);
+ exit(3);
+ }
+ break;
+
+ default:
+ abort();
+ break;
+ }
+
+
+ if(output_style == 't') {
+ dump_policyreply(&q);
+ } else {
+ /* start by seeing if there was any crypto */
+ if(q.strength < IPSEC_PRIVACY_PRIVATE) {
+ /* no, so say clear */
+ puts(plaintext);
+ exit(0);
+ }
+
+ /* we now it is crypto, but authentic is it? */
+ if(q.credential_count == 0) {
+ puts(vpntext);
+ exit(0);
+ }
+
+ switch(q.credentials[0].ii_format) {
+ case CERT_DNS_SIGNED_KEY:
+ puts(dnssectext);
+ exit(0);
+
+ case CERT_RAW_RSA:
+ puts(vpntext);
+ exit(0);
+
+ default:
+ puts(privacytext);
+ exit(0);
+ }
+ }
+
+ exit(0);
+}
+
+/*
+ * $Log: showpolicy.c,v $
+ * Revision 1.1 2004/03/15 20:35:31 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.4 2003/05/14 15:46:44 mcr
+ * switch statement was missing break statements and was running on.
+ *
+ * Revision 1.3 2003/05/14 02:12:27 mcr
+ * addition of CGI-focused interface to policy lookup interface
+ *
+ * Revision 1.2 2003/05/13 03:25:34 mcr
+ * print credentials, if any were provided.
+ *
+ * Revision 1.1 2003/05/11 00:45:08 mcr
+ * program to interogate ipsec policy of stdin.
+ * run this from inetd.
+ *
+ *
+ *
+ */
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);
+}
diff --git a/programs/spigrp/.cvsignore b/programs/spigrp/.cvsignore
new file mode 100644
index 000000000..4fee1abcf
--- /dev/null
+++ b/programs/spigrp/.cvsignore
@@ -0,0 +1 @@
+spigrp
diff --git a/programs/spigrp/Makefile b/programs/spigrp/Makefile
new file mode 100644
index 000000000..df8899eaf
--- /dev/null
+++ b/programs/spigrp/Makefile
@@ -0,0 +1,52 @@
+# Makefile for miscelaneous programs
+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:31 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM=spigrp
+EXTRA5PROC=${PROGRAM}.5
+
+LIBS=${FREESWANLIB}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# 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/spigrp/spigrp.5 b/programs/spigrp/spigrp.5
new file mode 100644
index 000000000..b00d7ae73
--- /dev/null
+++ b/programs/spigrp/spigrp.5
@@ -0,0 +1,116 @@
+.TH IPSEC_SPIGRP 5 "27 Jun 2000"
+.\"
+.\" RCSID $Id: spigrp.5,v 1.1 2004/03/15 20:35:31 as Exp $
+.\"
+.SH NAME
+ipsec_spigrp \- list IPSEC Security Association groupings
+.SH SYNOPSIS
+.B ipsec
+.B spigrp
+.PP
+.B cat
+.B /proc/net/ipsec_spigrp
+.PP
+.SH DESCRIPTION
+.I /proc/net/ipsec_spigrp
+is a read-only file that lists groups of IPSEC Security Associations
+(SAs).
+.PP
+An entry in the IPSEC extended routing table can only point (via an
+SAID) to one SA. If more than one transform must be applied to a given
+type of packet, this can be accomplished by setting up several SAs with
+the same destination address but potentially different SPIs and
+protocols, and grouping them with
+.IR ipsec_spigrp(8) .
+.PP
+The SA groups are listed, one line per connection/group, as a sequence
+of SAs to be applied (or that should have been applied, in the case of
+an incoming packet) from inside to outside the packet. An SA is
+identified by its SAID, which consists of protocol ("ah", "esp", "comp" or
+"tun"), SPI (with '.' for IPv4 or ':' for IPv6 prefixed hexadecimal number ) and destination address
+(IPv4 dotted quad or IPv6 coloned hex) prefixed by '@', in the format <proto><af><spi>@<dest>.
+.SH EXAMPLES
+.TP
+.B tun.3d0@192.168.2.110
+.B comp.3d0@192.168.2.110
+.B esp.187a101b@192.168.2.110
+.B ah.187a101a@192.168.2.110
+.LP
+is a group of 3 SAs, destined for
+.BR 192.168.2.110
+with an IPv4-in-IPv4 tunnel SA applied first with an SPI of
+.BR 3d0
+in hexadecimal, followed by a Deflate compression header to compress
+the packet with CPI of
+.BR 3d0
+in hexadecimal, followed by an Encapsulating Security Payload header to
+encrypt the packet with SPI
+.BR 187a101b
+in hexadecimal, followed by an Authentication Header to authenticate the
+packet with SPI
+.BR 187a101a
+in hexadecimal, applied from inside to outside the packet. This could
+be an incoming or outgoing group, depending on the address of the local
+machine.
+.LP
+.TP
+.B tun:3d0@3049:1::2
+.B comp:3d0@3049:1::2
+.B esp:187a101b@3049:1::2
+.B ah:187a101a@3049:1::2
+.LP
+is a group of 3 SAs, destined for
+.BR 3049:1::2
+with an IPv6-in-IPv6 tunnel SA applied first with an SPI of
+.BR 3d0
+in hexadecimal, followed by a Deflate compression header to compress
+the packet with CPI of
+.BR 3d0
+in hexadecimal, followed by an Encapsulating Security Payload header to
+encrypt the packet with SPI
+.BR 187a101b
+in hexadecimal, followed by an Authentication Header to authenticate the
+packet with SPI
+.BR 187a101a
+in hexadecimal, applied from inside to outside the packet. This could
+be an incoming or outgoing group, depending on the address of the local
+machine.
+.LP
+.SH FILES
+/proc/net/ipsec_spigrp, /usr/local/bin/ipsec
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_tncfg(5), ipsec_eroute(5),
+ipsec_spi(5), ipsec_klipsdebug(5), ipsec_spigrp(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
+:-)
+.\"
+.\" $Log: spigrp.5,v $
+.\" Revision 1.1 2004/03/15 20:35:31 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.6 2002/04/24 07:35:40 mcr
+.\" Moved from ./klips/utils/spigrp.5,v
+.\"
+.\" Revision 1.5 2000/09/17 18:56:48 rgb
+.\" Added IPCOMP support.
+.\"
+.\" Revision 1.4 2000/09/13 15:54:32 rgb
+.\" Added Gerhard's ipv6 updates.
+.\"
+.\" 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/spigrp/spigrp.8 b/programs/spigrp/spigrp.8
new file mode 100644
index 000000000..418ed5c3e
--- /dev/null
+++ b/programs/spigrp/spigrp.8
@@ -0,0 +1,174 @@
+.TH IPSEC_SPIGRP 8 "21 Jun 2000"
+.\"
+.\" RCSID $Id: spigrp.8,v 1.1 2004/03/15 20:35:31 as Exp $
+.\"
+.SH NAME
+ipsec spigrp \- group/ungroup IPSEC Security Associations
+.SH SYNOPSIS
+.B ipsec
+.B spigrp
+.PP
+.B ipsec
+.B spigrp
+[
+.B \-\-label
+label ]
+af1 dst1 spi1 proto1 [ af2 dst2 spi2 proto2 [ af3 dst3 spi3 proto3 [ af4 dst4 spi4 proto4 ] ] ]
+.PP
+.B ipsec
+.B spigrp
+[
+.B \-\-label
+label ]
+.B \-\-said
+SA1 [ SA2 [ SA3 [ SA4 ] ] ]
+.PP
+.B ipsec
+.B spigrp
+.B \-\-help
+.PP
+.B ipsec
+.B spigrp
+.B \-\-version
+.PP
+.SH DESCRIPTION
+.I Spigrp
+groups IPSEC Security Associations (SAs) together or ungroups
+previously grouped SAs.
+An entry in the IPSEC extended
+routing table can only point
+(via a destination address, a Security Parameters Index (SPI) and
+a protocol identifier) to one SA.
+If more than one transform must be applied to a given type of packet,
+this can be accomplished by setting up several SAs
+with the same destination address but potentially different SPIs and protocols,
+and grouping them with
+.IR spigrp .
+.PP
+The SAs to be grouped,
+specified by destination address (DNS name lookup, IPv4 dotted quad or IPv6 coloned hex), SPI
+('0x'-prefixed hexadecimal number) and protocol ("ah", "esp", "comp" or "tun"),
+are listed from the inside transform to the
+outside;
+in other words, the transforms are applied in
+the order of the command line and removed in the reverse
+order.
+The resulting SA group is referred to by its first SA (by
+.IR af1 ,
+.IR dst1 ,
+.IR spi1
+and
+.IR proto1 ).
+.PP
+The \-\-said option indicates that the SA IDs are to be specified as
+one argument each, in the format <proto><af><spi>@<dest>. The SA IDs must
+all be specified as separate parameters without the \-\-said option or
+all as monolithic parameters after the \-\-said option.
+.PP
+The SAs must already exist and must not already
+be part of a group.
+.PP
+If
+.I spigrp
+is invoked with only one SA specification,
+it ungroups the previously-grouped set of SAs containing
+the SA specified.
+.PP
+The \-\-label option identifies all responses from that command
+invocation with a user-supplied label, provided as an argument to the
+label option. This can be helpful for debugging one invocation of the
+command out of a large number.
+.PP
+The command form with no additional arguments lists the contents of
+/proc/net/ipsec_spigrp. The format of /proc/net/ipsec_spigrp is
+discussed in ipsec_spigrp(5).
+.SH EXAMPLES
+.TP
+.B ipsec spigrp inet gw2 0x113 tun inet gw2 0x115 esp inet gw2 0x116 ah
+groups 3 SAs together, all destined for
+.BR gw2 ,
+but with an IPv4-in-IPv4 tunnel SA applied first with SPI
+.BR 0x113 ,
+then an ESP header to encrypt the packet with SPI
+.BR 0x115 ,
+and finally an AH header to authenticate the packet with SPI
+.BR 0x116 .
+.LP
+.TP
+.B ipsec spigrp --said tun.113@gw2 esp.115@gw2 ah.116@gw2
+groups 3 SAs together, all destined for
+.BR gw2 ,
+but with an IPv4-in-IPv4 tunnel SA applied first with SPI
+.BR 0x113 ,
+then an ESP header to encrypt the packet with SPI
+.BR 0x115 ,
+and finally an AH header to authenticate the packet with SPI
+.BR 0x116 .
+.LP
+.TP
+.B ipsec spigrp --said tun:233@3049:1::1 esp:235@3049:1::1 ah:236@3049:1::1
+groups 3 SAs together, all destined for
+.BR 3049:1::1,
+but with an IPv6-in-IPv6 tunnel SA applied first with SPI
+.BR 0x233 ,
+then an ESP header to encrypt the packet with SPI
+.BR 0x235 ,
+and finally an AH header to authenticate the packet with SPI
+.BR 0x236 .
+.LP
+.TP
+.B ipsec spigrp inet6 3049:1::1 0x233 tun inet6 3049:1::1 0x235 esp inet6 3049:1::1 0x236 ah
+groups 3 SAs together, all destined for
+.BR 3049:1::1,
+but with an IPv6-in-IPv6 tunnel SA applied first with SPI
+.BR 0x233 ,
+then an ESP header to encrypt the packet with SPI
+.BR 0x235 ,
+and finally an AH header to authenticate the packet with SPI
+.BR 0x236 .
+.LP
+.SH FILES
+/proc/net/ipsec_spigrp, /usr/local/bin/ipsec
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_tncfg(8), ipsec_eroute(8),
+ipsec_spi(8), ipsec_klipsdebug(8), ipsec_spigrp(5)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Richard Guy Briggs.
+.SH BUGS
+Yes, it really is limited to a maximum of four SAs,
+although admittedly it's hard to see why you would need more.
+.\"
+.\" $Log: spigrp.8,v $
+.\" Revision 1.1 2004/03/15 20:35:31 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.20 2002/04/24 07:35:41 mcr
+.\" Moved from ./klips/utils/spigrp.8,v
+.\"
+.\" Revision 1.19 2000/09/17 18:56:48 rgb
+.\" Added IPCOMP support.
+.\"
+.\" Revision 1.18 2000/09/13 15:54:32 rgb
+.\" Added Gerhard's ipv6 updates.
+.\"
+.\" Revision 1.17 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.16 2000/06/21 16:54:57 rgb
+.\" Added 'no additional args' text for listing contents of
+.\" /proc/net/ipsec_* files.
+.\"
+.\" Revision 1.15 2000/02/14 21:08:30 rgb
+.\" Added description of --said option.
+.\"
+.\" Revision 1.14 1999/07/19 18:47:25 henry
+.\" fix slightly-misformed comments
+.\"
+.\" Revision 1.13 1999/04/06 04:54:39 rgb
+.\" Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+.\" patch shell fixes.
+.\"
diff --git a/programs/spigrp/spigrp.c b/programs/spigrp/spigrp.c
new file mode 100644
index 000000000..4cbac304d
--- /dev/null
+++ b/programs/spigrp/spigrp.c
@@ -0,0 +1,491 @@
+/*
+ * SA grouping
+ * Copyright (C) 1996 John Ioannidis.
+ * Copyright (C) 1997, 1998, 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.
+ */
+
+char spigrp_c_version[] = "RCSID $Id: spigrp.c,v 1.2 2004/06/07 15:16:34 as Exp $";
+
+
+#include <sys/types.h>
+#include <linux/types.h> /* new */
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h> /* open() */
+#include <fcntl.h> /* open() */
+#include <stdlib.h> /* system(), strtoul() */
+
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+/* #include <linux/ip.h> */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <freeswan.h>
+#if 0
+#include <linux/autoconf.h> /* CONFIG_IPSEC_PFKEYv2 */
+#endif
+
+#include <signal.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "freeswan/radij.h"
+#include "freeswan/ipsec_encap.h"
+#include "freeswan/ipsec_ah.h"
+
+
+char *program_name;
+
+int pfkey_sock;
+fd_set pfkey_socks;
+uint32_t pfkey_seq = 0;
+
+struct said_af {
+ int af;
+ ip_said said;
+}; /* to store the given saids and their address families in an array */
+ /* XXX: Note that we do *not* check if the address families of all SAID?s are the same.
+ * This can make it possible to group SAs for IPv4 addresses with SAs for
+ * IPv6 addresses (perhaps some kind of IPv4-over-secIPv6 or vice versa).
+ * Do not know, if this is a bug or feature */
+
+static void
+usage(char *s)
+{
+ fprintf(stdout, "usage: Note: position of options and arguments is important!\n");
+ fprintf(stdout, "usage: %s [ --debug ] [ --label <label> ] af1 dst1 spi1 proto1 [ af2 dst2 spi2 proto2 [ af3 dst3 spi3 proto3 [ af4 dst4 spi4 proto4 ] ] ]\n", s);
+ fprintf(stdout, "usage: %s [ --debug ] [ --label <label> ] --said <SA1> [ <SA2> [ <SA3> [ <SA4> ] ] ]\n", s);
+ fprintf(stdout, "usage: %s --help\n", s);
+ fprintf(stdout, "usage: %s --version\n", s);
+ fprintf(stdout, "usage: %s\n", s);
+ fprintf(stdout, " [ --debug ] is optional to any %s command.\n", s);
+ fprintf(stdout, " [ --label <label> ] is optional to any %s command.\n", s);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int i, nspis;
+ char *endptr;
+ int said_opt = 0;
+
+ const char* error_s = NULL;
+ char ipaddr_txt[ADDRTOT_BUF];
+ int debug = 0;
+ int j;
+ struct said_af said_af_array[4];
+
+ int error = 0;
+
+ struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+ struct sadb_msg *pfkey_msg;
+#if 0
+ ip_address pfkey_address_s_ska;
+#endif
+
+ program_name = argv[0];
+ for(i = 0; i < 4; i++) {
+ memset(&said_af_array[i], 0, sizeof(struct said_af));
+ }
+
+ if(argc > 1 && strcmp(argv[1], "--debug") == 0) {
+ debug = 1;
+ if(debug) {
+ fprintf(stdout, "\"--debug\" option requested.\n");
+ }
+ argv += 1;
+ argc -= 1;
+ pfkey_lib_debug = PF_KEY_DEBUG_PARSE_MAX;
+ }
+
+ if(debug) {
+ fprintf(stdout, "argc=%d (%d incl. --debug option).\n",
+ argc,
+ argc + 1);
+ }
+
+ if(argc > 1 && strcmp(argv[1], "--label") == 0) {
+ if(argc > 2) {
+ program_name = malloc(strlen(argv[0])
+ + 10 /* update this when changing the sprintf() */
+ + strlen(argv[2]));
+ sprintf(program_name, "%s --label %s",
+ argv[0],
+ argv[2]);
+ if(debug) {
+ fprintf(stdout, "using \"%s\" as a label.\n", program_name);
+ }
+ argv += 2;
+ argc -= 2;
+ } else {
+ fprintf(stderr, "%s: --label option requires an argument.\n",
+ program_name);
+ exit(1);
+ }
+ }
+
+ if(debug) {
+ fprintf(stdout, "...After check for --label option.\n");
+ }
+
+ if(argc == 1) {
+ system("cat /proc/net/ipsec_spigrp");
+ exit(0);
+ }
+
+ if(debug) {
+ fprintf(stdout, "...After check for no option to print /proc/net/ipsec_spigrp.\n");
+ }
+
+ if(strcmp(argv[1], "--help") == 0) {
+ if(debug) {
+ fprintf(stdout, "\"--help\" option requested.\n");
+ }
+ usage(program_name);
+ exit(1);
+ }
+
+ if(debug) {
+ fprintf(stdout, "...After check for --help option.\n");
+ }
+
+ if(strcmp(argv[1], "--version") == 0) {
+ if(debug) {
+ fprintf(stdout, "\"--version\" option requested.\n");
+ }
+ fprintf(stderr, "%s, %s\n", program_name, spigrp_c_version);
+ exit(1);
+ }
+
+ if(debug) {
+ fprintf(stdout, "...After check for --version option.\n");
+ }
+
+ if(strcmp(argv[1], "--said") == 0) {
+ if(debug) {
+ fprintf(stdout, "processing %d args with --said flag.\n", argc);
+ }
+ said_opt = 1;
+ }
+
+ if(debug) {
+ fprintf(stdout, "...After check for --said option.\n");
+ }
+
+ if(said_opt) {
+ if (argc < 3 /*|| argc > 5*/) {
+ fprintf(stderr, "expecting 3 or more args with --said, got %d.\n", argc);
+ usage(program_name);
+ exit(1);
+ }
+ nspis = argc - 2;
+ } else {
+ if ((argc < 5) || (argc > 17) || ((argc % 4) != 1)) {
+ fprintf(stderr, "expecting 5 or more args without --said, got %d.\n", argc);
+ usage(program_name);
+ exit(1);
+ }
+ nspis = argc / 4;
+ }
+
+ if(debug) {
+ fprintf(stdout, "processing %d nspis.\n", nspis);
+ }
+
+ for(i = 0; i < nspis; i++) {
+ if(debug) {
+ fprintf(stdout, "processing spi #%d.\n", i);
+ }
+
+ if(said_opt) {
+ error_s = ttosa((const char *)argv[i+2], 0, (ip_said*)&(said_af_array[i].said));
+ if(error_s != NULL) {
+ fprintf(stderr, "%s: Error, %s converting --sa argument:%s\n",
+ program_name, error_s, argv[i+2]);
+ exit (1);
+ }
+ said_af_array[i].af = addrtypeof(&(said_af_array[i].said.dst));
+ if(debug) {
+ addrtot(&said_af_array[i].said.dst, 0, ipaddr_txt, sizeof(ipaddr_txt));
+ fprintf(stdout, "said[%d].dst=%s.\n", i, ipaddr_txt);
+ }
+ } else {
+ if(!strcmp(argv[i*4+4], "ah")) {
+ said_af_array[i].said.proto = SA_AH;
+ }
+ if(!strcmp(argv[i*4+4], "esp")) {
+ said_af_array[i].said.proto = SA_ESP;
+ }
+ if(!strcmp(argv[i*4+4], "tun")) {
+ said_af_array[i].said.proto = SA_IPIP;
+ }
+ if(!strcmp(argv[i*4+4], "comp")) {
+ said_af_array[i].said.proto = SA_COMP;
+ }
+ if(said_af_array[i].said.proto == 0) {
+ fprintf(stderr, "%s: Badly formed proto: %s\n",
+ program_name, argv[i*4+4]);
+ exit(1);
+ }
+ said_af_array[i].said.spi = htonl(strtoul(argv[i*4+3], &endptr, 0));
+ if(!(endptr == argv[i*4+3] + strlen(argv[i*4+3]))) {
+ fprintf(stderr, "%s: Badly formed spi: %s\n",
+ program_name, argv[i*4+3]);
+ exit(1);
+ }
+ if(!strcmp(argv[i*4+1], "inet")) {
+ said_af_array[i].af = AF_INET;
+ }
+ if(!strcmp(argv[i*4+1], "inet6")) {
+ said_af_array[i].af = AF_INET6;
+ }
+ if((said_af_array[i].af != AF_INET) && (said_af_array[i].af != AF_INET6)) {
+ fprintf(stderr, "%s: Address family %s not supported\n",
+ program_name, argv[i*4+1]);
+ exit(1);
+ }
+ error_s = ttoaddr(argv[i*4+2], 0, said_af_array[i].af, &(said_af_array[i].said.dst));
+ if(error_s != NULL) {
+ fprintf(stderr, "%s: Error, %s converting %dth address argument:%s\n",
+ program_name, error_s, i, argv[i*4+2]);
+ exit (1);
+ }
+ }
+ if(debug) {
+ fprintf(stdout, "SA %d contains: ", i+1);
+ fprintf(stdout, "\n");
+ fprintf(stdout, "proto = %d\n", said_af_array[i].said.proto);
+ fprintf(stdout, "spi = %08x\n", said_af_array[i].said.spi);
+ addrtot(&said_af_array[i].said.dst, 0, ipaddr_txt, sizeof(ipaddr_txt));
+ fprintf(stdout, "edst = %s\n", ipaddr_txt);
+ }
+ }
+
+ if(debug) {
+ fprintf(stdout, "Opening pfkey socket.\n");
+ }
+
+ 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);
+ }
+
+ for(i = 0; i < (((nspis - 1) < 2) ? 1 : (nspis - 1)); i++) {
+ if(debug) {
+ fprintf(stdout, "processing %dth pfkey message.\n", i);
+ }
+
+ pfkey_extensions_init(extensions);
+ for(j = 0; j < ((nspis == 1) ? 1 : 2); j++) {
+ if(debug) {
+ fprintf(stdout, "processing %dth said of %dth pfkey message.\n", j, i);
+ }
+
+ /* Build an SADB_X_GRPSA message to send down. */
+ /* It needs <base, SA, SA2, address(D,D2) > minimum. */
+ if(!j) {
+ if((error = pfkey_msg_hdr_build(&extensions[0],
+ SADB_X_GRPSA,
+ proto2satype(said_af_array[i].said.proto),
+ 0,
+ ++pfkey_seq,
+ getpid()))) {
+ fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
+ program_name, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+ } else {
+ if(debug) {
+ fprintf(stdout, "setting x_satype proto=%d satype=%d\n",
+ said_af_array[i+j].said.proto,
+ proto2satype(said_af_array[i+j].said.proto)
+ );
+ }
+
+ if((error = pfkey_x_satype_build(&extensions[SADB_X_EXT_SATYPE2],
+ proto2satype(said_af_array[i+j].said.proto)
+ ))) {
+ fprintf(stderr, "%s: Trouble building message header, error=%d.\n",
+ program_name, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+ }
+
+ if((error = pfkey_sa_build(&extensions[!j ? SADB_EXT_SA : SADB_X_EXT_SA2],
+ !j ? SADB_EXT_SA : SADB_X_EXT_SA2,
+ said_af_array[i+j].said.spi, /* in network order */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0))) {
+ fprintf(stderr, "%s: Trouble building sa extension, error=%d.\n",
+ program_name, error);
+ pfkey_extensions_free(extensions);
+ exit(1);
+ }
+
+#if 0
+ if(!j) {
+ anyaddr(said_af_array[i].af, &pfkey_address_s_ska); /* Is the address family correct ?? */
+ if((error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+ SADB_EXT_ADDRESS_SRC,
+ 0,
+ 0,
+ sockaddrof(&pfkey_address_s_ska)))) {
+ addrtot(&pfkey_address_s_ska, 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);
+ }
+ }
+#endif
+ if((error = pfkey_address_build(&extensions[!j ? SADB_EXT_ADDRESS_DST : SADB_X_EXT_ADDRESS_DST2],
+ !j ? SADB_EXT_ADDRESS_DST : SADB_X_EXT_ADDRESS_DST2,
+ 0,
+ 0,
+ sockaddrof(&said_af_array[i+j].said.dst)))) {
+ addrtot(&said_af_array[i+j].said.dst,
+ 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((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((error = write(pfkey_sock,
+ pfkey_msg,
+ pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) !=
+ (ssize_t)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)) {
+ fprintf(stderr, "%s: pfkey write failed, returning %d with errno=%d.\n",
+ program_name, error, 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:
+ 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. Please report as much detail as possible to development team.\n", errno);
+ }
+ exit(1);
+ }
+ if(pfkey_msg) {
+ pfkey_extensions_free(extensions);
+ pfkey_msg_free(&pfkey_msg);
+ }
+ }
+
+ (void) close(pfkey_sock); /* close the socket */
+ exit(0);
+}
diff --git a/programs/starter/Makefile b/programs/starter/Makefile
new file mode 100644
index 000000000..60e95d360
--- /dev/null
+++ b/programs/starter/Makefile
@@ -0,0 +1,182 @@
+# ipsec starter Makefile
+# Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security
+#
+# 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.14 2006/02/17 19:34:02 as Exp $
+
+FREESWANSRCDIR?=$(shell cd ../..; pwd)
+include ${FREESWANSRCDIR}/Makefile.inc
+
+LD=$(CC)
+RM=rm
+LEX=flex
+BISON=bison
+GPERF=gperf
+
+FREESWANDIR=../..
+FREESWANLIB=$(FREESWANDIR)/lib/libfreeswan/libfreeswan.a
+PLUTODIR=../pluto
+OPENACDIR=../openac
+
+DEFINES+= -DVIRTUAL_IP -DDEBUG
+
+# This compile option activates the leak detective
+ifeq ($(USE_LEAK_DETECTIVE),true)
+ DEFINES+= -DLEAK_DETECTIVE
+endif
+
+INCLUDES=-I${FREESWANDIR}/linux/include
+CFLAGS=$(DEFINES) $(INCLUDES) -Wall
+CFLAGS+=-DIPSEC_EXECDIR=\"${FINALLIBEXECDIR}\" -DIPSEC_CONFDDIR=\"${FINALCONFDDIR}\"
+CFLAGS+=-DIPSEC_CONFDIR=\"${FINALCONFDIR}\"
+LDFLAGS=
+
+PLUTO_OBJS=defs.o
+
+OBJS=starter.o parser.tab.o lex.yy.o keywords.o args.o invokepluto.o \
+ starterwhack.o klips.o netkey.o interfaces.o exec.o cmp.o confread.o \
+ loglite.o ${PLUTO_OBJS}
+
+DISTSRC=$(OBJS:.o=.c)
+DISTSRC+=cmp.h confread.h confwrite.h exec.h files.h interfaces.h klips.h netkey.h
+DISTSRC+=parser.h args.h invokepluto.h starterwhack.h keywords.h keywords.txt
+
+LIBS=$(FREESWANLIB)
+
+PROGRAM=starter
+
+include ../Makefile.program
+
+all: starter
+
+starter: $(OBJS) $(FREESWANLIB)
+ $(LD) $(LDFLAGS) -o starter $(OBJS) $(LIBS)
+
+lex.yy.c: parser.tab.c parser.l parser.y parser.h
+ $(LEX) parser.l
+
+parser.tab.c: parser.l parser.y parser.h
+ $(BISON) -v -d parser.y
+
+keywords.c: keywords.txt keywords.h
+ $(GPERF) -C -G -t < keywords.txt > keywords.c
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+loglite.o : $(OPENACDIR)/loglite.c $(PLUTODIR)/log.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+# pluto library
+
+defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+clean::
+ $(RM) -f starter $(OBJS) parser.tab.* lex.yy.*
+
+# Stolen from pluto/Makefile
+
+gatherdeps:
+ @ls | grep '\.c$$' | sed -e 's/\(.*\)\.c$$/\1.o: \1.c/'
+ @echo
+ @ls | grep '\.c$$' | xargs grep '^#[ ]*include[ ]*"' | \
+ sed -e 's/\.c:#[ ]*include[ ]*"/.o: /' -e 's/".*//'
+
+# Dependencies generated by "make gatherdeps":
+
+args.o: args.c
+cmp.o: cmp.c
+confread.o: confread.c
+exec.o: exec.c
+interfaces.o: interfaces.c
+invokepluto.o: invokepluto.c
+keywords.o: keywords.c
+klips.o: klips.c
+lex.yy.o: lex.yy.c
+netkey.o: netkey.c
+parser.tab.o: parser.tab.c
+starter.o: starter.c
+starterwhack.o: starterwhack.c
+
+args.o: ../pluto/constants.h
+args.o: ../pluto/defs.h
+args.o: ../pluto/log.h
+args.o: keywords.h
+args.o: parser.h
+args.o: confread.h
+args.o: args.h
+cmp.o: ../pluto/constants.h
+cmp.o: ../pluto/defs.h
+cmp.o: confread.h
+cmp.o: args.h
+cmp.o: interfaces.h
+cmp.o: cmp.h
+confread.o: ../pluto/constants.h
+confread.o: ../pluto/defs.h
+confread.o: ../pluto/log.h
+confread.o: keywords.h
+confread.o: parser.h
+confread.o: confread.h
+confread.o: args.h
+confread.o: interfaces.h
+exec.o: ../pluto/constants.h
+exec.o: ../pluto/defs.h
+exec.o: ../pluto/log.h
+exec.o: exec.h
+interfaces.o: ../pluto/constants.h
+interfaces.o: ../pluto/defs.h
+interfaces.o: ../pluto/log.h
+interfaces.o: interfaces.h
+interfaces.o: exec.h
+interfaces.o: files.h
+invokepluto.o: ../pluto/constants.h
+invokepluto.o: ../pluto/defs.h
+invokepluto.o: ../pluto/log.h
+invokepluto.o: confread.h
+invokepluto.o: invokepluto.h
+invokepluto.o: files.h
+invokepluto.o: starterwhack.h
+keywords.o: keywords.h
+klips.o: ../pluto/constants.h
+klips.o: ../pluto/defs.h
+klips.o: ../pluto/log.h
+klips.o: confread.h
+klips.o: klips.h
+klips.o: files.h
+klips.o: exec.h
+lex.yy.o: parser.tab.h
+netkey.o: ../pluto/constants.h
+netkey.o: ../pluto/defs.h
+netkey.o: ../pluto/log.h
+netkey.o: files.h
+parser.tab.o: ../pluto/constants.h
+parser.tab.o: ../pluto/defs.h
+parser.tab.o: parser.h
+starter.o: ../pluto/constants.h
+starter.o: ../pluto/defs.h
+starter.o: ../pluto/log.h
+starter.o: confread.h
+starter.o: files.h
+starter.o: starterwhack.h
+starter.o: invokepluto.h
+starter.o: klips.h
+starter.o: netkey.h
+starter.o: cmp.h
+starter.o: interfaces.h
+starterwhack.o: ../pluto/constants.h
+starterwhack.o: ../pluto/defs.h
+starterwhack.o: ../pluto/log.h
+starterwhack.o: ../pluto/whack.h
+starterwhack.o: starterwhack.h
+starterwhack.o: confread.h
+starterwhack.o: files.h
diff --git a/programs/starter/README b/programs/starter/README
new file mode 100644
index 000000000..12a60a11d
--- /dev/null
+++ b/programs/starter/README
@@ -0,0 +1,104 @@
+
+IPsec Starter -- Version 0.2 [Contributed by Arkoon Network Security]
+============================ [ http://www.arkoon.net/]
+
+IPsec Starter is aimed to replace all the scripts which are used to
+start and stop strongSwan and to do that in a quicker and a smarter way.
+
+IPsec Starter can also reload the configuration file (kill --HUP or periodicaly)
+and apply the changes.
+
+Usage:
+ starter [--debug] [--auto_update <x seconds>]
+ --debug: enable debugging output
+ --no_fork: all msg (including pluto) are sent to the console
+ --auto_update: reload the config file (like kill -HUP) every x seconds
+ and determine any configuration changes
+
+FEATURES
+--------
+
+o Load and unload KLIPS (ipsec.o kernel module)
+
+o Load modules of the native Linux 2.6 IPsec stack
+
+o Launch and monitor pluto
+
+o Add, initiate, route and del connections
+
+o Attach and detach interfaces according to config file
+
+o kill -HUP can be used to reload the config file. New connections will be
+ added, old ones will be removed and modified ones will be reloaded.
+ Interfaces/Klips/Pluto will be reloaded if necessary.
+
+o Full support of the %defaultroute wildcard parameter.
+
+o save own pid in /var/run/starter
+
+o Upon reloading, dynamic DNS addr will be resolved and reloaded. Use
+ --auto_update to periodicaly check dynamic DNS changes.
+
+o kill -USR1 can be used to reload all connections (delete then add and
+ route/initiate)
+
+o /var/run/dynip/xxxx can be used to use a virtual interface name in
+ ipsec.conf. By example, when adsl can be ppp0, ppp1, ... :
+ ipsec.conf: interfaces="ipsec0=adsl"
+ And use /etc/ppp/ip-up to create /var/run/dynip/adsl
+ /var/run/dynip/adsl: IP_PHYS=ppp0
+
+o %auto can be used to automaticaly name the connections
+
+o kill -TERM can be used to stop FS. pluto will be stopped and KLIPS unloaded
+ (if it has been loaded).
+
+o Can be used to start strongSwan and load lots of connections in a few
+ seconds.
+
+TODO
+----
+
+o handle wildcards in include lines -- use glob() fct
+ ex: include /etc/ipsec.*.conf
+
+o handle duplicates keywords and sections
+
+o 'also' keyword not supported
+
+o manually keyed connections
+
+o IPv6
+
+o Documentation
+
+
+CHANGES
+-------
+
+o Version 0.1 -- 2002.01.14 -- First public release
+
+o Version 0.2 -- 2002.09.04 -- Various enhancements
+ FreeS/WAN 1.98b, x509 0.9.14, algo 0.8.0
+
+o Version 0.2d -- 2004.01.13 -- Adaptions for Openswan 1.0.0
+ by Stephan Scholz <sscholz@astaro.com>
+
+o Version 0.2e -- 2004.10.14 -- Added support for change of interface address
+ by Stephan Scholz <sscholz@astaro.com>
+
+o Version 0.2s -- 2005-12-02 -- Ported to strongSwan
+ by Stephan Scholz <sscholz@astaro.com>
+
+o Version 0.2x -- 2006-01-02 -- Added missing strongSwan keywords
+ Full support of the native Linux 2.6 IPsec stack
+ Full support of %defaultroute
+ Improved parsing of keywords using perfect hash
+ function generated by gperf.
+ by Andreas Steffen <andreas.steffen@hsr.ch>
+
+THANKS
+------
+
+o Nathan Angelacos - include fix
+
diff --git a/programs/starter/args.c b/programs/starter/args.c
new file mode 100644
index 000000000..6f3da63eb
--- /dev/null
+++ b/programs/starter/args.c
@@ -0,0 +1,620 @@
+/* automatic handling of confread struct arguments
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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: args.c,v 1.9 2006/04/17 10:32:36 as Exp $
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "keywords.h"
+#include "parser.h"
+#include "confread.h"
+#include "args.h"
+
+/* argument types */
+
+typedef enum {
+ ARG_NONE,
+ ARG_ENUM,
+ ARG_UINT,
+ ARG_TIME,
+ ARG_ULNG,
+ ARG_PCNT,
+ ARG_STR,
+ ARG_LST,
+ ARG_MISC
+} arg_t;
+
+/* various keyword lists */
+
+static const char *LST_bool[] = {
+ "no",
+ "yes",
+ NULL
+};
+
+static const char *LST_sendcert[] = {
+ "always",
+ "ifasked",
+ "never",
+ "yes",
+ "no",
+ NULL
+};
+
+static const char *LST_dpd_action[] = {
+ "none",
+ "clear",
+ "hold",
+ "restart",
+ NULL
+};
+
+static const char *LST_startup[] = {
+ "ignore",
+ "add",
+ "route",
+ "start",
+ NULL
+};
+
+static const char *LST_packetdefault[] = {
+ "drop",
+ "reject",
+ "pass",
+ NULL
+};
+
+static const char *LST_keyexchange[] = {
+ "ike",
+ NULL
+};
+
+static const char *LST_pfsgroup[] = {
+ "modp1024",
+ "modp1536",
+ "modp2048",
+ "modp3072",
+ "modp4096",
+ "modp6144",
+ "modp8192",
+ NULL
+};
+
+static const char *LST_plutodebug[] = {
+ "none",
+ "all",
+ "raw",
+ "crypt",
+ "parsing",
+ "emitting",
+ "control",
+ "lifecycle",
+ "klips",
+ "dns",
+ "natt",
+ "oppo",
+ "controlmore",
+ "private",
+ NULL
+};
+
+static const char *LST_klipsdebug[] = {
+ "tunnel",
+ "tunnel-xmit",
+ "pfkey",
+ "xform",
+ "eroute",
+ "spi",
+ "radij",
+ "esp",
+ "ah",
+ "ipcomp",
+ "verbose",
+ "all",
+ "none",
+ NULL
+};
+
+typedef struct {
+ arg_t type;
+ size_t offset;
+ const char **list;
+} token_info_t;
+
+static const token_info_t token_info[] =
+{
+ /* config setup keywords */
+ { ARG_LST, offsetof(starter_config_t, setup.interfaces), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.dumpdir), NULL },
+
+ /* pluto keywords */
+ { ARG_LST, offsetof(starter_config_t, setup.plutodebug), LST_plutodebug },
+ { ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL },
+ { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_bool },
+ { ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL },
+ { ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL },
+ { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },
+ { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_bool },
+ { ARG_ENUM, offsetof(starter_config_t, setup.nocrsend), LST_bool },
+ { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool },
+ { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL },
+ { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL },
+ { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool },
+ { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool },
+
+ /* KLIPS keywords */
+ { ARG_LST, offsetof(starter_config_t, setup.klipsdebug), LST_klipsdebug },
+ { ARG_ENUM, offsetof(starter_config_t, setup.fragicmp), LST_bool },
+ { ARG_STR, offsetof(starter_config_t, setup.packetdefault), LST_packetdefault },
+ { ARG_ENUM, offsetof(starter_config_t, setup.hidetos), LST_bool },
+
+ /* conn section keywords */
+ { ARG_STR, offsetof(starter_conn_t, name), NULL },
+ { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup },
+ { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange },
+ { ARG_MISC, 0, NULL /* KW_TYPE */ },
+ { ARG_MISC, 0, NULL /* KW_PFS */ },
+ { ARG_MISC, 0, NULL /* KW_COMPRESS */ },
+ { ARG_MISC, 0, NULL /* KW_AUTH */ },
+ { ARG_MISC, 0, NULL /* KW_AUTHBY */ },
+ { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
+ { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
+ { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
+ { ARG_ULNG, offsetof(starter_conn_t, sa_keying_tries), NULL },
+ { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
+ { ARG_MISC, 0, NULL /* KW_REKEY */ },
+ { ARG_STR, offsetof(starter_conn_t, ike), NULL },
+ { ARG_STR, offsetof(starter_conn_t, esp), NULL },
+ { ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup },
+ { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL },
+ { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL },
+ { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action },
+
+ /* ca section keywords */
+ { ARG_STR, offsetof(starter_ca_t, name), NULL },
+ { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup },
+ { ARG_STR, offsetof(starter_ca_t, cacert), NULL },
+ { ARG_STR, offsetof(starter_ca_t, ldaphost), NULL },
+ { ARG_STR, offsetof(starter_ca_t, ldapbase), NULL },
+ { ARG_STR, offsetof(starter_ca_t, crluri), NULL },
+ { ARG_STR, offsetof(starter_ca_t, crluri2), NULL },
+ { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL },
+
+ /* end keywords */
+ { ARG_MISC, 0, NULL /* KW_HOST */ },
+ { ARG_MISC, 0, NULL /* KW_NEXTHOP */ },
+ { ARG_MISC, 0, NULL /* KW_SUBNET */ },
+ { ARG_MISC, 0, NULL /* KW_SUBNETWITHIN */ },
+ { ARG_MISC, 0, NULL /* KW_PROTOPORT */ },
+ { ARG_MISC, 0, NULL /* KW_SOURCEIP */ },
+ { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool },
+ { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool },
+ { ARG_STR, offsetof(starter_end_t, updown), NULL },
+ { ARG_STR, offsetof(starter_end_t, id), NULL },
+ { ARG_STR, offsetof(starter_end_t, rsakey), NULL },
+ { ARG_STR, offsetof(starter_end_t, cert), NULL },
+ { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert },
+ { ARG_STR, offsetof(starter_end_t, ca), NULL },
+ { ARG_STR, offsetof(starter_end_t, groups), NULL },
+ { ARG_STR, offsetof(starter_end_t, iface), NULL }
+};
+
+static void
+free_list(char **list)
+{
+ char **s;
+
+ for (s = list; *s; s++)
+ pfree(*s);
+ pfree(list);
+}
+
+char **
+new_list(char *value)
+{
+ char *val, *b, *e, *end, **ret;
+ int count;
+
+ val = value ? clone_str(value, "list value") : NULL;
+ if (!val)
+ return NULL;
+ end = val + strlen(val);
+ for (b = val, count = 0; b < end;)
+ {
+ for (e = b; ((*e != ' ') && (*e != '\0')); e++);
+ *e = '\0';
+ if (e != b)
+ count++;
+ b = e + 1;
+ }
+ if (count == 0)
+ {
+ pfree(val);
+ return NULL;
+ }
+ ret = (char **)alloc_bytes((count+1) * sizeof(char *), "list");
+
+ for (b = val, count = 0; b < end; )
+ {
+ for (e = b; (*e != '\0'); e++);
+ if (e != b)
+ ret[count++] = clone_str(b, "list value");
+ b = e + 1;
+ }
+ ret[count] = NULL;
+ pfree(val);
+ return ret;
+}
+
+
+/*
+ * assigns an argument value to a struct field
+ */
+bool
+assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw, char *base
+ , bool *assigned)
+{
+ char *p = base + token_info[token].offset;
+ const char **list = token_info[token].list;
+
+ int index = -1; /* used for enumeration arguments */
+
+ lset_t *seen = (lset_t *)base; /* seen flags are at the top of the struct */
+ lset_t f = LELEM(token - first); /* compute flag position of argument */
+
+ *assigned = FALSE;
+
+ DBG(DBG_CONTROLMORE,
+ DBG_log(" %s=%s", kw->entry->name, kw->value)
+ )
+
+ if (*seen & f)
+ {
+ plog("# duplicate '%s' option", kw->entry->name);
+ return FALSE;
+ }
+
+ /* set flag that this argument has been seen */
+ *seen |= f;
+
+ /* is there a keyword list? */
+ if (list != NULL && token_info[token].type != ARG_LST)
+ {
+ bool match = FALSE;
+
+ while (*list != NULL && !match)
+ {
+ index++;
+ match = streq(kw->value, *list++);
+ }
+ if (!match)
+ {
+ plog("# bad value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ }
+
+ switch (token_info[token].type)
+ {
+ case ARG_NONE:
+ plog("# option '%s' not supported yet", kw->entry->name);
+ return FALSE;
+ case ARG_ENUM:
+ {
+ int *i = (int *)p;
+
+ if (index < 0)
+ {
+ plog("# bad enumeration value: %s=%s (%d)"
+ , kw->entry->name, kw->value, index);
+ return FALSE;
+ }
+ *i = index;
+ }
+ break;
+
+ case ARG_UINT:
+ {
+ char *endptr;
+ u_int *u = (u_int *)p;
+
+ *u = strtoul(kw->value, &endptr, 10);
+
+ if (*endptr != '\0')
+ {
+ plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ }
+ break;
+ case ARG_ULNG:
+ case ARG_PCNT:
+ {
+ char *endptr;
+ unsigned long *l = (unsigned long *)p;
+
+ *l = strtoul(kw->value, &endptr, 10);
+
+ if (token_info[token].type == ARG_ULNG)
+ {
+ if (*endptr != '\0')
+ {
+ plog("# bad integer value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ }
+ else
+ {
+ if ((*endptr != '%') || (endptr[1] != '\0') || endptr == kw->value)
+ {
+ plog("# bad percent value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ }
+
+ }
+ break;
+ case ARG_TIME:
+ {
+ char *endptr;
+ time_t *t = (time_t *)p;
+
+ *t = strtoul(kw->value, &endptr, 10);
+
+ /* time in seconds? */
+ if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0'))
+ break;
+
+ if (endptr[1] == '\0')
+ {
+ if (*endptr == 'm') /* time in minutes? */
+ {
+ *t *= 60;
+ break;
+ }
+ if (*endptr == 'h') /* time in hours? */
+ {
+ *t *= 3600;
+ break;
+ }
+ if (*endptr == 'd') /* time in days? */
+ {
+ *t *= 3600*24;
+ break;
+ }
+ }
+ plog("# bad duration value: %s=%s", kw->entry->name, kw->value);
+ return FALSE;
+ }
+ case ARG_STR:
+ {
+ char **cp = (char **)p;
+
+ /* free any existing string */
+ pfreeany(*cp);
+
+ /* assign the new string */
+ *cp = clone_str(kw->value, "str_value");
+ }
+ break;
+ case ARG_LST:
+ {
+ char ***listp = (char ***)p;
+
+ /* free any existing list */
+ if (*listp != NULL)
+ free_list(*listp);
+
+ /* create a new list and assign values */
+ *listp = new_list(kw->value);
+
+ /* is there a keyword list? */
+ if (list != NULL)
+ {
+ char ** lst;
+
+ for (lst = *listp; lst && *lst; lst++)
+ {
+ bool match = FALSE;
+
+ list = token_info[token].list;
+
+ while (*list != NULL && !match)
+ {
+ match = streq(*lst, *list++);
+ }
+ if (!match)
+ {
+ plog("# bad value: %s=%s", kw->entry->name, *lst);
+ return FALSE;
+ }
+ }
+ }
+ }
+ default:
+ return TRUE;
+ }
+
+ *assigned = TRUE;
+ return TRUE;
+}
+
+/*
+ * frees all dynamically allocated arguments in a struct
+ */
+void
+free_args(kw_token_t first, kw_token_t last, char *base)
+{
+ kw_token_t token;
+
+ for (token = first; token <= last; token++)
+ {
+ char *p = base + token_info[token].offset;
+
+ switch (token_info[token].type)
+ {
+ case ARG_STR:
+ {
+ char **cp = (char **)p;
+
+ pfreeany(*cp);
+ *cp = NULL;
+ }
+ break;
+ case ARG_LST:
+ {
+ char ***listp = (char ***)p;
+
+ if (*listp != NULL)
+ {
+ free_list(*listp);
+ *listp = NULL;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * clone all dynamically allocated arguments in a struct
+ */
+void
+clone_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
+{
+ kw_token_t token;
+
+ for (token = first; token <= last; token++)
+ {
+ if (token_info[token].type == ARG_STR)
+ {
+ char **cp1 = (char **)(base1 + token_info[token].offset);
+ char **cp2 = (char **)(base2 + token_info[token].offset);
+
+ *cp1 = clone_str(*cp2, "cloned str");
+ }
+ }
+}
+
+static bool
+cmp_list(char **list1, char **list2)
+{
+ if ((list1 == NULL) && (list2 == NULL))
+ return TRUE;
+ if ((list1 == NULL) || (list2 == NULL))
+ return FALSE;
+
+ for ( ; *list1 && *list2; list1++, list2++)
+ {
+ if (strcmp(*list1,*list2) != 0)
+ return FALSE;
+ }
+
+ if ((*list1 != NULL) || (*list2 != NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * compare all arguments in a struct
+ */
+bool
+cmp_args(kw_token_t first, kw_token_t last, char *base1, char *base2)
+{
+ kw_token_t token;
+
+ for (token = first; token <= last; token++)
+ {
+ char *p1 = base1 + token_info[token].offset;
+ char *p2 = base2 + token_info[token].offset;
+
+ switch (token_info[token].type)
+ {
+ case ARG_ENUM:
+ {
+ int *i1 = (int *)p1;
+ int *i2 = (int *)p2;
+
+ if (*i1 != *i2)
+ return FALSE;
+ }
+ break;
+ case ARG_UINT:
+ {
+ u_int *u1 = (u_int *)p1;
+ u_int *u2 = (u_int *)p2;
+
+ if (*u1 != *u2)
+ return FALSE;
+ }
+ break;
+ case ARG_ULNG:
+ case ARG_PCNT:
+ {
+ unsigned long *l1 = (unsigned long *)p1;
+ unsigned long *l2 = (unsigned long *)p2;
+
+ if (*l1 != *l2)
+ return FALSE;
+ }
+ break;
+ case ARG_TIME:
+ {
+ time_t *t1 = (time_t *)p1;
+ time_t *t2 = (time_t *)p2;
+
+ if (*t1 != *t2)
+ return FALSE;
+ }
+ break;
+ case ARG_STR:
+ {
+ char **cp1 = (char **)p1;
+ char **cp2 = (char **)p2;
+
+ if (*cp1 == NULL && *cp2 == NULL)
+ break;
+ if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0)
+ return FALSE;
+ }
+ break;
+ case ARG_LST:
+ {
+ char ***listp1 = (char ***)p1;
+ char ***listp2 = (char ***)p2;
+
+ if (!cmp_list(*listp1, *listp2))
+ return FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return TRUE;
+}
diff --git a/programs/starter/args.h b/programs/starter/args.h
new file mode 100644
index 000000000..302e9bb7b
--- /dev/null
+++ b/programs/starter/args.h
@@ -0,0 +1,34 @@
+/* automatic handling of confread struct arguments
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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: args.h,v 1.3 2006/01/13 18:02:02 as Exp $
+ */
+
+#ifndef _ARGS_H_
+#define _ARGS_H_
+
+#include "keywords.h"
+#include "parser.h"
+
+extern char **new_list(char *value);
+extern bool assign_arg(kw_token_t token, kw_token_t first, kw_list_t *kw
+ , char *base, bool *assigned);
+extern void free_args(kw_token_t first, kw_token_t last, char *base);
+extern void clone_args(kw_token_t first, kw_token_t last, char *base1
+ , char *base2);
+extern bool cmp_args(kw_token_t first, kw_token_t last, char *base1
+ , char *base2);
+
+#endif /* _ARGS_H_ */
+
diff --git a/programs/starter/cmp.c b/programs/starter/cmp.c
new file mode 100644
index 000000000..9222bf58f
--- /dev/null
+++ b/programs/starter/cmp.c
@@ -0,0 +1,105 @@
+/* strongSwan IPsec starter comparison functions
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: cmp.c,v 1.12 2006/01/13 18:03:25 as Exp $
+ */
+
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+
+#include "confread.h"
+#include "args.h"
+#include "interfaces.h"
+#include "cmp.h"
+
+#define VARCMP(obj) if (c1->obj != c2->obj) return FALSE
+#define ADDCMP(obj) if (!sameaddr(&c1->obj,&c2->obj)) return FALSE
+#define SUBCMP(obj) if (!samesubnet(&c1->obj,&c2->obj)) return FALSE
+
+static bool
+starter_cmp_end(starter_end_t *c1, starter_end_t *c2)
+{
+ if ((c1 == NULL) || (c2 == NULL))
+ return FALSE;
+
+ ADDCMP(addr);
+ ADDCMP(nexthop);
+ ADDCMP(srcip);
+ SUBCMP(subnet);
+ VARCMP(has_client);
+ VARCMP(has_client_wildcard);
+ VARCMP(has_port_wildcard);
+ VARCMP(has_srcip);
+ VARCMP(modecfg);
+ VARCMP(port);
+ VARCMP(protocol);
+
+ return cmp_args(KW_END_FIRST, KW_END_LAST, (char *)c1, (char *)c2);
+ }
+
+bool
+starter_cmp_conn(starter_conn_t *c1, starter_conn_t *c2)
+{
+ if ((c1 == NULL) || (c2 == NULL))
+ return FALSE;
+
+ VARCMP(policy);
+ VARCMP(addr_family);
+ VARCMP(tunnel_addr_family);
+
+ if (!starter_cmp_end(&c1->left, &c2->left))
+ return FALSE;
+ if (!starter_cmp_end(&c1->right, &c2->right))
+ return FALSE;
+
+ return cmp_args(KW_CONN_NAME, KW_CONN_LAST, (char *)c1, (char *)c2);
+}
+
+bool
+starter_cmp_ca(starter_ca_t *c1, starter_ca_t *c2)
+{
+ if (c1 == NULL || c2 == NULL)
+ return FALSE;
+
+ return cmp_args(KW_CA_NAME, KW_CA_LAST, (char *)c1, (char *)c2);
+}
+
+bool
+starter_cmp_klips(starter_config_t *c1, starter_config_t *c2)
+{
+ if ((c1 == NULL) || (c2 == NULL))
+ return FALSE;
+
+ return cmp_args(KW_KLIPS_FIRST, KW_KLIPS_LAST, (char *)c1, (char *)c2);
+}
+
+bool
+starter_cmp_pluto(starter_config_t *c1, starter_config_t *c2)
+{
+ if ((c1 == NULL) || (c2 == NULL))
+ return FALSE;
+
+ return cmp_args(KW_PLUTO_FIRST, KW_PLUTO_LAST, (char *)c1, (char *)c2);
+}
+
+bool
+starter_cmp_defaultroute(defaultroute_t *d1, defaultroute_t *d2)
+{
+ if ((d1 == NULL) || (d2 == NULL))
+ return FALSE;
+ return memcmp(d1, d2, sizeof(defaultroute_t)) == 0;
+}
diff --git a/programs/starter/cmp.h b/programs/starter/cmp.h
new file mode 100644
index 000000000..ca355e9eb
--- /dev/null
+++ b/programs/starter/cmp.h
@@ -0,0 +1,29 @@
+/* strongSwan IPsec starter comparison functions
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: cmp.h,v 1.4 2006/01/06 20:24:41 as Exp $
+ */
+
+#ifndef _STARTER_CMP_H_
+#define _STARTER_CMP_H_
+
+#include "interfaces.h"
+
+extern bool starter_cmp_conn(starter_conn_t *c1, starter_conn_t *c2);
+extern bool starter_cmp_ca(starter_ca_t *c1, starter_ca_t *c2);
+extern bool starter_cmp_klips(starter_config_t *c1, starter_config_t *c2);
+extern bool starter_cmp_pluto(starter_config_t *c1, starter_config_t *c2);
+extern bool starter_cmp_defaultroute(defaultroute_t *d1, defaultroute_t *d2);
+
+#endif
+
diff --git a/programs/starter/confread.c b/programs/starter/confread.c
new file mode 100644
index 000000000..cf12d05ca
--- /dev/null
+++ b/programs/starter/confread.c
@@ -0,0 +1,861 @@
+/* strongSwan IPsec config file parser
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: confread.c,v 1.37 2006/04/17 19:35:07 as Exp $
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "keywords.h"
+#include "parser.h"
+#include "confread.h"
+#include "args.h"
+#include "interfaces.h"
+
+static const char ike_defaults[] = "3des-sha, 3des-md5";
+static const char esp_defaults[] = "3des-sha1, 3des-md5";
+
+static const char firewall_defaults[] = "ipsec _updown iptables";
+
+static void
+default_values(starter_config_t *cfg)
+{
+ if (cfg == NULL)
+ return;
+
+ memset(cfg, 0, sizeof(struct starter_config));
+
+ /* is there enough space for all seen flags? */
+ assert(KW_SETUP_LAST - KW_SETUP_FIRST <
+ sizeof(cfg->setup.seen) * BITS_PER_BYTE);
+ assert(KW_CONN_LAST - KW_CONN_FIRST <
+ sizeof(cfg->conn_default.seen) * BITS_PER_BYTE);
+ assert(KW_END_LAST - KW_END_FIRST <
+ sizeof(cfg->conn_default.right.seen) * BITS_PER_BYTE);
+ assert(KW_CA_LAST - KW_CA_FIRST <
+ sizeof(cfg->ca_default.seen) * BITS_PER_BYTE);
+
+ cfg->setup.seen = LEMPTY;
+ cfg->setup.fragicmp = TRUE;
+ cfg->setup.hidetos = TRUE;
+ cfg->setup.uniqueids = TRUE;
+ cfg->setup.interfaces = new_list("%defaultroute");
+
+ cfg->conn_default.seen = LEMPTY;
+ cfg->conn_default.startup = STARTUP_NO;
+ cfg->conn_default.state = STATE_IGNORE;
+ cfg->conn_default.policy = POLICY_ENCRYPT | POLICY_TUNNEL | POLICY_RSASIG
+ | POLICY_PFS;
+
+ cfg->conn_default.ike = clone_str(ike_defaults, "ike_defaults");
+ cfg->conn_default.esp = clone_str(esp_defaults, "esp_defaults");
+ cfg->conn_default.sa_ike_life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT;
+ cfg->conn_default.sa_ipsec_life_seconds = PLUTO_SA_LIFE_DURATION_DEFAULT;
+ cfg->conn_default.sa_rekey_margin = SA_REPLACEMENT_MARGIN_DEFAULT;
+ cfg->conn_default.sa_rekey_fuzz = SA_REPLACEMENT_FUZZ_DEFAULT;
+ cfg->conn_default.sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT;
+ cfg->conn_default.addr_family = AF_INET;
+ cfg->conn_default.tunnel_addr_family = AF_INET;
+
+ cfg->conn_default.left.seen = LEMPTY;
+ cfg->conn_default.right.seen = LEMPTY;
+
+ anyaddr(AF_INET, &cfg->conn_default.left.addr);
+ anyaddr(AF_INET, &cfg->conn_default.left.nexthop);
+ anyaddr(AF_INET, &cfg->conn_default.left.srcip);
+ anyaddr(AF_INET, &cfg->conn_default.right.addr);
+ anyaddr(AF_INET, &cfg->conn_default.right.nexthop);
+ anyaddr(AF_INET, &cfg->conn_default.right.srcip);
+
+ cfg->ca_default.seen = LEMPTY;
+}
+
+#define KW_POLICY_FLAG(sy, sn, fl) \
+ if (streq(kw->value, sy)) { conn->policy |= fl; } \
+ else if (streq(kw->value, sn)) { conn->policy &= ~fl; } \
+ else { plog("# bad policy value: %s=%s", kw->entry->name, kw->value); cfg->err++; }
+
+static void
+load_setup(starter_config_t *cfg, config_parsed_t *cfgp)
+{
+ kw_list_t *kw;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Loading config setup")
+ )
+
+ for (kw = cfgp->config_setup; kw; kw = kw->next)
+ {
+ bool assigned = FALSE;
+
+ kw_token_t token = kw->entry->token;
+
+ if (token < KW_SETUP_FIRST || token > KW_SETUP_LAST)
+ {
+ plog("# unsupported keyword '%s' in config setup", kw->entry->name);
+ cfg->err++;
+ continue;
+ }
+
+ if (!assign_arg(token, KW_SETUP_FIRST, kw, (char *)cfg, &assigned))
+ {
+ plog(" bad argument value in config setup");
+ cfg->err++;
+ continue;
+ }
+ }
+}
+
+static void
+kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token
+ , kw_list_t *kw, char *conn_name, starter_config_t *cfg)
+{
+ err_t ugh = NULL;
+ bool assigned = FALSE;
+ int has_port_wildcard; /* set if port is %any */
+
+ char *name = kw->entry->name;
+ char *value = kw->value;
+
+ if (!assign_arg(token, KW_END_FIRST, kw, (char *)end, &assigned))
+ goto err;
+
+ if (token == KW_SENDCERT)
+ {
+ if (end->sendcert == CERT_YES_SEND)
+ end->sendcert = CERT_ALWAYS_SEND;
+ else if (end->sendcert == CERT_NO_SEND)
+ end->sendcert = CERT_NEVER_SEND;
+ }
+
+ if (assigned)
+ return;
+
+ switch (token)
+ {
+ case KW_HOST:
+ if (streq(value, "%defaultroute"))
+ {
+ if (cfg->defaultroute.defined)
+ {
+ end->addr = cfg->defaultroute.addr;
+ end->nexthop = cfg->defaultroute.nexthop;
+ }
+ else
+ {
+ plog("# default route not known: %s=%s", name, value);
+ goto err;
+ }
+ }
+ else if (streq(value,"%any"))
+ {
+ anyaddr(conn->addr_family, &end->addr);
+ }
+ else if (value[0] == '%')
+ {
+ if (end->iface)
+ pfree(end->iface);
+ end->iface = clone_str(value+1, "iface");
+ if (starter_iface_find(end->iface, conn->addr_family, &end->addr,
+ &end->nexthop) == -1)
+ {
+ conn->state = STATE_INVALID;
+ }
+ }
+ else
+ {
+ ugh = ttoaddr(value, 0, conn->addr_family, &end->addr);
+ if (ugh != NULL)
+ {
+ plog("# bad addr: %s=%s [%s]", name, value, ugh);
+ goto err;
+ }
+ }
+ break;
+ case KW_NEXTHOP:
+ if (streq(value, "%defaultroute"))
+ {
+ if (cfg->defaultroute.defined)
+ end->nexthop = cfg->defaultroute.nexthop;
+ else
+ {
+ plog("# default route not known: %s=%s", name, value);
+ goto err;
+ }
+ }
+ else if (streq(value, "%direct"))
+ ugh = anyaddr(conn->addr_family, &end->nexthop);
+ else
+ ugh = ttoaddr(value, 0, conn->addr_family, &end->nexthop);
+
+ if (ugh != NULL)
+ {
+ plog("# bad addr: %s=%s [%s]", name, value, ugh);
+ goto err;
+ }
+ break;
+ case KW_SUBNET:
+ if ((strlen(value) >= 6 && strncmp(value,"vhost:",6) == 0)
+ || (strlen(value) >= 5 && strncmp(value,"vnet:",5) == 0))
+ {
+ end->virt = clone_str(value, "virt");
+ }
+ else
+ {
+ end->has_client = TRUE;
+ ugh = ttosubnet(value, 0, conn->tunnel_addr_family, &end->subnet);
+ if (ugh != NULL)
+ {
+ plog("# bad subnet: %s=%s [%s]", name, value, ugh);
+ goto err;
+ }
+ }
+ break;
+ case KW_SUBNETWITHIN:
+ end->has_client = TRUE;
+ end->has_client_wildcard = TRUE;
+ ugh = ttosubnet(value, 0, conn->tunnel_addr_family, &end->subnet);
+ break;
+ case KW_PROTOPORT:
+ ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &has_port_wildcard);
+ end->has_port_wildcard = has_port_wildcard;
+ break;
+ case KW_SOURCEIP:
+ if (streq(value, "%modeconfig") || streq(value, "%modecfg"))
+ {
+ end->modecfg = TRUE;
+ }
+ else
+ {
+ ugh = ttoaddr(value, 0, conn->addr_family, &end->srcip);
+ if (ugh != NULL)
+ {
+ plog("# bad addr: %s=%s [%s]", name, value, ugh);
+ goto err;
+ }
+ end->has_srcip = TRUE;
+ }
+ conn->policy |= POLICY_TUNNEL;
+ break;
+ default:
+ break;
+ }
+ return;
+
+err:
+ plog(" bad argument value in conn '%s'", conn_name);
+ cfg->err++;
+}
+
+/*
+ * handles left|rightfirewall and left|rightupdown parameters
+ */
+static void
+handle_firewall( const char *label, starter_end_t *end, starter_config_t *cfg)
+{
+ if (end->firewall && (end->seen & LELEM(KW_FIREWALL - KW_END_FIRST)))
+ {
+ if (end->updown != NULL)
+ {
+ plog("# cannot have both %sfirewall and %supdown", label, label);
+ cfg->err++;
+ }
+ else
+ {
+ end->updown = clone_str(firewall_defaults, "firewall_defaults");
+ end->firewall = FALSE;
+ }
+ }
+}
+
+/*
+ * parse a conn section
+ */
+static void
+load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg)
+{
+ char *conn_name = (conn->name == NULL)? "%default":conn->name;
+
+ for ( ; kw; kw = kw->next)
+ {
+ bool assigned = FALSE;
+
+ kw_token_t token = kw->entry->token;
+
+ if (token >= KW_LEFT_FIRST && token <= KW_LEFT_LAST)
+ {
+ kw_end(conn, &conn->left, token - KW_LEFT_FIRST + KW_END_FIRST
+ , kw, conn_name, cfg);
+ continue;
+ }
+ else if (token >= KW_RIGHT_FIRST && token <= KW_RIGHT_LAST)
+ {
+ kw_end(conn, &conn->right, token - KW_RIGHT_FIRST + KW_END_FIRST
+ , kw, conn_name, cfg);
+ continue;
+ }
+
+ if (token == KW_AUTO)
+ {
+ token = KW_CONN_SETUP;
+ }
+ else if (token == KW_ALSO)
+ {
+ if (cfg->parse_also)
+ {
+ also_t *also = alloc_thing(also_t, "also_t");
+
+ also->name = clone_str(kw->value, "also");
+ also->next = conn->also;
+ conn->also = also;
+
+ DBG(DBG_CONTROL,
+ DBG_log(" also=%s", kw->value)
+ )
+ }
+ continue;
+ }
+
+ if (token < KW_CONN_FIRST || token > KW_CONN_LAST)
+ {
+ plog("# unsupported keyword '%s' in conn '%s'"
+ , kw->entry->name, conn_name);
+ cfg->err++;
+ continue;
+ }
+
+ if (!assign_arg(token, KW_CONN_FIRST, kw, (char *)conn, &assigned))
+ {
+ plog(" bad argument value in conn '%s'", conn_name);
+ cfg->err++;
+ continue;
+ }
+
+ if (assigned)
+ continue;
+
+ switch (token)
+ {
+ case KW_TYPE:
+ conn->policy &= ~(POLICY_TUNNEL | POLICY_SHUNT_MASK);
+ if (streq(kw->value, "tunnel"))
+ conn->policy |= POLICY_TUNNEL;
+ else if (streq(kw->value, "passthrough") || streq(kw->value, "pass"))
+ conn->policy |= POLICY_SHUNT_PASS;
+ else if (streq(kw->value, "drop"))
+ conn->policy |= POLICY_SHUNT_DROP;
+ else if (streq(kw->value, "reject"))
+ conn->policy |= POLICY_SHUNT_REJECT;
+ else if (strcmp(kw->value, "transport") != 0)
+ {
+ plog("# bad policy value: %s=%s", kw->entry->name, kw->value);
+ cfg->err++;
+ }
+ break;
+ case KW_PFS:
+ KW_POLICY_FLAG("yes", "no", POLICY_PFS)
+ break;
+ case KW_COMPRESS:
+ KW_POLICY_FLAG("yes", "no", POLICY_COMPRESS)
+ break;
+ case KW_AUTH:
+ KW_POLICY_FLAG("ah", "esp", POLICY_AUTHENTICATE)
+ break;
+ case KW_AUTHBY:
+ conn->policy &= ~(POLICY_RSASIG | POLICY_PSK | POLICY_ENCRYPT);
+
+ if (strcmp(kw->value, "never") != 0)
+ {
+ char *value = kw->value;
+ char *second = strchr(kw->value, '|');
+
+ if (second != NULL)
+ *second = '\0';
+
+ /* also handles the cases secret|rsasig and rsasig|secret */
+ for (;;)
+ {
+ if (streq(value, "rsasig"))
+ conn->policy |= POLICY_RSASIG | POLICY_ENCRYPT;
+ else if (streq(value, "secret"))
+ conn->policy |= POLICY_PSK | POLICY_ENCRYPT;
+ else
+ {
+ plog("# bad policy value: %s=%s", kw->entry->name, kw->value);
+ cfg->err++;
+ break;
+ }
+ if (second == NULL)
+ break;
+ value = second;
+ second = NULL; /* traverse the loop no more than twice */
+ }
+ }
+ break;
+ case KW_REKEY:
+ KW_POLICY_FLAG("no", "yes", POLICY_DONT_REKEY)
+ break;
+ default:
+ break;
+ }
+ }
+ handle_firewall("left", &conn->left, cfg);
+ handle_firewall("right", &conn->right, cfg);
+}
+
+/*
+ * initialize a conn object with the default conn
+ */
+static void
+conn_default(char *name, starter_conn_t *conn, starter_conn_t *def)
+{
+ memcpy(conn, def, sizeof(starter_conn_t));
+ conn->name = clone_str(name, "conn name");
+
+ clone_args(KW_CONN_FIRST, KW_CONN_LAST
+ , (char *)conn, (char *)def);
+ clone_args(KW_END_FIRST, KW_END_LAST
+ , (char *)&conn->left, (char *)&def->left);
+ clone_args(KW_END_FIRST, KW_END_LAST
+ , (char *)&conn->right, (char *)&def->right);
+}
+
+/*
+ * parse a ca section
+ */
+static void
+load_ca(starter_ca_t *ca, kw_list_t *kw, starter_config_t *cfg)
+{
+ char *ca_name = (ca->name == NULL)? "%default":ca->name;
+
+ for ( ; kw; kw = kw->next)
+ {
+ bool assigned = FALSE;
+
+ kw_token_t token = kw->entry->token;
+
+ if (token == KW_AUTO)
+ {
+ token = KW_CA_SETUP;
+ }
+ else if (token == KW_ALSO)
+ {
+ if (cfg->parse_also)
+ {
+ also_t *also = alloc_thing(also_t, "also_t");
+
+ also->name = clone_str(kw->value, "also");
+ also->next = ca->also;
+ ca->also = also;
+
+ DBG(DBG_CONTROL,
+ DBG_log(" also=%s", kw->value)
+ )
+ }
+ continue;
+ }
+
+ if (token < KW_CA_FIRST || token > KW_CA_LAST)
+ {
+ plog("# unsupported keyword '%s' in ca '%s'"
+ , kw->entry->name, ca_name);
+ cfg->err++;
+ continue;
+ }
+
+ if (!assign_arg(token, KW_CA_FIRST, kw, (char *)ca, &assigned))
+ {
+ plog(" bad argument value in ca '%s'", ca_name);
+ cfg->err++;
+ }
+ }
+
+ /* treat 'route' and 'start' as 'add' */
+ if (ca->startup != STARTUP_NO)
+ ca->startup = STARTUP_ADD;
+}
+
+/*
+ * initialize a ca object with the default ca
+ */
+static void
+ca_default(char *name, starter_ca_t *ca, starter_ca_t *def)
+{
+ memcpy(ca, def, sizeof(starter_ca_t));
+ ca->name = clone_str(name, "ca name");
+
+ clone_args(KW_CA_FIRST, KW_CA_LAST, (char *)ca, (char *)def);
+}
+
+static kw_list_t*
+find_also_conn(const char* name, starter_conn_t *conn, starter_config_t *cfg);
+
+static void
+load_also_conns(starter_conn_t *conn, also_t *also, starter_config_t *cfg)
+{
+ while (also != NULL)
+ {
+ kw_list_t *kw = find_also_conn(also->name, conn, cfg);
+
+ if (kw == NULL)
+ {
+ plog(" conn '%s' cannot include '%s'", conn->name, also->name);
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("conn '%s' includes '%s'", conn->name, also->name)
+ )
+ /* only load if no error occurred in the first round */
+ if (cfg->err == 0)
+ load_conn(conn, kw, cfg);
+ }
+ also = also->next;
+ }
+}
+
+/*
+ * find a conn included by also
+ */
+static kw_list_t*
+find_also_conn(const char* name, starter_conn_t *conn, starter_config_t *cfg)
+{
+ starter_conn_t *c = cfg->conn_first;
+
+ while (c != NULL)
+ {
+ if (streq(name, c->name))
+ {
+ if (conn->visit == c->visit)
+ {
+ plog("# detected also loop");
+ cfg->err++;
+ return NULL;
+ }
+ c->visit = conn->visit;
+ load_also_conns(conn, c->also, cfg);
+ return c->kw;
+ }
+ c = c->next;
+ }
+
+ plog("# also '%s' not found", name);
+ cfg->err++;
+ return NULL;
+}
+
+static kw_list_t*
+find_also_ca(const char* name, starter_ca_t *ca, starter_config_t *cfg);
+
+static void
+load_also_cas(starter_ca_t *ca, also_t *also, starter_config_t *cfg)
+{
+ while (also != NULL)
+ {
+ kw_list_t *kw = find_also_ca(also->name, ca, cfg);
+
+ if (kw == NULL)
+ {
+ plog(" ca '%s' cannot include '%s'", ca->name, also->name);
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("ca '%s' includes '%s'", ca->name, also->name)
+ )
+ /* only load if no error occurred in the first round */
+ if (cfg->err == 0)
+ load_ca(ca, kw, cfg);
+ }
+ also = also->next;
+ }
+}
+
+/*
+ * find a ca included by also
+ */
+static kw_list_t*
+find_also_ca(const char* name, starter_ca_t *ca, starter_config_t *cfg)
+{
+ starter_ca_t *c = cfg->ca_first;
+
+ while (c != NULL)
+ {
+ if (streq(name, c->name))
+ {
+ if (ca->visit == c->visit)
+ {
+ plog("# detected also loop");
+ cfg->err++;
+ return NULL;
+ }
+ c->visit = ca->visit;
+ load_also_cas(ca, c->also, cfg);
+ return c->kw;
+ }
+ c = c->next;
+ }
+
+ plog("# also '%s' not found", name);
+ cfg->err++;
+ return NULL;
+}
+
+
+
+/*
+ * load and parse an IPsec configuration file
+ */
+starter_config_t *
+confread_load(const char *file)
+{
+ starter_config_t *cfg = NULL;
+ config_parsed_t *cfgp;
+ section_list_t *sconn, *sca;
+ starter_conn_t *conn;
+ starter_ca_t *ca;
+
+ u_int visit = 0;
+
+ /* load IPSec configuration file */
+ cfgp = parser_load_conf(file);
+ if (!cfgp)
+ return NULL;
+
+ cfg = (starter_config_t *)alloc_thing(starter_config_t, "starter_config_t");
+
+ /* set default values */
+ default_values(cfg);
+
+ /* determine default route */
+ get_defaultroute(&cfg->defaultroute);
+
+ /* load config setup section */
+ load_setup(cfg, cfgp);
+
+ /* in the first round parse also statements */
+ cfg->parse_also = TRUE;
+
+ /* find %default ca section */
+ for (sca = cfgp->ca_first; sca; sca = sca->next)
+ {
+ if (streq(sca->name, "%default"))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("Loading ca %%default")
+ )
+ load_ca(&cfg->ca_default, sca->kw, cfg);
+ }
+ }
+
+ /* parameters defined in ca %default sections can be overloads */
+ cfg->ca_default.seen = LEMPTY;
+
+ /* load other ca sections */
+ for (sca = cfgp->ca_first; sca; sca = sca->next)
+ {
+ /* skip %default ca section */
+ if (streq(sca->name, "%default"))
+ continue;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Loading ca '%s'", sca->name)
+ )
+ ca = (starter_ca_t *)alloc_thing(starter_ca_t, "starter_ca_t");
+
+ ca_default(sca->name, ca, &cfg->ca_default);
+ ca->kw = sca->kw;
+ ca->next = NULL;
+
+ if (cfg->ca_last)
+ cfg->ca_last->next = ca;
+ cfg->ca_last = ca;
+ if (!cfg->ca_first)
+ cfg->ca_first = ca;
+
+ load_ca(ca, ca->kw, cfg);
+ }
+
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ also_t *also = ca->also;
+
+ while (also != NULL)
+ {
+ kw_list_t *kw = find_also_ca(also->name, cfg->ca_first, cfg);
+
+ load_ca(ca, kw, cfg);
+ also = also->next;
+ }
+
+ if (ca->startup != STARTUP_NO)
+ ca->state = STATE_TO_ADD;
+ }
+
+ /* find %default conn sections */
+ for (sconn = cfgp->conn_first; sconn; sconn = sconn->next)
+ {
+ if (streq(sconn->name, "%default"))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("Loading conn %%default")
+ )
+ load_conn(&cfg->conn_default, sconn->kw, cfg);
+ }
+ }
+
+ /* parameter defined in conn %default sections can be overloaded */
+ cfg->conn_default.seen = LEMPTY;
+ cfg->conn_default.right.seen = LEMPTY;
+ cfg->conn_default.left.seen = LEMPTY;
+
+ /* load other conn sections */
+ for (sconn = cfgp->conn_first; sconn; sconn = sconn->next)
+ {
+ /* skip %default conn section */
+ if (streq(sconn->name, "%default"))
+ continue;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Loading conn '%s'", sconn->name)
+ )
+ conn = (starter_conn_t *)alloc_thing(starter_conn_t, "starter_conn_t");
+
+ conn_default(sconn->name, conn, &cfg->conn_default);
+ conn->kw = sconn->kw;
+ conn->next = NULL;
+
+ if (cfg->conn_last)
+ cfg->conn_last->next = conn;
+ cfg->conn_last = conn;
+ if (!cfg->conn_first)
+ cfg->conn_first = conn;
+
+ load_conn(conn, conn->kw, cfg);
+ }
+
+ /* in the second round do not parse also statements */
+ cfg->parse_also = FALSE;
+
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ ca->visit = ++visit;
+ load_also_cas(ca, ca->also, cfg);
+
+ if (ca->startup != STARTUP_NO)
+ ca->state = STATE_TO_ADD;
+ }
+
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ conn->visit = ++visit;
+ load_also_conns(conn, conn->also, cfg);
+
+ if (conn->startup != STARTUP_NO)
+ conn->state = STATE_TO_ADD;
+ }
+
+ parser_free_conf(cfgp);
+
+ if (cfg->err)
+ {
+ plog("### %d parsing error%s ###", cfg->err, (cfg->err > 1)?"s":"");
+ confread_free(cfg);
+ cfg = NULL;
+ }
+
+ return cfg;
+}
+
+/*
+ * free the memory used by also_t objects
+ */
+static void
+free_also(also_t *head)
+{
+ while (head != NULL)
+ {
+ also_t *also = head;
+
+ head = also->next;
+ pfree(also->name);
+ pfree(also);
+ }
+}
+
+/*
+ * free the memory used by a starter_conn_t object
+ */
+static void
+confread_free_conn(starter_conn_t *conn)
+{
+ free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->left);
+ free_args(KW_END_FIRST, KW_END_LAST, (char *)&conn->right);
+ free_args(KW_CONN_NAME, KW_CONN_LAST, (char *)conn);
+ free_also(conn->also);
+}
+
+/*
+ * free the memory used by a starter_ca_t object
+ */
+static void
+confread_free_ca(starter_ca_t *ca)
+{
+ free_args(KW_CA_NAME, KW_CA_LAST, (char *)ca);
+ free_also(ca->also);
+}
+
+/*
+ * free the memory used by a starter_config_t object
+ */
+void
+confread_free(starter_config_t *cfg)
+{
+ starter_conn_t *conn = cfg->conn_first;
+ starter_ca_t *ca = cfg->ca_first;
+
+ free_args(KW_SETUP_FIRST, KW_SETUP_LAST, (char *)cfg);
+
+ confread_free_conn(&cfg->conn_default);
+
+ while (conn != NULL)
+ {
+ starter_conn_t *conn_aux = conn;
+
+ conn = conn->next;
+ confread_free_conn(conn_aux);
+ pfree(conn_aux);
+ }
+
+ confread_free_ca(&cfg->ca_default);
+
+ while (ca != NULL)
+ {
+ starter_ca_t *ca_aux = ca;
+
+ ca = ca->next;
+ confread_free_ca(ca_aux);
+ pfree(ca_aux);
+ }
+
+ pfree(cfg);
+}
diff --git a/programs/starter/confread.h b/programs/starter/confread.h
new file mode 100644
index 000000000..a3b1b7379
--- /dev/null
+++ b/programs/starter/confread.h
@@ -0,0 +1,199 @@
+/* strongSwan IPsec config file parser
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: confread.h,v 1.23 2006/04/17 10:32:36 as Exp $
+ */
+
+#ifndef _IPSEC_CONFREAD_H_
+#define _IPSEC_CONFREAD_H_
+
+#ifndef _FREESWAN_H
+#include <freeswan.h>
+#include "../pluto/constants.h"
+#endif
+
+#include "parser.h"
+#include "interfaces.h"
+
+typedef enum {
+ STARTUP_NO,
+ STARTUP_ADD,
+ STARTUP_ROUTE,
+ STARTUP_START
+} startup_t;
+
+typedef enum {
+ STATE_IGNORE,
+ STATE_TO_ADD,
+ STATE_ADDED,
+ STATE_REPLACED,
+ STATE_INVALID
+} starter_state_t;
+
+typedef struct starter_end starter_end_t;
+
+struct starter_end {
+ lset_t seen;
+ char *id;
+ char *rsakey;
+ char *cert;
+ char *ca;
+ char *groups;
+ char *iface;
+ ip_address addr;
+ ip_address nexthop;
+ ip_address srcip;
+ ip_subnet subnet;
+ bool has_client;
+ bool has_client_wildcard;
+ bool has_port_wildcard;
+ bool has_srcip;
+ bool modecfg;
+ certpolicy_t sendcert;
+ bool firewall;
+ bool hostaccess;
+ char *updown;
+ u_int16_t port;
+ u_int8_t protocol;
+#ifdef VIRTUAL_IP
+ char *virt;
+#endif
+};
+
+typedef struct also also_t;
+
+struct also {
+ char *name;
+ bool included;
+ also_t *next;
+};
+
+typedef struct starter_conn starter_conn_t;
+
+struct starter_conn {
+ lset_t seen;
+ char *name;
+ also_t *also;
+ kw_list_t *kw;
+ u_int visit;
+ startup_t startup;
+ starter_state_t state;
+
+ int keyexchange;
+ lset_t policy;
+ time_t sa_ike_life_seconds;
+ time_t sa_ipsec_life_seconds;
+ time_t sa_rekey_margin;
+ unsigned long sa_keying_tries;
+ unsigned long sa_rekey_fuzz;
+ sa_family_t addr_family;
+ sa_family_t tunnel_addr_family;
+
+ starter_end_t left, right;
+
+ unsigned long id;
+
+ char *esp;
+ char *ike;
+ char *pfsgroup;
+
+ time_t dpd_delay;
+ time_t dpd_timeout;
+ dpd_action_t dpd_action;
+ int dpd_count;
+
+ starter_conn_t *next;
+};
+
+typedef struct starter_ca starter_ca_t;
+
+struct starter_ca {
+ lset_t seen;
+ char *name;
+ also_t *also;
+ kw_list_t *kw;
+ u_int visit;
+ startup_t startup;
+ starter_state_t state;
+
+ char *cacert;
+ char *ldaphost;
+ char *ldapbase;
+ char *crluri;
+ char *crluri2;
+ char *ocspuri;
+
+ bool strict;
+
+ starter_ca_t *next;
+};
+
+typedef struct starter_config starter_config_t;
+
+struct starter_config {
+ struct {
+ lset_t seen;
+ char **interfaces;
+ char *dumpdir;
+
+ /* pluto keywords */
+ char **plutodebug;
+ char *prepluto;
+ char *postpluto;
+ bool uniqueids;
+ u_int overridemtu;
+ u_int crlcheckinterval;
+ bool cachecrls;
+ bool strictcrlpolicy;
+ bool nocrsend;
+ bool nat_traversal;
+ u_int keep_alive;
+ char *virtual_private;
+ char *pkcs11module;
+ bool pkcs11keepstate;
+ bool pkcs11proxy;
+
+ /* KLIPS keywords */
+ char **klipsdebug;
+ bool fragicmp;
+ char *packetdefault;
+ bool hidetos;
+ } setup;
+
+ /* information about the default route */
+ defaultroute_t defaultroute;
+
+ /* number of encountered parsing errors */
+ u_int err;
+
+ /* do we parse also statements */
+ bool parse_also;
+
+ /* ca %default */
+ starter_ca_t ca_default;
+
+ /* connections list (without %default) */
+ starter_ca_t *ca_first, *ca_last;
+
+ /* conn %default */
+ starter_conn_t conn_default;
+
+ /* connections list (without %default) */
+ starter_conn_t *conn_first, *conn_last;
+};
+
+extern starter_config_t *confread_load(const char *file);
+extern void confread_free(starter_config_t *cfg);
+
+#endif /* _IPSEC_CONFREAD_H_ */
+
diff --git a/programs/starter/exec.c b/programs/starter/exec.c
new file mode 100644
index 000000000..98541db75
--- /dev/null
+++ b/programs/starter/exec.c
@@ -0,0 +1,54 @@
+/* strongSwan IPsec exec helper function
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: exec.c,v 1.4 2006/01/04 23:30:24 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "exec.h"
+
+#define BUF_SIZE 2048
+
+/**
+ * TODO:
+ * o log stdout with LOG_LEVEL_INFO and stderr with LOG_LEVEL_ERR
+ */
+
+int
+starter_exec(const char *fmt, ...)
+{
+ va_list args;
+ static char buf[BUF_SIZE];
+ int r;
+
+ va_start (args, fmt);
+ vsnprintf(buf, BUF_SIZE-1, fmt, args);
+ buf[BUF_SIZE - 1] = '\0';
+ va_end(args);
+ r = system(buf);
+ DBG(DBG_CONTROL,
+ DBG_log("starter_exec(%s) = %d", buf, r)
+ )
+ return r;
+}
+
diff --git a/programs/starter/exec.h b/programs/starter/exec.h
new file mode 100644
index 000000000..d4be931dd
--- /dev/null
+++ b/programs/starter/exec.h
@@ -0,0 +1,23 @@
+/* strongSwan IPsec starter exec helper function
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: exec.h,v 1.2 2005/12/28 10:20:32 as Exp $
+ */
+
+#ifndef _STARTER_EXEC_H_
+#define _STARTER_EXEC_H_
+
+extern int starter_exec (const char *fmt, ...);
+
+#endif /* _STARTER_EXEC_H_ */
+
diff --git a/programs/starter/files.h b/programs/starter/files.h
new file mode 100644
index 000000000..286cdf105
--- /dev/null
+++ b/programs/starter/files.h
@@ -0,0 +1,47 @@
+/* strongSwan file locations
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: files.h,v 1.5 2006/02/04 18:52:58 as Exp $
+ */
+
+#ifndef _STARTER_FILES_H_
+#define _STARTER_FILES_H_
+
+#ifndef DEFAULT_CTLBASE
+#define DEFAULT_CTLBASE "/var/run/pluto"
+#endif
+#define CTL_SUFFIX ".ctl"
+#define PID_SUFFIX ".pid"
+
+#define MY_PID_FILE "/var/run/starter.pid"
+
+#define DEV_RANDOM "/dev/random"
+#define DEV_URANDOM "/dev/urandom"
+
+#define PROC_NETKEY "/proc/net/pfkey"
+#define PROC_IPSECVERSION "/proc/net/ipsec_version"
+#define PROC_SYSFLAGS "/proc/sys/net/ipsec"
+#define PROC_MODULES "/proc/modules"
+
+#define CONFIG_FILE IPSEC_CONFDIR"/ipsec.conf"
+#define SECRETS_FILE IPSEC_CONFDIR"/ipsec.secrets"
+
+#define PLUTO_CMD IPSEC_EXECDIR"/pluto"
+#define CTL_FILE DEFAULT_CTLBASE CTL_SUFFIX
+#define PID_FILE DEFAULT_CTLBASE PID_SUFFIX
+
+#define DYNIP_DIR "/var/run/dynip"
+#define INFO_FILE "/var/run/ipsec.info"
+
+#endif /* _STARTER_FILES_H_ */
+
diff --git a/programs/starter/interfaces.c b/programs/starter/interfaces.c
new file mode 100644
index 000000000..9926ea059
--- /dev/null
+++ b/programs/starter/interfaces.c
@@ -0,0 +1,595 @@
+/* strongSwan IPsec interfaces management
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: interfaces.c,v 1.15 2006/02/05 10:51:55 as Exp $
+ */
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_tunnel.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "interfaces.h"
+#include "exec.h"
+#include "files.h"
+
+#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) )
+
+#define N_IPSEC_IF 4
+
+struct st_ipsec_if {
+ char name[IFNAMSIZ];
+ char phys[IFNAMSIZ];
+ int up;
+};
+
+static struct st_ipsec_if _ipsec_if[N_IPSEC_IF];
+
+static char *
+_find_physical_iface(int sock, char *iface)
+{
+ static char _if[IFNAMSIZ];
+ char *b;
+ struct ifreq req;
+ FILE *fd;
+ char line[BUF_LEN];
+
+ strncpy(req.ifr_name, iface, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req)==0)
+ {
+ if (req.ifr_flags & IFF_UP)
+ {
+ strncpy(_if, iface, IFNAMSIZ);
+ return _if;
+ }
+ }
+ else
+ {
+ /* If there is a file named /var/run/dynip/<iface>, look if we
+ * can get interface name from there (IP_PHYS)
+ */
+ b = (char *)alloc_bytes(strlen(DYNIP_DIR) + strlen(iface) + 10, "iface");
+ if (b)
+ {
+ sprintf(b, "%s/%s", DYNIP_DIR, iface);
+ fd = fopen(b, "r");
+ pfree(b);
+ if (fd)
+ {
+ memset(_if, 0, sizeof(_if));
+ memset(line, 0, sizeof(line));
+ while (fgets(line, sizeof(line), fd) != 0)
+ {
+ if ((strncmp(line,"IP_PHYS=\"", 9) == 0)
+ && (line[strlen(line) - 2] == '"')
+ && (line[strlen(line) - 1] == '\n'))
+ {
+ strncpy(_if, line + 9, MIN(strlen(line) - 11, IFNAMSIZ));
+ break;
+ }
+ else if ((strncmp(line,"IP_PHYS=", 8) == 0)
+ && (line[8] != '"')
+ && (line[strlen(line) - 1] == '\n'))
+ {
+ strncpy(_if, line + 8, MIN(strlen(line) - 9, IFNAMSIZ));
+ break;
+ }
+ }
+ fclose(fd);
+
+ if (*_if)
+ {
+ strncpy(req.ifr_name, _if, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req) == 0)
+ {
+ if (req.ifr_flags & IFF_UP)
+ return _if;
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+int
+starter_iface_find(char *iface, int af, ip_address *dst, ip_address *nh)
+{
+ char *phys;
+ struct ifreq req;
+ struct sockaddr_in *sa = (struct sockaddr_in *)(&req.ifr_addr);
+ int sock;
+
+ if (!iface)
+ return -1;
+
+ sock = socket(af, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return -1;
+
+ phys = _find_physical_iface(sock, iface);
+ if (!phys)
+ goto failed;
+
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req)!=0)
+ goto failed;
+ if (!(req.ifr_flags & IFF_UP))
+ goto failed;
+
+ if ((req.ifr_flags & IFF_POINTOPOINT)
+ && nh
+ && ioctl(sock, SIOCGIFDSTADDR, &req) == 0)
+ {
+ if (sa->sin_family == af)
+ initaddr((const void *)&sa->sin_addr, sizeof(struct in_addr), af, nh);
+ }
+ if ((dst) && (ioctl(sock, SIOCGIFADDR, &req) == 0))
+ {
+ if (sa->sin_family == af)
+ initaddr((const void *)&sa->sin_addr, sizeof(struct in_addr), af, dst);
+ }
+ close(sock);
+ return 0;
+
+failed:
+ close(sock);
+ return -1;
+}
+
+static int
+valid_str(char *str, unsigned int *pn, char **pphys
+, defaultroute_t *defaultroute)
+{
+ if (streq(str, "%defaultroute"))
+ {
+ if (!defaultroute->defined)
+ {
+ return 0;
+ }
+ *pn = 0;
+ *pphys = defaultroute->iface;
+ }
+ else
+ {
+ if (strlen(str) < 8
+ || str[0] != 'i' || str[1] != 'p' || str[2] !='s' || str[3] != 'e'
+ || str[4] != 'c' || str[5] < '0' || str[5] > '9' || str[6] != '=')
+ {
+ return 0;
+ }
+ *pn = str[5] - '0';
+ *pphys = &(str[7]);
+ }
+ return 1;
+}
+
+static int
+_iface_up (int sock, struct st_ipsec_if *iface, char *phys
+, unsigned int mtu, bool nat_t)
+{
+ struct ifreq req;
+ struct ipsectunnelconf *shc=(struct ipsectunnelconf *)&req.ifr_data;
+ short phys_flags;
+ int ret = 0;
+ /* sscholz@astaro.com: for network mask 32 bit
+ struct sockaddr_in *inp;
+ */
+
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req) !=0 )
+ return ret;
+ phys_flags = req.ifr_flags;
+
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req) != 0)
+ return ret;
+
+ if ((!(req.ifr_flags & IFF_UP)) || (!iface->up))
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("attaching interface %s to %s", iface->name, phys)
+ )
+ ret = 1;
+ }
+
+ if ((*iface->phys) && (strcmp(iface->phys, phys) != 0 ))
+ {
+ /* tncfg --detach if phys has changed */
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ ioctl(sock, IPSEC_DEL_DEV, &req);
+ ret = 1;
+ }
+
+ /* tncfg --attach */
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ strncpy(shc->cf_name, phys, sizeof(shc->cf_name));
+ ioctl(sock, IPSEC_SET_DEV, &req);
+
+ /* set ipsec addr = phys addr */
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFADDR, &req) == 0)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ ioctl(sock, SIOCSIFADDR, &req);
+ }
+
+ /* set ipsec mask = phys mask */
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFNETMASK, &req) == 0)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ /* sscholz@astaro.com: changed netmask to 32 bit
+ * in order to prevent network routes from being created
+
+ inp = (struct sockaddr_in *)&req.ifr_addr;
+ inp->sin_addr.s_addr = 0xFFFFFFFFL;
+
+ */
+ ioctl(sock, SIOCSIFNETMASK, &req);
+ }
+
+ /* set other flags & addr */
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req)==0)
+ {
+/* removed by sscholz@astaro.com (caused trouble with DSL/ppp0) */
+/* if (phys_flags & IFF_POINTOPOINT)
+ {
+ req.ifr_flags |= IFF_POINTOPOINT;
+ req.ifr_flags &= ~IFF_BROADCAST;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFDSTADDR, &req) == 0)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ ioctl(sock, SIOCSIFDSTADDR, &req);
+ }
+ }
+ else
+ */
+ if (phys_flags & IFF_BROADCAST)
+ {
+ req.ifr_flags &= ~IFF_POINTOPOINT;
+ req.ifr_flags |= IFF_BROADCAST;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFBRDADDR, &req) == 0)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ ioctl(sock, SIOCSIFBRDADDR, &req);
+ }
+ }
+ else
+ {
+ req.ifr_flags &= ~IFF_POINTOPOINT;
+ req.ifr_flags &= ~IFF_BROADCAST;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ }
+ }
+
+ /*
+ * guess MTU = phys interface MTU - ESP Overhead
+ *
+ * ESP overhead : 10+16+7+2+12=57 -> 60 by security
+ * NAT-T overhead : 20
+ */
+ if (mtu == 0)
+ {
+ strncpy(req.ifr_name, phys, IFNAMSIZ);
+ ioctl(sock, SIOCGIFMTU, &req);
+ mtu = req.ifr_mtu - 60;
+ if (nat_t)
+ mtu -= 20;
+ }
+ /* set MTU */
+ if (mtu)
+ {
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ req.ifr_mtu = mtu;
+ ioctl(sock, SIOCSIFMTU, &req);
+ }
+
+ /* ipsec interface UP */
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req) == 0)
+ {
+ req.ifr_flags |= IFF_UP;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ }
+
+ iface->up = 1;
+ strncpy(iface->phys, phys, IFNAMSIZ);
+ return ret;
+}
+
+static int
+_iface_down(int sock, struct st_ipsec_if *iface)
+{
+ struct ifreq req;
+ int ret = 0;
+
+ iface->up = 0;
+
+ strncpy(req.ifr_name, iface->name, IFNAMSIZ);
+ if (ioctl(sock, SIOCGIFFLAGS, &req)!=0)
+ return ret;
+
+ if (req.ifr_flags & IFF_UP)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("shutting down interface %s/%s", iface->name, iface->phys)
+ )
+ req.ifr_flags &= ~IFF_UP;
+ ioctl(sock, SIOCSIFFLAGS, &req);
+ ret = 1;
+ }
+
+ /* unset addr */
+ memset(&req.ifr_addr, 0, sizeof(req.ifr_addr));
+ req.ifr_addr.sa_family = AF_INET;
+ ioctl(sock, SIOCSIFADDR, &req);
+
+ /* tncfg --detach */
+ ioctl(sock, IPSEC_DEL_DEV, &req);
+
+ memset(iface->phys, 0, sizeof(iface->phys));
+
+ return ret;
+}
+
+void
+starter_ifaces_init(void)
+{
+ int i;
+
+ memset(_ipsec_if, 0, sizeof(_ipsec_if));
+ for (i = 0; i < N_IPSEC_IF; i++)
+ snprintf(_ipsec_if[i].name, IFNAMSIZ, "ipsec%d", i);
+}
+
+void
+starter_ifaces_clear (void)
+{
+ int sock;
+ unsigned int i;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return;
+
+ for (i = 0; i < N_IPSEC_IF; i++)
+ _iface_down (sock, &(_ipsec_if[i]));
+}
+
+int
+starter_ifaces_load(char **ifaces, unsigned int omtu, bool nat_t
+, defaultroute_t *defaultroute)
+{
+ char *tmp_phys, *phys;
+ int n;
+ char **i;
+ int sock;
+ int j, found;
+ int ret = 0;
+ struct ifreq physreq, ipsecreq; // re-attach interface
+ struct sockaddr_in *inp1, *inp2; // re-attach interface
+
+ DBG(DBG_CONTROL,
+ DBG_log("starter_ifaces_load()")
+ )
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return -1;
+
+ for (j = 0; j < N_IPSEC_IF; j++)
+ {
+ found = 0;
+
+ for (i = ifaces; i && *i; i++)
+ {
+ if (valid_str(*i, &n, &tmp_phys, defaultroute)
+ && tmp_phys
+ && n >= 0
+ && n < N_IPSEC_IF)
+ {
+ if (n==j)
+ {
+ if (found)
+ {
+ plog( "ignoring duplicate entry for interface ipsec%d", j);
+ }
+ else
+ {
+ found++;
+ phys = _find_physical_iface(sock, tmp_phys);
+
+ /* Re-attach ipsec interface if IP address changes
+ * sscholz@astaro.com
+ */
+ if (phys)
+ {
+ memset ((void*)&physreq, 0, sizeof(physreq));
+ memset ((void*)&ipsecreq, 0, sizeof(ipsecreq));
+ strncpy(physreq.ifr_name, phys, IFNAMSIZ);
+ sprintf(ipsecreq.ifr_name, "ipsec%d", j);
+ ioctl(sock, SIOCGIFADDR, &physreq);
+ ioctl(sock, SIOCGIFADDR, &ipsecreq);
+ inp1 = (struct sockaddr_in *)&physreq.ifr_addr;
+ inp2 = (struct sockaddr_in *)&ipsecreq.ifr_addr;
+ if (inp1->sin_addr.s_addr != inp2->sin_addr.s_addr)
+ {
+ plog("IP address of physical interface changed "
+ "-> reinit of ipsec interface");
+ _iface_down (sock, &(_ipsec_if[n]));
+ }
+ ret += _iface_up (sock, &(_ipsec_if[n]), phys, omtu, nat_t);
+ }
+ else
+ {
+ ret += _iface_down (sock, &(_ipsec_if[n]));
+ }
+ }
+ }
+ }
+ else if (j == 0)
+ {
+ /* Only log in the first loop */
+ plog("ignoring invalid interface '%s'", *i);
+ }
+ }
+ if (!found)
+ ret += _iface_down (sock, &(_ipsec_if[j]));
+ }
+
+ close(sock);
+ return ret; /* = number of changes - 'whack --listen' if > 0 */
+}
+
+/*
+ * initialize a defaultroute_t struct
+ */
+static void
+init_defaultroute(defaultroute_t *defaultroute)
+{
+ memset(defaultroute, 0, sizeof(defaultroute_t));
+}
+
+/*
+ * discover the default route via /proc/net/route
+ */
+void
+get_defaultroute(defaultroute_t *defaultroute)
+{
+ FILE *fd;
+ char line[BUF_LEN];
+ bool first = TRUE;
+
+ init_defaultroute(defaultroute);
+
+ fd = fopen("/proc/net/route", "r");
+
+ if (!fd)
+ {
+ plog("could not open 'proc/net/route'");
+ return;
+ }
+
+ while (fgets(line, sizeof(line), fd) != 0)
+ {
+ char iface[11];
+ char destination[9];
+ char gateway[11];
+ char flags[5];
+ char mask[9];
+
+ int refcnt;
+ int use;
+ int metric;
+ int items;
+
+ /* proc/net/route returns IP addresses in host order */
+ strcpy(gateway, "0h");
+
+ /* skip the header line */
+ if (first)
+ {
+ first = FALSE;
+ continue;
+ }
+
+ /* parsing a single line of proc/net/route */
+ items = sscanf(line, "%10s\t%8s\t%8s\t%5s\t%d\t%d\t%d\t%8s\t"
+ , iface, destination, gateway+2, flags, &refcnt, &use, &metric, mask);
+ if (items < 8)
+ {
+ plog("parsing error while scanning /proc/net/route");
+ continue;
+ }
+
+ /* check for defaultroute (destination 0.0.0.0 and mask 0.0.0.0) */
+ if (streq(destination, "00000000") && streq(mask, "00000000"))
+ {
+ if (defaultroute->defined)
+ {
+ plog("multiple default routes - cannot cope with %%defaultroute!!!");
+ defaultroute->defined = FALSE;
+ fclose(fd);
+ return;
+ }
+ ttoaddr(gateway, strlen(gateway), AF_INET, &defaultroute->nexthop);
+ strncpy(defaultroute->iface, iface, IFNAMSIZ);
+ defaultroute->defined = TRUE;
+ }
+ }
+ fclose(fd);
+
+ if (!defaultroute->defined)
+ {
+ plog("no default route - cannot cope with %%defaultroute!!!");
+ }
+ else
+ {
+ char addr_buf[20], nexthop_buf[20];
+ struct ifreq physreq;
+
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+
+ /* determine IP address of iface */
+ if (sock < 0)
+ {
+ plog("could not open SOCK_DGRAM socket");
+ defaultroute->defined = FALSE;
+ return;
+ }
+ memset ((void*)&physreq, 0, sizeof(physreq));
+ strncpy(physreq.ifr_name, defaultroute->iface, IFNAMSIZ);
+ ioctl(sock, SIOCGIFADDR, &physreq);
+ close(sock);
+ defaultroute->addr.u.v4 = *((struct sockaddr_in *)&physreq.ifr_addr);
+
+ addrtot(&defaultroute->addr, 0, addr_buf, sizeof(addr_buf));
+ addrtot(&defaultroute->nexthop, 0, nexthop_buf, sizeof(nexthop_buf));
+
+ DBG(DBG_CONTROL,
+ DBG_log("Default route found: iface=%s, addr=%s, nexthop=%s"
+ , defaultroute->iface, addr_buf, nexthop_buf)
+ )
+
+ /* for backwards-compatibility with the awk shell scripts
+ * store the defaultroute in /var/run/ipsec.info
+ */
+ fd = fopen(INFO_FILE, "w");
+
+ if (fd)
+ {
+ fprintf(fd, "defaultroutephys=%s\n", defaultroute->iface );
+ fprintf(fd, "defaultroutevirt=ipsec0\n");
+ fprintf(fd, "defaultrouteaddr=%s\n", addr_buf);
+ fprintf(fd, "defaultroutenexthop=%s\n", nexthop_buf);
+ fclose(fd);
+ }
+ }
+ return;
+}
diff --git a/programs/starter/interfaces.h b/programs/starter/interfaces.h
new file mode 100644
index 000000000..9898c0516
--- /dev/null
+++ b/programs/starter/interfaces.h
@@ -0,0 +1,41 @@
+/* strongSwan IPsec interfaces management
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: interfaces.h,v 1.6 2006/01/06 20:24:07 as Exp $
+ */
+
+#ifndef _STARTER_INTERFACES_H_
+#define _STARTER_INTERFACES_H_
+
+#include <linux/if.h>
+
+#include "../pluto/constants.h"
+
+typedef struct {
+ bool defined;
+ char iface[IFNAMSIZ];
+ ip_address addr;
+ ip_address nexthop;
+} defaultroute_t;
+
+extern void starter_ifaces_init (void);
+extern int starter_iface_find(char *iface, int af, ip_address *dst
+ , ip_address *nh);
+extern int starter_ifaces_load (char **ifaces, unsigned int omtu, bool nat_t
+ , defaultroute_t *defaultroute);
+extern void starter_ifaces_clear (void);
+extern void get_defaultroute(defaultroute_t *defaultroute);
+
+
+#endif /* _STARTER_INTERFACES_H_ */
+
diff --git a/programs/starter/invokepluto.c b/programs/starter/invokepluto.c
new file mode 100644
index 000000000..70376e380
--- /dev/null
+++ b/programs/starter/invokepluto.c
@@ -0,0 +1,286 @@
+/* strongSwan Pluto launcher
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: invokepluto.c,v 1.12 2006/02/17 21:41:50 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "confread.h"
+#include "invokepluto.h"
+#include "files.h"
+#include "starterwhack.h"
+#
+static int _pluto_pid = 0;
+static int _stop_requested;
+
+pid_t
+starter_pluto_pid(void)
+{
+ return _pluto_pid;
+}
+
+void
+starter_pluto_sigchild(pid_t pid)
+{
+ if (pid == _pluto_pid)
+ {
+ _pluto_pid = 0;
+ if (!_stop_requested)
+ {
+ plog("pluto has died -- restart scheduled (%dsec)"
+ , PLUTO_RESTART_DELAY);
+ alarm(PLUTO_RESTART_DELAY); // restart in 5 sec
+ }
+ unlink(PID_FILE);
+ }
+}
+
+int
+starter_stop_pluto (void)
+{
+ pid_t pid;
+ int i;
+
+ pid = _pluto_pid;
+ if (pid)
+ {
+ _stop_requested = 1;
+ if (starter_whack_shutdown() == 0)
+ {
+ for (i = 0; i < 20; i++)
+ {
+ usleep(20000);
+ if (_pluto_pid == 0)
+ return 0;
+ }
+ }
+ /* be more and more aggressive */
+ for (i = 0; i < 20 && (pid = _pluto_pid) != 0; i++)
+ {
+ if (i < 10)
+ kill(pid, SIGTERM);
+ else
+ kill(pid, SIGKILL);
+ usleep(20000);
+ }
+ if (_pluto_pid == 0)
+ return 0;
+ plog("starter_stop_pluto(): can't stop pluto !!!");
+ return -1;
+ }
+ else
+ {
+ plog("stater_stop_pluto(): pluto is not started...");
+ }
+ return -1;
+}
+
+#define ADD_DEBUG(v) { \
+ for (l = cfg->setup.plutodebug; l && *l; l++) if (streq(*l, v)) \
+ arg[argc++] = "--debug-" v; \
+ }
+
+int
+starter_start_pluto (starter_config_t *cfg, bool debug)
+{
+ int i;
+ struct stat stb;
+ pid_t pid;
+ char **l;
+ int argc = 2;
+ char *arg[] = {
+ PLUTO_CMD, "--nofork"
+ , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ };
+
+ printf ("starter_start_pluto entered\n");
+
+ if (debug)
+ {
+ arg[argc++] = "--stderrlog";
+ }
+ if (cfg->setup.uniqueids)
+ {
+ arg[argc++] = "--uniqueids";
+ }
+ ADD_DEBUG("none")
+ ADD_DEBUG("all")
+ ADD_DEBUG("raw")
+ ADD_DEBUG("crypt")
+ ADD_DEBUG("parsing")
+ ADD_DEBUG("emitting")
+ ADD_DEBUG("control")
+ ADD_DEBUG("lifecycle")
+ ADD_DEBUG("klips")
+ ADD_DEBUG("dns")
+ ADD_DEBUG("natt")
+ ADD_DEBUG("oppo")
+ ADD_DEBUG("controlmore")
+ ADD_DEBUG("private")
+ if (cfg->setup.crlcheckinterval > 0)
+ {
+ static char buf1[15];
+
+ arg[argc++] = "--crlcheckinterval";
+ snprintf(buf1, sizeof(buf1), "%u", cfg->setup.crlcheckinterval);
+ arg[argc++] = buf1;
+ }
+ if (cfg->setup.cachecrls)
+ {
+ arg[argc++] = "--cachecrls";
+ }
+ if (cfg->setup.strictcrlpolicy)
+ {
+ arg[argc++] = "--strictcrlpolicy";
+ }
+ if (cfg->setup.nocrsend)
+ {
+ arg[argc++] = "--nocrsend";
+ }
+ if (cfg->setup.nat_traversal)
+ {
+ arg[argc++] = "--nat_traversal";
+ }
+ if (cfg->setup.keep_alive)
+ {
+ static char buf2[15];
+
+ arg[argc++] = "--keep_alive";
+ snprintf(buf2, sizeof(buf2), "%u", cfg->setup.keep_alive);
+ arg[argc++] = buf2;
+ }
+#ifdef VIRTUAL_IP
+ if (cfg->setup.virtual_private)
+ {
+ arg[argc++] = "--virtual_private";
+ arg[argc++] = cfg->setup.virtual_private;
+ }
+#endif
+ if (cfg->setup.pkcs11module)
+ {
+ arg[argc++] = "--pkcs11module";
+ arg[argc++] = cfg->setup.pkcs11module;
+ }
+ if (cfg->setup.pkcs11keepstate)
+ {
+ arg[argc++] = "--pkcs11keepstate";
+ }
+ if (cfg->setup.pkcs11proxy)
+ {
+ arg[argc++] = "--pkcs11proxy";
+ }
+
+ if (_pluto_pid)
+ {
+ plog("starter_start_pluto(): pluto already started...");
+ return -1;
+ }
+ else
+ {
+ unlink(CTL_FILE);
+ _stop_requested = 0;
+
+ if (cfg->setup.prepluto)
+ system(cfg->setup.prepluto);
+
+ /* if ipsec.secrets file is missing then generate RSA default key pair */
+ if (stat(SECRETS_FILE, &stb) != 0)
+ {
+ mode_t oldmask;
+ FILE *f;
+
+ plog("no %s file, generating RSA key", SECRETS_FILE);
+ system("ipsec scepclient --out pkcs1 --out cert-self --quiet");
+
+ /* ipsec.secrets is root readable only */
+ oldmask = umask(0066);
+
+ f = fopen(SECRETS_FILE, "w");
+ if (f)
+ {
+ fprintf(f, "# /etc/ipsec.secrets - strongSwan IPsec secrets file\n");
+ fprintf(f, "\n");
+ fprintf(f, ": RSA myKey.der\n");
+ fclose(f);
+ }
+ umask(oldmask);
+ }
+
+ pid = fork();
+ switch (pid)
+ {
+ case -1:
+ plog("can't fork(): %s", strerror(errno));
+ return -1;
+ case 0:
+ /* child */
+ setsid();
+ sigprocmask(SIG_SETMASK, 0, NULL);
+ execv(arg[0], arg);
+ plog("can't execv(%s,...): %s", arg[0], strerror(errno));
+ exit(1);
+ default:
+ /* father */
+ _pluto_pid = pid;
+ for (i = 0; i < 50 && _pluto_pid; i++)
+ {
+ /* wait for pluto */
+ usleep(20000);
+ if (stat(CTL_FILE, &stb) == 0)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("pluto (%d) started", _pluto_pid)
+ )
+ if (cfg->setup.postpluto)
+ system(cfg->setup.postpluto);
+ return 0;
+ }
+ }
+ if (_pluto_pid)
+ {
+ /* If pluto is started but with no ctl file, stop it */
+ plog("pluto too long to start... - kill kill");
+ for (i = 0; i < 20 && (pid = _pluto_pid) != 0; i++)
+ {
+ if (i < 10)
+ kill(pid, SIGTERM);
+ else
+ kill(pid, SIGKILL);
+ usleep(20000);
+ }
+ }
+ else
+ {
+ plog("pluto refused to be started");
+ }
+ return -1;
+ }
+ }
+ return -1;
+}
diff --git a/programs/starter/invokepluto.h b/programs/starter/invokepluto.h
new file mode 100644
index 000000000..26858f9b2
--- /dev/null
+++ b/programs/starter/invokepluto.h
@@ -0,0 +1,28 @@
+/* strongSwan pluto launcher
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: invokepluto.h,v 1.3 2006/01/04 23:30:24 as Exp $
+ */
+
+#ifndef _STARTER_PLUTO_H_
+#define _STARTER_PLUTO_H_
+
+#define PLUTO_RESTART_DELAY 5
+
+extern void starter_pluto_sigchild (pid_t pid);
+extern pid_t starter_pluto_pid (void);
+extern int starter_stop_pluto (void);
+extern int starter_start_pluto (struct starter_config *cfg, bool debug);
+
+#endif /* _STARTER_PLUTO_H_ */
+
diff --git a/programs/starter/keywords.c b/programs/starter/keywords.c
new file mode 100644
index 000000000..4cc5c03e8
--- /dev/null
+++ b/programs/starter/keywords.c
@@ -0,0 +1,235 @@
+/* C code produced by gperf version 3.0.1 */
+/* Command-line: gperf -C -G -t */
+/* Computed positions: -k'3,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+
+/* strongSwan keywords
+ * Copyright (C) 2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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: keywords.c,v 1.7 2006/04/17 10:32:48 as Exp $
+ */
+
+#include <string.h>
+
+#include "keywords.h"
+
+struct kw_entry {
+ char *name;
+ kw_token_t token;
+};
+
+#define TOTAL_KEYWORDS 77
+#define MIN_WORD_LENGTH 3
+#define MAX_WORD_LENGTH 17
+#define MIN_HASH_VALUE 9
+#define MAX_HASH_VALUE 146
+/* maximum key range = 138, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash (str, len)
+ register const char *str;
+ register unsigned int len;
+{
+ static const unsigned char asso_values[] =
+ {
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 15, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 85, 147, 40,
+ 25, 25, 0, 10, 5, 80, 147, 35, 60, 35,
+ 60, 55, 10, 147, 15, 20, 5, 65, 147, 147,
+ 147, 35, 0, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147
+ };
+ return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[len - 1]];
+}
+
+static const struct kw_entry wordlist[] =
+ {
+ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {"left", KW_LEFT},
+ {""}, {""}, {""},
+ {"leftcert", KW_LEFTCERT,},
+ {"auth", KW_AUTH},
+ {"leftsubnet", KW_LEFTSUBNET},
+ {""},
+ {"leftsendcert", KW_LEFTSENDCERT},
+ {"leftprotoport", KW_LEFTPROTOPORT},
+ {""},
+ {"right", KW_RIGHT},
+ {"leftnexthop", KW_LEFTNEXTHOP},
+ {"leftsourceip", KW_LEFTSOURCEIP},
+ {"esp", KW_ESP},
+ {"rightcert", KW_RIGHTCERT},
+ {""},
+ {"rightsubnet", KW_RIGHTSUBNET},
+ {""},
+ {"rightsendcert", KW_RIGHTSENDCERT},
+ {"rightprotoport", KW_RIGHTPROTOPORT},
+ {"leftgroups", KW_LEFTGROUPS},
+ {"leftid", KW_LEFTID},
+ {"rightnexthop", KW_RIGHTNEXTHOP},
+ {"rightsourceip", KW_RIGHTSOURCEIP},
+ {"lefthostaccess", KW_LEFTHOSTACCESS},
+ {"interfaces", KW_INTERFACES},
+ {""}, {""},
+ {"pfsgroup", KW_PFSGROUP},
+ {"type", KW_TYPE},
+ {"dpdtimeout", KW_DPDTIMEOUT},
+ {"rightgroups", KW_RIGHTGROUPS},
+ {"rightid", KW_RIGHTID},
+ {"pfs", KW_PFS},
+ {"rekeyfuzz", KW_REKEYFUZZ},
+ {"righthostaccess", KW_RIGHTHOSTACCESS},
+ {"authby", KW_AUTHBY},
+ {""},
+ {"leftrsasigkey", KW_LEFTRSASIGKEY},
+ {""}, {""},
+ {"cacert", KW_CACERT},
+ {"hidetos", KW_HIDETOS},
+ {"ike", KW_IKE},
+ {""},
+ {"virtual_private", KW_VIRTUAL_PRIVATE},
+ {""},
+ {"dumpdir", KW_DUMPDIR},
+ {"packetdefault", KW_PACKETDEFAULT},
+ {"rightrsasigkey", KW_RIGHTRSASIGKEY},
+ {"keep_alive", KW_KEEP_ALIVE},
+ {"ikelifetime", KW_IKELIFETIME},
+ {""},
+ {"compress", KW_COMPRESS},
+ {"auto", KW_AUTO},
+ {"strictcrlpolicy", KW_STRICTCRLPOLICY},
+ {"keyingtries", KW_KEYINGTRIES},
+ {"keylife", KW_KEYLIFE},
+ {"dpddelay", KW_DPDDELAY},
+ {"cachecrls", KW_CACHECRLS},
+ {"leftupdown", KW_LEFTUPDOWN},
+ {"keyexchange", KW_KEYEXCHANGE},
+ {"leftfirewall", KW_LEFTFIREWALL},
+ {"nocrsend", KW_NOCRSEND},
+ {""},
+ {"rekey", KW_REKEY},
+ {"leftsubnetwithin", KW_LEFTSUBNETWITHIN},
+ {"pkcs11module", KW_PKCS11MODULE},
+ {"nat_traversal", KW_NAT_TRAVERSAL},
+ {"also", KW_ALSO},
+ {"pkcs11keepstate", KW_PKCS11KEEPSTATE},
+ {"rightupdown", KW_RIGHTUPDOWN},
+ {"crluri2", KW_CRLURI2},
+ {"rightfirewall", KW_RIGHTFIREWALL},
+ {"postpluto", KW_POSTPLUTO},
+ {"plutodebug", KW_PLUTODEBUG},
+ {"pkcs11proxy", KW_PKCS11PROXY},
+ {"rightsubnetwithin", KW_RIGHTSUBNETWITHIN},
+ {"prepluto", KW_PREPLUTO},
+ {""}, {""},
+ {"leftca", KW_LEFTCA},
+ {""}, {""},
+ {"dpdaction", KW_DPDACTION},
+ {""}, {""}, {""},
+ {"ldaphost", KW_LDAPHOST},
+ {""},
+ {"klipsdebug", KW_KLIPSDEBUG},
+ {"overridemtu", KW_OVERRIDEMTU},
+ {"rightca", KW_RIGHTCA},
+ {"fragicmp", KW_FRAGICMP},
+ {""}, {""},
+ {"rekeymargin", KW_REKEYMARGIN},
+ {"ocspuri", KW_OCSPURI},
+ {""},
+ {"uniqueids", KW_UNIQUEIDS},
+ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {"ldapbase", KW_LDAPBASE},
+ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {"crlcheckinterval", KW_CRLCHECKINTERVAL},
+ {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+ {"crluri", KW_CRLURI}
+ };
+
+#ifdef __GNUC__
+__inline
+#endif
+const struct kw_entry *
+in_word_set (str, len)
+ register const char *str;
+ register unsigned int len;
+{
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/programs/starter/keywords.h b/programs/starter/keywords.h
new file mode 100644
index 000000000..6542ae1be
--- /dev/null
+++ b/programs/starter/keywords.h
@@ -0,0 +1,164 @@
+/* strongSwan keywords
+ * Copyright (C) 2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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: keywords.h,v 1.8 2006/04/17 10:30:27 as Exp $
+ */
+
+#ifndef _KEYWORDS_H_
+#define _KEYWORDS_H_
+
+typedef enum {
+ /* config setup keywords */
+ KW_INTERFACES,
+ KW_DUMPDIR,
+
+ /* pluto keywords */
+ KW_PLUTODEBUG,
+ KW_PREPLUTO,
+ KW_POSTPLUTO,
+ KW_UNIQUEIDS,
+ KW_OVERRIDEMTU,
+ KW_CRLCHECKINTERVAL,
+ KW_CACHECRLS,
+ KW_STRICTCRLPOLICY,
+ KW_NOCRSEND,
+ KW_NAT_TRAVERSAL,
+ KW_KEEP_ALIVE,
+ KW_VIRTUAL_PRIVATE,
+ KW_PKCS11MODULE,
+ KW_PKCS11KEEPSTATE,
+ KW_PKCS11PROXY,
+
+#define KW_PLUTO_FIRST KW_PLUTODEBUG
+#define KW_PLUTO_LAST KW_PKCS11PROXY
+
+ /* KLIPS keywords */
+ KW_KLIPSDEBUG,
+ KW_FRAGICMP,
+ KW_PACKETDEFAULT,
+ KW_HIDETOS,
+
+#define KW_KLIPS_FIRST KW_KLIPSDEBUG
+#define KW_KLIPS_LAST KW_HIDETOS
+
+#define KW_SETUP_FIRST KW_INTERFACES
+#define KW_SETUP_LAST KW_HIDETOS
+
+ /* conn section keywords */
+ KW_CONN_NAME,
+ KW_CONN_SETUP,
+ KW_KEYEXCHANGE,
+ KW_TYPE,
+ KW_PFS,
+ KW_COMPRESS,
+ KW_AUTH,
+ KW_AUTHBY,
+ KW_IKELIFETIME,
+ KW_KEYLIFE,
+ KW_REKEYMARGIN,
+ KW_KEYINGTRIES,
+ KW_REKEYFUZZ,
+ KW_REKEY,
+ KW_IKE,
+ KW_ESP,
+ KW_PFSGROUP,
+ KW_DPDDELAY,
+ KW_DPDTIMEOUT,
+ KW_DPDACTION,
+
+#define KW_CONN_FIRST KW_CONN_SETUP
+#define KW_CONN_LAST KW_DPDACTION
+
+ /* ca section keywords */
+ KW_CA_NAME,
+ KW_CA_SETUP,
+ KW_CACERT,
+ KW_LDAPHOST,
+ KW_LDAPBASE,
+ KW_CRLURI,
+ KW_CRLURI2,
+ KW_OCSPURI,
+
+#define KW_CA_FIRST KW_CA_SETUP
+#define KW_CA_LAST KW_OCSPURI
+
+ /* end keywords */
+ KW_HOST,
+ KW_NEXTHOP,
+ KW_SUBNET,
+ KW_SUBNETWITHIN,
+ KW_PROTOPORT,
+ KW_SOURCEIP,
+ KW_FIREWALL,
+ KW_HOSTACCESS,
+ KW_UPDOWN,
+ KW_ID,
+ KW_RSASIGKEY,
+ KW_CERT,
+ KW_SENDCERT,
+ KW_CA,
+ KW_GROUPS,
+ KW_IFACE,
+
+#define KW_END_FIRST KW_HOST
+#define KW_END_LAST KW_IFACE
+
+ /* left end keywords */
+ KW_LEFT,
+ KW_LEFTNEXTHOP,
+ KW_LEFTSUBNET,
+ KW_LEFTSUBNETWITHIN,
+ KW_LEFTPROTOPORT,
+ KW_LEFTSOURCEIP,
+ KW_LEFTFIREWALL,
+ KW_LEFTHOSTACCESS,
+ KW_LEFTUPDOWN,
+ KW_LEFTID,
+ KW_LEFTRSASIGKEY,
+ KW_LEFTCERT,
+ KW_LEFTSENDCERT,
+ KW_LEFTCA,
+ KW_LEFTGROUPS,
+
+#define KW_LEFT_FIRST KW_LEFT
+#define KW_LEFT_LAST KW_LEFTGROUPS
+
+ /* right end keywords */
+ KW_RIGHT,
+ KW_RIGHTNEXTHOP,
+ KW_RIGHTSUBNET,
+ KW_RIGHTSUBNETWITHIN,
+ KW_RIGHTPROTOPORT,
+ KW_RIGHTSOURCEIP,
+ KW_RIGHTFIREWALL,
+ KW_RIGHTHOSTACCESS,
+ KW_RIGHTUPDOWN,
+ KW_RIGHTID,
+ KW_RIGHTRSASIGKEY,
+ KW_RIGHTCERT,
+ KW_RIGHTSENDCERT,
+ KW_RIGHTCA,
+ KW_RIGHTGROUPS,
+
+#define KW_RIGHT_FIRST KW_RIGHT
+#define KW_RIGHT_LAST KW_RIGHTGROUPS
+
+ /* general section keywords */
+ KW_ALSO,
+ KW_AUTO
+
+} kw_token_t;
+
+#endif /* _KEYWORDS_H_ */
+
diff --git a/programs/starter/keywords.txt b/programs/starter/keywords.txt
new file mode 100644
index 000000000..dcfdafc98
--- /dev/null
+++ b/programs/starter/keywords.txt
@@ -0,0 +1,105 @@
+%{
+/* strongSwan keywords
+ * Copyright (C) 2005 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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: keywords.txt,v 1.6 2006/04/17 10:30:27 as Exp $
+ */
+
+#include <string.h>
+
+#include "keywords.h"
+
+%}
+struct kw_entry {
+ char *name;
+ kw_token_t token;
+};
+%%
+interfaces, KW_INTERFACES
+klipsdebug, KW_KLIPSDEBUG
+plutodebug, KW_PLUTODEBUG
+dumpdir, KW_DUMPDIR
+prepluto, KW_PREPLUTO
+postpluto, KW_POSTPLUTO
+fragicmp, KW_FRAGICMP
+packetdefault, KW_PACKETDEFAULT
+hidetos, KW_HIDETOS
+uniqueids, KW_UNIQUEIDS
+overridemtu, KW_OVERRIDEMTU
+crlcheckinterval, KW_CRLCHECKINTERVAL
+cachecrls, KW_CACHECRLS
+strictcrlpolicy, KW_STRICTCRLPOLICY
+nocrsend, KW_NOCRSEND
+nat_traversal, KW_NAT_TRAVERSAL
+keep_alive, KW_KEEP_ALIVE
+virtual_private, KW_VIRTUAL_PRIVATE
+pkcs11module, KW_PKCS11MODULE
+pkcs11keepstate, KW_PKCS11KEEPSTATE
+pkcs11proxy, KW_PKCS11PROXY
+keyexchange, KW_KEYEXCHANGE
+type, KW_TYPE
+pfs, KW_PFS
+compress, KW_COMPRESS
+auth, KW_AUTH
+authby, KW_AUTHBY
+keylife, KW_KEYLIFE
+rekeymargin, KW_REKEYMARGIN
+ikelifetime, KW_IKELIFETIME
+keyingtries, KW_KEYINGTRIES
+rekeyfuzz, KW_REKEYFUZZ
+rekey, KW_REKEY
+esp, KW_ESP
+ike, KW_IKE
+pfsgroup, KW_PFSGROUP
+dpddelay, KW_DPDDELAY
+dpdtimeout, KW_DPDTIMEOUT
+dpdaction, KW_DPDACTION
+cacert, KW_CACERT
+ldaphost, KW_LDAPHOST
+ldapbase, KW_LDAPBASE
+crluri, KW_CRLURI
+crluri2, KW_CRLURI2
+ocspuri, KW_OCSPURI
+left, KW_LEFT
+leftnexthop, KW_LEFTNEXTHOP
+leftsubnet, KW_LEFTSUBNET
+leftsubnetwithin, KW_LEFTSUBNETWITHIN
+leftprotoport, KW_LEFTPROTOPORT
+leftsourceip, KW_LEFTSOURCEIP
+leftfirewall, KW_LEFTFIREWALL
+lefthostaccess, KW_LEFTHOSTACCESS
+leftupdown, KW_LEFTUPDOWN
+leftid, KW_LEFTID
+leftrsasigkey, KW_LEFTRSASIGKEY
+leftcert, KW_LEFTCERT,
+leftsendcert, KW_LEFTSENDCERT
+leftca, KW_LEFTCA
+leftgroups, KW_LEFTGROUPS
+right, KW_RIGHT
+rightnexthop, KW_RIGHTNEXTHOP
+rightsubnet, KW_RIGHTSUBNET
+rightsubnetwithin, KW_RIGHTSUBNETWITHIN
+rightprotoport, KW_RIGHTPROTOPORT
+rightsourceip, KW_RIGHTSOURCEIP
+rightfirewall, KW_RIGHTFIREWALL
+righthostaccess, KW_RIGHTHOSTACCESS
+rightupdown, KW_RIGHTUPDOWN
+rightid, KW_RIGHTID
+rightrsasigkey, KW_RIGHTRSASIGKEY
+rightcert, KW_RIGHTCERT
+rightsendcert, KW_RIGHTSENDCERT
+rightca, KW_RIGHTCA
+rightgroups, KW_RIGHTGROUPS
+also, KW_ALSO
+auto, KW_AUTO
diff --git a/programs/starter/klips.c b/programs/starter/klips.c
new file mode 100644
index 000000000..5595eb6eb
--- /dev/null
+++ b/programs/starter/klips.c
@@ -0,0 +1,134 @@
+/* strongSwan KLIPS starter
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: klips.c,v 1.8 2006/02/15 18:33:57 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "confread.h"
+#include "klips.h"
+#include "files.h"
+#include "exec.h"
+
+static int _klips_module_loaded = 0;
+
+bool
+starter_klips_init(void)
+{
+ struct stat stb;
+
+ if (stat(PROC_IPSECVERSION, &stb) != 0)
+ {
+ if (stat(PROC_MODULES, &stb) == 0)
+ {
+ unsetenv("MODPATH");
+ unsetenv("MODULECONF");
+ system("depmod -a >/dev/null 2>&1");
+ system("modprobe -qv ipsec");
+ }
+ if (stat(PROC_IPSECVERSION, &stb) == 0)
+ {
+ _klips_module_loaded = 1;
+ }
+ else
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("kernel appears to lack KLIPS")
+ )
+ return FALSE;
+ }
+ }
+
+ /* make sure that all available crypto algorithms are loaded */
+ if (stat(PROC_MODULES, &stb) == 0)
+ {
+ system("modprobe -qv ipsec_aes");
+ system("modprobe -qv ipsec_serpent");
+ system("modprobe -qv ipsec_twofish");
+ system("modprobe -qv ipsec_blowfish");
+ system("modprobe -qv ipsec_sha2");
+ }
+
+ starter_klips_clear();
+
+ DBG(DBG_CONTROL,
+ DBG_log("Found KLIPS IPsec stack")
+ )
+ return TRUE;
+}
+
+static void
+_sysflags (char *name, int value)
+{
+ int res = starter_exec("echo %d >%s/%s 2>/dev/null"
+ , value? 1 : 0, PROC_SYSFLAGS, name);
+
+ if (res)
+ plog("can't set sysflag %s to %d", name, value? 1 : 0);
+}
+
+void
+starter_klips_set_config(starter_config_t *cfg)
+{
+ char **l;
+
+ _sysflags("icmp", cfg->setup.fragicmp);
+ _sysflags("inbound_policy_check", 1);
+ /* _sysflags("no_eroute_pass", 0); */
+ /* _sysflags("opportunistic", 0); */
+ _sysflags("tos", cfg->setup.hidetos);
+
+ starter_exec("%s/klipsdebug --none", IPSEC_EXECDIR);
+ for (l = cfg->setup.klipsdebug; l && *l; l++)
+ {
+ if ((streq(*l, "none")) || (streq(*l, "all")))
+ starter_exec("%s/klipsdebug --%s", IPSEC_EXECDIR, *l);
+ else
+ starter_exec("%s/klipsdebug --set %s", IPSEC_EXECDIR, *l);
+ }
+
+ starter_exec("%s/eroute --del --eraf inet --src 0/0 --dst 0/0 2>/dev/null"
+ , IPSEC_EXECDIR);
+ starter_exec("%s/eroute --label packetdefault --replace --eraf inet "
+ "--src 0/0 --dst 0/0 --said %%%s", IPSEC_EXECDIR
+ , cfg->setup.packetdefault ? cfg->setup.packetdefault : "drop");
+}
+
+void
+starter_klips_clear(void)
+{
+ system(IPSEC_EXECDIR"/eroute --clear");
+ system(IPSEC_EXECDIR"/spi --clear");
+ system(IPSEC_EXECDIR"/klipsdebug --none");
+}
+
+void
+starter_klips_cleanup(void)
+{
+ starter_klips_clear();
+ if (_klips_module_loaded)
+ {
+ system("rmmod ipsec");
+ _klips_module_loaded = 0;
+ }
+}
diff --git a/programs/starter/klips.h b/programs/starter/klips.h
new file mode 100644
index 000000000..d07c6cca4
--- /dev/null
+++ b/programs/starter/klips.h
@@ -0,0 +1,26 @@
+/* strongSwan klips initialization and cleanup
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: klips.h,v 1.2 2005/12/30 19:03:56 as Exp $
+ */
+
+#ifndef _STARTER_KLIPS_H_
+#define _STARTER_KLIPS_H_
+
+extern bool starter_klips_init (void);
+extern void starter_klips_set_config (struct starter_config *);
+extern void starter_klips_cleanup (void);
+extern void starter_klips_clear (void);
+
+#endif /* _STARTER_KLIPS_H_ */
+
diff --git a/programs/starter/lex.yy.c b/programs/starter/lex.yy.c
new file mode 100644
index 000000000..1626f1050
--- /dev/null
+++ b/programs/starter/lex.yy.c
@@ -0,0 +1,1966 @@
+
+#line 3 "lex.yy.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 33
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 14
+#define YY_END_OF_BUFFER 15
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[47] =
+ { 0,
+ 0, 0, 15, 11, 2, 4, 13, 11, 3, 11,
+ 11, 11, 11, 1, 11, 2, 0, 12, 11, 0,
+ 4, 8, 11, 11, 11, 11, 1, 11, 11, 11,
+ 11, 11, 7, 11, 11, 11, 11, 11, 6, 11,
+ 5, 11, 11, 9, 10, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 4, 5, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 6, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 7, 1, 8, 9,
+
+ 10, 11, 12, 1, 13, 1, 1, 14, 1, 15,
+ 16, 17, 1, 18, 19, 20, 21, 22, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[23] =
+ { 0,
+ 1, 2, 3, 2, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[51] =
+ { 0,
+ 0, 69, 70, 0, 67, 72, 64, 21, 72, 19,
+ 52, 56, 55, 62, 0, 61, 58, 72, 34, 58,
+ 72, 0, 45, 51, 38, 39, 54, 17, 41, 33,
+ 34, 39, 0, 30, 33, 36, 27, 25, 0, 17,
+ 0, 21, 15, 0, 0, 72, 28, 40, 42, 45
+ } ;
+
+static yyconst flex_int16_t yy_def[51] =
+ { 0,
+ 46, 1, 46, 47, 46, 46, 48, 49, 46, 47,
+ 47, 47, 47, 46, 47, 46, 48, 46, 49, 50,
+ 46, 47, 47, 47, 47, 47, 46, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 0, 46, 46, 46, 46
+ } ;
+
+static yyconst flex_int16_t yy_nxt[95] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 4, 10, 4, 4,
+ 4, 4, 11, 4, 4, 4, 4, 4, 12, 4,
+ 4, 13, 20, 21, 20, 22, 20, 32, 15, 45,
+ 44, 33, 43, 42, 23, 20, 21, 20, 41, 20,
+ 17, 17, 19, 19, 19, 20, 20, 20, 40, 39,
+ 38, 37, 36, 35, 34, 27, 31, 30, 29, 28,
+ 21, 18, 16, 27, 26, 25, 24, 18, 16, 46,
+ 14, 3, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46
+
+ } ;
+
+static yyconst flex_int16_t yy_chk[95] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 8, 8, 8, 10, 8, 28, 47, 43,
+ 42, 28, 40, 38, 10, 19, 19, 19, 37, 19,
+ 48, 48, 49, 49, 49, 50, 50, 50, 36, 35,
+ 34, 32, 31, 30, 29, 27, 26, 25, 24, 23,
+ 20, 17, 16, 14, 13, 12, 11, 7, 5, 3,
+ 2, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46
+
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "parser.l"
+#line 2 "parser.l"
+/* FreeS/WAN config file parser (parser.l)
+ * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: lex.yy.c,v 1.4 2006/03/28 22:32:49 as Exp $
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <glob.h>
+
+#include "parser.tab.h"
+
+#define MAX_INCLUDE_DEPTH 20
+
+#define YY_NO_UNPUT
+extern void yyerror(const char *);
+extern int yylex (void);
+
+static struct {
+ int stack_ptr;
+ YY_BUFFER_STATE stack[MAX_INCLUDE_DEPTH];
+ FILE *file[MAX_INCLUDE_DEPTH];
+ unsigned int line[MAX_INCLUDE_DEPTH];
+ char *filename[MAX_INCLUDE_DEPTH];
+} __parser_y_private;
+
+void _parser_y_error(char *b, int size, const char *s);
+void _parser_y_init (const char *f);
+void _parser_y_fini (void);
+int _parser_y_include (const char *filename);
+
+void _parser_y_error(char *b, int size, const char *s)
+{
+ extern char *yytext; // was: char yytext[];
+
+ snprintf(b, size, "%s:%d: %s [%s]",
+ __parser_y_private.filename[__parser_y_private.stack_ptr],
+ __parser_y_private.line[__parser_y_private.stack_ptr],
+ s, yytext);
+}
+
+void _parser_y_init (const char *f)
+{
+ memset(&__parser_y_private, 0, sizeof(__parser_y_private));
+ __parser_y_private.line[0] = 1;
+ __parser_y_private.filename[0] = strdup(f);
+}
+
+void _parser_y_fini (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_INCLUDE_DEPTH; i++)
+ {
+ if (__parser_y_private.filename[i])
+ free(__parser_y_private.filename[i]);
+ if (__parser_y_private.file[i])
+ fclose(__parser_y_private.file[i]);
+ }
+ memset(&__parser_y_private, 0, sizeof(__parser_y_private));
+}
+
+int _parser_y_include (const char *filename)
+{
+ glob_t files;
+ int i, ret;
+
+ ret = glob(filename, GLOB_ERR, NULL, &files);
+ if (ret)
+ {
+ const char *err;
+
+ switch (ret)
+ {
+ case GLOB_NOSPACE:
+ err = "include files ran out of memory";
+ break;
+ case GLOB_ABORTED:
+ err = "include files aborted due to read error";
+ break;
+ case GLOB_NOMATCH:
+ err = "include files found no matches";
+ break;
+ default:
+ err = "unknown include files error";
+ }
+ yyerror(err);
+ return 1;
+ }
+
+ for (i = 0; i < files.gl_pathc; i++)
+ {
+ FILE *f;
+ unsigned int p = __parser_y_private.stack_ptr + 1;
+
+ if (p >= MAX_INCLUDE_DEPTH)
+ {
+ yyerror("max inclusion depth reached");
+ return 1;
+ }
+
+ f = fopen(files.gl_pathv[i], "r");
+ if (!f)
+ {
+ yyerror("can't open include filename");
+ continue;
+ }
+
+ __parser_y_private.stack_ptr++;
+ __parser_y_private.file[p] = f;
+ __parser_y_private.stack[p] = YY_CURRENT_BUFFER;
+ __parser_y_private.line[p] = 1;
+ __parser_y_private.filename[p] = strdup(files.gl_pathv[i]);
+
+ yy_switch_to_buffer(yy_create_buffer(f,YY_BUF_SIZE));
+ }
+ globfree(&files);
+ return 0;
+}
+
+#line 618 "lex.yy.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 134 "parser.l"
+
+
+#line 777 "lex.yy.c"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 47 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 72 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case YY_STATE_EOF(INITIAL):
+#line 136 "parser.l"
+{
+ if (__parser_y_private.filename[__parser_y_private.stack_ptr]) {
+ free(__parser_y_private.filename[__parser_y_private.stack_ptr]);
+ __parser_y_private.filename[__parser_y_private.stack_ptr] = NULL;
+ }
+ if (__parser_y_private.file[__parser_y_private.stack_ptr]) {
+ fclose(__parser_y_private.file[__parser_y_private.stack_ptr]);
+ __parser_y_private.file[__parser_y_private.stack_ptr] = NULL;
+ yy_delete_buffer (YY_CURRENT_BUFFER);
+ yy_switch_to_buffer
+ (__parser_y_private.stack[__parser_y_private.stack_ptr]);
+ }
+ if (--__parser_y_private.stack_ptr < 0) {
+ yyterminate();
+ }
+}
+ YY_BREAK
+case 1:
+YY_RULE_SETUP
+#line 153 "parser.l"
+return FIRST_SPACES;
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 155 "parser.l"
+/* ignore spaces in line */ ;
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 157 "parser.l"
+return EQUAL;
+ YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 159 "parser.l"
+{
+ __parser_y_private.line[__parser_y_private.stack_ptr]++;
+ return EOL;
+ }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 164 "parser.l"
+return CONFIG;
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 165 "parser.l"
+return SETUP;
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 166 "parser.l"
+return CONN;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 167 "parser.l"
+return CA;
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 168 "parser.l"
+return INCLUDE;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 169 "parser.l"
+return VERSION;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 171 "parser.l"
+{
+ yylval.s = strdup(yytext);
+ return STRING;
+ }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 176 "parser.l"
+{
+ yylval.s = strdup(yytext+1);
+ if (yylval.s) yylval.s[strlen(yylval.s)-1]='\0';
+ return STRING;
+ }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 182 "parser.l"
+yyerror(yytext);
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 184 "parser.l"
+ECHO;
+ YY_BREAK
+#line 961 "lex.yy.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 47 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 47 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 46);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up yytext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+#ifndef _UNISTD_H /* assume unistd.h has isatty() for us */
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __THROW /* this is a gnuism */
+extern int isatty (int ) __THROW;
+#else
+extern int isatty (int );
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param str a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * __yystr )
+{
+
+ return yy_scan_bytes(__yystr,strlen(__yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 184 "parser.l"
+
+
+
+int yywrap(void)
+{
+ return 1;
+}
+
+
diff --git a/programs/starter/netkey.c b/programs/starter/netkey.c
new file mode 100644
index 000000000..d0b8e0a2c
--- /dev/null
+++ b/programs/starter/netkey.c
@@ -0,0 +1,85 @@
+/* strongSwan netkey starter
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: netkey.c,v 1.4 2006/02/15 18:33:57 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "files.h"
+
+bool
+starter_netkey_init(void)
+{
+ struct stat stb;
+
+ if (stat(PROC_NETKEY, &stb) != 0)
+ {
+ /* af_key module makes the netkey proc interface visible */
+ if (stat(PROC_MODULES, &stb) == 0)
+ {
+ system("modprobe -qv af_key");
+ }
+
+ /* now test again */
+ if (stat(PROC_NETKEY, &stb) != 0)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("kernel appears to lack the native netkey IPsec stack")
+ )
+ return FALSE;
+ }
+ }
+
+ /* make sure that all required IPsec modules are loaded */
+ if (stat(PROC_MODULES, &stb) == 0)
+ {
+ system("modprobe -qv ah4");
+ system("modprobe -qv esp4");
+ system("modprobe -qv ipcomp");
+ system("modprobe -qv xfrm4_tunnel");
+ system("modprobe -qv xfrm_user");
+ }
+
+ DBG(DBG_CONTROL,
+ DBG_log("Found netkey IPsec stack")
+ )
+ return TRUE;
+}
+
+void
+starter_netkey_cleanup(void)
+{
+ if (system("ip xfrm state > /dev/null 2>&1") == 0)
+ {
+ system("ip xfrm state flush");
+ system("ip xfrm policy flush");
+ }
+ else if (system("type setkey > /dev/null 2>&1") == 0)
+ {
+ system("setkey -F");
+ system("setkey -FP");
+ }
+ else
+ {
+ plog("WARNING: cannot flush IPsec state/policy database");
+ }
+}
diff --git a/programs/starter/netkey.h b/programs/starter/netkey.h
new file mode 100644
index 000000000..ff8989d34
--- /dev/null
+++ b/programs/starter/netkey.h
@@ -0,0 +1,24 @@
+/* strongSwan netkey initialization and cleanup
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: netkey.h,v 1.1 2005/12/30 19:03:15 as Exp $
+ */
+
+#ifndef _STARTER_NETKEY_H_
+#define _STARTER_NETKEY_H_
+
+extern bool starter_netkey_init (void);
+extern void starter_netkey_cleanup (void);
+
+#endif /* _STARTER_NETKEY_H_ */
+
diff --git a/programs/starter/parser.h b/programs/starter/parser.h
new file mode 100644
index 000000000..61bdea974
--- /dev/null
+++ b/programs/starter/parser.h
@@ -0,0 +1,57 @@
+/* strongSwan config file parser
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: parser.h,v 1.5 2006/01/17 23:43:36 as Exp $
+ */
+
+#ifndef _IPSEC_PARSER_H_
+#define _IPSEC_PARSER_H_
+
+#include "keywords.h"
+
+typedef struct kw_entry kw_entry_t;
+
+struct kw_entry {
+ char *name;
+ kw_token_t token;
+};
+
+typedef struct kw_list kw_list_t;
+
+struct kw_list {
+ kw_entry_t *entry;
+ char *value;
+ kw_list_t *next;
+};
+
+typedef struct section_list section_list_t;
+
+struct section_list {
+ char *name;
+ kw_list_t *kw;
+ section_list_t *next;
+};
+
+typedef struct config_parsed config_parsed_t;
+
+struct config_parsed {
+ kw_list_t *config_setup;
+ section_list_t *conn_first, *conn_last;
+ section_list_t *ca_first, *ca_last;
+};
+
+config_parsed_t *parser_load_conf (const char *file);
+void parser_free_conf (config_parsed_t *cfg);
+
+#endif /* _IPSEC_PARSER_H_ */
+
diff --git a/programs/starter/parser.l b/programs/starter/parser.l
new file mode 100644
index 000000000..8d1cc4c31
--- /dev/null
+++ b/programs/starter/parser.l
@@ -0,0 +1,190 @@
+%{
+/* FreeS/WAN config file parser (parser.l)
+ * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: parser.l,v 1.5 2006/03/28 22:32:33 as Exp $
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <glob.h>
+
+#include "parser.tab.h"
+
+#define MAX_INCLUDE_DEPTH 20
+
+#define YY_NO_UNPUT
+extern void yyerror(const char *);
+extern int yylex (void);
+
+static struct {
+ int stack_ptr;
+ YY_BUFFER_STATE stack[MAX_INCLUDE_DEPTH];
+ FILE *file[MAX_INCLUDE_DEPTH];
+ unsigned int line[MAX_INCLUDE_DEPTH];
+ char *filename[MAX_INCLUDE_DEPTH];
+} __parser_y_private;
+
+void _parser_y_error(char *b, int size, const char *s);
+void _parser_y_init (const char *f);
+void _parser_y_fini (void);
+int _parser_y_include (const char *filename);
+
+void _parser_y_error(char *b, int size, const char *s)
+{
+ extern char *yytext; // was: char yytext[];
+
+ snprintf(b, size, "%s:%d: %s [%s]",
+ __parser_y_private.filename[__parser_y_private.stack_ptr],
+ __parser_y_private.line[__parser_y_private.stack_ptr],
+ s, yytext);
+}
+
+void _parser_y_init (const char *f)
+{
+ memset(&__parser_y_private, 0, sizeof(__parser_y_private));
+ __parser_y_private.line[0] = 1;
+ __parser_y_private.filename[0] = strdup(f);
+}
+
+void _parser_y_fini (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_INCLUDE_DEPTH; i++)
+ {
+ if (__parser_y_private.filename[i])
+ free(__parser_y_private.filename[i]);
+ if (__parser_y_private.file[i])
+ fclose(__parser_y_private.file[i]);
+ }
+ memset(&__parser_y_private, 0, sizeof(__parser_y_private));
+}
+
+int _parser_y_include (const char *filename)
+{
+ glob_t files;
+ int i, ret;
+
+ ret = glob(filename, GLOB_ERR, NULL, &files);
+ if (ret)
+ {
+ const char *err;
+
+ switch (ret)
+ {
+ case GLOB_NOSPACE:
+ err = "include files ran out of memory";
+ break;
+ case GLOB_ABORTED:
+ err = "include files aborted due to read error";
+ break;
+ case GLOB_NOMATCH:
+ err = "include files found no matches";
+ break;
+ default:
+ err = "unknown include files error";
+ }
+ yyerror(err);
+ return 1;
+ }
+
+ for (i = 0; i < files.gl_pathc; i++)
+ {
+ FILE *f;
+ unsigned int p = __parser_y_private.stack_ptr + 1;
+
+ if (p >= MAX_INCLUDE_DEPTH)
+ {
+ yyerror("max inclusion depth reached");
+ return 1;
+ }
+
+ f = fopen(files.gl_pathv[i], "r");
+ if (!f)
+ {
+ yyerror("can't open include filename");
+ continue;
+ }
+
+ __parser_y_private.stack_ptr++;
+ __parser_y_private.file[p] = f;
+ __parser_y_private.stack[p] = YY_CURRENT_BUFFER;
+ __parser_y_private.line[p] = 1;
+ __parser_y_private.filename[p] = strdup(files.gl_pathv[i]);
+
+ yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
+ }
+ globfree(&files);
+ return 0;
+}
+
+%}
+
+%%
+
+<<EOF>> {
+ if (__parser_y_private.filename[__parser_y_private.stack_ptr]) {
+ free(__parser_y_private.filename[__parser_y_private.stack_ptr]);
+ __parser_y_private.filename[__parser_y_private.stack_ptr] = NULL;
+ }
+ if (__parser_y_private.file[__parser_y_private.stack_ptr]) {
+ fclose(__parser_y_private.file[__parser_y_private.stack_ptr]);
+ __parser_y_private.file[__parser_y_private.stack_ptr] = NULL;
+ yy_delete_buffer (YY_CURRENT_BUFFER);
+ yy_switch_to_buffer
+ (__parser_y_private.stack[__parser_y_private.stack_ptr]);
+ }
+ if (--__parser_y_private.stack_ptr < 0) {
+ yyterminate();
+ }
+}
+
+^[\t ]+ return FIRST_SPACES;
+
+[\t ]+ /* ignore spaces in line */ ;
+
+= return EQUAL;
+
+\n|#.*\n {
+ __parser_y_private.line[__parser_y_private.stack_ptr]++;
+ return EOL;
+ }
+
+config return CONFIG;
+setup return SETUP;
+conn return CONN;
+ca return CA;
+include return INCLUDE;
+version return VERSION;
+
+[^\"= \t\n]+ {
+ yylval.s = strdup(yytext);
+ return STRING;
+ }
+
+\"[^\"\n]*\" {
+ yylval.s = strdup(yytext+1);
+ if (yylval.s) yylval.s[strlen(yylval.s)-1]='\0';
+ return STRING;
+ }
+
+. yyerror(yytext);
+
+%%
+
+int yywrap(void)
+{
+ return 1;
+}
+
diff --git a/programs/starter/parser.output b/programs/starter/parser.output
new file mode 100644
index 000000000..ddb01e89a
--- /dev/null
+++ b/programs/starter/parser.output
@@ -0,0 +1,351 @@
+Grammar
+
+ 0 $accept: config_file $end
+
+ 1 config_file: config_file section_or_include
+ 2 | /* empty */
+
+ 3 section_or_include: VERSION STRING EOL
+
+ 4 @1: /* empty */
+
+ 5 section_or_include: CONFIG SETUP EOL @1 kw_section
+
+ 6 @2: /* empty */
+
+ 7 section_or_include: CONN STRING EOL @2 kw_section
+
+ 8 @3: /* empty */
+
+ 9 section_or_include: CA STRING EOL @3 kw_section
+
+ 10 @4: /* empty */
+
+ 11 section_or_include: INCLUDE STRING @4 EOL
+ 12 | EOL
+
+ 13 kw_section: FIRST_SPACES statement_kw EOL kw_section
+ 14 | /* empty */
+
+ 15 statement_kw: STRING EQUAL STRING
+ 16 | STRING EQUAL
+ 17 | /* empty */
+
+
+Terminals, with rules where they appear
+
+$end (0) 0
+error (256)
+EQUAL (258) 15 16
+FIRST_SPACES (259) 13
+EOL (260) 3 5 7 9 11 12 13
+CONFIG (261) 5
+SETUP (262) 5
+CONN (263) 7
+CA (264) 9
+INCLUDE (265) 11
+VERSION (266) 3
+STRING (267) 3 7 9 11 15 16
+
+
+Nonterminals, with rules where they appear
+
+$accept (13)
+ on left: 0
+config_file (14)
+ on left: 1 2, on right: 0 1
+section_or_include (15)
+ on left: 3 5 7 9 11 12, on right: 1
+@1 (16)
+ on left: 4, on right: 5
+@2 (17)
+ on left: 6, on right: 7
+@3 (18)
+ on left: 8, on right: 9
+@4 (19)
+ on left: 10, on right: 11
+kw_section (20)
+ on left: 13 14, on right: 5 7 9 13
+statement_kw (21)
+ on left: 15 16 17, on right: 13
+
+
+state 0
+
+ 0 $accept: . config_file $end
+
+ $default reduce using rule 2 (config_file)
+
+ config_file go to state 1
+
+
+state 1
+
+ 0 $accept: config_file . $end
+ 1 config_file: config_file . section_or_include
+
+ $end shift, and go to state 2
+ EOL shift, and go to state 3
+ CONFIG shift, and go to state 4
+ CONN shift, and go to state 5
+ CA shift, and go to state 6
+ INCLUDE shift, and go to state 7
+ VERSION shift, and go to state 8
+
+ section_or_include go to state 9
+
+
+state 2
+
+ 0 $accept: config_file $end .
+
+ $default accept
+
+
+state 3
+
+ 12 section_or_include: EOL .
+
+ $default reduce using rule 12 (section_or_include)
+
+
+state 4
+
+ 5 section_or_include: CONFIG . SETUP EOL @1 kw_section
+
+ SETUP shift, and go to state 10
+
+
+state 5
+
+ 7 section_or_include: CONN . STRING EOL @2 kw_section
+
+ STRING shift, and go to state 11
+
+
+state 6
+
+ 9 section_or_include: CA . STRING EOL @3 kw_section
+
+ STRING shift, and go to state 12
+
+
+state 7
+
+ 11 section_or_include: INCLUDE . STRING @4 EOL
+
+ STRING shift, and go to state 13
+
+
+state 8
+
+ 3 section_or_include: VERSION . STRING EOL
+
+ STRING shift, and go to state 14
+
+
+state 9
+
+ 1 config_file: config_file section_or_include .
+
+ $default reduce using rule 1 (config_file)
+
+
+state 10
+
+ 5 section_or_include: CONFIG SETUP . EOL @1 kw_section
+
+ EOL shift, and go to state 15
+
+
+state 11
+
+ 7 section_or_include: CONN STRING . EOL @2 kw_section
+
+ EOL shift, and go to state 16
+
+
+state 12
+
+ 9 section_or_include: CA STRING . EOL @3 kw_section
+
+ EOL shift, and go to state 17
+
+
+state 13
+
+ 11 section_or_include: INCLUDE STRING . @4 EOL
+
+ $default reduce using rule 10 (@4)
+
+ @4 go to state 18
+
+
+state 14
+
+ 3 section_or_include: VERSION STRING . EOL
+
+ EOL shift, and go to state 19
+
+
+state 15
+
+ 5 section_or_include: CONFIG SETUP EOL . @1 kw_section
+
+ $default reduce using rule 4 (@1)
+
+ @1 go to state 20
+
+
+state 16
+
+ 7 section_or_include: CONN STRING EOL . @2 kw_section
+
+ $default reduce using rule 6 (@2)
+
+ @2 go to state 21
+
+
+state 17
+
+ 9 section_or_include: CA STRING EOL . @3 kw_section
+
+ $default reduce using rule 8 (@3)
+
+ @3 go to state 22
+
+
+state 18
+
+ 11 section_or_include: INCLUDE STRING @4 . EOL
+
+ EOL shift, and go to state 23
+
+
+state 19
+
+ 3 section_or_include: VERSION STRING EOL .
+
+ $default reduce using rule 3 (section_or_include)
+
+
+state 20
+
+ 5 section_or_include: CONFIG SETUP EOL @1 . kw_section
+
+ FIRST_SPACES shift, and go to state 24
+
+ $default reduce using rule 14 (kw_section)
+
+ kw_section go to state 25
+
+
+state 21
+
+ 7 section_or_include: CONN STRING EOL @2 . kw_section
+
+ FIRST_SPACES shift, and go to state 24
+
+ $default reduce using rule 14 (kw_section)
+
+ kw_section go to state 26
+
+
+state 22
+
+ 9 section_or_include: CA STRING EOL @3 . kw_section
+
+ FIRST_SPACES shift, and go to state 24
+
+ $default reduce using rule 14 (kw_section)
+
+ kw_section go to state 27
+
+
+state 23
+
+ 11 section_or_include: INCLUDE STRING @4 EOL .
+
+ $default reduce using rule 11 (section_or_include)
+
+
+state 24
+
+ 13 kw_section: FIRST_SPACES . statement_kw EOL kw_section
+
+ STRING shift, and go to state 28
+
+ $default reduce using rule 17 (statement_kw)
+
+ statement_kw go to state 29
+
+
+state 25
+
+ 5 section_or_include: CONFIG SETUP EOL @1 kw_section .
+
+ $default reduce using rule 5 (section_or_include)
+
+
+state 26
+
+ 7 section_or_include: CONN STRING EOL @2 kw_section .
+
+ $default reduce using rule 7 (section_or_include)
+
+
+state 27
+
+ 9 section_or_include: CA STRING EOL @3 kw_section .
+
+ $default reduce using rule 9 (section_or_include)
+
+
+state 28
+
+ 15 statement_kw: STRING . EQUAL STRING
+ 16 | STRING . EQUAL
+
+ EQUAL shift, and go to state 30
+
+
+state 29
+
+ 13 kw_section: FIRST_SPACES statement_kw . EOL kw_section
+
+ EOL shift, and go to state 31
+
+
+state 30
+
+ 15 statement_kw: STRING EQUAL . STRING
+ 16 | STRING EQUAL .
+
+ STRING shift, and go to state 32
+
+ $default reduce using rule 16 (statement_kw)
+
+
+state 31
+
+ 13 kw_section: FIRST_SPACES statement_kw EOL . kw_section
+
+ FIRST_SPACES shift, and go to state 24
+
+ $default reduce using rule 14 (kw_section)
+
+ kw_section go to state 33
+
+
+state 32
+
+ 15 statement_kw: STRING EQUAL STRING .
+
+ $default reduce using rule 15 (statement_kw)
+
+
+state 33
+
+ 13 kw_section: FIRST_SPACES statement_kw EOL kw_section .
+
+ $default reduce using rule 13 (kw_section)
diff --git a/programs/starter/parser.tab.c b/programs/starter/parser.tab.c
new file mode 100644
index 000000000..bc21a2fd3
--- /dev/null
+++ b/programs/starter/parser.tab.c
@@ -0,0 +1,1666 @@
+/* A Bison parser, made by GNU Bison 2.1. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ 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, or (at your option)
+ any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ EQUAL = 258,
+ FIRST_SPACES = 259,
+ EOL = 260,
+ CONFIG = 261,
+ SETUP = 262,
+ CONN = 263,
+ CA = 264,
+ INCLUDE = 265,
+ VERSION = 266,
+ STRING = 267
+ };
+#endif
+/* Tokens. */
+#define EQUAL 258
+#define FIRST_SPACES 259
+#define EOL 260
+#define CONFIG 261
+#define SETUP 262
+#define CONN 263
+#define CA 264
+#define INCLUDE 265
+#define VERSION 266
+#define STRING 267
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "parser.y"
+
+/* strongSwan config file parser (parser.y)
+ * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: parser.tab.c,v 1.5 2006/03/28 22:32:49 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+#include "parser.h"
+
+#define YYERROR_VERBOSE
+#define ERRSTRING_LEN 256
+
+/**
+ * Bison
+ */
+static char parser_errstring[ERRSTRING_LEN+1];
+
+extern void yyerror(const char *s);
+extern int yylex (void);
+extern void _parser_y_error(char *b, int size, const char *s);
+
+/**
+ * Static Globals
+ */
+static int _save_errors_;
+static config_parsed_t *_parser_cfg;
+static kw_list_t **_parser_kw, *_parser_kw_last;
+static char errbuf[ERRSTRING_LEN+1];
+
+/**
+ * Gperf
+ */
+extern kw_entry_t *in_word_set (char *str, unsigned int len);
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 56 "parser.y"
+typedef union YYSTYPE { char *s; } YYSTYPE;
+/* Line 196 of yacc.c. */
+#line 166 "parser.tab.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 219 of yacc.c. */
+#line 178 "parser.tab.c"
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus))
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYINCLUDED_STDLIB_H
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1)
+# endif
+# ifdef __cplusplus
+extern "C" {
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \
+ && (defined (__STDC__) || defined (__cplusplus)))
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \
+ && (defined (__STDC__) || defined (__cplusplus)))
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifdef __cplusplus
+}
+# endif
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short int yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined (__GNUC__) && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 27
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 13
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 9
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 18
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 34
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 267
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned char yyprhs[] =
+{
+ 0, 0, 3, 6, 7, 11, 12, 18, 19, 25,
+ 26, 32, 33, 38, 40, 45, 46, 50, 53
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 14, 0, -1, 14, 15, -1, -1, 11, 12, 5,
+ -1, -1, 6, 7, 5, 16, 20, -1, -1, 8,
+ 12, 5, 17, 20, -1, -1, 9, 12, 5, 18,
+ 20, -1, -1, 10, 12, 19, 5, -1, 5, -1,
+ 4, 21, 5, 20, -1, -1, 12, 3, 12, -1,
+ 12, 3, -1, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned char yyrline[] =
+{
+ 0, 67, 67, 68, 72, 77, 76, 82, 81, 99,
+ 98, 115, 114, 120, 124, 125, 129, 154, 158
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "EQUAL", "FIRST_SPACES", "EOL", "CONFIG",
+ "SETUP", "CONN", "CA", "INCLUDE", "VERSION", "STRING", "$accept",
+ "config_file", "section_or_include", "@1", "@2", "@3", "@4",
+ "kw_section", "statement_kw", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short int yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 13, 14, 14, 15, 16, 15, 17, 15, 18,
+ 15, 19, 15, 15, 20, 20, 21, 21, 21
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 2, 0, 3, 0, 5, 0, 5, 0,
+ 5, 0, 4, 1, 4, 0, 3, 2, 0
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 3, 0, 1, 13, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 11, 0, 5, 7, 9, 0, 4,
+ 15, 15, 15, 12, 18, 6, 8, 10, 0, 0,
+ 17, 15, 16, 14
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+ -1, 1, 9, 20, 21, 22, 18, 25, 29
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -20
+static const yysigned_char yypact[] =
+{
+ -20, 0, -20, -20, -6, -8, -5, 1, 2, -20,
+ 10, 11, 12, -20, 13, -20, -20, -20, 14, -20,
+ 16, 16, 16, -20, 9, -20, -20, -20, 19, 18,
+ 15, 16, -20, -20
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -20, -20, -20, -20, -20, -20, -20, -19, -20
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+ 2, 10, 26, 27, 11, 3, 4, 12, 5, 6,
+ 7, 8, 33, 13, 14, 15, 16, 17, 19, 23,
+ 24, 28, 30, 31, 0, 0, 0, 32
+};
+
+static const yysigned_char yycheck[] =
+{
+ 0, 7, 21, 22, 12, 5, 6, 12, 8, 9,
+ 10, 11, 31, 12, 12, 5, 5, 5, 5, 5,
+ 4, 12, 3, 5, -1, -1, -1, 12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 14, 0, 5, 6, 8, 9, 10, 11, 15,
+ 7, 12, 12, 12, 12, 5, 5, 5, 19, 5,
+ 16, 17, 18, 5, 4, 20, 20, 20, 12, 21,
+ 3, 5, 12, 20
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (0)
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (N) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (0)
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short int *bottom;
+ short int *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ size_t yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+#endif /* YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+ ;
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short int yyssa[YYINITDEPTH];
+ short int *yyss = yyssa;
+ short int *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short int *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short int *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a look-ahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 73 "parser.y"
+ {
+ free((yyvsp[-1].s));
+ ;}
+ break;
+
+ case 5:
+#line 77 "parser.y"
+ {
+ _parser_kw = &(_parser_cfg->config_setup);
+ _parser_kw_last = NULL;
+ ;}
+ break;
+
+ case 7:
+#line 82 "parser.y"
+ {
+ section_list_t *section = (section_list_t *)alloc_thing(section_list_t
+ , "section_list_t");
+
+ section->name = clone_str((yyvsp[-1].s), "conn section name");
+ section->kw = NULL;
+ section->next = NULL;
+ _parser_kw = &(section->kw);
+ if (!_parser_cfg->conn_first)
+ _parser_cfg->conn_first = section;
+ if (_parser_cfg->conn_last)
+ _parser_cfg->conn_last->next = section;
+ _parser_cfg->conn_last = section;
+ _parser_kw_last = NULL;
+ free((yyvsp[-1].s));
+ ;}
+ break;
+
+ case 9:
+#line 99 "parser.y"
+ {
+ section_list_t *section = (section_list_t *)alloc_thing(section_list_t
+ , "section_list_t");
+ section->name = clone_str((yyvsp[-1].s), "ca section name");
+ section->kw = NULL;
+ section->next = NULL;
+ _parser_kw = &(section->kw);
+ if (!_parser_cfg->ca_first)
+ _parser_cfg->ca_first = section;
+ if (_parser_cfg->ca_last)
+ _parser_cfg->ca_last->next = section;
+ _parser_cfg->ca_last = section;
+ _parser_kw_last = NULL;
+ free((yyvsp[-1].s));
+ ;}
+ break;
+
+ case 11:
+#line 115 "parser.y"
+ {
+ extern void _parser_y_include (const char *f);
+ _parser_y_include((yyvsp[0].s));
+ free((yyvsp[0].s));
+ ;}
+ break;
+
+ case 16:
+#line 130 "parser.y"
+ {
+ kw_list_t *new;
+ kw_entry_t *entry = in_word_set((yyvsp[-2].s), strlen((yyvsp[-2].s)));
+
+ if (entry == NULL)
+ {
+ snprintf(errbuf, ERRSTRING_LEN, "unknown keyword '%s'", (yyvsp[-2].s));
+ yyerror(errbuf);
+ }
+ else if (_parser_kw)
+ {
+ new = (kw_list_t *)alloc_thing(kw_list_t, "kw_list_t");
+ new->entry = entry;
+ new->value = clone_str((yyvsp[0].s), "kw_list value");
+ new->next = NULL;
+ if (_parser_kw_last)
+ _parser_kw_last->next = new;
+ _parser_kw_last = new;
+ if (!*_parser_kw)
+ *_parser_kw = new;
+ }
+ free((yyvsp[-2].s));
+ free((yyvsp[0].s));
+ ;}
+ break;
+
+ case 17:
+#line 155 "parser.y"
+ {
+ free((yyvsp[-1].s));
+ ;}
+ break;
+
+
+ default: break;
+ }
+
+/* Line 1126 of yacc.c. */
+#line 1275 "parser.tab.c"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ char *yymsg = 0;
+# define YYERROR_VERBOSE_ARGS_MAXIMUM 5
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+#if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+#endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= yysize1 < yysize;
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= yysize1 < yysize;
+ yysize = yysize1;
+
+ if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM)
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyf))
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ goto yyexhaustedlab;
+ }
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror (YY_("syntax error"));
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding", yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (0)
+ goto yyerrorlab;
+
+yyvsp -= yylen;
+ yyssp -= yylen;
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping", yystos[yystate], yyvsp);
+ YYPOPSTACK;
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 161 "parser.y"
+
+
+void
+yyerror(const char *s)
+{
+ if (_save_errors_)
+ _parser_y_error(parser_errstring, ERRSTRING_LEN, s);
+}
+
+config_parsed_t *
+parser_load_conf(const char *file)
+{
+ config_parsed_t *cfg = NULL;
+ int err = 0;
+ FILE *f;
+
+ extern void _parser_y_init (const char *f);
+ extern FILE *yyin;
+
+ memset(parser_errstring, 0, ERRSTRING_LEN+1);
+
+ cfg = (config_parsed_t *)alloc_thing(config_parsed_t, "config_parsed_t");
+ if (cfg)
+ {
+ memset(cfg, 0, sizeof(config_parsed_t));
+ f = fopen(file, "r");
+ if (f)
+ {
+ yyin = f;
+ _parser_y_init(file);
+ _save_errors_ = 1;
+ _parser_cfg = cfg;
+
+ if (yyparse() !=0 )
+ {
+ if (parser_errstring[0] == '\0')
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "Unknown error...");
+ }
+ _save_errors_ = 0;
+ while (yyparse() != 0);
+ err++;
+ }
+ else if (parser_errstring[0] != '\0')
+ {
+ err++;
+ }
+ else
+ {
+ /**
+ * Config valid
+ */
+ }
+
+ fclose(f);
+ }
+ else
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "can't load file '%s'", file);
+ err++;
+ }
+ }
+ else
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "can't allocate memory");
+ err++;
+ }
+
+ if (err)
+ {
+ plog("%s", parser_errstring);
+
+ if (cfg)
+ parser_free_conf(cfg);
+ cfg = NULL;
+ }
+
+ return cfg;
+}
+
+static void
+parser_free_kwlist(kw_list_t *list)
+{
+ kw_list_t *elt;
+
+ while (list)
+ {
+ elt = list;
+ list = list->next;
+ if (elt->value)
+ pfree(elt->value);
+ pfree(elt);
+ }
+}
+
+void
+parser_free_conf(config_parsed_t *cfg)
+{
+ section_list_t *sec;
+ if (cfg)
+ {
+ parser_free_kwlist(cfg->config_setup);
+ while (cfg->conn_first)
+ {
+ sec = cfg->conn_first;
+ cfg->conn_first = cfg->conn_first->next;
+ if (sec->name)
+ pfree(sec->name);
+ parser_free_kwlist(sec->kw);
+ pfree(sec);
+ }
+ while (cfg->ca_first)
+ {
+ sec = cfg->ca_first;
+ cfg->ca_first = cfg->ca_first->next;
+ if (sec->name)
+ pfree(sec->name);
+ parser_free_kwlist(sec->kw);
+ pfree(sec);
+ }
+ pfree(cfg);
+ }
+}
+
diff --git a/programs/starter/parser.tab.h b/programs/starter/parser.tab.h
new file mode 100644
index 000000000..1ded28fdb
--- /dev/null
+++ b/programs/starter/parser.tab.h
@@ -0,0 +1,72 @@
+/* A Bison parser, made by GNU Bison 2.1. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+ 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, or (at your option)
+ any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ EQUAL = 258,
+ FIRST_SPACES = 259,
+ EOL = 260,
+ CONFIG = 261,
+ SETUP = 262,
+ CONN = 263,
+ CA = 264,
+ INCLUDE = 265,
+ VERSION = 266,
+ STRING = 267
+ };
+#endif
+/* Tokens. */
+#define EQUAL 258
+#define FIRST_SPACES 259
+#define EOL 260
+#define CONFIG 261
+#define SETUP 262
+#define CONN 263
+#define CA 264
+#define INCLUDE 265
+#define VERSION 266
+#define STRING 267
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 56 "parser.y"
+typedef union YYSTYPE { char *s; } YYSTYPE;
+/* Line 1447 of yacc.c. */
+#line 64 "parser.tab.h"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
+
+
diff --git a/programs/starter/parser.y b/programs/starter/parser.y
new file mode 100644
index 000000000..159bbc651
--- /dev/null
+++ b/programs/starter/parser.y
@@ -0,0 +1,283 @@
+%{
+/* strongSwan config file parser (parser.y)
+ * Copyright (C) 2001 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: parser.y,v 1.6 2006/01/17 23:43:36 as Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+#include "parser.h"
+
+#define YYERROR_VERBOSE
+#define ERRSTRING_LEN 256
+
+/**
+ * Bison
+ */
+static char parser_errstring[ERRSTRING_LEN+1];
+
+extern void yyerror(const char *s);
+extern int yylex (void);
+extern void _parser_y_error(char *b, int size, const char *s);
+
+/**
+ * Static Globals
+ */
+static int _save_errors_;
+static config_parsed_t *_parser_cfg;
+static kw_list_t **_parser_kw, *_parser_kw_last;
+static char errbuf[ERRSTRING_LEN+1];
+
+/**
+ * Gperf
+ */
+extern kw_entry_t *in_word_set (char *str, unsigned int len);
+
+%}
+
+%union { char *s; };
+%token EQUAL FIRST_SPACES EOL CONFIG SETUP CONN CA INCLUDE VERSION
+%token <s> STRING
+
+%%
+
+/*
+ * Config file
+ */
+
+config_file:
+ config_file section_or_include
+ | /* NULL */
+ ;
+
+section_or_include:
+ VERSION STRING EOL
+ {
+ free($2);
+ }
+ | CONFIG SETUP EOL
+ {
+ _parser_kw = &(_parser_cfg->config_setup);
+ _parser_kw_last = NULL;
+ } kw_section
+ | CONN STRING EOL
+ {
+ section_list_t *section = (section_list_t *)alloc_thing(section_list_t
+ , "section_list_t");
+
+ section->name = clone_str($2, "conn section name");
+ section->kw = NULL;
+ section->next = NULL;
+ _parser_kw = &(section->kw);
+ if (!_parser_cfg->conn_first)
+ _parser_cfg->conn_first = section;
+ if (_parser_cfg->conn_last)
+ _parser_cfg->conn_last->next = section;
+ _parser_cfg->conn_last = section;
+ _parser_kw_last = NULL;
+ free($2);
+ } kw_section
+ | CA STRING EOL
+ {
+ section_list_t *section = (section_list_t *)alloc_thing(section_list_t
+ , "section_list_t");
+ section->name = clone_str($2, "ca section name");
+ section->kw = NULL;
+ section->next = NULL;
+ _parser_kw = &(section->kw);
+ if (!_parser_cfg->ca_first)
+ _parser_cfg->ca_first = section;
+ if (_parser_cfg->ca_last)
+ _parser_cfg->ca_last->next = section;
+ _parser_cfg->ca_last = section;
+ _parser_kw_last = NULL;
+ free($2);
+ } kw_section
+ | INCLUDE STRING
+ {
+ extern void _parser_y_include (const char *f);
+ _parser_y_include($2);
+ free($2);
+ } EOL
+ | EOL
+ ;
+
+kw_section:
+ FIRST_SPACES statement_kw EOL kw_section
+ |
+ ;
+
+statement_kw:
+ STRING EQUAL STRING
+ {
+ kw_list_t *new;
+ kw_entry_t *entry = in_word_set($1, strlen($1));
+
+ if (entry == NULL)
+ {
+ snprintf(errbuf, ERRSTRING_LEN, "unknown keyword '%s'", $1);
+ yyerror(errbuf);
+ }
+ else if (_parser_kw)
+ {
+ new = (kw_list_t *)alloc_thing(kw_list_t, "kw_list_t");
+ new->entry = entry;
+ new->value = clone_str($3, "kw_list value");
+ new->next = NULL;
+ if (_parser_kw_last)
+ _parser_kw_last->next = new;
+ _parser_kw_last = new;
+ if (!*_parser_kw)
+ *_parser_kw = new;
+ }
+ free($1);
+ free($3);
+ }
+ | STRING EQUAL
+ {
+ free($1);
+ }
+ |
+ ;
+
+%%
+
+void
+yyerror(const char *s)
+{
+ if (_save_errors_)
+ _parser_y_error(parser_errstring, ERRSTRING_LEN, s);
+}
+
+config_parsed_t *
+parser_load_conf(const char *file)
+{
+ config_parsed_t *cfg = NULL;
+ int err = 0;
+ FILE *f;
+
+ extern void _parser_y_init (const char *f);
+ extern FILE *yyin;
+
+ memset(parser_errstring, 0, ERRSTRING_LEN+1);
+
+ cfg = (config_parsed_t *)alloc_thing(config_parsed_t, "config_parsed_t");
+ if (cfg)
+ {
+ memset(cfg, 0, sizeof(config_parsed_t));
+ f = fopen(file, "r");
+ if (f)
+ {
+ yyin = f;
+ _parser_y_init(file);
+ _save_errors_ = 1;
+ _parser_cfg = cfg;
+
+ if (yyparse() !=0 )
+ {
+ if (parser_errstring[0] == '\0')
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "Unknown error...");
+ }
+ _save_errors_ = 0;
+ while (yyparse() != 0);
+ err++;
+ }
+ else if (parser_errstring[0] != '\0')
+ {
+ err++;
+ }
+ else
+ {
+ /**
+ * Config valid
+ */
+ }
+
+ fclose(f);
+ }
+ else
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "can't load file '%s'", file);
+ err++;
+ }
+ }
+ else
+ {
+ snprintf(parser_errstring, ERRSTRING_LEN, "can't allocate memory");
+ err++;
+ }
+
+ if (err)
+ {
+ plog("%s", parser_errstring);
+
+ if (cfg)
+ parser_free_conf(cfg);
+ cfg = NULL;
+ }
+
+ return cfg;
+}
+
+static void
+parser_free_kwlist(kw_list_t *list)
+{
+ kw_list_t *elt;
+
+ while (list)
+ {
+ elt = list;
+ list = list->next;
+ if (elt->value)
+ pfree(elt->value);
+ pfree(elt);
+ }
+}
+
+void
+parser_free_conf(config_parsed_t *cfg)
+{
+ section_list_t *sec;
+ if (cfg)
+ {
+ parser_free_kwlist(cfg->config_setup);
+ while (cfg->conn_first)
+ {
+ sec = cfg->conn_first;
+ cfg->conn_first = cfg->conn_first->next;
+ if (sec->name)
+ pfree(sec->name);
+ parser_free_kwlist(sec->kw);
+ pfree(sec);
+ }
+ while (cfg->ca_first)
+ {
+ sec = cfg->ca_first;
+ cfg->ca_first = cfg->ca_first->next;
+ if (sec->name)
+ pfree(sec->name);
+ parser_free_kwlist(sec->kw);
+ pfree(sec);
+ }
+ pfree(cfg);
+ }
+}
diff --git a/programs/starter/starter.8 b/programs/starter/starter.8
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/programs/starter/starter.8
diff --git a/programs/starter/starter.c b/programs/starter/starter.c
new file mode 100644
index 000000000..0b2c83369
--- /dev/null
+++ b/programs/starter/starter.c
@@ -0,0 +1,571 @@
+/* strongSwan IPsec starter
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: starter.c,v 1.23 2006/02/15 18:37:46 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+
+#include "confread.h"
+#include "files.h"
+#include "starterwhack.h"
+#include "invokepluto.h"
+#include "klips.h"
+#include "netkey.h"
+#include "cmp.h"
+#include "interfaces.h"
+
+#define FLAG_ACTION_START_PLUTO 0x01
+#define FLAG_ACTION_UPDATE 0x02
+#define FLAG_ACTION_RELOAD 0x04
+#define FLAG_ACTION_QUIT 0x08
+#define FLAG_ACTION_LISTEN 0x10
+
+static unsigned int _action_ = 0;
+
+static void
+fsig(int signal)
+{
+ switch (signal)
+ {
+ case SIGCHLD:
+ {
+ int status;
+ pid_t pid;
+ char *name = NULL;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+ {
+ if (pid == starter_pluto_pid())
+ name = " (Pluto)";
+ if (WIFSIGNALED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has been killed by sig %d\n",
+ pid, name?name:"", WTERMSIG(status))
+ )
+ else if (WIFSTOPPED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has been stopped by sig %d\n",
+ pid, name?name:"", WSTOPSIG(status))
+ )
+ else if (WIFEXITED(status))
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has quit (exit code %d)\n",
+ pid, name?name:"", WEXITSTATUS(status))
+ )
+ else
+ DBG(DBG_CONTROL,
+ DBG_log("child %d%s has quit", pid, name?name:"")
+ )
+
+ if (pid == starter_pluto_pid())
+ starter_pluto_sigchild(pid);
+ }
+ }
+ break;
+
+ case SIGPIPE:
+ /** ignore **/
+ break;
+
+ case SIGALRM:
+ _action_ |= FLAG_ACTION_START_PLUTO;
+ break;
+
+ case SIGHUP:
+ _action_ |= FLAG_ACTION_UPDATE;
+ break;
+
+ case SIGTERM:
+ case SIGQUIT:
+ case SIGINT:
+ _action_ |= FLAG_ACTION_QUIT;
+ break;
+
+ case SIGUSR1:
+ _action_ |= FLAG_ACTION_RELOAD;
+ _action_ |= FLAG_ACTION_UPDATE;
+ break;
+
+ default:
+ plog("fsig(): unknown signal %d -- investigate", signal);
+ break;
+ }
+}
+
+static void
+usage(char *name)
+{
+ fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] "
+ "[--debug|--debug-more|--debug-all]\n");
+ exit(1);
+}
+
+int main (int argc, char **argv)
+{
+ starter_config_t *cfg = NULL;
+ starter_config_t *new_cfg;
+ starter_conn_t *conn, *conn2;
+ starter_ca_t *ca, *ca2;
+
+ struct stat stb;
+
+ char *err = NULL;
+ int i;
+ int id = 1;
+ struct timeval tv;
+ unsigned long auto_update = 0;
+ time_t last_reload;
+ bool has_netkey;
+ bool no_fork = FALSE;
+
+ /* global variables defined in log.h */
+ log_to_stderr = TRUE;
+ base_debugging = DBG_NONE;
+
+ /* parse command line */
+ for (i = 1; i < argc; i++)
+ {
+ if (streq(argv[i], "--debug"))
+ {
+ base_debugging |= DBG_CONTROL;
+ }
+ else if (streq(argv[i], "--debug-more"))
+ {
+ base_debugging |= DBG_CONTROLMORE;
+ }
+ else if (streq(argv[i], "--debug-all"))
+ {
+ base_debugging |= DBG_ALL;
+ }
+ else if (streq(argv[i], "--nofork"))
+ {
+ no_fork = TRUE;
+ }
+ else if (streq(argv[i], "--auto-update") && i+1 < argc)
+ {
+ auto_update = atoi(argv[++i]);
+ if (!auto_update)
+ usage(argv[0]);
+ }
+ else
+ {
+ usage(argv[0]);
+ }
+ }
+
+ /* Init */
+ init_log("ipsec_starter");
+ cur_debugging = base_debugging;
+
+ signal(SIGHUP, fsig);
+ signal(SIGCHLD, fsig);
+ signal(SIGPIPE, fsig);
+ signal(SIGINT, fsig);
+ signal(SIGTERM, fsig);
+ signal(SIGQUIT, fsig);
+ signal(SIGALRM, fsig);
+ signal(SIGUSR1, fsig);
+
+ /* verify that we can start */
+ if (getuid() != 0)
+ {
+ plog("permission denied (must be superuser)");
+ exit(1);
+ }
+
+ if (stat(PID_FILE, &stb) == 0)
+ {
+ plog("pluto is already running (%s exists) -- aborting", PID_FILE);
+ exit(1);
+ }
+
+ if (stat(DEV_RANDOM, &stb) != 0)
+ {
+ plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM);
+ exit(1);
+ }
+
+ if (stat(DEV_URANDOM, &stb)!= 0)
+ {
+ plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM);
+ exit(1);
+ }
+
+ cfg = confread_load(CONFIG_FILE);
+ if (!cfg)
+ {
+ plog("unable to start strongSwan -- errors in config");
+ exit(1);
+ }
+
+ /* determine if we have a native netkey IPsec stack */
+ has_netkey = starter_netkey_init();
+
+ if (!has_netkey)
+ {
+ /* determine if we have a KLIPS IPsec stack instead */
+ if (starter_klips_init())
+ {
+ starter_klips_set_config(cfg);
+ starter_ifaces_init();
+ starter_ifaces_clear();
+ }
+ else
+ {
+ plog("neither netkey nor KLIPS IPSec stack detected");
+ exit(1);
+ }
+ }
+
+ last_reload = time(NULL);
+
+ plog("Starting strongSwan IPsec %s [starter]...", ipsec_version_code());
+
+ /* fork if we're not debugging stuff */
+ if (!no_fork)
+ {
+ log_to_stderr = FALSE;
+
+ switch (fork())
+ {
+ case 0:
+ {
+ int fnull = open("/dev/null", O_RDWR);
+
+ if (fnull >= 0)
+ {
+ dup2(fnull, STDIN_FILENO);
+ dup2(fnull, STDOUT_FILENO);
+ dup2(fnull, STDERR_FILENO);
+ close(fnull);
+ }
+ }
+ break;
+ case -1:
+ plog("can't fork: %s", strerror(errno));
+ break;
+ default:
+ exit(0);
+ }
+ }
+
+ /* save pid file in /var/run/starter.pid */
+ {
+ FILE *fd = fopen(MY_PID_FILE, "w");
+
+ if (fd)
+ {
+ fprintf(fd, "%u\n", getpid());
+ fclose(fd);
+ }
+ }
+
+ if (!has_netkey)
+ {
+ starter_ifaces_load(cfg->setup.interfaces
+ , cfg->setup.overridemtu
+ , cfg->setup.nat_traversal
+ , &cfg->defaultroute);
+ }
+
+ _action_ = FLAG_ACTION_START_PLUTO;
+
+ for (;;)
+ {
+ /*
+ * Stop pluto (if started) and exit
+ */
+ if (_action_ & FLAG_ACTION_QUIT)
+ {
+ if (starter_pluto_pid())
+ starter_stop_pluto();
+ if (has_netkey)
+ starter_netkey_cleanup();
+ else
+ {
+ starter_ifaces_clear();
+ starter_klips_cleanup();
+ }
+ confread_free(cfg);
+ unlink(MY_PID_FILE);
+ unlink(INFO_FILE);
+#ifdef LEAK_DETECTIVE
+ report_leaks();
+#endif /* LEAK_DETECTIVE */
+ close_log();
+ plog("ipsec starter stopped");
+ exit(0);
+ }
+
+ /*
+ * Delete all connections. Will be added below
+ */
+ if (_action_ & FLAG_ACTION_RELOAD)
+ {
+ if (starter_pluto_pid())
+ {
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ {
+ starter_whack_del_conn(conn);
+ conn->state = STATE_TO_ADD;
+ }
+ }
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ {
+ starter_whack_del_ca(ca);
+ ca->state = STATE_TO_ADD;
+ }
+ }
+ }
+ _action_ &= ~FLAG_ACTION_RELOAD;
+ }
+
+ /*
+ * Update configuration
+ */
+ if (_action_ & FLAG_ACTION_UPDATE)
+ {
+ err = NULL;
+ DBG(DBG_CONTROL,
+ DBG_log("Reloading config...")
+ )
+ new_cfg = confread_load(CONFIG_FILE);
+
+ if (new_cfg)
+ {
+ /* Switch to new config. New conn will be loaded below */
+ if (has_netkey)
+ {
+ if (!starter_cmp_defaultroute(&new_cfg->defaultroute
+ , &cfg->defaultroute))
+ {
+ _action_ |= FLAG_ACTION_LISTEN;
+ }
+ }
+ else
+ {
+ if (!starter_cmp_klips(cfg, new_cfg))
+ {
+ plog("KLIPS has changed");
+ starter_klips_set_config(new_cfg);
+ }
+
+ if (starter_ifaces_load(new_cfg->setup.interfaces
+ , new_cfg->setup.overridemtu
+ , new_cfg->setup.nat_traversal
+ , &new_cfg->defaultroute))
+ {
+ _action_ |= FLAG_ACTION_LISTEN;
+ }
+ }
+
+ if (!starter_cmp_pluto(cfg, new_cfg))
+ {
+ plog("Pluto has changed");
+ if (starter_pluto_pid())
+ starter_stop_pluto();
+ _action_ &= ~FLAG_ACTION_LISTEN;
+ _action_ |= FLAG_ACTION_START_PLUTO;
+ }
+ else
+ {
+ /* Only reload conn and ca sections if pluto is not killed */
+
+ /* Look for new connections that are already loaded */
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ {
+ for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next)
+ {
+ if (conn2->state == STATE_TO_ADD
+ && starter_cmp_conn(conn, conn2))
+ {
+ conn->state = STATE_REPLACED;
+ conn2->state = STATE_ADDED;
+ conn2->id = conn->id;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Remove conn sections that have become unused */
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ starter_whack_del_conn(conn);
+ }
+
+ /* Look for new ca sections that are already loaded */
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ {
+ for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next)
+ {
+ if (ca2->state == STATE_TO_ADD
+ && starter_cmp_ca(ca, ca2))
+ {
+ ca->state = STATE_REPLACED;
+ ca2->state = STATE_ADDED;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Remove ca sections that have become unused */
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ starter_whack_del_ca(ca);
+ }
+ }
+ confread_free(cfg);
+ cfg = new_cfg;
+ }
+ else
+ {
+ plog("can't reload config file: %s -- keeping old one");
+ }
+ _action_ &= ~FLAG_ACTION_UPDATE;
+ last_reload = time(NULL);
+ }
+
+ /*
+ * Start pluto
+ */
+ if (_action_ & FLAG_ACTION_START_PLUTO)
+ {
+ if (starter_pluto_pid() == 0)
+ {
+ DBG(DBG_CONTROL,
+ DBG_log("Attempting to start pluto...")
+ )
+ if (!has_netkey)
+ starter_klips_clear();
+
+ if (starter_start_pluto(cfg, no_fork) == 0)
+ {
+ starter_whack_listen();
+ }
+ else
+ {
+ /* schedule next try */
+ alarm(PLUTO_RESTART_DELAY);
+ }
+ }
+ _action_ &= ~FLAG_ACTION_START_PLUTO;
+
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_ADDED)
+ ca->state = STATE_TO_ADD;
+ }
+
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_ADDED)
+ conn->state = STATE_TO_ADD;
+ }
+ }
+
+ /*
+ * Tell pluto to reread its interfaces
+ */
+ if (_action_ & FLAG_ACTION_LISTEN)
+ {
+ starter_whack_listen();
+ _action_ &= ~FLAG_ACTION_LISTEN;
+ }
+
+ /*
+ * Add stale conn and ca sections
+ */
+ if (starter_pluto_pid() != 0)
+ {
+ for (ca = cfg->ca_first; ca; ca = ca->next)
+ {
+ if (ca->state == STATE_TO_ADD)
+ {
+ starter_whack_add_ca(ca);
+ ca->state = STATE_ADDED;
+ }
+ }
+
+ for (conn = cfg->conn_first; conn; conn = conn->next)
+ {
+ if (conn->state == STATE_TO_ADD)
+ {
+ if (conn->id == 0)
+ {
+ /* affect new unique id */
+ conn->id = id++;
+ }
+ starter_whack_add_conn(conn);
+ conn->state = STATE_ADDED;
+ if (conn->startup == STARTUP_START)
+ starter_whack_initiate_conn(conn);
+ else if (conn->startup == STARTUP_ROUTE)
+ starter_whack_route_conn(conn);
+ }
+ }
+ }
+
+ /*
+ * If auto_update activated, when to stop select
+ */
+ if (auto_update)
+ {
+ time_t now = time(NULL);
+ tv.tv_sec = (now < last_reload + auto_update)
+ ? (last_reload + auto_update-now) : 0;
+ tv.tv_usec = 0;
+ }
+
+ /*
+ * Wait for something to happen
+ */
+ if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0)
+ {
+ /* timeout -> auto_update */
+ _action_ |= FLAG_ACTION_UPDATE;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/programs/starter/starterwhack.c b/programs/starter/starterwhack.c
new file mode 100644
index 000000000..a671c560c
--- /dev/null
+++ b/programs/starter/starterwhack.c
@@ -0,0 +1,371 @@
+/* strongSwan whack functions to communicate with pluto (whack.c)
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: starterwhack.c,v 1.17 2006/04/17 10:32:36 as Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <linux/stddef.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <freeswan.h>
+
+#include "../pluto/constants.h"
+#include "../pluto/defs.h"
+#include "../pluto/log.h"
+#include "../pluto/whack.h"
+
+#include "starterwhack.h"
+#include "confread.h"
+#include "files.h"
+
+static int
+pack_str (char **p, char **next, char **roof)
+{
+ const char *s = (*p==NULL) ? "" : *p; /* note: NULL becomes ""! */
+ size_t len = strlen(s) + 1;
+
+ if ((*roof - *next) < len)
+ {
+ return 0; /* not enough space */
+ }
+ else
+ {
+ strcpy(*next, s);
+ *next += len;
+ *p = NULL; /* don't send pointers on the wire! */
+ return 1;
+ }
+}
+
+static int
+send_whack_msg (whack_message_t *msg)
+{
+ struct sockaddr_un ctl_addr = { AF_UNIX, CTL_FILE };
+ int sock;
+ ssize_t len;
+ char *str_next, *str_roof;
+
+ /* pack strings */
+ str_next = (char *)msg->string;
+ str_roof = (char *)&msg->string[sizeof(msg->string)];
+
+ if (!pack_str(&msg->name, &str_next, &str_roof)
+ || !pack_str(&msg->left.id, &str_next, &str_roof)
+ || !pack_str(&msg->left.cert, &str_next, &str_roof)
+ || !pack_str(&msg->left.ca, &str_next, &str_roof)
+ || !pack_str(&msg->left.groups, &str_next, &str_roof)
+ || !pack_str(&msg->left.updown, &str_next, &str_roof)
+#ifdef VIRTUAL_IP
+ || !pack_str(&msg->left.virt, &str_next, &str_roof)
+#endif
+ || !pack_str(&msg->right.id, &str_next, &str_roof)
+ || !pack_str(&msg->right.cert, &str_next, &str_roof)
+ || !pack_str(&msg->right.ca, &str_next, &str_roof)
+ || !pack_str(&msg->right.groups, &str_next, &str_roof)
+ || !pack_str(&msg->right.updown, &str_next, &str_roof)
+#ifdef VIRTUAL_IP
+ || !pack_str(&msg->right.virt, &str_next, &str_roof)
+#endif
+ || !pack_str(&msg->keyid, &str_next, &str_roof)
+ || !pack_str(&msg->myid, &str_next, &str_roof)
+ || !pack_str(&msg->cacert, &str_next, &str_roof)
+ || !pack_str(&msg->ldaphost, &str_next, &str_roof)
+ || !pack_str(&msg->ldapbase, &str_next, &str_roof)
+ || !pack_str(&msg->crluri, &str_next, &str_roof)
+ || !pack_str(&msg->crluri2, &str_next, &str_roof)
+ || !pack_str(&msg->ocspuri, &str_next, &str_roof)
+ || !pack_str(&msg->ike, &str_next, &str_roof)
+ || !pack_str(&msg->esp, &str_next, &str_roof)
+ || !pack_str(&msg->sc_data, &str_next, &str_roof)
+ || (str_roof - str_next < msg->keyval.len))
+ {
+ plog("send_wack_msg(): can't pack strings");
+ return -1;
+ }
+ if (msg->keyval.ptr)
+ memcpy(str_next, msg->keyval.ptr, msg->keyval.len);
+ msg->keyval.ptr = NULL;
+ str_next += msg->keyval.len;
+ len = str_next - (char *)msg;
+
+ /* connect to pluto ctl */
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ plog("socket() failed: %s", strerror(errno));
+ return -1;
+ }
+ if (connect(sock, (struct sockaddr *)&ctl_addr,
+ offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
+ {
+ plog("connect(pluto_ctl) failed: %s", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ /* send message */
+ if (write(sock, msg, len) != len)
+ {
+ plog("write(pluto_ctl) failed: %s", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ /* TODO: read reply */
+ close(sock);
+ return 0;
+}
+
+static void
+init_whack_msg(whack_message_t *msg)
+{
+ memset(msg, 0, sizeof(whack_message_t));
+ msg->magic = WHACK_MAGIC;
+}
+
+static char *
+connection_name(starter_conn_t *conn)
+{
+ /* if connection name is '%auto', create a new name like conn_xxxxx */
+ static char buf[32];
+
+ if (streq(conn->name, "%auto"))
+ {
+ sprintf(buf, "conn_%ld", conn->id);
+ return buf;
+ }
+ return conn->name;
+}
+
+static void
+set_whack_end(whack_end_t *w, starter_end_t *end)
+{
+ w->id = end->id;
+ w->cert = end->cert;
+ w->ca = end->ca;
+ w->groups = end->groups;
+ w->host_addr = end->addr;
+ w->host_nexthop = end->nexthop;
+ w->host_srcip = end->srcip;
+
+ if (end->has_client)
+ w->client = end->subnet;
+ else
+ w->client.addr.u.v4.sin_family = AF_INET;
+
+ w->has_client = end->has_client;
+ w->has_client_wildcard = end->has_client_wildcard;
+ w->has_port_wildcard = end->has_port_wildcard;
+ w->has_srcip = end->has_srcip;
+ w->modecfg = end->modecfg;
+ w->hostaccess = end->hostaccess;
+ w->sendcert = end->sendcert;
+ w->updown = end->updown;
+ w->host_port = IKE_UDP_PORT;
+ w->port = end->port;
+ w->protocol = end->protocol;
+ w->virt = end->virt;
+
+ if (w->port != 0)
+ {
+ int port = htons(w->port);
+
+ setportof(port, &w->host_addr);
+ setportof(port, &w->client.addr);
+ }
+}
+
+static int
+starter_whack_add_pubkey (starter_conn_t *conn, starter_end_t *end
+, const char *lr)
+{
+ const char *err;
+ static char keyspace[1024 + 4];
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+
+ msg.whack_key = TRUE;
+ msg.pubkey_alg = PUBKEY_ALG_RSA;
+ if (end->id && end->rsakey)
+ {
+ /* special values to ignore */
+ if (streq(end->rsakey, "")
+ || streq(end->rsakey, "%none")
+ || streq(end->rsakey, "%cert")
+ || streq(end->rsakey, "0x00"))
+ {
+ return 0;
+ }
+ msg.keyid = end->id;
+ err = atobytes(end->rsakey, 0, keyspace, sizeof(keyspace), &msg.keyval.len);
+ if (err)
+ {
+ plog("conn %s/%s: rsakey malformed [%s]", connection_name(conn), lr, err);
+ return 1;
+ }
+ else
+ {
+ msg.keyval.ptr = keyspace;
+ return send_whack_msg(&msg);
+ }
+ }
+ return 0;
+}
+
+int
+starter_whack_add_conn(starter_conn_t *conn)
+{
+ whack_message_t msg;
+ int r;
+
+ init_whack_msg(&msg);
+
+ msg.whack_connection = TRUE;
+ msg.name = connection_name(conn);
+
+ msg.addr_family = conn->addr_family;
+ msg.tunnel_addr_family = conn->tunnel_addr_family;
+ msg.sa_ike_life_seconds = conn->sa_ike_life_seconds;
+ msg.sa_ipsec_life_seconds = conn->sa_ipsec_life_seconds;
+ msg.sa_rekey_margin = conn->sa_rekey_margin;
+ msg.sa_rekey_fuzz = conn->sa_rekey_fuzz;
+ msg.sa_keying_tries = conn->sa_keying_tries;
+ msg.policy = conn->policy;
+
+ set_whack_end(&msg.left, &conn->left);
+ set_whack_end(&msg.right, &conn->right);
+
+ msg.esp = conn->esp;
+ msg.ike = conn->ike;
+ msg.pfsgroup = conn->pfsgroup;
+
+ /* taken from pluto/whack.c */
+ if (msg.pfsgroup)
+ {
+ char esp_buf[256];
+
+ snprintf(esp_buf, sizeof (esp_buf), "%s;%s"
+ , msg.esp ? msg.esp : ""
+ , msg.pfsgroup ? msg.pfsgroup : "");
+ msg.esp = esp_buf;
+
+ DBG(DBG_CONTROL,
+ DBG_log("Setting --esp=%s", msg.esp)
+ )
+ }
+ msg.dpd_delay = conn->dpd_delay;
+ msg.dpd_timeout = conn->dpd_timeout;
+ msg.dpd_action = conn->dpd_action;
+/* msg.dpd_count = conn->dpd_count; not supported yet by strongSwan */
+
+ r = send_whack_msg(&msg);
+
+ if (r == 0 && (conn->policy & POLICY_RSASIG))
+ {
+ r += starter_whack_add_pubkey (conn, &conn->left, "left");
+ r += starter_whack_add_pubkey (conn, &conn->right, "right");
+ }
+
+ return r;
+}
+
+int
+starter_whack_del_conn(starter_conn_t *conn)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+ msg.whack_delete = TRUE;
+ msg.name = connection_name(conn);
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_route_conn(starter_conn_t *conn)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+ msg.whack_route = TRUE;
+ msg.name = connection_name(conn);
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_initiate_conn(starter_conn_t *conn)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+ msg.whack_initiate = TRUE;
+ msg.whack_async = TRUE;
+ msg.name = connection_name(conn);
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_listen(void)
+{
+ whack_message_t msg;
+ init_whack_msg(&msg);
+ msg.whack_listen = TRUE;
+ return send_whack_msg(&msg);
+}
+
+int starter_whack_shutdown(void)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+ msg.whack_shutdown = TRUE;
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_add_ca(starter_ca_t *ca)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+
+ msg.whack_ca = TRUE;
+ msg.name = ca->name;
+ msg.cacert = ca->cacert;
+ msg.ldaphost = ca->ldaphost;
+ msg.ldapbase = ca->ldapbase;
+ msg.crluri = ca->crluri;
+ msg.crluri2 = ca->crluri2;
+ msg.ocspuri = ca->ocspuri;
+ msg.whack_strict = ca->strict;
+
+ return send_whack_msg(&msg);
+}
+
+int
+starter_whack_del_ca(starter_ca_t *ca)
+{
+ whack_message_t msg;
+
+ init_whack_msg(&msg);
+
+ msg.whack_delete = TRUE;
+ msg.whack_ca = TRUE;
+ msg.name = ca->name;
+
+ return send_whack_msg(&msg);
+}
diff --git a/programs/starter/starterwhack.h b/programs/starter/starterwhack.h
new file mode 100644
index 000000000..2e79c0715
--- /dev/null
+++ b/programs/starter/starterwhack.h
@@ -0,0 +1,32 @@
+/* FreeS/WAN whack functions to communicate with pluto (whack.h)
+ * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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: starterwhack.h,v 1.6 2006/01/03 18:37:03 as Exp $
+ */
+
+#ifndef _STARTER_WHACK_H_
+#define _STARTER_WHACK_H_
+
+#include "confread.h"
+
+extern int starter_whack_add_conn(starter_conn_t *conn);
+extern int starter_whack_del_conn(starter_conn_t *conn);
+extern int starter_whack_route_conn(starter_conn_t *conn);
+extern int starter_whack_initiate_conn(starter_conn_t *conn);
+extern int starter_whack_listen(void);
+extern int starter_whack_shutdown(void);
+extern int starter_whack_add_ca(starter_ca_t *ca);
+extern int starter_whack_del_ca(starter_ca_t *ca);
+
+#endif /* _STARTER_WHACK_H_ */
+
diff --git a/programs/tncfg/.cvsignore b/programs/tncfg/.cvsignore
new file mode 100644
index 000000000..c05ca8d9a
--- /dev/null
+++ b/programs/tncfg/.cvsignore
@@ -0,0 +1 @@
+tncfg
diff --git a/programs/tncfg/Makefile b/programs/tncfg/Makefile
new file mode 100644
index 000000000..ded364dbf
--- /dev/null
+++ b/programs/tncfg/Makefile
@@ -0,0 +1,52 @@
+# Makefile for the KLIPS interface utilities
+# Copyright (C) 1998, 1999 Henry Spencer.
+# Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# RCSID $Id: Makefile,v 1.1 2004/03/15 20:35:31 as Exp $
+
+FREESWANSRCDIR=../..
+include ${FREESWANSRCDIR}/Makefile.inc
+
+PROGRAM:=tncfg
+EXTRA5PROC=${PROGRAM}.5
+
+LIBS:=${FREESWANLIB}
+
+include ../Makefile.program
+
+#
+# $Log: Makefile,v $
+# 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/tncfg/tncfg.5 b/programs/tncfg/tncfg.5
new file mode 100644
index 000000000..e4de862c6
--- /dev/null
+++ b/programs/tncfg/tncfg.5
@@ -0,0 +1,109 @@
+.TH IPSEC_TNCFG 5 "27 Jun 2000"
+.\"
+.\" RCSID $Id: tncfg.5,v 1.1 2004/03/15 20:35:31 as Exp $
+.\"
+.SH NAME
+ipsec_tncfg \- lists IPSEC virtual interfaces attached to real interfaces
+.SH SYNOPSIS
+.B ipsec
+.B tncfg
+.PP
+.B cat
+.B /proc/net/ipsec_tncfg
+.SH DESCRIPTION
+.I /proc/net/ipsec_tncfg
+is a read-only file which lists which IPSEC virtual interfaces are
+attached to which real interfaces, through which packets will be
+forwarded once processed by IPSEC.
+.PP
+Each line lists one ipsec I/F.
+A table entry consists of:
+.IP + 3
+an ipsec virtual I/F name
+.IP +
+a visual and machine parsable separator '->', separating the virtual I/F
+and the physical I/F,
+.IP +
+a physical I/F name, to which the ipsec virtual I/F is attached or NULL
+if it is not attached,
+.IP +
+the keyword
+.BR mtu= ,
+.IP +
+the MTU of the ipsec virtual I/F,
+.IP +
+the automatically adjusted effective MTU for PMTU discovery, in brackets,
+.IP +
+a visual and machine parsable separator '->', separating the virtual I/F
+MTU and the physical I/F MTU,
+.IP +
+the MTU of the attached physical I/F.
+.BR
+.SH EXAMPLES
+.TP
+.B ipsec2 -> eth3 mtu=16260(1443) -> 1500
+.LP
+shows that virtual device
+.B ipsec2
+with an MTU of
+.B 16260
+is connected to physical device
+.B eth3
+with an MTU of
+.B 1500
+and that the effective MTU as a result of PMTU discovery has been
+automatically set to
+.BR 1443.
+.TP
+.B ipsec0 \-> wvlan0 mtu=1400(16260) \-> 1500
+.LP
+shows that virtual device
+.B ipsec0
+with an MTU of
+.B 1400
+is connected to physical device
+.B wvlan0
+with an MTU of
+.B 1500
+and no PMTU packets have gotten far enough to bump down the effective MTU
+from its default of 16260.
+.TP
+.B ipsec3 \-> NULL mtu=0(0) \-> 0
+.LP
+shows that virtual device
+.B ipsec3
+is not connected to any physical device.
+.LP
+.SH "FILES"
+/proc/net/ipsec_tncfg, /usr/local/bin/ipsec
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_eroute(5), ipsec_spi(5),
+ipsec_spigrp(5), ipsec_klipsdebug(5), ipsec_tncfg(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.
+.\"
+.\" $Log: tncfg.5,v $
+.\" Revision 1.1 2004/03/15 20:35:31 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.5 2002/04/24 07:35:41 mcr
+.\" Moved from ./klips/utils/tncfg.5,v
+.\"
+.\" Revision 1.4 2001/05/29 05:15:53 rgb
+.\" Added PMTU to output format.
+.\"
+.\" 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:01 rgb
+.\" Added manpages for all 5 klips utils.
+.\"
+.\"
diff --git a/programs/tncfg/tncfg.8 b/programs/tncfg/tncfg.8
new file mode 100644
index 000000000..f888f2539
--- /dev/null
+++ b/programs/tncfg/tncfg.8
@@ -0,0 +1,113 @@
+.TH IPSEC_TNCFG 8 "21 Jun 2000"
+.\"
+.\" RCSID $Id: tncfg.8,v 1.1 2004/03/15 20:35:31 as Exp $
+.\"
+.SH NAME
+ipsec tncfg \- associate IPSEC virtual interface with physical interface
+.SH SYNOPSIS
+.B ipsec
+.B tncfg
+.PP
+.B ipsec
+.B tncfg
+.B \-\-attach
+.B \-\-virtual
+virtual
+.B \-\-physical
+physical
+.PP
+.B ipsec
+.B tncfg
+.B \-\-detach
+.B \-\-virtual
+virtual
+.PP
+.B ipsec
+.B tncfg
+.B \-\-clear
+.PP
+.B ipsec
+.B tncfg
+.B \-\-version
+.PP
+.B ipsec
+.B tncfg
+.B \-\-help
+.SH DESCRIPTION
+.I Tncfg
+attaches/detaches IPSEC virtual interfaces to/from
+physical interfaces,
+through which packets will be forwarded once processed by IPSEC.
+.PP
+The form with no additional arguments lists the contents of
+/proc/net/ipsec_tncfg. The format of /proc/net/ipsec_tncfg is discussed
+in ipsec_tncfg(5).
+The
+.B \-\-attach
+form attaches the
+.I virtual
+interface to the
+.I physical
+one.
+The
+.B \-\-detach
+form detaches the
+.I virtual
+interface from whichever physical interface it is attached to.
+The
+.B \-\-clear
+form clears all the
+.I virtual
+interfaces from whichever physical interfaces they were attached to.
+.PP
+Virtual interfaces typically have names like
+.BR ipsec0 ,
+while physical interfaces typically have names like
+.B eth0
+or
+.BR ppp0 .
+.SH EXAMPLES
+.TP
+.B ipsec tncfg \-\-attach \-\-virtual ipsec0 \-\-physical eth0
+attaches the
+.B ipsec0
+virtual device to the
+.B eth0
+physical device.
+.LP
+.SH "FILES"
+/proc/net/ipsec_tncfg, /usr/local/bin/ipsec
+.SH "SEE ALSO"
+ipsec(8), ipsec_manual(8), ipsec_eroute(8), ipsec_spi(8),
+ipsec_spigrp(8), ipsec_klipsdebug(8), ipsec_tncfg(5)
+.SH HISTORY
+Written for the Linux FreeS/WAN project
+<http://www.freeswan.org/>
+by Richard Guy Briggs.
+.\"
+.\" $Log: tncfg.8,v $
+.\" Revision 1.1 2004/03/15 20:35:31 as
+.\" added files from freeswan-2.04-x509-1.5.3
+.\"
+.\" Revision 1.15 2002/04/24 07:35:41 mcr
+.\" Moved from ./klips/utils/tncfg.8,v
+.\"
+.\" Revision 1.14 2000/09/12 13:09:04 rgb
+.\" Fixed real/physical discrepancy between tncfg.8 and tncfg.c.
+.\"
+.\" Revision 1.13 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.12 2000/06/21 16:54:58 rgb
+.\" Added 'no additional args' text for listing contents of
+.\" /proc/net/ipsec_* files.
+.\"
+.\" Revision 1.11 1999/07/19 18:47:25 henry
+.\" fix slightly-misformed comments
+.\"
+.\" Revision 1.10 1999/04/06 04:54:39 rgb
+.\" Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+.\" patch shell fixes.
+.\"
diff --git a/programs/tncfg/tncfg.c b/programs/tncfg/tncfg.c
new file mode 100644
index 000000000..f6aeae0e2
--- /dev/null
+++ b/programs/tncfg/tncfg.c
@@ -0,0 +1,393 @@
+/*
+ * IPSEC interface configuration
+ * Copyright (C) 1996 John Ioannidis.
+ * Copyright (C) 1998, 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.
+ */
+
+char tncfg_c_version[] = "RCSID $Id: tncfg.c,v 1.1 2004/03/15 20:35:31 as Exp $";
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h> /* system(), strtoul() */
+#include <unistd.h> /* getuid() */
+#include <linux/types.h>
+#include <sys/ioctl.h> /* ioctl() */
+
+#include <freeswan.h>
+#ifdef NET_21 /* from freeswan.h */
+#include <linux/sockios.h>
+#include <sys/socket.h>
+#endif /* NET_21 */ /* from freeswan.h */
+
+#if 0
+#include <linux/if.h>
+#else
+#include <net/if.h>
+#endif
+#include <sys/types.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include "freeswan/ipsec_tunnel.h"
+
+static void
+usage(char *name)
+{
+ fprintf(stdout,"%s --attach --virtual <virtual-device> --physical <physical-device>\n",
+ name);
+ fprintf(stdout,"%s --detach --virtual <virtual-device>\n",
+ name);
+ fprintf(stdout,"%s --clear\n",
+ name);
+ fprintf(stdout,"%s --help\n",
+ name);
+ fprintf(stdout,"%s --version\n",
+ name);
+ fprintf(stdout,"%s\n",
+ name);
+ fprintf(stdout, " [ --debug ] is optional to any %s command.\n", name);
+ fprintf(stdout, " [ --label <label> ] is optional to any %s command.\n", name);
+ exit(1);
+}
+
+static struct option const longopts[] =
+{
+ {"virtual", 1, 0, 'V'},
+ {"physical", 1, 0, 'P'},
+ {"attach", 0, 0, 'a'},
+ {"detach", 0, 0, 'd'},
+ {"clear", 0, 0, 'c'},
+ {"help", 0, 0, 'h'},
+ {"version", 0, 0, 'v'},
+ {"label", 1, 0, 'l'},
+ {"optionsfrom", 1, 0, '+'},
+ {"debug", 0, 0, 'g'},
+ {0, 0, 0, 0}
+};
+
+int
+main(int argc, char *argv[])
+{
+ struct ifreq ifr;
+ struct ipsectunnelconf *shc=(struct ipsectunnelconf *)&ifr.ifr_data;
+ int s;
+ int c, previous = -1;
+ char *program_name;
+ int debug = 0;
+ int argcount = argc;
+
+ memset(&ifr, 0, sizeof(ifr));
+ program_name = argv[0];
+
+ while((c = getopt_long_only(argc, argv, ""/*"adchvV:P:l:+:"*/, longopts, 0)) != EOF) {
+ switch(c) {
+ case 'g':
+ debug = 1;
+ argcount--;
+ break;
+ case 'a':
+ if(shc->cf_cmd) {
+ fprintf(stderr, "%s: exactly one of '--attach', '--detach' or '--clear' options must be specified.\n", program_name);
+ exit(1);
+ }
+ shc->cf_cmd = IPSEC_SET_DEV;
+ break;
+ case 'd':
+ if(shc->cf_cmd) {
+ fprintf(stderr, "%s: exactly one of '--attach', '--detach' or '--clear' options must be specified.\n", program_name);
+ exit(1);
+ }
+ shc->cf_cmd = IPSEC_DEL_DEV;
+ break;
+ case 'c':
+ if(shc->cf_cmd) {
+ fprintf(stderr, "%s: exactly one of '--attach', '--detach' or '--clear' options must be specified.\n", program_name);
+ exit(1);
+ }
+ shc->cf_cmd = IPSEC_CLR_DEV;
+ break;
+ case 'h':
+ usage(program_name);
+ break;
+ case 'v':
+ if(optarg) {
+ fprintf(stderr, "%s: warning; '-v' and '--version' options don't expect arguments, arg '%s' found, perhaps unintended.\n",
+ program_name, optarg);
+ }
+ fprintf(stdout, "%s, %s\n", program_name, tncfg_c_version);
+ exit(1);
+ break;
+ case 'V':
+ strcpy(ifr.ifr_name, optarg);
+ break;
+ case 'P':
+ strcpy(shc->cf_name, optarg);
+ 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 '+': /* optionsfrom */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* no return on error */
+ break;
+ default:
+ usage(program_name);
+ break;
+ }
+ previous = c;
+ }
+
+ if(argcount == 1) {
+ system("cat /proc/net/ipsec_tncfg");
+ exit(0);
+ }
+
+ switch(shc->cf_cmd) {
+ case IPSEC_SET_DEV:
+ if(!shc->cf_name) {
+ fprintf(stderr, "%s: physical I/F parameter missing.\n",
+ program_name);
+ exit(1);
+ }
+ case IPSEC_DEL_DEV:
+ if(!ifr.ifr_name) {
+ fprintf(stderr, "%s: virtual I/F parameter missing.\n",
+ program_name);
+ exit(1);
+ }
+ break;
+ case IPSEC_CLR_DEV:
+ strcpy(ifr.ifr_name, "ipsec0");
+ break;
+ default:
+ fprintf(stderr, "%s: exactly one of '--attach', '--detach' or '--clear' options must be specified.\n"
+ "Try %s --help' for usage information.\n",
+ program_name, program_name);
+ exit(1);
+ }
+
+ s=socket(AF_INET, SOCK_DGRAM,0);
+ if(s==-1)
+ {
+ fprintf(stderr, "%s: Socket creation failed -- ", program_name);
+ switch(errno)
+ {
+ case EACCES:
+ if(getuid()==0)
+ fprintf(stderr, "Root denied permission!?!\n");
+ else
+ fprintf(stderr, "Run as root user.\n");
+ break;
+ case EPROTONOSUPPORT:
+ fprintf(stderr, "Internet Protocol not enabled");
+ break;
+ case EMFILE:
+ case ENFILE:
+ case ENOBUFS:
+ fprintf(stderr, "Insufficient system resources.\n");
+ break;
+ case ENODEV:
+ fprintf(stderr, "No such device. Is the virtual device valid? Is the ipsec module linked into the kernel or loaded as a module?\n");
+ break;
+ default:
+ fprintf(stderr, "Unknown socket error %d.\n", errno);
+ }
+ exit(1);
+ }
+ if(ioctl(s, shc->cf_cmd, &ifr)==-1)
+ {
+ if(shc->cf_cmd == IPSEC_SET_DEV) {
+ fprintf(stderr, "%s: Socket ioctl failed on attach -- ", program_name);
+ switch(errno)
+ {
+ case EINVAL:
+ fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n");
+ break;
+ case ENODEV:
+ fprintf(stderr, "No such device. Is the virtual device valid? Is the ipsec module linked into the kernel or loaded as a module?\n");
+ break;
+ case ENXIO:
+ fprintf(stderr, "No such device. Is the physical device valid?\n");
+ break;
+ case EBUSY:
+ fprintf(stderr, "Device busy. Virtual device %s is already attached to a physical device -- Use detach first.\n",
+ ifr.ifr_name);
+ break;
+ default:
+ fprintf(stderr, "Unknown socket error %d.\n", errno);
+ }
+ exit(1);
+ }
+ if(shc->cf_cmd == IPSEC_DEL_DEV) {
+ fprintf(stderr, "%s: Socket ioctl failed on detach -- ", program_name);
+ switch(errno)
+ {
+ case EINVAL:
+ fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n");
+ break;
+ case ENODEV:
+ fprintf(stderr, "No such device. Is the virtual device valid? The ipsec module may not be linked into the kernel or loaded as a module.\n");
+ break;
+ case ENXIO:
+ fprintf(stderr, "Device requested is not linked to any physical device.\n");
+ break;
+ default:
+ fprintf(stderr, "Unknown socket error %d.\n", errno);
+ }
+ exit(1);
+ }
+ if(shc->cf_cmd == IPSEC_CLR_DEV) {
+ fprintf(stderr, "%s: Socket ioctl failed on clear -- ", program_name);
+ switch(errno)
+ {
+ case EINVAL:
+ fprintf(stderr, "Invalid argument, check kernel log messages for specifics.\n");
+ break;
+ case ENODEV:
+ fprintf(stderr, "Failed. Is the ipsec module linked into the kernel or loaded as a module?.\n");
+ break;
+ default:
+ fprintf(stderr, "Unknown socket error %d.\n", errno);
+ }
+ exit(1);
+ }
+ }
+ exit(0);
+}
+
+/*
+ * $Log: tncfg.c,v $
+ * Revision 1.1 2004/03/15 20:35:31 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.30 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.29 2002/04/24 07:35:41 mcr
+ * Moved from ./klips/utils/tncfg.c,v
+ *
+ * Revision 1.28 2002/03/08 21:44:05 rgb
+ * Update for all GNU-compliant --version strings.
+ *
+ * Revision 1.27 2001/06/14 19:35:15 rgb
+ * Update copyright date.
+ *
+ * Revision 1.26 2001/05/21 02:02:55 rgb
+ * Eliminate 1-letter options.
+ *
+ * Revision 1.25 2001/05/16 05:07:20 rgb
+ * Fixed --label option in KLIPS manual utils to add the label to the
+ * command name rather than replace it in error text.
+ * Fix 'print table' non-option in KLIPS manual utils to deal with --label
+ * and --debug options.
+ *
+ * Revision 1.24 2000/09/12 13:09:05 rgb
+ * Fixed real/physical discrepancy between tncfg.8 and tncfg.c.
+ *
+ * Revision 1.23 2000/08/27 01:48:30 rgb
+ * Update copyright.
+ *
+ * Revision 1.22 2000/07/26 03:41:46 rgb
+ * Changed all printf's to fprintf's. Fixed tncfg's usage to stderr.
+ *
+ * Revision 1.21 2000/06/21 16:51:27 rgb
+ * Added no additional argument option to usage text.
+ *
+ * Revision 1.20 2000/01/21 06:26:31 rgb
+ * Added --debug switch to command line.
+ *
+ * Revision 1.19 1999/12/08 20:32:41 rgb
+ * Cleaned out unused cruft.
+ * Changed include file, limiting scope, to avoid conflicts in 2.0.xx
+ * kernels.
+ *
+ * Revision 1.18 1999/12/07 18:27:10 rgb
+ * Added headers to silence fussy compilers.
+ * Converted local functions to static to limit scope.
+ *
+ * Revision 1.17 1999/11/18 04:09:21 rgb
+ * Replaced all kernel version macros to shorter, readable form.
+ *
+ * Revision 1.16 1999/05/25 01:45:36 rgb
+ * Fix version macros for 2.0.x as a module.
+ *
+ * Revision 1.15 1999/05/05 22:02:34 rgb
+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
+ *
+ * Revision 1.14 1999/04/15 15:37:28 rgb
+ * Forward check changes from POST1_00 branch.
+ *
+ * Revision 1.10.6.2 1999/04/13 20:58:10 rgb
+ * Add argc==1 --> /proc/net/ipsec_*.
+ *
+ * Revision 1.10.6.1 1999/03/30 17:01:36 rgb
+ * Make main() return type explicit.
+ *
+ * Revision 1.13 1999/04/11 00:12:09 henry
+ * GPL boilerplate
+ *
+ * Revision 1.12 1999/04/06 04:54:39 rgb
+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
+ * patch shell fixes.
+ *
+ * Revision 1.11 1999/03/17 15:40:54 rgb
+ * Make explicit main() return type of int.
+ *
+ * Revision 1.10 1998/11/12 21:08:04 rgb
+ * Add --label option to identify caller from scripts.
+ *
+ * Revision 1.9 1998/10/09 18:47:30 rgb
+ * Add 'optionfrom' to get more options from a named file.
+ *
+ * Revision 1.8 1998/10/09 04:36:55 rgb
+ * Changed help output from stderr to stdout.
+ * Deleted old commented out cruft.
+ *
+ * Revision 1.7 1998/08/28 03:15:14 rgb
+ * Add some manual long options to the usage text.
+ *
+ * Revision 1.6 1998/08/05 22:29:00 rgb
+ * Change includes to accomodate RH5.x.
+ * Force long option names.
+ * Add ENXIO error return code to narrow down error reporting.
+ *
+ * Revision 1.5 1998/07/29 21:45:28 rgb
+ * Convert to long option names.
+ *
+ * Revision 1.4 1998/07/09 18:14:11 rgb
+ * Added error checking to IP's and keys.
+ * Made most error messages more specific rather than spamming usage text.
+ * Added more descriptive kernel error return codes and messages.
+ * Converted all spi translations to unsigned.
+ * Removed all invocations of perror.
+ *
+ * Revision 1.3 1998/05/27 18:48:20 rgb
+ * Adding --help and --version directives.
+ *
+ * Revision 1.2 1998/04/23 21:11:39 rgb
+ * Fixed 0 argument usage case to prevent sigsegv.
+ *
+ * Revision 1.1.1.1 1998/04/08 05:35:09 henry
+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
+ *
+ * Revision 0.5 1997/06/03 04:31:55 ji
+ * New file.
+ *
+ */
diff --git a/testing/INSTALL b/testing/INSTALL
new file mode 100644
index 000000000..dfe21cc04
--- /dev/null
+++ b/testing/INSTALL
@@ -0,0 +1,150 @@
+
+ -------------------------------
+ strongSwan UML - Installation
+ -------------------------------
+
+
+Contents
+--------
+
+ 1. Making the host system UML-capable
+ 2. Installing the required files
+ 3. Creating the UML testing environment
+
+
+1. Making the host system UML-capable
+ ----------------------------------
+
+ UML instances can be run on both Linux 2.4 and Linux 2.6 kernels.
+ If you are using a vanilla kernel from kernel.org then you must first
+ apply the host SKAS patch available from
+
+ http://www.user-mode-linux.org/~blaisorblade/patches/
+
+ and recompile and reboot your host kernel. Some Linux distributions as e.g.
+ SuSE already include the SKAS patch in their kernels.
+
+ You will also need the UML utilities (uml_mconsole and uml_switch)
+ available from
+
+ http://prdownloads.sourceforge.net/user-mode-linux/uml_utilities_20040406.tar.bz2
+
+ Many Linux distributions offer the UML utilities as a package.
+
+
+2. Installing the required files
+ -----------------------------
+
+First create a directory where you want the strongSwan UML testing environment
+to be located.The default directory is "~/strongswan-testing". If you choose a
+different location, please adapt the UMLTESTDIR variable in "testing.conf"
+accordingly.
+
+ mkdir ~/strongswan-testing
+
+Now copy the "testing" subdirectory coming with the strongSwan distribution to
+the UML testing environment:
+
+ cp -r testing ~/strongswan-testing
+
+Next you need to copy several files into the ~/strongswan-testing directory that
+are required for the strongSwan testing environment:
+
+ * A vanilla Linux kernel on which the UML kernel will be based on.
+ We recommend the use of
+
+ http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.16.9.tar.bz2
+
+ * Starting with Linux kernel 2.6.9 no patch must be applied any more in order
+ to make the vanilla kernel UML-capable. For older kernels you'll find
+ a matching UML patch at
+
+ http://prdownloads.sourceforge.net/user-mode-linux/
+
+ * The matching .config file required to compile the UML kernel:
+
+ http://download.strongswan.org/uml/.config-2.6.16
+
+ * A gentoo-based UML file system (compressed size 130 MBytes) found at
+
+ http://download.strongswan.org/uml/gentoo-fs-20060330.tar.bz2
+
+ * The latest strongSwan distribution
+
+ http://download.strongswan.org/strongswan-2.7.0.tar.gz
+
+
+3. Creating the environment
+ ------------------------
+
+Now change into the testing subdirectory
+
+ cd ~/strongswan-testing/testing
+
+and make the UML testing environment:
+
+ ./make-testing <hosts>
+
+The "make-testing" script calls a series of subscripts which can be
+enabled or disabled individually by setting the corresponding flags
+in "testing.conf":
+
+ if [ $ENABLE_BUILD_UMLKERNEL = "yes" ]
+ then
+ scripts/build-umlkernel
+ fi
+
+builds an UML kernel out of the vanilla Linux kernel and the corresponding
+UML kernel patch.
+
+ if [ $ENABLE_BUILD_HOSTCONFIG = "yes" ]
+ then
+ scripts/build-hostconfig
+ fi
+
+generates the default configurations for the UML hosts alice, venus, moon,
+carol, winnetou, dave, sun, and bob by replacing the wildcards PH_IP_ALICE,
+etc. by the actual IP addresses defined in "testing.conf".
+
+ if [ $ENABLE_BUILD_UMLROOTFS = "yes" ]
+ then
+ scripts/build-umlrootfs
+ fi
+
+takes the gentoo-based UML file system and compiles the latest strongSwan
+distribution into it.
+
+ if [ $ENABLE_BUILD_SSHKEYS = "yes" ]
+ then
+ scripts/build-sshkeys
+ fi
+
+adds the common RSA public key of the UML instances to your ~/.ssh/known_hosts
+directory so that you can log onto the UML instances using ssh without typing
+in a password. The "scripts/build-sshkeys" script should only be run once.
+
+ if [ $ENABLE_BUILD_UMLHOSTFS = "yes" ]
+ then
+ scripts/build-umlhostfs <hosts>
+ fi
+
+creates the customized UML file systems for the instances given as command line
+arguments by adding the default host configurations to the UML root file system.
+If the "make-starting" scripts is called without any arguments then by default
+the UML file systems are created for the hosts alice, venus, moon, carol,
+winnetou, dave, sun, and bob. Each UML root file system has as size defined by
+the ROOTFSSIZE in testing.conf which by default is 544 MBytes. Thus all 8 UML
+hosts plus the master copy will require a total of 5 GBytes of disk space.
+
+ if [ $ENABLE_START_TESTING = "yes" ]
+ then
+ ./start-testing <hosts>
+ fi
+
+starts the automated testing. More details on the tests you'll find in the
+README document.
+
+-----------------------------------------------------------------------------
+
+This file is RCSID $Id: INSTALL,v 1.39 2006/04/24 16:58:03 as Exp $
+
diff --git a/testing/README b/testing/README
new file mode 100644
index 000000000..e1930a6e3
--- /dev/null
+++ b/testing/README
@@ -0,0 +1,160 @@
+
+ ------------------------------------
+ strongSwan UML - Running the Tests
+ ------------------------------------
+
+
+Contents
+--------
+
+ 1. Starting up the UML testing environment
+ 2. Running the automated tests
+ 3. Manual testing
+
+
+1. Starting up the UML testing environment
+ ---------------------------------------
+
+When the strongSwan UML testing environment has been put into place by
+running the "make-testing" script then you are ready to start up the
+UML instances by calling
+
+ ./start-testing <hosts>
+
+This main script first calls the subscript
+
+ scripts/start-switches
+
+that starts the three UML switches umlswitch0, umlswitch1, and umlswitch2
+which are connecting the UML instances among each other and via tun/tap
+devices also make them accessible from the host system.
+
+Then depending on the setting of the UMLSTARTMODE variable defined
+in "testing.conf", the UML instances given on the command line are started
+up with different terminals:
+
+If you are running the KDE graphical environment then by setting
+
+ UMLSTARTMODE=konsole
+
+the script
+
+ scripts/kstart-umls <hosts>
+
+is called which starts up each of the UML instances defined by <hosts> in
+a KDE konsole. If
+
+ UMLSTARTMODE=xterm
+
+is set then
+
+ scripts/xstart-umls <hosts>
+
+starts up the UML instances in an xterm each. And with the choice
+
+ UMLSTARTMODE=screen
+
+the instances are started up by
+
+ scripts/start-umls <hosts>
+
+in the background but the Linux command "screen -r <host>" can be used to
+connect a terminal to the UML instance <host> if desired.
+
+
+ if [ $ENABLE_DO_TESTS = "yes" ]
+ then
+ do-tests
+ fi
+
+either executes all the tests defined in the "testing/tests" directory
+if the variable SELECTEDTESTSONLY in "testing.conf" is set to "no" or the
+selected tests defined by the string in SELELECTEDTESTS if SELECTEDTESTSONLY
+is set to "yes".
+
+ if [ $ENABLE_STOP_TESTING = "yes" ]
+ then
+ stop-testing <hosts>
+ fi
+
+stops the both the UML switches and the UML instances designated by the
+<hosts> argument.
+
+
+2. Running the automated tests
+ ---------------------------
+
+The script
+
+ ./do-tests <testnames>
+
+runs the automated tests. With an empty <testnames> argument the tests
+as defined in "testing.conf" are executed, otherwise the tests enumerated
+by the <testnames> argument will be run as shown in the example below.
+
+ ./do-tests net2net-psk net2net-cert
+
+Each test is divided into the following phases:
+
+ * scripts/load-testconfig <testname>
+ loads the UML hosts with test specific settings if such are provided.
+
+ * next the "pretest.dat" script found in each test directory is executed.
+ Among other commands, strongSwan is started on the IPsec hosts.
+
+ * the "evaltest.dat" script evaluates if the test has been successful.
+
+ * the "posttest.dat" script terminates the test e.g. by stopping
+ strongSwan on the IPsec hosts.
+
+ * scripts/restore-defaults <testname>
+ restores the default settings on the UML hosts.
+
+The test results and configuration settings for all tests settings are stored
+in a folder labeled with the current date in the directory
+
+ ~/strongswan-testing/testresults
+
+the same results are also automatically transferred to the Apache server
+running on UML instance "winnetou" and can be accessed via the URL
+
+ http://192.168.0.150/testresults/
+
+
+3. Manual testing
+ --------------
+
+The greates flexibility can be achieved with manual testing. Just set
+
+ ENABLE_DO_TESTS="no"
+ ENABLE_STOP_TESTING="no"
+
+in "testing.conf" and start the UML instances that you want to experiment with
+by calling
+
+ ./start-testing <hosts>
+
+If you want to preload a test scenario with configurations differing from
+the default values, e.g. when using Preshared Keys then you can do this
+with the command
+
+ scripts/load-testconfig net2net-psk
+
+You can then log onto any UML instance using its konsole, xterm or screen
+terminal as root with the default password
+
+ tuxmux
+
+You can then execute any commands the UML instances, including changing
+and recompiling the strongSwan source code located in the /root directory.
+
+After you have finished testing, the default configuration settings can
+restored with the command
+
+ scripts/restore-defaults net2net-psk
+
+
+-----------------------------------------------------------------------------
+
+This file is RCSID $Id: README,v 1.2 2004/12/20 16:26:39 as Exp $
+
diff --git a/testing/do-tests b/testing/do-tests
new file mode 100755
index 000000000..ceddd72d8
--- /dev/null
+++ b/testing/do-tests
@@ -0,0 +1,458 @@
+#!/bin/bash
+# Automatically execute the strongSwan test cases
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: do-tests,v 1.20 2006/02/08 21:27:59 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/scripts/function.sh
+
+[ -f $DIR/testing.conf ] || die "Configuration file 'testing.conf' not found"
+[ -d $DIR/hosts ] || die "Directory 'hosts' not found"
+[ -d $DIR/tests ] || die "Directory 'tests' not found"
+
+source $DIR/testing.conf
+
+
+##############################################################################
+# test if UMLs have been built at all
+#
+
+[ -d $BUILDDIR ] || die "Directory '$BUILDDIR' does not exist. Please run 'make-testing'first."
+
+
+##############################################################################
+# take care of new path and file variables
+#
+
+[ -d $TESTRESULTSDIR ] || mkdir $TESTRESULTSDIR
+
+TESTDATE=`date +%Y%m%d-%H%M`
+
+TODAYDIR=$TESTRESULTSDIR/$TESTDATE
+mkdir $TODAYDIR
+TESTRESULTSHTML=$TODAYDIR/index.html
+DEFAULTTESTSDIR=$UMLTESTDIR/testing/tests
+
+testnumber="0"
+failed_cnt="0"
+passed_cnt="0"
+
+
+##############################################################################
+# copy default tests to $BUILDDIR
+#
+
+TESTSDIR=$BUILDDIR/tests
+[ -d $TESTSDIR ] || mkdir $TESTSDIR
+rm -rf $TESTSDIR/*
+cp -rfp $DEFAULTTESTSDIR/* $TESTSDIR
+
+
+##############################################################################
+# assign IP for each host to hostname
+#
+
+for host in $STRONGSWANHOSTS
+do
+ eval ip_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+ case $host in
+ moon)
+ eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+ searchandreplace PH_IP_MOON $ip_moon $TESTSDIR
+ searchandreplace PH_IP1_MOON $ip1_moon $TESTSDIR
+ ;;
+ sun)
+ eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+ searchandreplace PH_IP_SUN $ip_sun $TESTSDIR
+ searchandreplace PH_IP1_SUN $ip1_sun $TESTSDIR
+ ;;
+ alice)
+ searchandreplace PH_IP_ALICE $ip_alice $TESTSDIR
+ ;;
+ venus)
+ searchandreplace PH_IP_VENUS $ip_venus $TESTSDIR
+ ;;
+ bob)
+ searchandreplace PH_IP_BOB $ip_bob $TESTSDIR
+ ;;
+ carol)
+ eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+ searchandreplace PH_IP_CAROL $ip_carol $TESTSDIR
+ searchandreplace PH_IP1_CAROL $ip1_carol $TESTSDIR
+ ;;
+ dave)
+ eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+ searchandreplace PH_IP_DAVE $ip_dave $TESTSDIR
+ searchandreplace PH_IP1_DAVE $ip1_dave $TESTSDIR
+ ;;
+ winnetou)
+ searchandreplace PH_IP_WINNETOU $ip_winnetou $TESTSDIR
+ ;;
+ esac
+done
+
+
+##############################################################################
+# create header for the results html file
+#
+
+KERNEL_VERSION=`basename $KERNEL .tar.bz2`
+IPSEC_VERSION=`basename $STRONGSWAN .tar.bz2`
+
+cat > $TESTRESULTSHTML <<@EOF
+<html>
+<head>
+ <title>strongSwan UML Testing</title>
+</head>
+<body>
+ <h2>strongSwan UML Testing</h2>
+ <table border="0" cellspacing="2">
+ <tr><td><b>Host:</b></td><td>`uname -a`</td></tr>
+ <tr><td><b>UML kernel: &nbsp;</b></td><td>$KERNEL_VERSION</td></tr>
+ <tr><td><b>IPsec:</b></td><td>$IPSEC_VERSION</td></tr>
+ <tr><td><b>Date:</b></td><td>$TESTDATE</td></tr>
+ </table>
+ <p>
+ <table border="0" width="500">
+ <thead align="left"><th>Number</th><th>Test</th><th>Result</th></thead>
+@EOF
+
+cecho "UML kernel: $KERNEL_VERSION"
+cecho "IPsec: $IPSEC_VERSION"
+cecho "Date: $TESTDATE"
+cecho ""
+
+
+##############################################################################
+# enter specific test directory
+#
+
+if [ $# -gt 0 ]
+then
+ TESTS=$*
+elif [ $SELECTEDTESTSONLY = "yes" ]
+then
+ # set internal field seperator
+ TESTS=$SELECTEDTESTS
+else
+ # set internal field seperator
+ TESTS="`ls $TESTSDIR`"
+fi
+
+for testname in $TESTS
+do
+ let "testnumber += 1"
+ cecho-n " $testnumber $testname.."
+
+ if [ ! -d $TESTSDIR/${testname} ]
+ then
+ cecho "is missing..skipped"
+ continue
+ fi
+
+ [ -f $TESTSDIR/${testname}/description.txt ] || die "!! File 'description.txt' is missing"
+ [ -f $TESTSDIR/${testname}/test.conf ] || die "!! File 'test.conf' is missing"
+ [ -f $TESTSDIR/${testname}/pretest.dat ] || die "!! File 'pretest.dat' is missing"
+ [ -f $TESTSDIR/${testname}/posttest.dat ] || die "!! File 'posttest.dat' is missing"
+ [ -f $TESTSDIR/${testname}/evaltest.dat ] || die "!! File 'evaltest.dat' is missing"
+
+ TESTRESULTDIR=$TODAYDIR/$testname
+ mkdir $TESTRESULTDIR
+ CONSOLE_LOG=$TESTRESULTDIR/console.log
+ touch $CONSOLE_LOG
+
+
+ ##########################################################################
+ # copy test specific configurations to uml hosts and clear auth.log files
+ #
+
+ $DIR/scripts/load-testconfig $testname
+ source $TESTSDIR/$testname/test.conf
+
+
+ ##########################################################################
+ # run tcpdump in the background
+ #
+
+ if [ "$TCPDUMPHOSTS" != "" ]
+ then
+ echo -e "TCPDUMP\n" >> $CONSOLE_LOG 2>&1
+
+ for host_iface in $TCPDUMPHOSTS
+ do
+ host=`echo $host_iface | awk -F ":" '{print $1}'`
+ iface=`echo $host_iface | awk -F ":" '{if ($2 != "") { print $2 } else { printf("eth0") }}'`
+ tcpdump_cmd="tcpdump -i $iface not port ssh and not port domain and not arp > /tmp/tcpdump.log 2>&1 &"
+ echo "${host}# $tcpdump_cmd" >> $CONSOLE_LOG
+ ssh root@`eval echo \\\$ip_$host '$tcpdump_cmd'`
+ eval TDUP_${host}="true"
+ done
+ fi
+
+ ##########################################################################
+ # execute pre-test commands
+ #
+
+ cecho-n "pre.."
+ echo -e "\nPRE-TEST\n" >> $CONSOLE_LOG 2>&1
+
+ eval `awk -F "::" '{
+ if ($2 != "")
+ {
+ printf("echo \"%s# %s\"; ", $1, $2)
+ printf("ssh root@\044ip_%s \"%s\"; ", $1, $2)
+ printf("echo;\n")
+ }
+ }' $TESTSDIR/${testname}/pretest.dat` >> $CONSOLE_LOG 2>&1
+
+
+ ##########################################################################
+ # stop tcpdump
+ #
+
+ function stop_tcpdump {
+ echo "${1}# killall tcpdump" >> $CONSOLE_LOG
+ eval ssh root@\$ip_${1} killall tcpdump
+ eval TDUP_${1}="false"
+ echo ""
+ }
+
+
+ ##########################################################################
+ # get and evaluate test results
+ #
+
+ cecho-n "test.."
+ echo -e "\nTEST\n" >> $CONSOLE_LOG 2>&1
+
+ STATUS="passed"
+
+ eval `awk -F "::" '{
+ host=$1
+ command=$2
+ pattern=$3
+ hit=$4
+ if (command != "")
+ {
+ if (command == "tcpdump")
+ {
+ printf("if [ \044TDUP_%s == \"true\" ]; then stop_tcpdump %s; fi; \n", host, host)
+ printf("echo \"%s# cat /tmp/tcpdump.log | grep \047%s\047 [%s]\"; ", host, pattern, hit)
+ printf("ssh root@\044ip_%s cat /tmp/tcpdump.log | grep \"%s\"; ", host, pattern)
+ }
+ else
+ {
+ printf("echo \"%s# %s | grep \047%s\047 [%s]\"; ", host, command, pattern, hit)
+ printf("ssh root@\044ip_%s %s | grep \"%s\"; ", host, command, pattern)
+ }
+ printf("cmd_exit=\044?; ")
+ printf("echo; ")
+ printf("if [ \044cmd_exit -eq 0 -a \"%s\" = \"NO\" ] ", hit)
+ printf("|| [ \044cmd_exit -ne 0 -a \"%s\" = \"YES\" ] ", hit)
+ printf("; then STATUS=\"failed\"; fi; \n")
+
+ }
+ }' $TESTSDIR/${testname}/evaltest.dat` >> $CONSOLE_LOG 2>&1
+
+
+ ##########################################################################
+ # set counters
+ #
+
+ if [ $STATUS = "failed" ]
+ then
+ let "failed_cnt += 1"
+ else
+ let "passed_cnt += 1"
+ fi
+
+
+ ##########################################################################
+ # log statusall and listall output
+ # get copies of ipsec.conf, ipsec.secrets
+ # create index.html for the given test case
+
+ cat > $TESTRESULTDIR/index.html <<@EOF
+<html>
+<head>
+ <title>Test $testname</title>
+</head>
+<body>
+<table border="0" width="600">
+ <tr><td>
+ <h2>Test $testname</h2>
+ <h3>Description</h3>
+@EOF
+
+ cat $TESTSDIR/${testname}/description.txt >> $TESTRESULTDIR/index.html
+
+ cat >> $TESTRESULTDIR/index.html <<@EOF
+ <ul>
+ <li><a href="console.log">console.log</a></li>
+ </ul>
+ <img src="../images/$DIAGRAM" alt="$UMLHOSTS">
+@EOF
+
+
+ for host in $IPSECHOSTS
+ do
+ eval HOSTLOGIN=root@\$ip_${host}
+
+ for command in statusall listall
+ do
+ ssh $HOSTLOGIN ipsec $command \
+ > $TESTRESULTDIR/${host}.$command 2>/dev/null
+ done
+
+ for file in ipsec.conf ipsec.secrets
+ do
+ scp $HOSTLOGIN:/etc/$file \
+ $TESTRESULTDIR/${host}.$file > /dev/null 2>&1
+ done
+
+ cat >> $TESTRESULTDIR/index.html <<@EOF
+ <h3>$host</h3>
+ <ul>
+ <li><a href="$host.ipsec.conf">ipsec.conf</a></li>
+ <li><a href="$host.ipsec.secrets">ipsec.secrets</a></li>
+ <li><a href="$host.statusall">ipsec statusall</a></li>
+ <li><a href="$host.listall">ipsec listall</a></li>
+ <li><a href="$host.auth.log">auth.log</a></li>
+ </ul>
+@EOF
+
+ done
+
+ cat >> $TESTRESULTDIR/index.html <<@EOF
+ </td></tr>
+ <tr><td align="right">
+ <b><a href="../index.html">Back</a></b>
+ </td></tr>
+</table>
+</body>
+</html>
+@EOF
+
+
+ ##########################################################################
+ # execute post-test commands
+ #
+
+ cecho-n "post.."
+ echo -e "\nPOST-TEST\n" >> $CONSOLE_LOG 2>&1
+
+ eval `awk -F "::" '{
+ if ($2 != "")
+ {
+ printf("echo \"%s# %s\"; ", $1, $2)
+ printf("ssh root@\044ip_%s \"%s\"; ", $1, $2)
+ printf("echo;\n")
+ }
+ }' $TESTSDIR/${testname}/posttest.dat` >> $CONSOLE_LOG 2>&1
+
+
+ ##########################################################################
+ # get a copy of /var/log/auth.log
+ #
+
+ for host in $IPSECHOSTS
+ do
+ eval HOSTLOGIN=root@\$ip_${host}
+ ssh $HOSTLOGIN grep pluto /var/log/auth.log \
+ > $TESTRESULTDIR/${host}.auth.log
+ done
+
+
+ ##########################################################################
+ # stop tcpdump if necessary
+ #
+
+ for host in $TCPDUMPHOSTS
+ do
+ if [ "`eval echo \\\$TDUP_${host}`" = "true" ]
+ then
+ echo "${host}# killall tcpdump" >> $CONSOLE_LOG
+ eval ssh root@\$ip_$host killall tcpdump
+ eval TDUP_${host}="false"
+ fi
+ done
+
+
+ ##########################################################################
+ # copy default host config back if necessary
+ #
+
+ $DIR/scripts/restore-defaults $testname
+
+
+ ##########################################################################
+ # write test status to html file
+ #
+
+ cecho "$STATUS"
+ if [ $STATUS = "passed" ]
+ then
+ COLOR="green"
+ else
+ COLOR="red"
+ fi
+
+ cat >> $TESTRESULTSHTML << @EOF
+ <tr>
+ <td>$testnumber</td>
+ <td><a href="$testname/">$testname</a></td>
+ <td><a href="$testname/console.log"><font color="$COLOR">$STATUS</font></a></td>
+ </tr>
+@EOF
+
+done
+
+
+##############################################################################
+# finish the results html file
+#
+
+cat >> $TESTRESULTSHTML << @EOF
+ </table>
+ <p>
+ <b>Passed: &nbsp; $passed_cnt</b><br>
+ <b>Failed: &nbsp; $failed_cnt</b><br>
+ <p>
+</body>
+</html>
+@EOF
+
+cecho ""
+cecho "Passed: $passed_cnt"
+cecho "Failed: $failed_cnt"
+cecho ""
+
+
+##############################################################################
+# copy the test results to the apache server
+#
+
+HTDOCS="/var/www/localhost/htdocs"
+
+cecho-n "Copying test results to winnetou.."
+ssh root@${ip_winnetou} mkdir -p $HTDOCS/testresults > /dev/null 2>&1
+scp -r $TODAYDIR root@${ip_winnetou}:$HTDOCS/testresults > /dev/null 2>&1
+ssh root@${ip_winnetou} ln -s $HTDOCS/images $HTDOCS/testresults/$TESTDATE/images > /dev/null 2>&1
+cecho "done"
+cecho ""
+cecho "The results are available in $TODAYDIR"
+cecho "or via the link http://$ip_winnetou/testresults/$TESTDATE"
diff --git a/testing/hosts/alice/etc/conf.d/hostname b/testing/hosts/alice/etc/conf.d/hostname
new file mode 100644
index 000000000..2012e0451
--- /dev/null
+++ b/testing/hosts/alice/etc/conf.d/hostname
@@ -0,0 +1 @@
+HOSTNAME=alice
diff --git a/testing/hosts/alice/etc/conf.d/net b/testing/hosts/alice/etc/conf.d/net
new file mode 100644
index 000000000..3070a46b1
--- /dev/null
+++ b/testing/hosts/alice/etc/conf.d/net
@@ -0,0 +1,11 @@
+# /etc/conf.d/net:
+
+# This is basically the ifconfig argument without the ifconfig $iface
+#
+iface_lo="127.0.0.1 netmask 255.0.0.0"
+iface_eth0="PH_IP_ALICE broadcast 10.1.255.255 netmask 255.255.0.0"
+
+# For setting the default gateway
+#
+gateway="eth0/PH_IP1_MOON"
+
diff --git a/testing/hosts/alice/etc/init.d/iptables b/testing/hosts/alice/etc/init.d/iptables
new file mode 100755
index 000000000..1097ac5a4
--- /dev/null
+++ b/testing/hosts/alice/etc/init.d/iptables
@@ -0,0 +1,74 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow NAT-T
+ iptables -A INPUT -i eth0 -p udp --sport 4500 --dport 4500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 4500 --sport 4500 -j ACCEPT
+
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/hosts/alice/etc/init.d/net.eth0 b/testing/hosts/alice/etc/init.d/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/alice/etc/init.d/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/alice/etc/ipsec.conf b/testing/hosts/alice/etc/ipsec.conf
new file mode 100755
index 000000000..d6cdbba7b
--- /dev/null
+++ b/testing/hosts/alice/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn nat-t
+ left=%defaultroute
+ leftcert=aliceCert.pem
+ leftid=alice@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightid=@sun.strongswan.org
+ rightsubnet=10.2.0.0/16
+ auto=add
diff --git a/testing/hosts/alice/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/hosts/alice/etc/ipsec.d/cacerts/strongswanCert.pem
new file mode 100644
index 000000000..0de3b268d
--- /dev/null
+++ b/testing/hosts/alice/etc/ipsec.d/cacerts/strongswanCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMDE0NVoXDTE0MDkwODExMDE0NVowRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
+Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y
+X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f
+FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc
+4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/
+7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5
+gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr
+K+1LwdqRxo7HgMRiDw8CAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0jBGYw
+ZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYD
+VQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3Qg
+Q0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAJrXTj5gWS37myHHhii9drYwkMFyDHS/
+lHU8rW/drcnHdus507+qUhNr9SiEAHg4Ywj895UDvT0a1sFaw44QyEa/94iKA8/n
++g5kS1IrKvWu3wu8UI3EgzChgHV3cncQlQWbK+FI9Y3Ax1O1np1r+wLptoWpKKKE
+UxsYcxP9K4Nbyeon0AIHOajUheiL3t6aRc3m0o7VU7Do6S2r+He+1Zq/nRUfFeTy
+0Atebkn8tmUpPSKWaXkmwpVNrjZ1Qu9umAU+dtJyhzL2zmnyhPC4VqpsKCOp7imy
+gKZvUIKPm1zyf4T+yjwxwkiX2xVseoM3aKswb1EoZFelHwndU7u0GQ8=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/alice/etc/ipsec.d/certs/aliceCert.pem b/testing/hosts/alice/etc/ipsec.d/certs/aliceCert.pem
new file mode 100644
index 000000000..e99ae8ec7
--- /dev/null
+++ b/testing/hosts/alice/etc/ipsec.d/certs/aliceCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEHzCCAwegAwIBAgIBBTANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjQzOVoXDTA5MDkwOTExMjQzOVowVzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsTBVNhbGVz
+MR0wGwYDVQQDFBRhbGljZUBzdHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAK7FyvkE18/oujCaTd8GXBNOH+Cvoy0ibJ8j2sNsBrer
+GS1lgxRs8zaVfK9fosadu0UZeWIHsOKkew5469sPvkKK2SGGH+pu+x+xO/vuaEG4
+FlkAu8iGFWLQycLt6BJfcqw7FT8rwNuD18XXBXmP7hRavi/TEElbVYHbO7lm8T5W
+6hTr/sYddiSB7X9/ba7JBy6lxmBcUAx5bjiiHLaW/llefkqyhc6dw5nvPZ2DchvH
+v/HWvLF9bsvxbBkHU0/z/CEsRuMBI7EPEL4rx3UqmuCUAqiMJTS3IrDaIlfJOLWc
+KlbsnE6hHpwmt9oDB9iWBY9WeZUSAtJGFw4b7FCZvQ0CAwEAAaOCAQYwggECMAkG
+A1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBRZmh0JtiNTjBsQsfD7ECNa
+60iG2jBtBgNVHSMEZjBkgBRdp91wBlEyfue2bbO15eBg6i5N76FJpEcwRTELMAkG
+A1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0
+cm9uZ1N3YW4gUm9vdCBDQYIBADAfBgNVHREEGDAWgRRhbGljZUBzdHJvbmdzd2Fu
+Lm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3Jn
+L3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQADdQIlJkFtmHEjtuyo
+2aIcrsUx98FtvVgB7RpQB8JZlly7UEjvX0CIIvW/7Al5/8h9s1rhrRffX7nXQKAQ
+AmPnvD2Pp47obDnHqm/L109S1fcL5BiPN1AlgsseUBwzdqBpyRncPXZoAuBh/BU5
+D/1Dip0hXgB/X6+QymSzRJoSKfpeXVICj1kYH1nIkn0YXthYF3BTrCheCzBlKn0S
+CixbCUYsUjtSqld0nG76jyGb/gnWntNettH+RXWe1gm6qREJwfEFdeYviTqx2Uxi
+6sBKG/XjNAcMArXb7V6w0YAwCyjwCl49B+mLZaFH+9izzBJ7NyVqhH8ToB1gt0re
+JGhV
+-----END CERTIFICATE-----
diff --git a/testing/hosts/alice/etc/ipsec.d/private/aliceKey.pem b/testing/hosts/alice/etc/ipsec.d/private/aliceKey.pem
new file mode 100644
index 000000000..045ef0405
--- /dev/null
+++ b/testing/hosts/alice/etc/ipsec.d/private/aliceKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEArsXK+QTXz+i6MJpN3wZcE04f4K+jLSJsnyPaw2wGt6sZLWWD
+FGzzNpV8r1+ixp27RRl5Ygew4qR7Dnjr2w++QorZIYYf6m77H7E7++5oQbgWWQC7
+yIYVYtDJwu3oEl9yrDsVPyvA24PXxdcFeY/uFFq+L9MQSVtVgds7uWbxPlbqFOv+
+xh12JIHtf39trskHLqXGYFxQDHluOKIctpb+WV5+SrKFzp3Dme89nYNyG8e/8da8
+sX1uy/FsGQdTT/P8ISxG4wEjsQ8QvivHdSqa4JQCqIwlNLcisNoiV8k4tZwqVuyc
+TqEenCa32gMH2JYFj1Z5lRIC0kYXDhvsUJm9DQIDAQABAoIBAEsjnnARNPeeBu5+
+aJxKD6v9Gpdu66ir9Cc3MwZxmzG7zcdGrWRKswX0nvaHF2Rsy+aZXSZYSCQosv81
+3bEAw7u4FkHjeDVCIZUujatyhEA89N6vAgzkGK2zNgsoXW4IuzRw8mGGXhQCSvIz
+z5bD2ofFu560D3x6V/jMWJENQQqbfWuD27OI+bZp92K2DGM6MoSbdNnd886F2oWR
+4pQfrwoxmSm7JFFARoe4t6pZPy4G+5jjnrhB3kblxONaV297nvSby9Ctfke7oOkM
+A3JpzNzEmrjjb2M8GKkYmbm6P+0ARdYIToD0sFpbRCdjJAKLadwNNnk2kijxPvQh
+HNHGy8ECgYEA2uD922oiNaIvBR+rJ/zRsJg7Dth+upGePiieOZdS0S/dZUFEXuK7
+PdLZOcelQP2fIFRdODLEpkkOii292Ej3zixgzu9QYSfCdhcOoeV+RiAC7XEBBMqc
+gFI1DdL91KGSmMNZ+B8yocA31pwQQsVFDUpvgqpA8fxsZkRI9oVSiOsCgYEAzGna
+At/Kk9AQfiM7fpjBygYUt1ZErHsPJhLPVXmqx7+FuB2+RQvTMBS4sRdG6yC4Kd1y
+CNIo83Yzv2IQGyNOCcGr60OPeqzTSQ6AUn7VxMY5EJZ880nfXBud7mj+CbyFi48V
+Sh2qziF18aUYm7z4eJCTpLlFjPzHcoU1ORM0U+cCgYEAzCWp4Kp/OdMJVBgThXpz
+AekavGAE43LKS2OLIGAZqG6iaryTToTe62zrms6xPYrQjlDhmXcQn5/oZc0AEukL
+6ErQCHKBX/y7jXU3+pyYSEO3N0t9DcEEc1M5lKlEgrwohT8/fQNsMB2edxacvApO
+u3S/yPmPFaTAXio2e2gicP0CgYEAp3PjM02PDu14RUypdTjAL7YxjErwcPdSXpc0
+H8pOm9mKOlyrPLbGJ3IiJnhyETW5iBovS4iWIXNoStSTaxfN2vI72rt6sz0WzJdD
+idD7X3oezzboXwjaIANDqkV6LhGwuLXa898/yCLjErRzZ0kzptiRCnT3w9pjrK3w
+/rN7v2sCgYAEwfgrwjb7+JUaSSaf6TlbM9/ZuTRBVN0OTQz2JVhokeAePeFjHzXt
+nzJI2ETYlIu6e1VaFzHb6dp84PzWfLV7Kk8hZqJeCQN4RmQ04oNBllWoOZPbN7oa
+8pAMk/DCsBxcM/GvnDQJlDVLQRyY64zJU8EI0rF1t+zosIyGtXom/A==
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/alice/etc/ipsec.secrets b/testing/hosts/alice/etc/ipsec.secrets
new file mode 100644
index 000000000..5837fc7d7
--- /dev/null
+++ b/testing/hosts/alice/etc/ipsec.secrets
@@ -0,0 +1,9 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA aliceKey.pem
+
+
+
+
+
+
diff --git a/testing/hosts/alice/etc/runlevels/default/net.eth0 b/testing/hosts/alice/etc/runlevels/default/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/alice/etc/runlevels/default/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/bob/etc/conf.d/hostname b/testing/hosts/bob/etc/conf.d/hostname
new file mode 100644
index 000000000..bbf5a2ea6
--- /dev/null
+++ b/testing/hosts/bob/etc/conf.d/hostname
@@ -0,0 +1 @@
+HOSTNAME=bob
diff --git a/testing/hosts/bob/etc/conf.d/net b/testing/hosts/bob/etc/conf.d/net
new file mode 100644
index 000000000..09133acad
--- /dev/null
+++ b/testing/hosts/bob/etc/conf.d/net
@@ -0,0 +1,10 @@
+# /etc/conf.d/net:
+
+# This is basically the ifconfig argument without the ifconfig $iface
+#
+iface_lo="127.0.0.1 netmask 255.0.0.0"
+iface_eth0="PH_IP_BOB broadcast 10.2.255.255 netmask 255.255.0.0"
+
+# For setting the default gateway
+#
+gateway="eth0/PH_IP1_SUN"
diff --git a/testing/hosts/bob/etc/init.d/iptables b/testing/hosts/bob/etc/init.d/iptables
new file mode 100755
index 000000000..7b8756b81
--- /dev/null
+++ b/testing/hosts/bob/etc/init.d/iptables
@@ -0,0 +1,74 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --sport 500 -j ACCEPT
+
+ # allow NAT-T
+ iptables -A INPUT -i eth0 -p udp --dport 4500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --sport 4500 -j ACCEPT
+
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/hosts/bob/etc/init.d/net.eth0 b/testing/hosts/bob/etc/init.d/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/bob/etc/init.d/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/bob/etc/ipsec.conf b/testing/hosts/bob/etc/ipsec.conf
new file mode 100755
index 000000000..cdef4e042
--- /dev/null
+++ b/testing/hosts/bob/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn nat-t
+ left=%defaultroute
+ leftcert=bobCert.pem
+ leftid=bob@strongswan.org
+ leftfirewall=yes
+ right=%any
+ rightsubnetwithin=10.1.0.0/16
+ auto=add
diff --git a/testing/hosts/bob/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/hosts/bob/etc/ipsec.d/cacerts/strongswanCert.pem
new file mode 100644
index 000000000..0de3b268d
--- /dev/null
+++ b/testing/hosts/bob/etc/ipsec.d/cacerts/strongswanCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMDE0NVoXDTE0MDkwODExMDE0NVowRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
+Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y
+X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f
+FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc
+4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/
+7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5
+gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr
+K+1LwdqRxo7HgMRiDw8CAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0jBGYw
+ZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYD
+VQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3Qg
+Q0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAJrXTj5gWS37myHHhii9drYwkMFyDHS/
+lHU8rW/drcnHdus507+qUhNr9SiEAHg4Ywj895UDvT0a1sFaw44QyEa/94iKA8/n
++g5kS1IrKvWu3wu8UI3EgzChgHV3cncQlQWbK+FI9Y3Ax1O1np1r+wLptoWpKKKE
+UxsYcxP9K4Nbyeon0AIHOajUheiL3t6aRc3m0o7VU7Do6S2r+He+1Zq/nRUfFeTy
+0Atebkn8tmUpPSKWaXkmwpVNrjZ1Qu9umAU+dtJyhzL2zmnyhPC4VqpsKCOp7imy
+gKZvUIKPm1zyf4T+yjwxwkiX2xVseoM3aKswb1EoZFelHwndU7u0GQ8=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/bob/etc/ipsec.d/certs/bobCert.pem b/testing/hosts/bob/etc/ipsec.d/certs/bobCert.pem
new file mode 100644
index 000000000..199d3eee2
--- /dev/null
+++ b/testing/hosts/bob/etc/ipsec.d/certs/bobCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBBjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjUzNFoXDTA5MDkwOTExMjUzNFowWDELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMRswGQYDVQQDFBJib2JAc3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDAJaejS3/lJfQHgw0nzvotgSQS8ey/6tvbx7s5RsWY
+27x9K5xd44aPrvP2Qpyq34IXRY6uPlIqeUTQN7EKpLrWCxMOT36x5N0Co9J5UWRB
+fJC141D+8+1RwJ9/baEIecpCvb0GfDOX0GXN5ltcJk82hZjE4y1yHC1FN7V3zdRg
+xmloupPuon+X3bTmyMQ93NKkg48CQGtqtfwQ0MqPiOWu8MBhdztfOyu6aW3EgviF
+ithLc02SeNzlpqB3M8GDfX+mr3OVDhhhC2OI+VRlZzz7KxJ13DUR2KkvLZR8Ak4E
+5lRjkUnTYd/f3OQYxfjC8idUmj5ojR6Fb0x1tsV/glzXAgMBAAGjggEEMIIBADAJ
+BgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQUaLN5EPOkOkVU3J1Ud0sl
++27OOHswbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJ
+BgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJz
+dHJvbmdTd2FuIFJvb3QgQ0GCAQAwHQYDVR0RBBYwFIESYm9iQHN0cm9uZ3N3YW4u
+b3JnMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwuc3Ryb25nc3dhbi5vcmcv
+c3Ryb25nc3dhbi5jcmwwDQYJKoZIhvcNAQEEBQADggEBAIyQLLxdeO8clplzRW9z
+TRR3J0zSedvi2XlIZ/XCsv0ZVfoBLLWcDp3QrxNiVZXvXXtzjPsDs+DAveZF9LGq
+0tIw1uT3JorbgNNrmWvxBvJoQTtSw4LQBuV7vF27jrposx3Hi5qtUXUDS6wVnDUI
+5iORqsrddnoDuMN+Jt7oRcvKfYSNwTV+m0ZAHdB5a/ARWO5UILOrxEA/N72NcDYN
+NdAd+bLaB38SbkSbh1xj/AGnrHxdJBF4h4mx4btc9gtBSh+dwBHOsn4TheqJ6bbw
+7FlXBowQDCJIswKNhWfnIepQlM1KEzmq5YX43uZO2b7amRaIKqy2vNE7+UNFYBpE
+Mto=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/bob/etc/ipsec.d/private/bobKey.pem b/testing/hosts/bob/etc/ipsec.d/private/bobKey.pem
new file mode 100644
index 000000000..42af98bb0
--- /dev/null
+++ b/testing/hosts/bob/etc/ipsec.d/private/bobKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAwCWno0t/5SX0B4MNJ876LYEkEvHsv+rb28e7OUbFmNu8fSuc
+XeOGj67z9kKcqt+CF0WOrj5SKnlE0DexCqS61gsTDk9+seTdAqPSeVFkQXyQteNQ
+/vPtUcCff22hCHnKQr29Bnwzl9BlzeZbXCZPNoWYxOMtchwtRTe1d83UYMZpaLqT
+7qJ/l9205sjEPdzSpIOPAkBrarX8ENDKj4jlrvDAYXc7XzsrumltxIL4hYrYS3NN
+knjc5aagdzPBg31/pq9zlQ4YYQtjiPlUZWc8+ysSddw1EdipLy2UfAJOBOZUY5FJ
+02Hf39zkGMX4wvInVJo+aI0ehW9MdbbFf4Jc1wIDAQABAoIBAGbSP5jUiAYZfzKd
+4GZTDfFXz/QLXcN9bFV51ihaRNb9jyn0MmLTpGgzGP3Iu4l8vWKyqB154AI2jqpV
+gvnNGOX9Wx8nTwbnD5WgELs24M1iWRXcJLWp1m8PAsrv4WJlueRpIEPeJsWwkSnT
+gUQYg/8LEqsZXnJXvanym7sWe/Wkh8i/UyMQJv7zwS+TZ5qeKRfSVo8/9622Ppsh
+n+zKFKnTUhiICUHFed4qZWyVR6NVyuzIYjeQy+VmBa5AOzmF549Izg6llwNrvJ8g
+DiIKSdtblMrN5OlmTra8LGn2QmlETipRb+4qx+MasbVI8pM1VMMQtBGAJYjhpC51
+rX/RLLECgYEA/Qk9PlUfw2aTA7I6a93pcjhUFTnKFVe9RdrwY7mds5t7dOAPcRBj
+5wnIv+OhVszoEo/uOPrgWmBu3ifkmcpPTe4NREFEVA99NOadiJDI/7oAj/Is4c5t
+CEb/zHTqKtYMVDrjwhszuPD3m2KNIJ38y4gkkrWT071xQBciztWhvYUCgYEAwmXV
+DFoNagTrNhf7Ep5sUek0O3nXPXY/cYKnKhlloUP41ftLbNvZ02qBQ6zqxPHtjGlB
+5sPeRQMFbVbmyb+97oa3Mrui1TPiTa5IBPyD36Gg0nFx+xLeXTsy8O8leoFcq02D
+1SDSye+fEdj2uYr+f33CIknQHUR4/xkOikgSQasCgYEAzTjOHBzsGw25VLkbmtqr
+eIDo6SIqnS7BCsPsTeWAWuhSs9L5kyjI7dxIniEffIfJ/SwQ+NO4XHRz1ugiBv1H
+Xpwg1Gfe5BJ/6QTVZaqP6qBPzm+LKUTDt3/l/Uwhk8Zwz2vHx2lKhMei+rpuXbLl
+EaoEh5yPHZ87F9Dr4Tbw7AUCgYAjtFpmE2AlWdPtsofdypUwkjmStvUuh7ptWcbk
+N5fv/7EDdE1NKDAg4Y3uZSMVmy27PVXqUY1QdZaYl356DaqP1dRuEAJ/UDE/fUQj
+DlIWT/Re0pFRwQxwaUAY+oOStZHUsL8G9SliB43a1FO0jm/h8LIoZBBCX+ItUGfY
+RBZ+UwKBgCToB2oPwDfrfCkScNozV7GPfcmHTR5bvvpYgRMGyuE1hAwLIWW9V4u9
+1Bp1vCR/C4kiUSBpYsGXLRqJ1GURueQoEbREE4ZvkmNV+t40uX3Fd8/OchAGi934
+0jYmd3dvN4MtF7O02YwpBzuH/wAwdxK0iDbdv+KEZb7TLdL37IN1
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/bob/etc/ipsec.secrets b/testing/hosts/bob/etc/ipsec.secrets
new file mode 100644
index 000000000..b3a0af048
--- /dev/null
+++ b/testing/hosts/bob/etc/ipsec.secrets
@@ -0,0 +1,8 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA bobKey.pem
+
+
+
+
+
diff --git a/testing/hosts/bob/etc/runlevels/default/net.eth0 b/testing/hosts/bob/etc/runlevels/default/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/bob/etc/runlevels/default/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/carol/etc/conf.d/hostname b/testing/hosts/carol/etc/conf.d/hostname
new file mode 100644
index 000000000..d5101b924
--- /dev/null
+++ b/testing/hosts/carol/etc/conf.d/hostname
@@ -0,0 +1 @@
+HOSTNAME=carol
diff --git a/testing/hosts/carol/etc/conf.d/net b/testing/hosts/carol/etc/conf.d/net
new file mode 100644
index 000000000..39470ad14
--- /dev/null
+++ b/testing/hosts/carol/etc/conf.d/net
@@ -0,0 +1,10 @@
+# /etc/conf.d/net:
+
+# This is basically the ifconfig argument without the ifconfig $iface
+#
+iface_lo="127.0.0.1 netmask 255.0.0.0"
+iface_eth0="PH_IP_CAROL broadcast 192.168.0.255 netmask 255.255.255.0"
+
+# For setting the default gateway
+#
+gateway="eth0/192.168.0.254"
diff --git a/testing/hosts/carol/etc/init.d/iptables b/testing/hosts/carol/etc/init.d/iptables
new file mode 100755
index 000000000..cd7ba23ff
--- /dev/null
+++ b/testing/hosts/carol/etc/init.d/iptables
@@ -0,0 +1,73 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/hosts/carol/etc/init.d/net.eth0 b/testing/hosts/carol/etc/init.d/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/carol/etc/init.d/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/carol/etc/ipsec.conf b/testing/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..3228f4e16
--- /dev/null
+++ b/testing/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,29 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/hosts/carol/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/hosts/carol/etc/ipsec.d/cacerts/strongswanCert.pem
new file mode 100644
index 000000000..0de3b268d
--- /dev/null
+++ b/testing/hosts/carol/etc/ipsec.d/cacerts/strongswanCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMDE0NVoXDTE0MDkwODExMDE0NVowRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
+Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y
+X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f
+FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc
+4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/
+7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5
+gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr
+K+1LwdqRxo7HgMRiDw8CAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0jBGYw
+ZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYD
+VQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3Qg
+Q0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAJrXTj5gWS37myHHhii9drYwkMFyDHS/
+lHU8rW/drcnHdus507+qUhNr9SiEAHg4Ywj895UDvT0a1sFaw44QyEa/94iKA8/n
++g5kS1IrKvWu3wu8UI3EgzChgHV3cncQlQWbK+FI9Y3Ax1O1np1r+wLptoWpKKKE
+UxsYcxP9K4Nbyeon0AIHOajUheiL3t6aRc3m0o7VU7Do6S2r+He+1Zq/nRUfFeTy
+0Atebkn8tmUpPSKWaXkmwpVNrjZ1Qu9umAU+dtJyhzL2zmnyhPC4VqpsKCOp7imy
+gKZvUIKPm1zyf4T+yjwxwkiX2xVseoM3aKswb1EoZFelHwndU7u0GQ8=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/carol/etc/ipsec.d/certs/carolCert.pem b/testing/hosts/carol/etc/ipsec.d/certs/carolCert.pem
new file mode 100644
index 000000000..8492fbd45
--- /dev/null
+++ b/testing/hosts/carol/etc/ipsec.d/certs/carolCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIBCjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDEwMTIxNDMxOFoXDTA5MTIzMTIxNDMxOFowWjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALgbhJIECOCGyNJ4060un/wBuJ6MQjthK5CAEPgX
+T/lvZynoSxhfuW5geDCCxQes6dZPeb6wJS4F5fH3qJoLM+Z4n13rZlCEyyMBkcFl
+vK0aNFY+ARs0m7arUX8B7Pfi9N6WHTYgO4XpeBHLJrZQz9AU0V3S0rce/WVuVjii
+S/cJhrgSi7rl87Qo1jYOA9P06BZQLj0dFNcWWrGpKp/hXvBF1OSP9b15jsgMlCCW
+LJqXmLVKDtKgDPLJZR19mILhgcHvaxxD7craL9GR4QmWLb0m84oAIIwaw+0npZJM
+YDMMeYeOtcepCWCmRy+XmsqcWu4rtNCu05W1RsXjYZEKBjcCAwEAAaOCAQYwggEC
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBRVNeym66J5uu+IfxhD
+j9InsWdG0TBtBgNVHSMEZjBkgBRdp91wBlEyfue2bbO15eBg6i5N76FJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBADAfBgNVHREEGDAWgRRjYXJvbEBzdHJvbmdz
+d2FuLm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u
+b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQCxMEp+Zdclc0aI
+U+jO3TmL81gcwea0BUucjZfDyvCSkDXcXidOez+l/vUueGC7Bqq1ukDF8cpVgGtM
+2HPxM97ZSLPInMgWIeLq3uX8iTtIo05EYqRasJxBIAkY9o6ja6v6z0CZqjSbi2WE
+HrHkFrkOTrRi7deGzbAAhWVjOnAfzSxBaujkdUxb6jGBc2F5qpAeVSbE+sAxzmSd
+hRyF3tUUwl4yabBzmoedJzlQ4anqg0G14QScBxgXkq032gKuzNVVxWRp6OFannKG
+C1INvsBWYtN62wjXlXXhM/M4sBFhmPpftVb+Amgr1jSspTX2dQsNqhI/WtNvLmfK
+omBYfxqp
+-----END CERTIFICATE-----
diff --git a/testing/hosts/carol/etc/ipsec.d/private/carolKey.pem b/testing/hosts/carol/etc/ipsec.d/private/carolKey.pem
new file mode 100644
index 000000000..0522355ce
--- /dev/null
+++ b/testing/hosts/carol/etc/ipsec.d/private/carolKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAuBuEkgQI4IbI0njTrS6f/AG4noxCO2ErkIAQ+BdP+W9nKehL
+GF+5bmB4MILFB6zp1k95vrAlLgXl8feomgsz5nifXetmUITLIwGRwWW8rRo0Vj4B
+GzSbtqtRfwHs9+L03pYdNiA7hel4EcsmtlDP0BTRXdLStx79ZW5WOKJL9wmGuBKL
+uuXztCjWNg4D0/ToFlAuPR0U1xZasakqn+Fe8EXU5I/1vXmOyAyUIJYsmpeYtUoO
+0qAM8sllHX2YguGBwe9rHEPtytov0ZHhCZYtvSbzigAgjBrD7SelkkxgMwx5h461
+x6kJYKZHL5eaypxa7iu00K7TlbVGxeNhkQoGNwIDAQABAoIBAQCnhwq8H4XAYYWN
+17quJPYZR6uqQfDmvYX5yD8osXXpgNC8Fo92z2wZnxje86+8S0DA7bLXrMs4NM/H
+vVcjTTxd5LcHrHN+o0eBRCVQeXYVgfnL3EH/coCa2Qugaa0q589wV+Ke5Pek5AyJ
+DHXegmyHaNoW6Qcq8L0dtigpAq3jTLG5w/3QCo8DMDKOGNR3AJrFpDlS/gW3JXuL
+Tn+PUojoWO9W6joDGYDTi4eeYyfZSajzwZvzecEpez3vwKN0pupvHA6BJCR8Mzkq
+5EYIH0hvWLtBy8uiWRXTfu/ggoQI9/Z5hBWIQk71m23uMIBbkm+oDn/1fLSBcWfK
+cr9RyM+RAoGBANpWewy7xCbkRV/90bgBNkTZ9HeFsFsWOgFVyB1XwM2E/nOqdRJc
+rxFt5Qt63DaXB+2REn231EIrsIz/Xd+R9KDl+yZOCY/m/mL4oquTPurEGJPzZdgW
+X3kUOFW1pbfcMcmzSp1FPufI17JPiePtUb/q3C4RAjCKlnskHftEyK1pAoGBANfd
+eEN8UzoV/R3WsGNDNOecMdIVAX9aiGnkLLraP7CRZ1heCH5y+RV1RB98yppkJG31
+fw5F8a6GoomkMHWGqhzDzQacZQV8w7C6rDY0Bk5TF5vemvJTGlrydwodfMvcJj8Y
+KZrS7A0iS3GAAmM6VGr3THyscszfJTq0NwE3v4KfAoGAY7L1wVzENxYpb6nRZ/p1
+s37rGODdJNrDZfSrympVygMexeZiSx4zevv5iQJzKCJTJnIGRY35yLV2iwvY68wU
+LpyV0Gn2B9Xs93idn0c/hahBqN2N9dxRgFJxXwHxSEGuInJScfo6vVCC3hNf3cpy
+d/Zg0FBH9a5zBIv7fM9t63ECgYAosrSt5I68cNDcA1IWJOGgmS47cYJqxGLbtA1K
+3UMMwx08592qGXsktIs3dIuuOBs2MAbYZg9+3Btg3/fS8KS576CEEpBpTHCIrWky
+fvSBZ+EXngyQi2J4qyYOXijdNpBvbNrLOeEPSNv4di39D05DLITbLJgoUBnwy3Fj
+ZWNR+QKBgEKn19f5QWs/O1DPWBXfvCSc01cuSUx20a6Z3B6Lxj+7MuXBjVxPkGge
+kEaZnNzwgm+QQ1C51nIn9gY4LZx7OxMy0idEss76aRq4Lb7I6XakBrCQLQ9IiTkv
+gNOeJYGsQv7tkIWWRlBIXjSBGwT6HzTEfN5cvdHSDzARGFGjwYfK
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/carol/etc/ipsec.secrets b/testing/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..797f18a01
--- /dev/null
+++ b/testing/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA carolKey.pem
+
+
+
+
diff --git a/testing/hosts/carol/etc/runlevels/default/net.eth0 b/testing/hosts/carol/etc/runlevels/default/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/carol/etc/runlevels/default/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/dave/etc/conf.d/hostname b/testing/hosts/dave/etc/conf.d/hostname
new file mode 100644
index 000000000..c3fabf331
--- /dev/null
+++ b/testing/hosts/dave/etc/conf.d/hostname
@@ -0,0 +1 @@
+HOSTNAME=dave
diff --git a/testing/hosts/dave/etc/conf.d/net b/testing/hosts/dave/etc/conf.d/net
new file mode 100644
index 000000000..db3753fb0
--- /dev/null
+++ b/testing/hosts/dave/etc/conf.d/net
@@ -0,0 +1,10 @@
+# /etc/conf.d/net:
+
+# This is basically the ifconfig argument without the ifconfig $iface
+#
+iface_lo="127.0.0.1 netmask 255.0.0.0"
+iface_eth0="PH_IP_DAVE broadcast 192.168.0.255 netmask 255.255.255.0"
+
+# For setting the default gateway
+#
+gateway="eth0/192.168.0.254"
diff --git a/testing/hosts/dave/etc/init.d/iptables b/testing/hosts/dave/etc/init.d/iptables
new file mode 100755
index 000000000..cd7ba23ff
--- /dev/null
+++ b/testing/hosts/dave/etc/init.d/iptables
@@ -0,0 +1,73 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/hosts/dave/etc/init.d/net.eth0 b/testing/hosts/dave/etc/init.d/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/dave/etc/init.d/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/dave/etc/ipsec.conf b/testing/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..76623491c
--- /dev/null
+++ b/testing/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_DAVE
+ leftcert=daveCert.pem
+ leftid=dave@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/hosts/dave/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/hosts/dave/etc/ipsec.d/cacerts/strongswanCert.pem
new file mode 100644
index 000000000..0de3b268d
--- /dev/null
+++ b/testing/hosts/dave/etc/ipsec.d/cacerts/strongswanCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMDE0NVoXDTE0MDkwODExMDE0NVowRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
+Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y
+X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f
+FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc
+4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/
+7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5
+gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr
+K+1LwdqRxo7HgMRiDw8CAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0jBGYw
+ZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYD
+VQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3Qg
+Q0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAJrXTj5gWS37myHHhii9drYwkMFyDHS/
+lHU8rW/drcnHdus507+qUhNr9SiEAHg4Ywj895UDvT0a1sFaw44QyEa/94iKA8/n
++g5kS1IrKvWu3wu8UI3EgzChgHV3cncQlQWbK+FI9Y3Ax1O1np1r+wLptoWpKKKE
+UxsYcxP9K4Nbyeon0AIHOajUheiL3t6aRc3m0o7VU7Do6S2r+He+1Zq/nRUfFeTy
+0Atebkn8tmUpPSKWaXkmwpVNrjZ1Qu9umAU+dtJyhzL2zmnyhPC4VqpsKCOp7imy
+gKZvUIKPm1zyf4T+yjwxwkiX2xVseoM3aKswb1EoZFelHwndU7u0GQ8=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/dave/etc/ipsec.d/certs/daveCert.pem b/testing/hosts/dave/etc/ipsec.d/certs/daveCert.pem
new file mode 100644
index 000000000..abd1554e5
--- /dev/null
+++ b/testing/hosts/dave/etc/ipsec.d/certs/daveCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIBCDANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjY1MVoXDTA5MDkwOTExMjY1MVowWzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEzARBgNVBAsTCkFjY291
+bnRpbmcxHDAaBgNVBAMUE2RhdmVAc3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDGbCmUY6inir71/6RWebegcLUTmDSxRqpRONDx
+2IRUEuES5EKc7qsjRz45XoqjiywCQRjYW33fUEEY6r7fnHk70CyUnWeZyr7v4D/2
+LjBN3smDE6/ZZrzxPx+xphlUigYOF/vt4gUiW1dOZ5rcnxG9+eNrSL6gWNNg1iuE
+RflSTbmHV6TVmGU2PGddKGZ6XfqWfdA+6iOi2+oyqw6aH4u4hfXhJyMROEOhLdAF
+UvzU9UizEXSqsmEOSodS9vypVJRYTbZcx70e9Q7g2MghHvtQY6mVgBzAwakDBCt/
+98lAlKDeXXOQqPcqAZSc2VjG8gEmkr1dum8wsJw8C2liKGRFAgMBAAGjggEFMIIB
+ATAJBgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQU3pC10RxsZDx0UNNq
++Ihsoxk4+3IwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUx
+CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQD
+ExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQAwHgYDVR0RBBcwFYETZGF2ZUBzdHJvbmdz
+d2FuLm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u
+b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQAnotcnOE0tJDLy
+8Vh1+naT2zrxx9UxfMIeFljwhDqRiHXSLDAbCOnAWoqj8C9riuZwW7UImIIQ9JT9
+Gdktt4bbIcG25rGMC3uqP71CfaAz/SwIZZ2vm8Jt2ZzzSMHsE5qbjDIRAZnq6giR
+P2s6PVsMPSpvH34sRbE0UoWJSdtBZJP5bb+T4hc9gfmbyTewwMnjh09KkGJqVxKV
+UC/1z1U9zb3X1Gc9y+zI67/D46wM6KdRINaqPdK26aYRFM+/DLoTfFk07dsyz7lt
+0C+/ityQOvpfjVlZ/OepT92eWno4FuNRJuUP5/gYiHvSsjZbazqG02qGhJ6VgtGT
+5qILUTmI
+-----END CERTIFICATE-----
diff --git a/testing/hosts/dave/etc/ipsec.d/private/daveKey.pem b/testing/hosts/dave/etc/ipsec.d/private/daveKey.pem
new file mode 100644
index 000000000..1cbaa183f
--- /dev/null
+++ b/testing/hosts/dave/etc/ipsec.d/private/daveKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAxmwplGOop4q+9f+kVnm3oHC1E5g0sUaqUTjQ8diEVBLhEuRC
+nO6rI0c+OV6Ko4ssAkEY2Ft931BBGOq+35x5O9AslJ1nmcq+7+A/9i4wTd7JgxOv
+2Wa88T8fsaYZVIoGDhf77eIFIltXTmea3J8Rvfnja0i+oFjTYNYrhEX5Uk25h1ek
+1ZhlNjxnXShmel36ln3QPuojotvqMqsOmh+LuIX14ScjEThDoS3QBVL81PVIsxF0
+qrJhDkqHUvb8qVSUWE22XMe9HvUO4NjIIR77UGOplYAcwMGpAwQrf/fJQJSg3l1z
+kKj3KgGUnNlYxvIBJpK9XbpvMLCcPAtpYihkRQIDAQABAoIBAQCQP7nKotjNVFSX
+Sg4Sv9H61XUOlaxY5GKVQZTE/P7WkBMIROEYbXoE35og4tYvJtILoX+KapkLa7Cn
+iKDSt1J7ZU/DitryNy6v/HsDYXjEY55jqEBC8CmTyKwl3fa0OtNEE7OWsKXC4FyM
+J02x7gJb9fqa1/udXnXtBEYGl0g1x/vDmuhLgKyq6eliTm/orAyjGK2KfRxu06eS
+YUZObr25wC7yDLHCBsWHGNVC7ZyxQoxcPOu9WNwlWYu92ZJMdf3+rIgZSeXxCn3U
+3CWAC9tL1HnKC/twbyWEc2Gy0lZaQSgTJzaRtKOlqBTc5Szb4l1ibmyeAA7NanXK
+wnUYfiZRAoGBAOWW0+4lzZhWOxK/cYwM5+eoI66MhPECFVK2sL8iC34BKGFRCrSd
+YS/nugWiAu30knIBrw8z9BN0gYEfiE/EZyP5TbjtabKDN28xQa1+bw9Sr+5g5TcR
+HFvZRkJWSYGoIuVO22eXUh+1hwx3KZP/UX6pwkrc2dxQLxNk0mo/BexPAoGBAN0/
+geik9GNIjbKwSPLvIIwcmO4TZja2RJy9NCTJOrJZFpCII6HvOiO0eYx3+So+KblG
+n4AUxrhi4jq1/mAA+VUt4B9ywKH8xzGwhno78dJ1lvydpuzXSTHOEgsWh9Kme05P
+syt/t1C0ZkWqOKsBGk1f7dU9IOWuOkpVUbbMX10rAoGBALp0S5lUyiu1nDQVljmP
+IadZPeE77ZttfbO2+sO++mZSumCOWItmZM9q+gApGwf1YBmGlI1cPBSwwZwD58gg
+UUM97IkLBpQbTKHY9uXXkIp5NLf7qSuXkdhmFFE7kmbiDbT83eK7Wc62tf7Bp9qx
+t5WOeGQkCCqMVC8D6n6uwDixAoGABV4jErfdzgLWnT01p98xVPTkqPIDitRFOeBF
+QZc4O1d5+quy4ZziNjeMs2G9w86aSIp0GDFo2NRdVLtRnpande+U/m5UShnN42C7
+AoAtz8NWlG5mvFxExFaRjX9QcEXlu/KnECkbE3Qs/wewNEXkk3f+VywSfkAJ3f/P
+6bVvot0CgYBA1B9SXYhclR3KNZJPRuTn9OQ/TqLmcCMN62dIhPW4WZo2ixZH3YdS
+PE/bYmYfZUPt7MnOSNSnuLKineIf1Dipz0gjuSyFGAs5DE+N+8GWYo00n+0e3TLL
+pcBj4nOdIVPTZ31IFeVbi06dCYmzLPAGDeLe1M1Z7fakNky1Wv+Sdg==
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/dave/etc/ipsec.secrets b/testing/hosts/dave/etc/ipsec.secrets
new file mode 100644
index 000000000..3fa796491
--- /dev/null
+++ b/testing/hosts/dave/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA daveKey.pem
+
+
+
+
diff --git a/testing/hosts/dave/etc/runlevels/default/net.eth0 b/testing/hosts/dave/etc/runlevels/default/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/dave/etc/runlevels/default/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/default/etc/hosts b/testing/hosts/default/etc/hosts
new file mode 100644
index 000000000..b8bc8da66
--- /dev/null
+++ b/testing/hosts/default/etc/hosts
@@ -0,0 +1,34 @@
+# /etc/hosts: This file describes a number of hostname-to-address
+# mappings for the TCP/IP subsystem. It is mostly
+# used at boot time, when no name servers are running.
+# On small systems, this file can be used instead of a
+# "named" name server. Just add the names, addresses
+# and any aliases to this file...
+#
+
+127.0.0.1 localhost
+
+192.168.0.254 uml0.strongswan.org uml0
+10.1.0.254 uml1.strongswan.org uml1
+10.2.0.254 uml1.strongswan.org uml2
+
+PH_IP_ALICE alice.strongswan.org alice
+PH_IP_VENUS venus.strongswan.org venus
+PH_IP1_MOON moon1.strongswan.org moon1
+PH_IP_MOON moon.strongswan.org moon
+PH_IP_CAROL carol.strongswan.org carol
+PH_IP1_CAROL carol1.strongswan.org carol1
+PH_IP_WINNETOU winnetou.strongswan.org winnetou crl.strongswan.org ocsp.strongswan.org ldap.strongswan.org
+PH_IP_DAVE dave.strongswan.org dave
+PH_IP1_DAVE dave1.strongswan.org dave1
+PH_IP_SUN sun.strongswan.org sun
+PH_IP1_SUN sun1.strongswan.org sun1
+PH_IP_BOB bob.strongswan.org bob
+
+# IPV6 versions of localhost and co
+::1 ip6-localhost ip6-loopback
+fe00::0 ip6-localnet
+ff00::0 ip6-mcastprefix
+ff02::1 ip6-allnodes
+ff02::2 ip6-allrouters
+ff02::3 ip6-allhosts
diff --git a/testing/hosts/moon/etc/conf.d/hostname b/testing/hosts/moon/etc/conf.d/hostname
new file mode 100644
index 000000000..78e695337
--- /dev/null
+++ b/testing/hosts/moon/etc/conf.d/hostname
@@ -0,0 +1 @@
+HOSTNAME=moon
diff --git a/testing/hosts/moon/etc/conf.d/net b/testing/hosts/moon/etc/conf.d/net
new file mode 100644
index 000000000..7dec60ba5
--- /dev/null
+++ b/testing/hosts/moon/etc/conf.d/net
@@ -0,0 +1,11 @@
+# /etc/conf.d/net:
+
+# This is basically the ifconfig argument without the ifconfig $iface
+#
+iface_lo="127.0.0.1 netmask 255.0.0.0"
+iface_eth0="PH_IP_MOON broadcast 192.168.0.255 netmask 255.255.255.0"
+iface_eth1="PH_IP1_MOON broadcast 10.1.255.255 netmask 255.255.0.0"
+
+# For setting the default gateway
+#
+gateway="eth0/192.168.0.254"
diff --git a/testing/hosts/moon/etc/init.d/iptables b/testing/hosts/moon/etc/init.d/iptables
new file mode 100755
index 000000000..7f46267c2
--- /dev/null
+++ b/testing/hosts/moon/etc/init.d/iptables
@@ -0,0 +1,76 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # enable IP forwarding
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/hosts/moon/etc/init.d/net.eth0 b/testing/hosts/moon/etc/init.d/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/moon/etc/init.d/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/moon/etc/init.d/net.eth1 b/testing/hosts/moon/etc/init.d/net.eth1
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/moon/etc/init.d/net.eth1
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/moon/etc/ipsec.conf b/testing/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..a0e97e057
--- /dev/null
+++ b/testing/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,36 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=192.168.0.1
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+
+conn net-net
+ leftsubnet=10.1.0.0/16
+ right=192.168.0.2
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn host-host
+ right=192.168.0.2
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn rw
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
diff --git a/testing/hosts/moon/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/hosts/moon/etc/ipsec.d/cacerts/strongswanCert.pem
new file mode 100644
index 000000000..0de3b268d
--- /dev/null
+++ b/testing/hosts/moon/etc/ipsec.d/cacerts/strongswanCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMDE0NVoXDTE0MDkwODExMDE0NVowRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
+Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y
+X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f
+FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc
+4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/
+7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5
+gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr
+K+1LwdqRxo7HgMRiDw8CAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0jBGYw
+ZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYD
+VQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3Qg
+Q0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAJrXTj5gWS37myHHhii9drYwkMFyDHS/
+lHU8rW/drcnHdus507+qUhNr9SiEAHg4Ywj895UDvT0a1sFaw44QyEa/94iKA8/n
++g5kS1IrKvWu3wu8UI3EgzChgHV3cncQlQWbK+FI9Y3Ax1O1np1r+wLptoWpKKKE
+UxsYcxP9K4Nbyeon0AIHOajUheiL3t6aRc3m0o7VU7Do6S2r+He+1Zq/nRUfFeTy
+0Atebkn8tmUpPSKWaXkmwpVNrjZ1Qu9umAU+dtJyhzL2zmnyhPC4VqpsKCOp7imy
+gKZvUIKPm1zyf4T+yjwxwkiX2xVseoM3aKswb1EoZFelHwndU7u0GQ8=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/moon/etc/ipsec.d/certs/moonCert.pem b/testing/hosts/moon/etc/ipsec.d/certs/moonCert.pem
new file mode 100644
index 000000000..d8fbfa1c9
--- /dev/null
+++ b/testing/hosts/moon/etc/ipsec.d/certs/moonCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEDTCCAvWgAwIBAgIBAzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMTcyNVoXDTA5MDkwOTExMTcyNVowRjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHDAaBgNVBAMTE21vb24u
+c3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv
+ri4QmsCnG0N7bxqeUZTQhcmZ/iyN4RsmHwFsiOc06xpnZ7Fbx9gzi/OswU6KGL+F
+f9PfvOY36bDTZU8V2QaL30RQUXz3JlG+jUyP9zjqlhsvVYS/cImvqgo3uUkQ0YCD
+v2SafTlaQfBOaPFElNEP/H2YSiyB6X80IcHsOMYpskVqPY8785FehjF+pxuyRCK+
+9HXmd+iWdnC09u4qgKRa3L0IamU3q1/BK/afkHK2IAIN4YgM7GzepHVD0f7Exf9U
+esJEeh4hDZwSjcMzdybrY9XBxzGqLGPOF128jr+5weUZiBW+RzeBw/gsK1nSPeuX
+Od2lPJjTGj+6V3YK6qibAgMBAAGjggEFMIIBATAJBgNVHRMEAjAAMAsGA1UdDwQE
+AwIDqDAdBgNVHQ4EFgQU5eQQh2wqxL6thUlCpt52WDA6n8EwbQYDVR0jBGYwZIAU
+XafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQK
+ExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GC
+AQAwHgYDVR0RBBcwFYITbW9vbi5zdHJvbmdzd2FuLm9yZzA5BgNVHR8EMjAwMC6g
+LKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0G
+CSqGSIb3DQEBBAUAA4IBAQAvLykhZnqldrsMcbYB36WzWKk+hOihr5dU3fv8Z4ec
+tsa3gzxXSefDCxGoezVJ4QXdpdNxxFn31A+r1gxKyGI5JL6EyWz6Y462zp9lE7nW
+EIC4ldJwxAXqzDEMcJphO29hApyU9TWsWDa4kL5AKtLFLwH3/Uv/jAzAy+qXIO8h
+wLtB+wcmhSo8OFY9kX/cyhht7eb7yD/r2e3wVBOCRk7jePe4yWhN8NJAKwfrEd1K
+iGq15ymdmeomhplHRsLZwA2VsCspUNZ/eXjG21s3nEoxcCOcQUz3Q7q4ZgBTZoCW
+kAc6FQ5zxoZrmzNWFqzb06jmUVlt7baGtdjT7rEt+dcp
+-----END CERTIFICATE-----
diff --git a/testing/hosts/moon/etc/ipsec.d/private/moonKey.pem b/testing/hosts/moon/etc/ipsec.d/private/moonKey.pem
new file mode 100644
index 000000000..89197a447
--- /dev/null
+++ b/testing/hosts/moon/etc/ipsec.d/private/moonKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAr64uEJrApxtDe28anlGU0IXJmf4sjeEbJh8BbIjnNOsaZ2ex
+W8fYM4vzrMFOihi/hX/T37zmN+mw02VPFdkGi99EUFF89yZRvo1Mj/c46pYbL1WE
+v3CJr6oKN7lJENGAg79kmn05WkHwTmjxRJTRD/x9mEosgel/NCHB7DjGKbJFaj2P
+O/ORXoYxfqcbskQivvR15nfolnZwtPbuKoCkWty9CGplN6tfwSv2n5BytiACDeGI
+DOxs3qR1Q9H+xMX/VHrCRHoeIQ2cEo3DM3cm62PVwccxqixjzhddvI6/ucHlGYgV
+vkc3gcP4LCtZ0j3rlzndpTyY0xo/uld2CuqomwIDAQABAoIBAECAVQ1npCA2lFo3
+erByB49f75sIhVc6NPuUGrO8uBbn0vPwUGAASdLzKW5eMvXlDDx5qFLXSjdxJ6kV
+4ymEWzDzsmNC5/zeJtkti9S30j/fCPAiF/Ep4oOKjOHUt4zjPqoglVFbdLk8yHwh
+b6Pcd73E2GAXq6uvDTMYydhvJ+KaozAfbXmQ9vf3HbneI6xmgAug209Cu+gpMspW
+4IunMMY/668neRmM7jh+4JNLMqJhCrmQpLkIlRux2yNFzxkF8RrqptGzaLf4KxNF
+rRRUThHUfWmB/EvggzJgUMuVA2Pa0bKNvBbbQuwPqXMxLHMGBjvJ8wimsLzJZeXL
+fgsyPKECgYEA5x//2cmlKL3LbprRpfSzVOPqM3OSeEqseQtPun9Gs7WNVZZVc/ZJ
+O2hjdc9qDGjak3lDSwVbYl8B1kqfGTTLB1sl2171aDJQOWdNV3WQtexUKEhC4Ewn
+yXEDoVGAXJtiCj34QYHjoMEHUqfabKyWKUcaK8hbMsOhYPOorfLXg9MCgYEAwpaP
+W68NJGu5Zxsdz62rOiPNb58cuoxLDZsJ1sMKJO7BdPIqTZ0oGNdgt5phyc3ROBSH
+cjqZdzpim1gXGm4ocGvwg3APNQN6DLBknJNZmHzPd7RLSz2UxhTHRTfHAltQPcmW
+cJVBHsrsS0QnvDndXfzLuLq12S6UZasR5eBdcxkCgYEAizBuOI6DdGG4nceG8lbH
+mRwY8xtq3h66d7skLMBxp9ByaVS76bYsrCZVn6Fl0EtlNuMUb52uRzPIO3F9FwUA
+MFHoHpC1YibKwYdAwKcAm07T7950x/eVDm+NLB2VHDBHfruLQogiubEF4/VKSaA2
+Xm1/iVaD9bJzAZw7vWY9/BkCgYB/Xe9uErGmgkB0BaLIuiNWxfKFOn+id4v01uNk
+yHtOW10TgCNCdDi3sdpjs1CIuAhXDdDuav7itLuwdMOCkFI16+EdF29Mwv7TaW4h
+sq01i5R9BO03zZIg6Z7ZZr4Dg+OM3fNzs65RSn/KcE0V/kYwa/So8MVw5/VIauYn
+MmnYmQKBgDEFWQPyPH242olRqtE0yDp8qVHEjJp7mU822YFbyCyAUnttqOS+/5/u
+Z7H95QZHGaQESL1tcNnaiRASJAKDWjKOdM/TTotWjCn65v+DHvgk/IJeYJVHoGBS
+pBE+wJ8AZJu3t9GVp3PxFxHIjxUrEKG0rli7bYv8F245+Wx8DeXI
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/moon/etc/ipsec.secrets b/testing/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..c90b4c4a3
--- /dev/null
+++ b/testing/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA moonKey.pem
+
+
+
+
diff --git a/testing/hosts/moon/etc/runlevels/default/net.eth0 b/testing/hosts/moon/etc/runlevels/default/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/moon/etc/runlevels/default/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/moon/etc/runlevels/default/net.eth1 b/testing/hosts/moon/etc/runlevels/default/net.eth1
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/moon/etc/runlevels/default/net.eth1
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/ssh_host_rsa_key.pub b/testing/hosts/ssh_host_rsa_key.pub
new file mode 100644
index 000000000..a5f71de4e
--- /dev/null
+++ b/testing/hosts/ssh_host_rsa_key.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAsxKfTm05po6leGD8C+M0eAR5EE4s1pQXc0D/dVlqrmfZ65h5BFQY9lnwpCvapV6OVqKWx8ICmeIH3OhaPxPPNKlU81f3d0xgh8BRJpWh459DYkRVa5f7ax5eeFE1lelj9s1d0seUl/IZolpJ8Wmt9TN1hwJ0mrkwN4670rb3urc=
diff --git a/testing/hosts/sun/etc/conf.d/hostname b/testing/hosts/sun/etc/conf.d/hostname
new file mode 100644
index 000000000..bc042b68b
--- /dev/null
+++ b/testing/hosts/sun/etc/conf.d/hostname
@@ -0,0 +1 @@
+HOSTNAME=sun
diff --git a/testing/hosts/sun/etc/conf.d/net b/testing/hosts/sun/etc/conf.d/net
new file mode 100644
index 000000000..0f8dc57b1
--- /dev/null
+++ b/testing/hosts/sun/etc/conf.d/net
@@ -0,0 +1,13 @@
+# /etc/conf.d/net:
+
+# This is basically the ifconfig argument without the ifconfig $iface
+#
+iface_lo="127.0.0.1 netmask 255.0.0.0"
+iface_eth0="PH_IP_SUN broadcast 192.168.0.255 netmask 255.255.255.0"
+iface_eth1="PH_IP1_SUN broadcast 10.2.255.255 netmask 255.255.0.0"
+
+# For setting the default gateway
+#
+gateway="eth0/192.168.0.254"
+
+
diff --git a/testing/hosts/sun/etc/init.d/iptables b/testing/hosts/sun/etc/init.d/iptables
new file mode 100755
index 000000000..aeaf472fb
--- /dev/null
+++ b/testing/hosts/sun/etc/init.d/iptables
@@ -0,0 +1,80 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # enable IP forwarding
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --sport 500 -j ACCEPT
+
+ # allow NAT-T
+ iptables -A INPUT -i eth0 -p udp --dport 4500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --sport 4500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/hosts/sun/etc/init.d/net.eth0 b/testing/hosts/sun/etc/init.d/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/sun/etc/init.d/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/sun/etc/init.d/net.eth1 b/testing/hosts/sun/etc/init.d/net.eth1
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/sun/etc/init.d/net.eth1
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/sun/etc/ipsec.conf b/testing/hosts/sun/etc/ipsec.conf
new file mode 100755
index 000000000..4d0299a08
--- /dev/null
+++ b/testing/hosts/sun/etc/ipsec.conf
@@ -0,0 +1,37 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_SUN
+ leftcert=sunCert.pem
+ leftid=@sun.strongswan.org
+ leftfirewall=yes
+
+conn net-net
+ leftsubnet=10.2.0.0/16
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
+
+conn host-host
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+ auto=add
+
+conn nat-t
+ leftsubnet=10.2.0.0/16
+ right=%any
+ rightsubnetwithin=10.1.0.0/16
+ auto=add
diff --git a/testing/hosts/sun/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/hosts/sun/etc/ipsec.d/cacerts/strongswanCert.pem
new file mode 100644
index 000000000..0de3b268d
--- /dev/null
+++ b/testing/hosts/sun/etc/ipsec.d/cacerts/strongswanCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMDE0NVoXDTE0MDkwODExMDE0NVowRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
+Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y
+X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f
+FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc
+4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/
+7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5
+gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr
+K+1LwdqRxo7HgMRiDw8CAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0jBGYw
+ZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYD
+VQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3Qg
+Q0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAJrXTj5gWS37myHHhii9drYwkMFyDHS/
+lHU8rW/drcnHdus507+qUhNr9SiEAHg4Ywj895UDvT0a1sFaw44QyEa/94iKA8/n
++g5kS1IrKvWu3wu8UI3EgzChgHV3cncQlQWbK+FI9Y3Ax1O1np1r+wLptoWpKKKE
+UxsYcxP9K4Nbyeon0AIHOajUheiL3t6aRc3m0o7VU7Do6S2r+He+1Zq/nRUfFeTy
+0Atebkn8tmUpPSKWaXkmwpVNrjZ1Qu9umAU+dtJyhzL2zmnyhPC4VqpsKCOp7imy
+gKZvUIKPm1zyf4T+yjwxwkiX2xVseoM3aKswb1EoZFelHwndU7u0GQ8=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/sun/etc/ipsec.d/certs/sunCert.pem b/testing/hosts/sun/etc/ipsec.d/certs/sunCert.pem
new file mode 100644
index 000000000..e7825e3db
--- /dev/null
+++ b/testing/hosts/sun/etc/ipsec.d/certs/sunCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIECzCCAvOgAwIBAgIBAjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMTU1M1oXDTA5MDkwOTExMTU1M1owRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN1bi5z
+dHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOQ8
+foB9h5BZ92gA5JkQTJNuoF6FAzoq91Gh7To27/g74p01+SUnsSaBfPmNfGp4avdS
+Ewy2dWMA/7uj0Dbe8MEKssNztp0JQubp2s7n8mrrQLGsqB6YAS09l75XDjS3yqTC
+AtH1kD4zAl/j/AyeQBuLR4CyJEmC/rqD3/a+pr42CaljuFBgBRpCTUpU4mlslZSe
+zv9wu61PwTFxb8VDlBHUd/lwkXThKgU3uEhWRxLahpSldEGmiTTmx30k/XbOMF2n
+HObEHt5EY9uWRGGbj81ZRWiNk0dNtbpneUHv/NvdWLc591M8cEGEQdWW2XTVbL2G
+N67q8hdzGgIvb7QJPMcCAwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQD
+AgOoMB0GA1UdDgQWBBQ9xLkyCBbyQmRet0vvV1Fg6z5q2DBtBgNVHSMEZjBkgBRd
+p91wBlEyfue2bbO15eBg6i5N76FJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoT
+EExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIB
+ADAdBgNVHREEFjAUghJzdW4uc3Ryb25nc3dhbi5vcmcwOQYDVR0fBDIwMDAuoCyg
+KoYoaHR0cDovL2NybC5zdHJvbmdzd2FuLm9yZy9zdHJvbmdzd2FuLmNybDANBgkq
+hkiG9w0BAQQFAAOCAQEAGQQroiAa0SwwhJprGd7OM+rfBJAGbsa3DPzFCfHX1R7i
+ZyDs9aph1DK+IgUa377Ev1U7oB0EldpmOoJJugCjtNLfpW3t1RXBERL/QfpO2+VP
+Wt3SfZ0Oq48jiqB1MVLMZRPCICZEQjT4sJ3HYs5ZuucuvoxeMx3rQ4HxUtHtMD3S
+5JNMwFFiOXAjyIyrTlb7YuRJTT5hE+Rms8GUQ5Xnt7zKZ7yfoSLFzy0/cLFPdQvE
+JA7w8crODCZpDgEKVHVyUWuyt1O46N3ydUfDcnKJoQ9HWHm3xCbDex5MHTnvm1lk
+Stx71CGM7TE6VPy028UlrSw0JqEwCVwstei2cMzwgA==
+-----END CERTIFICATE-----
diff --git a/testing/hosts/sun/etc/ipsec.d/private/sunKey.pem b/testing/hosts/sun/etc/ipsec.d/private/sunKey.pem
new file mode 100644
index 000000000..de63615a6
--- /dev/null
+++ b/testing/hosts/sun/etc/ipsec.d/private/sunKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA5Dx+gH2HkFn3aADkmRBMk26gXoUDOir3UaHtOjbv+DvinTX5
+JSexJoF8+Y18anhq91ITDLZ1YwD/u6PQNt7wwQqyw3O2nQlC5unazufyautAsayo
+HpgBLT2XvlcONLfKpMIC0fWQPjMCX+P8DJ5AG4tHgLIkSYL+uoPf9r6mvjYJqWO4
+UGAFGkJNSlTiaWyVlJ7O/3C7rU/BMXFvxUOUEdR3+XCRdOEqBTe4SFZHEtqGlKV0
+QaaJNObHfST9ds4wXacc5sQe3kRj25ZEYZuPzVlFaI2TR021umd5Qe/8291Ytzn3
+UzxwQYRB1ZbZdNVsvYY3ruryF3MaAi9vtAk8xwIDAQABAoIBACOnh6OO+KSGSW4H
+5a47q5rEh2z8nnpxx90KzMJxXp+Ky2X/zoINZ1E6nUlm3u7LDPrB6ZPs1P24ZDrt
+5lMMFNQzVaXO59I0Zi0ojzQPbAFj6uFWtZTB7j0hCBmGBAQcSh3e6Q3frL7qvQ45
+0WAvQJiM84iZS63oNt7wRwaG1gmUn/k6j34y4qUkD5FfzGhFkekzDS54bRGwjhTA
+7XBUPAcsdNoIPcihokgLXwcdA8l6LBGsk48HN7O+CYOdh4xb6oQ4msgPED3pDIMo
+QRptqcPQ6y1qJaiM/D8SvdX2ZTFm/bh2jlGvcm5sWG8VdSDRqq9r0YCi4KlQzA1g
+OAyrMeECgYEA9dAVEegvRrFm4V6hC9CAwyS6fiOqx/l0xd354Xv4V6vR6n6rKwDF
+kv96A4sMH+mdNf6MwzFFCNW9zZV7noEIvAyPAc7jM7t/Hmt5M41DiDe0RJpWKEdQ
+lEj2qd8FqcY4YVDEH/TdchwIvoWHlD2sykW7eoseCY5mYEoQN4Ciwj8CgYEA7bHv
+qdaz2SoG9lyj8Mz7XthjYZLeaxKu7cpqP5bqzuRSkVFvib0WKoJfwsewzO5hCHnf
+8yMD3Wp4Ap2FYoN2XfV/jQyHvlpMlkxv+bU39/HLosdhzKbOJsru9kbBCaARHAVi
+av3O3JfV2/G+cwR6nPCNjcTsIcqtEpUO7kOfU3kCgYAKYNmy4tm0I2NTmpo0FH6L
+Pq69CqZ4QPkELaYSNhi7It7/BpAVhbfRyAWPxrwhUMy5beDlkNv4ToXv+yK4A3yp
+6+HR0rlXAtCQKTt5yLoUMz3iM531n2UwjZAUhf0IOP1CZpWRP9ZlrfdUi/C4eo4k
+ECOlPeBryN5brGTY4w58IwKBgQC0ukRF2I+qoP/mNg4Yu2KtfM4jlG4072G+P9eF
+PhSO9p+pCkhKbFD8RWDWUsslJmL09OXIkmkP4zIYmvieLOLFEjLHZi2YGER/SuMg
+9B74EQsKW5sK5hF9AXOsIaQI04Hu0lFAlHbC11euAiMShOdNiMG4d3ArSVVK+bb+
+hsAP0QKBgHcJuTJ6dv77evW3MFZPRjFH25pike40PWmSLgCt5PV25DRL2UG0pOut
+uybN9biQK5v377/3GD7eOL+acxHODjWmmfeEFW0YlJ1oUb/P8NlqsSnHvUoIqa24
+JmTXS/XzjgxQFFfzo0c1/1JLdG6r5CLTWxHq1EhIOJsowTlrCzX/
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/sun/etc/ipsec.secrets b/testing/hosts/sun/etc/ipsec.secrets
new file mode 100644
index 000000000..1095b74cc
--- /dev/null
+++ b/testing/hosts/sun/etc/ipsec.secrets
@@ -0,0 +1,8 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA sunKey.pem
+
+
+
+
+
diff --git a/testing/hosts/sun/etc/runlevels/default/net.eth0 b/testing/hosts/sun/etc/runlevels/default/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/sun/etc/runlevels/default/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/sun/etc/runlevels/default/net.eth1 b/testing/hosts/sun/etc/runlevels/default/net.eth1
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/sun/etc/runlevels/default/net.eth1
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/venus/etc/conf.d/hostname b/testing/hosts/venus/etc/conf.d/hostname
new file mode 100644
index 000000000..c9e3dd1d4
--- /dev/null
+++ b/testing/hosts/venus/etc/conf.d/hostname
@@ -0,0 +1 @@
+HOSTNAME=venus
diff --git a/testing/hosts/venus/etc/conf.d/net b/testing/hosts/venus/etc/conf.d/net
new file mode 100644
index 000000000..2c55c2c20
--- /dev/null
+++ b/testing/hosts/venus/etc/conf.d/net
@@ -0,0 +1,11 @@
+# /etc/conf.d/net:
+
+# This is basically the ifconfig argument without the ifconfig $iface
+#
+iface_lo="127.0.0.1 netmask 255.0.0.0"
+iface_eth0="PH_IP_VENUS broadcast 10.1.255.255 netmask 255.255.0.0"
+
+# For setting the default gateway
+#
+gateway="eth0/PH_IP1_MOON"
+
diff --git a/testing/hosts/venus/etc/init.d/iptables b/testing/hosts/venus/etc/init.d/iptables
new file mode 100755
index 000000000..1097ac5a4
--- /dev/null
+++ b/testing/hosts/venus/etc/init.d/iptables
@@ -0,0 +1,74 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow NAT-T
+ iptables -A INPUT -i eth0 -p udp --sport 4500 --dport 4500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 4500 --sport 4500 -j ACCEPT
+
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/hosts/venus/etc/init.d/net.eth0 b/testing/hosts/venus/etc/init.d/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/venus/etc/init.d/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/venus/etc/ipsec.conf b/testing/hosts/venus/etc/ipsec.conf
new file mode 100755
index 000000000..35f264f82
--- /dev/null
+++ b/testing/hosts/venus/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn nat-t
+ left=%defaultroute
+ leftcert=venusCert.pem
+ leftid=@venus.strongswan.org
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightid=@sun.strongswan.org
+ rightsubnet=10.2.0.0/16
+ auto=add
diff --git a/testing/hosts/venus/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/hosts/venus/etc/ipsec.d/cacerts/strongswanCert.pem
new file mode 100644
index 000000000..0de3b268d
--- /dev/null
+++ b/testing/hosts/venus/etc/ipsec.d/cacerts/strongswanCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMDE0NVoXDTE0MDkwODExMDE0NVowRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
+Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y
+X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f
+FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc
+4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/
+7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5
+gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr
+K+1LwdqRxo7HgMRiDw8CAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0jBGYw
+ZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYD
+VQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3Qg
+Q0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAJrXTj5gWS37myHHhii9drYwkMFyDHS/
+lHU8rW/drcnHdus507+qUhNr9SiEAHg4Ywj895UDvT0a1sFaw44QyEa/94iKA8/n
++g5kS1IrKvWu3wu8UI3EgzChgHV3cncQlQWbK+FI9Y3Ax1O1np1r+wLptoWpKKKE
+UxsYcxP9K4Nbyeon0AIHOajUheiL3t6aRc3m0o7VU7Do6S2r+He+1Zq/nRUfFeTy
+0Atebkn8tmUpPSKWaXkmwpVNrjZ1Qu9umAU+dtJyhzL2zmnyhPC4VqpsKCOp7imy
+gKZvUIKPm1zyf4T+yjwxwkiX2xVseoM3aKswb1EoZFelHwndU7u0GQ8=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/venus/etc/ipsec.d/certs/venusCert.pem b/testing/hosts/venus/etc/ipsec.d/certs/venusCert.pem
new file mode 100644
index 000000000..25a6941b0
--- /dev/null
+++ b/testing/hosts/venus/etc/ipsec.d/certs/venusCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBBDANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMTgyNloXDTA5MDkwOTExMTgyNlowRzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHTAbBgNVBAMTFHZlbnVz
+LnN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+mlQ2s9J7bw73onkw0ZwwcM2JDJuU3KmmuzETlmLdtg7m8yFCdhoDg6cxrsIvPAWy
+Gs++1e+1qzy7LTnNHckaHHFwJQf0JoIGE1bbUrJidX8B1T3sDdvZFbyfmQTWSEyJ
+thrdqdPS92VJW/9XQOPeEhudIHr+NtWQfCm3OQFKDXGCEkHOjpVNHn3BPUiL99ON
+FiLZX3gZy6vTERpEE8ga66fHtpM3RJfIxYoUQUdRw8iIa8iOvRGtJa/MfOWX6L/H
+wquRv3SuCl4iMSph7e/VE+z5xx3OyKSAki914DgRFnQITKjyGxw1lORlDQlZy2w/
+nu0BAbXS1pb/2AiF8jDpbQIDAQABo4IBBjCCAQIwCQYDVR0TBAIwADALBgNVHQ8E
+BAMCA6gwHQYDVR0OBBYEFEqPlXBYJh1knX0Q61HMcn9LOZ6sMG0GA1UdIwRmMGSA
+FF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQswCQYDVQQGEwJDSDEZMBcGA1UE
+ChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBSb290IENB
+ggEAMB8GA1UdEQQYMBaCFHZlbnVzLnN0cm9uZ3N3YW4ub3JnMDkGA1UdHwQyMDAw
+LqAsoCqGKGh0dHA6Ly9jcmwuc3Ryb25nc3dhbi5vcmcvc3Ryb25nc3dhbi5jcmww
+DQYJKoZIhvcNAQEEBQADggEBAEx3kXh2Z5CMH+tX6cJPyi6gSeOgXy7NBiNsEdXN
+rwGp4DwN6uiSog4EYZJA203oqE3eaoYdBXKiOGvjW4vyigvpDr8H+MeW2HsNuMKX
+PFpY4NucV0fJlzFhtkp31zTLHNESCgTqNIwGj+CbN0rxhHGE6502krnu+C12nJ7B
+fdMzml1RmVp4JlZC5yfiTy0F2s/aH+8xQ2x509UoD+boNM9GR+IlWS2dDypISGid
+hbM4rpiMLBj2riWD8HiuljkKQ6LemBXeZQXuIPlusl7cH/synNkHk8iiALM8xfGh
+wTEmdo5Tp5sDI3cj3LVvhcsTxjiOA81her1F0itlxpEA/gA=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/venus/etc/ipsec.d/private/venusKey.pem b/testing/hosts/venus/etc/ipsec.d/private/venusKey.pem
new file mode 100644
index 000000000..6c4aff0ad
--- /dev/null
+++ b/testing/hosts/venus/etc/ipsec.d/private/venusKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAmlQ2s9J7bw73onkw0ZwwcM2JDJuU3KmmuzETlmLdtg7m8yFC
+dhoDg6cxrsIvPAWyGs++1e+1qzy7LTnNHckaHHFwJQf0JoIGE1bbUrJidX8B1T3s
+DdvZFbyfmQTWSEyJthrdqdPS92VJW/9XQOPeEhudIHr+NtWQfCm3OQFKDXGCEkHO
+jpVNHn3BPUiL99ONFiLZX3gZy6vTERpEE8ga66fHtpM3RJfIxYoUQUdRw8iIa8iO
+vRGtJa/MfOWX6L/HwquRv3SuCl4iMSph7e/VE+z5xx3OyKSAki914DgRFnQITKjy
+Gxw1lORlDQlZy2w/nu0BAbXS1pb/2AiF8jDpbQIDAQABAoIBAFyVMMvn9YzGmeCq
+e5MD9Dt30kPyAffu/stFwc5yOTfC8OHijhBzwq/0WWXRsKx9bj+PaZjGWWIE6PVU
+u6ymvDdcBj7w6pM/ZY2siZ6uzUpXiy32G+qkfTMBGW2e7T4qTGMm8tuy69jmtn+u
+SxXunYaXckfOATu8GxWhoP1dvKMbCrlQxxmduP04au8HhpLTQgDZ28PrvyqUR6AW
+D+PDGACLbCFzmaMLgv6yv2+GNQpBEDr/VUjOOBvzZhUm9ku81dSdYNhHx8vbT/DG
+GkERG9tE2PA51sWB5cUh13ZItWmbW/NoWiykxJb7J7VkjXAn57jw4suSbNEQnA/E
+bg/5WwECgYEAyqEWS7cUCLheHuyWHOxkL7ACoko4wS8QO3Q4ohPlqZb7pca7FIqU
+WzXEUcyYZPkKTAKx/Vd0Xv6raGImi1QluuwLULACvZ7Ei5uLsMxUCJKyLX7wunTb
+64aH8jONNMAXX4K9eVj7EghBGjdnVc4HRAzm/QyH8F6hmXGT7Ulw3JECgYEAwvpU
+AkrUGb5UgVG/tNtlOlCqVGyvWOITDEsxLPCTlC6Ls6EIYKvc/21oRNL7n/ssfvS/
+DbyVTatiCXaF/MDbx0msbxJbq3sGTY16/XMb1PeTRdQm4xsUEQB1Fi3MnhLmPzV1
+jdKSKvKoxTfZKUg9eP/aVs4abRyHsIXc7BRznR0CgYBB86qBHGa969xerlyxr1Nw
+nhZNYmEUp8/duhdQ0a8XwtfHfmaX6f8drONoSHJ1swVh9iKetd9fp/58bC3lfY8G
+RxvruE48D7gjRI50Dh1v6OdrnXyXA8As6c3HzHWybK9u2+v12jtmBB/Ee7H7oKKG
+yLhKNtDsMLDic7BVNGkysQKBgHjzr0+oucCqiGOcoc8A1uABEFjE/1WlEOnsbzoQ
+l4wx/6nT+I13r+WoKimftEZ/GxA6pZZQ6VHAQlXad63eubf75QMWIVXUQIm1fZli
+Yd6QIoUL4X+62YzeesPib2+UC88kS6NKADCyTa3iQk3QqYm5Nenpew06yJXhxLWS
+zlGlAoGACEbPUlQB+ouInOFyVcFf1kHsMBcmg54MVi2J6x95149rq5FlY5kbmZcs
+6wlSBkAzzKb7WbPNgbGLMAYP+EXKODe+f1nzP+oojmJlCdTLfrudREFA2ZGGOKDX
+0o2EhnGL7VB4Upuw5ddMs7s1v6pqUKQXrZQUb24AX8w/1n+0PEM=
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/venus/etc/ipsec.secrets b/testing/hosts/venus/etc/ipsec.secrets
new file mode 100644
index 000000000..11f3aa4ca
--- /dev/null
+++ b/testing/hosts/venus/etc/ipsec.secrets
@@ -0,0 +1,8 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA venusKey.pem
+
+
+
+
+
diff --git a/testing/hosts/venus/etc/runlevels/default/net.eth0 b/testing/hosts/venus/etc/runlevels/default/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/venus/etc/runlevels/default/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/winnetou/etc/apache2/conf/ssl/ca.crt b/testing/hosts/winnetou/etc/apache2/conf/ssl/ca.crt
new file mode 100644
index 000000000..0de3b268d
--- /dev/null
+++ b/testing/hosts/winnetou/etc/apache2/conf/ssl/ca.crt
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMDE0NVoXDTE0MDkwODExMDE0NVowRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
+Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y
+X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f
+FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc
+4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/
+7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5
+gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr
+K+1LwdqRxo7HgMRiDw8CAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0jBGYw
+ZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYD
+VQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3Qg
+Q0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAJrXTj5gWS37myHHhii9drYwkMFyDHS/
+lHU8rW/drcnHdus507+qUhNr9SiEAHg4Ywj895UDvT0a1sFaw44QyEa/94iKA8/n
++g5kS1IrKvWu3wu8UI3EgzChgHV3cncQlQWbK+FI9Y3Ax1O1np1r+wLptoWpKKKE
+UxsYcxP9K4Nbyeon0AIHOajUheiL3t6aRc3m0o7VU7Do6S2r+He+1Zq/nRUfFeTy
+0Atebkn8tmUpPSKWaXkmwpVNrjZ1Qu9umAU+dtJyhzL2zmnyhPC4VqpsKCOp7imy
+gKZvUIKPm1zyf4T+yjwxwkiX2xVseoM3aKswb1EoZFelHwndU7u0GQ8=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/apache2/conf/ssl/server.crt b/testing/hosts/winnetou/etc/apache2/conf/ssl/server.crt
new file mode 100644
index 000000000..956c217d9
--- /dev/null
+++ b/testing/hosts/winnetou/etc/apache2/conf/ssl/server.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBDjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDYwODE5MTcxNFoXDTEwMDYwNzE5MTcxNFowSjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xIDAeBgNVBAMTF3dpbm5l
+dG91LnN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAwBkz95BmByWVZaEW8cDbeuGr4C1caGAj4QPmuwaIriK+7XqXuh16Ahe3S5vZ
+F56WhUSvMDOIyULckKH84oSa3Jx/SCz0g7X42x8vZuq92tpsjcP/u7BlyqpBUtLa
+r14qm5wYw/1nQqMcSG3k9MQOQ+e9KgaGqpidxWM/8T4M/41AaFRBK2gQGBUULo26
+sjoq3af7Z2jYmWkP/kzj1CHLy9Mgt+UvhKeA+ag5cZnyOG596cqVjlKyqG7vdggk
+wW2n+/KDpHNOndYfT7GMFeGXUNzJPkCImWlttic7ssi0mjP3q3MuOP3FNHIRMd2H
+AcNcqT0bgdJHqnNzGv8C0Ei9XQIDAQABo4IBCTCCAQUwCQYDVR0TBAIwADALBgNV
+HQ8EBAMCA6gwHQYDVR0OBBYEFEMS0mbhrA4zDvmfKf4MntUNxkH4MG0GA1UdIwRm
+MGSAFF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQswCQYDVQQGEwJDSDEZMBcG
+A1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBSb290
+IENBggEAMCIGA1UdEQQbMBmCF3dpbm5ldG91LnN0cm9uZ3N3YW4ub3JnMDkGA1Ud
+HwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwuc3Ryb25nc3dhbi5vcmcvc3Ryb25nc3dh
+bi5jcmwwDQYJKoZIhvcNAQEEBQADggEBACO4+j1Mwt/lbkopeSJst46uFh7OtegG
+6IWNE30i3l3FIn9slSwAOMtmZR0hAF8sExvk61EPlzCR/d9trSJ5+gyjPkeF/enw
+p61rxPMT13Grzomi9gYlk6Q/0zLmE9uYWEY69Q0bEIUcfdZfwB+F7kesa946JNMc
+yHfVEhKtvzmns9ueG0S/8E+6MPDeJv+JHQ++SdWSvOVg6JNxXDGusnim2fjM2Aln
+JmqA6iU4IaPl9DUCuXlLOVv/YhwhviNEbF94upyHq8xjOZdzPbKroHXg/2yvalAw
+4aXc/ZsnFxqsq3i6a2Fj1Y4J7gYsNO/HwA0xvKz3loOTqHaJqO/qeow=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/apache2/conf/ssl/server.key b/testing/hosts/winnetou/etc/apache2/conf/ssl/server.key
new file mode 100644
index 000000000..727027188
--- /dev/null
+++ b/testing/hosts/winnetou/etc/apache2/conf/ssl/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAwBkz95BmByWVZaEW8cDbeuGr4C1caGAj4QPmuwaIriK+7XqX
+uh16Ahe3S5vZF56WhUSvMDOIyULckKH84oSa3Jx/SCz0g7X42x8vZuq92tpsjcP/
+u7BlyqpBUtLar14qm5wYw/1nQqMcSG3k9MQOQ+e9KgaGqpidxWM/8T4M/41AaFRB
+K2gQGBUULo26sjoq3af7Z2jYmWkP/kzj1CHLy9Mgt+UvhKeA+ag5cZnyOG596cqV
+jlKyqG7vdggkwW2n+/KDpHNOndYfT7GMFeGXUNzJPkCImWlttic7ssi0mjP3q3Mu
+OP3FNHIRMd2HAcNcqT0bgdJHqnNzGv8C0Ei9XQIDAQABAoIBACYiWrCgl8B/c4Lz
+Uay4Tlm8hvQ/zQJjY3v93EXwbB21hBV8qrYlt9zGfHqj+5q2vsbB9c0pzdO2VDba
+EWueS2fUIWhglEG5VCebrztNCldx2O7jo9bMk8iBt+oLNaJunSK7ACeYHHGcE7dF
+KZh1eyd7z4+SMBWZqmhO5ZisasQoHCusVGepcyyMGQNkc3XKJ6resGAsOqrOoq7Q
+C4vO5Kkbnk8nnEGmQ/ldD8LwIyq1hzVLDiiqWXZgh6S5l4BEo7Dy3KYrZoZfVcZK
+GMVhAI2+uA1ZqY9twpwryT6VZ3eK4DXF/COQntiBW5pLOpaqTOnKqiVmZFwfbo3u
+cq8n5jkCgYEA5zgzRLifbM0q34c2HX8pTegh+BH7MGCxtcoU2uRPaXiGkqQObHI9
+aItrgUQp+pAmKSBnEWJKgKsOh2Uf5ogjIeNuruGG/AXw/Pw2ORHNueenhDuhu69T
+E2I4yxT3PPYbdzJ4ylBElfgm9WTrv7Wi7wSSfgQ6rEFdWukXa5vvsqMCgYEA1K+q
+m1Jv9MGVIVc6MxhuOOj2Ym+qcWt/Pjvg78rR8SRsKwHlGTuv1rdWUSXYDr3f2Nf7
+6DdbJtaSx5f8gY/UG34yGZx5FFbYV03vcCYBaLXsi/b6H7vb/VW74Y5g6bXqnprv
+4mcdVU7xfyNFgdbLPAP9sYVLijPYDwm0Qq3cz/8CgYBKSJz4BBR8AQI4JBl3qoXb
+mKtpJmW76iTN0amXlWgJ64XYkMptftpJvxj/w6V08WDBL77NL/XdlpcpWozAJJac
+6ZOCrcQPLd15eZH2Dck5Y7pG2l2gjbgz7wdt/0NbG3pBdj6mSNlwEPR7PDwdMD6z
+aZWi1LsA4lMaxO4YTVXZ3wKBgQCoFhTNH/+e/YawjNFQJFSn4WUnMn0Pmhc7xfLl
+T/NPkqtx6dN3d7ZmCQrMow33yJOqOje5tFXzgc0KtNE4S8Uj3T4XA5SlQGVFyjAa
+/85JRM2naA8RGVSpCCKuBeoNilnb8zL2SOvjyboN8oAyNuDzk2vh6ihjFsoASHkP
+4XwLXQKBgQC0k6rzt/plIwEiP56XXOqwOxJj6kuE/hx1zGIiGT6lWiOsih20Ym2T
+kYegVFvuDIWmSIAxGONWyee1lfnJbEuaHRixWQTnHUpqrU0FSnZTubnR3q/faZat
+hrvLDdpa0ydAKoMEn3qUPSrh3CdBfi3KTQAQn2Mlk7bGHh9ICWi3vA==
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/winnetou/etc/conf.d/apache2 b/testing/hosts/winnetou/etc/conf.d/apache2
new file mode 100644
index 000000000..cfb80a7d9
--- /dev/null
+++ b/testing/hosts/winnetou/etc/conf.d/apache2
@@ -0,0 +1,52 @@
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/strongswan/testing/hosts/winnetou/etc/conf.d/apache2,v 1.2 2006/01/06 12:21:21 as Exp $
+
+# Config file for /etc/init.d/apache2
+
+# An example from /etc/apache2/conf/modules.d/40_mod_ssl.conf:
+#
+# <IfDefine SSL>
+# <IfModule !mod_ssl.c>
+# LoadModule ssl_module extramodules/mod_ssl.so
+# </IfModule>
+# </IfDefine>
+#
+# This means that the mod_ssl.so DSO module is only loaded
+# into the server when you pass "-D SSL" at startup. To
+# enable WebDAV, add "-D DAV -D DAV_FS". If you installed
+# mod_php then add "-D PHP4". For more options, please
+# read the files in the /etc/apache2/conf/modules.d directory.
+
+APACHE2_OPTS="-D SSL -D DEFAULT_VHOST"
+
+# Extended options for advanced uses of Apache ONLY
+# You don't need to edit these unless you are doing crazy Apache stuff
+# As not having them set correctly, or feeding in an incorrect configuration
+# via them will result in Apache failing to start
+# YOU HAVE BEEN WARNED.
+
+# ServerRoot setting
+#SERVERROOT=/etc/apache2
+
+# Configuration file location
+# - If this does NOT start with a '/', then it is treated relative to
+# $SERVERROOT by Apache
+#CONFIGFILE=conf/apache2.conf
+
+# Location to log startup errors to
+# They are normally dumped to your terminal.
+#STARTUPERRORLOG="/var/log/apache2/startuperror.log"
+
+# PID file location
+# Note that this MUST match the setting in your configuration file!
+PIDFILE=/var/run/apache2.pid
+
+# Restart style
+# see http://httpd.apache.org/docs-2.0/stopping.html for more details
+# the default is 'graceful', the other possible value is 'restart'
+# If you use 'graceful', completion of the command does NOT imply that the system
+# has finished restarting. Restart is finished only when all child processes
+# have finished serving their current request sets. Read the URL for details.
+#RESTARTSTYLE="restart"
+RESTARTSTYLE="graceful"
diff --git a/testing/hosts/winnetou/etc/conf.d/hostname b/testing/hosts/winnetou/etc/conf.d/hostname
new file mode 100644
index 000000000..1bfa5acbd
--- /dev/null
+++ b/testing/hosts/winnetou/etc/conf.d/hostname
@@ -0,0 +1 @@
+HOSTNAME=winnetou
diff --git a/testing/hosts/winnetou/etc/conf.d/net b/testing/hosts/winnetou/etc/conf.d/net
new file mode 100644
index 000000000..1a32153f3
--- /dev/null
+++ b/testing/hosts/winnetou/etc/conf.d/net
@@ -0,0 +1,10 @@
+# /etc/conf.d/net:
+
+# This is basically the ifconfig argument without the ifconfig $iface
+#
+iface_lo="127.0.0.1 netmask 255.0.0.0"
+iface_eth0="PH_IP_WINNETOU broadcast 192.168.0.255 netmask 255.255.255.0"
+
+# For setting the default gateway
+#
+gateway="eth0/192.168.0.254"
diff --git a/testing/hosts/winnetou/etc/conf.d/slapd b/testing/hosts/winnetou/etc/conf.d/slapd
new file mode 100644
index 000000000..8d9ac4787
--- /dev/null
+++ b/testing/hosts/winnetou/etc/conf.d/slapd
@@ -0,0 +1,8 @@
+# conf.d file for the openldap-2.1 series
+#
+# To enable both the standard unciphered server and the ssl encrypted
+# one uncomment this line or set any other server starting options
+# you may desire.
+#
+# OPTS="-h 'ldaps:// ldap:// ldapi://%2fvar%2frun%2fopenldap%2fslapd.sock'"
+OPTS="-4"
diff --git a/testing/hosts/winnetou/etc/hostname b/testing/hosts/winnetou/etc/hostname
new file mode 100644
index 000000000..6338c7c73
--- /dev/null
+++ b/testing/hosts/winnetou/etc/hostname
@@ -0,0 +1 @@
+winnetou
diff --git a/testing/hosts/winnetou/etc/init.d/apache2 b/testing/hosts/winnetou/etc/init.d/apache2
new file mode 100755
index 000000000..f54f3444a
--- /dev/null
+++ b/testing/hosts/winnetou/etc/init.d/apache2
@@ -0,0 +1,78 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="${opts} reload"
+
+[ "x${SERVERROOT}" != "x" ] && APACHE2_OPTS="${APACHE2_OPTS} -d ${SERVERROOT}"
+[ "x${CONFIGFILE}" != "x" ] && APACHE2_OPTS="${APACHE2_OPTS} -f ${CONFIGFILE}"
+[ "x${STARTUPERRORLOG}" != "x" ] && APACHE2_OPTS="${APACHE2_OPTS} -E ${STARTUPERRORLOG}"
+# set a default for PIDFILE/RESTARTSTYLE for those that FAILED to follow
+# instructiosn and update the conf.d/apache2 file.
+# (bug #38787)
+[ -z "${PIDFILE}" ] && PIDFILE=/var/run/apache2.pid
+[ -z "${RESTARTSTYLE}" ] && RESTARTSTYLE="graceful"
+
+checkconfig() {
+ local myconf="/etc/apache2/conf/apache2.conf"
+ if [ "x${CONFIGFILE}" != "x" ]; then
+ if [ ${CONFIGFILE:0:1} = "/" ]; then
+ myconf="${CONFIGFILE}"
+ else
+ myconf="${SERVERROOT:-/usr/lib/apache2}/${CONFIGFILE}"
+ fi
+ fi
+ if [ ! -r "${myconf}" ]; then
+ eerror "Unable to read configuration file: ${myconf}"
+ return 1
+ fi
+ if [ -z "${PIDFILE}" ]; then
+ eerror "\$PIDFILE is not set!"
+ eerror "Did you etc-update /etc/conf.d/apache2?"
+ return 1
+ fi
+ if [ -z "${RESTARTSTYLE}" ]; then
+ eerror "\$RESTARTSTYLE is not set!"
+ eerror "Did you etc-update /etc/conf.d/apache2?"
+ return 1
+ fi
+ /usr/sbin/apache2 -t ${APACHE2_OPTS} 1>/dev/null 2>&1
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ eerror "Apache2 has detected a syntax error in your configuration files:"
+ /usr/sbin/apache2 -t ${APACHE2_OPTS}
+ fi
+ return $ret
+}
+
+depend() {
+ need net
+ use mysql dns logger netmount postgres
+ after sshd
+}
+
+start() {
+ checkconfig || return 1
+ ebegin "Starting apache2"
+ [ -f /var/log/apache2/ssl_scache ] && rm /var/log/apache2/ssl_scache
+ [ -f /usr/lib/apache2/build/envvars ] && . /usr/lib/apache2/build/envvars
+ env -i PATH=$PATH /sbin/start-stop-daemon --quiet \
+ --start --startas /usr/sbin/apache2 \
+ --pidfile ${PIDFILE} -- -k start ${APACHE2_OPTS}
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping apache2"
+ /usr/sbin/apache2ctl stop >/dev/null
+ start-stop-daemon -o --quiet --stop --pidfile ${PIDFILE}
+ eend $?
+}
+
+reload() {
+ # restarting apache2 is much easier than apache1. The server handles most of the work for us.
+ # see http://httpd.apache.org/docs-2.0/stopping.html for more details
+ ebegin "Restarting apache2"
+ /usr/sbin/apache2 ${APACHE2_OPTS} -k ${RESTARTSTYLE}
+ eend $?
+}
diff --git a/testing/hosts/winnetou/etc/init.d/net.eth0 b/testing/hosts/winnetou/etc/init.d/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/winnetou/etc/init.d/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/hosts/winnetou/etc/init.d/slapd b/testing/hosts/winnetou/etc/init.d/slapd
new file mode 100755
index 000000000..d4c070b33
--- /dev/null
+++ b/testing/hosts/winnetou/etc/init.d/slapd
@@ -0,0 +1,25 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/strongswan/testing/hosts/winnetou/etc/init.d/slapd,v 1.2 2005/05/31 14:04:43 as Exp $
+
+depend() {
+ need net
+}
+
+start() {
+ ebegin "Starting ldap-server"
+ eval start-stop-daemon --start --quiet --pidfile /var/run/openldap/slapd.pid --exec /usr/lib/openldap/slapd -- -u ldap -g ldap "${OPTS}"
+ eend $?
+ if [ ! -e /var/lib/openldap-data/objectClass.bdb ]
+ then
+ sleep 5
+ ldapadd -x -D "cn=Manager, o=Linux strongSwan, c=CH" -w tuxmux -f /etc/openldap/ldif.txt
+ fi
+}
+
+stop() {
+ ebegin "Stopping ldap-server"
+ start-stop-daemon --stop --signal 2 --quiet --pidfile /var/run/openldap/slapd.pid
+ eend $?
+}
diff --git a/testing/hosts/winnetou/etc/openldap/ldif.txt b/testing/hosts/winnetou/etc/openldap/ldif.txt
new file mode 100644
index 000000000..3eca4d6c6
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openldap/ldif.txt
@@ -0,0 +1,40 @@
+dn: o=Linux strongSwan, c=CH
+objectclass: organization
+o: Linux strongSwan
+
+dn: cn=Manager,o=Linux strongSwan, c=CH
+objectclass: organizationalRole
+cn: Manager
+
+dn: cn=strongSwan Root CA, o=Linux strongSwan, c=CH
+objectClass: organizationalRole
+cn: strongSwan Root CA
+objectClass: certificationAuthority
+authorityRevocationList;binary:< file:///etc/openssl/strongswan.crl
+certificateRevocationList;binary:< file:///etc/openssl/strongswan.crl
+cACertificate;binary:< file:///etc/openssl/strongswanCert.der
+
+dn: ou=Research, o=Linux strongSwan, c=CH
+objectclass: organizationalUnit
+ou: Research
+
+dn: cn=Research CA, ou=Research, o=Linux strongSwan, c=CH
+objectClass: organizationalRole
+cn: Research CA
+objectClass: certificationAuthority
+authorityRevocationList;binary:< file:///etc/openssl/research/research.crl
+certificateRevocationList;binary:< file:///etc/openssl/research/research.crl
+cACertificate;binary:< file:///etc/openssl/research/researchCert.der
+
+dn: ou=Sales, o=Linux strongSwan, c=CH
+objectclass: organizationalUnit
+ou: Sales
+
+dn: cn=Sales CA, ou=Sales, o=Linux strongSwan, c=CH
+objectClass: organizationalRole
+cn: Sales CA
+objectClass: certificationAuthority
+authorityRevocationList;binary:< file:///etc/openssl/sales/sales.crl
+certificateRevocationList;binary:< file:///etc/openssl/sales/sales.crl
+cACertificate;binary:< file:///etc/openssl/sales/salesCert.der
+
diff --git a/testing/hosts/winnetou/etc/openldap/slapd.conf b/testing/hosts/winnetou/etc/openldap/slapd.conf
new file mode 100644
index 000000000..4558ee2e2
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openldap/slapd.conf
@@ -0,0 +1,68 @@
+#
+# See slapd.conf(5) for details on configuration options.
+# This file should NOT be world readable.
+#
+include /etc/openldap/schema/core.schema
+
+# Define global ACLs to disable default read access.
+
+# Do not enable referrals until AFTER you have a working directory
+# service AND an understanding of referrals.
+#referral ldap://root.openldap.org
+
+pidfile /var/run/openldap/slapd.pid
+argsfile /var/run/openldap/slapd.args
+
+# Load dynamic backend modules:
+# modulepath /usr/lib/openldap/openldap
+# moduleload back_bdb.la
+# moduleload back_ldap.la
+# moduleload back_ldbm.la
+# moduleload back_passwd.la
+# moduleload back_shell.la
+
+# Sample security restrictions
+# Require integrity protection (prevent hijacking)
+# Require 112-bit (3DES or better) encryption for updates
+# Require 63-bit encryption for simple bind
+# security ssf=1 update_ssf=112 simple_bind=64
+
+# Sample access control policy:
+# Root DSE: allow anyone to read it
+# Subschema (sub)entry DSE: allow anyone to read it
+# Other DSEs:
+# Allow self write access
+# Allow authenticated users read access
+# Allow anonymous users to authenticate
+# Directives needed to implement policy:
+# access to dn.base="" by * read
+# access to dn.base="cn=Subschema" by * read
+# access to *
+# by self write
+# by users read
+# by anonymous auth
+#
+# if no access controls are present, the default policy
+# allows anyone and everyone to read anything but restricts
+# updates to rootdn. (e.g., "access to * by * read")
+#
+# rootdn can always read and write EVERYTHING!
+
+#######################################################################
+# BDB database definitions
+#######################################################################
+
+database bdb
+checkpoint 32 30 # <kbyte> <min>
+suffix "o=Linux strongSwan,c=CH"
+rootdn "cn=Manager,o=Linux strongSwan,c=CH"
+# Cleartext passwords, especially for the rootdn, should
+# be avoid. See slappasswd(8) and slapd.conf(5) for details.
+# Use of strong authentication encouraged.
+rootpw tuxmux
+# The database directory MUST exist prior to running slapd AND
+# should only be accessible by the slapd and slap tools.
+# Mode 700 recommended.
+directory /var/lib/openldap-data
+# Indices to maintain
+index objectClass eq
diff --git a/testing/hosts/winnetou/etc/openssl/generate-crl b/testing/hosts/winnetou/etc/openssl/generate-crl
new file mode 100755
index 000000000..5a8fd7782
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/generate-crl
@@ -0,0 +1,35 @@
+#! /bin/sh
+# generate a certificate revocation list (CRL) for the strongswan CA.
+#
+# Copyright (C) 2004 Andreas Steffen
+# Zuercher Hochschule Winterthur
+#
+# 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: generate-crl,v 1.2 2005/03/24 11:19:38 as Exp $
+
+export COMMON_NAME=strongSwan
+
+cd /etc/openssl
+openssl ca -config /etc/openssl/openssl.cnf -gencrl -out crl.pem
+openssl crl -in crl.pem -outform der -out strongswan.crl
+cp strongswan.crl /var/www/localhost/htdocs/
+cp strongswanCert.pem /var/www/localhost/htdocs/
+cp index.html /var/www/localhost/htdocs/
+cd /etc/openssl/research
+openssl ca -config /etc/openssl/research/openssl.cnf -gencrl -out crl.pem
+openssl crl -in crl.pem -outform der -out research.crl
+cp research.crl /var/www/localhost/htdocs/
+cd /etc/openssl/sales
+openssl ca -config /etc/openssl/sales/openssl.cnf -gencrl -out crl.pem
+openssl crl -in crl.pem -outform der -out sales.crl
+cp sales.crl /var/www/localhost/htdocs/
+
diff --git a/testing/hosts/winnetou/etc/openssl/index.html b/testing/hosts/winnetou/etc/openssl/index.html
new file mode 100644
index 000000000..1641768ae
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/index.html
@@ -0,0 +1,36 @@
+<html>
+<head>
+ <title>strongSwan Web Services</title>
+ <base target="_self">
+</head>
+
+<body bgcolor="#FFFFFF">
+<table border=0 cellpadding=0 cellspacing=0 width=600>
+
+<tr><td>
+ <h2>strongSwan Certification Authority</h2>
+ <ul>
+ <li>
+ <a href="strongswanCert.pem">Root CA Certificate</a>
+ </li>
+ </ul>
+ <ul>
+ <li>
+ <a href="strongswan.crl">Certificate Revocation List (CRL)</a>
+ </li>
+ </ul>
+
+ <h2>strongSwan UML Testing Environment</h2>
+ <ul>
+ <li>
+ <a href="testresults/">UML Test Results</a>
+ </li>
+ </ul>
+ <a href="images/umlArchitecture_large.png" target="_blank">
+ <img src="images/umlArchitecture_small.png" border="0">
+ </a>
+ <hr>
+ <address>Linux strongSwan (<a href="http://www.strongswan.org">www.strongswan.org</a>)</address>
+</td></tr>
+</table>
+</body>
diff --git a/testing/hosts/winnetou/etc/openssl/index.txt b/testing/hosts/winnetou/etc/openssl/index.txt
new file mode 100644
index 000000000..4db6c2924
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/index.txt
@@ -0,0 +1,15 @@
+V 090909111334Z 01 unknown /C=CH/O=Linux strongSwan/CN=mars.strongswan.org
+V 090909111553Z 02 unknown /C=CH/O=Linux strongSwan/CN=sun.strongswan.org
+V 090909111725Z 03 unknown /C=CH/O=Linux strongSwan/CN=moon.strongswan.org
+V 090909111826Z 04 unknown /C=CH/O=Linux strongSwan/CN=venus.strongswan.org
+V 090909112439Z 05 unknown /C=CH/O=Linux strongSwan/OU=Sales/CN=alice@strongswan.org
+V 090909112534Z 06 unknown /C=CH/O=Linux strongSwan/OU=Research/CN=bob@strongswan.org
+R 090909112548Z 041226135423Z 07 unknown /C=CH/O=Linux strongSwan/OU=Research/CN=carol@strongswan.org
+V 090909112651Z 08 unknown /C=CH/O=Linux strongSwan/OU=Accounting/CN=dave@strongswan.org
+V 091118162928Z 09 unknown /C=CH/O=Linux strongSwan/OU=OCSP Signing Authority/CN=ocsp.strongswan.org
+V 091231214318Z 0A unknown /C=CH/O=Linux strongSwan/OU=Research/CN=carol@strongswan.org
+V 100216084430Z 0B unknown /C=CH/O=Linux strongSwan/OU=Authorization Authority/CN=aa@strongswan.org
+R 140321062536Z 050621195214Z 0C unknown /C=CH/O=Linux strongSwan/OU=Research/CN=Research CA
+V 140321062916Z 0D unknown /C=CH/O=Linux strongSwan/OU=Sales/CN=Sales CA
+V 100607191714Z 0E unknown /C=CH/O=Linux strongSwan/CN=winnetou.strongswan.org
+V 100620195806Z 0F unknown /C=CH/O=Linux strongSwan/OU=Research/CN=Research CA
diff --git a/testing/hosts/winnetou/etc/openssl/index.txt.attr b/testing/hosts/winnetou/etc/openssl/index.txt.attr
new file mode 100644
index 000000000..8f7e63a34
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/index.txt.attr
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/testing/hosts/winnetou/etc/openssl/index.txt.attr.old b/testing/hosts/winnetou/etc/openssl/index.txt.attr.old
new file mode 100644
index 000000000..8f7e63a34
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/index.txt.attr.old
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/testing/hosts/winnetou/etc/openssl/index.txt.old b/testing/hosts/winnetou/etc/openssl/index.txt.old
new file mode 100644
index 000000000..669702b0c
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/index.txt.old
@@ -0,0 +1,14 @@
+V 090909111334Z 01 unknown /C=CH/O=Linux strongSwan/CN=mars.strongswan.org
+V 090909111553Z 02 unknown /C=CH/O=Linux strongSwan/CN=sun.strongswan.org
+V 090909111725Z 03 unknown /C=CH/O=Linux strongSwan/CN=moon.strongswan.org
+V 090909111826Z 04 unknown /C=CH/O=Linux strongSwan/CN=venus.strongswan.org
+V 090909112439Z 05 unknown /C=CH/O=Linux strongSwan/OU=Sales/CN=alice@strongswan.org
+V 090909112534Z 06 unknown /C=CH/O=Linux strongSwan/OU=Research/CN=bob@strongswan.org
+R 090909112548Z 041226135423Z 07 unknown /C=CH/O=Linux strongSwan/OU=Research/CN=carol@strongswan.org
+V 090909112651Z 08 unknown /C=CH/O=Linux strongSwan/OU=Accounting/CN=dave@strongswan.org
+V 091118162928Z 09 unknown /C=CH/O=Linux strongSwan/OU=OCSP Signing Authority/CN=ocsp.strongswan.org
+V 091231214318Z 0A unknown /C=CH/O=Linux strongSwan/OU=Research/CN=carol@strongswan.org
+V 100216084430Z 0B unknown /C=CH/O=Linux strongSwan/OU=Authorization Authority/CN=aa@strongswan.org
+R 140321062536Z 050621195214Z 0C unknown /C=CH/O=Linux strongSwan/OU=Research/CN=Research CA
+V 140321062916Z 0D unknown /C=CH/O=Linux strongSwan/OU=Sales/CN=Sales CA
+V 100607191714Z 0E unknown /C=CH/O=Linux strongSwan/CN=winnetou.strongswan.org
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/01.pem b/testing/hosts/winnetou/etc/openssl/newcerts/01.pem
new file mode 100644
index 000000000..bf4ba9375
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/01.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEDTCCAvWgAwIBAgIBATANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMTMzNFoXDTA5MDkwOTExMTMzNFowRjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHDAaBgNVBAMTE21hcnMu
+c3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA
+zRlshdPlLggS7bpAlovamLpk9pxYUv3c8J4W0kV4knMPbSJywfctpce95iPZfU6V
+ICV0fVOn/0utJG+0lMTYwcf5zvyIDPDccfsTT3WI+/PcaUpU6E5aaPAZxDG4na6w
+UVUKiRcOyiuyXanulnu+b48nM7MgoMVZNDWY5q15enEZh1oO2Fy0DlKwweDKEuAi
+8xSnu2RcZBFSZMDBCRCt3QgHGZygrzjP3vN6IgbvHL+YWIycMi5yiJR5EoCE6D17
+AT1dh0C8R9m1a0LUK8cKiN+akZQlK/AHYOCu77fg1vz84dMDRIs2PCUs6Ww/fvqy
+N4r1BXg8XKTVH0zmqfQLAgMBAAGjggEFMIIBATAJBgNVHRMEAjAAMAsGA1UdDwQE
+AwIDqDAdBgNVHQ4EFgQUbUWd4UeHwbTxn0Kr9io4nUGz6eAwbQYDVR0jBGYwZIAU
+XafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQK
+ExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GC
+AQAwHgYDVR0RBBcwFYITbWFycy5zdHJvbmdzd2FuLm9yZzA5BgNVHR8EMjAwMC6g
+LKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0G
+CSqGSIb3DQEBBAUAA4IBAQBY0ab/r6K40Gni/db8apZGJqoO3XFPE4K7wi46LNZq
+gB3mQgazLkf48luj06rcfux+vC/2W3DyqAtKD5JRccL0A5yxY55p3rrCNvz76Y9H
+0AkVledhZTjd7SxdtsfxlRuok4nACwQii9GXcfs8qBc5QE8ZQRAtPwRxVx8hE19n
+D3AllTSukJSC6nPJHf+4FXz1Dxt3aFZOnkJM4qERBjFREYE4jGLaz71HNNKshsYy
+2UuwLAqsQk6zYogrJgpWLIuMVE2GHoth/rjpkzK/ErAwcV4OgMNdA1bHGl94soDy
+zryvlFj1zaqlvdKayWATnrAQQTQeeYz3i0wF95CNR22b
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/02.pem b/testing/hosts/winnetou/etc/openssl/newcerts/02.pem
new file mode 100644
index 000000000..e7825e3db
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/02.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIECzCCAvOgAwIBAgIBAjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMTU1M1oXDTA5MDkwOTExMTU1M1owRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN1bi5z
+dHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOQ8
+foB9h5BZ92gA5JkQTJNuoF6FAzoq91Gh7To27/g74p01+SUnsSaBfPmNfGp4avdS
+Ewy2dWMA/7uj0Dbe8MEKssNztp0JQubp2s7n8mrrQLGsqB6YAS09l75XDjS3yqTC
+AtH1kD4zAl/j/AyeQBuLR4CyJEmC/rqD3/a+pr42CaljuFBgBRpCTUpU4mlslZSe
+zv9wu61PwTFxb8VDlBHUd/lwkXThKgU3uEhWRxLahpSldEGmiTTmx30k/XbOMF2n
+HObEHt5EY9uWRGGbj81ZRWiNk0dNtbpneUHv/NvdWLc591M8cEGEQdWW2XTVbL2G
+N67q8hdzGgIvb7QJPMcCAwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQD
+AgOoMB0GA1UdDgQWBBQ9xLkyCBbyQmRet0vvV1Fg6z5q2DBtBgNVHSMEZjBkgBRd
+p91wBlEyfue2bbO15eBg6i5N76FJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoT
+EExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIB
+ADAdBgNVHREEFjAUghJzdW4uc3Ryb25nc3dhbi5vcmcwOQYDVR0fBDIwMDAuoCyg
+KoYoaHR0cDovL2NybC5zdHJvbmdzd2FuLm9yZy9zdHJvbmdzd2FuLmNybDANBgkq
+hkiG9w0BAQQFAAOCAQEAGQQroiAa0SwwhJprGd7OM+rfBJAGbsa3DPzFCfHX1R7i
+ZyDs9aph1DK+IgUa377Ev1U7oB0EldpmOoJJugCjtNLfpW3t1RXBERL/QfpO2+VP
+Wt3SfZ0Oq48jiqB1MVLMZRPCICZEQjT4sJ3HYs5ZuucuvoxeMx3rQ4HxUtHtMD3S
+5JNMwFFiOXAjyIyrTlb7YuRJTT5hE+Rms8GUQ5Xnt7zKZ7yfoSLFzy0/cLFPdQvE
+JA7w8crODCZpDgEKVHVyUWuyt1O46N3ydUfDcnKJoQ9HWHm3xCbDex5MHTnvm1lk
+Stx71CGM7TE6VPy028UlrSw0JqEwCVwstei2cMzwgA==
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/03.pem b/testing/hosts/winnetou/etc/openssl/newcerts/03.pem
new file mode 100644
index 000000000..d8fbfa1c9
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/03.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEDTCCAvWgAwIBAgIBAzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMTcyNVoXDTA5MDkwOTExMTcyNVowRjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHDAaBgNVBAMTE21vb24u
+c3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv
+ri4QmsCnG0N7bxqeUZTQhcmZ/iyN4RsmHwFsiOc06xpnZ7Fbx9gzi/OswU6KGL+F
+f9PfvOY36bDTZU8V2QaL30RQUXz3JlG+jUyP9zjqlhsvVYS/cImvqgo3uUkQ0YCD
+v2SafTlaQfBOaPFElNEP/H2YSiyB6X80IcHsOMYpskVqPY8785FehjF+pxuyRCK+
+9HXmd+iWdnC09u4qgKRa3L0IamU3q1/BK/afkHK2IAIN4YgM7GzepHVD0f7Exf9U
+esJEeh4hDZwSjcMzdybrY9XBxzGqLGPOF128jr+5weUZiBW+RzeBw/gsK1nSPeuX
+Od2lPJjTGj+6V3YK6qibAgMBAAGjggEFMIIBATAJBgNVHRMEAjAAMAsGA1UdDwQE
+AwIDqDAdBgNVHQ4EFgQU5eQQh2wqxL6thUlCpt52WDA6n8EwbQYDVR0jBGYwZIAU
+XafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQK
+ExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GC
+AQAwHgYDVR0RBBcwFYITbW9vbi5zdHJvbmdzd2FuLm9yZzA5BgNVHR8EMjAwMC6g
+LKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0G
+CSqGSIb3DQEBBAUAA4IBAQAvLykhZnqldrsMcbYB36WzWKk+hOihr5dU3fv8Z4ec
+tsa3gzxXSefDCxGoezVJ4QXdpdNxxFn31A+r1gxKyGI5JL6EyWz6Y462zp9lE7nW
+EIC4ldJwxAXqzDEMcJphO29hApyU9TWsWDa4kL5AKtLFLwH3/Uv/jAzAy+qXIO8h
+wLtB+wcmhSo8OFY9kX/cyhht7eb7yD/r2e3wVBOCRk7jePe4yWhN8NJAKwfrEd1K
+iGq15ymdmeomhplHRsLZwA2VsCspUNZ/eXjG21s3nEoxcCOcQUz3Q7q4ZgBTZoCW
+kAc6FQ5zxoZrmzNWFqzb06jmUVlt7baGtdjT7rEt+dcp
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/04.pem b/testing/hosts/winnetou/etc/openssl/newcerts/04.pem
new file mode 100644
index 000000000..25a6941b0
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/04.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBBDANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMTgyNloXDTA5MDkwOTExMTgyNlowRzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHTAbBgNVBAMTFHZlbnVz
+LnN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+mlQ2s9J7bw73onkw0ZwwcM2JDJuU3KmmuzETlmLdtg7m8yFCdhoDg6cxrsIvPAWy
+Gs++1e+1qzy7LTnNHckaHHFwJQf0JoIGE1bbUrJidX8B1T3sDdvZFbyfmQTWSEyJ
+thrdqdPS92VJW/9XQOPeEhudIHr+NtWQfCm3OQFKDXGCEkHOjpVNHn3BPUiL99ON
+FiLZX3gZy6vTERpEE8ga66fHtpM3RJfIxYoUQUdRw8iIa8iOvRGtJa/MfOWX6L/H
+wquRv3SuCl4iMSph7e/VE+z5xx3OyKSAki914DgRFnQITKjyGxw1lORlDQlZy2w/
+nu0BAbXS1pb/2AiF8jDpbQIDAQABo4IBBjCCAQIwCQYDVR0TBAIwADALBgNVHQ8E
+BAMCA6gwHQYDVR0OBBYEFEqPlXBYJh1knX0Q61HMcn9LOZ6sMG0GA1UdIwRmMGSA
+FF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQswCQYDVQQGEwJDSDEZMBcGA1UE
+ChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBSb290IENB
+ggEAMB8GA1UdEQQYMBaCFHZlbnVzLnN0cm9uZ3N3YW4ub3JnMDkGA1UdHwQyMDAw
+LqAsoCqGKGh0dHA6Ly9jcmwuc3Ryb25nc3dhbi5vcmcvc3Ryb25nc3dhbi5jcmww
+DQYJKoZIhvcNAQEEBQADggEBAEx3kXh2Z5CMH+tX6cJPyi6gSeOgXy7NBiNsEdXN
+rwGp4DwN6uiSog4EYZJA203oqE3eaoYdBXKiOGvjW4vyigvpDr8H+MeW2HsNuMKX
+PFpY4NucV0fJlzFhtkp31zTLHNESCgTqNIwGj+CbN0rxhHGE6502krnu+C12nJ7B
+fdMzml1RmVp4JlZC5yfiTy0F2s/aH+8xQ2x509UoD+boNM9GR+IlWS2dDypISGid
+hbM4rpiMLBj2riWD8HiuljkKQ6LemBXeZQXuIPlusl7cH/synNkHk8iiALM8xfGh
+wTEmdo5Tp5sDI3cj3LVvhcsTxjiOA81her1F0itlxpEA/gA=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/05.pem b/testing/hosts/winnetou/etc/openssl/newcerts/05.pem
new file mode 100644
index 000000000..e99ae8ec7
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/05.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEHzCCAwegAwIBAgIBBTANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjQzOVoXDTA5MDkwOTExMjQzOVowVzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsTBVNhbGVz
+MR0wGwYDVQQDFBRhbGljZUBzdHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAK7FyvkE18/oujCaTd8GXBNOH+Cvoy0ibJ8j2sNsBrer
+GS1lgxRs8zaVfK9fosadu0UZeWIHsOKkew5469sPvkKK2SGGH+pu+x+xO/vuaEG4
+FlkAu8iGFWLQycLt6BJfcqw7FT8rwNuD18XXBXmP7hRavi/TEElbVYHbO7lm8T5W
+6hTr/sYddiSB7X9/ba7JBy6lxmBcUAx5bjiiHLaW/llefkqyhc6dw5nvPZ2DchvH
+v/HWvLF9bsvxbBkHU0/z/CEsRuMBI7EPEL4rx3UqmuCUAqiMJTS3IrDaIlfJOLWc
+KlbsnE6hHpwmt9oDB9iWBY9WeZUSAtJGFw4b7FCZvQ0CAwEAAaOCAQYwggECMAkG
+A1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBRZmh0JtiNTjBsQsfD7ECNa
+60iG2jBtBgNVHSMEZjBkgBRdp91wBlEyfue2bbO15eBg6i5N76FJpEcwRTELMAkG
+A1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0
+cm9uZ1N3YW4gUm9vdCBDQYIBADAfBgNVHREEGDAWgRRhbGljZUBzdHJvbmdzd2Fu
+Lm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3Jn
+L3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQADdQIlJkFtmHEjtuyo
+2aIcrsUx98FtvVgB7RpQB8JZlly7UEjvX0CIIvW/7Al5/8h9s1rhrRffX7nXQKAQ
+AmPnvD2Pp47obDnHqm/L109S1fcL5BiPN1AlgsseUBwzdqBpyRncPXZoAuBh/BU5
+D/1Dip0hXgB/X6+QymSzRJoSKfpeXVICj1kYH1nIkn0YXthYF3BTrCheCzBlKn0S
+CixbCUYsUjtSqld0nG76jyGb/gnWntNettH+RXWe1gm6qREJwfEFdeYviTqx2Uxi
+6sBKG/XjNAcMArXb7V6w0YAwCyjwCl49B+mLZaFH+9izzBJ7NyVqhH8ToB1gt0re
+JGhV
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/06.pem b/testing/hosts/winnetou/etc/openssl/newcerts/06.pem
new file mode 100644
index 000000000..199d3eee2
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/06.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBBjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjUzNFoXDTA5MDkwOTExMjUzNFowWDELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMRswGQYDVQQDFBJib2JAc3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDAJaejS3/lJfQHgw0nzvotgSQS8ey/6tvbx7s5RsWY
+27x9K5xd44aPrvP2Qpyq34IXRY6uPlIqeUTQN7EKpLrWCxMOT36x5N0Co9J5UWRB
+fJC141D+8+1RwJ9/baEIecpCvb0GfDOX0GXN5ltcJk82hZjE4y1yHC1FN7V3zdRg
+xmloupPuon+X3bTmyMQ93NKkg48CQGtqtfwQ0MqPiOWu8MBhdztfOyu6aW3EgviF
+ithLc02SeNzlpqB3M8GDfX+mr3OVDhhhC2OI+VRlZzz7KxJ13DUR2KkvLZR8Ak4E
+5lRjkUnTYd/f3OQYxfjC8idUmj5ojR6Fb0x1tsV/glzXAgMBAAGjggEEMIIBADAJ
+BgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQUaLN5EPOkOkVU3J1Ud0sl
++27OOHswbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJ
+BgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJz
+dHJvbmdTd2FuIFJvb3QgQ0GCAQAwHQYDVR0RBBYwFIESYm9iQHN0cm9uZ3N3YW4u
+b3JnMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwuc3Ryb25nc3dhbi5vcmcv
+c3Ryb25nc3dhbi5jcmwwDQYJKoZIhvcNAQEEBQADggEBAIyQLLxdeO8clplzRW9z
+TRR3J0zSedvi2XlIZ/XCsv0ZVfoBLLWcDp3QrxNiVZXvXXtzjPsDs+DAveZF9LGq
+0tIw1uT3JorbgNNrmWvxBvJoQTtSw4LQBuV7vF27jrposx3Hi5qtUXUDS6wVnDUI
+5iORqsrddnoDuMN+Jt7oRcvKfYSNwTV+m0ZAHdB5a/ARWO5UILOrxEA/N72NcDYN
+NdAd+bLaB38SbkSbh1xj/AGnrHxdJBF4h4mx4btc9gtBSh+dwBHOsn4TheqJ6bbw
+7FlXBowQDCJIswKNhWfnIepQlM1KEzmq5YX43uZO2b7amRaIKqy2vNE7+UNFYBpE
+Mto=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/07.pem b/testing/hosts/winnetou/etc/openssl/newcerts/07.pem
new file mode 100644
index 000000000..5b742fc9e
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/07.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIBBzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjU0OFoXDTA5MDkwOTExMjU0OFowWjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAM5413q1B2EF3spcYD1u0ce9AtIHdxmU3+1E0hqV
+mLqpIQtyp4SLbrRunxpoVUuEpHWXgLb3C/ljjlKCMWWmhw4wja1rBTjMNJLPj6Bo
+5Qn4Oeuqm7/kLHPGbveQGtcSsJCk6iLqFTbq0wsji5Ogq7kmjWgQv0nM2jpofHLv
+VOAtWVSj+x2b3OHdl/WpgTgTw1HHjYo7/NOkARdTcZ2/wxxM3z1Abp9iylc45GLN
+IL/OzHkT8b5pdokdMvVijz8IslkkewJYXrVQaCNMZg/ydlXOOAEKz0YqnvXQaYs5
+K+s8XvQ2RFCr5oO0fRT2VbiI9TgHnbcnfUi25iHl6txsXg0CAwEAAaOCAQYwggEC
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBTbA2TH3ca8tgCGkYy9
+OV/MqUTHAzBtBgNVHSMEZjBkgBRdp91wBlEyfue2bbO15eBg6i5N76FJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBADAfBgNVHREEGDAWgRRjYXJvbEBzdHJvbmdz
+d2FuLm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u
+b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQC9acuCUPEBOrWB
+56vS8N9bksQwv/XcYIFYqV73kFBAzOPLX2a9igFGvBPdCxFu/t8JCswzE6to4LFM
+2+6Z2QJf442CLPcJKxITahrjJXSxGbzMlmaDvZ5wFCJAlyin+yuInpTwl8rMZe/Q
+O5JeJjzGDgWJtnGdkLUk/l2r6sZ/Cmk5rZpuO0hcUHVztMLQYPzqTpuMvC5p4JzL
+LWGWhKRhJs53NmxXXodck/ZgaqiTWuQFYlbamJRvzVBfX7c1SWHRJvxSSOPKGIg3
+wphkO2naj/SQD+BNuWTRmZ9YCiLOQ64ybLpJzRZISETdqtLBPKsIqosUZwkxlR1N
+9IcgYi5x
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/08.pem b/testing/hosts/winnetou/etc/openssl/newcerts/08.pem
new file mode 100644
index 000000000..abd1554e5
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/08.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIBCDANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjY1MVoXDTA5MDkwOTExMjY1MVowWzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEzARBgNVBAsTCkFjY291
+bnRpbmcxHDAaBgNVBAMUE2RhdmVAc3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDGbCmUY6inir71/6RWebegcLUTmDSxRqpRONDx
+2IRUEuES5EKc7qsjRz45XoqjiywCQRjYW33fUEEY6r7fnHk70CyUnWeZyr7v4D/2
+LjBN3smDE6/ZZrzxPx+xphlUigYOF/vt4gUiW1dOZ5rcnxG9+eNrSL6gWNNg1iuE
+RflSTbmHV6TVmGU2PGddKGZ6XfqWfdA+6iOi2+oyqw6aH4u4hfXhJyMROEOhLdAF
+UvzU9UizEXSqsmEOSodS9vypVJRYTbZcx70e9Q7g2MghHvtQY6mVgBzAwakDBCt/
+98lAlKDeXXOQqPcqAZSc2VjG8gEmkr1dum8wsJw8C2liKGRFAgMBAAGjggEFMIIB
+ATAJBgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQU3pC10RxsZDx0UNNq
++Ihsoxk4+3IwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUx
+CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQD
+ExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQAwHgYDVR0RBBcwFYETZGF2ZUBzdHJvbmdz
+d2FuLm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u
+b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQAnotcnOE0tJDLy
+8Vh1+naT2zrxx9UxfMIeFljwhDqRiHXSLDAbCOnAWoqj8C9riuZwW7UImIIQ9JT9
+Gdktt4bbIcG25rGMC3uqP71CfaAz/SwIZZ2vm8Jt2ZzzSMHsE5qbjDIRAZnq6giR
+P2s6PVsMPSpvH34sRbE0UoWJSdtBZJP5bb+T4hc9gfmbyTewwMnjh09KkGJqVxKV
+UC/1z1U9zb3X1Gc9y+zI67/D46wM6KdRINaqPdK26aYRFM+/DLoTfFk07dsyz7lt
+0C+/ityQOvpfjVlZ/OepT92eWno4FuNRJuUP5/gYiHvSsjZbazqG02qGhJ6VgtGT
+5qILUTmI
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/09.pem b/testing/hosts/winnetou/etc/openssl/newcerts/09.pem
new file mode 100644
index 000000000..6ca9a58a4
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/09.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBCTANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MTExOTE2MjkyOFoXDTA5MTExODE2MjkyOFowZzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHzAdBgNVBAsTFk9DU1Ag
+U2lnbmluZyBBdXRob3JpdHkxHDAaBgNVBAMTE29jc3Auc3Ryb25nc3dhbi5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqJ0y0yhF4iEygd8M73wNC
+8RO590BqiD3Z3x9/5GSVCgfm+ao4hcg6CogNGicu4ybzgPoHt0V/El4D8JRkM8QB
+pg/R7WI4L1ndSZGgTHcQ1vViXGr4PUsIiUR/EgVCSFs8+6Z73J4bJeMomy27Hn9w
+s4leHbrqK87btA2TETV3UlCaDXC6NF8321ZH+D+8OFQaQ0SqKrThKMVYSTf+QdpX
+BlI9vtce1SyS6Kiy4WLdXAt8mO7x+UjaVEzFNyi6SXb9FAGVvO9OXi3+mxm9eK2g
++s1kA4jqDvL17JftvJLKzFZ5irEuTe2+wHdQbwtlOkW1JFAsGL4O+r4NIoBuMBZF
+AgMBAAGjggEaMIIBFjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQU
+iAcKuK7HwQdcvmhqxKV/gR83tVYwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXg
+YOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdT
+d2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQAwHgYDVR0RBBcwFYIT
+b2NzcC5zdHJvbmdzd2FuLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDCTA5BgNVHR8E
+MjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4u
+Y3JsMA0GCSqGSIb3DQEBBAUAA4IBAQA4jOyh+neFCkXMZ1gK0o98qkBr3vYEO2a0
+wb2hDv8Alx6T5kwLgdhAzZ5urZpAdiWF3NWE+z9KnEWnpep9MRDXNM8uBglgBO2v
+SAmV1BXNw2ZDe63w6QvQnezgUuWkrTShfduEDmb8j5jVdzoY+kTKwjLYHPG0Ec79
+Os3PPqXlfeUOkzWnhGVP2EtHCj8SppMdA/XIuwIq8aLN14SITi6gvo/cDMa5N6sT
+Q/UBAOWsxbLReaD7l5OXnAJOg3t/RM36vpRqPseGaAgrKy8805QDU2RxsCHrxwzF
+Wi/17J6nmX3e4PuwqPAI/4MsHlFdExRvSq/gXBN/Ib4AHGkUr0/q
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/0A.pem b/testing/hosts/winnetou/etc/openssl/newcerts/0A.pem
new file mode 100644
index 000000000..8492fbd45
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/0A.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIBCjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDEwMTIxNDMxOFoXDTA5MTIzMTIxNDMxOFowWjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALgbhJIECOCGyNJ4060un/wBuJ6MQjthK5CAEPgX
+T/lvZynoSxhfuW5geDCCxQes6dZPeb6wJS4F5fH3qJoLM+Z4n13rZlCEyyMBkcFl
+vK0aNFY+ARs0m7arUX8B7Pfi9N6WHTYgO4XpeBHLJrZQz9AU0V3S0rce/WVuVjii
+S/cJhrgSi7rl87Qo1jYOA9P06BZQLj0dFNcWWrGpKp/hXvBF1OSP9b15jsgMlCCW
+LJqXmLVKDtKgDPLJZR19mILhgcHvaxxD7craL9GR4QmWLb0m84oAIIwaw+0npZJM
+YDMMeYeOtcepCWCmRy+XmsqcWu4rtNCu05W1RsXjYZEKBjcCAwEAAaOCAQYwggEC
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBRVNeym66J5uu+IfxhD
+j9InsWdG0TBtBgNVHSMEZjBkgBRdp91wBlEyfue2bbO15eBg6i5N76FJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBADAfBgNVHREEGDAWgRRjYXJvbEBzdHJvbmdz
+d2FuLm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u
+b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQCxMEp+Zdclc0aI
+U+jO3TmL81gcwea0BUucjZfDyvCSkDXcXidOez+l/vUueGC7Bqq1ukDF8cpVgGtM
+2HPxM97ZSLPInMgWIeLq3uX8iTtIo05EYqRasJxBIAkY9o6ja6v6z0CZqjSbi2WE
+HrHkFrkOTrRi7deGzbAAhWVjOnAfzSxBaujkdUxb6jGBc2F5qpAeVSbE+sAxzmSd
+hRyF3tUUwl4yabBzmoedJzlQ4anqg0G14QScBxgXkq032gKuzNVVxWRp6OFannKG
+C1INvsBWYtN62wjXlXXhM/M4sBFhmPpftVb+Amgr1jSspTX2dQsNqhI/WtNvLmfK
+omBYfxqp
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/0B.pem b/testing/hosts/winnetou/etc/openssl/newcerts/0B.pem
new file mode 100644
index 000000000..3c5c5d91d
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/0B.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIBCzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDIxNzA4NDQzMFoXDTEwMDIxNjA4NDQzMFowZjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xIDAeBgNVBAsTF0F1dGhv
+cml6YXRpb24gQXV0aG9yaXR5MRowGAYDVQQDFBFhYUBzdHJvbmdzd2FuLm9yZzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2Czo4Mds6Jz15DWop6ExWI
+wWt9zU8Xu//ow1F0Kf9a4DLjo8qO+km3gybByNQQv1LrZ1eq+82Gy4RYXU1FnhC6
+dc8aobDmUQkY/8uYXtUmevKF5QcbYciDLp01W1q0DONAlc/9wmvJWhvjs9itWOBC
+fAUcH3eUNvMgkc7hlQTqreZTH4zyJ6M54JibkTsyfVg/1yOT41zUU3b+vI/r9kNB
+CYcp2DrdhdxX6mEiSTyDA/OMlgvCa7kPinUL4FJtQOFBozCsGcD28ONLc8Abkggf
+NABXCclPVAXOTawJF3dRWcMhIlNLWxWMVRvEt5OkAEdy/mXGBvtVArmGnmA+8zcC
+AwEAAaOCAQIwgf8wCQYDVR0TBAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFA+6
+5KwThPKc9Vxn0048uRThft1tMG0GA1UdIwRmMGSAFF2n3XAGUTJ+57Zts7Xl4GDq
+Lk3voUmkRzBFMQswCQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dh
+bjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBSb290IENBggEAMBwGA1UdEQQVMBOBEWFh
+QHN0cm9uZ3N3YW4ub3JnMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwuc3Ry
+b25nc3dhbi5vcmcvc3Ryb25nc3dhbi5jcmwwDQYJKoZIhvcNAQEEBQADggEBAIeg
+CjgR2yIGSuyrFolvEM/qoT3j+LpQREDZbx9BKr3kGmbqF75clwfpysJ4FlXZZ2CR
+aH2GoPOZGXwsYc3poqGeeWSxo+fpt4XIGUc1eREXm1rKVMd+qb0u0PXuhq2+u1aY
+ZJDY0yqUU2/7AInXjzG7lI120W+K6tuTM/5UVI5EPpAFwUVlCxnMh4Sl4VkgZ2Hw
+YnO3/8SEHmHR03/GhOd5d8hD8a0AGHtdOPpZnUOR9PH5FszpQ/alUdn+NTdQ7O2v
+Q8jqPCeQSAAkJbBBRvGA4bD6KXt1k74fXXUofiKWpQUozlO1Cc978Kfl5/do5bov
+wTLSA/z7c8nVCVoZI9Y=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/0C.pem b/testing/hosts/winnetou/etc/openssl/newcerts/0C.pem
new file mode 100644
index 000000000..c380a5110
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/0C.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwTCCAqmgAwIBAgIBDDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDMyMzA2MjUzNloXDTE0MDMyMTA2MjUzNlowUTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMRQwEgYDVQQDEwtSZXNlYXJjaCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALY5sjqm4AdbWKc/T7JahWpy9xtdPbHngBN6lbnpYaHfrxnGsvmD
+FCFZHCd7egRqQ/AuJHHcEv3DUdfJWWAypVnUvdlcp58hBjpxfTPXP9IDBxzQaQyU
+zsExIGWOVUY2e7xJ5BKBnXVkok3htY4Hr1GdqNh+3LEmbegJBngTRSRx4PKJ54FO
+/b78LUzB+rMxrzxw/lnI8jEmAtKlugQ7c9auMeFCz+NmlSfnSoWhHN5qm+0iNKy0
+C+25IuE8Nq+i3jtBiI8BwBqHY3u2IuflUh9Nc9d/R6vGsRPMHs30X1Ha/m0Ug494
++wwqwfEBZRjzxMmMF/1SG4I1E3TDOJ3srjkCAwEAAaOBrzCBrDAPBgNVHRMBAf8E
+BTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU53XwoPKtIM3NYCPMx8gPKfPd
+VCAwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNV
+BAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJv
+bmdTd2FuIFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEFBQADggEBAA4jpa5Vc/q94/X1
+LAHO2m7v2AFPl68SwspZLbCL7Le+iv5BUQ814Y9qCXMySak+NpZ5RLzm/cC+3GCa
+6eyozhZnS5LDxIgtStXWaC3vIQKQhJMwnc43RgcqneqqS5/H5zNXz/f0g/bRG8bN
+T6nO0ZRdpy8Zu0+fH3f/u9/sQPRX3iNL/rd3x/UVLoowkQHdKzZfjcrFm+8CPl4r
+9xOKjzC6epPY2ApfXmLodd0zemf84CKSJCXfkVlk0cYw1YLKUINnHToFfDAw0kCL
+cVc7wHWZlzSVSE3u0PYXVssnsm08RWqAGPL3TO09fnUntNMzlIxNpOTuWsKVXZPq
+YO2C4HE=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/0D.pem b/testing/hosts/winnetou/etc/openssl/newcerts/0D.pem
new file mode 100644
index 000000000..e50477872
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/0D.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIBDTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDMyMzA2MjkxNloXDTE0MDMyMTA2MjkxNlowSzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsTBVNhbGVz
+MREwDwYDVQQDEwhTYWxlcyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMJOTSaZjDe5UR+hJbodcE40WBxWm+r0FiD+FLc2c0hH/QcWm1Xfqnc9qaPP
+GoxO2BfwXgFEHfOdQzHGuthhsvdMPkmWP1Z3uDrwscqrmLyq4JI87exSen1ggmCV
+Eib55T4fNxrTIGJaoe6Jn9v9ZwG2B+Ur3nFA/wdckSdqJxc6XL9DKcRk3TxZtv9S
+uDftE9G787O6PJSyfyUYhldz1EZe5PTsUoAbBJ0DDXJx3562kDtfQdwezat0LAyO
+sVabYq/0G/fBZwLLer4qGF2+3CsvP7jNXnhRYeSv2+4i2mAjgbBRI1A3iqoU3Nq1
+vPAqzrekOI/RV9Hre9L1r8X1dIECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUX5sTRvkgcsgA1Yi1p0wul+oLkygwbQYD
+VR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNI
+MRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2Fu
+IFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEFBQADggEBAJ7j3X20Q8ICJ2e+iUCpVUIV
+8RudUeHt9qjSXalohuxxhegL5vu7I9Gx0H56RE4glOjLMCb1xqVZ55Odxx14pHaZ
+9iMnQFpgzi96exYAmBKYCHl4IFix2hrTqTWSJhEO+o+PXnQTgcfG43GQepk0qAQr
+iZZy8OWiUhHSJQLJtTMm4rnYjgPn+sLwx7hCPDZpHTZocETDars7wTiVkodCbeEU
+uKahAbq4b6MvvC3+7quvwoEpAEStT7+Yml+QuK/jKmhjX0hcQcw4ZWi+m32RjUAv
+xDJGEvBqV2hyrzRqwh4lVNJEBba5X+QB3N6a0So6BENaJrUM3v8EDaS2KLUWyu0=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/0E.pem b/testing/hosts/winnetou/etc/openssl/newcerts/0E.pem
new file mode 100644
index 000000000..956c217d9
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/0E.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBDjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDYwODE5MTcxNFoXDTEwMDYwNzE5MTcxNFowSjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xIDAeBgNVBAMTF3dpbm5l
+dG91LnN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAwBkz95BmByWVZaEW8cDbeuGr4C1caGAj4QPmuwaIriK+7XqXuh16Ahe3S5vZ
+F56WhUSvMDOIyULckKH84oSa3Jx/SCz0g7X42x8vZuq92tpsjcP/u7BlyqpBUtLa
+r14qm5wYw/1nQqMcSG3k9MQOQ+e9KgaGqpidxWM/8T4M/41AaFRBK2gQGBUULo26
+sjoq3af7Z2jYmWkP/kzj1CHLy9Mgt+UvhKeA+ag5cZnyOG596cqVjlKyqG7vdggk
+wW2n+/KDpHNOndYfT7GMFeGXUNzJPkCImWlttic7ssi0mjP3q3MuOP3FNHIRMd2H
+AcNcqT0bgdJHqnNzGv8C0Ei9XQIDAQABo4IBCTCCAQUwCQYDVR0TBAIwADALBgNV
+HQ8EBAMCA6gwHQYDVR0OBBYEFEMS0mbhrA4zDvmfKf4MntUNxkH4MG0GA1UdIwRm
+MGSAFF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQswCQYDVQQGEwJDSDEZMBcG
+A1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBSb290
+IENBggEAMCIGA1UdEQQbMBmCF3dpbm5ldG91LnN0cm9uZ3N3YW4ub3JnMDkGA1Ud
+HwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwuc3Ryb25nc3dhbi5vcmcvc3Ryb25nc3dh
+bi5jcmwwDQYJKoZIhvcNAQEEBQADggEBACO4+j1Mwt/lbkopeSJst46uFh7OtegG
+6IWNE30i3l3FIn9slSwAOMtmZR0hAF8sExvk61EPlzCR/d9trSJ5+gyjPkeF/enw
+p61rxPMT13Grzomi9gYlk6Q/0zLmE9uYWEY69Q0bEIUcfdZfwB+F7kesa946JNMc
+yHfVEhKtvzmns9ueG0S/8E+6MPDeJv+JHQ++SdWSvOVg6JNxXDGusnim2fjM2Aln
+JmqA6iU4IaPl9DUCuXlLOVv/YhwhviNEbF94upyHq8xjOZdzPbKroHXg/2yvalAw
+4aXc/ZsnFxqsq3i6a2Fj1Y4J7gYsNO/HwA0xvKz3loOTqHaJqO/qeow=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/0F.pem b/testing/hosts/winnetou/etc/openssl/newcerts/0F.pem
new file mode 100644
index 000000000..154cff654
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/newcerts/0F.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwTCCAqmgAwIBAgIBDzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDYyMTE5NTgwNloXDTEwMDYyMDE5NTgwNlowUTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMRQwEgYDVQQDEwtSZXNlYXJjaCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALY5sjqm4AdbWKc/T7JahWpy9xtdPbHngBN6lbnpYaHfrxnGsvmD
+FCFZHCd7egRqQ/AuJHHcEv3DUdfJWWAypVnUvdlcp58hBjpxfTPXP9IDBxzQaQyU
+zsExIGWOVUY2e7xJ5BKBnXVkok3htY4Hr1GdqNh+3LEmbegJBngTRSRx4PKJ54FO
+/b78LUzB+rMxrzxw/lnI8jEmAtKlugQ7c9auMeFCz+NmlSfnSoWhHN5qm+0iNKy0
+C+25IuE8Nq+i3jtBiI8BwBqHY3u2IuflUh9Nc9d/R6vGsRPMHs30X1Ha/m0Ug494
++wwqwfEBZRjzxMmMF/1SG4I1E3TDOJ3srjkCAwEAAaOBrzCBrDAPBgNVHRMBAf8E
+BTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU53XwoPKtIM3NYCPMx8gPKfPd
+VCAwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNV
+BAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJv
+bmdTd2FuIFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAHArS2trQnBoMVcg
+Br3HV78wYsa1MNAQCBAPhKMMd6EziO4FTwgNgecbKXpObX6ErFDgjtVTcLOMTvNX
+fvZoNuPpdcitlgcWjfxZafNbj6j9ClE/rMbGDO64NLhdXuPVkbmic6yXRwGZpTuq
+3CKgTguLvhzIEM47yfonXKaaJcKVPI7nYRZdlJmD4VflYrSUpzB361dCaPpl0AYa
+0zz1+jfBBvlyic/tf+cCngV3f+GlJ4ntZ3gvRjyysHRmYpWBD7xcA8mJzgUiMyi1
+IKeNzydp+tnLfxwetfA/8ptc346me7RktAaASqO9vpS/N78eXyJRthZTKEf/OqVW
+Tfcyi+M=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/ocspCert.pem b/testing/hosts/winnetou/etc/openssl/ocspCert.pem
new file mode 100644
index 000000000..6ca9a58a4
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/ocspCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBCTANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MTExOTE2MjkyOFoXDTA5MTExODE2MjkyOFowZzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHzAdBgNVBAsTFk9DU1Ag
+U2lnbmluZyBBdXRob3JpdHkxHDAaBgNVBAMTE29jc3Auc3Ryb25nc3dhbi5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqJ0y0yhF4iEygd8M73wNC
+8RO590BqiD3Z3x9/5GSVCgfm+ao4hcg6CogNGicu4ybzgPoHt0V/El4D8JRkM8QB
+pg/R7WI4L1ndSZGgTHcQ1vViXGr4PUsIiUR/EgVCSFs8+6Z73J4bJeMomy27Hn9w
+s4leHbrqK87btA2TETV3UlCaDXC6NF8321ZH+D+8OFQaQ0SqKrThKMVYSTf+QdpX
+BlI9vtce1SyS6Kiy4WLdXAt8mO7x+UjaVEzFNyi6SXb9FAGVvO9OXi3+mxm9eK2g
++s1kA4jqDvL17JftvJLKzFZ5irEuTe2+wHdQbwtlOkW1JFAsGL4O+r4NIoBuMBZF
+AgMBAAGjggEaMIIBFjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQU
+iAcKuK7HwQdcvmhqxKV/gR83tVYwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXg
+YOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdT
+d2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQAwHgYDVR0RBBcwFYIT
+b2NzcC5zdHJvbmdzd2FuLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDCTA5BgNVHR8E
+MjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4u
+Y3JsMA0GCSqGSIb3DQEBBAUAA4IBAQA4jOyh+neFCkXMZ1gK0o98qkBr3vYEO2a0
+wb2hDv8Alx6T5kwLgdhAzZ5urZpAdiWF3NWE+z9KnEWnpep9MRDXNM8uBglgBO2v
+SAmV1BXNw2ZDe63w6QvQnezgUuWkrTShfduEDmb8j5jVdzoY+kTKwjLYHPG0Ec79
+Os3PPqXlfeUOkzWnhGVP2EtHCj8SppMdA/XIuwIq8aLN14SITi6gvo/cDMa5N6sT
+Q/UBAOWsxbLReaD7l5OXnAJOg3t/RM36vpRqPseGaAgrKy8805QDU2RxsCHrxwzF
+Wi/17J6nmX3e4PuwqPAI/4MsHlFdExRvSq/gXBN/Ib4AHGkUr0/q
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/ocspKey.pem b/testing/hosts/winnetou/etc/openssl/ocspKey.pem
new file mode 100644
index 000000000..aa04e24c6
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/ocspKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAqidMtMoReIhMoHfDO98DQvETufdAaog92d8ff+RklQoH5vmq
+OIXIOgqIDRonLuMm84D6B7dFfxJeA/CUZDPEAaYP0e1iOC9Z3UmRoEx3ENb1Ylxq
++D1LCIlEfxIFQkhbPPume9yeGyXjKJstux5/cLOJXh266ivO27QNkxE1d1JQmg1w
+ujRfN9tWR/g/vDhUGkNEqiq04SjFWEk3/kHaVwZSPb7XHtUskuiosuFi3VwLfJju
+8flI2lRMxTcoukl2/RQBlbzvTl4t/psZvXitoPrNZAOI6g7y9eyX7bySysxWeYqx
+Lk3tvsB3UG8LZTpFtSRQLBi+Dvq+DSKAbjAWRQIDAQABAoIBAC9SnMfPR0qhhcY/
+aMIXBT4x9E2NUZIPcDxPDOCx8bNtxcLcfxYXRxe1ZB9YvbsRm/yvS1qoAyETR6iK
+2YqAxyu6Nr4o6l879B9SXbkaayb40ehYUbvWuC6Ylr9MkL/dhdqRFr1uH17ni6T4
+e6CGG+WJWVQeqqSEKJT8H6Zea+NSQi9UOsVgKIMiXr52j3hj8LraH/4FoOPlgg3r
+mqrVcQlDYLtt+cufpFJLGzJhTylqlWCRWA6nwKFl8zZqGNaCswKkC3Ql47vlAmQT
+ETl4MMpVsmezC8OcursRmgPJzRudnGg6RLyfTff9b/wFmIujvJLYeN/ILRFvFGkq
+kiIWNIUCgYEA27y3N6lHJ8ommqquoyAVfQpc5Y1gFFXoE8VzkO1ts5B0N6r2DVvy
+DFUT3cSWdBOsF2MykTnyAC0dVXRXTCTEI2AqdmgITOzs3Ydr0XlOPmuM3dOO060F
+I9x4GsCpVcV/zWBZfJyUhNQqxpozrWNvHVgxrEc8pjD29iMLf+EsP2cCgYEAxjvP
+9uQjRxWv3/5ZVEOpBnecZe+ysg0CgK0zt+nogTAn7ET27FFeW8BjcR6g+r57n9cu
+X6EGdxuLexwoqvt3dO/rBF74knTe4ElDzEhcAoxnZPnJrJ6aST0KZ7lGoX5UW7wp
+eyW7HXKpd1THY40v7aHhaSr4362kMTFpPvxxrXMCgYAkDa2+Kz8qjyeQXwryZvQ/
+pPCjFXQ7QfEnNVGF6P8D5GK9M4bVoE1xqo/s5jGNcCDfYX5Nh8VmNADJIaKlMq8f
+4sp0zRL3lDQ1EOAm6ZFl+n2NdAXOQ2hBfw4RzaS7FwGmL/Xe1U4lES7HkUuDWnpD
+xVG5I6MW3ZfXwN5FKCv7ZwKBgByIVWmq8qzzoSnzeTYYuwZ0Ru2hL65TEw4kX/JT
+16RoowZt8sCXAabhLS8GApO0wSSDm2gmTEDulQf2SKA7q7kII2KwrMSfz8imovyP
+WbcAMI2nKnEPLxPllk7RqynpfgjqL2pLRwB5FY1YhY59ru1cRI6XodTIMH7oJsbr
+HQ2jAoGADHlVLAf9hQTYMrLCaO4mjOlJwRa19e1l47o4Lt1H+cGh96Jc4i7Hfkmv
+e/j/ZF4XqtjvmZIR2xevL2+/pPVuMYV0hEWyDQzoUgM6OXF4smSG3N+SrDTSmM8I
+XE9Ohc2JL3IKWN8SarsTUCrqle7UakmbYTUJqH9bJwGyvm3Ro1o=
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/winnetou/etc/openssl/openssl.cnf b/testing/hosts/winnetou/etc/openssl/openssl.cnf
new file mode 100644
index 000000000..dbe31abbd
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/openssl.cnf
@@ -0,0 +1,182 @@
+# openssl.cnf - OpenSSL configuration file for the ZHW PKI
+# Mario Strasser <mario.strasser@zhwin.ch>
+#
+# $Id: openssl.cnf,v 1.2 2005/08/15 21:25:22 as Exp $
+#
+
+# This definitions were set by the ca_init script DO NOT change
+# them manualy.
+CAHOME = /etc/openssl
+RANDFILE = $CAHOME/.rand
+
+# Extra OBJECT IDENTIFIER info:
+oid_section = new_oids
+
+[ new_oids ]
+SmartcardLogin = 1.3.6.1.4.1.311.20.2
+ClientAuthentication = 1.3.6.1.4.1.311.20.2.2
+
+####################################################################
+
+[ ca ]
+default_ca = root_ca # The default ca section
+
+####################################################################
+
+[ root_ca ]
+
+dir = $CAHOME
+certs = $dir/certs # Where the issued certs are kept
+crl_dir = $dir/crl # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+new_certs_dir = $dir/newcerts # default place for new certs.
+
+certificate = $dir/strongswanCert.pem # The CA certificate
+serial = $dir/serial # The current serial number
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/strongswanKey.pem # The private key
+RANDFILE = $dir/.rand # private random number file
+
+x509_extensions = host_ext # The extentions to add to the cert
+
+crl_extensions = crl_ext # The extentions to add to the CRL
+
+default_days = 1825 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = md5 # which md to use.
+preserve = no # keep passed DN ordering
+email_in_dn = no # allow/forbid EMail in DN
+
+policy = policy_match # specifying how similar the request must look
+
+####################################################################
+
+# the 'match' policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = optional
+localityName = optional
+organizationName = match
+organizationalUnitName = optional
+userId = optional
+serialNumber = optional
+commonName = supplied
+emailAddress = optional
+
+# the 'anything' policy
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+
+[ req ]
+default_bits = 1024
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = ca_ext # The extentions to add to the self signed cert
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString.
+# utf8only: only UTF8Strings.
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
+# so use this option with caution!
+string_mask = nombstr
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+####################################################################
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = CH
+countryName_min = 2
+countryName_max = 2
+
+#stateOrProvinceName = State or Province Name (full name)
+#stateOrProvinceName_default = ZH
+
+#localityName = Locality Name (eg, city)
+#localityName_default = Winterthur
+
+organizationName = Organization Name (eg, company)
+organizationName_default = Linux strongSwan
+
+0.organizationalUnitName = Organizational Unit Name (eg, section)
+#0.organizationalUnitName_default = Research
+
+#1.organizationalUnitName = Type (eg, Staff)
+#1.organizationalUnitName_default = Staff
+
+#userId = UID
+
+commonName = Common Name (eg, YOUR name)
+commonName_default = $ENV::COMMON_NAME
+commonName_max = 64
+
+#0.emailAddress = Email Address (eg, foo@bar.com)
+#0.emailAddress_min = 0
+#0.emailAddress_max = 40
+
+#1.emailAddress = Second Email Address (eg, foo@bar.com)
+#1.emailAddress_min = 0
+#1.emailAddress_max = 40
+
+####################################################################
+
+[ req_attributes ]
+
+####################################################################
+
+[ host_ext ]
+
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, keyEncipherment, keyAgreement
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer:always
+subjectAltName = DNS:$ENV::COMMON_NAME
+#extendedKeyUsage = OCSPSigner
+crlDistributionPoints = URI:http://crl.strongswan.org/strongswan.crl
+
+####################################################################
+
+[ user_ext ]
+
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, keyEncipherment, keyAgreement
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer:always
+subjectAltName = email:$ENV::COMMON_NAME
+crlDistributionPoints = URI:http://crl.strongswan.org/strongswan.crl
+
+####################################################################
+
+[ ca_ext ]
+
+basicConstraints = critical, CA:TRUE
+keyUsage = cRLSign, keyCertSign
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer:always
+
+####################################################################
+
+[ crl_ext ]
+
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+#issuerAltName = issuer:copy
+authorityKeyIdentifier = keyid:always, issuer:always
+
+# eof
diff --git a/testing/hosts/winnetou/etc/openssl/research/.rand b/testing/hosts/winnetou/etc/openssl/research/.rand
new file mode 100644
index 000000000..7479c2979
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/.rand
Binary files differ
diff --git a/testing/hosts/winnetou/etc/openssl/research/carolReq.pem b/testing/hosts/winnetou/etc/openssl/research/carolReq.pem
new file mode 100644
index 000000000..f2a6b5c22
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/carolReq.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICnzCCAYcCAQAwWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9u
+Z1N3YW4xETAPBgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdz
+d2FuLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+oTiV7lCh1
+ID41edDUgUjRdZwEMPBAM1xDqoxJxIJpug8UIuuUL0TvQnZ4Z5fa/9QNNCkQ7FDh
+8ZcR+TT8x0mOdYYA73mMQic0n4O57F+s/lESKvIoN+vIDR3rGJBv9rYztS4ODE+D
+Jl9XK9TtId5u57jfXu/k3IYl5GeQ3f+ic2l2Ola70t70Op6cFDZIhOCjs2xWw2yq
+GdPWODaN/Enw5fOLv/om+7HHB4KgPGv4p4ohWIUCo2XK597Ii+jB2MdOUlG83/1a
+X7+M+IeYVwjIhzWjwRQfMz0AQha0HYN4cvrZ7stUluMxewsCROCBzcGQYTZxYU4F
+jR8nhH4ApYMCAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4IBAQA9OKM8HKu5Fp/HRsdS
+3Z/tuLVjwijVq/OIge1PnoW7Ri2hnTpWeaWcU2wIexsxPJR6kYwqp9NfxM73uUUU
+e/ROCU+kZxSuzfV3SMMI8bsjufuldxKUXs1B8Nit1Qkhhj1/4uN6FRzQ5E9vz0Yf
+OuVVJxMIEgQRdBTcZ8Cuf23Mcq+sBa/2OXD/y6WTUNrXvjTjmGWv1LnryB6Ro8se
+ndI7bIiMZ/sSOrhOWrii/655bpUSYIb0RCzOnbdNAevbn/bLMEpj0qiDSam88Y/6
+FIY5sDCsdlpHsI2vkIrvPo4PUE+yzBhezmrLbVoiHjVoZhr1h091777Bomg/oUxv
+beEk
+-----END CERTIFICATE REQUEST-----
diff --git a/testing/hosts/winnetou/etc/openssl/research/index.txt b/testing/hosts/winnetou/etc/openssl/research/index.txt
new file mode 100644
index 000000000..4bd650072
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/index.txt
@@ -0,0 +1,2 @@
+V 100322070423Z 01 unknown /C=CH/O=Linux strongSwan/OU=Research/CN=carol@strongswan.org
+V 100615195710Z 02 unknown /C=CH/O=Linux strongSwan/OU=Sales/CN=Sales CA
diff --git a/testing/hosts/winnetou/etc/openssl/research/index.txt.attr b/testing/hosts/winnetou/etc/openssl/research/index.txt.attr
new file mode 100644
index 000000000..8f7e63a34
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/index.txt.attr
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/testing/hosts/winnetou/etc/openssl/research/index.txt.attr.old b/testing/hosts/winnetou/etc/openssl/research/index.txt.attr.old
new file mode 100644
index 000000000..8f7e63a34
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/index.txt.attr.old
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/testing/hosts/winnetou/etc/openssl/research/index.txt.old b/testing/hosts/winnetou/etc/openssl/research/index.txt.old
new file mode 100644
index 000000000..148bab7d6
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/index.txt.old
@@ -0,0 +1 @@
+V 100322070423Z 01 unknown /C=CH/O=Linux strongSwan/OU=Research/CN=carol@strongswan.org
diff --git a/testing/hosts/winnetou/etc/openssl/research/newcerts/01.pem b/testing/hosts/winnetou/etc/openssl/research/newcerts/01.pem
new file mode 100644
index 000000000..2990d6a12
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/newcerts/01.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIELDCCAxSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjERMA8GA1UECxMIUmVzZWFyY2gxFDAS
+BgNVBAMTC1Jlc2VhcmNoIENBMB4XDTA1MDMyMzA3MDQyM1oXDTEwMDMyMjA3MDQy
+M1owWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
+BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+oTiV7lCh1ID41edDUgUjR
+dZwEMPBAM1xDqoxJxIJpug8UIuuUL0TvQnZ4Z5fa/9QNNCkQ7FDh8ZcR+TT8x0mO
+dYYA73mMQic0n4O57F+s/lESKvIoN+vIDR3rGJBv9rYztS4ODE+DJl9XK9TtId5u
+57jfXu/k3IYl5GeQ3f+ic2l2Ola70t70Op6cFDZIhOCjs2xWw2yqGdPWODaN/Enw
+5fOLv/om+7HHB4KgPGv4p4ohWIUCo2XK597Ii+jB2MdOUlG83/1aX7+M+IeYVwjI
+hzWjwRQfMz0AQha0HYN4cvrZ7stUluMxewsCROCBzcGQYTZxYU4FjR8nhH4ApYMC
+AwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSL
+qNn96rsWg0kOJY/cyXD2JpnPIjBtBgNVHSMEZjBkgBTndfCg8q0gzc1gI8zHyA8p
+891UIKFJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3
+YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIBDDAfBgNVHREEGDAWgRRj
+YXJvbEBzdHJvbmdzd2FuLm9yZzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3Js
+LnN0cm9uZ3N3YW4ub3JnL3Jlc2VhcmNoLmNybDANBgkqhkiG9w0BAQUFAAOCAQEA
+FNPepmta0ac9TWe7Gl31fKkuf6ZiQftMwx/uq6PoX9PBVGeooktJMo+EiROQhL3N
+Zomtl2nLfxYruXPHa7YaMWyv4+3NkV9p7jseC1K/2lCXipY4Vp8u14hqlRLCTejp
+7uC/0+628e+qXlCm8wafDb9/JXzQar7rADhoLp7gJKI2PKMAzLUP2xZVzY5zx57G
++OCR/ZXonVeAPy9/0g9N8uQzJEXOVZYMjsoRra9rdlvnY1DgDoAK7QvJMC4VzENm
+wKmz2rPrBlKaEcivubg7dwPMGNmb3f7F7w0HHuRbQd5Y0nDfEWBKCp0bVx1GLc7/
+MWjwPJs52qVJ3Ph++EF6bw==
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/research/newcerts/02.pem b/testing/hosts/winnetou/etc/openssl/research/newcerts/02.pem
new file mode 100644
index 000000000..90e207c4b
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/newcerts/02.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBAjANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjERMA8GA1UECxMIUmVzZWFyY2gxFDAS
+BgNVBAMTC1Jlc2VhcmNoIENBMB4XDTA1MDYxNjE5NTcxMFoXDTEwMDYxNTE5NTcx
+MFowSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAM
+BgNVBAsTBVNhbGVzMREwDwYDVQQDEwhTYWxlcyBDQTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMJOTSaZjDe5UR+hJbodcE40WBxWm+r0FiD+FLc2c0hH
+/QcWm1Xfqnc9qaPPGoxO2BfwXgFEHfOdQzHGuthhsvdMPkmWP1Z3uDrwscqrmLyq
+4JI87exSen1ggmCVEib55T4fNxrTIGJaoe6Jn9v9ZwG2B+Ur3nFA/wdckSdqJxc6
+XL9DKcRk3TxZtv9SuDftE9G787O6PJSyfyUYhldz1EZe5PTsUoAbBJ0DDXJx3562
+kDtfQdwezat0LAyOsVabYq/0G/fBZwLLer4qGF2+3CsvP7jNXnhRYeSv2+4i2mAj
+gbBRI1A3iqoU3Nq1vPAqzrekOI/RV9Hre9L1r8X1dIECAwEAAaOB6DCB5TAPBgNV
+HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUX5sTRvkgcsgA1Yi1
+p0wul+oLkygwbQYDVR0jBGYwZIAU53XwoPKtIM3NYCPMx8gPKfPdVCChSaRHMEUx
+CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQD
+ExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQwwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDov
+L2NybC5zdHJvbmdzd2FuLm9yZy9yZXNlYXJjaC5jcmwwDQYJKoZIhvcNAQEFBQAD
+ggEBAJW0/z17JK38rsn8zh0Ta+9Ql5fcA9UIUGcN/KfCvdGwrYaym8Dy6Pz+sZkO
+clOv5t+3R1zKDiiLGQ4m8jYW6NcxeJZyyPhGtKaafanXZsQuMpaTpvkRr62jx/NB
+b3c/HS3dqz2dTMvFJ6CC65vOnnGgzF1szhrrWymGI/NuHUge748WYPNw+OsLmBQI
+koXJsMURGtPWXtJE98Rre+r/6O5kzZNv7V8LGoBkWf1Z6g1q2VvCcnJPxANcQoxf
+Is+E+aqBhGJ6XlnQIlQB1SjoMhOnJ282JK9Hk3NmQYb/zvIzIfo3FCrjj1JI/XoA
+/szZoxwnE2iHtIoMAhfHZpRvOkg=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/research/openssl.cnf b/testing/hosts/winnetou/etc/openssl/research/openssl.cnf
new file mode 100644
index 000000000..b5afd3d2e
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/openssl.cnf
@@ -0,0 +1,181 @@
+# openssl.cnf - OpenSSL configuration file for the ZHW PKI
+# Mario Strasser <mario.strasser@zhwin.ch>
+#
+# $Id: openssl.cnf,v 1.1 2005/03/24 11:24:07 as Exp $
+#
+
+# This definitions were set by the ca_init script DO NOT change
+# them manualy.
+CAHOME = /etc/openssl/research
+RANDFILE = $CAHOME/.rand
+
+# Extra OBJECT IDENTIFIER info:
+oid_section = new_oids
+
+[ new_oids ]
+SmartcardLogin = 1.3.6.1.4.1.311.20.2
+ClientAuthentication = 1.3.6.1.4.1.311.20.2.2
+
+####################################################################
+
+[ ca ]
+default_ca = root_ca # The default ca section
+
+####################################################################
+
+[ root_ca ]
+
+dir = $CAHOME
+certs = $dir/certs # Where the issued certs are kept
+crl_dir = $dir/crl # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+new_certs_dir = $dir/newcerts # default place for new certs.
+
+certificate = $dir/researchCert.pem # The CA certificate
+serial = $dir/serial # The current serial number
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/researchKey.pem # The private key
+RANDFILE = $dir/.rand # private random number file
+
+x509_extensions = host_ext # The extentions to add to the cert
+
+crl_extensions = crl_ext # The extentions to add to the CRL
+
+default_days = 1825 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = sha1 # which md to use.
+preserve = no # keep passed DN ordering
+email_in_dn = no # allow/forbid EMail in DN
+
+policy = policy_match # specifying how similar the request must look
+
+####################################################################
+
+# the 'match' policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = optional
+localityName = optional
+organizationName = match
+organizationalUnitName = optional
+userId = optional
+commonName = supplied
+emailAddress = optional
+
+# the 'anything' policy
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+
+[ req ]
+default_bits = 1024
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = ca_ext # The extentions to add to the self signed cert
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString.
+# utf8only: only UTF8Strings.
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
+# so use this option with caution!
+string_mask = nombstr
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+####################################################################
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = CH
+countryName_min = 2
+countryName_max = 2
+
+#stateOrProvinceName = State or Province Name (full name)
+#stateOrProvinceName_default = ZH
+
+#localityName = Locality Name (eg, city)
+#localityName_default = Winterthur
+
+organizationName = Organization Name (eg, company)
+organizationName_default = Linux strongSwan
+
+0.organizationalUnitName = Organizational Unit Name (eg, section)
+0.organizationalUnitName_default = Research
+
+#1.organizationalUnitName = Type (eg, Staff)
+#1.organizationalUnitName_default = Staff
+
+#userId = UID
+
+commonName = Common Name (eg, YOUR name)
+commonName_default = $ENV::COMMON_NAME
+commonName_max = 64
+
+#0.emailAddress = Email Address (eg, foo@bar.com)
+#0.emailAddress_min = 0
+#0.emailAddress_max = 40
+
+#1.emailAddress = Second Email Address (eg, foo@bar.com)
+#1.emailAddress_min = 0
+#1.emailAddress_max = 40
+
+####################################################################
+
+[ req_attributes ]
+
+####################################################################
+
+[ host_ext ]
+
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, keyEncipherment, keyAgreement
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer:always
+subjectAltName = DNS:$ENV::COMMON_NAME
+#extendedKeyUsage = OCSPSigner
+crlDistributionPoints = URI:http://crl.strongswan.org/research.crl
+
+####################################################################
+
+[ user_ext ]
+
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, keyEncipherment, keyAgreement
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer:always
+subjectAltName = email:$ENV::COMMON_NAME
+crlDistributionPoints = URI:http://crl.strongswan.org/research.crl
+
+####################################################################
+
+[ ca_ext ]
+
+basicConstraints = critical, CA:TRUE
+keyUsage = cRLSign, keyCertSign
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer:always
+
+####################################################################
+
+[ crl_ext ]
+
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+#issuerAltName = issuer:copy
+authorityKeyIdentifier = keyid:always, issuer:always
+
+# eof
diff --git a/testing/hosts/winnetou/etc/openssl/research/researchCert.der b/testing/hosts/winnetou/etc/openssl/research/researchCert.der
new file mode 100644
index 000000000..2a52f620d
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/researchCert.der
Binary files differ
diff --git a/testing/hosts/winnetou/etc/openssl/research/researchCert.pem b/testing/hosts/winnetou/etc/openssl/research/researchCert.pem
new file mode 100644
index 000000000..154cff654
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/researchCert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwTCCAqmgAwIBAgIBDzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDYyMTE5NTgwNloXDTEwMDYyMDE5NTgwNlowUTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMRQwEgYDVQQDEwtSZXNlYXJjaCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALY5sjqm4AdbWKc/T7JahWpy9xtdPbHngBN6lbnpYaHfrxnGsvmD
+FCFZHCd7egRqQ/AuJHHcEv3DUdfJWWAypVnUvdlcp58hBjpxfTPXP9IDBxzQaQyU
+zsExIGWOVUY2e7xJ5BKBnXVkok3htY4Hr1GdqNh+3LEmbegJBngTRSRx4PKJ54FO
+/b78LUzB+rMxrzxw/lnI8jEmAtKlugQ7c9auMeFCz+NmlSfnSoWhHN5qm+0iNKy0
+C+25IuE8Nq+i3jtBiI8BwBqHY3u2IuflUh9Nc9d/R6vGsRPMHs30X1Ha/m0Ug494
++wwqwfEBZRjzxMmMF/1SG4I1E3TDOJ3srjkCAwEAAaOBrzCBrDAPBgNVHRMBAf8E
+BTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU53XwoPKtIM3NYCPMx8gPKfPd
+VCAwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNV
+BAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJv
+bmdTd2FuIFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAHArS2trQnBoMVcg
+Br3HV78wYsa1MNAQCBAPhKMMd6EziO4FTwgNgecbKXpObX6ErFDgjtVTcLOMTvNX
+fvZoNuPpdcitlgcWjfxZafNbj6j9ClE/rMbGDO64NLhdXuPVkbmic6yXRwGZpTuq
+3CKgTguLvhzIEM47yfonXKaaJcKVPI7nYRZdlJmD4VflYrSUpzB361dCaPpl0AYa
+0zz1+jfBBvlyic/tf+cCngV3f+GlJ4ntZ3gvRjyysHRmYpWBD7xcA8mJzgUiMyi1
+IKeNzydp+tnLfxwetfA/8ptc346me7RktAaASqO9vpS/N78eXyJRthZTKEf/OqVW
+Tfcyi+M=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/research/researchKey.pem b/testing/hosts/winnetou/etc/openssl/research/researchKey.pem
new file mode 100644
index 000000000..5e6f030f9
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/researchKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAtjmyOqbgB1tYpz9PslqFanL3G109seeAE3qVuelhod+vGcay
++YMUIVkcJ3t6BGpD8C4kcdwS/cNR18lZYDKlWdS92VynnyEGOnF9M9c/0gMHHNBp
+DJTOwTEgZY5VRjZ7vEnkEoGddWSiTeG1jgevUZ2o2H7csSZt6AkGeBNFJHHg8onn
+gU79vvwtTMH6szGvPHD+WcjyMSYC0qW6BDtz1q4x4ULP42aVJ+dKhaEc3mqb7SI0
+rLQL7bki4Tw2r6LeO0GIjwHAGodje7Yi5+VSH01z139Hq8axE8wezfRfUdr+bRSD
+j3j7DCrB8QFlGPPEyYwX/VIbgjUTdMM4neyuOQIDAQABAoIBAA0xhjb66BOASJ3r
+VpDaPvijFEMV8CaWVU6TvI12WUxIDrx2B3VLSUTU19X/+aiiLQMRxC++OF3JK37N
+JDxzzkb/wTMgoz5BPNs0ZlU/i25gK76pVEHF8GZKcUcJFCF+Rl0umGXCnqzmOV4c
+LnH3Gnl1SclK/h2RY7m+FYrSElp+COHYBnW0agLIfRv/fF/1yApBP6jGegEFXp5z
+ZEwmmS2GbjVRq7ClqXfadQaPwRmGuueChq9S0DaY2z6/EAQJM/mHZYkeZGNTJqTk
+KWY0RmFZlCXRIxs+hG1agPZ/jdRwnxghPDcpnNZHKXLyoQhUa9oXn+RuUxPdK/s3
+9nB30xECgYEA6snKErKb04Sj6sB0/ONMK3OENVcbBYZlhyzymuSgpFY8FhhyDFIG
+H80eMGzlusvrBfV7OfJd17Mwuy0H3WBSGapbqXUa/vNc37VSGCiTObz/5RDhyU1N
+6zq5RZKPVDgnJ3VBTEr8Ito6b5iZWtyaRw0e4Xv1K0tdQPTLe2TaAEUCgYEAxrA6
+A94jBZWMwrXrUa7DCi0Y7BPh8hbZwHH1qEr8xNALnXGHSA5BbhjqLkYCWP5GlvrC
+G0TNrX1SMTv739wQL/GqvLTM1Jc/jrmPkLBymLNyweaKBXFt1qJDOdvtMwZdDo0y
+9hKXfyCDMURi3JhP/GLzA3bUruw28njZYgWI92UCgYBSKHyKoG+Ay7hkTCZj29Hq
+noiT9cAh5c6fR645X2mLOBXckX9PKmC0Ph2jSmf1PqgmNKmDNHl8IlsaFH7dC3iP
+PJrIqI7iyhwkuBlbFM+385gD+y1XOLLcbncojkmTafbhitlnrhGezIiIRnjbX7io
+xkGZG7xGAyBFu6N8sWTLlQKBgHdPN2c/KxSdWytJBofEQ8aGkiKhRdqTsiqHxBZN
+AUBGFdNzauLv/IZaW7VxwNMjzcu3xHuPc1qsmICMHpGsmePQYNB0WVOHh1jzQKyH
+6CieCVk6UMM3+9cZFPlXgTZUqeilDWcKfwKNyXn6MMt6gv1xhbAc2VY47j3oJ9Fe
+tYKpAoGAAWY1MTen71hatSFA7UGweuTqok5vhp0CPtGwCXLNHUcEhy1Fc640EO9i
+8i35fLA79haYWgpZ+GvrW9eYLPB8djidGSfzajc5C2CITHOrDQ6YQzKhwLjRHvB5
+gFQ8pdzFiXmSEvtfRwhoJvW19wdCZZx41VZ554ILOYrjtkntOB8=
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/winnetou/etc/openssl/research/serial b/testing/hosts/winnetou/etc/openssl/research/serial
new file mode 100644
index 000000000..75016ea36
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/serial
@@ -0,0 +1 @@
+03
diff --git a/testing/hosts/winnetou/etc/openssl/research/serial.old b/testing/hosts/winnetou/etc/openssl/research/serial.old
new file mode 100644
index 000000000..9e22bcb8e
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/research/serial.old
@@ -0,0 +1 @@
+02
diff --git a/testing/hosts/winnetou/etc/openssl/sales/.rand b/testing/hosts/winnetou/etc/openssl/sales/.rand
new file mode 100644
index 000000000..dd489598f
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/.rand
Binary files differ
diff --git a/testing/hosts/winnetou/etc/openssl/sales/index.txt b/testing/hosts/winnetou/etc/openssl/sales/index.txt
new file mode 100644
index 000000000..5093b34e9
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/index.txt
@@ -0,0 +1,2 @@
+V 100322071017Z 01 unknown /C=CH/O=Linux strongSwan/OU=Sales/CN=dave@strongswan.org
+V 100615195536Z 02 unknown /C=CH/O=Linux strongSwan/OU=Research/CN=Research CA
diff --git a/testing/hosts/winnetou/etc/openssl/sales/index.txt.attr b/testing/hosts/winnetou/etc/openssl/sales/index.txt.attr
new file mode 100644
index 000000000..8f7e63a34
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/index.txt.attr
@@ -0,0 +1 @@
+unique_subject = yes
diff --git a/testing/hosts/winnetou/etc/openssl/sales/index.txt.old b/testing/hosts/winnetou/etc/openssl/sales/index.txt.old
new file mode 100644
index 000000000..7378ebb8a
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/index.txt.old
@@ -0,0 +1 @@
+V 100322071017Z 01 unknown /C=CH/O=Linux strongSwan/OU=Sales/CN=dave@strongswan.org
diff --git a/testing/hosts/winnetou/etc/openssl/sales/newcerts/01.pem b/testing/hosts/winnetou/etc/openssl/sales/newcerts/01.pem
new file mode 100644
index 000000000..b76032480
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/newcerts/01.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEHDCCAwSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEOMAwGA1UECxMFU2FsZXMxETAPBgNV
+BAMTCFNhbGVzIENBMB4XDTA1MDMyMzA3MTAxN1oXDTEwMDMyMjA3MTAxN1owVjEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsT
+BVNhbGVzMRwwGgYDVQQDFBNkYXZlQHN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqAR0itGIuSt/RR8IHjFTLH/lywprmHUw0GS
+zZwo/q4AE4v6OeWRG3JUUg44K40yBwr7zvcsLztRTfbNqlt7o+Hjpo3kz0AMwDo+
+1V42Qkh61VJW1P0NQvkgjiQn+ElSMg1u3uiYCIMAhYMYo2ZMKxHXxRqjU79AVuJN
+P3p8wUpfwReImAy3/n685YbSzWcbPqCfjRH/YrnYS8Ga7m/QzdNfrtxhAWAGow1+
++eTSMvLXSkQeujU6OCJNOPUNB3nnJ1IoZrQm8wNP8Y5B5HzvOSyFEvNuHFc63gSP
+aSRhuz0gubuMpr1d9Rgjny8JgsfCEbOktlKwnbFeSB8AAgVMjwIDAQABo4H/MIH8
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSCy57rUdNRbytUkRGY
+GjmjvXfIszBtBgNVHSMEZjBkgBRfmxNG+SByyADViLWnTC6X6guTKKFJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBDTAeBgNVHREEFzAVgRNkYXZlQHN0cm9uZ3N3
+YW4ub3JnMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwuc3Ryb25nc3dhbi5v
+cmcvc2FsZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQB+BknSxFKaDhbRVobOAU2P
+p9cirkVCitoZrvK2QIS/7WRoqy85RQ+zorJb3jyTxQl4Pu9Qrap9Zn0H8GQXGlQw
+ZJqdDqRaIa4nCc57qP5DsuQKIQRxc1QMCiWyIRAESn+r8IbxLbjvEd7ZXNsieip6
+Q15uUZldjTveHVi89i9oFWS1nWo4SV+tJaEqPBvsTZZKBPAEu6+7lRzbJ4ukzRsA
+DjuvmaPNUTyf21fD66I4sgrwgxoPhZ7r6qsqISJ5f0EzTXgYNi1yk/TXoAaot3c/
+Gu5+iyO/espV6kPADSOzPSFwsGHYG4kXi1VY0Z7x6UnjQSdEelOBplJ5XYDzEn4+
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/sales/newcerts/02.pem b/testing/hosts/winnetou/etc/openssl/sales/newcerts/02.pem
new file mode 100644
index 000000000..efb939e3a
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/newcerts/02.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID/TCCAuWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEOMAwGA1UECxMFU2FsZXMxETAPBgNV
+BAMTCFNhbGVzIENBMB4XDTA1MDYxNjE5NTUzNloXDTEwMDYxNTE5NTUzNlowUTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsT
+CFJlc2VhcmNoMRQwEgYDVQQDEwtSZXNlYXJjaCBDQTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALY5sjqm4AdbWKc/T7JahWpy9xtdPbHngBN6lbnpYaHf
+rxnGsvmDFCFZHCd7egRqQ/AuJHHcEv3DUdfJWWAypVnUvdlcp58hBjpxfTPXP9ID
+BxzQaQyUzsExIGWOVUY2e7xJ5BKBnXVkok3htY4Hr1GdqNh+3LEmbegJBngTRSRx
+4PKJ54FO/b78LUzB+rMxrzxw/lnI8jEmAtKlugQ7c9auMeFCz+NmlSfnSoWhHN5q
+m+0iNKy0C+25IuE8Nq+i3jtBiI8BwBqHY3u2IuflUh9Nc9d/R6vGsRPMHs30X1Ha
+/m0Ug494+wwqwfEBZRjzxMmMF/1SG4I1E3TDOJ3srjkCAwEAAaOB5TCB4jAPBgNV
+HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU53XwoPKtIM3NYCPM
+x8gPKfPdVCAwbQYDVR0jBGYwZIAUX5sTRvkgcsgA1Yi1p0wul+oLkyihSaRHMEUx
+CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQD
+ExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQ0wNAYDVR0fBC0wKzApoCegJYYjaHR0cDov
+L2NybC5zdHJvbmdzd2FuLm9yZy9zYWxlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEB
+AJ2EkXnpgdJpsBIMcH+3oTUks8gAT5bR+LdVQSMHqvjgfaCq5fuZY15niLm5QeFr
+Yhv2KtfHfF+tZgE+qWcqS33Y2U/jwUMO45Wqi5HXQDk8AM/gcvQZ8+PINkGdVdup
+Wyw3MM08S/fp8UUl/3QrDr+CBGqZCSx3LEIFILm2hvdXK1/okAtkwlKV4YiOEemg
+pZURzA2M29FeGDS8snfiVYFBkydT9QrrHnx8IwyVGykfOA4tnjRsjTvcs0qhtLcL
+rjK2FSmzBTCVl6/lBOYmB765KUHev6WF4hdMKHf7lsH2nhYb97jxoT54y73jVd1S
+uaJ2yDwEhOHn3ihb1bqlanM=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/sales/openssl.cnf b/testing/hosts/winnetou/etc/openssl/sales/openssl.cnf
new file mode 100644
index 000000000..adb204bc2
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/openssl.cnf
@@ -0,0 +1,181 @@
+# openssl.cnf - OpenSSL configuration file for the ZHW PKI
+# Mario Strasser <mario.strasser@zhwin.ch>
+#
+# $Id: openssl.cnf,v 1.1 2005/03/24 11:24:07 as Exp $
+#
+
+# This definitions were set by the ca_init script DO NOT change
+# them manualy.
+CAHOME = /etc/openssl/sales
+RANDFILE = $CAHOME/.rand
+
+# Extra OBJECT IDENTIFIER info:
+oid_section = new_oids
+
+[ new_oids ]
+SmartcardLogin = 1.3.6.1.4.1.311.20.2
+ClientAuthentication = 1.3.6.1.4.1.311.20.2.2
+
+####################################################################
+
+[ ca ]
+default_ca = root_ca # The default ca section
+
+####################################################################
+
+[ root_ca ]
+
+dir = $CAHOME
+certs = $dir/certs # Where the issued certs are kept
+crl_dir = $dir/crl # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+new_certs_dir = $dir/newcerts # default place for new certs.
+
+certificate = $dir/salesCert.pem # The CA certificate
+serial = $dir/serial # The current serial number
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/salesKey.pem # The private key
+RANDFILE = $dir/.rand # private random number file
+
+x509_extensions = host_ext # The extentions to add to the cert
+
+crl_extensions = crl_ext # The extentions to add to the CRL
+
+default_days = 1825 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = sha1 # which md to use.
+preserve = no # keep passed DN ordering
+email_in_dn = no # allow/forbid EMail in DN
+
+policy = policy_match # specifying how similar the request must look
+
+####################################################################
+
+# the 'match' policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = optional
+localityName = optional
+organizationName = match
+organizationalUnitName = optional
+userId = optional
+commonName = supplied
+emailAddress = optional
+
+# the 'anything' policy
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+
+[ req ]
+default_bits = 1024
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = ca_ext # The extentions to add to the self signed cert
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString.
+# utf8only: only UTF8Strings.
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
+# so use this option with caution!
+string_mask = nombstr
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+####################################################################
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = CH
+countryName_min = 2
+countryName_max = 2
+
+#stateOrProvinceName = State or Province Name (full name)
+#stateOrProvinceName_default = ZH
+
+#localityName = Locality Name (eg, city)
+#localityName_default = Winterthur
+
+organizationName = Organization Name (eg, company)
+organizationName_default = Linux strongSwan
+
+0.organizationalUnitName = Organizational Unit Name (eg, section)
+0.organizationalUnitName_default = Sales
+
+#1.organizationalUnitName = Type (eg, Staff)
+#1.organizationalUnitName_default = Staff
+
+#userId = UID
+
+commonName = Common Name (eg, YOUR name)
+commonName_default = $ENV::COMMON_NAME
+commonName_max = 64
+
+#0.emailAddress = Email Address (eg, foo@bar.com)
+#0.emailAddress_min = 0
+#0.emailAddress_max = 40
+
+#1.emailAddress = Second Email Address (eg, foo@bar.com)
+#1.emailAddress_min = 0
+#1.emailAddress_max = 40
+
+####################################################################
+
+[ req_attributes ]
+
+####################################################################
+
+[ host_ext ]
+
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, keyEncipherment, keyAgreement
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer:always
+subjectAltName = DNS:$ENV::COMMON_NAME
+#extendedKeyUsage = OCSPSigner
+crlDistributionPoints = URI:http://crl.strongswan.org/sales.crl
+
+####################################################################
+
+[ user_ext ]
+
+basicConstraints = CA:FALSE
+keyUsage = digitalSignature, keyEncipherment, keyAgreement
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer:always
+subjectAltName = email:$ENV::COMMON_NAME
+crlDistributionPoints = URI:http://crl.strongswan.org/sales.crl
+
+####################################################################
+
+[ ca_ext ]
+
+basicConstraints = critical, CA:TRUE
+keyUsage = cRLSign, keyCertSign
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid, issuer:always
+
+####################################################################
+
+[ crl_ext ]
+
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+#issuerAltName = issuer:copy
+authorityKeyIdentifier = keyid:always, issuer:always
+
+# eof
diff --git a/testing/hosts/winnetou/etc/openssl/sales/salesCert.der b/testing/hosts/winnetou/etc/openssl/sales/salesCert.der
new file mode 100644
index 000000000..529fd2d45
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/salesCert.der
Binary files differ
diff --git a/testing/hosts/winnetou/etc/openssl/sales/salesCert.pem b/testing/hosts/winnetou/etc/openssl/sales/salesCert.pem
new file mode 100644
index 000000000..e50477872
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/salesCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIBDTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDMyMzA2MjkxNloXDTE0MDMyMTA2MjkxNlowSzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsTBVNhbGVz
+MREwDwYDVQQDEwhTYWxlcyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMJOTSaZjDe5UR+hJbodcE40WBxWm+r0FiD+FLc2c0hH/QcWm1Xfqnc9qaPP
+GoxO2BfwXgFEHfOdQzHGuthhsvdMPkmWP1Z3uDrwscqrmLyq4JI87exSen1ggmCV
+Eib55T4fNxrTIGJaoe6Jn9v9ZwG2B+Ur3nFA/wdckSdqJxc6XL9DKcRk3TxZtv9S
+uDftE9G787O6PJSyfyUYhldz1EZe5PTsUoAbBJ0DDXJx3562kDtfQdwezat0LAyO
+sVabYq/0G/fBZwLLer4qGF2+3CsvP7jNXnhRYeSv2+4i2mAjgbBRI1A3iqoU3Nq1
+vPAqzrekOI/RV9Hre9L1r8X1dIECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUX5sTRvkgcsgA1Yi1p0wul+oLkygwbQYD
+VR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNI
+MRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2Fu
+IFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEFBQADggEBAJ7j3X20Q8ICJ2e+iUCpVUIV
+8RudUeHt9qjSXalohuxxhegL5vu7I9Gx0H56RE4glOjLMCb1xqVZ55Odxx14pHaZ
+9iMnQFpgzi96exYAmBKYCHl4IFix2hrTqTWSJhEO+o+PXnQTgcfG43GQepk0qAQr
+iZZy8OWiUhHSJQLJtTMm4rnYjgPn+sLwx7hCPDZpHTZocETDars7wTiVkodCbeEU
+uKahAbq4b6MvvC3+7quvwoEpAEStT7+Yml+QuK/jKmhjX0hcQcw4ZWi+m32RjUAv
+xDJGEvBqV2hyrzRqwh4lVNJEBba5X+QB3N6a0So6BENaJrUM3v8EDaS2KLUWyu0=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/sales/salesKey.pem b/testing/hosts/winnetou/etc/openssl/sales/salesKey.pem
new file mode 100644
index 000000000..96dab2928
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/salesKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAwk5NJpmMN7lRH6Eluh1wTjRYHFab6vQWIP4UtzZzSEf9Bxab
+Vd+qdz2po88ajE7YF/BeAUQd851DMca62GGy90w+SZY/Vne4OvCxyquYvKrgkjzt
+7FJ6fWCCYJUSJvnlPh83GtMgYlqh7omf2/1nAbYH5SvecUD/B1yRJ2onFzpcv0Mp
+xGTdPFm2/1K4N+0T0bvzs7o8lLJ/JRiGV3PURl7k9OxSgBsEnQMNcnHfnraQO19B
+3B7Nq3QsDI6xVptir/Qb98FnAst6vioYXb7cKy8/uM1eeFFh5K/b7iLaYCOBsFEj
+UDeKqhTc2rW88CrOt6Q4j9FX0et70vWvxfV0gQIDAQABAoIBACypguJUeP52Akea
+6ukUyzOupHIfFkezQ0LiJDDYuzbqFScD80CR4MT3z35vpFKL7O/TuEfiOGA+zasr
+WtdR3akqRUb02iot6pLhsHw9ZSY4wNXcW3PuoWkgPdelbD65QhA9bJUl4lO5MW97
+Atu2K28hQD9VDhRKNFSk2liM9d9IjGeO3Eg0FnN/gDiFRHN0A5vrjqnmkUWqeJzh
+561pomDuNxyGK1NkgZ+Cc75e+KJYwLX4sSzPiyMJhTt+ERLBb1ngcXpjcRn9Kjq+
+1QCsFbeuk1F034GnMEf5b1flu6vrmpWC3wnNQLRLuYommQ1O+uQtl9be2a+olCTd
+jD8aAuECgYEA5SnJtLNPQPTj6LzIE9EGZzp78OOzJaHDNfungGAAnv8xV55ap8g1
+3KORa+QKwpCa2MgV9UKtsuql1OjfslYjFARaOp24Qh7z+GFfzsWX4V7C4zlYbGfj
+Fe905/5sNeZnZwgiwKK0kQpZ/dyS1RI1koXphVBAb+sLh9gRdm3Qw/sCgYEA2Q+B
+Rv6WpymV09Vp7c3yHDWmVwLJCoFZoWgSuu6XPUF1MuH3omYN211M3lA526OiH1ce
+wqY1jtA5vSe0w7ZVMhBYkNG6GI/aKBdMzpCoBtWYW/QZ+fl6F36DkEKPBPloPxLP
+0hR9xCsBvU/6VlSlBPGNFmsX5eNNMeHY68WdhLMCgYBlNynByBjPJdqr5wWvyvi7
+C1fGs6tiiaoA49+9kal0kF4oxuZfiMxRYWVPc+9UtC3QZb9dDlBN39nSyfBTgjwI
+EUwQ66yAd89l+wwn9Zn5jrMhTSjC6Leh7puCBBujStqM5UkEMFj0XtAUkiHAPkSv
+LLpRiXqMdBIps8MyvZohlQKBgEPB7U8mJg0klBq+YgTT5yIbNUOwIOXgnwQdossr
+s5Zxmo45r73IMccqhtZXINiJahByd623iLx+D6gWfv0hK9Mm+x6p+Xe1YBpnu5g3
+29vWTWtW9czsrcoruhIMVOzuljYqPymLL/9OlYptLu5IGgNDDBHVeG5Q2EYcBEUF
+OTi1AoGBAND42O8VS8tGsoR7QLeEwxjT8hCvSXYoTWcCVzbKjsPdGBkX2LiKwEr1
+B5pOfvNfFEgSmRm4LU5R/pG7seFQzlaAZCAavv2NUfC9F+5hwx95VHKXjZF+yE4m
+J6e8kb0p2zcyCZCC/61kztGk7FqH9sb/6E+6CDMP+1QYxytrkYYR
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/winnetou/etc/openssl/sales/serial b/testing/hosts/winnetou/etc/openssl/sales/serial
new file mode 100644
index 000000000..75016ea36
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/serial
@@ -0,0 +1 @@
+03
diff --git a/testing/hosts/winnetou/etc/openssl/sales/serial.old b/testing/hosts/winnetou/etc/openssl/sales/serial.old
new file mode 100644
index 000000000..9e22bcb8e
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/sales/serial.old
@@ -0,0 +1 @@
+02
diff --git a/testing/hosts/winnetou/etc/openssl/serial b/testing/hosts/winnetou/etc/openssl/serial
new file mode 100644
index 000000000..f599e28b8
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/serial
@@ -0,0 +1 @@
+10
diff --git a/testing/hosts/winnetou/etc/openssl/serial.old b/testing/hosts/winnetou/etc/openssl/serial.old
new file mode 100644
index 000000000..0ced2f35e
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/serial.old
@@ -0,0 +1 @@
+0F
diff --git a/testing/hosts/winnetou/etc/openssl/start-ocsp b/testing/hosts/winnetou/etc/openssl/start-ocsp
new file mode 100755
index 000000000..bdc5dab38
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/start-ocsp
@@ -0,0 +1,20 @@
+#! /bin/sh
+# start an OpenSSL-based OCSP server
+#
+# Copyright (C) 2004 Andreas Steffen
+# Zuercher Hochschule Winterthur
+#
+# 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: start-ocsp,v 1.3 2005/01/01 18:12:14 as Exp $
+
+cd /etc/openssl
+openssl ocsp -index index.txt -CA strongswanCert.pem -port 8880 -rkey ocspKey.pem -rsigner ocspCert.pem -nmin 5 < /dev/null > /dev/null 2>&1 &
diff --git a/testing/hosts/winnetou/etc/openssl/strongswanCert.der b/testing/hosts/winnetou/etc/openssl/strongswanCert.der
new file mode 100644
index 000000000..c11cf21da
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/strongswanCert.der
Binary files differ
diff --git a/testing/hosts/winnetou/etc/openssl/strongswanCert.pem b/testing/hosts/winnetou/etc/openssl/strongswanCert.pem
new file mode 100644
index 000000000..0de3b268d
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/strongswanCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMDE0NVoXDTE0MDkwODExMDE0NVowRTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9u
+Z1N3YW4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/y
+X2LqPVZuWLPIeknK86xhz6ljd3NNhC2z+P1uoCP3sBMuZiZQEjFzhnKcbXxCeo2f
+FnvhOOjrrisSuVkzuu82oxXD3fIkzuS7m9V4E10EZzgmKWIf+WuNRfbgAuUINmLc
+4YGAXBQLPyzpP4Ou48hhz/YQo58Bics6PHy5v34qCVROIXDvqhj91P8g+pS+F21/
+7P+CH2jRcVIEHZtG8M/PweTPQ95dPzpYd2Ov6SZ/U7EWmbMmT8VcUYn1aChxFmy5
+gweVBWlkH6MP+1DeE0/tL5c87xo5KCeGK8Tdqpe7sBRC4pPEEHDQciTUvkeuJ1Pr
+K+1LwdqRxo7HgMRiDw8CAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQUXafdcAZRMn7ntm2zteXgYOouTe8wbQYDVR0jBGYw
+ZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYD
+VQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3Qg
+Q0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAJrXTj5gWS37myHHhii9drYwkMFyDHS/
+lHU8rW/drcnHdus507+qUhNr9SiEAHg4Ywj895UDvT0a1sFaw44QyEa/94iKA8/n
++g5kS1IrKvWu3wu8UI3EgzChgHV3cncQlQWbK+FI9Y3Ax1O1np1r+wLptoWpKKKE
+UxsYcxP9K4Nbyeon0AIHOajUheiL3t6aRc3m0o7VU7Do6S2r+He+1Zq/nRUfFeTy
+0Atebkn8tmUpPSKWaXkmwpVNrjZ1Qu9umAU+dtJyhzL2zmnyhPC4VqpsKCOp7imy
+gKZvUIKPm1zyf4T+yjwxwkiX2xVseoM3aKswb1EoZFelHwndU7u0GQ8=
+-----END CERTIFICATE-----
diff --git a/testing/hosts/winnetou/etc/openssl/strongswanKey.pem b/testing/hosts/winnetou/etc/openssl/strongswanKey.pem
new file mode 100644
index 000000000..24de3a820
--- /dev/null
+++ b/testing/hosts/winnetou/etc/openssl/strongswanKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAv/JfYuo9Vm5Ys8h6ScrzrGHPqWN3c02ELbP4/W6gI/ewEy5m
+JlASMXOGcpxtfEJ6jZ8We+E46OuuKxK5WTO67zajFcPd8iTO5Lub1XgTXQRnOCYp
+Yh/5a41F9uAC5Qg2YtzhgYBcFAs/LOk/g67jyGHP9hCjnwGJyzo8fLm/fioJVE4h
+cO+qGP3U/yD6lL4XbX/s/4IfaNFxUgQdm0bwz8/B5M9D3l0/Olh3Y6/pJn9TsRaZ
+syZPxVxRifVoKHEWbLmDB5UFaWQfow/7UN4TT+0vlzzvGjkoJ4YrxN2ql7uwFELi
+k8QQcNByJNS+R64nU+sr7UvB2pHGjseAxGIPDwIDAQABAoIBAFaigsMWjpDQRWD/
+/5IG9Gy9yQjfSC7Wse4e6ScaI1WYmfROYPSx90QyrGBWkmQfbUk2oONRCGq41WfD
+j7zfSGRn+Lv+J9L/IhLDStbS14qITj5dmxga7mzI2udOvH+7cTC2GWJmGSlC2kTf
+EjfRXCY5X6/kWrWN8C+2HU7+V5wNfMqFhhMnG3VTgPBRWeQ8oTgYdZ4jYolOt9/t
+DhXtw/eEvfDb1Rg8BYB4wgm5PbOshh4L6nFEnemHDZltx1H5ZtAKTrds2ZYdGIM/
+3V1b7/a+aKltoA2ctsp/U6aTDHdql4VPop01MHZHZZ0bAAw9a2QirBvpjjwiDIgd
+4K0EpYECgYEA6JHP9kV3KDMbU+H5rbAcp/I81MrpZ79Pvx2zO+p6Nrieqpgxgy1U
+PjE2td3RAWiJflrz7p7Kez/Y01BWIzQXjZQ1oRTYYByVqW9O1SjyGb3TIgO4pXqb
+0yr2y+yl8c6tD7RUYVrlNhBsln8vxZ1BVssM8iFuOXdIQTN3m8HY/HECgYEA00jc
+Hd7isVsBpBRgFuAS5o+jNsAq50GA2uRo2r2/hWQSeeCgm+0553u7gd+kMrd3q37l
+1xp1qYrEaMrZmBvpb0kDkIL+aT8trE6dYiNpAOvPoSd0SADH1uFMIK9YVxtRT1W6
+BklQ1epYDd+W8Or5kxMCtgSW/1IUYGaKxdz/g38CgYEAymGIvN/6Lws6LqaopRJp
+/WP4t5vTvKpodQEdZXhH3bKOsBk8jNA3TN96ooxiQn17mG8BcpbP0KzgvBJewsej
+71oXyRLgr9JwEj+ANFIrS2c6gZEHb0jgrMPoe9B1H5UgWFguTYHRkFh+hgArzCVq
+JGMR4upghrVcNRDadrobXqECgYEAndKc6YsmFoj+TswRgsTaGXNN3YXqBlg9okRf
+tpVqTH+V9Yg/MHoheLJKPBcMFf5J28asdOME5SIM2KI9q4ud8Uy+5uGSnJdezIjk
+svv0YYXD0IMiLu62V+Ju9TNFb7uuHu7QSAXX5hJot+Q+YbODvcLDkacYC5wKMIAo
+ROhxzI0CgYAQlsrMUOJoVQ93pMBMxy4e2/m4vkchCvk9LIdnGlZt60ee6yDGasYq
+Qya5/bwekHXc6XRv+98EtBJ8My6rh6FWZutM3vUUtibWcNFVe/Fj6es+Tvv2M/DT
+fL6Ui9cY9l/CH0DyoDbOuI1ysF5+L7hxH6HoGERTazY6P8fHQgooaA==
+-----END RSA PRIVATE KEY-----
diff --git a/testing/hosts/winnetou/etc/runlevels/default/apache2 b/testing/hosts/winnetou/etc/runlevels/default/apache2
new file mode 100755
index 000000000..f54f3444a
--- /dev/null
+++ b/testing/hosts/winnetou/etc/runlevels/default/apache2
@@ -0,0 +1,78 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="${opts} reload"
+
+[ "x${SERVERROOT}" != "x" ] && APACHE2_OPTS="${APACHE2_OPTS} -d ${SERVERROOT}"
+[ "x${CONFIGFILE}" != "x" ] && APACHE2_OPTS="${APACHE2_OPTS} -f ${CONFIGFILE}"
+[ "x${STARTUPERRORLOG}" != "x" ] && APACHE2_OPTS="${APACHE2_OPTS} -E ${STARTUPERRORLOG}"
+# set a default for PIDFILE/RESTARTSTYLE for those that FAILED to follow
+# instructiosn and update the conf.d/apache2 file.
+# (bug #38787)
+[ -z "${PIDFILE}" ] && PIDFILE=/var/run/apache2.pid
+[ -z "${RESTARTSTYLE}" ] && RESTARTSTYLE="graceful"
+
+checkconfig() {
+ local myconf="/etc/apache2/conf/apache2.conf"
+ if [ "x${CONFIGFILE}" != "x" ]; then
+ if [ ${CONFIGFILE:0:1} = "/" ]; then
+ myconf="${CONFIGFILE}"
+ else
+ myconf="${SERVERROOT:-/usr/lib/apache2}/${CONFIGFILE}"
+ fi
+ fi
+ if [ ! -r "${myconf}" ]; then
+ eerror "Unable to read configuration file: ${myconf}"
+ return 1
+ fi
+ if [ -z "${PIDFILE}" ]; then
+ eerror "\$PIDFILE is not set!"
+ eerror "Did you etc-update /etc/conf.d/apache2?"
+ return 1
+ fi
+ if [ -z "${RESTARTSTYLE}" ]; then
+ eerror "\$RESTARTSTYLE is not set!"
+ eerror "Did you etc-update /etc/conf.d/apache2?"
+ return 1
+ fi
+ /usr/sbin/apache2 -t ${APACHE2_OPTS} 1>/dev/null 2>&1
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ eerror "Apache2 has detected a syntax error in your configuration files:"
+ /usr/sbin/apache2 -t ${APACHE2_OPTS}
+ fi
+ return $ret
+}
+
+depend() {
+ need net
+ use mysql dns logger netmount postgres
+ after sshd
+}
+
+start() {
+ checkconfig || return 1
+ ebegin "Starting apache2"
+ [ -f /var/log/apache2/ssl_scache ] && rm /var/log/apache2/ssl_scache
+ [ -f /usr/lib/apache2/build/envvars ] && . /usr/lib/apache2/build/envvars
+ env -i PATH=$PATH /sbin/start-stop-daemon --quiet \
+ --start --startas /usr/sbin/apache2 \
+ --pidfile ${PIDFILE} -- -k start ${APACHE2_OPTS}
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping apache2"
+ /usr/sbin/apache2ctl stop >/dev/null
+ start-stop-daemon -o --quiet --stop --pidfile ${PIDFILE}
+ eend $?
+}
+
+reload() {
+ # restarting apache2 is much easier than apache1. The server handles most of the work for us.
+ # see http://httpd.apache.org/docs-2.0/stopping.html for more details
+ ebegin "Restarting apache2"
+ /usr/sbin/apache2 ${APACHE2_OPTS} -k ${RESTARTSTYLE}
+ eend $?
+}
diff --git a/testing/hosts/winnetou/etc/runlevels/default/net.eth0 b/testing/hosts/winnetou/etc/runlevels/default/net.eth0
new file mode 100755
index 000000000..fa1200242
--- /dev/null
+++ b/testing/hosts/winnetou/etc/runlevels/default/net.eth0
@@ -0,0 +1,314 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+
+#NB: Config is in /etc/conf.d/net
+
+if [[ -n $NET_DEBUG ]]; then
+ set -x
+ devnull=/dev/stderr
+else
+ devnull=/dev/null
+fi
+
+# For pcmcia users. note that pcmcia must be added to the same
+# runlevel as the net.* script that needs it.
+depend() {
+ use hotplug pcmcia
+}
+
+checkconfig() {
+ if [[ -z "${ifconfig_IFACE}" ]]; then
+ eerror "Please make sure that /etc/conf.d/net has \$ifconfig_$IFACE set"
+ eerror "(or \$iface_$IFACE for old-style configuration)"
+ return 1
+ fi
+ if [[ -n "${vlans_IFACE}" && ! -x /sbin/vconfig ]]; then
+ eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
+ return 1
+ fi
+}
+
+# Fix bug 50039 (init.d/net.eth0 localization)
+# Some other commands in this script might need to be wrapped, but
+# we'll get them one-by-one. Note that LC_ALL trumps LC_anything_else
+# according to locale(7)
+ifconfig() {
+ LC_ALL=C /sbin/ifconfig "$@"
+}
+
+# setup_vars: setup variables based on $1 and content of /etc/conf.d/net
+# The following variables are set, which should be declared local by
+# the calling routine.
+# status_IFACE (up or '')
+# vlans_IFACE (space-separated list)
+# ifconfig_IFACE (array of ifconfig lines, replaces iface_IFACE)
+# dhcpcd_IFACE (command-line args for dhcpcd)
+# routes_IFACE (array of route lines)
+# inet6_IFACE (array of inet6 lines)
+# ifconfig_fallback_IFACE (fallback ifconfig if dhcp fails)
+setup_vars() {
+ local i iface="${1//\./_}"
+
+ status_IFACE="$(ifconfig ${1} 2>${devnull} | gawk '$1 == "UP" {print "up"}')"
+ eval vlans_IFACE=\"\$\{iface_${iface}_vlans\}\"
+ eval ifconfig_IFACE=( \"\$\{ifconfig_$iface\[@\]\}\" )
+ eval dhcpcd_IFACE=\"\$\{dhcpcd_$iface\}\"
+ eval routes_IFACE=( \"\$\{routes_$iface\[@\]\}\" )
+ eval inet6_IFACE=( \"\$\{inet6_$iface\[@\]\}\" )
+ eval ifconfig_fallback_IFACE=( \"\$\{ifconfig_fallback_$iface\[@\]\}\" )
+
+ # BACKWARD COMPATIBILITY: populate the ifconfig_IFACE array
+ # if iface_IFACE is set (fex. iface_eth0 instead of ifconfig_eth0)
+ eval local iface_IFACE=\"\$\{iface_$iface\}\"
+ if [[ -n ${iface_IFACE} && -z ${ifconfig_IFACE} ]]; then
+ # Make sure these get evaluated as arrays
+ local -a aliases broadcasts netmasks
+
+ # Start with the primary interface
+ ifconfig_IFACE=( "${iface_IFACE}" )
+
+ # ..then add aliases
+ eval aliases=( \$\{alias_$iface\} )
+ eval broadcasts=( \$\{broadcast_$iface\} )
+ eval netmasks=( \$\{netmask_$iface\} )
+ for ((i = 0; i < ${#aliases[@]}; i = i + 1)); do
+ ifconfig_IFACE[i+1]="${aliases[i]} ${broadcasts[i]:+broadcast ${broadcasts[i]}} ${netmasks[i]:+netmask ${netmasks[i]}}"
+ done
+ fi
+
+ # BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
+ if [[ ${#inet6_IFACE[@]} == 1 && ${inet6_IFACE} == *' '* ]]; then
+ inet6_IFACE=( ${inet6_IFACE} )
+ fi
+}
+
+iface_start() {
+ local IFACE=${1} i x retval
+ checkconfig || return 1
+
+ if [[ ${ifconfig_IFACE} != dhcp ]]; then
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Bringing ${IFACE} up (${i})"
+ else
+ ebegin "Bringing ${IFACE} up"
+ fi
+ # ifconfig does not always return failure ..
+ ifconfig ${IFACE} ${ifconfig_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ # Check that eth0 was not brought up by the kernel ...
+ if [[ ${status_IFACE} == up ]]; then
+ einfo "Keeping kernel configuration for ${IFACE}"
+ else
+ ebegin "Bringing ${IFACE} up via DHCP"
+ /sbin/dhcpcd ${dhcpcd_IFACE} ${IFACE}
+ retval=$?
+ eend $retval
+ if [[ $retval == 0 ]]; then
+ # DHCP succeeded, show address retrieved
+ i=$(ifconfig ${IFACE} | grep -m1 -o 'inet addr:[^ ]*' |
+ cut -d: -f2)
+ [[ -n ${i} ]] && einfo " ${IFACE} received address ${i}"
+ elif [[ -n "${ifconfig_fallback_IFACE}" ]]; then
+ # DHCP failed, try fallback.
+ # Show the address, but catch if this interface will be inet6 only
+ i=${ifconfig_fallback_IFACE%% *}
+ if [[ ${i} == *.*.*.* ]]; then
+ ebegin "Using fallback configuration (${i}) for ${IFACE}"
+ else
+ ebegin "Using fallback configuration for ${IFACE}"
+ fi
+ ifconfig ${IFACE} ${ifconfig_fallback_IFACE} >${devnull} && \
+ ifconfig ${IFACE} up &>${devnull}
+ eend $? || return $?
+ else
+ return $retval
+ fi
+ fi
+ fi
+
+ if [[ ${#ifconfig_IFACE[@]} -gt 1 ]]; then
+ einfo " Adding aliases"
+ for ((i = 1; i < ${#ifconfig_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE}:${i} (${ifconfig_IFACE[i]%% *})"
+ ifconfig ${IFACE}:${i} ${ifconfig_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ if [[ -n ${inet6_IFACE} ]]; then
+ einfo " Adding inet6 addresses"
+ for ((i = 0; i < ${#inet6_IFACE[@]}; i = i + 1)); do
+ ebegin " ${IFACE} inet6 add ${inet6_IFACE[i]}"
+ ifconfig ${IFACE} inet6 add ${inet6_IFACE[i]} >${devnull}
+ eend $?
+ done
+ fi
+
+ # Set static routes
+ if [[ -n ${routes_IFACE} ]]; then
+ einfo " Adding routes"
+ for ((i = 0; i < ${#routes_IFACE[@]}; i = i + 1)); do
+ ebegin " ${routes_IFACE[i]}"
+ /sbin/route add ${routes_IFACE[i]}
+ eend $?
+ done
+ fi
+
+ # Set default route if applicable to this interface
+ if [[ ${gateway} == ${IFACE}/* ]]; then
+ local ogw=$(/bin/netstat -rn | awk '$1 == "0.0.0.0" {print $2}')
+ local gw=${gateway#*/}
+ if [[ ${ogw} != ${gw} ]]; then
+ ebegin " Setting default gateway ($gw)"
+
+ # First delete any existing route if it was setup by kernel...
+ /sbin/route del default dev ${IFACE} &>${devnull}
+
+ # Second delete old gateway if it was set...
+ /sbin/route del default gw ${ogw} &>${devnull}
+
+ # Third add our new default gateway
+ /sbin/route add default gw ${gw} >${devnull}
+ eend $? || {
+ true # need to have some command in here
+ # Note: This originally called stop, which is obviously
+ # wrong since it's calling with a local version of IFACE.
+ # The below code works correctly to abort configuration of
+ # the interface, but is commented because we're assuming
+ # that default route failure should not cause the interface
+ # to be unconfigured.
+ #local error=$?
+ #ewarn "Aborting configuration of ${IFACE}"
+ #iface_stop ${IFACE}
+ #return ${error}
+ }
+ fi
+ fi
+
+ # Enabling rp_filter causes wacky packets to be auto-dropped by
+ # the kernel. Note that we only do this if it is not set via
+ # /etc/sysctl.conf ...
+ if [[ -e /proc/sys/net/ipv4/conf/${IFACE}/rp_filter && \
+ -z "$(grep -s '^[^#]*rp_filter' /etc/sysctl.conf)" ]]; then
+ echo -n 1 > /proc/sys/net/ipv4/conf/${IFACE}/rp_filter
+ fi
+}
+
+# iface_stop: bring down an interface. Don't trust information in
+# /etc/conf.d/net since the configuration might have changed since
+# iface_start ran. Instead query for current configuration and bring
+# down the interface.
+iface_stop() {
+ local IFACE=${1} i x aliases inet6 count
+
+ # Try to do a simple down (no aliases, no inet6, no dhcp)
+ aliases="$(ifconfig | grep -o "^$IFACE:[0-9]*" | tac)"
+ inet6="$(ifconfig ${IFACE} | awk '$1 == "inet6" {print $2}')"
+ if [[ -z ${aliases} && -z ${inet6} && ! -e /var/run/dhcpcd-${IFACE}.pid ]]; then
+ ebegin "Bringing ${IFACE} down"
+ ifconfig ${IFACE} down &>/dev/null
+ eend 0
+ return 0
+ fi
+
+ einfo "Bringing ${IFACE} down"
+
+ # Stop aliases before primary interface.
+ # Note this must be done in reverse order, since ifconfig eth0:1
+ # will remove eth0:2, etc. It might be sufficient to simply remove
+ # the base interface but we're being safe here.
+ for i in ${aliases} ${IFACE}; do
+
+ # Delete all the inet6 addresses for this interface
+ inet6="$(ifconfig ${i} | awk '$1 == "inet6" {print $3}')"
+ if [[ -n ${inet6} ]]; then
+ einfo " Removing inet6 addresses"
+ for x in ${inet6}; do
+ ebegin " ${IFACE} inet6 del ${x}"
+ ifconfig ${i} inet6 del ${x}
+ eend $?
+ done
+ fi
+
+ # Stop DHCP (should be N/A for aliases)
+ # Don't trust current configuration... investigate ourselves
+ if /sbin/dhcpcd -z ${i} &>${devnull}; then
+ ebegin " Releasing DHCP lease for ${IFACE}"
+ for ((count = 0; count < 9; count = count + 1)); do
+ /sbin/dhcpcd -z ${i} &>${devnull} || break
+ sleep 1
+ done
+ [[ ${count} -lt 9 ]]
+ eend $? "Timed out"
+ fi
+ ebegin " Stopping ${i}"
+ ifconfig ${i} down &>${devnull}
+ eend 0
+ done
+
+ return 0
+}
+
+start() {
+ # These variables are set by setup_vars
+ local status_IFACE vlans_IFACE dhcpcd_IFACE
+ local -a ifconfig_IFACE routes_IFACE inet6_IFACE
+
+ # Call user-defined preup function if it exists
+ if [[ $(type -t preup) == function ]]; then
+ einfo "Running preup function"
+ preup ${IFACE} || {
+ eerror "preup ${IFACE} failed"
+ return 1
+ }
+ fi
+
+ # Start the primary interface and aliases
+ setup_vars ${IFACE}
+ iface_start ${IFACE} || return 1
+
+ # Start vlans
+ local vlan
+ for vlan in ${vlans_IFACE}; do
+ /sbin/vconfig add ${IFACE} ${vlan} >${devnull}
+ setup_vars ${IFACE}.${vlan}
+ iface_start ${IFACE}.${vlan}
+ done
+
+ # Call user-defined postup function if it exists
+ if [[ $(type -t postup) == function ]]; then
+ einfo "Running postup function"
+ postup ${IFACE}
+ fi
+}
+
+stop() {
+ # Call user-defined predown function if it exists
+ if [[ $(type -t predown) == function ]]; then
+ einfo "Running predown function"
+ predown ${IFACE}
+ fi
+
+ # Don't depend on setup_vars since configuration might have changed.
+ # Investigate current configuration instead.
+ local vlan
+ for vlan in $(ifconfig | grep -o "^${IFACE}\.[^ ]*"); do
+ iface_stop ${vlan}
+ /sbin/vconfig rem ${vlan} >${devnull}
+ done
+
+ iface_stop ${IFACE} || return 1 # always succeeds, btw
+
+ # Call user-defined postdown function if it exists
+ if [[ $(type -t postdown) == function ]]; then
+ einfo "Running postdown function"
+ postdown ${IFACE}
+ fi
+}
+
+# vim:ts=4
diff --git a/testing/images/a-m-c-w-d.png b/testing/images/a-m-c-w-d.png
new file mode 100755
index 000000000..f0d758021
--- /dev/null
+++ b/testing/images/a-m-c-w-d.png
Binary files differ
diff --git a/testing/images/a-m-c-w.png b/testing/images/a-m-c-w.png
new file mode 100755
index 000000000..0e8ec3a74
--- /dev/null
+++ b/testing/images/a-m-c-w.png
Binary files differ
diff --git a/testing/images/a-m-c.png b/testing/images/a-m-c.png
new file mode 100644
index 000000000..538929225
--- /dev/null
+++ b/testing/images/a-m-c.png
Binary files differ
diff --git a/testing/images/a-m-w-s-b.png b/testing/images/a-m-w-s-b.png
new file mode 100755
index 000000000..e31fe5e9b
--- /dev/null
+++ b/testing/images/a-m-w-s-b.png
Binary files differ
diff --git a/testing/images/a-v-m-c-w-d.png b/testing/images/a-v-m-c-w-d.png
new file mode 100755
index 000000000..1096af264
--- /dev/null
+++ b/testing/images/a-v-m-c-w-d.png
Binary files differ
diff --git a/testing/images/a-v-m-w-s-b.png b/testing/images/a-v-m-w-s-b.png
new file mode 100755
index 000000000..53eafba3b
--- /dev/null
+++ b/testing/images/a-v-m-w-s-b.png
Binary files differ
diff --git a/testing/images/m-c-w.png b/testing/images/m-c-w.png
new file mode 100755
index 000000000..066a8f8c6
--- /dev/null
+++ b/testing/images/m-c-w.png
Binary files differ
diff --git a/testing/images/m-w-s.png b/testing/images/m-w-s.png
new file mode 100755
index 000000000..5f1aee2aa
--- /dev/null
+++ b/testing/images/m-w-s.png
Binary files differ
diff --git a/testing/images/umlArchitecture_large.png b/testing/images/umlArchitecture_large.png
new file mode 100644
index 000000000..4588603e6
--- /dev/null
+++ b/testing/images/umlArchitecture_large.png
Binary files differ
diff --git a/testing/images/umlArchitecture_small.png b/testing/images/umlArchitecture_small.png
new file mode 100644
index 000000000..2328f7554
--- /dev/null
+++ b/testing/images/umlArchitecture_small.png
Binary files differ
diff --git a/testing/make-testing b/testing/make-testing
new file mode 100755
index 000000000..cf77a86d9
--- /dev/null
+++ b/testing/make-testing
@@ -0,0 +1,89 @@
+#!/bin/bash
+# Create the strongSwan UML testing environment
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: make-testing,v 1.4 2005/02/14 15:27:42 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/scripts/function.sh
+
+[ -f $DIR/testing.conf ] || die "!! Configuration file 'testing.conf' not found."
+
+source $DIR/testing.conf
+
+if [ "$#" -eq 0 ]
+then
+ HOSTS=$STRONGSWANHOSTS
+else
+ HOSTS=$*
+fi
+
+##########################################################################
+# build the UML kernel based on a vanilla kernel form kernel.org
+# and a matching UML patch from user-mode-linux.sourceforge.net
+#
+if [ $ENABLE_BUILD_UMLKERNEL = "yes" ]
+then
+ cecho "Building uml kernel (scripts/build-umlkernel)"
+ $DIR/scripts/build-umlkernel
+fi
+
+##########################################################################
+# Adding the ssh RSA public keys to ~/.ssh/known_hosts
+#
+if [ $ENABLE_BUILD_SSHKEYS = "yes" ]
+then
+ cecho "Adding ssh public keys of the uml instances (scripts/build-sshkeys)"
+ $DIR/scripts/build-sshkeys
+fi
+
+##########################################################################
+# copy the default UML host configurations to $BUILDDIR
+# and assign actual IP addresses to the UML hosts
+#
+if [ $ENABLE_BUILD_HOSTCONFIG = "yes" ]
+then
+ cecho "Building host configurations (scripts/build-hostconfig)"
+ $DIR/scripts/build-hostconfig
+fi
+
+##########################################################################
+# build a generic UML root file system based on a Gentoo root file system.
+# compile and install a specified strongSwan release into the file system.
+#
+if [ $ENABLE_BUILD_UMLROOTFS = "yes" ]
+then
+ cecho "Building uml root file system with strongSwan (scripts/build-umlrootfs)"
+ $DIR/scripts/build-umlrootfs
+fi
+
+##########################################################################
+# Creating the root filesystems for the specified UML instances
+#
+if [ $ENABLE_BUILD_UMLHOSTFS = "yes" ]
+then
+ cecho "Building uml host root file systems (scripts/build-umlhostfs)"
+ $DIR/scripts/build-umlhostfs $HOSTS
+fi
+
+##########################################################################
+# Start up the UML switches and designated UML instances
+#
+if [ $ENABLE_START_TESTING = "yes" ]
+then
+ cecho "Starting the uml switches and instances (start-testing)"
+ $DIR/start-testing $HOSTS
+fi
diff --git a/testing/scripts/build-hostconfig b/testing/scripts/build-hostconfig
new file mode 100755
index 000000000..0df8861c8
--- /dev/null
+++ b/testing/scripts/build-hostconfig
@@ -0,0 +1,103 @@
+#!/bin/bash
+# build the hosts configuration directory with the actual IP addresses
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: build-hostconfig,v 1.3 2005/02/08 10:40:48 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "!! Configuration file 'testing.conf' not found"
+[ -d $DIR/../hosts ] || die "!! Directory 'hosts' not found"
+
+source $DIR/../testing.conf
+
+if [ ! -d $BUILDDIR ]
+then
+ cecho " * Creating directory '$BUILDDIR'"
+ mkdir $BUILDDIR
+fi
+
+########################################
+# copy default host configs to $BUILDDIR
+#
+
+HOSTCONFIGDIR=${BUILDDIR}/hosts
+
+if [ -d $HOSTCONFIGDIR ]
+then
+ rm -r $HOSTCONFIGDIR
+fi
+
+mkdir $HOSTCONFIGDIR
+cp -rfp ${UMLTESTDIR}/testing/hosts $BUILDDIR
+
+cecho " * Copied default host config directory to '$HOSTCONFIGDIR'"
+
+########################################
+# assign IP for each host to hostname
+#
+
+cecho-n " * Generate default config for.."
+
+HOSTIP=`ifconfig eth0 |grep inet |sed -e "s/.*inet addr://" -e "s/ Bcast.*//"`
+
+for host in $STRONGSWANHOSTS
+do
+ cecho-n "${host}.."
+ eval ip_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+
+ [ "`eval echo \\\$ip_${host}`" != "$HOSTIP" ] || die "$host has the same IP as eth0 (Host)! Please change that."
+
+ case $host in
+ moon)
+ eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+ [ "`eval echo \\\$ip1_${host}`" != "$HOSTIP" ] || die "eth1 of $host has the same IP as eth0 (Host)! Please change that."
+ searchandreplace PH_IP_MOON $ip_moon $HOSTCONFIGDIR
+ searchandreplace PH_IP1_MOON $ip1_moon $HOSTCONFIGDIR
+ ;;
+ sun)
+ eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+ [ "`eval echo \\\$ip1_${host}`" != "$HOSTIP" ] || die "eth1 of $host has the same IP as eth0 (Host)! Please change that."
+ searchandreplace PH_IP_SUN $ip_sun $HOSTCONFIGDIR
+ searchandreplace PH_IP1_SUN $ip1_sun $HOSTCONFIGDIR
+ ;;
+ alice)
+ searchandreplace PH_IP_ALICE $ip_alice $HOSTCONFIGDIR
+ ;;
+ venus)
+ searchandreplace PH_IP_VENUS $ip_venus $HOSTCONFIGDIR
+ ;;
+ bob)
+ searchandreplace PH_IP_BOB $ip_bob $HOSTCONFIGDIR
+ ;;
+ carol)
+ eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+ searchandreplace PH_IP_CAROL $ip_carol $HOSTCONFIGDIR
+ searchandreplace PH_IP1_CAROL $ip1_carol $HOSTCONFIGDIR
+ ;;
+ dave)
+ eval ip1_${host}="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $2 }' | awk '{ print $1 }'`"
+ searchandreplace PH_IP_DAVE $ip_dave $HOSTCONFIGDIR
+ searchandreplace PH_IP1_DAVE $ip1_dave $HOSTCONFIGDIR
+ ;;
+ winnetou)
+ searchandreplace PH_IP_WINNETOU $ip_winnetou $HOSTCONFIGDIR
+ ;;
+ esac
+done
+
+cecho "done"
diff --git a/testing/scripts/build-sshkeys b/testing/scripts/build-sshkeys
new file mode 100755
index 000000000..f4d584d6b
--- /dev/null
+++ b/testing/scripts/build-sshkeys
@@ -0,0 +1,88 @@
+#!/bin/bash
+# build the hosts configuration directory with the actual IP addresses
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: build-sshkeys,v 1.2 2005/02/15 14:12:16 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "!! Configuration file 'testing.conf' not found"
+[ -d $DIR/../hosts ] || die "!! Directory 'hosts' not found"
+
+source $DIR/../testing.conf
+
+if [ ! -d $BUILDDIR ]
+then
+ cecho " * Creating directory '$BUILDDIR'"
+ mkdir $BUILDDIR
+fi
+
+LOGFILE=${BUILDDIR}/testing.log
+
+if [ ! -f $LOGFILE ]
+then
+ cecho-n " * Logfile '$LOGFILE' does not exist..creating.."
+ touch $LOGFILE
+ cecho "done"
+fi
+
+if [ ! -d ~/.ssh ]
+then
+ cecho-n " * Creating directory '~/.ssh'.."
+ mkdir ~/.ssh
+ cecho "done"
+fi
+
+if [ -f ~/.ssh/known_hosts ]
+then
+ cecho-n " * Backing up ~/.ssh/known_hosts to '~/.ssh/known_hosts.before_uml'.."
+ cp -fp ~/.ssh/known_hosts ~/.ssh/known_hosts.before_uml
+ cecho "done"
+else
+ cecho-n " * Creating '~/.ssh/known_hosts'"
+ touch ~/.ssh/known_hosts
+ cecho "done"
+fi
+
+for host in $HOSTNAMEIPS
+do
+ HOSTNAME=`echo $host | awk -F : '{ print $1 }'`
+ IP=`echo $host | awk -F : '{ print $2 }'`
+ if [ `grep "$IP " ~/.ssh/known_hosts | wc -l` != "0" ]
+ then
+ cecho "!! Warning: An entry exists for the following IP address: $IP"
+ else
+ cecho-n " * Adding uml host $HOSTNAME ($IP) to '~/.ssh/known_hosts'.."
+ echo "$HOSTNAME,$IP `cat $DIR/../hosts/ssh_host_rsa_key.pub`" >> ~/.ssh/known_hosts
+ cecho "done"
+ fi
+done
+
+#####################################
+# preparing ssh for PK authentication
+#
+
+cecho-n " * Checking for ssh rsa key '~/.ssh/id_rsa.pub'.."
+if [ -f ~/.ssh/id_rsa.pub ]
+then
+ cecho "already exists"
+else
+ cecho "not found"
+ cecho-n " * Generating ssh rsa key pair.."
+ echo "" | ssh-keygen -N "" -t rsa -f ~/.ssh/id_rsa >> $LOGFILE 2>&1
+ cecho "done"
+fi
diff --git a/testing/scripts/build-umlhostfs b/testing/scripts/build-umlhostfs
new file mode 100755
index 000000000..e77bfc025
--- /dev/null
+++ b/testing/scripts/build-umlhostfs
@@ -0,0 +1,78 @@
+#!/bin/bash
+# create UML host file systems
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: build-umlhostfs,v 1.3 2006/03/30 21:20:27 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "!! Configuration file 'testing.conf' not found."
+
+source $DIR/../testing.conf
+
+cd $BUILDDIR/root-fs
+
+[ -f gentoo-fs ] || die "!! Root file system 'gentoo-fs' not found."
+
+if [ ! -d $BUILDDIR ]
+then
+ cecho-n " * Directory '$BUILDDIR' does not exist..creating.."
+ mkdir $BUILDDIR
+ cecho "done"
+fi
+
+LOGFILE=${BUILDDIR}/testing.log
+
+if [ ! -f $LOGFILE ]
+then
+ cecho-n " * Logfile '$LOGFILE' does not exist..creating.."
+ touch $LOGFILE
+ cecho "done"
+fi
+
+LOOPDIR=loop
+
+if [ ! -d $LOOPDIR ]
+then
+ mkdir $LOOPDIR
+fi
+
+cecho-n " * Creating root filesystem for.."
+
+if [ "$#" -eq 0 ]
+then
+ HOSTS=$STRONGSWANHOSTS
+else
+ HOSTS=$*
+fi
+
+for host in $HOSTS
+do
+ cecho-n "$host.."
+ cp gentoo-fs gentoo-fs-$host
+ mount -o loop gentoo-fs-$host $LOOPDIR
+ cp -rfp $BUILDDIR/hosts/${host}/etc $LOOPDIR
+ if [ "$host" = "winnetou" ]
+ then
+ cp -rfp $UMLTESTDIR/testing/images $LOOPDIR/var/www/localhost/htdocs
+ chroot $LOOPDIR /etc/openssl/generate-crl >> $LOGFILE 2>&1
+ fi
+ chroot $LOOPDIR /etc/init.d/depscan.sh --update >> $LOGFILE 2>&1
+ umount $LOOPDIR
+done
+
+cecho "done"
diff --git a/testing/scripts/build-umlkernel b/testing/scripts/build-umlkernel
new file mode 100755
index 000000000..074d7847a
--- /dev/null
+++ b/testing/scripts/build-umlkernel
@@ -0,0 +1,134 @@
+#!/bin/bash
+# build an UML kernel based on a vanilla kernel and UML patch
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: build-umlkernel,v 1.2 2005/01/09 21:54:25 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "configuration file 'testing.conf' not found"
+
+source $DIR/../testing.conf
+
+cecho-n " * Looking for kernel at '$KERNEL'.."
+if [ -f "${KERNEL}" ]
+then
+ cecho "found it"
+ KERNELVERSION=`basename $KERNEL .tar.bz2 | sed -e 's/linux-//'`
+ cecho " * Kernel version is $KERNELVERSION"
+else
+ cecho "none"
+ exit
+fi
+
+if [ ${UMLPATCH} ]
+then
+ cecho-n " * Looking for uml patch at '$UMLPATCH'.."
+ if [ -f "${UMLPATCH}" ]
+ then
+ cecho "found it"
+ else
+ cecho "none"
+ exit
+ fi
+fi
+
+cecho-n " * Looking for kernel config at '$KERNELCONFIG'.."
+if [ -f "${KERNEL}" ]
+then
+ cecho "found it"
+else
+ cecho "none"
+ exit
+fi
+
+#######################################################
+# unpack kernel and create symlink
+#
+
+if [ ! -d $BUILDDIR ]
+then
+ cecho " * Creating directory '$BUILDDIR'"
+ mkdir $BUILDDIR
+fi
+
+cecho " * Changing to directory '$BUILDDIR'"
+cd $BUILDDIR
+
+LOGFILE=${BUILDDIR}/testing.log
+
+if [ ! -f $LOGFILE ]
+then
+ cecho-n " * Logfile '$LOGFILE' does not exist..creating.."
+ touch $LOGFILE
+ cecho "done"
+fi
+
+cecho-n " * Unpacking kernel.."
+tar xjf $KERNEL >> $LOGFILE 2>&1
+cecho "done"
+
+KERNELDIR=${BUILDDIR}/linux-${KERNELVERSION}
+
+if [ -d $KERNELDIR ]
+then
+ cecho " * Kernel directory is '$KERNELDIR'"
+ cecho " * Creating symlink 'linux'"
+ if [ -d linux ]
+ then
+ rm linux
+ fi
+ ln -s linux-${KERNELVERSION} linux
+else
+ cecho "!! Kernel directory '$KERNELDIR' can not be found"
+ exit
+fi
+
+#######################################################
+# patch kernel
+#
+
+cecho " * Changing to directory '$KERNELDIR'"
+cd $KERNELDIR
+
+if [ $UMLPATCH ]
+then
+ cecho-n " * Applying uml patch.."
+ bzcat $UMLPATCH | patch -p1 >> $LOGFILE 2>&1
+ cecho "done"
+fi
+
+#######################################################
+# copy our default .config to linux and build kernel
+#
+
+cp $KERNELCONFIG .config
+
+cecho "!!"
+cecho "!! Making .config for kernel. You might be prompted for new parameters!"
+cecho "!!"
+make oldconfig ARCH=um >> $LOGFILE 2>&1
+
+cecho-n " * Now compiling uml kernel.."
+make linux ARCH=um >> $LOGFILE 2>&1
+cecho "done"
+
+cecho-n " * Copying uml kernel to '${BUILDDIR}/linux-uml-${KERNELVERSION}'.."
+mv linux ${BUILDDIR}/linux-uml-${KERNELVERSION}
+cecho "done"
+
+
diff --git a/testing/scripts/build-umlrootfs b/testing/scripts/build-umlrootfs
new file mode 100755
index 000000000..ba103838f
--- /dev/null
+++ b/testing/scripts/build-umlrootfs
@@ -0,0 +1,174 @@
+#!/bin/bash
+# Create UML root filesystem
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: build-umlrootfs,v 1.11 2006/01/08 22:29:56 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "!! Configuration file 'testing.conf' not found"
+
+source $DIR/../testing.conf
+
+STRONGSWANVERSION=`basename $STRONGSWAN .tar.bz2`
+
+cecho-n " * Looking for strongSwan at '$STRONGSWAN'.."
+if [ -f "$STRONGSWAN" ]
+then
+ cecho "found it"
+ cecho " * strongSwan version is '$STRONGSWANVERSION'"
+else
+ cecho "none"
+ exit
+fi
+
+cecho-n " * Looking for gentoo root filesystem at '$ROOTFS'.."
+if [ -f "$ROOTFS" ]
+then
+ cecho "found it"
+else
+ cecho "none"
+ exit
+fi
+
+[ -d $BUILDDIR ] || die "!! Directory '$BUILDDIR' does not exist"
+
+HOSTCONFIGDIR=$BUILDDIR/hosts
+
+[ -d $HOSTCONFIGDIR ] || die "!! Directory '$HOSTCONFIGDIR' does not exist"
+
+LOGFILE=$BUILDDIR/testing.log
+
+if [ ! -f $LOGFILE ]
+then
+ cecho-n " * Logfile '$LOGFILE' does not exist..creating.."
+ touch $LOGFILE
+ cecho "done"
+fi
+
+ROOTFSDIR=$BUILDDIR/root-fs
+
+if [ ! -d $ROOTFSDIR ]
+then
+ cecho-n " * Root file system directory '$ROOTFSDIR' does not exist..creating.."
+ mkdir $ROOTFSDIR
+ cecho "done"
+fi
+
+cd $ROOTFSDIR
+
+LOOPDIR=$ROOTFSDIR/loop
+
+if [ ! -d $LOOPDIR ]
+then
+ mkdir $LOOPDIR
+fi
+
+######################################################
+# creating reiser-based uml root filesystem
+#
+
+cecho-n " * Building basic root filesystem (gentoo).."
+dd if=/dev/zero of=gentoo-fs count=$ROOTFSSIZE bs=1M >> $LOGFILE 2>&1
+mkreiserfs -q -f gentoo-fs >> $LOGFILE 2>&1
+mount -o loop gentoo-fs $LOOPDIR >> $LOGFILE 2>&1
+tar xjpf $ROOTFS -C $LOOPDIR >> $LOGFILE 2>&1
+cecho "done"
+
+
+######################################################
+# copying default /etc/hosts to the root filesystem
+#
+cecho " * Copying '$HOSTCONFIGDIR/default/etc/hosts' to the root filesystem"
+cp -fp $HOSTCONFIGDIR/default/etc/hosts $LOOPDIR/etc/hosts
+
+#
+#####################################################
+# extracting strongSwan into the root filesystem
+#
+
+cecho " * Extracting strongSwan into the root filesystem"
+tar xjf $STRONGSWAN -C $LOOPDIR/root >> $LOGFILE 2>&1
+
+
+######################################################
+# installing strongSwan and setting the local timezone
+#
+
+INSTALLSHELL=${LOOPDIR}/install.sh
+
+cecho " * Preparing strongSwan installation script"
+echo "ln -sf /usr/share/zoneinfo/${TZUML} /etc/localtime" >> $INSTALLSHELL
+
+if [ "$USE_LIBCURL" = "yes" ]
+then
+ echo "export USE_LIBCURL=true" >> $INSTALLSHELL
+fi
+
+if [ "$USE_LDAP" = "yes" ]
+then
+ echo "export USE_LDAP=true" >> $INSTALLSHELL
+fi
+
+echo "export USERCOMPILE=\'-DRANDOM_DEVICE=\\\"/dev/urandom\\\"\'" >> $INSTALLSHELL
+echo "cd /root/${STRONGSWANVERSION}" >> $INSTALLSHELL
+echo "make programs" >> $INSTALLSHELL
+echo "make install" >> $INSTALLSHELL
+
+cecho-n " * Compiling $STRONGSWANVERSION within the root file system as chroot.."
+chroot $LOOPDIR /bin/bash /install.sh >> $LOGFILE 2>&1
+cecho "done"
+
+rm -f $INSTALLSHELL
+
+
+######################################################
+# copying the host's ssh public key
+#
+
+if [ ! -d $LOOPDIR/root/.ssh ]
+then
+ mkdir $LOOPDIR/root/.ssh
+fi
+cp ~/.ssh/id_rsa.pub $LOOPDIR/root/.ssh/authorized_keys
+
+######################################################
+# setup public key based login among all hosts
+#
+cp $LOOPDIR/etc/ssh/ssh_host_rsa_key $LOOPDIR/root/.ssh/id_rsa
+
+for host in $STRONGSWANHOSTS
+do
+ eval ip="`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+ echo "$host,$ip `cat $HOSTCONFIGDIR/ssh_host_rsa_key.pub`" >> $LOOPDIR/root/.ssh/known_hosts
+ echo "`cat $HOSTCONFIGDIR/ssh_host_rsa_key.pub` root@$host" >> $LOOPDIR/root/.ssh/authorized_keys
+done
+
+######################################################
+# defining an empty modules.dep
+#
+
+if [ $UMLPATCH ]
+then
+ mkdir $LOOPDIR/lib/modules/`basename $UMLPATCH .bz2 | sed s/uml-patch-//`um
+ touch $LOOPDIR/lib/modules/`basename $UMLPATCH .bz2 | sed s/uml-patch-//`um/modules.dep
+else
+ mkdir $LOOPDIR/lib/modules/$KERNELVERSION
+ touch $LOOPDIR/lib/modules/$KERNELVERSION/modules.dep
+fi
+
+umount $LOOPDIR
diff --git a/testing/scripts/function.sh b/testing/scripts/function.sh
new file mode 100755
index 000000000..22a79698d
--- /dev/null
+++ b/testing/scripts/function.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+# provides some general-purpose script functions
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: function.sh,v 1.3 2005/02/16 22:20:52 as Exp $
+
+
+############################################
+# print output in color
+#
+
+function cecho {
+ echo -e "\033\13301;31m$1\033\1330m"
+}
+
+function cecho-n {
+ echo -en "\033\13301;31m$1\033\1330m"
+}
+
+
+#############################################
+# output all args to stderr and exit with
+# return code 1
+#
+
+die() {
+ echo $* 1>&2
+ exit 1
+}
+
+#############################################
+# search and replace strings throughout a
+# whole directory
+#
+
+function searchandreplace {
+
+ SEARCHSTRING="$1"
+ REPLACESTRING="$2"
+ DESTDIR="$3"
+
+ [ -d "$DESTDIR" ] || die "$DESTDIR is not a directory!"
+
+
+ #########################
+ # create a temporary file
+ #
+
+ TMPFILE="/tmp/sr.$$"
+
+
+ ###########################################
+ # search and replace in each found file the
+ # given string
+ #
+
+ for eachfoundfile in `find $DESTDIR -type f`
+ do
+ sed -e "s/$SEARCHSTRING/$REPLACESTRING/g" "$eachfoundfile" > "$TMPFILE"
+ cp -f "$TMPFILE" "$eachfoundfile"
+ done
+
+
+ ###########################
+ # delete the temporary file
+ #
+
+ rm -f "$TMPFILE"
+
+}
diff --git a/testing/scripts/kstart-umls b/testing/scripts/kstart-umls
new file mode 100755
index 000000000..a533fb728
--- /dev/null
+++ b/testing/scripts/kstart-umls
@@ -0,0 +1,113 @@
+#!/bin/bash
+# starts the UML instances in a konsole (requires KDE)
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: kstart-umls,v 1.6 2005/08/30 22:13:12 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "Configuration file 'testing.conf' not found"
+
+source $DIR/../testing.conf
+
+if [ "$#" -eq 0 ]
+then
+ HOSTS=$STRONGSWANHOSTS
+else
+ HOSTS=$*
+fi
+
+BOOTING_HOSTS=""
+count_max=12
+count=0
+
+for host in $HOSTS
+do
+ up=0
+
+ if [ -d ~/.uml/${host} ]
+ then
+ pid=`cat ~/.uml/${host}/pid`
+ up=`ps up $pid | wc -l`
+ fi
+
+ if [ $up -eq 2 ]
+ then
+ cecho " * Great, ${host} is already running!"
+ else
+ rm -rf ~/.uml/${host}
+ BOOTING_HOSTS="$BOOTING_HOSTS ${host}"
+ let "count_max += 12"
+
+ UMLHOSTFS=$BUILDDIR/root-fs/gentoo-fs-${host}
+ [ -f $UMLHOSTFS ] || die "!! uml root file system '$UMLHOSTFS' not found"
+
+ cecho-n " * Starting ${host}.."
+ eval konsole -title ${host} -e "$UMLKERNEL \
+ umid=${host} \
+ ubda=$UMLHOSTFS \
+ \$SWITCH_${host} \
+ mem=${MEM}M con=pty con0=fd:0,fd:1" &
+ cecho "done"
+ fi
+done
+
+if [ -z "$BOOTING_HOSTS" ]
+then
+ exit 0
+fi
+
+cecho " * Waiting for the uml instances to finish booting"
+
+for host in $BOOTING_HOSTS
+do
+ cecho-n " * Checking on $host.."
+
+ while [ $count -lt $count_max ] && [ ! -d ~/.uml/$host ]
+ do
+ cecho-n "."
+ sleep 5
+ let "count+=1"
+ done
+
+ if [ $count -ge $count_max ]
+ then
+ cecho "exit"
+ exit 1
+ fi
+
+ pid=`cat ~/.uml/$host/pid`
+ up=`ps up $pid | grep agetty | wc -l`
+
+ while [ $count -lt $count_max ] && [ $up -eq 0 ]
+ do
+ cecho-n "."
+ sleep 5
+ up=`ps up $pid | grep agetty | wc -l`
+ let "count+=1"
+ done
+
+ if [ $count -ge $count_max ]
+ then
+ cecho "exit"
+ exit 1
+ else
+ cecho "up"
+ fi
+done
+
+cecho " * All uml instances are up now"
diff --git a/testing/scripts/load-testconfig b/testing/scripts/load-testconfig
new file mode 100755
index 000000000..89da17e72
--- /dev/null
+++ b/testing/scripts/load-testconfig
@@ -0,0 +1,64 @@
+#!/bin/bash
+# Load test specific host configurations
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: load-testconfig,v 1.2 2004/12/13 21:02:42 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "Configuration file 'testing.conf' not found"
+
+source $DIR/../testing.conf
+
+##########################################################################
+# load-testconfig requires a testname as an argument
+#
+
+testname=$1
+
+TESTSDIR=$BUILDDIR/tests
+
+[ -d $TESTSDIR ] || die "Directory '$TESTSDIR' not found"
+[ -d $TESTSDIR/$testname ] || die "Test '$testname' not found"
+[ -f $TESTSDIR/$testname/test.conf ] || die "File 'test.conf' is missing"
+
+source $TESTSDIR/$testname/test.conf
+
+##########################################################################
+# copy test specific configurations to uml hosts
+#
+
+if [ -d $TESTSDIR/$testname/hosts ]
+then
+ for host in `ls $TESTSDIR/$testname/hosts`
+ do
+ eval HOSTLOGIN="root@`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+ scp -rp $TESTSDIR/$testname/hosts/$host/etc $HOSTLOGIN:/ > /dev/null 2>&1
+ done
+fi
+
+
+##########################################################################
+# clear the auth.log where IKE messages are logged
+#
+
+for host in $IPSECHOSTS
+do
+ eval HOSTLOGIN="root@`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+ ssh $HOSTLOGIN 'rm -f /var/log/auth.log; \
+ kill -SIGHUP `cat /var/run/syslogd.pid`' > /dev/null 2>&1
+done
diff --git a/testing/scripts/restore-defaults b/testing/scripts/restore-defaults
new file mode 100755
index 000000000..129e46f56
--- /dev/null
+++ b/testing/scripts/restore-defaults
@@ -0,0 +1,53 @@
+#!/bin/bash
+# Restore the default host configurations
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: restore-defaults,v 1.2 2004/12/20 07:56:33 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "Configuration file 'testing.conf' not found"
+
+source $DIR/../testing.conf
+
+##########################################################################
+# load-testconfig requires a testname as an argument
+#
+
+testname=$1
+
+HOSTCONFIGDIR=$BUILDDIR/hosts
+TESTSDIR=$BUILDDIR/tests
+
+[ -d $TESTSDIR ] || die "Directory '$TESTSDIR' not found"
+[ -d $TESTSDIR/$testname ] || die "Test '$testname' not found"
+[ -f $TESTSDIR/$testname/test.conf ] || die "File 'test.conf' is missing"
+
+source $TESTSDIR/$testname/test.conf
+
+##########################################################################
+# copy default host config back if necessary
+#
+
+if [ -d $TESTSDIR/${testname}/hosts ]
+then
+ for host in `ls $TESTSDIR/${testname}/hosts`
+ do
+ eval HOSTLOGIN="root@`echo $HOSTNAMEIPS | sed -n -e "s/^.*${host}://gp" | awk -F : '{ print $1 }' | awk '{ print $1 }'`"
+ scp -rp $HOSTCONFIGDIR/${host}/etc $HOSTLOGIN:/ > /dev/null 2>&1
+ done
+fi
diff --git a/testing/scripts/start-switches b/testing/scripts/start-switches
new file mode 100755
index 000000000..c90c9f86d
--- /dev/null
+++ b/testing/scripts/start-switches
@@ -0,0 +1,39 @@
+#!/bin/bash
+# starts the UML switches
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: start-switches,v 1.2 2004/12/19 19:17:25 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "Configuration file 'testing.conf' not found"
+
+source $DIR/../testing.conf
+
+for n in 0 1 2
+do
+ if [ `ps aux | grep uml_switch | grep umlswitch$n | wc -l` -eq 1 ]
+ then
+ cecho " * Great, umlswitch$n is already running!"
+ else
+ cecho-n " * Starting umlswitch$n.."
+ uml_switch -tap tap$n -unix /tmp/umlswitch$n >/dev/null </dev/null &
+ sleep 2
+ eval ifconfig "tap$n \$IFCONFIG_$n up"
+ cecho "done"
+ fi
+done
diff --git a/testing/scripts/start-umls b/testing/scripts/start-umls
new file mode 100755
index 000000000..f51791dfa
--- /dev/null
+++ b/testing/scripts/start-umls
@@ -0,0 +1,113 @@
+#!/bin/bash
+# starts the UML instances with a hidden screen
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: start-umls,v 1.5 2005/08/30 22:13:12 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "Configuration file 'testing.conf' not found"
+
+source $DIR/../testing.conf
+
+if [ "$#" -eq 0 ]
+then
+ HOSTS=$STRONGSWANHOSTS
+else
+ HOSTS=$*
+fi
+
+BOOTING_HOSTS=""
+count_max=12
+count=0
+
+for host in $HOSTS
+do
+ up=0
+
+ if [ -d ~/.uml/${host} ]
+ then
+ pid=`cat ~/.uml/${host}/pid`
+ up=`ps up $pid | wc -l`
+ fi
+
+ if [ $up -eq 2 ]
+ then
+ cecho " * Great, ${host} is already running!"
+ else
+ rm -rf ~/.uml/${host}
+ BOOTING_HOSTS="$BOOTING_HOSTS ${host}"
+ let "count_max += 12"
+
+ UMLHOSTFS=$BUILDDIR/root-fs/gentoo-fs-${host}
+ [ -f $UMLHOSTFS ] || die "!! uml root file system '$UMLHOSTFS' not found"
+
+ cecho-n " * Starting ${host}.."
+ eval screen -dmS ${host} "$UMLKERNEL \
+ umid=${host} \
+ ubda=$UMLHOSTFS \
+ \$SWITCH_${host} \
+ mem=${MEM}M con=pty con0=fd:0,fd:1"
+ cecho "done"
+ fi
+done
+
+if [ -z "$BOOTING_HOSTS" ]
+then
+ exit 0
+fi
+
+cecho " * Waiting for the uml instances to finish booting"
+
+for host in $BOOTING_HOSTS
+do
+ cecho-n " * Checking on $host.."
+
+ while [ $count -lt $count_max ] && [ ! -d ~/.uml/$host ]
+ do
+ cecho-n "."
+ sleep 5
+ let "count+=1"
+ done
+
+ if [ $count -ge $count_max ]
+ then
+ cecho "exit"
+ exit 1
+ fi
+
+ pid=`cat ~/.uml/$host/pid`
+ up=`ps up $pid | grep agetty | wc -l`
+
+ while [ $count -lt $count_max ] && [ $up -eq 0 ]
+ do
+ cecho-n "."
+ sleep 5
+ up=`ps up $pid | grep agetty | wc -l`
+ let "count+=1"
+ done
+
+ if [ $count -ge $count_max ]
+ then
+ cecho "exit"
+ exit 1
+ else
+ cecho "up"
+ fi
+done
+
+cecho " * All uml instances are up now"
diff --git a/testing/scripts/xstart-umls b/testing/scripts/xstart-umls
new file mode 100755
index 000000000..13c5d10a1
--- /dev/null
+++ b/testing/scripts/xstart-umls
@@ -0,0 +1,113 @@
+#!/bin/bash
+# starts the UML instances in an xterm (requires X11R6)
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: xstart-umls,v 1.6 2005/08/30 22:13:12 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/function.sh
+
+[ -f $DIR/../testing.conf ] || die "Configuration file 'testing.conf' not found"
+
+source $DIR/../testing.conf
+
+if [ "$#" -eq 0 ]
+then
+ HOSTS=$STRONGSWANHOSTS
+else
+ HOSTS=$*
+fi
+
+BOOTING_HOSTS=""
+count_max=12
+count=0
+
+for host in $HOSTS
+do
+ up=0
+
+ if [ -d ~/.uml/${host} ]
+ then
+ pid=`cat ~/.uml/${host}/pid`
+ up=`ps up $pid | wc -l`
+ fi
+
+ if [ $up -eq 2 ]
+ then
+ cecho " * Great, ${host} is already running!"
+ else
+ rm -rf ~/.uml/${host}
+ BOOTING_HOSTS="$BOOTING_HOSTS ${host}"
+ let "count_max += 12"
+
+ UMLHOSTFS=$BUILDDIR/root-fs/gentoo-fs-${host}
+ [ -f $UMLHOSTFS ] || die "!! uml root file system '$UMLHOSTFS' not found"
+
+ cecho-n " * Starting ${host}.."
+ eval xterm -title ${host} -rightbar -sb -sl 500 -e "$UMLKERNEL \
+ umid=${host} \
+ ubda=$UMLHOSTFS \
+ \$SWITCH_${host} \
+ mem=${MEM}M con=pty con0=fd:0,fd:1" &
+ cecho "done"
+ fi
+done
+
+if [ -z "$BOOTING_HOSTS" ]
+then
+ exit 0
+fi
+
+cecho " * Waiting for the uml instances to finish booting"
+
+for host in $BOOTING_HOSTS
+do
+ cecho-n " * Checking on $host.."
+
+ while [ $count -lt $count_max ] && [ ! -d ~/.uml/$host ]
+ do
+ cecho-n "."
+ sleep 5
+ let "count+=1"
+ done
+
+ if [ $count -ge $count_max ]
+ then
+ cecho "exit"
+ exit 1
+ fi
+
+ pid=`cat ~/.uml/$host/pid`
+ up=`ps up $pid | grep agetty | wc -l`
+
+ while [ $count -lt $count_max ] && [ $up -eq 0 ]
+ do
+ cecho-n "."
+ sleep 5
+ up=`ps up $pid | grep agetty | wc -l`
+ let "count+=1"
+ done
+
+ if [ $count -ge $count_max ]
+ then
+ cecho "exit"
+ exit 1
+ else
+ cecho "up"
+ fi
+done
+
+cecho " * All uml instances are up now"
diff --git a/testing/start-testing b/testing/start-testing
new file mode 100755
index 000000000..375a82be5
--- /dev/null
+++ b/testing/start-testing
@@ -0,0 +1,83 @@
+#!/bin/bash
+# Start up the specified UML instances and wait for them to finish booting
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: start-testing,v 1.4 2004/12/07 18:04:57 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/scripts/function.sh
+
+[ -f $DIR/testing.conf ] || die "!! Configuration file 'testing.conf' not found"
+[ -d $DIR/hosts ] || die "Directory hosts cannot be found."
+
+source $DIR/testing.conf
+
+if [ "$#" -eq 0 ]
+then
+ HOSTS=$STRONGSWANHOSTS
+else
+ HOSTS=$*
+fi
+
+#####################################################
+# start the uml switches
+#
+cecho "Start the uml switches (scripts/start-switches)"
+$DIR/scripts/start-switches
+
+
+#####################################################
+# start the uml instances
+#
+case $UMLSTARTMODE in
+ konsole)
+ cecho "Start the uml instances (scripts/kstart-umls)"
+ $DIR/scripts/kstart-umls $HOSTS
+ ;;
+ xterm)
+ cecho "Start the uml instances (scripts/xstart-umls)"
+ $DIR/scripts/xstart-umls $HOSTS
+ ;;
+ screen)
+ cecho "Start the uml instances (scripts/start-umls)"
+ $DIR/scripts/start-umls $HOSTS
+ ;;
+ *)
+ die "The start mode is unknown! Please set $UMLSTARTMODE properly."
+ ;;
+esac
+
+
+#####################################################
+# do the automated testing
+#
+if [ $ENABLE_DO_TESTS = "yes" ]
+then
+ cecho "Run the automated tests (do-tests)"
+ $DIR/do-tests
+fi
+
+
+##############################################################################
+# stop all UML instances and switches
+#
+
+if [ $ENABLE_STOP_TESTING = "yes" ]
+then
+ cecho "Stopping all UML instances and switches (stop-testing)"
+ $DIR/stop-testing $HOSTS
+fi
+
diff --git a/testing/stop-testing b/testing/stop-testing
new file mode 100755
index 000000000..5b53505ac
--- /dev/null
+++ b/testing/stop-testing
@@ -0,0 +1,51 @@
+#!/bin/bash
+# Stop all UML instances and UML switches
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: stop-testing,v 1.3 2004/12/07 18:04:57 as Exp $
+
+DIR=`dirname $0`
+
+source $DIR/scripts/function.sh
+
+[ -f $DIR/testing.conf ] || die "No configuration file testing.conf found."
+
+source $DIR/testing.conf
+
+if [ "$#" -eq 0 ]
+then
+ HOSTS=$STRONGSWANHOSTS
+else
+ HOSTS=$*
+fi
+
+#####################################################
+# Shutting down the uml instances
+#
+cecho-n " * Halting all UML instances.."
+for host in $HOSTS
+do
+ uml_mconsole $host halt &> /dev/null
+done
+cecho "done"
+
+#####################################################
+# Shutting down the uml switches
+#
+cecho-n " * Stopping the UML switches.."
+killall uml_switch &> /dev/null
+rm -f /tmp/umlswitch[012] &> /dev/null 2>&1
+cecho "done"
+
diff --git a/testing/testing.conf b/testing/testing.conf
new file mode 100755
index 000000000..92a138288
--- /dev/null
+++ b/testing/testing.conf
@@ -0,0 +1,154 @@
+#!/bin/bash
+# Global configuration file for strongswan UML testing.
+#
+# Copyright (C) 2004 Eric Marchionni, Patrik Rayo
+# Zuercher Hochschule Winterthur
+#
+# 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: testing.conf,v 1.52 2006/04/24 16:58:03 as Exp $
+
+# Root directory of testing
+UMLTESTDIR=~/strongswan-testing
+
+# Bzipped kernel sources
+# (file extension .tar.bz2 required)
+KERNEL=$UMLTESTDIR/linux-2.6.16.9.tar.bz2
+
+# Extract kernel version
+KERNELVERSION=`basename $KERNEL .tar.bz2 | sed -e 's/linux-//'`
+
+# Kernel configuration file
+KERNELCONFIG=$UMLTESTDIR/.config-2.6.16
+
+# Bzipped uml patch for kernel
+# (not needed anymore for 2.6.9 kernel or higher)
+UMLPATCH=
+
+# Bzipped source of strongSwan
+STRONGSWAN=$UMLTESTDIR/strongswan-2.7.0.tar.bz2
+
+# strongSwan compile options (use "yes" or "no")
+USE_LIBCURL="yes"
+USE_LDAP="yes"
+
+# Gentoo linux root filesystem
+ROOTFS=$UMLTESTDIR/gentoo-fs-20060330.tar.bz2
+
+# Size of the finished root filesystem in MB
+ROOTFSSIZE=544
+
+# Amount of Memory to use per UML [MB].
+# If "auto" is stated 1/12 of total host ram will be used.
+# Examples: MEM=64, MEM="128", MEM="auto"
+MEM=64
+
+# Directory where the UML kernels and file system will be built
+BUILDDIR=$UMLTESTDIR/umlbuild
+
+# Filename of the built UML Kernel
+UMLKERNEL=$BUILDDIR/linux-uml-$KERNELVERSION
+
+# Directory where test results will be stored
+TESTRESULTSDIR=$UMLTESTDIR/testresults
+
+# Timezone for the UMLs, look in /usr/share/zoneinfo!
+TZUML="Europe/Zurich"
+
+##############################################################
+# Enable particular steps in the make-testing and
+# start-testing scripts
+#
+ENABLE_BUILD_UMLKERNEL="yes"
+ENABLE_BUILD_SSHKEYS="yes"
+ENABLE_BUILD_HOSTCONFIG="yes"
+ENABLE_BUILD_UMLROOTFS="yes"
+ENABLE_BUILD_UMLHOSTFS="yes"
+ENABLE_START_TESTING="yes"
+ENABLE_DO_TESTS="yes"
+ENABLE_STOP_TESTING="no"
+
+##############################################################
+# How to start the UMLs?
+#
+# Start the UML instance in KDE konsole (requires KDE)
+UMLSTARTMODE="konsole"
+# Start the UML instance in an xterm (requires X11R6)
+# UMLSTARTMODE="xterm"
+# Start the UML instance without a terminal window
+# but screen -r <host> can open a window anytime
+# UMLSTARTMODE="screen"
+
+##############################################################
+# If set to "yes" only the tests stated at $SELECTEDTESTS
+# will be executed. (use "yes" or "no")
+#
+SELECTEDTESTSONLY="no"
+
+# Tests to do if $SELECTEDTESTSONLY is set "yes".
+#
+SELECTEDTESTS="net2net-cert"
+
+##############################################################
+# hostname and according IP(s)
+# You may change the IPs but keep them in the same net,
+# this means retain the netmasks!
+# Also don't use IPs ending with 254, they are reserved!
+#
+HOSTNAMEIPS="\
+alice:10.1.0.10 \
+venus:10.1.0.20 \
+moon:192.168.0.1:10.1.0.1 \
+carol:192.168.0.100:10.3.0.1 \
+winnetou:192.168.0.150 \
+dave:192.168.0.200:10.3.0.2 \
+sun:192.168.0.2:10.2.0.1 \
+bob:10.2.0.10"
+
+##############################################################
+# VPN gateways / clients
+# The hosts stated here will be created. Possible values
+# are sun, moon, dave, carol, alice, venus, bob, winnetou.
+# It's fine to make them all unless you don't have much
+# ressources. In this case we assume you know what you do!
+#
+STRONGSWANHOSTS="sun moon dave carol alice venus bob winnetou"
+
+##############################################################
+# Needed programs, do not change!
+#
+PROGRAMS="uml_switch uml_mconsole ssh ssh-keygen iptables \
+ chroot screen mkreiserfs"
+
+##############################################################
+# IP parameters of the UML switches
+#
+IFCONFIG_0="192.168.0.254 netmask 255.255.255.0"
+IFCONFIG_1="10.1.0.254 netmask 255.255.0.0"
+IFCONFIG_2="10.2.0.254 netmask 255.255.0.0"
+
+##############################################################
+# Network interfaces of the UML instances
+#
+SWITCH_alice="eth0=daemon,,unix,/tmp/umlswitch1"
+SWITCH_venus="eth0=daemon,,unix,/tmp/umlswitch1"
+SWITCH_moon="eth0=daemon,,unix,/tmp/umlswitch0 \
+ eth1=daemon,,unix,/tmp/umlswitch1"
+SWITCH_carol="eth0=daemon,,unix,/tmp/umlswitch0"
+SWITCH_winnetou="eth0=daemon,,unix,/tmp/umlswitch0"
+SWITCH_dave="eth0=daemon,,unix,/tmp/umlswitch0"
+SWITCH_sun="eth0=daemon,,unix,/tmp/umlswitch0 \
+ eth1=daemon,,unix,/tmp/umlswitch2"
+SWITCH_bob="eth0=daemon,,unix,/tmp/umlswitch2"
+
+
+
+
diff --git a/testing/tests/alg-blowfish/description.txt b/testing/tests/alg-blowfish/description.txt
new file mode 100644
index 000000000..cff0a1915
--- /dev/null
+++ b/testing/tests/alg-blowfish/description.txt
@@ -0,0 +1,4 @@
+Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the strong cipher suite
+<b>BLOWFISH_CBC_256-SHA2_512-MODP4096</b> for the IKE protocol and
+<b>BLOWFISH_256-HMAC_SHA2_256</b> for ESP packets. A ping from <b>carol</b> to
+<b>alice</b> successfully checks the established tunnel.
diff --git a/testing/tests/alg-blowfish/evaltest.dat b/testing/tests/alg-blowfish/evaltest.dat
new file mode 100644
index 000000000..a9c9b803a
--- /dev/null
+++ b/testing/tests/alg-blowfish/evaltest.dat
@@ -0,0 +1,9 @@
+
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec statusall::IKE algorithm newest: BLOWFISH_CBC_256-SHA2_512-MODP4096::YES
+carol::ipsec statusall::IKE algorithm newest: BLOWFISH_CBC_256-SHA2_512-MODP4096::YES
+moon::ipsec statusall::ESP algorithm newest: BLOWFISH_256-HMAC_SHA2_256::YES
+carol::ipsec statusall::ESP algorithm newest: BLOWFISH_256-HMAC_SHA2_256::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+
diff --git a/testing/tests/alg-blowfish/hosts/carol/etc/ipsec.conf b/testing/tests/alg-blowfish/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..fa68c9d3d
--- /dev/null
+++ b/testing/tests/alg-blowfish/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=blowfish256-sha2_512-modp4096!
+ esp=blowfish256-sha2_256!
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/alg-blowfish/hosts/moon/etc/ipsec.conf b/testing/tests/alg-blowfish/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..39916a7ba
--- /dev/null
+++ b/testing/tests/alg-blowfish/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=blowfish256-sha2_512-modp4096!
+ esp=blowfish256-sha2_256!
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/alg-blowfish/posttest.dat b/testing/tests/alg-blowfish/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/alg-blowfish/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/alg-blowfish/pretest.dat b/testing/tests/alg-blowfish/pretest.dat
new file mode 100644
index 000000000..6d2eeb5f9
--- /dev/null
+++ b/testing/tests/alg-blowfish/pretest.dat
@@ -0,0 +1,5 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/alg-blowfish/test.conf b/testing/tests/alg-blowfish/test.conf
new file mode 100644
index 000000000..a6c8f026c
--- /dev/null
+++ b/testing/tests/alg-blowfish/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/alg-serpent/description.txt b/testing/tests/alg-serpent/description.txt
new file mode 100644
index 000000000..f49c0a1c0
--- /dev/null
+++ b/testing/tests/alg-serpent/description.txt
@@ -0,0 +1,4 @@
+Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the strong cipher suite
+<b>SERPENT_CBC_256-SHA2_512-MODP4096</b> for the IKE protocol and
+<b>SERPENT_256-HMAC_SHA2_256</b> for ESP packets. A ping from <b>carol</b> to
+<b>alice</b> successfully checks the established tunnel.
diff --git a/testing/tests/alg-serpent/evaltest.dat b/testing/tests/alg-serpent/evaltest.dat
new file mode 100644
index 000000000..6b792538b
--- /dev/null
+++ b/testing/tests/alg-serpent/evaltest.dat
@@ -0,0 +1,9 @@
+
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec statusall::IKE algorithm newest: SERPENT_CBC_256-SHA2_512-MODP4096::YES
+carol::ipsec statusall::IKE algorithm newest: SERPENT_CBC_256-SHA2_512-MODP4096::YES
+moon::ipsec statusall::ESP algorithm newest: SERPENT_256-HMAC_SHA2_256::YES
+carol::ipsec statusall::ESP algorithm newest: SERPENT_256-HMAC_SHA2_256::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+
diff --git a/testing/tests/alg-serpent/hosts/carol/etc/ipsec.conf b/testing/tests/alg-serpent/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..5d2369924
--- /dev/null
+++ b/testing/tests/alg-serpent/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=serpent256-sha2_512-modp4096!
+ esp=serpent256-sha2_256!
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/alg-serpent/hosts/moon/etc/ipsec.conf b/testing/tests/alg-serpent/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..7bdddf008
--- /dev/null
+++ b/testing/tests/alg-serpent/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=serpent256-sha2_512-modp4096!
+ esp=serpent256-sha2_256!
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/alg-serpent/posttest.dat b/testing/tests/alg-serpent/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/alg-serpent/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/alg-serpent/pretest.dat b/testing/tests/alg-serpent/pretest.dat
new file mode 100644
index 000000000..6d2eeb5f9
--- /dev/null
+++ b/testing/tests/alg-serpent/pretest.dat
@@ -0,0 +1,5 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/alg-serpent/test.conf b/testing/tests/alg-serpent/test.conf
new file mode 100644
index 000000000..a6c8f026c
--- /dev/null
+++ b/testing/tests/alg-serpent/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/alg-sha2_256/description.txt b/testing/tests/alg-sha2_256/description.txt
new file mode 100644
index 000000000..900fcf017
--- /dev/null
+++ b/testing/tests/alg-sha2_256/description.txt
@@ -0,0 +1,4 @@
+Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the rather strong cipher suite
+<b>AES_CBC_128-SHA2_256-MODP1536</b> for the IKE protocol and
+<b>AES_128-HMAC_SHA2_256</b> for ESP packets. A ping from <b>carol</b> to
+<b>alice</b> successfully checks the established tunnel.
diff --git a/testing/tests/alg-sha2_256/evaltest.dat b/testing/tests/alg-sha2_256/evaltest.dat
new file mode 100644
index 000000000..9b4caa278
--- /dev/null
+++ b/testing/tests/alg-sha2_256/evaltest.dat
@@ -0,0 +1,9 @@
+
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec statusall::IKE algorithm newest: AES_CBC_128-SHA2_256-MODP1536::YES
+carol::ipsec statusall::IKE algorithm newest: AES_CBC_128-SHA2_256-MODP1536::YES
+moon::ipsec statusall::ESP algorithm newest: AES_128-HMAC_SHA2_256::YES
+carol::ipsec statusall::ESP algorithm newest: AES_128-HMAC_SHA2_256::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+
diff --git a/testing/tests/alg-sha2_256/hosts/carol/etc/ipsec.conf b/testing/tests/alg-sha2_256/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..c55ae8ab1
--- /dev/null
+++ b/testing/tests/alg-sha2_256/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=aes128-sha2_256-modp1536!
+ esp=aes128-sha2_256!
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/alg-sha2_256/hosts/moon/etc/ipsec.conf b/testing/tests/alg-sha2_256/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..748b1b85c
--- /dev/null
+++ b/testing/tests/alg-sha2_256/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=aes128-sha2_256-modp1536!
+ esp=aes128-sha2_256!
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/alg-sha2_256/posttest.dat b/testing/tests/alg-sha2_256/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/alg-sha2_256/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/alg-sha2_256/pretest.dat b/testing/tests/alg-sha2_256/pretest.dat
new file mode 100644
index 000000000..7d077c126
--- /dev/null
+++ b/testing/tests/alg-sha2_256/pretest.dat
@@ -0,0 +1,5 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/alg-sha2_256/test.conf b/testing/tests/alg-sha2_256/test.conf
new file mode 100644
index 000000000..a6c8f026c
--- /dev/null
+++ b/testing/tests/alg-sha2_256/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/alg-twofish/description.txt b/testing/tests/alg-twofish/description.txt
new file mode 100644
index 000000000..0015561ee
--- /dev/null
+++ b/testing/tests/alg-twofish/description.txt
@@ -0,0 +1,4 @@
+Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the strong cipher suite
+<b>TWOFISH_CBC_256-SHA2_512-MODP4096</b> for the IKE protocol and
+<b>TWOFISH_256-HMAC_SHA2_256</b> for ESP packets. A ping from <b>carol</b> to
+<b>alice</b> successfully checks the established tunnel.
diff --git a/testing/tests/alg-twofish/evaltest.dat b/testing/tests/alg-twofish/evaltest.dat
new file mode 100644
index 000000000..0568eec6e
--- /dev/null
+++ b/testing/tests/alg-twofish/evaltest.dat
@@ -0,0 +1,8 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec statusall::IKE algorithm newest: TWOFISH_CBC_256-SHA2_512-MODP4096::YES
+carol::ipsec statusall::IKE algorithm newest: TWOFISH_CBC_256-SHA2_512-MODP4096::YES
+moon::ipsec statusall::ESP algorithm newest: TWOFISH_256-HMAC_SHA2_256::YES
+carol::ipsec statusall::ESP algorithm newest: TWOFISH_256-HMAC_SHA2_256::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+
diff --git a/testing/tests/alg-twofish/hosts/carol/etc/ipsec.conf b/testing/tests/alg-twofish/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..8e3037a3b
--- /dev/null
+++ b/testing/tests/alg-twofish/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=twofish256-sha2_512-modp4096!
+ esp=twofish256-sha2_256!
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/alg-twofish/hosts/moon/etc/ipsec.conf b/testing/tests/alg-twofish/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..01004e94e
--- /dev/null
+++ b/testing/tests/alg-twofish/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=twofish256-sha2_512-modp4096!
+ esp=twofish256-sha2_256!
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/alg-twofish/posttest.dat b/testing/tests/alg-twofish/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/alg-twofish/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/alg-twofish/pretest.dat b/testing/tests/alg-twofish/pretest.dat
new file mode 100644
index 000000000..7d077c126
--- /dev/null
+++ b/testing/tests/alg-twofish/pretest.dat
@@ -0,0 +1,5 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/alg-twofish/test.conf b/testing/tests/alg-twofish/test.conf
new file mode 100644
index 000000000..a6c8f026c
--- /dev/null
+++ b/testing/tests/alg-twofish/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/attr-cert/description.txt b/testing/tests/attr-cert/description.txt
new file mode 100644
index 000000000..b7f809c36
--- /dev/null
+++ b/testing/tests/attr-cert/description.txt
@@ -0,0 +1,7 @@
+The VPN gateway <b>moon</b> controls the access to the hosts <b>alice</b> and
+<b>venus</b> by means of <b>X.509 Attribute Certificates</b>. Access to <b>alice</b>
+is granted to members of the group 'Research' whereas <b>venus</b> can only
+be reached by members of the groups 'Accounting' and 'Sales'. The roadwarriors
+<b>carol</b> and <b>dave</b> belong to the groups 'Research' and 'Accounting',
+respectively. Therefore <b>carol</b> can access <b>alice</b> and <b>dave</b>
+can reach <b>venus</b>. \ No newline at end of file
diff --git a/testing/tests/attr-cert/evaltest.dat b/testing/tests/attr-cert/evaltest.dat
new file mode 100644
index 000000000..59f6eb76a
--- /dev/null
+++ b/testing/tests/attr-cert/evaltest.dat
@@ -0,0 +1,12 @@
+carol::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::cat /var/log/auth.log::alice.*peer matches group 'Research'::YES
+moon::ipsec status::alice.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::cat /var/log/auth.log::venus.*peer doesn't match any group::YES
+moon::ipsec status::venus.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::NO
+dave::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::cat /var/log/auth.log::venus.*peer matches group 'Accounting'::YES
+moon::ipsec status::venus.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::YES
+dave::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::cat /var/log/auth.log::alice.*peer doesn't match any group::YES
+moon::ipsec status::alice.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::NO
diff --git a/testing/tests/attr-cert/hosts/carol/etc/ipsec.conf b/testing/tests/attr-cert/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..62fc49868
--- /dev/null
+++ b/testing/tests/attr-cert/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,33 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
+
+
+
+
+
diff --git a/testing/tests/attr-cert/hosts/dave/etc/ipsec.conf b/testing/tests/attr-cert/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..9d932dc54
--- /dev/null
+++ b/testing/tests/attr-cert/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,33 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_DAVE
+ leftnexthop=%direct
+ leftcert=daveCert.pem
+ leftid=dave@strongswan.org
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
+
+
+
+
+
diff --git a/testing/tests/attr-cert/hosts/moon/etc/ipsec.conf b/testing/tests/attr-cert/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..bd72715ff
--- /dev/null
+++ b/testing/tests/attr-cert/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,31 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn alice
+ leftsubnet=PH_IP_ALICE/32
+ right=%any
+ rightgroups=Research
+ auto=add
+
+conn venus
+ leftsubnet=PH_IP_VENUS/32
+ right=%any
+ rightgroups="Accounting, Sales"
+ auto=add
+
diff --git a/testing/tests/attr-cert/hosts/moon/etc/ipsec.d/aacerts/aaCert.pem b/testing/tests/attr-cert/hosts/moon/etc/ipsec.d/aacerts/aaCert.pem
new file mode 100644
index 000000000..3c5c5d91d
--- /dev/null
+++ b/testing/tests/attr-cert/hosts/moon/etc/ipsec.d/aacerts/aaCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIBCzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDIxNzA4NDQzMFoXDTEwMDIxNjA4NDQzMFowZjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xIDAeBgNVBAsTF0F1dGhv
+cml6YXRpb24gQXV0aG9yaXR5MRowGAYDVQQDFBFhYUBzdHJvbmdzd2FuLm9yZzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2Czo4Mds6Jz15DWop6ExWI
+wWt9zU8Xu//ow1F0Kf9a4DLjo8qO+km3gybByNQQv1LrZ1eq+82Gy4RYXU1FnhC6
+dc8aobDmUQkY/8uYXtUmevKF5QcbYciDLp01W1q0DONAlc/9wmvJWhvjs9itWOBC
+fAUcH3eUNvMgkc7hlQTqreZTH4zyJ6M54JibkTsyfVg/1yOT41zUU3b+vI/r9kNB
+CYcp2DrdhdxX6mEiSTyDA/OMlgvCa7kPinUL4FJtQOFBozCsGcD28ONLc8Abkggf
+NABXCclPVAXOTawJF3dRWcMhIlNLWxWMVRvEt5OkAEdy/mXGBvtVArmGnmA+8zcC
+AwEAAaOCAQIwgf8wCQYDVR0TBAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFA+6
+5KwThPKc9Vxn0048uRThft1tMG0GA1UdIwRmMGSAFF2n3XAGUTJ+57Zts7Xl4GDq
+Lk3voUmkRzBFMQswCQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dh
+bjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBSb290IENBggEAMBwGA1UdEQQVMBOBEWFh
+QHN0cm9uZ3N3YW4ub3JnMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwuc3Ry
+b25nc3dhbi5vcmcvc3Ryb25nc3dhbi5jcmwwDQYJKoZIhvcNAQEEBQADggEBAIeg
+CjgR2yIGSuyrFolvEM/qoT3j+LpQREDZbx9BKr3kGmbqF75clwfpysJ4FlXZZ2CR
+aH2GoPOZGXwsYc3poqGeeWSxo+fpt4XIGUc1eREXm1rKVMd+qb0u0PXuhq2+u1aY
+ZJDY0yqUU2/7AInXjzG7lI120W+K6tuTM/5UVI5EPpAFwUVlCxnMh4Sl4VkgZ2Hw
+YnO3/8SEHmHR03/GhOd5d8hD8a0AGHtdOPpZnUOR9PH5FszpQ/alUdn+NTdQ7O2v
+Q8jqPCeQSAAkJbBBRvGA4bD6KXt1k74fXXUofiKWpQUozlO1Cc978Kfl5/do5bov
+wTLSA/z7c8nVCVoZI9Y=
+-----END CERTIFICATE-----
diff --git a/testing/tests/attr-cert/hosts/moon/etc/openac/aaKey.pem b/testing/tests/attr-cert/hosts/moon/etc/openac/aaKey.pem
new file mode 100644
index 000000000..209b48f3a
--- /dev/null
+++ b/testing/tests/attr-cert/hosts/moon/etc/openac/aaKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAvYLOjgx2zonPXkNainoTFYjBa33NTxe7/+jDUXQp/1rgMuOj
+yo76SbeDJsHI1BC/UutnV6r7zYbLhFhdTUWeELp1zxqhsOZRCRj/y5he1SZ68oXl
+BxthyIMunTVbWrQM40CVz/3Ca8laG+Oz2K1Y4EJ8BRwfd5Q28yCRzuGVBOqt5lMf
+jPInozngmJuROzJ9WD/XI5PjXNRTdv68j+v2Q0EJhynYOt2F3FfqYSJJPIMD84yW
+C8JruQ+KdQvgUm1A4UGjMKwZwPbw40tzwBuSCB80AFcJyU9UBc5NrAkXd1FZwyEi
+U0tbFYxVG8S3k6QAR3L+ZcYG+1UCuYaeYD7zNwIDAQABAoIBAQCCGgsz+dqWcIWs
+cRD3gFcZsYkYAoWwhtrKFUIB6X3rkLfaN+16Yi3x7cpcES2OaPDwPCv2Q6warS+K
+7B8hrWmWkmvOgrn+eB+p3z+8xh5UttYxKTrSZjn7LhQSWU8eNf2jBfPTlqKi3Ni/
+zNLrLhaV3w7Fc0knDtmqj/GJ1dQ4SrUpME3sREpWbGSzjJ2UsR7iqQiDsYwWHzK2
+nWWwzrSmpObhDR3jiyOwBy/DEjXRC7h0fUL8eBghJvLWgFgifI5Z36FXa0FasxQr
+zKZnQdwuJHqQz7+sVjAmKtNd7x7RE5Ii0oQYiWDFr0OAwKD5UfMNydpcOVC/bV2n
+SKWmguoBAoGBAO73MTPP9ne4cfC7t4k2+F9hkb7mAjAbk9GbTyZyEKSDKH2bL02W
+G4kXdlkvZVgKhIDg8PCouRSQKv2IxubDrarFURb5KMJlyfBV1Q8JSxpVtxK69clq
+yIu/AtiiBE/n11MdmdoJLr6l2nNStJummj2jw5OyN8sdJarf83rCy+ITAoGBAMsF
+IfivZ+Tueavy0tGRb1qqKalIhwzLBRmWCna39bB9rK4eTNio5Oes95mC7t8mslmO
+18enKUTO87svWLzo8NVYIKSqg5B+kIN44hROErlV6HHPVd5vJzZFjH7SSfy5y8Ka
+wmsA1xiG6NEgEndc6F6uQ2YdaZAHWFO6CiTNpq7NAoGADXglb9QzAkCFO5p5F+Tf
+TxEC1A3G5ctII7JrXbFkOsGh0KKkoezqFGocI57GSZYeLd1/9zCrbftKUQwamftB
+mLSSg4b7wylVnpRX9AcEErHuJcIgBIBeWXIkyO0o7RAWVPsAJwgJeHmEvKdWwsc7
+PmoypeqPtoUoEF+bK7o7H70CgYAYlYaHlrX+AuK4766XsgTJ9dEVrrKr2enEL2cU
++THHLXC7pO+pTMprQ4a4ECLc4tK2BZYblyJoMqdRA2q7dXm0W/eX+Q31cV4OjZTS
+4KFj0ANVxMWhKdSVvdZFhTFwaQ9DgXoJexCQ58VJjZiu25FH5dJDi0w9JKaNfPm9
+eym0AQKBgHhfqD9EXxazoP27NyZAFUSA3r4u06qFjbAEjbuJVAJNSuEu6Sht2uIg
+lCHpTPssDLHVSY0faQwY4vPqJZVg0k/rAu2VlvbJxYrdzXr8eTfPRJrhv/s/Tbro
+n1rmisBKov1P2Cu2e03a8+GDO3lpSZr9YNG/e7wggSbfAvqCoUDF
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/attr-cert/hosts/moon/etc/openac/carolCert.pem b/testing/tests/attr-cert/hosts/moon/etc/openac/carolCert.pem
new file mode 100644
index 000000000..8492fbd45
--- /dev/null
+++ b/testing/tests/attr-cert/hosts/moon/etc/openac/carolCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIBCjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDEwMTIxNDMxOFoXDTA5MTIzMTIxNDMxOFowWjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALgbhJIECOCGyNJ4060un/wBuJ6MQjthK5CAEPgX
+T/lvZynoSxhfuW5geDCCxQes6dZPeb6wJS4F5fH3qJoLM+Z4n13rZlCEyyMBkcFl
+vK0aNFY+ARs0m7arUX8B7Pfi9N6WHTYgO4XpeBHLJrZQz9AU0V3S0rce/WVuVjii
+S/cJhrgSi7rl87Qo1jYOA9P06BZQLj0dFNcWWrGpKp/hXvBF1OSP9b15jsgMlCCW
+LJqXmLVKDtKgDPLJZR19mILhgcHvaxxD7craL9GR4QmWLb0m84oAIIwaw+0npZJM
+YDMMeYeOtcepCWCmRy+XmsqcWu4rtNCu05W1RsXjYZEKBjcCAwEAAaOCAQYwggEC
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBRVNeym66J5uu+IfxhD
+j9InsWdG0TBtBgNVHSMEZjBkgBRdp91wBlEyfue2bbO15eBg6i5N76FJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBADAfBgNVHREEGDAWgRRjYXJvbEBzdHJvbmdz
+d2FuLm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u
+b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQCxMEp+Zdclc0aI
+U+jO3TmL81gcwea0BUucjZfDyvCSkDXcXidOez+l/vUueGC7Bqq1ukDF8cpVgGtM
+2HPxM97ZSLPInMgWIeLq3uX8iTtIo05EYqRasJxBIAkY9o6ja6v6z0CZqjSbi2WE
+HrHkFrkOTrRi7deGzbAAhWVjOnAfzSxBaujkdUxb6jGBc2F5qpAeVSbE+sAxzmSd
+hRyF3tUUwl4yabBzmoedJzlQ4anqg0G14QScBxgXkq032gKuzNVVxWRp6OFannKG
+C1INvsBWYtN62wjXlXXhM/M4sBFhmPpftVb+Amgr1jSspTX2dQsNqhI/WtNvLmfK
+omBYfxqp
+-----END CERTIFICATE-----
diff --git a/testing/tests/attr-cert/hosts/moon/etc/openac/daveCert.pem b/testing/tests/attr-cert/hosts/moon/etc/openac/daveCert.pem
new file mode 100644
index 000000000..abd1554e5
--- /dev/null
+++ b/testing/tests/attr-cert/hosts/moon/etc/openac/daveCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIBCDANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjY1MVoXDTA5MDkwOTExMjY1MVowWzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xEzARBgNVBAsTCkFjY291
+bnRpbmcxHDAaBgNVBAMUE2RhdmVAc3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDGbCmUY6inir71/6RWebegcLUTmDSxRqpRONDx
+2IRUEuES5EKc7qsjRz45XoqjiywCQRjYW33fUEEY6r7fnHk70CyUnWeZyr7v4D/2
+LjBN3smDE6/ZZrzxPx+xphlUigYOF/vt4gUiW1dOZ5rcnxG9+eNrSL6gWNNg1iuE
+RflSTbmHV6TVmGU2PGddKGZ6XfqWfdA+6iOi2+oyqw6aH4u4hfXhJyMROEOhLdAF
+UvzU9UizEXSqsmEOSodS9vypVJRYTbZcx70e9Q7g2MghHvtQY6mVgBzAwakDBCt/
+98lAlKDeXXOQqPcqAZSc2VjG8gEmkr1dum8wsJw8C2liKGRFAgMBAAGjggEFMIIB
+ATAJBgNVHRMEAjAAMAsGA1UdDwQEAwIDqDAdBgNVHQ4EFgQU3pC10RxsZDx0UNNq
++Ihsoxk4+3IwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUx
+CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQD
+ExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQAwHgYDVR0RBBcwFYETZGF2ZUBzdHJvbmdz
+d2FuLm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u
+b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQAnotcnOE0tJDLy
+8Vh1+naT2zrxx9UxfMIeFljwhDqRiHXSLDAbCOnAWoqj8C9riuZwW7UImIIQ9JT9
+Gdktt4bbIcG25rGMC3uqP71CfaAz/SwIZZ2vm8Jt2ZzzSMHsE5qbjDIRAZnq6giR
+P2s6PVsMPSpvH34sRbE0UoWJSdtBZJP5bb+T4hc9gfmbyTewwMnjh09KkGJqVxKV
+UC/1z1U9zb3X1Gc9y+zI67/D46wM6KdRINaqPdK26aYRFM+/DLoTfFk07dsyz7lt
+0C+/ityQOvpfjVlZ/OepT92eWno4FuNRJuUP5/gYiHvSsjZbazqG02qGhJ6VgtGT
+5qILUTmI
+-----END CERTIFICATE-----
diff --git a/testing/tests/attr-cert/hosts/moon/etc/openac/default.conf b/testing/tests/attr-cert/hosts/moon/etc/openac/default.conf
new file mode 100644
index 000000000..134218eec
--- /dev/null
+++ b/testing/tests/attr-cert/hosts/moon/etc/openac/default.conf
@@ -0,0 +1,4 @@
+--cert /etc/ipsec.d/aacerts/aaCert.pem
+--key /etc/openac/aaKey.pem
+--quiet
+--hours 8
diff --git a/testing/tests/attr-cert/posttest.dat b/testing/tests/attr-cert/posttest.dat
new file mode 100644
index 000000000..a59c3ff63
--- /dev/null
+++ b/testing/tests/attr-cert/posttest.dat
@@ -0,0 +1,6 @@
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
+moon::rm /etc/openac/*
+moon::rm /etc/ipsec.d/aacerts/aaCert.pem
+moon::rm /etc/ipsec.d/acerts/*
diff --git a/testing/tests/attr-cert/pretest.dat b/testing/tests/attr-cert/pretest.dat
new file mode 100644
index 000000000..b3fecaf3c
--- /dev/null
+++ b/testing/tests/attr-cert/pretest.dat
@@ -0,0 +1,12 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+moon::cat /etc/openac/default.conf
+moon::ipsec openac --optionsfrom default.conf --usercert /etc/openac/carolCert.pem --groups Research --out /etc/ipsec.d/acerts/carolAC.pem
+moon::ipsec openac --optionsfrom default.conf --usercert /etc/openac/daveCert.pem --groups Accounting --out /etc/ipsec.d/acerts/daveAC.pem
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up alice
+carol::ipsec up venus
+dave::ipsec up venus
+dave::ipsec up alice
diff --git a/testing/tests/attr-cert/test.conf b/testing/tests/attr-cert/test.conf
new file mode 100644
index 000000000..08e5cc145
--- /dev/null
+++ b/testing/tests/attr-cert/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice venus moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-v-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/compress/description.txt b/testing/tests/compress/description.txt
new file mode 100644
index 000000000..47829839d
--- /dev/null
+++ b/testing/tests/compress/description.txt
@@ -0,0 +1,3 @@
+This scenario enables IPCOMP compression between roadwarrior <b>carol</b> and
+gateway <b>moon</b>. Two pings from <b>carol</b> to <b>alice</b> checks
+the established tunnel with compression.
diff --git a/testing/tests/compress/evaltest.dat b/testing/tests/compress/evaltest.dat
new file mode 100644
index 000000000..ff72e1762
--- /dev/null
+++ b/testing/tests/compress/evaltest.dat
@@ -0,0 +1,10 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec statusall::policy.*COMPRESS::YES
+carol::ipsec statusall::policy.*COMPRESS::YES
+moon::ipsec statusall::comp.::YES
+carol::ipsec statusall::comp.::YES
+carol::ping -n -c 2 -s 8184 -p deadbeef PH_IP_ALICE::8192 bytes from PH_IP_ALICE::YES
+moon::tcpdump::carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::moon.strongswan.org > carol.strongswan.org: ESP::YES
+
diff --git a/testing/tests/compress/hosts/carol/etc/ipsec.conf b/testing/tests/compress/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..9462ba5e6
--- /dev/null
+++ b/testing/tests/compress/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ compress=yes
+
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/compress/hosts/moon/etc/ipsec.conf b/testing/tests/compress/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..b8dfae646
--- /dev/null
+++ b/testing/tests/compress/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ compress=yes
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/compress/posttest.dat b/testing/tests/compress/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/compress/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/compress/pretest.dat b/testing/tests/compress/pretest.dat
new file mode 100644
index 000000000..7d077c126
--- /dev/null
+++ b/testing/tests/compress/pretest.dat
@@ -0,0 +1,5 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/compress/test.conf b/testing/tests/compress/test.conf
new file mode 100644
index 000000000..fd33cfb57
--- /dev/null
+++ b/testing/tests/compress/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/crl-from-cache/description.txt b/testing/tests/crl-from-cache/description.txt
new file mode 100644
index 000000000..17866f572
--- /dev/null
+++ b/testing/tests/crl-from-cache/description.txt
@@ -0,0 +1,5 @@
+By setting <b>strictcrlpolicy=yes</b> a <b>strict CRL policy</b> is enforced on
+both roadwarrior <b>carol</b> and gateway <b>moon</b>. When <b>carol</b> initiates
+an IPsec connection to <b>moon</b>, both VPN endpoints find a cached CRL in
+their <b>/etc/ipsec.d/crls/</b> directories which allows them to immediately verify
+the certificate received from their peer.
diff --git a/testing/tests/crl-from-cache/evaltest.dat b/testing/tests/crl-from-cache/evaltest.dat
new file mode 100644
index 000000000..dd200c8ef
--- /dev/null
+++ b/testing/tests/crl-from-cache/evaltest.dat
@@ -0,0 +1,10 @@
+moon::cat /var/log/auth.log::loaded crl file::YES
+carol::cat /var/log/auth.log::loaded crl file::YES
+moon::cat /var/log/auth.log::X.509 certificate rejected::NO
+carol::cat /var/log/auth.log::X.509 certificate rejected::NO
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::cat /var/log/auth.log::written crl file::NO
+carol::cat /var/log/auth.log::written crl file::NO
+moon::ipsec listcrls:: ok::YES
+carol::ipsec listcrls:: ok::YES
diff --git a/testing/tests/crl-from-cache/hosts/carol/etc/ipsec.conf b/testing/tests/crl-from-cache/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..93c4d7956
--- /dev/null
+++ b/testing/tests/crl-from-cache/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+ cachecrls=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+
+conn home
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/crl-from-cache/hosts/moon/etc/ipsec.conf b/testing/tests/crl-from-cache/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..ef9237518
--- /dev/null
+++ b/testing/tests/crl-from-cache/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,36 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+ cachecrls=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn net-net
+ leftsubnet=10.1.0.0/16
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn host-host
+ right=PH_IP_SUN
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn rw
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
diff --git a/testing/tests/crl-from-cache/posttest.dat b/testing/tests/crl-from-cache/posttest.dat
new file mode 100644
index 000000000..be17847c1
--- /dev/null
+++ b/testing/tests/crl-from-cache/posttest.dat
@@ -0,0 +1,4 @@
+moon::ipsec stop
+carol::ipsec stop
+moon::rm /etc/ipsec.d/crls/*
+carol::rm /etc/ipsec.d/crls/*
diff --git a/testing/tests/crl-from-cache/pretest.dat b/testing/tests/crl-from-cache/pretest.dat
new file mode 100644
index 000000000..acdb265ed
--- /dev/null
+++ b/testing/tests/crl-from-cache/pretest.dat
@@ -0,0 +1,8 @@
+moon::wget -q http://crl.strongswan.org/strongswan.crl
+moon::mv strongswan.crl /etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl
+carol::wget -q http://crl.strongswan.org/strongswan.crl
+carol::mv strongswan.crl /etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/crl-from-cache/test.conf b/testing/tests/crl-from-cache/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/crl-from-cache/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/crl-ldap/description.txt b/testing/tests/crl-ldap/description.txt
new file mode 100644
index 000000000..02dc0cbbe
--- /dev/null
+++ b/testing/tests/crl-ldap/description.txt
@@ -0,0 +1,9 @@
+By setting <b>strictcrlpolicy=yes</b> a <b>strict CRL policy</b> is enforced on
+both roadwarrior <b>carol</b> and gateway <b>moon</b>. Thus when <b>carol</b> initiates
+the connection and only an expired CRL cache file in <b>/etc/ipsec.d/crls</b> is
+available, the Main Mode negotiation fails. A http fetch for an updated CRL fails
+because the web server is currently not reachable. Thus the second Main Mode negotiation
+fails, too. Finally an ldap fetch to get the CRL from the LDAP server <b>winnetou</b>
+is triggered. When the third Main Mode trial comes around, the fetched CRL has become
+available and the IKE negotiation completes. The new CRL is again cached locally as a
+file in <b>/etc/ipsec.d/crls</b> due to the <b>cachecrls=yes</b> option.
diff --git a/testing/tests/crl-ldap/evaltest.dat b/testing/tests/crl-ldap/evaltest.dat
new file mode 100644
index 000000000..2b98e086a
--- /dev/null
+++ b/testing/tests/crl-ldap/evaltest.dat
@@ -0,0 +1,16 @@
+moon::cat /var/log/auth.log::loaded crl file::YES
+carol::cat /var/log/auth.log::loaded crl file::YES
+moon::cat /var/log/auth.log::crl update is overdue::YES
+carol::cat /var/log/auth.log::crl update is overdue::YES
+moon::cat /var/log/auth.log::X.509 certificate rejected::YES
+carol::cat /var/log/auth.log::X.509 certificate rejected::YES
+moon::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+carol::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+moon::cat /var/log/auth.log::Trying LDAP URL::YES
+carol::cat /var/log/auth.log::Trying LDAP URL::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::cat /var/log/auth.log::written crl file::YES
+carol::cat /var/log/auth.log::written crl file::YES
+moon::ipsec listcrls:: ok::YES
+carol::ipsec listcrls:: ok::YES
diff --git a/testing/tests/crl-ldap/hosts/carol/etc/init.d/iptables b/testing/tests/crl-ldap/hosts/carol/etc/init.d/iptables
new file mode 100755
index 000000000..571459bae
--- /dev/null
+++ b/testing/tests/crl-ldap/hosts/carol/etc/init.d/iptables
@@ -0,0 +1,73 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow ldap crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 389 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 389 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/crl-ldap/hosts/carol/etc/ipsec.conf b/testing/tests/crl-ldap/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..669a47d06
--- /dev/null
+++ b/testing/tests/crl-ldap/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,31 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+ cachecrls=yes
+
+ca strongswan
+ cacert=strongswanCert.pem
+ crluri="ldap://ldap.strongswan.org/cn=strongSwan Root CA, o=Linux strongSwan, c=CH?certificateRevocationList"
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=2
+
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/crl-ldap/hosts/carol/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl b/testing/tests/crl-ldap/hosts/carol/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl
new file mode 100644
index 000000000..75e8b0959
--- /dev/null
+++ b/testing/tests/crl-ldap/hosts/carol/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl
Binary files differ
diff --git a/testing/tests/crl-ldap/hosts/moon/etc/init.d/iptables b/testing/tests/crl-ldap/hosts/moon/etc/init.d/iptables
new file mode 100755
index 000000000..8de514a2e
--- /dev/null
+++ b/testing/tests/crl-ldap/hosts/moon/etc/init.d/iptables
@@ -0,0 +1,76 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # enable IP forwarding
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow ldap crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 389 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 389 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/crl-ldap/hosts/moon/etc/ipsec.conf b/testing/tests/crl-ldap/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..d5c0dd163
--- /dev/null
+++ b/testing/tests/crl-ldap/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,42 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+ cachecrls=yes
+
+ca strongswan
+ cacert=strongswanCert.pem
+ crluri="ldap://ldap.strongswan.org/cn=strongSwan Root CA, o=Linux strongSwan, c=CH?certificateRevocationList"
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=2
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+
+conn net-net
+ leftsubnet=10.1.0.0/16
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn host-host
+ right=PH_IP_SUN
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn rw
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
diff --git a/testing/tests/crl-ldap/hosts/moon/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl b/testing/tests/crl-ldap/hosts/moon/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl
new file mode 100644
index 000000000..75e8b0959
--- /dev/null
+++ b/testing/tests/crl-ldap/hosts/moon/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl
Binary files differ
diff --git a/testing/tests/crl-ldap/posttest.dat b/testing/tests/crl-ldap/posttest.dat
new file mode 100644
index 000000000..04f762331
--- /dev/null
+++ b/testing/tests/crl-ldap/posttest.dat
@@ -0,0 +1,9 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+winnetou::/etc/init.d/slapd stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+moon::rm /etc/ipsec.d/crls/*
+carol::rm /etc/ipsec.d/crls/*
diff --git a/testing/tests/crl-ldap/pretest.dat b/testing/tests/crl-ldap/pretest.dat
new file mode 100644
index 000000000..64fae2a16
--- /dev/null
+++ b/testing/tests/crl-ldap/pretest.dat
@@ -0,0 +1,7 @@
+winnetou::/etc/init.d/slapd start
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/crl-ldap/test.conf b/testing/tests/crl-ldap/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/crl-ldap/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/crl-revoked/description.txt b/testing/tests/crl-revoked/description.txt
new file mode 100644
index 000000000..780068ce6
--- /dev/null
+++ b/testing/tests/crl-revoked/description.txt
@@ -0,0 +1,7 @@
+By setting <b>strictcrlpolicy=yes</b> a <b>strict CRL policy</b> is enforced on
+both roadwarrior <b>carol</b> and gateway <b>moon</b>. Thus when <b>carol</b> initiates
+the connection and no current CRL is available, the Main Mode negotiation fails
+and a http fetch to get the CRL from the web server <b>winnetou</b> is triggered.
+When the second Main Mode trial comes around the fetched CRL will be available
+but because the certificate presented by carol has been revoked,
+the IKE negotatiation will fail.
diff --git a/testing/tests/crl-revoked/evaltest.dat b/testing/tests/crl-revoked/evaltest.dat
new file mode 100644
index 000000000..0fd1cae8c
--- /dev/null
+++ b/testing/tests/crl-revoked/evaltest.dat
@@ -0,0 +1,6 @@
+moon::cat /var/log/auth.log::X.509 certificate rejected::YES
+moon::cat /var/log/auth.log::certificate was revoked::YES
+carol::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+moon::ipsec listcrls:: ok::YES
+moon::ipsec status::rw.*STATE_MAIN_R3.*ISAKMP SA established::NO
+carol::ipsec status::home.*STATE_MAIN_I4.*ISAKMP SA established::NO
diff --git a/testing/tests/crl-revoked/hosts/carol/etc/ipsec.conf b/testing/tests/crl-revoked/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..5a1d246a6
--- /dev/null
+++ b/testing/tests/crl-revoked/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolRevokedCert.pem
+ leftid=carol@strongswan.org
+
+conn home
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/crl-revoked/hosts/carol/etc/ipsec.d/certs/carolRevokedCert.pem b/testing/tests/crl-revoked/hosts/carol/etc/ipsec.d/certs/carolRevokedCert.pem
new file mode 100644
index 000000000..5b742fc9e
--- /dev/null
+++ b/testing/tests/crl-revoked/hosts/carol/etc/ipsec.d/certs/carolRevokedCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIBBzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjU0OFoXDTA5MDkwOTExMjU0OFowWjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAM5413q1B2EF3spcYD1u0ce9AtIHdxmU3+1E0hqV
+mLqpIQtyp4SLbrRunxpoVUuEpHWXgLb3C/ljjlKCMWWmhw4wja1rBTjMNJLPj6Bo
+5Qn4Oeuqm7/kLHPGbveQGtcSsJCk6iLqFTbq0wsji5Ogq7kmjWgQv0nM2jpofHLv
+VOAtWVSj+x2b3OHdl/WpgTgTw1HHjYo7/NOkARdTcZ2/wxxM3z1Abp9iylc45GLN
+IL/OzHkT8b5pdokdMvVijz8IslkkewJYXrVQaCNMZg/ydlXOOAEKz0YqnvXQaYs5
+K+s8XvQ2RFCr5oO0fRT2VbiI9TgHnbcnfUi25iHl6txsXg0CAwEAAaOCAQYwggEC
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBTbA2TH3ca8tgCGkYy9
+OV/MqUTHAzBtBgNVHSMEZjBkgBRdp91wBlEyfue2bbO15eBg6i5N76FJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBADAfBgNVHREEGDAWgRRjYXJvbEBzdHJvbmdz
+d2FuLm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u
+b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQC9acuCUPEBOrWB
+56vS8N9bksQwv/XcYIFYqV73kFBAzOPLX2a9igFGvBPdCxFu/t8JCswzE6to4LFM
+2+6Z2QJf442CLPcJKxITahrjJXSxGbzMlmaDvZ5wFCJAlyin+yuInpTwl8rMZe/Q
+O5JeJjzGDgWJtnGdkLUk/l2r6sZ/Cmk5rZpuO0hcUHVztMLQYPzqTpuMvC5p4JzL
+LWGWhKRhJs53NmxXXodck/ZgaqiTWuQFYlbamJRvzVBfX7c1SWHRJvxSSOPKGIg3
+wphkO2naj/SQD+BNuWTRmZ9YCiLOQ64ybLpJzRZISETdqtLBPKsIqosUZwkxlR1N
+9IcgYi5x
+-----END CERTIFICATE-----
diff --git a/testing/tests/crl-revoked/hosts/carol/etc/ipsec.d/private/carolRevokedKey.pem b/testing/tests/crl-revoked/hosts/carol/etc/ipsec.d/private/carolRevokedKey.pem
new file mode 100644
index 000000000..8aefcc5a6
--- /dev/null
+++ b/testing/tests/crl-revoked/hosts/carol/etc/ipsec.d/private/carolRevokedKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAznjXerUHYQXeylxgPW7Rx70C0gd3GZTf7UTSGpWYuqkhC3Kn
+hItutG6fGmhVS4SkdZeAtvcL+WOOUoIxZaaHDjCNrWsFOMw0ks+PoGjlCfg566qb
+v+Qsc8Zu95Aa1xKwkKTqIuoVNurTCyOLk6CruSaNaBC/SczaOmh8cu9U4C1ZVKP7
+HZvc4d2X9amBOBPDUceNijv806QBF1Nxnb/DHEzfPUBun2LKVzjkYs0gv87MeRPx
+vml2iR0y9WKPPwiyWSR7AlhetVBoI0xmD/J2Vc44AQrPRiqe9dBpizkr6zxe9DZE
+UKvmg7R9FPZVuIj1OAedtyd9SLbmIeXq3GxeDQIDAQABAoIBAAUdyXko8z3cP2EU
+WO4syNYCQQejV7gykDn48pvmCRrXBhKajLwkGGIwO5ET9MkiSFEBqBbgmFNdvDEf
+OMokDkSzv08Ez+RQax0YN57p+oL8u7KzT5i5tsBHsog/8epSdD2hWIv08QGjYAdu
+og7OdHLqGabyg0r44I+B91OBysCjU51rDdkhz59AmURdEIJV5xhuGojFM68jaNm2
+MUxDfDuCsRIydjAP0VTUTAUxD4/S5I+jt/GK9aRsEeRH9Q3011iTGMR9viAUBhq/
+khkWNltg9lkOqO7LpnNku4sSv3v4CWge7/T+4RR2vZgv1oSs4ox2UKYoqIqiYIfx
+uUcnqQECgYEA+LPiRMoXvlssQWlaFc2k4xga0efs+mWeLglDdc3R3fBEibP/AU07
+a576AgvUJtkI50/WNGKT73O+VtxcXn/N646m/8OtqNXuVKKjsxxNOZEKdO8aOdbt
+7lM5WepNiQeaKAFudUxpUiZQx8LCKSsNDiJZKWBu6xAG2O5X32VMZvUCgYEA1Ie+
+rNa490PSC1ym7WbmdAjvGmSOn2GOBfO7BECsPZstccU7D5pZl/89fTfn1TDKP49Y
+ScVOuFz7f/u6UJpb/WzI71RXEQOdojLWmF2HDx5osRi3hXEJa20fbPq6DQXCJ8pf
+IF37AEqAY4UNSNic0Cw+rGHdWPQhDNXhFWpdu7kCgYEAmv4oNmyoDXbuhrlsbggi
+CXE9TbG3a3mm8dPOGf2yHBmf7R2i/6GtNW33Kw1KIwfBV77WpQEGZwWACsv8ONx3
+baUSiHTfpkfk5xQQ5w/tRMISfTuB4agD0jJFnLa7qXl2ZhY2S53aSVsdntDOhi+R
+TEy1umah2Za8Xbd0RgHwcn0CgYEAl9Hgg9dfikMIaNVm6W/4cCtxoojy2Sf3LIlP
+r1oDsH6JmBwsdJjuJ4ZNhoXJNqID2COuDgTEly7U+jf4gFvEGuT7JPw6tgy/Ln7i
+jTVCpaozX08oykpVUEhDirYQ8fyLFaGbEqQQCcUusej59G/IlW0F2F6QoFrEwUaH
+46R4EQECgYBEZ7edMkj3dmJH1wxQjp5GJNbrJkS8IKvzza0mDTJdz33CgEX9Oyva
+o2iEkDVpvj2SEy28ewt22IRptWKH/3bQfxSCcRV6JFNt3+LongMshRYqq1leqrKa
+9fnQVtfTIbIVXwjTZap6BL8R66OeFtexsSFRfDF/8P4n2oF4zmn4qA==
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/crl-revoked/hosts/carol/etc/ipsec.secrets b/testing/tests/crl-revoked/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..8e31be4cb
--- /dev/null
+++ b/testing/tests/crl-revoked/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA carolRevokedKey.pem
diff --git a/testing/tests/crl-revoked/hosts/moon/etc/ipsec.conf b/testing/tests/crl-revoked/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..a8953f557
--- /dev/null
+++ b/testing/tests/crl-revoked/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,35 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn net-net
+ leftsubnet=10.1.0.0/16
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn host-host
+ right=PH_IP_SUN
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn rw
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
diff --git a/testing/tests/crl-revoked/posttest.dat b/testing/tests/crl-revoked/posttest.dat
new file mode 100644
index 000000000..d742e8410
--- /dev/null
+++ b/testing/tests/crl-revoked/posttest.dat
@@ -0,0 +1,4 @@
+moon::ipsec stop
+carol::ipsec stop
+carol::rm /etc/ipsec.d/private/*
+carol::rm /etc/ipsec.d/certs/*
diff --git a/testing/tests/crl-revoked/pretest.dat b/testing/tests/crl-revoked/pretest.dat
new file mode 100644
index 000000000..d92333d86
--- /dev/null
+++ b/testing/tests/crl-revoked/pretest.dat
@@ -0,0 +1,4 @@
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/crl-revoked/test.conf b/testing/tests/crl-revoked/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/crl-revoked/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/crl-strict/description.txt b/testing/tests/crl-strict/description.txt
new file mode 100644
index 000000000..97011482e
--- /dev/null
+++ b/testing/tests/crl-strict/description.txt
@@ -0,0 +1,6 @@
+By setting <b>strictcrlpolicy=yes</b> a <b>strict CRL policy</b> is enforced on
+both roadwarrior <b>carol</b> and gateway <b>moon</b>. Thus when <b>carol</b> initiates
+the connection and no current CRL is available, the Main Mode negotiation fails
+but a http fetch to get the CRL from the web server <b>winnetou</b> is triggered.
+When the second Main Mode trial comes around, the fetched CRL will be available
+and the IKE negotiation completes.
diff --git a/testing/tests/crl-strict/evaltest.dat b/testing/tests/crl-strict/evaltest.dat
new file mode 100644
index 000000000..1d7adb05e
--- /dev/null
+++ b/testing/tests/crl-strict/evaltest.dat
@@ -0,0 +1,8 @@
+moon::cat /var/log/auth.log::X.509 certificate rejected::YES
+carol::cat /var/log/auth.log::X.509 certificate rejected::YES
+moon::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+carol::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec listcrls:: ok::YES
+carol::ipsec listcrls:: ok::YES
diff --git a/testing/tests/crl-strict/hosts/carol/etc/ipsec.conf b/testing/tests/crl-strict/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..6d0aee86a
--- /dev/null
+++ b/testing/tests/crl-strict/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+
+conn home
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/crl-strict/hosts/moon/etc/ipsec.conf b/testing/tests/crl-strict/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..a8953f557
--- /dev/null
+++ b/testing/tests/crl-strict/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,35 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn net-net
+ leftsubnet=10.1.0.0/16
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn host-host
+ right=PH_IP_SUN
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn rw
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
diff --git a/testing/tests/crl-strict/posttest.dat b/testing/tests/crl-strict/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/crl-strict/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/crl-strict/pretest.dat b/testing/tests/crl-strict/pretest.dat
new file mode 100644
index 000000000..d92333d86
--- /dev/null
+++ b/testing/tests/crl-strict/pretest.dat
@@ -0,0 +1,4 @@
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/crl-strict/test.conf b/testing/tests/crl-strict/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/crl-strict/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/crl-to-cache/description.txt b/testing/tests/crl-to-cache/description.txt
new file mode 100644
index 000000000..9f542e73d
--- /dev/null
+++ b/testing/tests/crl-to-cache/description.txt
@@ -0,0 +1,6 @@
+By setting <b>cachecrls=yes</b> in ipsec.conf, a copy of the CRL fetched
+via http from the web server <b>winnetou</b> is saved locally in the
+directory <b>/etc/ipsec.d/crls</b> on both the roadwarrior <b>carol</b>
+and the gateway <b>moon</b> when the IPsec connection is set up. The
+<b>subjectKeyIdentifier</b> of the issuing CA plus the suffix <b>.crl</b>
+is used as a unique filename for the cached CRL.
diff --git a/testing/tests/crl-to-cache/evaltest.dat b/testing/tests/crl-to-cache/evaltest.dat
new file mode 100644
index 000000000..be7737185
--- /dev/null
+++ b/testing/tests/crl-to-cache/evaltest.dat
@@ -0,0 +1,4 @@
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::cat /var/log/auth.log::written crl file.*/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl::YES
+carol::cat /var/log/auth.log::written crl file.*/etc/ipsec.d/crls/5da7dd700651327ee7b66db3b5e5e060ea2e4def.crl::YES
diff --git a/testing/tests/crl-to-cache/hosts/carol/etc/ipsec.conf b/testing/tests/crl-to-cache/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..955f08b1f
--- /dev/null
+++ b/testing/tests/crl-to-cache/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ cachecrls=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+
+conn home
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/crl-to-cache/hosts/moon/etc/ipsec.conf b/testing/tests/crl-to-cache/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..885354ab5
--- /dev/null
+++ b/testing/tests/crl-to-cache/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,23 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ cachecrls=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn rw
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
diff --git a/testing/tests/crl-to-cache/posttest.dat b/testing/tests/crl-to-cache/posttest.dat
new file mode 100644
index 000000000..be17847c1
--- /dev/null
+++ b/testing/tests/crl-to-cache/posttest.dat
@@ -0,0 +1,4 @@
+moon::ipsec stop
+carol::ipsec stop
+moon::rm /etc/ipsec.d/crls/*
+carol::rm /etc/ipsec.d/crls/*
diff --git a/testing/tests/crl-to-cache/pretest.dat b/testing/tests/crl-to-cache/pretest.dat
new file mode 100644
index 000000000..d92333d86
--- /dev/null
+++ b/testing/tests/crl-to-cache/pretest.dat
@@ -0,0 +1,4 @@
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/crl-to-cache/test.conf b/testing/tests/crl-to-cache/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/crl-to-cache/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/default-keys/description.txt b/testing/tests/default-keys/description.txt
new file mode 100644
index 000000000..639e909da
--- /dev/null
+++ b/testing/tests/default-keys/description.txt
@@ -0,0 +1,8 @@
+Because of the missing <b>/etc/ipsec.secrets</b> file, roadwarrior <b>carol</b>
+and gateway <b>moon</b> each automatically generate a PKCS#1 RSA private key
+and a self-signed X.509 certificate. Because the UML testing environment does
+not offer enough entropy, the non-blocking /dev/urandom device is used in place
+of /dev/random for generating the random primes.
+<p>
+The self-signed certificates are then distributed to the peers via scp
+and are used to set up a road warrior connection initiated by <b>carol</b>
diff --git a/testing/tests/default-keys/evaltest.dat b/testing/tests/default-keys/evaltest.dat
new file mode 100644
index 000000000..f190d7066
--- /dev/null
+++ b/testing/tests/default-keys/evaltest.dat
@@ -0,0 +1,7 @@
+carol::cat /var/log/auth.log::we have a cert but are not sending it::YES
+moon::cat /var/log/auth.log::we have a cert but are not sending it::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::carol.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/default-keys/hosts/carol/etc/ipsec.conf b/testing/tests/default-keys/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..c4bb10a65
--- /dev/null
+++ b/testing/tests/default-keys/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=0
+ strictcrlpolicy=no
+ nocrsend=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=selfCert.der
+ leftsendcert=never
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightcert=peerCert.der
+ auto=add
diff --git a/testing/tests/default-keys/hosts/moon/etc/init.d/iptables b/testing/tests/default-keys/hosts/moon/etc/init.d/iptables
new file mode 100755
index 000000000..13ad3063f
--- /dev/null
+++ b/testing/tests/default-keys/hosts/moon/etc/init.d/iptables
@@ -0,0 +1,78 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # enable IP forwarding
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A INPUT -p tcp --sport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/default-keys/hosts/moon/etc/ipsec.conf b/testing/tests/default-keys/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..eeeec645b
--- /dev/null
+++ b/testing/tests/default-keys/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,27 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=0
+ strictcrlpolicy=no
+ nocrsend=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn carol
+ left=192.168.0.1
+ leftnexthop=%direct
+ leftcert=selfCert.der
+ leftsendcert=never
+ leftfirewall=yes
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightcert=peerCert.der
+ auto=add
+
diff --git a/testing/tests/default-keys/posttest.dat b/testing/tests/default-keys/posttest.dat
new file mode 100644
index 000000000..52b48b9ef
--- /dev/null
+++ b/testing/tests/default-keys/posttest.dat
@@ -0,0 +1,10 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+carol::rm /etc/ipsec.d/private/*
+carol::rm /etc/ipsec.d/certs/*
+moon::rm /etc/ipsec.d/private/*
+moon::rm /etc/ipsec.d/certs/*
diff --git a/testing/tests/default-keys/pretest.dat b/testing/tests/default-keys/pretest.dat
new file mode 100644
index 000000000..54f70cbe9
--- /dev/null
+++ b/testing/tests/default-keys/pretest.dat
@@ -0,0 +1,18 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::rm /etc/ipsec.secrets
+carol::rm /etc/ipsec.d/private/*
+carol::rm /etc/ipsec.d/certs/*
+carol::rm /etc/ipsec.d/cacerts/*
+carol::ipsec start
+moon::rm /etc/ipsec.secrets
+moon::rm /etc/ipsec.d/private/*
+moon::rm /etc/ipsec.d/certs/*
+moon::rm /etc/ipsec.d/cacerts/*
+moon::ipsec start
+moon::sleep 4
+moon::scp /etc/ipsec.d/certs/selfCert.der carol:/etc/ipsec.d/certs/peerCert.der
+moon::scp carol:/etc/ipsec.d/certs/selfCert.der /etc/ipsec.d/certs/peerCert.der
+moon::ipsec reload
+carol::ipsec reload
+carol::ipsec up home
diff --git a/testing/tests/default-keys/test.conf b/testing/tests/default-keys/test.conf
new file mode 100644
index 000000000..0baa48d90
--- /dev/null
+++ b/testing/tests/default-keys/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/double-nat-net/description.txt b/testing/tests/double-nat-net/description.txt
new file mode 100644
index 000000000..ff09155f6
--- /dev/null
+++ b/testing/tests/double-nat-net/description.txt
@@ -0,0 +1,7 @@
+The roadwarrior <b>alice</b> sitting behind the NAT router <b>moon</b> sets up a
+tunnel to the subnet hiding behind the NAT router <b>sun</b>. All IKE and ESP traffic
+directed to the router <b>sun</b> is forwarded to the VPN gateway <b>bob</b>
+using destination NAT. UDP encapsulation is used to traverse the NAT routers.
+<b>leftfirewall=yes</b> automatically inserts iptables-based firewall rules that
+let pass the tunneled traffic. In order to test the double NAT-ed IPsec
+tunnel <b>alice</b> pings the inner IP address of the router <b>sun</b>.
diff --git a/testing/tests/double-nat-net/evaltest.dat b/testing/tests/double-nat-net/evaltest.dat
new file mode 100644
index 000000000..41eba6501
--- /dev/null
+++ b/testing/tests/double-nat-net/evaltest.dat
@@ -0,0 +1,5 @@
+alice::ipsec status::nat-t.*STATE_QUICK_I2.*IPsec SA established::YES
+bob::ipsec status::nat-t.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP1_SUN::64 bytes from PH_IP1_SUN: icmp_seq=1::YES
+moon::tcpdump::IP moon.strongswan.org.* > sun.strongswan.org.ipsec-nat-t: UDP::YES
+moon::tcpdump::IP sun.strongswan.org.ipsec-nat-t > moon.strongswan.org.*: UDP::YES
diff --git a/testing/tests/double-nat-net/hosts/alice/etc/ipsec.conf b/testing/tests/double-nat-net/hosts/alice/etc/ipsec.conf
new file mode 100755
index 000000000..395e62e7c
--- /dev/null
+++ b/testing/tests/double-nat-net/hosts/alice/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn nat-t
+ left=%defaultroute
+ leftcert=aliceCert.pem
+ leftid=alice@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightid=bob@strongswan.org
+ rightsubnet=10.2.0.0/16
+ auto=add
diff --git a/testing/tests/double-nat-net/hosts/bob/etc/ipsec.conf b/testing/tests/double-nat-net/hosts/bob/etc/ipsec.conf
new file mode 100755
index 000000000..6927a5ce4
--- /dev/null
+++ b/testing/tests/double-nat-net/hosts/bob/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn nat-t
+ left=%defaultroute
+ leftsubnet=10.2.0.0/16
+ leftcert=bobCert.pem
+ leftid=bob@strongswan.org
+ leftfirewall=yes
+ right=%any
+ rightsubnetwithin=10.1.0.0/16
+ auto=add
diff --git a/testing/tests/double-nat-net/posttest.dat b/testing/tests/double-nat-net/posttest.dat
new file mode 100644
index 000000000..0eb2c0d6c
--- /dev/null
+++ b/testing/tests/double-nat-net/posttest.dat
@@ -0,0 +1,9 @@
+alice::iptables -v -n -L
+bob::iptables -v -n -L
+bob::ipsec stop
+alice::ipsec stop
+alice::/etc/init.d/iptables stop 2> /dev/null
+bob::/etc/init.d/iptables stop 2> /dev/null
+moon::iptables -t nat -F
+sun::iptables -t nat -F
+sun::ip route del 10.1.0.0/16 via PH_IP_BOB
diff --git a/testing/tests/double-nat-net/pretest.dat b/testing/tests/double-nat-net/pretest.dat
new file mode 100644
index 000000000..84bc15092
--- /dev/null
+++ b/testing/tests/double-nat-net/pretest.dat
@@ -0,0 +1,15 @@
+alice::/etc/init.d/iptables start 2> /dev/null
+bob::/etc/init.d/iptables start 2> /dev/null
+bob::echo 1 > /proc/sys/net/ipv4/ip_forward
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+sun::echo 1 > /proc/sys/net/ipv4/ip_forward
+moon::iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p udp -j SNAT --to-source PH_IP_MOON:1024-1100
+moon::iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p tcp -j SNAT --to-source PH_IP_MOON:2000-2100
+sun::iptables -t nat -A POSTROUTING -o eth0 -s 10.2.0.0/16 -p tcp -j SNAT --to-source PH_IP_SUN:2000-2100
+sun::iptables -t nat -A PREROUTING -i eth0 -s PH_IP_MOON -p udp -j DNAT --to-destination PH_IP_BOB
+sun::ip route add 10.1.0.0/16 via PH_IP_BOB
+alice::ipsec start
+bob::ipsec start
+alice::sleep 2
+alice::ipsec up nat-t
+
diff --git a/testing/tests/double-nat-net/test.conf b/testing/tests/double-nat-net/test.conf
new file mode 100644
index 000000000..1ca2ffe5a
--- /dev/null
+++ b/testing/tests/double-nat-net/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="alice bob"
diff --git a/testing/tests/double-nat/description.txt b/testing/tests/double-nat/description.txt
new file mode 100644
index 000000000..ce7de0e56
--- /dev/null
+++ b/testing/tests/double-nat/description.txt
@@ -0,0 +1,5 @@
+The roadwarrior <b>alice</b> sitting behind the NAT router <b>moon</b> sets up a tunnel to
+the peer <b>bob</b> hiding behind the NAT router <b>sun</b>. UDP encapsulation is used to
+traverse the NAT routers. <b>leftfirewall=yes</b> automatically inserts iptables-based
+firewall rules that let pass the tunneled traffic. In order to test the double NAT-ed IPsec
+tunnel <b>alice</b> pings <b>bob</b>.
diff --git a/testing/tests/double-nat/evaltest.dat b/testing/tests/double-nat/evaltest.dat
new file mode 100644
index 000000000..05e751422
--- /dev/null
+++ b/testing/tests/double-nat/evaltest.dat
@@ -0,0 +1,5 @@
+alice::ipsec status::nat-t.*STATE_QUICK_I2.*IPsec SA established::YES
+bob::ipsec status::nat-t.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+moon::tcpdump::IP moon.strongswan.org.* > sun.strongswan.org.ipsec-nat-t: UDP::YES
+moon::tcpdump::IP sun.strongswan.org.ipsec-nat-t > moon.strongswan.org.*: UDP::YES
diff --git a/testing/tests/double-nat/hosts/alice/etc/ipsec.conf b/testing/tests/double-nat/hosts/alice/etc/ipsec.conf
new file mode 100755
index 000000000..5b3cddb63
--- /dev/null
+++ b/testing/tests/double-nat/hosts/alice/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn nat-t
+ left=%defaultroute
+ leftcert=aliceCert.pem
+ leftid=alice@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightid=bob@strongswan.org
+ rightsubnet=PH_IP_BOB/32
+ auto=add
diff --git a/testing/tests/double-nat/posttest.dat b/testing/tests/double-nat/posttest.dat
new file mode 100644
index 000000000..07f22d07d
--- /dev/null
+++ b/testing/tests/double-nat/posttest.dat
@@ -0,0 +1,8 @@
+alice::iptables -v -n -L
+bob::iptables -v -n -L
+bob::ipsec stop
+alice::ipsec stop
+alice::/etc/init.d/iptables stop 2> /dev/null
+bob::/etc/init.d/iptables stop 2> /dev/null
+moon::iptables -t nat -F
+sun::iptables -t nat -F
diff --git a/testing/tests/double-nat/pretest.dat b/testing/tests/double-nat/pretest.dat
new file mode 100644
index 000000000..cf495b778
--- /dev/null
+++ b/testing/tests/double-nat/pretest.dat
@@ -0,0 +1,13 @@
+alice::/etc/init.d/iptables start 2> /dev/null
+bob::/etc/init.d/iptables start 2> /dev/null
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+sun::echo 1 > /proc/sys/net/ipv4/ip_forward
+moon::iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p udp -j SNAT --to-source PH_IP_MOON:1024-1100
+moon::iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p tcp -j SNAT --to-source PH_IP_MOON:2000-2100
+sun::iptables -t nat -A POSTROUTING -o eth0 -s 10.2.0.0/16 -p tcp -j SNAT --to-source PH_IP_SUN:2000-2100
+sun::iptables -t nat -A PREROUTING -i eth0 -s PH_IP_MOON -p udp -j DNAT --to-destination PH_IP_BOB
+alice::ipsec start
+bob::ipsec start
+alice::sleep 2
+alice::ipsec up nat-t
+
diff --git a/testing/tests/double-nat/test.conf b/testing/tests/double-nat/test.conf
new file mode 100644
index 000000000..1ca2ffe5a
--- /dev/null
+++ b/testing/tests/double-nat/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="alice bob"
diff --git a/testing/tests/dpd-clear/description.txt b/testing/tests/dpd-clear/description.txt
new file mode 100644
index 000000000..f76b2d741
--- /dev/null
+++ b/testing/tests/dpd-clear/description.txt
@@ -0,0 +1,5 @@
+The roadwarrior <b>carol</b> sets up an IPsec tunnel connection to the gateway <b>moon</b>
+which in turn activates <b>Dead Peer Detection</b> (DPD) with a polling interval of 10 s.
+When the network connectivity between <b>carol</b> and <b>moon</b> is forcefully disrupted,
+<b>moon</b> clears the connection after the configured timeout of 30 s.
+
diff --git a/testing/tests/dpd-clear/evaltest.dat b/testing/tests/dpd-clear/evaltest.dat
new file mode 100644
index 000000000..98d5b146b
--- /dev/null
+++ b/testing/tests/dpd-clear/evaltest.dat
@@ -0,0 +1,7 @@
+carol::ipsec status::STATE_MAIN_I4 (ISAKMP SA established)::YES
+carol::iptables -A INPUT -i eth0 -s PH_IP_MOON -j DROP::no output expected::NO
+moon::sleep 50::no output expected::NO
+moon::cat /var/log/auth.log::inserting event EVENT_DPD::YES
+moon::cat /var/log/auth.log::DPD: No response from peer - declaring peer dead::YES
+moon::cat /var/log/auth.log::DPD: Terminating all SAs using this connection::YES
+moon::cat /var/log/auth.log::DPD: Clearing connection::YES
diff --git a/testing/tests/dpd-clear/hosts/moon/etc/ipsec.conf b/testing/tests/dpd-clear/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..cac521c8f
--- /dev/null
+++ b/testing/tests/dpd-clear/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,30 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ dpdaction=clear
+ dpddelay=10
+ dpdtimeout=30
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
+
+
+
diff --git a/testing/tests/dpd-clear/posttest.dat b/testing/tests/dpd-clear/posttest.dat
new file mode 100644
index 000000000..931db4272
--- /dev/null
+++ b/testing/tests/dpd-clear/posttest.dat
@@ -0,0 +1,3 @@
+carol::iptables -D INPUT -i eth0 -s PH_IP_MOON -j DROP
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/dpd-clear/pretest.dat b/testing/tests/dpd-clear/pretest.dat
new file mode 100644
index 000000000..14ed95322
--- /dev/null
+++ b/testing/tests/dpd-clear/pretest.dat
@@ -0,0 +1,4 @@
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/dpd-clear/test.conf b/testing/tests/dpd-clear/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/dpd-clear/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/esp-ah-transport/description.txt b/testing/tests/esp-ah-transport/description.txt
new file mode 100644
index 000000000..c7918fa38
--- /dev/null
+++ b/testing/tests/esp-ah-transport/description.txt
@@ -0,0 +1,5 @@
+In IKE phase 2 the roadwarrior <b>carol</b> proposes to gateway <b>moon</b>
+the ESP AES 128 bit encryption algorithm combined with AH SHA-1 authentication.
+In order to accept the AH and ESP encapsulated plaintext packets, the iptables firewall
+marks all incoming AH packets with the ESP mark. The transport mode connection is
+tested by <b>carol</b> sending a ping to gateway <b>moon</b>.
diff --git a/testing/tests/esp-ah-transport/evaltest.dat b/testing/tests/esp-ah-transport/evaltest.dat
new file mode 100644
index 000000000..7c498ad83
--- /dev/null
+++ b/testing/tests/esp-ah-transport/evaltest.dat
@@ -0,0 +1,8 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec statusall::ESP algorithm newest: AES_128-;::YES
+moon::ipsec statusall::ESP algorithm newest: AES_128-;::YES
+carol::ping -c 1 -s 120 -p deadbeef PH_IP_MOON::128 bytes from PH_IP_MOON: icmp_seq=1::YES
+carol::ipsec status::ah\..*ah\..*esp\..*ago.*esp\..*ago.*transport::YES
+moon::ipsec status::ah\..*ah\..*esp\..*ago.*esp\..*ago.*transport::YES
+moon::tcpdump::AH.*ESP::YES
diff --git a/testing/tests/esp-ah-transport/hosts/carol/etc/init.d/iptables b/testing/tests/esp-ah-transport/hosts/carol/etc/init.d/iptables
new file mode 100755
index 000000000..8c8817539
--- /dev/null
+++ b/testing/tests/esp-ah-transport/hosts/carol/etc/init.d/iptables
@@ -0,0 +1,73 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow AH
+ iptables -A INPUT -i eth0 -p 51 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 51 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/esp-ah-transport/hosts/carol/etc/ipsec.conf b/testing/tests/esp-ah-transport/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..13ab3e07f
--- /dev/null
+++ b/testing/tests/esp-ah-transport/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,28 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ auth=ah
+ ike=aes128-sha
+ esp=aes128-sha1
+
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+ type=transport
+ auto=add
diff --git a/testing/tests/esp-ah-transport/hosts/moon/etc/init.d/iptables b/testing/tests/esp-ah-transport/hosts/moon/etc/init.d/iptables
new file mode 100755
index 000000000..3e8922581
--- /dev/null
+++ b/testing/tests/esp-ah-transport/hosts/moon/etc/init.d/iptables
@@ -0,0 +1,76 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # enable IP forwarding
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow AH
+ iptables -A INPUT -i eth0 -p 51 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 51 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/esp-ah-transport/hosts/moon/etc/ipsec.conf b/testing/tests/esp-ah-transport/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..809f3c74b
--- /dev/null
+++ b/testing/tests/esp-ah-transport/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,28 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ auth=ah
+ ike=aes128-sha
+ esp=aes128-sha1
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ right=%any
+ rightid=carol@strongswan.org
+ type=transport
+ auto=add
diff --git a/testing/tests/esp-ah-transport/posttest.dat b/testing/tests/esp-ah-transport/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/esp-ah-transport/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/esp-ah-transport/pretest.dat b/testing/tests/esp-ah-transport/pretest.dat
new file mode 100644
index 000000000..bd68efb0b
--- /dev/null
+++ b/testing/tests/esp-ah-transport/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+moon::ipsec start
+sleep 2
+carol::ipsec up home
diff --git a/testing/tests/esp-ah-transport/test.conf b/testing/tests/esp-ah-transport/test.conf
new file mode 100644
index 000000000..fd33cfb57
--- /dev/null
+++ b/testing/tests/esp-ah-transport/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/esp-ah-tunnel/description.txt b/testing/tests/esp-ah-tunnel/description.txt
new file mode 100644
index 000000000..809f28c57
--- /dev/null
+++ b/testing/tests/esp-ah-tunnel/description.txt
@@ -0,0 +1,6 @@
+In IKE phase 2 the roadwarrior <b>carol</b> proposes to gateway <b>moon</b>
+the ESP AES 128 bit encryption algorithm combined with AH SHA-1 authentication.
+In order to accept the AH and ESP encapsulated plaintext packets, the iptables firewall
+marks all incoming AH packets with the ESP mark. The tunnel mode connection is
+tested by <b>carol</b> sending a ping to client <b>alice</b> hiding behind
+gateway <b>moon</b>.
diff --git a/testing/tests/esp-ah-tunnel/evaltest.dat b/testing/tests/esp-ah-tunnel/evaltest.dat
new file mode 100644
index 000000000..8f4a99641
--- /dev/null
+++ b/testing/tests/esp-ah-tunnel/evaltest.dat
@@ -0,0 +1,8 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec statusall::ESP algorithm newest: AES_128-;::YES
+moon::ipsec statusall::ESP algorithm newest: AES_128-;::YES
+carol::ping -c 1 -s 120 -p deadbeef PH_IP_ALICE::128 bytes from PH_IP_ALICE: icmp_seq=1::YES
+carol::ipsec status::ah\..*ah\..*esp\..*ago.*esp\..*ago.*tunnel::YES
+moon::ipsec status::ah\..*ah\..*esp\..*ago.*esp\..*ago.*tunnel::YES
+moon::tcpdump::AH.*ESP::YES
diff --git a/testing/tests/esp-ah-tunnel/hosts/carol/etc/init.d/iptables b/testing/tests/esp-ah-tunnel/hosts/carol/etc/init.d/iptables
new file mode 100755
index 000000000..8c8817539
--- /dev/null
+++ b/testing/tests/esp-ah-tunnel/hosts/carol/etc/init.d/iptables
@@ -0,0 +1,73 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow AH
+ iptables -A INPUT -i eth0 -p 51 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 51 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/esp-ah-tunnel/hosts/carol/etc/ipsec.conf b/testing/tests/esp-ah-tunnel/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..98cdaab7a
--- /dev/null
+++ b/testing/tests/esp-ah-tunnel/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,28 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ auth=ah
+ ike=aes128-sha
+ esp=aes128-sha1
+
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/esp-ah-tunnel/hosts/moon/etc/init.d/iptables b/testing/tests/esp-ah-tunnel/hosts/moon/etc/init.d/iptables
new file mode 100755
index 000000000..3e8922581
--- /dev/null
+++ b/testing/tests/esp-ah-tunnel/hosts/moon/etc/init.d/iptables
@@ -0,0 +1,76 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # enable IP forwarding
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow AH
+ iptables -A INPUT -i eth0 -p 51 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 51 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/esp-ah-tunnel/hosts/moon/etc/ipsec.conf b/testing/tests/esp-ah-tunnel/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..7f976376d
--- /dev/null
+++ b/testing/tests/esp-ah-tunnel/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,28 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ auth=ah
+ ike=aes128-sha
+ esp=aes128-sha1
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ leftfirewall=yes
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/esp-ah-tunnel/posttest.dat b/testing/tests/esp-ah-tunnel/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/esp-ah-tunnel/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/esp-ah-tunnel/pretest.dat b/testing/tests/esp-ah-tunnel/pretest.dat
new file mode 100644
index 000000000..bd68efb0b
--- /dev/null
+++ b/testing/tests/esp-ah-tunnel/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+moon::ipsec start
+sleep 2
+carol::ipsec up home
diff --git a/testing/tests/esp-ah-tunnel/test.conf b/testing/tests/esp-ah-tunnel/test.conf
new file mode 100644
index 000000000..fd33cfb57
--- /dev/null
+++ b/testing/tests/esp-ah-tunnel/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/esp-alg-des/description.txt b/testing/tests/esp-alg-des/description.txt
new file mode 100644
index 000000000..9546569dd
--- /dev/null
+++ b/testing/tests/esp-alg-des/description.txt
@@ -0,0 +1,5 @@
+In IKE phase 2 the roadwarrior <b>carol</b> proposes to gateway <b>moon</b>
+the ESP 1DES encryption algorithm with MD5 authentication. <b>moon</b> must
+explicitly accept the choice of this insecure algorithm by setting the strict
+flag '!' in <b>esp=des-md5!</b>. The tunnel is tested by <b>carol</b>
+sending a ping to client <b>alice</b> behind gateway <b>moon</b>.
diff --git a/testing/tests/esp-alg-des/evaltest.dat b/testing/tests/esp-alg-des/evaltest.dat
new file mode 100644
index 000000000..8e06392f1
--- /dev/null
+++ b/testing/tests/esp-alg-des/evaltest.dat
@@ -0,0 +1,6 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec statusall::ESP algorithm newest: DES_0-HMAC_MD5::YES
+carol::ipsec statusall::ESP algorithm newest: DES_0-HMAC_MD5::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+
diff --git a/testing/tests/esp-alg-des/hosts/carol/etc/ipsec.conf b/testing/tests/esp-alg-des/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..b4f067b6d
--- /dev/null
+++ b/testing/tests/esp-alg-des/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=3des-md5-modp1024!
+ esp=des-md5!
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-des/hosts/moon/etc/ipsec.conf b/testing/tests/esp-alg-des/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..9513f810d
--- /dev/null
+++ b/testing/tests/esp-alg-des/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=3des-md5-modp1024!
+ esp=des-md5!
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-des/posttest.dat b/testing/tests/esp-alg-des/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/esp-alg-des/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/esp-alg-des/pretest.dat b/testing/tests/esp-alg-des/pretest.dat
new file mode 100644
index 000000000..7d077c126
--- /dev/null
+++ b/testing/tests/esp-alg-des/pretest.dat
@@ -0,0 +1,5 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/esp-alg-des/test.conf b/testing/tests/esp-alg-des/test.conf
new file mode 100644
index 000000000..a6c8f026c
--- /dev/null
+++ b/testing/tests/esp-alg-des/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/esp-alg-null/description.txt b/testing/tests/esp-alg-null/description.txt
new file mode 100644
index 000000000..7880a799c
--- /dev/null
+++ b/testing/tests/esp-alg-null/description.txt
@@ -0,0 +1,5 @@
+In IKE phase 2 the roadwarrior <b>carol</b> proposes to gateway <b>moon</b>
+the ESP NULL encryption algorithm with SHA-1 authentication. <b>moon</b> must
+explicitly accept the choice of this insecure algorithm by setting the strict
+flag '!' in <b>esp=null-sha1!</b>. The tunnel is tested by <b>carol</b>
+sending a ping to client <b>alice</b> behind gateway <b>moon</b>.
diff --git a/testing/tests/esp-alg-null/evaltest.dat b/testing/tests/esp-alg-null/evaltest.dat
new file mode 100644
index 000000000..de2f2a571
--- /dev/null
+++ b/testing/tests/esp-alg-null/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec statusall::ESP algorithm newest::NULL_0-HMAC_SHA1::YES
+carol::ipsec statusall::ESP algorithm newest::NULL_0-HMAC_SHA1::YES
+carol::ping -c 1 -s 120 -p deadbeef PH_IP_ALICE::128 bytes from PH_IP_ALICE: icmp_seq=1::YES
diff --git a/testing/tests/esp-alg-null/hosts/carol/etc/ipsec.conf b/testing/tests/esp-alg-null/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..b732eba93
--- /dev/null
+++ b/testing/tests/esp-alg-null/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=aes-128-sha
+ esp=null-sha1!
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-null/hosts/moon/etc/ipsec.conf b/testing/tests/esp-alg-null/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..af11591a1
--- /dev/null
+++ b/testing/tests/esp-alg-null/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=aes128-sha!
+ esp=null-sha1!
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-null/posttest.dat b/testing/tests/esp-alg-null/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/esp-alg-null/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/esp-alg-null/pretest.dat b/testing/tests/esp-alg-null/pretest.dat
new file mode 100644
index 000000000..f5aa989fe
--- /dev/null
+++ b/testing/tests/esp-alg-null/pretest.dat
@@ -0,0 +1,4 @@
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/esp-alg-null/test.conf b/testing/tests/esp-alg-null/test.conf
new file mode 100644
index 000000000..a6c8f026c
--- /dev/null
+++ b/testing/tests/esp-alg-null/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/esp-alg-strict-fail/description.txt b/testing/tests/esp-alg-strict-fail/description.txt
new file mode 100644
index 000000000..03c655480
--- /dev/null
+++ b/testing/tests/esp-alg-strict-fail/description.txt
@@ -0,0 +1,5 @@
+The roadwarrior <b>carol</b> proposes <b>3DES</b> encryption with SHA-1 authentication
+as the only cipher suite for both the ISAKMP and IPsec SA. The gateway <b>moon</b> defines
+<b>ike=aes-128-sha</b> only, but will accept any other support algorithm proposed by the peer,
+leading to a successful negotiation of Phase 1. Because for Phase 2 <b>moon</b> enforces
+<b>esp=aes-128-sha1!</b> by using the strict flag '!', the ISAKMP SA will fail.
diff --git a/testing/tests/esp-alg-strict-fail/evaltest.dat b/testing/tests/esp-alg-strict-fail/evaltest.dat
new file mode 100644
index 000000000..6f2024ff9
--- /dev/null
+++ b/testing/tests/esp-alg-strict-fail/evaltest.dat
@@ -0,0 +1,9 @@
+carol::ipsec status::home.*STATE_MAIN_I4.*ISAKMP SA established::YES
+carol::ipsec statusall::IKE algorithm newest: 3DES_CBC_192-SHA::YES
+moon::ipsec status::rw.*STATE_MAIN_R3.*ISAKMP SA established::YES
+moon::ipsec statusall::IKE algorithm newest: 3DES_CBC_192-SHA::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::NO
+carol::cat /var/log/auth.log::NO_PROPOSAL_CHOSEN::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*ISAKMP SA established::NO
+moon::cat /var/log/auth.log::IPSec Transform.*ESP_3DES (192), AUTH_ALGORITHM_HMAC_SHA1.*refused due to strict flag::YES
+moon::cat /var/log/auth.log::no acceptable Proposal in IPsec SA::YES
diff --git a/testing/tests/esp-alg-strict-fail/hosts/carol/etc/ipsec.conf b/testing/tests/esp-alg-strict-fail/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..ae8d2b772
--- /dev/null
+++ b/testing/tests/esp-alg-strict-fail/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=3des-sha
+ esp=3des-sha1
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-strict-fail/hosts/moon/etc/ipsec.conf b/testing/tests/esp-alg-strict-fail/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..2dd1c763a
--- /dev/null
+++ b/testing/tests/esp-alg-strict-fail/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=aes128-sha
+ esp=aes128-sha1!
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-strict-fail/posttest.dat b/testing/tests/esp-alg-strict-fail/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/esp-alg-strict-fail/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/esp-alg-strict-fail/pretest.dat b/testing/tests/esp-alg-strict-fail/pretest.dat
new file mode 100644
index 000000000..f5aa989fe
--- /dev/null
+++ b/testing/tests/esp-alg-strict-fail/pretest.dat
@@ -0,0 +1,4 @@
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/esp-alg-strict-fail/test.conf b/testing/tests/esp-alg-strict-fail/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/esp-alg-strict-fail/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/esp-alg-strict/description.txt b/testing/tests/esp-alg-strict/description.txt
new file mode 100644
index 000000000..b4fc08253
--- /dev/null
+++ b/testing/tests/esp-alg-strict/description.txt
@@ -0,0 +1,7 @@
+Roadwarrior <b>carol</b> proposes <b>3DES</b> encryption (together with
+SHA-1 authentication) in the first place and <b>AES-128</b> encryption in
+second place for both the ISAKMP and IPsec SAs. Gateway <b>moon</b> defines
+<b>ike=aes-128-sha</b> but will accept any other supported algorithm proposed
+by the peer during Phase 1. But for ESP encryption <b>moon</b> enforces
+<b>esp=aes-128-sha1!</b> by applying the strict flag '!'.
+
diff --git a/testing/tests/esp-alg-strict/evaltest.dat b/testing/tests/esp-alg-strict/evaltest.dat
new file mode 100644
index 000000000..d5dd12d4e
--- /dev/null
+++ b/testing/tests/esp-alg-strict/evaltest.dat
@@ -0,0 +1,7 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::cat /var/log/auth.log::IPSec Transform.*ESP_3DES (192), AUTH_ALGORITHM_HMAC_SHA1.*refused due to strict flag::YES
+moon::ipsec statusall::IKE algorithm newest: 3DES_CBC_192-SHA::YES
+moon::ipsec statusall::ESP algorithm newest: AES_128-HMAC_SHA1::YES
+carol::ipsec statusall::IKE algorithm newest: 3DES_CBC_192-SHA::YES
+carol::ipsec statusall::ESP algorithm newest: AES_128-HMAC_SHA1::YES
diff --git a/testing/tests/esp-alg-strict/hosts/carol/etc/ipsec.conf b/testing/tests/esp-alg-strict/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..5a14de070
--- /dev/null
+++ b/testing/tests/esp-alg-strict/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=3des-sha,aes-128-sha
+ esp=3des-sha1,aes-128-sha1
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-strict/hosts/moon/etc/ipsec.conf b/testing/tests/esp-alg-strict/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..2dd1c763a
--- /dev/null
+++ b/testing/tests/esp-alg-strict/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=aes128-sha
+ esp=aes128-sha1!
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-strict/posttest.dat b/testing/tests/esp-alg-strict/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/esp-alg-strict/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/esp-alg-strict/pretest.dat b/testing/tests/esp-alg-strict/pretest.dat
new file mode 100644
index 000000000..f5aa989fe
--- /dev/null
+++ b/testing/tests/esp-alg-strict/pretest.dat
@@ -0,0 +1,4 @@
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/esp-alg-strict/test.conf b/testing/tests/esp-alg-strict/test.conf
new file mode 100644
index 000000000..a6c8f026c
--- /dev/null
+++ b/testing/tests/esp-alg-strict/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/esp-alg-weak/description.txt b/testing/tests/esp-alg-weak/description.txt
new file mode 100644
index 000000000..ffb6882f5
--- /dev/null
+++ b/testing/tests/esp-alg-weak/description.txt
@@ -0,0 +1,5 @@
+The roadwarrior <b>carol</b> proposes <b>1DES</b> encryption with MD5 authentication
+as the only cipher suite for the IPsec SA. Because gateway <b>moon</b> does
+not use an explicit <b>esp</b> statement any strong encryption algorithm will be
+accepted but any weak key length will be rejected by default and thus the ISAKMP SA
+is bound to fail.
diff --git a/testing/tests/esp-alg-weak/evaltest.dat b/testing/tests/esp-alg-weak/evaltest.dat
new file mode 100644
index 000000000..72b14e805
--- /dev/null
+++ b/testing/tests/esp-alg-weak/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::NO
+carol::cat /var/log/auth.log::NO_PROPOSAL_CHOSEN::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::NO
+moon::cat /var/log/auth.log::IPSec Transform.*refused due to insecure key_len::YES
+moon::cat /var/log/auth.log::no acceptable Proposal in IPsec SA::YES
diff --git a/testing/tests/esp-alg-weak/hosts/carol/etc/ipsec.conf b/testing/tests/esp-alg-weak/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..b4f067b6d
--- /dev/null
+++ b/testing/tests/esp-alg-weak/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=3des-md5-modp1024!
+ esp=des-md5!
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-weak/hosts/moon/etc/ipsec.conf b/testing/tests/esp-alg-weak/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..3f07213ae
--- /dev/null
+++ b/testing/tests/esp-alg-weak/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/esp-alg-weak/posttest.dat b/testing/tests/esp-alg-weak/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/esp-alg-weak/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/esp-alg-weak/pretest.dat b/testing/tests/esp-alg-weak/pretest.dat
new file mode 100644
index 000000000..7d077c126
--- /dev/null
+++ b/testing/tests/esp-alg-weak/pretest.dat
@@ -0,0 +1,5 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/esp-alg-weak/test.conf b/testing/tests/esp-alg-weak/test.conf
new file mode 100644
index 000000000..a6c8f026c
--- /dev/null
+++ b/testing/tests/esp-alg-weak/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/host2host-cert/description.txt b/testing/tests/host2host-cert/description.txt
new file mode 100644
index 000000000..6be21bf8f
--- /dev/null
+++ b/testing/tests/host2host-cert/description.txt
@@ -0,0 +1,4 @@
+A connection between the hosts <b>moon</b> and <b>sun</b> is successfully set up.
+The authentication is based on X.509 certificates. <b>leftfirewall=yes</b> automatically
+inserts iptables-based firewall rules that let pass the tunneled traffic.
+In order to test the host-to-host tunnel <b>moon</b> pings <b>sun</b>.
diff --git a/testing/tests/host2host-cert/evaltest.dat b/testing/tests/host2host-cert/evaltest.dat
new file mode 100644
index 000000000..d19f970f2
--- /dev/null
+++ b/testing/tests/host2host-cert/evaltest.dat
@@ -0,0 +1,5 @@
+moon::ipsec status::host-host.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::host-host.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/host2host-cert/posttest.dat b/testing/tests/host2host-cert/posttest.dat
new file mode 100644
index 000000000..52979508d
--- /dev/null
+++ b/testing/tests/host2host-cert/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+sun::iptables -v -n -L
+moon::ipsec stop
+sun::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/host2host-cert/pretest.dat b/testing/tests/host2host-cert/pretest.dat
new file mode 100644
index 000000000..3536fd886
--- /dev/null
+++ b/testing/tests/host2host-cert/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+sun::ipsec start
+moon::sleep 2
+moon::ipsec up host-host
diff --git a/testing/tests/host2host-cert/test.conf b/testing/tests/host2host-cert/test.conf
new file mode 100644
index 000000000..cf2e704fd
--- /dev/null
+++ b/testing/tests/host2host-cert/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon winnetou sun"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-w-s.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/host2host-swapped/description.txt b/testing/tests/host2host-swapped/description.txt
new file mode 100644
index 000000000..34cfe43cc
--- /dev/null
+++ b/testing/tests/host2host-swapped/description.txt
@@ -0,0 +1,3 @@
+Same scenario as test <a href="../host2host-cert/"><b>host2host-cert</b></a> but with
+swapped end definitions: <b>right</b> denotes the <b>local</b> side whereas
+<b>left</b> stands for the <b>remote</b> peer.
diff --git a/testing/tests/host2host-swapped/evaltest.dat b/testing/tests/host2host-swapped/evaltest.dat
new file mode 100644
index 000000000..d19f970f2
--- /dev/null
+++ b/testing/tests/host2host-swapped/evaltest.dat
@@ -0,0 +1,5 @@
+moon::ipsec status::host-host.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::host-host.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/host2host-swapped/hosts/moon/etc/ipsec.conf b/testing/tests/host2host-swapped/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..4b66a5ecb
--- /dev/null
+++ b/testing/tests/host2host-swapped/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn host-host
+ right=PH_IP_MOON
+ rightnexthop=%direct
+ rightcert=moonCert.pem
+ rightid=@moon.strongswan.org
+ rightfirewall=yes
+ left=PH_IP_SUN
+ leftid=@sun.strongswan.org
+ auto=add
diff --git a/testing/tests/host2host-swapped/hosts/sun/etc/ipsec.conf b/testing/tests/host2host-swapped/hosts/sun/etc/ipsec.conf
new file mode 100755
index 000000000..a58894b33
--- /dev/null
+++ b/testing/tests/host2host-swapped/hosts/sun/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn host-host
+ right=PH_IP_SUN
+ rightnexthop=%direct
+ rightcert=sunCert.pem
+ rightfirewall=yes
+ rightid=@sun.strongswan.org
+ left=PH_IP_MOON
+ leftid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/host2host-swapped/posttest.dat b/testing/tests/host2host-swapped/posttest.dat
new file mode 100644
index 000000000..52979508d
--- /dev/null
+++ b/testing/tests/host2host-swapped/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+sun::iptables -v -n -L
+moon::ipsec stop
+sun::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/host2host-swapped/pretest.dat b/testing/tests/host2host-swapped/pretest.dat
new file mode 100644
index 000000000..e2d98f2eb
--- /dev/null
+++ b/testing/tests/host2host-swapped/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+sun::ipsec start
+moon::sleep 2
+moon::ipsec up host-host
diff --git a/testing/tests/host2host-swapped/test.conf b/testing/tests/host2host-swapped/test.conf
new file mode 100644
index 000000000..cf2e704fd
--- /dev/null
+++ b/testing/tests/host2host-swapped/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon winnetou sun"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-w-s.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/host2host-transport/description.txt b/testing/tests/host2host-transport/description.txt
new file mode 100644
index 000000000..fe3482c96
--- /dev/null
+++ b/testing/tests/host2host-transport/description.txt
@@ -0,0 +1,4 @@
+An IPsec <b>transport-mode</b> connection between the hosts <b>moon</b> and <b>sun</b> is
+successfully set up. <b>leftfirewall=yes</b> automatically inserts iptables-based firewall
+rules that let pass the decrypted IP packets. In order to test the host-to-host connection
+<b>moon</b> pings <b>sun</b>.
diff --git a/testing/tests/host2host-transport/evaltest.dat b/testing/tests/host2host-transport/evaltest.dat
new file mode 100644
index 000000000..d19f970f2
--- /dev/null
+++ b/testing/tests/host2host-transport/evaltest.dat
@@ -0,0 +1,5 @@
+moon::ipsec status::host-host.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::host-host.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/host2host-transport/hosts/moon/etc/ipsec.conf b/testing/tests/host2host-transport/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..af5000fa8
--- /dev/null
+++ b/testing/tests/host2host-transport/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+
+conn host-host
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightid=@sun.strongswan.org
+ type=transport
+ auto=add
diff --git a/testing/tests/host2host-transport/hosts/sun/etc/ipsec.conf b/testing/tests/host2host-transport/hosts/sun/etc/ipsec.conf
new file mode 100755
index 000000000..10bea9847
--- /dev/null
+++ b/testing/tests/host2host-transport/hosts/sun/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+
+conn host-host
+ left=PH_IP_SUN
+ leftcert=sunCert.pem
+ leftid=@sun.strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+ type=transport
+ auto=add
+
diff --git a/testing/tests/host2host-transport/posttest.dat b/testing/tests/host2host-transport/posttest.dat
new file mode 100644
index 000000000..52979508d
--- /dev/null
+++ b/testing/tests/host2host-transport/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+sun::iptables -v -n -L
+moon::ipsec stop
+sun::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/host2host-transport/pretest.dat b/testing/tests/host2host-transport/pretest.dat
new file mode 100644
index 000000000..e2d98f2eb
--- /dev/null
+++ b/testing/tests/host2host-transport/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+sun::ipsec start
+moon::sleep 2
+moon::ipsec up host-host
diff --git a/testing/tests/host2host-transport/test.conf b/testing/tests/host2host-transport/test.conf
new file mode 100644
index 000000000..cf2e704fd
--- /dev/null
+++ b/testing/tests/host2host-transport/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon winnetou sun"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-w-s.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/ike-alg-sha2_512/description.txt b/testing/tests/ike-alg-sha2_512/description.txt
new file mode 100644
index 000000000..1bec4b8c6
--- /dev/null
+++ b/testing/tests/ike-alg-sha2_512/description.txt
@@ -0,0 +1,4 @@
+Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the paranoid cipher suite
+<b>AES_CBC_256-SHA2_512-MODP8192</b> for the IKE protocol and
+<b>AES_256-HMAC_SHA2_256</b> for ESP packets. A ping from <b>carol</b> to
+<b>alice</b> successfully checks the established tunnel.
diff --git a/testing/tests/ike-alg-sha2_512/evaltest.dat b/testing/tests/ike-alg-sha2_512/evaltest.dat
new file mode 100644
index 000000000..dbd35429c
--- /dev/null
+++ b/testing/tests/ike-alg-sha2_512/evaltest.dat
@@ -0,0 +1,8 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec statusall::IKE algorithm newest: AES_CBC_256-SHA2_512-MODP8192::YES
+carol::ipsec statusall::IKE algorithm newest: AES_CBC_256-SHA2_512-MODP8192::YES
+moon::ipsec statusall::ESP algorithm newest: AES_256-HMAC_SHA2_256::YES
+carol::ipsec statusall::ESP algorithm newest: AES_256-HMAC_SHA2_256::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+
diff --git a/testing/tests/ike-alg-sha2_512/hosts/carol/etc/ipsec.conf b/testing/tests/ike-alg-sha2_512/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..1f73cdc21
--- /dev/null
+++ b/testing/tests/ike-alg-sha2_512/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=aes256-sha2_512-modp8192!
+ esp=aes256-sha2_256!
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/ike-alg-sha2_512/hosts/moon/etc/ipsec.conf b/testing/tests/ike-alg-sha2_512/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..90911997e
--- /dev/null
+++ b/testing/tests/ike-alg-sha2_512/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug="control crypt"
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=aes256-sha2_512-modp8192!
+ esp=aes256-sha2_256!
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/ike-alg-sha2_512/posttest.dat b/testing/tests/ike-alg-sha2_512/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/ike-alg-sha2_512/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/ike-alg-sha2_512/pretest.dat b/testing/tests/ike-alg-sha2_512/pretest.dat
new file mode 100644
index 000000000..7d077c126
--- /dev/null
+++ b/testing/tests/ike-alg-sha2_512/pretest.dat
@@ -0,0 +1,5 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/ike-alg-sha2_512/test.conf b/testing/tests/ike-alg-sha2_512/test.conf
new file mode 100644
index 000000000..a6c8f026c
--- /dev/null
+++ b/testing/tests/ike-alg-sha2_512/test.conf
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
diff --git a/testing/tests/ike-alg-strict-fail/description.txt b/testing/tests/ike-alg-strict-fail/description.txt
new file mode 100644
index 000000000..03c655480
--- /dev/null
+++ b/testing/tests/ike-alg-strict-fail/description.txt
@@ -0,0 +1,5 @@
+The roadwarrior <b>carol</b> proposes <b>3DES</b> encryption with SHA-1 authentication
+as the only cipher suite for both the ISAKMP and IPsec SA. The gateway <b>moon</b> defines
+<b>ike=aes-128-sha</b> only, but will accept any other support algorithm proposed by the peer,
+leading to a successful negotiation of Phase 1. Because for Phase 2 <b>moon</b> enforces
+<b>esp=aes-128-sha1!</b> by using the strict flag '!', the ISAKMP SA will fail.
diff --git a/testing/tests/ike-alg-strict-fail/evaltest.dat b/testing/tests/ike-alg-strict-fail/evaltest.dat
new file mode 100644
index 000000000..931b8855a
--- /dev/null
+++ b/testing/tests/ike-alg-strict-fail/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_MAIN_I4.*ISAKMP SA established::NO
+moon::ipsec status::rw.*STATE_MAIN_R3.*ISAKMP SA established::NO
+carol::cat /var/log/auth.log::NO_PROPOSAL_CHOSEN::YES
+moon::cat /var/log/auth.log::Oakley Transform.*OAKLEY_3DES_CBC (192), OAKLEY_SHA.*refused due to strict flag::YES
+moon::cat /var/log/auth.log::no acceptable Oakley Transform::YES
diff --git a/testing/tests/ike-alg-strict-fail/hosts/carol/etc/ipsec.conf b/testing/tests/ike-alg-strict-fail/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..ae8d2b772
--- /dev/null
+++ b/testing/tests/ike-alg-strict-fail/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=3des-sha
+ esp=3des-sha1
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/ike-alg-strict-fail/hosts/moon/etc/ipsec.conf b/testing/tests/ike-alg-strict-fail/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..85cd235dc
--- /dev/null
+++ b/testing/tests/ike-alg-strict-fail/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=aes128-sha!
+ esp=aes128-sha1
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/ike-alg-strict-fail/posttest.dat b/testing/tests/ike-alg-strict-fail/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/ike-alg-strict-fail/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/ike-alg-strict-fail/pretest.dat b/testing/tests/ike-alg-strict-fail/pretest.dat
new file mode 100644
index 000000000..f5aa989fe
--- /dev/null
+++ b/testing/tests/ike-alg-strict-fail/pretest.dat
@@ -0,0 +1,4 @@
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/ike-alg-strict-fail/test.conf b/testing/tests/ike-alg-strict-fail/test.conf
new file mode 100644
index 000000000..7e7848831
--- /dev/null
+++ b/testing/tests/ike-alg-strict-fail/test.conf
@@ -0,0 +1,21 @@
+##!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/ike-alg-strict/description.txt b/testing/tests/ike-alg-strict/description.txt
new file mode 100644
index 000000000..35d266e20
--- /dev/null
+++ b/testing/tests/ike-alg-strict/description.txt
@@ -0,0 +1,5 @@
+The roadwarrior <b>carol</b> proposes <b>3DES</b> encryption with <b>SHA-1</b> authentication in the first place
+and <b>AES-128</b> encryption with <b>SHA-1</b> authentication in the second place for both the ISAKMP and IPsec SA.
+The gateway <b>moon</b> enforces <b>ike=aes-128-sha!</b> for Phase 1 by using the strict flag '!',
+but will accept any other supported algorithm proposed by the peer for Phase 2 , even though <b>moon</b>
+defines itself <b>esp=aes-128-sha1</b> only.
diff --git a/testing/tests/ike-alg-strict/evaltest.dat b/testing/tests/ike-alg-strict/evaltest.dat
new file mode 100644
index 000000000..46140be8a
--- /dev/null
+++ b/testing/tests/ike-alg-strict/evaltest.dat
@@ -0,0 +1,7 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::cat /var/log/auth.log::Oakley Transform.*OAKLEY_3DES_CBC (192), OAKLEY_SHA.*refused due to strict flag::YES
+moon::ipsec statusall::IKE algorithm newest: AES_CBC_128-SHA::YES
+moon::ipsec statusall::ESP algorithm newest: 3DES_0-HMAC_SHA1::YES
+carol::ipsec statusall::IKE algorithm newest: AES_CBC_128-SHA::YES
+carol::ipsec statusall::ESP algorithm newest: 3DES_0-HMAC_SHA1::YES
diff --git a/testing/tests/ike-alg-strict/hosts/carol/etc/ipsec.conf b/testing/tests/ike-alg-strict/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..5a14de070
--- /dev/null
+++ b/testing/tests/ike-alg-strict/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=3des-sha,aes-128-sha
+ esp=3des-sha1,aes-128-sha1
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/ike-alg-strict/hosts/moon/etc/ipsec.conf b/testing/tests/ike-alg-strict/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..85cd235dc
--- /dev/null
+++ b/testing/tests/ike-alg-strict/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+ ike=aes128-sha!
+ esp=aes128-sha1
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightid=carol@strongswan.org
+ auto=add
diff --git a/testing/tests/ike-alg-strict/posttest.dat b/testing/tests/ike-alg-strict/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/ike-alg-strict/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/ike-alg-strict/pretest.dat b/testing/tests/ike-alg-strict/pretest.dat
new file mode 100644
index 000000000..f5aa989fe
--- /dev/null
+++ b/testing/tests/ike-alg-strict/pretest.dat
@@ -0,0 +1,4 @@
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/ike-alg-strict/test.conf b/testing/tests/ike-alg-strict/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/ike-alg-strict/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/mode-config-swapped/description.txt b/testing/tests/mode-config-swapped/description.txt
new file mode 100644
index 000000000..e29e6f654
--- /dev/null
+++ b/testing/tests/mode-config-swapped/description.txt
@@ -0,0 +1,3 @@
+Same scenario as test <a href="../mode-config/"><b>mode-config</b></a> but with
+swapped end definitions: <b>right</b> denotes the <b>local</b> side whereas
+<b>left</b> stands for the <b>remote</b> peer.
diff --git a/testing/tests/mode-config-swapped/evaltest.dat b/testing/tests/mode-config-swapped/evaltest.dat
new file mode 100644
index 000000000..be8ca6ef5
--- /dev/null
+++ b/testing/tests/mode-config-swapped/evaltest.dat
@@ -0,0 +1,16 @@
+carol::cat /var/log/auth.log::setting virtual IP source address to 10.3.0.1::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+dave::cat /var/log/auth.log::setting virtual IP source address to 10.3.0.2::YES
+dave::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+dave::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::ipsec status::rw-carol.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec status::rw-dave.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
+moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
+alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: icmp::YES
+alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: icmp::YES
diff --git a/testing/tests/mode-config-swapped/hosts/carol/etc/ipsec.conf b/testing/tests/mode-config-swapped/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..bee23f4df
--- /dev/null
+++ b/testing/tests/mode-config-swapped/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,30 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ right=PH_IP_CAROL
+ rightsourceip=%modeconfig
+ rightnexthop=%direct
+ rightcert=carolCert.pem
+ rightid=carol@strongswan.org
+ rightfirewall=yes
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/tests/mode-config-swapped/hosts/dave/etc/ipsec.conf b/testing/tests/mode-config-swapped/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..698cd9673
--- /dev/null
+++ b/testing/tests/mode-config-swapped/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,30 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ right=PH_IP_DAVE
+ rightsourceip=%modeconfig
+ rightnexthop=%direct
+ rightcert=daveCert.pem
+ rightid=dave@strongswan.org
+ rightfirewall=yes
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/tests/mode-config-swapped/hosts/moon/etc/ipsec.conf b/testing/tests/mode-config-swapped/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..b9e401080
--- /dev/null
+++ b/testing/tests/mode-config-swapped/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,33 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightsourceip=PH_IP1_MOON
+ rightnexthop=%direct
+ rightcert=moonCert.pem
+ rightid=@moon.strongswan.org
+ rightfirewall=yes
+
+conn rw-carol
+ left=%any
+ leftid=carol@strongswan.org
+ leftsourceip=PH_IP1_CAROL
+ auto=add
+
+conn rw-dave
+ left=%any
+ leftid=dave@strongswan.org
+ leftsourceip=PH_IP1_DAVE
+ auto=add
diff --git a/testing/tests/mode-config-swapped/posttest.dat b/testing/tests/mode-config-swapped/posttest.dat
new file mode 100644
index 000000000..932b319a7
--- /dev/null
+++ b/testing/tests/mode-config-swapped/posttest.dat
@@ -0,0 +1,11 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+dave::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+dave::/etc/init.d/iptables stop 2> /dev/null
+carol::ip addr del PH_IP1_CAROL/32 dev eth0
+dave::ip addr del PH_IP1_DAVE/32 dev eth0
diff --git a/testing/tests/mode-config-swapped/pretest.dat b/testing/tests/mode-config-swapped/pretest.dat
new file mode 100644
index 000000000..1e45f00fd
--- /dev/null
+++ b/testing/tests/mode-config-swapped/pretest.dat
@@ -0,0 +1,9 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+dave::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
+dave::ipsec up home
diff --git a/testing/tests/mode-config-swapped/test.conf b/testing/tests/mode-config-swapped/test.conf
new file mode 100644
index 000000000..1a8f2a4e0
--- /dev/null
+++ b/testing/tests/mode-config-swapped/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon alice"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/mode-config/description.txt b/testing/tests/mode-config/description.txt
new file mode 100644
index 000000000..3e67f83f1
--- /dev/null
+++ b/testing/tests/mode-config/description.txt
@@ -0,0 +1,7 @@
+The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each to gateway <b>moon</b>.
+Both <b>carol</b> and <b>dave</b> request a <b>virtual IP</b> via the IKE Mode Config protocol
+by using the <b>leftsourceip=%modeconfig</b> parameter. <b>leftfirewall=yes</b> automatically
+inserts iptables-based firewall rules that let pass the tunneled traffic. In order to test the
+tunnels, <b>carol</b> and <b>dave</b> then ping the client <b>alice</b> behind the gateway
+<b>moon</b>. The source IP addresses of the two pings will be the virtual IPs <b>carol1</b>
+and <b>dave1</b>, respectively.
diff --git a/testing/tests/mode-config/evaltest.dat b/testing/tests/mode-config/evaltest.dat
new file mode 100644
index 000000000..be8ca6ef5
--- /dev/null
+++ b/testing/tests/mode-config/evaltest.dat
@@ -0,0 +1,16 @@
+carol::cat /var/log/auth.log::setting virtual IP source address to 10.3.0.1::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+dave::cat /var/log/auth.log::setting virtual IP source address to 10.3.0.2::YES
+dave::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+dave::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::ipsec status::rw-carol.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec status::rw-dave.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
+moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
+alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: icmp::YES
+alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: icmp::YES
diff --git a/testing/tests/mode-config/hosts/carol/etc/ipsec.conf b/testing/tests/mode-config/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..598997b45
--- /dev/null
+++ b/testing/tests/mode-config/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,30 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_CAROL
+ leftsourceip=%modeconfig
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/tests/mode-config/hosts/dave/etc/ipsec.conf b/testing/tests/mode-config/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..da601389c
--- /dev/null
+++ b/testing/tests/mode-config/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,30 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_DAVE
+ leftsourceip=%modeconfig
+ leftnexthop=%direct
+ leftcert=daveCert.pem
+ leftid=dave@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/tests/mode-config/hosts/moon/etc/ipsec.conf b/testing/tests/mode-config/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..49333e217
--- /dev/null
+++ b/testing/tests/mode-config/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,33 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftsourceip=PH_IP1_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+
+conn rw-carol
+ right=%any
+ rightid=carol@strongswan.org
+ rightsourceip=PH_IP1_CAROL
+ auto=add
+
+conn rw-dave
+ right=%any
+ rightid=dave@strongswan.org
+ rightsourceip=PH_IP1_DAVE
+ auto=add
diff --git a/testing/tests/mode-config/posttest.dat b/testing/tests/mode-config/posttest.dat
new file mode 100644
index 000000000..932b319a7
--- /dev/null
+++ b/testing/tests/mode-config/posttest.dat
@@ -0,0 +1,11 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+dave::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+dave::/etc/init.d/iptables stop 2> /dev/null
+carol::ip addr del PH_IP1_CAROL/32 dev eth0
+dave::ip addr del PH_IP1_DAVE/32 dev eth0
diff --git a/testing/tests/mode-config/pretest.dat b/testing/tests/mode-config/pretest.dat
new file mode 100644
index 000000000..1e45f00fd
--- /dev/null
+++ b/testing/tests/mode-config/pretest.dat
@@ -0,0 +1,9 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+dave::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
+dave::ipsec up home
diff --git a/testing/tests/mode-config/test.conf b/testing/tests/mode-config/test.conf
new file mode 100644
index 000000000..1a8f2a4e0
--- /dev/null
+++ b/testing/tests/mode-config/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon alice"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/multi-level-ca-ldap/description.txt b/testing/tests/multi-level-ca-ldap/description.txt
new file mode 100644
index 000000000..18fb88840
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/description.txt
@@ -0,0 +1,11 @@
+The VPN gateway <b>moon</b> controls the access to the hosts <b>alice</b> and
+<b>venus</b> by means of two different Intermediate CAs. Access to
+<b>alice</b> is granted to users presenting a certificate issued by the Research CA
+whereas <b>venus</b> can only be reached with a certificate issued by the
+Sales CA. The roadwarriors <b>carol</b> and <b>dave</b> have certificates from
+the Research CA and Sales CA, respectively. Therefore <b>carol</b> can access
+<b>alice</b> and <b>dave</b> can reach <b>venus</b>.
+<p>
+By setting <b>strictcrlpolicy=yes</b> the CRLs from the strongSwan, Research and
+Sales CAs must be fetched from the LDAP server <b>winnetou</b> first, before the
+connection setups can be successfully completed.
diff --git a/testing/tests/multi-level-ca-ldap/evaltest.dat b/testing/tests/multi-level-ca-ldap/evaltest.dat
new file mode 100644
index 000000000..f504706e2
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/evaltest.dat
@@ -0,0 +1,13 @@
+moon::cat /var/log/auth.log::PH_IP_CAROL.*X.509 certificate rejected::YES
+carol::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+moon::cat /var/log/auth.log::PH_IP_DAVE.*X.509 certificate rejected::YES
+dave::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+moon::cat /var/log/auth.log::Trying LDAP URL::YES
+carol::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::alice.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::ipsec status::venus.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::NO
+dave::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::venus.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::YES
+dave::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::ipsec status::alice.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::NO
diff --git a/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.conf b/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..222c3cf67
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,32 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+ca strongswan
+ cacert=strongswanCert.pem
+ crluri="ldap://ldap.strongswan.org/cn=strongSwan Root CA, o=Linux strongSwan, c=CH?certificateRevocationList"
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
diff --git a/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.d/certs/carolCert.pem b/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.d/certs/carolCert.pem
new file mode 100644
index 000000000..2990d6a12
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.d/certs/carolCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIELDCCAxSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjERMA8GA1UECxMIUmVzZWFyY2gxFDAS
+BgNVBAMTC1Jlc2VhcmNoIENBMB4XDTA1MDMyMzA3MDQyM1oXDTEwMDMyMjA3MDQy
+M1owWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
+BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+oTiV7lCh1ID41edDUgUjR
+dZwEMPBAM1xDqoxJxIJpug8UIuuUL0TvQnZ4Z5fa/9QNNCkQ7FDh8ZcR+TT8x0mO
+dYYA73mMQic0n4O57F+s/lESKvIoN+vIDR3rGJBv9rYztS4ODE+DJl9XK9TtId5u
+57jfXu/k3IYl5GeQ3f+ic2l2Ola70t70Op6cFDZIhOCjs2xWw2yqGdPWODaN/Enw
+5fOLv/om+7HHB4KgPGv4p4ohWIUCo2XK597Ii+jB2MdOUlG83/1aX7+M+IeYVwjI
+hzWjwRQfMz0AQha0HYN4cvrZ7stUluMxewsCROCBzcGQYTZxYU4FjR8nhH4ApYMC
+AwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSL
+qNn96rsWg0kOJY/cyXD2JpnPIjBtBgNVHSMEZjBkgBTndfCg8q0gzc1gI8zHyA8p
+891UIKFJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3
+YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIBDDAfBgNVHREEGDAWgRRj
+YXJvbEBzdHJvbmdzd2FuLm9yZzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3Js
+LnN0cm9uZ3N3YW4ub3JnL3Jlc2VhcmNoLmNybDANBgkqhkiG9w0BAQUFAAOCAQEA
+FNPepmta0ac9TWe7Gl31fKkuf6ZiQftMwx/uq6PoX9PBVGeooktJMo+EiROQhL3N
+Zomtl2nLfxYruXPHa7YaMWyv4+3NkV9p7jseC1K/2lCXipY4Vp8u14hqlRLCTejp
+7uC/0+628e+qXlCm8wafDb9/JXzQar7rADhoLp7gJKI2PKMAzLUP2xZVzY5zx57G
++OCR/ZXonVeAPy9/0g9N8uQzJEXOVZYMjsoRra9rdlvnY1DgDoAK7QvJMC4VzENm
+wKmz2rPrBlKaEcivubg7dwPMGNmb3f7F7w0HHuRbQd5Y0nDfEWBKCp0bVx1GLc7/
+MWjwPJs52qVJ3Ph++EF6bw==
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.d/private/carolKey.pem b/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.d/private/carolKey.pem
new file mode 100644
index 000000000..b91f9bf81
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/carol/etc/ipsec.d/private/carolKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAz6hOJXuUKHUgPjV50NSBSNF1nAQw8EAzXEOqjEnEgmm6DxQi
+65QvRO9Cdnhnl9r/1A00KRDsUOHxlxH5NPzHSY51hgDveYxCJzSfg7nsX6z+URIq
+8ig368gNHesYkG/2tjO1Lg4MT4MmX1cr1O0h3m7nuN9e7+TchiXkZ5Dd/6JzaXY6
+VrvS3vQ6npwUNkiE4KOzbFbDbKoZ09Y4No38SfDl84u/+ib7sccHgqA8a/iniiFY
+hQKjZcrn3siL6MHYx05SUbzf/Vpfv4z4h5hXCMiHNaPBFB8zPQBCFrQdg3hy+tnu
+y1SW4zF7CwJE4IHNwZBhNnFhTgWNHyeEfgClgwIDAQABAoIBAHXoftbRoIKIXtJz
+0sM8plwOctUvnAoOqhsNYN1fVXEnTzoYmOtirKRbpkVWgJu9Ad4J0UAwF76lTGQX
+FIV9sjqV5S09grxlY3qXaquE+i4pMA4gXro5E+eRI8GFJ+F7cX5rRcjsuRi8wyEH
+gh/YtY5zMqfKTUGxlXWmNlaH70WilianuMPNXwaKgyBGcfZdheyUggM0rYEJrG1Z
+PZqNo0JKfeI4htpENDp0k1xJ9lCjIqdNw0ZjBi+pL6hF5PYaPjlVC2yn5CzRaT1D
+nUeKUK+SVES4sPrEQtaOlk86uZC4pIz5IlEoSvaw/Yo3Gk1sQKIQMMh1crhHd0El
+U831KwECgYEA7fQY+aFk3fHabwgf9gjuPKgwetVQ8jNDWUiSqffHUC0AQfKZQQsF
+mXJeSRZomPCWG3DRz1EcqXr9f82bN295I0CI6foXZgKUmjed7Bohc0HvUqNOi2qm
+MdbdWBOaH4RBzi1fAENJZnprmq65jQ/tkfCwqIz4KaLt+8xiWmU2h6ECgYEA32gB
+UbCzs1LoJC03uGHqZFRWK/YNKOKBUw58XCnzPTA+34UupI88lPj8LD269tDtruRy
+G7wt4HjayPKtK430nKAl01IXq6ULBTByu3KrCOm/gTAycVMj4ZimTn7Qu9jyv4Lz
+Ka3rBQxB+yQWfn27dc7U+EBsA7PT53NR6Zl8CqMCgYALJYod93+AHho7ZUgKAHUY
+hlBvEJsQHXKkNhAYwjCmAtWmQTUIpPmILKFaDyCrOWnusyRA7+3FyqshV4JT4Hbu
+PdGsFDkQYEKRztUpADhc69PILTo6sa5DW2tW+uQXYdyrSdjPbFd943Iy9sheYUah
+tYKxApmFacp4JyTcUy1wwQKBgA44xLy6jvX/dR+4cS+frBgu9j1eMIBFyw3Kgkgr
+s3xVserww4NeSvEA2KzIUTqdGkRj7o+tbw43I1ZffH6lTskZuM63DyKyIv11lBgy
+uIicuMA0nUFxlXsrCIs+r3MF4I4oe+pPVALCQQEHzxbGUkSxogUbtMSXkgnN4Y0J
+ZEgZAoGAfo0nv/IeKi0KkKiPTQSGVWGAQyCpGE0UQ2RYYToT84kjXs+LrVGFH2lu
+LJvyYnSnM7eKqCFKh+kLQ3bezum56y5XTyAEipTmu7Lhp0CiVjSdnu+0QykmhKsx
+Z17Ut2ryGKOXySnlMNual4eCLq98o0iOcYPq08V6x33dhK7Z3kU=
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.conf b/testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..bfa0ebba3
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,32 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+ca strongswan
+ cacert=strongswanCert.pem
+ crluri="ldap://ldap.strongswan.org/cn=strongSwan Root CA, o=Linux strongSwan, c=CH?certificateRevocationList"
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_DAVE
+ leftnexthop=%direct
+ leftcert=daveCert.pem
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
diff --git a/testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.d/certs/daveCert.pem b/testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.d/certs/daveCert.pem
new file mode 100644
index 000000000..b76032480
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.d/certs/daveCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEHDCCAwSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEOMAwGA1UECxMFU2FsZXMxETAPBgNV
+BAMTCFNhbGVzIENBMB4XDTA1MDMyMzA3MTAxN1oXDTEwMDMyMjA3MTAxN1owVjEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsT
+BVNhbGVzMRwwGgYDVQQDFBNkYXZlQHN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqAR0itGIuSt/RR8IHjFTLH/lywprmHUw0GS
+zZwo/q4AE4v6OeWRG3JUUg44K40yBwr7zvcsLztRTfbNqlt7o+Hjpo3kz0AMwDo+
+1V42Qkh61VJW1P0NQvkgjiQn+ElSMg1u3uiYCIMAhYMYo2ZMKxHXxRqjU79AVuJN
+P3p8wUpfwReImAy3/n685YbSzWcbPqCfjRH/YrnYS8Ga7m/QzdNfrtxhAWAGow1+
++eTSMvLXSkQeujU6OCJNOPUNB3nnJ1IoZrQm8wNP8Y5B5HzvOSyFEvNuHFc63gSP
+aSRhuz0gubuMpr1d9Rgjny8JgsfCEbOktlKwnbFeSB8AAgVMjwIDAQABo4H/MIH8
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSCy57rUdNRbytUkRGY
+GjmjvXfIszBtBgNVHSMEZjBkgBRfmxNG+SByyADViLWnTC6X6guTKKFJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBDTAeBgNVHREEFzAVgRNkYXZlQHN0cm9uZ3N3
+YW4ub3JnMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwuc3Ryb25nc3dhbi5v
+cmcvc2FsZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQB+BknSxFKaDhbRVobOAU2P
+p9cirkVCitoZrvK2QIS/7WRoqy85RQ+zorJb3jyTxQl4Pu9Qrap9Zn0H8GQXGlQw
+ZJqdDqRaIa4nCc57qP5DsuQKIQRxc1QMCiWyIRAESn+r8IbxLbjvEd7ZXNsieip6
+Q15uUZldjTveHVi89i9oFWS1nWo4SV+tJaEqPBvsTZZKBPAEu6+7lRzbJ4ukzRsA
+DjuvmaPNUTyf21fD66I4sgrwgxoPhZ7r6qsqISJ5f0EzTXgYNi1yk/TXoAaot3c/
+Gu5+iyO/espV6kPADSOzPSFwsGHYG4kXi1VY0Z7x6UnjQSdEelOBplJ5XYDzEn4+
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.d/private/daveKey.pem b/testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.d/private/daveKey.pem
new file mode 100644
index 000000000..022436de4
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/dave/etc/ipsec.d/private/daveKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAyqAR0itGIuSt/RR8IHjFTLH/lywprmHUw0GSzZwo/q4AE4v6
+OeWRG3JUUg44K40yBwr7zvcsLztRTfbNqlt7o+Hjpo3kz0AMwDo+1V42Qkh61VJW
+1P0NQvkgjiQn+ElSMg1u3uiYCIMAhYMYo2ZMKxHXxRqjU79AVuJNP3p8wUpfwReI
+mAy3/n685YbSzWcbPqCfjRH/YrnYS8Ga7m/QzdNfrtxhAWAGow1++eTSMvLXSkQe
+ujU6OCJNOPUNB3nnJ1IoZrQm8wNP8Y5B5HzvOSyFEvNuHFc63gSPaSRhuz0gubuM
+pr1d9Rgjny8JgsfCEbOktlKwnbFeSB8AAgVMjwIDAQABAoIBAHKaRFoVpa6Ynpu0
+mVwYUqdFSaVsEgsSRC9HiEuIllsteNeVZSqX4BGhAXYDmttvGauIF9IAVNpF939c
+JwjCg1S2r3aFbLOXq16R0vYFOjUVH3xF/NysX3LQywv6AS1Z8wZiOKIU9eBij8nz
+0tygQFZf2iUeIuB8HFzH1B8iHSuI7qn6hh1Y9Zgx4kWYL9I+WYefbR906xveHVGq
+8VrgHtBAn1WeWg7FoN1VURW0s1bxkiWtpF9x9OMmwK4qR8HSCilss59V1eJrAAR0
+3FGdWwbbGg9hW0adnyDCtoaYW3r0WcXwqklyas4C+dClOpUInn8kZisoghQYT92u
+U2QeDzECgYEA5Rv7+rP9HX1pNd9NQwOyIHztv4jfx60gybioogtCeRZUwPQ3GtXJ
+Q0ouBxCVLdyCImIKcvd2q2b9HZE8tvOHBA/YxofH4miEN5GWA4aL+LcGrxIbxPWs
+MEkxgQwsyK7lWH47fG7eW86LMx0VikFXS1EeeZZS3f3Avaww1uRtXecCgYEA4mhS
+sAClZamGVWQ7VXCHuS4xHn/gPA4TCyoR5l9g9pwregGKxsROQVIFQCDMd9eTtS6B
+oqoUTHdg0TlujHVUojdwHtgDaqDMTk+RXD9qy2Wob9HQVBlIwgijoLb+OjwdoAj7
+1OQx8FmMjAlMmlyJ50e1FnbNJFEJ1EMgV5QxtxkCgYEArdUeyehYy1BFTJ/CIm+i
+bm37gdDbYchlUUivgkuiwvcDlWd2jADbdRfKdofJeIOPpYDXxsUmIATDVfTFqVZ7
+AcT4SCHrskh00SjANqqWdz5/bsQBl96DKBvQ2MYhEJ9K2mrkvZPtWKENEtolZsIO
+9tF0mvJIq7CF1iPY5qNoq88CgYEAoZhELErJwl3U+22my7ydopZNiK9MpJCHFxjX
+3c2Fr36XqWUgX+4MzKJ2DOdcCM1dJ5wh+q/Z/RnXiH2tYaL83SskY19aUOij6eDw
+px68YqAUMHtYbi39uD/iSftSSM5PdsHyvGiDHEFOB0U735Dc/K45mecBVEJi+ZVP
+qDKlqUECgYA1DcGOWM3P3XdB7zKy47LcankMtFZozEOLTUdGJRlmWrLdcRlZPKjt
+/ALripehesp1++VtmttWQJX7uI3gveD07/tSKeMHmIoKappjRTrcaA7Pa5+z/xS/
+UhRmZUFOJwNLzy3jdv5f2c/5SIz6o4Ae3I+Zb+IapHL+lBv146/I5g==
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/multi-level-ca-ldap/hosts/moon/etc/init.d/iptables b/testing/tests/multi-level-ca-ldap/hosts/moon/etc/init.d/iptables
new file mode 100755
index 000000000..8de514a2e
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/moon/etc/init.d/iptables
@@ -0,0 +1,76 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # enable IP forwarding
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow ldap crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 389 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 389 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.conf b/testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..e2b60589b
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,47 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+ca strongswan
+ cacert=strongswanCert.pem
+ crluri="ldap://ldap.strongswan.org/cn=strongSwan Root CA, o=Linux strongSwan, c=CH?certificateRevocationList"
+ auto=add
+
+ca research
+ cacert=researchCert.pem
+ crluri="ldap://ldap.strongswan.org/cn=Research CA, ou=Research, o=Linux strongSwan, c=CH?certificateRevocationList"
+ auto=add
+
+ca sales
+ cacert=salesCert.pem
+ crluri="ldap://ldap.strongswan.org/cn=Sales CA, ou=Sales, o=Linux strongSwan, c=CH?certificateRevocationList"
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+
+conn alice
+ leftsubnet=PH_IP_ALICE/32
+ right=%any
+ rightca="C=CH, O=Linux strongSwan, OU=Research, CN=Research CA"
+ auto=add
+
+conn venus
+ leftsubnet=PH_IP_VENUS/32
+ right=%any
+ rightca="C=CH, O=Linux strongSwan, OU=Sales, CN=Sales CA"
+ auto=add
+
diff --git a/testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem b/testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem
new file mode 100644
index 000000000..154cff654
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwTCCAqmgAwIBAgIBDzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDYyMTE5NTgwNloXDTEwMDYyMDE5NTgwNlowUTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMRQwEgYDVQQDEwtSZXNlYXJjaCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALY5sjqm4AdbWKc/T7JahWpy9xtdPbHngBN6lbnpYaHfrxnGsvmD
+FCFZHCd7egRqQ/AuJHHcEv3DUdfJWWAypVnUvdlcp58hBjpxfTPXP9IDBxzQaQyU
+zsExIGWOVUY2e7xJ5BKBnXVkok3htY4Hr1GdqNh+3LEmbegJBngTRSRx4PKJ54FO
+/b78LUzB+rMxrzxw/lnI8jEmAtKlugQ7c9auMeFCz+NmlSfnSoWhHN5qm+0iNKy0
+C+25IuE8Nq+i3jtBiI8BwBqHY3u2IuflUh9Nc9d/R6vGsRPMHs30X1Ha/m0Ug494
++wwqwfEBZRjzxMmMF/1SG4I1E3TDOJ3srjkCAwEAAaOBrzCBrDAPBgNVHRMBAf8E
+BTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU53XwoPKtIM3NYCPMx8gPKfPd
+VCAwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNV
+BAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJv
+bmdTd2FuIFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAHArS2trQnBoMVcg
+Br3HV78wYsa1MNAQCBAPhKMMd6EziO4FTwgNgecbKXpObX6ErFDgjtVTcLOMTvNX
+fvZoNuPpdcitlgcWjfxZafNbj6j9ClE/rMbGDO64NLhdXuPVkbmic6yXRwGZpTuq
+3CKgTguLvhzIEM47yfonXKaaJcKVPI7nYRZdlJmD4VflYrSUpzB361dCaPpl0AYa
+0zz1+jfBBvlyic/tf+cCngV3f+GlJ4ntZ3gvRjyysHRmYpWBD7xcA8mJzgUiMyi1
+IKeNzydp+tnLfxwetfA/8ptc346me7RktAaASqO9vpS/N78eXyJRthZTKEf/OqVW
+Tfcyi+M=
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem b/testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem
new file mode 100644
index 000000000..e50477872
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIBDTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDMyMzA2MjkxNloXDTE0MDMyMTA2MjkxNlowSzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsTBVNhbGVz
+MREwDwYDVQQDEwhTYWxlcyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMJOTSaZjDe5UR+hJbodcE40WBxWm+r0FiD+FLc2c0hH/QcWm1Xfqnc9qaPP
+GoxO2BfwXgFEHfOdQzHGuthhsvdMPkmWP1Z3uDrwscqrmLyq4JI87exSen1ggmCV
+Eib55T4fNxrTIGJaoe6Jn9v9ZwG2B+Ur3nFA/wdckSdqJxc6XL9DKcRk3TxZtv9S
+uDftE9G787O6PJSyfyUYhldz1EZe5PTsUoAbBJ0DDXJx3562kDtfQdwezat0LAyO
+sVabYq/0G/fBZwLLer4qGF2+3CsvP7jNXnhRYeSv2+4i2mAjgbBRI1A3iqoU3Nq1
+vPAqzrekOI/RV9Hre9L1r8X1dIECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUX5sTRvkgcsgA1Yi1p0wul+oLkygwbQYD
+VR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNI
+MRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2Fu
+IFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEFBQADggEBAJ7j3X20Q8ICJ2e+iUCpVUIV
+8RudUeHt9qjSXalohuxxhegL5vu7I9Gx0H56RE4glOjLMCb1xqVZ55Odxx14pHaZ
+9iMnQFpgzi96exYAmBKYCHl4IFix2hrTqTWSJhEO+o+PXnQTgcfG43GQepk0qAQr
+iZZy8OWiUhHSJQLJtTMm4rnYjgPn+sLwx7hCPDZpHTZocETDars7wTiVkodCbeEU
+uKahAbq4b6MvvC3+7quvwoEpAEStT7+Yml+QuK/jKmhjX0hcQcw4ZWi+m32RjUAv
+xDJGEvBqV2hyrzRqwh4lVNJEBba5X+QB3N6a0So6BENaJrUM3v8EDaS2KLUWyu0=
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-ldap/posttest.dat b/testing/tests/multi-level-ca-ldap/posttest.dat
new file mode 100644
index 000000000..e618fc419
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/posttest.dat
@@ -0,0 +1,8 @@
+moon::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
+moon::rm /etc/ipsec.d/cacerts/*
+winnetou::/etc/init.d/slapd stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+
diff --git a/testing/tests/multi-level-ca-ldap/pretest.dat b/testing/tests/multi-level-ca-ldap/pretest.dat
new file mode 100644
index 000000000..322f42102
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/pretest.dat
@@ -0,0 +1,10 @@
+winnetou::/etc/init.d/slapd start
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up alice
+carol::ipsec up venus
+dave::ipsec up venus
+dave::ipsec up alice
diff --git a/testing/tests/multi-level-ca-ldap/test.conf b/testing/tests/multi-level-ca-ldap/test.conf
new file mode 100644
index 000000000..08e5cc145
--- /dev/null
+++ b/testing/tests/multi-level-ca-ldap/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice venus moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-v-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/multi-level-ca-loop/description.txt b/testing/tests/multi-level-ca-loop/description.txt
new file mode 100644
index 000000000..9b63c2c66
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/description.txt
@@ -0,0 +1,6 @@
+The roadwarrior <b>carol</b>, possessing a certificate issued by the
+Research CA, tries to set up a tunnel to gateway <b>moon</b>.
+The Research CA's certificate is signed by the Sales CA and
+the Sales CA's certificate in turn is signed by the Research CA.
+This leads to an endless trust path loop but which is aborted by
+<b>moon</b> when the path level reaches a depth of 7 iterations.
diff --git a/testing/tests/multi-level-ca-loop/evaltest.dat b/testing/tests/multi-level-ca-loop/evaltest.dat
new file mode 100644
index 000000000..781a7b4ac
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/evaltest.dat
@@ -0,0 +1,3 @@
+moon::cat /var/log/auth.log::maximum ca path length of 7 levels exceeded::YES
+carol::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::ipsec status::alice.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::NO
diff --git a/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.conf b/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..c56678b59
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,28 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+
+
+
+
diff --git a/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.d/certs/carolCert.pem b/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.d/certs/carolCert.pem
new file mode 100644
index 000000000..2990d6a12
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.d/certs/carolCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIELDCCAxSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjERMA8GA1UECxMIUmVzZWFyY2gxFDAS
+BgNVBAMTC1Jlc2VhcmNoIENBMB4XDTA1MDMyMzA3MDQyM1oXDTEwMDMyMjA3MDQy
+M1owWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
+BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+oTiV7lCh1ID41edDUgUjR
+dZwEMPBAM1xDqoxJxIJpug8UIuuUL0TvQnZ4Z5fa/9QNNCkQ7FDh8ZcR+TT8x0mO
+dYYA73mMQic0n4O57F+s/lESKvIoN+vIDR3rGJBv9rYztS4ODE+DJl9XK9TtId5u
+57jfXu/k3IYl5GeQ3f+ic2l2Ola70t70Op6cFDZIhOCjs2xWw2yqGdPWODaN/Enw
+5fOLv/om+7HHB4KgPGv4p4ohWIUCo2XK597Ii+jB2MdOUlG83/1aX7+M+IeYVwjI
+hzWjwRQfMz0AQha0HYN4cvrZ7stUluMxewsCROCBzcGQYTZxYU4FjR8nhH4ApYMC
+AwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSL
+qNn96rsWg0kOJY/cyXD2JpnPIjBtBgNVHSMEZjBkgBTndfCg8q0gzc1gI8zHyA8p
+891UIKFJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3
+YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIBDDAfBgNVHREEGDAWgRRj
+YXJvbEBzdHJvbmdzd2FuLm9yZzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3Js
+LnN0cm9uZ3N3YW4ub3JnL3Jlc2VhcmNoLmNybDANBgkqhkiG9w0BAQUFAAOCAQEA
+FNPepmta0ac9TWe7Gl31fKkuf6ZiQftMwx/uq6PoX9PBVGeooktJMo+EiROQhL3N
+Zomtl2nLfxYruXPHa7YaMWyv4+3NkV9p7jseC1K/2lCXipY4Vp8u14hqlRLCTejp
+7uC/0+628e+qXlCm8wafDb9/JXzQar7rADhoLp7gJKI2PKMAzLUP2xZVzY5zx57G
++OCR/ZXonVeAPy9/0g9N8uQzJEXOVZYMjsoRra9rdlvnY1DgDoAK7QvJMC4VzENm
+wKmz2rPrBlKaEcivubg7dwPMGNmb3f7F7w0HHuRbQd5Y0nDfEWBKCp0bVx1GLc7/
+MWjwPJs52qVJ3Ph++EF6bw==
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.d/private/carolKey.pem b/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.d/private/carolKey.pem
new file mode 100644
index 000000000..b91f9bf81
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/hosts/carol/etc/ipsec.d/private/carolKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAz6hOJXuUKHUgPjV50NSBSNF1nAQw8EAzXEOqjEnEgmm6DxQi
+65QvRO9Cdnhnl9r/1A00KRDsUOHxlxH5NPzHSY51hgDveYxCJzSfg7nsX6z+URIq
+8ig368gNHesYkG/2tjO1Lg4MT4MmX1cr1O0h3m7nuN9e7+TchiXkZ5Dd/6JzaXY6
+VrvS3vQ6npwUNkiE4KOzbFbDbKoZ09Y4No38SfDl84u/+ib7sccHgqA8a/iniiFY
+hQKjZcrn3siL6MHYx05SUbzf/Vpfv4z4h5hXCMiHNaPBFB8zPQBCFrQdg3hy+tnu
+y1SW4zF7CwJE4IHNwZBhNnFhTgWNHyeEfgClgwIDAQABAoIBAHXoftbRoIKIXtJz
+0sM8plwOctUvnAoOqhsNYN1fVXEnTzoYmOtirKRbpkVWgJu9Ad4J0UAwF76lTGQX
+FIV9sjqV5S09grxlY3qXaquE+i4pMA4gXro5E+eRI8GFJ+F7cX5rRcjsuRi8wyEH
+gh/YtY5zMqfKTUGxlXWmNlaH70WilianuMPNXwaKgyBGcfZdheyUggM0rYEJrG1Z
+PZqNo0JKfeI4htpENDp0k1xJ9lCjIqdNw0ZjBi+pL6hF5PYaPjlVC2yn5CzRaT1D
+nUeKUK+SVES4sPrEQtaOlk86uZC4pIz5IlEoSvaw/Yo3Gk1sQKIQMMh1crhHd0El
+U831KwECgYEA7fQY+aFk3fHabwgf9gjuPKgwetVQ8jNDWUiSqffHUC0AQfKZQQsF
+mXJeSRZomPCWG3DRz1EcqXr9f82bN295I0CI6foXZgKUmjed7Bohc0HvUqNOi2qm
+MdbdWBOaH4RBzi1fAENJZnprmq65jQ/tkfCwqIz4KaLt+8xiWmU2h6ECgYEA32gB
+UbCzs1LoJC03uGHqZFRWK/YNKOKBUw58XCnzPTA+34UupI88lPj8LD269tDtruRy
+G7wt4HjayPKtK430nKAl01IXq6ULBTByu3KrCOm/gTAycVMj4ZimTn7Qu9jyv4Lz
+Ka3rBQxB+yQWfn27dc7U+EBsA7PT53NR6Zl8CqMCgYALJYod93+AHho7ZUgKAHUY
+hlBvEJsQHXKkNhAYwjCmAtWmQTUIpPmILKFaDyCrOWnusyRA7+3FyqshV4JT4Hbu
+PdGsFDkQYEKRztUpADhc69PILTo6sa5DW2tW+uQXYdyrSdjPbFd943Iy9sheYUah
+tYKxApmFacp4JyTcUy1wwQKBgA44xLy6jvX/dR+4cS+frBgu9j1eMIBFyw3Kgkgr
+s3xVserww4NeSvEA2KzIUTqdGkRj7o+tbw43I1ZffH6lTskZuM63DyKyIv11lBgy
+uIicuMA0nUFxlXsrCIs+r3MF4I4oe+pPVALCQQEHzxbGUkSxogUbtMSXkgnN4Y0J
+ZEgZAoGAfo0nv/IeKi0KkKiPTQSGVWGAQyCpGE0UQ2RYYToT84kjXs+LrVGFH2lu
+LJvyYnSnM7eKqCFKh+kLQ3bezum56y5XTyAEipTmu7Lhp0CiVjSdnu+0QykmhKsx
+Z17Ut2ryGKOXySnlMNual4eCLq98o0iOcYPq08V6x33dhK7Z3kU=
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.conf b/testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..343042f15
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn alice
+ leftsubnet=PH_IP_ALICE/32
+ right=%any
+ rightca="C=CH, O=Linux strongSwan, OU=Research, CN=Research CA"
+ auto=add
diff --git a/testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.d/cacerts/research_by_salesCert.pem b/testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.d/cacerts/research_by_salesCert.pem
new file mode 100644
index 000000000..efb939e3a
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.d/cacerts/research_by_salesCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID/TCCAuWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEOMAwGA1UECxMFU2FsZXMxETAPBgNV
+BAMTCFNhbGVzIENBMB4XDTA1MDYxNjE5NTUzNloXDTEwMDYxNTE5NTUzNlowUTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsT
+CFJlc2VhcmNoMRQwEgYDVQQDEwtSZXNlYXJjaCBDQTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALY5sjqm4AdbWKc/T7JahWpy9xtdPbHngBN6lbnpYaHf
+rxnGsvmDFCFZHCd7egRqQ/AuJHHcEv3DUdfJWWAypVnUvdlcp58hBjpxfTPXP9ID
+BxzQaQyUzsExIGWOVUY2e7xJ5BKBnXVkok3htY4Hr1GdqNh+3LEmbegJBngTRSRx
+4PKJ54FO/b78LUzB+rMxrzxw/lnI8jEmAtKlugQ7c9auMeFCz+NmlSfnSoWhHN5q
+m+0iNKy0C+25IuE8Nq+i3jtBiI8BwBqHY3u2IuflUh9Nc9d/R6vGsRPMHs30X1Ha
+/m0Ug494+wwqwfEBZRjzxMmMF/1SG4I1E3TDOJ3srjkCAwEAAaOB5TCB4jAPBgNV
+HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU53XwoPKtIM3NYCPM
+x8gPKfPdVCAwbQYDVR0jBGYwZIAUX5sTRvkgcsgA1Yi1p0wul+oLkyihSaRHMEUx
+CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQD
+ExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQ0wNAYDVR0fBC0wKzApoCegJYYjaHR0cDov
+L2NybC5zdHJvbmdzd2FuLm9yZy9zYWxlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEB
+AJ2EkXnpgdJpsBIMcH+3oTUks8gAT5bR+LdVQSMHqvjgfaCq5fuZY15niLm5QeFr
+Yhv2KtfHfF+tZgE+qWcqS33Y2U/jwUMO45Wqi5HXQDk8AM/gcvQZ8+PINkGdVdup
+Wyw3MM08S/fp8UUl/3QrDr+CBGqZCSx3LEIFILm2hvdXK1/okAtkwlKV4YiOEemg
+pZURzA2M29FeGDS8snfiVYFBkydT9QrrHnx8IwyVGykfOA4tnjRsjTvcs0qhtLcL
+rjK2FSmzBTCVl6/lBOYmB765KUHev6WF4hdMKHf7lsH2nhYb97jxoT54y73jVd1S
+uaJ2yDwEhOHn3ihb1bqlanM=
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.d/cacerts/sales_by_researchCert.pem b/testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.d/cacerts/sales_by_researchCert.pem
new file mode 100644
index 000000000..90e207c4b
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/hosts/moon/etc/ipsec.d/cacerts/sales_by_researchCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBAjANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjERMA8GA1UECxMIUmVzZWFyY2gxFDAS
+BgNVBAMTC1Jlc2VhcmNoIENBMB4XDTA1MDYxNjE5NTcxMFoXDTEwMDYxNTE5NTcx
+MFowSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAM
+BgNVBAsTBVNhbGVzMREwDwYDVQQDEwhTYWxlcyBDQTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMJOTSaZjDe5UR+hJbodcE40WBxWm+r0FiD+FLc2c0hH
+/QcWm1Xfqnc9qaPPGoxO2BfwXgFEHfOdQzHGuthhsvdMPkmWP1Z3uDrwscqrmLyq
+4JI87exSen1ggmCVEib55T4fNxrTIGJaoe6Jn9v9ZwG2B+Ur3nFA/wdckSdqJxc6
+XL9DKcRk3TxZtv9SuDftE9G787O6PJSyfyUYhldz1EZe5PTsUoAbBJ0DDXJx3562
+kDtfQdwezat0LAyOsVabYq/0G/fBZwLLer4qGF2+3CsvP7jNXnhRYeSv2+4i2mAj
+gbBRI1A3iqoU3Nq1vPAqzrekOI/RV9Hre9L1r8X1dIECAwEAAaOB6DCB5TAPBgNV
+HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUX5sTRvkgcsgA1Yi1
+p0wul+oLkygwbQYDVR0jBGYwZIAU53XwoPKtIM3NYCPMx8gPKfPdVCChSaRHMEUx
+CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQD
+ExJzdHJvbmdTd2FuIFJvb3QgQ0GCAQwwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDov
+L2NybC5zdHJvbmdzd2FuLm9yZy9yZXNlYXJjaC5jcmwwDQYJKoZIhvcNAQEFBQAD
+ggEBAJW0/z17JK38rsn8zh0Ta+9Ql5fcA9UIUGcN/KfCvdGwrYaym8Dy6Pz+sZkO
+clOv5t+3R1zKDiiLGQ4m8jYW6NcxeJZyyPhGtKaafanXZsQuMpaTpvkRr62jx/NB
+b3c/HS3dqz2dTMvFJ6CC65vOnnGgzF1szhrrWymGI/NuHUge748WYPNw+OsLmBQI
+koXJsMURGtPWXtJE98Rre+r/6O5kzZNv7V8LGoBkWf1Z6g1q2VvCcnJPxANcQoxf
+Is+E+aqBhGJ6XlnQIlQB1SjoMhOnJ282JK9Hk3NmQYb/zvIzIfo3FCrjj1JI/XoA
+/szZoxwnE2iHtIoMAhfHZpRvOkg=
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-loop/posttest.dat b/testing/tests/multi-level-ca-loop/posttest.dat
new file mode 100644
index 000000000..076f51f4d
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/posttest.dat
@@ -0,0 +1,4 @@
+moon::ipsec stop
+carol::ipsec stop
+moon::rm /etc/ipsec.d/cacerts/*
+
diff --git a/testing/tests/multi-level-ca-loop/pretest.dat b/testing/tests/multi-level-ca-loop/pretest.dat
new file mode 100644
index 000000000..0a0ec22bf
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/pretest.dat
@@ -0,0 +1,6 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+moon::rm /etc/ipsec.d/cacerts/strongswanCert.pem
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up alice
diff --git a/testing/tests/multi-level-ca-loop/test.conf b/testing/tests/multi-level-ca-loop/test.conf
new file mode 100644
index 000000000..3189fdfc7
--- /dev/null
+++ b/testing/tests/multi-level-ca-loop/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/multi-level-ca-revoked/description.txt b/testing/tests/multi-level-ca-revoked/description.txt
new file mode 100644
index 000000000..c91ac285b
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/description.txt
@@ -0,0 +1,4 @@
+The roadwarrior <b>carol</b> possesses a certificate issued by the Research CA.
+The certificate of the Research CA has been revoked by the Root CA by entering
+the serial number in the CRL. Therefore upon verification of the trust path
+the gateway <b>moon</b> will reject the roadwarrior's certificate
diff --git a/testing/tests/multi-level-ca-revoked/evaltest.dat b/testing/tests/multi-level-ca-revoked/evaltest.dat
new file mode 100644
index 000000000..0fd1cae8c
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/evaltest.dat
@@ -0,0 +1,6 @@
+moon::cat /var/log/auth.log::X.509 certificate rejected::YES
+moon::cat /var/log/auth.log::certificate was revoked::YES
+carol::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+moon::ipsec listcrls:: ok::YES
+moon::ipsec status::rw.*STATE_MAIN_R3.*ISAKMP SA established::NO
+carol::ipsec status::home.*STATE_MAIN_I4.*ISAKMP SA established::NO
diff --git a/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.conf b/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..6d0aee86a
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+
+conn home
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.d/certs/carolCert.pem b/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.d/certs/carolCert.pem
new file mode 100644
index 000000000..2990d6a12
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.d/certs/carolCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIELDCCAxSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjERMA8GA1UECxMIUmVzZWFyY2gxFDAS
+BgNVBAMTC1Jlc2VhcmNoIENBMB4XDTA1MDMyMzA3MDQyM1oXDTEwMDMyMjA3MDQy
+M1owWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
+BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+oTiV7lCh1ID41edDUgUjR
+dZwEMPBAM1xDqoxJxIJpug8UIuuUL0TvQnZ4Z5fa/9QNNCkQ7FDh8ZcR+TT8x0mO
+dYYA73mMQic0n4O57F+s/lESKvIoN+vIDR3rGJBv9rYztS4ODE+DJl9XK9TtId5u
+57jfXu/k3IYl5GeQ3f+ic2l2Ola70t70Op6cFDZIhOCjs2xWw2yqGdPWODaN/Enw
+5fOLv/om+7HHB4KgPGv4p4ohWIUCo2XK597Ii+jB2MdOUlG83/1aX7+M+IeYVwjI
+hzWjwRQfMz0AQha0HYN4cvrZ7stUluMxewsCROCBzcGQYTZxYU4FjR8nhH4ApYMC
+AwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSL
+qNn96rsWg0kOJY/cyXD2JpnPIjBtBgNVHSMEZjBkgBTndfCg8q0gzc1gI8zHyA8p
+891UIKFJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3
+YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIBDDAfBgNVHREEGDAWgRRj
+YXJvbEBzdHJvbmdzd2FuLm9yZzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3Js
+LnN0cm9uZ3N3YW4ub3JnL3Jlc2VhcmNoLmNybDANBgkqhkiG9w0BAQUFAAOCAQEA
+FNPepmta0ac9TWe7Gl31fKkuf6ZiQftMwx/uq6PoX9PBVGeooktJMo+EiROQhL3N
+Zomtl2nLfxYruXPHa7YaMWyv4+3NkV9p7jseC1K/2lCXipY4Vp8u14hqlRLCTejp
+7uC/0+628e+qXlCm8wafDb9/JXzQar7rADhoLp7gJKI2PKMAzLUP2xZVzY5zx57G
++OCR/ZXonVeAPy9/0g9N8uQzJEXOVZYMjsoRra9rdlvnY1DgDoAK7QvJMC4VzENm
+wKmz2rPrBlKaEcivubg7dwPMGNmb3f7F7w0HHuRbQd5Y0nDfEWBKCp0bVx1GLc7/
+MWjwPJs52qVJ3Ph++EF6bw==
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.d/private/carolKey.pem b/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.d/private/carolKey.pem
new file mode 100644
index 000000000..b91f9bf81
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.d/private/carolKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAz6hOJXuUKHUgPjV50NSBSNF1nAQw8EAzXEOqjEnEgmm6DxQi
+65QvRO9Cdnhnl9r/1A00KRDsUOHxlxH5NPzHSY51hgDveYxCJzSfg7nsX6z+URIq
+8ig368gNHesYkG/2tjO1Lg4MT4MmX1cr1O0h3m7nuN9e7+TchiXkZ5Dd/6JzaXY6
+VrvS3vQ6npwUNkiE4KOzbFbDbKoZ09Y4No38SfDl84u/+ib7sccHgqA8a/iniiFY
+hQKjZcrn3siL6MHYx05SUbzf/Vpfv4z4h5hXCMiHNaPBFB8zPQBCFrQdg3hy+tnu
+y1SW4zF7CwJE4IHNwZBhNnFhTgWNHyeEfgClgwIDAQABAoIBAHXoftbRoIKIXtJz
+0sM8plwOctUvnAoOqhsNYN1fVXEnTzoYmOtirKRbpkVWgJu9Ad4J0UAwF76lTGQX
+FIV9sjqV5S09grxlY3qXaquE+i4pMA4gXro5E+eRI8GFJ+F7cX5rRcjsuRi8wyEH
+gh/YtY5zMqfKTUGxlXWmNlaH70WilianuMPNXwaKgyBGcfZdheyUggM0rYEJrG1Z
+PZqNo0JKfeI4htpENDp0k1xJ9lCjIqdNw0ZjBi+pL6hF5PYaPjlVC2yn5CzRaT1D
+nUeKUK+SVES4sPrEQtaOlk86uZC4pIz5IlEoSvaw/Yo3Gk1sQKIQMMh1crhHd0El
+U831KwECgYEA7fQY+aFk3fHabwgf9gjuPKgwetVQ8jNDWUiSqffHUC0AQfKZQQsF
+mXJeSRZomPCWG3DRz1EcqXr9f82bN295I0CI6foXZgKUmjed7Bohc0HvUqNOi2qm
+MdbdWBOaH4RBzi1fAENJZnprmq65jQ/tkfCwqIz4KaLt+8xiWmU2h6ECgYEA32gB
+UbCzs1LoJC03uGHqZFRWK/YNKOKBUw58XCnzPTA+34UupI88lPj8LD269tDtruRy
+G7wt4HjayPKtK430nKAl01IXq6ULBTByu3KrCOm/gTAycVMj4ZimTn7Qu9jyv4Lz
+Ka3rBQxB+yQWfn27dc7U+EBsA7PT53NR6Zl8CqMCgYALJYod93+AHho7ZUgKAHUY
+hlBvEJsQHXKkNhAYwjCmAtWmQTUIpPmILKFaDyCrOWnusyRA7+3FyqshV4JT4Hbu
+PdGsFDkQYEKRztUpADhc69PILTo6sa5DW2tW+uQXYdyrSdjPbFd943Iy9sheYUah
+tYKxApmFacp4JyTcUy1wwQKBgA44xLy6jvX/dR+4cS+frBgu9j1eMIBFyw3Kgkgr
+s3xVserww4NeSvEA2KzIUTqdGkRj7o+tbw43I1ZffH6lTskZuM63DyKyIv11lBgy
+uIicuMA0nUFxlXsrCIs+r3MF4I4oe+pPVALCQQEHzxbGUkSxogUbtMSXkgnN4Y0J
+ZEgZAoGAfo0nv/IeKi0KkKiPTQSGVWGAQyCpGE0UQ2RYYToT84kjXs+LrVGFH2lu
+LJvyYnSnM7eKqCFKh+kLQ3bezum56y5XTyAEipTmu7Lhp0CiVjSdnu+0QykmhKsx
+Z17Ut2ryGKOXySnlMNual4eCLq98o0iOcYPq08V6x33dhK7Z3kU=
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.secrets b/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..fac55d63b
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA carolKey.pem
diff --git a/testing/tests/multi-level-ca-revoked/hosts/moon/etc/ipsec.conf b/testing/tests/multi-level-ca-revoked/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..39a298de9
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,29 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+ca strongswan
+ cacert=strongswanCert.pem
+ crluri=http://crl.strongswan.org/strongswan.crl
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn alice
+ leftsubnet=PH_IP_ALICE/32
+ right=%any
+ rightca="C=CH, O=Linux strongSwan, OU=Research, CN=Research CA"
+ auto=add
diff --git a/testing/tests/multi-level-ca-revoked/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem b/testing/tests/multi-level-ca-revoked/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem
new file mode 100644
index 000000000..c380a5110
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwTCCAqmgAwIBAgIBDDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDMyMzA2MjUzNloXDTE0MDMyMTA2MjUzNlowUTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMRQwEgYDVQQDEwtSZXNlYXJjaCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALY5sjqm4AdbWKc/T7JahWpy9xtdPbHngBN6lbnpYaHfrxnGsvmD
+FCFZHCd7egRqQ/AuJHHcEv3DUdfJWWAypVnUvdlcp58hBjpxfTPXP9IDBxzQaQyU
+zsExIGWOVUY2e7xJ5BKBnXVkok3htY4Hr1GdqNh+3LEmbegJBngTRSRx4PKJ54FO
+/b78LUzB+rMxrzxw/lnI8jEmAtKlugQ7c9auMeFCz+NmlSfnSoWhHN5qm+0iNKy0
+C+25IuE8Nq+i3jtBiI8BwBqHY3u2IuflUh9Nc9d/R6vGsRPMHs30X1Ha/m0Ug494
++wwqwfEBZRjzxMmMF/1SG4I1E3TDOJ3srjkCAwEAAaOBrzCBrDAPBgNVHRMBAf8E
+BTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU53XwoPKtIM3NYCPMx8gPKfPd
+VCAwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNV
+BAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJv
+bmdTd2FuIFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEFBQADggEBAA4jpa5Vc/q94/X1
+LAHO2m7v2AFPl68SwspZLbCL7Le+iv5BUQ814Y9qCXMySak+NpZ5RLzm/cC+3GCa
+6eyozhZnS5LDxIgtStXWaC3vIQKQhJMwnc43RgcqneqqS5/H5zNXz/f0g/bRG8bN
+T6nO0ZRdpy8Zu0+fH3f/u9/sQPRX3iNL/rd3x/UVLoowkQHdKzZfjcrFm+8CPl4r
+9xOKjzC6epPY2ApfXmLodd0zemf84CKSJCXfkVlk0cYw1YLKUINnHToFfDAw0kCL
+cVc7wHWZlzSVSE3u0PYXVssnsm08RWqAGPL3TO09fnUntNMzlIxNpOTuWsKVXZPq
+YO2C4HE=
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-revoked/posttest.dat b/testing/tests/multi-level-ca-revoked/posttest.dat
new file mode 100644
index 000000000..f84b7e37b
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/posttest.dat
@@ -0,0 +1,3 @@
+moon::ipsec stop
+carol::ipsec stop
+moon::rm /etc/ipsec.d/cacerts/*
diff --git a/testing/tests/multi-level-ca-revoked/pretest.dat b/testing/tests/multi-level-ca-revoked/pretest.dat
new file mode 100644
index 000000000..d92333d86
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/pretest.dat
@@ -0,0 +1,4 @@
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/multi-level-ca-revoked/test.conf b/testing/tests/multi-level-ca-revoked/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/multi-level-ca-revoked/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/multi-level-ca-strict/description.txt b/testing/tests/multi-level-ca-strict/description.txt
new file mode 100644
index 000000000..32413e3de
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/description.txt
@@ -0,0 +1,10 @@
+The VPN gateway <b>moon</b> controls the access to the hosts <b>alice</b> and
+<b>venus</b> by means of two different Intermediate CAs. Access to
+<b>alice</b> is granted to users presenting a certificate issued by the Research CA
+whereas <b>venus</b> can only be reached with a certificate issued by the
+Sales CA. The roadwarriors <b>carol</b> and <b>dave</b> have certificates from
+the Research CA and Sales CA, respectively. Therefore <b>carol</b> can access
+<b>alice</b> and <b>dave</b> can reach <b>venus</b>.
+<p>
+By setting <b>strictcrlpolicy=yes</b> the CRLs from the strongSwan, Research and
+Sales CAs must be fetched first, before the connection setups can be successfully completed.
diff --git a/testing/tests/multi-level-ca-strict/evaltest.dat b/testing/tests/multi-level-ca-strict/evaltest.dat
new file mode 100644
index 000000000..5a181a62d
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/evaltest.dat
@@ -0,0 +1,12 @@
+moon::cat /var/log/auth.log::PH_IP_CAROL.*X.509 certificate rejected::YES
+carol::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+moon::cat /var/log/auth.log::PH_IP_DAVE.*X.509 certificate rejected::YES
+dave::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+carol::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::alice.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::ipsec status::venus.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::NO
+dave::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::venus.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::YES
+dave::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::ipsec status::alice.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::NO
diff --git a/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.conf b/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..de179c565
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,32 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
+
+
+
+
+
diff --git a/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.d/certs/carolCert.pem b/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.d/certs/carolCert.pem
new file mode 100644
index 000000000..2990d6a12
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.d/certs/carolCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIELDCCAxSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjERMA8GA1UECxMIUmVzZWFyY2gxFDAS
+BgNVBAMTC1Jlc2VhcmNoIENBMB4XDTA1MDMyMzA3MDQyM1oXDTEwMDMyMjA3MDQy
+M1owWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
+BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+oTiV7lCh1ID41edDUgUjR
+dZwEMPBAM1xDqoxJxIJpug8UIuuUL0TvQnZ4Z5fa/9QNNCkQ7FDh8ZcR+TT8x0mO
+dYYA73mMQic0n4O57F+s/lESKvIoN+vIDR3rGJBv9rYztS4ODE+DJl9XK9TtId5u
+57jfXu/k3IYl5GeQ3f+ic2l2Ola70t70Op6cFDZIhOCjs2xWw2yqGdPWODaN/Enw
+5fOLv/om+7HHB4KgPGv4p4ohWIUCo2XK597Ii+jB2MdOUlG83/1aX7+M+IeYVwjI
+hzWjwRQfMz0AQha0HYN4cvrZ7stUluMxewsCROCBzcGQYTZxYU4FjR8nhH4ApYMC
+AwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSL
+qNn96rsWg0kOJY/cyXD2JpnPIjBtBgNVHSMEZjBkgBTndfCg8q0gzc1gI8zHyA8p
+891UIKFJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3
+YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIBDDAfBgNVHREEGDAWgRRj
+YXJvbEBzdHJvbmdzd2FuLm9yZzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3Js
+LnN0cm9uZ3N3YW4ub3JnL3Jlc2VhcmNoLmNybDANBgkqhkiG9w0BAQUFAAOCAQEA
+FNPepmta0ac9TWe7Gl31fKkuf6ZiQftMwx/uq6PoX9PBVGeooktJMo+EiROQhL3N
+Zomtl2nLfxYruXPHa7YaMWyv4+3NkV9p7jseC1K/2lCXipY4Vp8u14hqlRLCTejp
+7uC/0+628e+qXlCm8wafDb9/JXzQar7rADhoLp7gJKI2PKMAzLUP2xZVzY5zx57G
++OCR/ZXonVeAPy9/0g9N8uQzJEXOVZYMjsoRra9rdlvnY1DgDoAK7QvJMC4VzENm
+wKmz2rPrBlKaEcivubg7dwPMGNmb3f7F7w0HHuRbQd5Y0nDfEWBKCp0bVx1GLc7/
+MWjwPJs52qVJ3Ph++EF6bw==
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.d/private/carolKey.pem b/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.d/private/carolKey.pem
new file mode 100644
index 000000000..b91f9bf81
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/carol/etc/ipsec.d/private/carolKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAz6hOJXuUKHUgPjV50NSBSNF1nAQw8EAzXEOqjEnEgmm6DxQi
+65QvRO9Cdnhnl9r/1A00KRDsUOHxlxH5NPzHSY51hgDveYxCJzSfg7nsX6z+URIq
+8ig368gNHesYkG/2tjO1Lg4MT4MmX1cr1O0h3m7nuN9e7+TchiXkZ5Dd/6JzaXY6
+VrvS3vQ6npwUNkiE4KOzbFbDbKoZ09Y4No38SfDl84u/+ib7sccHgqA8a/iniiFY
+hQKjZcrn3siL6MHYx05SUbzf/Vpfv4z4h5hXCMiHNaPBFB8zPQBCFrQdg3hy+tnu
+y1SW4zF7CwJE4IHNwZBhNnFhTgWNHyeEfgClgwIDAQABAoIBAHXoftbRoIKIXtJz
+0sM8plwOctUvnAoOqhsNYN1fVXEnTzoYmOtirKRbpkVWgJu9Ad4J0UAwF76lTGQX
+FIV9sjqV5S09grxlY3qXaquE+i4pMA4gXro5E+eRI8GFJ+F7cX5rRcjsuRi8wyEH
+gh/YtY5zMqfKTUGxlXWmNlaH70WilianuMPNXwaKgyBGcfZdheyUggM0rYEJrG1Z
+PZqNo0JKfeI4htpENDp0k1xJ9lCjIqdNw0ZjBi+pL6hF5PYaPjlVC2yn5CzRaT1D
+nUeKUK+SVES4sPrEQtaOlk86uZC4pIz5IlEoSvaw/Yo3Gk1sQKIQMMh1crhHd0El
+U831KwECgYEA7fQY+aFk3fHabwgf9gjuPKgwetVQ8jNDWUiSqffHUC0AQfKZQQsF
+mXJeSRZomPCWG3DRz1EcqXr9f82bN295I0CI6foXZgKUmjed7Bohc0HvUqNOi2qm
+MdbdWBOaH4RBzi1fAENJZnprmq65jQ/tkfCwqIz4KaLt+8xiWmU2h6ECgYEA32gB
+UbCzs1LoJC03uGHqZFRWK/YNKOKBUw58XCnzPTA+34UupI88lPj8LD269tDtruRy
+G7wt4HjayPKtK430nKAl01IXq6ULBTByu3KrCOm/gTAycVMj4ZimTn7Qu9jyv4Lz
+Ka3rBQxB+yQWfn27dc7U+EBsA7PT53NR6Zl8CqMCgYALJYod93+AHho7ZUgKAHUY
+hlBvEJsQHXKkNhAYwjCmAtWmQTUIpPmILKFaDyCrOWnusyRA7+3FyqshV4JT4Hbu
+PdGsFDkQYEKRztUpADhc69PILTo6sa5DW2tW+uQXYdyrSdjPbFd943Iy9sheYUah
+tYKxApmFacp4JyTcUy1wwQKBgA44xLy6jvX/dR+4cS+frBgu9j1eMIBFyw3Kgkgr
+s3xVserww4NeSvEA2KzIUTqdGkRj7o+tbw43I1ZffH6lTskZuM63DyKyIv11lBgy
+uIicuMA0nUFxlXsrCIs+r3MF4I4oe+pPVALCQQEHzxbGUkSxogUbtMSXkgnN4Y0J
+ZEgZAoGAfo0nv/IeKi0KkKiPTQSGVWGAQyCpGE0UQ2RYYToT84kjXs+LrVGFH2lu
+LJvyYnSnM7eKqCFKh+kLQ3bezum56y5XTyAEipTmu7Lhp0CiVjSdnu+0QykmhKsx
+Z17Ut2ryGKOXySnlMNual4eCLq98o0iOcYPq08V6x33dhK7Z3kU=
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.conf b/testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..2fb6a301e
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,32 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_DAVE
+ leftnexthop=%direct
+ leftcert=daveCert.pem
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
+
+
+
+
+
diff --git a/testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.d/certs/daveCert.pem b/testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.d/certs/daveCert.pem
new file mode 100644
index 000000000..b76032480
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.d/certs/daveCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEHDCCAwSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEOMAwGA1UECxMFU2FsZXMxETAPBgNV
+BAMTCFNhbGVzIENBMB4XDTA1MDMyMzA3MTAxN1oXDTEwMDMyMjA3MTAxN1owVjEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsT
+BVNhbGVzMRwwGgYDVQQDFBNkYXZlQHN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqAR0itGIuSt/RR8IHjFTLH/lywprmHUw0GS
+zZwo/q4AE4v6OeWRG3JUUg44K40yBwr7zvcsLztRTfbNqlt7o+Hjpo3kz0AMwDo+
+1V42Qkh61VJW1P0NQvkgjiQn+ElSMg1u3uiYCIMAhYMYo2ZMKxHXxRqjU79AVuJN
+P3p8wUpfwReImAy3/n685YbSzWcbPqCfjRH/YrnYS8Ga7m/QzdNfrtxhAWAGow1+
++eTSMvLXSkQeujU6OCJNOPUNB3nnJ1IoZrQm8wNP8Y5B5HzvOSyFEvNuHFc63gSP
+aSRhuz0gubuMpr1d9Rgjny8JgsfCEbOktlKwnbFeSB8AAgVMjwIDAQABo4H/MIH8
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSCy57rUdNRbytUkRGY
+GjmjvXfIszBtBgNVHSMEZjBkgBRfmxNG+SByyADViLWnTC6X6guTKKFJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBDTAeBgNVHREEFzAVgRNkYXZlQHN0cm9uZ3N3
+YW4ub3JnMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwuc3Ryb25nc3dhbi5v
+cmcvc2FsZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQB+BknSxFKaDhbRVobOAU2P
+p9cirkVCitoZrvK2QIS/7WRoqy85RQ+zorJb3jyTxQl4Pu9Qrap9Zn0H8GQXGlQw
+ZJqdDqRaIa4nCc57qP5DsuQKIQRxc1QMCiWyIRAESn+r8IbxLbjvEd7ZXNsieip6
+Q15uUZldjTveHVi89i9oFWS1nWo4SV+tJaEqPBvsTZZKBPAEu6+7lRzbJ4ukzRsA
+DjuvmaPNUTyf21fD66I4sgrwgxoPhZ7r6qsqISJ5f0EzTXgYNi1yk/TXoAaot3c/
+Gu5+iyO/espV6kPADSOzPSFwsGHYG4kXi1VY0Z7x6UnjQSdEelOBplJ5XYDzEn4+
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.d/private/daveKey.pem b/testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.d/private/daveKey.pem
new file mode 100644
index 000000000..022436de4
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/dave/etc/ipsec.d/private/daveKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAyqAR0itGIuSt/RR8IHjFTLH/lywprmHUw0GSzZwo/q4AE4v6
+OeWRG3JUUg44K40yBwr7zvcsLztRTfbNqlt7o+Hjpo3kz0AMwDo+1V42Qkh61VJW
+1P0NQvkgjiQn+ElSMg1u3uiYCIMAhYMYo2ZMKxHXxRqjU79AVuJNP3p8wUpfwReI
+mAy3/n685YbSzWcbPqCfjRH/YrnYS8Ga7m/QzdNfrtxhAWAGow1++eTSMvLXSkQe
+ujU6OCJNOPUNB3nnJ1IoZrQm8wNP8Y5B5HzvOSyFEvNuHFc63gSPaSRhuz0gubuM
+pr1d9Rgjny8JgsfCEbOktlKwnbFeSB8AAgVMjwIDAQABAoIBAHKaRFoVpa6Ynpu0
+mVwYUqdFSaVsEgsSRC9HiEuIllsteNeVZSqX4BGhAXYDmttvGauIF9IAVNpF939c
+JwjCg1S2r3aFbLOXq16R0vYFOjUVH3xF/NysX3LQywv6AS1Z8wZiOKIU9eBij8nz
+0tygQFZf2iUeIuB8HFzH1B8iHSuI7qn6hh1Y9Zgx4kWYL9I+WYefbR906xveHVGq
+8VrgHtBAn1WeWg7FoN1VURW0s1bxkiWtpF9x9OMmwK4qR8HSCilss59V1eJrAAR0
+3FGdWwbbGg9hW0adnyDCtoaYW3r0WcXwqklyas4C+dClOpUInn8kZisoghQYT92u
+U2QeDzECgYEA5Rv7+rP9HX1pNd9NQwOyIHztv4jfx60gybioogtCeRZUwPQ3GtXJ
+Q0ouBxCVLdyCImIKcvd2q2b9HZE8tvOHBA/YxofH4miEN5GWA4aL+LcGrxIbxPWs
+MEkxgQwsyK7lWH47fG7eW86LMx0VikFXS1EeeZZS3f3Avaww1uRtXecCgYEA4mhS
+sAClZamGVWQ7VXCHuS4xHn/gPA4TCyoR5l9g9pwregGKxsROQVIFQCDMd9eTtS6B
+oqoUTHdg0TlujHVUojdwHtgDaqDMTk+RXD9qy2Wob9HQVBlIwgijoLb+OjwdoAj7
+1OQx8FmMjAlMmlyJ50e1FnbNJFEJ1EMgV5QxtxkCgYEArdUeyehYy1BFTJ/CIm+i
+bm37gdDbYchlUUivgkuiwvcDlWd2jADbdRfKdofJeIOPpYDXxsUmIATDVfTFqVZ7
+AcT4SCHrskh00SjANqqWdz5/bsQBl96DKBvQ2MYhEJ9K2mrkvZPtWKENEtolZsIO
+9tF0mvJIq7CF1iPY5qNoq88CgYEAoZhELErJwl3U+22my7ydopZNiK9MpJCHFxjX
+3c2Fr36XqWUgX+4MzKJ2DOdcCM1dJ5wh+q/Z/RnXiH2tYaL83SskY19aUOij6eDw
+px68YqAUMHtYbi39uD/iSftSSM5PdsHyvGiDHEFOB0U735Dc/K45mecBVEJi+ZVP
+qDKlqUECgYA1DcGOWM3P3XdB7zKy47LcankMtFZozEOLTUdGJRlmWrLdcRlZPKjt
+/ALripehesp1++VtmttWQJX7uI3gveD07/tSKeMHmIoKappjRTrcaA7Pa5+z/xS/
+UhRmZUFOJwNLzy3jdv5f2c/5SIz6o4Ae3I+Zb+IapHL+lBv146/I5g==
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.conf b/testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..6ed262d20
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,36 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+ca strongswan
+ cacert=strongswanCert.pem
+ crluri=http://crl.strongswan.org/strongswan.crl
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn alice
+ leftsubnet=PH_IP_ALICE/32
+ right=%any
+ rightca="C=CH, O=Linux strongSwan, OU=Research, CN=Research CA"
+ auto=add
+
+conn venus
+ leftsubnet=PH_IP_VENUS/32
+ right=%any
+ rightca="C=CH, O=Linux strongSwan, OU=Sales, CN=Sales CA"
+ auto=add
+
diff --git a/testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem b/testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem
new file mode 100644
index 000000000..154cff654
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwTCCAqmgAwIBAgIBDzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDYyMTE5NTgwNloXDTEwMDYyMDE5NTgwNlowUTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMRQwEgYDVQQDEwtSZXNlYXJjaCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALY5sjqm4AdbWKc/T7JahWpy9xtdPbHngBN6lbnpYaHfrxnGsvmD
+FCFZHCd7egRqQ/AuJHHcEv3DUdfJWWAypVnUvdlcp58hBjpxfTPXP9IDBxzQaQyU
+zsExIGWOVUY2e7xJ5BKBnXVkok3htY4Hr1GdqNh+3LEmbegJBngTRSRx4PKJ54FO
+/b78LUzB+rMxrzxw/lnI8jEmAtKlugQ7c9auMeFCz+NmlSfnSoWhHN5qm+0iNKy0
+C+25IuE8Nq+i3jtBiI8BwBqHY3u2IuflUh9Nc9d/R6vGsRPMHs30X1Ha/m0Ug494
++wwqwfEBZRjzxMmMF/1SG4I1E3TDOJ3srjkCAwEAAaOBrzCBrDAPBgNVHRMBAf8E
+BTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU53XwoPKtIM3NYCPMx8gPKfPd
+VCAwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNV
+BAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJv
+bmdTd2FuIFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAHArS2trQnBoMVcg
+Br3HV78wYsa1MNAQCBAPhKMMd6EziO4FTwgNgecbKXpObX6ErFDgjtVTcLOMTvNX
+fvZoNuPpdcitlgcWjfxZafNbj6j9ClE/rMbGDO64NLhdXuPVkbmic6yXRwGZpTuq
+3CKgTguLvhzIEM47yfonXKaaJcKVPI7nYRZdlJmD4VflYrSUpzB361dCaPpl0AYa
+0zz1+jfBBvlyic/tf+cCngV3f+GlJ4ntZ3gvRjyysHRmYpWBD7xcA8mJzgUiMyi1
+IKeNzydp+tnLfxwetfA/8ptc346me7RktAaASqO9vpS/N78eXyJRthZTKEf/OqVW
+Tfcyi+M=
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem b/testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem
new file mode 100644
index 000000000..e50477872
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIBDTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDMyMzA2MjkxNloXDTE0MDMyMTA2MjkxNlowSzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsTBVNhbGVz
+MREwDwYDVQQDEwhTYWxlcyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMJOTSaZjDe5UR+hJbodcE40WBxWm+r0FiD+FLc2c0hH/QcWm1Xfqnc9qaPP
+GoxO2BfwXgFEHfOdQzHGuthhsvdMPkmWP1Z3uDrwscqrmLyq4JI87exSen1ggmCV
+Eib55T4fNxrTIGJaoe6Jn9v9ZwG2B+Ur3nFA/wdckSdqJxc6XL9DKcRk3TxZtv9S
+uDftE9G787O6PJSyfyUYhldz1EZe5PTsUoAbBJ0DDXJx3562kDtfQdwezat0LAyO
+sVabYq/0G/fBZwLLer4qGF2+3CsvP7jNXnhRYeSv2+4i2mAjgbBRI1A3iqoU3Nq1
+vPAqzrekOI/RV9Hre9L1r8X1dIECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUX5sTRvkgcsgA1Yi1p0wul+oLkygwbQYD
+VR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNI
+MRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2Fu
+IFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEFBQADggEBAJ7j3X20Q8ICJ2e+iUCpVUIV
+8RudUeHt9qjSXalohuxxhegL5vu7I9Gx0H56RE4glOjLMCb1xqVZ55Odxx14pHaZ
+9iMnQFpgzi96exYAmBKYCHl4IFix2hrTqTWSJhEO+o+PXnQTgcfG43GQepk0qAQr
+iZZy8OWiUhHSJQLJtTMm4rnYjgPn+sLwx7hCPDZpHTZocETDars7wTiVkodCbeEU
+uKahAbq4b6MvvC3+7quvwoEpAEStT7+Yml+QuK/jKmhjX0hcQcw4ZWi+m32RjUAv
+xDJGEvBqV2hyrzRqwh4lVNJEBba5X+QB3N6a0So6BENaJrUM3v8EDaS2KLUWyu0=
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca-strict/posttest.dat b/testing/tests/multi-level-ca-strict/posttest.dat
new file mode 100644
index 000000000..1646d5ed2
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/posttest.dat
@@ -0,0 +1,5 @@
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
+moon::rm /etc/ipsec.d/cacerts/*
+
diff --git a/testing/tests/multi-level-ca-strict/pretest.dat b/testing/tests/multi-level-ca-strict/pretest.dat
new file mode 100644
index 000000000..67c50c2ef
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/pretest.dat
@@ -0,0 +1,9 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up alice
+carol::ipsec up venus
+dave::ipsec up venus
+dave::ipsec up alice
diff --git a/testing/tests/multi-level-ca-strict/test.conf b/testing/tests/multi-level-ca-strict/test.conf
new file mode 100644
index 000000000..08e5cc145
--- /dev/null
+++ b/testing/tests/multi-level-ca-strict/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice venus moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-v-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/multi-level-ca/description.txt b/testing/tests/multi-level-ca/description.txt
new file mode 100644
index 000000000..64825cb30
--- /dev/null
+++ b/testing/tests/multi-level-ca/description.txt
@@ -0,0 +1,7 @@
+The VPN gateway <b>moon</b> controls the access to the hosts <b>alice</b> and
+<b>venus</b> by means of two different Intermediate CAs. Access to
+<b>alice</b> is granted to users presenting a certificate issued by the Research CA
+whereas <b>venus</b> can only be reached with a certificate issued by the
+Sales CA. The roadwarriors <b>carol</b> and <b>dave</b> have certificates from
+the Research CA and Sales CA, respectively. Therefore <b>carol</b> can access
+<b>alice</b> and <b>dave</b> can reach <b>venus</b>.
diff --git a/testing/tests/multi-level-ca/evaltest.dat b/testing/tests/multi-level-ca/evaltest.dat
new file mode 100644
index 000000000..72f620b8e
--- /dev/null
+++ b/testing/tests/multi-level-ca/evaltest.dat
@@ -0,0 +1,12 @@
+carol::cat /var/log/auth.log::alice.*we have a cert and are sending it upon request::YES
+moon::cat /var/log/auth.log::alice.*we have a cert and are sending it upon request::YES
+dave::cat /var/log/auth.log::venus.*we have a cert and are sending it upon request::YES
+moon::cat /var/log/auth.log::venus.*we have a cert and are sending it upon request::YES
+carol::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::alice.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::ipsec status::venus.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::NO
+dave::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::venus.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::YES
+dave::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::ipsec status::alice.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::NO
diff --git a/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.conf b/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..e851a82f0
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,33 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftsendcert=ifasked
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
+
+
+
+
+
diff --git a/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.d/certs/carolCert.pem b/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.d/certs/carolCert.pem
new file mode 100644
index 000000000..2990d6a12
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.d/certs/carolCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIELDCCAxSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjERMA8GA1UECxMIUmVzZWFyY2gxFDAS
+BgNVBAMTC1Jlc2VhcmNoIENBMB4XDTA1MDMyMzA3MDQyM1oXDTEwMDMyMjA3MDQy
+M1owWjELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAP
+BgNVBAsTCFJlc2VhcmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+oTiV7lCh1ID41edDUgUjR
+dZwEMPBAM1xDqoxJxIJpug8UIuuUL0TvQnZ4Z5fa/9QNNCkQ7FDh8ZcR+TT8x0mO
+dYYA73mMQic0n4O57F+s/lESKvIoN+vIDR3rGJBv9rYztS4ODE+DJl9XK9TtId5u
+57jfXu/k3IYl5GeQ3f+ic2l2Ola70t70Op6cFDZIhOCjs2xWw2yqGdPWODaN/Enw
+5fOLv/om+7HHB4KgPGv4p4ohWIUCo2XK597Ii+jB2MdOUlG83/1aX7+M+IeYVwjI
+hzWjwRQfMz0AQha0HYN4cvrZ7stUluMxewsCROCBzcGQYTZxYU4FjR8nhH4ApYMC
+AwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSL
+qNn96rsWg0kOJY/cyXD2JpnPIjBtBgNVHSMEZjBkgBTndfCg8q0gzc1gI8zHyA8p
+891UIKFJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3
+YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIBDDAfBgNVHREEGDAWgRRj
+YXJvbEBzdHJvbmdzd2FuLm9yZzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3Js
+LnN0cm9uZ3N3YW4ub3JnL3Jlc2VhcmNoLmNybDANBgkqhkiG9w0BAQUFAAOCAQEA
+FNPepmta0ac9TWe7Gl31fKkuf6ZiQftMwx/uq6PoX9PBVGeooktJMo+EiROQhL3N
+Zomtl2nLfxYruXPHa7YaMWyv4+3NkV9p7jseC1K/2lCXipY4Vp8u14hqlRLCTejp
+7uC/0+628e+qXlCm8wafDb9/JXzQar7rADhoLp7gJKI2PKMAzLUP2xZVzY5zx57G
++OCR/ZXonVeAPy9/0g9N8uQzJEXOVZYMjsoRra9rdlvnY1DgDoAK7QvJMC4VzENm
+wKmz2rPrBlKaEcivubg7dwPMGNmb3f7F7w0HHuRbQd5Y0nDfEWBKCp0bVx1GLc7/
+MWjwPJs52qVJ3Ph++EF6bw==
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.d/private/carolKey.pem b/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.d/private/carolKey.pem
new file mode 100644
index 000000000..b91f9bf81
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/carol/etc/ipsec.d/private/carolKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAz6hOJXuUKHUgPjV50NSBSNF1nAQw8EAzXEOqjEnEgmm6DxQi
+65QvRO9Cdnhnl9r/1A00KRDsUOHxlxH5NPzHSY51hgDveYxCJzSfg7nsX6z+URIq
+8ig368gNHesYkG/2tjO1Lg4MT4MmX1cr1O0h3m7nuN9e7+TchiXkZ5Dd/6JzaXY6
+VrvS3vQ6npwUNkiE4KOzbFbDbKoZ09Y4No38SfDl84u/+ib7sccHgqA8a/iniiFY
+hQKjZcrn3siL6MHYx05SUbzf/Vpfv4z4h5hXCMiHNaPBFB8zPQBCFrQdg3hy+tnu
+y1SW4zF7CwJE4IHNwZBhNnFhTgWNHyeEfgClgwIDAQABAoIBAHXoftbRoIKIXtJz
+0sM8plwOctUvnAoOqhsNYN1fVXEnTzoYmOtirKRbpkVWgJu9Ad4J0UAwF76lTGQX
+FIV9sjqV5S09grxlY3qXaquE+i4pMA4gXro5E+eRI8GFJ+F7cX5rRcjsuRi8wyEH
+gh/YtY5zMqfKTUGxlXWmNlaH70WilianuMPNXwaKgyBGcfZdheyUggM0rYEJrG1Z
+PZqNo0JKfeI4htpENDp0k1xJ9lCjIqdNw0ZjBi+pL6hF5PYaPjlVC2yn5CzRaT1D
+nUeKUK+SVES4sPrEQtaOlk86uZC4pIz5IlEoSvaw/Yo3Gk1sQKIQMMh1crhHd0El
+U831KwECgYEA7fQY+aFk3fHabwgf9gjuPKgwetVQ8jNDWUiSqffHUC0AQfKZQQsF
+mXJeSRZomPCWG3DRz1EcqXr9f82bN295I0CI6foXZgKUmjed7Bohc0HvUqNOi2qm
+MdbdWBOaH4RBzi1fAENJZnprmq65jQ/tkfCwqIz4KaLt+8xiWmU2h6ECgYEA32gB
+UbCzs1LoJC03uGHqZFRWK/YNKOKBUw58XCnzPTA+34UupI88lPj8LD269tDtruRy
+G7wt4HjayPKtK430nKAl01IXq6ULBTByu3KrCOm/gTAycVMj4ZimTn7Qu9jyv4Lz
+Ka3rBQxB+yQWfn27dc7U+EBsA7PT53NR6Zl8CqMCgYALJYod93+AHho7ZUgKAHUY
+hlBvEJsQHXKkNhAYwjCmAtWmQTUIpPmILKFaDyCrOWnusyRA7+3FyqshV4JT4Hbu
+PdGsFDkQYEKRztUpADhc69PILTo6sa5DW2tW+uQXYdyrSdjPbFd943Iy9sheYUah
+tYKxApmFacp4JyTcUy1wwQKBgA44xLy6jvX/dR+4cS+frBgu9j1eMIBFyw3Kgkgr
+s3xVserww4NeSvEA2KzIUTqdGkRj7o+tbw43I1ZffH6lTskZuM63DyKyIv11lBgy
+uIicuMA0nUFxlXsrCIs+r3MF4I4oe+pPVALCQQEHzxbGUkSxogUbtMSXkgnN4Y0J
+ZEgZAoGAfo0nv/IeKi0KkKiPTQSGVWGAQyCpGE0UQ2RYYToT84kjXs+LrVGFH2lu
+LJvyYnSnM7eKqCFKh+kLQ3bezum56y5XTyAEipTmu7Lhp0CiVjSdnu+0QykmhKsx
+Z17Ut2ryGKOXySnlMNual4eCLq98o0iOcYPq08V6x33dhK7Z3kU=
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/multi-level-ca/hosts/dave/etc/ipsec.conf b/testing/tests/multi-level-ca/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..458a4ca5e
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,33 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_DAVE
+ leftnexthop=%direct
+ leftcert=daveCert.pem
+ leftsendcert=ifasked
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
+
+
+
+
+
diff --git a/testing/tests/multi-level-ca/hosts/dave/etc/ipsec.d/certs/daveCert.pem b/testing/tests/multi-level-ca/hosts/dave/etc/ipsec.d/certs/daveCert.pem
new file mode 100644
index 000000000..b76032480
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/dave/etc/ipsec.d/certs/daveCert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEHDCCAwSgAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEOMAwGA1UECxMFU2FsZXMxETAPBgNV
+BAMTCFNhbGVzIENBMB4XDTA1MDMyMzA3MTAxN1oXDTEwMDMyMjA3MTAxN1owVjEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsT
+BVNhbGVzMRwwGgYDVQQDFBNkYXZlQHN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqAR0itGIuSt/RR8IHjFTLH/lywprmHUw0GS
+zZwo/q4AE4v6OeWRG3JUUg44K40yBwr7zvcsLztRTfbNqlt7o+Hjpo3kz0AMwDo+
+1V42Qkh61VJW1P0NQvkgjiQn+ElSMg1u3uiYCIMAhYMYo2ZMKxHXxRqjU79AVuJN
+P3p8wUpfwReImAy3/n685YbSzWcbPqCfjRH/YrnYS8Ga7m/QzdNfrtxhAWAGow1+
++eTSMvLXSkQeujU6OCJNOPUNB3nnJ1IoZrQm8wNP8Y5B5HzvOSyFEvNuHFc63gSP
+aSRhuz0gubuMpr1d9Rgjny8JgsfCEbOktlKwnbFeSB8AAgVMjwIDAQABo4H/MIH8
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBSCy57rUdNRbytUkRGY
+GjmjvXfIszBtBgNVHSMEZjBkgBRfmxNG+SByyADViLWnTC6X6guTKKFJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBDTAeBgNVHREEFzAVgRNkYXZlQHN0cm9uZ3N3
+YW4ub3JnMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwuc3Ryb25nc3dhbi5v
+cmcvc2FsZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQB+BknSxFKaDhbRVobOAU2P
+p9cirkVCitoZrvK2QIS/7WRoqy85RQ+zorJb3jyTxQl4Pu9Qrap9Zn0H8GQXGlQw
+ZJqdDqRaIa4nCc57qP5DsuQKIQRxc1QMCiWyIRAESn+r8IbxLbjvEd7ZXNsieip6
+Q15uUZldjTveHVi89i9oFWS1nWo4SV+tJaEqPBvsTZZKBPAEu6+7lRzbJ4ukzRsA
+DjuvmaPNUTyf21fD66I4sgrwgxoPhZ7r6qsqISJ5f0EzTXgYNi1yk/TXoAaot3c/
+Gu5+iyO/espV6kPADSOzPSFwsGHYG4kXi1VY0Z7x6UnjQSdEelOBplJ5XYDzEn4+
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca/hosts/dave/etc/ipsec.d/private/daveKey.pem b/testing/tests/multi-level-ca/hosts/dave/etc/ipsec.d/private/daveKey.pem
new file mode 100644
index 000000000..022436de4
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/dave/etc/ipsec.d/private/daveKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAyqAR0itGIuSt/RR8IHjFTLH/lywprmHUw0GSzZwo/q4AE4v6
+OeWRG3JUUg44K40yBwr7zvcsLztRTfbNqlt7o+Hjpo3kz0AMwDo+1V42Qkh61VJW
+1P0NQvkgjiQn+ElSMg1u3uiYCIMAhYMYo2ZMKxHXxRqjU79AVuJNP3p8wUpfwReI
+mAy3/n685YbSzWcbPqCfjRH/YrnYS8Ga7m/QzdNfrtxhAWAGow1++eTSMvLXSkQe
+ujU6OCJNOPUNB3nnJ1IoZrQm8wNP8Y5B5HzvOSyFEvNuHFc63gSPaSRhuz0gubuM
+pr1d9Rgjny8JgsfCEbOktlKwnbFeSB8AAgVMjwIDAQABAoIBAHKaRFoVpa6Ynpu0
+mVwYUqdFSaVsEgsSRC9HiEuIllsteNeVZSqX4BGhAXYDmttvGauIF9IAVNpF939c
+JwjCg1S2r3aFbLOXq16R0vYFOjUVH3xF/NysX3LQywv6AS1Z8wZiOKIU9eBij8nz
+0tygQFZf2iUeIuB8HFzH1B8iHSuI7qn6hh1Y9Zgx4kWYL9I+WYefbR906xveHVGq
+8VrgHtBAn1WeWg7FoN1VURW0s1bxkiWtpF9x9OMmwK4qR8HSCilss59V1eJrAAR0
+3FGdWwbbGg9hW0adnyDCtoaYW3r0WcXwqklyas4C+dClOpUInn8kZisoghQYT92u
+U2QeDzECgYEA5Rv7+rP9HX1pNd9NQwOyIHztv4jfx60gybioogtCeRZUwPQ3GtXJ
+Q0ouBxCVLdyCImIKcvd2q2b9HZE8tvOHBA/YxofH4miEN5GWA4aL+LcGrxIbxPWs
+MEkxgQwsyK7lWH47fG7eW86LMx0VikFXS1EeeZZS3f3Avaww1uRtXecCgYEA4mhS
+sAClZamGVWQ7VXCHuS4xHn/gPA4TCyoR5l9g9pwregGKxsROQVIFQCDMd9eTtS6B
+oqoUTHdg0TlujHVUojdwHtgDaqDMTk+RXD9qy2Wob9HQVBlIwgijoLb+OjwdoAj7
+1OQx8FmMjAlMmlyJ50e1FnbNJFEJ1EMgV5QxtxkCgYEArdUeyehYy1BFTJ/CIm+i
+bm37gdDbYchlUUivgkuiwvcDlWd2jADbdRfKdofJeIOPpYDXxsUmIATDVfTFqVZ7
+AcT4SCHrskh00SjANqqWdz5/bsQBl96DKBvQ2MYhEJ9K2mrkvZPtWKENEtolZsIO
+9tF0mvJIq7CF1iPY5qNoq88CgYEAoZhELErJwl3U+22my7ydopZNiK9MpJCHFxjX
+3c2Fr36XqWUgX+4MzKJ2DOdcCM1dJ5wh+q/Z/RnXiH2tYaL83SskY19aUOij6eDw
+px68YqAUMHtYbi39uD/iSftSSM5PdsHyvGiDHEFOB0U735Dc/K45mecBVEJi+ZVP
+qDKlqUECgYA1DcGOWM3P3XdB7zKy47LcankMtFZozEOLTUdGJRlmWrLdcRlZPKjt
+/ALripehesp1++VtmttWQJX7uI3gveD07/tSKeMHmIoKappjRTrcaA7Pa5+z/xS/
+UhRmZUFOJwNLzy3jdv5f2c/5SIz6o4Ae3I+Zb+IapHL+lBv146/I5g==
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/multi-level-ca/hosts/moon/etc/ipsec.conf b/testing/tests/multi-level-ca/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..e60bbc016
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,37 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+ca strongswan
+ cacert=strongswanCert.pem
+ crluri=http://crl.strongswan.org/strongswan.crl
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftsendcert=ifasked
+ leftid=@moon.strongswan.org
+
+conn alice
+ leftsubnet=PH_IP_ALICE/32
+ right=%any
+ rightca="C=CH, O=Linux strongSwan, OU=Research, CN=Research CA"
+ auto=add
+
+conn venus
+ leftsubnet=PH_IP_VENUS/32
+ right=%any
+ rightca="C=CH, O=Linux strongSwan, OU=Sales, CN=Sales CA"
+ auto=add
+
diff --git a/testing/tests/multi-level-ca/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem b/testing/tests/multi-level-ca/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem
new file mode 100644
index 000000000..154cff654
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/moon/etc/ipsec.d/cacerts/researchCert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwTCCAqmgAwIBAgIBDzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDYyMTE5NTgwNloXDTEwMDYyMDE5NTgwNlowUTELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMRQwEgYDVQQDEwtSZXNlYXJjaCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALY5sjqm4AdbWKc/T7JahWpy9xtdPbHngBN6lbnpYaHfrxnGsvmD
+FCFZHCd7egRqQ/AuJHHcEv3DUdfJWWAypVnUvdlcp58hBjpxfTPXP9IDBxzQaQyU
+zsExIGWOVUY2e7xJ5BKBnXVkok3htY4Hr1GdqNh+3LEmbegJBngTRSRx4PKJ54FO
+/b78LUzB+rMxrzxw/lnI8jEmAtKlugQ7c9auMeFCz+NmlSfnSoWhHN5qm+0iNKy0
+C+25IuE8Nq+i3jtBiI8BwBqHY3u2IuflUh9Nc9d/R6vGsRPMHs30X1Ha/m0Ug494
++wwqwfEBZRjzxMmMF/1SG4I1E3TDOJ3srjkCAwEAAaOBrzCBrDAPBgNVHRMBAf8E
+BTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU53XwoPKtIM3NYCPMx8gPKfPd
+VCAwbQYDVR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNV
+BAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJv
+bmdTd2FuIFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEEBQADggEBAHArS2trQnBoMVcg
+Br3HV78wYsa1MNAQCBAPhKMMd6EziO4FTwgNgecbKXpObX6ErFDgjtVTcLOMTvNX
+fvZoNuPpdcitlgcWjfxZafNbj6j9ClE/rMbGDO64NLhdXuPVkbmic6yXRwGZpTuq
+3CKgTguLvhzIEM47yfonXKaaJcKVPI7nYRZdlJmD4VflYrSUpzB361dCaPpl0AYa
+0zz1+jfBBvlyic/tf+cCngV3f+GlJ4ntZ3gvRjyysHRmYpWBD7xcA8mJzgUiMyi1
+IKeNzydp+tnLfxwetfA/8ptc346me7RktAaASqO9vpS/N78eXyJRthZTKEf/OqVW
+Tfcyi+M=
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem b/testing/tests/multi-level-ca/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem
new file mode 100644
index 000000000..e50477872
--- /dev/null
+++ b/testing/tests/multi-level-ca/hosts/moon/etc/ipsec.d/cacerts/salesCert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIBDTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA1MDMyMzA2MjkxNloXDTE0MDMyMTA2MjkxNlowSzELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDjAMBgNVBAsTBVNhbGVz
+MREwDwYDVQQDEwhTYWxlcyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMJOTSaZjDe5UR+hJbodcE40WBxWm+r0FiD+FLc2c0hH/QcWm1Xfqnc9qaPP
+GoxO2BfwXgFEHfOdQzHGuthhsvdMPkmWP1Z3uDrwscqrmLyq4JI87exSen1ggmCV
+Eib55T4fNxrTIGJaoe6Jn9v9ZwG2B+Ur3nFA/wdckSdqJxc6XL9DKcRk3TxZtv9S
+uDftE9G787O6PJSyfyUYhldz1EZe5PTsUoAbBJ0DDXJx3562kDtfQdwezat0LAyO
+sVabYq/0G/fBZwLLer4qGF2+3CsvP7jNXnhRYeSv2+4i2mAjgbBRI1A3iqoU3Nq1
+vPAqzrekOI/RV9Hre9L1r8X1dIECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUX5sTRvkgcsgA1Yi1p0wul+oLkygwbQYD
+VR0jBGYwZIAUXafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNI
+MRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2Fu
+IFJvb3QgQ0GCAQAwDQYJKoZIhvcNAQEFBQADggEBAJ7j3X20Q8ICJ2e+iUCpVUIV
+8RudUeHt9qjSXalohuxxhegL5vu7I9Gx0H56RE4glOjLMCb1xqVZ55Odxx14pHaZ
+9iMnQFpgzi96exYAmBKYCHl4IFix2hrTqTWSJhEO+o+PXnQTgcfG43GQepk0qAQr
+iZZy8OWiUhHSJQLJtTMm4rnYjgPn+sLwx7hCPDZpHTZocETDars7wTiVkodCbeEU
+uKahAbq4b6MvvC3+7quvwoEpAEStT7+Yml+QuK/jKmhjX0hcQcw4ZWi+m32RjUAv
+xDJGEvBqV2hyrzRqwh4lVNJEBba5X+QB3N6a0So6BENaJrUM3v8EDaS2KLUWyu0=
+-----END CERTIFICATE-----
diff --git a/testing/tests/multi-level-ca/posttest.dat b/testing/tests/multi-level-ca/posttest.dat
new file mode 100644
index 000000000..1646d5ed2
--- /dev/null
+++ b/testing/tests/multi-level-ca/posttest.dat
@@ -0,0 +1,5 @@
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
+moon::rm /etc/ipsec.d/cacerts/*
+
diff --git a/testing/tests/multi-level-ca/pretest.dat b/testing/tests/multi-level-ca/pretest.dat
new file mode 100644
index 000000000..67c50c2ef
--- /dev/null
+++ b/testing/tests/multi-level-ca/pretest.dat
@@ -0,0 +1,9 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up alice
+carol::ipsec up venus
+dave::ipsec up venus
+dave::ipsec up alice
diff --git a/testing/tests/multi-level-ca/test.conf b/testing/tests/multi-level-ca/test.conf
new file mode 100644
index 000000000..08e5cc145
--- /dev/null
+++ b/testing/tests/multi-level-ca/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice venus moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-v-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/nat-one-rw/description.txt b/testing/tests/nat-one-rw/description.txt
new file mode 100644
index 000000000..c3b9bb820
--- /dev/null
+++ b/testing/tests/nat-one-rw/description.txt
@@ -0,0 +1,5 @@
+The roadwarrior <b>alice</b> sitting behind the NAT router <b>moon</b> sets up a tunnel to
+gateway <b>sun</b>. UDP encapsulation is used to traverse the NAT router.
+<b>leftfirewall=yes</b> automatically inserts iptables-based firewall rules that let pass
+the tunneled traffic. In order to test the tunnel, the NAT-ed host <b>alice</b> pings the
+client <b>bob</b> behind the gateway <b>sun</b>.
diff --git a/testing/tests/nat-one-rw/evaltest.dat b/testing/tests/nat-one-rw/evaltest.dat
new file mode 100644
index 000000000..bc193963d
--- /dev/null
+++ b/testing/tests/nat-one-rw/evaltest.dat
@@ -0,0 +1,5 @@
+alice::ipsec status::nat-t.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::nat-t.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+moon::tcpdump::IP moon.strongswan.org.* > sun.strongswan.org.ipsec-nat-t: UDP::YES
+moon::tcpdump::IP sun.strongswan.org.ipsec-nat-t > moon.strongswan.org.*: UDP::YES
diff --git a/testing/tests/nat-one-rw/posttest.dat b/testing/tests/nat-one-rw/posttest.dat
new file mode 100644
index 000000000..af8e00575
--- /dev/null
+++ b/testing/tests/nat-one-rw/posttest.dat
@@ -0,0 +1,8 @@
+alice::iptables -v -n -L
+sun::iptables -v -n -L
+alice::ipsec stop
+sun::ipsec stop
+alice::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
+moon::iptables -t nat -F
+
diff --git a/testing/tests/nat-one-rw/pretest.dat b/testing/tests/nat-one-rw/pretest.dat
new file mode 100644
index 000000000..9dacc672c
--- /dev/null
+++ b/testing/tests/nat-one-rw/pretest.dat
@@ -0,0 +1,10 @@
+alice::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+moon::iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p udp -j SNAT --to-source PH_IP_MOON:1024-1100
+moon::iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p tcp -j SNAT --to-source PH_IP_MOON:2000-2100
+alice::ipsec start
+sun::ipsec start
+alice::sleep 5
+alice::ipsec up nat-t
+
diff --git a/testing/tests/nat-one-rw/test.conf b/testing/tests/nat-one-rw/test.conf
new file mode 100644
index 000000000..d84149aaf
--- /dev/null
+++ b/testing/tests/nat-one-rw/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="alice sun"
diff --git a/testing/tests/nat-two-rw/description.txt b/testing/tests/nat-two-rw/description.txt
new file mode 100644
index 000000000..dcf4b94bd
--- /dev/null
+++ b/testing/tests/nat-two-rw/description.txt
@@ -0,0 +1,5 @@
+The roadwarriors <b>alice</b> and <b>venus</b> sitting behind the NAT router <b>moon</b> set up
+tunnels to gateway <b>sun</b>. UDP encapsulation is used to traverse the NAT router.
+<b>leftfirewall=yes</b> automatically inserts iptables-based firewall rules that let pass
+the tunneled traffic. In order to test the tunnel, the NAT-ed hosts <b>alice</b> and <b>venus</b>
+ping the client <b>bob</b> behind the gateway <b>sun</b>.
diff --git a/testing/tests/nat-two-rw/evaltest.dat b/testing/tests/nat-two-rw/evaltest.dat
new file mode 100644
index 000000000..b1a7d59ee
--- /dev/null
+++ b/testing/tests/nat-two-rw/evaltest.dat
@@ -0,0 +1,9 @@
+alice::ipsec status::nat-t.*STATE_QUICK_I2.*IPsec SA established::YES
+venus::ipsec status::nat-t.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::nat-t.*STATE_QUICK_R2.*IPsec SA established::YES
+sun::ipsec status::nat-t.*alice@strongswan.org::YES
+sun::ipsec status::nat-t.*@venus.strongswan.org::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+venus::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+moon::tcpdump::IP moon.strongswan.org.* > sun.strongswan.org.ipsec-nat-t: UDP::YES
+moon::tcpdump::IP sun.strongswan.org.ipsec-nat-t > moon.strongswan.org.*: UDP::YES
diff --git a/testing/tests/nat-two-rw/posttest.dat b/testing/tests/nat-two-rw/posttest.dat
new file mode 100644
index 000000000..f019842ed
--- /dev/null
+++ b/testing/tests/nat-two-rw/posttest.dat
@@ -0,0 +1,11 @@
+alice::iptables -v -n -L
+venus::iptables -v -n -L
+sun::iptables -v -n -L
+sun::ipsec stop
+alice::ipsec stop
+venus::ipsec stop
+alice::/etc/init.d/iptables stop 2> /dev/null
+venus::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
+moon::iptables -t nat -F
+
diff --git a/testing/tests/nat-two-rw/pretest.dat b/testing/tests/nat-two-rw/pretest.dat
new file mode 100644
index 000000000..dd5259936
--- /dev/null
+++ b/testing/tests/nat-two-rw/pretest.dat
@@ -0,0 +1,13 @@
+alice::/etc/init.d/iptables start 2> /dev/null
+venus::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+moon::iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p udp -j SNAT --to-source PH_IP_MOON:1024-1100
+moon::iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p tcp -j SNAT --to-source PH_IP_MOON:2000-2100
+alice::ipsec start
+venus::ipsec start
+sun::ipsec start
+alice::sleep 5
+alice::ipsec up nat-t
+venus::sleep 5
+venus::ipsec up nat-t
diff --git a/testing/tests/nat-two-rw/test.conf b/testing/tests/nat-two-rw/test.conf
new file mode 100644
index 000000000..84317fd70
--- /dev/null
+++ b/testing/tests/nat-two-rw/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice venus moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-v-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="alice venus sun"
diff --git a/testing/tests/net2net-cert/description.txt b/testing/tests/net2net-cert/description.txt
new file mode 100644
index 000000000..7eea9192f
--- /dev/null
+++ b/testing/tests/net2net-cert/description.txt
@@ -0,0 +1,6 @@
+A connection between the subnets behind the gateways <b>moon</b> and <b>sun</b> is set up.
+The authentication is based on <b>X.509 certificates</b>. Upon the successful
+establishment of the IPsec tunnel, <b>leftfirewall=yes</b> automatically
+inserts iptables-based firewall rules that let pass the tunneled traffic.
+In order to test both tunnel and firewall, client <b>alice</b> behind gateway <b>moon</b>
+pings client <b>bob</b> located behind gateway <b>sun</b>.
diff --git a/testing/tests/net2net-cert/evaltest.dat b/testing/tests/net2net-cert/evaltest.dat
new file mode 100644
index 000000000..7cbf92687
--- /dev/null
+++ b/testing/tests/net2net-cert/evaltest.dat
@@ -0,0 +1,5 @@
+moon::ipsec status::net-net.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::net-net.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/net2net-cert/posttest.dat b/testing/tests/net2net-cert/posttest.dat
new file mode 100644
index 000000000..52979508d
--- /dev/null
+++ b/testing/tests/net2net-cert/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+sun::iptables -v -n -L
+moon::ipsec stop
+sun::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/net2net-cert/pretest.dat b/testing/tests/net2net-cert/pretest.dat
new file mode 100644
index 000000000..9f60760c6
--- /dev/null
+++ b/testing/tests/net2net-cert/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+sun::ipsec start
+moon::sleep 2
+moon::ipsec up net-net
diff --git a/testing/tests/net2net-cert/test.conf b/testing/tests/net2net-cert/test.conf
new file mode 100644
index 000000000..d9a61590f
--- /dev/null
+++ b/testing/tests/net2net-cert/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/net2net-pgp/description.txt b/testing/tests/net2net-pgp/description.txt
new file mode 100644
index 000000000..c85f2e5d0
--- /dev/null
+++ b/testing/tests/net2net-pgp/description.txt
@@ -0,0 +1,6 @@
+A connection between the subnets behind the gateways <b>moon</b> and <b>sun</b> is set up.
+The authentication is based on <b>OpenPGP keys</b>. Upon the successful
+establishment of the IPsec tunnel, <b>leftfirewall=yes</b> automatically
+inserts iptables-based firewall rules that let pass the tunneled traffic.
+In order to test both tunnel and firewall, client <b>alice</b> behind gateway <b>moon</b>
+pings client <b>bob</b> located behind gateway <b>sun</b>.
diff --git a/testing/tests/net2net-pgp/evaltest.dat b/testing/tests/net2net-pgp/evaltest.dat
new file mode 100644
index 000000000..7cbf92687
--- /dev/null
+++ b/testing/tests/net2net-pgp/evaltest.dat
@@ -0,0 +1,5 @@
+moon::ipsec status::net-net.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::net-net.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.conf b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..e7de6cf0b
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ nocrsend=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftcert=moonCert.asc
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightcert=sunCert.asc
+ auto=add
diff --git a/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/certs/moonCert.asc b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/certs/moonCert.asc
new file mode 100644
index 000000000..135cfaec0
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/certs/moonCert.asc
@@ -0,0 +1,15 @@
+Type Bits/KeyID Date User ID
+pub 1024/613A3B61 2005/08/07 moon <moon.strongswan.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3i
+
+mQCNA0L2KI8AAAEEAM5GYrwuf1M9Cv7+Yfr6i5+17zMVGIyj/D4+msK43iUbEH61
++bhRKcrF+9NKvM+ujjZoUbfGjUipsBbTlPTaY7muZ9KaVy2OBHm73x13eiemkPS9
+RFWesrL9L39aBO5K47ti0PwRP8QIPMaNWMs2z7yoZLE/flVNQfWsCnlhOjthAAUR
+tBptb29uIDxtb29uLnN0cm9uZ3N3YW4ub3JnPokAlQMFEEL2KI/1rAp5YTo7YQEB
+vX4EAKtr0e6WMDIRlpE4VhhdQ7AgBgGyhgfqAdD9KDx8o4fG4nkmh7H1bG/PLJA1
+f+UfDGnOyIwPOrILNyNnwAbDHXjJaNylahM7poOP7i0VlbhZPLAC0cSQi02/Zrac
+t5bED5tHSrNSjcA/CjuxRuu9lmR6s57IQnQnwt9I4LTM+CFP
+=oaBj
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/certs/sunCert.asc b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/certs/sunCert.asc
new file mode 100644
index 000000000..32f204b10
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/certs/sunCert.asc
@@ -0,0 +1,15 @@
+Type Bits/KeyID Date User ID
+pub 1024/79949ADD 2005/08/07 sun <sun.strongswan.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3i
+
+mQCNA0L2Km8AAAEEANRAVMn8HBxfYaGhLqtQ3IZJArn9wpcQ+7sH/F9PaXIjzHRQ
+rfFkfmxxp9lVjCk0LM/BnnlnUmyz6F8K7V0Gi40Am4+ln1zHvZZIQJYGrDhDnjb7
+I5TVeD4Ib5bQ1CoUbIhv2LocCeR6OjefQgGmerC5RQ3d5ci7uB0pVpd5lJrdAAUR
+tBhzdW4gPHN1bi5zdHJvbmdzd2FuLm9yZz6JAJUDBRBC9ipvHSlWl3mUmt0BAUZR
+A/43nuZbxADMSviu54Mj8pvQbYeGLQVabiWT6h7L0ZPX4MWpFH3dTixBfRrZRSsj
+0AgiMMuZAMebfOe+Xf9uDQv7p1yumEiNg43tg85zyawkARWNTZZ04woxtvAqNwXn
+lQotGz7YA6JMxry9RQo5yI4Y4dPnVZ/o8eDpP0+I88cOhQ==
+=lLvB
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/private/moonKey.asc b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/private/moonKey.asc
new file mode 100644
index 000000000..6524773e0
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.d/private/moonKey.asc
@@ -0,0 +1,19 @@
+Type Bits/KeyID Date User ID
+sec 1024/613A3B61 2005/08/07 moon <moon.strongswan.org>
+
+-----BEGIN PGP SECRET KEY BLOCK-----
+Version: 2.6.3i
+
+lQHYA0L2KI8AAAEEAM5GYrwuf1M9Cv7+Yfr6i5+17zMVGIyj/D4+msK43iUbEH61
++bhRKcrF+9NKvM+ujjZoUbfGjUipsBbTlPTaY7muZ9KaVy2OBHm73x13eiemkPS9
+RFWesrL9L39aBO5K47ti0PwRP8QIPMaNWMs2z7yoZLE/flVNQfWsCnlhOjthAAUR
+AAP9Fj7OaaCfTL3Met8yuS8ZGMDL/fq+4f2bM+OdPSgD4N1Fiye0B1QMCVGWI1Xd
+JXS0+9QI0A3iD12YAnYwsP50KmsLHA69AqchN7BuimoMfHDXqpTSRW57E9MCEzQ9
+FFN8mVPRiDxAUro8qCjdHmk1vmtdt/PXn1BuXHE36SzZmmMCANBA4WHaO6MJshM6
+7StRicSCxoMn/lPcj6rfJS4EaS+a0MwECxKQ3HKTpP3/+7kaWfLI/D65Xmi3cVK3
+0CPwUK8CAP2RYWoBZPSA8dBGFYwR7W6bdNYhdmGmsVCaM7v4sVr0FwHwMERadByN
+8v0n5As3ZbrCURRp68wuE+JjfOM5mO8CAM3ZK7AVlBOqkoI3X3Ji3yviLlsr2ET7
+QrVKFQBq7eUhwYFo6mVemEqQb61tGirq+qL4Wfk/7+FffZPsUyLX1amfjLQabW9v
+biA8bW9vbi5zdHJvbmdzd2FuLm9yZz4=
+=YFQm
+-----END PGP SECRET KEY BLOCK-----
diff --git a/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.secrets b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..afb1ff927
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA moonKey.asc
diff --git a/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.conf b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.conf
new file mode 100755
index 000000000..5dd8a8587
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ nocrsend=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_SUN
+ leftsubnet=10.2.0.0/16
+ leftcert=sunCert.asc
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightcert=moonCert.asc
+ auto=add
diff --git a/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/certs/moonCert.asc b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/certs/moonCert.asc
new file mode 100644
index 000000000..135cfaec0
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/certs/moonCert.asc
@@ -0,0 +1,15 @@
+Type Bits/KeyID Date User ID
+pub 1024/613A3B61 2005/08/07 moon <moon.strongswan.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3i
+
+mQCNA0L2KI8AAAEEAM5GYrwuf1M9Cv7+Yfr6i5+17zMVGIyj/D4+msK43iUbEH61
++bhRKcrF+9NKvM+ujjZoUbfGjUipsBbTlPTaY7muZ9KaVy2OBHm73x13eiemkPS9
+RFWesrL9L39aBO5K47ti0PwRP8QIPMaNWMs2z7yoZLE/flVNQfWsCnlhOjthAAUR
+tBptb29uIDxtb29uLnN0cm9uZ3N3YW4ub3JnPokAlQMFEEL2KI/1rAp5YTo7YQEB
+vX4EAKtr0e6WMDIRlpE4VhhdQ7AgBgGyhgfqAdD9KDx8o4fG4nkmh7H1bG/PLJA1
+f+UfDGnOyIwPOrILNyNnwAbDHXjJaNylahM7poOP7i0VlbhZPLAC0cSQi02/Zrac
+t5bED5tHSrNSjcA/CjuxRuu9lmR6s57IQnQnwt9I4LTM+CFP
+=oaBj
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/certs/sunCert.asc b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/certs/sunCert.asc
new file mode 100644
index 000000000..32f204b10
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/certs/sunCert.asc
@@ -0,0 +1,15 @@
+Type Bits/KeyID Date User ID
+pub 1024/79949ADD 2005/08/07 sun <sun.strongswan.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3i
+
+mQCNA0L2Km8AAAEEANRAVMn8HBxfYaGhLqtQ3IZJArn9wpcQ+7sH/F9PaXIjzHRQ
+rfFkfmxxp9lVjCk0LM/BnnlnUmyz6F8K7V0Gi40Am4+ln1zHvZZIQJYGrDhDnjb7
+I5TVeD4Ib5bQ1CoUbIhv2LocCeR6OjefQgGmerC5RQ3d5ci7uB0pVpd5lJrdAAUR
+tBhzdW4gPHN1bi5zdHJvbmdzd2FuLm9yZz6JAJUDBRBC9ipvHSlWl3mUmt0BAUZR
+A/43nuZbxADMSviu54Mj8pvQbYeGLQVabiWT6h7L0ZPX4MWpFH3dTixBfRrZRSsj
+0AgiMMuZAMebfOe+Xf9uDQv7p1yumEiNg43tg85zyawkARWNTZZ04woxtvAqNwXn
+lQotGz7YA6JMxry9RQo5yI4Y4dPnVZ/o8eDpP0+I88cOhQ==
+=lLvB
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/private/sunKey.asc b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/private/sunKey.asc
new file mode 100644
index 000000000..de2393649
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.d/private/sunKey.asc
@@ -0,0 +1,19 @@
+Type Bits/KeyID Date User ID
+sec 1024/79949ADD 2005/08/07 sun <sun.strongswan.org>
+
+-----BEGIN PGP SECRET KEY BLOCK-----
+Version: 2.6.3i
+
+lQHYA0L2Km8AAAEEANRAVMn8HBxfYaGhLqtQ3IZJArn9wpcQ+7sH/F9PaXIjzHRQ
+rfFkfmxxp9lVjCk0LM/BnnlnUmyz6F8K7V0Gi40Am4+ln1zHvZZIQJYGrDhDnjb7
+I5TVeD4Ib5bQ1CoUbIhv2LocCeR6OjefQgGmerC5RQ3d5ci7uB0pVpd5lJrdAAUR
+AAP8DHxBOQ7UeiO6cutdGSLfy6nxGf/eRR8d3dNLFKpRfy9IQxPN/yQHb8pzSQUI
+Pqi3V4PcJUJQJIMNqzzgyTyey/OdTc+IFngywRGKQowyD7vY+urVbcEDHe+sRTL1
+GvrsQGMZoXNDimABHn5NbT6Pc06xQ9rNvpCSyHMyzcylpk0CANqf96aEaryGJozg
+vSN5GlS77rPJ9Y9mU2EJs1+0BlMcb7Sy4HN2RRc/V56ZmlW2m3UbGwPqG8R9XQQ2
+LO03bTcCAPiJbTcRdA/YnZExbZPgEnV5nq8tVXTc7bz1Sw7ZWRef0iZyIQEXbwLn
+2Z2EJik9bQpkcVJSBV17cH7Av/VdIosCAKJPVoBETiVzWejIpGHHqbnmZC8P9rUs
+xAXZbNukbL3YElLeopNMyddTi6kf45/m0sb7fr7rzW/OJ7WP8mDrGPec4rQYc3Vu
+IDxzdW4uc3Ryb25nc3dhbi5vcmc+
+=DwEu
+-----END PGP SECRET KEY BLOCK-----
diff --git a/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.secrets b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.secrets
new file mode 100644
index 000000000..ee98b1611
--- /dev/null
+++ b/testing/tests/net2net-pgp/hosts/sun/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA sunKey.asc
diff --git a/testing/tests/net2net-pgp/posttest.dat b/testing/tests/net2net-pgp/posttest.dat
new file mode 100644
index 000000000..80e765dfc
--- /dev/null
+++ b/testing/tests/net2net-pgp/posttest.dat
@@ -0,0 +1,10 @@
+moon::iptables -v -n -L
+sun::iptables -v -n -L
+moon::ipsec stop
+sun::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
+moon::rm /etc/ipsec.d/certs/*
+moon::rm /etc/ipsec.d/private/*
+sun::rm /etc/ipsec.d/certs/*
+sun::rm /etc/ipsec.d/private/*
diff --git a/testing/tests/net2net-pgp/pretest.dat b/testing/tests/net2net-pgp/pretest.dat
new file mode 100644
index 000000000..9e40684ab
--- /dev/null
+++ b/testing/tests/net2net-pgp/pretest.dat
@@ -0,0 +1,8 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::rm /etc/ipsec.d/cacerts/*
+sun::rm /etc/ipsec.d/cacerts/*
+moon::ipsec start
+sun::ipsec start
+moon::sleep 2
+moon::ipsec up net-net
diff --git a/testing/tests/net2net-pgp/test.conf b/testing/tests/net2net-pgp/test.conf
new file mode 100644
index 000000000..f74d0f7d6
--- /dev/null
+++ b/testing/tests/net2net-pgp/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/net2net-psk-fail/description.txt b/testing/tests/net2net-psk-fail/description.txt
new file mode 100644
index 000000000..5a794bd17
--- /dev/null
+++ b/testing/tests/net2net-psk-fail/description.txt
@@ -0,0 +1,7 @@
+An IPsec tunnel connecting the subnets behind the gateways <b>moon</b> and
+<b>sun</b> is set up. The authentication is based on <b>Preshared Keys</b>
+(PSK). Unfortunately the secret keys of <b>moon</b> and <b>sun</b> do not
+match, so that the responder cannot decrypt ISAKMP message MI3. The resulting
+encrypted notification message cannot in turn be read by the initiator
+<b>moon</b>. In order to avoid a <b>notify-war</b>, any further generation of
+PAYLOAD_MALFORMED messages is suppressed.
diff --git a/testing/tests/net2net-psk-fail/evaltest.dat b/testing/tests/net2net-psk-fail/evaltest.dat
new file mode 100644
index 000000000..7f7cb9726
--- /dev/null
+++ b/testing/tests/net2net-psk-fail/evaltest.dat
@@ -0,0 +1,6 @@
+moon::cat /var/log/auth.log::malformed payload in packet::YES
+sun::cat /var/log/auth.log::probable authentication failure.*mismatch of preshared secrets.*malformed payload in packet::YES
+sun::cat /var/log/auth.log::sending encrypted notification PAYLOAD_MALFORMED::YES
+moon::ipsec status::net-net.*STATE_MAIN_I4.*ISAKMP SA established::NO
+sun::ipsec status::net-net.*STATE_MAIN_R3.*ISAKMP SA established::NO
+
diff --git a/testing/tests/net2net-psk-fail/hosts/moon/etc/ipsec.conf b/testing/tests/net2net-psk-fail/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..87396e455
--- /dev/null
+++ b/testing/tests/net2net-psk-fail/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,23 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftid=@moon.strongswan.org
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=add
diff --git a/testing/tests/net2net-psk-fail/hosts/moon/etc/ipsec.secrets b/testing/tests/net2net-psk-fail/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..be95c4d99
--- /dev/null
+++ b/testing/tests/net2net-psk-fail/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+@moon.strongswan.org @sun.strongswan.org : PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/net2net-psk-fail/hosts/sun/etc/ipsec.conf b/testing/tests/net2net-psk-fail/hosts/sun/etc/ipsec.conf
new file mode 100755
index 000000000..7e102b25c
--- /dev/null
+++ b/testing/tests/net2net-psk-fail/hosts/sun/etc/ipsec.conf
@@ -0,0 +1,23 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_SUN
+ leftsubnet=10.2.0.0/16
+ leftid=@sun.strongswan.org
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/net2net-psk-fail/hosts/sun/etc/ipsec.secrets b/testing/tests/net2net-psk-fail/hosts/sun/etc/ipsec.secrets
new file mode 100644
index 000000000..b53577e1d
--- /dev/null
+++ b/testing/tests/net2net-psk-fail/hosts/sun/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+@moon.strongswan.org @sun.strongswan.org : PSK 0sZNbttZkdViYmLWprfhiZBtDjJbNAMHil
+
+
+
+
diff --git a/testing/tests/net2net-psk-fail/posttest.dat b/testing/tests/net2net-psk-fail/posttest.dat
new file mode 100644
index 000000000..dff181797
--- /dev/null
+++ b/testing/tests/net2net-psk-fail/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+sun::ipsec stop
diff --git a/testing/tests/net2net-psk-fail/pretest.dat b/testing/tests/net2net-psk-fail/pretest.dat
new file mode 100644
index 000000000..aa8e332e0
--- /dev/null
+++ b/testing/tests/net2net-psk-fail/pretest.dat
@@ -0,0 +1,6 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+sun::echo 1 > /proc/sys/net/ipv4/ip_forward
+moon::ipsec start
+sun::ipsec start
+moon::sleep 2
+moon::ipsec up net-net
diff --git a/testing/tests/net2net-psk-fail/test.conf b/testing/tests/net2net-psk-fail/test.conf
new file mode 100644
index 000000000..f6e064e7d
--- /dev/null
+++ b/testing/tests/net2net-psk-fail/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon winnetou sun"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-w-s.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/net2net-psk/description.txt b/testing/tests/net2net-psk/description.txt
new file mode 100644
index 000000000..02cddbb83
--- /dev/null
+++ b/testing/tests/net2net-psk/description.txt
@@ -0,0 +1,6 @@
+A connection between the subnets behind the gateways <b>moon</b> and <b>sun</b> is set up.
+The authentication is based on <b>Preshared Keys</b> (PSK). Upon the successful
+establishment of the IPsec tunnel, <b>leftfirewall=yes</b> automatically
+inserts iptables-based firewall rules that let pass the tunneled traffic.
+In order to test both tunnel and firewall, client <b>alice</b> behind gateway <b>moon</b>
+pings client <b>bob</b> located behind gateway <b>sun</b>.
diff --git a/testing/tests/net2net-psk/evaltest.dat b/testing/tests/net2net-psk/evaltest.dat
new file mode 100644
index 000000000..7cbf92687
--- /dev/null
+++ b/testing/tests/net2net-psk/evaltest.dat
@@ -0,0 +1,5 @@
+moon::ipsec status::net-net.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::net-net.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/net2net-psk/hosts/moon/etc/ipsec.conf b/testing/tests/net2net-psk/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..51c53a505
--- /dev/null
+++ b/testing/tests/net2net-psk/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=add
diff --git a/testing/tests/net2net-psk/hosts/moon/etc/ipsec.secrets b/testing/tests/net2net-psk/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..be95c4d99
--- /dev/null
+++ b/testing/tests/net2net-psk/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+@moon.strongswan.org @sun.strongswan.org : PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/net2net-psk/hosts/sun/etc/ipsec.conf b/testing/tests/net2net-psk/hosts/sun/etc/ipsec.conf
new file mode 100755
index 000000000..9c3695178
--- /dev/null
+++ b/testing/tests/net2net-psk/hosts/sun/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_SUN
+ leftsubnet=10.2.0.0/16
+ leftid=@sun.strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/net2net-psk/hosts/sun/etc/ipsec.secrets b/testing/tests/net2net-psk/hosts/sun/etc/ipsec.secrets
new file mode 100644
index 000000000..be95c4d99
--- /dev/null
+++ b/testing/tests/net2net-psk/hosts/sun/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+@moon.strongswan.org @sun.strongswan.org : PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/net2net-psk/posttest.dat b/testing/tests/net2net-psk/posttest.dat
new file mode 100644
index 000000000..52979508d
--- /dev/null
+++ b/testing/tests/net2net-psk/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+sun::iptables -v -n -L
+moon::ipsec stop
+sun::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/net2net-psk/pretest.dat b/testing/tests/net2net-psk/pretest.dat
new file mode 100644
index 000000000..9e40684ab
--- /dev/null
+++ b/testing/tests/net2net-psk/pretest.dat
@@ -0,0 +1,8 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::rm /etc/ipsec.d/cacerts/*
+sun::rm /etc/ipsec.d/cacerts/*
+moon::ipsec start
+sun::ipsec start
+moon::sleep 2
+moon::ipsec up net-net
diff --git a/testing/tests/net2net-psk/test.conf b/testing/tests/net2net-psk/test.conf
new file mode 100644
index 000000000..f74d0f7d6
--- /dev/null
+++ b/testing/tests/net2net-psk/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/net2net-route/description.txt b/testing/tests/net2net-route/description.txt
new file mode 100644
index 000000000..323f09555
--- /dev/null
+++ b/testing/tests/net2net-route/description.txt
@@ -0,0 +1,9 @@
+A tunnel that will connect the subnets behind the gateways <b>moon</b>
+and <b>sun</b>, respectively, is preconfigured by installing a %trap eroute
+on gateway <b>moon</b> by means of the setting <b>auto=route</b> in ipsec.conf.
+A subsequent ping issued by client <b>alice</b> behind gateway <b>moon</b> to
+<b>bob</b> located behind gateway <b>sun</b> triggers the %trap eroute and
+leads to the automatic establishment of the subnet-to-subnet tunnel.
+<p>
+<b>leftfirewall=yes</b> automatically inserts iptables-based firewall rules
+that let pass the tunneled traffic.
diff --git a/testing/tests/net2net-route/evaltest.dat b/testing/tests/net2net-route/evaltest.dat
new file mode 100644
index 000000000..38d589e5a
--- /dev/null
+++ b/testing/tests/net2net-route/evaltest.dat
@@ -0,0 +1,6 @@
+moon::cat /var/log/auth.log::initiate on demand from PH_IP_ALICE::YES
+moon::ipsec status::net-net.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::net-net.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/net2net-route/hosts/moon/etc/ipsec.conf b/testing/tests/net2net-route/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..4063ae05f
--- /dev/null
+++ b/testing/tests/net2net-route/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=route
diff --git a/testing/tests/net2net-route/posttest.dat b/testing/tests/net2net-route/posttest.dat
new file mode 100644
index 000000000..52979508d
--- /dev/null
+++ b/testing/tests/net2net-route/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+sun::iptables -v -n -L
+moon::ipsec stop
+sun::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/net2net-route/pretest.dat b/testing/tests/net2net-route/pretest.dat
new file mode 100644
index 000000000..2eef7de19
--- /dev/null
+++ b/testing/tests/net2net-route/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+sun::ipsec start
+moon::sleep 2
+alice::ping -c 10 PH_IP_BOB
diff --git a/testing/tests/net2net-route/test.conf b/testing/tests/net2net-route/test.conf
new file mode 100644
index 000000000..d9a61590f
--- /dev/null
+++ b/testing/tests/net2net-route/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/net2net-rsa/description.txt b/testing/tests/net2net-rsa/description.txt
new file mode 100644
index 000000000..a23fae8c3
--- /dev/null
+++ b/testing/tests/net2net-rsa/description.txt
@@ -0,0 +1,6 @@
+A connection between the subnets behind the gateways <b>moon</b> and <b>sun</b> is set up.
+The authentication is based on <b>raw RSA keys</b>. Upon the successful
+establishment of the IPsec tunnel, <b>leftfirewall=yes</b> automatically
+inserts iptables-based firewall rules that let pass the tunneled traffic.
+In order to test both tunnel and firewall, client <b>alice</b> behind gateway <b>moon</b>
+pings client <b>bob</b> located behind gateway <b>sun</b>.
diff --git a/testing/tests/net2net-rsa/evaltest.dat b/testing/tests/net2net-rsa/evaltest.dat
new file mode 100644
index 000000000..7cbf92687
--- /dev/null
+++ b/testing/tests/net2net-rsa/evaltest.dat
@@ -0,0 +1,5 @@
+moon::ipsec status::net-net.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::net-net.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/net2net-rsa/hosts/moon/etc/ipsec.conf b/testing/tests/net2net-rsa/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..772762321
--- /dev/null
+++ b/testing/tests/net2net-rsa/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftid=@moon.strongswan.org
+ leftrsasigkey=0sAQN+mkeECF5Bm7XnDkkkfmgny/TZndTkN1XzFZWB7nJroM3cTk3zMtdSPX8hY9GQxVGWSsmUBq7mGA5Qx39JpRNpyzxW7wRcMbwqDquG1PRfblLzV1ixdXOGSLUNaXonqDI/h5fCkqTuZtLbE4q3Pf4PmQAwzWVWaTZQ1gXXqUqKlN6218Hm2vbvNRE/CBHuFMmaCz11jckvaPvcqBLZzRTx9b/Mi+qD6xT7k9RpYHmtaGCJ95ed1bY6SZkapgHWu88/3M6bxCzD0KOA3oFbwlkHkFyaGWFB2+fc7L6BfYq0wr/d84tQdOxEn3BwLTrVKo7+6AxDrMi0I+blD2nd9cxj
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ rightrsasigkey=0sAQOiSuR9e/WMZFOxK3IdaFBOT2DGoObFDJURejqLcjMpmY2yVbA9Lpc+AEGKxqjb37WG6sVo3fBCDBOAhgmMw9s0b6DTSeXaIQloqW1M8IC+xe1fT+F0BsW1ttaEN0WTF5H+J+a4/arYg4HyiA+sjoqHagnCVPM15Rm5mkmg913XmSCgtkenD4WUq+NfPLuOcggqTjHAAoGD0doswRa3sebyqHQNAb32PXW9ecKi9ExcPrdr5hR5uNXRMYGumBtoxcE6xEvCM/sPRK1hbyynixc5nfMQ5Ymb4mdCUotUGaCyKDa4pF58sYgP6xpd/HXMXGdRP+KxqA4sfes46gp8UuJT
+ auto=add
diff --git a/testing/tests/net2net-rsa/hosts/moon/etc/ipsec.secrets b/testing/tests/net2net-rsa/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..9859ae8ed
--- /dev/null
+++ b/testing/tests/net2net-rsa/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,17 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA {
+ # RSA 2048 bits moon.strongswan.org Wed Dec 8 21:41:27 2004
+ # for signatures only, UNSAFE FOR ENCRYPTION
+ #pubkey=0sAQN+mkeECF5Bm7XnDkkkfmgny/TZndTkN1XzFZWB7nJroM3cTk3zMtdSPX8hY9GQxVGWSsmUBq7mGA5Qx39JpRNpyzxW7wRcMbwqDquG1PRfblLzV1ixdXOGSLUNaXonqDI/h5fCkqTuZtLbE4q3Pf4PmQAwzWVWaTZQ1gXXqUqKlN6218Hm2vbvNRE/CBHuFMmaCz11jckvaPvcqBLZzRTx9b/Mi+qD6xT7k9RpYHmtaGCJ95ed1bY6SZkapgHWu88/3M6bxCzD0KOA3oFbwlkHkFyaGWFB2+fc7L6BfYq0wr/d84tQdOxEn3BwLTrVKo7+6AxDrMi0I+blD2nd9cxj
+ Modulus: 0x7e9a4784085e419bb5e70e49247e6827cbf4d99dd4e43755f3159581ee726ba0cddc4e4df332d7523d7f2163d190c551964ac99406aee6180e50c77f49a51369cb3c56ef045c31bc2a0eab86d4f45f6e52f35758b175738648b50d697a27a8323f8797c292a4ee66d2db138ab73dfe0f990030cd6556693650d605d7a94a8a94deb6d7c1e6daf6ef35113f0811ee14c99a0b3d758dc92f68fbdca812d9cd14f1f5bfcc8bea83eb14fb93d4696079ad686089f7979dd5b63a49991aa601d6bbcf3fdcce9bc42cc3d0a380de815bc25907905c9a196141dbe7dcecbe817d8ab4c2bfddf38b5074ec449f70702d3ad52a8efee80c43acc8b423e6e50f69ddf5cc63
+ PublicExponent: 0x03
+ # everything after this point is secret
+ PrivateExponent: 0x1519b69601650aef48fbd7b6db6a66b14ca8ceefa37b5e8e532e4395a7bdbc9accfa0d0cfdddce8db4ea8590a2ed763843b72198abc7d1040262cbea8c462de6f734b927d60f5d9f5c57c741237e0fe7b87de3e41d9393410c1e2ce6e9b146b30a96994b1870d2667879d8971e8a5502998008223b8e66de62ce564e9c37171893a0e8a94749590fef394b9deda1e73937b1c664d2e4764ae49572771130a097024380c258fa25f9083eefc5eabe762d8e856237bdd8ad8217f899688f70ac1f37650dc08bf3748b74a4f30873842fe27bdfbc49d0cb14c3861ff18b1219153ddb69e5bcb09ff691473a856e63e23d2f36389959f804e82b13a547decc7d6df7
+ Prime1: 0xc11b8705063c662ee0a168b904bbd9c514025360c75e43e7c60c3c17846ede31bba328dfaf8abf513175f312a4263645db0f0797ca7f36d04f996680772264a63c1f76a2a2fe250aa0ca8e96122438bdd5b327e925742047f2b7d0fe3fa6ea07a10cd9a40f8994a95af505116131584c5fc247a7d69df08bfac1b5a23b7c157f
+ Prime2: 0xa7d5dcc534e67a60b918109b7b66cfad37de43b7d51025bfda4fbd30ee3a73362c879f1e251c47ed98a442b33bdcb2112e5aa2b160426e5d6a2c1bb22e104e6db75f0575d979e38146d89db8948500fad36b0875570b3f0ac5754440d14d4b47fa55b77b1d2b9033991c4a858256632759d22c80060d52957643aa8ed789231d
+ Exponent1: 0x80bd04ae0428441f406b9b260327e68362ac3795da3ed7efd95d7d6502f4942127c21b3fca5c7f8b764ea20c6d6eced93cb4afba86ff79e03510ef004f6c43197d6a4f17175418b1c08709b9616d7b2939221a9b6e4d6adaa1cfe0a97fc49c05160891180a5bb870e74e0360eb763add952c2fc539bea05d51d67916d252b8ff
+ Exponent2: 0x6fe3e8837899a6eb26100b1252448a737a942d2538b56e7fe6dfd375f426f779730514bec3682ff3bb182c777d3dcc0b743c6c76402c49939c1d67cc1eb5899e7a3f58f93ba697ab84906925b858ab51e2475af8e4b22a072e4e2d808b88dcdaa6e3cfa768c7b577bb6831ae56e4421a3be173000408e1b8f98271b48fb0c213
+ Coefficient: 0x0a9ea0e995d8d635ac37b5d5f1121ecd4d6387262ea65ea969499ec4c7af9d7a79b256654bda5c972b6efaf5aba35d6790ce4db39258930488ddb2443d19c344312380bed3290f29f0ff5b0ce382622c849f3279f653a2b7c4cc8efbfc5098852fe39aee9da947e53ddfe58bb6b7bb02b693a1b1228dc0481b681d51865d0339
+ }
+# do not change the indenting of that "}"
diff --git a/testing/tests/net2net-rsa/hosts/sun/etc/ipsec.conf b/testing/tests/net2net-rsa/hosts/sun/etc/ipsec.conf
new file mode 100755
index 000000000..9626ef168
--- /dev/null
+++ b/testing/tests/net2net-rsa/hosts/sun/etc/ipsec.conf
@@ -0,0 +1,25 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_SUN
+ leftsubnet=10.2.0.0/16
+ leftid=@sun.strongswan.org
+ leftrsasigkey=0sAQOiSuR9e/WMZFOxK3IdaFBOT2DGoObFDJURejqLcjMpmY2yVbA9Lpc+AEGKxqjb37WG6sVo3fBCDBOAhgmMw9s0b6DTSeXaIQloqW1M8IC+xe1fT+F0BsW1ttaEN0WTF5H+J+a4/arYg4HyiA+sjoqHagnCVPM15Rm5mkmg913XmSCgtkenD4WUq+NfPLuOcggqTjHAAoGD0doswRa3sebyqHQNAb32PXW9ecKi9ExcPrdr5hR5uNXRMYGumBtoxcE6xEvCM/sPRK1hbyynixc5nfMQ5Ymb4mdCUotUGaCyKDa4pF58sYgP6xpd/HXMXGdRP+KxqA4sfes46gp8UuJT
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ rightrsasigkey=0sAQN+mkeECF5Bm7XnDkkkfmgny/TZndTkN1XzFZWB7nJroM3cTk3zMtdSPX8hY9GQxVGWSsmUBq7mGA5Qx39JpRNpyzxW7wRcMbwqDquG1PRfblLzV1ixdXOGSLUNaXonqDI/h5fCkqTuZtLbE4q3Pf4PmQAwzWVWaTZQ1gXXqUqKlN6218Hm2vbvNRE/CBHuFMmaCz11jckvaPvcqBLZzRTx9b/Mi+qD6xT7k9RpYHmtaGCJ95ed1bY6SZkapgHWu88/3M6bxCzD0KOA3oFbwlkHkFyaGWFB2+fc7L6BfYq0wr/d84tQdOxEn3BwLTrVKo7+6AxDrMi0I+blD2nd9cxj
+ auto=add
diff --git a/testing/tests/net2net-rsa/hosts/sun/etc/ipsec.secrets b/testing/tests/net2net-rsa/hosts/sun/etc/ipsec.secrets
new file mode 100644
index 000000000..bf976a8d3
--- /dev/null
+++ b/testing/tests/net2net-rsa/hosts/sun/etc/ipsec.secrets
@@ -0,0 +1,17 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA {
+ # RSA 2048 bits sun.strongswan.org Wed Dec 8 21:44:27 2004
+ # for signatures only, UNSAFE FOR ENCRYPTION
+ #pubkey=0sAQOiSuR9e/WMZFOxK3IdaFBOT2DGoObFDJURejqLcjMpmY2yVbA9Lpc+AEGKxqjb37WG6sVo3fBCDBOAhgmMw9s0b6DTSeXaIQloqW1M8IC+xe1fT+F0BsW1ttaEN0WTF5H+J+a4/arYg4HyiA+sjoqHagnCVPM15Rm5mkmg913XmSCgtkenD4WUq+NfPLuOcggqTjHAAoGD0doswRa3sebyqHQNAb32PXW9ecKi9ExcPrdr5hR5uNXRMYGumBtoxcE6xEvCM/sPRK1hbyynixc5nfMQ5Ymb4mdCUotUGaCyKDa4pF58sYgP6xpd/HXMXGdRP+KxqA4sfes46gp8UuJT
+ Modulus: 0xa24ae47d7bf58c6453b12b721d68504e4f60c6a0e6c50c95117a3a8b723329998db255b03d2e973e00418ac6a8dbdfb586eac568ddf0420c138086098cc3db346fa0d349e5da210968a96d4cf080bec5ed5f4fe17406c5b5b6d6843745931791fe27e6b8fdaad88381f2880fac8e8a876a09c254f335e519b99a49a0f75dd79920a0b647a70f8594abe35f3cbb8e72082a4e31c0028183d1da2cc116b7b1e6f2a8740d01bdf63d75bd79c2a2f44c5c3eb76be61479b8d5d13181ae981b68c5c13ac44bc233fb0f44ad616f2ca78b17399df310e5899be26742528b5419a0b22836b8a45e7cb1880feb1a5dfc75cc5c67513fe2b1a80e2c7deb38ea0a7c52e253
+ PublicExponent: 0x03
+ # everything after this point is secret
+ PrivateExponent: 0x04eaff2a9726789e3114e24946b595d3d3dc250ca22500619bae5edd701110c697b0121c9d01696e7c21043490c0d83bcdc90dbd5c0f09c24e2aaeba78a1162860793cb4a9dfd274a614a638a27081e6f7ad8e0e96e8eeb7ee448fa49580941bb25e4ccf4d814c611373f49ba061690bdc6ce6dbc94f357ce69811bf0f40e780b643cbe7e076031f234e842b41bc10fb2d359617c64b434cb3dd4d9add91dcbcaef9fba1fb6f217a8ad65bde553bd2792c939ea8b5c0591598e7291597609a779a088e36c1ebe15ebb5e9a7774d9d9cd90913030b88e215f9e66fe0daafb198a3bb9d4e6277b625460ede2d84ce7f3334bf641829c826dbc1549625377c517db
+ Prime1: 0xfee3308b1f16875eeb4ca7ba6a9b8f9279eceff06531aae2bb50d2ccbf7f2b0901f2c5e046856c54c338f4b79943f8ad6d20a97fe0a48786cd659aff3f55e3a8c4c09cad526975180d1c2905ba028b58dd05a71d3a268153fae62eb5e9fe9184b20f9fbd626b14054c4acd7e2de69934d91cbf239c7a63c9d2721cd466df26eb
+ Prime2: 0xa3003cd898c297323377adeed7b4b214dc78e8bf0d9c2c0bef54ed53686547971847d7400e1d8055149ef6425e5241f28b43c8d52b48d281ae4fc7d0589ef8ad9ae95a05e2298cf679135cc0dd7378611e363380852313bfdc259cdb2543d5d1d1b492f6035ec72a2025529c5dff6995ad64b1b7dec3a3755a512073a50ba839
+ Exponent1: 0xa9eccb076a0f04e9f2331a7c47125fb6fbf34aa0437671ec7ce08c887faa1cb0abf72e958458f2e32cd0a32510d7fb1e48c070ffeb185a59de43bcaa2a394270832b131e36f0f8bab3681b5926ac5ce5e8ae6f68d16f00e2a7441f23f1546103215fbfd396f20d58dd8733a973ef10cde6132a17bda6ed3136f6bde2ef3f6f47
+ Exponent2: 0x6caad33b1081ba2177a51e9f3a7876b892fb45d4b3bd72b29f8df38cf043850f65853a2ab413aae36314a42c3ee1814c5cd7db38c785e1abc98a85359069fb1e67463c03ec1bb34efb623dd5e8f7a59614242255ae17627fe819133cc3828e8be1230ca4023f2f716ac38c683eaa4663c8edcbcfe9d7c24e3c3615a26e07c57b
+ Coefficient: 0xbf865c3ed94693c7f16e04fd73929d7b4a3a296d6113eb9b01e87d5cf3be71afa2f838a5a82a97b55e8309025214312edefd3b77c989054bf28ec81bf3989d698671cb64eac9f016cc136f6ab78ce4d5d3837198eea5ec8ed057ba8e0e6f240a60202171f65be992d7bcd54ee0f803e5bd6b8385223b55440e095b28f01bbd0a
+ }
+# do not change the indenting of that "}"
diff --git a/testing/tests/net2net-rsa/posttest.dat b/testing/tests/net2net-rsa/posttest.dat
new file mode 100644
index 000000000..52979508d
--- /dev/null
+++ b/testing/tests/net2net-rsa/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+sun::iptables -v -n -L
+moon::ipsec stop
+sun::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/net2net-rsa/pretest.dat b/testing/tests/net2net-rsa/pretest.dat
new file mode 100644
index 000000000..9e40684ab
--- /dev/null
+++ b/testing/tests/net2net-rsa/pretest.dat
@@ -0,0 +1,8 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::rm /etc/ipsec.d/cacerts/*
+sun::rm /etc/ipsec.d/cacerts/*
+moon::ipsec start
+sun::ipsec start
+moon::sleep 2
+moon::ipsec up net-net
diff --git a/testing/tests/net2net-rsa/test.conf b/testing/tests/net2net-rsa/test.conf
new file mode 100644
index 000000000..f74d0f7d6
--- /dev/null
+++ b/testing/tests/net2net-rsa/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/net2net-start/description.txt b/testing/tests/net2net-start/description.txt
new file mode 100644
index 000000000..f5320685e
--- /dev/null
+++ b/testing/tests/net2net-start/description.txt
@@ -0,0 +1,8 @@
+A tunnel connecting the subnets behind the gateways <b>moon</b> and <b>sun</b>,
+respectively, is automatically established by means of the setting
+<b>auto=start</b> in ipsec.conf. The connection is tested by client <b>alice</b>
+behind gateway <b>moon</b> pinging the client <b>bob</b> located behind
+gateway <b>sun</b>.
+<p>
+<b>leftfirewall=yes</b> automatically inserts iptables-based firewall rules
+that let pass the tunneled traffic.
diff --git a/testing/tests/net2net-start/evaltest.dat b/testing/tests/net2net-start/evaltest.dat
new file mode 100644
index 000000000..7cbf92687
--- /dev/null
+++ b/testing/tests/net2net-start/evaltest.dat
@@ -0,0 +1,5 @@
+moon::ipsec status::net-net.*STATE_QUICK_I2.*IPsec SA established::YES
+sun::ipsec status::net-net.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES
+sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
+sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
diff --git a/testing/tests/net2net-start/hosts/moon/etc/ipsec.conf b/testing/tests/net2net-start/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..677955bc1
--- /dev/null
+++ b/testing/tests/net2net-start/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ leftnexthop=%direct
+
+conn net-net
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=start
diff --git a/testing/tests/net2net-start/posttest.dat b/testing/tests/net2net-start/posttest.dat
new file mode 100644
index 000000000..52979508d
--- /dev/null
+++ b/testing/tests/net2net-start/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+sun::iptables -v -n -L
+moon::ipsec stop
+sun::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+sun::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/net2net-start/pretest.dat b/testing/tests/net2net-start/pretest.dat
new file mode 100644
index 000000000..ed8f39316
--- /dev/null
+++ b/testing/tests/net2net-start/pretest.dat
@@ -0,0 +1,5 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+sun::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+sun::ipsec start
+alice::sleep 12
diff --git a/testing/tests/net2net-start/test.conf b/testing/tests/net2net-start/test.conf
new file mode 100644
index 000000000..d9a61590f
--- /dev/null
+++ b/testing/tests/net2net-start/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon winnetou sun bob"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon sun"
diff --git a/testing/tests/no-priv-key/description.txt b/testing/tests/no-priv-key/description.txt
new file mode 100644
index 000000000..21b8eccb1
--- /dev/null
+++ b/testing/tests/no-priv-key/description.txt
@@ -0,0 +1,4 @@
+This scenario tests whether the correct encrypted informational messages are
+generated by the initiator <b>carol</b> and subsequently decoded by the
+responder <b>moon</b> when roadwarrior <b>carol</b> finds out that she
+doesn't have a private RSA key to sign her hash with.
diff --git a/testing/tests/no-priv-key/evaltest.dat b/testing/tests/no-priv-key/evaltest.dat
new file mode 100644
index 000000000..9bd85ba12
--- /dev/null
+++ b/testing/tests/no-priv-key/evaltest.dat
@@ -0,0 +1,4 @@
+carol::cat /var/log/auth.log::unable to locate my private key for RSA Signature::YES
+moon::cat /var/log/auth.log::ignoring informational payload, type AUTHENTICATION_FAILED::YES
+moon::ipsec status::rw.*STATE_MAIN_R3.*ISAKMP SA established::NO
+carol::ipsec status::home.*STATE_MAIN_I4.*ISAKMP SA established::NO
diff --git a/testing/tests/no-priv-key/hosts/carol/etc/ipsec.secrets b/testing/tests/no-priv-key/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..23b311aa6
--- /dev/null
+++ b/testing/tests/no-priv-key/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+# missing private RSA key
diff --git a/testing/tests/no-priv-key/posttest.dat b/testing/tests/no-priv-key/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/no-priv-key/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/no-priv-key/pretest.dat b/testing/tests/no-priv-key/pretest.dat
new file mode 100644
index 000000000..d92333d86
--- /dev/null
+++ b/testing/tests/no-priv-key/pretest.dat
@@ -0,0 +1,4 @@
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/no-priv-key/test.conf b/testing/tests/no-priv-key/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/no-priv-key/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/ocsp-revoked/description.txt b/testing/tests/ocsp-revoked/description.txt
new file mode 100644
index 000000000..cbdd1305a
--- /dev/null
+++ b/testing/tests/ocsp-revoked/description.txt
@@ -0,0 +1,7 @@
+By setting <b>strictcrlpolicy=yes</b> a <b>strict CRL policy</b> is enforced on
+both roadwarrior <b>carol</b> and gateway <b>moon</b>. Thus when <b>carol</b> initiates
+the connection and no current revocation information is available, the Main Mode
+negotiation fails but an OCSP request issued to the OCSP server <b>winnetou</b>.
+When the second Main Mode trial comes around the OCSP response will be available
+but because the certificate presented by carol has been revoked,
+the IKE negotatiation will fail..
diff --git a/testing/tests/ocsp-revoked/evaltest.dat b/testing/tests/ocsp-revoked/evaltest.dat
new file mode 100644
index 000000000..f5286cb61
--- /dev/null
+++ b/testing/tests/ocsp-revoked/evaltest.dat
@@ -0,0 +1,6 @@
+moon::cat /var/log/auth.log::X.509 certificate rejected::YES
+moon::cat /var/log/auth.log::certificate was revoked::YES
+carol::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+moon::ipsec listocsp:: revoked::YES
+moon::ipsec status::rw.*STATE_MAIN_R3.*ISAKMP SA established::NO
+carol::ipsec status::home.*STATE_MAIN_I4.*ISAKMP SA established::NO
diff --git a/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.conf b/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..7d4384767
--- /dev/null
+++ b/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,29 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+ca strongswan
+ cacert=strongswanCert.pem
+ ocspuri=http://ocsp.strongswan.org:8880
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolRevokedCert.pem
+ leftid=carol@strongswan.org
+
+conn home
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.d/certs/carolRevokedCert.pem b/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.d/certs/carolRevokedCert.pem
new file mode 100644
index 000000000..5b742fc9e
--- /dev/null
+++ b/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.d/certs/carolRevokedCert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIjCCAwqgAwIBAgIBBzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ
+MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
+b290IENBMB4XDTA0MDkxMDExMjU0OFoXDTA5MDkwOTExMjU0OFowWjELMAkGA1UE
+BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xETAPBgNVBAsTCFJlc2Vh
+cmNoMR0wGwYDVQQDFBRjYXJvbEBzdHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAM5413q1B2EF3spcYD1u0ce9AtIHdxmU3+1E0hqV
+mLqpIQtyp4SLbrRunxpoVUuEpHWXgLb3C/ljjlKCMWWmhw4wja1rBTjMNJLPj6Bo
+5Qn4Oeuqm7/kLHPGbveQGtcSsJCk6iLqFTbq0wsji5Ogq7kmjWgQv0nM2jpofHLv
+VOAtWVSj+x2b3OHdl/WpgTgTw1HHjYo7/NOkARdTcZ2/wxxM3z1Abp9iylc45GLN
+IL/OzHkT8b5pdokdMvVijz8IslkkewJYXrVQaCNMZg/ydlXOOAEKz0YqnvXQaYs5
+K+s8XvQ2RFCr5oO0fRT2VbiI9TgHnbcnfUi25iHl6txsXg0CAwEAAaOCAQYwggEC
+MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0GA1UdDgQWBBTbA2TH3ca8tgCGkYy9
+OV/MqUTHAzBtBgNVHSMEZjBkgBRdp91wBlEyfue2bbO15eBg6i5N76FJpEcwRTEL
+MAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMT
+EnN0cm9uZ1N3YW4gUm9vdCBDQYIBADAfBgNVHREEGDAWgRRjYXJvbEBzdHJvbmdz
+d2FuLm9yZzA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4u
+b3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBAUAA4IBAQC9acuCUPEBOrWB
+56vS8N9bksQwv/XcYIFYqV73kFBAzOPLX2a9igFGvBPdCxFu/t8JCswzE6to4LFM
+2+6Z2QJf442CLPcJKxITahrjJXSxGbzMlmaDvZ5wFCJAlyin+yuInpTwl8rMZe/Q
+O5JeJjzGDgWJtnGdkLUk/l2r6sZ/Cmk5rZpuO0hcUHVztMLQYPzqTpuMvC5p4JzL
+LWGWhKRhJs53NmxXXodck/ZgaqiTWuQFYlbamJRvzVBfX7c1SWHRJvxSSOPKGIg3
+wphkO2naj/SQD+BNuWTRmZ9YCiLOQ64ybLpJzRZISETdqtLBPKsIqosUZwkxlR1N
+9IcgYi5x
+-----END CERTIFICATE-----
diff --git a/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.d/private/carolRevokedKey.pem b/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.d/private/carolRevokedKey.pem
new file mode 100644
index 000000000..8aefcc5a6
--- /dev/null
+++ b/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.d/private/carolRevokedKey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAznjXerUHYQXeylxgPW7Rx70C0gd3GZTf7UTSGpWYuqkhC3Kn
+hItutG6fGmhVS4SkdZeAtvcL+WOOUoIxZaaHDjCNrWsFOMw0ks+PoGjlCfg566qb
+v+Qsc8Zu95Aa1xKwkKTqIuoVNurTCyOLk6CruSaNaBC/SczaOmh8cu9U4C1ZVKP7
+HZvc4d2X9amBOBPDUceNijv806QBF1Nxnb/DHEzfPUBun2LKVzjkYs0gv87MeRPx
+vml2iR0y9WKPPwiyWSR7AlhetVBoI0xmD/J2Vc44AQrPRiqe9dBpizkr6zxe9DZE
+UKvmg7R9FPZVuIj1OAedtyd9SLbmIeXq3GxeDQIDAQABAoIBAAUdyXko8z3cP2EU
+WO4syNYCQQejV7gykDn48pvmCRrXBhKajLwkGGIwO5ET9MkiSFEBqBbgmFNdvDEf
+OMokDkSzv08Ez+RQax0YN57p+oL8u7KzT5i5tsBHsog/8epSdD2hWIv08QGjYAdu
+og7OdHLqGabyg0r44I+B91OBysCjU51rDdkhz59AmURdEIJV5xhuGojFM68jaNm2
+MUxDfDuCsRIydjAP0VTUTAUxD4/S5I+jt/GK9aRsEeRH9Q3011iTGMR9viAUBhq/
+khkWNltg9lkOqO7LpnNku4sSv3v4CWge7/T+4RR2vZgv1oSs4ox2UKYoqIqiYIfx
+uUcnqQECgYEA+LPiRMoXvlssQWlaFc2k4xga0efs+mWeLglDdc3R3fBEibP/AU07
+a576AgvUJtkI50/WNGKT73O+VtxcXn/N646m/8OtqNXuVKKjsxxNOZEKdO8aOdbt
+7lM5WepNiQeaKAFudUxpUiZQx8LCKSsNDiJZKWBu6xAG2O5X32VMZvUCgYEA1Ie+
+rNa490PSC1ym7WbmdAjvGmSOn2GOBfO7BECsPZstccU7D5pZl/89fTfn1TDKP49Y
+ScVOuFz7f/u6UJpb/WzI71RXEQOdojLWmF2HDx5osRi3hXEJa20fbPq6DQXCJ8pf
+IF37AEqAY4UNSNic0Cw+rGHdWPQhDNXhFWpdu7kCgYEAmv4oNmyoDXbuhrlsbggi
+CXE9TbG3a3mm8dPOGf2yHBmf7R2i/6GtNW33Kw1KIwfBV77WpQEGZwWACsv8ONx3
+baUSiHTfpkfk5xQQ5w/tRMISfTuB4agD0jJFnLa7qXl2ZhY2S53aSVsdntDOhi+R
+TEy1umah2Za8Xbd0RgHwcn0CgYEAl9Hgg9dfikMIaNVm6W/4cCtxoojy2Sf3LIlP
+r1oDsH6JmBwsdJjuJ4ZNhoXJNqID2COuDgTEly7U+jf4gFvEGuT7JPw6tgy/Ln7i
+jTVCpaozX08oykpVUEhDirYQ8fyLFaGbEqQQCcUusej59G/IlW0F2F6QoFrEwUaH
+46R4EQECgYBEZ7edMkj3dmJH1wxQjp5GJNbrJkS8IKvzza0mDTJdz33CgEX9Oyva
+o2iEkDVpvj2SEy28ewt22IRptWKH/3bQfxSCcRV6JFNt3+LongMshRYqq1leqrKa
+9fnQVtfTIbIVXwjTZap6BL8R66OeFtexsSFRfDF/8P4n2oF4zmn4qA==
+-----END RSA PRIVATE KEY-----
diff --git a/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.secrets b/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..8e31be4cb
--- /dev/null
+++ b/testing/tests/ocsp-revoked/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA carolRevokedKey.pem
diff --git a/testing/tests/ocsp-revoked/hosts/moon/etc/ipsec.conf b/testing/tests/ocsp-revoked/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..7134b6ee9
--- /dev/null
+++ b/testing/tests/ocsp-revoked/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,40 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+ca strongswan
+ cacert=strongswanCert.pem
+ ocspuri=http://ocsp.strongswan.org:8880
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn net-net
+ leftsubnet=10.1.0.0/16
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn host-host
+ right=PH_IP_SUN
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn rw
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
diff --git a/testing/tests/ocsp-revoked/posttest.dat b/testing/tests/ocsp-revoked/posttest.dat
new file mode 100644
index 000000000..d883459e7
--- /dev/null
+++ b/testing/tests/ocsp-revoked/posttest.dat
@@ -0,0 +1,5 @@
+moon::ipsec stop
+carol::ipsec stop
+winnetou::killall openssl
+carol::rm /etc/ipsec.d/private/*
+carol::rm /etc/ipsec.d/certs/*
diff --git a/testing/tests/ocsp-revoked/pretest.dat b/testing/tests/ocsp-revoked/pretest.dat
new file mode 100644
index 000000000..d5516fd3b
--- /dev/null
+++ b/testing/tests/ocsp-revoked/pretest.dat
@@ -0,0 +1,5 @@
+winnetou::/etc/openssl/start-ocsp
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/ocsp-revoked/test.conf b/testing/tests/ocsp-revoked/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/ocsp-revoked/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/ocsp-strict/description.txt b/testing/tests/ocsp-strict/description.txt
new file mode 100644
index 000000000..7cb983140
--- /dev/null
+++ b/testing/tests/ocsp-strict/description.txt
@@ -0,0 +1,6 @@
+By setting <b>strictcrlpolicy=yes</b> a <b>strict CRL policy</b> is enforced on
+both roadwarrior <b>carol</b> and gateway <b>moon</b>. Thus when <b>carol</b> initiates
+the connection and no current revocation information is available, the Main Mode
+negotiation fails but an OCSP request is issued to the OCSP server <b>winnetou</b>.
+When the second Main Mode trial comes around, the OCSP response will be available
+and the IKE negotiation completes.
diff --git a/testing/tests/ocsp-strict/evaltest.dat b/testing/tests/ocsp-strict/evaltest.dat
new file mode 100644
index 000000000..66b27aaac
--- /dev/null
+++ b/testing/tests/ocsp-strict/evaltest.dat
@@ -0,0 +1,8 @@
+moon::cat /var/log/auth.log::X.509 certificate rejected::YES
+carol::cat /var/log/auth.log::X.509 certificate rejected::YES
+moon::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+carol::cat /var/log/auth.log::ignoring informational payload, type INVALID_KEY_INFORMATION::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec listocsp:: good::YES
+carol::ipsec listocsp:: good::YES
diff --git a/testing/tests/ocsp-strict/hosts/carol/etc/ipsec.conf b/testing/tests/ocsp-strict/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..b34719401
--- /dev/null
+++ b/testing/tests/ocsp-strict/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,29 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+ca strongswan
+ cacert=strongswanCert.pem
+ ocspuri=http://ocsp.strongswan.org:8880
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+
+conn home
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/ocsp-strict/hosts/moon/etc/ipsec.conf b/testing/tests/ocsp-strict/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..7134b6ee9
--- /dev/null
+++ b/testing/tests/ocsp-strict/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,40 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=yes
+
+ca strongswan
+ cacert=strongswanCert.pem
+ ocspuri=http://ocsp.strongswan.org:8880
+ auto=add
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn net-net
+ leftsubnet=10.1.0.0/16
+ right=PH_IP_SUN
+ rightsubnet=10.2.0.0/16
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn host-host
+ right=PH_IP_SUN
+ rightid=@sun.strongswan.org
+ auto=add
+
+conn rw
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
diff --git a/testing/tests/ocsp-strict/posttest.dat b/testing/tests/ocsp-strict/posttest.dat
new file mode 100644
index 000000000..117f625f6
--- /dev/null
+++ b/testing/tests/ocsp-strict/posttest.dat
@@ -0,0 +1,3 @@
+moon::ipsec stop
+carol::ipsec stop
+winnetou::killall openssl
diff --git a/testing/tests/ocsp-strict/pretest.dat b/testing/tests/ocsp-strict/pretest.dat
new file mode 100644
index 000000000..d5516fd3b
--- /dev/null
+++ b/testing/tests/ocsp-strict/pretest.dat
@@ -0,0 +1,5 @@
+winnetou::/etc/openssl/start-ocsp
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/ocsp-strict/test.conf b/testing/tests/ocsp-strict/test.conf
new file mode 100644
index 000000000..2b240d895
--- /dev/null
+++ b/testing/tests/ocsp-strict/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/protoport-dual/description.txt b/testing/tests/protoport-dual/description.txt
new file mode 100644
index 000000000..7bed8b959
--- /dev/null
+++ b/testing/tests/protoport-dual/description.txt
@@ -0,0 +1,6 @@
+Using the <b>left|rightprotoport</b> selectors, two IPsec tunnels
+between the roadwarrior <b>carol</b> and the gateway <b>moon</b> are
+defined. The first IPsec SA is restricted to ICMP packets and the second
+covers TCP-based SSH connections. The established tunnels are tested
+by <b>carol</b> by first pinging <b>alice</b> behind <b>moon</b> and
+then setting up an SSH session to the same client.
diff --git a/testing/tests/protoport-dual/evaltest.dat b/testing/tests/protoport-dual/evaltest.dat
new file mode 100644
index 000000000..625c8c54c
--- /dev/null
+++ b/testing/tests/protoport-dual/evaltest.dat
@@ -0,0 +1,7 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+carol::ping -c 1 PH_IP1_MOON::64 bytes from PH_IP1_MOON: icmp_seq=1::YES
+carol::ssh -o ConnectTimeout=5 PH_IP_ALICE hostname::alice::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/protoport-dual/hosts/carol/etc/ipsec.conf b/testing/tests/protoport-dual/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..9e05ecf61
--- /dev/null
+++ b/testing/tests/protoport-dual/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,31 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
+
+conn home-icmp
+ leftprotoport=icmp
+ rightprotoport=icmp
+
+conn home-ssh
+ leftprotoport=tcp
+ rightprotoport=tcp/ssh
diff --git a/testing/tests/protoport-dual/hosts/moon/etc/ipsec.conf b/testing/tests/protoport-dual/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..84b9b0ba3
--- /dev/null
+++ b/testing/tests/protoport-dual/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,31 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
+
+conn rw-icmp
+ lefthostaccess=yes
+ leftprotoport=icmp
+ rightprotoport=icmp
+
+conn rw-ssh
+ leftprotoport=tcp/ssh
+ rightprotoport=tcp
diff --git a/testing/tests/protoport-dual/posttest.dat b/testing/tests/protoport-dual/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/protoport-dual/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/protoport-dual/pretest.dat b/testing/tests/protoport-dual/pretest.dat
new file mode 100644
index 000000000..d3d0061c3
--- /dev/null
+++ b/testing/tests/protoport-dual/pretest.dat
@@ -0,0 +1,7 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home-icmp
+carol::ipsec up home-ssh
diff --git a/testing/tests/protoport-dual/test.conf b/testing/tests/protoport-dual/test.conf
new file mode 100644
index 000000000..9cd583b16
--- /dev/null
+++ b/testing/tests/protoport-dual/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/protoport-pass/description.txt b/testing/tests/protoport-pass/description.txt
new file mode 100644
index 000000000..63744fa47
--- /dev/null
+++ b/testing/tests/protoport-pass/description.txt
@@ -0,0 +1,13 @@
+The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>.
+Using the <b>left|rightprotoport</b> selectors, the IPsec tunnel is
+restricted to the ICMP protocol. Upon the successful establishment of the
+IPsec tunnel, <b>firewall=yes</b> automatically inserts iptables-based
+firewall rules that let pass the tunneled ICMP traffic. In order to test
+both tunnel and firewall, <b>carol</b> pings the client <b>alice</b> behind
+the gateway <b>moon</b> as well as the inner interface of the gateway.
+For the latter ping <b>lefthostaccess=yes</b> is required.
+<p>
+By default, the native IPsec stack of the Linux 2.6 kernel transmits
+protocols and ports not covered by any IPsec SA in the clear. Thus by
+selectively opening the firewalls, <b>carol</b> sets up an SSH session to
+<b>alice</b> that is not going through the tunnel.
diff --git a/testing/tests/protoport-pass/evaltest.dat b/testing/tests/protoport-pass/evaltest.dat
new file mode 100644
index 000000000..625c8c54c
--- /dev/null
+++ b/testing/tests/protoport-pass/evaltest.dat
@@ -0,0 +1,7 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+carol::ping -c 1 PH_IP1_MOON::64 bytes from PH_IP1_MOON: icmp_seq=1::YES
+carol::ssh -o ConnectTimeout=5 PH_IP_ALICE hostname::alice::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/protoport-pass/hosts/carol/etc/ipsec.conf b/testing/tests/protoport-pass/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..ade7308f6
--- /dev/null
+++ b/testing/tests/protoport-pass/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,27 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home-icmp
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftid=carol@strongswan.org
+ leftcert=carolCert.pem
+ leftprotoport=icmp
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightprotoport=icmp
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/protoport-pass/hosts/moon/etc/ipsec.conf b/testing/tests/protoport-pass/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..fd67e2b4b
--- /dev/null
+++ b/testing/tests/protoport-pass/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,27 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn rw-icmp
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftsubnet=10.1.0.0/16
+ leftprotoport=icmp
+ leftid=@moon.strongswan.org
+ leftcert=moonCert.pem
+ leftfirewall=yes
+ lefthostaccess=yes
+ right=%any
+ rightprotoport=icmp
+ auto=add
diff --git a/testing/tests/protoport-pass/posttest.dat b/testing/tests/protoport-pass/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/protoport-pass/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/protoport-pass/pretest.dat b/testing/tests/protoport-pass/pretest.dat
new file mode 100644
index 000000000..13b4ad4a0
--- /dev/null
+++ b/testing/tests/protoport-pass/pretest.dat
@@ -0,0 +1,10 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+moon::iptables -I FORWARD -i eth0 -p tcp -d 10.1.0.0/16 --dport ssh -jACCEPT
+moon::iptables -I FORWARD -o eth0 -p tcp -s 10.1.0.0/16 --sport ssh -jACCEPT
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::iptables -I INPUT -i eth0 -p tcp -s 10.1.0.0/16 --sport ssh -d PH_IP_CAROL -jACCEPT
+carol::iptables -I OUTPUT -o eth0 -p tcp -d 10.1.0.0/16 --dport ssh -s PH_IP_CAROL -jACCEPT
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ipsec up home-icmp
diff --git a/testing/tests/protoport-pass/test.conf b/testing/tests/protoport-pass/test.conf
new file mode 100644
index 000000000..9cd583b16
--- /dev/null
+++ b/testing/tests/protoport-pass/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/protoport-route/description.txt b/testing/tests/protoport-route/description.txt
new file mode 100644
index 000000000..ec7ec69b0
--- /dev/null
+++ b/testing/tests/protoport-route/description.txt
@@ -0,0 +1,8 @@
+Using the <b>left|rightprotoport</b> selectors, two IPsec tunnels
+between the roadwarrior <b>carol</b> and the gateway <b>moon</b> are
+defined. The first IPsec SA is restricted to ICMP packets and the second
+covers TCP-based SSH connections. Using <b>add=route</b> %trap
+eroutes for these IPsec SAs are prepared on <b>carol</b>. By sending
+a ping to the client <b>alice</b> behind <b>moon</b>, the ICMP eroute
+is triggered and the corresponding IPsec tunnel is set up. In the same
+way an ssh session to <b>alice</b> over the second IPsec SA is established.
diff --git a/testing/tests/protoport-route/evaltest.dat b/testing/tests/protoport-route/evaltest.dat
new file mode 100644
index 000000000..8f3eb208f
--- /dev/null
+++ b/testing/tests/protoport-route/evaltest.dat
@@ -0,0 +1,8 @@
+carol::ping -c 2 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq::YES
+carol::ping -c 2 PH_IP1_MOON::64 bytes from PH_IP1_MOON: icmp_seq::YES
+carol::ssh PH_IP_ALICE hostname::alice::YES
+carol::cat /var/log/auth.log::initiate on demand::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/protoport-route/hosts/carol/etc/ipsec.conf b/testing/tests/protoport-route/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..31c25c12f
--- /dev/null
+++ b/testing/tests/protoport-route/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,31 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=route
+
+conn home-icmp
+ leftprotoport=icmp
+ rightprotoport=icmp
+
+conn home-ssh
+ leftprotoport=tcp
+ rightprotoport=tcp/ssh
diff --git a/testing/tests/protoport-route/hosts/moon/etc/ipsec.conf b/testing/tests/protoport-route/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..84b9b0ba3
--- /dev/null
+++ b/testing/tests/protoport-route/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,31 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ leftsubnet=10.1.0.0/16
+ right=%any
+ auto=add
+
+conn rw-icmp
+ lefthostaccess=yes
+ leftprotoport=icmp
+ rightprotoport=icmp
+
+conn rw-ssh
+ leftprotoport=tcp/ssh
+ rightprotoport=tcp
diff --git a/testing/tests/protoport-route/posttest.dat b/testing/tests/protoport-route/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/protoport-route/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/protoport-route/pretest.dat b/testing/tests/protoport-route/pretest.dat
new file mode 100644
index 000000000..f233ad48f
--- /dev/null
+++ b/testing/tests/protoport-route/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+carol::ipsec start
+carol::sleep 2
+carol::ssh PH_IP_ALICE hostname
diff --git a/testing/tests/protoport-route/test.conf b/testing/tests/protoport-route/test.conf
new file mode 100644
index 000000000..9cd583b16
--- /dev/null
+++ b/testing/tests/protoport-route/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/req-pkcs10/description.txt b/testing/tests/req-pkcs10/description.txt
new file mode 100644
index 000000000..a958cb8e8
--- /dev/null
+++ b/testing/tests/req-pkcs10/description.txt
@@ -0,0 +1,11 @@
+Both the roadwarrior <b>carol</b> and the gateway <b>moon</b> generate a
+PKCS#1 RSA private key and a PKCS#10 certificate request using the
+<b>ipsec scepclient</b> function. Because the UML testing environment
+does not offer enough entropy, the non-blocking /dev/urandom device is
+used in place of /dev/random for generating the random primes.
+<p>
+The certificate requests are copied to <b>winnetou</b> where a certification
+authority based on OpenSSL issues X.509 certificates by verifying and
+signing the PCKS#10 requests. The certificates are then copied back to
+the corresponding hosts and used to set up a road warrior connection
+initiated by <b>carol</b>
diff --git a/testing/tests/req-pkcs10/evaltest.dat b/testing/tests/req-pkcs10/evaltest.dat
new file mode 100644
index 000000000..c7657801e
--- /dev/null
+++ b/testing/tests/req-pkcs10/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/req-pkcs10/hosts/carol/etc/ipsec.conf b/testing/tests/req-pkcs10/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..58e2f1e5b
--- /dev/null
+++ b/testing/tests/req-pkcs10/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,29 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=myCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/tests/req-pkcs10/hosts/carol/etc/ipsec.secrets b/testing/tests/req-pkcs10/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..167d743df
--- /dev/null
+++ b/testing/tests/req-pkcs10/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA myKey.der
diff --git a/testing/tests/req-pkcs10/hosts/carol/etc/scepclient.conf b/testing/tests/req-pkcs10/hosts/carol/etc/scepclient.conf
new file mode 100644
index 000000000..6afd3fa11
--- /dev/null
+++ b/testing/tests/req-pkcs10/hosts/carol/etc/scepclient.conf
@@ -0,0 +1,3 @@
+--debug-control
+--out pkcs1
+--out pkcs10
diff --git a/testing/tests/req-pkcs10/hosts/moon/etc/ipsec.secrets b/testing/tests/req-pkcs10/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..b9ec17dbc
--- /dev/null
+++ b/testing/tests/req-pkcs10/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA moonKey.der
diff --git a/testing/tests/req-pkcs10/hosts/moon/etc/scepclient.conf b/testing/tests/req-pkcs10/hosts/moon/etc/scepclient.conf
new file mode 100644
index 000000000..da8177348
--- /dev/null
+++ b/testing/tests/req-pkcs10/hosts/moon/etc/scepclient.conf
@@ -0,0 +1,4 @@
+--debug-control
+--keylength 2064
+--out pkcs1=moonKey.der
+--out pkcs10=moonReq.der
diff --git a/testing/tests/req-pkcs10/hosts/winnetou/etc/openssl/yy.txt b/testing/tests/req-pkcs10/hosts/winnetou/etc/openssl/yy.txt
new file mode 100644
index 000000000..9b48ee4cf
--- /dev/null
+++ b/testing/tests/req-pkcs10/hosts/winnetou/etc/openssl/yy.txt
@@ -0,0 +1,2 @@
+y
+y
diff --git a/testing/tests/req-pkcs10/posttest.dat b/testing/tests/req-pkcs10/posttest.dat
new file mode 100644
index 000000000..534e3af20
--- /dev/null
+++ b/testing/tests/req-pkcs10/posttest.dat
@@ -0,0 +1,13 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+carol::rm /etc/ipsec.d/private/*
+carol::rm /etc/ipsec.d/certs/*
+carol::rm /etc/ipsec.d/reqs/*
+moon::rm /etc/ipsec.d/private/*
+moon::rm /etc/ipsec.d/reqs/*
+winnetou::rm /etc/openssl/carol*
+winnetou::rm /etc/openssl/moon*
diff --git a/testing/tests/req-pkcs10/pretest.dat b/testing/tests/req-pkcs10/pretest.dat
new file mode 100644
index 000000000..18b8b16e6
--- /dev/null
+++ b/testing/tests/req-pkcs10/pretest.dat
@@ -0,0 +1,22 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::rm /etc/ipsec.d/private/*
+carol::rm /etc/ipsec.d/certs/*
+carol::cat /etc/scepclient.conf
+carol::ipsec scepclient --dn \"C=CH, O=Linux strongSwan, CN=carol@strongswan.org\" --optionsfrom /etc/scepclient.conf
+winnetou::scp carol:/etc/ipsec.d/reqs/myReq.der /etc/openssl/carolReq.der
+winnetou::openssl req -inform der -in /etc/openssl/carolReq.der -out /etc/openssl/carolReq.pem
+winnetou::cd /etc/openssl; COMMON_NAME="carol@strongswan.org" openssl ca -in carolReq.pem -out carolCert.pem -notext -config openssl.cnf -extensions user_ext < yy.txt
+winnetou::scp /etc/openssl/carolCert.pem carol:/etc/ipsec.d/certs/myCert.pem
+moon::rm /etc/ipsec.d/private/*
+moon::rm /etc/ipsec.d/certs/*
+moon::cat /etc/scepclient.conf
+moon::ipsec scepclient --dn \"C=CH, O=Linux strongSwan, SN=01, CN=moon.strongswan.org\" --optionsfrom /etc/scepclient.conf
+winnetou::scp moon:/etc/ipsec.d/reqs/moonReq.der /etc/openssl/
+winnetou::openssl req -inform der -in /etc/openssl/moonReq.der -out /etc/openssl/moonReq.pem
+winnetou::cd /etc/openssl; COMMON_NAME="moon.strongswan.org" openssl ca -in moonReq.pem -out moonCert.pem -notext -config openssl.cnf -extensions host_ext < yy.txt
+winnetou::scp /etc/openssl/moonCert.pem moon:/etc/ipsec.d/certs/
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/req-pkcs10/test.conf b/testing/tests/req-pkcs10/test.conf
new file mode 100644
index 000000000..9cd583b16
--- /dev/null
+++ b/testing/tests/req-pkcs10/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/rw-cert/description.txt b/testing/tests/rw-cert/description.txt
new file mode 100644
index 000000000..8df6b1c0d
--- /dev/null
+++ b/testing/tests/rw-cert/description.txt
@@ -0,0 +1,6 @@
+The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>.
+The authentication is based on <b>X.509 certificates</b>. Upon the successful
+establishment of the IPsec tunnel, <b>leftfirewall=yes</b> automatically
+inserts iptables-based firewall rules that let pass the tunneled traffic.
+In order to test both tunnel and firewall, <b>carol</b> pings the client
+<b>alice</b> behind the gateway <b>moon</b>.
diff --git a/testing/tests/rw-cert/evaltest.dat b/testing/tests/rw-cert/evaltest.dat
new file mode 100644
index 000000000..c7657801e
--- /dev/null
+++ b/testing/tests/rw-cert/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/rw-cert/posttest.dat b/testing/tests/rw-cert/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/rw-cert/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/rw-cert/pretest.dat b/testing/tests/rw-cert/pretest.dat
new file mode 100644
index 000000000..bd68efb0b
--- /dev/null
+++ b/testing/tests/rw-cert/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+moon::ipsec start
+sleep 2
+carol::ipsec up home
diff --git a/testing/tests/rw-cert/test.conf b/testing/tests/rw-cert/test.conf
new file mode 100644
index 000000000..9cd583b16
--- /dev/null
+++ b/testing/tests/rw-cert/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/rw-psk-fqdn-named/description.txt b/testing/tests/rw-psk-fqdn-named/description.txt
new file mode 100644
index 000000000..adfab2f4d
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn-named/description.txt
@@ -0,0 +1,11 @@
+The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>. The authentication is
+based on <b>Preshared Keys</b> (PSK) and <b>Fully Qualified Domain Names</b> (ID_FQDN).
+<b>leftfirewall=yes</b> automatically inserts iptables-based firewall rules that let pass the
+tunneled traffic. In order to test the tunnel <b>carol</b> pings the client <b>alice</b> behind
+the gateway <b>moon</b>.
+<p>
+The significant difference between this scenario and the test
+<a href="../rw-psk-fqdn"><b>rw-psk-fqdn</b></a>
+is the additional line <b>rightid=@carol.strongswan.org</b> by which gateway
+<b>moon</b> restricts the roadwarrior connection to host <b>carol</b>.
+</p>
diff --git a/testing/tests/rw-psk-fqdn-named/evaltest.dat b/testing/tests/rw-psk-fqdn-named/evaltest.dat
new file mode 100644
index 000000000..c7657801e
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn-named/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/rw-psk-fqdn-named/hosts/carol/etc/ipsec.conf b/testing/tests/rw-psk-fqdn-named/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..da5e198a8
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn-named/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,23 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn home
+ left=PH_IP_CAROL
+ leftid=@carol.strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/rw-psk-fqdn-named/hosts/carol/etc/ipsec.secrets b/testing/tests/rw-psk-fqdn-named/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..db3884e57
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn-named/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+@carol.strongswan.org @moon.strongswan.org : PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/rw-psk-fqdn-named/hosts/moon/etc/ipsec.conf b/testing/tests/rw-psk-fqdn-named/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..c32dfaf9b
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn-named/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,23 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn rw-carol
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ right=%any
+ rightid=@carol.strongswan.org
+ auto=add
diff --git a/testing/tests/rw-psk-fqdn-named/hosts/moon/etc/ipsec.secrets b/testing/tests/rw-psk-fqdn-named/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..6281340ae
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn-named/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+@moon.strongswan.org : PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/rw-psk-fqdn-named/posttest.dat b/testing/tests/rw-psk-fqdn-named/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn-named/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/rw-psk-fqdn-named/pretest.dat b/testing/tests/rw-psk-fqdn-named/pretest.dat
new file mode 100644
index 000000000..dbf03f552
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn-named/pretest.dat
@@ -0,0 +1,8 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+moon::rm /etc/ipsec.d/cacerts/*
+carol::rm /etc/ipsec.d/cacerts/*
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/rw-psk-fqdn-named/test.conf b/testing/tests/rw-psk-fqdn-named/test.conf
new file mode 100644
index 000000000..9cd583b16
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn-named/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/rw-psk-fqdn/description.txt b/testing/tests/rw-psk-fqdn/description.txt
new file mode 100644
index 000000000..d6c79afb2
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn/description.txt
@@ -0,0 +1,5 @@
+The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>. The authentication is
+based on <b>Preshared Keys</b> (PSK) and <b>Fully Qualified Domain Names</b> (ID_FQDN).
+<b>leftfirewall=yes</b> automatically inserts iptables-based firewall rules that let pass the
+tunneled traffic. In order to test the tunnel <b>carol</b> pings the client <b>alice</b> behind
+the gateway <b>moon</b>.
diff --git a/testing/tests/rw-psk-fqdn/evaltest.dat b/testing/tests/rw-psk-fqdn/evaltest.dat
new file mode 100644
index 000000000..c7657801e
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/rw-psk-fqdn/hosts/carol/etc/ipsec.conf b/testing/tests/rw-psk-fqdn/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..da5e198a8
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,23 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn home
+ left=PH_IP_CAROL
+ leftid=@carol.strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/rw-psk-fqdn/hosts/carol/etc/ipsec.secrets b/testing/tests/rw-psk-fqdn/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..db3884e57
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+@carol.strongswan.org @moon.strongswan.org : PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/rw-psk-fqdn/hosts/moon/etc/ipsec.conf b/testing/tests/rw-psk-fqdn/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..9a894806c
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,22 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn rw
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ right=%any
+ auto=add
diff --git a/testing/tests/rw-psk-fqdn/hosts/moon/etc/ipsec.secrets b/testing/tests/rw-psk-fqdn/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..6281340ae
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+@moon.strongswan.org : PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/rw-psk-fqdn/posttest.dat b/testing/tests/rw-psk-fqdn/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/rw-psk-fqdn/pretest.dat b/testing/tests/rw-psk-fqdn/pretest.dat
new file mode 100644
index 000000000..dbf03f552
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn/pretest.dat
@@ -0,0 +1,8 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+moon::rm /etc/ipsec.d/cacerts/*
+carol::rm /etc/ipsec.d/cacerts/*
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/rw-psk-fqdn/test.conf b/testing/tests/rw-psk-fqdn/test.conf
new file mode 100644
index 000000000..9cd583b16
--- /dev/null
+++ b/testing/tests/rw-psk-fqdn/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/rw-psk-ipv4/description.txt b/testing/tests/rw-psk-ipv4/description.txt
new file mode 100644
index 000000000..b3a0bc192
--- /dev/null
+++ b/testing/tests/rw-psk-ipv4/description.txt
@@ -0,0 +1,5 @@
+The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>. The authentication is
+based on <b>Preshared Keys</b> (PSK) and <b>IPv4 addresses</b> (ID_IPV4_ADDR).
+<b>firewall=yes</b> automatically inserts iptables-based firewall rules that let pass
+the tunneled traffic. In order to test the tunnel <b>carol</b> pings the client <b>alice</b>
+behind the gateway <b>moon</b>.
diff --git a/testing/tests/rw-psk-ipv4/evaltest.dat b/testing/tests/rw-psk-ipv4/evaltest.dat
new file mode 100644
index 000000000..c7657801e
--- /dev/null
+++ b/testing/tests/rw-psk-ipv4/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/rw-psk-ipv4/hosts/carol/etc/ipsec.conf b/testing/tests/rw-psk-ipv4/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..2c0227b7a
--- /dev/null
+++ b/testing/tests/rw-psk-ipv4/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,21 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn home
+ left=PH_IP_CAROL
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ auto=add
diff --git a/testing/tests/rw-psk-ipv4/hosts/carol/etc/ipsec.secrets b/testing/tests/rw-psk-ipv4/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..69313b289
--- /dev/null
+++ b/testing/tests/rw-psk-ipv4/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+PH_IP_CAROL PH_IP_MOON : PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/rw-psk-ipv4/hosts/moon/etc/ipsec.conf b/testing/tests/rw-psk-ipv4/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..a75d4e222
--- /dev/null
+++ b/testing/tests/rw-psk-ipv4/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,21 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ authby=secret
+ leftnexthop=%direct
+
+conn rw
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftfirewall=yes
+ right=%any
+ auto=add
diff --git a/testing/tests/rw-psk-ipv4/hosts/moon/etc/ipsec.secrets b/testing/tests/rw-psk-ipv4/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..a8e367950
--- /dev/null
+++ b/testing/tests/rw-psk-ipv4/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+PH_IP_MOON %any : PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/rw-psk-ipv4/posttest.dat b/testing/tests/rw-psk-ipv4/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/rw-psk-ipv4/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/rw-psk-ipv4/pretest.dat b/testing/tests/rw-psk-ipv4/pretest.dat
new file mode 100644
index 000000000..dbf03f552
--- /dev/null
+++ b/testing/tests/rw-psk-ipv4/pretest.dat
@@ -0,0 +1,8 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+moon::rm /etc/ipsec.d/cacerts/*
+carol::rm /etc/ipsec.d/cacerts/*
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/rw-psk-ipv4/test.conf b/testing/tests/rw-psk-ipv4/test.conf
new file mode 100644
index 000000000..9cd583b16
--- /dev/null
+++ b/testing/tests/rw-psk-ipv4/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/rw-psk-no-policy/description.txt b/testing/tests/rw-psk-no-policy/description.txt
new file mode 100644
index 000000000..0e359414f
--- /dev/null
+++ b/testing/tests/rw-psk-no-policy/description.txt
@@ -0,0 +1,3 @@
+The roadwarrior <b>carol</b> wants to set up a connection to gateway <b>moon</b> using
+<b>PSK</b>-based authentication. Since <b>moon</b> supports <b>RSASIG</b>-based
+authentication only, the connection setup fails.
diff --git a/testing/tests/rw-psk-no-policy/evaltest.dat b/testing/tests/rw-psk-no-policy/evaltest.dat
new file mode 100644
index 000000000..a28377dbd
--- /dev/null
+++ b/testing/tests/rw-psk-no-policy/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::cat /var/log/auth.log::peer requests PSK authentication::YES
+moon::cat /var/log/auth.log::but no connection has been authorized with policy=PSK::YES
+moon::ipsec status::*PH_IP_CAROL STATE_QUICK_R2.*IPsec SA established::NO
+
diff --git a/testing/tests/rw-psk-no-policy/hosts/carol/etc/ipsec.conf b/testing/tests/rw-psk-no-policy/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..413eff762
--- /dev/null
+++ b/testing/tests/rw-psk-no-policy/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,23 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ authby=secret
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+ rightsubnet=10.1.0.0/16
+ auto=add
diff --git a/testing/tests/rw-psk-no-policy/hosts/carol/etc/ipsec.secrets b/testing/tests/rw-psk-no-policy/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..1b721dc58
--- /dev/null
+++ b/testing/tests/rw-psk-no-policy/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/rw-psk-no-policy/hosts/moon/etc/ipsec.conf b/testing/tests/rw-psk-no-policy/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..ac63abdc9
--- /dev/null
+++ b/testing/tests/rw-psk-no-policy/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,22 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn rw
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ leftfirewall=yes
+ right=%any
+ auto=add
diff --git a/testing/tests/rw-psk-no-policy/posttest.dat b/testing/tests/rw-psk-no-policy/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/rw-psk-no-policy/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/rw-psk-no-policy/pretest.dat b/testing/tests/rw-psk-no-policy/pretest.dat
new file mode 100644
index 000000000..3a7804ddd
--- /dev/null
+++ b/testing/tests/rw-psk-no-policy/pretest.dat
@@ -0,0 +1,5 @@
+carol::rm /etc/ipsec.d/cacerts/*
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/rw-psk-no-policy/test.conf b/testing/tests/rw-psk-no-policy/test.conf
new file mode 100644
index 000000000..f622c18b7
--- /dev/null
+++ b/testing/tests/rw-psk-no-policy/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/rw-psk-rsa-mixed/description.txt b/testing/tests/rw-psk-rsa-mixed/description.txt
new file mode 100644
index 000000000..b99a8e5b3
--- /dev/null
+++ b/testing/tests/rw-psk-rsa-mixed/description.txt
@@ -0,0 +1,5 @@
+The roadwarriors <b>carol</b> and <b>dave</b> each set up a connection to gateway <b>moon</b>.
+<b>carol</b>'s authentication is based on a Pre-Shared Key (<b>PSK</b>) whereas <b>dave</b>'s
+is based on an RSA signature (<b>RSASIG</b>). Gateway <b>moon</b> supports both authentication modes
+and automatically selects the correct roadwarrior connection definition based on policy
+information gained from pre-parsing the peers' ISAKMP proposal payload.
diff --git a/testing/tests/rw-psk-rsa-mixed/evaltest.dat b/testing/tests/rw-psk-rsa-mixed/evaltest.dat
new file mode 100644
index 000000000..9e1354121
--- /dev/null
+++ b/testing/tests/rw-psk-rsa-mixed/evaltest.dat
@@ -0,0 +1,7 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+dave::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::cat /var/log/auth.log::peer requests PSK authentication::YES
+moon::ipsec status::rw-psk.*PH_IP_CAROL STATE_QUICK_R2.*IPsec SA established::YES
+moon::cat /var/log/auth.log::peer requests RSASIG authentication::YES
+moon::ipsec status::rw-rsasig.*PH_IP_DAVE STATE_QUICK_R2.*IPsec SA established::YES
+
diff --git a/testing/tests/rw-psk-rsa-mixed/hosts/carol/etc/ipsec.conf b/testing/tests/rw-psk-rsa-mixed/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..69e13b538
--- /dev/null
+++ b/testing/tests/rw-psk-rsa-mixed/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,24 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ ike=aes128,serpent128,twofish128,3des
+
+conn home
+ authby=secret
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+ rightsubnet=10.1.0.0/16
+ auto=add
diff --git a/testing/tests/rw-psk-rsa-mixed/hosts/carol/etc/ipsec.secrets b/testing/tests/rw-psk-rsa-mixed/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..1b721dc58
--- /dev/null
+++ b/testing/tests/rw-psk-rsa-mixed/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,7 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+
+
+
diff --git a/testing/tests/rw-psk-rsa-mixed/hosts/moon/etc/ipsec.conf b/testing/tests/rw-psk-rsa-mixed/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..b23248b5b
--- /dev/null
+++ b/testing/tests/rw-psk-rsa-mixed/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,27 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ leftfirewall=yes
+ right=%any
+
+conn rw-rsasig
+ authby=rsasig
+ leftcert=moonCert.pem
+ auto=add
+
+conn rw-psk
+ authby=secret
+ auto=add
diff --git a/testing/tests/rw-psk-rsa-mixed/hosts/moon/etc/ipsec.secrets b/testing/tests/rw-psk-rsa-mixed/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..fd33507a7
--- /dev/null
+++ b/testing/tests/rw-psk-rsa-mixed/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,5 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
+
+: RSA moonKey.pem
diff --git a/testing/tests/rw-psk-rsa-mixed/posttest.dat b/testing/tests/rw-psk-rsa-mixed/posttest.dat
new file mode 100644
index 000000000..ed530f6d9
--- /dev/null
+++ b/testing/tests/rw-psk-rsa-mixed/posttest.dat
@@ -0,0 +1,3 @@
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
diff --git a/testing/tests/rw-psk-rsa-mixed/pretest.dat b/testing/tests/rw-psk-rsa-mixed/pretest.dat
new file mode 100644
index 000000000..35797b589
--- /dev/null
+++ b/testing/tests/rw-psk-rsa-mixed/pretest.dat
@@ -0,0 +1,7 @@
+carol::rm /etc/ipsec.d/cacerts/*
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
+dave::ipsec up home
diff --git a/testing/tests/rw-psk-rsa-mixed/test.conf b/testing/tests/rw-psk-rsa-mixed/test.conf
new file mode 100644
index 000000000..699b88e88
--- /dev/null
+++ b/testing/tests/rw-psk-rsa-mixed/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol dave winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/rw-rsa-no-policy/description.txt b/testing/tests/rw-rsa-no-policy/description.txt
new file mode 100644
index 000000000..c3336b769
--- /dev/null
+++ b/testing/tests/rw-rsa-no-policy/description.txt
@@ -0,0 +1,3 @@
+The roadwarrior <b>carol</b> wants to set up a connection to gateway <b>moon</b> using
+<b>RSASIG</b>-based authentication. Since <b>moon</b> supports <b>PSK</b>-based
+authentication only, the connection setup fails.
diff --git a/testing/tests/rw-rsa-no-policy/evaltest.dat b/testing/tests/rw-rsa-no-policy/evaltest.dat
new file mode 100644
index 000000000..188b7bbb5
--- /dev/null
+++ b/testing/tests/rw-rsa-no-policy/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::cat /var/log/auth.log::peer requests RSASIG authentication::YES
+moon::cat /var/log/auth.log::but no connection has been authorized with policy=RSASIG::YES
+moon::ipsec status::*PH_IP_CAROL STATE_QUICK_R2.*IPsec SA established::NO
+
diff --git a/testing/tests/rw-rsa-no-policy/hosts/moon/etc/ipsec.conf b/testing/tests/rw-rsa-no-policy/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..b9318c058
--- /dev/null
+++ b/testing/tests/rw-rsa-no-policy/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,22 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn rw-psk
+ authby=secret
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ leftfirewall=yes
+ right=%any
+ auto=add
diff --git a/testing/tests/rw-rsa-no-policy/hosts/moon/etc/ipsec.secrets b/testing/tests/rw-rsa-no-policy/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..e8c151f05
--- /dev/null
+++ b/testing/tests/rw-rsa-no-policy/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: PSK 0sv+NkxY9LLZvwj4qCC2o/gGrWDF2d21jL
diff --git a/testing/tests/rw-rsa-no-policy/posttest.dat b/testing/tests/rw-rsa-no-policy/posttest.dat
new file mode 100644
index 000000000..c6d6235f9
--- /dev/null
+++ b/testing/tests/rw-rsa-no-policy/posttest.dat
@@ -0,0 +1,2 @@
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/rw-rsa-no-policy/pretest.dat b/testing/tests/rw-rsa-no-policy/pretest.dat
new file mode 100644
index 000000000..0d2a0dd1f
--- /dev/null
+++ b/testing/tests/rw-rsa-no-policy/pretest.dat
@@ -0,0 +1,5 @@
+moon::rm /etc/ipsec.d/cacerts/*
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/rw-rsa-no-policy/test.conf b/testing/tests/rw-rsa-no-policy/test.conf
new file mode 100644
index 000000000..f622c18b7
--- /dev/null
+++ b/testing/tests/rw-rsa-no-policy/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/self-signed/description.txt b/testing/tests/self-signed/description.txt
new file mode 100644
index 000000000..2d7bfc2bf
--- /dev/null
+++ b/testing/tests/self-signed/description.txt
@@ -0,0 +1,8 @@
+Roadwarrior <b>carol</b> and gateway <b>moon</b> each generate a
+PKCS#1 RSA private key and a self-signed X.509 certificate
+using the <b>ipsec scepclient</b> function. Because the UML testing
+environment does not offer enough entropy, the non-blocking /dev/urandom
+device is used in place of /dev/random for generating the random primes.
+<p>
+The self-signed certificates are then distributed to the peers via scp
+and are used to set up a road warrior connection initiated by <b>carol</b>
diff --git a/testing/tests/self-signed/evaltest.dat b/testing/tests/self-signed/evaltest.dat
new file mode 100644
index 000000000..f190d7066
--- /dev/null
+++ b/testing/tests/self-signed/evaltest.dat
@@ -0,0 +1,7 @@
+carol::cat /var/log/auth.log::we have a cert but are not sending it::YES
+moon::cat /var/log/auth.log::we have a cert but are not sending it::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::carol.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/self-signed/hosts/carol/etc/ipsec.conf b/testing/tests/self-signed/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..fcf7a1754
--- /dev/null
+++ b/testing/tests/self-signed/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,27 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=0
+ strictcrlpolicy=no
+ nocrsend=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=selfCert.der
+ leftsendcert=never
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightcert=peerCert.der
+ rightid=@moon.strongswan.org
+ auto=add
diff --git a/testing/tests/self-signed/hosts/carol/etc/ipsec.secrets b/testing/tests/self-signed/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 000000000..167d743df
--- /dev/null
+++ b/testing/tests/self-signed/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA myKey.der
diff --git a/testing/tests/self-signed/hosts/moon/etc/init.d/iptables b/testing/tests/self-signed/hosts/moon/etc/init.d/iptables
new file mode 100755
index 000000000..13ad3063f
--- /dev/null
+++ b/testing/tests/self-signed/hosts/moon/etc/init.d/iptables
@@ -0,0 +1,78 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # enable IP forwarding
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A INPUT -p tcp --sport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/self-signed/hosts/moon/etc/ipsec.conf b/testing/tests/self-signed/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..7d7f42b06
--- /dev/null
+++ b/testing/tests/self-signed/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,28 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=0
+ strictcrlpolicy=no
+ nocrsend=yes
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn carol
+ left=192.168.0.1
+ leftnexthop=%direct
+ leftcert=moonCert.der
+ leftid=@moon.strongswan.org
+ leftsendcert=never
+ leftfirewall=yes
+ leftsubnet=10.1.0.0/16
+ right=%any
+ rightcert=carolCert.der
+ auto=add
+
diff --git a/testing/tests/self-signed/hosts/moon/etc/ipsec.secrets b/testing/tests/self-signed/hosts/moon/etc/ipsec.secrets
new file mode 100644
index 000000000..b9ec17dbc
--- /dev/null
+++ b/testing/tests/self-signed/hosts/moon/etc/ipsec.secrets
@@ -0,0 +1,3 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
+
+: RSA moonKey.der
diff --git a/testing/tests/self-signed/hosts/moon/etc/scepclient.conf b/testing/tests/self-signed/hosts/moon/etc/scepclient.conf
new file mode 100644
index 000000000..b84f3e131
--- /dev/null
+++ b/testing/tests/self-signed/hosts/moon/etc/scepclient.conf
@@ -0,0 +1,6 @@
+--debug-control
+--keylength 2032
+--days 1460
+--subjectAltName dns=moon.strongswan.org
+--out pkcs1=moonKey.der
+--out cert-self=moonCert.der
diff --git a/testing/tests/self-signed/posttest.dat b/testing/tests/self-signed/posttest.dat
new file mode 100644
index 000000000..52b48b9ef
--- /dev/null
+++ b/testing/tests/self-signed/posttest.dat
@@ -0,0 +1,10 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+carol::rm /etc/ipsec.d/private/*
+carol::rm /etc/ipsec.d/certs/*
+moon::rm /etc/ipsec.d/private/*
+moon::rm /etc/ipsec.d/certs/*
diff --git a/testing/tests/self-signed/pretest.dat b/testing/tests/self-signed/pretest.dat
new file mode 100644
index 000000000..a7cddf677
--- /dev/null
+++ b/testing/tests/self-signed/pretest.dat
@@ -0,0 +1,17 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::rm /etc/ipsec.d/private/*
+carol::rm /etc/ipsec.d/certs/*
+carol::rm /etc/ipsec.d/cacerts/*
+carol::ipsec scepclient --out pkcs1 --out cert-self
+moon::rm /etc/ipsec.d/private/*
+moon::rm /etc/ipsec.d/certs/*
+moon::rm /etc/ipsec.d/cacerts/*
+moon::cat /etc/scepclient.conf
+moon::ipsec scepclient --dn \"C=CH, O=Linux strongSwan, CN=moon.strongswan.org\" --optionsfrom /etc/scepclient.conf
+moon::scp carol:/etc/ipsec.d/certs/selfCert.der /etc/ipsec.d/certs/carolCert.der
+moon::scp /etc/ipsec.d/certs/moonCert.der carol:/etc/ipsec.d/certs/peerCert.der
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/self-signed/test.conf b/testing/tests/self-signed/test.conf
new file mode 100644
index 000000000..0baa48d90
--- /dev/null
+++ b/testing/tests/self-signed/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/starter-also-loop/description.txt b/testing/tests/starter-also-loop/description.txt
new file mode 100644
index 000000000..7451f4e12
--- /dev/null
+++ b/testing/tests/starter-also-loop/description.txt
@@ -0,0 +1,4 @@
+This scenario is the same as test <b><a href="../rw-cert">rw-cert</a></b> but
+uses the <b>also</b> parameter in <b>moon</b>'s ipsec.conf in order to define
+the connections in a modular form. A closed also loop created by including
+<b>conn host-host</b> in <b>conn moon</b> is successfully detected.
diff --git a/testing/tests/starter-also-loop/evaltest.dat b/testing/tests/starter-also-loop/evaltest.dat
new file mode 100644
index 000000000..161772f8e
--- /dev/null
+++ b/testing/tests/starter-also-loop/evaltest.dat
@@ -0,0 +1,3 @@
+moon::cat /var/log/auth.log::detected also loop::YES
+moon::cat /var/log/auth.log::errors in config::YES
+
diff --git a/testing/tests/starter-also-loop/hosts/moon/etc/ipsec.conf b/testing/tests/starter-also-loop/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..e1d210253
--- /dev/null
+++ b/testing/tests/starter-also-loop/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,48 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn net-net
+ also=host-host
+ also=moon-net
+ also=sun-net
+
+conn host-host
+ also=moon
+ also=sun
+ auto=add
+
+conn rw
+ right=%any
+ also=moon
+ also=moon-net
+ auto=add
+
+conn moon
+ left=192.168.0.1
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ also=host-host
+
+conn moon-net
+ leftsubnet=10.1.0.0/16
+
+conn sun
+ right=192.168.0.2
+ rightid=@sun.strongswan.org
+
+conn sun-net
+ rightsubnet=10.2.0.0/16
diff --git a/testing/tests/starter-also-loop/posttest.dat b/testing/tests/starter-also-loop/posttest.dat
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/testing/tests/starter-also-loop/posttest.dat
diff --git a/testing/tests/starter-also-loop/pretest.dat b/testing/tests/starter-also-loop/pretest.dat
new file mode 100644
index 000000000..aa46124dc
--- /dev/null
+++ b/testing/tests/starter-also-loop/pretest.dat
@@ -0,0 +1 @@
+moon::ipsec start --debug-all
diff --git a/testing/tests/starter-also-loop/test.conf b/testing/tests/starter-also-loop/test.conf
new file mode 100644
index 000000000..e7735308f
--- /dev/null
+++ b/testing/tests/starter-also-loop/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon"
diff --git a/testing/tests/starter-also/description.txt b/testing/tests/starter-also/description.txt
new file mode 100644
index 000000000..3d4ff7dbf
--- /dev/null
+++ b/testing/tests/starter-also/description.txt
@@ -0,0 +1,3 @@
+This scenario is the same as test <b><a href="../rw-cert">rw-cert</a></b> but
+uses the <b>also</b> parameter in <b>moon</b>'s ipsec.conf in order to define
+the connections in a modular form.
diff --git a/testing/tests/starter-also/evaltest.dat b/testing/tests/starter-also/evaltest.dat
new file mode 100644
index 000000000..c7657801e
--- /dev/null
+++ b/testing/tests/starter-also/evaltest.dat
@@ -0,0 +1,5 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/starter-also/hosts/moon/etc/ipsec.conf b/testing/tests/starter-also/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..74d009cfa
--- /dev/null
+++ b/testing/tests/starter-also/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,47 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn net-net
+ also=host-host
+ also=moon-net
+ also=sun-net
+
+conn host-host
+ also=moon
+ also=sun
+ auto=add
+
+conn rw
+ right=%any
+ also=moon
+ also=moon-net
+ auto=add
+
+conn moon
+ left=192.168.0.1
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+
+conn moon-net
+ leftsubnet=10.1.0.0/16
+
+conn sun
+ right=192.168.0.2
+ rightid=@sun.strongswan.org
+
+conn sun-net
+ rightsubnet=10.2.0.0/16
diff --git a/testing/tests/starter-also/posttest.dat b/testing/tests/starter-also/posttest.dat
new file mode 100644
index 000000000..26848212b
--- /dev/null
+++ b/testing/tests/starter-also/posttest.dat
@@ -0,0 +1,6 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/starter-also/pretest.dat b/testing/tests/starter-also/pretest.dat
new file mode 100644
index 000000000..4f96e61df
--- /dev/null
+++ b/testing/tests/starter-also/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+moon::ipsec start --debug-all
+sleep 2
+carol::ipsec up home
diff --git a/testing/tests/starter-also/test.conf b/testing/tests/starter-also/test.conf
new file mode 100644
index 000000000..9cd583b16
--- /dev/null
+++ b/testing/tests/starter-also/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/starter-includes/description.txt b/testing/tests/starter-includes/description.txt
new file mode 100644
index 000000000..6a05c0cca
--- /dev/null
+++ b/testing/tests/starter-includes/description.txt
@@ -0,0 +1,6 @@
+This test is based on the <a href="../mode-config">mode-config</a>
+scenario and demonstrates the multiple use of the <b>include</b>
+parameter in IPsec configuration files. At the top level <b>/etc/ipsec.conf</b>
+defines the config setup section and includes <b>/etc/ipsec.connections</b>
+which in turn includes <b>/etc/ipsec.host</b> and <b>/etc/ipsec.peers/*</b>
+thereby showing the use of wildcards in path definitions.
diff --git a/testing/tests/starter-includes/evaltest.dat b/testing/tests/starter-includes/evaltest.dat
new file mode 100644
index 000000000..be8ca6ef5
--- /dev/null
+++ b/testing/tests/starter-includes/evaltest.dat
@@ -0,0 +1,16 @@
+carol::cat /var/log/auth.log::setting virtual IP source address to 10.3.0.1::YES
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+dave::cat /var/log/auth.log::setting virtual IP source address to 10.3.0.2::YES
+dave::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+dave::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+moon::ipsec status::rw-carol.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec status::rw-dave.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
+moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
+alice::tcpdump::IP dave1.strongswan.org > alice.strongswan.org: icmp::YES
+alice::tcpdump::IP alice.strongswan.org > dave1.strongswan.org: icmp::YES
diff --git a/testing/tests/starter-includes/hosts/carol/etc/ipsec.conf b/testing/tests/starter-includes/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..598997b45
--- /dev/null
+++ b/testing/tests/starter-includes/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,30 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_CAROL
+ leftsourceip=%modeconfig
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/tests/starter-includes/hosts/dave/etc/ipsec.conf b/testing/tests/starter-includes/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..da601389c
--- /dev/null
+++ b/testing/tests/starter-includes/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,30 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_DAVE
+ leftsourceip=%modeconfig
+ leftnexthop=%direct
+ leftcert=daveCert.pem
+ leftid=dave@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/tests/starter-includes/hosts/moon/etc/ipsec.conf b/testing/tests/starter-includes/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..aa9116252
--- /dev/null
+++ b/testing/tests/starter-includes/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,10 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+include /etc/ipsec.connections
diff --git a/testing/tests/starter-includes/hosts/moon/etc/ipsec.connections b/testing/tests/starter-includes/hosts/moon/etc/ipsec.connections
new file mode 100644
index 000000000..7cd938628
--- /dev/null
+++ b/testing/tests/starter-includes/hosts/moon/etc/ipsec.connections
@@ -0,0 +1,12 @@
+# /etc/ipsec.connections - connection definitions
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+include /etc/ipsec.host
+
+include /etc/ipsec.peers/*
+
diff --git a/testing/tests/starter-includes/hosts/moon/etc/ipsec.host b/testing/tests/starter-includes/hosts/moon/etc/ipsec.host
new file mode 100755
index 000000000..e84e5cdc6
--- /dev/null
+++ b/testing/tests/starter-includes/hosts/moon/etc/ipsec.host
@@ -0,0 +1,11 @@
+# /etc/ipsec.host - my host configuration
+
+conn %default
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftsourceip=PH_IP1_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+
diff --git a/testing/tests/starter-includes/hosts/moon/etc/ipsec.peers/ipsec.carol b/testing/tests/starter-includes/hosts/moon/etc/ipsec.peers/ipsec.carol
new file mode 100644
index 000000000..9212a9e96
--- /dev/null
+++ b/testing/tests/starter-includes/hosts/moon/etc/ipsec.peers/ipsec.carol
@@ -0,0 +1,8 @@
+# /etc/ipsec.peers/ipsec.carol - connection from carol
+
+conn rw-carol
+ right=%any
+ rightid=carol@strongswan.org
+ rightsourceip=PH_IP1_CAROL
+ auto=add
+
diff --git a/testing/tests/starter-includes/hosts/moon/etc/ipsec.peers/ipsec.dave b/testing/tests/starter-includes/hosts/moon/etc/ipsec.peers/ipsec.dave
new file mode 100644
index 000000000..482d15a21
--- /dev/null
+++ b/testing/tests/starter-includes/hosts/moon/etc/ipsec.peers/ipsec.dave
@@ -0,0 +1,8 @@
+# /etc/ipsec.peers/ipsec.dave - connection from dave
+
+conn rw-dave
+ right=%any
+ rightid=dave@strongswan.org
+ rightsourceip=PH_IP1_DAVE
+ auto=add
+
diff --git a/testing/tests/starter-includes/posttest.dat b/testing/tests/starter-includes/posttest.dat
new file mode 100644
index 000000000..121aa8aea
--- /dev/null
+++ b/testing/tests/starter-includes/posttest.dat
@@ -0,0 +1,13 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+dave::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+dave::/etc/init.d/iptables stop 2> /dev/null
+carol::ip addr del PH_IP1_CAROL/32 dev eth0
+dave::ip addr del PH_IP1_DAVE/32 dev eth0
+moon::rm /etc/ipsec.connections /etc/ipsec.host
+moon::rm -r /etc/ipsec.peers
diff --git a/testing/tests/starter-includes/pretest.dat b/testing/tests/starter-includes/pretest.dat
new file mode 100644
index 000000000..0af79a6d2
--- /dev/null
+++ b/testing/tests/starter-includes/pretest.dat
@@ -0,0 +1,10 @@
+moon::cat /etc/ipsec.connections /etc/ipsec.host /etc/ipsec.peers/*
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+dave::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start --debug-all
+carol::sleep 2
+carol::ipsec up home
+dave::ipsec up home
diff --git a/testing/tests/starter-includes/test.conf b/testing/tests/starter-includes/test.conf
new file mode 100644
index 000000000..1a8f2a4e0
--- /dev/null
+++ b/testing/tests/starter-includes/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon alice"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/virtual-ip-swapped/description.txt b/testing/tests/virtual-ip-swapped/description.txt
new file mode 100644
index 000000000..230906c5d
--- /dev/null
+++ b/testing/tests/virtual-ip-swapped/description.txt
@@ -0,0 +1,3 @@
+Same scenario as test <a href="../virtual-ip/"><b>virtual-ip</b></a> but with
+swapped end definitions: <b>right</b> denotes the <b>local</b> side whereas
+<b>left</b> stands for the <b>remote</b> peer.
diff --git a/testing/tests/virtual-ip-swapped/evaltest.dat b/testing/tests/virtual-ip-swapped/evaltest.dat
new file mode 100644
index 000000000..5160a340f
--- /dev/null
+++ b/testing/tests/virtual-ip-swapped/evaltest.dat
@@ -0,0 +1,9 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+carol::ping -c 1 PH_IP1_MOON::64 bytes from PH_IP1_MOON: icmp_seq=1::YES
+moon::ping -c 1 PH_IP1_CAROL::64 bytes from PH_IP1_CAROL: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
diff --git a/testing/tests/virtual-ip-swapped/hosts/carol/etc/ipsec.conf b/testing/tests/virtual-ip-swapped/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..0e239b707
--- /dev/null
+++ b/testing/tests/virtual-ip-swapped/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,30 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ right=PH_IP_CAROL
+ rightsourceip=PH_IP1_CAROL
+ rightnexthop=%direct
+ rightcert=carolCert.pem
+ rightid=carol@strongswan.org
+ rightfirewall=yes
+ left=PH_IP_MOON
+ leftsubnet=10.1.0.0/16
+ leftid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/tests/virtual-ip-swapped/hosts/moon/etc/ipsec.conf b/testing/tests/virtual-ip-swapped/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..db6effbac
--- /dev/null
+++ b/testing/tests/virtual-ip-swapped/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn rw
+ right=PH_IP_MOON
+ rightsourceip=PH_IP1_MOON
+ rightnexthop=%direct
+ rightcert=moonCert.pem
+ rightid=@moon.strongswan.org
+ rightsubnet=10.1.0.0/16
+ rightfirewall=yes
+ leftsubnetwithin=10.3.0.0/16
+ left=%any
+ auto=add
diff --git a/testing/tests/virtual-ip-swapped/posttest.dat b/testing/tests/virtual-ip-swapped/posttest.dat
new file mode 100644
index 000000000..ac5c7dd82
--- /dev/null
+++ b/testing/tests/virtual-ip-swapped/posttest.dat
@@ -0,0 +1,7 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+carol::ip addr del PH_IP1_CAROL/32 dev eth0
diff --git a/testing/tests/virtual-ip-swapped/pretest.dat b/testing/tests/virtual-ip-swapped/pretest.dat
new file mode 100644
index 000000000..4fe0ee90b
--- /dev/null
+++ b/testing/tests/virtual-ip-swapped/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/virtual-ip-swapped/test.conf b/testing/tests/virtual-ip-swapped/test.conf
new file mode 100644
index 000000000..f106524e2
--- /dev/null
+++ b/testing/tests/virtual-ip-swapped/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon alice"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/virtual-ip/description.txt b/testing/tests/virtual-ip/description.txt
new file mode 100644
index 000000000..4ec6021ea
--- /dev/null
+++ b/testing/tests/virtual-ip/description.txt
@@ -0,0 +1,8 @@
+The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>. Both <b>carol</b>
+and <b>moon</b> define a static virtual IP using the <b>leftsourceip</b> parameter.
+<b>leftfirewall=yes</b> automatically inserts iptables-based firewall rules that let pass
+the tunneled traffic. In order to test the tunnel, <b>carol</b> pings the client <b>alice</b>
+behind the gateway <b>moon</b> as well as the inner interface of the gateway. The source IP
+of the two pings will be the virtual IP <b>carol1</b>. Also thanks to its virtual IP <b>moon1</b>
+the gateway <b>moon</b> is able to ping <b>carol1</b> by using the existing subnet-subnet IPsec
+tunnel.
diff --git a/testing/tests/virtual-ip/evaltest.dat b/testing/tests/virtual-ip/evaltest.dat
new file mode 100644
index 000000000..5160a340f
--- /dev/null
+++ b/testing/tests/virtual-ip/evaltest.dat
@@ -0,0 +1,9 @@
+carol::ipsec status::home.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::rw.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES
+carol::ping -c 1 PH_IP1_MOON::64 bytes from PH_IP1_MOON: icmp_seq=1::YES
+moon::ping -c 1 PH_IP1_CAROL::64 bytes from PH_IP1_CAROL: icmp_seq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
+alice::tcpdump::IP carol1.strongswan.org > alice.strongswan.org: icmp::YES
+alice::tcpdump::IP alice.strongswan.org > carol1.strongswan.org: icmp::YES
diff --git a/testing/tests/virtual-ip/hosts/carol/etc/ipsec.conf b/testing/tests/virtual-ip/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..2f1170a6b
--- /dev/null
+++ b/testing/tests/virtual-ip/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,30 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn home
+ left=PH_IP_CAROL
+ leftsourceip=PH_IP1_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ leftfirewall=yes
+ right=PH_IP_MOON
+ rightsubnet=10.1.0.0/16
+ rightid=@moon.strongswan.org
+ auto=add
+
+
+
+
diff --git a/testing/tests/virtual-ip/hosts/moon/etc/ipsec.conf b/testing/tests/virtual-ip/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..1cd8aab25
--- /dev/null
+++ b/testing/tests/virtual-ip/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,26 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn rw
+ left=PH_IP_MOON
+ leftsourceip=PH_IP1_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ leftfirewall=yes
+ rightsubnetwithin=10.3.0.0/16
+ right=%any
+ auto=add
diff --git a/testing/tests/virtual-ip/posttest.dat b/testing/tests/virtual-ip/posttest.dat
new file mode 100644
index 000000000..ac5c7dd82
--- /dev/null
+++ b/testing/tests/virtual-ip/posttest.dat
@@ -0,0 +1,7 @@
+moon::iptables -v -n -L
+carol::iptables -v -n -L
+moon::ipsec stop
+carol::ipsec stop
+moon::/etc/init.d/iptables stop 2> /dev/null
+carol::/etc/init.d/iptables stop 2> /dev/null
+carol::ip addr del PH_IP1_CAROL/32 dev eth0
diff --git a/testing/tests/virtual-ip/pretest.dat b/testing/tests/virtual-ip/pretest.dat
new file mode 100644
index 000000000..4fe0ee90b
--- /dev/null
+++ b/testing/tests/virtual-ip/pretest.dat
@@ -0,0 +1,6 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+carol::/etc/init.d/iptables start 2> /dev/null
+carol::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up home
diff --git a/testing/tests/virtual-ip/test.conf b/testing/tests/virtual-ip/test.conf
new file mode 100644
index 000000000..f106524e2
--- /dev/null
+++ b/testing/tests/virtual-ip/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon alice"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/wildcards/description.txt b/testing/tests/wildcards/description.txt
new file mode 100644
index 000000000..e485f7066
--- /dev/null
+++ b/testing/tests/wildcards/description.txt
@@ -0,0 +1,8 @@
+The VPN gateway <b>moon</b> controls the access to the hosts <b>alice</b> and
+<b>venus</b> by means of wildcard parameters that must match the subject
+<b>Distinguished Name</b> contained in the peer's X.509 certificate. Access to
+<b>alice</b> is granted for DNs containing a OU=Research field whereas <b>venus</b>
+can only be reached with a DN containing OU=Accounting. The roadwarriors
+<b>carol</b> and <b>dave</b> belong to the departments 'Research' and 'Accounting',
+respectively. Therefore <b>carol</b> can access <b>alice</b> and <b>dave</b>
+can reach <b>venus</b>.
diff --git a/testing/tests/wildcards/evaltest.dat b/testing/tests/wildcards/evaltest.dat
new file mode 100644
index 000000000..cbc94b75a
--- /dev/null
+++ b/testing/tests/wildcards/evaltest.dat
@@ -0,0 +1,8 @@
+carol::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::alice.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::YES
+carol::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::ipsec status::venus.*PH_IP_CAROL.*STATE_QUICK_R2.*IPsec SA established::NO
+dave::ipsec status::venus.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::venus.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::YES
+dave::ipsec status::alice.*STATE_QUICK_I2.*IPsec SA established::NO
+moon::ipsec status::alice.*PH_IP_DAVE.*STATE_QUICK_R2.*IPsec SA established::NO
diff --git a/testing/tests/wildcards/hosts/carol/etc/ipsec.conf b/testing/tests/wildcards/hosts/carol/etc/ipsec.conf
new file mode 100755
index 000000000..de179c565
--- /dev/null
+++ b/testing/tests/wildcards/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,32 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_CAROL
+ leftnexthop=%direct
+ leftcert=carolCert.pem
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
+
+
+
+
+
diff --git a/testing/tests/wildcards/hosts/dave/etc/ipsec.conf b/testing/tests/wildcards/hosts/dave/etc/ipsec.conf
new file mode 100755
index 000000000..2fb6a301e
--- /dev/null
+++ b/testing/tests/wildcards/hosts/dave/etc/ipsec.conf
@@ -0,0 +1,32 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_DAVE
+ leftnexthop=%direct
+ leftcert=daveCert.pem
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+
+conn alice
+ rightsubnet=PH_IP_ALICE/32
+ auto=add
+
+conn venus
+ rightsubnet=PH_IP_VENUS/32
+ auto=add
+
+
+
+
+
diff --git a/testing/tests/wildcards/hosts/moon/etc/ipsec.conf b/testing/tests/wildcards/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..ee7bc8115
--- /dev/null
+++ b/testing/tests/wildcards/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,31 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+ left=PH_IP_MOON
+ leftnexthop=%direct
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+
+conn alice
+ leftsubnet=PH_IP_ALICE/32
+ right=%any
+ rightid="C=CH, O=Linux strongSwan, OU=Research, CN=*"
+ auto=add
+
+conn venus
+ leftsubnet=PH_IP_VENUS/32
+ right=%any
+ rightid="C=CH, O=Linux strongSwan, OU=Accounting, CN=*"
+ auto=add
+
diff --git a/testing/tests/wildcards/posttest.dat b/testing/tests/wildcards/posttest.dat
new file mode 100644
index 000000000..ed530f6d9
--- /dev/null
+++ b/testing/tests/wildcards/posttest.dat
@@ -0,0 +1,3 @@
+moon::ipsec stop
+carol::ipsec stop
+dave::ipsec stop
diff --git a/testing/tests/wildcards/pretest.dat b/testing/tests/wildcards/pretest.dat
new file mode 100644
index 000000000..67c50c2ef
--- /dev/null
+++ b/testing/tests/wildcards/pretest.dat
@@ -0,0 +1,9 @@
+moon::echo 1 > /proc/sys/net/ipv4/ip_forward
+carol::ipsec start
+dave::ipsec start
+moon::ipsec start
+carol::sleep 2
+carol::ipsec up alice
+carol::ipsec up venus
+dave::ipsec up venus
+dave::ipsec up alice
diff --git a/testing/tests/wildcards/test.conf b/testing/tests/wildcards/test.conf
new file mode 100644
index 000000000..08e5cc145
--- /dev/null
+++ b/testing/tests/wildcards/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice venus moon carol winnetou dave"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-v-m-c-w-d.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS=""
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol dave"
diff --git a/testing/tests/wlan/description.txt b/testing/tests/wlan/description.txt
new file mode 100644
index 000000000..e018148bd
--- /dev/null
+++ b/testing/tests/wlan/description.txt
@@ -0,0 +1,15 @@
+The WLAN clients <b>alice</b> and <b>venus</b> secure all their wireless traffic
+by setting up an IPsec tunnel to gateway <b>moon</b>. The VPN network mask is
+<b>0.0.0.0/0</b>. Traffic with destination outside the protected 10.1.0.0/10 network
+is NAT-ed by router <b>moon</b>. The IPsec connections are tested by pings from
+<b>alice</b> to <b>venus</b> tunneled via <b>moon</b> and to both the internal
+and external interface of gateway <b>moon</b>. Access to the gateway is
+set up by <b>lefthostaccess=yes</b> in conjunction with <b>leftfirewall=yes</b>.
+At last <b>alice</b> and <b>venus</b> ping the external host <b>sun</b> via the NAT router.
+<p>
+The host system controls the UML instances <b>alice</b> and <b>carol</b> via
+ssh commands sent over the virtual <b>tap1</b> interface. In order to keep up
+the control flow in the presence of the all-encompassing 0.0.0.0/0 tunnel
+to the gateway <b>moon</b> an auxiliary <b>passthrough</b> eroute restricted
+to the ssh port is statically set up by <b>conn system</b>.
+
diff --git a/testing/tests/wlan/evaltest.dat b/testing/tests/wlan/evaltest.dat
new file mode 100644
index 000000000..ccf5d0c8a
--- /dev/null
+++ b/testing/tests/wlan/evaltest.dat
@@ -0,0 +1,11 @@
+alice::ipsec status::wlan.*STATE_QUICK_I2.*IPsec SA established::YES
+venus::ipsec status::wlan.*STATE_QUICK_I2.*IPsec SA established::YES
+moon::ipsec status::alice.*STATE_QUICK_R2.*IPsec SA established::YES
+moon::ipsec status::venus.*STATE_QUICK_R2.*IPsec SA established::YES
+alice::ping -c 1 PH_IP_VENUS::64 bytes from PH_IP_VENUS: icmp_seq=1::YES
+alice::ping -c 1 PH_IP1_MOON::64 bytes from PH_IP1_MOON: icmp_seq=1::YES
+alice::ping -c 1 PH_IP_MOON::64 bytes from PH_IP_MOON: icmp_seq=1::YES
+alice::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_seq=1::YES
+venus::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_seq=1::YES
+moon::tcpdump::ESP::YES
+sun::tcpdump::icmp::YES
diff --git a/testing/tests/wlan/hosts/alice/etc/init.d/iptables b/testing/tests/wlan/hosts/alice/etc/init.d/iptables
new file mode 100755
index 000000000..86a76e2db
--- /dev/null
+++ b/testing/tests/wlan/hosts/alice/etc/init.d/iptables
@@ -0,0 +1,73 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/wlan/hosts/alice/etc/ipsec.conf b/testing/tests/wlan/hosts/alice/etc/ipsec.conf
new file mode 100755
index 000000000..a658e4fe8
--- /dev/null
+++ b/testing/tests/wlan/hosts/alice/etc/ipsec.conf
@@ -0,0 +1,37 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn system
+ left=PH_IP_ALICE
+ leftprotoport=tcp/ssh
+ leftnexthop=%direct
+ authby=never
+ type=passthrough
+ right=10.1.0.254
+ rightprotoport=tcp
+ auto=route
+
+conn wlan
+ left=PH_IP_ALICE
+ leftnexthop=%direct
+ leftcert=aliceCert.pem
+ leftid=alice@strongswan.org
+ leftfirewall=yes
+ right=PH_IP1_MOON
+ rightid=@moon.strongswan.org
+ rightsubnet=0.0.0.0/0
+ auto=add
+
diff --git a/testing/tests/wlan/hosts/moon/etc/init.d/iptables b/testing/tests/wlan/hosts/moon/etc/init.d/iptables
new file mode 100755
index 000000000..e95ef44c6
--- /dev/null
+++ b/testing/tests/wlan/hosts/moon/etc/init.d/iptables
@@ -0,0 +1,82 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # enable IP forwarding
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth1 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth1 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth1 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth1 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A FORWARD -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A FORWARD -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ # enable SNAT
+ iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p icmp -j SNAT --to-source PH_IP_MOON
+ iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p tcp -j SNAT --to-source PH_IP_MOON:2000-2100
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/wlan/hosts/moon/etc/ipsec.conf b/testing/tests/wlan/hosts/moon/etc/ipsec.conf
new file mode 100755
index 000000000..f873479e8
--- /dev/null
+++ b/testing/tests/wlan/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,37 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn alice
+ right=PH_IP_ALICE
+ rightid=alice@strongswan.org
+ also=wlan
+ auto=add
+
+conn venus
+ right=PH_IP_VENUS
+ rightid=@venus.strongswan.org
+ also=wlan
+ auto=add
+
+conn wlan
+ left=PH_IP1_MOON
+ leftnexthop=%direct
+ leftsubnet=0.0.0.0/0
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftfirewall=yes
+ lefthostaccess=yes
+
diff --git a/testing/tests/wlan/hosts/venus/etc/init.d/iptables b/testing/tests/wlan/hosts/venus/etc/init.d/iptables
new file mode 100755
index 000000000..6f95e7576
--- /dev/null
+++ b/testing/tests/wlan/hosts/venus/etc/init.d/iptables
@@ -0,0 +1,73 @@
+#!/sbin/runscript
+# Copyright 1999-2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+opts="start stop reload"
+
+depend() {
+ before net
+ need logger
+}
+
+start() {
+ ebegin "Starting firewall"
+
+ # default policy is DROP
+ /sbin/iptables -P INPUT DROP
+ /sbin/iptables -P OUTPUT DROP
+ /sbin/iptables -P FORWARD DROP
+
+ # allow esp
+ iptables -A INPUT -i eth0 -p 50 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT
+
+ # allow IKE
+ iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT
+
+ # allow crl fetch from winnetou
+ iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT
+ iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT
+
+ # allow ssh
+ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
+ iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
+
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+
+ if [ $a == nat ]; then
+ /sbin/iptables -t nat -P PREROUTING ACCEPT
+ /sbin/iptables -t nat -P POSTROUTING ACCEPT
+ /sbin/iptables -t nat -P OUTPUT ACCEPT
+ elif [ $a == mangle ]; then
+ /sbin/iptables -t mangle -P PREROUTING ACCEPT
+ /sbin/iptables -t mangle -P INPUT ACCEPT
+ /sbin/iptables -t mangle -P FORWARD ACCEPT
+ /sbin/iptables -t mangle -P OUTPUT ACCEPT
+ /sbin/iptables -t mangle -P POSTROUTING ACCEPT
+ elif [ $a == filter ]; then
+ /sbin/iptables -t filter -P INPUT ACCEPT
+ /sbin/iptables -t filter -P FORWARD ACCEPT
+ /sbin/iptables -t filter -P OUTPUT ACCEPT
+ fi
+ done
+ eend $?
+}
+
+reload() {
+ ebegin "Flushing firewall"
+ for a in `cat /proc/net/ip_tables_names`; do
+ /sbin/iptables -F -t $a
+ /sbin/iptables -X -t $a
+ done;
+ eend $?
+ start
+}
+
diff --git a/testing/tests/wlan/hosts/venus/etc/ipsec.conf b/testing/tests/wlan/hosts/venus/etc/ipsec.conf
new file mode 100755
index 000000000..742c1dbce
--- /dev/null
+++ b/testing/tests/wlan/hosts/venus/etc/ipsec.conf
@@ -0,0 +1,37 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+version 2.0 # conforms to second version of ipsec.conf specification
+
+config setup
+ plutodebug=control
+ crlcheckinterval=180
+ strictcrlpolicy=no
+ nat_traversal=no
+
+conn %default
+ ikelifetime=60m
+ keylife=20m
+ rekeymargin=3m
+ keyingtries=1
+
+conn system
+ left=PH_IP_VENUS
+ leftprotoport=tcp/ssh
+ leftnexthop=%direct
+ authby=never
+ type=passthrough
+ right=10.1.0.254
+ rightprotoport=tcp
+ auto=route
+
+conn wlan
+ left=PH_IP_VENUS
+ leftnexthop=%direct
+ leftcert=venusCert.pem
+ leftid=@venus.strongswan.org
+ leftfirewall=yes
+ right=PH_IP1_MOON
+ rightid=@moon.strongswan.org
+ rightsubnet=0.0.0.0/0
+ auto=add
+
diff --git a/testing/tests/wlan/posttest.dat b/testing/tests/wlan/posttest.dat
new file mode 100644
index 000000000..cc873d1ff
--- /dev/null
+++ b/testing/tests/wlan/posttest.dat
@@ -0,0 +1,10 @@
+alice::iptables -v -n -L
+venus::iptables -v -n -L
+moon::iptables -t nat -v -n -L POSTROUTING
+moon::iptables -v -n -L
+moon::ipsec stop
+alice::ipsec stop
+venus::ipsec stop
+alice::/etc/init.d/iptables stop 2> /dev/null
+venus::/etc/init.d/iptables stop 2> /dev/null
+moon::/etc/init.d/iptables stop 2> /dev/null
diff --git a/testing/tests/wlan/pretest.dat b/testing/tests/wlan/pretest.dat
new file mode 100644
index 000000000..de4a6ad31
--- /dev/null
+++ b/testing/tests/wlan/pretest.dat
@@ -0,0 +1,11 @@
+moon::/etc/init.d/iptables start 2> /dev/null
+alice::/etc/init.d/iptables start 2> /dev/null
+venus::/etc/init.d/iptables start 2> /dev/null
+moon::ipsec start
+alice::ipsec start
+venus::ipsec start
+alice::sleep 2
+alice::ipsec up wlan
+venus::sleep 2
+venus::ipsec up wlan
+venus::sleep 2
diff --git a/testing/tests/wlan/test.conf b/testing/tests/wlan/test.conf
new file mode 100644
index 000000000..b141c4f1b
--- /dev/null
+++ b/testing/tests/wlan/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# UML instances used for this test
+
+# All UML instances that are required for this test
+#
+UMLHOSTS="alice venus moon winnetou sun"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-v-m-w-s-b.png"
+
+# UML instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon:eth1 sun"
+
+# UML instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="alice venus moon"